@design-ai/cli 4.56.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 (264) hide show
  1. package/.claude-plugin/plugin.json +109 -25
  2. package/CHANGELOG.md +36 -0
  3. package/README.ko.md +9 -26
  4. package/README.md +10 -23
  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 +13 -3
  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-bundle-handoff-expected.mjs +173 -0
  48. package/cli/lib/site-bundle-handoff-runbook-action-summary.mjs +332 -0
  49. package/cli/lib/site-bundle-handoff-runbook-human-lines.mjs +167 -0
  50. package/cli/lib/site-bundle-handoff-runbook-maps.mjs +238 -0
  51. package/cli/lib/site-bundle-handoff-runbook-next-step.mjs +278 -0
  52. package/cli/lib/site-bundle-handoff-runbook.mjs +44 -931
  53. package/cli/lib/site-test-support.mjs +68 -0
  54. package/cli/lib/skill-proposals-apply-commands.mjs +135 -0
  55. package/cli/lib/skill-proposals-apply-contract.mjs +750 -0
  56. package/cli/lib/skill-proposals-apply-plan.mjs +118 -0
  57. package/cli/lib/skill-proposals-generate.mjs +298 -0
  58. package/cli/lib/skill-proposals-render.mjs +532 -0
  59. package/cli/lib/skill-proposals-review.mjs +262 -0
  60. package/cli/lib/skill-proposals.mjs +15 -2046
  61. package/cli/lib/workspace-args.mjs +83 -0
  62. package/cli/lib/workspace-git.mjs +169 -0
  63. package/cli/lib/workspace-learning.mjs +483 -0
  64. package/cli/lib/workspace-repo.mjs +139 -0
  65. package/cli/lib/workspace-report.mjs +283 -0
  66. package/cli/lib/workspace-test-support.mjs +99 -0
  67. package/cli/lib/workspace.mjs +30 -1056
  68. package/docs/AI-LEARNING-PHASE2.md +215 -0
  69. package/docs/DISTRIBUTION.ko.md +2 -2
  70. package/docs/DISTRIBUTION.md +2 -2
  71. package/docs/NEXT-SURFACE-DECISION.md +125 -0
  72. package/docs/PRODUCT-READINESS.md +3 -3
  73. package/docs/RELEASE-GATES.ko.md +35 -0
  74. package/docs/RELEASE-GATES.md +234 -0
  75. package/docs/ROADMAP.md +53 -8
  76. package/docs/external-status.md +6 -8
  77. package/docs/inspection-20260630.md +169 -0
  78. package/docs/integrations/design-ai-mcp-server.md +4 -4
  79. package/docs/reference/ant-design.md +413 -0
  80. package/docs/reference/awesome-design-md.md +439 -0
  81. package/docs/reference/mui.md +783 -0
  82. package/docs/reference/shadcn-ui.md +298 -0
  83. package/examples/component-accordion-actions.md +5 -5
  84. package/examples/component-accordion-details.md +5 -5
  85. package/examples/component-accordion-summary.md +5 -5
  86. package/examples/component-accordion.md +3 -3
  87. package/examples/component-affix.md +1 -1
  88. package/examples/component-alert-dialog.md +1 -1
  89. package/examples/component-alert-title.md +1 -1
  90. package/examples/component-alert.md +3 -3
  91. package/examples/component-anchor.md +1 -1
  92. package/examples/component-app-bar.md +1 -1
  93. package/examples/component-aspect-ratio.md +1 -1
  94. package/examples/component-auto-complete.md +2 -2
  95. package/examples/component-avatar-group.md +5 -5
  96. package/examples/component-avatar.md +3 -3
  97. package/examples/component-back-top.md +1 -1
  98. package/examples/component-backdrop.md +1 -1
  99. package/examples/component-badge.md +3 -3
  100. package/examples/component-border-beam.md +3 -3
  101. package/examples/component-bottom-navigation.md +1 -1
  102. package/examples/component-box.md +1 -1
  103. package/examples/component-breadcrumb.md +3 -3
  104. package/examples/component-button-base.md +3 -3
  105. package/examples/component-button-group.md +2 -2
  106. package/examples/component-button.md +3 -3
  107. package/examples/component-calendar.md +2 -2
  108. package/examples/component-card-actions.md +1 -1
  109. package/examples/component-card-content.md +1 -1
  110. package/examples/component-card-header.md +1 -1
  111. package/examples/component-card-media.md +1 -1
  112. package/examples/component-card.md +3 -3
  113. package/examples/component-carousel.md +2 -2
  114. package/examples/component-cascader.md +1 -1
  115. package/examples/component-chart.md +1 -1
  116. package/examples/component-checkbox.md +3 -3
  117. package/examples/component-click-away-listener.md +1 -1
  118. package/examples/component-code.md +1 -1
  119. package/examples/component-collapsible.md +1 -1
  120. package/examples/component-color-picker.md +1 -1
  121. package/examples/component-combobox.md +1 -1
  122. package/examples/component-command.md +1 -1
  123. package/examples/component-config-provider.md +3 -3
  124. package/examples/component-context-menu.md +1 -1
  125. package/examples/component-css-baseline.md +3 -3
  126. package/examples/component-date-picker.md +2 -2
  127. package/examples/component-descriptions.md +1 -1
  128. package/examples/component-dialog-actions.md +1 -1
  129. package/examples/component-dialog-content-text.md +1 -1
  130. package/examples/component-dialog-content.md +1 -1
  131. package/examples/component-dialog-title.md +1 -1
  132. package/examples/component-dialog.md +2 -2
  133. package/examples/component-divider.md +3 -3
  134. package/examples/component-drawer.md +3 -3
  135. package/examples/component-dropdown.md +3 -3
  136. package/examples/component-empty.md +2 -2
  137. package/examples/component-fade.md +1 -1
  138. package/examples/component-field.md +1 -1
  139. package/examples/component-filled-input.md +1 -1
  140. package/examples/component-flex.md +1 -1
  141. package/examples/component-float-button.md +2 -2
  142. package/examples/component-form-control-label.md +1 -1
  143. package/examples/component-form-control.md +1 -1
  144. package/examples/component-form-controls.md +1 -1
  145. package/examples/component-form-group.md +1 -1
  146. package/examples/component-form-helper-text.md +1 -1
  147. package/examples/component-form-label.md +1 -1
  148. package/examples/component-form.md +2 -2
  149. package/examples/component-grid.md +2 -2
  150. package/examples/component-grow.md +1 -1
  151. package/examples/component-hover-card.md +1 -1
  152. package/examples/component-icon-button.md +1 -1
  153. package/examples/component-icon.md +1 -1
  154. package/examples/component-image-list.md +1 -1
  155. package/examples/component-image.md +1 -1
  156. package/examples/component-input-adornment.md +1 -1
  157. package/examples/component-input-base.md +1 -1
  158. package/examples/component-input-number.md +1 -1
  159. package/examples/component-input-otp.md +2 -2
  160. package/examples/component-input.md +3 -3
  161. package/examples/component-item.md +1 -1
  162. package/examples/component-label.md +1 -1
  163. package/examples/component-layout.md +1 -1
  164. package/examples/component-link.md +1 -1
  165. package/examples/component-list-item-avatar.md +1 -1
  166. package/examples/component-list-item-button.md +1 -1
  167. package/examples/component-list-item-icon.md +1 -1
  168. package/examples/component-list-item-text.md +1 -1
  169. package/examples/component-list-item.md +1 -1
  170. package/examples/component-list-subheader.md +1 -1
  171. package/examples/component-list.md +2 -2
  172. package/examples/component-masonry.md +1 -1
  173. package/examples/component-mentions.md +1 -1
  174. package/examples/component-menu-item.md +1 -1
  175. package/examples/component-menu-list.md +1 -1
  176. package/examples/component-menu.md +1 -1
  177. package/examples/component-menubar.md +1 -1
  178. package/examples/component-message.md +1 -1
  179. package/examples/component-mobile-stepper.md +1 -1
  180. package/examples/component-modal.md +5 -5
  181. package/examples/component-navigation-menu.md +1 -1
  182. package/examples/component-notification.md +1 -1
  183. package/examples/component-outlined-input.md +1 -1
  184. package/examples/component-pagination.md +3 -3
  185. package/examples/component-paper.md +1 -1
  186. package/examples/component-popconfirm.md +1 -1
  187. package/examples/component-popover.md +3 -3
  188. package/examples/component-popper.md +1 -1
  189. package/examples/component-progress.md +2 -2
  190. package/examples/component-qr-code.md +1 -1
  191. package/examples/component-radio.md +3 -3
  192. package/examples/component-rate.md +2 -2
  193. package/examples/component-resizable.md +1 -1
  194. package/examples/component-result.md +1 -1
  195. package/examples/component-scroll-area.md +1 -1
  196. package/examples/component-segmented.md +3 -3
  197. package/examples/component-select.md +3 -3
  198. package/examples/component-separator.md +1 -1
  199. package/examples/component-sheet.md +1 -1
  200. package/examples/component-sidebar.md +1 -1
  201. package/examples/component-skeleton.md +3 -3
  202. package/examples/component-slide.md +1 -1
  203. package/examples/component-slider.md +3 -3
  204. package/examples/component-snackbar-content.md +1 -1
  205. package/examples/component-snackbar.md +1 -1
  206. package/examples/component-sonner.md +1 -1
  207. package/examples/component-space.md +1 -1
  208. package/examples/component-speed-dial-action.md +1 -1
  209. package/examples/component-speed-dial.md +1 -1
  210. package/examples/component-spin.md +2 -2
  211. package/examples/component-spinner.md +1 -1
  212. package/examples/component-splitter.md +2 -2
  213. package/examples/component-stack.md +1 -1
  214. package/examples/component-statistic.md +1 -1
  215. package/examples/component-step-button.md +4 -4
  216. package/examples/component-step-connector.md +4 -4
  217. package/examples/component-step-content.md +1 -1
  218. package/examples/component-step-icon.md +1 -1
  219. package/examples/component-step-label.md +1 -1
  220. package/examples/component-step.md +2 -2
  221. package/examples/component-steps.md +2 -2
  222. package/examples/component-swipeable-drawer.md +1 -1
  223. package/examples/component-switch.md +3 -3
  224. package/examples/component-tab-scroll-button.md +5 -5
  225. package/examples/component-tab.md +1 -1
  226. package/examples/component-table-body.md +1 -1
  227. package/examples/component-table-cell.md +1 -1
  228. package/examples/component-table-container.md +1 -1
  229. package/examples/component-table-footer.md +1 -1
  230. package/examples/component-table-head.md +1 -1
  231. package/examples/component-table-pagination.md +1 -1
  232. package/examples/component-table-row.md +1 -1
  233. package/examples/component-table-sort-label.md +1 -1
  234. package/examples/component-table.md +2 -2
  235. package/examples/component-tabs.md +3 -3
  236. package/examples/component-tag-badge.md +2 -2
  237. package/examples/component-tag.md +1 -1
  238. package/examples/component-textarea-autosize.md +1 -1
  239. package/examples/component-textarea.md +1 -1
  240. package/examples/component-time-picker.md +1 -1
  241. package/examples/component-timeline.md +1 -1
  242. package/examples/component-toast.md +4 -4
  243. package/examples/component-toggle-button.md +1 -1
  244. package/examples/component-toggle.md +1 -1
  245. package/examples/component-toolbar.md +1 -1
  246. package/examples/component-tooltip.md +3 -3
  247. package/examples/component-tour.md +1 -1
  248. package/examples/component-transfer.md +1 -1
  249. package/examples/component-tree-select.md +1 -1
  250. package/examples/component-tree.md +1 -1
  251. package/examples/component-typography.md +2 -2
  252. package/examples/component-upload.md +1 -1
  253. package/examples/component-watermark.md +1 -1
  254. package/examples/component-zoom.md +1 -1
  255. package/knowledge/COVERAGE.md +4 -3
  256. package/knowledge/components/INDEX.md +202 -202
  257. package/knowledge/patterns/brand-references.md +72 -72
  258. package/package.json +1 -1
  259. package/tools/audit/local-ci.py +16 -1
  260. package/tools/audit/package-smoke.py +611 -9
  261. package/tools/audit/registry-smoke.py +534 -0
  262. package/tools/audit/release-metadata.py +47 -1
  263. package/tools/audit/smoke_assertions.py +915 -13
  264. package/tools/migrations/refs-links-to-reference-pages.py +179 -0
@@ -0,0 +1,478 @@
1
+ // Markdown renderers for the learning signal registry and agent backlog reports.
2
+
3
+ import { summarizeAgentBacklogCommandEffects } from "./signals-backlog-commands.mjs";
4
+ import {
5
+ renderOptionalGapDetails,
6
+ renderReadinessCheckIndex,
7
+ } from "./signals-readiness.mjs";
8
+ import { listItem, yesNo } from "./signals-shared.mjs";
9
+
10
+ export function renderAgentBacklogReport(payload, {
11
+ generatedAt = new Date(),
12
+ } = {}) {
13
+ const generatedAtText = generatedAt instanceof Date ? generatedAt.toISOString() : String(generatedAt || "");
14
+ const counts = payload.counts || {};
15
+ const actions = Array.isArray(payload.actions) ? payload.actions : [];
16
+ const lines = [
17
+ "# Agent Development Backlog Report",
18
+ "",
19
+ listItem("Generated", generatedAtText),
20
+ listItem("Status", payload.status || "unknown"),
21
+ listItem("Signal status", payload.signalStatus || "unknown"),
22
+ listItem("Learning file", payload.file || ""),
23
+ listItem("Usage file", payload.usageFile || ""),
24
+ listItem("Signal source", payload.signalSource || ""),
25
+ "",
26
+ "## Summary",
27
+ "",
28
+ listItem("Actions", counts.actions ?? actions.length),
29
+ listItem("P0", counts.p0 ?? 0),
30
+ listItem("P1", counts.p1 ?? 0),
31
+ listItem("P2", counts.p2 ?? 0),
32
+ listItem("P3", counts.p3 ?? 0),
33
+ listItem("Learning entries", counts.learningEntries ?? 0),
34
+ listItem("Usage events", counts.usageEvents ?? 0),
35
+ listItem("Eval signals", counts.evalSignals ?? 0),
36
+ listItem("Check captures", counts.checkCaptures ?? 0),
37
+ listItem("Workspace next actions", counts.workspaceNextActions ?? 0),
38
+ ];
39
+
40
+ const readiness = payload.readiness && typeof payload.readiness === "object" ? payload.readiness : null;
41
+ if (readiness) {
42
+ lines.push(
43
+ "",
44
+ "## Signal Readiness",
45
+ "",
46
+ listItem("Status", readiness.status || payload.signalStatus || "unknown"),
47
+ listItem("Summary", readiness.summary || ""),
48
+ listItem("Required ready", yesNo(Boolean(readiness.requiredReady))),
49
+ listItem("Required checks", `${readiness.requiredPassCount ?? 0}/${readiness.requiredCount ?? 0}`),
50
+ listItem("Blocking checks", readiness.blockingCount ?? 0),
51
+ listItem("Optional gaps", readiness.optionalGapCount ?? 0),
52
+ );
53
+ const checks = Array.isArray(readiness.checks) ? readiness.checks : [];
54
+ renderReadinessCheckIndex(lines, readiness);
55
+ if (checks.length > 0) {
56
+ lines.push("", "Readiness checks:");
57
+ for (const check of checks) {
58
+ const required = check.required ? "required" : "optional";
59
+ lines.push(`- ${check.id || "unknown"} [${required}] ${check.status || "unknown"}: ${check.summary || ""}`);
60
+ }
61
+ }
62
+ renderOptionalGapDetails(lines, readiness);
63
+ }
64
+
65
+ lines.push("", "## Backlog Actions", "");
66
+
67
+ if (actions.length === 0) {
68
+ lines.push("No agent development backlog actions emitted.");
69
+ } else {
70
+ for (const action of actions) {
71
+ lines.push(`### ${action.rank}. ${action.title}`);
72
+ lines.push("");
73
+ lines.push(listItem("Id", action.id));
74
+ lines.push(listItem("Priority", action.priority));
75
+ lines.push(listItem("Category", action.category));
76
+ lines.push(listItem("Rationale", action.rationale));
77
+ if (action.command) {
78
+ lines.push("");
79
+ lines.push("Command:");
80
+ lines.push("");
81
+ lines.push("```bash");
82
+ lines.push(action.command);
83
+ lines.push("```");
84
+ }
85
+ const evidence = action.evidence && typeof action.evidence === "object" ? action.evidence : {};
86
+ const evidenceItems = Object.entries(evidence);
87
+ if (evidenceItems.length > 0) {
88
+ lines.push("");
89
+ lines.push("Evidence:");
90
+ for (const [key, value] of evidenceItems) {
91
+ const rendered = typeof value === "object" ? JSON.stringify(value) : String(value);
92
+ lines.push(`- ${key}: ${rendered}`);
93
+ }
94
+ }
95
+ lines.push("");
96
+ }
97
+ }
98
+
99
+ const actionPlan = payload.actionPlan || {};
100
+ const planSteps = Array.isArray(actionPlan.steps) ? actionPlan.steps : [];
101
+ lines.push("## Action Plan", "");
102
+ const safetySummary = actionPlan.safetySummary && typeof actionPlan.safetySummary === "object" ? actionPlan.safetySummary : null;
103
+ if (safetySummary) {
104
+ lines.push("Safety summary:");
105
+ lines.push(`- Read-only: ${safetySummary.readOnly ?? 0}`);
106
+ lines.push(`- Writes local file: ${safetySummary.writesLocalFile ?? 0}`);
107
+ lines.push(`- Mutates local state: ${safetySummary.mutatesLocalState ?? 0}`);
108
+ lines.push(`- Requires clean workspace: ${safetySummary.requiresCleanWorkspace ?? 0}`);
109
+ lines.push(`- Requires mutation review: ${safetySummary.requiresReviewBeforeMutation ?? 0}`);
110
+ lines.push("");
111
+ }
112
+ const executionQueue = actionPlan.executionQueue && typeof actionPlan.executionQueue === "object" ? actionPlan.executionQueue : null;
113
+ if (executionQueue) {
114
+ lines.push("Execution queue:");
115
+ lines.push(`- Preview/read-only commands: ${executionQueue.previewCount ?? 0}`);
116
+ lines.push(`- Local file-write review commands: ${executionQueue.fileWriteReviewCount ?? 0}`);
117
+ lines.push(`- Local mutation review commands: ${executionQueue.mutationReviewCount ?? 0}`);
118
+ lines.push(`- Ordered commands: ${executionQueue.orderedCount ?? 0}`);
119
+ lines.push(`- Command manifest entries: ${executionQueue.commandManifestCount ?? 0}`);
120
+ const commandEffectSummary = executionQueue.commandEffectSummary && typeof executionQueue.commandEffectSummary === "object"
121
+ ? executionQueue.commandEffectSummary
122
+ : null;
123
+ if (commandEffectSummary) {
124
+ lines.push(`- Command effect targets: output ${commandEffectSummary.outputTargetCount ?? 0}, profile ${commandEffectSummary.profileTargetCount ?? 0}, usage ${commandEffectSummary.usageTargetCount ?? 0}, mutation flags ${commandEffectSummary.mutationFlagCount ?? 0}`);
125
+ }
126
+ const commandEffectReview = executionQueue.commandEffectReview && typeof executionQueue.commandEffectReview === "object"
127
+ ? executionQueue.commandEffectReview
128
+ : null;
129
+ if (commandEffectReview?.headline) {
130
+ lines.push(`- Command effect review: ${commandEffectReview.headline}`);
131
+ const reviewChecklist = Array.isArray(commandEffectReview.checklist) ? commandEffectReview.checklist : [];
132
+ for (const item of reviewChecklist) {
133
+ lines.push(` - ${item}`);
134
+ }
135
+ const gatePhaseSummary = commandEffectReview.gatePhaseSummary && typeof commandEffectReview.gatePhaseSummary === "object"
136
+ ? commandEffectReview.gatePhaseSummary
137
+ : null;
138
+ if (gatePhaseSummary) {
139
+ const phases = Array.isArray(gatePhaseSummary.phases) && gatePhaseSummary.phases.length > 0
140
+ ? gatePhaseSummary.phases.join(", ")
141
+ : "none";
142
+ lines.push(`- Command effect gate phases: ${phases} (${gatePhaseSummary.requiredCount ?? 0}/${gatePhaseSummary.count ?? 0} required)`);
143
+ }
144
+ const gateRunbook = commandEffectReview.gateRunbook && typeof commandEffectReview.gateRunbook === "object"
145
+ ? commandEffectReview.gateRunbook
146
+ : null;
147
+ if (gateRunbook) {
148
+ lines.push(`- Command effect gate runbook: before ${Array.isArray(gateRunbook.before) ? gateRunbook.before.length : 0}, after ${Array.isArray(gateRunbook.after) ? gateRunbook.after.length : 0}, refresh ${Array.isArray(gateRunbook.refresh) ? gateRunbook.refresh.length : 0}`);
149
+ }
150
+ const gateCommands = Array.isArray(commandEffectReview.gateCommands) ? commandEffectReview.gateCommands : [];
151
+ if (gateCommands.length > 0) {
152
+ lines.push("- Command effect gates:");
153
+ for (const item of gateCommands) {
154
+ const phase = item.phase ? `${item.phase}: ` : "";
155
+ lines.push(` - ${phase}${item.label || "Review gate"}: \`${item.command || ""}\``);
156
+ }
157
+ }
158
+ }
159
+ const operatorRunbook = executionQueue.operatorRunbook && typeof executionQueue.operatorRunbook === "object"
160
+ ? executionQueue.operatorRunbook
161
+ : null;
162
+ if (operatorRunbook) {
163
+ lines.push(`- Operator runbook: ${operatorRunbook.stageCount ?? 0} stage(s), ${operatorRunbook.commandCount ?? 0} command(s), ${operatorRunbook.requiredCommandCount ?? 0} required`);
164
+ if (operatorRunbook.nextCommand) {
165
+ lines.push(`- Operator next command: ${operatorRunbook.nextStage || "unknown"}: \`${operatorRunbook.nextCommand}\``);
166
+ }
167
+ const operatorSelection = operatorRunbook.nextCommandSelection && typeof operatorRunbook.nextCommandSelection === "object"
168
+ ? operatorRunbook.nextCommandSelection
169
+ : null;
170
+ if (operatorSelection) {
171
+ lines.push(`- Operator next command selection: ${operatorSelection.strategy || "unknown"} (${operatorSelection.reason || "no reason provided"})`);
172
+ }
173
+ }
174
+ if (executionQueue.nextActionId) lines.push(`- Recommended next action: ${executionQueue.nextActionId}`);
175
+ if (executionQueue.nextCommandRunPolicy) lines.push(`- Recommended next command policy: ${executionQueue.nextCommandRunPolicy}`);
176
+ const nextCommandSelection = executionQueue.nextCommandSelection && typeof executionQueue.nextCommandSelection === "object"
177
+ ? executionQueue.nextCommandSelection
178
+ : null;
179
+ if (nextCommandSelection) {
180
+ lines.push(`- Recommended next command selection: ${nextCommandSelection.strategy || "unknown"} (${nextCommandSelection.reason || "no reason provided"})`);
181
+ if (nextCommandSelection.planNextActionId) {
182
+ lines.push(`- Ranked next action: ${nextCommandSelection.planNextActionId}; matches recommended command: ${nextCommandSelection.matchesPlanNextAction ? "yes" : "no"}`);
183
+ }
184
+ }
185
+ const nextCommandAlignment = executionQueue.nextCommandAlignment && typeof executionQueue.nextCommandAlignment === "object"
186
+ ? executionQueue.nextCommandAlignment
187
+ : null;
188
+ if (nextCommandAlignment) {
189
+ lines.push(`- Operator/queue next command alignment: ${nextCommandAlignment.matchesQueueNextCommand ? "same" : "different"} (${nextCommandAlignment.reason || "no reason provided"})`);
190
+ }
191
+ const operatorHandoff = executionQueue.operatorHandoff && typeof executionQueue.operatorHandoff === "object"
192
+ ? executionQueue.operatorHandoff
193
+ : null;
194
+ if (operatorHandoff) {
195
+ const phase = operatorHandoff.phase ? `${operatorHandoff.phase} ` : "";
196
+ const decision = operatorHandoff.decision ? `${operatorHandoff.decision}; ` : "";
197
+ lines.push(`- Operator handoff: ${phase}${operatorHandoff.source || "unknown"} (${decision}${operatorHandoff.reason || "no reason provided"})`);
198
+ const handoffState = operatorHandoff.state && typeof operatorHandoff.state === "object" ? operatorHandoff.state : null;
199
+ if (handoffState) {
200
+ lines.push(`- Operator handoff state: ${handoffState.status || "unknown"}; ready ${handoffState.ready ? "yes" : "no"}; can run without review ${handoffState.canRunWithoutReview ? "yes" : "no"}; refresh ${handoffState.requiresRefresh ? "required" : "optional"}`);
201
+ if (handoffState.summary) {
202
+ lines.push(`- Operator handoff summary: ${handoffState.summary}`);
203
+ }
204
+ }
205
+ if (operatorHandoff.refreshCommand) {
206
+ lines.push(`- Operator handoff refresh: ${operatorHandoff.refreshCommand}`);
207
+ }
208
+ }
209
+ if (executionQueue.nextCommand) {
210
+ lines.push("");
211
+ lines.push("Recommended next command:");
212
+ lines.push("");
213
+ lines.push("```bash");
214
+ lines.push(executionQueue.nextCommand);
215
+ lines.push("```");
216
+ }
217
+ const orderedItems = Array.isArray(executionQueue.ordered) ? executionQueue.ordered : [];
218
+ if (orderedItems.length > 0) {
219
+ lines.push("");
220
+ lines.push("Queue order:");
221
+ for (const item of orderedItems) {
222
+ lines.push(`${item.rank}. ${item.actionId || "unknown-action"} (${item.safetyLevel || "unknown"}, ${item.runPolicy || "manual-review"})`);
223
+ }
224
+ }
225
+ const commandManifest = Array.isArray(executionQueue.commandManifest) ? executionQueue.commandManifest : [];
226
+ if (commandManifest.length > 0) {
227
+ lines.push("");
228
+ lines.push("Command manifest:");
229
+ for (const item of commandManifest) {
230
+ lines.push(`${item.rank}. ${item.actionId || "unknown-action"} - ${item.runPolicy || "manual-review"} (${summarizeAgentBacklogCommandEffects(item.commandEffects)})`);
231
+ }
232
+ }
233
+ lines.push("");
234
+ }
235
+ if (planSteps.length === 0) {
236
+ lines.push("No execution steps emitted.");
237
+ } else {
238
+ for (const step of planSteps) {
239
+ lines.push(`### Step ${step.rank}. ${step.title}`);
240
+ lines.push("");
241
+ lines.push(listItem("Action id", step.actionId));
242
+ lines.push(listItem("Priority", step.priority));
243
+ lines.push(listItem("Category", step.category));
244
+ const commandSafety = step.commandSafety && typeof step.commandSafety === "object" ? step.commandSafety : {};
245
+ lines.push(listItem("Command safety", commandSafety.level || "unknown"));
246
+ lines.push(listItem("Writes local files", yesNo(Boolean(commandSafety.writesLocalFiles))));
247
+ lines.push(listItem("Mutates local state", yesNo(Boolean(commandSafety.mutatesLocalState))));
248
+ lines.push(listItem("Requires mutation review", yesNo(Boolean(step.requiresReviewBeforeMutation))));
249
+ if (commandSafety.reason) lines.push(listItem("Safety reason", commandSafety.reason));
250
+ if (step.expectedOutcome) lines.push(listItem("Expected outcome", step.expectedOutcome));
251
+ if (step.command) {
252
+ lines.push("");
253
+ lines.push("Command:");
254
+ lines.push("");
255
+ lines.push("```bash");
256
+ lines.push(step.command);
257
+ lines.push("```");
258
+ }
259
+ if (step.applyCommand) {
260
+ const applySafety = step.applyCommandSafety && typeof step.applyCommandSafety === "object" ? step.applyCommandSafety : {};
261
+ lines.push("");
262
+ lines.push("Apply command after review:");
263
+ lines.push("");
264
+ lines.push("```bash");
265
+ lines.push(step.applyCommand);
266
+ lines.push("```");
267
+ lines.push(listItem("Apply command safety", applySafety.level || "unknown"));
268
+ lines.push(listItem("Apply requires mutation review", yesNo(Boolean(step.applyRequiresReviewBeforeMutation))));
269
+ }
270
+ const verification = Array.isArray(step.verification) ? step.verification : [];
271
+ if (verification.length > 0) {
272
+ lines.push("");
273
+ lines.push("Verification:");
274
+ for (const item of verification) {
275
+ lines.push(`- ${item}`);
276
+ }
277
+ }
278
+ lines.push("");
279
+ }
280
+ }
281
+
282
+ const recommendations = Array.isArray(payload.recommendations) ? payload.recommendations : [];
283
+ lines.push("## Recommendations", "");
284
+ if (recommendations.length === 0) {
285
+ lines.push("No recommendations emitted.");
286
+ } else {
287
+ for (const recommendation of recommendations) {
288
+ lines.push(`- ${recommendation.level}: ${recommendation.text}`);
289
+ }
290
+ }
291
+
292
+ const commands = payload.commands || {};
293
+ lines.push("", "## Follow-Up Commands", "");
294
+ if (commands.signalsJson) {
295
+ lines.push("Signal registry JSON:");
296
+ lines.push("");
297
+ lines.push("```bash");
298
+ lines.push(commands.signalsJson);
299
+ lines.push("```");
300
+ lines.push("");
301
+ }
302
+ if (commands.signalsReport) {
303
+ lines.push("Signal registry Markdown:");
304
+ lines.push("");
305
+ lines.push("```bash");
306
+ lines.push(commands.signalsReport);
307
+ lines.push("```");
308
+ lines.push("");
309
+ }
310
+
311
+ const privacy = payload.privacy || {};
312
+ lines.push("## Privacy And Boundaries", "");
313
+ lines.push(listItem("Mutates learning profile", yesNo(Boolean(privacy.mutatesProfile))));
314
+ lines.push(listItem("Mutates skill files", yesNo(Boolean(privacy.mutatesSkillFiles))));
315
+ lines.push(listItem("Calls external AI APIs", yesNo(Boolean(privacy.callsExternalAiApis))));
316
+ lines.push(listItem("Stores raw brief text", yesNo(Boolean(privacy.storesRawBriefText))));
317
+ lines.push(listItem("Reads signal files only", yesNo(Boolean(privacy.readsSignalFilesOnly))));
318
+ lines.push("", "This report is read-only evidence; it does not mutate learning profiles, usage sidecars, eval files, skill files, or target repositories.");
319
+
320
+ return `${lines.join("\n")}\n`;
321
+ }
322
+
323
+ export function renderLearningSignalReport(payload, {
324
+ generatedAt = new Date(),
325
+ } = {}) {
326
+ const generatedAtText = generatedAt instanceof Date ? generatedAt.toISOString() : String(generatedAt || "");
327
+ const learning = payload.learning || {};
328
+ const usage = payload.usage || {};
329
+ const evals = payload.evals || {};
330
+ const workspace = payload.workspace || {};
331
+ const agentDevelopment = payload.agentDevelopment || {};
332
+ const readiness = payload.readiness || {};
333
+ const lines = [
334
+ "# Learning Signal Registry Report",
335
+ "",
336
+ listItem("Generated", generatedAtText),
337
+ listItem("Status", payload.status || "unknown"),
338
+ listItem("Learning file", payload.file || ""),
339
+ listItem("Signal source", payload.signalSource || ""),
340
+ "",
341
+ "## Readiness Summary",
342
+ "",
343
+ listItem("Status", readiness.status || payload.status || "unknown"),
344
+ listItem("Summary", readiness.summary || ""),
345
+ listItem("Required ready", yesNo(Boolean(readiness.requiredReady))),
346
+ listItem("Required checks", `${readiness.requiredPassCount ?? 0}/${readiness.requiredCount ?? 0}`),
347
+ listItem("Blocking checks", readiness.blockingCount ?? 0),
348
+ listItem("Optional gaps", readiness.optionalGapCount ?? 0),
349
+ ];
350
+
351
+ const readinessChecks = Array.isArray(readiness.checks) ? readiness.checks : [];
352
+ renderReadinessCheckIndex(lines, readiness);
353
+ if (readinessChecks.length > 0) {
354
+ lines.push("", "Readiness checks:");
355
+ for (const check of readinessChecks) {
356
+ const required = check.required ? "required" : "optional";
357
+ lines.push(`- ${check.id || "unknown"} [${required}] ${check.status || "unknown"}: ${check.summary || ""}`);
358
+ }
359
+ }
360
+ renderOptionalGapDetails(lines, readiness);
361
+
362
+ lines.push(
363
+ "",
364
+ "## Learning Profile",
365
+ "",
366
+ listItem("Exists", yesNo(Boolean(learning.exists))),
367
+ listItem("Version", learning.version ?? ""),
368
+ listItem("Updated at", learning.updatedAt || ""),
369
+ listItem("Entries", learning.count ?? 0),
370
+ listItem("Audit status", learning.auditSummary?.status || "unknown"),
371
+ listItem("Audit failures", learning.auditSummary?.failures ?? 0),
372
+ listItem("Audit warnings", learning.auditSummary?.warnings ?? 0),
373
+ "",
374
+ "## Usage Signals",
375
+ "",
376
+ listItem("Usage file", usage.usageFile || ""),
377
+ listItem("Exists", yesNo(Boolean(usage.exists))),
378
+ listItem("Events", usage.eventCount ?? 0),
379
+ listItem("Used entries", usage.usedEntryCount ?? 0),
380
+ listItem("Unused entries", usage.unusedEntryCount ?? 0),
381
+ listItem("Stale selected ids", usage.staleSelectedEntryCount ?? 0),
382
+ listItem("Stores raw brief text", yesNo(Boolean(usage.privacy?.storesRawBriefText))),
383
+ "",
384
+ "## Eval Signals",
385
+ "",
386
+ listItem("Source", evals.source || ""),
387
+ listItem("Files", evals.count ?? 0),
388
+ listItem("Reports", evals.reports ?? 0),
389
+ listItem("Templates", evals.templates ?? 0),
390
+ listItem("Passed", evals.passed ?? 0),
391
+ listItem("Warned", evals.warned ?? 0),
392
+ listItem("Failed", evals.failed ?? 0),
393
+ );
394
+
395
+ const evalFiles = Array.isArray(evals.files) ? evals.files : [];
396
+ if (evalFiles.length > 0) {
397
+ lines.push("", "Eval files:");
398
+ for (const item of evalFiles) {
399
+ const counts = item.shape === "report"
400
+ ? ` pass ${item.passed} / warn ${item.warned} / fail ${item.failed}`
401
+ : `${item.caseCount} case(s)`;
402
+ lines.push(`- \`${item.file}\`: ${item.kind} ${item.shape} ${item.status} (${counts})`);
403
+ if (item.error) lines.push(` - ${item.error}`);
404
+ }
405
+ }
406
+
407
+ const latestCaptures = Array.isArray(payload.checkCapture?.latestEntries)
408
+ ? payload.checkCapture.latestEntries
409
+ : [];
410
+ lines.push("", "## Check Capture", "");
411
+ lines.push(listItem("Entries", payload.checkCapture?.count ?? 0));
412
+ if (latestCaptures.length > 0) {
413
+ lines.push("", "Recent captures:");
414
+ for (const entry of latestCaptures) {
415
+ lines.push(`- \`${entry.id}\` [${entry.category}] ${entry.source}`);
416
+ if (entry.textPreview) lines.push(` - ${entry.textPreview}`);
417
+ }
418
+ }
419
+
420
+ lines.push("", "## Workspace Readiness", "");
421
+ lines.push(listItem("Root", workspace.root || ""));
422
+ lines.push(listItem("Branch", workspace.git?.branch || "unknown"));
423
+ lines.push(listItem("Clean", yesNo(Boolean(workspace.git?.clean))));
424
+ lines.push(listItem("Repository status", workspace.repository?.status || "unknown"));
425
+ lines.push(listItem("Learning status", workspace.learning?.status || "unknown"));
426
+ lines.push(listItem("Usage status", workspace.learningUsage?.status || "unknown"));
427
+ lines.push(listItem("Eval status", workspace.learningEval?.status || "not checked"));
428
+ lines.push(listItem("Next actions", workspace.nextActionCount ?? 0));
429
+
430
+ const actions = Array.isArray(agentDevelopment.actions) ? agentDevelopment.actions : [];
431
+ lines.push("", "## Agent Development Backlog", "");
432
+ lines.push(listItem("Status", agentDevelopment.status || "unknown"));
433
+ lines.push(listItem("Actions", agentDevelopment.actionCount ?? actions.length));
434
+ lines.push(listItem("P0", agentDevelopment.p0Count ?? 0));
435
+ lines.push(listItem("P1", agentDevelopment.p1Count ?? 0));
436
+ lines.push(listItem("P2", agentDevelopment.p2Count ?? 0));
437
+ lines.push(listItem("P3", agentDevelopment.p3Count ?? 0));
438
+ if (actions.length > 0) {
439
+ lines.push("");
440
+ for (const action of actions) {
441
+ lines.push(`### ${action.rank}. ${action.title}`);
442
+ lines.push("");
443
+ lines.push(listItem("Id", action.id));
444
+ lines.push(listItem("Priority", action.priority));
445
+ lines.push(listItem("Category", action.category));
446
+ lines.push(listItem("Rationale", action.rationale));
447
+ if (action.command) {
448
+ lines.push("");
449
+ lines.push("Command:");
450
+ lines.push("");
451
+ lines.push("```bash");
452
+ lines.push(action.command);
453
+ lines.push("```");
454
+ }
455
+ lines.push("");
456
+ }
457
+ }
458
+
459
+ const recommendations = Array.isArray(payload.recommendations) ? payload.recommendations : [];
460
+ lines.push("## Recommendations", "");
461
+ if (recommendations.length === 0) {
462
+ lines.push("No recommendations emitted.");
463
+ } else {
464
+ for (const recommendation of recommendations) {
465
+ lines.push(`- ${recommendation.level}: ${recommendation.text}`);
466
+ }
467
+ }
468
+
469
+ const privacy = payload.privacy || {};
470
+ lines.push("", "## Privacy And Boundaries", "");
471
+ lines.push(listItem("Mutates learning profile", yesNo(Boolean(privacy.mutatesProfile))));
472
+ lines.push(listItem("Stores raw brief text", yesNo(Boolean(privacy.storesRawBriefText))));
473
+ lines.push(listItem("Reads signal files only", yesNo(Boolean(privacy.readsSignalFilesOnly))));
474
+ lines.push(listItem("External AI APIs", "no"));
475
+ lines.push("", "This report is read-only evidence; it does not mutate learning profiles, usage sidecars, eval files, skill files, or target repositories.");
476
+
477
+ return `${lines.join("\n")}\n`;
478
+ }
@@ -0,0 +1,75 @@
1
+ // Generic status/command/formatting helpers shared by the signals-* modules.
2
+
3
+ export function countBy(items, keyFn) {
4
+ const counts = {};
5
+ for (const item of items || []) {
6
+ const key = keyFn(item);
7
+ if (!key) continue;
8
+ counts[key] = (counts[key] || 0) + 1;
9
+ }
10
+ return counts;
11
+ }
12
+
13
+ export function readinessCountByStatus(items = []) {
14
+ const counts = {
15
+ pass: 0,
16
+ info: 0,
17
+ warn: 0,
18
+ fail: 0,
19
+ missing: 0,
20
+ template: 0,
21
+ unknown: 0,
22
+ };
23
+ for (const item of items || []) {
24
+ const status = String(item?.status || "unknown").trim() || "unknown";
25
+ if (Object.hasOwn(counts, status)) {
26
+ counts[status] += 1;
27
+ } else {
28
+ counts.unknown += 1;
29
+ }
30
+ }
31
+ return counts;
32
+ }
33
+
34
+ export function previewText(text, maxLength = 120) {
35
+ const normalized = String(text || "").replace(/\s+/g, " ").trim();
36
+ if (normalized.length <= maxLength) return normalized;
37
+ return `${normalized.slice(0, maxLength - 1)}...`;
38
+ }
39
+
40
+ export function statusRank(status) {
41
+ if (status === "fail") return 3;
42
+ if (status === "warn" || status === "missing") return 2;
43
+ if (status === "template" || status === "unknown") return 1;
44
+ return 0;
45
+ }
46
+
47
+ export function worstStatus(statuses, fallback = "pass") {
48
+ return [...statuses].sort((a, b) => statusRank(b) - statusRank(a))[0] || fallback;
49
+ }
50
+
51
+ export function shellQuote(value) {
52
+ const text = String(value || "");
53
+ if (/^[A-Za-z0-9_./:=@+-]+$/.test(text)) return text;
54
+ return `'${text.replace(/'/g, "'\\''")}'`;
55
+ }
56
+
57
+ export function commandFromArgs(args = []) {
58
+ return args.map(shellQuote).join(" ");
59
+ }
60
+
61
+ export function commandSpec(args = []) {
62
+ const commandArgs = args.map((item) => String(item));
63
+ return {
64
+ commandArgs,
65
+ command: commandFromArgs(commandArgs),
66
+ };
67
+ }
68
+
69
+ export function yesNo(value) {
70
+ return value ? "yes" : "no";
71
+ }
72
+
73
+ export function listItem(label, value) {
74
+ return `- ${label}: ${value}`;
75
+ }