@ouro.bot/cli 0.1.0-alpha.694 → 0.1.0-alpha.696
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 +13 -0
- package/dist/arc/flight-recorder.js +139 -21
- package/dist/arc/obligations.js +28 -6
- package/dist/arc/packets.js +48 -0
- package/dist/heart/context-loss-sentinel.js +165 -3
- package/dist/heart/daemon/daemon-entry.js +33 -9
- package/dist/heart/work-card.js +1 -11
- package/dist/repertoire/tools-obligations.js +39 -0
- package/dist/senses/pipeline.js +1 -11
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
{
|
|
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
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.696",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Prevent completed return-work packets from re-entering active Arc state."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.695",
|
|
12
|
+
"changes": [
|
|
13
|
+
"Prevent daemon-health context-loss Sentinel checks from treating Sentinel-authored flight-recorder cleanup as bundle dirt.",
|
|
14
|
+
"Clear daemon shutdown fallback timers after graceful SIGINT/SIGTERM and circuit-breaker stops."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
4
17
|
{
|
|
5
18
|
"version": "0.1.0-alpha.694",
|
|
6
19
|
"changes": [
|
|
@@ -51,6 +51,7 @@ const crypto_1 = require("crypto");
|
|
|
51
51
|
const session_events_1 = require("../heart/session-events");
|
|
52
52
|
const runtime_1 = require("../nerves/runtime");
|
|
53
53
|
const obligations_1 = require("./obligations");
|
|
54
|
+
const packets_1 = require("./packets");
|
|
54
55
|
function isHabitRunTrigger(value) {
|
|
55
56
|
return value === "cron"
|
|
56
57
|
|| value === "launchd"
|
|
@@ -235,10 +236,16 @@ function remainingArcWorkDescriptions(resume) {
|
|
|
235
236
|
...resume.openEvolutionCaseIds.map((id) => `evolution case ${id}`),
|
|
236
237
|
];
|
|
237
238
|
}
|
|
238
|
-
function nextSafeActionAfterObligationReconcile(resume, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds) {
|
|
239
|
+
function nextSafeActionAfterObligationReconcile(resume, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, unverifiableActivePacketIds) {
|
|
239
240
|
if (unverifiableActiveObligationIds.length > 0) {
|
|
240
241
|
return (0, session_events_1.capStructuredRecordString)(`inspect unverifiable active obligations before acting: ${unverifiableActiveObligationIds.join(", ")}`);
|
|
241
242
|
}
|
|
243
|
+
if (unverifiableActiveReturnObligationIds.length > 0) {
|
|
244
|
+
return (0, session_events_1.capStructuredRecordString)(`inspect unverifiable active return obligations before acting: ${unverifiableActiveReturnObligationIds.join(", ")}`);
|
|
245
|
+
}
|
|
246
|
+
if (unverifiableActivePacketIds.length > 0) {
|
|
247
|
+
return (0, session_events_1.capStructuredRecordString)(`inspect unverifiable active packets before acting: ${unverifiableActivePacketIds.join(", ")}`);
|
|
248
|
+
}
|
|
242
249
|
const firstActive = activeObligations[0];
|
|
243
250
|
if (firstActive) {
|
|
244
251
|
const detail = firstActive.nextAction?.trim() || firstActive.content;
|
|
@@ -248,11 +255,56 @@ function nextSafeActionAfterObligationReconcile(resume, activeObligations, stale
|
|
|
248
255
|
if (remainingWork.length > 0) {
|
|
249
256
|
return (0, session_events_1.capStructuredRecordString)(`continue remaining Arc work: ${remainingWork.slice(0, 5).join(", ")}`);
|
|
250
257
|
}
|
|
251
|
-
|
|
258
|
+
if (staleActiveObligationIds.length > 0) {
|
|
259
|
+
return (0, session_events_1.capStructuredRecordString)(`wait for new input; reconciled completed or missing obligations: ${staleActiveObligationIds.join(", ")}`);
|
|
260
|
+
}
|
|
261
|
+
if (staleActiveReturnObligationIds.length > 0) {
|
|
262
|
+
return (0, session_events_1.capStructuredRecordString)(`wait for new input; reconciled completed or missing return obligations: ${staleActiveReturnObligationIds.join(", ")}`);
|
|
263
|
+
}
|
|
264
|
+
return (0, session_events_1.capStructuredRecordString)(`wait for new input; reconciled completed or missing packets: ${staleActivePacketIds.join(", ")}`);
|
|
265
|
+
}
|
|
266
|
+
function reconcileActiveReturnObligationIds(resume, returnObligations, activeReturnObligations) {
|
|
267
|
+
const canonicalIdSet = new Set(returnObligations.map((obligation) => obligation.id));
|
|
268
|
+
const activeIdSet = new Set(activeReturnObligations.map((obligation) => obligation.id));
|
|
269
|
+
const resumeIdSet = new Set(resume.activeReturnObligationIds);
|
|
270
|
+
const staleActiveReturnObligationIds = resume.activeReturnObligationIds.filter((id) => canonicalIdSet.has(id) && !activeIdSet.has(id));
|
|
271
|
+
const unverifiableActiveReturnObligationIds = resume.activeReturnObligationIds.filter((id) => !canonicalIdSet.has(id));
|
|
272
|
+
const missingActiveReturnObligationIds = activeReturnObligations
|
|
273
|
+
.map((obligation) => obligation.id)
|
|
274
|
+
.filter((id) => !resumeIdSet.has(id));
|
|
275
|
+
const activeReturnObligationIds = uniqueStrings([
|
|
276
|
+
...resume.activeReturnObligationIds.filter((id) => !staleActiveReturnObligationIds.includes(id)),
|
|
277
|
+
...missingActiveReturnObligationIds,
|
|
278
|
+
]);
|
|
279
|
+
return {
|
|
280
|
+
activeReturnObligationIds,
|
|
281
|
+
staleActiveReturnObligationIds,
|
|
282
|
+
missingActiveReturnObligationIds,
|
|
283
|
+
unverifiableActiveReturnObligationIds,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function reconcileActivePacketIds(resume, packets, activePackets) {
|
|
287
|
+
const canonicalIdSet = new Set(packets.map((packet) => packet.id));
|
|
288
|
+
const activeIdSet = new Set(activePackets.map((packet) => packet.id));
|
|
289
|
+
const resumeIdSet = new Set(resume.activePacketIds);
|
|
290
|
+
const staleActivePacketIds = resume.activePacketIds.filter((id) => canonicalIdSet.has(id) && !activeIdSet.has(id));
|
|
291
|
+
const unverifiableActivePacketIds = resume.activePacketIds.filter((id) => !canonicalIdSet.has(id));
|
|
292
|
+
const missingActivePacketIds = activePackets
|
|
293
|
+
.map((packet) => packet.id)
|
|
294
|
+
.filter((id) => !resumeIdSet.has(id));
|
|
295
|
+
const activePacketIds = uniqueStrings([
|
|
296
|
+
...resume.activePacketIds.filter((id) => !staleActivePacketIds.includes(id)),
|
|
297
|
+
...missingActivePacketIds,
|
|
298
|
+
]);
|
|
299
|
+
return { activePacketIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds };
|
|
252
300
|
}
|
|
253
301
|
function reconcileActiveObligations(agentRoot, resume) {
|
|
254
302
|
const obligations = (0, obligations_1.readVerifiedObligations)(agentRoot);
|
|
255
303
|
const activeObligations = (0, obligations_1.readVerifiedPendingObligations)(agentRoot);
|
|
304
|
+
const returnObligations = (0, obligations_1.listReturnObligationsForRoot)(agentRoot);
|
|
305
|
+
const activeReturnObligations = (0, obligations_1.listActiveReturnObligationsForRoot)(agentRoot);
|
|
306
|
+
const packets = (0, packets_1.listPonderPackets)(agentRoot);
|
|
307
|
+
const activePackets = (0, packets_1.listActivePonderPackets)(agentRoot);
|
|
256
308
|
const canonicalIdSet = new Set(obligations.map((obligation) => obligation.id));
|
|
257
309
|
const openIdSet = new Set(activeObligations.map((obligation) => obligation.id));
|
|
258
310
|
const resumeIdSet = new Set(resume.activeObligationIds);
|
|
@@ -261,33 +313,66 @@ function reconcileActiveObligations(agentRoot, resume) {
|
|
|
261
313
|
const missingActiveObligationIds = activeObligations
|
|
262
314
|
.map((obligation) => obligation.id)
|
|
263
315
|
.filter((id) => !resumeIdSet.has(id));
|
|
316
|
+
const { activeReturnObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, } = reconcileActiveReturnObligationIds(resume, returnObligations, activeReturnObligations);
|
|
317
|
+
const { activePacketIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds, } = reconcileActivePacketIds(resume, packets, activePackets);
|
|
264
318
|
if (staleActiveObligationIds.length === 0
|
|
265
319
|
&& missingActiveObligationIds.length === 0
|
|
266
|
-
&& unverifiableActiveObligationIds.length === 0
|
|
267
|
-
|
|
320
|
+
&& unverifiableActiveObligationIds.length === 0
|
|
321
|
+
&& staleActiveReturnObligationIds.length === 0
|
|
322
|
+
&& missingActiveReturnObligationIds.length === 0
|
|
323
|
+
&& unverifiableActiveReturnObligationIds.length === 0
|
|
324
|
+
&& staleActivePacketIds.length === 0
|
|
325
|
+
&& missingActivePacketIds.length === 0
|
|
326
|
+
&& unverifiableActivePacketIds.length === 0) {
|
|
327
|
+
return {
|
|
328
|
+
resume,
|
|
329
|
+
staleActiveObligationIds,
|
|
330
|
+
missingActiveObligationIds,
|
|
331
|
+
unverifiableActiveObligationIds,
|
|
332
|
+
staleActiveReturnObligationIds,
|
|
333
|
+
missingActiveReturnObligationIds,
|
|
334
|
+
unverifiableActiveReturnObligationIds,
|
|
335
|
+
staleActivePacketIds,
|
|
336
|
+
missingActivePacketIds,
|
|
337
|
+
unverifiableActivePacketIds,
|
|
338
|
+
};
|
|
268
339
|
}
|
|
269
340
|
const activeObligationIds = uniqueStrings([
|
|
270
341
|
...resume.activeObligationIds.filter((id) => !staleActiveObligationIds.includes(id)),
|
|
271
342
|
...missingActiveObligationIds,
|
|
272
343
|
]);
|
|
273
344
|
const hasActiveArcContinuation = activeObligationIds.length > 0
|
|
274
|
-
||
|
|
275
|
-
||
|
|
345
|
+
|| activeReturnObligationIds.length > 0
|
|
346
|
+
|| activePacketIds.length > 0
|
|
276
347
|
|| resume.openEvolutionCaseIds.length > 0;
|
|
277
|
-
const isTerminalWait = staleActiveObligationIds.length > 0
|
|
348
|
+
const isTerminalWait = (staleActiveObligationIds.length > 0
|
|
349
|
+
|| staleActiveReturnObligationIds.length > 0
|
|
350
|
+
|| staleActivePacketIds.length > 0) && !hasActiveArcContinuation;
|
|
278
351
|
const mustSynthesizeAction = staleActiveObligationIds.length > 0
|
|
279
352
|
|| unverifiableActiveObligationIds.length > 0
|
|
353
|
+
|| staleActiveReturnObligationIds.length > 0
|
|
354
|
+
|| unverifiableActiveReturnObligationIds.length > 0
|
|
355
|
+
|| staleActivePacketIds.length > 0
|
|
356
|
+
|| unverifiableActivePacketIds.length > 0
|
|
280
357
|
|| !nonEmpty(resume.nextSafeAction.value);
|
|
281
358
|
const nextSafeActionValue = mustSynthesizeAction
|
|
282
|
-
? nextSafeActionAfterObligationReconcile(resume, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds)
|
|
359
|
+
? nextSafeActionAfterObligationReconcile({ ...resume, activeObligationIds, activeReturnObligationIds, activePacketIds }, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, unverifiableActivePacketIds)
|
|
283
360
|
: resume.nextSafeAction.value;
|
|
284
|
-
const
|
|
361
|
+
const unverifiableIssues = [
|
|
362
|
+
...(unverifiableActiveObligationIds.length > 0
|
|
363
|
+
? [`active obligation ids could not be verified in arc/obligations: ${unverifiableActiveObligationIds.join(", ")}`]
|
|
364
|
+
: []),
|
|
365
|
+
...(unverifiableActiveReturnObligationIds.length > 0
|
|
366
|
+
? [`active return obligation ids could not be verified in arc/obligations/inner: ${unverifiableActiveReturnObligationIds.join(", ")}`]
|
|
367
|
+
: []),
|
|
368
|
+
...(unverifiableActivePacketIds.length > 0
|
|
369
|
+
? [`active packet ids could not be verified in arc/packets: ${unverifiableActivePacketIds.join(", ")}`]
|
|
370
|
+
: []),
|
|
371
|
+
];
|
|
372
|
+
const recorderHealth = unverifiableIssues.length > 0
|
|
285
373
|
? {
|
|
286
374
|
status: resume.recorderHealth.status === "unavailable" ? "unavailable" : "degraded",
|
|
287
|
-
issues: uniqueStrings([
|
|
288
|
-
...resume.recorderHealth.issues,
|
|
289
|
-
`active obligation ids could not be verified in arc/obligations: ${unverifiableActiveObligationIds.join(", ")}`,
|
|
290
|
-
]),
|
|
375
|
+
issues: uniqueStrings([...resume.recorderHealth.issues, ...unverifiableIssues]),
|
|
291
376
|
}
|
|
292
377
|
: resume.recorderHealth;
|
|
293
378
|
const canContinue = nonEmpty(resume.currentAsk.value)
|
|
@@ -302,6 +387,8 @@ function reconcileActiveObligations(agentRoot, resume) {
|
|
|
302
387
|
canContinue,
|
|
303
388
|
recorderHealth,
|
|
304
389
|
activeObligationIds,
|
|
390
|
+
activeReturnObligationIds,
|
|
391
|
+
activePacketIds,
|
|
305
392
|
nextSafeAction: {
|
|
306
393
|
...resume.nextSafeAction,
|
|
307
394
|
value: nextSafeActionValue,
|
|
@@ -309,22 +396,41 @@ function reconcileActiveObligations(agentRoot, resume) {
|
|
|
309
396
|
? [FLIGHT_RECORDER_RECONCILE_SOURCE_ID]
|
|
310
397
|
: resume.nextSafeAction.sourceEventIds,
|
|
311
398
|
stopBefore: unverifiableActiveObligationIds.length > 0
|
|
312
|
-
|
|
399
|
+
|| unverifiableActiveReturnObligationIds.length > 0
|
|
400
|
+
|| unverifiableActivePacketIds.length > 0
|
|
401
|
+
? uniqueStrings([
|
|
402
|
+
...resume.nextSafeAction.stopBefore,
|
|
403
|
+
...(unverifiableActiveObligationIds.length > 0 ? ["acting on unverifiable obligation state"] : []),
|
|
404
|
+
...(unverifiableActiveReturnObligationIds.length > 0 ? ["acting on unverifiable return obligation state"] : []),
|
|
405
|
+
...(unverifiableActivePacketIds.length > 0 ? ["acting on unverifiable packet state"] : []),
|
|
406
|
+
])
|
|
313
407
|
: resume.nextSafeAction.stopBefore,
|
|
314
408
|
},
|
|
315
409
|
}),
|
|
316
410
|
staleActiveObligationIds,
|
|
317
411
|
missingActiveObligationIds,
|
|
318
412
|
unverifiableActiveObligationIds,
|
|
413
|
+
staleActiveReturnObligationIds,
|
|
414
|
+
missingActiveReturnObligationIds,
|
|
415
|
+
unverifiableActiveReturnObligationIds,
|
|
416
|
+
staleActivePacketIds,
|
|
417
|
+
missingActivePacketIds,
|
|
418
|
+
unverifiableActivePacketIds,
|
|
319
419
|
};
|
|
320
420
|
}
|
|
321
421
|
function normalizeResumeForAgentRoot(agentRoot, resume) {
|
|
322
422
|
return reconcileActiveObligations(agentRoot, normalizeResumeInvariants(resume));
|
|
323
423
|
}
|
|
324
|
-
function emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds) {
|
|
424
|
+
function emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds) {
|
|
325
425
|
if (staleActiveObligationIds.length === 0
|
|
326
426
|
&& missingActiveObligationIds.length === 0
|
|
327
|
-
&& unverifiableActiveObligationIds.length === 0
|
|
427
|
+
&& unverifiableActiveObligationIds.length === 0
|
|
428
|
+
&& staleActiveReturnObligationIds.length === 0
|
|
429
|
+
&& missingActiveReturnObligationIds.length === 0
|
|
430
|
+
&& unverifiableActiveReturnObligationIds.length === 0
|
|
431
|
+
&& staleActivePacketIds.length === 0
|
|
432
|
+
&& missingActivePacketIds.length === 0
|
|
433
|
+
&& unverifiableActivePacketIds.length === 0)
|
|
328
434
|
return;
|
|
329
435
|
(0, runtime_1.emitNervesEvent)({
|
|
330
436
|
component: "mind",
|
|
@@ -335,6 +441,12 @@ function emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missi
|
|
|
335
441
|
staleActiveObligationIds,
|
|
336
442
|
missingActiveObligationIds,
|
|
337
443
|
unverifiableActiveObligationIds,
|
|
444
|
+
staleActiveReturnObligationIds,
|
|
445
|
+
missingActiveReturnObligationIds,
|
|
446
|
+
unverifiableActiveReturnObligationIds,
|
|
447
|
+
staleActivePacketIds,
|
|
448
|
+
missingActivePacketIds,
|
|
449
|
+
unverifiableActivePacketIds,
|
|
338
450
|
},
|
|
339
451
|
});
|
|
340
452
|
}
|
|
@@ -390,11 +502,17 @@ function readFlightRecorderResume(agentRoot) {
|
|
|
390
502
|
if (!isFlightRecorderResume(parsed)) {
|
|
391
503
|
throw new Error("latest.json has invalid flight-recorder resume shape");
|
|
392
504
|
}
|
|
393
|
-
const { resume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, } = normalizeResumeForAgentRoot(agentRoot, parsed);
|
|
505
|
+
const { resume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds, } = normalizeResumeForAgentRoot(agentRoot, parsed);
|
|
394
506
|
if (staleActiveObligationIds.length > 0
|
|
395
507
|
|| missingActiveObligationIds.length > 0
|
|
396
|
-
|| unverifiableActiveObligationIds.length > 0
|
|
397
|
-
|
|
508
|
+
|| unverifiableActiveObligationIds.length > 0
|
|
509
|
+
|| staleActiveReturnObligationIds.length > 0
|
|
510
|
+
|| missingActiveReturnObligationIds.length > 0
|
|
511
|
+
|| unverifiableActiveReturnObligationIds.length > 0
|
|
512
|
+
|| staleActivePacketIds.length > 0
|
|
513
|
+
|| missingActivePacketIds.length > 0
|
|
514
|
+
|| unverifiableActivePacketIds.length > 0) {
|
|
515
|
+
emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds);
|
|
398
516
|
}
|
|
399
517
|
(0, runtime_1.emitNervesEvent)({
|
|
400
518
|
component: "mind",
|
|
@@ -418,9 +536,9 @@ function readFlightRecorderResume(agentRoot) {
|
|
|
418
536
|
}
|
|
419
537
|
}
|
|
420
538
|
function writeFlightRecorderResume(agentRoot, resume) {
|
|
421
|
-
const { resume: safeResume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, } = normalizeResumeForAgentRoot(agentRoot, resume);
|
|
539
|
+
const { resume: safeResume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds, } = normalizeResumeForAgentRoot(agentRoot, resume);
|
|
422
540
|
atomicWriteJson(flightRecorderLatestPath(agentRoot), safeResume);
|
|
423
|
-
emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds);
|
|
541
|
+
emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, staleActiveReturnObligationIds, missingActiveReturnObligationIds, unverifiableActiveReturnObligationIds, staleActivePacketIds, missingActivePacketIds, unverifiableActivePacketIds);
|
|
424
542
|
(0, runtime_1.emitNervesEvent)({
|
|
425
543
|
component: "mind",
|
|
426
544
|
event: "mind.flight_recorder_resume_written",
|
package/dist/arc/obligations.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readObligation = readObligation;
|
|
36
37
|
exports.isOpenObligationStatus = isOpenObligationStatus;
|
|
37
38
|
exports.isOpenObligation = isOpenObligation;
|
|
38
39
|
exports.createObligation = createObligation;
|
|
@@ -49,7 +50,11 @@ exports.getReturnObligationsDir = getReturnObligationsDir;
|
|
|
49
50
|
exports.getReturnObligationsDirForRoot = getReturnObligationsDirForRoot;
|
|
50
51
|
exports.createReturnObligation = createReturnObligation;
|
|
51
52
|
exports.readReturnObligation = readReturnObligation;
|
|
53
|
+
exports.readReturnObligationForRoot = readReturnObligationForRoot;
|
|
52
54
|
exports.advanceReturnObligation = advanceReturnObligation;
|
|
55
|
+
exports.isActiveReturnObligationStatus = isActiveReturnObligationStatus;
|
|
56
|
+
exports.listReturnObligationsForRoot = listReturnObligationsForRoot;
|
|
57
|
+
exports.isActiveReturnObligationRecord = isActiveReturnObligationRecord;
|
|
53
58
|
exports.listActiveReturnObligations = listActiveReturnObligations;
|
|
54
59
|
exports.listActiveReturnObligationsForRoot = listActiveReturnObligationsForRoot;
|
|
55
60
|
const path = __importStar(require("path"));
|
|
@@ -60,6 +65,9 @@ const json_store_1 = require("./json-store");
|
|
|
60
65
|
function obligationsDir(agentRoot) {
|
|
61
66
|
return path.join(agentRoot, "arc", "obligations");
|
|
62
67
|
}
|
|
68
|
+
function readObligation(agentRoot, obligationId) {
|
|
69
|
+
return (0, json_store_1.readJsonFile)(obligationsDir(agentRoot), obligationId);
|
|
70
|
+
}
|
|
63
71
|
function isOpenObligationStatus(status) {
|
|
64
72
|
return status !== "fulfilled";
|
|
65
73
|
}
|
|
@@ -256,6 +264,9 @@ function createReturnObligation(agentName, obligation) {
|
|
|
256
264
|
function readReturnObligation(agentName, obligationId) {
|
|
257
265
|
return (0, json_store_1.readJsonFile)(getReturnObligationsDir(agentName), obligationId);
|
|
258
266
|
}
|
|
267
|
+
function readReturnObligationForRoot(agentRoot, obligationId) {
|
|
268
|
+
return (0, json_store_1.readJsonFile)(getReturnObligationsDirForRoot(agentRoot), obligationId);
|
|
269
|
+
}
|
|
259
270
|
function advanceReturnObligation(agentName, obligationId, update) {
|
|
260
271
|
const existing = readReturnObligation(agentName, obligationId);
|
|
261
272
|
if (!existing)
|
|
@@ -295,6 +306,9 @@ const RETURN_OBLIGATION_INJECTION_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000;
|
|
|
295
306
|
// surface-tool boundary) is treated as terminal — i.e., we do not re-inject
|
|
296
307
|
// it. This is a read-time defense; the underlying file is left as-is.
|
|
297
308
|
const ACTIVE_RETURN_OBLIGATION_STATUSES = new Set(["queued", "running"]);
|
|
309
|
+
function isActiveReturnObligationStatus(status) {
|
|
310
|
+
return ACTIVE_RETURN_OBLIGATION_STATUSES.has(status);
|
|
311
|
+
}
|
|
298
312
|
function isSelfInnerReturnObligation(obligation) {
|
|
299
313
|
return obligation.origin?.friendId === "self" && obligation.origin.channel === "inner";
|
|
300
314
|
}
|
|
@@ -311,16 +325,24 @@ function isReturnObligationRecord(value) {
|
|
|
311
325
|
&& typeof candidate.origin.channel === "string"
|
|
312
326
|
&& typeof candidate.origin.key === "string";
|
|
313
327
|
}
|
|
328
|
+
function listReturnObligationsForRoot(agentRoot) {
|
|
329
|
+
return (0, json_store_1.readJsonDir)(getReturnObligationsDirForRoot(agentRoot))
|
|
330
|
+
.filter(isReturnObligationRecord);
|
|
331
|
+
}
|
|
332
|
+
function isActiveReturnObligationRecord(value, options = {}) {
|
|
333
|
+
if (!isReturnObligationRecord(value))
|
|
334
|
+
return false;
|
|
335
|
+
const nowMs = (options.now ?? Date.now)();
|
|
336
|
+
return isActiveReturnObligationStatus(value.status)
|
|
337
|
+
&& !isSelfInnerReturnObligation(value)
|
|
338
|
+
&& nowMs - value.createdAt <= RETURN_OBLIGATION_INJECTION_MAX_AGE_MS;
|
|
339
|
+
}
|
|
314
340
|
function listActiveReturnObligations(agentName, options = {}) {
|
|
315
341
|
return listActiveReturnObligationsForRoot((0, identity_1.getAgentRoot)(agentName), options);
|
|
316
342
|
}
|
|
317
343
|
function listActiveReturnObligationsForRoot(agentRoot, options = {}) {
|
|
318
|
-
const all = (0, json_store_1.readJsonDir)(getReturnObligationsDirForRoot(agentRoot));
|
|
319
344
|
const nowMs = (options.now ?? Date.now)();
|
|
320
|
-
return
|
|
321
|
-
.filter(
|
|
322
|
-
.filter((parsed) => ACTIVE_RETURN_OBLIGATION_STATUSES.has(parsed.status))
|
|
323
|
-
.filter((parsed) => !isSelfInnerReturnObligation(parsed))
|
|
324
|
-
.filter((parsed) => nowMs - parsed.createdAt <= RETURN_OBLIGATION_INJECTION_MAX_AGE_MS)
|
|
345
|
+
return listReturnObligationsForRoot(agentRoot)
|
|
346
|
+
.filter((parsed) => isActiveReturnObligationRecord(parsed, { now: () => nowMs }))
|
|
325
347
|
.sort((a, b) => a.createdAt - b.createdAt);
|
|
326
348
|
}
|
package/dist/arc/packets.js
CHANGED
|
@@ -33,9 +33,16 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ACTIVE_PONDER_PACKET_STATUSES = void 0;
|
|
36
37
|
exports.getPonderPacketArtifactsDir = getPonderPacketArtifactsDir;
|
|
38
|
+
exports.isActivePonderPacketStatus = isActivePonderPacketStatus;
|
|
39
|
+
exports.isActivePonderPacket = isActivePonderPacket;
|
|
37
40
|
exports.listPonderPackets = listPonderPackets;
|
|
41
|
+
exports.listActivePonderPackets = listActivePonderPackets;
|
|
38
42
|
exports.readPonderPacket = readPonderPacket;
|
|
43
|
+
exports.findPonderPacketByRelatedReturnObligationId = findPonderPacketByRelatedReturnObligationId;
|
|
44
|
+
exports.listPonderPacketsByRelatedReturnObligationId = listPonderPacketsByRelatedReturnObligationId;
|
|
45
|
+
exports.listPonderPacketsByRelatedObligationId = listPonderPacketsByRelatedObligationId;
|
|
39
46
|
exports.createPonderPacket = createPonderPacket;
|
|
40
47
|
exports.revisePonderPacket = revisePonderPacket;
|
|
41
48
|
exports.advancePonderPacket = advancePonderPacket;
|
|
@@ -46,6 +53,7 @@ const session_events_1 = require("../heart/session-events");
|
|
|
46
53
|
const runtime_1 = require("../nerves/runtime");
|
|
47
54
|
const task_lifecycle_1 = require("./task-lifecycle");
|
|
48
55
|
const json_store_1 = require("./json-store");
|
|
56
|
+
const obligations_1 = require("./obligations");
|
|
49
57
|
const evolution_1 = require("./evolution");
|
|
50
58
|
function packetsDir(agentRoot) {
|
|
51
59
|
return path.join(agentRoot, "arc", "packets");
|
|
@@ -82,6 +90,34 @@ function isPonderPacket(value) {
|
|
|
82
90
|
&& typeof packet.createdAt === "number"
|
|
83
91
|
&& typeof packet.updatedAt === "number";
|
|
84
92
|
}
|
|
93
|
+
exports.ACTIVE_PONDER_PACKET_STATUSES = new Set([
|
|
94
|
+
"drafting",
|
|
95
|
+
"processing",
|
|
96
|
+
"validating",
|
|
97
|
+
"collaborating",
|
|
98
|
+
"paused",
|
|
99
|
+
"blocked",
|
|
100
|
+
]);
|
|
101
|
+
function isActivePonderPacketStatus(status) {
|
|
102
|
+
return exports.ACTIVE_PONDER_PACKET_STATUSES.has(status);
|
|
103
|
+
}
|
|
104
|
+
function hasInactiveLinkedReturnObligation(agentRoot, packet, options = {}) {
|
|
105
|
+
if (!packet.relatedReturnObligationId)
|
|
106
|
+
return false;
|
|
107
|
+
const obligation = (0, obligations_1.readReturnObligationForRoot)(agentRoot, packet.relatedReturnObligationId);
|
|
108
|
+
return !(0, obligations_1.isActiveReturnObligationRecord)(obligation, options);
|
|
109
|
+
}
|
|
110
|
+
function hasFulfilledLinkedObligation(agentRoot, packet) {
|
|
111
|
+
if (!packet.relatedObligationId)
|
|
112
|
+
return false;
|
|
113
|
+
const obligation = (0, obligations_1.readObligation)(agentRoot, packet.relatedObligationId);
|
|
114
|
+
return obligation?.status === "fulfilled";
|
|
115
|
+
}
|
|
116
|
+
function isActivePonderPacket(agentRoot, packet, options = {}) {
|
|
117
|
+
return isActivePonderPacketStatus(packet.status)
|
|
118
|
+
&& !hasInactiveLinkedReturnObligation(agentRoot, packet, options)
|
|
119
|
+
&& !hasFulfilledLinkedObligation(agentRoot, packet);
|
|
120
|
+
}
|
|
85
121
|
function payloadString(payload, key) {
|
|
86
122
|
const value = payload[key];
|
|
87
123
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
@@ -156,10 +192,22 @@ function listPonderPackets(agentRoot) {
|
|
|
156
192
|
.filter(isPonderPacket)
|
|
157
193
|
.sort((left, right) => left.createdAt - right.createdAt);
|
|
158
194
|
}
|
|
195
|
+
function listActivePonderPackets(agentRoot, options = {}) {
|
|
196
|
+
return listPonderPackets(agentRoot).filter((packet) => isActivePonderPacket(agentRoot, packet, options));
|
|
197
|
+
}
|
|
159
198
|
function readPonderPacket(agentRoot, packetId) {
|
|
160
199
|
const packet = (0, json_store_1.readJsonFile)(packetsDir(agentRoot), packetId);
|
|
161
200
|
return isPonderPacket(packet) ? packet : null;
|
|
162
201
|
}
|
|
202
|
+
function findPonderPacketByRelatedReturnObligationId(agentRoot, relatedReturnObligationId) {
|
|
203
|
+
return listPonderPacketsByRelatedReturnObligationId(agentRoot, relatedReturnObligationId)[0] ?? null;
|
|
204
|
+
}
|
|
205
|
+
function listPonderPacketsByRelatedReturnObligationId(agentRoot, relatedReturnObligationId) {
|
|
206
|
+
return listPonderPackets(agentRoot).filter((packet) => packet.relatedReturnObligationId === relatedReturnObligationId);
|
|
207
|
+
}
|
|
208
|
+
function listPonderPacketsByRelatedObligationId(agentRoot, relatedObligationId) {
|
|
209
|
+
return listPonderPackets(agentRoot).filter((packet) => packet.relatedObligationId === relatedObligationId);
|
|
210
|
+
}
|
|
163
211
|
function createPonderPacket(agentRoot, input) {
|
|
164
212
|
const now = Date.now();
|
|
165
213
|
const packet = bindHarnessFrictionEvolutionCase(agentRoot, {
|
|
@@ -48,6 +48,7 @@ const runtime_1 = require("../nerves/runtime");
|
|
|
48
48
|
const context_loss_gauntlet_1 = require("./context-loss-gauntlet");
|
|
49
49
|
const provider_visibility_1 = require("./provider-visibility");
|
|
50
50
|
const CONTEXT_LOSS_SENTINEL_RECEIPT_FILE_LIMIT = 512;
|
|
51
|
+
const CONTEXT_LOSS_SENTINEL_GIT_STATUS_TIMEOUT_MS = 5_000;
|
|
51
52
|
const REQUIRED_LANES = ["outward", "inner"];
|
|
52
53
|
function logicalLocator(...parts) {
|
|
53
54
|
return path.posix.join(...parts);
|
|
@@ -524,7 +525,7 @@ function defaultGitStatus(agentRoot) {
|
|
|
524
525
|
cwd: agentRoot,
|
|
525
526
|
encoding: "utf-8",
|
|
526
527
|
stdio: ["ignore", "pipe", "pipe"],
|
|
527
|
-
timeout:
|
|
528
|
+
timeout: CONTEXT_LOSS_SENTINEL_GIT_STATUS_TIMEOUT_MS,
|
|
528
529
|
});
|
|
529
530
|
return { ok: true, porcelain };
|
|
530
531
|
}
|
|
@@ -574,7 +575,167 @@ function isSentinelGitStatusEntry(entry) {
|
|
|
574
575
|
return normalizedPath === sentinelRoot || normalizedPath.startsWith(`${sentinelRoot}/`);
|
|
575
576
|
});
|
|
576
577
|
}
|
|
577
|
-
function
|
|
578
|
+
function isContextLossSentinelBlockerText(value) {
|
|
579
|
+
return value.startsWith("context-loss Sentinel blocked:");
|
|
580
|
+
}
|
|
581
|
+
function hasContextLossSentinelCheckpointEvents(agentRoot, resume) {
|
|
582
|
+
const events = readFlightRecorderEventsByIds(agentRoot, resume.lastSafeCheckpoint.sourceEventIds);
|
|
583
|
+
const foundEventIds = new Set(events.map((event) => event.id));
|
|
584
|
+
if (resume.lastSafeCheckpoint.sourceEventIds.some((eventId) => !foundEventIds.has(eventId)))
|
|
585
|
+
return false;
|
|
586
|
+
return resume.blockedBecause.length > 0
|
|
587
|
+
? events.every(isContextLossSentinelBlockerEvent)
|
|
588
|
+
: events.every(isContextLossSentinelRecoveryEvent);
|
|
589
|
+
}
|
|
590
|
+
function isContextLossSentinelCheckpoint(agentRoot, resume) {
|
|
591
|
+
return resume.lastSafeCheckpoint.sourceEventIds.length > 0
|
|
592
|
+
&& resume.lastSafeCheckpoint.sourceEventIds.every((eventId) => eventId.startsWith("fr-sentinel-"))
|
|
593
|
+
&& resume.blockedBecause.every(isContextLossSentinelBlockerText)
|
|
594
|
+
&& hasContextLossSentinelCheckpointEvents(agentRoot, resume);
|
|
595
|
+
}
|
|
596
|
+
function neutralizeSentinelCheckpoint(resume) {
|
|
597
|
+
return {
|
|
598
|
+
...resume,
|
|
599
|
+
canContinue: true,
|
|
600
|
+
blockedBecause: [],
|
|
601
|
+
lastSafeCheckpoint: {
|
|
602
|
+
turnId: null,
|
|
603
|
+
sessionRef: null,
|
|
604
|
+
recordedAt: null,
|
|
605
|
+
sourceEventIds: [],
|
|
606
|
+
},
|
|
607
|
+
recorderHealth: { status: "ok", issues: [] },
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function isContextLossSentinelProducedRef(value) {
|
|
611
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
612
|
+
return false;
|
|
613
|
+
const record = value;
|
|
614
|
+
if (record.kind !== "arc" || typeof record.locator !== "string")
|
|
615
|
+
return false;
|
|
616
|
+
const sentinelRoot = relativeSentinelRoot();
|
|
617
|
+
return record.locator === sentinelRoot || record.locator.startsWith(`${sentinelRoot}/`);
|
|
618
|
+
}
|
|
619
|
+
function isContextLossSentinelFlightRecorderEvent(value) {
|
|
620
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
621
|
+
return false;
|
|
622
|
+
const record = value;
|
|
623
|
+
const meta = record.meta;
|
|
624
|
+
const producedRefs = record.producedRefs;
|
|
625
|
+
return typeof record.id === "string"
|
|
626
|
+
&& record.id.startsWith("fr-sentinel-")
|
|
627
|
+
&& (record.kind === "blocker_detected" || record.kind === "agent_note")
|
|
628
|
+
&& meta?.source === "context-loss-sentinel"
|
|
629
|
+
&& Array.isArray(producedRefs)
|
|
630
|
+
&& producedRefs.length > 0
|
|
631
|
+
&& producedRefs.every(isContextLossSentinelProducedRef);
|
|
632
|
+
}
|
|
633
|
+
function isContextLossSentinelBlockerEvent(event) {
|
|
634
|
+
return isContextLossSentinelFlightRecorderEvent(event)
|
|
635
|
+
&& event.kind === "blocker_detected"
|
|
636
|
+
&& Array.isArray(event.blockedBecause)
|
|
637
|
+
&& event.blockedBecause.length > 0
|
|
638
|
+
&& event.blockedBecause.every(isContextLossSentinelBlockerText);
|
|
639
|
+
}
|
|
640
|
+
function isContextLossSentinelRecoveryEvent(event) {
|
|
641
|
+
return isContextLossSentinelFlightRecorderEvent(event)
|
|
642
|
+
&& event.kind === "agent_note"
|
|
643
|
+
&& Array.isArray(event.blockedBecause)
|
|
644
|
+
&& event.blockedBecause.length === 0
|
|
645
|
+
&& event.meta?.resolution === "blocked-signals-recovered";
|
|
646
|
+
}
|
|
647
|
+
function gitShowHeadFile(agentRoot, entryPath) {
|
|
648
|
+
try {
|
|
649
|
+
return (0, child_process_1.execFileSync)("git", ["show", `HEAD:${entryPath}`], {
|
|
650
|
+
cwd: agentRoot,
|
|
651
|
+
encoding: "utf-8",
|
|
652
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
653
|
+
timeout: CONTEXT_LOSS_SENTINEL_GIT_STATUS_TIMEOUT_MS,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
catch {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
function nonEmptyLines(text) {
|
|
661
|
+
return text.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
662
|
+
}
|
|
663
|
+
function isFlightRecorderEventsPath(entryPath) {
|
|
664
|
+
return /^arc\/flight-recorder\/events\/[^/]+\.jsonl$/.test(entryPath);
|
|
665
|
+
}
|
|
666
|
+
function isFlightRecorderLatestPath(entryPath) {
|
|
667
|
+
return entryPath === "arc/flight-recorder/latest.json";
|
|
668
|
+
}
|
|
669
|
+
function isDeletedGitStatusEntry(entry) {
|
|
670
|
+
return entry.slice(0, 2).includes("D");
|
|
671
|
+
}
|
|
672
|
+
function isUntrackedGitStatusEntry(entry) {
|
|
673
|
+
return entry.startsWith("??");
|
|
674
|
+
}
|
|
675
|
+
function isWorktreeOnlyModifiedGitStatusEntry(entry) {
|
|
676
|
+
return entry.slice(0, 2) === " M";
|
|
677
|
+
}
|
|
678
|
+
function parseJsonLine(line) {
|
|
679
|
+
try {
|
|
680
|
+
return JSON.parse(line);
|
|
681
|
+
}
|
|
682
|
+
catch {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function isContextLossSentinelEventFileDirty(agentRoot, entry, entryPath) {
|
|
687
|
+
if (isDeletedGitStatusEntry(entry))
|
|
688
|
+
return false;
|
|
689
|
+
const filePath = path.join(agentRoot, entryPath);
|
|
690
|
+
if (isUntrackedGitStatusEntry(entry)) {
|
|
691
|
+
const candidateLines = fs.existsSync(filePath) ? nonEmptyLines(fs.readFileSync(filePath, "utf-8")) : [];
|
|
692
|
+
return candidateLines.length > 0
|
|
693
|
+
&& candidateLines.every((line) => isContextLossSentinelFlightRecorderEvent(parseJsonLine(line)));
|
|
694
|
+
}
|
|
695
|
+
if (!isWorktreeOnlyModifiedGitStatusEntry(entry) || !fs.existsSync(filePath))
|
|
696
|
+
return false;
|
|
697
|
+
const headText = gitShowHeadFile(agentRoot, entryPath);
|
|
698
|
+
if (headText === null)
|
|
699
|
+
return false;
|
|
700
|
+
const headLines = nonEmptyLines(headText);
|
|
701
|
+
const currentLines = nonEmptyLines(fs.readFileSync(filePath, "utf-8"));
|
|
702
|
+
if (currentLines.length <= headLines.length)
|
|
703
|
+
return false;
|
|
704
|
+
if (!headLines.every((line, index) => currentLines[index] === line))
|
|
705
|
+
return false;
|
|
706
|
+
const appendedLines = currentLines.slice(headLines.length);
|
|
707
|
+
return appendedLines.every((line) => isContextLossSentinelFlightRecorderEvent(parseJsonLine(line)));
|
|
708
|
+
}
|
|
709
|
+
function isContextLossSentinelLatestDirty(agentRoot, entry, entryPath) {
|
|
710
|
+
if (isDeletedGitStatusEntry(entry) || isUntrackedGitStatusEntry(entry))
|
|
711
|
+
return false;
|
|
712
|
+
if (!isWorktreeOnlyModifiedGitStatusEntry(entry))
|
|
713
|
+
return false;
|
|
714
|
+
const current = readJson(path.join(agentRoot, entryPath));
|
|
715
|
+
if (!current.ok || !(0, flight_recorder_1.isFlightRecorderResume)(current.value) || !isContextLossSentinelCheckpoint(agentRoot, current.value)) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
const headText = gitShowHeadFile(agentRoot, entryPath);
|
|
719
|
+
if (headText === null)
|
|
720
|
+
return false;
|
|
721
|
+
const head = parseJsonLine(headText);
|
|
722
|
+
if (!(0, flight_recorder_1.isFlightRecorderResume)(head))
|
|
723
|
+
return false;
|
|
724
|
+
return JSON.stringify(neutralizeSentinelCheckpoint(current.value))
|
|
725
|
+
=== JSON.stringify(neutralizeSentinelCheckpoint(head));
|
|
726
|
+
}
|
|
727
|
+
function isContextLossSentinelFlightRecorderGitStatusEntry(agentRoot, entry) {
|
|
728
|
+
return gitStatusPaths(entry).every((entryPath) => (isFlightRecorderEventsPath(entryPath)
|
|
729
|
+
? isContextLossSentinelEventFileDirty(agentRoot, entry, entryPath)
|
|
730
|
+
: isFlightRecorderLatestPath(entryPath)
|
|
731
|
+
? isContextLossSentinelLatestDirty(agentRoot, entry, entryPath)
|
|
732
|
+
: false));
|
|
733
|
+
}
|
|
734
|
+
function isContextLossSentinelOwnedGitStatusEntry(entry, options) {
|
|
735
|
+
return isSentinelGitStatusEntry(entry)
|
|
736
|
+
|| isContextLossSentinelFlightRecorderGitStatusEntry(options.agentRoot, entry);
|
|
737
|
+
}
|
|
738
|
+
function bundleSignal(status, options) {
|
|
578
739
|
const gitStatusCommand = "git status --porcelain=v1 -uall";
|
|
579
740
|
if (!status.ok) {
|
|
580
741
|
return {
|
|
@@ -589,7 +750,7 @@ function bundleSignal(status, options = {}) {
|
|
|
589
750
|
};
|
|
590
751
|
}
|
|
591
752
|
const dirtyEntries = gitStatusEntries(status.porcelain)
|
|
592
|
-
.filter((entry) => !(options.ignoreSentinelDirtyEntries &&
|
|
753
|
+
.filter((entry) => !(options.ignoreSentinelDirtyEntries && isContextLossSentinelOwnedGitStatusEntry(entry, options)));
|
|
593
754
|
if (dirtyEntries.length > 0) {
|
|
594
755
|
return {
|
|
595
756
|
id: "bundle:git",
|
|
@@ -723,6 +884,7 @@ function makeReceipt(agentName, agentRoot, options, generatedAt) {
|
|
|
723
884
|
...healthSignals(options.daemonHealthResults ?? []),
|
|
724
885
|
bundleSignal((options.gitStatus ?? (() => defaultGitStatus(agentRoot)))(), {
|
|
725
886
|
ignoreSentinelDirtyEntries: options.trigger === "daemon_health",
|
|
887
|
+
agentRoot,
|
|
726
888
|
}),
|
|
727
889
|
];
|
|
728
890
|
const verdict = sentinelVerdict(signals);
|
|
@@ -687,9 +687,15 @@ void preloadProviderCredentialPools().then(() => daemon.start()).then(async () =
|
|
|
687
687
|
message: "daemon entrypoint failed",
|
|
688
688
|
meta: { error: error.message },
|
|
689
689
|
});
|
|
690
|
-
setTimeout(() => process.exit(1), 5_000)
|
|
691
|
-
|
|
692
|
-
|
|
690
|
+
const forcedExit = setTimeout(() => process.exit(1), 5_000);
|
|
691
|
+
forcedExit.unref();
|
|
692
|
+
try {
|
|
693
|
+
await daemon.stop();
|
|
694
|
+
}
|
|
695
|
+
finally {
|
|
696
|
+
clearTimeout(forcedExit);
|
|
697
|
+
process.exit(1);
|
|
698
|
+
}
|
|
693
699
|
});
|
|
694
700
|
process.on("SIGINT", () => {
|
|
695
701
|
// ALWAYS write a tombstone, even on signal-driven shutdown. The previous
|
|
@@ -702,15 +708,29 @@ process.on("SIGINT", () => {
|
|
|
702
708
|
_tombstoneWritten = true;
|
|
703
709
|
(0, daemon_tombstone_1.writeDaemonTombstone)("sigint", new Error("daemon received SIGINT"));
|
|
704
710
|
stopEntryRuntime();
|
|
705
|
-
setTimeout(() => process.exit(1), 5_000)
|
|
706
|
-
|
|
711
|
+
const forcedExit = setTimeout(() => process.exit(1), 5_000);
|
|
712
|
+
forcedExit.unref();
|
|
713
|
+
void daemon.stop().then(() => {
|
|
714
|
+
clearTimeout(forcedExit);
|
|
715
|
+
process.exit(0);
|
|
716
|
+
}, () => {
|
|
717
|
+
clearTimeout(forcedExit);
|
|
718
|
+
process.exit(1);
|
|
719
|
+
});
|
|
707
720
|
});
|
|
708
721
|
process.on("SIGTERM", () => {
|
|
709
722
|
_tombstoneWritten = true;
|
|
710
723
|
(0, daemon_tombstone_1.writeDaemonTombstone)("sigterm", new Error("daemon received SIGTERM"));
|
|
711
724
|
stopEntryRuntime();
|
|
712
|
-
setTimeout(() => process.exit(1), 5_000)
|
|
713
|
-
|
|
725
|
+
const forcedExit = setTimeout(() => process.exit(1), 5_000);
|
|
726
|
+
forcedExit.unref();
|
|
727
|
+
void daemon.stop().then(() => {
|
|
728
|
+
clearTimeout(forcedExit);
|
|
729
|
+
process.exit(0);
|
|
730
|
+
}, () => {
|
|
731
|
+
clearTimeout(forcedExit);
|
|
732
|
+
process.exit(1);
|
|
733
|
+
});
|
|
714
734
|
});
|
|
715
735
|
/* v8 ignore stop */
|
|
716
736
|
// Suppress EPIPE on stdout/stderr — normal when detached daemon's parent exits
|
|
@@ -750,8 +770,12 @@ process.on("uncaughtException", (error) => {
|
|
|
750
770
|
message: `daemon exiting: ${_uncaughtCount} uncaught exceptions in ${CIRCUIT_BREAKER_WINDOW_MS / 1000}s`,
|
|
751
771
|
meta: { uncaughtCount: _uncaughtCount },
|
|
752
772
|
});
|
|
753
|
-
setTimeout(() => process.exit(1), 5_000)
|
|
754
|
-
|
|
773
|
+
const forcedExit = setTimeout(() => process.exit(1), 5_000);
|
|
774
|
+
forcedExit.unref();
|
|
775
|
+
void daemon.stop().finally(() => {
|
|
776
|
+
clearTimeout(forcedExit);
|
|
777
|
+
process.exit(1);
|
|
778
|
+
});
|
|
755
779
|
}
|
|
756
780
|
});
|
|
757
781
|
process.on("unhandledRejection", (reason) => {
|
package/dist/heart/work-card.js
CHANGED
|
@@ -44,14 +44,6 @@ const evolution_1 = require("../arc/evolution");
|
|
|
44
44
|
const obligations_1 = require("../arc/obligations");
|
|
45
45
|
const packets_1 = require("../arc/packets");
|
|
46
46
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
47
|
-
const ACTIVE_PACKET_STATUSES = new Set([
|
|
48
|
-
"drafting",
|
|
49
|
-
"processing",
|
|
50
|
-
"validating",
|
|
51
|
-
"collaborating",
|
|
52
|
-
"paused",
|
|
53
|
-
"blocked",
|
|
54
|
-
]);
|
|
55
47
|
function isoFromMs(ms) {
|
|
56
48
|
return new Date(ms).toISOString();
|
|
57
49
|
}
|
|
@@ -244,9 +236,7 @@ function buildWorkCard(agentName, agentRoot, options = {}) {
|
|
|
244
236
|
const sourceIssues = scanArcSourceIssues(agentRoot);
|
|
245
237
|
const owed = (0, obligations_1.readPendingObligations)(agentRoot).map(obligationItem);
|
|
246
238
|
const returnObligations = (0, obligations_1.listActiveReturnObligationsForRoot)(agentRoot, { now: options.nowMs }).map(returnObligationItem);
|
|
247
|
-
const activePackets = (0, packets_1.
|
|
248
|
-
.filter((packet) => ACTIVE_PACKET_STATUSES.has(packet.status))
|
|
249
|
-
.map(packetItem);
|
|
239
|
+
const activePackets = (0, packets_1.listActivePonderPackets)(agentRoot, { now: options.nowMs }).map(packetItem);
|
|
250
240
|
const evolutionCases = (0, evolution_1.listOpenEvolutionCases)(agentRoot).map(evolutionItem);
|
|
251
241
|
const activeWork = [...activePackets, ...evolutionCases];
|
|
252
242
|
const waiting = waitingOnHuman([...owed, ...returnObligations, ...activeWork]);
|
|
@@ -39,6 +39,7 @@ const identity_1 = require("../heart/identity");
|
|
|
39
39
|
const runtime_1 = require("../nerves/runtime");
|
|
40
40
|
const json_store_1 = require("../arc/json-store");
|
|
41
41
|
const obligations_1 = require("../arc/obligations");
|
|
42
|
+
const packets_1 = require("../arc/packets");
|
|
42
43
|
/**
|
|
43
44
|
* `let_go` lets the agent release a held work item from its attention loop.
|
|
44
45
|
*
|
|
@@ -61,6 +62,40 @@ function outerObligationsDir(agentRoot) {
|
|
|
61
62
|
function readOuterObligation(agentRoot, id) {
|
|
62
63
|
return (0, json_store_1.readJsonFile)(outerObligationsDir(agentRoot), id) ?? null;
|
|
63
64
|
}
|
|
65
|
+
function completeRelatedPacket(agentRoot, packet, relation) {
|
|
66
|
+
try {
|
|
67
|
+
(0, packets_1.completePonderPacket)(agentRoot, packet.id);
|
|
68
|
+
(0, runtime_1.emitNervesEvent)({
|
|
69
|
+
component: "repertoire",
|
|
70
|
+
event: "repertoire.packet_completed_for_released_obligation",
|
|
71
|
+
message: "linked packet completed for released return obligation",
|
|
72
|
+
meta: { ...relation, packetId: packet.id },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
(0, runtime_1.emitNervesEvent)({
|
|
77
|
+
level: "warn",
|
|
78
|
+
component: "repertoire",
|
|
79
|
+
event: "repertoire.packet_completion_for_released_obligation_failed",
|
|
80
|
+
message: "failed to complete linked packet for released return obligation",
|
|
81
|
+
meta: {
|
|
82
|
+
...relation,
|
|
83
|
+
packetId: packet.id,
|
|
84
|
+
error: error instanceof Error ? error.message : String(error),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function completePacketsForReturnObligation(agentRoot, returnObligationId) {
|
|
90
|
+
for (const packet of (0, packets_1.listPonderPacketsByRelatedReturnObligationId)(agentRoot, returnObligationId)) {
|
|
91
|
+
completeRelatedPacket(agentRoot, packet, { returnObligationId });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function completePacketsForObligation(agentRoot, obligationId) {
|
|
95
|
+
for (const packet of (0, packets_1.listPonderPacketsByRelatedObligationId)(agentRoot, obligationId)) {
|
|
96
|
+
completeRelatedPacket(agentRoot, packet, { obligationId });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
64
99
|
function letGo(args, agentRoot, agentName) {
|
|
65
100
|
if (typeof args.id !== "string" || args.id.trim().length === 0) {
|
|
66
101
|
return JSON.stringify({ error: "id is required" });
|
|
@@ -73,6 +108,7 @@ function letGo(args, agentRoot, agentName) {
|
|
|
73
108
|
const ret = (0, obligations_1.readReturnObligation)(agentName, id);
|
|
74
109
|
if (ret) {
|
|
75
110
|
if (ret.status === "returned" || ret.status === "deferred") {
|
|
111
|
+
completePacketsForReturnObligation(agentRoot, id);
|
|
76
112
|
return JSON.stringify({ kind: "return_obligation", id, already: ret.status });
|
|
77
113
|
}
|
|
78
114
|
(0, obligations_1.advanceReturnObligation)(agentName, id, {
|
|
@@ -80,6 +116,7 @@ function letGo(args, agentRoot, agentName) {
|
|
|
80
116
|
returnedAt: Date.now(),
|
|
81
117
|
returnTarget: "surface",
|
|
82
118
|
});
|
|
119
|
+
completePacketsForReturnObligation(agentRoot, id);
|
|
83
120
|
(0, runtime_1.emitNervesEvent)({
|
|
84
121
|
component: "repertoire",
|
|
85
122
|
event: "repertoire.obligation_let_go",
|
|
@@ -92,9 +129,11 @@ function letGo(args, agentRoot, agentName) {
|
|
|
92
129
|
const outer = readOuterObligation(agentRoot, id);
|
|
93
130
|
if (outer) {
|
|
94
131
|
if (outer.status === "fulfilled") {
|
|
132
|
+
completePacketsForObligation(agentRoot, id);
|
|
95
133
|
return JSON.stringify({ kind: "obligation", id, already: "fulfilled" });
|
|
96
134
|
}
|
|
97
135
|
(0, obligations_1.fulfillObligation)(agentRoot, id);
|
|
136
|
+
completePacketsForObligation(agentRoot, id);
|
|
98
137
|
if (reason !== null) {
|
|
99
138
|
// Persist the dismissal reason as the obligation's latestNote so future-me
|
|
100
139
|
// can read why this was released (the nerves event also captures it).
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -71,14 +71,6 @@ const orientation_frame_1 = require("../heart/orientation-frame");
|
|
|
71
71
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
72
72
|
const context_loss_sentinel_1 = require("../heart/context-loss-sentinel");
|
|
73
73
|
const VOICE_PENDING_MAX_AGE_MS = 15 * 60 * 1_000;
|
|
74
|
-
const ACTIVE_FLIGHT_RECORDER_PACKET_STATUSES = new Set([
|
|
75
|
-
"drafting",
|
|
76
|
-
"processing",
|
|
77
|
-
"validating",
|
|
78
|
-
"collaborating",
|
|
79
|
-
"paused",
|
|
80
|
-
"blocked",
|
|
81
|
-
]);
|
|
82
74
|
function pendingExpirationReason(channel, message, now) {
|
|
83
75
|
/* v8 ignore start -- pending expiry edge permutations are covered by the stale voice queue tests; this helper keeps defensive non-voice fallbacks @preserve */
|
|
84
76
|
if (Number.isFinite(message.expiresAt) && Number(message.expiresAt) <= now)
|
|
@@ -224,9 +216,7 @@ function readPostTurnFlightRecorderArcSnapshot(agentRoot) {
|
|
|
224
216
|
return {
|
|
225
217
|
activeObligationIds: (0, obligations_1.readPendingObligations)(agentRoot).map((obligation) => obligation.id),
|
|
226
218
|
activeReturnObligationIds: (0, obligations_1.listActiveReturnObligationsForRoot)(agentRoot).map((obligation) => obligation.id),
|
|
227
|
-
activePacketIds: (0, packets_1.
|
|
228
|
-
.filter((packet) => ACTIVE_FLIGHT_RECORDER_PACKET_STATUSES.has(packet.status))
|
|
229
|
-
.map((packet) => packet.id),
|
|
219
|
+
activePacketIds: (0, packets_1.listActivePonderPackets)(agentRoot).map((packet) => packet.id),
|
|
230
220
|
openEvolutionCaseIds: (0, evolution_1.listOpenEvolutionCases)(agentRoot).map((evolutionCase) => evolutionCase.id),
|
|
231
221
|
recentClaimIds: latest.recentClaimIds,
|
|
232
222
|
unverifiedClaimIds: latest.unverifiedClaimIds,
|