@ouro.bot/cli 0.1.0-alpha.48 → 0.1.0-alpha.480
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 +132 -19
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3061 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +857 -0
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +426 -0
- package/dist/heart/background-operations.js +234 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +110 -128
- package/dist/heart/core.js +745 -227
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +490 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +216 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +640 -0
- package/dist/heart/daemon/cli-exec.js +6933 -0
- package/dist/heart/daemon/cli-help.js +487 -0
- package/dist/heart/daemon/cli-parse.js +1527 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +561 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1616
- package/dist/heart/daemon/daemon-entry.js +345 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +677 -58
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +486 -0
- package/dist/heart/daemon/health-monitor.js +92 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +25 -5
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +214 -0
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +73 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +178 -37
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +109 -4
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +264 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +149 -10
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +201 -66
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +66 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +244 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +31 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +195 -0
- package/dist/heart/outlook/readers/agent-machine.js +359 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/mail.js +362 -0
- package/dist/heart/outlook/readers/runtime-readers.js +644 -0
- package/dist/heart/outlook/readers/sessions.js +232 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +424 -0
- package/dist/heart/provider-failover.js +266 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +193 -55
- package/dist/heart/providers/azure.js +103 -12
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +29 -7
- package/dist/heart/providers/openai-codex.js +62 -38
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +260 -0
- package/dist/heart/sense-truth.js +11 -4
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +855 -0
- package/dist/heart/session-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +361 -0
- package/dist/heart/turn-coordinator.js +24 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +425 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +558 -0
- package/dist/mailroom/core.js +658 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +400 -0
- package/dist/mailroom/mbox-import.js +341 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +197 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +132 -93
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +74 -93
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +30 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +38 -1
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +66 -7
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +978 -169
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +84 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/outlook-ui/assets/index-CPfhbn13.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +774 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +37 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +44 -740
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +896 -0
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +746 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +144 -113
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +561 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +73 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +7 -3
- package/dist/senses/{bluebubbles.js → bluebubbles/index.js} +705 -116
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +516 -211
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +97 -17
- package/dist/senses/inner-dialog.js +404 -14
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +232 -0
- package/dist/senses/pipeline.js +533 -72
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +205 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +413 -163
- package/dist/senses/trust-gate.js +5 -5
- package/package.json +37 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/debug-activity.js +0 -127
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -33,12 +33,25 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listAllBundleAgents = listAllBundleAgents;
|
|
36
37
|
exports.listEnabledBundleAgents = listEnabledBundleAgents;
|
|
38
|
+
exports.listBundleSyncRows = listBundleSyncRows;
|
|
37
39
|
const fs = __importStar(require("fs"));
|
|
38
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
39
42
|
const identity_1 = require("../identity");
|
|
40
43
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Walk the bundles root and return one row per `<name>.ouro` directory whose
|
|
46
|
+
* `agent.json` is readable and parseable. Includes both enabled and disabled
|
|
47
|
+
* agents — the caller decides what to do with the `enabled` flag.
|
|
48
|
+
*
|
|
49
|
+
* Bundles whose `agent.json` is missing, malformed, or unreadable are skipped
|
|
50
|
+
* silently (they aren't real agents from the harness's perspective).
|
|
51
|
+
*
|
|
52
|
+
* Sorted alphabetically by name for stable display.
|
|
53
|
+
*/
|
|
54
|
+
function listAllBundleAgents(options = {}) {
|
|
42
55
|
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
43
56
|
const readdirSync = options.readdirSync ?? fs.readdirSync;
|
|
44
57
|
const readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
@@ -73,9 +86,72 @@ function listEnabledBundleAgents(options = {}) {
|
|
|
73
86
|
catch {
|
|
74
87
|
continue;
|
|
75
88
|
}
|
|
89
|
+
discovered.push({ name: agentName, enabled });
|
|
90
|
+
}
|
|
91
|
+
return discovered.sort((left, right) => left.name.localeCompare(right.name));
|
|
92
|
+
}
|
|
93
|
+
function listEnabledBundleAgents(options = {}) {
|
|
94
|
+
return listAllBundleAgents(options).filter((row) => row.enabled).map((row) => row.name);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Read the per-agent sync block from each enabled bundle's agent.json.
|
|
98
|
+
* Used by the daemon (and stopped-state status renderer) to build per-agent
|
|
99
|
+
* sync rows without depending on argv-derived global identity. Bundles that
|
|
100
|
+
* cannot be read are skipped silently.
|
|
101
|
+
*
|
|
102
|
+
* For rows with sync enabled, also checks whether the bundle is a git repo
|
|
103
|
+
* (via .git directory presence) and resolves the remote URL via
|
|
104
|
+
* `git remote get-url <remote>`. On any error the URL is left undefined and
|
|
105
|
+
* the status renderer falls back to "local only" or "not a git repo".
|
|
106
|
+
*/
|
|
107
|
+
function listBundleSyncRows(options = {}) {
|
|
108
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
109
|
+
const readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
110
|
+
const execFileSync = options.execFileSync ?? child_process_1.execFileSync;
|
|
111
|
+
const existsSync = options.existsSync ?? fs.existsSync;
|
|
112
|
+
const agents = listEnabledBundleAgents(options);
|
|
113
|
+
const rows = [];
|
|
114
|
+
for (const agent of agents) {
|
|
115
|
+
const bundleRoot = path.join(bundlesRoot, `${agent}.ouro`);
|
|
116
|
+
const configPath = path.join(bundleRoot, "agent.json");
|
|
117
|
+
let enabled = false;
|
|
118
|
+
let remote = "origin";
|
|
119
|
+
try {
|
|
120
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
121
|
+
const parsed = JSON.parse(raw);
|
|
122
|
+
if (parsed.sync && typeof parsed.sync === "object") {
|
|
123
|
+
if (typeof parsed.sync.enabled === "boolean")
|
|
124
|
+
enabled = parsed.sync.enabled;
|
|
125
|
+
if (typeof parsed.sync.remote === "string" && parsed.sync.remote.length > 0) {
|
|
126
|
+
remote = parsed.sync.remote;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Best-effort: bundle without readable config still gets a row with defaults
|
|
132
|
+
}
|
|
133
|
+
const row = { agent, enabled, remote };
|
|
76
134
|
if (enabled) {
|
|
77
|
-
|
|
135
|
+
// Only meaningful when sync is enabled — we don't care about disabled bundles'
|
|
136
|
+
// git state. Check .git presence before attempting any git invocation.
|
|
137
|
+
const gitInitialized = existsSync(path.join(bundleRoot, ".git"));
|
|
138
|
+
row.gitInitialized = gitInitialized;
|
|
139
|
+
if (gitInitialized) {
|
|
140
|
+
try {
|
|
141
|
+
const out = execFileSync("git", ["remote", "get-url", remote], {
|
|
142
|
+
cwd: bundleRoot,
|
|
143
|
+
stdio: "pipe",
|
|
144
|
+
timeout: 5000,
|
|
145
|
+
}).toString().trim();
|
|
146
|
+
if (out.length > 0)
|
|
147
|
+
row.remoteUrl = out;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// No remote configured or git missing — leave remoteUrl undefined.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
78
153
|
}
|
|
154
|
+
rows.push(row);
|
|
79
155
|
}
|
|
80
|
-
return
|
|
156
|
+
return rows;
|
|
81
157
|
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent service layer — handles MCP-facing daemon commands.
|
|
4
|
+
* Each handler receives { agent, friendId, ...params } and returns DaemonResponse.
|
|
5
|
+
*
|
|
6
|
+
* DRY: uses the same shared functions the agent's own tools use (diary, session transcript).
|
|
7
|
+
* This file is a thin adapter — no reimplemented search, parsing, or state reading.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.handleAgentStatus = handleAgentStatus;
|
|
44
|
+
exports.handleAgentAsk = handleAgentAsk;
|
|
45
|
+
exports.handleAgentCatchup = handleAgentCatchup;
|
|
46
|
+
exports.handleAgentDelegate = handleAgentDelegate;
|
|
47
|
+
exports.handleAgentGetContext = handleAgentGetContext;
|
|
48
|
+
exports.handleAgentSearchNotes = handleAgentSearchNotes;
|
|
49
|
+
exports.handleAgentGetTask = handleAgentGetTask;
|
|
50
|
+
exports.handleAgentCheckScope = handleAgentCheckScope;
|
|
51
|
+
exports.handleAgentRequestDecision = handleAgentRequestDecision;
|
|
52
|
+
exports.handleAgentCheckGuidance = handleAgentCheckGuidance;
|
|
53
|
+
exports.handleAgentReportProgress = handleAgentReportProgress;
|
|
54
|
+
exports.handleAgentReportBlocker = handleAgentReportBlocker;
|
|
55
|
+
exports.handleAgentReportComplete = handleAgentReportComplete;
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const identity_1 = require("../identity");
|
|
59
|
+
const diary_1 = require("../../mind/diary");
|
|
60
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
61
|
+
/** Format diary hits the same way the search_notes tool does. */
|
|
62
|
+
function formatDiaryHits(hits) {
|
|
63
|
+
return hits.map((f) => `[diary] ${f.text} (source=${f.source}, createdAt=${f.createdAt})`);
|
|
64
|
+
}
|
|
65
|
+
/** Read a file from the agent root, returning null if it doesn't exist. */
|
|
66
|
+
function readAgentFile(agent, ...segments) {
|
|
67
|
+
const filePath = path.join((0, identity_1.getAgentRoot)(agent), ...segments);
|
|
68
|
+
if (!fs.existsSync(filePath))
|
|
69
|
+
return null;
|
|
70
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
71
|
+
}
|
|
72
|
+
/** Resolve the diary root for a specific agent. */
|
|
73
|
+
function agentDiaryRoot(agent) {
|
|
74
|
+
return (0, diary_1.resolveDiaryRoot)(path.join((0, identity_1.getAgentRoot)(agent), "diary"));
|
|
75
|
+
}
|
|
76
|
+
/** Read inner dialog runtime status. */
|
|
77
|
+
function readInnerDialogStatus(agent) {
|
|
78
|
+
const content = readAgentFile(agent, "state", "sessions", "self", "inner", "runtime.json");
|
|
79
|
+
if (!content)
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
const data = JSON.parse(content);
|
|
83
|
+
return { status: data.status ?? "unknown", lastCompletedAt: data.lastCompletedAt ?? "" };
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function safeReaddir(dirPath) {
|
|
90
|
+
try {
|
|
91
|
+
return fs.readdirSync(dirPath).map(String);
|
|
92
|
+
/* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
/* v8 ignore stop */
|
|
98
|
+
}
|
|
99
|
+
function safeIsDir(dirPath) {
|
|
100
|
+
try {
|
|
101
|
+
return fs.statSync(dirPath).isDirectory();
|
|
102
|
+
/* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/* v8 ignore stop */
|
|
108
|
+
}
|
|
109
|
+
/** Enumerate sessions from state/sessions/, reading session.json files. */
|
|
110
|
+
function enumerateSessions(agent) {
|
|
111
|
+
const sessionsDir = path.join((0, identity_1.getAgentRoot)(agent), "state", "sessions");
|
|
112
|
+
if (!fs.existsSync(sessionsDir))
|
|
113
|
+
return [];
|
|
114
|
+
const sessions = [];
|
|
115
|
+
for (const friendId of safeReaddir(sessionsDir)) {
|
|
116
|
+
const friendPath = path.join(sessionsDir, friendId);
|
|
117
|
+
if (!safeIsDir(friendPath))
|
|
118
|
+
continue;
|
|
119
|
+
for (const channel of safeReaddir(friendPath)) {
|
|
120
|
+
const channelPath = path.join(friendPath, channel);
|
|
121
|
+
if (!safeIsDir(channelPath))
|
|
122
|
+
continue;
|
|
123
|
+
for (const key of safeReaddir(channelPath)) {
|
|
124
|
+
const sessionFile = path.join(channelPath, key, "session.json");
|
|
125
|
+
if (!fs.existsSync(sessionFile))
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
const data = JSON.parse(fs.readFileSync(sessionFile, "utf-8"));
|
|
129
|
+
sessions.push({ friendId, channel, key, lastUsage: data.lastUsage ?? "" });
|
|
130
|
+
}
|
|
131
|
+
catch { /* skip malformed */ }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return sessions;
|
|
136
|
+
}
|
|
137
|
+
/** List markdown files in {agentRoot}/tasks/. */
|
|
138
|
+
function listTaskFiles(agent) {
|
|
139
|
+
const tasksDir = path.join((0, identity_1.getAgentRoot)(agent), "tasks");
|
|
140
|
+
if (!fs.existsSync(tasksDir))
|
|
141
|
+
return [];
|
|
142
|
+
try {
|
|
143
|
+
return fs.readdirSync(tasksDir).map(String).filter((f) => f.endsWith(".md"));
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function emit(event, message, meta) {
|
|
150
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event, message, meta });
|
|
151
|
+
}
|
|
152
|
+
// ─── Handlers ────────────────────────────────────────────────────────────────
|
|
153
|
+
async function handleAgentStatus(params) {
|
|
154
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.agent_service_start", message: "handling agent.status", meta: { agent: params.agent } });
|
|
155
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
156
|
+
const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
|
|
157
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
158
|
+
const sessions = enumerateSessions(params.agent);
|
|
159
|
+
emit("daemon.agent_service_end", "completed agent.status", { agent: params.agent });
|
|
160
|
+
return {
|
|
161
|
+
ok: true,
|
|
162
|
+
message: `Agent ${params.agent} status`,
|
|
163
|
+
data: {
|
|
164
|
+
agent: params.agent,
|
|
165
|
+
innerStatus: innerStatus?.status ?? "unknown",
|
|
166
|
+
lastThoughtAt: innerStatus?.lastCompletedAt ?? null,
|
|
167
|
+
sessionCount: sessions.length,
|
|
168
|
+
hasDiaryEntries: facts.length > 0,
|
|
169
|
+
factCount: facts.length,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function handleAgentAsk(params) {
|
|
174
|
+
emit("daemon.agent_service_start", "handling agent.ask", { agent: params.agent });
|
|
175
|
+
const question = params.question;
|
|
176
|
+
if (!question) {
|
|
177
|
+
emit("daemon.agent_service_error", "agent.ask missing question", { agent: params.agent });
|
|
178
|
+
return { ok: false, error: "Missing required parameter: question" };
|
|
179
|
+
}
|
|
180
|
+
// Use the same searchDiaryEntries the search_notes tool uses (substring fallback — no embedding provider in shim)
|
|
181
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
182
|
+
const hits = await (0, diary_1.searchDiaryEntries)(question, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
183
|
+
const context = hits.length > 0
|
|
184
|
+
? hits.slice(0, 10).map((f) => f.text).join("\n")
|
|
185
|
+
: `No relevant notes found for: ${question}`;
|
|
186
|
+
emit("daemon.agent_service_end", "completed agent.ask", { agent: params.agent });
|
|
187
|
+
return { ok: true, message: context };
|
|
188
|
+
}
|
|
189
|
+
async function handleAgentCatchup(params) {
|
|
190
|
+
emit("daemon.agent_service_start", "handling agent.catchup", { agent: params.agent });
|
|
191
|
+
const sessions = enumerateSessions(params.agent);
|
|
192
|
+
const sorted = sessions.sort((a, b) => (b.lastUsage || "").localeCompare(a.lastUsage || ""));
|
|
193
|
+
const recentSessions = sorted.slice(0, 5);
|
|
194
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
195
|
+
const parts = [];
|
|
196
|
+
if (innerStatus) {
|
|
197
|
+
parts.push(`Inner dialog: ${innerStatus.status} (last completed: ${innerStatus.lastCompletedAt || "never"})`);
|
|
198
|
+
}
|
|
199
|
+
if (recentSessions.length > 0) {
|
|
200
|
+
parts.push(`Recent sessions (${recentSessions.length}):`);
|
|
201
|
+
for (const s of recentSessions) {
|
|
202
|
+
parts.push(` - ${s.friendId}/${s.channel}/${s.key} (${s.lastUsage || "unknown"})`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
parts.push("No recent sessions");
|
|
207
|
+
}
|
|
208
|
+
emit("daemon.agent_service_end", "completed agent.catchup", { agent: params.agent });
|
|
209
|
+
return {
|
|
210
|
+
ok: true,
|
|
211
|
+
/* v8 ignore next — parts always has at least one element (either sessions or "No recent sessions") */
|
|
212
|
+
message: parts.length > 0 ? parts.join("\n") : `No recent activity for ${params.agent}`,
|
|
213
|
+
data: { recentSessions, innerStatus },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async function handleAgentDelegate(params) {
|
|
217
|
+
emit("daemon.agent_service_start", "handling agent.delegate", { agent: params.agent });
|
|
218
|
+
const task = params.task;
|
|
219
|
+
if (!task) {
|
|
220
|
+
emit("daemon.agent_service_error", "agent.delegate missing task", { agent: params.agent });
|
|
221
|
+
return { ok: false, error: "Missing required parameter: task" };
|
|
222
|
+
}
|
|
223
|
+
emit("daemon.agent_service_end", "completed agent.delegate", { agent: params.agent });
|
|
224
|
+
return { ok: true, message: `Task queued: ${task}`, data: { task, context: params.context ?? null, queuedAt: new Date().toISOString() } };
|
|
225
|
+
}
|
|
226
|
+
async function handleAgentGetContext(params) {
|
|
227
|
+
emit("daemon.agent_service_start", "handling agent.getContext", { agent: params.agent });
|
|
228
|
+
const query = (params.question ?? params.query ?? params.topic);
|
|
229
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
230
|
+
const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
|
|
231
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
232
|
+
const sessions = enumerateSessions(params.agent);
|
|
233
|
+
const taskFiles = listTaskFiles(params.agent);
|
|
234
|
+
let noteSummary = null;
|
|
235
|
+
if (query) {
|
|
236
|
+
const hits = await (0, diary_1.searchDiaryEntries)(query, facts);
|
|
237
|
+
noteSummary = hits.length > 0
|
|
238
|
+
? hits.slice(0, 10).map((f) => f.text).join("\n")
|
|
239
|
+
: `No relevant notes for: ${query}`;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const recent = facts.slice(-10);
|
|
243
|
+
if (recent.length > 0)
|
|
244
|
+
noteSummary = recent.map((f) => f.text).join("\n");
|
|
245
|
+
}
|
|
246
|
+
emit("daemon.agent_service_end", "completed agent.getContext", { agent: params.agent });
|
|
247
|
+
return {
|
|
248
|
+
ok: true,
|
|
249
|
+
data: {
|
|
250
|
+
agent: params.agent,
|
|
251
|
+
hasDiaryEntries: facts.length > 0,
|
|
252
|
+
factCount: facts.length,
|
|
253
|
+
noteSummary,
|
|
254
|
+
taskCount: taskFiles.length,
|
|
255
|
+
sessionCount: sessions.length,
|
|
256
|
+
innerStatus: innerStatus?.status ?? null,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
async function handleAgentSearchNotes(params) {
|
|
261
|
+
emit("daemon.agent_service_start", "handling agent.searchNotes", { agent: params.agent });
|
|
262
|
+
const query = params.query;
|
|
263
|
+
if (!query) {
|
|
264
|
+
emit("daemon.agent_service_error", "agent.searchNotes missing query", { agent: params.agent });
|
|
265
|
+
return { ok: false, error: "Missing required parameter: query" };
|
|
266
|
+
}
|
|
267
|
+
// Same searchDiaryEntries as the search_notes tool
|
|
268
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
269
|
+
const hits = await (0, diary_1.searchDiaryEntries)(query, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
270
|
+
const formatted = formatDiaryHits(hits.slice(0, 20));
|
|
271
|
+
emit("daemon.agent_service_end", "completed agent.searchNotes", { agent: params.agent, matchCount: hits.length });
|
|
272
|
+
return {
|
|
273
|
+
ok: true,
|
|
274
|
+
message: hits.length > 0 ? `Found ${hits.length} matches` : "No matches found",
|
|
275
|
+
data: { query, matches: formatted },
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async function handleAgentGetTask(params) {
|
|
279
|
+
emit("daemon.agent_service_start", "handling agent.getTask", { agent: params.agent });
|
|
280
|
+
const taskFiles = listTaskFiles(params.agent);
|
|
281
|
+
const activeTasks = taskFiles.filter((f) => f.toLowerCase().includes("doing") && !f.toLowerCase().includes("done"));
|
|
282
|
+
const taskNames = activeTasks.length > 0 ? activeTasks : taskFiles;
|
|
283
|
+
const tasks = taskNames.map((name) => {
|
|
284
|
+
const content = readAgentFile(params.agent, "tasks", name);
|
|
285
|
+
const firstLine = content?.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
|
|
286
|
+
return { name, statusLine: firstLine };
|
|
287
|
+
});
|
|
288
|
+
emit("daemon.agent_service_end", "completed agent.getTask", { agent: params.agent });
|
|
289
|
+
return {
|
|
290
|
+
ok: true,
|
|
291
|
+
message: tasks.length > 0 ? `Tasks (${tasks.length}): ${tasks.map((t) => t.name).join(", ")}` : `No active tasks for ${params.agent}`,
|
|
292
|
+
data: { tasks, activeCount: activeTasks.length, totalCount: taskFiles.length },
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
async function handleAgentCheckScope(params) {
|
|
296
|
+
emit("daemon.agent_service_start", "handling agent.checkScope", { agent: params.agent });
|
|
297
|
+
const item = params.item;
|
|
298
|
+
if (!item) {
|
|
299
|
+
emit("daemon.agent_service_error", "agent.checkScope missing item", { agent: params.agent });
|
|
300
|
+
return { ok: false, error: "Missing required parameter: item" };
|
|
301
|
+
}
|
|
302
|
+
emit("daemon.agent_service_end", "completed agent.checkScope", { agent: params.agent });
|
|
303
|
+
return { ok: true, message: `Scope check for: ${item}`, data: { item, inScope: true, reason: "MVP: scope check requires inference — defaulting to in-scope" } };
|
|
304
|
+
}
|
|
305
|
+
async function handleAgentRequestDecision(params) {
|
|
306
|
+
emit("daemon.agent_service_start", "handling agent.requestDecision", { agent: params.agent });
|
|
307
|
+
const topic = params.topic;
|
|
308
|
+
if (!topic) {
|
|
309
|
+
emit("daemon.agent_service_error", "agent.requestDecision missing topic", { agent: params.agent });
|
|
310
|
+
return { ok: false, error: "Missing required parameter: topic" };
|
|
311
|
+
}
|
|
312
|
+
emit("daemon.agent_service_end", "completed agent.requestDecision", { agent: params.agent });
|
|
313
|
+
return { ok: true, message: `Decision request queued: ${topic}`, data: { topic, options: params.options ?? null, status: "pending" } };
|
|
314
|
+
}
|
|
315
|
+
async function handleAgentCheckGuidance(params) {
|
|
316
|
+
emit("daemon.agent_service_start", "handling agent.checkGuidance", { agent: params.agent });
|
|
317
|
+
const topic = params.topic;
|
|
318
|
+
if (!topic) {
|
|
319
|
+
emit("daemon.agent_service_error", "agent.checkGuidance missing topic", { agent: params.agent });
|
|
320
|
+
return { ok: false, error: "Missing required parameter: topic" };
|
|
321
|
+
}
|
|
322
|
+
// Same searchDiaryEntries as the search_notes tool
|
|
323
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
324
|
+
const hits = await (0, diary_1.searchDiaryEntries)(topic, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
325
|
+
const guidance = hits.length > 0
|
|
326
|
+
? `Relevant guidance:\n${hits.slice(0, 10).map((f) => f.text).join("\n")}`
|
|
327
|
+
: `No specific guidance found for: ${topic}`;
|
|
328
|
+
emit("daemon.agent_service_end", "completed agent.checkGuidance", { agent: params.agent });
|
|
329
|
+
return { ok: true, message: guidance };
|
|
330
|
+
}
|
|
331
|
+
async function handleAgentReportProgress(params) {
|
|
332
|
+
emit("daemon.agent_service_start", "handling agent.reportProgress", { agent: params.agent });
|
|
333
|
+
const summary = params.summary;
|
|
334
|
+
if (!summary) {
|
|
335
|
+
emit("daemon.agent_service_error", "agent.reportProgress missing summary", { agent: params.agent });
|
|
336
|
+
return { ok: false, error: "Missing required parameter: summary" };
|
|
337
|
+
}
|
|
338
|
+
emit("daemon.agent_service_end", "completed agent.reportProgress", { agent: params.agent });
|
|
339
|
+
return { ok: true, message: `Progress noted: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
|
|
340
|
+
}
|
|
341
|
+
async function handleAgentReportBlocker(params) {
|
|
342
|
+
emit("daemon.agent_service_start", "handling agent.reportBlocker", { agent: params.agent });
|
|
343
|
+
const blocker = params.blocker;
|
|
344
|
+
if (!blocker) {
|
|
345
|
+
emit("daemon.agent_service_error", "agent.reportBlocker missing blocker", { agent: params.agent });
|
|
346
|
+
return { ok: false, error: "Missing required parameter: blocker" };
|
|
347
|
+
}
|
|
348
|
+
emit("daemon.agent_service_end", "completed agent.reportBlocker", { agent: params.agent });
|
|
349
|
+
return { ok: true, message: `Blocker reported: ${blocker}`, data: { blocker, receivedAt: new Date().toISOString() } };
|
|
350
|
+
}
|
|
351
|
+
async function handleAgentReportComplete(params) {
|
|
352
|
+
emit("daemon.agent_service_start", "handling agent.reportComplete", { agent: params.agent });
|
|
353
|
+
const summary = params.summary;
|
|
354
|
+
if (!summary) {
|
|
355
|
+
emit("daemon.agent_service_error", "agent.reportComplete missing summary", { agent: params.agent });
|
|
356
|
+
return { ok: false, error: "Missing required parameter: summary" };
|
|
357
|
+
}
|
|
358
|
+
emit("daemon.agent_service_end", "completed agent.reportComplete", { agent: params.agent });
|
|
359
|
+
return { ok: true, message: `Completion reported: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
|
|
360
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agentic repair flow for degraded agents detected during `ouro up`.
|
|
4
|
+
*
|
|
5
|
+
* Runs known local repair prompts first, then offers AI-assisted diagnosis
|
|
6
|
+
* when no local repair was attempted and a working LLM provider is available.
|
|
7
|
+
* This is a lightweight integration: one diagnostic LLM call, not a chat loop.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createAgenticDiagnosisProviderRuntime = createAgenticDiagnosisProviderRuntime;
|
|
11
|
+
exports.runAgenticRepair = runAgenticRepair;
|
|
12
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
13
|
+
const interactive_repair_1 = require("./interactive-repair");
|
|
14
|
+
const provider_ping_1 = require("../provider-ping");
|
|
15
|
+
const readiness_repair_1 = require("./readiness-repair");
|
|
16
|
+
function buildSystemPrompt(degraded) {
|
|
17
|
+
const agentList = degraded
|
|
18
|
+
.map((d) => `- ${d.agent}: error="${d.errorReason}", hint="${d.fixHint}"`)
|
|
19
|
+
.join("\n");
|
|
20
|
+
return [
|
|
21
|
+
"You are a diagnostic assistant for the Ouroboros agent daemon.",
|
|
22
|
+
"The daemon detected degraded agents during startup.",
|
|
23
|
+
"Analyze the errors below and provide a concise diagnosis with suggested fixes.",
|
|
24
|
+
"",
|
|
25
|
+
"Degraded agents:",
|
|
26
|
+
agentList,
|
|
27
|
+
"",
|
|
28
|
+
"Keep your response brief and actionable. Focus on the most likely root cause",
|
|
29
|
+
"and the simplest fix the user can apply.",
|
|
30
|
+
].join("\n");
|
|
31
|
+
}
|
|
32
|
+
function buildUserMessage(degraded, logsTail) {
|
|
33
|
+
const agentDetails = degraded
|
|
34
|
+
.map((d) => `Agent: ${d.agent}\n Error: ${d.errorReason}\n Fix hint: ${d.fixHint}`)
|
|
35
|
+
.join("\n\n");
|
|
36
|
+
return [
|
|
37
|
+
"Here are the degraded agents and recent daemon logs:",
|
|
38
|
+
"",
|
|
39
|
+
agentDetails,
|
|
40
|
+
"",
|
|
41
|
+
"Recent daemon logs:",
|
|
42
|
+
logsTail,
|
|
43
|
+
"",
|
|
44
|
+
"What is the most likely cause and how should I fix it?",
|
|
45
|
+
].join("\n");
|
|
46
|
+
}
|
|
47
|
+
function makeInteractiveRepairDeps(deps) {
|
|
48
|
+
return {
|
|
49
|
+
promptInput: deps.promptInput,
|
|
50
|
+
writeStdout: deps.writeStdout,
|
|
51
|
+
/* v8 ignore next -- fallback no-op: tests always inject runAuthFlow; default is for production @preserve */
|
|
52
|
+
runAuthFlow: deps.runAuthFlow ?? (async () => undefined),
|
|
53
|
+
runVaultUnlock: deps.runVaultUnlock,
|
|
54
|
+
skipQueueSummary: deps.skipQueueSummary,
|
|
55
|
+
isTTY: deps.isTTY,
|
|
56
|
+
stdoutColumns: deps.stdoutColumns,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function runDeterministicRepair(degraded, deps) {
|
|
60
|
+
return deps.runInteractiveRepair(degraded, makeInteractiveRepairDeps(deps));
|
|
61
|
+
}
|
|
62
|
+
function discoveredProviderModel(provider) {
|
|
63
|
+
const model = provider.providerConfig.model?.trim();
|
|
64
|
+
return model ? model : undefined;
|
|
65
|
+
}
|
|
66
|
+
function createAgenticDiagnosisProviderRuntime(provider) {
|
|
67
|
+
const config = {
|
|
68
|
+
...provider.providerConfig,
|
|
69
|
+
...provider.credentials,
|
|
70
|
+
};
|
|
71
|
+
return (0, provider_ping_1.createProviderRuntimeForConfig)(provider.provider, config, {
|
|
72
|
+
model: discoveredProviderModel(provider),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function tryAgenticDiagnosis(degraded, provider, deps) {
|
|
76
|
+
const logsTail = deps.readDaemonLogsTail();
|
|
77
|
+
const runtime = deps.createProviderRuntime(provider);
|
|
78
|
+
const systemPrompt = buildSystemPrompt(degraded);
|
|
79
|
+
const userMessage = buildUserMessage(degraded, logsTail);
|
|
80
|
+
const messages = [
|
|
81
|
+
{ role: "system", content: systemPrompt },
|
|
82
|
+
{ role: "user", content: userMessage },
|
|
83
|
+
];
|
|
84
|
+
/* v8 ignore start -- no-op callbacks: satisfy interface contract, never invoked by diagnostic call @preserve */
|
|
85
|
+
const noopCallbacks = {
|
|
86
|
+
onModelStart: () => { },
|
|
87
|
+
onModelStreamStart: () => { },
|
|
88
|
+
onTextChunk: () => { },
|
|
89
|
+
onReasoningChunk: () => { },
|
|
90
|
+
onToolStart: () => { },
|
|
91
|
+
onToolEnd: () => { },
|
|
92
|
+
onError: () => { },
|
|
93
|
+
};
|
|
94
|
+
/* v8 ignore stop */
|
|
95
|
+
const result = await runtime.streamTurn({
|
|
96
|
+
messages,
|
|
97
|
+
activeTools: [],
|
|
98
|
+
callbacks: noopCallbacks,
|
|
99
|
+
});
|
|
100
|
+
if (result.content) {
|
|
101
|
+
deps.writeStdout("");
|
|
102
|
+
deps.writeStdout("--- AI Diagnosis ---");
|
|
103
|
+
deps.writeStdout(result.content);
|
|
104
|
+
deps.writeStdout("--- End Diagnosis ---");
|
|
105
|
+
deps.writeStdout("");
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
async function runAgenticRepair(degraded, deps) {
|
|
110
|
+
(0, runtime_1.emitNervesEvent)({
|
|
111
|
+
level: "info",
|
|
112
|
+
component: "daemon",
|
|
113
|
+
event: "daemon.agentic_repair_start",
|
|
114
|
+
message: "agentic repair flow started",
|
|
115
|
+
meta: { degradedCount: degraded.length },
|
|
116
|
+
});
|
|
117
|
+
if (degraded.length === 0) {
|
|
118
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
119
|
+
}
|
|
120
|
+
const hasLocalRepair = degraded.some(interactive_repair_1.hasRunnableInteractiveRepair);
|
|
121
|
+
const hasKnownTypedRepair = degraded.some((entry) => (0, readiness_repair_1.isKnownReadinessIssue)(entry.issue));
|
|
122
|
+
if (hasLocalRepair) {
|
|
123
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
124
|
+
if (interactiveResult.repairsAttempted) {
|
|
125
|
+
return { repairsAttempted: true, usedAgentic: false };
|
|
126
|
+
}
|
|
127
|
+
if (hasKnownTypedRepair) {
|
|
128
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (hasKnownTypedRepair) {
|
|
132
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
133
|
+
}
|
|
134
|
+
// Try to discover a working provider for agentic diagnosis
|
|
135
|
+
let discoveredProvider = null;
|
|
136
|
+
try {
|
|
137
|
+
discoveredProvider = await deps.discoverWorkingProvider(degraded[0].agent);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
141
|
+
(0, runtime_1.emitNervesEvent)({
|
|
142
|
+
level: "warn",
|
|
143
|
+
component: "daemon",
|
|
144
|
+
event: "daemon.agentic_repair_discovery_error",
|
|
145
|
+
message: `provider discovery failed during agentic repair: ${msg}`,
|
|
146
|
+
meta: { error: msg },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (!discoveredProvider) {
|
|
150
|
+
// No working provider — fall back to deterministic repair
|
|
151
|
+
(0, runtime_1.emitNervesEvent)({
|
|
152
|
+
level: "info",
|
|
153
|
+
component: "daemon",
|
|
154
|
+
event: "daemon.agentic_repair_no_provider",
|
|
155
|
+
message: "no working provider found, falling back to deterministic repair",
|
|
156
|
+
meta: {},
|
|
157
|
+
});
|
|
158
|
+
if (hasLocalRepair) {
|
|
159
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
160
|
+
}
|
|
161
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
162
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic: false };
|
|
163
|
+
}
|
|
164
|
+
// Offer agentic diagnosis
|
|
165
|
+
const answer = await deps.promptInput("would you like AI-assisted diagnosis? [y/n] ");
|
|
166
|
+
if (!(0, interactive_repair_1.isAffirmativeAnswer)(answer)) {
|
|
167
|
+
// User declined — fall back to deterministic repair
|
|
168
|
+
(0, runtime_1.emitNervesEvent)({
|
|
169
|
+
level: "info",
|
|
170
|
+
component: "daemon",
|
|
171
|
+
event: "daemon.agentic_repair_declined",
|
|
172
|
+
message: "user declined agentic diagnosis",
|
|
173
|
+
meta: {},
|
|
174
|
+
});
|
|
175
|
+
if (hasLocalRepair) {
|
|
176
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
177
|
+
}
|
|
178
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
179
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic: false };
|
|
180
|
+
}
|
|
181
|
+
// User accepted — run agentic diagnosis then fall through to deterministic repair
|
|
182
|
+
let usedAgentic = false;
|
|
183
|
+
try {
|
|
184
|
+
usedAgentic = await tryAgenticDiagnosis(degraded, discoveredProvider, deps);
|
|
185
|
+
(0, runtime_1.emitNervesEvent)({
|
|
186
|
+
level: "info",
|
|
187
|
+
component: "daemon",
|
|
188
|
+
event: "daemon.agentic_repair_diagnosis_complete",
|
|
189
|
+
message: "agentic diagnosis completed, proceeding to deterministic repair",
|
|
190
|
+
meta: { provider: discoveredProvider.provider },
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
195
|
+
deps.writeStdout(`AI diagnosis failed: ${msg}`);
|
|
196
|
+
(0, runtime_1.emitNervesEvent)({
|
|
197
|
+
level: "warn",
|
|
198
|
+
component: "daemon",
|
|
199
|
+
event: "daemon.agentic_repair_diagnosis_error",
|
|
200
|
+
message: `agentic diagnosis failed: ${msg}`,
|
|
201
|
+
meta: { error: msg, provider: discoveredProvider.provider },
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// Always fall through to deterministic repair for actionable fixes
|
|
205
|
+
const interactiveResult = hasLocalRepair
|
|
206
|
+
? { repairsAttempted: false }
|
|
207
|
+
: await runDeterministicRepair(degraded, deps);
|
|
208
|
+
(0, runtime_1.emitNervesEvent)({
|
|
209
|
+
level: "info",
|
|
210
|
+
component: "daemon",
|
|
211
|
+
event: "daemon.agentic_repair_end",
|
|
212
|
+
message: "agentic repair flow completed",
|
|
213
|
+
meta: { usedAgentic, repairsAttempted: interactiveResult.repairsAttempted },
|
|
214
|
+
});
|
|
215
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic };
|
|
216
|
+
}
|