@ouro.bot/cli 0.1.0-alpha.42 → 0.1.0-alpha.420
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 +118 -15
- 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 +2627 -9
- 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 +832 -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 +424 -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 +801 -217
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +419 -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 +214 -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 +605 -0
- package/dist/heart/daemon/cli-exec.js +4140 -0
- package/dist/heart/daemon/cli-help.js +413 -0
- package/dist/heart/daemon/cli-parse.js +1151 -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/daemon-cli.js +28 -1582
- package/dist/heart/daemon/daemon-entry.js +356 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +171 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +684 -58
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +427 -0
- package/dist/heart/daemon/health-monitor.js +79 -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/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +307 -0
- package/dist/heart/daemon/launchd.js +46 -9
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -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/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +250 -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 +145 -32
- 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 +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +259 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +218 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +53 -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 +161 -65
- 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 +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -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 +28 -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/runtime-readers.js +660 -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 +133 -0
- package/dist/heart/provider-binding-resolver.js +239 -0
- package/dist/heart/provider-credentials.js +389 -0
- package/dist/heart/provider-failover.js +266 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +237 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +186 -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-credentials.js +260 -0
- package/dist/heart/sense-truth.js +3 -0
- 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 +351 -0
- package/dist/heart/turn-coordinator.js +28 -0
- 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 +301 -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 +3 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +134 -87
- 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/first-impressions.js +14 -1
- package/dist/mind/friends/channel.js +21 -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 +1 -1
- 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 +948 -168
- 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 +83 -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-BAcU08c-.css +1 -0
- package/dist/outlook-ui/assets/index-D7l3l4vY.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 +702 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -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 +371 -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 +26 -1
- 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 +42 -687
- 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 +361 -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-notes.js +376 -0
- package/dist/repertoire/tools-session.js +739 -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 +421 -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} +260 -9
- package/dist/senses/bluebubbles/entry.js +73 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1620 -0
- 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} +45 -3
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- 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 +526 -211
- package/dist/senses/commands.js +66 -3
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +596 -94
- package/dist/senses/pipeline.js +539 -61
- 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 +569 -237
- package/dist/senses/trust-gate.js +5 -5
- package/package.json +29 -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 -134
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -832
- package/dist/senses/debug-activity.js +0 -127
- package/subagents/README.md +0 -60
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /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
|
@@ -37,6 +37,115 @@ exports.bundleMetaHook = bundleMetaHook;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const runtime_1 = require("../../../nerves/runtime");
|
|
40
|
+
/**
|
|
41
|
+
* Migrate bundle from schema 1 to schema 2:
|
|
42
|
+
* - Move state/{episodes,obligations,cares,intentions}/* to arc/{name}/*
|
|
43
|
+
* - Move the old psyche note store to diary/
|
|
44
|
+
* Idempotent: skips missing sources; on collision, newer mtime wins.
|
|
45
|
+
*/
|
|
46
|
+
function migrateToSchema2(agentRoot) {
|
|
47
|
+
(0, runtime_1.emitNervesEvent)({
|
|
48
|
+
component: "daemon",
|
|
49
|
+
event: "daemon.bundle_migration_start",
|
|
50
|
+
message: "migrating bundle to schema 2",
|
|
51
|
+
meta: { agentRoot },
|
|
52
|
+
});
|
|
53
|
+
// Migrate arc entities
|
|
54
|
+
for (const name of ["episodes", "obligations", "cares", "intentions"]) {
|
|
55
|
+
const src = path.join(agentRoot, "state", name);
|
|
56
|
+
const dest = path.join(agentRoot, "arc", name);
|
|
57
|
+
migrateDirectory(src, dest);
|
|
58
|
+
}
|
|
59
|
+
// Migrate diary from the old pre-diary bundle layout.
|
|
60
|
+
const legacyDiarySrc = path.join(agentRoot, "psyche", "mem" + "ory");
|
|
61
|
+
const diaryDest = path.join(agentRoot, "diary");
|
|
62
|
+
migrateDirectory(legacyDiarySrc, diaryDest);
|
|
63
|
+
// Update bundle .gitignore
|
|
64
|
+
updateBundleGitignore(agentRoot);
|
|
65
|
+
(0, runtime_1.emitNervesEvent)({
|
|
66
|
+
component: "daemon",
|
|
67
|
+
event: "daemon.bundle_migration_end",
|
|
68
|
+
message: "bundle migration to schema 2 complete",
|
|
69
|
+
meta: { agentRoot },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ensure bundle .gitignore has state/ ignored and does NOT ignore arc/, diary/, journal/.
|
|
74
|
+
*/
|
|
75
|
+
function updateBundleGitignore(agentRoot) {
|
|
76
|
+
const gitignorePath = path.join(agentRoot, ".gitignore");
|
|
77
|
+
let lines = [];
|
|
78
|
+
try {
|
|
79
|
+
if (fs.existsSync(gitignorePath)) {
|
|
80
|
+
lines = fs.readFileSync(gitignorePath, "utf-8").split("\n");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// If we can't read, start fresh
|
|
85
|
+
}
|
|
86
|
+
// Remove arc/, diary/, journal/ from ignore (they should be tracked)
|
|
87
|
+
const toRemove = new Set(["arc/", "diary/", "journal/"]);
|
|
88
|
+
lines = lines.filter((line) => !toRemove.has(line.trim()));
|
|
89
|
+
// Ensure state/ is in the ignore list
|
|
90
|
+
const hasState = lines.some((line) => line.trim() === "state/");
|
|
91
|
+
if (!hasState) {
|
|
92
|
+
lines.push("state/");
|
|
93
|
+
}
|
|
94
|
+
// Write back, trimming trailing empty lines and ensuring trailing newline
|
|
95
|
+
const content = lines.join("\n").replace(/\n+$/, "") + "\n";
|
|
96
|
+
try {
|
|
97
|
+
fs.writeFileSync(gitignorePath, content, "utf-8");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Non-blocking: if we can't write .gitignore, migration still succeeds
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Recursively copy files from src to dest.
|
|
105
|
+
* Creates destination directories as needed. Skips if source doesn't exist.
|
|
106
|
+
* When both source and destination exist, compares mtimes: newer file wins.
|
|
107
|
+
* Logs a warning either way when a collision is detected.
|
|
108
|
+
*/
|
|
109
|
+
function migrateDirectory(src, dest) {
|
|
110
|
+
if (!fs.existsSync(src))
|
|
111
|
+
return;
|
|
112
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
113
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const srcPath = path.join(src, entry.name);
|
|
116
|
+
const destPath = path.join(dest, entry.name);
|
|
117
|
+
if (entry.isDirectory()) {
|
|
118
|
+
migrateDirectory(srcPath, destPath);
|
|
119
|
+
}
|
|
120
|
+
else if (!fs.existsSync(destPath)) {
|
|
121
|
+
fs.copyFileSync(srcPath, destPath);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Collision: both source and destination exist — compare mtimes
|
|
125
|
+
const srcMtime = fs.statSync(srcPath).mtimeMs;
|
|
126
|
+
const destMtime = fs.statSync(destPath).mtimeMs;
|
|
127
|
+
if (srcMtime > destMtime) {
|
|
128
|
+
fs.copyFileSync(srcPath, destPath);
|
|
129
|
+
(0, runtime_1.emitNervesEvent)({
|
|
130
|
+
level: "warn",
|
|
131
|
+
component: "daemon",
|
|
132
|
+
event: "daemon.bundle_migration_collision",
|
|
133
|
+
message: `migration collision: source newer, overwriting destination`,
|
|
134
|
+
meta: { srcPath, destPath, srcMtime, destMtime },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
(0, runtime_1.emitNervesEvent)({
|
|
139
|
+
level: "warn",
|
|
140
|
+
component: "daemon",
|
|
141
|
+
event: "daemon.bundle_migration_collision",
|
|
142
|
+
message: `migration collision: destination newer or equal, keeping destination`,
|
|
143
|
+
meta: { srcPath, destPath, srcMtime, destMtime },
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
40
149
|
async function bundleMetaHook(ctx) {
|
|
41
150
|
(0, runtime_1.emitNervesEvent)({
|
|
42
151
|
component: "daemon",
|
|
@@ -56,9 +165,14 @@ async function bundleMetaHook(ctx) {
|
|
|
56
165
|
// Malformed JSON -- treat as missing, will overwrite with fresh
|
|
57
166
|
existing = undefined;
|
|
58
167
|
}
|
|
168
|
+
// Run schema-2 migration if needed
|
|
169
|
+
const currentSchema = existing?.bundleSchemaVersion ?? 1;
|
|
170
|
+
if (currentSchema < 2) {
|
|
171
|
+
migrateToSchema2(ctx.agentRoot);
|
|
172
|
+
}
|
|
59
173
|
const updated = {
|
|
60
174
|
runtimeVersion: ctx.currentVersion,
|
|
61
|
-
bundleSchemaVersion:
|
|
175
|
+
bundleSchemaVersion: currentSchema < 2 ? 2 : currentSchema,
|
|
62
176
|
lastUpdated: new Date().toISOString(),
|
|
63
177
|
};
|
|
64
178
|
// Save old runtimeVersion as previousRuntimeVersion (if there was one)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createHttpHealthProbe = createHttpHealthProbe;
|
|
37
|
+
const http = __importStar(require("node:http"));
|
|
38
|
+
function createHttpHealthProbe(name, port, timeoutMs = 5000) {
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
check: () => new Promise((resolve) => {
|
|
42
|
+
const req = http.get({
|
|
43
|
+
hostname: "127.0.0.1",
|
|
44
|
+
port,
|
|
45
|
+
path: "/health",
|
|
46
|
+
timeout: timeoutMs,
|
|
47
|
+
}, (res) => {
|
|
48
|
+
let body = "";
|
|
49
|
+
res.on("data", (chunk) => {
|
|
50
|
+
body += chunk.toString();
|
|
51
|
+
});
|
|
52
|
+
res.on("end", () => {
|
|
53
|
+
if (res.statusCode !== 200) {
|
|
54
|
+
resolve({ ok: false, detail: `HTTP ${res.statusCode}` });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(body);
|
|
59
|
+
if (parsed.status === "ok") {
|
|
60
|
+
resolve({ ok: true });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
resolve({ ok: false, detail: `unexpected status: ${String(parsed.status)}` });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
resolve({ ok: false, detail: "invalid JSON response" });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
req.on("timeout", () => {
|
|
72
|
+
req.destroy();
|
|
73
|
+
resolve({ ok: false, detail: "timeout" });
|
|
74
|
+
});
|
|
75
|
+
req.on("error", (err) => {
|
|
76
|
+
resolve({ ok: false, detail: err.message });
|
|
77
|
+
});
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildInnerStatusOutput = buildInnerStatusOutput;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
function formatRelativeTime(elapsedMs) {
|
|
6
|
+
const minutes = Math.floor(elapsedMs / (60 * 1000));
|
|
7
|
+
if (minutes < 1)
|
|
8
|
+
return "just now";
|
|
9
|
+
if (minutes === 1)
|
|
10
|
+
return "1 minute ago";
|
|
11
|
+
if (minutes < 60)
|
|
12
|
+
return `${minutes} minutes ago`;
|
|
13
|
+
const hours = Math.floor(minutes / 60);
|
|
14
|
+
if (hours === 1)
|
|
15
|
+
return "1 hour ago";
|
|
16
|
+
return `${hours} hours ago`;
|
|
17
|
+
}
|
|
18
|
+
function formatCadence(cadenceMs) {
|
|
19
|
+
const minutes = Math.round(cadenceMs / (60 * 1000));
|
|
20
|
+
if (minutes >= 60) {
|
|
21
|
+
const hours = Math.round(minutes / 60);
|
|
22
|
+
return `${hours}h`;
|
|
23
|
+
}
|
|
24
|
+
return `${minutes}m`;
|
|
25
|
+
}
|
|
26
|
+
function buildInnerStatusOutput(input) {
|
|
27
|
+
const { agentName, runtimeState, journalFiles, heartbeat, attentionCount, now } = input;
|
|
28
|
+
const lines = [];
|
|
29
|
+
lines.push(`inner dialog status: ${agentName}`);
|
|
30
|
+
// Last turn
|
|
31
|
+
if (runtimeState?.lastCompletedAt) {
|
|
32
|
+
const lastMs = new Date(runtimeState.lastCompletedAt).getTime();
|
|
33
|
+
const elapsed = now - lastMs;
|
|
34
|
+
const relativeTime = formatRelativeTime(elapsed);
|
|
35
|
+
const reasonSuffix = runtimeState.reason ? ` (${runtimeState.reason})` : "";
|
|
36
|
+
lines.push(` last turn: ${relativeTime}${reasonSuffix}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
lines.push(" last turn: unknown");
|
|
40
|
+
}
|
|
41
|
+
// Status
|
|
42
|
+
if (runtimeState) {
|
|
43
|
+
const reasonSuffix = runtimeState.status === "running" && runtimeState.reason ? ` (${runtimeState.reason})` : "";
|
|
44
|
+
lines.push(` status: ${runtimeState.status}${reasonSuffix}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
lines.push(" status: unknown");
|
|
48
|
+
}
|
|
49
|
+
// Heartbeat health
|
|
50
|
+
if (heartbeat && heartbeat.lastCompletedAt !== null) {
|
|
51
|
+
const elapsed = now - heartbeat.lastCompletedAt;
|
|
52
|
+
const threshold = heartbeat.cadenceMs * 1.5;
|
|
53
|
+
const health = elapsed < threshold ? "healthy" : "overdue";
|
|
54
|
+
const cadenceStr = formatCadence(heartbeat.cadenceMs);
|
|
55
|
+
const sinceStr = formatRelativeTime(elapsed);
|
|
56
|
+
lines.push(` heartbeat: ${health} (cadence ${cadenceStr}, ${sinceStr})`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
lines.push(" heartbeat: unknown");
|
|
60
|
+
}
|
|
61
|
+
// Journal
|
|
62
|
+
if (journalFiles.length === 0) {
|
|
63
|
+
lines.push(" journal: (empty)");
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
lines.push(" journal:");
|
|
67
|
+
const sorted = [...journalFiles].sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
68
|
+
for (const file of sorted) {
|
|
69
|
+
const elapsed = now - file.mtimeMs;
|
|
70
|
+
const relativeTime = formatRelativeTime(elapsed);
|
|
71
|
+
lines.push(` - ${file.name} (${relativeTime})`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Attention
|
|
75
|
+
const thoughtWord = attentionCount === 1 ? "thought" : "thoughts";
|
|
76
|
+
lines.push(` attention: ${attentionCount} held ${thoughtWord}`);
|
|
77
|
+
(0, runtime_1.emitNervesEvent)({
|
|
78
|
+
component: "daemon",
|
|
79
|
+
event: "daemon.inner_status_read",
|
|
80
|
+
message: "inner dialog status read",
|
|
81
|
+
meta: {
|
|
82
|
+
agentName,
|
|
83
|
+
status: runtimeState?.status ?? "unknown",
|
|
84
|
+
journalCount: journalFiles.length,
|
|
85
|
+
attentionCount,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Interactive repair flow for degraded agents detected during `ouro up`.
|
|
4
|
+
*
|
|
5
|
+
* Examines each degraded agent's errorReason and fixHint to detect common
|
|
6
|
+
* issue patterns and prompt the user for repair actions.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.hasRunnableInteractiveRepair = hasRunnableInteractiveRepair;
|
|
10
|
+
exports.isAffirmativeAnswer = isAffirmativeAnswer;
|
|
11
|
+
exports.runInteractiveRepair = runInteractiveRepair;
|
|
12
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
13
|
+
const identity_1 = require("../identity");
|
|
14
|
+
function isCredentialIssue(degraded) {
|
|
15
|
+
const reason = degraded.errorReason.toLowerCase();
|
|
16
|
+
const hint = degraded.fixHint.toLowerCase();
|
|
17
|
+
return reason.includes("credentials") || hint.includes("ouro auth");
|
|
18
|
+
}
|
|
19
|
+
function isVaultUnlockIssue(degraded) {
|
|
20
|
+
const text = `${degraded.errorReason}\n${degraded.fixHint}`.toLowerCase();
|
|
21
|
+
return /ouro vault unlock|credential vault is locked|vault(?: is)? locked/.test(text);
|
|
22
|
+
}
|
|
23
|
+
function isConfigError(degraded) {
|
|
24
|
+
return degraded.fixHint.length > 0 && !isVaultUnlockIssue(degraded) && !isCredentialIssue(degraded);
|
|
25
|
+
}
|
|
26
|
+
function hasRunnableInteractiveRepair(degraded) {
|
|
27
|
+
if (degraded.issue?.actions.some((action) => typedActionToRunnable(degraded, action) !== undefined)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return isVaultUnlockIssue(degraded) || isCredentialIssue(degraded);
|
|
31
|
+
}
|
|
32
|
+
function isAgentProvider(value) {
|
|
33
|
+
return Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
|
|
34
|
+
}
|
|
35
|
+
function extractProviderFromFixHint(fixHint) {
|
|
36
|
+
const provider = fixHint.match(/--provider\s+([a-z0-9-]+)/)?.[1]
|
|
37
|
+
?? fixHint.match(/providers\.([a-z0-9-]+)/)?.[1];
|
|
38
|
+
if (!provider || !isAgentProvider(provider))
|
|
39
|
+
return undefined;
|
|
40
|
+
return provider;
|
|
41
|
+
}
|
|
42
|
+
function escapeRegExp(value) {
|
|
43
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
44
|
+
}
|
|
45
|
+
function cleanExtractedCommand(command) {
|
|
46
|
+
const cleaned = command?.trim().replace(/[`'",;:.)]+$/g, "").trim();
|
|
47
|
+
return cleaned && cleaned.length > 0 ? cleaned : undefined;
|
|
48
|
+
}
|
|
49
|
+
function extractRepairCommand(fixHint, commandPrefix) {
|
|
50
|
+
const escapedPrefix = escapeRegExp(commandPrefix);
|
|
51
|
+
const commandBody = `${escapedPrefix}(?=\\s|$)[^\`'"]*`;
|
|
52
|
+
const quoted = fixHint.match(new RegExp(`[\`'"](${commandBody})[\`'"]`, "i"))?.[1];
|
|
53
|
+
const unquoted = fixHint.match(new RegExp(`(${escapedPrefix}(?=\\s|$)[^\\n,;.]+)`, "i"))?.[1];
|
|
54
|
+
return cleanExtractedCommand(quoted) ?? cleanExtractedCommand(unquoted);
|
|
55
|
+
}
|
|
56
|
+
function authCommandFor(degraded) {
|
|
57
|
+
const command = extractRepairCommand(degraded.fixHint, "ouro auth");
|
|
58
|
+
return command && command.length > 0 ? command : `ouro auth --agent ${degraded.agent}`;
|
|
59
|
+
}
|
|
60
|
+
function vaultUnlockCommandFor(degraded) {
|
|
61
|
+
const command = extractRepairCommand(degraded.fixHint, "ouro vault unlock");
|
|
62
|
+
return command && command.length > 0 ? command : `ouro vault unlock --agent ${degraded.agent}`;
|
|
63
|
+
}
|
|
64
|
+
function isAffirmativeAnswer(answer) {
|
|
65
|
+
return /^(y|yes)$/i.test(answer.trim());
|
|
66
|
+
}
|
|
67
|
+
function uniqueCommands(commands) {
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
const unique = [];
|
|
70
|
+
commands.forEach((command) => {
|
|
71
|
+
if (!command)
|
|
72
|
+
return;
|
|
73
|
+
if (seen.has(command))
|
|
74
|
+
return;
|
|
75
|
+
seen.add(command);
|
|
76
|
+
unique.push(command);
|
|
77
|
+
});
|
|
78
|
+
return unique;
|
|
79
|
+
}
|
|
80
|
+
function fallbackCommandsFor(degraded, primaryCommand) {
|
|
81
|
+
const issueCommands = degraded.issue?.actions.map((action) => action.command) ?? [];
|
|
82
|
+
return uniqueCommands([
|
|
83
|
+
primaryCommand,
|
|
84
|
+
...issueCommands,
|
|
85
|
+
extractRepairCommand(degraded.fixHint, "ouro vault replace"),
|
|
86
|
+
extractRepairCommand(degraded.fixHint, "ouro vault recover"),
|
|
87
|
+
extractRepairCommand(degraded.fixHint, "ouro use"),
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
function renderRepairChoices(prefix, commands) {
|
|
91
|
+
return commands.map((command, index) => ` ${index === 0 ? prefix : "or"}: ${command}`);
|
|
92
|
+
}
|
|
93
|
+
function renderRepairQueueSummaryLines(degraded) {
|
|
94
|
+
const repairable = degraded
|
|
95
|
+
.map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
|
|
96
|
+
.filter((item) => item.action !== undefined);
|
|
97
|
+
if (repairable.length < 2)
|
|
98
|
+
return [];
|
|
99
|
+
const lines = [
|
|
100
|
+
"Repair queue",
|
|
101
|
+
`${repairable.length} agents need attention before startup can finish.`,
|
|
102
|
+
"",
|
|
103
|
+
];
|
|
104
|
+
repairable.forEach(({ entry, action }, index) => {
|
|
105
|
+
lines.push(`${entry.agent} - ${action.label}`);
|
|
106
|
+
lines.push(` ${action.command}`);
|
|
107
|
+
if (index < repairable.length - 1)
|
|
108
|
+
lines.push("");
|
|
109
|
+
});
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
112
|
+
function renderActionPromptLines(agent, action) {
|
|
113
|
+
const lines = [
|
|
114
|
+
`${agent}`,
|
|
115
|
+
` needs: ${action.label}`,
|
|
116
|
+
` run: ${action.command}`,
|
|
117
|
+
];
|
|
118
|
+
if (action.kind === "vault-unlock") {
|
|
119
|
+
lines.push(" note: use the saved vault unlock secret");
|
|
120
|
+
}
|
|
121
|
+
return lines;
|
|
122
|
+
}
|
|
123
|
+
function renderDeferredRepair(agent, commands) {
|
|
124
|
+
return [
|
|
125
|
+
`Leaving ${agent} for later.`,
|
|
126
|
+
...renderRepairChoices("next", commands),
|
|
127
|
+
].join("\n");
|
|
128
|
+
}
|
|
129
|
+
function renderManualRepairHint(agent, fixHint) {
|
|
130
|
+
return [
|
|
131
|
+
`${agent}`,
|
|
132
|
+
" needs manual attention",
|
|
133
|
+
` next: ${fixHint}`,
|
|
134
|
+
].join("\n");
|
|
135
|
+
}
|
|
136
|
+
function renderUnknownRepair(agent, errorReason) {
|
|
137
|
+
return [
|
|
138
|
+
`${agent}`,
|
|
139
|
+
` ${errorReason}`,
|
|
140
|
+
].join("\n");
|
|
141
|
+
}
|
|
142
|
+
function writeDeclinedRepair(degraded, command, deps) {
|
|
143
|
+
deps.writeStdout(renderDeferredRepair(degraded.agent, fallbackCommandsFor(degraded, command)));
|
|
144
|
+
}
|
|
145
|
+
function runnableRepairActionFor(degraded) {
|
|
146
|
+
const typedAction = degraded.issue?.actions
|
|
147
|
+
.map((action) => typedActionToRunnable(degraded, action))
|
|
148
|
+
.find((action) => action !== undefined);
|
|
149
|
+
if (typedAction)
|
|
150
|
+
return typedAction;
|
|
151
|
+
if (isVaultUnlockIssue(degraded)) {
|
|
152
|
+
return { kind: "vault-unlock", label: "vault unlock", command: vaultUnlockCommandFor(degraded) };
|
|
153
|
+
}
|
|
154
|
+
if (isCredentialIssue(degraded)) {
|
|
155
|
+
return {
|
|
156
|
+
kind: "provider-auth",
|
|
157
|
+
label: "provider auth",
|
|
158
|
+
command: authCommandFor(degraded),
|
|
159
|
+
provider: extractProviderFromFixHint(degraded.fixHint),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
function typedActionToRunnable(degraded, action) {
|
|
165
|
+
if (action.executable === false || action.command.includes("<"))
|
|
166
|
+
return undefined;
|
|
167
|
+
if (action.kind === "vault-unlock") {
|
|
168
|
+
return { kind: "vault-unlock", label: "vault unlock", command: action.command };
|
|
169
|
+
}
|
|
170
|
+
if (action.kind === "provider-auth") {
|
|
171
|
+
return {
|
|
172
|
+
kind: "provider-auth",
|
|
173
|
+
label: "provider auth",
|
|
174
|
+
command: action.command || `ouro auth --agent ${degraded.agent}`,
|
|
175
|
+
provider: action.provider,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
function writeRepairQueueSummary(degraded, deps) {
|
|
181
|
+
const lines = renderRepairQueueSummaryLines(degraded);
|
|
182
|
+
if (lines.length > 0)
|
|
183
|
+
deps.writeStdout(lines.join("\n"));
|
|
184
|
+
}
|
|
185
|
+
async function attemptVaultUnlock(entry, action, deps) {
|
|
186
|
+
deps.writeStdout(renderActionPromptLines(entry.agent, action).join("\n"));
|
|
187
|
+
const answer = await deps.promptInput(`Unlock ${entry.agent}'s vault now? [y/N] `);
|
|
188
|
+
if (!isAffirmativeAnswer(answer)) {
|
|
189
|
+
writeDeclinedRepair(entry, action.command, deps);
|
|
190
|
+
return { succeeded: false, attempted: false };
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
if (!deps.runVaultUnlock) {
|
|
194
|
+
deps.writeStdout(renderManualRepairHint(entry.agent, entry.fixHint));
|
|
195
|
+
return { succeeded: false, attempted: false };
|
|
196
|
+
}
|
|
197
|
+
await deps.runVaultUnlock(entry.agent);
|
|
198
|
+
return { succeeded: true, attempted: true };
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
202
|
+
deps.writeStdout(`Vault unlock did not finish for ${entry.agent}.\n ${msg}`);
|
|
203
|
+
(0, runtime_1.emitNervesEvent)({
|
|
204
|
+
level: "error",
|
|
205
|
+
component: "daemon",
|
|
206
|
+
event: "daemon.interactive_repair_vault_unlock_error",
|
|
207
|
+
message: `vault unlock failed for ${entry.agent}`,
|
|
208
|
+
meta: { agent: entry.agent, error: msg },
|
|
209
|
+
});
|
|
210
|
+
return { succeeded: false, attempted: true };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function attemptProviderAuth(entry, action, deps) {
|
|
214
|
+
deps.writeStdout(renderActionPromptLines(entry.agent, action).join("\n"));
|
|
215
|
+
const answer = await deps.promptInput(`Open the auth flow for ${entry.agent} now? [y/N] `);
|
|
216
|
+
if (!isAffirmativeAnswer(answer)) {
|
|
217
|
+
writeDeclinedRepair(entry, action.command, deps);
|
|
218
|
+
return { succeeded: false, attempted: false };
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
if (action.provider) {
|
|
222
|
+
await deps.runAuthFlow(entry.agent, action.provider);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
await deps.runAuthFlow(entry.agent);
|
|
226
|
+
}
|
|
227
|
+
return { succeeded: true, attempted: true };
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
231
|
+
deps.writeStdout(`Auth did not finish for ${entry.agent}.\n ${msg}`);
|
|
232
|
+
(0, runtime_1.emitNervesEvent)({
|
|
233
|
+
level: "error",
|
|
234
|
+
component: "daemon",
|
|
235
|
+
event: "daemon.interactive_repair_auth_error",
|
|
236
|
+
message: `auth flow failed for ${entry.agent}`,
|
|
237
|
+
meta: { agent: entry.agent, error: msg },
|
|
238
|
+
});
|
|
239
|
+
return { succeeded: false, attempted: true };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function processEntry(entry, deps) {
|
|
243
|
+
let current = entry;
|
|
244
|
+
while (current) {
|
|
245
|
+
const action = runnableRepairActionFor(current);
|
|
246
|
+
let outcome;
|
|
247
|
+
if (action?.kind === "vault-unlock") {
|
|
248
|
+
outcome = await attemptVaultUnlock(current, action, deps);
|
|
249
|
+
}
|
|
250
|
+
else if (action?.kind === "provider-auth") {
|
|
251
|
+
outcome = await attemptProviderAuth(current, action, deps);
|
|
252
|
+
}
|
|
253
|
+
else if (isConfigError(current)) {
|
|
254
|
+
deps.writeStdout(renderManualRepairHint(current.agent, current.fixHint));
|
|
255
|
+
return { attempted: false };
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
deps.writeStdout(renderUnknownRepair(current.agent, current.errorReason));
|
|
259
|
+
return { attempted: false };
|
|
260
|
+
}
|
|
261
|
+
if (!outcome.succeeded || !deps.recheckAgent) {
|
|
262
|
+
return { attempted: outcome.attempted };
|
|
263
|
+
}
|
|
264
|
+
// Re-evaluate the agent after successful repair
|
|
265
|
+
const recheckResult = await deps.recheckAgent(current.agent);
|
|
266
|
+
if (recheckResult === null) {
|
|
267
|
+
deps.writeStdout(`${current.agent} recovered.`);
|
|
268
|
+
return { attempted: true };
|
|
269
|
+
}
|
|
270
|
+
// Agent still degraded with a new error -- loop to present the new action
|
|
271
|
+
current = recheckResult;
|
|
272
|
+
}
|
|
273
|
+
/* v8 ignore next -- unreachable: loop always returns from within @preserve */
|
|
274
|
+
return { attempted: false };
|
|
275
|
+
}
|
|
276
|
+
async function runInteractiveRepair(degraded, deps) {
|
|
277
|
+
(0, runtime_1.emitNervesEvent)({
|
|
278
|
+
level: "info",
|
|
279
|
+
component: "daemon",
|
|
280
|
+
event: "daemon.interactive_repair_start",
|
|
281
|
+
message: "interactive repair flow started",
|
|
282
|
+
meta: { degradedCount: degraded.length },
|
|
283
|
+
});
|
|
284
|
+
if (degraded.length === 0) {
|
|
285
|
+
return { repairsAttempted: false };
|
|
286
|
+
}
|
|
287
|
+
let repairsAttempted = false;
|
|
288
|
+
if (!deps.skipQueueSummary) {
|
|
289
|
+
writeRepairQueueSummary(degraded, deps);
|
|
290
|
+
}
|
|
291
|
+
for (const entry of degraded) {
|
|
292
|
+
const result = await processEntry(entry, deps);
|
|
293
|
+
if (result.attempted)
|
|
294
|
+
repairsAttempted = true;
|
|
295
|
+
}
|
|
296
|
+
if (repairsAttempted) {
|
|
297
|
+
deps.writeStdout("Repair flow complete.");
|
|
298
|
+
}
|
|
299
|
+
(0, runtime_1.emitNervesEvent)({
|
|
300
|
+
level: "info",
|
|
301
|
+
component: "daemon",
|
|
302
|
+
event: "daemon.interactive_repair_end",
|
|
303
|
+
message: "interactive repair flow completed",
|
|
304
|
+
meta: { repairsAttempted },
|
|
305
|
+
});
|
|
306
|
+
return { repairsAttempted };
|
|
307
|
+
}
|