@agentwhy/cli 0.0.0-dev

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 (400) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +181 -0
  4. package/THIRD_PARTY_NOTICES.md +31 -0
  5. package/dist/adapter/claude-code/contract/assumptions.js +208 -0
  6. package/dist/adapter/claude-code/contract/denials.js +15 -0
  7. package/dist/adapter/claude-code/contract/entry-points.js +15 -0
  8. package/dist/adapter/claude-code/contract/fields.js +73 -0
  9. package/dist/adapter/claude-code/contract/hooks.js +96 -0
  10. package/dist/adapter/claude-code/contract/identifiers.js +15 -0
  11. package/dist/adapter/claude-code/contract/layout.js +29 -0
  12. package/dist/adapter/claude-code/contract/line-types.js +26 -0
  13. package/dist/adapter/claude-code/contract/projects.js +23 -0
  14. package/dist/adapter/claude-code/contract/recognition.js +14 -0
  15. package/dist/adapter/claude-code/contract/session-title.js +20 -0
  16. package/dist/adapter/claude-code/contract/settings.js +27 -0
  17. package/dist/adapter/claude-code/contract/task-notifications.js +33 -0
  18. package/dist/adapter/claude-code/contract/tools.js +37 -0
  19. package/dist/adapter/claude-code/contract/version.js +51 -0
  20. package/dist/adapter/claude-code/discovery/claude-code-project-catalogue.js +129 -0
  21. package/dist/adapter/claude-code/discovery/claude-code-recognition.js +46 -0
  22. package/dist/adapter/claude-code/discovery/claude-code-session-catalogue.js +100 -0
  23. package/dist/adapter/claude-code/discovery/claude-code-session-discovery.js +61 -0
  24. package/dist/adapter/claude-code/discovery/claude-code-session-titles.js +28 -0
  25. package/dist/adapter/claude-code/discovery/discovered-session.js +1 -0
  26. package/dist/adapter/claude-code/discovery/session-entries.js +41 -0
  27. package/dist/adapter/claude-code/discovery/transcript-tail.js +81 -0
  28. package/dist/adapter/claude-code/events/claude-code-session-source.js +197 -0
  29. package/dist/adapter/claude-code/events/delegation-index.js +15 -0
  30. package/dist/adapter/claude-code/events/transcript-scan.js +179 -0
  31. package/dist/adapter/claude-code/hooks/hook-output.js +42 -0
  32. package/dist/adapter/claude-code/hooks/pre-tool-use-input.js +23 -0
  33. package/dist/adapter/claude-code/hooks/stop-input.js +25 -0
  34. package/dist/adapter/claude-code/hooks/subagent-stop-input.js +26 -0
  35. package/dist/adapter/claude-code/policy/deny-rules.js +46 -0
  36. package/dist/adapter/claude-code/probe/claude-code-probe.js +86 -0
  37. package/dist/adapter/claude-code/probe/collectors/agent-tool-input-key-collector.js +24 -0
  38. package/dist/adapter/claude-code/probe/collectors/denial-kind-collector.js +20 -0
  39. package/dist/adapter/claude-code/probe/collectors/denied-call-collector.js +11 -0
  40. package/dist/adapter/claude-code/probe/collectors/identifier-collector.js +19 -0
  41. package/dist/adapter/claude-code/probe/collectors/line-collector.js +1 -0
  42. package/dist/adapter/claude-code/probe/collectors/line-type-collector.js +29 -0
  43. package/dist/adapter/claude-code/probe/collectors/sidechain-collector.js +20 -0
  44. package/dist/adapter/claude-code/probe/collectors/task-notification-collector.js +51 -0
  45. package/dist/adapter/claude-code/probe/collectors/tool-result-reference-collector.js +31 -0
  46. package/dist/adapter/claude-code/probe/collectors/tool-use-collector.js +24 -0
  47. package/dist/adapter/claude-code/probe/collectors/tool-version-collector.js +14 -0
  48. package/dist/adapter/claude-code/probe/collectors/top-level-key-collector.js +14 -0
  49. package/dist/adapter/claude-code/probe/collectors/unknown-line-type-key-collector.js +24 -0
  50. package/dist/adapter/claude-code/probe/collectors/working-directory-collector.js +28 -0
  51. package/dist/adapter/claude-code/probe/doctor-report.js +1 -0
  52. package/dist/adapter/claude-code/probe/meta-tally.js +42 -0
  53. package/dist/adapter/claude-code/probe/session-probe.js +1 -0
  54. package/dist/adapter/claude-code/probe/session-tally.js +41 -0
  55. package/dist/adapter/claude-code/probe/transcript-line.js +30 -0
  56. package/dist/adapter/claude-code/probe/transcript-tally.js +74 -0
  57. package/dist/adapter/claude-code/settings/deny-entries.js +65 -0
  58. package/dist/adapter/claude-code/settings/hook-entries.js +303 -0
  59. package/dist/adapter/codex/contract/actions.js +69 -0
  60. package/dist/adapter/codex/contract/assumptions.js +55 -0
  61. package/dist/adapter/codex/contract/capabilities.js +24 -0
  62. package/dist/adapter/codex/contract/delegations.js +30 -0
  63. package/dist/adapter/codex/contract/deliveries.js +25 -0
  64. package/dist/adapter/codex/contract/envelope.js +33 -0
  65. package/dist/adapter/codex/contract/hook-refusals.js +14 -0
  66. package/dist/adapter/codex/contract/hooks.js +46 -0
  67. package/dist/adapter/codex/contract/messages.js +47 -0
  68. package/dist/adapter/codex/contract/permissions.js +27 -0
  69. package/dist/adapter/codex/contract/reviews.js +13 -0
  70. package/dist/adapter/codex/contract/session.js +31 -0
  71. package/dist/adapter/codex/contract/turns.js +23 -0
  72. package/dist/adapter/codex/contract/version.js +15 -0
  73. package/dist/adapter/codex/discovery/codex-conversations.js +44 -0
  74. package/dist/adapter/codex/discovery/codex-project-catalogue.js +49 -0
  75. package/dist/adapter/codex/discovery/codex-recognition.js +20 -0
  76. package/dist/adapter/codex/discovery/codex-session-catalogue.js +28 -0
  77. package/dist/adapter/codex/discovery/codex-session-discovery.js +115 -0
  78. package/dist/adapter/codex/discovery/codex-session-index.js +21 -0
  79. package/dist/adapter/codex/discovery/codex-session-titles.js +135 -0
  80. package/dist/adapter/codex/discovery/session-header.js +86 -0
  81. package/dist/adapter/codex/discovery/session-owners.js +11 -0
  82. package/dist/adapter/codex/discovery/session-roots.js +49 -0
  83. package/dist/adapter/codex/events/action-items.js +138 -0
  84. package/dist/adapter/codex/events/capability-records.js +26 -0
  85. package/dist/adapter/codex/events/codex-session-source.js +121 -0
  86. package/dist/adapter/codex/events/hook-refusals.js +27 -0
  87. package/dist/adapter/codex/events/rollout-scan.js +614 -0
  88. package/dist/adapter/codex/events/turn-permissions.js +60 -0
  89. package/dist/adapter/codex/hooks/pre-tool-use-input.js +24 -0
  90. package/dist/adapter/codex/hooks/stop-refusals.js +57 -0
  91. package/dist/adapter/codex/probe/codex-doctor-report.js +1 -0
  92. package/dist/adapter/codex/probe/codex-probe.js +268 -0
  93. package/dist/adapter/codex/settings/codex-hooks.js +83 -0
  94. package/dist/cli/cli-command.js +1 -0
  95. package/dist/cli/command-router.js +42 -0
  96. package/dist/cli/commands/check-cli-command.js +128 -0
  97. package/dist/cli/commands/codex-stop-cli-command.js +27 -0
  98. package/dist/cli/commands/doctor-arguments.js +32 -0
  99. package/dist/cli/commands/doctor-cli-command.js +31 -0
  100. package/dist/cli/commands/doctor-usage.js +14 -0
  101. package/dist/cli/commands/init-cli-command.js +123 -0
  102. package/dist/cli/commands/menu-cli-command.js +58 -0
  103. package/dist/cli/commands/notify-cli-command.js +158 -0
  104. package/dist/cli/commands/refuse-cli-command.js +79 -0
  105. package/dist/cli/commands/report-arguments.js +62 -0
  106. package/dist/cli/commands/report-cli-command.js +36 -0
  107. package/dist/cli/commands/report-usage.js +41 -0
  108. package/dist/cli/commands/sessions-cli-command.js +184 -0
  109. package/dist/cli/commands/start-cli-command.js +83 -0
  110. package/dist/cli/commands/watch-cli-command.js +142 -0
  111. package/dist/cli/exit-codes.js +13 -0
  112. package/dist/cli/project-switches.js +46 -0
  113. package/dist/cli.js +80 -0
  114. package/dist/composition-root.js +411 -0
  115. package/dist/core/access/command-line.js +454 -0
  116. package/dist/core/access/listing.js +58 -0
  117. package/dist/core/access/path-shape.js +59 -0
  118. package/dist/core/access/path-tokens.js +37 -0
  119. package/dist/core/access/protected-access.js +310 -0
  120. package/dist/core/access/protected-values.js +102 -0
  121. package/dist/core/access/recorded-effect.js +67 -0
  122. package/dist/core/access/returns.js +173 -0
  123. package/dist/core/access/search-output.js +34 -0
  124. package/dist/core/access/search-reach.js +268 -0
  125. package/dist/core/access/uses.js +143 -0
  126. package/dist/core/access/words-before.js +52 -0
  127. package/dist/core/agent.js +1 -0
  128. package/dist/core/capability.js +11 -0
  129. package/dist/core/combined-project-catalogue.js +36 -0
  130. package/dist/core/combined-session-catalogue.js +25 -0
  131. package/dist/core/completeness.js +10 -0
  132. package/dist/core/context.js +1 -0
  133. package/dist/core/correlation/correlate.js +329 -0
  134. package/dist/core/delegation.js +1 -0
  135. package/dist/core/detector/prompt-signals.js +78 -0
  136. package/dist/core/entry-point.js +1 -0
  137. package/dist/core/event.js +1 -0
  138. package/dist/core/evidence.js +9 -0
  139. package/dist/core/late-message.js +32 -0
  140. package/dist/core/message.js +1 -0
  141. package/dist/core/nearest-project.js +28 -0
  142. package/dist/core/policy/default-policy.js +32 -0
  143. package/dist/core/policy/glob.js +56 -0
  144. package/dist/core/policy/parse-policy.js +70 -0
  145. package/dist/core/policy/policy.js +20 -0
  146. package/dist/core/policy/resolve-policy.js +16 -0
  147. package/dist/core/project-catalogue.js +1 -0
  148. package/dist/core/project-root.js +133 -0
  149. package/dist/core/provider-titles.js +10 -0
  150. package/dist/core/redaction/entropy.js +46 -0
  151. package/dist/core/redaction/redacted.js +4 -0
  152. package/dist/core/redaction/redactor.js +339 -0
  153. package/dist/core/redaction/secret-patterns.js +22 -0
  154. package/dist/core/redaction/value-shapes.js +81 -0
  155. package/dist/core/redaction/value-trace.js +110 -0
  156. package/dist/core/review.js +1 -0
  157. package/dist/core/session-catalogue.js +19 -0
  158. package/dist/core/session-filter.js +42 -0
  159. package/dist/core/session-format.js +27 -0
  160. package/dist/core/session-model.js +1 -0
  161. package/dist/core/session-reader.js +22 -0
  162. package/dist/core/session-records.js +1 -0
  163. package/dist/core/session-source.js +1 -0
  164. package/dist/core/session-titles.js +21 -0
  165. package/dist/core/turn.js +1 -0
  166. package/dist/doctor/codex-doctor.js +14 -0
  167. package/dist/doctor/doctor-use-case.js +1 -0
  168. package/dist/doctor/format-selecting-doctor.js +28 -0
  169. package/dist/doctor/render/attention/attention-rule.js +1 -0
  170. package/dist/doctor/render/attention/doctor-attention-rules.js +28 -0
  171. package/dist/doctor/render/attention/rules/damaged-meta-files-rule.js +8 -0
  172. package/dist/doctor/render/attention/rules/damaged-transcripts-rule.js +9 -0
  173. package/dist/doctor/render/attention/rules/incomplete-subagent-pairs-rule.js +6 -0
  174. package/dist/doctor/render/attention/rules/missing-main-transcript-rule.js +5 -0
  175. package/dist/doctor/render/attention/rules/missing-spilled-results-rule.js +6 -0
  176. package/dist/doctor/render/attention/rules/multiple-working-directories-rule.js +15 -0
  177. package/dist/doctor/render/attention/rules/unknown-denial-kinds-rule.js +5 -0
  178. package/dist/doctor/render/attention/rules/unknown-line-types-rule.js +6 -0
  179. package/dist/doctor/render/attention/rules/unrecognised-entries-rule.js +6 -0
  180. package/dist/doctor/render/attention/rules/unusable-directories-rule.js +12 -0
  181. package/dist/doctor/render/attention/transcript-scopes.js +6 -0
  182. package/dist/doctor/render/codex-text-doctor-renderer.js +97 -0
  183. package/dist/doctor/render/doctor-renderers.js +1 -0
  184. package/dist/doctor/render/json-doctor-renderer.js +7 -0
  185. package/dist/doctor/render/output-format.js +1 -0
  186. package/dist/doctor/render/text-doctor-renderer.js +124 -0
  187. package/dist/doctor/session-doctor.js +16 -0
  188. package/dist/infrastructure/clack-asker.js +24 -0
  189. package/dist/infrastructure/clack-chooser.js +40 -0
  190. package/dist/infrastructure/clack-multi-chooser.js +31 -0
  191. package/dist/infrastructure/file-alert-store.js +120 -0
  192. package/dist/infrastructure/file-checked-store.js +55 -0
  193. package/dist/infrastructure/file-mark-store.js +67 -0
  194. package/dist/infrastructure/file-onboarding-store.js +93 -0
  195. package/dist/infrastructure/folder-window.js +26 -0
  196. package/dist/infrastructure/node-agentwhy-invocation.js +99 -0
  197. package/dist/infrastructure/node-browser.js +40 -0
  198. package/dist/infrastructure/node-file-system.js +111 -0
  199. package/dist/infrastructure/node-local-server.js +115 -0
  200. package/dist/infrastructure/node-text-input.js +26 -0
  201. package/dist/infrastructure/os-notifier.js +21 -0
  202. package/dist/infrastructure/osascript-folder-chooser.js +53 -0
  203. package/dist/infrastructure/powershell-folder-chooser.js +78 -0
  204. package/dist/infrastructure/real-directory.js +18 -0
  205. package/dist/infrastructure/stream-printer.js +11 -0
  206. package/dist/infrastructure/terminal-banner.js +19 -0
  207. package/dist/ports/agentwhy-invocation.js +1 -0
  208. package/dist/ports/alert-store.js +1 -0
  209. package/dist/ports/asker.js +1 -0
  210. package/dist/ports/browser.js +1 -0
  211. package/dist/ports/checked-store.js +1 -0
  212. package/dist/ports/chooser.js +1 -0
  213. package/dist/ports/directory-reader.js +1 -0
  214. package/dist/ports/file-access-error.js +11 -0
  215. package/dist/ports/file-reader.js +1 -0
  216. package/dist/ports/file-tail-reader.js +1 -0
  217. package/dist/ports/file-writer.js +1 -0
  218. package/dist/ports/folder-chooser.js +1 -0
  219. package/dist/ports/local-server.js +1 -0
  220. package/dist/ports/mark-store.js +10 -0
  221. package/dist/ports/multi-chooser.js +1 -0
  222. package/dist/ports/notifier.js +1 -0
  223. package/dist/ports/onboarding-store.js +1 -0
  224. package/dist/ports/printer.js +1 -0
  225. package/dist/ports/text-input.js +1 -0
  226. package/dist/refuse/command-reach.js +135 -0
  227. package/dist/refuse/command-refusal.js +88 -0
  228. package/dist/refuse/render/codex-stop-words.js +21 -0
  229. package/dist/refuse/render/refusal-words.js +34 -0
  230. package/dist/report/build-report.js +1037 -0
  231. package/dist/report/check/actions-digest.js +73 -0
  232. package/dist/report/check/check-lines.js +83 -0
  233. package/dist/report/check/mark-request.js +90 -0
  234. package/dist/report/check/marks.js +84 -0
  235. package/dist/report/check/render/text-digest-renderer.js +332 -0
  236. package/dist/report/check/session-actions.js +90 -0
  237. package/dist/report/check/session-check.js +91 -0
  238. package/dist/report/choose-policy.js +61 -0
  239. package/dist/report/flow-reads.js +18 -0
  240. package/dist/report/private-files/tell-lists.js +84 -0
  241. package/dist/report/project-rules.js +33 -0
  242. package/dist/report/render/home-relative.js +18 -0
  243. package/dist/report/render/html-head.js +26 -0
  244. package/dist/report/render/html-report-components.js +48 -0
  245. package/dist/report/render/html-report-styles.js +500 -0
  246. package/dist/report/render/html-sidebar.js +42 -0
  247. package/dist/report/render/path-tail.js +14 -0
  248. package/dist/report/render/report-copy.js +1177 -0
  249. package/dist/report/render/report-page/advanced-view.js +167 -0
  250. package/dist/report/render/report-page/file-story.js +114 -0
  251. package/dist/report/render/report-page/files-view.js +381 -0
  252. package/dist/report/render/report-page/files.js +77 -0
  253. package/dist/report/render/report-page/fix-wizard-script.js +269 -0
  254. package/dist/report/render/report-page/fix-wizard.js +310 -0
  255. package/dist/report/render/report-page/helpers-view.js +383 -0
  256. package/dist/report/render/report-page/helpers.js +51 -0
  257. package/dist/report/render/report-page/item-names.js +63 -0
  258. package/dist/report/render/report-page/protect-patterns.js +13 -0
  259. package/dist/report/render/report-page/providers.js +208 -0
  260. package/dist/report/render/report-page/record-view.js +367 -0
  261. package/dist/report/render/report-page/report-page-renderer.js +129 -0
  262. package/dist/report/render/report-page/report-views.js +31 -0
  263. package/dist/report/render/report-page/story-window.js +356 -0
  264. package/dist/report/render/report-page/times.js +25 -0
  265. package/dist/report/render/report-page/to-do-view.js +299 -0
  266. package/dist/report/render/report-page/to-do.js +152 -0
  267. package/dist/report/render/report-page.js +1 -0
  268. package/dist/report/render/session-view.js +250 -0
  269. package/dist/report/render/text-report-renderer.js +981 -0
  270. package/dist/report/render/ui/add-file-popup.js +122 -0
  271. package/dist/report/render/ui/app-sidebar.js +78 -0
  272. package/dist/report/render/ui/ask-panel.js +80 -0
  273. package/dist/report/render/ui/avatar.js +19 -0
  274. package/dist/report/render/ui/backdrop.js +29 -0
  275. package/dist/report/render/ui/brand-mark.js +4 -0
  276. package/dist/report/render/ui/button.js +67 -0
  277. package/dist/report/render/ui/callout.js +20 -0
  278. package/dist/report/render/ui/chat-example.js +17 -0
  279. package/dist/report/render/ui/checklist.js +50 -0
  280. package/dist/report/render/ui/confirm-dialog.js +34 -0
  281. package/dist/report/render/ui/data-table.js +49 -0
  282. package/dist/report/render/ui/drawer.js +25 -0
  283. package/dist/report/render/ui/file-chip.js +37 -0
  284. package/dist/report/render/ui/fold-line.js +22 -0
  285. package/dist/report/render/ui/guide-card.js +25 -0
  286. package/dist/report/render/ui/hero.js +37 -0
  287. package/dist/report/render/ui/labelled-select.js +10 -0
  288. package/dist/report/render/ui/live-script.js +222 -0
  289. package/dist/report/render/ui/local-date.js +58 -0
  290. package/dist/report/render/ui/mode-icon.js +6 -0
  291. package/dist/report/render/ui/page-shell.js +101 -0
  292. package/dist/report/render/ui/pill-tabs.js +47 -0
  293. package/dist/report/render/ui/popup.js +77 -0
  294. package/dist/report/render/ui/progress.js +35 -0
  295. package/dist/report/render/ui/project-list.js +284 -0
  296. package/dist/report/render/ui/scope-choice.js +19 -0
  297. package/dist/report/render/ui/stats.js +21 -0
  298. package/dist/report/render/ui/status-icon.js +30 -0
  299. package/dist/report/render/ui/status-look.js +21 -0
  300. package/dist/report/render/ui/switch.js +11 -0
  301. package/dist/report/render/ui/tag.js +19 -0
  302. package/dist/report/render/ui/task-list.js +56 -0
  303. package/dist/report/render/ui/tokens.js +46 -0
  304. package/dist/report/render/ui/update-notice.js +146 -0
  305. package/dist/report/render/ui/words/app-words.js +163 -0
  306. package/dist/report/render/ui/words/conversations-words.js +457 -0
  307. package/dist/report/render/ui/words/month-words.js +59 -0
  308. package/dist/report/render/ui/words/onboarding-words.js +446 -0
  309. package/dist/report/render/ui/words/projects-words.js +217 -0
  310. package/dist/report/render/ui/words/report-words.js +2099 -0
  311. package/dist/report/render/ui/words/settings-words.js +611 -0
  312. package/dist/report/render/ui/words/to-fix-words.js +287 -0
  313. package/dist/report/report-model.js +2 -0
  314. package/dist/report/report-use-case.js +1 -0
  315. package/dist/report/rule-names.js +20 -0
  316. package/dist/report/session-report.js +163 -0
  317. package/dist/report/start/app-nav.js +37 -0
  318. package/dist/report/start/conversations/calendar-view.js +104 -0
  319. package/dist/report/start/conversations/conversation-columns.js +187 -0
  320. package/dist/report/start/conversations/conversations-renderer.js +54 -0
  321. package/dist/report/start/conversations/empty-week.js +120 -0
  322. package/dist/report/start/conversations/files-window.js +166 -0
  323. package/dist/report/start/conversations/period-section.js +280 -0
  324. package/dist/report/start/conversations/periods-script.js +440 -0
  325. package/dist/report/start/conversations/periods.js +110 -0
  326. package/dist/report/start/conversations/week-view.js +30 -0
  327. package/dist/report/start/conversations/weeks.js +17 -0
  328. package/dist/report/start/month/month-renderer.js +50 -0
  329. package/dist/report/start/month/month-view.js +135 -0
  330. package/dist/report/start/month/months.js +17 -0
  331. package/dist/report/start/onboarding/done.js +171 -0
  332. package/dist/report/start/onboarding/finish-onboarding.js +93 -0
  333. package/dist/report/start/onboarding/intro.js +100 -0
  334. package/dist/report/start/onboarding/onboarding-changes.js +40 -0
  335. package/dist/report/start/onboarding/onboarding-renderer.js +195 -0
  336. package/dist/report/start/onboarding/onboarding-script.js +400 -0
  337. package/dist/report/start/onboarding/onboarding-view.js +98 -0
  338. package/dist/report/start/onboarding/project-step.js +210 -0
  339. package/dist/report/start/onboarding/steps.js +239 -0
  340. package/dist/report/start/onboarding/welcome.js +66 -0
  341. package/dist/report/start/page-notice.js +10 -0
  342. package/dist/report/start/projects/index-projects.js +43 -0
  343. package/dist/report/start/projects/moved-page.js +82 -0
  344. package/dist/report/start/projects/project-switch.js +138 -0
  345. package/dist/report/start/projects/projects-window.js +67 -0
  346. package/dist/report/start/projects/temporary-space.js +18 -0
  347. package/dist/report/start/render/air-datepicker-vendor.js +27 -0
  348. package/dist/report/start/render/session-status.js +41 -0
  349. package/dist/report/start/render/start-words.js +84 -0
  350. package/dist/report/start/repository.js +28 -0
  351. package/dist/report/start/serve/index-handler.js +372 -0
  352. package/dist/report/start/serve/onboarding-request.js +50 -0
  353. package/dist/report/start/serve/settings-request.js +1 -0
  354. package/dist/report/start/serve/settings-setup.js +193 -0
  355. package/dist/report/start/session-index.js +1 -0
  356. package/dist/report/start/session-start.js +974 -0
  357. package/dist/report/start/settings/alerts-tab.js +104 -0
  358. package/dist/report/start/settings/files-tab.js +169 -0
  359. package/dist/report/start/settings/general-tab.js +71 -0
  360. package/dist/report/start/settings/settings-renderer.js +254 -0
  361. package/dist/report/start/settings/settings-script.js +161 -0
  362. package/dist/report/start/settings/settings-view.js +240 -0
  363. package/dist/report/start/settings/settings-windows.js +334 -0
  364. package/dist/report/start/settings-files.js +43 -0
  365. package/dist/report/start/to-fix/done-list.js +45 -0
  366. package/dist/report/start/to-fix/file-window.js +110 -0
  367. package/dist/report/start/to-fix/to-fix-list.js +70 -0
  368. package/dist/report/start/to-fix/to-fix-renderer.js +237 -0
  369. package/dist/report/start/to-fix/to-fix-script.js +94 -0
  370. package/dist/report/start/to-fix/to-fix-view.js +124 -0
  371. package/dist/report/watch/agent-alert.js +72 -0
  372. package/dist/report/watch/notice-choices.js +35 -0
  373. package/dist/report/watch/notice-settings.js +65 -0
  374. package/dist/report/watch/preferences.js +100 -0
  375. package/dist/report/watch/render/instruction-words.js +54 -0
  376. package/dist/report/watch/render/notice-words.js +182 -0
  377. package/dist/report/watch/subagent-watch.js +345 -0
  378. package/dist/report/watch/watch-notice.js +1 -0
  379. package/dist/setup/behind.js +18 -0
  380. package/dist/setup/codex-mirror.js +171 -0
  381. package/dist/setup/not-a-project.js +19 -0
  382. package/dist/setup/project-setup.js +644 -0
  383. package/dist/setup/protected-patterns.js +30 -0
  384. package/dist/shared/colour.js +23 -0
  385. package/dist/shared/compare.js +4 -0
  386. package/dist/shared/content-version.js +13 -0
  387. package/dist/shared/counter.js +11 -0
  388. package/dist/shared/file-stamp.js +4 -0
  389. package/dist/shared/json.js +13 -0
  390. package/dist/shared/label.js +13 -0
  391. package/dist/shared/package-name.js +6 -0
  392. package/dist/shared/plain-invocation.js +44 -0
  393. package/dist/shared/plain-version.js +21 -0
  394. package/dist/shared/printable.js +25 -0
  395. package/dist/shared/renderer.js +1 -0
  396. package/dist/shared/sentence.js +20 -0
  397. package/dist/shared/terminal-logo.js +41 -0
  398. package/dist/shared/text-table.js +15 -0
  399. package/dist/shared/wrap.js +29 -0
  400. package/package.json +70 -0
@@ -0,0 +1,614 @@
1
+ import { FileAccessError } from '../../../ports/file-access-error.js';
2
+ import { isJsonObject, parseJsonObject } from '../../../shared/json.js';
3
+ import { ITEM, ITEM_EVENT } from '../contract/actions.js';
4
+ import { ACTIVITY, AGENT_MESSAGE, DELEGATION_TOOLS, SPAWN_ARGUMENTS } from '../contract/delegations.js';
5
+ import { CODE_CELL, FUNCTION_CALL } from '../contract/deliveries.js';
6
+ import { ENVELOPE, LINE_TYPES, PASSIVE_EVENTS, PASSIVE_LINE_TYPES } from '../contract/envelope.js';
7
+ import { EVENT_MESSAGES, ITEM_TEXT_BLOCKS, MESSAGE, MESSAGE_ITEMS, PHASES, REASONING, REASONING_ITEM, RESPONSE_ITEMS, ROLES, TEXT_BLOCKS, } from '../contract/messages.js';
8
+ import { VERDICT } from '../contract/reviews.js';
9
+ import { SESSION } from '../contract/session.js';
10
+ import { RESPONSE_TURN, TURN_CONTEXT, TURN_EVENTS } from '../contract/turns.js';
11
+ import { HOOK_REFUSAL } from '../contract/hook-refusals.js';
12
+ import { PRE_TOOL_USE } from '../contract/hooks.js';
13
+ import { isActionItem, readAction } from './action-items.js';
14
+ import { hookRefusalsIn } from './hook-refusals.js';
15
+ import { capabilitiesOf } from './capability-records.js';
16
+ import { permissionsOf } from './turn-permissions.js';
17
+ /**
18
+ * One rollout file, read line by line into the collection. Only top-level lines are records (X13); order is the line's
19
+ * position, and time is shown only (X12). What joins what inside the file - a cell and its output by `call_id`, a copy of a
20
+ * message by its `id` - is read here, where the format says it; every relation between agents is left to the core.
21
+ */
22
+ export async function scanRollout(files, path, role, collected) {
23
+ const state = new FileState(role, collected);
24
+ try {
25
+ for await (const raw of files.readLines(path)) {
26
+ if (raw.trim() === '')
27
+ continue;
28
+ state.line(raw);
29
+ }
30
+ }
31
+ catch (error) {
32
+ if (!(error instanceof FileAccessError))
33
+ throw error;
34
+ collected.gaps.push({ kind: 'source-missing', ...(role.kind === 'agent' ? { agentId: role.agentId } : { source: role.source }) });
35
+ }
36
+ state.finish();
37
+ }
38
+ class FileState {
39
+ #role;
40
+ #collected;
41
+ #record = 0;
42
+ #calls = new Map();
43
+ #outputs = [];
44
+ #itemIds = new Set();
45
+ #actionCalls = [];
46
+ #said = [];
47
+ #reasoning = new Map();
48
+ #agentItems = [];
49
+ #completions = [];
50
+ #reviewedTurns = new Map();
51
+ #verdicts = [];
52
+ #unrecognised = false;
53
+ #interrupted = false;
54
+ #hiddenReasoning = false;
55
+ #permissionsRecorded = false;
56
+ #permissionsIncomplete = false;
57
+ #reviewerActions = false;
58
+ #firstEvidence;
59
+ constructor(role, collected) {
60
+ this.#role = role;
61
+ this.#collected = collected;
62
+ }
63
+ line(raw) {
64
+ this.#record += 1;
65
+ const line = parseJsonObject(raw);
66
+ const agentGap = this.#role.kind === 'agent' ? { agentId: this.#role.agentId } : { source: this.#role.source };
67
+ if (line === undefined) {
68
+ this.#collected.gaps.push({ kind: 'record-damaged', ...agentGap });
69
+ return;
70
+ }
71
+ const stamp = line[ENVELOPE.recordedAt];
72
+ const time = typeof stamp === 'string' ? Date.parse(stamp) : Number.NaN;
73
+ const evidence = { source: this.#role.source, record: this.#record, ...(Number.isFinite(time) ? { at: time } : {}) };
74
+ this.#firstEvidence ??= evidence;
75
+ const payload = line[ENVELOPE.payload];
76
+ if (!isJsonObject(payload)) {
77
+ this.#collected.gaps.push({ kind: 'record-damaged', ...agentGap });
78
+ return;
79
+ }
80
+ switch (line[ENVELOPE.type]) {
81
+ case LINE_TYPES.sessionMeta:
82
+ // A later session_meta never changes whose file this is (X3); its directory is a directory the records carried.
83
+ this.#directory(payload[SESSION.workingDirectory]);
84
+ return;
85
+ case LINE_TYPES.turnContext:
86
+ this.#turn(payload, evidence);
87
+ return;
88
+ case LINE_TYPES.responseItem:
89
+ this.#response(payload, evidence);
90
+ return;
91
+ case LINE_TYPES.event:
92
+ this.#event(payload, evidence);
93
+ return;
94
+ case LINE_TYPES.tokenUsage:
95
+ this.#reviewed(payload[TURN_EVENTS.turnId], payload[TURN_EVENTS.rootTurnId]);
96
+ return;
97
+ default:
98
+ if (!PASSIVE_LINE_TYPES.some((type) => type === line[ENVELOPE.type]))
99
+ this.#unrecognised = true;
100
+ }
101
+ }
102
+ #directory(value) {
103
+ if (typeof value === 'string' && value !== '')
104
+ this.#collected.workingDirectories.add(value);
105
+ }
106
+ #turn(payload, evidence) {
107
+ this.#directory(payload[TURN_CONTEXT.workingDirectory]);
108
+ this.#reviewed(payload[TURN_CONTEXT.turnId], payload[TURN_EVENTS.rootTurnId]);
109
+ const id = payload[TURN_CONTEXT.turnId];
110
+ if (this.#role.kind !== 'agent' || typeof id !== 'string' || id === '')
111
+ return;
112
+ const permissions = permissionsOf(payload);
113
+ this.#permissionsRecorded = true;
114
+ if (!permissions.complete)
115
+ this.#permissionsIncomplete = true;
116
+ this.#collected.turns.push({ id, agentId: this.#role.agentId, permissions, evidence });
117
+ }
118
+ /** On a reviewer's turn, the turn of the agent it reviewed (X19). Two different answers for one turn answer nothing. */
119
+ #reviewed(turnId, rootTurnId) {
120
+ if (this.#role.kind !== 'reviewer' || typeof turnId !== 'string' || typeof rootTurnId !== 'string')
121
+ return;
122
+ const known = this.#reviewedTurns.get(turnId);
123
+ this.#reviewedTurns.set(turnId, known === undefined || known === rootTurnId ? rootTurnId : null);
124
+ }
125
+ #response(payload, evidence) {
126
+ const turnId = turnOf(payload);
127
+ switch (payload[ENVELOPE.payloadType]) {
128
+ case RESPONSE_ITEMS.message:
129
+ this.#message(payload, evidence, turnId);
130
+ return;
131
+ case RESPONSE_ITEMS.reasoning:
132
+ this.#reasoningRecord(payload, evidence, turnId);
133
+ return;
134
+ case RESPONSE_ITEMS.codeCell:
135
+ case RESPONSE_ITEMS.functionCall:
136
+ this.#call(payload, evidence, turnId);
137
+ return;
138
+ case RESPONSE_ITEMS.codeCellOutput:
139
+ case RESPONSE_ITEMS.functionOutput:
140
+ this.#output(payload, evidence, turnId);
141
+ return;
142
+ case RESPONSE_ITEMS.agentMessage:
143
+ this.#agentMessage(payload, evidence, turnId);
144
+ return;
145
+ case RESPONSE_ITEMS.compaction:
146
+ return;
147
+ default:
148
+ this.#unrecognised = true;
149
+ }
150
+ }
151
+ /** X31: assistant text is the agent's own words - a reviewer's are its own, never its parent's; any other role is context. */
152
+ #message(payload, evidence, turnId) {
153
+ const role = payload[MESSAGE.role];
154
+ const words = textOf(payload[MESSAGE.content], role === ROLES.assistant ? [TEXT_BLOCKS.said] : [TEXT_BLOCKS.given]);
155
+ if (role === ROLES.assistant && this.#role.kind === 'agent') {
156
+ const id = payload[MESSAGE.id];
157
+ const phase = payload[MESSAGE.phase];
158
+ const channel = typeof phase === 'string' && Object.hasOwn(PHASES, phase) ? PHASES[phase] : undefined;
159
+ this.#said.push({
160
+ message: {
161
+ agentId: this.#role.agentId, kind: 'said', text: words.text, completeness: words.completeness, evidence,
162
+ ...(typeof id === 'string' && id !== '' ? { id } : {}), ...(channel === undefined ? {} : { channel }),
163
+ },
164
+ ...(turnId === undefined ? {} : { turnId }),
165
+ copies: [],
166
+ });
167
+ return;
168
+ }
169
+ const author = this.#role.kind === 'reviewer'
170
+ ? (role === ROLES.assistant ? 'reviewer' : 'runtime')
171
+ : role === ROLES.user ? 'person' : role === ROLES.developer ? 'developer' : 'unknown';
172
+ this.#context('conversation', author, words.text, words.completeness, evidence, turnId);
173
+ }
174
+ /** X31: readable summary text is reasoning, never the whole of it; encrypted content is never read or guessed. */
175
+ #reasoningRecord(payload, evidence, turnId) {
176
+ const summary = payload[REASONING.summary];
177
+ const parts = Array.isArray(summary)
178
+ ? summary.flatMap((part) => (isJsonObject(part) && typeof part[REASONING.summaryText] === 'string' && part[REASONING.summaryText] !== '' ? [part[REASONING.summaryText]] : []))
179
+ : [];
180
+ const id = payload[MESSAGE.id];
181
+ // A reviewer's thoughts are its own, never its parent's (X19): context, whatever it wrote.
182
+ if (this.#role.kind !== 'agent') {
183
+ if (parts.length > 0)
184
+ this.#context('conversation', 'reviewer', parts.join('\n'), 'partial', evidence, turnId);
185
+ return;
186
+ }
187
+ if (parts.length === 0) {
188
+ this.#hiddenReasoning = true;
189
+ if (typeof id === 'string')
190
+ this.#reasoning.set(id, 'hidden');
191
+ return;
192
+ }
193
+ const encrypted = typeof payload[REASONING.encrypted] === 'string';
194
+ if (encrypted)
195
+ this.#hiddenReasoning = true;
196
+ const said = {
197
+ message: {
198
+ agentId: this.#role.agentId, kind: 'reasoning', text: parts.join('\n'),
199
+ completeness: encrypted ? 'partial' : 'complete', evidence, ...(typeof id === 'string' && id !== '' ? { id } : {}),
200
+ },
201
+ ...(turnId === undefined ? {} : { turnId }),
202
+ copies: [],
203
+ };
204
+ this.#said.push(said);
205
+ if (typeof id === 'string' && id !== '')
206
+ this.#reasoning.set(id, said);
207
+ }
208
+ #call(payload, evidence, turnId) {
209
+ const callId = payload[CODE_CELL.callId];
210
+ const name = payload[FUNCTION_CALL.name];
211
+ const cell = payload[ENVELOPE.payloadType] === RESPONSE_ITEMS.codeCell && name === CODE_CELL.tool;
212
+ const code = payload[CODE_CELL.code];
213
+ // X14: the cell is context - the code the agent wrote, never an action, never joined to what it ran.
214
+ if (cell && typeof code === 'string')
215
+ this.#context('code', this.#role.kind === 'reviewer' ? 'reviewer' : 'agent', code, 'complete', evidence, turnId);
216
+ if (typeof callId !== 'string' || callId === '') {
217
+ if (!cell)
218
+ this.#unrecognised = true;
219
+ return;
220
+ }
221
+ const args = payload[FUNCTION_CALL.arguments];
222
+ const input = typeof args === 'string' ? (parseJsonObject(args) ?? { arguments: args }) : isJsonObject(args) ? args : cell ? {} : { input: code };
223
+ const kind = cell
224
+ ? 'cell'
225
+ : name === DELEGATION_TOOLS.spawn ? 'spawn' : name === DELEGATION_TOOLS.send || name === DELEGATION_TOOLS.followUp ? 'follow-up' : 'direct';
226
+ // XB9: whatever a reviewer ran is unmeasured, and never its parent's.
227
+ if (this.#role.kind === 'reviewer')
228
+ this.#reviewerActions = true;
229
+ this.#calls.set(callId, {
230
+ kind, id: callId, evidence, toolName: typeof name === 'string' ? name : 'unrecognised call', input, ...(turnId === undefined ? {} : { turnId }),
231
+ });
232
+ if (this.#role.kind !== 'agent')
233
+ return;
234
+ if (kind === 'spawn') {
235
+ const message = input[SPAWN_ARGUMENTS.message];
236
+ const task = input[SPAWN_ARGUMENTS.name];
237
+ this.#collected.delegations.push({
238
+ callId: this.#scoped(callId), parentAgentId: this.#role.agentId, evidence,
239
+ ...(typeof message === 'string' ? { prompt: message } : {}), ...(typeof task === 'string' ? { description: task } : {}),
240
+ });
241
+ }
242
+ // X17: its words are raw content, as the call carried them - the arguments whose message key XB4 has not measured.
243
+ if (kind === 'follow-up') {
244
+ this.#collected.followUps.push({
245
+ callId: this.#scoped(callId), senderAgentId: this.#role.agentId, evidence, text: typeof args === 'string' ? args : JSON.stringify(args ?? null),
246
+ });
247
+ }
248
+ }
249
+ #output(payload, evidence, turnId) {
250
+ const callId = payload[CODE_CELL.callId];
251
+ const read = outputText(payload[CODE_CELL.output]);
252
+ const kind = payload[ENVELOPE.payloadType] === RESPONSE_ITEMS.codeCellOutput ? 'cell' : 'function';
253
+ if (typeof callId !== 'string' || callId === '') {
254
+ this.#orphan(read, evidence, turnId);
255
+ return;
256
+ }
257
+ this.#outputs.push({ kind, output: { callId, ...read, evidence, ...(turnId === undefined ? {} : { turnId }) } });
258
+ }
259
+ /** X18: a report is by its author's `agent_path`, a name; a name two children share names neither. */
260
+ #agentMessage(payload, evidence, turnId) {
261
+ const content = payload[AGENT_MESSAGE.content];
262
+ const words = typeof content === 'string' ? { text: content, completeness: 'complete' } : textOf(content, [TEXT_BLOCKS.given, TEXT_BLOCKS.said]);
263
+ const author = payload[AGENT_MESSAGE.author];
264
+ const child = typeof author === 'string' && this.#role.childByPath.has(author) ? { found: this.#role.childByPath.get(author) } : undefined;
265
+ if (this.#role.kind === 'agent' && child?.found !== undefined) {
266
+ this.#collected.agentReports.push({ fromAgentId: child.found, recipientAgentId: this.#role.agentId, content: words.text, evidence });
267
+ return;
268
+ }
269
+ if (child !== undefined)
270
+ this.#collected.gaps.push({ kind: 'relation-unresolved', agentId: this.#role.agentId });
271
+ this.#context('conversation', 'another-agent', words.text, words.completeness, evidence, turnId);
272
+ }
273
+ #event(payload, evidence) {
274
+ const type = payload[ENVELOPE.payloadType];
275
+ const turnId = typeof payload[TURN_EVENTS.turnId] === 'string' ? payload[TURN_EVENTS.turnId] : undefined;
276
+ if (type === ITEM_EVENT.type) {
277
+ const item = payload[ITEM_EVENT.item];
278
+ if (isJsonObject(item))
279
+ this.#item(item, evidence, turnId);
280
+ else
281
+ this.#unrecognised = true;
282
+ return;
283
+ }
284
+ if (type === TURN_EVENTS.started) {
285
+ this.#reviewed(turnId, payload[TURN_EVENTS.rootTurnId]);
286
+ return;
287
+ }
288
+ if (type === TURN_EVENTS.complete) {
289
+ const last = payload[TURN_EVENTS.lastMessage];
290
+ if (this.#role.kind === 'reviewer')
291
+ this.#verdicts.push({ ...(turnId === undefined ? {} : { turnId }), text: last, evidence });
292
+ else if (typeof last === 'string' && last !== '')
293
+ this.#completions.push({ ...(turnId === undefined ? {} : { turnId }), text: last, evidence });
294
+ return;
295
+ }
296
+ // Copies the editor builds wrote: no source rule is measured for them, so they stay context (X31).
297
+ if (type === EVENT_MESSAGES.user || type === EVENT_MESSAGES.agent) {
298
+ const text = payload[EVENT_MESSAGES.text];
299
+ if (typeof text !== 'string')
300
+ return;
301
+ if (type === EVENT_MESSAGES.agent && this.#role.kind === 'agent') {
302
+ this.#collected.gaps.push({ kind: 'relation-unresolved', agentId: this.#role.agentId });
303
+ this.#context('conversation', 'agent', text, 'complete', evidence, turnId);
304
+ }
305
+ else
306
+ this.#context('conversation', type === EVENT_MESSAGES.user ? 'person' : 'reviewer', text, 'complete', evidence, turnId);
307
+ return;
308
+ }
309
+ // X14: an interrupted turn cannot show that what it recorded is all it ran, however well its records parse.
310
+ if (type === TURN_EVENTS.aborted) {
311
+ this.#interrupted = true;
312
+ return;
313
+ }
314
+ if (PASSIVE_EVENTS.some((each) => each === type))
315
+ return;
316
+ // `patch_apply_end`, `web_search_end` and anything else: records of something done that the contract cannot map.
317
+ this.#unrecognised = true;
318
+ this.#orphan({ text: JSON.stringify(payload), completeness: 'unknown' }, evidence, turnId, 'runtime');
319
+ }
320
+ #item(item, evidence, turnId) {
321
+ const type = item[ITEM.type];
322
+ const id = item[ITEM.id];
323
+ if (type === ACTIVITY.type) {
324
+ this.#activity(item);
325
+ return;
326
+ }
327
+ if (type === MESSAGE_ITEMS.agent) {
328
+ this.#agentItems.push({ id, evidence, text: textOf(item[MESSAGE.content], ITEM_TEXT_BLOCKS).text });
329
+ return;
330
+ }
331
+ if (type === MESSAGE_ITEMS.user) {
332
+ const words = textOf(item[MESSAGE.content], ITEM_TEXT_BLOCKS);
333
+ this.#context('conversation', this.#role.kind === 'reviewer' ? 'runtime' : 'person', words.text, words.completeness, evidence, turnId);
334
+ return;
335
+ }
336
+ if (type === MESSAGE_ITEMS.reasoning) {
337
+ this.#reasoningItem(item, evidence, turnId);
338
+ return;
339
+ }
340
+ if (type === MESSAGE_ITEMS.compaction || type === MESSAGE_ITEMS.functionOutput)
341
+ return;
342
+ // X6: an action item; one the contract does not name is read as an unknown tool, with a gap.
343
+ if (!isActionItem(type))
344
+ this.#unrecognised = true;
345
+ if (this.#role.kind === 'reviewer') {
346
+ // X19, XB9: a reviewer's own actions are neither its parent's nor dropped: kept, scanned, and said as unmeasured.
347
+ this.#reviewerActions = true;
348
+ this.#context('conversation', 'reviewer', JSON.stringify(item), 'unknown', evidence, turnId);
349
+ return;
350
+ }
351
+ if (typeof id !== 'string' || id === '') {
352
+ this.#unrecognised = true;
353
+ this.#orphan({ text: JSON.stringify(item), completeness: 'unknown' }, evidence, turnId, 'tool');
354
+ return;
355
+ }
356
+ this.#itemIds.add(id);
357
+ const action = readAction(item);
358
+ for (const question of action.unanswered) {
359
+ this.#collected.gaps.push({ kind: 'capability-absent', question, agentId: this.#role.agentId });
360
+ }
361
+ const callId = this.#scoped(id);
362
+ this.#actionCalls.push({
363
+ call: {
364
+ id: callId, agentId: this.#role.agentId, toolName: action.toolName, input: action.input, targets: action.targets,
365
+ commands: action.commands, resultShape: action.resultShape, toolKnown: action.toolKnown,
366
+ ...(action.written === undefined ? {} : { written: action.written }), ...(turnId === undefined ? {} : { turnId }), evidence,
367
+ },
368
+ // The item is both the call and what came back (X6). What it printed is the execution stage: never delivered by itself.
369
+ result: {
370
+ callId, stage: 'execution', completeness: action.output?.completeness ?? 'complete', execution: action.execution, evidence,
371
+ ...(action.output === undefined ? {} : { content: action.output.text }),
372
+ },
373
+ });
374
+ }
375
+ /** X16, X17: `started` names the agent a spawn started, `interacted` the agent a later call reached, by the call's id. */
376
+ #activity(item) {
377
+ const kind = item[ACTIVITY.kind];
378
+ const id = item[ITEM.id];
379
+ const thread = item[ACTIVITY.agentThreadId];
380
+ if (this.#role.kind !== 'agent' || typeof id !== 'string' || typeof thread !== 'string' || thread === '')
381
+ return;
382
+ if (kind === ACTIVITY.kinds.started) {
383
+ const header = this.#role.threads.get(thread);
384
+ const origin = header?.origin.kind === 'spawned' ? header.origin : undefined;
385
+ this.#collected.delegationIndex.push({
386
+ callId: this.#scoped(id), agentId: thread,
387
+ ...(origin === undefined ? {} : { requestedType: origin.role ?? 'subagent' }),
388
+ ...(origin?.depth === undefined ? {} : { depth: origin.depth }),
389
+ ...(header?.parent.kind === 'parent' ? { recordedParentAgentId: header.parent.id } : {}),
390
+ });
391
+ }
392
+ else if (kind === ACTIVITY.kinds.interacted) {
393
+ this.#collected.followUpIndex.push({ callId: this.#scoped(id), agentId: thread });
394
+ }
395
+ }
396
+ #reasoningItem(item, evidence, turnId) {
397
+ const id = item[ITEM.id];
398
+ const joined = typeof id === 'string' ? this.#reasoning.get(id) : undefined;
399
+ const readable = [item[REASONING_ITEM.summary], item[REASONING_ITEM.raw]]
400
+ .flatMap((list) => (Array.isArray(list) ? list : []))
401
+ .flatMap((part) => (typeof part === 'string' ? [part] : isJsonObject(part) && typeof part[MESSAGE.blockText] === 'string' ? [part[MESSAGE.blockText]] : []))
402
+ .filter((text) => text !== '');
403
+ // A copy holds nothing its reasoning does not: no readable text, or the same text but for whitespace at its ends. Text
404
+ // that differs is not dropped as a copy - it may hold what the reasoning does not - and is kept below with a gap.
405
+ if (joined !== undefined && joined !== 'hidden' && (readable.length === 0 || readable.join('\n').trim() === joined.message.text.trim())) {
406
+ joined.copies.push(evidence);
407
+ return;
408
+ }
409
+ if (readable.length === 0)
410
+ return;
411
+ // The id joins a reasoning record that held no readable text: this is its summary, and the encrypted rest stays unread.
412
+ if (joined === 'hidden' && typeof id === 'string' && this.#role.kind === 'agent') {
413
+ const said = {
414
+ message: { agentId: this.#role.agentId, kind: 'reasoning', text: readable.join('\n'), completeness: 'partial', evidence, id },
415
+ ...(turnId === undefined ? {} : { turnId }),
416
+ copies: [],
417
+ };
418
+ this.#said.push(said);
419
+ this.#reasoning.set(id, said);
420
+ return;
421
+ }
422
+ // Readable text that joins no reasoning record: kept, scanned, and not counted as the agent's words (X31).
423
+ this.#collected.gaps.push({ kind: 'relation-unresolved', ...(this.#role.kind === 'agent' ? { agentId: this.#role.agentId } : { source: this.#role.source }) });
424
+ this.#context('conversation', this.#role.kind === 'agent' ? 'agent' : 'reviewer', readable.join('\n'), 'partial', evidence, turnId);
425
+ }
426
+ #context(kind, author, text, completeness, evidence, turnId) {
427
+ if (text === '' && completeness === 'complete')
428
+ return;
429
+ this.#collected.contexts.push({
430
+ kind, author, text, completeness, evidence, ...(turnId === undefined ? {} : { turnId }),
431
+ // A reviewer's records are named by their `review` source: a reviewer is no agent (X19).
432
+ ...(this.#role.kind === 'agent' ? { agentId: this.#role.agentId } : {}),
433
+ });
434
+ }
435
+ /** X6: an output no call joins is counted and kept, attributed to nothing, with a gap. */
436
+ #orphan(read, evidence, turnId, author = 'tool') {
437
+ this.#collected.gaps.push({ kind: 'relation-unresolved', ...(this.#role.kind === 'agent' ? { agentId: this.#role.agentId } : { source: this.#role.source }) });
438
+ this.#context('orphan-output', author, read.text, read.completeness, evidence, turnId);
439
+ }
440
+ #scoped(id) {
441
+ return this.#role.idScope + id;
442
+ }
443
+ finish() {
444
+ if (this.#role.kind === 'agent')
445
+ this.#finishAgent();
446
+ else
447
+ this.#finishReviewer();
448
+ // A reviewer is no agent (X19): its source names it, and no agent id does.
449
+ const agentId = this.#role.kind === 'agent' ? this.#role.agentId : undefined;
450
+ this.#collected.capabilities.push(...capabilitiesOf(this.#role.header, this.#role.source, agentId, {
451
+ unrecognised: this.#unrecognised,
452
+ interrupted: this.#interrupted,
453
+ hiddenReasoning: this.#hiddenReasoning,
454
+ permissionsIncomplete: this.#permissionsIncomplete,
455
+ permissionsRecorded: this.#permissionsRecorded,
456
+ }));
457
+ }
458
+ #finishAgent() {
459
+ const agentId = this.#role.agentId;
460
+ const calls = [...this.#actionCalls];
461
+ for (const call of this.#calls.values()) {
462
+ // A direct call its action item answers is that item: one action, never two (X6).
463
+ if (call.kind === 'cell' || call.kind === 'follow-up' || (call.kind === 'direct' && this.#itemIds.has(call.id)))
464
+ continue;
465
+ calls.push({
466
+ call: {
467
+ id: this.#scoped(call.id), agentId, toolName: call.toolName, input: call.input, targets: [], commands: [], resultShape: 'none',
468
+ toolKnown: call.kind === 'spawn', evidence: call.evidence, ...(call.turnId === undefined ? {} : { turnId: call.turnId }),
469
+ },
470
+ });
471
+ }
472
+ for (const { kind, output } of this.#outputs) {
473
+ const call = this.#calls.get(output.callId);
474
+ if (call === undefined) {
475
+ this.#orphan(output, output.evidence, output.turnId);
476
+ continue;
477
+ }
478
+ const turn = output.turnId === undefined ? {} : { turnId: output.turnId };
479
+ // X10: a cell's output is what the agent's model was handed, from no action any id names.
480
+ if (kind === 'cell' && call.kind === 'cell') {
481
+ this.#collected.deliveries.push({ recipientAgentId: agentId, status: 'confirmed', text: output.text, completeness: output.completeness, evidence: output.evidence, ...turn });
482
+ // `codex-blocks-too` CK12: a command agentwhy's hook refused ran nowhere and left no item; its one trace is agentwhy's
483
+ // own reason in this output. Each is a call of the shell - named as Codex names it to a hook (CKB2) - refused
484
+ // before it ran, on the path the reason names.
485
+ hookRefusalsIn(output.text).forEach((refusal, at) => {
486
+ const id = `${this.#scoped(call.id)}:refused:${at + 1}`;
487
+ calls.push({
488
+ call: {
489
+ id, agentId, toolName: PRE_TOOL_USE.shellTool, input: refusal.command === undefined ? {} : { command: refusal.command },
490
+ targets: [refusal.path], commands: refusal.command === undefined ? [] : [refusal.command], resultShape: 'listing', toolKnown: true,
491
+ evidence: output.evidence, ...turn,
492
+ },
493
+ result: {
494
+ callId: id, content: refusal.reason, stage: 'model', completeness: 'complete', evidence: output.evidence,
495
+ denial: { kind: HOOK_REFUSAL.denialKind, recognised: true },
496
+ },
497
+ });
498
+ });
499
+ }
500
+ else if (call.kind === 'follow-up' || (call.kind === 'direct' && this.#itemIds.has(call.id))) {
501
+ this.#collected.deliveries.push({
502
+ recipientAgentId: agentId, sourceId: this.#scoped(call.id), status: 'confirmed', text: output.text, completeness: output.completeness, evidence: output.evidence, ...turn,
503
+ });
504
+ }
505
+ else {
506
+ this.#collected.results.push({
507
+ callId: this.#scoped(call.id), content: output.text, stage: 'model', completeness: output.completeness, evidence: output.evidence,
508
+ // A spawn's output says only that the agent started; what it did comes back as its reports (§2.4).
509
+ ...(call.kind === 'spawn' ? { launchNotice: true } : {}),
510
+ });
511
+ }
512
+ }
513
+ for (const { result } of calls)
514
+ if (result !== undefined)
515
+ this.#collected.results.push(result);
516
+ calls.sort((first, second) => first.call.evidence.record - second.call.evidence.record);
517
+ calls.forEach(({ call }, index) => this.#collected.calls.push({ ...call, sequence: index + 1 }));
518
+ this.#joinCopies();
519
+ this.#collected.messages.push(...this.#said.map(({ message, copies }) => (copies.length === 0 ? message : { ...message, copies })));
520
+ }
521
+ /**
522
+ * X31: an `AgentMessage` item is a copy of the message with its `id`. A `task_complete` text carries no id, so it is a
523
+ * copy only of the one final answer of its turn whose text it equals but for whitespace at its ends, as it did in 6 of 6
524
+ * (§2.8). Whatever joins nothing
525
+ * - a text that differs among them - is kept as context with a gap, and never counted as a second utterance.
526
+ */
527
+ #joinCopies() {
528
+ const byId = new Map(this.#said.filter(({ message }) => message.kind === 'said' && message.id !== undefined).map((said) => [said.message.id, said]));
529
+ for (const item of this.#agentItems) {
530
+ const said = typeof item.id === 'string' ? byId.get(item.id) : undefined;
531
+ if (said !== undefined)
532
+ said.copies.push(item.evidence);
533
+ else
534
+ this.#uncertainCopy(item.text, item.evidence);
535
+ }
536
+ for (const completion of this.#completions) {
537
+ const finals = this.#said.filter(({ message, turnId }) => message.channel === 'final' && completion.turnId !== undefined && turnId === completion.turnId);
538
+ const final = finals.length === 1 ? finals[0] : undefined;
539
+ // Whitespace at either end holds no value, so a difference there alone does not make the text another one.
540
+ if (final !== undefined && final.message.text.trim() === completion.text.trim())
541
+ final.copies.push(completion.evidence);
542
+ else
543
+ this.#uncertainCopy(completion.text, completion.evidence);
544
+ }
545
+ }
546
+ #uncertainCopy(text, evidence) {
547
+ if (text === '')
548
+ return;
549
+ this.#collected.gaps.push({ kind: 'relation-unresolved', agentId: this.#role.agentId });
550
+ this.#context('conversation', 'agent', text, 'complete', evidence);
551
+ }
552
+ /** X19, X20: every verdict with its own evidence, on the reviewed turn its reviewer's turn names, or on none. */
553
+ #finishReviewer() {
554
+ for (const { output } of this.#outputs)
555
+ this.#context('conversation', 'reviewer', output.text, output.completeness, output.evidence, output.turnId);
556
+ const verdicts = this.#verdicts.map(({ turnId, text, evidence }) => {
557
+ const reviewed = turnId === undefined ? undefined : this.#reviewedTurns.get(turnId);
558
+ if (reviewed === null)
559
+ this.#collected.gaps.push({ kind: 'relation-unresolved', source: this.#role.source });
560
+ const verdict = typeof text === 'string' ? parseJsonObject(text) : undefined;
561
+ if (verdict === undefined && typeof text === 'string')
562
+ this.#context('conversation', 'reviewer', text, 'complete', evidence, turnId);
563
+ const risk = verdict?.[VERDICT.risk];
564
+ const rationale = verdict?.[VERDICT.rationale];
565
+ return {
566
+ outcome: verdict?.[VERDICT.outcome] === VERDICT.allowed ? 'allowed' : 'unrecognised',
567
+ ...(typeof reviewed === 'string' ? { turnId: reviewed } : {}),
568
+ ...(typeof risk === 'string' ? { risk } : {}),
569
+ ...(typeof rationale === 'string' ? { rationale } : {}),
570
+ evidence,
571
+ };
572
+ });
573
+ this.#collected.reviews.push({
574
+ id: this.#role.agentId,
575
+ ...(this.#role.reviewedAgentId === undefined ? {} : { reviewedAgentId: this.#role.reviewedAgentId }),
576
+ verdicts,
577
+ evidence: this.#firstEvidence ?? { source: this.#role.source, record: 1 },
578
+ });
579
+ if (this.#reviewerActions)
580
+ this.#collected.capabilities.push({ question: 'actions', state: 'unmeasured', source: this.#role.source });
581
+ }
582
+ }
583
+ /** The turn a response record belongs to, where its metadata carries one (§2.2). */
584
+ function turnOf(payload) {
585
+ const metadata = payload[RESPONSE_TURN.metadata];
586
+ const turn = isJsonObject(metadata) ? metadata[RESPONSE_TURN.turnId] : undefined;
587
+ return typeof turn === 'string' && turn !== '' ? turn : undefined;
588
+ }
589
+ /**
590
+ * The text of content blocks of the listed types. A block of another type, or one whose text is not a string, is not
591
+ * coerced: the text is then `partial` (X10). Content that is no list of blocks is `unknown`.
592
+ */
593
+ function textOf(content, types) {
594
+ if (typeof content === 'string')
595
+ return { text: content, completeness: 'complete' };
596
+ if (!Array.isArray(content))
597
+ return { text: '', completeness: content === undefined ? 'complete' : 'unknown' };
598
+ let whole = true;
599
+ const texts = [];
600
+ for (const block of content) {
601
+ const text = isJsonObject(block) ? block[MESSAGE.blockText] : undefined;
602
+ if (isJsonObject(block) && types.some((type) => type === block[MESSAGE.blockType]) && typeof text === 'string')
603
+ texts.push(text);
604
+ else
605
+ whole = false;
606
+ }
607
+ return { text: texts.join('\n'), completeness: whole ? 'complete' : 'partial' };
608
+ }
609
+ /** A cell's or a call's output: a string, or parts whose text is under `input_text` (§2.8). */
610
+ function outputText(output) {
611
+ if (typeof output === 'string')
612
+ return { text: output, completeness: 'complete' };
613
+ return textOf(output, [CODE_CELL.textPart]);
614
+ }