@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,247 @@
1
+ // Learning signal readiness checks and readiness report rendering helpers.
2
+
3
+ import { readinessCountByStatus, statusRank, yesNo } from "./signals-shared.mjs";
4
+
5
+ export function optionalGapDetail(check = {}) {
6
+ if (check.id === "check-capture") {
7
+ return {
8
+ id: check.id,
9
+ label: check.label || "Check learning capture",
10
+ status: check.status || "info",
11
+ summary: check.summary || "",
12
+ reason: "No real warn/fail check result has been intentionally captured into the local learning profile yet.",
13
+ nextCondition: "Run `design-ai check <artifact.md> --learn --yes` only after reviewing an actual warning or failure that should improve future outputs.",
14
+ automationPolicy: "Do not emit placeholder mutation commands for this advisory gap; wait for real check evidence.",
15
+ };
16
+ }
17
+
18
+ return {
19
+ id: check.id || "unknown",
20
+ label: check.label || "Optional readiness check",
21
+ status: check.status || "info",
22
+ summary: check.summary || "",
23
+ reason: "Optional evidence is incomplete.",
24
+ nextCondition: "Collect real local evidence before treating this optional signal as complete.",
25
+ automationPolicy: "Keep this advisory unless a future required gate explicitly depends on it.",
26
+ };
27
+ }
28
+
29
+ export function renderOptionalGapDetails(lines, readiness = {}) {
30
+ const details = Array.isArray(readiness.optionalGapDetails) ? readiness.optionalGapDetails : [];
31
+ if (details.length === 0) return;
32
+ lines.push("", "Optional gap details:");
33
+ for (const detail of details) {
34
+ lines.push(`- ${detail.id || "unknown"}: ${detail.reason || detail.summary || ""}`);
35
+ if (detail.nextCondition) lines.push(` Next condition: ${detail.nextCondition}`);
36
+ if (detail.automationPolicy) lines.push(` Automation policy: ${detail.automationPolicy}`);
37
+ }
38
+ }
39
+
40
+ export function renderReadinessCheckIndex(lines, readiness = {}) {
41
+ const requiredIds = Array.isArray(readiness.requiredCheckIds) ? readiness.requiredCheckIds : [];
42
+ const optionalIds = Array.isArray(readiness.optionalCheckIds) ? readiness.optionalCheckIds : [];
43
+ const statusById = readiness.checkStatusById && typeof readiness.checkStatusById === "object"
44
+ ? readiness.checkStatusById
45
+ : {};
46
+ const requiredById = readiness.checkRequiredById && typeof readiness.checkRequiredById === "object"
47
+ ? readiness.checkRequiredById
48
+ : {};
49
+ const checks = Array.isArray(readiness.checks) ? readiness.checks : [];
50
+ const indexIds = [...new Set([
51
+ ...checks.map((item) => item?.id).filter(Boolean),
52
+ ...requiredIds,
53
+ ...optionalIds,
54
+ ...Object.keys(statusById),
55
+ ...Object.keys(requiredById),
56
+ ])];
57
+ if (indexIds.length === 0) return;
58
+
59
+ lines.push("", "Readiness check index:");
60
+ lines.push(`- Required ids: ${requiredIds.length > 0 ? requiredIds.join(", ") : "none"}`);
61
+ lines.push(`- Optional ids: ${optionalIds.length > 0 ? optionalIds.join(", ") : "none"}`);
62
+ lines.push(`- Status index: ${indexIds.map((id) => `${id}=${statusById[id] || "unknown"}`).join(", ")}`);
63
+ lines.push(`- Required index: ${indexIds.map((id) => `${id}=${yesNo(Boolean(requiredById[id]))}`).join(", ")}`);
64
+ if (readiness.checkCountByStatus && typeof readiness.checkCountByStatus === "object") {
65
+ const formatCounts = (counts = {}) => ["pass", "info", "warn", "fail", "missing", "template", "unknown"]
66
+ .map((key) => `${key}=${counts[key] ?? 0}`)
67
+ .join(", ");
68
+ lines.push(`- Status counts: ${formatCounts(readiness.checkCountByStatus)}`);
69
+ lines.push(`- Required status counts: ${formatCounts(readiness.requiredCheckCountByStatus)}`);
70
+ lines.push(`- Optional status counts: ${formatCounts(readiness.optionalCheckCountByStatus)}`);
71
+ }
72
+ }
73
+ export function signalCheck({
74
+ id,
75
+ label,
76
+ status,
77
+ required,
78
+ summary,
79
+ evidence = {},
80
+ }) {
81
+ return {
82
+ id,
83
+ label,
84
+ status,
85
+ required: Boolean(required),
86
+ summary,
87
+ evidence,
88
+ };
89
+ }
90
+
91
+ export function buildLearningSignalReadiness({
92
+ audit,
93
+ usage,
94
+ evals,
95
+ checkCapture,
96
+ workspace,
97
+ agentDevelopment,
98
+ status,
99
+ }) {
100
+ const profileStatus = !audit.exists
101
+ ? "missing"
102
+ : audit.summary.failures > 0
103
+ ? "fail"
104
+ : audit.summary.warnings > 0
105
+ ? "warn"
106
+ : "pass";
107
+ const usageStatus = usage.staleSelectedEntryCount > 0
108
+ ? "warn"
109
+ : usage.exists && usage.eventCount > 0
110
+ ? "pass"
111
+ : "info";
112
+ const evalStatus = evals.failed > 0
113
+ ? "fail"
114
+ : evals.warned > 0 || evals.templates > 0 || evals.count === 0
115
+ ? "warn"
116
+ : "pass";
117
+ const checkCaptureStatus = checkCapture.count > 0 ? "pass" : "info";
118
+ const workspaceStatus = workspace.nextActionCounts.fail > 0
119
+ ? "fail"
120
+ : workspace.nextActionCounts.warn > 0
121
+ ? "warn"
122
+ : "pass";
123
+ const agentStatus = agentDevelopment.status || "unknown";
124
+ const checks = [
125
+ signalCheck({
126
+ id: "learning-profile",
127
+ label: "Learning profile",
128
+ status: profileStatus,
129
+ required: true,
130
+ summary: audit.exists
131
+ ? `Profile has ${audit.count} entries with ${audit.summary.failures} audit failure(s) and ${audit.summary.warnings} warning(s).`
132
+ : "Learning profile is missing.",
133
+ evidence: {
134
+ exists: Boolean(audit.exists),
135
+ entries: audit.count,
136
+ failures: audit.summary.failures,
137
+ warnings: audit.summary.warnings,
138
+ },
139
+ }),
140
+ signalCheck({
141
+ id: "usage-sidecar",
142
+ label: "Usage sidecar",
143
+ status: usageStatus,
144
+ required: false,
145
+ summary: usage.exists && usage.eventCount > 0
146
+ ? `Usage sidecar has ${usage.eventCount} event(s) and ${usage.staleSelectedEntryCount} stale selected id(s).`
147
+ : "Usage sidecar has no prompt/pack usage events yet.",
148
+ evidence: {
149
+ exists: Boolean(usage.exists),
150
+ events: usage.eventCount,
151
+ staleSelectedEntryCount: usage.staleSelectedEntryCount,
152
+ },
153
+ }),
154
+ signalCheck({
155
+ id: "eval-signals",
156
+ label: "Eval signals",
157
+ status: evalStatus,
158
+ required: true,
159
+ summary: evals.count > 0
160
+ ? `Eval signals include ${evals.reports} report(s), ${evals.templates} unresolved template(s), ${evals.failed} failed report(s), and ${evals.warned} warned report(s).`
161
+ : "No route, prompt, pack, or learning eval signal files were found.",
162
+ evidence: {
163
+ files: evals.count,
164
+ reports: evals.reports,
165
+ templates: evals.templates,
166
+ failed: evals.failed,
167
+ warned: evals.warned,
168
+ },
169
+ }),
170
+ signalCheck({
171
+ id: "check-capture",
172
+ label: "Check learning capture",
173
+ status: checkCaptureStatus,
174
+ required: false,
175
+ summary: checkCapture.count > 0
176
+ ? `Profile includes ${checkCapture.count} check-capture learning entr${checkCapture.count === 1 ? "y" : "ies"}.`
177
+ : "No check-capture entries are present; this is advisory until real warn/fail checks are captured.",
178
+ evidence: {
179
+ entries: checkCapture.count,
180
+ categoryCounts: checkCapture.categoryCounts,
181
+ },
182
+ }),
183
+ signalCheck({
184
+ id: "workspace-readiness",
185
+ label: "Workspace readiness",
186
+ status: workspaceStatus,
187
+ required: true,
188
+ summary: `Workspace has ${workspace.nextActionCounts.fail || 0} fail action(s), ${workspace.nextActionCounts.warn || 0} warn action(s), and ${workspace.nextActionCount || 0} total next action(s).`,
189
+ evidence: {
190
+ fail: workspace.nextActionCounts.fail || 0,
191
+ warn: workspace.nextActionCounts.warn || 0,
192
+ nextActionCount: workspace.nextActionCount || 0,
193
+ },
194
+ }),
195
+ signalCheck({
196
+ id: "agent-development",
197
+ label: "Agent development backlog",
198
+ status: agentStatus,
199
+ required: true,
200
+ summary: `Agent backlog has ${agentDevelopment.actionCount || 0} action(s): ${agentDevelopment.p0Count || 0} P0, ${agentDevelopment.p1Count || 0} P1, ${agentDevelopment.p2Count || 0} P2, ${agentDevelopment.p3Count || 0} P3.`,
201
+ evidence: {
202
+ actions: agentDevelopment.actionCount || 0,
203
+ p0: agentDevelopment.p0Count || 0,
204
+ p1: agentDevelopment.p1Count || 0,
205
+ p2: agentDevelopment.p2Count || 0,
206
+ p3: agentDevelopment.p3Count || 0,
207
+ },
208
+ }),
209
+ ];
210
+ const requiredChecks = checks.filter((item) => item.required);
211
+ const optionalChecks = checks.filter((item) => !item.required);
212
+ const blockingChecks = requiredChecks.filter((item) => statusRank(item.status) >= statusRank("warn"));
213
+ const optionalGaps = optionalChecks.filter((item) => item.status !== "pass");
214
+ const requiredPassCount = requiredChecks.filter((item) => item.status === "pass").length;
215
+ const checkStatusById = Object.fromEntries(checks.map((item) => [item.id, item.status]));
216
+ const checkRequiredById = Object.fromEntries(checks.map((item) => [item.id, Boolean(item.required)]));
217
+ const checkCountByStatus = readinessCountByStatus(checks);
218
+ const requiredCheckCountByStatus = readinessCountByStatus(requiredChecks);
219
+ const optionalCheckCountByStatus = readinessCountByStatus(optionalChecks);
220
+ const summary = blockingChecks.length === 0
221
+ ? optionalGaps.length === 0
222
+ ? "Required and optional local learning signal surfaces are complete."
223
+ : "Required local learning signal surfaces are ready; optional evidence gaps remain."
224
+ : "Required local learning signal surfaces need review before this can be used as a gate.";
225
+
226
+ return {
227
+ version: 1,
228
+ status,
229
+ summary,
230
+ requiredPassCount,
231
+ requiredCount: requiredChecks.length,
232
+ requiredReady: blockingChecks.length === 0,
233
+ blockingCount: blockingChecks.length,
234
+ optionalGapCount: optionalGaps.length,
235
+ blockingChecks: blockingChecks.map((item) => item.id),
236
+ optionalGaps: optionalGaps.map((item) => item.id),
237
+ optionalGapDetails: optionalGaps.map(optionalGapDetail),
238
+ requiredCheckIds: requiredChecks.map((item) => item.id),
239
+ optionalCheckIds: optionalChecks.map((item) => item.id),
240
+ checkStatusById,
241
+ checkRequiredById,
242
+ checkCountByStatus,
243
+ requiredCheckCountByStatus,
244
+ optionalCheckCountByStatus,
245
+ checks,
246
+ };
247
+ }
@@ -0,0 +1,377 @@
1
+ // Read-only learning signal registry and agent backlog report payload builders.
2
+
3
+ import path from "node:path";
4
+
5
+ import {
6
+ auditLearningProfile,
7
+ defaultLearningFile,
8
+ defaultLearningUsageFile,
9
+ learningStats,
10
+ learningUsageStats,
11
+ loadLearningProfile,
12
+ } from "./learn.mjs";
13
+ import {
14
+ buildAgentBacklogActionPlan,
15
+ buildAgentDevelopmentBacklog,
16
+ } from "./signals-backlog.mjs";
17
+ import {
18
+ defaultLearningEvalReportPath,
19
+ resolveSignalFiles,
20
+ summarizeEvalSignals,
21
+ summarizeSignalEvalFile,
22
+ } from "./signals-eval.mjs";
23
+ import { buildLearningSignalReadiness } from "./signals-readiness.mjs";
24
+ import {
25
+ commandFromArgs,
26
+ countBy,
27
+ previewText,
28
+ worstStatus,
29
+ } from "./signals-shared.mjs";
30
+ import { collectWorkspaceReport, defaultLearningEvalPath } from "./workspace.mjs";
31
+
32
+ export function summarizeCheckCapture(profile) {
33
+ const entries = (profile.entries || []).filter((entry) => String(entry.source || "").startsWith("check:"));
34
+ const sorted = [...entries].sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
35
+ return {
36
+ count: entries.length,
37
+ categoryCounts: countBy(entries, (entry) => entry.category || "other"),
38
+ sourceCounts: countBy(entries, (entry) => entry.source || "check:artifact"),
39
+ latestEntries: sorted.slice(0, 5).map((entry) => ({
40
+ id: entry.id,
41
+ category: entry.category,
42
+ source: entry.source,
43
+ createdAt: entry.createdAt || "",
44
+ textPreview: previewText(entry.text),
45
+ })),
46
+ };
47
+ }
48
+
49
+ export function summarizeWorkspace(report) {
50
+ const nextActions = Array.isArray(report?.nextActions) ? report.nextActions : [];
51
+ const actionCounts = countBy(nextActions, (item) => item.level || "info");
52
+ return {
53
+ root: report?.context?.root || "",
54
+ version: report?.context?.version || "",
55
+ git: {
56
+ isRepo: Boolean(report?.git?.isRepo),
57
+ branch: report?.git?.branch || "",
58
+ clean: Boolean(report?.git?.clean),
59
+ ahead: Number.isInteger(report?.git?.ahead) ? report.git.ahead : 0,
60
+ behind: Number.isInteger(report?.git?.behind) ? report.git.behind : 0,
61
+ },
62
+ repository: {
63
+ status: report?.repository?.status || "",
64
+ canonical: Boolean(report?.repository?.canonical),
65
+ },
66
+ learning: {
67
+ status: report?.learning?.readiness?.status || report?.learning?.auditSummary?.status || "",
68
+ reason: report?.learning?.readiness?.reason || "",
69
+ },
70
+ learningUsage: report?.learningUsage?.readiness || null,
71
+ learningEval: report?.learningEval?.freshness || report?.learningEval?.readiness || null,
72
+ nextActionCounts: actionCounts,
73
+ nextActionCount: nextActions.length,
74
+ };
75
+ }
76
+
77
+ export function buildRecommendations({ audit, usage, evals, checkCapture, workspace }) {
78
+ const recommendations = [];
79
+ if (!audit.exists) {
80
+ recommendations.push({
81
+ level: "info",
82
+ text: "Initialize or import a local learning profile before treating signal registry output as complete.",
83
+ });
84
+ } else if (audit.summary.failures > 0) {
85
+ recommendations.push({
86
+ level: "fail",
87
+ text: "Fix learning profile audit failures before using local learning signals as release evidence.",
88
+ });
89
+ } else if (audit.summary.warnings > 0) {
90
+ recommendations.push({
91
+ level: "warn",
92
+ text: "Review learning profile audit warnings before promoting learned preferences.",
93
+ });
94
+ }
95
+
96
+ if (!usage.exists || usage.eventCount === 0) {
97
+ recommendations.push({
98
+ level: "info",
99
+ text: "Run prompt or pack with --with-learning to create usage signals for selected learning entries.",
100
+ });
101
+ }
102
+ if (usage.staleSelectedEntryCount > 0) {
103
+ recommendations.push({
104
+ level: "warn",
105
+ text: "Usage sidecar references learning entry ids that are no longer active.",
106
+ });
107
+ }
108
+ if (evals.files.length === 0) {
109
+ recommendations.push({
110
+ level: "warn",
111
+ text: "No route/prompt/pack/learning eval signal files were found; generate eval reports before relying on this registry as a gate.",
112
+ });
113
+ }
114
+ if (evals.failed > 0) {
115
+ recommendations.push({
116
+ level: "fail",
117
+ text: "At least one eval signal report failed; inspect the failing checkpoint before continuing agent development.",
118
+ });
119
+ }
120
+ if (evals.templates > 0) {
121
+ recommendations.push({
122
+ level: "warn",
123
+ text: "Some eval signals are templates rather than executed reports; replay them with --eval --strict for stronger evidence.",
124
+ });
125
+ }
126
+ if (checkCapture.count === 0) {
127
+ recommendations.push({
128
+ level: "info",
129
+ text: "No check learning capture entries are present yet; run check --learn --yes on real warnings/failures when appropriate.",
130
+ });
131
+ }
132
+ if (workspace.nextActionCounts.fail > 0 || workspace.nextActionCounts.warn > 0) {
133
+ recommendations.push({
134
+ level: workspace.nextActionCounts.fail > 0 ? "fail" : "warn",
135
+ text: "Workspace readiness has unresolved next actions; review workspace output before using signals as release evidence.",
136
+ });
137
+ }
138
+ return recommendations;
139
+ }
140
+
141
+ export function learningSignalRegistry({
142
+ filePath = defaultLearningFile(),
143
+ usageFile = "",
144
+ signalSource = "",
145
+ root = process.cwd(),
146
+ now = new Date(),
147
+ workspaceReportProvider = collectWorkspaceReport,
148
+ learningStatsProvider = learningStats,
149
+ learningUsageStatsProvider = learningUsageStats,
150
+ } = {}) {
151
+ const resolvedFile = path.resolve(filePath);
152
+ const resolvedUsageFile = path.resolve(usageFile || defaultLearningUsageFile(resolvedFile));
153
+ const profile = loadLearningProfile(resolvedFile);
154
+ const audit = auditLearningProfile({ filePath: resolvedFile });
155
+ const stats = learningStatsProvider({ filePath: resolvedFile });
156
+ const usage = learningUsageStatsProvider({
157
+ filePath: resolvedFile,
158
+ usageFile: resolvedUsageFile,
159
+ });
160
+ const signalFiles = resolveSignalFiles({
161
+ signalSource,
162
+ root,
163
+ extraFiles: [defaultLearningEvalPath(resolvedFile), defaultLearningEvalReportPath(resolvedFile)],
164
+ });
165
+ const evalFiles = signalFiles.map((file) => summarizeSignalEvalFile(file));
166
+ const evalSignalSummary = summarizeEvalSignals(evalFiles);
167
+ const evalSummary = {
168
+ source: signalSource ? path.resolve(signalSource) : path.resolve(root),
169
+ count: evalFiles.length,
170
+ reports: evalSignalSummary.reports,
171
+ templates: evalSignalSummary.templates,
172
+ rawTemplates: evalSignalSummary.rawTemplates,
173
+ templateFiles: evalSignalSummary.templateFiles,
174
+ failed: evalSignalSummary.failed,
175
+ warned: evalSignalSummary.warned,
176
+ passed: evalSignalSummary.passed,
177
+ files: evalFiles,
178
+ };
179
+ const workspaceReport = workspaceReportProvider({
180
+ root,
181
+ learningFilePath: resolvedFile,
182
+ learningUsagePath: resolvedUsageFile,
183
+ });
184
+ const workspace = summarizeWorkspace(workspaceReport);
185
+ const checkCapture = summarizeCheckCapture(profile);
186
+ const recommendations = buildRecommendations({
187
+ audit,
188
+ usage,
189
+ evals: evalSummary,
190
+ checkCapture,
191
+ workspace,
192
+ });
193
+ const agentDevelopment = buildAgentDevelopmentBacklog({
194
+ audit,
195
+ usage,
196
+ evals: evalSummary,
197
+ checkCapture,
198
+ workspace,
199
+ filePath: resolvedFile,
200
+ usageFile: resolvedUsageFile,
201
+ signalSource: evalSummary.source,
202
+ });
203
+ const status = worstStatus([
204
+ audit.summary.failures > 0 ? "fail" : "",
205
+ audit.summary.warnings > 0 ? "warn" : "",
206
+ usage.staleSelectedEntryCount > 0 ? "warn" : "",
207
+ evalSummary.failed > 0 ? "fail" : "",
208
+ evalSummary.warned > 0 || evalSummary.templates > 0 || evalSummary.count === 0 ? "warn" : "",
209
+ workspace.nextActionCounts.fail > 0 ? "fail" : "",
210
+ workspace.nextActionCounts.warn > 0 ? "warn" : "",
211
+ "pass",
212
+ ]);
213
+ const readiness = buildLearningSignalReadiness({
214
+ audit,
215
+ usage,
216
+ evals: evalSummary,
217
+ checkCapture,
218
+ workspace,
219
+ agentDevelopment,
220
+ status,
221
+ });
222
+
223
+ return {
224
+ version: 1,
225
+ generatedAt: (now instanceof Date ? now : new Date(now)).toISOString(),
226
+ status,
227
+ file: resolvedFile,
228
+ signalSource: evalSummary.source,
229
+ learning: {
230
+ exists: audit.exists,
231
+ version: audit.version,
232
+ updatedAt: audit.updatedAt,
233
+ count: audit.count,
234
+ categoryCounts: audit.categoryCounts,
235
+ sourceCounts: stats.sourceCounts || {},
236
+ auditSummary: audit.summary,
237
+ },
238
+ usage: {
239
+ usageFile: usage.usageFile,
240
+ exists: usage.exists,
241
+ eventCount: usage.eventCount,
242
+ usedEntryCount: usage.usedEntryCount,
243
+ unusedEntryCount: usage.unusedEntryCount,
244
+ staleSelectedEntryCount: usage.staleSelectedEntryCount,
245
+ commandCounts: usage.commandCounts,
246
+ routeCounts: usage.routeCounts,
247
+ latestEvent: usage.latestEvent || null,
248
+ privacy: usage.privacy,
249
+ },
250
+ evals: evalSummary,
251
+ checkCapture,
252
+ workspace,
253
+ agentDevelopment,
254
+ readiness,
255
+ recommendations,
256
+ privacy: {
257
+ mutatesProfile: false,
258
+ storesRawBriefText: false,
259
+ exposesEntryTextPreview: true,
260
+ readsSignalFilesOnly: true,
261
+ },
262
+ };
263
+ }
264
+
265
+ export function agentBacklogReport({
266
+ filePath = defaultLearningFile(),
267
+ usageFile = "",
268
+ signalSource = "",
269
+ root = process.cwd(),
270
+ now = new Date(),
271
+ signalRegistryProvider = learningSignalRegistry,
272
+ } = {}) {
273
+ const registry = signalRegistryProvider({
274
+ filePath,
275
+ usageFile,
276
+ signalSource,
277
+ root,
278
+ now,
279
+ });
280
+ const agentDevelopment = registry.agentDevelopment || {
281
+ status: "unknown",
282
+ actionCount: 0,
283
+ p0Count: 0,
284
+ p1Count: 0,
285
+ p2Count: 0,
286
+ p3Count: 0,
287
+ actions: [],
288
+ privacy: {
289
+ mutatesProfile: false,
290
+ mutatesSkillFiles: false,
291
+ callsExternalAiApis: false,
292
+ storesRawBriefText: false,
293
+ },
294
+ };
295
+ const actions = Array.isArray(agentDevelopment.actions) ? agentDevelopment.actions : [];
296
+ const signalsJsonArgs = [
297
+ "design-ai",
298
+ "learn",
299
+ "--signals",
300
+ "--from-file",
301
+ registry.signalSource || ".",
302
+ "--file",
303
+ registry.file || filePath,
304
+ "--usage-file",
305
+ registry.usage?.usageFile || usageFile || defaultLearningUsageFile(path.resolve(filePath)),
306
+ "--json",
307
+ ];
308
+ const signalsReportArgs = [
309
+ "design-ai",
310
+ "learn",
311
+ "--signals",
312
+ "--from-file",
313
+ registry.signalSource || ".",
314
+ "--file",
315
+ registry.file || filePath,
316
+ "--usage-file",
317
+ registry.usage?.usageFile || usageFile || defaultLearningUsageFile(path.resolve(filePath)),
318
+ "--report",
319
+ "--out",
320
+ "learning-signals.md",
321
+ ];
322
+ const agentBacklogJsonArgs = [
323
+ "design-ai",
324
+ "learn",
325
+ "--agent-backlog",
326
+ "--from-file",
327
+ registry.signalSource || ".",
328
+ "--file",
329
+ registry.file || filePath,
330
+ "--usage-file",
331
+ registry.usage?.usageFile || usageFile || defaultLearningUsageFile(path.resolve(filePath)),
332
+ "--strict",
333
+ "--json",
334
+ ];
335
+ const commands = {
336
+ signalsJson: commandFromArgs(signalsJsonArgs),
337
+ signalsJsonArgs,
338
+ signalsReport: commandFromArgs(signalsReportArgs),
339
+ signalsReportArgs,
340
+ agentBacklogJson: commandFromArgs(agentBacklogJsonArgs),
341
+ agentBacklogJsonArgs,
342
+ };
343
+ const privacy = {
344
+ mutatesProfile: false,
345
+ mutatesSkillFiles: false,
346
+ callsExternalAiApis: false,
347
+ storesRawBriefText: false,
348
+ readsSignalFilesOnly: true,
349
+ };
350
+ return {
351
+ version: 1,
352
+ generatedAt: registry.generatedAt || (now instanceof Date ? now : new Date(now)).toISOString(),
353
+ status: agentDevelopment.status || "unknown",
354
+ signalStatus: registry.status || "unknown",
355
+ file: registry.file || path.resolve(filePath),
356
+ usageFile: registry.usage?.usageFile || path.resolve(usageFile || defaultLearningUsageFile(path.resolve(filePath))),
357
+ signalSource: registry.signalSource || (signalSource ? path.resolve(signalSource) : path.resolve(root)),
358
+ counts: {
359
+ actions: agentDevelopment.actionCount ?? actions.length,
360
+ p0: agentDevelopment.p0Count ?? 0,
361
+ p1: agentDevelopment.p1Count ?? 0,
362
+ p2: agentDevelopment.p2Count ?? 0,
363
+ p3: agentDevelopment.p3Count ?? 0,
364
+ learningEntries: registry.learning?.count ?? 0,
365
+ usageEvents: registry.usage?.eventCount ?? 0,
366
+ evalSignals: registry.evals?.count ?? 0,
367
+ checkCaptures: registry.checkCapture?.count ?? 0,
368
+ workspaceNextActions: registry.workspace?.nextActionCount ?? 0,
369
+ },
370
+ actions,
371
+ actionPlan: buildAgentBacklogActionPlan({ actions, commands, privacy }),
372
+ readiness: registry.readiness || null,
373
+ commands,
374
+ recommendations: registry.recommendations || [],
375
+ privacy,
376
+ };
377
+ }