@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.
@@ -1,1595 +1,28 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.readOutlookAgentState = readOutlookAgentState;
37
- exports.readOutlookMachineState = readOutlookMachineState;
38
- exports.readSessionInventory = readSessionInventory;
39
- exports.readSessionTranscript = readSessionTranscript;
40
- exports.readCodingDeep = readCodingDeep;
41
- exports.readAttentionView = readAttentionView;
42
- exports.readBridgeInventory = readBridgeInventory;
43
- exports.readDaemonHealthDeep = readDaemonHealthDeep;
44
- exports.readMemoryView = readMemoryView;
45
- exports.readFriendView = readFriendView;
46
- exports.readLogView = readLogView;
47
- exports.readHabitView = readHabitView;
48
- exports.readNeedsMeView = readNeedsMeView;
49
- exports.readDeskPrefs = readDeskPrefs;
50
- exports.readOutlookContinuity = readOutlookContinuity;
51
- exports.readOrientationView = readOrientationView;
52
- exports.readObligationDetailView = readObligationDetailView;
53
- exports.readChangesView = readChangesView;
54
- exports.readSelfFixView = readSelfFixView;
55
- exports.readMemoryDecisionView = readMemoryDecisionView;
56
- const fs = __importStar(require("fs"));
57
- const path = __importStar(require("path"));
58
- const runtime_1 = require("../../nerves/runtime");
59
- const identity_1 = require("../identity");
60
- const obligations_1 = require("../../arc/obligations");
61
- const session_activity_1 = require("../session-activity");
62
- const board_1 = require("../../repertoire/tasks/board");
63
- const scanner_1 = require("../../repertoire/tasks/scanner");
64
- const agent_discovery_1 = require("../daemon/agent-discovery");
65
- const runtime_metadata_1 = require("../daemon/runtime-metadata");
66
- const thoughts_1 = require("../daemon/thoughts");
67
- const outlook_types_1 = require("./outlook-types");
68
- const presence_1 = require("../../arc/presence");
69
- const cares_1 = require("../../arc/cares");
70
- const episodes_1 = require("../../arc/episodes");
71
- const session_events_1 = require("../session-events");
72
- const LIVE_TASK_STATUSES = ["processing", "validating", "collaborating", "blocked"];
73
- const ACTIVE_CODING_STATUSES = new Set(["spawning", "running", "waiting_input", "stalled"]);
74
- const BLOCKED_CODING_STATUSES = new Set(["waiting_input", "stalled"]);
75
- const STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
76
- function issue(code, detail) {
77
- return { code, detail };
78
- }
79
- function emptyByStatus() {
80
- return {
81
- drafting: 0,
82
- processing: 0,
83
- validating: 0,
84
- collaborating: 0,
85
- paused: 0,
86
- blocked: 0,
87
- cancelled: 0,
88
- done: 0,
89
- };
90
- }
91
- function readAgentConfig(agentRoot) {
92
- const configPath = path.join(agentRoot, "agent.json");
93
- try {
94
- const raw = fs.readFileSync(configPath, "utf-8");
95
- const parsed = JSON.parse(raw);
96
- const senses = Object.entries(parsed.senses ?? {})
97
- .filter(([, value]) => value && typeof value.enabled === "boolean" && value.enabled)
98
- .map(([name]) => name)
99
- .sort((left, right) => left.localeCompare(right));
100
- return {
101
- summary: {
102
- enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : true,
103
- provider: typeof parsed.provider === "string" ? parsed.provider : null,
104
- senses,
105
- },
106
- issues: [],
107
- };
108
- }
109
- catch (error) {
110
- return {
111
- summary: {
112
- enabled: false,
113
- provider: null,
114
- senses: [],
115
- },
116
- issues: [issue("agent-config-unreadable", `${configPath}: ${error instanceof Error ? error.message : String(error)}`)],
117
- };
118
- }
119
- }
120
- function readTaskSummary(agentRoot) {
121
- const taskRoot = path.join(agentRoot, "tasks");
122
- const index = (0, scanner_1.scanTasks)(taskRoot);
123
- const board = (0, board_1.buildTaskBoard)(index);
124
- const byStatus = emptyByStatus();
125
- for (const status of Object.keys(byStatus)) {
126
- byStatus[status] = board.byStatus[status].length;
127
- }
128
- const liveTaskNames = LIVE_TASK_STATUSES.flatMap((status) => board.byStatus[status]);
129
- const issues = index.issues.map((taskIssue) => issue(taskIssue.code, `${taskIssue.target}: ${taskIssue.description}`));
130
- return {
131
- summary: {
132
- totalCount: index.tasks.length,
133
- liveCount: liveTaskNames.length,
134
- blockedCount: board.byStatus.blocked.length,
135
- byStatus,
136
- liveTaskNames,
137
- actionRequired: [...board.actionRequired],
138
- activeBridges: [...board.activeBridges],
139
- },
140
- issues,
141
- };
142
- }
143
- function readObligationSummary(agentRoot) {
144
- const items = (0, obligations_1.readPendingObligations)(agentRoot)
145
- .map((obligation) => ({
146
- id: obligation.id,
147
- status: obligation.status,
148
- content: obligation.content,
149
- updatedAt: obligation.updatedAt ?? obligation.createdAt,
150
- nextAction: obligation.nextAction ?? null,
151
- /* v8 ignore start */
152
- origin: obligation.origin ?? null,
153
- currentSurface: obligation.currentSurface ?? null,
154
- /* v8 ignore stop */
155
- }))
156
- .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
157
- return { items };
158
- }
159
- function readSessionSummary(agentName, agentRoot, now) {
160
- const items = (0, session_activity_1.listSessionActivity)({
161
- sessionsDir: path.join(agentRoot, "state", "sessions"),
162
- friendsDir: path.join(agentRoot, "friends"),
163
- agentName,
164
- nowMs: now.getTime(),
165
- })
166
- .filter((session) => !(session.friendId === "self" && session.channel === "inner"))
167
- .map((session) => ({
168
- friendId: session.friendId,
169
- friendName: session.friendName,
170
- channel: session.channel,
171
- key: session.key,
172
- sessionPath: session.sessionPath,
173
- lastActivityAt: session.lastActivityAt,
174
- activitySource: session.activitySource,
175
- }));
176
- return { items };
177
- }
178
- function readInnerSummary(agentRoot) {
179
- const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
180
- const pendingDir = path.join(agentRoot, "state", "pending", "self", "inner", "dialog");
181
- const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
182
- const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
183
- const surfacedSummary = job.surfacedResult ? (0, thoughts_1.formatSurfacedValue)(job.surfacedResult) : null;
184
- const latestPendingTimestamp = pendingMessages.length > 0
185
- ? new Date(Math.max(...pendingMessages.map((message) => message.timestamp))).toISOString()
186
- : null;
187
- const latestActivityAt = latestPendingTimestamp
188
- ?? runtimeState?.startedAt
189
- ?? runtimeState?.lastCompletedAt
190
- ?? null;
191
- return {
192
- summary: {
193
- visibility: outlook_types_1.OUTLOOK_DEFAULT_INNER_VISIBILITY,
194
- status: job.status,
195
- hasPending: pendingMessages.length > 0,
196
- surfacedSummary,
197
- origin: job.origin,
198
- obligationStatus: job.obligationStatus,
199
- latestActivityAt,
200
- },
201
- issues: [],
202
- latestActivityAt,
203
- };
204
- }
205
- function readCodingSummary(agentRoot) {
206
- const stateFilePath = path.join(agentRoot, "state", "coding", "sessions.json");
207
- const issues = [];
208
- if (!fs.existsSync(stateFilePath)) {
209
- return { items: [], issues };
210
- }
211
- let parsed;
212
- try {
213
- parsed = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));
214
- }
215
- catch (error) {
216
- issues.push(issue("coding-state-unreadable", `${stateFilePath}: ${error instanceof Error ? error.message : String(error)}`));
217
- return { items: [], issues };
218
- }
219
- const items = Array.isArray(parsed.records)
220
- ? parsed.records.flatMap((record) => {
221
- const session = record?.session;
222
- if (!session || typeof session.id !== "string" || typeof session.runner !== "string" || typeof session.status !== "string" || typeof session.workdir !== "string" || typeof session.lastActivityAt !== "string") {
223
- return [];
224
- }
225
- const checkpoint = typeof session.checkpoint === "string"
226
- ? session.checkpoint
227
- : typeof session.stderrTail === "string" && session.stderrTail.trim().length > 0
228
- ? session.stderrTail.trim()
229
- : typeof session.stdoutTail === "string" && session.stdoutTail.trim().length > 0
230
- ? session.stdoutTail.trim()
231
- : null;
232
- const originSession = session.originSession;
233
- const normalizedOrigin = originSession
234
- && typeof originSession.friendId === "string"
235
- && typeof originSession.channel === "string"
236
- && typeof originSession.key === "string"
237
- ? {
238
- friendId: originSession.friendId,
239
- channel: originSession.channel,
240
- key: originSession.key,
241
- }
242
- : null;
243
- return [{
244
- id: session.id,
245
- runner: session.runner,
246
- status: session.status,
247
- checkpoint,
248
- taskRef: typeof session.taskRef === "string" ? session.taskRef : null,
249
- workdir: session.workdir,
250
- originSession: normalizedOrigin,
251
- lastActivityAt: session.lastActivityAt,
252
- }];
253
- })
254
- : [];
255
- return { items, issues };
256
- }
257
- function collectLatestActivityTimestamps(input) {
258
- const timestamps = [];
259
- for (const item of input.obligations)
260
- timestamps.push(item.updatedAt);
261
- for (const item of input.sessions)
262
- timestamps.push(item.lastActivityAt);
263
- for (const item of input.coding)
264
- timestamps.push(item.lastActivityAt);
265
- if (input.innerLatestActivityAt)
266
- timestamps.push(input.innerLatestActivityAt);
267
- return timestamps
268
- .filter((value) => Number.isFinite(Date.parse(value)));
269
- }
270
- function summarizeFreshness(latestActivityAt, now) {
271
- if (!latestActivityAt) {
272
- return {
273
- status: "unknown",
274
- latestActivityAt: null,
275
- ageMs: null,
276
- };
277
- }
278
- const ageMs = now.getTime() - Date.parse(latestActivityAt);
279
- return {
280
- status: ageMs > STALE_THRESHOLD_MS ? "stale" : "fresh",
281
- latestActivityAt,
282
- ageMs,
283
- };
284
- }
285
- function summarizeDegraded(issues) {
286
- return {
287
- status: issues.length > 0 ? "degraded" : "ok",
288
- issues,
289
- };
290
- }
291
- function summarizeAgent(state) {
292
- return {
293
- agentName: state.agentName,
294
- enabled: state.enabled,
295
- freshness: state.freshness,
296
- degraded: state.degraded,
297
- tasks: {
298
- liveCount: state.tasks.liveCount,
299
- blockedCount: state.tasks.blockedCount,
300
- },
301
- obligations: {
302
- openCount: state.obligations.openCount,
303
- },
304
- coding: {
305
- activeCount: state.coding.activeCount,
306
- blockedCount: state.coding.blockedCount,
307
- },
308
- };
309
- }
310
- function readOutlookAgentState(agentName, options = {}) {
311
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
312
- const now = options.now?.() ?? new Date();
313
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
314
- const issues = [];
315
- const config = readAgentConfig(agentRoot);
316
- issues.push(...config.issues);
317
- const tasks = readTaskSummary(agentRoot);
318
- issues.push(...tasks.issues);
319
- const obligations = readObligationSummary(agentRoot);
320
- const sessions = readSessionSummary(agentName, agentRoot, now);
321
- const inner = readInnerSummary(agentRoot);
322
- issues.push(...inner.issues);
323
- const coding = readCodingSummary(agentRoot);
324
- issues.push(...coding.issues);
325
- const latestActivityAt = collectLatestActivityTimestamps({
326
- obligations: obligations.items,
327
- sessions: sessions.items,
328
- innerLatestActivityAt: inner.latestActivityAt,
329
- coding: coding.items,
330
- }).sort((left, right) => right.localeCompare(left))[0] ?? null;
331
- return {
332
- productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
333
- agentName,
334
- agentRoot,
335
- enabled: config.summary.enabled,
336
- provider: config.summary.provider,
337
- senses: config.summary.senses,
338
- freshness: summarizeFreshness(latestActivityAt, now),
339
- degraded: summarizeDegraded(issues),
340
- tasks: tasks.summary,
341
- obligations: {
342
- openCount: obligations.items.length,
343
- items: obligations.items,
344
- },
345
- sessions: {
346
- liveCount: sessions.items.length,
347
- items: sessions.items,
348
- },
349
- inner: inner.summary,
350
- coding: {
351
- totalCount: coding.items.length,
352
- activeCount: coding.items.filter((item) => ACTIVE_CODING_STATUSES.has(item.status)).length,
353
- blockedCount: coding.items.filter((item) => BLOCKED_CODING_STATUSES.has(item.status)).length,
354
- items: coding.items,
355
- },
356
- };
357
- }
358
- function readOutlookMachineState(options = {}) {
359
- /* v8 ignore next */
360
- (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_read", message: "reading outlook machine state", meta: {} });
361
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
362
- const now = options.now?.() ?? new Date();
363
- const runtime = options.runtimeMetadata ?? (0, runtime_metadata_1.getRuntimeMetadata)({ bundlesRoot });
364
- const agentNames = options.agentNames ?? (0, agent_discovery_1.listEnabledBundleAgents)({ bundlesRoot });
365
- const agentStates = agentNames.map((agentName) => readOutlookAgentState(agentName, { ...options, bundlesRoot, now: () => now }));
366
- const degradedIssues = agentStates
367
- .flatMap((state) => state.degraded.issues.map((problem) => issue("agent-degraded", `${state.agentName}: ${problem.detail}`)));
368
- const freshest = agentStates
369
- .map((state) => state.freshness.latestActivityAt)
370
- .filter((value) => typeof value === "string")
371
- .sort((left, right) => right.localeCompare(left))[0] ?? null;
372
- return {
373
- productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
374
- observedAt: now.toISOString(),
375
- runtime,
376
- agentCount: agentStates.length,
377
- freshness: summarizeFreshness(freshest, now),
378
- degraded: summarizeDegraded(degradedIssues),
379
- agents: agentStates.map(summarizeAgent),
380
- };
381
- }
382
- // ---------------------------------------------------------------------------
383
- // Session inventory — enumerate all sessions with summary metadata
384
- // ---------------------------------------------------------------------------
385
- /* v8 ignore start — session envelope parsing utilities */
386
- function parseSessionUsage(raw) {
387
- if (!raw || typeof raw !== "object")
388
- return null;
389
- const record = raw;
390
- const inputTokens = typeof record.input_tokens === "number" ? record.input_tokens : 0;
391
- const outputTokens = typeof record.output_tokens === "number" ? record.output_tokens : 0;
392
- const reasoningTokens = typeof record.reasoning_tokens === "number" ? record.reasoning_tokens : 0;
393
- const totalTokens = typeof record.total_tokens === "number" ? record.total_tokens : 0;
394
- if (inputTokens === 0 && outputTokens === 0 && totalTokens === 0)
395
- return null;
396
- return { input_tokens: inputTokens, output_tokens: outputTokens, reasoning_tokens: reasoningTokens, total_tokens: totalTokens };
397
- }
398
- function parseSessionContinuity(raw) {
399
- if (!raw)
400
- return null;
401
- if (typeof raw !== "object")
402
- return null;
403
- const record = raw;
404
- const continuity = {
405
- mustResolveBeforeHandoff: record.mustResolveBeforeHandoff === true,
406
- lastFriendActivityAt: typeof record.lastFriendActivityAt === "string" ? record.lastFriendActivityAt : null,
407
- };
408
- if (!continuity.mustResolveBeforeHandoff && continuity.lastFriendActivityAt === null)
409
- return null;
410
- return continuity;
411
- }
412
- function extractContent(event) {
413
- if (!event)
414
- return null;
415
- const text = (0, session_events_1.extractEventText)(event);
416
- return text.length > 0 ? text : null;
417
- }
418
- function extractToolCallNames(event) {
419
- if (!event)
420
- return [];
421
- return event.toolCalls
422
- .map((call) => call.function.name)
423
- .filter((name) => typeof name === "string" && name.length > 0);
424
- }
425
- /* v8 ignore stop */
426
- function estimateTokenCount(messages) {
427
- let charCount = 0;
428
- for (const msg of messages) {
429
- const content = extractContent(msg);
430
- if (content)
431
- charCount += content.length;
432
- if (msg.toolCalls.length > 0)
433
- charCount += JSON.stringify(msg.toolCalls).length;
434
- }
435
- return Math.ceil(charCount / 4);
436
- }
437
- function readSessionEnvelope(sessionPath) {
438
- return (0, session_events_1.loadSessionEnvelopeFile)(sessionPath);
439
- }
440
- /* v8 ignore start — filesystem traversal with defensive isDirectory checks */
441
- function resolveAllSessionPaths(sessionsDir) {
442
- const results = [];
443
- if (!fs.existsSync(sessionsDir))
444
- return results;
445
- for (const friendId of safeReaddir(sessionsDir)) {
446
- const friendDir = path.join(sessionsDir, friendId);
447
- if (!safeIsDirectory(friendDir))
448
- continue;
449
- for (const channel of safeReaddir(friendDir)) {
450
- const channelDir = path.join(friendDir, channel);
451
- if (!safeIsDirectory(channelDir))
452
- continue;
453
- for (const file of safeReaddir(channelDir)) {
454
- if (!file.endsWith(".json"))
455
- continue;
456
- const key = file.slice(0, -5);
457
- results.push({
458
- friendId,
459
- channel,
460
- key,
461
- sessionPath: path.join(channelDir, file),
462
- });
463
- }
464
- }
465
- }
466
- return results;
467
- }
468
- /* v8 ignore stop */
469
- function safeReaddir(dir) {
470
- try {
471
- return fs.readdirSync(dir);
472
- }
473
- catch {
474
- return [];
475
- }
476
- }
477
- function safeIsDirectory(filePath) {
478
- try {
479
- return fs.statSync(filePath).isDirectory();
480
- /* v8 ignore start */
481
- }
482
- catch {
483
- return false;
484
- }
485
- /* v8 ignore stop */
486
- }
487
- /* v8 ignore start — defensive friend name resolution */
488
- function resolveFriendName(friendsDir, friendId) {
489
- try {
490
- const raw = fs.readFileSync(path.join(friendsDir, `${friendId}.json`), "utf-8");
491
- const parsed = JSON.parse(raw);
492
- return typeof parsed.name === "string" ? parsed.name : friendId;
493
- }
494
- catch {
495
- return friendId;
496
- }
497
- }
498
- /* v8 ignore stop */
499
- /* v8 ignore start — session inventory with defensive parsing */
500
- function readSessionInventory(agentName, options = {}) {
501
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
502
- const now = options.now?.() ?? new Date();
503
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
504
- const sessionsDir = path.join(agentRoot, "state", "sessions");
505
- const friendsDir = path.join(agentRoot, "friends");
506
- const allSessions = resolveAllSessionPaths(sessionsDir);
507
- const items = [];
508
- for (const { friendId, channel, key, sessionPath } of allSessions) {
509
- if (friendId === "self" && channel === "inner")
510
- continue;
511
- const envelope = readSessionEnvelope(sessionPath);
512
- const events = envelope?.events ?? [];
513
- const chronology = (0, session_events_1.deriveSessionChronology)(events);
514
- const lastUsage = parseSessionUsage(envelope?.lastUsage);
515
- const continuity = parseSessionContinuity(envelope?.state);
516
- const hasObservedEventTiming = events.some((event) => event.time.authoredAt !== null || event.time.observedAt !== null);
517
- const lastActivityAt = hasObservedEventTiming
518
- ? (chronology.lastActivityAt ?? continuity?.lastFriendActivityAt ?? safeFileMtime(sessionPath) ?? now.toISOString())
519
- : (continuity?.lastFriendActivityAt ?? safeFileMtime(sessionPath) ?? now.toISOString());
520
- const activitySource = hasObservedEventTiming && chronology.lastActivityAt
521
- ? "event-timeline"
522
- : continuity?.lastFriendActivityAt
523
- ? "friend-facing"
524
- : "mtime-fallback";
525
- const userMessages = events.filter((m) => m.role === "user");
526
- const assistantMessages = events.filter((m) => m.role === "assistant");
527
- const lastUser = userMessages.length > 0 ? userMessages[userMessages.length - 1] : null;
528
- const lastAssistant = assistantMessages.length > 0 ? assistantMessages[assistantMessages.length - 1] : null;
529
- const latestToolCallNames = [];
530
- for (let i = events.length - 1; i >= 0; i--) {
531
- const names = extractToolCallNames(events[i]);
532
- if (names.length > 0) {
533
- latestToolCallNames.push(...names);
534
- break;
535
- }
536
- }
537
- const friendName = resolveFriendName(friendsDir, friendId);
538
- // Derive reply state from message pattern
539
- const lastMsg = events.length > 0 ? events[events.length - 1] : null;
540
- const mustResolve = continuity?.mustResolveBeforeHandoff === true;
541
- let replyState = "idle";
542
- if (mustResolve) {
543
- replyState = "on-hold";
544
- }
545
- else if (lastMsg?.role === "user") {
546
- replyState = "needs-reply";
547
- }
548
- else if (events.length > 0) {
549
- replyState = "monitoring";
550
- }
551
- items.push({
552
- friendId,
553
- friendName,
554
- channel,
555
- key,
556
- sessionPath,
557
- lastActivityAt,
558
- activitySource,
559
- replyState,
560
- messageCount: events.length,
561
- lastUsage,
562
- continuity,
563
- latestUserExcerpt: truncateExcerpt(extractContent(lastUser)),
564
- latestAssistantExcerpt: truncateExcerpt(extractContent(lastAssistant)),
565
- latestToolCallNames,
566
- estimatedTokens: events.length > 0 ? estimateTokenCount(events) : null,
567
- });
568
- }
569
- items.sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));
570
- const ageThreshold = now.getTime() - STALE_THRESHOLD_MS;
571
- const activeCount = items.filter((item) => Date.parse(item.lastActivityAt) >= ageThreshold).length;
572
- return {
573
- totalCount: items.length,
574
- activeCount,
575
- staleCount: items.length - activeCount,
576
- items,
577
- };
578
- }
579
- /* v8 ignore start — utility helpers with defensive branches */
580
- function truncateExcerpt(content, maxLength = 200) {
581
- if (!content)
582
- return null;
583
- if (content.length <= maxLength)
584
- return content;
585
- const truncated = content.slice(0, maxLength);
586
- const lastSpace = truncated.lastIndexOf(" ");
587
- return (lastSpace > maxLength * 0.6 ? truncated.slice(0, lastSpace) : truncated) + "…";
588
- }
589
- function safeFileMtime(filePath) {
590
- try {
591
- return fs.statSync(filePath).mtime.toISOString();
592
- }
593
- catch {
594
- return null;
595
- }
596
- }
597
- /* v8 ignore stop */
598
- // ---------------------------------------------------------------------------
599
- /* v8 ignore stop */
600
- // Session transcript — full x-ray of one session
601
- // ---------------------------------------------------------------------------
602
- /* v8 ignore start — defensive parsing */
603
- function readSessionTranscript(agentName, friendId, channel, key, options = {}) {
604
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
605
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
606
- const sessionPath = path.join(agentRoot, "state", "sessions", friendId, channel, `${key}.json`);
607
- const envelope = readSessionEnvelope(sessionPath);
608
- if (!envelope)
609
- return null;
610
- const rawMessages = envelope.events;
611
- const friendsDir = path.join(agentRoot, "friends");
612
- const friendName = resolveFriendName(friendsDir, friendId);
613
- const messages = rawMessages;
614
- return {
615
- friendId,
616
- friendName,
617
- channel,
618
- key,
619
- sessionPath,
620
- messageCount: messages.length,
621
- lastUsage: parseSessionUsage(envelope.lastUsage),
622
- continuity: parseSessionContinuity(envelope.state),
623
- messages,
624
- };
625
- }
626
- // ---------------------------------------------------------------------------
627
- // Coding deep — full details for all coding sessions
628
- // ---------------------------------------------------------------------------
629
- /* v8 ignore start — defensive parsing of on-disk JSON, fallback branches are safety nets */
630
- function readCodingDeep(agentRoot) {
631
- const stateFilePath = path.join(agentRoot, "state", "coding", "sessions.json");
632
- if (!fs.existsSync(stateFilePath)) {
633
- return { totalCount: 0, activeCount: 0, blockedCount: 0, items: [] };
634
- }
635
- let parsed;
636
- try {
637
- parsed = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));
638
- }
639
- catch {
640
- return { totalCount: 0, activeCount: 0, blockedCount: 0, items: [] };
641
- }
642
- const items = Array.isArray(parsed.records)
643
- ? parsed.records.flatMap((record) => {
644
- const s = record?.session;
645
- if (!s || typeof s.id !== "string" || typeof s.status !== "string")
646
- return [];
647
- const checkpoint = typeof s.checkpoint === "string" ? s.checkpoint
648
- : typeof s.stderrTail === "string" && s.stderrTail.trim().length > 0 ? s.stderrTail.trim()
649
- : typeof s.stdoutTail === "string" && s.stdoutTail.trim().length > 0 ? s.stdoutTail.trim()
650
- : null;
651
- const originSession = s.originSession;
652
- const normalizedOrigin = originSession
653
- && typeof originSession.friendId === "string"
654
- && typeof originSession.channel === "string"
655
- && typeof originSession.key === "string"
656
- ? { friendId: originSession.friendId, channel: originSession.channel, key: originSession.key }
657
- : null;
658
- const failure = s.failure;
659
- const normalizedFailure = failure && typeof failure === "object"
660
- ? {
661
- command: typeof failure.command === "string" ? failure.command : "",
662
- args: Array.isArray(failure.args) ? failure.args.map(String) : [],
663
- code: typeof failure.code === "number" ? failure.code : null,
664
- signal: typeof failure.signal === "string" ? failure.signal : null,
665
- stdoutTail: typeof failure.stdoutTail === "string" ? failure.stdoutTail : "",
666
- stderrTail: typeof failure.stderrTail === "string" ? failure.stderrTail : "",
667
- }
668
- : null;
669
- return [{
670
- id: s.id,
671
- runner: (typeof s.runner === "string" ? s.runner : "claude"),
672
- status: s.status,
673
- checkpoint,
674
- taskRef: typeof s.taskRef === "string" ? s.taskRef : null,
675
- workdir: typeof s.workdir === "string" ? s.workdir : "",
676
- originSession: normalizedOrigin,
677
- obligationId: typeof s.obligationId === "string" ? s.obligationId : null,
678
- scopeFile: typeof s.scopeFile === "string" ? s.scopeFile : null,
679
- stateFile: typeof s.stateFile === "string" ? s.stateFile : null,
680
- artifactPath: typeof s.artifactPath === "string" ? s.artifactPath : null,
681
- pid: typeof s.pid === "number" ? s.pid : null,
682
- startedAt: typeof s.startedAt === "string" ? s.startedAt : "",
683
- lastActivityAt: typeof s.lastActivityAt === "string" ? s.lastActivityAt : "",
684
- endedAt: typeof s.endedAt === "string" ? s.endedAt : null,
685
- restartCount: typeof s.restartCount === "number" ? s.restartCount : 0,
686
- lastExitCode: typeof s.lastExitCode === "number" ? s.lastExitCode : null,
687
- lastSignal: typeof s.lastSignal === "string" ? s.lastSignal : null,
688
- stdoutTail: typeof s.stdoutTail === "string" ? s.stdoutTail : "",
689
- stderrTail: typeof s.stderrTail === "string" ? s.stderrTail : "",
690
- failure: normalizedFailure,
691
- }];
692
- })
693
- : [];
694
- return {
695
- totalCount: items.length,
696
- activeCount: items.filter((item) => ACTIVE_CODING_STATUSES.has(item.status)).length,
697
- blockedCount: items.filter((item) => BLOCKED_CODING_STATUSES.has(item.status)).length,
698
- items,
699
- };
700
- }
701
- // ---------------------------------------------------------------------------
702
- // Attention / pending / inbox
703
- // ---------------------------------------------------------------------------
704
- /* v8 ignore stop */
705
- function scanPendingChannels(agentRoot) {
706
- const pendingRoot = path.join(agentRoot, "state", "pending");
707
- const channels = [];
708
- for (const friendId of safeReaddir(pendingRoot)) {
709
- if (friendId === "self")
710
- continue;
711
- const friendDir = path.join(pendingRoot, friendId);
712
- if (!safeIsDirectory(friendDir))
713
- continue;
714
- for (const channel of safeReaddir(friendDir)) {
715
- const channelDir = path.join(friendDir, channel);
716
- if (!safeIsDirectory(channelDir))
717
- continue;
718
- for (const key of safeReaddir(channelDir)) {
719
- const keyDir = path.join(channelDir, key);
720
- if (!safeIsDirectory(keyDir))
721
- continue;
722
- const files = safeReaddir(keyDir).filter((f) => f.endsWith(".json") || f.endsWith(".json.processing"));
723
- if (files.length > 0) {
724
- channels.push({ friendId, channel, key, messageCount: files.length });
725
- }
726
- }
727
- }
728
- }
729
- return channels;
730
- }
731
- function readPendingMessagesNonDestructive(pendingDir) {
732
- const files = safeReaddir(pendingDir).filter((f) => f.endsWith(".json") || f.endsWith(".json.processing"));
733
- const messages = [];
734
- for (const file of files.sort()) {
735
- try {
736
- const raw = fs.readFileSync(path.join(pendingDir, file), "utf-8");
737
- messages.push(JSON.parse(raw));
738
- }
739
- catch {
740
- // skip unparseable pending messages
741
- }
742
- }
743
- return messages;
744
- }
745
- /* v8 ignore stop */
746
- function readAttentionView(agentName, options = {}) {
747
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
748
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
749
- const friendsDir = path.join(agentRoot, "friends");
750
- const pendingChannels = scanPendingChannels(agentRoot);
751
- // Build attention queue items from pending messages across all channels
752
- const queueItems = [];
753
- const pendingRoot = path.join(agentRoot, "state", "pending");
754
- for (const pending of pendingChannels) {
755
- const pendingDir = path.join(pendingRoot, pending.friendId, pending.channel, pending.key);
756
- const messages = readPendingMessagesNonDestructive(pendingDir);
757
- for (const msg of messages) {
758
- const delegatedFrom = msg.delegatedFrom;
759
- queueItems.push({
760
- id: typeof msg.timestamp === "number" ? `${msg.timestamp}-${pending.friendId}` : `pending-${Date.now()}`,
761
- friendId: pending.friendId,
762
- friendName: resolveFriendName(friendsDir, pending.friendId),
763
- channel: pending.channel,
764
- key: pending.key,
765
- bridgeId: delegatedFrom && typeof delegatedFrom.bridgeId === "string" ? delegatedFrom.bridgeId : null,
766
- delegatedContent: typeof msg.content === "string" ? msg.content : "",
767
- obligationId: typeof msg.obligationId === "string" ? msg.obligationId : null,
768
- source: "pending",
769
- timestamp: typeof msg.timestamp === "number" ? msg.timestamp : 0,
770
- });
771
- }
772
- }
773
- queueItems.sort((a, b) => a.timestamp - b.timestamp);
774
- // Return obligations
775
- const returnObligations = readObligationSummary(agentRoot).items;
776
- return {
777
- queueLength: queueItems.length,
778
- queueItems,
779
- pendingChannels,
780
- returnObligations,
781
- };
782
- }
783
- // ---------------------------------------------------------------------------
784
- // Bridge inventory — all bridge records
785
- // ---------------------------------------------------------------------------
786
- /* v8 ignore start — defensive parsing */
787
- function readBridgeInventory(agentRoot) {
788
- const bridgesDir = path.join(agentRoot, "state", "bridges");
789
- const items = [];
790
- for (const file of safeReaddir(bridgesDir)) {
791
- if (!file.endsWith(".json"))
792
- continue;
793
- try {
794
- const raw = fs.readFileSync(path.join(bridgesDir, file), "utf-8");
795
- const bridge = JSON.parse(raw);
796
- if (typeof bridge.id !== "string")
797
- continue;
798
- const attachedSessions = Array.isArray(bridge.attachedSessions)
799
- ? bridge.attachedSessions
800
- .filter((s) => typeof s.friendId === "string")
801
- .map((s) => ({
802
- friendId: s.friendId,
803
- channel: typeof s.channel === "string" ? s.channel : "",
804
- key: typeof s.key === "string" ? s.key : "",
805
- sessionPath: typeof s.sessionPath === "string" ? s.sessionPath : "",
806
- snapshot: typeof s.snapshot === "string" ? s.snapshot : null,
807
- }))
808
- : [];
809
- const taskLink = bridge.task;
810
- const normalizedTask = taskLink && typeof taskLink === "object" && typeof taskLink.taskName === "string"
811
- ? {
812
- taskName: taskLink.taskName,
813
- path: typeof taskLink.path === "string" ? taskLink.path : "",
814
- mode: typeof taskLink.mode === "string" ? taskLink.mode : "bound",
815
- boundAt: typeof taskLink.boundAt === "string" ? taskLink.boundAt : "",
816
- }
817
- : null;
818
- items.push({
819
- id: bridge.id,
820
- objective: typeof bridge.objective === "string" ? bridge.objective : "",
821
- summary: typeof bridge.summary === "string" ? bridge.summary : "",
822
- lifecycle: typeof bridge.lifecycle === "string" ? bridge.lifecycle : "unknown",
823
- runtime: typeof bridge.runtime === "string" ? bridge.runtime : "unknown",
824
- createdAt: typeof bridge.createdAt === "string" ? bridge.createdAt : "",
825
- updatedAt: typeof bridge.updatedAt === "string" ? bridge.updatedAt : "",
826
- attachedSessions,
827
- task: normalizedTask,
828
- });
829
- }
830
- catch {
831
- // skip unparseable bridge files
832
- }
833
- }
834
- items.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
835
- const activeCount = items.filter((item) => item.lifecycle === "active").length;
836
- return {
837
- totalCount: items.length,
838
- activeCount,
839
- items,
840
- };
841
- }
842
- // ---------------------------------------------------------------------------
843
- // Daemon health deep
844
- // ---------------------------------------------------------------------------
845
- /* v8 ignore stop */
846
- /* v8 ignore start — defensive parsing */
847
- function readDaemonHealthDeep(healthPath) {
848
- const resolvedPath = healthPath ?? path.join(process.env.HOME ?? "", ".ouro-cli", "daemon-health.json");
849
- try {
850
- const raw = fs.readFileSync(resolvedPath, "utf-8");
851
- const health = JSON.parse(raw);
852
- return {
853
- status: typeof health.status === "string" ? health.status : "unknown",
854
- mode: typeof health.mode === "string" ? health.mode : "unknown",
855
- pid: typeof health.pid === "number" ? health.pid : 0,
856
- startedAt: typeof health.startedAt === "string" ? health.startedAt : "",
857
- uptimeSeconds: typeof health.uptimeSeconds === "number" ? health.uptimeSeconds : 0,
858
- safeMode: health.safeMode && typeof health.safeMode === "object"
859
- ? {
860
- active: health.safeMode.active === true,
861
- reason: typeof health.safeMode.reason === "string" ? health.safeMode.reason : "",
862
- enteredAt: typeof health.safeMode.enteredAt === "string" ? health.safeMode.enteredAt : "",
863
- }
864
- : null,
865
- degradedComponents: Array.isArray(health.degraded)
866
- ? health.degraded.map((c) => ({
867
- component: typeof c.component === "string" ? c.component : "",
868
- reason: typeof c.reason === "string" ? c.reason : "",
869
- since: typeof c.since === "string" ? c.since : "",
870
- }))
871
- : [],
872
- agentHealth: health.agents && typeof health.agents === "object"
873
- ? Object.fromEntries(Object.entries(health.agents).map(([name, entry]) => [
874
- name,
875
- {
876
- status: typeof entry.status === "string" ? entry.status : "unknown",
877
- pid: typeof entry.pid === "number" ? entry.pid : null,
878
- crashes: typeof entry.crashes === "number" ? entry.crashes : 0,
879
- },
880
- ]))
881
- : {},
882
- habitHealth: health.habits && typeof health.habits === "object"
883
- ? Object.fromEntries(Object.entries(health.habits).map(([name, entry]) => [
884
- name,
885
- {
886
- cronStatus: typeof entry.cronStatus === "string" ? entry.cronStatus : "unknown",
887
- lastFired: typeof entry.lastFired === "string" ? entry.lastFired : null,
888
- fallback: entry.fallback === true,
889
- },
890
- ]))
891
- : {},
892
- };
893
- }
894
- catch {
895
- return null;
896
- }
897
- }
898
- // ---------------------------------------------------------------------------
899
- // Memory / journal inspection
900
- // ---------------------------------------------------------------------------
901
- /* v8 ignore stop */
902
- /* v8 ignore start — defensive parsing */
903
- function readMemoryView(agentRoot) {
904
- // Read diary entries from facts.jsonl
905
- const diaryRoot = path.join(agentRoot, "diary");
906
- const effectiveDiaryRoot = fs.existsSync(diaryRoot) ? diaryRoot : null;
907
- const diaryEntries = [];
908
- if (effectiveDiaryRoot) {
909
- const factsPath = path.join(effectiveDiaryRoot, "facts.jsonl");
910
- try {
911
- const raw = fs.readFileSync(factsPath, "utf-8");
912
- for (const line of raw.split("\n")) {
913
- if (!line.trim())
914
- continue;
915
- try {
916
- const entry = JSON.parse(line);
917
- if (typeof entry.id === "string" && typeof entry.text === "string") {
918
- diaryEntries.push({
919
- id: entry.id,
920
- text: entry.text,
921
- source: typeof entry.source === "string" ? entry.source : "",
922
- createdAt: typeof entry.createdAt === "string" ? entry.createdAt : "",
923
- });
924
- }
925
- }
926
- catch {
927
- // skip unparseable lines
928
- }
929
- }
930
- }
931
- catch {
932
- // no diary facts file
933
- }
934
- }
935
- // Sort by createdAt descending, take recent
936
- diaryEntries.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
937
- // Read journal index
938
- const journalDir = path.join(agentRoot, "journal");
939
- const journalEntries = [];
940
- const indexPath = path.join(journalDir, ".index.json");
941
- try {
942
- const raw = fs.readFileSync(indexPath, "utf-8");
943
- const index = JSON.parse(raw);
944
- if (Array.isArray(index)) {
945
- for (const entry of index) {
946
- if (typeof entry.filename === "string") {
947
- journalEntries.push({
948
- filename: entry.filename,
949
- preview: typeof entry.preview === "string" ? entry.preview : "",
950
- mtime: typeof entry.mtime === "number" ? entry.mtime : 0,
951
- });
952
- }
953
- }
954
- }
955
- }
956
- catch {
957
- // no journal index
958
- }
959
- journalEntries.sort((a, b) => b.mtime - a.mtime);
960
- return {
961
- diaryEntryCount: diaryEntries.length,
962
- recentDiaryEntries: diaryEntries.slice(0, 20),
963
- journalEntryCount: journalEntries.length,
964
- recentJournalEntries: journalEntries.slice(0, 20),
965
- };
966
- }
967
- // ---------------------------------------------------------------------------
968
- // Friend / relationship economics
969
- // ---------------------------------------------------------------------------
970
- /* v8 ignore stop */
971
- function readFriendView(agentName, options = {}) {
972
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
973
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
974
- const friendsDir = path.join(agentRoot, "friends");
975
- const sessionsDir = path.join(agentRoot, "state", "sessions");
976
- const friends = [];
977
- for (const file of safeReaddir(friendsDir)) {
978
- if (!file.endsWith(".json"))
979
- continue;
980
- const friendId = file.slice(0, -5);
981
- try {
982
- const raw = fs.readFileSync(path.join(friendsDir, file), "utf-8");
983
- const record = JSON.parse(raw);
984
- // Count sessions and channels for this friend
985
- const friendSessionsDir = path.join(sessionsDir, friendId);
986
- const channels = new Set();
987
- let sessionCount = 0;
988
- let latestActivity = null;
989
- for (const channel of safeReaddir(friendSessionsDir)) {
990
- const channelDir = path.join(friendSessionsDir, channel);
991
- if (!safeIsDirectory(channelDir))
992
- continue;
993
- for (const keyFile of safeReaddir(channelDir)) {
994
- if (!keyFile.endsWith(".json"))
995
- continue;
996
- channels.add(channel);
997
- sessionCount++;
998
- const mtime = safeFileMtime(path.join(channelDir, keyFile));
999
- if (mtime && (!latestActivity || mtime > latestActivity)) {
1000
- latestActivity = mtime;
1001
- }
1002
- }
1003
- }
1004
- friends.push({
1005
- friendId,
1006
- friendName: typeof record.name === "string" ? record.name : friendId,
1007
- totalTokens: typeof record.totalTokens === "number" ? record.totalTokens : 0,
1008
- sessionCount,
1009
- channels: [...channels].sort(),
1010
- lastActivityAt: latestActivity,
1011
- });
1012
- }
1013
- catch {
1014
- // skip unparseable friend records
1015
- }
1016
- }
1017
- friends.sort((a, b) => b.totalTokens - a.totalTokens);
1018
- return {
1019
- totalFriends: friends.length,
1020
- friends,
1021
- };
1022
- }
1023
- // ---------------------------------------------------------------------------
1024
- // Log / event reading (NDJSON)
1025
- // ---------------------------------------------------------------------------
1026
- function readLogView(logPath, limit = 100) {
1027
- if (!logPath || !fs.existsSync(logPath)) {
1028
- return { logPath, totalLines: 0, entries: [] };
1029
- }
1030
- try {
1031
- const raw = fs.readFileSync(logPath, "utf-8");
1032
- const lines = raw.split("\n").filter((l) => l.trim().length > 0);
1033
- const totalLines = lines.length;
1034
- const recentLines = lines.slice(-limit);
1035
- const entries = [];
1036
- for (const line of recentLines) {
1037
- try {
1038
- const parsed = JSON.parse(line);
1039
- entries.push({
1040
- ts: typeof parsed.ts === "string" ? parsed.ts : "",
1041
- level: typeof parsed.level === "string" ? parsed.level : "info",
1042
- event: typeof parsed.event === "string" ? parsed.event : "",
1043
- component: typeof parsed.component === "string" ? parsed.component : "",
1044
- message: typeof parsed.message === "string" ? parsed.message : "",
1045
- trace_id: typeof parsed.trace_id === "string" ? parsed.trace_id : "",
1046
- meta: parsed.meta && typeof parsed.meta === "object" ? parsed.meta : {},
1047
- });
1048
- }
1049
- catch {
1050
- // skip unparseable log lines
1051
- }
1052
- }
1053
- return { logPath, totalLines, entries };
1054
- }
1055
- catch { /* v8 ignore next */
1056
- return { logPath, totalLines: 0, entries: [] };
1057
- }
1058
- }
1059
- // ---------------------------------------------------------------------------
1060
- // Habit inspection
1061
- // ---------------------------------------------------------------------------
1062
- function readHabitView(agentRoot, options = {}) {
1063
- const habitsDir = path.join(agentRoot, "habits");
1064
- const now = options.now?.() ?? new Date();
1065
- const items = [];
1066
- for (const file of safeReaddir(habitsDir)) {
1067
- if (!file.endsWith(".md"))
1068
- continue;
1069
- try {
1070
- const raw = fs.readFileSync(path.join(habitsDir, file), "utf-8");
1071
- const habit = parseHabitFrontmatter(raw);
1072
- if (!habit)
1073
- continue;
1074
- const cadenceMs = parseCadenceMs(habit.cadence);
1075
- let isOverdue = false;
1076
- let overdueMs = null;
1077
- if (habit.status === "active" && habit.lastRun && cadenceMs) {
1078
- const elapsed = now.getTime() - Date.parse(habit.lastRun);
1079
- if (elapsed > cadenceMs) {
1080
- isOverdue = true;
1081
- overdueMs = elapsed - cadenceMs;
1082
- }
1083
- }
1084
- items.push({
1085
- name: habit.name ?? file.slice(0, -3),
1086
- title: habit.title ?? file.slice(0, -3),
1087
- cadence: habit.cadence,
1088
- status: habit.status === "paused" ? "paused" : "active",
1089
- lastRun: habit.lastRun,
1090
- bodyExcerpt: truncateExcerpt(habit.body, 120),
1091
- isDegraded: false,
1092
- degradedReason: null,
1093
- isOverdue,
1094
- overdueMs,
1095
- });
1096
- }
1097
- catch {
1098
- // skip unparseable habit files
1099
- }
1100
- }
1101
- items.sort((a, b) => {
1102
- if (a.isOverdue && !b.isOverdue)
1103
- return -1;
1104
- if (!a.isOverdue && b.isOverdue)
1105
- return 1;
1106
- return a.name.localeCompare(b.name);
1107
- });
1108
- return {
1109
- totalCount: items.length,
1110
- activeCount: items.filter((h) => h.status === "active").length,
1111
- pausedCount: items.filter((h) => h.status === "paused").length,
1112
- degradedCount: items.filter((h) => h.isDegraded).length,
1113
- overdueCount: items.filter((h) => h.isOverdue).length,
1114
- items,
1115
- };
1116
- }
1117
- function parseHabitFrontmatter(content) {
1118
- const fmMatch = /^---\n([\s\S]*?)\n---/.exec(content);
1119
- if (!fmMatch)
1120
- return null;
1121
- const fm = fmMatch[1];
1122
- const body = content.slice(fmMatch[0].length).trim() || null;
1123
- function extract(key) {
1124
- const match = new RegExp(`^${key}:\\s*(.+)$`, "m").exec(fm);
1125
- return match ? match[1].trim() : null;
1126
- }
1127
- return {
1128
- name: extract("name"),
1129
- title: extract("title"),
1130
- cadence: extract("cadence"),
1131
- status: extract("status"),
1132
- lastRun: extract("lastRun") ?? extract("last_run"),
1133
- body,
1134
- };
1135
- }
1136
- // ---------------------------------------------------------------------------
1137
- // "What needs me now" — aggregates across all surfaces
1138
- // ---------------------------------------------------------------------------
1139
- /* v8 ignore start — defensive parsing in needs-me aggregator */
1140
- function readNeedsMeView(agentName, options = {}) {
1141
- const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
1142
- const now = options.now?.() ?? new Date();
1143
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
1144
- const items = [];
1145
- // Load dismissed obligations to filter them out
1146
- const prefs = readDeskPrefs(agentRoot);
1147
- const dismissed = new Set(prefs.dismissedObligations);
1148
- // 1. Sessions that need a reply (last message is from user)
1149
- const sessions = readSessionInventory(agentName, options);
1150
- for (const s of sessions.items) {
1151
- if (s.replyState === "needs-reply") {
1152
- items.push({
1153
- urgency: "owed-reply",
1154
- label: `${s.friendName} is waiting for a reply`,
1155
- detail: `via ${s.channel} · ${s.latestUserExcerpt ? truncateExcerpt(s.latestUserExcerpt, 80) ?? "" : ""}`,
1156
- ref: { tab: "sessions", focus: `${s.friendId}/${s.channel}/${s.key}` },
1157
- ageMs: now.getTime() - Date.parse(s.lastActivityAt),
1158
- });
1159
- }
1160
- }
1161
- // 2. Obligations that are blocking or stale
1162
- const obligations = readObligationSummary(agentRoot);
1163
- for (const o of obligations.items) {
1164
- if (dismissed.has(o.id))
1165
- continue;
1166
- const ageMs = now.getTime() - Date.parse(o.updatedAt);
1167
- const isStale = ageMs > 24 * 60 * 60 * 1000;
1168
- // Return-ready: obligation has a surface (result exists) but status is still open
1169
- const hasResult = o.currentSurface !== null;
1170
- const isOpen = o.status === "pending" || o.status === "investigating" || o.status === "waiting_for_merge" || o.status === "updating_runtime";
1171
- if (isOpen) {
1172
- items.push({
1173
- urgency: hasResult ? "return-ready" : isStale ? "stale-delegation" : "blocking-obligation",
1174
- label: truncateExcerpt(o.content, 80) ?? o.id,
1175
- detail: hasResult ? `result ready — ${o.currentSurface.kind}: ${o.currentSurface.label}` : `${o.status}${o.nextAction ? ` · next: ${o.nextAction}` : ""}`,
1176
- ref: { tab: "work", focus: o.id },
1177
- ageMs,
1178
- });
1179
- }
1180
- }
1181
- // 3. Pending attention queue items (someone delegated work that hasn't been picked up)
1182
- const pendingChannels = scanPendingChannels(agentRoot);
1183
- for (const p of pendingChannels) {
1184
- if (p.friendId === "self")
1185
- continue;
1186
- const friendName = resolveFriendName(path.join(agentRoot, "friends"), p.friendId);
1187
- items.push({
1188
- urgency: "stale-delegation",
1189
- label: `${p.messageCount} pending from ${friendName}`,
1190
- detail: `${p.channel}/${p.key}`,
1191
- ref: { tab: "connections" },
1192
- ageMs: null,
1193
- });
1194
- }
1195
- // 4. Overdue habits
1196
- const habits = readHabitView(agentRoot, options);
1197
- for (const h of habits.items) {
1198
- if (h.isOverdue) {
1199
- items.push({
1200
- urgency: "overdue-habit",
1201
- label: `${h.title} is overdue`,
1202
- detail: h.cadence ? `every ${h.cadence} · last ${h.lastRun ?? "never"}` : "no cadence set",
1203
- ref: { tab: "inner" },
1204
- ageMs: h.overdueMs,
1205
- });
1206
- }
1207
- }
1208
- // Sort: owed replies first, then blocking obligations, then stale, then habits
1209
- const urgencyOrder = {
1210
- "owed-reply": 0,
1211
- "blocking-obligation": 1,
1212
- "broken-return": 2,
1213
- "stale-delegation": 3,
1214
- "return-ready": 4,
1215
- "overdue-habit": 5,
1216
- };
1217
- items.sort((a, b) => (urgencyOrder[a.urgency] ?? 99) - (urgencyOrder[b.urgency] ?? 99));
1218
- return { items };
1219
- }
1220
- // ---------------------------------------------------------------------------
1221
- // Agent desk preferences
1222
- // ---------------------------------------------------------------------------
1223
- /* v8 ignore stop */
1224
- /* v8 ignore start — defensive JSON parsing in desk prefs reader */
1225
- function readDeskPrefs(agentRoot) {
1226
- const prefsPath = path.join(agentRoot, "state", "outlook-prefs.json");
1227
- const defaults = {
1228
- carrying: null,
1229
- statusLine: null,
1230
- tabOrder: null,
1231
- starredFriends: [],
1232
- pinnedConstellations: [],
1233
- dismissedObligations: [],
1234
- };
1235
- try {
1236
- const raw = fs.readFileSync(prefsPath, "utf-8");
1237
- const parsed = JSON.parse(raw);
1238
- return {
1239
- carrying: typeof parsed.carrying === "string" ? parsed.carrying : null,
1240
- statusLine: typeof parsed.statusLine === "string" ? parsed.statusLine : null,
1241
- tabOrder: Array.isArray(parsed.tabOrder) ? parsed.tabOrder.filter((t) => typeof t === "string") : null,
1242
- starredFriends: Array.isArray(parsed.starredFriends) ? parsed.starredFriends.filter((f) => typeof f === "string") : [],
1243
- pinnedConstellations: Array.isArray(parsed.pinnedConstellations)
1244
- ? parsed.pinnedConstellations.map((c) => ({
1245
- label: typeof c.label === "string" ? c.label : "",
1246
- friendIds: Array.isArray(c.friendIds) ? c.friendIds.filter((f) => typeof f === "string") : [],
1247
- taskRefs: Array.isArray(c.taskRefs) ? c.taskRefs.filter((t) => typeof t === "string") : [],
1248
- bridgeIds: Array.isArray(c.bridgeIds) ? c.bridgeIds.filter((b) => typeof b === "string") : [],
1249
- codingIds: Array.isArray(c.codingIds) ? c.codingIds.filter((c2) => typeof c2 === "string") : [],
1250
- }))
1251
- : [],
1252
- dismissedObligations: Array.isArray(parsed.dismissedObligations) ? parsed.dismissedObligations.filter((id) => typeof id === "string") : [],
1253
- };
1254
- }
1255
- catch {
1256
- return defaults;
1257
- }
1258
- }
1259
- /* v8 ignore stop */
1260
- function parseCadenceMs(cadence) {
1261
- if (!cadence)
1262
- return null;
1263
- const match = /^(\d+)\s*(m|min|h|hr|d|day)s?$/i.exec(cadence.trim());
1264
- if (!match)
1265
- return null;
1266
- const value = parseInt(match[1], 10);
1267
- const unit = match[2].toLowerCase();
1268
- if (unit === "m" || unit === "min")
1269
- return value * 60 * 1000;
1270
- if (unit === "h" || unit === "hr")
1271
- return value * 60 * 60 * 1000;
1272
- if (unit === "d" || unit === "day")
1273
- return value * 24 * 60 * 60 * 1000;
1274
- /* v8 ignore next */
1275
- return null;
1276
- }
1277
- // ---------------------------------------------------------------------------
1278
- // Continuity — presence, cares, episodes for outlook surfaces
1279
- // ---------------------------------------------------------------------------
1280
- function readOutlookContinuity(agentRoot, agentName) {
1281
- const self = (0, presence_1.readPresence)(agentRoot, agentName);
1282
- const peers = (0, presence_1.readPeerPresence)(agentRoot);
1283
- const cares = (0, cares_1.readActiveCares)(agentRoot);
1284
- const episodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 10 });
1285
- (0, runtime_1.emitNervesEvent)({
1286
- component: "heart",
1287
- event: "heart.outlook_continuity_read",
1288
- message: `outlook continuity: ${cares.length} cares, ${episodes.length} episodes`,
1289
- meta: { careCount: cares.length, episodeCount: episodes.length, hasSelf: self != null, peerCount: peers.length },
1290
- });
1291
- return {
1292
- presence: { self, peers },
1293
- cares: {
1294
- activeCount: cares.length,
1295
- items: cares.map((c) => ({
1296
- id: c.id,
1297
- label: c.label,
1298
- status: c.status,
1299
- salience: c.salience,
1300
- })),
1301
- },
1302
- episodes: {
1303
- recentCount: episodes.length,
1304
- items: episodes.map((ep) => ({
1305
- id: ep.id,
1306
- kind: ep.kind,
1307
- summary: ep.summary,
1308
- timestamp: ep.timestamp,
1309
- })),
1310
- },
1311
- };
1312
- }
1313
- // ---------------------------------------------------------------------------
1314
- // Orientation reader — daemon-side assembly of "where am I?"
1315
- // ---------------------------------------------------------------------------
1316
- function readOrientationView(agentRoot, agentName) {
1317
- // Read obligations for primary selection
1318
- let obligations = [];
1319
- try {
1320
- obligations = (0, obligations_1.readObligations)(agentRoot);
1321
- }
1322
- catch {
1323
- obligations = [];
1324
- }
1325
- const openObligations = obligations.filter(obligations_1.isOpenObligation);
1326
- // Select primary obligation (most advanced status, then most recent)
1327
- const statusPriority = {
1328
- returning: 0,
1329
- collaborating: 1,
1330
- in_progress: 2,
1331
- delegated: 3,
1332
- accepted: 4,
1333
- pending: 5,
1334
- };
1335
- const sorted = [...openObligations].sort((a, b) => {
1336
- const sp = (statusPriority[a.status] ?? 99) - (statusPriority[b.status] ?? 99);
1337
- if (sp !== 0)
1338
- return sp;
1339
- const aMs = new Date(a.updatedAt ?? a.createdAt).getTime();
1340
- const bMs = new Date(b.updatedAt ?? b.createdAt).getTime();
1341
- return bMs - aMs;
1342
- });
1343
- const primary = sorted[0] ?? null;
1344
- // Read session activity for current session and others
1345
- let sessions = [];
1346
- try {
1347
- sessions = (0, session_activity_1.listSessionActivity)({
1348
- sessionsDir: path.join(agentRoot, "state", "sessions"),
1349
- friendsDir: path.join(agentRoot, "friends"),
1350
- agentName,
1351
- });
1352
- }
1353
- catch {
1354
- sessions = [];
1355
- }
1356
- const sortedSessions = [...sessions].sort((a, b) => b.lastActivityMs - a.lastActivityMs);
1357
- const currentSession = sortedSessions.length > 0
1358
- ? {
1359
- friendId: sortedSessions[0].friendId,
1360
- channel: sortedSessions[0].channel,
1361
- key: sortedSessions[0].key,
1362
- lastActivityAt: sortedSessions[0].lastActivityAt,
1363
- }
1364
- : null;
1365
- const otherActiveSessions = sortedSessions.slice(1).map((s) => ({
1366
- friendId: s.friendId,
1367
- friendName: s.friendName,
1368
- channel: s.channel,
1369
- key: s.key,
1370
- lastActivityAt: s.lastActivityAt,
1371
- }));
1372
- // Derive center of gravity summary
1373
- const parts = [];
1374
- if (primary)
1375
- parts.push(primary.content);
1376
- if (openObligations.length > 1)
1377
- parts.push(`${openObligations.length} open obligations`);
1378
- if (sessions.length > 0)
1379
- parts.push(`${sessions.length} active sessions`);
1380
- const centerOfGravity = parts.length > 0 ? parts.join(" | ") : "idle";
1381
- const primaryObligation = primary
1382
- ? {
1383
- id: primary.id,
1384
- content: primary.content,
1385
- status: primary.status,
1386
- nextAction: primary.nextAction ?? null,
1387
- waitingOn: primary.meaning?.waitingOn?.detail ?? null,
1388
- }
1389
- : null;
1390
- (0, runtime_1.emitNervesEvent)({
1391
- component: "heart",
1392
- event: "heart.outlook_orientation_read",
1393
- message: `outlook orientation: ${openObligations.length} obligations, ${sessions.length} sessions`,
1394
- meta: { obligationCount: openObligations.length, sessionCount: sessions.length, primaryId: primary?.id ?? null },
1395
- });
1396
- return {
1397
- currentSession,
1398
- centerOfGravity,
1399
- primaryObligation,
1400
- resumeHandle: null,
1401
- otherActiveSessions,
1402
- rawState: null,
1403
- };
1404
- }
1405
- // ---------------------------------------------------------------------------
1406
- // Obligation detail reader — richer view with primary selection context
1407
- // ---------------------------------------------------------------------------
1408
- function readObligationDetailView(agentRoot) {
1409
- let obligations = [];
1410
- try {
1411
- obligations = (0, obligations_1.readObligations)(agentRoot);
1412
- }
1413
- catch {
1414
- obligations = [];
1415
- }
1416
- const openObligations = obligations.filter(obligations_1.isOpenObligation);
1417
- // Select primary (same logic as orientation)
1418
- const statusPriority = {
1419
- returning: 0,
1420
- collaborating: 1,
1421
- in_progress: 2,
1422
- delegated: 3,
1423
- accepted: 4,
1424
- pending: 5,
1425
- };
1426
- const sorted = [...openObligations].sort((a, b) => {
1427
- const sp = (statusPriority[a.status] ?? 99) - (statusPriority[b.status] ?? 99);
1428
- if (sp !== 0)
1429
- return sp;
1430
- const aMs = new Date(a.updatedAt ?? a.createdAt).getTime();
1431
- const bMs = new Date(b.updatedAt ?? b.createdAt).getTime();
1432
- return bMs - aMs;
1433
- });
1434
- const primary = sorted[0] ?? null;
1435
- const items = openObligations.map((ob) => ({
1436
- id: ob.id,
1437
- status: ob.status,
1438
- content: ob.content,
1439
- updatedAt: ob.updatedAt ?? ob.createdAt,
1440
- nextAction: ob.nextAction ?? null,
1441
- origin: ob.origin ?? null,
1442
- currentSurface: ob.currentSurface ? { kind: ob.currentSurface.kind, label: ob.currentSurface.label } : null,
1443
- meaning: ob.meaning ? { waitingOn: ob.meaning.waitingOn?.detail ?? null } : null,
1444
- isPrimary: primary ? ob.id === primary.id : false,
1445
- }));
1446
- let primarySelectionReason = null;
1447
- if (primary) {
1448
- if (primary.status !== "pending") {
1449
- primarySelectionReason = `most advanced status: ${primary.status}`;
1450
- }
1451
- else {
1452
- primarySelectionReason = "most recent pending";
1453
- }
1454
- }
1455
- (0, runtime_1.emitNervesEvent)({
1456
- component: "heart",
1457
- event: "heart.outlook_obligations_read",
1458
- message: `outlook obligations: ${openObligations.length} open`,
1459
- meta: { openCount: openObligations.length, primaryId: primary?.id ?? null },
1460
- });
1461
- return {
1462
- openCount: openObligations.length,
1463
- primaryId: primary?.id ?? null,
1464
- primarySelectionReason,
1465
- items,
1466
- };
1467
- }
1468
- // ---------------------------------------------------------------------------
1469
- // Changes reader — cross-session drift via snapshot comparison
1470
- // ---------------------------------------------------------------------------
1471
- const active_work_1 = require("../active-work");
1472
- function readChangesView(agentRoot) {
1473
- const snapshotPath = path.join(agentRoot, "state", "outlook", "active-work-snapshot.json");
1474
- // Read prior snapshot
1475
- let previous = null;
1476
- try {
1477
- const raw = fs.readFileSync(snapshotPath, "utf-8");
1478
- previous = JSON.parse(raw);
1479
- if (!previous.obligationSnapshots || !previous.codingSnapshots)
1480
- previous = null;
1481
- }
1482
- catch {
1483
- previous = null;
1484
- }
1485
- // Build current snapshot from raw state
1486
- let obligations = [];
1487
- try {
1488
- obligations = (0, obligations_1.readObligations)(agentRoot);
1489
- }
1490
- catch {
1491
- obligations = [];
1492
- }
1493
- const openObligations = obligations.filter(obligations_1.isOpenObligation);
1494
- const current = {
1495
- obligationSnapshots: openObligations.map((ob) => ({
1496
- id: ob.id,
1497
- status: ob.status,
1498
- artifact: ob.currentArtifact?.trim() || null,
1499
- nextAction: ob.nextAction?.trim() || null,
1500
- })),
1501
- codingSnapshots: [],
1502
- timestamp: new Date().toISOString(),
1503
- };
1504
- // Persist current as the new snapshot
1505
- try {
1506
- fs.mkdirSync(path.dirname(snapshotPath), { recursive: true });
1507
- fs.writeFileSync(snapshotPath, JSON.stringify(current, null, 2) + "\n", "utf-8");
1508
- }
1509
- catch {
1510
- // Best effort
1511
- }
1512
- if (!previous) {
1513
- return { changeCount: 0, items: [], snapshotAge: null, formatted: "" };
1514
- }
1515
- const changes = (0, active_work_1.detectActiveWorkChanges)(previous, current);
1516
- const formatted = (0, active_work_1.formatActiveWorkChanges)(changes);
1517
- (0, runtime_1.emitNervesEvent)({
1518
- component: "heart",
1519
- event: "heart.outlook_changes_read",
1520
- message: `outlook changes: ${changes.length} detected`,
1521
- meta: { changeCount: changes.length, snapshotAge: previous.timestamp },
1522
- });
1523
- return {
1524
- changeCount: changes.length,
1525
- items: changes.map((c) => ({ kind: c.kind, id: c.id, from: c.from, to: c.to, summary: c.summary })),
1526
- snapshotAge: previous.timestamp,
1527
- formatted,
1528
- };
1529
- }
1530
- // ---------------------------------------------------------------------------
1531
- // Self-fix workflow reader — derived from task board and coding state
1532
- // ---------------------------------------------------------------------------
1533
- function readSelfFixView(agentRoot) {
1534
- // Derive self-fix state from task scanner
1535
- let tasks = [];
1536
- try {
1537
- const scanned = (0, scanner_1.scanTasks)(path.join(agentRoot, "tasks"));
1538
- tasks = scanned.tasks.map((t) => ({ name: t.name, title: t.title, status: t.status }));
1539
- }
1540
- catch {
1541
- tasks = [];
1542
- }
1543
- // Look for self-fix-related tasks
1544
- const selfFixTasks = tasks.filter((t) => t.title.toLowerCase().includes("fix") || t.title.toLowerCase().includes("self-fix"));
1545
- if (selfFixTasks.length === 0) {
1546
- return { active: false, currentStep: null, steps: [] };
1547
- }
1548
- const steps = selfFixTasks.map((t) => ({
1549
- label: t.title,
1550
- status: t.status === "done" ? "done" : t.status === "processing" ? "active" : "pending",
1551
- detail: `task ${t.name}: ${t.status}`,
1552
- }));
1553
- const activeStep = steps.find((s) => s.status === "active");
1554
- (0, runtime_1.emitNervesEvent)({
1555
- component: "heart",
1556
- event: "heart.outlook_selffix_read",
1557
- message: `outlook self-fix: ${selfFixTasks.length} tasks`,
1558
- meta: { taskCount: selfFixTasks.length, active: !!activeStep },
1559
- });
1560
- return {
1561
- active: !!activeStep,
1562
- currentStep: activeStep?.label ?? null,
1563
- steps,
1564
- };
1565
- }
1566
- // ---------------------------------------------------------------------------
1567
- // Memory decisions reader — append-only JSONL log
1568
- // ---------------------------------------------------------------------------
1569
- function readMemoryDecisionView(agentRoot, limit = 50) {
1570
- const logPath = path.join(agentRoot, "state", "outlook", "memory-decisions.jsonl");
1571
- let lines = [];
1572
- try {
1573
- const raw = fs.readFileSync(logPath, "utf-8");
1574
- lines = raw.split("\n").filter((l) => l.trim().length > 0);
1575
- }
1576
- catch {
1577
- return { totalCount: 0, items: [] };
1578
- }
1579
- const items = [];
1580
- for (const line of lines) {
1581
- try {
1582
- const parsed = JSON.parse(line);
1583
- if (parsed.kind && parsed.decision && parsed.timestamp) {
1584
- items.push(parsed);
1585
- }
1586
- }
1587
- catch {
1588
- // Skip malformed lines
1589
- }
1590
- }
1591
- // Reverse chronological
1592
- items.reverse();
1593
- const limited = items.slice(0, limit);
1594
- return { totalCount: items.length, items: limited };
1595
- }
3
+ exports.readSelfFixView = exports.readOutlookContinuity = exports.readOrientationView = exports.readObligationDetailView = exports.readMemoryDecisionView = exports.readChangesView = exports.readNeedsMeView = exports.readMemoryView = exports.readLogView = exports.readHabitView = exports.readFriendView = exports.readDeskPrefs = exports.readDaemonHealthDeep = exports.readCodingDeep = exports.readBridgeInventory = exports.readAttentionView = exports.readSessionTranscript = exports.readSessionInventory = exports.readOutlookMachineState = exports.readOutlookAgentState = exports.readObligationSummary = void 0;
4
+ var agent_machine_1 = require("./readers/agent-machine");
5
+ Object.defineProperty(exports, "readObligationSummary", { enumerable: true, get: function () { return agent_machine_1.readObligationSummary; } });
6
+ Object.defineProperty(exports, "readOutlookAgentState", { enumerable: true, get: function () { return agent_machine_1.readOutlookAgentState; } });
7
+ Object.defineProperty(exports, "readOutlookMachineState", { enumerable: true, get: function () { return agent_machine_1.readOutlookMachineState; } });
8
+ var sessions_1 = require("./readers/sessions");
9
+ Object.defineProperty(exports, "readSessionInventory", { enumerable: true, get: function () { return sessions_1.readSessionInventory; } });
10
+ Object.defineProperty(exports, "readSessionTranscript", { enumerable: true, get: function () { return sessions_1.readSessionTranscript; } });
11
+ var runtime_readers_1 = require("./readers/runtime-readers");
12
+ Object.defineProperty(exports, "readAttentionView", { enumerable: true, get: function () { return runtime_readers_1.readAttentionView; } });
13
+ Object.defineProperty(exports, "readBridgeInventory", { enumerable: true, get: function () { return runtime_readers_1.readBridgeInventory; } });
14
+ Object.defineProperty(exports, "readCodingDeep", { enumerable: true, get: function () { return runtime_readers_1.readCodingDeep; } });
15
+ Object.defineProperty(exports, "readDaemonHealthDeep", { enumerable: true, get: function () { return runtime_readers_1.readDaemonHealthDeep; } });
16
+ Object.defineProperty(exports, "readDeskPrefs", { enumerable: true, get: function () { return runtime_readers_1.readDeskPrefs; } });
17
+ Object.defineProperty(exports, "readFriendView", { enumerable: true, get: function () { return runtime_readers_1.readFriendView; } });
18
+ Object.defineProperty(exports, "readHabitView", { enumerable: true, get: function () { return runtime_readers_1.readHabitView; } });
19
+ Object.defineProperty(exports, "readLogView", { enumerable: true, get: function () { return runtime_readers_1.readLogView; } });
20
+ Object.defineProperty(exports, "readMemoryView", { enumerable: true, get: function () { return runtime_readers_1.readMemoryView; } });
21
+ Object.defineProperty(exports, "readNeedsMeView", { enumerable: true, get: function () { return runtime_readers_1.readNeedsMeView; } });
22
+ var continuity_readers_1 = require("./readers/continuity-readers");
23
+ Object.defineProperty(exports, "readChangesView", { enumerable: true, get: function () { return continuity_readers_1.readChangesView; } });
24
+ Object.defineProperty(exports, "readMemoryDecisionView", { enumerable: true, get: function () { return continuity_readers_1.readMemoryDecisionView; } });
25
+ Object.defineProperty(exports, "readObligationDetailView", { enumerable: true, get: function () { return continuity_readers_1.readObligationDetailView; } });
26
+ Object.defineProperty(exports, "readOrientationView", { enumerable: true, get: function () { return continuity_readers_1.readOrientationView; } });
27
+ Object.defineProperty(exports, "readOutlookContinuity", { enumerable: true, get: function () { return continuity_readers_1.readOutlookContinuity; } });
28
+ Object.defineProperty(exports, "readSelfFixView", { enumerable: true, get: function () { return continuity_readers_1.readSelfFixView; } });