@phuetz/code-buddy 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.fr.md +56 -0
- package/README.md +74 -16
- package/codebuddy-runtime.json +5 -5
- package/dist/agent/codebuddy-agent.d.ts +18 -0
- package/dist/agent/codebuddy-agent.js +45 -8
- package/dist/agent/execution/agent-executor.d.ts +0 -9
- package/dist/agent/execution/agent-executor.js +176 -12
- package/dist/agent/execution/context-pipeline.d.ts +9 -0
- package/dist/agent/execution/context-pipeline.js +64 -2
- package/dist/agent/execution/tool-loop-guard.d.ts +76 -0
- package/dist/agent/execution/tool-loop-guard.js +165 -0
- package/dist/agent/execution/tool-selection-strategy.d.ts +7 -0
- package/dist/agent/execution/tool-selection-strategy.js +32 -2
- package/dist/agent/facades/session-facade.d.ts +0 -6
- package/dist/agent/facades/session-facade.js +0 -45
- package/dist/agent/hermes-claw-migrate.d.ts +0 -21
- package/dist/agent/hermes-claw-migrate.js +9 -4
- package/dist/agent/hermes-protocol-gateways.js +8 -1
- package/dist/agent/repo-profiler.js +17 -4
- package/dist/agent/self-improvement/authored-tool-runtime.js +10 -2
- package/dist/agent/self-improvement/evolution/ast-novelty.d.ts +5 -0
- package/dist/agent/self-improvement/evolution/ast-novelty.js +58 -23
- package/dist/agent/self-improvement/evolution/code-variant-store.d.ts +3 -0
- package/dist/agent/self-improvement/evolution/evolution-engine.js +2 -0
- package/dist/agent/self-improvement/evolution/protected-paths.js +6 -0
- package/dist/agent/self-improvement/evolution/variant-fitness.d.ts +13 -2
- package/dist/agent/self-improvement/evolution/variant-fitness.js +184 -58
- package/dist/agent/self-improvement/evolution/worktree-scorer.d.ts +2 -0
- package/dist/agent/self-improvement/evolution/worktree-scorer.js +15 -0
- package/dist/agent/self-improvement/evolutionary-archive.d.ts +2 -1
- package/dist/agent/self-improvement/evolutionary-archive.js +34 -5
- package/dist/agent/self-improvement/proposal-store.d.ts +1 -0
- package/dist/agent/self-improvement/proposal-store.js +79 -17
- package/dist/agent/self-improvement/skill-apply-journal.d.ts +44 -0
- package/dist/agent/self-improvement/skill-apply-journal.js +178 -0
- package/dist/agent/self-improvement/skill-behavior-benchmark.d.ts +3 -0
- package/dist/agent/self-improvement/skill-behavior-benchmark.js +19 -0
- package/dist/agent/self-improvement/skill-behavior-gate.d.ts +34 -0
- package/dist/agent/self-improvement/skill-behavior-gate.js +96 -0
- package/dist/agent/self-improvement/skill-engine.d.ts +22 -0
- package/dist/agent/self-improvement/skill-engine.js +385 -13
- package/dist/agent/self-improvement/skill-gate.d.ts +2 -0
- package/dist/agent/self-improvement/skill-gate.js +17 -2
- package/dist/agent/self-improvement/skill-mutator.d.ts +6 -1
- package/dist/agent/self-improvement/skill-mutator.js +51 -15
- package/dist/agent/self-improvement/skill-types.d.ts +2 -1
- package/dist/agent/self-improvement/types.d.ts +11 -0
- package/dist/agent/tool-handler.d.ts +1 -1
- package/dist/agent/tool-handler.js +28 -9
- package/dist/auth/profile-manager.js +1 -1
- package/dist/channels/companion-channel-turn.d.ts +53 -4
- package/dist/channels/companion-channel-turn.js +218 -16
- package/dist/channels/slash-parity.d.ts +4 -6
- package/dist/channels/slash-parity.js +9 -44
- package/dist/cli/session-commands.d.ts +9 -0
- package/dist/cli/session-commands.js +45 -5
- package/dist/cli/session-picker.d.ts +43 -0
- package/dist/cli/session-picker.js +128 -0
- package/dist/codebuddy/a2a-call-tool-defs.d.ts +26 -0
- package/dist/codebuddy/a2a-call-tool-defs.js +12 -0
- package/dist/codebuddy/fleet-tool-defs.d.ts +2 -0
- package/dist/codebuddy/fleet-tool-defs.js +55 -0
- package/dist/codebuddy/providers/chatgpt-headers.d.ts +18 -0
- package/dist/codebuddy/providers/chatgpt-headers.js +37 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +2 -1
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +10 -23
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +7 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +29 -1
- package/dist/codebuddy/ragchat-tool-defs.d.ts +31 -0
- package/dist/codebuddy/ragchat-tool-defs.js +19 -0
- package/dist/codebuddy/resource-catalog-tool-defs.d.ts +28 -0
- package/dist/codebuddy/resource-catalog-tool-defs.js +18 -0
- package/dist/codebuddy/tool-definitions/agent-tools.js +2 -2
- package/dist/codebuddy/tool-definitions/code-exec-tools.js +5 -1
- package/dist/codebuddy/tool-definitions/cron-tools.js +6 -0
- package/dist/codebuddy/tool-definitions/self-describe-tools.js +6 -1
- package/dist/codebuddy/tools.d.ts +0 -6
- package/dist/codebuddy/tools.js +25 -3
- package/dist/commands/cli/daemon-commands.js +3 -1
- package/dist/commands/cli/evolve-command.js +21 -5
- package/dist/commands/cli/fleet-collaboration-commands.d.ts +2 -0
- package/dist/commands/cli/fleet-collaboration-commands.js +57 -0
- package/dist/commands/cli/fleet-commands.js +29 -0
- package/dist/commands/cli/fleet-mission-commands.d.ts +3 -0
- package/dist/commands/cli/fleet-mission-commands.js +72 -0
- package/dist/commands/cli/fleet-rooms-commands.d.ts +10 -0
- package/dist/commands/cli/fleet-rooms-commands.js +289 -0
- package/dist/commands/cli/tools-commands.js +2 -1
- package/dist/commands/cli/triage-command.d.ts +8 -0
- package/dist/commands/cli/triage-command.js +72 -0
- package/dist/commands/cli/utility-commands.js +25 -1
- package/dist/commands/client-dispatcher.d.ts +7 -0
- package/dist/commands/client-dispatcher.js +73 -21
- package/dist/commands/cron-cli/index.d.ts +3 -1
- package/dist/commands/cron-cli/index.js +25 -0
- package/dist/commands/device-auth.d.ts +10 -0
- package/dist/commands/device-auth.js +91 -0
- package/dist/commands/enhanced-command-handler.d.ts +9 -0
- package/dist/commands/enhanced-command-handler.js +28 -6
- package/dist/commands/handlers/agent-handlers.d.ts +1 -1
- package/dist/commands/handlers/agent-handlers.js +4 -4
- package/dist/commands/handlers/channel-handlers.js +53 -2
- package/dist/commands/handlers/export-handlers.d.ts +3 -2
- package/dist/commands/handlers/export-handlers.js +55 -28
- package/dist/commands/handlers/extra-handlers.js +5 -1
- package/dist/commands/handlers/grill-me-handler.js +26 -18
- package/dist/commands/handlers/memory-handlers.d.ts +6 -2
- package/dist/commands/handlers/memory-handlers.js +35 -15
- package/dist/commands/handlers/missing-handlers.d.ts +2 -2
- package/dist/commands/handlers/missing-handlers.js +12 -4
- package/dist/commands/handlers/resources-handler.d.ts +12 -0
- package/dist/commands/handlers/resources-handler.js +52 -0
- package/dist/commands/handlers/starter-handlers.d.ts +1 -1
- package/dist/commands/handlers/starter-handlers.js +32 -2
- package/dist/commands/handlers/switch-handler.d.ts +1 -1
- package/dist/commands/handlers/switch-handler.js +15 -0
- package/dist/commands/handlers/test-handlers.js +4 -86
- package/dist/commands/handlers/ui-handlers.js +11 -5
- package/dist/commands/login-chatgpt.d.ts +8 -0
- package/dist/commands/login-chatgpt.js +17 -0
- package/dist/commands/mcp-import.d.ts +11 -0
- package/dist/commands/mcp-import.js +67 -0
- package/dist/commands/mcp-invoke.d.ts +2 -0
- package/dist/commands/mcp-invoke.js +68 -0
- package/dist/commands/mcp.d.ts +13 -0
- package/dist/commands/mcp.js +66 -21
- package/dist/commands/pipeline.d.ts +7 -1
- package/dist/commands/pipeline.js +104 -7
- package/dist/commands/resources.d.ts +2 -0
- package/dist/commands/resources.js +64 -0
- package/dist/commands/skills-cli/index.js +35 -12
- package/dist/commands/slash/builtin-commands.js +16 -3
- package/dist/commands/slash/index.d.ts +3 -1
- package/dist/commands/slash/index.js +2 -0
- package/dist/commands/slash/surfaces.d.ts +53 -0
- package/dist/commands/slash/surfaces.js +177 -0
- package/dist/commands/slash/types.d.ts +17 -0
- package/dist/commands/try.d.ts +1 -1
- package/dist/commands/try.js +1 -1
- package/dist/companion/companion-identity.d.ts +43 -0
- package/dist/companion/companion-identity.js +136 -0
- package/dist/companion/companion-toolset.d.ts +66 -0
- package/dist/companion/companion-toolset.js +368 -0
- package/dist/companion/companion-turn.d.ts +10 -2
- package/dist/companion/companion-turn.js +38 -1
- package/dist/config/code-exec-policy.d.ts +25 -0
- package/dist/config/code-exec-policy.js +39 -0
- package/dist/config/model-tools.d.ts +9 -0
- package/dist/config/model-tools.js +103 -0
- package/dist/context/context-manager-v2.js +2 -2
- package/dist/context/lm-resizer-compressor.js +3 -2
- package/dist/context/lm-resizer-diagnostics.d.ts +9 -0
- package/dist/context/lm-resizer-diagnostics.js +30 -0
- package/dist/context/tool-output-masking.js +3 -4
- package/dist/curator/curator.d.ts +6 -0
- package/dist/curator/curator.js +53 -3
- package/dist/daemon/cron-agent-bridge.d.ts +6 -0
- package/dist/daemon/cron-agent-bridge.js +31 -4
- package/dist/doctor/index.d.ts +11 -2
- package/dist/doctor/index.js +84 -21
- package/dist/doctor/integrations.d.ts +197 -0
- package/dist/doctor/integrations.js +241 -0
- package/dist/doctor/triage.d.ts +108 -0
- package/dist/doctor/triage.js +304 -0
- package/dist/errors/crash-handler.js +2 -0
- package/dist/fleet/collaboration.d.ts +44 -0
- package/dist/fleet/collaboration.js +170 -0
- package/dist/fleet/fleet-listener.d.ts +1 -0
- package/dist/fleet/fleet-listener.js +87 -46
- package/dist/fleet/fleet-registry.d.ts +2 -0
- package/dist/fleet/resource-catalog.d.ts +245 -0
- package/dist/fleet/resource-catalog.js +211 -0
- package/dist/fleet/rooms/room-access.d.ts +138 -0
- package/dist/fleet/rooms/room-access.js +196 -0
- package/dist/fleet/rooms/room-client.d.ts +158 -0
- package/dist/fleet/rooms/room-client.js +685 -0
- package/dist/fleet/rooms/room-event.d.ts +139 -0
- package/dist/fleet/rooms/room-event.js +330 -0
- package/dist/fleet/rooms/room-filter.d.ts +48 -0
- package/dist/fleet/rooms/room-filter.js +152 -0
- package/dist/fleet/rooms/room-hub.d.ts +154 -0
- package/dist/fleet/rooms/room-hub.js +363 -0
- package/dist/fleet/rooms/room-identity.d.ts +26 -0
- package/dist/fleet/rooms/room-identity.js +82 -0
- package/dist/fleet/rooms/room-lock.d.ts +34 -0
- package/dist/fleet/rooms/room-lock.js +180 -0
- package/dist/fleet/rooms/room-observations.d.ts +7 -0
- package/dist/fleet/rooms/room-observations.js +61 -0
- package/dist/fleet/rooms/room-server.d.ts +28 -0
- package/dist/fleet/rooms/room-server.js +75 -0
- package/dist/fleet/rooms/room-store.d.ts +119 -0
- package/dist/fleet/rooms/room-store.js +448 -0
- package/dist/fleet/rooms/room-ws-bridge.d.ts +27 -0
- package/dist/fleet/rooms/room-ws-bridge.js +137 -0
- package/dist/fleet/sensory-mission-bridge.d.ts +42 -0
- package/dist/fleet/sensory-mission-bridge.js +136 -0
- package/dist/git/worktree-sessions.js +1 -0
- package/dist/harness/contract.d.ts +4 -4
- package/dist/harness/fleet-supervisor.d.ts +16 -0
- package/dist/harness/fleet-supervisor.js +64 -0
- package/dist/harness/index.d.ts +4 -0
- package/dist/harness/index.js +4 -0
- package/dist/harness/mission-runner.d.ts +3 -0
- package/dist/harness/mission-runner.js +53 -0
- package/dist/harness/mission-store.d.ts +93 -0
- package/dist/harness/mission-store.js +297 -0
- package/dist/harness/tool-harness.d.ts +56 -0
- package/dist/harness/tool-harness.js +153 -0
- package/dist/hooks/use-enhanced-input.js +48 -4
- package/dist/hooks/use-input-handler.d.ts +1 -0
- package/dist/hooks/use-input-handler.js +82 -22
- package/dist/hooks/use-input-history.js +1 -0
- package/dist/identity/lisa-introspection.js +5 -2
- package/dist/identity/operational-self-model.d.ts +2 -0
- package/dist/identity/operational-self-model.js +4 -0
- package/dist/index.js +52 -6
- package/dist/mcp/client.d.ts +11 -0
- package/dist/mcp/client.js +68 -3
- package/dist/mcp/config.d.ts +20 -0
- package/dist/mcp/config.js +121 -8
- package/dist/mcp/import-normalize.d.ts +12 -0
- package/dist/mcp/import-normalize.js +114 -0
- package/dist/mcp/mcp-oauth-constants.d.ts +8 -0
- package/dist/mcp/mcp-oauth-constants.js +9 -0
- package/dist/mcp/mcp-oauth-provider.d.ts +80 -0
- package/dist/mcp/mcp-oauth-provider.js +241 -0
- package/dist/mcp/mcp-oauth.d.ts +60 -1
- package/dist/mcp/mcp-oauth.js +241 -65
- package/dist/mcp/transports.d.ts +14 -5
- package/dist/mcp/transports.js +112 -101
- package/dist/mcp/types.d.ts +5 -0
- package/dist/media/comfyui-recipe-contract.d.ts +7 -7
- package/dist/memory/facts-memory.d.ts +11 -1
- package/dist/memory/facts-memory.js +47 -8
- package/dist/memory/memory-candidate-queue.d.ts +2 -2
- package/dist/memory/memory-candidate-queue.js +6 -6
- package/dist/memory/persistent-memory.d.ts +13 -8
- package/dist/memory/persistent-memory.js +77 -30
- package/dist/nodes/device-node.js +5 -9
- package/dist/observability/mobile-supervision-gateway-contract.js +20 -7
- package/dist/observability/run-event-writer.d.ts +21 -0
- package/dist/observability/run-event-writer.js +81 -0
- package/dist/observability/run-store.d.ts +5 -0
- package/dist/observability/run-store.js +18 -13
- package/dist/observability/run-trajectory.js +1 -1
- package/dist/optimization/prompt-cache.d.ts +19 -2
- package/dist/optimization/prompt-cache.js +41 -6
- package/dist/orchestration/orchestrator.d.ts +21 -0
- package/dist/orchestration/orchestrator.js +122 -15
- package/dist/persistence/session-content.d.ts +8 -0
- package/dist/persistence/session-content.js +76 -0
- package/dist/persistence/session-handoff.d.ts +64 -0
- package/dist/persistence/session-handoff.js +80 -0
- package/dist/persistence/session-history.d.ts +4 -0
- package/dist/persistence/session-history.js +38 -0
- package/dist/persistence/session-store.d.ts +9 -0
- package/dist/persistence/session-store.js +48 -20
- package/dist/personas/persona-manager.js +17 -1
- package/dist/plugins/code-explorer/CodeExplorerManager.d.ts +10 -4
- package/dist/plugins/code-explorer/CodeExplorerManager.js +69 -16
- package/dist/plugins/plugin-manager.js +10 -1
- package/dist/prompts/prompt-manager.js +11 -4
- package/dist/prompts/system-base.js +6 -2
- package/dist/protocols/a2a/codebuddy-executor.d.ts +11 -2
- package/dist/protocols/a2a/codebuddy-executor.js +9 -8
- package/dist/protocols/a2a/index.d.ts +1 -1
- package/dist/protocols/a2a/jsonrpc-v1.d.ts +41 -0
- package/dist/protocols/a2a/jsonrpc-v1.js +145 -0
- package/dist/protocols/a2a/peer-config.d.ts +20 -0
- package/dist/protocols/a2a/peer-config.js +55 -0
- package/dist/providers/codex-oauth.js +30 -6
- package/dist/providers/model-provider-compat.js +2 -1
- package/dist/sandbox/os-sandbox.d.ts +1 -1
- package/dist/scheduler/cron-scheduler.d.ts +15 -2
- package/dist/scheduler/cron-scheduler.js +35 -4
- package/dist/scheduler/job-notepad.d.ts +69 -0
- package/dist/scheduler/job-notepad.js +339 -0
- package/dist/security/audit-logger.d.ts +1 -1
- package/dist/security/compute-confinement.d.ts +4 -0
- package/dist/security/compute-confinement.js +89 -0
- package/dist/security/session-encryption.d.ts +4 -0
- package/dist/security/session-encryption.js +31 -0
- package/dist/sensory/voice-loop.d.ts +17 -0
- package/dist/sensory/voice-loop.js +72 -15
- package/dist/server/auth/device-session-context.d.ts +9 -0
- package/dist/server/auth/device-session-context.js +13 -0
- package/dist/server/auth/device-store.d.ts +89 -0
- package/dist/server/auth/device-store.js +261 -0
- package/dist/server/auth/device-token.d.ts +3 -0
- package/dist/server/auth/device-token.js +6 -0
- package/dist/server/auth/jwt.js +4 -0
- package/dist/server/index.d.ts +0 -10
- package/dist/server/index.js +28 -0
- package/dist/server/middleware/auth.js +3 -2
- package/dist/server/routes/a2a-jsonrpc.d.ts +9 -0
- package/dist/server/routes/a2a-jsonrpc.js +66 -0
- package/dist/server/routes/a2a-protocol.d.ts +12 -0
- package/dist/server/routes/a2a-protocol.js +1 -1
- package/dist/server/routes/device-auth.d.ts +4 -0
- package/dist/server/routes/device-auth.js +40 -0
- package/dist/server/types.d.ts +4 -0
- package/dist/server/websocket/handler.d.ts +13 -0
- package/dist/server/websocket/handler.js +102 -17
- package/dist/services/prompt-builder.d.ts +2 -0
- package/dist/services/prompt-builder.js +16 -6
- package/dist/services/runtime-settings-context.d.ts +81 -0
- package/dist/services/runtime-settings-context.js +79 -0
- package/dist/skills/executor.js +2 -0
- package/dist/skills/hub.js +16 -14
- package/dist/skills/local-inventory.d.ts +21 -0
- package/dist/skills/local-inventory.js +72 -0
- package/dist/skills/skill-loader.js +2 -2
- package/dist/skills/skill-usage-store.d.ts +49 -0
- package/dist/skills/skill-usage-store.js +121 -0
- package/dist/testing/ai-integration-tests.js +8 -5
- package/dist/themes/theme-manager.d.ts +12 -0
- package/dist/themes/theme-manager.js +29 -0
- package/dist/themes/theme-schema.d.ts +24 -24
- package/dist/tools/a2a-call-tool.d.ts +34 -0
- package/dist/tools/a2a-call-tool.js +75 -0
- package/dist/tools/bash/streaming-executor.d.ts +1 -0
- package/dist/tools/bash/streaming-executor.js +78 -90
- package/dist/tools/code-exec-preflight-runner.d.ts +41 -0
- package/dist/tools/code-exec-preflight-runner.js +254 -0
- package/dist/tools/code-exec-preflight.d.ts +44 -0
- package/dist/tools/code-exec-preflight.js +501 -0
- package/dist/tools/code-exec-tool.d.ts +48 -1
- package/dist/tools/code-exec-tool.js +191 -47
- package/dist/tools/comment-watcher.js +29 -12
- package/dist/tools/core-code-inspection.d.ts +56 -0
- package/dist/tools/core-code-inspection.js +86 -0
- package/dist/tools/create-skill-tool.d.ts +2 -3
- package/dist/tools/create-skill-tool.js +16 -75
- package/dist/tools/cronjob-tool.d.ts +1 -0
- package/dist/tools/cronjob-tool.js +1 -0
- package/dist/tools/env-doctor-tool.d.ts +2 -0
- package/dist/tools/env-doctor-tool.js +4 -3
- package/dist/tools/execute-code-rpc-invoker.d.ts +1 -1
- package/dist/tools/execute-code-rpc-invoker.js +35 -19
- package/dist/tools/execute-code-runner.d.ts +2 -0
- package/dist/tools/execute-code-runner.js +52 -17
- package/dist/tools/fleet-room-tool.d.ts +104 -0
- package/dist/tools/fleet-room-tool.js +124 -0
- package/dist/tools/integration-tool-hints.d.ts +4 -0
- package/dist/tools/integration-tool-hints.js +19 -0
- package/dist/tools/list-peers-tool.d.ts +3 -0
- package/dist/tools/list-peers-tool.js +11 -4
- package/dist/tools/media-generation-tool.d.ts +16 -1
- package/dist/tools/media-generation-tool.js +341 -9
- package/dist/tools/merge-conflict-tool.js +53 -25
- package/dist/tools/metadata.d.ts +1 -5
- package/dist/tools/metadata.js +30 -28
- package/dist/tools/peer-tool-invoke-tool.d.ts +61 -0
- package/dist/tools/peer-tool-invoke-tool.js +396 -0
- package/dist/tools/ragchat-tool.d.ts +39 -0
- package/dist/tools/ragchat-tool.js +105 -0
- package/dist/tools/registry/fleet-tools.d.ts +21 -3
- package/dist/tools/registry/fleet-tools.js +137 -4
- package/dist/tools/registry/index.d.ts +1 -1
- package/dist/tools/registry/index.js +2 -2
- package/dist/tools/registry/knowledge-tools.d.ts +2 -2
- package/dist/tools/registry/knowledge-tools.js +2 -2
- package/dist/tools/registry/lessons-tools.d.ts +7 -0
- package/dist/tools/registry/lessons-tools.js +43 -3
- package/dist/tools/registry/memory-tools.d.ts +1 -1
- package/dist/tools/registry/memory-tools.js +8 -8
- package/dist/tools/registry/research-tools.d.ts +1 -0
- package/dist/tools/registry/research-tools.js +4 -13
- package/dist/tools/registry/self-describe-tools.d.ts +1 -1
- package/dist/tools/registry/self-describe-tools.js +43 -30
- package/dist/tools/resource-catalog-tool.d.ts +38 -0
- package/dist/tools/resource-catalog-tool.js +46 -0
- package/dist/tools/skills-inspection-tool.js +30 -1
- package/dist/tools/stream-tool-output.d.ts +3 -0
- package/dist/tools/stream-tool-output.js +33 -0
- package/dist/tools/tool-call-scheduler.d.ts +10 -0
- package/dist/tools/tool-call-scheduler.js +58 -0
- package/dist/tools/tool-effect.d.ts +5 -0
- package/dist/tools/tool-effect.js +26 -0
- package/dist/tools/tool-search.d.ts +12 -11
- package/dist/tools/tool-search.js +67 -26
- package/dist/tools/types.d.ts +6 -0
- package/dist/ui/components/ChatHistory.d.ts +1 -1
- package/dist/ui/components/ChatHistory.js +2 -2
- package/dist/ui/components/ChatInput.d.ts +2 -1
- package/dist/ui/components/ChatInput.js +42 -88
- package/dist/ui/components/ChatInterface.d.ts +4 -2
- package/dist/ui/components/ChatInterface.js +27 -63
- package/dist/ui/components/CommandSuggestions.d.ts +0 -1
- package/dist/ui/components/CommandSuggestions.js +4 -6
- package/dist/ui/components/FileAutocomplete.js +1 -1
- package/dist/ui/components/KeyboardHelp.js +8 -6
- package/dist/ui/components/ModelSelection.js +6 -5
- package/dist/ui/components/StatusBar.d.ts +2 -1
- package/dist/ui/components/StatusBar.js +8 -7
- package/dist/ui/context/theme-context.js +3 -2
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/utils/markdown-renderer.js +4 -13
- package/dist/utils/atomic-write.d.ts +22 -0
- package/dist/utils/atomic-write.js +29 -0
- package/dist/utils/bounded-output.d.ts +16 -0
- package/dist/utils/bounded-output.js +63 -0
- package/dist/utils/config-validation/schema.d.ts +2 -2
- package/dist/utils/device-store-file.d.ts +4 -0
- package/dist/utils/device-store-file.js +40 -0
- package/dist/utils/export-manager.d.ts +9 -0
- package/dist/utils/export-manager.js +19 -0
- package/dist/utils/first-use-hints.d.ts +25 -0
- package/dist/utils/first-use-hints.js +58 -0
- package/dist/utils/graceful-shutdown.d.ts +8 -0
- package/dist/utils/graceful-shutdown.js +23 -7
- package/dist/utils/history-manager.js +1 -1
- package/dist/utils/update-notifier.js +16 -18
- package/dist/wizard/environment-detection.d.ts +5 -1
- package/dist/wizard/environment-detection.js +49 -7
- package/dist/wizard/onboarding.d.ts +5 -1
- package/dist/wizard/onboarding.js +90 -30
- package/dist/wizard/provider-onboarding.d.ts +2 -0
- package/dist/wizard/provider-onboarding.js +55 -17
- package/package.json +7 -3
|
@@ -42,7 +42,7 @@ function mapFactCategoryToMemoryCategory(cat) {
|
|
|
42
42
|
}
|
|
43
43
|
const DEFAULT_CONFIG = {
|
|
44
44
|
projectMemoryPath: ".codebuddy/CODEBUDDY_MEMORY.md",
|
|
45
|
-
userMemoryPath
|
|
45
|
+
get userMemoryPath() { return path.join(os.homedir(), ".codebuddy", "memory.md"); },
|
|
46
46
|
autoCapture: true,
|
|
47
47
|
maxMemories: 100,
|
|
48
48
|
relevanceThreshold: 0.5,
|
|
@@ -215,6 +215,10 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
215
215
|
constructor(config = {}) {
|
|
216
216
|
super();
|
|
217
217
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
218
|
+
// Freeze relative paths at construction; later process/session cwd changes
|
|
219
|
+
// must not redirect a delayed metadata flush to another project.
|
|
220
|
+
this.config.projectMemoryPath = path.resolve(this.config.projectMemoryPath);
|
|
221
|
+
this.config.userMemoryPath = path.resolve(this.config.userMemoryPath);
|
|
218
222
|
}
|
|
219
223
|
/**
|
|
220
224
|
* Initialize memory system, loading existing memories.
|
|
@@ -446,6 +450,7 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
446
450
|
}
|
|
447
451
|
const previousMemories = cloneMemoryMap(memories);
|
|
448
452
|
let resultKey = normalizedKey;
|
|
453
|
+
let reconciliation = { status: 'skipped', reason: 'no LLM provider available' };
|
|
449
454
|
try {
|
|
450
455
|
const { FactsMemoryService } = await import('./facts-memory.js');
|
|
451
456
|
const service = new FactsMemoryService();
|
|
@@ -485,6 +490,7 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
485
490
|
tags: mergeMemoryTags(prior?.tags, fact.source, tags)
|
|
486
491
|
});
|
|
487
492
|
}
|
|
493
|
+
await this.guardReconciliation(previousMemories, memories, scope, normalizedKey);
|
|
488
494
|
if (!memories.has(normalizedKey)) {
|
|
489
495
|
const newKeys = Array.from(memories.keys()).filter((memoryKey) => !previousMemories.has(memoryKey));
|
|
490
496
|
const reconciledKey = newKeys[newKeys.length - 1];
|
|
@@ -493,6 +499,7 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
493
499
|
}
|
|
494
500
|
resultKey = reconciledKey;
|
|
495
501
|
}
|
|
502
|
+
reconciliation = { status: 'applied' };
|
|
496
503
|
}
|
|
497
504
|
else {
|
|
498
505
|
// Fallback to default direct write
|
|
@@ -501,6 +508,8 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
501
508
|
}
|
|
502
509
|
catch (err) {
|
|
503
510
|
const message = err instanceof Error ? err.message : String(err);
|
|
511
|
+
reconciliation = { status: 'failed', reason: message };
|
|
512
|
+
resultKey = normalizedKey;
|
|
504
513
|
logger.warn(`[FactsMemory] Failed to reconcile remember, falling back to default behavior: ${message}`);
|
|
505
514
|
memories.clear();
|
|
506
515
|
for (const [memoryKey, memory] of previousMemories) {
|
|
@@ -543,6 +552,7 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
543
552
|
message: status === 'updated'
|
|
544
553
|
? `Updated "${resultKey}" in ${scope} memory.`
|
|
545
554
|
: `Stored "${resultKey}" in ${scope} memory.`,
|
|
555
|
+
reconciliation,
|
|
546
556
|
};
|
|
547
557
|
}
|
|
548
558
|
async replace(key, value, options = {}) {
|
|
@@ -826,6 +836,45 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
826
836
|
...(m.tags ? { tags: [...m.tags] } : {}),
|
|
827
837
|
}));
|
|
828
838
|
}
|
|
839
|
+
/** Guard the result, including model renames/omissions, rather than trusting DELETE alone. */
|
|
840
|
+
async guardReconciliation(previous, next, scope, explicitKey) {
|
|
841
|
+
const removed = [];
|
|
842
|
+
const protection = resolveForgettingConfig();
|
|
843
|
+
for (const [key, memory] of previous) {
|
|
844
|
+
const replacement = next.get(key);
|
|
845
|
+
if (isProtectedMemory(memory, protection)) {
|
|
846
|
+
if (key !== explicitKey || !replacement)
|
|
847
|
+
next.set(key, memory);
|
|
848
|
+
else
|
|
849
|
+
next.set(key, { ...replacement, category: memory.category, tags: mergeMemoryTags(memory.tags, undefined, replacement.tags) });
|
|
850
|
+
}
|
|
851
|
+
else if (!replacement || replacement.value !== memory.value || replacement.category !== memory.category) {
|
|
852
|
+
removed.push(memory);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
if (!removed.length)
|
|
856
|
+
return;
|
|
857
|
+
const archivePath = this.getArchivePath(scope);
|
|
858
|
+
const now = new Date();
|
|
859
|
+
const lines = removed.map(memory => {
|
|
860
|
+
const tags = memory.tags?.length ? ` [${memory.tags.join(', ')}]` : '';
|
|
861
|
+
const ageDays = Math.max(0, Math.round((now.getTime() - memory.createdAt.getTime()) / 86_400_000));
|
|
862
|
+
return `- **${memory.key}** (${memory.category}${tags}, accessed ${memory.accessCount}×, age ${ageDays}d, retention 1.000): ${escapeArchiveValue(memory.value)}`;
|
|
863
|
+
});
|
|
864
|
+
// Same recoverable format as forgetting. Durable archive precedes deletion;
|
|
865
|
+
// failures propagate to the caller's snapshot rollback/direct-write fallback.
|
|
866
|
+
await withSessionLock(archivePath, async () => {
|
|
867
|
+
let existing = '';
|
|
868
|
+
try {
|
|
869
|
+
existing = await fs.readFile(archivePath, 'utf8');
|
|
870
|
+
}
|
|
871
|
+
catch (error) {
|
|
872
|
+
if (error.code !== 'ENOENT')
|
|
873
|
+
throw error;
|
|
874
|
+
}
|
|
875
|
+
await writeFileAtomic(archivePath, `${existing}\n## Forgotten ${now.toISOString()}\n${lines.join('\n')}\n`, { mode: 0o600 });
|
|
876
|
+
});
|
|
877
|
+
}
|
|
829
878
|
/**
|
|
830
879
|
* Ebbinghaus forgetting pass (recoverable): memories whose retention decayed
|
|
831
880
|
* below the threshold are appended to a sibling `*.archive.md`, then removed.
|
|
@@ -1225,6 +1274,7 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
1225
1274
|
async autoCapture(message, response) {
|
|
1226
1275
|
if (!this.config.autoCapture)
|
|
1227
1276
|
return;
|
|
1277
|
+
const beforeCapture = cloneMemoryMap(this.projectMemories);
|
|
1228
1278
|
try {
|
|
1229
1279
|
const { FactsMemoryService } = await import('./facts-memory.js');
|
|
1230
1280
|
const service = new FactsMemoryService();
|
|
@@ -1271,9 +1321,14 @@ export class PersistentMemoryManager extends EventEmitter {
|
|
|
1271
1321
|
tags: mergeMemoryTags(prior?.tags, fact.source, ['auto-captured'])
|
|
1272
1322
|
});
|
|
1273
1323
|
}
|
|
1324
|
+
await this.guardReconciliation(priorProjectMemories, this.projectMemories, 'project');
|
|
1325
|
+
this.assertScopeWithinLimit('project');
|
|
1274
1326
|
await this.saveMemories("project");
|
|
1275
1327
|
}
|
|
1276
1328
|
catch (err) {
|
|
1329
|
+
this.projectMemories.clear();
|
|
1330
|
+
for (const [key, memory] of beforeCapture)
|
|
1331
|
+
this.projectMemories.set(key, memory);
|
|
1277
1332
|
const reason = err instanceof Error ? err.message : String(err);
|
|
1278
1333
|
if (err instanceof FactsExtractionError) {
|
|
1279
1334
|
logger.warn(`[FactsMemory] Failed to autoCapture facts: ${reason}`);
|
|
@@ -1424,40 +1479,32 @@ function unescapeArchiveValue(value) {
|
|
|
1424
1479
|
.slice(ARCHIVE_ESCAPED_VALUE_PREFIX.length)
|
|
1425
1480
|
.replace(/\\(\\|n)/g, (_match, escaped) => escaped === "n" ? "\n" : "\\");
|
|
1426
1481
|
}
|
|
1427
|
-
//
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
let inst = memoryManagerByBot.get(botId);
|
|
1444
|
-
if (!inst) {
|
|
1445
|
-
const botDir = path.join(os.homedir(), '.codebuddy', 'bots', botId);
|
|
1446
|
-
inst = new PersistentMemoryManager({
|
|
1447
|
-
...(config ?? {}),
|
|
1448
|
-
userMemoryPath: path.join(botDir, 'memory.md'),
|
|
1449
|
-
projectMemoryPath: path.join(botDir, 'CODEBUDDY_MEMORY.md'),
|
|
1482
|
+
// A project manager is shared by its tools, prompt reader and review queue.
|
|
1483
|
+
const memoryManagers = new Map();
|
|
1484
|
+
export function getMemoryManager(config, botId, cwd = process.cwd()) {
|
|
1485
|
+
const root = path.resolve(cwd);
|
|
1486
|
+
// Bot memory deliberately remains per-bot (historical channel contract).
|
|
1487
|
+
const key = botId ? `bot:${botId}` : `project:${root}`;
|
|
1488
|
+
let manager = memoryManagers.get(key);
|
|
1489
|
+
if (!manager) {
|
|
1490
|
+
const botDir = botId ? path.join(os.homedir(), '.codebuddy', 'bots', botId) : undefined;
|
|
1491
|
+
manager = new PersistentMemoryManager({
|
|
1492
|
+
projectMemoryPath: path.join(root, '.codebuddy', 'CODEBUDDY_MEMORY.md'),
|
|
1493
|
+
...config,
|
|
1494
|
+
...(botDir ? {
|
|
1495
|
+
userMemoryPath: path.join(botDir, 'memory.md'),
|
|
1496
|
+
projectMemoryPath: path.join(botDir, 'CODEBUDDY_MEMORY.md'),
|
|
1497
|
+
} : {}),
|
|
1450
1498
|
});
|
|
1451
|
-
|
|
1499
|
+
memoryManagers.set(key, manager);
|
|
1452
1500
|
}
|
|
1453
|
-
return
|
|
1501
|
+
return manager;
|
|
1454
1502
|
}
|
|
1455
1503
|
export function resetMemoryManagerForTests() {
|
|
1456
|
-
|
|
1457
|
-
memoryManagerByBot.clear();
|
|
1504
|
+
memoryManagers.clear();
|
|
1458
1505
|
}
|
|
1459
|
-
export async function initializeMemory(config) {
|
|
1460
|
-
const manager = getMemoryManager(config);
|
|
1506
|
+
export async function initializeMemory(config, cwd) {
|
|
1507
|
+
const manager = getMemoryManager(config, undefined, cwd);
|
|
1461
1508
|
await manager.initialize();
|
|
1462
1509
|
return manager;
|
|
1463
1510
|
}
|
|
@@ -10,7 +10,7 @@ import * as os from 'os';
|
|
|
10
10
|
import * as crypto from 'crypto';
|
|
11
11
|
import { logger } from '../utils/logger.js';
|
|
12
12
|
import { getPlatformCommands } from './platform-commands.js';
|
|
13
|
-
import {
|
|
13
|
+
import { readDeviceStoreFile, updateDeviceStoreFile } from '../utils/device-store-file.js';
|
|
14
14
|
function validCoordinates(lat, lon) {
|
|
15
15
|
const latitude = typeof lat === 'number'
|
|
16
16
|
? lat
|
|
@@ -74,13 +74,9 @@ export class DeviceNodeManager {
|
|
|
74
74
|
// ==========================================================================
|
|
75
75
|
loadDevices() {
|
|
76
76
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
value.version === DEVICES_VERSION &&
|
|
81
|
-
Array.isArray(value.devices)),
|
|
82
|
-
});
|
|
83
|
-
if (data) {
|
|
77
|
+
// The shared envelope also carries revocations; never restore stale backups.
|
|
78
|
+
const data = readDeviceStoreFile(DEVICES_FILE);
|
|
79
|
+
if (data.version === DEVICES_VERSION && Array.isArray(data.devices)) {
|
|
84
80
|
for (const d of data.devices) {
|
|
85
81
|
this.devices.set(d.id, d);
|
|
86
82
|
}
|
|
@@ -96,7 +92,7 @@ export class DeviceNodeManager {
|
|
|
96
92
|
version: DEVICES_VERSION,
|
|
97
93
|
devices: Array.from(this.devices.values()),
|
|
98
94
|
};
|
|
99
|
-
|
|
95
|
+
updateDeviceStoreFile(DEVICES_FILE, envelope => Object.assign(envelope, data));
|
|
100
96
|
}
|
|
101
97
|
catch (err) {
|
|
102
98
|
logger.warn('Failed to save devices', {
|
|
@@ -1,16 +1,29 @@
|
|
|
1
|
-
import { buildMobileSupervisionSnapshot, evaluateMobileSupervisionAction, } from './mobile-supervision-snapshot.js';
|
|
1
|
+
import { buildMobileSupervisionSnapshot, MOBILE_SUPERVISION_ALLOWED_ACTIONS, MOBILE_SUPERVISION_BLOCKED_ACTIONS, evaluateMobileSupervisionAction, } from './mobile-supervision-snapshot.js';
|
|
2
2
|
export const MOBILE_SUPERVISION_GATEWAY_CONTRACT_SCHEMA_VERSION = 1;
|
|
3
3
|
export async function buildMobileSupervisionGatewayContract(query, options = {}) {
|
|
4
|
-
|
|
4
|
+
// A contract-only preview must not query run/session databases. Besides
|
|
5
|
+
// unnecessary I/O, loading a host-native SQLite store in Electron can abort
|
|
6
|
+
// the process before a rejected promise can be caught by the IPC bridge.
|
|
7
|
+
const snapshot = options.includeSnapshot === false
|
|
8
|
+
? undefined
|
|
9
|
+
: await buildMobileSupervisionSnapshot(query, options);
|
|
10
|
+
const policy = snapshot ?? {
|
|
11
|
+
allowedActions: [...MOBILE_SUPERVISION_ALLOWED_ACTIONS],
|
|
12
|
+
blockedActions: [...MOBILE_SUPERVISION_BLOCKED_ACTIONS],
|
|
13
|
+
safety: {
|
|
14
|
+
autoDispatch: false, localApprovalRequired: true, outreachDisabled: true,
|
|
15
|
+
remoteExecutionDisabled: true, redaction: 'secrets-redacted',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
5
18
|
const basePath = normalizeBasePath(options.basePath);
|
|
6
19
|
const auth = buildGatewayAuth();
|
|
7
|
-
const endpoints = buildGatewayEndpoints(
|
|
20
|
+
const endpoints = buildGatewayEndpoints(policy, basePath, auth);
|
|
8
21
|
return {
|
|
9
22
|
schemaVersion: MOBILE_SUPERVISION_GATEWAY_CONTRACT_SCHEMA_VERSION,
|
|
10
23
|
generatedAt: new Date().toISOString(),
|
|
11
24
|
mode: 'contract_only',
|
|
12
25
|
basePath,
|
|
13
|
-
query: snapshot.
|
|
26
|
+
query: snapshot?.query ?? query.trim(),
|
|
14
27
|
auth,
|
|
15
28
|
transport: {
|
|
16
29
|
exposure: 'local_first',
|
|
@@ -18,11 +31,11 @@ export async function buildMobileSupervisionGatewayContract(query, options = {})
|
|
|
18
31
|
remoteExecution: 'disabled',
|
|
19
32
|
},
|
|
20
33
|
endpoints,
|
|
21
|
-
blockedOperations:
|
|
34
|
+
blockedOperations: policy.blockedActions.map(action => ({
|
|
22
35
|
action,
|
|
23
|
-
policy: evaluateMobileSupervisionAction(
|
|
36
|
+
policy: evaluateMobileSupervisionAction(policy, action),
|
|
24
37
|
})),
|
|
25
|
-
snapshot
|
|
38
|
+
snapshot,
|
|
26
39
|
};
|
|
27
40
|
}
|
|
28
41
|
export function renderMobileSupervisionGatewayContract(contract) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WriteStream } from 'node:fs';
|
|
2
|
+
export interface RunPersistenceStatus {
|
|
3
|
+
state: 'pending' | 'flushed' | 'failed';
|
|
4
|
+
received: number;
|
|
5
|
+
written: number;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Tracks stream acknowledgements separately from in-memory observability. */
|
|
9
|
+
export declare class RunEventWriter {
|
|
10
|
+
private readonly stream;
|
|
11
|
+
private readonly onFailure;
|
|
12
|
+
private received;
|
|
13
|
+
private written;
|
|
14
|
+
private failure?;
|
|
15
|
+
constructor(stream: WriteStream, onFailure: (error: Error) => void);
|
|
16
|
+
private fail;
|
|
17
|
+
write(line: string): void;
|
|
18
|
+
status(): RunPersistenceStatus;
|
|
19
|
+
/** A stream flush, not an fsync guarantee. Rejects on any prior lost event. */
|
|
20
|
+
flush(): Promise<RunPersistenceStatus>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Tracks stream acknowledgements separately from in-memory observability. */
|
|
2
|
+
export class RunEventWriter {
|
|
3
|
+
stream;
|
|
4
|
+
onFailure;
|
|
5
|
+
received = 0;
|
|
6
|
+
written = 0;
|
|
7
|
+
failure;
|
|
8
|
+
constructor(stream, onFailure) {
|
|
9
|
+
this.stream = stream;
|
|
10
|
+
this.onFailure = onFailure;
|
|
11
|
+
stream.on('error', error => this.fail(error));
|
|
12
|
+
}
|
|
13
|
+
fail(error) {
|
|
14
|
+
if (this.failure)
|
|
15
|
+
return;
|
|
16
|
+
this.failure = error;
|
|
17
|
+
this.onFailure(error);
|
|
18
|
+
}
|
|
19
|
+
write(line) {
|
|
20
|
+
this.received++;
|
|
21
|
+
if (this.failure)
|
|
22
|
+
return;
|
|
23
|
+
if (this.stream.writableLength + Buffer.byteLength(line) > 1024 * 1024) {
|
|
24
|
+
this.fail(new Error('Run event queue exceeded 1 MiB; journal is incomplete'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
this.stream.write(line, error => {
|
|
29
|
+
if (error)
|
|
30
|
+
this.fail(error);
|
|
31
|
+
else
|
|
32
|
+
this.written++;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
status() {
|
|
40
|
+
return {
|
|
41
|
+
state: this.failure ? 'failed' : this.received === this.written ? 'flushed' : 'pending',
|
|
42
|
+
received: this.received,
|
|
43
|
+
written: this.written,
|
|
44
|
+
...(this.failure ? { error: this.failure.message } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** A stream flush, not an fsync guarantee. Rejects on any prior lost event. */
|
|
48
|
+
async flush() {
|
|
49
|
+
if (this.failure)
|
|
50
|
+
throw this.failure;
|
|
51
|
+
if (!this.stream.writableFinished) {
|
|
52
|
+
await new Promise((resolve, reject) => {
|
|
53
|
+
const cleanup = () => {
|
|
54
|
+
this.stream.removeListener('error', failed);
|
|
55
|
+
this.stream.removeListener('finish', finished);
|
|
56
|
+
this.stream.removeListener('close', closed);
|
|
57
|
+
};
|
|
58
|
+
const failed = (error) => { cleanup(); reject(error); };
|
|
59
|
+
const finished = () => { cleanup(); resolve(); };
|
|
60
|
+
const closed = () => {
|
|
61
|
+
if (this.stream.writableFinished)
|
|
62
|
+
finished();
|
|
63
|
+
else
|
|
64
|
+
failed(new Error('Run event stream closed before flush'));
|
|
65
|
+
};
|
|
66
|
+
this.stream.once('error', failed);
|
|
67
|
+
this.stream.once('close', closed);
|
|
68
|
+
if (this.stream.destroyed)
|
|
69
|
+
closed();
|
|
70
|
+
else if (this.stream.writableEnded)
|
|
71
|
+
this.stream.once('finish', finished);
|
|
72
|
+
else
|
|
73
|
+
this.stream.write('', error => error ? failed(error) : finished());
|
|
74
|
+
}).catch(error => { this.fail(error); throw error; });
|
|
75
|
+
}
|
|
76
|
+
if (this.failure)
|
|
77
|
+
throw this.failure;
|
|
78
|
+
return this.status();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=run-event-writer.js.map
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Written in append mode for performance — no full-file parsing per event.
|
|
10
10
|
* Automatic pruning keeps the 30 most recent runs.
|
|
11
11
|
*/
|
|
12
|
+
import { type RunPersistenceStatus } from './run-event-writer.js';
|
|
12
13
|
export type RunEventType = 'run_start' | 'run_end' | 'step_start' | 'step_end' | 'tool_call' | 'tool_result' | 'patch_created' | 'patch_applied' | 'decision' | 'error' | 'metric' | 'lesson_added' | 'lesson_candidate_proposed' | 'skill_selected' | 'context_snapshot' | 'pause_suggested';
|
|
13
14
|
export interface RunEvent {
|
|
14
15
|
ts: number;
|
|
@@ -57,6 +58,7 @@ export interface RunSummary {
|
|
|
57
58
|
metadata?: RunMetadata;
|
|
58
59
|
}
|
|
59
60
|
export interface RunRecord {
|
|
61
|
+
persistence?: RunPersistenceStatus;
|
|
60
62
|
summary: RunSummary;
|
|
61
63
|
metrics: Partial<RunMetrics>;
|
|
62
64
|
artifacts: string[];
|
|
@@ -160,6 +162,7 @@ export declare class RunStore {
|
|
|
160
162
|
private runsDir;
|
|
161
163
|
/** File handles for active run event streams */
|
|
162
164
|
private handles;
|
|
165
|
+
private eventWriters;
|
|
163
166
|
/** Immediate in-process view of events, avoiding read-after-write stream races. */
|
|
164
167
|
private eventBuffers;
|
|
165
168
|
/** In-memory event counts per run */
|
|
@@ -205,6 +208,8 @@ export declare class RunStore {
|
|
|
205
208
|
/**
|
|
206
209
|
* Emit an event for a run. Thread-safe: writes are serialized by the writable stream.
|
|
207
210
|
*/
|
|
211
|
+
getPersistenceStatus(runId: string): RunPersistenceStatus | undefined;
|
|
212
|
+
flushRun(runId: string): Promise<RunPersistenceStatus>;
|
|
208
213
|
emit(runId: string, event: Omit<RunEvent, 'ts' | 'runId'>): void;
|
|
209
214
|
/**
|
|
210
215
|
* End a run and flush the event stream.
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Written in append mode for performance — no full-file parsing per event.
|
|
10
10
|
* Automatic pruning keeps the 30 most recent runs.
|
|
11
11
|
*/
|
|
12
|
+
import { RunEventWriter } from './run-event-writer.js';
|
|
12
13
|
import fs from 'fs';
|
|
13
14
|
import path from 'path';
|
|
14
15
|
import os from 'os';
|
|
@@ -35,6 +36,7 @@ export class RunStore {
|
|
|
35
36
|
runsDir;
|
|
36
37
|
/** File handles for active run event streams */
|
|
37
38
|
handles = new Map();
|
|
39
|
+
eventWriters = new Map();
|
|
38
40
|
/** Immediate in-process view of events, avoiding read-after-write stream races. */
|
|
39
41
|
eventBuffers = new Map();
|
|
40
42
|
/** In-memory event counts per run */
|
|
@@ -129,12 +131,9 @@ export class RunStore {
|
|
|
129
131
|
const eventsPath = path.join(runDir, 'events.jsonl');
|
|
130
132
|
fs.writeFileSync(eventsPath, '', { flag: 'a' }); // ensure file exists
|
|
131
133
|
const ws = fs.createWriteStream(eventsPath, { flags: 'a', encoding: 'utf-8' });
|
|
132
|
-
|
|
133
|
-
logger.
|
|
134
|
-
|
|
135
|
-
err: err instanceof Error ? err.message : String(err),
|
|
136
|
-
});
|
|
137
|
-
});
|
|
134
|
+
this.eventWriters.set(runId, new RunEventWriter(ws, error => {
|
|
135
|
+
logger.warn('RunStore: journal persistence failed', { runId, error: error.message });
|
|
136
|
+
}));
|
|
138
137
|
this.handles.set(runId, ws);
|
|
139
138
|
// Emit run_start event
|
|
140
139
|
this.emit(runId, { type: 'run_start', data: { objective, metadata } });
|
|
@@ -198,6 +197,15 @@ export class RunStore {
|
|
|
198
197
|
/**
|
|
199
198
|
* Emit an event for a run. Thread-safe: writes are serialized by the writable stream.
|
|
200
199
|
*/
|
|
200
|
+
getPersistenceStatus(runId) {
|
|
201
|
+
return this.eventWriters.get(runId)?.status();
|
|
202
|
+
}
|
|
203
|
+
async flushRun(runId) {
|
|
204
|
+
const writer = this.eventWriters.get(runId);
|
|
205
|
+
if (!writer)
|
|
206
|
+
throw new Error(`No active journal writer for run ${runId}`);
|
|
207
|
+
return writer.flush();
|
|
208
|
+
}
|
|
201
209
|
emit(runId, event) {
|
|
202
210
|
const ws = this.handles.get(runId);
|
|
203
211
|
if (!ws)
|
|
@@ -211,12 +219,7 @@ export class RunStore {
|
|
|
211
219
|
if (buffer) {
|
|
212
220
|
buffer.push(fullEvent);
|
|
213
221
|
}
|
|
214
|
-
|
|
215
|
-
ws.write(JSON.stringify(fullEvent) + '\n');
|
|
216
|
-
}
|
|
217
|
-
catch (err) {
|
|
218
|
-
logger.debug('RunStore: failed to write event', { runId, err });
|
|
219
|
-
}
|
|
222
|
+
this.eventWriters.get(runId)?.write(JSON.stringify(fullEvent) + '\n');
|
|
220
223
|
// Update in-memory count
|
|
221
224
|
const count = (this.eventCounts.get(runId) || 0) + 1;
|
|
222
225
|
this.eventCounts.set(runId, count);
|
|
@@ -396,7 +399,8 @@ export class RunStore {
|
|
|
396
399
|
catch {
|
|
397
400
|
// Ignore
|
|
398
401
|
}
|
|
399
|
-
|
|
402
|
+
const persistence = this.getPersistenceStatus(runId);
|
|
403
|
+
return { summary, metrics, artifacts, ...(persistence ? { persistence } : {}) };
|
|
400
404
|
}
|
|
401
405
|
/**
|
|
402
406
|
* List runs, most recent first.
|
|
@@ -1055,6 +1059,7 @@ export class RunStore {
|
|
|
1055
1059
|
if (ws) {
|
|
1056
1060
|
ws.destroy();
|
|
1057
1061
|
this.handles.delete(s.runId);
|
|
1062
|
+
this.eventWriters.delete(s.runId);
|
|
1058
1063
|
}
|
|
1059
1064
|
// Remove directory after a short delay to let the stream fully close
|
|
1060
1065
|
setTimeout(() => {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* The CLI is only a presenter. No new telemetry is written.
|
|
6
6
|
*/
|
|
7
7
|
import os from 'node:os';
|
|
8
|
-
import { resolveToolEffect } from '../tools/
|
|
8
|
+
import { resolveToolEffect } from '../tools/tool-effect.js';
|
|
9
9
|
export const RUN_TRAJECTORY_SCHEMA_VERSION = 1;
|
|
10
10
|
export const RUN_TRAJECTORY_KIND = 'run_trajectory';
|
|
11
11
|
export function unlogged(reason) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompt Caching Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Tracks local prompt repetition and exact component changes. Cache hits and
|
|
5
|
+
* savings here are heuristics, not measurements of a provider's prompt cache.
|
|
6
6
|
*
|
|
7
7
|
* References:
|
|
8
8
|
* - OpenAI Prompt Caching: https://platform.openai.com/docs/guides/prompt-caching
|
|
@@ -31,6 +31,19 @@ export interface CacheStats {
|
|
|
31
31
|
estimatedCostSaved: number;
|
|
32
32
|
entries: number;
|
|
33
33
|
}
|
|
34
|
+
/** Consecutive raw observations within this manager, not provider cache usage. */
|
|
35
|
+
export interface PrefixStabilityStats {
|
|
36
|
+
system: {
|
|
37
|
+
observations: number;
|
|
38
|
+
unchanged: number;
|
|
39
|
+
changes: number;
|
|
40
|
+
};
|
|
41
|
+
tools: {
|
|
42
|
+
observations: number;
|
|
43
|
+
unchanged: number;
|
|
44
|
+
changes: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
34
47
|
/**
|
|
35
48
|
* Cache configuration
|
|
36
49
|
*/
|
|
@@ -58,11 +71,13 @@ export declare class PromptCacheManager extends EventEmitter {
|
|
|
58
71
|
private systemPromptHash;
|
|
59
72
|
private toolsHash;
|
|
60
73
|
private contextHashes;
|
|
74
|
+
private prefixStats;
|
|
61
75
|
constructor(config?: Partial<CacheConfig>);
|
|
62
76
|
/**
|
|
63
77
|
* Generate hash for content
|
|
64
78
|
*/
|
|
65
79
|
private hash;
|
|
80
|
+
private observePrefix;
|
|
66
81
|
/**
|
|
67
82
|
* Estimate token count (rough approximation)
|
|
68
83
|
*/
|
|
@@ -103,6 +118,8 @@ export declare class PromptCacheManager extends EventEmitter {
|
|
|
103
118
|
* Get cache statistics
|
|
104
119
|
*/
|
|
105
120
|
getStats(): CacheStats;
|
|
121
|
+
/** Includes short components below the cache threshold; stores no prompt text. */
|
|
122
|
+
getPrefixStats(): PrefixStabilityStats;
|
|
106
123
|
/**
|
|
107
124
|
* Format stats for display
|
|
108
125
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompt Caching Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Tracks local prompt repetition and exact component changes. Cache hits and
|
|
5
|
+
* savings here are heuristics, not measurements of a provider's prompt cache.
|
|
6
6
|
*
|
|
7
7
|
* References:
|
|
8
8
|
* - OpenAI Prompt Caching: https://platform.openai.com/docs/guides/prompt-caching
|
|
@@ -42,6 +42,11 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
42
42
|
systemPromptHash = null;
|
|
43
43
|
toolsHash = null;
|
|
44
44
|
contextHashes = new Map();
|
|
45
|
+
// Fixed-size diagnostics: retain only the previous component hashes and counts.
|
|
46
|
+
prefixStats = {
|
|
47
|
+
system: { observations: 0, unchanged: 0, changes: 0 },
|
|
48
|
+
tools: { observations: 0, unchanged: 0, changes: 0 },
|
|
49
|
+
};
|
|
45
50
|
constructor(config = {}) {
|
|
46
51
|
super();
|
|
47
52
|
this.config = { ...DEFAULT_CACHE_CONFIG, ...config };
|
|
@@ -52,6 +57,23 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
52
57
|
hash(content) {
|
|
53
58
|
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
54
59
|
}
|
|
60
|
+
observePrefix(type, hash) {
|
|
61
|
+
if (!this.config.enabled)
|
|
62
|
+
return;
|
|
63
|
+
const previous = type === 'system' ? this.systemPromptHash : this.toolsHash;
|
|
64
|
+
const stats = this.prefixStats[type];
|
|
65
|
+
stats.observations++;
|
|
66
|
+
if (previous !== null) {
|
|
67
|
+
if (previous === hash)
|
|
68
|
+
stats.unchanged++;
|
|
69
|
+
else
|
|
70
|
+
stats.changes++;
|
|
71
|
+
}
|
|
72
|
+
if (type === 'system')
|
|
73
|
+
this.systemPromptHash = hash;
|
|
74
|
+
else
|
|
75
|
+
this.toolsHash = hash;
|
|
76
|
+
}
|
|
55
77
|
/**
|
|
56
78
|
* Estimate token count (rough approximation)
|
|
57
79
|
*/
|
|
@@ -96,9 +118,9 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
96
118
|
cacheSystemPrompt(prompt) {
|
|
97
119
|
const hash = this.hash(prompt);
|
|
98
120
|
const tokens = this.estimateTokens(prompt);
|
|
121
|
+
this.observePrefix('system', hash);
|
|
99
122
|
if (tokens >= this.config.minTokensToCache) {
|
|
100
123
|
this.addEntry(hash, tokens, "system");
|
|
101
|
-
this.systemPromptHash = hash;
|
|
102
124
|
}
|
|
103
125
|
return hash;
|
|
104
126
|
}
|
|
@@ -109,9 +131,9 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
109
131
|
const content = JSON.stringify(tools);
|
|
110
132
|
const hash = this.hash(content);
|
|
111
133
|
const tokens = this.estimateTokens(content);
|
|
134
|
+
this.observePrefix('tools', hash);
|
|
112
135
|
if (tokens >= this.config.minTokensToCache) {
|
|
113
136
|
this.addEntry(hash, tokens, "tools");
|
|
114
|
-
this.toolsHash = hash;
|
|
115
137
|
}
|
|
116
138
|
return hash;
|
|
117
139
|
}
|
|
@@ -176,6 +198,13 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
176
198
|
getStats() {
|
|
177
199
|
return { ...this.stats };
|
|
178
200
|
}
|
|
201
|
+
/** Includes short components below the cache threshold; stores no prompt text. */
|
|
202
|
+
getPrefixStats() {
|
|
203
|
+
return {
|
|
204
|
+
system: { ...this.prefixStats.system },
|
|
205
|
+
tools: { ...this.prefixStats.tools },
|
|
206
|
+
};
|
|
207
|
+
}
|
|
179
208
|
/**
|
|
180
209
|
* Format stats for display
|
|
181
210
|
*/
|
|
@@ -184,8 +213,10 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
184
213
|
"📦 Prompt Cache Statistics",
|
|
185
214
|
`├─ Entries: ${this.stats.entries}`,
|
|
186
215
|
`├─ Hit Rate: ${(this.stats.hitRate * 100).toFixed(1)}%`,
|
|
187
|
-
`├─ Tokens
|
|
188
|
-
|
|
216
|
+
`├─ Est. Reused Tokens: ${this.stats.totalTokensSaved.toLocaleString()}`,
|
|
217
|
+
`├─ Est. Cost Saved (heuristic): $${this.stats.estimatedCostSaved.toFixed(4)}`,
|
|
218
|
+
`└─ Prefix Changes (local): system ${this.prefixStats.system.changes}, tools ${this.prefixStats.tools.changes}`,
|
|
219
|
+
'Local repetition estimates; provider cache usage is not measured.',
|
|
189
220
|
];
|
|
190
221
|
return lines.join("\n");
|
|
191
222
|
}
|
|
@@ -197,6 +228,10 @@ export class PromptCacheManager extends EventEmitter {
|
|
|
197
228
|
this.systemPromptHash = null;
|
|
198
229
|
this.toolsHash = null;
|
|
199
230
|
this.contextHashes.clear();
|
|
231
|
+
this.prefixStats = {
|
|
232
|
+
system: { observations: 0, unchanged: 0, changes: 0 },
|
|
233
|
+
tools: { observations: 0, unchanged: 0, changes: 0 },
|
|
234
|
+
};
|
|
200
235
|
logger.debug("Prompt cache cleared");
|
|
201
236
|
}
|
|
202
237
|
/**
|