onbuzz 4.9.13 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/glob/README.md +31 -5
- package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/glob.js +2 -1
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
- package/node_modules/glob/dist/commonjs/index.min.js +3 -3
- package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/pattern.js +4 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
- package/node_modules/glob/dist/esm/glob.d.ts +8 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/glob.js +2 -1
- package/node_modules/glob/dist/esm/glob.js.map +1 -1
- package/node_modules/glob/dist/esm/index.min.js +3 -3
- package/node_modules/glob/dist/esm/index.min.js.map +4 -4
- package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/pattern.js +4 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -1
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
- package/node_modules/glob/node_modules/minimatch/README.md +76 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/package.json +17 -11
- package/node_modules/glob/package.json +10 -13
- package/node_modules/minipass/LICENSE.md +55 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
- package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/commonjs/index.js +13 -3
- package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
- package/node_modules/minipass/dist/esm/index.d.ts +12 -16
- package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/esm/index.js +3 -1
- package/node_modules/minipass/dist/esm/index.js.map +1 -1
- package/node_modules/minipass/package.json +9 -14
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
- package/node_modules/path-scurry/package.json +8 -24
- package/package.json +1 -1
- package/scripts/debug-balance-probe.mjs +35 -35
- package/scripts/push-image.sh +43 -43
- package/scripts/setup-acr.sh +65 -65
- package/scripts/verify-optional-deps.js +96 -1
- package/src/__tests__/composioCliFlags.test.js +239 -239
- package/src/analyzers/CSSAnalyzer.js +298 -297
- package/src/analyzers/ConfigValidator.js +691 -690
- package/src/analyzers/ESLintAnalyzer.js +320 -320
- package/src/analyzers/JavaScriptAnalyzer.js +260 -261
- package/src/analyzers/PrettierFormatter.js +246 -247
- package/src/analyzers/PythonAnalyzer.js +283 -283
- package/src/analyzers/SecurityAnalyzer.js +729 -729
- package/src/analyzers/SparrowAnalyzer.js +341 -341
- package/src/analyzers/TypeScriptAnalyzer.js +247 -247
- package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
- package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
- package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
- package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
- package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
- package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
- package/src/analyzers/codeCloneDetector/detector.js +250 -250
- package/src/analyzers/codeCloneDetector/index.js +194 -192
- package/src/analyzers/codeCloneDetector/parser.js +199 -199
- package/src/core/__tests__/agentPool.test.js +866 -866
- package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
- package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
- package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
- package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
- package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
- package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
- package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
- package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
- package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
- package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
- package/src/core/__tests__/flowEndToEnd.test.js +565 -565
- package/src/core/__tests__/flowFieldMapping.test.js +188 -189
- package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
- package/src/core/__tests__/flowSavePayload.test.js +170 -169
- package/src/core/__tests__/flowTemplates.test.js +311 -311
- package/src/core/__tests__/flowVersionStore.test.js +123 -123
- package/src/core/__tests__/messageProcessor.test.js +669 -669
- package/src/core/__tests__/stateManager.test.js +0 -1
- package/src/core/agentPool.js +2474 -2475
- package/src/core/agentScheduler.js +1 -4
- package/src/core/contextManager.js +708 -708
- package/src/core/flowExecutor.js +1510 -1510
- package/src/core/flowFieldMapping.js +136 -138
- package/src/core/messageProcessor.js +953 -954
- package/src/core/orchestrator.js +593 -595
- package/src/core/stateManager.js +1765 -1752
- package/src/index.js +1221 -1221
- package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
- package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
- package/src/interfaces/__tests__/imageServing.test.js +228 -228
- package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
- package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
- package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
- package/src/interfaces/schedulerRoutes.js +50 -50
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
- package/src/interfaces/terminal/api/session.js +265 -266
- package/src/interfaces/terminal/api/websocket.js +496 -497
- package/src/interfaces/terminal/components/AgentCreator.js +691 -705
- package/src/interfaces/terminal/components/AgentEditor.js +676 -678
- package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
- package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
- package/src/interfaces/terminal/components/Header.js +28 -28
- package/src/interfaces/terminal/components/Layout.js +598 -603
- package/src/interfaces/terminal/components/MessageList.js +280 -281
- package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
- package/src/interfaces/terminal/components/StatusBar.js +2 -0
- package/src/interfaces/terminal/index.js +168 -168
- package/src/interfaces/terminal/state/useAgentControl.js +496 -496
- package/src/interfaces/terminal/state/useAgents.js +537 -537
- package/src/interfaces/terminal/state/useMessages.js +629 -630
- package/src/interfaces/terminal/state/useTools.js +554 -554
- package/src/interfaces/terminal/utils/debugLogger.js +44 -44
- package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
- package/src/interfaces/webServer.js +7578 -7579
- package/src/interfaces/webServer.js.bak +7046 -7046
- package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
- package/src/modules/fileExplorer/controller.js +470 -469
- package/src/modules/fileExplorer/routes.js +285 -286
- package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
- package/src/modules/widget/__tests__/routes.test.js +677 -678
- package/src/modules/widget/__tests__/runtime.test.js +401 -401
- package/src/modules/widget/__tests__/versioning.test.js +309 -309
- package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
- package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
- package/src/modules/widget/routes.js +435 -435
- package/src/modules/widget/runtime/bundle.js +640 -640
- package/src/modules/widget/runtime/webComponentBundle.js +470 -470
- package/src/modules/widget/schema.js +182 -181
- package/src/modules/widget/widgetTool.js +1389 -1389
- package/src/services/__tests__/agentActivityService.test.js +401 -402
- package/src/services/__tests__/benchmarkService.test.js +184 -184
- package/src/services/__tests__/contextInjectionService.test.js +246 -246
- package/src/services/__tests__/conversationQuery.test.js +721 -723
- package/src/services/__tests__/credentialVault.test.js +469 -469
- package/src/services/__tests__/discordService.integration.test.js +638 -639
- package/src/services/__tests__/flowContextService.test.js +590 -590
- package/src/services/__tests__/memoryService.test.js +1 -1
- package/src/services/__tests__/messageSource.test.js +380 -380
- package/src/services/__tests__/modelRouterNaming.test.js +111 -111
- package/src/services/__tests__/projectDetector.test.js +34 -34
- package/src/services/__tests__/promptService.test.js +242 -242
- package/src/services/__tests__/telegramService.test.js +941 -941
- package/src/services/__tests__/tokenCountingService.test.js +48 -48
- package/src/services/agentActivityService.js +419 -420
- package/src/services/aiService.js +2997 -3001
- package/src/services/apiKeyManager.js +359 -359
- package/src/services/benchmarkService.js +196 -196
- package/src/services/codebaseKnowledgeService.js +2 -2
- package/src/services/composioService.js +738 -738
- package/src/services/conversationCompactionService.js +1258 -1257
- package/src/services/credentialVault.js +685 -685
- package/src/services/discordService.js +792 -793
- package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
- package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
- package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
- package/src/services/embeddings/autoRecall.js +218 -219
- package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
- package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
- package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
- package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
- package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
- package/src/services/embeddings/indexers/composioIndexer.js +279 -279
- package/src/services/embeddings/providerInterface.js +206 -206
- package/src/services/embeddings/providers/localProvider.js +11 -7
- package/src/services/embeddings/providers/openaiProvider.js +101 -101
- package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
- package/src/services/errorHandler.js +809 -809
- package/src/services/flowContextService.js +586 -586
- package/src/services/grounding/MockAdapter.js +125 -125
- package/src/services/modelRouterService.js +26 -31
- package/src/services/modelsService.js +322 -322
- package/src/services/ollamaService.js +452 -452
- package/src/services/projectDetector.js +403 -404
- package/src/services/promptService.js +418 -418
- package/src/services/qualityInspector.js +795 -795
- package/src/services/scheduleService.js +726 -726
- package/src/services/serviceRegistry.js +386 -386
- package/src/services/telegrafBot.js +174 -174
- package/src/services/telegramService.js +1972 -1972
- package/src/services/visualEditorBridge.js +1033 -1033
- package/src/services/visualEditorServer.js +1769 -1774
- package/src/services/whatsappService.js +667 -668
- package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
- package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
- package/src/tools/__tests__/agentDelayTool.test.js +342 -342
- package/src/tools/__tests__/baseTool.test.js +3 -3
- package/src/tools/__tests__/codeMapTool.test.js +915 -915
- package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
- package/src/tools/__tests__/fileTreeTool.test.js +274 -274
- package/src/tools/__tests__/filesystemTool.test.js +815 -815
- package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
- package/src/tools/__tests__/imageTool.validator.test.js +194 -194
- package/src/tools/__tests__/jobDoneTool.test.js +580 -581
- package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
- package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
- package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
- package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
- package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
- package/src/tools/__tests__/memoryTool.test.js +1 -1
- package/src/tools/__tests__/seekTool.test.js +282 -282
- package/src/tools/__tests__/skillsTool.search.test.js +164 -164
- package/src/tools/__tests__/skillsTool.test.js +226 -226
- package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
- package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
- package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
- package/src/tools/__tests__/taskManagerTool.test.js +866 -866
- package/src/tools/__tests__/terminalTool.test.js +448 -448
- package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
- package/src/tools/__tests__/userPromptTool.test.js +297 -297
- package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
- package/src/tools/__tests__/webTool.e2e.test.js +609 -603
- package/src/tools/__tests__/webTool.unit.test.js +195 -195
- package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
- package/src/tools/agentCommunicationTool.js +8 -10
- package/src/tools/agentDelayTool.js +496 -497
- package/src/tools/asyncToolManager.js +602 -603
- package/src/tools/baseTool.js +12 -11
- package/src/tools/cloneDetectionTool.js +576 -581
- package/src/tools/codeMapTool.js +0 -6
- package/src/tools/composioTool.js +617 -617
- package/src/tools/dependencyResolverTool.js +1211 -1212
- package/src/tools/desktop/DesktopTool.js +629 -638
- package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
- package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
- package/src/tools/desktop/__tests__/osController.test.js +364 -364
- package/src/tools/desktop/osController.js +491 -491
- package/src/tools/docxTool.js +623 -623
- package/src/tools/excelTool.js +636 -636
- package/src/tools/fileContentReplaceTool.js +5 -7
- package/src/tools/fileSystemTool.js +12 -19
- package/src/tools/fileTreeTool.js +840 -840
- package/src/tools/foundryWebSearchTool.js +273 -273
- package/src/tools/helpTool.js +198 -198
- package/src/tools/imageTool.js +1397 -1397
- package/src/tools/importAnalyzerTool.js +1056 -1056
- package/src/tools/jobDoneTool.js +495 -495
- package/src/tools/memoryTool.js +1 -1
- package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
- package/src/tools/office/pres/archetypes/agenda.js +61 -61
- package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
- package/src/tools/office/pres/archetypes/bigStat.js +140 -142
- package/src/tools/office/pres/archetypes/closing.js +70 -70
- package/src/tools/office/pres/archetypes/hero.js +70 -70
- package/src/tools/office/pres/archetypes/productHero.js +93 -94
- package/src/tools/office/pres/archetypes/table.js +73 -74
- package/src/tools/office/pres/backgrounds/orb.js +66 -66
- package/src/tools/office/pres/components.js +422 -423
- package/src/tools/officeTool.js +441 -441
- package/src/tools/pdfTool.js +625 -627
- package/src/tools/platformControlTool.js +1081 -1081
- package/src/tools/seekTool.js +917 -918
- package/src/tools/skillsTool.js +1 -1
- package/src/tools/staticAnalysisTool.js +2143 -2146
- package/src/tools/taskManagerTool.js +3324 -3324
- package/src/tools/terminalTool.js +2615 -2618
- package/src/tools/videoTool.js +1303 -1303
- package/src/tools/visionTool.js +508 -508
- package/src/tools/visualEditorTool.js +1289 -1290
- package/src/tools/webTool.js +3368 -3368
- package/src/tools/whatsappTool.js +464 -464
- package/src/types/__tests__/agent.test.js +499 -499
- package/src/types/__tests__/contextReference.test.js +606 -606
- package/src/types/__tests__/conversation.test.js +555 -555
- package/src/types/__tests__/toolCommand.test.js +584 -584
- package/src/types/contextReference.js +974 -971
- package/src/types/conversation.js +729 -729
- package/src/types/toolCommand.js +746 -746
- package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
- package/src/utilities/__tests__/auditReport.test.js +328 -328
- package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
- package/src/utilities/__tests__/jsonRepair.test.js +103 -104
- package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
- package/src/utilities/__tests__/platformUtils.test.js +80 -87
- package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
- package/src/utilities/__tests__/toolConstants.test.js +92 -94
- package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
- package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
- package/src/utilities/attachmentValidator.js +284 -288
- package/src/utilities/authCache.js.backup-1779570472481 +121 -121
- package/src/utilities/browserStealth.js +631 -630
- package/src/utilities/configManager.js +616 -617
- package/src/utilities/directoryAccessManager.js +564 -565
- package/src/utilities/fileProcessor.js +308 -307
- package/src/utilities/humanBehavior.js +454 -453
- package/src/utilities/logger.js +479 -479
- package/src/utilities/structuredFileValidator.js +696 -699
- package/src/utilities/tagParser.js +5 -10
- package/src/utilities/userDataDir.js +308 -308
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
- package/node_modules/minipass/LICENSE +0 -15
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
package/src/tools/officeTool.js
CHANGED
|
@@ -1,441 +1,441 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* officeTool — single Office tool covering Word (.docx), Excel (.xlsx),
|
|
3
|
-
* and PowerPoint (.pptx). Replaces the older `doc` and `spreadsheet`
|
|
4
|
-
* tools (which we keep registered for back-compat for one release).
|
|
5
|
-
*
|
|
6
|
-
* Action shape — plural-canonical envelope:
|
|
7
|
-
*
|
|
8
|
-
* {
|
|
9
|
-
* toolId: "office",
|
|
10
|
-
* actions: [
|
|
11
|
-
* { type: "doc.create", outputPath, content },
|
|
12
|
-
* { type: "doc.read", filePath, format? },
|
|
13
|
-
* { type: "doc.info", filePath },
|
|
14
|
-
* { type: "sheet.create", outputPath, content },
|
|
15
|
-
* { type: "sheet.read", filePath, sheetName?, startRow?, endRow?, includeFormulas? },
|
|
16
|
-
* { type: "sheet.info", filePath },
|
|
17
|
-
* { type: "pres.create", outputPath, content },
|
|
18
|
-
* { type: "pres.info", filePath }
|
|
19
|
-
* ]
|
|
20
|
-
* }
|
|
21
|
-
*
|
|
22
|
-
* Forgiving inputs:
|
|
23
|
-
* - Accepts both `type` and `action` as the discriminator.
|
|
24
|
-
* - Accepts a legacy singular envelope `{action, ...}` for one release
|
|
25
|
-
* cycle (reverse-forgiveness pattern). New callers should generate
|
|
26
|
-
* the plural envelope.
|
|
27
|
-
*
|
|
28
|
-
* Output:
|
|
29
|
-
* - Each action returns {success, action, ...payload, output, message}.
|
|
30
|
-
* - Multiple actions in one envelope return `{success, summary, results}`
|
|
31
|
-
* similar to the bulk-agent endpoint.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import { BaseTool } from './baseTool.js';
|
|
35
|
-
import TagParser from '../utilities/tagParser.js';
|
|
36
|
-
import fs from 'fs/promises';
|
|
37
|
-
import path from 'path';
|
|
38
|
-
|
|
39
|
-
import { createDoc, readDoc, docInfo } from './office/officeDoc.js';
|
|
40
|
-
import { createSheet, readSheet, sheetInfo } from './office/officeSheet.js';
|
|
41
|
-
import {
|
|
42
|
-
createPres,
|
|
43
|
-
presInfo,
|
|
44
|
-
readPresOutline,
|
|
45
|
-
fillPresPlaceholders,
|
|
46
|
-
listPresentationSystem,
|
|
47
|
-
} from './office/officePres.js';
|
|
48
|
-
|
|
49
|
-
const SUPPORTED = new Set([
|
|
50
|
-
'doc.create', 'doc.read', 'doc.info',
|
|
51
|
-
'sheet.create', 'sheet.read', 'sheet.info',
|
|
52
|
-
'pres.create', 'pres.info', 'pres.read', 'pres.fill', 'pres.system',
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
const READ_ACTIONS = new Set([
|
|
56
|
-
'doc.read', 'doc.info',
|
|
57
|
-
'sheet.read', 'sheet.info',
|
|
58
|
-
'pres.info', 'pres.read', 'pres.system',
|
|
59
|
-
]);
|
|
60
|
-
const CREATE_ACTIONS = new Set(['doc.create', 'sheet.create', 'pres.create', 'pres.fill']);
|
|
61
|
-
|
|
62
|
-
class OfficeTool extends BaseTool {
|
|
63
|
-
constructor(config = {}, logger = null) {
|
|
64
|
-
super(config, logger);
|
|
65
|
-
this.id = 'office';
|
|
66
|
-
this.name = 'Office Tool';
|
|
67
|
-
this.description = 'Create + read Word (.docx), Excel (.xlsx), and PowerPoint (.pptx) files';
|
|
68
|
-
this.version = '1.0.0';
|
|
69
|
-
this.requiresProject = false;
|
|
70
|
-
this.isAsync = false;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
getDescription() {
|
|
74
|
-
return `
|
|
75
|
-
Office Tool: Create and read Word, Excel, and PowerPoint files in one place.
|
|
76
|
-
|
|
77
|
-
Plural-canonical envelope:
|
|
78
|
-
|
|
79
|
-
\`\`\`json
|
|
80
|
-
{
|
|
81
|
-
"toolId": "office",
|
|
82
|
-
"actions": [
|
|
83
|
-
{ "type": "doc.create", "outputPath": "out/report.docx", "content": { "title": "...", "sections": [ { "children": [ ... ] } ] } },
|
|
84
|
-
{ "type": "sheet.create", "outputPath": "out/data.xlsx", "content": { "sheets": [ { "name": "Q1", "columns": [...], "rows": [...] } ] } },
|
|
85
|
-
{ "type": "pres.create", "outputPath": "out/deck.pptx", "content": { "title": "...", "slides": [ { "layout": "title", "title": "..." } ] } },
|
|
86
|
-
{ "type": "doc.read", "filePath": "in/notes.docx", "format": "text" },
|
|
87
|
-
{ "type": "sheet.read", "filePath": "in/data.xlsx", "sheetName": "Q1", "startRow": 1, "endRow": 50 },
|
|
88
|
-
{ "type": "doc.info", "filePath": "in/notes.docx" },
|
|
89
|
-
{ "type": "sheet.info", "filePath": "in/data.xlsx" },
|
|
90
|
-
{ "type": "pres.info", "filePath": "in/deck.pptx" }
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
\`\`\`
|
|
94
|
-
|
|
95
|
-
Word (.docx) content nodes:
|
|
96
|
-
- heading { level: 1-6, text, color?, alignment? }
|
|
97
|
-
- paragraph { text, bold?, italic?, underline?, fontSize?, color?, alignment?, indent? }
|
|
98
|
-
- richParagraph{ runs: [{ text, bold?, italic?, color?, size?, font? }] }
|
|
99
|
-
- list { ordered?: bool, items: ["..."] or [{ text, level: 0-3 }] }
|
|
100
|
-
- table { headers: [...], rows: [[...]], widths?, headerFill?, alternateFill?, borderColor? }
|
|
101
|
-
- callout { label, content, color? } — left-bar coloured callout
|
|
102
|
-
- hyperlink { text, url }
|
|
103
|
-
- pageBreak / horizontalRule
|
|
104
|
-
|
|
105
|
-
Excel (.xlsx) sheet object:
|
|
106
|
-
- columns [{ header, key?, width?, type: "text|number|currency|percent|date|duration", numFmt? }]
|
|
107
|
-
- rows [ { key: val } | [val, ...] ] — strings starting with "=" become formulas
|
|
108
|
-
- headerStyle { bold?, fontColor?, fill?, alignment?, height? }
|
|
109
|
-
- alternateRowFill #RRGGBB for zebra rows
|
|
110
|
-
- formulas [{ cell: "C2", formula: "=A2+B2" }]
|
|
111
|
-
- cellStyles [{ cell: "B5", bold?, fill?, fontColor?, alignment?, border? }]
|
|
112
|
-
- mergedCells [{ range: "A1:C1" }]
|
|
113
|
-
- freezeRow / freezeColumn
|
|
114
|
-
- autoFilter true | { from, to }
|
|
115
|
-
- conditionalFormatting [{ range, type: "cellIs|containsText|dataBar|colorScale", operator?, value?, fill?, fontColor? }]
|
|
116
|
-
- namedRanges [{ name, range }]
|
|
117
|
-
- charts [...] — best-effort
|
|
118
|
-
|
|
119
|
-
PowerPoint (.pptx) — TWO ways to build, pick by intent:
|
|
120
|
-
|
|
121
|
-
═══ A) THEMED (recommended — looks designed) ═══════════════════════
|
|
122
|
-
Pass a STRING \`theme\` and pick an archetype per slide. The system
|
|
123
|
-
handles colour, typography, spacing, backgrounds, chart styling so
|
|
124
|
-
the deck looks like a designer made it. Use this 95% of the time.
|
|
125
|
-
|
|
126
|
-
Example:
|
|
127
|
-
{
|
|
128
|
-
"type": "pres.create",
|
|
129
|
-
"outputPath": "out/q4-report.pptx",
|
|
130
|
-
"content": {
|
|
131
|
-
"title": "Q4 2026 Investor Update",
|
|
132
|
-
"theme": "tech-bold",
|
|
133
|
-
"palette": "electric-night", // optional (per-theme default if omitted)
|
|
134
|
-
"spacing": "cozy", // optional: tight | cozy | airy
|
|
135
|
-
"shape": "round", // optional: sharp | soft | round | pill
|
|
136
|
-
"background": "mesh", // optional: solid | gradient | mesh | noise | geometric | grid
|
|
137
|
-
"slides": [
|
|
138
|
-
{ "archetype": "hero", "eyebrow": "Q4 2026", "title": "Higher gear.", "subtitle": "Investor update", "author": "Loxia", "date": "May 28" },
|
|
139
|
-
{ "archetype": "agenda", "items": ["Where we are", "What changed", "What's next"] },
|
|
140
|
-
{ "archetype": "sectionHeader", "number": "01", "title": "Where we are", "subtitle": "Growth, retention, runway" },
|
|
141
|
-
{ "archetype": "statCallout", "eyebrow": "ARR growth", "stat": "+47%", "label": "Year-over-year", "footnote": "Through April 2026" },
|
|
142
|
-
{ "archetype": "twoColChart", "title": "Revenue mix", "leftText": { "headline": "Composition shifted", "body": "..." }, "chart": { "type": "donut", "data": [ { "label": "Pro", "value": 62 }, { "label": "Team", "value": 28 }, { "label": "Enterprise", "value": 10 } ] } },
|
|
143
|
-
{ "archetype": "bullets", "title": "Key wins", "items": ["Shipped X", "Closed Y", "Hired Z"] },
|
|
144
|
-
{ "archetype": "twoColText", "title": "Risks & mitigations", "left": { "headline": "Risk", "body": "..." }, "right": { "headline": "Mitigation", "body": "..." } },
|
|
145
|
-
{ "archetype": "quote", "quote": "...", "attribution": "Customer name, role" },
|
|
146
|
-
{ "archetype": "table", "title": "By segment", "headers": ["Segment", "ARR", "Net retention"], "rows": [["Pro", "$4.1M", "118%"], ["Team", "$1.8M", "133%"]] },
|
|
147
|
-
{ "archetype": "closing", "eyebrow": "Thank you", "title": "Let's keep building.", "cta": { "label": "loxia.ai/q4", "url": "https://loxia.ai/q4" } }
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
Themes (pick by use case):
|
|
153
|
-
- "editorial-warm" — narrative/research/brand decks (serif display + sans body, warm cream bg, sharp corners)
|
|
154
|
-
- "tech-bold" — investor pitches, product launches (dark, electric accents, mesh backgrounds, round corners + shadows)
|
|
155
|
-
- "data-heavy" — KPI reviews, analyst reports (dense grid, monospace numerals, restrained colours)
|
|
156
|
-
|
|
157
|
-
Palettes (preset names — every theme has 3):
|
|
158
|
-
- editorial-warm: cream-charcoal · ink-paper · mint-charcoal
|
|
159
|
-
- tech-bold: electric-night · cyber-dawn · neon-violet
|
|
160
|
-
- data-heavy: bloomberg · mono-data · finch
|
|
161
|
-
|
|
162
|
-
Archetypes (slide types — pick per slide):
|
|
163
|
-
- hero — opening slide: { eyebrow?, title, subtitle?, author?, date? }
|
|
164
|
-
- agenda — overview list: { title?, items: [string | {title, hint}] }
|
|
165
|
-
- sectionHeader — section break: { number?, title, subtitle? }
|
|
166
|
-
- statCallout — big stat: { eyebrow?, stat, label, footnote? }
|
|
167
|
-
- bullets — title + list: { title?, subtitle?, items }
|
|
168
|
-
- twoColText — side-by-side: { title?, left: {headline, body}, right: {headline, body} }
|
|
169
|
-
- twoColChart — text + chart: { title?, leftText: {headline, body}, chart: {...} }
|
|
170
|
-
- quote — pull-quote: { quote, attribution?, subtext? }
|
|
171
|
-
- imageFullBleed — full image: { imagePath | imageData, title?, eyebrow?, overlay? }
|
|
172
|
-
- table — data table: { title?, headers, rows }
|
|
173
|
-
- closing — last slide: { eyebrow?, title, cta?, contact? }
|
|
174
|
-
- freeform — escape hatch: { title?, items: [{type, x, y, w, h, ...}] } — coordinates as 0..1 of safe area
|
|
175
|
-
|
|
176
|
-
Chart spec inside twoColChart or freeform:
|
|
177
|
-
{ type: "bar|column|line|area|pie|donut", categories?: [...], series?: [{name, data:[...]}], data?: [{label, value}], stacked?: bool }
|
|
178
|
-
|
|
179
|
-
═══ B) LEGACY (manual coordinates — only for fine control) ═══════════
|
|
180
|
-
Omit \`theme\` (or pass it as an object) and you get the pre-themed
|
|
181
|
-
builder where you place each element yourself. Use this only when
|
|
182
|
-
you genuinely need to draw something the archetypes can't:
|
|
183
|
-
|
|
184
|
-
{
|
|
185
|
-
"type": "pres.create",
|
|
186
|
-
"outputPath": "out/deck.pptx",
|
|
187
|
-
"content": {
|
|
188
|
-
"title": "...",
|
|
189
|
-
"theme": { "fontFamily": "Calibri", "primaryColor": "#1F3864" },
|
|
190
|
-
"slides": [ { "layout": "content", "title": "...", "content": [ { "type": "text", "text": "...", "x": 0.5, "y": 1, "w": 9, "h": 0.7 } ] } ]
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
Discover available themes / archetypes / backgrounds at runtime:
|
|
195
|
-
{ "type": "pres.system" } → { themes, archetypes, backgrounds }
|
|
196
|
-
|
|
197
|
-
Read or fill an existing .pptx:
|
|
198
|
-
{ "type": "pres.read", "filePath": "in/template.pptx" }
|
|
199
|
-
→ { slideCount, slides: [{index, title, body, tokens}], tokens }
|
|
200
|
-
{ "type": "pres.fill", "sourcePath": "in/template.pptx", "outputPath": "out/customised.pptx",
|
|
201
|
-
"values": { "customerName": "Acme", "date": "May 2026", ... } }
|
|
202
|
-
→ { path, size, replaced: {token: count}, unresolved }
|
|
203
|
-
(Templates use {{tokenName}} placeholders. pres.read first to discover them.)
|
|
204
|
-
|
|
205
|
-
Output paths can be relative — they're resolved under the agent's projectDir
|
|
206
|
-
and protected against path traversal.
|
|
207
|
-
`.trim();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
parseParameters(content) {
|
|
211
|
-
// Backwards compatibility for tag-format. Most callers use JSON.
|
|
212
|
-
try {
|
|
213
|
-
const typeMatches = TagParser.extractContent(content, 'type');
|
|
214
|
-
const actionMatches = TagParser.extractContent(content, 'action');
|
|
215
|
-
const filePathMatches = TagParser.extractContent(content, 'filePath');
|
|
216
|
-
const outputPathMatches = TagParser.extractContent(content, 'outputPath');
|
|
217
|
-
const formatMatches = TagParser.extractContent(content, 'format');
|
|
218
|
-
return {
|
|
219
|
-
actions: [{
|
|
220
|
-
type: (typeMatches[0] || actionMatches[0] || 'doc.info').trim(),
|
|
221
|
-
filePath: (filePathMatches[0] || '').trim(),
|
|
222
|
-
outputPath: (outputPathMatches[0] || '').trim(),
|
|
223
|
-
format: (formatMatches[0] || 'text').trim(),
|
|
224
|
-
}],
|
|
225
|
-
};
|
|
226
|
-
} catch (error) {
|
|
227
|
-
throw new Error(`Failed to parse Office tool parameters: ${error.message}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
getSupportedActions() {
|
|
232
|
-
return Array.from(SUPPORTED);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
async execute(params, context) {
|
|
236
|
-
const { projectDir } = context || {};
|
|
237
|
-
|
|
238
|
-
// Normalise envelope: accept plural-canonical OR legacy singular.
|
|
239
|
-
let actions = Array.isArray(params?.actions) ? params.actions : null;
|
|
240
|
-
if (!actions) {
|
|
241
|
-
const single = params?.action ? { ...params, type: params.action } : params;
|
|
242
|
-
if (single && (single.type || single.action)) actions = [single];
|
|
243
|
-
}
|
|
244
|
-
if (!actions || actions.length === 0) {
|
|
245
|
-
return {
|
|
246
|
-
success: false,
|
|
247
|
-
error: 'No actions provided',
|
|
248
|
-
output: 'Provide actions array — e.g. [{ "type": "doc.create", "outputPath": "...", "content": { ... } }]',
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const results = [];
|
|
253
|
-
for (const raw of actions) {
|
|
254
|
-
const type = String(raw.type || raw.action || '').toLowerCase();
|
|
255
|
-
if (!SUPPORTED.has(type)) {
|
|
256
|
-
results.push({
|
|
257
|
-
success: false,
|
|
258
|
-
type,
|
|
259
|
-
error: `Unknown action: ${type}`,
|
|
260
|
-
output: `Unsupported action "${type}". Supported: ${Array.from(SUPPORTED).join(', ')}`,
|
|
261
|
-
});
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
try {
|
|
265
|
-
const result = await this._runOne(type, raw, projectDir);
|
|
266
|
-
results.push(result);
|
|
267
|
-
} catch (err) {
|
|
268
|
-
this.logger?.error?.('officeTool action failed', { type, error: err.message });
|
|
269
|
-
results.push({ success: false, type, error: err.message, output: err.message });
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Single-action: return its result directly (matches the legacy shape).
|
|
274
|
-
if (results.length === 1) return results[0];
|
|
275
|
-
|
|
276
|
-
const ok = results.filter(r => r.success).length;
|
|
277
|
-
const failed = results.length - ok;
|
|
278
|
-
return {
|
|
279
|
-
success: failed === 0,
|
|
280
|
-
summary: { total: results.length, ok, failed },
|
|
281
|
-
results,
|
|
282
|
-
output: `Office: ${ok}/${results.length} actions succeeded`,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async _runOne(type, action, projectDir) {
|
|
287
|
-
if (CREATE_ACTIONS.has(type)) {
|
|
288
|
-
return this._handleCreate(type, action, projectDir);
|
|
289
|
-
}
|
|
290
|
-
if (READ_ACTIONS.has(type)) {
|
|
291
|
-
return this._handleRead(type, action, projectDir);
|
|
292
|
-
}
|
|
293
|
-
return { success: false, type, error: 'Unhandled action', output: `Unhandled: ${type}` };
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async _handleCreate(type, action, projectDir) {
|
|
297
|
-
let outputPath = action.outputPath;
|
|
298
|
-
if (!outputPath) {
|
|
299
|
-
return { success: false, type, error: 'outputPath is required', output: 'Provide an outputPath' };
|
|
300
|
-
}
|
|
301
|
-
// pres.fill takes `values` + `sourcePath` instead of `content`; skip
|
|
302
|
-
// the content check for that single action.
|
|
303
|
-
if (type !== 'pres.fill' && (!action.content || typeof action.content !== 'object')) {
|
|
304
|
-
return { success: false, type, error: 'content is required', output: 'Provide a content object' };
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (!path.isAbsolute(outputPath)) {
|
|
308
|
-
outputPath = path.resolve(projectDir || process.cwd(), outputPath);
|
|
309
|
-
}
|
|
310
|
-
const baseDir = projectDir || process.cwd();
|
|
311
|
-
const normalized = path.normalize(outputPath);
|
|
312
|
-
if (!normalized.startsWith(path.normalize(baseDir))) {
|
|
313
|
-
return { success: false, type, error: 'Path traversal detected', output: 'outputPath must be inside the project directory' };
|
|
314
|
-
}
|
|
315
|
-
await fs.mkdir(path.dirname(normalized), { recursive: true });
|
|
316
|
-
|
|
317
|
-
// Ensure extension matches the action type.
|
|
318
|
-
const extExpected = type === 'doc.create' ? '.docx'
|
|
319
|
-
: type === 'sheet.create' ? '.xlsx'
|
|
320
|
-
: '.pptx';
|
|
321
|
-
let finalPath = normalized;
|
|
322
|
-
if (!finalPath.toLowerCase().endsWith(extExpected)) {
|
|
323
|
-
finalPath += extExpected;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
let writeResult;
|
|
327
|
-
if (type === 'doc.create') writeResult = await createDoc(action.content, finalPath);
|
|
328
|
-
if (type === 'sheet.create') writeResult = await createSheet(action.content, finalPath);
|
|
329
|
-
if (type === 'pres.create') writeResult = await createPres(action.content, finalPath);
|
|
330
|
-
if (type === 'pres.fill') {
|
|
331
|
-
// pres.fill takes sourcePath + values instead of `content`.
|
|
332
|
-
// The path-resolution above already handled outputPath; resolve
|
|
333
|
-
// sourcePath the same way before forwarding.
|
|
334
|
-
let sourcePath = action.sourcePath;
|
|
335
|
-
if (!sourcePath) {
|
|
336
|
-
return { success: false, type, error: 'sourcePath is required', output: 'pres.fill needs sourcePath (a template .pptx)' };
|
|
337
|
-
}
|
|
338
|
-
if (!path.isAbsolute(sourcePath)) sourcePath = path.resolve(projectDir || process.cwd(), sourcePath);
|
|
339
|
-
writeResult = await fillPresPlaceholders({
|
|
340
|
-
sourcePath,
|
|
341
|
-
outputPath: finalPath,
|
|
342
|
-
values: action.values || {},
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
return {
|
|
347
|
-
success: true,
|
|
348
|
-
type,
|
|
349
|
-
outputPath: writeResult.path,
|
|
350
|
-
fileSize: writeResult.size,
|
|
351
|
-
output: `Created ${path.basename(writeResult.path)} (${(writeResult.size / 1024).toFixed(1)} KB)`,
|
|
352
|
-
message: `Wrote ${path.basename(writeResult.path)}`,
|
|
353
|
-
...(writeResult.sheetCount ? { sheetCount: writeResult.sheetCount } : {}),
|
|
354
|
-
...(writeResult.slideCount ? { slideCount: writeResult.slideCount } : {}),
|
|
355
|
-
...(writeResult.theme ? { theme: writeResult.theme } : {}),
|
|
356
|
-
...(writeResult.palette ? { palette: writeResult.palette } : {}),
|
|
357
|
-
...(writeResult.replaced ? { replaced: writeResult.replaced } : {}),
|
|
358
|
-
...(writeResult.unresolved ? { unresolved: writeResult.unresolved } : {}),
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async _handleRead(type, action, projectDir) {
|
|
363
|
-
// pres.system is a pure metadata query — no file involved.
|
|
364
|
-
if (type === 'pres.system') {
|
|
365
|
-
const system = listPresentationSystem();
|
|
366
|
-
return {
|
|
367
|
-
success: true,
|
|
368
|
-
type,
|
|
369
|
-
...system,
|
|
370
|
-
output:
|
|
371
|
-
`Themes: ${system.themes.map(t => t.id).join(', ')}\n` +
|
|
372
|
-
`Archetypes: ${system.archetypes.join(', ')}\n` +
|
|
373
|
-
`Backgrounds: ${system.backgrounds.join(', ')}`,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
let filePath = action.filePath;
|
|
378
|
-
if (!filePath) {
|
|
379
|
-
return { success: false, type, error: 'filePath is required', output: 'Provide a filePath' };
|
|
380
|
-
}
|
|
381
|
-
if (!path.isAbsolute(filePath)) {
|
|
382
|
-
filePath = path.resolve(projectDir || process.cwd(), filePath);
|
|
383
|
-
}
|
|
384
|
-
try {
|
|
385
|
-
await fs.access(filePath);
|
|
386
|
-
} catch {
|
|
387
|
-
return { success: false, type, error: 'File not found', output: `Not found: ${filePath}` };
|
|
388
|
-
}
|
|
389
|
-
// Extension guards
|
|
390
|
-
const lower = filePath.toLowerCase();
|
|
391
|
-
if ((type === 'doc.read' || type === 'doc.info') && !/\.docx?$/.test(lower)) {
|
|
392
|
-
return { success: false, type, error: 'Wrong extension', output: `Expected .docx for ${type}` };
|
|
393
|
-
}
|
|
394
|
-
if ((type === 'sheet.read' || type === 'sheet.info') && !/\.(xlsx|xls|csv)$/.test(lower)) {
|
|
395
|
-
return { success: false, type, error: 'Wrong extension', output: `Expected .xlsx/.csv for ${type}` };
|
|
396
|
-
}
|
|
397
|
-
if ((type === 'pres.info' || type === 'pres.read') && !/\.pptx$/.test(lower)) {
|
|
398
|
-
return { success: false, type, error: 'Wrong extension', output: `Expected .pptx for ${type}` };
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (type === 'doc.info') {
|
|
402
|
-
const info = await docInfo(filePath);
|
|
403
|
-
return { success: true, type, filePath, info, output: `Doc info: ${info.fileName} (${info.wordCount} words, ~${info.estimatedPages} pages)` };
|
|
404
|
-
}
|
|
405
|
-
if (type === 'doc.read') {
|
|
406
|
-
const r = await readDoc(filePath, action.format || 'text');
|
|
407
|
-
return { success: true, type, filePath, format: r.format, content: r.content, output: r.content };
|
|
408
|
-
}
|
|
409
|
-
if (type === 'sheet.info') {
|
|
410
|
-
const info = await sheetInfo(filePath);
|
|
411
|
-
const summary = info.sheets.map(s => `${s.name} (${s.rowCount}r × ${s.columnCount}c)`).join('; ');
|
|
412
|
-
return { success: true, type, filePath, info, output: `Sheet info: ${info.fileName} — ${summary}` };
|
|
413
|
-
}
|
|
414
|
-
if (type === 'sheet.read') {
|
|
415
|
-
const r = await readSheet(filePath, action);
|
|
416
|
-
return {
|
|
417
|
-
success: true, type, filePath,
|
|
418
|
-
sheetName: r.sheetName, totalRows: r.totalRows, rowCount: r.rows.length, rows: r.rows,
|
|
419
|
-
output: `Read ${r.rows.length} rows from "${r.sheetName}"`,
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
if (type === 'pres.info') {
|
|
423
|
-
const info = await presInfo(filePath);
|
|
424
|
-
return { success: true, type, filePath, info, output: `Pres info: ${info.fileName} (${info.slideCount ?? '?'} slides)` };
|
|
425
|
-
}
|
|
426
|
-
if (type === 'pres.read') {
|
|
427
|
-
const outline = await readPresOutline(filePath);
|
|
428
|
-
return {
|
|
429
|
-
success: true, type, filePath,
|
|
430
|
-
slideCount: outline.slideCount,
|
|
431
|
-
slides: outline.slides,
|
|
432
|
-
tokens: outline.tokens,
|
|
433
|
-
output:
|
|
434
|
-
`${outline.slideCount} slides${outline.tokens.length ? `; tokens: ${outline.tokens.join(', ')}` : ''}`,
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
return { success: false, type, error: 'Unhandled', output: `Unhandled: ${type}` };
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
export default OfficeTool;
|
|
1
|
+
/**
|
|
2
|
+
* officeTool — single Office tool covering Word (.docx), Excel (.xlsx),
|
|
3
|
+
* and PowerPoint (.pptx). Replaces the older `doc` and `spreadsheet`
|
|
4
|
+
* tools (which we keep registered for back-compat for one release).
|
|
5
|
+
*
|
|
6
|
+
* Action shape — plural-canonical envelope:
|
|
7
|
+
*
|
|
8
|
+
* {
|
|
9
|
+
* toolId: "office",
|
|
10
|
+
* actions: [
|
|
11
|
+
* { type: "doc.create", outputPath, content },
|
|
12
|
+
* { type: "doc.read", filePath, format? },
|
|
13
|
+
* { type: "doc.info", filePath },
|
|
14
|
+
* { type: "sheet.create", outputPath, content },
|
|
15
|
+
* { type: "sheet.read", filePath, sheetName?, startRow?, endRow?, includeFormulas? },
|
|
16
|
+
* { type: "sheet.info", filePath },
|
|
17
|
+
* { type: "pres.create", outputPath, content },
|
|
18
|
+
* { type: "pres.info", filePath }
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* Forgiving inputs:
|
|
23
|
+
* - Accepts both `type` and `action` as the discriminator.
|
|
24
|
+
* - Accepts a legacy singular envelope `{action, ...}` for one release
|
|
25
|
+
* cycle (reverse-forgiveness pattern). New callers should generate
|
|
26
|
+
* the plural envelope.
|
|
27
|
+
*
|
|
28
|
+
* Output:
|
|
29
|
+
* - Each action returns {success, action, ...payload, output, message}.
|
|
30
|
+
* - Multiple actions in one envelope return `{success, summary, results}`
|
|
31
|
+
* similar to the bulk-agent endpoint.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { BaseTool } from './baseTool.js';
|
|
35
|
+
import TagParser from '../utilities/tagParser.js';
|
|
36
|
+
import fs from 'fs/promises';
|
|
37
|
+
import path from 'path';
|
|
38
|
+
|
|
39
|
+
import { createDoc, readDoc, docInfo } from './office/officeDoc.js';
|
|
40
|
+
import { createSheet, readSheet, sheetInfo } from './office/officeSheet.js';
|
|
41
|
+
import {
|
|
42
|
+
createPres,
|
|
43
|
+
presInfo,
|
|
44
|
+
readPresOutline,
|
|
45
|
+
fillPresPlaceholders,
|
|
46
|
+
listPresentationSystem,
|
|
47
|
+
} from './office/officePres.js';
|
|
48
|
+
|
|
49
|
+
const SUPPORTED = new Set([
|
|
50
|
+
'doc.create', 'doc.read', 'doc.info',
|
|
51
|
+
'sheet.create', 'sheet.read', 'sheet.info',
|
|
52
|
+
'pres.create', 'pres.info', 'pres.read', 'pres.fill', 'pres.system',
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
const READ_ACTIONS = new Set([
|
|
56
|
+
'doc.read', 'doc.info',
|
|
57
|
+
'sheet.read', 'sheet.info',
|
|
58
|
+
'pres.info', 'pres.read', 'pres.system',
|
|
59
|
+
]);
|
|
60
|
+
const CREATE_ACTIONS = new Set(['doc.create', 'sheet.create', 'pres.create', 'pres.fill']);
|
|
61
|
+
|
|
62
|
+
class OfficeTool extends BaseTool {
|
|
63
|
+
constructor(config = {}, logger = null) {
|
|
64
|
+
super(config, logger);
|
|
65
|
+
this.id = 'office';
|
|
66
|
+
this.name = 'Office Tool';
|
|
67
|
+
this.description = 'Create + read Word (.docx), Excel (.xlsx), and PowerPoint (.pptx) files';
|
|
68
|
+
this.version = '1.0.0';
|
|
69
|
+
this.requiresProject = false;
|
|
70
|
+
this.isAsync = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getDescription() {
|
|
74
|
+
return `
|
|
75
|
+
Office Tool: Create and read Word, Excel, and PowerPoint files in one place.
|
|
76
|
+
|
|
77
|
+
Plural-canonical envelope:
|
|
78
|
+
|
|
79
|
+
\`\`\`json
|
|
80
|
+
{
|
|
81
|
+
"toolId": "office",
|
|
82
|
+
"actions": [
|
|
83
|
+
{ "type": "doc.create", "outputPath": "out/report.docx", "content": { "title": "...", "sections": [ { "children": [ ... ] } ] } },
|
|
84
|
+
{ "type": "sheet.create", "outputPath": "out/data.xlsx", "content": { "sheets": [ { "name": "Q1", "columns": [...], "rows": [...] } ] } },
|
|
85
|
+
{ "type": "pres.create", "outputPath": "out/deck.pptx", "content": { "title": "...", "slides": [ { "layout": "title", "title": "..." } ] } },
|
|
86
|
+
{ "type": "doc.read", "filePath": "in/notes.docx", "format": "text" },
|
|
87
|
+
{ "type": "sheet.read", "filePath": "in/data.xlsx", "sheetName": "Q1", "startRow": 1, "endRow": 50 },
|
|
88
|
+
{ "type": "doc.info", "filePath": "in/notes.docx" },
|
|
89
|
+
{ "type": "sheet.info", "filePath": "in/data.xlsx" },
|
|
90
|
+
{ "type": "pres.info", "filePath": "in/deck.pptx" }
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
\`\`\`
|
|
94
|
+
|
|
95
|
+
Word (.docx) content nodes:
|
|
96
|
+
- heading { level: 1-6, text, color?, alignment? }
|
|
97
|
+
- paragraph { text, bold?, italic?, underline?, fontSize?, color?, alignment?, indent? }
|
|
98
|
+
- richParagraph{ runs: [{ text, bold?, italic?, color?, size?, font? }] }
|
|
99
|
+
- list { ordered?: bool, items: ["..."] or [{ text, level: 0-3 }] }
|
|
100
|
+
- table { headers: [...], rows: [[...]], widths?, headerFill?, alternateFill?, borderColor? }
|
|
101
|
+
- callout { label, content, color? } — left-bar coloured callout
|
|
102
|
+
- hyperlink { text, url }
|
|
103
|
+
- pageBreak / horizontalRule
|
|
104
|
+
|
|
105
|
+
Excel (.xlsx) sheet object:
|
|
106
|
+
- columns [{ header, key?, width?, type: "text|number|currency|percent|date|duration", numFmt? }]
|
|
107
|
+
- rows [ { key: val } | [val, ...] ] — strings starting with "=" become formulas
|
|
108
|
+
- headerStyle { bold?, fontColor?, fill?, alignment?, height? }
|
|
109
|
+
- alternateRowFill #RRGGBB for zebra rows
|
|
110
|
+
- formulas [{ cell: "C2", formula: "=A2+B2" }]
|
|
111
|
+
- cellStyles [{ cell: "B5", bold?, fill?, fontColor?, alignment?, border? }]
|
|
112
|
+
- mergedCells [{ range: "A1:C1" }]
|
|
113
|
+
- freezeRow / freezeColumn
|
|
114
|
+
- autoFilter true | { from, to }
|
|
115
|
+
- conditionalFormatting [{ range, type: "cellIs|containsText|dataBar|colorScale", operator?, value?, fill?, fontColor? }]
|
|
116
|
+
- namedRanges [{ name, range }]
|
|
117
|
+
- charts [...] — best-effort
|
|
118
|
+
|
|
119
|
+
PowerPoint (.pptx) — TWO ways to build, pick by intent:
|
|
120
|
+
|
|
121
|
+
═══ A) THEMED (recommended — looks designed) ═══════════════════════
|
|
122
|
+
Pass a STRING \`theme\` and pick an archetype per slide. The system
|
|
123
|
+
handles colour, typography, spacing, backgrounds, chart styling so
|
|
124
|
+
the deck looks like a designer made it. Use this 95% of the time.
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
{
|
|
128
|
+
"type": "pres.create",
|
|
129
|
+
"outputPath": "out/q4-report.pptx",
|
|
130
|
+
"content": {
|
|
131
|
+
"title": "Q4 2026 Investor Update",
|
|
132
|
+
"theme": "tech-bold",
|
|
133
|
+
"palette": "electric-night", // optional (per-theme default if omitted)
|
|
134
|
+
"spacing": "cozy", // optional: tight | cozy | airy
|
|
135
|
+
"shape": "round", // optional: sharp | soft | round | pill
|
|
136
|
+
"background": "mesh", // optional: solid | gradient | mesh | noise | geometric | grid
|
|
137
|
+
"slides": [
|
|
138
|
+
{ "archetype": "hero", "eyebrow": "Q4 2026", "title": "Higher gear.", "subtitle": "Investor update", "author": "Loxia", "date": "May 28" },
|
|
139
|
+
{ "archetype": "agenda", "items": ["Where we are", "What changed", "What's next"] },
|
|
140
|
+
{ "archetype": "sectionHeader", "number": "01", "title": "Where we are", "subtitle": "Growth, retention, runway" },
|
|
141
|
+
{ "archetype": "statCallout", "eyebrow": "ARR growth", "stat": "+47%", "label": "Year-over-year", "footnote": "Through April 2026" },
|
|
142
|
+
{ "archetype": "twoColChart", "title": "Revenue mix", "leftText": { "headline": "Composition shifted", "body": "..." }, "chart": { "type": "donut", "data": [ { "label": "Pro", "value": 62 }, { "label": "Team", "value": 28 }, { "label": "Enterprise", "value": 10 } ] } },
|
|
143
|
+
{ "archetype": "bullets", "title": "Key wins", "items": ["Shipped X", "Closed Y", "Hired Z"] },
|
|
144
|
+
{ "archetype": "twoColText", "title": "Risks & mitigations", "left": { "headline": "Risk", "body": "..." }, "right": { "headline": "Mitigation", "body": "..." } },
|
|
145
|
+
{ "archetype": "quote", "quote": "...", "attribution": "Customer name, role" },
|
|
146
|
+
{ "archetype": "table", "title": "By segment", "headers": ["Segment", "ARR", "Net retention"], "rows": [["Pro", "$4.1M", "118%"], ["Team", "$1.8M", "133%"]] },
|
|
147
|
+
{ "archetype": "closing", "eyebrow": "Thank you", "title": "Let's keep building.", "cta": { "label": "loxia.ai/q4", "url": "https://loxia.ai/q4" } }
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
Themes (pick by use case):
|
|
153
|
+
- "editorial-warm" — narrative/research/brand decks (serif display + sans body, warm cream bg, sharp corners)
|
|
154
|
+
- "tech-bold" — investor pitches, product launches (dark, electric accents, mesh backgrounds, round corners + shadows)
|
|
155
|
+
- "data-heavy" — KPI reviews, analyst reports (dense grid, monospace numerals, restrained colours)
|
|
156
|
+
|
|
157
|
+
Palettes (preset names — every theme has 3):
|
|
158
|
+
- editorial-warm: cream-charcoal · ink-paper · mint-charcoal
|
|
159
|
+
- tech-bold: electric-night · cyber-dawn · neon-violet
|
|
160
|
+
- data-heavy: bloomberg · mono-data · finch
|
|
161
|
+
|
|
162
|
+
Archetypes (slide types — pick per slide):
|
|
163
|
+
- hero — opening slide: { eyebrow?, title, subtitle?, author?, date? }
|
|
164
|
+
- agenda — overview list: { title?, items: [string | {title, hint}] }
|
|
165
|
+
- sectionHeader — section break: { number?, title, subtitle? }
|
|
166
|
+
- statCallout — big stat: { eyebrow?, stat, label, footnote? }
|
|
167
|
+
- bullets — title + list: { title?, subtitle?, items }
|
|
168
|
+
- twoColText — side-by-side: { title?, left: {headline, body}, right: {headline, body} }
|
|
169
|
+
- twoColChart — text + chart: { title?, leftText: {headline, body}, chart: {...} }
|
|
170
|
+
- quote — pull-quote: { quote, attribution?, subtext? }
|
|
171
|
+
- imageFullBleed — full image: { imagePath | imageData, title?, eyebrow?, overlay? }
|
|
172
|
+
- table — data table: { title?, headers, rows }
|
|
173
|
+
- closing — last slide: { eyebrow?, title, cta?, contact? }
|
|
174
|
+
- freeform — escape hatch: { title?, items: [{type, x, y, w, h, ...}] } — coordinates as 0..1 of safe area
|
|
175
|
+
|
|
176
|
+
Chart spec inside twoColChart or freeform:
|
|
177
|
+
{ type: "bar|column|line|area|pie|donut", categories?: [...], series?: [{name, data:[...]}], data?: [{label, value}], stacked?: bool }
|
|
178
|
+
|
|
179
|
+
═══ B) LEGACY (manual coordinates — only for fine control) ═══════════
|
|
180
|
+
Omit \`theme\` (or pass it as an object) and you get the pre-themed
|
|
181
|
+
builder where you place each element yourself. Use this only when
|
|
182
|
+
you genuinely need to draw something the archetypes can't:
|
|
183
|
+
|
|
184
|
+
{
|
|
185
|
+
"type": "pres.create",
|
|
186
|
+
"outputPath": "out/deck.pptx",
|
|
187
|
+
"content": {
|
|
188
|
+
"title": "...",
|
|
189
|
+
"theme": { "fontFamily": "Calibri", "primaryColor": "#1F3864" },
|
|
190
|
+
"slides": [ { "layout": "content", "title": "...", "content": [ { "type": "text", "text": "...", "x": 0.5, "y": 1, "w": 9, "h": 0.7 } ] } ]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
Discover available themes / archetypes / backgrounds at runtime:
|
|
195
|
+
{ "type": "pres.system" } → { themes, archetypes, backgrounds }
|
|
196
|
+
|
|
197
|
+
Read or fill an existing .pptx:
|
|
198
|
+
{ "type": "pres.read", "filePath": "in/template.pptx" }
|
|
199
|
+
→ { slideCount, slides: [{index, title, body, tokens}], tokens }
|
|
200
|
+
{ "type": "pres.fill", "sourcePath": "in/template.pptx", "outputPath": "out/customised.pptx",
|
|
201
|
+
"values": { "customerName": "Acme", "date": "May 2026", ... } }
|
|
202
|
+
→ { path, size, replaced: {token: count}, unresolved }
|
|
203
|
+
(Templates use {{tokenName}} placeholders. pres.read first to discover them.)
|
|
204
|
+
|
|
205
|
+
Output paths can be relative — they're resolved under the agent's projectDir
|
|
206
|
+
and protected against path traversal.
|
|
207
|
+
`.trim();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
parseParameters(content) {
|
|
211
|
+
// Backwards compatibility for tag-format. Most callers use JSON.
|
|
212
|
+
try {
|
|
213
|
+
const typeMatches = TagParser.extractContent(content, 'type');
|
|
214
|
+
const actionMatches = TagParser.extractContent(content, 'action');
|
|
215
|
+
const filePathMatches = TagParser.extractContent(content, 'filePath');
|
|
216
|
+
const outputPathMatches = TagParser.extractContent(content, 'outputPath');
|
|
217
|
+
const formatMatches = TagParser.extractContent(content, 'format');
|
|
218
|
+
return {
|
|
219
|
+
actions: [{
|
|
220
|
+
type: (typeMatches[0] || actionMatches[0] || 'doc.info').trim(),
|
|
221
|
+
filePath: (filePathMatches[0] || '').trim(),
|
|
222
|
+
outputPath: (outputPathMatches[0] || '').trim(),
|
|
223
|
+
format: (formatMatches[0] || 'text').trim(),
|
|
224
|
+
}],
|
|
225
|
+
};
|
|
226
|
+
} catch (error) {
|
|
227
|
+
throw new Error(`Failed to parse Office tool parameters: ${error.message}`, { cause: error });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
getSupportedActions() {
|
|
232
|
+
return Array.from(SUPPORTED);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async execute(params, context) {
|
|
236
|
+
const { projectDir } = context || {};
|
|
237
|
+
|
|
238
|
+
// Normalise envelope: accept plural-canonical OR legacy singular.
|
|
239
|
+
let actions = Array.isArray(params?.actions) ? params.actions : null;
|
|
240
|
+
if (!actions) {
|
|
241
|
+
const single = params?.action ? { ...params, type: params.action } : params;
|
|
242
|
+
if (single && (single.type || single.action)) actions = [single];
|
|
243
|
+
}
|
|
244
|
+
if (!actions || actions.length === 0) {
|
|
245
|
+
return {
|
|
246
|
+
success: false,
|
|
247
|
+
error: 'No actions provided',
|
|
248
|
+
output: 'Provide actions array — e.g. [{ "type": "doc.create", "outputPath": "...", "content": { ... } }]',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const results = [];
|
|
253
|
+
for (const raw of actions) {
|
|
254
|
+
const type = String(raw.type || raw.action || '').toLowerCase();
|
|
255
|
+
if (!SUPPORTED.has(type)) {
|
|
256
|
+
results.push({
|
|
257
|
+
success: false,
|
|
258
|
+
type,
|
|
259
|
+
error: `Unknown action: ${type}`,
|
|
260
|
+
output: `Unsupported action "${type}". Supported: ${Array.from(SUPPORTED).join(', ')}`,
|
|
261
|
+
});
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const result = await this._runOne(type, raw, projectDir);
|
|
266
|
+
results.push(result);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
this.logger?.error?.('officeTool action failed', { type, error: err.message });
|
|
269
|
+
results.push({ success: false, type, error: err.message, output: err.message });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Single-action: return its result directly (matches the legacy shape).
|
|
274
|
+
if (results.length === 1) return results[0];
|
|
275
|
+
|
|
276
|
+
const ok = results.filter(r => r.success).length;
|
|
277
|
+
const failed = results.length - ok;
|
|
278
|
+
return {
|
|
279
|
+
success: failed === 0,
|
|
280
|
+
summary: { total: results.length, ok, failed },
|
|
281
|
+
results,
|
|
282
|
+
output: `Office: ${ok}/${results.length} actions succeeded`,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async _runOne(type, action, projectDir) {
|
|
287
|
+
if (CREATE_ACTIONS.has(type)) {
|
|
288
|
+
return this._handleCreate(type, action, projectDir);
|
|
289
|
+
}
|
|
290
|
+
if (READ_ACTIONS.has(type)) {
|
|
291
|
+
return this._handleRead(type, action, projectDir);
|
|
292
|
+
}
|
|
293
|
+
return { success: false, type, error: 'Unhandled action', output: `Unhandled: ${type}` };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async _handleCreate(type, action, projectDir) {
|
|
297
|
+
let outputPath = action.outputPath;
|
|
298
|
+
if (!outputPath) {
|
|
299
|
+
return { success: false, type, error: 'outputPath is required', output: 'Provide an outputPath' };
|
|
300
|
+
}
|
|
301
|
+
// pres.fill takes `values` + `sourcePath` instead of `content`; skip
|
|
302
|
+
// the content check for that single action.
|
|
303
|
+
if (type !== 'pres.fill' && (!action.content || typeof action.content !== 'object')) {
|
|
304
|
+
return { success: false, type, error: 'content is required', output: 'Provide a content object' };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (!path.isAbsolute(outputPath)) {
|
|
308
|
+
outputPath = path.resolve(projectDir || process.cwd(), outputPath);
|
|
309
|
+
}
|
|
310
|
+
const baseDir = projectDir || process.cwd();
|
|
311
|
+
const normalized = path.normalize(outputPath);
|
|
312
|
+
if (!normalized.startsWith(path.normalize(baseDir))) {
|
|
313
|
+
return { success: false, type, error: 'Path traversal detected', output: 'outputPath must be inside the project directory' };
|
|
314
|
+
}
|
|
315
|
+
await fs.mkdir(path.dirname(normalized), { recursive: true });
|
|
316
|
+
|
|
317
|
+
// Ensure extension matches the action type.
|
|
318
|
+
const extExpected = type === 'doc.create' ? '.docx'
|
|
319
|
+
: type === 'sheet.create' ? '.xlsx'
|
|
320
|
+
: '.pptx';
|
|
321
|
+
let finalPath = normalized;
|
|
322
|
+
if (!finalPath.toLowerCase().endsWith(extExpected)) {
|
|
323
|
+
finalPath += extExpected;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
let writeResult;
|
|
327
|
+
if (type === 'doc.create') writeResult = await createDoc(action.content, finalPath);
|
|
328
|
+
if (type === 'sheet.create') writeResult = await createSheet(action.content, finalPath);
|
|
329
|
+
if (type === 'pres.create') writeResult = await createPres(action.content, finalPath);
|
|
330
|
+
if (type === 'pres.fill') {
|
|
331
|
+
// pres.fill takes sourcePath + values instead of `content`.
|
|
332
|
+
// The path-resolution above already handled outputPath; resolve
|
|
333
|
+
// sourcePath the same way before forwarding.
|
|
334
|
+
let sourcePath = action.sourcePath;
|
|
335
|
+
if (!sourcePath) {
|
|
336
|
+
return { success: false, type, error: 'sourcePath is required', output: 'pres.fill needs sourcePath (a template .pptx)' };
|
|
337
|
+
}
|
|
338
|
+
if (!path.isAbsolute(sourcePath)) sourcePath = path.resolve(projectDir || process.cwd(), sourcePath);
|
|
339
|
+
writeResult = await fillPresPlaceholders({
|
|
340
|
+
sourcePath,
|
|
341
|
+
outputPath: finalPath,
|
|
342
|
+
values: action.values || {},
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
success: true,
|
|
348
|
+
type,
|
|
349
|
+
outputPath: writeResult.path,
|
|
350
|
+
fileSize: writeResult.size,
|
|
351
|
+
output: `Created ${path.basename(writeResult.path)} (${(writeResult.size / 1024).toFixed(1)} KB)`,
|
|
352
|
+
message: `Wrote ${path.basename(writeResult.path)}`,
|
|
353
|
+
...(writeResult.sheetCount ? { sheetCount: writeResult.sheetCount } : {}),
|
|
354
|
+
...(writeResult.slideCount ? { slideCount: writeResult.slideCount } : {}),
|
|
355
|
+
...(writeResult.theme ? { theme: writeResult.theme } : {}),
|
|
356
|
+
...(writeResult.palette ? { palette: writeResult.palette } : {}),
|
|
357
|
+
...(writeResult.replaced ? { replaced: writeResult.replaced } : {}),
|
|
358
|
+
...(writeResult.unresolved ? { unresolved: writeResult.unresolved } : {}),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async _handleRead(type, action, projectDir) {
|
|
363
|
+
// pres.system is a pure metadata query — no file involved.
|
|
364
|
+
if (type === 'pres.system') {
|
|
365
|
+
const system = listPresentationSystem();
|
|
366
|
+
return {
|
|
367
|
+
success: true,
|
|
368
|
+
type,
|
|
369
|
+
...system,
|
|
370
|
+
output:
|
|
371
|
+
`Themes: ${system.themes.map(t => t.id).join(', ')}\n` +
|
|
372
|
+
`Archetypes: ${system.archetypes.join(', ')}\n` +
|
|
373
|
+
`Backgrounds: ${system.backgrounds.join(', ')}`,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
let filePath = action.filePath;
|
|
378
|
+
if (!filePath) {
|
|
379
|
+
return { success: false, type, error: 'filePath is required', output: 'Provide a filePath' };
|
|
380
|
+
}
|
|
381
|
+
if (!path.isAbsolute(filePath)) {
|
|
382
|
+
filePath = path.resolve(projectDir || process.cwd(), filePath);
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
await fs.access(filePath);
|
|
386
|
+
} catch {
|
|
387
|
+
return { success: false, type, error: 'File not found', output: `Not found: ${filePath}` };
|
|
388
|
+
}
|
|
389
|
+
// Extension guards
|
|
390
|
+
const lower = filePath.toLowerCase();
|
|
391
|
+
if ((type === 'doc.read' || type === 'doc.info') && !/\.docx?$/.test(lower)) {
|
|
392
|
+
return { success: false, type, error: 'Wrong extension', output: `Expected .docx for ${type}` };
|
|
393
|
+
}
|
|
394
|
+
if ((type === 'sheet.read' || type === 'sheet.info') && !/\.(xlsx|xls|csv)$/.test(lower)) {
|
|
395
|
+
return { success: false, type, error: 'Wrong extension', output: `Expected .xlsx/.csv for ${type}` };
|
|
396
|
+
}
|
|
397
|
+
if ((type === 'pres.info' || type === 'pres.read') && !/\.pptx$/.test(lower)) {
|
|
398
|
+
return { success: false, type, error: 'Wrong extension', output: `Expected .pptx for ${type}` };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (type === 'doc.info') {
|
|
402
|
+
const info = await docInfo(filePath);
|
|
403
|
+
return { success: true, type, filePath, info, output: `Doc info: ${info.fileName} (${info.wordCount} words, ~${info.estimatedPages} pages)` };
|
|
404
|
+
}
|
|
405
|
+
if (type === 'doc.read') {
|
|
406
|
+
const r = await readDoc(filePath, action.format || 'text');
|
|
407
|
+
return { success: true, type, filePath, format: r.format, content: r.content, output: r.content };
|
|
408
|
+
}
|
|
409
|
+
if (type === 'sheet.info') {
|
|
410
|
+
const info = await sheetInfo(filePath);
|
|
411
|
+
const summary = info.sheets.map(s => `${s.name} (${s.rowCount}r × ${s.columnCount}c)`).join('; ');
|
|
412
|
+
return { success: true, type, filePath, info, output: `Sheet info: ${info.fileName} — ${summary}` };
|
|
413
|
+
}
|
|
414
|
+
if (type === 'sheet.read') {
|
|
415
|
+
const r = await readSheet(filePath, action);
|
|
416
|
+
return {
|
|
417
|
+
success: true, type, filePath,
|
|
418
|
+
sheetName: r.sheetName, totalRows: r.totalRows, rowCount: r.rows.length, rows: r.rows,
|
|
419
|
+
output: `Read ${r.rows.length} rows from "${r.sheetName}"`,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
if (type === 'pres.info') {
|
|
423
|
+
const info = await presInfo(filePath);
|
|
424
|
+
return { success: true, type, filePath, info, output: `Pres info: ${info.fileName} (${info.slideCount ?? '?'} slides)` };
|
|
425
|
+
}
|
|
426
|
+
if (type === 'pres.read') {
|
|
427
|
+
const outline = await readPresOutline(filePath);
|
|
428
|
+
return {
|
|
429
|
+
success: true, type, filePath,
|
|
430
|
+
slideCount: outline.slideCount,
|
|
431
|
+
slides: outline.slides,
|
|
432
|
+
tokens: outline.tokens,
|
|
433
|
+
output:
|
|
434
|
+
`${outline.slideCount} slides${outline.tokens.length ? `; tokens: ${outline.tokens.join(', ')}` : ''}`,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
return { success: false, type, error: 'Unhandled', output: `Unhandled: ${type}` };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export default OfficeTool;
|