@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,299 @@
1
+ import { PROVIDER_NAMES } from '../../../core/session-format.js';
2
+ import { escapeHtml as e } from '../html-report-components.js';
3
+ import { inLanguages } from '../report-copy.js';
4
+ import { askCard, writtenAnswer } from '../ui/ask-panel.js';
5
+ import { pill } from '../ui/button.js';
6
+ import { fileChips } from '../ui/file-chip.js';
7
+ import { guideCard } from '../ui/guide-card.js';
8
+ import { hero } from '../ui/hero.js';
9
+ import { LOOKS } from '../ui/status-look.js';
10
+ import { opener } from '../ui/popup.js';
11
+ import { progressBar } from '../ui/progress.js';
12
+ import { tag } from '../ui/tag.js';
13
+ import { taskList } from '../ui/task-list.js';
14
+ import { helperViews } from './helpers.js';
15
+ import { titleOf } from './item-names.js';
16
+ /** The id of the Fix it window of the item at `at`. The page's own counter, never transcript text. */
17
+ export const fixId = (at) => 'fix-' + at;
18
+ /** The id of the window that says what happened to the item at `at`. */
19
+ export const storyId = (at) => 'story-' + at;
20
+ /**
21
+ * "Your to-do list" (the report page spec P6-P11, P59): the answer centred, one place to start, where the person is,
22
+ * and one card per file. With nothing to fix, "All good." and what happened - unless a key's shape came back in a result, which is never
23
+ * a clean session. A file with a standing mark (`done`, M5) is drawn done, and the place to start is the first one that
24
+ * is not (P44).
25
+ */
26
+ export function toDoView(items, report, marked, gaps, clock, rows, context, names) {
27
+ if (items.length === 0)
28
+ return '<div class="rp-narrow">' + whenLine(report, clock) + '</div>' + nothingView(report, gaps, rows, context, names);
29
+ const done = items.filter((item) => marked.has(item.path)).length;
30
+ const first = Math.max(items.findIndex((item) => !marked.has(item.path)), 0);
31
+ const finished = done === items.length;
32
+ return '<div class="rp-narrow">' + whenLine(report, clock) +
33
+ hero({
34
+ eyebrow: '',
35
+ fact: inLanguages((t) => t('rp.hero.fact', { n: items.length })),
36
+ action: inLanguages((t) => t('rp.hero.todo', { n: items.length })),
37
+ lead: inLanguages((t) => t('rp.hero.lead')),
38
+ centred: true,
39
+ // The maintainer, 2026-09-30: a mark above the answer, as on every other screen - coral while there is something to fix.
40
+ mark: finished ? 'tick' : 'todo',
41
+ }) +
42
+ '<div data-guide' + (finished ? ' hidden' : '') + '>' + guideCard({
43
+ tone: 'coral',
44
+ title: inLanguages((t) => t('rp.guide.start')),
45
+ body: inLanguages((t) => t('rp.guide.startBody')),
46
+ action: { label: inLanguages((t) => t('rp.guide.go')), href: '#' + fixId(first), attributes: opener(fixId(first)) + ' data-guide-go' },
47
+ }) + '</div>' +
48
+ '<div data-all-done' + (finished ? '' : ' hidden') + '>' + guideCard({
49
+ tone: 'mint',
50
+ title: inLanguages((t) => t('rp.done.title')),
51
+ body: inLanguages((t) => t(items.every((item) => item.kind === 'keys') ? 'rp.done.keys' : 'rp.done.other')),
52
+ }) + '</div>' +
53
+ (gaps ? gapBanner(report) : '') +
54
+ // P4, the maintainer 2026-09-30: "You asked" stands right above the list, as it stands above "What happened".
55
+ youAsked(context.title) +
56
+ '<div class="rp-todo-bar"><span class="rp-todo-label">' + inLanguages((t) => t('rp.todo.heading')) + '</span>' +
57
+ '<span data-progress>' + progressBar(done, items.length, inLanguages((t) => t('rp.todo.progress', { done: '<b data-done>' + done + '</b>', total: items.length }))) + '</span></div>' +
58
+ taskList([inLanguages((t) => t('rp.col.file')), inLanguages((t) => t('rp.col.details')), inLanguages((t) => t('rp.col.action'))], items.map((item, at) => ({
59
+ title: inLanguages((t, lang) => titleOf(item, t, lang)),
60
+ path: item.path,
61
+ label: names(item.path),
62
+ done: marked.has(item.path),
63
+ details: pill({ label: inLanguages((t) => t('rp.what')), tone: 'secondary', href: '#' + storyId(at), attributes: opener(storyId(at)) }),
64
+ action: pill({ label: inLanguages((t) => t('rp.fix')), tone: 'primary', size: 'task', href: '#' + fixId(at), attributes: opener(fixId(at)) }) +
65
+ '<span class="rp-done-tag">' + tag(inLanguages((t) => t('rp.fixed')), 'mint', 'md') + '</span>',
66
+ attributes: ' data-item="' + at + '" title="' + e(item.path) + '"',
67
+ }))) + '</div>';
68
+ }
69
+ /**
70
+ * P4, M4: which conversation this is - the day, and the first and last record's time, in the machine's time zone. A
71
+ * record with no time says nothing here rather than a guessed one.
72
+ */
73
+ function whenLine(report, clock) {
74
+ // X28: the page names the AI the conversation was with, a shared page too, on a line of its own above when it was.
75
+ const ai = '<p class="rp-ai">' + tag(e(PROVIDER_NAMES[report.scope.provider]), 'grey', 'badge') + '</p>';
76
+ const times = report.scope.times;
77
+ if (times === undefined)
78
+ return ai;
79
+ // A conversation that ran over more than one day names both days: "18:46 – 15:28" under one day would read as backwards.
80
+ const oneDay = clock.day(times.first, 'en') === clock.day(times.last, 'en');
81
+ const when = (lang) => oneDay
82
+ ? clock.day(times.first, lang) + ', ' + clock.time(times.first).slice(0, 5) + ' – ' + clock.time(times.last).slice(0, 5)
83
+ : clock.day(times.first, lang) + ', ' + clock.time(times.first).slice(0, 5) + ' – ' + clock.day(times.last, lang) + ', ' + clock.time(times.last).slice(0, 5);
84
+ return ai + '<p class="rp-when">' + inLanguages((t, lang) => t('rp.when', { when: '<b>' + e(when(lang)) + '</b>' })) + '</p>';
85
+ }
86
+ /**
87
+ * Why a Codex record has a gap, where that is what its format cannot show (`2026-09-27-what-codex-wrote.md` X23): an
88
+ * older record that shows no command at all (`legacy`), or one that does not show every step. Absent for any other record.
89
+ */
90
+ function codexGap(report) {
91
+ if (report.scope.provider !== 'codex')
92
+ return undefined;
93
+ const { capabilities } = report.recorded;
94
+ if (capabilities.some((one) => one.question === 'access' && one.state === 'absent'))
95
+ return 'legacy';
96
+ return capabilities.some((one) => one.question === 'actions' && one.state !== 'supported') ? 'partial' : undefined;
97
+ }
98
+ /** P60: a record with a gap says so above the list, and where to read what is missing - for Codex, in its own words (X23). */
99
+ function gapBanner(report) {
100
+ const words = codexGap(report) === undefined ? 'rp.gap.banner' : 'rp.gap.codex.banner';
101
+ return '<div class="rp-gap" role="note"><span class="rp-gap-mark" aria-hidden="true">!</span><span>' + inLanguages((t) => t(words)) + ' ' +
102
+ '<a class="rp-gap-link" href="#advanced" data-record-link>' + inLanguages((t) => t('rp.gap.link')) + '</a></span></div>';
103
+ }
104
+ function nothingView(report, gaps, rows, context, names) {
105
+ const say = (key, vars = {}) => inLanguages((t) => t(key, vars));
106
+ const shapes = [...new Set(report.secretShapes.flatMap((finding) => finding.classes.map(String)))];
107
+ const back = context.back ? '<div class="rp-back">' + pill({ label: say('rp.nothing.back'), tone: 'light', size: 'lg', href: 'index.html' }) + '</div>' : '';
108
+ // P59: a key's shape in a result is never a clean screen - but it is not a to-do item either, since no protected file
109
+ // is known to hold it. The answer says what to do and where the record shows it, and the summary says what else the AI
110
+ // did, as on a clean screen (unless the record has a gap, P60). Drawn as every other screen is (the maintainer,
111
+ // 2026-09-30): the mark, the two lines, the lead, its one button.
112
+ if (shapes.length > 0) {
113
+ return '<div class="rp-narrow rp-alone">' +
114
+ hero({
115
+ eyebrow: '',
116
+ fact: say('rp.shape.fact'),
117
+ action: say('rp.shape.action'),
118
+ lead: inLanguages((t) => t('rp.shape.title') + ' ' + t('rp.shape.body', { kinds: '<code>' + shapes.map((shape) => e(shape)).join(', ') + '</code>' }) + ' ' + t('rp.shape.next')),
119
+ centred: true,
120
+ mark: 'alert',
121
+ }) +
122
+ heroGo(say('rp.shape.link')) + youAsked(context.title) + whatHappened(report, rows, { shape: true, gaps }, names) + back + '</div>';
123
+ }
124
+ // P60, invariant 4: with a gap in the record, no evidence is not "nothing happened", so the all-clear is not drawn.
125
+ // The screen is the clean one's all the same (the maintainer, 2026-09-30): the centred answer - nothing to fix that
126
+ // the record shows, in amber, since the rest is not known - where to read what is missing, and what the record does show.
127
+ if (gaps) {
128
+ // X23: a Codex record says what its format cannot show - never "part of it is missing", which blames nobody right.
129
+ const codex = codexGap(report);
130
+ // The maintainer, 2026-09-30: where the record shows a private file stopped, and none whose outcome is not recorded,
131
+ // that is said in mint - the protection worked - and the gap moves to the line under it; never "All good.".
132
+ const stopped = rows.some((row) => row.private && row.access === 'stopped') && !rows.some((row) => row.private && row.access === 'unknown');
133
+ return '<div class="rp-narrow rp-alone">' +
134
+ hero({
135
+ eyebrow: '',
136
+ fact: say('rp.gap.fact'),
137
+ action: say(stopped ? 'rp.gap.stopped' : codex === undefined ? 'rp.gap.action' : codex === 'legacy' ? 'rp.gap.codex.legacyAction' : 'rp.gap.codex.action'),
138
+ lead: say(codex === undefined ? 'rp.gap.body' : codex === 'legacy' ? 'rp.gap.codex.legacy' : stopped ? 'rp.gap.codex.lead' : 'rp.gap.codex.body'),
139
+ centred: true,
140
+ ...(stopped ? { calm: true, mark: 'tick' } : { mark: 'unsure' }),
141
+ }) +
142
+ heroGo(say('rp.gap.link')) +
143
+ youAsked(context.title) + whatHappened(report, rows, { shape: false, gaps }, names) + back + '</div>';
144
+ }
145
+ const named = rows.filter((row) => row.private && row.access === 'name').length;
146
+ // F57a: a private file read with nothing to do is one the person chose Tell me for - never "didn't read anything private".
147
+ const allowed = allowedReads(rows).length > 0;
148
+ return '<div class="rp-narrow rp-alone">' +
149
+ hero({ eyebrow: '', fact: say('rp.nothing.fact'), action: say('rp.nothing.action'), lead: say(allowed ? 'rp.nothing.allowed' : 'rp.nothing.title'), centred: true, calm: true, mark: 'tick' }) +
150
+ youAsked(context.title) + whatHappened(report, rows, { shape: false, gaps: false }, names) + back +
151
+ askCard(say('rp.ask.title'), [...(named > 0 ? ['name'] : []), 'safe', 'change'].map((key) => ({
152
+ question: say('rp.ask.' + key),
153
+ answer: inLanguages((t) => writtenAnswer(t('rp.ask.' + key + (key === 'safe' && allowed ? 'AllowedA' : 'A')))),
154
+ })), 'rp-ask') +
155
+ '<details class="rp-dev"><summary class="rp-dev-line">' + say('rp.dev.title') + '<span class="rp-dev-caret" aria-hidden="true">▾</span></summary>' +
156
+ '<div class="rp-dev-body"><span class="rp-did-note">' + say('fl.commands') + '</span>' +
157
+ pill({ label: say('rp.clean.record'), tone: 'secondary', href: '#advanced' }) + '</div></details></div>';
158
+ }
159
+ /** The one button under a screen's answer, where it leads to the record (P59, P60). */
160
+ function heroGo(label) {
161
+ return '<div class="rp-hero-go">' + pill({ label, tone: 'primary', size: 'lg', href: '#advanced', attributes: ' data-record-link' }) + '</div>';
162
+ }
163
+ /**
164
+ * The private files the AI read that ask for nothing (F57a): on a screen with nothing to fix, every private file read is
165
+ * one the person chose Tell me for and that held no key - the to-do list keeps every other read.
166
+ */
167
+ function allowedReads(rows) {
168
+ return rows.filter((row) => row.private && row.access === 'read' && row.item === undefined).map((row) => row.path);
169
+ }
170
+ /** P4: "You asked" - the title Claude Code gave the session, which is what Conversations lists it by. Absent says nothing. */
171
+ function youAsked(title) {
172
+ if (title === undefined)
173
+ return '';
174
+ return '<div class="rp-asked"><span class="rp-asked-mark" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" ' +
175
+ 'stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="3.5"/><path d="M5 20c1.2-3.6 3.8-5.5 7-5.5s5.8 1.9 7 5.5"/></svg></span>' +
176
+ '<span><span class="rp-asked-label">' + inLanguages((t) => t('rp.asked')) + '</span>' +
177
+ '<span class="rp-asked-title">' + e(title) + '</span></span></div>';
178
+ }
179
+ /**
180
+ * P11: what the AI did in this conversation, so a clean screen says what happened - from the model's facts only: that
181
+ * no private file was opened, or the ones it read because the person let it (F57a), the private files it only saw the
182
+ * name of, was stopped from, or whose outcome is not recorded, and the helpers it brought in. Each line says why it asks nothing, in the colours every page uses (mint =
183
+ * nothing reached, blue = only saw the name, grey = not known). The foot says what the record cannot show and leads to
184
+ * every file. Under P59's card (`shape`) no line says the keys stayed closed: a result carried something like one.
185
+ */
186
+ function whatHappened(report, rows, under, names) {
187
+ const say = (key, vars = {}) => inLanguages((t) => t(key, vars));
188
+ const privately = (access) => rows.filter((row) => row.private && row.access === access).map((row) => row.path);
189
+ const lines = [];
190
+ // Invariant 4: an outcome not recorded is said as that, and then no line says no private file was opened - nor
191
+ // under P60's card, where part of the record is missing.
192
+ const unknown = privately('unknown');
193
+ const allowed = allowedReads(rows);
194
+ if (unknown.length === 0 && allowed.length === 0 && !under.gaps) {
195
+ lines.push({ glyph: '✓', tone: 'mint', title: say('rp.clean.private'), tag: { label: say('rp.clean.privateTag'), tone: 'mint' },
196
+ line: say(under.shape ? 'rp.clean.privateShape' : 'rp.clean.privateLine') });
197
+ }
198
+ // It read them, and that stays said (F57a); in Track's sand, since the choice was the person's and there is nothing to do.
199
+ if (allowed.length > 0) {
200
+ lines.push({ glyph: LOOKS.allowed.glyph, tone: LOOKS.allowed.tone, title: say('rp.clean.allowed', { n: allowed.length }), tag: { label: say('fl.mode.told'), tone: 'sand' },
201
+ line: say('rp.clean.allowedLine', { n: allowed.length }), paths: allowed });
202
+ }
203
+ const named = privately('name');
204
+ if (named.length > 0) {
205
+ lines.push({ glyph: LOOKS.name.glyph, tone: LOOKS.name.tone, title: say('rp.clean.named', { n: named.length }), tag: { label: say(LOOKS.name.label), tone: 'blue' },
206
+ // X10: under P60's gap card a name seen is not "nothing to do" - the record cannot show the AI saw no more.
207
+ line: say(under.gaps ? 'rp.clean.namedLineGap' : 'rp.clean.namedLine', { n: named.length }), paths: named });
208
+ }
209
+ const stopped = privately('stopped');
210
+ if (stopped.length > 0) {
211
+ lines.push({ glyph: LOOKS.stopped.glyph, tone: 'mint', title: say('rp.clean.stopped', { n: stopped.length }), tag: { label: say(LOOKS.stopped.label), tone: 'mint' },
212
+ line: say('rp.clean.stoppedLine'), paths: stopped });
213
+ }
214
+ if (unknown.length > 0) {
215
+ lines.push({ glyph: LOOKS.unchecked.glyph, tone: 'grey', title: say('rp.clean.unknown', { n: unknown.length }), tag: { label: say(LOOKS.unchecked.label), tone: 'grey' },
216
+ line: say('rp.clean.unknownLine'), paths: unknown });
217
+ }
218
+ lines.push(helpersLine(report));
219
+ return '<section class="rp-did"><h2 class="rp-did-heading">' + say('rp.clean.heading') + '</h2>' +
220
+ '<div class="rp-did-card"><ul class="rp-did-list">' + lines.map((row) => didRow(row, names)).join('') + '</ul>' +
221
+ '<div class="rp-did-foot"><span class="rp-did-note">' + say('st.foot') + '</span>' +
222
+ (rows.length === 0 ? '' : pill({ label: say('rp.clean.seeFiles'), tone: 'secondary', href: '#files' })) + '</div></div></section>';
223
+ }
224
+ /**
225
+ * The helpers it brought in. "None of them read your private files" is said only where every helper's own steps say so;
226
+ * a helper whose actions or outcome were not recorded is never counted as one that read nothing (invariant 4).
227
+ */
228
+ function helpersLine(report) {
229
+ const say = (key, vars = {}) => inLanguages((t) => t(key, vars));
230
+ const helpers = helperViews(report).filter((view) => view.agent.ordinal !== undefined);
231
+ if (helpers.length === 0) {
232
+ return { glyph: '✓', tone: 'mint', title: say('rp.clean.noHelpers'), tag: { label: say('rp.clean.noHelpersTag'), tone: 'mint' }, line: say('rp.clean.alone') };
233
+ }
234
+ const n = helpers.length;
235
+ const read = helpers.filter((view) => view.status === 'read').length;
236
+ const unrecorded = helpers.some((view) => view.status === 'unknown' || view.status === 'empty');
237
+ const look = read > 0 ? 'read' : unrecorded ? 'unchecked' : 'none';
238
+ const tone = look === 'none' ? 'mint' : LOOKS[look].tone;
239
+ return {
240
+ glyph: LOOKS[look].glyph,
241
+ tone,
242
+ title: say('rp.clean.helpers', { n }),
243
+ tag: { label: say(LOOKS[look].label), tone },
244
+ line: read > 0 ? (read === n ? say('hp.all', { n }) : say('hp.some', { n: read }))
245
+ : unrecorded ? say('rp.clean.helpersUnknown', { n }) : say('rp.clean.helpersClean', { n }),
246
+ link: { label: say('rp.clean.seeHelpers'), href: '#helpers' },
247
+ };
248
+ }
249
+ function didRow(row, names) {
250
+ return '<li class="rp-did-row"><span class="look look-' + row.tone + '"><span class="look-glyph" aria-hidden="true">' + row.glyph + '</span></span>' +
251
+ '<span class="rp-did-text"><span class="rp-did-title">' + row.title + ' ' + tag(row.tag.label, row.tag.tone, 'badge') + '</span>' +
252
+ '<span class="rp-did-line">' + row.line + '</span>' +
253
+ (row.paths === undefined ? '' : '<span class="rp-did-chips">' + fileChips(row.paths, 3, names) + '</span>') + '</span>' +
254
+ (row.link === undefined ? '' : pill({ label: row.link.label, tone: 'secondary', href: row.link.href })) + '</li>';
255
+ }
256
+ export const TO_DO_VIEW_STYLE = String.raw `
257
+ .rp-narrow{max-width:840px;margin:0 auto}
258
+ /* A light gap under "Report from", the same above every screen's mark (the maintainer, 2026-09-30). */
259
+ .rp-alone,.rp-narrow:not(.rp-alone)>.hero-centred{padding-top:16px}
260
+ .rp-todo-bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;padding:0 4px}
261
+ .rp-todo-label{font-size:14px;color:var(--text-2)}
262
+ .rp-gap{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;margin:0 0 18px;border-radius:14px;background:var(--coral-07);border:1px solid var(--coral-35);font-size:15px;line-height:1.5}
263
+ .rp-gap-mark{flex:none;width:24px;height:24px;border-radius:50%;background:var(--coral);color:var(--on-coral);font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center}
264
+ .rp-gap-link{font-weight:600;color:var(--coral-text);white-space:nowrap}
265
+ .rp-hero-go{display:flex;justify-content:center;margin:-12px 0 36px}
266
+ .rp-narrow .hero-lead code{font-size:14px;color:var(--text-soft)}
267
+ /* X28: which AI the page is about, readable at a glance above the heading - the badge of the kit, larger here alone. */
268
+ .rp-ai{margin:0 0 14px;text-align:center}
269
+ .rp-ai .tag-badge{font-size:15px;padding:7px 18px;color:var(--text);background:var(--white-10);border:1px solid var(--white-28)}
270
+ .rp-when{margin:0 0 18px;text-align:center;font-size:14px;color:var(--text-3)}.rp-when b{color:var(--text-soft);font-weight:600}
271
+ .rp-did-heading{margin:0 0 12px;padding:0 4px;font-size:14px;font-weight:600;color:var(--text-2)}
272
+ .rp-did-card{border-radius:18px;background:var(--card);border:1px solid var(--white-09);overflow:hidden}
273
+ .rp-did-list{list-style:none;margin:0;padding:0}
274
+ .rp-did-row{display:flex;align-items:flex-start;gap:18px;flex-wrap:wrap;padding:22px 24px;border-bottom:1px solid var(--white-06)}
275
+ .rp-did-row>.look{margin-top:1px}
276
+ .rp-did-row>.look .look-glyph{width:30px;height:30px;font-size:14px}
277
+ .rp-did-row>.pill{align-self:center}
278
+ .rp-did-text{flex:1;min-width:220px}
279
+ .rp-did-title{display:flex;align-items:center;flex-wrap:wrap;gap:6px 10px;font-size:17px;font-weight:600;line-height:1.35}
280
+ .rp-did-line{display:block;margin-top:4px;font-size:15px;line-height:1.5;color:var(--text-2)}
281
+ .rp-did-chips{display:block;margin-top:10px}
282
+ .rp-did-foot{display:flex;align-items:center;justify-content:space-between;gap:12px 20px;flex-wrap:wrap;padding:18px 24px}
283
+ .rp-did-note{flex:1;min-width:220px;font-size:14px;line-height:1.5;color:var(--text-3)}
284
+ .rp-asked{display:flex;align-items:center;gap:16px;margin:0 0 30px;padding:18px 22px;border-radius:18px;background:var(--card);border:1px solid var(--white-09)}
285
+ .rp-asked-mark{flex:none;width:36px;height:36px;border-radius:50%;border:1px solid var(--white-14);color:var(--text-soft);display:flex;align-items:center;justify-content:center}
286
+ .rp-asked-mark svg{width:18px;height:18px}
287
+ .rp-asked-label{display:block;font-size:13px;font-weight:600;color:var(--text-3)}
288
+ .rp-asked-title{display:block;margin-top:2px;font-size:17px;font-weight:600;line-height:1.4;overflow-wrap:anywhere}
289
+ .rp-back{display:flex;justify-content:center;margin:34px 0 8px}
290
+ .rp-dev{margin-top:26px}
291
+ .rp-dev-line{display:inline-flex;align-items:center;gap:6px;padding:4px;font-size:14px;font-weight:600;color:var(--text-2);cursor:pointer;list-style:none}
292
+ .rp-dev-line::-webkit-details-marker{display:none}
293
+ .rp-dev-line:hover{color:var(--text)}
294
+ .rp-dev-caret{font-size:11px;transition:transform .15s}.rp-dev[open] .rp-dev-caret{transform:rotate(180deg)}
295
+ .rp-dev-body{display:flex;align-items:center;justify-content:space-between;gap:12px 20px;flex-wrap:wrap;margin-top:12px;padding:16px 20px;border-radius:14px;background:var(--panel);border:1px solid var(--white-08)}
296
+ @media (max-width:640px){.rp-did-row{padding:18px;gap:14px}.rp-did-foot{padding:16px 18px}.rp-asked{padding:16px 18px}}
297
+ .rp-done-tag{display:none}
298
+ .tc-done .rp-done-tag{display:inline-flex}.tc-done .tc-action>.pill{display:none}
299
+ `;
@@ -0,0 +1,152 @@
1
+ import { actionsOf, holdsKeys } from '../../check/session-actions.js';
2
+ import { readIn } from '../../flow-reads.js';
3
+ import { ruleKey } from './item-names.js';
4
+ import { nameWords, providerOfName, providerOfPattern } from './providers.js';
5
+ /** Shapes many keys share, as against a key's own format: only a key of such a shape is judged by its line's name. */
6
+ const SHAPES = new Set(['jwt', 'high-entropy value', 'value beside a sensitive name']);
7
+ const SECRET_WORDS = new Set(['SECRET', 'SERVICE', 'PRIVATE', 'PASSWORD', 'PASS', 'PWD', 'ADMIN', 'MASTER']);
8
+ const PUBLIC_WORDS = new Set(['ANON', 'PUBLISHABLE']);
9
+ const TEST_WORDS = new Set(['TEST', 'SANDBOX']);
10
+ /**
11
+ * A key line's urgency (the report page spec P20b). A key's own format - a live Stripe key, a private key block - is a
12
+ * secret. So is a name that says it is one (`SERVICE_ROLE`, `SECRET`, `PASSWORD`), even under a framework's public
13
+ * prefix, where a secret is already shown to everyone and changing it is most urgent. A name a framework ships to the
14
+ * browser (`NEXT_PUBLIC_`, `VITE_`), or an anon, publishable or public key, is public; a test or sandbox key is less
15
+ * urgent. From names, so a guess, and said as one.
16
+ */
17
+ export function urgencyOf(line) {
18
+ if (!SHAPES.has(line.key))
19
+ return 'secret';
20
+ const { words, shipped } = nameWords(line.name);
21
+ const test = words.some((word) => TEST_WORDS.has(word));
22
+ if (words.some((word) => SECRET_WORDS.has(word)))
23
+ return test ? 'test' : 'secret';
24
+ if (shipped || words.some((word) => PUBLIC_WORDS.has(word)) || words.join('_').includes('PUBLIC_KEY'))
25
+ return 'public';
26
+ return test ? 'test' : 'secret';
27
+ }
28
+ /**
29
+ * The to-do list, in the order F21 gives: files a value went further from first, then files of keys, then files whose
30
+ * contents cannot be changed; within each, in the order the session first reached them.
31
+ */
32
+ export function toDoItems(report) {
33
+ const actions = actionsOf(report);
34
+ const seen = new Map(actions.rotate.map((file) => [file.path, file.template]));
35
+ const further = furtherPaths(report);
36
+ const patternOf = new Map(report.findings.map((finding) => [finding.path, finding.pattern]));
37
+ const items = report.privateFiles
38
+ .filter((file) => seen.has(file.path))
39
+ .map((file) => {
40
+ const pattern = patternOf.get(file.path);
41
+ return toDoItem(file.path, file, {
42
+ template: seen.get(file.path) === true,
43
+ further: further.has(file.path),
44
+ readers: readersOf(report, file.path),
45
+ ...(pattern === undefined ? {} : { pattern }),
46
+ });
47
+ });
48
+ const rank = (item) => (item.further ? 0 : item.kind === 'keys' ? 1 : 2);
49
+ return items.map((item, at) => ({ item, at })).sort((a, b) => rank(a.item) - rank(b.item) || a.at - b.at).map(({ item }) => item);
50
+ }
51
+ /**
52
+ * One file as the Fix it wizard draws it, from what was read from it - the report page from its session, To fix from
53
+ * every session that read it (`FileRead`, merged).
54
+ */
55
+ export function toDoItem(path, file, facts) {
56
+ const { providers, guesses, lines, tests, open, unnamed } = servicesOf(file);
57
+ const kept = file.keyed.filter((line) => !open.includes(line.name));
58
+ // F45, amended 2026-09-24: a file one of the built-in rules protects - `.env*`, `.npmrc`, `secrets/`, SSH keys - is
59
+ // a file of passwords and keys by the rule that matched it, which is a fact. Where no known format was found in it,
60
+ // or its text was never read as its own (a `grep`, a read of several files), its keys are ones we cannot name - it
61
+ // is never asked "what's in this file?", a question for a file only the person's own rule protects.
62
+ const byRule = ruleKey(facts.pattern) !== undefined;
63
+ const keys = holdsKeys(file) || byRule;
64
+ return {
65
+ path,
66
+ kind: keys ? 'keys' : 'data',
67
+ providers,
68
+ guesses,
69
+ lines,
70
+ tests,
71
+ open,
72
+ keyCount: file.keyed.length,
73
+ unnamed,
74
+ names: kept.length > 0 ? kept.map((line) => line.name) : file.names,
75
+ keyedNames: kept.length > 0,
76
+ template: facts.template,
77
+ further: facts.further,
78
+ readers: facts.readers,
79
+ ...(facts.pattern === undefined ? {} : { pattern: facts.pattern }),
80
+ };
81
+ }
82
+ /** Nothing was read from a file that could be named: no key format, no line. */
83
+ export const NOTHING_READ = { keys: [], names: [], keyed: [] };
84
+ /**
85
+ * Which services a file's keys are for (F45): by a key's format first, a fact; then, for a key line no format names, by
86
+ * the line's variable name (O11), a guess; and a key line neither names is left to the person, by its name. A key class
87
+ * no key line accounts for - a value that stood beside no name - is one nothing here can place. Lines are taken most
88
+ * urgent first (P20b), and a public one is set apart - unless it is all there is, with nothing to set it apart from.
89
+ */
90
+ function servicesOf(file) {
91
+ const providers = new Map();
92
+ for (const key of file.keys) {
93
+ const provider = providerOfPattern(key);
94
+ if (provider !== undefined && !providers.has(provider.name))
95
+ providers.set(provider.name, provider);
96
+ }
97
+ const RANK = { secret: 0, test: 1, public: 2 };
98
+ const ranked = file.keyed.map((line, at) => ({ line, at, urgency: urgencyOf(line) }))
99
+ .sort((a, b) => RANK[a.urgency] - RANK[b.urgency] || a.at - b.at);
100
+ const setApart = providers.size > 0 || ranked.some((each) => each.urgency !== 'public');
101
+ const guesses = new Map();
102
+ const lines = [];
103
+ const tests = [];
104
+ const open = [];
105
+ for (const { line, urgency } of ranked) {
106
+ if (urgency === 'public' && setApart) {
107
+ open.push(line.name);
108
+ continue;
109
+ }
110
+ if (urgency === 'test')
111
+ tests.push(line.name);
112
+ if (providerOfPattern(line.key) !== undefined)
113
+ continue;
114
+ const provider = providerOfName(line.name);
115
+ if (provider === undefined)
116
+ lines.push(line.name);
117
+ else if (!providers.has(provider.name)) {
118
+ const guess = guesses.get(provider.name) ?? { provider, names: [] };
119
+ guess.names.push(line.name);
120
+ guesses.set(provider.name, guess);
121
+ }
122
+ }
123
+ const placed = new Set(file.keyed.map((line) => String(line.key)));
124
+ const unplaced = file.keys.some((key) => providerOfPattern(key) === undefined && !placed.has(key));
125
+ return { providers: [...providers.values()], guesses: [...guesses.values()], lines, tests, open, unnamed: unplaced || file.mixed === true };
126
+ }
127
+ /** The paths a value went further from: a reply that carried it, a file it was written into, a use of it. */
128
+ function furtherPaths(report) {
129
+ const paths = new Set();
130
+ for (const statement of report.returns) {
131
+ if (statement.strength === 'value')
132
+ for (const path of statement.paths)
133
+ paths.add(path);
134
+ for (const path of statement.writtenFrom)
135
+ paths.add(path);
136
+ }
137
+ for (const use of report.uses)
138
+ for (const path of use.files)
139
+ paths.add(path);
140
+ return paths;
141
+ }
142
+ /** The agents whose own steps carried a value read from this file. */
143
+ function readersOf(report, path) {
144
+ const agents = new Set();
145
+ for (const flow of report.flows) {
146
+ for (const step of flow.steps) {
147
+ if ((step.kind === 'reached' && readIn(step, path)) || (step.kind === 'received' && step.files.map(String).includes(path)))
148
+ agents.add(flow.agentIndex);
149
+ }
150
+ }
151
+ return Math.max(agents.size, 1);
152
+ }
@@ -0,0 +1 @@
1
+ export {};