{"_id":"@dieulc/pi-office-bridge","_rev":"7-aad3836d13ba0079cd459ad37299d00c","name":"@dieulc/pi-office-bridge","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.0":{"name":"@dieulc/pi-office-bridge","version":"0.1.0","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"license":"MIT","_id":"@dieulc/pi-office-bridge@0.1.0","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"0455cc998a662910cd7244e62c5719dc4af0fdce","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.1.0.tgz","fileCount":6,"integrity":"sha512-6wMifASN+2PHDfY4GUBwjktNvjbVQde/ZNfHCunq7k1YQSdYbZRNNkF9DXP2WKb0V21fmPIAU741i5ILfEmmKg==","signatures":[{"sig":"MEUCIQDkqAfRxHpHb04kYChcvuH0pV75zfLv29vcrcKc8gXy0gIgce7TVP/G3wBtICos41dq7rzGWHvZTBQZmcpAHZmaPYo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37199},"type":"module","engines":{"node":">=20"},"gitHead":"27c924c0c23579c12ca7cfb31745bb8d78aeb833","scripts":{"test":"npm run test:smoke && npm run test:interop","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:smoke":"npm run build && node tests/smoke.mjs","test:interop":"npm run build && node tests/pane-interop.mjs"},"_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"tmp":"tmp/pi-office-bridge_0.1.0_1788887676124_0.4247957999498593","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@dieulc/pi-office-bridge","version":"0.2.0","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"license":"MIT","_id":"@dieulc/pi-office-bridge@0.2.0","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"f58086f06fe7a8c4e1f2250d403c0d4ba5ade6cc","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.2.0.tgz","fileCount":6,"integrity":"sha512-AjidfoOmWLQWcMeuHiq7MV3qNbvkIrj67Uj/mcofNiI3QoCZj5Uoeqyrodju2PTfCmuXPRGnFgw3kyvlrCfKkA==","signatures":[{"sig":"MEUCIQC+rFKqJeyHVTNN89+MdV+4uIzEa4c4tpDEEN3BN+m/swIgSECkIUShkgbccSAEIuCio+PQmGr3RBDCIPMzjuyPJN4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46186},"type":"module","engines":{"node":">=20"},"gitHead":"bd9648ce411d14177c5317b07fc572956d94e5c7","scripts":{"test":"npm run test:smoke && npm run test:interop","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:smoke":"npm run build && node tests/smoke.mjs","test:interop":"npm run build && node tests/pane-interop.mjs"},"_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"tmp":"tmp/pi-office-bridge_0.2.0_1789083528384_0.6188122862429091","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@dieulc/pi-office-bridge","version":"0.3.0","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"license":"MIT","_id":"@dieulc/pi-office-bridge@0.3.0","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"29341fcd438454da241ed233e5c5f26b0f01b0e1","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.3.0.tgz","fileCount":7,"integrity":"sha512-qU1evoszGkwK5Yu8584PvUmEprzR5Dec2ywwpz0ex3lQPSU+tp10nVl813geFJOdZK6ueXHhf4bypQxczO/gxg==","signatures":[{"sig":"MEYCIQDEz/j0QJib09K/rdC/RoZT3yjJFthempmPEn533Ui68AIhAIEi5MAG0zA80y7qVWP91MBzDaXmXtSsGz0jJpo69Aob","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50921},"type":"module","engines":{"node":">=20"},"gitHead":"e0083b35d9984b3688461d116001ee81515f66d2","scripts":{"test":"npm run test:active && npm run test:smoke && npm run test:interop","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:smoke":"npm run build && node tests/smoke.mjs","test:active":"node --test tests/active-tools.test.mjs","test:interop":"npm run build && node --import ./tests/register-ts-loader.mjs tests/pane-interop.mjs"},"_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"^0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"tmp":"tmp/pi-office-bridge_0.3.0_1789284572082_0.3579332915972686","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@dieulc/pi-office-bridge","version":"0.4.0","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"license":"MIT","_id":"@dieulc/pi-office-bridge@0.4.0","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"8294e228915c795ef8efefeebd728b5afce82ee3","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.4.0.tgz","fileCount":7,"integrity":"sha512-C26TU3Hb3poHAVSS9QY7mEzzOLssXH+idBxZXfKx5iCitXkrN6LjHsZsoLAaj3chDgqrRi8D6fqXcQbvjibQvw==","signatures":[{"sig":"MEUCIQD5Ax1H+BY1Ss8on+/d3fih7SQLtlS9E73tqw1hQiQG4QIgMkvbiXGv1rI2yJ0F4MHejAR3/Hrk1wyGyHOoJ0rsphE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69733},"type":"module","engines":{"node":">=20"},"gitHead":"dd91ed8215794d0ba9d68e975f96be3cbf4c29ba","scripts":{"test":"npm run test:active && npm run test:replies && npm run test:mentions && npm run test:smoke && npm run test:interop && npm run test:multi","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:multi":"npm run build && node tests/multi-document.test.mjs","test:smoke":"npm run build && node tests/smoke.mjs","test:active":"node --test tests/active-tools.test.mjs","test:interop":"npm run build && node --import ./tests/register-ts-loader.mjs tests/pane-interop.mjs","test:replies":"npm run build && node --test tests/pane-replies.test.mjs","test:mentions":"npm run build && node --test tests/document-mentions.test.mjs"},"_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"deprecated":"missing src modules (pane-replies.ts, document-mentions.ts) — install >=0.4.1","repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"^0.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"tmp":"tmp/pi-office-bridge_0.4.0_1789453051706_0.946324311887041","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@dieulc/pi-office-bridge","version":"0.4.1","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"license":"MIT","_id":"@dieulc/pi-office-bridge@0.4.1","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"9377f2930e19e833a82ad67592cbe0fb17da25c3","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.4.1.tgz","fileCount":9,"integrity":"sha512-TTKRL+9Xm25iFz7nNNeXhfb2ccXP67wEErEa5xhHVm5uaNKlrET74C4ylb7/25jQKKI6aRFYJx5f6nMmSvKTPA==","signatures":[{"sig":"MEUCIQCmZaUfPkdH0hiyw1grhoRG7Yt0A0eBED047BIxB0ZYEAIgKFKF8M2upaoTg8XI4oDOFFlNAFtRSerop7FwmsyrKBA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":81172},"type":"module","engines":{"node":">=20"},"gitHead":"dd91ed8215794d0ba9d68e975f96be3cbf4c29ba","scripts":{"test":"npm run test:active && npm run test:replies && npm run test:mentions && npm run test:smoke && npm run test:interop && npm run test:multi && npm run test:package","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:multi":"npm run build && node tests/multi-document.test.mjs","test:smoke":"npm run build && node tests/smoke.mjs","test:active":"node --test tests/active-tools.test.mjs","test:interop":"npm run build && node --import ./tests/register-ts-loader.mjs tests/pane-interop.mjs","test:package":"node ../../scripts/check-package-contents.mjs .","test:replies":"npm run build && node --test tests/pane-replies.test.mjs","test:mentions":"npm run build && node --test tests/document-mentions.test.mjs"},"_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"^0.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"tmp":"tmp/pi-office-bridge_0.4.1_1789454915408_0.2797449393249196","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"pi":{"extensions":["./src/index.ts"]},"_id":"@dieulc/pi-office-bridge@0.5.0","bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"dist":{"shasum":"95d0fc39b71054797a0f7cf40a455e281e07cf77","tarball":"https://registry.npmjs.org/@dieulc/pi-office-bridge/-/pi-office-bridge-0.5.0.tgz","fileCount":9,"integrity":"sha512-LhJZ4+6omw2jhtPme07MnwlNMadPXe/HF8YjU0Ag+xyq28PK3CoAXr8zpMY3XK9P/SVslPnB9+e81GAx9Uwe/w==","signatures":[{"sig":"MEUCICwY6RzOlZh/2t90fIFoeNLKuQQKmbo/ZtMY9wmwLkhaAiEA6ROG5+6tZwxFVEcE+ZOA/prvUTtg8LRLQyqWJFyjaus=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAazzsB5D5wBH3uWCnvRIQlD820k+DTp9P20d34mp7Z+AiAYVF6rfCi7GwLWSVjWovngFrrHSYYEikOW2dywNxqz7Q=="}],"unpackedSize":87259},"name":"@dieulc/pi-office-bridge","type":"module","engines":{"node":">=20"},"gitHead":"b5979294b5d9e43a073a79cf67bcfbed25b17c71","license":"MIT","scripts":{"test":"npm run test:active && npm run test:replies && npm run test:mentions && npm run test:smoke && npm run test:interop && npm run test:multi && npm run test:package","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:multi":"npm run build && node tests/multi-document.test.mjs","test:smoke":"npm run build && node tests/smoke.mjs","test:active":"node --test tests/active-tools.test.mjs","test:interop":"npm run build && node --import ./tests/register-ts-loader.mjs tests/pane-interop.mjs","test:package":"node ../../scripts/check-package-contents.mjs .","test:replies":"npm run build && node --test tests/pane-replies.test.mjs","test:mentions":"npm run build && node --test tests/document-mentions.test.mjs"},"version":"0.5.0","_npmUser":{"name":"dieulc","email":"dieuluucanh@gmail.com"},"homepage":"https://github.com/dieuluucanh/pi-for-office#readme","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"_npmVersion":"11.13.0","description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","directories":{},"maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"_nodeVersion":"24.16.0","dependencies":{"ws":"^8.18.0","typebox":"^1.3.10","@dieulc/pi-office-protocol":"^0.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.5.13","typescript":"^5.9.0","@types/node":"^22.20.0","@earendil-works/pi-ai":"0.85.1","@earendil-works/pi-coding-agent":"0.85.1"},"peerDependencies":{"@earendil-works/pi-ai":">=0.83.0","@earendil-works/pi-coding-agent":">=0.85.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-office-bridge_0.5.0_1789825125506_0.6713955190831609"}}},"time":{"created":"2026-09-08T17:14:35.929Z","modified":"2026-09-19T13:38:45.743Z","0.1.0":"2026-09-08T17:14:36.279Z","0.2.0":"2026-09-10T23:38:48.519Z","0.3.0":"2026-09-13T07:29:32.207Z","0.4.0":"2026-09-15T06:17:31.839Z","0.4.1":"2026-09-15T06:48:35.543Z","0.5.0":"2026-09-19T13:38:45.584Z"},"bugs":{"url":"https://github.com/dieuluucanh/pi-for-office/issues"},"license":"MIT","homepage":"https://github.com/dieuluucanh/pi-for-office#readme","keywords":["pi","pi-package","office","excel","word","powerpoint","bridge","extension"],"repository":{"url":"git+https://github.com/dieuluucanh/pi-for-office.git","type":"git"},"description":"Native Pi extension — WebSocket bridge + Office tool proxy so Pi can drive Excel, Word, and PowerPoint through the pi-for-office add-in.","maintainers":[{"name":"dieulc","email":"dieuluucanh@gmail.com"}],"readme":"# @dieulc/pi-office-bridge\r\n\r\nNative Pi extension that lets a local Pi process drive **Excel**, **Word**, and\r\n**PowerPoint** through the [pi-for-office](../add-in/README.md) task-pane\r\nadd-in.\r\n\r\nPure extension — it only uses Pi's public extension API, so **Pi core is never\r\ntouched** and Pi can be updated freely.\r\n\r\n## How it works\r\n\r\n```\r\nExcel / Word / PowerPoint  (pi-for-office task pane)\r\n        │  WebSocket  ws://127.0.0.1:38617\r\n        ▼\r\nlocal Pi process  (this extension)\r\n   • registers office_<host>_<op> tools\r\n   • proxies Office.js calls back to the pane\r\n   • injects pane prompts into the Pi session\r\n```\r\n\r\nTwo flows:\r\n\r\n1. **Tool proxy (Pi → pane):** the Pi agent calls `office_excel_read_range`,\r\n   `office_word_insert_text`, …; the extension forwards a `tool_call` to the\r\n   attached pane; the pane runs the Office.js op and answers with a\r\n   `tool_result`. The LLM then sees the document content **and** has Pi's full\r\n   system tools (bash, git, files).\r\n\r\n2. **Pane-driven chat (pane → Pi):** the user types in the add-in sidebar; the\r\n   pane forwards a `user_message`; the extension injects it into the Pi session\r\n   and streams the assistant's final reply back to the pane.\r\n\r\n## Multiple open documents (protocol v2)\r\n\r\nThe bridge serves **every open document of every attached host app**, not just\r\nthe most recently connected one. In `hello` each pane reports a\r\nprivacy-preserving document identity (`document.id` = a local hash,\r\n`document.name` = display name, `document.source`), and the server routes each\r\ntool call to one specific document:\r\n\r\n- Every `office_*` tool takes an optional **`document`** argument: a document id\r\n  (from `office_list_documents`), a unique document name, or `\"active\"`.\r\n- An omitted / `\"active\"` target resolves to the **focused** document, then to\r\n  the only attached document of that host. If several documents are open and\r\n  none is focused, the call **fails with the candidate list** instead of\r\n  editing a guess.\r\n- Panes report focus/visibility with `pane_state` frames; typing in a pane also\r\n  counts as focus, and Excel additionally uses `Workbook.onActivated`.\r\n- `office_list_documents` lists the attached documents (id, name, host, focused,\r\n  windows); the system prompt carries the same list before every turn.\r\n- Two windows of the **same file** share one document id: the call routes to the\r\n  focused window, and errors if neither is focused.\r\n- In the Pi TUI, type **`#`** while composing a prompt to pick a document from a\r\n  dropdown (focused first). Enter inserts `#<name>` — or `#<document id>` when\r\n  two open documents share a name. The server strips the leading `#` when\r\n  resolving the target, so the mention is directly usable.\r\n- Agent replies are matched to the pane prompt that caused them and are sent\r\n  **only to that pane** (never broadcast), and the injected prompt carries an\r\n  `[office:<host> \"<name>\" id=…]` tag so a shared conversation stays traceable.\r\n\r\n**Protocol v2 is breaking:** update the add-in and the bridge together\r\n(protocol 0.4.0 + bridge 0.4.0). A v1 pane is rejected at the handshake with\r\n`protocol_mismatch`.\r\n\r\n## Install\r\n\r\n```bash\r\npi install npm:@dieulc/pi-office-bridge\r\n```\r\n\r\n**Update to the latest** (the full 29-tool catalog incl. structure/format tools\r\nneeds ≥ 0.3.0; multi-document targeting, `office_list_documents` and `#` mention\r\nautocomplete need ≥ 0.4.0 (protocol v2, which requires the matching add-in\r\nbuild); the `/health` probe and version display need ≥ 0.2.0):\r\n\r\n```bash\r\npi install npm:@dieulc/pi-office-bridge@latest\r\n```\r\n\r\nThen restart Pi. Note that `pi install` pins the version it fetched into\r\n`~/.pi/agent/npm/package.json`, so Pi will **not** auto-upgrade — re-run the\r\ncommand above to get the newest bridge.\r\n\r\nOr from the monorepo (development) as the **dev bridge** on port `38618`\r\n(`--no-extensions` ignores settings, so the globally installed prod bridge\r\nnever double-loads in the same process):\r\n\r\n```bash\r\nnpm run bridge:dev   # repo root → pi --no-extensions -e ./packages/bridge-extension/src/index.ts --office-bridge-port 38618\r\n```\r\n\r\n> **Troubleshooting: the agent says it has no `office_excel_modify_structure`**\r\n> (or any other newer tool). A bridge **< 0.3.0** ships a small hardcoded\r\n> catalog (12 tools) and ignores the pane's `hello.ops`, so newer ops silently\r\n> never register. Fix: `pi install npm:@dieulc/pi-office-bridge@latest`, restart\r\n> Pi, then verify with `/office-tools` (29 tools) and `/office` (pane ops +\r\n> catalog version).\r\n\r\n## Enable in the add-in\r\n\r\n1. Install/run the bridge so a Pi process with this extension is listening\r\n   (see above). Keep that Pi process running in the background.\r\n2. Open pi-for-office in Excel / Word / PowerPoint.\r\n3. Go to **Settings → Connections → Local Pi agent (advanced)** and flip the\r\n   **Enable local Pi agent** toggle on. The card shows the live connection\r\n   state (Connecting… → Connected); no taskpane reload is needed.\r\n4. Verify with the card's **Test connection** button, or from a terminal:\r\n\r\n```bash\r\ncurl http://127.0.0.1:38617/health\r\n# → { \"ok\": true, \"service\": \"pi-office-bridge\", \"serverVersion\": \"0.2.0\",\r\n#     \"capabilities\": [\"http-health\"], \"panes\": [ … ] }\r\n```\r\n\r\n`/health` lists the attached pane(s) and their host app (excel / word /\r\npowerpoint), so it doubles as a quick host-detection check. The add-in's\r\nprobe classifies the response (current / older bridge / timeout / browser\r\nblocked) instead of reporting a bare failure — see\r\n[`docs/local-development.md`](../../docs/local-development.md).\r\n\r\n## Version & capabilities\r\n\r\nEvery `welcome` frame (and `GET /health`) advertises additive server\r\nmetadata:\r\n\r\n- `serverVersion` — this package's version (e.g. `\"0.2.0\"`).\r\n- `capabilities` — `[\"http-health\"]` means the HTTP `/health` surface is\r\n  served.\r\n\r\nClients (the add-in card) treat an absent `capabilities` as “legacy bridge\r\n(< 0.2.0)” and tell the user to update instead of claiming the bridge is\r\ndown. The connection state is surfaced live to the Pi TUI as soon as a pane\r\nattaches or detaches (`onPanesChanged`).\r\n\r\n## Commands\r\n\r\n| Command | Description |\r\n|---------|-------------|\r\n| `/office` | Show bridge status: port + attached apps (Excel/Word/PowerPoint) |\r\n| `/office-tools` | List every `office_*` tool registered |\r\n\r\n## Configuration\r\n\r\n- **Port** — flag `--office-bridge-port <port>` or env `PI_OFFICE_BRIDGE_PORT`\r\n  (default `38617`). The add-in connects to the same default; change both if you\r\n  override it (the add-in's bridge card has a **Bridge URL** row that both the\r\n  WebSocket client and the probe use). If the port is already taken by another\r\n  Pi process, the extension reports `EADDRINUSE` with the override hint.\r\n- **Allowed origins** — env `PI_OFFICE_BRIDGE_ALLOWED_ORIGINS` (comma-separated)\r\n  extends the browser origins allowed to read `GET /health`. Defaults cover the\r\n  dev Vite server (`https://localhost:3141`) and the hosted GitHub Pages add-in\r\n  (`https://dieuluucanh.github.io`). The pane's WebSocket connection is\r\n  loopback-only and is not restricted by this list.\r\n\r\n## Office tools\r\n\r\nThe extension registers a `office_<host>_<op>` tool per op in the shared\r\ncatalog. The catalog is the single source of truth: it lives in\r\n`@dieulc/pi-office-protocol` (`office-catalog.ts`) and BOTH the Pi extension\r\nand the add-in derive from it — the Pi side here, and the pane's bridge op\r\nregistry (`packages/add-in/src/bridge/`) there. Op ids are namespaced by host:\r\n\r\n| Host | Ops |\r\n| --- | --- |\r\n| Excel | `get_overview`, `read_range`, `write_cells`, `fill_formula`, `search_workbook`, `modify_structure`, `format_cells`, `conditional_format`, `charts`, `trace_dependencies`, `explain_formula`, `view_settings`, `comments`, `workbook_history` |\r\n| Word | `get_overview`, `read_document`, `insert_text`, `replace_text`, `format_range`, `insert_blocks`, `insert_table`, `insert_page_break`, `insert_image`, `insert_hyperlink` |\r\n| PowerPoint | `get_overview`, `read_slide`, `add_slide`, `add_text_box`, `format_slide` |\r\n\r\nPlus the host-agnostic discovery tool **`office_list_documents`** (id, name,\r\nhost, focused, windows), always active while the extension is loaded.\r\n\r\n### Active-tool reconciliation\r\n\r\nThe office tools are registered at `session_start` from the catalog, but only\r\n**the ops the currently attached pane advertises are kept active** in the Pi\r\nsession (`pi.setActiveTools()`). Opening an app activates that host's tools;\r\nclosing it deactivates them; everything else stays untouched. Panes that don't\r\nadvertise an `ops` list (legacy 0.2.x clients) are given only the v1 op set.\r\nThis keeps the agent's prompt small and focused on the app actually open.\r\n\r\n### Capability handshake\r\n\r\nPanes send `hello.ops` + `hello.catalogVersion` with the op ids they can\r\nexecute. The server validates them against its own catalog (entries that don't\r\nbelong to the pane's host, or that the server doesn't know, are dropped and\r\ncounted). `callOfficeTool` then rejects any op the pane did not advertise with\r\nan actionable message, so a mismatched add-in/bridge pair fails loudly instead\r\nof silently. That op list — together with `opsIgnoredCount` — is the real\r\nenforcement: `catalogVersion` is informational only (reported in `/health` and\r\nthe `/office` summary), so bumping it never silently changes what a pane may\r\nexecute.\r\n\r\n- `/office` shows each attached pane's host, op count, catalog version, and any\r\n  ignored-op count.\r\n- `/office-tools` lists every registered tool + catalog version.\r\n- `GET /health` exposes `catalogVersion` and per-pane `ops` / `catalogVersion`.\r\n- `before_agent_start` appends a pane-context block (attached host, \"the\r\n  office_* tools edit the live document\", \"never emit HTML for Word\") so the\r\n  agent uses the tools directly. It deliberately does **not** claim formatting is\r\n  universally supported: each tool's schema lists exactly the properties it\r\n  accepts, and the block instructs the agent to say a property is not available\r\n  rather than assert support — consulting `office_word_get_capabilities` when a\r\n  request depends on a Word feature it is unsure about.\r\n\r\nTools never silently degrade: when a requested feature needs an Office.js\r\nrequirement set the host lacks, the call returns a message naming the capability,\r\nthe set + version, the platform, and the remedy. Two CI guards keep the surface\r\nhonest — every advertised formatting property must have a real assignment in the\r\nimplementation that applies it, and every declared capability must either be\r\nconsumed by a caller or be explicitly probe-only. The panes and this extension\r\nboth read the *same* catalog parameter objects (no per-side schema copies), so a\r\nnew parameter cannot drift between the two agents.\r\n\r\nThe pane-side executors are thin delegates to the same local tool factories the\r\nbrowser-only path uses (see `packages/add-in/src/bridge/`), and a parity test\r\n(`packages/add-in/tests/bridge-catalog-parity.test.ts`) fails CI if the pane\r\nregistry ever drifts from the shared catalog.\r\n\r\n## Development\r\n\r\n```bash\r\nnpm run typecheck     # typecheck against @earendil-works/pi-coding-agent 0.85.x\r\nnpm run build         # emit dist/ (for the node smoke tests)\r\nnpm test              # smoke test + end-to-end interop test (real client ↔ real server)\r\n```\r\n\r\n`tests/pane-interop.mjs` wires the **real** add-in `PaneBridgeClient` to the\r\n**real** bridge server through the shared `@dieulc/pi-office-protocol` package —\r\nthe strongest proof the two halves agree on the wire format.\r\n\r\n## Protocol\r\n\r\nThe wire protocol is shared in `@dieulc/pi-office-protocol`\r\n(`packages/protocol`). It is currently at **v2** (document identity + targeting);\r\nbump `BRIDGE_PROTOCOL_VERSION` on breaking changes. See\r\n[`packages/protocol/README.md`](../protocol/README.md) for the v2 changelog.\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}