@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,262 @@
1
+ // Skill proposal review-state loading and review checks for `design-ai learn --propose-skills`.
2
+
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const REVIEW_STATUSES = ["accepted", "rejected", "applied", "deferred"];
7
+ const REVIEW_CLEAR_STATUSES = new Set(["rejected", "applied"]);
8
+
9
+ export function proposalStatus({ signalStatus, proposalCount }) {
10
+ if (signalStatus === "fail") return "fail";
11
+ if (signalStatus && signalStatus !== "pass") return "warn";
12
+ if (proposalCount > 0) return "warn";
13
+ return "pass";
14
+ }
15
+
16
+ function normalizeReviewStatus(rawStatus) {
17
+ const status = String(rawStatus || "").trim().toLowerCase();
18
+ return REVIEW_STATUSES.includes(status) ? status : "";
19
+ }
20
+
21
+ function emptyProposalReviewState(reviewFile = "") {
22
+ return {
23
+ file: reviewFile ? path.resolve(reviewFile) : "",
24
+ exists: false,
25
+ status: reviewFile ? "missing" : "not-configured",
26
+ decisionCount: 0,
27
+ matchedCount: 0,
28
+ staleCount: 0,
29
+ pendingCount: 0,
30
+ acceptedCount: 0,
31
+ rejectedCount: 0,
32
+ appliedCount: 0,
33
+ deferredCount: 0,
34
+ clearedCount: 0,
35
+ warnings: [],
36
+ decisionsByProposalId: new Map(),
37
+ };
38
+ }
39
+
40
+ export function loadSkillProposalReviewState(reviewFile = "") {
41
+ if (!reviewFile) return emptyProposalReviewState();
42
+ const resolvedFile = path.resolve(reviewFile);
43
+ if (!existsSync(resolvedFile)) return emptyProposalReviewState(resolvedFile);
44
+
45
+ const state = emptyProposalReviewState(resolvedFile);
46
+ state.exists = true;
47
+ state.status = "pass";
48
+
49
+ let rawPayload = null;
50
+ try {
51
+ rawPayload = JSON.parse(readFileSync(resolvedFile, "utf8"));
52
+ } catch {
53
+ return {
54
+ ...state,
55
+ status: "fail",
56
+ warnings: [`Review file is not valid JSON: ${resolvedFile}`],
57
+ };
58
+ }
59
+
60
+ const rawDecisions = Array.isArray(rawPayload?.decisions)
61
+ ? rawPayload.decisions
62
+ : Array.isArray(rawPayload?.reviews)
63
+ ? rawPayload.reviews
64
+ : [];
65
+
66
+ if (!Array.isArray(rawPayload?.decisions) && !Array.isArray(rawPayload?.reviews)) {
67
+ state.status = "warn";
68
+ state.warnings.push("Review file should contain a decisions array.");
69
+ }
70
+
71
+ rawDecisions.forEach((decision, index) => {
72
+ const proposalId = String(decision?.proposalId || decision?.id || "").trim();
73
+ const status = normalizeReviewStatus(decision?.status);
74
+ if (!proposalId) {
75
+ state.status = state.status === "fail" ? "fail" : "warn";
76
+ state.warnings.push(`Decision ${index + 1} is missing proposalId.`);
77
+ return;
78
+ }
79
+ if (!status) {
80
+ state.status = state.status === "fail" ? "fail" : "warn";
81
+ state.warnings.push(`Decision ${proposalId} has unsupported status; use ${REVIEW_STATUSES.join(", ")}.`);
82
+ return;
83
+ }
84
+ state.decisionsByProposalId.set(proposalId, {
85
+ proposalId,
86
+ status,
87
+ reviewedAt: String(decision?.reviewedAt || decision?.createdAt || "").trim(),
88
+ reviewer: String(decision?.reviewer || "").trim(),
89
+ note: String(decision?.note || decision?.reason || "").trim(),
90
+ });
91
+ });
92
+
93
+ state.decisionCount = state.decisionsByProposalId.size;
94
+ return state;
95
+ }
96
+
97
+ export function applySkillProposalReviewState(proposals, reviewState) {
98
+ const decisions = reviewState?.decisionsByProposalId instanceof Map
99
+ ? reviewState.decisionsByProposalId
100
+ : new Map();
101
+ const currentProposalIds = new Set(proposals.map((proposal) => proposal.id));
102
+ const reviewedProposals = proposals.map((proposal) => {
103
+ const decision = decisions.get(proposal.id);
104
+ const reviewStatus = decision?.status || "pending";
105
+ const reviewClearsStrict = REVIEW_CLEAR_STATUSES.has(reviewStatus);
106
+ return {
107
+ ...proposal,
108
+ reviewStatus,
109
+ reviewClearsStrict,
110
+ ...(decision ? { reviewDecision: decision } : {}),
111
+ };
112
+ });
113
+
114
+ const counts = {
115
+ matchedCount: reviewedProposals.filter((proposal) => proposal.reviewDecision).length,
116
+ staleCount: [...decisions.keys()].filter((proposalId) => !currentProposalIds.has(proposalId)).length,
117
+ pendingCount: reviewedProposals.filter((proposal) => !proposal.reviewClearsStrict).length,
118
+ acceptedCount: reviewedProposals.filter((proposal) => proposal.reviewStatus === "accepted").length,
119
+ rejectedCount: reviewedProposals.filter((proposal) => proposal.reviewStatus === "rejected").length,
120
+ appliedCount: reviewedProposals.filter((proposal) => proposal.reviewStatus === "applied").length,
121
+ deferredCount: reviewedProposals.filter((proposal) => proposal.reviewStatus === "deferred").length,
122
+ clearedCount: reviewedProposals.filter((proposal) => proposal.reviewClearsStrict).length,
123
+ };
124
+
125
+ return {
126
+ proposals: reviewedProposals,
127
+ review: {
128
+ file: reviewState?.file || "",
129
+ exists: Boolean(reviewState?.exists),
130
+ status: reviewState?.status || "not-configured",
131
+ decisionCount: reviewState?.decisionCount || 0,
132
+ warnings: reviewState?.warnings || [],
133
+ ...counts,
134
+ },
135
+ };
136
+ }
137
+
138
+ export function skillProposalStatus({ signalStatus, reviewStatus, pendingReviewCount, reviewWarnings }) {
139
+ if (signalStatus === "fail" || reviewStatus === "fail") return "fail";
140
+ if (signalStatus && signalStatus !== "pass") return "warn";
141
+ if (reviewWarnings > 0) return "warn";
142
+ if (pendingReviewCount > 0) return "warn";
143
+ return "pass";
144
+ }
145
+
146
+ function reviewCheck({ id, level = "pass", passed = true, message, evidence = {} }) {
147
+ return {
148
+ id,
149
+ level,
150
+ passed,
151
+ message,
152
+ evidence,
153
+ };
154
+ }
155
+
156
+ function summarizeReviewChecks(checks) {
157
+ const failures = checks.filter((check) => check.level === "fail").length;
158
+ const warnings = checks.filter((check) => check.level === "warn").length;
159
+ return {
160
+ status: failures > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
161
+ failures,
162
+ warnings,
163
+ passes: checks.filter((check) => check.level === "pass").length,
164
+ total: checks.length,
165
+ };
166
+ }
167
+
168
+ export function buildSkillProposalReviewCheck(payload, {
169
+ generatedAt = new Date(),
170
+ } = {}) {
171
+ const generatedAtText = generatedAt instanceof Date ? generatedAt.toISOString() : String(generatedAt || "");
172
+ const review = payload.review || {};
173
+ const reviewFile = payload.reviewFile || review.file || "";
174
+ const warnings = Array.isArray(review.warnings) ? review.warnings : [];
175
+ const checks = [];
176
+
177
+ checks.push(reviewCheck({
178
+ id: "review-file-configured",
179
+ level: reviewFile ? "pass" : "fail",
180
+ passed: Boolean(reviewFile),
181
+ message: reviewFile ? "A skill proposal review file is configured." : "No review file was provided.",
182
+ evidence: { reviewFile },
183
+ }));
184
+ checks.push(reviewCheck({
185
+ id: "review-file-exists",
186
+ level: review.exists ? "pass" : "fail",
187
+ passed: Boolean(review.exists),
188
+ message: review.exists ? "The review file exists." : "The review file does not exist.",
189
+ evidence: { reviewFile, exists: Boolean(review.exists) },
190
+ }));
191
+ checks.push(reviewCheck({
192
+ id: "review-file-valid",
193
+ level: review.status === "fail" ? "fail" : warnings.length > 0 || review.status === "warn" ? "warn" : "pass",
194
+ passed: review.status === "pass",
195
+ message: review.status === "pass"
196
+ ? "The review file is valid and has a decisions array."
197
+ : `Review file status is ${review.status || "unknown"}.`,
198
+ evidence: { reviewStatus: review.status || "unknown", warnings },
199
+ }));
200
+ checks.push(reviewCheck({
201
+ id: "current-proposals-cleared",
202
+ level: (payload.pendingReviewCount || 0) > 0 ? "warn" : "pass",
203
+ passed: (payload.pendingReviewCount || 0) === 0,
204
+ message: (payload.pendingReviewCount || 0) === 0
205
+ ? "All current proposals are applied or rejected."
206
+ : "Some current proposals are still pending, accepted, or deferred.",
207
+ evidence: {
208
+ proposalCount: payload.proposalCount || 0,
209
+ pendingReviewCount: payload.pendingReviewCount || 0,
210
+ clearedCount: review.clearedCount || 0,
211
+ },
212
+ }));
213
+ checks.push(reviewCheck({
214
+ id: "no-stale-review-decisions",
215
+ level: (review.staleCount || 0) > 0 ? "warn" : "pass",
216
+ passed: (review.staleCount || 0) === 0,
217
+ message: (review.staleCount || 0) === 0
218
+ ? "No stale review decisions were found."
219
+ : "Review file contains decisions for proposals that are no longer current.",
220
+ evidence: {
221
+ staleCount: review.staleCount || 0,
222
+ decisionCount: review.decisionCount || 0,
223
+ matchedCount: review.matchedCount || 0,
224
+ },
225
+ }));
226
+
227
+ const summary = summarizeReviewChecks(checks);
228
+ return {
229
+ version: 1,
230
+ kind: "skill-proposal-review-check",
231
+ generatedAt: generatedAtText,
232
+ file: payload.file,
233
+ usageFile: payload.usageFile,
234
+ signalSource: payload.signalSource,
235
+ reviewFile,
236
+ status: summary.status,
237
+ proposalStatus: payload.status,
238
+ signalStatus: payload.signalStatus,
239
+ proposalCount: payload.proposalCount || 0,
240
+ pendingReviewCount: payload.pendingReviewCount || 0,
241
+ reviewedCount: payload.reviewedCount || 0,
242
+ review,
243
+ summary,
244
+ checks,
245
+ recommendations: summary.status === "pass"
246
+ ? [{
247
+ level: "info",
248
+ text: "Review decisions clear the current skill proposal gate. Re-run proposal verification after any manual skill edit.",
249
+ }]
250
+ : [{
251
+ level: "warning",
252
+ text: "Refresh the review file from `--review-template`, then mark current proposals as applied or rejected after manual review.",
253
+ }],
254
+ privacy: {
255
+ mutatesProfile: false,
256
+ mutatesSkillFiles: false,
257
+ callsExternalAiApis: false,
258
+ storesRawBriefText: false,
259
+ exposesEntryTextPreview: false,
260
+ },
261
+ };
262
+ }