@tulex-cli/tulex-code 0.1.1
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/README.md +54 -0
- package/dist/.last_build +0 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +121 -0
- package/dist/src/acp-integration/acpAgent.d.ts +59 -0
- package/dist/src/acp-integration/acpAgent.js +3646 -0
- package/dist/src/acp-integration/acpAgent.js.map +1 -0
- package/dist/src/acp-integration/acpAgent.test.d.ts +6 -0
- package/dist/src/acp-integration/acpAgent.test.js +3690 -0
- package/dist/src/acp-integration/acpAgent.test.js.map +1 -0
- package/dist/src/acp-integration/acpAgent.worktree.test.d.ts +16 -0
- package/dist/src/acp-integration/acpAgent.worktree.test.js +354 -0
- package/dist/src/acp-integration/acpAgent.worktree.test.js.map +1 -0
- package/dist/src/acp-integration/authMethods.d.ts +9 -0
- package/dist/src/acp-integration/authMethods.js +28 -0
- package/dist/src/acp-integration/authMethods.js.map +1 -0
- package/dist/src/acp-integration/authMethods.test.d.ts +6 -0
- package/dist/src/acp-integration/authMethods.test.js +23 -0
- package/dist/src/acp-integration/authMethods.test.js.map +1 -0
- package/dist/src/acp-integration/authPreflight.test.d.ts +6 -0
- package/dist/src/acp-integration/authPreflight.test.js +54 -0
- package/dist/src/acp-integration/authPreflight.test.js.map +1 -0
- package/dist/src/acp-integration/errorCodes.d.ts +15 -0
- package/dist/src/acp-integration/errorCodes.js +22 -0
- package/dist/src/acp-integration/errorCodes.js.map +1 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.d.ts +2 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.js +5 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.js.map +1 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.test.d.ts +1 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.test.js +29 -0
- package/dist/src/acp-integration/runtimeOutputDirContext.test.js.map +1 -0
- package/dist/src/acp-integration/service/filesystem.d.ts +17 -0
- package/dist/src/acp-integration/service/filesystem.js +73 -0
- package/dist/src/acp-integration/service/filesystem.js.map +1 -0
- package/dist/src/acp-integration/service/filesystem.test.d.ts +6 -0
- package/dist/src/acp-integration/service/filesystem.test.js +85 -0
- package/dist/src/acp-integration/service/filesystem.test.js.map +1 -0
- package/dist/src/acp-integration/session/HistoryReplayer.d.ts +63 -0
- package/dist/src/acp-integration/session/HistoryReplayer.js +222 -0
- package/dist/src/acp-integration/session/HistoryReplayer.js.map +1 -0
- package/dist/src/acp-integration/session/HistoryReplayer.test.d.ts +6 -0
- package/dist/src/acp-integration/session/HistoryReplayer.test.js +405 -0
- package/dist/src/acp-integration/session/HistoryReplayer.test.js.map +1 -0
- package/dist/src/acp-integration/session/Session.d.ts +150 -0
- package/dist/src/acp-integration/session/Session.js +2381 -0
- package/dist/src/acp-integration/session/Session.js.map +1 -0
- package/dist/src/acp-integration/session/Session.test.d.ts +6 -0
- package/dist/src/acp-integration/session/Session.test.js +3845 -0
- package/dist/src/acp-integration/session/Session.test.js.map +1 -0
- package/dist/src/acp-integration/session/Session.worktree.test.d.ts +18 -0
- package/dist/src/acp-integration/session/Session.worktree.test.js +195 -0
- package/dist/src/acp-integration/session/Session.worktree.test.js.map +1 -0
- package/dist/src/acp-integration/session/SubAgentTracker.d.ts +58 -0
- package/dist/src/acp-integration/session/SubAgentTracker.js +208 -0
- package/dist/src/acp-integration/session/SubAgentTracker.js.map +1 -0
- package/dist/src/acp-integration/session/SubAgentTracker.test.d.ts +6 -0
- package/dist/src/acp-integration/session/SubAgentTracker.test.js +612 -0
- package/dist/src/acp-integration/session/SubAgentTracker.test.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/BaseEmitter.d.ts +34 -0
- package/dist/src/acp-integration/session/emitters/BaseEmitter.js +53 -0
- package/dist/src/acp-integration/session/emitters/BaseEmitter.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.d.ts +61 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.js +124 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.test.d.ts +6 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.test.js +202 -0
- package/dist/src/acp-integration/session/emitters/MessageEmitter.test.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.d.ts +39 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.js +83 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.test.d.ts +6 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.test.js +176 -0
- package/dist/src/acp-integration/session/emitters/PlanEmitter.test.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.d.ts +82 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.js +284 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.test.d.ts +6 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.test.js +607 -0
- package/dist/src/acp-integration/session/emitters/ToolCallEmitter.test.js.map +1 -0
- package/dist/src/acp-integration/session/emitters/index.d.ts +9 -0
- package/dist/src/acp-integration/session/emitters/index.js +10 -0
- package/dist/src/acp-integration/session/emitters/index.js.map +1 -0
- package/dist/src/acp-integration/session/index.d.ts +24 -0
- package/dist/src/acp-integration/session/index.js +16 -0
- package/dist/src/acp-integration/session/index.js.map +1 -0
- package/dist/src/acp-integration/session/permissionUtils.d.ts +9 -0
- package/dist/src/acp-integration/session/permissionUtils.js +165 -0
- package/dist/src/acp-integration/session/permissionUtils.js.map +1 -0
- package/dist/src/acp-integration/session/permissionUtils.test.d.ts +6 -0
- package/dist/src/acp-integration/session/permissionUtils.test.js +83 -0
- package/dist/src/acp-integration/session/permissionUtils.test.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.d.ts +26 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.js +131 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.test.d.ts +6 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.test.js +188 -0
- package/dist/src/acp-integration/session/rewrite/LlmRewriter.test.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.d.ts +42 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.js +159 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.test.d.ts +6 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.test.js +255 -0
- package/dist/src/acp-integration/session/rewrite/MessageRewriteMiddleware.test.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/README.md +35 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.d.ts +25 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.js +53 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.test.d.ts +6 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.test.js +95 -0
- package/dist/src/acp-integration/session/rewrite/TurnBuffer.test.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/config.d.ts +13 -0
- package/dist/src/acp-integration/session/rewrite/config.js +19 -0
- package/dist/src/acp-integration/session/rewrite/config.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/config.test.d.ts +6 -0
- package/dist/src/acp-integration/session/rewrite/config.test.js +72 -0
- package/dist/src/acp-integration/session/rewrite/config.test.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/index.d.ts +8 -0
- package/dist/src/acp-integration/session/rewrite/index.js +8 -0
- package/dist/src/acp-integration/session/rewrite/index.js.map +1 -0
- package/dist/src/acp-integration/session/rewrite/types.d.ts +36 -0
- package/dist/src/acp-integration/session/rewrite/types.js +7 -0
- package/dist/src/acp-integration/session/rewrite/types.js.map +1 -0
- package/dist/src/acp-integration/session/types.d.ts +93 -0
- package/dist/src/acp-integration/session/types.js +7 -0
- package/dist/src/acp-integration/session/types.js.map +1 -0
- package/dist/src/commands/auth.d.ts +9 -0
- package/dist/src/commands/auth.js +55 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/auth.test.d.ts +6 -0
- package/dist/src/commands/auth.test.js +84 -0
- package/dist/src/commands/auth.test.js.map +1 -0
- package/dist/src/commands/channel/channel-registry.d.ts +4 -0
- package/dist/src/commands/channel/channel-registry.js +33 -0
- package/dist/src/commands/channel/channel-registry.js.map +1 -0
- package/dist/src/commands/channel/config-utils.d.ts +4 -0
- package/dist/src/commands/channel/config-utils.js +66 -0
- package/dist/src/commands/channel/config-utils.js.map +1 -0
- package/dist/src/commands/channel/config-utils.test.d.ts +1 -0
- package/dist/src/commands/channel/config-utils.test.js +142 -0
- package/dist/src/commands/channel/config-utils.test.js.map +1 -0
- package/dist/src/commands/channel/configure.d.ts +4 -0
- package/dist/src/commands/channel/configure.js +65 -0
- package/dist/src/commands/channel/configure.js.map +1 -0
- package/dist/src/commands/channel/pairing.d.ts +8 -0
- package/dist/src/commands/channel/pairing.js +49 -0
- package/dist/src/commands/channel/pairing.js.map +1 -0
- package/dist/src/commands/channel/pidfile.d.ts +25 -0
- package/dist/src/commands/channel/pidfile.js +104 -0
- package/dist/src/commands/channel/pidfile.js.map +1 -0
- package/dist/src/commands/channel/pidfile.test.d.ts +1 -0
- package/dist/src/commands/channel/pidfile.test.js +143 -0
- package/dist/src/commands/channel/pidfile.test.js.map +1 -0
- package/dist/src/commands/channel/start.d.ts +16 -0
- package/dist/src/commands/channel/start.js +352 -0
- package/dist/src/commands/channel/start.js.map +1 -0
- package/dist/src/commands/channel/start.test.d.ts +1 -0
- package/dist/src/commands/channel/start.test.js +156 -0
- package/dist/src/commands/channel/start.test.js.map +1 -0
- package/dist/src/commands/channel/status.d.ts +2 -0
- package/dist/src/commands/channel/status.js +58 -0
- package/dist/src/commands/channel/status.js.map +1 -0
- package/dist/src/commands/channel/stop.d.ts +2 -0
- package/dist/src/commands/channel/stop.js +34 -0
- package/dist/src/commands/channel/stop.js.map +1 -0
- package/dist/src/commands/channel.d.ts +2 -0
- package/dist/src/commands/channel.js +29 -0
- package/dist/src/commands/channel.js.map +1 -0
- package/dist/src/commands/extensions/consent.d.ts +47 -0
- package/dist/src/commands/extensions/consent.js +182 -0
- package/dist/src/commands/extensions/consent.js.map +1 -0
- package/dist/src/commands/extensions/consent.test.d.ts +6 -0
- package/dist/src/commands/extensions/consent.test.js +277 -0
- package/dist/src/commands/extensions/consent.test.js.map +1 -0
- package/dist/src/commands/extensions/disable.d.ts +13 -0
- package/dist/src/commands/extensions/disable.js +65 -0
- package/dist/src/commands/extensions/disable.js.map +1 -0
- package/dist/src/commands/extensions/disable.test.d.ts +6 -0
- package/dist/src/commands/extensions/disable.test.js +101 -0
- package/dist/src/commands/extensions/disable.test.js.map +1 -0
- package/dist/src/commands/extensions/enable.d.ts +13 -0
- package/dist/src/commands/extensions/enable.js +70 -0
- package/dist/src/commands/extensions/enable.js.map +1 -0
- package/dist/src/commands/extensions/enable.test.d.ts +6 -0
- package/dist/src/commands/extensions/enable.test.js +93 -0
- package/dist/src/commands/extensions/enable.test.js.map +1 -0
- package/dist/src/commands/extensions/examples/agent/agents/diary.md +86 -0
- package/dist/src/commands/extensions/examples/agent/qwen-extension.json +5 -0
- package/dist/src/commands/extensions/examples/commands/commands/fs/grep-code.md +3 -0
- package/dist/src/commands/extensions/examples/commands/qwen-extension.json +5 -0
- package/dist/src/commands/extensions/examples/context/QWEN.md +8 -0
- package/dist/src/commands/extensions/examples/context/qwen-extension.json +5 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.ts +60 -0
- package/dist/src/commands/extensions/examples/mcp-server/package.json +18 -0
- package/dist/src/commands/extensions/examples/mcp-server/qwen-extension.json +12 -0
- package/dist/src/commands/extensions/examples/mcp-server/tsconfig.json +13 -0
- package/dist/src/commands/extensions/examples/skills/qwen-extension.json +5 -0
- package/dist/src/commands/extensions/examples/skills/skills/synonyms/SKILL.md +48 -0
- package/dist/src/commands/extensions/install.d.ts +17 -0
- package/dist/src/commands/extensions/install.js +105 -0
- package/dist/src/commands/extensions/install.js.map +1 -0
- package/dist/src/commands/extensions/install.test.d.ts +6 -0
- package/dist/src/commands/extensions/install.test.js +164 -0
- package/dist/src/commands/extensions/install.test.js.map +1 -0
- package/dist/src/commands/extensions/link.d.ts +12 -0
- package/dist/src/commands/extensions/link.js +48 -0
- package/dist/src/commands/extensions/link.js.map +1 -0
- package/dist/src/commands/extensions/link.test.d.ts +6 -0
- package/dist/src/commands/extensions/link.test.js +74 -0
- package/dist/src/commands/extensions/link.test.js.map +1 -0
- package/dist/src/commands/extensions/list.d.ts +8 -0
- package/dist/src/commands/extensions/list.js +35 -0
- package/dist/src/commands/extensions/list.js.map +1 -0
- package/dist/src/commands/extensions/list.test.d.ts +6 -0
- package/dist/src/commands/extensions/list.test.js +76 -0
- package/dist/src/commands/extensions/list.test.js.map +1 -0
- package/dist/src/commands/extensions/new.d.ts +7 -0
- package/dist/src/commands/extensions/new.js +95 -0
- package/dist/src/commands/extensions/new.js.map +1 -0
- package/dist/src/commands/extensions/new.test.d.ts +6 -0
- package/dist/src/commands/extensions/new.test.js +59 -0
- package/dist/src/commands/extensions/new.test.js.map +1 -0
- package/dist/src/commands/extensions/settings.d.ts +7 -0
- package/dist/src/commands/extensions/settings.js +115 -0
- package/dist/src/commands/extensions/settings.js.map +1 -0
- package/dist/src/commands/extensions/settings.test.d.ts +6 -0
- package/dist/src/commands/extensions/settings.test.js +251 -0
- package/dist/src/commands/extensions/settings.test.js.map +1 -0
- package/dist/src/commands/extensions/uninstall.d.ts +12 -0
- package/dist/src/commands/extensions/uninstall.js +50 -0
- package/dist/src/commands/extensions/uninstall.js.map +1 -0
- package/dist/src/commands/extensions/uninstall.test.d.ts +6 -0
- package/dist/src/commands/extensions/uninstall.test.js +18 -0
- package/dist/src/commands/extensions/uninstall.test.js.map +1 -0
- package/dist/src/commands/extensions/update.d.ts +13 -0
- package/dist/src/commands/extensions/update.js +102 -0
- package/dist/src/commands/extensions/update.js.map +1 -0
- package/dist/src/commands/extensions/update.test.d.ts +6 -0
- package/dist/src/commands/extensions/update.test.js +185 -0
- package/dist/src/commands/extensions/update.test.js.map +1 -0
- package/dist/src/commands/extensions/utils.d.ts +8 -0
- package/dist/src/commands/extensions/utils.js +79 -0
- package/dist/src/commands/extensions/utils.js.map +1 -0
- package/dist/src/commands/extensions/utils.test.d.ts +6 -0
- package/dist/src/commands/extensions/utils.test.js +147 -0
- package/dist/src/commands/extensions/utils.test.js.map +1 -0
- package/dist/src/commands/extensions.d.ts +7 -0
- package/dist/src/commands/extensions.js +35 -0
- package/dist/src/commands/extensions.js.map +1 -0
- package/dist/src/commands/extensions.test.d.ts +6 -0
- package/dist/src/commands/extensions.test.js +72 -0
- package/dist/src/commands/extensions.test.js.map +1 -0
- package/dist/src/commands/hooks.d.ts +7 -0
- package/dist/src/commands/hooks.js +20 -0
- package/dist/src/commands/hooks.js.map +1 -0
- package/dist/src/commands/mcp/add.d.ts +7 -0
- package/dist/src/commands/mcp/add.js +247 -0
- package/dist/src/commands/mcp/add.js.map +1 -0
- package/dist/src/commands/mcp/list.d.ts +8 -0
- package/dist/src/commands/mcp/list.js +118 -0
- package/dist/src/commands/mcp/list.js.map +1 -0
- package/dist/src/commands/mcp/reconnect.d.ts +7 -0
- package/dist/src/commands/mcp/reconnect.js +154 -0
- package/dist/src/commands/mcp/reconnect.js.map +1 -0
- package/dist/src/commands/mcp/remove.d.ts +7 -0
- package/dist/src/commands/mcp/remove.js +54 -0
- package/dist/src/commands/mcp/remove.js.map +1 -0
- package/dist/src/commands/mcp.d.ts +7 -0
- package/dist/src/commands/mcp.js +25 -0
- package/dist/src/commands/mcp.js.map +1 -0
- package/dist/src/commands/review/cleanup.d.ts +7 -0
- package/dist/src/commands/review/cleanup.js +81 -0
- package/dist/src/commands/review/cleanup.js.map +1 -0
- package/dist/src/commands/review/deterministic.d.ts +7 -0
- package/dist/src/commands/review/deterministic.js +474 -0
- package/dist/src/commands/review/deterministic.js.map +1 -0
- package/dist/src/commands/review/fetch-pr.d.ts +7 -0
- package/dist/src/commands/review/fetch-pr.js +124 -0
- package/dist/src/commands/review/fetch-pr.js.map +1 -0
- package/dist/src/commands/review/lib/gh.d.ts +34 -0
- package/dist/src/commands/review/lib/gh.js +64 -0
- package/dist/src/commands/review/lib/gh.js.map +1 -0
- package/dist/src/commands/review/lib/git.d.ts +18 -0
- package/dist/src/commands/review/lib/git.js +41 -0
- package/dist/src/commands/review/lib/git.js.map +1 -0
- package/dist/src/commands/review/lib/paths.d.ts +23 -0
- package/dist/src/commands/review/lib/paths.js +37 -0
- package/dist/src/commands/review/lib/paths.js.map +1 -0
- package/dist/src/commands/review/load-rules.d.ts +7 -0
- package/dist/src/commands/review/load-rules.js +112 -0
- package/dist/src/commands/review/load-rules.js.map +1 -0
- package/dist/src/commands/review/pr-context.d.ts +7 -0
- package/dist/src/commands/review/pr-context.js +214 -0
- package/dist/src/commands/review/pr-context.js.map +1 -0
- package/dist/src/commands/review/presubmit.d.ts +7 -0
- package/dist/src/commands/review/presubmit.js +190 -0
- package/dist/src/commands/review/presubmit.js.map +1 -0
- package/dist/src/commands/review.d.ts +7 -0
- package/dist/src/commands/review.js +28 -0
- package/dist/src/commands/review.js.map +1 -0
- package/dist/src/commands/serve.d.ts +21 -0
- package/dist/src/commands/serve.js +214 -0
- package/dist/src/commands/serve.js.map +1 -0
- package/dist/src/commands/sp.d.ts +7 -0
- package/dist/src/commands/sp.js +62 -0
- package/dist/src/commands/sp.js.map +1 -0
- package/dist/src/config/auth.d.ts +10 -0
- package/dist/src/config/auth.js +183 -0
- package/dist/src/config/auth.js.map +1 -0
- package/dist/src/config/auth.test.d.ts +6 -0
- package/dist/src/config/auth.test.js +292 -0
- package/dist/src/config/auth.test.js.map +1 -0
- package/dist/src/config/config.d.ts +144 -0
- package/dist/src/config/config.js +1618 -0
- package/dist/src/config/config.js.map +1 -0
- package/dist/src/config/jsonSchemaArg.test.d.ts +6 -0
- package/dist/src/config/jsonSchemaArg.test.js +305 -0
- package/dist/src/config/jsonSchemaArg.test.js.map +1 -0
- package/dist/src/config/keyBindings.d.ts +89 -0
- package/dist/src/config/keyBindings.js +188 -0
- package/dist/src/config/keyBindings.js.map +1 -0
- package/dist/src/config/keyBindings.test.d.ts +6 -0
- package/dist/src/config/keyBindings.test.js +51 -0
- package/dist/src/config/keyBindings.test.js.map +1 -0
- package/dist/src/config/loadedSettingsAdapter.d.ts +15 -0
- package/dist/src/config/loadedSettingsAdapter.js +80 -0
- package/dist/src/config/loadedSettingsAdapter.js.map +1 -0
- package/dist/src/config/loadedSettingsAdapter.test.d.ts +6 -0
- package/dist/src/config/loadedSettingsAdapter.test.js +127 -0
- package/dist/src/config/loadedSettingsAdapter.test.js.map +1 -0
- package/dist/src/config/migration/index.d.ts +59 -0
- package/dist/src/config/migration/index.js +94 -0
- package/dist/src/config/migration/index.js.map +1 -0
- package/dist/src/config/migration/index.test.d.ts +6 -0
- package/dist/src/config/migration/index.test.js +295 -0
- package/dist/src/config/migration/index.test.js.map +1 -0
- package/dist/src/config/migration/scheduler.d.ts +51 -0
- package/dist/src/config/migration/scheduler.js +95 -0
- package/dist/src/config/migration/scheduler.js.map +1 -0
- package/dist/src/config/migration/scheduler.test.d.ts +6 -0
- package/dist/src/config/migration/scheduler.test.js +129 -0
- package/dist/src/config/migration/scheduler.test.js.map +1 -0
- package/dist/src/config/migration/types.d.ts +53 -0
- package/dist/src/config/migration/types.js +7 -0
- package/dist/src/config/migration/types.js.map +1 -0
- package/dist/src/config/migration/versions/v1-to-v2-shared.d.ts +27 -0
- package/dist/src/config/migration/versions/v1-to-v2-shared.js +174 -0
- package/dist/src/config/migration/versions/v1-to-v2-shared.js.map +1 -0
- package/dist/src/config/migration/versions/v1-to-v2.d.ts +81 -0
- package/dist/src/config/migration/versions/v1-to-v2.js +222 -0
- package/dist/src/config/migration/versions/v1-to-v2.js.map +1 -0
- package/dist/src/config/migration/versions/v1-to-v2.test.d.ts +6 -0
- package/dist/src/config/migration/versions/v1-to-v2.test.js +189 -0
- package/dist/src/config/migration/versions/v1-to-v2.test.js.map +1 -0
- package/dist/src/config/migration/versions/v2-to-v3.d.ts +61 -0
- package/dist/src/config/migration/versions/v2-to-v3.js +185 -0
- package/dist/src/config/migration/versions/v2-to-v3.js.map +1 -0
- package/dist/src/config/migration/versions/v2-to-v3.test.d.ts +6 -0
- package/dist/src/config/migration/versions/v2-to-v3.test.js +337 -0
- package/dist/src/config/migration/versions/v2-to-v3.test.js.map +1 -0
- package/dist/src/config/migration/versions/v3-to-v4.d.ts +34 -0
- package/dist/src/config/migration/versions/v3-to-v4.js +126 -0
- package/dist/src/config/migration/versions/v3-to-v4.js.map +1 -0
- package/dist/src/config/migration/versions/v3-to-v4.test.d.ts +6 -0
- package/dist/src/config/migration/versions/v3-to-v4.test.js +164 -0
- package/dist/src/config/migration/versions/v3-to-v4.test.js.map +1 -0
- package/dist/src/config/modelProvidersScope.d.ts +20 -0
- package/dist/src/config/modelProvidersScope.js +39 -0
- package/dist/src/config/modelProvidersScope.js.map +1 -0
- package/dist/src/config/modelProvidersScope.test.d.ts +6 -0
- package/dist/src/config/modelProvidersScope.test.js +66 -0
- package/dist/src/config/modelProvidersScope.test.js.map +1 -0
- package/dist/src/config/path-freshness.test.d.ts +6 -0
- package/dist/src/config/path-freshness.test.js +52 -0
- package/dist/src/config/path-freshness.test.js.map +1 -0
- package/dist/src/config/sandboxConfig.d.ts +13 -0
- package/dist/src/config/sandboxConfig.js +74 -0
- package/dist/src/config/sandboxConfig.js.map +1 -0
- package/dist/src/config/settings.d.ts +119 -0
- package/dist/src/config/settings.js +1015 -0
- package/dist/src/config/settings.js.map +1 -0
- package/dist/src/config/settingsSchema.d.ts +2207 -0
- package/dist/src/config/settingsSchema.js +2246 -0
- package/dist/src/config/settingsSchema.js.map +1 -0
- package/dist/src/config/settingsSchema.test.d.ts +6 -0
- package/dist/src/config/settingsSchema.test.js +232 -0
- package/dist/src/config/settingsSchema.test.js.map +1 -0
- package/dist/src/config/trustedFolders.d.ts +54 -0
- package/dist/src/config/trustedFolders.js +176 -0
- package/dist/src/config/trustedFolders.js.map +1 -0
- package/dist/src/config/trustedFolders.test.d.ts +6 -0
- package/dist/src/config/trustedFolders.test.js +354 -0
- package/dist/src/config/trustedFolders.test.js.map +1 -0
- package/dist/src/core/auth.d.ts +13 -0
- package/dist/src/core/auth.js +34 -0
- package/dist/src/core/auth.js.map +1 -0
- package/dist/src/core/auth.test.d.ts +6 -0
- package/dist/src/core/auth.test.js +47 -0
- package/dist/src/core/auth.test.js.map +1 -0
- package/dist/src/core/initializer.d.ts +21 -0
- package/dist/src/core/initializer.js +42 -0
- package/dist/src/core/initializer.js.map +1 -0
- package/dist/src/core/initializer.test.d.ts +6 -0
- package/dist/src/core/initializer.test.js +123 -0
- package/dist/src/core/initializer.test.js.map +1 -0
- package/dist/src/core/theme.d.ts +12 -0
- package/dist/src/core/theme.js +25 -0
- package/dist/src/core/theme.js.map +1 -0
- package/dist/src/core/theme.test.d.ts +6 -0
- package/dist/src/core/theme.test.js +57 -0
- package/dist/src/core/theme.test.js.map +1 -0
- package/dist/src/dualOutput/DualOutputBridge.d.ts +84 -0
- package/dist/src/dualOutput/DualOutputBridge.js +293 -0
- package/dist/src/dualOutput/DualOutputBridge.js.map +1 -0
- package/dist/src/dualOutput/DualOutputBridge.test.d.ts +6 -0
- package/dist/src/dualOutput/DualOutputBridge.test.js +157 -0
- package/dist/src/dualOutput/DualOutputBridge.test.js.map +1 -0
- package/dist/src/dualOutput/DualOutputContext.d.ts +19 -0
- package/dist/src/dualOutput/DualOutputContext.js +22 -0
- package/dist/src/dualOutput/DualOutputContext.js.map +1 -0
- package/dist/src/dualOutput/index.d.ts +7 -0
- package/dist/src/dualOutput/index.js +8 -0
- package/dist/src/dualOutput/index.js.map +1 -0
- package/dist/src/export/index.d.ts +6 -0
- package/dist/src/export/index.js +7 -0
- package/dist/src/export/index.js.map +1 -0
- package/dist/src/gemini.d.ts +13 -0
- package/dist/src/gemini.js +908 -0
- package/dist/src/gemini.js.map +1 -0
- package/dist/src/gemini.test.d.ts +6 -0
- package/dist/src/gemini.test.js +975 -0
- package/dist/src/gemini.test.js.map +1 -0
- package/dist/src/generated/git-commit.d.ts +7 -0
- package/dist/src/generated/git-commit.js +10 -0
- package/dist/src/generated/git-commit.js.map +1 -0
- package/dist/src/i18n/index.d.ts +27 -0
- package/dist/src/i18n/index.js +213 -0
- package/dist/src/i18n/index.js.map +1 -0
- package/dist/src/i18n/index.test.d.ts +6 -0
- package/dist/src/i18n/index.test.js +103 -0
- package/dist/src/i18n/index.test.js.map +1 -0
- package/dist/src/i18n/languages.d.ts +43 -0
- package/dist/src/i18n/languages.js +138 -0
- package/dist/src/i18n/languages.js.map +1 -0
- package/dist/src/i18n/locales/ca.js +3951 -0
- package/dist/src/i18n/locales/de.js +2018 -0
- package/dist/src/i18n/locales/en.js +2161 -0
- package/dist/src/i18n/locales/fr.js +2013 -0
- package/dist/src/i18n/locales/ja.js +1780 -0
- package/dist/src/i18n/locales/pt.js +2005 -0
- package/dist/src/i18n/locales/ru.js +1993 -0
- package/dist/src/i18n/locales/zh-TW.js +1729 -0
- package/dist/src/i18n/locales/zh.js +1929 -0
- package/dist/src/i18n/mustTranslateKeys.d.ts +12 -0
- package/dist/src/i18n/mustTranslateKeys.js +111 -0
- package/dist/src/i18n/mustTranslateKeys.js.map +1 -0
- package/dist/src/i18n/mustTranslateKeys.test.d.ts +6 -0
- package/dist/src/i18n/mustTranslateKeys.test.js +103 -0
- package/dist/src/i18n/mustTranslateKeys.test.js.map +1 -0
- package/dist/src/i18n/translationDict.d.ts +9 -0
- package/dist/src/i18n/translationDict.js +17 -0
- package/dist/src/i18n/translationDict.js.map +1 -0
- package/dist/src/nonInteractive/control/ControlContext.d.ts +71 -0
- package/dist/src/nonInteractive/control/ControlContext.js +36 -0
- package/dist/src/nonInteractive/control/ControlContext.js.map +1 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.d.ts +116 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.js +290 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.js.map +1 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.test.d.ts +6 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.test.js +614 -0
- package/dist/src/nonInteractive/control/ControlDispatcher.test.js.map +1 -0
- package/dist/src/nonInteractive/control/ControlService.d.ts +79 -0
- package/dist/src/nonInteractive/control/ControlService.js +139 -0
- package/dist/src/nonInteractive/control/ControlService.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/baseController.d.ts +53 -0
- package/dist/src/nonInteractive/control/controllers/baseController.js +136 -0
- package/dist/src/nonInteractive/control/controllers/baseController.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/hookController.d.ts +25 -0
- package/dist/src/nonInteractive/control/controllers/hookController.js +40 -0
- package/dist/src/nonInteractive/control/controllers/hookController.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.d.ts +57 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.js +361 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.test.d.ts +6 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.test.js +140 -0
- package/dist/src/nonInteractive/control/controllers/permissionController.test.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/sdkMcpController.d.ts +54 -0
- package/dist/src/nonInteractive/control/controllers/sdkMcpController.js +80 -0
- package/dist/src/nonInteractive/control/controllers/sdkMcpController.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/systemController.d.ts +67 -0
- package/dist/src/nonInteractive/control/controllers/systemController.js +326 -0
- package/dist/src/nonInteractive/control/controllers/systemController.js.map +1 -0
- package/dist/src/nonInteractive/control/controllers/systemController.test.d.ts +6 -0
- package/dist/src/nonInteractive/control/controllers/systemController.test.js +121 -0
- package/dist/src/nonInteractive/control/controllers/systemController.test.js.map +1 -0
- package/dist/src/nonInteractive/control/types/serviceAPIs.d.ts +105 -0
- package/dist/src/nonInteractive/control/types/serviceAPIs.js +7 -0
- package/dist/src/nonInteractive/control/types/serviceAPIs.js.map +1 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.d.ts +505 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.js +1041 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.js.map +1 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.d.ts +6 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.js +1304 -0
- package/dist/src/nonInteractive/io/BaseJsonOutputAdapter.test.js.map +1 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.d.ts +29 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.js +64 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.js.map +1 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.test.d.ts +6 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.test.js +684 -0
- package/dist/src/nonInteractive/io/JsonOutputAdapter.test.js.map +1 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.d.ts +16 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.js +54 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.js.map +1 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.test.d.ts +6 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.test.js +178 -0
- package/dist/src/nonInteractive/io/StreamJsonInputReader.test.js.map +1 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.d.ts +84 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.dualOutput.test.d.ts +6 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.dualOutput.test.js +118 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.dualOutput.test.js.map +1 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.js +227 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.js.map +1 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.d.ts +6 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.js +1046 -0
- package/dist/src/nonInteractive/io/StreamJsonOutputAdapter.test.js.map +1 -0
- package/dist/src/nonInteractive/io/index.d.ts +6 -0
- package/dist/src/nonInteractive/io/index.js +7 -0
- package/dist/src/nonInteractive/io/index.js.map +1 -0
- package/dist/src/nonInteractive/session.d.ts +8 -0
- package/dist/src/nonInteractive/session.js +664 -0
- package/dist/src/nonInteractive/session.js.map +1 -0
- package/dist/src/nonInteractive/session.test.d.ts +6 -0
- package/dist/src/nonInteractive/session.test.js +680 -0
- package/dist/src/nonInteractive/session.test.js.map +1 -0
- package/dist/src/nonInteractive/types.d.ts +415 -0
- package/dist/src/nonInteractive/types.js +77 -0
- package/dist/src/nonInteractive/types.js.map +1 -0
- package/dist/src/nonInteractiveCli.d.ts +33 -0
- package/dist/src/nonInteractiveCli.js +1058 -0
- package/dist/src/nonInteractiveCli.js.map +1 -0
- package/dist/src/nonInteractiveCliCommands.d.ts +59 -0
- package/dist/src/nonInteractiveCliCommands.js +326 -0
- package/dist/src/nonInteractiveCliCommands.js.map +1 -0
- package/dist/src/nonInteractiveCliCommands.test.d.ts +6 -0
- package/dist/src/nonInteractiveCliCommands.test.js +484 -0
- package/dist/src/nonInteractiveCliCommands.test.js.map +1 -0
- package/dist/src/patches/is-in-ci.d.ts +7 -0
- package/dist/src/patches/is-in-ci.js +15 -0
- package/dist/src/patches/is-in-ci.js.map +1 -0
- package/dist/src/remoteInput/RemoteInputContext.d.ts +8 -0
- package/dist/src/remoteInput/RemoteInputContext.js +9 -0
- package/dist/src/remoteInput/RemoteInputContext.js.map +1 -0
- package/dist/src/remoteInput/RemoteInputWatcher.d.ts +83 -0
- package/dist/src/remoteInput/RemoteInputWatcher.js +201 -0
- package/dist/src/remoteInput/RemoteInputWatcher.js.map +1 -0
- package/dist/src/remoteInput/RemoteInputWatcher.test.d.ts +6 -0
- package/dist/src/remoteInput/RemoteInputWatcher.test.js +100 -0
- package/dist/src/remoteInput/RemoteInputWatcher.test.js.map +1 -0
- package/dist/src/remoteInput/index.d.ts +7 -0
- package/dist/src/remoteInput/index.js +8 -0
- package/dist/src/remoteInput/index.js.map +1 -0
- package/dist/src/serve/auth/deviceFlow.d.ts +595 -0
- package/dist/src/serve/auth/deviceFlow.js +1243 -0
- package/dist/src/serve/auth/deviceFlow.js.map +1 -0
- package/dist/src/serve/auth/deviceFlow.test.d.ts +6 -0
- package/dist/src/serve/auth/deviceFlow.test.js +1314 -0
- package/dist/src/serve/auth/deviceFlow.test.js.map +1 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.d.ts +30 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.js +331 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.js.map +1 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.test.d.ts +6 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.test.js +301 -0
- package/dist/src/serve/auth/qwenDeviceFlowProvider.test.js.map +1 -0
- package/dist/src/serve/auth.d.ts +101 -0
- package/dist/src/serve/auth.js +216 -0
- package/dist/src/serve/auth.js.map +1 -0
- package/dist/src/serve/capabilities.d.ts +196 -0
- package/dist/src/serve/capabilities.js +227 -0
- package/dist/src/serve/capabilities.js.map +1 -0
- package/dist/src/serve/daemonStatusProvider.d.ts +14 -0
- package/dist/src/serve/daemonStatusProvider.js +252 -0
- package/dist/src/serve/daemonStatusProvider.js.map +1 -0
- package/dist/src/serve/debugMode.d.ts +27 -0
- package/dist/src/serve/debugMode.js +33 -0
- package/dist/src/serve/debugMode.js.map +1 -0
- package/dist/src/serve/demo.d.ts +11 -0
- package/dist/src/serve/demo.js +640 -0
- package/dist/src/serve/demo.js.map +1 -0
- package/dist/src/serve/envSnapshot.d.ts +28 -0
- package/dist/src/serve/envSnapshot.js +199 -0
- package/dist/src/serve/envSnapshot.js.map +1 -0
- package/dist/src/serve/envSnapshot.test.d.ts +6 -0
- package/dist/src/serve/envSnapshot.test.js +181 -0
- package/dist/src/serve/envSnapshot.test.js.map +1 -0
- package/dist/src/serve/eventBus.d.ts +6 -0
- package/dist/src/serve/eventBus.js +15 -0
- package/dist/src/serve/eventBus.js.map +1 -0
- package/dist/src/serve/fs/audit.d.ts +144 -0
- package/dist/src/serve/fs/audit.js +193 -0
- package/dist/src/serve/fs/audit.js.map +1 -0
- package/dist/src/serve/fs/audit.test.d.ts +6 -0
- package/dist/src/serve/fs/audit.test.js +246 -0
- package/dist/src/serve/fs/audit.test.js.map +1 -0
- package/dist/src/serve/fs/contract.test.d.ts +6 -0
- package/dist/src/serve/fs/contract.test.js +211 -0
- package/dist/src/serve/fs/contract.test.js.map +1 -0
- package/dist/src/serve/fs/errors.d.ts +87 -0
- package/dist/src/serve/fs/errors.js +128 -0
- package/dist/src/serve/fs/errors.js.map +1 -0
- package/dist/src/serve/fs/errors.test.d.ts +6 -0
- package/dist/src/serve/fs/errors.test.js +152 -0
- package/dist/src/serve/fs/errors.test.js.map +1 -0
- package/dist/src/serve/fs/index.d.ts +10 -0
- package/dist/src/serve/fs/index.js +11 -0
- package/dist/src/serve/fs/index.js.map +1 -0
- package/dist/src/serve/fs/paths.d.ts +103 -0
- package/dist/src/serve/fs/paths.js +433 -0
- package/dist/src/serve/fs/paths.js.map +1 -0
- package/dist/src/serve/fs/paths.test.d.ts +6 -0
- package/dist/src/serve/fs/paths.test.js +309 -0
- package/dist/src/serve/fs/paths.test.js.map +1 -0
- package/dist/src/serve/fs/policy.d.ts +142 -0
- package/dist/src/serve/fs/policy.js +189 -0
- package/dist/src/serve/fs/policy.js.map +1 -0
- package/dist/src/serve/fs/policy.test.d.ts +6 -0
- package/dist/src/serve/fs/policy.test.js +193 -0
- package/dist/src/serve/fs/policy.test.js.map +1 -0
- package/dist/src/serve/fs/workspaceFileSystem.d.ts +157 -0
- package/dist/src/serve/fs/workspaceFileSystem.js +1377 -0
- package/dist/src/serve/fs/workspaceFileSystem.js.map +1 -0
- package/dist/src/serve/fs/workspaceFileSystem.test.d.ts +6 -0
- package/dist/src/serve/fs/workspaceFileSystem.test.js +880 -0
- package/dist/src/serve/fs/workspaceFileSystem.test.js.map +1 -0
- package/dist/src/serve/httpAcpBridge.d.ts +80 -0
- package/dist/src/serve/httpAcpBridge.js +3559 -0
- package/dist/src/serve/httpAcpBridge.js.map +1 -0
- package/dist/src/serve/httpAcpBridge.test.d.ts +6 -0
- package/dist/src/serve/httpAcpBridge.test.js +4987 -0
- package/dist/src/serve/httpAcpBridge.test.js.map +1 -0
- package/dist/src/serve/inMemoryChannel.d.ts +6 -0
- package/dist/src/serve/inMemoryChannel.js +14 -0
- package/dist/src/serve/inMemoryChannel.js.map +1 -0
- package/dist/src/serve/index.d.ts +15 -0
- package/dist/src/serve/index.js +16 -0
- package/dist/src/serve/index.js.map +1 -0
- package/dist/src/serve/loopbackBinds.d.ts +18 -0
- package/dist/src/serve/loopbackBinds.js +33 -0
- package/dist/src/serve/loopbackBinds.js.map +1 -0
- package/dist/src/serve/routes/workspaceFileRead.d.ts +90 -0
- package/dist/src/serve/routes/workspaceFileRead.js +458 -0
- package/dist/src/serve/routes/workspaceFileRead.js.map +1 -0
- package/dist/src/serve/routes/workspaceFileRead.test.d.ts +6 -0
- package/dist/src/serve/routes/workspaceFileRead.test.js +453 -0
- package/dist/src/serve/routes/workspaceFileRead.test.js.map +1 -0
- package/dist/src/serve/routes/workspaceFileWrite.d.ts +17 -0
- package/dist/src/serve/routes/workspaceFileWrite.js +224 -0
- package/dist/src/serve/routes/workspaceFileWrite.js.map +1 -0
- package/dist/src/serve/routes/workspaceFileWrite.test.d.ts +6 -0
- package/dist/src/serve/routes/workspaceFileWrite.test.js +223 -0
- package/dist/src/serve/routes/workspaceFileWrite.test.js.map +1 -0
- package/dist/src/serve/runQwenServe.d.ts +67 -0
- package/dist/src/serve/runQwenServe.js +616 -0
- package/dist/src/serve/runQwenServe.js.map +1 -0
- package/dist/src/serve/server.d.ts +125 -0
- package/dist/src/serve/server.js +2297 -0
- package/dist/src/serve/server.js.map +1 -0
- package/dist/src/serve/status.d.ts +6 -0
- package/dist/src/serve/status.js +13 -0
- package/dist/src/serve/status.js.map +1 -0
- package/dist/src/serve/types.d.ts +175 -0
- package/dist/src/serve/types.js +10 -0
- package/dist/src/serve/types.js.map +1 -0
- package/dist/src/serve/workspaceAgents.d.ts +47 -0
- package/dist/src/serve/workspaceAgents.js +1171 -0
- package/dist/src/serve/workspaceAgents.js.map +1 -0
- package/dist/src/serve/workspaceAgents.test.d.ts +6 -0
- package/dist/src/serve/workspaceAgents.test.js +823 -0
- package/dist/src/serve/workspaceAgents.test.js.map +1 -0
- package/dist/src/serve/workspaceMemory.d.ts +60 -0
- package/dist/src/serve/workspaceMemory.js +323 -0
- package/dist/src/serve/workspaceMemory.js.map +1 -0
- package/dist/src/serve/workspaceMemory.test.d.ts +6 -0
- package/dist/src/serve/workspaceMemory.test.js +418 -0
- package/dist/src/serve/workspaceMemory.test.js.map +1 -0
- package/dist/src/services/BuiltinCommandLoader.d.ts +24 -0
- package/dist/src/services/BuiltinCommandLoader.js +159 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -0
- package/dist/src/services/BuiltinCommandLoader.test.d.ts +6 -0
- package/dist/src/services/BuiltinCommandLoader.test.js +234 -0
- package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -0
- package/dist/src/services/BundledSkillLoader.d.ts +17 -0
- package/dist/src/services/BundledSkillLoader.js +97 -0
- package/dist/src/services/BundledSkillLoader.js.map +1 -0
- package/dist/src/services/BundledSkillLoader.test.d.ts +6 -0
- package/dist/src/services/BundledSkillLoader.test.js +301 -0
- package/dist/src/services/BundledSkillLoader.test.js.map +1 -0
- package/dist/src/services/CommandService.d.ts +69 -0
- package/dist/src/services/CommandService.js +128 -0
- package/dist/src/services/CommandService.js.map +1 -0
- package/dist/src/services/CommandService.test.d.ts +6 -0
- package/dist/src/services/CommandService.test.js +263 -0
- package/dist/src/services/CommandService.test.js.map +1 -0
- package/dist/src/services/FileCommandLoader-extension.test.d.ts +6 -0
- package/dist/src/services/FileCommandLoader-extension.test.js +279 -0
- package/dist/src/services/FileCommandLoader-extension.test.js.map +1 -0
- package/dist/src/services/FileCommandLoader-markdown.test.d.ts +6 -0
- package/dist/src/services/FileCommandLoader-markdown.test.js +111 -0
- package/dist/src/services/FileCommandLoader-markdown.test.js.map +1 -0
- package/dist/src/services/FileCommandLoader.d.ts +64 -0
- package/dist/src/services/FileCommandLoader.js +259 -0
- package/dist/src/services/FileCommandLoader.js.map +1 -0
- package/dist/src/services/McpPromptLoader.d.ts +35 -0
- package/dist/src/services/McpPromptLoader.js +261 -0
- package/dist/src/services/McpPromptLoader.js.map +1 -0
- package/dist/src/services/McpPromptLoader.test.d.ts +6 -0
- package/dist/src/services/McpPromptLoader.test.js +341 -0
- package/dist/src/services/McpPromptLoader.test.js.map +1 -0
- package/dist/src/services/SkillCommandLoader.d.ts +23 -0
- package/dist/src/services/SkillCommandLoader.js +110 -0
- package/dist/src/services/SkillCommandLoader.js.map +1 -0
- package/dist/src/services/SkillCommandLoader.test.d.ts +6 -0
- package/dist/src/services/SkillCommandLoader.test.js +307 -0
- package/dist/src/services/SkillCommandLoader.test.js.map +1 -0
- package/dist/src/services/command-factory.d.ts +25 -0
- package/dist/src/services/command-factory.js +122 -0
- package/dist/src/services/command-factory.js.map +1 -0
- package/dist/src/services/command-factory.test.d.ts +6 -0
- package/dist/src/services/command-factory.test.js +31 -0
- package/dist/src/services/command-factory.test.js.map +1 -0
- package/dist/src/services/command-migration-tool.d.ts +39 -0
- package/dist/src/services/command-migration-tool.js +135 -0
- package/dist/src/services/command-migration-tool.js.map +1 -0
- package/dist/src/services/command-migration-tool.test.d.ts +6 -0
- package/dist/src/services/command-migration-tool.test.js +175 -0
- package/dist/src/services/command-migration-tool.test.js.map +1 -0
- package/dist/src/services/commandMetadata.d.ts +21 -0
- package/dist/src/services/commandMetadata.js +106 -0
- package/dist/src/services/commandMetadata.js.map +1 -0
- package/dist/src/services/commandMetadata.test.d.ts +6 -0
- package/dist/src/services/commandMetadata.test.js +216 -0
- package/dist/src/services/commandMetadata.test.js.map +1 -0
- package/dist/src/services/commandUtils.d.ts +36 -0
- package/dist/src/services/commandUtils.js +57 -0
- package/dist/src/services/commandUtils.js.map +1 -0
- package/dist/src/services/commandUtils.test.d.ts +6 -0
- package/dist/src/services/commandUtils.test.js +159 -0
- package/dist/src/services/commandUtils.test.js.map +1 -0
- package/dist/src/services/insight/generators/DataProcessor.d.ts +23 -0
- package/dist/src/services/insight/generators/DataProcessor.js +1001 -0
- package/dist/src/services/insight/generators/DataProcessor.js.map +1 -0
- package/dist/src/services/insight/generators/DataProcessor.test.d.ts +6 -0
- package/dist/src/services/insight/generators/DataProcessor.test.js +1210 -0
- package/dist/src/services/insight/generators/DataProcessor.test.js.map +1 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.d.ts +16 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.js +63 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.js.map +1 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.test.d.ts +6 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.test.js +60 -0
- package/dist/src/services/insight/generators/StaticInsightGenerator.test.js.map +1 -0
- package/dist/src/services/insight/generators/TemplateRenderer.d.ts +9 -0
- package/dist/src/services/insight/generators/TemplateRenderer.js +49 -0
- package/dist/src/services/insight/generators/TemplateRenderer.js.map +1 -0
- package/dist/src/services/insight/types/QualitativeInsightTypes.d.ts +74 -0
- package/dist/src/services/insight/types/QualitativeInsightTypes.js +2 -0
- package/dist/src/services/insight/types/QualitativeInsightTypes.js.map +1 -0
- package/dist/src/services/insight/types/StaticInsightTypes.d.ts +59 -0
- package/dist/src/services/insight/types/StaticInsightTypes.js +7 -0
- package/dist/src/services/insight/types/StaticInsightTypes.js.map +1 -0
- package/dist/src/services/markdown-command-parser.d.ts +52 -0
- package/dist/src/services/markdown-command-parser.js +60 -0
- package/dist/src/services/markdown-command-parser.js.map +1 -0
- package/dist/src/services/markdown-command-parser.test.d.ts +6 -0
- package/dist/src/services/markdown-command-parser.test.js +146 -0
- package/dist/src/services/markdown-command-parser.test.js.map +1 -0
- package/dist/src/services/notificationService.d.ts +19 -0
- package/dist/src/services/notificationService.js +64 -0
- package/dist/src/services/notificationService.js.map +1 -0
- package/dist/src/services/notificationService.test.d.ts +6 -0
- package/dist/src/services/notificationService.test.js +114 -0
- package/dist/src/services/notificationService.test.js.map +1 -0
- package/dist/src/services/prompt-processors/argumentProcessor.d.ts +16 -0
- package/dist/src/services/prompt-processors/argumentProcessor.js +21 -0
- package/dist/src/services/prompt-processors/argumentProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/atFileProcessor.d.ts +12 -0
- package/dist/src/services/prompt-processors/atFileProcessor.js +63 -0
- package/dist/src/services/prompt-processors/atFileProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/atFileProcessor.test.d.ts +6 -0
- package/dist/src/services/prompt-processors/atFileProcessor.test.js +174 -0
- package/dist/src/services/prompt-processors/atFileProcessor.test.js.map +1 -0
- package/dist/src/services/prompt-processors/injectionParser.d.ts +29 -0
- package/dist/src/services/prompt-processors/injectionParser.js +60 -0
- package/dist/src/services/prompt-processors/injectionParser.js.map +1 -0
- package/dist/src/services/prompt-processors/injectionParser.test.d.ts +6 -0
- package/dist/src/services/prompt-processors/injectionParser.test.js +189 -0
- package/dist/src/services/prompt-processors/injectionParser.test.js.map +1 -0
- package/dist/src/services/prompt-processors/shellProcessor.d.ts +27 -0
- package/dist/src/services/prompt-processors/shellProcessor.js +146 -0
- package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/types.d.ts +45 -0
- package/dist/src/services/prompt-processors/types.js +20 -0
- package/dist/src/services/prompt-processors/types.js.map +1 -0
- package/dist/src/services/test-commands/example.md +5 -0
- package/dist/src/services/tips/index.d.ts +10 -0
- package/dist/src/services/tips/index.js +21 -0
- package/dist/src/services/tips/index.js.map +1 -0
- package/dist/src/services/tips/tipHistory.d.ts +49 -0
- package/dist/src/services/tips/tipHistory.js +138 -0
- package/dist/src/services/tips/tipHistory.js.map +1 -0
- package/dist/src/services/tips/tipHistory.test.d.ts +6 -0
- package/dist/src/services/tips/tipHistory.test.js +102 -0
- package/dist/src/services/tips/tipHistory.test.js.map +1 -0
- package/dist/src/services/tips/tipRegistry.d.ts +32 -0
- package/dist/src/services/tips/tipRegistry.js +148 -0
- package/dist/src/services/tips/tipRegistry.js.map +1 -0
- package/dist/src/services/tips/tipRegistry.test.d.ts +6 -0
- package/dist/src/services/tips/tipRegistry.test.js +65 -0
- package/dist/src/services/tips/tipRegistry.test.js.map +1 -0
- package/dist/src/services/tips/tipScheduler.d.ts +21 -0
- package/dist/src/services/tips/tipScheduler.js +38 -0
- package/dist/src/services/tips/tipScheduler.js.map +1 -0
- package/dist/src/services/tips/tipScheduler.test.d.ts +6 -0
- package/dist/src/services/tips/tipScheduler.test.js +126 -0
- package/dist/src/services/tips/tipScheduler.test.js.map +1 -0
- package/dist/src/services/types.d.ts +22 -0
- package/dist/src/services/types.js +7 -0
- package/dist/src/services/types.js.map +1 -0
- package/dist/src/startup/worktreeStartup.d.ts +112 -0
- package/dist/src/startup/worktreeStartup.js +350 -0
- package/dist/src/startup/worktreeStartup.js.map +1 -0
- package/dist/src/startup/worktreeStartup.test.d.ts +6 -0
- package/dist/src/startup/worktreeStartup.test.js +332 -0
- package/dist/src/startup/worktreeStartup.test.js.map +1 -0
- package/dist/src/test-utils/customMatchers.d.ts +14 -0
- package/dist/src/test-utils/customMatchers.js +40 -0
- package/dist/src/test-utils/customMatchers.js.map +1 -0
- package/dist/src/test-utils/mockCommandContext.d.ts +18 -0
- package/dist/src/test-utils/mockCommandContext.js +107 -0
- package/dist/src/test-utils/mockCommandContext.js.map +1 -0
- package/dist/src/test-utils/mockCommandContext.test.d.ts +6 -0
- package/dist/src/test-utils/mockCommandContext.test.js +51 -0
- package/dist/src/test-utils/mockCommandContext.test.js.map +1 -0
- package/dist/src/test-utils/render.d.ts +14 -0
- package/dist/src/test-utils/render.js +15 -0
- package/dist/src/test-utils/render.js.map +1 -0
- package/dist/src/ui/App.d.ts +6 -0
- package/dist/src/ui/App.js +65 -0
- package/dist/src/ui/App.js.map +1 -0
- package/dist/src/ui/AppContainer.d.ts +24 -0
- package/dist/src/ui/AppContainer.js +2853 -0
- package/dist/src/ui/AppContainer.js.map +1 -0
- package/dist/src/ui/AppContainer.test.d.ts +6 -0
- package/dist/src/ui/AppContainer.test.js +2368 -0
- package/dist/src/ui/AppContainer.test.js.map +1 -0
- package/dist/src/ui/CommandFormatMigrationNudge.d.ts +14 -0
- package/dist/src/ui/CommandFormatMigrationNudge.js +44 -0
- package/dist/src/ui/CommandFormatMigrationNudge.js.map +1 -0
- package/dist/src/ui/FeedbackDialog.d.ts +9 -0
- package/dist/src/ui/FeedbackDialog.js +44 -0
- package/dist/src/ui/FeedbackDialog.js.map +1 -0
- package/dist/src/ui/IdeIntegrationNudge.d.ts +16 -0
- package/dist/src/ui/IdeIntegrationNudge.js +53 -0
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.d.ts +7 -0
- package/dist/src/ui/auth/AuthDialog.js +214 -0
- package/dist/src/ui/auth/AuthDialog.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.test.d.ts +6 -0
- package/dist/src/ui/auth/AuthDialog.test.js +1029 -0
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -0
- package/dist/src/ui/auth/AuthInProgress.d.ts +11 -0
- package/dist/src/ui/auth/AuthInProgress.js +24 -0
- package/dist/src/ui/auth/AuthInProgress.js.map +1 -0
- package/dist/src/ui/auth/ProviderSetupSteps.d.ts +11 -0
- package/dist/src/ui/auth/ProviderSetupSteps.js +320 -0
- package/dist/src/ui/auth/ProviderSetupSteps.js.map +1 -0
- package/dist/src/ui/auth/ProviderSetupSteps.test.d.ts +6 -0
- package/dist/src/ui/auth/ProviderSetupSteps.test.js +322 -0
- package/dist/src/ui/auth/ProviderSetupSteps.test.js.map +1 -0
- package/dist/src/ui/auth/useAuth.d.ts +76 -0
- package/dist/src/ui/auth/useAuth.js +192 -0
- package/dist/src/ui/auth/useAuth.js.map +1 -0
- package/dist/src/ui/auth/useAuth.test.d.ts +6 -0
- package/dist/src/ui/auth/useAuth.test.js +267 -0
- package/dist/src/ui/auth/useAuth.test.js.map +1 -0
- package/dist/src/ui/auth/useProviderSetupFlow.d.ts +54 -0
- package/dist/src/ui/auth/useProviderSetupFlow.js +380 -0
- package/dist/src/ui/auth/useProviderSetupFlow.js.map +1 -0
- package/dist/src/ui/colors.d.ts +7 -0
- package/dist/src/ui/colors.js +60 -0
- package/dist/src/ui/colors.js.map +1 -0
- package/dist/src/ui/commands/aboutCommand.d.ts +7 -0
- package/dist/src/ui/commands/aboutCommand.js +69 -0
- package/dist/src/ui/commands/aboutCommand.js.map +1 -0
- package/dist/src/ui/commands/agentsCommand.d.ts +7 -0
- package/dist/src/ui/commands/agentsCommand.js +42 -0
- package/dist/src/ui/commands/agentsCommand.js.map +1 -0
- package/dist/src/ui/commands/approvalModeCommand.d.ts +7 -0
- package/dist/src/ui/commands/approvalModeCommand.js +89 -0
- package/dist/src/ui/commands/approvalModeCommand.js.map +1 -0
- package/dist/src/ui/commands/approvalModeCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/approvalModeCommand.test.js +112 -0
- package/dist/src/ui/commands/approvalModeCommand.test.js.map +1 -0
- package/dist/src/ui/commands/arenaCommand.agentComplete.test.d.ts +6 -0
- package/dist/src/ui/commands/arenaCommand.agentComplete.test.js +118 -0
- package/dist/src/ui/commands/arenaCommand.agentComplete.test.js.map +1 -0
- package/dist/src/ui/commands/arenaCommand.d.ts +7 -0
- package/dist/src/ui/commands/arenaCommand.js +519 -0
- package/dist/src/ui/commands/arenaCommand.js.map +1 -0
- package/dist/src/ui/commands/arenaCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/arenaCommand.test.js +352 -0
- package/dist/src/ui/commands/arenaCommand.test.js.map +1 -0
- package/dist/src/ui/commands/authCommand.d.ts +7 -0
- package/dist/src/ui/commands/authCommand.js +31 -0
- package/dist/src/ui/commands/authCommand.js.map +1 -0
- package/dist/src/ui/commands/branchCommand.d.ts +7 -0
- package/dist/src/ui/commands/branchCommand.js +49 -0
- package/dist/src/ui/commands/branchCommand.js.map +1 -0
- package/dist/src/ui/commands/branchCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/branchCommand.test.js +57 -0
- package/dist/src/ui/commands/branchCommand.test.js.map +1 -0
- package/dist/src/ui/commands/btwCommand.d.ts +7 -0
- package/dist/src/ui/commands/btwCommand.js +164 -0
- package/dist/src/ui/commands/btwCommand.js.map +1 -0
- package/dist/src/ui/commands/btwCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/btwCommand.test.js +338 -0
- package/dist/src/ui/commands/btwCommand.test.js.map +1 -0
- package/dist/src/ui/commands/bugCommand.d.ts +7 -0
- package/dist/src/ui/commands/bugCommand.js +54 -0
- package/dist/src/ui/commands/bugCommand.js.map +1 -0
- package/dist/src/ui/commands/clearCommand.d.ts +7 -0
- package/dist/src/ui/commands/clearCommand.js +122 -0
- package/dist/src/ui/commands/clearCommand.js.map +1 -0
- package/dist/src/ui/commands/compressCommand.d.ts +7 -0
- package/dist/src/ui/commands/compressCommand.js +178 -0
- package/dist/src/ui/commands/compressCommand.js.map +1 -0
- package/dist/src/ui/commands/contextCommand.d.ts +14 -0
- package/dist/src/ui/commands/contextCommand.js +443 -0
- package/dist/src/ui/commands/contextCommand.js.map +1 -0
- package/dist/src/ui/commands/contextCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/contextCommand.test.js +184 -0
- package/dist/src/ui/commands/contextCommand.test.js.map +1 -0
- package/dist/src/ui/commands/copyCommand.d.ts +7 -0
- package/dist/src/ui/commands/copyCommand.js +374 -0
- package/dist/src/ui/commands/copyCommand.js.map +1 -0
- package/dist/src/ui/commands/deleteCommand.d.ts +7 -0
- package/dist/src/ui/commands/deleteCommand.js +19 -0
- package/dist/src/ui/commands/deleteCommand.js.map +1 -0
- package/dist/src/ui/commands/deleteCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/deleteCommand.test.js +27 -0
- package/dist/src/ui/commands/deleteCommand.test.js.map +1 -0
- package/dist/src/ui/commands/diffCommand.d.ts +42 -0
- package/dist/src/ui/commands/diffCommand.js +206 -0
- package/dist/src/ui/commands/diffCommand.js.map +1 -0
- package/dist/src/ui/commands/diffCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/diffCommand.test.js +482 -0
- package/dist/src/ui/commands/diffCommand.test.js.map +1 -0
- package/dist/src/ui/commands/directoryCommand.d.ts +13 -0
- package/dist/src/ui/commands/directoryCommand.js +252 -0
- package/dist/src/ui/commands/directoryCommand.js.map +1 -0
- package/dist/src/ui/commands/docsCommand.d.ts +7 -0
- package/dist/src/ui/commands/docsCommand.js +49 -0
- package/dist/src/ui/commands/docsCommand.js.map +1 -0
- package/dist/src/ui/commands/doctorCommand.d.ts +7 -0
- package/dist/src/ui/commands/doctorCommand.js +530 -0
- package/dist/src/ui/commands/doctorCommand.js.map +1 -0
- package/dist/src/ui/commands/doctorCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/doctorCommand.test.js +804 -0
- package/dist/src/ui/commands/doctorCommand.test.js.map +1 -0
- package/dist/src/ui/commands/dreamCommand.d.ts +7 -0
- package/dist/src/ui/commands/dreamCommand.js +42 -0
- package/dist/src/ui/commands/dreamCommand.js.map +1 -0
- package/dist/src/ui/commands/dreamCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/dreamCommand.test.js +39 -0
- package/dist/src/ui/commands/dreamCommand.test.js.map +1 -0
- package/dist/src/ui/commands/editorCommand.d.ts +7 -0
- package/dist/src/ui/commands/editorCommand.js +20 -0
- package/dist/src/ui/commands/editorCommand.js.map +1 -0
- package/dist/src/ui/commands/exportCommand.d.ts +10 -0
- package/dist/src/ui/commands/exportCommand.js +373 -0
- package/dist/src/ui/commands/exportCommand.js.map +1 -0
- package/dist/src/ui/commands/exportCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/exportCommand.test.js +905 -0
- package/dist/src/ui/commands/exportCommand.test.js.map +1 -0
- package/dist/src/ui/commands/extensionsCommand.d.ts +10 -0
- package/dist/src/ui/commands/extensionsCommand.js +185 -0
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -0
- package/dist/src/ui/commands/forgetCommand.d.ts +7 -0
- package/dist/src/ui/commands/forgetCommand.js +45 -0
- package/dist/src/ui/commands/forgetCommand.js.map +1 -0
- package/dist/src/ui/commands/forkCommand.d.ts +7 -0
- package/dist/src/ui/commands/forkCommand.js +163 -0
- package/dist/src/ui/commands/forkCommand.js.map +1 -0
- package/dist/src/ui/commands/forkCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/forkCommand.test.js +229 -0
- package/dist/src/ui/commands/forkCommand.test.js.map +1 -0
- package/dist/src/ui/commands/goalCommand.d.ts +7 -0
- package/dist/src/ui/commands/goalCommand.js +181 -0
- package/dist/src/ui/commands/goalCommand.js.map +1 -0
- package/dist/src/ui/commands/goalCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/goalCommand.test.js +328 -0
- package/dist/src/ui/commands/goalCommand.test.js.map +1 -0
- package/dist/src/ui/commands/helpCommand.d.ts +7 -0
- package/dist/src/ui/commands/helpCommand.js +21 -0
- package/dist/src/ui/commands/helpCommand.js.map +1 -0
- package/dist/src/ui/commands/hooksCommand.d.ts +7 -0
- package/dist/src/ui/commands/hooksCommand.js +153 -0
- package/dist/src/ui/commands/hooksCommand.js.map +1 -0
- package/dist/src/ui/commands/hooksCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/hooksCommand.test.js +189 -0
- package/dist/src/ui/commands/hooksCommand.test.js.map +1 -0
- package/dist/src/ui/commands/ideCommand.d.ts +7 -0
- package/dist/src/ui/commands/ideCommand.js +256 -0
- package/dist/src/ui/commands/ideCommand.js.map +1 -0
- package/dist/src/ui/commands/initCommand.d.ts +7 -0
- package/dist/src/ui/commands/initCommand.js +119 -0
- package/dist/src/ui/commands/initCommand.js.map +1 -0
- package/dist/src/ui/commands/insightCommand.d.ts +7 -0
- package/dist/src/ui/commands/insightCommand.js +195 -0
- package/dist/src/ui/commands/insightCommand.js.map +1 -0
- package/dist/src/ui/commands/insightCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/insightCommand.test.js +173 -0
- package/dist/src/ui/commands/insightCommand.test.js.map +1 -0
- package/dist/src/ui/commands/languageCommand.d.ts +7 -0
- package/dist/src/ui/commands/languageCommand.js +291 -0
- package/dist/src/ui/commands/languageCommand.js.map +1 -0
- package/dist/src/ui/commands/languageCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/languageCommand.test.js +664 -0
- package/dist/src/ui/commands/languageCommand.test.js.map +1 -0
- package/dist/src/ui/commands/lspCommand.d.ts +7 -0
- package/dist/src/ui/commands/lspCommand.js +62 -0
- package/dist/src/ui/commands/lspCommand.js.map +1 -0
- package/dist/src/ui/commands/lspCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/lspCommand.test.js +175 -0
- package/dist/src/ui/commands/lspCommand.test.js.map +1 -0
- package/dist/src/ui/commands/mcpCommand.d.ts +7 -0
- package/dist/src/ui/commands/mcpCommand.js +21 -0
- package/dist/src/ui/commands/mcpCommand.js.map +1 -0
- package/dist/src/ui/commands/memoryCommand.d.ts +7 -0
- package/dist/src/ui/commands/memoryCommand.js +21 -0
- package/dist/src/ui/commands/memoryCommand.js.map +1 -0
- package/dist/src/ui/commands/modelCommand.d.ts +7 -0
- package/dist/src/ui/commands/modelCommand.js +226 -0
- package/dist/src/ui/commands/modelCommand.js.map +1 -0
- package/dist/src/ui/commands/modelCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/modelCommand.test.js +503 -0
- package/dist/src/ui/commands/modelCommand.test.js.map +1 -0
- package/dist/src/ui/commands/permissionsCommand.d.ts +7 -0
- package/dist/src/ui/commands/permissionsCommand.js +20 -0
- package/dist/src/ui/commands/permissionsCommand.js.map +1 -0
- package/dist/src/ui/commands/permissionsCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/permissionsCommand.test.js +30 -0
- package/dist/src/ui/commands/permissionsCommand.test.js.map +1 -0
- package/dist/src/ui/commands/planCommand.d.ts +7 -0
- package/dist/src/ui/commands/planCommand.js +88 -0
- package/dist/src/ui/commands/planCommand.js.map +1 -0
- package/dist/src/ui/commands/planCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/planCommand.test.js +113 -0
- package/dist/src/ui/commands/planCommand.test.js.map +1 -0
- package/dist/src/ui/commands/quitCommand.d.ts +7 -0
- package/dist/src/ui/commands/quitCommand.js +38 -0
- package/dist/src/ui/commands/quitCommand.js.map +1 -0
- package/dist/src/ui/commands/recapCommand.d.ts +7 -0
- package/dist/src/ui/commands/recapCommand.js +56 -0
- package/dist/src/ui/commands/recapCommand.js.map +1 -0
- package/dist/src/ui/commands/rememberCommand.d.ts +7 -0
- package/dist/src/ui/commands/rememberCommand.js +54 -0
- package/dist/src/ui/commands/rememberCommand.js.map +1 -0
- package/dist/src/ui/commands/renameCommand.d.ts +7 -0
- package/dist/src/ui/commands/renameCommand.js +208 -0
- package/dist/src/ui/commands/renameCommand.js.map +1 -0
- package/dist/src/ui/commands/renameCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/renameCommand.test.js +414 -0
- package/dist/src/ui/commands/renameCommand.test.js.map +1 -0
- package/dist/src/ui/commands/restoreCommand.d.ts +8 -0
- package/dist/src/ui/commands/restoreCommand.js +159 -0
- package/dist/src/ui/commands/restoreCommand.js.map +1 -0
- package/dist/src/ui/commands/resumeCommand.d.ts +7 -0
- package/dist/src/ui/commands/resumeCommand.js +65 -0
- package/dist/src/ui/commands/resumeCommand.js.map +1 -0
- package/dist/src/ui/commands/resumeCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/resumeCommand.test.js +135 -0
- package/dist/src/ui/commands/resumeCommand.test.js.map +1 -0
- package/dist/src/ui/commands/rewindCommand.d.ts +7 -0
- package/dist/src/ui/commands/rewindCommand.js +20 -0
- package/dist/src/ui/commands/rewindCommand.js.map +1 -0
- package/dist/src/ui/commands/settingsCommand.d.ts +7 -0
- package/dist/src/ui/commands/settingsCommand.js +20 -0
- package/dist/src/ui/commands/settingsCommand.js.map +1 -0
- package/dist/src/ui/commands/setupGithubCommand.d.ts +9 -0
- package/dist/src/ui/commands/setupGithubCommand.js +165 -0
- package/dist/src/ui/commands/setupGithubCommand.js.map +1 -0
- package/dist/src/ui/commands/setupGithubCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/setupGithubCommand.test.js +164 -0
- package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -0
- package/dist/src/ui/commands/skillsCommand.d.ts +7 -0
- package/dist/src/ui/commands/skillsCommand.js +63 -0
- package/dist/src/ui/commands/skillsCommand.js.map +1 -0
- package/dist/src/ui/commands/skillsCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/skillsCommand.test.js +136 -0
- package/dist/src/ui/commands/skillsCommand.test.js.map +1 -0
- package/dist/src/ui/commands/statsCommand.d.ts +7 -0
- package/dist/src/ui/commands/statsCommand.js +130 -0
- package/dist/src/ui/commands/statsCommand.js.map +1 -0
- package/dist/src/ui/commands/statuslineCommand.d.ts +7 -0
- package/dist/src/ui/commands/statuslineCommand.js +33 -0
- package/dist/src/ui/commands/statuslineCommand.js.map +1 -0
- package/dist/src/ui/commands/statuslineCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/statuslineCommand.test.js +54 -0
- package/dist/src/ui/commands/statuslineCommand.test.js.map +1 -0
- package/dist/src/ui/commands/summaryCommand.d.ts +7 -0
- package/dist/src/ui/commands/summaryCommand.js +261 -0
- package/dist/src/ui/commands/summaryCommand.js.map +1 -0
- package/dist/src/ui/commands/tasksCommand.d.ts +7 -0
- package/dist/src/ui/commands/tasksCommand.js +222 -0
- package/dist/src/ui/commands/tasksCommand.js.map +1 -0
- package/dist/src/ui/commands/tasksCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/tasksCommand.test.js +365 -0
- package/dist/src/ui/commands/tasksCommand.test.js.map +1 -0
- package/dist/src/ui/commands/terminalSetupCommand.d.ts +13 -0
- package/dist/src/ui/commands/terminalSetupCommand.js +48 -0
- package/dist/src/ui/commands/terminalSetupCommand.js.map +1 -0
- package/dist/src/ui/commands/themeCommand.d.ts +7 -0
- package/dist/src/ui/commands/themeCommand.js +20 -0
- package/dist/src/ui/commands/themeCommand.js.map +1 -0
- package/dist/src/ui/commands/toolsCommand.d.ts +7 -0
- package/dist/src/ui/commands/toolsCommand.js +45 -0
- package/dist/src/ui/commands/toolsCommand.js.map +1 -0
- package/dist/src/ui/commands/trustCommand.d.ts +7 -0
- package/dist/src/ui/commands/trustCommand.js +20 -0
- package/dist/src/ui/commands/trustCommand.js.map +1 -0
- package/dist/src/ui/commands/trustCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/trustCommand.test.js +30 -0
- package/dist/src/ui/commands/trustCommand.test.js.map +1 -0
- package/dist/src/ui/commands/types.d.ts +298 -0
- package/dist/src/ui/commands/types.js +13 -0
- package/dist/src/ui/commands/types.js.map +1 -0
- package/dist/src/ui/commands/vimCommand.d.ts +7 -0
- package/dist/src/ui/commands/vimCommand.js +27 -0
- package/dist/src/ui/commands/vimCommand.js.map +1 -0
- package/dist/src/ui/components/AboutBox.d.ts +12 -0
- package/dist/src/ui/components/AboutBox.js +10 -0
- package/dist/src/ui/components/AboutBox.js.map +1 -0
- package/dist/src/ui/components/AnsiOutput.d.ts +20 -0
- package/dist/src/ui/components/AnsiOutput.js +27 -0
- package/dist/src/ui/components/AnsiOutput.js.map +1 -0
- package/dist/src/ui/components/AnsiOutput.test.d.ts +6 -0
- package/dist/src/ui/components/AnsiOutput.test.js +134 -0
- package/dist/src/ui/components/AnsiOutput.test.js.map +1 -0
- package/dist/src/ui/components/ApiKeyInput.d.ts +22 -0
- package/dist/src/ui/components/ApiKeyInput.js +35 -0
- package/dist/src/ui/components/ApiKeyInput.js.map +1 -0
- package/dist/src/ui/components/AppHeader.d.ts +10 -0
- package/dist/src/ui/components/AppHeader.js +49 -0
- package/dist/src/ui/components/AppHeader.js.map +1 -0
- package/dist/src/ui/components/AppHeader.test.d.ts +6 -0
- package/dist/src/ui/components/AppHeader.test.js +109 -0
- package/dist/src/ui/components/AppHeader.test.js.map +1 -0
- package/dist/src/ui/components/ApprovalModeDialog.d.ts +21 -0
- package/dist/src/ui/components/ApprovalModeDialog.js +109 -0
- package/dist/src/ui/components/ApprovalModeDialog.js.map +1 -0
- package/dist/src/ui/components/ApprovalModeDialog.test.d.ts +6 -0
- package/dist/src/ui/components/ApprovalModeDialog.test.js +63 -0
- package/dist/src/ui/components/ApprovalModeDialog.test.js.map +1 -0
- package/dist/src/ui/components/AsciiArt.d.ts +1 -0
- package/dist/src/ui/components/AsciiArt.js +54 -0
- package/dist/src/ui/components/AsciiArt.js.map +1 -0
- package/dist/src/ui/components/AutoAcceptIndicator.d.ts +12 -0
- package/dist/src/ui/components/AutoAcceptIndicator.js +37 -0
- package/dist/src/ui/components/AutoAcceptIndicator.js.map +1 -0
- package/dist/src/ui/components/BaseTextInput.d.ts +74 -0
- package/dist/src/ui/components/BaseTextInput.js +144 -0
- package/dist/src/ui/components/BaseTextInput.js.map +1 -0
- package/dist/src/ui/components/BaseTextInput.test.d.ts +6 -0
- package/dist/src/ui/components/BaseTextInput.test.js +78 -0
- package/dist/src/ui/components/BaseTextInput.test.js.map +1 -0
- package/dist/src/ui/components/Composer.d.ts +6 -0
- package/dist/src/ui/components/Composer.js +92 -0
- package/dist/src/ui/components/Composer.js.map +1 -0
- package/dist/src/ui/components/Composer.test.d.ts +6 -0
- package/dist/src/ui/components/Composer.test.js +344 -0
- package/dist/src/ui/components/Composer.test.js.map +1 -0
- package/dist/src/ui/components/ConsentPrompt.d.ts +14 -0
- package/dist/src/ui/components/ConsentPrompt.js +35 -0
- package/dist/src/ui/components/ConsentPrompt.js.map +1 -0
- package/dist/src/ui/components/ConsentPrompt.test.d.ts +6 -0
- package/dist/src/ui/components/ConsentPrompt.test.js +110 -0
- package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -0
- package/dist/src/ui/components/ContextSummaryDisplay.d.ts +20 -0
- package/dist/src/ui/components/ContextSummaryDisplay.js +90 -0
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -0
- package/dist/src/ui/components/ContextUsageDisplay.d.ts +10 -0
- package/dist/src/ui/components/ContextUsageDisplay.js +33 -0
- package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -0
- package/dist/src/ui/components/DebugModeNotification.d.ts +9 -0
- package/dist/src/ui/components/DebugModeNotification.js +23 -0
- package/dist/src/ui/components/DebugModeNotification.js.map +1 -0
- package/dist/src/ui/components/DebugProfiler.d.ts +6 -0
- package/dist/src/ui/components/DebugProfiler.js +27 -0
- package/dist/src/ui/components/DebugProfiler.js.map +1 -0
- package/dist/src/ui/components/DialogManager.d.ts +12 -0
- package/dist/src/ui/components/DialogManager.js +247 -0
- package/dist/src/ui/components/DialogManager.js.map +1 -0
- package/dist/src/ui/components/DiffDialog.d.ts +15 -0
- package/dist/src/ui/components/DiffDialog.js +412 -0
- package/dist/src/ui/components/DiffDialog.js.map +1 -0
- package/dist/src/ui/components/EditorSettingsDialog.d.ts +16 -0
- package/dist/src/ui/components/EditorSettingsDialog.js +76 -0
- package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -0
- package/dist/src/ui/components/ExitWarning.d.ts +7 -0
- package/dist/src/ui/components/ExitWarning.js +9 -0
- package/dist/src/ui/components/ExitWarning.js.map +1 -0
- package/dist/src/ui/components/ExternalAuthProgress.d.ts +14 -0
- package/dist/src/ui/components/ExternalAuthProgress.js +14 -0
- package/dist/src/ui/components/ExternalAuthProgress.js.map +1 -0
- package/dist/src/ui/components/ExternalAuthProgress.test.d.ts +6 -0
- package/dist/src/ui/components/ExternalAuthProgress.test.js +20 -0
- package/dist/src/ui/components/ExternalAuthProgress.test.js.map +1 -0
- package/dist/src/ui/components/FolderTrustDialog.d.ts +17 -0
- package/dist/src/ui/components/FolderTrustDialog.js +58 -0
- package/dist/src/ui/components/FolderTrustDialog.js.map +1 -0
- package/dist/src/ui/components/FolderTrustDialog.test.d.ts +6 -0
- package/dist/src/ui/components/FolderTrustDialog.test.js +88 -0
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -0
- package/dist/src/ui/components/Footer.d.ts +7 -0
- package/dist/src/ui/components/Footer.js +104 -0
- package/dist/src/ui/components/Footer.js.map +1 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.d.ts +22 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.js +47 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.js.map +1 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.test.d.ts +6 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.test.js +29 -0
- package/dist/src/ui/components/GeminiRespondingSpinner.test.js.map +1 -0
- package/dist/src/ui/components/GoalPill.d.ts +25 -0
- package/dist/src/ui/components/GoalPill.js +77 -0
- package/dist/src/ui/components/GoalPill.js.map +1 -0
- package/dist/src/ui/components/GoalPill.test.d.ts +6 -0
- package/dist/src/ui/components/GoalPill.test.js +56 -0
- package/dist/src/ui/components/GoalPill.test.js.map +1 -0
- package/dist/src/ui/components/Header.d.ts +62 -0
- package/dist/src/ui/components/Header.js +155 -0
- package/dist/src/ui/components/Header.js.map +1 -0
- package/dist/src/ui/components/Header.test.d.ts +6 -0
- package/dist/src/ui/components/Header.test.js +142 -0
- package/dist/src/ui/components/Header.test.js.map +1 -0
- package/dist/src/ui/components/Help.d.ts +18 -0
- package/dist/src/ui/components/Help.js +236 -0
- package/dist/src/ui/components/Help.js.map +1 -0
- package/dist/src/ui/components/Help.test.d.ts +6 -0
- package/dist/src/ui/components/Help.test.js +243 -0
- package/dist/src/ui/components/Help.test.js.map +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +39 -0
- package/dist/src/ui/components/HistoryItemDisplay.js +51 -0
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/HistoryItemDisplay.test.js +197 -0
- package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.d.ts +11 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.js +34 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.js.map +1 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.d.ts +6 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js +53 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js.map +1 -0
- package/dist/src/ui/components/InputPrompt.d.ts +63 -0
- package/dist/src/ui/components/InputPrompt.js +1220 -0
- package/dist/src/ui/components/InputPrompt.js.map +1 -0
- package/dist/src/ui/components/KeyboardShortcuts.d.ts +7 -0
- package/dist/src/ui/components/KeyboardShortcuts.js +78 -0
- package/dist/src/ui/components/KeyboardShortcuts.js.map +1 -0
- package/dist/src/ui/components/LoadingIndicator.d.ts +31 -0
- package/dist/src/ui/components/LoadingIndicator.js +46 -0
- package/dist/src/ui/components/LoadingIndicator.js.map +1 -0
- package/dist/src/ui/components/LoadingIndicator.test.d.ts +6 -0
- package/dist/src/ui/components/LoadingIndicator.test.js +246 -0
- package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.d.ts +13 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.js +37 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.d.ts +6 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js +28 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -0
- package/dist/src/ui/components/MainContent.d.ts +6 -0
- package/dist/src/ui/components/MainContent.js +437 -0
- package/dist/src/ui/components/MainContent.js.map +1 -0
- package/dist/src/ui/components/MainContent.test.d.ts +6 -0
- package/dist/src/ui/components/MainContent.test.js +621 -0
- package/dist/src/ui/components/MainContent.test.js.map +1 -0
- package/dist/src/ui/components/MemoryDialog.d.ts +10 -0
- package/dist/src/ui/components/MemoryDialog.js +288 -0
- package/dist/src/ui/components/MemoryDialog.js.map +1 -0
- package/dist/src/ui/components/MemoryDialog.test.d.ts +6 -0
- package/dist/src/ui/components/MemoryDialog.test.js +165 -0
- package/dist/src/ui/components/MemoryDialog.test.js.map +1 -0
- package/dist/src/ui/components/MemoryUsageDisplay.d.ts +7 -0
- package/dist/src/ui/components/MemoryUsageDisplay.js +24 -0
- package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -0
- package/dist/src/ui/components/ModelDialog.d.ts +12 -0
- package/dist/src/ui/components/ModelDialog.js +390 -0
- package/dist/src/ui/components/ModelDialog.js.map +1 -0
- package/dist/src/ui/components/ModelDialog.test.d.ts +6 -0
- package/dist/src/ui/components/ModelDialog.test.js +489 -0
- package/dist/src/ui/components/ModelDialog.test.js.map +1 -0
- package/dist/src/ui/components/ModelStatsDisplay.d.ts +11 -0
- package/dist/src/ui/components/ModelStatsDisplay.js +61 -0
- package/dist/src/ui/components/ModelStatsDisplay.js.map +1 -0
- package/dist/src/ui/components/Notifications.d.ts +6 -0
- package/dist/src/ui/components/Notifications.js +20 -0
- package/dist/src/ui/components/Notifications.js.map +1 -0
- package/dist/src/ui/components/PermissionsDialog.d.ts +11 -0
- package/dist/src/ui/components/PermissionsDialog.js +547 -0
- package/dist/src/ui/components/PermissionsDialog.js.map +1 -0
- package/dist/src/ui/components/PlanSummaryDisplay.d.ts +14 -0
- package/dist/src/ui/components/PlanSummaryDisplay.js +10 -0
- package/dist/src/ui/components/PlanSummaryDisplay.js.map +1 -0
- package/dist/src/ui/components/PluginChoicePrompt.d.ts +18 -0
- package/dist/src/ui/components/PluginChoicePrompt.js +96 -0
- package/dist/src/ui/components/PluginChoicePrompt.js.map +1 -0
- package/dist/src/ui/components/PluginChoicePrompt.test.d.ts +6 -0
- package/dist/src/ui/components/PluginChoicePrompt.test.js +136 -0
- package/dist/src/ui/components/PluginChoicePrompt.test.js.map +1 -0
- package/dist/src/ui/components/PrepareLabel.d.ts +15 -0
- package/dist/src/ui/components/PrepareLabel.js +72 -0
- package/dist/src/ui/components/PrepareLabel.js.map +1 -0
- package/dist/src/ui/components/PrepareLabel.test.d.ts +6 -0
- package/dist/src/ui/components/PrepareLabel.test.js +71 -0
- package/dist/src/ui/components/PrepareLabel.test.js.map +1 -0
- package/dist/src/ui/components/ProviderUpdatePrompt.d.ts +12 -0
- package/dist/src/ui/components/ProviderUpdatePrompt.js +49 -0
- package/dist/src/ui/components/ProviderUpdatePrompt.js.map +1 -0
- package/dist/src/ui/components/QueuedMessageDisplay.d.ts +9 -0
- package/dist/src/ui/components/QueuedMessageDisplay.js +35 -0
- package/dist/src/ui/components/QueuedMessageDisplay.js.map +1 -0
- package/dist/src/ui/components/QueuedMessageDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/QueuedMessageDisplay.test.js +76 -0
- package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -0
- package/dist/src/ui/components/QuittingDisplay.d.ts +6 -0
- package/dist/src/ui/components/QuittingDisplay.js +21 -0
- package/dist/src/ui/components/QuittingDisplay.js.map +1 -0
- package/dist/src/ui/components/QwenOAuthProgress.d.ts +16 -0
- package/dist/src/ui/components/QwenOAuthProgress.js +65 -0
- package/dist/src/ui/components/QwenOAuthProgress.js.map +1 -0
- package/dist/src/ui/components/QwenOAuthProgress.test.d.ts +6 -0
- package/dist/src/ui/components/QwenOAuthProgress.test.js +287 -0
- package/dist/src/ui/components/QwenOAuthProgress.test.js.map +1 -0
- package/dist/src/ui/components/RewindSelector.d.ts +22 -0
- package/dist/src/ui/components/RewindSelector.js +264 -0
- package/dist/src/ui/components/RewindSelector.js.map +1 -0
- package/dist/src/ui/components/RewindSelector.test.d.ts +6 -0
- package/dist/src/ui/components/RewindSelector.test.js +146 -0
- package/dist/src/ui/components/RewindSelector.test.js.map +1 -0
- package/dist/src/ui/components/SessionPicker.d.ts +55 -0
- package/dist/src/ui/components/SessionPicker.js +142 -0
- package/dist/src/ui/components/SessionPicker.js.map +1 -0
- package/dist/src/ui/components/SessionPreview.d.ts +20 -0
- package/dist/src/ui/components/SessionPreview.js +97 -0
- package/dist/src/ui/components/SessionPreview.js.map +1 -0
- package/dist/src/ui/components/SessionPreview.test.d.ts +1 -0
- package/dist/src/ui/components/SessionPreview.test.js +124 -0
- package/dist/src/ui/components/SessionPreview.test.js.map +1 -0
- package/dist/src/ui/components/SessionSummaryDisplay.d.ts +12 -0
- package/dist/src/ui/components/SessionSummaryDisplay.js +17 -0
- package/dist/src/ui/components/SessionSummaryDisplay.js.map +1 -0
- package/dist/src/ui/components/SettingInputPrompt.d.ts +15 -0
- package/dist/src/ui/components/SettingInputPrompt.js +63 -0
- package/dist/src/ui/components/SettingInputPrompt.js.map +1 -0
- package/dist/src/ui/components/SettingInputPrompt.test.d.ts +6 -0
- package/dist/src/ui/components/SettingInputPrompt.test.js +60 -0
- package/dist/src/ui/components/SettingInputPrompt.test.js.map +1 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.d.ts +14 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.js +44 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.js.map +1 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.test.d.ts +6 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.test.js +162 -0
- package/dist/src/ui/components/SettingsCorruptedDialog.test.js.map +1 -0
- package/dist/src/ui/components/SettingsDialog.d.ts +18 -0
- package/dist/src/ui/components/SettingsDialog.js +658 -0
- package/dist/src/ui/components/SettingsDialog.js.map +1 -0
- package/dist/src/ui/components/SettingsDialog.test.d.ts +6 -0
- package/dist/src/ui/components/SettingsDialog.test.js +1127 -0
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -0
- package/dist/src/ui/components/ShellConfirmationDialog.d.ts +17 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js +75 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -0
- package/dist/src/ui/components/ShellConfirmationDialog.test.d.ts +6 -0
- package/dist/src/ui/components/ShellConfirmationDialog.test.js +167 -0
- package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -0
- package/dist/src/ui/components/ShellInputPrompt.d.ts +11 -0
- package/dist/src/ui/components/ShellInputPrompt.js +42 -0
- package/dist/src/ui/components/ShellInputPrompt.js.map +1 -0
- package/dist/src/ui/components/ShellModeIndicator.d.ts +7 -0
- package/dist/src/ui/components/ShellModeIndicator.js +5 -0
- package/dist/src/ui/components/ShellModeIndicator.js.map +1 -0
- package/dist/src/ui/components/ShowMoreLines.d.ts +10 -0
- package/dist/src/ui/components/ShowMoreLines.js +24 -0
- package/dist/src/ui/components/ShowMoreLines.js.map +1 -0
- package/dist/src/ui/components/StandaloneSessionPicker.d.ts +11 -0
- package/dist/src/ui/components/StandaloneSessionPicker.js +105 -0
- package/dist/src/ui/components/StandaloneSessionPicker.js.map +1 -0
- package/dist/src/ui/components/StandaloneSessionPicker.test.d.ts +6 -0
- package/dist/src/ui/components/StandaloneSessionPicker.test.js +667 -0
- package/dist/src/ui/components/StandaloneSessionPicker.test.js.map +1 -0
- package/dist/src/ui/components/StatsActivityTab.d.ts +14 -0
- package/dist/src/ui/components/StatsActivityTab.js +85 -0
- package/dist/src/ui/components/StatsActivityTab.js.map +1 -0
- package/dist/src/ui/components/StatsDialog.d.ts +12 -0
- package/dist/src/ui/components/StatsDialog.js +104 -0
- package/dist/src/ui/components/StatsDialog.js.map +1 -0
- package/dist/src/ui/components/StatsDisplay.d.ts +13 -0
- package/dist/src/ui/components/StatsDisplay.js +52 -0
- package/dist/src/ui/components/StatsDisplay.js.map +1 -0
- package/dist/src/ui/components/StatsEfficiencyTab.d.ts +11 -0
- package/dist/src/ui/components/StatsEfficiencyTab.js +99 -0
- package/dist/src/ui/components/StatsEfficiencyTab.js.map +1 -0
- package/dist/src/ui/components/StatsHeatmapView.d.ts +12 -0
- package/dist/src/ui/components/StatsHeatmapView.js +40 -0
- package/dist/src/ui/components/StatsHeatmapView.js.map +1 -0
- package/dist/src/ui/components/StatsSessionTab.d.ts +7 -0
- package/dist/src/ui/components/StatsSessionTab.js +40 -0
- package/dist/src/ui/components/StatsSessionTab.js.map +1 -0
- package/dist/src/ui/components/StatusLineDialog.d.ts +22 -0
- package/dist/src/ui/components/StatusLineDialog.js +140 -0
- package/dist/src/ui/components/StatusLineDialog.js.map +1 -0
- package/dist/src/ui/components/StatusLineDialog.test.d.ts +6 -0
- package/dist/src/ui/components/StatusLineDialog.test.js +180 -0
- package/dist/src/ui/components/StatusLineDialog.test.js.map +1 -0
- package/dist/src/ui/components/StickyTodoList.d.ts +14 -0
- package/dist/src/ui/components/StickyTodoList.js +45 -0
- package/dist/src/ui/components/StickyTodoList.js.map +1 -0
- package/dist/src/ui/components/StickyTodoList.test.d.ts +6 -0
- package/dist/src/ui/components/StickyTodoList.test.js +128 -0
- package/dist/src/ui/components/StickyTodoList.test.js.map +1 -0
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +47 -0
- package/dist/src/ui/components/SuggestionsDisplay.js +43 -0
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -0
- package/dist/src/ui/components/SuggestionsDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/SuggestionsDisplay.test.js +39 -0
- package/dist/src/ui/components/SuggestionsDisplay.test.js.map +1 -0
- package/dist/src/ui/components/ThemeDialog.d.ts +20 -0
- package/dist/src/ui/components/ThemeDialog.js +137 -0
- package/dist/src/ui/components/ThemeDialog.js.map +1 -0
- package/dist/src/ui/components/ThemeDialog.test.d.ts +6 -0
- package/dist/src/ui/components/ThemeDialog.test.js +75 -0
- package/dist/src/ui/components/ThemeDialog.test.js.map +1 -0
- package/dist/src/ui/components/ThinkingDots.d.ts +11 -0
- package/dist/src/ui/components/ThinkingDots.js +47 -0
- package/dist/src/ui/components/ThinkingDots.js.map +1 -0
- package/dist/src/ui/components/ThinkingIndicator.d.ts +7 -0
- package/dist/src/ui/components/ThinkingIndicator.js +13 -0
- package/dist/src/ui/components/ThinkingIndicator.js.map +1 -0
- package/dist/src/ui/components/Tips.d.ts +6 -0
- package/dist/src/ui/components/Tips.js +37 -0
- package/dist/src/ui/components/Tips.js.map +1 -0
- package/dist/src/ui/components/Tips.test.d.ts +6 -0
- package/dist/src/ui/components/Tips.test.js +145 -0
- package/dist/src/ui/components/Tips.test.js.map +1 -0
- package/dist/src/ui/components/TodoDisplay.d.ts +16 -0
- package/dist/src/ui/components/TodoDisplay.js +27 -0
- package/dist/src/ui/components/TodoDisplay.js.map +1 -0
- package/dist/src/ui/components/TodoDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/TodoDisplay.test.js +77 -0
- package/dist/src/ui/components/TodoDisplay.test.js.map +1 -0
- package/dist/src/ui/components/ToolStatsDisplay.d.ts +11 -0
- package/dist/src/ui/components/ToolStatsDisplay.js +42 -0
- package/dist/src/ui/components/ToolStatsDisplay.js.map +1 -0
- package/dist/src/ui/components/TrustDialog.d.ts +13 -0
- package/dist/src/ui/components/TrustDialog.js +48 -0
- package/dist/src/ui/components/TrustDialog.js.map +1 -0
- package/dist/src/ui/components/TrustDialog.test.d.ts +6 -0
- package/dist/src/ui/components/TrustDialog.test.js +154 -0
- package/dist/src/ui/components/TrustDialog.test.js.map +1 -0
- package/dist/src/ui/components/UpdateNotification.d.ts +10 -0
- package/dist/src/ui/components/UpdateNotification.js +10 -0
- package/dist/src/ui/components/UpdateNotification.js.map +1 -0
- package/dist/src/ui/components/WelcomeBackDialog.d.ts +13 -0
- package/dist/src/ui/components/WelcomeBackDialog.js +43 -0
- package/dist/src/ui/components/WelcomeBackDialog.js.map +1 -0
- package/dist/src/ui/components/WorktreeExitDialog.d.ts +26 -0
- package/dist/src/ui/components/WorktreeExitDialog.js +134 -0
- package/dist/src/ui/components/WorktreeExitDialog.js.map +1 -0
- package/dist/src/ui/components/WorktreeExitDialog.test.d.ts +6 -0
- package/dist/src/ui/components/WorktreeExitDialog.test.js +41 -0
- package/dist/src/ui/components/WorktreeExitDialog.test.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentChatContent.d.ts +27 -0
- package/dist/src/ui/components/agent-view/AgentChatContent.js +150 -0
- package/dist/src/ui/components/agent-view/AgentChatContent.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentChatView.d.ts +10 -0
- package/dist/src/ui/components/agent-view/AgentChatView.js +24 -0
- package/dist/src/ui/components/agent-view/AgentChatView.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentComposer.d.ts +10 -0
- package/dist/src/ui/components/agent-view/AgentComposer.js +183 -0
- package/dist/src/ui/components/agent-view/AgentComposer.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentFooter.d.ts +20 -0
- package/dist/src/ui/components/agent-view/AgentFooter.js +15 -0
- package/dist/src/ui/components/agent-view/AgentFooter.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentHeader.d.ts +19 -0
- package/dist/src/ui/components/agent-view/AgentHeader.js +13 -0
- package/dist/src/ui/components/agent-view/AgentHeader.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.d.ts +6 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.js +110 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.js.map +1 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.test.d.ts +6 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.test.js +90 -0
- package/dist/src/ui/components/agent-view/AgentTabBar.test.js.map +1 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.d.ts +31 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.js +148 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.js.map +1 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.test.d.ts +6 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.test.js +318 -0
- package/dist/src/ui/components/agent-view/agentHistoryAdapter.test.js.map +1 -0
- package/dist/src/ui/components/agent-view/index.d.ts +11 -0
- package/dist/src/ui/components/agent-view/index.js +12 -0
- package/dist/src/ui/components/agent-view/index.js.map +1 -0
- package/dist/src/ui/components/approvalModeVisuals.d.ts +11 -0
- package/dist/src/ui/components/approvalModeVisuals.js +37 -0
- package/dist/src/ui/components/approvalModeVisuals.js.map +1 -0
- package/dist/src/ui/components/approvalModeVisuals.test.d.ts +6 -0
- package/dist/src/ui/components/approvalModeVisuals.test.js +32 -0
- package/dist/src/ui/components/approvalModeVisuals.test.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaCards.d.ts +21 -0
- package/dist/src/ui/components/arena/ArenaCards.js +99 -0
- package/dist/src/ui/components/arena/ArenaCards.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaCards.test.d.ts +6 -0
- package/dist/src/ui/components/arena/ArenaCards.test.js +128 -0
- package/dist/src/ui/components/arena/ArenaCards.test.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.d.ts +16 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.js +213 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.test.d.ts +6 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.test.js +149 -0
- package/dist/src/ui/components/arena/ArenaSelectDialog.test.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaStartDialog.d.ts +12 -0
- package/dist/src/ui/components/arena/ArenaStartDialog.js +49 -0
- package/dist/src/ui/components/arena/ArenaStartDialog.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaStatusDialog.d.ts +14 -0
- package/dist/src/ui/components/arena/ArenaStatusDialog.js +111 -0
- package/dist/src/ui/components/arena/ArenaStatusDialog.js.map +1 -0
- package/dist/src/ui/components/arena/ArenaStopDialog.d.ts +15 -0
- package/dist/src/ui/components/arena/ArenaStopDialog.js +113 -0
- package/dist/src/ui/components/arena/ArenaStopDialog.js.map +1 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.d.ts +17 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.js +614 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.js.map +1 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.test.d.ts +6 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.test.js +606 -0
- package/dist/src/ui/components/background-view/BackgroundTasksDialog.test.js.map +1 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.d.ts +14 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.js +94 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.js.map +1 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.test.d.ts +6 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.test.js +158 -0
- package/dist/src/ui/components/background-view/BackgroundTasksPill.test.js.map +1 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.d.ts +43 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.js +361 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.js.map +1 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.test.d.ts +6 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.test.js +595 -0
- package/dist/src/ui/components/background-view/LiveAgentPanel.test.js.map +1 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.d.ts +12 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.js +337 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.js.map +1 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.test.d.ts +6 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.test.js +90 -0
- package/dist/src/ui/components/extensions/ExtensionsManagerDialog.test.js.map +1 -0
- package/dist/src/ui/components/extensions/index.d.ts +8 -0
- package/dist/src/ui/components/extensions/index.js +8 -0
- package/dist/src/ui/components/extensions/index.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.d.ts +15 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.js +75 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.test.d.ts +6 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.test.js +56 -0
- package/dist/src/ui/components/extensions/steps/ActionSelectionStep.test.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ExtensionDetailStep.d.ts +11 -0
- package/dist/src/ui/components/extensions/steps/ExtensionDetailStep.js +23 -0
- package/dist/src/ui/components/extensions/steps/ExtensionDetailStep.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.d.ts +13 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.js +105 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.test.d.ts +6 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.test.js +74 -0
- package/dist/src/ui/components/extensions/steps/ExtensionListStep.test.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/ScopeSelectStep.d.ts +13 -0
- package/dist/src/ui/components/extensions/steps/ScopeSelectStep.js +40 -0
- package/dist/src/ui/components/extensions/steps/ScopeSelectStep.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/UninstallConfirmStep.d.ts +13 -0
- package/dist/src/ui/components/extensions/steps/UninstallConfirmStep.js +38 -0
- package/dist/src/ui/components/extensions/steps/UninstallConfirmStep.js.map +1 -0
- package/dist/src/ui/components/extensions/steps/index.d.ts +10 -0
- package/dist/src/ui/components/extensions/steps/index.js +11 -0
- package/dist/src/ui/components/extensions/steps/index.js.map +1 -0
- package/dist/src/ui/components/extensions/types.d.ts +73 -0
- package/dist/src/ui/components/extensions/types.js +18 -0
- package/dist/src/ui/components/extensions/types.js.map +1 -0
- package/dist/src/ui/components/hooks/HandlerListBody.d.ts +12 -0
- package/dist/src/ui/components/hooks/HandlerListBody.js +54 -0
- package/dist/src/ui/components/hooks/HandlerListBody.js.map +1 -0
- package/dist/src/ui/components/hooks/HandlerListBody.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HandlerListBody.test.js +175 -0
- package/dist/src/ui/components/hooks/HandlerListBody.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.d.ts +12 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.js +48 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.test.js +236 -0
- package/dist/src/ui/components/hooks/HookConfigDetailStep.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HookDetailStep.d.ts +12 -0
- package/dist/src/ui/components/hooks/HookDetailStep.js +11 -0
- package/dist/src/ui/components/hooks/HookDetailStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HookDetailStep.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HookDetailStep.test.js +241 -0
- package/dist/src/ui/components/hooks/HookDetailStep.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HookEventHandlerListStep.d.ts +12 -0
- package/dist/src/ui/components/hooks/HookEventHandlerListStep.js +18 -0
- package/dist/src/ui/components/hooks/HookEventHandlerListStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HookEventHeader.d.ts +13 -0
- package/dist/src/ui/components/hooks/HookEventHeader.js +23 -0
- package/dist/src/ui/components/hooks/HookEventHeader.js.map +1 -0
- package/dist/src/ui/components/hooks/HookEventMatcherListStep.d.ts +12 -0
- package/dist/src/ui/components/hooks/HookEventMatcherListStep.js +28 -0
- package/dist/src/ui/components/hooks/HookEventMatcherListStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.d.ts +13 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.js +16 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.test.js +154 -0
- package/dist/src/ui/components/hooks/HookMatcherDetailStep.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.d.ts +10 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.js +23 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.test.js +86 -0
- package/dist/src/ui/components/hooks/HooksDisabledStep.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksListStep.d.ts +12 -0
- package/dist/src/ui/components/hooks/HooksListStep.js +32 -0
- package/dist/src/ui/components/hooks/HooksListStep.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksListStep.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HooksListStep.test.js +144 -0
- package/dist/src/ui/components/hooks/HooksListStep.test.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.d.ts +7 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.js +418 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.js.map +1 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.test.js +305 -0
- package/dist/src/ui/components/hooks/HooksManagementDialog.test.js.map +1 -0
- package/dist/src/ui/components/hooks/constants.d.ts +26 -0
- package/dist/src/ui/components/hooks/constants.js +227 -0
- package/dist/src/ui/components/hooks/constants.js.map +1 -0
- package/dist/src/ui/components/hooks/constants.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/constants.test.js +317 -0
- package/dist/src/ui/components/hooks/constants.test.js.map +1 -0
- package/dist/src/ui/components/hooks/index.d.ts +12 -0
- package/dist/src/ui/components/hooks/index.js +13 -0
- package/dist/src/ui/components/hooks/index.js.map +1 -0
- package/dist/src/ui/components/hooks/matcherGrouping.d.ts +9 -0
- package/dist/src/ui/components/hooks/matcherGrouping.js +35 -0
- package/dist/src/ui/components/hooks/matcherGrouping.js.map +1 -0
- package/dist/src/ui/components/hooks/matcherGrouping.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/matcherGrouping.test.js +183 -0
- package/dist/src/ui/components/hooks/matcherGrouping.test.js.map +1 -0
- package/dist/src/ui/components/hooks/sourceLabels.d.ts +13 -0
- package/dist/src/ui/components/hooks/sourceLabels.js +35 -0
- package/dist/src/ui/components/hooks/sourceLabels.js.map +1 -0
- package/dist/src/ui/components/hooks/sourceLabels.test.d.ts +6 -0
- package/dist/src/ui/components/hooks/sourceLabels.test.js +81 -0
- package/dist/src/ui/components/hooks/sourceLabels.test.js.map +1 -0
- package/dist/src/ui/components/hooks/types.d.ts +42 -0
- package/dist/src/ui/components/hooks/types.js +13 -0
- package/dist/src/ui/components/hooks/types.js.map +1 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.d.ts +24 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.js +33 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.js.map +1 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.test.d.ts +6 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.test.js +42 -0
- package/dist/src/ui/components/mcp/MCPHealthPill.test.js.map +1 -0
- package/dist/src/ui/components/mcp/MCPManagementDialog.d.ts +7 -0
- package/dist/src/ui/components/mcp/MCPManagementDialog.js +472 -0
- package/dist/src/ui/components/mcp/MCPManagementDialog.js.map +1 -0
- package/dist/src/ui/components/mcp/constants.d.ts +29 -0
- package/dist/src/ui/components/mcp/constants.js +34 -0
- package/dist/src/ui/components/mcp/constants.js.map +1 -0
- package/dist/src/ui/components/mcp/index.d.ts +12 -0
- package/dist/src/ui/components/mcp/index.js +15 -0
- package/dist/src/ui/components/mcp/index.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/AuthenticateStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/AuthenticateStep.js +187 -0
- package/dist/src/ui/components/mcp/steps/AuthenticateStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/DisableScopeSelectStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/DisableScopeSelectStep.js +44 -0
- package/dist/src/ui/components/mcp/steps/DisableScopeSelectStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ServerDetailStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/ServerDetailStep.js +108 -0
- package/dist/src/ui/components/mcp/steps/ServerDetailStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.js +74 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.test.d.ts +6 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.test.js +60 -0
- package/dist/src/ui/components/mcp/steps/ServerListStep.test.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ToolDetailStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/ToolDetailStep.js +49 -0
- package/dist/src/ui/components/mcp/steps/ToolDetailStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.d.ts +7 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.js +80 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.js.map +1 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.test.d.ts +6 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.test.js +55 -0
- package/dist/src/ui/components/mcp/steps/ToolListStep.test.js.map +1 -0
- package/dist/src/ui/components/mcp/types.d.ts +177 -0
- package/dist/src/ui/components/mcp/types.js +17 -0
- package/dist/src/ui/components/mcp/types.js.map +1 -0
- package/dist/src/ui/components/mcp/utils.d.ts +40 -0
- package/dist/src/ui/components/mcp/utils.js +126 -0
- package/dist/src/ui/components/mcp/utils.js.map +1 -0
- package/dist/src/ui/components/mcp/utils.test.d.ts +6 -0
- package/dist/src/ui/components/mcp/utils.test.js +130 -0
- package/dist/src/ui/components/mcp/utils.test.js.map +1 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.d.ts +14 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.js +291 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.js.map +1 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.test.d.ts +6 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.test.js +281 -0
- package/dist/src/ui/components/messages/AskUserQuestionDialog.test.js.map +1 -0
- package/dist/src/ui/components/messages/BtwMessage.d.ts +14 -0
- package/dist/src/ui/components/messages/BtwMessage.js +30 -0
- package/dist/src/ui/components/messages/BtwMessage.js.map +1 -0
- package/dist/src/ui/components/messages/BtwMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/BtwMessage.test.js +60 -0
- package/dist/src/ui/components/messages/BtwMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.d.ts +20 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.js +80 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.js.map +1 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.test.js +139 -0
- package/dist/src/ui/components/messages/CompactToolGroupDisplay.test.js.map +1 -0
- package/dist/src/ui/components/messages/CompressionMessage.d.ts +10 -0
- package/dist/src/ui/components/messages/CompressionMessage.js +50 -0
- package/dist/src/ui/components/messages/CompressionMessage.js.map +1 -0
- package/dist/src/ui/components/messages/CompressionMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/CompressionMessage.test.js +160 -0
- package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/ConversationMessages.d.ts +46 -0
- package/dist/src/ui/components/messages/ConversationMessages.js +32 -0
- package/dist/src/ui/components/messages/ConversationMessages.js.map +1 -0
- package/dist/src/ui/components/messages/DiffRenderer.d.ts +19 -0
- package/dist/src/ui/components/messages/DiffRenderer.js +219 -0
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -0
- package/dist/src/ui/components/messages/DiffRenderer.test.d.ts +6 -0
- package/dist/src/ui/components/messages/DiffRenderer.test.js +296 -0
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.d.ts +18 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.js +50 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.js.map +1 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.test.js +165 -0
- package/dist/src/ui/components/messages/DiffStatsDisplay.test.js.map +1 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.d.ts +16 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.js +76 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.js.map +1 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.test.js +32 -0
- package/dist/src/ui/components/messages/GoalStatusMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.d.ts +33 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.js +196 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.js.map +1 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.test.js +219 -0
- package/dist/src/ui/components/messages/InlineParallelAgentsDisplay.test.js.map +1 -0
- package/dist/src/ui/components/messages/InsightProgressMessage.d.ts +12 -0
- package/dist/src/ui/components/messages/InsightProgressMessage.js +20 -0
- package/dist/src/ui/components/messages/InsightProgressMessage.js.map +1 -0
- package/dist/src/ui/components/messages/MemorySavedMessage.d.ts +18 -0
- package/dist/src/ui/components/messages/MemorySavedMessage.js +15 -0
- package/dist/src/ui/components/messages/MemorySavedMessage.js.map +1 -0
- package/dist/src/ui/components/messages/StatusMessages.d.ts +33 -0
- package/dist/src/ui/components/messages/StatusMessages.js +28 -0
- package/dist/src/ui/components/messages/StatusMessages.js.map +1 -0
- package/dist/src/ui/components/messages/StatusMessages.test.d.ts +6 -0
- package/dist/src/ui/components/messages/StatusMessages.test.js +21 -0
- package/dist/src/ui/components/messages/StatusMessages.test.js.map +1 -0
- package/dist/src/ui/components/messages/SummaryMessage.d.ts +11 -0
- package/dist/src/ui/components/messages/SummaryMessage.js +38 -0
- package/dist/src/ui/components/messages/SummaryMessage.js.map +1 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.d.ts +16 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +352 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +312 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +58 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.js +278 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +619 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/ToolMessage.d.ts +39 -0
- package/dist/src/ui/components/messages/ToolMessage.js +400 -0
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -0
- package/dist/src/ui/components/messages/ToolMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/ToolMessage.test.js +575 -0
- package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -0
- package/dist/src/ui/components/shared/BaseSelectionList.d.ts +40 -0
- package/dist/src/ui/components/shared/BaseSelectionList.js +75 -0
- package/dist/src/ui/components/shared/BaseSelectionList.js.map +1 -0
- package/dist/src/ui/components/shared/BaseSelectionList.test.d.ts +6 -0
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +376 -0
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.d.ts +37 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.js +13 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.js.map +1 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.d.ts +6 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js +79 -0
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js.map +1 -0
- package/dist/src/ui/components/shared/EnumSelector.d.ts +18 -0
- package/dist/src/ui/components/shared/EnumSelector.js +44 -0
- package/dist/src/ui/components/shared/EnumSelector.js.map +1 -0
- package/dist/src/ui/components/shared/EnumSelector.test.d.ts +6 -0
- package/dist/src/ui/components/shared/EnumSelector.test.js +70 -0
- package/dist/src/ui/components/shared/EnumSelector.test.js.map +1 -0
- package/dist/src/ui/components/shared/MaxSizedBox.d.ts +61 -0
- package/dist/src/ui/components/shared/MaxSizedBox.js +453 -0
- package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -0
- package/dist/src/ui/components/shared/MaxSizedBox.test.d.ts +6 -0
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +154 -0
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -0
- package/dist/src/ui/components/shared/MultiSelect.d.ts +30 -0
- package/dist/src/ui/components/shared/MultiSelect.js +94 -0
- package/dist/src/ui/components/shared/MultiSelect.js.map +1 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.d.ts +45 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.js +21 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.test.d.ts +6 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js +134 -0
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js.map +1 -0
- package/dist/src/ui/components/shared/ScopeSelector.d.ts +19 -0
- package/dist/src/ui/components/shared/ScopeSelector.js +16 -0
- package/dist/src/ui/components/shared/ScopeSelector.js.map +1 -0
- package/dist/src/ui/components/shared/ScrollableList.d.ts +19 -0
- package/dist/src/ui/components/shared/ScrollableList.js +97 -0
- package/dist/src/ui/components/shared/ScrollableList.js.map +1 -0
- package/dist/src/ui/components/shared/ScrollableList.test.d.ts +6 -0
- package/dist/src/ui/components/shared/ScrollableList.test.js +158 -0
- package/dist/src/ui/components/shared/ScrollableList.test.js.map +1 -0
- package/dist/src/ui/components/shared/StaticRender.d.ts +25 -0
- package/dist/src/ui/components/shared/StaticRender.js +25 -0
- package/dist/src/ui/components/shared/StaticRender.js.map +1 -0
- package/dist/src/ui/components/shared/TextInput.d.ts +25 -0
- package/dist/src/ui/components/shared/TextInput.js +163 -0
- package/dist/src/ui/components/shared/TextInput.js.map +1 -0
- package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
- package/dist/src/ui/components/shared/TextInput.test.js +91 -0
- package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.d.ts +30 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.js +43 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.js.map +1 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.test.d.ts +6 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.test.js +63 -0
- package/dist/src/ui/components/shared/ToolElapsedTime.test.js.map +1 -0
- package/dist/src/ui/components/shared/ToolStatusIndicator.d.ts +14 -0
- package/dist/src/ui/components/shared/ToolStatusIndicator.js +13 -0
- package/dist/src/ui/components/shared/ToolStatusIndicator.js.map +1 -0
- package/dist/src/ui/components/shared/VirtualizedList.d.ts +49 -0
- package/dist/src/ui/components/shared/VirtualizedList.js +529 -0
- package/dist/src/ui/components/shared/VirtualizedList.js.map +1 -0
- package/dist/src/ui/components/shared/VirtualizedList.test.d.ts +6 -0
- package/dist/src/ui/components/shared/VirtualizedList.test.js +371 -0
- package/dist/src/ui/components/shared/VirtualizedList.test.js.map +1 -0
- package/dist/src/ui/components/shared/text-buffer-external-editor.test.d.ts +6 -0
- package/dist/src/ui/components/shared/text-buffer-external-editor.test.js +657 -0
- package/dist/src/ui/components/shared/text-buffer-external-editor.test.js.map +1 -0
- package/dist/src/ui/components/shared/text-buffer.d.ts +503 -0
- package/dist/src/ui/components/shared/text-buffer.js +2181 -0
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.d.ts +74 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js +612 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -0
- package/dist/src/ui/components/skills/SkillsManagerDialog.d.ts +44 -0
- package/dist/src/ui/components/skills/SkillsManagerDialog.js +423 -0
- package/dist/src/ui/components/skills/SkillsManagerDialog.js.map +1 -0
- package/dist/src/ui/components/stats-helpers.d.ts +30 -0
- package/dist/src/ui/components/stats-helpers.js +79 -0
- package/dist/src/ui/components/stats-helpers.js.map +1 -0
- package/dist/src/ui/components/subagents/constants.d.ts +23 -0
- package/dist/src/ui/components/subagents/constants.js +67 -0
- package/dist/src/ui/components/subagents/constants.js.map +1 -0
- package/dist/src/ui/components/subagents/create/AgentCreationWizard.d.ts +15 -0
- package/dist/src/ui/components/subagents/create/AgentCreationWizard.js +173 -0
- package/dist/src/ui/components/subagents/create/AgentCreationWizard.js.map +1 -0
- package/dist/src/ui/components/subagents/create/ColorSelector.d.ts +15 -0
- package/dist/src/ui/components/subagents/create/ColorSelector.js +43 -0
- package/dist/src/ui/components/subagents/create/ColorSelector.js.map +1 -0
- package/dist/src/ui/components/subagents/create/CreationSummary.d.ts +10 -0
- package/dist/src/ui/components/subagents/create/CreationSummary.js +176 -0
- package/dist/src/ui/components/subagents/create/CreationSummary.js.map +1 -0
- package/dist/src/ui/components/subagents/create/DescriptionInput.d.ts +10 -0
- package/dist/src/ui/components/subagents/create/DescriptionInput.js +107 -0
- package/dist/src/ui/components/subagents/create/DescriptionInput.js.map +1 -0
- package/dist/src/ui/components/subagents/create/GenerationMethodSelector.d.ts +10 -0
- package/dist/src/ui/components/subagents/create/GenerationMethodSelector.js +39 -0
- package/dist/src/ui/components/subagents/create/GenerationMethodSelector.js.map +1 -0
- package/dist/src/ui/components/subagents/create/LocationSelector.d.ts +10 -0
- package/dist/src/ui/components/subagents/create/LocationSelector.js +39 -0
- package/dist/src/ui/components/subagents/create/LocationSelector.js.map +1 -0
- package/dist/src/ui/components/subagents/create/TextEntryStep.d.ts +26 -0
- package/dist/src/ui/components/subagents/create/TextEntryStep.js +28 -0
- package/dist/src/ui/components/subagents/create/TextEntryStep.js.map +1 -0
- package/dist/src/ui/components/subagents/create/ToolSelector.d.ts +16 -0
- package/dist/src/ui/components/subagents/create/ToolSelector.js +145 -0
- package/dist/src/ui/components/subagents/create/ToolSelector.js.map +1 -0
- package/dist/src/ui/components/subagents/index.d.ts +7 -0
- package/dist/src/ui/components/subagents/index.js +13 -0
- package/dist/src/ui/components/subagents/index.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/ActionSelectionStep.d.ts +13 -0
- package/dist/src/ui/components/subagents/manage/ActionSelectionStep.js +73 -0
- package/dist/src/ui/components/subagents/manage/ActionSelectionStep.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentDeleteStep.d.ts +13 -0
- package/dist/src/ui/components/subagents/manage/AgentDeleteStep.js +38 -0
- package/dist/src/ui/components/subagents/manage/AgentDeleteStep.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentEditStep.d.ts +15 -0
- package/dist/src/ui/components/subagents/manage/AgentEditStep.js +76 -0
- package/dist/src/ui/components/subagents/manage/AgentEditStep.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.d.ts +12 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.js +342 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.test.d.ts +6 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.test.js +56 -0
- package/dist/src/ui/components/subagents/manage/AgentSelectionStep.test.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentViewerStep.d.ts +11 -0
- package/dist/src/ui/components/subagents/manage/AgentViewerStep.js +20 -0
- package/dist/src/ui/components/subagents/manage/AgentViewerStep.js.map +1 -0
- package/dist/src/ui/components/subagents/manage/AgentsManagerDialog.d.ts +15 -0
- package/dist/src/ui/components/subagents/manage/AgentsManagerDialog.js +214 -0
- package/dist/src/ui/components/subagents/manage/AgentsManagerDialog.js.map +1 -0
- package/dist/src/ui/components/subagents/reducers.d.ts +14 -0
- package/dist/src/ui/components/subagents/reducers.js +162 -0
- package/dist/src/ui/components/subagents/reducers.js.map +1 -0
- package/dist/src/ui/components/subagents/types.d.ts +137 -0
- package/dist/src/ui/components/subagents/types.js +15 -0
- package/dist/src/ui/components/subagents/types.js.map +1 -0
- package/dist/src/ui/components/subagents/utils.d.ts +15 -0
- package/dist/src/ui/components/subagents/utils.js +79 -0
- package/dist/src/ui/components/subagents/utils.js.map +1 -0
- package/dist/src/ui/components/views/ContextUsage.d.ts +23 -0
- package/dist/src/ui/components/views/ContextUsage.js +130 -0
- package/dist/src/ui/components/views/ContextUsage.js.map +1 -0
- package/dist/src/ui/components/views/ContextUsage.test.d.ts +6 -0
- package/dist/src/ui/components/views/ContextUsage.test.js +76 -0
- package/dist/src/ui/components/views/ContextUsage.test.js.map +1 -0
- package/dist/src/ui/components/views/DoctorReport.d.ts +18 -0
- package/dist/src/ui/components/views/DoctorReport.js +45 -0
- package/dist/src/ui/components/views/DoctorReport.js.map +1 -0
- package/dist/src/ui/components/views/ExtensionsList.d.ts +6 -0
- package/dist/src/ui/components/views/ExtensionsList.js +49 -0
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -0
- package/dist/src/ui/components/views/ExtensionsList.test.d.ts +6 -0
- package/dist/src/ui/components/views/ExtensionsList.test.js +88 -0
- package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -0
- package/dist/src/ui/components/views/McpStatus.d.ts +27 -0
- package/dist/src/ui/components/views/McpStatus.js +90 -0
- package/dist/src/ui/components/views/McpStatus.js.map +1 -0
- package/dist/src/ui/components/views/McpStatus.test.d.ts +6 -0
- package/dist/src/ui/components/views/McpStatus.test.js +117 -0
- package/dist/src/ui/components/views/McpStatus.test.js.map +1 -0
- package/dist/src/ui/components/views/SkillsList.d.ts +12 -0
- package/dist/src/ui/components/views/SkillsList.js +7 -0
- package/dist/src/ui/components/views/SkillsList.js.map +1 -0
- package/dist/src/ui/components/views/ToolsList.d.ts +14 -0
- package/dist/src/ui/components/views/ToolsList.js +8 -0
- package/dist/src/ui/components/views/ToolsList.js.map +1 -0
- package/dist/src/ui/components/views/ToolsList.test.d.ts +6 -0
- package/dist/src/ui/components/views/ToolsList.test.js +45 -0
- package/dist/src/ui/components/views/ToolsList.test.js.map +1 -0
- package/dist/src/ui/constants.d.ts +18 -0
- package/dist/src/ui/constants.js +23 -0
- package/dist/src/ui/constants.js.map +1 -0
- package/dist/src/ui/contexts/AgentViewContext.d.ts +49 -0
- package/dist/src/ui/contexts/AgentViewContext.js +187 -0
- package/dist/src/ui/contexts/AgentViewContext.js.map +1 -0
- package/dist/src/ui/contexts/AppContext.d.ts +11 -0
- package/dist/src/ui/contexts/AppContext.js +15 -0
- package/dist/src/ui/contexts/AppContext.js.map +1 -0
- package/dist/src/ui/contexts/BackgroundTaskViewContext.d.ts +60 -0
- package/dist/src/ui/contexts/BackgroundTaskViewContext.js +238 -0
- package/dist/src/ui/contexts/BackgroundTaskViewContext.js.map +1 -0
- package/dist/src/ui/contexts/CompactModeContext.d.ts +13 -0
- package/dist/src/ui/contexts/CompactModeContext.js +13 -0
- package/dist/src/ui/contexts/CompactModeContext.js.map +1 -0
- package/dist/src/ui/contexts/ConfigContext.d.ts +9 -0
- package/dist/src/ui/contexts/ConfigContext.js +16 -0
- package/dist/src/ui/contexts/ConfigContext.js.map +1 -0
- package/dist/src/ui/contexts/KeypressContext.d.ts +40 -0
- package/dist/src/ui/contexts/KeypressContext.js +959 -0
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -0
- package/dist/src/ui/contexts/KeypressContext.test.d.ts +6 -0
- package/dist/src/ui/contexts/KeypressContext.test.js +1360 -0
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -0
- package/dist/src/ui/contexts/OverflowContext.d.ts +19 -0
- package/dist/src/ui/contexts/OverflowContext.js +38 -0
- package/dist/src/ui/contexts/OverflowContext.js.map +1 -0
- package/dist/src/ui/contexts/RenderModeContext.d.ts +14 -0
- package/dist/src/ui/contexts/RenderModeContext.js +15 -0
- package/dist/src/ui/contexts/RenderModeContext.js.map +1 -0
- package/dist/src/ui/contexts/SessionContext.d.ts +47 -0
- package/dist/src/ui/contexts/SessionContext.js +180 -0
- package/dist/src/ui/contexts/SessionContext.js.map +1 -0
- package/dist/src/ui/contexts/SettingsContext.d.ts +9 -0
- package/dist/src/ui/contexts/SettingsContext.js +15 -0
- package/dist/src/ui/contexts/SettingsContext.js.map +1 -0
- package/dist/src/ui/contexts/ShellFocusContext.d.ts +7 -0
- package/dist/src/ui/contexts/ShellFocusContext.js +9 -0
- package/dist/src/ui/contexts/ShellFocusContext.js.map +1 -0
- package/dist/src/ui/contexts/StreamingContext.d.ts +9 -0
- package/dist/src/ui/contexts/StreamingContext.js +15 -0
- package/dist/src/ui/contexts/StreamingContext.js.map +1 -0
- package/dist/src/ui/contexts/TerminalOutputContext.d.ts +12 -0
- package/dist/src/ui/contexts/TerminalOutputContext.js +11 -0
- package/dist/src/ui/contexts/TerminalOutputContext.js.map +1 -0
- package/dist/src/ui/contexts/UIActionsContext.d.ts +91 -0
- package/dist/src/ui/contexts/UIActionsContext.js +22 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -0
- package/dist/src/ui/contexts/UIStateContext.d.ts +158 -0
- package/dist/src/ui/contexts/UIStateContext.js +20 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -0
- package/dist/src/ui/contexts/VimModeContext.d.ts +31 -0
- package/dist/src/ui/contexts/VimModeContext.js +60 -0
- package/dist/src/ui/contexts/VimModeContext.js.map +1 -0
- package/dist/src/ui/contexts/VimModeContext.test.d.ts +11 -0
- package/dist/src/ui/contexts/VimModeContext.test.js +99 -0
- package/dist/src/ui/contexts/VimModeContext.test.js.map +1 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.d.ts +101 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.js +695 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.js.map +1 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.test.d.ts +6 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.test.js +784 -0
- package/dist/src/ui/daemon/DaemonTuiAdapter.test.js.map +1 -0
- package/dist/src/ui/editors/editorSettingsManager.d.ts +19 -0
- package/dist/src/ui/editors/editorSettingsManager.js +48 -0
- package/dist/src/ui/editors/editorSettingsManager.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.d.ts +33 -0
- package/dist/src/ui/hooks/atCommandProcessor.js +344 -0
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.test.d.ts +6 -0
- package/dist/src/ui/hooks/atCommandProcessor.test.js +871 -0
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -0
- package/dist/src/ui/hooks/keyToAnsi.d.ts +15 -0
- package/dist/src/ui/hooks/keyToAnsi.js +67 -0
- package/dist/src/ui/hooks/keyToAnsi.js.map +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +18 -0
- package/dist/src/ui/hooks/shellCommandProcessor.js +287 -0
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.test.d.ts +6 -0
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +509 -0
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -0
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +71 -0
- package/dist/src/ui/hooks/slashCommandProcessor.js +837 -0
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -0
- package/dist/src/ui/hooks/useAgentStreamingState.d.ts +29 -0
- package/dist/src/ui/hooks/useAgentStreamingState.js +109 -0
- package/dist/src/ui/hooks/useAgentStreamingState.js.map +1 -0
- package/dist/src/ui/hooks/useAgentsManagerDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useAgentsManagerDialog.js +21 -0
- package/dist/src/ui/hooks/useAgentsManagerDialog.js.map +1 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.d.ts +37 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.js +44 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.js.map +1 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.d.ts +6 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.js +74 -0
- package/dist/src/ui/hooks/useAnimatedScrollbar.test.js.map +1 -0
- package/dist/src/ui/hooks/useAnimationFrame.d.ts +25 -0
- package/dist/src/ui/hooks/useAnimationFrame.js +86 -0
- package/dist/src/ui/hooks/useAnimationFrame.js.map +1 -0
- package/dist/src/ui/hooks/useApprovalModeCommand.d.ts +14 -0
- package/dist/src/ui/hooks/useApprovalModeCommand.js +33 -0
- package/dist/src/ui/hooks/useApprovalModeCommand.js.map +1 -0
- package/dist/src/ui/hooks/useArenaCommand.d.ts +13 -0
- package/dist/src/ui/hooks/useArenaCommand.js +21 -0
- package/dist/src/ui/hooks/useArenaCommand.js.map +1 -0
- package/dist/src/ui/hooks/useArenaInProcess.d.ts +14 -0
- package/dist/src/ui/hooks/useArenaInProcess.js +136 -0
- package/dist/src/ui/hooks/useArenaInProcess.js.map +1 -0
- package/dist/src/ui/hooks/useAtCompletion.d.ts +23 -0
- package/dist/src/ui/hooks/useAtCompletion.js +184 -0
- package/dist/src/ui/hooks/useAtCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useAttentionNotifications.d.ts +22 -0
- package/dist/src/ui/hooks/useAttentionNotifications.js +89 -0
- package/dist/src/ui/hooks/useAttentionNotifications.js.map +1 -0
- package/dist/src/ui/hooks/useAttentionNotifications.test.d.ts +6 -0
- package/dist/src/ui/hooks/useAttentionNotifications.test.js +222 -0
- package/dist/src/ui/hooks/useAttentionNotifications.test.js.map +1 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.d.ts +32 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +124 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.d.ts +6 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +379 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -0
- package/dist/src/ui/hooks/useAwaySummary.d.ts +35 -0
- package/dist/src/ui/hooks/useAwaySummary.js +141 -0
- package/dist/src/ui/hooks/useAwaySummary.js.map +1 -0
- package/dist/src/ui/hooks/useAwaySummary.test.d.ts +6 -0
- package/dist/src/ui/hooks/useAwaySummary.test.js +103 -0
- package/dist/src/ui/hooks/useAwaySummary.test.js.map +1 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.d.ts +69 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.js +217 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.js.map +1 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.test.d.ts +6 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.test.js +455 -0
- package/dist/src/ui/hooks/useBackgroundTaskView.test.js.map +1 -0
- package/dist/src/ui/hooks/useBatchedScroll.d.ts +14 -0
- package/dist/src/ui/hooks/useBatchedScroll.js +25 -0
- package/dist/src/ui/hooks/useBatchedScroll.js.map +1 -0
- package/dist/src/ui/hooks/useBatchedScroll.test.d.ts +6 -0
- package/dist/src/ui/hooks/useBatchedScroll.test.js +42 -0
- package/dist/src/ui/hooks/useBatchedScroll.test.js.map +1 -0
- package/dist/src/ui/hooks/useBracketedPaste.d.ts +12 -0
- package/dist/src/ui/hooks/useBracketedPaste.js +32 -0
- package/dist/src/ui/hooks/useBracketedPaste.js.map +1 -0
- package/dist/src/ui/hooks/useBranchCommand.d.ts +33 -0
- package/dist/src/ui/hooks/useBranchCommand.js +230 -0
- package/dist/src/ui/hooks/useBranchCommand.js.map +1 -0
- package/dist/src/ui/hooks/useBranchCommand.test.d.ts +6 -0
- package/dist/src/ui/hooks/useBranchCommand.test.js +386 -0
- package/dist/src/ui/hooks/useBranchCommand.test.js.map +1 -0
- package/dist/src/ui/hooks/useCommandCompletion.d.ts +37 -0
- package/dist/src/ui/hooks/useCommandCompletion.js +227 -0
- package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useCommandMigration.d.ts +16 -0
- package/dist/src/ui/hooks/useCommandMigration.js +40 -0
- package/dist/src/ui/hooks/useCommandMigration.js.map +1 -0
- package/dist/src/ui/hooks/useCompletion.d.ts +24 -0
- package/dist/src/ui/hooks/useCompletion.js +88 -0
- package/dist/src/ui/hooks/useCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useConfigInitMessage.d.ts +6 -0
- package/dist/src/ui/hooks/useConfigInitMessage.js +45 -0
- package/dist/src/ui/hooks/useConfigInitMessage.js.map +1 -0
- package/dist/src/ui/hooks/useConfigInitMessage.test.d.ts +6 -0
- package/dist/src/ui/hooks/useConfigInitMessage.test.js +80 -0
- package/dist/src/ui/hooks/useConfigInitMessage.test.js.map +1 -0
- package/dist/src/ui/hooks/useContextualTips.d.ts +19 -0
- package/dist/src/ui/hooks/useContextualTips.js +65 -0
- package/dist/src/ui/hooks/useContextualTips.js.map +1 -0
- package/dist/src/ui/hooks/useDeleteCommand.d.ts +19 -0
- package/dist/src/ui/hooks/useDeleteCommand.js +167 -0
- package/dist/src/ui/hooks/useDeleteCommand.js.map +1 -0
- package/dist/src/ui/hooks/useDeleteCommand.test.d.ts +6 -0
- package/dist/src/ui/hooks/useDeleteCommand.test.js +391 -0
- package/dist/src/ui/hooks/useDeleteCommand.test.js.map +1 -0
- package/dist/src/ui/hooks/useDialogClose.d.ts +48 -0
- package/dist/src/ui/hooks/useDialogClose.js +102 -0
- package/dist/src/ui/hooks/useDialogClose.js.map +1 -0
- package/dist/src/ui/hooks/useDiffData.d.ts +32 -0
- package/dist/src/ui/hooks/useDiffData.js +72 -0
- package/dist/src/ui/hooks/useDiffData.js.map +1 -0
- package/dist/src/ui/hooks/useDoublePress.d.ts +18 -0
- package/dist/src/ui/hooks/useDoublePress.js +47 -0
- package/dist/src/ui/hooks/useDoublePress.js.map +1 -0
- package/dist/src/ui/hooks/useEditorSettings.d.ts +16 -0
- package/dist/src/ui/hooks/useEditorSettings.js +43 -0
- package/dist/src/ui/hooks/useEditorSettings.js.map +1 -0
- package/dist/src/ui/hooks/useEditorSettings.test.d.ts +6 -0
- package/dist/src/ui/hooks/useEditorSettings.test.js +164 -0
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -0
- package/dist/src/ui/hooks/useExportCompletion.d.ts +70 -0
- package/dist/src/ui/hooks/useExportCompletion.js +208 -0
- package/dist/src/ui/hooks/useExportCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useExportCompletion.test.d.ts +6 -0
- package/dist/src/ui/hooks/useExportCompletion.test.js +190 -0
- package/dist/src/ui/hooks/useExportCompletion.test.js.map +1 -0
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +71 -0
- package/dist/src/ui/hooks/useExtensionUpdates.js +229 -0
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -0
- package/dist/src/ui/hooks/useExtensionUpdates.test.d.ts +6 -0
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +455 -0
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -0
- package/dist/src/ui/hooks/useExtensionsManagerDialog.d.ts +12 -0
- package/dist/src/ui/hooks/useExtensionsManagerDialog.js +21 -0
- package/dist/src/ui/hooks/useExtensionsManagerDialog.js.map +1 -0
- package/dist/src/ui/hooks/useFeedbackDialog.d.ts +18 -0
- package/dist/src/ui/hooks/useFeedbackDialog.js +130 -0
- package/dist/src/ui/hooks/useFeedbackDialog.js.map +1 -0
- package/dist/src/ui/hooks/useFocus.d.ts +10 -0
- package/dist/src/ui/hooks/useFocus.js +51 -0
- package/dist/src/ui/hooks/useFocus.js.map +1 -0
- package/dist/src/ui/hooks/useFolderTrust.d.ts +13 -0
- package/dist/src/ui/hooks/useFolderTrust.js +60 -0
- package/dist/src/ui/hooks/useFolderTrust.js.map +1 -0
- package/dist/src/ui/hooks/useFollowupSuggestions.d.ts +53 -0
- package/dist/src/ui/hooks/useFollowupSuggestions.js +89 -0
- package/dist/src/ui/hooks/useFollowupSuggestions.js.map +1 -0
- package/dist/src/ui/hooks/useGeminiStream.d.ts +76 -0
- package/dist/src/ui/hooks/useGeminiStream.js +1899 -0
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -0
- package/dist/src/ui/hooks/useGitBranchName.d.ts +6 -0
- package/dist/src/ui/hooks/useGitBranchName.js +61 -0
- package/dist/src/ui/hooks/useGitBranchName.js.map +1 -0
- package/dist/src/ui/hooks/useGitBranchName.test.d.ts +6 -0
- package/dist/src/ui/hooks/useGitBranchName.test.js +192 -0
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -0
- package/dist/src/ui/hooks/useHistoryManager.d.ts +24 -0
- package/dist/src/ui/hooks/useHistoryManager.js +183 -0
- package/dist/src/ui/hooks/useHistoryManager.js.map +1 -0
- package/dist/src/ui/hooks/useHistoryManager.test.d.ts +6 -0
- package/dist/src/ui/hooks/useHistoryManager.test.js +495 -0
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -0
- package/dist/src/ui/hooks/useHooksDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useHooksDialog.js +21 -0
- package/dist/src/ui/hooks/useHooksDialog.js.map +1 -0
- package/dist/src/ui/hooks/useIdeTrustListener.d.ts +16 -0
- package/dist/src/ui/hooks/useIdeTrustListener.js +65 -0
- package/dist/src/ui/hooks/useIdeTrustListener.js.map +1 -0
- package/dist/src/ui/hooks/useIdeTrustListener.test.d.ts +6 -0
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +183 -0
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -0
- package/dist/src/ui/hooks/useInitializationAuthError.d.ts +22 -0
- package/dist/src/ui/hooks/useInitializationAuthError.js +40 -0
- package/dist/src/ui/hooks/useInitializationAuthError.js.map +1 -0
- package/dist/src/ui/hooks/useInputHistory.d.ts +20 -0
- package/dist/src/ui/hooks/useInputHistory.js +85 -0
- package/dist/src/ui/hooks/useInputHistory.js.map +1 -0
- package/dist/src/ui/hooks/useInputHistory.test.d.ts +6 -0
- package/dist/src/ui/hooks/useInputHistory.test.js +207 -0
- package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -0
- package/dist/src/ui/hooks/useInputHistoryStore.d.ts +19 -0
- package/dist/src/ui/hooks/useInputHistoryStore.js +83 -0
- package/dist/src/ui/hooks/useInputHistoryStore.js.map +1 -0
- package/dist/src/ui/hooks/useInputHistoryStore.test.d.ts +6 -0
- package/dist/src/ui/hooks/useInputHistoryStore.test.js +231 -0
- package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -0
- package/dist/src/ui/hooks/useKeypress.d.ts +17 -0
- package/dist/src/ui/hooks/useKeypress.js +27 -0
- package/dist/src/ui/hooks/useKeypress.js.map +1 -0
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +15 -0
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +20 -0
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +1 -0
- package/dist/src/ui/hooks/useLaunchEditor.d.ts +5 -0
- package/dist/src/ui/hooks/useLaunchEditor.js +75 -0
- package/dist/src/ui/hooks/useLaunchEditor.js.map +1 -0
- package/dist/src/ui/hooks/useLoadingIndicator.d.ts +11 -0
- package/dist/src/ui/hooks/useLoadingIndicator.js +50 -0
- package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -0
- package/dist/src/ui/hooks/useLoadingIndicator.test.d.ts +6 -0
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +172 -0
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -0
- package/dist/src/ui/hooks/useLogger.d.ts +11 -0
- package/dist/src/ui/hooks/useLogger.js +32 -0
- package/dist/src/ui/hooks/useLogger.js.map +1 -0
- package/dist/src/ui/hooks/useMCPHealth.d.ts +16 -0
- package/dist/src/ui/hooks/useMCPHealth.js +56 -0
- package/dist/src/ui/hooks/useMCPHealth.js.map +1 -0
- package/dist/src/ui/hooks/useMcpDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useMcpDialog.js +21 -0
- package/dist/src/ui/hooks/useMcpDialog.js.map +1 -0
- package/dist/src/ui/hooks/useMemoryDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useMemoryDialog.js +21 -0
- package/dist/src/ui/hooks/useMemoryDialog.js.map +1 -0
- package/dist/src/ui/hooks/useMemoryMonitor.d.ts +17 -0
- package/dist/src/ui/hooks/useMemoryMonitor.js +83 -0
- package/dist/src/ui/hooks/useMemoryMonitor.js.map +1 -0
- package/dist/src/ui/hooks/useMemoryMonitor.test.d.ts +6 -0
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +153 -0
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -0
- package/dist/src/ui/hooks/useMessageQueue.d.ts +18 -0
- package/dist/src/ui/hooks/useMessageQueue.js +67 -0
- package/dist/src/ui/hooks/useMessageQueue.js.map +1 -0
- package/dist/src/ui/hooks/useMessageQueue.test.d.ts +6 -0
- package/dist/src/ui/hooks/useMessageQueue.test.js +219 -0
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -0
- package/dist/src/ui/hooks/useModelCommand.d.ts +15 -0
- package/dist/src/ui/hooks/useModelCommand.js +25 -0
- package/dist/src/ui/hooks/useModelCommand.js.map +1 -0
- package/dist/src/ui/hooks/useModelCommand.test.d.ts +6 -0
- package/dist/src/ui/hooks/useModelCommand.test.js +35 -0
- package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -0
- package/dist/src/ui/hooks/useMouseEvents.d.ts +44 -0
- package/dist/src/ui/hooks/useMouseEvents.js +85 -0
- package/dist/src/ui/hooks/useMouseEvents.js.map +1 -0
- package/dist/src/ui/hooks/usePhraseCycler.d.ts +14 -0
- package/dist/src/ui/hooks/usePhraseCycler.js +70 -0
- package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -0
- package/dist/src/ui/hooks/usePreferredEditor.d.ts +7 -0
- package/dist/src/ui/hooks/usePreferredEditor.js +25 -0
- package/dist/src/ui/hooks/usePreferredEditor.js.map +1 -0
- package/dist/src/ui/hooks/useProviderUpdates.d.ts +33 -0
- package/dist/src/ui/hooks/useProviderUpdates.js +215 -0
- package/dist/src/ui/hooks/useProviderUpdates.js.map +1 -0
- package/dist/src/ui/hooks/useProviderUpdates.test.d.ts +6 -0
- package/dist/src/ui/hooks/useProviderUpdates.test.js +293 -0
- package/dist/src/ui/hooks/useProviderUpdates.test.js.map +1 -0
- package/dist/src/ui/hooks/useQwenAuth.d.ts +20 -0
- package/dist/src/ui/hooks/useQwenAuth.js +74 -0
- package/dist/src/ui/hooks/useQwenAuth.js.map +1 -0
- package/dist/src/ui/hooks/useQwenAuth.test.d.ts +6 -0
- package/dist/src/ui/hooks/useQwenAuth.test.js +266 -0
- package/dist/src/ui/hooks/useQwenAuth.test.js.map +1 -0
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +33 -0
- package/dist/src/ui/hooks/useReactToolScheduler.js +236 -0
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -0
- package/dist/src/ui/hooks/useRefreshMemoryCommand.d.ts +6 -0
- package/dist/src/ui/hooks/useRefreshMemoryCommand.js +7 -0
- package/dist/src/ui/hooks/useRefreshMemoryCommand.js.map +1 -0
- package/dist/src/ui/hooks/useResumeCommand.d.ts +31 -0
- package/dist/src/ui/hooks/useResumeCommand.js +114 -0
- package/dist/src/ui/hooks/useResumeCommand.js.map +1 -0
- package/dist/src/ui/hooks/useResumeCommand.test.d.ts +6 -0
- package/dist/src/ui/hooks/useResumeCommand.test.js +349 -0
- package/dist/src/ui/hooks/useResumeCommand.test.js.map +1 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.d.ts +19 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.js +103 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.d.ts +6 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +163 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -0
- package/dist/src/ui/hooks/useSelectionList.d.ts +41 -0
- package/dist/src/ui/hooks/useSelectionList.js +276 -0
- package/dist/src/ui/hooks/useSelectionList.js.map +1 -0
- package/dist/src/ui/hooks/useSelectionList.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSelectionList.test.js +782 -0
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -0
- package/dist/src/ui/hooks/useSessionPicker.d.ts +95 -0
- package/dist/src/ui/hooks/useSessionPicker.js +383 -0
- package/dist/src/ui/hooks/useSessionPicker.js.map +1 -0
- package/dist/src/ui/hooks/useSessionPicker.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSessionPicker.test.js +94 -0
- package/dist/src/ui/hooks/useSessionPicker.test.js.map +1 -0
- package/dist/src/ui/hooks/useSessionSearchInput.d.ts +69 -0
- package/dist/src/ui/hooks/useSessionSearchInput.js +124 -0
- package/dist/src/ui/hooks/useSessionSearchInput.js.map +1 -0
- package/dist/src/ui/hooks/useSessionSearchInput.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSessionSearchInput.test.js +342 -0
- package/dist/src/ui/hooks/useSessionSearchInput.test.js.map +1 -0
- package/dist/src/ui/hooks/useSettingsCommand.d.ts +10 -0
- package/dist/src/ui/hooks/useSettingsCommand.js +21 -0
- package/dist/src/ui/hooks/useSettingsCommand.js.map +1 -0
- package/dist/src/ui/hooks/useShellHistory.d.ts +14 -0
- package/dist/src/ui/hooks/useShellHistory.js +112 -0
- package/dist/src/ui/hooks/useShellHistory.js.map +1 -0
- package/dist/src/ui/hooks/useShellHistory.test.d.ts +6 -0
- package/dist/src/ui/hooks/useShellHistory.test.js +193 -0
- package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -0
- package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +9 -0
- package/dist/src/ui/hooks/useShowMemoryCommand.js +55 -0
- package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -0
- package/dist/src/ui/hooks/useSkillsManagerDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useSkillsManagerDialog.js +21 -0
- package/dist/src/ui/hooks/useSkillsManagerDialog.js.map +1 -0
- package/dist/src/ui/hooks/useSlashCompletion.d.ts +27 -0
- package/dist/src/ui/hooks/useSlashCompletion.integration.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSlashCompletion.integration.test.js +84 -0
- package/dist/src/ui/hooks/useSlashCompletion.integration.test.js.map +1 -0
- package/dist/src/ui/hooks/useSlashCompletion.js +490 -0
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -0
- package/dist/src/ui/hooks/useSlashCompletion.test.d.ts +9 -0
- package/dist/src/ui/hooks/useSlashCompletion.test.js +805 -0
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -0
- package/dist/src/ui/hooks/useStateAndRef.d.ts +7 -0
- package/dist/src/ui/hooks/useStateAndRef.js +26 -0
- package/dist/src/ui/hooks/useStateAndRef.js.map +1 -0
- package/dist/src/ui/hooks/useStatsDialog.d.ts +11 -0
- package/dist/src/ui/hooks/useStatsDialog.js +13 -0
- package/dist/src/ui/hooks/useStatsDialog.js.map +1 -0
- package/dist/src/ui/hooks/useStatusLine.d.ts +84 -0
- package/dist/src/ui/hooks/useStatusLine.js +528 -0
- package/dist/src/ui/hooks/useStatusLine.js.map +1 -0
- package/dist/src/ui/hooks/useStatusLine.test.d.ts +6 -0
- package/dist/src/ui/hooks/useStatusLine.test.js +1039 -0
- package/dist/src/ui/hooks/useStatusLine.test.js.map +1 -0
- package/dist/src/ui/hooks/useSubagentCreateDialog.d.ts +10 -0
- package/dist/src/ui/hooks/useSubagentCreateDialog.js +21 -0
- package/dist/src/ui/hooks/useSubagentCreateDialog.js.map +1 -0
- package/dist/src/ui/hooks/useTerminalNotification.d.ts +32 -0
- package/dist/src/ui/hooks/useTerminalNotification.js +45 -0
- package/dist/src/ui/hooks/useTerminalNotification.js.map +1 -0
- package/dist/src/ui/hooks/useTerminalNotification.test.d.ts +6 -0
- package/dist/src/ui/hooks/useTerminalNotification.test.js +69 -0
- package/dist/src/ui/hooks/useTerminalNotification.test.js.map +1 -0
- package/dist/src/ui/hooks/useTerminalProgress.d.ts +12 -0
- package/dist/src/ui/hooks/useTerminalProgress.js +76 -0
- package/dist/src/ui/hooks/useTerminalProgress.js.map +1 -0
- package/dist/src/ui/hooks/useTerminalSize.d.ts +13 -0
- package/dist/src/ui/hooks/useTerminalSize.js +30 -0
- package/dist/src/ui/hooks/useTerminalSize.js.map +1 -0
- package/dist/src/ui/hooks/useThemeCommand.d.ts +15 -0
- package/dist/src/ui/hooks/useThemeCommand.js +85 -0
- package/dist/src/ui/hooks/useThemeCommand.js.map +1 -0
- package/dist/src/ui/hooks/useThemeCommand.test.d.ts +6 -0
- package/dist/src/ui/hooks/useThemeCommand.test.js +42 -0
- package/dist/src/ui/hooks/useThemeCommand.test.js.map +1 -0
- package/dist/src/ui/hooks/useTimer.d.ts +12 -0
- package/dist/src/ui/hooks/useTimer.js +58 -0
- package/dist/src/ui/hooks/useTimer.js.map +1 -0
- package/dist/src/ui/hooks/useTimer.test.d.ts +6 -0
- package/dist/src/ui/hooks/useTimer.test.js +90 -0
- package/dist/src/ui/hooks/useTimer.test.js.map +1 -0
- package/dist/src/ui/hooks/useTomlMigration.d.ts +1 -0
- package/dist/src/ui/hooks/useTomlMigration.js +2 -0
- package/dist/src/ui/hooks/useTomlMigration.js.map +1 -0
- package/dist/src/ui/hooks/useToolScheduler.test.d.ts +6 -0
- package/dist/src/ui/hooks/useToolScheduler.test.js +624 -0
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -0
- package/dist/src/ui/hooks/useTrustModify.d.ts +17 -0
- package/dist/src/ui/hooks/useTrustModify.js +78 -0
- package/dist/src/ui/hooks/useTrustModify.js.map +1 -0
- package/dist/src/ui/hooks/useTrustModify.test.d.ts +6 -0
- package/dist/src/ui/hooks/useTrustModify.test.js +182 -0
- package/dist/src/ui/hooks/useTrustModify.test.js.map +1 -0
- package/dist/src/ui/hooks/useTurnDiffs.d.ts +34 -0
- package/dist/src/ui/hooks/useTurnDiffs.js +130 -0
- package/dist/src/ui/hooks/useTurnDiffs.js.map +1 -0
- package/dist/src/ui/hooks/useTurnDiffs.test.d.ts +6 -0
- package/dist/src/ui/hooks/useTurnDiffs.test.js +164 -0
- package/dist/src/ui/hooks/useTurnDiffs.test.js.map +1 -0
- package/dist/src/ui/hooks/useWelcomeBack.d.ts +23 -0
- package/dist/src/ui/hooks/useWelcomeBack.js +99 -0
- package/dist/src/ui/hooks/useWelcomeBack.js.map +1 -0
- package/dist/src/ui/hooks/useWelcomeBack.test.d.ts +6 -0
- package/dist/src/ui/hooks/useWelcomeBack.test.js +94 -0
- package/dist/src/ui/hooks/useWelcomeBack.test.js.map +1 -0
- package/dist/src/ui/hooks/useWorktreeSession.d.ts +26 -0
- package/dist/src/ui/hooks/useWorktreeSession.js +92 -0
- package/dist/src/ui/hooks/useWorktreeSession.js.map +1 -0
- package/dist/src/ui/hooks/useWorktreeSession.test.d.ts +6 -0
- package/dist/src/ui/hooks/useWorktreeSession.test.js +84 -0
- package/dist/src/ui/hooks/useWorktreeSession.test.js.map +1 -0
- package/dist/src/ui/hooks/vim.d.ts +13 -0
- package/dist/src/ui/hooks/vim.js +1637 -0
- package/dist/src/ui/hooks/vim.js.map +1 -0
- package/dist/src/ui/hooks/vim.test.d.ts +6 -0
- package/dist/src/ui/hooks/vim.test.js +1975 -0
- package/dist/src/ui/hooks/vim.test.js.map +1 -0
- package/dist/src/ui/keyMatchers.d.ts +27 -0
- package/dist/src/ui/keyMatchers.js +71 -0
- package/dist/src/ui/keyMatchers.js.map +1 -0
- package/dist/src/ui/keyMatchers.test.d.ts +6 -0
- package/dist/src/ui/keyMatchers.test.js +421 -0
- package/dist/src/ui/keyMatchers.test.js.map +1 -0
- package/dist/src/ui/layouts/DefaultAppLayout.d.ts +7 -0
- package/dist/src/ui/layouts/DefaultAppLayout.js +49 -0
- package/dist/src/ui/layouts/DefaultAppLayout.js.map +1 -0
- package/dist/src/ui/layouts/DefaultAppLayout.test.d.ts +6 -0
- package/dist/src/ui/layouts/DefaultAppLayout.test.js +185 -0
- package/dist/src/ui/layouts/DefaultAppLayout.test.js.map +1 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.d.ts +7 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.js +27 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.js.map +1 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.test.d.ts +6 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.test.js +135 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.test.js.map +1 -0
- package/dist/src/ui/models/availableModels.d.ts +30 -0
- package/dist/src/ui/models/availableModels.js +103 -0
- package/dist/src/ui/models/availableModels.js.map +1 -0
- package/dist/src/ui/models/availableModels.test.d.ts +6 -0
- package/dist/src/ui/models/availableModels.test.js +142 -0
- package/dist/src/ui/models/availableModels.test.js.map +1 -0
- package/dist/src/ui/noninteractive/nonInteractiveUi.d.ts +12 -0
- package/dist/src/ui/noninteractive/nonInteractiveUi.js +33 -0
- package/dist/src/ui/noninteractive/nonInteractiveUi.js.map +1 -0
- package/dist/src/ui/semantic-colors.d.ts +7 -0
- package/dist/src/ui/semantic-colors.js +24 -0
- package/dist/src/ui/semantic-colors.js.map +1 -0
- package/dist/src/ui/state/extensions.d.ts +43 -0
- package/dist/src/ui/state/extensions.js +63 -0
- package/dist/src/ui/state/extensions.js.map +1 -0
- package/dist/src/ui/statusLinePresets.d.ts +79 -0
- package/dist/src/ui/statusLinePresets.js +310 -0
- package/dist/src/ui/statusLinePresets.js.map +1 -0
- package/dist/src/ui/statusLinePresets.test.d.ts +6 -0
- package/dist/src/ui/statusLinePresets.test.js +221 -0
- package/dist/src/ui/statusLinePresets.test.js.map +1 -0
- package/dist/src/ui/textConstants.d.ts +9 -0
- package/dist/src/ui/textConstants.js +10 -0
- package/dist/src/ui/textConstants.js.map +1 -0
- package/dist/src/ui/themes/ansi-light.d.ts +7 -0
- package/dist/src/ui/themes/ansi-light.js +144 -0
- package/dist/src/ui/themes/ansi-light.js.map +1 -0
- package/dist/src/ui/themes/ansi.d.ts +7 -0
- package/dist/src/ui/themes/ansi.js +154 -0
- package/dist/src/ui/themes/ansi.js.map +1 -0
- package/dist/src/ui/themes/atom-one-dark.d.ts +7 -0
- package/dist/src/ui/themes/atom-one-dark.js +140 -0
- package/dist/src/ui/themes/atom-one-dark.js.map +1 -0
- package/dist/src/ui/themes/ayu-light.d.ts +7 -0
- package/dist/src/ui/themes/ayu-light.js +132 -0
- package/dist/src/ui/themes/ayu-light.js.map +1 -0
- package/dist/src/ui/themes/ayu.d.ts +7 -0
- package/dist/src/ui/themes/ayu.js +106 -0
- package/dist/src/ui/themes/ayu.js.map +1 -0
- package/dist/src/ui/themes/color-utils.d.ts +21 -0
- package/dist/src/ui/themes/color-utils.js +223 -0
- package/dist/src/ui/themes/color-utils.js.map +1 -0
- package/dist/src/ui/themes/color-utils.test.d.ts +6 -0
- package/dist/src/ui/themes/color-utils.test.js +197 -0
- package/dist/src/ui/themes/color-utils.test.js.map +1 -0
- package/dist/src/ui/themes/default-light.d.ts +7 -0
- package/dist/src/ui/themes/default-light.js +100 -0
- package/dist/src/ui/themes/default-light.js.map +1 -0
- package/dist/src/ui/themes/default.d.ts +7 -0
- package/dist/src/ui/themes/default.js +143 -0
- package/dist/src/ui/themes/default.js.map +1 -0
- package/dist/src/ui/themes/detect-terminal-theme.d.ts +75 -0
- package/dist/src/ui/themes/detect-terminal-theme.js +228 -0
- package/dist/src/ui/themes/detect-terminal-theme.js.map +1 -0
- package/dist/src/ui/themes/detect-terminal-theme.test.d.ts +6 -0
- package/dist/src/ui/themes/detect-terminal-theme.test.js +269 -0
- package/dist/src/ui/themes/detect-terminal-theme.test.js.map +1 -0
- package/dist/src/ui/themes/dracula.d.ts +7 -0
- package/dist/src/ui/themes/dracula.js +117 -0
- package/dist/src/ui/themes/dracula.js.map +1 -0
- package/dist/src/ui/themes/github-dark.d.ts +7 -0
- package/dist/src/ui/themes/github-dark.js +140 -0
- package/dist/src/ui/themes/github-dark.js.map +1 -0
- package/dist/src/ui/themes/github-light.d.ts +7 -0
- package/dist/src/ui/themes/github-light.js +142 -0
- package/dist/src/ui/themes/github-light.js.map +1 -0
- package/dist/src/ui/themes/googlecode.d.ts +7 -0
- package/dist/src/ui/themes/googlecode.js +139 -0
- package/dist/src/ui/themes/googlecode.js.map +1 -0
- package/dist/src/ui/themes/no-color.d.ts +7 -0
- package/dist/src/ui/themes/no-color.js +120 -0
- package/dist/src/ui/themes/no-color.js.map +1 -0
- package/dist/src/ui/themes/qwen-dark.d.ts +7 -0
- package/dist/src/ui/themes/qwen-dark.js +107 -0
- package/dist/src/ui/themes/qwen-dark.js.map +1 -0
- package/dist/src/ui/themes/qwen-light.d.ts +7 -0
- package/dist/src/ui/themes/qwen-light.js +133 -0
- package/dist/src/ui/themes/qwen-light.js.map +1 -0
- package/dist/src/ui/themes/semantic-tokens.d.ts +40 -0
- package/dist/src/ui/themes/semantic-tokens.js +103 -0
- package/dist/src/ui/themes/semantic-tokens.js.map +1 -0
- package/dist/src/ui/themes/shades-of-purple.d.ts +11 -0
- package/dist/src/ui/themes/shades-of-purple.js +306 -0
- package/dist/src/ui/themes/shades-of-purple.js.map +1 -0
- package/dist/src/ui/themes/theme-manager.d.ts +91 -0
- package/dist/src/ui/themes/theme-manager.js +311 -0
- package/dist/src/ui/themes/theme-manager.js.map +1 -0
- package/dist/src/ui/themes/theme-manager.test.d.ts +6 -0
- package/dist/src/ui/themes/theme-manager.test.js +188 -0
- package/dist/src/ui/themes/theme-manager.test.js.map +1 -0
- package/dist/src/ui/themes/theme.d.ts +137 -0
- package/dist/src/ui/themes/theme.js +393 -0
- package/dist/src/ui/themes/theme.js.map +1 -0
- package/dist/src/ui/themes/xcode.d.ts +7 -0
- package/dist/src/ui/themes/xcode.js +147 -0
- package/dist/src/ui/themes/xcode.js.map +1 -0
- package/dist/src/ui/types.d.ts +620 -0
- package/dist/src/ui/types.js +77 -0
- package/dist/src/ui/types.js.map +1 -0
- package/dist/src/ui/utils/CodeColorizer.d.ts +18 -0
- package/dist/src/ui/utils/CodeColorizer.js +155 -0
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +18 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.js +173 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.test.d.ts +6 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.test.js +303 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.test.js.map +1 -0
- package/dist/src/ui/utils/MarkdownDisplay.d.ts +25 -0
- package/dist/src/ui/utils/MarkdownDisplay.js +420 -0
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -0
- package/dist/src/ui/utils/MarkdownDisplay.test.d.ts +6 -0
- package/dist/src/ui/utils/MarkdownDisplay.test.js +702 -0
- package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -0
- package/dist/src/ui/utils/MermaidDiagram.d.ts +15 -0
- package/dist/src/ui/utils/MermaidDiagram.js +88 -0
- package/dist/src/ui/utils/MermaidDiagram.js.map +1 -0
- package/dist/src/ui/utils/MermaidDiagram.test.d.ts +6 -0
- package/dist/src/ui/utils/MermaidDiagram.test.js +90 -0
- package/dist/src/ui/utils/MermaidDiagram.test.js.map +1 -0
- package/dist/src/ui/utils/TableRenderer.d.ts +30 -0
- package/dist/src/ui/utils/TableRenderer.js +563 -0
- package/dist/src/ui/utils/TableRenderer.js.map +1 -0
- package/dist/src/ui/utils/TableRenderer.test.d.ts +6 -0
- package/dist/src/ui/utils/TableRenderer.test.js +568 -0
- package/dist/src/ui/utils/TableRenderer.test.js.map +1 -0
- package/dist/src/ui/utils/approvalModeDisplay.d.ts +8 -0
- package/dist/src/ui/utils/approvalModeDisplay.js +34 -0
- package/dist/src/ui/utils/approvalModeDisplay.js.map +1 -0
- package/dist/src/ui/utils/approvalModeDisplay.test.d.ts +6 -0
- package/dist/src/ui/utils/approvalModeDisplay.test.js +35 -0
- package/dist/src/ui/utils/approvalModeDisplay.test.js.map +1 -0
- package/dist/src/ui/utils/asciiCharts.d.ts +44 -0
- package/dist/src/ui/utils/asciiCharts.js +307 -0
- package/dist/src/ui/utils/asciiCharts.js.map +1 -0
- package/dist/src/ui/utils/asciiCharts.test.d.ts +6 -0
- package/dist/src/ui/utils/asciiCharts.test.js +208 -0
- package/dist/src/ui/utils/asciiCharts.test.js.map +1 -0
- package/dist/src/ui/utils/backgroundWorkUtils.d.ts +8 -0
- package/dist/src/ui/utils/backgroundWorkUtils.js +16 -0
- package/dist/src/ui/utils/backgroundWorkUtils.js.map +1 -0
- package/dist/src/ui/utils/backgroundWorkUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/backgroundWorkUtils.test.js +85 -0
- package/dist/src/ui/utils/backgroundWorkUtils.test.js.map +1 -0
- package/dist/src/ui/utils/clipboardUtils.d.ts +28 -0
- package/dist/src/ui/utils/clipboardUtils.js +522 -0
- package/dist/src/ui/utils/clipboardUtils.js.map +1 -0
- package/dist/src/ui/utils/clipboardUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/clipboardUtils.test.js +465 -0
- package/dist/src/ui/utils/clipboardUtils.test.js.map +1 -0
- package/dist/src/ui/utils/commandUtils.d.ts +112 -0
- package/dist/src/ui/utils/commandUtils.js +285 -0
- package/dist/src/ui/utils/commandUtils.js.map +1 -0
- package/dist/src/ui/utils/commandUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/commandUtils.test.js +560 -0
- package/dist/src/ui/utils/commandUtils.test.js.map +1 -0
- package/dist/src/ui/utils/computeStats.d.ts +10 -0
- package/dist/src/ui/utils/computeStats.js +57 -0
- package/dist/src/ui/utils/computeStats.js.map +1 -0
- package/dist/src/ui/utils/customBanner.d.ts +35 -0
- package/dist/src/ui/utils/customBanner.js +361 -0
- package/dist/src/ui/utils/customBanner.js.map +1 -0
- package/dist/src/ui/utils/customBanner.test.d.ts +6 -0
- package/dist/src/ui/utils/customBanner.test.js +439 -0
- package/dist/src/ui/utils/customBanner.test.js.map +1 -0
- package/dist/src/ui/utils/displayUtils.d.ts +25 -0
- package/dist/src/ui/utils/displayUtils.js +46 -0
- package/dist/src/ui/utils/displayUtils.js.map +1 -0
- package/dist/src/ui/utils/displayUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/displayUtils.test.js +61 -0
- package/dist/src/ui/utils/displayUtils.test.js.map +1 -0
- package/dist/src/ui/utils/export/collect.d.ts +16 -0
- package/dist/src/ui/utils/export/collect.js +509 -0
- package/dist/src/ui/utils/export/collect.js.map +1 -0
- package/dist/src/ui/utils/export/collect.test.d.ts +6 -0
- package/dist/src/ui/utils/export/collect.test.js +80 -0
- package/dist/src/ui/utils/export/collect.test.js.map +1 -0
- package/dist/src/ui/utils/export/formatters/html.d.ts +23 -0
- package/dist/src/ui/utils/export/formatters/html.js +65 -0
- package/dist/src/ui/utils/export/formatters/html.js.map +1 -0
- package/dist/src/ui/utils/export/formatters/json.d.ts +11 -0
- package/dist/src/ui/utils/export/formatters/json.js +13 -0
- package/dist/src/ui/utils/export/formatters/json.js.map +1 -0
- package/dist/src/ui/utils/export/formatters/jsonl.d.ts +11 -0
- package/dist/src/ui/utils/export/formatters/jsonl.js +69 -0
- package/dist/src/ui/utils/export/formatters/jsonl.js.map +1 -0
- package/dist/src/ui/utils/export/formatters/markdown.d.ts +10 -0
- package/dist/src/ui/utils/export/formatters/markdown.js +254 -0
- package/dist/src/ui/utils/export/formatters/markdown.js.map +1 -0
- package/dist/src/ui/utils/export/index.d.ts +13 -0
- package/dist/src/ui/utils/export/index.js +13 -0
- package/dist/src/ui/utils/export/index.js.map +1 -0
- package/dist/src/ui/utils/export/normalize.d.ts +12 -0
- package/dist/src/ui/utils/export/normalize.js +279 -0
- package/dist/src/ui/utils/export/normalize.js.map +1 -0
- package/dist/src/ui/utils/export/normalize.test.d.ts +6 -0
- package/dist/src/ui/utils/export/normalize.test.js +62 -0
- package/dist/src/ui/utils/export/normalize.test.js.map +1 -0
- package/dist/src/ui/utils/export/types.d.ts +93 -0
- package/dist/src/ui/utils/export/types.js +7 -0
- package/dist/src/ui/utils/export/types.js.map +1 -0
- package/dist/src/ui/utils/export/utils.d.ts +9 -0
- package/dist/src/ui/utils/export/utils.js +13 -0
- package/dist/src/ui/utils/export/utils.js.map +1 -0
- package/dist/src/ui/utils/formatters.d.ts +28 -0
- package/dist/src/ui/utils/formatters.js +100 -0
- package/dist/src/ui/utils/formatters.js.map +1 -0
- package/dist/src/ui/utils/formatters.test.d.ts +6 -0
- package/dist/src/ui/utils/formatters.test.js +141 -0
- package/dist/src/ui/utils/formatters.test.js.map +1 -0
- package/dist/src/ui/utils/gradientUtils.d.ts +6 -0
- package/dist/src/ui/utils/gradientUtils.js +11 -0
- package/dist/src/ui/utils/gradientUtils.js.map +1 -0
- package/dist/src/ui/utils/highlight.d.ts +12 -0
- package/dist/src/ui/utils/highlight.js +90 -0
- package/dist/src/ui/utils/highlight.js.map +1 -0
- package/dist/src/ui/utils/highlight.test.d.ts +6 -0
- package/dist/src/ui/utils/highlight.test.js +173 -0
- package/dist/src/ui/utils/highlight.test.js.map +1 -0
- package/dist/src/ui/utils/historyMapping.d.ts +44 -0
- package/dist/src/ui/utils/historyMapping.js +110 -0
- package/dist/src/ui/utils/historyMapping.js.map +1 -0
- package/dist/src/ui/utils/historyMapping.test.d.ts +6 -0
- package/dist/src/ui/utils/historyMapping.test.js +376 -0
- package/dist/src/ui/utils/historyMapping.test.js.map +1 -0
- package/dist/src/ui/utils/historyUtils.d.ts +34 -0
- package/dist/src/ui/utils/historyUtils.js +117 -0
- package/dist/src/ui/utils/historyUtils.js.map +1 -0
- package/dist/src/ui/utils/historyUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/historyUtils.test.js +107 -0
- package/dist/src/ui/utils/historyUtils.test.js.map +1 -0
- package/dist/src/ui/utils/isNarrowWidth.d.ts +6 -0
- package/dist/src/ui/utils/isNarrowWidth.js +9 -0
- package/dist/src/ui/utils/isNarrowWidth.js.map +1 -0
- package/dist/src/ui/utils/kittyProtocolDetector.d.ts +19 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js +115 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -0
- package/dist/src/ui/utils/latexRenderer.d.ts +6 -0
- package/dist/src/ui/utils/latexRenderer.js +187 -0
- package/dist/src/ui/utils/latexRenderer.js.map +1 -0
- package/dist/src/ui/utils/latexRenderer.test.d.ts +6 -0
- package/dist/src/ui/utils/latexRenderer.test.js +27 -0
- package/dist/src/ui/utils/latexRenderer.test.js.map +1 -0
- package/dist/src/ui/utils/layoutUtils.d.ts +32 -0
- package/dist/src/ui/utils/layoutUtils.js +46 -0
- package/dist/src/ui/utils/layoutUtils.js.map +1 -0
- package/dist/src/ui/utils/layoutUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/layoutUtils.test.js +30 -0
- package/dist/src/ui/utils/layoutUtils.test.js.map +1 -0
- package/dist/src/ui/utils/lowlightLoader.d.ts +43 -0
- package/dist/src/ui/utils/lowlightLoader.js +88 -0
- package/dist/src/ui/utils/lowlightLoader.js.map +1 -0
- package/dist/src/ui/utils/lowlightLoader.test.d.ts +6 -0
- package/dist/src/ui/utils/lowlightLoader.test.js +120 -0
- package/dist/src/ui/utils/lowlightLoader.test.js.map +1 -0
- package/dist/src/ui/utils/markdownUtilities.d.ts +6 -0
- package/dist/src/ui/utils/markdownUtilities.js +110 -0
- package/dist/src/ui/utils/markdownUtilities.js.map +1 -0
- package/dist/src/ui/utils/markdownUtilities.test.d.ts +6 -0
- package/dist/src/ui/utils/markdownUtilities.test.js +42 -0
- package/dist/src/ui/utils/markdownUtilities.test.js.map +1 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.d.ts +62 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.js +212 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.js.map +1 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.test.d.ts +6 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.test.js +473 -0
- package/dist/src/ui/utils/mergeCompactToolGroups.test.js.map +1 -0
- package/dist/src/ui/utils/mermaidImageRenderer.d.ts +54 -0
- package/dist/src/ui/utils/mermaidImageRenderer.js +955 -0
- package/dist/src/ui/utils/mermaidImageRenderer.js.map +1 -0
- package/dist/src/ui/utils/mermaidImageRenderer.test.d.ts +6 -0
- package/dist/src/ui/utils/mermaidImageRenderer.test.js +528 -0
- package/dist/src/ui/utils/mermaidImageRenderer.test.js.map +1 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.d.ts +12 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.js +1097 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.js.map +1 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.test.d.ts +6 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.test.js +69 -0
- package/dist/src/ui/utils/mermaidVisualRenderer.test.js.map +1 -0
- package/dist/src/ui/utils/modelsBySource.d.ts +47 -0
- package/dist/src/ui/utils/modelsBySource.js +89 -0
- package/dist/src/ui/utils/modelsBySource.js.map +1 -0
- package/dist/src/ui/utils/modelsBySource.test.d.ts +6 -0
- package/dist/src/ui/utils/modelsBySource.test.js +111 -0
- package/dist/src/ui/utils/modelsBySource.test.js.map +1 -0
- package/dist/src/ui/utils/mouse.d.ts +39 -0
- package/dist/src/ui/utils/mouse.js +169 -0
- package/dist/src/ui/utils/mouse.js.map +1 -0
- package/dist/src/ui/utils/mouse.test.d.ts +6 -0
- package/dist/src/ui/utils/mouse.test.js +117 -0
- package/dist/src/ui/utils/mouse.test.js.map +1 -0
- package/dist/src/ui/utils/osc8.d.ts +124 -0
- package/dist/src/ui/utils/osc8.js +463 -0
- package/dist/src/ui/utils/osc8.js.map +1 -0
- package/dist/src/ui/utils/osc8.test.d.ts +6 -0
- package/dist/src/ui/utils/osc8.test.js +494 -0
- package/dist/src/ui/utils/osc8.test.js.map +1 -0
- package/dist/src/ui/utils/platformConstants.d.ts +75 -0
- package/dist/src/ui/utils/platformConstants.js +78 -0
- package/dist/src/ui/utils/platformConstants.js.map +1 -0
- package/dist/src/ui/utils/restoreGoal.d.ts +47 -0
- package/dist/src/ui/utils/restoreGoal.js +124 -0
- package/dist/src/ui/utils/restoreGoal.js.map +1 -0
- package/dist/src/ui/utils/restoreGoal.test.d.ts +6 -0
- package/dist/src/ui/utils/restoreGoal.test.js +220 -0
- package/dist/src/ui/utils/restoreGoal.test.js.map +1 -0
- package/dist/src/ui/utils/resumeHistoryUtils.d.ts +22 -0
- package/dist/src/ui/utils/resumeHistoryUtils.js +410 -0
- package/dist/src/ui/utils/resumeHistoryUtils.js.map +1 -0
- package/dist/src/ui/utils/resumeHistoryUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/resumeHistoryUtils.test.js +378 -0
- package/dist/src/ui/utils/resumeHistoryUtils.test.js.map +1 -0
- package/dist/src/ui/utils/sessionPickerUtils.d.ts +35 -0
- package/dist/src/ui/utils/sessionPickerUtils.js +69 -0
- package/dist/src/ui/utils/sessionPickerUtils.js.map +1 -0
- package/dist/src/ui/utils/sessionPickerUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/sessionPickerUtils.test.js +79 -0
- package/dist/src/ui/utils/sessionPickerUtils.test.js.map +1 -0
- package/dist/src/ui/utils/statsDataService.d.ts +49 -0
- package/dist/src/ui/utils/statsDataService.js +221 -0
- package/dist/src/ui/utils/statsDataService.js.map +1 -0
- package/dist/src/ui/utils/statsDataService.test.d.ts +6 -0
- package/dist/src/ui/utils/statsDataService.test.js +406 -0
- package/dist/src/ui/utils/statsDataService.test.js.map +1 -0
- package/dist/src/ui/utils/synchronizedOutput.d.ts +16 -0
- package/dist/src/ui/utils/synchronizedOutput.js +88 -0
- package/dist/src/ui/utils/synchronizedOutput.js.map +1 -0
- package/dist/src/ui/utils/synchronizedOutput.test.d.ts +6 -0
- package/dist/src/ui/utils/synchronizedOutput.test.js +154 -0
- package/dist/src/ui/utils/synchronizedOutput.test.js.map +1 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.d.ts +21 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.js +108 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.js.map +1 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.test.d.ts +6 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.test.js +85 -0
- package/dist/src/ui/utils/terminalRedrawOptimizer.test.js.map +1 -0
- package/dist/src/ui/utils/terminalSetup.d.ts +30 -0
- package/dist/src/ui/utils/terminalSetup.js +310 -0
- package/dist/src/ui/utils/terminalSetup.js.map +1 -0
- package/dist/src/ui/utils/textUtils.d.ts +86 -0
- package/dist/src/ui/utils/textUtils.js +360 -0
- package/dist/src/ui/utils/textUtils.js.map +1 -0
- package/dist/src/ui/utils/textUtils.test.d.ts +6 -0
- package/dist/src/ui/utils/textUtils.test.js +269 -0
- package/dist/src/ui/utils/textUtils.test.js.map +1 -0
- package/dist/src/ui/utils/todoSnapshot.d.ts +13 -0
- package/dist/src/ui/utils/todoSnapshot.js +133 -0
- package/dist/src/ui/utils/todoSnapshot.js.map +1 -0
- package/dist/src/ui/utils/todoSnapshot.test.d.ts +6 -0
- package/dist/src/ui/utils/todoSnapshot.test.js +281 -0
- package/dist/src/ui/utils/todoSnapshot.test.js.map +1 -0
- package/dist/src/ui/utils/updateCheck.d.ts +12 -0
- package/dist/src/ui/utils/updateCheck.js +80 -0
- package/dist/src/ui/utils/updateCheck.js.map +1 -0
- package/dist/src/ui/utils/updateCheck.test.d.ts +6 -0
- package/dist/src/ui/utils/updateCheck.test.js +145 -0
- package/dist/src/ui/utils/updateCheck.test.js.map +1 -0
- package/dist/src/utils/acpModelUtils.d.ts +39 -0
- package/dist/src/utils/acpModelUtils.js +61 -0
- package/dist/src/utils/acpModelUtils.js.map +1 -0
- package/dist/src/utils/acpModelUtils.test.d.ts +6 -0
- package/dist/src/utils/acpModelUtils.test.js +31 -0
- package/dist/src/utils/acpModelUtils.test.js.map +1 -0
- package/dist/src/utils/apiPreconnect.d.ts +22 -0
- package/dist/src/utils/apiPreconnect.js +188 -0
- package/dist/src/utils/apiPreconnect.js.map +1 -0
- package/dist/src/utils/apiPreconnect.test.d.ts +6 -0
- package/dist/src/utils/apiPreconnect.test.js +252 -0
- package/dist/src/utils/apiPreconnect.test.js.map +1 -0
- package/dist/src/utils/checks.d.ts +19 -0
- package/dist/src/utils/checks.js +24 -0
- package/dist/src/utils/checks.js.map +1 -0
- package/dist/src/utils/cleanup.d.ts +23 -0
- package/dist/src/utils/cleanup.js +96 -0
- package/dist/src/utils/cleanup.js.map +1 -0
- package/dist/src/utils/commands.d.ts +20 -0
- package/dist/src/utils/commands.js +53 -0
- package/dist/src/utils/commands.js.map +1 -0
- package/dist/src/utils/commands.test.d.ts +6 -0
- package/dist/src/utils/commands.test.js +115 -0
- package/dist/src/utils/commands.test.js.map +1 -0
- package/dist/src/utils/commentJson.d.ts +25 -0
- package/dist/src/utils/commentJson.js +113 -0
- package/dist/src/utils/commentJson.js.map +1 -0
- package/dist/src/utils/commentJson.test.d.ts +6 -0
- package/dist/src/utils/commentJson.test.js +385 -0
- package/dist/src/utils/commentJson.test.js.map +1 -0
- package/dist/src/utils/costCalculator.d.ts +14 -0
- package/dist/src/utils/costCalculator.js +19 -0
- package/dist/src/utils/costCalculator.js.map +1 -0
- package/dist/src/utils/costCalculator.test.d.ts +6 -0
- package/dist/src/utils/costCalculator.test.js +177 -0
- package/dist/src/utils/costCalculator.test.js.map +1 -0
- package/dist/src/utils/cpuProfiler.d.ts +63 -0
- package/dist/src/utils/cpuProfiler.js +341 -0
- package/dist/src/utils/cpuProfiler.js.map +1 -0
- package/dist/src/utils/cpuProfiler.test.d.ts +6 -0
- package/dist/src/utils/cpuProfiler.test.js +293 -0
- package/dist/src/utils/cpuProfiler.test.js.map +1 -0
- package/dist/src/utils/deepMerge.d.ts +9 -0
- package/dist/src/utils/deepMerge.js +58 -0
- package/dist/src/utils/deepMerge.js.map +1 -0
- package/dist/src/utils/deepMerge.test.d.ts +6 -0
- package/dist/src/utils/deepMerge.test.js +143 -0
- package/dist/src/utils/deepMerge.test.js.map +1 -0
- package/dist/src/utils/dialogScopeUtils.d.ts +28 -0
- package/dist/src/utils/dialogScopeUtils.js +51 -0
- package/dist/src/utils/dialogScopeUtils.js.map +1 -0
- package/dist/src/utils/doctorChecks.d.ts +11 -0
- package/dist/src/utils/doctorChecks.js +351 -0
- package/dist/src/utils/doctorChecks.js.map +1 -0
- package/dist/src/utils/doctorChecks.test.d.ts +6 -0
- package/dist/src/utils/doctorChecks.test.js +280 -0
- package/dist/src/utils/doctorChecks.test.js.map +1 -0
- package/dist/src/utils/earlyInputCapture.d.ts +33 -0
- package/dist/src/utils/earlyInputCapture.js +311 -0
- package/dist/src/utils/earlyInputCapture.js.map +1 -0
- package/dist/src/utils/earlyInputCapture.test.d.ts +6 -0
- package/dist/src/utils/earlyInputCapture.test.js +274 -0
- package/dist/src/utils/earlyInputCapture.test.js.map +1 -0
- package/dist/src/utils/envVarResolver.d.ts +39 -0
- package/dist/src/utils/envVarResolver.js +100 -0
- package/dist/src/utils/envVarResolver.js.map +1 -0
- package/dist/src/utils/envVarResolver.test.d.ts +6 -0
- package/dist/src/utils/envVarResolver.test.js +221 -0
- package/dist/src/utils/envVarResolver.test.js.map +1 -0
- package/dist/src/utils/errors.d.ts +76 -0
- package/dist/src/utils/errors.js +237 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/errors.test.d.ts +6 -0
- package/dist/src/utils/errors.test.js +536 -0
- package/dist/src/utils/errors.test.js.map +1 -0
- package/dist/src/utils/events.d.ts +13 -0
- package/dist/src/utils/events.js +15 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/gitUtils.d.ts +30 -0
- package/dist/src/utils/gitUtils.js +108 -0
- package/dist/src/utils/gitUtils.js.map +1 -0
- package/dist/src/utils/gitUtils.test.d.ts +6 -0
- package/dist/src/utils/gitUtils.test.js +172 -0
- package/dist/src/utils/gitUtils.test.js.map +1 -0
- package/dist/src/utils/handleAutoUpdate.d.ts +16 -0
- package/dist/src/utils/handleAutoUpdate.js +144 -0
- package/dist/src/utils/handleAutoUpdate.js.map +1 -0
- package/dist/src/utils/headlessSafetyWarnings.d.ts +21 -0
- package/dist/src/utils/headlessSafetyWarnings.js +45 -0
- package/dist/src/utils/headlessSafetyWarnings.js.map +1 -0
- package/dist/src/utils/headlessSafetyWarnings.test.d.ts +6 -0
- package/dist/src/utils/headlessSafetyWarnings.test.js +66 -0
- package/dist/src/utils/headlessSafetyWarnings.test.js.map +1 -0
- package/dist/src/utils/housekeeping/cleanup.d.ts +15 -0
- package/dist/src/utils/housekeeping/cleanup.js +69 -0
- package/dist/src/utils/housekeeping/cleanup.js.map +1 -0
- package/dist/src/utils/housekeeping/cleanup.test.d.ts +6 -0
- package/dist/src/utils/housekeeping/cleanup.test.js +166 -0
- package/dist/src/utils/housekeeping/cleanup.test.js.map +1 -0
- package/dist/src/utils/housekeeping/lastInteractionAt.d.ts +9 -0
- package/dist/src/utils/housekeeping/lastInteractionAt.js +22 -0
- package/dist/src/utils/housekeeping/lastInteractionAt.js.map +1 -0
- package/dist/src/utils/housekeeping/scheduler.d.ts +17 -0
- package/dist/src/utils/housekeeping/scheduler.js +130 -0
- package/dist/src/utils/housekeeping/scheduler.js.map +1 -0
- package/dist/src/utils/housekeeping/scheduler.test.d.ts +6 -0
- package/dist/src/utils/housekeeping/scheduler.test.js +190 -0
- package/dist/src/utils/housekeeping/scheduler.test.js.map +1 -0
- package/dist/src/utils/housekeeping/throttledOnce.d.ts +13 -0
- package/dist/src/utils/housekeeping/throttledOnce.js +110 -0
- package/dist/src/utils/housekeeping/throttledOnce.js.map +1 -0
- package/dist/src/utils/housekeeping/throttledOnce.test.d.ts +6 -0
- package/dist/src/utils/housekeeping/throttledOnce.test.js +94 -0
- package/dist/src/utils/housekeeping/throttledOnce.test.js.map +1 -0
- package/dist/src/utils/installationInfo.d.ts +26 -0
- package/dist/src/utils/installationInfo.js +266 -0
- package/dist/src/utils/installationInfo.js.map +1 -0
- package/dist/src/utils/installationInfo.test.d.ts +6 -0
- package/dist/src/utils/installationInfo.test.js +466 -0
- package/dist/src/utils/installationInfo.test.js.map +1 -0
- package/dist/src/utils/languageUtils.d.ts +40 -0
- package/dist/src/utils/languageUtils.js +163 -0
- package/dist/src/utils/languageUtils.js.map +1 -0
- package/dist/src/utils/languageUtils.test.d.ts +6 -0
- package/dist/src/utils/languageUtils.test.js +341 -0
- package/dist/src/utils/languageUtils.test.js.map +1 -0
- package/dist/src/utils/math.d.ts +13 -0
- package/dist/src/utils/math.js +14 -0
- package/dist/src/utils/math.js.map +1 -0
- package/dist/src/utils/memoryDiagnostics.d.ts +65 -0
- package/dist/src/utils/memoryDiagnostics.js +365 -0
- package/dist/src/utils/memoryDiagnostics.js.map +1 -0
- package/dist/src/utils/memoryDiagnostics.test.d.ts +6 -0
- package/dist/src/utils/memoryDiagnostics.test.js +641 -0
- package/dist/src/utils/memoryDiagnostics.test.js.map +1 -0
- package/dist/src/utils/modelConfigUtils.d.ts +55 -0
- package/dist/src/utils/modelConfigUtils.js +186 -0
- package/dist/src/utils/modelConfigUtils.js.map +1 -0
- package/dist/src/utils/modelConfigUtils.test.d.ts +6 -0
- package/dist/src/utils/modelConfigUtils.test.js +1247 -0
- package/dist/src/utils/modelConfigUtils.test.js.map +1 -0
- package/dist/src/utils/nonInteractiveHelpers.d.ts +101 -0
- package/dist/src/utils/nonInteractiveHelpers.js +479 -0
- package/dist/src/utils/nonInteractiveHelpers.js.map +1 -0
- package/dist/src/utils/nonInteractiveHelpers.test.d.ts +6 -0
- package/dist/src/utils/nonInteractiveHelpers.test.js +1038 -0
- package/dist/src/utils/nonInteractiveHelpers.test.js.map +1 -0
- package/dist/src/utils/osc.d.ts +91 -0
- package/dist/src/utils/osc.js +162 -0
- package/dist/src/utils/osc.js.map +1 -0
- package/dist/src/utils/osc.test.d.ts +6 -0
- package/dist/src/utils/osc.test.js +217 -0
- package/dist/src/utils/osc.test.js.map +1 -0
- package/dist/src/utils/package.d.ts +12 -0
- package/dist/src/utils/package.js +24 -0
- package/dist/src/utils/package.js.map +1 -0
- package/dist/src/utils/processUtils.d.ts +13 -0
- package/dist/src/utils/processUtils.js +18 -0
- package/dist/src/utils/processUtils.js.map +1 -0
- package/dist/src/utils/processUtils.test.d.ts +6 -0
- package/dist/src/utils/processUtils.test.js +20 -0
- package/dist/src/utils/processUtils.test.js.map +1 -0
- package/dist/src/utils/readStdin.d.ts +6 -0
- package/dist/src/utils/readStdin.js +60 -0
- package/dist/src/utils/readStdin.js.map +1 -0
- package/dist/src/utils/readStdin.test.d.ts +6 -0
- package/dist/src/utils/readStdin.test.js +88 -0
- package/dist/src/utils/readStdin.test.js.map +1 -0
- package/dist/src/utils/relaunch.d.ts +9 -0
- package/dist/src/utils/relaunch.js +68 -0
- package/dist/src/utils/relaunch.js.map +1 -0
- package/dist/src/utils/relaunch.test.d.ts +6 -0
- package/dist/src/utils/relaunch.test.js +291 -0
- package/dist/src/utils/relaunch.test.js.map +1 -0
- package/dist/src/utils/resolvePath.d.ts +6 -0
- package/dist/src/utils/resolvePath.js +21 -0
- package/dist/src/utils/resolvePath.js.map +1 -0
- package/dist/src/utils/runBudget.d.ts +116 -0
- package/dist/src/utils/runBudget.js +235 -0
- package/dist/src/utils/runBudget.js.map +1 -0
- package/dist/src/utils/runBudget.test.d.ts +6 -0
- package/dist/src/utils/runBudget.test.js +187 -0
- package/dist/src/utils/runBudget.test.js.map +1 -0
- package/dist/src/utils/sandbox-macos-permissive-closed.sb +33 -0
- package/dist/src/utils/sandbox-macos-permissive-open.sb +28 -0
- package/dist/src/utils/sandbox-macos-permissive-proxied.sb +38 -0
- package/dist/src/utils/sandbox-macos-restrictive-closed.sb +94 -0
- package/dist/src/utils/sandbox-macos-restrictive-open.sb +97 -0
- package/dist/src/utils/sandbox-macos-restrictive-proxied.sb +99 -0
- package/dist/src/utils/sandbox.d.ts +7 -0
- package/dist/src/utils/sandbox.js +788 -0
- package/dist/src/utils/sandbox.js.map +1 -0
- package/dist/src/utils/sessionPaths.d.ts +19 -0
- package/dist/src/utils/sessionPaths.js +141 -0
- package/dist/src/utils/sessionPaths.js.map +1 -0
- package/dist/src/utils/sessionPaths.test.d.ts +6 -0
- package/dist/src/utils/sessionPaths.test.js +249 -0
- package/dist/src/utils/sessionPaths.test.js.map +1 -0
- package/dist/src/utils/settingsUtils.d.ts +167 -0
- package/dist/src/utils/settingsUtils.js +532 -0
- package/dist/src/utils/settingsUtils.js.map +1 -0
- package/dist/src/utils/settingsUtils.test.d.ts +6 -0
- package/dist/src/utils/settingsUtils.test.js +849 -0
- package/dist/src/utils/settingsUtils.test.js.map +1 -0
- package/dist/src/utils/spawnWrapper.d.ts +7 -0
- package/dist/src/utils/spawnWrapper.js +8 -0
- package/dist/src/utils/spawnWrapper.js.map +1 -0
- package/dist/src/utils/standalone-update-verify.d.ts +12 -0
- package/dist/src/utils/standalone-update-verify.js +43 -0
- package/dist/src/utils/standalone-update-verify.js.map +1 -0
- package/dist/src/utils/standalone-update-verify.test.d.ts +6 -0
- package/dist/src/utils/standalone-update-verify.test.js +27 -0
- package/dist/src/utils/standalone-update-verify.test.js.map +1 -0
- package/dist/src/utils/standalone-update.d.ts +27 -0
- package/dist/src/utils/standalone-update.js +714 -0
- package/dist/src/utils/standalone-update.js.map +1 -0
- package/dist/src/utils/standalone-update.test.d.ts +6 -0
- package/dist/src/utils/standalone-update.test.js +301 -0
- package/dist/src/utils/standalone-update.test.js.map +1 -0
- package/dist/src/utils/startupProfiler.d.ts +90 -0
- package/dist/src/utils/startupProfiler.js +267 -0
- package/dist/src/utils/startupProfiler.js.map +1 -0
- package/dist/src/utils/startupProfiler.test.d.ts +1 -0
- package/dist/src/utils/startupProfiler.test.js +293 -0
- package/dist/src/utils/startupProfiler.test.js.map +1 -0
- package/dist/src/utils/startupWarnings.d.ts +6 -0
- package/dist/src/utils/startupWarnings.js +40 -0
- package/dist/src/utils/startupWarnings.js.map +1 -0
- package/dist/src/utils/stdioHelpers.d.ts +31 -0
- package/dist/src/utils/stdioHelpers.js +38 -0
- package/dist/src/utils/stdioHelpers.js.map +1 -0
- package/dist/src/utils/systemInfo.d.ts +78 -0
- package/dist/src/utils/systemInfo.js +208 -0
- package/dist/src/utils/systemInfo.js.map +1 -0
- package/dist/src/utils/systemInfo.test.d.ts +6 -0
- package/dist/src/utils/systemInfo.test.js +380 -0
- package/dist/src/utils/systemInfo.test.js.map +1 -0
- package/dist/src/utils/systemInfoFields.d.ts +18 -0
- package/dist/src/utils/systemInfoFields.js +102 -0
- package/dist/src/utils/systemInfoFields.js.map +1 -0
- package/dist/src/utils/systemInfoFields.test.d.ts +6 -0
- package/dist/src/utils/systemInfoFields.test.js +74 -0
- package/dist/src/utils/systemInfoFields.test.js.map +1 -0
- package/dist/src/utils/terminalSequence.d.ts +21 -0
- package/dist/src/utils/terminalSequence.js +124 -0
- package/dist/src/utils/terminalSequence.js.map +1 -0
- package/dist/src/utils/terminalSequence.test.d.ts +6 -0
- package/dist/src/utils/terminalSequence.test.js +132 -0
- package/dist/src/utils/terminalSequence.test.js.map +1 -0
- package/dist/src/utils/truncatedDiffPreview.d.ts +6 -0
- package/dist/src/utils/truncatedDiffPreview.js +18 -0
- package/dist/src/utils/truncatedDiffPreview.js.map +1 -0
- package/dist/src/utils/updateEventEmitter.d.ts +11 -0
- package/dist/src/utils/updateEventEmitter.js +12 -0
- package/dist/src/utils/updateEventEmitter.js.map +1 -0
- package/dist/src/utils/userPromptExpansionHook.d.ts +9 -0
- package/dist/src/utils/userPromptExpansionHook.js +30 -0
- package/dist/src/utils/userPromptExpansionHook.js.map +1 -0
- package/dist/src/utils/userPromptExpansionHook.test.d.ts +6 -0
- package/dist/src/utils/userPromptExpansionHook.test.js +69 -0
- package/dist/src/utils/userPromptExpansionHook.test.js.map +1 -0
- package/dist/src/utils/userStartupWarnings.d.ts +12 -0
- package/dist/src/utils/userStartupWarnings.js +74 -0
- package/dist/src/utils/userStartupWarnings.js.map +1 -0
- package/dist/src/utils/userStartupWarnings.test.d.ts +6 -0
- package/dist/src/utils/userStartupWarnings.test.js +88 -0
- package/dist/src/utils/userStartupWarnings.test.js.map +1 -0
- package/dist/src/utils/version.d.ts +6 -0
- package/dist/src/utils/version.js +11 -0
- package/dist/src/utils/version.js.map +1 -0
- package/dist/src/utils/warningHandler.d.ts +29 -0
- package/dist/src/utils/warningHandler.js +100 -0
- package/dist/src/utils/warningHandler.js.map +1 -0
- package/dist/src/utils/warningHandler.test.d.ts +6 -0
- package/dist/src/utils/warningHandler.test.js +185 -0
- package/dist/src/utils/warningHandler.test.js.map +1 -0
- package/dist/src/utils/windowTitle.d.ts +12 -0
- package/dist/src/utils/windowTitle.js +19 -0
- package/dist/src/utils/windowTitle.js.map +1 -0
- package/dist/src/utils/windowTitle.test.d.ts +6 -0
- package/dist/src/utils/windowTitle.test.js +49 -0
- package/dist/src/utils/windowTitle.test.js.map +1 -0
- package/dist/src/utils/writeWithBackup.d.ts +49 -0
- package/dist/src/utils/writeWithBackup.js +136 -0
- package/dist/src/utils/writeWithBackup.js.map +1 -0
- package/dist/src/utils/writeWithBackup.test.d.ts +6 -0
- package/dist/src/utils/writeWithBackup.test.js +177 -0
- package/dist/src/utils/writeWithBackup.test.js.map +1 -0
- package/dist/src/validateNonInterActiveAuth.d.ts +8 -0
- package/dist/src/validateNonInterActiveAuth.js +66 -0
- package/dist/src/validateNonInterActiveAuth.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1,3559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Qwen Team
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
import { promises as fs } from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { Readable, Writable } from 'node:stream';
|
|
11
|
+
import { ClientSideConnection, PROTOCOL_VERSION, ndJsonStream, } from '@agentclientprotocol/sdk';
|
|
12
|
+
import { writeStderrLine } from '../utils/stdioHelpers.js';
|
|
13
|
+
import { canonicalizeWorkspace } from './fs/paths.js';
|
|
14
|
+
import { EventBus, DEFAULT_RING_SIZE } from './eventBus.js';
|
|
15
|
+
import { BridgeChannelClosedError, BridgeTimeoutError, MissingCliEntryError, SERVE_CONTROL_EXT_METHODS, SERVE_STATUS_EXT_METHODS, STATUS_SCHEMA_VERSION, createIdleAcpPreflightCells, createIdleEnvStatus, createIdleWorkspaceMcpStatus, createIdleWorkspaceProvidersStatus, createIdleWorkspaceSkillsStatus, mapDomainErrorToErrorKind, } from './status.js';
|
|
16
|
+
import { TrustGateError, getCurrentGeminiMdFilename, } from '@tulex-cli/tulex-cli-core';
|
|
17
|
+
// Bridge errors lifted to `@tulex-cli/acp-bridge/bridgeErrors` in
|
|
18
|
+
// #4175 PR 22b. `MAX_WORKSPACE_PATH_LENGTH` lifted to
|
|
19
|
+
// `@tulex-cli/acp-bridge/workspacePaths` in the same slice.
|
|
20
|
+
// Imported AND re-exported so existing relative callers (server.ts:31,
|
|
21
|
+
// workspaceAgents.ts, workspaceMemory.ts) keep resolving and the local
|
|
22
|
+
// factory code below can still construct + throw these errors.
|
|
23
|
+
import { SessionNotFoundError, RestoreInProgressError, InvalidSessionScopeError, SessionLimitExceededError, WorkspaceMismatchError, InvalidClientIdError, InvalidPermissionOptionError, InvalidSessionMetadataError, WorkspaceInitConflictError, McpServerNotFoundError, McpServerRestartFailedError, } from '@tulex-cli/acp-bridge/bridgeErrors';
|
|
24
|
+
import { MAX_WORKSPACE_PATH_LENGTH } from '@tulex-cli/acp-bridge/workspacePaths';
|
|
25
|
+
export { SessionNotFoundError, RestoreInProgressError, InvalidSessionScopeError, SessionLimitExceededError, WorkspaceMismatchError, InvalidClientIdError, InvalidPermissionOptionError, InvalidSessionMetadataError, WorkspaceInitConflictError, McpServerNotFoundError, McpServerRestartFailedError, MAX_WORKSPACE_PATH_LENGTH, };
|
|
26
|
+
/** @internal Visible for bridge lifecycle regression tests. */
|
|
27
|
+
export function findChannelInfoForEntry(current, alive, entry) {
|
|
28
|
+
if (current?.channel === entry.channel)
|
|
29
|
+
return current;
|
|
30
|
+
for (const info of alive) {
|
|
31
|
+
if (info.channel === entry.channel)
|
|
32
|
+
return info;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/** @internal Visible for bridge lifecycle regression tests. */
|
|
37
|
+
export function detachSessionIdFromEntryChannel(current, alive, entry, sessionId) {
|
|
38
|
+
const info = findChannelInfoForEntry(current, alive, entry);
|
|
39
|
+
info?.sessionIds.delete(sessionId);
|
|
40
|
+
return info;
|
|
41
|
+
}
|
|
42
|
+
// Bounded duplicate-vote cache. Stores only requestId/sessionId/outcome, so
|
|
43
|
+
// 512 records stays small while covering normal UI reconnect/race windows.
|
|
44
|
+
const MAX_RESOLVED_PERMISSION_RECORDS = 512;
|
|
45
|
+
function isServeDebugLoggingEnabled() {
|
|
46
|
+
const value = process.env['QWEN_SERVE_DEBUG'];
|
|
47
|
+
if (!value)
|
|
48
|
+
return false;
|
|
49
|
+
return !['0', 'false', 'off', 'no'].includes(value.trim().toLowerCase());
|
|
50
|
+
}
|
|
51
|
+
function writeServeDebugLine(message) {
|
|
52
|
+
if (!isServeDebugLoggingEnabled())
|
|
53
|
+
return;
|
|
54
|
+
writeStderrLine(`qwen serve debug: ${message}`);
|
|
55
|
+
}
|
|
56
|
+
// `InvalidPermissionOptionError` lifted to
|
|
57
|
+
// `@tulex-cli/acp-bridge/bridgeErrors` in #4175 PR 22b — see
|
|
58
|
+
// the consolidated re-export block earlier in this file.
|
|
59
|
+
const MAX_DISPLAY_NAME_LENGTH = 256;
|
|
60
|
+
/**
|
|
61
|
+
* PR 14b fix #1 (codex review round 1): bounded buffering for ACP
|
|
62
|
+
* `extNotification` frames that arrive on `BridgeClient` before the
|
|
63
|
+
* matching session has been registered in `byId`. The bridge populates
|
|
64
|
+
* `byId` only AFTER `connection.newSession` returns, but the child's
|
|
65
|
+
* MCP discovery runs INSIDE `newSession` and may fire budget events
|
|
66
|
+
* synchronously before the response makes it back. Without buffering,
|
|
67
|
+
* those frames hit `resolveEntry → undefined` and are silently dropped
|
|
68
|
+
* — the very first replay-ring slot for the new session is missing
|
|
69
|
+
* the events that fired during its creation.
|
|
70
|
+
*
|
|
71
|
+
* The triple bound (max sessions × max events per session × TTL)
|
|
72
|
+
* caps worst-case heap retention even if a malicious / buggy child
|
|
73
|
+
* spammed `extNotification` for sessionIds that never register:
|
|
74
|
+
* 64 × 32 × ~200B ≈ 400 KB total. TTL is generous (60s — far longer
|
|
75
|
+
* than realistic session creation latency of seconds) so brief
|
|
76
|
+
* scheduling pauses don't cause real warnings to be evicted.
|
|
77
|
+
*/
|
|
78
|
+
const MAX_EARLY_EVENT_SESSIONS = 64;
|
|
79
|
+
const MAX_EARLY_EVENTS_PER_SESSION = 32;
|
|
80
|
+
const EARLY_EVENT_TTL_MS = 60_000;
|
|
81
|
+
function hasControlCharacter(value) {
|
|
82
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
83
|
+
const code = value.charCodeAt(i);
|
|
84
|
+
if (code <= 0x1f || code === 0x7f) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
// `InvalidSessionMetadataError`, `WorkspaceInitConflictError`,
|
|
91
|
+
// `McpServerNotFoundError`, `McpServerRestartFailedError` lifted to
|
|
92
|
+
// `@tulex-cli/acp-bridge/bridgeErrors` in #4175 PR 22b — see the
|
|
93
|
+
// consolidated re-export block earlier in this file.
|
|
94
|
+
/**
|
|
95
|
+
* Bridge `Client` implementation — the daemon's response surface for things
|
|
96
|
+
* the agent asks the client (file reads/writes, permission prompts).
|
|
97
|
+
*
|
|
98
|
+
* Stage 1 behavior:
|
|
99
|
+
* - `requestPermission` publishes a `permission_request` event onto the
|
|
100
|
+
* session bus and awaits the first HTTP `POST /permission/:requestId`
|
|
101
|
+
* vote (first-responder wins). When the session is cancelled or the
|
|
102
|
+
* daemon shuts down, the pending promise resolves with
|
|
103
|
+
* `{ outcome: { outcome: 'cancelled' } }` per ACP spec.
|
|
104
|
+
* - `sessionUpdate` notifications publish onto the session's EventBus; SSE
|
|
105
|
+
* subscribers (`GET /session/:id/events`) drain it.
|
|
106
|
+
* - File reads/writes proxy to local fs (daemon and agent share the host).
|
|
107
|
+
*
|
|
108
|
+
* Stage 1 trust model: the spawned `qwen --acp` child runs as the same user
|
|
109
|
+
* as the daemon, so the file-proxy methods do NOT enforce a workspace-cwd
|
|
110
|
+
* sandbox. The agent could already read or write the same files via its
|
|
111
|
+
* built-in tools (e.g. shell). Restricting the bridge here would be
|
|
112
|
+
* theatre. Stage 4+ remote-sandbox deployments swap this `Client` for a
|
|
113
|
+
* sandbox-aware variant — see issue #3803 §11.
|
|
114
|
+
*/
|
|
115
|
+
class BridgeClient {
|
|
116
|
+
resolveEntry;
|
|
117
|
+
resolvePendingRestoreEvents;
|
|
118
|
+
registerPending;
|
|
119
|
+
rollbackPending;
|
|
120
|
+
permissionTimeoutMs;
|
|
121
|
+
maxPendingPerSession;
|
|
122
|
+
constructor(
|
|
123
|
+
/**
|
|
124
|
+
* Look up the `SessionEntry` for an ACP call. Stage 1.5 multi-
|
|
125
|
+
* session on one channel means `BridgeClient` is shared across
|
|
126
|
+
* many sessions, so we can't bind the entry in a closure — we
|
|
127
|
+
* dispatch by the `sessionId` ACP includes in every per-session
|
|
128
|
+
* notification / request. `undefined` sessionId is the fallback
|
|
129
|
+
* for ACP calls that don't carry one (none expected on the
|
|
130
|
+
* client surface as of this writing) and resolves to whatever
|
|
131
|
+
* the channel's most-recent entry is — kept defensive to avoid
|
|
132
|
+
* silent drops if ACP grows a no-sessionId call.
|
|
133
|
+
*/
|
|
134
|
+
resolveEntry, resolvePendingRestoreEvents, registerPending,
|
|
135
|
+
/**
|
|
136
|
+
* Roll back a `registerPending` call when the subsequent publish
|
|
137
|
+
* fails (closed bus). Resolves the pending promise as cancelled
|
|
138
|
+
* and removes it from the daemon-wide maps so a late
|
|
139
|
+
* `respondToPermission` for this id returns 404 cleanly.
|
|
140
|
+
*/
|
|
141
|
+
rollbackPending,
|
|
142
|
+
/**
|
|
143
|
+
* Bd1yh: wall-clock ms before `requestPermission` resolves as
|
|
144
|
+
* cancelled if no client vote arrives. 0 = disabled. Prevents
|
|
145
|
+
* the per-session FIFO `promptQueue` from poisoning forever
|
|
146
|
+
* when no SSE subscriber is connected.
|
|
147
|
+
*/
|
|
148
|
+
permissionTimeoutMs,
|
|
149
|
+
/**
|
|
150
|
+
* Bd1z5: per-session cap on in-flight permissions. New requests
|
|
151
|
+
* past this cap resolve as cancelled with a stderr warning.
|
|
152
|
+
* Infinity = disabled.
|
|
153
|
+
*/
|
|
154
|
+
maxPendingPerSession) {
|
|
155
|
+
this.resolveEntry = resolveEntry;
|
|
156
|
+
this.resolvePendingRestoreEvents = resolvePendingRestoreEvents;
|
|
157
|
+
this.registerPending = registerPending;
|
|
158
|
+
this.rollbackPending = rollbackPending;
|
|
159
|
+
this.permissionTimeoutMs = permissionTimeoutMs;
|
|
160
|
+
this.maxPendingPerSession = maxPendingPerSession;
|
|
161
|
+
}
|
|
162
|
+
// FIXME(stage-1.5, chiga0 finding 3):
|
|
163
|
+
// The first-responder permission flow here is a third permission
|
|
164
|
+
// model in the codebase (alongside ACP `requestPermission` direct
|
|
165
|
+
// and stream-json `ControlDispatcher`). Stage 1.5 should lift
|
|
166
|
+
// "permission request lifecycle" into a `PermissionMediator`
|
|
167
|
+
// interface with strategy-pluggable policies (`first-responder` |
|
|
168
|
+
// `designated` | `consensus` | `local-only`) so all four
|
|
169
|
+
// agent-exposing surfaces share one lifecycle. This is also the
|
|
170
|
+
// closure point for the prior chiga0 audit Risk 2 (first-responder
|
|
171
|
+
// lacks an authorization model). Reference:
|
|
172
|
+
// https://github.com/Tulex/tulex-cli/pull/3889#issuecomment-4427773706
|
|
173
|
+
async requestPermission(params) {
|
|
174
|
+
const entry = this.resolveEntry(params.sessionId);
|
|
175
|
+
if (!entry)
|
|
176
|
+
return { outcome: { outcome: 'cancelled' } };
|
|
177
|
+
// Bd1z5: per-session cap. Reject before registering so we never
|
|
178
|
+
// grow `pendingPermissionIds` past the limit.
|
|
179
|
+
if (entry.pendingPermissionIds.size >= this.maxPendingPerSession) {
|
|
180
|
+
writeStderrLine(`qwen serve: session ${entry.sessionId} exceeded ` +
|
|
181
|
+
`maxPendingPermissionsPerSession (${this.maxPendingPerSession}) — ` +
|
|
182
|
+
`resolving new permission as cancelled.`);
|
|
183
|
+
return { outcome: { outcome: 'cancelled' } };
|
|
184
|
+
}
|
|
185
|
+
const requestId = randomUUID();
|
|
186
|
+
return await new Promise((resolve) => {
|
|
187
|
+
let settled = false;
|
|
188
|
+
let timer;
|
|
189
|
+
const settleOnce = (response) => {
|
|
190
|
+
if (settled)
|
|
191
|
+
return;
|
|
192
|
+
settled = true;
|
|
193
|
+
if (timer)
|
|
194
|
+
clearTimeout(timer);
|
|
195
|
+
resolve(response);
|
|
196
|
+
};
|
|
197
|
+
// BkwQI: snapshot the option-id set the agent is offering for
|
|
198
|
+
// this prompt. `respondToPermission` checks the voter's
|
|
199
|
+
// `optionId` against this set so a malicious client can't
|
|
200
|
+
// forge an option (e.g. `ProceedAlways*`) the agent
|
|
201
|
+
// intentionally hid.
|
|
202
|
+
const allowedOptionIds = new Set(params.options.map((o) => String(o.optionId ?? '')));
|
|
203
|
+
allowedOptionIds.delete('');
|
|
204
|
+
this.registerPending({
|
|
205
|
+
requestId,
|
|
206
|
+
sessionId: entry.sessionId,
|
|
207
|
+
resolve: settleOnce,
|
|
208
|
+
allowedOptionIds,
|
|
209
|
+
});
|
|
210
|
+
// `publish()` returns `undefined` on a closed bus — the
|
|
211
|
+
// shutdown path closes per-session buses BEFORE awaiting
|
|
212
|
+
// `channel.kill()`, leaving a small window where the agent
|
|
213
|
+
// can still issue `requestPermission`. If we registered the
|
|
214
|
+
// pending entry above but the publish fails, no SSE
|
|
215
|
+
// subscriber will ever see the request → no client can vote
|
|
216
|
+
// → the pending promise never resolves → agent's
|
|
217
|
+
// `requestPermission` hangs forever (a real bug, not a
|
|
218
|
+
// theoretical one — the daemon's shutdown.kill() loop awaits
|
|
219
|
+
// each child, and a child stuck waiting on permission would
|
|
220
|
+
// pin shutdown until the kill timer expires).
|
|
221
|
+
//
|
|
222
|
+
// Resolve as `cancelled` immediately if the bus rejected
|
|
223
|
+
// the publish. Mirrors the orphan-permission handling in
|
|
224
|
+
// `registerPending` itself for the entry-already-gone case.
|
|
225
|
+
const published = entry.events.publish({
|
|
226
|
+
type: 'permission_request',
|
|
227
|
+
data: {
|
|
228
|
+
requestId,
|
|
229
|
+
sessionId: entry.sessionId,
|
|
230
|
+
toolCall: params.toolCall,
|
|
231
|
+
options: params.options,
|
|
232
|
+
},
|
|
233
|
+
...(entry.activePromptOriginatorClientId
|
|
234
|
+
? { originatorClientId: entry.activePromptOriginatorClientId }
|
|
235
|
+
: {}),
|
|
236
|
+
});
|
|
237
|
+
if (!published) {
|
|
238
|
+
// Roll back the pending registration and resolve cancelled.
|
|
239
|
+
this.rollbackPending(requestId);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// Bd1yh: arm the deadline AFTER publish so we don't fire-and-
|
|
243
|
+
// cancel a no-subscriber request before the bus even saw it.
|
|
244
|
+
// When the deadline fires, roll back the pending (so a late
|
|
245
|
+
// vote returns 404) and resolve as cancelled (unwinding the
|
|
246
|
+
// agent's awaiting promise so the per-session FIFO can drain).
|
|
247
|
+
if (this.permissionTimeoutMs > 0) {
|
|
248
|
+
timer = setTimeout(() => {
|
|
249
|
+
if (settled)
|
|
250
|
+
return;
|
|
251
|
+
writeStderrLine(`qwen serve: session ${entry.sessionId} permission ` +
|
|
252
|
+
`${requestId} timed out after ${this.permissionTimeoutMs}ms ` +
|
|
253
|
+
`(no client voted) — resolving as cancelled.`);
|
|
254
|
+
this.rollbackPending(requestId);
|
|
255
|
+
}, this.permissionTimeoutMs);
|
|
256
|
+
if (typeof timer === 'object' && timer && 'unref' in timer) {
|
|
257
|
+
timer.unref();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
async sessionUpdate(params) {
|
|
263
|
+
const entry = this.resolveEntry(params.sessionId);
|
|
264
|
+
const events = entry?.events ?? this.resolvePendingRestoreEvents(params.sessionId);
|
|
265
|
+
if (!events)
|
|
266
|
+
return;
|
|
267
|
+
events.publish({
|
|
268
|
+
type: 'session_update',
|
|
269
|
+
data: params,
|
|
270
|
+
...(entry?.activePromptOriginatorClientId
|
|
271
|
+
? { originatorClientId: entry.activePromptOriginatorClientId }
|
|
272
|
+
: {}),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* PR 14b fix #1 (codex review round 1): bounded early-event buffer.
|
|
277
|
+
* Frames are keyed by sessionId; each entry tracks its `expiresAt`
|
|
278
|
+
* for lazy TTL-based eviction in `bufferEarlyEvent`. Drained by
|
|
279
|
+
* `drainEarlyEvents` whenever the bridge registers a session with
|
|
280
|
+
* a matching id. See MAX_EARLY_EVENT_* constants for capacity
|
|
281
|
+
* bounds.
|
|
282
|
+
*/
|
|
283
|
+
earlyEvents = new Map();
|
|
284
|
+
/**
|
|
285
|
+
* PR 14b fix (codex review round 5): tombstone for closed/killed
|
|
286
|
+
* session ids. Pre-fix, `extNotification` buffered events for any
|
|
287
|
+
* unknown sessionId — including ids of just-closed sessions whose
|
|
288
|
+
* dying child fired one last `extNotification` between
|
|
289
|
+
* `byId.delete(sid)` and the channel actually exiting. If the SAME
|
|
290
|
+
* id was later re-registered via `session/load` or `session/resume`
|
|
291
|
+
* within the buffer's 60s TTL, `drainEarlyEvents` would replay
|
|
292
|
+
* stale prior-session telemetry (false budget warnings, refused
|
|
293
|
+
* server names from the OLD session) onto the NEW subscriber.
|
|
294
|
+
*
|
|
295
|
+
* Tombstone semantics:
|
|
296
|
+
* - Marked when the bridge removes a sessionId from `byId` (kill
|
|
297
|
+
* path, channel.exited handler, closeSession).
|
|
298
|
+
* - Concurrently purges any in-flight `earlyEvents[id]` so a
|
|
299
|
+
* buffered-but-undelivered frame can't leak either.
|
|
300
|
+
* - `bufferEarlyEvent` rejects tombstoned ids (the dying child's
|
|
301
|
+
* late notification just gets dropped).
|
|
302
|
+
* - `drainEarlyEvents` clears the tombstone — a fresh
|
|
303
|
+
* `createSessionEntry` for the same id is the legitimate
|
|
304
|
+
* "load/resume of a persisted session id" case, and at that
|
|
305
|
+
* point any stale event has already been rejected at buffer time.
|
|
306
|
+
* - TTL = `EARLY_EVENT_TTL_MS` (60s) — same as the early-event
|
|
307
|
+
* buffer, so by the time a tombstone expires there can be no
|
|
308
|
+
* stale frame for that id anywhere in the system.
|
|
309
|
+
*/
|
|
310
|
+
tombstonedSessionIds = new Map();
|
|
311
|
+
/**
|
|
312
|
+
* PR 14b fix (codex review round 6): allow-list of sessionIds that
|
|
313
|
+
* are currently being restored via `session/load` /
|
|
314
|
+
* `session/resume`. Bypasses the tombstone check in
|
|
315
|
+
* `bufferEarlyEvent` so restore-time guardrail events for a
|
|
316
|
+
* previously-closed id flow through to the future
|
|
317
|
+
* `createSessionEntry → drainEarlyEvents` call.
|
|
318
|
+
*
|
|
319
|
+
* Pre-fix the round-5 tombstone protected against post-mortem
|
|
320
|
+
* stale events from dying children (correct), but it ALSO
|
|
321
|
+
* rejected legitimate restore-time events for the same id
|
|
322
|
+
* because `markSessionClosed` (60s TTL) is set BEFORE a future
|
|
323
|
+
* `load` can clear the tombstone via `drainEarlyEvents` (which
|
|
324
|
+
* only runs AFTER `createSessionEntry`, which only runs AFTER the
|
|
325
|
+
* ACP `loadSession`/`unstable_resumeSession` returns). The
|
|
326
|
+
* restored child's MCP discovery firing during that ACP call
|
|
327
|
+
* window had its budget events silently dropped.
|
|
328
|
+
*
|
|
329
|
+
* Bridge factory enters the set before awaiting the ACP restore
|
|
330
|
+
* call and exits the set on settle (success or failure). Multi-
|
|
331
|
+
* waiter coalescing on the same id is naturally handled — the
|
|
332
|
+
* Set is idempotent on add and the cleanup is paired with the
|
|
333
|
+
* IIFE that does the ACP call (only one such IIFE per id at a
|
|
334
|
+
* time).
|
|
335
|
+
*/
|
|
336
|
+
inFlightRestoreIds = new Set();
|
|
337
|
+
/**
|
|
338
|
+
* Handle child→bridge ACP `extNotification` calls and translate them into
|
|
339
|
+
* session-scoped SSE frames.
|
|
340
|
+
*/
|
|
341
|
+
async extNotification(method, params) {
|
|
342
|
+
const sessionId = params['sessionId'];
|
|
343
|
+
if (typeof sessionId !== 'string')
|
|
344
|
+
return;
|
|
345
|
+
if (method === 'qwen/notify/session/terminal-sequence') {
|
|
346
|
+
const { v: _v2, sessionId: _sid2, ...tsRest } = params;
|
|
347
|
+
void _v2;
|
|
348
|
+
void _sid2;
|
|
349
|
+
const terminalSequence = tsRest['terminalSequence'];
|
|
350
|
+
if (typeof terminalSequence !== 'string' ||
|
|
351
|
+
terminalSequence.length === 0) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
this.publishExtNotification(sessionId, 'terminal_sequence', tsRest);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (method !== 'qwen/notify/session/mcp-budget-event')
|
|
358
|
+
return;
|
|
359
|
+
const kind = params['kind'];
|
|
360
|
+
const type = kind === 'budget_warning'
|
|
361
|
+
? 'mcp_budget_warning'
|
|
362
|
+
: kind === 'refused_batch'
|
|
363
|
+
? 'mcp_child_refused_batch'
|
|
364
|
+
: undefined;
|
|
365
|
+
if (!type)
|
|
366
|
+
return;
|
|
367
|
+
// Strip the routing fields (`v`, `sessionId`, `kind`) from the
|
|
368
|
+
// outbound `data` payload — the SSE frame already carries `v` at
|
|
369
|
+
// the envelope level (`EVENT_SCHEMA_VERSION`) and the session id
|
|
370
|
+
// is implicit from the endpoint, so duplicating them in `data`
|
|
371
|
+
// would be noise. `kind` is encoded as the frame `type`.
|
|
372
|
+
const { v: _v, sessionId: _sid, kind: _kind, ...rest } = params;
|
|
373
|
+
void _v;
|
|
374
|
+
void _sid;
|
|
375
|
+
void _kind;
|
|
376
|
+
this.publishExtNotification(sessionId, type, rest);
|
|
377
|
+
}
|
|
378
|
+
publishExtNotification(sessionId, type, data) {
|
|
379
|
+
const entry = this.resolveEntry(sessionId);
|
|
380
|
+
const frame = {
|
|
381
|
+
type,
|
|
382
|
+
data,
|
|
383
|
+
...(entry?.activePromptOriginatorClientId
|
|
384
|
+
? { originatorClientId: entry.activePromptOriginatorClientId }
|
|
385
|
+
: {}),
|
|
386
|
+
};
|
|
387
|
+
if (entry) {
|
|
388
|
+
entry.events.publish(frame);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
// No entry yet — buffer for `drainEarlyEvents`. The bridge calls
|
|
392
|
+
// `drainEarlyEvents` immediately after `byId.set(sessionId, entry)`
|
|
393
|
+
// in `createSessionEntry`; if the session never registers (spawn
|
|
394
|
+
// failure), the entry is GC'd by TTL after EARLY_EVENT_TTL_MS.
|
|
395
|
+
this.bufferEarlyEvent(sessionId, frame);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* PR 14b fix #1: enqueue `frame` for `sessionId`. Lazy TTL sweep
|
|
399
|
+
* runs first so caller doesn't pay for stale entries before
|
|
400
|
+
* deciding whether the session-cap is reached. New sessionIds
|
|
401
|
+
* past `MAX_EARLY_EVENT_SESSIONS` are dropped (defense against a
|
|
402
|
+
* malicious / buggy child fanning out fake sessionIds); same-
|
|
403
|
+
* sessionId frames past `MAX_EARLY_EVENTS_PER_SESSION` are dropped
|
|
404
|
+
* to bound per-session memory.
|
|
405
|
+
*/
|
|
406
|
+
bufferEarlyEvent(sessionId, frame) {
|
|
407
|
+
const now = Date.now();
|
|
408
|
+
// PR 14b fix (codex round 5): drop frames for ids the bridge has
|
|
409
|
+
// already marked closed/killed. Sweep + check before any other
|
|
410
|
+
// work so a malicious / buggy child can't keep appending
|
|
411
|
+
// post-mortem frames against an old id. Live ids that re-register
|
|
412
|
+
// (load/resume) clear their tombstone in `drainEarlyEvents`.
|
|
413
|
+
//
|
|
414
|
+
// Round 6 amendment: skip the tombstone check for ids currently
|
|
415
|
+
// being restored. Pre-amendment a `close → load same id` sequence
|
|
416
|
+
// within 60s lost any restore-time guardrail events because the
|
|
417
|
+
// tombstone outlived `bufferEarlyEvent` but `drainEarlyEvents`
|
|
418
|
+
// (which clears it) only runs after the ACP restore returns.
|
|
419
|
+
this.sweepExpiredTombstones(now);
|
|
420
|
+
if (this.tombstonedSessionIds.has(sessionId) &&
|
|
421
|
+
!this.inFlightRestoreIds.has(sessionId)) {
|
|
422
|
+
writeStderrLine(`qwen serve: dropping mcp guardrail extNotification ` +
|
|
423
|
+
`for tombstoned session ${JSON.stringify(sessionId)} ` +
|
|
424
|
+
`(post-close stale event)`);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
this.sweepExpiredEarlyEvents(now);
|
|
428
|
+
let buf = this.earlyEvents.get(sessionId);
|
|
429
|
+
if (!buf) {
|
|
430
|
+
if (this.earlyEvents.size >= MAX_EARLY_EVENT_SESSIONS) {
|
|
431
|
+
// PR 14b fix (codex round 6): observability. Other drop
|
|
432
|
+
// sites in this PR all log; the silent return here was the
|
|
433
|
+
// outlier. Stays at stderr (visible without debug=true)
|
|
434
|
+
// because hitting this cap means the daemon is under
|
|
435
|
+
// notification pressure from 64+ concurrent sessions —
|
|
436
|
+
// worth surfacing.
|
|
437
|
+
writeStderrLine(`qwen serve: dropping mcp guardrail extNotification — ` +
|
|
438
|
+
`early-event buffer at MAX_EARLY_EVENT_SESSIONS ` +
|
|
439
|
+
`(${MAX_EARLY_EVENT_SESSIONS}); possible session-id fanout abuse`);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
buf = { frames: [], expiresAt: now + EARLY_EVENT_TTL_MS };
|
|
443
|
+
this.earlyEvents.set(sessionId, buf);
|
|
444
|
+
}
|
|
445
|
+
if (buf.frames.length >= MAX_EARLY_EVENTS_PER_SESSION) {
|
|
446
|
+
writeStderrLine(`qwen serve: dropping mcp guardrail extNotification ` +
|
|
447
|
+
`for session ${JSON.stringify(sessionId)} — per-session ` +
|
|
448
|
+
`cap (${MAX_EARLY_EVENTS_PER_SESSION}) reached`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
buf.frames.push(frame);
|
|
452
|
+
}
|
|
453
|
+
sweepExpiredEarlyEvents(now) {
|
|
454
|
+
for (const [sid, buf] of this.earlyEvents) {
|
|
455
|
+
if (buf.expiresAt <= now)
|
|
456
|
+
this.earlyEvents.delete(sid);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
sweepExpiredTombstones(now) {
|
|
460
|
+
for (const [sid, expiresAt] of this.tombstonedSessionIds) {
|
|
461
|
+
if (expiresAt <= now)
|
|
462
|
+
this.tombstonedSessionIds.delete(sid);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* PR 14b fix (codex round 5): mark a sessionId as closed so a late
|
|
467
|
+
* `extNotification` from the dying child can't leak into the
|
|
468
|
+
* early-event buffer. Bridge factory calls this from every
|
|
469
|
+
* `byId.delete(sid)` site (kill path, channel.exited handler,
|
|
470
|
+
* closeSession). Idempotent on already-tombstoned ids — refreshes
|
|
471
|
+
* the TTL so a recently-killed id stays dead long enough for any
|
|
472
|
+
* in-flight stale frames to expire.
|
|
473
|
+
*/
|
|
474
|
+
markSessionClosed(sessionId) {
|
|
475
|
+
const now = Date.now();
|
|
476
|
+
// PR 14b fix (codex round 7): bound `tombstonedSessionIds` under
|
|
477
|
+
// session churn. Pre-fix `sweepExpiredTombstones` was only called
|
|
478
|
+
// inside `bufferEarlyEvent`; on a daemon that closes/kills many
|
|
479
|
+
// sessions but rarely receives extNotifications (the common
|
|
480
|
+
// production pattern when MCP guardrail mode is `off`), the map
|
|
481
|
+
// grew monotonically and the documented 60s TTL didn't bound
|
|
482
|
+
// memory. Sweeping at every close is O(map size) but cheap (one
|
|
483
|
+
// integer compare per entry); under any realistic workload the
|
|
484
|
+
// map stays small.
|
|
485
|
+
this.sweepExpiredTombstones(now);
|
|
486
|
+
this.tombstonedSessionIds.set(sessionId, now + EARLY_EVENT_TTL_MS);
|
|
487
|
+
// Purge any frames already buffered for this id — they're now
|
|
488
|
+
// stale by definition (their session is dead).
|
|
489
|
+
this.earlyEvents.delete(sessionId);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* PR 14b fix (codex round 6): mark a sessionId as currently being
|
|
493
|
+
* restored via `session/load` / `session/resume`. While in this set,
|
|
494
|
+
* `bufferEarlyEvent` accepts frames for the id even if it's
|
|
495
|
+
* tombstoned — so restore-time guardrail events from the freshly-
|
|
496
|
+
* restored child reach `drainEarlyEvents` instead of being rejected
|
|
497
|
+
* by the close-window tombstone.
|
|
498
|
+
*
|
|
499
|
+
* Bridge factory calls this BEFORE awaiting the ACP restore call.
|
|
500
|
+
* `clearRestoreInFlight` is paired in the matching `finally` so a
|
|
501
|
+
* failed restore doesn't leave a dangling allow-list entry.
|
|
502
|
+
* Idempotent — safe to call repeatedly during coalesced restores.
|
|
503
|
+
*/
|
|
504
|
+
markRestoreInFlight(sessionId) {
|
|
505
|
+
this.inFlightRestoreIds.add(sessionId);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* PR 14b fix (codex round 6): companion to `markRestoreInFlight`.
|
|
509
|
+
* Bridge factory calls this when the restore IIFE settles —
|
|
510
|
+
* after `createSessionEntry` runs (success) or after the ACP
|
|
511
|
+
* restore call fails (error). After the entry is registered,
|
|
512
|
+
* `bufferEarlyEvent` is no longer reached for this id (notifications
|
|
513
|
+
* route through `entry.events.publish`), so the allow-list entry
|
|
514
|
+
* has no further effect — but cleared anyway to prevent the Set
|
|
515
|
+
* from growing forever under high restore churn.
|
|
516
|
+
*/
|
|
517
|
+
clearRestoreInFlight(sessionId) {
|
|
518
|
+
this.inFlightRestoreIds.delete(sessionId);
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* PR 14b fix #1: drain any frames buffered for `sessionId` onto
|
|
522
|
+
* `entry.events`. Bridge calls this immediately after
|
|
523
|
+
* `byId.set(sessionId, entry)` in `createSessionEntry`. The frames
|
|
524
|
+
* were captured before the entry existed (e.g. MCP discovery during
|
|
525
|
+
* the child's `newSession` handler), so draining them now lands
|
|
526
|
+
* them in the replay ring as the FIRST events of this session —
|
|
527
|
+
* SDK consumers reconnecting with `Last-Event-ID: 0` see them on
|
|
528
|
+
* their initial subscription.
|
|
529
|
+
*
|
|
530
|
+
* Public so the bridge factory can call it directly. Idempotent on
|
|
531
|
+
* unknown sessionIds.
|
|
532
|
+
*/
|
|
533
|
+
drainEarlyEvents(sessionId, entry) {
|
|
534
|
+
// PR 14b fix (codex round 5): a fresh registration clears any
|
|
535
|
+
// tombstone for this id — this is the legitimate
|
|
536
|
+
// "load/resume of a persisted session id" case. Any stale
|
|
537
|
+
// pre-tombstone frame was already rejected by `bufferEarlyEvent`
|
|
538
|
+
// above; clearing the tombstone now means subsequent
|
|
539
|
+
// notifications for this re-attached session (which is now in
|
|
540
|
+
// `byId`) flow through the normal `entry.events.publish` path.
|
|
541
|
+
this.tombstonedSessionIds.delete(sessionId);
|
|
542
|
+
const buf = this.earlyEvents.get(sessionId);
|
|
543
|
+
if (!buf)
|
|
544
|
+
return;
|
|
545
|
+
for (const frame of buf.frames)
|
|
546
|
+
entry.events.publish(frame);
|
|
547
|
+
this.earlyEvents.delete(sessionId);
|
|
548
|
+
}
|
|
549
|
+
async writeTextFile(params) {
|
|
550
|
+
// Stage 1 known divergence: this raw `fs.writeFile` reimplements file
|
|
551
|
+
// I/O instead of delegating to core's filesystem service. The
|
|
552
|
+
// user-visible scenarios where they differ:
|
|
553
|
+
// - BOM handling: this drops/re-encodes whatever the agent passed;
|
|
554
|
+
// core would preserve.
|
|
555
|
+
// - Non-UTF-8 source files: round-tripping through utf8 mangles
|
|
556
|
+
// content.
|
|
557
|
+
// - Original line endings: core preserves CRLF on Windows files;
|
|
558
|
+
// this writes whatever the agent buffered.
|
|
559
|
+
// Wiring core's FileSystemService through the bridge requires
|
|
560
|
+
// exposing it as a constructor dep; the cost-benefit is low for
|
|
561
|
+
// Stage 1 (most agent-side tools call core directly, NOT through
|
|
562
|
+
// these ACP fs methods) and Stage 2 in-process eliminates the
|
|
563
|
+
// bridge fs proxy entirely. Tracked as a Stage 2 prerequisite.
|
|
564
|
+
//
|
|
565
|
+
// BSA0D: write-then-rename so a SIGKILL / OOM mid-write doesn't
|
|
566
|
+
// leave the target truncated. POSIX `rename` is atomic within the
|
|
567
|
+
// same filesystem; on Windows it's atomic when the target doesn't
|
|
568
|
+
// exist (we tolerate the race-on-overwrite case as a Stage 2
|
|
569
|
+
// gap). The tmp file lives in the same directory so the rename
|
|
570
|
+
// can't cross filesystem boundaries (which would degrade to a
|
|
571
|
+
// copy + race re-emerges).
|
|
572
|
+
//
|
|
573
|
+
// BX8Yw: rename would replace a symlink at the target path with a
|
|
574
|
+
// regular file, leaving the original symlink target unchanged
|
|
575
|
+
// while the write appears successful. Resolve symlinks via
|
|
576
|
+
// `realpath` first so the atomic write lands at the actual file.
|
|
577
|
+
//
|
|
578
|
+
// BfFvO: dangling-symlink case — `realpath` throws ENOENT when
|
|
579
|
+
// the symlink's target doesn't exist. A blanket catch then
|
|
580
|
+
// silently falls back to `params.path` (the symlink itself), and
|
|
581
|
+
// `rename(tmp, params.path)` would replace the symlink with a
|
|
582
|
+
// regular file — exactly the bug BX8Yw was supposed to fix.
|
|
583
|
+
// Distinguish "path doesn't exist at all" (truly new file →
|
|
584
|
+
// write through) from "dangling symlink" (symlink exists, target
|
|
585
|
+
// doesn't → write through to the symlink's intended target so
|
|
586
|
+
// the symlink stays a symlink and points at a fresh file).
|
|
587
|
+
let realTarget = params.path;
|
|
588
|
+
try {
|
|
589
|
+
realTarget = await fs.realpath(params.path);
|
|
590
|
+
}
|
|
591
|
+
catch (err) {
|
|
592
|
+
const code = err && typeof err === 'object' && 'code' in err
|
|
593
|
+
? err.code
|
|
594
|
+
: undefined;
|
|
595
|
+
if (code !== 'ENOENT')
|
|
596
|
+
throw err;
|
|
597
|
+
// realpath ENOENT can mean (a) path doesn't exist at all, or
|
|
598
|
+
// (b) the path is a symlink whose target doesn't exist. Use
|
|
599
|
+
// `readlink` to disambiguate. If it succeeds we've got a
|
|
600
|
+
// dangling symlink → resolve its target manually so the
|
|
601
|
+
// subsequent rename creates the target instead of replacing
|
|
602
|
+
// the symlink.
|
|
603
|
+
try {
|
|
604
|
+
const linkTarget = await fs.readlink(params.path);
|
|
605
|
+
realTarget = path.resolve(path.dirname(params.path), linkTarget);
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
// readlink also failed → truly non-existent path → write
|
|
609
|
+
// through to the original (it'll be created).
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
// BX8Yp + BX9_h: temp filename must include random bytes —
|
|
613
|
+
// PID+ms alone collides under `sessionScope: 'thread'` (two
|
|
614
|
+
// concurrent sessions writing the same path in the same ms) AND
|
|
615
|
+
// can collide between concurrent prompts in one session. Add a
|
|
616
|
+
// UUID and create exclusively (`flag: 'wx'`) so any residual
|
|
617
|
+
// collision fails before content is overwritten.
|
|
618
|
+
const tmp = `${realTarget}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
619
|
+
// BkwQW: preserve the existing target's mode bits (and owner/group
|
|
620
|
+
// where possible) so editing a `0600` secret doesn't downgrade
|
|
621
|
+
// it to `0644` via the process umask, and an executable file
|
|
622
|
+
// doesn't lose its `+x` bit. Snapshot before write — if the
|
|
623
|
+
// target doesn't exist yet, fall through to umask defaults
|
|
624
|
+
// (which is correct for a new file).
|
|
625
|
+
let preserveMode;
|
|
626
|
+
try {
|
|
627
|
+
const targetStat = await fs.stat(realTarget);
|
|
628
|
+
preserveMode = {
|
|
629
|
+
mode: targetStat.mode & 0o7777,
|
|
630
|
+
uid: targetStat.uid,
|
|
631
|
+
gid: targetStat.gid,
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
catch (err) {
|
|
635
|
+
const code = err && typeof err === 'object' && 'code' in err
|
|
636
|
+
? err.code
|
|
637
|
+
: undefined;
|
|
638
|
+
if (code !== 'ENOENT')
|
|
639
|
+
throw err;
|
|
640
|
+
// New file — accept umask defaults.
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
// Blehd: pass `mode` to `writeFile` so the temp file is
|
|
644
|
+
// CREATED with the preserved mode (atomically, via the
|
|
645
|
+
// syscall's open(O_CREAT, mode)). The previous "create with
|
|
646
|
+
// umask defaults → chmod after" had a window where a `0600`
|
|
647
|
+
// secret-edit existed at `0644` on disk before chmod ran,
|
|
648
|
+
// briefly readable by anyone with directory access. Passing
|
|
649
|
+
// `mode` shrinks that window to "doesn't exist". On Windows
|
|
650
|
+
// the mode bits are mostly ignored by the OS; that's fine
|
|
651
|
+
// since the platform has no equivalent threat model here.
|
|
652
|
+
await fs.writeFile(tmp, params.content, {
|
|
653
|
+
encoding: 'utf8',
|
|
654
|
+
flag: 'wx',
|
|
655
|
+
mode: preserveMode?.mode ?? 0o600,
|
|
656
|
+
});
|
|
657
|
+
if (preserveMode) {
|
|
658
|
+
// `writeFile`'s `mode` option is `mode & ~umask` on POSIX,
|
|
659
|
+
// so a tight umask (e.g. operator's shell `umask 077` for
|
|
660
|
+
// 0o600 default) could still drop bits we wanted preserved.
|
|
661
|
+
// Belt-and-suspenders chmod brings the file to EXACTLY the
|
|
662
|
+
// target's preserved mode regardless of umask interference.
|
|
663
|
+
await fs.chmod(tmp, preserveMode.mode).catch(() => {
|
|
664
|
+
/* chmod failed (Windows / fs without permission bits) */
|
|
665
|
+
});
|
|
666
|
+
// chown is owner-restricted on POSIX; non-root daemons hit
|
|
667
|
+
// EPERM here. Silent ignore — preserving mode is the
|
|
668
|
+
// first-order goal, ownership is a stretch goal.
|
|
669
|
+
await fs.chown(tmp, preserveMode.uid, preserveMode.gid).catch(() => {
|
|
670
|
+
/* expected EPERM for non-root operators */
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
await fs.rename(tmp, realTarget);
|
|
674
|
+
}
|
|
675
|
+
catch (err) {
|
|
676
|
+
// Best-effort cleanup if the write succeeded but rename failed
|
|
677
|
+
// (e.g. permission change between calls). Swallow cleanup
|
|
678
|
+
// errors — the original failure is the meaningful one.
|
|
679
|
+
await fs.unlink(tmp).catch(() => { });
|
|
680
|
+
throw err;
|
|
681
|
+
}
|
|
682
|
+
return {};
|
|
683
|
+
}
|
|
684
|
+
async readTextFile(params) {
|
|
685
|
+
// Reject obviously-degenerate `limit` up front. Without this,
|
|
686
|
+
// `sliceLineRange` hits the `end < start` path and returns an
|
|
687
|
+
// unexpectedly-larger slice (or empty depending on internals).
|
|
688
|
+
// ACP doesn't define semantics for limit ≤ 0, so treat as "no
|
|
689
|
+
// bytes wanted".
|
|
690
|
+
if (typeof params.limit === 'number' && params.limit <= 0) {
|
|
691
|
+
return { content: '' };
|
|
692
|
+
}
|
|
693
|
+
// BSA0E: cap the file size we'll buffer into RSS at 100 MiB so a
|
|
694
|
+
// request like `{ line: 1, limit: 10 }` against a 500 MB log
|
|
695
|
+
// doesn't cost the daemon 500 MB of memory just to return 10
|
|
696
|
+
// lines. Stage 2's in-process refactor will replace this proxy
|
|
697
|
+
// with a streaming readline implementation that stops at the
|
|
698
|
+
// requested range; until then the cap is the cheapest defense.
|
|
699
|
+
//
|
|
700
|
+
// BX8YO: also reject non-regular files. Character devices, named
|
|
701
|
+
// pipes (FIFOs), procfs / sysfs entries, sockets etc. can report
|
|
702
|
+
// `stats.size === 0` while producing unbounded data on read, so
|
|
703
|
+
// a size-only cap doesn't protect against `/dev/zero` /
|
|
704
|
+
// `/dev/urandom` / `/proc/kcore`-style inputs. ACP's contract
|
|
705
|
+
// for `readTextFile` is "regular file"; everything else is an
|
|
706
|
+
// operator-supplied path mistake or an adversarial-prompt
|
|
707
|
+
// attempt and should fail loud.
|
|
708
|
+
const READ_FILE_SIZE_CAP = 100 * 1024 * 1024;
|
|
709
|
+
const stats = await fs.stat(params.path);
|
|
710
|
+
if (!stats.isFile()) {
|
|
711
|
+
throw new Error(`readTextFile: ${params.path} is not a regular file ` +
|
|
712
|
+
`(reported as ${describeStatKind(stats)}). ` +
|
|
713
|
+
`Pipe / device / proc-like inputs can produce unbounded data ` +
|
|
714
|
+
`and aren't supported by the bridge fs proxy.`);
|
|
715
|
+
}
|
|
716
|
+
if (stats.size > READ_FILE_SIZE_CAP) {
|
|
717
|
+
throw new Error(`readTextFile: ${params.path} is ${stats.size} bytes, ` +
|
|
718
|
+
`exceeds the ${READ_FILE_SIZE_CAP}-byte daemon cap. ` +
|
|
719
|
+
`Tail/grep externally and feed the relevant slice instead.`);
|
|
720
|
+
}
|
|
721
|
+
const content = await fs.readFile(params.path, 'utf8');
|
|
722
|
+
if (typeof params.line === 'number' || typeof params.limit === 'number') {
|
|
723
|
+
// ACP `ReadTextFileRequest.line` is 1-based per spec — clients passing
|
|
724
|
+
// `{ line: 1, limit: 2 }` mean "the first two lines", not "skip the
|
|
725
|
+
// first then take two". Convert to a 0-based slice index, clamping
|
|
726
|
+
// values < 1 to 0 to be tolerant of unusual inputs.
|
|
727
|
+
const startLine = params.line ?? 1;
|
|
728
|
+
const start = startLine > 0 ? startLine - 1 : 0;
|
|
729
|
+
const end = params.limit != null ? start + params.limit : undefined;
|
|
730
|
+
// Avoid `content.split('\n')` — allocating a per-line String[] for
|
|
731
|
+
// a 100 MB file roughly doubles the memory footprint just to
|
|
732
|
+
// extract a few lines. Manual scan walks `indexOf('\n', …)` only
|
|
733
|
+
// until the end-of-range boundary is found, then slices a single
|
|
734
|
+
// range of the original string. Stage 2 in-process replaces this
|
|
735
|
+
// proxy entirely (the bridge stops reading user fs).
|
|
736
|
+
return { content: sliceLineRange(content, start, end) };
|
|
737
|
+
}
|
|
738
|
+
return { content };
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const DEFAULT_INIT_TIMEOUT_MS = 10_000;
|
|
742
|
+
/**
|
|
743
|
+
* #4282 fold-in 2 (gpt-5.5 CV2). Bridge-race deadline for the
|
|
744
|
+
* `workspace/mcp/:server/restart` ACP extMethod. The MCP manager's
|
|
745
|
+
* per-server discovery deadline can be up to 5 minutes
|
|
746
|
+
* (`McpClientManager.MAX_DISCOVERY_TIMEOUT_MS`), so reusing
|
|
747
|
+
* `initTimeoutMs` (10s) here produced a guaranteed false-timeout for
|
|
748
|
+
* any stdio MCP server slower than 10s while the ACP child kept
|
|
749
|
+
* reconnecting in the background. The bridge race is purely a safety
|
|
750
|
+
* net against a completely wedged ACP channel; it should be at least
|
|
751
|
+
* as long as the slowest legitimate per-server discovery.
|
|
752
|
+
*/
|
|
753
|
+
const MCP_RESTART_TIMEOUT_MS = 300_000;
|
|
754
|
+
const DEFAULT_MAX_SESSIONS = 20;
|
|
755
|
+
/**
|
|
756
|
+
* Soft upper bound on `BridgeOptions.eventRingSize` to catch operator
|
|
757
|
+
* typos before they OOM the daemon. At ~500 B per `BridgeEvent` an
|
|
758
|
+
* 1 000 000-frame ring already pins ~500 MB per session — well past
|
|
759
|
+
* any realistic workload. Not a security boundary (the flag is
|
|
760
|
+
* operator-controlled), just typo defense.
|
|
761
|
+
*/
|
|
762
|
+
const MAX_EVENT_RING_SIZE = 1_000_000;
|
|
763
|
+
// Bd1yh: per-permission-request wall clock. Without this, an agent
|
|
764
|
+
// calling `requestPermission` while no SSE subscriber is connected
|
|
765
|
+
// would hang the per-session FIFO promptQueue forever (the prompt
|
|
766
|
+
// can't complete, every subsequent prompt is blocked behind it).
|
|
767
|
+
// 5 minutes is generous for "human reads UI, decides, clicks
|
|
768
|
+
// approve" while still bounded enough to recover from a wedged
|
|
769
|
+
// state. Configurable via `BridgeOptions.permissionResponseTimeoutMs`.
|
|
770
|
+
const DEFAULT_PERMISSION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
771
|
+
// Bd1z5: per-session cap on pending permissions in flight. A chatty
|
|
772
|
+
// agent making rapid `requestPermission` calls would otherwise grow
|
|
773
|
+
// `pendingPermissions` unboundedly — each entry is a UUID + closure
|
|
774
|
+
// + bus event. 64 mirrors `DEFAULT_MAX_SUBSCRIBERS` (one pending
|
|
775
|
+
// per subscriber feels like a reasonable headroom). Excess requests
|
|
776
|
+
// resolve as cancelled and emit a stderr warning so operators see
|
|
777
|
+
// the limit being hit. Configurable via
|
|
778
|
+
// `BridgeOptions.maxPendingPermissionsPerSession`.
|
|
779
|
+
const DEFAULT_MAX_PENDING_PER_SESSION = 64;
|
|
780
|
+
export function createHttpAcpBridge(opts) {
|
|
781
|
+
const defaultSessionScope = opts.sessionScope ?? 'single';
|
|
782
|
+
// `undefined` → default 20 (intentionally tight per #3803 N≈50 cliff).
|
|
783
|
+
// `0` → explicitly unlimited (operator opt-out).
|
|
784
|
+
// `Infinity` → unlimited (programmatic opt-out — accepted as a
|
|
785
|
+
// long-standing alias since the cap check is `>= max`).
|
|
786
|
+
// `NaN` / negative → throw. A typo / parse error in CLI/config
|
|
787
|
+
// silently disabling the daemon's only resource
|
|
788
|
+
// guard is fail-OPEN behavior; gpt-5.5 flagged
|
|
789
|
+
// this as critical (BRApy) — we'd rather fail
|
|
790
|
+
// boot than serve unbounded.
|
|
791
|
+
let maxSessions;
|
|
792
|
+
if (opts.maxSessions === undefined) {
|
|
793
|
+
maxSessions = DEFAULT_MAX_SESSIONS;
|
|
794
|
+
}
|
|
795
|
+
else if (Number.isNaN(opts.maxSessions)) {
|
|
796
|
+
throw new TypeError(`Invalid maxSessions: NaN. Must be a number >= 0 ` +
|
|
797
|
+
`(0 / Infinity = unlimited).`);
|
|
798
|
+
}
|
|
799
|
+
else if (opts.maxSessions < 0) {
|
|
800
|
+
throw new TypeError(`Invalid maxSessions: ${opts.maxSessions}. Must be >= 0 ` +
|
|
801
|
+
`(0 / Infinity = unlimited).`);
|
|
802
|
+
}
|
|
803
|
+
else if (opts.maxSessions === 0 || opts.maxSessions === Infinity) {
|
|
804
|
+
maxSessions = Infinity;
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
maxSessions = opts.maxSessions;
|
|
808
|
+
}
|
|
809
|
+
if (defaultSessionScope !== 'single' && defaultSessionScope !== 'thread') {
|
|
810
|
+
throw new TypeError(`Invalid sessionScope: ${JSON.stringify(defaultSessionScope)}. ` +
|
|
811
|
+
`Expected 'single' or 'thread'.`);
|
|
812
|
+
}
|
|
813
|
+
// `eventRingSize` follows the same fail-CLOSED posture as
|
|
814
|
+
// `maxSessions`: silently disabling SSE backpressure on a config
|
|
815
|
+
// typo is worse than failing to start. Unlike `maxSessions` there
|
|
816
|
+
// is NO unlimited sentinel — an unbounded ring would grow forever.
|
|
817
|
+
// Soft upper bound MAX_EVENT_RING_SIZE catches operator typos
|
|
818
|
+
// (`--event-ring-size 80000000` instead of `8000000`); at 1M
|
|
819
|
+
// frames × ~500 B/frame the per-session ceiling is already
|
|
820
|
+
// ~500 MB, well past any legitimate use.
|
|
821
|
+
const eventRingSize = opts.eventRingSize ?? DEFAULT_RING_SIZE;
|
|
822
|
+
// `Number.isInteger` already rejects NaN / Infinity / non-finite
|
|
823
|
+
// — no separate `Number.isFinite` guard needed.
|
|
824
|
+
if (!Number.isInteger(eventRingSize) ||
|
|
825
|
+
eventRingSize < 1 ||
|
|
826
|
+
eventRingSize > MAX_EVENT_RING_SIZE) {
|
|
827
|
+
throw new TypeError(`Invalid eventRingSize: ${opts.eventRingSize}. ` +
|
|
828
|
+
`Must be a positive integer in [1, ${MAX_EVENT_RING_SIZE}].`);
|
|
829
|
+
}
|
|
830
|
+
const channelFactory = opts.channelFactory ?? defaultSpawnChannelFactory;
|
|
831
|
+
// PR 14 fix (review #4247 wenshao R5 runQwenServe.ts:216): close over
|
|
832
|
+
// a per-handle env-override snapshot. Calls to `channelFactory` at
|
|
833
|
+
// spawn time receive this as the 2nd arg, so the default factory
|
|
834
|
+
// can merge into the child env without consulting any global state
|
|
835
|
+
// that another concurrent `runQwenServe()` handle might have
|
|
836
|
+
// mutated. Frozen to make accidental mutation throw rather than
|
|
837
|
+
// silently corrupt later spawns.
|
|
838
|
+
const childEnvOverrides = opts.childEnvOverrides
|
|
839
|
+
? Object.freeze({ ...opts.childEnvOverrides })
|
|
840
|
+
: Object.freeze({});
|
|
841
|
+
const initTimeoutMs = opts.initializeTimeoutMs ?? DEFAULT_INIT_TIMEOUT_MS;
|
|
842
|
+
if (initTimeoutMs <= 0) {
|
|
843
|
+
throw new TypeError(`Invalid initializeTimeoutMs: ${initTimeoutMs}. Must be > 0.`);
|
|
844
|
+
}
|
|
845
|
+
// Bd1yh + Bd1z5: per-permission deadline + per-session pending cap.
|
|
846
|
+
// 0 / Infinity / non-finite (NaN, -1) all disable — same sentinel
|
|
847
|
+
// convention as maxSessions / maxConnections.
|
|
848
|
+
const permissionTimeoutRaw = opts.permissionResponseTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
849
|
+
const permissionTimeoutMs = permissionTimeoutRaw > 0 && Number.isFinite(permissionTimeoutRaw)
|
|
850
|
+
? permissionTimeoutRaw
|
|
851
|
+
: 0; // 0 = disabled
|
|
852
|
+
const maxPendingRaw = opts.maxPendingPermissionsPerSession ?? DEFAULT_MAX_PENDING_PER_SESSION;
|
|
853
|
+
const maxPendingPerSession = maxPendingRaw > 0 && Number.isFinite(maxPendingRaw)
|
|
854
|
+
? maxPendingRaw
|
|
855
|
+
: Infinity;
|
|
856
|
+
// #3803 §02: the bound path is the canonical form `spawnOrAttach`
|
|
857
|
+
// compares incoming `workspaceCwd` against. The caller MUST pass an
|
|
858
|
+
// already-canonical value (via `canonicalizeWorkspace`). `runQwenServe`
|
|
859
|
+
// does this at boot and threads the same value into both
|
|
860
|
+
// `createHttpAcpBridge` and `createServeApp` (via
|
|
861
|
+
// `deps.boundWorkspace`); direct embeds / tests that construct the
|
|
862
|
+
// bridge themselves must call `canonicalizeWorkspace` first.
|
|
863
|
+
//
|
|
864
|
+
// Pre-fix the bridge re-canonicalized defensively here. The fix
|
|
865
|
+
// (deepseek-v4-pro review) drops the redundant `realpathSync.native`:
|
|
866
|
+
// (a) on case-insensitive / symlinked filesystems two independent
|
|
867
|
+
// `realpathSync.native` calls could theoretically disagree if the FS
|
|
868
|
+
// mutates between them (NFS transient, operator rename), landing
|
|
869
|
+
// the bridge with one canonical form while `runQwenServe` advertises
|
|
870
|
+
// another and `/capabilities` clients see `workspace_mismatch` on
|
|
871
|
+
// every POST; (b) it's a syscall removed from the boot path. The
|
|
872
|
+
// `path.isAbsolute` guard stays — it's a structural input check, not
|
|
873
|
+
// a syscall.
|
|
874
|
+
if (!path.isAbsolute(opts.boundWorkspace)) {
|
|
875
|
+
throw new TypeError(`Invalid boundWorkspace: "${opts.boundWorkspace}". Must be an ` +
|
|
876
|
+
`absolute path.`);
|
|
877
|
+
}
|
|
878
|
+
const boundWorkspace = opts.boundWorkspace;
|
|
879
|
+
const persistApprovalMode = opts.persistApprovalMode;
|
|
880
|
+
const persistDisabledTools = opts.persistDisabledTools;
|
|
881
|
+
// #3803 §02 single-workspace model: the bridge hosts AT MOST one
|
|
882
|
+
// ATTACH-AVAILABLE channel and one default attach-target entry.
|
|
883
|
+
// Multi-session multiplexing happens through `channelInfo.sessionIds`;
|
|
884
|
+
// the `defaultEntry` slot is the FIRST session created (the one a
|
|
885
|
+
// same-workspace attach under `single` scope reuses). Thread-scope
|
|
886
|
+
// sessions add to `byId` but don't displace `defaultEntry`.
|
|
887
|
+
let defaultEntry;
|
|
888
|
+
// `channelInfo` is the SINGLE attach-available channel. Cleared
|
|
889
|
+
// ONLY by the `channel.exited` handler (see below) when the OS
|
|
890
|
+
// reaps the underlying child process. Teardown initiators
|
|
891
|
+
// (`killSession` last-session-leaving, `doSpawn`-newSession-failure
|
|
892
|
+
// on an empty channel, `ensureChannel` init-failure /
|
|
893
|
+
// late-shutdown, `shutdown`) set `isDying = true` but LEAVE
|
|
894
|
+
// `channelInfo` pointing at the dying channel until OS reap — that
|
|
895
|
+
// asymmetry IS the BkUyD invariant. It lets `killAllSync` reach a
|
|
896
|
+
// mid-SIGTERM-grace channel through `aliveChannels` while a
|
|
897
|
+
// concurrent `spawnOrAttach` can already start spawning a fresh
|
|
898
|
+
// replacement (which overwrites `channelInfo` when its
|
|
899
|
+
// handshake completes). Race-aware code paths (`ensureChannel`,
|
|
900
|
+
// `killAllSync`) gate on `isDying` rather than presence; see
|
|
901
|
+
// `ChannelInfo.isDying` for the per-set-site rationale.
|
|
902
|
+
let channelInfo;
|
|
903
|
+
// tanzhenxin BkUyD: superset of `channelInfo` covering channels
|
|
904
|
+
// that are dying but not yet OS-reaped. `killSession` /
|
|
905
|
+
// `doSpawn`-newSession-failure / `shutdown` mark a channel as
|
|
906
|
+
// `isDying` and start its async kill; meanwhile a concurrent
|
|
907
|
+
// `spawnOrAttach` can spawn a FRESH channel and reassign
|
|
908
|
+
// `channelInfo`. Without this set, the dying channel becomes
|
|
909
|
+
// unreachable — a double-Ctrl+C arriving mid-grace would call
|
|
910
|
+
// `killAllSync()`, find only the fresh channel in `channelInfo`,
|
|
911
|
+
// force-kill it, and `process.exit(1)` would orphan the dying one
|
|
912
|
+
// whose SIGTERM hadn't yet completed. The set is the OS-level
|
|
913
|
+
// "still alive" source of truth: entries are added when a channel
|
|
914
|
+
// is created and removed when its `channel.exited` resolves.
|
|
915
|
+
// `killAllSync` iterates THIS set to fire SIGKILL on every alive
|
|
916
|
+
// child regardless of whether it's still the attach target.
|
|
917
|
+
const aliveChannels = new Set();
|
|
918
|
+
// Coalesces a concurrent second `ensureChannel()` call onto the
|
|
919
|
+
// first one's spawn so we never create two children for the same
|
|
920
|
+
// daemon. Cleared in the `finally` of the creator.
|
|
921
|
+
let inFlightChannelSpawn;
|
|
922
|
+
const byId = new Map();
|
|
923
|
+
// Daemon-wide pending permission table; requestIds are UUIDs so collisions
|
|
924
|
+
// across sessions are infeasible in practice.
|
|
925
|
+
const pendingPermissions = new Map();
|
|
926
|
+
const resolvedPermissions = new Map();
|
|
927
|
+
const resolvedPermissionOrder = [];
|
|
928
|
+
// Set by `shutdown()` so any in-flight `spawnOrAttach` that was
|
|
929
|
+
// dispatched on an existing connection AFTER the shutdown snapshot
|
|
930
|
+
// taken in `shutdown()` fails fast instead of creating a child the
|
|
931
|
+
// shutdown path has no more visibility into. Without this, the
|
|
932
|
+
// server.listen → bridge.shutdown ordering in `runQwenServe` leaves
|
|
933
|
+
// a window between (a) shutdown snapshotting `byId` for kills and
|
|
934
|
+
// (b) `server.close` rejecting new connections, during which a
|
|
935
|
+
// late-arriving `POST /session` slips a fresh child past cleanup.
|
|
936
|
+
let shuttingDown = false;
|
|
937
|
+
// Coalesces concurrent `spawnOrAttach` calls under single-scope and
|
|
938
|
+
// tracks in-progress thread-scope spawns for shutdown to await.
|
|
939
|
+
// Single-scope uses the workspaceKey as the dedup key (at most one
|
|
940
|
+
// entry; concurrent callers pass the `defaultEntry` check together
|
|
941
|
+
// and coalesce here). Thread-scope uses `workspaceKey#uuid` so
|
|
942
|
+
// simultaneous calls don't collide while still being awaitable from
|
|
943
|
+
// `shutdown()`.
|
|
944
|
+
const inFlightSpawns = new Map();
|
|
945
|
+
// Coalesces concurrent explicit restore calls for the same session id.
|
|
946
|
+
// `session/load` replays history through SSE and `session/resume` restores
|
|
947
|
+
// context; running either twice for the same id at the same time can
|
|
948
|
+
// duplicate history frames or race two entries into `byId`.
|
|
949
|
+
const inFlightRestores = new Map();
|
|
950
|
+
// `session/load` emits history replay as session_update notifications before
|
|
951
|
+
// the ACP request returns. Keep a temporary bus so those replay frames land in
|
|
952
|
+
// the ring, then promote the same bus into the registered SessionEntry.
|
|
953
|
+
const pendingRestoreEvents = new Map();
|
|
954
|
+
const createClientId = () => `client_${randomUUID()}`;
|
|
955
|
+
const registerClient = (entry, requestedClientId) => {
|
|
956
|
+
if (requestedClientId && entry.clientIds.has(requestedClientId)) {
|
|
957
|
+
entry.clientIds.set(requestedClientId, (entry.clientIds.get(requestedClientId) ?? 0) + 1);
|
|
958
|
+
return requestedClientId;
|
|
959
|
+
}
|
|
960
|
+
const clientId = createClientId();
|
|
961
|
+
entry.clientIds.set(clientId, 1);
|
|
962
|
+
return clientId;
|
|
963
|
+
};
|
|
964
|
+
const unregisterClient = (entry, clientId) => {
|
|
965
|
+
if (clientId === undefined)
|
|
966
|
+
return;
|
|
967
|
+
const count = entry.clientIds.get(clientId);
|
|
968
|
+
if (count === undefined)
|
|
969
|
+
return;
|
|
970
|
+
if (count <= 1) {
|
|
971
|
+
entry.clientIds.delete(clientId);
|
|
972
|
+
// Drop the last-seen entry alongside the registration ref.
|
|
973
|
+
// Otherwise a long-lived daemon servicing a churn of disconnect/
|
|
974
|
+
// reconnect clients (each picking a fresh `clientId`) would
|
|
975
|
+
// accumulate stale heartbeat timestamps for clients that no
|
|
976
|
+
// longer exist — the very leak revocation policy (PR 24) is
|
|
977
|
+
// meant to plug.
|
|
978
|
+
entry.clientLastSeenAt.delete(clientId);
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
entry.clientIds.set(clientId, count - 1);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
const resolveTrustedClientId = (entry, clientId) => {
|
|
985
|
+
if (clientId === undefined)
|
|
986
|
+
return undefined;
|
|
987
|
+
if (!entry.clientIds.has(clientId)) {
|
|
988
|
+
throw new InvalidClientIdError(entry.sessionId, clientId);
|
|
989
|
+
}
|
|
990
|
+
return clientId;
|
|
991
|
+
};
|
|
992
|
+
const resolveAnyTrustedClientId = (clientId) => {
|
|
993
|
+
for (const entry of byId.values()) {
|
|
994
|
+
if (entry.clientIds.has(clientId))
|
|
995
|
+
return clientId;
|
|
996
|
+
}
|
|
997
|
+
throw new InvalidClientIdError('unknown', clientId);
|
|
998
|
+
};
|
|
999
|
+
const registerPending = (p) => {
|
|
1000
|
+
const entry = byId.get(p.sessionId);
|
|
1001
|
+
if (!entry) {
|
|
1002
|
+
// The session was torn down (channel.exited, killSession, shutdown)
|
|
1003
|
+
// between when the agent decided to ask for permission and when the
|
|
1004
|
+
// request reached this function. There's no SessionEntry to chain
|
|
1005
|
+
// the requestId onto and no SSE bus to publish `permission_request`
|
|
1006
|
+
// — nobody can vote, so the permission would hang the agent's
|
|
1007
|
+
// `requestPermission` forever. Resolve immediately as cancelled to
|
|
1008
|
+
// unwind the agent side; matches the shutdown / killSession path.
|
|
1009
|
+
p.resolve({ outcome: { outcome: 'cancelled' } });
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
pendingPermissions.set(p.requestId, p);
|
|
1013
|
+
entry.pendingPermissionIds.add(p.requestId);
|
|
1014
|
+
};
|
|
1015
|
+
const rememberResolvedPermission = (record) => {
|
|
1016
|
+
if (!resolvedPermissions.has(record.requestId)) {
|
|
1017
|
+
resolvedPermissionOrder.push(record.requestId);
|
|
1018
|
+
}
|
|
1019
|
+
resolvedPermissions.set(record.requestId, record);
|
|
1020
|
+
while (resolvedPermissionOrder.length > MAX_RESOLVED_PERMISSION_RECORDS) {
|
|
1021
|
+
const oldest = resolvedPermissionOrder.shift();
|
|
1022
|
+
if (oldest !== undefined)
|
|
1023
|
+
resolvedPermissions.delete(oldest);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
const publishPermissionAlreadyResolved = (record) => {
|
|
1027
|
+
const entry = byId.get(record.sessionId);
|
|
1028
|
+
if (!entry)
|
|
1029
|
+
return;
|
|
1030
|
+
try {
|
|
1031
|
+
writeServeDebugLine(`permission ${JSON.stringify(record.requestId)} ` +
|
|
1032
|
+
`for session ${JSON.stringify(record.sessionId)} was already ` +
|
|
1033
|
+
'resolved; publishing duplicate-vote notification.');
|
|
1034
|
+
entry.events.publish({
|
|
1035
|
+
type: 'permission_already_resolved',
|
|
1036
|
+
data: {
|
|
1037
|
+
requestId: record.requestId,
|
|
1038
|
+
sessionId: record.sessionId,
|
|
1039
|
+
outcome: record.outcome,
|
|
1040
|
+
},
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
catch {
|
|
1044
|
+
writeServeDebugLine(`skipped duplicate-vote notification for permission ` +
|
|
1045
|
+
`${JSON.stringify(record.requestId)} during shutdown.`);
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
/** Resolve a single pending request and clean up its bookkeeping. */
|
|
1049
|
+
const resolvePending = (requestId, response, originatorClientId) => {
|
|
1050
|
+
const pending = pendingPermissions.get(requestId);
|
|
1051
|
+
if (!pending)
|
|
1052
|
+
return false;
|
|
1053
|
+
pendingPermissions.delete(requestId);
|
|
1054
|
+
const entry = byId.get(pending.sessionId);
|
|
1055
|
+
if (entry) {
|
|
1056
|
+
entry.pendingPermissionIds.delete(requestId);
|
|
1057
|
+
// Fan-out a follow-up event so other clients update their UI when the
|
|
1058
|
+
// race is decided. Best-effort — failure to publish (e.g. bus closed
|
|
1059
|
+
// mid-shutdown) doesn't block resolution.
|
|
1060
|
+
try {
|
|
1061
|
+
entry.events.publish({
|
|
1062
|
+
type: 'permission_resolved',
|
|
1063
|
+
data: { requestId, outcome: response.outcome },
|
|
1064
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
catch {
|
|
1068
|
+
/* bus closed during shutdown */
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
rememberResolvedPermission({
|
|
1072
|
+
requestId,
|
|
1073
|
+
sessionId: pending.sessionId,
|
|
1074
|
+
outcome: response.outcome,
|
|
1075
|
+
});
|
|
1076
|
+
pending.resolve(response);
|
|
1077
|
+
return true;
|
|
1078
|
+
};
|
|
1079
|
+
/**
|
|
1080
|
+
* Get-or-create the daemon's single `qwen --acp` channel (#3803 §02).
|
|
1081
|
+
* N sessions multiplex onto it via `connection.newSession()`.
|
|
1082
|
+
* Concurrent callers coalesce through `inFlightChannelSpawn` so we
|
|
1083
|
+
* never spawn two children. The returned `ChannelInfo` is shared —
|
|
1084
|
+
* the caller adds their session id to `sessionIds` and uses
|
|
1085
|
+
* `info.connection.newSession()`.
|
|
1086
|
+
*
|
|
1087
|
+
* Wires up the one-and-only `channel.exited` cleanup on first
|
|
1088
|
+
* creation so the late-arriving event tears down ALL multiplexed
|
|
1089
|
+
* sessions.
|
|
1090
|
+
*/
|
|
1091
|
+
async function ensureChannel() {
|
|
1092
|
+
// Skip a channel that's marked dying — its underlying transport is
|
|
1093
|
+
// mid-SIGTERM-or-already-dead and `connection.newSession()` on it
|
|
1094
|
+
// would either hang or land the caller with a sessionId that
|
|
1095
|
+
// immediately 404s on every follow-up.
|
|
1096
|
+
if (channelInfo && !channelInfo.isDying)
|
|
1097
|
+
return channelInfo;
|
|
1098
|
+
if (inFlightChannelSpawn)
|
|
1099
|
+
return await inFlightChannelSpawn;
|
|
1100
|
+
const promise = (async () => {
|
|
1101
|
+
const channel = await channelFactory(boundWorkspace, childEnvOverrides);
|
|
1102
|
+
const client = new BridgeClient(
|
|
1103
|
+
// BfFut: ACP today carries a sessionId on every per-session
|
|
1104
|
+
// notification / request, so the no-sessionId branch is
|
|
1105
|
+
// technically unreachable. But the channel is multi-session
|
|
1106
|
+
// (Stage 1.5 multiplex), so if ACP ever grows a no-sessionId
|
|
1107
|
+
// call we'd silently drop it on a multi-session channel
|
|
1108
|
+
// instead of throwing. Surface that ambiguity loudly.
|
|
1109
|
+
(sessionId) => {
|
|
1110
|
+
if (sessionId)
|
|
1111
|
+
return byId.get(sessionId);
|
|
1112
|
+
if (channelInfo && channelInfo.sessionIds.size > 1) {
|
|
1113
|
+
throw new Error('BridgeClient: ACP call without sessionId on a ' +
|
|
1114
|
+
'multi-session channel cannot be routed — workspace=' +
|
|
1115
|
+
boundWorkspace);
|
|
1116
|
+
}
|
|
1117
|
+
return undefined;
|
|
1118
|
+
}, (sessionId) => sessionId ? pendingRestoreEvents.get(sessionId) : undefined, registerPending, (rid) =>
|
|
1119
|
+
// Roll back a register-then-publish-failed pending so the agent
|
|
1120
|
+
// doesn't hang waiting on a vote nobody can see.
|
|
1121
|
+
resolvePending(rid, { outcome: { outcome: 'cancelled' } }), permissionTimeoutMs, maxPendingPerSession);
|
|
1122
|
+
const connection = new ClientSideConnection(() => client, channel.stream);
|
|
1123
|
+
// Add to `aliveChannels` + register the `channel.exited` handler
|
|
1124
|
+
// BEFORE the `initialize` handshake (tanzhenxin cold-spawn-window
|
|
1125
|
+
// finding): the agent child exists from the moment
|
|
1126
|
+
// `channelFactory(boundWorkspace)` returns, so a `killAllSync()`
|
|
1127
|
+
// during the handshake window (up to `initTimeoutMs`, default
|
|
1128
|
+
// 10s) must find it to avoid orphaning on `process.exit(1)`.
|
|
1129
|
+
// Init-failure / child-crash / late-shutdown all converge on
|
|
1130
|
+
// the same cleanup path via the handler below.
|
|
1131
|
+
// `channelInfo` (the attach target) is assigned only AFTER
|
|
1132
|
+
// initialize succeeds so callers don't attach to a still-
|
|
1133
|
+
// handshaking channel.
|
|
1134
|
+
const info = {
|
|
1135
|
+
channel,
|
|
1136
|
+
connection,
|
|
1137
|
+
client,
|
|
1138
|
+
sessionIds: new Set(),
|
|
1139
|
+
pendingRestoreIds: new Set(),
|
|
1140
|
+
isDying: false,
|
|
1141
|
+
};
|
|
1142
|
+
aliveChannels.add(info);
|
|
1143
|
+
// Belt-and-suspenders leak detection. The set is intentionally
|
|
1144
|
+
// multi-entry to cover the `killSession`-then-`spawnOrAttach`
|
|
1145
|
+
// overlap window (size 2 is legitimate: one dying + one fresh
|
|
1146
|
+
// attach-target). Anything higher implies a `channel.exited`
|
|
1147
|
+
// handler never fired for some prior channel — a real leak we'd
|
|
1148
|
+
// otherwise notice only as gradually-growing RSS over hours.
|
|
1149
|
+
// The warning surfaces it the moment it happens. Threshold is
|
|
1150
|
+
// 2 because that's the design ceiling; bumping it requires
|
|
1151
|
+
// updating both this guard and the comments around
|
|
1152
|
+
// `aliveChannels` declaration.
|
|
1153
|
+
if (aliveChannels.size > 2) {
|
|
1154
|
+
writeStderrLine(`qwen serve: WARNING aliveChannels.size=${aliveChannels.size} ` +
|
|
1155
|
+
`(expected 1, max 2 during killSession-then-spawnOrAttach ` +
|
|
1156
|
+
`overlap) — possible channel leak; check that prior channels' ` +
|
|
1157
|
+
`channel.exited fired and the handler ran cleanup.`);
|
|
1158
|
+
}
|
|
1159
|
+
// One-time channel.exited cleanup. The child dying takes ALL
|
|
1160
|
+
// multiplexed sessions with it — iterate `sessionIds` (snapshot
|
|
1161
|
+
// first to be safe against concurrent killSession during
|
|
1162
|
+
// iteration), publish `session_died` on each session's bus,
|
|
1163
|
+
// remove from byId / defaultEntry / pending tables.
|
|
1164
|
+
//
|
|
1165
|
+
// Registered BEFORE the `initialize` await (tanzhenxin
|
|
1166
|
+
// cold-spawn-window fix above) so init-failure / child-crash /
|
|
1167
|
+
// late-shutdown all converge here. During handshake
|
|
1168
|
+
// `sessionIds` is empty — the loop below no-ops, the stderr
|
|
1169
|
+
// line still fires to tell operators "agent process gone
|
|
1170
|
+
// during init", and `aliveChannels.delete(info)` clears the
|
|
1171
|
+
// entry through the normal exit path.
|
|
1172
|
+
//
|
|
1173
|
+
// tanzhenxin BkUyD: drop from `aliveChannels` ONLY when the OS
|
|
1174
|
+
// process is actually gone. Async kill paths (`killSession`
|
|
1175
|
+
// reap, `shutdown()` await, `doSpawn`'s newSession-failure
|
|
1176
|
+
// tear-down) mark `isDying = true` but leave the entry in
|
|
1177
|
+
// `aliveChannels` until this handler fires, so the double-Ctrl+C
|
|
1178
|
+
// `killAllSync` force-kill path still has a reference to fire
|
|
1179
|
+
// SIGKILL against during the SIGTERM grace window — even if a
|
|
1180
|
+
// concurrent `spawnOrAttach` has already reassigned
|
|
1181
|
+
// `channelInfo` to a fresh channel.
|
|
1182
|
+
void channel.exited.then((exitInfo) => {
|
|
1183
|
+
aliveChannels.delete(info);
|
|
1184
|
+
if (channelInfo === info)
|
|
1185
|
+
channelInfo = undefined;
|
|
1186
|
+
const sessions = Array.from(info.sessionIds);
|
|
1187
|
+
info.sessionIds.clear();
|
|
1188
|
+
// Operator breadcrumb for UNEXPECTED channel exits. Without
|
|
1189
|
+
// this an agent crash (OOM / segfault) is invisible from the
|
|
1190
|
+
// daemon log: each affected SSE subscriber sees a
|
|
1191
|
+
// `session_died` frame and disconnects, the daemon's
|
|
1192
|
+
// child-stderr forwarder emits whatever the child wrote before
|
|
1193
|
+
// dying (often nothing on a SIGKILL / segfault), and operators
|
|
1194
|
+
// can't tell from `qwen serve`'s own output that the agent
|
|
1195
|
+
// process is gone.
|
|
1196
|
+
//
|
|
1197
|
+
// Suppressed during `shuttingDown` because the operator
|
|
1198
|
+
// already saw "received SIGINT, draining..." from
|
|
1199
|
+
// `runQwenServe`'s signal handler. The standalone
|
|
1200
|
+
// killSession case (last session leaves, channel torn down
|
|
1201
|
+
// but daemon stays up) still logs — there's no upstream
|
|
1202
|
+
// context line in that flow, and the message confirms the
|
|
1203
|
+
// cleanup actually ran.
|
|
1204
|
+
if (!shuttingDown) {
|
|
1205
|
+
writeStderrLine(`qwen serve: channel exited (code=${exitInfo?.exitCode ?? 'none'}, signal=${exitInfo?.signalCode ?? 'none'}, ${sessions.length} session(s) torn down)`);
|
|
1206
|
+
}
|
|
1207
|
+
for (const sid of sessions) {
|
|
1208
|
+
const sessEntry = byId.get(sid);
|
|
1209
|
+
if (!sessEntry)
|
|
1210
|
+
continue;
|
|
1211
|
+
cancelPendingForSession(sid);
|
|
1212
|
+
try {
|
|
1213
|
+
sessEntry.events.publish({
|
|
1214
|
+
type: 'session_died',
|
|
1215
|
+
data: {
|
|
1216
|
+
sessionId: sid,
|
|
1217
|
+
reason: 'channel_closed',
|
|
1218
|
+
// BX9_P: thread exitCode/signalCode through.
|
|
1219
|
+
exitCode: exitInfo?.exitCode ?? null,
|
|
1220
|
+
signalCode: exitInfo?.signalCode ?? null,
|
|
1221
|
+
},
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
catch {
|
|
1225
|
+
/* bus already closed */
|
|
1226
|
+
}
|
|
1227
|
+
byId.delete(sid);
|
|
1228
|
+
// PR 14b fix (codex round 5): tombstone the id so any
|
|
1229
|
+
// late `extNotification` from the dying child can't leak
|
|
1230
|
+
// into the early-event buffer for a future load/resume of
|
|
1231
|
+
// the same persisted session id.
|
|
1232
|
+
info.client.markSessionClosed(sid);
|
|
1233
|
+
if (defaultEntry === sessEntry)
|
|
1234
|
+
defaultEntry = undefined;
|
|
1235
|
+
sessEntry.events.close();
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
// Initialize handshake. The channel is already in
|
|
1239
|
+
// `aliveChannels` and the `channel.exited` handler above is
|
|
1240
|
+
// registered, so failure paths (init throw, timeout, late
|
|
1241
|
+
// shutdown) only need to mark dying + kill — the handler does
|
|
1242
|
+
// the alive-set cleanup when the OS reaps the child.
|
|
1243
|
+
try {
|
|
1244
|
+
await withTimeout(connection.initialize({
|
|
1245
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
1246
|
+
clientCapabilities: {
|
|
1247
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
1248
|
+
},
|
|
1249
|
+
clientInfo: { name: 'qwen-serve-bridge', version: '0' },
|
|
1250
|
+
}), initTimeoutMs, 'initialize');
|
|
1251
|
+
}
|
|
1252
|
+
catch (err) {
|
|
1253
|
+
// Mark the half-initialized channel as dying/unavailable, then
|
|
1254
|
+
// kill it. Coalesced callers (`inFlightChannelSpawn` branch in
|
|
1255
|
+
// `ensureChannel`) observe the same rejection on this promise
|
|
1256
|
+
// and propagate it to their callers; the `inFlightSpawns`
|
|
1257
|
+
// tracker is cleared in `spawnOrAttach`'s finally so a follow-
|
|
1258
|
+
// up call retries cleanly. The `channel.exited` handler
|
|
1259
|
+
// registered earlier removes `info` from `aliveChannels` once
|
|
1260
|
+
// the OS reaps the child. `isDying` here is the cross-path
|
|
1261
|
+
// invariant marker (matches `killSession` / `doSpawn`-
|
|
1262
|
+
// newSession-failure / `shutdown`): "any channel in
|
|
1263
|
+
// `aliveChannels` with `isDying === true` is mid-teardown."
|
|
1264
|
+
info.isDying = true;
|
|
1265
|
+
await channel.kill().catch(() => { });
|
|
1266
|
+
throw err;
|
|
1267
|
+
}
|
|
1268
|
+
// Late-shutdown re-check: if shutdown flipped during the
|
|
1269
|
+
// handshake, tear this channel down rather than leak past
|
|
1270
|
+
// `process.exit(0)`. Same cleanup pattern as the init-failure
|
|
1271
|
+
// path: mark dying + kill, let the exited handler reap.
|
|
1272
|
+
if (shuttingDown) {
|
|
1273
|
+
info.isDying = true;
|
|
1274
|
+
await channel.kill().catch(() => { });
|
|
1275
|
+
throw new Error('HttpAcpBridge is shutting down');
|
|
1276
|
+
}
|
|
1277
|
+
// Handshake succeeded — now publish the channel as the
|
|
1278
|
+
// attach-available slot. `channelInfo` is assigned LAST so
|
|
1279
|
+
// `ensureChannel`'s fast-path (`if (channelInfo && !.isDying)`)
|
|
1280
|
+
// never returns a still-handshaking channel to a concurrent
|
|
1281
|
+
// caller.
|
|
1282
|
+
channelInfo = info;
|
|
1283
|
+
return info;
|
|
1284
|
+
})();
|
|
1285
|
+
inFlightChannelSpawn = promise;
|
|
1286
|
+
try {
|
|
1287
|
+
return await promise;
|
|
1288
|
+
}
|
|
1289
|
+
finally {
|
|
1290
|
+
inFlightChannelSpawn = undefined;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
async function doSpawn(modelServiceId, effectiveScope, requestedClientId) {
|
|
1294
|
+
// #3803 §02: get-or-create the daemon's single channel, then call
|
|
1295
|
+
// `connection.newSession()` on it. Sessions share the child's
|
|
1296
|
+
// process / OAuth / file-cache / hierarchy-memory parse via the
|
|
1297
|
+
// agent's `sessions: Map<string, Session>` (see
|
|
1298
|
+
// `acp-integration/acpAgent.ts:194`).
|
|
1299
|
+
//
|
|
1300
|
+
// newSession on an established channel can fail (auth, config,
|
|
1301
|
+
// etc.) without the channel dying. We DON'T kill the channel on
|
|
1302
|
+
// newSession failure when OTHER sessions are still using it —
|
|
1303
|
+
// they'd lose their work for a problem orthogonal to them.
|
|
1304
|
+
//
|
|
1305
|
+
// BkwQA: when the failed newSession was the channel's ONLY
|
|
1306
|
+
// attempt (sessionIds.size === 0), the empty channel must NOT
|
|
1307
|
+
// linger — it would stay set as `channelInfo` invisible to
|
|
1308
|
+
// `sessionCount` / `maxSessions` (both backed by `byId`), and
|
|
1309
|
+
// repeated failing creates would still find this channel via
|
|
1310
|
+
// `ensureChannel`, never spawning a fresh one. Tear down the
|
|
1311
|
+
// empty channel so the next attempt gets a clean spawn.
|
|
1312
|
+
const ci = await ensureChannel();
|
|
1313
|
+
let newSessionResp;
|
|
1314
|
+
try {
|
|
1315
|
+
newSessionResp = await withTimeout(ci.connection.newSession({
|
|
1316
|
+
cwd: boundWorkspace,
|
|
1317
|
+
mcpServers: [],
|
|
1318
|
+
}), initTimeoutMs, 'newSession');
|
|
1319
|
+
}
|
|
1320
|
+
catch (err) {
|
|
1321
|
+
// Only reap when this newSession was the channel's first/only
|
|
1322
|
+
// attempt — a populated channel keeps running for its other
|
|
1323
|
+
// live sessions.
|
|
1324
|
+
if (ci.sessionIds.size === 0) {
|
|
1325
|
+
// Mark dying SYNCHRONOUSLY so a concurrent `spawnOrAttach`
|
|
1326
|
+
// calling `ensureChannel()` between this point and the
|
|
1327
|
+
// `channel.exited` cleanup spawns a fresh channel instead of
|
|
1328
|
+
// attaching to the one we're about to tear down. `channelInfo`
|
|
1329
|
+
// stays set until OS reap so `killAllSync` mid-SIGTERM still
|
|
1330
|
+
// finds a target (tanzhenxin BkUyD invariant).
|
|
1331
|
+
ci.isDying = true;
|
|
1332
|
+
await ci.channel.kill().catch(() => {
|
|
1333
|
+
/* best-effort — channel.exited handler still runs */
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
throw err;
|
|
1337
|
+
}
|
|
1338
|
+
// Late-shutdown re-check (BUy4U): shutdown() may have flipped
|
|
1339
|
+
// while we were in `connection.newSession` (~1s on cold start).
|
|
1340
|
+
if (shuttingDown) {
|
|
1341
|
+
// Don't kill the channel — see comment above. Just throw.
|
|
1342
|
+
throw new Error('HttpAcpBridge is shutting down');
|
|
1343
|
+
}
|
|
1344
|
+
const entry = createSessionEntry(ci, newSessionResp.sessionId, boundWorkspace);
|
|
1345
|
+
const clientId = registerClient(entry, requestedClientId);
|
|
1346
|
+
// `defaultEntry` is the single-scope attach target — only sessions
|
|
1347
|
+
// SPAWNED UNDER `'single'` may claim it. A thread-scope spawn must
|
|
1348
|
+
// never become the attach target, otherwise a later omitted-scope
|
|
1349
|
+
// (or daemon-default-`single`) caller would attach with
|
|
1350
|
+
// `attached: true` to what its sender promised was an isolated
|
|
1351
|
+
// session — see #4175 PR 5 (mixed-scope leak found in review).
|
|
1352
|
+
// Subsequent same-scope spawns also don't overwrite (first wins).
|
|
1353
|
+
if (effectiveScope === 'single' && !defaultEntry)
|
|
1354
|
+
defaultEntry = entry;
|
|
1355
|
+
// ACP `newSession` doesn't take a model id; honor the caller's
|
|
1356
|
+
// `modelServiceId` via `unstable_setSessionModel`. See
|
|
1357
|
+
// `applyModelServiceId` for rationale (race against
|
|
1358
|
+
// transportClosedReject, publish model_switched on success,
|
|
1359
|
+
// model_switch_failed on failure, don't tear down the session).
|
|
1360
|
+
if (modelServiceId) {
|
|
1361
|
+
await applyModelServiceId(entry, modelServiceId, initTimeoutMs, clientId).catch(() => {
|
|
1362
|
+
// Already published `model_switch_failed`; session stays
|
|
1363
|
+
// operational on the agent's default model.
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
// Bd1zc: re-check that the entry is still live before returning.
|
|
1367
|
+
// The model-switch call yields and races against
|
|
1368
|
+
// `channel.exited` — if the child crashed during the model
|
|
1369
|
+
// switch, the exited handler already removed the entry from
|
|
1370
|
+
// byId. Without this check, the caller would get HTTP 200 with
|
|
1371
|
+
// a sessionId that already 404s on every subsequent request.
|
|
1372
|
+
if (!byId.has(entry.sessionId)) {
|
|
1373
|
+
throw new Error(`Session ${entry.sessionId} died during model-switch ` +
|
|
1374
|
+
`initialization`);
|
|
1375
|
+
}
|
|
1376
|
+
return {
|
|
1377
|
+
sessionId: entry.sessionId,
|
|
1378
|
+
workspaceCwd: entry.workspaceCwd,
|
|
1379
|
+
attached: false,
|
|
1380
|
+
clientId,
|
|
1381
|
+
createdAt: entry.createdAt,
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Send `unstable_setSessionModel` and broadcast a `model_switched`
|
|
1386
|
+
* event. Used at create-session time (via doSpawn) AND on attach when
|
|
1387
|
+
* the caller passes a modelServiceId — the existing session may be
|
|
1388
|
+
* running a different model.
|
|
1389
|
+
*
|
|
1390
|
+
* Serialized through `entry.modelChangeQueue` so two concurrent
|
|
1391
|
+
* attach-with-different-model requests can't race into the agent.
|
|
1392
|
+
* On failure, publishes a `model_switch_failed` event for cross-client
|
|
1393
|
+
* observability and re-throws so the HTTP caller sees the error
|
|
1394
|
+
* (session keeps running its previous model — that's the safer
|
|
1395
|
+
* default than tearing down a shared session because one client
|
|
1396
|
+
* asked for an unknown model).
|
|
1397
|
+
*/
|
|
1398
|
+
async function applyModelServiceId(entry, modelId, timeoutMs, originatorClientId) {
|
|
1399
|
+
const conn = entry.connection;
|
|
1400
|
+
// Race against `transportClosedReject` so a child crash during
|
|
1401
|
+
// model switch fails the call immediately instead of waiting the
|
|
1402
|
+
// full `timeoutMs`. Matches what `sendPrompt` and `setSessionModel`
|
|
1403
|
+
// already do — without this, a callback-attach with a broken model
|
|
1404
|
+
// wedges the HTTP handler for 10s.
|
|
1405
|
+
const transportClosed = getTransportClosedReject(entry);
|
|
1406
|
+
const work = entry.modelChangeQueue.then(async () => {
|
|
1407
|
+
try {
|
|
1408
|
+
await Promise.race([
|
|
1409
|
+
withTimeout(conn.unstable_setSessionModel({
|
|
1410
|
+
sessionId: entry.sessionId,
|
|
1411
|
+
modelId,
|
|
1412
|
+
}), timeoutMs, 'setSessionModel'),
|
|
1413
|
+
transportClosed,
|
|
1414
|
+
]);
|
|
1415
|
+
entry.events.publish({
|
|
1416
|
+
type: 'model_switched',
|
|
1417
|
+
data: { sessionId: entry.sessionId, modelId },
|
|
1418
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
catch (err) {
|
|
1422
|
+
// Surface the failure to ALL attached clients, not just the
|
|
1423
|
+
// caller — a shared session swallowing a denied model change
|
|
1424
|
+
// silently would surprise the others.
|
|
1425
|
+
entry.events.publish({
|
|
1426
|
+
type: 'model_switch_failed',
|
|
1427
|
+
data: {
|
|
1428
|
+
sessionId: entry.sessionId,
|
|
1429
|
+
requestedModelId: modelId,
|
|
1430
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1431
|
+
},
|
|
1432
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
1433
|
+
});
|
|
1434
|
+
throw err;
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
// Tail swallows failures so subsequent model changes still run; the
|
|
1438
|
+
// original caller still observes the rejection on `work`.
|
|
1439
|
+
entry.modelChangeQueue = work.then(() => undefined, () => undefined);
|
|
1440
|
+
return work;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Resolve every pending request belonging to one session as cancelled.
|
|
1444
|
+
*
|
|
1445
|
+
* **Scope contract (per ACP spec / live-collab default):**
|
|
1446
|
+
* Permissions are issued by the agent inline DURING an active
|
|
1447
|
+
* prompt — `requestPermission` returns a Promise the agent awaits
|
|
1448
|
+
* before continuing. Per the bridge's per-session FIFO + ACP's
|
|
1449
|
+
* "one active prompt per session" guarantee, ALL outstanding
|
|
1450
|
+
* permissions at any moment belong to the **currently active
|
|
1451
|
+
* prompt**. So "cancel all pending permissions for this session"
|
|
1452
|
+
* is equivalent to "cancel the active prompt's permissions" — and
|
|
1453
|
+
* that's exactly what ACP requires when a prompt is cancelled
|
|
1454
|
+
* ("cancelling a prompt MUST resolve outstanding requestPermission
|
|
1455
|
+
* calls with outcome.cancelled").
|
|
1456
|
+
*
|
|
1457
|
+
* **Multi-client live-collab caveat:** under `sessionScope: 'single'`
|
|
1458
|
+
* Client B may have been about to vote on A's pending permission
|
|
1459
|
+
* via SSE — when A disconnects mid-prompt, B's vote (if it arrives
|
|
1460
|
+
* after the abort) gets `404`. This is the right behavior: A's
|
|
1461
|
+
* prompt is being cancelled, so the permission belongs to a turn
|
|
1462
|
+
* that no longer matters. From B's side they see
|
|
1463
|
+
* `permission_resolved` with `outcome: cancelled` on the SSE
|
|
1464
|
+
* stream, then the prompt's `cancelled` stop reason. Voting on a
|
|
1465
|
+
* cancelled-prompt's permission was never going to drive the
|
|
1466
|
+
* agent forward anyway.
|
|
1467
|
+
*/
|
|
1468
|
+
const cancelPendingForSession = (sessionId) => {
|
|
1469
|
+
const entry = byId.get(sessionId);
|
|
1470
|
+
if (!entry)
|
|
1471
|
+
return;
|
|
1472
|
+
// Snapshot ids — resolvePending mutates the underlying set.
|
|
1473
|
+
const ids = Array.from(entry.pendingPermissionIds);
|
|
1474
|
+
for (const id of ids) {
|
|
1475
|
+
resolvePending(id, { outcome: { outcome: 'cancelled' } });
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
/**
|
|
1479
|
+
* Lazy-init the per-session `transportClosedReject` promise that
|
|
1480
|
+
* `sendPrompt` / `setSessionModel` / `applyModelServiceId` race their
|
|
1481
|
+
* ACP calls against. ONE listener is attached to `channel.exited`
|
|
1482
|
+
* over the session's lifetime (the first caller "wins" and creates
|
|
1483
|
+
* the promise; subsequent callers reuse it) — a per-call attach
|
|
1484
|
+
* would grow Node's listener list linearly with prompt count on
|
|
1485
|
+
* chatty sessions. The rejection message names the FIRST caller,
|
|
1486
|
+
* which can be misleading if a later method observes the failure;
|
|
1487
|
+
* the cost-benefit favors the single-listener invariant.
|
|
1488
|
+
*/
|
|
1489
|
+
const getTransportClosedReject = (entry) => {
|
|
1490
|
+
if (!entry.transportClosedReject) {
|
|
1491
|
+
entry.transportClosedReject = entry.channel.exited.then(() => {
|
|
1492
|
+
throw new BridgeChannelClosedError(`mid-request (session ${entry.sessionId})`);
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
return entry.transportClosedReject;
|
|
1496
|
+
};
|
|
1497
|
+
const resolveWorkspaceKey = (workspaceCwd) => {
|
|
1498
|
+
if (!path.isAbsolute(workspaceCwd)) {
|
|
1499
|
+
throw new Error(`workspaceCwd must be an absolute path; got "${workspaceCwd}"`);
|
|
1500
|
+
}
|
|
1501
|
+
const workspaceKey = workspaceCwd === boundWorkspace
|
|
1502
|
+
? boundWorkspace
|
|
1503
|
+
: canonicalizeWorkspace(workspaceCwd);
|
|
1504
|
+
if (workspaceKey !== boundWorkspace) {
|
|
1505
|
+
throw new WorkspaceMismatchError(boundWorkspace, workspaceKey);
|
|
1506
|
+
}
|
|
1507
|
+
return workspaceKey;
|
|
1508
|
+
};
|
|
1509
|
+
const liveChannelInfo = () => {
|
|
1510
|
+
if (!channelInfo || channelInfo.isDying)
|
|
1511
|
+
return undefined;
|
|
1512
|
+
return channelInfo;
|
|
1513
|
+
};
|
|
1514
|
+
const channelInfoForEntry = (entry) => findChannelInfoForEntry(channelInfo, aliveChannels, entry);
|
|
1515
|
+
const getChannelClosedReject = (info) => {
|
|
1516
|
+
if (!info.statusClosedReject) {
|
|
1517
|
+
info.statusClosedReject = info.channel.exited.then(() => {
|
|
1518
|
+
throw new BridgeChannelClosedError('mid-request (workspace status)');
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
return info.statusClosedReject;
|
|
1522
|
+
};
|
|
1523
|
+
const requestWorkspaceStatus = async (method, idle) => {
|
|
1524
|
+
const info = liveChannelInfo();
|
|
1525
|
+
if (!info)
|
|
1526
|
+
return idle();
|
|
1527
|
+
const response = await withTimeout(Promise.race([
|
|
1528
|
+
info.connection.extMethod(method, { cwd: boundWorkspace }),
|
|
1529
|
+
getChannelClosedReject(info),
|
|
1530
|
+
]), initTimeoutMs, method);
|
|
1531
|
+
return response;
|
|
1532
|
+
};
|
|
1533
|
+
const requestSessionStatus = async (sessionId, method) => {
|
|
1534
|
+
const entry = byId.get(sessionId);
|
|
1535
|
+
if (!entry)
|
|
1536
|
+
throw new SessionNotFoundError(sessionId);
|
|
1537
|
+
const info = channelInfoForEntry(entry);
|
|
1538
|
+
if (!info || info.isDying)
|
|
1539
|
+
throw new SessionNotFoundError(sessionId);
|
|
1540
|
+
const response = await Promise.race([
|
|
1541
|
+
withTimeout(entry.connection.extMethod(method, { sessionId }), initTimeoutMs, method),
|
|
1542
|
+
getTransportClosedReject(entry),
|
|
1543
|
+
]);
|
|
1544
|
+
return response;
|
|
1545
|
+
};
|
|
1546
|
+
/**
|
|
1547
|
+
* Fan-out an event to every live session bus. PR 17 mutation events
|
|
1548
|
+
* (`tool_toggled`, `workspace_initialized`, `mcp_server_restart*`)
|
|
1549
|
+
* call this; semantically identical to PR 16's
|
|
1550
|
+
* `publishWorkspaceEvent` member on the bridge object (same
|
|
1551
|
+
* `byId.values()` iteration, same per-entry try/catch posture).
|
|
1552
|
+
* Kept as a local closure alias rather than a member method because
|
|
1553
|
+
* call sites within the bridge implementation can't invoke own
|
|
1554
|
+
* methods through `this` here. PR 16's richer success/failure
|
|
1555
|
+
* accounting (per-entry shutdown/debug logging) lives only on the
|
|
1556
|
+
* member version — these PR 17 events are best-effort, so the
|
|
1557
|
+
* simpler swallow-and-skip is acceptable.
|
|
1558
|
+
*/
|
|
1559
|
+
const broadcastWorkspaceEvent = (envelope) => {
|
|
1560
|
+
for (const entry of byId.values()) {
|
|
1561
|
+
try {
|
|
1562
|
+
entry.events.publish(envelope);
|
|
1563
|
+
}
|
|
1564
|
+
catch {
|
|
1565
|
+
/* bus closed for this session; skip */
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
const createSessionEntry = (ci, sessionId, workspaceCwd, events = new EventBus(eventRingSize)) => {
|
|
1570
|
+
const entry = {
|
|
1571
|
+
sessionId,
|
|
1572
|
+
workspaceCwd,
|
|
1573
|
+
createdAt: new Date().toISOString(),
|
|
1574
|
+
channel: ci.channel,
|
|
1575
|
+
connection: ci.connection,
|
|
1576
|
+
events,
|
|
1577
|
+
promptQueue: Promise.resolve(),
|
|
1578
|
+
modelChangeQueue: Promise.resolve(),
|
|
1579
|
+
pendingPermissionIds: new Set(),
|
|
1580
|
+
clientIds: new Map(),
|
|
1581
|
+
clientLastSeenAt: new Map(),
|
|
1582
|
+
attachCount: 0,
|
|
1583
|
+
spawnOwnerWantedKill: false,
|
|
1584
|
+
};
|
|
1585
|
+
ci.sessionIds.add(entry.sessionId);
|
|
1586
|
+
byId.set(entry.sessionId, entry);
|
|
1587
|
+
// PR 14b fix #1 (codex review round 1): drain any guardrail
|
|
1588
|
+
// events that fired during this session's `newSession` handler
|
|
1589
|
+
// (before this entry registered) onto the freshly-created
|
|
1590
|
+
// EventBus. Idempotent on unknown sessionIds.
|
|
1591
|
+
ci.client.drainEarlyEvents(entry.sessionId, entry);
|
|
1592
|
+
return entry;
|
|
1593
|
+
};
|
|
1594
|
+
const isAcpSessionResourceNotFound = (err, sessionId) => {
|
|
1595
|
+
if (!err || typeof err !== 'object')
|
|
1596
|
+
return false;
|
|
1597
|
+
const maybe = err;
|
|
1598
|
+
if (maybe.code !== -32002)
|
|
1599
|
+
return false;
|
|
1600
|
+
const expectedUri = `session:${sessionId}`;
|
|
1601
|
+
if (maybe.data &&
|
|
1602
|
+
typeof maybe.data === 'object' &&
|
|
1603
|
+
maybe.data.uri === expectedUri) {
|
|
1604
|
+
return true;
|
|
1605
|
+
}
|
|
1606
|
+
// Fallback for ACP servers that omit `data.uri` and embed the
|
|
1607
|
+
// URI in the human-readable message. Use exact equality on the
|
|
1608
|
+
// canonical "Resource not found: <uri>" form rather than
|
|
1609
|
+
// `includes(expectedUri)` — a substring match would cause a
|
|
1610
|
+
// sessionId of `"a"` to falsely match a message containing
|
|
1611
|
+
// `"session:abc"`.
|
|
1612
|
+
return (typeof maybe.message === 'string' &&
|
|
1613
|
+
maybe.message === `Resource not found: ${expectedUri}`);
|
|
1614
|
+
};
|
|
1615
|
+
async function restoreSession(action, req) {
|
|
1616
|
+
if (shuttingDown) {
|
|
1617
|
+
throw new Error('HttpAcpBridge is shutting down');
|
|
1618
|
+
}
|
|
1619
|
+
const workspaceKey = resolveWorkspaceKey(req.workspaceCwd);
|
|
1620
|
+
const existing = byId.get(req.sessionId);
|
|
1621
|
+
if (existing) {
|
|
1622
|
+
existing.attachCount++;
|
|
1623
|
+
const clientId = registerClient(existing, req.clientId);
|
|
1624
|
+
return {
|
|
1625
|
+
sessionId: existing.sessionId,
|
|
1626
|
+
workspaceCwd: existing.workspaceCwd,
|
|
1627
|
+
attached: true,
|
|
1628
|
+
clientId,
|
|
1629
|
+
createdAt: existing.createdAt,
|
|
1630
|
+
// Late attachers get the same ACP state the original restore
|
|
1631
|
+
// caller saw; spawn-only sessions don't carry a state payload.
|
|
1632
|
+
state: existing.restoreState ?? {},
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
const inFlight = inFlightRestores.get(req.sessionId);
|
|
1636
|
+
if (inFlight) {
|
|
1637
|
+
// Cross-action races BOTH ways must reject. A `resume` arriving
|
|
1638
|
+
// while a `load` is in flight cannot quietly coalesce: the load
|
|
1639
|
+
// is replaying full history through SSE on a shared EventBus,
|
|
1640
|
+
// and `DaemonSessionClient.resume()` seeds `lastEventId: 0`,
|
|
1641
|
+
// which means the resume client would receive every replayed
|
|
1642
|
+
// frame — directly violating resume's "no UI replay" contract.
|
|
1643
|
+
// The mirror direction (`load` onto `resume`) is rejected for
|
|
1644
|
+
// the same reason: a load caller expects history but resume
|
|
1645
|
+
// didn't replay any. Same-action coalescing is unaffected.
|
|
1646
|
+
if (action !== inFlight.action) {
|
|
1647
|
+
throw new RestoreInProgressError(req.sessionId, inFlight.action, action);
|
|
1648
|
+
}
|
|
1649
|
+
// Reserve the attach SYNCHRONOUSLY before awaiting so the spawn
|
|
1650
|
+
// owner's `requireZeroAttaches` disconnect-reaper observes our
|
|
1651
|
+
// intent. The IIFE folds this counter into `entry.attachCount`
|
|
1652
|
+
// at `createSessionEntry` time.
|
|
1653
|
+
inFlight.coalesceState.count++;
|
|
1654
|
+
let restored;
|
|
1655
|
+
try {
|
|
1656
|
+
restored = await inFlight.promise;
|
|
1657
|
+
}
|
|
1658
|
+
catch (err) {
|
|
1659
|
+
// Roll back our reservation so a subsequent retry isn't
|
|
1660
|
+
// permanently skewed if the in-flight restore failed.
|
|
1661
|
+
inFlight.coalesceState.count--;
|
|
1662
|
+
throw err;
|
|
1663
|
+
}
|
|
1664
|
+
const entry = byId.get(restored.sessionId);
|
|
1665
|
+
if (!entry) {
|
|
1666
|
+
// Restore owner's session got reaped before our await
|
|
1667
|
+
// resumed (channel died mid-microtask, etc). Roll back the
|
|
1668
|
+
// reservation too — there's no entry for it to live on.
|
|
1669
|
+
inFlight.coalesceState.count--;
|
|
1670
|
+
throw new SessionNotFoundError(restored.sessionId, 'the agent child likely crashed during session restore — retry to restore the session');
|
|
1671
|
+
}
|
|
1672
|
+
// NOTE: do NOT bump entry.attachCount here — `createSessionEntry`
|
|
1673
|
+
// already initialized it from coalesceState.count synchronously
|
|
1674
|
+
// when the IIFE registered the entry. Spread `restored` so the
|
|
1675
|
+
// ACP state propagates to coalesced waiters (BQ9tV-equivalent
|
|
1676
|
+
// for restore waiter consistency).
|
|
1677
|
+
return {
|
|
1678
|
+
...restored,
|
|
1679
|
+
attached: true,
|
|
1680
|
+
clientId: registerClient(entry, req.clientId),
|
|
1681
|
+
createdAt: entry.createdAt,
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
if (byId.size + inFlightSpawns.size + inFlightRestores.size >=
|
|
1685
|
+
maxSessions) {
|
|
1686
|
+
throw new SessionLimitExceededError(maxSessions);
|
|
1687
|
+
}
|
|
1688
|
+
const restoreEvents = new EventBus(eventRingSize);
|
|
1689
|
+
let registeredEntry;
|
|
1690
|
+
let ci;
|
|
1691
|
+
// Live counter shared with coalesced waiters (see InFlightRestore
|
|
1692
|
+
// doc comment). Mutated synchronously by the coalesce branch above
|
|
1693
|
+
// and read once by the IIFE when seeding `entry.attachCount`.
|
|
1694
|
+
const coalesceState = { count: 0 };
|
|
1695
|
+
const promise = (async () => {
|
|
1696
|
+
pendingRestoreEvents.set(req.sessionId, restoreEvents);
|
|
1697
|
+
ci = await ensureChannel();
|
|
1698
|
+
ci.pendingRestoreIds.add(req.sessionId);
|
|
1699
|
+
// PR 14b fix (codex round 6): mark this id as in-flight restore
|
|
1700
|
+
// BEFORE the ACP `loadSession`/`unstable_resumeSession` call.
|
|
1701
|
+
// Restore-time guardrail events arriving on the bridge during
|
|
1702
|
+
// that ACP call hit `bufferEarlyEvent` BEFORE the
|
|
1703
|
+
// post-restore `createSessionEntry → drainEarlyEvents` clears
|
|
1704
|
+
// the (close-window) tombstone, so without this allow-list the
|
|
1705
|
+
// tombstone would silently drop them. Cleared in the matching
|
|
1706
|
+
// `finally` below regardless of success / failure.
|
|
1707
|
+
ci.client.markRestoreInFlight(req.sessionId);
|
|
1708
|
+
// Restore is a low-frequency one-shot path, so we register a
|
|
1709
|
+
// fresh `channel.exited` listener per call instead of going
|
|
1710
|
+
// through `getTransportClosedReject` (which exists to keep
|
|
1711
|
+
// sendPrompt's per-session listener count at 1 over the
|
|
1712
|
+
// session's lifetime). The listener is bound to this restore's
|
|
1713
|
+
// race only — once the race settles, no new awaits attach to
|
|
1714
|
+
// it, so there's no listener leak across restores.
|
|
1715
|
+
const transportClosed = ci.channel.exited.then(() => {
|
|
1716
|
+
throw new BridgeChannelClosedError(`during session/${action}`);
|
|
1717
|
+
});
|
|
1718
|
+
// Suppress the dangling rejection if `withTimeout` wins the
|
|
1719
|
+
// race below: `transportClosed` then stays pending, and a
|
|
1720
|
+
// later `channel.exited` settle fires the inner `throw` with
|
|
1721
|
+
// no observer attached. Node 22 logs `unhandledRejection`;
|
|
1722
|
+
// under `--unhandled-rejections=throw` (common in container
|
|
1723
|
+
// deployments) the daemon process crashes. The `Promise.race`
|
|
1724
|
+
// path's own consumer below catches the rejection in the
|
|
1725
|
+
// try/catch, so the suppressed rejection here is the
|
|
1726
|
+
// race-loser case only.
|
|
1727
|
+
transportClosed.catch(() => { });
|
|
1728
|
+
let state;
|
|
1729
|
+
try {
|
|
1730
|
+
if (action === 'load') {
|
|
1731
|
+
state = await Promise.race([
|
|
1732
|
+
withTimeout(ci.connection.loadSession({
|
|
1733
|
+
sessionId: req.sessionId,
|
|
1734
|
+
cwd: workspaceKey,
|
|
1735
|
+
// Restore path drops per-request `mcpServers` (matches
|
|
1736
|
+
// `doSpawn`); daemon-wide MCP comes from settings on
|
|
1737
|
+
// the agent side. The SDK's `RestoreSessionRequest`
|
|
1738
|
+
// intentionally has no `mcpServers` field for the
|
|
1739
|
+
// same reason.
|
|
1740
|
+
mcpServers: [],
|
|
1741
|
+
}), initTimeoutMs, 'loadSession'),
|
|
1742
|
+
transportClosed,
|
|
1743
|
+
]);
|
|
1744
|
+
}
|
|
1745
|
+
else {
|
|
1746
|
+
state = await Promise.race([
|
|
1747
|
+
withTimeout(ci.connection.unstable_resumeSession({
|
|
1748
|
+
sessionId: req.sessionId,
|
|
1749
|
+
cwd: workspaceKey,
|
|
1750
|
+
mcpServers: [],
|
|
1751
|
+
}), initTimeoutMs, 'resumeSession'),
|
|
1752
|
+
transportClosed,
|
|
1753
|
+
]);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
catch (err) {
|
|
1757
|
+
restoreEvents.close();
|
|
1758
|
+
if (isAcpSessionResourceNotFound(err, req.sessionId)) {
|
|
1759
|
+
throw new SessionNotFoundError(req.sessionId);
|
|
1760
|
+
}
|
|
1761
|
+
if (ci.sessionIds.size === 0 &&
|
|
1762
|
+
ci.pendingRestoreIds.size === 1 &&
|
|
1763
|
+
ci.pendingRestoreIds.has(req.sessionId)) {
|
|
1764
|
+
ci.isDying = true;
|
|
1765
|
+
await ci.channel.kill().catch(() => {
|
|
1766
|
+
/* best-effort — channel.exited handler still runs */
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
throw err;
|
|
1770
|
+
}
|
|
1771
|
+
if (shuttingDown) {
|
|
1772
|
+
restoreEvents.close();
|
|
1773
|
+
throw new Error('HttpAcpBridge is shutting down');
|
|
1774
|
+
}
|
|
1775
|
+
if (ci.isDying || !aliveChannels.has(ci)) {
|
|
1776
|
+
restoreEvents.close();
|
|
1777
|
+
throw new Error(`Session ${req.sessionId} restored on a closed agent channel`);
|
|
1778
|
+
}
|
|
1779
|
+
const racedEntry = byId.get(req.sessionId);
|
|
1780
|
+
if (racedEntry) {
|
|
1781
|
+
restoreEvents.close();
|
|
1782
|
+
// Self + any coalescers we accumulated while the restore was
|
|
1783
|
+
// in flight. Coalescers must not bump attachCount themselves
|
|
1784
|
+
// (they read it off the registered entry on the next tick).
|
|
1785
|
+
racedEntry.attachCount += 1 + coalesceState.count;
|
|
1786
|
+
const clientId = registerClient(racedEntry, req.clientId);
|
|
1787
|
+
return {
|
|
1788
|
+
sessionId: racedEntry.sessionId,
|
|
1789
|
+
workspaceCwd: racedEntry.workspaceCwd,
|
|
1790
|
+
attached: true,
|
|
1791
|
+
clientId,
|
|
1792
|
+
createdAt: racedEntry.createdAt,
|
|
1793
|
+
state: racedEntry.restoreState ?? {},
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
const entry = createSessionEntry(ci, req.sessionId, workspaceKey, restoreEvents);
|
|
1797
|
+
entry.restoreState = state;
|
|
1798
|
+
const clientId = registerClient(entry, req.clientId);
|
|
1799
|
+
// Fold synchronous coalesce reservations into the new entry's
|
|
1800
|
+
// `attachCount`. By this point all coalescers that beat us must
|
|
1801
|
+
// have hit the inFlightRestores branch and bumped
|
|
1802
|
+
// `coalesceState.count`; later coalescers will hit the byId
|
|
1803
|
+
// early-return path instead and increment `entry.attachCount`
|
|
1804
|
+
// directly.
|
|
1805
|
+
entry.attachCount = coalesceState.count;
|
|
1806
|
+
registeredEntry = entry;
|
|
1807
|
+
// Explicit `session/load` / `session/resume` is "give me THIS
|
|
1808
|
+
// id"; it must NOT become the implicit attach target for
|
|
1809
|
+
// subsequent omitted-id `POST /session` callers under `single`
|
|
1810
|
+
// scope. Those callers asked for "any default", and silently
|
|
1811
|
+
// joining a restored live history would surprise them.
|
|
1812
|
+
// `defaultEntry` is reserved for sessions created through
|
|
1813
|
+
// `doSpawn` under `'single'` scope.
|
|
1814
|
+
return {
|
|
1815
|
+
sessionId: entry.sessionId,
|
|
1816
|
+
workspaceCwd: entry.workspaceCwd,
|
|
1817
|
+
attached: false,
|
|
1818
|
+
clientId,
|
|
1819
|
+
createdAt: entry.createdAt,
|
|
1820
|
+
state,
|
|
1821
|
+
};
|
|
1822
|
+
})().finally(() => {
|
|
1823
|
+
ci?.pendingRestoreIds.delete(req.sessionId);
|
|
1824
|
+
// PR 14b fix (codex round 6): pair with `markRestoreInFlight`.
|
|
1825
|
+
// Once the IIFE settles, either `createSessionEntry` ran
|
|
1826
|
+
// (`drainEarlyEvents` already cleared the tombstone) or the
|
|
1827
|
+
// restore failed (handled below).
|
|
1828
|
+
ci?.client.clearRestoreInFlight(req.sessionId);
|
|
1829
|
+
pendingRestoreEvents.delete(req.sessionId);
|
|
1830
|
+
if (!registeredEntry) {
|
|
1831
|
+
restoreEvents.close();
|
|
1832
|
+
// PR 14b fix (codex round 7): on restore failure, purge any
|
|
1833
|
+
// guardrail events that the child buffered during this
|
|
1834
|
+
// restore window AND re-tombstone the id. Pre-fix the
|
|
1835
|
+
// round-6 allow-list (`markRestoreInFlight`) let
|
|
1836
|
+
// `bufferEarlyEvent` accept frames during the ACP call;
|
|
1837
|
+
// failure here only cleared the allow-list entry, leaving
|
|
1838
|
+
// queued frames in `earlyEvents`. A subsequent successful
|
|
1839
|
+
// `session/load`/`session/resume` for the same id within
|
|
1840
|
+
// 60s would then `drainEarlyEvents` those stale frames into
|
|
1841
|
+
// the new session — exactly the leak round 5's tombstone
|
|
1842
|
+
// was meant to prevent. `markSessionClosed` already does
|
|
1843
|
+
// both: refresh tombstone + delete `earlyEvents[id]`.
|
|
1844
|
+
ci?.client.markSessionClosed(req.sessionId);
|
|
1845
|
+
}
|
|
1846
|
+
});
|
|
1847
|
+
inFlightRestores.set(req.sessionId, { action, promise, coalesceState });
|
|
1848
|
+
try {
|
|
1849
|
+
return await promise;
|
|
1850
|
+
}
|
|
1851
|
+
finally {
|
|
1852
|
+
inFlightRestores.delete(req.sessionId);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return {
|
|
1856
|
+
get sessionCount() {
|
|
1857
|
+
return byId.size;
|
|
1858
|
+
},
|
|
1859
|
+
get pendingPermissionCount() {
|
|
1860
|
+
return pendingPermissions.size;
|
|
1861
|
+
},
|
|
1862
|
+
async loadSession(req) {
|
|
1863
|
+
return restoreSession('load', req);
|
|
1864
|
+
},
|
|
1865
|
+
async resumeSession(req) {
|
|
1866
|
+
return restoreSession('resume', req);
|
|
1867
|
+
},
|
|
1868
|
+
async spawnOrAttach(req) {
|
|
1869
|
+
if (shuttingDown) {
|
|
1870
|
+
// `runQwenServe.close()` calls `bridge.shutdown()` BEFORE
|
|
1871
|
+
// `server.close()`. During that window, established HTTP
|
|
1872
|
+
// connections can still hit `POST /session`. Refuse here so
|
|
1873
|
+
// late-arrivers don't spawn children the shutdown path won't
|
|
1874
|
+
// see — they'd otherwise leak past `process.exit(0)`.
|
|
1875
|
+
throw new Error('HttpAcpBridge is shutting down');
|
|
1876
|
+
}
|
|
1877
|
+
// Fast-path the common §02 case: clients pre-flight `caps.workspaceCwd`
|
|
1878
|
+
// and post back the exact same string, so the equality check
|
|
1879
|
+
// saves a `realpathSync.native` syscall per spawnOrAttach. The
|
|
1880
|
+
// omit-cwd path in `server.ts` also synthesizes `cwd =
|
|
1881
|
+
// boundWorkspace` before calling here, so it hits this branch
|
|
1882
|
+
// too. Falls through to the full canonicalize when the client
|
|
1883
|
+
// sent a non-canonical alias (`/work/./bound`, mixed casing on
|
|
1884
|
+
// case-insensitive FS, a symlinked aliased path, …) — that
|
|
1885
|
+
// still needs the realpath to compare correctly.
|
|
1886
|
+
const workspaceKey = resolveWorkspaceKey(req.workspaceCwd);
|
|
1887
|
+
// Resolve the effective scope for THIS call. A per-request
|
|
1888
|
+
// `req.sessionScope` overrides the daemon-wide default; omitting
|
|
1889
|
+
// it falls back to `defaultSessionScope` so every existing caller
|
|
1890
|
+
// observes pre-#4175-PR-5 behavior bit-for-bit. The string-validation
|
|
1891
|
+
// happens here (rather than at the route layer alone) so direct
|
|
1892
|
+
// callers — tests, embeds, future entry points — can't bypass it.
|
|
1893
|
+
if (req.sessionScope !== undefined &&
|
|
1894
|
+
req.sessionScope !== 'single' &&
|
|
1895
|
+
req.sessionScope !== 'thread') {
|
|
1896
|
+
throw new InvalidSessionScopeError(req.sessionScope);
|
|
1897
|
+
}
|
|
1898
|
+
const effectiveScope = req.sessionScope ?? defaultSessionScope;
|
|
1899
|
+
if (effectiveScope === 'single') {
|
|
1900
|
+
const existing = defaultEntry;
|
|
1901
|
+
if (existing) {
|
|
1902
|
+
// BRSCi: bump attach counter BEFORE any await so the
|
|
1903
|
+
// spawn-owner's disconnect reaper (server.ts:
|
|
1904
|
+
// `requireZeroAttaches: true`) sees this attach even when
|
|
1905
|
+
// we yield on the model-switch below. Increment is
|
|
1906
|
+
// synchronous → atomic against the killSession
|
|
1907
|
+
// sync-prefix check.
|
|
1908
|
+
//
|
|
1909
|
+
// BVryk + BWGSL: counter is NOT strictly monotonic any
|
|
1910
|
+
// more — `detachClient()` decrements it to roll back an
|
|
1911
|
+
// attach whose HTTP response couldn't be written
|
|
1912
|
+
// (tanzhenxin issue 2). The race-guard invariant we still
|
|
1913
|
+
// hold is "attachCount reflects the number of attaching
|
|
1914
|
+
// clients whose response was written or is about to be
|
|
1915
|
+
// written"; decrementing is the symmetric cleanup for
|
|
1916
|
+
// attaches that turned out to be fictitious. The
|
|
1917
|
+
// ordering guarantee that matters for the killSession
|
|
1918
|
+
// race is "bump runs before any await inside this
|
|
1919
|
+
// microtask," which is what we get here.
|
|
1920
|
+
existing.attachCount++;
|
|
1921
|
+
const clientId = registerClient(existing, req.clientId);
|
|
1922
|
+
// If the caller passed a modelServiceId on attach, the session
|
|
1923
|
+
// may currently be running a DIFFERENT model. Honor the request
|
|
1924
|
+
// by issuing setSessionModel — same call we'd use on
|
|
1925
|
+
// /session/:id/model. Surfaces a `model_switched` event so
|
|
1926
|
+
// every attached client sees the change. If the new model is
|
|
1927
|
+
// rejected, propagate as a spawn-style error rather than
|
|
1928
|
+
// silently returning an attach-with-stale-model.
|
|
1929
|
+
if (req.modelServiceId) {
|
|
1930
|
+
// Swallow: matches the create-session catch in `doSpawn`
|
|
1931
|
+
// below — a model-switch rejection on an already-running
|
|
1932
|
+
// session must NOT 500 the attach (the session is fully
|
|
1933
|
+
// operational on its current model; tearing it down or
|
|
1934
|
+
// returning an error without the sessionId would deny
|
|
1935
|
+
// the caller any way to recover). The
|
|
1936
|
+
// `model_switch_failed` SSE event is the visible signal.
|
|
1937
|
+
await applyModelServiceId(existing, req.modelServiceId, initTimeoutMs, clientId).catch(() => { });
|
|
1938
|
+
}
|
|
1939
|
+
return {
|
|
1940
|
+
sessionId: existing.sessionId,
|
|
1941
|
+
workspaceCwd: existing.workspaceCwd,
|
|
1942
|
+
attached: true,
|
|
1943
|
+
clientId,
|
|
1944
|
+
createdAt: existing.createdAt,
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
// Coalesce: if another caller is already mid-spawn for this same
|
|
1948
|
+
// workspace, await their result. The reporter's call appears as an
|
|
1949
|
+
// attach (the spawn was someone else's, not theirs). If the
|
|
1950
|
+
// reporter asked for a different modelServiceId than the spawn
|
|
1951
|
+
// chose, apply it now.
|
|
1952
|
+
const inFlight = inFlightSpawns.get(workspaceKey);
|
|
1953
|
+
if (inFlight) {
|
|
1954
|
+
const session = await inFlight;
|
|
1955
|
+
// BRSCi: bump attach counter SYNCHRONOUSLY in the same
|
|
1956
|
+
// microtask the in-flight spawn resolves to us, BEFORE
|
|
1957
|
+
// any further await. The spawn-owner's route handler
|
|
1958
|
+
// microtask (which calls `killSession({requireZeroAttaches})`)
|
|
1959
|
+
// runs after our spawnOrAttach() resolves; the ordering
|
|
1960
|
+
// guarantee is "every attach-bump runs before the
|
|
1961
|
+
// matching killSession sync prefix" only if the bump is
|
|
1962
|
+
// the first sync step after `await inFlight`. Doing the
|
|
1963
|
+
// model-switch await first re-opens the race deepseek-v4-pro
|
|
1964
|
+
// flagged in BRSCi.
|
|
1965
|
+
const attachedEntry = byId.get(session.sessionId);
|
|
1966
|
+
if (attachedEntry)
|
|
1967
|
+
attachedEntry.attachCount++;
|
|
1968
|
+
// BX9_U: even with the BRSCi bump-before-await ordering,
|
|
1969
|
+
// there are still adversarial paths where the entry could
|
|
1970
|
+
// be torn down between `await inFlight` resolving and our
|
|
1971
|
+
// continuation running (e.g. channel.exited firing during
|
|
1972
|
+
// a crash spawn, or a direct bridge.killSession call from
|
|
1973
|
+
// outside the route handler). In those cases byId.get()
|
|
1974
|
+
// returned undefined. Fail loud with a descriptive error
|
|
1975
|
+
// so the caller can distinguish "immediate agent death"
|
|
1976
|
+
// from a stale sessionId and retry into a fresh spawn.
|
|
1977
|
+
if (!attachedEntry) {
|
|
1978
|
+
throw new SessionNotFoundError(session.sessionId, 'the agent child likely crashed during initialization — retry to spawn a new session');
|
|
1979
|
+
}
|
|
1980
|
+
const clientId = registerClient(attachedEntry, req.clientId);
|
|
1981
|
+
if (req.modelServiceId) {
|
|
1982
|
+
// Same swallow as above — we picked up an in-flight
|
|
1983
|
+
// spawn, the session is real, model-switch failure
|
|
1984
|
+
// shouldn't deny us the sessionId.
|
|
1985
|
+
await applyModelServiceId(attachedEntry, req.modelServiceId, initTimeoutMs, clientId).catch(() => { });
|
|
1986
|
+
}
|
|
1987
|
+
return { ...session, attached: true, clientId };
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
// Cap check: count both registered sessions and in-flight spawns
|
|
1991
|
+
// (a fresh-spawn races that's about to register hasn't hit
|
|
1992
|
+
// `byId` yet but should still count toward the limit). Attaches
|
|
1993
|
+
// returned above bypass this — only NEW children are gated.
|
|
1994
|
+
if (byId.size + inFlightSpawns.size + inFlightRestores.size >=
|
|
1995
|
+
maxSessions) {
|
|
1996
|
+
throw new SessionLimitExceededError(maxSessions);
|
|
1997
|
+
}
|
|
1998
|
+
const promise = doSpawn(req.modelServiceId, effectiveScope, req.clientId);
|
|
1999
|
+
// Track in-flight spawns regardless of scope. Under `single`
|
|
2000
|
+
// this also serves the coalescing path above (a parallel
|
|
2001
|
+
// `spawnOrAttach` finds the entry and waits for the same
|
|
2002
|
+
// promise). Under `thread` we don't need coalescing — every
|
|
2003
|
+
// call gets its own session — but `shutdown()` snapshots
|
|
2004
|
+
// `inFlightSpawns.values()` to know which spawns to await
|
|
2005
|
+
// for graceful tear-down. Without this, a `thread`-scope
|
|
2006
|
+
// shutdown returns before in-progress spawns finish their
|
|
2007
|
+
// child cleanup, surfacing stderr noise after the daemon
|
|
2008
|
+
// claimed graceful shutdown. Use a unique key per spawn so
|
|
2009
|
+
// simultaneous thread-scope spawns don't collide on the
|
|
2010
|
+
// workspace key.
|
|
2011
|
+
const tracker = effectiveScope === 'single'
|
|
2012
|
+
? workspaceKey
|
|
2013
|
+
: `${workspaceKey}#${randomUUID()}`;
|
|
2014
|
+
inFlightSpawns.set(tracker, promise);
|
|
2015
|
+
try {
|
|
2016
|
+
return await promise;
|
|
2017
|
+
}
|
|
2018
|
+
finally {
|
|
2019
|
+
// Always clear the in-flight slot whether the spawn resolved
|
|
2020
|
+
// or rejected — leaving a rejected promise behind would
|
|
2021
|
+
// poison every future coalescing-path call for this
|
|
2022
|
+
// workspace (single-scope) or grow unbounded (thread-scope).
|
|
2023
|
+
inFlightSpawns.delete(tracker);
|
|
2024
|
+
}
|
|
2025
|
+
},
|
|
2026
|
+
async sendPrompt(sessionId, req, signal, context) {
|
|
2027
|
+
const entry = byId.get(sessionId);
|
|
2028
|
+
if (!entry)
|
|
2029
|
+
throw new SessionNotFoundError(sessionId);
|
|
2030
|
+
const originatorClientId = resolveTrustedClientId(entry, context?.clientId);
|
|
2031
|
+
// Pre-aborted: skip the queue entirely. Without this the prompt
|
|
2032
|
+
// chains onto promptQueue, waits its turn, and the FIFO worker
|
|
2033
|
+
// checks `signal.aborted` only AFTER reaching the head — wasted
|
|
2034
|
+
// queue churn on every retry-after-abort, plus a confusing trace
|
|
2035
|
+
// where the prompt appears to "run" before erroring.
|
|
2036
|
+
if (signal?.aborted) {
|
|
2037
|
+
throw new DOMException('Prompt aborted', 'AbortError');
|
|
2038
|
+
}
|
|
2039
|
+
// Force the body's sessionId to match the routing id — a client that
|
|
2040
|
+
// sent a stale id in the body would otherwise be dispatched to the
|
|
2041
|
+
// wrong agent process.
|
|
2042
|
+
const normalized = { ...req, sessionId };
|
|
2043
|
+
const result = entry.promptQueue.then(() => {
|
|
2044
|
+
// If the caller aborted while we were queued behind earlier
|
|
2045
|
+
// prompts, don't even start this one.
|
|
2046
|
+
if (signal?.aborted) {
|
|
2047
|
+
throw new DOMException('Prompt aborted', 'AbortError');
|
|
2048
|
+
}
|
|
2049
|
+
if (originatorClientId === undefined) {
|
|
2050
|
+
delete entry.activePromptOriginatorClientId;
|
|
2051
|
+
}
|
|
2052
|
+
else {
|
|
2053
|
+
entry.activePromptOriginatorClientId = originatorClientId;
|
|
2054
|
+
}
|
|
2055
|
+
const promptPromise = entry.connection
|
|
2056
|
+
.prompt(normalized)
|
|
2057
|
+
.finally(() => {
|
|
2058
|
+
delete entry.activePromptOriginatorClientId;
|
|
2059
|
+
});
|
|
2060
|
+
// Race against channel termination: if the underlying transport
|
|
2061
|
+
// dies (child crashed, stream torn down) WHILE the prompt is in
|
|
2062
|
+
// flight, the SDK's pending-request promise can hang because the
|
|
2063
|
+
// wire never delivers a response. Make the prompt fail-fast in
|
|
2064
|
+
// that case so the per-session FIFO doesn't poison the next
|
|
2065
|
+
// queued prompt with an unbounded await. See
|
|
2066
|
+
// `getTransportClosedReject` for the single-listener invariant.
|
|
2067
|
+
//
|
|
2068
|
+
// FIXME(stage-2): no absolute prompt deadline. A buggy agent
|
|
2069
|
+
// that ignores `cancel()` while keeping the channel alive can
|
|
2070
|
+
// hold this race open indefinitely — the abort path fires
|
|
2071
|
+
// `cancel()` and resolves pending permissions, but the
|
|
2072
|
+
// `promptPromise` itself only settles when the agent
|
|
2073
|
+
// cooperates. Stage 2 should add a configurable per-prompt
|
|
2074
|
+
// wall clock (e.g. `--prompt-deadline 30m`) into this race so
|
|
2075
|
+
// a wedged agent can't slow-leak prompt promises. Tracked
|
|
2076
|
+
// under #3803 follow-ups.
|
|
2077
|
+
const racedPromise = Promise.race([
|
|
2078
|
+
promptPromise,
|
|
2079
|
+
getTransportClosedReject(entry),
|
|
2080
|
+
]);
|
|
2081
|
+
if (!signal)
|
|
2082
|
+
return racedPromise;
|
|
2083
|
+
// Wire the abort: when the signal fires (e.g. SSE route's
|
|
2084
|
+
// req.on('close')), tell the agent to wind down. ACP cancel is a
|
|
2085
|
+
// notification — the active prompt resolves with
|
|
2086
|
+
// stopReason: 'cancelled', then the next queued prompt can run.
|
|
2087
|
+
//
|
|
2088
|
+
// Also resolve any pending permission requests as `cancelled`.
|
|
2089
|
+
// ACP spec requires `cancel` to settle outstanding
|
|
2090
|
+
// `requestPermission` calls — `cancelSession()` already does
|
|
2091
|
+
// this; the abort path here was missing the call. Without it,
|
|
2092
|
+
// a client disconnecting while the agent is inside
|
|
2093
|
+
// `requestPermission` leaves the permission promise unresolved
|
|
2094
|
+
// forever (the agent is stuck waiting on a vote that no SSE
|
|
2095
|
+
// subscriber will ever cast).
|
|
2096
|
+
const onAbort = () => {
|
|
2097
|
+
cancelPendingForSession(sessionId);
|
|
2098
|
+
entry.connection.cancel({ sessionId }).catch(() => {
|
|
2099
|
+
// Cancel is fire-and-forget; the agent may already be dead.
|
|
2100
|
+
});
|
|
2101
|
+
};
|
|
2102
|
+
if (signal.aborted) {
|
|
2103
|
+
onAbort();
|
|
2104
|
+
}
|
|
2105
|
+
else {
|
|
2106
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
2107
|
+
// The aborted state can flip synchronously between the early-exit
|
|
2108
|
+
// check at the top of `sendPrompt` and addEventListener — re-check
|
|
2109
|
+
// after registration so a microsecond-window abort still fires
|
|
2110
|
+
// `cancel()` instead of letting the prompt run uncancellable.
|
|
2111
|
+
if (signal.aborted)
|
|
2112
|
+
onAbort();
|
|
2113
|
+
// Detach the listener once the prompt resolves so the
|
|
2114
|
+
// AbortController can be GC'd. The `.finally()` returns a
|
|
2115
|
+
// promise chained on `racedPromise`; if `racedPromise`
|
|
2116
|
+
// rejects, that returned promise rejects too — and we
|
|
2117
|
+
// never await it, so under Node's default
|
|
2118
|
+
// unhandled-rejection behavior the daemon could terminate
|
|
2119
|
+
// even though the route's own catch handles the original
|
|
2120
|
+
// rejection. Attach `.catch(() => {})` to the
|
|
2121
|
+
// listener-cleanup chain only — the caller's reference to
|
|
2122
|
+
// `racedPromise` (via `return racedPromise` below) still
|
|
2123
|
+
// surfaces failures normally.
|
|
2124
|
+
racedPromise
|
|
2125
|
+
.finally(() => signal.removeEventListener('abort', onAbort))
|
|
2126
|
+
.catch(() => { });
|
|
2127
|
+
}
|
|
2128
|
+
return racedPromise;
|
|
2129
|
+
});
|
|
2130
|
+
// Tail swallows failures so subsequent prompts still run. The caller
|
|
2131
|
+
// still sees rejections on its own `result` reference.
|
|
2132
|
+
entry.promptQueue = result.then(() => undefined, () => undefined);
|
|
2133
|
+
return result;
|
|
2134
|
+
},
|
|
2135
|
+
async cancelSession(sessionId, req, context) {
|
|
2136
|
+
const entry = byId.get(sessionId);
|
|
2137
|
+
if (!entry)
|
|
2138
|
+
throw new SessionNotFoundError(sessionId);
|
|
2139
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
2140
|
+
// Validation-only: cancellation resolves permissions as system
|
|
2141
|
+
// cancellations, so those generated events intentionally omit an
|
|
2142
|
+
// originator client id.
|
|
2143
|
+
// ACP spec: cancelling a prompt MUST resolve outstanding
|
|
2144
|
+
// requestPermission calls with outcome.cancelled. Do this *before*
|
|
2145
|
+
// forwarding the notification so the agent's wind-down sees the
|
|
2146
|
+
// resolutions.
|
|
2147
|
+
cancelPendingForSession(sessionId);
|
|
2148
|
+
// Cancel intentionally bypasses the prompt queue: it's a notification
|
|
2149
|
+
// that the agent uses to wind down the *currently active* prompt, not
|
|
2150
|
+
// something to wait behind queued work.
|
|
2151
|
+
//
|
|
2152
|
+
// CONTRACT (multi-prompt clients): cancel affects ONLY the active
|
|
2153
|
+
// prompt. Any prompts the client previously POSTed and that are
|
|
2154
|
+
// still queued behind the active one will continue to execute
|
|
2155
|
+
// after the active prompt resolves with `stopReason: 'cancelled'`.
|
|
2156
|
+
// This matches ACP's "cancel is a wind-down notification for the
|
|
2157
|
+
// current turn" semantics — multi-prompt queueing is a daemon
|
|
2158
|
+
// convenience, not in spec, so we don't extend cancel's reach
|
|
2159
|
+
// there. Clients that want a hard stop should stop posting new
|
|
2160
|
+
// prompts and call `cancelSession` after their last prompt
|
|
2161
|
+
// resolves, or kill the session via the channel-exit path.
|
|
2162
|
+
const notif = req
|
|
2163
|
+
? { ...req, sessionId }
|
|
2164
|
+
: { sessionId };
|
|
2165
|
+
await entry.connection.cancel(notif);
|
|
2166
|
+
},
|
|
2167
|
+
subscribeEvents(sessionId, subOpts) {
|
|
2168
|
+
const entry = byId.get(sessionId);
|
|
2169
|
+
if (!entry)
|
|
2170
|
+
throw new SessionNotFoundError(sessionId);
|
|
2171
|
+
return entry.events.subscribe(subOpts);
|
|
2172
|
+
},
|
|
2173
|
+
respondToPermission(requestId, response, context) {
|
|
2174
|
+
const pending = pendingPermissions.get(requestId);
|
|
2175
|
+
let originatorClientId;
|
|
2176
|
+
if (context?.clientId !== undefined && !pending) {
|
|
2177
|
+
resolveAnyTrustedClientId(context.clientId);
|
|
2178
|
+
}
|
|
2179
|
+
else if (pending && context?.clientId !== undefined) {
|
|
2180
|
+
const entry = byId.get(pending.sessionId);
|
|
2181
|
+
if (entry) {
|
|
2182
|
+
originatorClientId = resolveTrustedClientId(entry, context.clientId);
|
|
2183
|
+
}
|
|
2184
|
+
else {
|
|
2185
|
+
resolveAnyTrustedClientId(context.clientId);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
if (!pending) {
|
|
2189
|
+
const record = resolvedPermissions.get(requestId);
|
|
2190
|
+
if (record) {
|
|
2191
|
+
publishPermissionAlreadyResolved(record);
|
|
2192
|
+
}
|
|
2193
|
+
return false;
|
|
2194
|
+
}
|
|
2195
|
+
// BkwQI: validate the voter's optionId against the original
|
|
2196
|
+
// options the agent advertised. The route already enforces
|
|
2197
|
+
// "non-empty string" structurally; this layer enforces
|
|
2198
|
+
// semantic membership in the agent-published set so a
|
|
2199
|
+
// malicious client can't forge hidden outcomes (e.g.
|
|
2200
|
+
// `ProceedAlways*` when the prompt's `hideAlwaysAllow`
|
|
2201
|
+
// policy intentionally suppressed them).
|
|
2202
|
+
if (response.outcome.outcome === 'selected') {
|
|
2203
|
+
if (!pending.allowedOptionIds.has(response.outcome.optionId)) {
|
|
2204
|
+
throw new InvalidPermissionOptionError(requestId, response.outcome.optionId);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
return resolvePending(requestId, response, originatorClientId);
|
|
2208
|
+
},
|
|
2209
|
+
respondToSessionPermission(sessionId, requestId, response, context) {
|
|
2210
|
+
const entry = byId.get(sessionId);
|
|
2211
|
+
if (!entry)
|
|
2212
|
+
throw new SessionNotFoundError(sessionId);
|
|
2213
|
+
const pending = pendingPermissions.get(requestId);
|
|
2214
|
+
if (!pending) {
|
|
2215
|
+
const record = resolvedPermissions.get(requestId);
|
|
2216
|
+
if (record?.sessionId === sessionId) {
|
|
2217
|
+
resolveTrustedClientId(entry, context?.clientId);
|
|
2218
|
+
publishPermissionAlreadyResolved(record);
|
|
2219
|
+
}
|
|
2220
|
+
else if (record) {
|
|
2221
|
+
writeServeDebugLine(`rejected permission vote ${JSON.stringify(requestId)} ` +
|
|
2222
|
+
`for session ${JSON.stringify(sessionId)}; request belongs to ` +
|
|
2223
|
+
`session ${JSON.stringify(record.sessionId)}.`);
|
|
2224
|
+
}
|
|
2225
|
+
return false;
|
|
2226
|
+
}
|
|
2227
|
+
if (pending.sessionId !== sessionId) {
|
|
2228
|
+
writeServeDebugLine(`rejected permission vote ${JSON.stringify(requestId)} ` +
|
|
2229
|
+
`for session ${JSON.stringify(sessionId)}; request belongs to ` +
|
|
2230
|
+
`session ${JSON.stringify(pending.sessionId)}.`);
|
|
2231
|
+
return false;
|
|
2232
|
+
}
|
|
2233
|
+
const originatorClientId = resolveTrustedClientId(entry, context?.clientId);
|
|
2234
|
+
if (response.outcome.outcome === 'selected' &&
|
|
2235
|
+
!pending.allowedOptionIds.has(response.outcome.optionId)) {
|
|
2236
|
+
throw new InvalidPermissionOptionError(requestId, response.outcome.optionId);
|
|
2237
|
+
}
|
|
2238
|
+
return resolvePending(requestId, response, originatorClientId);
|
|
2239
|
+
},
|
|
2240
|
+
async closeSession(sessionId, context) {
|
|
2241
|
+
const entry = byId.get(sessionId);
|
|
2242
|
+
if (!entry)
|
|
2243
|
+
throw new SessionNotFoundError(sessionId);
|
|
2244
|
+
let originatorClientId;
|
|
2245
|
+
if (context?.clientId !== undefined) {
|
|
2246
|
+
originatorClientId = resolveTrustedClientId(entry, context.clientId);
|
|
2247
|
+
}
|
|
2248
|
+
writeStderrLine(`qwen serve: closing session ${JSON.stringify(sessionId)}` +
|
|
2249
|
+
(originatorClientId
|
|
2250
|
+
? ` by client ${JSON.stringify(originatorClientId)}`
|
|
2251
|
+
: ''));
|
|
2252
|
+
if (defaultEntry === entry)
|
|
2253
|
+
defaultEntry = undefined;
|
|
2254
|
+
const ci = detachSessionIdFromEntryChannel(channelInfo, aliveChannels, entry, sessionId);
|
|
2255
|
+
for (const id of Array.from(entry.pendingPermissionIds)) {
|
|
2256
|
+
resolvePending(id, { outcome: { outcome: 'cancelled' } });
|
|
2257
|
+
}
|
|
2258
|
+
byId.delete(sessionId);
|
|
2259
|
+
// PR 14b fix (codex round 5): tombstone the closed sessionId
|
|
2260
|
+
// so any late `extNotification` from the (now-defunct) child
|
|
2261
|
+
// can't seed the early-event buffer and leak into a future
|
|
2262
|
+
// load/resume of the same persisted id.
|
|
2263
|
+
ci?.client.markSessionClosed(sessionId);
|
|
2264
|
+
try {
|
|
2265
|
+
entry.events.publish({
|
|
2266
|
+
type: 'session_closed',
|
|
2267
|
+
data: {
|
|
2268
|
+
sessionId,
|
|
2269
|
+
reason: 'client_close',
|
|
2270
|
+
...(originatorClientId ? { closedBy: originatorClientId } : {}),
|
|
2271
|
+
},
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
catch {
|
|
2275
|
+
/* bus already closed */
|
|
2276
|
+
}
|
|
2277
|
+
// `session_closed` is terminal. Close the bus before ACP cancel so any
|
|
2278
|
+
// late cancellation frames from the agent are intentionally dropped.
|
|
2279
|
+
entry.events.close();
|
|
2280
|
+
try {
|
|
2281
|
+
await entry.connection.cancel({ sessionId });
|
|
2282
|
+
}
|
|
2283
|
+
catch {
|
|
2284
|
+
/* no active prompt or session already torn down */
|
|
2285
|
+
}
|
|
2286
|
+
if (ci && ci.sessionIds.size === 0 && ci.pendingRestoreIds.size === 0) {
|
|
2287
|
+
ci.isDying = true;
|
|
2288
|
+
await ci.channel.kill().catch((err) => {
|
|
2289
|
+
writeStderrLine(`qwen serve: closeSession channel kill failed for session ` +
|
|
2290
|
+
`${JSON.stringify(sessionId)}: ${String(err)}`);
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
2294
|
+
updateSessionMetadata(sessionId, metadata, context) {
|
|
2295
|
+
const entry = byId.get(sessionId);
|
|
2296
|
+
if (!entry)
|
|
2297
|
+
throw new SessionNotFoundError(sessionId);
|
|
2298
|
+
if (context?.clientId !== undefined) {
|
|
2299
|
+
resolveTrustedClientId(entry, context.clientId);
|
|
2300
|
+
}
|
|
2301
|
+
if (metadata.displayName !== undefined) {
|
|
2302
|
+
if (typeof metadata.displayName !== 'string' ||
|
|
2303
|
+
metadata.displayName.length > MAX_DISPLAY_NAME_LENGTH) {
|
|
2304
|
+
throw new InvalidSessionMetadataError('displayName', `must be a string of at most ${MAX_DISPLAY_NAME_LENGTH} characters`);
|
|
2305
|
+
}
|
|
2306
|
+
if (hasControlCharacter(metadata.displayName)) {
|
|
2307
|
+
throw new InvalidSessionMetadataError('displayName', 'must not contain control characters');
|
|
2308
|
+
}
|
|
2309
|
+
const nextDisplayName = metadata.displayName || undefined;
|
|
2310
|
+
if (entry.displayName !== nextDisplayName) {
|
|
2311
|
+
entry.displayName = nextDisplayName;
|
|
2312
|
+
writeStderrLine(`qwen serve: updated session metadata ${JSON.stringify(sessionId)} ` +
|
|
2313
|
+
`displayName=${entry.displayName === undefined ? 'cleared' : 'set'}` +
|
|
2314
|
+
(context?.clientId
|
|
2315
|
+
? ` by client ${JSON.stringify(context.clientId)}`
|
|
2316
|
+
: ''));
|
|
2317
|
+
try {
|
|
2318
|
+
entry.events.publish({
|
|
2319
|
+
type: 'session_metadata_updated',
|
|
2320
|
+
data: { sessionId, displayName: entry.displayName },
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2323
|
+
catch {
|
|
2324
|
+
/* bus already closed */
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
return { displayName: entry.displayName };
|
|
2329
|
+
},
|
|
2330
|
+
listWorkspaceSessions(workspaceCwd) {
|
|
2331
|
+
if (!path.isAbsolute(workspaceCwd))
|
|
2332
|
+
return [];
|
|
2333
|
+
const key = workspaceCwd === boundWorkspace
|
|
2334
|
+
? boundWorkspace
|
|
2335
|
+
: canonicalizeWorkspace(workspaceCwd);
|
|
2336
|
+
if (key !== boundWorkspace)
|
|
2337
|
+
return [];
|
|
2338
|
+
const out = [];
|
|
2339
|
+
for (const entry of byId.values()) {
|
|
2340
|
+
if (entry.workspaceCwd === key) {
|
|
2341
|
+
out.push({
|
|
2342
|
+
sessionId: entry.sessionId,
|
|
2343
|
+
workspaceCwd: entry.workspaceCwd,
|
|
2344
|
+
createdAt: entry.createdAt,
|
|
2345
|
+
displayName: entry.displayName,
|
|
2346
|
+
clientCount: entry.clientIds.size,
|
|
2347
|
+
hasActivePrompt: entry.activePromptOriginatorClientId !== undefined,
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
return out;
|
|
2352
|
+
},
|
|
2353
|
+
recordHeartbeat(sessionId, context) {
|
|
2354
|
+
const entry = byId.get(sessionId);
|
|
2355
|
+
if (!entry)
|
|
2356
|
+
throw new SessionNotFoundError(sessionId);
|
|
2357
|
+
// Validate the optional client id BEFORE bumping any timestamp so
|
|
2358
|
+
// an unknown client doesn't get to advance the per-session
|
|
2359
|
+
// watermark — that would let an attacker with a valid bearer
|
|
2360
|
+
// token mask client absence by spamming heartbeats with random
|
|
2361
|
+
// ids. `resolveTrustedClientId` throws `InvalidClientIdError`,
|
|
2362
|
+
// which the route layer maps to `400 invalid_client_id`.
|
|
2363
|
+
const clientId = resolveTrustedClientId(entry, context?.clientId);
|
|
2364
|
+
const lastSeenAt = Date.now();
|
|
2365
|
+
entry.sessionLastSeenAt = lastSeenAt;
|
|
2366
|
+
if (clientId !== undefined) {
|
|
2367
|
+
entry.clientLastSeenAt.set(clientId, lastSeenAt);
|
|
2368
|
+
}
|
|
2369
|
+
return {
|
|
2370
|
+
sessionId: entry.sessionId,
|
|
2371
|
+
...(clientId !== undefined ? { clientId } : {}),
|
|
2372
|
+
lastSeenAt,
|
|
2373
|
+
};
|
|
2374
|
+
},
|
|
2375
|
+
getHeartbeatState(sessionId) {
|
|
2376
|
+
const entry = byId.get(sessionId);
|
|
2377
|
+
if (!entry)
|
|
2378
|
+
return undefined;
|
|
2379
|
+
// Snapshot the client map so callers can't mutate the live one;
|
|
2380
|
+
// `sessionLastSeenAt` is undefined for sessions that have never
|
|
2381
|
+
// received a heartbeat (the typical state right after spawn).
|
|
2382
|
+
return {
|
|
2383
|
+
...(entry.sessionLastSeenAt !== undefined
|
|
2384
|
+
? { sessionLastSeenAt: entry.sessionLastSeenAt }
|
|
2385
|
+
: {}),
|
|
2386
|
+
clientLastSeenAt: new Map(entry.clientLastSeenAt),
|
|
2387
|
+
};
|
|
2388
|
+
},
|
|
2389
|
+
publishWorkspaceEvent(event) {
|
|
2390
|
+
// Issue #4175 PR 16. Workspace-level mutations (memory writes /
|
|
2391
|
+
// agent CRUD) need a fan-out path that doesn't require a session
|
|
2392
|
+
// id. Iterate every live session's bus best-effort — a closed bus
|
|
2393
|
+
// (mid-shutdown, or evicted under load) is silently skipped, same
|
|
2394
|
+
// posture as `permission_resolved` at line 1717.
|
|
2395
|
+
//
|
|
2396
|
+
// The route handler's contract is "read-after-write" and any SSE
|
|
2397
|
+
// subscriber that misses the event can re-fetch via the route's
|
|
2398
|
+
// GET sibling. Stage 5 PR 24 PermissionMediator can layer a
|
|
2399
|
+
// proper workspace event bus on top if adapters need stricter
|
|
2400
|
+
// delivery semantics.
|
|
2401
|
+
//
|
|
2402
|
+
// Per-entry exceptions go to stderr in normal operation, but
|
|
2403
|
+
// are downgraded to the debug channel when `shuttingDown` is
|
|
2404
|
+
// true. `EventBus.publish` is documented never to throw (BX9_p
|
|
2405
|
+
// contract at eventBus.ts:186), so anything landing here in
|
|
2406
|
+
// normal ops is by definition unexpected — silencing it via
|
|
2407
|
+
// QWEN_SERVE_DEBUG would let a true regression succeed at the
|
|
2408
|
+
// route layer (200 OK) while SSE subscribers stop seeing
|
|
2409
|
+
// events. The shutdown gate keeps the common race noise out of
|
|
2410
|
+
// the production log without hiding actual bugs.
|
|
2411
|
+
//
|
|
2412
|
+
// PR #4255 fold-in 9: track per-session success/fail. A
|
|
2413
|
+
// closed-bus return (`undefined` from `EventBus.publish` —
|
|
2414
|
+
// see eventBus.ts:195-207) counts as a failure (operator
|
|
2415
|
+
// signal), distinct from a thrown exception (regression
|
|
2416
|
+
// signal). When zero sessions are active OR every active bus
|
|
2417
|
+
// dropped the event, we elevate to unconditional stderr so
|
|
2418
|
+
// monitoring catches the all-buses-dropped scenario.
|
|
2419
|
+
// Inherited from the (now removed) `broadcastWorkspaceEvent`
|
|
2420
|
+
// PR 21 added — PR 16's helper is now the single fan-out.
|
|
2421
|
+
const sessions = Array.from(byId.values());
|
|
2422
|
+
let successCount = 0;
|
|
2423
|
+
let failureCount = 0;
|
|
2424
|
+
for (const entry of sessions) {
|
|
2425
|
+
try {
|
|
2426
|
+
const published = entry.events.publish(event);
|
|
2427
|
+
if (published === undefined) {
|
|
2428
|
+
failureCount += 1;
|
|
2429
|
+
writeServeDebugLine(`publishWorkspaceEvent: publish on session ${entry.sessionId} no-op (bus closed)`);
|
|
2430
|
+
}
|
|
2431
|
+
else {
|
|
2432
|
+
successCount += 1;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
catch (err) {
|
|
2436
|
+
failureCount += 1;
|
|
2437
|
+
const detail = `publishWorkspaceEvent: bus publish failed for session ` +
|
|
2438
|
+
`${JSON.stringify(entry.sessionId)} (type=${event.type}): ` +
|
|
2439
|
+
`${err instanceof Error ? err.message : String(err)}`;
|
|
2440
|
+
if (shuttingDown) {
|
|
2441
|
+
writeServeDebugLine(detail);
|
|
2442
|
+
}
|
|
2443
|
+
else {
|
|
2444
|
+
writeStderrLine(`qwen serve: ${detail}`);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
if (sessions.length > 0 && successCount === 0 && !shuttingDown) {
|
|
2449
|
+
writeStderrLine(`qwen serve: publishWorkspaceEvent type=${event.type} dropped on ALL ${failureCount} session bus(es); SSE subscribers will miss this event (GET fallback still authoritative)`);
|
|
2450
|
+
}
|
|
2451
|
+
},
|
|
2452
|
+
knownClientIds() {
|
|
2453
|
+
// Snapshot the union of every live session's stamped client ids.
|
|
2454
|
+
// Returned as a fresh Set so callers can mutate-safely (the live
|
|
2455
|
+
// per-session maps stay private). Workspace-level mutation routes
|
|
2456
|
+
// use this to validate `X-Qwen-Client-Id` without owning a
|
|
2457
|
+
// session id; PR 24 will replace it with a workspace-scoped
|
|
2458
|
+
// registry that doesn't conflate session-attach with workspace-
|
|
2459
|
+
// attach.
|
|
2460
|
+
const out = new Set();
|
|
2461
|
+
for (const entry of byId.values()) {
|
|
2462
|
+
for (const id of entry.clientIds.keys())
|
|
2463
|
+
out.add(id);
|
|
2464
|
+
}
|
|
2465
|
+
return out;
|
|
2466
|
+
},
|
|
2467
|
+
async getWorkspaceMcpStatus() {
|
|
2468
|
+
return requestWorkspaceStatus(SERVE_STATUS_EXT_METHODS.workspaceMcp, () => createIdleWorkspaceMcpStatus(boundWorkspace));
|
|
2469
|
+
},
|
|
2470
|
+
async getWorkspaceSkillsStatus() {
|
|
2471
|
+
return requestWorkspaceStatus(SERVE_STATUS_EXT_METHODS.workspaceSkills, () => createIdleWorkspaceSkillsStatus(boundWorkspace));
|
|
2472
|
+
},
|
|
2473
|
+
async getWorkspaceProvidersStatus() {
|
|
2474
|
+
return requestWorkspaceStatus(SERVE_STATUS_EXT_METHODS.workspaceProviders, () => createIdleWorkspaceProvidersStatus(boundWorkspace));
|
|
2475
|
+
},
|
|
2476
|
+
async getWorkspaceEnvStatus() {
|
|
2477
|
+
const acpChannelLive = !!liveChannelInfo();
|
|
2478
|
+
// PR 22b/2: daemon-host env snapshot delegated to
|
|
2479
|
+
// `BridgeOptions.statusProvider`. When omitted (Mode A in-process
|
|
2480
|
+
// consumers, tests) the bridge returns an idle envelope —
|
|
2481
|
+
// matches the "queryable but empty" pattern PR 12 / 13
|
|
2482
|
+
// established for diagnostic routes.
|
|
2483
|
+
//
|
|
2484
|
+
// Wenshao review fold-in (#4304): a custom provider that throws
|
|
2485
|
+
// would otherwise propagate past the bridge into `/workspace/env`
|
|
2486
|
+
// as a 500. Catch + log + fall back to the idle envelope so the
|
|
2487
|
+
// route still responds — the `daemon cells always answerable`
|
|
2488
|
+
// invariant the pre-injection `buildEnvStatusFromProcess` carried
|
|
2489
|
+
// (it never threw because it was synchronous and self-contained)
|
|
2490
|
+
// is preserved structurally.
|
|
2491
|
+
if (!opts.statusProvider) {
|
|
2492
|
+
return createIdleEnvStatus(boundWorkspace, acpChannelLive);
|
|
2493
|
+
}
|
|
2494
|
+
try {
|
|
2495
|
+
return await opts.statusProvider.getEnvStatus(boundWorkspace, acpChannelLive);
|
|
2496
|
+
}
|
|
2497
|
+
catch (err) {
|
|
2498
|
+
writeStderrLine(`qwen serve: statusProvider.getEnvStatus failed; ` +
|
|
2499
|
+
`falling back to idle envelope: ` +
|
|
2500
|
+
(err instanceof Error ? err.message : String(err)));
|
|
2501
|
+
return createIdleEnvStatus(boundWorkspace, acpChannelLive);
|
|
2502
|
+
}
|
|
2503
|
+
},
|
|
2504
|
+
async getWorkspacePreflightStatus() {
|
|
2505
|
+
// PR 22b/2: daemon-host preflight cells delegated to
|
|
2506
|
+
// `BridgeOptions.statusProvider`. Without a provider the daemon
|
|
2507
|
+
// half is empty `[]`; ACP-side cells are still fetched normally
|
|
2508
|
+
// when a child is live.
|
|
2509
|
+
//
|
|
2510
|
+
// Wenshao review fold-in (#4304): a throwing provider would
|
|
2511
|
+
// otherwise propagate past the bridge and turn the entire
|
|
2512
|
+
// preflight envelope into a 500 — losing both daemon cells AND
|
|
2513
|
+
// the ACP-side cells fetched below. Catch + log + fall back to
|
|
2514
|
+
// empty so ACP cells still render. Pre-injection
|
|
2515
|
+
// `buildDaemonPreflightCells` used `Promise.allSettled` and was
|
|
2516
|
+
// effectively unthrowable; this preserves that route-level
|
|
2517
|
+
// invariant for custom provider impls that may throw.
|
|
2518
|
+
let daemonCells;
|
|
2519
|
+
if (!opts.statusProvider) {
|
|
2520
|
+
// Asymmetric vs `getWorkspaceEnvStatus` (which falls back to a
|
|
2521
|
+
// full `createIdleEnvStatus` envelope): preflight is the union
|
|
2522
|
+
// of daemon-locality + ACP-locality cells stitched below, so an
|
|
2523
|
+
// empty daemon slice IS the right fallback — the ACP slice
|
|
2524
|
+
// fills in independently from the live channel (or its
|
|
2525
|
+
// `not_started` placeholders).
|
|
2526
|
+
daemonCells = [];
|
|
2527
|
+
}
|
|
2528
|
+
else {
|
|
2529
|
+
try {
|
|
2530
|
+
daemonCells =
|
|
2531
|
+
await opts.statusProvider.getDaemonPreflightCells(boundWorkspace);
|
|
2532
|
+
}
|
|
2533
|
+
catch (err) {
|
|
2534
|
+
writeStderrLine(`qwen serve: statusProvider.getDaemonPreflightCells failed; ` +
|
|
2535
|
+
`falling back to empty daemon cells: ` +
|
|
2536
|
+
(err instanceof Error ? err.message : String(err)));
|
|
2537
|
+
daemonCells = [];
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const acpChannelLive = !!liveChannelInfo();
|
|
2541
|
+
let acpResponse;
|
|
2542
|
+
let envelopeError;
|
|
2543
|
+
try {
|
|
2544
|
+
acpResponse = await requestWorkspaceStatus(SERVE_STATUS_EXT_METHODS.workspacePreflight, () => ({ cells: createIdleAcpPreflightCells() }));
|
|
2545
|
+
}
|
|
2546
|
+
catch (err) {
|
|
2547
|
+
// Bridge-side timeout / channel close while consulting ACP. Daemon
|
|
2548
|
+
// cells still render; envelope-level error tells the client which
|
|
2549
|
+
// surface failed without sinking the whole route.
|
|
2550
|
+
const errorKind = mapDomainErrorToErrorKind(err);
|
|
2551
|
+
envelopeError = {
|
|
2552
|
+
kind: 'preflight',
|
|
2553
|
+
status: 'error',
|
|
2554
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2555
|
+
...(errorKind ? { errorKind } : {}),
|
|
2556
|
+
};
|
|
2557
|
+
acpResponse = { cells: createIdleAcpPreflightCells() };
|
|
2558
|
+
}
|
|
2559
|
+
const errors = [
|
|
2560
|
+
...(acpResponse.errors ?? []),
|
|
2561
|
+
...(envelopeError ? [envelopeError] : []),
|
|
2562
|
+
];
|
|
2563
|
+
return {
|
|
2564
|
+
v: STATUS_SCHEMA_VERSION,
|
|
2565
|
+
workspaceCwd: boundWorkspace,
|
|
2566
|
+
initialized: true,
|
|
2567
|
+
acpChannelLive,
|
|
2568
|
+
cells: [...daemonCells, ...acpResponse.cells],
|
|
2569
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
2570
|
+
};
|
|
2571
|
+
},
|
|
2572
|
+
async getSessionContextStatus(sessionId) {
|
|
2573
|
+
return requestSessionStatus(sessionId, SERVE_STATUS_EXT_METHODS.sessionContext);
|
|
2574
|
+
},
|
|
2575
|
+
async getSessionSupportedCommandsStatus(sessionId) {
|
|
2576
|
+
return requestSessionStatus(sessionId, SERVE_STATUS_EXT_METHODS.sessionSupportedCommands);
|
|
2577
|
+
},
|
|
2578
|
+
async setSessionModel(sessionId, req, context) {
|
|
2579
|
+
const entry = byId.get(sessionId);
|
|
2580
|
+
if (!entry)
|
|
2581
|
+
throw new SessionNotFoundError(sessionId);
|
|
2582
|
+
const originatorClientId = resolveTrustedClientId(entry, context?.clientId);
|
|
2583
|
+
const normalized = { ...req, sessionId };
|
|
2584
|
+
// The ACP SDK marks setSessionModel as unstable (not in spec yet); the
|
|
2585
|
+
// method on AgentSideConnection is `unstable_setSessionModel`. Cast
|
|
2586
|
+
// through the shape we know rather than couple to the prefix in case
|
|
2587
|
+
// it's renamed when the spec stabilizes.
|
|
2588
|
+
const conn = entry.connection;
|
|
2589
|
+
// Serialize through `entry.modelChangeQueue` so a `POST /session/:id/model`
|
|
2590
|
+
// can't race with `applyModelServiceId` (e.g. an attach-with-different-
|
|
2591
|
+
// modelServiceId) and leave the agent connection in an indeterminate
|
|
2592
|
+
// model. `applyModelServiceId` already chains on this queue; without
|
|
2593
|
+
// mirroring that here, two concurrent model changes interleave and the
|
|
2594
|
+
// last `model_switched` event published may not match the actual model
|
|
2595
|
+
// the agent is on.
|
|
2596
|
+
//
|
|
2597
|
+
// Race the agent call against `transportClosedReject` and a
|
|
2598
|
+
// `withTimeout` so a wedged child can't block the HTTP handler
|
|
2599
|
+
// forever. Matches `sendPrompt` (transport race) and
|
|
2600
|
+
// `applyModelServiceId` (timeout) — the absence of either was an
|
|
2601
|
+
// attack surface for "POST /session/:id/model never returns".
|
|
2602
|
+
// See `getTransportClosedReject` for the single-listener invariant.
|
|
2603
|
+
//
|
|
2604
|
+
// FIXME(stage-2): we reuse `initTimeoutMs` (default 10s) as the
|
|
2605
|
+
// model-switch deadline because the two values happen to share
|
|
2606
|
+
// a sensible order of magnitude today. They're conceptually
|
|
2607
|
+
// distinct (cold-start handshake vs in-flight model swap) and
|
|
2608
|
+
// a Stage 2 split into `modelSwitchTimeoutMs` would let
|
|
2609
|
+
// operators tune them independently — also a good time to
|
|
2610
|
+
// remove the no-abort behavior of `withTimeout` (it rejects
|
|
2611
|
+
// the promise but leaves the underlying ACP call running, so a
|
|
2612
|
+
// late-arriving `model_switched` can race a previously-fired
|
|
2613
|
+
// `model_switch_failed`). Both depend on ACP exposing a cancel
|
|
2614
|
+
// signal for `unstable_setSessionModel`.
|
|
2615
|
+
const transportClosed = getTransportClosedReject(entry);
|
|
2616
|
+
const work = entry.modelChangeQueue.then(() => Promise.race([
|
|
2617
|
+
withTimeout(conn.unstable_setSessionModel(normalized), initTimeoutMs, 'setSessionModel'),
|
|
2618
|
+
transportClosed,
|
|
2619
|
+
]));
|
|
2620
|
+
// Tail-swallow on the queue so a model-change failure doesn't poison
|
|
2621
|
+
// every subsequent change (matches `applyModelServiceId`'s pattern).
|
|
2622
|
+
entry.modelChangeQueue = work.then(() => undefined, () => undefined);
|
|
2623
|
+
let response;
|
|
2624
|
+
try {
|
|
2625
|
+
response = await work;
|
|
2626
|
+
}
|
|
2627
|
+
catch (err) {
|
|
2628
|
+
// Mirror `applyModelServiceId`'s observability contract: surface
|
|
2629
|
+
// failed model changes on the SSE bus so subscribers can update
|
|
2630
|
+
// their UI / retry. Without this the only signal is the HTTP
|
|
2631
|
+
// 5xx, which doesn't reach passive viewers.
|
|
2632
|
+
try {
|
|
2633
|
+
entry.events.publish({
|
|
2634
|
+
type: 'model_switch_failed',
|
|
2635
|
+
data: {
|
|
2636
|
+
sessionId: entry.sessionId,
|
|
2637
|
+
requestedModelId: req.modelId,
|
|
2638
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2639
|
+
},
|
|
2640
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
catch {
|
|
2644
|
+
/* bus closed */
|
|
2645
|
+
}
|
|
2646
|
+
throw err;
|
|
2647
|
+
}
|
|
2648
|
+
try {
|
|
2649
|
+
entry.events.publish({
|
|
2650
|
+
type: 'model_switched',
|
|
2651
|
+
data: { sessionId: entry.sessionId, modelId: req.modelId },
|
|
2652
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
catch {
|
|
2656
|
+
/* bus closed */
|
|
2657
|
+
}
|
|
2658
|
+
return response;
|
|
2659
|
+
},
|
|
2660
|
+
async setSessionApprovalMode(sessionId, mode, opts, context) {
|
|
2661
|
+
// #4175 Wave 4 PR 17. Forwards through `qwen/control/session/
|
|
2662
|
+
// approval_mode` so the change lands inside the ACP child's own
|
|
2663
|
+
// `Config` (per-session `setApprovalMode`). The bridge layer adds
|
|
2664
|
+
// two things on top: trusted `originatorClientId` resolution and
|
|
2665
|
+
// an opt-in persist hook that writes `tools.approvalMode` to the
|
|
2666
|
+
// workspace settings file. Persist is OFF by default — see the
|
|
2667
|
+
// interface doc for the reasoning.
|
|
2668
|
+
const entry = byId.get(sessionId);
|
|
2669
|
+
if (!entry)
|
|
2670
|
+
throw new SessionNotFoundError(sessionId);
|
|
2671
|
+
const info = channelInfoForEntry(entry);
|
|
2672
|
+
if (!info || info.isDying)
|
|
2673
|
+
throw new SessionNotFoundError(sessionId);
|
|
2674
|
+
const originatorClientId = resolveTrustedClientId(entry, context?.clientId);
|
|
2675
|
+
// #4282 fold-in 4 (qwen-latest C1): validate the persist contract
|
|
2676
|
+
// BEFORE the ACP roundtrip changes the in-process mode. The previous
|
|
2677
|
+
// post-call placement meant a missing `persistApprovalMode` callback
|
|
2678
|
+
// produced a 500 *after* the ACP child had already applied the
|
|
2679
|
+
// mode change — observable to other in-flight requests but
|
|
2680
|
+
// invisible to the caller. Mirrors the pre-call validation in
|
|
2681
|
+
// `setWorkspaceToolEnabled`.
|
|
2682
|
+
if (opts.persist && !persistApprovalMode) {
|
|
2683
|
+
throw new Error('setSessionApprovalMode called with `persist: true` but no ' +
|
|
2684
|
+
'`persistApprovalMode` callback wired in BridgeOptions. ' +
|
|
2685
|
+
'runQwenServe wires the production callback; direct embeds ' +
|
|
2686
|
+
'and tests must opt in or omit `persist`.');
|
|
2687
|
+
}
|
|
2688
|
+
let response;
|
|
2689
|
+
try {
|
|
2690
|
+
response = (await Promise.race([
|
|
2691
|
+
withTimeout(entry.connection.extMethod(SERVE_CONTROL_EXT_METHODS.sessionApprovalMode, { sessionId, mode }), initTimeoutMs, SERVE_CONTROL_EXT_METHODS.sessionApprovalMode),
|
|
2692
|
+
getTransportClosedReject(entry),
|
|
2693
|
+
]));
|
|
2694
|
+
}
|
|
2695
|
+
catch (err) {
|
|
2696
|
+
// The ACP child rethrows `TrustGateError` as a JSON-RPC error
|
|
2697
|
+
// whose `data.errorKind` is the literal `'trust_gate'`. On the
|
|
2698
|
+
// wire it arrives as a plain `{code, message, data}` object —
|
|
2699
|
+
// re-instantiate the typed class here so the HTTP route layer
|
|
2700
|
+
// recognizes it via `instanceof` / `err.name` and maps the
|
|
2701
|
+
// failure to HTTP 403 with the `auth_env_error` errorKind.
|
|
2702
|
+
const data = err?.data;
|
|
2703
|
+
if (data &&
|
|
2704
|
+
typeof data === 'object' &&
|
|
2705
|
+
'errorKind' in data &&
|
|
2706
|
+
data.errorKind === 'trust_gate') {
|
|
2707
|
+
const rawMessage = err?.message;
|
|
2708
|
+
const message = typeof rawMessage === 'string'
|
|
2709
|
+
? rawMessage
|
|
2710
|
+
: 'Trust-gate rejection from ACP child';
|
|
2711
|
+
throw new TrustGateError(message);
|
|
2712
|
+
}
|
|
2713
|
+
throw err;
|
|
2714
|
+
}
|
|
2715
|
+
let persisted = false;
|
|
2716
|
+
if (opts.persist) {
|
|
2717
|
+
try {
|
|
2718
|
+
await persistApprovalMode?.(boundWorkspace, mode);
|
|
2719
|
+
persisted = persistApprovalMode !== undefined;
|
|
2720
|
+
}
|
|
2721
|
+
catch (err) {
|
|
2722
|
+
// Persist failure is non-fatal — the in-process change already
|
|
2723
|
+
// took effect inside the ACP child. Log to stderr so operators
|
|
2724
|
+
// notice but don't fail the route (the SDK consumer would have
|
|
2725
|
+
// no good recovery path; the runtime change is real).
|
|
2726
|
+
writeStderrLine(`setSessionApprovalMode: persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
try {
|
|
2730
|
+
entry.events.publish({
|
|
2731
|
+
type: 'approval_mode_changed',
|
|
2732
|
+
data: {
|
|
2733
|
+
sessionId: entry.sessionId,
|
|
2734
|
+
previous: response.previous,
|
|
2735
|
+
next: response.current,
|
|
2736
|
+
persisted,
|
|
2737
|
+
},
|
|
2738
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2739
|
+
});
|
|
2740
|
+
}
|
|
2741
|
+
catch {
|
|
2742
|
+
/* bus closed */
|
|
2743
|
+
}
|
|
2744
|
+
// #4282 fold-in 4 (qwen-latest S2): when the change is persisted to
|
|
2745
|
+
// workspace settings, the new mode becomes the default for every
|
|
2746
|
+
// future session in this workspace. Fan out a workspace-scoped
|
|
2747
|
+
// mirror so peer sessions can update their UI before they next
|
|
2748
|
+
// spawn an ACP child. The session-scoped publish above remains the
|
|
2749
|
+
// authoritative signal for the requesting session (and carries the
|
|
2750
|
+
// sessionId in `data`); the workspace mirror is informational.
|
|
2751
|
+
if (persisted) {
|
|
2752
|
+
broadcastWorkspaceEvent({
|
|
2753
|
+
type: 'approval_mode_changed',
|
|
2754
|
+
data: {
|
|
2755
|
+
sessionId: entry.sessionId,
|
|
2756
|
+
previous: response.previous,
|
|
2757
|
+
next: response.current,
|
|
2758
|
+
persisted,
|
|
2759
|
+
},
|
|
2760
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
return {
|
|
2764
|
+
sessionId: entry.sessionId,
|
|
2765
|
+
mode: response.current,
|
|
2766
|
+
previous: response.previous,
|
|
2767
|
+
persisted,
|
|
2768
|
+
};
|
|
2769
|
+
},
|
|
2770
|
+
async setWorkspaceToolEnabled(toolName, enabled, originatorClientId) {
|
|
2771
|
+
// #4175 Wave 4 PR 17. Pure file IO + event fan-out — no ACP
|
|
2772
|
+
// roundtrip. The settings file is the source of truth; live
|
|
2773
|
+
// sessions retain their already-registered tools until the next
|
|
2774
|
+
// ACP child spawn (when `tools.disabled` is consulted at Config
|
|
2775
|
+
// construction time).
|
|
2776
|
+
if (!persistDisabledTools) {
|
|
2777
|
+
throw new Error('setWorkspaceToolEnabled requires `persistDisabledTools` in ' +
|
|
2778
|
+
'BridgeOptions; runQwenServe wires the production callback. ' +
|
|
2779
|
+
'Direct embeds and tests must opt in.');
|
|
2780
|
+
}
|
|
2781
|
+
await persistDisabledTools(boundWorkspace, toolName, enabled);
|
|
2782
|
+
broadcastWorkspaceEvent({
|
|
2783
|
+
type: 'tool_toggled',
|
|
2784
|
+
data: { toolName, enabled },
|
|
2785
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2786
|
+
});
|
|
2787
|
+
return { toolName, enabled };
|
|
2788
|
+
},
|
|
2789
|
+
async restartMcpServer(serverName, originatorClientId) {
|
|
2790
|
+
// #4175 Wave 4 PR 17. The restart logic lives inside the ACP
|
|
2791
|
+
// child (it owns the `McpClientManager`); the bridge's role is
|
|
2792
|
+
// to (a) pick a live channel to forward through, (b) translate
|
|
2793
|
+
// the structured response back into the typed result, (c) fan
|
|
2794
|
+
// out the appropriate event to every session bus. Soft refusals
|
|
2795
|
+
// (skipped:true) come back as a normal response; hard errors
|
|
2796
|
+
// (server not configured, manager unavailable, post-discover
|
|
2797
|
+
// not connected) are translated via `data.errorKind` into typed
|
|
2798
|
+
// bridge errors that `sendBridgeError` maps to stable HTTP
|
|
2799
|
+
// responses (#4282 gpt-5.5 C4/C5 fold-in).
|
|
2800
|
+
const info = liveChannelInfo();
|
|
2801
|
+
if (!info) {
|
|
2802
|
+
throw new SessionNotFoundError(`mcp:${serverName}`);
|
|
2803
|
+
}
|
|
2804
|
+
let response;
|
|
2805
|
+
try {
|
|
2806
|
+
response = (await Promise.race([
|
|
2807
|
+
withTimeout(info.connection.extMethod(SERVE_CONTROL_EXT_METHODS.workspaceMcpRestart, { serverName }), MCP_RESTART_TIMEOUT_MS, SERVE_CONTROL_EXT_METHODS.workspaceMcpRestart),
|
|
2808
|
+
getChannelClosedReject(info),
|
|
2809
|
+
]));
|
|
2810
|
+
}
|
|
2811
|
+
catch (err) {
|
|
2812
|
+
// Detect structured ACP error payloads and re-instantiate as
|
|
2813
|
+
// typed bridge errors. JSON-RPC strips class names across the
|
|
2814
|
+
// wire; the agent attaches `data.errorKind` as the
|
|
2815
|
+
// reconstruction signal.
|
|
2816
|
+
const data = err?.data;
|
|
2817
|
+
if (data && typeof data === 'object') {
|
|
2818
|
+
const kind = data.errorKind;
|
|
2819
|
+
const sn = data.serverName;
|
|
2820
|
+
if (kind === 'mcp_server_not_found' && typeof sn === 'string') {
|
|
2821
|
+
throw new McpServerNotFoundError(sn);
|
|
2822
|
+
}
|
|
2823
|
+
if (kind === 'mcp_restart_failed' && typeof sn === 'string') {
|
|
2824
|
+
const status = data.mcpStatus;
|
|
2825
|
+
throw new McpServerRestartFailedError(sn, typeof status === 'string' ? status : 'unknown');
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
throw err;
|
|
2829
|
+
}
|
|
2830
|
+
if (response.restarted === true) {
|
|
2831
|
+
broadcastWorkspaceEvent({
|
|
2832
|
+
type: 'mcp_server_restarted',
|
|
2833
|
+
data: {
|
|
2834
|
+
serverName: response.serverName,
|
|
2835
|
+
durationMs: response.durationMs,
|
|
2836
|
+
},
|
|
2837
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
else {
|
|
2841
|
+
broadcastWorkspaceEvent({
|
|
2842
|
+
type: 'mcp_server_restart_refused',
|
|
2843
|
+
data: {
|
|
2844
|
+
serverName: response.serverName,
|
|
2845
|
+
reason: response.reason,
|
|
2846
|
+
},
|
|
2847
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
return response;
|
|
2851
|
+
},
|
|
2852
|
+
async initWorkspace(initOpts, originatorClientId) {
|
|
2853
|
+
// #4175 Wave 4 PR 17. Mechanical scaffold of an empty `QWEN.md`
|
|
2854
|
+
// (or whatever `getCurrentGeminiMdFilename()` returns under
|
|
2855
|
+
// `--memory-file-name` overrides). No ACP roundtrip, no LLM
|
|
2856
|
+
// call — clients that want AI-fill follow up with
|
|
2857
|
+
// `POST /session/:id/prompt`.
|
|
2858
|
+
//
|
|
2859
|
+
// FIXME(#4282 fold-in 2 — deepseek SV2): this route uses
|
|
2860
|
+
// `node:fs/promises` directly instead of routing through
|
|
2861
|
+
// `WorkspaceFileSystem` (PR 18 boundary), so it produces no
|
|
2862
|
+
// `fs.access`/`fs.denied` audit trail and skips
|
|
2863
|
+
// `assertTrustedForIntent`. The bridge doesn't have an
|
|
2864
|
+
// `fsFactory` plumbed at the bridge layer today — the boundary
|
|
2865
|
+
// is constructed per-request inside `createServeApp` for PR 19+
|
|
2866
|
+
// routes. A follow-up will hoist the factory into
|
|
2867
|
+
// `BridgeOptions` so daemon-level routes (init, future
|
|
2868
|
+
// workspace ops) can share the same trust + audit posture.
|
|
2869
|
+
// Impact today is low: the daemon binds to a workspace the
|
|
2870
|
+
// operator chose and the trust dialog flow doesn't yet exist
|
|
2871
|
+
// for the daemon. The CV1 symlink reject below covers the
|
|
2872
|
+
// immediate boundary-escape concern.
|
|
2873
|
+
const filename = getCurrentGeminiMdFilename();
|
|
2874
|
+
// #4282 gpt-5.5 C1 fold-in: `getCurrentGeminiMdFilename()` is
|
|
2875
|
+
// settings-controlled. A daemon configured with
|
|
2876
|
+
// `context.fileName: "../outside.md"` would otherwise resolve
|
|
2877
|
+
// outside `boundWorkspace` and let this strict-gated mutation
|
|
2878
|
+
// create or truncate a file outside the workspace boundary.
|
|
2879
|
+
// Resolve the joined path and reject anything that escapes.
|
|
2880
|
+
const target = path.resolve(boundWorkspace, filename);
|
|
2881
|
+
const withinWorkspace = target === boundWorkspace ||
|
|
2882
|
+
target.startsWith(boundWorkspace + path.sep);
|
|
2883
|
+
if (!withinWorkspace) {
|
|
2884
|
+
throw new Error(`Configured workspace context filename ${JSON.stringify(filename)} ` +
|
|
2885
|
+
`resolves outside the bound workspace ${JSON.stringify(boundWorkspace)}. ` +
|
|
2886
|
+
`Refusing to write.`);
|
|
2887
|
+
}
|
|
2888
|
+
// #4282 fold-in 2 (gpt-5.5 CV1): the textual `withinWorkspace`
|
|
2889
|
+
// check above only validates the JOINED path, but a file at
|
|
2890
|
+
// `target` that's a symlink can still point outside the
|
|
2891
|
+
// workspace. Without an explicit `lstat` reject, `force: true`
|
|
2892
|
+
// would follow the link and truncate the external target; a
|
|
2893
|
+
// dangling-symlink pointing outside would also let `writeFile`
|
|
2894
|
+
// create the external target. Reject symlinks at the boundary
|
|
2895
|
+
// — PR 18's `WorkspaceFileSystem` will provide the proper
|
|
2896
|
+
// chain-aware resolution + audit hooks once `initWorkspace`
|
|
2897
|
+
// routes through that boundary (tracked as a follow-up).
|
|
2898
|
+
try {
|
|
2899
|
+
const lst = await fs.lstat(target);
|
|
2900
|
+
if (lst.isSymbolicLink()) {
|
|
2901
|
+
throw new Error(`Workspace context file ${JSON.stringify(target)} is a symlink. ` +
|
|
2902
|
+
`Refusing to follow it for write — replace the symlink with a ` +
|
|
2903
|
+
`regular file (or remove it) before re-running init.`);
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
catch (err) {
|
|
2907
|
+
const code = err?.code;
|
|
2908
|
+
if (code !== 'ENOENT')
|
|
2909
|
+
throw err;
|
|
2910
|
+
// ENOENT — target doesn't exist; fresh create is fine.
|
|
2911
|
+
}
|
|
2912
|
+
let existingSize;
|
|
2913
|
+
let action = 'created';
|
|
2914
|
+
try {
|
|
2915
|
+
const existing = await fs.readFile(target, 'utf8');
|
|
2916
|
+
if (existing.trim().length > 0) {
|
|
2917
|
+
existingSize = Buffer.byteLength(existing, 'utf8');
|
|
2918
|
+
if (initOpts.force !== true) {
|
|
2919
|
+
throw new WorkspaceInitConflictError(target, existingSize);
|
|
2920
|
+
}
|
|
2921
|
+
action = 'overwrote';
|
|
2922
|
+
}
|
|
2923
|
+
else {
|
|
2924
|
+
// #4282 wenshao H4 fold-in: an existing whitespace-only file
|
|
2925
|
+
// is treated as a no-op rather than silently overwritten.
|
|
2926
|
+
// Previously the code would label the response `'created'`
|
|
2927
|
+
// and unconditionally `writeFile(target, '')`, destroying
|
|
2928
|
+
// the user's whitespace content (stray template, half-
|
|
2929
|
+
// written init, intentional newline) without `force: true`.
|
|
2930
|
+
// The HTTP intent of "init only if absent" is honored by
|
|
2931
|
+
// skipping the write and surfacing `'noop'` so the SSE
|
|
2932
|
+
// event accurately reflects that no on-disk change
|
|
2933
|
+
// occurred.
|
|
2934
|
+
action = 'noop';
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
catch (err) {
|
|
2938
|
+
if (err instanceof WorkspaceInitConflictError)
|
|
2939
|
+
throw err;
|
|
2940
|
+
const code = err?.code;
|
|
2941
|
+
if (code !== 'ENOENT')
|
|
2942
|
+
throw err;
|
|
2943
|
+
// ENOENT — fall through to create.
|
|
2944
|
+
}
|
|
2945
|
+
if (action !== 'noop') {
|
|
2946
|
+
await fs.writeFile(target, '', 'utf8');
|
|
2947
|
+
}
|
|
2948
|
+
broadcastWorkspaceEvent({
|
|
2949
|
+
type: 'workspace_initialized',
|
|
2950
|
+
data: { path: target, action },
|
|
2951
|
+
...(originatorClientId ? { originatorClientId } : {}),
|
|
2952
|
+
});
|
|
2953
|
+
return { path: target, action };
|
|
2954
|
+
},
|
|
2955
|
+
async killSession(sessionId, opts) {
|
|
2956
|
+
const entry = byId.get(sessionId);
|
|
2957
|
+
if (!entry)
|
|
2958
|
+
return;
|
|
2959
|
+
// BQ9tV race guard: skip the reap if any other client already
|
|
2960
|
+
// attached to this entry. The disconnect-reaper in server.ts
|
|
2961
|
+
// sets `requireZeroAttaches: true` because it only wants to
|
|
2962
|
+
// reap when the spawn-owner that disconnected truly was the
|
|
2963
|
+
// sole client. Counter increment + this check both run
|
|
2964
|
+
// synchronously, so no microtask boundary lets a race slip
|
|
2965
|
+
// through.
|
|
2966
|
+
// BkwQP: when bailing because of an attach, set the tombstone
|
|
2967
|
+
// so a later `detachClient` (that brings attachCount back to
|
|
2968
|
+
// 0) can complete the deferred reap. Without this, both
|
|
2969
|
+
// spawn-owner-and-attach disconnecting leaves the session
|
|
2970
|
+
// orphaned forever (spawn owner's reap bails here, attach's
|
|
2971
|
+
// detach does nothing structural).
|
|
2972
|
+
if (opts?.requireZeroAttaches && entry.attachCount > 0) {
|
|
2973
|
+
entry.spawnOwnerWantedKill = true;
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
// Remove from the state eagerly so concurrent `spawnOrAttach`
|
|
2977
|
+
// can't reattach to a session we're tearing down.
|
|
2978
|
+
if (defaultEntry === entry)
|
|
2979
|
+
defaultEntry = undefined;
|
|
2980
|
+
byId.delete(sessionId);
|
|
2981
|
+
// Detach from the channel. The channel dies only when its LAST
|
|
2982
|
+
// session leaves — other sessions on the same channel keep
|
|
2983
|
+
// running.
|
|
2984
|
+
const ci = detachSessionIdFromEntryChannel(channelInfo, aliveChannels, entry, sessionId);
|
|
2985
|
+
// PR 14b fix (codex round 5): tombstone the killed sessionId
|
|
2986
|
+
// so any in-flight `extNotification` from the (about-to-be-
|
|
2987
|
+
// killed) child can't seed the early-event buffer for a
|
|
2988
|
+
// subsequent load/resume of the same persisted id. See the
|
|
2989
|
+
// matching guard in BridgeClient.bufferEarlyEvent.
|
|
2990
|
+
ci?.client.markSessionClosed(sessionId);
|
|
2991
|
+
// Resolve any still-pending permission as cancelled (matches the
|
|
2992
|
+
// shutdown path) so callers awaiting requestPermission unwind.
|
|
2993
|
+
for (const id of Array.from(entry.pendingPermissionIds)) {
|
|
2994
|
+
resolvePending(id, { outcome: { outcome: 'cancelled' } });
|
|
2995
|
+
}
|
|
2996
|
+
// Publish `session_died` BEFORE closing the bus. After the eager
|
|
2997
|
+
// `byId.delete` above, the channel.exited handler's
|
|
2998
|
+
// `byId.get(...)` returns undefined so the automatic publish
|
|
2999
|
+
// at crash time wouldn't fire. SSE subscribers need this
|
|
3000
|
+
// terminal frame to know the session is gone.
|
|
3001
|
+
try {
|
|
3002
|
+
entry.events.publish({
|
|
3003
|
+
type: 'session_died',
|
|
3004
|
+
data: { sessionId, reason: 'killed' },
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
catch {
|
|
3008
|
+
/* bus already closed */
|
|
3009
|
+
}
|
|
3010
|
+
entry.events.close();
|
|
3011
|
+
// Only kill the channel when no other sessions remain AND no
|
|
3012
|
+
// restore is in flight. ACP doesn't expose a per-session "close"
|
|
3013
|
+
// call on the agent side, so the agent's `sessions: Map<string,
|
|
3014
|
+
// Session>` grows by one until the channel dies — bounded by
|
|
3015
|
+
// `maxSessions` (default 20) so memory is capped. FIXME(stage-
|
|
3016
|
+
// 1.5): if ACP grows a `closeSession` notification, send it
|
|
3017
|
+
// here so the agent can drop the entry from its map immediately
|
|
3018
|
+
// rather than at channel exit. (`channelInfo` itself is cleared
|
|
3019
|
+
// by the `channel.exited` handler once the OS reaps the child —
|
|
3020
|
+
// tanzhenxin BkUyD invariant.)
|
|
3021
|
+
//
|
|
3022
|
+
// `pendingRestoreIds` covers in-flight `session/load` and
|
|
3023
|
+
// `session/resume` calls that haven't yet registered into
|
|
3024
|
+
// `sessionIds`. Killing the channel out from under them would
|
|
3025
|
+
// SIGTERM the restore mid-flight and 500 the caller for a
|
|
3026
|
+
// failure orthogonal to their request.
|
|
3027
|
+
if (ci && ci.sessionIds.size === 0 && ci.pendingRestoreIds.size === 0) {
|
|
3028
|
+
// Mark dying SYNCHRONOUSLY before the await so a concurrent
|
|
3029
|
+
// `spawnOrAttach` arriving during the SIGTERM grace window
|
|
3030
|
+
// doesn't attach to a transport we're tearing down — without
|
|
3031
|
+
// this it would land the caller with a sessionId that 404s on
|
|
3032
|
+
// every follow-up once `channel.exited` fires (the equivalent
|
|
3033
|
+
// of the pre-PR eager `byWorkspaceChannel.delete()` from the
|
|
3034
|
+
// Stage 1 routing era). `channelInfo` stays set until OS reap
|
|
3035
|
+
// so `killAllSync` still finds a target (BkUyD).
|
|
3036
|
+
ci.isDying = true;
|
|
3037
|
+
await ci.channel.kill().catch(() => {
|
|
3038
|
+
// Best-effort kill — channel may already be dead.
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
},
|
|
3042
|
+
async detachClient(sessionId, clientId) {
|
|
3043
|
+
// tanzhenxin issue 2: the BQ9tV `attachCount` race guard is
|
|
3044
|
+
// monotonic — once any attach bumps it, the spawn-owner's
|
|
3045
|
+
// disconnect-reaper becomes a permanent no-op even if the
|
|
3046
|
+
// attaching client itself disconnected. This is the symmetric
|
|
3047
|
+
// rollback the server's `!res.writable && session.attached`
|
|
3048
|
+
// path calls into.
|
|
3049
|
+
//
|
|
3050
|
+
// BkwQP: detachClient ONLY decrements; it does NOT reap on
|
|
3051
|
+
// its own. Reaping is the spawn-owner's responsibility, and
|
|
3052
|
+
// the spawn owner's `killSession({ requireZeroAttaches: true })`
|
|
3053
|
+
// sets `spawnOwnerWantedKill` if they had to bail because we
|
|
3054
|
+
// already had `attachCount > 0`. Only when that tombstone is
|
|
3055
|
+
// set do we complete the deferred reap from here. Without
|
|
3056
|
+
// this restraint, a transient attach disconnecting would
|
|
3057
|
+
// reap a still-valid session whose spawn owner is alive but
|
|
3058
|
+
// hasn't opened SSE yet.
|
|
3059
|
+
const entry = byId.get(sessionId);
|
|
3060
|
+
if (!entry)
|
|
3061
|
+
return;
|
|
3062
|
+
if (entry.attachCount > 0)
|
|
3063
|
+
entry.attachCount--;
|
|
3064
|
+
unregisterClient(entry, clientId);
|
|
3065
|
+
if (entry.spawnOwnerWantedKill &&
|
|
3066
|
+
entry.attachCount === 0 &&
|
|
3067
|
+
entry.events.subscriberCount === 0) {
|
|
3068
|
+
// Defer-completed reap. Re-use killSession's logic; pass
|
|
3069
|
+
// `requireZeroAttaches: false` (default) because we've
|
|
3070
|
+
// already validated all the conditions ourselves.
|
|
3071
|
+
await this.killSession(sessionId).catch(() => {
|
|
3072
|
+
/* best-effort; channel.exited will eventually reap anyway */
|
|
3073
|
+
});
|
|
3074
|
+
}
|
|
3075
|
+
},
|
|
3076
|
+
killAllSync() {
|
|
3077
|
+
// Bd1y6: synchronous best-effort SIGKILL on EVERY alive channel
|
|
3078
|
+
// (typically 1, but during a `killSession`-then-`spawnOrAttach`
|
|
3079
|
+
// overlap there can be 2 — the dying one in `aliveChannels`
|
|
3080
|
+
// plus a fresh attach-target in `channelInfo`). Set
|
|
3081
|
+
// `shuttingDown` so any racing async path fails fast.
|
|
3082
|
+
//
|
|
3083
|
+
// tanzhenxin BkUyD: iterate `aliveChannels` (the OS-level "still
|
|
3084
|
+
// alive" source of truth) — `channelInfo` only points at the
|
|
3085
|
+
// CURRENT attach target, missing any dying channel whose
|
|
3086
|
+
// `channel.exited` hasn't fired yet. Without this, a fresh
|
|
3087
|
+
// spawn overwriting `channelInfo` during the prior channel's
|
|
3088
|
+
// SIGTERM grace would leave the dying child without SIGKILL
|
|
3089
|
+
// escalation when `process.exit(1)` fires.
|
|
3090
|
+
shuttingDown = true;
|
|
3091
|
+
const channels = Array.from(aliveChannels);
|
|
3092
|
+
defaultEntry = undefined;
|
|
3093
|
+
byId.clear();
|
|
3094
|
+
for (const info of channels) {
|
|
3095
|
+
try {
|
|
3096
|
+
info.channel.killSync();
|
|
3097
|
+
}
|
|
3098
|
+
catch {
|
|
3099
|
+
/* best-effort — already-dead child / pid race */
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
},
|
|
3103
|
+
async shutdown() {
|
|
3104
|
+
// Set BEFORE the snapshot so any racing `spawnOrAttach` triggered
|
|
3105
|
+
// by an in-flight HTTP connection after `runQwenServe.close()`
|
|
3106
|
+
// entered the bridge.shutdown() phase fails fast instead of
|
|
3107
|
+
// spawning a child this teardown won't see.
|
|
3108
|
+
shuttingDown = true;
|
|
3109
|
+
const entries = Array.from(byId.values());
|
|
3110
|
+
// Snapshot every alive channel (typically 1; up to 2 during a
|
|
3111
|
+
// `killSession`-then-`spawnOrAttach` overlap) — entries are
|
|
3112
|
+
// intentionally NOT removed from `aliveChannels` here; their
|
|
3113
|
+
// `channel.exited` handlers clear them once the OS has reaped
|
|
3114
|
+
// each child. That preserves the BkUyD invariant: a
|
|
3115
|
+
// double-Ctrl+C arriving mid-SIGTERM-grace can still find every
|
|
3116
|
+
// alive channel via `killAllSync`. Marking each `isDying` makes
|
|
3117
|
+
// them invisible to any racing `ensureChannel` call — but
|
|
3118
|
+
// `shuttingDown` already blocks new `spawnOrAttach` upstream,
|
|
3119
|
+
// so this is mostly belt-and-suspenders (a direct internal
|
|
3120
|
+
// `ensureChannel` past the gate would still see the dying
|
|
3121
|
+
// state and not attach).
|
|
3122
|
+
const channels = Array.from(aliveChannels);
|
|
3123
|
+
for (const ci of channels)
|
|
3124
|
+
ci.isDying = true;
|
|
3125
|
+
// Resolve every still-pending permission as cancelled before clearing
|
|
3126
|
+
// the maps so callers awaiting `requestPermission` unwind cleanly.
|
|
3127
|
+
for (const e of entries) {
|
|
3128
|
+
const ids = Array.from(e.pendingPermissionIds);
|
|
3129
|
+
for (const id of ids) {
|
|
3130
|
+
resolvePending(id, { outcome: { outcome: 'cancelled' } });
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
defaultEntry = undefined;
|
|
3134
|
+
byId.clear();
|
|
3135
|
+
pendingPermissions.clear();
|
|
3136
|
+
// Publish a terminal `session_died` BEFORE closing each bus so SSE
|
|
3137
|
+
// subscribers can distinguish "daemon shut down" from a transient
|
|
3138
|
+
// network error and don't sit indefinitely retrying. The
|
|
3139
|
+
// channel.exited handler also publishes this on a child crash,
|
|
3140
|
+
// but at shutdown time the entry has already been removed from
|
|
3141
|
+
// `byId` (above), so the handler's `byId.get(...)` is undefined
|
|
3142
|
+
// and the automatic publish wouldn't fire.
|
|
3143
|
+
for (const e of entries) {
|
|
3144
|
+
try {
|
|
3145
|
+
e.events.publish({
|
|
3146
|
+
type: 'session_died',
|
|
3147
|
+
data: { sessionId: e.sessionId, reason: 'daemon_shutdown' },
|
|
3148
|
+
});
|
|
3149
|
+
}
|
|
3150
|
+
catch {
|
|
3151
|
+
/* bus already closed */
|
|
3152
|
+
}
|
|
3153
|
+
e.events.close();
|
|
3154
|
+
}
|
|
3155
|
+
// Wait for in-flight channel + session spawns. The snapshot
|
|
3156
|
+
// above only sees what's already registered; a doSpawn past
|
|
3157
|
+
// `newSession()` but pre-`byId.set` is missed, as is an
|
|
3158
|
+
// `ensureChannel` past `channelFactory()` but pre-`channelInfo
|
|
3159
|
+
// = info`. The late-shutdown re-checks at doSpawn/ensureChannel
|
|
3160
|
+
// catch both — but without these awaits, `bridge.shutdown()`
|
|
3161
|
+
// would resolve before they finish, and the orphan stderr
|
|
3162
|
+
// error from a half-built child would fire AFTER the daemon
|
|
3163
|
+
// claimed graceful shutdown (log-confusing).
|
|
3164
|
+
const inFlightSessionAwaits = Array.from(inFlightSpawns.values()).map((p) => p.then(() => undefined, () => undefined));
|
|
3165
|
+
const inFlightRestoreAwaits = Array.from(inFlightRestores.values()).map((restore) => restore.promise.then(() => undefined, () => undefined));
|
|
3166
|
+
const inFlightChannelAwait = inFlightChannelSpawn
|
|
3167
|
+
? inFlightChannelSpawn.then(() => undefined, () => undefined)
|
|
3168
|
+
: Promise.resolve();
|
|
3169
|
+
await Promise.all([
|
|
3170
|
+
...channels.map((ci) => ci.channel.kill().catch(() => { })),
|
|
3171
|
+
...inFlightSessionAwaits,
|
|
3172
|
+
...inFlightRestoreAwaits,
|
|
3173
|
+
inFlightChannelAwait,
|
|
3174
|
+
]);
|
|
3175
|
+
},
|
|
3176
|
+
};
|
|
3177
|
+
}
|
|
3178
|
+
/**
|
|
3179
|
+
* Human-readable label for a `fs.Stats` object's kind, used in the
|
|
3180
|
+
* `readTextFile` "not a regular file" rejection message (BX8YO).
|
|
3181
|
+
* Sockets, pipes, char-devices etc. all report `size: 0` but stream
|
|
3182
|
+
* unbounded data; the operator wants to know which one they hit so
|
|
3183
|
+
* the path-mistake is obvious.
|
|
3184
|
+
*/
|
|
3185
|
+
function describeStatKind(stats) {
|
|
3186
|
+
if (stats.isDirectory())
|
|
3187
|
+
return 'directory';
|
|
3188
|
+
if (stats.isSymbolicLink())
|
|
3189
|
+
return 'symlink';
|
|
3190
|
+
if (stats.isCharacterDevice())
|
|
3191
|
+
return 'character device';
|
|
3192
|
+
if (stats.isBlockDevice())
|
|
3193
|
+
return 'block device';
|
|
3194
|
+
if (stats.isFIFO())
|
|
3195
|
+
return 'named pipe (FIFO)';
|
|
3196
|
+
if (stats.isSocket())
|
|
3197
|
+
return 'socket';
|
|
3198
|
+
return 'non-regular file';
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* Extract the line range `[startLine, endLine)` (0-based) from a string
|
|
3202
|
+
* without allocating a per-line array. Equivalent to
|
|
3203
|
+
* `content.split('\n').slice(startLine, endLine).join('\n')` but
|
|
3204
|
+
* O(file size) string scan rather than O(file size) string + O(line
|
|
3205
|
+
* count) array. Matters for the partial-read path of `readTextFile`
|
|
3206
|
+
* where the limit is small and the file is large.
|
|
3207
|
+
*/
|
|
3208
|
+
function sliceLineRange(content, startLine, endLine) {
|
|
3209
|
+
// Find the byte offset where line `startLine` begins.
|
|
3210
|
+
let offset = 0;
|
|
3211
|
+
for (let i = 0; i < startLine; i++) {
|
|
3212
|
+
const nl = content.indexOf('\n', offset);
|
|
3213
|
+
if (nl === -1)
|
|
3214
|
+
return '';
|
|
3215
|
+
offset = nl + 1;
|
|
3216
|
+
}
|
|
3217
|
+
if (endLine === undefined)
|
|
3218
|
+
return content.slice(offset);
|
|
3219
|
+
// Walk `endLine - startLine` newlines forward to find the end byte.
|
|
3220
|
+
let end = offset;
|
|
3221
|
+
const want = endLine - startLine;
|
|
3222
|
+
for (let i = 0; i < want; i++) {
|
|
3223
|
+
const nl = content.indexOf('\n', end);
|
|
3224
|
+
if (nl === -1)
|
|
3225
|
+
return content.slice(offset);
|
|
3226
|
+
end = nl + 1;
|
|
3227
|
+
}
|
|
3228
|
+
// Trim the trailing `\n` so the slice mirrors `lines.slice(...).join('\n')`.
|
|
3229
|
+
return content.slice(offset, end > offset ? end - 1 : end);
|
|
3230
|
+
}
|
|
3231
|
+
/**
|
|
3232
|
+
* Re-export of the workspace canonicalizer for callers that historically
|
|
3233
|
+
* imported it from `httpAcpBridge.ts`. The implementation was extracted
|
|
3234
|
+
* to `./fs/paths.ts` in #4175 PR 18 (commit 1) so the forthcoming
|
|
3235
|
+
* `WorkspaceFileSystem` boundary can reuse the same primitive without
|
|
3236
|
+
* pulling in the 3.6k-line bridge module. See `./fs/paths.ts` for the
|
|
3237
|
+
* cross-module contract that governs this function.
|
|
3238
|
+
*/
|
|
3239
|
+
export { canonicalizeWorkspace };
|
|
3240
|
+
/**
|
|
3241
|
+
* Race `p` against a timeout. The timeout REJECTS the returned
|
|
3242
|
+
* promise but does NOT abort the underlying operation — `p` keeps
|
|
3243
|
+
* running to completion (or its own failure) and its eventual
|
|
3244
|
+
* resolution is silently dropped.
|
|
3245
|
+
*
|
|
3246
|
+
* Stage 1 limitation: for `unstable_setSessionModel` the agent may
|
|
3247
|
+
* complete the model switch AFTER we surfaced the timeout to the
|
|
3248
|
+
* HTTP caller, leading to drift between caller's perceived model
|
|
3249
|
+
* and agent's actual model. Subscribers also see contradictory
|
|
3250
|
+
* SSE events (`model_switch_failed` from the timeout, then a late
|
|
3251
|
+
* `model_switched` if the agent succeeds). Acceptable for Stage 1
|
|
3252
|
+
* because:
|
|
3253
|
+
* 1. ACP's `unstable_setSessionModel` doesn't accept a cancel
|
|
3254
|
+
* signal yet (the SDK's `prompt` does, hence `sendPrompt`'s
|
|
3255
|
+
* explicit `cancel` notification on abort).
|
|
3256
|
+
* 2. Model switches complete in milliseconds in practice; a
|
|
3257
|
+
* timeout firing means the agent is genuinely wedged, not
|
|
3258
|
+
* just slow, and would have been DOA anyway.
|
|
3259
|
+
* Stage 2 will add abort plumbing once ACP exposes a cancel hook
|
|
3260
|
+
* for `unstable_setSessionModel`. Tracked in the model-change
|
|
3261
|
+
* concurrency notes in `applyModelServiceId`. BSA0C suggested a
|
|
3262
|
+
* `modelSwitchTimedOut` flag + `model_switch_late_success`
|
|
3263
|
+
* synthetic frame for full observability of the divergent state;
|
|
3264
|
+
* recorded as a Stage 2 follow-up so the timeout/late-success
|
|
3265
|
+
* handshake is implemented once across both ACP-side cancel and
|
|
3266
|
+
* the bridge-side state flag (rather than just papering over the
|
|
3267
|
+
* symptom).
|
|
3268
|
+
*/
|
|
3269
|
+
async function withTimeout(p, ms, label) {
|
|
3270
|
+
let timer;
|
|
3271
|
+
const timeoutP = new Promise((_, reject) => {
|
|
3272
|
+
timer = setTimeout(() => reject(new BridgeTimeoutError(label, ms)), ms);
|
|
3273
|
+
});
|
|
3274
|
+
try {
|
|
3275
|
+
return await Promise.race([p, timeoutP]);
|
|
3276
|
+
}
|
|
3277
|
+
finally {
|
|
3278
|
+
if (timer)
|
|
3279
|
+
clearTimeout(timer);
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
/**
|
|
3283
|
+
* Default channel factory: spawn the current Node executable running this
|
|
3284
|
+
* CLI's entry script in `--acp` mode. `process.argv[1]` resolves to the qwen
|
|
3285
|
+
* entry script when launched via the `qwen` bin shim.
|
|
3286
|
+
*
|
|
3287
|
+
* Note on `cwd`: CodeQL flags the `workspaceCwd` flow into `spawn({cwd})`
|
|
3288
|
+
* as an "uncontrolled data used in path expression" finding. That's the
|
|
3289
|
+
* Stage 1 trust model speaking — the caller (a token-authenticated HTTP
|
|
3290
|
+
* client) is treated as an extension of the operator. The agent already
|
|
3291
|
+
* runs as the same UID with shell-tool access, so restricting the spawn
|
|
3292
|
+
* cwd to a sandbox here would be theatre. Stage 4+ remote-sandbox swaps
|
|
3293
|
+
* this factory for a sandbox-aware variant; see issue #3803 §11.
|
|
3294
|
+
*/
|
|
3295
|
+
export const defaultSpawnChannelFactory = async (workspaceCwd, childEnvOverrides) => {
|
|
3296
|
+
// Resolution order:
|
|
3297
|
+
// 1. `QWEN_CLI_ENTRY` env override — escape hatch for non-standard
|
|
3298
|
+
// launch paths (bundled binaries, npx wrappers, `node -e`,
|
|
3299
|
+
// `tsx ./src/...`, custom shims, container images that
|
|
3300
|
+
// relocate the entry script). Anyone hitting "process.argv[1]
|
|
3301
|
+
// is empty" or "process.argv[1] points at the wrong file" can
|
|
3302
|
+
// set this without code changes.
|
|
3303
|
+
// 2. `process.argv[1]` — works when launched via the `qwen` bin
|
|
3304
|
+
// shim, which is the common path.
|
|
3305
|
+
// Fail loudly with an actionable error if neither resolves.
|
|
3306
|
+
const cliEntry = process.env['QWEN_CLI_ENTRY'] || process.argv[1];
|
|
3307
|
+
if (!cliEntry) {
|
|
3308
|
+
throw new MissingCliEntryError();
|
|
3309
|
+
}
|
|
3310
|
+
// Each session takes ~3 file descriptors (stdin/stdout/stderr) for the
|
|
3311
|
+
// child plus a few sockets. Operators running many concurrent sessions
|
|
3312
|
+
// should bump `ulimit -n` accordingly. Stage 1 doesn't pre-flight FD
|
|
3313
|
+
// headroom — Stage 2 in-process drops the per-session FD cost entirely.
|
|
3314
|
+
// Child stderr is piped (NOT `inherit`ed) so we can prefix each
|
|
3315
|
+
// line with `[serve pid=… cwd=…]` before forwarding to the
|
|
3316
|
+
// daemon's stderr — see the prefix-and-forward loop below the
|
|
3317
|
+
// `spawn(...)` call. Sessions are still interleaved on the
|
|
3318
|
+
// daemon's stderr stream but each line carries its own session
|
|
3319
|
+
// identifier, so operators can `grep pid=12345` to pull one
|
|
3320
|
+
// session's trace cleanly. Stage 4+ remote sandboxes will isolate
|
|
3321
|
+
// stderr at the transport level.
|
|
3322
|
+
//
|
|
3323
|
+
// Note: spawning `process.execPath` only works when the entry script can
|
|
3324
|
+
// be loaded by raw Node. In dev (e.g. `npm run dev` via `tsx`) the entry
|
|
3325
|
+
// is a `.ts` file Node can't run; users should `npm run build` before
|
|
3326
|
+
// `qwen serve` or set `process.execPath` to a tsx-aware shim. Stage 1
|
|
3327
|
+
// accepts this — the daemon is meant for built deployments.
|
|
3328
|
+
// Pass through the daemon's full environment to the child, scrubbing
|
|
3329
|
+
// ONLY daemon-internal secrets (see SCRUBBED_CHILD_ENV_KEYS at module
|
|
3330
|
+
// scope). An earlier version used an allowlist, but that broke the
|
|
3331
|
+
// common deployment shape: users export `OPENAI_API_KEY` /
|
|
3332
|
+
// `ANTHROPIC_API_KEY` / `QWEN_*` / `DASHSCOPE_API_KEY` / a custom
|
|
3333
|
+
// `modelProviders[].envKey` to authenticate the agent's LLM calls,
|
|
3334
|
+
// and core's model config resolves those from `process.env`. An
|
|
3335
|
+
// exhaustive allowlist can't enumerate user-defined provider keys,
|
|
3336
|
+
// so the agent ends up unable to authenticate.
|
|
3337
|
+
//
|
|
3338
|
+
// Threat-model rationale: the agent already runs as the same UID
|
|
3339
|
+
// with shell-tool access — anything in `~/.bashrc`, `~/.npmrc`,
|
|
3340
|
+
// `~/.aws/credentials`, etc. is reachable by prompt injection
|
|
3341
|
+
// regardless of what we put in `env`. The env passthrough is not
|
|
3342
|
+
// the security boundary; the user-as-trust-root is. The only thing
|
|
3343
|
+
// we MUST scrub is `QWEN_SERVER_TOKEN` (daemon-only auth that
|
|
3344
|
+
// would let a prompt-injected shell turn the agent into an
|
|
3345
|
+
// authenticated client of its own daemon — escalation the agent
|
|
3346
|
+
// doesn't otherwise have).
|
|
3347
|
+
const childEnv = { ...process.env };
|
|
3348
|
+
for (const key of SCRUBBED_CHILD_ENV_KEYS) {
|
|
3349
|
+
delete childEnv[key];
|
|
3350
|
+
}
|
|
3351
|
+
// PR 14 fix (review #4247 wenshao R5 runQwenServe.ts:216): apply
|
|
3352
|
+
// per-handle env overrides on top of the process.env snapshot.
|
|
3353
|
+
// `undefined` value means "delete this var from the child env" so
|
|
3354
|
+
// an embedded caller can scrub a stale inherited var without
|
|
3355
|
+
// having to mutate the daemon's global process.env. Applied AFTER
|
|
3356
|
+
// `SCRUBBED_CHILD_ENV_KEYS` so the daemon-only secret list still
|
|
3357
|
+
// wins (operators can't override the scrub by passing
|
|
3358
|
+
// `QWEN_SERVER_TOKEN` in overrides — defense in depth).
|
|
3359
|
+
if (childEnvOverrides) {
|
|
3360
|
+
for (const [key, value] of Object.entries(childEnvOverrides)) {
|
|
3361
|
+
if (SCRUBBED_CHILD_ENV_KEYS.has(key))
|
|
3362
|
+
continue;
|
|
3363
|
+
if (value === undefined) {
|
|
3364
|
+
delete childEnv[key];
|
|
3365
|
+
}
|
|
3366
|
+
else {
|
|
3367
|
+
childEnv[key] = value;
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
// CodeQL `js/path-injection` flags the `cwd: workspaceCwd` flow.
|
|
3372
|
+
// Stage 1 trust model accepts this — see the function-level comment
|
|
3373
|
+
// above for the design rationale. Defense-in-depth: the cwd is
|
|
3374
|
+
// canonicalized via `path.resolve()` upstream in `spawnOrAttach`,
|
|
3375
|
+
// and `spawn`'s `cwd` only changes the child's working directory,
|
|
3376
|
+
// it doesn't pass through any shell.
|
|
3377
|
+
//
|
|
3378
|
+
// NOTE: GitHub Code Scanning does NOT honor inline `// lgtm` /
|
|
3379
|
+
// `// codeql` annotations (LGTM.com retired in 2021). Suppressing
|
|
3380
|
+
// this alert requires either (a) UI dismissal as "won't fix" with
|
|
3381
|
+
// the rationale above, or (b) a repo-level
|
|
3382
|
+
// `.github/codeql/codeql-config.yml` query exclusion. Both are
|
|
3383
|
+
// out of scope for a code-only PR; flagging here for the human
|
|
3384
|
+
// reviewer.
|
|
3385
|
+
const child = spawn(process.execPath, [cliEntry, '--acp'], {
|
|
3386
|
+
cwd: workspaceCwd,
|
|
3387
|
+
// Pipe stderr (was: 'inherit') so we can prefix each line with
|
|
3388
|
+
// the spawn's pid + workspace, making per-session crash output
|
|
3389
|
+
// attributable. Bare 'inherit' sends every child's stderr to
|
|
3390
|
+
// the daemon's stderr verbatim and unprefixed — under any
|
|
3391
|
+
// multi-session load the operator's log becomes a salad of
|
|
3392
|
+
// unattributed traces.
|
|
3393
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
3394
|
+
env: childEnv,
|
|
3395
|
+
});
|
|
3396
|
+
// Forward child stderr to the daemon's stderr line-by-line, with a
|
|
3397
|
+
// `[serve pid=… cwd=…]` prefix on each line so operators can
|
|
3398
|
+
// correlate stack traces back to the spawning request. Best-effort:
|
|
3399
|
+
// a child that prints partial lines without a trailing newline is
|
|
3400
|
+
// flushed when the stream emits `end`.
|
|
3401
|
+
if (child.stderr) {
|
|
3402
|
+
let buf = '';
|
|
3403
|
+
const prefix = `[serve pid=${child.pid} cwd=${workspaceCwd}] `;
|
|
3404
|
+
// BRAp3 cap: a buggy child that writes a huge stderr line, or
|
|
3405
|
+
// never emits `\n`, would otherwise grow `buf` per spawn
|
|
3406
|
+
// unboundedly. 64 KiB is generous for the longest legitimate
|
|
3407
|
+
// stack trace line we'd expect from a Node child; anything
|
|
3408
|
+
// past that gets force-flushed with a `[truncated]` marker so
|
|
3409
|
+
// the operator still sees a prefix-attributed log line and
|
|
3410
|
+
// memory stays bounded. We DON'T drop content — we flush
|
|
3411
|
+
// chunks at the cap. (Picking 64 KiB matches our SSE per-frame
|
|
3412
|
+
// write budget; anything above this already implies the child
|
|
3413
|
+
// is misbehaving.)
|
|
3414
|
+
const STDERR_LINE_CAP_CHARS = 64 * 1024;
|
|
3415
|
+
const flush = (line) => {
|
|
3416
|
+
if (line.length > 0)
|
|
3417
|
+
process.stderr.write(prefix + line + '\n');
|
|
3418
|
+
};
|
|
3419
|
+
child.stderr.setEncoding('utf8');
|
|
3420
|
+
child.stderr.on('data', (chunk) => {
|
|
3421
|
+
buf += chunk;
|
|
3422
|
+
let nl = buf.indexOf('\n');
|
|
3423
|
+
while (nl !== -1) {
|
|
3424
|
+
flush(buf.slice(0, nl));
|
|
3425
|
+
buf = buf.slice(nl + 1);
|
|
3426
|
+
nl = buf.indexOf('\n');
|
|
3427
|
+
}
|
|
3428
|
+
// Force-flush the unterminated tail if it's grown past the cap
|
|
3429
|
+
// — keeps memory bounded against a `\n`-less stderr storm.
|
|
3430
|
+
while (buf.length > STDERR_LINE_CAP_CHARS) {
|
|
3431
|
+
flush(buf.slice(0, STDERR_LINE_CAP_CHARS) + ' [truncated]');
|
|
3432
|
+
buf = buf.slice(STDERR_LINE_CAP_CHARS);
|
|
3433
|
+
}
|
|
3434
|
+
});
|
|
3435
|
+
child.stderr.on('end', () => {
|
|
3436
|
+
if (buf.length > 0)
|
|
3437
|
+
flush(buf);
|
|
3438
|
+
});
|
|
3439
|
+
child.stderr.on('error', () => {
|
|
3440
|
+
// Don't crash the daemon if the pipe breaks; the child is
|
|
3441
|
+
// already gone or about to be.
|
|
3442
|
+
});
|
|
3443
|
+
}
|
|
3444
|
+
// Build the `exited` promise BEFORE checking stdin/stdout so the listener
|
|
3445
|
+
// is in place before any error event can fire. We treat both `exit` and
|
|
3446
|
+
// `error` as termination — without an `error` listener Node would treat
|
|
3447
|
+
// an async spawn failure (ENOMEM, EACCES, …) as an unhandled error and
|
|
3448
|
+
// crash the whole daemon.
|
|
3449
|
+
const exited = new Promise((resolve) => {
|
|
3450
|
+
let resolved = false;
|
|
3451
|
+
const finish = (info) => {
|
|
3452
|
+
if (resolved)
|
|
3453
|
+
return;
|
|
3454
|
+
resolved = true;
|
|
3455
|
+
resolve(info);
|
|
3456
|
+
};
|
|
3457
|
+
child.once('exit', (code, signal) => finish({ exitCode: code, signalCode: signal }));
|
|
3458
|
+
child.once('error', () => finish(undefined));
|
|
3459
|
+
});
|
|
3460
|
+
if (!child.stdin || !child.stdout) {
|
|
3461
|
+
child.kill('SIGKILL');
|
|
3462
|
+
throw new Error('Spawned ACP child has no stdin/stdout — cannot establish NDJSON channel.');
|
|
3463
|
+
}
|
|
3464
|
+
const writable = Writable.toWeb(child.stdin);
|
|
3465
|
+
const readable = Readable.toWeb(child.stdout);
|
|
3466
|
+
const stream = ndJsonStream(writable, readable);
|
|
3467
|
+
return {
|
|
3468
|
+
stream,
|
|
3469
|
+
kill: () => killChild(child),
|
|
3470
|
+
killSync: () => {
|
|
3471
|
+
// Bd1y6: synchronous SIGKILL for the double-signal force-exit
|
|
3472
|
+
// path. Skip if child already exited (kill on a dead process
|
|
3473
|
+
// raises an OS-level error that's noise here).
|
|
3474
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
3475
|
+
try {
|
|
3476
|
+
child.kill('SIGKILL');
|
|
3477
|
+
}
|
|
3478
|
+
catch {
|
|
3479
|
+
/* already dead / pid recycled — ignore */
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
},
|
|
3483
|
+
exited,
|
|
3484
|
+
};
|
|
3485
|
+
};
|
|
3486
|
+
const KILL_HARD_DEADLINE_MS = 10_000;
|
|
3487
|
+
/**
|
|
3488
|
+
* Environment variables stripped from the spawned `qwen --acp` child's
|
|
3489
|
+
* environment. Everything else is passed through — see the
|
|
3490
|
+
* threat-model rationale at the call site in `defaultSpawnChannelFactory`.
|
|
3491
|
+
*
|
|
3492
|
+
* Currently just `QWEN_SERVER_TOKEN`: the daemon's own bearer token,
|
|
3493
|
+
* which the agent doesn't need (it speaks to the daemon over stdio,
|
|
3494
|
+
* not HTTP). Leaving it in the child's env would let prompt injection
|
|
3495
|
+
* turn the agent into an authenticated client of its own daemon — an
|
|
3496
|
+
* escalation the agent doesn't otherwise have.
|
|
3497
|
+
*
|
|
3498
|
+
* **WARNING**: this denylist is correct *only because the agent
|
|
3499
|
+
* already has unrestricted shell-tool access* — anything in the env
|
|
3500
|
+
* is reachable via `~/.bashrc`/`~/.aws/credentials`/etc. anyway.
|
|
3501
|
+
* Any future mode that **removes** shell-tool access (e.g. a
|
|
3502
|
+
* sandbox-locked agent variant) MUST switch this back to an
|
|
3503
|
+
* allowlist OR significantly expand the denylist to cover common
|
|
3504
|
+
* provider/CI/cloud secret prefixes (`OPENAI_*`, `ANTHROPIC_*`,
|
|
3505
|
+
* `AWS_*`, `GITHUB_TOKEN`, `CI_*`, `*_API_KEY`, `*_SECRET`, …).
|
|
3506
|
+
* See issue #3803 §11 for the Stage 4+ remote-sandbox plan.
|
|
3507
|
+
*
|
|
3508
|
+
* Defined at module scope so the Set is allocated once at load.
|
|
3509
|
+
*/
|
|
3510
|
+
const SCRUBBED_CHILD_ENV_KEYS = new Set([
|
|
3511
|
+
'QWEN_SERVER_TOKEN',
|
|
3512
|
+
]);
|
|
3513
|
+
function killChild(child) {
|
|
3514
|
+
return new Promise((resolve) => {
|
|
3515
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
3516
|
+
resolve();
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3519
|
+
let resolved = false;
|
|
3520
|
+
const finish = () => {
|
|
3521
|
+
if (resolved)
|
|
3522
|
+
return;
|
|
3523
|
+
resolved = true;
|
|
3524
|
+
child.removeListener('exit', finish);
|
|
3525
|
+
resolve();
|
|
3526
|
+
};
|
|
3527
|
+
child.once('exit', finish);
|
|
3528
|
+
try {
|
|
3529
|
+
child.kill('SIGTERM');
|
|
3530
|
+
}
|
|
3531
|
+
catch {
|
|
3532
|
+
finish();
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
setTimeout(() => {
|
|
3536
|
+
if (!resolved && child.exitCode === null && child.signalCode === null) {
|
|
3537
|
+
try {
|
|
3538
|
+
child.kill('SIGKILL');
|
|
3539
|
+
}
|
|
3540
|
+
catch {
|
|
3541
|
+
/* swallow */
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
}, 5_000).unref();
|
|
3545
|
+
// Even SIGKILL doesn't return if the child is in uninterruptible
|
|
3546
|
+
// sleep (D-state, e.g. NFS read blocked on a dead server). Without
|
|
3547
|
+
// this hard deadline, `bridge.shutdown()`'s `Promise.all` waits
|
|
3548
|
+
// forever on that one wedged child and SHUTDOWN_FORCE_CLOSE_MS in
|
|
3549
|
+
// `runQwenServe` only covers `server.close()`, not the bridge.
|
|
3550
|
+
// After the deadline give up: the child is probably stuck in a
|
|
3551
|
+
// kernel call we can't cancel, and `process.exit(0)` will reap it
|
|
3552
|
+
// when the daemon returns to its caller.
|
|
3553
|
+
setTimeout(() => {
|
|
3554
|
+
if (!resolved)
|
|
3555
|
+
finish();
|
|
3556
|
+
}, KILL_HARD_DEADLINE_MS).unref();
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
//# sourceMappingURL=httpAcpBridge.js.map
|