attocode 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +164 -0
- package/dist/src/adapters.d.ts +83 -0
- package/dist/src/adapters.d.ts.map +1 -0
- package/dist/src/adapters.js +221 -0
- package/dist/src/adapters.js.map +1 -0
- package/dist/src/agent-tools/index.d.ts +7 -0
- package/dist/src/agent-tools/index.d.ts.map +1 -0
- package/dist/src/agent-tools/index.js +8 -0
- package/dist/src/agent-tools/index.js.map +1 -0
- package/dist/src/agent-tools/lsp-file-tools.d.ts +33 -0
- package/dist/src/agent-tools/lsp-file-tools.d.ts.map +1 -0
- package/dist/src/agent-tools/lsp-file-tools.js +200 -0
- package/dist/src/agent-tools/lsp-file-tools.js.map +1 -0
- package/dist/src/agent.d.ts +667 -0
- package/dist/src/agent.d.ts.map +1 -0
- package/dist/src/agent.js +2824 -0
- package/dist/src/agent.js.map +1 -0
- package/dist/src/cli.d.ts +36 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +176 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/handler.d.ts +22 -0
- package/dist/src/commands/handler.d.ts.map +1 -0
- package/dist/src/commands/handler.js +1320 -0
- package/dist/src/commands/handler.js.map +1 -0
- package/dist/src/commands/init.d.ts +7 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +153 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/types.d.ts +70 -0
- package/dist/src/commands/types.d.ts.map +1 -0
- package/dist/src/commands/types.js +8 -0
- package/dist/src/commands/types.js.map +1 -0
- package/dist/src/config.d.ts +22 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +25 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/core/index.d.ts +32 -0
- package/dist/src/core/index.d.ts.map +1 -0
- package/dist/src/core/index.js +35 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/process-handlers.d.ts +43 -0
- package/dist/src/core/process-handlers.d.ts.map +1 -0
- package/dist/src/core/process-handlers.js +117 -0
- package/dist/src/core/process-handlers.js.map +1 -0
- package/dist/src/core/protocol/bridge.d.ts +117 -0
- package/dist/src/core/protocol/bridge.d.ts.map +1 -0
- package/dist/src/core/protocol/bridge.js +149 -0
- package/dist/src/core/protocol/bridge.js.map +1 -0
- package/dist/src/core/protocol/index.d.ts +8 -0
- package/dist/src/core/protocol/index.d.ts.map +1 -0
- package/dist/src/core/protocol/index.js +8 -0
- package/dist/src/core/protocol/index.js.map +1 -0
- package/dist/src/core/protocol/types.d.ts +539 -0
- package/dist/src/core/protocol/types.d.ts.map +1 -0
- package/dist/src/core/protocol/types.js +149 -0
- package/dist/src/core/protocol/types.js.map +1 -0
- package/dist/src/core/queues/atomic-counter.d.ts +36 -0
- package/dist/src/core/queues/atomic-counter.d.ts.map +1 -0
- package/dist/src/core/queues/atomic-counter.js +46 -0
- package/dist/src/core/queues/atomic-counter.js.map +1 -0
- package/dist/src/core/queues/event-queue.d.ts +126 -0
- package/dist/src/core/queues/event-queue.d.ts.map +1 -0
- package/dist/src/core/queues/event-queue.js +208 -0
- package/dist/src/core/queues/event-queue.js.map +1 -0
- package/dist/src/core/queues/index.d.ts +12 -0
- package/dist/src/core/queues/index.d.ts.map +1 -0
- package/dist/src/core/queues/index.js +15 -0
- package/dist/src/core/queues/index.js.map +1 -0
- package/dist/src/core/queues/submission-queue.d.ts +116 -0
- package/dist/src/core/queues/submission-queue.d.ts.map +1 -0
- package/dist/src/core/queues/submission-queue.js +236 -0
- package/dist/src/core/queues/submission-queue.js.map +1 -0
- package/dist/src/costs/index.d.ts +22 -0
- package/dist/src/costs/index.d.ts.map +1 -0
- package/dist/src/costs/index.js +22 -0
- package/dist/src/costs/index.js.map +1 -0
- package/dist/src/costs/model-registry.d.ts +80 -0
- package/dist/src/costs/model-registry.d.ts.map +1 -0
- package/dist/src/costs/model-registry.js +237 -0
- package/dist/src/costs/model-registry.js.map +1 -0
- package/dist/src/costs/types.d.ts +50 -0
- package/dist/src/costs/types.d.ts.map +1 -0
- package/dist/src/costs/types.js +2 -0
- package/dist/src/costs/types.js.map +1 -0
- package/dist/src/defaults.d.ts +114 -0
- package/dist/src/defaults.d.ts.map +1 -0
- package/dist/src/defaults.js +457 -0
- package/dist/src/defaults.js.map +1 -0
- package/dist/src/first-run.d.ts +35 -0
- package/dist/src/first-run.d.ts.map +1 -0
- package/dist/src/first-run.js +94 -0
- package/dist/src/first-run.js.map +1 -0
- package/dist/src/hello.d.ts +2 -0
- package/dist/src/hello.d.ts.map +1 -0
- package/dist/src/hello.js +4 -0
- package/dist/src/hello.js.map +1 -0
- package/dist/src/integrations/agent-registry.d.ts +160 -0
- package/dist/src/integrations/agent-registry.d.ts.map +1 -0
- package/dist/src/integrations/agent-registry.js +446 -0
- package/dist/src/integrations/agent-registry.js.map +1 -0
- package/dist/src/integrations/auto-compaction.d.ts +177 -0
- package/dist/src/integrations/auto-compaction.d.ts.map +1 -0
- package/dist/src/integrations/auto-compaction.js +428 -0
- package/dist/src/integrations/auto-compaction.js.map +1 -0
- package/dist/src/integrations/cancellation.d.ts +162 -0
- package/dist/src/integrations/cancellation.d.ts.map +1 -0
- package/dist/src/integrations/cancellation.js +339 -0
- package/dist/src/integrations/cancellation.js.map +1 -0
- package/dist/src/integrations/codebase-context.d.ts +319 -0
- package/dist/src/integrations/codebase-context.d.ts.map +1 -0
- package/dist/src/integrations/codebase-context.js +816 -0
- package/dist/src/integrations/codebase-context.js.map +1 -0
- package/dist/src/integrations/compaction.d.ts +192 -0
- package/dist/src/integrations/compaction.d.ts.map +1 -0
- package/dist/src/integrations/compaction.js +376 -0
- package/dist/src/integrations/compaction.js.map +1 -0
- package/dist/src/integrations/context-engineering.d.ts +246 -0
- package/dist/src/integrations/context-engineering.d.ts.map +1 -0
- package/dist/src/integrations/context-engineering.js +394 -0
- package/dist/src/integrations/context-engineering.js.map +1 -0
- package/dist/src/integrations/diff-utils.d.ts +105 -0
- package/dist/src/integrations/diff-utils.d.ts.map +1 -0
- package/dist/src/integrations/diff-utils.js +497 -0
- package/dist/src/integrations/diff-utils.js.map +1 -0
- package/dist/src/integrations/economics.d.ts +192 -0
- package/dist/src/integrations/economics.d.ts.map +1 -0
- package/dist/src/integrations/economics.js +431 -0
- package/dist/src/integrations/economics.js.map +1 -0
- package/dist/src/integrations/execution-policy.d.ts +189 -0
- package/dist/src/integrations/execution-policy.d.ts.map +1 -0
- package/dist/src/integrations/execution-policy.js +352 -0
- package/dist/src/integrations/execution-policy.js.map +1 -0
- package/dist/src/integrations/file-change-tracker.d.ts +161 -0
- package/dist/src/integrations/file-change-tracker.d.ts.map +1 -0
- package/dist/src/integrations/file-change-tracker.js +520 -0
- package/dist/src/integrations/file-change-tracker.js.map +1 -0
- package/dist/src/integrations/hierarchical-config.d.ts +212 -0
- package/dist/src/integrations/hierarchical-config.d.ts.map +1 -0
- package/dist/src/integrations/hierarchical-config.js +484 -0
- package/dist/src/integrations/hierarchical-config.js.map +1 -0
- package/dist/src/integrations/hooks.d.ts +114 -0
- package/dist/src/integrations/hooks.d.ts.map +1 -0
- package/dist/src/integrations/hooks.js +326 -0
- package/dist/src/integrations/hooks.js.map +1 -0
- package/dist/src/integrations/ignore.d.ts +143 -0
- package/dist/src/integrations/ignore.d.ts.map +1 -0
- package/dist/src/integrations/ignore.js +417 -0
- package/dist/src/integrations/ignore.js.map +1 -0
- package/dist/src/integrations/image-renderer.d.ts +119 -0
- package/dist/src/integrations/image-renderer.d.ts.map +1 -0
- package/dist/src/integrations/image-renderer.js +306 -0
- package/dist/src/integrations/image-renderer.js.map +1 -0
- package/dist/src/integrations/index.d.ts +42 -0
- package/dist/src/integrations/index.d.ts.map +1 -0
- package/dist/src/integrations/index.js +73 -0
- package/dist/src/integrations/index.js.map +1 -0
- package/dist/src/integrations/lsp.d.ts +196 -0
- package/dist/src/integrations/lsp.d.ts.map +1 -0
- package/dist/src/integrations/lsp.js +582 -0
- package/dist/src/integrations/lsp.js.map +1 -0
- package/dist/src/integrations/mcp-client.d.ts +270 -0
- package/dist/src/integrations/mcp-client.d.ts.map +1 -0
- package/dist/src/integrations/mcp-client.js +698 -0
- package/dist/src/integrations/mcp-client.js.map +1 -0
- package/dist/src/integrations/mcp-tool-search.d.ts +77 -0
- package/dist/src/integrations/mcp-tool-search.d.ts.map +1 -0
- package/dist/src/integrations/mcp-tool-search.js +220 -0
- package/dist/src/integrations/mcp-tool-search.js.map +1 -0
- package/dist/src/integrations/memory.d.ts +108 -0
- package/dist/src/integrations/memory.d.ts.map +1 -0
- package/dist/src/integrations/memory.js +288 -0
- package/dist/src/integrations/memory.js.map +1 -0
- package/dist/src/integrations/multi-agent.d.ts +150 -0
- package/dist/src/integrations/multi-agent.d.ts.map +1 -0
- package/dist/src/integrations/multi-agent.js +306 -0
- package/dist/src/integrations/multi-agent.js.map +1 -0
- package/dist/src/integrations/observability.d.ts +162 -0
- package/dist/src/integrations/observability.d.ts.map +1 -0
- package/dist/src/integrations/observability.js +406 -0
- package/dist/src/integrations/observability.js.map +1 -0
- package/dist/src/integrations/openrouter-pricing.d.ts +42 -0
- package/dist/src/integrations/openrouter-pricing.d.ts.map +1 -0
- package/dist/src/integrations/openrouter-pricing.js +124 -0
- package/dist/src/integrations/openrouter-pricing.js.map +1 -0
- package/dist/src/integrations/pending-plan.d.ts +171 -0
- package/dist/src/integrations/pending-plan.d.ts.map +1 -0
- package/dist/src/integrations/pending-plan.js +244 -0
- package/dist/src/integrations/pending-plan.js.map +1 -0
- package/dist/src/integrations/persistence.d.ts +48 -0
- package/dist/src/integrations/persistence.d.ts.map +1 -0
- package/dist/src/integrations/persistence.js +196 -0
- package/dist/src/integrations/persistence.js.map +1 -0
- package/dist/src/integrations/planning.d.ts +96 -0
- package/dist/src/integrations/planning.d.ts.map +1 -0
- package/dist/src/integrations/planning.js +338 -0
- package/dist/src/integrations/planning.js.map +1 -0
- package/dist/src/integrations/pty-shell.d.ts +169 -0
- package/dist/src/integrations/pty-shell.d.ts.map +1 -0
- package/dist/src/integrations/pty-shell.js +367 -0
- package/dist/src/integrations/pty-shell.js.map +1 -0
- package/dist/src/integrations/react.d.ts +139 -0
- package/dist/src/integrations/react.d.ts.map +1 -0
- package/dist/src/integrations/react.js +273 -0
- package/dist/src/integrations/react.js.map +1 -0
- package/dist/src/integrations/resources.d.ts +177 -0
- package/dist/src/integrations/resources.d.ts.map +1 -0
- package/dist/src/integrations/resources.js +311 -0
- package/dist/src/integrations/resources.js.map +1 -0
- package/dist/src/integrations/result-synthesizer.d.ts +389 -0
- package/dist/src/integrations/result-synthesizer.d.ts.map +1 -0
- package/dist/src/integrations/result-synthesizer.js +951 -0
- package/dist/src/integrations/result-synthesizer.js.map +1 -0
- package/dist/src/integrations/routing.d.ts +117 -0
- package/dist/src/integrations/routing.d.ts.map +1 -0
- package/dist/src/integrations/routing.js +347 -0
- package/dist/src/integrations/routing.js.map +1 -0
- package/dist/src/integrations/rules.d.ts +131 -0
- package/dist/src/integrations/rules.d.ts.map +1 -0
- package/dist/src/integrations/rules.js +284 -0
- package/dist/src/integrations/rules.js.map +1 -0
- package/dist/src/integrations/safety.d.ts +142 -0
- package/dist/src/integrations/safety.d.ts.map +1 -0
- package/dist/src/integrations/safety.js +342 -0
- package/dist/src/integrations/safety.js.map +1 -0
- package/dist/src/integrations/sandbox/basic.d.ts +74 -0
- package/dist/src/integrations/sandbox/basic.d.ts.map +1 -0
- package/dist/src/integrations/sandbox/basic.js +310 -0
- package/dist/src/integrations/sandbox/basic.js.map +1 -0
- package/dist/src/integrations/sandbox/docker.d.ts +94 -0
- package/dist/src/integrations/sandbox/docker.d.ts.map +1 -0
- package/dist/src/integrations/sandbox/docker.js +293 -0
- package/dist/src/integrations/sandbox/docker.js.map +1 -0
- package/dist/src/integrations/sandbox/index.d.ts +182 -0
- package/dist/src/integrations/sandbox/index.d.ts.map +1 -0
- package/dist/src/integrations/sandbox/index.js +382 -0
- package/dist/src/integrations/sandbox/index.js.map +1 -0
- package/dist/src/integrations/sandbox/landlock.d.ts +59 -0
- package/dist/src/integrations/sandbox/landlock.d.ts.map +1 -0
- package/dist/src/integrations/sandbox/landlock.js +326 -0
- package/dist/src/integrations/sandbox/landlock.js.map +1 -0
- package/dist/src/integrations/sandbox/seatbelt.d.ts +68 -0
- package/dist/src/integrations/sandbox/seatbelt.d.ts.map +1 -0
- package/dist/src/integrations/sandbox/seatbelt.js +298 -0
- package/dist/src/integrations/sandbox/seatbelt.js.map +1 -0
- package/dist/src/integrations/semantic-cache.d.ts +178 -0
- package/dist/src/integrations/semantic-cache.d.ts.map +1 -0
- package/dist/src/integrations/semantic-cache.js +372 -0
- package/dist/src/integrations/semantic-cache.js.map +1 -0
- package/dist/src/integrations/session-store.d.ts +183 -0
- package/dist/src/integrations/session-store.d.ts.map +1 -0
- package/dist/src/integrations/session-store.js +345 -0
- package/dist/src/integrations/session-store.js.map +1 -0
- package/dist/src/integrations/shared-blackboard.d.ts +403 -0
- package/dist/src/integrations/shared-blackboard.d.ts.map +1 -0
- package/dist/src/integrations/shared-blackboard.js +710 -0
- package/dist/src/integrations/shared-blackboard.js.map +1 -0
- package/dist/src/integrations/skills.d.ts +171 -0
- package/dist/src/integrations/skills.d.ts.map +1 -0
- package/dist/src/integrations/skills.js +403 -0
- package/dist/src/integrations/skills.js.map +1 -0
- package/dist/src/integrations/smart-decomposer.d.ts +322 -0
- package/dist/src/integrations/smart-decomposer.d.ts.map +1 -0
- package/dist/src/integrations/smart-decomposer.js +856 -0
- package/dist/src/integrations/smart-decomposer.js.map +1 -0
- package/dist/src/integrations/sourcegraph.d.ts +169 -0
- package/dist/src/integrations/sourcegraph.d.ts.map +1 -0
- package/dist/src/integrations/sourcegraph.js +379 -0
- package/dist/src/integrations/sourcegraph.js.map +1 -0
- package/dist/src/integrations/sqlite-store.d.ts +518 -0
- package/dist/src/integrations/sqlite-store.d.ts.map +1 -0
- package/dist/src/integrations/sqlite-store.js +1423 -0
- package/dist/src/integrations/sqlite-store.js.map +1 -0
- package/dist/src/integrations/streaming.d.ts +102 -0
- package/dist/src/integrations/streaming.d.ts.map +1 -0
- package/dist/src/integrations/streaming.js +362 -0
- package/dist/src/integrations/streaming.js.map +1 -0
- package/dist/src/integrations/thread-manager.d.ts +199 -0
- package/dist/src/integrations/thread-manager.d.ts.map +1 -0
- package/dist/src/integrations/thread-manager.js +357 -0
- package/dist/src/integrations/thread-manager.js.map +1 -0
- package/dist/src/main.d.ts +26 -0
- package/dist/src/main.d.ts.map +1 -0
- package/dist/src/main.js +170 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/modes/index.d.ts +10 -0
- package/dist/src/modes/index.d.ts.map +1 -0
- package/dist/src/modes/index.js +10 -0
- package/dist/src/modes/index.js.map +1 -0
- package/dist/src/modes/repl.d.ts +19 -0
- package/dist/src/modes/repl.d.ts.map +1 -0
- package/dist/src/modes/repl.js +393 -0
- package/dist/src/modes/repl.js.map +1 -0
- package/dist/src/modes/tui.d.ts +29 -0
- package/dist/src/modes/tui.d.ts.map +1 -0
- package/dist/src/modes/tui.js +272 -0
- package/dist/src/modes/tui.js.map +1 -0
- package/dist/src/modes.d.ts +179 -0
- package/dist/src/modes.d.ts.map +1 -0
- package/dist/src/modes.js +385 -0
- package/dist/src/modes.js.map +1 -0
- package/dist/src/observability/tracer.d.ts +111 -0
- package/dist/src/observability/tracer.d.ts.map +1 -0
- package/dist/src/observability/tracer.js +300 -0
- package/dist/src/observability/tracer.js.map +1 -0
- package/dist/src/observability/types.d.ts +271 -0
- package/dist/src/observability/types.d.ts.map +1 -0
- package/dist/src/observability/types.js +24 -0
- package/dist/src/observability/types.js.map +1 -0
- package/dist/src/paths.d.ts +101 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +148 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/persistence/index.d.ts +38 -0
- package/dist/src/persistence/index.d.ts.map +1 -0
- package/dist/src/persistence/index.js +48 -0
- package/dist/src/persistence/index.js.map +1 -0
- package/dist/src/persistence/migrator.d.ts +135 -0
- package/dist/src/persistence/migrator.d.ts.map +1 -0
- package/dist/src/persistence/migrator.js +303 -0
- package/dist/src/persistence/migrator.js.map +1 -0
- package/dist/src/persistence/schema.d.ts +101 -0
- package/dist/src/persistence/schema.d.ts.map +1 -0
- package/dist/src/persistence/schema.js +395 -0
- package/dist/src/persistence/schema.js.map +1 -0
- package/dist/src/providers/adapters/anthropic.d.ts +20 -0
- package/dist/src/providers/adapters/anthropic.d.ts.map +1 -0
- package/dist/src/providers/adapters/anthropic.js +124 -0
- package/dist/src/providers/adapters/anthropic.js.map +1 -0
- package/dist/src/providers/adapters/mock.d.ts +25 -0
- package/dist/src/providers/adapters/mock.d.ts.map +1 -0
- package/dist/src/providers/adapters/mock.js +133 -0
- package/dist/src/providers/adapters/mock.js.map +1 -0
- package/dist/src/providers/adapters/openai.d.ts +21 -0
- package/dist/src/providers/adapters/openai.d.ts.map +1 -0
- package/dist/src/providers/adapters/openai.js +126 -0
- package/dist/src/providers/adapters/openai.js.map +1 -0
- package/dist/src/providers/adapters/openrouter.d.ts +49 -0
- package/dist/src/providers/adapters/openrouter.d.ts.map +1 -0
- package/dist/src/providers/adapters/openrouter.js +363 -0
- package/dist/src/providers/adapters/openrouter.js.map +1 -0
- package/dist/src/providers/provider.d.ts +54 -0
- package/dist/src/providers/provider.d.ts.map +1 -0
- package/dist/src/providers/provider.js +111 -0
- package/dist/src/providers/provider.js.map +1 -0
- package/dist/src/providers/resilient-fetch.d.ts +99 -0
- package/dist/src/providers/resilient-fetch.d.ts.map +1 -0
- package/dist/src/providers/resilient-fetch.js +208 -0
- package/dist/src/providers/resilient-fetch.js.map +1 -0
- package/dist/src/providers/types.d.ts +227 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +24 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/session-picker.d.ts +28 -0
- package/dist/src/session-picker.d.ts.map +1 -0
- package/dist/src/session-picker.js +256 -0
- package/dist/src/session-picker.js.map +1 -0
- package/dist/src/test-sqlite.d.ts +2 -0
- package/dist/src/test-sqlite.d.ts.map +1 -0
- package/dist/src/test-sqlite.js +114 -0
- package/dist/src/test-sqlite.js.map +1 -0
- package/dist/src/tools/agent.d.ts +44 -0
- package/dist/src/tools/agent.d.ts.map +1 -0
- package/dist/src/tools/agent.js +110 -0
- package/dist/src/tools/agent.js.map +1 -0
- package/dist/src/tools/bash.d.ts +52 -0
- package/dist/src/tools/bash.d.ts.map +1 -0
- package/dist/src/tools/bash.js +141 -0
- package/dist/src/tools/bash.js.map +1 -0
- package/dist/src/tools/file.d.ts +47 -0
- package/dist/src/tools/file.d.ts.map +1 -0
- package/dist/src/tools/file.js +263 -0
- package/dist/src/tools/file.js.map +1 -0
- package/dist/src/tools/permission.d.ts +43 -0
- package/dist/src/tools/permission.d.ts.map +1 -0
- package/dist/src/tools/permission.js +216 -0
- package/dist/src/tools/permission.js.map +1 -0
- package/dist/src/tools/registry.d.ts +63 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +250 -0
- package/dist/src/tools/registry.js.map +1 -0
- package/dist/src/tools/standard.d.ts +57 -0
- package/dist/src/tools/standard.d.ts.map +1 -0
- package/dist/src/tools/standard.js +113 -0
- package/dist/src/tools/standard.js.map +1 -0
- package/dist/src/tools/types.d.ts +146 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +28 -0
- package/dist/src/tools/types.js.map +1 -0
- package/dist/src/tools/undo.d.ts +71 -0
- package/dist/src/tools/undo.d.ts.map +1 -0
- package/dist/src/tools/undo.js +123 -0
- package/dist/src/tools/undo.js.map +1 -0
- package/dist/src/tracing/cache-boundary-tracker.d.ts +189 -0
- package/dist/src/tracing/cache-boundary-tracker.d.ts.map +1 -0
- package/dist/src/tracing/cache-boundary-tracker.js +411 -0
- package/dist/src/tracing/cache-boundary-tracker.js.map +1 -0
- package/dist/src/tracing/trace-collector.d.ts +274 -0
- package/dist/src/tracing/trace-collector.d.ts.map +1 -0
- package/dist/src/tracing/trace-collector.js +727 -0
- package/dist/src/tracing/trace-collector.js.map +1 -0
- package/dist/src/tracing/types.d.ts +657 -0
- package/dist/src/tracing/types.d.ts.map +1 -0
- package/dist/src/tracing/types.js +39 -0
- package/dist/src/tracing/types.js.map +1 -0
- package/dist/src/tricks/failure-evidence.d.ts +268 -0
- package/dist/src/tricks/failure-evidence.d.ts.map +1 -0
- package/dist/src/tricks/failure-evidence.js +544 -0
- package/dist/src/tricks/failure-evidence.js.map +1 -0
- package/dist/src/tricks/json-utils.d.ts +77 -0
- package/dist/src/tricks/json-utils.d.ts.map +1 -0
- package/dist/src/tricks/json-utils.js +247 -0
- package/dist/src/tricks/json-utils.js.map +1 -0
- package/dist/src/tricks/kv-cache-context.d.ts +227 -0
- package/dist/src/tricks/kv-cache-context.d.ts.map +1 -0
- package/dist/src/tricks/kv-cache-context.js +377 -0
- package/dist/src/tricks/kv-cache-context.js.map +1 -0
- package/dist/src/tricks/recitation.d.ts +208 -0
- package/dist/src/tricks/recitation.d.ts.map +1 -0
- package/dist/src/tricks/recitation.js +374 -0
- package/dist/src/tricks/recitation.js.map +1 -0
- package/dist/src/tricks/reversible-compaction.d.ts +251 -0
- package/dist/src/tricks/reversible-compaction.d.ts.map +1 -0
- package/dist/src/tricks/reversible-compaction.js +555 -0
- package/dist/src/tricks/reversible-compaction.js.map +1 -0
- package/dist/src/tricks/serialization-diversity.d.ts +197 -0
- package/dist/src/tricks/serialization-diversity.d.ts.map +1 -0
- package/dist/src/tricks/serialization-diversity.js +460 -0
- package/dist/src/tricks/serialization-diversity.js.map +1 -0
- package/dist/src/tui/app.d.ts +42 -0
- package/dist/src/tui/app.d.ts.map +1 -0
- package/dist/src/tui/app.js +1076 -0
- package/dist/src/tui/app.js.map +1 -0
- package/dist/src/tui/components/ApprovalDialog.d.ts +28 -0
- package/dist/src/tui/components/ApprovalDialog.d.ts.map +1 -0
- package/dist/src/tui/components/ApprovalDialog.js +59 -0
- package/dist/src/tui/components/ApprovalDialog.js.map +1 -0
- package/dist/src/tui/components/InputArea.d.ts +35 -0
- package/dist/src/tui/components/InputArea.d.ts.map +1 -0
- package/dist/src/tui/components/InputArea.js +144 -0
- package/dist/src/tui/components/InputArea.js.map +1 -0
- package/dist/src/tui/components/MessageItem.d.ts +28 -0
- package/dist/src/tui/components/MessageItem.d.ts.map +1 -0
- package/dist/src/tui/components/MessageItem.js +27 -0
- package/dist/src/tui/components/MessageItem.js.map +1 -0
- package/dist/src/tui/components/ScrollableBox.d.ts +41 -0
- package/dist/src/tui/components/ScrollableBox.d.ts.map +1 -0
- package/dist/src/tui/components/ScrollableBox.js +101 -0
- package/dist/src/tui/components/ScrollableBox.js.map +1 -0
- package/dist/src/tui/components/ToolCallItem.d.ts +33 -0
- package/dist/src/tui/components/ToolCallItem.d.ts.map +1 -0
- package/dist/src/tui/components/ToolCallItem.js +91 -0
- package/dist/src/tui/components/ToolCallItem.js.map +1 -0
- package/dist/src/tui/components/index.d.ts +13 -0
- package/dist/src/tui/components/index.d.ts.map +1 -0
- package/dist/src/tui/components/index.js +15 -0
- package/dist/src/tui/components/index.js.map +1 -0
- package/dist/src/tui/event-display.d.ts +19 -0
- package/dist/src/tui/event-display.d.ts.map +1 -0
- package/dist/src/tui/event-display.js +178 -0
- package/dist/src/tui/event-display.js.map +1 -0
- package/dist/src/tui/index.d.ts +105 -0
- package/dist/src/tui/index.d.ts.map +1 -0
- package/dist/src/tui/index.js +214 -0
- package/dist/src/tui/index.js.map +1 -0
- package/dist/src/tui/input/CommandPalette.d.ts +55 -0
- package/dist/src/tui/input/CommandPalette.d.ts.map +1 -0
- package/dist/src/tui/input/CommandPalette.js +135 -0
- package/dist/src/tui/input/CommandPalette.js.map +1 -0
- package/dist/src/tui/input/index.d.ts +7 -0
- package/dist/src/tui/input/index.d.ts.map +1 -0
- package/dist/src/tui/input/index.js +7 -0
- package/dist/src/tui/input/index.js.map +1 -0
- package/dist/src/tui/theme/index.d.ts +45 -0
- package/dist/src/tui/theme/index.d.ts.map +1 -0
- package/dist/src/tui/theme/index.js +215 -0
- package/dist/src/tui/theme/index.js.map +1 -0
- package/dist/src/tui/types.d.ts +214 -0
- package/dist/src/tui/types.d.ts.map +1 -0
- package/dist/src/tui/types.js +27 -0
- package/dist/src/tui/types.js.map +1 -0
- package/dist/src/types.d.ts +905 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +9 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,1320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Command Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles all slash commands for both REPL and TUI modes.
|
|
5
|
+
* Uses CommandContext.output for all output, making it mode-agnostic.
|
|
6
|
+
*/
|
|
7
|
+
import { persistenceDebug, saveCheckpointToStore, } from '../integrations/persistence.js';
|
|
8
|
+
import { formatServerList, getContextUsage, formatCompactionResult } from '../integrations/index.js';
|
|
9
|
+
import { formatSessionsTable } from '../session-picker.js';
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// ANSI COLOR UTILITIES
|
|
12
|
+
// =============================================================================
|
|
13
|
+
const colors = {
|
|
14
|
+
reset: '\x1b[0m',
|
|
15
|
+
bold: '\x1b[1m',
|
|
16
|
+
dim: '\x1b[2m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
magenta: '\x1b[35m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
white: '\x1b[37m',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Apply ANSI color to text.
|
|
27
|
+
*/
|
|
28
|
+
function c(text, color) {
|
|
29
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
30
|
+
}
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// HELP TEXT
|
|
33
|
+
// =============================================================================
|
|
34
|
+
function getHelpText() {
|
|
35
|
+
return `
|
|
36
|
+
${c('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'dim')}
|
|
37
|
+
${c(' ATTOCODE HELP', 'bold')}
|
|
38
|
+
${c('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'dim')}
|
|
39
|
+
|
|
40
|
+
${c('GENERAL', 'bold')}
|
|
41
|
+
${c('/help', 'cyan')} Show this help (alias: /h, /?)
|
|
42
|
+
${c('/status', 'cyan')} Show session stats, metrics & token usage
|
|
43
|
+
${c('/clear', 'cyan')} Clear the screen
|
|
44
|
+
${c('/reset', 'cyan')} Reset agent state (clears conversation)
|
|
45
|
+
${c('/quit', 'cyan')} Exit attocode (alias: /exit, /q)
|
|
46
|
+
|
|
47
|
+
${c('AGENT MODES', 'bold')}
|
|
48
|
+
${c('/mode', 'cyan')} Show current mode and available modes
|
|
49
|
+
${c('/mode <name>', 'cyan')} Switch to mode (build, plan, review, debug)
|
|
50
|
+
${c('/plan', 'cyan')} Toggle plan mode (writes queued for approval)
|
|
51
|
+
|
|
52
|
+
${c('PLAN APPROVAL (in Plan Mode)', 'bold')}
|
|
53
|
+
${c('/show-plan', 'cyan')} Show pending plan with proposed changes
|
|
54
|
+
${c('/approve', 'cyan')} Approve and execute all pending changes
|
|
55
|
+
${c('/approve <n>', 'cyan')} Approve and execute first n changes only
|
|
56
|
+
${c('/reject', 'cyan')} Reject and discard all pending changes
|
|
57
|
+
|
|
58
|
+
${c('SESSIONS & PERSISTENCE', 'bold')}
|
|
59
|
+
${c('/save', 'cyan')} Save current session to disk
|
|
60
|
+
${c('/load <id>', 'cyan')} Load a previous session by ID
|
|
61
|
+
${c('/sessions', 'cyan')} List all saved sessions with timestamps
|
|
62
|
+
${c('/resume', 'cyan')} Resume most recent session (auto-loads last checkpoint)
|
|
63
|
+
|
|
64
|
+
${c('CONTEXT MANAGEMENT', 'bold')}
|
|
65
|
+
${c('/context', 'cyan')} Show context window usage (tokens used/available)
|
|
66
|
+
${c('/context breakdown', 'cyan')} Detailed token breakdown by category
|
|
67
|
+
${c('/compact', 'cyan')} Summarize & compress context to free tokens
|
|
68
|
+
${c('/compact status', 'cyan')} Check if compaction is recommended
|
|
69
|
+
|
|
70
|
+
${c('CHECKPOINTS & THREADS', 'bold')}
|
|
71
|
+
${c('/checkpoint [label]', 'cyan')} Create a named checkpoint (alias: /cp)
|
|
72
|
+
${c('/checkpoints', 'cyan')} List all checkpoints (alias: /cps)
|
|
73
|
+
${c('/restore <id>', 'cyan')} Restore conversation to a checkpoint
|
|
74
|
+
${c('/rollback [n]', 'cyan')} Rollback n steps (default: 1) (alias: /rb)
|
|
75
|
+
${c('/fork <name>', 'cyan')} Fork conversation into a new thread
|
|
76
|
+
${c('/threads', 'cyan')} List all conversation threads
|
|
77
|
+
${c('/switch <id>', 'cyan')} Switch to a different thread
|
|
78
|
+
|
|
79
|
+
${c('REASONING MODES', 'bold')}
|
|
80
|
+
${c('/react <task>', 'cyan')} Run with ReAct (Reason + Act) pattern
|
|
81
|
+
${c('/team <task>', 'cyan')} Run with multi-agent team coordination
|
|
82
|
+
|
|
83
|
+
${c('SUBAGENTS', 'bold')}
|
|
84
|
+
${c('/agents', 'cyan')} List all available agents with descriptions
|
|
85
|
+
${c('/spawn <agent> <task>', 'cyan')} Spawn a specific agent to handle task
|
|
86
|
+
${c('/find <query>', 'cyan')} Find agents by keyword search
|
|
87
|
+
${c('/suggest <task>', 'cyan')} AI-powered agent suggestion for task
|
|
88
|
+
${c('/auto <task>', 'cyan')} Auto-route task to best agent
|
|
89
|
+
|
|
90
|
+
${c('MCP INTEGRATION', 'bold')}
|
|
91
|
+
${c('/mcp', 'cyan')} List MCP servers and connection status
|
|
92
|
+
${c('/mcp connect <name>', 'cyan')} Connect to an MCP server
|
|
93
|
+
${c('/mcp disconnect <name>', 'cyan')} Disconnect from server
|
|
94
|
+
${c('/mcp tools', 'cyan')} List all available MCP tools
|
|
95
|
+
${c('/mcp search <query>', 'cyan')} Search & lazy-load MCP tools
|
|
96
|
+
${c('/mcp stats', 'cyan')} Show MCP context usage statistics
|
|
97
|
+
|
|
98
|
+
${c('BUDGET & ECONOMICS', 'bold')}
|
|
99
|
+
${c('/budget', 'cyan')} Show token/cost budget and usage
|
|
100
|
+
${c('/extend <type> <n>', 'cyan')} Extend budget limit
|
|
101
|
+
|
|
102
|
+
${c('PERMISSIONS & SECURITY', 'bold')}
|
|
103
|
+
${c('/grants', 'cyan')} Show active permission grants
|
|
104
|
+
${c('/audit', 'cyan')} Show security audit log
|
|
105
|
+
|
|
106
|
+
${c('DEBUGGING & TESTING', 'bold')}
|
|
107
|
+
${c('/skills', 'cyan')} List loaded skills
|
|
108
|
+
${c('/sandbox', 'cyan')} Show sandbox modes available
|
|
109
|
+
${c('/shell', 'cyan')} Show PTY shell integration info
|
|
110
|
+
${c('/lsp', 'cyan')} Show LSP integration status
|
|
111
|
+
${c('/tui', 'cyan')} Show TUI features & capabilities
|
|
112
|
+
|
|
113
|
+
${c('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'dim')}
|
|
114
|
+
${c('SHORTCUTS', 'bold')}
|
|
115
|
+
${c('Ctrl+C', 'yellow')} Exit ${c('Ctrl+L', 'yellow')} Clear screen
|
|
116
|
+
${c('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'dim')}
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// MAIN COMMAND HANDLER
|
|
121
|
+
// =============================================================================
|
|
122
|
+
/**
|
|
123
|
+
* Handle a slash command.
|
|
124
|
+
*
|
|
125
|
+
* @param cmd - Command string (with leading slash)
|
|
126
|
+
* @param args - Command arguments
|
|
127
|
+
* @param ctx - Command context with agent, output, integrations
|
|
128
|
+
* @returns 'quit' to exit, void otherwise
|
|
129
|
+
*/
|
|
130
|
+
export async function handleCommand(cmd, args, ctx) {
|
|
131
|
+
const { agent, sessionId, output, integrations } = ctx;
|
|
132
|
+
const { sessionStore, mcpClient, compactor } = integrations;
|
|
133
|
+
switch (cmd) {
|
|
134
|
+
// =========================================================================
|
|
135
|
+
// GENERAL COMMANDS
|
|
136
|
+
// =========================================================================
|
|
137
|
+
case '/quit':
|
|
138
|
+
case '/exit':
|
|
139
|
+
case '/q':
|
|
140
|
+
return 'quit';
|
|
141
|
+
case '/help':
|
|
142
|
+
case '/h':
|
|
143
|
+
case '/?':
|
|
144
|
+
output.log(getHelpText());
|
|
145
|
+
break;
|
|
146
|
+
case '/status': {
|
|
147
|
+
const metrics = agent.getMetrics();
|
|
148
|
+
const state = agent.getState();
|
|
149
|
+
// Get goals summary if SQLite store
|
|
150
|
+
let goalsSummary = '';
|
|
151
|
+
if ('listActiveGoals' in sessionStore) {
|
|
152
|
+
const sqlStore = sessionStore;
|
|
153
|
+
const activeGoals = sqlStore.listActiveGoals();
|
|
154
|
+
if (activeGoals.length > 0) {
|
|
155
|
+
let totalCurrent = 0;
|
|
156
|
+
let totalExpected = 0;
|
|
157
|
+
const goalLines = [];
|
|
158
|
+
for (const goal of activeGoals) {
|
|
159
|
+
if (goal.progressTotal) {
|
|
160
|
+
totalCurrent += goal.progressCurrent;
|
|
161
|
+
totalExpected += goal.progressTotal;
|
|
162
|
+
const pct = Math.round((goal.progressCurrent / goal.progressTotal) * 100);
|
|
163
|
+
goalLines.push(` - ${goal.goalText} (${goal.progressCurrent}/${goal.progressTotal} - ${pct}%)`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
goalLines.push(` - ${goal.goalText}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
goalsSummary = `\n${c('Active Goals:', 'bold')} (${activeGoals.length})`;
|
|
170
|
+
if (totalExpected > 0) {
|
|
171
|
+
const overallPct = Math.round((totalCurrent / totalExpected) * 100);
|
|
172
|
+
goalsSummary += c(` [Overall: ${overallPct}%]`, 'cyan');
|
|
173
|
+
}
|
|
174
|
+
goalsSummary += '\n' + goalLines.slice(0, 5).join('\n');
|
|
175
|
+
if (activeGoals.length > 5) {
|
|
176
|
+
goalsSummary += c(`\n ... and ${activeGoals.length - 5} more`, 'dim');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
output.log(`
|
|
181
|
+
${c('Session Status:', 'bold')}
|
|
182
|
+
Session ID: ${sessionId}
|
|
183
|
+
Status: ${state.status}
|
|
184
|
+
Iteration: ${state.iteration}
|
|
185
|
+
Messages: ${state.messages.length}
|
|
186
|
+
|
|
187
|
+
${c('Token Usage:', 'bold')}
|
|
188
|
+
Input tokens: ${metrics.inputTokens.toLocaleString()}
|
|
189
|
+
Output tokens: ${metrics.outputTokens.toLocaleString()}
|
|
190
|
+
Total tokens: ${metrics.totalTokens.toLocaleString()}
|
|
191
|
+
|
|
192
|
+
${c('Activity:', 'bold')}
|
|
193
|
+
LLM calls: ${metrics.llmCalls}
|
|
194
|
+
Tool calls: ${metrics.toolCalls}
|
|
195
|
+
Duration: ${metrics.duration}ms
|
|
196
|
+
Est. Cost: $${metrics.estimatedCost.toFixed(4)}
|
|
197
|
+
${goalsSummary}`);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case '/clear':
|
|
201
|
+
output.clear();
|
|
202
|
+
output.log(c(`Production Agent - Session: ${sessionId}`, 'cyan'));
|
|
203
|
+
break;
|
|
204
|
+
case '/reset':
|
|
205
|
+
agent.reset();
|
|
206
|
+
output.log(c('+ Agent state reset', 'green'));
|
|
207
|
+
break;
|
|
208
|
+
// =========================================================================
|
|
209
|
+
// MODE MANAGEMENT
|
|
210
|
+
// =========================================================================
|
|
211
|
+
case '/mode': {
|
|
212
|
+
if (args.length === 0) {
|
|
213
|
+
const modeInfo = agent.getModeInfo();
|
|
214
|
+
const hasPlan = agent.hasPendingPlan();
|
|
215
|
+
const pendingCount = agent.getPendingChangeCount();
|
|
216
|
+
output.log(`
|
|
217
|
+
${c('Current Mode:', 'bold')} ${modeInfo.color}${modeInfo.icon} ${modeInfo.name}\x1b[0m
|
|
218
|
+
${hasPlan ? c(` Pending Plan: ${pendingCount} change(s) awaiting approval`, 'yellow') : ''}
|
|
219
|
+
|
|
220
|
+
${agent.getAvailableModes()}
|
|
221
|
+
|
|
222
|
+
${c('Usage:', 'dim')} /mode <name> to switch, /plan to toggle plan mode`);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const newMode = args[0].toLowerCase();
|
|
226
|
+
agent.setMode(newMode);
|
|
227
|
+
const modeInfo = agent.getModeInfo();
|
|
228
|
+
output.log(`${c('Mode changed to:', 'green')} ${modeInfo.color}${modeInfo.icon} ${modeInfo.name}\x1b[0m`);
|
|
229
|
+
if (newMode !== 'plan' && agent.hasPendingPlan()) {
|
|
230
|
+
output.log(c('Warning: You have a pending plan. Use /show-plan to view, /approve or /reject to resolve.', 'yellow'));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case '/plan': {
|
|
236
|
+
const newMode = agent.togglePlanMode();
|
|
237
|
+
const modeInfo = agent.getModeInfo();
|
|
238
|
+
output.log(`${c('Mode toggled to:', 'green')} ${modeInfo.color}${modeInfo.icon} ${modeInfo.name}\x1b[0m`);
|
|
239
|
+
if (newMode === 'plan') {
|
|
240
|
+
output.log(c(`
|
|
241
|
+
In Plan Mode:
|
|
242
|
+
- You can explore the codebase and use all tools
|
|
243
|
+
- Write operations will be QUEUED for approval
|
|
244
|
+
- Use /show-plan to see queued changes
|
|
245
|
+
- Use /approve to execute, /reject to discard
|
|
246
|
+
`, 'dim'));
|
|
247
|
+
}
|
|
248
|
+
else if (agent.hasPendingPlan()) {
|
|
249
|
+
output.log(c('Note: You have a pending plan. Use /show-plan, /approve, or /reject.', 'yellow'));
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
// =========================================================================
|
|
254
|
+
// PLAN APPROVAL COMMANDS
|
|
255
|
+
// =========================================================================
|
|
256
|
+
case '/show-plan': {
|
|
257
|
+
if (!agent.hasPendingPlan()) {
|
|
258
|
+
output.log(c('No pending plan. Enter plan mode with /plan and make requests that would modify files.', 'dim'));
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
output.log(`\n${agent.formatPendingPlan()}`);
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case '/approve': {
|
|
266
|
+
if (!agent.hasPendingPlan()) {
|
|
267
|
+
output.log(c('No pending plan to approve.', 'dim'));
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
const count = args[0] ? parseInt(args[0], 10) : undefined;
|
|
271
|
+
if (args[0] && (isNaN(count) || count < 1)) {
|
|
272
|
+
output.log(c('Invalid count. Use /approve or /approve <number>', 'red'));
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
const pendingCount = agent.getPendingChangeCount();
|
|
276
|
+
const toApprove = count ?? pendingCount;
|
|
277
|
+
output.log(c(`Approving ${toApprove} of ${pendingCount} change(s)...`, 'yellow'));
|
|
278
|
+
const result = await agent.approvePlan(count);
|
|
279
|
+
if (result.success) {
|
|
280
|
+
output.log(c(`\n+ Successfully executed ${result.executed} change(s)`, 'green'));
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
output.log(c(`\n! Executed ${result.executed} change(s) with ${result.errors.length} error(s):`, 'yellow'));
|
|
284
|
+
for (const err of result.errors) {
|
|
285
|
+
output.log(c(` - ${err}`, 'red'));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (agent.getMode() === 'plan') {
|
|
289
|
+
agent.setMode('build');
|
|
290
|
+
output.log(c('\nSwitched to Build mode.', 'dim'));
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
case '/reject': {
|
|
295
|
+
if (!agent.hasPendingPlan()) {
|
|
296
|
+
output.log(c('No pending plan to reject.', 'dim'));
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
const pendingCount = agent.getPendingChangeCount();
|
|
300
|
+
agent.rejectPlan();
|
|
301
|
+
output.log(c(`x Rejected plan with ${pendingCount} change(s). All proposed changes discarded.`, 'yellow'));
|
|
302
|
+
if (agent.getMode() === 'plan') {
|
|
303
|
+
agent.setMode('build');
|
|
304
|
+
output.log(c('Switched to Build mode.', 'dim'));
|
|
305
|
+
}
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
// =========================================================================
|
|
309
|
+
// GOALS
|
|
310
|
+
// =========================================================================
|
|
311
|
+
case '/goals':
|
|
312
|
+
if ('listActiveGoals' in sessionStore) {
|
|
313
|
+
const sqliteStore = sessionStore;
|
|
314
|
+
const subCmd = args[0]?.toLowerCase();
|
|
315
|
+
if (!subCmd || subCmd === 'list') {
|
|
316
|
+
const goals = sqliteStore.listActiveGoals();
|
|
317
|
+
if (goals.length === 0) {
|
|
318
|
+
output.log(c('No active goals. Use /goals add <text> to create one.', 'dim'));
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
output.log(c('\nActive Goals:', 'bold'));
|
|
322
|
+
for (const goal of goals) {
|
|
323
|
+
const progress = goal.progressTotal
|
|
324
|
+
? ` (${goal.progressCurrent}/${goal.progressTotal})`
|
|
325
|
+
: '';
|
|
326
|
+
const priority = goal.priority === 1 ? c(' [HIGH]', 'red') :
|
|
327
|
+
goal.priority === 3 ? c(' [low]', 'dim') : '';
|
|
328
|
+
output.log(` - ${goal.goalText}${progress}${priority}`);
|
|
329
|
+
output.log(c(` ID: ${goal.id}`, 'dim'));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else if (subCmd === 'add' && args.length > 1) {
|
|
334
|
+
const goalText = args.slice(1).join(' ');
|
|
335
|
+
const goalId = sqliteStore.createGoal(goalText);
|
|
336
|
+
output.log(c(`+ Goal created: ${goalId}`, 'green'));
|
|
337
|
+
}
|
|
338
|
+
else if (subCmd === 'done' && args[1]) {
|
|
339
|
+
sqliteStore.completeGoal(args[1]);
|
|
340
|
+
output.log(c(`+ Goal completed: ${args[1]}`, 'green'));
|
|
341
|
+
}
|
|
342
|
+
else if (subCmd === 'progress' && args[1] && args[2] && args[3]) {
|
|
343
|
+
sqliteStore.updateGoal(args[1], {
|
|
344
|
+
progressCurrent: parseInt(args[2], 10),
|
|
345
|
+
progressTotal: parseInt(args[3], 10),
|
|
346
|
+
});
|
|
347
|
+
output.log(c(`+ Progress updated: ${args[2]}/${args[3]}`, 'green'));
|
|
348
|
+
}
|
|
349
|
+
else if (subCmd === 'all') {
|
|
350
|
+
const goals = sqliteStore.listGoals();
|
|
351
|
+
output.log(c('\nAll Goals:', 'bold'));
|
|
352
|
+
for (const goal of goals) {
|
|
353
|
+
const status = goal.status === 'completed' ? c('+', 'green') :
|
|
354
|
+
goal.status === 'abandoned' ? c('x', 'red') : ' ';
|
|
355
|
+
output.log(` ${status} ${goal.goalText} [${goal.status}]`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else if (subCmd === 'junctures') {
|
|
359
|
+
const junctures = sqliteStore.listJunctures(undefined, 10);
|
|
360
|
+
if (junctures.length === 0) {
|
|
361
|
+
output.log(c('No junctures logged yet.', 'dim'));
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
output.log(c('\nRecent Key Moments:', 'bold'));
|
|
365
|
+
for (const j of junctures) {
|
|
366
|
+
const icon = j.type === 'failure' ? c('x', 'red') :
|
|
367
|
+
j.type === 'breakthrough' ? c('*', 'yellow') :
|
|
368
|
+
j.type === 'decision' ? c('>', 'cyan') : c('~', 'magenta');
|
|
369
|
+
output.log(` ${icon} [${j.type}] ${j.description}`);
|
|
370
|
+
if (j.outcome)
|
|
371
|
+
output.log(c(` -> ${j.outcome}`, 'dim'));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
output.log(c('Usage:', 'bold'));
|
|
377
|
+
output.log(c(' /goals - List active goals', 'dim'));
|
|
378
|
+
output.log(c(' /goals add <text> - Create a new goal', 'dim'));
|
|
379
|
+
output.log(c(' /goals done <id> - Mark goal as completed', 'dim'));
|
|
380
|
+
output.log(c(' /goals progress <id> <current> <total> - Update progress', 'dim'));
|
|
381
|
+
output.log(c(' /goals all - List all goals (including completed)', 'dim'));
|
|
382
|
+
output.log(c(' /goals junctures - Show recent key moments', 'dim'));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
output.log(c('Goals require SQLite store (not available with JSONL fallback)', 'yellow'));
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
case '/handoff':
|
|
390
|
+
if ('exportSessionManifest' in sessionStore) {
|
|
391
|
+
const sqliteStore = sessionStore;
|
|
392
|
+
const format = args[0]?.toLowerCase() || 'markdown';
|
|
393
|
+
if (format === 'json') {
|
|
394
|
+
const manifest = sqliteStore.exportSessionManifest();
|
|
395
|
+
if (manifest) {
|
|
396
|
+
output.log(JSON.stringify(manifest, null, 2));
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
output.log(c('No active session to export', 'yellow'));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
const markdown = sqliteStore.exportSessionMarkdown();
|
|
404
|
+
output.log(markdown);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
output.log(c('Handoff requires SQLite store (not available with JSONL fallback)', 'yellow'));
|
|
409
|
+
}
|
|
410
|
+
break;
|
|
411
|
+
// =========================================================================
|
|
412
|
+
// REASONING MODES
|
|
413
|
+
// =========================================================================
|
|
414
|
+
case '/react':
|
|
415
|
+
if (args.length === 0) {
|
|
416
|
+
output.log(c('Usage: /react <task>', 'yellow'));
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const task = args.join(' ');
|
|
420
|
+
output.log(c(`\nRunning with ReAct pattern: ${task}`, 'cyan'));
|
|
421
|
+
try {
|
|
422
|
+
const trace = await agent.runWithReAct(task);
|
|
423
|
+
output.log(c('\n--- ReAct Trace ---', 'magenta'));
|
|
424
|
+
output.log(agent.formatReActTrace(trace));
|
|
425
|
+
output.log(c('-------------------', 'magenta'));
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
case '/team':
|
|
433
|
+
if (args.length === 0) {
|
|
434
|
+
output.log(c('Usage: /team <task>', 'yellow'));
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
const task = args.join(' ');
|
|
438
|
+
output.log(c(`\nRunning with team: ${task}`, 'cyan'));
|
|
439
|
+
try {
|
|
440
|
+
const { CODER_ROLE, REVIEWER_ROLE, RESEARCHER_ROLE } = await import('../integrations/multi-agent.js');
|
|
441
|
+
const result = await agent.runWithTeam({ id: `team-${Date.now()}`, goal: task, context: '' }, [RESEARCHER_ROLE, CODER_ROLE, REVIEWER_ROLE]);
|
|
442
|
+
output.log(c('\n--- Team Result ---', 'magenta'));
|
|
443
|
+
output.log(`Success: ${result.success}`);
|
|
444
|
+
output.log(`Coordinator: ${result.coordinator}`);
|
|
445
|
+
if (result.consensus) {
|
|
446
|
+
output.log(`Consensus: ${result.consensus.agreed ? 'Agreed' : 'Disagreed'} - ${result.consensus.result}`);
|
|
447
|
+
}
|
|
448
|
+
output.log(c('-------------------', 'magenta'));
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
break;
|
|
455
|
+
// =========================================================================
|
|
456
|
+
// CHECKPOINTS & THREADS
|
|
457
|
+
// =========================================================================
|
|
458
|
+
case '/checkpoint':
|
|
459
|
+
case '/cp':
|
|
460
|
+
try {
|
|
461
|
+
const label = args.length > 0 ? args.join(' ') : undefined;
|
|
462
|
+
const checkpoint = agent.createCheckpoint(label);
|
|
463
|
+
output.log(c(`+ Checkpoint created: ${checkpoint.id}${label ? ` (${label})` : ''}`, 'green'));
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
467
|
+
}
|
|
468
|
+
break;
|
|
469
|
+
case '/checkpoints':
|
|
470
|
+
case '/cps':
|
|
471
|
+
try {
|
|
472
|
+
const checkpoints = agent.getCheckpoints();
|
|
473
|
+
if (checkpoints.length === 0) {
|
|
474
|
+
output.log(c('No checkpoints.', 'dim'));
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
output.log(c('\nCheckpoints:', 'bold'));
|
|
478
|
+
checkpoints.forEach(cp => {
|
|
479
|
+
output.log(` ${c(cp.id, 'cyan')}${cp.label ? ` - ${cp.label}` : ''}`);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
485
|
+
}
|
|
486
|
+
break;
|
|
487
|
+
case '/restore':
|
|
488
|
+
if (args.length === 0) {
|
|
489
|
+
output.log(c('Usage: /restore <checkpoint-id>', 'yellow'));
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
const success = agent.restoreCheckpoint(args[0]);
|
|
493
|
+
output.log(success ? c(`+ Restored: ${args[0]}`, 'green') : c(`x Not found: ${args[0]}`, 'red'));
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
case '/rollback':
|
|
497
|
+
case '/rb': {
|
|
498
|
+
const steps = args.length > 0 ? parseInt(args[0], 10) : 1;
|
|
499
|
+
if (isNaN(steps) || steps < 1) {
|
|
500
|
+
output.log(c('Usage: /rollback <steps>', 'yellow'));
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
const success = agent.rollback(steps);
|
|
504
|
+
output.log(success ? c(`+ Rolled back ${steps} steps`, 'green') : c('x Rollback failed', 'red'));
|
|
505
|
+
}
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
case '/fork':
|
|
509
|
+
if (args.length === 0) {
|
|
510
|
+
output.log(c('Usage: /fork <name>', 'yellow'));
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
try {
|
|
514
|
+
const threadId = agent.fork(args.join(' '));
|
|
515
|
+
output.log(c(`+ Forked: ${threadId}`, 'green'));
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
case '/threads':
|
|
523
|
+
try {
|
|
524
|
+
const threads = agent.getAllThreads();
|
|
525
|
+
if (threads.length === 0) {
|
|
526
|
+
output.log(c('No threads.', 'dim'));
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
output.log(c('\nThreads:', 'bold'));
|
|
530
|
+
threads.forEach((t) => {
|
|
531
|
+
output.log(` ${c(t.id, 'cyan')}${t.name ? ` - ${t.name}` : ''} (${t.messages?.length || 0} messages)`);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
537
|
+
}
|
|
538
|
+
break;
|
|
539
|
+
case '/switch':
|
|
540
|
+
if (args.length === 0) {
|
|
541
|
+
output.log(c('Usage: /switch <thread-id>', 'yellow'));
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
const success = agent.switchThread(args[0]);
|
|
545
|
+
output.log(success ? c(`+ Switched to: ${args[0]}`, 'green') : c(`x Not found: ${args[0]}`, 'red'));
|
|
546
|
+
}
|
|
547
|
+
break;
|
|
548
|
+
// =========================================================================
|
|
549
|
+
// SECURITY
|
|
550
|
+
// =========================================================================
|
|
551
|
+
case '/grants':
|
|
552
|
+
try {
|
|
553
|
+
const grants = agent.getActiveGrants();
|
|
554
|
+
if (grants.length === 0) {
|
|
555
|
+
output.log(c('No active permission grants.', 'dim'));
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
output.log(c('\nActive Grants:', 'bold'));
|
|
559
|
+
grants.forEach((g) => {
|
|
560
|
+
output.log(` ${c(g.id, 'cyan')} - ${g.toolName} (${g.grantedBy})`);
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
566
|
+
}
|
|
567
|
+
break;
|
|
568
|
+
case '/audit':
|
|
569
|
+
try {
|
|
570
|
+
const log = agent.getAuditLog();
|
|
571
|
+
if (log.length === 0) {
|
|
572
|
+
output.log(c('No audit entries.', 'dim'));
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
output.log(c('\nAudit Log:', 'bold'));
|
|
576
|
+
log.slice(-10).forEach((entry) => {
|
|
577
|
+
const status = entry.approved ? c('+', 'green') : c('x', 'red');
|
|
578
|
+
output.log(` ${status} ${entry.action} - ${entry.tool || 'n/a'}`);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
catch (error) {
|
|
583
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
584
|
+
}
|
|
585
|
+
break;
|
|
586
|
+
// =========================================================================
|
|
587
|
+
// BUDGET
|
|
588
|
+
// =========================================================================
|
|
589
|
+
case '/budget':
|
|
590
|
+
try {
|
|
591
|
+
const usage = agent.getBudgetUsage();
|
|
592
|
+
const limits = agent.getBudgetLimits();
|
|
593
|
+
const progress = agent.getProgress();
|
|
594
|
+
if (!usage || !limits) {
|
|
595
|
+
output.log(c('Economics not available.', 'dim'));
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
output.log(`
|
|
599
|
+
${c('Budget Usage:', 'bold')}
|
|
600
|
+
Tokens: ${usage.tokens.toLocaleString()} / ${limits.maxTokens.toLocaleString()} (${usage.percentUsed.toFixed(1)}%)
|
|
601
|
+
Cost: $${usage.cost.toFixed(4)} / $${limits.maxCost.toFixed(2)}
|
|
602
|
+
Duration: ${Math.round(usage.duration / 1000)}s / ${Math.round(limits.maxDuration / 1000)}s
|
|
603
|
+
Iterations: ${usage.iterations} / ${limits.maxIterations}
|
|
604
|
+
|
|
605
|
+
${c('Progress:', 'bold')}
|
|
606
|
+
Files read: ${progress?.filesRead || 0}
|
|
607
|
+
Files modified: ${progress?.filesModified || 0}
|
|
608
|
+
Commands run: ${progress?.commandsRun || 0}
|
|
609
|
+
Status: ${progress?.isStuck ? c('STUCK', 'red') : c('Active', 'green')}
|
|
610
|
+
`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
615
|
+
}
|
|
616
|
+
break;
|
|
617
|
+
case '/extend':
|
|
618
|
+
if (args.length === 0) {
|
|
619
|
+
output.log(c('Usage: /extend <tokens|cost|time> <amount>', 'yellow'));
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
const [what, amount] = args;
|
|
623
|
+
const value = parseFloat(amount);
|
|
624
|
+
if (isNaN(value)) {
|
|
625
|
+
output.log(c('Invalid amount', 'red'));
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
const limits = agent.getBudgetLimits();
|
|
629
|
+
if (!limits) {
|
|
630
|
+
output.log(c('Economics not available', 'dim'));
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
switch (what) {
|
|
634
|
+
case 'tokens':
|
|
635
|
+
agent.extendBudget({ maxTokens: limits.maxTokens + value });
|
|
636
|
+
output.log(c(`+ Token budget extended to ${(limits.maxTokens + value).toLocaleString()}`, 'green'));
|
|
637
|
+
break;
|
|
638
|
+
case 'cost':
|
|
639
|
+
agent.extendBudget({ maxCost: limits.maxCost + value });
|
|
640
|
+
output.log(c(`+ Cost budget extended to $${(limits.maxCost + value).toFixed(2)}`, 'green'));
|
|
641
|
+
break;
|
|
642
|
+
case 'time':
|
|
643
|
+
agent.extendBudget({ maxDuration: limits.maxDuration + value * 1000 });
|
|
644
|
+
output.log(c(`+ Time budget extended to ${Math.round((limits.maxDuration + value * 1000) / 1000)}s`, 'green'));
|
|
645
|
+
break;
|
|
646
|
+
default:
|
|
647
|
+
output.log(c('Unknown budget type. Use: tokens, cost, or time', 'yellow'));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
break;
|
|
653
|
+
// =========================================================================
|
|
654
|
+
// SUBAGENTS
|
|
655
|
+
// =========================================================================
|
|
656
|
+
case '/agents':
|
|
657
|
+
try {
|
|
658
|
+
const agentList = agent.formatAgentList();
|
|
659
|
+
output.log(c('\nAvailable Agents:', 'bold'));
|
|
660
|
+
output.log(agentList);
|
|
661
|
+
}
|
|
662
|
+
catch (error) {
|
|
663
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
664
|
+
}
|
|
665
|
+
break;
|
|
666
|
+
case '/spawn':
|
|
667
|
+
if (args.length < 2) {
|
|
668
|
+
output.log(c('Usage: /spawn <agent-name> <task>', 'yellow'));
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
const agentName = args[0];
|
|
672
|
+
const task = args.slice(1).join(' ');
|
|
673
|
+
output.log(c(`\nSpawning ${agentName}: ${task}`, 'cyan'));
|
|
674
|
+
try {
|
|
675
|
+
const result = await agent.spawnAgent(agentName, task);
|
|
676
|
+
output.log(c('\n--- Agent Result ---', 'magenta'));
|
|
677
|
+
output.log(`Success: ${result.success}`);
|
|
678
|
+
output.log(`Output: ${result.output}`);
|
|
679
|
+
output.log(c(`\nTokens: ${result.metrics.tokens} | Tools: ${result.metrics.toolCalls} | Duration: ${result.metrics.duration}ms`, 'dim'));
|
|
680
|
+
output.log(c('--------------------', 'magenta'));
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
break;
|
|
687
|
+
case '/find':
|
|
688
|
+
if (args.length === 0) {
|
|
689
|
+
output.log(c('Usage: /find <query>', 'yellow'));
|
|
690
|
+
}
|
|
691
|
+
else {
|
|
692
|
+
const query = args.join(' ');
|
|
693
|
+
output.log(c(`\nFinding agents for: "${query}"`, 'cyan'));
|
|
694
|
+
const matches = agent.findAgentsForTask(query);
|
|
695
|
+
if (matches.length === 0) {
|
|
696
|
+
output.log(c('No matching agents found.', 'dim'));
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
output.log(c('\nMatching Agents:', 'bold'));
|
|
700
|
+
matches.forEach((a, i) => {
|
|
701
|
+
output.log(` ${i + 1}. ${c(a.name, 'cyan')} (${a.source})`);
|
|
702
|
+
output.log(` ${a.description.split('.')[0]}`);
|
|
703
|
+
if (a.capabilities?.length) {
|
|
704
|
+
output.log(c(` Capabilities: ${a.capabilities.join(', ')}`, 'dim'));
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
output.log(c('\nUse /spawn <agent-name> <task> to run an agent.', 'dim'));
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
break;
|
|
711
|
+
case '/suggest':
|
|
712
|
+
if (args.length === 0) {
|
|
713
|
+
output.log(c('Usage: /suggest <task description>', 'yellow'));
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
const taskDesc = args.join(' ');
|
|
717
|
+
output.log(c(`\nAnalyzing task: "${taskDesc}"`, 'cyan'));
|
|
718
|
+
try {
|
|
719
|
+
const { suggestions, shouldDelegate, delegateAgent } = await agent.suggestAgentForTask(taskDesc);
|
|
720
|
+
if (suggestions.length === 0) {
|
|
721
|
+
output.log(c('\nNo specialized agent recommended. Main agent should handle this task.', 'dim'));
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
output.log(c('\nAgent Suggestions:', 'bold'));
|
|
725
|
+
suggestions.forEach((s, i) => {
|
|
726
|
+
const confidenceBar = '='.repeat(Math.round(s.confidence * 10)) + '-'.repeat(10 - Math.round(s.confidence * 10));
|
|
727
|
+
output.log(` ${i + 1}. ${c(s.agent.name, 'cyan')} [${confidenceBar}] ${(s.confidence * 100).toFixed(0)}%`);
|
|
728
|
+
output.log(` ${s.reason}`);
|
|
729
|
+
});
|
|
730
|
+
if (shouldDelegate && delegateAgent) {
|
|
731
|
+
output.log(c(`\nRecommendation: Delegate to "${delegateAgent}"`, 'green'));
|
|
732
|
+
output.log(c(` Run: /spawn ${delegateAgent} ${taskDesc}`, 'dim'));
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
output.log(c('\nRecommendation: Main agent should handle this task.', 'dim'));
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
catch (error) {
|
|
740
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
break;
|
|
744
|
+
case '/auto':
|
|
745
|
+
if (args.length === 0) {
|
|
746
|
+
output.log(c('Usage: /auto <task>', 'yellow'));
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
const autoTask = args.join(' ');
|
|
750
|
+
output.log(c(`\nAuto-routing: "${autoTask}"`, 'cyan'));
|
|
751
|
+
try {
|
|
752
|
+
// Create a confirmation callback
|
|
753
|
+
const confirmDelegate = async (suggestedAgent, reason) => {
|
|
754
|
+
output.log(c(`\nSuggested agent: ${suggestedAgent.name}`, 'yellow'));
|
|
755
|
+
output.log(c(` Reason: ${reason}`, 'dim'));
|
|
756
|
+
if (ctx.confirm) {
|
|
757
|
+
return ctx.confirm('Delegate to this agent?');
|
|
758
|
+
}
|
|
759
|
+
if (ctx.rl) {
|
|
760
|
+
const answer = await ctx.rl.question(c(' Delegate to this agent? (y/n): ', 'yellow'));
|
|
761
|
+
return answer.toLowerCase().startsWith('y');
|
|
762
|
+
}
|
|
763
|
+
return false;
|
|
764
|
+
};
|
|
765
|
+
const result = await agent.runWithAutoRouting(autoTask, {
|
|
766
|
+
confidenceThreshold: 0.75,
|
|
767
|
+
confirmDelegate,
|
|
768
|
+
});
|
|
769
|
+
if ('output' in result) {
|
|
770
|
+
output.log(c('\n--- Subagent Result ---', 'magenta'));
|
|
771
|
+
output.log(`Success: ${result.success}`);
|
|
772
|
+
output.log(result.output);
|
|
773
|
+
output.log(c(`\nTokens: ${result.metrics.tokens} | Duration: ${result.metrics.duration}ms`, 'dim'));
|
|
774
|
+
output.log(c('-----------------------', 'magenta'));
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
output.log(c('\n--- Assistant ---', 'magenta'));
|
|
778
|
+
output.log(result.response);
|
|
779
|
+
output.log(c('-----------------', 'magenta'));
|
|
780
|
+
output.log(c(`\nTokens: ${result.metrics.inputTokens} in / ${result.metrics.outputTokens} out | Tools: ${result.metrics.toolCalls}`, 'dim'));
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
catch (error) {
|
|
784
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
break;
|
|
788
|
+
// =========================================================================
|
|
789
|
+
// MCP INTEGRATION
|
|
790
|
+
// =========================================================================
|
|
791
|
+
case '/mcp':
|
|
792
|
+
if (args.length === 0) {
|
|
793
|
+
const servers = mcpClient.listServers();
|
|
794
|
+
output.log(formatServerList(servers));
|
|
795
|
+
}
|
|
796
|
+
else if (args[0] === 'connect' && args[1]) {
|
|
797
|
+
output.log(c(`Connecting to ${args[1]}...`, 'cyan'));
|
|
798
|
+
try {
|
|
799
|
+
await mcpClient.connectServer(args[1]);
|
|
800
|
+
output.log(c(`+ Connected to ${args[1]}`, 'green'));
|
|
801
|
+
const tools = mcpClient.getAllTools();
|
|
802
|
+
for (const tool of tools) {
|
|
803
|
+
agent.addTool(tool);
|
|
804
|
+
}
|
|
805
|
+
output.log(c(` Added ${tools.length} tools from MCP servers`, 'dim'));
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
else if (args[0] === 'disconnect' && args[1]) {
|
|
812
|
+
await mcpClient.disconnectServer(args[1]);
|
|
813
|
+
output.log(c(`+ Disconnected from ${args[1]}`, 'green'));
|
|
814
|
+
}
|
|
815
|
+
else if (args[0] === 'tools') {
|
|
816
|
+
const tools = mcpClient.getAllTools();
|
|
817
|
+
if (tools.length === 0) {
|
|
818
|
+
output.log(c('No MCP tools available.', 'dim'));
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
output.log(c('\nMCP Tools:', 'bold'));
|
|
822
|
+
tools.forEach(t => {
|
|
823
|
+
const loaded = mcpClient.isToolLoaded(t.name);
|
|
824
|
+
const status = loaded ? c('+', 'green') : c('o', 'dim');
|
|
825
|
+
output.log(` ${status} ${c(t.name, 'cyan')} - ${t.description?.slice(0, 60) || 'No description'}...`);
|
|
826
|
+
});
|
|
827
|
+
const stats = mcpClient.getContextStats();
|
|
828
|
+
output.log(c(`\n Legend: + = full schema loaded, o = summary only`, 'dim'));
|
|
829
|
+
output.log(c(` Loaded: ${stats.loadedCount}/${stats.totalTools} tools`, 'dim'));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
else if (args[0] === 'search') {
|
|
833
|
+
const query = args.slice(1).join(' ');
|
|
834
|
+
if (!query) {
|
|
835
|
+
output.log(c('Usage: /mcp search <query>', 'yellow'));
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
output.log(c(`Searching for: "${query}"...`, 'cyan'));
|
|
839
|
+
const results = mcpClient.searchTools(query, { limit: 10 });
|
|
840
|
+
if (results.length === 0) {
|
|
841
|
+
output.log(c('No matching tools found.', 'dim'));
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
output.log(c(`\nFound ${results.length} tool(s):`, 'bold'));
|
|
845
|
+
results.forEach(r => {
|
|
846
|
+
output.log(` ${c(r.name, 'cyan')} (${r.serverName})`);
|
|
847
|
+
output.log(` ${r.description}`);
|
|
848
|
+
});
|
|
849
|
+
const loadedTools = mcpClient.loadTools(results.map(r => r.name));
|
|
850
|
+
for (const tool of loadedTools) {
|
|
851
|
+
agent.addTool(tool);
|
|
852
|
+
}
|
|
853
|
+
output.log(c(`\n+ Loaded ${loadedTools.length} tool(s). They are now available for use.`, 'green'));
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
else if (args[0] === 'stats') {
|
|
858
|
+
const stats = mcpClient.getContextStats();
|
|
859
|
+
const fullLoadEstimate = stats.totalTools * 200;
|
|
860
|
+
const currentTokens = stats.summaryTokens + stats.definitionTokens;
|
|
861
|
+
const savingsPercent = fullLoadEstimate > 0
|
|
862
|
+
? Math.round((1 - currentTokens / fullLoadEstimate) * 100)
|
|
863
|
+
: 0;
|
|
864
|
+
output.log(`
|
|
865
|
+
${c('MCP Context Usage:', 'bold')}
|
|
866
|
+
Tool summaries: ${stats.summaryCount.toString().padStart(3)} tools (~${stats.summaryTokens.toLocaleString()} tokens)
|
|
867
|
+
Full definitions: ${stats.loadedCount.toString().padStart(3)} tools (~${stats.definitionTokens.toLocaleString()} tokens)
|
|
868
|
+
Total: ${stats.totalTools.toString().padStart(3)} tools (~${currentTokens.toLocaleString()} tokens)
|
|
869
|
+
|
|
870
|
+
Context savings: ${savingsPercent}% vs loading all full schemas
|
|
871
|
+
${savingsPercent > 50 ? c('+ Good - lazy loading is saving context', 'green') : c('! Consider using lazy loading more', 'yellow')}
|
|
872
|
+
|
|
873
|
+
${c('Tip:', 'dim')} Use /mcp search <query> to load specific tools on-demand.
|
|
874
|
+
`);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
output.log(c('Usage:', 'bold'));
|
|
878
|
+
output.log(c(' /mcp - List servers', 'dim'));
|
|
879
|
+
output.log(c(' /mcp connect <name> - Connect to server', 'dim'));
|
|
880
|
+
output.log(c(' /mcp disconnect <name> - Disconnect', 'dim'));
|
|
881
|
+
output.log(c(' /mcp tools - List available tools', 'dim'));
|
|
882
|
+
output.log(c(' /mcp search <query> - Search & load tools', 'dim'));
|
|
883
|
+
output.log(c(' /mcp stats - Show context usage stats', 'dim'));
|
|
884
|
+
}
|
|
885
|
+
break;
|
|
886
|
+
// =========================================================================
|
|
887
|
+
// SESSION MANAGEMENT
|
|
888
|
+
// =========================================================================
|
|
889
|
+
case '/save':
|
|
890
|
+
try {
|
|
891
|
+
const state = agent.getState();
|
|
892
|
+
const metrics = agent.getMetrics();
|
|
893
|
+
const saveCheckpointId = `ckpt-manual-${Date.now().toString(36)}`;
|
|
894
|
+
persistenceDebug.log('/save command - creating checkpoint', {
|
|
895
|
+
checkpointId: saveCheckpointId,
|
|
896
|
+
messageCount: state.messages?.length ?? 0,
|
|
897
|
+
});
|
|
898
|
+
saveCheckpointToStore(sessionStore, {
|
|
899
|
+
id: saveCheckpointId,
|
|
900
|
+
label: 'manual-save',
|
|
901
|
+
messages: state.messages,
|
|
902
|
+
iteration: state.iteration,
|
|
903
|
+
metrics: metrics,
|
|
904
|
+
plan: state.plan,
|
|
905
|
+
memoryContext: state.memoryContext,
|
|
906
|
+
});
|
|
907
|
+
output.log(c(`+ Session saved: ${sessionId} (checkpoint: ${saveCheckpointId})`, 'green'));
|
|
908
|
+
}
|
|
909
|
+
catch (error) {
|
|
910
|
+
persistenceDebug.error('/save command failed', error);
|
|
911
|
+
output.log(c(`Error saving session: ${error.message}`, 'red'));
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
case '/load':
|
|
915
|
+
if (args.length === 0) {
|
|
916
|
+
output.log(c('Usage: /load <session-id>', 'yellow'));
|
|
917
|
+
output.log(c(' Use /sessions to list available sessions', 'dim'));
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
const loadId = args[0];
|
|
921
|
+
try {
|
|
922
|
+
let checkpointData;
|
|
923
|
+
if ('loadLatestCheckpoint' in sessionStore && typeof sessionStore.loadLatestCheckpoint === 'function') {
|
|
924
|
+
const sqliteCheckpoint = sessionStore.loadLatestCheckpoint(loadId);
|
|
925
|
+
if (sqliteCheckpoint?.state) {
|
|
926
|
+
checkpointData = sqliteCheckpoint.state;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (!checkpointData) {
|
|
930
|
+
const entries = await sessionStore.loadSession(loadId);
|
|
931
|
+
if (entries.length === 0) {
|
|
932
|
+
output.log(c(`No entries found for session: ${loadId}`, 'yellow'));
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
const checkpoint = [...entries].reverse().find(e => e.type === 'checkpoint');
|
|
936
|
+
checkpointData = checkpoint?.data;
|
|
937
|
+
}
|
|
938
|
+
if (checkpointData?.messages) {
|
|
939
|
+
agent.loadState({
|
|
940
|
+
messages: checkpointData.messages,
|
|
941
|
+
iteration: checkpointData.iteration,
|
|
942
|
+
metrics: checkpointData.metrics,
|
|
943
|
+
plan: checkpointData.plan,
|
|
944
|
+
memoryContext: checkpointData.memoryContext,
|
|
945
|
+
});
|
|
946
|
+
output.log(c(`+ Loaded ${checkpointData.messages.length} messages from ${loadId}`, 'green'));
|
|
947
|
+
}
|
|
948
|
+
else {
|
|
949
|
+
output.log(c('No checkpoint found in session', 'yellow'));
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
catch (error) {
|
|
953
|
+
output.log(c(`Error loading session: ${error.message}`, 'red'));
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
break;
|
|
957
|
+
case '/resume':
|
|
958
|
+
try {
|
|
959
|
+
const recentSession = sessionStore.getRecentSession();
|
|
960
|
+
if (!recentSession) {
|
|
961
|
+
output.log(c('No previous sessions found', 'yellow'));
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
output.log(c(`Found recent session: ${recentSession.id}`, 'dim'));
|
|
965
|
+
output.log(c(` Created: ${new Date(recentSession.createdAt).toLocaleString()}`, 'dim'));
|
|
966
|
+
output.log(c(` Messages: ${recentSession.messageCount}`, 'dim'));
|
|
967
|
+
let resumeCheckpointData;
|
|
968
|
+
if ('loadLatestCheckpoint' in sessionStore && typeof sessionStore.loadLatestCheckpoint === 'function') {
|
|
969
|
+
const sqliteCheckpoint = sessionStore.loadLatestCheckpoint(recentSession.id);
|
|
970
|
+
if (sqliteCheckpoint?.state) {
|
|
971
|
+
resumeCheckpointData = sqliteCheckpoint.state;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
if (!resumeCheckpointData) {
|
|
975
|
+
const entriesResult = sessionStore.loadSession(recentSession.id);
|
|
976
|
+
const entries = Array.isArray(entriesResult) ? entriesResult : await entriesResult;
|
|
977
|
+
const checkpoint = [...entries].reverse().find(e => e.type === 'checkpoint');
|
|
978
|
+
if (checkpoint?.data) {
|
|
979
|
+
resumeCheckpointData = checkpoint.data;
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
const messages = entries
|
|
983
|
+
.filter((e) => e.type === 'message')
|
|
984
|
+
.map((e) => e.data);
|
|
985
|
+
if (messages.length > 0) {
|
|
986
|
+
agent.loadState({ messages: messages });
|
|
987
|
+
output.log(c(`+ Resumed ${messages.length} messages from last session`, 'green'));
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
output.log(c('No messages found in last session', 'yellow'));
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
if (resumeCheckpointData?.messages) {
|
|
995
|
+
agent.loadState({
|
|
996
|
+
messages: resumeCheckpointData.messages,
|
|
997
|
+
iteration: resumeCheckpointData.iteration,
|
|
998
|
+
metrics: resumeCheckpointData.metrics,
|
|
999
|
+
plan: resumeCheckpointData.plan,
|
|
1000
|
+
memoryContext: resumeCheckpointData.memoryContext,
|
|
1001
|
+
});
|
|
1002
|
+
output.log(c(`+ Resumed ${resumeCheckpointData.messages.length} messages from last session`, 'green'));
|
|
1003
|
+
if (resumeCheckpointData.iteration) {
|
|
1004
|
+
output.log(c(` Iteration: ${resumeCheckpointData.iteration}`, 'dim'));
|
|
1005
|
+
}
|
|
1006
|
+
if (resumeCheckpointData.plan) {
|
|
1007
|
+
output.log(c(` Plan restored`, 'dim'));
|
|
1008
|
+
}
|
|
1009
|
+
if ('getPendingPlan' in sessionStore && typeof sessionStore.getPendingPlan === 'function') {
|
|
1010
|
+
const pendingPlan = sessionStore.getPendingPlan(recentSession.id);
|
|
1011
|
+
if (pendingPlan && pendingPlan.status === 'pending') {
|
|
1012
|
+
output.log(c(`\nFound pending plan: "${pendingPlan.task}"`, 'yellow'));
|
|
1013
|
+
output.log(c(` ${pendingPlan.proposedChanges.length} change(s) awaiting approval`, 'yellow'));
|
|
1014
|
+
output.log(c(' Use /show-plan to view, /approve to execute, /reject to discard', 'dim'));
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
catch (error) {
|
|
1021
|
+
output.log(c(`Error resuming session: ${error.message}`, 'red'));
|
|
1022
|
+
}
|
|
1023
|
+
break;
|
|
1024
|
+
case '/sessions':
|
|
1025
|
+
try {
|
|
1026
|
+
const sessions = await sessionStore.listSessions();
|
|
1027
|
+
output.log(formatSessionsTable(sessions));
|
|
1028
|
+
}
|
|
1029
|
+
catch (error) {
|
|
1030
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
1031
|
+
}
|
|
1032
|
+
break;
|
|
1033
|
+
// =========================================================================
|
|
1034
|
+
// CONTEXT MANAGEMENT
|
|
1035
|
+
// =========================================================================
|
|
1036
|
+
case '/compact':
|
|
1037
|
+
try {
|
|
1038
|
+
const state = agent.getState();
|
|
1039
|
+
const contextUsage = getContextUsage(state.messages, 80000);
|
|
1040
|
+
if (args[0] === 'status') {
|
|
1041
|
+
output.log(`
|
|
1042
|
+
${c('Context Status:', 'bold')}
|
|
1043
|
+
Messages: ${state.messages.length}
|
|
1044
|
+
Est. Tokens: ${contextUsage.tokens.toLocaleString()}
|
|
1045
|
+
Usage: ${contextUsage.percent}%
|
|
1046
|
+
Threshold: 80%
|
|
1047
|
+
Should Compact: ${contextUsage.shouldCompact ? c('Yes', 'yellow') : c('No', 'green')}
|
|
1048
|
+
`);
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
if (state.messages.length < 5) {
|
|
1052
|
+
output.log(c('Not enough messages to compact.', 'dim'));
|
|
1053
|
+
}
|
|
1054
|
+
else {
|
|
1055
|
+
output.log(c('Compacting context...', 'cyan'));
|
|
1056
|
+
const result = await compactor.compact(state.messages);
|
|
1057
|
+
agent.loadMessages(result.preservedMessages);
|
|
1058
|
+
output.log(formatCompactionResult(result));
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
catch (error) {
|
|
1063
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
1064
|
+
}
|
|
1065
|
+
break;
|
|
1066
|
+
case '/context':
|
|
1067
|
+
try {
|
|
1068
|
+
const state = agent.getState();
|
|
1069
|
+
if (args[0] === 'breakdown') {
|
|
1070
|
+
// Detailed token breakdown
|
|
1071
|
+
const mcpStats = mcpClient.getContextStats();
|
|
1072
|
+
const systemPrompt = agent.getSystemPromptWithMode();
|
|
1073
|
+
const estimateTokens = (str) => Math.ceil(str.length / 3.2);
|
|
1074
|
+
const systemTokens = estimateTokens(systemPrompt);
|
|
1075
|
+
const mcpTokens = mcpStats.summaryTokens + mcpStats.definitionTokens;
|
|
1076
|
+
const agentTools = agent.getTools().filter(t => !t.name.startsWith('mcp_'));
|
|
1077
|
+
const agentToolTokens = agentTools.length * 150;
|
|
1078
|
+
const convTokens = state.messages
|
|
1079
|
+
.filter(m => m.role !== 'system')
|
|
1080
|
+
.reduce((sum, m) => sum + estimateTokens(m.content), 0);
|
|
1081
|
+
const totalTokens = systemTokens + mcpTokens + agentToolTokens + convTokens;
|
|
1082
|
+
const messageCount = state.messages.filter(m => m.role !== 'system').length;
|
|
1083
|
+
const sysPct = totalTokens > 0 ? Math.round((systemTokens / totalTokens) * 100) : 0;
|
|
1084
|
+
const mcpPct = totalTokens > 0 ? Math.round((mcpTokens / totalTokens) * 100) : 0;
|
|
1085
|
+
const agentPct = totalTokens > 0 ? Math.round((agentToolTokens / totalTokens) * 100) : 0;
|
|
1086
|
+
const convPct = totalTokens > 0 ? Math.round((convTokens / totalTokens) * 100) : 0;
|
|
1087
|
+
output.log(`
|
|
1088
|
+
${c('Context Token Breakdown', 'bold')} (Total: ~${totalTokens.toLocaleString()} tokens)
|
|
1089
|
+
|
|
1090
|
+
${c(' Category Tokens % of Total', 'dim')}
|
|
1091
|
+
System prompt: ${systemTokens.toLocaleString().padStart(7)} tokens ${sysPct.toString().padStart(3)}%
|
|
1092
|
+
MCP tools: ${mcpTokens.toLocaleString().padStart(7)} tokens ${mcpPct.toString().padStart(3)}% (${mcpStats.loadedCount} loaded / ${mcpStats.totalTools} total)
|
|
1093
|
+
Agent tools: ${agentToolTokens.toLocaleString().padStart(7)} tokens ${agentPct.toString().padStart(3)}% (${agentTools.length} tools)
|
|
1094
|
+
Conversation: ${convTokens.toLocaleString().padStart(7)} tokens ${convPct.toString().padStart(3)}% (${messageCount} messages)
|
|
1095
|
+
`);
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
// Simple context overview
|
|
1099
|
+
const mcpStats = mcpClient.getContextStats();
|
|
1100
|
+
const systemPrompt = agent.getSystemPromptWithMode();
|
|
1101
|
+
const estimateTokens = (str) => Math.ceil(str.length / 3.2);
|
|
1102
|
+
const systemTokens = estimateTokens(systemPrompt);
|
|
1103
|
+
const mcpTokens = mcpStats.summaryTokens + mcpStats.definitionTokens;
|
|
1104
|
+
const agentTools = agent.getTools().filter(t => !t.name.startsWith('mcp_'));
|
|
1105
|
+
const agentToolTokens = agentTools.length * 150;
|
|
1106
|
+
const baseTokens = systemTokens + mcpTokens + agentToolTokens;
|
|
1107
|
+
const convTokens = state.messages
|
|
1108
|
+
.filter(m => m.role !== 'system')
|
|
1109
|
+
.reduce((sum, m) => sum + estimateTokens(m.content), 0);
|
|
1110
|
+
const totalTokens = baseTokens + convTokens;
|
|
1111
|
+
const contextLimit = 80000;
|
|
1112
|
+
const percent = Math.round((totalTokens / contextLimit) * 100);
|
|
1113
|
+
const shouldCompact = percent >= 80;
|
|
1114
|
+
const bar = '='.repeat(Math.min(20, Math.round(percent / 5))) +
|
|
1115
|
+
'-'.repeat(Math.max(0, 20 - Math.round(percent / 5)));
|
|
1116
|
+
const color = percent >= 80 ? 'red' : percent >= 60 ? 'yellow' : 'green';
|
|
1117
|
+
output.log(`
|
|
1118
|
+
${c('Context Window:', 'bold')}
|
|
1119
|
+
[${c(bar, color)}] ${percent}%
|
|
1120
|
+
Base: ~${baseTokens.toLocaleString()} tokens (system + ${agentTools.length} agent tools)
|
|
1121
|
+
MCP: ~${mcpTokens.toLocaleString()} tokens (${mcpStats.loadedCount}/${mcpStats.totalTools} tools loaded)
|
|
1122
|
+
Messages: ${state.messages.filter(m => m.role !== 'system').length} (~${convTokens.toLocaleString()} tokens)
|
|
1123
|
+
Total: ~${totalTokens.toLocaleString()} / ${(contextLimit / 1000).toFixed(0)}k tokens
|
|
1124
|
+
${shouldCompact ? c('! Consider running /compact', 'yellow') : c('+ Healthy', 'green')}
|
|
1125
|
+
`);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
output.log(c(`Error: ${error.message}`, 'red'));
|
|
1130
|
+
}
|
|
1131
|
+
break;
|
|
1132
|
+
// =========================================================================
|
|
1133
|
+
// THEME
|
|
1134
|
+
// =========================================================================
|
|
1135
|
+
case '/theme':
|
|
1136
|
+
try {
|
|
1137
|
+
const { getThemeNames, getTheme } = await import('../tui/theme/index.js');
|
|
1138
|
+
const themes = getThemeNames();
|
|
1139
|
+
if (args.length === 0) {
|
|
1140
|
+
output.log(`
|
|
1141
|
+
${c('Available Themes:', 'bold')}
|
|
1142
|
+
${themes.map(t => ` ${c(t, 'cyan')}`).join('\n')}
|
|
1143
|
+
|
|
1144
|
+
${c('Usage:', 'dim')} /theme <name>
|
|
1145
|
+
${c('Note:', 'dim')} Theme switching is visual in TUI mode. REPL mode uses fixed ANSI colors.
|
|
1146
|
+
`);
|
|
1147
|
+
}
|
|
1148
|
+
else {
|
|
1149
|
+
const themeName = args[0];
|
|
1150
|
+
if (themes.includes(themeName)) {
|
|
1151
|
+
const selectedTheme = getTheme(themeName);
|
|
1152
|
+
output.log(c(`+ Theme set to: ${themeName}`, 'green'));
|
|
1153
|
+
output.log(c(` Primary: ${selectedTheme.colors.primary}`, 'dim'));
|
|
1154
|
+
output.log(c(` Note: Full theme support requires TUI mode`, 'dim'));
|
|
1155
|
+
}
|
|
1156
|
+
else {
|
|
1157
|
+
output.log(c(`Unknown theme: ${themeName}`, 'red'));
|
|
1158
|
+
output.log(c(`Available: ${themes.join(', ')}`, 'dim'));
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
catch (error) {
|
|
1163
|
+
output.log(c(`Error loading themes: ${error.message}`, 'red'));
|
|
1164
|
+
}
|
|
1165
|
+
break;
|
|
1166
|
+
// =========================================================================
|
|
1167
|
+
// DEBUGGING & TESTING
|
|
1168
|
+
// =========================================================================
|
|
1169
|
+
case '/skills':
|
|
1170
|
+
try {
|
|
1171
|
+
const skills = agent.getSkills();
|
|
1172
|
+
if (skills.length === 0) {
|
|
1173
|
+
output.log(c('No skills loaded.', 'dim'));
|
|
1174
|
+
output.log(c('Add .md files to .skills/ directory to create skills.', 'dim'));
|
|
1175
|
+
}
|
|
1176
|
+
else {
|
|
1177
|
+
output.log(c('\nLoaded Skills:', 'bold'));
|
|
1178
|
+
skills.forEach((skill) => {
|
|
1179
|
+
const active = skill.active ? c('+', 'green') : c('o', 'dim');
|
|
1180
|
+
output.log(` ${active} ${c(skill.name, 'cyan')} - ${skill.description || 'No description'}`);
|
|
1181
|
+
if (skill.triggers?.length > 0) {
|
|
1182
|
+
output.log(c(` Triggers: ${skill.triggers.join(', ')}`, 'dim'));
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
catch (error) {
|
|
1188
|
+
output.log(c(`Skills not available: ${error.message}`, 'yellow'));
|
|
1189
|
+
}
|
|
1190
|
+
break;
|
|
1191
|
+
case '/sandbox':
|
|
1192
|
+
try {
|
|
1193
|
+
const { createSandboxManager } = await import('../integrations/sandbox/index.js');
|
|
1194
|
+
const sandboxManager = createSandboxManager({ mode: 'auto', verbose: true });
|
|
1195
|
+
const available = await sandboxManager.getAvailableSandboxes();
|
|
1196
|
+
output.log(c('\nSandbox Modes:', 'bold'));
|
|
1197
|
+
for (const { mode, available: isAvailable } of available) {
|
|
1198
|
+
const icon = isAvailable ? c('+', 'green') : c('x', 'red');
|
|
1199
|
+
const desc = {
|
|
1200
|
+
auto: 'Auto-detect best available sandbox',
|
|
1201
|
+
seatbelt: 'macOS sandbox-exec with Seatbelt profiles',
|
|
1202
|
+
landlock: 'Linux Landlock LSM / bubblewrap / firejail',
|
|
1203
|
+
docker: 'Docker container isolation',
|
|
1204
|
+
basic: 'Allowlist-based command validation',
|
|
1205
|
+
none: 'No sandboxing (passthrough)',
|
|
1206
|
+
};
|
|
1207
|
+
output.log(` ${icon} ${c(mode.padEnd(10), 'cyan')} ${desc[mode] || ''}`);
|
|
1208
|
+
}
|
|
1209
|
+
const sandbox = await sandboxManager.getSandbox();
|
|
1210
|
+
output.log(c(`\nActive sandbox: ${sandbox.getType()}`, 'green'));
|
|
1211
|
+
if (args[0] === 'test') {
|
|
1212
|
+
output.log(c('\nTesting sandbox with "echo hello"...', 'dim'));
|
|
1213
|
+
const result = await sandboxManager.execute('echo hello');
|
|
1214
|
+
output.log(` Exit code: ${result.exitCode}`);
|
|
1215
|
+
output.log(` Output: ${result.stdout.trim()}`);
|
|
1216
|
+
output.log(` Sandboxed: ${sandbox.getType() !== 'none' ? 'Yes' : 'No'}`);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
output.log(c('\nUse /sandbox test to run a test command.', 'dim'));
|
|
1220
|
+
}
|
|
1221
|
+
await sandboxManager.cleanup();
|
|
1222
|
+
}
|
|
1223
|
+
catch (error) {
|
|
1224
|
+
output.log(c(`Sandbox error: ${error.message}`, 'red'));
|
|
1225
|
+
}
|
|
1226
|
+
break;
|
|
1227
|
+
case '/shell':
|
|
1228
|
+
try {
|
|
1229
|
+
const { createPTYShell } = await import('../integrations/pty-shell.js');
|
|
1230
|
+
if (args[0] === 'test') {
|
|
1231
|
+
output.log(c('\nTesting persistent PTY shell...', 'cyan'));
|
|
1232
|
+
const shell = createPTYShell({ timeout: 5000 });
|
|
1233
|
+
await shell.start();
|
|
1234
|
+
output.log(c(' 1. Setting variable: export TEST_VAR="hello"', 'dim'));
|
|
1235
|
+
await shell.execute('export TEST_VAR="hello"');
|
|
1236
|
+
output.log(c(' 2. Reading variable back...', 'dim'));
|
|
1237
|
+
const result = await shell.execute('echo $TEST_VAR');
|
|
1238
|
+
output.log(` Result: ${result.output}`);
|
|
1239
|
+
output.log(` Exit code: ${result.exitCode}`);
|
|
1240
|
+
output.log(c(' 3. Checking state persistence...', 'dim'));
|
|
1241
|
+
const state = shell.getState();
|
|
1242
|
+
output.log(` CWD: ${state.cwd}`);
|
|
1243
|
+
output.log(` Commands run: ${state.history.length}`);
|
|
1244
|
+
output.log(` Shell running: ${state.isRunning}`);
|
|
1245
|
+
await shell.cleanup();
|
|
1246
|
+
output.log(c('\n+ PTY shell test passed!', 'green'));
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
output.log(`
|
|
1250
|
+
${c('PTY Shell:', 'bold')}
|
|
1251
|
+
The persistent shell maintains state between commands:
|
|
1252
|
+
- Working directory persists across cd commands
|
|
1253
|
+
- Environment variables are retained
|
|
1254
|
+
- Command history is tracked
|
|
1255
|
+
|
|
1256
|
+
${c('Use /shell test to run a quick test.', 'dim')}
|
|
1257
|
+
`);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
catch (error) {
|
|
1261
|
+
output.log(c(`Shell error: ${error.message}`, 'red'));
|
|
1262
|
+
}
|
|
1263
|
+
break;
|
|
1264
|
+
case '/lsp':
|
|
1265
|
+
output.log(`
|
|
1266
|
+
${c('LSP Integration:', 'bold')}
|
|
1267
|
+
The LSP-enhanced file tools provide real-time diagnostics:
|
|
1268
|
+
|
|
1269
|
+
${c('LSP-Enhanced Tools:', 'bold')}
|
|
1270
|
+
- ${c('lsp_edit_file', 'cyan')} - Edit with diagnostics feedback
|
|
1271
|
+
- ${c('lsp_write_file', 'cyan')} - Write with diagnostics feedback
|
|
1272
|
+
|
|
1273
|
+
${c('How it works:', 'dim')}
|
|
1274
|
+
1. After edit/write, LSP server analyzes the file
|
|
1275
|
+
2. Returns errors, warnings, and hints inline
|
|
1276
|
+
3. Agent can self-correct based on feedback
|
|
1277
|
+
`);
|
|
1278
|
+
break;
|
|
1279
|
+
case '/tui':
|
|
1280
|
+
output.log(`
|
|
1281
|
+
${c('TUI (Terminal UI):', 'bold')}
|
|
1282
|
+
Status: ${c('Active', 'green')}
|
|
1283
|
+
|
|
1284
|
+
${c('Features:', 'bold')}
|
|
1285
|
+
- Syntax highlighting for code blocks
|
|
1286
|
+
- Colored tool call display
|
|
1287
|
+
- Progress spinners
|
|
1288
|
+
- Error/success styling
|
|
1289
|
+
|
|
1290
|
+
${c('Code Highlighting Languages:', 'dim')}
|
|
1291
|
+
Python, JavaScript, TypeScript
|
|
1292
|
+
|
|
1293
|
+
${c('Test it:', 'dim')}
|
|
1294
|
+
Ask the agent to write code, e.g.:
|
|
1295
|
+
"Write a Python function to calculate factorial"
|
|
1296
|
+
`);
|
|
1297
|
+
break;
|
|
1298
|
+
// =========================================================================
|
|
1299
|
+
// UNKNOWN COMMAND
|
|
1300
|
+
// =========================================================================
|
|
1301
|
+
default:
|
|
1302
|
+
output.log(c(`Unknown command: ${cmd}. Type /help`, 'yellow'));
|
|
1303
|
+
}
|
|
1304
|
+
output.log('');
|
|
1305
|
+
}
|
|
1306
|
+
// =============================================================================
|
|
1307
|
+
// CONSOLE OUTPUT ADAPTER
|
|
1308
|
+
// =============================================================================
|
|
1309
|
+
/**
|
|
1310
|
+
* Create a CommandOutput that writes to console.
|
|
1311
|
+
* Used by REPL mode.
|
|
1312
|
+
*/
|
|
1313
|
+
export function createConsoleOutput() {
|
|
1314
|
+
return {
|
|
1315
|
+
log: (message) => console.log(message),
|
|
1316
|
+
error: (message) => console.error(message),
|
|
1317
|
+
clear: () => console.clear(),
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
//# sourceMappingURL=handler.js.map
|