@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
|
@@ -140,6 +140,10 @@ export interface JobRun {
|
|
|
140
140
|
result?: unknown;
|
|
141
141
|
error?: string;
|
|
142
142
|
duration?: number;
|
|
143
|
+
/** Structured output from this job run, passed as inputData to chained jobs. */
|
|
144
|
+
outputData?: string;
|
|
145
|
+
/** Input data received from a parent job in a chain. */
|
|
146
|
+
inputData?: string;
|
|
143
147
|
}
|
|
144
148
|
export interface CronSchedulerConfig {
|
|
145
149
|
/** Jobs persist path */
|
|
@@ -174,7 +178,7 @@ export declare class CronScheduler extends EventEmitter {
|
|
|
174
178
|
/**
|
|
175
179
|
* Set the task executor (for CronAgentBridge integration)
|
|
176
180
|
*/
|
|
177
|
-
setTaskExecutor(executor: (job: CronJob) => Promise<unknown>): void;
|
|
181
|
+
setTaskExecutor(executor: (job: CronJob, inputData?: string) => Promise<unknown>): void;
|
|
178
182
|
/**
|
|
179
183
|
* Load persisted jobs into memory without starting the tick loop. Useful for
|
|
180
184
|
* one-shot CLI commands (`buddy cron list/add/remove`) that must see the
|
|
@@ -182,7 +186,7 @@ export declare class CronScheduler extends EventEmitter {
|
|
|
182
186
|
* overwrite the file with only the in-memory jobs.
|
|
183
187
|
*/
|
|
184
188
|
loadFromDisk(): Promise<void>;
|
|
185
|
-
start(taskExecutor?: (job: CronJob) => Promise<unknown>): Promise<void>;
|
|
189
|
+
start(taskExecutor?: (job: CronJob, inputData?: string) => Promise<unknown>): Promise<void>;
|
|
186
190
|
stop(): Promise<void>;
|
|
187
191
|
/**
|
|
188
192
|
* Add a new job
|
|
@@ -232,11 +236,19 @@ export declare class CronScheduler extends EventEmitter {
|
|
|
232
236
|
/**
|
|
233
237
|
* Run a job immediately
|
|
234
238
|
*/
|
|
235
|
-
runJobNow(jobId: string): Promise<JobRun | null>;
|
|
239
|
+
runJobNow(jobId: string, inputData?: string): Promise<JobRun | null>;
|
|
236
240
|
private scheduleJob;
|
|
237
241
|
private cancelJobTimer;
|
|
238
242
|
private calculateNextRun;
|
|
239
243
|
private executeJob;
|
|
244
|
+
/** Max bytes for outputData passed between chained jobs. */
|
|
245
|
+
private static readonly MAX_OUTPUT_DATA_BYTES;
|
|
246
|
+
/**
|
|
247
|
+
* Extract a string `outputData` from the executor result. Looks for an
|
|
248
|
+
* explicit `outputData` field first, then falls back to `output`, then
|
|
249
|
+
* stringifies the whole result. Always capped at 64KB.
|
|
250
|
+
*/
|
|
251
|
+
static extractOutputData(result: unknown): string | undefined;
|
|
240
252
|
/**
|
|
241
253
|
* Resolve and execute a chained (`then`) job after its parent succeeds.
|
|
242
254
|
*
|
|
@@ -304,11 +304,11 @@ export class CronScheduler extends EventEmitter {
|
|
|
304
304
|
/**
|
|
305
305
|
* Run a job immediately
|
|
306
306
|
*/
|
|
307
|
-
async runJobNow(jobId) {
|
|
307
|
+
async runJobNow(jobId, inputData) {
|
|
308
308
|
const job = this.jobs.get(jobId);
|
|
309
309
|
if (!job)
|
|
310
310
|
return null;
|
|
311
|
-
return await this.executeJob(job);
|
|
311
|
+
return await this.executeJob(job, 0, inputData);
|
|
312
312
|
}
|
|
313
313
|
// ==========================================================================
|
|
314
314
|
// Scheduling
|
|
@@ -379,19 +379,20 @@ export class CronScheduler extends EventEmitter {
|
|
|
379
379
|
// ==========================================================================
|
|
380
380
|
// Execution
|
|
381
381
|
// ==========================================================================
|
|
382
|
-
async executeJob(job, chainDepth = 0) {
|
|
382
|
+
async executeJob(job, chainDepth = 0, inputData) {
|
|
383
383
|
const run = {
|
|
384
384
|
id: crypto.randomUUID(),
|
|
385
385
|
jobId: job.id,
|
|
386
386
|
startedAt: new Date(),
|
|
387
387
|
status: 'running',
|
|
388
|
+
...(inputData !== undefined ? { inputData } : {}),
|
|
388
389
|
};
|
|
389
390
|
this.emit('job:run:start', run);
|
|
390
391
|
try {
|
|
391
392
|
// Execute task
|
|
392
393
|
let result;
|
|
393
394
|
if (this.taskExecutor) {
|
|
394
|
-
result = await this.taskExecutor(job);
|
|
395
|
+
result = await this.taskExecutor(job, inputData);
|
|
395
396
|
}
|
|
396
397
|
else {
|
|
397
398
|
// Default execution (just log)
|
|
@@ -401,6 +402,10 @@ export class CronScheduler extends EventEmitter {
|
|
|
401
402
|
run.status = 'success';
|
|
402
403
|
run.result = result;
|
|
403
404
|
run.duration = run.completedAt.getTime() - run.startedAt.getTime();
|
|
405
|
+
// Extract outputData from the executor result for cross-job data passing.
|
|
406
|
+
// The executor may return an object with an `output` or `outputData`
|
|
407
|
+
// field; we cap at 64KB to keep run history manageable.
|
|
408
|
+
run.outputData = CronScheduler.extractOutputData(result);
|
|
404
409
|
job.lastRunAt = run.startedAt;
|
|
405
410
|
job.runCount++;
|
|
406
411
|
// Reset backoff on success
|
|
@@ -444,10 +449,50 @@ export class CronScheduler extends EventEmitter {
|
|
|
444
449
|
// successful run, so the chain runs inside a guarded helper that swallows
|
|
445
450
|
// (and logs) any error from the chained job.
|
|
446
451
|
if (run.status === 'success' && job.then) {
|
|
447
|
-
await this.runChainedJob(job, chainDepth);
|
|
452
|
+
await this.runChainedJob(job, chainDepth, run.outputData);
|
|
448
453
|
}
|
|
449
454
|
return run;
|
|
450
455
|
}
|
|
456
|
+
/** Max bytes for outputData passed between chained jobs. */
|
|
457
|
+
static MAX_OUTPUT_DATA_BYTES = 65_536; // 64 KiB
|
|
458
|
+
/**
|
|
459
|
+
* Extract a string `outputData` from the executor result. Looks for an
|
|
460
|
+
* explicit `outputData` field first, then falls back to `output`, then
|
|
461
|
+
* stringifies the whole result. Always capped at 64KB.
|
|
462
|
+
*/
|
|
463
|
+
static extractOutputData(result) {
|
|
464
|
+
if (result == null)
|
|
465
|
+
return undefined;
|
|
466
|
+
let raw;
|
|
467
|
+
if (typeof result === 'string') {
|
|
468
|
+
raw = result;
|
|
469
|
+
}
|
|
470
|
+
else if (typeof result === 'object') {
|
|
471
|
+
const obj = result;
|
|
472
|
+
if (typeof obj.outputData === 'string') {
|
|
473
|
+
raw = obj.outputData;
|
|
474
|
+
}
|
|
475
|
+
else if (typeof obj.output === 'string') {
|
|
476
|
+
raw = obj.output;
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
try {
|
|
480
|
+
raw = JSON.stringify(result);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
return undefined;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
raw = String(result);
|
|
489
|
+
}
|
|
490
|
+
if (!raw || raw.length === 0)
|
|
491
|
+
return undefined;
|
|
492
|
+
return raw.length > CronScheduler.MAX_OUTPUT_DATA_BYTES
|
|
493
|
+
? raw.slice(0, CronScheduler.MAX_OUTPUT_DATA_BYTES)
|
|
494
|
+
: raw;
|
|
495
|
+
}
|
|
451
496
|
/**
|
|
452
497
|
* Resolve and execute a chained (`then`) job after its parent succeeds.
|
|
453
498
|
*
|
|
@@ -455,7 +500,7 @@ export class CronScheduler extends EventEmitter {
|
|
|
455
500
|
* authored out of order. A missing/disabled target, a self-reference, or a
|
|
456
501
|
* depth-cap breach is logged and stops the chain — it never throws.
|
|
457
502
|
*/
|
|
458
|
-
async runChainedJob(parent, chainDepth) {
|
|
503
|
+
async runChainedJob(parent, chainDepth, outputData) {
|
|
459
504
|
const target = parent.then;
|
|
460
505
|
if (!target)
|
|
461
506
|
return;
|
|
@@ -493,7 +538,8 @@ export class CronScheduler extends EventEmitter {
|
|
|
493
538
|
return;
|
|
494
539
|
}
|
|
495
540
|
try {
|
|
496
|
-
|
|
541
|
+
// Pass the parent job's outputData as the chained job's inputData.
|
|
542
|
+
await this.executeJob(next, chainDepth + 1, outputData);
|
|
497
543
|
}
|
|
498
544
|
catch (err) {
|
|
499
545
|
// A chained failure is captured in the chained job's own run record; it
|
|
@@ -26,6 +26,8 @@ export interface CronScriptResult {
|
|
|
26
26
|
exitCode: number | null;
|
|
27
27
|
/** Combined stdout + stderr, capped. */
|
|
28
28
|
output: string;
|
|
29
|
+
/** Stdout only, capped at 64KB. Used for cross-job data passing. */
|
|
30
|
+
stdout: string;
|
|
29
31
|
/** True when the timeout fired and the process was killed. */
|
|
30
32
|
timedOut: boolean;
|
|
31
33
|
}
|
|
@@ -16,6 +16,7 @@ import { spawn } from 'child_process';
|
|
|
16
16
|
import path from 'path';
|
|
17
17
|
const DEFAULT_SCRIPT_TIMEOUT_MS = 600_000;
|
|
18
18
|
const MAX_OUTPUT_BYTES = 1_048_576; // 1 MiB cap on captured output
|
|
19
|
+
const MAX_STDOUT_BYTES = 65_536; // 64 KiB cap on stdout for data passing
|
|
19
20
|
const DEFAULT_ALLOWED_EXECUTABLES = new Set([
|
|
20
21
|
'bash',
|
|
21
22
|
'cargo',
|
|
@@ -68,27 +69,41 @@ function spawnScript(command, timeoutMs) {
|
|
|
68
69
|
windowsHide: true,
|
|
69
70
|
});
|
|
70
71
|
let output = '';
|
|
72
|
+
let stdoutOnly = '';
|
|
71
73
|
let timedOut = false;
|
|
72
|
-
const
|
|
74
|
+
const appendOutput = (chunk) => {
|
|
73
75
|
if (output.length < MAX_OUTPUT_BYTES) {
|
|
74
76
|
output += chunk;
|
|
75
77
|
}
|
|
76
78
|
};
|
|
79
|
+
const appendStdout = (chunk) => {
|
|
80
|
+
if (stdoutOnly.length < MAX_STDOUT_BYTES) {
|
|
81
|
+
stdoutOnly += chunk;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
77
84
|
const timer = setTimeout(() => {
|
|
78
85
|
timedOut = true;
|
|
79
86
|
child.kill('SIGTERM');
|
|
80
87
|
}, timeoutMs);
|
|
81
88
|
child.stdout.setEncoding('utf8');
|
|
82
|
-
child.stdout.on('data',
|
|
89
|
+
child.stdout.on('data', (chunk) => {
|
|
90
|
+
appendOutput(chunk);
|
|
91
|
+
appendStdout(chunk);
|
|
92
|
+
});
|
|
83
93
|
child.stderr.setEncoding('utf8');
|
|
84
|
-
child.stderr.on('data',
|
|
94
|
+
child.stderr.on('data', appendOutput);
|
|
85
95
|
child.on('error', (error) => {
|
|
86
96
|
clearTimeout(timer);
|
|
87
97
|
reject(error);
|
|
88
98
|
});
|
|
89
99
|
child.on('close', (exitCode) => {
|
|
90
100
|
clearTimeout(timer);
|
|
91
|
-
resolve({
|
|
101
|
+
resolve({
|
|
102
|
+
exitCode,
|
|
103
|
+
output: output.trimEnd(),
|
|
104
|
+
stdout: stdoutOnly.trimEnd(),
|
|
105
|
+
timedOut,
|
|
106
|
+
});
|
|
92
107
|
});
|
|
93
108
|
});
|
|
94
109
|
}
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* The aggregate `ok` is true only when there are no alerts and no errors.
|
|
17
17
|
*/
|
|
18
18
|
import { spawn } from 'child_process';
|
|
19
|
-
import fs from 'fs';
|
|
20
19
|
import path from 'path';
|
|
20
|
+
import { getFreeSpaceInfo } from '../utils/disk-guard.js';
|
|
21
21
|
const DEFAULT_HTTP_TIMEOUT_MS = 10_000;
|
|
22
22
|
const DEFAULT_BUILD_ALLOWED_EXECUTABLES = new Set([
|
|
23
23
|
'bash',
|
|
@@ -115,32 +115,19 @@ async function runSingleCheck(check, allowedExecutables) {
|
|
|
115
115
|
}
|
|
116
116
|
function checkDisk(check, name) {
|
|
117
117
|
const target = check.path || process.cwd();
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
// Single source of truth for free space (uses bavail); null when statfs is
|
|
119
|
+
// unavailable or the path can't be stat'd.
|
|
120
|
+
const info = getFreeSpaceInfo(target);
|
|
121
|
+
if (info === null) {
|
|
120
122
|
return {
|
|
121
123
|
type: 'disk',
|
|
122
124
|
name,
|
|
123
125
|
status: 'error',
|
|
124
|
-
summary:
|
|
126
|
+
summary: `cannot determine free space at ${target} (fs.statfsSync unavailable or path unreadable)`,
|
|
125
127
|
details: { path: target },
|
|
126
128
|
};
|
|
127
129
|
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
stats = statfs(target);
|
|
131
|
-
}
|
|
132
|
-
catch (err) {
|
|
133
|
-
return {
|
|
134
|
-
type: 'disk',
|
|
135
|
-
name,
|
|
136
|
-
status: 'error',
|
|
137
|
-
summary: `cannot stat filesystem at ${target}: ${errMsg(err)}`,
|
|
138
|
-
details: { path: target },
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const totalBytes = stats.blocks * stats.bsize;
|
|
142
|
-
const freeBytes = stats.bavail * stats.bsize;
|
|
143
|
-
const freePercent = totalBytes > 0 ? (freeBytes / totalBytes) * 100 : 0;
|
|
130
|
+
const { freeBytes, totalBytes, freePercent } = info;
|
|
144
131
|
const breaches = [];
|
|
145
132
|
if (typeof check.minFreeBytes === 'number' && freeBytes < check.minFreeBytes) {
|
|
146
133
|
breaches.push(`free ${formatBytes(freeBytes)} < min ${formatBytes(check.minFreeBytes)}`);
|
|
@@ -89,8 +89,13 @@ export class USearchVectorIndex extends EventEmitter {
|
|
|
89
89
|
*/
|
|
90
90
|
async loadUSearch() {
|
|
91
91
|
try {
|
|
92
|
-
// Dynamic import for
|
|
93
|
-
|
|
92
|
+
// Dynamic import for an OPTIONAL native dependency (see optionalDependencies).
|
|
93
|
+
// Use a non-literal specifier so `tsc` doesn't require 'usearch' to be
|
|
94
|
+
// resolvable on every platform — it isn't installed on some CI runners
|
|
95
|
+
// (e.g. windows-latest), which otherwise fails type-check with TS2307.
|
|
96
|
+
// Types come from the local USearchModule interface, not the package.
|
|
97
|
+
const usearchSpecifier = 'usearch';
|
|
98
|
+
const usearch = (await import(usearchSpecifier));
|
|
94
99
|
return usearch;
|
|
95
100
|
}
|
|
96
101
|
catch (_err) {
|
|
@@ -42,6 +42,8 @@ export const TOOL_GROUPS = {
|
|
|
42
42
|
// Runtime - Process
|
|
43
43
|
spawn_process: ['group:runtime', 'group:runtime:process'],
|
|
44
44
|
kill_process: ['group:runtime', 'group:runtime:process', 'group:dangerous'],
|
|
45
|
+
// Runtime - Office macros (arbitrary VBA/PowerShell via COM, Windows only)
|
|
46
|
+
office_macro_execute: ['group:runtime', 'group:runtime:shell', 'group:dangerous'],
|
|
45
47
|
// Web - Fetch
|
|
46
48
|
web_fetch: ['group:web', 'group:web:fetch'],
|
|
47
49
|
http_request: ['group:web', 'group:web:fetch'],
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dreaming — heartbeat-paced memory consolidation. Every N beats, the short-term
|
|
3
|
+
* sensory buffer is drained and consolidated into a compact "dream" summary
|
|
4
|
+
* (counts by kind, salient events, time window, average load) appended to a
|
|
5
|
+
* long-term dream journal. The heartbeat-paced analogue of OpenClaw's dreaming
|
|
6
|
+
* (short-term recall → consolidated long-term memory).
|
|
7
|
+
*
|
|
8
|
+
* @module sensory/dreaming
|
|
9
|
+
*/
|
|
10
|
+
import type { Perception } from './reactions.js';
|
|
11
|
+
export interface DreamSummary {
|
|
12
|
+
dreamedAt: number;
|
|
13
|
+
windowStartMs: number | null;
|
|
14
|
+
windowEndMs: number | null;
|
|
15
|
+
total: number;
|
|
16
|
+
/** "audio/speech_start" → count, "vital/heartbeat" → count, … */
|
|
17
|
+
byKind: Record<string, number>;
|
|
18
|
+
salient: Array<{
|
|
19
|
+
modality?: string;
|
|
20
|
+
kind?: string;
|
|
21
|
+
salience?: number;
|
|
22
|
+
tsMs?: number;
|
|
23
|
+
}>;
|
|
24
|
+
avgLoad: number | null;
|
|
25
|
+
}
|
|
26
|
+
/** Pure consolidation: summarize a window of perceptions into a dream. */
|
|
27
|
+
export declare function consolidate(perceptions: Perception[], now: number): DreamSummary;
|
|
28
|
+
export interface DreamingOptions {
|
|
29
|
+
cwd?: string;
|
|
30
|
+
now?: number;
|
|
31
|
+
/** Injectable promotion (tests); defaults to promoteSalientDream. */
|
|
32
|
+
promote?: (summary: DreamSummary) => Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* One dreaming pass: drain the short-term buffer, consolidate, append to the
|
|
36
|
+
* dream journal, and promote a SALIENT dream into long-term persistent memory.
|
|
37
|
+
* Returns the summary, or null if there was nothing to consolidate.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runDreamingPass(options?: DreamingOptions): Promise<DreamSummary | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Promote a salient dream into Code Buddy's persistent memory under a STABLE key
|
|
42
|
+
* (`dream:recent`) so repeated promotions UPDATE rather than accumulate (stays
|
|
43
|
+
* within the memory char budget). Never throws.
|
|
44
|
+
*/
|
|
45
|
+
export declare function promoteSalientDream(summary: DreamSummary): Promise<void>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dreaming — heartbeat-paced memory consolidation. Every N beats, the short-term
|
|
3
|
+
* sensory buffer is drained and consolidated into a compact "dream" summary
|
|
4
|
+
* (counts by kind, salient events, time window, average load) appended to a
|
|
5
|
+
* long-term dream journal. The heartbeat-paced analogue of OpenClaw's dreaming
|
|
6
|
+
* (short-term recall → consolidated long-term memory).
|
|
7
|
+
*
|
|
8
|
+
* @module sensory/dreaming
|
|
9
|
+
*/
|
|
10
|
+
import { appendFile, mkdir, stat, rename } from 'fs/promises';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { getSensoryMemory } from './sensory-memory.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
const SALIENT_THRESHOLD = 128;
|
|
15
|
+
/** Pure consolidation: summarize a window of perceptions into a dream. */
|
|
16
|
+
export function consolidate(perceptions, now) {
|
|
17
|
+
const byKind = {};
|
|
18
|
+
const salient = [];
|
|
19
|
+
let loadSum = 0;
|
|
20
|
+
let loadN = 0;
|
|
21
|
+
let minTs = null;
|
|
22
|
+
let maxTs = null;
|
|
23
|
+
for (const p of perceptions) {
|
|
24
|
+
const key = `${p.modality}/${p.kind}`;
|
|
25
|
+
byKind[key] = (byKind[key] ?? 0) + 1;
|
|
26
|
+
if ((p.salience ?? 0) >= SALIENT_THRESHOLD) {
|
|
27
|
+
salient.push({ modality: p.modality, kind: p.kind, salience: p.salience, tsMs: p.tsMs });
|
|
28
|
+
}
|
|
29
|
+
const load = p.payload?.load1;
|
|
30
|
+
if (typeof load === 'number') {
|
|
31
|
+
loadSum += load;
|
|
32
|
+
loadN += 1;
|
|
33
|
+
}
|
|
34
|
+
// Window on the ingest wall-clock (consistent across senses), not the
|
|
35
|
+
// sense-relative tsMs (frame-relative for audio vs unix for vital).
|
|
36
|
+
if (typeof p.receivedAt === 'number') {
|
|
37
|
+
minTs = minTs === null ? p.receivedAt : Math.min(minTs, p.receivedAt);
|
|
38
|
+
maxTs = maxTs === null ? p.receivedAt : Math.max(maxTs, p.receivedAt);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
dreamedAt: now,
|
|
43
|
+
windowStartMs: minTs,
|
|
44
|
+
windowEndMs: maxTs,
|
|
45
|
+
total: perceptions.length,
|
|
46
|
+
byKind,
|
|
47
|
+
salient: salient.slice(0, 20),
|
|
48
|
+
avgLoad: loadN > 0 ? loadSum / loadN : null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One dreaming pass: drain the short-term buffer, consolidate, append to the
|
|
53
|
+
* dream journal, and promote a SALIENT dream into long-term persistent memory.
|
|
54
|
+
* Returns the summary, or null if there was nothing to consolidate.
|
|
55
|
+
*/
|
|
56
|
+
export async function runDreamingPass(options = {}) {
|
|
57
|
+
const perceptions = getSensoryMemory().drain();
|
|
58
|
+
if (perceptions.length === 0)
|
|
59
|
+
return null;
|
|
60
|
+
const summary = consolidate(perceptions, options.now ?? Date.now());
|
|
61
|
+
try {
|
|
62
|
+
const dir = path.join(options.cwd ?? process.cwd(), '.codebuddy', 'companion');
|
|
63
|
+
await mkdir(dir, { recursive: true });
|
|
64
|
+
const file = path.join(dir, 'dreams.jsonl');
|
|
65
|
+
// Rotate when large (the disk-guard lesson): keep one .1 backup, never grow unbounded.
|
|
66
|
+
try {
|
|
67
|
+
const info = await stat(file);
|
|
68
|
+
if (info.size > 512 * 1024)
|
|
69
|
+
await rename(file, `${file}.1`);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* no file yet */
|
|
73
|
+
}
|
|
74
|
+
await appendFile(file, `${JSON.stringify(summary)}\n`, 'utf8');
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
logger.warn(`[dreaming] could not persist dream: ${err instanceof Error ? err.message : String(err)}`);
|
|
78
|
+
}
|
|
79
|
+
// Deep consolidation — salient dreams become long-term memory the agent reads.
|
|
80
|
+
if (summary.salient.length > 0) {
|
|
81
|
+
await (options.promote ?? promoteSalientDream)(summary);
|
|
82
|
+
}
|
|
83
|
+
logger.info(`[dreaming] consolidated ${summary.total} perception(s) → ${Object.keys(summary.byKind).length} kind(s), ${summary.salient.length} salient, avg load ${summary.avgLoad ?? '?'}`);
|
|
84
|
+
return summary;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Promote a salient dream into Code Buddy's persistent memory under a STABLE key
|
|
88
|
+
* (`dream:recent`) so repeated promotions UPDATE rather than accumulate (stays
|
|
89
|
+
* within the memory char budget). Never throws.
|
|
90
|
+
*/
|
|
91
|
+
export async function promoteSalientDream(summary) {
|
|
92
|
+
try {
|
|
93
|
+
const { getMemoryManager } = await import('../memory/persistent-memory.js');
|
|
94
|
+
const manager = getMemoryManager();
|
|
95
|
+
await manager.initialize();
|
|
96
|
+
// Cap the kinds string (a daemon could emit many distinct kinds → an
|
|
97
|
+
// oversized write that the memory char-limit would reject).
|
|
98
|
+
const kindEntries = Object.entries(summary.byKind).sort((a, b) => b[1] - a[1]);
|
|
99
|
+
const kinds = kindEntries
|
|
100
|
+
.slice(0, 12)
|
|
101
|
+
.map(([k, n]) => `${k}×${n}`)
|
|
102
|
+
.join(', ') + (kindEntries.length > 12 ? `, +${kindEntries.length - 12} more` : '');
|
|
103
|
+
const top = summary.salient
|
|
104
|
+
.slice(0, 5)
|
|
105
|
+
.map((s) => `${s.modality}/${s.kind}`)
|
|
106
|
+
.join(', ');
|
|
107
|
+
const value = `Recent salient perception: ${summary.total} events (${kinds}); salient: ${top}; avg load ${summary.avgLoad ?? '?'}.`;
|
|
108
|
+
await manager.remember('dream:recent', value, { scope: 'project', category: 'context', tags: ['dream', 'sensory'] });
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logger.warn(`[dreaming] could not promote dream to memory: ${err instanceof Error ? err.message : String(err)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=dreaming.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heartbeat scheduler — turns the nervous-system heartbeat into a PACEMAKER for
|
|
3
|
+
* periodic processing in Code Buddy. Register "treatments" that fire every N
|
|
4
|
+
* beats; the daemon's heart rate (BUDDY_SENSE_HEARTBEAT_MS) dials how often they
|
|
5
|
+
* run — a faster heart triggers more processing, a slower one less.
|
|
6
|
+
*
|
|
7
|
+
* This is the heartbeat-paced analogue of Hermes's curator/cron and OpenClaw's
|
|
8
|
+
* cron-jobs + dreaming: scheduled background work, but driven by the heart rather
|
|
9
|
+
* than a wall clock. Each beat carries vital signs (uptime, load) the treatments
|
|
10
|
+
* can read — so a treatment can also adapt to the body's state.
|
|
11
|
+
*
|
|
12
|
+
* @module sensory/heartbeat-scheduler
|
|
13
|
+
*/
|
|
14
|
+
export interface HeartbeatContext {
|
|
15
|
+
beat: number;
|
|
16
|
+
uptimeMs?: number;
|
|
17
|
+
load1?: number | null;
|
|
18
|
+
}
|
|
19
|
+
export type HeartbeatHandler = (ctx: HeartbeatContext) => void | Promise<void>;
|
|
20
|
+
export interface HeartbeatTask {
|
|
21
|
+
name: string;
|
|
22
|
+
/** Fire when `beat % everyBeats === 0` (1 = every beat). */
|
|
23
|
+
everyBeats: number;
|
|
24
|
+
handler: HeartbeatHandler;
|
|
25
|
+
}
|
|
26
|
+
export declare class HeartbeatScheduler {
|
|
27
|
+
private readonly tasks;
|
|
28
|
+
private listenerId?;
|
|
29
|
+
/** Register a treatment to run every N beats. Re-registering replaces it. */
|
|
30
|
+
register(task: HeartbeatTask): void;
|
|
31
|
+
unregister(name: string): void;
|
|
32
|
+
list(): HeartbeatTask[];
|
|
33
|
+
/** Subscribe to the sensory bus and start pacing. Idempotent. */
|
|
34
|
+
start(): void;
|
|
35
|
+
stop(): void;
|
|
36
|
+
private onBeat;
|
|
37
|
+
}
|
|
38
|
+
export declare function getHeartbeatScheduler(): HeartbeatScheduler;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heartbeat scheduler — turns the nervous-system heartbeat into a PACEMAKER for
|
|
3
|
+
* periodic processing in Code Buddy. Register "treatments" that fire every N
|
|
4
|
+
* beats; the daemon's heart rate (BUDDY_SENSE_HEARTBEAT_MS) dials how often they
|
|
5
|
+
* run — a faster heart triggers more processing, a slower one less.
|
|
6
|
+
*
|
|
7
|
+
* This is the heartbeat-paced analogue of Hermes's curator/cron and OpenClaw's
|
|
8
|
+
* cron-jobs + dreaming: scheduled background work, but driven by the heart rather
|
|
9
|
+
* than a wall clock. Each beat carries vital signs (uptime, load) the treatments
|
|
10
|
+
* can read — so a treatment can also adapt to the body's state.
|
|
11
|
+
*
|
|
12
|
+
* @module sensory/heartbeat-scheduler
|
|
13
|
+
*/
|
|
14
|
+
import { getGlobalEventBus } from '../events/event-bus.js';
|
|
15
|
+
import { logger } from '../utils/logger.js';
|
|
16
|
+
export class HeartbeatScheduler {
|
|
17
|
+
tasks = new Map();
|
|
18
|
+
listenerId;
|
|
19
|
+
/** Register a treatment to run every N beats. Re-registering replaces it. */
|
|
20
|
+
register(task) {
|
|
21
|
+
if (!Number.isInteger(task.everyBeats) || task.everyBeats < 1) {
|
|
22
|
+
throw new Error(`heartbeat task "${task.name}": everyBeats must be an integer >= 1`);
|
|
23
|
+
}
|
|
24
|
+
this.tasks.set(task.name, task);
|
|
25
|
+
}
|
|
26
|
+
unregister(name) {
|
|
27
|
+
this.tasks.delete(name);
|
|
28
|
+
}
|
|
29
|
+
list() {
|
|
30
|
+
return [...this.tasks.values()];
|
|
31
|
+
}
|
|
32
|
+
/** Subscribe to the sensory bus and start pacing. Idempotent. */
|
|
33
|
+
start() {
|
|
34
|
+
if (this.listenerId)
|
|
35
|
+
return;
|
|
36
|
+
const bus = getGlobalEventBus();
|
|
37
|
+
this.listenerId = bus.on('sensory:perception', (evt) => {
|
|
38
|
+
const m = evt.metadata;
|
|
39
|
+
if (m?.modality !== 'vital' || m?.kind !== 'heartbeat')
|
|
40
|
+
return;
|
|
41
|
+
const beat = Number(m.payload?.beat ?? 0);
|
|
42
|
+
if (!Number.isFinite(beat) || beat < 1)
|
|
43
|
+
return;
|
|
44
|
+
void this.onBeat({ beat, uptimeMs: m.payload?.uptime_ms, load1: m.payload?.load1 });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
stop() {
|
|
48
|
+
if (this.listenerId) {
|
|
49
|
+
getGlobalEventBus().off(this.listenerId);
|
|
50
|
+
this.listenerId = undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async onBeat(ctx) {
|
|
54
|
+
for (const task of this.tasks.values()) {
|
|
55
|
+
if (ctx.beat % task.everyBeats !== 0)
|
|
56
|
+
continue;
|
|
57
|
+
try {
|
|
58
|
+
await task.handler(ctx);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
logger.warn(`[heartbeat] treatment "${task.name}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let singleton;
|
|
67
|
+
export function getHeartbeatScheduler() {
|
|
68
|
+
if (!singleton)
|
|
69
|
+
singleton = new HeartbeatScheduler();
|
|
70
|
+
return singleton;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=heartbeat-scheduler.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensory reactions — subscribers that turn `sensory:perception` events from the
|
|
3
|
+
* nervous-system daemon into Code Buddy behaviour. Phase 1 logs + exposes a hook;
|
|
4
|
+
* Phase 2 will route (speech_end → STT → turn; motion → camera_analyze).
|
|
5
|
+
*
|
|
6
|
+
* @module sensory/reactions
|
|
7
|
+
*/
|
|
8
|
+
import type { BaseEvent } from '../events/types.js';
|
|
9
|
+
export interface Perception {
|
|
10
|
+
modality?: string;
|
|
11
|
+
kind?: string;
|
|
12
|
+
salience?: number;
|
|
13
|
+
/** Sense-relative timestamp (frame-relative for audio, unix-millis for vital). */
|
|
14
|
+
tsMs?: number;
|
|
15
|
+
/** Ingest wall-clock (one consistent clock across senses — used for dream windows). */
|
|
16
|
+
receivedAt?: number;
|
|
17
|
+
payload?: unknown;
|
|
18
|
+
}
|
|
19
|
+
export declare function perceptionOf(evt: BaseEvent): Perception;
|
|
20
|
+
/**
|
|
21
|
+
* Wire reactions to the sensory bus. Returns an unsubscribe fn. `onPerception`
|
|
22
|
+
* is an injectable hook (tests + future routing).
|
|
23
|
+
*/
|
|
24
|
+
export declare function wireSensoryReactions(onPerception?: (p: Perception, evt: BaseEvent) => void): () => void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensory reactions — subscribers that turn `sensory:perception` events from the
|
|
3
|
+
* nervous-system daemon into Code Buddy behaviour. Phase 1 logs + exposes a hook;
|
|
4
|
+
* Phase 2 will route (speech_end → STT → turn; motion → camera_analyze).
|
|
5
|
+
*
|
|
6
|
+
* @module sensory/reactions
|
|
7
|
+
*/
|
|
8
|
+
import { getGlobalEventBus } from '../events/event-bus.js';
|
|
9
|
+
import { logger } from '../utils/logger.js';
|
|
10
|
+
import { getSensoryMemory } from './sensory-memory.js';
|
|
11
|
+
export function perceptionOf(evt) {
|
|
12
|
+
const meta = evt.metadata ?? {};
|
|
13
|
+
return { ...meta, receivedAt: evt.timestamp };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wire reactions to the sensory bus. Returns an unsubscribe fn. `onPerception`
|
|
17
|
+
* is an injectable hook (tests + future routing).
|
|
18
|
+
*/
|
|
19
|
+
export function wireSensoryReactions(onPerception) {
|
|
20
|
+
const bus = getGlobalEventBus();
|
|
21
|
+
const id = bus.on('sensory:perception', (evt) => {
|
|
22
|
+
const p = perceptionOf(evt);
|
|
23
|
+
logger.info(`[sensory] ${p.modality}/${p.kind} (salience ${p.salience ?? 0})`);
|
|
24
|
+
getSensoryMemory().push(p); // short-term memory → consolidated by dreaming
|
|
25
|
+
onPerception?.(p, evt);
|
|
26
|
+
});
|
|
27
|
+
return () => {
|
|
28
|
+
bus.off(id);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=reactions.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen reaction — on a `screen/change` event from the nervous-system daemon,
|
|
3
|
+
* record a companion percept and (optionally) run an injected analyzer (OCR /
|
|
4
|
+
* vision describe). DEBOUNCED, opt-in (`CODEBUDDY_SENSORY_SCREEN=true`),
|
|
5
|
+
* never-throws. The heavy OCR/describe is pluggable so we don't duplicate Code
|
|
6
|
+
* Buddy's existing OCR/vision; inject an analyzer to wire it.
|
|
7
|
+
*
|
|
8
|
+
* @module sensory/screen-reaction
|
|
9
|
+
*/
|
|
10
|
+
export interface ScreenAnalysis {
|
|
11
|
+
description?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ScreenAnalyzer {
|
|
14
|
+
analyze(): Promise<ScreenAnalysis>;
|
|
15
|
+
}
|
|
16
|
+
export interface ScreenReactionOptions {
|
|
17
|
+
/** Injectable OCR/vision describe (default: none — just record the change). */
|
|
18
|
+
analyzer?: ScreenAnalyzer;
|
|
19
|
+
debounceMs?: number;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
now?: () => number;
|
|
22
|
+
}
|
|
23
|
+
export declare function wireScreenReaction(options?: ScreenReactionOptions): () => void;
|