@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
package/dist/codebuddy/tools.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { A2A_CALL_TOOL_DEF } from './a2a-call-tool-defs.js';
|
|
2
|
+
import { RESOURCE_CATALOG_TOOL_DEF } from './resource-catalog-tool-defs.js';
|
|
3
|
+
import { RAGCHAT_TOOL_DEF } from './ragchat-tool-defs.js';
|
|
4
|
+
import { integrationToolHints } from '../tools/integration-tool-hints.js';
|
|
1
5
|
/**
|
|
2
6
|
* Grok Tools
|
|
3
7
|
*
|
|
4
8
|
* Main entry point for tool definitions and management.
|
|
5
9
|
* Tools are now organized in modular files under tool-definitions/.
|
|
6
10
|
*/
|
|
7
|
-
import {
|
|
11
|
+
import { TOOL_METADATA as SEARCH_TOOL_METADATA } from '../tools/metadata.js';
|
|
12
|
+
import { setDeferredMCPSchemas, resolveDeferredSchemas as resolveSelectedSchemas } from "../tools/deferred-schema-state.js";
|
|
8
13
|
import { MCPManager } from "../mcp/client.js";
|
|
9
14
|
import { loadMCPConfig } from "../mcp/config.js";
|
|
10
15
|
import { getToolSelector, selectRelevantTools } from "../tools/tool-selector.js";
|
|
@@ -137,6 +142,7 @@ export function getBuiltinToolNames() {
|
|
|
137
142
|
MERGE_CONFLICT_TOOLS,
|
|
138
143
|
VULN_SCANNER_TOOLS,
|
|
139
144
|
SESSION_TOOLS,
|
|
145
|
+
[RAGCHAT_TOOL_DEF, RESOURCE_CATALOG_TOOL_DEF, A2A_CALL_TOOL_DEF],
|
|
140
146
|
FLEET_TOOLS,
|
|
141
147
|
CODE_EXPLORER_TOOLS,
|
|
142
148
|
WINDOWS_TOOLS,
|
|
@@ -269,6 +275,7 @@ export function initializeToolRegistry() {
|
|
|
269
275
|
registerGroup(SESSION_TOOLS);
|
|
270
276
|
// Fleet tools — peer_delegate, list_peers (Phase (d).17). Always available;
|
|
271
277
|
// peer_delegate returns a clear error when no peers are connected.
|
|
278
|
+
registerGroup([RAGCHAT_TOOL_DEF, RESOURCE_CATALOG_TOOL_DEF, A2A_CALL_TOOL_DEF]);
|
|
272
279
|
registerGroup(FLEET_TOOLS);
|
|
273
280
|
// CodeExplorer tools
|
|
274
281
|
registerGroup(CODE_EXPLORER_TOOLS);
|
|
@@ -593,6 +600,8 @@ export async function getAllCodeBuddyTools() {
|
|
|
593
600
|
initToolSearchIndex(allTools.map((t) => ({
|
|
594
601
|
name: t.function.name,
|
|
595
602
|
description: t.function.description ?? '',
|
|
603
|
+
parameters: t.function.parameters,
|
|
604
|
+
keywords: SEARCH_TOOL_METADATA.find(meta => meta.name === t.function.name)?.keywords,
|
|
596
605
|
})));
|
|
597
606
|
}
|
|
598
607
|
catch {
|
|
@@ -603,6 +612,12 @@ export async function getAllCodeBuddyTools() {
|
|
|
603
612
|
// ============================================================================
|
|
604
613
|
// Tool Selection (RAG-based)
|
|
605
614
|
// ============================================================================
|
|
615
|
+
/** Hydrate only names already exposed by assembly/selection; never add permissions. */
|
|
616
|
+
function hydrateExposedToolSchemas(tools) {
|
|
617
|
+
const resolved = new Map(resolveSelectedSchemas(tools.map(tool => tool.function.name))
|
|
618
|
+
.map(tool => [tool.function.name, tool]));
|
|
619
|
+
return tools.map(tool => resolved.get(tool.function.name) ?? tool);
|
|
620
|
+
}
|
|
606
621
|
/**
|
|
607
622
|
* Get relevant tools for a specific query using RAG-based selection
|
|
608
623
|
*
|
|
@@ -621,7 +636,7 @@ export async function getRelevantTools(query, options = {}) {
|
|
|
621
636
|
// If RAG is disabled, return all tools
|
|
622
637
|
if (!useRAG) {
|
|
623
638
|
return {
|
|
624
|
-
selectedTools: allTools,
|
|
639
|
+
selectedTools: hydrateExposedToolSchemas(allTools),
|
|
625
640
|
scores: new Map(allTools.map(t => [t.function.name, 1])),
|
|
626
641
|
classification: {
|
|
627
642
|
categories: ['file_read', 'file_write', 'system'],
|
|
@@ -633,7 +648,14 @@ export async function getRelevantTools(query, options = {}) {
|
|
|
633
648
|
originalTokens: 0
|
|
634
649
|
};
|
|
635
650
|
}
|
|
636
|
-
|
|
651
|
+
const preferred = integrationToolHints(query, allTools.map(tool => tool.function.name));
|
|
652
|
+
const selection = selectRelevantTools(query, allTools, maxTools, [
|
|
653
|
+
...(options.alwaysInclude ?? ['view_file', 'bash']), ...preferred,
|
|
654
|
+
]);
|
|
655
|
+
// Once selected, a deferred MCP tool must expose its argument schema.
|
|
656
|
+
// Empty stubs otherwise force valid models to emit {} for required inputs.
|
|
657
|
+
selection.selectedTools = hydrateExposedToolSchemas(selection.selectedTools);
|
|
658
|
+
return selection;
|
|
637
659
|
}
|
|
638
660
|
/**
|
|
639
661
|
* Classify a query to understand what types of tools are needed
|
|
@@ -144,16 +144,17 @@ export function registerDaemonCommands(program) {
|
|
|
144
144
|
const { getCronAgentBridge } = await import('../../daemon/cron-agent-bridge.js');
|
|
145
145
|
const { getCronScheduler } = await import('../../scheduler/cron-scheduler.js');
|
|
146
146
|
const { RunStore } = await import('../../observability/run-store.js');
|
|
147
|
+
const scheduler = getCronScheduler();
|
|
147
148
|
const bridge = getCronAgentBridge({
|
|
148
149
|
apiKey,
|
|
149
150
|
baseURL: process.env.GROK_BASE_URL,
|
|
150
151
|
model: process.env.GROK_MODEL || 'grok-3-latest',
|
|
151
152
|
maxToolRounds: 20,
|
|
152
153
|
jobTimeoutMs: 300000,
|
|
154
|
+
notepadDir: scheduler.notepadDir,
|
|
153
155
|
// Scheduled executions become first-class run records + artifacts.
|
|
154
156
|
runStore: RunStore.getInstance(),
|
|
155
157
|
});
|
|
156
|
-
const scheduler = getCronScheduler();
|
|
157
158
|
scheduler.setTaskExecutor(bridge.createTaskExecutor());
|
|
158
159
|
}
|
|
159
160
|
}
|
|
@@ -175,6 +176,7 @@ export function registerDaemonCommands(program) {
|
|
|
175
176
|
model: process.env.GROK_MODEL || 'grok-3-latest',
|
|
176
177
|
maxToolRounds: 20,
|
|
177
178
|
jobTimeoutMs: 600000,
|
|
179
|
+
notepadDir: scheduler.notepadDir,
|
|
178
180
|
runStore: RunStore.getInstance(),
|
|
179
181
|
});
|
|
180
182
|
scheduler.setTaskExecutor(bridge.createTaskExecutor());
|
|
@@ -129,6 +129,20 @@ export function registerEvolveCommands(program) {
|
|
|
129
129
|
process.exitCode = 1;
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
|
+
if (!v.passedAll || v.regressions.length || !/^[a-f0-9]{40,64}$/.test(v.sha)) {
|
|
133
|
+
logger.error('Variant is not eligible: missing verified commit, failed checks, or regressions.');
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
if (git(['rev-parse', '--verify', `${v.branch}^{commit}`]).trim() !== v.sha)
|
|
139
|
+
throw new Error('Variant branch changed since evaluation');
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
132
146
|
if (!options.confirm) {
|
|
133
147
|
logger.info(`Preview: keep ${v.id} (${v.branch}) → merge into '${current}'.`);
|
|
134
148
|
logger.info(` fitness=${v.score.toFixed(3)} passedAll=${v.passedAll} regressions=[${v.regressions.join(', ')}]`);
|
|
@@ -136,7 +150,7 @@ export function registerEvolveCommands(program) {
|
|
|
136
150
|
return;
|
|
137
151
|
}
|
|
138
152
|
try {
|
|
139
|
-
execFileSync('git', ['merge', '--no-ff', '-m', `evolve: keep ${v.id} (${v.detail ?? ''})`, v.
|
|
153
|
+
execFileSync('git', ['merge', '--no-ff', '-m', `evolve: keep ${v.id} (${v.detail ?? ''})`, v.sha], {
|
|
140
154
|
stdio: 'inherit',
|
|
141
155
|
});
|
|
142
156
|
logger.info(`Merged ${v.branch} into '${current}'. Review the result and run your full validation.`);
|
|
@@ -155,6 +169,7 @@ export function registerEvolveCommands(program) {
|
|
|
155
169
|
.option('--rounds <n>', 'Candidates per goal (fan-out), or max auto-weaknesses', '1')
|
|
156
170
|
.option('--concurrency <n>', 'How many candidates to evaluate at once', '2')
|
|
157
171
|
.option('--baseline <ref>', 'Baseline ref to branch from + rank against', 'main')
|
|
172
|
+
.option('--eval-task <ids...>', 'Opt in to whole-agent LLM eval tasks; default objective is the offline harness benchmark')
|
|
158
173
|
.option('--model <model>', 'Model for the mutator agent + planner')
|
|
159
174
|
.option('--model-bandit', 'Pick the mutator model per-cycle with the cost-aware UCB bandit (opt-in; overrides --model per cycle)')
|
|
160
175
|
.option('--no-plan', 'Skip deliberate planning (use the ad-hoc mutator prompt)')
|
|
@@ -173,11 +188,12 @@ export function registerEvolveCommands(program) {
|
|
|
173
188
|
}
|
|
174
189
|
const { runEvolutionRound, agentMutator, formatEvolveRoundSummary } = await import('../../agent/self-improvement/evolution/evolution-engine.js');
|
|
175
190
|
const { makeLlmVariantPlanner } = await import('../../agent/self-improvement/evolution/variant-planner.js');
|
|
176
|
-
const {
|
|
177
|
-
const
|
|
191
|
+
const { defaultDeterministicComponents, evalTasksComponent, harnessTasksComponent } = await import('../../agent/self-improvement/evolution/variant-fitness.js');
|
|
192
|
+
const { scoreReferenceInWorktree } = await import('../../agent/self-improvement/evolution/worktree-scorer.js');
|
|
193
|
+
const baselineRef = git(['rev-parse', '--verify', `${options.baseline ?? 'main'}^{commit}`]).trim();
|
|
178
194
|
const rounds = Math.max(1, Number(options.rounds ?? '1') || 1);
|
|
179
195
|
const concurrency = Math.max(1, Number(options.concurrency ?? '2') || 2);
|
|
180
|
-
const components = defaultDeterministicComponents();
|
|
196
|
+
const components = [...defaultDeterministicComponents(true), options.evalTask ? evalTasksComponent(options.evalTask) : harnessTasksComponent()];
|
|
181
197
|
const mutate = agentMutator(options.model ? { model: options.model } : {});
|
|
182
198
|
// Deliberate planner (default on). --no-plan → a planner that returns null → mutator's ad-hoc prompt.
|
|
183
199
|
const planner = options.plan === false
|
|
@@ -219,7 +235,7 @@ export function registerEvolveCommands(program) {
|
|
|
219
235
|
logger.info(`Selected ${weaknesses.length} weakness(es): ${weaknesses.map((w) => w.goal.slice(0, 60)).join(' | ')}`);
|
|
220
236
|
}
|
|
221
237
|
logger.info(`Scoring baseline (${baselineRef})…`);
|
|
222
|
-
const baseline = await
|
|
238
|
+
const baseline = (await scoreReferenceInWorktree(baselineRef, { components })).report;
|
|
223
239
|
logger.info(` baseline fitness=${baseline.score.toFixed(3)}`);
|
|
224
240
|
// Compounding: build each candidate on top of the current best elite (guarded by reachability
|
|
225
241
|
// in the engine → falls back to baseline if that elite branch was pruned). Fitness stays vs baseline.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
export function registerFleetCollaborationCommands(fleet) {
|
|
3
|
+
const run = async (options, goal) => {
|
|
4
|
+
const controller = new AbortController();
|
|
5
|
+
const stop = () => controller.abort();
|
|
6
|
+
process.once('SIGINT', stop);
|
|
7
|
+
process.once('SIGTERM', stop);
|
|
8
|
+
try {
|
|
9
|
+
const { parseCollaborationConfig, runCollaboration } = await import('../../fleet/collaboration.js');
|
|
10
|
+
const config = parseCollaborationConfig(JSON.parse(await readFile(options.config, 'utf8')));
|
|
11
|
+
const report = await runCollaboration(config, {
|
|
12
|
+
goal, timeoutMs: Number(options.timeout), signal: controller.signal,
|
|
13
|
+
onProgress: options.json ? undefined : message => { process.stderr.write(`${message}\n`); },
|
|
14
|
+
});
|
|
15
|
+
if (options.json)
|
|
16
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
17
|
+
else {
|
|
18
|
+
process.stdout.write(`Fleet: ${report.status}\n`);
|
|
19
|
+
for (const peer of report.peers) {
|
|
20
|
+
process.stdout.write(`\n${peer.id} — ${peer.status}${peer.model ? ` (${peer.model})` : ''}\n${peer.error ?? peer.text ?? 'Authenticated and ready for peer.chat'}\n`);
|
|
21
|
+
}
|
|
22
|
+
if (report.synthesis)
|
|
23
|
+
process.stdout.write(`\nSynthesis (${report.synthesis.peer})\n${report.synthesis.text}\n`);
|
|
24
|
+
if (report.synthesisError)
|
|
25
|
+
process.stdout.write(`\nSynthesis: ${report.synthesisError}\n`);
|
|
26
|
+
}
|
|
27
|
+
if (report.status !== 'complete')
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// Syntax errors can quote raw configuration, which may contain misplaced secrets.
|
|
32
|
+
const message = error instanceof SyntaxError ? 'Invalid fleet JSON configuration' : error instanceof Error ? error.message : 'Fleet operation failed';
|
|
33
|
+
if (options.json)
|
|
34
|
+
process.stdout.write(`${JSON.stringify({ status: 'failed', error: message })}\n`);
|
|
35
|
+
else
|
|
36
|
+
process.stderr.write(`${message}\n`);
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
process.removeListener('SIGINT', stop);
|
|
41
|
+
process.removeListener('SIGTERM', stop);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
fleet.command('check')
|
|
45
|
+
.description('Verify authenticated peers and chat readiness without calling an LLM')
|
|
46
|
+
.requiredOption('--config <file>', 'Fleet JSON configuration (token environment variable names only)')
|
|
47
|
+
.option('--timeout <ms>', 'Per-request timeout, 1000–300000 ms', '10000')
|
|
48
|
+
.option('--json', 'Structured report')
|
|
49
|
+
.action((options) => run(options));
|
|
50
|
+
fleet.command('collaborate <goal>')
|
|
51
|
+
.description('Collect parallel peer reviews, then synthesize them (no remote file edits)')
|
|
52
|
+
.requiredOption('--config <file>', 'Fleet JSON configuration (2–8 peers)')
|
|
53
|
+
.option('--timeout <ms>', 'Per-request timeout, 1000–300000 ms', '120000')
|
|
54
|
+
.option('--json', 'Structured report')
|
|
55
|
+
.action((goal, options) => run(options, goal));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=fleet-collaboration-commands.js.map
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* These commands expose the same dispatch profile policy decisions used by
|
|
5
5
|
* Cowork/Fleet so an operator can inspect a route before running it.
|
|
6
6
|
*/
|
|
7
|
+
import { registerFleetMissionCommands } from './fleet-mission-commands.js';
|
|
8
|
+
import { registerFleetCollaborationCommands } from './fleet-collaboration-commands.js';
|
|
9
|
+
import { registerFleetRoomsCommands } from './fleet-rooms-commands.js';
|
|
7
10
|
import { createTokenCommand, registerFleetTokenCommand } from '../token.js';
|
|
8
11
|
import { DEFAULT_DISPATCH_POLICY_PREVIEW_TOOLS, FLEET_DISPATCH_PROFILES, FLEET_DISPATCH_PROFILE_GUIDANCE, buildHermesToolsetDescriptor, getDispatchToolPolicy, normalizeDispatchProfile, previewDispatchToolDecisions, } from '../../fleet/dispatch-profile.js';
|
|
9
12
|
function resolveFleetServerUrl(serverUrl) {
|
|
@@ -68,6 +71,32 @@ export function registerFleetCommands(program) {
|
|
|
68
71
|
const fleet = program
|
|
69
72
|
.command('fleet')
|
|
70
73
|
.description('Inspect Fleet routing, toolsets, and dispatch policy decisions');
|
|
74
|
+
registerFleetMissionCommands(fleet);
|
|
75
|
+
registerFleetRoomsCommands(fleet);
|
|
76
|
+
registerFleetCollaborationCommands(fleet);
|
|
77
|
+
fleet.command('supervise <manifest> <operation>')
|
|
78
|
+
.description('Run a fixed local fleet operation through the Code Buddy harness')
|
|
79
|
+
.option('--json', 'Output the structured harness result')
|
|
80
|
+
.action(async (manifest, operation, options) => {
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const stop = () => controller.abort();
|
|
83
|
+
process.once('SIGINT', stop);
|
|
84
|
+
process.once('SIGTERM', stop);
|
|
85
|
+
try {
|
|
86
|
+
const { runSupervisor } = await import('../../harness/fleet-supervisor.js');
|
|
87
|
+
const result = await runSupervisor(manifest, operation, { signal: controller.signal });
|
|
88
|
+
console.log(options.json ? JSON.stringify({ kind: 'fleet_supervisor_result', operation, ...result }) : result.output ?? result.error ?? '');
|
|
89
|
+
if (!result.success)
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
printFleetServerError(error);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
process.removeListener('SIGINT', stop);
|
|
97
|
+
process.removeListener('SIGTERM', stop);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
71
100
|
fleet
|
|
72
101
|
.command('status')
|
|
73
102
|
.description('Show Fleet status from the configured Code Buddy server')
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { MissionStore } from '../../harness/mission-store.js';
|
|
5
|
+
import { runMission } from '../../harness/mission-runner.js';
|
|
6
|
+
import { parseSupervisorManifest } from '../../harness/fleet-supervisor.js';
|
|
7
|
+
/** All paths/manifests are operator input. No provider or server is booted. */
|
|
8
|
+
export function registerFleetMissionCommands(fleet) {
|
|
9
|
+
const group = fleet.command('mission').description('Durable local mission ownership, handoff and results');
|
|
10
|
+
const output = (action) => async (...args) => {
|
|
11
|
+
try {
|
|
12
|
+
console.log(JSON.stringify(await action(...args.filter(a => typeof a === 'string'))));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
group.command('list <store>')
|
|
20
|
+
.description('List mission metadata, with bounded pages and unreadable-record notices')
|
|
21
|
+
.option('--limit <count>', 'Maximum records examined in this page (1..100)', '25')
|
|
22
|
+
.option('--cursor <hash>', 'Continue after the previous page nextCursor')
|
|
23
|
+
.action((directory, options) => {
|
|
24
|
+
try {
|
|
25
|
+
console.log(JSON.stringify(new MissionStore(directory).list({ limit: Number(options.limit), cursor: options.cursor })));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
group.command('create <store> <id> <manifest> <operation>').action(output(async (directory, id, manifestPath, name) => {
|
|
33
|
+
const file = path.resolve(manifestPath);
|
|
34
|
+
const manifest = parseSupervisorManifest(JSON.parse(await fs.readFile(file, 'utf8')), path.dirname(file), 43200000);
|
|
35
|
+
const op = manifest.operations.get(name);
|
|
36
|
+
if (!op)
|
|
37
|
+
throw new Error('Unknown manifest operation');
|
|
38
|
+
return new MissionStore(directory).create(id, { command: op.command, args: op.args, timeoutMs: op.timeoutMs, workspace: manifest.workspace });
|
|
39
|
+
}));
|
|
40
|
+
group.command('show <store> <id>').action(output((directory, id) => new MissionStore(directory).get(id)));
|
|
41
|
+
group.command('claim <store> <id> <owner>').action(output((directory, id, owner) => new MissionStore(directory).claim(id, owner)));
|
|
42
|
+
group.command('renew <store> <id> <owner> <generation>').action(output((directory, id, owner, generation) => new MissionStore(directory).renew(id, { owner: owner, generation: generation })));
|
|
43
|
+
group.command('run <store> <id> <owner> <generation>').action(output(async (directory, id, owner, generation) => {
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const stop = () => controller.abort();
|
|
46
|
+
process.once('SIGINT', stop);
|
|
47
|
+
process.once('SIGTERM', stop);
|
|
48
|
+
try {
|
|
49
|
+
const mission = await runMission(new MissionStore(directory), id, { owner: owner, generation: generation }, controller.signal);
|
|
50
|
+
if (!mission.result?.success)
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return mission;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
process.removeListener('SIGINT', stop);
|
|
56
|
+
process.removeListener('SIGTERM', stop);
|
|
57
|
+
}
|
|
58
|
+
}));
|
|
59
|
+
group.command('handoff <store> <id> <owner> <generation> <capsule>').action(output(async (directory, id, owner, generation, capsule) => new MissionStore(directory).handoff(id, { owner: owner, generation: generation }, JSON.parse(await fs.readFile(capsule, 'utf8')))));
|
|
60
|
+
group.command('reconcile <store> <id> <generation> <resolution> <evidence>').action(output((directory, id, generation, resolution, evidence) => new MissionStore(directory).reconcile(id, generation, resolution, evidence)));
|
|
61
|
+
group.command('ack <store> <id> <consumer>').action(output((directory, id, consumer) => new MissionStore(directory).acknowledge(id, consumer)));
|
|
62
|
+
const head = (workspace) => execFileSync('git', ['rev-parse', '--verify', 'HEAD'], { cwd: workspace, encoding: 'utf8', timeout: 5000 }).trim();
|
|
63
|
+
group.command('submit <store> <id> <owner> <generation>').action(output((directory, id, owner, generation) => {
|
|
64
|
+
const store = new MissionStore(directory);
|
|
65
|
+
return store.submit(id, { owner: owner, generation: generation }, head(store.get(id).operation.workspace));
|
|
66
|
+
}));
|
|
67
|
+
group.command('approve <store> <id> <reviewer> <commit>').action(output((directory, id, reviewer, commit) => {
|
|
68
|
+
const store = new MissionStore(directory);
|
|
69
|
+
return store.approve(id, reviewer, commit);
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=fleet-mission-commands.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `buddy fleet rooms` — persistent signed messages between fleet members.
|
|
3
|
+
*
|
|
4
|
+
* Messages are data: `read` and `tail` print sanitized text and never run
|
|
5
|
+
* anything. Credentials come from the environment by default
|
|
6
|
+
* (`CODEBUDDY_FLEET_ROOMS_URL`, `CODEBUDDY_FLEET_API_KEY` / `CODEBUDDY_FLEET_TOKEN`);
|
|
7
|
+
* the member secret stays in its 0600 identity file and is never printed.
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from 'commander';
|
|
10
|
+
export declare function registerFleetRoomsCommands(fleet: Command): void;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `buddy fleet rooms` — persistent signed messages between fleet members.
|
|
3
|
+
*
|
|
4
|
+
* Messages are data: `read` and `tail` print sanitized text and never run
|
|
5
|
+
* anything. Credentials come from the environment by default
|
|
6
|
+
* (`CODEBUDDY_FLEET_ROOMS_URL`, `CODEBUDDY_FLEET_API_KEY` / `CODEBUDDY_FLEET_TOKEN`);
|
|
7
|
+
* the member secret stays in its 0600 identity file and is never printed.
|
|
8
|
+
*/
|
|
9
|
+
const collect = (value, previous) => [...previous, value];
|
|
10
|
+
function addConnectionOptions(command) {
|
|
11
|
+
return command
|
|
12
|
+
.option('--url <url>', 'hub WebSocket URL (default $CODEBUDDY_FLEET_ROOMS_URL)')
|
|
13
|
+
.option('--api-key <key>', 'hub API key with fleet:listen (prefer $CODEBUDDY_FLEET_API_KEY)')
|
|
14
|
+
.option('--jwt <token>', 'hub JWT with fleet:listen (prefer $CODEBUDDY_FLEET_TOKEN)')
|
|
15
|
+
.option('--audience <url>', 'hub URL to sign for when reached through a proxy')
|
|
16
|
+
.option('--identity <file>', 'member identity file (default $CODEBUDDY_FLEET_ROOMS_IDENTITY)')
|
|
17
|
+
.option('--json', 'machine-readable output');
|
|
18
|
+
}
|
|
19
|
+
function fail(error) {
|
|
20
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
}
|
|
23
|
+
async function connect(options) {
|
|
24
|
+
const url = options.url ?? process.env.CODEBUDDY_FLEET_ROOMS_URL;
|
|
25
|
+
if (!url)
|
|
26
|
+
throw new Error('hub URL required: --url or CODEBUDDY_FLEET_ROOMS_URL');
|
|
27
|
+
const apiKey = options.apiKey ?? process.env.CODEBUDDY_FLEET_API_KEY;
|
|
28
|
+
const jwt = options.jwt ?? process.env.CODEBUDDY_FLEET_TOKEN;
|
|
29
|
+
const [{ FleetRoomClient }, { loadRoomIdentity }] = await Promise.all([
|
|
30
|
+
import('../../fleet/rooms/room-client.js'),
|
|
31
|
+
import('../../fleet/rooms/room-identity.js'),
|
|
32
|
+
]);
|
|
33
|
+
const identity = loadRoomIdentity(options.identity);
|
|
34
|
+
const client = new FleetRoomClient({
|
|
35
|
+
url,
|
|
36
|
+
secretKey: identity.secretKey,
|
|
37
|
+
...(apiKey ? { apiKey } : jwt ? { jwt } : {}),
|
|
38
|
+
...(options.audience ? { audience: options.audience } : {}),
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const session = await client.connect();
|
|
42
|
+
return { client, session };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
await client.close();
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function toJson(message) {
|
|
50
|
+
return {
|
|
51
|
+
seq: message.seq,
|
|
52
|
+
id: message.event.id,
|
|
53
|
+
room: message.room,
|
|
54
|
+
author: message.author,
|
|
55
|
+
createdAt: message.event.created_at,
|
|
56
|
+
mentions: message.mentions,
|
|
57
|
+
...(message.thread ? { thread: message.thread } : {}),
|
|
58
|
+
text: message.text,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function printMessage(message) {
|
|
62
|
+
const when = new Date(message.event.created_at * 1000).toISOString();
|
|
63
|
+
const reply = message.thread ? ` ↳${message.thread.parent.slice(0, 8)}` : '';
|
|
64
|
+
console.log(`#${message.seq} ${when} ${message.author.slice(0, 12)}${reply} [${message.event.id.slice(0, 8)}]\n ${message.text.replace(/\n/g, '\n ')}`);
|
|
65
|
+
}
|
|
66
|
+
async function readCursor(file, room) {
|
|
67
|
+
const fs = await import('node:fs/promises');
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = await fs.readFile(file, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error.code === 'ENOENT')
|
|
74
|
+
return undefined;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
const parsed = JSON.parse(raw);
|
|
78
|
+
if (parsed.version !== 1 || parsed.room !== room || typeof parsed.storeId !== 'string' ||
|
|
79
|
+
!Number.isSafeInteger(parsed.throughSeq) || parsed.throughSeq < 0) {
|
|
80
|
+
throw new Error(`cursor file ${file} does not belong to room ${room}`);
|
|
81
|
+
}
|
|
82
|
+
return { storeId: parsed.storeId, throughSeq: parsed.throughSeq };
|
|
83
|
+
}
|
|
84
|
+
async function writeCursor(file, room, cursor) {
|
|
85
|
+
const { writeJsonAtomic } = await import('../../utils/atomic-write.js');
|
|
86
|
+
await writeJsonAtomic(file, { version: 1, room, storeId: cursor.storeId, throughSeq: cursor.throughSeq });
|
|
87
|
+
}
|
|
88
|
+
function filterFor(room, options, pubkey) {
|
|
89
|
+
const filter = { '#h': [room], kinds: [9] };
|
|
90
|
+
if (options.mentionsMe)
|
|
91
|
+
filter['#p'] = [pubkey];
|
|
92
|
+
if (options.limit !== undefined) {
|
|
93
|
+
const limit = Number(options.limit);
|
|
94
|
+
if (!Number.isSafeInteger(limit) || limit < 0 || limit > 500)
|
|
95
|
+
throw new Error('--limit must be an integer between 0 and 500');
|
|
96
|
+
filter.limit = limit;
|
|
97
|
+
}
|
|
98
|
+
return filter;
|
|
99
|
+
}
|
|
100
|
+
export function registerFleetRoomsCommands(fleet) {
|
|
101
|
+
const rooms = fleet
|
|
102
|
+
.command('rooms')
|
|
103
|
+
.description('Persistent signed messages between fleet members (read as data, never executed)');
|
|
104
|
+
const identity = rooms.command('identity').description('Member key used to sign room messages');
|
|
105
|
+
identity.command('init')
|
|
106
|
+
.description('Create this member key (0600 file); prints only the public key')
|
|
107
|
+
.option('--identity <file>', 'identity file (default $CODEBUDDY_FLEET_ROOMS_IDENTITY)')
|
|
108
|
+
.option('--force', 'rotate: keep the old file aside and create a new key')
|
|
109
|
+
.option('--json', 'machine-readable output')
|
|
110
|
+
.action(async (options) => {
|
|
111
|
+
try {
|
|
112
|
+
const { createRoomIdentity } = await import('../../fleet/rooms/room-identity.js');
|
|
113
|
+
const created = createRoomIdentity(options.identity, { force: options.force === true });
|
|
114
|
+
console.log(options.json
|
|
115
|
+
? JSON.stringify({ publicKey: created.publicKey, path: created.path })
|
|
116
|
+
: `Room key created: ${created.publicKey}\nAsk the hub operator to add it to rooms.json.`);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
fail(error);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
identity.command('show')
|
|
123
|
+
.description('Print this member public key')
|
|
124
|
+
.option('--identity <file>', 'identity file (default $CODEBUDDY_FLEET_ROOMS_IDENTITY)')
|
|
125
|
+
.option('--json', 'machine-readable output')
|
|
126
|
+
.action(async (options) => {
|
|
127
|
+
try {
|
|
128
|
+
const { loadRoomIdentity } = await import('../../fleet/rooms/room-identity.js');
|
|
129
|
+
const loaded = loadRoomIdentity(options.identity);
|
|
130
|
+
console.log(options.json ? JSON.stringify({ publicKey: loaded.publicKey, path: loaded.path }) : loaded.publicKey);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
fail(error);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
addConnectionOptions(rooms.command('post <room> <text...>'))
|
|
137
|
+
.description('Sign and publish a message; returns once the hub stored it durably')
|
|
138
|
+
.option('--mention <pubkey>', 'notify a member (repeatable)', collect, [])
|
|
139
|
+
.option('--reply-to <id>', 'answer this message')
|
|
140
|
+
.option('--reply-root <id>', 'thread root when answering a nested reply')
|
|
141
|
+
.action(async (room, words, options) => {
|
|
142
|
+
let client;
|
|
143
|
+
try {
|
|
144
|
+
const connected = await connect(options);
|
|
145
|
+
client = connected.client;
|
|
146
|
+
const replyTo = options.replyTo
|
|
147
|
+
? { root: options.replyRoot ?? options.replyTo, parent: options.replyTo }
|
|
148
|
+
: undefined;
|
|
149
|
+
const ack = await connected.client.publish({
|
|
150
|
+
room,
|
|
151
|
+
content: words.join(' '),
|
|
152
|
+
mentions: options.mention,
|
|
153
|
+
...(replyTo ? { replyTo } : {}),
|
|
154
|
+
});
|
|
155
|
+
console.log(options.json ? JSON.stringify(ack) : `${ack.duplicate ? 'Already stored' : 'Stored'} #${ack.seq} ${ack.id}`);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
fail(error);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await client?.close();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
addConnectionOptions(rooms.command('read <room>'))
|
|
165
|
+
.description('Print stored messages; with --cursor, only those after the saved cursor')
|
|
166
|
+
.option('--limit <n>', 'newest messages to show without a cursor (0..500, default 100)')
|
|
167
|
+
.option('--mentions-me', 'only messages mentioning this member')
|
|
168
|
+
.option('--cursor <file>', 'resume after, then update, the cursor saved in this file')
|
|
169
|
+
.action(async (room, options) => {
|
|
170
|
+
let client;
|
|
171
|
+
try {
|
|
172
|
+
const connected = await connect(options);
|
|
173
|
+
client = connected.client;
|
|
174
|
+
const previous = options.cursor ? await readCursor(options.cursor, room) : undefined;
|
|
175
|
+
const result = await connected.client.fetch([filterFor(room, options, connected.client.pubkey)], previous);
|
|
176
|
+
if (options.cursor)
|
|
177
|
+
await writeCursor(options.cursor, room, result.cursor);
|
|
178
|
+
if (options.json) {
|
|
179
|
+
console.log(JSON.stringify({
|
|
180
|
+
messages: result.messages.map(toJson),
|
|
181
|
+
cursor: result.cursor,
|
|
182
|
+
gap: result.gap,
|
|
183
|
+
epochChanged: result.epochChanged,
|
|
184
|
+
truncated: result.truncated,
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
if (result.gap)
|
|
189
|
+
console.log('! some messages after your cursor were evicted by retention');
|
|
190
|
+
if (result.epochChanged)
|
|
191
|
+
console.log('! the hub ledger changed generation; showing current history');
|
|
192
|
+
if (result.truncated)
|
|
193
|
+
console.log('! more messages remain; read again with --cursor to continue');
|
|
194
|
+
for (const message of result.messages)
|
|
195
|
+
printMessage(message);
|
|
196
|
+
if (result.messages.length === 0)
|
|
197
|
+
console.log('(no messages)');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
fail(error);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await client?.close();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
addConnectionOptions(rooms.command('tail <room>'))
|
|
208
|
+
.description('Follow a room live (reconnects and catches up automatically) until Ctrl+C')
|
|
209
|
+
.option('--mentions-me', 'only messages mentioning this member')
|
|
210
|
+
.option('--cursor <file>', 'resume after, and keep updating, the cursor saved in this file')
|
|
211
|
+
.action(async (room, options) => {
|
|
212
|
+
let client;
|
|
213
|
+
let finish = () => { };
|
|
214
|
+
const done = new Promise(resolve => { finish = resolve; });
|
|
215
|
+
let pendingWrite;
|
|
216
|
+
let latestCursor;
|
|
217
|
+
let caughtUp = false;
|
|
218
|
+
const persist = (cursor) => {
|
|
219
|
+
if (!options.cursor)
|
|
220
|
+
return;
|
|
221
|
+
latestCursor = cursor;
|
|
222
|
+
if (pendingWrite)
|
|
223
|
+
return;
|
|
224
|
+
const file = options.cursor;
|
|
225
|
+
pendingWrite = (async () => {
|
|
226
|
+
while (latestCursor) {
|
|
227
|
+
const next = latestCursor;
|
|
228
|
+
latestCursor = undefined;
|
|
229
|
+
await writeCursor(file, room, next);
|
|
230
|
+
}
|
|
231
|
+
})().catch(error => { fail(error); finish(); }).finally(() => {
|
|
232
|
+
pendingWrite = undefined;
|
|
233
|
+
if (latestCursor)
|
|
234
|
+
persist(latestCursor);
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
const disconnected = () => { caughtUp = false; };
|
|
238
|
+
const exhausted = () => { fail(new Error('Room reconnection attempts exhausted')); finish(); };
|
|
239
|
+
const reconnectError = (error) => {
|
|
240
|
+
if (error.code === 'ROOM_AUTH_REFUSED') {
|
|
241
|
+
fail(error);
|
|
242
|
+
finish();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
try {
|
|
246
|
+
client = (await connect(options)).client;
|
|
247
|
+
const previous = options.cursor ? await readCursor(options.cursor, room) : undefined;
|
|
248
|
+
process.once('SIGINT', finish);
|
|
249
|
+
process.once('SIGTERM', finish);
|
|
250
|
+
client.on('disconnected', disconnected);
|
|
251
|
+
client.on('reconnect-exhausted', exhausted);
|
|
252
|
+
client.on('reconnect-error', reconnectError);
|
|
253
|
+
const handle = client.subscribe('tail', [filterFor(room, { ...options, limit: '20' }, client.pubkey)], {
|
|
254
|
+
onMessage: (message) => {
|
|
255
|
+
if (options.json)
|
|
256
|
+
console.log(JSON.stringify(toJson(message)));
|
|
257
|
+
else
|
|
258
|
+
printMessage(message);
|
|
259
|
+
const cursor = handle.cursor();
|
|
260
|
+
if (caughtUp && cursor)
|
|
261
|
+
persist(cursor);
|
|
262
|
+
},
|
|
263
|
+
onEose: (info) => {
|
|
264
|
+
caughtUp = true;
|
|
265
|
+
persist({ storeId: info.storeId, throughSeq: info.throughSeq });
|
|
266
|
+
},
|
|
267
|
+
onClosed: (message) => {
|
|
268
|
+
fail(new Error(message));
|
|
269
|
+
finish();
|
|
270
|
+
},
|
|
271
|
+
}, previous);
|
|
272
|
+
await done;
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
fail(error);
|
|
276
|
+
}
|
|
277
|
+
finally {
|
|
278
|
+
process.removeListener('SIGINT', finish);
|
|
279
|
+
process.removeListener('SIGTERM', finish);
|
|
280
|
+
client?.off('disconnected', disconnected);
|
|
281
|
+
client?.off('reconnect-exhausted', exhausted);
|
|
282
|
+
client?.off('reconnect-error', reconnectError);
|
|
283
|
+
await client?.close();
|
|
284
|
+
while (pendingWrite)
|
|
285
|
+
await pendingWrite;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=fleet-rooms-commands.js.map
|