@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,60 @@
1
+ import { isJsonObject } from '../../../shared/json.js';
2
+ import { APPROVAL_POLICIES, APPROVERS, PERMISSIONS, SANDBOX_TYPES, SCOPE_ACCESS, SCOPE_TARGETS } from '../contract/permissions.js';
3
+ /**
4
+ * The permissions a `turn_context` recorded (X22): kept as recorded settings, apart from agentwhy's policy. A value the
5
+ * contract does not list is not copied into the model - it is said as unrecognised, and the record as incomplete.
6
+ */
7
+ export function permissionsOf(context) {
8
+ let complete = true;
9
+ const known = (value, list) => {
10
+ if (value === undefined)
11
+ return undefined;
12
+ const found = list.find((each) => each === value);
13
+ if (found === undefined)
14
+ complete = false;
15
+ return found;
16
+ };
17
+ const approval = known(context[PERMISSIONS.approval], APPROVAL_POLICIES);
18
+ const approverValue = context[PERMISSIONS.approver];
19
+ const approver = approverValue === undefined
20
+ ? 'unrecorded'
21
+ : typeof approverValue === 'string' && Object.hasOwn(APPROVERS, approverValue)
22
+ ? APPROVERS[approverValue]
23
+ : 'unrecognised';
24
+ if (approver === 'unrecognised')
25
+ complete = false;
26
+ const sandboxPolicy = context[PERMISSIONS.sandbox];
27
+ const sandbox = isJsonObject(sandboxPolicy) ? known(sandboxPolicy[PERMISSIONS.sandboxType], SANDBOX_TYPES) : undefined;
28
+ const networkValue = isJsonObject(sandboxPolicy) ? sandboxPolicy[PERMISSIONS.network] : undefined;
29
+ const network = networkValue === undefined ? 'unrecorded' : networkValue === true ? 'allowed' : networkValue === false ? 'restricted' : 'unrecognised';
30
+ if (network === 'unrecognised')
31
+ complete = false;
32
+ const fileSystem = context[PERMISSIONS.fileSystem];
33
+ const entries = isJsonObject(fileSystem) ? fileSystem[PERMISSIONS.entries] : undefined;
34
+ const scopes = Array.isArray(entries) ? entries.map((entry) => scopeOf(entry, () => { complete = false; })) : [];
35
+ if (fileSystem !== undefined && !Array.isArray(entries))
36
+ complete = false;
37
+ return {
38
+ ...(approval === undefined ? {} : { approval }),
39
+ approver,
40
+ ...(sandbox === undefined ? {} : { sandbox }),
41
+ network,
42
+ scopes,
43
+ complete,
44
+ };
45
+ }
46
+ function scopeOf(entry, unknownPart) {
47
+ const access = isJsonObject(entry) ? SCOPE_ACCESS.find((each) => each === entry[PERMISSIONS.access]) : undefined;
48
+ const target = isJsonObject(entry) ? entry[PERMISSIONS.target] : undefined;
49
+ const type = isJsonObject(target) ? target[PERMISSIONS.targetType] : undefined;
50
+ const path = isJsonObject(target) ? target[PERMISSIONS.targetPath] : undefined;
51
+ const scope = {
52
+ access: access ?? 'unrecognised',
53
+ target: type === SCOPE_TARGETS.path && typeof path === 'string'
54
+ ? { kind: 'path', path }
55
+ : type === SCOPE_TARGETS.special ? { kind: 'special' } : { kind: 'unrecognised' },
56
+ };
57
+ if (scope.access === 'unrecognised' || scope.target.kind === 'unrecognised')
58
+ unknownPart();
59
+ return scope;
60
+ }
@@ -0,0 +1,24 @@
1
+ import { PRE_TOOL_USE } from '../contract/hooks.js';
2
+ import { isJsonObject, parseJsonObject } from '../../../shared/json.js';
3
+ /**
4
+ * Reads the text a Codex `PreToolUse` hook was given (`codex-blocks-too` CK4): the command line of a shell call, and the
5
+ * session's folder, which `refuse --codex` looks for the project from (CK3). A call to any tool but the shell is
6
+ * `another-tool`, and passes. Never throws. The fields are Codex's own, measured (CKB2); that they are named as Claude
7
+ * Code's are is an observation, not a shared definition.
8
+ */
9
+ export function parseCodexPreToolUseInput(text) {
10
+ const input = parseJsonObject(text);
11
+ if (input === undefined)
12
+ return { unusable: 'not-json' };
13
+ const { fields } = PRE_TOOL_USE;
14
+ if (input[fields.event] !== PRE_TOOL_USE.event)
15
+ return { unusable: 'another-event' };
16
+ if (input[fields.toolName] !== PRE_TOOL_USE.shellTool)
17
+ return { anotherTool: true };
18
+ const toolInput = input[fields.toolInput];
19
+ const command = isJsonObject(toolInput) ? toolInput[fields.command] : undefined;
20
+ if (typeof command !== 'string')
21
+ return { unusable: 'field-missing' };
22
+ const cwd = input[fields.cwd];
23
+ return typeof cwd === 'string' && cwd !== '' ? { command, cwd } : { command };
24
+ }
@@ -0,0 +1,57 @@
1
+ import { FileAccessError } from '../../../ports/file-access-error.js';
2
+ import { isJsonObject, parseJsonObject } from '../../../shared/json.js';
3
+ import { CODE_CELL } from '../contract/deliveries.js';
4
+ import { ENVELOPE, LINE_TYPES } from '../contract/envelope.js';
5
+ import { STOP } from '../contract/hooks.js';
6
+ import { RESPONSE_ITEMS } from '../contract/messages.js';
7
+ import { RESPONSE_TURN } from '../contract/turns.js';
8
+ import { hookRefusalsIn } from '../events/hook-refusals.js';
9
+ /**
10
+ * `Stop` has a session id, a turn id and (outside ephemeral runs) a transcript path. The rollout reader already
11
+ * recognizes agentwhy's own refusal text in a code cell's output; this narrow reader applies that recognizer only to
12
+ * outputs with the Stop input's turn id. It never returns any other transcript content.
13
+ */
14
+ export class CodexTurnRefusals {
15
+ #input;
16
+ #files;
17
+ constructor(input, files) {
18
+ this.#input = input;
19
+ this.#files = files;
20
+ }
21
+ async find() {
22
+ const text = await this.#input.readAll(1024 * 1024);
23
+ const input = text === undefined ? undefined : parseJsonObject(text);
24
+ if (input === undefined || input[STOP.fields.event] !== STOP.event || input[STOP.fields.active] === true)
25
+ return [];
26
+ const turnId = input[STOP.fields.turnId];
27
+ const path = input[STOP.fields.transcriptPath];
28
+ if (typeof turnId !== 'string' || turnId === '' || typeof path !== 'string' || path === '')
29
+ return [];
30
+ const found = [];
31
+ try {
32
+ for await (const raw of this.#files.readLines(path)) {
33
+ const line = parseJsonObject(raw);
34
+ if (line?.[ENVELOPE.type] !== LINE_TYPES.responseItem)
35
+ continue;
36
+ const payload = line[ENVELOPE.payload];
37
+ if (!isJsonObject(payload) || payload[ENVELOPE.payloadType] !== RESPONSE_ITEMS.codeCellOutput)
38
+ continue;
39
+ const metadata = payload[RESPONSE_TURN.metadata];
40
+ if (!isJsonObject(metadata) || metadata[RESPONSE_TURN.turnId] !== turnId)
41
+ continue;
42
+ const output = payload[CODE_CELL.output];
43
+ const parts = typeof output === 'string' ? [output] : Array.isArray(output)
44
+ ? output.flatMap((part) => isJsonObject(part) && part[CODE_CELL.partType] === CODE_CELL.textPart &&
45
+ typeof part[CODE_CELL.partText] === 'string' ? [part[CODE_CELL.partText]] : [])
46
+ : [];
47
+ found.push(...hookRefusalsIn(parts.join('\n')));
48
+ }
49
+ }
50
+ catch (error) {
51
+ if (!(error instanceof FileAccessError))
52
+ throw error;
53
+ return [];
54
+ }
55
+ return found;
56
+ }
57
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,268 @@
1
+ import { basename } from 'node:path';
2
+ import { Counter } from '../../../shared/counter.js';
3
+ import { FileAccessError } from '../../../ports/file-access-error.js';
4
+ import { isJsonObject, parseJsonObject } from '../../../shared/json.js';
5
+ import { agentSource } from '../../../core/evidence.js';
6
+ import { ACTION_ITEMS, COMMAND, ITEM, ITEM_EVENT, ITEM_STATUSES, SHELL_FLAGS, SHELLS } from '../contract/actions.js';
7
+ import { ACTIVITY } from '../contract/delegations.js';
8
+ import { ENVELOPE, LEGACY_EVENTS, LINE_TYPES, PASSIVE_EVENTS } from '../contract/envelope.js';
9
+ import { EVENT_MESSAGES, MESSAGE_ITEMS, REASONING, RESPONSE_ITEMS } from '../contract/messages.js';
10
+ import { SESSION } from '../contract/session.js';
11
+ import { TURN_CONTEXT, TURN_EVENTS } from '../contract/turns.js';
12
+ import { CONTRACT_VERSION, VERIFIED_AGAINST } from '../contract/version.js';
13
+ import { sessionOwners, AMBIGUOUS } from '../discovery/session-owners.js';
14
+ import { sessionRoots } from '../discovery/session-roots.js';
15
+ import { capabilitiesOf } from '../events/capability-records.js';
16
+ import { permissionsOf } from '../events/turn-permissions.js';
17
+ const UNKNOWN = '<unknown>';
18
+ const UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
19
+ const KNOWN_LINES = Object.values(LINE_TYPES);
20
+ const KNOWN_RESPONSES = Object.values(RESPONSE_ITEMS);
21
+ const KNOWN_EVENTS = [
22
+ ITEM_EVENT.type, TURN_EVENTS.started, TURN_EVENTS.complete, TURN_EVENTS.aborted, EVENT_MESSAGES.user, EVENT_MESSAGES.agent,
23
+ ...PASSIVE_EVENTS, ...LEGACY_EVENTS,
24
+ ];
25
+ const KNOWN_ITEMS = [...Object.values(ACTION_ITEMS), ...Object.values(MESSAGE_ITEMS), ACTIVITY.type];
26
+ const ACTIONS = Object.values(ACTION_ITEMS);
27
+ const LEGACY = LEGACY_EVENTS;
28
+ /** A label from a fixed vocabulary, or `<unknown>`: an unknown spelling is counted and never printed (X24). */
29
+ function known(value, vocabulary) {
30
+ return typeof value === 'string' && vocabulary.includes(value) ? value : UNKNOWN;
31
+ }
32
+ /**
33
+ * Measures Codex rollouts for `doctor` (X26): a file given by name, or every rollout under a folder. It shares the
34
+ * ownership rule with discovery and the reconnaissance probe (`sessionOwners`), and reads the contract's vocabularies
35
+ * rather than the probe script, which stays a tool of its own (spec §8).
36
+ */
37
+ export class CodexProbe {
38
+ #discovery;
39
+ #directories;
40
+ #files;
41
+ constructor(dependencies) {
42
+ this.#discovery = dependencies.discovery;
43
+ this.#directories = dependencies.directories;
44
+ this.#files = dependencies.files;
45
+ }
46
+ async probe(input) {
47
+ const tally = new Tally();
48
+ const sources = await this.#sources(input, tally);
49
+ const owners = sessionOwners(sources.map((source) => (source.header.id === '' ? undefined : source.header.id)));
50
+ for (const [id, owner] of owners) {
51
+ if (owner === AMBIGUOUS) {
52
+ tally.sharedIds += 1;
53
+ tally.filesSharingIds += sources.filter((source) => source.header.id === id).length;
54
+ }
55
+ else
56
+ tally.uniqueIds += 1;
57
+ }
58
+ for (const source of sources) {
59
+ const { header } = source;
60
+ tally.versions.add(known(header.version, VERIFIED_AGAINST.codex));
61
+ tally.historyModes.add(header.historyMode === 'unknown' ? UNKNOWN : header.historyMode);
62
+ tally.origins.add(header.origin.kind);
63
+ const named = UUID.exec(basename(source.path))?.[0];
64
+ if (named !== undefined && named.toLowerCase() !== header.id.toLowerCase())
65
+ tally.fileNameDisagrees += 1;
66
+ if (source.relation.kind === 'resolved') {
67
+ if (sources[source.relation.root] === source)
68
+ tally.roots += 1;
69
+ else
70
+ tally.descendants += 1;
71
+ }
72
+ else
73
+ tally.unresolved.add(source.relation.reason);
74
+ await this.#file(source, tally);
75
+ }
76
+ return tally.report();
77
+ }
78
+ /** The rollouts to measure: the file given, or the recognised rollouts under a folder, each with its tree relation. */
79
+ async #sources(input, tally) {
80
+ let kind;
81
+ try {
82
+ kind = await this.#directories.kindOf(input);
83
+ }
84
+ catch (error) {
85
+ if (!(error instanceof FileAccessError))
86
+ throw error;
87
+ tally.unreadable += 1;
88
+ return [];
89
+ }
90
+ if (kind === 'directory') {
91
+ const listing = await this.#discovery.list(input);
92
+ const unknownFormat = listing.gaps.filter((gap) => gap.reason === 'unknown-format').length;
93
+ tally.found += listing.sources.length + unknownFormat;
94
+ tally.unknownFormat += unknownFormat;
95
+ tally.unreadable += listing.gaps.length - unknownFormat;
96
+ return listing.sources;
97
+ }
98
+ tally.found += 1;
99
+ const head = await this.#discovery.readHeader(input);
100
+ if (head.kind === 'unknown')
101
+ tally.unknownFormat += 1;
102
+ if (head.kind === 'unavailable')
103
+ tally.unreadable += 1;
104
+ if (head.kind !== 'recognised')
105
+ return [];
106
+ return [{ path: input, header: head.header, relation: sessionRoots([head.header])[0] ?? { kind: 'unresolved', reason: 'invalid-identity' } }];
107
+ }
108
+ async #file(source, tally) {
109
+ tally.recognised += 1;
110
+ const directories = new Set();
111
+ let lastOrdinal;
112
+ let metadata = 0;
113
+ const facts = { unrecognised: false, interrupted: false, hiddenReasoning: false, permissionsIncomplete: false, permissionsRecorded: false };
114
+ try {
115
+ for await (const raw of this.#files.readLines(source.path)) {
116
+ if (raw.trim() === '')
117
+ continue;
118
+ tally.lines += 1;
119
+ const line = parseJsonObject(raw);
120
+ if (line === undefined) {
121
+ tally.unparsable += 1;
122
+ continue;
123
+ }
124
+ const ordinal = line[ENVELOPE.ordinal];
125
+ if (typeof ordinal === 'number') {
126
+ if (lastOrdinal !== undefined && ordinal < lastOrdinal)
127
+ tally.ordinalBackwards += 1;
128
+ if (lastOrdinal !== undefined && ordinal === lastOrdinal)
129
+ tally.ordinalRepeats += 1;
130
+ lastOrdinal = ordinal;
131
+ }
132
+ const type = known(line[ENVELOPE.type], KNOWN_LINES);
133
+ tally.lineTypes.add(type);
134
+ if (type === UNKNOWN)
135
+ facts.unrecognised = true;
136
+ const payload = line[ENVELOPE.payload];
137
+ if (!isJsonObject(payload))
138
+ continue;
139
+ if (type === LINE_TYPES.sessionMeta) {
140
+ metadata += 1;
141
+ const directory = payload[SESSION.workingDirectory];
142
+ if (typeof directory === 'string')
143
+ directories.add(directory);
144
+ }
145
+ if (type === LINE_TYPES.turnContext) {
146
+ const directory = payload[TURN_CONTEXT.workingDirectory];
147
+ if (typeof directory === 'string')
148
+ directories.add(directory);
149
+ facts.permissionsRecorded = true;
150
+ if (!permissionsOf(payload).complete)
151
+ facts.permissionsIncomplete = true;
152
+ }
153
+ if (type === LINE_TYPES.responseItem) {
154
+ const kind = known(payload[ENVELOPE.payloadType], KNOWN_RESPONSES);
155
+ tally.responseItems.add(kind);
156
+ if (kind === UNKNOWN)
157
+ facts.unrecognised = true;
158
+ if (kind === RESPONSE_ITEMS.reasoning && !readableSummary(payload[REASONING.summary]))
159
+ facts.hiddenReasoning = true;
160
+ }
161
+ if (type === LINE_TYPES.event) {
162
+ const kind = known(payload[ENVELOPE.payloadType], KNOWN_EVENTS);
163
+ tally.events.add(kind);
164
+ // A legacy event is a label the contract knows and a record the reader cannot map, and so is an item event with
165
+ // no item: both are unrecognised to the reader (`rollout-scan.ts`), so what the file can answer is said alike.
166
+ if (kind === UNKNOWN || LEGACY.includes(kind))
167
+ facts.unrecognised = true;
168
+ if (kind === TURN_EVENTS.aborted)
169
+ facts.interrupted = true;
170
+ const item = payload[ITEM_EVENT.item];
171
+ if (kind === ITEM_EVENT.type && !isJsonObject(item))
172
+ facts.unrecognised = true;
173
+ if (kind === ITEM_EVENT.type && isJsonObject(item)) {
174
+ const itemType = known(item[ITEM.type], KNOWN_ITEMS);
175
+ tally.items.add(itemType);
176
+ if (itemType === UNKNOWN)
177
+ facts.unrecognised = true;
178
+ if (itemType === UNKNOWN || ACTIONS.includes(itemType)) {
179
+ tally.itemStatuses.add(`${itemType} ${item[ITEM.status] === undefined ? '(none)' : known(item[ITEM.status], Object.values(ITEM_STATUSES))}`);
180
+ }
181
+ if (itemType === ACTION_ITEMS.command)
182
+ tally.commandShapes.add(commandShape(item[COMMAND.command]));
183
+ }
184
+ }
185
+ }
186
+ }
187
+ catch (error) {
188
+ if (!(error instanceof FileAccessError))
189
+ throw error;
190
+ tally.unreadable += 1;
191
+ }
192
+ if (metadata > 1)
193
+ tally.laterMetadata += metadata - 1;
194
+ if (directories.size > 1)
195
+ tally.filesWithSeveral += 1;
196
+ if (directories.size === 0)
197
+ tally.filesWithNone += 1;
198
+ for (const record of capabilitiesOf(source.header, agentSource(source.header.id), source.header.id, facts)) {
199
+ tally.capabilities.add(`${record.question} ${record.state}`);
200
+ }
201
+ }
202
+ }
203
+ /** X7: a command read as a line, or kept whole. */
204
+ function commandShape(command) {
205
+ return Array.isArray(command) && command.length === 3 && typeof command[0] === 'string' && SHELLS.some((shell) => shell === basename(command[0]))
206
+ && SHELL_FLAGS.some((flag) => flag === command[1]) && typeof command[2] === 'string' ? 'recognised' : 'other';
207
+ }
208
+ function readableSummary(summary) {
209
+ return Array.isArray(summary) && summary.some((part) => isJsonObject(part) && typeof part[REASONING.summaryText] === 'string' && part[REASONING.summaryText] !== '');
210
+ }
211
+ /** What a run counts, turned into the closed report. */
212
+ class Tally {
213
+ found = 0;
214
+ recognised = 0;
215
+ unknownFormat = 0;
216
+ unreadable = 0;
217
+ lines = 0;
218
+ unparsable = 0;
219
+ uniqueIds = 0;
220
+ sharedIds = 0;
221
+ filesSharingIds = 0;
222
+ fileNameDisagrees = 0;
223
+ laterMetadata = 0;
224
+ roots = 0;
225
+ descendants = 0;
226
+ filesWithSeveral = 0;
227
+ filesWithNone = 0;
228
+ ordinalBackwards = 0;
229
+ ordinalRepeats = 0;
230
+ versions = new Counter();
231
+ historyModes = new Counter();
232
+ origins = new Counter();
233
+ unresolved = new Counter();
234
+ lineTypes = new Counter();
235
+ responseItems = new Counter();
236
+ events = new Counter();
237
+ items = new Counter();
238
+ itemStatuses = new Counter();
239
+ commandShapes = new Counter();
240
+ capabilities = new Counter();
241
+ report() {
242
+ return {
243
+ schemaVersion: 1,
244
+ provider: 'codex',
245
+ contractVersion: CONTRACT_VERSION,
246
+ verifiedAgainst: VERIFIED_AGAINST.codex,
247
+ files: { found: this.found, recognised: this.recognised, unknownFormat: this.unknownFormat, unreadable: this.unreadable },
248
+ lines: { total: this.lines, unparsable: this.unparsable },
249
+ versions: this.versions.toCounts(),
250
+ historyModes: this.historyModes.toCounts(),
251
+ origins: this.origins.toCounts(),
252
+ identity: {
253
+ uniqueIds: this.uniqueIds, sharedIds: this.sharedIds, filesSharingIds: this.filesSharingIds,
254
+ fileNameDisagrees: this.fileNameDisagrees, laterMetadata: this.laterMetadata,
255
+ },
256
+ tree: { roots: this.roots, descendants: this.descendants, unresolved: this.unresolved.toCounts() },
257
+ workingDirectories: { filesWithSeveral: this.filesWithSeveral, filesWithNone: this.filesWithNone },
258
+ order: { ordinalBackwards: this.ordinalBackwards, ordinalRepeats: this.ordinalRepeats },
259
+ lineTypes: this.lineTypes.toCounts(),
260
+ responseItems: this.responseItems.toCounts(),
261
+ events: this.events.toCounts(),
262
+ items: this.items.toCounts(),
263
+ itemStatuses: this.itemStatuses.toCounts(),
264
+ commandShapes: this.commandShapes.toCounts(),
265
+ capabilities: this.capabilities.toCounts(),
266
+ };
267
+ }
268
+ }
@@ -0,0 +1,83 @@
1
+ import { isJsonObject } from '../../../shared/json.js';
2
+ import { PRE_TOOL_USE, PROJECT_HOOKS } from '../contract/hooks.js';
3
+ /**
4
+ * agentwhy's Codex hook, and no one else's: `refuse` with `--codex` straight after it. Nothing but agentwhy writes that
5
+ * flag, so a command with it is taken out and replaced, and every other command in the file is left as it was (K13).
6
+ */
7
+ const RUNS_CODEX_REFUSE = /(?:^|\s)refuse\s+--codex(?:\s|$)/;
8
+ const RUNS_CODEX_STOP = /(?:^|\s)codex-stop\s+--codex(?:\s|$)/;
9
+ /**
10
+ * The command agentwhy's Codex hook runs (`codex-blocks-too` CK3): the invocation, `refuse --codex`, and the settings
11
+ * file Claude Code's `refuse` reads, relative to the project, where it reads one. `refuse --codex` finds the project
12
+ * from the folder Codex runs it in, so no absolute path is written and the file works in a clone.
13
+ */
14
+ export function codexRefuseCommand(invoke, settings) {
15
+ return `${invoke} refuse --codex${settings === undefined ? '' : ` --settings "${settings}"`}`;
16
+ }
17
+ /** The companion Stop hook asks Codex to credit agentwhy for a blocked command in its reply. */
18
+ export function codexStopCommand(invoke) {
19
+ return `${invoke} codex-stop --codex`;
20
+ }
21
+ /** The command agentwhy's Codex hook runs in this file, where it runs one. */
22
+ export function codexRefuseIn(file) {
23
+ return commandsOf(file, PRE_TOOL_USE.event).find((command) => RUNS_CODEX_REFUSE.test(command));
24
+ }
25
+ export function codexStopIn(file) {
26
+ return commandsOf(file, 'Stop').find((command) => RUNS_CODEX_STOP.test(command));
27
+ }
28
+ /** The file with agentwhy's Codex hook running `command`, on the shell's `PreToolUse`, in place of any it had (CK5). */
29
+ export function withCodexRefuse(file, command, stopCommand) {
30
+ const { file: without } = withoutCodexRefuse(file);
31
+ const hooks = isJsonObject(without[PROJECT_HOOKS.hooks]) ? { ...without[PROJECT_HOOKS.hooks] } : {};
32
+ const list = Array.isArray(hooks[PRE_TOOL_USE.event]) ? [...hooks[PRE_TOOL_USE.event]] : [];
33
+ const stops = Array.isArray(hooks.Stop) ? [...hooks.Stop] : [];
34
+ list.push({
35
+ [PROJECT_HOOKS.matcher]: PRE_TOOL_USE.shellTool,
36
+ [PROJECT_HOOKS.commands]: [{ [PROJECT_HOOKS.type]: PROJECT_HOOKS.commandType, [PROJECT_HOOKS.command]: command }],
37
+ });
38
+ stops.push({ [PROJECT_HOOKS.commands]: [{ [PROJECT_HOOKS.type]: PROJECT_HOOKS.commandType, [PROJECT_HOOKS.command]: stopCommand }] });
39
+ return { ...without, [PROJECT_HOOKS.hooks]: { ...hooks, [PRE_TOOL_USE.event]: list, Stop: stops } };
40
+ }
41
+ /**
42
+ * The file without agentwhy's Codex hook. An entry left with no command is dropped, and an event left with no entry;
43
+ * the `hooks` object itself stays, empty or not, and so does every other key and hook.
44
+ */
45
+ export function withoutCodexRefuse(file) {
46
+ const hooks = file[PROJECT_HOOKS.hooks];
47
+ if (!isJsonObject(hooks))
48
+ return { file, removed: 0 };
49
+ let removed = 0;
50
+ const kept = {};
51
+ for (const [event, list] of Object.entries(hooks)) {
52
+ if (!Array.isArray(list)) {
53
+ kept[event] = list;
54
+ continue;
55
+ }
56
+ const entries = list.flatMap((entry) => {
57
+ if (!isJsonObject(entry) || !Array.isArray(entry[PROJECT_HOOKS.commands]))
58
+ return [entry];
59
+ const commands = entry[PROJECT_HOOKS.commands].filter((item) => {
60
+ const ours = isJsonObject(item) && typeof item[PROJECT_HOOKS.command] === 'string' &&
61
+ (event === PRE_TOOL_USE.event ? RUNS_CODEX_REFUSE.test(item[PROJECT_HOOKS.command]) :
62
+ event === 'Stop' && RUNS_CODEX_STOP.test(item[PROJECT_HOOKS.command]));
63
+ if (ours)
64
+ removed += 1;
65
+ return !ours;
66
+ });
67
+ return commands.length === 0 ? [] : [{ ...entry, [PROJECT_HOOKS.commands]: commands }];
68
+ });
69
+ if (entries.length > 0)
70
+ kept[event] = entries;
71
+ }
72
+ return { file: removed === 0 ? file : { ...file, [PROJECT_HOOKS.hooks]: kept }, removed };
73
+ }
74
+ function commandsOf(file, event) {
75
+ const hooks = file[PROJECT_HOOKS.hooks];
76
+ if (!isJsonObject(hooks))
77
+ return [];
78
+ return [hooks[event]].flatMap((list) => Array.isArray(list)
79
+ ? list.flatMap((entry) => isJsonObject(entry) && Array.isArray(entry[PROJECT_HOOKS.commands])
80
+ ? entry[PROJECT_HOOKS.commands].flatMap((item) => isJsonObject(item) && typeof item[PROJECT_HOOKS.command] === 'string' ? [item[PROJECT_HOOKS.command]] : [])
81
+ : [])
82
+ : []);
83
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ const HELP_FLAGS = ['--help', '-h'];
2
+ /** Dispatches argv to the registered command of that name. Adding a command never changes the router. */
3
+ export class CommandRouter {
4
+ #commands;
5
+ #withoutACommand;
6
+ /**
7
+ * `withoutACommand` answers `agentwhy` with nothing after it, and with arguments that begin with `-` (they are its
8
+ * flags); without one, that stays a usage error. It may also be registered under its own name.
9
+ */
10
+ constructor(commands, withoutACommand) {
11
+ this.#withoutACommand = withoutACommand;
12
+ const byName = new Map();
13
+ for (const command of commands) {
14
+ if (byName.has(command.name))
15
+ throw new Error(`duplicate command: ${command.name}`);
16
+ byName.set(command.name, command);
17
+ }
18
+ this.#commands = byName;
19
+ }
20
+ /** The usage of every command, in registration order, after the one a bare `agentwhy` runs, and never twice. */
21
+ get usage() {
22
+ const commands = new Set([...(this.#withoutACommand === undefined ? [] : [this.#withoutACommand]), ...this.#commands.values()]);
23
+ return [...commands].map((command) => command.usage).join('\n');
24
+ }
25
+ async route(argv) {
26
+ const [name, ...args] = argv;
27
+ if (name !== undefined && HELP_FLAGS.includes(name))
28
+ return { kind: 'help', usage: this.usage };
29
+ if (name === undefined) {
30
+ return this.#withoutACommand === undefined ? this.#usageError('missing command') : this.#withoutACommand.execute([]);
31
+ }
32
+ if (name.startsWith('-') && this.#withoutACommand !== undefined)
33
+ return this.#withoutACommand.execute(argv);
34
+ const command = this.#commands.get(name);
35
+ if (command === undefined)
36
+ return this.#usageError(`unknown command: ${name}`);
37
+ return command.execute(args);
38
+ }
39
+ #usageError(message) {
40
+ return { kind: 'usage-error', message, usage: this.usage };
41
+ }
42
+ }