@phuetz/code-buddy 1.1.0 → 1.3.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.md +211 -163
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
- package/dist/agent/base-agent.d.ts +4 -0
- package/dist/agent/base-agent.js +6 -0
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +69 -14
- package/dist/agent/execution/agent-executor.js +122 -12
- package/dist/agent/execution/tool-dependency-graph.js +7 -0
- package/dist/agent/execution/tool-hooks.d.ts +6 -0
- package/dist/agent/execution/tool-hooks.js +13 -5
- package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
- package/dist/agent/execution/tool-selection-strategy.js +67 -10
- package/dist/agent/extended-thinking.d.ts +8 -0
- package/dist/agent/extended-thinking.js +27 -0
- package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
- package/dist/agent/facades/infrastructure-facade.js +15 -6
- package/dist/agent/hermes-browser-backends.js +151 -11
- package/dist/agent/hermes-claw-migrate.d.ts +59 -0
- package/dist/agent/hermes-claw-migrate.js +427 -26
- package/dist/agent/hermes-parity-manifest.js +78 -71
- package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
- package/dist/agent/hermes-runtime-lifecycle.js +468 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
- package/dist/agent/middleware/visual-validation-middleware.js +67 -0
- package/dist/agent/model-benchmark.d.ts +77 -0
- package/dist/agent/model-benchmark.js +309 -0
- package/dist/agent/model-tier.d.ts +14 -0
- package/dist/agent/model-tier.js +71 -0
- package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
- package/dist/agent/multi-agent/multi-agent-system.js +3 -1
- package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
- package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
- package/dist/agent/multi-agent/session-tools.js +22 -5
- package/dist/agent/reasoning/mcts.js +20 -6
- package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
- package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
- package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
- package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
- package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
- package/dist/agent/self-improvement/authored-tool-store.js +57 -0
- package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
- package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
- package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
- package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
- package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
- package/dist/agent/self-improvement/self-knowledge.js +24 -0
- package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
- package/dist/agent/self-improvement/skill-benchmark.js +22 -0
- package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
- package/dist/agent/self-improvement/skill-consolidator.js +137 -0
- package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
- package/dist/agent/self-improvement/skill-engine.js +87 -0
- package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
- package/dist/agent/self-improvement/skill-gate.js +62 -0
- package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
- package/dist/agent/self-improvement/skill-mutator.js +223 -0
- package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
- package/dist/agent/self-improvement/skill-proposer.js +82 -0
- package/dist/agent/self-improvement/skill-types.d.ts +41 -0
- package/dist/agent/self-improvement/skill-types.js +13 -0
- package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
- package/dist/agent/self-improvement/tool-benchmark.js +37 -0
- package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
- package/dist/agent/self-improvement/tool-engine.js +101 -0
- package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
- package/dist/agent/self-improvement/tool-gate.js +78 -0
- package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
- package/dist/agent/self-improvement/tool-proposer.js +34 -0
- package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
- package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
- package/dist/agent/self-improvement/tool-types.d.ts +48 -0
- package/dist/agent/self-improvement/tool-types.js +9 -0
- package/dist/agent/self-improvement/types.d.ts +3 -1
- package/dist/agent/session-end-flush.d.ts +6 -1
- package/dist/agent/session-end-flush.js +20 -4
- package/dist/agent/streaming/streaming-handler.d.ts +7 -0
- package/dist/agent/streaming/streaming-handler.js +8 -1
- package/dist/agent/tool-executor.js +1 -0
- package/dist/agent/tool-handler.d.ts +5 -0
- package/dist/agent/tool-handler.js +133 -4
- package/dist/browser-automation/browser-operator-executor.js +15 -0
- package/dist/browser-automation/browser-use-runner.d.ts +96 -0
- package/dist/browser-automation/browser-use-runner.js +492 -0
- package/dist/browser-automation/camofox-runner.d.ts +107 -0
- package/dist/browser-automation/camofox-runner.js +287 -0
- package/dist/channels/dingtalk/index.js +3 -0
- package/dist/channels/discord/client.d.ts +9 -0
- package/dist/channels/discord/client.js +12 -0
- package/dist/channels/feishu/index.d.ts +167 -1
- package/dist/channels/feishu/index.js +432 -7
- package/dist/channels/gateway-lifecycle.d.ts +132 -0
- package/dist/channels/gateway-lifecycle.js +219 -0
- package/dist/channels/google-chat/index.d.ts +5 -1
- package/dist/channels/google-chat/index.js +5 -1
- package/dist/channels/imessage/index.d.ts +14 -0
- package/dist/channels/imessage/index.js +64 -17
- package/dist/channels/index.d.ts +4 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/irc/index.d.ts +73 -3
- package/dist/channels/irc/index.js +446 -11
- package/dist/channels/line/index.js +3 -0
- package/dist/channels/mattermost/index.d.ts +51 -4
- package/dist/channels/mattermost/index.js +303 -20
- package/dist/channels/nextcloud-talk/index.d.ts +89 -8
- package/dist/channels/nextcloud-talk/index.js +367 -16
- package/dist/channels/nostr/index.d.ts +121 -1
- package/dist/channels/nostr/index.js +396 -8
- package/dist/channels/ntfy/index.js +3 -0
- package/dist/channels/qq/index.js +3 -0
- package/dist/channels/slash-parity.d.ts +117 -0
- package/dist/channels/slash-parity.js +185 -0
- package/dist/channels/synology-chat/index.js +3 -0
- package/dist/channels/teams/index.d.ts +3 -0
- package/dist/channels/teams/index.js +3 -0
- package/dist/channels/telegram/client.d.ts +9 -0
- package/dist/channels/telegram/client.js +12 -0
- package/dist/channels/twilio-voice/index.js +3 -0
- package/dist/channels/webchat/index.d.ts +7 -1
- package/dist/channels/webchat/index.js +7 -1
- package/dist/channels/wecom/index.js +3 -0
- package/dist/channels/weixin/index.js +3 -0
- package/dist/channels/zalo/index.js +3 -0
- package/dist/cli/config-loader.js +1 -1
- package/dist/codebuddy/client.d.ts +30 -1
- package/dist/codebuddy/client.js +167 -20
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
- package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
- package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
- package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
- package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
- package/dist/codebuddy/tool-definitions/index.js +2 -1
- package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
- package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
- package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
- package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
- package/dist/codebuddy/tools.d.ts +8 -1
- package/dist/codebuddy/tools.js +67 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/improve-command.js +123 -0
- package/dist/commands/cli/native-engine-commands.js +102 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +2 -2
- package/dist/commands/goal-cli.d.ts +30 -0
- package/dist/commands/goal-cli.js +210 -27
- package/dist/commands/handlers/goal-handler.d.ts +9 -2
- package/dist/commands/handlers/goal-handler.js +36 -9
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- package/dist/commands/handlers/missing-handlers.d.ts +1 -1
- package/dist/commands/handlers/missing-handlers.js +26 -3
- package/dist/commands/headless-slash.d.ts +2 -0
- package/dist/commands/headless-slash.js +12 -0
- package/dist/commands/llm-provider-resolution.d.ts +5 -3
- package/dist/commands/llm-provider-resolution.js +87 -33
- package/dist/commands/ollama.d.ts +25 -0
- package/dist/commands/ollama.js +100 -0
- package/dist/commands/provider.d.ts +5 -0
- package/dist/commands/provider.js +106 -55
- package/dist/commands/skills-cli/index.js +123 -0
- package/dist/commands/slash/builtin-commands.js +1 -1
- package/dist/commands/spec-next.js +2 -1
- package/dist/commands/spec-plan.js +5 -16
- package/dist/commands/tunnel.d.ts +2 -0
- package/dist/commands/tunnel.js +48 -0
- package/dist/companion/percepts.js +11 -1
- package/dist/config/config-resolver.d.ts +2 -1
- package/dist/config/config-resolver.js +54 -41
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/env-schema.js +756 -0
- package/dist/config/model-tools.js +4 -4
- package/dist/config/toml-config.d.ts +16 -0
- package/dist/config/toml-config.js +3 -0
- package/dist/context/bootstrap-loader.js +6 -23
- package/dist/context/context-manager-v2.js +1 -0
- package/dist/context/import-directive-parser.d.ts +4 -0
- package/dist/context/import-directive-parser.js +51 -6
- package/dist/context/instruction-excludes.d.ts +30 -1
- package/dist/context/instruction-excludes.js +71 -1
- package/dist/context/jit-context.d.ts +8 -10
- package/dist/context/jit-context.js +28 -106
- package/dist/context/project-context.d.ts +90 -0
- package/dist/context/project-context.js +295 -0
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +3 -3
- package/dist/daemon/autonomous-loop.d.ts +31 -1
- package/dist/daemon/autonomous-loop.js +91 -4
- package/dist/daemon/colab-goal.js +9 -1
- package/dist/daemon/cron-agent-bridge.d.ts +12 -3
- package/dist/daemon/cron-agent-bridge.js +25 -9
- package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
- package/dist/desktop/codebuddy-engine-adapter.js +257 -80
- package/dist/desktop/engine-adapter.d.ts +14 -0
- package/dist/desktop-automation/automation-manager.js +16 -0
- package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
- package/dist/desktop-automation/omniparser-runner.js +115 -0
- package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
- package/dist/desktop-automation/smart-snapshot.js +72 -5
- package/dist/doctor/index.js +40 -23
- package/dist/events/types.d.ts +11 -0
- package/dist/fleet/colab-store.js +14 -2
- package/dist/fleet/peer-session-bridge.js +50 -12
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/goals/goal-decomposer.d.ts +27 -0
- package/dist/goals/goal-decomposer.js +293 -0
- package/dist/goals/goal-judge-client.d.ts +15 -0
- package/dist/goals/goal-judge-client.js +45 -0
- package/dist/goals/goal-judge.d.ts +2 -0
- package/dist/goals/goal-judge.js +35 -6
- package/dist/goals/goal-loop.d.ts +14 -0
- package/dist/goals/goal-loop.js +47 -2
- package/dist/goals/goal-manager.d.ts +6 -0
- package/dist/goals/goal-manager.js +67 -14
- package/dist/goals/goal-state.d.ts +13 -0
- package/dist/goals/goal-state.js +83 -13
- package/dist/goals/goal-store.d.ts +3 -0
- package/dist/goals/goal-store.js +31 -15
- package/dist/harness/contract.d.ts +28 -28
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/identity/identity-manager.js +3 -2
- package/dist/index.js +481 -26
- package/dist/input/text-to-speech.d.ts +2 -6
- package/dist/input/text-to-speech.js +2 -27
- package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
- package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
- package/dist/integrations/tailscale.d.ts +13 -0
- package/dist/integrations/tailscale.js +87 -34
- package/dist/knowledge/workspace-indexer.js +53 -9
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
- package/dist/mcp/mcp-desktop-tools.js +158 -0
- package/dist/mcp/mcp-resources.js +2 -3
- package/dist/mcp/mcp-server.js +2 -0
- package/dist/memory/enhanced-memory.d.ts +10 -0
- package/dist/memory/enhanced-memory.js +33 -2
- package/dist/memory/index.d.ts +3 -1
- package/dist/memory/index.js +4 -1
- package/dist/memory/memory-auto-proposer.d.ts +23 -0
- package/dist/memory/memory-auto-proposer.js +308 -0
- package/dist/memory/memory-candidate-queue.d.ts +92 -0
- package/dist/memory/memory-candidate-queue.js +261 -0
- package/dist/memory/persistent-memory.d.ts +45 -2
- package/dist/memory/persistent-memory.js +236 -40
- package/dist/ml/bayesian-qualifier.d.ts +1 -1
- package/dist/ml/bayesian-qualifier.js +35 -2
- package/dist/openclaw/gateway-bridge.js +5 -0
- package/dist/plugins/marketplace.d.ts +1 -0
- package/dist/plugins/marketplace.js +7 -0
- package/dist/prompts/execution-discipline.d.ts +14 -0
- package/dist/prompts/execution-discipline.js +29 -0
- package/dist/prompts/variation-injector.js +9 -2
- package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
- package/dist/protocols/acp/acp-agentic-runner.js +115 -18
- package/dist/protocols/acp/acp-session-store.d.ts +23 -0
- package/dist/protocols/acp/acp-session-store.js +77 -0
- package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
- package/dist/protocols/acp/acp-stdio-server.js +71 -16
- package/dist/providers/active-llm-registry.d.ts +37 -0
- package/dist/providers/active-llm-registry.js +186 -0
- package/dist/providers/auxiliary-provider.d.ts +25 -0
- package/dist/providers/auxiliary-provider.js +192 -0
- package/dist/providers/codex-oauth.d.ts +1 -1
- package/dist/providers/codex-oauth.js +27 -4
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/provider-catalog.d.ts +70 -0
- package/dist/providers/provider-catalog.js +738 -0
- package/dist/providers/provider-fallback.d.ts +35 -0
- package/dist/providers/provider-fallback.js +171 -0
- package/dist/providers/xai-oauth.d.ts +128 -0
- package/dist/providers/xai-oauth.js +735 -0
- package/dist/scheduler/cron-scheduler.d.ts +15 -3
- package/dist/scheduler/cron-scheduler.js +53 -7
- package/dist/scheduler/script-runner.d.ts +2 -0
- package/dist/scheduler/script-runner.js +19 -4
- package/dist/scheduler/watchdog-handlers.js +7 -20
- package/dist/search/usearch-index.js +7 -2
- package/dist/security/tool-policy/tool-groups.js +2 -0
- package/dist/sensory/dreaming.d.ts +45 -0
- package/dist/sensory/dreaming.js +114 -0
- package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
- package/dist/sensory/heartbeat-scheduler.js +72 -0
- package/dist/sensory/reactions.d.ts +24 -0
- package/dist/sensory/reactions.js +31 -0
- package/dist/sensory/screen-reaction.d.ts +23 -0
- package/dist/sensory/screen-reaction.js +59 -0
- package/dist/sensory/sensory-bridge.d.ts +23 -0
- package/dist/sensory/sensory-bridge.js +85 -0
- package/dist/sensory/sensory-memory.d.ts +20 -0
- package/dist/sensory/sensory-memory.js +39 -0
- package/dist/sensory/speech-reaction.d.ts +21 -0
- package/dist/sensory/speech-reaction.js +83 -0
- package/dist/sensory/vision-reaction.d.ts +31 -0
- package/dist/sensory/vision-reaction.js +74 -0
- package/dist/server/index.js +106 -2
- package/dist/server/routes/mobile.d.ts +12 -4
- package/dist/server/routes/mobile.js +116 -1
- package/dist/server/tls-config.d.ts +35 -0
- package/dist/server/tls-config.js +142 -0
- package/dist/server/tunnel-manager.d.ts +20 -0
- package/dist/server/tunnel-manager.js +58 -0
- package/dist/server/websocket/fleet-bridge.js +5 -0
- package/dist/services/prompt-builder.d.ts +11 -0
- package/dist/services/prompt-builder.js +124 -17
- package/dist/shared/engine-types.d.ts +15 -1
- package/dist/sidecar/sidecar-bridge.d.ts +1 -0
- package/dist/sidecar/sidecar-bridge.js +21 -10
- package/dist/skills/parser.js +3 -0
- package/dist/skills/skill-importer.d.ts +58 -0
- package/dist/skills/skill-importer.js +261 -0
- package/dist/skills/skill-sources.d.ts +20 -0
- package/dist/skills/skill-sources.js +102 -0
- package/dist/skills/types.d.ts +6 -0
- package/dist/spec/spec-store.js +8 -1
- package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
- package/dist/talk-mode/providers/audioreader-tts.js +8 -8
- package/dist/templates/project-scaffolding.js +3 -2
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/application-profiles.js +38 -0
- package/dist/tools/bash/bash-tool.d.ts +1 -0
- package/dist/tools/bash/bash-tool.js +16 -2
- package/dist/tools/bash/command-validator.js +3 -0
- package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
- package/dist/tools/bash/rtk-rewrite.js +100 -0
- package/dist/tools/bash/streaming-executor.js +14 -1
- package/dist/tools/computer-control-tool.d.ts +16 -1
- package/dist/tools/computer-control-tool.js +317 -5
- package/dist/tools/document-generator.d.ts +14 -0
- package/dist/tools/document-generator.js +79 -0
- package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
- package/dist/tools/execute-code-rpc-invoker.js +46 -5
- package/dist/tools/metadata.js +28 -0
- package/dist/tools/office-macro-tool.d.ts +10 -0
- package/dist/tools/office-macro-tool.js +93 -0
- package/dist/tools/register-tool-handler.d.ts +25 -0
- package/dist/tools/register-tool-handler.js +100 -0
- package/dist/tools/registry/index.d.ts +2 -1
- package/dist/tools/registry/index.js +2 -1
- package/dist/tools/registry/memory-tools.d.ts +20 -0
- package/dist/tools/registry/memory-tools.js +225 -3
- package/dist/tools/registry/multimodal-tools.js +2 -2
- package/dist/tools/registry/vision-tools.d.ts +33 -0
- package/dist/tools/registry/vision-tools.js +308 -6
- package/dist/tools/registry/windows-tools.d.ts +2 -0
- package/dist/tools/registry/windows-tools.js +47 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +8 -0
- package/dist/tools/route-peer-tool.js +14 -0
- package/dist/tools/screenshot-tool.js +14 -2
- package/dist/tools/text-to-speech-tool.d.ts +1 -1
- package/dist/tools/text-to-speech-tool.js +2 -12
- package/dist/tools/tool-selector.js +3 -59
- package/dist/utils/config-validation/schema.d.ts +40 -7
- package/dist/utils/config-validation/schema.js +130 -1
- package/dist/utils/cost-tracker.js +21 -1
- package/dist/utils/disk-guard.d.ts +180 -0
- package/dist/utils/disk-guard.js +404 -0
- package/dist/utils/init-project.d.ts +7 -0
- package/dist/utils/init-project.js +37 -0
- package/dist/utils/interactive-setup.js +35 -2
- package/dist/utils/model-utils.js +11 -2
- package/dist/utils/output-sanitizer.js +11 -0
- package/dist/utils/provider-detector.d.ts +8 -7
- package/dist/utils/provider-detector.js +19 -77
- package/dist/utils/settings-manager.d.ts +19 -0
- package/dist/utils/token-display.d.ts +3 -3
- package/dist/utils/token-display.js +22 -4
- package/dist/wizard/onboarding.d.ts +39 -0
- package/dist/wizard/onboarding.js +433 -21
- package/dist/wizard/provider-onboarding.d.ts +8 -23
- package/dist/wizard/provider-onboarding.js +39 -158
- package/package.json +4 -2
- package/dist/plugins/provider-onboarding.d.ts +0 -23
- package/dist/plugins/provider-onboarding.js +0 -116
- package/dist/utils/kokoro-tts.d.ts +0 -8
- package/dist/utils/kokoro-tts.js +0 -67
|
@@ -12,10 +12,72 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Exit codes: 0 = goal done, 1 = paused (budget/judge) or error.
|
|
14
14
|
*/
|
|
15
|
-
import { Command } from 'commander';
|
|
15
|
+
import { Command, InvalidArgumentError } from 'commander';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { resolveGoalJudgeClient } from '../goals/goal-judge-client.js';
|
|
16
18
|
import { maybeContinueGoalAfterTurn } from '../goals/goal-loop.js';
|
|
17
|
-
import { getGoalManager } from '../goals/goal-manager.js';
|
|
19
|
+
import { getGoalManager, resolveGoalsConfig } from '../goals/goal-manager.js';
|
|
18
20
|
import { resolveCommandProvider } from './llm-provider-resolution.js';
|
|
21
|
+
const TOOL_RESULT_SNIPPET_CHARS = 1600;
|
|
22
|
+
export const LOCAL_GOAL_ACTOR_SYSTEM_PROMPT = 'You are Code Buddy running in headless goal mode on a local model. ' +
|
|
23
|
+
'Work only toward the user standing goal. Use available tools when they are necessary, ' +
|
|
24
|
+
'then report concrete progress or the final result. For simple answer-only goals, ' +
|
|
25
|
+
'output exactly the requested answer and no extra text. Do not greet the user, add markdown, ' +
|
|
26
|
+
'or explain unless the goal asks for it.';
|
|
27
|
+
export function buildLocalGoalActorSystemPrompt(workingDirectory = process.cwd()) {
|
|
28
|
+
return `${LOCAL_GOAL_ACTOR_SYSTEM_PROMPT}
|
|
29
|
+
|
|
30
|
+
Workspace:
|
|
31
|
+
- Current project directory: ${workingDirectory}
|
|
32
|
+
- Use paths relative to the current project directory whenever possible.
|
|
33
|
+
- Do not invent container paths such as /workspace or root paths such as /src unless a tool result proves they exist.`;
|
|
34
|
+
}
|
|
35
|
+
export function shouldUseLocalGoalActorPrompt(provider) {
|
|
36
|
+
const label = provider.providerLabel?.toLowerCase() ?? '';
|
|
37
|
+
const baseURL = provider.baseURL?.toLowerCase() ?? '';
|
|
38
|
+
return provider.apiKey === 'ollama' || label.includes('ollama') || baseURL.includes(':11434');
|
|
39
|
+
}
|
|
40
|
+
export function resolveLocalGoalActorSystemPrompt(provider, workingDirectory = process.cwd()) {
|
|
41
|
+
return shouldUseLocalGoalActorPrompt(provider)
|
|
42
|
+
? buildLocalGoalActorSystemPrompt(workingDirectory)
|
|
43
|
+
: undefined;
|
|
44
|
+
}
|
|
45
|
+
function truncateGoalTurnPart(text) {
|
|
46
|
+
if (text.length <= TOOL_RESULT_SNIPPET_CHARS)
|
|
47
|
+
return text;
|
|
48
|
+
return `${text.slice(0, TOOL_RESULT_SNIPPET_CHARS)}... [truncated]`;
|
|
49
|
+
}
|
|
50
|
+
function buildGoalTurnSummary(entries) {
|
|
51
|
+
const parts = [];
|
|
52
|
+
let hasToolResult = false;
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (entry.type === 'assistant' && entry.content.trim()) {
|
|
55
|
+
parts.push(entry.content.trim());
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (entry.type !== 'tool_result')
|
|
59
|
+
continue;
|
|
60
|
+
hasToolResult = true;
|
|
61
|
+
const toolOutput = (entry.toolResult?.success ? entry.toolResult.output : entry.toolResult?.error) ??
|
|
62
|
+
entry.content;
|
|
63
|
+
const trimmedOutput = String(toolOutput ?? '').trim();
|
|
64
|
+
if (!trimmedOutput)
|
|
65
|
+
continue;
|
|
66
|
+
const toolName = entry.toolCall?.function?.name ?? 'tool';
|
|
67
|
+
const status = entry.toolResult ? (entry.toolResult.success ? 'success' : 'error') : 'result';
|
|
68
|
+
parts.push(`[tool:${toolName} ${status}]\n${truncateGoalTurnPart(trimmedOutput)}`);
|
|
69
|
+
}
|
|
70
|
+
const summary = parts.join('\n\n');
|
|
71
|
+
if (summary && !hasToolResult) {
|
|
72
|
+
return `[tool evidence: none]\n\n${summary}`;
|
|
73
|
+
}
|
|
74
|
+
return summary;
|
|
75
|
+
}
|
|
76
|
+
function buildGoalRunSummary(turnSummaries) {
|
|
77
|
+
return turnSummaries
|
|
78
|
+
.map((summary, index) => `[Goal turn ${index + 1}]\n${summary}`)
|
|
79
|
+
.join('\n\n');
|
|
80
|
+
}
|
|
19
81
|
/**
|
|
20
82
|
* Drive the goal loop headlessly on an in-process agent. Sets the goal,
|
|
21
83
|
* runs the first turn with the goal text (mirroring the interactive
|
|
@@ -24,25 +86,32 @@ import { resolveCommandProvider } from './llm-provider-resolution.js';
|
|
|
24
86
|
*/
|
|
25
87
|
export async function runGoalLoop(agent, goalText, options = {}) {
|
|
26
88
|
const manager = getGoalManager();
|
|
27
|
-
const state = manager.set(goalText, options.maxTurns ? { maxTurns: options.maxTurns } : {});
|
|
89
|
+
const state = manager.set(goalText, options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {});
|
|
28
90
|
const emit = options.onMessage ?? (() => { });
|
|
91
|
+
const judgeClient = options.judgeClient ?? agent.getClient();
|
|
29
92
|
emit(`⊙ Goal set (${state.maxTurns}-turn budget): ${state.goal}`);
|
|
30
93
|
let prompt = state.goal;
|
|
94
|
+
const turnSummaries = [];
|
|
31
95
|
// Hard backstop on top of the manager's own budget/auto-pause guards.
|
|
32
96
|
const maxIterations = state.maxTurns + 1;
|
|
33
97
|
for (let i = 0; i < maxIterations; i++) {
|
|
34
98
|
const entries = await agent.processUserMessage(prompt);
|
|
35
|
-
const lastResponse = entries
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
|
|
99
|
+
const lastResponse = buildGoalTurnSummary(entries);
|
|
100
|
+
if (lastResponse.trim()) {
|
|
101
|
+
turnSummaries.push(lastResponse);
|
|
102
|
+
}
|
|
39
103
|
const outcome = await maybeContinueGoalAfterTurn({
|
|
40
|
-
client:
|
|
41
|
-
lastResponse,
|
|
104
|
+
client: judgeClient,
|
|
105
|
+
lastResponse: lastResponse.trim() ? buildGoalRunSummary(turnSummaries) : lastResponse,
|
|
42
106
|
interrupted: false,
|
|
43
107
|
});
|
|
44
108
|
if (outcome?.message)
|
|
45
109
|
emit(outcome.message);
|
|
110
|
+
if (!outcome && !lastResponse.trim() && manager.isActive()) {
|
|
111
|
+
manager.pause('empty response (nothing to evaluate)');
|
|
112
|
+
emit('⏸ Goal paused — the agent produced no judgeable response.');
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
46
115
|
if (!outcome?.continuationPrompt)
|
|
47
116
|
break;
|
|
48
117
|
prompt = outcome.continuationPrompt;
|
|
@@ -54,37 +123,151 @@ export async function runGoalLoop(agent, goalText, options = {}) {
|
|
|
54
123
|
...(final?.lastReason ? { lastReason: final.lastReason } : {}),
|
|
55
124
|
};
|
|
56
125
|
}
|
|
126
|
+
async function createStandaloneJudgeClient(judgeModel, agentProvider, currentClient) {
|
|
127
|
+
const resolved = await resolveGoalJudgeClient(currentClient, judgeModel, agentProvider);
|
|
128
|
+
return resolved === currentClient ? undefined : resolved;
|
|
129
|
+
}
|
|
130
|
+
export async function runGoalCommandWithAgent(agent, goal, options) {
|
|
131
|
+
try {
|
|
132
|
+
const createJudgeClient = options.createJudgeClient ?? createStandaloneJudgeClient;
|
|
133
|
+
const runLoop = options.runLoop ?? runGoalLoop;
|
|
134
|
+
const judgeClient = await createJudgeClient(options.judgeModel, options.provider, agent.getClient());
|
|
135
|
+
await agent.systemPromptReady;
|
|
136
|
+
if (shouldUseLocalGoalActorPrompt(options.provider)) {
|
|
137
|
+
agent.setSystemPrompt?.(buildLocalGoalActorSystemPrompt(options.workingDirectory));
|
|
138
|
+
}
|
|
139
|
+
return await runLoop(agent, goal, {
|
|
140
|
+
...(options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {}),
|
|
141
|
+
...(judgeClient ? { judgeClient } : {}),
|
|
142
|
+
...(options.onMessage ? { onMessage: options.onMessage } : {}),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await Promise.resolve(agent.dispose?.());
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function resolveGoalCliJudgeModel(explicitJudgeModel) {
|
|
150
|
+
const explicit = explicitJudgeModel?.trim();
|
|
151
|
+
if (explicit)
|
|
152
|
+
return explicit;
|
|
153
|
+
const configured = resolveGoalsConfig().judgeModel.trim();
|
|
154
|
+
return configured || undefined;
|
|
155
|
+
}
|
|
156
|
+
export function resolveGoalCliMaxToolRounds(commandValue, command) {
|
|
157
|
+
const commandSource = command?.getOptionValueSource?.('maxToolRounds');
|
|
158
|
+
if (commandSource && commandSource !== 'default') {
|
|
159
|
+
return commandValue ?? 50;
|
|
160
|
+
}
|
|
161
|
+
const parentSource = command?.parent?.getOptionValueSource?.('maxToolRounds');
|
|
162
|
+
const parentValue = command?.optsWithGlobals?.()?.maxToolRounds;
|
|
163
|
+
if (parentSource && parentSource !== 'default' && parentValue !== undefined) {
|
|
164
|
+
return parsePositiveIntegerOption(String(parentValue), '--max-tool-rounds');
|
|
165
|
+
}
|
|
166
|
+
return commandValue ?? 50;
|
|
167
|
+
}
|
|
168
|
+
export function resolveGoalCliWorkingDirectory(command) {
|
|
169
|
+
const value = command?.optsWithGlobals?.()?.directory;
|
|
170
|
+
if (typeof value !== 'string')
|
|
171
|
+
return undefined;
|
|
172
|
+
const directory = value.trim();
|
|
173
|
+
if (!directory)
|
|
174
|
+
return undefined;
|
|
175
|
+
return path.resolve(process.cwd(), directory);
|
|
176
|
+
}
|
|
177
|
+
export function applyGoalCliWorkingDirectory(command) {
|
|
178
|
+
const directory = resolveGoalCliWorkingDirectory(command);
|
|
179
|
+
if (directory) {
|
|
180
|
+
process.chdir(directory);
|
|
181
|
+
}
|
|
182
|
+
return process.cwd();
|
|
183
|
+
}
|
|
184
|
+
async function loadGoalCliEnv(directory) {
|
|
185
|
+
const dotenv = await import('dotenv');
|
|
186
|
+
dotenv.config({ path: path.join(directory, '.env') });
|
|
187
|
+
}
|
|
188
|
+
async function prepareGoalCliWorkspace(command) {
|
|
189
|
+
const launchDirectory = process.cwd();
|
|
190
|
+
await loadGoalCliEnv(launchDirectory);
|
|
191
|
+
const cwd = applyGoalCliWorkingDirectory(command);
|
|
192
|
+
if (cwd !== launchDirectory) {
|
|
193
|
+
await loadGoalCliEnv(cwd);
|
|
194
|
+
}
|
|
195
|
+
const opts = command?.optsWithGlobals?.();
|
|
196
|
+
const { initializeWorkspaceIsolation } = await import('../workspace/workspace-isolation.js');
|
|
197
|
+
initializeWorkspaceIsolation({
|
|
198
|
+
allowOutside: opts?.allowOutside,
|
|
199
|
+
directory: cwd,
|
|
200
|
+
additionalPaths: opts?.addDir,
|
|
201
|
+
});
|
|
202
|
+
return cwd;
|
|
203
|
+
}
|
|
204
|
+
export function parsePositiveIntegerOption(value, optionName) {
|
|
205
|
+
const trimmed = value.trim();
|
|
206
|
+
const n = Number(trimmed);
|
|
207
|
+
if (!/^[1-9]\d*$/.test(trimmed) || !Number.isSafeInteger(n)) {
|
|
208
|
+
throw new InvalidArgumentError(`${optionName} must be a positive integer`);
|
|
209
|
+
}
|
|
210
|
+
return n;
|
|
211
|
+
}
|
|
212
|
+
export function validateGoalCommandNumericOptions(argv) {
|
|
213
|
+
for (let i = 2; i < argv.length; i++) {
|
|
214
|
+
const arg = argv[i];
|
|
215
|
+
if (arg === undefined)
|
|
216
|
+
continue;
|
|
217
|
+
if (arg === '--')
|
|
218
|
+
break;
|
|
219
|
+
if (arg === '--max-turns' || arg === '--max-tool-rounds') {
|
|
220
|
+
const value = argv[i + 1];
|
|
221
|
+
if (value === undefined)
|
|
222
|
+
continue;
|
|
223
|
+
parsePositiveIntegerOption(value, arg);
|
|
224
|
+
i++;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const eqIndex = arg?.indexOf('=') ?? -1;
|
|
228
|
+
if (eqIndex <= 0)
|
|
229
|
+
continue;
|
|
230
|
+
const optionName = arg.slice(0, eqIndex);
|
|
231
|
+
if (optionName === '--max-turns' || optionName === '--max-tool-rounds') {
|
|
232
|
+
parsePositiveIntegerOption(arg.slice(eqIndex + 1), optionName);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
57
236
|
export function createGoalCommand() {
|
|
58
237
|
const cmd = new Command('goal')
|
|
59
238
|
.description('Run the agent toward a standing goal until a judge model confirms it is done (Ralph loop)')
|
|
60
239
|
.argument('<goal>', 'The goal to pursue')
|
|
61
|
-
.option('--max-turns <n>', 'Turn budget (default 20, or goals.maxTurns from settings)')
|
|
240
|
+
.option('--max-turns <n>', 'Turn budget (default 20, or goals.maxTurns from settings)', value => parsePositiveIntegerOption(value, '--max-turns'))
|
|
62
241
|
.option('--judge-model <model>', 'Model for the goal judge (default: session model)')
|
|
63
242
|
.option('-m, --model <model>', 'Override the agent model for this run')
|
|
64
|
-
.option('--max-tool-rounds <n>', 'Max tool rounds per turn', '
|
|
243
|
+
.option('--max-tool-rounds <n>', 'Max tool rounds per turn', value => parsePositiveIntegerOption(value, '--max-tool-rounds'), 50)
|
|
65
244
|
.action(async (goal, options, command) => {
|
|
66
|
-
const modelOverride = options.model ?? command?.optsWithGlobals?.()?.model;
|
|
67
|
-
const resolved = resolveCommandProvider({ explicitModel: modelOverride });
|
|
68
|
-
if (!resolved) {
|
|
69
|
-
console.error('Error: No provider available — set an API key, run `buddy onboard`, or point CODEBUDDY_PROVIDER=ollama at a local Ollama.');
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
if (options.judgeModel) {
|
|
73
|
-
process.env.CODEBUDDY_GOAL_JUDGE_MODEL = options.judgeModel;
|
|
74
|
-
}
|
|
75
|
-
process.env.CODEBUDDY_DISABLE_MCP = process.env.CODEBUDDY_DISABLE_MCP ?? 'true';
|
|
76
|
-
process.env.CODEBUDDY_HEADLESS = 'true';
|
|
77
245
|
try {
|
|
246
|
+
const cwd = await prepareGoalCliWorkspace(command);
|
|
247
|
+
const modelOverride = options.model ?? command?.optsWithGlobals?.()?.model;
|
|
248
|
+
const resolved = resolveCommandProvider({ explicitModel: modelOverride });
|
|
249
|
+
if (!resolved) {
|
|
250
|
+
console.error('Error: No provider available — set an API key, run `buddy onboard`, or point CODEBUDDY_PROVIDER=ollama at a local Ollama.');
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
if (options.judgeModel) {
|
|
254
|
+
process.env.CODEBUDDY_GOAL_JUDGE_MODEL = options.judgeModel;
|
|
255
|
+
}
|
|
256
|
+
const judgeModel = resolveGoalCliJudgeModel(options.judgeModel);
|
|
257
|
+
const maxToolRounds = resolveGoalCliMaxToolRounds(options.maxToolRounds, command);
|
|
258
|
+
process.env.CODEBUDDY_DISABLE_MCP = process.env.CODEBUDDY_DISABLE_MCP ?? 'true';
|
|
259
|
+
process.env.CODEBUDDY_HEADLESS = 'true';
|
|
78
260
|
const { CodeBuddyAgent } = await import('../agent/codebuddy-agent.js');
|
|
79
261
|
const { ConfirmationService } = await import('../utils/confirmation-service.js');
|
|
80
262
|
ConfirmationService.getInstance().setSessionFlag('allOperations', true);
|
|
81
|
-
const agent = new CodeBuddyAgent(resolved.apiKey, resolved.baseURL, resolved.model,
|
|
82
|
-
await agent
|
|
83
|
-
|
|
84
|
-
|
|
263
|
+
const agent = new CodeBuddyAgent(resolved.apiKey, resolved.baseURL, resolved.model, maxToolRounds, true, undefined, cwd, undefined, resolveLocalGoalActorSystemPrompt(resolved, cwd));
|
|
264
|
+
const result = await runGoalCommandWithAgent(agent, goal, {
|
|
265
|
+
provider: resolved,
|
|
266
|
+
judgeModel,
|
|
267
|
+
workingDirectory: cwd,
|
|
268
|
+
...(options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {}),
|
|
85
269
|
onMessage: text => console.log(`\n${text}`),
|
|
86
270
|
});
|
|
87
|
-
agent.dispose?.();
|
|
88
271
|
process.exit(result.status === 'done' ? 0 : 1);
|
|
89
272
|
}
|
|
90
273
|
catch (err) {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import type { CodeBuddyClient } from '../../codebuddy/client.js';
|
|
2
|
+
import { type GoalPlan } from '../../goals/goal-decomposer.js';
|
|
1
3
|
import { CommandHandlerResult } from './branch-handlers.js';
|
|
4
|
+
export interface GoalHandlerOptions {
|
|
5
|
+
sessionKey?: string;
|
|
6
|
+
client?: CodeBuddyClient | null;
|
|
7
|
+
planner?: (goal: string, client: CodeBuddyClient) => Promise<GoalPlan | null>;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* /goal — standing goal with judge + auto-continue loop (the Ralph loop,
|
|
4
11
|
* ported from Hermes Agent).
|
|
@@ -10,7 +17,7 @@ import { CommandHandlerResult } from './branch-handlers.js';
|
|
|
10
17
|
* /goal resume restart the loop (resets the turn budget)
|
|
11
18
|
* /goal clear discard the goal (aliases: stop, done)
|
|
12
19
|
*/
|
|
13
|
-
export declare function handleGoal(args: string[]): Promise<CommandHandlerResult>;
|
|
20
|
+
export declare function handleGoal(args: string[], options?: GoalHandlerOptions): Promise<CommandHandlerResult>;
|
|
14
21
|
/**
|
|
15
22
|
* /subgoal — extra acceptance criteria added mid-loop.
|
|
16
23
|
*
|
|
@@ -24,4 +31,4 @@ export declare function handleGoal(args: string[]): Promise<CommandHandlerResult
|
|
|
24
31
|
* them) and the continuation prompt (agent sees them) on the next turn
|
|
25
32
|
* boundary — no special kick needed.
|
|
26
33
|
*/
|
|
27
|
-
export declare function handleSubgoal(args: string[]): Promise<CommandHandlerResult>;
|
|
34
|
+
export declare function handleSubgoal(args: string[], options?: GoalHandlerOptions): Promise<CommandHandlerResult>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decomposeGoal, formatGoalPlan, shouldAutoDecomposeGoal, } from '../../goals/goal-decomposer.js';
|
|
1
2
|
import { getGoalManager } from '../../goals/goal-manager.js';
|
|
2
3
|
/**
|
|
3
4
|
* /goal — standing goal with judge + auto-continue loop (the Ralph loop,
|
|
@@ -10,10 +11,10 @@ import { getGoalManager } from '../../goals/goal-manager.js';
|
|
|
10
11
|
* /goal resume restart the loop (resets the turn budget)
|
|
11
12
|
* /goal clear discard the goal (aliases: stop, done)
|
|
12
13
|
*/
|
|
13
|
-
export async function handleGoal(args) {
|
|
14
|
+
export async function handleGoal(args, options = {}) {
|
|
14
15
|
const arg = args.join(' ').trim();
|
|
15
16
|
const lower = arg.toLowerCase();
|
|
16
|
-
const mgr = getGoalManager();
|
|
17
|
+
const mgr = getGoalManager(options.sessionKey);
|
|
17
18
|
if (!arg || lower === 'status') {
|
|
18
19
|
return textResult(mgr.statusLine());
|
|
19
20
|
}
|
|
@@ -35,13 +36,37 @@ export async function handleGoal(args) {
|
|
|
35
36
|
return textResult(had ? '✓ Goal cleared.' : 'No active goal.');
|
|
36
37
|
}
|
|
37
38
|
// Otherwise treat the arg as the goal text.
|
|
39
|
+
let plan = null;
|
|
40
|
+
let planAttempted = false;
|
|
41
|
+
let planError = '';
|
|
42
|
+
if (options.client && shouldAutoDecomposeGoal(arg)) {
|
|
43
|
+
planAttempted = true;
|
|
44
|
+
try {
|
|
45
|
+
plan = await (options.planner ?? decomposeGoal)(arg, options.client);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
planError = error instanceof Error ? error.message : String(error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
38
51
|
let state;
|
|
39
52
|
try {
|
|
40
|
-
state = mgr.set(arg
|
|
53
|
+
state = mgr.set(arg, {
|
|
54
|
+
...(plan ? { goalPlan: plan } : {}),
|
|
55
|
+
...(planAttempted ? { goalPlanAttempted: true } : {}),
|
|
56
|
+
});
|
|
57
|
+
if (planAttempted && !plan && planError) {
|
|
58
|
+
mgr.markGoalPlanAttempted(planError);
|
|
59
|
+
state = mgr.state ?? state;
|
|
60
|
+
}
|
|
41
61
|
}
|
|
42
62
|
catch (error) {
|
|
43
63
|
return textResult(`Invalid goal: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
64
|
}
|
|
65
|
+
const planBlock = state.goalPlan
|
|
66
|
+
? `\n\nHermes-style task graph attached:\n${formatGoalPlan(state.goalPlan)}`
|
|
67
|
+
: planError
|
|
68
|
+
? `\n\nGoal planning was skipped after an LLM planner error: ${planError}`
|
|
69
|
+
: '';
|
|
45
70
|
return {
|
|
46
71
|
handled: true,
|
|
47
72
|
entry: {
|
|
@@ -51,7 +76,8 @@ export async function handleGoal(args) {
|
|
|
51
76
|
'keeps working until it is, you pause/clear it, or the budget is ' +
|
|
52
77
|
'exhausted. Use /goal status, /goal pause, /goal resume, /goal clear. ' +
|
|
53
78
|
'Tip: for unattended runs, enable auto-approval (/yolo or auto-edit) so ' +
|
|
54
|
-
'the loop is not blocked on confirmations.'
|
|
79
|
+
'the loop is not blocked on confirmations.' +
|
|
80
|
+
planBlock,
|
|
55
81
|
timestamp: new Date(),
|
|
56
82
|
},
|
|
57
83
|
// Kick the loop off immediately — the dispatcher feeds the goal text as
|
|
@@ -73,9 +99,9 @@ export async function handleGoal(args) {
|
|
|
73
99
|
* them) and the continuation prompt (agent sees them) on the next turn
|
|
74
100
|
* boundary — no special kick needed.
|
|
75
101
|
*/
|
|
76
|
-
export async function handleSubgoal(args) {
|
|
102
|
+
export async function handleSubgoal(args, options = {}) {
|
|
77
103
|
const arg = args.join(' ').trim();
|
|
78
|
-
const mgr = getGoalManager();
|
|
104
|
+
const mgr = getGoalManager(options.sessionKey);
|
|
79
105
|
if (!mgr.hasGoal()) {
|
|
80
106
|
return textResult('No active goal. Set one with /goal <text>.');
|
|
81
107
|
}
|
|
@@ -88,9 +114,10 @@ export async function handleSubgoal(args) {
|
|
|
88
114
|
if (!rest) {
|
|
89
115
|
return textResult('Usage: /subgoal remove <n>');
|
|
90
116
|
}
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
117
|
+
const indexToken = rest.split(/\s+/)[0] ?? '';
|
|
118
|
+
const idx = Number(indexToken);
|
|
119
|
+
if (!/^[1-9]\d*$/.test(indexToken) || !Number.isSafeInteger(idx)) {
|
|
120
|
+
return textResult('/subgoal remove: <n> must be a positive integer (1-based index).');
|
|
94
121
|
}
|
|
95
122
|
try {
|
|
96
123
|
const removed = mgr.removeSubgoal(idx);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* and the current TurboQuant routing statistics.
|
|
7
7
|
*/
|
|
8
8
|
import { logger } from '../../utils/logger.js';
|
|
9
|
+
import { fetchOllamaStatus } from '../ollama.js';
|
|
9
10
|
async function checkEndpoint(name, url, timeoutMs = 4000) {
|
|
10
11
|
const start = Date.now();
|
|
11
12
|
try {
|
|
@@ -49,6 +50,35 @@ function formatRoutingStats(stats) {
|
|
|
49
50
|
}
|
|
50
51
|
return lines.join('\n');
|
|
51
52
|
}
|
|
53
|
+
function formatOllamaSummary(status) {
|
|
54
|
+
const lines = [
|
|
55
|
+
` Reachable: ${status.reachable ? 'YES' : 'NO'}`,
|
|
56
|
+
` Version: ${status.version ?? '(unknown)'}`,
|
|
57
|
+
` Models: ${status.models.length > 0 ? status.models.join(', ') : '(none)'}`,
|
|
58
|
+
];
|
|
59
|
+
if (status.error) {
|
|
60
|
+
lines.push(` Error: ${status.error}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push(` Gemma 4 ready: ${isGemma4Ready(status.version, status.models) ? 'YES' : 'NO'}`);
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}
|
|
65
|
+
function isGemma4Ready(version, models) {
|
|
66
|
+
if (!version)
|
|
67
|
+
return false;
|
|
68
|
+
const [majorRaw, minorRaw, patchRaw] = version.split('.');
|
|
69
|
+
const major = Number.parseInt(majorRaw ?? '', 10);
|
|
70
|
+
const minor = Number.parseInt(minorRaw ?? '', 10);
|
|
71
|
+
const patch = Number.parseInt(patchRaw ?? '', 10);
|
|
72
|
+
if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch))
|
|
73
|
+
return false;
|
|
74
|
+
if (major > 0)
|
|
75
|
+
return true;
|
|
76
|
+
if (minor > 24)
|
|
77
|
+
return true;
|
|
78
|
+
if (minor === 24 && patch >= 1)
|
|
79
|
+
return true;
|
|
80
|
+
return models.some((model) => model.toLowerCase().includes('gemma4'));
|
|
81
|
+
}
|
|
52
82
|
// ---------------------------------------------------------------------------
|
|
53
83
|
// Main handler
|
|
54
84
|
// ---------------------------------------------------------------------------
|
|
@@ -102,6 +132,9 @@ async function handleInfraDashboard() {
|
|
|
102
132
|
lines.push(formatStatus(s));
|
|
103
133
|
}
|
|
104
134
|
lines.push('');
|
|
135
|
+
lines.push('Ollama Summary:');
|
|
136
|
+
lines.push(formatOllamaSummary(await fetchOllamaStatus(ollamaUrl)));
|
|
137
|
+
lines.push('');
|
|
105
138
|
// Routing stats from TurboQuant plugin
|
|
106
139
|
try {
|
|
107
140
|
const { getTurboQuantStats } = await import('../../plugins/bundled/turboquant-plugin.js');
|
|
@@ -159,6 +192,9 @@ async function handleInfraHealth() {
|
|
|
159
192
|
for (const s of statuses) {
|
|
160
193
|
lines.push(formatStatus(s));
|
|
161
194
|
}
|
|
195
|
+
lines.push('');
|
|
196
|
+
lines.push('Ollama Summary:');
|
|
197
|
+
lines.push(formatOllamaSummary(await fetchOllamaStatus(ollamaUrl)));
|
|
162
198
|
return { handled: true, response: lines.join('\n') };
|
|
163
199
|
}
|
|
164
200
|
//# sourceMappingURL=infra-handlers.js.map
|
|
@@ -27,6 +27,9 @@ function formatTimeAgo(date, now = new Date()) {
|
|
|
27
27
|
const yr = Math.floor(day / 365);
|
|
28
28
|
return `${yr} year${yr === 1 ? "" : "s"} ago`;
|
|
29
29
|
}
|
|
30
|
+
function clip(text, max = 180) {
|
|
31
|
+
return text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
32
|
+
}
|
|
30
33
|
/**
|
|
31
34
|
* Memory - Manage persistent memory using PersistentMemoryManager (Markdown) and EnhancedMemory (SQLite/Vector)
|
|
32
35
|
*/
|
|
@@ -103,10 +106,10 @@ export async function handleMemory(args) {
|
|
|
103
106
|
content = `Usage: /memory remember <key> <content> [project|user]`;
|
|
104
107
|
break;
|
|
105
108
|
}
|
|
106
|
-
const value = args.slice(2).join(" ");
|
|
107
109
|
const scope = (args[args.length - 1] === "user" || args[args.length - 1] === "project")
|
|
108
110
|
? args.pop()
|
|
109
111
|
: "project";
|
|
112
|
+
const value = args.slice(2).join(" ");
|
|
110
113
|
// Store in both for redundancy and better retrieval
|
|
111
114
|
await persistentMemory.remember(key, value, { scope, category: "custom" });
|
|
112
115
|
await enhancedMemory.store({
|
|
@@ -121,6 +124,30 @@ export async function handleMemory(args) {
|
|
|
121
124
|
content = `Usage: /memory remember <key> <content> [project|user]`;
|
|
122
125
|
}
|
|
123
126
|
break;
|
|
127
|
+
case "replace":
|
|
128
|
+
case "update":
|
|
129
|
+
if (args.length >= 3) {
|
|
130
|
+
const key = args[1];
|
|
131
|
+
if (key === undefined) {
|
|
132
|
+
content = `Usage: /memory replace <key> <content> [project|user]`;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
const scope = (args[args.length - 1] === "user" || args[args.length - 1] === "project")
|
|
136
|
+
? args.pop()
|
|
137
|
+
: "project";
|
|
138
|
+
const value = args.slice(2).join(" ");
|
|
139
|
+
const result = await persistentMemory.replace(key, value, { scope });
|
|
140
|
+
if (result.status === 'missing') {
|
|
141
|
+
content = result.message;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
content = `✅ ${result.message}\nCapacity: ${result.usage.used}/${result.usage.limit} chars (${result.usage.percent}%).`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
content = `Usage: /memory replace <key> <content> [project|user]`;
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
124
151
|
case "context":
|
|
125
152
|
const enhancedContext = await enhancedMemory.buildContext({
|
|
126
153
|
includeProject: true,
|
|
@@ -154,6 +181,74 @@ export async function handleMemory(args) {
|
|
|
154
181
|
}
|
|
155
182
|
break;
|
|
156
183
|
}
|
|
184
|
+
case "candidates":
|
|
185
|
+
case "candidate":
|
|
186
|
+
case "pending": {
|
|
187
|
+
const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
|
|
188
|
+
const statusArg = args[1];
|
|
189
|
+
const status = statusArg === "pending" || statusArg === "accepted" || statusArg === "rejected"
|
|
190
|
+
? statusArg
|
|
191
|
+
: undefined;
|
|
192
|
+
const rawLimit = parseInt(args[status ? 2 : 1] ?? "20", 10);
|
|
193
|
+
const limit = Math.min(50, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 20));
|
|
194
|
+
const candidates = getMemoryCandidateQueue(process.cwd()).list(status).slice(0, limit);
|
|
195
|
+
if (candidates.length === 0) {
|
|
196
|
+
content = status ? `No ${status} memory candidates.` : "No memory candidates yet.";
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
const lines = [`🧠 Memory candidates (${candidates.length}${status ? ` ${status}` : ""})`, "═".repeat(50)];
|
|
200
|
+
for (const candidate of candidates) {
|
|
201
|
+
const created = formatTimeAgo(new Date(candidate.createdAt));
|
|
202
|
+
const confidence = typeof candidate.confidence === "number"
|
|
203
|
+
? ` | confidence ${(candidate.confidence * 100).toFixed(0)}%`
|
|
204
|
+
: "";
|
|
205
|
+
lines.push(`[${candidate.status}] ${candidate.id} | ${candidate.scope}/${candidate.category}${confidence} | ${created}`);
|
|
206
|
+
lines.push(` ${candidate.key}: ${clip(candidate.value)}`);
|
|
207
|
+
const citation = candidate.citations?.[0];
|
|
208
|
+
if (citation) {
|
|
209
|
+
const label = citation.sessionId
|
|
210
|
+
? `${citation.sessionId}${citation.messageId ? `#${citation.messageId}` : citation.messageIndex ? `#${citation.messageIndex}` : ""}`
|
|
211
|
+
: citation.messageIndex ? `message ${citation.messageIndex}` : "evidence";
|
|
212
|
+
lines.push(` citation: ${label}${citation.role ? ` (${citation.role})` : ""} — ${clip(citation.snippet, 140)}`);
|
|
213
|
+
}
|
|
214
|
+
lines.push("");
|
|
215
|
+
}
|
|
216
|
+
lines.push("Approve: /memory accept <id> [reviewer]");
|
|
217
|
+
lines.push("Reject: /memory reject <id> [reason]");
|
|
218
|
+
content = lines.join("\n").trimEnd();
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case "accept":
|
|
223
|
+
case "approve": {
|
|
224
|
+
const id = args[1];
|
|
225
|
+
if (!id) {
|
|
226
|
+
content = `Usage: /memory accept <candidate-id> [reviewer]`;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
const reviewedBy = args.slice(2).join(" ").trim() || "user";
|
|
230
|
+
const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
|
|
231
|
+
const { candidate, write } = await getMemoryCandidateQueue(process.cwd()).accept(id, { reviewedBy });
|
|
232
|
+
content = `✅ Accepted ${candidate.id} into ${candidate.scope} memory as "${candidate.key}".\n` +
|
|
233
|
+
`Write status: ${write.status}. Capacity: ${write.usage.used}/${write.usage.limit} chars (${write.usage.percent}%).`;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case "reject":
|
|
237
|
+
case "discard": {
|
|
238
|
+
const id = args[1];
|
|
239
|
+
if (!id) {
|
|
240
|
+
content = `Usage: /memory reject <candidate-id> [reason]`;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
const reason = args.slice(2).join(" ").trim();
|
|
244
|
+
const { getMemoryCandidateQueue } = await import("../../memory/memory-candidate-queue.js");
|
|
245
|
+
const candidate = getMemoryCandidateQueue(process.cwd()).reject(id, {
|
|
246
|
+
reviewedBy: "user",
|
|
247
|
+
...(reason ? { reason } : {}),
|
|
248
|
+
});
|
|
249
|
+
content = `🗑️ Rejected memory candidate ${candidate.id}.`;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
157
252
|
case "status":
|
|
158
253
|
case "list":
|
|
159
254
|
default:
|
|
@@ -22,7 +22,7 @@ export declare function handleDiffCheckpoints(args: string[]): Promise<CommandHa
|
|
|
22
22
|
export declare function handleFeatures(): CommandHandlerResult;
|
|
23
23
|
export declare function handleListCheckpoints(_args: string[]): Promise<CommandHandlerResult>;
|
|
24
24
|
export declare function handleRestoreCheckpoint(args: string[]): Promise<CommandHandlerResult>;
|
|
25
|
-
export declare function handleInitGrok(): Promise<CommandHandlerResult>;
|
|
25
|
+
export declare function handleInitGrok(args?: string[]): Promise<CommandHandlerResult>;
|
|
26
26
|
export declare function handleReinitGrok(): Promise<CommandHandlerResult>;
|
|
27
27
|
export declare function handleStatus(): Promise<CommandHandlerResult>;
|
|
28
28
|
export declare function handleNew(args: string[]): Promise<CommandHandlerResult>;
|
|
@@ -660,17 +660,40 @@ Use /checkpoints to see available checkpoints.`,
|
|
|
660
660
|
// ============================================================================
|
|
661
661
|
// /init - Initialize Code Buddy Project
|
|
662
662
|
// ============================================================================
|
|
663
|
-
export async function handleInitGrok() {
|
|
663
|
+
export async function handleInitGrok(args = []) {
|
|
664
664
|
try {
|
|
665
|
-
const
|
|
665
|
+
const fast = args.some((a) => a === '--fast' || a === '-f');
|
|
666
|
+
const { initCodeBuddyProject, formatInitResult, buildInitPrompt } = await import('../../utils/init-project.js');
|
|
667
|
+
// Deterministic scaffolding first (.codebuddy plumbing + template files,
|
|
668
|
+
// skip-if-exists). This always runs, so the config + a baseline AGENTS.md exist.
|
|
666
669
|
const initResult = await initCodeBuddyProject();
|
|
670
|
+
if (fast) {
|
|
671
|
+
// --fast: deterministic template only (the legacy behavior).
|
|
672
|
+
return {
|
|
673
|
+
handled: true,
|
|
674
|
+
entry: { type: 'assistant', content: formatInitResult(initResult), timestamp: new Date() },
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
// Default: hand off to the agent to read the code and write a tailored
|
|
678
|
+
// AGENTS.md, grounded on the RepoProfiler's verified facts.
|
|
679
|
+
let contextPack = '';
|
|
680
|
+
try {
|
|
681
|
+
const { getRepoProfiler } = await import('../../agent/repo-profiler.js');
|
|
682
|
+
const profile = await getRepoProfiler().getProfile();
|
|
683
|
+
contextPack = profile.contextPack ?? '';
|
|
684
|
+
}
|
|
685
|
+
catch {
|
|
686
|
+
/* profiler optional — the prompt still works without the facts block */
|
|
687
|
+
}
|
|
667
688
|
return {
|
|
668
689
|
handled: true,
|
|
669
690
|
entry: {
|
|
670
691
|
type: 'assistant',
|
|
671
|
-
content: formatInitResult(initResult)
|
|
692
|
+
content: `${formatInitResult(initResult)}\n\nNow analyzing the repository to write a tailored \`AGENTS.md\`… (run \`/init --fast\` for the deterministic template only)`,
|
|
672
693
|
timestamp: new Date(),
|
|
673
694
|
},
|
|
695
|
+
passToAI: true,
|
|
696
|
+
prompt: buildInitPrompt(contextPack),
|
|
674
697
|
};
|
|
675
698
|
}
|
|
676
699
|
catch (error) {
|
|
@@ -33,6 +33,8 @@ export interface HeadlessSlashContext {
|
|
|
33
33
|
conversationHistory?: ChatEntry[];
|
|
34
34
|
/** LLM client, for tokens that call the model directly (ai-test, btw). */
|
|
35
35
|
client?: CodeBuddyClient;
|
|
36
|
+
/** Optional goal-state key for non-TUI surfaces with their own session ids. */
|
|
37
|
+
goalSessionKey?: string;
|
|
36
38
|
}
|
|
37
39
|
/** Result of running a special token outside the TUI. */
|
|
38
40
|
export interface HeadlessSlashResult {
|