@ouro.bot/cli 0.1.0-alpha.40 → 0.1.0-alpha.400
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 +109 -14
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +2455 -6
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +417 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +101 -128
- package/dist/heart/core.js +801 -217
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +397 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +213 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +599 -0
- package/dist/heart/daemon/cli-exec.js +3616 -0
- package/dist/heart/daemon/cli-help.js +396 -0
- package/dist/heart/daemon/cli-parse.js +1118 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +560 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +28 -1582
- package/dist/heart/daemon/daemon-entry.js +356 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +684 -58
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +419 -0
- package/dist/heart/daemon/health-monitor.js +79 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +209 -0
- package/dist/heart/daemon/launchd.js +46 -9
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +201 -0
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +216 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +73 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +119 -30
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +237 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +135 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +53 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +33 -12
- package/dist/heart/identity.js +161 -65
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +28 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +195 -0
- package/dist/heart/outlook/readers/agent-machine.js +359 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/runtime-readers.js +660 -0
- package/dist/heart/outlook/readers/sessions.js +232 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-attempt.js +133 -0
- package/dist/heart/provider-binding-resolver.js +239 -0
- package/dist/heart/provider-credentials.js +383 -0
- package/dist/heart/provider-failover.js +266 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +237 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +186 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +193 -55
- package/dist/heart/providers/azure.js +103 -12
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +29 -7
- package/dist/heart/providers/openai-codex.js +39 -29
- package/dist/heart/runtime-credentials.js +181 -0
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +855 -0
- package/dist/heart/session-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +351 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +301 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +134 -87
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +14 -1
- package/dist/mind/friends/channel.js +21 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +38 -1
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +1 -1
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +66 -7
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +946 -167
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +83 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-BAcU08c-.css +1 -0
- package/dist/outlook-ui/assets/index-D7l3l4vY.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +461 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +107 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +371 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +26 -1
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +42 -687
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +182 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +739 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +144 -113
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +118 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +382 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +260 -9
- package/dist/senses/bluebubbles/entry.js +70 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1620 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +45 -3
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +526 -211
- package/dist/senses/commands.js +66 -3
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +600 -95
- package/dist/senses/pipeline.js +539 -61
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +205 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +569 -237
- package/dist/senses/trust-gate.js +5 -5
- package/package.json +28 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +110 -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 +134 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/mind/associative-recall.js +0 -197
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -832
- package/dist/senses/debug-activity.js +0 -127
- package/subagents/README.md +0 -60
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -39,6 +39,7 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const identity_1 = require("../identity");
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
41
|
const parser_1 = require("../../repertoire/tasks/parser");
|
|
42
|
+
const cadence_1 = require("./cadence");
|
|
42
43
|
function walkMarkdownFiles(root, readdirSync, existsSync, files) {
|
|
43
44
|
if (!existsSync(root))
|
|
44
45
|
return;
|
|
@@ -53,29 +54,6 @@ function walkMarkdownFiles(root, readdirSync, existsSync, files) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
function parseCadence(raw) {
|
|
57
|
-
if (typeof raw !== "string")
|
|
58
|
-
return null;
|
|
59
|
-
const value = raw.trim();
|
|
60
|
-
if (!value)
|
|
61
|
-
return null;
|
|
62
|
-
// Cron format (minute hour day month weekday)
|
|
63
|
-
if (/^\S+\s+\S+\s+\S+\s+\S+\s+\S+$/.test(value)) {
|
|
64
|
-
return value;
|
|
65
|
-
}
|
|
66
|
-
const cadenceMatch = /^(\d+)(m|h|d)$/.exec(value);
|
|
67
|
-
if (!cadenceMatch)
|
|
68
|
-
return null;
|
|
69
|
-
const interval = Number.parseInt(cadenceMatch[1], 10);
|
|
70
|
-
if (!Number.isFinite(interval) || interval <= 0)
|
|
71
|
-
return null;
|
|
72
|
-
const unit = cadenceMatch[2];
|
|
73
|
-
if (unit === "m")
|
|
74
|
-
return `*/${interval} * * * *`;
|
|
75
|
-
if (unit === "h")
|
|
76
|
-
return `0 */${interval} * * *`;
|
|
77
|
-
return `0 0 */${interval} * *`;
|
|
78
|
-
}
|
|
79
57
|
function parseScheduledAt(raw) {
|
|
80
58
|
if (typeof raw !== "string")
|
|
81
59
|
return null;
|
|
@@ -140,7 +118,7 @@ class TaskDrivenScheduler {
|
|
|
140
118
|
const nextTaskPaths = new Map();
|
|
141
119
|
for (const agent of this.agents) {
|
|
142
120
|
const taskRoot = path.join(this.bundlesRoot, `${agent}.ouro`, "tasks");
|
|
143
|
-
const collections = ["one-shots", "ongoing"
|
|
121
|
+
const collections = ["one-shots", "ongoing"];
|
|
144
122
|
const files = [];
|
|
145
123
|
for (const collection of collections) {
|
|
146
124
|
walkMarkdownFiles(path.join(taskRoot, collection), this.readdirSync, this.existsSync, files);
|
|
@@ -157,7 +135,7 @@ class TaskDrivenScheduler {
|
|
|
157
135
|
nextTaskPaths.set(`${agent}:${taskId}`, filePath);
|
|
158
136
|
if (task.status === "done")
|
|
159
137
|
continue;
|
|
160
|
-
const cadence =
|
|
138
|
+
const cadence = (0, cadence_1.parseCadenceToCron)(task.frontmatter.cadence);
|
|
161
139
|
if (cadence) {
|
|
162
140
|
const id = `${agent}:${taskId}:cadence`;
|
|
163
141
|
nextJobs.set(id, {
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Formats inner dialog session turns for human consumption.
|
|
3
|
+
// Used by `ouro thoughts` CLI command to show what the agent has been thinking.
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.formatSurfacedValue = formatSurfacedValue;
|
|
39
|
+
exports.deriveInnerDialogStatus = deriveInnerDialogStatus;
|
|
40
|
+
exports.deriveInnerJob = deriveInnerJob;
|
|
41
|
+
exports.formatInnerDialogStatus = formatInnerDialogStatus;
|
|
42
|
+
exports.extractThoughtResponseFromMessages = extractThoughtResponseFromMessages;
|
|
43
|
+
exports.parseInnerDialogSession = parseInnerDialogSession;
|
|
44
|
+
exports.formatThoughtTurns = formatThoughtTurns;
|
|
45
|
+
exports.getInnerDialogSessionPath = getInnerDialogSessionPath;
|
|
46
|
+
exports.readInnerDialogStatus = readInnerDialogStatus;
|
|
47
|
+
exports.readInnerDialogRawData = readInnerDialogRawData;
|
|
48
|
+
exports.followThoughts = followThoughts;
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
52
|
+
function contentToText(content) {
|
|
53
|
+
if (typeof content === "string")
|
|
54
|
+
return content;
|
|
55
|
+
if (!Array.isArray(content))
|
|
56
|
+
return "";
|
|
57
|
+
return content
|
|
58
|
+
.map((part) => {
|
|
59
|
+
if (typeof part === "string")
|
|
60
|
+
return part;
|
|
61
|
+
if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
|
|
62
|
+
return part.text;
|
|
63
|
+
}
|
|
64
|
+
return "";
|
|
65
|
+
})
|
|
66
|
+
.join("\n");
|
|
67
|
+
}
|
|
68
|
+
function extractToolFunction(toolCall) {
|
|
69
|
+
if (!toolCall || typeof toolCall !== "object" || !("function" in toolCall))
|
|
70
|
+
return null;
|
|
71
|
+
const maybeFunction = toolCall.function;
|
|
72
|
+
if (!maybeFunction || typeof maybeFunction !== "object")
|
|
73
|
+
return null;
|
|
74
|
+
const name = "name" in maybeFunction && typeof maybeFunction.name === "string"
|
|
75
|
+
? maybeFunction.name
|
|
76
|
+
: undefined;
|
|
77
|
+
const argumentsValue = "arguments" in maybeFunction && typeof maybeFunction.arguments === "string"
|
|
78
|
+
? maybeFunction.arguments
|
|
79
|
+
: undefined;
|
|
80
|
+
return { name, arguments: argumentsValue };
|
|
81
|
+
}
|
|
82
|
+
function classifyTurn(userText) {
|
|
83
|
+
if (userText.includes("waking up."))
|
|
84
|
+
return { type: "boot" };
|
|
85
|
+
const taskMatch = /## task: (.+)$/m.exec(userText);
|
|
86
|
+
if (taskMatch)
|
|
87
|
+
return { type: "task", taskId: taskMatch[1] };
|
|
88
|
+
return { type: "heartbeat" };
|
|
89
|
+
}
|
|
90
|
+
function extractToolNames(messages) {
|
|
91
|
+
const names = [];
|
|
92
|
+
for (const msg of messages) {
|
|
93
|
+
if (msg.role === "assistant" && Array.isArray(msg.tool_calls)) {
|
|
94
|
+
for (const tc of msg.tool_calls) {
|
|
95
|
+
const toolFunction = extractToolFunction(tc);
|
|
96
|
+
if (toolFunction?.name && toolFunction.name !== "settle")
|
|
97
|
+
names.push(toolFunction.name);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return names;
|
|
102
|
+
}
|
|
103
|
+
function extractPendingPromptMessages(prompt) {
|
|
104
|
+
return prompt
|
|
105
|
+
.split("\n")
|
|
106
|
+
.map((line) => line.trim())
|
|
107
|
+
.filter((line) => line.startsWith("[pending from "))
|
|
108
|
+
.map((line) => {
|
|
109
|
+
const separator = line.indexOf("]: ");
|
|
110
|
+
return separator >= 0 ? line.slice(separator + 3).trim() : "";
|
|
111
|
+
})
|
|
112
|
+
.filter((line) => line.length > 0);
|
|
113
|
+
}
|
|
114
|
+
function readPendingMessagesForStatus(pendingDir) {
|
|
115
|
+
if (!fs.existsSync(pendingDir))
|
|
116
|
+
return [];
|
|
117
|
+
let entries;
|
|
118
|
+
try {
|
|
119
|
+
entries = fs.readdirSync(pendingDir);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
const files = [
|
|
125
|
+
...entries.filter((entry) => entry.endsWith(".json.processing")),
|
|
126
|
+
...entries.filter((entry) => entry.endsWith(".json") && !entry.endsWith(".json.processing")),
|
|
127
|
+
].sort((a, b) => a.localeCompare(b));
|
|
128
|
+
const messages = [];
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
try {
|
|
131
|
+
const raw = fs.readFileSync(path.join(pendingDir, file), "utf-8");
|
|
132
|
+
const parsed = JSON.parse(raw);
|
|
133
|
+
if (typeof parsed.content === "string") {
|
|
134
|
+
messages.push(parsed);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// unreadable pending files should not break status queries
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return messages;
|
|
142
|
+
}
|
|
143
|
+
function formatSurfacedValue(text, maxLength = 120) {
|
|
144
|
+
const firstLine = text
|
|
145
|
+
.split("\n")
|
|
146
|
+
.map((line) => line.trim())
|
|
147
|
+
.find((line) => line.length > 0);
|
|
148
|
+
if (!firstLine)
|
|
149
|
+
return "no outward result";
|
|
150
|
+
if (firstLine.length <= maxLength)
|
|
151
|
+
return `"${firstLine}"`;
|
|
152
|
+
return `"${firstLine.slice(0, maxLength - 3)}..."`;
|
|
153
|
+
}
|
|
154
|
+
function extractEnrichedFields(pendingMessages) {
|
|
155
|
+
const delegated = pendingMessages.find((msg) => msg.delegatedFrom);
|
|
156
|
+
if (!delegated?.delegatedFrom)
|
|
157
|
+
return {};
|
|
158
|
+
const snippet = delegated.content.length > 80 ? delegated.content.slice(0, 77) + "..." : delegated.content;
|
|
159
|
+
return {
|
|
160
|
+
origin: {
|
|
161
|
+
friendId: delegated.delegatedFrom.friendId,
|
|
162
|
+
channel: delegated.delegatedFrom.channel,
|
|
163
|
+
key: delegated.delegatedFrom.key,
|
|
164
|
+
},
|
|
165
|
+
contentSnippet: snippet,
|
|
166
|
+
...(delegated.obligationStatus === "pending" ? { obligationPending: true } : {}),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function deriveInnerDialogStatus(pendingMessages, turns, runtimeState) {
|
|
170
|
+
if (runtimeState?.status === "running") {
|
|
171
|
+
if (pendingMessages.length > 0) {
|
|
172
|
+
return {
|
|
173
|
+
queue: "queued to inner/dialog",
|
|
174
|
+
wake: "queued behind active turn",
|
|
175
|
+
processing: "pending",
|
|
176
|
+
surfaced: "nothing yet",
|
|
177
|
+
...extractEnrichedFields(pendingMessages),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
queue: "clear",
|
|
182
|
+
wake: "in progress",
|
|
183
|
+
processing: "started",
|
|
184
|
+
surfaced: "nothing yet",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (pendingMessages.length > 0) {
|
|
188
|
+
return {
|
|
189
|
+
queue: "queued to inner/dialog",
|
|
190
|
+
wake: "awaiting inner session",
|
|
191
|
+
processing: "pending",
|
|
192
|
+
surfaced: "nothing yet",
|
|
193
|
+
...extractEnrichedFields(pendingMessages),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const latestProcessedPendingTurn = [...turns]
|
|
197
|
+
.reverse()
|
|
198
|
+
.find((turn) => extractPendingPromptMessages(turn.prompt).length > 0);
|
|
199
|
+
if (!latestProcessedPendingTurn) {
|
|
200
|
+
return {
|
|
201
|
+
queue: "clear",
|
|
202
|
+
wake: "idle",
|
|
203
|
+
processing: "idle",
|
|
204
|
+
surfaced: "nothing recent",
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
queue: "clear",
|
|
209
|
+
wake: "completed",
|
|
210
|
+
processing: "processed",
|
|
211
|
+
surfaced: formatSurfacedValue(latestProcessedPendingTurn.response),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function deriveInnerJob(pendingMessages, turns, runtimeState) {
|
|
215
|
+
const isRunning = runtimeState?.status === "running";
|
|
216
|
+
const delegated = pendingMessages.find((msg) => msg.delegatedFrom);
|
|
217
|
+
const enriched = extractEnrichedFields(pendingMessages);
|
|
218
|
+
const pendingMode = delegated && "mode" in delegated && delegated.mode ? delegated.mode : "reflect";
|
|
219
|
+
const origin = enriched.origin ?? null;
|
|
220
|
+
const content = delegated?.content ?? null;
|
|
221
|
+
const obligationStatus = delegated?.obligationStatus ?? null;
|
|
222
|
+
const queuedAt = delegated?.timestamp ?? null;
|
|
223
|
+
if (isRunning) {
|
|
224
|
+
(0, runtime_1.emitNervesEvent)({
|
|
225
|
+
component: "engine",
|
|
226
|
+
event: "engine.inner_job_derive",
|
|
227
|
+
message: "derived inner job state",
|
|
228
|
+
meta: { status: "running", mode: pendingMode, hasOrigin: origin !== null, hasObligation: obligationStatus !== null },
|
|
229
|
+
});
|
|
230
|
+
return {
|
|
231
|
+
status: "running",
|
|
232
|
+
content,
|
|
233
|
+
origin,
|
|
234
|
+
mode: pendingMode,
|
|
235
|
+
obligationStatus,
|
|
236
|
+
surfacedResult: null,
|
|
237
|
+
queuedAt,
|
|
238
|
+
startedAt: runtimeState?.startedAt ?? null,
|
|
239
|
+
surfacedAt: null,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (pendingMessages.length > 0) {
|
|
243
|
+
(0, runtime_1.emitNervesEvent)({
|
|
244
|
+
component: "engine",
|
|
245
|
+
event: "engine.inner_job_derive",
|
|
246
|
+
message: "derived inner job state",
|
|
247
|
+
meta: { status: "queued", mode: pendingMode, hasOrigin: origin !== null, hasObligation: obligationStatus !== null },
|
|
248
|
+
});
|
|
249
|
+
return {
|
|
250
|
+
status: "queued",
|
|
251
|
+
content,
|
|
252
|
+
origin,
|
|
253
|
+
mode: pendingMode,
|
|
254
|
+
obligationStatus,
|
|
255
|
+
surfacedResult: null,
|
|
256
|
+
queuedAt,
|
|
257
|
+
startedAt: null,
|
|
258
|
+
surfacedAt: null,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// No pending, not running -- check for surfaced result
|
|
262
|
+
const latestProcessedPendingTurn = [...turns]
|
|
263
|
+
.reverse()
|
|
264
|
+
.find((turn) => extractPendingPromptMessages(turn.prompt).length > 0);
|
|
265
|
+
if (latestProcessedPendingTurn) {
|
|
266
|
+
const surfacedResult = extractThoughtResponseFromMessages([
|
|
267
|
+
{ role: "assistant", content: latestProcessedPendingTurn.response },
|
|
268
|
+
]);
|
|
269
|
+
(0, runtime_1.emitNervesEvent)({
|
|
270
|
+
component: "engine",
|
|
271
|
+
event: "engine.inner_job_derive",
|
|
272
|
+
message: "derived inner job state",
|
|
273
|
+
meta: { status: "surfaced", mode: "reflect", hasOrigin: false, hasObligation: false },
|
|
274
|
+
});
|
|
275
|
+
return {
|
|
276
|
+
status: "surfaced",
|
|
277
|
+
content: null,
|
|
278
|
+
origin: null,
|
|
279
|
+
mode: "reflect",
|
|
280
|
+
obligationStatus: null,
|
|
281
|
+
/* v8 ignore next -- defensive: surfacedResult fallback @preserve */
|
|
282
|
+
surfacedResult: surfacedResult || null,
|
|
283
|
+
queuedAt: null,
|
|
284
|
+
startedAt: null,
|
|
285
|
+
surfacedAt: null,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
(0, runtime_1.emitNervesEvent)({
|
|
289
|
+
component: "engine",
|
|
290
|
+
event: "engine.inner_job_derive",
|
|
291
|
+
message: "derived inner job state",
|
|
292
|
+
meta: { status: "idle", mode: "reflect", hasOrigin: false, hasObligation: false },
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
status: "idle",
|
|
296
|
+
content: null,
|
|
297
|
+
origin: null,
|
|
298
|
+
mode: "reflect",
|
|
299
|
+
obligationStatus: null,
|
|
300
|
+
surfacedResult: null,
|
|
301
|
+
queuedAt: null,
|
|
302
|
+
startedAt: null,
|
|
303
|
+
surfacedAt: null,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function formatInnerDialogStatus(status) {
|
|
307
|
+
const lines = [
|
|
308
|
+
`queue: ${status.queue}`,
|
|
309
|
+
`wake: ${status.wake}`,
|
|
310
|
+
`processing: ${status.processing}`,
|
|
311
|
+
`surfaced: ${status.surfaced}`,
|
|
312
|
+
];
|
|
313
|
+
if (status.origin) {
|
|
314
|
+
lines.push(`origin: ${status.origin.friendId}/${status.origin.channel}/${status.origin.key}`);
|
|
315
|
+
}
|
|
316
|
+
if (status.contentSnippet) {
|
|
317
|
+
lines.push(`asked: ${status.contentSnippet}`);
|
|
318
|
+
}
|
|
319
|
+
if (status.obligationPending) {
|
|
320
|
+
lines.push("obligation: pending");
|
|
321
|
+
}
|
|
322
|
+
return lines.join("\n");
|
|
323
|
+
}
|
|
324
|
+
/** Extract text from a settle tool call's arguments. */
|
|
325
|
+
function extractSettleAnswer(messages) {
|
|
326
|
+
for (let k = messages.length - 1; k >= 0; k--) {
|
|
327
|
+
const msg = messages[k];
|
|
328
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls))
|
|
329
|
+
continue;
|
|
330
|
+
for (const tc of msg.tool_calls) {
|
|
331
|
+
const toolFunction = extractToolFunction(tc);
|
|
332
|
+
if (toolFunction?.name !== "settle")
|
|
333
|
+
continue;
|
|
334
|
+
try {
|
|
335
|
+
const parsed = JSON.parse(toolFunction.arguments ?? "{}");
|
|
336
|
+
if (typeof parsed.answer === "string" && parsed.answer.trim())
|
|
337
|
+
return parsed.answer.trim();
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// malformed arguments — skip
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return "";
|
|
345
|
+
}
|
|
346
|
+
function extractThoughtResponseFromMessages(messages) {
|
|
347
|
+
const assistantMsgs = messages.filter((message) => message.role === "assistant");
|
|
348
|
+
const lastAssistant = assistantMsgs.reverse().find((message) => contentToText(message.content).trim().length > 0);
|
|
349
|
+
return lastAssistant
|
|
350
|
+
? contentToText(lastAssistant.content).trim()
|
|
351
|
+
: extractSettleAnswer(messages);
|
|
352
|
+
}
|
|
353
|
+
function parseInnerDialogSession(sessionPath) {
|
|
354
|
+
(0, runtime_1.emitNervesEvent)({
|
|
355
|
+
component: "daemon",
|
|
356
|
+
event: "daemon.thoughts_parse",
|
|
357
|
+
message: "parsing inner dialog session",
|
|
358
|
+
meta: { sessionPath },
|
|
359
|
+
});
|
|
360
|
+
let raw;
|
|
361
|
+
try {
|
|
362
|
+
raw = fs.readFileSync(sessionPath, "utf-8");
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
let data;
|
|
368
|
+
try {
|
|
369
|
+
data = JSON.parse(raw);
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
if (data.version !== 1 || !Array.isArray(data.messages))
|
|
375
|
+
return [];
|
|
376
|
+
const turns = [];
|
|
377
|
+
const messages = data.messages;
|
|
378
|
+
// Walk messages, pairing user → (tool calls) → assistant sequences
|
|
379
|
+
let i = 0;
|
|
380
|
+
while (i < messages.length) {
|
|
381
|
+
const msg = messages[i];
|
|
382
|
+
if (msg.role === "system") {
|
|
383
|
+
i++;
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (msg.role !== "user") {
|
|
387
|
+
i++;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const userText = contentToText(msg.content);
|
|
391
|
+
const classification = classifyTurn(userText);
|
|
392
|
+
// Collect all messages until the next user message (or end)
|
|
393
|
+
const turnMessages = [];
|
|
394
|
+
let j = i + 1;
|
|
395
|
+
while (j < messages.length && messages[j].role !== "user") {
|
|
396
|
+
turnMessages.push(messages[j]);
|
|
397
|
+
j++;
|
|
398
|
+
}
|
|
399
|
+
// Find the last assistant text response in this turn.
|
|
400
|
+
// With tool_choice="required", the response may be inside a settle tool call.
|
|
401
|
+
const response = extractThoughtResponseFromMessages(turnMessages);
|
|
402
|
+
const tools = extractToolNames(turnMessages);
|
|
403
|
+
turns.push({
|
|
404
|
+
type: classification.type,
|
|
405
|
+
prompt: userText.trim(),
|
|
406
|
+
response,
|
|
407
|
+
tools,
|
|
408
|
+
...(classification.taskId ? { taskId: classification.taskId } : {}),
|
|
409
|
+
});
|
|
410
|
+
i = j;
|
|
411
|
+
}
|
|
412
|
+
return turns;
|
|
413
|
+
}
|
|
414
|
+
function formatThoughtTurns(turns, lastN) {
|
|
415
|
+
if (turns.length === 0)
|
|
416
|
+
return "no inner dialog activity";
|
|
417
|
+
const selected = lastN > 0 ? turns.slice(-lastN) : turns;
|
|
418
|
+
/* v8 ignore next -- unreachable: turns.length > 0 checked above, slice always returns ≥1 @preserve */
|
|
419
|
+
if (selected.length === 0)
|
|
420
|
+
return "no inner dialog activity";
|
|
421
|
+
const lines = [];
|
|
422
|
+
for (const turn of selected) {
|
|
423
|
+
const typeLabel = turn.type === "task" && turn.taskId
|
|
424
|
+
? `task: ${turn.taskId}`
|
|
425
|
+
: turn.type;
|
|
426
|
+
lines.push(`--- ${typeLabel} ---`);
|
|
427
|
+
if (turn.tools.length > 0) {
|
|
428
|
+
lines.push(`tools: ${turn.tools.join(", ")}`);
|
|
429
|
+
}
|
|
430
|
+
if (turn.response) {
|
|
431
|
+
lines.push(turn.response);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
lines.push("(no response)");
|
|
435
|
+
}
|
|
436
|
+
lines.push("");
|
|
437
|
+
}
|
|
438
|
+
return lines.join("\n").trim();
|
|
439
|
+
}
|
|
440
|
+
function getInnerDialogSessionPath(agentRoot) {
|
|
441
|
+
return path.join(agentRoot, "state", "sessions", "self", "inner", "dialog.json");
|
|
442
|
+
}
|
|
443
|
+
function getInnerDialogRuntimeStatePath(sessionPath) {
|
|
444
|
+
return path.join(path.dirname(sessionPath), "runtime.json");
|
|
445
|
+
}
|
|
446
|
+
function readInnerDialogRuntimeState(runtimePath) {
|
|
447
|
+
try {
|
|
448
|
+
const raw = fs.readFileSync(runtimePath, "utf-8");
|
|
449
|
+
const parsed = JSON.parse(raw);
|
|
450
|
+
if (parsed.status !== "running" && parsed.status !== "idle")
|
|
451
|
+
return null;
|
|
452
|
+
return {
|
|
453
|
+
status: parsed.status,
|
|
454
|
+
reason: parsed.reason === "boot" || parsed.reason === "heartbeat" || parsed.reason === "instinct"
|
|
455
|
+
? parsed.reason
|
|
456
|
+
: undefined,
|
|
457
|
+
startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : undefined,
|
|
458
|
+
lastCompletedAt: typeof parsed.lastCompletedAt === "string" ? parsed.lastCompletedAt : undefined,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function readInnerDialogStatus(sessionPath, pendingDir, runtimePath = getInnerDialogRuntimeStatePath(sessionPath)) {
|
|
466
|
+
const pendingMessages = readPendingMessagesForStatus(pendingDir);
|
|
467
|
+
const turns = parseInnerDialogSession(sessionPath);
|
|
468
|
+
const runtimeState = readInnerDialogRuntimeState(runtimePath);
|
|
469
|
+
return deriveInnerDialogStatus(pendingMessages, turns, runtimeState);
|
|
470
|
+
}
|
|
471
|
+
function readInnerDialogRawData(sessionPath, pendingDir) {
|
|
472
|
+
const runtimePath = getInnerDialogRuntimeStatePath(sessionPath);
|
|
473
|
+
const pendingMessages = readPendingMessagesForStatus(pendingDir);
|
|
474
|
+
const turns = parseInnerDialogSession(sessionPath);
|
|
475
|
+
const runtimeState = readInnerDialogRuntimeState(runtimePath);
|
|
476
|
+
return { pendingMessages, turns, runtimeState };
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Watch a session file and emit new turns as they appear.
|
|
480
|
+
* Returns a cleanup function that stops the watcher.
|
|
481
|
+
*/
|
|
482
|
+
function followThoughts(sessionPath, onNewTurns, pollIntervalMs = 1000) {
|
|
483
|
+
let displayedCount = parseInnerDialogSession(sessionPath).length;
|
|
484
|
+
(0, runtime_1.emitNervesEvent)({
|
|
485
|
+
component: "daemon",
|
|
486
|
+
event: "daemon.thoughts_follow_start",
|
|
487
|
+
message: "started following inner dialog session",
|
|
488
|
+
meta: { sessionPath, initialTurns: displayedCount },
|
|
489
|
+
});
|
|
490
|
+
fs.watchFile(sessionPath, { interval: pollIntervalMs }, () => {
|
|
491
|
+
const turns = parseInnerDialogSession(sessionPath);
|
|
492
|
+
if (turns.length > displayedCount) {
|
|
493
|
+
const newTurns = turns.slice(displayedCount);
|
|
494
|
+
onNewTurns(formatThoughtTurns(newTurns, 0));
|
|
495
|
+
displayedCount = turns.length;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
return () => {
|
|
499
|
+
fs.unwatchFile(sessionPath);
|
|
500
|
+
// Must be named `_end` (not `_stop`) to satisfy the nerves audit's
|
|
501
|
+
// start/end pairing rule — see src/nerves/coverage/audit-rules.ts which
|
|
502
|
+
// pairs `<prefix>_start` with `<prefix>_end` or `<prefix>_error`.
|
|
503
|
+
(0, runtime_1.emitNervesEvent)({
|
|
504
|
+
component: "daemon",
|
|
505
|
+
event: "daemon.thoughts_follow_end",
|
|
506
|
+
message: "stopped following inner dialog session",
|
|
507
|
+
meta: { sessionPath, totalTurns: displayedCount },
|
|
508
|
+
});
|
|
509
|
+
};
|
|
510
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* UpProgress — accumulated-checklist progress renderer for `ouro up`.
|
|
4
|
+
*
|
|
5
|
+
* Displays completed phases with checkmarks, the current phase with a
|
|
6
|
+
* spinner and elapsed time, and pending phases as plain text. Uses ANSI
|
|
7
|
+
* cursor control for in-place overwriting in TTY mode, and falls back to
|
|
8
|
+
* static line-per-phase output in non-TTY mode.
|
|
9
|
+
*
|
|
10
|
+
* The caller drives animation by calling `render(now)` on a setInterval.
|
|
11
|
+
* This module owns no timers.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.UpProgress = void 0;
|
|
15
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
16
|
+
// ── ANSI constants (shared with startup-tui.ts pattern) ──
|
|
17
|
+
const SPINNER_FRAMES = "\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F";
|
|
18
|
+
const RESET = "\x1b[0m";
|
|
19
|
+
const BOLD = "\x1b[1m";
|
|
20
|
+
const DIM = "\x1b[2m";
|
|
21
|
+
const GREEN = "\x1b[38;2;46;204;64m";
|
|
22
|
+
// ── UpProgress class ──
|
|
23
|
+
class UpProgress {
|
|
24
|
+
write;
|
|
25
|
+
isTTY;
|
|
26
|
+
completed = [];
|
|
27
|
+
currentPhase = null;
|
|
28
|
+
prevLineCount = 0;
|
|
29
|
+
ended = false;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
/* v8 ignore next -- thin wrapper: raw process.stdout.write for ANSI cursor control @preserve */
|
|
32
|
+
this.write = options?.write ?? ((text) => process.stdout.write(text));
|
|
33
|
+
/* v8 ignore next -- thin wrapper: real isTTY check injected for testability @preserve */
|
|
34
|
+
this.isTTY = options?.isTTY ?? (process.stdout.isTTY === true);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Begin a new phase with spinner. If a phase is already active, it is
|
|
38
|
+
* auto-completed (no detail text).
|
|
39
|
+
*/
|
|
40
|
+
startPhase(label) {
|
|
41
|
+
if (this.currentPhase) {
|
|
42
|
+
this.completePhase(this.currentPhase.label);
|
|
43
|
+
}
|
|
44
|
+
this.currentPhase = { label, startedAt: Date.now() };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Emit a one-line status breadcrumb in non-TTY mode without affecting the
|
|
48
|
+
* accumulated checklist state. Used for daemon startup sub-steps.
|
|
49
|
+
*/
|
|
50
|
+
announceStep(label) {
|
|
51
|
+
if (this.isTTY)
|
|
52
|
+
return;
|
|
53
|
+
this.write(label);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Mark the current phase as done. In non-TTY mode, immediately writes
|
|
57
|
+
* a static line. Emits a nerves event for observability.
|
|
58
|
+
*/
|
|
59
|
+
completePhase(label, detail) {
|
|
60
|
+
if (!this.currentPhase) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const elapsedMs = Date.now() - this.currentPhase.startedAt;
|
|
64
|
+
this.completed.push({ label, detail });
|
|
65
|
+
this.currentPhase = null;
|
|
66
|
+
(0, runtime_1.emitNervesEvent)({
|
|
67
|
+
component: "daemon",
|
|
68
|
+
event: "daemon.up_phase_complete",
|
|
69
|
+
message: `phase complete: ${label}`,
|
|
70
|
+
meta: { phase: label, detail: detail ?? null, elapsedMs },
|
|
71
|
+
});
|
|
72
|
+
if (!this.isTTY) {
|
|
73
|
+
const detailStr = detail ? ` \u2014 ${detail}` : "";
|
|
74
|
+
this.write(` \u2713 ${label}${detailStr}\n`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build an ANSI string for in-place terminal display. Returns empty
|
|
79
|
+
* string in non-TTY mode (output is written eagerly in completePhase).
|
|
80
|
+
*/
|
|
81
|
+
render(now) {
|
|
82
|
+
if (!this.isTTY) {
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
85
|
+
const lines = [];
|
|
86
|
+
// Completed phases
|
|
87
|
+
for (const phase of this.completed) {
|
|
88
|
+
const detailStr = phase.detail ? ` ${DIM}\u2014 ${phase.detail}${RESET}` : "";
|
|
89
|
+
lines.push(` ${GREEN}\u2713${RESET} ${phase.label}${detailStr}`);
|
|
90
|
+
}
|
|
91
|
+
// Current phase with spinner
|
|
92
|
+
if (this.currentPhase) {
|
|
93
|
+
const elapsed = now - this.currentPhase.startedAt;
|
|
94
|
+
const elapsedSec = (elapsed / 1000).toFixed(1);
|
|
95
|
+
const frameIndex = Math.floor(elapsed / 80) % SPINNER_FRAMES.length;
|
|
96
|
+
const spinner = SPINNER_FRAMES[frameIndex];
|
|
97
|
+
lines.push(` ${BOLD}${spinner}${RESET} ${this.currentPhase.label} ${DIM}(${elapsedSec}s)${RESET}`);
|
|
98
|
+
}
|
|
99
|
+
let output = "";
|
|
100
|
+
if (this.prevLineCount > 0) {
|
|
101
|
+
output += `\x1b[${this.prevLineCount}A`;
|
|
102
|
+
}
|
|
103
|
+
for (const line of lines) {
|
|
104
|
+
output += `\x1b[2K${line}\n`;
|
|
105
|
+
}
|
|
106
|
+
// Clear any leftover lines from previous render that are no longer needed
|
|
107
|
+
if (lines.length < this.prevLineCount) {
|
|
108
|
+
for (let i = 0; i < this.prevLineCount - lines.length; i++) {
|
|
109
|
+
output += `\x1b[2K\n`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.prevLineCount = lines.length;
|
|
113
|
+
return output;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Finalize the progress display. Clears the current phase (if any) and
|
|
117
|
+
* writes the final checklist state. Idempotent.
|
|
118
|
+
*/
|
|
119
|
+
end() {
|
|
120
|
+
if (this.ended) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.ended = true;
|
|
124
|
+
if (this.currentPhase) {
|
|
125
|
+
this.currentPhase = null;
|
|
126
|
+
}
|
|
127
|
+
if (this.isTTY) {
|
|
128
|
+
const output = this.render(Date.now());
|
|
129
|
+
if (output) {
|
|
130
|
+
this.write(output);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.UpProgress = UpProgress;
|