@ouro.bot/cli 0.1.0-alpha.62 → 0.1.0-alpha.637
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 +127 -23
- 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-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 +4087 -13
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +144 -0
- package/dist/arc/episodes.js +118 -0
- package/dist/arc/evolution.js +487 -0
- package/dist/arc/intentions.js +134 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +270 -0
- package/dist/arc/packets.js +288 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +57 -0
- package/dist/heart/active-work.js +860 -43
- package/dist/heart/agent-entry.js +69 -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/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/awaiting/await-alert.js +146 -0
- package/dist/heart/awaiting/await-expiry.js +108 -0
- package/dist/heart/awaiting/await-loader.js +91 -0
- package/dist/heart/awaiting/await-parser.js +141 -0
- package/dist/heart/awaiting/await-runtime-state.js +100 -0
- package/dist/heart/awaiting/await-scheduler.js +377 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bridges/manager.js +137 -17
- package/dist/heart/bridges/store.js +14 -2
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +135 -0
- package/dist/heart/config-registry.js +322 -0
- package/dist/heart/config.js +114 -119
- package/dist/heart/core.js +1028 -248
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +419 -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 +547 -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 +776 -0
- package/dist/heart/daemon/cli-desk.js +322 -0
- package/dist/heart/daemon/cli-exec.js +7468 -0
- package/dist/heart/daemon/cli-help.js +505 -0
- package/dist/heart/daemon/cli-parse.js +1554 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +763 -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 -1700
- package/dist/heart/daemon/daemon-entry.js +485 -2
- package/dist/heart/daemon/daemon-health.js +176 -0
- package/dist/heart/daemon/daemon-rollup.js +57 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +906 -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 +873 -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 +89 -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 +79 -10
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/migrate-to-desk.js +848 -0
- 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/plugin-cli.js +432 -0
- package/dist/heart/daemon/process-manager.js +501 -35
- 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 +11 -3
- package/dist/heart/daemon/runtime-metadata.js +2 -30
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +493 -38
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +22 -9
- 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 +117 -39
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +229 -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 -4
- 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 +32 -56
- 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 +37 -14
- package/dist/heart/identity.js +168 -57
- 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 +197 -0
- package/dist/heart/mailbox/readers/agent-machine.js +418 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +319 -0
- package/dist/heart/mailbox/readers/mail.js +375 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +756 -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 +692 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/orientation-frame.js +217 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +272 -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-readiness-cache.js +40 -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 +23 -11
- 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 +13 -4
- package/dist/heart/session-activity.js +48 -24
- package/dist/heart/session-events.js +1163 -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 +133 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/structured-output.js +196 -0
- 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 +143 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +389 -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-9-AxCxuB.js +61 -0
- package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -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 +715 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +788 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +568 -0
- package/dist/mailroom/mbox-import.js +393 -0
- package/dist/mailroom/migration.js +164 -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 +334 -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 +14 -1
- package/dist/mind/context.js +251 -101
- package/dist/mind/desk-section.js +310 -0
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +68 -76
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +39 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +48 -4
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +162 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +6 -1
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1075 -146
- 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/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 +16 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +1040 -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 +331 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +166 -10
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +219 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +178 -0
- package/dist/repertoire/desk/classifier.js +362 -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 +385 -0
- package/dist/repertoire/mcp-client.js +295 -0
- package/dist/repertoire/mcp-manager.js +403 -0
- package/dist/repertoire/mcp-tools.js +83 -0
- package/dist/repertoire/plugin-mcp.js +175 -0
- package/dist/repertoire/plugins.js +253 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +48 -4
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-awaiting.js +372 -0
- package/dist/repertoire/tools-base.js +59 -1082
- package/dist/repertoire/tools-bluebubbles.js +2 -0
- package/dist/repertoire/tools-bridge.js +144 -0
- package/dist/repertoire/tools-bundle.js +993 -0
- package/dist/repertoire/tools-config.js +186 -0
- package/dist/repertoire/tools-continuity.js +252 -0
- package/dist/repertoire/tools-credential.js +383 -0
- package/dist/repertoire/tools-evolution.js +527 -0
- package/dist/repertoire/tools-files.js +344 -0
- package/dist/repertoire/tools-flight.js +227 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +3 -8
- package/dist/repertoire/tools-mail.js +1975 -0
- package/dist/repertoire/tools-notes.js +438 -0
- package/dist/repertoire/tools-obligations.js +143 -0
- package/dist/repertoire/tools-orientation.js +31 -0
- package/dist/repertoire/tools-record.js +464 -0
- package/dist/repertoire/tools-runtime.js +150 -0
- package/dist/repertoire/tools-session.js +766 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +182 -0
- package/dist/repertoire/tools-surface.js +344 -0
- package/dist/repertoire/tools-teams.js +12 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +982 -0
- package/dist/repertoire/tools-user-profile.js +146 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools-voice.js +145 -0
- package/dist/repertoire/tools.js +215 -103
- 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 +594 -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 +186 -0
- package/dist/senses/await-turn-message.js +58 -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 +2737 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
- 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/bluebubbles-meta-guard.js +40 -0
- 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 +100 -0
- package/dist/senses/cli.js +517 -204
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +254 -22
- package/dist/senses/inner-dialog.js +505 -40
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +666 -181
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +393 -0
- package/dist/senses/surface-tool.js +108 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +388 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/senses/voice/audio-playback.js +237 -0
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +202 -0
- package/dist/senses/voice/floor-control.js +431 -0
- package/dist/senses/voice/floor-controller.js +115 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +29 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/outbound.js +190 -0
- package/dist/senses/voice/phone.js +33 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/realtime-eval.js +496 -0
- package/dist/senses/voice/realtime-trace.js +531 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +191 -0
- package/dist/senses/voice/twilio-phone-runtime.js +807 -0
- package/dist/senses/voice/twilio-phone.js +5079 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +81 -0
- package/dist/senses/voice-realtime-eval-command.js +99 -0
- package/dist/senses/voice-realtime-eval-entry.js +21 -0
- package/dist/senses/voice-twilio-entry.js +87 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +265 -0
- package/dist/util/frontmatter.js +53 -0
- package/package.json +48 -8
- 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 +99 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/auth-flow.js +0 -351
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/safe-workspace.js +0 -228
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/repertoire/tasks/board.js +0 -134
- package/dist/repertoire/tasks/index.js +0 -224
- package/dist/repertoire/tasks/lifecycle.js +0 -80
- package/dist/repertoire/tasks/middleware.js +0 -65
- package/dist/repertoire/tasks/parser.js +0 -173
- package/dist/repertoire/tasks/scanner.js +0 -132
- package/dist/repertoire/tasks/transitions.js +0 -144
- 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 -7
- /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/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +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,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Commerce self-test — per-service health checks for the agent's
|
|
4
|
+
* commerce infrastructure (Stripe, Duffel, LiteAPI).
|
|
5
|
+
*
|
|
6
|
+
* Used by the setup wizard to verify configuration and provide
|
|
7
|
+
* actionable error messages when services are misconfigured.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.commerceSelfTest = commerceSelfTest;
|
|
11
|
+
const stripe_client_1 = require("./stripe-client");
|
|
12
|
+
const duffel_client_1 = require("./duffel-client");
|
|
13
|
+
const credential_access_1 = require("./credential-access");
|
|
14
|
+
const runtime_1 = require("../nerves/runtime");
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Per-service tests
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
async function testStripe() {
|
|
19
|
+
try {
|
|
20
|
+
const client = await (0, stripe_client_1.createStripeClient)();
|
|
21
|
+
// Create a test card and immediately deactivate it
|
|
22
|
+
const card = await client.createVirtualCard({
|
|
23
|
+
type: "single_use",
|
|
24
|
+
spendLimit: 1,
|
|
25
|
+
currency: "usd",
|
|
26
|
+
});
|
|
27
|
+
await client.deactivateCard(card.cardId);
|
|
28
|
+
return { status: "ok", message: "Stripe Issuing working. Test card created and deactivated." };
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
/* v8 ignore next -- reason @preserve */
|
|
32
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
33
|
+
if (reason.includes("no credential found") || reason.includes("restrictedKey")) {
|
|
34
|
+
return {
|
|
35
|
+
status: "error",
|
|
36
|
+
message: `Stripe key missing. Add your restricted key at https://dashboard.stripe.com/apikeys and store it in the vault as stripe.com/restrictedKey.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (reason.includes("401") || reason.includes("Invalid API Key")) {
|
|
40
|
+
return {
|
|
41
|
+
status: "error",
|
|
42
|
+
message: `Stripe key returned 401. Verify it at https://dashboard.stripe.com/apikeys.`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status: "error",
|
|
47
|
+
message: `Stripe error: ${reason}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function testDuffel() {
|
|
52
|
+
try {
|
|
53
|
+
const client = await (0, duffel_client_1.createDuffelClient)();
|
|
54
|
+
await client.searchFlights({
|
|
55
|
+
origin: "SFO",
|
|
56
|
+
destination: "JFK",
|
|
57
|
+
departureDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
|
|
58
|
+
passengers: [{ type: "adult" }],
|
|
59
|
+
});
|
|
60
|
+
return { status: "ok", message: "Duffel Flights working. Test search completed." };
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
/* v8 ignore next -- reason @preserve */
|
|
64
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
65
|
+
if (reason.includes("no credential found") || reason.includes("apiKey")) {
|
|
66
|
+
return {
|
|
67
|
+
status: "error",
|
|
68
|
+
message: `Duffel key missing. Add your API key from https://app.duffel.com/tokens and store it in the vault as duffel.com/apiKey.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (reason.includes("401") || reason.includes("Unauthorized")) {
|
|
72
|
+
return {
|
|
73
|
+
status: "error",
|
|
74
|
+
message: `Your Duffel key returned 401. Verify it at https://app.duffel.com/tokens.`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
status: "error",
|
|
79
|
+
message: `Duffel error: ${reason}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function testLiteApi() {
|
|
84
|
+
try {
|
|
85
|
+
const store = (0, credential_access_1.getCredentialStore)();
|
|
86
|
+
await store.getRawSecret("liteapi.travel", "apiKey");
|
|
87
|
+
// If we can retrieve the key, the config is present.
|
|
88
|
+
// LiteAPI is accessed via MCP, so we can't do a direct API call here.
|
|
89
|
+
// The actual health check happens when the MCP server starts.
|
|
90
|
+
return { status: "ok", message: "LiteAPI key found in vault. MCP server will use vault:liteapi.travel/apiKey." };
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
/* v8 ignore next -- reason @preserve */
|
|
94
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
95
|
+
if (reason.includes("no credential found")) {
|
|
96
|
+
return {
|
|
97
|
+
status: "error",
|
|
98
|
+
message: `LiteAPI key missing. Get your API key from https://dashboard.liteapi.travel and store it in the vault as liteapi.travel/apiKey.`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
status: "error",
|
|
103
|
+
message: `LiteAPI error: ${reason}`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Main self-test
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
async function commerceSelfTest() {
|
|
111
|
+
(0, runtime_1.emitNervesEvent)({
|
|
112
|
+
component: "repertoire",
|
|
113
|
+
event: "repertoire.commerce_self_test_start",
|
|
114
|
+
message: "starting commerce self-test",
|
|
115
|
+
meta: {},
|
|
116
|
+
});
|
|
117
|
+
const [stripe, duffel, liteapi] = await Promise.all([
|
|
118
|
+
testStripe(),
|
|
119
|
+
testDuffel(),
|
|
120
|
+
testLiteApi(),
|
|
121
|
+
]);
|
|
122
|
+
const services = { stripe, duffel, liteapi };
|
|
123
|
+
const okCount = Object.values(services).filter((s) => s.status === "ok").length;
|
|
124
|
+
const total = Object.keys(services).length;
|
|
125
|
+
let overall;
|
|
126
|
+
if (okCount === total) {
|
|
127
|
+
overall = "healthy";
|
|
128
|
+
}
|
|
129
|
+
else if (okCount > 0) {
|
|
130
|
+
overall = "partial";
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
overall = "unhealthy";
|
|
134
|
+
}
|
|
135
|
+
const lines = [];
|
|
136
|
+
if (stripe.status === "ok")
|
|
137
|
+
lines.push("Stripe: working");
|
|
138
|
+
else
|
|
139
|
+
lines.push(`Stripe: ${stripe.message}`);
|
|
140
|
+
if (duffel.status === "ok")
|
|
141
|
+
lines.push("Duffel: working");
|
|
142
|
+
else
|
|
143
|
+
lines.push(`Duffel: ${duffel.message}`);
|
|
144
|
+
if (liteapi.status === "ok")
|
|
145
|
+
lines.push("LiteAPI: working");
|
|
146
|
+
else
|
|
147
|
+
lines.push(`LiteAPI: ${liteapi.message}`);
|
|
148
|
+
const summary = `Commerce health: ${okCount}/${total} services ok.\n${lines.join("\n")}`;
|
|
149
|
+
(0, runtime_1.emitNervesEvent)({
|
|
150
|
+
component: "repertoire",
|
|
151
|
+
event: "repertoire.commerce_self_test_end",
|
|
152
|
+
message: "commerce self-test complete",
|
|
153
|
+
meta: { overall, okCount, total },
|
|
154
|
+
});
|
|
155
|
+
return { overall, services, summary };
|
|
156
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Credential access layer.
|
|
4
|
+
*
|
|
5
|
+
* Bitwarden/Vaultwarden is the sole runtime credential store. The only local
|
|
6
|
+
* secret is the vault unlock material held by an explicit local unlock store.
|
|
7
|
+
*
|
|
8
|
+
* Each agent owns one credential vault. getCredentialStore() returns that
|
|
9
|
+
* agent's vault directly; item names are not shared or namespaced across
|
|
10
|
+
* agents.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.getCredentialStore = getCredentialStore;
|
|
47
|
+
exports.probeCredentialVaultAccess = probeCredentialVaultAccess;
|
|
48
|
+
exports.resetCredentialStore = resetCredentialStore;
|
|
49
|
+
const crypto = __importStar(require("node:crypto"));
|
|
50
|
+
const fs = __importStar(require("node:fs"));
|
|
51
|
+
const os = __importStar(require("node:os"));
|
|
52
|
+
const path = __importStar(require("node:path"));
|
|
53
|
+
const runtime_1 = require("../nerves/runtime");
|
|
54
|
+
const identity = __importStar(require("../heart/identity"));
|
|
55
|
+
const bitwarden_store_1 = require("./bitwarden-store");
|
|
56
|
+
const vault_unlock_1 = require("./vault-unlock");
|
|
57
|
+
let stores = new Map();
|
|
58
|
+
function loadVaultSectionForAgent(agentName) {
|
|
59
|
+
const configPath = path.join(identity.getAgentRoot(agentName), "agent.json");
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
62
|
+
return { configPath, vault: parsed.vault };
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { configPath };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function bitwardenAppDataDir(agentName, vaultConfig, homeDir = os.homedir()) {
|
|
69
|
+
const digest = crypto
|
|
70
|
+
.createHash("sha256")
|
|
71
|
+
.update(`${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`)
|
|
72
|
+
.digest("hex")
|
|
73
|
+
.slice(0, 24);
|
|
74
|
+
return path.join(homeDir, ".ouro-cli", "bitwarden", digest);
|
|
75
|
+
}
|
|
76
|
+
function getCredentialStore(agentNameInput) {
|
|
77
|
+
const agentName = agentNameInput ?? identity.getAgentName();
|
|
78
|
+
if (agentName === "SerpentGuide") {
|
|
79
|
+
throw new Error("SerpentGuide does not have a persistent credential vault; hatch bootstrap uses provider credentials in memory only.");
|
|
80
|
+
}
|
|
81
|
+
const { configPath, vault } = loadVaultSectionForAgent(agentName);
|
|
82
|
+
if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
|
|
83
|
+
throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
|
|
84
|
+
}
|
|
85
|
+
const vaultConfig = identity.resolveVaultConfig(agentName, vault);
|
|
86
|
+
const cacheKey = `${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`;
|
|
87
|
+
const cached = stores.get(cacheKey);
|
|
88
|
+
if (cached)
|
|
89
|
+
return cached;
|
|
90
|
+
const unlock = (0, vault_unlock_1.readVaultUnlockSecret)({
|
|
91
|
+
agentName,
|
|
92
|
+
email: vaultConfig.email,
|
|
93
|
+
serverUrl: vaultConfig.serverUrl,
|
|
94
|
+
});
|
|
95
|
+
const unlockConfig = { agentName, email: vaultConfig.email, serverUrl: vaultConfig.serverUrl };
|
|
96
|
+
const unlockSource = unlock.source ?? unlockConfig;
|
|
97
|
+
let invalidUnlockCleared = false;
|
|
98
|
+
let canonicalUnlockStored = false;
|
|
99
|
+
const store = new bitwarden_store_1.BitwardenCredentialStore(vaultConfig.serverUrl, vaultConfig.email, unlock.secret, {
|
|
100
|
+
appDataDir: bitwardenAppDataDir(agentName, vaultConfig),
|
|
101
|
+
onInvalidUnlockSecret: (error) => {
|
|
102
|
+
if (invalidUnlockCleared)
|
|
103
|
+
return;
|
|
104
|
+
invalidUnlockCleared = true;
|
|
105
|
+
(0, vault_unlock_1.clearVaultUnlockSecret)({
|
|
106
|
+
agentName,
|
|
107
|
+
email: unlockSource.email,
|
|
108
|
+
serverUrl: unlockSource.serverUrl,
|
|
109
|
+
});
|
|
110
|
+
stores.delete(cacheKey);
|
|
111
|
+
(0, runtime_1.emitNervesEvent)({
|
|
112
|
+
level: "warn",
|
|
113
|
+
event: "repertoire.credential_store_invalid_unlock_cleared",
|
|
114
|
+
component: "repertoire",
|
|
115
|
+
message: "cleared rejected local vault unlock material",
|
|
116
|
+
meta: {
|
|
117
|
+
agentName,
|
|
118
|
+
serverUrl: vaultConfig.serverUrl,
|
|
119
|
+
email: vaultConfig.email,
|
|
120
|
+
sourceServerUrl: unlockSource.serverUrl,
|
|
121
|
+
error: error.message,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
onLoginSuccess: () => {
|
|
126
|
+
if (canonicalUnlockStored)
|
|
127
|
+
return;
|
|
128
|
+
if (unlockSource.serverUrl === vaultConfig.serverUrl && unlockSource.email === vaultConfig.email)
|
|
129
|
+
return;
|
|
130
|
+
canonicalUnlockStored = true;
|
|
131
|
+
try {
|
|
132
|
+
(0, vault_unlock_1.storeVaultUnlockSecret)(unlockConfig, unlock.secret);
|
|
133
|
+
(0, vault_unlock_1.noteVaultUnlockSelfHeal)(unlockConfig, unlock.store.kind, unlockSource.serverUrl);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
(0, runtime_1.emitNervesEvent)({
|
|
137
|
+
level: "warn",
|
|
138
|
+
event: "repertoire.vault_unlock_self_heal_failed",
|
|
139
|
+
component: "repertoire",
|
|
140
|
+
message: "failed to rewrite local unlock material using canonical vault coordinates",
|
|
141
|
+
meta: {
|
|
142
|
+
store: unlock.store.kind,
|
|
143
|
+
email: vaultConfig.email,
|
|
144
|
+
sourceServerUrl: unlockSource.serverUrl,
|
|
145
|
+
targetServerUrl: vaultConfig.serverUrl,
|
|
146
|
+
error: error instanceof Error ? error.message : String(error),
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
stores.set(cacheKey, store);
|
|
153
|
+
(0, runtime_1.emitNervesEvent)({
|
|
154
|
+
event: "repertoire.credential_store_init",
|
|
155
|
+
component: "repertoire",
|
|
156
|
+
message: "credential store initialized",
|
|
157
|
+
meta: {
|
|
158
|
+
backend: "bitwarden",
|
|
159
|
+
agentName,
|
|
160
|
+
serverUrl: vaultConfig.serverUrl,
|
|
161
|
+
email: vaultConfig.email,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
return store;
|
|
165
|
+
}
|
|
166
|
+
async function probeCredentialVaultAccess(agentNameInput, unlockSecret, options = {}) {
|
|
167
|
+
const agentName = agentNameInput;
|
|
168
|
+
const { configPath, vault } = loadVaultSectionForAgent(agentName);
|
|
169
|
+
if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
|
|
170
|
+
throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
|
|
171
|
+
}
|
|
172
|
+
const vaultConfig = identity.resolveVaultConfig(agentName, vault);
|
|
173
|
+
const store = new bitwarden_store_1.BitwardenCredentialStore(vaultConfig.serverUrl, vaultConfig.email, unlockSecret, { appDataDir: bitwardenAppDataDir(agentName, vaultConfig, options.homeDir) });
|
|
174
|
+
await store.get("__ouro_vault_probe__");
|
|
175
|
+
}
|
|
176
|
+
function resetCredentialStore() {
|
|
177
|
+
stores = new Map();
|
|
178
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared classifier for legacy `tasks/` → `desk/` migration.
|
|
4
|
+
*
|
|
5
|
+
* Pure data + parsing. Takes a file path relative to `<bundle>/tasks/` plus
|
|
6
|
+
* its content, returns a classification bucket. Used by `migrate-to-desk.ts`
|
|
7
|
+
* to decide where each file lands in the new `desk/` shape.
|
|
8
|
+
*
|
|
9
|
+
* Bucket definitions:
|
|
10
|
+
* - **terminal** — explicit done/complete/approved/cancelled/fixed status (or
|
|
11
|
+
* synonyms). Always archived. Files under `tasks/archive/` are unconditionally
|
|
12
|
+
* terminal regardless of frontmatter.
|
|
13
|
+
* - **stale_live** — live-looking status (`in-progress`, `ready_for_execution`,
|
|
14
|
+
* `drafting`, `collaborating`, etc.) but the resolved `updated` date is
|
|
15
|
+
* older than the 30-day cutoff. → archive (when-in-doubt rule).
|
|
16
|
+
* - **ambiguous** — no status, junk format, unknown status, `.md.bak` backup,
|
|
17
|
+
* or empty file. → archive.
|
|
18
|
+
* - **live_clear** — live status AND updated within the last 30 days AND
|
|
19
|
+
* coherent. → migrate to `legacy` track on the new desk.
|
|
20
|
+
* - **special_europe_trip** — historical one-off `ongoing/2026-03-09-1410-summer-2026-europe-trip.md` from the initial bundle that authored this migrator; kept as a labelled special case until the bundle is deprecated.
|
|
21
|
+
*
|
|
22
|
+
* Effective `updated` resolution priority: YAML `updated` → `approved` →
|
|
23
|
+
* `created` → body `**Updated**:` → date prefix in filename → file mtime.
|
|
24
|
+
*
|
|
25
|
+
* This is a pure-data helper: no side effects, no nerves observability of
|
|
26
|
+
* its own. The migrator emits nerves events around classify() calls.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.resolveUpdatedMs = resolveUpdatedMs;
|
|
30
|
+
exports.classifyFile = classifyFile;
|
|
31
|
+
exports.deriveTaskSlug = deriveTaskSlug;
|
|
32
|
+
exports.extractParentTaskDir = extractParentTaskDir;
|
|
33
|
+
const frontmatter_1 = require("../../util/frontmatter");
|
|
34
|
+
// ── Status vocabulary ──
|
|
35
|
+
const TERMINAL_STATUSES = new Set([
|
|
36
|
+
"done",
|
|
37
|
+
"complete",
|
|
38
|
+
"completed",
|
|
39
|
+
"approved",
|
|
40
|
+
"cancelled",
|
|
41
|
+
"canceled",
|
|
42
|
+
"fixed",
|
|
43
|
+
"merged",
|
|
44
|
+
"merged_and_published",
|
|
45
|
+
"abandoned",
|
|
46
|
+
"rejected",
|
|
47
|
+
"closed",
|
|
48
|
+
"shipped",
|
|
49
|
+
"resolved",
|
|
50
|
+
"archived",
|
|
51
|
+
"obsolete",
|
|
52
|
+
"deprecated",
|
|
53
|
+
"superseded",
|
|
54
|
+
"converted",
|
|
55
|
+
"discarded",
|
|
56
|
+
"won't-do",
|
|
57
|
+
"wontfix",
|
|
58
|
+
"won't-fix",
|
|
59
|
+
]);
|
|
60
|
+
const LIVE_STATUSES = new Set([
|
|
61
|
+
"drafting",
|
|
62
|
+
"in-progress",
|
|
63
|
+
"in_progress",
|
|
64
|
+
"inprogress",
|
|
65
|
+
"ready_for_execution",
|
|
66
|
+
"ready-for-execution",
|
|
67
|
+
"collaborating",
|
|
68
|
+
"processing",
|
|
69
|
+
"validating",
|
|
70
|
+
"blocked",
|
|
71
|
+
"paused",
|
|
72
|
+
"open",
|
|
73
|
+
"needs_review",
|
|
74
|
+
"needs-review",
|
|
75
|
+
"handoff_needs_work_planner",
|
|
76
|
+
"running",
|
|
77
|
+
"active",
|
|
78
|
+
"reopened",
|
|
79
|
+
"handed-off",
|
|
80
|
+
"local_verified",
|
|
81
|
+
"ongoing",
|
|
82
|
+
]);
|
|
83
|
+
// ── Helpers ──
|
|
84
|
+
function isMarkdownFile(relPath) {
|
|
85
|
+
return relPath.endsWith(".md");
|
|
86
|
+
}
|
|
87
|
+
function isBackupFile(relPath) {
|
|
88
|
+
return relPath.endsWith(".md.bak") || relPath.endsWith("~") || relPath.endsWith(".swp");
|
|
89
|
+
}
|
|
90
|
+
function isInArchiveSubdir(relPath) {
|
|
91
|
+
return relPath.startsWith("archive/") || relPath.includes("/archive/");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Detect the historical europe-trip task. Per the lift plan:
|
|
95
|
+
* `ongoing/2026-03-09-1410-summer-2026-europe-trip.md` is the only
|
|
96
|
+
* special-cased file.
|
|
97
|
+
*/
|
|
98
|
+
function isEuropeTripTask(relPath) {
|
|
99
|
+
return relPath === "ongoing/2026-03-09-1410-summer-2026-europe-trip.md";
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Extract the frontmatter block (between `---` fences) from a markdown file.
|
|
103
|
+
* Returns the raw frontmatter text or undefined if no fenced block exists.
|
|
104
|
+
*/
|
|
105
|
+
function extractFrontmatterBlock(content) {
|
|
106
|
+
const trimmed = content.trimStart();
|
|
107
|
+
if (!trimmed.startsWith("---"))
|
|
108
|
+
return undefined;
|
|
109
|
+
const afterFirstFence = trimmed.slice(3);
|
|
110
|
+
const closeIdx = afterFirstFence.indexOf("\n---");
|
|
111
|
+
if (closeIdx === -1)
|
|
112
|
+
return undefined;
|
|
113
|
+
return afterFirstFence.slice(0, closeIdx).replace(/^\r?\n/, "");
|
|
114
|
+
}
|
|
115
|
+
function readStatusFromFrontmatter(fm) {
|
|
116
|
+
const candidates = ["status", "Status", "STATUS", "state", "State"];
|
|
117
|
+
for (const key of candidates) {
|
|
118
|
+
const value = fm[key];
|
|
119
|
+
if (typeof value === "string" && value.trim()) {
|
|
120
|
+
return value.trim().toLowerCase();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
function readDateFromFrontmatter(fm, key) {
|
|
126
|
+
const value = fm[key];
|
|
127
|
+
if (typeof value !== "string")
|
|
128
|
+
return undefined;
|
|
129
|
+
const parsed = parseDateString(value);
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Parse a date string into epoch ms. Accepts YYYY-MM-DD and full ISO 8601
|
|
134
|
+
* timestamps. Returns undefined for unparseable input.
|
|
135
|
+
*/
|
|
136
|
+
function parseDateString(raw) {
|
|
137
|
+
const trimmed = raw.trim();
|
|
138
|
+
/* v8 ignore start -- defensive: callers (readDateFromFrontmatter, extractUpdatedFromBody) only pass values that have already been confirmed non-empty (frontmatter scalar or regex-captured digits). The empty-string fallback is unreachable in practice. @preserve */
|
|
139
|
+
if (!trimmed)
|
|
140
|
+
return undefined;
|
|
141
|
+
/* v8 ignore stop */
|
|
142
|
+
// YYYY-MM-DD or YYYY-MM-DD HH:MM or full ISO
|
|
143
|
+
const dateOnlyMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
|
|
144
|
+
if (dateOnlyMatch) {
|
|
145
|
+
const ms = Date.UTC(Number(dateOnlyMatch[1]), Number(dateOnlyMatch[2]) - 1, Number(dateOnlyMatch[3]));
|
|
146
|
+
/* v8 ignore start -- Date.UTC normalizes out-of-range numeric inputs to finite ms; the regex already guarantees four+two+two-digit ints. The undefined branch is genuinely unreachable. @preserve */
|
|
147
|
+
return Number.isFinite(ms) ? ms : undefined;
|
|
148
|
+
/* v8 ignore stop */
|
|
149
|
+
}
|
|
150
|
+
const ms = Date.parse(trimmed);
|
|
151
|
+
/* v8 ignore start -- v8 coverage tooling intermittently fails to register the NaN→undefined branch even when tests demonstrably exercise it (see "garbage123" / "not-a-date-at-all-12345xyz67890" tests in migrate-to-desk.test.ts). The behavior is correct; the coverage signal is the noise. @preserve */
|
|
152
|
+
if (!Number.isFinite(ms))
|
|
153
|
+
return undefined;
|
|
154
|
+
/* v8 ignore stop */
|
|
155
|
+
return ms;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Extract date prefix from a filename like `2026-05-12-1122-doing-foo.md`.
|
|
159
|
+
* Returns epoch ms or undefined.
|
|
160
|
+
*/
|
|
161
|
+
function extractDatePrefixFromFilename(relPath) {
|
|
162
|
+
/* v8 ignore start -- defensive `?? relPath` fallback: String.split() always returns at least one element, so pop() never returns undefined on a non-empty input. The fallback exists only as a type guard for the strict no-implicit-any setting. @preserve */
|
|
163
|
+
const base = relPath.split("/").pop() ?? relPath;
|
|
164
|
+
/* v8 ignore stop */
|
|
165
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})(?:-(\d{2})(\d{2}))?/.exec(base);
|
|
166
|
+
if (!match)
|
|
167
|
+
return undefined;
|
|
168
|
+
const ms = Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]), match[4] ? Number(match[4]) : 0, match[5] ? Number(match[5]) : 0);
|
|
169
|
+
/* v8 ignore start -- Date.UTC normalizes out-of-range numeric inputs to finite ms; the regex already guarantees four+two+two-digit ints. The undefined branch is genuinely unreachable. @preserve */
|
|
170
|
+
return Number.isFinite(ms) ? ms : undefined;
|
|
171
|
+
/* v8 ignore stop */
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Extract `**Updated**: YYYY-MM-DD` from body prose (some legacy task formats
|
|
175
|
+
* use this convention instead of YAML frontmatter).
|
|
176
|
+
*/
|
|
177
|
+
function extractUpdatedFromBody(content) {
|
|
178
|
+
const match = /\*\*Updated\*\*:\s*([0-9]{4}-[0-9]{2}-[0-9]{2}[A-Za-z0-9:_\- .]*)/.exec(content);
|
|
179
|
+
if (!match)
|
|
180
|
+
return undefined;
|
|
181
|
+
return parseDateString(match[1]);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Resolve the effective `updated` timestamp using the priority chain.
|
|
185
|
+
* Priority: YAML `updated` → `approved` → `created` → body `**Updated**:` →
|
|
186
|
+
* date prefix in filename → file mtime.
|
|
187
|
+
*/
|
|
188
|
+
function resolveUpdatedMs(input) {
|
|
189
|
+
const fmBlock = extractFrontmatterBlock(input.content);
|
|
190
|
+
if (fmBlock) {
|
|
191
|
+
const fm = (0, frontmatter_1.parseFrontmatter)(fmBlock);
|
|
192
|
+
const updated = readDateFromFrontmatter(fm, "updated") ?? readDateFromFrontmatter(fm, "Updated");
|
|
193
|
+
if (updated !== undefined)
|
|
194
|
+
return updated;
|
|
195
|
+
const approved = readDateFromFrontmatter(fm, "approved") ?? readDateFromFrontmatter(fm, "Approved");
|
|
196
|
+
if (approved !== undefined)
|
|
197
|
+
return approved;
|
|
198
|
+
const created = readDateFromFrontmatter(fm, "created") ?? readDateFromFrontmatter(fm, "Created");
|
|
199
|
+
if (created !== undefined)
|
|
200
|
+
return created;
|
|
201
|
+
}
|
|
202
|
+
const bodyUpdated = extractUpdatedFromBody(input.content);
|
|
203
|
+
if (bodyUpdated !== undefined)
|
|
204
|
+
return bodyUpdated;
|
|
205
|
+
const filenameDate = extractDatePrefixFromFilename(input.relPath);
|
|
206
|
+
if (filenameDate !== undefined)
|
|
207
|
+
return filenameDate;
|
|
208
|
+
return input.mtimeMs;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Classify a status string into a coarse category. `terminal` overrides
|
|
212
|
+
* everything. `live` is the explicit live set. `unknown` is anything else.
|
|
213
|
+
*/
|
|
214
|
+
function classifyStatus(status) {
|
|
215
|
+
if (!status)
|
|
216
|
+
return "missing";
|
|
217
|
+
const normalized = status.trim().toLowerCase();
|
|
218
|
+
// Some statuses are free-text sentences (e.g. "core line approved, companion proof line in discussion").
|
|
219
|
+
// Match terminal keywords if they appear as the leading word.
|
|
220
|
+
const head = normalized.split(/[\s,;:]+/)[0];
|
|
221
|
+
if (TERMINAL_STATUSES.has(head) || TERMINAL_STATUSES.has(normalized))
|
|
222
|
+
return "terminal";
|
|
223
|
+
if (LIVE_STATUSES.has(head) || LIVE_STATUSES.has(normalized))
|
|
224
|
+
return "live";
|
|
225
|
+
return "unknown";
|
|
226
|
+
}
|
|
227
|
+
// ── Public classifier ──
|
|
228
|
+
/**
|
|
229
|
+
* Classify a single file. Pairing/grouping is handled by the migrator at a
|
|
230
|
+
* higher level — this function is purely per-file.
|
|
231
|
+
*/
|
|
232
|
+
function classifyFile(input) {
|
|
233
|
+
// Europe-trip override comes first.
|
|
234
|
+
if (isEuropeTripTask(input.relPath)) {
|
|
235
|
+
return {
|
|
236
|
+
bucket: "special_europe_trip",
|
|
237
|
+
updatedMs: resolveUpdatedMs(input),
|
|
238
|
+
status: undefined,
|
|
239
|
+
reason: "operator-flagged europe-trip task",
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// Backup files and `archive/` subdir are unconditionally archived.
|
|
243
|
+
if (isBackupFile(input.relPath)) {
|
|
244
|
+
return {
|
|
245
|
+
bucket: "ambiguous",
|
|
246
|
+
updatedMs: resolveUpdatedMs(input),
|
|
247
|
+
status: undefined,
|
|
248
|
+
reason: "backup or swap file",
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
if (isInArchiveSubdir(input.relPath)) {
|
|
252
|
+
return {
|
|
253
|
+
bucket: "terminal",
|
|
254
|
+
updatedMs: resolveUpdatedMs(input),
|
|
255
|
+
status: undefined,
|
|
256
|
+
reason: "under archive/ subdir",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// Empty file → ambiguous.
|
|
260
|
+
if (input.content.trim().length === 0) {
|
|
261
|
+
return {
|
|
262
|
+
bucket: "ambiguous",
|
|
263
|
+
updatedMs: input.mtimeMs,
|
|
264
|
+
status: undefined,
|
|
265
|
+
reason: "empty file",
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Non-markdown files inherit from their parent task dir (handled at the
|
|
269
|
+
// migrator level via the pairing rule). Classifier defaults to ambiguous
|
|
270
|
+
// for non-md singletons.
|
|
271
|
+
if (!isMarkdownFile(input.relPath)) {
|
|
272
|
+
return {
|
|
273
|
+
bucket: "ambiguous",
|
|
274
|
+
updatedMs: resolveUpdatedMs(input),
|
|
275
|
+
status: undefined,
|
|
276
|
+
reason: "non-markdown file (will inherit from parent if grouped)",
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
const fmBlock = extractFrontmatterBlock(input.content);
|
|
280
|
+
const fm = fmBlock ? (0, frontmatter_1.parseFrontmatter)(fmBlock) : {};
|
|
281
|
+
const status = readStatusFromFrontmatter(fm);
|
|
282
|
+
const category = classifyStatus(status);
|
|
283
|
+
const updatedMs = resolveUpdatedMs(input);
|
|
284
|
+
if (category === "terminal") {
|
|
285
|
+
return {
|
|
286
|
+
bucket: "terminal",
|
|
287
|
+
updatedMs,
|
|
288
|
+
status,
|
|
289
|
+
reason: `terminal status: ${status}`,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
if (category === "missing" || category === "unknown") {
|
|
293
|
+
return {
|
|
294
|
+
bucket: "ambiguous",
|
|
295
|
+
updatedMs,
|
|
296
|
+
status,
|
|
297
|
+
reason: status ? `unknown status: ${status}` : "no status",
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
// category === "live"
|
|
301
|
+
if (updatedMs < input.cutoffMs) {
|
|
302
|
+
return {
|
|
303
|
+
bucket: "stale_live",
|
|
304
|
+
updatedMs,
|
|
305
|
+
status,
|
|
306
|
+
reason: `live status (${status}) but updated >30d ago`,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
bucket: "live_clear",
|
|
311
|
+
updatedMs,
|
|
312
|
+
status,
|
|
313
|
+
reason: `live status (${status}) within 30d`,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
// ── Pairing rules ──
|
|
317
|
+
/**
|
|
318
|
+
* Derive a task slug from a filename. Strips the `YYYY-MM-DD-HHMM-` (or
|
|
319
|
+
* `YYYY-MM-DD-`) prefix and the `planning-` / `doing-` / `ideation-` /
|
|
320
|
+
* `audit-` / `audit-report-` / `audit-backlog-` infix. Returns the remaining
|
|
321
|
+
* stem (without `.md`).
|
|
322
|
+
*
|
|
323
|
+
* Examples:
|
|
324
|
+
* `2026-05-10-doing-foo.md` → `foo`
|
|
325
|
+
* `2026-05-12-1122-doing-rest-loop-incident.md` → `rest-loop-incident`
|
|
326
|
+
* `2026-05-12-1122-planning-rest-loop-incident.md` → `rest-loop-incident`
|
|
327
|
+
* `one-shots/2026-04-29-0942-planning-substrate-trip-control-deploy.md`
|
|
328
|
+
* → `substrate-trip-control-deploy`
|
|
329
|
+
*/
|
|
330
|
+
function deriveTaskSlug(relPath) {
|
|
331
|
+
/* v8 ignore start -- defensive `?? relPath` fallback: String.split() always returns at least one element, so pop() never returns undefined. The fallback exists as a type guard. @preserve */
|
|
332
|
+
const base = relPath.split("/").pop() ?? relPath;
|
|
333
|
+
/* v8 ignore stop */
|
|
334
|
+
const stem = base.replace(/\.md$/, "");
|
|
335
|
+
// Strip YYYY-MM-DD[-HHMM]- prefix
|
|
336
|
+
let remainder = stem.replace(/^\d{4}-\d{2}-\d{2}(?:-\d{4})?-/, "");
|
|
337
|
+
// Strip role infix: planning, doing, ideation, audit, audit-report, audit-backlog
|
|
338
|
+
remainder = remainder.replace(/^(planning|doing|ideation|audit-report|audit-backlog|audit)-/, "");
|
|
339
|
+
return remainder;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Extract the parent task directory for a sub-artifact path. Returns
|
|
343
|
+
* undefined for top-level files.
|
|
344
|
+
*
|
|
345
|
+
* Examples:
|
|
346
|
+
* `one-shots/2026-05-10-doing-foo/baseline.md` → `one-shots/2026-05-10-doing-foo`
|
|
347
|
+
* `one-shots/2026-05-10-doing-foo.md` → undefined
|
|
348
|
+
*/
|
|
349
|
+
function extractParentTaskDir(relPath) {
|
|
350
|
+
const segments = relPath.split("/");
|
|
351
|
+
if (segments.length < 2)
|
|
352
|
+
return undefined;
|
|
353
|
+
// Walk segments — if any intermediate segment looks like a task-dir name
|
|
354
|
+
// (matches the `YYYY-MM-DD[-HHMM]-(planning|doing|ideation|audit*)-` pattern),
|
|
355
|
+
// return everything up to and including it. Otherwise no parent.
|
|
356
|
+
for (let i = segments.length - 2; i >= 0; i -= 1) {
|
|
357
|
+
if (/^\d{4}-\d{2}-\d{2}(?:-\d{4})?-(planning|doing|ideation|audit-report|audit-backlog|audit)-/.test(segments[i])) {
|
|
358
|
+
return segments.slice(0, i + 1).join("/");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|