@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
|
@@ -13,7 +13,7 @@ import path from 'path';
|
|
|
13
13
|
import { getSettingsHierarchy } from '../config/settings-hierarchy.js';
|
|
14
14
|
import { getSessionStore } from '../persistence/session-store.js';
|
|
15
15
|
import { logger } from '../utils/logger.js';
|
|
16
|
-
import { DEFAULT_JUDGE_MAX_TOKENS, DEFAULT_JUDGE_TIMEOUT_MS, DEFAULT_MAX_TURNS, applyJudgeOutcome, buildContinuationPrompt, createGoalState, formatGoalStatusLine, renderSubgoalsBlock, } from './goal-state.js';
|
|
16
|
+
import { DEFAULT_JUDGE_MAX_TOKENS, DEFAULT_JUDGE_TIMEOUT_MS, DEFAULT_MAX_TURNS, applyJudgeOutcome, buildContinuationPrompt, createGoalState, formatGoalStatusLine, getGoalJudgeCriteria, renderSubgoalsBlock, } from './goal-state.js';
|
|
17
17
|
import { GoalStore } from './goal-store.js';
|
|
18
18
|
export class GoalManager {
|
|
19
19
|
sessionKey;
|
|
@@ -47,13 +47,40 @@ export class GoalManager {
|
|
|
47
47
|
if (!text) {
|
|
48
48
|
throw new Error('goal text is empty');
|
|
49
49
|
}
|
|
50
|
-
const state = createGoalState(text, options.maxTurns
|
|
50
|
+
const state = createGoalState(text, options.maxTurns ?? this.defaultMaxTurns);
|
|
51
|
+
if (options.goalPlan)
|
|
52
|
+
state.goalPlan = options.goalPlan;
|
|
53
|
+
if (typeof options.goalPlanAttempted === 'boolean') {
|
|
54
|
+
state.goalPlanAttempted = options.goalPlanAttempted;
|
|
55
|
+
}
|
|
51
56
|
this._state = state;
|
|
52
57
|
this.store.save(this.sessionKey, state);
|
|
53
58
|
return state;
|
|
54
59
|
}
|
|
60
|
+
attachGoalPlan(plan) {
|
|
61
|
+
if (!this.hasGoal() || !this._state)
|
|
62
|
+
return null;
|
|
63
|
+
this._state.goalPlan = plan;
|
|
64
|
+
this._state.goalPlanAttempted = true;
|
|
65
|
+
delete this._state.goalPlanLastError;
|
|
66
|
+
this.store.save(this.sessionKey, this._state);
|
|
67
|
+
return this._state;
|
|
68
|
+
}
|
|
69
|
+
markGoalPlanAttempted(error) {
|
|
70
|
+
if (!this.hasGoal() || !this._state)
|
|
71
|
+
return null;
|
|
72
|
+
this._state.goalPlanAttempted = true;
|
|
73
|
+
if (error) {
|
|
74
|
+
this._state.goalPlanLastError = error;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
delete this._state.goalPlanLastError;
|
|
78
|
+
}
|
|
79
|
+
this.store.save(this.sessionKey, this._state);
|
|
80
|
+
return this._state;
|
|
81
|
+
}
|
|
55
82
|
pause(reason = 'user-paused') {
|
|
56
|
-
if (!this._state)
|
|
83
|
+
if (!this._state || !['active', 'paused'].includes(this._state.status))
|
|
57
84
|
return null;
|
|
58
85
|
this._state.status = 'paused';
|
|
59
86
|
this._state.pausedReason = reason;
|
|
@@ -61,10 +88,13 @@ export class GoalManager {
|
|
|
61
88
|
return this._state;
|
|
62
89
|
}
|
|
63
90
|
resume(options = {}) {
|
|
64
|
-
if (!this._state)
|
|
91
|
+
if (!this._state || this._state.status !== 'paused')
|
|
65
92
|
return null;
|
|
66
93
|
this._state.status = 'active';
|
|
67
94
|
delete this._state.pausedReason;
|
|
95
|
+
delete this._state.lastVerdict;
|
|
96
|
+
delete this._state.lastReason;
|
|
97
|
+
this._state.consecutiveParseFailures = 0;
|
|
68
98
|
if (options.resetBudget ?? true) {
|
|
69
99
|
this._state.turnsUsed = 0;
|
|
70
100
|
}
|
|
@@ -103,7 +133,10 @@ export class GoalManager {
|
|
|
103
133
|
if (!this.hasGoal() || !this._state) {
|
|
104
134
|
throw new Error('no active goal');
|
|
105
135
|
}
|
|
106
|
-
|
|
136
|
+
if (!Number.isSafeInteger(index1Based) || index1Based < 1) {
|
|
137
|
+
throw new Error('index must be a positive integer');
|
|
138
|
+
}
|
|
139
|
+
const idx = index1Based - 1;
|
|
107
140
|
if (idx < 0 || idx >= this._state.subgoals.length) {
|
|
108
141
|
throw new Error(`index out of range (1..${this._state.subgoals.length})`);
|
|
109
142
|
}
|
|
@@ -145,10 +178,11 @@ export class GoalManager {
|
|
|
145
178
|
message: '',
|
|
146
179
|
};
|
|
147
180
|
}
|
|
181
|
+
const criteria = getGoalJudgeCriteria(state);
|
|
148
182
|
const outcome = await deps.judge({
|
|
149
183
|
goal: state.goal,
|
|
150
184
|
lastResponse,
|
|
151
|
-
...(
|
|
185
|
+
...(criteria.length ? { subgoals: criteria } : {}),
|
|
152
186
|
});
|
|
153
187
|
const decision = applyJudgeOutcome(state, outcome);
|
|
154
188
|
this.store.save(this.sessionKey, state);
|
|
@@ -166,7 +200,9 @@ export class GoalManager {
|
|
|
166
200
|
export function resolveGoalsConfig() {
|
|
167
201
|
let raw = {};
|
|
168
202
|
try {
|
|
169
|
-
const
|
|
203
|
+
const hierarchy = getSettingsHierarchy(process.cwd());
|
|
204
|
+
hierarchy.loadAllLevels?.();
|
|
205
|
+
const settings = hierarchy.getAllSettings();
|
|
170
206
|
if (settings && typeof settings.goals === 'object' && settings.goals !== null) {
|
|
171
207
|
raw = settings.goals;
|
|
172
208
|
}
|
|
@@ -174,21 +210,38 @@ export function resolveGoalsConfig() {
|
|
|
174
210
|
catch (error) {
|
|
175
211
|
logger.debug('goals: settings hierarchy unavailable, using defaults', { error: String(error) });
|
|
176
212
|
}
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const
|
|
213
|
+
const maxTurns = positiveInt(process.env.CODEBUDDY_GOAL_MAX_TURNS, 0)
|
|
214
|
+
|| positiveInt(raw.maxTurns, DEFAULT_MAX_TURNS);
|
|
215
|
+
const judgeModel = nonEmptyString(process.env.CODEBUDDY_GOAL_JUDGE_MODEL)
|
|
216
|
+
|| nonEmptyString(raw.judgeModel);
|
|
217
|
+
const plannerModel = nonEmptyString(process.env.CODEBUDDY_GOAL_PLANNER_MODEL)
|
|
218
|
+
|| nonEmptyString(raw.plannerModel);
|
|
182
219
|
return {
|
|
183
220
|
maxTurns,
|
|
184
221
|
judgeModel,
|
|
222
|
+
plannerModel,
|
|
185
223
|
judgeMaxTokens: positiveInt(raw.judgeMaxTokens, DEFAULT_JUDGE_MAX_TOKENS),
|
|
186
224
|
judgeTimeoutMs: positiveInt(raw.judgeTimeoutMs, DEFAULT_JUDGE_TIMEOUT_MS),
|
|
187
225
|
};
|
|
188
226
|
}
|
|
189
227
|
function positiveInt(value, fallback) {
|
|
190
|
-
const n =
|
|
191
|
-
return Number.
|
|
228
|
+
const n = parsePositiveSafeInteger(value);
|
|
229
|
+
return Number.isSafeInteger(n) && n > 0 ? n : fallback;
|
|
230
|
+
}
|
|
231
|
+
function nonEmptyString(value) {
|
|
232
|
+
if (typeof value !== 'string')
|
|
233
|
+
return '';
|
|
234
|
+
return value.trim();
|
|
235
|
+
}
|
|
236
|
+
function parsePositiveSafeInteger(value) {
|
|
237
|
+
if (typeof value === 'number')
|
|
238
|
+
return value;
|
|
239
|
+
if (typeof value !== 'string')
|
|
240
|
+
return Number.NaN;
|
|
241
|
+
const trimmed = value.trim();
|
|
242
|
+
if (!/^[1-9]\d*$/.test(trimmed))
|
|
243
|
+
return Number.NaN;
|
|
244
|
+
return Number(trimmed);
|
|
192
245
|
}
|
|
193
246
|
// ============================================================================
|
|
194
247
|
// Singleton registry (one manager per session key)
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* - A real user message mid-loop preempts the continuation prompt; the judge
|
|
17
17
|
* re-runs after that turn.
|
|
18
18
|
*/
|
|
19
|
+
import type { GoalPlan } from './goal-decomposer.js';
|
|
19
20
|
export type GoalStatus = 'active' | 'paused' | 'done' | 'cleared';
|
|
20
21
|
export type GoalVerdict = 'done' | 'continue' | 'skipped';
|
|
21
22
|
export interface GoalState {
|
|
@@ -37,6 +38,16 @@ export interface GoalState {
|
|
|
37
38
|
* empty so old persisted state loads unchanged.
|
|
38
39
|
*/
|
|
39
40
|
subgoals: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Optional Hermes-style decomposition graph generated for complex goals.
|
|
43
|
+
* Its acceptance criteria are fed to the judge alongside user-added
|
|
44
|
+
* subgoals, while remaining separate so /subgoal stays a manual control.
|
|
45
|
+
*/
|
|
46
|
+
goalPlan?: GoalPlan;
|
|
47
|
+
/** True once an LLM planning attempt was made for this goal. */
|
|
48
|
+
goalPlanAttempted?: boolean;
|
|
49
|
+
/** Last planning failure, kept for status/debug without retrying forever. */
|
|
50
|
+
goalPlanLastError?: string;
|
|
40
51
|
}
|
|
41
52
|
export declare const DEFAULT_MAX_TURNS = 20;
|
|
42
53
|
export declare const DEFAULT_JUDGE_TIMEOUT_MS = 30000;
|
|
@@ -47,12 +58,14 @@ export declare const JUDGE_RESPONSE_SNIPPET_CHARS = 4000;
|
|
|
47
58
|
export declare const MAX_CONSECUTIVE_PARSE_FAILURES = 3;
|
|
48
59
|
export declare const CONTINUATION_PROMPT_TEMPLATE: string;
|
|
49
60
|
export declare const CONTINUATION_PROMPT_WITH_SUBGOALS_TEMPLATE: string;
|
|
61
|
+
export declare const CONTINUATION_PROMPT_WITH_PLAN_TEMPLATE: string;
|
|
50
62
|
export declare const JUDGE_SYSTEM_PROMPT: string;
|
|
51
63
|
export declare const JUDGE_USER_PROMPT_TEMPLATE: string;
|
|
52
64
|
export declare const JUDGE_USER_PROMPT_WITH_SUBGOALS_TEMPLATE: string;
|
|
53
65
|
export declare function truncateText(text: string, limit: number): string;
|
|
54
66
|
/** Render subgoals as a numbered `- N. text` block. Empty string when none. */
|
|
55
67
|
export declare function renderSubgoalsBlock(subgoals: string[]): string;
|
|
68
|
+
export declare function getGoalJudgeCriteria(state: Pick<GoalState, 'goalPlan' | 'subgoals'>): string[];
|
|
56
69
|
export declare function createGoalState(goal: string, maxTurns?: number): GoalState;
|
|
57
70
|
/**
|
|
58
71
|
* Defensive deserialization of a persisted goal state. Returns null when the
|
package/dist/goals/goal-state.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* - A real user message mid-loop preempts the continuation prompt; the judge
|
|
17
17
|
* re-runs after that turn.
|
|
18
18
|
*/
|
|
19
|
+
import { formatGoalPlan, goalPlanToCriteria, normalizeGoalPlan, } from './goal-decomposer.js';
|
|
19
20
|
// ──────────────────────────────────────────────────────────────────────
|
|
20
21
|
// Constants & defaults
|
|
21
22
|
// ──────────────────────────────────────────────────────────────────────
|
|
@@ -47,27 +48,56 @@ export const CONTINUATION_PROMPT_WITH_SUBGOALS_TEMPLATE = '[Continuing toward yo
|
|
|
47
48
|
'additional criterion are complete, state so explicitly and stop. ' +
|
|
48
49
|
'If you are blocked and need input from the user, say so clearly ' +
|
|
49
50
|
'and stop.';
|
|
51
|
+
export const CONTINUATION_PROMPT_WITH_PLAN_TEMPLATE = '[Continuing toward your standing goal]\n' +
|
|
52
|
+
'Goal: {goal}\n\n' +
|
|
53
|
+
'Decomposition plan:\n' +
|
|
54
|
+
'{goal_plan_block}\n\n' +
|
|
55
|
+
'{manual_subgoals_block}' +
|
|
56
|
+
'Continue working through the plan. Prefer ready tasks whose dependencies ' +
|
|
57
|
+
'are already satisfied, keep independent lanes separate, and produce ' +
|
|
58
|
+
'concrete evidence for every acceptance criterion. If you believe the goal ' +
|
|
59
|
+
'and every criterion are complete, state so explicitly and stop. If you are ' +
|
|
60
|
+
'blocked and need input from the user, say so clearly and stop.';
|
|
50
61
|
export const JUDGE_SYSTEM_PROMPT = "You are a strict judge evaluating whether an autonomous agent has " +
|
|
51
62
|
"achieved a user's stated goal. You receive the goal text and the " +
|
|
52
63
|
"agent's most recent response. Your only job is to decide whether " +
|
|
53
64
|
'the goal is fully satisfied based on that response.\n\n' +
|
|
65
|
+
'The response may begin with internal evidence metadata such as ' +
|
|
66
|
+
'`[tool evidence: none]` or `[tool:<name> success]`. Treat those ' +
|
|
67
|
+
'bracketed metadata lines as evidence annotations only. They are NOT ' +
|
|
68
|
+
"part of the assistant's answer text for exact-answer goals; ignore " +
|
|
69
|
+
'the metadata itself when comparing exact requested output. For ' +
|
|
70
|
+
'side-effect goals, use the metadata and any following tool output to ' +
|
|
71
|
+
'decide whether concrete evidence exists.\n\n' +
|
|
54
72
|
'A goal is DONE only when:\n' +
|
|
55
|
-
'-
|
|
73
|
+
'- For answer-only or explanation goals, the response directly answers the requested question, OR\n' +
|
|
56
74
|
'- The response clearly shows the final deliverable was produced, OR\n' +
|
|
57
75
|
'- The response explains the goal is unachievable / blocked / needs ' +
|
|
58
76
|
'user input (treat this as DONE with reason describing the block).\n\n' +
|
|
77
|
+
'For goals that require external side effects such as creating, editing, ' +
|
|
78
|
+
'moving, deleting, reading, or verifying files; running commands; calling ' +
|
|
79
|
+
'tools; changing repository state; or producing artifacts, unsupported ' +
|
|
80
|
+
'assistant claims are NOT evidence. Do not accept statements like "I ' +
|
|
81
|
+
'created the file" or "I verified it" unless the response includes concrete ' +
|
|
82
|
+
'evidence such as a tool result, command output, file contents excerpt, diff, ' +
|
|
83
|
+
'test output, or artifact path backed by tool output. If a side-effect goal ' +
|
|
84
|
+
'has no concrete evidence, return CONTINUE.\n\n' +
|
|
59
85
|
'Otherwise the goal is NOT done — CONTINUE.\n\n' +
|
|
60
86
|
'Reply ONLY with a single JSON object on one line:\n' +
|
|
61
87
|
'{"done": <true|false>, "reason": "<one-sentence rationale>"}';
|
|
62
88
|
export const JUDGE_USER_PROMPT_TEMPLATE = 'Goal:\n{goal}\n\n' +
|
|
63
|
-
"Agent's most recent response:\n{response}\n\n" +
|
|
64
89
|
'Current time: {current_time}\n\n' +
|
|
90
|
+
"Agent's most recent response is delimited by <response> tags. " +
|
|
91
|
+
'Text outside those tags is prompt metadata, not part of the response:\n' +
|
|
92
|
+
'<response>\n{response}\n</response>\n\n' +
|
|
65
93
|
'Is the goal satisfied?';
|
|
66
94
|
export const JUDGE_USER_PROMPT_WITH_SUBGOALS_TEMPLATE = 'Goal:\n{goal}\n\n' +
|
|
67
95
|
'Additional criteria the user added mid-loop (all must also be ' +
|
|
68
96
|
'satisfied for the goal to be DONE):\n{subgoals_block}\n\n' +
|
|
69
|
-
"Agent's most recent response:\n{response}\n\n" +
|
|
70
97
|
'Current time: {current_time}\n\n' +
|
|
98
|
+
"Agent's most recent response is delimited by <response> tags. " +
|
|
99
|
+
'Text outside those tags is prompt metadata, not part of the response:\n' +
|
|
100
|
+
'<response>\n{response}\n</response>\n\n' +
|
|
71
101
|
'Decision: For each numbered criterion above, find concrete ' +
|
|
72
102
|
"evidence in the agent's response that the criterion is " +
|
|
73
103
|
"satisfied. Do not accept generic phrases like 'all requirements " +
|
|
@@ -92,7 +122,13 @@ export function renderSubgoalsBlock(subgoals) {
|
|
|
92
122
|
return '';
|
|
93
123
|
return subgoals.map((text, i) => `- ${i + 1}. ${text}`).join('\n');
|
|
94
124
|
}
|
|
125
|
+
export function getGoalJudgeCriteria(state) {
|
|
126
|
+
return [...goalPlanToCriteria(state.goalPlan), ...state.subgoals];
|
|
127
|
+
}
|
|
95
128
|
export function createGoalState(goal, maxTurns = DEFAULT_MAX_TURNS) {
|
|
129
|
+
if (!Number.isSafeInteger(maxTurns) || maxTurns <= 0) {
|
|
130
|
+
throw new Error('maxTurns must be a positive integer');
|
|
131
|
+
}
|
|
96
132
|
return {
|
|
97
133
|
goal,
|
|
98
134
|
status: 'active',
|
|
@@ -121,19 +157,28 @@ export function normalizeGoalState(raw) {
|
|
|
121
157
|
const subgoals = Array.isArray(data.subgoals)
|
|
122
158
|
? data.subgoals.map(s => String(s).trim()).filter(Boolean)
|
|
123
159
|
: [];
|
|
160
|
+
const goalPlan = normalizeGoalPlan(data.goalPlan);
|
|
124
161
|
const verdict = ['done', 'continue', 'skipped'].includes(String(data.lastVerdict))
|
|
125
162
|
? data.lastVerdict
|
|
126
163
|
: undefined;
|
|
127
164
|
const state = {
|
|
128
165
|
goal,
|
|
129
166
|
status,
|
|
130
|
-
turnsUsed:
|
|
131
|
-
maxTurns:
|
|
167
|
+
turnsUsed: toNonNegativeInt(data.turnsUsed, 0),
|
|
168
|
+
maxTurns: toPositiveInt(data.maxTurns, DEFAULT_MAX_TURNS),
|
|
132
169
|
createdAt: toNumber(data.createdAt, 0),
|
|
133
170
|
lastTurnAt: toNumber(data.lastTurnAt, 0),
|
|
134
|
-
consecutiveParseFailures:
|
|
171
|
+
consecutiveParseFailures: toNonNegativeInt(data.consecutiveParseFailures, 0),
|
|
135
172
|
subgoals,
|
|
136
173
|
};
|
|
174
|
+
if (goalPlan)
|
|
175
|
+
state.goalPlan = goalPlan;
|
|
176
|
+
if (typeof data.goalPlanAttempted === 'boolean') {
|
|
177
|
+
state.goalPlanAttempted = data.goalPlanAttempted;
|
|
178
|
+
}
|
|
179
|
+
if (typeof data.goalPlanLastError === 'string') {
|
|
180
|
+
state.goalPlanLastError = data.goalPlanLastError;
|
|
181
|
+
}
|
|
137
182
|
if (verdict)
|
|
138
183
|
state.lastVerdict = verdict;
|
|
139
184
|
if (typeof data.lastReason === 'string')
|
|
@@ -142,9 +187,23 @@ export function normalizeGoalState(raw) {
|
|
|
142
187
|
state.pausedReason = data.pausedReason;
|
|
143
188
|
return state;
|
|
144
189
|
}
|
|
145
|
-
function
|
|
146
|
-
const n =
|
|
147
|
-
return Number.
|
|
190
|
+
function toPositiveInt(value, fallback) {
|
|
191
|
+
const n = parseSafeInteger(value, /^[1-9]\d*$/);
|
|
192
|
+
return Number.isSafeInteger(n) && n > 0 ? n : fallback;
|
|
193
|
+
}
|
|
194
|
+
function toNonNegativeInt(value, fallback) {
|
|
195
|
+
const n = parseSafeInteger(value, /^(?:0|[1-9]\d*)$/);
|
|
196
|
+
return Number.isSafeInteger(n) && n >= 0 ? n : fallback;
|
|
197
|
+
}
|
|
198
|
+
function parseSafeInteger(value, stringPattern) {
|
|
199
|
+
if (typeof value === 'number')
|
|
200
|
+
return value;
|
|
201
|
+
if (typeof value !== 'string')
|
|
202
|
+
return Number.NaN;
|
|
203
|
+
const trimmed = value.trim();
|
|
204
|
+
if (!stringPattern.test(trimmed))
|
|
205
|
+
return Number.NaN;
|
|
206
|
+
return Number(trimmed);
|
|
148
207
|
}
|
|
149
208
|
function toNumber(value, fallback) {
|
|
150
209
|
const n = Number(value);
|
|
@@ -159,20 +218,31 @@ export function formatGoalStatusLine(state) {
|
|
|
159
218
|
const sub = state.subgoals.length
|
|
160
219
|
? `, ${state.subgoals.length} subgoal${state.subgoals.length !== 1 ? 's' : ''}`
|
|
161
220
|
: '';
|
|
221
|
+
const plan = state.goalPlan
|
|
222
|
+
? `, plan ${state.goalPlan.tasks.length} task${state.goalPlan.tasks.length !== 1 ? 's' : ''}`
|
|
223
|
+
: '';
|
|
162
224
|
if (state.status === 'active') {
|
|
163
|
-
return `⊙ Goal (active, ${turns}${sub}): ${state.goal}`;
|
|
225
|
+
return `⊙ Goal (active, ${turns}${sub}${plan}): ${state.goal}`;
|
|
164
226
|
}
|
|
165
227
|
if (state.status === 'paused') {
|
|
166
228
|
const extra = state.pausedReason ? ` — ${state.pausedReason}` : '';
|
|
167
|
-
return `⏸ Goal (paused, ${turns}${sub}${extra}): ${state.goal}`;
|
|
229
|
+
return `⏸ Goal (paused, ${turns}${sub}${plan}${extra}): ${state.goal}`;
|
|
168
230
|
}
|
|
169
231
|
if (state.status === 'done') {
|
|
170
|
-
return `✓ Goal done (${turns}${sub}): ${state.goal}`;
|
|
232
|
+
return `✓ Goal done (${turns}${sub}${plan}): ${state.goal}`;
|
|
171
233
|
}
|
|
172
|
-
return `Goal (${state.status}, ${turns}${sub}): ${state.goal}`;
|
|
234
|
+
return `Goal (${state.status}, ${turns}${sub}${plan}): ${state.goal}`;
|
|
173
235
|
}
|
|
174
236
|
/** The canonical user-role continuation message for an active goal. */
|
|
175
237
|
export function buildContinuationPrompt(state) {
|
|
238
|
+
if (state.goalPlan) {
|
|
239
|
+
const manualSubgoalsBlock = state.subgoals.length
|
|
240
|
+
? `Additional user criteria:\n${renderSubgoalsBlock(state.subgoals)}\n\n`
|
|
241
|
+
: '';
|
|
242
|
+
return CONTINUATION_PROMPT_WITH_PLAN_TEMPLATE.replace('{goal}', state.goal)
|
|
243
|
+
.replace('{goal_plan_block}', formatGoalPlan(state.goalPlan))
|
|
244
|
+
.replace('{manual_subgoals_block}', manualSubgoalsBlock);
|
|
245
|
+
}
|
|
176
246
|
if (state.subgoals.length) {
|
|
177
247
|
return CONTINUATION_PROMPT_WITH_SUBGOALS_TEMPLATE.replace('{goal}', state.goal).replace('{subgoals_block}', renderSubgoalsBlock(state.subgoals));
|
|
178
248
|
}
|
package/dist/goals/goal-store.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Cleared goals keep a tombstone (`status: 'cleared'`) for audit, mirroring
|
|
10
10
|
* Hermes' SessionDB behavior.
|
|
11
11
|
*/
|
|
12
|
+
import { createHash } from 'crypto';
|
|
12
13
|
import fs from 'fs';
|
|
13
14
|
import path from 'path';
|
|
14
15
|
import { getCodeBuddyPath } from '../utils/codebuddy-home.js';
|
|
@@ -25,17 +26,18 @@ export class GoalStore {
|
|
|
25
26
|
load(key) {
|
|
26
27
|
if (!key)
|
|
27
28
|
return null;
|
|
28
|
-
const file
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
for (const file of this.fileCandidatesForRead(key)) {
|
|
30
|
+
try {
|
|
31
|
+
if (!fs.existsSync(file))
|
|
32
|
+
continue;
|
|
33
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
34
|
+
return normalizeGoalState(JSON.parse(raw));
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
logger.debug('GoalStore: failed to load goal state', { key, file, error: String(error) });
|
|
38
|
+
}
|
|
38
39
|
}
|
|
40
|
+
return null;
|
|
39
41
|
}
|
|
40
42
|
save(key, state) {
|
|
41
43
|
if (!key)
|
|
@@ -54,18 +56,32 @@ export class GoalStore {
|
|
|
54
56
|
delete(key) {
|
|
55
57
|
if (!key)
|
|
56
58
|
return;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
for (const file of this.fileCandidatesForRead(key)) {
|
|
60
|
+
try {
|
|
61
|
+
fs.rmSync(file, { force: true });
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
logger.debug('GoalStore: failed to delete goal state', { key, file, error: String(error) });
|
|
65
|
+
}
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
fileFor(key) {
|
|
69
|
+
const label = this.fileLabel(key);
|
|
70
|
+
const digest = createHash('sha256').update(key).digest('hex').slice(0, 16);
|
|
71
|
+
return path.join(this.storeDir, `${label}-${digest}.json`);
|
|
72
|
+
}
|
|
73
|
+
fileCandidatesForRead(key) {
|
|
74
|
+
return Array.from(new Set([this.fileFor(key), this.legacyFileFor(key)]));
|
|
75
|
+
}
|
|
76
|
+
legacyFileFor(key) {
|
|
65
77
|
// Session ids and dir-hash keys are already filesystem-safe; sanitize
|
|
66
78
|
// anyway so a malformed key can't escape the store directory.
|
|
67
79
|
const safe = key.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
68
80
|
return path.join(this.storeDir, `${safe}.json`);
|
|
69
81
|
}
|
|
82
|
+
fileLabel(key) {
|
|
83
|
+
const safe = key.replace(/[^a-zA-Z0-9._-]/g, '_').replace(/^\.+$/, '_').slice(0, 80);
|
|
84
|
+
return safe || 'goal';
|
|
85
|
+
}
|
|
70
86
|
}
|
|
71
87
|
//# sourceMappingURL=goal-store.js.map
|