@ouro.bot/cli 0.1.0-alpha.320 → 0.1.0-alpha.321
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/changelog.json +7 -0
- package/dist/heart/outlook/outlook-read.js +26 -1593
- package/dist/heart/outlook/readers/agent-machine.js +355 -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 +231 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/package.json +1 -1
|
@@ -0,0 +1,355 @@
|
|
|
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.readObligationSummary = readObligationSummary;
|
|
37
|
+
exports.readOutlookAgentState = readOutlookAgentState;
|
|
38
|
+
exports.readOutlookMachineState = readOutlookMachineState;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
42
|
+
const obligations_1 = require("../../../arc/obligations");
|
|
43
|
+
const board_1 = require("../../../repertoire/tasks/board");
|
|
44
|
+
const scanner_1 = require("../../../repertoire/tasks/scanner");
|
|
45
|
+
const session_activity_1 = require("../../session-activity");
|
|
46
|
+
const identity_1 = require("../../identity");
|
|
47
|
+
const agent_discovery_1 = require("../../daemon/agent-discovery");
|
|
48
|
+
const runtime_metadata_1 = require("../../daemon/runtime-metadata");
|
|
49
|
+
const thoughts_1 = require("../../daemon/thoughts");
|
|
50
|
+
const outlook_types_1 = require("../outlook-types");
|
|
51
|
+
const shared_1 = require("./shared");
|
|
52
|
+
const LIVE_TASK_STATUSES = ["processing", "validating", "collaborating", "blocked"];
|
|
53
|
+
function emptyByStatus() {
|
|
54
|
+
return {
|
|
55
|
+
drafting: 0,
|
|
56
|
+
processing: 0,
|
|
57
|
+
validating: 0,
|
|
58
|
+
collaborating: 0,
|
|
59
|
+
paused: 0,
|
|
60
|
+
blocked: 0,
|
|
61
|
+
cancelled: 0,
|
|
62
|
+
done: 0,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function readAgentConfig(agentRoot) {
|
|
66
|
+
const configPath = path.join(agentRoot, "agent.json");
|
|
67
|
+
try {
|
|
68
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
const senses = Object.entries(parsed.senses ?? {})
|
|
71
|
+
.filter(([, value]) => value && typeof value.enabled === "boolean" && value.enabled)
|
|
72
|
+
.map(([name]) => name)
|
|
73
|
+
.sort((left, right) => left.localeCompare(right));
|
|
74
|
+
return {
|
|
75
|
+
summary: {
|
|
76
|
+
enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : true,
|
|
77
|
+
provider: typeof parsed.provider === "string" ? parsed.provider : null,
|
|
78
|
+
senses,
|
|
79
|
+
},
|
|
80
|
+
issues: [],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
summary: {
|
|
86
|
+
enabled: false,
|
|
87
|
+
provider: null,
|
|
88
|
+
senses: [],
|
|
89
|
+
},
|
|
90
|
+
issues: [(0, shared_1.issue)("agent-config-unreadable", `${configPath}: ${error instanceof Error ? error.message : String(error)}`)],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function readTaskSummary(agentRoot) {
|
|
95
|
+
const taskRoot = path.join(agentRoot, "tasks");
|
|
96
|
+
const index = (0, scanner_1.scanTasks)(taskRoot);
|
|
97
|
+
const board = (0, board_1.buildTaskBoard)(index);
|
|
98
|
+
const byStatus = emptyByStatus();
|
|
99
|
+
for (const status of Object.keys(byStatus)) {
|
|
100
|
+
byStatus[status] = board.byStatus[status].length;
|
|
101
|
+
}
|
|
102
|
+
const liveTaskNames = LIVE_TASK_STATUSES.flatMap((status) => board.byStatus[status]);
|
|
103
|
+
const issues = index.issues.map((taskIssue) => (0, shared_1.issue)(taskIssue.code, `${taskIssue.target}: ${taskIssue.description}`));
|
|
104
|
+
return {
|
|
105
|
+
summary: {
|
|
106
|
+
totalCount: index.tasks.length,
|
|
107
|
+
liveCount: liveTaskNames.length,
|
|
108
|
+
blockedCount: board.byStatus.blocked.length,
|
|
109
|
+
byStatus,
|
|
110
|
+
liveTaskNames,
|
|
111
|
+
actionRequired: [...board.actionRequired],
|
|
112
|
+
activeBridges: [...board.activeBridges],
|
|
113
|
+
},
|
|
114
|
+
issues,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function readObligationSummary(agentRoot) {
|
|
118
|
+
const items = (0, obligations_1.readPendingObligations)(agentRoot)
|
|
119
|
+
.map((obligation) => ({
|
|
120
|
+
id: obligation.id,
|
|
121
|
+
status: obligation.status,
|
|
122
|
+
content: obligation.content,
|
|
123
|
+
updatedAt: obligation.updatedAt ?? obligation.createdAt,
|
|
124
|
+
nextAction: obligation.nextAction ?? null,
|
|
125
|
+
/* v8 ignore start */
|
|
126
|
+
origin: obligation.origin ?? null,
|
|
127
|
+
currentSurface: obligation.currentSurface ?? null,
|
|
128
|
+
/* v8 ignore stop */
|
|
129
|
+
}))
|
|
130
|
+
.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
131
|
+
return { items };
|
|
132
|
+
}
|
|
133
|
+
function readSessionSummary(agentName, agentRoot, now) {
|
|
134
|
+
const items = (0, session_activity_1.listSessionActivity)({
|
|
135
|
+
sessionsDir: path.join(agentRoot, "state", "sessions"),
|
|
136
|
+
friendsDir: path.join(agentRoot, "friends"),
|
|
137
|
+
agentName,
|
|
138
|
+
nowMs: now.getTime(),
|
|
139
|
+
})
|
|
140
|
+
.filter((session) => !(session.friendId === "self" && session.channel === "inner"))
|
|
141
|
+
.map((session) => ({
|
|
142
|
+
friendId: session.friendId,
|
|
143
|
+
friendName: session.friendName,
|
|
144
|
+
channel: session.channel,
|
|
145
|
+
key: session.key,
|
|
146
|
+
sessionPath: session.sessionPath,
|
|
147
|
+
lastActivityAt: session.lastActivityAt,
|
|
148
|
+
activitySource: session.activitySource,
|
|
149
|
+
}));
|
|
150
|
+
return { items };
|
|
151
|
+
}
|
|
152
|
+
function readInnerSummary(agentRoot) {
|
|
153
|
+
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
|
|
154
|
+
const pendingDir = path.join(agentRoot, "state", "pending", "self", "inner", "dialog");
|
|
155
|
+
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
156
|
+
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
157
|
+
const surfacedSummary = job.surfacedResult ? (0, thoughts_1.formatSurfacedValue)(job.surfacedResult) : null;
|
|
158
|
+
const latestPendingTimestamp = pendingMessages.length > 0
|
|
159
|
+
? new Date(Math.max(...pendingMessages.map((message) => message.timestamp))).toISOString()
|
|
160
|
+
: null;
|
|
161
|
+
const latestActivityAt = latestPendingTimestamp
|
|
162
|
+
?? runtimeState?.startedAt
|
|
163
|
+
?? runtimeState?.lastCompletedAt
|
|
164
|
+
?? null;
|
|
165
|
+
return {
|
|
166
|
+
summary: {
|
|
167
|
+
visibility: outlook_types_1.OUTLOOK_DEFAULT_INNER_VISIBILITY,
|
|
168
|
+
status: job.status,
|
|
169
|
+
hasPending: pendingMessages.length > 0,
|
|
170
|
+
surfacedSummary,
|
|
171
|
+
origin: job.origin,
|
|
172
|
+
obligationStatus: job.obligationStatus,
|
|
173
|
+
latestActivityAt,
|
|
174
|
+
},
|
|
175
|
+
issues: [],
|
|
176
|
+
latestActivityAt,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function readCodingSummary(agentRoot) {
|
|
180
|
+
const stateFilePath = path.join(agentRoot, "state", "coding", "sessions.json");
|
|
181
|
+
const issues = [];
|
|
182
|
+
if (!fs.existsSync(stateFilePath)) {
|
|
183
|
+
return { items: [], issues };
|
|
184
|
+
}
|
|
185
|
+
let parsed;
|
|
186
|
+
try {
|
|
187
|
+
parsed = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
issues.push((0, shared_1.issue)("coding-state-unreadable", `${stateFilePath}: ${error instanceof Error ? error.message : String(error)}`));
|
|
191
|
+
return { items: [], issues };
|
|
192
|
+
}
|
|
193
|
+
const items = Array.isArray(parsed.records)
|
|
194
|
+
? parsed.records.flatMap((record) => {
|
|
195
|
+
const session = record?.session;
|
|
196
|
+
if (!session || typeof session.id !== "string" || typeof session.runner !== "string" || typeof session.status !== "string" || typeof session.workdir !== "string" || typeof session.lastActivityAt !== "string") {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const checkpoint = typeof session.checkpoint === "string"
|
|
200
|
+
? session.checkpoint
|
|
201
|
+
: typeof session.stderrTail === "string" && session.stderrTail.trim().length > 0
|
|
202
|
+
? session.stderrTail.trim()
|
|
203
|
+
: typeof session.stdoutTail === "string" && session.stdoutTail.trim().length > 0
|
|
204
|
+
? session.stdoutTail.trim()
|
|
205
|
+
: null;
|
|
206
|
+
const originSession = session.originSession;
|
|
207
|
+
const normalizedOrigin = originSession
|
|
208
|
+
&& typeof originSession.friendId === "string"
|
|
209
|
+
&& typeof originSession.channel === "string"
|
|
210
|
+
&& typeof originSession.key === "string"
|
|
211
|
+
? {
|
|
212
|
+
friendId: originSession.friendId,
|
|
213
|
+
channel: originSession.channel,
|
|
214
|
+
key: originSession.key,
|
|
215
|
+
}
|
|
216
|
+
: null;
|
|
217
|
+
return [{
|
|
218
|
+
id: session.id,
|
|
219
|
+
runner: session.runner,
|
|
220
|
+
status: session.status,
|
|
221
|
+
checkpoint,
|
|
222
|
+
taskRef: typeof session.taskRef === "string" ? session.taskRef : null,
|
|
223
|
+
workdir: session.workdir,
|
|
224
|
+
originSession: normalizedOrigin,
|
|
225
|
+
lastActivityAt: session.lastActivityAt,
|
|
226
|
+
}];
|
|
227
|
+
})
|
|
228
|
+
: [];
|
|
229
|
+
return { items, issues };
|
|
230
|
+
}
|
|
231
|
+
function collectLatestActivityTimestamps(input) {
|
|
232
|
+
const timestamps = [];
|
|
233
|
+
for (const item of input.obligations)
|
|
234
|
+
timestamps.push(item.updatedAt);
|
|
235
|
+
for (const item of input.sessions)
|
|
236
|
+
timestamps.push(item.lastActivityAt);
|
|
237
|
+
for (const item of input.coding)
|
|
238
|
+
timestamps.push(item.lastActivityAt);
|
|
239
|
+
if (input.innerLatestActivityAt)
|
|
240
|
+
timestamps.push(input.innerLatestActivityAt);
|
|
241
|
+
return timestamps
|
|
242
|
+
.filter((value) => Number.isFinite(Date.parse(value)));
|
|
243
|
+
}
|
|
244
|
+
function summarizeFreshness(latestActivityAt, now) {
|
|
245
|
+
if (!latestActivityAt) {
|
|
246
|
+
return {
|
|
247
|
+
status: "unknown",
|
|
248
|
+
latestActivityAt: null,
|
|
249
|
+
ageMs: null,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const ageMs = now.getTime() - Date.parse(latestActivityAt);
|
|
253
|
+
return {
|
|
254
|
+
status: ageMs > shared_1.STALE_THRESHOLD_MS ? "stale" : "fresh",
|
|
255
|
+
latestActivityAt,
|
|
256
|
+
ageMs,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function summarizeDegraded(issues) {
|
|
260
|
+
return {
|
|
261
|
+
status: issues.length > 0 ? "degraded" : "ok",
|
|
262
|
+
issues,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function summarizeAgent(state) {
|
|
266
|
+
return {
|
|
267
|
+
agentName: state.agentName,
|
|
268
|
+
enabled: state.enabled,
|
|
269
|
+
freshness: state.freshness,
|
|
270
|
+
degraded: state.degraded,
|
|
271
|
+
tasks: {
|
|
272
|
+
liveCount: state.tasks.liveCount,
|
|
273
|
+
blockedCount: state.tasks.blockedCount,
|
|
274
|
+
},
|
|
275
|
+
obligations: {
|
|
276
|
+
openCount: state.obligations.openCount,
|
|
277
|
+
},
|
|
278
|
+
coding: {
|
|
279
|
+
activeCount: state.coding.activeCount,
|
|
280
|
+
blockedCount: state.coding.blockedCount,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function readOutlookAgentState(agentName, options = {}) {
|
|
285
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
286
|
+
const now = options.now?.() ?? new Date();
|
|
287
|
+
const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
|
|
288
|
+
const issues = [];
|
|
289
|
+
const config = readAgentConfig(agentRoot);
|
|
290
|
+
issues.push(...config.issues);
|
|
291
|
+
const tasks = readTaskSummary(agentRoot);
|
|
292
|
+
issues.push(...tasks.issues);
|
|
293
|
+
const obligations = readObligationSummary(agentRoot);
|
|
294
|
+
const sessions = readSessionSummary(agentName, agentRoot, now);
|
|
295
|
+
const inner = readInnerSummary(agentRoot);
|
|
296
|
+
issues.push(...inner.issues);
|
|
297
|
+
const coding = readCodingSummary(agentRoot);
|
|
298
|
+
issues.push(...coding.issues);
|
|
299
|
+
const latestActivityAt = collectLatestActivityTimestamps({
|
|
300
|
+
obligations: obligations.items,
|
|
301
|
+
sessions: sessions.items,
|
|
302
|
+
innerLatestActivityAt: inner.latestActivityAt,
|
|
303
|
+
coding: coding.items,
|
|
304
|
+
}).sort((left, right) => right.localeCompare(left))[0] ?? null;
|
|
305
|
+
return {
|
|
306
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
307
|
+
agentName,
|
|
308
|
+
agentRoot,
|
|
309
|
+
enabled: config.summary.enabled,
|
|
310
|
+
provider: config.summary.provider,
|
|
311
|
+
senses: config.summary.senses,
|
|
312
|
+
freshness: summarizeFreshness(latestActivityAt, now),
|
|
313
|
+
degraded: summarizeDegraded(issues),
|
|
314
|
+
tasks: tasks.summary,
|
|
315
|
+
obligations: {
|
|
316
|
+
openCount: obligations.items.length,
|
|
317
|
+
items: obligations.items,
|
|
318
|
+
},
|
|
319
|
+
sessions: {
|
|
320
|
+
liveCount: sessions.items.length,
|
|
321
|
+
items: sessions.items,
|
|
322
|
+
},
|
|
323
|
+
inner: inner.summary,
|
|
324
|
+
coding: {
|
|
325
|
+
totalCount: coding.items.length,
|
|
326
|
+
activeCount: coding.items.filter((item) => shared_1.ACTIVE_CODING_STATUSES.has(item.status)).length,
|
|
327
|
+
blockedCount: coding.items.filter((item) => shared_1.BLOCKED_CODING_STATUSES.has(item.status)).length,
|
|
328
|
+
items: coding.items,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function readOutlookMachineState(options = {}) {
|
|
333
|
+
/* v8 ignore next */
|
|
334
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_read", message: "reading outlook machine state", meta: {} });
|
|
335
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
336
|
+
const now = options.now?.() ?? new Date();
|
|
337
|
+
const runtime = options.runtimeMetadata ?? (0, runtime_metadata_1.getRuntimeMetadata)({ bundlesRoot });
|
|
338
|
+
const agentNames = options.agentNames ?? (0, agent_discovery_1.listEnabledBundleAgents)({ bundlesRoot });
|
|
339
|
+
const agentStates = agentNames.map((agentName) => readOutlookAgentState(agentName, { ...options, bundlesRoot, now: () => now }));
|
|
340
|
+
const degradedIssues = agentStates
|
|
341
|
+
.flatMap((state) => state.degraded.issues.map((problem) => (0, shared_1.issue)("agent-degraded", `${state.agentName}: ${problem.detail}`)));
|
|
342
|
+
const freshest = agentStates
|
|
343
|
+
.map((state) => state.freshness.latestActivityAt)
|
|
344
|
+
.filter((value) => typeof value === "string")
|
|
345
|
+
.sort((left, right) => right.localeCompare(left))[0] ?? null;
|
|
346
|
+
return {
|
|
347
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
348
|
+
observedAt: now.toISOString(),
|
|
349
|
+
runtime,
|
|
350
|
+
agentCount: agentStates.length,
|
|
351
|
+
freshness: summarizeFreshness(freshest, now),
|
|
352
|
+
degraded: summarizeDegraded(degradedIssues),
|
|
353
|
+
agents: agentStates.map(summarizeAgent),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
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.readOutlookContinuity = readOutlookContinuity;
|
|
37
|
+
exports.readOrientationView = readOrientationView;
|
|
38
|
+
exports.readObligationDetailView = readObligationDetailView;
|
|
39
|
+
exports.readChangesView = readChangesView;
|
|
40
|
+
exports.readSelfFixView = readSelfFixView;
|
|
41
|
+
exports.readMemoryDecisionView = readMemoryDecisionView;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
45
|
+
const cares_1 = require("../../../arc/cares");
|
|
46
|
+
const episodes_1 = require("../../../arc/episodes");
|
|
47
|
+
const obligations_1 = require("../../../arc/obligations");
|
|
48
|
+
const presence_1 = require("../../../arc/presence");
|
|
49
|
+
const scanner_1 = require("../../../repertoire/tasks/scanner");
|
|
50
|
+
const active_work_1 = require("../../active-work");
|
|
51
|
+
const session_activity_1 = require("../../session-activity");
|
|
52
|
+
function sortOpenObligations(obligations) {
|
|
53
|
+
const statusPriority = {
|
|
54
|
+
returning: 0,
|
|
55
|
+
collaborating: 1,
|
|
56
|
+
in_progress: 2,
|
|
57
|
+
delegated: 3,
|
|
58
|
+
accepted: 4,
|
|
59
|
+
pending: 5,
|
|
60
|
+
};
|
|
61
|
+
return obligations
|
|
62
|
+
.map((obligation) => ({
|
|
63
|
+
obligation,
|
|
64
|
+
priority: statusPriority[obligation.status] ?? 99,
|
|
65
|
+
updatedMs: new Date(obligation.updatedAt ?? obligation.createdAt).getTime(),
|
|
66
|
+
}))
|
|
67
|
+
.sort((a, b) => {
|
|
68
|
+
if (a.priority !== b.priority)
|
|
69
|
+
return a.priority - b.priority;
|
|
70
|
+
return b.updatedMs - a.updatedMs;
|
|
71
|
+
})
|
|
72
|
+
.map((entry) => entry.obligation);
|
|
73
|
+
}
|
|
74
|
+
function readOutlookContinuity(agentRoot, agentName) {
|
|
75
|
+
const self = (0, presence_1.readPresence)(agentRoot, agentName);
|
|
76
|
+
const peers = (0, presence_1.readPeerPresence)(agentRoot);
|
|
77
|
+
const cares = (0, cares_1.readActiveCares)(agentRoot);
|
|
78
|
+
const episodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 10 });
|
|
79
|
+
(0, runtime_1.emitNervesEvent)({
|
|
80
|
+
component: "heart",
|
|
81
|
+
event: "heart.outlook_continuity_read",
|
|
82
|
+
message: `outlook continuity: ${cares.length} cares, ${episodes.length} episodes`,
|
|
83
|
+
meta: { careCount: cares.length, episodeCount: episodes.length, hasSelf: self != null, peerCount: peers.length },
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
presence: { self, peers },
|
|
87
|
+
cares: {
|
|
88
|
+
activeCount: cares.length,
|
|
89
|
+
items: cares.map((c) => ({
|
|
90
|
+
id: c.id,
|
|
91
|
+
label: c.label,
|
|
92
|
+
status: c.status,
|
|
93
|
+
salience: c.salience,
|
|
94
|
+
})),
|
|
95
|
+
},
|
|
96
|
+
episodes: {
|
|
97
|
+
recentCount: episodes.length,
|
|
98
|
+
items: episodes.map((ep) => ({
|
|
99
|
+
id: ep.id,
|
|
100
|
+
kind: ep.kind,
|
|
101
|
+
summary: ep.summary,
|
|
102
|
+
timestamp: ep.timestamp,
|
|
103
|
+
})),
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function readOrientationView(agentRoot, agentName) {
|
|
108
|
+
let obligations = [];
|
|
109
|
+
try {
|
|
110
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
obligations = [];
|
|
114
|
+
}
|
|
115
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
116
|
+
const sorted = sortOpenObligations(openObligations);
|
|
117
|
+
const primary = sorted[0] ?? null;
|
|
118
|
+
let sessions = [];
|
|
119
|
+
try {
|
|
120
|
+
sessions = (0, session_activity_1.listSessionActivity)({
|
|
121
|
+
sessionsDir: path.join(agentRoot, "state", "sessions"),
|
|
122
|
+
friendsDir: path.join(agentRoot, "friends"),
|
|
123
|
+
agentName,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
sessions = [];
|
|
128
|
+
}
|
|
129
|
+
const sortedSessions = [...sessions].sort((a, b) => b.lastActivityMs - a.lastActivityMs);
|
|
130
|
+
const currentSession = sortedSessions.length > 0
|
|
131
|
+
? {
|
|
132
|
+
friendId: sortedSessions[0].friendId,
|
|
133
|
+
channel: sortedSessions[0].channel,
|
|
134
|
+
key: sortedSessions[0].key,
|
|
135
|
+
lastActivityAt: sortedSessions[0].lastActivityAt,
|
|
136
|
+
}
|
|
137
|
+
: null;
|
|
138
|
+
const otherActiveSessions = sortedSessions.slice(1).map((s) => ({
|
|
139
|
+
friendId: s.friendId,
|
|
140
|
+
friendName: s.friendName,
|
|
141
|
+
channel: s.channel,
|
|
142
|
+
key: s.key,
|
|
143
|
+
lastActivityAt: s.lastActivityAt,
|
|
144
|
+
}));
|
|
145
|
+
const parts = [];
|
|
146
|
+
if (primary)
|
|
147
|
+
parts.push(primary.content);
|
|
148
|
+
if (openObligations.length > 1)
|
|
149
|
+
parts.push(`${openObligations.length} open obligations`);
|
|
150
|
+
if (sessions.length > 0)
|
|
151
|
+
parts.push(`${sessions.length} active sessions`);
|
|
152
|
+
const centerOfGravity = parts.length > 0 ? parts.join(" | ") : "idle";
|
|
153
|
+
const primaryObligation = primary
|
|
154
|
+
? {
|
|
155
|
+
id: primary.id,
|
|
156
|
+
content: primary.content,
|
|
157
|
+
status: primary.status,
|
|
158
|
+
nextAction: primary.nextAction ?? null,
|
|
159
|
+
waitingOn: primary.meaning?.waitingOn?.detail ?? null,
|
|
160
|
+
}
|
|
161
|
+
: null;
|
|
162
|
+
(0, runtime_1.emitNervesEvent)({
|
|
163
|
+
component: "heart",
|
|
164
|
+
event: "heart.outlook_orientation_read",
|
|
165
|
+
message: `outlook orientation: ${openObligations.length} obligations, ${sessions.length} sessions`,
|
|
166
|
+
meta: { obligationCount: openObligations.length, sessionCount: sessions.length, primaryId: primary?.id ?? null },
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
currentSession,
|
|
170
|
+
centerOfGravity,
|
|
171
|
+
primaryObligation,
|
|
172
|
+
resumeHandle: null,
|
|
173
|
+
otherActiveSessions,
|
|
174
|
+
rawState: null,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function readObligationDetailView(agentRoot) {
|
|
178
|
+
let obligations = [];
|
|
179
|
+
try {
|
|
180
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
obligations = [];
|
|
184
|
+
}
|
|
185
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
186
|
+
const sorted = sortOpenObligations(openObligations);
|
|
187
|
+
const primary = sorted[0] ?? null;
|
|
188
|
+
const items = openObligations.map((ob) => ({
|
|
189
|
+
id: ob.id,
|
|
190
|
+
status: ob.status,
|
|
191
|
+
content: ob.content,
|
|
192
|
+
updatedAt: ob.updatedAt ?? ob.createdAt,
|
|
193
|
+
nextAction: ob.nextAction ?? null,
|
|
194
|
+
origin: ob.origin ?? null,
|
|
195
|
+
currentSurface: ob.currentSurface ? { kind: ob.currentSurface.kind, label: ob.currentSurface.label } : null,
|
|
196
|
+
meaning: ob.meaning ? { waitingOn: ob.meaning.waitingOn?.detail ?? null } : null,
|
|
197
|
+
isPrimary: ob.id === primary.id,
|
|
198
|
+
}));
|
|
199
|
+
let primarySelectionReason = null;
|
|
200
|
+
if (primary) {
|
|
201
|
+
if (primary.status !== "pending") {
|
|
202
|
+
primarySelectionReason = `most advanced status: ${primary.status}`;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
primarySelectionReason = "most recent pending";
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
(0, runtime_1.emitNervesEvent)({
|
|
209
|
+
component: "heart",
|
|
210
|
+
event: "heart.outlook_obligations_read",
|
|
211
|
+
message: `outlook obligations: ${openObligations.length} open`,
|
|
212
|
+
meta: { openCount: openObligations.length, primaryId: primary?.id ?? null },
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
openCount: openObligations.length,
|
|
216
|
+
primaryId: primary?.id ?? null,
|
|
217
|
+
primarySelectionReason,
|
|
218
|
+
items,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function readChangesView(agentRoot) {
|
|
222
|
+
const snapshotPath = path.join(agentRoot, "state", "outlook", "active-work-snapshot.json");
|
|
223
|
+
let previous = null;
|
|
224
|
+
try {
|
|
225
|
+
const raw = fs.readFileSync(snapshotPath, "utf-8");
|
|
226
|
+
previous = JSON.parse(raw);
|
|
227
|
+
if (!previous.obligationSnapshots || !previous.codingSnapshots)
|
|
228
|
+
previous = null;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
previous = null;
|
|
232
|
+
}
|
|
233
|
+
let obligations = [];
|
|
234
|
+
try {
|
|
235
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
obligations = [];
|
|
239
|
+
}
|
|
240
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
241
|
+
const current = {
|
|
242
|
+
obligationSnapshots: openObligations.map((ob) => ({
|
|
243
|
+
id: ob.id,
|
|
244
|
+
status: ob.status,
|
|
245
|
+
artifact: ob.currentArtifact?.trim() || null,
|
|
246
|
+
nextAction: ob.nextAction?.trim() || null,
|
|
247
|
+
})),
|
|
248
|
+
codingSnapshots: [],
|
|
249
|
+
timestamp: new Date().toISOString(),
|
|
250
|
+
};
|
|
251
|
+
try {
|
|
252
|
+
fs.mkdirSync(path.dirname(snapshotPath), { recursive: true });
|
|
253
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(current, null, 2) + "\n", "utf-8");
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
// Best effort
|
|
257
|
+
}
|
|
258
|
+
if (!previous) {
|
|
259
|
+
return { changeCount: 0, items: [], snapshotAge: null, formatted: "" };
|
|
260
|
+
}
|
|
261
|
+
const changes = (0, active_work_1.detectActiveWorkChanges)(previous, current);
|
|
262
|
+
const formatted = (0, active_work_1.formatActiveWorkChanges)(changes);
|
|
263
|
+
(0, runtime_1.emitNervesEvent)({
|
|
264
|
+
component: "heart",
|
|
265
|
+
event: "heart.outlook_changes_read",
|
|
266
|
+
message: `outlook changes: ${changes.length} detected`,
|
|
267
|
+
meta: { changeCount: changes.length, snapshotAge: previous.timestamp },
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
changeCount: changes.length,
|
|
271
|
+
items: changes.map((c) => ({ kind: c.kind, id: c.id, from: c.from, to: c.to, summary: c.summary })),
|
|
272
|
+
snapshotAge: previous.timestamp,
|
|
273
|
+
formatted,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function readSelfFixView(agentRoot) {
|
|
277
|
+
let tasks = [];
|
|
278
|
+
try {
|
|
279
|
+
const scanned = (0, scanner_1.scanTasks)(path.join(agentRoot, "tasks"));
|
|
280
|
+
tasks = scanned.tasks.map((t) => ({ name: t.name, title: t.title, status: t.status }));
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
tasks = [];
|
|
284
|
+
}
|
|
285
|
+
const selfFixTasks = tasks.filter((t) => t.title.toLowerCase().includes("fix"));
|
|
286
|
+
if (selfFixTasks.length === 0) {
|
|
287
|
+
return { active: false, currentStep: null, steps: [] };
|
|
288
|
+
}
|
|
289
|
+
const steps = selfFixTasks.map((t) => ({
|
|
290
|
+
label: t.title,
|
|
291
|
+
status: t.status === "done" ? "done" : t.status === "processing" ? "active" : "pending",
|
|
292
|
+
detail: `task ${t.name}: ${t.status}`,
|
|
293
|
+
}));
|
|
294
|
+
const activeStep = steps.find((s) => s.status === "active");
|
|
295
|
+
(0, runtime_1.emitNervesEvent)({
|
|
296
|
+
component: "heart",
|
|
297
|
+
event: "heart.outlook_selffix_read",
|
|
298
|
+
message: `outlook self-fix: ${selfFixTasks.length} tasks`,
|
|
299
|
+
meta: { taskCount: selfFixTasks.length, active: !!activeStep },
|
|
300
|
+
});
|
|
301
|
+
return {
|
|
302
|
+
active: !!activeStep,
|
|
303
|
+
currentStep: activeStep?.label ?? null,
|
|
304
|
+
steps,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function readMemoryDecisionView(agentRoot, limit = 50) {
|
|
308
|
+
const logPath = path.join(agentRoot, "state", "outlook", "memory-decisions.jsonl");
|
|
309
|
+
let lines = [];
|
|
310
|
+
try {
|
|
311
|
+
const raw = fs.readFileSync(logPath, "utf-8");
|
|
312
|
+
lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return { totalCount: 0, items: [] };
|
|
316
|
+
}
|
|
317
|
+
const items = [];
|
|
318
|
+
for (const line of lines) {
|
|
319
|
+
try {
|
|
320
|
+
const parsed = JSON.parse(line);
|
|
321
|
+
if (parsed.kind && parsed.decision && parsed.timestamp) {
|
|
322
|
+
items.push(parsed);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Skip malformed lines
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
items.reverse();
|
|
330
|
+
const limited = items.slice(0, limit);
|
|
331
|
+
return { totalCount: items.length, items: limited };
|
|
332
|
+
}
|