@phuetz/code-buddy 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.fr.md +56 -0
- package/README.md +73 -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 +165 -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.js +19 -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 +1 -0
- package/dist/codebuddy/fleet-tool-defs.js +24 -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.js +1 -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 +4 -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.js +4 -0
- 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 +4 -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 +179 -0
- package/dist/doctor/integrations.js +227 -0
- package/dist/doctor/triage.d.ts +108 -0
- package/dist/doctor/triage.js +304 -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.js +6 -0
- 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/transports.d.ts +10 -5
- package/dist/mcp/transports.js +61 -99
- 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 +13 -5
- package/dist/services/runtime-settings-context.d.ts +73 -0
- package/dist/services/runtime-settings-context.js +69 -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 +21 -28
- 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 +9 -0
- package/dist/tools/registry/fleet-tools.js +22 -1
- 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/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/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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MCPServerConfig } from './types.js';
|
|
2
|
+
export type MCPImportSource = 'hermes' | 'openclaw';
|
|
3
|
+
export interface MCPImportResult {
|
|
4
|
+
servers: MCPServerConfig[];
|
|
5
|
+
warnings: string[];
|
|
6
|
+
rejected: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Supported subset: exact names and star globs. Unsupported exclusions must never broaden exposure. */
|
|
9
|
+
export declare function validateMCPToolFilter(filter: MCPServerConfig['toolFilter']): void;
|
|
10
|
+
export declare function mcpToolAllowed(name: string, filter: MCPServerConfig['toolFilter']): boolean;
|
|
11
|
+
/** Pure import: never resolve env, connect, run commands or transfer credentials. */
|
|
12
|
+
export declare function normalizeMCPImports(input: unknown, source: MCPImportSource): MCPImportResult;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { SECRET_PATTERNS } from '../security/secret-patterns.js';
|
|
2
|
+
const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
3
|
+
const sensitiveKey = /KEY|TOKEN|SECRET|PASSWORD|AUTHORIZATION|COOKIE/i;
|
|
4
|
+
const reference = /^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/;
|
|
5
|
+
const hasSecret = (value) => SECRET_PATTERNS.some(p => new RegExp(p.pattern.source, p.pattern.flags.replace('g', '')).test(value));
|
|
6
|
+
/** Supported subset: exact names and star globs. Unsupported exclusions must never broaden exposure. */
|
|
7
|
+
export function validateMCPToolFilter(filter) {
|
|
8
|
+
if (!filter)
|
|
9
|
+
return;
|
|
10
|
+
for (const patterns of [filter.include, filter.exclude]) {
|
|
11
|
+
if (patterns !== undefined && (!Array.isArray(patterns) || patterns.some(p => typeof p !== 'string' || !/^[A-Za-z0-9_.:*-]+$/.test(p)))) {
|
|
12
|
+
throw new Error('Unsupported MCP tool filter; only names and * are supported');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function mcpToolAllowed(name, filter) {
|
|
17
|
+
validateMCPToolFilter(filter);
|
|
18
|
+
const matches = (pattern) => new RegExp(`^${pattern.split('*').map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('.*')}$`).test(name);
|
|
19
|
+
return (!filter?.include || filter.include.some(matches)) && !filter?.exclude?.some(matches);
|
|
20
|
+
}
|
|
21
|
+
/** Pure import: never resolve env, connect, run commands or transfer credentials. */
|
|
22
|
+
export function normalizeMCPImports(input, source) {
|
|
23
|
+
const result = { servers: [], warnings: [], rejected: [] };
|
|
24
|
+
if (!record(input)) {
|
|
25
|
+
result.rejected.push('MCP server map must be an object');
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
for (const [name, raw] of Object.entries(input)) {
|
|
29
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,95}$/.test(name) || !record(raw)) {
|
|
30
|
+
result.rejected.push('Invalid MCP server entry');
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const warn = (message) => result.warnings.push(`${name}: ${message}`);
|
|
34
|
+
try {
|
|
35
|
+
const clean = (key, value) => {
|
|
36
|
+
if (typeof value !== 'string')
|
|
37
|
+
throw new Error('Expected string configuration value');
|
|
38
|
+
if (reference.test(value) || /^Bearer \$\{[A-Za-z_][A-Za-z0-9_]*\}$/i.test(value))
|
|
39
|
+
return value;
|
|
40
|
+
if (sensitiveKey.test(key) || /^(?:--)?[^=]*(?:token|secret|password|authorization|api[_-]?key)[^=]*=/i.test(value) || hasSecret(value)) {
|
|
41
|
+
const envName = `MCP_IMPORT_${name}_${key}`.replace(/[^A-Za-z0-9_]/g, '_').toUpperCase();
|
|
42
|
+
warn(`secret not copied; configure environment ${envName}`);
|
|
43
|
+
return '${' + envName + '}';
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
};
|
|
47
|
+
const map = (key) => {
|
|
48
|
+
if (raw[key] === undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
if (!record(raw[key]))
|
|
51
|
+
throw new Error(`Invalid ${key}`);
|
|
52
|
+
return Object.fromEntries(Object.entries(raw[key]).map(([k, v]) => [k, clean(`${key}_${k}`, v)]));
|
|
53
|
+
};
|
|
54
|
+
const type = raw.transport ?? raw.type;
|
|
55
|
+
let transport;
|
|
56
|
+
if (type === 'stdio' || (type === undefined && typeof raw.command === 'string')) {
|
|
57
|
+
if (typeof raw.command !== 'string' || !raw.command.trim())
|
|
58
|
+
throw new Error('stdio requires command');
|
|
59
|
+
if (raw.args !== undefined && (!Array.isArray(raw.args) || raw.args.some(a => typeof a !== 'string')))
|
|
60
|
+
throw new Error('Invalid args');
|
|
61
|
+
const args = (raw.args ?? []);
|
|
62
|
+
transport = { type: 'stdio', inheritEnv: false, command: clean('command', raw.command), args: args.map((v, i) => clean(sensitiveKey.test(args[i - 1] ?? '') ? `arg_secret_${i}` : `arg_${i}`, v)), env: map('env') };
|
|
63
|
+
if (raw.cwd !== undefined)
|
|
64
|
+
transport.cwd = clean('cwd', raw.cwd);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const mapped = type === undefined ? (source === 'hermes' ? 'streamable_http' : 'sse')
|
|
68
|
+
: type === 'http' || type === 'streamable-http' || type === 'streamable_http' ? 'streamable_http'
|
|
69
|
+
: type === 'sse' || type === 'sse_sdk' ? 'sse' : undefined;
|
|
70
|
+
if (!mapped)
|
|
71
|
+
throw new Error('Unsupported transport');
|
|
72
|
+
if (typeof raw.url !== 'string')
|
|
73
|
+
throw new Error('Remote transport requires URL');
|
|
74
|
+
if (!reference.test(raw.url)) {
|
|
75
|
+
const url = new URL(raw.url);
|
|
76
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.hash || url.search)
|
|
77
|
+
throw new Error('Remote URL must not contain credentials, query or fragment; use environment reference');
|
|
78
|
+
}
|
|
79
|
+
transport = { type: mapped, url: raw.url, headers: map('headers') };
|
|
80
|
+
if (type === undefined && source === 'hermes')
|
|
81
|
+
warn('streamable HTTP selected; implicit SSE fallback is not imported');
|
|
82
|
+
}
|
|
83
|
+
const server = { name, transport, enabled: raw.enabled !== false };
|
|
84
|
+
const filter = raw.toolFilter ?? raw.tool_filter ?? raw.tools;
|
|
85
|
+
if (filter !== undefined) {
|
|
86
|
+
if (!record(filter))
|
|
87
|
+
throw new Error('Invalid tool filter');
|
|
88
|
+
const allowedKeys = filter === raw.tools ? ['include', 'exclude', 'resources', 'prompts'] : ['include', 'exclude'];
|
|
89
|
+
if (Object.keys(filter).some(key => !allowedKeys.includes(key)))
|
|
90
|
+
throw new Error('Unsupported tool filter fields');
|
|
91
|
+
if (filter.resources !== undefined || filter.prompts !== undefined)
|
|
92
|
+
warn('resource/prompt utilities are not imported; Buddy imports native tools only');
|
|
93
|
+
if (filter.include !== undefined || filter.exclude !== undefined) {
|
|
94
|
+
server.toolFilter = { ...(filter.include !== undefined ? { include: typeof filter.include === 'string' ? [filter.include] : filter.include } : {}),
|
|
95
|
+
...(filter.exclude !== undefined ? { exclude: typeof filter.exclude === 'string' ? [filter.exclude] : filter.exclude } : {}) };
|
|
96
|
+
validateMCPToolFilter(server.toolFilter);
|
|
97
|
+
// OpenClaw treats an empty include as unrestricted, unlike Hermes.
|
|
98
|
+
if (source === 'openclaw' && server.toolFilter.include?.length === 0)
|
|
99
|
+
delete server.toolFilter.include;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (raw.auth !== undefined || raw.oauth !== undefined) {
|
|
103
|
+
server.enabled = false;
|
|
104
|
+
warn('authentication settings not imported; server disabled until operator configures authentication in Buddy');
|
|
105
|
+
}
|
|
106
|
+
result.servers.push(server);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
result.rejected.push(`${name}: unsupported or unsafe configuration; no values copied`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=import-normalize.js.map
|
package/dist/mcp/transports.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
|
-
export type TransportType = 'stdio' | 'http' | 'sse' | 'streamable_http';
|
|
3
|
+
export type TransportType = 'stdio' | 'http' | 'sse' | 'sse_sdk' | 'legacy_rpc' | 'streamable_http';
|
|
4
4
|
export interface TransportConfig {
|
|
5
5
|
type: TransportType;
|
|
6
6
|
command?: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
/** Imported stdio servers receive SDK baseline env plus explicit declarations only. */
|
|
9
|
+
inheritEnv?: boolean;
|
|
7
10
|
args?: string[];
|
|
8
11
|
env?: Record<string, string>;
|
|
9
12
|
url?: string;
|
|
@@ -31,9 +34,9 @@ export declare class HttpTransport extends EventEmitter implements MCPTransport
|
|
|
31
34
|
disconnect(): Promise<void>;
|
|
32
35
|
getType(): TransportType;
|
|
33
36
|
}
|
|
34
|
-
export declare class SSETransport
|
|
37
|
+
export declare class SSETransport implements MCPTransport {
|
|
35
38
|
private config;
|
|
36
|
-
private
|
|
39
|
+
private transport?;
|
|
37
40
|
constructor(config: TransportConfig);
|
|
38
41
|
connect(): Promise<Transport>;
|
|
39
42
|
disconnect(): Promise<void>;
|
|
@@ -41,10 +44,12 @@ export declare class SSETransport extends EventEmitter implements MCPTransport {
|
|
|
41
44
|
}
|
|
42
45
|
export declare class StreamableHttpTransport extends EventEmitter implements MCPTransport {
|
|
43
46
|
private config;
|
|
44
|
-
private
|
|
47
|
+
private transport?;
|
|
45
48
|
constructor(config: TransportConfig);
|
|
46
49
|
connect(): Promise<Transport>;
|
|
47
50
|
disconnect(): Promise<void>;
|
|
48
51
|
getType(): TransportType;
|
|
49
52
|
}
|
|
50
|
-
|
|
53
|
+
/** Resolve references only at connection time; missing credentials fail closed. */
|
|
54
|
+
export declare function resolveMCPTransport(config: TransportConfig): TransportConfig;
|
|
55
|
+
export declare function createTransport(input: TransportConfig): MCPTransport;
|
package/dist/mcp/transports.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SSEClientTransport as SDKSSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
2
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
|
+
import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
2
4
|
import { EventEmitter } from "events";
|
|
3
5
|
import axios from "axios";
|
|
4
6
|
import { logger } from '../utils/logger.js';
|
|
@@ -14,7 +16,7 @@ export class StdioTransport {
|
|
|
14
16
|
async connect() {
|
|
15
17
|
// Create transport with environment variables to suppress verbose output
|
|
16
18
|
const env = {
|
|
17
|
-
...process.env,
|
|
19
|
+
...(this.config.inheritEnv === false ? getDefaultEnvironment() : process.env),
|
|
18
20
|
...this.config.env,
|
|
19
21
|
// Try to suppress verbose output from mcp-remote
|
|
20
22
|
MCP_REMOTE_QUIET: '1',
|
|
@@ -25,6 +27,7 @@ export class StdioTransport {
|
|
|
25
27
|
const transportConfig = {
|
|
26
28
|
command: this.config.command,
|
|
27
29
|
args: this.config.args || [],
|
|
30
|
+
cwd: this.config.cwd,
|
|
28
31
|
env,
|
|
29
32
|
// The SDK default is stderr:'inherit', which lets a noisy MCP server
|
|
30
33
|
// (startup banners, progress logs) write raw bytes into the CLI's own
|
|
@@ -69,6 +72,7 @@ export class HttpTransport extends EventEmitter {
|
|
|
69
72
|
async connect() {
|
|
70
73
|
this.client = axios.create({
|
|
71
74
|
baseURL: this.config.url,
|
|
75
|
+
maxRedirects: 0,
|
|
72
76
|
headers: {
|
|
73
77
|
'Content-Type': 'application/json',
|
|
74
78
|
...this.config.headers
|
|
@@ -93,35 +97,28 @@ export class HttpTransport extends EventEmitter {
|
|
|
93
97
|
return 'http';
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
|
-
export class SSETransport
|
|
100
|
+
export class SSETransport {
|
|
97
101
|
config;
|
|
98
|
-
|
|
102
|
+
transport;
|
|
99
103
|
constructor(config) {
|
|
100
|
-
super();
|
|
101
104
|
this.config = config;
|
|
102
|
-
if (!config.url)
|
|
103
|
-
throw new Error('URL is required for SSE MCP transport
|
|
104
|
-
}
|
|
105
|
+
if (!config.url)
|
|
106
|
+
throw new Error('URL is required for SSE MCP transport');
|
|
105
107
|
}
|
|
106
108
|
async connect() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
reject(error);
|
|
116
|
-
}
|
|
109
|
+
this.transport = new SDKSSEClientTransport(new URL(this.config.url), {
|
|
110
|
+
requestInit: { headers: this.config.headers, redirect: 'error' },
|
|
111
|
+
eventSourceInit: { fetch: (url, init) => {
|
|
112
|
+
const headers = new Headers(init?.headers);
|
|
113
|
+
for (const [key, value] of Object.entries(this.config.headers ?? {}))
|
|
114
|
+
headers.set(key, value);
|
|
115
|
+
return fetch(url, { ...init, headers, redirect: 'error' });
|
|
116
|
+
} },
|
|
117
117
|
});
|
|
118
|
+
return this.transport;
|
|
118
119
|
}
|
|
119
|
-
async disconnect() {
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
getType() {
|
|
123
|
-
return 'sse';
|
|
124
|
-
}
|
|
120
|
+
async disconnect() { await this.transport?.close(); this.transport = undefined; }
|
|
121
|
+
getType() { return 'sse'; }
|
|
125
122
|
}
|
|
126
123
|
// Custom HTTP Transport implementation
|
|
127
124
|
class HttpClientTransport extends EventEmitter {
|
|
@@ -156,105 +153,70 @@ class HttpClientTransport extends EventEmitter {
|
|
|
156
153
|
}
|
|
157
154
|
}
|
|
158
155
|
}
|
|
159
|
-
// Custom SSE Transport implementation
|
|
160
|
-
class SSEClientTransport extends EventEmitter {
|
|
161
|
-
url;
|
|
162
|
-
onclose;
|
|
163
|
-
onerror;
|
|
164
|
-
onmessage;
|
|
165
|
-
sessionId;
|
|
166
|
-
constructor(url) {
|
|
167
|
-
super();
|
|
168
|
-
this.url = url;
|
|
169
|
-
}
|
|
170
|
-
async start() {
|
|
171
|
-
// SSE transport is event-driven, so we're always "started"
|
|
172
|
-
}
|
|
173
|
-
async close() {
|
|
174
|
-
// Nothing to close for basic SSE transport
|
|
175
|
-
}
|
|
176
|
-
async send(message, _options) {
|
|
177
|
-
// For bidirectional communication over SSE, we typically use HTTP POST
|
|
178
|
-
// for sending messages and SSE for receiving
|
|
179
|
-
try {
|
|
180
|
-
const response = await axios.post(this.url.replace('/sse', '/rpc'), message, {
|
|
181
|
-
headers: { 'Content-Type': 'application/json' }
|
|
182
|
-
});
|
|
183
|
-
if (this.onmessage && response.data) {
|
|
184
|
-
this.onmessage(response.data);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
const err = new Error(`SSE transport error: ${error}`);
|
|
189
|
-
if (this.onerror) {
|
|
190
|
-
this.onerror(err);
|
|
191
|
-
}
|
|
192
|
-
throw err;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
156
|
export class StreamableHttpTransport extends EventEmitter {
|
|
197
157
|
config;
|
|
198
|
-
|
|
158
|
+
transport;
|
|
199
159
|
constructor(config) {
|
|
200
160
|
super();
|
|
201
161
|
this.config = config;
|
|
202
|
-
if (!config.url)
|
|
162
|
+
if (!config.url)
|
|
203
163
|
throw new Error('URL is required for streamable_http transport');
|
|
204
|
-
}
|
|
205
164
|
}
|
|
206
165
|
async connect() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
reject(error);
|
|
214
|
-
}
|
|
166
|
+
const url = new URL(this.config.url);
|
|
167
|
+
if (!['http:', 'https:'].includes(url.protocol)) {
|
|
168
|
+
throw new Error('Streamable HTTP MCP requires an HTTP(S) URL');
|
|
169
|
+
}
|
|
170
|
+
this.transport = new StreamableHTTPClientTransport(url, {
|
|
171
|
+
requestInit: { headers: this.config.headers, redirect: 'error' },
|
|
215
172
|
});
|
|
173
|
+
return this.transport;
|
|
216
174
|
}
|
|
217
175
|
async disconnect() {
|
|
218
|
-
|
|
176
|
+
const transport = this.transport;
|
|
177
|
+
this.transport = undefined;
|
|
178
|
+
await transport?.close();
|
|
219
179
|
}
|
|
220
180
|
getType() {
|
|
221
181
|
return 'streamable_http';
|
|
222
182
|
}
|
|
223
183
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
logger.debug('StreamableHttpTransport: Message that would be sent', { message: _message });
|
|
246
|
-
// For now, throw an error to indicate the transport type is not compatible
|
|
247
|
-
// with the MCP protocol's request-response pattern
|
|
248
|
-
throw new Error('StreamableHttpTransport: SSE endpoints are not compatible with MCP request-response pattern. GitHub Copilot MCP may require a different integration approach.');
|
|
184
|
+
/** Resolve references only at connection time; missing credentials fail closed. */
|
|
185
|
+
export function resolveMCPTransport(config) {
|
|
186
|
+
const resolve = (value) => value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, key) => {
|
|
187
|
+
const result = process.env[key];
|
|
188
|
+
if (!result)
|
|
189
|
+
throw new Error(`Missing MCP environment reference: ${key}`);
|
|
190
|
+
return result;
|
|
191
|
+
});
|
|
192
|
+
const map = (values) => values && Object.fromEntries(Object.entries(values).map(([k, v]) => [k, resolve(v)]));
|
|
193
|
+
const resolved = { ...config, command: config.command && resolve(config.command), cwd: config.cwd && resolve(config.cwd),
|
|
194
|
+
args: config.args?.map(resolve), env: map(config.env), headers: map(config.headers), url: config.url && resolve(config.url) };
|
|
195
|
+
if (resolved.url) {
|
|
196
|
+
let url;
|
|
197
|
+
try {
|
|
198
|
+
url = new URL(resolved.url);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
throw new Error('Invalid MCP endpoint configuration');
|
|
202
|
+
}
|
|
203
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
204
|
+
throw new Error('MCP requires HTTP(S) without embedded credentials, query or fragment');
|
|
249
205
|
}
|
|
206
|
+
return resolved;
|
|
250
207
|
}
|
|
251
|
-
export function createTransport(
|
|
208
|
+
export function createTransport(input) {
|
|
209
|
+
const config = resolveMCPTransport(input);
|
|
252
210
|
switch (config.type) {
|
|
253
211
|
case 'stdio':
|
|
254
212
|
return new StdioTransport(config);
|
|
255
213
|
case 'http':
|
|
214
|
+
logger.warn('MCP http /rpc transport is deprecated; use legacy_rpc explicitly or streamable_http for MCP HTTP');
|
|
215
|
+
return new HttpTransport(config);
|
|
216
|
+
case 'legacy_rpc':
|
|
256
217
|
return new HttpTransport(config);
|
|
257
218
|
case 'sse':
|
|
219
|
+
case 'sse_sdk':
|
|
258
220
|
return new SSETransport(config);
|
|
259
221
|
case 'streamable_http':
|
|
260
222
|
return new StreamableHttpTransport(config);
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface MCPServerConfig {
|
|
|
15
15
|
maxRetries?: number;
|
|
16
16
|
/** Optional: Enable/disable this server (default: true) */
|
|
17
17
|
enabled?: boolean;
|
|
18
|
+
/** Exact names and star globs; exclusions win. Empty include denies every tool. */
|
|
19
|
+
toolFilter?: {
|
|
20
|
+
include?: string[];
|
|
21
|
+
exclude?: string[];
|
|
22
|
+
};
|
|
18
23
|
}
|
|
19
24
|
export type ServerStatus = 'connecting' | 'connected' | 'disconnected' | 'error';
|
|
20
25
|
export interface MCPTool {
|
|
@@ -473,12 +473,6 @@ export declare const comfyUIRecipeSchema: z.ZodObject<{
|
|
|
473
473
|
name?: string | undefined;
|
|
474
474
|
url?: string | undefined;
|
|
475
475
|
};
|
|
476
|
-
schemaVersion: 1;
|
|
477
|
-
fallback: {
|
|
478
|
-
id: string;
|
|
479
|
-
reason?: string | undefined;
|
|
480
|
-
version?: string | undefined;
|
|
481
|
-
}[];
|
|
482
476
|
resources: {
|
|
483
477
|
tier: "high" | "low" | "balanced" | "extreme";
|
|
484
478
|
maxConcurrency: number;
|
|
@@ -486,6 +480,12 @@ export declare const comfyUIRecipeSchema: z.ZodObject<{
|
|
|
486
480
|
minRamMiB: number;
|
|
487
481
|
estimatedSeconds?: number | undefined;
|
|
488
482
|
};
|
|
483
|
+
schemaVersion: 1;
|
|
484
|
+
fallback: {
|
|
485
|
+
id: string;
|
|
486
|
+
reason?: string | undefined;
|
|
487
|
+
version?: string | undefined;
|
|
488
|
+
}[];
|
|
489
489
|
bindings: {
|
|
490
490
|
prompt: {
|
|
491
491
|
input: string;
|
|
@@ -573,7 +573,6 @@ export declare const comfyUIRecipeSchema: z.ZodObject<{
|
|
|
573
573
|
name?: string | undefined;
|
|
574
574
|
url?: string | undefined;
|
|
575
575
|
};
|
|
576
|
-
schemaVersion: 1;
|
|
577
576
|
resources: {
|
|
578
577
|
tier: "high" | "low" | "balanced" | "extreme";
|
|
579
578
|
minVramMiB: number;
|
|
@@ -581,6 +580,7 @@ export declare const comfyUIRecipeSchema: z.ZodObject<{
|
|
|
581
580
|
maxConcurrency?: number | undefined;
|
|
582
581
|
estimatedSeconds?: number | undefined;
|
|
583
582
|
};
|
|
583
|
+
schemaVersion: 1;
|
|
584
584
|
bindings: {
|
|
585
585
|
prompt: {
|
|
586
586
|
input: string;
|
|
@@ -63,8 +63,18 @@ export declare const ReconciliationActionSchema: z.ZodObject<{
|
|
|
63
63
|
} | undefined;
|
|
64
64
|
}>;
|
|
65
65
|
export type ReconciliationAction = z.infer<typeof ReconciliationActionSchema>;
|
|
66
|
+
/** Keep concurrent command sessions on their own provider, including an explicit offline scope. */
|
|
67
|
+
export declare function withFactsMemorySessionClient<T>(client: CodeBuddyClient | null, action: () => T): T;
|
|
68
|
+
/**
|
|
69
|
+
* Async generators execute on next/return/throw, not when they are created.
|
|
70
|
+
* Scope every resumption so model/tool/cleanup work belongs to this agent,
|
|
71
|
+
* while consumers outside a yielded event keep their own async context.
|
|
72
|
+
*/
|
|
73
|
+
export declare function bindFactsMemorySession<T>(client: CodeBuddyClient, iterator: AsyncGenerator<T, void, unknown>): AsyncGenerator<T, void, unknown>;
|
|
74
|
+
export declare function setFactsMemorySessionClient(client: CodeBuddyClient | null): void;
|
|
66
75
|
export declare class FactsMemoryService {
|
|
67
|
-
private
|
|
76
|
+
private readonly explicitClient;
|
|
77
|
+
private fallbackClient;
|
|
68
78
|
constructor(client?: CodeBuddyClient);
|
|
69
79
|
isAvailable(): Promise<boolean>;
|
|
70
80
|
private getClient;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { logger } from '../utils/logger.js';
|
|
3
4
|
import { CodeBuddyClient } from '../codebuddy/client.js';
|
|
@@ -30,20 +31,58 @@ export const ReconciliationActionSchema = z.object({
|
|
|
30
31
|
targetIndex: z.number().optional(),
|
|
31
32
|
fact: FactSchema.optional()
|
|
32
33
|
});
|
|
34
|
+
/**
|
|
35
|
+
* Client of the live session (the provider and endpoint the user actually
|
|
36
|
+
* started with). Without it, reconciliation fell back to environment
|
|
37
|
+
* auto-detection and could send project memories to a different, cloud
|
|
38
|
+
* provider than the local session (e.g. xAI because GROK_API_KEY was set while
|
|
39
|
+
* the CLI ran on --base-url http://127.0.0.1:11434/v1).
|
|
40
|
+
*/
|
|
41
|
+
let sessionClient = null;
|
|
42
|
+
const sessionScope = new AsyncLocalStorage();
|
|
43
|
+
/** Keep concurrent command sessions on their own provider, including an explicit offline scope. */
|
|
44
|
+
export function withFactsMemorySessionClient(client, action) {
|
|
45
|
+
return sessionScope.run({ client }, action);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Async generators execute on next/return/throw, not when they are created.
|
|
49
|
+
* Scope every resumption so model/tool/cleanup work belongs to this agent,
|
|
50
|
+
* while consumers outside a yielded event keep their own async context.
|
|
51
|
+
*/
|
|
52
|
+
export function bindFactsMemorySession(client, iterator) {
|
|
53
|
+
return {
|
|
54
|
+
next(...args) { return withFactsMemorySessionClient(client, () => iterator.next(...args)); },
|
|
55
|
+
return(value) { return withFactsMemorySessionClient(client, () => iterator.return(value)); },
|
|
56
|
+
throw(error) { return withFactsMemorySessionClient(client, () => iterator.throw(error)); },
|
|
57
|
+
[Symbol.asyncIterator]() { return this; },
|
|
58
|
+
async [Symbol.asyncDispose]() {
|
|
59
|
+
await withFactsMemorySessionClient(client, () => iterator.return());
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function setFactsMemorySessionClient(client) {
|
|
64
|
+
sessionClient = client;
|
|
65
|
+
}
|
|
33
66
|
export class FactsMemoryService {
|
|
34
|
-
|
|
67
|
+
explicitClient;
|
|
68
|
+
fallbackClient = null;
|
|
35
69
|
constructor(client) {
|
|
36
|
-
|
|
37
|
-
this.client = client;
|
|
38
|
-
}
|
|
70
|
+
this.explicitClient = client ?? null;
|
|
39
71
|
}
|
|
40
72
|
async isAvailable() {
|
|
41
73
|
const client = await this.getClient();
|
|
42
74
|
return client !== null;
|
|
43
75
|
}
|
|
44
76
|
async getClient() {
|
|
45
|
-
if (this.
|
|
46
|
-
return this.
|
|
77
|
+
if (this.explicitClient)
|
|
78
|
+
return this.explicitClient;
|
|
79
|
+
const scoped = sessionScope.getStore();
|
|
80
|
+
if (scoped)
|
|
81
|
+
return scoped.client;
|
|
82
|
+
if (sessionClient)
|
|
83
|
+
return sessionClient;
|
|
84
|
+
if (this.fallbackClient)
|
|
85
|
+
return this.fallbackClient;
|
|
47
86
|
// Skip auto-detecting client in unit tests to prevent timeouts/real API calls
|
|
48
87
|
if (process.env.NODE_ENV === 'test' || process.env.VITEST) {
|
|
49
88
|
return null;
|
|
@@ -53,8 +92,8 @@ export class FactsMemoryService {
|
|
|
53
92
|
logger.warn('[FactsMemory] No LLM provider configuration found.');
|
|
54
93
|
return null;
|
|
55
94
|
}
|
|
56
|
-
this.
|
|
57
|
-
return this.
|
|
95
|
+
this.fallbackClient = new CodeBuddyClient(detected.apiKey, detected.defaultModel, detected.baseURL);
|
|
96
|
+
return this.fallbackClient;
|
|
58
97
|
}
|
|
59
98
|
/**
|
|
60
99
|
* Extract atom facts from a conversation or context block.
|
|
@@ -72,7 +72,7 @@ export interface MemoryCandidateStats {
|
|
|
72
72
|
total: number;
|
|
73
73
|
byStatus: Record<MemoryCandidateStatus, number>;
|
|
74
74
|
}
|
|
75
|
-
export declare function getMemoryCandidateQueue(workDir?: string): MemoryCandidateQueue;
|
|
75
|
+
export declare function getMemoryCandidateQueue(workDir?: string, botId?: string): MemoryCandidateQueue;
|
|
76
76
|
export declare function resetMemoryCandidateQueues(): void;
|
|
77
77
|
export declare class MemoryCandidateQueue {
|
|
78
78
|
private workDir;
|
|
@@ -80,7 +80,7 @@ export declare class MemoryCandidateQueue {
|
|
|
80
80
|
private filePath;
|
|
81
81
|
private candidates;
|
|
82
82
|
private loaded;
|
|
83
|
-
constructor(workDir?: string, memoryManager?: PersistentMemoryManager | undefined);
|
|
83
|
+
constructor(workDir?: string, memoryManager?: PersistentMemoryManager | undefined, botId?: string);
|
|
84
84
|
propose(input: ProposeMemoryCandidateInput): ProposeMemoryCandidateResult;
|
|
85
85
|
list(status?: MemoryCandidateStatus): MemoryCandidate[];
|
|
86
86
|
get(id: string): MemoryCandidate | null;
|
|
@@ -22,10 +22,10 @@ const VALID_CATEGORIES = [
|
|
|
22
22
|
'custom',
|
|
23
23
|
];
|
|
24
24
|
const registry = new Map();
|
|
25
|
-
export function getMemoryCandidateQueue(workDir = process.cwd()) {
|
|
26
|
-
const key = path.resolve(workDir);
|
|
25
|
+
export function getMemoryCandidateQueue(workDir = process.cwd(), botId) {
|
|
26
|
+
const key = JSON.stringify([path.resolve(workDir), botId ?? '']);
|
|
27
27
|
if (!registry.has(key)) {
|
|
28
|
-
registry.set(key, new MemoryCandidateQueue(
|
|
28
|
+
registry.set(key, new MemoryCandidateQueue(path.resolve(workDir), botId ? getMemoryManager(undefined, botId, workDir) : undefined, botId));
|
|
29
29
|
if (registry.size > 20) {
|
|
30
30
|
const firstKey = registry.keys().next().value;
|
|
31
31
|
if (firstKey)
|
|
@@ -43,10 +43,10 @@ export class MemoryCandidateQueue {
|
|
|
43
43
|
filePath;
|
|
44
44
|
candidates = [];
|
|
45
45
|
loaded = false;
|
|
46
|
-
constructor(workDir = process.cwd(), memoryManager) {
|
|
46
|
+
constructor(workDir = process.cwd(), memoryManager, botId) {
|
|
47
47
|
this.workDir = workDir;
|
|
48
48
|
this.memoryManager = memoryManager;
|
|
49
|
-
this.filePath = path.join(workDir, '.codebuddy', 'memory-candidates.json');
|
|
49
|
+
this.filePath = path.join(workDir, '.codebuddy', botId ? `memory-candidates-${encodeURIComponent(botId)}.json` : 'memory-candidates.json');
|
|
50
50
|
}
|
|
51
51
|
propose(input) {
|
|
52
52
|
this.load();
|
|
@@ -122,7 +122,7 @@ export class MemoryCandidateQueue {
|
|
|
122
122
|
throw new Error('Accepted memory key cannot be empty.');
|
|
123
123
|
if (!value)
|
|
124
124
|
throw new Error('Accepted memory value cannot be empty.');
|
|
125
|
-
const manager = this.memoryManager ?? getMemoryManager();
|
|
125
|
+
const manager = this.memoryManager ?? getMemoryManager(undefined, undefined, this.workDir);
|
|
126
126
|
await manager.initialize();
|
|
127
127
|
const write = await manager.remember(key, value, {
|
|
128
128
|
scope,
|
|
@@ -53,6 +53,15 @@ export interface MemoryWriteResult {
|
|
|
53
53
|
category?: MemoryCategory;
|
|
54
54
|
usage: MemoryUsage;
|
|
55
55
|
message: string;
|
|
56
|
+
/**
|
|
57
|
+
* Outcome of the optional LLM fact reconciliation, separate from the primary
|
|
58
|
+
* write: `failed` means the memory was still written directly and existing
|
|
59
|
+
* memories were restored unchanged.
|
|
60
|
+
*/
|
|
61
|
+
reconciliation?: {
|
|
62
|
+
status: 'applied' | 'skipped' | 'failed';
|
|
63
|
+
reason?: string;
|
|
64
|
+
};
|
|
56
65
|
}
|
|
57
66
|
export declare class MemoryWriteRejectedError extends Error {
|
|
58
67
|
readonly code: 'memory_limit_exceeded' | 'memory_security_rejected';
|
|
@@ -164,6 +173,8 @@ export declare class PersistentMemoryManager extends EventEmitter {
|
|
|
164
173
|
* poking the private maps. Does NOT reinforce (unlike getRelevantMemories).
|
|
165
174
|
*/
|
|
166
175
|
listMemories(scope: MemoryScope): Memory[];
|
|
176
|
+
/** Guard the result, including model renames/omissions, rather than trusting DELETE alone. */
|
|
177
|
+
private guardReconciliation;
|
|
167
178
|
/**
|
|
168
179
|
* Ebbinghaus forgetting pass (recoverable): memories whose retention decayed
|
|
169
180
|
* below the threshold are appended to a sibling `*.archive.md`, then removed.
|
|
@@ -250,12 +261,6 @@ export declare class PersistentMemoryManager extends EventEmitter {
|
|
|
250
261
|
};
|
|
251
262
|
private assertScopeReadable;
|
|
252
263
|
}
|
|
253
|
-
|
|
254
|
-
* Get the memory manager. With no `botId`, returns the global singleton (default
|
|
255
|
-
* — CLI / desktop / server behavior unchanged). With a `botId` (multi-bot
|
|
256
|
-
* channels), returns a per-bot instance whose memory files live under
|
|
257
|
-
* `~/.codebuddy/bots/<botId>/`, so bots never share each other's `remember` facts.
|
|
258
|
-
*/
|
|
259
|
-
export declare function getMemoryManager(config?: Partial<MemoryConfig>, botId?: string): PersistentMemoryManager;
|
|
264
|
+
export declare function getMemoryManager(config?: Partial<MemoryConfig>, botId?: string, cwd?: string): PersistentMemoryManager;
|
|
260
265
|
export declare function resetMemoryManagerForTests(): void;
|
|
261
|
-
export declare function initializeMemory(config?: Partial<MemoryConfig
|
|
266
|
+
export declare function initializeMemory(config?: Partial<MemoryConfig>, cwd?: string): Promise<PersistentMemoryManager>;
|