@orion-agents/orion-code 0.1.4 → 0.1.6
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 +73 -38
- package/README.zh-CN.md +32 -10
- package/dist/agents/coder.d.ts.map +1 -1
- package/dist/agents/coder.js.map +1 -1
- package/dist/agents/fork.d.ts +12 -4
- package/dist/agents/fork.d.ts.map +1 -1
- package/dist/agents/fork.js +28 -32
- package/dist/agents/fork.js.map +1 -1
- package/dist/agents/leader.d.ts.map +1 -1
- package/dist/agents/leader.js.map +1 -1
- package/dist/agents/worker-pool.d.ts.map +1 -1
- package/dist/agents/worker-pool.js +38 -29
- package/dist/agents/worker-pool.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/context-commands.d.ts +4 -0
- package/dist/commands/context-commands.d.ts.map +1 -0
- package/dist/commands/context-commands.js +74 -0
- package/dist/commands/context-commands.js.map +1 -0
- package/dist/commands/context-tool-command-handlers.d.ts +13 -0
- package/dist/commands/context-tool-command-handlers.d.ts.map +1 -0
- package/dist/commands/context-tool-command-handlers.js +617 -0
- package/dist/commands/context-tool-command-handlers.js.map +1 -0
- package/dist/commands/core-command-handlers.d.ts +12 -0
- package/dist/commands/core-command-handlers.d.ts.map +1 -0
- package/dist/commands/core-command-handlers.js +805 -0
- package/dist/commands/core-command-handlers.js.map +1 -0
- package/dist/commands/diagnostic-command-handlers.d.ts +14 -0
- package/dist/commands/diagnostic-command-handlers.d.ts.map +1 -0
- package/dist/commands/diagnostic-command-handlers.js +1043 -0
- package/dist/commands/diagnostic-command-handlers.js.map +1 -0
- package/dist/commands/diagnostic-commands.d.ts +4 -0
- package/dist/commands/diagnostic-commands.d.ts.map +1 -0
- package/dist/commands/diagnostic-commands.js +175 -0
- package/dist/commands/diagnostic-commands.js.map +1 -0
- package/dist/commands/index.d.ts +9 -10
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +42 -3563
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/legacy-commands.d.ts +4 -0
- package/dist/commands/legacy-commands.d.ts.map +1 -0
- package/dist/commands/legacy-commands.js +44 -0
- package/dist/commands/legacy-commands.js.map +1 -0
- package/dist/commands/model-command-handlers.d.ts +15 -0
- package/dist/commands/model-command-handlers.d.ts.map +1 -0
- package/dist/commands/model-command-handlers.js +526 -0
- package/dist/commands/model-command-handlers.js.map +1 -0
- package/dist/commands/model-commands.d.ts +4 -0
- package/dist/commands/model-commands.d.ts.map +1 -0
- package/dist/commands/model-commands.js +85 -0
- package/dist/commands/model-commands.js.map +1 -0
- package/dist/commands/parser.d.ts +12 -0
- package/dist/commands/parser.d.ts.map +1 -1
- package/dist/commands/parser.js +48 -7
- package/dist/commands/parser.js.map +1 -1
- package/dist/commands/registry.d.ts +4 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +566 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/session-command-handlers.d.ts +10 -0
- package/dist/commands/session-command-handlers.d.ts.map +1 -0
- package/dist/commands/session-command-handlers.js +626 -0
- package/dist/commands/session-command-handlers.js.map +1 -0
- package/dist/commands/session-commands.d.ts +4 -0
- package/dist/commands/session-commands.d.ts.map +1 -0
- package/dist/commands/session-commands.js +102 -0
- package/dist/commands/session-commands.js.map +1 -0
- package/dist/commands/system-commands.d.ts +4 -0
- package/dist/commands/system-commands.d.ts.map +1 -0
- package/dist/commands/system-commands.js +80 -0
- package/dist/commands/system-commands.js.map +1 -0
- package/dist/commands/target-command.d.ts +1 -1
- package/dist/commands/target-command.d.ts.map +1 -1
- package/dist/commands/target-command.js +42 -6
- package/dist/commands/target-command.js.map +1 -1
- package/dist/commands/tool-commands.d.ts +4 -0
- package/dist/commands/tool-commands.d.ts.map +1 -0
- package/dist/commands/tool-commands.js +49 -0
- package/dist/commands/tool-commands.js.map +1 -0
- package/dist/commands/types.d.ts +69 -5
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js +3 -4
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/workflow-command-handlers.d.ts +7 -0
- package/dist/commands/workflow-command-handlers.d.ts.map +1 -0
- package/dist/commands/workflow-command-handlers.js +32 -0
- package/dist/commands/workflow-command-handlers.js.map +1 -0
- package/dist/commands/workflow-commands.d.ts +4 -0
- package/dist/commands/workflow-commands.d.ts.map +1 -0
- package/dist/commands/workflow-commands.js +124 -0
- package/dist/commands/workflow-commands.js.map +1 -0
- package/dist/core/checkpoint.d.ts +12 -4
- package/dist/core/checkpoint.d.ts.map +1 -1
- package/dist/core/checkpoint.js +114 -28
- package/dist/core/checkpoint.js.map +1 -1
- package/dist/core/cost-tracker.d.ts +17 -1
- package/dist/core/cost-tracker.d.ts.map +1 -1
- package/dist/core/cost-tracker.js +24 -8
- package/dist/core/cost-tracker.js.map +1 -1
- package/dist/core/warn-dedup.d.ts +3 -0
- package/dist/core/warn-dedup.d.ts.map +1 -1
- package/dist/core/warn-dedup.js +6 -6
- package/dist/core/warn-dedup.js.map +1 -1
- package/dist/framework/index.d.ts +1 -1
- package/dist/framework/index.d.ts.map +1 -1
- package/dist/framework/index.js.map +1 -1
- package/dist/framework/prompt.d.ts +2 -2
- package/dist/framework/query.d.ts +2 -2
- package/dist/framework/query.d.ts.map +1 -1
- package/dist/framework/query.js +57 -10
- package/dist/framework/query.js.map +1 -1
- package/dist/framework/store.d.ts +15 -6
- package/dist/framework/store.d.ts.map +1 -1
- package/dist/framework/store.js +18 -0
- package/dist/framework/store.js.map +1 -1
- package/dist/framework/tool-scheduler.d.ts +16 -13
- package/dist/framework/tool-scheduler.d.ts.map +1 -1
- package/dist/framework/tool-scheduler.js +155 -38
- package/dist/framework/tool-scheduler.js.map +1 -1
- package/dist/framework/tool.d.ts +39 -2
- package/dist/framework/tool.d.ts.map +1 -1
- package/dist/framework/tool.js +27 -1
- package/dist/framework/tool.js.map +1 -1
- package/dist/harness/assembler.d.ts.map +1 -1
- package/dist/harness/assembler.js +4 -2
- package/dist/harness/assembler.js.map +1 -1
- package/dist/harness/drift-guard.d.ts.map +1 -1
- package/dist/harness/drift-guard.js +9 -1
- package/dist/harness/drift-guard.js.map +1 -1
- package/dist/harness/evidence.d.ts.map +1 -1
- package/dist/harness/evidence.js +3 -2
- package/dist/harness/evidence.js.map +1 -1
- package/dist/harness/safety.d.ts +11 -1
- package/dist/harness/safety.d.ts.map +1 -1
- package/dist/harness/safety.js +112 -16
- package/dist/harness/safety.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +4 -8
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +4 -4
- package/dist/init.js.map +1 -1
- package/dist/ink-ui/App.d.ts +2 -2
- package/dist/ink-ui/components/Markdown.d.ts.map +1 -1
- package/dist/ink-ui/components/Markdown.js.map +1 -1
- package/dist/ink-ui/components/PixelHorseBanner.d.ts +2 -2
- package/dist/ink-ui/components/StatusLine.d.ts +2 -2
- package/dist/ink-ui/launch.d.ts +2 -2
- package/dist/ink-ui/screens/ReplScreen.d.ts +4 -3
- package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.js +103 -31
- package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
- package/dist/memory/relevant-finder.d.ts +2 -1
- package/dist/memory/relevant-finder.d.ts.map +1 -1
- package/dist/memory/relevant-finder.js +17 -8
- package/dist/memory/relevant-finder.js.map +1 -1
- package/dist/memory/semantic-config.d.ts +9 -0
- package/dist/memory/semantic-config.d.ts.map +1 -0
- package/dist/memory/semantic-config.js +16 -0
- package/dist/memory/semantic-config.js.map +1 -0
- package/dist/memory/semantic-search.d.ts +1 -6
- package/dist/memory/semantic-search.d.ts.map +1 -1
- package/dist/memory/semantic-search.js +3 -15
- package/dist/memory/semantic-search.js.map +1 -1
- package/dist/memory/storage.d.ts +23 -0
- package/dist/memory/storage.d.ts.map +1 -1
- package/dist/memory/storage.js +116 -9
- package/dist/memory/storage.js.map +1 -1
- package/dist/memory/validation.d.ts +3 -0
- package/dist/memory/validation.d.ts.map +1 -1
- package/dist/memory/validation.js +123 -10
- package/dist/memory/validation.js.map +1 -1
- package/dist/memory/vector-store.d.ts +30 -0
- package/dist/memory/vector-store.d.ts.map +1 -1
- package/dist/memory/vector-store.js +160 -21
- package/dist/memory/vector-store.js.map +1 -1
- package/dist/migration/command.d.ts.map +1 -1
- package/dist/migration/command.js +0 -1
- package/dist/migration/command.js.map +1 -1
- package/dist/migration/migrate.d.ts.map +1 -1
- package/dist/migration/migrate.js +59 -107
- package/dist/migration/migrate.js.map +1 -1
- package/dist/migration/types.d.ts +0 -1
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/print-ui/launch.d.ts +13 -3
- package/dist/print-ui/launch.d.ts.map +1 -1
- package/dist/print-ui/launch.js +28 -3
- package/dist/print-ui/launch.js.map +1 -1
- package/dist/product/environment.d.ts +3 -5
- package/dist/product/environment.d.ts.map +1 -1
- package/dist/product/environment.js +4 -32
- package/dist/product/environment.js.map +1 -1
- package/dist/product/index.d.ts +1 -1
- package/dist/product/index.d.ts.map +1 -1
- package/dist/product/index.js +1 -3
- package/dist/product/index.js.map +1 -1
- package/dist/product/paths.d.ts.map +1 -1
- package/dist/product/paths.js +16 -11
- package/dist/product/paths.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts +4 -2
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +129 -15
- package/dist/runtime/agent-runtime-controller.js.map +1 -1
- package/dist/runtime/agent-runtime-protocol.d.ts +15 -0
- package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-protocol.js +6 -0
- package/dist/runtime/agent-runtime-protocol.js.map +1 -1
- package/dist/runtime/chat-checkpoint.d.ts +17 -0
- package/dist/runtime/chat-checkpoint.d.ts.map +1 -0
- package/dist/runtime/chat-checkpoint.js +108 -0
- package/dist/runtime/chat-checkpoint.js.map +1 -0
- package/dist/runtime/chat-controller.d.ts +10 -51
- package/dist/runtime/chat-controller.d.ts.map +1 -1
- package/dist/runtime/chat-controller.js +256 -1070
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/chat-effort.d.ts +5 -0
- package/dist/runtime/chat-effort.d.ts.map +1 -0
- package/dist/runtime/chat-effort.js +47 -0
- package/dist/runtime/chat-effort.js.map +1 -0
- package/dist/runtime/chat-presentation.d.ts +60 -0
- package/dist/runtime/chat-presentation.d.ts.map +1 -0
- package/dist/runtime/chat-presentation.js +537 -0
- package/dist/runtime/chat-presentation.js.map +1 -0
- package/dist/runtime/chat-trace.d.ts +52 -0
- package/dist/runtime/chat-trace.d.ts.map +1 -0
- package/dist/runtime/chat-trace.js +234 -0
- package/dist/runtime/chat-trace.js.map +1 -0
- package/dist/runtime/chat-workspace.d.ts +22 -0
- package/dist/runtime/chat-workspace.d.ts.map +1 -0
- package/dist/runtime/chat-workspace.js +154 -0
- package/dist/runtime/chat-workspace.js.map +1 -0
- package/dist/runtime/goals/accounting.js +1 -1
- package/dist/runtime/goals/accounting.js.map +1 -1
- package/dist/runtime/goals/completion-audit.d.ts.map +1 -1
- package/dist/runtime/goals/completion-audit.js +5 -4
- package/dist/runtime/goals/completion-audit.js.map +1 -1
- package/dist/runtime/goals/coordinator.d.ts +3 -0
- package/dist/runtime/goals/coordinator.d.ts.map +1 -1
- package/dist/runtime/goals/coordinator.js +56 -2
- package/dist/runtime/goals/coordinator.js.map +1 -1
- package/dist/runtime/goals/prompt.d.ts +1 -1
- package/dist/runtime/goals/prompt.d.ts.map +1 -1
- package/dist/runtime/goals/prompt.js +4 -3
- package/dist/runtime/goals/prompt.js.map +1 -1
- package/dist/runtime/goals/tools.d.ts +32 -8
- package/dist/runtime/goals/tools.d.ts.map +1 -1
- package/dist/runtime/goals/tools.js +187 -11
- package/dist/runtime/goals/tools.js.map +1 -1
- package/dist/runtime/goals/types.d.ts +9 -0
- package/dist/runtime/goals/types.d.ts.map +1 -1
- package/dist/runtime/goals/types.js +1 -0
- package/dist/runtime/goals/types.js.map +1 -1
- package/dist/runtime/loop-budget.d.ts +2 -2
- package/dist/runtime/rich-text/markdown-parser.d.ts +2 -0
- package/dist/runtime/rich-text/markdown-parser.d.ts.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.js +50 -10
- package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
- package/dist/runtime/subagents/index.d.ts +2 -2
- package/dist/runtime/subagents/index.d.ts.map +1 -1
- package/dist/runtime/subagents/index.js +2 -1
- package/dist/runtime/subagents/index.js.map +1 -1
- package/dist/runtime/subagents/policy.d.ts +1 -1
- package/dist/runtime/subagents/policy.d.ts.map +1 -1
- package/dist/runtime/subagents/policy.js.map +1 -1
- package/dist/runtime/subagents/presets.d.ts +2 -2
- package/dist/runtime/subagents/research-artifact.d.ts +7 -0
- package/dist/runtime/subagents/research-artifact.d.ts.map +1 -1
- package/dist/runtime/subagents/research-artifact.js +73 -27
- package/dist/runtime/subagents/research-artifact.js.map +1 -1
- package/dist/runtime/subagents/research-contract.d.ts +18 -4
- package/dist/runtime/subagents/research-contract.d.ts.map +1 -1
- package/dist/runtime/subagents/research-contract.js +122 -17
- package/dist/runtime/subagents/research-contract.js.map +1 -1
- package/dist/runtime/subagents/research-renderer.d.ts +27 -11
- package/dist/runtime/subagents/research-renderer.d.ts.map +1 -1
- package/dist/runtime/subagents/research-renderer.js +34 -2
- package/dist/runtime/subagents/research-renderer.js.map +1 -1
- package/dist/runtime/subagents/result-parser.d.ts +1 -5
- package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
- package/dist/runtime/subagents/result-parser.js +5 -72
- package/dist/runtime/subagents/result-parser.js.map +1 -1
- package/dist/runtime/subagents/runtime-integration.d.ts +13 -7
- package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
- package/dist/runtime/subagents/runtime-integration.js +112 -2
- package/dist/runtime/subagents/runtime-integration.js.map +1 -1
- package/dist/runtime/subagents/supervisor.d.ts +15 -1
- package/dist/runtime/subagents/supervisor.d.ts.map +1 -1
- package/dist/runtime/subagents/supervisor.js +58 -3
- package/dist/runtime/subagents/supervisor.js.map +1 -1
- package/dist/runtime/subagents/tool.d.ts +2 -2
- package/dist/runtime/subagents/tool.d.ts.map +1 -1
- package/dist/runtime/subagents/tool.js +129 -9
- package/dist/runtime/subagents/tool.js.map +1 -1
- package/dist/runtime/subagents/types.d.ts +20 -0
- package/dist/runtime/subagents/types.d.ts.map +1 -1
- package/dist/runtime/subagents/types.js.map +1 -1
- package/dist/runtime/subagents/web-research-adapter.d.ts +4 -2
- package/dist/runtime/subagents/web-research-adapter.d.ts.map +1 -1
- package/dist/runtime/subagents/web-research-adapter.js +81 -15
- package/dist/runtime/subagents/web-research-adapter.js.map +1 -1
- package/dist/runtime/ui-events.d.ts +36 -8
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/runtime/ui-view-model.d.ts +53 -4
- package/dist/runtime/ui-view-model.d.ts.map +1 -1
- package/dist/runtime/ui-view-model.js +190 -10
- package/dist/runtime/ui-view-model.js.map +1 -1
- package/dist/services/agent-runner.d.ts +5 -2
- package/dist/services/agent-runner.d.ts.map +1 -1
- package/dist/services/agent-runner.js +18 -18
- package/dist/services/agent-runner.js.map +1 -1
- package/dist/services/atomic-write.d.ts +9 -1
- package/dist/services/atomic-write.d.ts.map +1 -1
- package/dist/services/atomic-write.js +55 -2
- package/dist/services/atomic-write.js.map +1 -1
- package/dist/services/auth/auth.d.ts +11 -7
- package/dist/services/auth/auth.d.ts.map +1 -1
- package/dist/services/auth/auth.js +117 -31
- package/dist/services/auth/auth.js.map +1 -1
- package/dist/services/auth/aws.d.ts +2 -0
- package/dist/services/auth/aws.d.ts.map +1 -1
- package/dist/services/auth/aws.js +126 -12
- package/dist/services/auth/aws.js.map +1 -1
- package/dist/services/auth/index.d.ts +1 -1
- package/dist/services/auth/index.d.ts.map +1 -1
- package/dist/services/auth/index.js +2 -1
- package/dist/services/auth/index.js.map +1 -1
- package/dist/services/auto-fix/autoFixConfig.d.ts +0 -3
- package/dist/services/auto-fix/autoFixConfig.d.ts.map +1 -1
- package/dist/services/auto-fix/autoFixConfig.js +25 -8
- package/dist/services/auto-fix/autoFixConfig.js.map +1 -1
- package/dist/services/auto-fix/autoFixHook.d.ts +7 -0
- package/dist/services/auto-fix/autoFixHook.d.ts.map +1 -1
- package/dist/services/auto-fix/autoFixHook.js +10 -1
- package/dist/services/auto-fix/autoFixHook.js.map +1 -1
- package/dist/services/compact/auto-compact.d.ts +2 -0
- package/dist/services/compact/auto-compact.d.ts.map +1 -1
- package/dist/services/compact/auto-compact.js +15 -1
- package/dist/services/compact/auto-compact.js.map +1 -1
- package/dist/services/compact/compact.d.ts.map +1 -1
- package/dist/services/compact/compact.js +9 -11
- package/dist/services/compact/compact.js.map +1 -1
- package/dist/services/compact/summary-generator.d.ts.map +1 -1
- package/dist/services/compact/summary-generator.js +28 -4
- package/dist/services/compact/summary-generator.js.map +1 -1
- package/dist/services/compact/tool-call-groups.d.ts +19 -0
- package/dist/services/compact/tool-call-groups.d.ts.map +1 -0
- package/dist/services/compact/tool-call-groups.js +105 -0
- package/dist/services/compact/tool-call-groups.js.map +1 -0
- package/dist/services/concurrent-sessions.d.ts +4 -0
- package/dist/services/concurrent-sessions.d.ts.map +1 -1
- package/dist/services/concurrent-sessions.js +59 -12
- package/dist/services/concurrent-sessions.js.map +1 -1
- package/dist/services/config.d.ts +8 -4
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +15 -71
- package/dist/services/config.js.map +1 -1
- package/dist/services/doctor.d.ts +2 -2
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/effort.d.ts +40 -0
- package/dist/services/effort.d.ts.map +1 -0
- package/dist/services/effort.js +88 -0
- package/dist/services/effort.js.map +1 -0
- package/dist/services/file-glob.d.ts.map +1 -1
- package/dist/services/file-glob.js +22 -2
- package/dist/services/file-glob.js.map +1 -1
- package/dist/services/file-lock.d.ts +7 -0
- package/dist/services/file-lock.d.ts.map +1 -0
- package/dist/services/file-lock.js +193 -0
- package/dist/services/file-lock.js.map +1 -0
- package/dist/services/global-config.d.ts +9 -0
- package/dist/services/global-config.d.ts.map +1 -1
- package/dist/services/global-config.js +79 -4
- package/dist/services/global-config.js.map +1 -1
- package/dist/services/goal-storage.d.ts.map +1 -1
- package/dist/services/goal-storage.js +35 -11
- package/dist/services/goal-storage.js.map +1 -1
- package/dist/services/llm.d.ts +35 -17
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +249 -113
- package/dist/services/llm.js.map +1 -1
- package/dist/services/mcp/transports.d.ts +0 -1
- package/dist/services/mcp/transports.d.ts.map +1 -1
- package/dist/services/mcp/transports.js +12 -13
- package/dist/services/mcp/transports.js.map +1 -1
- package/dist/services/model-context.d.ts +8 -0
- package/dist/services/model-context.d.ts.map +1 -1
- package/dist/services/model-context.js +111 -7
- package/dist/services/model-context.js.map +1 -1
- package/dist/services/model-registry.d.ts +3 -0
- package/dist/services/model-registry.d.ts.map +1 -1
- package/dist/services/model-registry.js +59 -2
- package/dist/services/model-registry.js.map +1 -1
- package/dist/services/provider-diagnostics.d.ts +1 -1
- package/dist/services/provider-diagnostics.d.ts.map +1 -1
- package/dist/services/provider-diagnostics.js +30 -16
- package/dist/services/provider-diagnostics.js.map +1 -1
- package/dist/services/provider-resilience/coordinator.d.ts +8 -3
- package/dist/services/provider-resilience/coordinator.d.ts.map +1 -1
- package/dist/services/provider-resilience/coordinator.js +86 -19
- package/dist/services/provider-resilience/coordinator.js.map +1 -1
- package/dist/services/provider-resilience/error-classifier.d.ts +1 -0
- package/dist/services/provider-resilience/error-classifier.d.ts.map +1 -1
- package/dist/services/provider-resilience/error-classifier.js +50 -26
- package/dist/services/provider-resilience/error-classifier.js.map +1 -1
- package/dist/services/provider-resilience/index.d.ts +3 -3
- package/dist/services/provider-resilience/index.d.ts.map +1 -1
- package/dist/services/provider-resilience/index.js +3 -1
- package/dist/services/provider-resilience/index.js.map +1 -1
- package/dist/services/provider-resilience/request-gate.d.ts +6 -0
- package/dist/services/provider-resilience/request-gate.d.ts.map +1 -1
- package/dist/services/provider-resilience/request-gate.js +24 -9
- package/dist/services/provider-resilience/request-gate.js.map +1 -1
- package/dist/services/provider-resilience/types.d.ts +10 -1
- package/dist/services/provider-resilience/types.d.ts.map +1 -1
- package/dist/services/provider-resilience/types.js.map +1 -1
- package/dist/services/redaction.d.ts.map +1 -1
- package/dist/services/redaction.js +29 -1
- package/dist/services/redaction.js.map +1 -1
- package/dist/services/session-index.d.ts.map +1 -1
- package/dist/services/session-index.js +75 -44
- package/dist/services/session-index.js.map +1 -1
- package/dist/services/session-memory/sessionMemory.d.ts.map +1 -1
- package/dist/services/session-memory/sessionMemory.js +6 -3
- package/dist/services/session-memory/sessionMemory.js.map +1 -1
- package/dist/services/session-storage.d.ts +12 -0
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +301 -230
- package/dist/services/session-storage.js.map +1 -1
- package/dist/services/storage-maintenance.d.ts.map +1 -1
- package/dist/services/storage-maintenance.js +25 -7
- package/dist/services/storage-maintenance.js.map +1 -1
- package/dist/services/task-manager.d.ts +6 -1
- package/dist/services/task-manager.d.ts.map +1 -1
- package/dist/services/task-manager.js +18 -4
- package/dist/services/task-manager.js.map +1 -1
- package/dist/services/tool-allowlist.d.ts +20 -10
- package/dist/services/tool-allowlist.d.ts.map +1 -1
- package/dist/services/tool-allowlist.js +64 -15
- package/dist/services/tool-allowlist.js.map +1 -1
- package/dist/services/usage-state.d.ts +10 -0
- package/dist/services/usage-state.d.ts.map +1 -1
- package/dist/services/usage-state.js +116 -45
- package/dist/services/usage-state.js.map +1 -1
- package/dist/services/verification-profile.d.ts.map +1 -1
- package/dist/services/verification-profile.js +23 -3
- package/dist/services/verification-profile.js.map +1 -1
- package/dist/services/workspace-diff.d.ts +14 -0
- package/dist/services/workspace-diff.d.ts.map +1 -1
- package/dist/services/workspace-diff.js +60 -11
- package/dist/services/workspace-diff.js.map +1 -1
- package/dist/services/yaml-config.d.ts.map +1 -1
- package/dist/services/yaml-config.js +2 -1
- package/dist/services/yaml-config.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +23 -9
- package/dist/skills/loader.js.map +1 -1
- package/dist/skills/runtime.d.ts +3 -3
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +37 -4
- package/dist/skills/runtime.js.map +1 -1
- package/dist/skills/types.d.ts +1 -1
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/terminal-ui/launch.d.ts +26 -8
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +82 -39
- package/dist/terminal-ui/launch.js.map +1 -1
- package/dist/tools/bash_security.d.ts +17 -0
- package/dist/tools/bash_security.d.ts.map +1 -1
- package/dist/tools/bash_security.js +233 -27
- package/dist/tools/bash_security.js.map +1 -1
- package/dist/tools/git.d.ts +8 -8
- package/dist/tools/git.d.ts.map +1 -1
- package/dist/tools/git.js +248 -55
- package/dist/tools/git.js.map +1 -1
- package/dist/tools/index.d.ts +13 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +262 -30
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/lsp.d.ts +74 -6
- package/dist/tools/lsp.d.ts.map +1 -1
- package/dist/tools/lsp.js +24 -5
- package/dist/tools/lsp.js.map +1 -1
- package/dist/tools/mcp.d.ts +11 -4
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mcp.js +99 -3
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/plan.d.ts +4 -4
- package/dist/tools/sandbox.d.ts +5 -1
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +29 -13
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/todo.d.ts +3 -3
- package/dist/tools/web.d.ts +15 -4
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +240 -26
- package/dist/tools/web.js.map +1 -1
- package/dist/tui-ui/launch.d.ts +3 -3
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +3 -3
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.d.ts.map +1 -1
- package/dist/tui-ui/layout.js +19 -5
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/pickers.d.ts.map +1 -1
- package/dist/tui-ui/pickers.js +1 -0
- package/dist/tui-ui/pickers.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +2 -1
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +18 -29
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +13 -1
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +28 -1
- package/dist/tui-ui/state.js.map +1 -1
- package/dist/ui/markdown.js.map +1 -1
- package/dist/utils/debug-log.d.ts +3 -3
- package/dist/utils/debug-log.d.ts.map +1 -1
- package/dist/utils/debug-log.js +7 -4
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/json.d.ts +6 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +66 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/mask.d.ts +8 -1
- package/dist/utils/mask.d.ts.map +1 -1
- package/dist/utils/mask.js +10 -12
- package/dist/utils/mask.js.map +1 -1
- package/dist/utils/observability.d.ts +22 -0
- package/dist/utils/observability.d.ts.map +1 -0
- package/dist/utils/observability.js +80 -0
- package/dist/utils/observability.js.map +1 -0
- package/dist/utils/token-estimate.d.ts +8 -0
- package/dist/utils/token-estimate.d.ts.map +1 -1
- package/dist/utils/token-estimate.js +30 -17
- package/dist/utils/token-estimate.js.map +1 -1
- package/package.json +9 -8
package/dist/commands/index.js
CHANGED
|
@@ -1,3580 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Orion Code slash-command registry.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Command definitions are grouped by product domain while handler implementations
|
|
6
|
+
* remain isolated from registry lookup. Keep the concatenation order stable: aliases
|
|
7
|
+
* and duplicate detection use first-registration semantics.
|
|
6
8
|
*/
|
|
7
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
-
};
|
|
10
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.getCommandCategoryLabel =
|
|
12
|
-
exports.sortCommands = sortCommands;
|
|
13
|
-
exports.getCommands = getCommands;
|
|
10
|
+
exports.sortCommands = exports.getCommandCategoryLabel = exports.executeChat = void 0;
|
|
14
11
|
exports.getVisibleCommands = getVisibleCommands;
|
|
12
|
+
exports.getCommands = getCommands;
|
|
15
13
|
exports.findCommand = findCommand;
|
|
16
14
|
exports.getCommandNames = getCommandNames;
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const session_storage_1 = require("../services/session-storage");
|
|
33
|
-
const session_index_1 = require("../services/session-index");
|
|
34
|
-
const auto_compact_1 = require("../services/compact/auto-compact");
|
|
35
|
-
const coordinator_1 = require("../services/compact/coordinator");
|
|
36
|
-
const harness_1 = require("../harness");
|
|
37
|
-
const skills_1 = require("../skills");
|
|
38
|
-
const file_context_1 = require("../services/file-context");
|
|
39
|
-
const project_instructions_1 = require("../services/project-instructions");
|
|
40
|
-
const prompt_context_1 = require("../services/prompt-context");
|
|
41
|
-
const doctor_1 = require("../services/doctor");
|
|
42
|
-
const model_context_1 = require("../services/model-context");
|
|
43
|
-
const token_estimate_1 = require("../utils/token-estimate");
|
|
44
|
-
const mask_1 = require("../utils/mask");
|
|
45
|
-
const model_catalog_1 = require("../services/model-catalog");
|
|
46
|
-
const model_registry_1 = require("../services/model-registry");
|
|
47
|
-
const workspace_diff_1 = require("../services/workspace-diff");
|
|
48
|
-
const commit_plan_1 = require("../services/commit-plan");
|
|
49
|
-
const tool_artifacts_1 = require("../core/tool-artifacts");
|
|
50
|
-
const checkpoint_1 = require("../core/checkpoint");
|
|
51
|
-
const storage_maintenance_1 = require("../services/storage-maintenance");
|
|
52
|
-
const agent_status_1 = require("../runtime/agent-status");
|
|
53
|
-
const loop_budget_1 = require("../runtime/loop-budget");
|
|
54
|
-
const usage_state_1 = require("../services/usage-state");
|
|
55
|
-
const command_1 = require("../migration/command");
|
|
56
|
-
// ============================================================================
|
|
57
|
-
// 颜色常量
|
|
58
|
-
// ============================================================================
|
|
59
|
-
const BRAND = chalk_1.default.hex('#FF6B35');
|
|
60
|
-
const ACCENT = chalk_1.default.hex('#00D4AA');
|
|
61
|
-
const DIM = chalk_1.default.dim;
|
|
62
|
-
const ERROR = chalk_1.default.red;
|
|
63
|
-
const WARN = chalk_1.default.yellow;
|
|
64
|
-
const SUCCESS = chalk_1.default.green;
|
|
65
|
-
const HEADER = chalk_1.default.cyan.bold;
|
|
66
|
-
const CATEGORY_ORDER = [
|
|
67
|
-
'workflow',
|
|
68
|
-
'session',
|
|
69
|
-
'context',
|
|
70
|
-
'tools',
|
|
71
|
-
'model',
|
|
72
|
-
'system',
|
|
73
|
-
'diagnostics',
|
|
74
|
-
'legacy',
|
|
75
|
-
];
|
|
76
|
-
function commandUICapabilities(ctx) {
|
|
77
|
-
return (0, ui_view_model_1.createStatusSnapshot)({
|
|
78
|
-
renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
|
|
79
|
-
capabilities: ctx.uiCapabilities,
|
|
80
|
-
}).renderer.capabilities;
|
|
81
|
-
}
|
|
82
|
-
function formatTokenCount(tokens) {
|
|
83
|
-
if (tokens >= 1000000)
|
|
84
|
-
return `${(tokens / 1000000).toFixed(1)}M`;
|
|
85
|
-
if (tokens >= 1000)
|
|
86
|
-
return `${Math.round(tokens / 1000)}K`;
|
|
87
|
-
return String(tokens);
|
|
88
|
-
}
|
|
89
|
-
function formatThreshold(value) {
|
|
90
|
-
return `${Math.round(value * 100)}%`;
|
|
91
|
-
}
|
|
92
|
-
function formatDurationMs(ms) {
|
|
93
|
-
if (ms >= 1000)
|
|
94
|
-
return `${(ms / 1000).toFixed(1)}s`;
|
|
95
|
-
return `${Math.round(ms)}ms`;
|
|
96
|
-
}
|
|
97
|
-
function formatRendererStatus(ctx) {
|
|
98
|
-
const snapshot = (0, ui_view_model_1.createStatusSnapshot)({
|
|
99
|
-
renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
|
|
100
|
-
capabilities: ctx.uiCapabilities,
|
|
101
|
-
});
|
|
102
|
-
const status = snapshot.renderer.status === 'deprecated'
|
|
103
|
-
? WARN('deprecated')
|
|
104
|
-
: snapshot.renderer.status === 'product'
|
|
105
|
-
? SUCCESS('product')
|
|
106
|
-
: snapshot.renderer.status === 'technical'
|
|
107
|
-
? DIM('technical')
|
|
108
|
-
: snapshot.renderer.status === 'non-interactive'
|
|
109
|
-
? DIM('non-interactive')
|
|
110
|
-
: DIM('custom');
|
|
111
|
-
return `${BRAND(snapshot.renderer.name)} ${status} ${DIM(snapshot.renderer.capabilityLabels.join(', '))}`;
|
|
112
|
-
}
|
|
113
|
-
function getProfileByModelId(registry, modelId) {
|
|
114
|
-
if (!registry)
|
|
115
|
-
return undefined;
|
|
116
|
-
const normalized = modelId.trim();
|
|
117
|
-
if (!normalized)
|
|
118
|
-
return undefined;
|
|
119
|
-
if (registry.profiles.has(normalized))
|
|
120
|
-
return registry.profiles.get(normalized);
|
|
121
|
-
for (const profile of registry.profiles.values()) {
|
|
122
|
-
if (modelId === profile.model)
|
|
123
|
-
return profile;
|
|
124
|
-
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
function resolveModelFromRegistry(config, selector) {
|
|
128
|
-
if (!config.modelRegistry)
|
|
129
|
-
return undefined;
|
|
130
|
-
const trimmed = selector.trim();
|
|
131
|
-
if (!trimmed)
|
|
132
|
-
return undefined;
|
|
133
|
-
return (0, model_registry_1.lookupProfile)(config.modelRegistry, trimmed) ?? undefined;
|
|
134
|
-
}
|
|
135
|
-
function listConfiguredModelCatalogEntries(registry) {
|
|
136
|
-
if (!registry)
|
|
137
|
-
return [];
|
|
138
|
-
return registry.enabledProfiles.map(profile => {
|
|
139
|
-
const provider = registry.providers.get(profile.provider);
|
|
140
|
-
return {
|
|
141
|
-
name: profile.id,
|
|
142
|
-
alias: profile.aliases?.[0],
|
|
143
|
-
provider: provider?.displayName ?? profile.provider,
|
|
144
|
-
contextWindow: profile.resolvedContextWindow,
|
|
145
|
-
maxOutputTokens: profile.resolvedMaxOutputTokens,
|
|
146
|
-
source: `${profile.contextSource}/${profile.outputSource}`,
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
function formatLoopBudgetSource(stats) {
|
|
151
|
-
const source = stats.loopBudgetSource ?? 'unknown';
|
|
152
|
-
if (source === 'config' && stats.loopBudgetBaseProfile) {
|
|
153
|
-
return `config over ${stats.loopBudgetBaseProfile}`;
|
|
154
|
-
}
|
|
155
|
-
return source;
|
|
156
|
-
}
|
|
157
|
-
function formatLoopStatsLines(stats, detail = false) {
|
|
158
|
-
const lines = [
|
|
159
|
-
`Finish ${stats.finishReason}`,
|
|
160
|
-
`Requests ${stats.llmRequests} LLM / ${stats.turnsStarted} turns`,
|
|
161
|
-
`Tools ${stats.toolCalls} total (${stats.readOnlyToolCalls} read-only, ${stats.unsafeToolCalls} unsafe)`,
|
|
162
|
-
`Tool bytes ${(0, format_1.formatBytes)(stats.modelVisibleToolBytes)} model-visible / ${(0, format_1.formatBytes)(stats.toolResultBytes)} total`,
|
|
163
|
-
];
|
|
164
|
-
if (stats.summarizedBytes > 0) {
|
|
165
|
-
lines.push(`Saved ${(0, format_1.formatBytes)(stats.summarizedBytes)} from model context`);
|
|
166
|
-
}
|
|
167
|
-
if (stats.compactTrigger) {
|
|
168
|
-
lines.push(`Compact ${stats.compactTrigger}`);
|
|
169
|
-
}
|
|
170
|
-
if (stats.localFastPathUsed) {
|
|
171
|
-
lines.push('Fast path yes');
|
|
172
|
-
}
|
|
173
|
-
if (stats.budgetExceededReason) {
|
|
174
|
-
lines.push(`Budget ${stats.budgetExceededReason}`);
|
|
175
|
-
}
|
|
176
|
-
if (stats.continuationActions && stats.continuationActions.length > 0) {
|
|
177
|
-
lines.push(`Next ${stats.continuationActions.join(', ')}`);
|
|
178
|
-
}
|
|
179
|
-
if ((stats.providerRetryCount ?? 0) > 0) {
|
|
180
|
-
const retryParts = [
|
|
181
|
-
`${stats.providerRetryCount} retries`,
|
|
182
|
-
`delay ${formatDurationMs(stats.providerRetryDelayMs ?? 0)}`,
|
|
183
|
-
stats.providerLastRetryErrorType
|
|
184
|
-
? `last ${stats.providerLastRetryErrorType}${stats.providerLastRetryStatus ? `/${stats.providerLastRetryStatus}` : ''}`
|
|
185
|
-
: undefined,
|
|
186
|
-
].filter(Boolean);
|
|
187
|
-
lines.push(`Provider ${retryParts.join(', ')}`);
|
|
188
|
-
}
|
|
189
|
-
if ((stats.providerFallbackCount ?? 0) > 0 || stats.providerUsingFallback) {
|
|
190
|
-
const fallbackPath = stats.providerFallbackFromModel && stats.providerFallbackToModel
|
|
191
|
-
? `${stats.providerFallbackFromModel} -> ${stats.providerFallbackToModel}`
|
|
192
|
-
: stats.providerFinalModel
|
|
193
|
-
? `final ${stats.providerFinalModel}`
|
|
194
|
-
: 'active';
|
|
195
|
-
lines.push(`Fallback ${fallbackPath}`);
|
|
196
|
-
}
|
|
197
|
-
if (typeof stats.verificationClaimAllowed === 'boolean') {
|
|
198
|
-
const verificationParts = [
|
|
199
|
-
stats.verificationProfile ?? 'unknown',
|
|
200
|
-
`required=${stats.verificationRequired ? 'yes' : 'no'}`,
|
|
201
|
-
`passed=${stats.verificationPassedCommands?.length ?? 0}`,
|
|
202
|
-
`failed=${stats.verificationFailedCommands?.length ?? 0}`,
|
|
203
|
-
`missing=${stats.verificationMissingCommands?.length ?? 0}`,
|
|
204
|
-
`claim=${stats.verificationClaimAllowed ? 'yes' : 'no'}`,
|
|
205
|
-
];
|
|
206
|
-
lines.push(`Verify ${verificationParts.join(' ')}`);
|
|
207
|
-
}
|
|
208
|
-
if (typeof stats.loopBudgetMaxLlmRequests === 'number' ||
|
|
209
|
-
typeof stats.loopBudgetMaxToolCalls === 'number' ||
|
|
210
|
-
typeof stats.loopBudgetMaxModelVisibleBytes === 'number') {
|
|
211
|
-
const caps = [
|
|
212
|
-
typeof stats.loopBudgetMaxLlmRequests === 'number'
|
|
213
|
-
? `${stats.llmRequests}/${stats.loopBudgetMaxLlmRequests} LLM`
|
|
214
|
-
: undefined,
|
|
215
|
-
typeof stats.loopBudgetMaxToolCalls === 'number'
|
|
216
|
-
? `${stats.toolCalls}/${stats.loopBudgetMaxToolCalls} tools`
|
|
217
|
-
: undefined,
|
|
218
|
-
typeof stats.loopBudgetMaxModelVisibleBytes === 'number'
|
|
219
|
-
? `${(0, format_1.formatBytes)(stats.modelVisibleToolBytes)}/${(0, format_1.formatBytes)(stats.loopBudgetMaxModelVisibleBytes)} visible`
|
|
220
|
-
: undefined,
|
|
221
|
-
typeof stats.loopBudgetMaxReadOnlyFragmentation === 'number'
|
|
222
|
-
? `fragment ${stats.singleReadOnlyStreak}/${stats.loopBudgetMaxReadOnlyFragmentation}`
|
|
223
|
-
: undefined,
|
|
224
|
-
].filter(Boolean);
|
|
225
|
-
lines.push(`Budget cap ${caps.join(', ')} (${formatLoopBudgetSource(stats)})`);
|
|
226
|
-
}
|
|
227
|
-
if (stats.singleReadOnlyStreak > 0 || stats.batchReadSuggestionCount > 0) {
|
|
228
|
-
lines.push(`Read-only streak ${stats.singleReadOnlyStreak}, batch_read hints ${stats.batchReadSuggestionCount}`);
|
|
229
|
-
}
|
|
230
|
-
if (detail) {
|
|
231
|
-
lines.push(`Unsafe ${stats.unsafeToolCalls}`);
|
|
232
|
-
if (stats.providerRetryErrorTypes && stats.providerRetryErrorTypes.length > 0) {
|
|
233
|
-
lines.push(`Retry type ${stats.providerRetryErrorTypes.join(', ')}`);
|
|
234
|
-
}
|
|
235
|
-
if (stats.verificationFailedCommands && stats.verificationFailedCommands.length > 0) {
|
|
236
|
-
lines.push(`Failed ${stats.verificationFailedCommands.join(' && ')}`);
|
|
237
|
-
}
|
|
238
|
-
if (stats.verificationMissingCommands && stats.verificationMissingCommands.length > 0) {
|
|
239
|
-
lines.push(`Missing ${stats.verificationMissingCommands.join(' && ')}`);
|
|
240
|
-
}
|
|
241
|
-
if (stats.verificationSkippedReason) {
|
|
242
|
-
lines.push(`Verify why ${stats.verificationSkippedReason}`);
|
|
243
|
-
}
|
|
244
|
-
if (stats.continuationHint) {
|
|
245
|
-
lines.push(`Next why ${stats.continuationHint}`);
|
|
246
|
-
}
|
|
247
|
-
lines.push(`Budget hit ${stats.finishReason === 'budget_exceeded' ? 'yes' : 'no'}`);
|
|
248
|
-
}
|
|
249
|
-
return lines;
|
|
250
|
-
}
|
|
251
|
-
const CATEGORY_LABELS = {
|
|
252
|
-
workflow: 'Workflow',
|
|
253
|
-
session: 'Session',
|
|
254
|
-
context: 'Context',
|
|
255
|
-
tools: 'Tools',
|
|
256
|
-
model: 'Model',
|
|
257
|
-
system: 'System',
|
|
258
|
-
diagnostics: 'Diagnostics',
|
|
259
|
-
legacy: 'Legacy',
|
|
260
|
-
};
|
|
261
|
-
function commandCategory(command) {
|
|
262
|
-
return command.category ?? 'system';
|
|
263
|
-
}
|
|
264
|
-
function getCommandCategoryLabel(category) {
|
|
265
|
-
return CATEGORY_LABELS[category ?? 'system'];
|
|
266
|
-
}
|
|
267
|
-
function sortCommands(commands) {
|
|
268
|
-
return [...commands].sort((a, b) => {
|
|
269
|
-
const categoryDelta = CATEGORY_ORDER.indexOf(commandCategory(a)) - CATEGORY_ORDER.indexOf(commandCategory(b));
|
|
270
|
-
if (categoryDelta !== 0)
|
|
271
|
-
return categoryDelta;
|
|
272
|
-
const priorityDelta = (a.priority ?? 100) - (b.priority ?? 100);
|
|
273
|
-
if (priorityDelta !== 0)
|
|
274
|
-
return priorityDelta;
|
|
275
|
-
return a.name.localeCompare(b.name);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
function isAbortError(error, abortSignal) {
|
|
279
|
-
if (abortSignal?.aborted)
|
|
280
|
-
return true;
|
|
281
|
-
if (error instanceof Error) {
|
|
282
|
-
return error.name === 'AbortError' || error.message.toLowerCase().includes('aborted');
|
|
283
|
-
}
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
function hasCommandFlag(args, flag) {
|
|
287
|
-
return args.trim().split(/\s+/u).includes(flag);
|
|
288
|
-
}
|
|
289
|
-
// ============================================================================
|
|
290
|
-
// 工具参数摘要
|
|
291
|
-
// ============================================================================
|
|
292
|
-
// ============================================================================
|
|
293
|
-
// 命令实现
|
|
294
|
-
// ============================================================================
|
|
295
|
-
let taskManager = null;
|
|
296
|
-
function showHelp(ctx) {
|
|
297
|
-
console.log();
|
|
298
|
-
console.log(HEADER('Commands:'));
|
|
299
|
-
console.log();
|
|
300
|
-
const visible = getVisibleCommands(ctx.uiRenderer);
|
|
301
|
-
for (const category of CATEGORY_ORDER) {
|
|
302
|
-
const items = visible.filter(cmd => commandCategory(cmd) === category);
|
|
303
|
-
if (items.length === 0)
|
|
304
|
-
continue;
|
|
305
|
-
console.log(DIM(getCommandCategoryLabel(category)));
|
|
306
|
-
for (const cmd of items) {
|
|
307
|
-
const aliases = cmd.aliases ? ` (${cmd.aliases.join(', ')})` : '';
|
|
308
|
-
const params = cmd.argumentHint || cmd.params?.map(p => `<${p.name}>`).join(' ') || '';
|
|
309
|
-
const lifecycle = cmd.deprecated
|
|
310
|
-
? ` deprecated since ${cmd.deprecated.since}${cmd.deprecated.replacement ? `; use ${cmd.deprecated.replacement}` : ''}`
|
|
311
|
-
: '';
|
|
312
|
-
const risk = cmd.risk === 'destructive' ? ' destructive' : '';
|
|
313
|
-
const availability = cmd.availability?.(ctx);
|
|
314
|
-
const unavailable = availability && !availability.available
|
|
315
|
-
? ` unavailable: ${availability.reason ?? 'requirements not met'}`
|
|
316
|
-
: '';
|
|
317
|
-
console.log(` ${ACCENT(`/${cmd.name}`)}${aliases} ${DIM(params)}`);
|
|
318
|
-
console.log(` ${DIM(`${cmd.description}${lifecycle}${risk}${unavailable}`)}`);
|
|
319
|
-
}
|
|
320
|
-
console.log();
|
|
321
|
-
}
|
|
322
|
-
console.log(DIM('Type any text without / prefix to chat with the LLM.'));
|
|
323
|
-
console.log();
|
|
324
|
-
return { success: true };
|
|
325
|
-
}
|
|
326
|
-
function showStatus(ctx) {
|
|
327
|
-
console.log();
|
|
328
|
-
console.log(HEADER('System Status'));
|
|
329
|
-
console.log(DIM('─'.repeat(40)));
|
|
330
|
-
const brainStatus = ctx.runtime.brain.getStatus();
|
|
331
|
-
const memStatus = ctx.runtime.memory.getStatus();
|
|
332
|
-
const storeStats = ctx.runtime.store.getStats();
|
|
333
|
-
console.log(` Mode ${BRAND(ctx.config.mode)}`);
|
|
334
|
-
console.log(` Log level ${DIM(ctx.config.logLevel)}`);
|
|
335
|
-
const modelId = ctx.llm?.getModel() ?? snapshotCurrentModel(ctx);
|
|
336
|
-
const modelContext = (0, model_context_1.resolveModelContext)(modelId);
|
|
337
|
-
const compactStats = getCommandAutoCompact(ctx, modelId).getStats();
|
|
338
|
-
console.log(` Model ${BRAND(modelId)}`);
|
|
339
|
-
console.log(` Context ${DIM(`${formatTokenCount(modelContext.contextWindow)} tokens (${modelContext.source}${modelContext.source === 'fuzzy' ? `:${modelContext.matchedId}` : ''})`)}`);
|
|
340
|
-
console.log(` Compact ${compactStats.enabled ? SUCCESS('auto') : WARN('off')} ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}, used ${compactStats.ctxPercent}%`)}`);
|
|
341
|
-
console.log(` Renderer ${formatRendererStatus(ctx)}`);
|
|
342
|
-
console.log();
|
|
343
|
-
console.log(` Agents ${SUCCESS(brainStatus.agents.length)} registered`);
|
|
344
|
-
console.log(` Tasks ${brainStatus.pendingTasks} pending (${brainStatus.strategy} strategy)`);
|
|
345
|
-
console.log();
|
|
346
|
-
console.log(` Memory (inline):`);
|
|
347
|
-
console.log(` Working ${memStatus.working} entries`);
|
|
348
|
-
console.log(` Short-term ${memStatus['short-term']} entries`);
|
|
349
|
-
console.log(` Long-term ${memStatus['long-term']} entries`);
|
|
350
|
-
console.log();
|
|
351
|
-
console.log(` Memory (store):`);
|
|
352
|
-
console.log(` Working ${storeStats.working} entries`);
|
|
353
|
-
console.log(` Short-term ${storeStats['short-term']} entries`);
|
|
354
|
-
console.log(` Long-term ${storeStats['long-term']} entries`);
|
|
355
|
-
(0, prompt_context_1.refreshProjectInstructions)(ctx.store, ctx.cwd);
|
|
356
|
-
const snapshot = ctx.store.getSnapshot();
|
|
357
|
-
const instructionFiles = (0, project_instructions_1.loadProjectInstructionFiles)(ctx.cwd);
|
|
358
|
-
console.log();
|
|
359
|
-
console.log(` Context:`);
|
|
360
|
-
console.log(` Project rules ${instructionFiles.length > 0 ? SUCCESS(`${instructionFiles.length} files`) : DIM('none')}`);
|
|
361
|
-
for (const file of instructionFiles.slice(0, 8)) {
|
|
362
|
-
console.log(` ${DIM(file.path)}${file.truncated ? ` ${WARN('(truncated)')}` : ''}`);
|
|
363
|
-
}
|
|
364
|
-
if (instructionFiles.length > 8) {
|
|
365
|
-
console.log(` ${DIM(`... ${instructionFiles.length - 8} more`)}`);
|
|
366
|
-
}
|
|
367
|
-
console.log(` Prompt rules ${snapshot.projectInstructionsContent ? SUCCESS(`${snapshot.projectInstructionsContent.length} chars`) : DIM('none')}`);
|
|
368
|
-
console.log(` Project memory ${snapshot.memoryContent ? SUCCESS(`${snapshot.memoryContent.length} chars`) : DIM('none')}`);
|
|
369
|
-
console.log(` Skills index ${snapshot.skillsContent ? SUCCESS(`${snapshot.skillsContent.length} chars`) : DIM('none')}`);
|
|
370
|
-
if (snapshot.lastLoopStats) {
|
|
371
|
-
const stats = snapshot.lastLoopStats;
|
|
372
|
-
console.log();
|
|
373
|
-
console.log(` Last loop:`);
|
|
374
|
-
for (const line of formatLoopStatsLines(stats)) {
|
|
375
|
-
console.log(` ${line}`);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
const harnessState = snapshot.harnessState;
|
|
379
|
-
if (harnessState?.contract || harnessState?.capsule) {
|
|
380
|
-
console.log();
|
|
381
|
-
console.log(` Harness:`);
|
|
382
|
-
if (harnessState.contract) {
|
|
383
|
-
console.log(` Objective ${ACCENT(harnessState.contract.objective)}`);
|
|
384
|
-
}
|
|
385
|
-
console.log(` Ledger ${DIM(`${harnessState.ledger.length} entries`)}`);
|
|
386
|
-
if (harnessState.capsule) {
|
|
387
|
-
console.log(` Next ${DIM(harnessState.capsule.nextAction)}`);
|
|
388
|
-
const passed = harnessState.capsule.verification.passed.length;
|
|
389
|
-
const failed = harnessState.capsule.verification.failed.length;
|
|
390
|
-
console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
console.log();
|
|
394
|
-
return { success: true };
|
|
395
|
-
}
|
|
396
|
-
function handleLoopStats(ctx) {
|
|
397
|
-
const stats = ctx.store.getSnapshot().lastLoopStats;
|
|
398
|
-
if (!stats) {
|
|
399
|
-
console.log('No agent-loop stats recorded yet.');
|
|
400
|
-
return { success: true };
|
|
401
|
-
}
|
|
402
|
-
console.log(HEADER('Agent Loop Stats'));
|
|
403
|
-
console.log();
|
|
404
|
-
for (const line of formatLoopStatsLines(stats, true)) {
|
|
405
|
-
console.log(` ${line}`);
|
|
406
|
-
}
|
|
407
|
-
console.log();
|
|
408
|
-
console.log(DIM('Use this to spot excessive LLM requests, fragmented read-only tool calls, and local fast-path hits.'));
|
|
409
|
-
return { success: true };
|
|
410
|
-
}
|
|
411
|
-
function formatTraceEventLine(event) {
|
|
412
|
-
const time = new Date(event.timestamp).toLocaleTimeString();
|
|
413
|
-
const prefix = `${DIM(time)} ${ACCENT(event.type)}`;
|
|
414
|
-
switch (event.type) {
|
|
415
|
-
case 'turn_start':
|
|
416
|
-
return `${prefix} input=${(0, format_1.formatBytes)(event.inputBytes ?? 0)}${event.localFastPathUsed ? ' fast-path' : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
417
|
-
case 'request_start':
|
|
418
|
-
return `${prefix} model=${event.model ?? 'unknown'} iteration=${event.turn ?? '?'}`;
|
|
419
|
-
case 'provider_retry': {
|
|
420
|
-
const parts = [
|
|
421
|
-
`count=${event.providerRetryCount ?? 0}`,
|
|
422
|
-
`delay=${formatDurationMs(event.providerRetryDelayMs ?? 0)}`,
|
|
423
|
-
event.providerLastRetryErrorType
|
|
424
|
-
? `last=${event.providerLastRetryErrorType}${event.providerLastRetryStatus ? `/${event.providerLastRetryStatus}` : ''}`
|
|
425
|
-
: '',
|
|
426
|
-
event.providerRetryErrorTypes?.length
|
|
427
|
-
? `types=${event.providerRetryErrorTypes.join(',')}`
|
|
428
|
-
: '',
|
|
429
|
-
event.providerFinalModel ? `final=${event.providerFinalModel}` : '',
|
|
430
|
-
].filter(Boolean);
|
|
431
|
-
return `${prefix} ${parts.join(' ')}`;
|
|
432
|
-
}
|
|
433
|
-
case 'provider_fallback': {
|
|
434
|
-
const path = event.providerFallbackFromModel && event.providerFallbackToModel
|
|
435
|
-
? `${event.providerFallbackFromModel}->${event.providerFallbackToModel}`
|
|
436
|
-
: (event.providerFinalModel ?? 'active');
|
|
437
|
-
const parts = [
|
|
438
|
-
`count=${event.providerFallbackCount ?? 0}`,
|
|
439
|
-
`path=${path}`,
|
|
440
|
-
`using=${event.providerUsingFallback ? 'yes' : 'no'}`,
|
|
441
|
-
];
|
|
442
|
-
return `${prefix} ${parts.join(' ')}`;
|
|
443
|
-
}
|
|
444
|
-
case 'prompt_assembly': {
|
|
445
|
-
const parts = [
|
|
446
|
-
`model=${event.promptModelId ?? 'unknown'}`,
|
|
447
|
-
`tokens=${event.promptEstimatedTokens ?? 0}/${event.promptBudgetTokens ?? 0}`,
|
|
448
|
-
`core=${event.promptCoreTokens ?? 0}`,
|
|
449
|
-
`evidenceBudget=${event.promptEvidenceBudgetTokens ?? 0}`,
|
|
450
|
-
`recentBudget=${event.promptRecentTurnBudgetTokens ?? 0}`,
|
|
451
|
-
`included=${event.promptIncludedEvidenceCount ?? 0}`,
|
|
452
|
-
`omitted=${event.promptOmittedEvidenceCount ?? 0}`,
|
|
453
|
-
];
|
|
454
|
-
const sections = event.promptSections?.length
|
|
455
|
-
? ` sections=${event.promptSections.join(',')}`
|
|
456
|
-
: '';
|
|
457
|
-
const evidence = event.promptIncludedEvidence?.length
|
|
458
|
-
? ` evidence=${event.promptIncludedEvidence.slice(0, 6).join(', ')}${event.promptIncludedEvidence.length > 6 ? ', ...' : ''}`
|
|
459
|
-
: '';
|
|
460
|
-
return `${prefix} ${parts.join(' ')}${sections ? DIM(sections) : ''}${evidence ? ` ${DIM(evidence)}` : ''}`;
|
|
461
|
-
}
|
|
462
|
-
case 'assistant_tool_calls':
|
|
463
|
-
return `${prefix} calls=${event.toolCallCount ?? 0} assistant=${(0, format_1.formatBytes)(event.contentBytes ?? 0)}`;
|
|
464
|
-
case 'checkpoint': {
|
|
465
|
-
const files = event.checkpointFiles?.length
|
|
466
|
-
? ` files=${event.checkpointFiles.slice(0, 6).join(', ')}${event.checkpointFiles.length > 6 ? ', ...' : ''}`
|
|
467
|
-
: '';
|
|
468
|
-
const targets = event.workspaceFiles?.length && !files
|
|
469
|
-
? ` targets=${event.workspaceFiles.slice(0, 6).join(', ')}${event.workspaceFiles.length > 6 ? ', ...' : ''}`
|
|
470
|
-
: '';
|
|
471
|
-
return `${prefix} id=${event.checkpointId ?? 'unknown'} saved=${event.checkpointFileCount ?? 0}${files}${targets}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
472
|
-
}
|
|
473
|
-
case 'tool_call':
|
|
474
|
-
return `${prefix} ${event.name ?? 'tool'}${event.argsSummary ? ` ${DIM(event.argsSummary)}` : ''}${event.argsArtifactId ? ` ${DIM(`args=/artifacts show ${event.argsArtifactId} --full${event.argsBytes ? ` (${(0, format_1.formatBytes)(event.argsBytes)})` : ''}`)}` : ''}${event.callId ? ` ${DIM(event.callId)}` : ''}`;
|
|
475
|
-
case 'permission_decision': {
|
|
476
|
-
const status = event.permissionApproved ? SUCCESS('approved') : ERROR('denied');
|
|
477
|
-
const parts = [
|
|
478
|
-
`source=${event.permissionSource ?? 'unknown'}`,
|
|
479
|
-
`behavior=${event.permissionBehavior ?? 'unknown'}`,
|
|
480
|
-
];
|
|
481
|
-
if (typeof event.permissionDuration === 'number') {
|
|
482
|
-
parts.push(`${event.permissionDuration}ms`);
|
|
483
|
-
}
|
|
484
|
-
return `${prefix} ${status} ${event.name ?? 'tool'} ${DIM(parts.join(' '))}${event.permissionReason ? ` ${DIM(event.permissionReason)}` : ''}`;
|
|
485
|
-
}
|
|
486
|
-
case 'tool_result': {
|
|
487
|
-
const status = event.success === false ? ERROR('error') : SUCCESS('ok');
|
|
488
|
-
const bytes = [
|
|
489
|
-
`output=${(0, format_1.formatBytes)(event.outputBytes ?? 0)}`,
|
|
490
|
-
`model=${(0, format_1.formatBytes)(event.modelVisibleBytes ?? 0)}`,
|
|
491
|
-
];
|
|
492
|
-
if (event.artifactId)
|
|
493
|
-
bytes.push(`artifact=${event.artifactId}`);
|
|
494
|
-
return `${prefix} ${status} ${event.name ?? 'tool'} ${DIM(`${event.duration ?? 0}ms`)} ${DIM(bytes.join(' '))}${event.error ? ` ${ERROR(event.error)}` : ''}`;
|
|
495
|
-
}
|
|
496
|
-
case 'message':
|
|
497
|
-
return `${prefix} assistant=${(0, format_1.formatBytes)(event.contentBytes ?? 0)}`;
|
|
498
|
-
case 'strategy_exhausted':
|
|
499
|
-
return `${prefix}${event.note ? ` ${WARN(event.note)}` : ''}`;
|
|
500
|
-
case 'complete': {
|
|
501
|
-
const stats = [
|
|
502
|
-
`finish=${event.finishReason ?? 'unknown'}`,
|
|
503
|
-
`llm=${typeof event.llmRequests === 'number' ? event.llmRequests : 'unknown'}`,
|
|
504
|
-
`tools=${typeof event.toolCalls === 'number' ? event.toolCalls : 'unknown'}`,
|
|
505
|
-
];
|
|
506
|
-
if (event.loopBudgetSource ||
|
|
507
|
-
typeof event.loopBudgetMaxLlmRequests === 'number' ||
|
|
508
|
-
typeof event.loopBudgetMaxToolCalls === 'number' ||
|
|
509
|
-
typeof event.loopBudgetMaxModelVisibleBytes === 'number') {
|
|
510
|
-
const source = event.loopBudgetSource === 'config' && event.loopBudgetBaseProfile
|
|
511
|
-
? `config/${event.loopBudgetBaseProfile}`
|
|
512
|
-
: (event.loopBudgetSource ?? 'unknown');
|
|
513
|
-
const caps = [
|
|
514
|
-
typeof event.loopBudgetMaxLlmRequests === 'number'
|
|
515
|
-
? `${typeof event.llmRequests === 'number' ? event.llmRequests : '?'}/${event.loopBudgetMaxLlmRequests}llm`
|
|
516
|
-
: undefined,
|
|
517
|
-
typeof event.loopBudgetMaxToolCalls === 'number'
|
|
518
|
-
? `${typeof event.toolCalls === 'number' ? event.toolCalls : '?'}/${event.loopBudgetMaxToolCalls}tools`
|
|
519
|
-
: undefined,
|
|
520
|
-
typeof event.loopBudgetMaxModelVisibleBytes === 'number'
|
|
521
|
-
? `${(0, format_1.formatBytes)(event.loopBudgetMaxModelVisibleBytes)}visible`
|
|
522
|
-
: undefined,
|
|
523
|
-
typeof event.loopBudgetMaxReadOnlyFragmentation === 'number'
|
|
524
|
-
? `frag=${event.loopBudgetMaxReadOnlyFragmentation}`
|
|
525
|
-
: undefined,
|
|
526
|
-
event.loopBudgetConfigOverride ? 'override=yes' : undefined,
|
|
527
|
-
].filter(Boolean);
|
|
528
|
-
stats.push(`budgetProfile=${source}${caps.length ? `(${caps.join(',')})` : ''}`);
|
|
529
|
-
}
|
|
530
|
-
if (event.budgetExceededReason)
|
|
531
|
-
stats.push(`budget=${event.budgetExceededReason}`);
|
|
532
|
-
if (event.continuationActions?.length)
|
|
533
|
-
stats.push(`next=${event.continuationActions.join(',')}`);
|
|
534
|
-
if (event.continuationHint)
|
|
535
|
-
stats.push(`hint=${event.continuationHint}`);
|
|
536
|
-
if (event.localFastPathUsed)
|
|
537
|
-
stats.push('fast-path=yes');
|
|
538
|
-
return `${prefix} ${stats.join(' ')}`;
|
|
539
|
-
}
|
|
540
|
-
case 'local_fast_path':
|
|
541
|
-
return `${prefix} ${event.name ?? 'tool'}${event.argsSummary ? ` ${DIM(event.argsSummary)}` : ''}${event.argsArtifactId ? ` ${DIM(`args=/artifacts show ${event.argsArtifactId} --full${event.argsBytes ? ` (${(0, format_1.formatBytes)(event.argsBytes)})` : ''}`)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
542
|
-
case 'workspace_snapshot': {
|
|
543
|
-
const state = event.workspaceGitAvailable === false
|
|
544
|
-
? WARN('not-git')
|
|
545
|
-
: event.workspaceDirty
|
|
546
|
-
? WARN('dirty')
|
|
547
|
-
: SUCCESS('clean');
|
|
548
|
-
const files = event.workspaceFiles?.length
|
|
549
|
-
? ` files=${event.workspaceFiles.slice(0, 6).join(', ')}${event.workspaceFiles.length > 6 ? ', ...' : ''}`
|
|
550
|
-
: '';
|
|
551
|
-
return `${prefix} ${event.workspacePhase ?? 'unknown'} ${state} count=${event.workspaceFileCount ?? 0}${event.workspaceBranch ? ` branch=${event.workspaceBranch}` : ''}${files}${event.error ? ` ${ERROR(event.error)}` : ''}`;
|
|
552
|
-
}
|
|
553
|
-
case 'workspace_delta': {
|
|
554
|
-
const added = event.workspaceNewByTurn ?? [];
|
|
555
|
-
const changed = event.workspaceChangedByTurn ?? [];
|
|
556
|
-
const modifiedPreExisting = event.workspaceModifiedPreExistingByTurn ?? [];
|
|
557
|
-
const resolved = event.workspaceResolvedByTurn ?? [];
|
|
558
|
-
const parts = [
|
|
559
|
-
`after=${event.workspaceFileCount ?? 0}`,
|
|
560
|
-
`new=${added.length}`,
|
|
561
|
-
`changed=${changed.length}`,
|
|
562
|
-
`pre-existing-modified=${modifiedPreExisting.length}`,
|
|
563
|
-
`resolved=${resolved.length}`,
|
|
564
|
-
];
|
|
565
|
-
const details = [
|
|
566
|
-
added.length
|
|
567
|
-
? `new: ${added.slice(0, 6).join(', ')}${added.length > 6 ? ', ...' : ''}`
|
|
568
|
-
: '',
|
|
569
|
-
changed.length
|
|
570
|
-
? `changed: ${changed.slice(0, 6).join(', ')}${changed.length > 6 ? ', ...' : ''}`
|
|
571
|
-
: '',
|
|
572
|
-
modifiedPreExisting.length
|
|
573
|
-
? `pre-existing modified: ${modifiedPreExisting.slice(0, 6).join(', ')}${modifiedPreExisting.length > 6 ? ', ...' : ''}`
|
|
574
|
-
: '',
|
|
575
|
-
resolved.length
|
|
576
|
-
? `resolved: ${resolved.slice(0, 6).join(', ')}${resolved.length > 6 ? ', ...' : ''}`
|
|
577
|
-
: '',
|
|
578
|
-
]
|
|
579
|
-
.filter(Boolean)
|
|
580
|
-
.join(' | ');
|
|
581
|
-
return `${prefix} ${parts.join(' ')}${details ? ` ${DIM(details)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
582
|
-
}
|
|
583
|
-
case 'verification_profile': {
|
|
584
|
-
const commands = event.verificationCommands ?? [];
|
|
585
|
-
const files = event.verificationChangedFiles ?? [];
|
|
586
|
-
const details = [
|
|
587
|
-
`profile=${event.verificationProfile ?? 'unknown'}`,
|
|
588
|
-
`required=${event.verificationRequired === false ? 'no' : 'yes'}`,
|
|
589
|
-
`commands=${commands.length}`,
|
|
590
|
-
`files=${files.length}`,
|
|
591
|
-
];
|
|
592
|
-
if (event.verificationRisky) {
|
|
593
|
-
details.push(`risk=${WARN('high')}(${files.length} files)`);
|
|
594
|
-
}
|
|
595
|
-
const commandPreview = commands.length
|
|
596
|
-
? ` cmds: ${commands.slice(0, 4).join(' && ')}${commands.length > 4 ? ' && ...' : ''}`
|
|
597
|
-
: '';
|
|
598
|
-
return `${prefix} ${details.join(' ')}${commandPreview ? ` ${DIM(commandPreview)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
599
|
-
}
|
|
600
|
-
case 'verification_result': {
|
|
601
|
-
const status = event.verificationPassed === true ? SUCCESS('passed') : ERROR('failed');
|
|
602
|
-
const command = event.verificationCommand ?? 'unknown';
|
|
603
|
-
return `${prefix} ${status} ${command}${typeof event.outputBytes === 'number' ? ` ${DIM((0, format_1.formatBytes)(event.outputBytes))}` : ''}${event.error ? ` ${ERROR(event.error)}` : ''}`;
|
|
604
|
-
}
|
|
605
|
-
case 'verification_summary': {
|
|
606
|
-
const passed = event.verificationPassedCommands?.length ?? 0;
|
|
607
|
-
const failed = event.verificationFailedCommands?.length ?? 0;
|
|
608
|
-
const missing = event.verificationMissingCommands?.length ?? 0;
|
|
609
|
-
const parts = [
|
|
610
|
-
`profile=${event.verificationProfile ?? 'unknown'}`,
|
|
611
|
-
`required=${event.verificationRequired === false ? 'no' : 'yes'}`,
|
|
612
|
-
`passed=${passed}`,
|
|
613
|
-
`failed=${failed}`,
|
|
614
|
-
`missing=${missing}`,
|
|
615
|
-
`claimAllowed=${event.verificationClaimAllowed ? 'yes' : 'no'}`,
|
|
616
|
-
];
|
|
617
|
-
const missingPreview = missing > 0
|
|
618
|
-
? ` missing: ${(event.verificationMissingCommands ?? []).slice(0, 4).join(' && ')}${missing > 4 ? ' && ...' : ''}`
|
|
619
|
-
: '';
|
|
620
|
-
return `${prefix} ${parts.join(' ')}${missingPreview ? ` ${DIM(missingPreview)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
|
|
621
|
-
}
|
|
622
|
-
case 'aborted':
|
|
623
|
-
return `${prefix}${event.note ? ` ${WARN(event.note)}` : ''}`;
|
|
624
|
-
case 'error':
|
|
625
|
-
return `${prefix} ${ERROR(event.error ?? 'unknown error')}`;
|
|
626
|
-
default:
|
|
627
|
-
return prefix;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
function handleTrace(ctx, args = '') {
|
|
631
|
-
const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
|
|
632
|
-
if (!session) {
|
|
633
|
-
console.log(ERROR('No active session.'));
|
|
634
|
-
console.log(DIM('Use /resume <session-id> first, or start a chat turn to create a session.'));
|
|
635
|
-
return { success: false };
|
|
636
|
-
}
|
|
637
|
-
const events = (0, session_storage_1.readSessionTraceEvents)(session.id);
|
|
638
|
-
if (events.length === 0) {
|
|
639
|
-
console.log(DIM(`No trace events recorded for session ${session.id.slice(0, 8)} yet.`));
|
|
640
|
-
return { success: true };
|
|
641
|
-
}
|
|
642
|
-
const ref = args.trim();
|
|
643
|
-
const requestedTurnId = ref && ref !== 'latest' ? ref : events[events.length - 1].turnId;
|
|
644
|
-
const turnEvents = events.filter(event => event.turnId === requestedTurnId);
|
|
645
|
-
if (turnEvents.length === 0) {
|
|
646
|
-
const recentTurnIds = [...new Set(events.map(event => event.turnId))].slice(-8).reverse();
|
|
647
|
-
console.log(ERROR(`Trace turn not found: ${requestedTurnId}`));
|
|
648
|
-
console.log(DIM(`Recent turns: ${recentTurnIds.join(', ')}`));
|
|
649
|
-
return { success: false };
|
|
650
|
-
}
|
|
651
|
-
console.log(HEADER(`Trace ${requestedTurnId}`));
|
|
652
|
-
console.log(DIM(`Session ${session.id} Events ${turnEvents.length}`));
|
|
653
|
-
console.log(DIM('─'.repeat(40)));
|
|
654
|
-
for (const event of turnEvents) {
|
|
655
|
-
console.log(` ${formatTraceEventLine(event)}`);
|
|
656
|
-
}
|
|
657
|
-
console.log();
|
|
658
|
-
console.log(DIM('Trace stores metadata only; full transcript and tool output stay in session/artifacts.'));
|
|
659
|
-
return { success: true };
|
|
660
|
-
}
|
|
661
|
-
function latestToolTrace(events) {
|
|
662
|
-
for (let index = events.length - 1; index >= 0; index--) {
|
|
663
|
-
const event = events[index];
|
|
664
|
-
if (event.type !== 'tool_result' && event.type !== 'tool_call')
|
|
665
|
-
continue;
|
|
666
|
-
const callId = event.callId;
|
|
667
|
-
const result = event.type === 'tool_result' ? event : undefined;
|
|
668
|
-
const call = event.type === 'tool_call'
|
|
669
|
-
? event
|
|
670
|
-
: callId
|
|
671
|
-
? events
|
|
672
|
-
.slice(0, index)
|
|
673
|
-
.reverse()
|
|
674
|
-
.find(candidate => candidate.type === 'tool_call' && candidate.callId === callId)
|
|
675
|
-
: undefined;
|
|
676
|
-
return { call, result };
|
|
677
|
-
}
|
|
678
|
-
return null;
|
|
679
|
-
}
|
|
680
|
-
/** Find tool trace by 1-based sequence number across all tool events. */
|
|
681
|
-
function toolTraceBySeq(events, seq) {
|
|
682
|
-
let counter = 0;
|
|
683
|
-
const toolEvents = new Map();
|
|
684
|
-
for (const event of events) {
|
|
685
|
-
if (event.type !== 'tool_call' && event.type !== 'tool_result')
|
|
686
|
-
continue;
|
|
687
|
-
if (!event.callId)
|
|
688
|
-
continue;
|
|
689
|
-
const entry = toolEvents.get(event.callId) ?? {};
|
|
690
|
-
if (event.type === 'tool_call') {
|
|
691
|
-
counter++;
|
|
692
|
-
entry.call = event;
|
|
693
|
-
}
|
|
694
|
-
else {
|
|
695
|
-
if (!entry.call)
|
|
696
|
-
counter++;
|
|
697
|
-
entry.result = event;
|
|
698
|
-
}
|
|
699
|
-
toolEvents.set(event.callId, entry);
|
|
700
|
-
if (counter === seq) {
|
|
701
|
-
return toolEvents.get(event.callId) ?? null;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
/** Find tool trace by callId prefix. */
|
|
707
|
-
function toolTraceByCallId(events, callIdPrefix) {
|
|
708
|
-
let call;
|
|
709
|
-
let result;
|
|
710
|
-
for (const event of events) {
|
|
711
|
-
if (event.type !== 'tool_call' && event.type !== 'tool_result')
|
|
712
|
-
continue;
|
|
713
|
-
if (!event.callId?.startsWith(callIdPrefix))
|
|
714
|
-
continue;
|
|
715
|
-
if (event.type === 'tool_call')
|
|
716
|
-
call = event;
|
|
717
|
-
else
|
|
718
|
-
result = event;
|
|
719
|
-
}
|
|
720
|
-
if (!call && !result)
|
|
721
|
-
return null;
|
|
722
|
-
return { call, result };
|
|
723
|
-
}
|
|
724
|
-
/** Collect all tool trace pairs ordered by appearance (1-based sequence). */
|
|
725
|
-
function collectToolTracePairs(events) {
|
|
726
|
-
const pairs = [];
|
|
727
|
-
const seen = new Map();
|
|
728
|
-
let counter = 0;
|
|
729
|
-
for (const event of events) {
|
|
730
|
-
if (event.type !== 'tool_call' && event.type !== 'tool_result')
|
|
731
|
-
continue;
|
|
732
|
-
if (!event.callId)
|
|
733
|
-
continue;
|
|
734
|
-
let entry = seen.get(event.callId);
|
|
735
|
-
if (!entry) {
|
|
736
|
-
counter++;
|
|
737
|
-
entry = { seq: counter };
|
|
738
|
-
seen.set(event.callId, entry);
|
|
739
|
-
pairs.push(entry);
|
|
740
|
-
}
|
|
741
|
-
if (event.type === 'tool_call')
|
|
742
|
-
entry.call = event;
|
|
743
|
-
else
|
|
744
|
-
entry.result = event;
|
|
745
|
-
}
|
|
746
|
-
return pairs;
|
|
747
|
-
}
|
|
748
|
-
function parseLastToolArgs(args = '') {
|
|
749
|
-
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
750
|
-
const ref = parts.length > 0 && !parts[0].startsWith('--') ? parts[0] : undefined;
|
|
751
|
-
return {
|
|
752
|
-
full: parts.includes('--full'),
|
|
753
|
-
preview: !parts.includes('--no-preview'),
|
|
754
|
-
ref,
|
|
755
|
-
};
|
|
756
|
-
}
|
|
757
|
-
function printLastToolArtifactPreview(projectPath, label, artifactId, full) {
|
|
758
|
-
if (!artifactId)
|
|
759
|
-
return;
|
|
760
|
-
const artifact = (0, tool_artifacts_1.findArtifact)(projectPath, artifactId);
|
|
761
|
-
if (!artifact) {
|
|
762
|
-
console.log(` ${label} preview ${DIM(`artifact not found or ambiguous: ${artifactId}`)}`);
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
const content = (0, tool_artifacts_1.retrieveArtifact)(artifact.path);
|
|
766
|
-
if (content == null) {
|
|
767
|
-
console.log(` ${label} preview ${DIM(`artifact cannot be read: ${artifact.id}`)}`);
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
const redacted = (0, session_storage_1.redactTraceText)(content);
|
|
771
|
-
const maxPreviewBytes = 4 * 1024;
|
|
772
|
-
const shouldTruncate = !full && Buffer.byteLength(redacted, 'utf8') > maxPreviewBytes;
|
|
773
|
-
const preview = shouldTruncate
|
|
774
|
-
? Buffer.from(redacted, 'utf8').subarray(0, maxPreviewBytes).toString('utf8')
|
|
775
|
-
: redacted;
|
|
776
|
-
console.log(` ${label} preview`);
|
|
777
|
-
console.log(` ${DIM('─'.repeat(40))}`);
|
|
778
|
-
for (const line of preview.split('\n')) {
|
|
779
|
-
console.log(` ${line}`);
|
|
780
|
-
}
|
|
781
|
-
if (shouldTruncate) {
|
|
782
|
-
console.log(` ${DIM(`... preview truncated at ${(0, format_1.formatBytes)(maxPreviewBytes)}. Use /last-tool --full or /artifacts show ${artifact.id} --full.`)}`);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
function lastToolInputLabel(toolName) {
|
|
786
|
-
return toolName === 'exec_command' ? 'Command' : 'Args';
|
|
787
|
-
}
|
|
788
|
-
function lastToolField(label) {
|
|
789
|
-
return label.padEnd(13, ' ');
|
|
790
|
-
}
|
|
791
|
-
function handleLastTool(ctx, args = '') {
|
|
792
|
-
const options = parseLastToolArgs(args);
|
|
793
|
-
const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
|
|
794
|
-
if (!session) {
|
|
795
|
-
console.log(ERROR('No active session.'));
|
|
796
|
-
console.log(DIM('Use /resume <session-id> first, or start a chat turn to create a session.'));
|
|
797
|
-
return { success: false };
|
|
798
|
-
}
|
|
799
|
-
const events = (0, session_storage_1.readSessionTraceEvents)(session.id);
|
|
800
|
-
// Resolve reference: latest (default), #N, or callId prefix
|
|
801
|
-
let trace = null;
|
|
802
|
-
let listMode = false;
|
|
803
|
-
if (!options.ref || options.ref === 'latest') {
|
|
804
|
-
trace = latestToolTrace(events);
|
|
805
|
-
}
|
|
806
|
-
else if (/^#?\d+$/.test(options.ref)) {
|
|
807
|
-
const seq = parseInt(options.ref.replace('#', ''), 10);
|
|
808
|
-
trace = toolTraceBySeq(events, seq);
|
|
809
|
-
if (!trace) {
|
|
810
|
-
console.log(ERROR(`Tool #${seq} not found in session trace.`));
|
|
811
|
-
// Fall back to listing available tools
|
|
812
|
-
listMode = true;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
else {
|
|
816
|
-
trace = toolTraceByCallId(events, options.ref);
|
|
817
|
-
if (!trace) {
|
|
818
|
-
console.log(ERROR(`Tool with callId prefix "${options.ref}" not found in session trace.`));
|
|
819
|
-
listMode = true;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
if (listMode || !trace) {
|
|
823
|
-
const pairs = collectToolTracePairs(events);
|
|
824
|
-
if (pairs.length === 0) {
|
|
825
|
-
console.log(DIM(`No tool trace events recorded for session ${session.id.slice(0, 8)} yet.`));
|
|
826
|
-
return { success: true };
|
|
827
|
-
}
|
|
828
|
-
console.log(HEADER(`Tools (${pairs.length})`));
|
|
829
|
-
console.log(DIM('─'.repeat(60)));
|
|
830
|
-
for (const pair of pairs.slice(-30)) {
|
|
831
|
-
const source = pair.result ?? pair.call;
|
|
832
|
-
const name = source?.name ?? 'tool';
|
|
833
|
-
const status = pair.result ? (pair.result.success === false ? '✗' : '✓') : '…';
|
|
834
|
-
const duration = typeof pair.result?.duration === 'number'
|
|
835
|
-
? ` (${formatDurationMs(pair.result.duration)})`
|
|
836
|
-
: '';
|
|
837
|
-
const argsShort = (pair.call?.argsSummary ?? '').slice(0, 40);
|
|
838
|
-
console.log(` #${pair.seq} ${status} ${ACCENT(name)}${duration} ${DIM(argsShort)}`);
|
|
839
|
-
}
|
|
840
|
-
console.log();
|
|
841
|
-
console.log(DIM('Use /last-tool #N or /last-tool <callId> for details.'));
|
|
842
|
-
return { success: true };
|
|
843
|
-
}
|
|
844
|
-
const call = trace.call;
|
|
845
|
-
const result = trace.result;
|
|
846
|
-
const source = result ?? call;
|
|
847
|
-
const argsSource = call ?? result;
|
|
848
|
-
const name = source?.name ?? 'tool';
|
|
849
|
-
const inputLabel = lastToolInputLabel(name);
|
|
850
|
-
const callId = source?.callId ?? call?.callId;
|
|
851
|
-
const status = result
|
|
852
|
-
? result.success === false
|
|
853
|
-
? ERROR('error')
|
|
854
|
-
: SUCCESS('ok')
|
|
855
|
-
: WARN('running');
|
|
856
|
-
// Resolve sequence number from the trace events
|
|
857
|
-
let seqLabel = '';
|
|
858
|
-
if (options.ref && /^#?\d+$/.test(options.ref)) {
|
|
859
|
-
seqLabel = `#${parseInt(options.ref.replace('#', ''), 10)} `;
|
|
860
|
-
}
|
|
861
|
-
else if (result || call) {
|
|
862
|
-
const allPairs = collectToolTracePairs(events);
|
|
863
|
-
const matchingPair = allPairs.find(p => p.call?.callId === callId || p.result?.callId === callId);
|
|
864
|
-
if (matchingPair)
|
|
865
|
-
seqLabel = `#${matchingPair.seq} `;
|
|
866
|
-
}
|
|
867
|
-
console.log(HEADER(`Last Tool ${seqLabel}`.trimEnd()));
|
|
868
|
-
console.log(DIM('─'.repeat(40)));
|
|
869
|
-
console.log(` Tool ${ACCENT(name)}`);
|
|
870
|
-
console.log(` Turn ${DIM(source?.turnId ?? 'unknown')}`);
|
|
871
|
-
if (callId)
|
|
872
|
-
console.log(` Call ${DIM(callId)}`);
|
|
873
|
-
console.log(` Status ${status}`);
|
|
874
|
-
if (typeof result?.duration === 'number') {
|
|
875
|
-
console.log(` Time ${DIM(formatDurationMs(result.duration))}`);
|
|
876
|
-
}
|
|
877
|
-
if (argsSource?.argsSummary) {
|
|
878
|
-
console.log(` ${lastToolField(inputLabel)}${DIM((0, session_storage_1.redactTraceText)(argsSource.argsSummary))}`);
|
|
879
|
-
}
|
|
880
|
-
if (argsSource?.argsArtifactId) {
|
|
881
|
-
const size = typeof argsSource.argsBytes === 'number' ? ` (${(0, format_1.formatBytes)(argsSource.argsBytes)})` : '';
|
|
882
|
-
console.log(` ${lastToolField(`${inputLabel} full`)}${DIM(`/artifacts show ${argsSource.argsArtifactId} --full${size}`)}`);
|
|
883
|
-
}
|
|
884
|
-
if (typeof result?.outputBytes === 'number') {
|
|
885
|
-
const modelVisible = typeof result.modelVisibleBytes === 'number'
|
|
886
|
-
? `, model-visible ${(0, format_1.formatBytes)(result.modelVisibleBytes)}`
|
|
887
|
-
: '';
|
|
888
|
-
console.log(` Output ${DIM(`${(0, format_1.formatBytes)(result.outputBytes)}${modelVisible}`)}`);
|
|
889
|
-
}
|
|
890
|
-
if (result?.artifactId) {
|
|
891
|
-
console.log(` Output full ${DIM(`/artifacts show ${result.artifactId} --full`)}`);
|
|
892
|
-
}
|
|
893
|
-
if (result?.error) {
|
|
894
|
-
console.log(` Error ${ERROR((0, session_storage_1.redactTraceText)(result.error))}`);
|
|
895
|
-
}
|
|
896
|
-
if (options.preview) {
|
|
897
|
-
const projectPath = session.projectPath || ctx.cwd;
|
|
898
|
-
printLastToolArtifactPreview(projectPath, inputLabel, argsSource?.argsArtifactId, options.full);
|
|
899
|
-
printLastToolArtifactPreview(projectPath, 'Output', result?.artifactId, options.full);
|
|
900
|
-
}
|
|
901
|
-
console.log();
|
|
902
|
-
console.log(DIM('Use /last-tool --full for redacted full previews, --no-preview for metadata only, or /trace latest for the ordered turn timeline.'));
|
|
903
|
-
return { success: true };
|
|
904
|
-
}
|
|
905
|
-
function formatDateTime(timestamp) {
|
|
906
|
-
return new Date(timestamp).toLocaleString();
|
|
907
|
-
}
|
|
908
|
-
function parseArtifactArgs(args) {
|
|
909
|
-
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
910
|
-
let full = false;
|
|
911
|
-
let limit = 20;
|
|
912
|
-
const positional = [];
|
|
913
|
-
for (let i = 0; i < parts.length; i++) {
|
|
914
|
-
const part = parts[i];
|
|
915
|
-
if (part === '--full') {
|
|
916
|
-
full = true;
|
|
917
|
-
continue;
|
|
918
|
-
}
|
|
919
|
-
if ((part === '--limit' || part === '-n') && parts[i + 1]) {
|
|
920
|
-
const parsed = Number(parts[i + 1]);
|
|
921
|
-
if (Number.isInteger(parsed) && parsed > 0) {
|
|
922
|
-
limit = Math.min(parsed, 200);
|
|
923
|
-
}
|
|
924
|
-
i++;
|
|
925
|
-
continue;
|
|
926
|
-
}
|
|
927
|
-
positional.push(part);
|
|
928
|
-
}
|
|
929
|
-
if (positional[0] === 'show' || positional[0] === 'cat') {
|
|
930
|
-
return { action: 'show', ref: positional[1], full, limit };
|
|
931
|
-
}
|
|
932
|
-
if (positional[0]) {
|
|
933
|
-
return { action: 'show', ref: positional[0], full, limit };
|
|
934
|
-
}
|
|
935
|
-
return { action: 'list', full, limit };
|
|
936
|
-
}
|
|
937
|
-
function printArtifactPreview(content, full) {
|
|
938
|
-
const maxPreviewBytes = 16 * 1024;
|
|
939
|
-
if (full || Buffer.byteLength(content, 'utf8') <= maxPreviewBytes) {
|
|
940
|
-
console.log(content);
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
const preview = Buffer.from(content, 'utf8').subarray(0, maxPreviewBytes).toString('utf8');
|
|
944
|
-
console.log(preview);
|
|
945
|
-
console.log();
|
|
946
|
-
console.log(DIM(`... preview truncated at ${(0, format_1.formatBytes)(maxPreviewBytes)}. Use /artifacts show <id> --full for full output.`));
|
|
947
|
-
}
|
|
948
|
-
function formatArtifactPathForDisplay(artifactPath) {
|
|
949
|
-
return (0, session_storage_1.redactTraceText)(artifactPath);
|
|
950
|
-
}
|
|
951
|
-
function handleArtifacts(ctx, args = '') {
|
|
952
|
-
const parsed = parseArtifactArgs(args);
|
|
953
|
-
if (parsed.action === 'list') {
|
|
954
|
-
const artifacts = (0, tool_artifacts_1.listArtifacts)(ctx.cwd, parsed.limit);
|
|
955
|
-
console.log(HEADER('Artifacts'));
|
|
956
|
-
console.log(DIM('─'.repeat(40)));
|
|
957
|
-
if (artifacts.length === 0) {
|
|
958
|
-
console.log(DIM('No artifacts found for this project.'));
|
|
959
|
-
return { success: true };
|
|
960
|
-
}
|
|
961
|
-
for (const artifact of artifacts) {
|
|
962
|
-
console.log(`${ACCENT(artifact.id)} ${DIM(artifact.toolName)} ${(0, format_1.formatBytes)(artifact.outputBytes)}`);
|
|
963
|
-
console.log(` ${DIM(formatDateTime(artifact.modifiedAt))}`);
|
|
964
|
-
console.log(` ${DIM(formatArtifactPathForDisplay(artifact.path))}`);
|
|
965
|
-
}
|
|
966
|
-
console.log();
|
|
967
|
-
console.log(DIM('Use /artifacts show <id|prefix> to preview, or add --full for full output.'));
|
|
968
|
-
return { success: true };
|
|
969
|
-
}
|
|
970
|
-
if (!parsed.ref) {
|
|
971
|
-
console.log(ERROR('Usage: /artifacts show <id|prefix> [--full]'));
|
|
972
|
-
return { success: false };
|
|
973
|
-
}
|
|
974
|
-
const artifact = (0, tool_artifacts_1.findArtifact)(ctx.cwd, parsed.ref);
|
|
975
|
-
if (!artifact) {
|
|
976
|
-
console.log(ERROR(`Artifact not found or ambiguous: ${parsed.ref}`));
|
|
977
|
-
console.log(DIM('Run /artifacts to list available artifact ids.'));
|
|
978
|
-
return { success: false };
|
|
979
|
-
}
|
|
980
|
-
const content = (0, tool_artifacts_1.retrieveArtifact)(artifact.path);
|
|
981
|
-
if (content == null) {
|
|
982
|
-
console.log(ERROR(`Artifact exists but cannot be read: ${artifact.id}`));
|
|
983
|
-
console.log(DIM(formatArtifactPathForDisplay(artifact.path)));
|
|
984
|
-
return { success: false };
|
|
985
|
-
}
|
|
986
|
-
console.log(HEADER(`Artifact ${artifact.id}`));
|
|
987
|
-
console.log(DIM(`Tool ${artifact.toolName} Size ${(0, format_1.formatBytes)(artifact.outputBytes)} Modified ${formatDateTime(artifact.modifiedAt)}`));
|
|
988
|
-
console.log(DIM(formatArtifactPathForDisplay(artifact.path)));
|
|
989
|
-
console.log(DIM('─'.repeat(40)));
|
|
990
|
-
printArtifactPreview(content, parsed.full);
|
|
991
|
-
return { success: true };
|
|
992
|
-
}
|
|
993
|
-
function findCheckpointByRef(ctx, ref) {
|
|
994
|
-
const checkpoints = (0, checkpoint_1.listCheckpoints)(ctx.cwd);
|
|
995
|
-
const exact = checkpoints.find(checkpoint => checkpoint.turnId === ref);
|
|
996
|
-
if (exact)
|
|
997
|
-
return { checkpoint: exact, ambiguous: false };
|
|
998
|
-
const matches = checkpoints.filter(checkpoint => checkpoint.turnId.startsWith(ref));
|
|
999
|
-
return {
|
|
1000
|
-
checkpoint: matches.length === 1 ? matches[0] : undefined,
|
|
1001
|
-
ambiguous: matches.length > 1,
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
function handleCheckpoint(ctx, args = '') {
|
|
1005
|
-
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
1006
|
-
const action = tokens[0] ?? 'list';
|
|
1007
|
-
if (action === 'list') {
|
|
1008
|
-
const checkpoints = (0, checkpoint_1.listCheckpoints)(ctx.cwd);
|
|
1009
|
-
console.log(HEADER('Checkpoints'));
|
|
1010
|
-
console.log(DIM('─'.repeat(40)));
|
|
1011
|
-
if (checkpoints.length === 0) {
|
|
1012
|
-
console.log(DIM('No checkpoints found for this project.'));
|
|
1013
|
-
return { success: true };
|
|
1014
|
-
}
|
|
1015
|
-
for (const checkpoint of checkpoints.slice(0, 20)) {
|
|
1016
|
-
console.log(`${ACCENT(checkpoint.turnId)} ${DIM(formatDateTime(checkpoint.createdAt))}`);
|
|
1017
|
-
const files = checkpoint.files
|
|
1018
|
-
.map(file => file.path)
|
|
1019
|
-
.slice(0, 8)
|
|
1020
|
-
.join(', ');
|
|
1021
|
-
console.log(` ${DIM(`${checkpoint.files.length} file(s)${files ? `: ${files}` : ''}`)}`);
|
|
1022
|
-
}
|
|
1023
|
-
console.log();
|
|
1024
|
-
console.log(DIM('Use /checkpoint restore <turn-id|prefix> to preview, then add --yes to restore.'));
|
|
1025
|
-
return { success: true };
|
|
1026
|
-
}
|
|
1027
|
-
if (action !== 'restore') {
|
|
1028
|
-
console.log(ERROR('Usage: /checkpoint [list|restore <turn-id|prefix> [--yes]]'));
|
|
1029
|
-
return { success: false };
|
|
1030
|
-
}
|
|
1031
|
-
const ref = tokens.find(token => token !== 'restore' && token !== '--yes');
|
|
1032
|
-
const confirmed = tokens.includes('--yes');
|
|
1033
|
-
if (!ref) {
|
|
1034
|
-
console.log(ERROR('Usage: /checkpoint restore <turn-id|prefix> [--yes]'));
|
|
1035
|
-
return { success: false };
|
|
1036
|
-
}
|
|
1037
|
-
const { checkpoint, ambiguous } = findCheckpointByRef(ctx, ref);
|
|
1038
|
-
if (!checkpoint) {
|
|
1039
|
-
console.log(ERROR(ambiguous ? `Checkpoint prefix is ambiguous: ${ref}` : `Checkpoint not found: ${ref}`));
|
|
1040
|
-
console.log(DIM('Run /checkpoint to list available checkpoint ids.'));
|
|
1041
|
-
return { success: false };
|
|
1042
|
-
}
|
|
1043
|
-
if (!confirmed) {
|
|
1044
|
-
console.log(HEADER(`Checkpoint ${checkpoint.turnId}`));
|
|
1045
|
-
console.log(DIM(`${formatDateTime(checkpoint.createdAt)} ${checkpoint.files.length} file(s)`));
|
|
1046
|
-
for (const file of checkpoint.files.slice(0, 20)) {
|
|
1047
|
-
console.log(` ${file.path} ${DIM((0, format_1.formatBytes)(file.sizeBytes))}`);
|
|
1048
|
-
}
|
|
1049
|
-
console.log();
|
|
1050
|
-
console.log(WARN(`This will overwrite current files from checkpoint ${checkpoint.turnId}.`));
|
|
1051
|
-
console.log(DIM(`Run /checkpoint restore ${checkpoint.turnId} --yes to restore.`));
|
|
1052
|
-
return { success: true };
|
|
1053
|
-
}
|
|
1054
|
-
const result = (0, checkpoint_1.restoreCheckpoint)(ctx.cwd, checkpoint.turnId);
|
|
1055
|
-
if (result.error) {
|
|
1056
|
-
console.log(ERROR(result.error));
|
|
1057
|
-
return { success: false, error: result.error };
|
|
1058
|
-
}
|
|
1059
|
-
console.log(SUCCESS(`Restored ${result.restored.length} file(s) from checkpoint ${checkpoint.turnId}.`));
|
|
1060
|
-
for (const file of result.restored.slice(0, 20)) {
|
|
1061
|
-
console.log(` ${file}`);
|
|
1062
|
-
}
|
|
1063
|
-
return { success: true, output: result.restored.join('\n') };
|
|
1064
|
-
}
|
|
1065
|
-
function snapshotCurrentModel(ctx) {
|
|
1066
|
-
return ctx.store.getSnapshot().currentModel || ctx.config.model;
|
|
1067
|
-
}
|
|
1068
|
-
function getCommandAutoCompact(ctx, modelId) {
|
|
1069
|
-
if (ctx.compactCoordinator) {
|
|
1070
|
-
ctx.compactCoordinator.configure({
|
|
1071
|
-
modelId,
|
|
1072
|
-
llm: ctx.llm,
|
|
1073
|
-
outputReserveTokens: ctx.llm?.getMaxTokens?.(),
|
|
1074
|
-
});
|
|
1075
|
-
return ctx.compactCoordinator.getAutomatic();
|
|
1076
|
-
}
|
|
1077
|
-
return (0, auto_compact_1.getAutoCompact)({ modelId });
|
|
1078
|
-
}
|
|
1079
|
-
function showAgents(ctx) {
|
|
1080
|
-
console.log();
|
|
1081
|
-
console.log(HEADER('Registered Agents'));
|
|
1082
|
-
console.log(DIM('─'.repeat(40)));
|
|
1083
|
-
for (const agent of ctx.runtime.agents) {
|
|
1084
|
-
const status = agent.getStatus();
|
|
1085
|
-
const statusColor = status.status === 'idle' ? SUCCESS : WARN;
|
|
1086
|
-
console.log();
|
|
1087
|
-
console.log(` ${ACCENT(status.name)} ${DIM(`(${status.id})`)}`);
|
|
1088
|
-
console.log(` Status: ${statusColor(status.status)}`);
|
|
1089
|
-
console.log(` Capabilities: ${status.capabilities.join(', ')}`);
|
|
1090
|
-
}
|
|
1091
|
-
console.log();
|
|
1092
|
-
return { success: true };
|
|
1093
|
-
}
|
|
1094
|
-
function showMemory(ctx) {
|
|
1095
|
-
console.log();
|
|
1096
|
-
console.log(HEADER('Memory Status'));
|
|
1097
|
-
console.log(DIM('─'.repeat(40)));
|
|
1098
|
-
const memStatus = ctx.runtime.memory.getStatus();
|
|
1099
|
-
const storeStats = ctx.runtime.store.getStats();
|
|
1100
|
-
console.log();
|
|
1101
|
-
console.log(HEADER(' Inline MemorySystem:'));
|
|
1102
|
-
console.log(` Working ${memStatus.working} / ${ctx.runtime.config.memory.workingCapacity}`);
|
|
1103
|
-
console.log(` Short-term ${memStatus['short-term']} / ${ctx.runtime.config.memory.shortTermCapacity}`);
|
|
1104
|
-
console.log(` Long-term ${memStatus['long-term']} entries`);
|
|
1105
|
-
console.log();
|
|
1106
|
-
console.log(HEADER(' Modular MemoryStore:'));
|
|
1107
|
-
console.log(` Working ${storeStats.working}`);
|
|
1108
|
-
console.log(` Short-term ${storeStats['short-term']}`);
|
|
1109
|
-
console.log(` Long-term ${storeStats['long-term']} entries`);
|
|
1110
|
-
console.log();
|
|
1111
|
-
return { success: true };
|
|
1112
|
-
}
|
|
1113
|
-
async function handleMemoryReindex(_ctx) {
|
|
1114
|
-
const { isSemanticEnabled, getSemanticSearchService } = require('../memory/semantic-search');
|
|
1115
|
-
if (!isSemanticEnabled()) {
|
|
1116
|
-
console.log();
|
|
1117
|
-
console.log(WARN('⚠ Semantic search is not enabled.'));
|
|
1118
|
-
console.log(DIM(' Set ORION_CODE_EMBEDDING_PROVIDER=ollama or openai to enable.'));
|
|
1119
|
-
console.log();
|
|
1120
|
-
return { success: false };
|
|
1121
|
-
}
|
|
1122
|
-
console.log();
|
|
1123
|
-
console.log(HEADER('Reindexing project memories...'));
|
|
1124
|
-
try {
|
|
1125
|
-
const service = getSemanticSearchService();
|
|
1126
|
-
const count = await service.indexExistingMemories(process.cwd());
|
|
1127
|
-
console.log(SUCCESS(`✔ Indexed ${count} memories`));
|
|
1128
|
-
}
|
|
1129
|
-
catch (err) {
|
|
1130
|
-
console.log(ERROR(`✗ Reindex failed: ${err.message}`));
|
|
1131
|
-
return { success: false };
|
|
1132
|
-
}
|
|
1133
|
-
console.log();
|
|
1134
|
-
return { success: true };
|
|
1135
|
-
}
|
|
1136
|
-
async function handleMemory(ctx, args) {
|
|
1137
|
-
const sub = args.trim().toLowerCase();
|
|
1138
|
-
if (sub === 'reindex') {
|
|
1139
|
-
return handleMemoryReindex(ctx);
|
|
1140
|
-
}
|
|
1141
|
-
return showMemory(ctx);
|
|
1142
|
-
}
|
|
1143
|
-
function showSafety(ctx) {
|
|
1144
|
-
console.log();
|
|
1145
|
-
console.log(HEADER('Safety Checker'));
|
|
1146
|
-
console.log(DIM('─'.repeat(40)));
|
|
1147
|
-
const policy = ctx.runtime.safety.getPolicy();
|
|
1148
|
-
const summary = ctx.runtime.safety.getAuditSummary();
|
|
1149
|
-
console.log();
|
|
1150
|
-
console.log(` Enabled ${policy.enabled ? SUCCESS('yes') : ERROR('no')}`);
|
|
1151
|
-
console.log(` Sandbox ${policy.sandboxMode ? WARN('on') : DIM('off')}`);
|
|
1152
|
-
console.log();
|
|
1153
|
-
console.log(` Blocked patterns:`);
|
|
1154
|
-
for (const pattern of policy.blocked) {
|
|
1155
|
-
console.log(` ${ERROR('✗')} ${DIM(pattern)}`);
|
|
1156
|
-
}
|
|
1157
|
-
console.log();
|
|
1158
|
-
console.log(` Dangerous patterns:`);
|
|
1159
|
-
for (const pattern of policy.dangerousPatterns) {
|
|
1160
|
-
console.log(` ${WARN('⚠')} ${DIM(pattern)}`);
|
|
1161
|
-
}
|
|
1162
|
-
console.log();
|
|
1163
|
-
console.log(` Audit summary: ${summary.total} checks | ${SUCCESS(`${summary.passed} passed`)} | ${ERROR(`${summary.blocked} blocked`)}`);
|
|
1164
|
-
console.log();
|
|
1165
|
-
return { success: true };
|
|
1166
|
-
}
|
|
1167
|
-
function showHarness(ctx, args = '') {
|
|
1168
|
-
const explain = args.trim().toLowerCase() === 'explain';
|
|
1169
|
-
console.log();
|
|
1170
|
-
console.log(HEADER(explain ? 'Harness Explain' : 'Harness'));
|
|
1171
|
-
console.log(DIM('─'.repeat(40)));
|
|
1172
|
-
const cfg = ctx.runtime.harness.getConfig();
|
|
1173
|
-
console.log();
|
|
1174
|
-
if (!explain) {
|
|
1175
|
-
console.log(` Max steps ${cfg.maxSteps}`);
|
|
1176
|
-
console.log(` Boundary check ${cfg.boundaryCheck ? SUCCESS('on') : ERROR('off')}`);
|
|
1177
|
-
console.log(` Goal constraint ${cfg.goalConstraint ? SUCCESS('on') : ERROR('off')}`);
|
|
1178
|
-
console.log(` Result validate ${cfg.resultValidation ? SUCCESS('on') : ERROR('off')}`);
|
|
1179
|
-
console.log(` Sandbox ${cfg.sandbox ? WARN('on') : DIM('off')}`);
|
|
1180
|
-
console.log(` Timeout ${cfg.timeout}ms`);
|
|
1181
|
-
console.log(` Blocked actions ${DIM(cfg.blockedActions.join(', ') || 'none')}`);
|
|
1182
|
-
}
|
|
1183
|
-
const state = ctx.store.getSnapshot().harnessState;
|
|
1184
|
-
if (!state) {
|
|
1185
|
-
console.log();
|
|
1186
|
-
console.log(DIM(' No Context Harness state for this session yet.'));
|
|
1187
|
-
console.log();
|
|
1188
|
-
return { success: true };
|
|
1189
|
-
}
|
|
1190
|
-
if (explain) {
|
|
1191
|
-
// Build explain output from harnessState in store
|
|
1192
|
-
const contract = state.contract;
|
|
1193
|
-
// Contract section
|
|
1194
|
-
console.log(HEADER(' Contract'));
|
|
1195
|
-
if (contract) {
|
|
1196
|
-
console.log(` Objective ${ACCENT(contract.objective || '(none)')}`);
|
|
1197
|
-
if (contract.requirements?.length) {
|
|
1198
|
-
console.log(` Requires ${DIM(contract.requirements.slice(0, 3).join(' | '))}`);
|
|
1199
|
-
}
|
|
1200
|
-
if (contract.prohibitions?.length) {
|
|
1201
|
-
console.log(` Prohibits ${WARN(contract.prohibitions.slice(0, 3).join(' | '))}`);
|
|
1202
|
-
}
|
|
1203
|
-
if (contract.successCriteria?.length) {
|
|
1204
|
-
console.log(` Success ${DIM(contract.successCriteria.slice(0, 3).join(' | '))}`);
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
else {
|
|
1208
|
-
console.log(DIM(' (no contract established)'));
|
|
1209
|
-
}
|
|
1210
|
-
console.log();
|
|
1211
|
-
// Context source
|
|
1212
|
-
console.log(HEADER(' Context Source'));
|
|
1213
|
-
const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
|
|
1214
|
-
const isRestored = session?.transcriptDisplayStartTime != null;
|
|
1215
|
-
const isCompactActive = Boolean(state.promptAssemblyStats);
|
|
1216
|
-
console.log(` Root ${ACCENT(state.rootObjective || contract?.objective || '(none)')}`);
|
|
1217
|
-
console.log(` Active ${DIM(state.activeInstruction || contract?.userIntent || '(none)')}`);
|
|
1218
|
-
console.log(` Source ${isRestored ? WARN('restored session') : DIM('live turn')}`);
|
|
1219
|
-
if (isRestored && session) {
|
|
1220
|
-
const restoredTime = session.transcriptDisplayStartTime
|
|
1221
|
-
? new Date(session.transcriptDisplayStartTime).toLocaleString()
|
|
1222
|
-
: 'unknown';
|
|
1223
|
-
console.log(` Restored ${DIM(restoredTime)}`);
|
|
1224
|
-
}
|
|
1225
|
-
if (isCompactActive) {
|
|
1226
|
-
console.log(` Compact ${SUCCESS('active')}`);
|
|
1227
|
-
}
|
|
1228
|
-
console.log();
|
|
1229
|
-
// Evidence index summary
|
|
1230
|
-
console.log(HEADER(' Evidence Index'));
|
|
1231
|
-
const evidenceItems = state.evidenceIndex?.length ?? 0;
|
|
1232
|
-
const evidenceKinds = new Map();
|
|
1233
|
-
if (state.evidenceIndex) {
|
|
1234
|
-
for (const item of state.evidenceIndex) {
|
|
1235
|
-
const kind = item.kind || 'unknown';
|
|
1236
|
-
evidenceKinds.set(kind, (evidenceKinds.get(kind) || 0) + 1);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
console.log(` Total ${ACCENT(String(evidenceItems))} items`);
|
|
1240
|
-
if (evidenceKinds.size > 0) {
|
|
1241
|
-
const kinds = Array.from(evidenceKinds.entries())
|
|
1242
|
-
.sort((a, b) => b[1] - a[1])
|
|
1243
|
-
.slice(0, 10);
|
|
1244
|
-
for (const [kind, count] of kinds) {
|
|
1245
|
-
console.log(` ${DIM(kind.padEnd(16))} ${count}`);
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
else {
|
|
1249
|
-
console.log(DIM(' (no evidence records yet)'));
|
|
1250
|
-
}
|
|
1251
|
-
console.log();
|
|
1252
|
-
// Intent history
|
|
1253
|
-
console.log(HEADER(' Recent Intents'));
|
|
1254
|
-
const intents = state.intentHistory?.slice(-5) ?? [];
|
|
1255
|
-
if (intents.length > 0) {
|
|
1256
|
-
for (const intent of intents) {
|
|
1257
|
-
const conf = intent.confidence != null ? ` (${Math.round(intent.confidence * 100)}%)` : '';
|
|
1258
|
-
console.log(` ${ACCENT(intent.kind)}${DIM(conf)} ${DIM(intent.summary?.slice(0, 50) || '')}`);
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
else {
|
|
1262
|
-
console.log(DIM(' (no intents recorded)'));
|
|
1263
|
-
}
|
|
1264
|
-
console.log();
|
|
1265
|
-
// Capsule snapshot
|
|
1266
|
-
console.log(HEADER(' Capsule'));
|
|
1267
|
-
const capsule = state.capsule;
|
|
1268
|
-
if (capsule) {
|
|
1269
|
-
console.log(` Next ${DIM(capsule.nextAction)}`);
|
|
1270
|
-
if (capsule.completed?.length) {
|
|
1271
|
-
console.log(` Done ${SUCCESS(`${capsule.completed.length} steps`)}`);
|
|
1272
|
-
}
|
|
1273
|
-
if (capsule.openTodos?.length) {
|
|
1274
|
-
console.log(` Open ${WARN(`${capsule.openTodos.length} todos`)}`);
|
|
1275
|
-
}
|
|
1276
|
-
if (capsule.changedFiles?.length) {
|
|
1277
|
-
console.log(` Files ${DIM(capsule.changedFiles.slice(0, 5).join(', '))}`);
|
|
1278
|
-
}
|
|
1279
|
-
const passed = capsule.verification?.passed?.length ?? 0;
|
|
1280
|
-
const failed = capsule.verification?.failed?.length ?? 0;
|
|
1281
|
-
console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
|
|
1282
|
-
}
|
|
1283
|
-
else {
|
|
1284
|
-
console.log(DIM(' (no capsule yet)'));
|
|
1285
|
-
}
|
|
1286
|
-
console.log();
|
|
1287
|
-
// Prompt assembly stats
|
|
1288
|
-
const stats = state.promptAssemblyStats;
|
|
1289
|
-
console.log(HEADER(' Prompt Assembly'));
|
|
1290
|
-
if (stats) {
|
|
1291
|
-
console.log(` Model ${ACCENT(stats.modelId)}`);
|
|
1292
|
-
console.log(` Budget ${DIM(`${stats.estimatedTokens}/${stats.budgetTokens} tokens`)}`);
|
|
1293
|
-
console.log(` Sections ${DIM(stats.sections.join(', ') || 'none')}`);
|
|
1294
|
-
console.log(` Ledger ${DIM(`${state.ledger?.length ?? 0} entries`)}`);
|
|
1295
|
-
console.log(` Evidence ${DIM(`${state.evidenceIndex?.length ?? 0} records`)}`);
|
|
1296
|
-
console.log(` Turns ${DIM(`${state.turnSummaries?.length ?? 0} summaries`)}`);
|
|
1297
|
-
console.log();
|
|
1298
|
-
console.log(HEADER(' Included Evidence'));
|
|
1299
|
-
for (const item of stats.includedEvidence.slice(0, 10)) {
|
|
1300
|
-
console.log(` ${ACCENT(item.id)} ${DIM(`[${item.kind}] score=${item.score} tokens=${item.tokens}`)}`);
|
|
1301
|
-
console.log(` ${DIM(item.reason)}`);
|
|
1302
|
-
}
|
|
1303
|
-
if (stats.includedEvidence.length === 0) {
|
|
1304
|
-
console.log(DIM(' none'));
|
|
1305
|
-
}
|
|
1306
|
-
if (stats.omittedEvidence.length > 0) {
|
|
1307
|
-
console.log();
|
|
1308
|
-
console.log(HEADER(' Omitted Evidence'));
|
|
1309
|
-
for (const item of stats.omittedEvidence.slice(0, 8)) {
|
|
1310
|
-
console.log(` ${DIM(item.id)} ${DIM(`[${item.kind}] score=${item.score} tokens=${item.tokens}`)}`);
|
|
1311
|
-
console.log(` ${DIM(item.reason)}`);
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
else {
|
|
1316
|
-
console.log(DIM(' No prompt assembly stats recorded yet. Run a chat turn first.'));
|
|
1317
|
-
}
|
|
1318
|
-
console.log();
|
|
1319
|
-
console.log(HEADER(' Auto Compact'));
|
|
1320
|
-
const compactStats = getCommandAutoCompact(ctx, state.promptAssemblyStats?.modelId ?? snapshotCurrentModel(ctx)).getStats();
|
|
1321
|
-
const contextInfo = (0, model_context_1.resolveModelContext)(compactStats.modelId);
|
|
1322
|
-
console.log(` Model ${ACCENT(compactStats.modelId)}`);
|
|
1323
|
-
console.log(` Window ${DIM(`${formatTokenCount(contextInfo.contextWindow)} tokens (${contextInfo.source}${contextInfo.source === 'fuzzy' ? `:${contextInfo.matchedId}` : ''})`)}`);
|
|
1324
|
-
console.log(` Thresholds ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}, prewarm ${formatThreshold(compactStats.preCompactThreshold)}`)}`);
|
|
1325
|
-
console.log(` Usage ${DIM(`${compactStats.lastTokenCount} tokens, ${compactStats.ctxPercent}%`)}`);
|
|
1326
|
-
console.log(` Armed ${compactStats.preCompactArmed ? SUCCESS('yes') : DIM('no')}`);
|
|
1327
|
-
console.log(` Last mode ${DIM(compactStats.lastCompactMode ?? 'none')}`);
|
|
1328
|
-
console.log();
|
|
1329
|
-
return { success: true };
|
|
1330
|
-
}
|
|
1331
|
-
console.log();
|
|
1332
|
-
console.log(HEADER(' Context State'));
|
|
1333
|
-
console.log(` Version ${ACCENT(String(state.version ?? 1))}`);
|
|
1334
|
-
console.log(` Epoch ${ACCENT(String(state.taskEpoch ?? 1))}`);
|
|
1335
|
-
console.log(` Objective ${ACCENT(state.rootObjective ?? state.contract?.objective ?? '(none)')}`);
|
|
1336
|
-
console.log(` Active ${DIM(state.activeInstruction ?? state.contract?.userIntent ?? '(none)')}`);
|
|
1337
|
-
console.log(` Ledger ${DIM(`${state.ledger.length} entries`)}`);
|
|
1338
|
-
console.log(` Evidence ${DIM(`${state.evidenceIndex?.length ?? 0} records`)}`);
|
|
1339
|
-
console.log(` Turns ${DIM(`${state.turnSummaries?.length ?? 0} summaries`)}`);
|
|
1340
|
-
if (state.activeConstraints && state.activeConstraints.length > 0) {
|
|
1341
|
-
console.log(` Constraints ${DIM(state.activeConstraints.slice(0, 3).join(' | '))}`);
|
|
1342
|
-
}
|
|
1343
|
-
if (state.capsule) {
|
|
1344
|
-
console.log(` Next ${DIM(state.capsule.nextAction)}`);
|
|
1345
|
-
const passed = state.capsule.verification.passed.length;
|
|
1346
|
-
const failed = state.capsule.verification.failed.length;
|
|
1347
|
-
console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
|
|
1348
|
-
}
|
|
1349
|
-
if (state.diagnostics && state.diagnostics.length > 0) {
|
|
1350
|
-
console.log(` Diagnostics ${WARN(state.diagnostics.slice(-2).join(' | '))}`);
|
|
1351
|
-
}
|
|
1352
|
-
console.log();
|
|
1353
|
-
return { success: true };
|
|
1354
|
-
}
|
|
1355
|
-
function showConfig(ctx) {
|
|
1356
|
-
console.log();
|
|
1357
|
-
console.log(HEADER('Configuration'));
|
|
1358
|
-
console.log(DIM('─'.repeat(40)));
|
|
1359
|
-
const allowlist = (0, tool_allowlist_1.resolveProjectToolAllowlist)(ctx.cwd);
|
|
1360
|
-
const allowlistSummary = allowlist.rules.length === 0 && allowlist.invalid.length === 0
|
|
1361
|
-
? '(none)'
|
|
1362
|
-
: `${allowlist.rules.length} rule(s)` +
|
|
1363
|
-
(allowlist.invalid.length > 0 ? `, ${allowlist.invalid.length} invalid (ignored)` : '');
|
|
1364
|
-
const summary = {
|
|
1365
|
-
name: ctx.config.name,
|
|
1366
|
-
model: ctx.config.model,
|
|
1367
|
-
apiBaseUrl: ctx.config.apiBaseUrl || '(default OpenAI)',
|
|
1368
|
-
apiKey: (0, mask_1.maskSecret)(ctx.config.apiKey),
|
|
1369
|
-
mode: ctx.config.mode,
|
|
1370
|
-
logLevel: ctx.config.logLevel,
|
|
1371
|
-
toolConfirmation: ctx.config.toolConfirmation,
|
|
1372
|
-
allowedTools: allowlistSummary,
|
|
1373
|
-
};
|
|
1374
|
-
const llmSummary = ctx.llm?.getConfigSummary() ?? {};
|
|
1375
|
-
for (const [key, val] of Object.entries(summary)) {
|
|
1376
|
-
console.log(` ${ACCENT(key.padEnd(16))} ${DIM(val)}`);
|
|
1377
|
-
}
|
|
1378
|
-
if (allowlist.rules.length > 0 || allowlist.invalid.length > 0) {
|
|
1379
|
-
console.log();
|
|
1380
|
-
console.log(HEADER(' Project allowedTools:'));
|
|
1381
|
-
for (const rule of allowlist.rules) {
|
|
1382
|
-
console.log(` ${ACCENT(rule.effect.padEnd(6))} ${DIM(rule.tool)}${DIM(rule.pattern ? `(${rule.pattern})` : '')}`);
|
|
1383
|
-
}
|
|
1384
|
-
for (const entry of allowlist.invalid) {
|
|
1385
|
-
console.log(` ${WARN('invalid')} ${DIM(entry)}`);
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
console.log();
|
|
1389
|
-
console.log(HEADER(' LLM Settings:'));
|
|
1390
|
-
for (const [key, val] of Object.entries(llmSummary)) {
|
|
1391
|
-
console.log(` ${ACCENT(key.padEnd(16))} ${DIM(val)}`);
|
|
1392
|
-
}
|
|
1393
|
-
console.log();
|
|
1394
|
-
return { success: true };
|
|
1395
|
-
}
|
|
1396
|
-
function handleModel(ctx, args) {
|
|
1397
|
-
const trimmedArgs = args.trim().toLowerCase();
|
|
1398
|
-
// 显示当前模型
|
|
1399
|
-
if (!args || trimmedArgs === '?' || trimmedArgs === 'info') {
|
|
1400
|
-
console.log();
|
|
1401
|
-
if (ctx.llm) {
|
|
1402
|
-
const currentModel = ctx.store.getSnapshot().currentModel || ctx.llm.getModel();
|
|
1403
|
-
const profile = getProfileByModelId(ctx.config.modelRegistry, currentModel);
|
|
1404
|
-
const aliasEntry = (0, model_catalog_1.getModelCatalogEntry)(currentModel);
|
|
1405
|
-
const contextInfo = profile
|
|
1406
|
-
? {
|
|
1407
|
-
id: profile.model,
|
|
1408
|
-
label: profile.displayName || profile.id,
|
|
1409
|
-
contextWindow: profile.resolvedContextWindow,
|
|
1410
|
-
maxOutputTokens: profile.resolvedMaxOutputTokens,
|
|
1411
|
-
source: 'config',
|
|
1412
|
-
matchedId: profile.model,
|
|
1413
|
-
}
|
|
1414
|
-
: (0, model_context_1.resolveModelContext)(currentModel);
|
|
1415
|
-
const compactStats = getCommandAutoCompact(ctx, currentModel).getStats();
|
|
1416
|
-
console.log(HEADER('Current Model'));
|
|
1417
|
-
console.log(DIM('─'.repeat(40)));
|
|
1418
|
-
console.log(` Model ${BRAND(currentModel)}`);
|
|
1419
|
-
if (profile) {
|
|
1420
|
-
console.log(` Alias ${ACCENT(profile.aliases?.[0] ? `(${profile.aliases[0]})` : 'none')}`);
|
|
1421
|
-
const provider = ctx.config.modelRegistry?.providers.get(profile.provider);
|
|
1422
|
-
console.log(` Provider ${DIM(provider?.displayName || profile.provider)}`);
|
|
1423
|
-
}
|
|
1424
|
-
else if (aliasEntry) {
|
|
1425
|
-
console.log(` Alias ${ACCENT(aliasEntry.alias)}`);
|
|
1426
|
-
console.log(` Provider ${DIM(aliasEntry.provider)}`);
|
|
1427
|
-
}
|
|
1428
|
-
console.log(` Context ${DIM(`${formatTokenCount(contextInfo.contextWindow)} tokens`)}`);
|
|
1429
|
-
if (contextInfo.maxOutputTokens) {
|
|
1430
|
-
console.log(` Output ${DIM(`${formatTokenCount(contextInfo.maxOutputTokens)} tokens`)}`);
|
|
1431
|
-
}
|
|
1432
|
-
console.log(` Source ${DIM(`${contextInfo.source}${contextInfo.source === 'fuzzy' ? `:${contextInfo.matchedId}` : ''}`)}`);
|
|
1433
|
-
console.log(` Compact ${compactStats.enabled ? SUCCESS('auto') : WARN('off')} ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}`)}`);
|
|
1434
|
-
}
|
|
1435
|
-
else {
|
|
1436
|
-
console.log(ERROR('LLM not initialized. Set ORION_CODE_API_KEY first.'));
|
|
1437
|
-
}
|
|
1438
|
-
console.log();
|
|
1439
|
-
return { success: true };
|
|
1440
|
-
}
|
|
1441
|
-
// /model list|ls|help 已移除,统一由 /models 承接(交互式选择切换)
|
|
1442
|
-
if (trimmedArgs === 'list' || trimmedArgs === 'ls' || trimmedArgs === 'help') {
|
|
1443
|
-
console.log();
|
|
1444
|
-
console.log(WARN(`/model ${trimmedArgs} was removed.`));
|
|
1445
|
-
console.log(DIM('Use /models to switch models interactively,'));
|
|
1446
|
-
console.log(DIM('or /model <name|alias> to switch directly, e.g. /model sonnet'));
|
|
1447
|
-
console.log();
|
|
1448
|
-
return { success: true };
|
|
1449
|
-
}
|
|
1450
|
-
// 设置模型
|
|
1451
|
-
if (!ctx.llm) {
|
|
1452
|
-
console.log(ERROR('LLM not initialized. Set ORION_CODE_API_KEY first.'));
|
|
1453
|
-
console.log();
|
|
1454
|
-
return { success: false };
|
|
1455
|
-
}
|
|
1456
|
-
// 解析别名
|
|
1457
|
-
const registryProfile = resolveModelFromRegistry(ctx.config, args);
|
|
1458
|
-
const resolvedModel = registryProfile ? registryProfile.model : (0, model_catalog_1.resolveModelAlias)(args);
|
|
1459
|
-
const resolvedProfileId = registryProfile ? registryProfile.id : resolvedModel;
|
|
1460
|
-
ctx.llm.setModel(resolvedModel);
|
|
1461
|
-
getCommandAutoCompact(ctx, resolvedModel);
|
|
1462
|
-
ctx.store.setState({ currentModel: resolvedProfileId });
|
|
1463
|
-
console.log(SUCCESS(`✔ Model changed to ${BRAND(resolvedProfileId)}`));
|
|
1464
|
-
const contextInfo = registryProfile
|
|
1465
|
-
? {
|
|
1466
|
-
contextWindow: registryProfile.resolvedContextWindow,
|
|
1467
|
-
maxOutputTokens: registryProfile.resolvedMaxOutputTokens,
|
|
1468
|
-
source: 'resolved',
|
|
1469
|
-
}
|
|
1470
|
-
: (0, model_context_1.resolveModelContext)(resolvedModel);
|
|
1471
|
-
console.log(DIM(` Context window ${formatTokenCount(contextInfo.contextWindow)} tokens (${contextInfo.source})`));
|
|
1472
|
-
console.log();
|
|
1473
|
-
return { success: true };
|
|
1474
|
-
}
|
|
1475
|
-
/**
|
|
1476
|
-
* /models — 交互式选择切换模型。
|
|
1477
|
-
* 交互式渲染器返回结构化 modelPicker 请求(渲染器弹出选择层,选中即 /model <id>);
|
|
1478
|
-
* 非交互式渲染器直接打印候选列表并提示 /model <name|alias>。
|
|
1479
|
-
*/
|
|
1480
|
-
function handleModels(ctx, _args) {
|
|
1481
|
-
console.log();
|
|
1482
|
-
const currentModel = ctx.store.getSnapshot().currentModel || ctx.llm?.getModel() || '';
|
|
1483
|
-
const configuredModels = listConfiguredModelCatalogEntries(ctx.config.modelRegistry);
|
|
1484
|
-
const candidates = configuredModels.length > 0
|
|
1485
|
-
? configuredModels
|
|
1486
|
-
: (0, model_catalog_1.listModelCatalogEntries)().map(model => {
|
|
1487
|
-
const contextInfo = (0, model_context_1.resolveModelContext)(model.name);
|
|
1488
|
-
return {
|
|
1489
|
-
name: model.name,
|
|
1490
|
-
alias: model.alias,
|
|
1491
|
-
provider: model.provider,
|
|
1492
|
-
contextWindow: contextInfo.contextWindow,
|
|
1493
|
-
maxOutputTokens: contextInfo.maxOutputTokens,
|
|
1494
|
-
source: contextInfo.source,
|
|
1495
|
-
};
|
|
1496
|
-
});
|
|
1497
|
-
const ui = commandUICapabilities(ctx);
|
|
1498
|
-
if (ui.structuredPickers) {
|
|
1499
|
-
return {
|
|
1500
|
-
success: true,
|
|
1501
|
-
modelPicker: {
|
|
1502
|
-
models: candidates,
|
|
1503
|
-
currentModel,
|
|
1504
|
-
title: 'Switch Model',
|
|
1505
|
-
maxVisibleItems: 12,
|
|
1506
|
-
},
|
|
1507
|
-
};
|
|
1508
|
-
}
|
|
1509
|
-
// 非交互式渲染器:打印候选列表
|
|
1510
|
-
console.log(HEADER('Available Models'));
|
|
1511
|
-
console.log(DIM('─'.repeat(40)));
|
|
1512
|
-
const modelPicker = (0, ui_view_model_1.createModelPickerState)({ currentModel, models: candidates });
|
|
1513
|
-
for (const item of modelPicker.visibleItems) {
|
|
1514
|
-
const marker = item.isCurrent ? SUCCESS('●') : DIM('○');
|
|
1515
|
-
const alias = item.alias ? `(${item.alias})` : '';
|
|
1516
|
-
const context = `${formatTokenCount(item.contextWindow ?? 0)} ctx`;
|
|
1517
|
-
const current = item.isCurrent ? BRAND('(current)') : '';
|
|
1518
|
-
console.log(` ${marker} ${ACCENT(item.name)} ${DIM(alias)} ${DIM(context)} ${current}`);
|
|
1519
|
-
console.log(` ${DIM(item.provider ?? 'unknown')}`);
|
|
1520
|
-
}
|
|
1521
|
-
console.log();
|
|
1522
|
-
console.log(DIM('Use /model <name|alias> to switch, e.g. /model sonnet'));
|
|
1523
|
-
console.log();
|
|
1524
|
-
return { success: true };
|
|
1525
|
-
}
|
|
1526
|
-
function normalizePermissionMode(raw) {
|
|
1527
|
-
const value = raw.trim().toLowerCase();
|
|
1528
|
-
if (!value)
|
|
1529
|
-
return null;
|
|
1530
|
-
if (value === 'accept' ||
|
|
1531
|
-
value === 'acceptedits' ||
|
|
1532
|
-
value === 'accept-edits' ||
|
|
1533
|
-
value === 'edit') {
|
|
1534
|
-
return 'acceptEdits';
|
|
1535
|
-
}
|
|
1536
|
-
if (value === 'default' || value === 'ask')
|
|
1537
|
-
return 'default';
|
|
1538
|
-
if (value === 'plan' || value === 'readonly' || value === 'read-only')
|
|
1539
|
-
return 'plan';
|
|
1540
|
-
if (value === 'auto' || value === 'full-auto')
|
|
1541
|
-
return 'auto';
|
|
1542
|
-
return null;
|
|
1543
|
-
}
|
|
1544
|
-
function handleMode(ctx, args) {
|
|
1545
|
-
const current = ctx.store.getSnapshot().permissionMode;
|
|
1546
|
-
const trimmed = args.trim();
|
|
1547
|
-
if (!trimmed || trimmed === '?' || trimmed === 'help') {
|
|
1548
|
-
console.log();
|
|
1549
|
-
console.log(HEADER('Permission Mode'));
|
|
1550
|
-
console.log(DIM('─'.repeat(40)));
|
|
1551
|
-
console.log(` Current ${ACCENT(current)} ${DIM((0, types_1.getModeDisplayText)(current) || 'ask before sensitive actions')}`);
|
|
1552
|
-
console.log();
|
|
1553
|
-
console.log(` ${ACCENT('/mode next')} Cycle to the next mode`);
|
|
1554
|
-
console.log(` ${ACCENT('/mode default')} Ask before sensitive actions`);
|
|
1555
|
-
console.log(` ${ACCENT('/mode accept-edits')} Auto-accept file edits`);
|
|
1556
|
-
console.log(` ${ACCENT('/mode plan')} Plan first, avoid executing edits`);
|
|
1557
|
-
console.log(` ${ACCENT('/mode auto')} Auto-run allowed actions`);
|
|
1558
|
-
console.log();
|
|
1559
|
-
return { success: true };
|
|
1560
|
-
}
|
|
1561
|
-
const next = trimmed === 'next' ? (0, types_1.getNextPermissionMode)(current) : normalizePermissionMode(trimmed);
|
|
1562
|
-
if (!next || !types_1.PERMISSION_MODES.includes(next)) {
|
|
1563
|
-
return {
|
|
1564
|
-
success: false,
|
|
1565
|
-
error: `Unknown mode: ${trimmed}. Use one of: default, accept-edits, plan, auto, next.`,
|
|
1566
|
-
};
|
|
1567
|
-
}
|
|
1568
|
-
ctx.store.setPermissionMode(next);
|
|
1569
|
-
const display = (0, types_1.getModeDisplayText)(next);
|
|
1570
|
-
return {
|
|
1571
|
-
success: true,
|
|
1572
|
-
output: `Mode changed to ${next}${display ? ` (${display})` : ''}.`,
|
|
1573
|
-
};
|
|
1574
|
-
}
|
|
1575
|
-
function handleTask(ctx, args) {
|
|
1576
|
-
const [sub] = args.trim().split(/\s+/);
|
|
1577
|
-
if (sub === 'list' || sub === 'ls') {
|
|
1578
|
-
if (!taskManager) {
|
|
1579
|
-
taskManager = new task_manager_1.TaskManager();
|
|
1580
|
-
}
|
|
1581
|
-
console.log();
|
|
1582
|
-
console.log(HEADER('Task List'));
|
|
1583
|
-
console.log(DIM('─'.repeat(40)));
|
|
1584
|
-
const stats = taskManager.getStats();
|
|
1585
|
-
console.log(` Total ${stats.total}`);
|
|
1586
|
-
console.log(` Pending ${stats.pending}`);
|
|
1587
|
-
console.log(` Running ${stats.running}`);
|
|
1588
|
-
console.log(` Completed ${SUCCESS(stats.completed)}`);
|
|
1589
|
-
console.log(` Failed ${ERROR(stats.failed)}`);
|
|
1590
|
-
console.log(` Cancelled ${DIM(stats.cancelled)}`);
|
|
1591
|
-
const tasks = taskManager.list();
|
|
1592
|
-
if (tasks.length > 0) {
|
|
1593
|
-
console.log();
|
|
1594
|
-
for (const t of tasks) {
|
|
1595
|
-
const statusIcon = t.status === 'completed'
|
|
1596
|
-
? SUCCESS('✓')
|
|
1597
|
-
: t.status === 'failed'
|
|
1598
|
-
? ERROR('✗')
|
|
1599
|
-
: t.status === 'running'
|
|
1600
|
-
? WARN('◌')
|
|
1601
|
-
: t.status === 'cancelled'
|
|
1602
|
-
? DIM('⊘')
|
|
1603
|
-
: DIM('○');
|
|
1604
|
-
console.log(` ${statusIcon} ${ACCENT(t.name)} ${DIM(`(${t.id.slice(0, 8)})`)}`);
|
|
1605
|
-
console.log(` ${DIM(`[${t.priority}]`)} ${t.description.slice(0, 60)}`);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
console.log();
|
|
1609
|
-
return { success: true };
|
|
1610
|
-
}
|
|
1611
|
-
// 默认行为: 作为任务名提交
|
|
1612
|
-
const taskName = args.trim() || 'demo-task';
|
|
1613
|
-
const task = {
|
|
1614
|
-
id: `cli-${Date.now()}`,
|
|
1615
|
-
name: taskName,
|
|
1616
|
-
description: `Task submitted from CLI: ${taskName}`,
|
|
1617
|
-
priority: 'P1',
|
|
1618
|
-
assignedTo: 'leader',
|
|
1619
|
-
status: 'pending',
|
|
1620
|
-
};
|
|
1621
|
-
console.log();
|
|
1622
|
-
ctx.runtime.brain.submitTask(task);
|
|
1623
|
-
console.log(SUCCESS(`✔ Task "${taskName}" submitted`));
|
|
1624
|
-
console.log();
|
|
1625
|
-
return { success: true };
|
|
1626
|
-
}
|
|
1627
|
-
async function handleRun(ctx, args) {
|
|
1628
|
-
if (!args.trim()) {
|
|
1629
|
-
console.log(ERROR('Usage: /run <task description>'));
|
|
1630
|
-
console.log(DIM(' Creates a task and executes it through the Agent + LLM pipeline.'));
|
|
1631
|
-
console.log();
|
|
1632
|
-
return { success: false };
|
|
1633
|
-
}
|
|
1634
|
-
if (!ctx.llm || !(0, config_1.isConfigured)(ctx.config)) {
|
|
1635
|
-
console.log(WARN('⚠ LLM not configured. Set ORION_CODE_API_KEY in .env to enable run mode.'));
|
|
1636
|
-
console.log();
|
|
1637
|
-
return { success: false };
|
|
1638
|
-
}
|
|
1639
|
-
if (!taskManager) {
|
|
1640
|
-
taskManager = new task_manager_1.TaskManager();
|
|
1641
|
-
}
|
|
1642
|
-
const taskOptions = {
|
|
1643
|
-
name: args.slice(0, 80),
|
|
1644
|
-
description: args,
|
|
1645
|
-
priority: 'P1',
|
|
1646
|
-
assignedTo: 'leader',
|
|
1647
|
-
tags: ['cli', 'interactive'],
|
|
1648
|
-
};
|
|
1649
|
-
const record = taskManager.create(taskOptions);
|
|
1650
|
-
console.log();
|
|
1651
|
-
console.log(SUCCESS(`✔ Task created: ${ACCENT(record.name)}`));
|
|
1652
|
-
console.log(DIM(` ID: ${record.id} | Tags: ${record.tags.join(', ')}`));
|
|
1653
|
-
taskManager.start(record.id);
|
|
1654
|
-
console.log(WARN('◌ Running task through Agent + LLM...'));
|
|
1655
|
-
try {
|
|
1656
|
-
const agent = ctx.runtime.agents[0];
|
|
1657
|
-
if (!agent) {
|
|
1658
|
-
throw new Error('No agents registered');
|
|
1659
|
-
}
|
|
1660
|
-
const runner = new agent_runner_1.AgentRunner(agent, ctx.llm);
|
|
1661
|
-
const task = taskManager.toTask(record);
|
|
1662
|
-
const result = await runner.run(task);
|
|
1663
|
-
if (result.success) {
|
|
1664
|
-
taskManager.complete(record.id, result);
|
|
1665
|
-
console.log(SUCCESS(`✓ Task completed in ${result.duration}ms`));
|
|
1666
|
-
if (result.tokenUsage) {
|
|
1667
|
-
console.log(DIM(` Tokens: ${result.tokenUsage.promptTokens} in / ${result.tokenUsage.completionTokens} out`));
|
|
1668
|
-
}
|
|
1669
|
-
if (result.data?.summary) {
|
|
1670
|
-
console.log();
|
|
1671
|
-
console.log(ACCENT(' Summary:'));
|
|
1672
|
-
console.log(` ${result.data.summary}`);
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
else {
|
|
1676
|
-
taskManager.fail(record.id, result.error, result);
|
|
1677
|
-
console.log(ERROR(`✗ Task failed: ${result.error}`));
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
catch (error) {
|
|
1681
|
-
taskManager.fail(record.id, error.message);
|
|
1682
|
-
console.log(ERROR(`✗ Task error: ${error.message}`));
|
|
1683
|
-
}
|
|
1684
|
-
console.log();
|
|
1685
|
-
return { success: true };
|
|
1686
|
-
}
|
|
1687
|
-
async function handleChat(ctx, input) {
|
|
1688
|
-
const ui = commandUICapabilities(ctx);
|
|
1689
|
-
const writeOutput = ctx.writeOutput ?? ((text) => process.stdout.write(text));
|
|
1690
|
-
const writeLine = ctx.writeLine ?? ((text = '') => console.log(text));
|
|
1691
|
-
if (!input) {
|
|
1692
|
-
console.log(ERROR('Usage: /chat <message>'));
|
|
1693
|
-
console.log();
|
|
1694
|
-
return { success: false };
|
|
1695
|
-
}
|
|
1696
|
-
if (!ctx.llm || !(0, config_1.isConfigured)(ctx.config)) {
|
|
1697
|
-
console.log(WARN('⚠ LLM not configured. Set ORION_CODE_API_KEY in .env to enable chat.'));
|
|
1698
|
-
console.log();
|
|
1699
|
-
return { success: false };
|
|
1700
|
-
}
|
|
1701
|
-
const activeSession = ctx.getSession?.() ??
|
|
1702
|
-
ctx.ensureSession?.() ??
|
|
1703
|
-
(ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
|
|
1704
|
-
const sessionId = activeSession?.id ?? ctx.sessionId;
|
|
1705
|
-
const runtimeTools = (0, tools_1.getRuntimeTools)();
|
|
1706
|
-
const skillResolution = (0, skills_1.resolveSkillsForTurn)({
|
|
1707
|
-
cwd: ctx.cwd,
|
|
1708
|
-
input,
|
|
1709
|
-
tools: runtimeTools,
|
|
1710
|
-
projectPath: activeSession?.projectPath,
|
|
1711
|
-
sessionId,
|
|
1712
|
-
});
|
|
1713
|
-
const appliedSkillNames = skillResolution.skills.map(skill => skill.name);
|
|
1714
|
-
// Record user message to session
|
|
1715
|
-
if (sessionId) {
|
|
1716
|
-
(0, session_storage_1.appendSessionMessage)(sessionId, {
|
|
1717
|
-
role: 'user',
|
|
1718
|
-
content: input,
|
|
1719
|
-
timestamp: Date.now(),
|
|
1720
|
-
appliedSkills: appliedSkillNames.length > 0 ? appliedSkillNames : undefined,
|
|
1721
|
-
});
|
|
1722
|
-
}
|
|
1723
|
-
ctx.store.addMessage({ role: 'user', content: input });
|
|
1724
|
-
(0, prompt_context_1.refreshProjectInstructions)(ctx.store, ctx.cwd);
|
|
1725
|
-
const snapshot = ctx.store.getSnapshot();
|
|
1726
|
-
const harness = (0, harness_1.createContextHarness)({
|
|
1727
|
-
cwd: ctx.cwd,
|
|
1728
|
-
modelId: ctx.llm.getModel(),
|
|
1729
|
-
state: snapshot.harnessState,
|
|
1730
|
-
config: {
|
|
1731
|
-
enabled: true,
|
|
1732
|
-
driftGuard: 'warn',
|
|
1733
|
-
completionGate: true,
|
|
1734
|
-
},
|
|
1735
|
-
});
|
|
1736
|
-
const intent = harness.updateContractFromUserInput(input);
|
|
1737
|
-
harness.recordAppliedSkills(skillResolution.skills);
|
|
1738
|
-
const promptCtx = {
|
|
1739
|
-
cwd: ctx.cwd,
|
|
1740
|
-
platform: process.platform,
|
|
1741
|
-
nodeVersion: process.version,
|
|
1742
|
-
tools: skillResolution.tools,
|
|
1743
|
-
memoryContent: snapshot.memoryContent,
|
|
1744
|
-
skillsContent: snapshot.skillsContent,
|
|
1745
|
-
projectInstructionsContent: snapshot.projectInstructionsContent,
|
|
1746
|
-
activeSkillsContent: skillResolution.promptInjection,
|
|
1747
|
-
referencedFilesContent: (0, file_context_1.buildReferencedFilesPrompt)(input, ctx.cwd),
|
|
1748
|
-
};
|
|
1749
|
-
const systemPrompt = (0, framework_1.getSystemPrompt)(promptCtx);
|
|
1750
|
-
const spinner = (0, box_1.createSpinner)();
|
|
1751
|
-
const useSpinner = !ui.inlineProgress;
|
|
1752
|
-
if (useSpinner) {
|
|
1753
|
-
spinner.start('Thinking');
|
|
1754
|
-
}
|
|
1755
|
-
let finalContent = '';
|
|
1756
|
-
let finalModel = '';
|
|
1757
|
-
let finalUsage;
|
|
1758
|
-
let responseStarted = false;
|
|
1759
|
-
const sessionMessagesToRecord = [];
|
|
1760
|
-
// Issue #22: 批量工具调用进度显示
|
|
1761
|
-
let toolCallCount = 0;
|
|
1762
|
-
let lastProgressUpdate = 0;
|
|
1763
|
-
// 流式 Markdown 渲染器
|
|
1764
|
-
let streamRenderer = null;
|
|
1765
|
-
// Issue #32 #3.2: toolExecutor 支持 abortSignal
|
|
1766
|
-
const toolExecutor = async (name, args, abortSignal) => {
|
|
1767
|
-
if (!skillResolution.tools.some(tool => tool.name === name)) {
|
|
1768
|
-
return JSON.stringify({
|
|
1769
|
-
success: false,
|
|
1770
|
-
error: skillResolution.toolScopeActive
|
|
1771
|
-
? `Tool ${name} is not available for the active skill scope. Available tools: ${skillResolution.tools.map(tool => tool.name).join(', ') || 'none'}`
|
|
1772
|
-
: `Tool ${name} is not available.`,
|
|
1773
|
-
});
|
|
1774
|
-
}
|
|
1775
|
-
const result = await (0, tools_1.executeTool)(name, args, abortSignal, {
|
|
1776
|
-
cwd: ctx.cwd,
|
|
1777
|
-
config: {
|
|
1778
|
-
name: ctx.config.name,
|
|
1779
|
-
mode: ctx.config.mode,
|
|
1780
|
-
},
|
|
1781
|
-
sessionId,
|
|
1782
|
-
turnId: ctx.turnId,
|
|
1783
|
-
});
|
|
1784
|
-
// 不在这里打印,让 tool_result 事件处理
|
|
1785
|
-
return result;
|
|
1786
|
-
};
|
|
1787
|
-
const streamCallbacks = {
|
|
1788
|
-
onChunk: (chunk) => {
|
|
1789
|
-
if (ctx.abortSignal?.aborted) {
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
if (!responseStarted) {
|
|
1793
|
-
responseStarted = true;
|
|
1794
|
-
spinner.stop();
|
|
1795
|
-
// 打印换行,让流式输出在新行开始
|
|
1796
|
-
writeLine();
|
|
1797
|
-
// 初始化流式渲染器
|
|
1798
|
-
streamRenderer = (0, stream_markdown_1.createStreamRenderer)();
|
|
1799
|
-
}
|
|
1800
|
-
// 使用流式渲染器处理 chunk
|
|
1801
|
-
if (streamRenderer) {
|
|
1802
|
-
const rendered = streamRenderer.feed(chunk);
|
|
1803
|
-
if (rendered) {
|
|
1804
|
-
writeOutput(rendered);
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
else {
|
|
1808
|
-
writeOutput(chunk);
|
|
1809
|
-
}
|
|
1810
|
-
},
|
|
1811
|
-
};
|
|
1812
|
-
try {
|
|
1813
|
-
const messages = [
|
|
1814
|
-
{ role: 'system', content: systemPrompt },
|
|
1815
|
-
...snapshot.conversationHistory,
|
|
1816
|
-
];
|
|
1817
|
-
for await (const event of (0, framework_1.query)({
|
|
1818
|
-
messages,
|
|
1819
|
-
tools: skillResolution.tools,
|
|
1820
|
-
toolExecutor,
|
|
1821
|
-
llm: ctx.llm,
|
|
1822
|
-
streamCallbacks,
|
|
1823
|
-
costTracker: snapshot.costTracker,
|
|
1824
|
-
permissionMode: snapshot.permissionMode,
|
|
1825
|
-
toolConfirmation: ctx.config.toolConfirmation,
|
|
1826
|
-
toolAllowlist: (0, tool_allowlist_1.resolveProjectToolAllowlist)(ctx.cwd).evaluator,
|
|
1827
|
-
toolContext: {
|
|
1828
|
-
cwd: ctx.cwd,
|
|
1829
|
-
config: {
|
|
1830
|
-
name: ctx.config.name,
|
|
1831
|
-
mode: ctx.config.mode,
|
|
1832
|
-
},
|
|
1833
|
-
sessionId,
|
|
1834
|
-
turnId: ctx.turnId,
|
|
1835
|
-
},
|
|
1836
|
-
abortSignal: ctx.abortSignal,
|
|
1837
|
-
harness,
|
|
1838
|
-
input,
|
|
1839
|
-
loopBudget: (0, loop_budget_1.resolveRuntimeLoopBudget)(input, ctx.config, harness.toJSON()),
|
|
1840
|
-
})) {
|
|
1841
|
-
switch (event.type) {
|
|
1842
|
-
case 'request_start':
|
|
1843
|
-
// 停止 spinner,等待 LLM 响应
|
|
1844
|
-
spinner.stop();
|
|
1845
|
-
writeLine();
|
|
1846
|
-
writeLine(DIM((0, agent_status_1.agentStepStatus)(event.turn)));
|
|
1847
|
-
// 重置流式渲染器
|
|
1848
|
-
streamRenderer = (0, stream_markdown_1.createStreamRenderer)();
|
|
1849
|
-
// Issue #22: 重置工具调用计数器
|
|
1850
|
-
toolCallCount = 0;
|
|
1851
|
-
lastProgressUpdate = 0;
|
|
1852
|
-
break;
|
|
1853
|
-
case 'assistant_tool_calls':
|
|
1854
|
-
if (event.toolCalls.length > 1) {
|
|
1855
|
-
writeLine(DIM((0, agent_status_1.runningToolsStatus)(event.toolCalls.length)));
|
|
1856
|
-
}
|
|
1857
|
-
sessionMessagesToRecord.push({
|
|
1858
|
-
role: 'assistant',
|
|
1859
|
-
content: event.content || '',
|
|
1860
|
-
timestamp: Date.now(),
|
|
1861
|
-
tool_calls: event.toolCalls,
|
|
1862
|
-
});
|
|
1863
|
-
break;
|
|
1864
|
-
case 'tool_call':
|
|
1865
|
-
// Issue #22: 批量工具调用进度显示
|
|
1866
|
-
toolCallCount++;
|
|
1867
|
-
if (toolCallCount >= 3 && Date.now() - lastProgressUpdate > 1000) {
|
|
1868
|
-
(0, progress_1.showToolProgress)(toolCallCount, event.name);
|
|
1869
|
-
lastProgressUpdate = Date.now();
|
|
1870
|
-
}
|
|
1871
|
-
break;
|
|
1872
|
-
case 'tool_result':
|
|
1873
|
-
// Issue #22: 隐藏进度指示
|
|
1874
|
-
(0, progress_1.hideProgress)();
|
|
1875
|
-
// 显示工具结果后,准备下一轮(不启动 spinner)
|
|
1876
|
-
writeLine(event.summary || (0, box_1.toolLine)(event.name, event.args, event.success, event.duration));
|
|
1877
|
-
// 显示错误详情
|
|
1878
|
-
if (!event.success && event.error) {
|
|
1879
|
-
writeLine(ERROR(` Error: ${event.error}`));
|
|
1880
|
-
}
|
|
1881
|
-
// Debug: 显示接收到的参数
|
|
1882
|
-
if (!event.success && Object.keys(event.args).length === 0) {
|
|
1883
|
-
writeLine(WARN(` ⚠ Tool received empty arguments - LLM may not be providing parameters correctly`));
|
|
1884
|
-
writeLine(DIM(` Try using /model qwen or /model gpt4o for better tool calling support`));
|
|
1885
|
-
}
|
|
1886
|
-
// Record tool result for session
|
|
1887
|
-
sessionMessagesToRecord.push({
|
|
1888
|
-
role: 'tool',
|
|
1889
|
-
content: event.result,
|
|
1890
|
-
modelVisibleContent: event.modelVisibleResult,
|
|
1891
|
-
timestamp: Date.now(),
|
|
1892
|
-
toolCallId: event.callId,
|
|
1893
|
-
});
|
|
1894
|
-
break;
|
|
1895
|
-
case 'message':
|
|
1896
|
-
if (event.content) {
|
|
1897
|
-
sessionMessagesToRecord.push({
|
|
1898
|
-
role: 'assistant',
|
|
1899
|
-
content: event.content,
|
|
1900
|
-
timestamp: Date.now(),
|
|
1901
|
-
});
|
|
1902
|
-
}
|
|
1903
|
-
break;
|
|
1904
|
-
case 'strategy_exhausted':
|
|
1905
|
-
writeLine(WARN(`⚠ ${event.suggestion}`));
|
|
1906
|
-
break;
|
|
1907
|
-
case 'complete':
|
|
1908
|
-
finalContent = event.content;
|
|
1909
|
-
finalModel = event.model;
|
|
1910
|
-
finalUsage = event.usage;
|
|
1911
|
-
if (event.stats) {
|
|
1912
|
-
ctx.store.setLastLoopStats(event.stats);
|
|
1913
|
-
}
|
|
1914
|
-
break;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
// 刷新流式渲染器,输出剩余内容
|
|
1918
|
-
if (streamRenderer) {
|
|
1919
|
-
const remaining = streamRenderer.flush();
|
|
1920
|
-
if (remaining) {
|
|
1921
|
-
writeOutput(remaining);
|
|
1922
|
-
}
|
|
1923
|
-
streamRenderer = null;
|
|
1924
|
-
}
|
|
1925
|
-
const wasAborted = ctx.abortSignal?.aborted === true;
|
|
1926
|
-
if (finalContent && !wasAborted) {
|
|
1927
|
-
ctx.store.addMessage({ role: 'assistant', content: finalContent });
|
|
1928
|
-
}
|
|
1929
|
-
if (sessionId && sessionMessagesToRecord.length > 0 && !wasAborted) {
|
|
1930
|
-
(0, session_storage_1.appendSessionMessages)(sessionId, sessionMessagesToRecord);
|
|
1931
|
-
}
|
|
1932
|
-
if (finalUsage && !wasAborted) {
|
|
1933
|
-
ctx.store.setTokenUsage(finalUsage);
|
|
1934
|
-
}
|
|
1935
|
-
if (!wasAborted) {
|
|
1936
|
-
harness.ingestTurn({
|
|
1937
|
-
userInput: input,
|
|
1938
|
-
assistantContent: finalContent,
|
|
1939
|
-
sessionMessages: sessionMessagesToRecord,
|
|
1940
|
-
intent,
|
|
1941
|
-
});
|
|
1942
|
-
const harnessState = harness.toJSON();
|
|
1943
|
-
ctx.store.setState({ harnessState });
|
|
1944
|
-
if (sessionId) {
|
|
1945
|
-
(0, session_storage_1.updateSessionSkills)(sessionId, appliedSkillNames);
|
|
1946
|
-
(0, session_storage_1.updateSessionHarnessState)(sessionId, harnessState);
|
|
1947
|
-
const recordedMessages = (0, session_storage_1.readSessionMessages)(sessionId);
|
|
1948
|
-
if (recordedMessages.length > 0) {
|
|
1949
|
-
(0, session_storage_1.updateSessionSummary)(sessionId, recordedMessages);
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
if (responseStarted) {
|
|
1954
|
-
writeLine();
|
|
1955
|
-
if (ui.extraAssistantSpacing) {
|
|
1956
|
-
writeLine();
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
if (!ui.suppressLegacyTokenMeta) {
|
|
1960
|
-
const stats = [
|
|
1961
|
-
finalUsage ? `tokens: ${finalUsage.promptTokens}+${finalUsage.completionTokens}` : '',
|
|
1962
|
-
finalModel ? finalModel : '',
|
|
1963
|
-
]
|
|
1964
|
-
.filter(Boolean)
|
|
1965
|
-
.join(' ');
|
|
1966
|
-
if (stats) {
|
|
1967
|
-
writeLine(DIM(stats));
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
catch (error) {
|
|
1972
|
-
spinner.stop();
|
|
1973
|
-
writeLine();
|
|
1974
|
-
if (isAbortError(error, ctx.abortSignal)) {
|
|
1975
|
-
(0, progress_1.hideProgress)();
|
|
1976
|
-
if (!ui.suppressAbortNotice) {
|
|
1977
|
-
writeLine(DIM('Interrupted.'));
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
else {
|
|
1981
|
-
writeLine(ERROR(`✗ ${error.message || String(error)}`));
|
|
1982
|
-
const hist = ctx.store.getSnapshot().conversationHistory;
|
|
1983
|
-
if (hist.length > 0) {
|
|
1984
|
-
ctx.store.setState({ conversationHistory: hist.slice(0, -1) });
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
}
|
|
1988
|
-
return { success: true };
|
|
1989
|
-
}
|
|
1990
|
-
async function handleExit(ctx) {
|
|
1991
|
-
console.log();
|
|
1992
|
-
console.log(DIM('Shutting down...'));
|
|
1993
|
-
// Update session summary before exit
|
|
1994
|
-
if (ctx.sessionId) {
|
|
1995
|
-
const messages = (0, session_storage_1.readSessionMessages)(ctx.sessionId);
|
|
1996
|
-
if (messages.length > 0) {
|
|
1997
|
-
(0, session_storage_1.updateSessionSummary)(ctx.sessionId, messages);
|
|
1998
|
-
}
|
|
1999
|
-
(0, session_storage_1.endSession)(ctx.sessionId);
|
|
2000
|
-
}
|
|
2001
|
-
ctx.requestShutdown?.('user request');
|
|
2002
|
-
await ctx.runtime.shutdown();
|
|
2003
|
-
console.log(SUCCESS('Goodbye.'));
|
|
2004
|
-
return { success: true };
|
|
2005
|
-
}
|
|
2006
|
-
function handleCost(ctx) {
|
|
2007
|
-
console.log();
|
|
2008
|
-
console.log(HEADER('Lifetime Cost'));
|
|
2009
|
-
console.log(DIM('─'.repeat(40)));
|
|
2010
|
-
const costTracker = ctx.store.getSnapshot().costTracker;
|
|
2011
|
-
const state = (0, usage_state_1.loadUsageState)();
|
|
2012
|
-
const ledger = (0, usage_state_1.summarizeUsageLedger)();
|
|
2013
|
-
if (state.totalTokens === 0 && state.totalCost === 0) {
|
|
2014
|
-
console.log(DIM(' No usage recorded yet.'));
|
|
2015
|
-
console.log(DIM(' Use /run or /chat to interact with LLM.'));
|
|
2016
|
-
console.log();
|
|
2017
|
-
return { success: true };
|
|
2018
|
-
}
|
|
2019
|
-
// Summary
|
|
2020
|
-
console.log();
|
|
2021
|
-
console.log(` ${ACCENT('Total Tokens')} ${state.totalTokens.toLocaleString()}`);
|
|
2022
|
-
console.log(` ${ACCENT('Tracked Cost')} ${costTracker.formatCost(state.totalCost)}`);
|
|
2023
|
-
console.log(` ${ACCENT('Provider Cost')} ${costTracker.formatCost(state.providerCost)}`);
|
|
2024
|
-
console.log(` ${ACCENT('Estimated Cost')} ${costTracker.formatCost(state.estimatedCost)}`);
|
|
2025
|
-
console.log(` ${ACCENT('Requests')} ${state.usageRecords.toLocaleString()}`);
|
|
2026
|
-
console.log(` ${ACCENT('Sessions')} ${state.totalSessions.toLocaleString()}`);
|
|
2027
|
-
// By Model
|
|
2028
|
-
if (Object.keys(ledger.byModel).length > 0) {
|
|
2029
|
-
console.log();
|
|
2030
|
-
console.log(HEADER(' By Model:'));
|
|
2031
|
-
for (const [model, data] of Object.entries(ledger.byModel)) {
|
|
2032
|
-
console.log(` ${BRAND(model.padEnd(20))} ${data.tokens} tokens, ${costTracker.formatCost(data.cost)}`);
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
console.log();
|
|
2036
|
-
console.log(HEADER(' Cost Sources:'));
|
|
2037
|
-
for (const source of ['provider', 'configured', 'builtin', 'fallback']) {
|
|
2038
|
-
const data = ledger.bySource[source];
|
|
2039
|
-
if (data.count === 0)
|
|
2040
|
-
continue;
|
|
2041
|
-
console.log(` ${source.padEnd(12)} ${data.count} requests, ${costTracker.formatCost(data.cost)}`);
|
|
2042
|
-
}
|
|
2043
|
-
if (state.baselineCost > 0 || state.baselineTokens > 0) {
|
|
2044
|
-
console.log(DIM(` legacy ${state.baselineTokens.toLocaleString()} tokens, ${costTracker.formatCost(state.baselineCost)}`));
|
|
2045
|
-
}
|
|
2046
|
-
if (ledger.bySource.fallback.count > 0) {
|
|
2047
|
-
console.log();
|
|
2048
|
-
console.log(WARN(' Unknown-model fallback pricing is an estimate.'));
|
|
2049
|
-
console.log(DIM(' Configure cost.modelPricing in ~/.orion-code/orion.json for accuracy.'));
|
|
2050
|
-
}
|
|
2051
|
-
// Budget
|
|
2052
|
-
const budget = costTracker.getBudget();
|
|
2053
|
-
if (budget !== null) {
|
|
2054
|
-
const check = costTracker.checkBudget();
|
|
2055
|
-
console.log();
|
|
2056
|
-
console.log(HEADER(' Budget:'));
|
|
2057
|
-
console.log(` ${ACCENT('Limit')} ${costTracker.formatCost(budget)}`);
|
|
2058
|
-
console.log(` ${ACCENT('Used this run')} ${costTracker.formatCost(check.used)}`);
|
|
2059
|
-
console.log(` ${check.ok ? SUCCESS('✓ Within budget') : WARN('⚠ Budget exceeded')}`);
|
|
2060
|
-
}
|
|
2061
|
-
console.log();
|
|
2062
|
-
return { success: true };
|
|
2063
|
-
}
|
|
2064
|
-
function handleSkills(_ctx) {
|
|
2065
|
-
console.log();
|
|
2066
|
-
console.log(HEADER('Loaded Skills'));
|
|
2067
|
-
console.log(DIM('─'.repeat(40)));
|
|
2068
|
-
try {
|
|
2069
|
-
const registry = (0, skills_1.getSkillsRegistry)();
|
|
2070
|
-
const summary = registry.getSummary();
|
|
2071
|
-
if (summary.count === 0) {
|
|
2072
|
-
console.log();
|
|
2073
|
-
console.log(DIM(' No skills loaded.'));
|
|
2074
|
-
console.log(DIM(' Place SKILL.md files in ~/.orion-code/skills/<name>/ or .orion-code/skills/<name>/'));
|
|
2075
|
-
console.log();
|
|
2076
|
-
return { success: true };
|
|
2077
|
-
}
|
|
2078
|
-
console.log();
|
|
2079
|
-
console.log(` Total ${SUCCESS(summary.count)} skills (${WARN(summary.autoCount)} auto-trigger)`);
|
|
2080
|
-
console.log();
|
|
2081
|
-
for (const skill of registry.getAllSkills()) {
|
|
2082
|
-
const source = registry.getSource(skill.name);
|
|
2083
|
-
const sourceType = source?.type || 'unknown';
|
|
2084
|
-
const resourceRoot = skill.resourceRoot || skill.source || source?.path;
|
|
2085
|
-
const skillFile = resourceRoot
|
|
2086
|
-
? `${resourceRoot.replace(/\/SKILL\.md$/i, '')}/SKILL.md`
|
|
2087
|
-
: source?.skillFile;
|
|
2088
|
-
console.log(` ${ACCENT(skill.name)} ${DIM(`(${sourceType})`)}`);
|
|
2089
|
-
console.log(` ${DIM(skill.description || '(no description)')}`);
|
|
2090
|
-
if (skillFile)
|
|
2091
|
-
console.log(` ${DIM(`SKILL.md ${skillFile}`)}`);
|
|
2092
|
-
if (resourceRoot)
|
|
2093
|
-
console.log(` ${DIM(`Root ${resourceRoot}`)}`);
|
|
2094
|
-
}
|
|
2095
|
-
console.log();
|
|
2096
|
-
}
|
|
2097
|
-
catch (err) {
|
|
2098
|
-
console.log(ERROR(`✗ ${err.message}`));
|
|
2099
|
-
return { success: false };
|
|
2100
|
-
}
|
|
2101
|
-
return { success: true };
|
|
2102
|
-
}
|
|
2103
|
-
function handleSkill(ctx, args) {
|
|
2104
|
-
const trimmed = args.trim();
|
|
2105
|
-
const registry = (0, skills_1.getSkillsRegistry)();
|
|
2106
|
-
registry.initialize();
|
|
2107
|
-
if (!trimmed) {
|
|
2108
|
-
const names = registry
|
|
2109
|
-
.getAllSkills()
|
|
2110
|
-
.map(skill => skill.name)
|
|
2111
|
-
.sort();
|
|
2112
|
-
return {
|
|
2113
|
-
success: false,
|
|
2114
|
-
error: ['Usage: /skill <name> <task>', `Loaded skills: ${names.join(', ') || 'none'}`].join('\n'),
|
|
2115
|
-
};
|
|
2116
|
-
}
|
|
2117
|
-
const parsed = (0, skills_1.parseSkillCommandInput)(`/skill ${trimmed}`);
|
|
2118
|
-
const rawName = trimmed.split(/\s+/, 1)[0] || '';
|
|
2119
|
-
const requestedName = parsed.skillName || (0, skills_1.normalizeRequestedSkillName)(rawName);
|
|
2120
|
-
const referencedSkill = (0, skills_1.loadExplicitSkillReference)(`/skill ${trimmed}`, ctx.cwd);
|
|
2121
|
-
if (parsed.skillPath && !referencedSkill) {
|
|
2122
|
-
return {
|
|
2123
|
-
success: false,
|
|
2124
|
-
error: `Invalid skill reference: ${parsed.skillPath}`,
|
|
2125
|
-
};
|
|
2126
|
-
}
|
|
2127
|
-
const skill = referencedSkill ||
|
|
2128
|
-
registry
|
|
2129
|
-
.getAllSkills()
|
|
2130
|
-
.find(candidate => (0, skills_1.skillActivationNames)(candidate).some(name => (0, skills_1.normalizeRequestedSkillName)(name) === requestedName));
|
|
2131
|
-
if (!skill) {
|
|
2132
|
-
const suggestions = registry
|
|
2133
|
-
.getAllSkills()
|
|
2134
|
-
.map(candidate => candidate.name)
|
|
2135
|
-
.filter(name => name.includes(requestedName) || requestedName.includes(name))
|
|
2136
|
-
.slice(0, 5);
|
|
2137
|
-
return {
|
|
2138
|
-
success: false,
|
|
2139
|
-
error: suggestions.length > 0
|
|
2140
|
-
? `Unknown skill: ${rawName}\nDid you mean: ${suggestions.join(', ')}?`
|
|
2141
|
-
: `Unknown skill: ${rawName}`,
|
|
2142
|
-
};
|
|
2143
|
-
}
|
|
2144
|
-
const task = parsed.task;
|
|
2145
|
-
const source = registry.getSource(skill.name);
|
|
2146
|
-
const resourceRoot = skill.resourceRoot || skill.source || source?.path;
|
|
2147
|
-
const skillFile = resourceRoot
|
|
2148
|
-
? `${resourceRoot.replace(/\/SKILL\.md$/i, '')}/SKILL.md`
|
|
2149
|
-
: source?.skillFile;
|
|
2150
|
-
if (!task) {
|
|
2151
|
-
const usageSelector = parsed.skillPath
|
|
2152
|
-
? `[$${skill.name}](${formatSkillReferencePath(parsed.skillPath)})`
|
|
2153
|
-
: skill.name;
|
|
2154
|
-
return {
|
|
2155
|
-
success: true,
|
|
2156
|
-
output: [
|
|
2157
|
-
parsed.skillPath
|
|
2158
|
-
? `Skill reference ${skill.name} is valid for one turn.`
|
|
2159
|
-
: `Skill ${skill.name} is loaded.`,
|
|
2160
|
-
skillFile ? `SKILL.md ${skillFile}` : '',
|
|
2161
|
-
resourceRoot ? `Root ${resourceRoot}` : '',
|
|
2162
|
-
`Use: /skill ${usageSelector} <task>`,
|
|
2163
|
-
]
|
|
2164
|
-
.filter(Boolean)
|
|
2165
|
-
.join('\n'),
|
|
2166
|
-
};
|
|
2167
|
-
}
|
|
2168
|
-
return {
|
|
2169
|
-
success: true,
|
|
2170
|
-
continueAsChat: true,
|
|
2171
|
-
chatInput: parsed.skillPath
|
|
2172
|
-
? `/skill [$${skill.name}](${formatSkillReferencePath(parsed.skillPath)}) ${task}`
|
|
2173
|
-
: `/skill ${skill.name} ${task}`,
|
|
2174
|
-
};
|
|
2175
|
-
}
|
|
2176
|
-
function formatSkillReferencePath(path) {
|
|
2177
|
-
return /[\s()]/u.test(path) ? `<${path}>` : path;
|
|
2178
|
-
}
|
|
2179
|
-
function handleMcp(_ctx) {
|
|
2180
|
-
console.log();
|
|
2181
|
-
console.log(HEADER('MCP Servers'));
|
|
2182
|
-
console.log(DIM('─'.repeat(40)));
|
|
2183
|
-
const status = mcp_1.mcpManager.getStatus();
|
|
2184
|
-
if (status.length === 0) {
|
|
2185
|
-
console.log();
|
|
2186
|
-
console.log(DIM(' No servers configured. Add to ~/.orion-code/mcp.json'));
|
|
2187
|
-
console.log();
|
|
2188
|
-
return { success: true };
|
|
2189
|
-
}
|
|
2190
|
-
console.log();
|
|
2191
|
-
for (const s of status) {
|
|
2192
|
-
const stateLabel = s.dead
|
|
2193
|
-
? ERROR('dead')
|
|
2194
|
-
: s.connected
|
|
2195
|
-
? SUCCESS('connected')
|
|
2196
|
-
: WARN('disconnected');
|
|
2197
|
-
console.log(` ${ACCENT(s.name.padEnd(20))} ${stateLabel} ${DIM(`${s.toolCount} tools`)}`);
|
|
2198
|
-
}
|
|
2199
|
-
console.log();
|
|
2200
|
-
return { success: true };
|
|
2201
|
-
}
|
|
2202
|
-
function handleDoctor(ctx) {
|
|
2203
|
-
const report = (0, doctor_1.collectDoctorReport)(ctx);
|
|
2204
|
-
console.log();
|
|
2205
|
-
console.log((0, doctor_1.formatDoctorReport)(report));
|
|
2206
|
-
console.log();
|
|
2207
|
-
return { success: !(0, doctor_1.hasDoctorFailures)(report) };
|
|
2208
|
-
}
|
|
2209
|
-
function handleStorage(_ctx, args) {
|
|
2210
|
-
const usage = '/storage [doctor|status|repair [--dry-run|--yes] [--plan=<token>]|cleanup [--dry-run|--yes] [--plan=<token>]]';
|
|
2211
|
-
const trimmed = args.trim();
|
|
2212
|
-
const tokens = trimmed ? trimmed.split(/\s+/u) : [];
|
|
2213
|
-
const action = tokens[0] ?? 'doctor';
|
|
2214
|
-
const flags = tokens.slice(1);
|
|
2215
|
-
const acceptsMutationFlags = action === 'cleanup' || action === 'repair';
|
|
2216
|
-
const planFlags = flags.filter(flag => flag.startsWith('--plan='));
|
|
2217
|
-
const invalidTokens = flags.filter(flag => !acceptsMutationFlags ||
|
|
2218
|
-
(flag !== '--dry-run' && flag !== '--yes' && !flag.startsWith('--plan=')) ||
|
|
2219
|
-
(flag.startsWith('--plan=') && flag.length === '--plan='.length));
|
|
2220
|
-
if (planFlags.length > 1)
|
|
2221
|
-
invalidTokens.push(...planFlags.slice(1));
|
|
2222
|
-
if (invalidTokens.length > 0) {
|
|
2223
|
-
return {
|
|
2224
|
-
success: false,
|
|
2225
|
-
error: `Unknown /storage option: ${invalidTokens.join(', ')}. Usage: ${usage}`,
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
const confirmed = flags.includes('--yes');
|
|
2229
|
-
const explicitDryRun = flags.includes('--dry-run');
|
|
2230
|
-
const planToken = planFlags[0]?.slice('--plan='.length);
|
|
2231
|
-
const decodedPlan = planToken ? (0, storage_maintenance_1.deserializeStorageMaintenancePlan)(planToken) : undefined;
|
|
2232
|
-
if (planToken && !decodedPlan) {
|
|
2233
|
-
return { success: false, error: `Invalid or corrupted storage plan token. Usage: ${usage}` };
|
|
2234
|
-
}
|
|
2235
|
-
if (action === 'cleanup') {
|
|
2236
|
-
if (decodedPlan && decodedPlan.kind !== 'cleanup') {
|
|
2237
|
-
return { success: false, error: 'The supplied storage plan is not a cleanup plan.' };
|
|
2238
|
-
}
|
|
2239
|
-
const dryRun = explicitDryRun || !confirmed;
|
|
2240
|
-
if (!dryRun && !decodedPlan) {
|
|
2241
|
-
return {
|
|
2242
|
-
success: false,
|
|
2243
|
-
error: 'Cleanup requires the exact preview plan. Run /storage cleanup first.',
|
|
2244
|
-
};
|
|
2245
|
-
}
|
|
2246
|
-
const consumedPlan = !dryRun && planToken ? (0, storage_maintenance_1.consumeStorageMaintenancePlan)(planToken) : undefined;
|
|
2247
|
-
if (!dryRun && (!consumedPlan || consumedPlan.kind !== 'cleanup')) {
|
|
2248
|
-
return {
|
|
2249
|
-
success: false,
|
|
2250
|
-
error: 'The storage cleanup plan expired, was already used, or is not valid in this process.',
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
const plan = dryRun
|
|
2254
|
-
? decodedPlan?.kind === 'cleanup'
|
|
2255
|
-
? decodedPlan.plan
|
|
2256
|
-
: (0, storage_maintenance_1.collectStorageCleanupPlan)()
|
|
2257
|
-
: consumedPlan
|
|
2258
|
-
.plan;
|
|
2259
|
-
const result = (0, storage_maintenance_1.cleanupStorage)({ dryRun }, plan);
|
|
2260
|
-
console.log();
|
|
2261
|
-
console.log((0, storage_maintenance_1.formatStorageCleanupResult)(result));
|
|
2262
|
-
if (dryRun) {
|
|
2263
|
-
const portablePlan = planToken ?? (0, storage_maintenance_1.serializeStorageMaintenancePlan)({ kind: 'cleanup', plan });
|
|
2264
|
-
console.log(DIM(`Preview only. Run /storage cleanup --plan=${portablePlan} --yes to apply this plan.`));
|
|
2265
|
-
}
|
|
2266
|
-
console.log();
|
|
2267
|
-
return { success: true };
|
|
2268
|
-
}
|
|
2269
|
-
if (action === 'repair') {
|
|
2270
|
-
if (decodedPlan && decodedPlan.kind !== 'repair') {
|
|
2271
|
-
return { success: false, error: 'The supplied storage plan is not a repair plan.' };
|
|
2272
|
-
}
|
|
2273
|
-
const plan = decodedPlan?.kind === 'repair' ? decodedPlan.plan : (0, storage_maintenance_1.collectProjectMetadataRepairPlan)();
|
|
2274
|
-
if (explicitDryRun || !confirmed) {
|
|
2275
|
-
console.log();
|
|
2276
|
-
console.log(HEADER('Orion Code Storage Repair Preview'));
|
|
2277
|
-
console.log(DIM('─'.repeat(40)));
|
|
2278
|
-
console.log(` Repairable metadata entries ${ACCENT(String(plan.actions.length))}`);
|
|
2279
|
-
for (const action of plan.actions.slice(0, 12)) {
|
|
2280
|
-
console.log(` ${DIM('•')} ${DIM(action.metadataPath)}`);
|
|
2281
|
-
}
|
|
2282
|
-
const portablePlan = planToken ?? (0, storage_maintenance_1.serializeStorageMaintenancePlan)({ kind: 'repair', plan });
|
|
2283
|
-
console.log(DIM(` Preview only. Writable repair is disabled; /storage repair --plan=${portablePlan} --yes will fail closed.`));
|
|
2284
|
-
console.log();
|
|
2285
|
-
return { success: true };
|
|
2286
|
-
}
|
|
2287
|
-
if (!decodedPlan) {
|
|
2288
|
-
return {
|
|
2289
|
-
success: false,
|
|
2290
|
-
error: 'Repair requires the exact preview plan. Run /storage repair first.',
|
|
2291
|
-
};
|
|
2292
|
-
}
|
|
2293
|
-
const consumedPlan = planToken ? (0, storage_maintenance_1.consumeStorageMaintenancePlan)(planToken) : undefined;
|
|
2294
|
-
if (!consumedPlan || consumedPlan.kind !== 'repair') {
|
|
2295
|
-
return {
|
|
2296
|
-
success: false,
|
|
2297
|
-
error: 'The storage repair plan expired, was already used, or is not valid in this process.',
|
|
2298
|
-
};
|
|
2299
|
-
}
|
|
2300
|
-
const result = (0, storage_maintenance_1.repairProjectMetadata)(consumedPlan.plan);
|
|
2301
|
-
return { success: false, error: result.blockedReason };
|
|
2302
|
-
}
|
|
2303
|
-
if (action !== 'doctor' && action !== 'status') {
|
|
2304
|
-
return {
|
|
2305
|
-
success: false,
|
|
2306
|
-
error: `Usage: ${usage}`,
|
|
2307
|
-
};
|
|
2308
|
-
}
|
|
2309
|
-
const report = (0, storage_maintenance_1.collectStorageReport)();
|
|
2310
|
-
console.log();
|
|
2311
|
-
console.log((0, storage_maintenance_1.formatStorageReport)(report));
|
|
2312
|
-
console.log();
|
|
2313
|
-
return { success: true };
|
|
2314
|
-
}
|
|
2315
|
-
function handleDiff(ctx, args) {
|
|
2316
|
-
const maxFilesMatch = args.match(/--max-files(?:=|\s+)(\d+)/);
|
|
2317
|
-
const maxFiles = maxFilesMatch ? Number(maxFilesMatch[1]) : 40;
|
|
2318
|
-
const report = (0, workspace_diff_1.collectWorkspaceDiff)({ cwd: ctx.cwd, maxFiles });
|
|
2319
|
-
console.log();
|
|
2320
|
-
console.log((0, workspace_diff_1.formatWorkspaceDiff)(report, { maxFiles }));
|
|
2321
|
-
console.log();
|
|
2322
|
-
return { success: report.isGitRepo };
|
|
2323
|
-
}
|
|
2324
|
-
function handleCommitPlan(ctx, args) {
|
|
2325
|
-
const maxFilesMatch = args.match(/--max-files(?:=|\s+)(\d+)/);
|
|
2326
|
-
const maxFiles = maxFilesMatch ? Number(maxFilesMatch[1]) : 20;
|
|
2327
|
-
const plan = (0, commit_plan_1.createCommitPlan)({ cwd: ctx.cwd, maxFiles });
|
|
2328
|
-
console.log();
|
|
2329
|
-
console.log((0, commit_plan_1.formatCommitPlan)(plan));
|
|
2330
|
-
console.log();
|
|
2331
|
-
return { success: plan.diff.isGitRepo };
|
|
2332
|
-
}
|
|
2333
|
-
function handleTools(ctx) {
|
|
2334
|
-
const tools = ctx.store.getSnapshot().tools.length > 0 ? ctx.store.getSnapshot().tools : (0, tools_1.getRuntimeTools)();
|
|
2335
|
-
const staticTools = tools.filter(tool => !tool.name.startsWith('mcp__'));
|
|
2336
|
-
const mcpTools = tools.filter(tool => tool.name.startsWith('mcp__'));
|
|
2337
|
-
console.log();
|
|
2338
|
-
console.log(HEADER('Available Tools'));
|
|
2339
|
-
console.log(DIM('─'.repeat(40)));
|
|
2340
|
-
console.log(` Static tools ${ACCENT(String(staticTools.length))}`);
|
|
2341
|
-
console.log(` MCP tools ${ACCENT(String(mcpTools.length))}`);
|
|
2342
|
-
console.log();
|
|
2343
|
-
const visible = [...staticTools, ...mcpTools].slice(0, 28);
|
|
2344
|
-
for (const tool of visible) {
|
|
2345
|
-
const label = tool.name.startsWith('mcp__') ? 'mcp' : 'tool';
|
|
2346
|
-
console.log(` ${ACCENT(tool.name)} ${DIM(`[${label}]`)}`);
|
|
2347
|
-
console.log(` ${DIM(tool.description.slice(0, 96))}`);
|
|
2348
|
-
}
|
|
2349
|
-
if (tools.length > visible.length) {
|
|
2350
|
-
console.log();
|
|
2351
|
-
console.log(DIM(` ... ${tools.length - visible.length} more tools hidden`));
|
|
2352
|
-
}
|
|
2353
|
-
console.log();
|
|
2354
|
-
return { success: true };
|
|
2355
|
-
}
|
|
2356
|
-
function handleTodos(ctx) {
|
|
2357
|
-
const todos = ctx.store.getSnapshot().todos;
|
|
2358
|
-
console.log();
|
|
2359
|
-
console.log(HEADER('Todos'));
|
|
2360
|
-
console.log(DIM('─'.repeat(40)));
|
|
2361
|
-
if (todos.length === 0) {
|
|
2362
|
-
console.log(DIM(' No active todos yet.'));
|
|
2363
|
-
console.log();
|
|
2364
|
-
return { success: true };
|
|
2365
|
-
}
|
|
2366
|
-
for (const todo of todos) {
|
|
2367
|
-
const marker = todo.status === 'completed'
|
|
2368
|
-
? SUCCESS('✓')
|
|
2369
|
-
: todo.status === 'in_progress'
|
|
2370
|
-
? WARN('›')
|
|
2371
|
-
: DIM('○');
|
|
2372
|
-
console.log(` ${marker} ${todo.content}`);
|
|
2373
|
-
if (todo.activeForm && todo.activeForm !== todo.content) {
|
|
2374
|
-
console.log(` ${DIM(todo.activeForm)}`);
|
|
2375
|
-
}
|
|
2376
|
-
}
|
|
2377
|
-
console.log();
|
|
2378
|
-
return { success: true };
|
|
2379
|
-
}
|
|
2380
|
-
function handleContextClear(ctx, args) {
|
|
2381
|
-
const history = ctx.store.getSnapshot().conversationHistory;
|
|
2382
|
-
if (history.length === 0) {
|
|
2383
|
-
console.log(DIM('Current in-memory model context is already empty.'));
|
|
2384
|
-
console.log();
|
|
2385
|
-
return { success: true };
|
|
2386
|
-
}
|
|
2387
|
-
if (!hasCommandFlag(args, '--yes')) {
|
|
2388
|
-
return {
|
|
2389
|
-
success: false,
|
|
2390
|
-
error: [
|
|
2391
|
-
`This will clear ${history.length} message(s) from the current in-memory model context.`,
|
|
2392
|
-
'Saved session history will not be deleted and can still be restored with /resume.',
|
|
2393
|
-
'Run /context-clear --yes to continue.',
|
|
2394
|
-
].join('\n'),
|
|
2395
|
-
};
|
|
2396
|
-
}
|
|
2397
|
-
ctx.store.resetConversation();
|
|
2398
|
-
(0, framework_1.resetToolState)();
|
|
2399
|
-
console.log(SUCCESS(`✔ Cleared ${history.length} messages from current model context`));
|
|
2400
|
-
console.log(DIM(' Saved session history, configuration, and system state were preserved.'));
|
|
2401
|
-
console.log();
|
|
2402
|
-
return { success: true };
|
|
2403
|
-
}
|
|
2404
|
-
async function handleCompact(ctx, args) {
|
|
2405
|
-
const history = ctx.store.getSnapshot().conversationHistory;
|
|
2406
|
-
if (history.length === 0) {
|
|
2407
|
-
console.log(DIM('Conversation history is empty, nothing to compact'));
|
|
2408
|
-
console.log();
|
|
2409
|
-
return { success: true };
|
|
2410
|
-
}
|
|
2411
|
-
// 解析参数
|
|
2412
|
-
const thresholdArg = parseInt(args.trim(), 10);
|
|
2413
|
-
const threshold = thresholdArg > 0 ? thresholdArg : 50;
|
|
2414
|
-
console.log();
|
|
2415
|
-
console.log(HEADER('Compacting Conversation'));
|
|
2416
|
-
console.log(DIM('─'.repeat(40)));
|
|
2417
|
-
console.log(` Current messages: ${history.length}`);
|
|
2418
|
-
console.log(` Threshold: ${threshold}`);
|
|
2419
|
-
console.log();
|
|
2420
|
-
if (history.length <= threshold) {
|
|
2421
|
-
console.log(DIM(`Conversation has ${history.length} messages, below compact threshold ${threshold}.`));
|
|
2422
|
-
console.log(DIM('Nothing compacted.'));
|
|
2423
|
-
console.log();
|
|
2424
|
-
return { success: true };
|
|
2425
|
-
}
|
|
2426
|
-
console.log(DIM((0, agent_status_1.compactStatus)()));
|
|
2427
|
-
try {
|
|
2428
|
-
const modelId = ctx.llm?.getModel() ?? ctx.store.getSnapshot().currentModel;
|
|
2429
|
-
const coordinator = ctx.compactCoordinator ??
|
|
2430
|
-
new coordinator_1.CompactCoordinator({
|
|
2431
|
-
modelId,
|
|
2432
|
-
llm: ctx.llm,
|
|
2433
|
-
outputReserveTokens: ctx.llm?.getMaxTokens?.(),
|
|
2434
|
-
getContextCapsule: () => ctx.store.getSnapshot().harnessState?.capsule,
|
|
2435
|
-
getHarnessState: () => ctx.store.getSnapshot().harnessState,
|
|
2436
|
-
});
|
|
2437
|
-
coordinator.configure({
|
|
2438
|
-
modelId,
|
|
2439
|
-
llm: ctx.llm,
|
|
2440
|
-
outputReserveTokens: ctx.llm?.getMaxTokens?.(),
|
|
2441
|
-
getContextCapsule: () => ctx.store.getSnapshot().harnessState?.capsule,
|
|
2442
|
-
getHarnessState: () => ctx.store.getSnapshot().harnessState,
|
|
2443
|
-
});
|
|
2444
|
-
const beforeTokens = (0, token_estimate_1.estimateMessagesTokens)(history);
|
|
2445
|
-
const automaticStats = coordinator.getAutomatic().getStats();
|
|
2446
|
-
const beforeUsage = (0, model_context_1.createContextUsageSnapshot)({
|
|
2447
|
-
modelId,
|
|
2448
|
-
usedTokens: beforeTokens,
|
|
2449
|
-
source: 'estimated',
|
|
2450
|
-
outputReserveTokens: ctx.llm?.getMaxTokens?.(),
|
|
2451
|
-
warningThreshold: automaticStats.preCompactThreshold,
|
|
2452
|
-
autoCompactThreshold: automaticStats.threshold,
|
|
2453
|
-
autoCompactEnabled: automaticStats.enabled,
|
|
2454
|
-
});
|
|
2455
|
-
const result = await coordinator.compactManual(history, threshold);
|
|
2456
|
-
const compacted = result.messages;
|
|
2457
|
-
const compactedTokens = (0, token_estimate_1.estimateMessagesTokens)(compacted);
|
|
2458
|
-
const afterUsage = (0, model_context_1.createContextUsageSnapshot)({
|
|
2459
|
-
modelId,
|
|
2460
|
-
usedTokens: compactedTokens,
|
|
2461
|
-
source: 'estimated',
|
|
2462
|
-
outputReserveTokens: ctx.llm?.getMaxTokens?.(),
|
|
2463
|
-
warningThreshold: automaticStats.preCompactThreshold,
|
|
2464
|
-
autoCompactThreshold: automaticStats.threshold,
|
|
2465
|
-
autoCompactEnabled: automaticStats.enabled,
|
|
2466
|
-
});
|
|
2467
|
-
const reduction = history.length - compacted.length;
|
|
2468
|
-
const percent = Math.round((reduction / history.length) * 100);
|
|
2469
|
-
const sessionId = ctx.getSession?.()?.id ?? ctx.sessionId;
|
|
2470
|
-
if (sessionId) {
|
|
2471
|
-
const sourceMessageCount = (0, session_storage_1.readSessionMessages)(sessionId).length;
|
|
2472
|
-
const checkpoint = (0, session_storage_1.commitSessionCompactCheckpoint)({
|
|
2473
|
-
sessionId,
|
|
2474
|
-
mode: 'manual',
|
|
2475
|
-
modelId,
|
|
2476
|
-
sourceMessageCount,
|
|
2477
|
-
transcriptStartMessageIndex: Math.max(0, sourceMessageCount - threshold),
|
|
2478
|
-
modelHistory: compacted,
|
|
2479
|
-
summary: {
|
|
2480
|
-
text: result.summary,
|
|
2481
|
-
generatedAt: result.summaryGeneratedAt,
|
|
2482
|
-
source: result.summarySource,
|
|
2483
|
-
},
|
|
2484
|
-
beforeUsage,
|
|
2485
|
-
afterUsage,
|
|
2486
|
-
});
|
|
2487
|
-
ctx.store.setState({ conversationHistory: checkpoint.modelHistory });
|
|
2488
|
-
}
|
|
2489
|
-
else {
|
|
2490
|
-
ctx.store.setState({ conversationHistory: compacted });
|
|
2491
|
-
}
|
|
2492
|
-
ctx.store.setContextUsage(afterUsage);
|
|
2493
|
-
console.log(SUCCESS(`✔ Compacted ${history.length} → ${compacted.length} messages`));
|
|
2494
|
-
console.log(DIM(` Reduced by ${reduction} messages (${percent}%)`));
|
|
2495
|
-
console.log();
|
|
2496
|
-
return { success: true };
|
|
2497
|
-
}
|
|
2498
|
-
catch (err) {
|
|
2499
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2500
|
-
console.log(ERROR(`✗ Compact failed: ${message}`));
|
|
2501
|
-
console.log();
|
|
2502
|
-
return { success: false };
|
|
2503
|
-
}
|
|
2504
|
-
}
|
|
2505
|
-
function handleUsage(ctx) {
|
|
2506
|
-
console.log();
|
|
2507
|
-
console.log(HEADER('Usage Statistics'));
|
|
2508
|
-
console.log(DIM('─'.repeat(40)));
|
|
2509
|
-
const snapshot = ctx.store.getSnapshot();
|
|
2510
|
-
const usage = snapshot.tokenUsage;
|
|
2511
|
-
const history = snapshot.conversationHistory;
|
|
2512
|
-
console.log();
|
|
2513
|
-
// Token usage
|
|
2514
|
-
console.log(HEADER(' Tokens:'));
|
|
2515
|
-
if (usage) {
|
|
2516
|
-
console.log(` Input ${ACCENT(usage.promptTokens.toLocaleString())}`);
|
|
2517
|
-
console.log(` Output ${ACCENT(usage.completionTokens.toLocaleString())}`);
|
|
2518
|
-
const total = usage.promptTokens + usage.completionTokens;
|
|
2519
|
-
console.log(` Total ${DIM(total.toLocaleString())}`);
|
|
2520
|
-
const ratio = usage.completionTokens / usage.promptTokens;
|
|
2521
|
-
console.log(` Ratio ${DIM(ratio.toFixed(2))} (output/input)`);
|
|
2522
|
-
}
|
|
2523
|
-
else {
|
|
2524
|
-
console.log(DIM(' No token usage recorded'));
|
|
2525
|
-
}
|
|
2526
|
-
console.log();
|
|
2527
|
-
// Conversation stats
|
|
2528
|
-
console.log(HEADER(' Conversation:'));
|
|
2529
|
-
console.log(` Messages ${DIM(history.length.toString())}`);
|
|
2530
|
-
console.log(` Turns ${DIM(Math.floor(history.length / 2).toString())}`);
|
|
2531
|
-
// Count by role
|
|
2532
|
-
const byRole = { user: 0, assistant: 0, system: 0, tool: 0 };
|
|
2533
|
-
for (const msg of history) {
|
|
2534
|
-
byRole[msg.role] = (byRole[msg.role] || 0) + 1;
|
|
2535
|
-
}
|
|
2536
|
-
console.log(` User msgs ${DIM(byRole.user.toString())}`);
|
|
2537
|
-
console.log(` Assistant ${DIM(byRole.assistant.toString())}`);
|
|
2538
|
-
console.log();
|
|
2539
|
-
// Model info
|
|
2540
|
-
console.log(HEADER(' Model:'));
|
|
2541
|
-
console.log(` Current ${BRAND(snapshot.currentModel)}`);
|
|
2542
|
-
if (ctx.llm) {
|
|
2543
|
-
console.log(` Active ${ACCENT(ctx.llm.getModel())}`);
|
|
2544
|
-
}
|
|
2545
|
-
console.log();
|
|
2546
|
-
return { success: true };
|
|
2547
|
-
}
|
|
2548
|
-
// ============================================================================
|
|
2549
|
-
// Session 命令
|
|
2550
|
-
// ============================================================================
|
|
2551
|
-
function parseSessionScopeArgs(args, cwd) {
|
|
2552
|
-
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
2553
|
-
let allProjects = false;
|
|
2554
|
-
let last = false;
|
|
2555
|
-
let projectPath = (0, session_storage_1.resolveProjectPath)(cwd);
|
|
2556
|
-
const queryParts = [];
|
|
2557
|
-
for (let i = 0; i < parts.length; i++) {
|
|
2558
|
-
const part = parts[i];
|
|
2559
|
-
if (part === '--all' || part === '-a') {
|
|
2560
|
-
allProjects = true;
|
|
2561
|
-
continue;
|
|
2562
|
-
}
|
|
2563
|
-
if (part === '--last' || part === '-l') {
|
|
2564
|
-
last = true;
|
|
2565
|
-
continue;
|
|
2566
|
-
}
|
|
2567
|
-
if ((part === '--project' || part === '-p') && parts[i + 1]) {
|
|
2568
|
-
projectPath = (0, session_storage_1.resolveProjectPath)(parts[i + 1]);
|
|
2569
|
-
i++;
|
|
2570
|
-
continue;
|
|
2571
|
-
}
|
|
2572
|
-
queryParts.push(part);
|
|
2573
|
-
}
|
|
2574
|
-
return {
|
|
2575
|
-
allProjects,
|
|
2576
|
-
projectPath,
|
|
2577
|
-
last,
|
|
2578
|
-
query: queryParts.join(' '),
|
|
2579
|
-
};
|
|
2580
|
-
}
|
|
2581
|
-
function sessionTitle(session) {
|
|
2582
|
-
return session.name || session.taskSummary || '(untitled)';
|
|
2583
|
-
}
|
|
2584
|
-
function truncateText(text, max) {
|
|
2585
|
-
return text.length > max ? text.slice(0, max - 3) + '...' : text;
|
|
2586
|
-
}
|
|
2587
|
-
function printSessionRows(sessions, options = {}) {
|
|
2588
|
-
for (let i = 0; i < sessions.length; i++) {
|
|
2589
|
-
const session = sessions[i];
|
|
2590
|
-
const startTime = new Date(session.startTime).toLocaleString();
|
|
2591
|
-
const updatedTime = new Date(session.updatedAt ?? session.startTime).toLocaleString();
|
|
2592
|
-
const duration = session.endTime
|
|
2593
|
-
? Math.round((session.endTime - session.startTime) / 1000) + 's'
|
|
2594
|
-
: 'active';
|
|
2595
|
-
const status = session.endTime ? DIM('completed') : ACCENT('active');
|
|
2596
|
-
const index = options.indexed ? `${String(i + 1).padStart(2, ' ')}. ` : ' ';
|
|
2597
|
-
const name = session.name ? ` ${ACCENT(`"${session.name}"`)}` : '';
|
|
2598
|
-
console.log(`${index}${status} ${BRAND(session.id.slice(0, 8))}${name} ${DIM(session.model)}`);
|
|
2599
|
-
console.log(` ${truncateText(sessionTitle(session), 96)}`);
|
|
2600
|
-
console.log(` ${DIM(`Started: ${startTime}`)} ${DIM(`Updated: ${updatedTime}`)} ${DIM(`Duration: ${duration}`)}`);
|
|
2601
|
-
console.log(` ${DIM(`Messages: ${session.messageCount ?? 0}`)} ${DIM(`Size: ${(0, format_1.formatBytes)(session.historySizeBytes ?? 0)}`)} ${DIM(`Tokens: ${session.tokenCount}`)} ${DIM(`Cost: $${session.cost.toFixed(4)}`)}`);
|
|
2602
|
-
if (options.showIndexSummary) {
|
|
2603
|
-
const indexSummary = (0, session_index_1.loadSessionIndex)(session.id, session.projectPath);
|
|
2604
|
-
if (indexSummary) {
|
|
2605
|
-
const toolCount = Object.values(indexSummary.tools).reduce((total, count) => total + count, 0);
|
|
2606
|
-
console.log(` ${DIM(`Index: ${indexSummary.files.length} files, ${toolCount} tool calls, ${indexSummary.topics.length} topics`)}`);
|
|
2607
|
-
}
|
|
2608
|
-
else {
|
|
2609
|
-
console.log(` ${DIM('Index: not built')}`);
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
if (options.showProject) {
|
|
2613
|
-
console.log(` ${DIM(`Project: ${session.projectPath}`)}`);
|
|
2614
|
-
}
|
|
2615
|
-
console.log();
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
function parsePickerIndex(ref, max) {
|
|
2619
|
-
const trimmed = ref.trim();
|
|
2620
|
-
const match = trimmed.match(/^#?(\d+)$/);
|
|
2621
|
-
if (!match)
|
|
2622
|
-
return null;
|
|
2623
|
-
const index = Number(match[1]);
|
|
2624
|
-
if (!Number.isInteger(index) || index < 1 || index > max)
|
|
2625
|
-
return null;
|
|
2626
|
-
return index - 1;
|
|
2627
|
-
}
|
|
2628
|
-
function printSessionConflict(ref, matches) {
|
|
2629
|
-
console.log(ERROR(`Session reference is ambiguous: ${ref}`));
|
|
2630
|
-
console.log(DIM('Use a longer id prefix, exact session name, or pick one of these:'));
|
|
2631
|
-
console.log();
|
|
2632
|
-
printSessionRows(matches.slice(0, 10), { indexed: true, showProject: true });
|
|
2633
|
-
console.log(DIM('Example: /resume <longer-session-id>'));
|
|
2634
|
-
console.log();
|
|
2635
|
-
}
|
|
2636
|
-
function printSessionPicker(sessions, options) {
|
|
2637
|
-
console.log(HEADER(options.title));
|
|
2638
|
-
console.log(DIM('─'.repeat(Math.min(process.stdout.columns || 80, 96))));
|
|
2639
|
-
printSessionRows(sessions, { indexed: true, showProject: options.showProject });
|
|
2640
|
-
if (options.moreCount && options.moreCount > 0) {
|
|
2641
|
-
console.log(DIM(`... ${options.moreCount} more sessions. Use /sessions to list them, or /resume <session-id>.`));
|
|
2642
|
-
}
|
|
2643
|
-
console.log(DIM('Use /resume <number|session-id|name> or /resume --last.'));
|
|
2644
|
-
}
|
|
2645
|
-
function handleSessions(ctx, args = '') {
|
|
2646
|
-
const scope = parseSessionScopeArgs(args, ctx.cwd);
|
|
2647
|
-
const query = scope.query?.trim();
|
|
2648
|
-
// If there's a search query, use the session index
|
|
2649
|
-
if (query && !query.startsWith('--')) {
|
|
2650
|
-
const allSessions = scope.allProjects ? (0, session_storage_1.listSessions)() : (0, session_storage_1.listProjectSessions)(scope.projectPath);
|
|
2651
|
-
const matchedIds = (0, session_index_1.searchSessions)(query, allSessions.map(session => ({
|
|
2652
|
-
id: session.id,
|
|
2653
|
-
projectPath: session.projectPath,
|
|
2654
|
-
})));
|
|
2655
|
-
if (matchedIds.length === 0) {
|
|
2656
|
-
console.log();
|
|
2657
|
-
console.log(HEADER(`Sessions (search: "${query}")`));
|
|
2658
|
-
console.log(DIM('─'.repeat(40)));
|
|
2659
|
-
console.log(DIM(' No matching sessions found'));
|
|
2660
|
-
console.log();
|
|
2661
|
-
console.log(DIM('Tip: search by file path, tool name, or topic keyword'));
|
|
2662
|
-
console.log();
|
|
2663
|
-
return { success: true };
|
|
2664
|
-
}
|
|
2665
|
-
// Rebuild session list in matched order
|
|
2666
|
-
const sessionMap = new Map(allSessions.map(s => [s.id, s]));
|
|
2667
|
-
const matchedSessions = matchedIds
|
|
2668
|
-
.map(id => sessionMap.get(id))
|
|
2669
|
-
.filter(Boolean);
|
|
2670
|
-
console.log();
|
|
2671
|
-
console.log(HEADER(`Sessions (search: "${query}") — ${matchedSessions.length} matches`));
|
|
2672
|
-
console.log(DIM('─'.repeat(40)));
|
|
2673
|
-
console.log();
|
|
2674
|
-
printSessionRows(matchedSessions, {
|
|
2675
|
-
indexed: true,
|
|
2676
|
-
showProject: scope.allProjects,
|
|
2677
|
-
showIndexSummary: true,
|
|
2678
|
-
});
|
|
2679
|
-
console.log();
|
|
2680
|
-
console.log(DIM(`Searched ${allSessions.length} sessions, found ${matchedSessions.length} matches`));
|
|
2681
|
-
console.log(DIM('Use /resume <number|session-id|name> to restore a session'));
|
|
2682
|
-
console.log();
|
|
2683
|
-
return { success: true };
|
|
2684
|
-
}
|
|
2685
|
-
console.log();
|
|
2686
|
-
console.log(HEADER(scope.allProjects ? 'Sessions (all projects)' : 'Sessions'));
|
|
2687
|
-
console.log(DIM('─'.repeat(40)));
|
|
2688
|
-
const sessions = scope.allProjects
|
|
2689
|
-
? (0, session_storage_1.listSessions)(10)
|
|
2690
|
-
: (0, session_storage_1.listProjectSessions)(scope.projectPath, 10);
|
|
2691
|
-
if (sessions.length === 0) {
|
|
2692
|
-
console.log(DIM(scope.allProjects ? ' No sessions found' : ' No sessions found for this project'));
|
|
2693
|
-
console.log();
|
|
2694
|
-
return { success: true };
|
|
2695
|
-
}
|
|
2696
|
-
console.log();
|
|
2697
|
-
printSessionRows(sessions, { indexed: true, showProject: scope.allProjects });
|
|
2698
|
-
console.log(DIM('Use /resume <number|session-id|name> to restore a session'));
|
|
2699
|
-
console.log(DIM('Use /session-rename <number|session-id|name> <new name> to rename'));
|
|
2700
|
-
console.log(DIM('Use /sessions --all to list sessions from every project'));
|
|
2701
|
-
console.log(DIM('Use /sessions <query> to search by file, tool, or keyword'));
|
|
2702
|
-
console.log();
|
|
2703
|
-
return { success: true };
|
|
2704
|
-
}
|
|
2705
|
-
function handleResume(ctx, args) {
|
|
2706
|
-
const ui = commandUICapabilities(ctx);
|
|
2707
|
-
const scope = parseSessionScopeArgs(args, ctx.cwd);
|
|
2708
|
-
const sessionRef = scope.query;
|
|
2709
|
-
const scopedSessions = (scope.allProjects ? (0, session_storage_1.listSessions)() : (0, session_storage_1.listProjectSessions)(scope.projectPath)).filter(session => (session.messageCount ?? 0) > 0);
|
|
2710
|
-
if (!sessionRef) {
|
|
2711
|
-
const lastSession = scopedSessions[0];
|
|
2712
|
-
if (!lastSession) {
|
|
2713
|
-
console.log(ERROR('No previous session found for this project'));
|
|
2714
|
-
console.log(DIM('Use /sessions --all to list all sessions'));
|
|
2715
|
-
console.log();
|
|
2716
|
-
return { success: false };
|
|
2717
|
-
}
|
|
2718
|
-
if (scope.last || scopedSessions.length === 1) {
|
|
2719
|
-
return restoreSession(ctx, lastSession, true);
|
|
2720
|
-
}
|
|
2721
|
-
const picker = {
|
|
2722
|
-
title: scope.allProjects ? 'Pick a Session (all projects)' : 'Pick a Session',
|
|
2723
|
-
showProject: scope.allProjects,
|
|
2724
|
-
moreCount: 0,
|
|
2725
|
-
sessions: scopedSessions,
|
|
2726
|
-
allProjects: scope.allProjects,
|
|
2727
|
-
maxVisibleItems: 10,
|
|
2728
|
-
};
|
|
2729
|
-
if (ui.structuredPickers) {
|
|
2730
|
-
return { success: true, sessionPicker: picker };
|
|
2731
|
-
}
|
|
2732
|
-
const visibleSessions = scopedSessions.slice(0, 10);
|
|
2733
|
-
console.log();
|
|
2734
|
-
printSessionPicker(visibleSessions, {
|
|
2735
|
-
title: picker.title,
|
|
2736
|
-
showProject: picker.showProject,
|
|
2737
|
-
moreCount: Math.max(0, scopedSessions.length - visibleSessions.length),
|
|
2738
|
-
});
|
|
2739
|
-
console.log();
|
|
2740
|
-
return { success: true };
|
|
2741
|
-
}
|
|
2742
|
-
const pickerIndex = parsePickerIndex(sessionRef, scopedSessions.length);
|
|
2743
|
-
if (pickerIndex !== null) {
|
|
2744
|
-
return restoreSession(ctx, scopedSessions[pickerIndex], false);
|
|
2745
|
-
}
|
|
2746
|
-
// Resume specific session
|
|
2747
|
-
const result = (0, session_storage_1.lookupSessionRef)(sessionRef, scope.projectPath, {
|
|
2748
|
-
allProjects: scope.allProjects,
|
|
2749
|
-
});
|
|
2750
|
-
if (result.status === 'ambiguous') {
|
|
2751
|
-
printSessionConflict(sessionRef, result.matches);
|
|
2752
|
-
return { success: false };
|
|
2753
|
-
}
|
|
2754
|
-
if (result.status === 'not_found') {
|
|
2755
|
-
console.log(ERROR(`Session not found: ${sessionRef}`));
|
|
2756
|
-
console.log(DIM(scope.allProjects
|
|
2757
|
-
? 'Use /sessions --all to list sessions'
|
|
2758
|
-
: 'Use /sessions to list project sessions, or /resume <id> --all'));
|
|
2759
|
-
console.log();
|
|
2760
|
-
return { success: false };
|
|
2761
|
-
}
|
|
2762
|
-
return restoreSession(ctx, result.session, false);
|
|
2763
|
-
}
|
|
2764
|
-
function restoreSession(ctx, session, isLast) {
|
|
2765
|
-
const resumed = (0, session_storage_1.resumeSession)(session.id) ?? session;
|
|
2766
|
-
// Swap in the resumed session's transcript BEFORE emitting any command output,
|
|
2767
|
-
// so the output is appended after the history rather than wiped by the
|
|
2768
|
-
// transcript replacement below.
|
|
2769
|
-
ctx.setSession?.(resumed);
|
|
2770
|
-
// Load history and notify runtime/TUI consumers.
|
|
2771
|
-
const history = (0, session_storage_1.loadSessionHistory)(resumed.id);
|
|
2772
|
-
const transcriptMessages = (0, session_storage_1.loadSessionTranscriptMessages)(resumed.id);
|
|
2773
|
-
const rawMessages = (0, session_storage_1.readSessionMessages)(resumed.id);
|
|
2774
|
-
const checkpoint = (0, session_storage_1.loadSessionCompactCheckpoint)(resumed.id);
|
|
2775
|
-
const resumeGeneratedAt = Date.now();
|
|
2776
|
-
const summary = checkpoint?.summary.text ?? (history.length > 0 ? generateHistorySummary(history) : '');
|
|
2777
|
-
const summaryGeneratedAt = checkpoint?.summary.generatedAt ?? resumeGeneratedAt;
|
|
2778
|
-
const summarySource = checkpoint?.summary.source ?? 'resume_heuristic';
|
|
2779
|
-
const summaryCoveredMessages = checkpoint?.summary.sourceMessageCount ?? rawMessages.length;
|
|
2780
|
-
if (history.length > 0) {
|
|
2781
|
-
const eventSummary = checkpoint?.summary.text ?? generateRestoredSessionEventSummary(history);
|
|
2782
|
-
ctx.store.setState({ conversationHistory: history });
|
|
2783
|
-
ctx.store.setState({
|
|
2784
|
-
harnessState: (0, session_storage_1.loadSessionHarnessState)(resumed.id) ?? resumed.harnessState,
|
|
2785
|
-
});
|
|
2786
|
-
(0, framework_1.resetToolState)();
|
|
2787
|
-
ctx.sessionRestored?.({
|
|
2788
|
-
sessionId: resumed.id,
|
|
2789
|
-
projectPath: resumed.projectPath,
|
|
2790
|
-
model: resumed.model,
|
|
2791
|
-
restoredMessages: history.length,
|
|
2792
|
-
messageCount: resumed.messageCount,
|
|
2793
|
-
summary: eventSummary,
|
|
2794
|
-
summaryGeneratedAt,
|
|
2795
|
-
summarySource,
|
|
2796
|
-
summaryCoveredMessages,
|
|
2797
|
-
checkpointId: checkpoint?.checkpointId,
|
|
2798
|
-
transcriptMessages: transcriptMessages.length,
|
|
2799
|
-
});
|
|
2800
|
-
}
|
|
2801
|
-
else {
|
|
2802
|
-
ctx.sessionRestored?.({
|
|
2803
|
-
sessionId: resumed.id,
|
|
2804
|
-
projectPath: resumed.projectPath,
|
|
2805
|
-
model: resumed.model,
|
|
2806
|
-
restoredMessages: 0,
|
|
2807
|
-
messageCount: resumed.messageCount,
|
|
2808
|
-
summaryGeneratedAt,
|
|
2809
|
-
summarySource,
|
|
2810
|
-
summaryCoveredMessages,
|
|
2811
|
-
checkpointId: checkpoint?.checkpointId,
|
|
2812
|
-
transcriptMessages: transcriptMessages.length,
|
|
2813
|
-
});
|
|
2814
|
-
}
|
|
2815
|
-
// Emit the resume summary. In TUI (inline-surface) mode, route through the
|
|
2816
|
-
// command-output sink instead of raw console.log: a bare console.log writes
|
|
2817
|
-
// directly to stdout and desyncs the surface's cursor tracking, leaving the
|
|
2818
|
-
// live region mis-positioned (blank lower screen, content stuck at top).
|
|
2819
|
-
// Plain text is used so no raw ANSI escapes leak into the TUI frame.
|
|
2820
|
-
const bannerLines = [
|
|
2821
|
-
isLast ? 'Resuming last session' : `Resuming session ${resumed.id.slice(0, 8)}`,
|
|
2822
|
-
` ID: ${resumed.id}`,
|
|
2823
|
-
` Model: ${resumed.model}`,
|
|
2824
|
-
` Project: ${resumed.projectPath}`,
|
|
2825
|
-
` Started: ${new Date(resumed.startTime).toLocaleString()}`,
|
|
2826
|
-
];
|
|
2827
|
-
if (history.length > 0) {
|
|
2828
|
-
bannerLines.push(` Summary: ${summary}`);
|
|
2829
|
-
bannerLines.push(` Generated: ${new Date(summaryGeneratedAt).toLocaleString()} (${checkpoint ? 'compact checkpoint' : 'generated on resume'})`);
|
|
2830
|
-
bannerLines.push(` Covers: ${summaryCoveredMessages} source messages`);
|
|
2831
|
-
bannerLines.push(`✔ Restored ${history.length} model-context messages / ${transcriptMessages.length} transcript messages`);
|
|
2832
|
-
}
|
|
2833
|
-
else {
|
|
2834
|
-
bannerLines.push(' No messages in session');
|
|
2835
|
-
}
|
|
2836
|
-
if (ctx.uiRenderer === 'tui' || ctx.uiRenderer === 'ink') {
|
|
2837
|
-
if (!ctx.sessionRestored) {
|
|
2838
|
-
for (const line of bannerLines)
|
|
2839
|
-
ctx.writeLine?.(line);
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
else {
|
|
2843
|
-
console.log();
|
|
2844
|
-
console.log(HEADER(bannerLines[0]));
|
|
2845
|
-
for (const line of bannerLines.slice(1)) {
|
|
2846
|
-
console.log(line.startsWith('✔') ? SUCCESS(line) : DIM(line));
|
|
2847
|
-
}
|
|
2848
|
-
console.log();
|
|
2849
|
-
}
|
|
2850
|
-
return { success: true };
|
|
2851
|
-
}
|
|
2852
|
-
function handleSessionRename(ctx, args) {
|
|
2853
|
-
const scope = parseSessionScopeArgs(args, ctx.cwd);
|
|
2854
|
-
const parts = scope.query.split(/\s+/).filter(Boolean);
|
|
2855
|
-
const ref = parts.shift();
|
|
2856
|
-
const newName = parts.join(' ').trim();
|
|
2857
|
-
if (!ref || !newName) {
|
|
2858
|
-
console.log(ERROR('Usage: /session-rename <number|session-id|name> <new name>'));
|
|
2859
|
-
console.log(DIM('Run /sessions first to see picker numbers for this project.'));
|
|
2860
|
-
console.log();
|
|
2861
|
-
return { success: false };
|
|
2862
|
-
}
|
|
2863
|
-
const scopedSessions = scope.allProjects
|
|
2864
|
-
? (0, session_storage_1.listSessions)()
|
|
2865
|
-
: (0, session_storage_1.listProjectSessions)(scope.projectPath);
|
|
2866
|
-
const pickerIndex = parsePickerIndex(ref, scopedSessions.length);
|
|
2867
|
-
let session = pickerIndex !== null ? scopedSessions[pickerIndex] : null;
|
|
2868
|
-
if (!session) {
|
|
2869
|
-
const result = (0, session_storage_1.lookupSessionRef)(ref, scope.projectPath, { allProjects: scope.allProjects });
|
|
2870
|
-
if (result.status === 'ambiguous') {
|
|
2871
|
-
printSessionConflict(ref, result.matches);
|
|
2872
|
-
return { success: false };
|
|
2873
|
-
}
|
|
2874
|
-
if (result.status === 'not_found') {
|
|
2875
|
-
console.log(ERROR(`Session not found: ${ref}`));
|
|
2876
|
-
console.log(DIM(scope.allProjects
|
|
2877
|
-
? 'Use /sessions --all to list sessions'
|
|
2878
|
-
: 'Use /sessions to list project sessions'));
|
|
2879
|
-
console.log();
|
|
2880
|
-
return { success: false };
|
|
2881
|
-
}
|
|
2882
|
-
session = result.session;
|
|
2883
|
-
}
|
|
2884
|
-
const duplicate = scopedSessions.find(s => s.id !== session.id && s.name === newName);
|
|
2885
|
-
const renamed = (0, session_storage_1.renameSession)(session.id, newName);
|
|
2886
|
-
if (!renamed) {
|
|
2887
|
-
console.log(ERROR(`Session not found: ${ref}`));
|
|
2888
|
-
console.log();
|
|
2889
|
-
return { success: false };
|
|
2890
|
-
}
|
|
2891
|
-
if (ctx.getSession?.()?.id === renamed.id) {
|
|
2892
|
-
ctx.setSession?.(renamed);
|
|
2893
|
-
}
|
|
2894
|
-
console.log();
|
|
2895
|
-
console.log(SUCCESS(`✔ Renamed session ${renamed.id.slice(0, 8)} to "${newName}"`));
|
|
2896
|
-
if (duplicate) {
|
|
2897
|
-
console.log(WARN(` Name already exists on ${duplicate.id.slice(0, 8)}; /resume "${newName}" will be ambiguous.`));
|
|
2898
|
-
}
|
|
2899
|
-
console.log();
|
|
2900
|
-
return { success: true };
|
|
2901
|
-
}
|
|
2902
|
-
async function handleEditPreview(ctx) {
|
|
2903
|
-
const lastEdit = (0, framework_1.getToolState)().lastEditFileArgs;
|
|
2904
|
-
if (!lastEdit) {
|
|
2905
|
-
console.log(ERROR('No previous edit_file call found for preview'));
|
|
2906
|
-
console.log(DIM('Run an edit_file tool call first, then use /edit-preview to inspect the match candidates.'));
|
|
2907
|
-
console.log();
|
|
2908
|
-
return { success: false };
|
|
2909
|
-
}
|
|
2910
|
-
const hasMetadata = Boolean(lastEdit.sessionId || lastEdit.turnId);
|
|
2911
|
-
if (!hasMetadata) {
|
|
2912
|
-
console.log(WARN('Using legacy edit-preview state without session/turn tags. Running preview as best-effort.'));
|
|
2913
|
-
}
|
|
2914
|
-
const staleBySession = Boolean(lastEdit.sessionId && ctx.sessionId && lastEdit.sessionId !== ctx.sessionId);
|
|
2915
|
-
const staleByTurn = Boolean(lastEdit.turnId != null && ctx.turnId != null && String(lastEdit.turnId) !== String(ctx.turnId));
|
|
2916
|
-
if (staleBySession || staleByTurn) {
|
|
2917
|
-
const mismatch = [];
|
|
2918
|
-
if (staleBySession)
|
|
2919
|
-
mismatch.push(`session ${lastEdit.sessionId} vs ${ctx.sessionId}`);
|
|
2920
|
-
if (staleByTurn)
|
|
2921
|
-
mismatch.push(`turn ${String(lastEdit.turnId)} vs ${String(ctx.turnId)}`);
|
|
2922
|
-
console.log(ERROR('Edit preview target does not match current context.'));
|
|
2923
|
-
console.log(DIM(`Stale edit target: ${mismatch.join(', ')}.`));
|
|
2924
|
-
console.log();
|
|
2925
|
-
return { success: false };
|
|
2926
|
-
}
|
|
2927
|
-
if (hasMetadata && !(ctx.sessionId || ctx.turnId)) {
|
|
2928
|
-
console.log(WARN('Edit preview context is available, but current command context is missing session/turn metadata.'));
|
|
2929
|
-
console.log(DIM('Preview is allowed, but stale checks cannot be fully validated.'));
|
|
2930
|
-
}
|
|
2931
|
-
const rawResult = await (0, tools_1.executeTool)('edit_file', {
|
|
2932
|
-
...lastEdit,
|
|
2933
|
-
preview: true,
|
|
2934
|
-
}, ctx.abortSignal, {
|
|
2935
|
-
cwd: ctx.cwd,
|
|
2936
|
-
config: {
|
|
2937
|
-
name: ctx.config.name,
|
|
2938
|
-
mode: ctx.config.mode,
|
|
2939
|
-
},
|
|
2940
|
-
sessionId: ctx.sessionId,
|
|
2941
|
-
turnId: ctx.turnId,
|
|
2942
|
-
});
|
|
2943
|
-
let parsed;
|
|
2944
|
-
try {
|
|
2945
|
-
parsed = JSON.parse(rawResult);
|
|
2946
|
-
}
|
|
2947
|
-
catch {
|
|
2948
|
-
parsed = { success: false, error: rawResult };
|
|
2949
|
-
}
|
|
2950
|
-
console.log();
|
|
2951
|
-
console.log(HEADER('Edit Preview'));
|
|
2952
|
-
console.log(DIM('─'.repeat(40)));
|
|
2953
|
-
if (parsed.success) {
|
|
2954
|
-
console.log(parsed.output || DIM('No preview output'));
|
|
2955
|
-
}
|
|
2956
|
-
else {
|
|
2957
|
-
console.log(ERROR(parsed.error || 'Preview failed'));
|
|
2958
|
-
}
|
|
2959
|
-
console.log();
|
|
2960
|
-
// Return structured data for terminal/TUI/Ink picker rendering.
|
|
2961
|
-
if (parsed.success && parsed.metadata?.candidates && Array.isArray(parsed.metadata.candidates)) {
|
|
2962
|
-
return {
|
|
2963
|
-
success: true,
|
|
2964
|
-
editPreview: {
|
|
2965
|
-
path: lastEdit.path,
|
|
2966
|
-
newString: lastEdit.new_string,
|
|
2967
|
-
kind: (lastEdit.fuzzy_match ? 'fuzzy' : 'exact'),
|
|
2968
|
-
candidates: parsed.metadata.candidates,
|
|
2969
|
-
},
|
|
2970
|
-
};
|
|
2971
|
-
}
|
|
2972
|
-
return { success: parsed.success === true };
|
|
2973
|
-
}
|
|
2974
|
-
/** Generate a brief summary of conversation history */
|
|
2975
|
-
function truncateRedactedSummary(text, maxLength) {
|
|
2976
|
-
const redacted = (0, session_storage_1.redactTraceText)(text);
|
|
2977
|
-
if (redacted.length <= maxLength)
|
|
2978
|
-
return redacted;
|
|
2979
|
-
let truncated = redacted.slice(0, maxLength);
|
|
2980
|
-
for (const marker of ['[REDACTED_SECRET]']) {
|
|
2981
|
-
const markerStart = truncated.indexOf(marker.slice(0, 6));
|
|
2982
|
-
if (markerStart >= 0 && !truncated.includes(marker)) {
|
|
2983
|
-
truncated = `${truncated.slice(0, markerStart)}${marker}`;
|
|
2984
|
-
break;
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
return `${truncated}...`;
|
|
2988
|
-
}
|
|
2989
|
-
function generateHistorySummary(messages) {
|
|
2990
|
-
const userMsgs = messages.filter(m => m.role === 'user' && m.content);
|
|
2991
|
-
const assistantMsgsWithTools = messages.filter(m => m.role === 'assistant' && m.tool_calls && m.tool_calls.length > 0);
|
|
2992
|
-
// Extract topics from first few user messages
|
|
2993
|
-
const topics = userMsgs.slice(0, 3).map(m => {
|
|
2994
|
-
return truncateRedactedSummary(m.content || '', 40);
|
|
2995
|
-
});
|
|
2996
|
-
// Extract tools used
|
|
2997
|
-
const toolsUsed = assistantMsgsWithTools.flatMap(m => m.tool_calls?.map(tc => tc.function.name) || []);
|
|
2998
|
-
const uniqueTools = [...new Set(toolsUsed)];
|
|
2999
|
-
// Build summary
|
|
3000
|
-
const parts = [];
|
|
3001
|
-
if (topics.length > 0) {
|
|
3002
|
-
parts.push(`Topics: ${topics.join('; ')}`);
|
|
3003
|
-
}
|
|
3004
|
-
if (uniqueTools.length > 0) {
|
|
3005
|
-
parts.push(`Tools: ${uniqueTools.join(', ')}`);
|
|
3006
|
-
}
|
|
3007
|
-
if (parts.length === 0) {
|
|
3008
|
-
return 'No significant activity';
|
|
3009
|
-
}
|
|
3010
|
-
return parts.join('. ');
|
|
3011
|
-
}
|
|
3012
|
-
function generateRestoredSessionEventSummary(messages) {
|
|
3013
|
-
const assistantMsgsWithTools = messages.filter(m => m.role === 'assistant' && m.tool_calls && m.tool_calls.length > 0);
|
|
3014
|
-
const toolsUsed = assistantMsgsWithTools.flatMap(m => m.tool_calls?.map(tc => tc.function.name) || []);
|
|
3015
|
-
const uniqueTools = [...new Set(toolsUsed)].slice(0, 8);
|
|
3016
|
-
if (uniqueTools.length === 0)
|
|
3017
|
-
return undefined;
|
|
3018
|
-
return `Tools: ${uniqueTools.join(', ')}`;
|
|
3019
|
-
}
|
|
3020
|
-
function continueAsSlashChat(name, args) {
|
|
3021
|
-
const trimmed = args.trim();
|
|
3022
|
-
return {
|
|
3023
|
-
success: true,
|
|
3024
|
-
continueAsChat: true,
|
|
3025
|
-
chatInput: `/${name}${trimmed ? ` ${trimmed}` : ''}`,
|
|
3026
|
-
};
|
|
15
|
+
const registry_1 = require("./registry");
|
|
16
|
+
const core_command_handlers_1 = require("./core-command-handlers");
|
|
17
|
+
const workflow_commands_1 = require("./workflow-commands");
|
|
18
|
+
const session_commands_1 = require("./session-commands");
|
|
19
|
+
const context_commands_1 = require("./context-commands");
|
|
20
|
+
const tool_commands_1 = require("./tool-commands");
|
|
21
|
+
const model_commands_1 = require("./model-commands");
|
|
22
|
+
const system_commands_1 = require("./system-commands");
|
|
23
|
+
const diagnostic_commands_1 = require("./diagnostic-commands");
|
|
24
|
+
const legacy_commands_1 = require("./legacy-commands");
|
|
25
|
+
function getVisibleCommands(renderer) {
|
|
26
|
+
return (0, core_command_handlers_1.sortCommands)(COMMANDS.filter(command => !command.isHidden &&
|
|
27
|
+
command.audience !== 'compatibility' &&
|
|
28
|
+
command.audience !== 'internal' &&
|
|
29
|
+
(!renderer || !command.rendererScope || command.rendererScope.includes(renderer))));
|
|
3027
30
|
}
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
category: 'workflow',
|
|
3039
|
-
priority: 3,
|
|
3040
|
-
type: 'builtin',
|
|
3041
|
-
execution: 'builtin',
|
|
3042
|
-
risk: 'state-write',
|
|
3043
|
-
execute: () => ({
|
|
3044
|
-
success: false,
|
|
3045
|
-
error: '/target must be routed through the shared AgentRuntimeController.',
|
|
3046
|
-
}),
|
|
3047
|
-
},
|
|
3048
|
-
{
|
|
3049
|
-
name: 'diff',
|
|
3050
|
-
description: 'Summarize current git workspace changes and touched files',
|
|
3051
|
-
argumentHint: '[--max-files N]',
|
|
3052
|
-
category: 'workflow',
|
|
3053
|
-
priority: 5,
|
|
3054
|
-
type: 'builtin',
|
|
3055
|
-
execution: 'builtin',
|
|
3056
|
-
risk: 'read-only',
|
|
3057
|
-
execute: (ctx, args) => handleDiff(ctx, args),
|
|
3058
|
-
},
|
|
3059
|
-
{
|
|
3060
|
-
name: 'commit',
|
|
3061
|
-
description: 'Create a read-only commit plan and suggested message for current changes',
|
|
3062
|
-
argumentHint: '[--max-files N]',
|
|
3063
|
-
category: 'workflow',
|
|
3064
|
-
priority: 8,
|
|
3065
|
-
type: 'builtin',
|
|
3066
|
-
execution: 'builtin',
|
|
3067
|
-
risk: 'read-only',
|
|
3068
|
-
execute: (ctx, args) => handleCommitPlan(ctx, args),
|
|
3069
|
-
},
|
|
3070
|
-
{
|
|
3071
|
-
name: 'review',
|
|
3072
|
-
description: 'Review the current change or requested files',
|
|
3073
|
-
argumentHint: '[scope]',
|
|
3074
|
-
category: 'workflow',
|
|
3075
|
-
priority: 10,
|
|
3076
|
-
type: 'chat',
|
|
3077
|
-
execution: 'agent-workflow',
|
|
3078
|
-
risk: 'read-only',
|
|
3079
|
-
execute: (_ctx, args) => continueAsSlashChat('review', args),
|
|
3080
|
-
},
|
|
3081
|
-
{
|
|
3082
|
-
name: 'security',
|
|
3083
|
-
aliases: ['audit'],
|
|
3084
|
-
description: 'Review code or dependencies for security risks',
|
|
3085
|
-
argumentHint: '[scope]',
|
|
3086
|
-
category: 'workflow',
|
|
3087
|
-
priority: 20,
|
|
3088
|
-
type: 'chat',
|
|
3089
|
-
execution: 'agent-workflow',
|
|
3090
|
-
risk: 'read-only',
|
|
3091
|
-
execute: (_ctx, args) => continueAsSlashChat('security', args),
|
|
3092
|
-
},
|
|
3093
|
-
{
|
|
3094
|
-
name: 'test-gen',
|
|
3095
|
-
aliases: ['tests'],
|
|
3096
|
-
description: 'Generate or improve tests for a target area',
|
|
3097
|
-
argumentHint: '[scope]',
|
|
3098
|
-
category: 'workflow',
|
|
3099
|
-
priority: 30,
|
|
3100
|
-
type: 'chat',
|
|
3101
|
-
execution: 'agent-workflow',
|
|
3102
|
-
risk: 'state-write',
|
|
3103
|
-
execute: (_ctx, args) => continueAsSlashChat('test-gen', args),
|
|
3104
|
-
},
|
|
3105
|
-
{
|
|
3106
|
-
name: 'todos',
|
|
3107
|
-
aliases: ['todo'],
|
|
3108
|
-
description: 'Show current agent todo state',
|
|
3109
|
-
category: 'workflow',
|
|
3110
|
-
priority: 40,
|
|
3111
|
-
type: 'builtin',
|
|
3112
|
-
execution: 'builtin',
|
|
3113
|
-
risk: 'read-only',
|
|
3114
|
-
execute: ctx => handleTodos(ctx),
|
|
3115
|
-
},
|
|
3116
|
-
// Sessions and context lifecycle
|
|
3117
|
-
{
|
|
3118
|
-
name: 'resume',
|
|
3119
|
-
description: 'Resume a previous session',
|
|
3120
|
-
argumentHint: '[number|session-id|name]',
|
|
3121
|
-
category: 'session',
|
|
3122
|
-
priority: 10,
|
|
3123
|
-
type: 'builtin',
|
|
3124
|
-
execution: 'builtin',
|
|
3125
|
-
risk: 'state-write',
|
|
3126
|
-
execute: (ctx, args) => handleResume(ctx, args),
|
|
3127
|
-
},
|
|
3128
|
-
{
|
|
3129
|
-
name: 'sessions',
|
|
3130
|
-
description: 'List recent sessions, or search by file/tool/keyword',
|
|
3131
|
-
argumentHint: '[<query>|--all]',
|
|
3132
|
-
category: 'session',
|
|
3133
|
-
priority: 20,
|
|
3134
|
-
type: 'builtin',
|
|
3135
|
-
execution: 'builtin',
|
|
3136
|
-
risk: 'read-only',
|
|
3137
|
-
execute: (ctx, args) => handleSessions(ctx, args),
|
|
3138
|
-
},
|
|
3139
|
-
{
|
|
3140
|
-
name: 'session-rename',
|
|
3141
|
-
aliases: ['rename-session'],
|
|
3142
|
-
description: 'Rename a saved session',
|
|
3143
|
-
argumentHint: '<number|session-id|name> <new name>',
|
|
3144
|
-
category: 'session',
|
|
3145
|
-
priority: 30,
|
|
3146
|
-
type: 'builtin',
|
|
3147
|
-
execution: 'builtin',
|
|
3148
|
-
risk: 'state-write',
|
|
3149
|
-
execute: (ctx, args) => handleSessionRename(ctx, args),
|
|
3150
|
-
},
|
|
3151
|
-
{
|
|
3152
|
-
name: 'compact',
|
|
3153
|
-
description: 'Compact conversation history to reduce context size',
|
|
3154
|
-
argumentHint: '[threshold]',
|
|
3155
|
-
category: 'session',
|
|
3156
|
-
priority: 40,
|
|
3157
|
-
type: 'builtin',
|
|
3158
|
-
execution: 'builtin',
|
|
3159
|
-
risk: 'state-write',
|
|
3160
|
-
execute: (ctx, args) => handleCompact(ctx, args),
|
|
3161
|
-
},
|
|
3162
|
-
{
|
|
3163
|
-
name: 'context-clear',
|
|
3164
|
-
description: 'Clear current in-memory model context; preserve saved session history',
|
|
3165
|
-
argumentHint: '--yes',
|
|
3166
|
-
category: 'session',
|
|
3167
|
-
priority: 50,
|
|
3168
|
-
type: 'builtin',
|
|
3169
|
-
execution: 'builtin',
|
|
3170
|
-
risk: 'destructive',
|
|
3171
|
-
execute: (ctx, args) => handleContextClear(ctx, args),
|
|
3172
|
-
},
|
|
3173
|
-
{
|
|
3174
|
-
name: 'clear-history',
|
|
3175
|
-
aliases: ['reset'],
|
|
3176
|
-
description: 'Deprecated alias for clearing only the current in-memory model context',
|
|
3177
|
-
argumentHint: '--yes',
|
|
3178
|
-
category: 'legacy',
|
|
3179
|
-
priority: 50,
|
|
3180
|
-
type: 'builtin',
|
|
3181
|
-
isHidden: true,
|
|
3182
|
-
execution: 'builtin',
|
|
3183
|
-
risk: 'destructive',
|
|
3184
|
-
deprecated: { since: 'v0.1.1', replacement: '/context-clear', removeIn: 'v0.3.0' },
|
|
3185
|
-
execute: (ctx, args) => handleContextClear(ctx, args),
|
|
3186
|
-
},
|
|
3187
|
-
// Harness, memory, and skills
|
|
3188
|
-
{
|
|
3189
|
-
name: 'harness',
|
|
3190
|
-
description: 'Show Context Harness state, or `/harness explain` for prompt assembly details',
|
|
3191
|
-
argumentHint: '[explain]',
|
|
3192
|
-
category: 'context',
|
|
3193
|
-
priority: 10,
|
|
3194
|
-
type: 'builtin',
|
|
3195
|
-
execution: 'builtin',
|
|
3196
|
-
risk: 'read-only',
|
|
3197
|
-
execute: (ctx, args) => showHarness(ctx, args),
|
|
3198
|
-
},
|
|
3199
|
-
{
|
|
3200
|
-
name: 'skills',
|
|
3201
|
-
description: 'List loaded skills (built-in / user / project)',
|
|
3202
|
-
category: 'context',
|
|
3203
|
-
priority: 20,
|
|
3204
|
-
type: 'builtin',
|
|
3205
|
-
execution: 'builtin',
|
|
3206
|
-
risk: 'read-only',
|
|
3207
|
-
execute: ctx => handleSkills(ctx),
|
|
3208
|
-
},
|
|
3209
|
-
{
|
|
3210
|
-
name: 'skill',
|
|
3211
|
-
aliases: ['use-skill', 'activate-skill'],
|
|
3212
|
-
description: 'Activate a loaded skill for one chat turn',
|
|
3213
|
-
argumentHint: '<name> <task>',
|
|
3214
|
-
category: 'context',
|
|
3215
|
-
priority: 21,
|
|
3216
|
-
type: 'chat',
|
|
3217
|
-
execution: 'agent-workflow',
|
|
3218
|
-
risk: 'state-write',
|
|
3219
|
-
execute: (ctx, args) => handleSkill(ctx, args),
|
|
3220
|
-
},
|
|
3221
|
-
{
|
|
3222
|
-
name: 'memory',
|
|
3223
|
-
description: 'Show memory status, or `/memory reindex` to rebuild semantic index',
|
|
3224
|
-
argumentHint: '[reindex]',
|
|
3225
|
-
category: 'context',
|
|
3226
|
-
priority: 30,
|
|
3227
|
-
type: 'builtin',
|
|
3228
|
-
execution: 'builtin',
|
|
3229
|
-
risk: 'state-write',
|
|
3230
|
-
execute: (ctx, args) => handleMemory(ctx, args),
|
|
3231
|
-
},
|
|
3232
|
-
// Tools and safety
|
|
3233
|
-
{
|
|
3234
|
-
name: 'tools',
|
|
3235
|
-
aliases: ['tool'],
|
|
3236
|
-
description: 'List available built-in and MCP tools',
|
|
3237
|
-
category: 'tools',
|
|
3238
|
-
priority: 10,
|
|
3239
|
-
type: 'builtin',
|
|
3240
|
-
execution: 'builtin',
|
|
3241
|
-
risk: 'read-only',
|
|
3242
|
-
execute: ctx => handleTools(ctx),
|
|
3243
|
-
},
|
|
3244
|
-
{
|
|
3245
|
-
name: 'edit-preview',
|
|
3246
|
-
description: 'Preview the last edit_file match candidates without writing',
|
|
3247
|
-
category: 'tools',
|
|
3248
|
-
priority: 15,
|
|
3249
|
-
type: 'builtin',
|
|
3250
|
-
execution: 'builtin',
|
|
3251
|
-
risk: 'read-only',
|
|
3252
|
-
execute: ctx => handleEditPreview(ctx),
|
|
3253
|
-
},
|
|
3254
|
-
{
|
|
3255
|
-
name: 'mcp',
|
|
3256
|
-
description: 'Show connected MCP servers and their status',
|
|
3257
|
-
category: 'tools',
|
|
3258
|
-
priority: 20,
|
|
3259
|
-
type: 'builtin',
|
|
3260
|
-
execution: 'builtin',
|
|
3261
|
-
risk: 'read-only',
|
|
3262
|
-
execute: ctx => handleMcp(ctx),
|
|
3263
|
-
},
|
|
3264
|
-
{
|
|
3265
|
-
name: 'safety',
|
|
3266
|
-
description: 'Show safety checker status and audit summary',
|
|
3267
|
-
category: 'tools',
|
|
3268
|
-
priority: 30,
|
|
3269
|
-
type: 'builtin',
|
|
3270
|
-
execution: 'builtin',
|
|
3271
|
-
risk: 'read-only',
|
|
3272
|
-
execute: ctx => showSafety(ctx),
|
|
3273
|
-
},
|
|
3274
|
-
// Model and runtime configuration
|
|
3275
|
-
{
|
|
3276
|
-
name: 'model',
|
|
3277
|
-
description: 'Show or change the current model',
|
|
3278
|
-
argumentHint: '[model|info]',
|
|
3279
|
-
category: 'model',
|
|
3280
|
-
priority: 10,
|
|
3281
|
-
type: 'builtin',
|
|
3282
|
-
execution: 'builtin',
|
|
3283
|
-
risk: 'state-write',
|
|
3284
|
-
execute: (ctx, args) => handleModel(ctx, args),
|
|
3285
|
-
},
|
|
3286
|
-
{
|
|
3287
|
-
name: 'models',
|
|
3288
|
-
description: 'Switch the current model interactively',
|
|
3289
|
-
argumentHint: '',
|
|
3290
|
-
category: 'model',
|
|
3291
|
-
priority: 10,
|
|
3292
|
-
type: 'builtin',
|
|
3293
|
-
execution: 'builtin',
|
|
3294
|
-
risk: 'state-write',
|
|
3295
|
-
execute: (ctx, args) => handleModels(ctx, args),
|
|
3296
|
-
},
|
|
3297
|
-
{
|
|
3298
|
-
name: 'mode',
|
|
3299
|
-
aliases: ['perm'],
|
|
3300
|
-
description: 'Show or change tool permission mode',
|
|
3301
|
-
argumentHint: '[default|accept-edits|plan|auto|next]',
|
|
3302
|
-
category: 'model',
|
|
3303
|
-
priority: 20,
|
|
3304
|
-
type: 'builtin',
|
|
3305
|
-
execution: 'builtin',
|
|
3306
|
-
risk: 'state-write',
|
|
3307
|
-
execute: (ctx, args) => handleMode(ctx, args),
|
|
3308
|
-
},
|
|
3309
|
-
{
|
|
3310
|
-
name: 'config',
|
|
3311
|
-
description: 'Show current configuration',
|
|
3312
|
-
category: 'model',
|
|
3313
|
-
priority: 30,
|
|
3314
|
-
type: 'builtin',
|
|
3315
|
-
execution: 'builtin',
|
|
3316
|
-
risk: 'read-only',
|
|
3317
|
-
execute: ctx => showConfig(ctx),
|
|
3318
|
-
},
|
|
3319
|
-
// System commands
|
|
3320
|
-
{
|
|
3321
|
-
name: 'help',
|
|
3322
|
-
aliases: ['h'],
|
|
3323
|
-
description: 'Show available commands',
|
|
3324
|
-
category: 'system',
|
|
3325
|
-
priority: 10,
|
|
3326
|
-
type: 'builtin',
|
|
3327
|
-
execution: 'builtin',
|
|
3328
|
-
risk: 'read-only',
|
|
3329
|
-
execute: ctx => showHelp(ctx),
|
|
3330
|
-
},
|
|
3331
|
-
{
|
|
3332
|
-
name: 'status',
|
|
3333
|
-
aliases: ['s'],
|
|
3334
|
-
description: 'Show system status overview',
|
|
3335
|
-
category: 'system',
|
|
3336
|
-
priority: 20,
|
|
3337
|
-
type: 'builtin',
|
|
3338
|
-
execution: 'builtin',
|
|
3339
|
-
risk: 'read-only',
|
|
3340
|
-
execute: ctx => showStatus(ctx),
|
|
3341
|
-
},
|
|
3342
|
-
{
|
|
3343
|
-
name: 'clear',
|
|
3344
|
-
description: 'Clear the current view without deleting session data',
|
|
3345
|
-
category: 'system',
|
|
3346
|
-
priority: 30,
|
|
3347
|
-
type: 'builtin',
|
|
3348
|
-
execution: 'renderer-local',
|
|
3349
|
-
risk: 'read-only',
|
|
3350
|
-
rendererScope: ['tui', 'terminal'],
|
|
3351
|
-
execute: ctx => {
|
|
3352
|
-
ctx.clearView?.();
|
|
3353
|
-
return { success: true };
|
|
3354
|
-
},
|
|
3355
|
-
},
|
|
3356
|
-
{
|
|
3357
|
-
name: 'tool-output',
|
|
3358
|
-
description: 'Set the TUI tool output presentation mode',
|
|
3359
|
-
argumentHint: '[adaptive|collapsed|full]',
|
|
3360
|
-
category: 'system',
|
|
3361
|
-
priority: 32,
|
|
3362
|
-
type: 'builtin',
|
|
3363
|
-
execution: 'renderer-local',
|
|
3364
|
-
risk: 'read-only',
|
|
3365
|
-
rendererScope: ['tui'],
|
|
3366
|
-
execute: () => ({ success: true }),
|
|
3367
|
-
},
|
|
3368
|
-
{
|
|
3369
|
-
name: 'permissions',
|
|
3370
|
-
description: 'Set the tool confirmation policy (TUI). No argument opens a picker; with an argument applies immediately.',
|
|
3371
|
-
argumentHint: '[allow|ask|deny]',
|
|
3372
|
-
category: 'system',
|
|
3373
|
-
priority: 33,
|
|
3374
|
-
type: 'builtin',
|
|
3375
|
-
execution: 'renderer-local',
|
|
3376
|
-
risk: 'state-write',
|
|
3377
|
-
rendererScope: ['tui'],
|
|
3378
|
-
execute: () => ({ success: true }),
|
|
3379
|
-
},
|
|
3380
|
-
{
|
|
3381
|
-
name: 'redraw',
|
|
3382
|
-
description: 'Redraw the TUI-owned live region',
|
|
3383
|
-
category: 'system',
|
|
3384
|
-
priority: 34,
|
|
3385
|
-
type: 'builtin',
|
|
3386
|
-
execution: 'renderer-local',
|
|
3387
|
-
risk: 'read-only',
|
|
3388
|
-
rendererScope: ['tui'],
|
|
3389
|
-
execute: () => ({ success: true }),
|
|
3390
|
-
},
|
|
3391
|
-
{
|
|
3392
|
-
name: 'exit',
|
|
3393
|
-
aliases: ['quit', 'q'],
|
|
3394
|
-
description: 'Shutdown and exit',
|
|
3395
|
-
category: 'system',
|
|
3396
|
-
priority: 40,
|
|
3397
|
-
type: 'builtin',
|
|
3398
|
-
execution: 'builtin',
|
|
3399
|
-
risk: 'state-write',
|
|
3400
|
-
execute: ctx => handleExit(ctx),
|
|
3401
|
-
},
|
|
3402
|
-
// Diagnostics
|
|
3403
|
-
{
|
|
3404
|
-
name: 'doctor',
|
|
3405
|
-
aliases: ['diag', 'diagnose'],
|
|
3406
|
-
description: 'Run configuration, tools, MCP, skills, session, and harness diagnostics',
|
|
3407
|
-
category: 'diagnostics',
|
|
3408
|
-
priority: 5,
|
|
3409
|
-
type: 'builtin',
|
|
3410
|
-
execution: 'builtin',
|
|
3411
|
-
risk: 'read-only',
|
|
3412
|
-
execute: ctx => handleDoctor(ctx),
|
|
3413
|
-
},
|
|
3414
|
-
{
|
|
3415
|
-
name: 'storage',
|
|
3416
|
-
description: 'Inspect, repair, or clean Orion Code storage layout',
|
|
3417
|
-
argumentHint: '[doctor|repair [--dry-run|--yes] [--plan=<token>]|cleanup [--dry-run|--yes] [--plan=<token>]]',
|
|
3418
|
-
category: 'diagnostics',
|
|
3419
|
-
priority: 8,
|
|
3420
|
-
type: 'builtin',
|
|
3421
|
-
execution: 'builtin',
|
|
3422
|
-
risk: 'destructive',
|
|
3423
|
-
execute: (ctx, args) => handleStorage(ctx, args),
|
|
3424
|
-
},
|
|
3425
|
-
{
|
|
3426
|
-
name: 'usage',
|
|
3427
|
-
aliases: ['stats'],
|
|
3428
|
-
description: 'Show detailed usage statistics',
|
|
3429
|
-
category: 'diagnostics',
|
|
3430
|
-
priority: 10,
|
|
3431
|
-
type: 'builtin',
|
|
3432
|
-
execution: 'builtin',
|
|
3433
|
-
risk: 'read-only',
|
|
3434
|
-
execute: ctx => handleUsage(ctx),
|
|
3435
|
-
},
|
|
3436
|
-
{
|
|
3437
|
-
name: 'loop-stats',
|
|
3438
|
-
aliases: ['loop'],
|
|
3439
|
-
description: 'Show detailed agent-loop budget and efficiency diagnostics',
|
|
3440
|
-
category: 'diagnostics',
|
|
3441
|
-
priority: 12,
|
|
3442
|
-
type: 'builtin',
|
|
3443
|
-
execution: 'builtin',
|
|
3444
|
-
risk: 'read-only',
|
|
3445
|
-
execute: ctx => handleLoopStats(ctx),
|
|
3446
|
-
},
|
|
3447
|
-
{
|
|
3448
|
-
name: 'trace',
|
|
3449
|
-
description: 'Show structured event timeline for the latest or selected turn',
|
|
3450
|
-
argumentHint: '[latest|turn-id]',
|
|
3451
|
-
category: 'diagnostics',
|
|
3452
|
-
priority: 14,
|
|
3453
|
-
type: 'builtin',
|
|
3454
|
-
execution: 'builtin',
|
|
3455
|
-
risk: 'read-only',
|
|
3456
|
-
execute: (ctx, args) => handleTrace(ctx, args),
|
|
3457
|
-
},
|
|
3458
|
-
{
|
|
3459
|
-
name: 'last-tool',
|
|
3460
|
-
aliases: ['tool-last'],
|
|
3461
|
-
description: 'Show the latest tool call/result with full inspection hints',
|
|
3462
|
-
category: 'diagnostics',
|
|
3463
|
-
priority: 15,
|
|
3464
|
-
type: 'builtin',
|
|
3465
|
-
execution: 'builtin',
|
|
3466
|
-
risk: 'read-only',
|
|
3467
|
-
execute: (ctx, args) => handleLastTool(ctx, args),
|
|
3468
|
-
},
|
|
3469
|
-
{
|
|
3470
|
-
name: 'artifacts',
|
|
3471
|
-
aliases: ['artifact'],
|
|
3472
|
-
description: 'List or inspect saved full tool outputs for this project',
|
|
3473
|
-
argumentHint: '[show <id|prefix> --full]',
|
|
3474
|
-
category: 'diagnostics',
|
|
3475
|
-
priority: 16,
|
|
3476
|
-
type: 'builtin',
|
|
3477
|
-
execution: 'builtin',
|
|
3478
|
-
risk: 'read-only',
|
|
3479
|
-
execute: (ctx, args) => handleArtifacts(ctx, args),
|
|
3480
|
-
},
|
|
3481
|
-
{
|
|
3482
|
-
name: 'checkpoint',
|
|
3483
|
-
aliases: ['checkpoints'],
|
|
3484
|
-
description: 'List or restore file checkpoints created before agent edits',
|
|
3485
|
-
argumentHint: '[list|restore <turn-id|prefix> --yes]',
|
|
3486
|
-
category: 'diagnostics',
|
|
3487
|
-
priority: 18,
|
|
3488
|
-
type: 'builtin',
|
|
3489
|
-
execution: 'builtin',
|
|
3490
|
-
risk: 'destructive',
|
|
3491
|
-
execute: (ctx, args) => handleCheckpoint(ctx, args),
|
|
3492
|
-
},
|
|
3493
|
-
{
|
|
3494
|
-
name: 'cost',
|
|
3495
|
-
description: 'Show session token usage',
|
|
3496
|
-
category: 'diagnostics',
|
|
3497
|
-
priority: 20,
|
|
3498
|
-
type: 'builtin',
|
|
3499
|
-
execution: 'builtin',
|
|
3500
|
-
risk: 'read-only',
|
|
3501
|
-
deprecated: { since: 'v0.1.1', replacement: '/usage', removeIn: 'v0.3.0' },
|
|
3502
|
-
execute: ctx => handleCost(ctx),
|
|
3503
|
-
},
|
|
3504
|
-
{
|
|
3505
|
-
name: 'agents',
|
|
3506
|
-
description: 'List registered agents and their status',
|
|
3507
|
-
category: 'diagnostics',
|
|
3508
|
-
priority: 30,
|
|
3509
|
-
type: 'builtin',
|
|
3510
|
-
execution: 'builtin',
|
|
3511
|
-
risk: 'read-only',
|
|
3512
|
-
isHidden: true,
|
|
3513
|
-
execute: ctx => showAgents(ctx),
|
|
3514
|
-
},
|
|
3515
|
-
{
|
|
3516
|
-
name: 'migrate',
|
|
3517
|
-
description: 'Migrate data from OpenHorse to Orion Code',
|
|
3518
|
-
argumentHint: 'openhorse [--dry-run | --yes] [--include-env] [--include-project-files]',
|
|
3519
|
-
category: 'diagnostics',
|
|
3520
|
-
priority: 32,
|
|
3521
|
-
type: 'builtin',
|
|
3522
|
-
execution: 'builtin',
|
|
3523
|
-
risk: 'destructive',
|
|
3524
|
-
execute: (ctx, args) => (0, command_1.handleMigrateCommand)(ctx, args),
|
|
3525
|
-
},
|
|
3526
|
-
// Legacy commands kept executable for compatibility, but not shown in help/palette.
|
|
3527
|
-
{
|
|
3528
|
-
name: 'task',
|
|
3529
|
-
description: 'Submit or list tasks',
|
|
3530
|
-
params: [{ name: 'action', description: 'list | <task-name>', required: false }],
|
|
3531
|
-
category: 'legacy',
|
|
3532
|
-
type: 'builtin',
|
|
3533
|
-
isHidden: true,
|
|
3534
|
-
execution: 'builtin',
|
|
3535
|
-
risk: 'state-write',
|
|
3536
|
-
deprecated: { since: 'v0.1.1', replacement: '/target', removeIn: 'v0.3.0' },
|
|
3537
|
-
execute: (ctx, args) => handleTask(ctx, args),
|
|
3538
|
-
},
|
|
3539
|
-
{
|
|
3540
|
-
name: 'run',
|
|
3541
|
-
description: 'Create and run a task through Agent + LLM',
|
|
3542
|
-
params: [{ name: 'description', description: 'Task description', required: true }],
|
|
3543
|
-
category: 'legacy',
|
|
3544
|
-
type: 'builtin',
|
|
3545
|
-
isHidden: true,
|
|
3546
|
-
execution: 'agent-workflow',
|
|
3547
|
-
risk: 'state-write',
|
|
3548
|
-
deprecated: { since: 'v0.1.1', replacement: '/target', removeIn: 'v0.3.0' },
|
|
3549
|
-
execute: (ctx, args) => handleRun(ctx, args),
|
|
3550
|
-
},
|
|
3551
|
-
{
|
|
3552
|
-
name: 'chat',
|
|
3553
|
-
description: 'Send a message to the LLM',
|
|
3554
|
-
params: [{ name: 'message', description: 'Message to send', required: true }],
|
|
3555
|
-
category: 'legacy',
|
|
3556
|
-
type: 'chat',
|
|
3557
|
-
isHidden: true,
|
|
3558
|
-
execution: 'agent-workflow',
|
|
3559
|
-
risk: 'state-write',
|
|
3560
|
-
deprecated: { since: 'v0.1.1', removeIn: 'v0.3.0' },
|
|
3561
|
-
execute: (ctx, args) => ({ success: true, continueAsChat: true, chatInput: args }),
|
|
3562
|
-
},
|
|
31
|
+
const SYSTEM_COMMANDS = (0, system_commands_1.createSystemCommands)(getVisibleCommands);
|
|
32
|
+
const COMMAND_DEFINITIONS = [
|
|
33
|
+
...workflow_commands_1.WORKFLOW_COMMANDS,
|
|
34
|
+
...session_commands_1.SESSION_COMMANDS,
|
|
35
|
+
...context_commands_1.CONTEXT_COMMANDS,
|
|
36
|
+
...tool_commands_1.TOOL_COMMANDS,
|
|
37
|
+
...model_commands_1.MODEL_COMMANDS,
|
|
38
|
+
...SYSTEM_COMMANDS,
|
|
39
|
+
...diagnostic_commands_1.DIAGNOSTIC_COMMANDS,
|
|
40
|
+
...legacy_commands_1.LEGACY_COMMANDS,
|
|
3563
41
|
];
|
|
3564
|
-
|
|
3565
|
-
// 导出
|
|
3566
|
-
// ============================================================================
|
|
42
|
+
const COMMANDS = (0, registry_1.registerBuiltinCommands)(COMMAND_DEFINITIONS);
|
|
3567
43
|
function getCommands() {
|
|
3568
|
-
return sortCommands(COMMANDS);
|
|
3569
|
-
}
|
|
3570
|
-
function getVisibleCommands(renderer) {
|
|
3571
|
-
return sortCommands(COMMANDS.filter(command => !command.isHidden &&
|
|
3572
|
-
(!renderer || !command.rendererScope || command.rendererScope.includes(renderer))));
|
|
44
|
+
return (0, core_command_handlers_1.sortCommands)(COMMANDS);
|
|
3573
45
|
}
|
|
3574
46
|
function findCommand(name) {
|
|
3575
|
-
|
|
47
|
+
const normalized = name.toLowerCase();
|
|
48
|
+
return COMMANDS.find(command => command.name.toLowerCase() === normalized ||
|
|
49
|
+
command.aliases?.some(alias => alias.toLowerCase() === normalized) ||
|
|
50
|
+
command.compatibilityAliases?.some(alias => alias.name.toLowerCase() === normalized));
|
|
3576
51
|
}
|
|
3577
52
|
function getCommandNames() {
|
|
3578
|
-
return getVisibleCommands().map(
|
|
53
|
+
return getVisibleCommands().map(command => command.name);
|
|
3579
54
|
}
|
|
55
|
+
var core_command_handlers_2 = require("./core-command-handlers");
|
|
56
|
+
Object.defineProperty(exports, "executeChat", { enumerable: true, get: function () { return core_command_handlers_2.handleChat; } });
|
|
57
|
+
Object.defineProperty(exports, "getCommandCategoryLabel", { enumerable: true, get: function () { return core_command_handlers_2.getCommandCategoryLabel; } });
|
|
58
|
+
Object.defineProperty(exports, "sortCommands", { enumerable: true, get: function () { return core_command_handlers_2.sortCommands; } });
|
|
3580
59
|
//# sourceMappingURL=index.js.map
|