@llblab/pi-kit 0.38.3 → 0.39.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 (430) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-actors/AGENTS.md +108 -20
  4. package/node_modules/@llblab/pi-actors/BACKLOG.md +207 -4
  5. package/node_modules/@llblab/pi-actors/CHANGELOG.md +13 -0
  6. package/node_modules/@llblab/pi-actors/README.md +31 -1
  7. package/node_modules/@llblab/pi-actors/dist/index.js +1 -1
  8. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +37 -0
  9. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +131 -62
  10. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.d.ts +2 -0
  11. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.js +3 -2
  12. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.d.ts +37 -0
  13. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +263 -129
  14. package/node_modules/@llblab/pi-actors/dist/lib/execution-files.d.ts +32 -0
  15. package/node_modules/@llblab/pi-actors/dist/lib/execution-files.js +128 -0
  16. package/node_modules/@llblab/pi-actors/dist/lib/execution-output.js +5 -4
  17. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.d.ts +19 -1
  18. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.js +62 -26
  19. package/node_modules/@llblab/pi-actors/dist/lib/execution.d.ts +4 -1
  20. package/node_modules/@llblab/pi-actors/dist/lib/execution.js +6 -1
  21. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.d.ts +9 -2
  22. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +92 -14
  23. package/node_modules/@llblab/pi-actors/dist/lib/file-state.js +21 -2
  24. package/node_modules/@llblab/pi-actors/dist/lib/inspector-command.js +2 -2
  25. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.d.ts +25 -7
  26. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.js +562 -262
  27. package/node_modules/@llblab/pi-actors/dist/lib/inspector.d.ts +20 -10
  28. package/node_modules/@llblab/pi-actors/dist/lib/inspector.js +80 -91
  29. package/node_modules/@llblab/pi-actors/dist/lib/limits.d.ts +1 -0
  30. package/node_modules/@llblab/pi-actors/dist/lib/limits.js +1 -0
  31. package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +15 -1
  32. package/node_modules/@llblab/pi-actors/dist/lib/observability.js +216 -99
  33. package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +5 -4
  34. package/node_modules/@llblab/pi-actors/dist/lib/pi.js +64 -10
  35. package/node_modules/@llblab/pi-actors/dist/lib/recipe-projection.d.ts +18 -0
  36. package/node_modules/@llblab/pi-actors/dist/lib/recipe-projection.js +220 -0
  37. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.d.ts +2 -0
  38. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.js +30 -6
  39. package/node_modules/@llblab/pi-actors/dist/lib/registry.js +270 -36
  40. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +213 -5
  41. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +1909 -40
  42. package/node_modules/@llblab/pi-actors/dist/lib/run-supervision.d.ts +107 -0
  43. package/node_modules/@llblab/pi-actors/dist/lib/run-supervision.js +412 -0
  44. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.d.ts +9 -2
  45. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +283 -60
  46. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.d.ts +26 -1
  47. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.js +68 -2
  48. package/node_modules/@llblab/pi-actors/dist/lib/runs-context-exports.d.ts +451 -0
  49. package/node_modules/@llblab/pi-actors/dist/lib/runs-context-exports.js +2315 -0
  50. package/node_modules/@llblab/pi-actors/dist/lib/runs-context-index.d.ts +97 -0
  51. package/node_modules/@llblab/pi-actors/dist/lib/runs-context-index.js +368 -0
  52. package/node_modules/@llblab/pi-actors/dist/lib/runs-control-delivery.js +46 -7
  53. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.d.ts +78 -2
  54. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.js +334 -2
  55. package/node_modules/@llblab/pi-actors/dist/lib/runs-controls.js +4 -1
  56. package/node_modules/@llblab/pi-actors/dist/lib/runs-descendant-launches.d.ts +80 -0
  57. package/node_modules/@llblab/pi-actors/dist/lib/runs-descendant-launches.js +287 -0
  58. package/node_modules/@llblab/pi-actors/dist/lib/runs-execution-evidence.d.ts +110 -0
  59. package/node_modules/@llblab/pi-actors/dist/lib/runs-execution-evidence.js +282 -0
  60. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.d.ts +66 -1
  61. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.js +349 -13
  62. package/node_modules/@llblab/pi-actors/dist/lib/runs-native-launches.d.ts +73 -0
  63. package/node_modules/@llblab/pi-actors/dist/lib/runs-native-launches.js +227 -0
  64. package/node_modules/@llblab/pi-actors/dist/lib/runs-outcomes.d.ts +141 -0
  65. package/node_modules/@llblab/pi-actors/dist/lib/runs-outcomes.js +292 -0
  66. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.d.ts +10 -1
  67. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.js +36 -4
  68. package/node_modules/@llblab/pi-actors/dist/lib/runs-process-windows-mi.d.ts +46 -0
  69. package/node_modules/@llblab/pi-actors/dist/lib/runs-process-windows-mi.js +114 -0
  70. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.d.ts +34 -1
  71. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.js +158 -26
  72. package/node_modules/@llblab/pi-actors/dist/lib/runs-results.d.ts +116 -0
  73. package/node_modules/@llblab/pi-actors/dist/lib/runs-results.js +518 -0
  74. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.d.ts +15 -2
  75. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.js +148 -9
  76. package/node_modules/@llblab/pi-actors/dist/lib/runs-session-exports.d.ts +95 -0
  77. package/node_modules/@llblab/pi-actors/dist/lib/runs-session-exports.js +470 -0
  78. package/node_modules/@llblab/pi-actors/dist/lib/runs-snapshot.d.ts +58 -0
  79. package/node_modules/@llblab/pi-actors/dist/lib/runs-snapshot.js +92 -0
  80. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.d.ts +2 -0
  81. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.js +44 -3
  82. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.d.ts +15 -1
  83. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.js +337 -13
  84. package/node_modules/@llblab/pi-actors/dist/lib/runs-supervision.d.ts +105 -0
  85. package/node_modules/@llblab/pi-actors/dist/lib/runs-supervision.js +501 -0
  86. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.d.ts +1 -0
  87. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.js +14 -3
  88. package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +22 -3
  89. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.d.ts +37 -0
  90. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.js +59 -3
  91. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.d.ts +4 -1
  92. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.js +14 -8
  93. package/node_modules/@llblab/pi-actors/dist/lib/temp.d.ts +2 -4
  94. package/node_modules/@llblab/pi-actors/dist/lib/temp.js +4 -56
  95. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.d.ts +3 -0
  96. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.js +13 -0
  97. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.d.ts +1 -0
  98. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.js +110 -43
  99. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.d.ts +3 -0
  100. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.js +18 -6
  101. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.d.ts +4 -1
  102. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.js +126 -31
  103. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.d.ts +31 -3
  104. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.js +311 -47
  105. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.d.ts +3 -0
  106. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.js +29 -7
  107. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.d.ts +20 -0
  108. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.js +192 -43
  109. package/node_modules/@llblab/pi-actors/dist/scripts/async-runner.mjs +272 -194
  110. package/node_modules/@llblab/pi-actors/dist/scripts/conformance.mjs +14 -2
  111. package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +46 -2
  112. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/diagnostics.md +40 -0
  113. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/runs.md +55 -1
  114. package/node_modules/@llblab/pi-actors/docs/README.md +9 -1
  115. package/node_modules/@llblab/pi-actors/docs/actor-inspector.md +84 -15
  116. package/node_modules/@llblab/pi-actors/docs/agent-experience.md +216 -0
  117. package/node_modules/@llblab/pi-actors/docs/async-runs.md +18 -2
  118. package/node_modules/@llblab/pi-actors/docs/composition-transport.md +103 -0
  119. package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +204 -4
  120. package/node_modules/@llblab/pi-actors/docs/inspection.md +38 -2
  121. package/node_modules/@llblab/pi-actors/docs/output-projection-map.md +130 -0
  122. package/node_modules/@llblab/pi-actors/docs/releasing.md +19 -2
  123. package/node_modules/@llblab/pi-actors/docs/run-supervision.md +1622 -0
  124. package/node_modules/@llblab/pi-actors/docs/template-recipes.md +4 -0
  125. package/node_modules/@llblab/pi-actors/docs/windows-process-observation.md +248 -0
  126. package/node_modules/@llblab/pi-actors/index.ts +1 -1
  127. package/node_modules/@llblab/pi-actors/lib/async-runs.ts +164 -73
  128. package/node_modules/@llblab/pi-actors/lib/automatic-review-runtime.ts +4 -2
  129. package/node_modules/@llblab/pi-actors/lib/command-templates.ts +287 -138
  130. package/node_modules/@llblab/pi-actors/lib/execution-files.ts +118 -0
  131. package/node_modules/@llblab/pi-actors/lib/execution-output.ts +4 -4
  132. package/node_modules/@llblab/pi-actors/lib/execution-sessions.ts +57 -27
  133. package/node_modules/@llblab/pi-actors/lib/execution.ts +8 -0
  134. package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +102 -12
  135. package/node_modules/@llblab/pi-actors/lib/file-state.ts +16 -2
  136. package/node_modules/@llblab/pi-actors/lib/inspector-command.ts +2 -2
  137. package/node_modules/@llblab/pi-actors/lib/inspector-overlay.ts +524 -261
  138. package/node_modules/@llblab/pi-actors/lib/inspector.ts +101 -130
  139. package/node_modules/@llblab/pi-actors/lib/limits.ts +1 -0
  140. package/node_modules/@llblab/pi-actors/lib/observability.ts +235 -116
  141. package/node_modules/@llblab/pi-actors/lib/pi.ts +59 -11
  142. package/node_modules/@llblab/pi-actors/lib/recipe-projection.ts +232 -0
  143. package/node_modules/@llblab/pi-actors/lib/recipes-context.ts +27 -6
  144. package/node_modules/@llblab/pi-actors/lib/registry.ts +266 -36
  145. package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +1737 -49
  146. package/node_modules/@llblab/pi-actors/lib/run-supervision.ts +411 -0
  147. package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +237 -73
  148. package/node_modules/@llblab/pi-actors/lib/runs-artifacts.ts +73 -1
  149. package/node_modules/@llblab/pi-actors/lib/runs-context-exports.ts +1871 -0
  150. package/node_modules/@llblab/pi-actors/lib/runs-context-index.ts +372 -0
  151. package/node_modules/@llblab/pi-actors/lib/runs-control-delivery.ts +36 -18
  152. package/node_modules/@llblab/pi-actors/lib/runs-control.ts +297 -1
  153. package/node_modules/@llblab/pi-actors/lib/runs-controls.ts +3 -1
  154. package/node_modules/@llblab/pi-actors/lib/runs-descendant-launches.ts +338 -0
  155. package/node_modules/@llblab/pi-actors/lib/runs-execution-evidence.ts +302 -0
  156. package/node_modules/@llblab/pi-actors/lib/runs-index.ts +345 -17
  157. package/node_modules/@llblab/pi-actors/lib/runs-native-launches.ts +270 -0
  158. package/node_modules/@llblab/pi-actors/lib/runs-outcomes.ts +377 -0
  159. package/node_modules/@llblab/pi-actors/lib/runs-ownership.ts +37 -4
  160. package/node_modules/@llblab/pi-actors/lib/runs-process-windows-mi.ts +113 -0
  161. package/node_modules/@llblab/pi-actors/lib/runs-process.ts +210 -34
  162. package/node_modules/@llblab/pi-actors/lib/runs-results.ts +601 -0
  163. package/node_modules/@llblab/pi-actors/lib/runs-retention.ts +134 -10
  164. package/node_modules/@llblab/pi-actors/lib/runs-session-exports.ts +406 -0
  165. package/node_modules/@llblab/pi-actors/lib/runs-snapshot.ts +143 -0
  166. package/node_modules/@llblab/pi-actors/lib/runs-start.ts +44 -2
  167. package/node_modules/@llblab/pi-actors/lib/runs-status.ts +252 -10
  168. package/node_modules/@llblab/pi-actors/lib/runs-supervision.ts +394 -0
  169. package/node_modules/@llblab/pi-actors/lib/runs-trace.ts +14 -3
  170. package/node_modules/@llblab/pi-actors/lib/runtime.ts +22 -3
  171. package/node_modules/@llblab/pi-actors/lib/session-evidence.ts +76 -4
  172. package/node_modules/@llblab/pi-actors/lib/state-readers.ts +16 -7
  173. package/node_modules/@llblab/pi-actors/lib/temp.ts +3 -56
  174. package/node_modules/@llblab/pi-actors/lib/tools-access.ts +13 -0
  175. package/node_modules/@llblab/pi-actors/lib/tools-inspect.ts +110 -51
  176. package/node_modules/@llblab/pi-actors/lib/tools-local.ts +37 -24
  177. package/node_modules/@llblab/pi-actors/lib/tools-message.ts +120 -37
  178. package/node_modules/@llblab/pi-actors/lib/tools-response.ts +273 -50
  179. package/node_modules/@llblab/pi-actors/lib/tools-spawn.ts +31 -10
  180. package/node_modules/@llblab/pi-actors/lib/trace-projection.ts +165 -42
  181. package/node_modules/@llblab/pi-actors/package.json +10 -6
  182. package/node_modules/@llblab/pi-actors/scripts/async-runner.mjs +272 -194
  183. package/node_modules/@llblab/pi-actors/scripts/conformance.mjs +14 -2
  184. package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +46 -2
  185. package/node_modules/@llblab/pi-actors/skills/actors/references/diagnostics.md +40 -0
  186. package/node_modules/@llblab/pi-actors/skills/actors/references/runs.md +55 -1
  187. package/node_modules/@llblab/pi-codex-usage/AGENTS.md +2 -2
  188. package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +6 -0
  189. package/node_modules/@llblab/pi-codex-usage/README.md +9 -5
  190. package/node_modules/@llblab/pi-codex-usage/lib/query.ts +229 -50
  191. package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +9 -1
  192. package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
  193. package/node_modules/yaml/LICENSE +13 -0
  194. package/node_modules/yaml/README.md +172 -0
  195. package/node_modules/yaml/bin.mjs +11 -0
  196. package/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
  197. package/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
  198. package/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
  199. package/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
  200. package/node_modules/yaml/browser/dist/compose/composer.js +219 -0
  201. package/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
  202. package/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
  203. package/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
  204. package/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
  205. package/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
  206. package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +225 -0
  207. package/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
  208. package/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
  209. package/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
  210. package/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
  211. package/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
  212. package/node_modules/yaml/browser/dist/doc/Document.js +335 -0
  213. package/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
  214. package/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
  215. package/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
  216. package/node_modules/yaml/browser/dist/doc/directives.js +176 -0
  217. package/node_modules/yaml/browser/dist/errors.js +57 -0
  218. package/node_modules/yaml/browser/dist/index.js +17 -0
  219. package/node_modules/yaml/browser/dist/log.js +11 -0
  220. package/node_modules/yaml/browser/dist/nodes/Alias.js +116 -0
  221. package/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
  222. package/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
  223. package/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
  224. package/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
  225. package/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
  226. package/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
  227. package/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
  228. package/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
  229. package/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
  230. package/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
  231. package/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
  232. package/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
  233. package/node_modules/yaml/browser/dist/parse/cst.js +98 -0
  234. package/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
  235. package/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
  236. package/node_modules/yaml/browser/dist/parse/parser.js +975 -0
  237. package/node_modules/yaml/browser/dist/public-api.js +102 -0
  238. package/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
  239. package/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
  240. package/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
  241. package/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
  242. package/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
  243. package/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
  244. package/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
  245. package/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
  246. package/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
  247. package/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
  248. package/node_modules/yaml/browser/dist/schema/tags.js +96 -0
  249. package/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
  250. package/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
  251. package/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
  252. package/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
  253. package/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
  254. package/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
  255. package/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
  256. package/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
  257. package/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
  258. package/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
  259. package/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
  260. package/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
  261. package/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
  262. package/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
  263. package/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
  264. package/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
  265. package/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
  266. package/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
  267. package/node_modules/yaml/browser/dist/util.js +11 -0
  268. package/node_modules/yaml/browser/dist/visit.js +233 -0
  269. package/node_modules/yaml/browser/index.js +5 -0
  270. package/node_modules/yaml/browser/package.json +3 -0
  271. package/node_modules/yaml/dist/cli.d.ts +8 -0
  272. package/node_modules/yaml/dist/cli.mjs +201 -0
  273. package/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
  274. package/node_modules/yaml/dist/compose/compose-collection.js +90 -0
  275. package/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
  276. package/node_modules/yaml/dist/compose/compose-doc.js +45 -0
  277. package/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
  278. package/node_modules/yaml/dist/compose/compose-node.js +112 -0
  279. package/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
  280. package/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
  281. package/node_modules/yaml/dist/compose/composer.d.ts +63 -0
  282. package/node_modules/yaml/dist/compose/composer.js +224 -0
  283. package/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
  284. package/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
  285. package/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
  286. package/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
  287. package/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
  288. package/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
  289. package/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
  290. package/node_modules/yaml/dist/compose/resolve-end.js +39 -0
  291. package/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
  292. package/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
  293. package/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
  294. package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +227 -0
  295. package/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
  296. package/node_modules/yaml/dist/compose/resolve-props.js +148 -0
  297. package/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
  298. package/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
  299. package/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
  300. package/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
  301. package/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
  302. package/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
  303. package/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
  304. package/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
  305. package/node_modules/yaml/dist/doc/Document.d.ts +141 -0
  306. package/node_modules/yaml/dist/doc/Document.js +337 -0
  307. package/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
  308. package/node_modules/yaml/dist/doc/anchors.js +76 -0
  309. package/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
  310. package/node_modules/yaml/dist/doc/applyReviver.js +57 -0
  311. package/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
  312. package/node_modules/yaml/dist/doc/createNode.js +90 -0
  313. package/node_modules/yaml/dist/doc/directives.d.ts +49 -0
  314. package/node_modules/yaml/dist/doc/directives.js +178 -0
  315. package/node_modules/yaml/dist/errors.d.ts +21 -0
  316. package/node_modules/yaml/dist/errors.js +62 -0
  317. package/node_modules/yaml/dist/index.d.ts +25 -0
  318. package/node_modules/yaml/dist/index.js +50 -0
  319. package/node_modules/yaml/dist/log.d.ts +3 -0
  320. package/node_modules/yaml/dist/log.js +19 -0
  321. package/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
  322. package/node_modules/yaml/dist/nodes/Alias.js +118 -0
  323. package/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
  324. package/node_modules/yaml/dist/nodes/Collection.js +151 -0
  325. package/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
  326. package/node_modules/yaml/dist/nodes/Node.js +40 -0
  327. package/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
  328. package/node_modules/yaml/dist/nodes/Pair.js +39 -0
  329. package/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
  330. package/node_modules/yaml/dist/nodes/Scalar.js +27 -0
  331. package/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
  332. package/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
  333. package/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
  334. package/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
  335. package/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
  336. package/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
  337. package/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
  338. package/node_modules/yaml/dist/nodes/identity.js +53 -0
  339. package/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
  340. package/node_modules/yaml/dist/nodes/toJS.js +39 -0
  341. package/node_modules/yaml/dist/options.d.ts +350 -0
  342. package/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
  343. package/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
  344. package/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
  345. package/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
  346. package/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
  347. package/node_modules/yaml/dist/parse/cst-visit.js +99 -0
  348. package/node_modules/yaml/dist/parse/cst.d.ts +109 -0
  349. package/node_modules/yaml/dist/parse/cst.js +112 -0
  350. package/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
  351. package/node_modules/yaml/dist/parse/lexer.js +723 -0
  352. package/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
  353. package/node_modules/yaml/dist/parse/line-counter.js +41 -0
  354. package/node_modules/yaml/dist/parse/parser.d.ts +84 -0
  355. package/node_modules/yaml/dist/parse/parser.js +980 -0
  356. package/node_modules/yaml/dist/public-api.d.ts +44 -0
  357. package/node_modules/yaml/dist/public-api.js +107 -0
  358. package/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
  359. package/node_modules/yaml/dist/schema/Schema.js +39 -0
  360. package/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
  361. package/node_modules/yaml/dist/schema/common/map.js +19 -0
  362. package/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
  363. package/node_modules/yaml/dist/schema/common/null.js +17 -0
  364. package/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
  365. package/node_modules/yaml/dist/schema/common/seq.js +19 -0
  366. package/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
  367. package/node_modules/yaml/dist/schema/common/string.js +16 -0
  368. package/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
  369. package/node_modules/yaml/dist/schema/core/bool.js +21 -0
  370. package/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
  371. package/node_modules/yaml/dist/schema/core/float.js +47 -0
  372. package/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
  373. package/node_modules/yaml/dist/schema/core/int.js +42 -0
  374. package/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
  375. package/node_modules/yaml/dist/schema/core/schema.js +25 -0
  376. package/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
  377. package/node_modules/yaml/dist/schema/json/schema.js +64 -0
  378. package/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
  379. package/node_modules/yaml/dist/schema/tags.d.ts +48 -0
  380. package/node_modules/yaml/dist/schema/tags.js +99 -0
  381. package/node_modules/yaml/dist/schema/types.d.ts +92 -0
  382. package/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
  383. package/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
  384. package/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
  385. package/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
  386. package/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
  387. package/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
  388. package/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
  389. package/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
  390. package/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
  391. package/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
  392. package/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
  393. package/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
  394. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
  395. package/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
  396. package/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
  397. package/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
  398. package/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
  399. package/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
  400. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
  401. package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
  402. package/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
  403. package/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
  404. package/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
  405. package/node_modules/yaml/dist/stringify/stringify.js +132 -0
  406. package/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
  407. package/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
  408. package/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
  409. package/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
  410. package/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
  411. package/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
  412. package/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
  413. package/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
  414. package/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
  415. package/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
  416. package/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
  417. package/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
  418. package/node_modules/yaml/dist/test-events.d.ts +4 -0
  419. package/node_modules/yaml/dist/test-events.js +134 -0
  420. package/node_modules/yaml/dist/util.d.ts +16 -0
  421. package/node_modules/yaml/dist/util.js +28 -0
  422. package/node_modules/yaml/dist/visit.d.ts +102 -0
  423. package/node_modules/yaml/dist/visit.js +236 -0
  424. package/node_modules/yaml/package.json +97 -0
  425. package/node_modules/yaml/util.js +2 -0
  426. package/package.json +3 -3
  427. package/node_modules/@llblab/pi-actors/banner.jpg +0 -0
  428. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.d.ts +0 -16
  429. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.js +0 -57
  430. package/node_modules/@llblab/pi-actors/lib/inspector-actions.ts +0 -79
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Descendant Run launch-intent evidence.
3
+ * Owns: declared/prepared parent-child generation facts, strict persistence, and unresolved-scope mutation fences.
4
+ * Excludes: authenticating child birth/membership, work/control authority, exhaustive scope, and termination.
5
+ */
6
+
7
+ import { randomUUID } from "node:crypto";
8
+ import { lstatSync, readFileSync } from "node:fs";
9
+ import { isAbsolute, join, resolve } from "node:path";
10
+
11
+ import { writeJsonAtomic } from "./file-state.ts";
12
+ import { assertOwnedRunStateDirectory } from "./runs-ownership.ts";
13
+ import { readJsonFileResilient } from "./state-readers.ts";
14
+
15
+ export const RUN_DESCENDANT_LAUNCH_FILE = "descendant-launches.json";
16
+ export const RUN_DESCENDANT_PREPARATION_FILE = "descendant-preparation.json";
17
+ export const RUN_DESCENDANT_PREPARED_META_FILE = "prepared-run.json";
18
+ const SCHEMA = "run-descendant-launches-v1";
19
+ const PREPARATION_SCHEMA = "run-descendant-preparation-v1";
20
+
21
+ export interface RunDescendantLaunchOwner {
22
+ readonly run: string;
23
+ readonly runInstanceId: string;
24
+ readonly ownerId?: string;
25
+ readonly pid: number;
26
+ readonly processIdentityDigest?: string;
27
+ }
28
+
29
+ export interface RunDescendantLaunchRequest {
30
+ readonly run: string;
31
+ readonly runInstanceId: string;
32
+ readonly ownerId?: string;
33
+ readonly stateDir: string;
34
+ }
35
+
36
+ export interface RunDescendantLaunchTarget {
37
+ readonly run: string;
38
+ readonly run_instance_id: string;
39
+ readonly ownerId?: string;
40
+ readonly state_dir: string;
41
+ }
42
+
43
+ export interface RunDescendantPreparedFact {
44
+ readonly preparation_id: string;
45
+ readonly prepared_at: string;
46
+ }
47
+
48
+ /** Persisted reference to the original producer, never a reconstructed runtime capability or native membership proof. */
49
+ export interface RunDescendantProducerBinding {
50
+ readonly pid: number;
51
+ readonly process_identity_digest: string | null;
52
+ }
53
+
54
+ export interface RunDescendantPreparation extends RunDescendantPreparedFact {
55
+ readonly schema: typeof PREPARATION_SCHEMA;
56
+ readonly parent: Readonly<RunDescendantLaunchTarget>;
57
+ readonly child: Readonly<RunDescendantLaunchTarget>;
58
+ // Absent only in retained unbound metadata; new prepared facts require the original binding.
59
+ readonly parent_producer?: Readonly<RunDescendantProducerBinding>;
60
+ }
61
+
62
+ export interface RunDescendantLaunchIntent {
63
+ readonly intent_id: string;
64
+ readonly admitted_at: string;
65
+ readonly child: Readonly<RunDescendantLaunchTarget>;
66
+ readonly preparation?: Readonly<RunDescendantPreparedFact>;
67
+ }
68
+
69
+ export interface RunDescendantLaunchLedger {
70
+ readonly schema: typeof SCHEMA;
71
+ readonly run: string;
72
+ readonly run_instance_id: string;
73
+ readonly ownerId?: string;
74
+ readonly runner_pid: number;
75
+ readonly runner_identity_digest: string | null;
76
+ readonly intents: readonly Readonly<RunDescendantLaunchIntent>[];
77
+ }
78
+
79
+ export type RunDescendantLaunchReading =
80
+ | { state: "absent" | "invalid" }
81
+ | { state: "available"; ledger: Readonly<RunDescendantLaunchLedger> };
82
+
83
+ function record(value: unknown): value is Record<string, unknown> {
84
+ return value !== null && typeof value === "object" && !Array.isArray(value);
85
+ }
86
+
87
+ function onlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {
88
+ return Object.keys(value).every((key) => keys.includes(key));
89
+ }
90
+
91
+ function required(value: Record<string, unknown>, keys: readonly string[]): boolean {
92
+ return keys.every((key) => Object.hasOwn(value, key));
93
+ }
94
+
95
+ function text(value: unknown): value is string {
96
+ return typeof value === "string" && value.length > 0;
97
+ }
98
+
99
+ function optionalText(value: Record<string, unknown>, key: string): boolean {
100
+ return !(key in value) || (Object.hasOwn(value, key) && (value[key] === undefined || text(value[key])));
101
+ }
102
+
103
+ function validOwner(value: unknown): value is RunDescendantLaunchOwner {
104
+ if (!record(value) || !required(value, ["run", "runInstanceId", "pid"]) ||
105
+ !text(value.run) || !text(value.runInstanceId) || !Number.isSafeInteger(value.pid) || Number(value.pid) <= 0 ||
106
+ !optionalText(value, "ownerId")) return false;
107
+ return !("processIdentityDigest" in value) || (Object.hasOwn(value, "processIdentityDigest") &&
108
+ (value.processIdentityDigest === undefined || (typeof value.processIdentityDigest === "string" &&
109
+ /^[a-f0-9]{64}$/.exec(value.processIdentityDigest)?.[0] === value.processIdentityDigest)));
110
+ }
111
+
112
+ function intentId(value: unknown): value is string {
113
+ return typeof value === "string" &&
114
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.exec(value)?.[0] === value;
115
+ }
116
+
117
+ function timestamp(value: unknown): value is string {
118
+ if (!text(value)) return false;
119
+ try { return new Date(value).toISOString() === value; } catch { return false; }
120
+ }
121
+
122
+ function decodeReference(value: unknown): Readonly<RunDescendantLaunchTarget> | undefined {
123
+ if (!record(value) || !onlyKeys(value, ["run", "run_instance_id", "ownerId", "state_dir"]) ||
124
+ !required(value, ["run", "run_instance_id", "state_dir"]) || typeof value.run !== "string" ||
125
+ /^[A-Za-z0-9_.-]+$/.exec(value.run)?.[0] !== value.run || !text(value.run_instance_id) ||
126
+ !optionalText(value, "ownerId") || !text(value.state_dir) || !isAbsolute(value.state_dir) ||
127
+ resolve(value.state_dir) !== value.state_dir) return undefined;
128
+ // A normalized declaration is not filesystem identity, existence, or child ownership proof.
129
+ return Object.freeze({ run: value.run, run_instance_id: value.run_instance_id,
130
+ ...(value.ownerId === undefined ? {} : { ownerId: String(value.ownerId) }), state_dir: value.state_dir });
131
+ }
132
+
133
+ function decodeTarget(value: unknown, owner: RunDescendantLaunchOwner, stateDir: string): Readonly<RunDescendantLaunchTarget> | undefined {
134
+ const target = decodeReference(value);
135
+ return target && target.run_instance_id !== owner.runInstanceId && target.state_dir !== stateDir ? target : undefined;
136
+ }
137
+
138
+ function decodePreparedFact(value: unknown): Readonly<RunDescendantPreparedFact> | undefined {
139
+ if (!record(value) || !onlyKeys(value, ["preparation_id", "prepared_at"]) ||
140
+ !intentId(value.preparation_id) || !timestamp(value.prepared_at)) return undefined;
141
+ return Object.freeze({ preparation_id: value.preparation_id, prepared_at: value.prepared_at });
142
+ }
143
+
144
+ function decodeProducerBinding(value: unknown): Readonly<RunDescendantProducerBinding> | undefined {
145
+ if (!record(value) || !onlyKeys(value, ["pid", "process_identity_digest"]) ||
146
+ !required(value, ["pid", "process_identity_digest"]) || !Number.isSafeInteger(value.pid) || Number(value.pid) <= 0 ||
147
+ (value.process_identity_digest !== null && (typeof value.process_identity_digest !== "string" ||
148
+ /^[a-f0-9]{64}$/.exec(value.process_identity_digest)?.[0] !== value.process_identity_digest))) return undefined;
149
+ return Object.freeze({ pid: Number(value.pid), process_identity_digest: value.process_identity_digest as string | null });
150
+ }
151
+
152
+ function decodePreparation(value: unknown): Readonly<RunDescendantPreparation> | undefined {
153
+ if (!record(value) || !onlyKeys(value, ["schema", "preparation_id", "prepared_at", "parent", "child", "parent_producer"]) ||
154
+ value.schema !== PREPARATION_SCHEMA || !intentId(value.preparation_id) || !timestamp(value.prepared_at)) return undefined;
155
+ const parent = decodeReference(value.parent);
156
+ const child = decodeReference(value.child);
157
+ const producer = Object.hasOwn(value, "parent_producer") ? decodeProducerBinding(value.parent_producer) : undefined;
158
+ if (!parent || !child || parent.run_instance_id === child.run_instance_id || parent.state_dir === child.state_dir ||
159
+ ("parent_producer" in value && (!Object.hasOwn(value, "parent_producer") || !producer))) return undefined;
160
+ return Object.freeze({ schema: PREPARATION_SCHEMA, preparation_id: value.preparation_id, prepared_at: value.prepared_at, parent, child,
161
+ ...(producer ? { parent_producer: producer } : {}) });
162
+ }
163
+
164
+ function sameReference(a: RunDescendantLaunchTarget, b: RunDescendantLaunchTarget): boolean {
165
+ return a.run === b.run && a.run_instance_id === b.run_instance_id && a.ownerId === b.ownerId && a.state_dir === b.state_dir;
166
+ }
167
+
168
+ /** Validated reference data only; resolving a target never grants work or membership authority. */
169
+ export function resolveRunDescendantLaunchTarget(value: unknown, owner: RunDescendantLaunchOwner, stateDir: string): Readonly<RunDescendantLaunchTarget> | undefined {
170
+ if (!record(value) || !onlyKeys(value, ["run", "runInstanceId", "ownerId", "stateDir"]) ||
171
+ !required(value, ["run", "runInstanceId", "stateDir"]) || !optionalText(value, "ownerId")) return undefined;
172
+ return decodeTarget({ run: value.run, run_instance_id: value.runInstanceId,
173
+ ...(value.ownerId === undefined ? {} : { ownerId: value.ownerId }), state_dir: value.stateDir }, owner, stateDir);
174
+ }
175
+
176
+ function decode(value: unknown, owner: RunDescendantLaunchOwner, stateDir: string): Readonly<RunDescendantLaunchLedger> | undefined {
177
+ if (!record(value) || !onlyKeys(value, ["schema", "run", "run_instance_id", "ownerId", "runner_pid", "runner_identity_digest", "intents"]) ||
178
+ value.schema !== SCHEMA || value.run !== owner.run || value.run_instance_id !== owner.runInstanceId ||
179
+ value.ownerId !== owner.ownerId || value.runner_pid !== owner.pid ||
180
+ value.runner_identity_digest !== (owner.processIdentityDigest ?? null) || !Array.isArray(value.intents)) return undefined;
181
+ const ids = new Set<string>();
182
+ const generations = new Set<string>();
183
+ const preparations = new Set<string>();
184
+ const intents: Readonly<RunDescendantLaunchIntent>[] = [];
185
+ for (const item of value.intents) {
186
+ if (!record(item) || !onlyKeys(item, ["intent_id", "admitted_at", "child", "preparation"]) || !intentId(item.intent_id) ||
187
+ ids.has(item.intent_id) || !timestamp(item.admitted_at)) return undefined;
188
+ const child = decodeTarget(item.child, owner, stateDir);
189
+ const preparation = item.preparation === undefined ? undefined : decodePreparedFact(item.preparation);
190
+ if (!child || generations.has(child.run_instance_id) || (item.preparation !== undefined && !preparation) ||
191
+ (preparation && preparations.has(preparation.preparation_id))) return undefined;
192
+ ids.add(item.intent_id);
193
+ generations.add(child.run_instance_id);
194
+ if (preparation) preparations.add(preparation.preparation_id);
195
+ intents.push(Object.freeze({ intent_id: item.intent_id, admitted_at: item.admitted_at, child,
196
+ ...(preparation ? { preparation } : {}) }));
197
+ }
198
+ return Object.freeze({ schema: SCHEMA, run: owner.run, run_instance_id: owner.runInstanceId,
199
+ ...(owner.ownerId === undefined ? {} : { ownerId: owner.ownerId }), runner_pid: owner.pid,
200
+ runner_identity_digest: owner.processIdentityDigest ?? null, intents: Object.freeze(intents) });
201
+ }
202
+
203
+ /** Only ENOENT permits mutation; an empty or invalid journal is not closure proof. */
204
+ export function assertNoRetainedDescendantLaunchScope(stateDir: string): void {
205
+ assertNoRetainedDescendantFiles(stateDir, [RUN_DESCENDANT_LAUNCH_FILE, RUN_DESCENDANT_PREPARATION_FILE, RUN_DESCENDANT_PREPARED_META_FILE]);
206
+ }
207
+
208
+ function assertNoRetainedDescendantFiles(stateDir: string, files: readonly string[]): void {
209
+ for (const file of files) {
210
+ try { lstatSync(join(stateDir, file)); }
211
+ catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") continue; }
212
+ throw new Error("Run descendant launch scope is unproven; confirm the complete owned scope before replacing or retiring its state.");
213
+ }
214
+ }
215
+
216
+ /** Declared generations and paths confer no child work/control authority or exhaustive membership. */
217
+ export function readRunDescendantLaunchLedger(stateDir: string, owner: RunDescendantLaunchOwner): RunDescendantLaunchReading {
218
+ if (!validOwner(owner)) return { state: "invalid" };
219
+ let canonical: string;
220
+ try { canonical = assertOwnedRunStateDirectory(stateDir, owner.run); }
221
+ catch { return { state: "invalid" }; }
222
+ const path = join(canonical, RUN_DESCENDANT_LAUNCH_FILE);
223
+ try { if (!lstatSync(path).isFile()) return { state: "invalid" }; }
224
+ catch (error) { return { state: (error as NodeJS.ErrnoException).code === "ENOENT" ? "absent" : "invalid" }; }
225
+ const read = readJsonFileResilient<unknown>(path, undefined);
226
+ if (read.diagnostics.length) return { state: "invalid" };
227
+ const ledger = decode(read.value, owner, canonical);
228
+ return ledger ? { state: "available", ledger } : { state: "invalid" };
229
+ }
230
+
231
+ /** Retained preparation data is evidence, never a native-start or membership capability. */
232
+ export function readRunDescendantPreparation(
233
+ stateDir: string,
234
+ child: RunDescendantLaunchTarget,
235
+ parent: RunDescendantLaunchTarget,
236
+ ): Readonly<RunDescendantPreparation> | undefined {
237
+ try {
238
+ const canonical = assertOwnedRunStateDirectory(stateDir, child.run);
239
+ const path = join(canonical, RUN_DESCENDANT_PREPARATION_FILE);
240
+ if (!lstatSync(path).isFile()) return undefined;
241
+ const value = decodePreparation(JSON.parse(readFileSync(path, "utf8")));
242
+ return value && child.state_dir === canonical && sameReference(value.child, child) && sameReference(value.parent, parent) ? value : undefined;
243
+ } catch { return undefined; }
244
+ }
245
+
246
+ /** Fresh evidence checks only, not a capability reconstructed from staged metadata. */
247
+ export function assertRunDescendantPreparedMetadata(stateDir: string, child: RunDescendantLaunchTarget): void {
248
+ const canonical = assertOwnedRunStateDirectory(stateDir, child.run);
249
+ let unpublished = false;
250
+ try { lstatSync(join(canonical, "run.json")); }
251
+ catch (error) { unpublished = (error as NodeJS.ErrnoException).code === "ENOENT"; }
252
+ if (!unpublished) throw new Error("Run descendant preparation is published or unavailable.");
253
+ const path = join(canonical, RUN_DESCENDANT_PREPARED_META_FILE);
254
+ if (!lstatSync(path).isFile()) throw new Error("Run descendant prepared metadata is unavailable or invalid.");
255
+ const meta: unknown = JSON.parse(readFileSync(path, "utf8"));
256
+ if (!record(meta) || meta.run !== child.run || meta.run_instance_id !== child.run_instance_id ||
257
+ meta.ownerId !== child.ownerId || meta.state_dir !== canonical || child.state_dir !== canonical ||
258
+ meta.pid !== 0 || meta.process_identity !== undefined) {
259
+ throw new Error("Run descendant prepared metadata is unavailable or invalid.");
260
+ }
261
+ }
262
+
263
+ /** Storage only: the kernel prepare-only branch owns child creation and holds parent then child lifecycle locks. */
264
+ export function recordRunDescendantPreparationUnderLock(
265
+ stateDir: string,
266
+ child: RunDescendantLaunchTarget,
267
+ parent: RunDescendantLaunchTarget,
268
+ producer: RunDescendantLaunchOwner,
269
+ ): Readonly<RunDescendantPreparation> {
270
+ const parentReference = decodeReference(parent);
271
+ if (!validOwner(producer) || !parentReference || parentReference.run !== producer.run ||
272
+ parentReference.run_instance_id !== producer.runInstanceId || parentReference.ownerId !== producer.ownerId) {
273
+ throw new Error("Run descendant preparation producer binding is invalid.");
274
+ }
275
+ const canonical = assertOwnedRunStateDirectory(stateDir, child.run);
276
+ assertNoRetainedDescendantFiles(canonical, [RUN_DESCENDANT_LAUNCH_FILE, RUN_DESCENDANT_PREPARATION_FILE]);
277
+ assertRunDescendantPreparedMetadata(canonical, child);
278
+ const preparation = decodePreparation({ schema: PREPARATION_SCHEMA, preparation_id: randomUUID(),
279
+ prepared_at: new Date().toISOString(), child, parent: parentReference,
280
+ parent_producer: { pid: producer.pid, process_identity_digest: producer.processIdentityDigest ?? null } });
281
+ if (!preparation || preparation.child.state_dir !== canonical) throw new Error("Run descendant preparation binding is invalid.");
282
+ writeJsonAtomic(join(canonical, RUN_DESCENDANT_PREPARATION_FILE), preparation);
283
+ return preparation;
284
+ }
285
+
286
+ /** Storage only: bare intents require work admission; prepared facts may use evidence admission. Validate child evidence under its lock. */
287
+ export function recordRunDescendantLaunchIntentUnderLock(
288
+ stateDir: string,
289
+ owner: RunDescendantLaunchOwner,
290
+ request: RunDescendantLaunchRequest,
291
+ preparation?: RunDescendantPreparation,
292
+ ): Readonly<RunDescendantLaunchIntent> {
293
+ if (!validOwner(owner)) throw new Error("Run descendant launch identity or request is invalid.");
294
+ const canonical = assertOwnedRunStateDirectory(stateDir, owner.run);
295
+ const child = resolveRunDescendantLaunchTarget(request, owner, canonical);
296
+ if (!child) throw new Error("Run descendant launch identity or request is invalid.");
297
+ const current = readRunDescendantLaunchLedger(canonical, owner);
298
+ if (current.state === "invalid") throw new Error("Run descendant launch evidence is unavailable or invalid.");
299
+ const prior = current.state === "available" ? current.ledger.intents : [];
300
+ const index = prior.findIndex((item) => item.child.run_instance_id === child.run_instance_id);
301
+ const existing = prior[index];
302
+ if (existing && preparation === undefined) throw new Error("Run descendant launch generation is already retained.");
303
+ if (existing && !sameReference(existing.child, child)) throw new Error("Run descendant preparation target changed.");
304
+ let prepared: Readonly<RunDescendantPreparedFact> | undefined;
305
+ if (preparation !== undefined) {
306
+ const parent = { run: owner.run, run_instance_id: owner.runInstanceId,
307
+ ...(owner.ownerId === undefined ? {} : { ownerId: owner.ownerId }), state_dir: canonical };
308
+ const claimed = decodePreparation(preparation);
309
+ if (!claimed || !sameReference(claimed.parent, parent) || !sameReference(claimed.child, child)) {
310
+ throw new Error("Run descendant preparation binding changed or is unavailable.");
311
+ }
312
+ if (existing?.preparation && (existing.preparation.preparation_id !== claimed.preparation_id ||
313
+ existing.preparation.prepared_at !== claimed.prepared_at)) {
314
+ throw new Error("Run descendant preparation binding changed or is unavailable.");
315
+ }
316
+ const retained = readRunDescendantPreparation(child.state_dir, child, parent);
317
+ if (!retained || JSON.stringify(claimed) !== JSON.stringify(retained)) {
318
+ throw new Error("Run descendant preparation binding changed or is unavailable.");
319
+ }
320
+ assertRunDescendantPreparedMetadata(child.state_dir, child);
321
+ if (existing?.preparation) return existing;
322
+ if (!retained.parent_producer || retained.parent_producer.pid !== owner.pid ||
323
+ retained.parent_producer.process_identity_digest !== (owner.processIdentityDigest ?? null)) {
324
+ throw new Error("Run descendant preparation producer binding changed or is unavailable.");
325
+ }
326
+ prepared = Object.freeze({ preparation_id: retained.preparation_id, prepared_at: retained.prepared_at });
327
+ }
328
+ const intent = existing ? Object.freeze({ ...existing, preparation: prepared! })
329
+ : Object.freeze({ intent_id: randomUUID(), admitted_at: new Date().toISOString(), child,
330
+ ...(prepared ? { preparation: prepared } : {}) });
331
+ const intents = existing ? prior.map((item, i) => i === index ? intent : item) : [...prior, intent];
332
+ const updated = decode({ schema: SCHEMA, run: owner.run, run_instance_id: owner.runInstanceId,
333
+ ...(owner.ownerId === undefined ? {} : { ownerId: owner.ownerId }), runner_pid: owner.pid,
334
+ runner_identity_digest: owner.processIdentityDigest ?? null, intents }, owner, canonical);
335
+ if (!updated) throw new Error("Run descendant launch evidence is unavailable or invalid.");
336
+ writeJsonAtomic(join(canonical, RUN_DESCENDANT_LAUNCH_FILE), updated);
337
+ return updated.intents[existing ? index : updated.intents.length - 1]!;
338
+ }
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Owned-generation execution evidence and explicit kernel source selection.
3
+ * Owns: data-only manifest projection, recorded capture/session reference admission and checked canonical runner stream input.
4
+ * Excludes: raw-body exposure permission, session discovery, primary-source completeness, producer/work authority and native closure.
5
+ */
6
+ import { lstatSync, type BigIntStats } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { observeExecutionFileReference, readExecutionRunnerStreamText } from "./execution-files.ts";
9
+ import { createRunRecipeEvidenceRedactor } from "./recipe-projection.ts";
10
+ import { readRunContextIdentity, RUN_CONTEXT_SOURCE_METADATA_MAX_BYTES, type RunContextIndexIdentity } from "./runs-context-index.ts";
11
+ import { readJsonFileResilient } from "./state-readers.ts";
12
+
13
+ // --- Manifest projection ---
14
+
15
+ export interface ExecutionCaptureView {
16
+ readonly reported_saved_bytes: number | null;
17
+ readonly persistence: "incomplete" | "reported_complete" | "unproven";
18
+ readonly reported_observed_bytes?: number;
19
+ readonly error?: "capture_write_failed";
20
+ }
21
+ export interface ExecutionAttemptView {
22
+ readonly attempt: number;
23
+ readonly code: number;
24
+ readonly native_exit_code?: number | null;
25
+ readonly native_signal?: string;
26
+ readonly reported_killed?: boolean;
27
+ readonly stdout: Readonly<ExecutionCaptureView>;
28
+ readonly stderr: Readonly<ExecutionCaptureView>;
29
+ }
30
+ export interface ExecutionCommandView {
31
+ readonly id: string;
32
+ readonly reported_status: string;
33
+ readonly attempts: readonly Readonly<ExecutionAttemptView>[];
34
+ readonly stage?: string;
35
+ readonly command?: string;
36
+ readonly label?: string;
37
+ readonly occurrence?: number;
38
+ readonly branch_index?: number;
39
+ readonly prompt_bytes?: number;
40
+ readonly started_at?: string;
41
+ readonly completed_at?: string;
42
+ readonly semantic_acceptance?: string;
43
+ readonly exit_code?: number;
44
+ readonly effective_exit_code?: number;
45
+ readonly native_exit_code?: number | null;
46
+ readonly reported_killed?: boolean;
47
+ readonly interruption?: string;
48
+ readonly reported_session_file_count?: number;
49
+ }
50
+ export interface RunExecutionView {
51
+ readonly reported_status: string;
52
+ readonly updated_at: string;
53
+ readonly reported_active_subagents: number;
54
+ readonly commands_total: number;
55
+ readonly settled_attempts_reported: number;
56
+ readonly commands: readonly Readonly<ExecutionCommandView>[];
57
+ }
58
+ export type RunExecutionProjection = { readonly state: "available"; readonly view: Readonly<RunExecutionView> }
59
+ | { readonly state: "unavailable"; readonly reason: "manifest_invalid" | "identity_mismatch" };
60
+
61
+ function manifestField(value: Record<string, unknown>, key: string): unknown { return Object.hasOwn(value, key) ? value[key] : undefined; }
62
+ function count(value: unknown): value is number { return typeof value === "number" && Number.isSafeInteger(value) && value >= 0; }
63
+ function code(value: unknown): value is number { return typeof value === "number" && Number.isSafeInteger(value); }
64
+ function timestamp(value: unknown): value is string {
65
+ const time = typeof value === "string" ? Date.parse(value) : NaN;
66
+ return Number.isSafeInteger(time) && new Date(time).toISOString() === value;
67
+ }
68
+ function capture(value: unknown): Readonly<ExecutionCaptureView> | undefined {
69
+ const source = record(value);
70
+ if (!source) return undefined;
71
+ const saved = manifestField(source, "bytes");
72
+ const observed = manifestField(source, "bytes_observed");
73
+ const complete = manifestField(source, "complete");
74
+ const error = manifestField(source, "error");
75
+ if ((saved !== null && !count(saved)) || (observed !== undefined && !count(observed)) ||
76
+ (complete !== undefined && typeof complete !== "boolean") || (error !== undefined && error !== "capture_write_failed") ||
77
+ (typeof saved === "number" && typeof observed === "number" && saved > observed) || (error !== undefined && complete !== false)) return undefined;
78
+ return Object.freeze({ reported_saved_bytes: saved,
79
+ persistence: complete === false ? "incomplete" : saved === null ? "unproven" : "reported_complete",
80
+ ...(typeof observed === "number" ? { reported_observed_bytes: observed } : {}), ...(error ? { error } : {}) });
81
+ }
82
+ function attempt(value: unknown, ordinal: number): Readonly<ExecutionAttemptView> | undefined {
83
+ const source = record(value);
84
+ if (!source || manifestField(source, "attempt") !== ordinal || !code(manifestField(source, "code"))) return undefined;
85
+ const nativeCode = manifestField(source, "native_exit_code");
86
+ const signal = manifestField(source, "native_signal");
87
+ const killed = manifestField(source, "killed");
88
+ if ((nativeCode !== undefined && nativeCode !== null && !code(nativeCode)) ||
89
+ (signal !== undefined && (typeof signal !== "string" || !/^SIG[A-Z0-9]{1,31}$/u.test(signal))) ||
90
+ (killed !== undefined && typeof killed !== "boolean")) return undefined;
91
+ const stdout = capture(manifestField(source, "stdout"));
92
+ const stderr = capture(manifestField(source, "stderr"));
93
+ if (!stdout || !stderr) return undefined;
94
+ return Object.freeze({ attempt: ordinal, code: source.code as number, stdout, stderr,
95
+ ...(nativeCode !== undefined ? { native_exit_code: nativeCode as number | null } : {}),
96
+ ...(typeof signal === "string" ? { native_signal: signal } : {}),
97
+ ...(typeof killed === "boolean" ? { reported_killed: killed } : {}) });
98
+ }
99
+
100
+ /** Already-captured metadata is data, never a reconstructed producer/work/close capability. */
101
+ export function projectRunExecutionManifest(
102
+ expected: { readonly run: string; readonly run_instance_id: string },
103
+ value: unknown,
104
+ recipe: Record<string, unknown> = {},
105
+ redactEvidence?: (value: unknown) => unknown,
106
+ ): Readonly<RunExecutionProjection> {
107
+ const invalid = (): Readonly<RunExecutionProjection> => Object.freeze({ state: "unavailable", reason: "manifest_invalid" });
108
+ const identity = record(expected);
109
+ const source = record(value);
110
+ if (!identity || typeof manifestField(identity, "run") !== "string" || !identity.run ||
111
+ typeof manifestField(identity, "run_instance_id") !== "string" || !identity.run_instance_id || !source || manifestField(source, "version") !== 1) return invalid();
112
+ if (manifestField(source, "run") !== expected.run || manifestField(source, "run_instance_id") !== expected.run_instance_id) {
113
+ return Object.freeze({ state: "unavailable", reason: "identity_mismatch" });
114
+ }
115
+ const status = manifestField(source, "status");
116
+ const updated = manifestField(source, "updated_at");
117
+ const active = manifestField(source, "active_subagents");
118
+ const records = manifestField(source, "commands");
119
+ if (typeof status !== "string" || !["running", "stopping", "done", "failed"].includes(status) || !timestamp(updated) ||
120
+ !count(active) || !Array.isArray(records)) return invalid();
121
+ const redact = redactEvidence ?? createRunRecipeEvidenceRedactor(recipe);
122
+ const commands: Readonly<ExecutionCommandView>[] = [];
123
+ const ids = new Set<string>();
124
+ let attemptsReported = 0;
125
+ for (const value of records) {
126
+ const command = record(value);
127
+ if (!command) return invalid();
128
+ const id = manifestField(command, "id");
129
+ const state = manifestField(command, "status");
130
+ const rows = manifestField(command, "attempts");
131
+ if (typeof id !== "string" || !/^command-[0-9]{3,}$/u.test(id) || !count(Number(id.slice(8))) || Number(id.slice(8)) === 0 || ids.has(id) ||
132
+ typeof state !== "string" || !["running", "done", "failed", "interrupted"].includes(state) || !Array.isArray(rows)) return invalid();
133
+ ids.add(id);
134
+ const attempts: Readonly<ExecutionAttemptView>[] = [];
135
+ for (const [index, row] of rows.entries()) { const item = attempt(row, index + 1); if (!item) return invalid(); attempts.push(item); }
136
+ const details: Record<string, unknown> = {};
137
+ for (const key of ["stage", "command", "label"]) {
138
+ const item = manifestField(command, key);
139
+ if (item !== undefined) { if (typeof item !== "string") return invalid(); details[key] = redact(item); }
140
+ }
141
+ for (const key of ["occurrence", "branch_index", "prompt_bytes"]) {
142
+ const item = manifestField(command, key);
143
+ if (item !== undefined) { if (!count(item) || (key === "occurrence" && item === 0)) return invalid(); details[key] = item; }
144
+ }
145
+ for (const key of ["started_at", "completed_at"]) {
146
+ const item = manifestField(command, key);
147
+ if (item !== undefined) { if (!timestamp(item)) return invalid(); details[key] = item; }
148
+ }
149
+ for (const key of ["exit_code", "effective_exit_code", "native_exit_code"]) {
150
+ const item = manifestField(command, key);
151
+ if (item !== undefined) { if (!(key === "native_exit_code" && item === null) && !code(item)) return invalid(); details[key] = item; }
152
+ }
153
+ const semantic = manifestField(command, "semantic_acceptance");
154
+ if (semantic !== undefined) {
155
+ if (typeof semantic !== "string" || !["pending", "accepted", "rejected", "not_required", "unavailable"].includes(semantic)) return invalid();
156
+ details.semantic_acceptance = semantic;
157
+ }
158
+ const killed = manifestField(command, "killed");
159
+ if (killed !== undefined) { if (typeof killed !== "boolean") return invalid(); details.reported_killed = killed; }
160
+ const sessions = manifestField(command, "session_files");
161
+ if (sessions !== undefined) {
162
+ if (!Array.isArray(sessions) || sessions.some(file => typeof file !== "string")) return invalid();
163
+ details.reported_session_file_count = sessions.length;
164
+ }
165
+ const interruption = record(manifestField(command, "interruption"));
166
+ const message = interruption ? manifestField(interruption, "message") : undefined;
167
+ if (typeof message === "string") details.interruption = redact(message);
168
+ commands.push(Object.freeze({ id, reported_status: state, attempts: Object.freeze(attempts), ...details }));
169
+ attemptsReported += attempts.length;
170
+ }
171
+ return Object.freeze({ state: "available", view: Object.freeze({ reported_status: status, updated_at: updated,
172
+ reported_active_subagents: active, commands_total: commands.length, settled_attempts_reported: attemptsReported,
173
+ commands: Object.freeze(commands) }) });
174
+ }
175
+
176
+ // --- Canonical kernel stream input ---
177
+
178
+ export type KernelRunStreamSourceReading =
179
+ | { readonly state: "available"; readonly identity: Readonly<RunContextIndexIdentity>; readonly stream: "stdout" | "stderr";
180
+ readonly source_scope: "canonical_runner_stream"; readonly visibility: "kernel_only"; readonly capture_completeness: "not_asserted";
181
+ readonly bytes_total: number; readonly text: string; readonly unchanged: () => boolean }
182
+ | { readonly state: "unavailable"; readonly reason: "stream_invalid" | "identity_unavailable" | "identity_mismatch" | "observation_changed" |
183
+ "stream_missing" | "stream_unavailable" | "stream_too_large" | "stream_invalid_text" };
184
+ type StreamUnavailable = Extract<KernelRunStreamSourceReading, { state: "unavailable" }>;
185
+ function streamUnavailable(reason: StreamUnavailable["reason"]): Readonly<StreamUnavailable> { return Object.freeze({ state: "unavailable", reason }); }
186
+
187
+ /** Never serialize this raw source as tool/model evidence: an export owner still owes a fixed privacy projection. */
188
+ export function readRunStreamSource(stateDir: string, expected: unknown, stream: unknown): Readonly<KernelRunStreamSourceReading> {
189
+ if (stream !== "stdout" && stream !== "stderr") return streamUnavailable("stream_invalid");
190
+ const owner = readRunContextIdentity(stateDir, expected);
191
+ if (owner.state === "unavailable") return owner;
192
+ const source = readExecutionRunnerStreamText(owner.local_path, stream);
193
+ if (!owner.unchanged()) return streamUnavailable("observation_changed");
194
+ if (source.availability === "unavailable") return streamUnavailable(source.reason === "reference_changed" ? "observation_changed"
195
+ : source.reason === "reference_missing" ? "stream_missing" : source.reason === "reference_too_large" ? "stream_too_large"
196
+ : source.reason === "reference_invalid_text" ? "stream_invalid_text" : "stream_unavailable");
197
+ const { reference, text } = source;
198
+ const unchanged = (): boolean => owner.unchanged() && reference.unchanged();
199
+ if (!unchanged()) return streamUnavailable("observation_changed");
200
+ return Object.freeze({ state: "available", identity: owner.identity, stream, source_scope: "canonical_runner_stream",
201
+ visibility: "kernel_only", capture_completeness: "not_asserted", bytes_total: reference.bytes_total, text, unchanged });
202
+ }
203
+
204
+ // --- Recorded reference admission ---
205
+
206
+ export type RunExecutionReferenceRequest =
207
+ | { readonly kind: "capture"; readonly command_id: string; readonly attempt: number; readonly stream: "stdout" | "stderr" }
208
+ | { readonly kind: "session"; readonly command_id: string; readonly path: string };
209
+ interface ExecutionReferenceMetadata {
210
+ readonly command_id: string;
211
+ readonly path: string;
212
+ readonly local_path: string;
213
+ readonly bytes_total: number;
214
+ readonly mutable: true;
215
+ }
216
+ export type RunExecutionReference = ExecutionReferenceMetadata & (
217
+ | { readonly kind: "capture"; readonly attempt: number; readonly stream: "stdout" | "stderr"; readonly capture: Readonly<ExecutionCaptureView> }
218
+ | { readonly kind: "session" }
219
+ );
220
+ export type RunExecutionReferenceReading =
221
+ | { readonly state: "available"; readonly identity: Readonly<RunContextIndexIdentity>;
222
+ readonly source_updated_at: string; readonly reference: Readonly<RunExecutionReference>; readonly unchanged: () => boolean }
223
+ | { readonly state: "unavailable"; readonly reason: "request_invalid" | "identity_unavailable" | "identity_mismatch" |
224
+ "observation_changed" | "manifest_absent" | "manifest_unavailable" | "manifest_invalid" | "manifest_identity_mismatch" |
225
+ "reference_not_recorded" | "reference_invalid" | "reference_missing" | "reference_unavailable" | "reference_changed" |
226
+ "reference_size_unrepresentable" | "capture_size_mismatch" };
227
+ type Unavailable = Extract<RunExecutionReferenceReading, { state: "unavailable" }>;
228
+ function unavailable(reason: Unavailable["reason"]): Readonly<Unavailable> { return Object.freeze({ state: "unavailable", reason }); }
229
+ function record(value: unknown): Record<string, unknown> | undefined {
230
+ return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
231
+ }
232
+ function own(value: Record<string, unknown>, key: string): unknown { return Object.getOwnPropertyDescriptor(value, key)?.value; }
233
+ function request(value: unknown): Readonly<RunExecutionReferenceRequest> | undefined {
234
+ const source = record(value);
235
+ if (!source) return undefined;
236
+ const kind = own(source, "kind");
237
+ const command = own(source, "command_id");
238
+ if (typeof command !== "string" || !/^command-[0-9]{3,}$/u.test(command) || !Number.isSafeInteger(Number(command.slice(8))) || Number(command.slice(8)) < 1) return undefined;
239
+ if (kind === "capture") {
240
+ const attempt = own(source, "attempt"); const stream = own(source, "stream");
241
+ return typeof attempt === "number" && Number.isSafeInteger(attempt) && attempt > 0 && (stream === "stdout" || stream === "stderr") &&
242
+ Object.keys(source).every(key => ["kind", "command_id", "attempt", "stream"].includes(key))
243
+ ? Object.freeze({ kind, command_id: command, attempt, stream }) : undefined;
244
+ }
245
+ const path = own(source, "path");
246
+ return kind === "session" && typeof path === "string" && path.length > 0 && Object.keys(source).every(key => ["kind", "command_id", "path"].includes(key))
247
+ ? Object.freeze({ kind, command_id: command, path }) : undefined;
248
+ }
249
+ function sameFile(left: BigIntStats, right: BigIntStats): boolean {
250
+ return right.isFile() && left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
251
+ }
252
+
253
+ /** Local paths and unchanged callbacks describe data only, never readable-body exposure or native capabilities. */
254
+ export function readRunExecutionReference(stateDir: string, expected: unknown, query: unknown): Readonly<RunExecutionReferenceReading> {
255
+ const selected = request(query);
256
+ if (!selected) return unavailable("request_invalid");
257
+ const owner = readRunContextIdentity(stateDir, expected);
258
+ if (owner.state === "unavailable") return unavailable(owner.reason);
259
+ const sourcePath = join(owner.local_path, "execution.json");
260
+ try {
261
+ let before: BigIntStats;
262
+ try { before = lstatSync(sourcePath, { bigint: true }); }
263
+ catch (error) { return unavailable((error as NodeJS.ErrnoException).code === "ENOENT" ? "manifest_absent" : "manifest_unavailable"); }
264
+ if (!before.isFile() || before.size > BigInt(RUN_CONTEXT_SOURCE_METADATA_MAX_BYTES)) return unavailable("manifest_unavailable");
265
+ const captured = readJsonFileResilient<unknown>(sourcePath, undefined, { maxBytes: RUN_CONTEXT_SOURCE_METADATA_MAX_BYTES, strictUtf8: true });
266
+ const sourceUnchanged = (): boolean => {
267
+ try { return owner.unchanged() && sameFile(before, lstatSync(sourcePath, { bigint: true })); } catch { return false; }
268
+ };
269
+ if (!sourceUnchanged()) return unavailable("observation_changed");
270
+ if (captured.diagnostics.length) return unavailable("manifest_invalid");
271
+ const projected = projectRunExecutionManifest(owner.identity, captured.value);
272
+ if (projected.state === "unavailable") return unavailable(projected.reason === "identity_mismatch" ? "manifest_identity_mismatch" : "manifest_invalid");
273
+ const index = projected.view.commands.findIndex(command => command.id === selected.command_id);
274
+ if (index < 0) return unavailable("reference_not_recorded");
275
+ const command = (record(captured.value)!.commands as Record<string, unknown>[])[index];
276
+ const view = projected.view.commands[index];
277
+ let relative: string;
278
+ let capture: Readonly<ExecutionCaptureView> | undefined;
279
+ if (selected.kind === "capture") {
280
+ const attempt = (command.attempts as Record<string, unknown>[])[selected.attempt - 1];
281
+ const reported = record(attempt?.[selected.stream]);
282
+ if (!reported || !Object.hasOwn(reported, "path")) return unavailable("reference_not_recorded");
283
+ relative = `captures/${selected.command_id}/attempt-${String(selected.attempt).padStart(3, "0")}/${selected.stream}.log`;
284
+ if (reported.path !== relative) return unavailable("reference_invalid");
285
+ capture = view.attempts[selected.attempt - 1][selected.stream];
286
+ } else {
287
+ if (!Array.isArray(command.session_files) || !command.session_files.includes(selected.path)) return unavailable("reference_not_recorded");
288
+ relative = selected.path;
289
+ }
290
+ const observed = observeExecutionFileReference(owner.local_path, { kind: selected.kind, path: relative });
291
+ if (!sourceUnchanged()) return unavailable("observation_changed");
292
+ if (observed.availability === "unavailable") return unavailable(observed.reason === "invalid_reference" ? "reference_invalid" : observed.reason);
293
+ if (!observed.unchanged()) return unavailable("reference_changed");
294
+ if (capture && capture.reported_saved_bytes !== null && capture.reported_saved_bytes !== observed.bytes_total) return unavailable("capture_size_mismatch");
295
+ const base = { command_id: selected.command_id, path: observed.path, local_path: observed.local_path, bytes_total: observed.bytes_total, mutable: true as const };
296
+ const reference: Readonly<RunExecutionReference> = selected.kind === "capture"
297
+ ? Object.freeze({ ...base, kind: "capture", attempt: selected.attempt, stream: selected.stream, capture: capture! })
298
+ : Object.freeze({ ...base, kind: "session" });
299
+ return Object.freeze({ state: "available", identity: owner.identity, source_updated_at: projected.view.updated_at,
300
+ reference, unchanged: () => sourceUnchanged() && observed.unchanged() });
301
+ } catch { return unavailable("manifest_unavailable"); }
302
+ }