@ouro.bot/cli 0.1.0-alpha.807 → 0.1.0-alpha.809

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.
@@ -121,7 +121,6 @@ function resolveAllSessionPaths(sessionsDir) {
121
121
  return results;
122
122
  }
123
123
  /* v8 ignore stop */
124
- /* v8 ignore start — defensive parsing */
125
124
  function readSessionInventory(agentName, options = {}) {
126
125
  const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
127
126
  const now = options.now?.() ?? new Date();
@@ -134,7 +133,7 @@ function readSessionInventory(agentName, options = {}) {
134
133
  if (friendId === "self" && channel === "inner")
135
134
  continue;
136
135
  const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
137
- const events = envelope?.events ?? [];
136
+ const events = (0, session_events_1.selectEffectiveSessionEvents)(envelope?.events ?? []);
138
137
  const chronology = (0, session_events_1.deriveSessionChronology)(events);
139
138
  const lastUsage = parseSessionUsage(envelope?.lastUsage);
140
139
  const continuity = parseSessionContinuity(envelope?.state);
@@ -213,7 +212,7 @@ function readSessionTranscript(agentName, friendId, channel, key, options = {})
213
212
  const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
214
213
  if (!envelope)
215
214
  return null;
216
- const rawMessages = envelope.events;
215
+ const rawMessages = (0, session_events_1.selectEffectiveSessionEvents)(envelope.events);
217
216
  const friendsDir = path.join(agentRoot, "friends");
218
217
  const friendName = (0, shared_1.resolveFriendName)(friendsDir, friendId);
219
218
  const messages = rawMessages;
@@ -81,7 +81,9 @@ function parseFriendActivity(sessionPath, activeThresholdMs, nowMs) {
81
81
  }
82
82
  const envelope = (0, session_events_1.loadSessionEnvelopeFile)(sessionPath);
83
83
  const chronology = envelope ? (0, session_events_1.deriveSessionChronology)(envelope.events) : null;
84
- const explicit = envelope?.state.lastFriendActivityAt;
84
+ const explicit = envelope && envelope.events.length > 0 && (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length !== envelope.events.length
85
+ ? chronology?.lastInboundAt
86
+ : envelope?.state.lastFriendActivityAt;
85
87
  if (typeof explicit === "string") {
86
88
  const parsedMs = Date.parse(explicit);
87
89
  if (Number.isFinite(parsedMs)) {
@@ -61,12 +61,15 @@ exports.extractEventText = extractEventText;
61
61
  exports.deriveSessionChronology = deriveSessionChronology;
62
62
  exports.describeCurrentSessionTiming = describeCurrentSessionTiming;
63
63
  exports.migrateLegacySessionEnvelope = migrateLegacySessionEnvelope;
64
+ exports.isExactRawSessionRedactionMarker = isExactRawSessionRedactionMarker;
65
+ exports.selectEffectiveSessionEvents = selectEffectiveSessionEvents;
64
66
  exports.parseSessionEnvelope = parseSessionEnvelope;
65
67
  exports.loadSessionEnvelopeFile = loadSessionEnvelopeFile;
66
68
  exports.buildCanonicalSessionEnvelope = buildCanonicalSessionEnvelope;
67
69
  exports.appendSyntheticAssistantEvent = appendSyntheticAssistantEvent;
68
70
  const fs = __importStar(require("fs"));
69
71
  const node_crypto_1 = require("node:crypto");
72
+ const node_util_1 = require("node:util");
70
73
  const runtime_1 = require("../nerves/runtime");
71
74
  const structured_output_1 = require("./structured-output");
72
75
  const APPROVAL_TERMINAL_TEXT = {
@@ -942,12 +945,15 @@ function projectedSessionEventIds(envelope) {
942
945
  ? envelope.projection.eventIds
943
946
  : envelope.events.map((event) => event.id);
944
947
  }
945
- function projectProviderMessages(envelope) {
948
+ function providerProjectionEvents(envelope) {
946
949
  const eventIds = projectedSessionEventIds(envelope);
947
- const byId = new Map(envelope.events.map((event) => [event.id, event]));
950
+ const byId = new Map(selectEffectiveSessionEvents(envelope.events).map((event) => [event.id, event]));
948
951
  return eventIds
949
952
  .map((id) => byId.get(id))
950
- .filter((event) => Boolean(event))
953
+ .filter((event) => Boolean(event));
954
+ }
955
+ function projectProviderMessages(envelope) {
956
+ return providerProjectionEvents(envelope)
951
957
  .map((event) => toProviderMessage({
952
958
  role: event.role,
953
959
  content: event.content,
@@ -962,11 +968,7 @@ function projectProviderMessages(envelope) {
962
968
  * System and tool messages are untouched.
963
969
  */
964
970
  function annotateMessageTimestamps(envelope, messages, nowMs = Date.now()) {
965
- const eventIds = projectedSessionEventIds(envelope);
966
- const byId = new Map(envelope.events.map((event) => [event.id, event]));
967
- const events = eventIds
968
- .map((id) => byId.get(id))
969
- .filter((event) => Boolean(event));
971
+ const events = providerProjectionEvents(envelope);
970
972
  return messages.map((msg, i) => {
971
973
  const event = events[i];
972
974
  if (!event)
@@ -1012,6 +1014,7 @@ function extractEventText(event) {
1012
1014
  return contentText(event.content);
1013
1015
  }
1014
1016
  function deriveSessionChronology(events) {
1017
+ events = selectEffectiveSessionEvents(events);
1015
1018
  let lastInboundAt = null;
1016
1019
  let lastOutboundAt = null;
1017
1020
  let lastActivityAt = null;
@@ -1081,6 +1084,139 @@ function migrateLegacySessionEnvelope(raw, options) {
1081
1084
  state: normalizeContinuityState(legacy.state),
1082
1085
  };
1083
1086
  }
1087
+ function normalizeSessionEvent(event, index, recordedAt) {
1088
+ const role = normalizeRole(event.role);
1089
+ const time = event.time;
1090
+ const relations = event.relations;
1091
+ const provenance = event.provenance;
1092
+ const content = sanitizeConversationContent(role, normalizeContent(event.content));
1093
+ return {
1094
+ id: typeof event.id === "string" ? event.id : makeEventId(index + 1),
1095
+ sequence: typeof event.sequence === "number" ? event.sequence : index + 1,
1096
+ role,
1097
+ content,
1098
+ name: typeof event.name === "string" ? event.name : null,
1099
+ toolCallId: typeof event.toolCallId === "string" ? event.toolCallId : null,
1100
+ toolCalls: normalizeToolCalls(event.toolCalls),
1101
+ attachments: Array.isArray(event.attachments) ? event.attachments.filter((item) => typeof item === "string") : [],
1102
+ time: {
1103
+ authoredAt: typeof time?.authoredAt === "string" ? time.authoredAt : null,
1104
+ authoredAtSource: typeof time?.authoredAtSource === "string" ? time.authoredAtSource : "unknown",
1105
+ observedAt: typeof time?.observedAt === "string" ? time.observedAt : null,
1106
+ observedAtSource: typeof time?.observedAtSource === "string" ? time.observedAtSource : "unknown",
1107
+ recordedAt: typeof time?.recordedAt === "string" ? time.recordedAt : recordedAt,
1108
+ recordedAtSource: typeof time?.recordedAtSource === "string" ? time.recordedAtSource : "save",
1109
+ },
1110
+ relations: {
1111
+ replyToEventId: typeof relations?.replyToEventId === "string" ? relations.replyToEventId : null,
1112
+ threadRootEventId: typeof relations?.threadRootEventId === "string" ? relations.threadRootEventId : null,
1113
+ references: Array.isArray(relations?.references) ? relations.references.filter((item) => typeof item === "string") : [],
1114
+ toolCallId: typeof relations?.toolCallId === "string" ? relations.toolCallId : null,
1115
+ supersedesEventId: typeof relations?.supersedesEventId === "string" ? relations.supersedesEventId : null,
1116
+ redactsEventId: typeof relations?.redactsEventId === "string" ? relations.redactsEventId : null,
1117
+ },
1118
+ provenance: {
1119
+ captureKind: typeof provenance?.captureKind === "string" ? provenance.captureKind : "live",
1120
+ legacyVersion: typeof provenance?.legacyVersion === "number" ? provenance.legacyVersion : null,
1121
+ sourceMessageIndex: typeof provenance?.sourceMessageIndex === "number" ? provenance.sourceMessageIndex : null,
1122
+ },
1123
+ };
1124
+ }
1125
+ function exactKeys(value, keys) {
1126
+ return value !== null && typeof value === "object" && !Array.isArray(value)
1127
+ && Reflect.ownKeys(value).length === keys.length
1128
+ && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
1129
+ }
1130
+ function nonblank(value) {
1131
+ return typeof value === "string" && value.trim().length > 0;
1132
+ }
1133
+ function exactIsoTime(value) {
1134
+ return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
1135
+ }
1136
+ function exactRawEvent(value, index) {
1137
+ if (!exactKeys(value, ["id", "sequence", "role", "content", "name", "toolCallId", "toolCalls", "attachments", "time", "relations", "provenance"]))
1138
+ return false;
1139
+ if (!nonblank(value.id) || !Number.isSafeInteger(value.sequence) || Number(value.sequence) <= 0
1140
+ || typeof value.role !== "string" || !["system", "user", "assistant", "tool"].includes(value.role)
1141
+ || !(value.name === null || typeof value.name === "string") || !(value.toolCallId === null || typeof value.toolCallId === "string")
1142
+ || !(value.content === null || typeof value.content === "string" || Array.isArray(value.content))
1143
+ || !Array.isArray(value.attachments) || !value.attachments.every((item) => typeof item === "string")
1144
+ || !Array.isArray(value.toolCalls))
1145
+ return false;
1146
+ for (const call of value.toolCalls) {
1147
+ if (!exactKeys(call, ["id", "type", "function"]) || !nonblank(call.id) || call.type !== "function"
1148
+ || !exactKeys(call.function, ["name", "arguments"]) || !nonblank(call.function.name) || typeof call.function.arguments !== "string")
1149
+ return false;
1150
+ }
1151
+ const time = value.time;
1152
+ if (!exactKeys(time, ["authoredAt", "authoredAtSource", "observedAt", "observedAtSource", "recordedAt", "recordedAtSource"])
1153
+ || !(time.authoredAt === null || exactIsoTime(time.authoredAt))
1154
+ || !(time.observedAt === null || exactIsoTime(time.observedAt)) || !exactIsoTime(time.recordedAt))
1155
+ return false;
1156
+ for (const key of ["authoredAtSource", "observedAtSource", "recordedAtSource"]) {
1157
+ if (typeof time[key] !== "string" || !["unknown", "local", "ingest", "migration", "save"].includes(time[key]))
1158
+ return false;
1159
+ }
1160
+ const relations = value.relations;
1161
+ if (!exactKeys(relations, ["replyToEventId", "threadRootEventId", "references", "toolCallId", "supersedesEventId", "redactsEventId"])
1162
+ || !Array.isArray(relations.references) || !relations.references.every((item) => typeof item === "string"))
1163
+ return false;
1164
+ for (const key of ["replyToEventId", "threadRootEventId", "toolCallId", "supersedesEventId", "redactsEventId"]) {
1165
+ if (relations[key] !== null && typeof relations[key] !== "string")
1166
+ return false;
1167
+ }
1168
+ const provenance = value.provenance;
1169
+ if (!exactKeys(provenance, ["captureKind", "legacyVersion", "sourceMessageIndex"])
1170
+ || typeof provenance.captureKind !== "string" || !["live", "synthetic", "migration"].includes(provenance.captureKind)
1171
+ || !(provenance.legacyVersion === null || Number.isSafeInteger(provenance.legacyVersion) && Number(provenance.legacyVersion) > 0)
1172
+ || !(provenance.sourceMessageIndex === null || Number.isSafeInteger(provenance.sourceMessageIndex) && Number(provenance.sourceMessageIndex) >= 0))
1173
+ return false;
1174
+ return (0, node_util_1.isDeepStrictEqual)(value, normalizeSessionEvent(value, index, time.recordedAt));
1175
+ }
1176
+ function isExactRawSessionRedactionMarker(candidate, rawEvents) {
1177
+ if (!candidate || typeof candidate !== "object" || candidate.role !== "system"
1178
+ || !exactRawEvent(candidate, 0) || candidate.content !== null || candidate.name !== null || candidate.toolCallId !== null
1179
+ || candidate.toolCalls.length !== 0 || candidate.attachments.length !== 0
1180
+ || candidate.time.authoredAt !== null || candidate.time.observedAt !== null
1181
+ || candidate.time.authoredAtSource !== "migration" || candidate.time.observedAtSource !== "migration" || candidate.time.recordedAtSource !== "migration"
1182
+ || candidate.provenance.captureKind !== "migration" || candidate.provenance.legacyVersion !== 2 || candidate.provenance.sourceMessageIndex !== null
1183
+ || candidate.relations.replyToEventId !== null || candidate.relations.threadRootEventId !== null || candidate.relations.references.length !== 0
1184
+ || candidate.relations.toolCallId !== null || candidate.relations.supersedesEventId !== null || !nonblank(candidate.relations.redactsEventId)
1185
+ || !Array.isArray(rawEvents))
1186
+ return false;
1187
+ const ids = new Set();
1188
+ let previousSequence = 0;
1189
+ for (const raw of rawEvents) {
1190
+ if (!raw || typeof raw !== "object")
1191
+ return false;
1192
+ const event = raw;
1193
+ if (!nonblank(event.id) || ids.has(event.id) || !Number.isSafeInteger(event.sequence) || Number(event.sequence) <= previousSequence)
1194
+ return false;
1195
+ ids.add(event.id);
1196
+ previousSequence = Number(event.sequence);
1197
+ }
1198
+ const candidateIndex = rawEvents.findIndex((raw) => raw.id === candidate.id);
1199
+ if (candidateIndex < 0 || !(0, node_util_1.isDeepStrictEqual)(rawEvents[candidateIndex], candidate))
1200
+ return false;
1201
+ const targetIndex = rawEvents.findIndex((raw) => raw.id === candidate.relations.redactsEventId);
1202
+ if (targetIndex < 0 || targetIndex >= candidateIndex)
1203
+ return false;
1204
+ const target = rawEvents[targetIndex];
1205
+ if (!exactRawEvent(target, targetIndex) || target.role !== "user" || target.relations.redactsEventId !== null)
1206
+ return false;
1207
+ const attempts = rawEvents.map((raw) => raw.relations?.redactsEventId);
1208
+ return attempts.filter((id) => id === target.id).length === 1 && !attempts.includes(candidate.id);
1209
+ }
1210
+ function selectEffectiveSessionEvents(events) {
1211
+ const hidden = new Set();
1212
+ for (const event of events) {
1213
+ if (isExactRawSessionRedactionMarker(event, events)) {
1214
+ hidden.add(event.id);
1215
+ hidden.add(event.relations.redactsEventId);
1216
+ }
1217
+ }
1218
+ return events.filter((event) => !hidden.has(event.id));
1219
+ }
1084
1220
  function parseSessionEnvelope(raw, options = {}) {
1085
1221
  const recordedAt = options.recordedAt ?? new Date().toISOString();
1086
1222
  const fileMtimeAt = options.fileMtimeAt ?? null;
@@ -1093,46 +1229,24 @@ function parseSessionEnvelope(raw, options = {}) {
1093
1229
  if (record.version !== 2 || !Array.isArray(record.events) || !record.projection || typeof record.projection !== "object") {
1094
1230
  return null;
1095
1231
  }
1232
+ const validMarkers = new Set(record.events.filter((event) => isExactRawSessionRedactionMarker(event, record.events)));
1233
+ let invalidMarkers = 0;
1096
1234
  const rawEvents = record.events
1097
1235
  .filter((event) => event != null && typeof event === "object")
1098
1236
  .map((event, index) => {
1099
- const role = normalizeRole(event.role);
1100
- const time = event.time;
1101
- const relations = event.relations;
1102
- const provenance = event.provenance;
1103
- const content = sanitizeConversationContent(role, normalizeContent(event.content));
1104
- return {
1105
- id: typeof event.id === "string" ? event.id : makeEventId(index + 1),
1106
- sequence: typeof event.sequence === "number" ? event.sequence : index + 1,
1107
- role,
1108
- content,
1109
- name: typeof event.name === "string" ? event.name : null,
1110
- toolCallId: typeof event.toolCallId === "string" ? event.toolCallId : null,
1111
- toolCalls: normalizeToolCalls(event.toolCalls),
1112
- attachments: Array.isArray(event.attachments) ? event.attachments.filter((item) => typeof item === "string") : [],
1113
- time: {
1114
- authoredAt: typeof time?.authoredAt === "string" ? time.authoredAt : null,
1115
- authoredAtSource: typeof time?.authoredAtSource === "string" ? time.authoredAtSource : "unknown",
1116
- observedAt: typeof time?.observedAt === "string" ? time.observedAt : null,
1117
- observedAtSource: typeof time?.observedAtSource === "string" ? time.observedAtSource : "unknown",
1118
- recordedAt: typeof time?.recordedAt === "string" ? time.recordedAt : recordedAt,
1119
- recordedAtSource: typeof time?.recordedAtSource === "string" ? time.recordedAtSource : "save",
1120
- },
1121
- relations: {
1122
- replyToEventId: typeof relations?.replyToEventId === "string" ? relations.replyToEventId : null,
1123
- threadRootEventId: typeof relations?.threadRootEventId === "string" ? relations.threadRootEventId : null,
1124
- references: Array.isArray(relations?.references) ? relations.references.filter((item) => typeof item === "string") : [],
1125
- toolCallId: typeof relations?.toolCallId === "string" ? relations.toolCallId : null,
1126
- supersedesEventId: typeof relations?.supersedesEventId === "string" ? relations.supersedesEventId : null,
1127
- redactsEventId: typeof relations?.redactsEventId === "string" ? relations.redactsEventId : null,
1128
- },
1129
- provenance: {
1130
- captureKind: typeof provenance?.captureKind === "string" ? provenance.captureKind : "live",
1131
- legacyVersion: typeof provenance?.legacyVersion === "number" ? provenance.legacyVersion : null,
1132
- sourceMessageIndex: typeof provenance?.sourceMessageIndex === "number" ? provenance.sourceMessageIndex : null,
1133
- },
1134
- };
1237
+ const normalized = normalizeSessionEvent(event, index, recordedAt);
1238
+ const attempted = event.relations?.redactsEventId;
1239
+ if (attempted !== undefined && attempted !== null && !validMarkers.has(event)) {
1240
+ normalized.relations.redactsEventId = null;
1241
+ invalidMarkers++;
1242
+ }
1243
+ return normalized;
1135
1244
  });
1245
+ if (invalidMarkers > 0)
1246
+ (0, runtime_1.emitNervesEvent)({
1247
+ level: "warn", component: "heart", event: "session.redaction_marker_invalid",
1248
+ message: "invalid raw redaction authority ignored", meta: { count: invalidMarkers },
1249
+ });
1136
1250
  // Self-heal duplicate event ids that may have been written by concurrent
1137
1251
  // writers in older harness versions. Last-occurrence-wins by id (later
1138
1252
  // entries in the persisted file are the more recent state for that id).
@@ -1151,9 +1265,7 @@ function parseSessionEnvelope(raw, options = {}) {
1151
1265
  inputTokens: typeof projection.inputTokens === "number" ? projection.inputTokens : null,
1152
1266
  projectedAt: typeof projection.projectedAt === "string" ? projection.projectedAt : null,
1153
1267
  },
1154
- structuredOutputs: record.structuredOutputs === undefined
1155
- ? (0, structured_output_1.extractStructuredOutputsFromEvents)(events, { emitTelemetry: false })
1156
- : (0, structured_output_1.normalizeStructuredOutputs)(record.structuredOutputs),
1268
+ structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents(events), { emitTelemetry: false }),
1157
1269
  lastUsage: normalizeUsage(record.lastUsage),
1158
1270
  state: normalizeContinuityState(record.state),
1159
1271
  approvalSuspensions: normalizeApprovalSuspensions(record.approvalSuspensions),
@@ -1228,9 +1340,7 @@ function buildCanonicalSessionEnvelope(options) {
1228
1340
  const previousMessages = options.previousMessages;
1229
1341
  const currentMessages = options.currentMessages;
1230
1342
  const trimmedMessages = options.trimmedMessages;
1231
- const previousProjectionIds = existing?.projection.eventIds.length
1232
- ? [...existing.projection.eventIds]
1233
- : existing?.events.map((event) => event.id) ?? [];
1343
+ const previousProjectionIds = existing ? providerProjectionEvents(existing).map((event) => event.id) : [];
1234
1344
  // Compare only non-system messages to find the common prefix.
1235
1345
  // System messages change every turn (live world-state in system prompt)
1236
1346
  // and must not defeat prefix matching of the actual conversation.
@@ -1278,21 +1388,23 @@ function buildCanonicalSessionEnvelope(options) {
1278
1388
  // Prune events: only keep events whose IDs are in the projection.
1279
1389
  // Events not in projection are returned as evicted for archiving.
1280
1390
  const projectionIdSet = new Set(projectionEventIds);
1281
- const prunedEvents = events.filter((event) => projectionIdSet.has(event.id));
1282
- const evictedEvents = events.filter((event) => !projectionIdSet.has(event.id));
1391
+ const effectiveIds = new Set(selectEffectiveSessionEvents(events).map((event) => event.id));
1392
+ const keep = (event) => projectionIdSet.has(event.id) || !effectiveIds.has(event.id);
1393
+ const prunedEvents = events.filter(keep);
1394
+ const evictedEvents = events.filter((event) => !keep(event));
1283
1395
  return {
1284
1396
  envelope: {
1285
1397
  version: 2,
1286
1398
  events: prunedEvents,
1287
1399
  projection: {
1288
- eventIds: projectionEventIds,
1400
+ eventIds: projectionEventIds.filter((id) => effectiveIds.has(id)),
1289
1401
  trimmed: projectionEventIds.length < currentEventIds.length,
1290
1402
  maxTokens: options.projectionBasis.maxTokens,
1291
1403
  contextMargin: options.projectionBasis.contextMargin,
1292
1404
  inputTokens: options.projectionBasis.inputTokens,
1293
1405
  projectedAt: options.recordedAt,
1294
1406
  },
1295
- structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(prunedEvents),
1407
+ structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents(prunedEvents)),
1296
1408
  lastUsage: normalizeUsage(options.lastUsage),
1297
1409
  state: normalizeContinuityState(options.state),
1298
1410
  approvalSuspensions: structuredClone(options.existing?.approvalSuspensions ?? []),
@@ -1309,7 +1421,7 @@ function appendSyntheticAssistantEvent(envelope, content, recordedAt) {
1309
1421
  return {
1310
1422
  ...envelope,
1311
1423
  events: [...envelope.events, event],
1312
- structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)([...envelope.events, event]),
1424
+ structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents([...envelope.events, event])),
1313
1425
  projection: {
1314
1426
  ...envelope.projection,
1315
1427
  eventIds: [...envelope.projection.eventIds, event.id],
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const runtime_1 = require("../nerves/runtime");
4
+ const session_redaction_repair_1 = require("./session-redaction-repair");
5
+ // Deliberately a direct packaged entrypoint, never public CLI/model routing.
6
+ async function main() {
7
+ const args = process.argv.slice(2);
8
+ (0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.session_redaction_repair_cli", message: "private fixed repair entrypoint invoked", meta: { argumentCount: args.length } });
9
+ try {
10
+ let result;
11
+ if (args.length === 7 && args[0] === "inspect" && args[1] === "--agent" && args[3] === "--session" && args[5] === "--artifacts-dir") {
12
+ result = await (0, session_redaction_repair_1.inspectA003SessionRepair)({ agent: args[2], sessionPath: args[4], artifactsDir: args[6] });
13
+ }
14
+ else if (args.length === 4 && args[0] === "apply" && args[1] === "--manifest-sha256") {
15
+ result = await (0, session_redaction_repair_1.applyA003SessionRepair)({ manifestSha256: args[2], manifestPath: args[3] });
16
+ }
17
+ else if (args.length === 5 && args[0] === "rollback" && args[1] === "--manifest-sha256") {
18
+ result = await (0, session_redaction_repair_1.rollbackA003SessionRepair)({ manifestSha256: args[2], manifestPath: args[3], preimagePath: args[4] });
19
+ }
20
+ else {
21
+ throw new Error("expected fixed inspect, apply, or rollback arguments");
22
+ }
23
+ process.stdout.write(`${JSON.stringify(result)}\n`);
24
+ process.exitCode = result.status === "indeterminate" || result.status === "not_applied" ? 1 : 0;
25
+ }
26
+ catch (error) {
27
+ process.stdout.write(`${JSON.stringify({ status: "refused", error: (error instanceof Error ? error.message : String(error)).slice(0, 512) })}\n`);
28
+ process.exitCode = 2;
29
+ }
30
+ }
31
+ void main();