@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,161 @@
1
+ /**
2
+ * What only Settings does (`.ai/plans/2026-09-23-settings-redesign.md`, step 3). The kit opens and closes the windows
3
+ * and switches the tabs; this posts what a confirm button carries, and reads the page again once the server has
4
+ * written it (R60), so a control shows what the file holds and never what was clicked. A refusal is said in the words
5
+ * the server gave (R59). Opened as a file, nothing can be written, and the same button shows the command that would
6
+ * do it (R61).
7
+ *
8
+ * Picking or typing a file's name is the kit's (`add-file-popup.ts`), which reads a picked file's name and nothing
9
+ * else (F36).
10
+ */
11
+ export const SETTINGS_SCRIPT = String.raw `
12
+ (() => {
13
+ const root = document.querySelector('[data-settings]');
14
+ if (!root) return;
15
+ const served = location.protocol === 'http:' || location.protocol === 'https:';
16
+ const words = JSON.parse(root.dataset.setWords || '{}');
17
+ const word = (key) => (words[document.documentElement.dataset.lang] || words.en || {})[key] || '';
18
+ const TABS = ['files', 'alerts', 'general'];
19
+
20
+ // The tab a person was on survives the page being read again after a write.
21
+ const pills = [...root.querySelectorAll(':scope .tabs-state [data-tab]')];
22
+ const opened = TABS.indexOf(location.hash.slice(1));
23
+ if (opened > 0 && pills[opened]) pills[opened].click();
24
+ pills.forEach((pill, at) => pill.addEventListener('click', () => history.replaceState(null, '', '#' + TABS[at])));
25
+
26
+ const say = (where, text, command, busy) => {
27
+ const line = where && where.querySelector('[data-set-say]');
28
+ if (!line) return;
29
+ line.textContent = text;
30
+ line.classList.toggle('set-say-busy', busy === true);
31
+ if (command) {
32
+ const code = document.createElement('code');
33
+ code.textContent = command;
34
+ line.append(code);
35
+ }
36
+ line.hidden = false;
37
+ };
38
+
39
+ const quote = (text) => /^[\w@%+=:,./*-]+$/.test(text) ? text : "'" + text.replace(/'/g, "'\\''") + "'";
40
+ const shared = (where) => where === 'shared' ? ' --shared' : '';
41
+ const commandFor = (body) => {
42
+ // A private file is kept from searches too (F38), so protecting names refuse, as the page's own write does.
43
+ if (body.change === 'protect') return 'agentwhy init --protect ' + quote(body.pattern) + ' --refuse' + shared(body.where);
44
+ if (body.change === 'adopt') return 'agentwhy init' + body.patterns.map((pattern) => ' --protect ' + quote(pattern)).join('') + ' --refuse' + shared(body.where);
45
+ if (body.change === 'unprotect') return 'agentwhy init --remove --unprotect ' + quote(body.pattern) + shared(body.where);
46
+ if (body.scope === 'project') return 'agentwhy notify' + (body.on ? ' --on ' + body.on : '') + (body.clean ? ' --clean ' + body.clean : '');
47
+ return '';
48
+ };
49
+
50
+ const post = (url, body, where, controls) => {
51
+ controls.forEach((control) => { control.disabled = true; control.setAttribute('aria-busy', 'true'); });
52
+ say(where, word('saving'), '', true);
53
+ fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })
54
+ .then((response) => response.json().then((answer) => ({ ok: response.ok && answer.ok, message: answer.message || '' })))
55
+ .catch(() => ({ ok: false, message: word('unreachable') }))
56
+ .then((answer) => {
57
+ if (answer.ok) {
58
+ const tab = TABS[pills.findIndex((pill) => pill.classList.contains('tabs-on'))] || TABS[0];
59
+ location.replace(location.pathname + '?at=' + Date.now() + '#' + tab);
60
+ return;
61
+ }
62
+ controls.forEach((control) => { control.disabled = false; control.removeAttribute('aria-busy'); });
63
+ say(where, word('refused') + ' ' + answer.message);
64
+ });
65
+ };
66
+
67
+ /** A change that writes into the project: posted where the page is served, said as a command where it is a file. */
68
+ const change = (body, button, command) => {
69
+ const dialog = button.closest('dialog');
70
+ if (!served) { say(dialog, word('asFile'), command || commandFor(body)); return; }
71
+ post('api/settings', body, dialog, [button]);
72
+ };
73
+
74
+ // A row that needs row 1 answers a click - on its switch or anywhere on it - with a bubble beside its switch, and
75
+ // row 1 lights up for a moment.
76
+ const tips = [...root.querySelectorAll('[data-set-tip]')];
77
+ const hideTips = (except) => tips.forEach((tip) => { if (tip !== except) tip.hidden = true; });
78
+ document.addEventListener('keydown', (event) => { if (event.key === 'Escape') hideTips(); });
79
+ document.addEventListener('click', (event) => { if (!event.target.closest('[data-set-tip], .set-msg-locked')) hideTips(); });
80
+
81
+ root.addEventListener('click', (event) => {
82
+ if (event.target.closest('[data-set-tip] [data-popup-open]')) hideTips();
83
+ const locked = !event.target.closest('[data-set-tip]') && event.target.closest('.set-msg-locked');
84
+ const needs = locked && locked.querySelector('[data-set-needs-first]');
85
+ if (needs) {
86
+ const tip = document.getElementById(needs.getAttribute('aria-describedby'));
87
+ hideTips(tip);
88
+ if (tip) tip.hidden = false;
89
+ const first = root.querySelector('[data-set-first]');
90
+ if (first) {
91
+ first.classList.add('set-msg-point');
92
+ setTimeout(() => first.classList.remove('set-msg-point'), 1600);
93
+ }
94
+ return;
95
+ }
96
+
97
+ const confirm = event.target.closest('[data-set-write]');
98
+ if (confirm) {
99
+ const body = JSON.parse(confirm.dataset.setWrite);
100
+ if (confirm.dataset.setWho) {
101
+ const picked = document.querySelector('input[name="' + confirm.dataset.setWho + '"]:checked');
102
+ body.where = picked ? picked.value : 'local';
103
+ }
104
+ change(body, confirm, confirm.getAttribute('data-set-command-' + (body.where || 'local')));
105
+ return;
106
+ }
107
+
108
+ // A row not watched yet opens its confirmation from anywhere on it, as its own button does.
109
+ const unwatched = event.target.closest('[data-set-row]');
110
+ if (unwatched && !event.target.closest('[data-popup-open]')) {
111
+ const button = unwatched.querySelector('[data-popup-open]');
112
+ if (button) button.click();
113
+ return;
114
+ }
115
+
116
+ const add = event.target.closest('[data-set-add]');
117
+ if (add) {
118
+ const settings = JSON.parse(add.dataset.setAdd);
119
+ const pattern = add.dataset.pattern;
120
+ if (!pattern) return;
121
+ const body = settings.builtIn.length > 0
122
+ ? { change: 'adopt', patterns: [...settings.builtIn, pattern], where: settings.where }
123
+ : { change: 'protect', pattern, where: settings.where };
124
+ // Where alerts run from the same file, the command names them too: \`init\` with a hook flag takes out any other.
125
+ change(body, add, commandFor(body).replace(/( --shared)?$/, (settings.watch ? ' --watch' : '') + '$1'));
126
+ return;
127
+ }
128
+
129
+ // Rows 2 and 3 are notice choices for this project, written at once (R26a).
130
+ const notice = event.target.closest('[data-set-notice]');
131
+ if (notice) {
132
+ const body = Object.assign({ scope: 'project' }, JSON.parse(notice.dataset.setNotice));
133
+ const card = notice.closest('.set-msg');
134
+ if (!served) { say(card, word('asFile'), commandFor(body)); return; }
135
+ post('api/notify', body, card, [notice]);
136
+ return;
137
+ }
138
+
139
+ });
140
+
141
+ /**
142
+ * The kit's "Add a private file" hands over a name already turned into its pattern, or refused in words (F36, R46);
143
+ * Settings shows the pattern exactly as it will be written, and what it means, and asks (F35).
144
+ */
145
+ const picker = root.querySelector('#set-add');
146
+ if (picker) picker.addEventListener('add-file', (event) => {
147
+ const confirm = root.querySelector('#set-add-confirm');
148
+ if (!confirm) return;
149
+ const { name, kind, pattern } = event.detail;
150
+ confirm.querySelectorAll('[data-set-name]').forEach((slot) => { slot.textContent = kind === 'folder' ? name + '/' : name; });
151
+ confirm.querySelectorAll('[data-set-pattern]').forEach((slot) => { slot.textContent = pattern; });
152
+ confirm.querySelectorAll('[data-set-kind]').forEach((slot) => { slot.hidden = slot.dataset.setKind !== kind; });
153
+ const button = confirm.querySelector('[data-set-add]');
154
+ if (button) button.dataset.pattern = pattern;
155
+ const line = confirm.querySelector('[data-set-say]');
156
+ if (line) line.hidden = true;
157
+ if (picker.open) picker.close();
158
+ confirm.showModal();
159
+ });
160
+ })();
161
+ `;
@@ -0,0 +1,240 @@
1
+ import { DEFAULT_POLICY } from '../../../core/policy/default-policy.js';
2
+ import { SETTINGS_FILES } from '../../../adapter/claude-code/contract/settings.js';
3
+ import { DEFAULT_THRESHOLD } from '../../watch/agent-alert.js';
4
+ import { DEFAULT_CLEAN } from '../../watch/notice-choices.js';
5
+ import { RULE_NAMES } from '../../rule-names.js';
6
+ /**
7
+ * What the Settings page shows, decided from what the files hold (`for-people-who-build-with-ai.md` §3 C; the plan's
8
+ * S4). No HTML: every state, name and source of the page is chosen here, and the page only writes it.
9
+ *
10
+ * "Watched" means what the `watch` hook reads, never the list this run of `start` read: a settings file's rules replace
11
+ * the built-in list for a hook that names it, so a pattern is called watched only where that hook's rules hold it.
12
+ */
13
+ const BUILT_IN = DEFAULT_POLICY.protected.map((entry) => entry.pattern);
14
+ const NO_HOOKS = {
15
+ watch: false,
16
+ refuse: false,
17
+ reads: { watch: 'default', refuse: 'default' },
18
+ path: SETTINGS_FILES.directory + '/' + SETTINGS_FILES.local,
19
+ sharedPath: SETTINGS_FILES.directory + '/' + SETTINGS_FILES.shared,
20
+ };
21
+ export function settingsView(settings) {
22
+ const hooks = settings.hooks ?? NO_HOOKS;
23
+ const canWrite = settings.hooks !== undefined && settings.mine !== undefined;
24
+ const alerts = hookOf(hooks.watch);
25
+ const stop = hookOf(hooks.refuse);
26
+ const reads = hooks.reads.watch;
27
+ const notices = settings.notices;
28
+ const on = notices?.on ?? DEFAULT_THRESHOLD;
29
+ const clean = notices?.clean ?? DEFAULT_CLEAN;
30
+ const known = settings.hooks !== undefined;
31
+ // Unknown, the hooks' rules are unknown too: the list is what this run read, and no row claims to be watched or not.
32
+ const read = known ? readPatterns(settings, reads) : undefined;
33
+ const told = toldIn(settings);
34
+ const canTell = canWrite && settings.told !== undefined && settings.told.local !== 'unreadable' && settings.told.shared !== 'unreadable';
35
+ const rows = read === undefined ? policyRows(settings) : fileRows(settings, reads, read, told, canTell).map((row) => keptOf(row, settings, hooks));
36
+ const unread = read === undefined ? [] : unreadRules(settings, read);
37
+ const addTo = reads === 'local' || reads === 'shared' ? reads : alerts.who ?? stop.who ?? 'local';
38
+ // A built-in pattern on a told list is read and told, never blocked again by an add (F57).
39
+ const withBuiltIn = read === undefined ? [] : BUILT_IN.filter((pattern) => (reads === 'default' || !read.has(pattern)) && !told.has(pattern));
40
+ const scope = known ? scopeOf(settings, hooks) : undefined;
41
+ return {
42
+ known,
43
+ canWrite,
44
+ alerts,
45
+ stopped: { on: on === 'refused', locked: known && !alerts.on },
46
+ fine: { on: clean !== 'off', locked: known && !alerts.on },
47
+ noticesWritable: notices !== undefined && !notices.unusable,
48
+ stop,
49
+ scope,
50
+ moves: { local: movesInto(settings, hooks, 'local'), shared: movesInto(settings, hooks, 'shared') },
51
+ uninstall: known ? uninstallFrom(settings, hooks) : {},
52
+ writeTo: scope === 'local' || scope === 'shared' ? scope : addTo,
53
+ canTell,
54
+ reads,
55
+ rows,
56
+ unread,
57
+ unfinished: unfinishedOf(settings, rows, withBuiltIn, told, stop.on),
58
+ toWatch: new Set([...unread.map((rule) => rule.rule), ...(reads === 'default' ? [] : withBuiltIn)]).size,
59
+ addTo,
60
+ // Read from the built-in list, the whole of it goes into the file the hooks will read from then on; read from a
61
+ // file, only what that file lacks.
62
+ withBuiltIn,
63
+ canAdd: canWrite && read !== undefined,
64
+ developer: developerRows(settings, known ? hooks : undefined, reads, unread),
65
+ ...(hooks.codex === undefined ? {} : { codex: hooks.codex }),
66
+ };
67
+ }
68
+ const FILES = ['local', 'shared'];
69
+ /**
70
+ * The rules of agentwhy's own a file holds: whole rules, the kind `init` writes and can take back out (`IndexRule`). A
71
+ * rule written by hand is somebody's own work and stays where they put it, so it neither splits the scope nor moves.
72
+ */
73
+ function ownRules(settings, file) {
74
+ return (settings.held?.[file] ?? []).flatMap((pattern) => {
75
+ const rule = settings.mine?.[pattern];
76
+ return rule !== undefined && rule.whole ? [rule.rule] : [];
77
+ });
78
+ }
79
+ function scopeOf(settings, hooks) {
80
+ const used = FILES.filter((file) => hooks.watch === file || hooks.refuse === file || ownRules(settings, file).length > 0);
81
+ return used.length === 2 ? 'mixed' : used[0];
82
+ }
83
+ function movesInto(settings, hooks, into) {
84
+ const other = into === 'local' ? 'shared' : 'local';
85
+ return {
86
+ patterns: [...new Set(ownRules(settings, other))],
87
+ hooks: ['watch', 'refuse'].filter((hook) => hooks[hook] === other),
88
+ };
89
+ }
90
+ function uninstallFrom(settings, hooks) {
91
+ return Object.fromEntries(FILES.flatMap((file) => {
92
+ const rules = [...new Set(ownRules(settings, file))];
93
+ return hooks.watch === file || hooks.refuse === file || rules.length > 0 ? [[file, rules]] : [];
94
+ }));
95
+ }
96
+ function hookOf(where) {
97
+ return where === false ? { on: false } : { on: true, who: where };
98
+ }
99
+ /** The patterns the hooks watch, or undefined where they read a policy or a file this page cannot see into. */
100
+ function readPatterns(settings, reads) {
101
+ if (reads === 'default')
102
+ return new Set(BUILT_IN);
103
+ if (reads === 'local' || reads === 'shared')
104
+ return new Set(settings.held?.[reads] ?? []);
105
+ return undefined;
106
+ }
107
+ /** Every pattern of both told lists that could be read (F57). */
108
+ function toldIn(settings) {
109
+ return new Set(FILES.flatMap((file) => {
110
+ const list = settings.told?.[file];
111
+ return list === undefined || list === 'unreadable' ? [] : list;
112
+ }));
113
+ }
114
+ /**
115
+ * The rows where the hooks read the built-in list or a project file: the named groups first, in F33's order, each
116
+ * watched where the file holds any of its patterns or a told list does, then every other rule the file holds, as its
117
+ * pattern, then every told pattern no rule holds (F57). A row's switch goes to the other mode where this page can write
118
+ * both halves of it: the rules out of the files and the pattern into a list, or the other way round.
119
+ */
120
+ function fileRows(settings, reads, read, told, canTell) {
121
+ const ruleOf = (pattern) => {
122
+ const rule = settings.mine?.[pattern];
123
+ return rule !== undefined && rule.whole ? rule.rule : undefined;
124
+ };
125
+ // Going to `tell` takes the rules out; where one is a rule somebody wrote by hand, the page cannot, and offers nothing.
126
+ const toTell = (patterns) => {
127
+ if (!canTell)
128
+ return undefined;
129
+ const rules = reads === 'default' ? [] : patterns.map(ruleOf);
130
+ return rules.every((rule) => rule !== undefined) ? { to: 'tell', patterns, rules: rules } : undefined;
131
+ };
132
+ const toBlock = (patterns) => (canTell ? { to: 'block', patterns, rules: [] } : undefined);
133
+ const named = RULE_NAMES.map((group) => {
134
+ const blocked = group.patterns.filter((pattern) => read.has(pattern) && !told.has(pattern));
135
+ const toldHere = group.patterns.filter((pattern) => told.has(pattern));
136
+ if (blocked.length > 0)
137
+ return withSwitch({ name: group.name, patterns: blocked, source: 'agentwhy', watched: true, mode: 'block' }, toTell(blocked));
138
+ if (toldHere.length > 0)
139
+ return withSwitch({ name: group.name, patterns: toldHere, source: 'agentwhy', watched: true, mode: 'tell' }, toBlock(toldHere));
140
+ return { name: group.name, patterns: group.patterns, source: 'agentwhy', watched: false, mode: 'block' };
141
+ });
142
+ const own = [...read].filter((pattern) => !BUILT_IN.includes(pattern) && !told.has(pattern)).map((pattern) => {
143
+ const rule = settings.mine?.[pattern];
144
+ // Only a whole rule in the file the hooks read is one `init` could have written and can take back out; half a
145
+ // pair is somebody's own work (`IndexRule.whole`), and a pattern `mine` places in the other file cannot be
146
+ // removed from this one by name.
147
+ const removable = rule !== undefined && rule.whole && rule.file === reads;
148
+ return withSwitch({
149
+ patterns: [pattern],
150
+ source: removable ? 'you' : 'project',
151
+ watched: true,
152
+ mode: 'block',
153
+ ...(removable ? { remove: { rule: rule.rule, file: rule.file } } : {}),
154
+ }, toTell([pattern]));
155
+ });
156
+ const toldOnly = [...told].filter((pattern) => !BUILT_IN.includes(pattern)).map((pattern) => withSwitch({ patterns: [pattern], source: 'you', watched: true, mode: 'tell', ...(canTell ? { untell: [pattern] } : {}) }, toBlock([pattern])));
157
+ return [...named, ...own, ...toldOnly];
158
+ }
159
+ function withSwitch(row, switchTo) {
160
+ return switchTo === undefined ? row : { ...row, switchTo };
161
+ }
162
+ /**
163
+ * Where the hooks read a policy or another file, or what they read is unknown: the list this run read, as it is, and
164
+ * nothing here can change it. The built-in list is named in words where it is what the run read.
165
+ */
166
+ function policyRows(settings) {
167
+ const builtIn = settings.origin.kind === 'default';
168
+ const named = builtIn
169
+ ? RULE_NAMES.flatMap((group) => {
170
+ const held = group.patterns.filter((pattern) => settings.protected.includes(pattern));
171
+ return held.length === 0 ? [] : [{ name: group.name, patterns: held, source: 'agentwhy', watched: true, mode: 'block' }];
172
+ })
173
+ : [];
174
+ const rest = settings.protected.filter((pattern) => !builtIn || !BUILT_IN.includes(pattern));
175
+ return [...named, ...rest.map((pattern) => ({ patterns: [pattern], source: 'project', watched: true, mode: 'block' }))];
176
+ }
177
+ /**
178
+ * K1, K2: a watched `block` row, read for both halves of a block - its rules in either settings file, which Claude Code
179
+ * applies both of (R4d), and `refuse` running over rules that hold every pattern of it. Where `refuse` reads a policy or
180
+ * a file this page cannot see into, only the rules are claimed.
181
+ */
182
+ function keptOf(row, settings, hooks) {
183
+ if (!row.watched || row.mode !== 'block' || settings.held === undefined)
184
+ return row;
185
+ const ruled = row.patterns.filter((pattern) => denied(settings, pattern));
186
+ if (ruled.length === 0)
187
+ return { ...row, kept: 'none' };
188
+ const searched = hooks.refuse === false ? new Set() : readPatterns(settings, hooks.reads.refuse);
189
+ const whole = ruled.length === row.patterns.length && (searched === undefined || row.patterns.every((pattern) => searched.has(pattern)));
190
+ return whole ? row : { ...row, kept: 'open' };
191
+ }
192
+ function denied(settings, pattern) {
193
+ return FILES.some((file) => settings.held?.[file]?.includes(pattern) ?? false);
194
+ }
195
+ /**
196
+ * K9: what one confirmed write closes. Rules no file holds are written as an add writes them - with the built-in list,
197
+ * so that pointing the hooks at a file drops nothing they watched (S4.3), and never a pattern the person chose to be
198
+ * told about (F57) - and `refuse` with them. Where every rule is there, `refuse` alone, where it does not run. Where it
199
+ * runs and reads other rules, `init` does not point it again without writing a rule (R4d), so nothing is offered.
200
+ */
201
+ function unfinishedOf(settings, rows, withBuiltIn, told, refuseOn) {
202
+ const open = rows.filter((row) => row.kept !== undefined);
203
+ const missing = open.flatMap((row) => row.patterns.filter((pattern) => !denied(settings, pattern)));
204
+ const patterns = missing.length === 0 ? [] : [...new Set([...withBuiltIn, ...missing])].filter((pattern) => !told.has(pattern));
205
+ return { rows: open.length, patterns, refuse: open.length > 0 && patterns.length === 0 && !refuseOn };
206
+ }
207
+ /** F34: a rule a project file holds that the hooks do not read. A built-in pattern read anyway is not one. */
208
+ function unreadRules(settings, read) {
209
+ return Object.entries(settings.mine ?? {})
210
+ .filter(([pattern]) => !read.has(pattern))
211
+ .map(([, rule]) => ({ rule: rule.rule, file: rule.file }));
212
+ }
213
+ /** `hooks` is absent where the project's file could not be read: then what runs, and what it reads, is not known. */
214
+ function developerRows(settings, known, reads, unread) {
215
+ const hooks = known ?? NO_HOOKS;
216
+ const pathOf = (file) => (file === 'shared' ? hooks.sharedPath : hooks.path);
217
+ const where = (hook) => {
218
+ if (known === undefined)
219
+ return { word: 'set.dev.unknown' };
220
+ const file = hooks[hook];
221
+ return file === false ? { word: 'set.dev.notInstalled' } : pathOf(file);
222
+ };
223
+ const notices = settings.notices;
224
+ const rules = reads === 'local' || reads === 'shared'
225
+ ? [...(settings.held?.[reads] ?? [])].join(' ') + ' (' + pathOf(reads) + ')'
226
+ : reads === 'default' ? BUILT_IN.join(' ') : settings.protected.join(' ');
227
+ const unreadFiles = [...new Set(unread.map((rule) => pathOf(rule.file)))];
228
+ return [
229
+ { key: 'set.dev.watch', value: where('watch') },
230
+ { key: 'set.dev.refuse', value: where('refuse') },
231
+ { key: 'set.dev.reads', value: known === undefined ? { word: 'set.dev.unknown' } : reads === 'local' || reads === 'shared' ? pathOf(reads) : { word: 'set.dev.reads.' + reads } },
232
+ { key: 'set.dev.rules', value: known === undefined ? settings.protected.join(' ') : rules },
233
+ { key: 'set.dev.unread', value: unreadFiles.length === 0 ? { word: 'set.dev.none' } : unreadFiles.join(' ') },
234
+ { key: 'set.dev.exceptions', value: settings.allowed.length === 0 ? { word: 'set.dev.none' } : settings.allowed.join(' ') },
235
+ { key: 'set.dev.notices', value: notices === undefined ? { word: 'set.dev.none' } : notices.path },
236
+ { key: 'set.dev.on', value: notices?.on ?? DEFAULT_THRESHOLD },
237
+ { key: 'set.dev.clean', value: notices?.clean ?? DEFAULT_CLEAN },
238
+ ...(notices === undefined ? [] : [{ key: 'set.dev.said', value: notices.say + ' · ' + notices.notify.join(', ') }]),
239
+ ];
240
+ }