@ouro.bot/cli 0.1.0-alpha.6 → 0.1.0-alpha.61

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.
Files changed (119) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +70 -9
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +147 -205
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +334 -0
  7. package/dist/heart/active-work.js +178 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/config.js +57 -23
  12. package/dist/heart/core.js +236 -90
  13. package/dist/heart/cross-chat-delivery.js +146 -0
  14. package/dist/heart/daemon/agent-discovery.js +81 -0
  15. package/dist/heart/daemon/auth-flow.js +351 -0
  16. package/dist/heart/daemon/daemon-cli.js +1175 -232
  17. package/dist/heart/daemon/daemon-entry.js +55 -6
  18. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  19. package/dist/heart/daemon/daemon.js +189 -10
  20. package/dist/heart/daemon/hatch-animation.js +10 -3
  21. package/dist/heart/daemon/hatch-flow.js +4 -82
  22. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  23. package/dist/heart/daemon/launchd.js +159 -0
  24. package/dist/heart/daemon/log-tailer.js +4 -3
  25. package/dist/heart/daemon/message-router.js +17 -8
  26. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  27. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  28. package/dist/heart/daemon/ouro-entry.js +0 -0
  29. package/dist/heart/daemon/ouro-path-installer.js +178 -0
  30. package/dist/heart/daemon/ouro-uti.js +11 -2
  31. package/dist/heart/daemon/process-manager.js +14 -1
  32. package/dist/heart/daemon/run-hooks.js +37 -0
  33. package/dist/heart/daemon/runtime-logging.js +58 -15
  34. package/dist/heart/daemon/runtime-metadata.js +219 -0
  35. package/dist/heart/daemon/runtime-mode.js +67 -0
  36. package/dist/heart/daemon/sense-manager.js +307 -0
  37. package/dist/heart/daemon/skill-management-installer.js +73 -0
  38. package/dist/heart/daemon/socket-client.js +202 -0
  39. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  40. package/dist/heart/daemon/specialist-prompt.js +64 -5
  41. package/dist/heart/daemon/specialist-tools.js +213 -58
  42. package/dist/heart/daemon/staged-restart.js +114 -0
  43. package/dist/heart/daemon/thoughts.js +379 -0
  44. package/dist/heart/daemon/update-checker.js +111 -0
  45. package/dist/heart/daemon/update-hooks.js +138 -0
  46. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  47. package/dist/heart/delegation.js +62 -0
  48. package/dist/heart/identity.js +122 -19
  49. package/dist/heart/kicks.js +1 -19
  50. package/dist/heart/model-capabilities.js +40 -0
  51. package/dist/heart/progress-story.js +42 -0
  52. package/dist/heart/providers/anthropic.js +74 -9
  53. package/dist/heart/providers/azure.js +86 -7
  54. package/dist/heart/providers/minimax.js +4 -0
  55. package/dist/heart/providers/openai-codex.js +12 -3
  56. package/dist/heart/safe-workspace.js +228 -0
  57. package/dist/heart/sense-truth.js +61 -0
  58. package/dist/heart/session-activity.js +169 -0
  59. package/dist/heart/session-recall.js +116 -0
  60. package/dist/heart/streaming.js +100 -22
  61. package/dist/heart/target-resolution.js +123 -0
  62. package/dist/heart/turn-coordinator.js +28 -0
  63. package/dist/mind/associative-recall.js +14 -2
  64. package/dist/mind/bundle-manifest.js +70 -0
  65. package/dist/mind/context.js +27 -11
  66. package/dist/mind/first-impressions.js +16 -2
  67. package/dist/mind/friends/channel.js +35 -0
  68. package/dist/mind/friends/group-context.js +144 -0
  69. package/dist/mind/friends/store-file.js +19 -0
  70. package/dist/mind/friends/trust-explanation.js +74 -0
  71. package/dist/mind/friends/types.js +8 -0
  72. package/dist/mind/memory.js +27 -26
  73. package/dist/mind/pending.js +72 -9
  74. package/dist/mind/phrases.js +1 -0
  75. package/dist/mind/prompt.js +299 -77
  76. package/dist/mind/token-estimate.js +8 -12
  77. package/dist/nerves/cli-logging.js +15 -2
  78. package/dist/nerves/coverage/run-artifacts.js +1 -1
  79. package/dist/repertoire/ado-client.js +4 -2
  80. package/dist/repertoire/coding/feedback.js +134 -0
  81. package/dist/repertoire/coding/index.js +4 -1
  82. package/dist/repertoire/coding/manager.js +62 -4
  83. package/dist/repertoire/coding/spawner.js +3 -3
  84. package/dist/repertoire/coding/tools.js +41 -2
  85. package/dist/repertoire/data/ado-endpoints.json +188 -0
  86. package/dist/repertoire/skills.js +3 -26
  87. package/dist/repertoire/tasks/board.js +12 -0
  88. package/dist/repertoire/tasks/index.js +23 -9
  89. package/dist/repertoire/tasks/transitions.js +1 -2
  90. package/dist/repertoire/tools-base.js +629 -251
  91. package/dist/repertoire/tools-bluebubbles.js +93 -0
  92. package/dist/repertoire/tools-teams.js +58 -25
  93. package/dist/repertoire/tools.js +92 -48
  94. package/dist/senses/bluebubbles-client.js +210 -5
  95. package/dist/senses/bluebubbles-entry.js +2 -0
  96. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  97. package/dist/senses/bluebubbles-media.js +339 -0
  98. package/dist/senses/bluebubbles-model.js +12 -4
  99. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  100. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  101. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  102. package/dist/senses/bluebubbles.js +890 -45
  103. package/dist/senses/cli-layout.js +87 -0
  104. package/dist/senses/cli.js +345 -144
  105. package/dist/senses/continuity.js +94 -0
  106. package/dist/senses/debug-activity.js +148 -0
  107. package/dist/senses/inner-dialog-worker.js +47 -18
  108. package/dist/senses/inner-dialog.js +330 -84
  109. package/dist/senses/pipeline.js +278 -0
  110. package/dist/senses/teams.js +570 -129
  111. package/dist/senses/trust-gate.js +112 -2
  112. package/package.json +14 -3
  113. package/subagents/README.md +4 -70
  114. package/dist/heart/daemon/specialist-session.js +0 -142
  115. package/dist/heart/daemon/subagent-installer.js +0 -125
  116. package/dist/inner-worker-entry.js +0 -4
  117. package/subagents/work-doer.md +0 -233
  118. package/subagents/work-merger.md +0 -624
  119. package/subagents/work-planner.md +0 -373
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.performStagedRestart = performStagedRestart;
37
+ const path = __importStar(require("path"));
38
+ const runtime_1 = require("../../nerves/runtime");
39
+ async function performStagedRestart(version, deps) {
40
+ (0, runtime_1.emitNervesEvent)({
41
+ component: "daemon",
42
+ event: "daemon.staged_restart_start",
43
+ message: "starting staged restart",
44
+ meta: { version },
45
+ });
46
+ // Step 1: Install new version
47
+ try {
48
+ deps.execSync(`npm install -g @ouro.bot/cli@${version}`);
49
+ }
50
+ catch (err) {
51
+ const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
52
+ (0, runtime_1.emitNervesEvent)({
53
+ component: "daemon",
54
+ event: "daemon.staged_restart_install_failed",
55
+ message: "npm install failed",
56
+ meta: { version, error: errorMessage },
57
+ });
58
+ return { ok: false, error: errorMessage };
59
+ }
60
+ // Step 2: Resolve new code path
61
+ const newCodePath = deps.resolveNewCodePath(version);
62
+ if (!newCodePath) {
63
+ (0, runtime_1.emitNervesEvent)({
64
+ component: "daemon",
65
+ event: "daemon.staged_restart_path_failed",
66
+ message: "could not resolve new code path",
67
+ meta: { version },
68
+ });
69
+ return { ok: false, error: "could not resolve new code path after install" };
70
+ }
71
+ // Step 3: Spawn hook runner on NEW code
72
+ const hookRunnerPath = path.join(newCodePath, "dist", "heart", "daemon", "run-hooks.js");
73
+ const spawnResult = deps.spawnSync(deps.nodePath, [hookRunnerPath, "--bundles-root", deps.bundlesRoot], { stdio: "inherit" });
74
+ if (spawnResult.error) {
75
+ const errorMessage = spawnResult.error.message;
76
+ (0, runtime_1.emitNervesEvent)({
77
+ component: "daemon",
78
+ event: "daemon.staged_restart_spawn_failed",
79
+ message: "hook runner spawn failed",
80
+ meta: { version, error: errorMessage },
81
+ });
82
+ return { ok: false, error: errorMessage };
83
+ }
84
+ if (spawnResult.status !== 0) {
85
+ (0, runtime_1.emitNervesEvent)({
86
+ component: "daemon",
87
+ event: "daemon.staged_restart_hooks_failed",
88
+ message: "hook runner exited with non-zero status",
89
+ meta: { version, exitCode: spawnResult.status },
90
+ });
91
+ return { ok: false, error: `hook runner exited with code ${spawnResult.status}` };
92
+ }
93
+ // Step 4: Graceful shutdown (launchd will restart with new code)
94
+ (0, runtime_1.emitNervesEvent)({
95
+ component: "daemon",
96
+ event: "daemon.staged_restart_hooks_passed",
97
+ message: "hooks passed, shutting down for restart",
98
+ meta: { version },
99
+ });
100
+ try {
101
+ await deps.gracefulShutdown();
102
+ }
103
+ catch (err) {
104
+ const shutdownError = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
105
+ (0, runtime_1.emitNervesEvent)({
106
+ component: "daemon",
107
+ event: "daemon.staged_restart_shutdown_error",
108
+ message: "graceful shutdown encountered error",
109
+ meta: { version, error: shutdownError },
110
+ });
111
+ return { ok: true, shutdownError };
112
+ }
113
+ return { ok: true };
114
+ }
@@ -0,0 +1,379 @@
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.formatInnerDialogStatus = formatInnerDialogStatus;
41
+ exports.extractThoughtResponseFromMessages = extractThoughtResponseFromMessages;
42
+ exports.parseInnerDialogSession = parseInnerDialogSession;
43
+ exports.formatThoughtTurns = formatThoughtTurns;
44
+ exports.getInnerDialogSessionPath = getInnerDialogSessionPath;
45
+ exports.readInnerDialogStatus = readInnerDialogStatus;
46
+ exports.followThoughts = followThoughts;
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const runtime_1 = require("../../nerves/runtime");
50
+ function contentToText(content) {
51
+ if (typeof content === "string")
52
+ return content;
53
+ if (!Array.isArray(content))
54
+ return "";
55
+ return content
56
+ .map((part) => {
57
+ if (typeof part === "string")
58
+ return part;
59
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
60
+ return part.text;
61
+ }
62
+ return "";
63
+ })
64
+ .join("\n");
65
+ }
66
+ function extractToolFunction(toolCall) {
67
+ if (!toolCall || typeof toolCall !== "object" || !("function" in toolCall))
68
+ return null;
69
+ const maybeFunction = toolCall.function;
70
+ if (!maybeFunction || typeof maybeFunction !== "object")
71
+ return null;
72
+ const name = "name" in maybeFunction && typeof maybeFunction.name === "string"
73
+ ? maybeFunction.name
74
+ : undefined;
75
+ const argumentsValue = "arguments" in maybeFunction && typeof maybeFunction.arguments === "string"
76
+ ? maybeFunction.arguments
77
+ : undefined;
78
+ return { name, arguments: argumentsValue };
79
+ }
80
+ function classifyTurn(userText) {
81
+ if (userText.includes("waking up."))
82
+ return { type: "boot" };
83
+ const taskMatch = /## task: (.+)$/m.exec(userText);
84
+ if (taskMatch)
85
+ return { type: "task", taskId: taskMatch[1] };
86
+ return { type: "heartbeat" };
87
+ }
88
+ function extractToolNames(messages) {
89
+ const names = [];
90
+ for (const msg of messages) {
91
+ if (msg.role === "assistant" && Array.isArray(msg.tool_calls)) {
92
+ for (const tc of msg.tool_calls) {
93
+ const toolFunction = extractToolFunction(tc);
94
+ if (toolFunction?.name && toolFunction.name !== "final_answer")
95
+ names.push(toolFunction.name);
96
+ }
97
+ }
98
+ }
99
+ return names;
100
+ }
101
+ function extractPendingPromptMessages(prompt) {
102
+ return prompt
103
+ .split("\n")
104
+ .map((line) => line.trim())
105
+ .filter((line) => line.startsWith("[pending from "))
106
+ .map((line) => {
107
+ const separator = line.indexOf("]: ");
108
+ return separator >= 0 ? line.slice(separator + 3).trim() : "";
109
+ })
110
+ .filter((line) => line.length > 0);
111
+ }
112
+ function readPendingMessagesForStatus(pendingDir) {
113
+ if (!fs.existsSync(pendingDir))
114
+ return [];
115
+ let entries;
116
+ try {
117
+ entries = fs.readdirSync(pendingDir);
118
+ }
119
+ catch {
120
+ return [];
121
+ }
122
+ const files = [
123
+ ...entries.filter((entry) => entry.endsWith(".json.processing")),
124
+ ...entries.filter((entry) => entry.endsWith(".json") && !entry.endsWith(".json.processing")),
125
+ ].sort((a, b) => a.localeCompare(b));
126
+ const messages = [];
127
+ for (const file of files) {
128
+ try {
129
+ const raw = fs.readFileSync(path.join(pendingDir, file), "utf-8");
130
+ const parsed = JSON.parse(raw);
131
+ if (typeof parsed.content === "string") {
132
+ messages.push(parsed);
133
+ }
134
+ }
135
+ catch {
136
+ // unreadable pending files should not break status queries
137
+ }
138
+ }
139
+ return messages;
140
+ }
141
+ function formatSurfacedValue(text, maxLength = 120) {
142
+ const firstLine = text
143
+ .split("\n")
144
+ .map((line) => line.trim())
145
+ .find((line) => line.length > 0);
146
+ if (!firstLine)
147
+ return "no outward result";
148
+ if (firstLine.length <= maxLength)
149
+ return `"${firstLine}"`;
150
+ return `"${firstLine.slice(0, maxLength - 3)}..."`;
151
+ }
152
+ function deriveInnerDialogStatus(pendingMessages, turns, runtimeState) {
153
+ if (runtimeState?.status === "running") {
154
+ if (pendingMessages.length > 0) {
155
+ return {
156
+ queue: "queued to inner/dialog",
157
+ wake: "queued behind active turn",
158
+ processing: "pending",
159
+ surfaced: "nothing yet",
160
+ };
161
+ }
162
+ return {
163
+ queue: "clear",
164
+ wake: "in progress",
165
+ processing: "started",
166
+ surfaced: "nothing yet",
167
+ };
168
+ }
169
+ if (pendingMessages.length > 0) {
170
+ return {
171
+ queue: "queued to inner/dialog",
172
+ wake: "awaiting inner session",
173
+ processing: "pending",
174
+ surfaced: "nothing yet",
175
+ };
176
+ }
177
+ const latestProcessedPendingTurn = [...turns]
178
+ .reverse()
179
+ .find((turn) => extractPendingPromptMessages(turn.prompt).length > 0);
180
+ if (!latestProcessedPendingTurn) {
181
+ return {
182
+ queue: "clear",
183
+ wake: "idle",
184
+ processing: "idle",
185
+ surfaced: "nothing recent",
186
+ };
187
+ }
188
+ return {
189
+ queue: "clear",
190
+ wake: "completed",
191
+ processing: "processed",
192
+ surfaced: formatSurfacedValue(latestProcessedPendingTurn.response),
193
+ };
194
+ }
195
+ function formatInnerDialogStatus(status) {
196
+ return [
197
+ `queue: ${status.queue}`,
198
+ `wake: ${status.wake}`,
199
+ `processing: ${status.processing}`,
200
+ `surfaced: ${status.surfaced}`,
201
+ ].join("\n");
202
+ }
203
+ /** Extract text from a final_answer tool call's arguments. */
204
+ function extractFinalAnswer(messages) {
205
+ for (let k = messages.length - 1; k >= 0; k--) {
206
+ const msg = messages[k];
207
+ if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls))
208
+ continue;
209
+ for (const tc of msg.tool_calls) {
210
+ const toolFunction = extractToolFunction(tc);
211
+ if (toolFunction?.name !== "final_answer")
212
+ continue;
213
+ try {
214
+ const parsed = JSON.parse(toolFunction.arguments ?? "{}");
215
+ if (typeof parsed.answer === "string" && parsed.answer.trim())
216
+ return parsed.answer.trim();
217
+ }
218
+ catch {
219
+ // malformed arguments — skip
220
+ }
221
+ }
222
+ }
223
+ return "";
224
+ }
225
+ function extractThoughtResponseFromMessages(messages) {
226
+ const assistantMsgs = messages.filter((message) => message.role === "assistant");
227
+ const lastAssistant = assistantMsgs.reverse().find((message) => contentToText(message.content).trim().length > 0);
228
+ return lastAssistant
229
+ ? contentToText(lastAssistant.content).trim()
230
+ : extractFinalAnswer(messages);
231
+ }
232
+ function parseInnerDialogSession(sessionPath) {
233
+ (0, runtime_1.emitNervesEvent)({
234
+ component: "daemon",
235
+ event: "daemon.thoughts_parse",
236
+ message: "parsing inner dialog session",
237
+ meta: { sessionPath },
238
+ });
239
+ let raw;
240
+ try {
241
+ raw = fs.readFileSync(sessionPath, "utf-8");
242
+ }
243
+ catch {
244
+ return [];
245
+ }
246
+ let data;
247
+ try {
248
+ data = JSON.parse(raw);
249
+ }
250
+ catch {
251
+ return [];
252
+ }
253
+ if (data.version !== 1 || !Array.isArray(data.messages))
254
+ return [];
255
+ const turns = [];
256
+ const messages = data.messages;
257
+ // Walk messages, pairing user → (tool calls) → assistant sequences
258
+ let i = 0;
259
+ while (i < messages.length) {
260
+ const msg = messages[i];
261
+ if (msg.role === "system") {
262
+ i++;
263
+ continue;
264
+ }
265
+ if (msg.role !== "user") {
266
+ i++;
267
+ continue;
268
+ }
269
+ const userText = contentToText(msg.content);
270
+ const classification = classifyTurn(userText);
271
+ // Collect all messages until the next user message (or end)
272
+ const turnMessages = [];
273
+ let j = i + 1;
274
+ while (j < messages.length && messages[j].role !== "user") {
275
+ turnMessages.push(messages[j]);
276
+ j++;
277
+ }
278
+ // Find the last assistant text response in this turn.
279
+ // With tool_choice="required", the response may be inside a final_answer tool call.
280
+ const response = extractThoughtResponseFromMessages(turnMessages);
281
+ const tools = extractToolNames(turnMessages);
282
+ turns.push({
283
+ type: classification.type,
284
+ prompt: userText.trim(),
285
+ response,
286
+ tools,
287
+ ...(classification.taskId ? { taskId: classification.taskId } : {}),
288
+ });
289
+ i = j;
290
+ }
291
+ return turns;
292
+ }
293
+ function formatThoughtTurns(turns, lastN) {
294
+ if (turns.length === 0)
295
+ return "no inner dialog activity";
296
+ const selected = lastN > 0 ? turns.slice(-lastN) : turns;
297
+ /* v8 ignore next -- unreachable: turns.length > 0 checked above, slice always returns ≥1 @preserve */
298
+ if (selected.length === 0)
299
+ return "no inner dialog activity";
300
+ const lines = [];
301
+ for (const turn of selected) {
302
+ const typeLabel = turn.type === "task" && turn.taskId
303
+ ? `task: ${turn.taskId}`
304
+ : turn.type;
305
+ lines.push(`--- ${typeLabel} ---`);
306
+ if (turn.tools.length > 0) {
307
+ lines.push(`tools: ${turn.tools.join(", ")}`);
308
+ }
309
+ if (turn.response) {
310
+ lines.push(turn.response);
311
+ }
312
+ else {
313
+ lines.push("(no response)");
314
+ }
315
+ lines.push("");
316
+ }
317
+ return lines.join("\n").trim();
318
+ }
319
+ function getInnerDialogSessionPath(agentRoot) {
320
+ return path.join(agentRoot, "state", "sessions", "self", "inner", "dialog.json");
321
+ }
322
+ function getInnerDialogRuntimeStatePath(sessionPath) {
323
+ return path.join(path.dirname(sessionPath), "runtime.json");
324
+ }
325
+ function readInnerDialogRuntimeState(runtimePath) {
326
+ try {
327
+ const raw = fs.readFileSync(runtimePath, "utf-8");
328
+ const parsed = JSON.parse(raw);
329
+ if (parsed.status !== "running" && parsed.status !== "idle")
330
+ return null;
331
+ return {
332
+ status: parsed.status,
333
+ reason: parsed.reason === "boot" || parsed.reason === "heartbeat" || parsed.reason === "instinct"
334
+ ? parsed.reason
335
+ : undefined,
336
+ startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : undefined,
337
+ lastCompletedAt: typeof parsed.lastCompletedAt === "string" ? parsed.lastCompletedAt : undefined,
338
+ };
339
+ }
340
+ catch {
341
+ return null;
342
+ }
343
+ }
344
+ function readInnerDialogStatus(sessionPath, pendingDir, runtimePath = getInnerDialogRuntimeStatePath(sessionPath)) {
345
+ const pendingMessages = readPendingMessagesForStatus(pendingDir);
346
+ const turns = parseInnerDialogSession(sessionPath);
347
+ const runtimeState = readInnerDialogRuntimeState(runtimePath);
348
+ return deriveInnerDialogStatus(pendingMessages, turns, runtimeState);
349
+ }
350
+ /**
351
+ * Watch a session file and emit new turns as they appear.
352
+ * Returns a cleanup function that stops the watcher.
353
+ */
354
+ function followThoughts(sessionPath, onNewTurns, pollIntervalMs = 1000) {
355
+ let displayedCount = parseInnerDialogSession(sessionPath).length;
356
+ (0, runtime_1.emitNervesEvent)({
357
+ component: "daemon",
358
+ event: "daemon.thoughts_follow_start",
359
+ message: "started following inner dialog session",
360
+ meta: { sessionPath, initialTurns: displayedCount },
361
+ });
362
+ fs.watchFile(sessionPath, { interval: pollIntervalMs }, () => {
363
+ const turns = parseInnerDialogSession(sessionPath);
364
+ if (turns.length > displayedCount) {
365
+ const newTurns = turns.slice(displayedCount);
366
+ onNewTurns(formatThoughtTurns(newTurns, 0));
367
+ displayedCount = turns.length;
368
+ }
369
+ });
370
+ return () => {
371
+ fs.unwatchFile(sessionPath);
372
+ (0, runtime_1.emitNervesEvent)({
373
+ component: "daemon",
374
+ event: "daemon.thoughts_follow_stop",
375
+ message: "stopped following inner dialog session",
376
+ meta: { sessionPath, totalTurns: displayedCount },
377
+ });
378
+ };
379
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.checkForUpdate = checkForUpdate;
37
+ exports.startUpdateChecker = startUpdateChecker;
38
+ exports.stopUpdateChecker = stopUpdateChecker;
39
+ const semver = __importStar(require("semver"));
40
+ const runtime_1 = require("../../nerves/runtime");
41
+ const DEFAULT_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes
42
+ async function checkForUpdate(currentVersion, deps) {
43
+ (0, runtime_1.emitNervesEvent)({
44
+ component: "daemon",
45
+ event: "daemon.update_check",
46
+ message: "checking for update",
47
+ meta: { currentVersion, distTag: deps.distTag },
48
+ });
49
+ let registryData;
50
+ try {
51
+ registryData = (await deps.fetchRegistryJson());
52
+ }
53
+ catch (err) {
54
+ const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
55
+ return { available: false, error: errorMessage };
56
+ }
57
+ const distTags = registryData?.["dist-tags"];
58
+ if (!distTags) {
59
+ return { available: false, error: "registry response missing dist-tags" };
60
+ }
61
+ const latestVersion = distTags[deps.distTag];
62
+ if (!latestVersion) {
63
+ return { available: false, error: `dist-tag "${deps.distTag}" not found in registry` };
64
+ }
65
+ const available = semver.gt(latestVersion, currentVersion);
66
+ (0, runtime_1.emitNervesEvent)({
67
+ component: "daemon",
68
+ event: "daemon.update_check_result",
69
+ message: available ? "update available" : "no update available",
70
+ meta: { currentVersion, latestVersion, available },
71
+ });
72
+ return { available, latestVersion };
73
+ }
74
+ let _intervalId = null;
75
+ function startUpdateChecker(options) {
76
+ const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
77
+ (0, runtime_1.emitNervesEvent)({
78
+ component: "daemon",
79
+ event: "daemon.update_checker_start",
80
+ message: "starting update checker",
81
+ meta: { intervalMs, currentVersion: options.currentVersion },
82
+ });
83
+ _intervalId = setInterval(() => {
84
+ void (async () => {
85
+ const result = await checkForUpdate(options.currentVersion, options.deps);
86
+ if (result.available && options.onUpdate) {
87
+ await options.onUpdate(result);
88
+ }
89
+ })().catch((err) => {
90
+ (0, runtime_1.emitNervesEvent)({
91
+ component: "daemon",
92
+ event: "daemon.update_checker_error",
93
+ level: "warn",
94
+ message: "update checker tick failed",
95
+ meta: { reason: err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err) },
96
+ });
97
+ });
98
+ }, intervalMs);
99
+ }
100
+ function stopUpdateChecker() {
101
+ if (_intervalId) {
102
+ clearInterval(_intervalId);
103
+ _intervalId = null;
104
+ }
105
+ (0, runtime_1.emitNervesEvent)({
106
+ component: "daemon",
107
+ event: "daemon.update_checker_stop",
108
+ message: "stopping update checker",
109
+ meta: {},
110
+ });
111
+ }