@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
@@ -5,15 +5,18 @@
5
5
  */
6
6
  import { readFileSync, statSync } from "node:fs";
7
7
  import * as path from "node:path";
8
- import { matchesKey, sliceByColumn, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
8
+ import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
9
+ import { Document, isScalar, visit } from "yaml";
10
+ import { matchesKey, Markdown, sliceByColumn, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
9
11
  import * as ActorInspector from "./inspector.js";
10
12
  import * as ControlProjection from "./control-projection.js";
11
13
  import * as RunsControls from "./runs-controls.js";
12
14
  import * as RunControlDelivery from "./runs-control-delivery.js";
13
15
  import * as RunsTrace from "./runs-trace.js";
14
16
  import * as Limits from "./limits.js";
15
- import { computeRunControlCapacity } from "./run-evidence-policy.js";
17
+ import { computeRunControlCapacity, runControlStatusTimestamp } from "./run-evidence-policy.js";
16
18
  import * as RuntimeTriage from "./runtime-triage.js";
19
+ import { normalizeRecipeControl } from "./recipe-control.js";
17
20
  import * as TraceProjection from "./trace-projection.js";
18
21
  const TABS = ["recipe", "trace", "control"];
19
22
  const TRACE_SOURCES = [
@@ -40,12 +43,20 @@ export class ActorInspectorOverlay {
40
43
  documentScroll = 0;
41
44
  detailScroll = 0;
42
45
  feedback;
46
+ feedbackFromAction = false;
47
+ feedbackScroll = 0;
48
+ feedbackPageRows = 1;
49
+ inspectorFrame;
43
50
  focus = "runs";
44
51
  killConfirmation;
45
52
  killDialogChoice = "cancel";
53
+ killDialogScroll = 0;
54
+ killDialogPageRows = 1;
46
55
  rowIndex = 0;
47
56
  runCache;
48
57
  selectedTraceId;
58
+ controlCache;
59
+ controlSelection;
49
60
  runIndex = 0;
50
61
  selectorIndex = 0;
51
62
  selectorMode;
@@ -74,10 +85,9 @@ export class ActorInspectorOverlay {
74
85
  invalidate() {
75
86
  this.runCache = undefined;
76
87
  this.traceCache = undefined;
88
+ this.controlCache = undefined;
77
89
  }
78
90
  handleInput(data) {
79
- const runs = this.runs();
80
- this.runIndex = Math.min(this.runIndex, Math.max(0, runs.length - 1));
81
91
  if (matchesKey(data, "ctrl+c")) {
82
92
  this.done();
83
93
  return;
@@ -87,11 +97,35 @@ export class ActorInspectorOverlay {
87
97
  this.tui.requestRender();
88
98
  return;
89
99
  }
100
+ if (this.feedback) {
101
+ if (matchesKey(data, "escape")) {
102
+ this.feedback = undefined;
103
+ this.feedbackFromAction = false;
104
+ this.feedbackScroll = 0;
105
+ }
106
+ else if (matchesKey(data, "up"))
107
+ this.feedbackScroll = Math.max(0, this.feedbackScroll - 1);
108
+ else if (matchesKey(data, "down"))
109
+ this.feedbackScroll++;
110
+ else if (matchesKey(data, "pageUp"))
111
+ this.feedbackScroll = Math.max(0, this.feedbackScroll - this.feedbackPageRows);
112
+ else if (matchesKey(data, "pageDown"))
113
+ this.feedbackScroll += this.feedbackPageRows;
114
+ this.tui.requestRender();
115
+ return;
116
+ }
117
+ const runs = this.runs();
118
+ this.runIndex = Math.min(this.runIndex, Math.max(0, runs.length - 1));
90
119
  if (data.toLowerCase() === "k") {
91
120
  this.requestKill(runs[this.runIndex]);
92
121
  this.tui.requestRender();
93
122
  return;
94
123
  }
124
+ if (this.tab === "control" && (this.focus === "list" || this.focus === "detail")) {
125
+ this.handleControlInput(data, runs[this.runIndex]);
126
+ this.tui.requestRender();
127
+ return;
128
+ }
95
129
  if (matchesKey(data, "escape")) {
96
130
  if (this.focus === "select") {
97
131
  this.selectorMode = undefined;
@@ -125,7 +159,9 @@ export class ActorInspectorOverlay {
125
159
  return;
126
160
  }
127
161
  if (this.focus === "document") {
128
- if (matchesKey(data, "left"))
162
+ if (this.tab === "control" && matchesKey(data, "return"))
163
+ this.openControlList(runs[this.runIndex]);
164
+ else if (matchesKey(data, "left"))
129
165
  this.focus = "tabs";
130
166
  else if (matchesKey(data, "up") && this.documentScroll === 0)
131
167
  this.focus = "tabs";
@@ -167,6 +203,8 @@ export class ActorInspectorOverlay {
167
203
  else if (matchesKey(data, "return")) {
168
204
  if (this.tab === "trace")
169
205
  this.openSourceSelector(runs[this.runIndex]);
206
+ else if (this.tab === "control")
207
+ this.openControlList(runs[this.runIndex]);
170
208
  else
171
209
  this.focus = "document";
172
210
  }
@@ -213,29 +251,28 @@ export class ActorInspectorOverlay {
213
251
  }
214
252
  render(width) {
215
253
  const safeWidth = Math.max(24, width);
254
+ const modal = !!(this.killConfirmation || this.feedback);
255
+ if (!modal || !this.inspectorFrame)
256
+ this.inspectorFrame = { width: safeWidth, lines: this.renderInspector(safeWidth) };
257
+ const lines = this.modalUnderlay(safeWidth);
258
+ if (this.killConfirmation)
259
+ this.compositePopup(lines, this.renderKillDialog(safeWidth - 2, lines.length), safeWidth);
260
+ else if (this.feedback)
261
+ this.compositePopup(lines, this.renderFeedbackPopup(safeWidth, lines.length), safeWidth);
262
+ return lines;
263
+ }
264
+ renderInspector(safeWidth) {
216
265
  const innerWidth = safeWidth - 2;
217
266
  const runs = this.runs();
218
267
  this.runIndex = Math.min(this.runIndex, Math.max(0, runs.length - 1));
219
268
  const run = runs[this.runIndex];
220
- if (this.killConfirmation)
221
- return this.renderKillDialog(innerWidth);
222
269
  const lines = [this.border("╭", " Actor Inspector ", "╮", innerWidth)];
223
- lines.push(this.row(this.renderRunControl(run, runs.length - this.runIndex - 1), innerWidth));
270
+ lines.push(this.row(this.renderRunControl(run, runs.length - this.runIndex - 1, innerWidth), innerWidth));
224
271
  lines.push(this.row(this.renderTabs(run), innerWidth));
225
272
  lines.push(this.border("├", "", "┤", innerWidth));
226
273
  this.contentSelectedRows.clear();
227
274
  this.contentStripeIndices = [];
228
275
  let content = this.renderContent(run, innerWidth);
229
- if (this.feedback) {
230
- const color = this.feedback.ok
231
- ? "success"
232
- : /^Kill (failed|rejected)/u.test(this.feedback.message)
233
- ? "error"
234
- : "warning";
235
- content = [this.theme.fg(color, ` ${this.feedback.message}`), ...content];
236
- this.contentSelectedRows = new Set([...this.contentSelectedRows].map((index) => index + 1));
237
- this.contentStripeIndices = [0, ...this.contentStripeIndices];
238
- }
239
276
  const viewportRows = this.contentViewportRows();
240
277
  content = content.slice(0, viewportRows);
241
278
  for (let index = 0; index < viewportRows; index += 1) {
@@ -245,9 +282,9 @@ export class ActorInspectorOverlay {
245
282
  if (this.focus === "select") {
246
283
  const runSelector = this.selectorMode === "run";
247
284
  const startRow = runSelector ? 2 : 3;
248
- const horizontalOffset = runSelector ? 4 : 12;
285
+ const horizontalOffset = runSelector ? 5 : 12;
249
286
  const availableRows = Math.max(3, lines.length - startRow - 1);
250
- const menu = this.renderSelector(run, availableRows);
287
+ const menu = this.renderSelector(run, availableRows, innerWidth);
251
288
  for (const [offset, menuLine] of menu.entries()) {
252
289
  const target = startRow + offset;
253
290
  if (target >= lines.length - 1)
@@ -286,15 +323,16 @@ export class ActorInspectorOverlay {
286
323
  }
287
324
  handleScrollableInput(data, target) {
288
325
  const key = target === "detail" ? "detailScroll" : "documentScroll";
326
+ const pageRows = () => this.contentViewportRows();
289
327
  if (matchesKey(data, "up"))
290
328
  this[key] = Math.max(0, this[key] - 1);
291
329
  else if (matchesKey(data, "down"))
292
330
  this[key] += 1;
293
331
  else if (matchesKey(data, "pageUp")) {
294
- this[key] = Math.max(0, this[key] - this.contentViewportRows());
332
+ this[key] = Math.max(0, this[key] - pageRows());
295
333
  }
296
334
  else if (matchesKey(data, "pageDown")) {
297
- this[key] += this.contentViewportRows();
335
+ this[key] += pageRows();
298
336
  }
299
337
  else if (matchesKey(data, "left") && target === "detail") {
300
338
  this.selectedTraceId = this.traceDetail?.id;
@@ -343,6 +381,8 @@ export class ActorInspectorOverlay {
343
381
  }
344
382
  requestKill(run) {
345
383
  this.feedback = undefined;
384
+ this.feedbackFromAction = false;
385
+ this.feedbackScroll = 0;
346
386
  if (this.focus !== "runs") {
347
387
  this.feedback = { ok: false, message: "Focus Run before using Kill." };
348
388
  return;
@@ -369,11 +409,18 @@ export class ActorInspectorOverlay {
369
409
  status: run.status,
370
410
  };
371
411
  this.killDialogChoice = "cancel";
412
+ this.killDialogScroll = 0;
372
413
  }
373
414
  handleKillInput(data) {
374
415
  const key = data.toLowerCase();
375
- if (matchesKey(data, "escape") || key === "n") {
376
- this.feedback = { ok: false, message: "Kill cancelled." };
416
+ if (matchesKey(data, "pageUp")) {
417
+ this.killDialogScroll = Math.max(0, this.killDialogScroll - this.killDialogPageRows);
418
+ }
419
+ else if (matchesKey(data, "pageDown")) {
420
+ this.killDialogScroll += this.killDialogPageRows;
421
+ }
422
+ else if (matchesKey(data, "escape") || key === "n") {
423
+ this.feedback = undefined;
377
424
  this.killConfirmation = undefined;
378
425
  this.killDialogChoice = "cancel";
379
426
  }
@@ -387,7 +434,7 @@ export class ActorInspectorOverlay {
387
434
  if (this.killDialogChoice === "kill")
388
435
  this.confirmKill();
389
436
  else {
390
- this.feedback = { ok: false, message: "Kill cancelled." };
437
+ this.feedback = undefined;
391
438
  this.killConfirmation = undefined;
392
439
  }
393
440
  }
@@ -398,6 +445,7 @@ export class ActorInspectorOverlay {
398
445
  this.killDialogChoice = "cancel";
399
446
  if (!confirmation || !this.killRun)
400
447
  return;
448
+ this.feedbackFromAction = true;
401
449
  try {
402
450
  const result = this.killRun(confirmation.run, confirmation.runInstanceId);
403
451
  this.feedback = result.ok ? undefined : result;
@@ -406,44 +454,52 @@ export class ActorInspectorOverlay {
406
454
  }
407
455
  catch (error) {
408
456
  const message = error instanceof Error ? error.message : String(error);
457
+ const normalized = message.replaceAll(/\s+/g, " ");
458
+ let selected = normalized.slice(0, 160);
459
+ const clipped = typeof normalized === "string" && normalized.length > 160;
460
+ if (clipped && typeof selected === "string" && /[\uD800-\uDBFF]/u.test(selected.at(-1) ?? "") && /[\uDC00-\uDFFF]/u.test(normalized[160]))
461
+ selected = selected.slice(0, -1);
409
462
  this.feedback = {
410
463
  ok: false,
411
- message: `Kill failed: ${message.replaceAll(/\s+/g, " ").slice(0, 160)}.`,
464
+ message: ActorInspector.formatActorInspectorKillFeedback("failed", `${selected}`, { clipped }),
412
465
  };
413
466
  }
414
467
  }
415
- renderKillDialog(innerWidth) {
468
+ renderKillDialog(width, maxRows) {
469
+ const innerWidth = Math.min(width, 70), textWidth = innerWidth - 2;
416
470
  const confirmation = this.killConfirmation;
417
471
  const cancel = this.killDialogChoice === "cancel"
418
- ? this.theme.bg("selectedBg", this.theme.fg("accent", " Cancel "))
419
- : this.theme.fg("muted", " Cancel ");
472
+ ? this.theme.bg("selectedBg", this.theme.fg("accent", " Cancel "))
473
+ : this.theme.fg("muted", " Cancel ");
420
474
  const kill = this.killDialogChoice === "kill"
421
- ? this.theme.bg("selectedBg", this.theme.fg("error", " Kill actor "))
422
- : this.theme.fg("error", " Kill actor ");
423
- const body = [
424
- "",
425
- this.theme.fg("error", "Kill this running actor?"),
426
- "",
427
- `${this.theme.fg("muted", "Run:")} ${this.theme.fg("accent", `run:${confirmation.run}`)}`,
428
- `${this.theme.fg("muted", "Current status:")} ${this.theme.fg("warning", confirmation.status)}`,
429
- "",
430
- this.theme.fg("text", "This invokes generation-fenced runtime kill."),
431
- "",
432
- `${cancel} ${kill}`,
433
- "",
475
+ ? this.theme.bg("selectedBg", this.theme.fg("error", " Kill actor "))
476
+ : this.theme.fg("error", " Kill actor ");
477
+ const details = this.documentProjection({
478
+ run: confirmation.run,
479
+ state: confirmation.status,
480
+ action: "generation-fenced runtime kill",
481
+ }, textWidth).lines;
482
+ const safety = this.closureWarning(textWidth).map(line => this.theme.fg("warning", line));
483
+ const choices = visibleWidth(cancel) + 2 + visibleWidth(kill) <= textWidth
484
+ ? [this.center(`${cancel} ${kill}`, textWidth)]
485
+ : [this.center(cancel, textWidth), this.center(kill, textWidth)];
486
+ const layout = this.popupLayout(maxRows, safety.length + 1 + choices.length, details.length);
487
+ this.killDialogPageRows = layout.pageRows;
488
+ this.killDialogScroll = Math.min(this.killDialogScroll, Math.max(0, details.length - this.killDialogPageRows));
489
+ const visible = details.slice(this.killDialogScroll, this.killDialogScroll + this.killDialogPageRows);
490
+ const hints = innerWidth < 30 ? this.keyHints(["↵", "pick"], ["esc", "back"])
491
+ : innerWidth < 60 ? this.keyHints(["←→/tab", "choose"], ["↵", "pick"], ["esc", "back"]) : this.renderKeyHints(true);
492
+ return [
493
+ this.border("╭", " Confirm Actor Kill ", "╮", innerWidth),
494
+ ...(layout.top ? [this.row("", innerWidth)] : []),
495
+ ...visible.map(line => this.row(" " + line, innerWidth)),
496
+ ...(layout.paged ? [this.row(" " + this.theme.fg("muted", `${this.killDialogScroll + 1}-${this.killDialogScroll + visible.length}/${details.length} pgup/pgdn`), innerWidth)] : []),
497
+ ...[...safety, "", ...choices].map(line => this.row(" " + line, innerWidth)),
498
+ ...(layout.bottom ? [this.row("", innerWidth)] : []),
499
+ this.footerBorder(hints, innerWidth),
434
500
  ];
435
- const lines = [this.border("╭", " Confirm Actor Kill ", "╮", innerWidth)];
436
- const availableRows = this.contentViewportRows() + 3;
437
- const topPadding = Math.max(0, Math.floor((availableRows - body.length) / 2));
438
- const rows = [...Array.from({ length: topPadding }, () => ""), ...body].slice(0, availableRows);
439
- while (rows.length < availableRows)
440
- rows.push("");
441
- for (const line of rows)
442
- lines.push(this.row(this.center(line, innerWidth), innerWidth));
443
- lines.push(this.footerBorder(this.renderKeyHints(), innerWidth));
444
- return lines;
445
501
  }
446
- renderRunControl(run, sequence) {
502
+ renderRunControl(run, sequence, width) {
447
503
  const active = this.focus === "runs" || (this.focus === "select" && this.selectorMode === "run");
448
504
  const prefix = active ? this.theme.fg("accent", " ← ") : " ";
449
505
  const suffix = active ? this.theme.fg("accent", " → ") : " ";
@@ -452,10 +508,11 @@ export class ActorInspectorOverlay {
452
508
  return active ? this.theme.bg("selectedBg", empty) : empty;
453
509
  }
454
510
  const value = `${prefix}${this.theme.fg("muted", "Run: ")}${this.theme.fg("text", `#${sequence}`)} ${this.theme.fg("accent", run.run)} ${this.theme.fg(this.statusColor(run.status), run.status)}${suffix}`;
455
- return active ? this.theme.bg("selectedBg", value) : value;
511
+ const bounded = truncateToWidth(value, width, "…");
512
+ return active ? this.theme.bg("selectedBg", bounded) : bounded;
456
513
  }
457
514
  renderTabs(run) {
458
- const source = this.traceSource(run);
515
+ const source = this.tab === "trace" ? this.traceSource(run) : "all";
459
516
  return TABS.map((tab, index) => {
460
517
  const base = `${tab[0].toUpperCase()}${tab.slice(1)}`;
461
518
  const label = tab === "trace" && source !== "all" ? `${base}: ${source}` : base;
@@ -479,39 +536,112 @@ export class ActorInspectorOverlay {
479
536
  renderContent(run, width) {
480
537
  if (!run)
481
538
  return [this.theme.fg("muted", " No owned actor runs")];
539
+ if (this.tab === "control" && (this.focus === "list" || this.focus === "detail"))
540
+ return this.renderControlContent(run, width);
482
541
  if (this.focus === "detail")
483
542
  return this.renderTraceDetail(width);
484
543
  if (this.tab === "trace")
485
- return this.renderTraceList(run);
486
- const stateDir = path.join(this.stateRoot, run.run);
544
+ return this.renderTraceList(run, width);
545
+ const selectedRun = run.run;
546
+ const stateDir = path.join(this.stateRoot, selectedRun);
487
547
  const value = this.tab === "recipe"
488
548
  ? ActorInspector.readActorInspectorRecipe(stateDir)
489
549
  : this.controlDocument(run, stateDir);
490
- const projection = this.documentProjection(value, width);
550
+ const body = this.documentProjection(value, width);
551
+ const identity = this.documentProjection({ selected_run_id: selectedRun }, width);
552
+ const projection = {
553
+ lines: [...identity.lines, ...body.lines],
554
+ stripes: [...identity.stripes, ...body.stripes.map(index => index + 1)],
555
+ };
491
556
  const maxStart = Math.max(0, projection.lines.length - this.contentViewportRows());
492
557
  this.documentScroll = Math.min(this.documentScroll, maxStart);
493
558
  this.contentStripeIndices = projection.stripes.slice(this.documentScroll, this.documentScroll + this.contentViewportRows());
494
559
  return projection.lines.slice(this.documentScroll, this.documentScroll + this.contentViewportRows());
495
560
  }
496
- renderSelector(run, availableRows) {
561
+ modalUnderlay(width) {
562
+ const frame = this.inspectorFrame;
563
+ const height = this.contentViewportRows() + 5;
564
+ if (frame.width === width && frame.lines.length === height)
565
+ return frame.lines.slice();
566
+ // Resize the frozen underlay without refreshing evidence behind an open modal.
567
+ const innerWidth = width - 2;
568
+ const content = (index) => sliceByColumn(frame.lines[index] ?? "", 1, frame.width - 2, true);
569
+ return [
570
+ this.border("╭", " Actor Inspector ", "╮", innerWidth),
571
+ this.row(content(1), innerWidth),
572
+ this.row(content(2), innerWidth),
573
+ this.border("├", "", "┤", innerWidth),
574
+ ...Array.from({ length: height - 5 }, (_, index) => this.row(index < frame.lines.length - 5 ? content(index + 4) : "", innerWidth)),
575
+ this.footerBorder(content(frame.lines.length - 1), innerWidth),
576
+ ];
577
+ }
578
+ compositePopup(lines, popup, width) {
579
+ const popupWidth = visibleWidth(popup[0]);
580
+ const left = Math.floor((width - popupWidth) / 2);
581
+ const top = Math.floor((lines.length - popup.length) / 2);
582
+ for (const [offset, line] of popup.entries()) {
583
+ const base = lines[top + offset];
584
+ const right = left + popupWidth;
585
+ // Terminal-default background masks underlying stripes; selected buttons keep their own fill.
586
+ lines[top + offset] = `${sliceByColumn(base, 0, left, true)}\u001b[49m${line}\u001b[49m${sliceByColumn(base, right, width - right, true)}`;
587
+ }
588
+ }
589
+ popupLayout(maxRows, fixedRows, detailRows) {
590
+ // Reserve readable text, pinned safety and choices before decorative blank rows.
591
+ const minimum = 2 + fixedRows + Math.min(2, detailRows);
592
+ const paddingRows = Math.min(2, Math.max(0, maxRows - minimum));
593
+ const height = Math.min(maxRows, Math.max(maxRows - 2, minimum + paddingRows));
594
+ const slots = height - 2 - fixedRows - paddingRows;
595
+ const paged = detailRows > slots;
596
+ return { top: paddingRows > 0, bottom: paddingRows > 1, pageRows: Math.min(detailRows, slots - Number(paged)), paged };
597
+ }
598
+ renderFeedbackPopup(width, maxRows) {
599
+ const feedback = this.feedback;
600
+ const innerWidth = Math.min(70, width - 2), textWidth = innerWidth - 2;
601
+ const color = feedback.ok
602
+ ? "success"
603
+ : /^(?:Kill (?:failed|rejected)|- action: kill\n- result: (?:failed|rejected)\n)/u.test(feedback.message) ? "error" : "warning";
604
+ const message = `${feedback.message}`;
605
+ const details = this.wrapDocument(message.split(/\r\n|\r|\n/u).map(text => ({ text })), textWidth).map(line => line.text);
606
+ const safety = this.feedbackFromAction ? [...this.closureWarning(textWidth), "No automatic retry."] : [];
607
+ const layout = this.popupLayout(maxRows, safety.length, details.length);
608
+ this.feedbackPageRows = layout.pageRows;
609
+ this.feedbackScroll = Math.min(this.feedbackScroll, Math.max(0, details.length - this.feedbackPageRows));
610
+ const visible = details.slice(this.feedbackScroll, this.feedbackScroll + this.feedbackPageRows);
611
+ return [
612
+ this.border("╭", " Notice ", "╮", innerWidth),
613
+ ...(layout.top ? [this.row("", innerWidth)] : []),
614
+ ...visible.map(line => this.row(" " + this.theme.fg(color, line), innerWidth)),
615
+ ...(layout.paged ? [this.row(" " + this.theme.fg("muted", `${this.feedbackScroll + 1}-${this.feedbackScroll + visible.length}/${details.length} ↑↓ pgup/pgdn`), innerWidth)] : []),
616
+ ...safety.map(line => this.row(" " + this.theme.fg("warning", line), innerWidth)),
617
+ ...(layout.bottom ? [this.row("", innerWidth)] : []),
618
+ this.footerBorder(this.keyHints(["esc", "close"]), innerWidth),
619
+ ];
620
+ }
621
+ closureWarning(width) {
622
+ return width >= visibleWidth("- closure: unconfirmed")
623
+ ? ["- closure: unconfirmed"] : ["- closure:", " unconfirmed"];
624
+ }
625
+ renderSelector(run, availableRows, width) {
626
+ // Run menu reserves five offset columns, two markers, two borders and one right-padding column.
497
627
  const options = this.selectorMode === "run"
498
- ? this.runSelectorOptions()
628
+ ? this.runSelectorOptions(Math.max(0, width - 10))
499
629
  : this.traceSources(run).map((source) => ({
500
630
  content: `${this.theme.fg("accent", "Trace:")} ${this.theme.fg("text", source)}`,
501
631
  preserveColors: true,
502
632
  }));
503
633
  return this.renderMenuBox(options, this.selectorIndex, availableRows);
504
634
  }
505
- runSelectorOptions() {
635
+ runSelectorOptions(width) {
506
636
  const runs = this.runs();
507
637
  const sequenceWidth = Math.max(2, ...runs.map((_item, index) => `#${runs.length - index - 1}`.length));
508
638
  const runWidth = Math.max(1, ...runs.map((item) => visibleWidth(item.run)));
509
639
  return runs.map((item, index) => ({
510
- content: [
640
+ content: truncateToWidth([
511
641
  this.theme.fg("text", this.fit(`#${runs.length - index - 1}`, sequenceWidth)),
512
642
  this.theme.fg("accent", this.fit(item.run, runWidth)),
513
643
  this.theme.fg(this.statusColor(item.status), item.status),
514
- ].join(" "),
644
+ ].join(" "), width, "…"),
515
645
  preserveColors: true,
516
646
  }));
517
647
  }
@@ -522,29 +652,40 @@ export class ActorInspectorOverlay {
522
652
  const maxStart = Math.max(0, options.length - visibleLimit);
523
653
  const start = Math.max(0, Math.min(focusedIndex - Math.floor(visibleLimit / 2), maxStart));
524
654
  const visible = options.slice(start, start + visibleLimit);
525
- const width = Math.max(8, ...options.map((option) => visibleWidth(option.content) + 4));
526
- const border = (left, right, marker = "") => this.theme.fg("borderAccent", `${left}${marker}${"─".repeat(Math.max(0, width - visibleWidth(marker)))}${right}`);
655
+ const runMenu = this.selectorMode === "run";
656
+ const width = Math.max(8, ...options.map((option) => visibleWidth(option.content) + (runMenu ? 3 : 4)));
657
+ // Reset both menu edges so sliced document backgrounds cannot bleed through.
658
+ const ownBackground = (line) => runMenu ? `\u001b[49m${line}\u001b[49m` : line;
659
+ const border = (left, right, marker = "") => ownBackground(this.theme.fg("borderAccent", `${left}${marker}${"─".repeat(Math.max(0, width - visibleWidth(marker)))}${right}`));
527
660
  return [
528
661
  border("╭", "╮", start > 0 ? "↑" : ""),
529
662
  ...visible.map((option, offset) => {
530
663
  const index = start + offset;
531
664
  const marker = index === focusedIndex
532
- ? this.theme.fg("accent", " ▶ ")
533
- : " ";
534
- const row = this.fit(`${marker}${option.content}`, width);
665
+ ? this.theme.fg("accent", runMenu ? "▶ " : " ▶ ")
666
+ : runMenu ? " " : " ";
667
+ const row = this.fit(`${marker}${option.content}`, width - Number(runMenu)) + (runMenu ? " " : "");
535
668
  const colored = index === focusedIndex && !option.preserveColors
536
669
  ? this.theme.fg("accent", row)
537
670
  : row;
538
- const styled = index === focusedIndex ? this.theme.bg("selectedBg", colored) : colored;
539
- return `${this.theme.fg("borderAccent", "│")}${styled}${this.theme.fg("borderAccent", "│")}`;
671
+ const background = index === focusedIndex ? "selectedBg" : runMenu && index % 2 ? "customMessageBg" : undefined;
672
+ // Native truncation emits full SGR resets; repaint each resulting segment.
673
+ const styled = background === undefined ? colored : runMenu
674
+ ? colored.split("\u001b[0m").map(part => this.theme.bg(background, part)).join("\u001b[0m")
675
+ : this.theme.bg(background, colored);
676
+ return ownBackground(`${this.theme.fg("borderAccent", "│")}${styled}${this.theme.fg("borderAccent", "│")}`);
540
677
  }),
541
678
  border("╰", "╯", start + visible.length < options.length ? "↓" : ""),
542
679
  ];
543
680
  }
544
- renderTraceList(run) {
681
+ traceTableLine(text, width) {
682
+ const [first = "", ...rest] = text.split(/\r\n|\r|\n/u);
683
+ return truncateToWidth(first + (rest.length ? "…" : ""), width, "…");
684
+ }
685
+ renderTraceList(run, width) {
545
686
  const items = this.traceItems(run);
546
- const summary = RunsTrace.summarizeRunTraceJournal(RunsTrace.readRunTraceJournal(path.join(this.stateRoot, run.run)));
547
- const banner = summary.history_complete ? [] : [this.theme.fg("warning", ` ! Trace history incomplete: ${summary.compacted ? `${summary.compactions_total} compaction(s), ` : ""}${summary.dropped_event_count_exact ? summary.dropped_events : "unknown"} dropped event(s), ${summary.dropped_bytes} bytes`)];
687
+ const summary = this.traceCache.journalSummary ??= RunsTrace.summarizeRunTraceJournal(RunsTrace.readRunTraceJournal(path.join(this.stateRoot, run.run)));
688
+ const banner = summary.history_complete ? [] : [this.theme.fg("warning", width < visibleWidth(" ! Trace history incomplete:") ? " ! Trace incomplete…" : this.traceTableLine(` ! Trace history incomplete: ${summary.compacted ? `${summary.compactions_total} compaction(s), ` : ""}${summary.dropped_event_count_exact ? summary.dropped_events : "unknown"} dropped event(s), ${summary.dropped_bytes} bytes`, width))];
548
689
  if (items.length === 0)
549
690
  return [...banner, this.theme.fg("muted", " No Trace evidence")];
550
691
  if (this.selectedTraceId) {
@@ -575,59 +716,315 @@ export class ActorInspectorOverlay {
575
716
  const detail = item.detail && typeof item.detail === "object"
576
717
  ? item.detail
577
718
  : {};
578
- const marker = item.level === "error"
579
- ? this.theme.fg("error", "!")
580
- : detail.attention
581
- ? this.theme.fg("warning", "A")
582
- : " ";
719
+ const attention = item.level !== "error" && detail.attention
720
+ ? this.theme.fg("warning", "A") + " "
721
+ : "";
583
722
  const prefix = this.focus === "list" && index === this.rowIndex
584
- ? this.theme.fg("accent", " ▶ ")
585
- : " ";
586
- const sequence = item[TraceProjection.TRACE_ITEM_SEQUENCE] ?? items.length - index - 1;
587
- const row = `${prefix}${this.theme.fg("text", `#${sequence}`)} ${marker} ${this.theme.fg("muted", item.source)}/${this.theme.fg(item.level === "error" ? "error" : "accent", item.kind)} ${this.theme.fg("text", item.summary)}`;
723
+ ? this.theme.fg("accent", "▶ ")
724
+ : " ";
725
+ const chronology = item[TraceProjection.TRACE_ITEM_CHRONOLOGY];
726
+ const sequence = chronology?.state === "available" ? chronology.ordinal : "?";
727
+ const row = `${prefix}${this.theme.fg("text", `#${sequence}`)} ${attention}${this.theme.fg("muted", item.source)}/${this.theme.fg(item.level === "error" ? "error" : "accent", item.kind)} ${this.theme.fg("text", item.summary)}`;
728
+ const preview = this.traceTableLine(row, width);
588
729
  return this.focus === "list" && index === this.rowIndex
589
- ? this.theme.fg("accent", row)
590
- : row;
730
+ ? this.theme.fg("accent", preview)
731
+ : preview;
591
732
  })];
592
733
  }
593
734
  renderTraceDetail(width) {
594
735
  if (!this.traceDetail)
595
736
  return [this.theme.fg("warning", " Trace row is no longer available")];
596
- const projection = this.documentProjection(this.traceDetail, width);
737
+ const sequence = this.traceDetail[TraceProjection.TRACE_ITEM_SEQUENCE];
738
+ const value = {
739
+ ...(sequence !== undefined ? { projection_sequence: sequence } : {}),
740
+ ...this.traceDetail,
741
+ chronology: this.traceDetail[TraceProjection.TRACE_ITEM_CHRONOLOGY] ?? { state: "unavailable", reason: "metadata_unavailable" },
742
+ };
743
+ const projection = this.traceDetail.source === "agent" && this.traceDetail.kind === "agent.turn"
744
+ ? this.agentDetailProjection(value, width) : this.documentProjection(value, width);
597
745
  const maxStart = Math.max(0, projection.lines.length - this.contentViewportRows());
598
746
  this.detailScroll = Math.min(this.detailScroll, maxStart);
599
747
  this.contentStripeIndices = projection.stripes.slice(this.detailScroll, this.detailScroll + this.contentViewportRows());
600
748
  return projection.lines.slice(this.detailScroll, this.detailScroll + this.contentViewportRows());
601
749
  }
750
+ agentDetailSegments(value) {
751
+ const extractedBody = Symbol("extracted-body");
752
+ const bodies = [];
753
+ // Only typed SessionEvidenceTurn slots are bodies. Never inspect authored text for framing.
754
+ const select = (item, field) => {
755
+ if (typeof item === "string") {
756
+ bodies.push({ field, text: item });
757
+ return extractedBody;
758
+ }
759
+ return item;
760
+ };
761
+ const record = value;
762
+ const detail = record.detail;
763
+ let metadata = value;
764
+ if (detail && typeof detail === "object" && !Array.isArray(detail)) {
765
+ const retained = Object.fromEntries(Object.entries(detail).map(([key, item]) => {
766
+ if (["assistantText", "userText", "thinking"].includes(key) && typeof item === "string") {
767
+ return [key, select(item, ["detail", key])];
768
+ }
769
+ if (key !== "toolCalls" || !Array.isArray(item))
770
+ return [key, item];
771
+ return [key, item.map((call, callIndex) => {
772
+ if (!call || typeof call !== "object" || Array.isArray(call))
773
+ return call;
774
+ // Action-first display order only; retained tool-call data and body rendering stay unchanged.
775
+ const rank = (key) => key === "name" ? 0 : key === "arguments" ? 1 : key === "result" ? 3 : 2;
776
+ return Object.fromEntries(Object.entries(call).sort(([left], [right]) => rank(left) - rank(right)).map(([name, result]) => {
777
+ if (name !== "result")
778
+ return [name, result];
779
+ const field = ["detail", key, callIndex, name];
780
+ if (typeof result === "string")
781
+ return [name, select(result, field)];
782
+ if (!Array.isArray(result))
783
+ return [name, result];
784
+ return [name, result.map((block, blockIndex) => {
785
+ if (!block || typeof block !== "object" || block.type !== "text" || typeof block.text !== "string")
786
+ return block;
787
+ select(block.text, [...field, blockIndex, "text"]);
788
+ return Object.fromEntries(Object.entries(block).filter(([slot]) => slot !== "text"));
789
+ })];
790
+ }).filter(([, item]) => item !== extractedBody));
791
+ })];
792
+ }).filter(([, item]) => item !== extractedBody));
793
+ metadata = { ...record, detail: retained };
794
+ }
795
+ return [{ kind: "metadata", value: metadata }, ...bodies.flatMap(({ field, text }) => [
796
+ { kind: "metadata", value: { field } }, { kind: "body", text },
797
+ ])];
798
+ }
799
+ metadataText(value) {
800
+ // Copy own selected data, so the library cannot invoke an object's toJSON hook.
801
+ const copy = (item) => {
802
+ // UI-only value state: keep an own undefined slot visible, distinct from null or literal text.
803
+ if (item === undefined)
804
+ return { value_state: "undefined" };
805
+ if (typeof item === "function")
806
+ throw new TypeError("Inspector metadata must be selected own data");
807
+ if (!item || typeof item !== "object")
808
+ return item;
809
+ if (Array.isArray(item))
810
+ return Array.from({ length: item.length }, (_, index) => {
811
+ const descriptor = Object.getOwnPropertyDescriptor(item, String(index));
812
+ if (descriptor && !Object.hasOwn(descriptor, "value"))
813
+ throw new TypeError("Inspector metadata must be selected own data");
814
+ return copy(descriptor?.value);
815
+ });
816
+ const result = Object.create(null);
817
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(item))) {
818
+ if (!descriptor.enumerable)
819
+ continue;
820
+ if (!Object.hasOwn(descriptor, "value"))
821
+ throw new TypeError("Inspector metadata must be selected own data");
822
+ result[key] = copy(descriptor.value);
823
+ }
824
+ return result;
825
+ };
826
+ const document = new Document(copy(value), { version: "1.2", schema: "core", aliasDuplicateObjects: false });
827
+ visit(document, { Pair(_key, pair) {
828
+ if (isScalar(pair.key) && typeof pair.key.value === "string" && pair.key.value.includes("\uFEFF"))
829
+ pair.key.type = "QUOTE_DOUBLE";
830
+ } });
831
+ return document.toString({ collectionStyle: "block", indent: 2, lineWidth: 0, directives: false,
832
+ defaultStringType: "PLAIN", doubleQuotedAsJSON: true });
833
+ }
834
+ agentDetailProjection(value, width) {
835
+ const segments = this.agentDetailSegments(value);
836
+ const lines = [], stripes = [];
837
+ const markdownTheme = { ...getMarkdownTheme(), codeBlockIndent: "" };
838
+ const detailStripe = Object.keys(value).indexOf("detail");
839
+ const append = (rendered, stripe) => {
840
+ lines.push(...rendered);
841
+ stripes.push(...rendered.map(() => stripe));
842
+ };
843
+ const metadata = (selected, stripe) => {
844
+ // yaml's standard serializer has no completion-wire budget/depth ceiling. Data is already admitted upstream.
845
+ const yaml = this.metadataText(selected).replace(/\n$/u, "");
846
+ append(this.wrapDocument(yaml.split("\n").map(text => ({ text })), width).map(line => this.theme.fg("muted", line.text)), stripe);
847
+ };
848
+ segments.forEach((segment, index) => {
849
+ if (index)
850
+ append([""], detailStripe);
851
+ if (segment.kind === "body") {
852
+ append(new Markdown(segment.text, 0, 0, markdownTheme, { color: text => this.theme.fg("text", text) }).render(width), detailStripe);
853
+ }
854
+ else if (index === 0) {
855
+ // Serialize root entries separately to retain root-field stripe provenance without parsing YAML rows.
856
+ Object.entries(segment.value).forEach(([key, item], stripe) => metadata({ [key]: item }, stripe));
857
+ }
858
+ else {
859
+ if (segments[index + 1]?.kind === "body")
860
+ append([this.theme.fg("muted", "---")], detailStripe);
861
+ metadata(segment.value, detailStripe);
862
+ if (segments[index + 1]?.kind === "body")
863
+ append([this.theme.fg("muted", "---")], detailStripe);
864
+ }
865
+ });
866
+ return { lines, stripes };
867
+ }
602
868
  controlDocument(run, stateDir) {
603
- const endpoint = run.runInstanceId
604
- ? RunControlDelivery.readRunControlEndpoint(stateDir, run.runInstanceId)
605
- : undefined;
869
+ return this.controlObservation(run, stateDir).document;
870
+ }
871
+ controlObservation(run, stateDir = path.join(this.stateRoot, run.run)) {
872
+ if (this.controlCache?.run === run.run && this.controlCache.generation === run.runInstanceId)
873
+ return this.controlCache;
606
874
  const meta = this.readRunMeta(stateDir);
607
- const journal = RunsControls.readRunControlJournalFromStateDir(stateDir);
608
- const capacity = computeRunControlCapacity(journal.records);
609
- const stalePending = journal.records.reduce((count, control) => count + Number(Boolean(RuntimeTriage.classifyRuntimeControl({ run: run.run,
610
- runInstanceId: run.runInstanceId, status: run.status }, control, Date.now()).stale)), 0);
611
- return {
612
- status: run.status,
613
- run_instance_id: run.runInstanceId,
614
- pending: capacity.pending, pending_limit: capacity.limit,
615
- available: capacity.available, backpressured: capacity.backpressured,
616
- journal_bytes: (() => { try {
617
- return statSync(RunsControls.runControlsFile(stateDir)).size;
875
+ const bound = Boolean(meta && !Array.isArray(meta) && run.runInstanceId && meta.run === run.run
876
+ && meta.run_instance_id === run.runInstanceId && meta.ownerId === this.ownerId);
877
+ const diagnostics = [];
878
+ let actions = [];
879
+ if (!bound)
880
+ diagnostics.push({ reason: "metadata_binding_unavailable" });
881
+ else {
882
+ try {
883
+ actions = normalizeRecipeControl(meta.control) ?? [];
618
884
  }
619
885
  catch {
620
- return 0;
621
- } })(),
622
- journal_limit: Limits.RUN_CONTROL_JOURNAL_MAX_BYTES,
623
- stale_pending: stalePending,
624
- diagnostics: journal.diagnostics.map((item) => item.line === undefined
625
- ? { reason: "unreadable_control_journal" } : { line: item.line, reason: "invalid_control_json" }),
626
- actor_actions: Array.isArray(meta.control) ? meta.control : [],
627
- runtime_actions: run.status === "running" ? ["kill"] : ["archive", "prune"],
628
- endpoint,
629
- recent_controls: journal.records.slice(-20).reverse().map((control) => ControlProjection.projectRunControl(control)),
630
- };
886
+ diagnostics.push({ reason: "invalid_action_declarations" });
887
+ }
888
+ }
889
+ const endpoint = bound ? RunControlDelivery.readRunControlEndpoint(stateDir, run.runInstanceId) : undefined;
890
+ const journal = bound ? RunsControls.readRunControlJournalFromStateDir(stateDir) : { records: [], diagnostics: [] };
891
+ diagnostics.push(...journal.diagnostics.map(item => item.line === undefined
892
+ ? { reason: "unreadable_control_journal" } : { reason: "invalid_control_json", line: item.line }));
893
+ const now = Date.now();
894
+ const ids = new Map();
895
+ for (const value of journal.records) {
896
+ if (value && typeof value === "object" && typeof value.id === "string") {
897
+ const id = value.id;
898
+ ids.set(id, (ids.get(id) ?? 0) + 1);
899
+ }
900
+ }
901
+ const accepted = [];
902
+ for (const [parsedIndex, value] of journal.records.entries()) {
903
+ const classification = RuntimeTriage.classifyRuntimeControl(run, value, now);
904
+ if (classification.diagnostic) {
905
+ diagnostics.push({ reason: classification.diagnostic.reason });
906
+ continue;
907
+ }
908
+ const record = value;
909
+ if (record.run_instance_id !== run.runInstanceId) {
910
+ diagnostics.push({ reason: "foreign_generation" });
911
+ continue;
912
+ }
913
+ if (ids.get(record.id) !== 1) {
914
+ diagnostics.push({ reason: "duplicate_control_id" });
915
+ continue;
916
+ }
917
+ if (["queued_at", "delivered_at", "claimed_at", "handled_at", "failed_at"].some(field => {
918
+ const timestamp = record[field];
919
+ return (field === "queued_at" || timestamp !== undefined) && (typeof timestamp !== "string" || !Number.isFinite(Date.parse(timestamp)));
920
+ })) {
921
+ diagnostics.push({ reason: "invalid_record_timestamp" });
922
+ continue;
923
+ }
924
+ accepted.push({ id: record.id, value: ControlProjection.projectRunControl(record), parsedIndex,
925
+ age: Math.max(0, now - Date.parse(runControlStatusTimestamp(record, record.status))),
926
+ reason: classification.stale?.reason });
927
+ }
928
+ const capacity = computeRunControlCapacity(journal.records);
929
+ const partial = diagnostics.length > 0;
930
+ const rows = accepted.filter(row => row.parsedIndex >= journal.records.length - 20).reverse();
931
+ const readiness = partial ? "data_unavailable" : run.status !== "running" ? "not_ready"
932
+ : !actions.length ? "unsupported" : capacity.backpressured ? "backpressure" : endpoint ? "ready_recorded_endpoint" : "not_ready";
933
+ const reason = partial ? "partial_observation" : run.status !== "running" ? "run_terminal"
934
+ : !actions.length ? "no_declared_actor_actions" : capacity.backpressured ? "pending_limit_reached"
935
+ : endpoint ? "recorded_endpoint_only_not_connection_proof" : "recorded_endpoint_unavailable";
936
+ this.controlCache = { run: run.run, generation: run.runInstanceId, rows, document: {
937
+ actor_control_readiness: readiness, reason, actor_actions: actions,
938
+ data_state: partial ? "partial" : "available", pending: bound ? capacity.pending : null,
939
+ pending_limit: capacity.limit, available: partial ? null : capacity.available,
940
+ backpressured: bound ? capacity.backpressured : null,
941
+ runtime_actions: bound ? run.status === "running" ? this.killRun && run.runInstanceId ? ["kill"] : [] : ["archive", "prune"] : [],
942
+ runtime_actions_note: "API capabilities; only existing Run-focus Kill is interactive",
943
+ request_history: { shown: rows.length, retained: journal.records.length, parsed_suffix_limit: 20,
944
+ partial: partial || journal.records.length > 20, coverage: "recent parsed journal records; malformed-line coverage unavailable; not complete lifetime history" },
945
+ request_navigation: "Enter opens requests; Down scrolls overview",
946
+ evidence: "Saved non-atomic observation; delivered != handled; handled != Run completion; stale never expires requests",
947
+ status: run.status, run_instance_id: run.runInstanceId,
948
+ journal_bytes: (() => { try {
949
+ return statSync(RunsControls.runControlsFile(stateDir)).size;
950
+ }
951
+ catch {
952
+ return null;
953
+ } })(),
954
+ journal_limit: Limits.RUN_CONTROL_JOURNAL_MAX_BYTES,
955
+ stale_pending: accepted.filter(row => row.reason).length, diagnostics,
956
+ endpoint, recent_controls: rows.map(row => row.value),
957
+ } };
958
+ return this.controlCache;
959
+ }
960
+ selectedControl(observation) {
961
+ const selection = this.controlSelection;
962
+ return selection?.run === observation.run && selection.generation === observation.generation
963
+ ? observation.rows.find(row => row.id === selection.id) : undefined;
964
+ }
965
+ openControlList(run) {
966
+ this.focus = "list";
967
+ this.rowIndex = 0;
968
+ const observation = run ? this.controlObservation(run) : undefined;
969
+ const first = observation?.rows[0];
970
+ this.controlSelection = first ? { run: observation.run, generation: observation.generation, id: first.id } : undefined;
971
+ }
972
+ handleControlInput(data, run) {
973
+ if (matchesKey(data, "escape") || matchesKey(data, "left")) {
974
+ this.focus = this.focus === "detail" ? "list" : "tabs";
975
+ this.detailScroll = 0;
976
+ return;
977
+ }
978
+ if (!run)
979
+ return;
980
+ const observation = this.controlObservation(run);
981
+ const selected = this.selectedControl(observation);
982
+ if (this.focus === "detail") {
983
+ this.handleScrollableInput(data, "detail");
984
+ return;
985
+ }
986
+ const index = selected ? observation.rows.indexOf(selected) : -1;
987
+ let next = index;
988
+ if (matchesKey(data, "up"))
989
+ next = Math.max(0, index - 1);
990
+ else if (matchesKey(data, "down"))
991
+ next = Math.min(observation.rows.length - 1, index + 1);
992
+ else if (matchesKey(data, "pageUp"))
993
+ next = Math.max(0, index - this.contentViewportRows());
994
+ else if (matchesKey(data, "pageDown"))
995
+ next = Math.min(observation.rows.length - 1, index + this.contentViewportRows());
996
+ else if ((matchesKey(data, "return") || matchesKey(data, "right")) && selected) {
997
+ this.focus = "detail";
998
+ this.detailScroll = 0;
999
+ return;
1000
+ }
1001
+ if (next !== index && observation.rows[next])
1002
+ this.controlSelection = {
1003
+ run: observation.run, generation: observation.generation, id: observation.rows[next].id,
1004
+ };
1005
+ }
1006
+ renderControlContent(run, width) {
1007
+ const observation = this.controlObservation(run);
1008
+ const selected = this.selectedControl(observation);
1009
+ if (this.focus === "detail") {
1010
+ const projection = this.documentProjection(selected ? selected.value : { request: "unavailable", reason: "selected Run/generation/id no longer available" }, width);
1011
+ this.detailScroll = Math.min(this.detailScroll, Math.max(0, projection.lines.length - this.contentViewportRows()));
1012
+ this.contentStripeIndices = projection.stripes.slice(this.detailScroll, this.detailScroll + this.contentViewportRows());
1013
+ return projection.lines.slice(this.detailScroll, this.detailScroll + this.contentViewportRows());
1014
+ }
1015
+ const coverage = observation.document.request_history;
1016
+ const banner = this.traceTableLine(` Requests ${coverage.shown}/${coverage.retained} parsed; recent20${coverage.partial ? "; partial" : ""}`, width);
1017
+ if (!observation.rows.length)
1018
+ return [banner, " No requests", this.traceTableLine(" Saved observation; history may be partial", width)];
1019
+ const index = selected ? observation.rows.indexOf(selected) : -1;
1020
+ const count = Math.max(1, this.contentViewportRows() - 2);
1021
+ const start = Math.max(0, index - Math.floor(count / 2));
1022
+ const rows = observation.rows.slice(start, start + count);
1023
+ this.contentStripeIndices = [0, 0, ...rows.map((_row, offset) => start + offset + 1)];
1024
+ if (index >= start)
1025
+ this.contentSelectedRows.add(index - start + 2);
1026
+ return [banner, this.traceTableLine(index < 0 ? " Selection unavailable; arrows select a request" : " Status | action | status age | error/stale", width),
1027
+ ...rows.map(row => this.traceTableLine(`${row === selected ? "▶" : " "} ${row.value.status} | ${row.value.action} | ${Math.floor(row.age / 1000)}s | ${row.value.error ?? row.reason ?? ""}`, width))];
631
1028
  }
632
1029
  allTraceItems(run) {
633
1030
  if (!run)
@@ -666,178 +1063,81 @@ export class ActorInspectorOverlay {
666
1063
  }
667
1064
  }
668
1065
  documentProjection(value, width) {
669
- const sections = value && typeof value === "object" && !Array.isArray(value)
670
- ? Object.entries(value).map(([key, item]) => this.labeledDocumentLines(key, item))
671
- : [this.document(value)];
1066
+ // Copy before enumerating roots: accessors and hooks must never run during projection.
1067
+ const selected = this.metadataText(value);
1068
+ const descriptors = value && typeof value === "object" && !Array.isArray(value)
1069
+ ? Object.entries(Object.getOwnPropertyDescriptors(value)).filter(([, descriptor]) => descriptor.enumerable) : [];
1070
+ const sections = descriptors.length
1071
+ ? descriptors.map(([key, descriptor]) => this.metadataText({ [key]: descriptor.value }))
1072
+ : [selected];
672
1073
  const lines = [];
673
1074
  const stripes = [];
674
1075
  sections.forEach((section, sectionIndex) => {
675
- const wrapped = this.wrapDocument(section, width);
676
- lines.push(...wrapped.map((line) => this.styleDocumentLine(line)));
1076
+ const wrapped = this.wrapDocument(section.replace(/\n$/u, "").split("\n").map(text => ({ text })), width);
1077
+ lines.push(...wrapped.map((line) => this.theme.fg("muted", line.text)));
677
1078
  stripes.push(...wrapped.map(() => sectionIndex));
678
1079
  });
679
1080
  return { lines, stripes };
680
1081
  }
681
- inlineDocumentValue(value) {
682
- if (Array.isArray(value)) {
683
- if (value.length === 0)
684
- return "[]";
685
- if (value.every((item) => (item === null || typeof item !== "object") &&
686
- !(typeof item === "string" && /[\r\n]/u.test(item)))) {
687
- return `[${value.map((item) => String(item ?? "none")).join(", ")}]`;
688
- }
689
- return undefined;
690
- }
691
- if (value && typeof value === "object") {
692
- if (Object.keys(value).length === 0)
693
- return "{}";
694
- }
695
- return undefined;
696
- }
697
- labeledDocumentLines(key, value, depth = 0) {
698
- const inline = this.inlineDocumentValue(value);
699
- if (inline !== undefined)
700
- return [`${" ".repeat(depth)}${key}: ${inline}`];
701
- if (value && typeof value === "object") {
702
- const indent = " ".repeat(depth);
703
- const nested = this.document(value, depth);
704
- return [`${indent}${key}: ${nested[0].slice(indent.length)}`, ...nested.slice(1)];
705
- }
706
- return this.labeledScalarLines(key, value, depth);
707
- }
708
- labeledScalarLines(key, value, depth = 0) {
709
- const indent = " ".repeat(depth);
710
- const [first = "", ...rest] = String(value ?? "none").split(/\r?\n/u);
711
- return [
712
- `${indent}${key}: ${first}`,
713
- ...rest.map((line) => `${indent} ${line}`),
714
- ];
715
- }
716
- document(value, depth = 0) {
717
- if (value === null || value === undefined)
718
- return [`${" ".repeat(depth)}none`];
719
- const inline = this.inlineDocumentValue(value);
720
- if (inline !== undefined)
721
- return [`${" ".repeat(depth)}${inline}`];
722
- if (Array.isArray(value)) {
723
- const indent = " ".repeat(depth);
724
- return [
725
- `${indent}[`,
726
- ...value.flatMap((item, index) => {
727
- const itemDepth = depth + 1;
728
- const itemIndent = " ".repeat(itemDepth);
729
- const marker = `#${index}`;
730
- const itemInline = this.inlineDocumentValue(item);
731
- let lines;
732
- if (itemInline !== undefined) {
733
- lines = [`${itemIndent}${marker}: ${itemInline}`];
734
- }
735
- else if (item && typeof item === "object") {
736
- const nested = this.document(item, itemDepth);
737
- lines = [
738
- `${itemIndent}${marker}: ${nested[0].slice(itemIndent.length)}`,
739
- ...nested.slice(1),
740
- ];
741
- }
742
- else {
743
- lines = this.labeledScalarLines(marker, item, itemDepth);
744
- }
745
- if (index < value.length - 1)
746
- lines[lines.length - 1] += ",";
747
- return lines;
748
- }),
749
- `${indent}]`,
750
- ];
751
- }
752
- if (typeof value === "object") {
753
- const indent = " ".repeat(depth);
754
- const entries = Object.entries(value);
755
- return [
756
- `${indent}{`,
757
- ...entries.flatMap(([key, item], index) => {
758
- const lines = this.labeledDocumentLines(key, item, depth + 1);
759
- if (index < entries.length - 1)
760
- lines[lines.length - 1] += ",";
761
- return lines;
762
- }),
763
- `${indent}}`,
764
- ];
765
- }
766
- return String(value)
767
- .split(/\r?\n/u)
768
- .map((line) => `${" ".repeat(depth)}${line}`);
769
- }
770
1082
  wrapDocument(lines, width) {
771
1083
  return lines.flatMap((line) => {
772
- const normalized = line.replaceAll("\t", " ");
773
- if (visibleWidth(normalized) <= width)
774
- return [normalized];
775
- const leading = normalized.match(/^ */u)?.[0] ?? "";
776
- const continuation = `${leading} `;
1084
+ // Keep the existing terminal tab display policy; never alter the source value.
1085
+ const text = line.text.replaceAll("\t", " ");
1086
+ const label = line.label?.replaceAll("\t", " ");
1087
+ if (visibleWidth(text) <= width)
1088
+ return [{ text, label }];
1089
+ const leading = text.match(/^ */u)?.[0] ?? "";
1090
+ const hanging = label === undefined ? leading : `${leading} `;
1091
+ const continuation = hanging.length <= width - 2 ? hanging : "";
777
1092
  const wrapped = [];
778
- let rest = normalized.slice(leading.length);
779
- let prefix = leading;
780
- while (rest && visibleWidth(`${prefix}${rest}`) > width) {
781
- const available = Math.max(1, width - visibleWidth(prefix));
782
- const candidate = this.visiblePrefix(rest, available);
783
- const minimumBreak = Math.floor(candidate.length * 0.6);
784
- const preferred = Math.max(candidate.lastIndexOf(" "), candidate.lastIndexOf("/"), candidate.lastIndexOf(","));
785
- const cut = preferred >= minimumBreak ? preferred + 1 : candidate.length;
786
- wrapped.push(`${prefix}${rest.slice(0, cut).trimEnd()}`);
787
- rest = rest.slice(cut).trimStart();
788
- prefix = continuation;
789
- }
790
- if (rest)
791
- wrapped.push(`${prefix}${rest}`);
1093
+ const columns = visibleWidth(text);
1094
+ let offset = 0;
1095
+ while (offset < columns) {
1096
+ const prefix = offset === 0 ? "" : continuation;
1097
+ const available = width - visibleWidth(prefix);
1098
+ // Native cell slicing keeps graphemes; retain separators instead of trimming authored spaces.
1099
+ let part = sliceByColumn(text, offset, available, true);
1100
+ const preferred = Math.max(part.lastIndexOf(" "), part.lastIndexOf("/"), part.lastIndexOf(","));
1101
+ if (offset + visibleWidth(part) < columns && preferred >= Math.floor(part.length * 0.6)) {
1102
+ part = sliceByColumn(text, offset, visibleWidth(part.slice(0, preferred + 1)), true);
1103
+ }
1104
+ const consumed = visibleWidth(part);
1105
+ const labelPart = label === undefined ? "" : sliceByColumn(label, offset, consumed, true);
1106
+ wrapped.push({ text: prefix + part, ...(labelPart ? { label: prefix + labelPart } : {}) });
1107
+ offset += consumed;
1108
+ }
792
1109
  return wrapped;
793
1110
  });
794
1111
  }
795
- styleDocumentLine(line) {
796
- const indent = line.match(/^ */u)?.[0] ?? "";
797
- const content = line.slice(indent.length);
798
- if (content.endsWith(":")) {
799
- return `${indent}${this.theme.fg("accent", content)}`;
800
- }
801
- const indexed = /^(#\d+:)(.*)$/u.exec(content);
802
- if (indexed) {
803
- return `${indent}${this.theme.fg("accent", indexed[1])}${this.theme.fg("text", indexed[2])}`;
804
- }
805
- const labeled = /^([^:]+:)(.*)$/u.exec(content);
806
- if (labeled) {
807
- return `${indent}${this.theme.fg("muted", labeled[1])}${this.theme.fg("text", labeled[2])}`;
808
- }
809
- return `${indent}${this.theme.fg(content === "none" || content === "[]" ? "muted" : "text", content)}`;
810
- }
811
- visiblePrefix(value, width) {
812
- let consumed = 0;
813
- let result = "";
814
- for (const character of value) {
815
- const characterWidth = visibleWidth(character);
816
- if (consumed + characterWidth > width)
817
- break;
818
- result += character;
819
- consumed += characterWidth;
820
- }
821
- return result;
822
- }
823
- renderKeyHints() {
1112
+ keyHints(...items) {
824
1113
  const hint = (keys, description) => `${this.theme.fg("accent", keys)}${this.theme.fg("borderAccent", ` ${description}`)}`;
825
1114
  const divider = this.theme.fg("borderAccent", " ─ ");
826
- const hints = (...items) => items.map(([keys, description]) => hint(keys, description)).join(divider);
827
- if (this.killConfirmation) {
828
- return hints(["←→/tab", "choose"], ["enter/y", "confirm"], ["esc/n", "cancel"]);
1115
+ return items.map(([keys, description]) => hint(keys, description)).join(divider);
1116
+ }
1117
+ renderKeyHints(killConfirmation = false) {
1118
+ if (killConfirmation) {
1119
+ return this.keyHints(["←→/tab", "choose"], ["enter", "pick"], ["y", "kill"], ["esc/n", "cancel"]);
829
1120
  }
830
1121
  if (this.focus === "select") {
831
- return hints(["↑↓", "option"], ["enter/→", "apply"], ["←/esc", "back"]);
1122
+ return this.keyHints(["↑↓", "option"], ["enter/→", "apply"], ["←/esc", "back"]);
832
1123
  }
833
1124
  if (this.focus === "detail") {
834
- return hints(["↑↓/pgup/pgdn", "scroll"], ["←/esc", "back"]);
1125
+ return this.keyHints(["↑↓/pgup/pgdn", "scroll"], ["←/esc", "back"]);
1126
+ }
1127
+ if (this.tab === "control" && this.focus === "document") {
1128
+ return this.keyHints(["↑↓/pgup/pgdn", "scroll"], ["enter", "requests"], ["←/esc", "tabs"]);
1129
+ }
1130
+ if (this.tab === "control" && this.focus === "list") {
1131
+ return this.keyHints(["↑↓/pgup/pgdn", "row"], ["→/enter", "YAML"], ["←/esc", "tabs"]);
1132
+ }
1133
+ if (this.tab === "control" && this.focus === "tabs") {
1134
+ return this.keyHints(["←→", "tabs"], ["↓", "overview"], ["enter", "requests"], ["esc", "close"]);
835
1135
  }
836
1136
  if (this.focus === "document") {
837
- return hints(["↑↓/pgup/pgdn", "scroll"], ["↑ at top", "tabs"], ["←/esc", "tabs"]);
1137
+ return this.keyHints(["↑↓/pgup/pgdn", "scroll"], ["↑ at top", "tabs"], ["←/esc", "tabs"]);
838
1138
  }
839
1139
  if (this.focus === "list") {
840
- return hints(["↑↓/pgup/pgdn", "row"], ["→/enter", "open"], ["←", "tabs"], ["esc", "close"]);
1140
+ return this.keyHints(["↑↓/pgup/pgdn", "row"], ["→/enter", "open"], ["←", "tabs"], ["esc", "close"]);
841
1141
  }
842
1142
  if (this.focus === "runs") {
843
1143
  const items = [["←→", "run"], ["↓", "tabs"], ["enter", "list"]];
@@ -845,11 +1145,11 @@ export class ActorInspectorOverlay {
845
1145
  if (this.killRun && run?.status === "running" && run.runInstanceId)
846
1146
  items.push(["k", "kill"]);
847
1147
  items.push(["esc", "close"]);
848
- return hints(...items);
1148
+ return this.keyHints(...items);
849
1149
  }
850
1150
  return this.tab === "trace"
851
- ? hints(["←→", "tabs"], ["↑↓", "focus"], ["enter/f", "source"], ["esc", "close"])
852
- : hints(["←→", "tabs"], ["↑↓", "focus"], ["enter", "open"], ["esc", "close"]);
1151
+ ? this.keyHints(["←→", "tabs"], ["↑↓", "focus"], ["enter/f", "source"], ["esc", "close"])
1152
+ : this.keyHints(["←→", "tabs"], ["↑↓", "focus"], ["enter", "open"], ["esc", "close"]);
853
1153
  }
854
1154
  statusColor(status) {
855
1155
  if (status === "failed")