@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.550
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 +133 -19
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -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 +3555 -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 +837 -26
- 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 +479 -0
- package/dist/heart/background-operations.js +281 -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 +114 -118
- package/dist/heart/core.js +925 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +512 -0
- package/dist/heart/daemon/agent-discovery.js +102 -3
- package/dist/heart/daemon/agent-service.js +522 -0
- package/dist/heart/daemon/agentic-repair.js +554 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +665 -0
- package/dist/heart/daemon/cli-exec.js +7565 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1590 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +775 -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 -1672
- package/dist/heart/daemon/daemon-entry.js +417 -2
- package/dist/heart/daemon/daemon-health.js +183 -0
- package/dist/heart/daemon/daemon-rollup.js +58 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +758 -71
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +844 -0
- package/dist/heart/daemon/drift-detection.js +146 -0
- package/dist/heart/daemon/health-monitor.js +122 -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 +102 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +14 -12
- 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 +375 -33
- 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 +3 -31
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +353 -38
- 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 +158 -11
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +330 -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 +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- 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 +6 -8
- 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 +200 -51
- 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/mail-import-discovery.js +353 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +31 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +195 -0
- package/dist/heart/mailbox/readers/agent-machine.js +382 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
- package/dist/heart/mailbox/readers/mail.js +362 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
- package/dist/heart/mailbox/readers/sessions.js +232 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +683 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +425 -0
- package/dist/heart/provider-failover.js +301 -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 +139 -52
- package/dist/heart/providers/azure.js +97 -13
- package/dist/heart/providers/error-classification.js +127 -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 +26 -8
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +367 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +11 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1149 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +243 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +9 -5
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-description.js +139 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +381 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -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 +6 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -0
- package/dist/mailbox-ui/index.html +15 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +674 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +720 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +430 -0
- package/dist/mailroom/mbox-import.js +383 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +233 -0
- package/dist/mailroom/search-cache.js +256 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +165 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +62 -75
- 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/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- 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 +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +995 -123
- 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 +139 -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/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- 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 +816 -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 +295 -0
- package/dist/repertoire/mcp-manager.js +362 -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 +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -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 +47 -1075
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +142 -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 +119 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1857 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-session.js +750 -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-trip.js +604 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +108 -100
- 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/active-turns.js +216 -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 +77 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +2305 -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} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -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 +607 -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 +85 -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 +520 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +569 -182
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +248 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +38 -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/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1177
- package/dist/senses/debug-activity.js +0 -148
- 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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeDaemonRollup = computeDaemonRollup;
|
|
4
|
+
/**
|
|
5
|
+
* Pure rollup decision function — given the post-inventory daemon
|
|
6
|
+
* surface, returns the daemon-wide rollup state per the locked Layer 1
|
|
7
|
+
* vocabulary table:
|
|
8
|
+
*
|
|
9
|
+
* | rollup | when |
|
|
10
|
+
* | ---------- | --------------------------------------------------------- |
|
|
11
|
+
* | healthy | every enabled agent serving + no bootstrap-degraded + no safe-mode |
|
|
12
|
+
* | partial | (≥1 serving + ≥1 not serving) OR (all serving + ≥1 bootstrap-degraded) |
|
|
13
|
+
* | degraded | zero enabled agents serving (fresh install OR all unhealthy) |
|
|
14
|
+
* | safe-mode | `safeMode === true` overrides everything else |
|
|
15
|
+
*
|
|
16
|
+
* The function NEVER returns `"down"`. By the time `computeDaemonRollup`
|
|
17
|
+
* is reachable, the daemon process has started, opened its socket, and
|
|
18
|
+
* read its agent inventory — pre-inventory failure is the caller's
|
|
19
|
+
* domain. `daemon-entry.ts`'s startup-failure path assigns `"down"` to
|
|
20
|
+
* `DaemonHealthState.status` directly without consulting this function.
|
|
21
|
+
*/
|
|
22
|
+
function computeDaemonRollup(input) {
|
|
23
|
+
// Safe mode wins, period. Crash-loop detection trumps everything —
|
|
24
|
+
// we want the human to see SAFE MODE, not a noisy partial/degraded.
|
|
25
|
+
if (input.safeMode) {
|
|
26
|
+
return "safe-mode";
|
|
27
|
+
}
|
|
28
|
+
// Count serving agents. "Serving" = "running" worker status.
|
|
29
|
+
// Anything else (crashed/stopped/starting/etc) is not serving.
|
|
30
|
+
let serving = 0;
|
|
31
|
+
let notServing = 0;
|
|
32
|
+
for (const agent of input.enabledAgents) {
|
|
33
|
+
if (agent.status === "running") {
|
|
34
|
+
serving++;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
notServing++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Zero-serving wins over bootstrap-degraded — we have no working
|
|
41
|
+
// agents to surface a "partially working" story about. This covers
|
|
42
|
+
// both fresh-install (`enabledAgents.length === 0`) and
|
|
43
|
+
// all-failed-live-check (`serving === 0` with `notServing > 0`).
|
|
44
|
+
// Render layer (cli-render.ts) splits the UX copy by inspecting the
|
|
45
|
+
// agents map; the rollup itself doesn't carry the distinction.
|
|
46
|
+
if (serving === 0) {
|
|
47
|
+
return "degraded";
|
|
48
|
+
}
|
|
49
|
+
// From here we have ≥1 serving agent. The remaining choice is
|
|
50
|
+
// healthy vs partial.
|
|
51
|
+
const hasUnhealthyAgent = notServing > 0;
|
|
52
|
+
const hasBootstrapDegraded = input.bootstrapDegraded.length > 0;
|
|
53
|
+
const hasDrift = input.driftDetected === true;
|
|
54
|
+
if (hasUnhealthyAgent || hasBootstrapDegraded || hasDrift) {
|
|
55
|
+
return "partial";
|
|
56
|
+
}
|
|
57
|
+
return "healthy";
|
|
58
|
+
}
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureCurrentDaemonRuntime = ensureCurrentDaemonRuntime;
|
|
4
4
|
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
/* v8 ignore start -- daemon liveness poll: real socket timing untestable in vitest @preserve */
|
|
6
|
+
async function verifyDaemonStarted(deps) {
|
|
7
|
+
if (!deps.checkSocketAlive)
|
|
8
|
+
return true;
|
|
9
|
+
const maxWaitMs = 10_000;
|
|
10
|
+
const pollIntervalMs = 500;
|
|
11
|
+
const deadline = Date.now() + maxWaitMs;
|
|
12
|
+
deps.onProgress?.("waiting for the replacement background service to answer");
|
|
13
|
+
while (Date.now() < deadline) {
|
|
14
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
15
|
+
if (await deps.checkSocketAlive(deps.socketPath))
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
/* v8 ignore stop */
|
|
5
21
|
function isKnownVersion(version) {
|
|
6
22
|
return version !== "unknown" && version.trim().length > 0;
|
|
7
23
|
}
|
|
@@ -17,6 +33,7 @@ function normalizeRuntimeIdentity(value) {
|
|
|
17
33
|
lastUpdated: typeof value.lastUpdated === "string" ? value.lastUpdated : "unknown",
|
|
18
34
|
repoRoot: typeof value.repoRoot === "string" ? value.repoRoot : "unknown",
|
|
19
35
|
configFingerprint: typeof value.configFingerprint === "string" ? value.configFingerprint : "unknown",
|
|
36
|
+
managedAgents: typeof value.managedAgents === "string" ? value.managedAgents : "unknown",
|
|
20
37
|
};
|
|
21
38
|
}
|
|
22
39
|
async function readRunningRuntimeIdentity(deps) {
|
|
@@ -55,23 +72,29 @@ function collectRuntimeDriftReasons(local, running) {
|
|
|
55
72
|
running: running.configFingerprint,
|
|
56
73
|
});
|
|
57
74
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
if (isKnownRuntimeValue(local.managedAgents)
|
|
76
|
+
&& isKnownRuntimeValue(running.managedAgents)
|
|
77
|
+
&& local.managedAgents !== running.managedAgents) {
|
|
78
|
+
reasons.push({
|
|
79
|
+
key: "managedAgents",
|
|
80
|
+
label: "managed agents",
|
|
81
|
+
local: local.managedAgents,
|
|
82
|
+
running: running.managedAgents,
|
|
83
|
+
});
|
|
63
84
|
}
|
|
64
|
-
return
|
|
85
|
+
return reasons;
|
|
65
86
|
}
|
|
66
|
-
function
|
|
67
|
-
return reasons.map((reason) =>
|
|
87
|
+
function formatRuntimeDriftPublicSummary(reasons) {
|
|
88
|
+
return reasons.map((reason) => reason.label).join(", ");
|
|
68
89
|
}
|
|
69
90
|
async function ensureCurrentDaemonRuntime(deps) {
|
|
91
|
+
deps.onProgress?.("checking whether an older background service is already running");
|
|
70
92
|
const localRuntime = normalizeRuntimeIdentity({
|
|
71
93
|
version: deps.localVersion,
|
|
72
94
|
lastUpdated: deps.localLastUpdated,
|
|
73
95
|
repoRoot: deps.localRepoRoot,
|
|
74
96
|
configFingerprint: deps.localConfigFingerprint,
|
|
97
|
+
managedAgents: deps.localManagedAgents,
|
|
75
98
|
});
|
|
76
99
|
try {
|
|
77
100
|
const runningRuntime = await readRunningRuntimeIdentity(deps);
|
|
@@ -80,17 +103,40 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
80
103
|
let result;
|
|
81
104
|
if (driftReasons.length > 0) {
|
|
82
105
|
const includesVersionDrift = driftReasons.some((entry) => entry.key === "version");
|
|
83
|
-
const
|
|
106
|
+
const publicDriftSummary = formatRuntimeDriftPublicSummary(driftReasons);
|
|
84
107
|
try {
|
|
108
|
+
deps.onProgress?.("stopping the older background service");
|
|
85
109
|
await deps.stopDaemon();
|
|
110
|
+
if (deps.prepareDaemonRuntimeReplacement) {
|
|
111
|
+
deps.onProgress?.("disabling daemon auto-restart during replacement");
|
|
112
|
+
try {
|
|
113
|
+
await Promise.resolve(deps.prepareDaemonRuntimeReplacement());
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
(0, runtime_1.emitNervesEvent)({
|
|
117
|
+
level: "warn",
|
|
118
|
+
component: "daemon",
|
|
119
|
+
event: "daemon.runtime_sync_replacement_prepare_error",
|
|
120
|
+
message: "daemon runtime replacement preparation failed",
|
|
121
|
+
meta: {
|
|
122
|
+
socketPath: deps.socketPath,
|
|
123
|
+
reason: formatErrorReason(error),
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
86
128
|
}
|
|
87
129
|
catch (error) {
|
|
88
130
|
const reason = formatErrorReason(error);
|
|
89
131
|
result = {
|
|
132
|
+
ok: false,
|
|
90
133
|
alreadyRunning: true,
|
|
91
134
|
message: includesVersionDrift
|
|
92
|
-
? `daemon already running (${deps.socketPath}; could not replace
|
|
93
|
-
: `daemon already running (${deps.socketPath}; could not replace
|
|
135
|
+
? `daemon already running (${deps.socketPath}; could not replace the older background service ${runningVersion} -> ${deps.localVersion}: ${reason})`
|
|
136
|
+
: `daemon already running (${deps.socketPath}; could not replace the older background service after runtime drift ${publicDriftSummary}: ${reason})`,
|
|
137
|
+
startupFailureReason: includesVersionDrift
|
|
138
|
+
? "could not replace the older background service"
|
|
139
|
+
: "could not replace the older background service after runtime drift",
|
|
94
140
|
};
|
|
95
141
|
(0, runtime_1.emitNervesEvent)({
|
|
96
142
|
level: "warn",
|
|
@@ -103,10 +149,12 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
103
149
|
localLastUpdated: localRuntime.lastUpdated,
|
|
104
150
|
localRepoRoot: localRuntime.repoRoot,
|
|
105
151
|
localConfigFingerprint: localRuntime.configFingerprint,
|
|
152
|
+
localManagedAgents: localRuntime.managedAgents,
|
|
106
153
|
runningVersion,
|
|
107
154
|
runningLastUpdated: runningRuntime.lastUpdated,
|
|
108
155
|
runningRepoRoot: runningRuntime.repoRoot,
|
|
109
156
|
runningConfigFingerprint: runningRuntime.configFingerprint,
|
|
157
|
+
runningManagedAgents: runningRuntime.managedAgents,
|
|
110
158
|
action: "stale_replace_failed",
|
|
111
159
|
driftKeys: driftReasons.map((entry) => entry.key),
|
|
112
160
|
reason,
|
|
@@ -115,12 +163,26 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
115
163
|
return result;
|
|
116
164
|
}
|
|
117
165
|
deps.cleanupStaleSocket(deps.socketPath);
|
|
166
|
+
deps.onProgress?.("starting the replacement background service");
|
|
118
167
|
const started = await deps.startDaemonProcess(deps.socketPath);
|
|
168
|
+
const pid = started.pid ?? "unknown";
|
|
169
|
+
const startupCheck = deps.waitForDaemonStartup
|
|
170
|
+
? await deps.waitForDaemonStartup({ pid: started.pid ?? null })
|
|
171
|
+
: { ok: await verifyDaemonStarted(deps) };
|
|
172
|
+
const verified = startupCheck.ok;
|
|
173
|
+
/* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
|
|
174
|
+
const suffix = verified
|
|
175
|
+
? ""
|
|
176
|
+
: `\n${startupCheck.reason ?? "replacement background service did not answer in time"}; check logs with \`ouro logs\` or run \`ouro doctor\`.`;
|
|
119
177
|
result = {
|
|
178
|
+
ok: verified,
|
|
120
179
|
alreadyRunning: false,
|
|
121
180
|
message: includesVersionDrift
|
|
122
|
-
? `
|
|
123
|
-
: `
|
|
181
|
+
? `replaced an older background service ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
|
|
182
|
+
: `replaced an older background service after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
|
|
183
|
+
verifyStartupStatus: verified,
|
|
184
|
+
startedPid: started.pid ?? null,
|
|
185
|
+
startupFailureReason: verified ? null : (startupCheck.reason ?? "replacement background service did not answer in time"),
|
|
124
186
|
};
|
|
125
187
|
(0, runtime_1.emitNervesEvent)({
|
|
126
188
|
component: "daemon",
|
|
@@ -132,10 +194,12 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
132
194
|
localLastUpdated: localRuntime.lastUpdated,
|
|
133
195
|
localRepoRoot: localRuntime.repoRoot,
|
|
134
196
|
localConfigFingerprint: localRuntime.configFingerprint,
|
|
197
|
+
localManagedAgents: localRuntime.managedAgents,
|
|
135
198
|
runningVersion,
|
|
136
199
|
runningLastUpdated: runningRuntime.lastUpdated,
|
|
137
200
|
runningRepoRoot: runningRuntime.repoRoot,
|
|
138
201
|
runningConfigFingerprint: runningRuntime.configFingerprint,
|
|
202
|
+
runningManagedAgents: runningRuntime.managedAgents,
|
|
139
203
|
action: "stale_restarted",
|
|
140
204
|
driftKeys: driftReasons.map((entry) => entry.key),
|
|
141
205
|
pid: started.pid ?? null,
|
|
@@ -145,6 +209,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
145
209
|
}
|
|
146
210
|
if (!isKnownVersion(localRuntime.version) || !isKnownVersion(runningVersion)) {
|
|
147
211
|
result = {
|
|
212
|
+
ok: true,
|
|
148
213
|
alreadyRunning: true,
|
|
149
214
|
message: `daemon already running (${deps.socketPath}; unable to verify version)`,
|
|
150
215
|
};
|
|
@@ -158,10 +223,12 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
158
223
|
localLastUpdated: localRuntime.lastUpdated,
|
|
159
224
|
localRepoRoot: localRuntime.repoRoot,
|
|
160
225
|
localConfigFingerprint: localRuntime.configFingerprint,
|
|
226
|
+
localManagedAgents: localRuntime.managedAgents,
|
|
161
227
|
runningVersion,
|
|
162
228
|
runningLastUpdated: runningRuntime.lastUpdated,
|
|
163
229
|
runningRepoRoot: runningRuntime.repoRoot,
|
|
164
230
|
runningConfigFingerprint: runningRuntime.configFingerprint,
|
|
231
|
+
runningManagedAgents: runningRuntime.managedAgents,
|
|
165
232
|
action: "unknown_version",
|
|
166
233
|
},
|
|
167
234
|
});
|
|
@@ -171,6 +238,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
171
238
|
catch (error) {
|
|
172
239
|
const reason = formatErrorReason(error);
|
|
173
240
|
const result = {
|
|
241
|
+
ok: true,
|
|
174
242
|
alreadyRunning: true,
|
|
175
243
|
message: `daemon already running (${deps.socketPath}; unable to verify version: ${reason})`,
|
|
176
244
|
};
|
|
@@ -185,6 +253,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
185
253
|
localLastUpdated: localRuntime.lastUpdated,
|
|
186
254
|
localRepoRoot: localRuntime.repoRoot,
|
|
187
255
|
localConfigFingerprint: localRuntime.configFingerprint,
|
|
256
|
+
localManagedAgents: localRuntime.managedAgents,
|
|
188
257
|
action: "status_lookup_failed",
|
|
189
258
|
reason,
|
|
190
259
|
},
|
|
@@ -192,8 +261,12 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
192
261
|
return result;
|
|
193
262
|
}
|
|
194
263
|
const result = {
|
|
264
|
+
ok: true,
|
|
195
265
|
alreadyRunning: true,
|
|
196
266
|
message: `daemon already running (${deps.socketPath})`,
|
|
267
|
+
verifyStartupStatus: true,
|
|
268
|
+
startedPid: null,
|
|
269
|
+
startupFailureReason: null,
|
|
197
270
|
};
|
|
198
271
|
(0, runtime_1.emitNervesEvent)({
|
|
199
272
|
component: "daemon",
|
|
@@ -205,6 +278,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
205
278
|
localLastUpdated: localRuntime.lastUpdated,
|
|
206
279
|
localRepoRoot: localRuntime.repoRoot,
|
|
207
280
|
localConfigFingerprint: localRuntime.configFingerprint,
|
|
281
|
+
localManagedAgents: localRuntime.managedAgents,
|
|
208
282
|
action: "already_current",
|
|
209
283
|
},
|
|
210
284
|
});
|
|
@@ -0,0 +1,236 @@
|
|
|
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.RECENT_CRASHES_MAX = void 0;
|
|
37
|
+
exports.getTombstonePath = getTombstonePath;
|
|
38
|
+
exports.setTombstonePath = setTombstonePath;
|
|
39
|
+
exports.captureDeathForensics = captureDeathForensics;
|
|
40
|
+
exports.writeDaemonTombstone = writeDaemonTombstone;
|
|
41
|
+
exports.readDaemonTombstone = readDaemonTombstone;
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
47
|
+
/** Maximum number of historical crash timestamps to retain in the tombstone. */
|
|
48
|
+
exports.RECENT_CRASHES_MAX = 100;
|
|
49
|
+
let _tombstonePath = null;
|
|
50
|
+
function getTombstonePath() {
|
|
51
|
+
if (!_tombstonePath) {
|
|
52
|
+
_tombstonePath = path.join(os.homedir(), ".ouro-cli", "daemon-death.json");
|
|
53
|
+
}
|
|
54
|
+
return _tombstonePath;
|
|
55
|
+
}
|
|
56
|
+
/** Overrides the tombstone path for testing. Pass null to reset. */
|
|
57
|
+
function setTombstonePath(p) {
|
|
58
|
+
_tombstonePath = p;
|
|
59
|
+
}
|
|
60
|
+
/* v8 ignore start -- shells out to ps; covered via injected runPs in unit tests @preserve */
|
|
61
|
+
function defaultRunPs(args) {
|
|
62
|
+
try {
|
|
63
|
+
return (0, child_process_1.execSync)(`ps ${args.join(" ")}`, { encoding: "utf-8", timeout: 2000 });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/* v8 ignore stop */
|
|
70
|
+
const DEFAULT_FORENSICS_DEPS = {
|
|
71
|
+
/* v8 ignore next -- defensive: process.ppid always exists in node @preserve */
|
|
72
|
+
ppid: () => (typeof process !== "undefined" && typeof process.ppid === "number" ? process.ppid : 0),
|
|
73
|
+
runPs: defaultRunPs,
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Capture forensic data about who is likely to have killed the daemon.
|
|
77
|
+
* Synchronous and best-effort: never throws, always returns a structured
|
|
78
|
+
* record (with nulls if anything failed). Called from inside SIGTERM/SIGINT
|
|
79
|
+
* handlers, so it must be fast and have no async dependencies.
|
|
80
|
+
*/
|
|
81
|
+
function captureDeathForensics(deps = DEFAULT_FORENSICS_DEPS) {
|
|
82
|
+
const parentPid = (() => {
|
|
83
|
+
try {
|
|
84
|
+
const p = deps.ppid();
|
|
85
|
+
return typeof p === "number" && p > 0 ? p : null;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
let parentCommand = null;
|
|
92
|
+
if (parentPid !== null) {
|
|
93
|
+
const psParent = deps.runPs(["-p", String(parentPid), "-o", "command="]);
|
|
94
|
+
if (psParent !== null) {
|
|
95
|
+
const trimmed = psParent.trim();
|
|
96
|
+
parentCommand = trimmed.length > 0 ? trimmed : null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const processSnapshot = (() => {
|
|
100
|
+
const psAll = deps.runPs(["-eo", "pid,ppid,command"]);
|
|
101
|
+
if (psAll === null)
|
|
102
|
+
return null;
|
|
103
|
+
const lines = psAll.split("\n");
|
|
104
|
+
// Filter for relevant processes only — node, vitest, ouro, kill commands.
|
|
105
|
+
// Keeps the snapshot small and human-scannable.
|
|
106
|
+
const relevant = lines.filter((line) => {
|
|
107
|
+
const lower = line.toLowerCase();
|
|
108
|
+
return (lower.includes("node")
|
|
109
|
+
|| lower.includes("vitest")
|
|
110
|
+
|| lower.includes("ouro")
|
|
111
|
+
|| lower.includes("/kill ")
|
|
112
|
+
|| lower.includes("pkill")
|
|
113
|
+
|| lower.includes("killall"));
|
|
114
|
+
});
|
|
115
|
+
if (relevant.length === 0)
|
|
116
|
+
return null;
|
|
117
|
+
return relevant.join("\n");
|
|
118
|
+
})();
|
|
119
|
+
const killerHint = deriveKillerHint(parentCommand, processSnapshot);
|
|
120
|
+
return { parentPid, parentCommand, processSnapshot, killerHint };
|
|
121
|
+
}
|
|
122
|
+
function deriveKillerHint(parentCommand, snapshot) {
|
|
123
|
+
if (parentCommand !== null && parentCommand.toLowerCase().includes("launchd")) {
|
|
124
|
+
return "process was reparented to launchd — likely killed by launchctl bootout, KeepAlive thrash, or RSS pressure";
|
|
125
|
+
}
|
|
126
|
+
if (snapshot !== null) {
|
|
127
|
+
const lower = snapshot.toLowerCase();
|
|
128
|
+
if (lower.includes("vitest")) {
|
|
129
|
+
return "vitest worker is running — possible test cleanup killing detached processes";
|
|
130
|
+
}
|
|
131
|
+
if (lower.includes("pkill") || lower.includes("killall")) {
|
|
132
|
+
return "saw pkill/killall in process list — explicit kill command";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
function writeDaemonTombstone(reason, error, forensicsDeps) {
|
|
138
|
+
const now = new Date().toISOString();
|
|
139
|
+
const filePath = getTombstonePath();
|
|
140
|
+
// Read existing recentCrashes from previous tombstone (best-effort)
|
|
141
|
+
let existingCrashes = [];
|
|
142
|
+
try {
|
|
143
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
144
|
+
const existing = JSON.parse(raw);
|
|
145
|
+
if (Array.isArray(existing.recentCrashes)) {
|
|
146
|
+
existingCrashes = existing.recentCrashes.filter((entry) => typeof entry === "string");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// No existing tombstone or unreadable — start fresh
|
|
151
|
+
}
|
|
152
|
+
// Append the new crash and cap at the most recent RECENT_CRASHES_MAX entries
|
|
153
|
+
// so the tombstone doesn't grow without bound (we saw it hit 12,265 entries
|
|
154
|
+
// after a March 31 crash-restart thrash loop).
|
|
155
|
+
const recentCrashes = [...existingCrashes, now].slice(-exports.RECENT_CRASHES_MAX);
|
|
156
|
+
// Forensics: only meaningful for signal-driven deaths (sigterm/sigint).
|
|
157
|
+
// For uncaughtException etc. we skip the snapshot to keep tombstone writes
|
|
158
|
+
// fast on the unhappy path.
|
|
159
|
+
const shouldCaptureForensics = reason === "sigterm" || reason === "sigint";
|
|
160
|
+
const forensics = shouldCaptureForensics
|
|
161
|
+
? captureDeathForensics(forensicsDeps)
|
|
162
|
+
: undefined;
|
|
163
|
+
const tombstone = {
|
|
164
|
+
reason,
|
|
165
|
+
message: error?.message ?? reason,
|
|
166
|
+
stack: error?.stack ?? null,
|
|
167
|
+
timestamp: now,
|
|
168
|
+
pid: process.pid,
|
|
169
|
+
uptimeSeconds: Math.floor(process.uptime()),
|
|
170
|
+
recentCrashes,
|
|
171
|
+
...(forensics ? { forensics } : {}),
|
|
172
|
+
};
|
|
173
|
+
try {
|
|
174
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
175
|
+
fs.writeFileSync(filePath, JSON.stringify(tombstone, null, 2) + "\n", "utf-8");
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Best-effort: if we can't write, we're already dying.
|
|
179
|
+
}
|
|
180
|
+
(0, runtime_1.emitNervesEvent)({
|
|
181
|
+
level: "error",
|
|
182
|
+
component: "daemon",
|
|
183
|
+
event: "daemon.tombstone_written",
|
|
184
|
+
message: `daemon tombstone written: ${reason}`,
|
|
185
|
+
meta: {
|
|
186
|
+
reason,
|
|
187
|
+
errorMessage: error?.message ?? null,
|
|
188
|
+
filePath,
|
|
189
|
+
parentPid: forensics?.parentPid ?? null,
|
|
190
|
+
killerHint: forensics?.killerHint ?? null,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function readDaemonTombstone() {
|
|
195
|
+
const filePath = getTombstonePath();
|
|
196
|
+
try {
|
|
197
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
198
|
+
const parsed = JSON.parse(raw);
|
|
199
|
+
if (typeof parsed.reason !== "string" || typeof parsed.timestamp !== "string") {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
(0, runtime_1.emitNervesEvent)({
|
|
203
|
+
component: "daemon",
|
|
204
|
+
event: "daemon.tombstone_read",
|
|
205
|
+
message: "read daemon tombstone",
|
|
206
|
+
meta: { filePath },
|
|
207
|
+
});
|
|
208
|
+
const forensics = parseForensics(parsed.forensics);
|
|
209
|
+
return {
|
|
210
|
+
reason: parsed.reason,
|
|
211
|
+
message: typeof parsed.message === "string" ? parsed.message : String(parsed.reason),
|
|
212
|
+
stack: typeof parsed.stack === "string" ? parsed.stack : null,
|
|
213
|
+
timestamp: parsed.timestamp,
|
|
214
|
+
pid: typeof parsed.pid === "number" ? parsed.pid : 0,
|
|
215
|
+
uptimeSeconds: typeof parsed.uptimeSeconds === "number" ? parsed.uptimeSeconds : 0,
|
|
216
|
+
recentCrashes: Array.isArray(parsed.recentCrashes)
|
|
217
|
+
? parsed.recentCrashes.filter((e) => typeof e === "string")
|
|
218
|
+
: [],
|
|
219
|
+
...(forensics ? { forensics } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function parseForensics(value) {
|
|
227
|
+
if (value === null || typeof value !== "object")
|
|
228
|
+
return null;
|
|
229
|
+
const v = value;
|
|
230
|
+
return {
|
|
231
|
+
parentPid: typeof v.parentPid === "number" ? v.parentPid : null,
|
|
232
|
+
parentCommand: typeof v.parentCommand === "string" ? v.parentCommand : null,
|
|
233
|
+
processSnapshot: typeof v.processSnapshot === "string" ? v.processSnapshot : null,
|
|
234
|
+
killerHint: typeof v.killerHint === "string" ? v.killerHint : null,
|
|
235
|
+
};
|
|
236
|
+
}
|