Skip to content

Add offline M365 Copilot (Cowork) plugin build and release workflow - #55

Merged
zx000097 merged 9 commits into
mainfrom
zanebong-microsoft-m365-snapshot-skill-script
Oct 27, 2026
Merged

zx000097 merged 9 commits into
mainfrom
zanebong-microsoft-m365-snapshot-skill-script

Conversation

@zx000097

@zx000097 zx000097 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds an offline Microsoft 365 Copilot (Cowork) plugin for the Microsoft Events skill, and a workflow that publishes it as a release zip. Cowork runs skill scripts in a sandbox with Node.js but no network access, so the skill's usual npx -y @microsoft/events-cli commands can't run there. Instead, the plugin includes the CLI and a frozen copy of the session catalogs. The Learn MCP connector still works, because Cowork calls MCP connectors from outside the sandbox.

  • Offline mode (MSEVENTS_OFFLINE=1): the CLI only reads its cache. It doesn't fetch, revalidate or write. For an event that isn't cached, it returns no sessions and prints a note to stderr. refresh exits with code 1, and status marks entries as offline.
  • npm run build:m365 (cli/scripts/build-m365-plugin.mjs):
    • Downloads the live catalogs into a frozen data/ folder.
    • Bundles the whole CLI with esbuild into scripts/msevents.mjs. The bundle always runs in offline mode and reads its cache from data/.
    • Renders the hand-written cli/m365-skill/SKILL.md template.
    • With --package, also builds the app package zip with atk, run without a shell.
    • Writes output to out/m365-plugin, which is git-ignored.
  • M365 skill template (cli/m365-skill/SKILL.md, under 20,000 characters): uses only node scripts/msevents.mjs commands. The agent doesn't mention that the data is bundled, and suggests checking the event site for the latest times and rooms.
  • npm run smoke:m365: builds the plugin from a fixture with the network disabled and the data read-only, then checks that the bundle's output matches msevents. It's added to CI.
  • Release workflow (.github/workflows/m365-plugin.yml):
    • Run it manually on main with a version (x.y.z, higher than the last m365-v* tag).
    • It builds the plugin with live catalogs and publishes release m365-v<version> with microsoft-build-m365.zip attached, marked Latest. The README links to releases/latest/download/microsoft-build-m365.zip.
    • The M365 plugin has its own version, separate from the plugin manifests, because catalog refreshes also need new releases.
    • Only the publish job gets contents: write.
  • Lockfile: the esbuild entries now point at registry.npmjs.org with sha512 integrity.
  • Docs: AGENTS.md, README.md and cli/README.md are updated.

The repo skill (skills/microsoft-build/SKILL.md) is unchanged, so this PR doesn't bump the plugin manifest versions.

Validation (from cli/):

  • npm ci: passed
  • npm run build: passed
  • npm test: passed (7 files, 67 tests, including 15 new tests in test/offline.test.ts)
  • npm run smoke:fixture: passed
  • npm run smoke:m365: passed ("M365 plugin smoke passed (10 commands match the CLI).")
  • npm run build:m365 -- --plugin-version 1.0.6 --package: passed on Windows, and in a node:22 Linux container that repeats the workflow's build steps. Earlier builds were installed and tested in Cowork.
  • actionlint 1.7.12 on m365-plugin.yml and ci.yml: passed
  • Not run: npm run smoke:live, and the M365 plugin workflow itself, which can only run from main. Not yet tested with the Ignite 2026 event from Add Ignite 2026 event to CLI #57; the branch merges cleanly with main.

Note

This project is maintained by a small team for Microsoft Build. We may not be able to review or accept all contributions — but we appreciate the effort!

Before submitting a PR, consider opening an issue or discussion first. This helps us align on direction before you invest time in code.

Checklist

  • I have not included any secrets or credentials
  • I have tested my changes (if applicable)
  • My changes don't break existing functionality

Microsoft 365 Copilot Cowork runs skill scripts in a sandbox with Node but
no network, so the skill's npx workflow can't run there. Instead of a
separate snapshot script, reuse the real CLI:

- MSEVENTS_OFFLINE=1 makes the CLI read its cache without fetching,
  revalidating, or writing. Missing events return no sessions with a
  stderr note; refresh exits 1; status marks entries as offline.
- npm run build:snapshot downloads the catalogs, bundles the whole CLI
  into skills/microsoft-build/scripts/msevents.mjs with esbuild (banner
  forces offline mode and points MSEVENTS_CACHE_DIR at ../data), writes
  the cache files as a frozen data/ folder, renders the hand-written
  cli/snapshot-skill/SKILL.md template, and optionally packages the
  plugin with atk (--package).
- The Cowork template tells the agent not to volunteer that the data is
  bundled or when it was downloaded. It adds a "check the event site for
  the latest schedule" tip for times and rooms, and gives the download
  date truthfully if the user asks how current the data is.
- npm run smoke:snapshot checks the bundle against the live CLI with
  network disabled and read-only data; CI runs it.

The repo skill (skills/microsoft-build/SKILL.md) is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 16, 2026 08:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Packaging interprets output paths through a shell, allowing unintended command execution.

1 open finding
What changed in this PR

Adds read-only offline catalog access to the CLI and packages it for Microsoft 365 Copilot Cowork.

Changes:

  • Adds offline cache behavior and status reporting.
  • Builds a bundled CLI with frozen catalogs and a dedicated skill template.
  • Adds offline tests, CI smoke coverage, and usage documentation.
File Description
README.md Adds Cowork installation guidance.
cli/​test/​offline.test.ts Tests offline behavior.
cli/​src/​output/​format.ts Reports offline status.
cli/​src/​index.ts Supports bundled version metadata.
cli/​src/​config.ts Detects offline mode.
cli/​src/​commands/​status.ts Passes offline state to formatting.
cli/​src/​commands/​refresh.ts Rejects offline refreshes.
cli/​src/​commands/​common.ts Reads cached sessions without network access.
cli/​snapshot-skill/​SKILL.md Defines offline agent workflows.
cli/​scripts/​smoke-snapshot.mjs Checks bundle behavior and CLI parity.
cli/​scripts/​build-snapshot.mjs Builds and packages frozen catalogs.
cli/​README.md Documents offline usage and packaging.
cli/​package.json Adds snapshot scripts and esbuild.
cli/​package-lock.json Locks bundling dependencies.
AGENTS.md Documents snapshot maintenance requirements.
.github/​workflows/​ci.yml Runs snapshot smoke checks.
Files not reviewed (1)
  • cli/package-lock.json: Generated file

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cli/scripts/build-snapshot.mjs Outdated
Output paths were interpolated into a shell command, so names containing $(...), backticks or %VAR% were expanded before reaching atk. Start atk with execFile instead. On Windows, npm installs atk as a .cmd shim that Node can't start without cmd.exe, so run the package's JS entry with node.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 16, 2026 08:49
@zx000097
zx000097 marked this pull request as ready for review October 16, 2026 08:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The live-download, Cowork packaging, and installation workflow still needs end-to-end human validation.

0 open findings

1 resolved since last review
Files not reviewed (1)
  • cli/package-lock.json: Generated file

🧠 Review effort: Balanced

Zane Bong and others added 2 commits October 22, 2026 18:48
The esbuild entries added with the offline snapshot build resolved to an internal Azure Artifacts feed with sha1 integrity. Point them at registry.npmjs.org with sha512 integrity so the lockfile matches main's registry; tarballs are byte-identical.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Rename build:snapshot/smoke:snapshot to build:m365/smoke:m365, cli/snapshot-skill to cli/m365-skill, and default output to out/m365-plugin.

Add the M365 plugin workflow. A manual run on main takes a version, which must be higher than the last m365-v* tag, builds the package with live catalogs, and publishes release m365-v<version> with microsoft-build-m365.zip attached, marked Latest. The M365 plugin is versioned separately from the plugin manifests because catalog refreshes need new releases too.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 22, 2026 09:21
@zx000097 zx000097 changed the title Add MSEVENTS_OFFLINE mode and Cowork snapshot build Add offline M365 Copilot (Cowork) plugin build and release workflow Oct 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new Agents Toolkit packaging and public-release path needs end-to-end human validation before approval.

No open issues 🎉

1 file not reviewed
  • cli/package-lock.json: Generated file

Review effort: Balanced

The test hard-coded the uncached event names, so it failed once main added Ignite 2026.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 22, 2026 09:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new public-release workflow has not been exercised end to end and needs final maintainer validation.

No open issues 🎉

1 file not reviewed
  • cli/package-lock.json: Generated file

Review effort: Balanced

Zane Bong and others added 2 commits October 23, 2026 11:21
Resolve the cli/package-lock.json conflict by keeping this branch's esbuild entries with the CLI version from main (0.3.2).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Replace the hand-written cli/m365-skill/SKILL.md with cli/m365-skill/offline-overlay.md. build:m365 now generates the Cowork SKILL.md from skills/microsoft-build/SKILL.md: the overlay replaces the catalog-access section and offline frontmatter, SKILL_REWRITES swap the remaining online steps, and the build fails if a rewrite stops matching or online wording is left.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 23, 2026 07:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The public-release workflow has not run end to end, so the packaging and publication path needs final human validation.

No open issues 🎉

1 file not reviewed
  • cli/package-lock.json: Generated file

Review effort: Balanced

Comment thread cli/m365-skill/SKILL.md Outdated
@@ -1,12 +1,12 @@
import { KNOWN_EVENTS } from '../config.js';
import { KNOWN_EVENTS, OFFLINE_ENV_VAR, isOfflineMode } from '../config.js';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add some evidences in the comments that show offlinemode and onlien mode both works after this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Osmond Jiang (@OsmondJiang). Below are the evidences for online and offline modes.

Online mode: GitHub Copilot and Claude Code plugins

Check Result
npm run smoke:live ✅ live download of Build 2026, 461 sessions
sessions --query agents --event build-2026 ✅ ODSP926, …
sessions --tech "Azure Cosmos DB" --event build-2026 ✅ OD820, LTG411
sessions --query agents --event ignite-2026 ✅ LTG1172 (1,037 sessions)
sessions --query agents (all events) ✅ results from Build 2026, and status shows Ignite 2026 cached
refresh --event build-2026 ✅ conditional GET, 304 Not Modified

Offline mode in Cowork

Image

Lets a release bundle only the listed events, for example when a past event's catalog is no longer downloadable. Empty bundles every supported event.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 26, 2026 04:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The release workflow has not run end to end, so publishing and installation of the released Cowork package need final human validation.

No open issues 🎉

1 file not reviewed
  • cli/package-lock.json: Generated file

Review effort: Balanced

…ip in CI

The offline skill now adds one short note with the snapshot date the first time it recommends sessions or gives times or rooms, instead of never mentioning the snapshot unprompted.

smoke:m365 gains a --package mode that builds the zip with atk, unzips it, checks the skill files match the plugin folder byte for byte, and runs the offline checks against the unzipped skill. CI installs atk and runs this mode.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dc8d0c3c-e6a7-4a74-bee9-cf99887b72b5
Copilot AI balanced review requested due to automatic review settings October 27, 2026 01:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues block the Cowork offline support changes.

No open issues 🎉

1 file not reviewed
  • cli/package-lock.json: Generated file

Review effort: Balanced

@zx000097
zx000097 merged commit 456537f into main Oct 27, 2026
5 checks passed
@zx000097
zx000097 deleted the zanebong-microsoft-m365-snapshot-skill-script branch October 27, 2026 03:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants