@ouro.bot/cli 0.1.0-alpha.667 → 0.1.0-alpha.668
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
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
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.668",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Harden flight-recorder reconciliation so terminal fulfilled-only repairs are not continuable work, unverifiable active obligation ids are preserved and degraded, parseable-invalid obligation records are excluded from verified recovery state, synthesized recovery actions get fresh provenance, reads remain side-effect-free, and legacy obligation records stay visible in Mailbox, Workbench, and Work Card summaries."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.667",
|
|
6
12
|
"changes": [
|
|
@@ -50,6 +50,7 @@ const path = __importStar(require("path"));
|
|
|
50
50
|
const crypto_1 = require("crypto");
|
|
51
51
|
const session_events_1 = require("../heart/session-events");
|
|
52
52
|
const runtime_1 = require("../nerves/runtime");
|
|
53
|
+
const obligations_1 = require("./obligations");
|
|
53
54
|
function isHabitRunTrigger(value) {
|
|
54
55
|
return value === "cron"
|
|
55
56
|
|| value === "launchd"
|
|
@@ -201,7 +202,7 @@ function normalizeResumeInvariants(resume) {
|
|
|
201
202
|
];
|
|
202
203
|
const missingChanged = resume.missing.join("\n") !== missing.join("\n");
|
|
203
204
|
const issues = [
|
|
204
|
-
...(resume.canContinue && !
|
|
205
|
+
...(resume.canContinue && !hasCompleteState ? ["canContinue true while hasCompleteState false"] : []),
|
|
205
206
|
...(resume.canContinue && !hasCurrentAsk ? ["canContinue true without currentAsk"] : []),
|
|
206
207
|
...(resume.canContinue && !hasNextSafeAction ? ["canContinue true without nextSafeAction"] : []),
|
|
207
208
|
...(resume.canContinue && resume.blockedBecause.length > 0 ? ["canContinue true while blocked"] : []),
|
|
@@ -226,7 +227,117 @@ function normalizeResumeInvariants(resume) {
|
|
|
226
227
|
: resume.recorderHealth,
|
|
227
228
|
};
|
|
228
229
|
}
|
|
229
|
-
|
|
230
|
+
const FLIGHT_RECORDER_RECONCILE_SOURCE_ID = "reconcile:active-obligations";
|
|
231
|
+
function remainingArcWorkDescriptions(resume) {
|
|
232
|
+
return [
|
|
233
|
+
...resume.activeReturnObligationIds.map((id) => `return obligation ${id}`),
|
|
234
|
+
...resume.activePacketIds.map((id) => `packet ${id}`),
|
|
235
|
+
...resume.openEvolutionCaseIds.map((id) => `evolution case ${id}`),
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
function nextSafeActionAfterObligationReconcile(resume, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds) {
|
|
239
|
+
if (unverifiableActiveObligationIds.length > 0) {
|
|
240
|
+
return (0, session_events_1.capStructuredRecordString)(`inspect unverifiable active obligations before acting: ${unverifiableActiveObligationIds.join(", ")}`);
|
|
241
|
+
}
|
|
242
|
+
const firstActive = activeObligations[0];
|
|
243
|
+
if (firstActive) {
|
|
244
|
+
const detail = firstActive.nextAction?.trim() || firstActive.content;
|
|
245
|
+
return (0, session_events_1.capStructuredRecordString)(`continue open obligation ${firstActive.id}: ${detail}`);
|
|
246
|
+
}
|
|
247
|
+
const remainingWork = remainingArcWorkDescriptions(resume);
|
|
248
|
+
if (remainingWork.length > 0) {
|
|
249
|
+
return (0, session_events_1.capStructuredRecordString)(`continue remaining Arc work: ${remainingWork.slice(0, 5).join(", ")}`);
|
|
250
|
+
}
|
|
251
|
+
return (0, session_events_1.capStructuredRecordString)(`wait for new input; reconciled completed or missing obligations: ${staleActiveObligationIds.join(", ")}`);
|
|
252
|
+
}
|
|
253
|
+
function reconcileActiveObligations(agentRoot, resume) {
|
|
254
|
+
const obligations = (0, obligations_1.readVerifiedObligations)(agentRoot);
|
|
255
|
+
const activeObligations = (0, obligations_1.readVerifiedPendingObligations)(agentRoot);
|
|
256
|
+
const canonicalIdSet = new Set(obligations.map((obligation) => obligation.id));
|
|
257
|
+
const openIdSet = new Set(activeObligations.map((obligation) => obligation.id));
|
|
258
|
+
const resumeIdSet = new Set(resume.activeObligationIds);
|
|
259
|
+
const staleActiveObligationIds = resume.activeObligationIds.filter((id) => canonicalIdSet.has(id) && !openIdSet.has(id));
|
|
260
|
+
const unverifiableActiveObligationIds = resume.activeObligationIds.filter((id) => !canonicalIdSet.has(id));
|
|
261
|
+
const missingActiveObligationIds = activeObligations
|
|
262
|
+
.map((obligation) => obligation.id)
|
|
263
|
+
.filter((id) => !resumeIdSet.has(id));
|
|
264
|
+
if (staleActiveObligationIds.length === 0
|
|
265
|
+
&& missingActiveObligationIds.length === 0
|
|
266
|
+
&& unverifiableActiveObligationIds.length === 0) {
|
|
267
|
+
return { resume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds };
|
|
268
|
+
}
|
|
269
|
+
const activeObligationIds = uniqueStrings([
|
|
270
|
+
...resume.activeObligationIds.filter((id) => !staleActiveObligationIds.includes(id)),
|
|
271
|
+
...missingActiveObligationIds,
|
|
272
|
+
]);
|
|
273
|
+
const hasActiveArcContinuation = activeObligationIds.length > 0
|
|
274
|
+
|| resume.activeReturnObligationIds.length > 0
|
|
275
|
+
|| resume.activePacketIds.length > 0
|
|
276
|
+
|| resume.openEvolutionCaseIds.length > 0;
|
|
277
|
+
const isTerminalWait = staleActiveObligationIds.length > 0 && !hasActiveArcContinuation;
|
|
278
|
+
const mustSynthesizeAction = staleActiveObligationIds.length > 0
|
|
279
|
+
|| unverifiableActiveObligationIds.length > 0
|
|
280
|
+
|| !nonEmpty(resume.nextSafeAction.value);
|
|
281
|
+
const nextSafeActionValue = mustSynthesizeAction
|
|
282
|
+
? nextSafeActionAfterObligationReconcile(resume, activeObligations, staleActiveObligationIds, unverifiableActiveObligationIds)
|
|
283
|
+
: resume.nextSafeAction.value;
|
|
284
|
+
const recorderHealth = unverifiableActiveObligationIds.length > 0
|
|
285
|
+
? {
|
|
286
|
+
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
|
+
]),
|
|
291
|
+
}
|
|
292
|
+
: resume.recorderHealth;
|
|
293
|
+
const canContinue = nonEmpty(resume.currentAsk.value)
|
|
294
|
+
&& nonEmpty(nextSafeActionValue)
|
|
295
|
+
&& resume.blockedBecause.length === 0
|
|
296
|
+
&& recorderHealth.status === "ok"
|
|
297
|
+
&& hasActiveArcContinuation
|
|
298
|
+
&& !isTerminalWait;
|
|
299
|
+
return {
|
|
300
|
+
resume: normalizeResumeInvariants({
|
|
301
|
+
...resume,
|
|
302
|
+
canContinue,
|
|
303
|
+
recorderHealth,
|
|
304
|
+
activeObligationIds,
|
|
305
|
+
nextSafeAction: {
|
|
306
|
+
...resume.nextSafeAction,
|
|
307
|
+
value: nextSafeActionValue,
|
|
308
|
+
sourceEventIds: mustSynthesizeAction
|
|
309
|
+
? [FLIGHT_RECORDER_RECONCILE_SOURCE_ID]
|
|
310
|
+
: resume.nextSafeAction.sourceEventIds,
|
|
311
|
+
stopBefore: unverifiableActiveObligationIds.length > 0
|
|
312
|
+
? uniqueStrings([...resume.nextSafeAction.stopBefore, "acting on unverifiable obligation state"])
|
|
313
|
+
: resume.nextSafeAction.stopBefore,
|
|
314
|
+
},
|
|
315
|
+
}),
|
|
316
|
+
staleActiveObligationIds,
|
|
317
|
+
missingActiveObligationIds,
|
|
318
|
+
unverifiableActiveObligationIds,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function normalizeResumeForAgentRoot(agentRoot, resume) {
|
|
322
|
+
return reconcileActiveObligations(agentRoot, normalizeResumeInvariants(resume));
|
|
323
|
+
}
|
|
324
|
+
function emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds) {
|
|
325
|
+
if (staleActiveObligationIds.length === 0
|
|
326
|
+
&& missingActiveObligationIds.length === 0
|
|
327
|
+
&& unverifiableActiveObligationIds.length === 0)
|
|
328
|
+
return;
|
|
329
|
+
(0, runtime_1.emitNervesEvent)({
|
|
330
|
+
component: "mind",
|
|
331
|
+
event: "mind.flight_recorder_resume_reconciled",
|
|
332
|
+
message: "flight recorder resume reconciled with canonical Arc state",
|
|
333
|
+
meta: {
|
|
334
|
+
agentRoot,
|
|
335
|
+
staleActiveObligationIds,
|
|
336
|
+
missingActiveObligationIds,
|
|
337
|
+
unverifiableActiveObligationIds,
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
}
|
|
230
341
|
function latestFromEvent(event, previous) {
|
|
231
342
|
const currentAskValue = event.currentAsk !== undefined ? event.currentAsk : previous.currentAsk.value;
|
|
232
343
|
const nextSafeActionValue = event.nextSafeAction !== undefined ? event.nextSafeAction : previous.nextSafeAction.value;
|
|
@@ -279,7 +390,12 @@ function readFlightRecorderResume(agentRoot) {
|
|
|
279
390
|
if (!isFlightRecorderResume(parsed)) {
|
|
280
391
|
throw new Error("latest.json has invalid flight-recorder resume shape");
|
|
281
392
|
}
|
|
282
|
-
const resume =
|
|
393
|
+
const { resume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, } = normalizeResumeForAgentRoot(agentRoot, parsed);
|
|
394
|
+
if (staleActiveObligationIds.length > 0
|
|
395
|
+
|| missingActiveObligationIds.length > 0
|
|
396
|
+
|| unverifiableActiveObligationIds.length > 0) {
|
|
397
|
+
emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds);
|
|
398
|
+
}
|
|
283
399
|
(0, runtime_1.emitNervesEvent)({
|
|
284
400
|
component: "mind",
|
|
285
401
|
event: "mind.flight_recorder_resume_read",
|
|
@@ -302,8 +418,9 @@ function readFlightRecorderResume(agentRoot) {
|
|
|
302
418
|
}
|
|
303
419
|
}
|
|
304
420
|
function writeFlightRecorderResume(agentRoot, resume) {
|
|
305
|
-
const safeResume =
|
|
421
|
+
const { resume: safeResume, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds, } = normalizeResumeForAgentRoot(agentRoot, resume);
|
|
306
422
|
atomicWriteJson(flightRecorderLatestPath(agentRoot), safeResume);
|
|
423
|
+
emitFlightRecorderReconciled(agentRoot, staleActiveObligationIds, missingActiveObligationIds, unverifiableActiveObligationIds);
|
|
307
424
|
(0, runtime_1.emitNervesEvent)({
|
|
308
425
|
component: "mind",
|
|
309
426
|
event: "mind.flight_recorder_resume_written",
|
package/dist/arc/obligations.js
CHANGED
|
@@ -38,6 +38,8 @@ exports.isOpenObligation = isOpenObligation;
|
|
|
38
38
|
exports.createObligation = createObligation;
|
|
39
39
|
exports.readObligations = readObligations;
|
|
40
40
|
exports.readPendingObligations = readPendingObligations;
|
|
41
|
+
exports.readVerifiedObligations = readVerifiedObligations;
|
|
42
|
+
exports.readVerifiedPendingObligations = readVerifiedPendingObligations;
|
|
41
43
|
exports.advanceObligation = advanceObligation;
|
|
42
44
|
exports.fulfillObligation = fulfillObligation;
|
|
43
45
|
exports.findPendingObligationForOrigin = findPendingObligationForOrigin;
|
|
@@ -64,6 +66,31 @@ function isOpenObligationStatus(status) {
|
|
|
64
66
|
function isOpenObligation(obligation) {
|
|
65
67
|
return isOpenObligationStatus(obligation.status);
|
|
66
68
|
}
|
|
69
|
+
function isReadableObligation(value) {
|
|
70
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
71
|
+
return false;
|
|
72
|
+
const obligation = value;
|
|
73
|
+
return typeof obligation.id === "string"
|
|
74
|
+
&& typeof obligation.content === "string";
|
|
75
|
+
}
|
|
76
|
+
function isVerifiedObligationStatus(value) {
|
|
77
|
+
return value === "pending"
|
|
78
|
+
|| value === "investigating"
|
|
79
|
+
|| value === "waiting_for_merge"
|
|
80
|
+
|| value === "updating_runtime"
|
|
81
|
+
|| value === "fulfilled";
|
|
82
|
+
}
|
|
83
|
+
function isVerifiedObligation(value) {
|
|
84
|
+
if (!isReadableObligation(value))
|
|
85
|
+
return false;
|
|
86
|
+
const obligation = value;
|
|
87
|
+
return isVerifiedObligationStatus(obligation.status)
|
|
88
|
+
&& typeof obligation.createdAt === "string"
|
|
89
|
+
&& !!obligation.origin
|
|
90
|
+
&& typeof obligation.origin.friendId === "string"
|
|
91
|
+
&& typeof obligation.origin.channel === "string"
|
|
92
|
+
&& typeof obligation.origin.key === "string";
|
|
93
|
+
}
|
|
67
94
|
function createObligation(agentRoot, input) {
|
|
68
95
|
const now = new Date().toISOString();
|
|
69
96
|
const id = (0, json_store_1.generateTimestampId)();
|
|
@@ -92,11 +119,18 @@ function createObligation(agentRoot, input) {
|
|
|
92
119
|
}
|
|
93
120
|
function readObligations(agentRoot) {
|
|
94
121
|
const all = (0, json_store_1.readJsonDir)(obligationsDir(agentRoot));
|
|
95
|
-
return all.filter(
|
|
122
|
+
return all.filter(isReadableObligation);
|
|
96
123
|
}
|
|
97
124
|
function readPendingObligations(agentRoot) {
|
|
98
125
|
return readObligations(agentRoot).filter(isOpenObligation);
|
|
99
126
|
}
|
|
127
|
+
function readVerifiedObligations(agentRoot) {
|
|
128
|
+
const all = (0, json_store_1.readJsonDir)(obligationsDir(agentRoot));
|
|
129
|
+
return all.filter(isVerifiedObligation);
|
|
130
|
+
}
|
|
131
|
+
function readVerifiedPendingObligations(agentRoot) {
|
|
132
|
+
return readVerifiedObligations(agentRoot).filter(isOpenObligation);
|
|
133
|
+
}
|
|
100
134
|
function advanceObligation(agentRoot, obligationId, update) {
|
|
101
135
|
const dir = obligationsDir(agentRoot);
|
|
102
136
|
const obligation = (0, json_store_1.readJsonFile)(dir, obligationId);
|
|
@@ -127,14 +127,24 @@ function normalizeObligationCurrentSurface(currentSurface, updatedAt, liveCoding
|
|
|
127
127
|
&& (Date.now() - updatedAtMs) <= STALE_CODING_SURFACE_WINDOW_MS;
|
|
128
128
|
return recentlyTouched ? currentSurface : null;
|
|
129
129
|
}
|
|
130
|
+
function legacyObligationTimestamp(obligation) {
|
|
131
|
+
if (typeof obligation.updatedAt === "string")
|
|
132
|
+
return obligation.updatedAt;
|
|
133
|
+
if (typeof obligation.createdAt === "string")
|
|
134
|
+
return obligation.createdAt;
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
137
|
+
function legacyObligationStatus(obligation) {
|
|
138
|
+
return typeof obligation.status === "string" ? obligation.status : "pending";
|
|
139
|
+
}
|
|
130
140
|
function readObligationSummary(agentRoot) {
|
|
131
141
|
const liveCodingSurfaceLabels = buildLiveCodingSurfaceLabels(agentRoot);
|
|
132
142
|
const items = (0, obligations_1.readPendingObligations)(agentRoot)
|
|
133
143
|
.map((obligation) => {
|
|
134
|
-
const updatedAt = obligation
|
|
144
|
+
const updatedAt = legacyObligationTimestamp(obligation);
|
|
135
145
|
return {
|
|
136
146
|
id: obligation.id,
|
|
137
|
-
status: obligation
|
|
147
|
+
status: legacyObligationStatus(obligation),
|
|
138
148
|
content: obligation.content,
|
|
139
149
|
updatedAt,
|
|
140
150
|
nextAction: obligation.nextAction ?? null,
|
package/dist/heart/work-card.js
CHANGED
|
@@ -134,14 +134,18 @@ function scanArcSourceIssues(agentRoot) {
|
|
|
134
134
|
}
|
|
135
135
|
function obligationItem(obligation) {
|
|
136
136
|
const freshness = obligation.meaning?.stalenessClass === "at-risk" ? "stale_risky" : "current";
|
|
137
|
+
const status = typeof obligation.status === "string" ? obligation.status : "pending";
|
|
138
|
+
const updatedAt = typeof obligation.updatedAt === "string"
|
|
139
|
+
? obligation.updatedAt
|
|
140
|
+
: typeof obligation.createdAt === "string" ? obligation.createdAt : undefined;
|
|
137
141
|
return {
|
|
138
142
|
id: obligation.id,
|
|
139
143
|
title: obligation.content,
|
|
140
|
-
status
|
|
144
|
+
status,
|
|
141
145
|
source: source("obligation", obligationLocator(obligation.id), freshness),
|
|
142
146
|
...(obligation.latestNote ? { summary: obligation.latestNote } : {}),
|
|
143
147
|
...(obligation.nextAction ? { nextAction: obligation.nextAction } : {}),
|
|
144
|
-
updatedAt
|
|
148
|
+
...(updatedAt ? { updatedAt } : {}),
|
|
145
149
|
};
|
|
146
150
|
}
|
|
147
151
|
function returnObligationItem(obligation) {
|