open-multi-agent-kit 0.92.0 → 0.94.0

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.
Files changed (173) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +2 -2
  3. package/dist/core/agent-session.d.ts +36 -14
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +155 -357
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction/branch-summarization.d.ts +5 -1
  8. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  9. package/dist/core/compaction/branch-summarization.js +5 -7
  10. package/dist/core/compaction/branch-summarization.js.map +1 -1
  11. package/dist/core/compaction/compaction.d.ts +12 -3
  12. package/dist/core/compaction/compaction.d.ts.map +1 -1
  13. package/dist/core/compaction/compaction.js +28 -15
  14. package/dist/core/compaction/compaction.js.map +1 -1
  15. package/dist/core/extensions/builtin/command-safety-gate.d.ts +8 -0
  16. package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/command-safety-gate.js +23 -0
  18. package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +4 -0
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +2 -0
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/keybindings.d.ts +5 -0
  26. package/dist/core/keybindings.d.ts.map +1 -1
  27. package/dist/core/keybindings.js +5 -0
  28. package/dist/core/keybindings.js.map +1 -1
  29. package/dist/core/model-resolver.d.ts +41 -3
  30. package/dist/core/model-resolver.d.ts.map +1 -1
  31. package/dist/core/model-resolver.js +17 -9
  32. package/dist/core/model-resolver.js.map +1 -1
  33. package/dist/core/package-manager.d.ts.map +1 -1
  34. package/dist/core/package-manager.js +11 -1
  35. package/dist/core/package-manager.js.map +1 -1
  36. package/dist/core/provider-resilience.d.ts.map +1 -1
  37. package/dist/core/provider-resilience.js +3 -1
  38. package/dist/core/provider-resilience.js.map +1 -1
  39. package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
  40. package/dist/core/reasoning-router-v4-weights.js +9 -3
  41. package/dist/core/reasoning-router-v4-weights.js.map +1 -1
  42. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  43. package/dist/core/reasoning-router-v4.js +94 -24
  44. package/dist/core/reasoning-router-v4.js.map +1 -1
  45. package/dist/core/resource-loader.d.ts.map +1 -1
  46. package/dist/core/resource-loader.js +11 -5
  47. package/dist/core/resource-loader.js.map +1 -1
  48. package/dist/core/sandbox/default-policy.d.ts +14 -0
  49. package/dist/core/sandbox/default-policy.d.ts.map +1 -0
  50. package/dist/core/sandbox/default-policy.js +58 -0
  51. package/dist/core/sandbox/default-policy.js.map +1 -0
  52. package/dist/core/sdk.d.ts.map +1 -1
  53. package/dist/core/sdk.js +1 -1
  54. package/dist/core/sdk.js.map +1 -1
  55. package/dist/core/session-bash-runtime.d.ts +62 -0
  56. package/dist/core/session-bash-runtime.d.ts.map +1 -0
  57. package/dist/core/session-bash-runtime.js +167 -0
  58. package/dist/core/session-bash-runtime.js.map +1 -0
  59. package/dist/core/session-bash-service.d.ts +61 -0
  60. package/dist/core/session-bash-service.d.ts.map +1 -0
  61. package/dist/core/session-bash-service.js +155 -0
  62. package/dist/core/session-bash-service.js.map +1 -0
  63. package/dist/core/session-compaction-service.d.ts +48 -0
  64. package/dist/core/session-compaction-service.d.ts.map +1 -0
  65. package/dist/core/session-compaction-service.js +250 -0
  66. package/dist/core/session-compaction-service.js.map +1 -0
  67. package/dist/core/session-file-compaction.d.ts.map +1 -1
  68. package/dist/core/session-file-compaction.js +39 -5
  69. package/dist/core/session-file-compaction.js.map +1 -1
  70. package/dist/core/session-termination.d.ts.map +1 -1
  71. package/dist/core/session-termination.js +1 -1
  72. package/dist/core/session-termination.js.map +1 -1
  73. package/dist/core/settings-manager.d.ts +3 -0
  74. package/dist/core/settings-manager.d.ts.map +1 -1
  75. package/dist/core/settings-manager.js +8 -0
  76. package/dist/core/settings-manager.js.map +1 -1
  77. package/dist/core/skills-catalog-cache.d.ts +25 -0
  78. package/dist/core/skills-catalog-cache.d.ts.map +1 -0
  79. package/dist/core/skills-catalog-cache.js +123 -0
  80. package/dist/core/skills-catalog-cache.js.map +1 -0
  81. package/dist/core/skills.d.ts +6 -0
  82. package/dist/core/skills.d.ts.map +1 -1
  83. package/dist/core/skills.js +25 -4
  84. package/dist/core/skills.js.map +1 -1
  85. package/dist/core/system-prompt.d.ts.map +1 -1
  86. package/dist/core/system-prompt.js +2 -2
  87. package/dist/core/system-prompt.js.map +1 -1
  88. package/dist/core/tools/bash.d.ts +5 -0
  89. package/dist/core/tools/bash.d.ts.map +1 -1
  90. package/dist/core/tools/bash.js +41 -13
  91. package/dist/core/tools/bash.js.map +1 -1
  92. package/dist/core/tools/diagnostics.d.ts +29 -0
  93. package/dist/core/tools/diagnostics.d.ts.map +1 -0
  94. package/dist/core/tools/diagnostics.js +325 -0
  95. package/dist/core/tools/diagnostics.js.map +1 -0
  96. package/dist/core/tools/index.d.ts +2 -1
  97. package/dist/core/tools/index.d.ts.map +1 -1
  98. package/dist/core/tools/index.js +18 -1
  99. package/dist/core/tools/index.js.map +1 -1
  100. package/dist/core/verified-bash-adapter.d.ts +18 -1
  101. package/dist/core/verified-bash-adapter.d.ts.map +1 -1
  102. package/dist/core/verified-bash-adapter.js +38 -1
  103. package/dist/core/verified-bash-adapter.js.map +1 -1
  104. package/dist/core/verified-bash-runtime.d.ts +13 -0
  105. package/dist/core/verified-bash-runtime.d.ts.map +1 -0
  106. package/dist/core/verified-bash-runtime.js +81 -0
  107. package/dist/core/verified-bash-runtime.js.map +1 -0
  108. package/dist/index.d.ts +4 -2
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +4 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/modes/interactive/components/control-panel-box.d.ts +27 -0
  113. package/dist/modes/interactive/components/control-panel-box.d.ts.map +1 -1
  114. package/dist/modes/interactive/components/control-panel-box.js +60 -8
  115. package/dist/modes/interactive/components/control-panel-box.js.map +1 -1
  116. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  117. package/dist/modes/interactive/components/control-panel-layout.js +100 -45
  118. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  119. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts +9 -0
  120. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/control-panel-runtime-status.js +10 -8
  122. package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
  123. package/dist/modes/interactive/components/control-panel-sparkles.d.ts +5 -0
  124. package/dist/modes/interactive/components/control-panel-sparkles.d.ts.map +1 -1
  125. package/dist/modes/interactive/components/control-panel-sparkles.js +14 -9
  126. package/dist/modes/interactive/components/control-panel-sparkles.js.map +1 -1
  127. package/dist/modes/interactive/components/footer.d.ts +10 -0
  128. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/footer.js +3 -3
  130. package/dist/modes/interactive/components/footer.js.map +1 -1
  131. package/dist/modes/interactive/components/status-sidebar.d.ts +49 -0
  132. package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -0
  133. package/dist/modes/interactive/components/status-sidebar.js +253 -0
  134. package/dist/modes/interactive/components/status-sidebar.js.map +1 -0
  135. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  136. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  137. package/dist/modes/interactive/interactive-mode.js +94 -20
  138. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  139. package/dist/modes/interactive/theme/omk-neon-control.json +13 -13
  140. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  141. package/dist/modes/rpc/rpc-mode.js +1 -0
  142. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  143. package/dist/types/evidence.d.ts +1 -1
  144. package/dist/types/evidence.d.ts.map +1 -1
  145. package/dist/types/evidence.js.map +1 -1
  146. package/dist/utils/clipboard.d.ts.map +1 -1
  147. package/dist/utils/clipboard.js +19 -8
  148. package/dist/utils/clipboard.js.map +1 -1
  149. package/dist/utils/frontmatter.d.ts.map +1 -1
  150. package/dist/utils/frontmatter.js +31 -5
  151. package/dist/utils/frontmatter.js.map +1 -1
  152. package/docs/compaction.md +7 -0
  153. package/docs/docs.json +4 -0
  154. package/docs/environment-variables.md +94 -0
  155. package/docs/index.md +1 -0
  156. package/docs/rpc.md +5 -2
  157. package/docs/sdk.md +10 -4
  158. package/docs/settings.md +1 -0
  159. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  160. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  161. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  162. package/examples/extensions/gondolin/package-lock.json +2 -2
  163. package/examples/extensions/gondolin/package.json +1 -1
  164. package/examples/extensions/sandbox/package-lock.json +2 -2
  165. package/examples/extensions/sandbox/package.json +1 -1
  166. package/examples/extensions/subagent/agents.test.ts +86 -0
  167. package/examples/extensions/subagent/agents.ts +18 -4
  168. package/examples/extensions/subagent/capabilities.ts +15 -1
  169. package/examples/extensions/subagent/domain-profiles.ts +272 -0
  170. package/examples/extensions/with-deps/package-lock.json +2 -2
  171. package/examples/extensions/with-deps/package.json +1 -1
  172. package/npm-shrinkwrap.json +15 -15
  173. package/package.json +10 -7
@@ -48,13 +48,41 @@ function sameOrderedIds(left, right) {
48
48
  return left.length === right.length && left.every((id, index) => id === right[index]?.id);
49
49
  }
50
50
  function assertSourceMatches(entry, envelope, source) {
51
- if (envelope.source.sessionId === "" ||
52
- !sameOrderedIds(envelope.source.entryIds, source) ||
53
- envelope.source.sourceSha256 !== sourceSha256(source) ||
54
- envelope.source.activeLeafId !== entry.parentId) {
51
+ if (!matchesSource(entry, envelope, source)) {
55
52
  throw new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);
56
53
  }
57
54
  }
55
+ function matchesSource(entry, envelope, source) {
56
+ return (envelope.source.sessionId !== "" &&
57
+ sameOrderedIds(envelope.source.entryIds, source) &&
58
+ envelope.source.sourceSha256 === sourceSha256(source) &&
59
+ envelope.source.activeLeafId === entry.parentId);
60
+ }
61
+ /**
62
+ * Writer-mirrored source window. The compaction writer (agent-session.ts) attests
63
+ * the slice of the active branch from the previous compaction's firstKeptEntryId
64
+ * onward — the summary covers the kept window plus earlier summaries, not the
65
+ * full parent branch. For the second and later compactions this window is
66
+ * strictly smaller than the full branch, so validating persisted envelopes
67
+ * against the full branch alone makes every twice-compacted session unopenable.
68
+ */
69
+ function windowedSourceFromPrefix(prefix, leafId) {
70
+ const branch = branchFromPrefix(prefix, leafId);
71
+ let latestCompactionIndex = -1;
72
+ for (let index = branch.length - 1; index >= 0; index -= 1) {
73
+ if (branch[index]?.type === "compaction") {
74
+ latestCompactionIndex = index;
75
+ break;
76
+ }
77
+ }
78
+ if (latestCompactionIndex < 0)
79
+ return branch;
80
+ const latestCompaction = branch[latestCompactionIndex];
81
+ if (latestCompaction?.type !== "compaction")
82
+ return branch;
83
+ const firstKeptIndex = branch.findIndex((entry) => entry.id === latestCompaction.firstKeptEntryId);
84
+ return branch.slice(firstKeptIndex < 0 ? latestCompactionIndex : firstKeptIndex);
85
+ }
58
86
  function persistedRecordStarts(bytes) {
59
87
  const starts = [0];
60
88
  for (let index = 0; index < bytes.byteLength; index += 1) {
@@ -106,7 +134,13 @@ export function validatePersistedCompactionEnvelopes(path, entries, sessionId) {
106
134
  envelope.summarySha256 !== summarySha256) {
107
135
  throw new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);
108
136
  }
109
- assertSourceMatches(entry, envelope, source);
137
+ // The writer attests either the full parent branch or its kept-window
138
+ // slice since the previous compaction (both are exact matches, so
139
+ // tamper-evidence is preserved; see windowedSourceFromPrefix).
140
+ if (!matchesSource(entry, envelope, source) &&
141
+ !matchesSource(entry, envelope, windowedSourceFromPrefix(prefix, entry.parentId))) {
142
+ throw new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);
143
+ }
110
144
  }
111
145
  }
112
146
  /** Copy one branch while rebinding nested compaction provenance in source order. */
@@ -1 +1 @@
1
- {"version":3,"file":"session-file-compaction.js","sourceRoot":"","sources":["../../src/core/session-file-compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport {\n\ttype CompactionEnvelope,\n\tcreateSessionRevisionToken,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/transaction.ts\";\nimport type { CompactionEntry, FileEntry, SessionEntry, SessionHeader } from \"./session-manager.ts\";\n\nfunction envelopeFromEntry(entry: CompactionEntry): CompactionEnvelope | null {\n\tif (typeof entry.details !== \"object\" || entry.details === null || Array.isArray(entry.details)) return null;\n\tif (!Object.hasOwn(entry.details, \"compactionEnvelope\")) return null;\n\treturn validateCompactionEnvelope(Reflect.get(entry.details, \"compactionEnvelope\"));\n}\n\nfunction branchFromPrefix(prefix: readonly FileEntry[], leafId: string): SessionEntry[] {\n\tconst byId = new Map(\n\t\tprefix.filter((entry): entry is SessionEntry => entry.type !== \"session\").map((entry) => [entry.id, entry]),\n\t);\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current = byId.get(leafId);\n\twhile (current) {\n\t\tif (seen.has(current.id)) throw new Error(`Compaction source at ${leafId} contains a cycle`);\n\t\tseen.add(current.id);\n\t\tbranch.unshift(current);\n\t\tcurrent = current.parentId === null ? undefined : byId.get(current.parentId);\n\t}\n\tif (branch.at(-1)?.id !== leafId)\n\t\tthrow new Error(`Compaction source leaf ${leafId} is outside the persisted prefix`);\n\treturn branch;\n}\n\nfunction sourceSha256(entries: readonly SessionEntry[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(entries.map((entry) => JSON.stringify(entry)).join(\"\\n\"), \"utf8\")\n\t\t.digest(\"hex\");\n}\n\nfunction serializedPrefix(prefix: readonly FileEntry[]): string {\n\treturn `${prefix.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nfunction prefixRevision(header: SessionHeader, prefix: readonly FileEntry[], leafId: string) {\n\tconst bytes = serializedPrefix(prefix);\n\tconst last = prefix.at(-1);\n\treturn createSessionRevisionToken({\n\t\tsessionId: header.id,\n\t\tcompleteBytes: Buffer.byteLength(bytes),\n\t\trecordCount: prefix.length,\n\t\tleafId,\n\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes, \"utf8\").digest(\"hex\"),\n\t});\n}\n\nfunction sameOrderedIds(left: readonly string[], right: readonly SessionEntry[]): boolean {\n\treturn left.length === right.length && left.every((id, index) => id === right[index]?.id);\n}\n\nfunction assertSourceMatches(\n\tentry: CompactionEntry,\n\tenvelope: CompactionEnvelope,\n\tsource: readonly SessionEntry[],\n): void {\n\tif (\n\t\tenvelope.source.sessionId === \"\" ||\n\t\t!sameOrderedIds(envelope.source.entryIds, source) ||\n\t\tenvelope.source.sourceSha256 !== sourceSha256(source) ||\n\t\tenvelope.source.activeLeafId !== entry.parentId\n\t) {\n\t\tthrow new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);\n\t}\n}\n\nfunction persistedRecordStarts(bytes: Uint8Array): number[] {\n\tconst starts = [0];\n\tfor (let index = 0; index < bytes.byteLength; index += 1) {\n\t\tif (bytes[index] === 0x0a && index + 1 < bytes.byteLength) starts.push(index + 1);\n\t}\n\treturn starts;\n}\n\n/** Recompute persisted compaction provenance instead of trusting its envelope. */\nexport function validatePersistedCompactionEnvelopes(\n\tpath: string,\n\tentries: readonly FileEntry[],\n\tsessionId: string,\n): void {\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || header.id !== sessionId) throw new Error(\"Invalid session header\");\n\tconst bytes = readFileSync(path);\n\tconst starts = persistedRecordStarts(bytes);\n\tfor (let index = 0; index < entries.length; index += 1) {\n\t\tconst entry = entries[index];\n\t\tif (!entry || entry.type !== \"compaction\") continue;\n\t\tconst envelope = envelopeFromEntry(entry);\n\t\tif (!envelope) continue;\n\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\tconst prefix = entries.slice(0, index);\n\t\tconst source = branchFromPrefix(prefix, entry.parentId);\n\t\tconst start = starts[index];\n\t\tif (start === undefined) throw new Error(`Compaction entry ${entry.id} has no persisted prefix`);\n\t\tconst last = prefix.at(-1);\n\t\tconst expectedRevision = createSessionRevisionToken({\n\t\t\tsessionId,\n\t\t\tcompleteBytes: start,\n\t\t\trecordCount: index,\n\t\t\tleafId: entry.parentId,\n\t\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes.subarray(0, start)).digest(\"hex\"),\n\t\t});\n\t\tconst base = envelope.baseRevision;\n\t\tconst summarySha256 = createHash(\"sha256\").update(entry.summary, \"utf8\").digest(\"hex\");\n\t\tif (\n\t\t\tbase.sessionId !== expectedRevision.sessionId ||\n\t\t\tbase.completeBytes !== expectedRevision.completeBytes ||\n\t\t\tbase.recordCount !== expectedRevision.recordCount ||\n\t\t\tbase.leafId !== expectedRevision.leafId ||\n\t\t\tbase.lastEntryId !== expectedRevision.lastEntryId ||\n\t\t\tbase.completePrefixSha256 !== expectedRevision.completePrefixSha256 ||\n\t\t\tenvelope.source.sessionId !== sessionId ||\n\t\t\tenvelope.summary !== entry.summary ||\n\t\t\tenvelope.summarySha256 !== summarySha256\n\t\t) {\n\t\t\tthrow new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);\n\t\t}\n\t\tassertSourceMatches(entry, envelope, source);\n\t}\n}\n\n/** Copy one branch while rebinding nested compaction provenance in source order. */\nexport function rebindBranchedCompactionEnvelopes(\n\theader: SessionHeader,\n\tentries: readonly SessionEntry[],\n): SessionEntry[] {\n\tconst referencedLabels = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"compaction\") continue;\n\t\tfor (const id of envelopeFromEntry(entry)?.source.entryIds ?? []) referencedLabels.add(id);\n\t}\n\tconst originalPrefix: FileEntry[] = [];\n\tconst copiedPrefix: FileEntry[] = [header];\n\tconst copied: SessionEntry[] = [];\n\tfor (const entry of entries) {\n\t\tlet copy = entry;\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst details = entry.details;\n\t\t\tconst envelope = envelopeFromEntry(entry);\n\t\t\tif (envelope) {\n\t\t\t\tif (typeof details !== \"object\" || details === null || Array.isArray(details))\n\t\t\t\t\tthrow new Error(`Compaction entry ${entry.id} has invalid details`);\n\t\t\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\t\t\tassertSourceMatches(entry, envelope, branchFromPrefix(originalPrefix, entry.parentId));\n\t\t\t\tconst source = branchFromPrefix(copiedPrefix, entry.parentId);\n\t\t\t\tconst first = source[0];\n\t\t\t\tconst last = source.at(-1);\n\t\t\t\tif (!first || !last) throw new Error(`Compaction entry ${entry.id} has no source entries`);\n\t\t\t\tcopy = {\n\t\t\t\t\t...entry,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\t...details,\n\t\t\t\t\t\tcompactionEnvelope: validateCompactionEnvelope({\n\t\t\t\t\t\t\t...envelope,\n\t\t\t\t\t\t\tbaseRevision: prefixRevision(header, copiedPrefix, entry.parentId),\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\t...envelope.source,\n\t\t\t\t\t\t\t\tsessionId: header.id,\n\t\t\t\t\t\t\t\tentryIds: source.map((candidate) => candidate.id),\n\t\t\t\t\t\t\t\tfirstEntryId: first.id,\n\t\t\t\t\t\t\t\tlastEntryId: last.id,\n\t\t\t\t\t\t\t\tsourceSha256: sourceSha256(source),\n\t\t\t\t\t\t\t\tactiveLeafId: entry.parentId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\toriginalPrefix.push(entry);\n\t\tif (entry.type === \"label\" && !referencedLabels.has(entry.id)) continue;\n\t\tcopied.push(copy);\n\t\tcopiedPrefix.push(copy);\n\t}\n\treturn copied;\n}\n"]}
1
+ {"version":3,"file":"session-file-compaction.js","sourceRoot":"","sources":["../../src/core/session-file-compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport {\n\ttype CompactionEnvelope,\n\tcreateSessionRevisionToken,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/transaction.ts\";\nimport type { CompactionEntry, FileEntry, SessionEntry, SessionHeader } from \"./session-manager.ts\";\n\nfunction envelopeFromEntry(entry: CompactionEntry): CompactionEnvelope | null {\n\tif (typeof entry.details !== \"object\" || entry.details === null || Array.isArray(entry.details)) return null;\n\tif (!Object.hasOwn(entry.details, \"compactionEnvelope\")) return null;\n\treturn validateCompactionEnvelope(Reflect.get(entry.details, \"compactionEnvelope\"));\n}\n\nfunction branchFromPrefix(prefix: readonly FileEntry[], leafId: string): SessionEntry[] {\n\tconst byId = new Map(\n\t\tprefix.filter((entry): entry is SessionEntry => entry.type !== \"session\").map((entry) => [entry.id, entry]),\n\t);\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current = byId.get(leafId);\n\twhile (current) {\n\t\tif (seen.has(current.id)) throw new Error(`Compaction source at ${leafId} contains a cycle`);\n\t\tseen.add(current.id);\n\t\tbranch.unshift(current);\n\t\tcurrent = current.parentId === null ? undefined : byId.get(current.parentId);\n\t}\n\tif (branch.at(-1)?.id !== leafId)\n\t\tthrow new Error(`Compaction source leaf ${leafId} is outside the persisted prefix`);\n\treturn branch;\n}\n\nfunction sourceSha256(entries: readonly SessionEntry[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(entries.map((entry) => JSON.stringify(entry)).join(\"\\n\"), \"utf8\")\n\t\t.digest(\"hex\");\n}\n\nfunction serializedPrefix(prefix: readonly FileEntry[]): string {\n\treturn `${prefix.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nfunction prefixRevision(header: SessionHeader, prefix: readonly FileEntry[], leafId: string) {\n\tconst bytes = serializedPrefix(prefix);\n\tconst last = prefix.at(-1);\n\treturn createSessionRevisionToken({\n\t\tsessionId: header.id,\n\t\tcompleteBytes: Buffer.byteLength(bytes),\n\t\trecordCount: prefix.length,\n\t\tleafId,\n\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes, \"utf8\").digest(\"hex\"),\n\t});\n}\n\nfunction sameOrderedIds(left: readonly string[], right: readonly SessionEntry[]): boolean {\n\treturn left.length === right.length && left.every((id, index) => id === right[index]?.id);\n}\n\nfunction assertSourceMatches(\n\tentry: CompactionEntry,\n\tenvelope: CompactionEnvelope,\n\tsource: readonly SessionEntry[],\n): void {\n\tif (!matchesSource(entry, envelope, source)) {\n\t\tthrow new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);\n\t}\n}\n\nfunction matchesSource(entry: CompactionEntry, envelope: CompactionEnvelope, source: readonly SessionEntry[]): boolean {\n\treturn (\n\t\tenvelope.source.sessionId !== \"\" &&\n\t\tsameOrderedIds(envelope.source.entryIds, source) &&\n\t\tenvelope.source.sourceSha256 === sourceSha256(source) &&\n\t\tenvelope.source.activeLeafId === entry.parentId\n\t);\n}\n\n/**\n * Writer-mirrored source window. The compaction writer (agent-session.ts) attests\n * the slice of the active branch from the previous compaction's firstKeptEntryId\n * onward — the summary covers the kept window plus earlier summaries, not the\n * full parent branch. For the second and later compactions this window is\n * strictly smaller than the full branch, so validating persisted envelopes\n * against the full branch alone makes every twice-compacted session unopenable.\n */\nfunction windowedSourceFromPrefix(prefix: readonly FileEntry[], leafId: string): SessionEntry[] {\n\tconst branch = branchFromPrefix(prefix, leafId);\n\tlet latestCompactionIndex = -1;\n\tfor (let index = branch.length - 1; index >= 0; index -= 1) {\n\t\tif (branch[index]?.type === \"compaction\") {\n\t\t\tlatestCompactionIndex = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (latestCompactionIndex < 0) return branch;\n\tconst latestCompaction = branch[latestCompactionIndex];\n\tif (latestCompaction?.type !== \"compaction\") return branch;\n\tconst firstKeptIndex = branch.findIndex((entry) => entry.id === latestCompaction.firstKeptEntryId);\n\treturn branch.slice(firstKeptIndex < 0 ? latestCompactionIndex : firstKeptIndex);\n}\n\nfunction persistedRecordStarts(bytes: Uint8Array): number[] {\n\tconst starts = [0];\n\tfor (let index = 0; index < bytes.byteLength; index += 1) {\n\t\tif (bytes[index] === 0x0a && index + 1 < bytes.byteLength) starts.push(index + 1);\n\t}\n\treturn starts;\n}\n\n/** Recompute persisted compaction provenance instead of trusting its envelope. */\nexport function validatePersistedCompactionEnvelopes(\n\tpath: string,\n\tentries: readonly FileEntry[],\n\tsessionId: string,\n): void {\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || header.id !== sessionId) throw new Error(\"Invalid session header\");\n\tconst bytes = readFileSync(path);\n\tconst starts = persistedRecordStarts(bytes);\n\tfor (let index = 0; index < entries.length; index += 1) {\n\t\tconst entry = entries[index];\n\t\tif (!entry || entry.type !== \"compaction\") continue;\n\t\tconst envelope = envelopeFromEntry(entry);\n\t\tif (!envelope) continue;\n\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\tconst prefix = entries.slice(0, index);\n\t\tconst source = branchFromPrefix(prefix, entry.parentId);\n\t\tconst start = starts[index];\n\t\tif (start === undefined) throw new Error(`Compaction entry ${entry.id} has no persisted prefix`);\n\t\tconst last = prefix.at(-1);\n\t\tconst expectedRevision = createSessionRevisionToken({\n\t\t\tsessionId,\n\t\t\tcompleteBytes: start,\n\t\t\trecordCount: index,\n\t\t\tleafId: entry.parentId,\n\t\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes.subarray(0, start)).digest(\"hex\"),\n\t\t});\n\t\tconst base = envelope.baseRevision;\n\t\tconst summarySha256 = createHash(\"sha256\").update(entry.summary, \"utf8\").digest(\"hex\");\n\t\tif (\n\t\t\tbase.sessionId !== expectedRevision.sessionId ||\n\t\t\tbase.completeBytes !== expectedRevision.completeBytes ||\n\t\t\tbase.recordCount !== expectedRevision.recordCount ||\n\t\t\tbase.leafId !== expectedRevision.leafId ||\n\t\t\tbase.lastEntryId !== expectedRevision.lastEntryId ||\n\t\t\tbase.completePrefixSha256 !== expectedRevision.completePrefixSha256 ||\n\t\t\tenvelope.source.sessionId !== sessionId ||\n\t\t\tenvelope.summary !== entry.summary ||\n\t\t\tenvelope.summarySha256 !== summarySha256\n\t\t) {\n\t\t\tthrow new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);\n\t\t}\n\t\t// The writer attests either the full parent branch or its kept-window\n\t\t// slice since the previous compaction (both are exact matches, so\n\t\t// tamper-evidence is preserved; see windowedSourceFromPrefix).\n\t\tif (\n\t\t\t!matchesSource(entry, envelope, source) &&\n\t\t\t!matchesSource(entry, envelope, windowedSourceFromPrefix(prefix, entry.parentId))\n\t\t) {\n\t\t\tthrow new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);\n\t\t}\n\t}\n}\n\n/** Copy one branch while rebinding nested compaction provenance in source order. */\nexport function rebindBranchedCompactionEnvelopes(\n\theader: SessionHeader,\n\tentries: readonly SessionEntry[],\n): SessionEntry[] {\n\tconst referencedLabels = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"compaction\") continue;\n\t\tfor (const id of envelopeFromEntry(entry)?.source.entryIds ?? []) referencedLabels.add(id);\n\t}\n\tconst originalPrefix: FileEntry[] = [];\n\tconst copiedPrefix: FileEntry[] = [header];\n\tconst copied: SessionEntry[] = [];\n\tfor (const entry of entries) {\n\t\tlet copy = entry;\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst details = entry.details;\n\t\t\tconst envelope = envelopeFromEntry(entry);\n\t\t\tif (envelope) {\n\t\t\t\tif (typeof details !== \"object\" || details === null || Array.isArray(details))\n\t\t\t\t\tthrow new Error(`Compaction entry ${entry.id} has invalid details`);\n\t\t\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\t\t\tassertSourceMatches(entry, envelope, branchFromPrefix(originalPrefix, entry.parentId));\n\t\t\t\tconst source = branchFromPrefix(copiedPrefix, entry.parentId);\n\t\t\t\tconst first = source[0];\n\t\t\t\tconst last = source.at(-1);\n\t\t\t\tif (!first || !last) throw new Error(`Compaction entry ${entry.id} has no source entries`);\n\t\t\t\tcopy = {\n\t\t\t\t\t...entry,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\t...details,\n\t\t\t\t\t\tcompactionEnvelope: validateCompactionEnvelope({\n\t\t\t\t\t\t\t...envelope,\n\t\t\t\t\t\t\tbaseRevision: prefixRevision(header, copiedPrefix, entry.parentId),\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\t...envelope.source,\n\t\t\t\t\t\t\t\tsessionId: header.id,\n\t\t\t\t\t\t\t\tentryIds: source.map((candidate) => candidate.id),\n\t\t\t\t\t\t\t\tfirstEntryId: first.id,\n\t\t\t\t\t\t\t\tlastEntryId: last.id,\n\t\t\t\t\t\t\t\tsourceSha256: sourceSha256(source),\n\t\t\t\t\t\t\t\tactiveLeafId: entry.parentId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\toriginalPrefix.push(entry);\n\t\tif (entry.type === \"label\" && !referencedLabels.has(entry.id)) continue;\n\t\tcopied.push(copy);\n\t\tcopiedPrefix.push(copy);\n\t}\n\treturn copied;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-termination.d.ts","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"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","sourcesContent":["export const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/**\n * Canonical list of termination kinds. The run-journal validator derives its\n * runtime bounds from this tuple so a newly added kind can never crash\n * journaling with \"termination kind is out of bounds\" again.\n */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n] as const;\n\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\n\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\n\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\n\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\";\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\"aborted\", \"failed\", \"stale\"]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\treturn `Run /login${input.provider ? ` ${input.provider}` : \"\"} or configure valid credentials, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\treturn \"Retry compaction after resolving the reported barrier or stale transaction.\";\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"Correct the provider, model, tool, or session configuration and retry.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
1
+ {"version":3,"file":"session-termination.d.ts","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"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","sourcesContent":["export const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/**\n * Canonical list of termination kinds. The run-journal validator derives its\n * runtime bounds from this tuple so a newly added kind can never crash\n * journaling with \"termination kind is out of bounds\" again.\n */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n] as const;\n\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\n\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\n\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\n\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\";\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\"aborted\", \"failed\", \"stale\"]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\treturn `Run /login${input.provider ? ` ${input.provider}` : \"\"} or configure valid credentials, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/qwen3.8-max/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\treturn \"Retry compaction after resolving the reported barrier or stale transaction.\";\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"Correct the provider, model, tool, or session configuration and retry.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
@@ -353,7 +353,7 @@ function nextActionFor(classification, input) {
353
353
  case "provider_protocol":
354
354
  return "Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.";
355
355
  case "provider_refusal":
356
- return "Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/grok-4.5/deepseek) / rephrase as a pure coding task.";
356
+ return "Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/qwen3.8-max/grok-4.5/deepseek) / rephrase as a pure coding task.";
357
357
  case "context_overflow":
358
358
  return "Compact or reduce context, or switch to a larger-context model.";
359
359
  case "tool_timeout":
@@ -1 +1 @@
1
- {"version":3,"file":"session-termination.js","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"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","sourcesContent":["export const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/**\n * Canonical list of termination kinds. The run-journal validator derives its\n * runtime bounds from this tuple so a newly added kind can never crash\n * journaling with \"termination kind is out of bounds\" again.\n */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n] as const;\n\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\n\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\n\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\n\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\";\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\"aborted\", \"failed\", \"stale\"]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\treturn `Run /login${input.provider ? ` ${input.provider}` : \"\"} or configure valid credentials, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\treturn \"Retry compaction after resolving the reported barrier or stale transaction.\";\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"Correct the provider, model, tool, or session configuration and retry.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
1
+ {"version":3,"file":"session-termination.js","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"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","sourcesContent":["export const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/**\n * Canonical list of termination kinds. The run-journal validator derives its\n * runtime bounds from this tuple so a newly added kind can never crash\n * journaling with \"termination kind is out of bounds\" again.\n */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n] as const;\n\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\n\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\n\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\n\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\";\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\"aborted\", \"failed\", \"stale\"]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\treturn `Run /login${input.provider ? ` ${input.provider}` : \"\"} or configure valid credentials, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/qwen3.8-max/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\treturn \"Retry compaction after resolving the reported barrier or stale transaction.\";\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"Correct the provider, model, tool, or session configuration and retry.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
@@ -149,6 +149,7 @@ export interface Settings {
149
149
  editorPaddingX?: number;
150
150
  autocompleteMaxVisible?: number;
151
151
  showHardwareCursor?: boolean;
152
+ pinStatusSidebar?: boolean;
152
153
  markdown?: MarkdownSettings;
153
154
  warnings?: WarningSettings;
154
155
  sessionDir?: string;
@@ -348,6 +349,8 @@ export declare class SettingsManager {
348
349
  setTreeFilterMode(mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): void;
349
350
  getShowHardwareCursor(): boolean;
350
351
  setShowHardwareCursor(enabled: boolean): void;
352
+ getPinStatusSidebar(): boolean;
353
+ setPinStatusSidebar(pinned: boolean): void;
351
354
  getEditorPaddingX(): number;
352
355
  setEditorPaddingX(padding: number): void;
353
356
  getAutocompleteMaxVisible(): number;