@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,129 @@
1
+ import { escapeHtml as e } from '../html-report-components.js';
2
+ import { CONTENT_SECURITY_POLICY_META, INDEX_CONTENT_SECURITY_POLICY_META } from '../html-head.js';
3
+ import { inLanguages } from '../report-copy.js';
4
+ import { appSidebar, APP_SIDEBAR_STYLE } from '../ui/app-sidebar.js';
5
+ import { ASK_PANEL_SCRIPT, ASK_PANEL_STYLE } from '../ui/ask-panel.js';
6
+ import { AVATAR_STYLE } from '../ui/avatar.js';
7
+ import { DATA_TABLE_STYLE } from '../ui/data-table.js';
8
+ import { LABELLED_SELECT_STYLE } from '../ui/labelled-select.js';
9
+ import { STATUS_ICON_STYLE } from '../ui/status-icon.js';
10
+ import { BUTTON_STYLE } from '../ui/button.js';
11
+ import { CALLOUT_STYLE } from '../ui/callout.js';
12
+ import { CHECKLIST_SCRIPT, CHECKLIST_STYLE } from '../ui/checklist.js';
13
+ import { confirmDialog, CONFIRM_DIALOG_STYLE } from '../ui/confirm-dialog.js';
14
+ import { DRAWER_STYLE } from '../ui/drawer.js';
15
+ import { FILE_CHIP_SCRIPT, FILE_CHIP_STYLE } from '../ui/file-chip.js';
16
+ import { FOLD_LINE_STYLE } from '../ui/fold-line.js';
17
+ import { GUIDE_CARD_STYLE } from '../ui/guide-card.js';
18
+ import { HERO_STYLE } from '../ui/hero.js';
19
+ import { pageShell } from '../ui/page-shell.js';
20
+ import { POPUP_SCRIPT, POPUP_STYLE } from '../ui/popup.js';
21
+ import { PILL_TABS_SCRIPT, PILL_TABS_STYLE } from '../ui/pill-tabs.js';
22
+ import { PROGRESS_STYLE } from '../ui/progress.js';
23
+ import { STAT_STYLE } from '../ui/stats.js';
24
+ import { TAG_STYLE } from '../ui/tag.js';
25
+ import { TASK_LIST_STYLE } from '../ui/task-list.js';
26
+ import { FIX_WIZARD_SCRIPT } from './fix-wizard-script.js';
27
+ import { ADVANCED_SCRIPT, ADVANCED_VIEW_STYLE, advancedView } from './advanced-view.js';
28
+ import { commandRow, fixWizard, FIX_WIZARD_STYLE } from './fix-wizard.js';
29
+ import { savedInto } from './file-story.js';
30
+ import { fileRows, onlyNamed } from './files.js';
31
+ import { FILES_SCRIPT, FILES_VIEW_STYLE, fileWindows, filesView } from './files-view.js';
32
+ import { helperDrawers, HELPERS_SCRIPT, HELPERS_VIEW_STYLE, helpersView } from './helpers-view.js';
33
+ import { fileNames, nameOf } from './item-names.js';
34
+ import { protectPatterns } from './protect-patterns.js';
35
+ import { recordGaps, RECORD_VIEW_STYLE } from './record-view.js';
36
+ import { storyWindow, STORY_WINDOW_STYLE } from './story-window.js';
37
+ import { toDoItems } from './to-do.js';
38
+ import { REPORT_VIEWS_SCRIPT, REPORT_VIEWS_STYLE } from './report-views.js';
39
+ import { clockIn } from './times.js';
40
+ import { toDoView, TO_DO_VIEW_STYLE } from './to-do-view.js';
41
+ /**
42
+ * The report page, rebuilt on the UI kit (`specs/2026-09-23-the-report-page.md`; `.ai/plans/2026-09-23-report-redesign.md`).
43
+ * Built beside `HtmlReportRenderer`, which stays the page `report --html` and `start` write until every view is here
44
+ * (slice h). So far: the to-do list, the Fix it wizard (slice c), what happened to each file (slice d), Helpers
45
+ * (slice e), Files, with Protect it on any private file (slice f), and Advanced (slice g).
46
+ *
47
+ * Served by `start`, the page may reach the origin it came from and sends its marks and rules there (P43); written on
48
+ * its own it reaches nowhere, as every other page, and hands over the command instead. A shared copy does neither (P46).
49
+ */
50
+ export class ReportPageRenderer {
51
+ render(page) {
52
+ const { report } = page;
53
+ const items = toDoItems(report);
54
+ const shared = report.scope.paths.shared;
55
+ const served = page.served === true && !shared;
56
+ const done = new Set(shared ? [] : items.map((item) => item.path).filter((path) => page.marks?.has(path) === true));
57
+ const rows = fileRows(report, items, done, page.denied);
58
+ // R5: every file the page names, so two of one name are told apart wherever either is named - its rows, and the files
59
+ // a story says a value was saved into, which need not be rows (found by a review). Every story the page tells is a row's.
60
+ const paths = rows.map((row) => row.path);
61
+ const names = fileNames([...paths, ...savedInto(report, paths)]);
62
+ // One Protect window per file, keyed by its row: the wizard, the table and a file's own window open the same one.
63
+ const protectKeys = new Map();
64
+ const patterns = new Map();
65
+ rows.forEach((row, key) => {
66
+ // A told file (F57) is the person's choice, and not a file to talk them out of from here: Settings switches it.
67
+ const found = row.protection !== 'yes' && row.protection !== 'told' ? protectPatterns(row.path, shared) : undefined;
68
+ if (found === undefined)
69
+ return;
70
+ protectKeys.set(row.path, key);
71
+ patterns.set(key, found);
72
+ });
73
+ const toldPaths = new Set(rows.filter((row) => row.protection === 'told').map((row) => row.path));
74
+ const protectedPaths = new Set(rows.filter((row) => row.protection === 'yes').map((row) => row.path));
75
+ const clock = clockIn(page.timeZone);
76
+ const nav = [
77
+ ...(page.withIndexLink ? [{ name: 'rp.nav.back', href: 'index.html' }] : []),
78
+ { name: 'rp.nav.todo', href: '#todo', active: true, count: items.length, countTone: 'coral' },
79
+ { name: 'rp.nav.files', href: '#files', count: rows.filter((row) => !onlyNamed(row)).length },
80
+ { name: 'rp.nav.helpers', href: '#helpers', count: report.graph.agents.length },
81
+ { name: 'rp.nav.advanced', href: '#advanced' },
82
+ ];
83
+ return pageShell({
84
+ title: 'rp.title',
85
+ policy: served ? INDEX_CONTENT_SECURITY_POLICY_META : CONTENT_SECURITY_POLICY_META,
86
+ styles: [APP_SIDEBAR_STYLE, BUTTON_STYLE, HERO_STYLE, GUIDE_CARD_STYLE, PROGRESS_STYLE, TAG_STYLE, TASK_LIST_STYLE, POPUP_STYLE,
87
+ CHECKLIST_STYLE, ASK_PANEL_STYLE, FILE_CHIP_STYLE, CONFIRM_DIALOG_STYLE, AVATAR_STYLE, PILL_TABS_STYLE, STAT_STYLE, TO_DO_VIEW_STYLE, FIX_WIZARD_STYLE,
88
+ STORY_WINDOW_STYLE, DRAWER_STYLE, FOLD_LINE_STYLE, HELPERS_VIEW_STYLE, DATA_TABLE_STYLE, LABELLED_SELECT_STYLE, STATUS_ICON_STYLE, FILES_VIEW_STYLE,
89
+ ADVANCED_VIEW_STYLE, CALLOUT_STYLE, RECORD_VIEW_STYLE, REPORT_VIEWS_STYLE],
90
+ scripts: [POPUP_SCRIPT, CHECKLIST_SCRIPT, ASK_PANEL_SCRIPT, FILE_CHIP_SCRIPT, PILL_TABS_SCRIPT, FIX_WIZARD_SCRIPT, HELPERS_SCRIPT, FILES_SCRIPT, ADVANCED_SCRIPT, REPORT_VIEWS_SCRIPT],
91
+ sidebar: appSidebar({ home: page.withIndexLink ? 'index.html' : '#todo', items: nav, showProject: false }),
92
+ main: '<section id="todo" data-view>' + toDoView(items, report, done, recordGaps(report).any, clock, rows, { back: page.withIndexLink, ...(page.title === undefined ? {} : { title: page.title }) }, names) + '</section>' +
93
+ '<section id="files" data-view>' + filesView(rows, items, protectKeys, names) + '</section>' +
94
+ '<section id="helpers" data-view>' + helpersView(report, items, names) + '</section>' +
95
+ '<section id="advanced" data-view>' + advancedView(report, items, done, clock, names) + '</section>' +
96
+ // Windows opened from more than one view live outside all of them (a hidden view hides what is in it).
97
+ helperDrawers(report, items, done, names) + fileWindows(rows, protectKeys, report, clock, names) +
98
+ items.map((item, at) => storyWindow(item, at, report, done.has(item.path), clock, names)).join('') +
99
+ items.map((_item, at) => fixWizard(items, at, { done, shared, protectKeys, protectedPaths, toldPaths, names })).join('') +
100
+ [...patterns].map(([key, found]) => protectWindow(rows[key], key, found, names)).join('') +
101
+ '<div id="wizard-words" data-served="' + served + '" hidden>' + ['wz.all', 'wz.finish', 'wz.saving', 'wz.tickFirst', 'wz.pickFirst']
102
+ .map((key) => '<span data-word="' + key + '">' + inLanguages((t) => t(key)) + '</span>').join('') + '</div>',
103
+ });
104
+ }
105
+ }
106
+ /**
107
+ * "Protect this file?" (P38, P38a-c): the file's own path, or every file of its name where the option is ticked. The
108
+ * page's script sends the rule served, and otherwise shows the `init --protect` command in the window (R61). For an
109
+ * everyday file it is "Make this file private?": the same rule, which is what adding a file in Settings writes.
110
+ */
111
+ function protectWindow(row, at, patterns, names) {
112
+ const path = row.path;
113
+ // The option protects every file of its name, so it says the name alone; the chip says which file this is.
114
+ const name = e(nameOf(path));
115
+ const words = row.protection === 'na' ? 'mp' : 'pr';
116
+ return confirmDialog({
117
+ id: 'protect-' + at,
118
+ title: inLanguages((t) => t(words + '.title')),
119
+ subject: '<span class="tc-chip" title="' + e(path) + '">' + e(names(path)) + '</span>',
120
+ sentence: inLanguages((t) => t(words + '.sentence', { path: '<code>' + e(path) + '</code>' })),
121
+ option: '<label class="pr-option"><input type="checkbox" data-protect-every> ' + inLanguages((t) => t(words + '.option', { name: '<code>' + name + '</code>' })) + '</label>',
122
+ cancel: inLanguages((t) => t('app.cancel')),
123
+ confirm: inLanguages((t) => t(words + '.confirm')),
124
+ confirmAttributes: ' data-protect="' + at + '" data-pattern="' + e(patterns.exact) + '" data-pattern-every="' + e(patterns.every) + '"',
125
+ note: '<div class="cf-note" data-protect-note>' +
126
+ '<p class="wz-reason" data-note-reason role="alert" hidden></p>' +
127
+ '<div class="wz-handover" data-note-command hidden><p class="wz-handover-text">' + inLanguages((t) => t(words + '.cmd')) + '</p>' + commandRow() + '</div></div>',
128
+ });
129
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The report page's views (the report page spec P2, P45): one section per sidebar item. With a script the one the
3
+ * address names is shown - the first where it names none - and its sidebar item is the active one; with none, every
4
+ * view is on the page in sidebar order, and the sidebar's links go down to them.
5
+ *
6
+ * Only the report page has views today; it goes into the kit when a second page does (the plan's rule 2).
7
+ */
8
+ export const REPORT_VIEWS_SCRIPT = String.raw `
9
+ (() => {
10
+ const views = [...document.querySelectorAll('[data-view]')];
11
+ if (views.length === 0) return;
12
+ const links = [...document.querySelectorAll('.sb-nav a[href^="#"]')];
13
+ const pick = () => {
14
+ const wanted = views.find((view) => '#' + view.id === location.hash);
15
+ if (!wanted && views.some((view) => view.classList.contains('rv-on'))) return;
16
+ const view = wanted || views[0];
17
+ views.forEach((each) => each.classList.toggle('rv-on', each === view));
18
+ links.forEach((link) => {
19
+ const on = link.getAttribute('href') === '#' + view.id;
20
+ link.classList.toggle('sb-active', on);
21
+ if (on) link.setAttribute('aria-current', 'page'); else link.removeAttribute('aria-current');
22
+ });
23
+ };
24
+ pick();
25
+ window.addEventListener('hashchange', () => { pick(); window.scrollTo(0, 0); });
26
+ })();
27
+ `;
28
+ export const REPORT_VIEWS_STYLE = String.raw `
29
+ .js [data-view]:not(.rv-on){display:none}
30
+ html:not(.js) [data-view]+[data-view]{margin-top:72px;padding-top:40px;border-top:1px solid var(--white-07)}
31
+ `;
@@ -0,0 +1,356 @@
1
+ import { escapeHtml as e } from '../html-report-components.js';
2
+ import { inLanguages, labelAttributes } from '../report-copy.js';
3
+ import { avatar } from '../ui/avatar.js';
4
+ import { closeButton, pill } from '../ui/button.js';
5
+ import { pillTabs } from '../ui/pill-tabs.js';
6
+ import { CLOSES, opener, popup, popupFoot } from '../ui/popup.js';
7
+ import { stats } from '../ui/stats.js';
8
+ import { tag } from '../ui/tag.js';
9
+ import { fileStory } from './file-story.js';
10
+ import { nameOf, ruleKey, titleOf } from './item-names.js';
11
+ import { fixId, storyId } from './to-do-view.js';
12
+ /**
13
+ * "What happened to this file" (the report page spec P12-P17; design file *agentwhy App*): the story in sentences, the
14
+ * same facts as a diagram, and the full record for a developer. Every sentence is chosen from `fileStory`'s kinds; a
15
+ * helper's job is quoted as what it was asked, and nothing is said about what the file holds (F51).
16
+ *
17
+ * The record has no time column yet: times are M4, their own slice. Order is the record's order, as it always is.
18
+ */
19
+ export function storyWindow(item, at, report, done, clock, names) {
20
+ return storyWindowOf(fileStory(report, item.path), item, at, report.scope.sessionId, done, clock, { names });
21
+ }
22
+ /** The same window from a story already told: a page that holds no session's model (To fix) is handed its story. */
23
+ export function storyWindowOf(story, item, at, sessionId, done, clock, extras = {}) {
24
+ const label = (key) => inLanguages((t) => t(key));
25
+ return storyPopup(story, {
26
+ path: item.path,
27
+ keys: item.kind === 'keys',
28
+ title: inLanguages((t, lang) => titleOf(item, t, lang)),
29
+ ...(item.pattern === undefined ? {} : { pattern: item.pattern }),
30
+ exposed: true,
31
+ }, storyId(at), sessionId, clock, extras,
32
+ // Wrapped, so `hidden` is not beaten by a pill's own `display`; the wizard's script swaps the two once the file is done.
33
+ '<span data-story-fix="' + at + '"' + (done ? ' hidden' : '') + '>' + pill({ label: label('rp.fix'), tone: 'primary', size: 'md', href: '#' + fixId(at), attributes: opener(fixId(at)) }) + '</span>' +
34
+ '<span data-story-fixed="' + at + '"' + (done ? '' : ' hidden') + '>' + tag(label('rp.fixed'), 'mint', 'md') + '</span>');
35
+ }
36
+ /** The window, whoever it is for: the head, the three tabs and the foot, with what the page puts beside Close. */
37
+ export function storyPopup(story, subject, id, sessionId, clock, extras, action) {
38
+ const label = (key, vars = {}) => inLanguages((t) => t(key, vars));
39
+ const names = extras.names ?? nameOf;
40
+ const head = '<div class="sw-head">' +
41
+ '<div class="sw-top"><span class="sw-id"><span class="sw-chip" title="' + e(subject.path) + '">' + e(names(subject.path)) + '</span>' +
42
+ '<span class="sw-kind">' + subject.title + '</span></span>' +
43
+ closeButton(labelAttributes((t) => t('app.close')) + CLOSES) + '</div>' +
44
+ '<h2 class="sw-h2" id="' + id + '-title">' + label('st.heading') + '</h2>' +
45
+ '<p class="sw-summary">' + (subject.summary ?? summaryOf(story, subject.keys)) + '</p>' +
46
+ (extras.context === undefined ? '' : '<p class="sw-context">' + extras.context + '</p>') + '</div>';
47
+ const body = '<div class="sw-body">' + pillTabs([
48
+ { label: label('st.tab.story'), panel: storyPanel(story, subject.keys, clock, subject.exposed, names) },
49
+ { label: label('st.tab.diagram'), panel: diagramPanel(story, subject, names) },
50
+ { label: label('st.tab.record'), panel: recordPanel(story, subject, sessionId, clock, names) },
51
+ ...(extras.tabs ?? []),
52
+ ], 'inset') + '</div>';
53
+ const foot = popupFoot(label('st.foot'), pill({ label: label('app.close'), tone: 'outline', size: 'md', button: true, attributes: CLOSES }) + action);
54
+ return popup({ id, size: 'wide', labelledBy: id + '-title', body: head + body + foot });
55
+ }
56
+ /** P12: who read it, and that a copy went on to the company - one sentence, from the readers the story counted. */
57
+ function summaryOf(story, keys) {
58
+ const only = story.holders.filter((holder) => holder.read);
59
+ if (only.length === 0)
60
+ return inLanguages((t) => t('st.summary.reached'));
61
+ if (only.length === 1 && only[0]?.agent.ordinal !== undefined)
62
+ return inLanguages((t) => t(keys ? 'st.summary.keysHelper' : 'st.summary.dataHelper'));
63
+ return inLanguages((t) => t(keys ? 'st.summary.keys' : 'st.summary.data', { n: only.length }));
64
+ }
65
+ /** Your AI, or "Helper 6". */
66
+ function whoOf(agent, t) {
67
+ return agent.ordinal === undefined ? t('st.main') : t('st.helper', { ordinal: agent.ordinal });
68
+ }
69
+ function initialsOf(agent) {
70
+ return agent.ordinal === undefined ? 'AI' : 'H' + agent.ordinal;
71
+ }
72
+ /** P14: an entry's line and the line under it, from its kind; the sentence under a helper's first entry is its job. */
73
+ function sentences(entries, keys, names) {
74
+ const readers = new Set();
75
+ const seen = new Set();
76
+ return entries.map((entry) => {
77
+ const first = !seen.has(entry.agent.index);
78
+ seen.add(entry.agent.index);
79
+ const did = (t) => entry.did === undefined ? '' : t('st.sub.didTimes', { n: entry.count, did: '<code>' + e(entry.did) + '</code>' });
80
+ const job = (t) => entry.agent.askedTo === undefined ? t('st.sub.notAsked') : t('st.sub.asked', { task: e(entry.agent.askedTo) });
81
+ const helperFirst = first && entry.agent.ordinal !== undefined;
82
+ switch (entry.kind) {
83
+ case 'read': {
84
+ const again = readers.has(entry.agent.index);
85
+ const earlier = readers.size > 0;
86
+ readers.add(entry.agent.index);
87
+ const kind = keys ? 'keys' : 'data';
88
+ // X10: text its own code handed back is read, but no file was opened by it, so it is never said so.
89
+ const title = entry.inResult === true ? 'st.e.inResult.' + kind
90
+ : again ? 'st.e.again' : entry.agent.ordinal !== undefined ? (earlier ? 'st.e.helperReadToo.' : 'st.e.helperRead.') + kind
91
+ : entry.received === true ? 'st.e.received.' + kind : 'st.e.read.' + kind;
92
+ if (entry.received === true)
93
+ return { title: (t) => t(title), sub: helperFirst ? job : (t) => t('st.sub.received') };
94
+ const inResult = (t) => t('st.sub.inResult', { did: entry.did === undefined ? '' : '<code>' + e(entry.did) + '</code>' });
95
+ // search-hits-are-reads H8: how it was read, where a search printed its lines - and still that nothing asked for it.
96
+ const lines = (t) => t(entry.inResult === true ? 'st.sub.inResultLines' : 'st.sub.lines', { n: entry.lines ?? 0, did: entry.did === undefined ? '' : '<code>' + e(entry.did) + '</code>' });
97
+ return { title: (t) => t(title), sub: helperFirst ? job : entry.lines !== undefined ? lines : entry.inResult === true ? inResult : did };
98
+ }
99
+ case 'named': return { title: (t) => t('st.e.named'), sub: helperFirst ? job : did };
100
+ case 'unknown': return { title: (t) => t('st.e.unknown'), sub: helperFirst ? job : (t) => t('st.sub.unknown') };
101
+ case 'stopped': return { title: (t) => t('st.e.stopped'), sub: helperFirst ? job : did };
102
+ case 'passed': return {
103
+ title: (t) => t('st.e.passed', { to: entry.to === undefined || entry.to.ordinal === undefined ? t('st.mainLower') : t('st.helper', { ordinal: entry.to.ordinal }) }),
104
+ sub: (t) => t('st.sub.passed'),
105
+ };
106
+ case 'saved': return {
107
+ title: (t) => t('st.e.saved'),
108
+ sub: (t) => entry.into === undefined ? t('st.sub.savedAny') : t('st.sub.saved', { files: entry.into.map((file) => '<code>' + e(names(file)) + '</code>').join(', ') }),
109
+ };
110
+ case 'handed': return { title: (t) => t('st.e.handed'), sub: (t) => t('st.sub.handed') };
111
+ case 'repeated': return { title: (t) => t('st.e.repeated'), sub: (t) => t('st.sub.repeated') };
112
+ case 'used': return {
113
+ title: (t) => t('st.e.used'),
114
+ sub: (t) => entry.into === undefined ? t('st.sub.usedAny') : t('st.sub.used', { programs: entry.into.map((program) => '<code>' + e(program) + '</code>').join(', ') }),
115
+ };
116
+ }
117
+ });
118
+ }
119
+ /**
120
+ * P13: one entry per record that named the file, then the AI company - whose line never says what it keeps (F24) - where
121
+ * its contents reached an AI at all.
122
+ */
123
+ function storyPanel(story, keys, clock, exposed, names) {
124
+ const lines = sentences(story.entries, keys, names);
125
+ // P13, M4: each entry's time beside it where the record has one; the entries stay in the record's order either way.
126
+ const timed = story.entries.some((each) => each.at !== undefined);
127
+ const entry = (avatarHtml, who, title, sub, last, alert, at) => '<li class="sw-ev' + (alert ? ' sw-ev-alert' : '') + (timed ? ' sw-timed' : '') + '">' +
128
+ (timed ? '<span class="sw-time">' + (at === undefined ? '' : e(clock.time(at))) + '</span>' : '') +
129
+ '<div class="sw-rail">' + avatarHtml + (last ? '' : '<span class="sw-line"></span>') + '</div>' +
130
+ '<div class="sw-ev-body"><div class="sw-who">' + who + '</div><div class="sw-ev-title">' + title + '</div>' +
131
+ (sub === '' ? '' : '<div class="sw-ev-sub">' + sub + '</div>') + '</div></li>';
132
+ return '<ol class="sw-story">' +
133
+ story.entries.map((each, at) => entry(avatar(initialsOf(each.agent), each.agent.ordinal === undefined ? 'coral' : 'grey', 40), inLanguages((t) => whoOf(each.agent, t)), inLanguages((t) => lines[at]?.title(t) ?? ''), inLanguages((t) => lines[at]?.sub(t) ?? ''), !exposed && at === story.entries.length - 1, false, each.at)).join('') +
134
+ (exposed ? entry(avatar('↗', 'alert', 40), inLanguages((t) => t('st.company')), inLanguages((t) => t('st.e.company')), inLanguages((t) => t('st.sub.company')), true, true) : '') +
135
+ '</ol>';
136
+ }
137
+ /** What a node of the diagram says it did: "read the keys · 2×", "passed it back". */
138
+ function didOf(holder, story, keys) {
139
+ const reads = story.entries.filter((entry) => entry.agent.index === holder.agent.index && entry.kind === 'read').reduce((sum, entry) => sum + entry.count, 0);
140
+ const named = story.entries.some((entry) => entry.agent.index === holder.agent.index && entry.kind === 'named');
141
+ return inLanguages((t) => [
142
+ ...(holder.read ? [t(keys ? 'st.d.readKeys' : 'st.d.readIt') + (reads > 1 ? ' · ' + t('st.d.times', { n: reads }) : '')] : []),
143
+ ...(!holder.read && named ? [t('st.d.named')] : []),
144
+ ...(holder.passed ? [t('st.d.passed')] : []),
145
+ ...(holder.saved ? [t('st.d.saved')] : []),
146
+ ...(holder.stopped ? [t('st.d.stopped')] : []),
147
+ ].join(' · '));
148
+ }
149
+ /** How an AI's line reaches the file: read beats stopped beats only its name; none where it only passed something on. */
150
+ function reachOf(holder, story) {
151
+ if (holder.read)
152
+ return 'read';
153
+ if (holder.stopped)
154
+ return 'stopped';
155
+ return story.entries.some((entry) => entry.agent.index === holder.agent.index && entry.kind === 'named') ? 'named' : undefined;
156
+ }
157
+ const NODE_HEIGHT = 64;
158
+ const ROW = 84;
159
+ const TOP = 64;
160
+ const GAP = 60;
161
+ /**
162
+ * P15: You → your AI → the helpers in the story → the file → the company, in the Helpers diagram's look (P29): boxes
163
+ * with an icon and connector dots on a dotted board, curves between them, one colour per kind of line. What each one
164
+ * did is its box's second line, so no label sits on a line or over a box. The Helpers script dims what a hovered box is
165
+ * not joined to.
166
+ */
167
+ function diagramPanel(story, subject, names) {
168
+ const { keys, exposed } = subject;
169
+ const main = story.holders.find((holder) => holder.agent.ordinal === undefined);
170
+ const helpers = story.holders.filter((holder) => holder.agent.ordinal !== undefined);
171
+ // Where nothing was read, the file is the last box: nothing went on to the company.
172
+ const widths = (helpers.length === 0 ? [190, 240, 240, 240] : [170, 200, 210, 250, 220]).slice(0, exposed ? undefined : -1);
173
+ const xs = widths.reduce((all, width, at) => [...all, at === 0 ? 24 : all[at - 1] + widths[at - 1] + GAP], []);
174
+ const column = (at) => ({ x: xs[at], w: widths[at] });
175
+ const [you, ai] = [column(0), column(1)];
176
+ const help = helpers.length === 0 ? undefined : column(2);
177
+ const file = column(help === undefined ? 2 : 3);
178
+ const company = exposed ? column(help === undefined ? 3 : 4) : undefined;
179
+ const width = (company ?? file).x + (company ?? file).w + 24;
180
+ // The file's row runs straight through. Where your AI has a line of its own to the file, the helpers hang below that
181
+ // row, so no box stands on it; where it has none, the first helper stands on the row, and the chain from you to the
182
+ // company is one straight line rather than a dip down to a helper and back up to the file.
183
+ const mainReach = main === undefined ? undefined : reachOf(main, story);
184
+ const below = mainReach === undefined ? 0 : 1;
185
+ const height = TOP + Math.max(1, below + helpers.length) * ROW + 8;
186
+ const middle = TOP;
187
+ const across = (units) => Number((units / width * 100).toFixed(3)) + '%';
188
+ const box = (node, icon, tone, label, sub, extra = '') => '<span class="hd-node sd-node' + extra + '" tabindex="0" data-node="' + node.id + '" style="left:' + across(node.x) + ';top:' + node.y + 'px;width:' + across(node.w) + '">' +
189
+ (node.first === true ? '' : '<span class="hd-port hd-in"></span>') + (node.last === true ? '' : '<span class="hd-port hd-out"></span>') +
190
+ '<span class="hd-icon hd-icon-' + tone + '">' + icon + '</span>' +
191
+ '<span class="hd-text"><span class="hd-label">' + label + '</span>' + (sub === '' ? '' : '<span class="hd-sub">' + sub + '</span>') + '</span></span>';
192
+ const toneOf = (reach) => reach === 'read' ? 'coral' : reach === 'stopped' ? 'mint' : 'grey';
193
+ const nodes = [
194
+ { id: 'you', ...you, y: middle, first: true },
195
+ { id: 'a0', ...ai, y: middle },
196
+ ...helpers.map((holder, row) => ({ id: 'h' + holder.agent.index, x: help.x, w: help.w, y: TOP + (row + below) * ROW })),
197
+ { id: 'file', ...file, y: middle, ...(company === undefined ? { last: true } : {}) },
198
+ ...(company === undefined ? [] : [{ id: 'company', ...company, y: middle, last: true }]),
199
+ ];
200
+ const byId = new Map(nodes.map((node) => [node.id, node]));
201
+ const idOf = (holder) => holder.agent.ordinal === undefined ? 'a0' : 'h' + holder.agent.index;
202
+ const parentOf = (holder) => {
203
+ const by = holder.agent.broughtBy;
204
+ const parent = by === undefined || by === 'main' ? undefined : helpers.find((each) => each.agent.ordinal === by);
205
+ return parent === undefined ? 'a0' : idOf(parent);
206
+ };
207
+ const edges = [
208
+ { from: 'you', to: 'a0', kind: 'work' },
209
+ ...helpers.map((holder) => ({ from: parentOf(holder), to: idOf(holder), kind: 'work' })),
210
+ ...[...(main === undefined ? [] : [main]), ...helpers].flatMap((holder) => {
211
+ const reach = reachOf(holder, story);
212
+ return reach === undefined ? [] : [{ from: idOf(holder), to: 'file', kind: reach }];
213
+ }),
214
+ ...(exposed ? [{ from: 'file', to: 'company', kind: 'read' }] : []),
215
+ ];
216
+ const centre = (node) => node.y + NODE_HEIGHT / 2;
217
+ const path = (from, to) => {
218
+ // A helper brought in by another helper stands in the same column: its line bows out to the left, clear of both boxes.
219
+ if (from.x === to.x)
220
+ return 'M' + from.x + ',' + centre(from) + ' C' + (from.x - 40) + ',' + centre(from) + ' ' + (to.x - 40) + ',' + centre(to) + ' ' + to.x + ',' + centre(to);
221
+ const [x1, y1, x2, y2] = [from.x + from.w, centre(from), to.x, centre(to)];
222
+ const d = (x2 - x1) / 2;
223
+ return 'M' + x1 + ',' + y1 + ' C' + (x1 + d) + ',' + y1 + ' ' + (x2 - d) + ',' + y2 + ' ' + x2 + ',' + y2;
224
+ };
225
+ const lines = edges.flatMap((edge) => {
226
+ const from = byId.get(edge.from);
227
+ const to = byId.get(edge.to);
228
+ return from === undefined || to === undefined ? [] : ['<path class="hd-edge hd-' + edge.kind + '" data-from="' + edge.from + '" data-to="' + edge.to + '" d="' + path(from, to) + '"/>'];
229
+ });
230
+ const kinds = new Set(edges.map((edge) => edge.kind));
231
+ const key = (kind, words) => kinds.has(kind) ? '<span><span class="hd-key hd-key-' + kind + '"></span>' + inLanguages((t) => t(words)) + '</span>' : '';
232
+ const legend = '<div class="hd-legend">' + key('read', 'st.d.legendRead') + key('named', 'hp.key.named') + key('stopped', 'hp.key.stopped') + key('work', 'st.d.legendWork') + '</div>';
233
+ const at = (id) => byId.get(id);
234
+ const boxes = box(at('you'), 'You', 'you', inLanguages((t) => t('st.you')), inLanguages((t) => t('st.d.asked'))) +
235
+ box(at('a0'), 'AI', toneOf(mainReach), inLanguages((t) => t('st.main')), main === undefined ? '' : didOf(main, story, keys), mainReach === 'read' ? ' hd-risk' : '') +
236
+ helpers.map((holder) => {
237
+ const reach = reachOf(holder, story);
238
+ return box(at(idOf(holder)), initialsOf(holder.agent), toneOf(reach), inLanguages((t) => whoOf(holder.agent, t)), didOf(holder, story, keys), reach === 'read' ? ' hd-risk' : '');
239
+ }).join('') +
240
+ (exposed || subject.look === undefined
241
+ ? box(at('file'), '!', 'coral', '<span class="hd-mono">' + e(names(subject.path)) + '</span>', inLanguages((t) => t('st.d.file')), ' hd-risk')
242
+ : box(at('file'), subject.look.glyph, subject.look.tone, '<span class="hd-mono">' + e(names(subject.path)) + '</span>', inLanguages((t) => t('st.d.file')))) +
243
+ (company === undefined ? '' : box(at('company'), '↗', 'company', inLanguages((t) => t('st.company')), inLanguages((t) => t('st.d.company')), ' sd-company'));
244
+ return '<div class="hd-scroll sd-diagram"><div class="hd-board" data-diagram style="min-width:' + Math.round(width * 0.8) + 'px;height:' + height + 'px">' +
245
+ '<svg class="hd-lines" viewBox="0 0 ' + width + ' ' + height + '" preserveAspectRatio="none" aria-hidden="true">' + lines.join('') + '</svg>' +
246
+ legend + boxes + '</div></div>' +
247
+ '<p class="hd-hint js-only">' + inLanguages((t) => t('st.d.hint')) + '</p>';
248
+ }
249
+ /** P16: the numbers, every record in order, what each AI did, and the file's details - for a developer. */
250
+ function recordPanel(story, subject, sessionId, clock, names) {
251
+ const label = (key, vars = {}) => inLanguages((t) => t(key, vars));
252
+ const lines = sentences(story.entries, subject.keys, names);
253
+ const numbers = stats([
254
+ { label: label('st.stat.opened'), value: String(story.opened) },
255
+ { label: label('st.stat.readers'), value: String(story.readers), tone: 'coral' },
256
+ { label: label('st.stat.stopped'), value: String(story.stopped) },
257
+ { label: label('st.stat.record'), value: label(story.complete ? 'st.complete' : 'st.gaps'), ...(story.complete ? { tone: 'mint' } : {}) },
258
+ ], 'record');
259
+ const heading = (title, note) => '<div class="sw-rec-head"><span class="sw-rec-title">' + title + '</span><span class="sw-rec-note">' + note + '</span></div>';
260
+ const cells = (values) => values.map((value) => '<span>' + value + '</span>').join('');
261
+ // P16, M4: a Time column where the record has times, and the note that says what they are.
262
+ const timed = story.entries.some((entry) => entry.at !== undefined);
263
+ const every = heading(label('st.rec.every'), label('st.rec.count', { n: story.entries.length })) +
264
+ (timed ? '<p class="sw-times-note">' + label('st.rec.timesNote') + '</p>' : '') +
265
+ '<div class="sw-table"><div class="sw-grid sw-grid-every' + (timed ? ' sw-grid-timed' : '') + ' sw-grid-head">' +
266
+ cells(['st.col.n', ...(timed ? ['st.col.time'] : []), 'st.col.who', 'st.col.what', 'st.col.tool', 'st.col.result', 'st.col.evidence'].map((key) => label(key))) + '</div>' +
267
+ story.entries.map((entry, at) => '<div class="sw-grid sw-grid-every' + (timed ? ' sw-grid-timed' : '') + '">' +
268
+ '<span class="sw-mono sw-dim">' + (at + 1) + '</span>' +
269
+ (timed ? '<span class="sw-mono">' + (entry.at === undefined ? '<span class="sw-dim">—</span>' : e(clock.time(entry.at))) + '</span>' : '') +
270
+ '<span class="sw-who-cell"><span class="sw-dot' + (entry.agent.ordinal === undefined ? '' : ' sw-dot-grey') + '"></span>' + inLanguages((t) => whoOf(entry.agent, t)) + '</span>' +
271
+ '<span>' + inLanguages((t) => lines[at]?.title(t) ?? '') + '</span>' +
272
+ '<span>' + (entry.did === undefined ? '<span class="sw-dim">—</span>' : '<span class="sw-tool">' + e(entry.did) + '</span>') + '</span>' +
273
+ '<span>' + tag(label('st.res.' + entry.outcome), entry.outcome === 'succeeded' ? 'mint' : entry.outcome === 'blocked' ? 'grey' : 'coral', 'sm') + '</span>' +
274
+ '<span class="sw-mono sw-dim">' + entry.evidence.map((one) => e(one)).join(' – ') + '</span></div>').join('') +
275
+ '</div>';
276
+ const yes = (on) => '<span class="sw-yn' + (on ? ' sw-yes' : '') + '">' + label(on ? 'st.yes' : 'st.no') + '</span>';
277
+ const roleOf = (agent, t) => agent.ordinal === undefined ? t('st.role.main')
278
+ : agent.broughtBy === undefined ? t('st.role.helperAny')
279
+ : t('st.role.helper', { who: agent.broughtBy === 'main' ? t('st.mainLower') : t('st.helper', { ordinal: agent.broughtBy }) });
280
+ const each = heading(label('st.rec.each'), label('st.rec.yes')) +
281
+ '<div class="sw-table"><div class="sw-grid sw-grid-each sw-grid-head">' +
282
+ cells(['st.col.who', 'st.col.role', 'st.col.read', 'st.col.passed', 'st.col.saved', 'st.col.repeated', 'st.col.used', 'st.col.actions'].map((key) => label(key))) + '</div>' +
283
+ story.holders.map((holder) => '<div class="sw-grid sw-grid-each">' +
284
+ '<span class="sw-strong">' + inLanguages((t) => whoOf(holder.agent, t)) + '</span>' +
285
+ '<span class="sw-dim">' + inLanguages((t) => roleOf(holder.agent, t)) + '</span>' +
286
+ [holder.read, holder.passed, holder.saved, holder.repeated, holder.used].map((on) => '<span>' + yes(on) + '</span>').join('') +
287
+ '<span class="sw-mono">' + holder.agent.actions + '</span></div>').join('') +
288
+ '</div>';
289
+ const rule = ruleKey(subject.pattern);
290
+ const fact = (key, value, mono) => '<div class="sw-fact"><span class="sw-fact-key">' + label(key) + '</span><span class="sw-fact-value' + (mono ? ' sw-mono' : '') + '">' + value + '</span></div>';
291
+ const details = '<div class="sw-rec-title sw-rec-alone">' + label('st.rec.details') + '</div><div class="sw-facts">' +
292
+ fact('st.fact.path', e(subject.path), true) +
293
+ fact('st.fact.rule', subject.pattern === undefined ? '—' : e(subject.pattern), true) +
294
+ fact('st.fact.why', label(rule === undefined ? 'st.why.other' : rule.replace('rule.', 'st.why.')), false) +
295
+ fact('st.fact.session', e(sessionId), true) +
296
+ fact('st.fact.complete', label(story.complete ? 'st.complete.yes' : 'st.complete.no'), false) +
297
+ '</div>';
298
+ return numbers + every + each + details;
299
+ }
300
+ export const STORY_WINDOW_STYLE = String.raw `
301
+ .sw-head{padding:26px 32px 0}
302
+ .sw-top{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:20px}
303
+ .sw-id{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
304
+ .sw-chip{font-family:var(--mono);font-size:14px;font-weight:500;color:var(--text);background:var(--white-07);border:1px solid var(--white-10);border-radius:6px;padding:3px 8px}
305
+ .sw-kind{font-size:14px;color:var(--text-2)}
306
+ .sw-h2{margin:0 0 6px;font-size:32px;line-height:1.15;letter-spacing:-0.02em;font-weight:650;text-wrap:balance}
307
+ .sw-summary{margin:0 0 22px;font-size:16px;line-height:1.5;color:var(--text-2)}
308
+ .sw-context{margin:-12px 0 22px;font-size:14px;line-height:1.5;color:var(--text-3)}
309
+ .sw-body{padding:0 32px 30px}
310
+ .sw-body>.tabs>.tabs-bar{margin-left:auto;margin-right:auto}
311
+ .sw-story{list-style:none;margin:0 auto;padding:0;display:flex;flex-direction:column;max-width:720px}
312
+ .sw-ev{display:grid;grid-template-columns:40px minmax(0,1fr);gap:14px}
313
+ .sw-ev.sw-timed{grid-template-columns:64px 40px minmax(0,1fr)}
314
+ .sw-time{font-family:var(--mono);font-size:12.5px;color:var(--text-3);padding-top:11px;text-align:right}
315
+ .sw-times-note{margin:-4px 0 12px;font-size:13px;color:var(--text-3)}
316
+ .sw-grid-every.sw-grid-timed{grid-template-columns:44px 84px 130px minmax(0,1.5fr) minmax(0,1.2fr) 120px 180px;min-width:980px}
317
+ @media (max-width:640px){.sw-ev.sw-timed{grid-template-columns:52px 40px minmax(0,1fr);gap:10px}}
318
+ .sw-rail{display:flex;flex-direction:column;align-items:center}
319
+ .sw-line{flex:1;width:1.5px;background:var(--coral-30);margin:4px 0}
320
+ .sw-ev-body{padding:2px 0 22px}
321
+ .sw-who{font-size:13px;font-weight:600;color:var(--text-3);margin-bottom:3px}.sw-ev-alert .sw-who{color:var(--coral-text)}
322
+ .sw-ev-title{font-size:16px;font-weight:600;line-height:1.4}
323
+ .sw-ev-sub{font-size:14.5px;line-height:1.5;color:var(--text-2);margin-top:3px;text-wrap:pretty}
324
+ .sw-ev-sub code{font-family:var(--mono);font-size:13.5px;color:var(--text)}
325
+ .sd-diagram .hd-node{height:64px;cursor:default;transition:opacity .15s,border-color .15s,transform .15s,box-shadow .15s}
326
+ .sd-diagram .hd-node:hover,.sd-diagram .hd-node:focus-visible{border-color:var(--white-40);transform:translateY(-1px);box-shadow:0 10px 26px var(--node-shadow);outline:none}
327
+ .sd-diagram .hd-risk:hover,.sd-diagram .hd-risk:focus-visible{border-color:var(--coral)}
328
+ .sd-diagram .hd-sub{white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-height:1.3}
329
+ .sd-company{background:var(--coral-12);border-color:var(--coral)}
330
+ .sd-diagram .hd-icon-amber{background:var(--amber-16);color:var(--amber)}
331
+ .sd-diagram .hd-icon-sand{background:var(--sand-16);color:var(--sand)}.sd-diagram .hd-icon-blue{background:var(--blue-16);color:var(--blue)}
332
+ .sd-company .hd-label{color:var(--coral-text)}.sd-company .hd-sub{color:var(--text-soft)}
333
+ .hd-icon-company{background:var(--coral);color:var(--on-coral)}
334
+ .sw-rec-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:12px}
335
+ .sw-rec-title{font-size:16px;font-weight:650}.sw-rec-alone{margin-bottom:12px}
336
+ .sw-rec-note{font-size:13px;color:var(--text-3)}
337
+ .sw-table{border-radius:14px;border:1px solid var(--white-09);overflow:auto;margin-bottom:32px}
338
+ .sw-grid{display:grid;gap:16px;padding:15px 18px;border-bottom:1px solid var(--white-06);align-items:center;font-size:14.5px}
339
+ .sw-grid:last-child{border-bottom:none}
340
+ .sw-grid-head{padding:12px 18px;background:var(--panel);font-size:12.5px;font-weight:600;color:var(--text-3);border-bottom:1px solid var(--white-08)}
341
+ .sw-grid-every{grid-template-columns:44px 130px minmax(0,1.5fr) minmax(0,1.2fr) 120px 180px;min-width:900px}
342
+ .sw-grid-each{grid-template-columns:minmax(0,1.2fr) minmax(0,1.3fr) repeat(5,110px) 90px;min-width:1000px}
343
+ .sw-mono{font-family:var(--mono);font-size:13px}
344
+ .sw-dim{color:var(--text-3)}
345
+ .sw-strong{font-size:15px;font-weight:600}
346
+ .sw-who-cell{display:flex;align-items:center;gap:8px;font-weight:600}
347
+ .sw-dot{width:8px;height:8px;border-radius:50%;background:var(--coral);flex:none}.sw-dot-grey{background:var(--white-35)}
348
+ .sw-tool{font-family:var(--mono);font-size:13px;color:var(--text);background:var(--white-07);border:1px solid var(--white-10);border-radius:6px;padding:3px 8px}
349
+ .sw-yn{font-size:12px;font-weight:700;border-radius:999px;padding:4px 11px;color:var(--text-2);background:var(--white-07)}
350
+ .sw-yes{color:var(--on-coral);background:var(--coral)}
351
+ .sw-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));border-radius:14px;border:1px solid var(--white-09);overflow:hidden}
352
+ .sw-fact{display:grid;grid-template-columns:150px minmax(0,1fr);gap:14px;padding:14px 18px;border-bottom:1px solid var(--white-06);border-right:1px solid var(--white-06);align-items:baseline}
353
+ .sw-fact-key{font-size:13.5px;color:var(--text-3)}
354
+ .sw-fact-value{font-size:14px;color:var(--text);word-break:break-all}
355
+ @media (max-width:640px){.sw-head{padding:22px 20px 0}.sw-body{padding:0 20px 24px}.sw-h2{font-size:26px}}
356
+ `;
@@ -0,0 +1,25 @@
1
+ const LOCALES = { en: 'en-GB', pl: 'pl-PL', de: 'de-DE' };
2
+ export function clockIn(zone) {
3
+ const known = (candidate) => {
4
+ if (candidate === undefined)
5
+ return 'UTC';
6
+ try {
7
+ new Intl.DateTimeFormat('en-GB', { timeZone: candidate });
8
+ return candidate;
9
+ }
10
+ catch {
11
+ return 'UTC';
12
+ }
13
+ };
14
+ const timeZone = known(zone);
15
+ const time = new Intl.DateTimeFormat('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h23', timeZone });
16
+ const days = new Map();
17
+ return {
18
+ time: (epoch) => time.format(new Date(epoch)),
19
+ day: (epoch, lang) => {
20
+ const format = days.get(lang) ?? new Intl.DateTimeFormat(LOCALES[lang], { weekday: 'long', day: 'numeric', month: 'long', timeZone });
21
+ days.set(lang, format);
22
+ return format.format(new Date(epoch));
23
+ },
24
+ };
25
+ }