@design-ai/cli 4.55.0 → 4.57.0

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 (301) hide show
  1. package/.claude-plugin/plugin.json +109 -25
  2. package/CHANGELOG.md +75 -0
  3. package/README.ko.md +15 -32
  4. package/README.md +18 -31
  5. package/cli/bin/design-ai.mjs +1 -0
  6. package/cli/commands/help.mjs +7 -4
  7. package/cli/commands/index.mjs +292 -0
  8. package/cli/commands/learn-help.mjs +149 -0
  9. package/cli/commands/learn-print-profile.mjs +373 -0
  10. package/cli/commands/learn-print-restore.mjs +349 -0
  11. package/cli/commands/learn-print-signals.mjs +453 -0
  12. package/cli/commands/learn.mjs +60 -1281
  13. package/cli/commands/pack.mjs +7 -3
  14. package/cli/commands/prompt.mjs +7 -3
  15. package/cli/commands/search.mjs +94 -1
  16. package/cli/lib/dispatch.mjs +3 -0
  17. package/cli/lib/embedding-index.mjs +199 -0
  18. package/cli/lib/embedding-provider.mjs +121 -0
  19. package/cli/lib/embedding-rerank.mjs +52 -0
  20. package/cli/lib/learn-args.mjs +490 -0
  21. package/cli/lib/learn-backup.mjs +748 -0
  22. package/cli/lib/learn-curation.mjs +612 -0
  23. package/cli/lib/learn-eval.mjs +459 -0
  24. package/cli/lib/learn-profile.mjs +763 -0
  25. package/cli/lib/learn-select.mjs +223 -0
  26. package/cli/lib/learn-shared.mjs +158 -0
  27. package/cli/lib/learn-test-support.mjs +218 -0
  28. package/cli/lib/learn-usage.mjs +360 -0
  29. package/cli/lib/learn.mjs +83 -3694
  30. package/cli/lib/lexical.mjs +137 -0
  31. package/cli/lib/local-config.mjs +110 -0
  32. package/cli/lib/mcp-server.mjs +221 -13
  33. package/cli/lib/pack.mjs +31 -4
  34. package/cli/lib/prompt.mjs +42 -4
  35. package/cli/lib/recall.mjs +193 -0
  36. package/cli/lib/retrieval-index.mjs +0 -0
  37. package/cli/lib/search-ranked.mjs +170 -0
  38. package/cli/lib/search.mjs +11 -1
  39. package/cli/lib/signals-backlog-commands.mjs +673 -0
  40. package/cli/lib/signals-backlog.mjs +361 -0
  41. package/cli/lib/signals-eval.mjs +176 -0
  42. package/cli/lib/signals-readiness.mjs +247 -0
  43. package/cli/lib/signals-registry.mjs +377 -0
  44. package/cli/lib/signals-render.mjs +478 -0
  45. package/cli/lib/signals-shared.mjs +75 -0
  46. package/cli/lib/signals.mjs +16 -2337
  47. package/cli/lib/site-analysis.mjs +297 -0
  48. package/cli/lib/site-args.mjs +433 -0
  49. package/cli/lib/site-bundle-build.mjs +127 -0
  50. package/cli/lib/site-bundle-check.mjs +454 -0
  51. package/cli/lib/site-bundle-commands.mjs +95 -0
  52. package/cli/lib/site-bundle-compare.mjs +157 -0
  53. package/cli/lib/site-bundle-contract.mjs +79 -0
  54. package/cli/lib/site-bundle-files.mjs +87 -0
  55. package/cli/lib/site-bundle-handoff-expected.mjs +173 -0
  56. package/cli/lib/site-bundle-handoff-runbook-action-summary.mjs +332 -0
  57. package/cli/lib/site-bundle-handoff-runbook-actions.mjs +113 -0
  58. package/cli/lib/site-bundle-handoff-runbook-evidence-fields.mjs +164 -0
  59. package/cli/lib/site-bundle-handoff-runbook-evidence.mjs +334 -0
  60. package/cli/lib/site-bundle-handoff-runbook-format.mjs +31 -0
  61. package/cli/lib/site-bundle-handoff-runbook-human-lines.mjs +167 -0
  62. package/cli/lib/site-bundle-handoff-runbook-maps.mjs +238 -0
  63. package/cli/lib/site-bundle-handoff-runbook-next-step.mjs +278 -0
  64. package/cli/lib/site-bundle-handoff-runbook-stage-metadata.mjs +84 -0
  65. package/cli/lib/site-bundle-handoff-runbook.mjs +444 -0
  66. package/cli/lib/site-bundle-handoff-summary.mjs +183 -0
  67. package/cli/lib/site-bundle-handoff.mjs +271 -0
  68. package/cli/lib/site-bundle-readme.mjs +98 -0
  69. package/cli/lib/site-bundle-repair-report.mjs +143 -0
  70. package/cli/lib/site-bundle-repair.mjs +68 -0
  71. package/cli/lib/site-content.mjs +399 -0
  72. package/cli/lib/site-evidence.mjs +35 -0
  73. package/cli/lib/site-mcp-commands.mjs +28 -0
  74. package/cli/lib/site-mcp-probes.mjs +159 -0
  75. package/cli/lib/site-mcp-readiness.mjs +157 -0
  76. package/cli/lib/site-mcp-report.mjs +324 -0
  77. package/cli/lib/site-next-actions.mjs +333 -0
  78. package/cli/lib/site-options.mjs +104 -0
  79. package/cli/lib/site-prompts.mjs +332 -0
  80. package/cli/lib/site-starter.mjs +153 -0
  81. package/cli/lib/site-strings.mjs +23 -0
  82. package/cli/lib/site-tasks.mjs +93 -0
  83. package/cli/lib/site-test-support.mjs +68 -0
  84. package/cli/lib/site-workflow-graph.mjs +309 -0
  85. package/cli/lib/site-workspace.mjs +492 -0
  86. package/cli/lib/site.mjs +108 -6617
  87. package/cli/lib/skill-proposals-apply-commands.mjs +135 -0
  88. package/cli/lib/skill-proposals-apply-contract.mjs +750 -0
  89. package/cli/lib/skill-proposals-apply-plan.mjs +118 -0
  90. package/cli/lib/skill-proposals-generate.mjs +298 -0
  91. package/cli/lib/skill-proposals-render.mjs +532 -0
  92. package/cli/lib/skill-proposals-review.mjs +262 -0
  93. package/cli/lib/skill-proposals.mjs +15 -2046
  94. package/cli/lib/workspace-args.mjs +83 -0
  95. package/cli/lib/workspace-git.mjs +169 -0
  96. package/cli/lib/workspace-learning.mjs +483 -0
  97. package/cli/lib/workspace-repo.mjs +139 -0
  98. package/cli/lib/workspace-report.mjs +283 -0
  99. package/cli/lib/workspace-test-support.mjs +99 -0
  100. package/cli/lib/workspace.mjs +30 -1056
  101. package/docs/AI-LEARNING-PHASE2.md +215 -0
  102. package/docs/DISTRIBUTION.ko.md +35 -6
  103. package/docs/DISTRIBUTION.md +35 -8
  104. package/docs/NEXT-SURFACE-DECISION.md +125 -0
  105. package/docs/PRODUCT-READINESS.md +3 -3
  106. package/docs/RELEASE-CHECKLIST.md +20 -3
  107. package/docs/RELEASE-GATES.ko.md +35 -0
  108. package/docs/RELEASE-GATES.md +234 -0
  109. package/docs/ROADMAP.md +2232 -8
  110. package/docs/external-status.md +20 -7
  111. package/docs/inspection-20260630.md +169 -0
  112. package/docs/integrations/design-ai-mcp-server.md +35 -3
  113. package/docs/integrations/vscode-walkthrough.ko.md +3 -3
  114. package/docs/integrations/vscode-walkthrough.md +3 -3
  115. package/docs/reference/ant-design.md +413 -0
  116. package/docs/reference/awesome-design-md.md +439 -0
  117. package/docs/reference/mui.md +783 -0
  118. package/docs/reference/shadcn-ui.md +298 -0
  119. package/docs/site-overrides/main.html +1 -1
  120. package/examples/component-accordion-actions.md +5 -5
  121. package/examples/component-accordion-details.md +5 -5
  122. package/examples/component-accordion-summary.md +5 -5
  123. package/examples/component-accordion.md +3 -3
  124. package/examples/component-affix.md +1 -1
  125. package/examples/component-alert-dialog.md +1 -1
  126. package/examples/component-alert-title.md +1 -1
  127. package/examples/component-alert.md +3 -3
  128. package/examples/component-anchor.md +1 -1
  129. package/examples/component-app-bar.md +1 -1
  130. package/examples/component-aspect-ratio.md +1 -1
  131. package/examples/component-auto-complete.md +2 -2
  132. package/examples/component-avatar-group.md +5 -5
  133. package/examples/component-avatar.md +3 -3
  134. package/examples/component-back-top.md +1 -1
  135. package/examples/component-backdrop.md +1 -1
  136. package/examples/component-badge.md +3 -3
  137. package/examples/component-border-beam.md +3 -3
  138. package/examples/component-bottom-navigation.md +1 -1
  139. package/examples/component-box.md +1 -1
  140. package/examples/component-breadcrumb.md +3 -3
  141. package/examples/component-button-base.md +3 -3
  142. package/examples/component-button-group.md +2 -2
  143. package/examples/component-button.md +3 -3
  144. package/examples/component-calendar.md +2 -2
  145. package/examples/component-card-actions.md +1 -1
  146. package/examples/component-card-content.md +1 -1
  147. package/examples/component-card-header.md +1 -1
  148. package/examples/component-card-media.md +1 -1
  149. package/examples/component-card.md +3 -3
  150. package/examples/component-carousel.md +2 -2
  151. package/examples/component-cascader.md +1 -1
  152. package/examples/component-chart.md +1 -1
  153. package/examples/component-checkbox.md +3 -3
  154. package/examples/component-click-away-listener.md +1 -1
  155. package/examples/component-code.md +1 -1
  156. package/examples/component-collapsible.md +1 -1
  157. package/examples/component-color-picker.md +1 -1
  158. package/examples/component-combobox.md +1 -1
  159. package/examples/component-command.md +1 -1
  160. package/examples/component-config-provider.md +3 -3
  161. package/examples/component-context-menu.md +1 -1
  162. package/examples/component-css-baseline.md +3 -3
  163. package/examples/component-date-picker.md +2 -2
  164. package/examples/component-descriptions.md +1 -1
  165. package/examples/component-dialog-actions.md +1 -1
  166. package/examples/component-dialog-content-text.md +1 -1
  167. package/examples/component-dialog-content.md +1 -1
  168. package/examples/component-dialog-title.md +1 -1
  169. package/examples/component-dialog.md +2 -2
  170. package/examples/component-divider.md +3 -3
  171. package/examples/component-drawer.md +3 -3
  172. package/examples/component-dropdown.md +3 -3
  173. package/examples/component-empty.md +2 -2
  174. package/examples/component-fade.md +1 -1
  175. package/examples/component-field.md +1 -1
  176. package/examples/component-filled-input.md +1 -1
  177. package/examples/component-flex.md +1 -1
  178. package/examples/component-float-button.md +2 -2
  179. package/examples/component-form-control-label.md +1 -1
  180. package/examples/component-form-control.md +1 -1
  181. package/examples/component-form-controls.md +1 -1
  182. package/examples/component-form-group.md +1 -1
  183. package/examples/component-form-helper-text.md +1 -1
  184. package/examples/component-form-label.md +1 -1
  185. package/examples/component-form.md +2 -2
  186. package/examples/component-grid.md +2 -2
  187. package/examples/component-grow.md +1 -1
  188. package/examples/component-hover-card.md +1 -1
  189. package/examples/component-icon-button.md +1 -1
  190. package/examples/component-icon.md +1 -1
  191. package/examples/component-image-list.md +1 -1
  192. package/examples/component-image.md +1 -1
  193. package/examples/component-input-adornment.md +1 -1
  194. package/examples/component-input-base.md +1 -1
  195. package/examples/component-input-number.md +1 -1
  196. package/examples/component-input-otp.md +2 -2
  197. package/examples/component-input.md +3 -3
  198. package/examples/component-item.md +1 -1
  199. package/examples/component-label.md +1 -1
  200. package/examples/component-layout.md +1 -1
  201. package/examples/component-link.md +1 -1
  202. package/examples/component-list-item-avatar.md +1 -1
  203. package/examples/component-list-item-button.md +1 -1
  204. package/examples/component-list-item-icon.md +1 -1
  205. package/examples/component-list-item-text.md +1 -1
  206. package/examples/component-list-item.md +1 -1
  207. package/examples/component-list-subheader.md +1 -1
  208. package/examples/component-list.md +2 -2
  209. package/examples/component-masonry.md +1 -1
  210. package/examples/component-mentions.md +1 -1
  211. package/examples/component-menu-item.md +1 -1
  212. package/examples/component-menu-list.md +1 -1
  213. package/examples/component-menu.md +1 -1
  214. package/examples/component-menubar.md +1 -1
  215. package/examples/component-message.md +1 -1
  216. package/examples/component-mobile-stepper.md +1 -1
  217. package/examples/component-modal.md +5 -5
  218. package/examples/component-navigation-menu.md +1 -1
  219. package/examples/component-notification.md +1 -1
  220. package/examples/component-outlined-input.md +1 -1
  221. package/examples/component-pagination.md +3 -3
  222. package/examples/component-paper.md +1 -1
  223. package/examples/component-popconfirm.md +1 -1
  224. package/examples/component-popover.md +3 -3
  225. package/examples/component-popper.md +1 -1
  226. package/examples/component-progress.md +2 -2
  227. package/examples/component-qr-code.md +1 -1
  228. package/examples/component-radio.md +3 -3
  229. package/examples/component-rate.md +2 -2
  230. package/examples/component-resizable.md +1 -1
  231. package/examples/component-result.md +1 -1
  232. package/examples/component-scroll-area.md +1 -1
  233. package/examples/component-segmented.md +3 -3
  234. package/examples/component-select.md +3 -3
  235. package/examples/component-separator.md +1 -1
  236. package/examples/component-sheet.md +1 -1
  237. package/examples/component-sidebar.md +1 -1
  238. package/examples/component-skeleton.md +3 -3
  239. package/examples/component-slide.md +1 -1
  240. package/examples/component-slider.md +3 -3
  241. package/examples/component-snackbar-content.md +1 -1
  242. package/examples/component-snackbar.md +1 -1
  243. package/examples/component-sonner.md +1 -1
  244. package/examples/component-space.md +1 -1
  245. package/examples/component-speed-dial-action.md +1 -1
  246. package/examples/component-speed-dial.md +1 -1
  247. package/examples/component-spin.md +2 -2
  248. package/examples/component-spinner.md +1 -1
  249. package/examples/component-splitter.md +2 -2
  250. package/examples/component-stack.md +1 -1
  251. package/examples/component-statistic.md +1 -1
  252. package/examples/component-step-button.md +4 -4
  253. package/examples/component-step-connector.md +4 -4
  254. package/examples/component-step-content.md +1 -1
  255. package/examples/component-step-icon.md +1 -1
  256. package/examples/component-step-label.md +1 -1
  257. package/examples/component-step.md +2 -2
  258. package/examples/component-steps.md +2 -2
  259. package/examples/component-swipeable-drawer.md +1 -1
  260. package/examples/component-switch.md +3 -3
  261. package/examples/component-tab-scroll-button.md +5 -5
  262. package/examples/component-tab.md +1 -1
  263. package/examples/component-table-body.md +1 -1
  264. package/examples/component-table-cell.md +1 -1
  265. package/examples/component-table-container.md +1 -1
  266. package/examples/component-table-footer.md +1 -1
  267. package/examples/component-table-head.md +1 -1
  268. package/examples/component-table-pagination.md +1 -1
  269. package/examples/component-table-row.md +1 -1
  270. package/examples/component-table-sort-label.md +1 -1
  271. package/examples/component-table.md +2 -2
  272. package/examples/component-tabs.md +3 -3
  273. package/examples/component-tag-badge.md +2 -2
  274. package/examples/component-tag.md +1 -1
  275. package/examples/component-textarea-autosize.md +1 -1
  276. package/examples/component-textarea.md +1 -1
  277. package/examples/component-time-picker.md +1 -1
  278. package/examples/component-timeline.md +1 -1
  279. package/examples/component-toast.md +4 -4
  280. package/examples/component-toggle-button.md +1 -1
  281. package/examples/component-toggle.md +1 -1
  282. package/examples/component-toolbar.md +1 -1
  283. package/examples/component-tooltip.md +3 -3
  284. package/examples/component-tour.md +1 -1
  285. package/examples/component-transfer.md +1 -1
  286. package/examples/component-tree-select.md +1 -1
  287. package/examples/component-tree.md +1 -1
  288. package/examples/component-typography.md +2 -2
  289. package/examples/component-upload.md +1 -1
  290. package/examples/component-watermark.md +1 -1
  291. package/examples/component-zoom.md +1 -1
  292. package/knowledge/COVERAGE.md +4 -3
  293. package/knowledge/components/INDEX.md +202 -202
  294. package/knowledge/patterns/brand-references.md +72 -72
  295. package/package.json +1 -1
  296. package/tools/audit/local-ci.py +16 -1
  297. package/tools/audit/package-smoke.py +717 -9
  298. package/tools/audit/registry-smoke.py +912 -10
  299. package/tools/audit/release-metadata.py +47 -1
  300. package/tools/audit/smoke_assertions.py +998 -35
  301. package/tools/migrations/refs-links-to-reference-pages.py +179 -0
@@ -0,0 +1,332 @@
1
+ // Aggregate action summary metrics for the bundle-handoff operator runbook.
2
+
3
+ import { uniqueValues } from "./site-bundle-handoff-runbook-evidence.mjs";
4
+ import {
5
+ callsExternalSystem,
6
+ hasCommands,
7
+ hasOutputFile,
8
+ isManualStage,
9
+ isOptionalStage,
10
+ isRequiredStage,
11
+ mutatesTargetRepo,
12
+ usesLocalOutputRunPolicy,
13
+ usesReadOnlyRunPolicy,
14
+ } from "./site-bundle-handoff-runbook-maps.mjs";
15
+
16
+ export function buildActionSummary({
17
+ stages,
18
+ commandStages,
19
+ stageActionRows,
20
+ stageHumanLineMaps,
21
+ nextActionSummary,
22
+ }) {
23
+ const { stageHumanLineDisplayRowSummary, stageHumanLineSummary } = stageHumanLineMaps;
24
+ const countBy = (predicate) => stages.filter(predicate).length;
25
+ const countActions = (predicate) => stageActionRows.filter(predicate).length;
26
+ const firstActionKey = (predicate) => stageActionRows.find(predicate)?.key || "";
27
+ const sumActions = (getValue) => stageActionRows.reduce((sum, stage) => sum + getValue(stage), 0);
28
+ const maxActionValue = (getValue) => Math.max(0, ...stageActionRows.map(getValue));
29
+ const countActionsWithItems = (field) => countActions((stage) => stage[field].length > 0);
30
+ const sumActionItems = (field) => sumActions((stage) => stage[field].length);
31
+ const sumActionItemValues = (field, getValue) => sumActions(
32
+ (stage) => stage[field].reduce((sum, item) => sum + getValue(item), 0),
33
+ );
34
+ const countActionItems = (field, predicate) => sumActions(
35
+ (stage) => stage[field].filter(predicate).length,
36
+ );
37
+ const countEvidenceCaptureFields = (predicate) => countActionItems("actionEvidenceCaptureFields", predicate);
38
+ const countPayloadBindings = (predicate) => countActionItems("actionEvidenceCapturePayloadBindings", predicate);
39
+ const countValidationSpecs = (predicate) => countActionItems("actionEvidenceCaptureValidationSpecs", predicate);
40
+ const countInitialValidationStates = (predicate) => countActionItems("actionEvidenceCaptureInitialValidationStates", predicate);
41
+ const countInitialDisplayRows = (predicate) => countActionItems("actionEvidenceCaptureInitialValidationDisplayMetadata", predicate);
42
+ const countInitialChecklistItems = (predicate) => countActionItems("actionEvidenceCaptureInitialValidationChecklist", predicate);
43
+ const countActionsBySummary = (field, predicate) => countActions((stage) => predicate(stage[field]));
44
+ const sumSummaryValues = (field, getValue) => sumActions((stage) => getValue(stage[field]));
45
+ const countInitialValidationSummaries = (predicate) => (
46
+ countActionsBySummary("actionEvidenceCaptureInitialValidationSummary", predicate)
47
+ );
48
+ const sumInitialValidationSummaryValues = (getValue) => (
49
+ sumSummaryValues("actionEvidenceCaptureInitialValidationSummary", getValue)
50
+ );
51
+ const countInitialChecklistSummaries = (predicate) => (
52
+ countActionsBySummary("actionEvidenceCaptureInitialValidationChecklistSummary", predicate)
53
+ );
54
+ const sumInitialChecklistSummaryValues = (getValue) => (
55
+ sumSummaryValues("actionEvidenceCaptureInitialValidationChecklistSummary", getValue)
56
+ );
57
+ const uniqueActionListValueCount = (field) => uniqueValues(stageActionRows.flatMap((stage) => stage[field])).length;
58
+ const payloadTemplatePathCount = (stage) => Object.keys(stage.actionEvidenceCapturePayloadFlatTemplate).length;
59
+ const maxActionItemValue = (field, getValue) => Math.max(
60
+ 0,
61
+ ...stageActionRows.flatMap((stage) => stage[field].map(getValue)),
62
+ );
63
+ const maxEvidenceCaptureFieldValue = (getValue) => maxActionItemValue("actionEvidenceCaptureFields", getValue);
64
+ const firstActionWithEvidenceCaptureField = (predicate) => (
65
+ firstActionKey((stage) => stage.actionEvidenceCaptureFields.some(predicate))
66
+ );
67
+ const firstStageKey = (predicate) => stages.find(predicate)?.key || "";
68
+ const isActionEnabled = (action) => action.actionEnabled;
69
+ const isActionDisabled = (action) => !action.actionEnabled;
70
+ const isManualDisabledAction = (action) => isActionDisabled(action) && action.manual;
71
+ const hasActionPrerequisites = (action) => action.actionHasPrerequisites;
72
+ const hasActionDependencyReason = (action) => action.actionDependencyReasonCode;
73
+ const blocksOtherActions = (action) => action.actionBlocksStages;
74
+ const hasActionCompletionCriteria = (action) => action.actionHasCompletionCriteria;
75
+ const requiresActionEvidence = (action) => action.actionRequiresEvidence;
76
+ const targetsLocalCommandEvidence = (action) => action.actionEvidenceTarget === "local-command-output";
77
+ const targetsLocalOutputEvidence = (action) => action.actionEvidenceTarget === "local-output-file";
78
+ const targetsTargetRepoEvidence = (action) => action.actionEvidenceTarget === "target-repo-working-tree";
79
+ const targetsHandoffRecordEvidence = (action) => action.actionEvidenceTarget === "handoff-evidence-record";
80
+ const hasActionEvidenceCaptureFields = (action) => action.actionHasEvidenceCaptureFields;
81
+ const hasRequiredActionEvidenceCaptureFields = (action) => action.actionRequiredEvidenceCaptureFieldCount > 0;
82
+ const hasOptionalActionEvidenceCaptureFields = (action) => action.actionOptionalEvidenceCaptureFieldCount > 0;
83
+ const hasMultipleEvidenceCaptureSections = (action) => action.actionEvidenceCaptureSectionCount > 1;
84
+ const hasMultipleEvidenceCapturePayloadNamespaces = (action) => action.actionEvidenceCapturePayloadNamespaceCount > 1;
85
+ const hasEvidenceCapturePayloadTemplate = (action) => payloadTemplatePathCount(action) > 0;
86
+ const isManualAction = (action) => action.manual;
87
+ const isManualEvidenceAction = (action) => action.actionType === "manual-evidence";
88
+ const usesTextareaInput = (field) => field.inputType === "textarea";
89
+ const usesTextInput = (field) => field.inputType === "text";
90
+ const usesFilePathInput = (field) => field.inputType === "file-path";
91
+ const usesListInput = (field) => field.inputType === "list";
92
+ const capturesLongText = (field) => field.valueShape === "long-text";
93
+ const capturesShortText = (field) => field.valueShape === "short-text";
94
+ const capturesFilePathValue = (field) => field.valueShape === "file-path";
95
+ const capturesStringList = (field) => field.valueShape === "string-list";
96
+ const acceptsMultipleValues = (item) => item.acceptsMultiple;
97
+ const acceptsSingleValue = (item) => !item.acceptsMultiple;
98
+ const hasEmptyStringValue = (field) => field.emptyValue === "";
99
+ const hasEmptyListValue = (field) => Array.isArray(field.emptyValue);
100
+ const hasPlaceholder = (field) => Boolean(field.placeholder);
101
+ const hasAriaLabel = (field) => Boolean(field.ariaLabel);
102
+ const hasHelpText = (field) => Boolean(field.helpText);
103
+ const belongsToEvidenceCaptureSection = (field) => Boolean(field.sectionKey);
104
+ const mapsToPayloadPath = (field) => Boolean(field.payloadPath);
105
+ const isRequiredItem = (item) => item.required;
106
+ const isOptionalItem = (item) => !item.required;
107
+ const hasValidationRule = (item) => Boolean(item.validationRule);
108
+ const isRequiredValidatedField = (field) => isRequiredItem(field) && hasValidationRule(field);
109
+ const isOptionalValidatedField = (field) => isOptionalItem(field) && hasValidationRule(field);
110
+ const isErrorValidationSpec = (spec) => spec.severity === "error";
111
+ const isInfoValidationSpec = (spec) => spec.severity === "info";
112
+ const isValidInitialState = (state) => state.valid;
113
+ const isInvalidInitialState = (state) => !state.valid;
114
+ const isBlockingInitialState = (state) => state.blocking;
115
+ const isOptionalEmptyInitialState = (state) => state.status === "optional-empty";
116
+ const isMissingRequiredInitialState = (state) => state.status === "missing-required";
117
+ const isPristineInitialState = (state) => !state.dirty && !state.touched;
118
+ const isDangerInitialDisplayRow = (display) => display.statusTone === "danger";
119
+ const isInfoInitialDisplayRow = (display) => display.statusTone === "info";
120
+ const isBlockingInitialDisplayRow = (display) => display.blocking;
121
+ const isNonBlockingInitialDisplayRow = (display) => !display.blocking;
122
+ const isInitiallyCheckedChecklistItem = (item) => item.checkedInitially;
123
+ const isInitiallyUncheckedChecklistItem = (item) => !item.checkedInitially;
124
+ const blocksChecklistCompletion = (item) => item.completionBlocking;
125
+ const doesNotBlockChecklistCompletion = (item) => !item.completionBlocking;
126
+ const actionCountSummary = {
127
+ totalActionCount: stages.length,
128
+ commandActionCount: commandStages.length,
129
+ manualActionCount: countBy(isManualStage),
130
+ enabledActionCount: countActions(isActionEnabled),
131
+ disabledActionCount: countActions(isActionDisabled),
132
+ manualDisabledActionCount: countActions(isManualDisabledAction),
133
+ };
134
+ const actionDependencySummary = {
135
+ actionWithPrerequisiteCount: countActions(hasActionPrerequisites),
136
+ maxActionPrerequisiteCount: maxActionValue((stage) => stage.actionPrerequisiteCount),
137
+ actionWithDependencyReasonCount: countActions(hasActionDependencyReason),
138
+ actionBlockingOtherActionCount: countActions(blocksOtherActions),
139
+ maxActionBlockedStageCount: maxActionValue((stage) => stage.actionBlockedStageCount),
140
+ actionWithCompletionCriteriaCount: countActions(hasActionCompletionCriteria),
141
+ totalActionCompletionCriteriaCount: sumActions((stage) => stage.actionCompletionCriteriaCount),
142
+ maxActionCompletionCriteriaCount: maxActionValue((stage) => stage.actionCompletionCriteriaCount),
143
+ };
144
+ const actionEvidenceSummary = {
145
+ actionRequiringEvidenceCount: countActions(requiresActionEvidence),
146
+ totalActionEvidenceRequirementCount: sumActions((stage) => stage.actionEvidenceRequirementCount),
147
+ maxActionEvidenceRequirementCount: maxActionValue((stage) => stage.actionEvidenceRequirementCount),
148
+ localCommandEvidenceActionCount: countActions(targetsLocalCommandEvidence),
149
+ localOutputEvidenceActionCount: countActions(targetsLocalOutputEvidence),
150
+ targetRepoEvidenceActionCount: countActions(targetsTargetRepoEvidence),
151
+ handoffRecordEvidenceActionCount: countActions(targetsHandoffRecordEvidence),
152
+ };
153
+ const actionEvidenceCaptureFieldSummary = {
154
+ actionWithEvidenceCaptureFieldCount: countActions(hasActionEvidenceCaptureFields),
155
+ actionWithRequiredEvidenceCaptureFieldCount: countActions(hasRequiredActionEvidenceCaptureFields),
156
+ actionWithOptionalEvidenceCaptureFieldCount: countActions(hasOptionalActionEvidenceCaptureFields),
157
+ totalActionEvidenceCaptureFieldCount: sumActions((stage) => stage.actionEvidenceCaptureFieldCount),
158
+ totalRequiredActionEvidenceCaptureFieldCount: sumActions((stage) => stage.actionRequiredEvidenceCaptureFieldCount),
159
+ totalOptionalActionEvidenceCaptureFieldCount: sumActions((stage) => stage.actionOptionalEvidenceCaptureFieldCount),
160
+ maxActionEvidenceCaptureFieldCount: maxActionValue((stage) => stage.actionEvidenceCaptureFieldCount),
161
+ textareaEvidenceCaptureFieldCount: countEvidenceCaptureFields(usesTextareaInput),
162
+ textEvidenceCaptureFieldCount: countEvidenceCaptureFields(usesTextInput),
163
+ filePathEvidenceCaptureFieldCount: countEvidenceCaptureFields(usesFilePathInput),
164
+ listEvidenceCaptureFieldCount: countEvidenceCaptureFields(usesListInput),
165
+ longTextEvidenceCaptureFieldCount: countEvidenceCaptureFields(capturesLongText),
166
+ shortTextEvidenceCaptureFieldCount: countEvidenceCaptureFields(capturesShortText),
167
+ filePathValueEvidenceCaptureFieldCount: countEvidenceCaptureFields(capturesFilePathValue),
168
+ stringListEvidenceCaptureFieldCount: countEvidenceCaptureFields(capturesStringList),
169
+ multiValueEvidenceCaptureFieldCount: countEvidenceCaptureFields(acceptsMultipleValues),
170
+ singleValueEvidenceCaptureFieldCount: countEvidenceCaptureFields(acceptsSingleValue),
171
+ emptyStringEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasEmptyStringValue),
172
+ emptyListEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasEmptyListValue),
173
+ placeholderEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasPlaceholder),
174
+ ariaLabelEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasAriaLabel),
175
+ helpTextEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasHelpText),
176
+ sectionedEvidenceCaptureFieldCount: countEvidenceCaptureFields(belongsToEvidenceCaptureSection),
177
+ uniqueEvidenceCaptureSectionCount: uniqueActionListValueCount("actionEvidenceCaptureSectionKeys"),
178
+ actionWithMultipleEvidenceCaptureSectionCount: countActions(hasMultipleEvidenceCaptureSections),
179
+ maxActionEvidenceCaptureSectionCount: maxActionValue((stage) => stage.actionEvidenceCaptureSectionCount),
180
+ payloadMappedEvidenceCaptureFieldCount: countEvidenceCaptureFields(mapsToPayloadPath),
181
+ };
182
+ const actionEvidenceCapturePayloadSummary = {
183
+ uniqueEvidenceCapturePayloadNamespaceCount: uniqueActionListValueCount("actionEvidenceCapturePayloadNamespaces"),
184
+ actionWithMultipleEvidenceCapturePayloadNamespaceCount: countActions(hasMultipleEvidenceCapturePayloadNamespaces),
185
+ maxActionEvidenceCapturePayloadNamespaceCount: maxActionValue((stage) => stage.actionEvidenceCapturePayloadNamespaceCount),
186
+ actionWithEvidenceCapturePayloadTemplateCount: countActions(hasEvidenceCapturePayloadTemplate),
187
+ evidenceCapturePayloadTemplatePathCount: sumActions(payloadTemplatePathCount),
188
+ maxActionEvidenceCapturePayloadTemplatePathCount: maxActionValue(payloadTemplatePathCount),
189
+ actionWithEvidenceCapturePayloadBindingCount: countActionsWithItems("actionEvidenceCapturePayloadBindings"),
190
+ evidenceCapturePayloadBindingCount: sumActionItems("actionEvidenceCapturePayloadBindings"),
191
+ requiredEvidenceCapturePayloadBindingCount: countPayloadBindings(isRequiredItem),
192
+ optionalEvidenceCapturePayloadBindingCount: countPayloadBindings(isOptionalItem),
193
+ multiValueEvidenceCapturePayloadBindingCount: countPayloadBindings(acceptsMultipleValues),
194
+ };
195
+ const actionEvidenceCaptureValidationSummary = {
196
+ actionWithEvidenceCaptureValidationSpecCount: countActionsWithItems("actionEvidenceCaptureValidationSpecs"),
197
+ evidenceCaptureValidationSpecCount: sumActionItems("actionEvidenceCaptureValidationSpecs"),
198
+ requiredEvidenceCaptureValidationSpecCount: countValidationSpecs(isRequiredItem),
199
+ optionalEvidenceCaptureValidationSpecCount: countValidationSpecs(isOptionalItem),
200
+ errorEvidenceCaptureValidationSpecCount: countValidationSpecs(isErrorValidationSpec),
201
+ infoEvidenceCaptureValidationSpecCount: countValidationSpecs(isInfoValidationSpec),
202
+ multiValueEvidenceCaptureValidationSpecCount: countValidationSpecs(acceptsMultipleValues),
203
+ };
204
+ const actionEvidenceCaptureInitialStateSummary = {
205
+ actionWithEvidenceCaptureInitialValidationStateCount: countActionsWithItems("actionEvidenceCaptureInitialValidationStates"),
206
+ evidenceCaptureInitialValidationStateCount: sumActionItems("actionEvidenceCaptureInitialValidationStates"),
207
+ validInitialEvidenceCaptureStateCount: countInitialValidationStates(isValidInitialState),
208
+ invalidInitialEvidenceCaptureStateCount: countInitialValidationStates(isInvalidInitialState),
209
+ blockingInitialEvidenceCaptureStateCount: countInitialValidationStates(isBlockingInitialState),
210
+ optionalEmptyInitialEvidenceCaptureStateCount: countInitialValidationStates(isOptionalEmptyInitialState),
211
+ missingRequiredInitialEvidenceCaptureStateCount: countInitialValidationStates(isMissingRequiredInitialState),
212
+ pristineInitialEvidenceCaptureStateCount: countInitialValidationStates(isPristineInitialState),
213
+ };
214
+ const actionEvidenceCaptureInitialDisplaySummary = {
215
+ actionWithEvidenceCaptureInitialValidationDisplayMetadataCount: countActionsWithItems("actionEvidenceCaptureInitialValidationDisplayMetadata"),
216
+ evidenceCaptureInitialValidationDisplayMetadataCount: sumActionItems("actionEvidenceCaptureInitialValidationDisplayMetadata"),
217
+ dangerInitialEvidenceCaptureDisplayMetadataCount: countInitialDisplayRows(isDangerInitialDisplayRow),
218
+ infoInitialEvidenceCaptureDisplayMetadataCount: countInitialDisplayRows(isInfoInitialDisplayRow),
219
+ blockingInitialEvidenceCaptureDisplayMetadataCount: countInitialDisplayRows(isBlockingInitialDisplayRow),
220
+ nonBlockingInitialEvidenceCaptureDisplayMetadataCount: countInitialDisplayRows(isNonBlockingInitialDisplayRow),
221
+ };
222
+ const actionEvidenceCaptureInitialValidationSummary = {
223
+ actionWithEvidenceCaptureInitialValidationSummaryCount: countInitialValidationSummaries((summary) => summary.fieldCount > 0),
224
+ blockedInitialEvidenceCaptureSummaryActionCount: countInitialValidationSummaries((summary) => summary.status === "blocked"),
225
+ readyInitialEvidenceCaptureSummaryActionCount: countInitialValidationSummaries((summary) => summary.status === "ready"),
226
+ completableInitialEvidenceCaptureSummaryActionCount: countInitialValidationSummaries((summary) => summary.canCompleteInitially),
227
+ nonCompletableInitialEvidenceCaptureSummaryActionCount: countInitialValidationSummaries((summary) => !summary.canCompleteInitially),
228
+ initialEvidenceCaptureSummaryBlockingFieldCount: sumInitialValidationSummaryValues((summary) => summary.blockingCount),
229
+ initialEvidenceCaptureSummaryMissingRequiredFieldCount: sumInitialValidationSummaryValues((summary) => summary.missingRequiredCount),
230
+ initialEvidenceCaptureSummaryOptionalEmptyFieldCount: sumInitialValidationSummaryValues((summary) => summary.optionalEmptyCount),
231
+ };
232
+ const actionEvidenceCaptureInitialChecklistSummary = {
233
+ actionWithEvidenceCaptureInitialValidationChecklistCount: countActionsWithItems("actionEvidenceCaptureInitialValidationChecklist"),
234
+ evidenceCaptureInitialValidationChecklistItemCount: sumActionItems("actionEvidenceCaptureInitialValidationChecklist"),
235
+ checkedInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(isInitiallyCheckedChecklistItem),
236
+ uncheckedInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(isInitiallyUncheckedChecklistItem),
237
+ blockingInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(blocksChecklistCompletion),
238
+ nonBlockingInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(doesNotBlockChecklistCompletion),
239
+ requiredInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(isRequiredItem),
240
+ optionalInitialEvidenceCaptureChecklistItemCount: countInitialChecklistItems(isOptionalItem),
241
+ actionWithEvidenceCaptureInitialValidationChecklistSummaryCount: countInitialChecklistSummaries((summary) => summary.itemCount > 0),
242
+ blockedInitialEvidenceCaptureChecklistSummaryActionCount: countInitialChecklistSummaries((summary) => summary.status === "blocked"),
243
+ readyInitialEvidenceCaptureChecklistSummaryActionCount: countInitialChecklistSummaries((summary) => summary.status === "ready"),
244
+ completeInitialEvidenceCaptureChecklistSummaryActionCount: countInitialChecklistSummaries((summary) => summary.allCheckedInitially),
245
+ incompleteInitialEvidenceCaptureChecklistSummaryActionCount: countInitialChecklistSummaries((summary) => !summary.allCheckedInitially),
246
+ initialEvidenceCaptureChecklistSummaryCheckedItemCount: sumInitialChecklistSummaryValues((summary) => summary.checkedCount),
247
+ initialEvidenceCaptureChecklistSummaryUncheckedItemCount: sumInitialChecklistSummaryValues((summary) => summary.uncheckedCount),
248
+ initialEvidenceCaptureChecklistSummaryBlockingUncheckedItemCount: sumInitialChecklistSummaryValues((summary) => summary.blockingUncheckedCount),
249
+ };
250
+ const humanLineActionSummary = {
251
+ humanLineCount: stageHumanLineSummary.count,
252
+ humanLineByKeyCount: stageHumanLineSummary.byKeyCount,
253
+ humanLineWithEvidenceProgressCount: stageHumanLineSummary.evidenceProgressCount,
254
+ humanLineWithBlockedEvidenceProgressCount: stageHumanLineSummary.blockedEvidenceProgressCount,
255
+ humanLineWithReadyEvidenceProgressCount: stageHumanLineSummary.readyEvidenceProgressCount,
256
+ humanLineDisplayRowCount: stageHumanLineDisplayRowSummary.count,
257
+ humanLineDisplayRowByKeyCount: stageHumanLineDisplayRowSummary.byKeyCount,
258
+ humanLineDisplayRowWithEvidenceProgressCount: stageHumanLineDisplayRowSummary.evidenceProgressCount,
259
+ humanLineDisplayRowWithBlockedEvidenceProgressCount: stageHumanLineDisplayRowSummary.blockedEvidenceProgressCount,
260
+ humanLineDisplayRowWithReadyEvidenceProgressCount: stageHumanLineDisplayRowSummary.readyEvidenceProgressCount,
261
+ humanLineDisplayRowReadyActionCount: stageHumanLineDisplayRowSummary.readyActionStatusCount,
262
+ humanLineDisplayRowManualActionCount: stageHumanLineDisplayRowSummary.manualActionStatusCount,
263
+ };
264
+ const evidenceCaptureValidatedFieldSummary = {
265
+ validatedEvidenceCaptureFieldCount: countEvidenceCaptureFields(hasValidationRule),
266
+ requiredValidatedEvidenceCaptureFieldCount: countEvidenceCaptureFields(isRequiredValidatedField),
267
+ optionalValidatedEvidenceCaptureFieldCount: countEvidenceCaptureFields(isOptionalValidatedField),
268
+ minEvidenceCaptureFieldLengthTotal: sumActionItemValues(
269
+ "actionEvidenceCaptureFields",
270
+ (field) => field.minLength,
271
+ ),
272
+ maxEvidenceCaptureFieldMinLength: maxEvidenceCaptureFieldValue((field) => field.minLength),
273
+ };
274
+ const actionRunPolicySummary = {
275
+ requiredActionCount: countBy(isRequiredStage),
276
+ optionalActionCount: countBy(isOptionalStage),
277
+ readOnlyActionCount: countBy(usesReadOnlyRunPolicy),
278
+ localOutputActionCount: countBy(usesLocalOutputRunPolicy),
279
+ outputFileActionCount: countBy(hasOutputFile),
280
+ externalCallActionCount: countBy(callsExternalSystem),
281
+ targetRepoMutationActionCount: countBy(mutatesTargetRepo),
282
+ };
283
+ const firstActionLookupSummary = {
284
+ firstRequiredCommandStageKey: firstStageKey((stage) => isRequiredStage(stage) && hasCommands(stage)),
285
+ firstLocalOutputStageKey: firstStageKey((stage) => stage.writesLocalFile),
286
+ firstManualStageKey: firstStageKey(isManualStage),
287
+ firstRequiredManualStageKey: firstStageKey((stage) => isRequiredStage(stage) && isManualStage(stage)),
288
+ firstEvidenceStageKey: firstStageKey((stage) => stage.kind === "manual-reporting"),
289
+ firstActionWithPrerequisiteKey: firstActionKey(hasActionPrerequisites),
290
+ firstManualActionWithPrerequisiteKey: firstActionKey((action) => isManualAction(action) && hasActionPrerequisites(action)),
291
+ firstEvidenceActionWithPrerequisiteKey: firstActionKey((action) => isManualEvidenceAction(action) && hasActionPrerequisites(action)),
292
+ firstActionWithDependencyReasonKey: firstActionKey(hasActionDependencyReason),
293
+ firstActionBlockingOtherActionKey: firstActionKey(blocksOtherActions),
294
+ firstActionWithCompletionCriteriaKey: firstActionKey(hasActionCompletionCriteria),
295
+ firstManualActionWithCompletionCriteriaKey: firstActionKey((action) => isManualAction(action) && hasActionCompletionCriteria(action)),
296
+ firstActionRequiringEvidenceKey: firstActionKey(requiresActionEvidence),
297
+ firstManualActionRequiringEvidenceKey: firstActionKey((action) => isManualAction(action) && requiresActionEvidence(action)),
298
+ firstEvidenceRecordingActionKey: firstActionKey((action) => isManualEvidenceAction(action) && requiresActionEvidence(action)),
299
+ firstTargetRepoEvidenceActionKey: firstActionKey(targetsTargetRepoEvidence),
300
+ firstLocalOutputEvidenceActionKey: firstActionKey(targetsLocalOutputEvidence),
301
+ firstActionWithEvidenceCaptureFieldKey: firstActionKey(hasActionEvidenceCaptureFields),
302
+ firstActionWithOptionalEvidenceCaptureFieldKey: firstActionKey(hasOptionalActionEvidenceCaptureFields),
303
+ firstManualActionWithEvidenceCaptureFieldKey: firstActionKey((action) => isManualAction(action) && hasActionEvidenceCaptureFields(action)),
304
+ firstTextareaEvidenceCaptureActionKey: firstActionWithEvidenceCaptureField(usesTextareaInput),
305
+ firstMultiValueEvidenceCaptureActionKey: firstActionWithEvidenceCaptureField(acceptsMultipleValues),
306
+ firstValidationRuleEvidenceCaptureActionKey: firstActionWithEvidenceCaptureField(hasValidationRule),
307
+ };
308
+ const actionBoundarySummary = {
309
+ requiresTargetRepoWork: stages.some((stage) => stage.kind === "manual-target-repo"),
310
+ requiresEvidenceReturn: stages.some((stage) => stage.kind === "manual-reporting"),
311
+ externalCalls: stages.some(callsExternalSystem),
312
+ targetRepoMutation: stages.some(mutatesTargetRepo),
313
+ };
314
+ return {
315
+ ...actionCountSummary,
316
+ ...actionDependencySummary,
317
+ ...actionEvidenceSummary,
318
+ ...actionEvidenceCaptureFieldSummary,
319
+ ...actionEvidenceCapturePayloadSummary,
320
+ ...actionEvidenceCaptureValidationSummary,
321
+ ...actionEvidenceCaptureInitialStateSummary,
322
+ ...actionEvidenceCaptureInitialDisplaySummary,
323
+ ...actionEvidenceCaptureInitialValidationSummary,
324
+ ...actionEvidenceCaptureInitialChecklistSummary,
325
+ ...humanLineActionSummary,
326
+ ...evidenceCaptureValidatedFieldSummary,
327
+ ...actionRunPolicySummary,
328
+ ...nextActionSummary,
329
+ ...firstActionLookupSummary,
330
+ ...actionBoundarySummary,
331
+ };
332
+ }
@@ -0,0 +1,113 @@
1
+ // Action metadata helpers for Website Improvement bundle handoff runbooks.
2
+
3
+ export function getStageActionType(stage) {
4
+ if (stage.commandCount > 0 && stage.writesLocalFile) return "write-local-output";
5
+ if (stage.commandCount > 0 && stage.required) return "run-local-gate";
6
+ if (stage.commandCount > 0) return "refresh-local-preview";
7
+ if (stage.kind === "manual-target-repo") return "manual-target-repo";
8
+ if (stage.kind === "manual-reporting") return "manual-evidence";
9
+ return "review-stage";
10
+ }
11
+
12
+ export function getStageActionLabel(stage) {
13
+ return {
14
+ verifySourceBundle: "Run strict bundle check",
15
+ refreshHandoffSnapshot: "Refresh strict handoff JSON",
16
+ writeEffectiveTaskPrompt: "Write selected task prompt",
17
+ executeInTargetRepo: "Implement in target repo",
18
+ recordEvidence: "Record verification evidence",
19
+ }[stage.key] || stage.label;
20
+ }
21
+
22
+ export function getStageActionInstruction(stage) {
23
+ return {
24
+ verifySourceBundle: "Run the strict local bundle check and resolve any checksum or generated-file drift before handoff.",
25
+ refreshHandoffSnapshot: "Optional: regenerate the strict handoff JSON snapshot when a wrapper or GUI needs the latest contract.",
26
+ writeEffectiveTaskPrompt: "Write the selected task prompt to a local Markdown file before switching into the target website repo.",
27
+ executeInTargetRepo: "Manual: open the generated prompt in the target website repo, inspect architecture, implement the scoped task, and run target-repo verification.",
28
+ recordEvidence: "Manual: record changed files, verification commands, viewport checks, accessibility checks, remaining risks, and the bundle digest.",
29
+ }[stage.key] || stage.reason;
30
+ }
31
+
32
+ export function getStageActionButtonLabel(stage) {
33
+ return {
34
+ verifySourceBundle: "Run Check",
35
+ refreshHandoffSnapshot: "Refresh JSON",
36
+ writeEffectiveTaskPrompt: "Write Prompt",
37
+ executeInTargetRepo: "Open Target Repo",
38
+ recordEvidence: "Record Evidence",
39
+ }[stage.key] || getStageActionLabel(stage);
40
+ }
41
+
42
+ export function getStageActionAffordance(stage) {
43
+ if (stage.commandCount > 0 && stage.writesLocalFile) return "local-output-button";
44
+ if (stage.commandCount > 0 && stage.required) return "primary-command-button";
45
+ if (stage.commandCount > 0) return "secondary-command-button";
46
+ if (stage.kind === "manual-target-repo") return "manual-target-repo-step";
47
+ if (stage.kind === "manual-reporting") return "manual-evidence-step";
48
+ return "review-step";
49
+ }
50
+
51
+ export function getStageActionEnabled(stage) {
52
+ return stage.commandCount > 0;
53
+ }
54
+
55
+ export function getStageActionStatus(stage) {
56
+ if (stage.commandCount > 0 && stage.required) return "ready";
57
+ if (stage.commandCount > 0) return "optional";
58
+ if (stage.kind === "manual-target-repo" || stage.kind === "manual-reporting") return "manual";
59
+ return "blocked";
60
+ }
61
+
62
+ export function getStageActionStatusLabel(stage) {
63
+ return {
64
+ ready: "Ready",
65
+ optional: "Optional",
66
+ manual: "Manual",
67
+ blocked: "Blocked",
68
+ }[getStageActionStatus(stage)];
69
+ }
70
+
71
+ export function getStageActionStatusTone(stage) {
72
+ return {
73
+ ready: "success",
74
+ optional: "neutral",
75
+ manual: "info",
76
+ blocked: "danger",
77
+ }[getStageActionStatus(stage)];
78
+ }
79
+
80
+ export function getStageActionDisabledReasonCode(stage) {
81
+ if (getStageActionEnabled(stage)) return "";
82
+ if (stage.kind === "manual-target-repo") return "manual-target-repo-step";
83
+ if (stage.kind === "manual-reporting") return "manual-evidence-step";
84
+ return "missing-local-command";
85
+ }
86
+
87
+ export function getStageActionDisabledReason(stage) {
88
+ return {
89
+ "manual-target-repo-step": "No local design-ai command is available for this stage; execute the generated prompt inside the target website repo.",
90
+ "manual-evidence-step": "No local design-ai command is available for this stage; record evidence after target-repo implementation and verification.",
91
+ "missing-local-command": "No local command is available for this stage.",
92
+ }[getStageActionDisabledReasonCode(stage)] || "";
93
+ }
94
+
95
+ export function getStageActionEvidenceTarget(stage) {
96
+ return {
97
+ verifySourceBundle: "local-command-output",
98
+ refreshHandoffSnapshot: "local-command-output",
99
+ writeEffectiveTaskPrompt: "local-output-file",
100
+ executeInTargetRepo: "target-repo-working-tree",
101
+ recordEvidence: "handoff-evidence-record",
102
+ }[stage.key] || "not-applicable";
103
+ }
104
+
105
+ export function getStageActionEvidenceTargetLabel(stage) {
106
+ return {
107
+ "local-command-output": "Local command output",
108
+ "local-output-file": "Local output file",
109
+ "target-repo-working-tree": "Target repo working tree",
110
+ "handoff-evidence-record": "Handoff evidence record",
111
+ "not-applicable": "Not applicable",
112
+ }[getStageActionEvidenceTarget(stage)];
113
+ }
@@ -0,0 +1,164 @@
1
+ // Stage-specific evidence capture fields for Website Improvement bundle handoff runbooks.
2
+
3
+ import {
4
+ getStageActionEvidenceTarget,
5
+ } from "./site-bundle-handoff-runbook-actions.mjs";
6
+ import {
7
+ getEvidenceCaptureFieldAriaLabel,
8
+ getEvidenceCaptureFieldEmptyValue,
9
+ getEvidenceCaptureFieldHelpText,
10
+ getEvidenceCaptureFieldPayloadNamespace,
11
+ getEvidenceCaptureFieldPayloadPath,
12
+ getEvidenceCaptureFieldRequirementLabel,
13
+ getEvidenceCaptureFieldSectionKey,
14
+ getEvidenceCaptureFieldSectionLabel,
15
+ getEvidenceCaptureFieldValueShape,
16
+ } from "./site-bundle-handoff-runbook-evidence.mjs";
17
+
18
+ export function getStageActionEvidenceCaptureFields(stage) {
19
+ return ({
20
+ verifySourceBundle: [
21
+ {
22
+ key: "strictBundleCheckOutput",
23
+ label: "Strict bundle-check output",
24
+ inputType: "textarea",
25
+ required: true,
26
+ evidenceTarget: getStageActionEvidenceTarget(stage),
27
+ placeholder: "Paste the strict bundle-check pass output or JSON status.",
28
+ validationRule: "non-empty-text",
29
+ minLength: 20,
30
+ example: "Status: pass; checksumFailures: 0; generatedFailures: 0",
31
+ validationHint: "Required: paste a passing strict bundle-check result.",
32
+ },
33
+ {
34
+ key: "bundleDigest",
35
+ label: "Bundle digest",
36
+ inputType: "text",
37
+ required: true,
38
+ evidenceTarget: getStageActionEvidenceTarget(stage),
39
+ placeholder: "Record the bundle digest or checksum summary.",
40
+ validationRule: "checksum-or-digest-text",
41
+ minLength: 8,
42
+ example: "7685113af4744990fadf301b220b4739066e5f6ec2c40857825211e1167241aa",
43
+ validationHint: "Required: record a digest, checksum, or equivalent bundle integrity summary.",
44
+ },
45
+ ],
46
+ refreshHandoffSnapshot: [
47
+ {
48
+ key: "handoffJsonSnapshot",
49
+ label: "Strict handoff JSON snapshot",
50
+ inputType: "textarea",
51
+ required: false,
52
+ evidenceTarget: getStageActionEvidenceTarget(stage),
53
+ placeholder: "Paste or link the refreshed strict handoff JSON snapshot when used.",
54
+ validationRule: "optional-json-snapshot",
55
+ minLength: 0,
56
+ example: "{ \"status\": \"pass\", \"operatorRunbook\": { ... } }",
57
+ validationHint: "Optional: paste the refreshed strict handoff JSON snapshot when available.",
58
+ },
59
+ ],
60
+ writeEffectiveTaskPrompt: [
61
+ {
62
+ key: "promptOutputFile",
63
+ label: "Prompt output file",
64
+ inputType: "file-path",
65
+ required: true,
66
+ evidenceTarget: getStageActionEvidenceTarget(stage),
67
+ placeholder: "target-repo-task-...-handoff.md",
68
+ validationRule: "local-markdown-file-path",
69
+ minLength: 12,
70
+ example: "target-repo-task-accessibility-handoff.md",
71
+ validationHint: "Required: record the local Markdown prompt file path generated for the selected task.",
72
+ },
73
+ {
74
+ key: "selectedTaskId",
75
+ label: "Selected task id",
76
+ inputType: "text",
77
+ required: true,
78
+ evidenceTarget: getStageActionEvidenceTarget(stage),
79
+ placeholder: "task-...",
80
+ validationRule: "task-id",
81
+ minLength: 5,
82
+ example: "task-accessibility",
83
+ validationHint: "Required: record the bundle task id used for the target-repo handoff prompt.",
84
+ },
85
+ ],
86
+ executeInTargetRepo: [
87
+ {
88
+ key: "targetRepoChangedFiles",
89
+ label: "Target repo changed files",
90
+ inputType: "list",
91
+ required: true,
92
+ evidenceTarget: getStageActionEvidenceTarget(stage),
93
+ placeholder: "List changed files from the target website repo.",
94
+ validationRule: "non-empty-file-list",
95
+ minLength: 1,
96
+ example: "src/components/Header.tsx",
97
+ validationHint: "Required: list at least one changed target-repo file or a no-change justification.",
98
+ },
99
+ {
100
+ key: "targetRepoVerificationResults",
101
+ label: "Target repo verification results",
102
+ inputType: "textarea",
103
+ required: true,
104
+ evidenceTarget: getStageActionEvidenceTarget(stage),
105
+ placeholder: "Record lint, typecheck, build, test, or equivalent command results.",
106
+ validationRule: "verification-results",
107
+ minLength: 20,
108
+ example: "npm test: pass; npm run build: pass",
109
+ validationHint: "Required: record target-repo verification commands and results.",
110
+ },
111
+ {
112
+ key: "viewportAccessibilityNotes",
113
+ label: "Viewport and accessibility notes",
114
+ inputType: "textarea",
115
+ required: true,
116
+ evidenceTarget: getStageActionEvidenceTarget(stage),
117
+ placeholder: "Record desktop/tablet/mobile checks, keyboard focus, contrast, and screen-reader notes.",
118
+ validationRule: "viewport-accessibility-notes",
119
+ minLength: 20,
120
+ example: "desktop/tablet/mobile checked; focus visible; contrast AA",
121
+ validationHint: "Required: document viewport coverage plus keyboard, contrast, and screen-reader notes.",
122
+ },
123
+ ],
124
+ recordEvidence: [
125
+ {
126
+ key: "finalEvidenceRecord",
127
+ label: "Final evidence record",
128
+ inputType: "textarea",
129
+ required: true,
130
+ evidenceTarget: getStageActionEvidenceTarget(stage),
131
+ placeholder: "Summarize changed files, verification, viewport/accessibility checks, risks, and digest.",
132
+ validationRule: "final-evidence-record",
133
+ minLength: 30,
134
+ example: "Changed files recorded; verification passed; digest captured",
135
+ validationHint: "Required: summarize changes, verification, viewport/accessibility checks, risks, and digest.",
136
+ },
137
+ {
138
+ key: "remainingRisks",
139
+ label: "Remaining risks",
140
+ inputType: "textarea",
141
+ required: true,
142
+ evidenceTarget: getStageActionEvidenceTarget(stage),
143
+ placeholder: "List unresolved risks, skipped checks, or follow-up tasks.",
144
+ validationRule: "risk-notes",
145
+ minLength: 10,
146
+ example: "Stakeholder copy review still pending",
147
+ validationHint: "Required: record unresolved risks, skipped checks, or confirm none remain.",
148
+ },
149
+ ],
150
+ }[stage.key] || []).map((field) => ({
151
+ ...field,
152
+ valueShape: getEvidenceCaptureFieldValueShape(field),
153
+ acceptsMultiple: field.inputType === "list",
154
+ defaultValue: getEvidenceCaptureFieldEmptyValue(field),
155
+ emptyValue: getEvidenceCaptureFieldEmptyValue(field),
156
+ requirementLabel: getEvidenceCaptureFieldRequirementLabel(field),
157
+ ariaLabel: getEvidenceCaptureFieldAriaLabel(field),
158
+ helpText: getEvidenceCaptureFieldHelpText(field),
159
+ sectionKey: getEvidenceCaptureFieldSectionKey(field),
160
+ sectionLabel: getEvidenceCaptureFieldSectionLabel(field),
161
+ payloadNamespace: getEvidenceCaptureFieldPayloadNamespace(field),
162
+ payloadPath: getEvidenceCaptureFieldPayloadPath(field),
163
+ }));
164
+ }