@ouro.bot/cli 0.1.0-alpha.191 → 0.1.0-alpha.193
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 +9 -2
- package/dist/heart/active-work.js +2 -2
- package/dist/heart/daemon/daemon.js +1 -1
- package/dist/heart/daemon/outlook-http.js +52 -12
- package/dist/heart/daemon/outlook-read.js +288 -0
- package/dist/heart/wake-packet.js +9 -7
- package/dist/mind/prompt.js +8 -2
- package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +2 -2
- package/dist/senses/pipeline.js +6 -1
- package/package.json +1 -1
- package/dist/outlook-ui/assets/index-DN6vVYPm.css +0 -1
- package/dist/outlook-ui/assets/index-M1l1tDTX.js +0 -61
package/changelog.json
CHANGED
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
4
|
{
|
|
5
|
-
"version": "0.1.0-alpha.
|
|
5
|
+
"version": "0.1.0-alpha.193",
|
|
6
6
|
"changes": [
|
|
7
|
+
"feat: Outlook visibility \u2014 orientation, obligations, changes, self-fix, memory decisions, route migration to /"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.192",
|
|
12
|
+
"changes": [
|
|
13
|
+
"refactor: canonical obligations \u2014 ActiveWorkFrame as single source of truth for prompt sections",
|
|
7
14
|
"feat(mcp): dynamic server add/remove \u2014 agents can manage MCP servers without daemon restart"
|
|
8
15
|
]
|
|
9
16
|
},
|
|
@@ -1197,4 +1204,4 @@
|
|
|
1197
1204
|
]
|
|
1198
1205
|
}
|
|
1199
1206
|
]
|
|
1200
|
-
}
|
|
1207
|
+
}
|
|
@@ -666,8 +666,8 @@ function formatActiveWorkFrame(frame, options) {
|
|
|
666
666
|
}
|
|
667
667
|
if ((frame.pendingObligations ?? []).length > 0) {
|
|
668
668
|
const openCount = frame.pendingObligations.filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
|
|
669
|
-
if (options?.
|
|
670
|
-
//
|
|
669
|
+
if (options?.obligationDetailsRenderedElsewhere && openCount > 0) {
|
|
670
|
+
// Enriched obligation data (with resumeHint, stalenessClass, waitingOn) is rendered elsewhere.
|
|
671
671
|
// Avoid duplicating the full list — just anchor the count here.
|
|
672
672
|
lines.push("");
|
|
673
673
|
lines.push(`return obligations: ${openCount} active (canonical details in **Owed** section of wake packet)`);
|
|
@@ -208,7 +208,7 @@ class OuroDaemon {
|
|
|
208
208
|
daemon: "running",
|
|
209
209
|
health: workers.every((worker) => worker.status === "running") ? "ok" : "warn",
|
|
210
210
|
socketPath: this.socketPath,
|
|
211
|
-
outlookUrl:
|
|
211
|
+
outlookUrl: this.outlookServer?.origin ?? "http://127.0.0.1:0",
|
|
212
212
|
...(0, runtime_metadata_1.getRuntimeMetadata)(),
|
|
213
213
|
workerCount: workers.length,
|
|
214
214
|
senseCount: senses.length,
|
|
@@ -196,6 +196,12 @@ async function startOutlookHttpServer(options = {}) {
|
|
|
196
196
|
readAgentBridges: options.readAgentBridges ?? ((agentName) => (0, outlook_read_1.readBridgeInventory)(agentRoot(agentName))),
|
|
197
197
|
readAgentMemory: options.readAgentMemory ?? ((agentName) => (0, outlook_read_1.readMemoryView)(agentRoot(agentName))),
|
|
198
198
|
readAgentFriends: options.readAgentFriends ?? ((agentName) => (0, outlook_read_1.readFriendView)(agentName, bundlesRoot ? { bundlesRoot } : undefined)),
|
|
199
|
+
readAgentContinuity: options.readAgentContinuity ?? ((agentName) => (0, outlook_read_1.readOutlookContinuity)(agentRoot(agentName), agentName)),
|
|
200
|
+
readAgentOrientation: options.readAgentOrientation ?? ((agentName) => (0, outlook_read_1.readOrientationView)(agentRoot(agentName), agentName)),
|
|
201
|
+
readAgentObligations: options.readAgentObligations ?? ((agentName) => (0, outlook_read_1.readObligationDetailView)(agentRoot(agentName))),
|
|
202
|
+
readAgentChanges: options.readAgentChanges ?? ((agentName) => (0, outlook_read_1.readChangesView)(agentRoot(agentName))),
|
|
203
|
+
readAgentSelfFix: options.readAgentSelfFix ?? ((agentName) => (0, outlook_read_1.readSelfFixView)(agentRoot(agentName))),
|
|
204
|
+
readAgentMemoryDecisions: options.readAgentMemoryDecisions ?? ((agentName) => (0, outlook_read_1.readMemoryDecisionView)(agentRoot(agentName))),
|
|
199
205
|
readAgentHabits: options.readAgentHabits ?? ((agentName) => (0, outlook_read_1.readHabitView)(agentRoot(agentName))),
|
|
200
206
|
readDaemonHealth: options.readDaemonHealth ?? (() => (0, outlook_read_1.readDaemonHealthDeep)(options.healthPath)),
|
|
201
207
|
readLogs: options.readLogs ?? (() => (0, outlook_read_1.readLogView)(options.logPath ?? null)),
|
|
@@ -208,14 +214,8 @@ async function startOutlookHttpServer(options = {}) {
|
|
|
208
214
|
}) : null;
|
|
209
215
|
/* v8 ignore stop */
|
|
210
216
|
const server = http.createServer((request, response) => {
|
|
211
|
-
|
|
217
|
+
let pathname = normalizePath(request.url);
|
|
212
218
|
const origin = `http://${host}:${server.address().port}`;
|
|
213
|
-
if (pathname === "/outlook/api/events") {
|
|
214
|
-
response.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", "connection": "keep-alive", "access-control-allow-origin": "*" });
|
|
215
|
-
response.write(":ok\n\n");
|
|
216
|
-
sse.add(response);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
219
|
/* v8 ignore start — SPA static asset serving */
|
|
220
220
|
// Serve built SPA static assets: /assets/*
|
|
221
221
|
if (pathname.startsWith("/assets/")) {
|
|
@@ -235,23 +235,39 @@ async function startOutlookHttpServer(options = {}) {
|
|
|
235
235
|
response.end();
|
|
236
236
|
return;
|
|
237
237
|
}
|
|
238
|
-
|
|
238
|
+
// Compatibility alias: /outlook/api/* → /api/*
|
|
239
|
+
/* v8 ignore start -- legacy compat path: tested via integration @preserve */
|
|
240
|
+
if (pathname.startsWith("/outlook/api/")) {
|
|
241
|
+
pathname = pathname.slice("/outlook".length);
|
|
242
|
+
}
|
|
243
|
+
else if (pathname === "/outlook/api") {
|
|
244
|
+
pathname = "/api";
|
|
245
|
+
}
|
|
246
|
+
/* v8 ignore stop */
|
|
247
|
+
// SSE event stream
|
|
248
|
+
if (pathname === "/api/events") {
|
|
249
|
+
response.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", "connection": "keep-alive", "access-control-allow-origin": "*" });
|
|
250
|
+
response.write(":ok\n\n");
|
|
251
|
+
sse.add(response);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (pathname === "/api/machine") {
|
|
239
255
|
const machine = readMachineState();
|
|
240
256
|
const machineView = readMachineView?.({ origin, machine });
|
|
241
257
|
writeJson(response, 200, machineView ?? machine);
|
|
242
258
|
return;
|
|
243
259
|
}
|
|
244
|
-
if (pathname === "/
|
|
260
|
+
if (pathname === "/api/machine/health") {
|
|
245
261
|
const health = hooks.readDaemonHealth();
|
|
246
262
|
writeJson(response, 200, health ?? { status: "unavailable" });
|
|
247
263
|
return;
|
|
248
264
|
}
|
|
249
|
-
if (pathname === "/
|
|
265
|
+
if (pathname === "/api/machine/logs") {
|
|
250
266
|
writeJson(response, 200, hooks.readLogs());
|
|
251
267
|
return;
|
|
252
268
|
}
|
|
253
|
-
// Agent-level endpoints: /
|
|
254
|
-
const agentMatch = /^\/
|
|
269
|
+
// Agent-level endpoints: /api/agents/:agent[/:surface[/:params...]]
|
|
270
|
+
const agentMatch = /^\/api\/agents\/([^/]+)(?:\/(.+))?$/.exec(pathname);
|
|
255
271
|
if (agentMatch) {
|
|
256
272
|
const agent = decodeURIComponent(agentMatch[1]);
|
|
257
273
|
const surface = agentMatch[2] ?? null;
|
|
@@ -306,6 +322,30 @@ async function startOutlookHttpServer(options = {}) {
|
|
|
306
322
|
writeJson(response, 200, hooks.readAgentFriends(agent));
|
|
307
323
|
return;
|
|
308
324
|
}
|
|
325
|
+
if (surface === "continuity") {
|
|
326
|
+
writeJson(response, 200, hooks.readAgentContinuity(agent));
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (surface === "orientation") {
|
|
330
|
+
writeJson(response, 200, hooks.readAgentOrientation(agent));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (surface === "obligations") {
|
|
334
|
+
writeJson(response, 200, hooks.readAgentObligations(agent));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (surface === "changes") {
|
|
338
|
+
writeJson(response, 200, hooks.readAgentChanges(agent));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (surface === "self-fix") {
|
|
342
|
+
writeJson(response, 200, hooks.readAgentSelfFix(agent));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (surface === "memory-decisions") {
|
|
346
|
+
writeJson(response, 200, hooks.readAgentMemoryDecisions(agent));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
309
349
|
/* v8 ignore start — desk prefs write + reads */
|
|
310
350
|
if (surface === "dismiss-obligation" && request.method === "POST") {
|
|
311
351
|
let body = "";
|
|
@@ -48,6 +48,11 @@ exports.readHabitView = readHabitView;
|
|
|
48
48
|
exports.readNeedsMeView = readNeedsMeView;
|
|
49
49
|
exports.readDeskPrefs = readDeskPrefs;
|
|
50
50
|
exports.readOutlookContinuity = readOutlookContinuity;
|
|
51
|
+
exports.readOrientationView = readOrientationView;
|
|
52
|
+
exports.readObligationDetailView = readObligationDetailView;
|
|
53
|
+
exports.readChangesView = readChangesView;
|
|
54
|
+
exports.readSelfFixView = readSelfFixView;
|
|
55
|
+
exports.readMemoryDecisionView = readMemoryDecisionView;
|
|
51
56
|
const fs = __importStar(require("fs"));
|
|
52
57
|
const path = __importStar(require("path"));
|
|
53
58
|
const runtime_1 = require("../../nerves/runtime");
|
|
@@ -1329,3 +1334,286 @@ function readOutlookContinuity(agentRoot, agentName) {
|
|
|
1329
1334
|
},
|
|
1330
1335
|
};
|
|
1331
1336
|
}
|
|
1337
|
+
// ---------------------------------------------------------------------------
|
|
1338
|
+
// Orientation reader — daemon-side assembly of "where am I?"
|
|
1339
|
+
// ---------------------------------------------------------------------------
|
|
1340
|
+
function readOrientationView(agentRoot, agentName) {
|
|
1341
|
+
// Read obligations for primary selection
|
|
1342
|
+
let obligations = [];
|
|
1343
|
+
try {
|
|
1344
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
1345
|
+
}
|
|
1346
|
+
catch {
|
|
1347
|
+
obligations = [];
|
|
1348
|
+
}
|
|
1349
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
1350
|
+
// Select primary obligation (most advanced status, then most recent)
|
|
1351
|
+
const statusPriority = {
|
|
1352
|
+
returning: 0,
|
|
1353
|
+
collaborating: 1,
|
|
1354
|
+
in_progress: 2,
|
|
1355
|
+
delegated: 3,
|
|
1356
|
+
accepted: 4,
|
|
1357
|
+
pending: 5,
|
|
1358
|
+
};
|
|
1359
|
+
const sorted = [...openObligations].sort((a, b) => {
|
|
1360
|
+
const sp = (statusPriority[a.status] ?? 99) - (statusPriority[b.status] ?? 99);
|
|
1361
|
+
if (sp !== 0)
|
|
1362
|
+
return sp;
|
|
1363
|
+
const aMs = new Date(a.updatedAt ?? a.createdAt).getTime();
|
|
1364
|
+
const bMs = new Date(b.updatedAt ?? b.createdAt).getTime();
|
|
1365
|
+
return bMs - aMs;
|
|
1366
|
+
});
|
|
1367
|
+
const primary = sorted[0] ?? null;
|
|
1368
|
+
// Read session activity for current session and others
|
|
1369
|
+
let sessions = [];
|
|
1370
|
+
try {
|
|
1371
|
+
sessions = (0, session_activity_1.listSessionActivity)({
|
|
1372
|
+
sessionsDir: path.join(agentRoot, "state", "sessions"),
|
|
1373
|
+
friendsDir: path.join(agentRoot, "friends"),
|
|
1374
|
+
agentName,
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
catch {
|
|
1378
|
+
sessions = [];
|
|
1379
|
+
}
|
|
1380
|
+
const sortedSessions = [...sessions].sort((a, b) => b.lastActivityMs - a.lastActivityMs);
|
|
1381
|
+
const currentSession = sortedSessions.length > 0
|
|
1382
|
+
? {
|
|
1383
|
+
friendId: sortedSessions[0].friendId,
|
|
1384
|
+
channel: sortedSessions[0].channel,
|
|
1385
|
+
key: sortedSessions[0].key,
|
|
1386
|
+
lastActivityAt: sortedSessions[0].lastActivityAt,
|
|
1387
|
+
}
|
|
1388
|
+
: null;
|
|
1389
|
+
const otherActiveSessions = sortedSessions.slice(1).map((s) => ({
|
|
1390
|
+
friendId: s.friendId,
|
|
1391
|
+
friendName: s.friendName,
|
|
1392
|
+
channel: s.channel,
|
|
1393
|
+
key: s.key,
|
|
1394
|
+
lastActivityAt: s.lastActivityAt,
|
|
1395
|
+
}));
|
|
1396
|
+
// Derive center of gravity summary
|
|
1397
|
+
const parts = [];
|
|
1398
|
+
if (primary)
|
|
1399
|
+
parts.push(primary.content);
|
|
1400
|
+
if (openObligations.length > 1)
|
|
1401
|
+
parts.push(`${openObligations.length} open obligations`);
|
|
1402
|
+
if (sessions.length > 0)
|
|
1403
|
+
parts.push(`${sessions.length} active sessions`);
|
|
1404
|
+
const centerOfGravity = parts.length > 0 ? parts.join(" | ") : "idle";
|
|
1405
|
+
const primaryObligation = primary
|
|
1406
|
+
? {
|
|
1407
|
+
id: primary.id,
|
|
1408
|
+
content: primary.content,
|
|
1409
|
+
status: primary.status,
|
|
1410
|
+
nextAction: primary.nextAction ?? null,
|
|
1411
|
+
waitingOn: primary.meaning?.waitingOn?.detail ?? null,
|
|
1412
|
+
}
|
|
1413
|
+
: null;
|
|
1414
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1415
|
+
component: "heart",
|
|
1416
|
+
event: "heart.outlook_orientation_read",
|
|
1417
|
+
message: `outlook orientation: ${openObligations.length} obligations, ${sessions.length} sessions`,
|
|
1418
|
+
meta: { obligationCount: openObligations.length, sessionCount: sessions.length, primaryId: primary?.id ?? null },
|
|
1419
|
+
});
|
|
1420
|
+
return {
|
|
1421
|
+
currentSession,
|
|
1422
|
+
centerOfGravity,
|
|
1423
|
+
primaryObligation,
|
|
1424
|
+
resumeHandle: null,
|
|
1425
|
+
otherActiveSessions,
|
|
1426
|
+
rawState: null,
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
// ---------------------------------------------------------------------------
|
|
1430
|
+
// Obligation detail reader — richer view with primary selection context
|
|
1431
|
+
// ---------------------------------------------------------------------------
|
|
1432
|
+
function readObligationDetailView(agentRoot) {
|
|
1433
|
+
let obligations = [];
|
|
1434
|
+
try {
|
|
1435
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
1436
|
+
}
|
|
1437
|
+
catch {
|
|
1438
|
+
obligations = [];
|
|
1439
|
+
}
|
|
1440
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
1441
|
+
// Select primary (same logic as orientation)
|
|
1442
|
+
const statusPriority = {
|
|
1443
|
+
returning: 0,
|
|
1444
|
+
collaborating: 1,
|
|
1445
|
+
in_progress: 2,
|
|
1446
|
+
delegated: 3,
|
|
1447
|
+
accepted: 4,
|
|
1448
|
+
pending: 5,
|
|
1449
|
+
};
|
|
1450
|
+
const sorted = [...openObligations].sort((a, b) => {
|
|
1451
|
+
const sp = (statusPriority[a.status] ?? 99) - (statusPriority[b.status] ?? 99);
|
|
1452
|
+
if (sp !== 0)
|
|
1453
|
+
return sp;
|
|
1454
|
+
const aMs = new Date(a.updatedAt ?? a.createdAt).getTime();
|
|
1455
|
+
const bMs = new Date(b.updatedAt ?? b.createdAt).getTime();
|
|
1456
|
+
return bMs - aMs;
|
|
1457
|
+
});
|
|
1458
|
+
const primary = sorted[0] ?? null;
|
|
1459
|
+
const items = openObligations.map((ob) => ({
|
|
1460
|
+
id: ob.id,
|
|
1461
|
+
status: ob.status,
|
|
1462
|
+
content: ob.content,
|
|
1463
|
+
updatedAt: ob.updatedAt ?? ob.createdAt,
|
|
1464
|
+
nextAction: ob.nextAction ?? null,
|
|
1465
|
+
origin: ob.origin ?? null,
|
|
1466
|
+
currentSurface: ob.currentSurface ? { kind: ob.currentSurface.kind, label: ob.currentSurface.label } : null,
|
|
1467
|
+
meaning: ob.meaning ? { waitingOn: ob.meaning.waitingOn?.detail ?? null } : null,
|
|
1468
|
+
isPrimary: primary ? ob.id === primary.id : false,
|
|
1469
|
+
}));
|
|
1470
|
+
let primarySelectionReason = null;
|
|
1471
|
+
if (primary) {
|
|
1472
|
+
if (primary.status !== "pending") {
|
|
1473
|
+
primarySelectionReason = `most advanced status: ${primary.status}`;
|
|
1474
|
+
}
|
|
1475
|
+
else {
|
|
1476
|
+
primarySelectionReason = "most recent pending";
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1480
|
+
component: "heart",
|
|
1481
|
+
event: "heart.outlook_obligations_read",
|
|
1482
|
+
message: `outlook obligations: ${openObligations.length} open`,
|
|
1483
|
+
meta: { openCount: openObligations.length, primaryId: primary?.id ?? null },
|
|
1484
|
+
});
|
|
1485
|
+
return {
|
|
1486
|
+
openCount: openObligations.length,
|
|
1487
|
+
primaryId: primary?.id ?? null,
|
|
1488
|
+
primarySelectionReason,
|
|
1489
|
+
items,
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
// ---------------------------------------------------------------------------
|
|
1493
|
+
// Changes reader — cross-session drift via snapshot comparison
|
|
1494
|
+
// ---------------------------------------------------------------------------
|
|
1495
|
+
const active_work_1 = require("../active-work");
|
|
1496
|
+
function readChangesView(agentRoot) {
|
|
1497
|
+
const snapshotPath = path.join(agentRoot, "state", "outlook", "active-work-snapshot.json");
|
|
1498
|
+
// Read prior snapshot
|
|
1499
|
+
let previous = null;
|
|
1500
|
+
try {
|
|
1501
|
+
const raw = fs.readFileSync(snapshotPath, "utf-8");
|
|
1502
|
+
previous = JSON.parse(raw);
|
|
1503
|
+
if (!previous.obligationSnapshots || !previous.codingSnapshots)
|
|
1504
|
+
previous = null;
|
|
1505
|
+
}
|
|
1506
|
+
catch {
|
|
1507
|
+
previous = null;
|
|
1508
|
+
}
|
|
1509
|
+
// Build current snapshot from raw state
|
|
1510
|
+
let obligations = [];
|
|
1511
|
+
try {
|
|
1512
|
+
obligations = (0, obligations_1.readObligations)(agentRoot);
|
|
1513
|
+
}
|
|
1514
|
+
catch {
|
|
1515
|
+
obligations = [];
|
|
1516
|
+
}
|
|
1517
|
+
const openObligations = obligations.filter(obligations_1.isOpenObligation);
|
|
1518
|
+
const current = {
|
|
1519
|
+
obligationSnapshots: openObligations.map((ob) => ({
|
|
1520
|
+
id: ob.id,
|
|
1521
|
+
status: ob.status,
|
|
1522
|
+
artifact: ob.currentArtifact?.trim() || null,
|
|
1523
|
+
nextAction: ob.nextAction?.trim() || null,
|
|
1524
|
+
})),
|
|
1525
|
+
codingSnapshots: [],
|
|
1526
|
+
timestamp: new Date().toISOString(),
|
|
1527
|
+
};
|
|
1528
|
+
// Persist current as the new snapshot
|
|
1529
|
+
try {
|
|
1530
|
+
fs.mkdirSync(path.dirname(snapshotPath), { recursive: true });
|
|
1531
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(current, null, 2) + "\n", "utf-8");
|
|
1532
|
+
}
|
|
1533
|
+
catch {
|
|
1534
|
+
// Best effort
|
|
1535
|
+
}
|
|
1536
|
+
if (!previous) {
|
|
1537
|
+
return { changeCount: 0, items: [], snapshotAge: null, formatted: "" };
|
|
1538
|
+
}
|
|
1539
|
+
const changes = (0, active_work_1.detectActiveWorkChanges)(previous, current);
|
|
1540
|
+
const formatted = (0, active_work_1.formatActiveWorkChanges)(changes);
|
|
1541
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1542
|
+
component: "heart",
|
|
1543
|
+
event: "heart.outlook_changes_read",
|
|
1544
|
+
message: `outlook changes: ${changes.length} detected`,
|
|
1545
|
+
meta: { changeCount: changes.length, snapshotAge: previous.timestamp },
|
|
1546
|
+
});
|
|
1547
|
+
return {
|
|
1548
|
+
changeCount: changes.length,
|
|
1549
|
+
items: changes.map((c) => ({ kind: c.kind, id: c.id, from: c.from, to: c.to, summary: c.summary })),
|
|
1550
|
+
snapshotAge: previous.timestamp,
|
|
1551
|
+
formatted,
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
// ---------------------------------------------------------------------------
|
|
1555
|
+
// Self-fix workflow reader — derived from task board and coding state
|
|
1556
|
+
// ---------------------------------------------------------------------------
|
|
1557
|
+
function readSelfFixView(agentRoot) {
|
|
1558
|
+
// Derive self-fix state from task scanner
|
|
1559
|
+
let tasks = [];
|
|
1560
|
+
try {
|
|
1561
|
+
const scanned = (0, scanner_1.scanTasks)(path.join(agentRoot, "tasks"));
|
|
1562
|
+
tasks = scanned.tasks.map((t) => ({ name: t.name, title: t.title, status: t.status }));
|
|
1563
|
+
}
|
|
1564
|
+
catch {
|
|
1565
|
+
tasks = [];
|
|
1566
|
+
}
|
|
1567
|
+
// Look for self-fix-related tasks
|
|
1568
|
+
const selfFixTasks = tasks.filter((t) => t.title.toLowerCase().includes("fix") || t.title.toLowerCase().includes("self-fix"));
|
|
1569
|
+
if (selfFixTasks.length === 0) {
|
|
1570
|
+
return { active: false, currentStep: null, steps: [] };
|
|
1571
|
+
}
|
|
1572
|
+
const steps = selfFixTasks.map((t) => ({
|
|
1573
|
+
label: t.title,
|
|
1574
|
+
status: t.status === "done" ? "done" : t.status === "processing" ? "active" : "pending",
|
|
1575
|
+
detail: `task ${t.name}: ${t.status}`,
|
|
1576
|
+
}));
|
|
1577
|
+
const activeStep = steps.find((s) => s.status === "active");
|
|
1578
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1579
|
+
component: "heart",
|
|
1580
|
+
event: "heart.outlook_selffix_read",
|
|
1581
|
+
message: `outlook self-fix: ${selfFixTasks.length} tasks`,
|
|
1582
|
+
meta: { taskCount: selfFixTasks.length, active: !!activeStep },
|
|
1583
|
+
});
|
|
1584
|
+
return {
|
|
1585
|
+
active: !!activeStep,
|
|
1586
|
+
currentStep: activeStep?.label ?? null,
|
|
1587
|
+
steps,
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
// ---------------------------------------------------------------------------
|
|
1591
|
+
// Memory decisions reader — append-only JSONL log
|
|
1592
|
+
// ---------------------------------------------------------------------------
|
|
1593
|
+
function readMemoryDecisionView(agentRoot, limit = 50) {
|
|
1594
|
+
const logPath = path.join(agentRoot, "state", "outlook", "memory-decisions.jsonl");
|
|
1595
|
+
let lines = [];
|
|
1596
|
+
try {
|
|
1597
|
+
const raw = fs.readFileSync(logPath, "utf-8");
|
|
1598
|
+
lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
1599
|
+
}
|
|
1600
|
+
catch {
|
|
1601
|
+
return { totalCount: 0, items: [] };
|
|
1602
|
+
}
|
|
1603
|
+
const items = [];
|
|
1604
|
+
for (const line of lines) {
|
|
1605
|
+
try {
|
|
1606
|
+
const parsed = JSON.parse(line);
|
|
1607
|
+
if (parsed.kind && parsed.decision && parsed.timestamp) {
|
|
1608
|
+
items.push(parsed);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
catch {
|
|
1612
|
+
// Skip malformed lines
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
// Reverse chronological
|
|
1616
|
+
items.reverse();
|
|
1617
|
+
const limited = items.slice(0, limit);
|
|
1618
|
+
return { totalCount: items.length, items: limited };
|
|
1619
|
+
}
|
|
@@ -65,10 +65,11 @@ function buildPresenceSection(peers) {
|
|
|
65
65
|
.map((p) => `- ${p.agentName}: ${p.availability}/${p.lane}`)
|
|
66
66
|
.join("\n");
|
|
67
67
|
}
|
|
68
|
-
function buildResumeHint(view) {
|
|
68
|
+
function buildResumeHint(view, obligations) {
|
|
69
69
|
// Compose from authored obligation resumeHints and top intentions
|
|
70
70
|
const hints = [];
|
|
71
|
-
|
|
71
|
+
const effectiveObligations = obligations ?? view.activeObligations;
|
|
72
|
+
for (const ob of effectiveObligations) {
|
|
72
73
|
if (ob.meaning?.resumeHint) {
|
|
73
74
|
hints.push(ob.meaning.resumeHint);
|
|
74
75
|
}
|
|
@@ -78,23 +79,24 @@ function buildResumeHint(view) {
|
|
|
78
79
|
}
|
|
79
80
|
if (hints.length === 0) {
|
|
80
81
|
// Fall back to top obligation content
|
|
81
|
-
if (
|
|
82
|
-
hints.push(
|
|
82
|
+
if (effectiveObligations.length > 0) {
|
|
83
|
+
hints.push(effectiveObligations[0].content);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
if (hints.length === 0)
|
|
86
87
|
return "";
|
|
87
88
|
return hints.join("; ");
|
|
88
89
|
}
|
|
89
|
-
function buildWakePacket(view) {
|
|
90
|
+
function buildWakePacket(view, opts) {
|
|
90
91
|
const tempo = view.tempo;
|
|
91
92
|
const tokenBudget = tempo_1.TEMPO_BUDGETS[tempo];
|
|
93
|
+
const effectiveObligations = opts?.canonicalObligations ? opts.canonicalObligations.all : view.activeObligations;
|
|
92
94
|
const packet = {
|
|
93
95
|
plotLine: buildPlotLine(view.recentEpisodes, tempo),
|
|
94
|
-
obligations: buildObligationsSection(
|
|
96
|
+
obligations: buildObligationsSection(effectiveObligations),
|
|
95
97
|
cares: buildCaresSection(view.activeCares),
|
|
96
98
|
presence: buildPresenceSection(view.peerPresence),
|
|
97
|
-
resumeHint: buildResumeHint(view),
|
|
99
|
+
resumeHint: buildResumeHint(view, opts?.canonicalObligations ? effectiveObligations : undefined),
|
|
98
100
|
tempo,
|
|
99
101
|
tokenBudget,
|
|
100
102
|
assembledAt: new Date().toISOString(),
|
package/dist/mind/prompt.js
CHANGED
|
@@ -106,7 +106,10 @@ function resetPsycheCache() {
|
|
|
106
106
|
}
|
|
107
107
|
const DEFAULT_ACTIVE_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
108
108
|
function buildSessionSummary(options) {
|
|
109
|
-
const { sessionsDir, friendsDir, agentName,
|
|
109
|
+
const { sessionsDir, friendsDir, agentName, currentSession, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, } = options;
|
|
110
|
+
const currentFriendId = currentSession?.friendId ?? options.currentFriendId;
|
|
111
|
+
const currentChannel = currentSession?.channel ?? options.currentChannel;
|
|
112
|
+
const currentKey = currentSession?.key ?? options.currentKey;
|
|
110
113
|
const now = Date.now();
|
|
111
114
|
const query = {
|
|
112
115
|
sessionsDir,
|
|
@@ -519,7 +522,7 @@ function wakePacketSection(options) {
|
|
|
519
522
|
function activeWorkSection(options) {
|
|
520
523
|
if (!options?.activeWorkFrame)
|
|
521
524
|
return "";
|
|
522
|
-
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame, {
|
|
525
|
+
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame, { obligationDetailsRenderedElsewhere: !!options?.wakePacket });
|
|
523
526
|
}
|
|
524
527
|
function liveWorldStateSection(options) {
|
|
525
528
|
if (!options?.activeWorkFrame)
|
|
@@ -1079,6 +1082,9 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1079
1082
|
sessionsDir: path.join((0, identity_1.getAgentRoot)(), "state", "sessions"),
|
|
1080
1083
|
friendsDir: path.join((0, identity_1.getAgentRoot)(), "friends"),
|
|
1081
1084
|
agentName: (0, identity_1.getAgentName)(),
|
|
1085
|
+
currentSession: options?.activeWorkFrame?.currentSession
|
|
1086
|
+
? { friendId: options.activeWorkFrame.currentSession.friendId, channel: options.activeWorkFrame.currentSession.channel, key: options.activeWorkFrame.currentSession.key }
|
|
1087
|
+
: undefined,
|
|
1082
1088
|
currentFriendId: context?.friend?.id,
|
|
1083
1089
|
currentChannel: channel,
|
|
1084
1090
|
currentKey: options?.currentSessionKey ?? "session",
|