@design-ai/cli 4.55.0 → 4.56.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 (52) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +39 -0
  3. package/README.ko.md +7 -7
  4. package/README.md +9 -9
  5. package/cli/lib/mcp-server.mjs +208 -10
  6. package/cli/lib/site-analysis.mjs +297 -0
  7. package/cli/lib/site-args.mjs +433 -0
  8. package/cli/lib/site-bundle-build.mjs +127 -0
  9. package/cli/lib/site-bundle-check.mjs +454 -0
  10. package/cli/lib/site-bundle-commands.mjs +95 -0
  11. package/cli/lib/site-bundle-compare.mjs +157 -0
  12. package/cli/lib/site-bundle-contract.mjs +79 -0
  13. package/cli/lib/site-bundle-files.mjs +87 -0
  14. package/cli/lib/site-bundle-handoff-runbook-actions.mjs +113 -0
  15. package/cli/lib/site-bundle-handoff-runbook-evidence-fields.mjs +164 -0
  16. package/cli/lib/site-bundle-handoff-runbook-evidence.mjs +334 -0
  17. package/cli/lib/site-bundle-handoff-runbook-format.mjs +31 -0
  18. package/cli/lib/site-bundle-handoff-runbook-stage-metadata.mjs +84 -0
  19. package/cli/lib/site-bundle-handoff-runbook.mjs +1331 -0
  20. package/cli/lib/site-bundle-handoff-summary.mjs +183 -0
  21. package/cli/lib/site-bundle-handoff.mjs +271 -0
  22. package/cli/lib/site-bundle-readme.mjs +98 -0
  23. package/cli/lib/site-bundle-repair-report.mjs +143 -0
  24. package/cli/lib/site-bundle-repair.mjs +68 -0
  25. package/cli/lib/site-content.mjs +399 -0
  26. package/cli/lib/site-evidence.mjs +35 -0
  27. package/cli/lib/site-mcp-commands.mjs +28 -0
  28. package/cli/lib/site-mcp-probes.mjs +159 -0
  29. package/cli/lib/site-mcp-readiness.mjs +157 -0
  30. package/cli/lib/site-mcp-report.mjs +324 -0
  31. package/cli/lib/site-next-actions.mjs +333 -0
  32. package/cli/lib/site-options.mjs +104 -0
  33. package/cli/lib/site-prompts.mjs +332 -0
  34. package/cli/lib/site-starter.mjs +153 -0
  35. package/cli/lib/site-strings.mjs +23 -0
  36. package/cli/lib/site-tasks.mjs +93 -0
  37. package/cli/lib/site-workflow-graph.mjs +309 -0
  38. package/cli/lib/site-workspace.mjs +492 -0
  39. package/cli/lib/site.mjs +108 -6617
  40. package/docs/DISTRIBUTION.ko.md +35 -6
  41. package/docs/DISTRIBUTION.md +35 -8
  42. package/docs/RELEASE-CHECKLIST.md +20 -3
  43. package/docs/ROADMAP.md +2179 -0
  44. package/docs/external-status.md +22 -7
  45. package/docs/integrations/design-ai-mcp-server.md +32 -0
  46. package/docs/integrations/vscode-walkthrough.ko.md +3 -3
  47. package/docs/integrations/vscode-walkthrough.md +3 -3
  48. package/docs/site-overrides/main.html +1 -1
  49. package/package.json +1 -1
  50. package/tools/audit/package-smoke.py +106 -0
  51. package/tools/audit/registry-smoke.py +378 -10
  52. package/tools/audit/smoke_assertions.py +83 -22
@@ -0,0 +1,309 @@
1
+ // Website Improvement workflow graph helpers.
2
+
3
+ import {
4
+ buildSiteMcpCheckReport,
5
+ combineStatuses,
6
+ normalizeMcpKey,
7
+ } from "./site-mcp-report.mjs";
8
+ import { orderedRefactorTasks } from "./site-prompts.mjs";
9
+ import { markdownTable } from "./site-strings.mjs";
10
+ import {
11
+ AUDIT_CATEGORIES,
12
+ } from "./site-options.mjs";
13
+ import {
14
+ SITE_PROMPT_TEMPLATES,
15
+ } from "./site-content.mjs";
16
+ import { analyzeSiteWorkspace } from "./site-analysis.mjs";
17
+ import { generateSiteRefactorTasks } from "./site-tasks.mjs";
18
+
19
+ function workflowNode(id, type, label, status, data = {}) {
20
+ return {
21
+ id,
22
+ type,
23
+ label,
24
+ status,
25
+ data,
26
+ };
27
+ }
28
+
29
+ function workflowEdge(from, to, type, label) {
30
+ return {
31
+ id: `${from}->${to}:${type}`,
32
+ from,
33
+ to,
34
+ type,
35
+ label,
36
+ };
37
+ }
38
+
39
+ function siteProfileNodeId(profile) {
40
+ return `profile:${profile.id || "site"}`;
41
+ }
42
+
43
+ function workflowGraphMcpNodes(mcpReport) {
44
+ return mcpReport.items.map((item) => workflowNode(
45
+ `mcp:${item.key}`,
46
+ "mcp-readiness",
47
+ item.label,
48
+ item.level,
49
+ {
50
+ key: item.key,
51
+ requestedStatus: item.requestedStatus,
52
+ state: item.state,
53
+ evidence: item.evidence,
54
+ actions: item.actions,
55
+ },
56
+ ));
57
+ }
58
+
59
+ function workflowGraphTaskNode(task) {
60
+ return workflowNode(
61
+ `task:${task.id}`,
62
+ "refactor-task",
63
+ task.title,
64
+ "planned",
65
+ {
66
+ id: task.id,
67
+ category: task.category,
68
+ problem: task.problem,
69
+ evidence: task.evidence,
70
+ impact: task.impact,
71
+ effort: task.effort,
72
+ priority: task.priority,
73
+ pages: task.pages,
74
+ recommendedMcp: task.recommendedMcp,
75
+ codexPrompt: task.codexPrompt,
76
+ verification: task.verification,
77
+ risks: task.risks,
78
+ },
79
+ );
80
+ }
81
+
82
+ export function buildSiteWorkflowGraph(workspaceInput, summary = {}) {
83
+ const taskResult = generateSiteRefactorTasks(workspaceInput);
84
+ const workspace = taskResult.workspace;
85
+ const filePath = summary.filePath || "workspace.json";
86
+ const { summary: taskSummary } = analyzeSiteWorkspace(workspace, { filePath });
87
+ const mcpReport = buildSiteMcpCheckReport(workspace, taskSummary);
88
+ const profile = workspace.siteProfile;
89
+ const profileNodeId = siteProfileNodeId(profile);
90
+ const orderedTasks = orderedRefactorTasks(workspace);
91
+ const nodes = [];
92
+ const edges = [];
93
+
94
+ nodes.push(workflowNode(
95
+ "workspace:intake",
96
+ "workspace",
97
+ "Workspace intake",
98
+ taskSummary.status,
99
+ {
100
+ version: workspace.version,
101
+ updatedAt: workspace.updatedAt,
102
+ source: filePath,
103
+ workspaceStatus: taskSummary.status,
104
+ mcpStatus: mcpReport.status,
105
+ },
106
+ ));
107
+ nodes.push(workflowNode(
108
+ profileNodeId,
109
+ "site-profile",
110
+ profile.name,
111
+ taskSummary.status,
112
+ {
113
+ id: profile.id,
114
+ liveUrl: profile.liveUrl,
115
+ repoUrl: profile.repoUrl,
116
+ localPath: profile.localPath,
117
+ figmaUrl: profile.figmaUrl,
118
+ deployProvider: profile.deployProvider,
119
+ cms: profile.cms,
120
+ database: profile.database,
121
+ pages: profile.pages,
122
+ userFlows: profile.userFlows,
123
+ viewports: profile.viewports,
124
+ brandNotes: profile.brandNotes,
125
+ },
126
+ ));
127
+ edges.push(workflowEdge("workspace:intake", profileNodeId, "profile", "Workspace defines the target site profile"));
128
+
129
+ for (const category of AUDIT_CATEGORIES) {
130
+ const row = workspace.auditChecklist[category.id];
131
+ const nodeId = `audit:${category.id}`;
132
+ nodes.push(workflowNode(
133
+ nodeId,
134
+ "audit-category",
135
+ category.label,
136
+ row.status,
137
+ {
138
+ category: category.id,
139
+ notes: row.notes,
140
+ findings: row.findings,
141
+ findingCount: row.findings.length,
142
+ defaultVerification: category.defaultVerification,
143
+ },
144
+ ));
145
+ edges.push(workflowEdge(profileNodeId, nodeId, "audit-input", "Site context drives this audit category"));
146
+ }
147
+
148
+ const mcpNodes = workflowGraphMcpNodes(mcpReport);
149
+ nodes.push(...mcpNodes);
150
+ for (const node of mcpNodes) {
151
+ edges.push(workflowEdge(profileNodeId, node.id, "readiness-input", "Site profile provides MCP readiness evidence"));
152
+ }
153
+
154
+ for (const task of orderedTasks) {
155
+ const taskNode = workflowGraphTaskNode(task);
156
+ nodes.push(taskNode);
157
+ edges.push(workflowEdge(`audit:${task.category}`, taskNode.id, "finding-to-task", "Audit finding informs this refactor task"));
158
+ edges.push(workflowEdge(profileNodeId, taskNode.id, "site-context", "Site profile scopes this refactor task"));
159
+ for (const rawMcp of task.recommendedMcp) {
160
+ const key = normalizeMcpKey(rawMcp);
161
+ if (workspace.mcpReadiness[key]) {
162
+ edges.push(workflowEdge(`mcp:${key}`, taskNode.id, "mcp-support", "MCP readiness supports task execution"));
163
+ }
164
+ }
165
+ }
166
+
167
+ for (const template of SITE_PROMPT_TEMPLATES) {
168
+ const promptNodeId = `prompt:${template.id}`;
169
+ nodes.push(workflowNode(
170
+ promptNodeId,
171
+ "prompt-template",
172
+ template.label,
173
+ "ready",
174
+ {
175
+ id: template.id,
176
+ agent: template.agent,
177
+ output: template.output,
178
+ description: template.description,
179
+ taskSelectable: template.taskSelectable,
180
+ },
181
+ ));
182
+ edges.push(workflowEdge(profileNodeId, promptNodeId, "profile-context", "Prompt template receives site profile context"));
183
+ }
184
+
185
+ for (const task of orderedTasks) {
186
+ edges.push(workflowEdge(`task:${task.id}`, "prompt:codex-implementation", "implementation-prompt", "Task can be exported as a Codex implementation prompt"));
187
+ }
188
+
189
+ nodes.push(workflowNode(
190
+ "handoff:report",
191
+ "handoff-report",
192
+ "Handoff report",
193
+ "ready",
194
+ {
195
+ output: "website-handoff.md",
196
+ purpose: "Summarize site state, audit findings, priority improvements, verification, and remaining risk",
197
+ },
198
+ ));
199
+ nodes.push(workflowNode(
200
+ "handoff:bundle",
201
+ "handoff-bundle",
202
+ "Local handoff bundle",
203
+ "ready",
204
+ {
205
+ output: "website-handoff-bundle",
206
+ purpose: "Package the local Website Improvement plan without mutating the target repo",
207
+ },
208
+ ));
209
+ nodes.push(workflowNode(
210
+ "handoff:target-repo",
211
+ "target-repo",
212
+ "Target website repo",
213
+ "external",
214
+ {
215
+ repoUrl: profile.repoUrl,
216
+ localPath: profile.localPath,
217
+ boundary: "Implementation happens outside the design-ai repository",
218
+ },
219
+ ));
220
+ edges.push(workflowEdge(profileNodeId, "handoff:report", "handoff-input", "Site profile anchors the handoff report"));
221
+ for (const task of orderedTasks) {
222
+ edges.push(workflowEdge(`task:${task.id}`, "handoff:report", "handoff-input", "Refactor task is summarized in the handoff report"));
223
+ }
224
+ for (const item of mcpReport.items.filter((item) => item.requestedStatus !== "unused")) {
225
+ edges.push(workflowEdge(`mcp:${item.key}`, "handoff:report", "readiness-input", "MCP readiness is summarized in the handoff report"));
226
+ }
227
+ for (const template of SITE_PROMPT_TEMPLATES) {
228
+ edges.push(workflowEdge(`prompt:${template.id}`, "handoff:target-repo", "agent-prompt", "Prompt can be used in the target website workflow"));
229
+ }
230
+ edges.push(workflowEdge("handoff:report", "handoff:bundle", "bundle-input", "Handoff report can be packaged into a local bundle"));
231
+ edges.push(workflowEdge("handoff:bundle", "handoff:target-repo", "handoff", "Verified bundle can become target-repo implementation context"));
232
+
233
+ const status = combineStatuses(taskSummary.status, mcpReport.status);
234
+ return {
235
+ version: 1,
236
+ kind: "website-improvement-workflow-graph",
237
+ generatedAt: workspace.updatedAt,
238
+ filePath,
239
+ status,
240
+ workspaceStatus: taskSummary.status,
241
+ mcpStatus: mcpReport.status,
242
+ externalCalls: false,
243
+ site: {
244
+ id: profile.id,
245
+ name: profile.name,
246
+ liveUrl: profile.liveUrl,
247
+ repoUrl: profile.repoUrl,
248
+ localPath: profile.localPath,
249
+ },
250
+ summary: {
251
+ status,
252
+ workspaceStatus: taskSummary.status,
253
+ mcpStatus: mcpReport.status,
254
+ nodeCount: nodes.length,
255
+ edgeCount: edges.length,
256
+ auditCategoryCount: AUDIT_CATEGORIES.length,
257
+ taskCount: orderedTasks.length,
258
+ generatedTaskCount: taskResult.created.length,
259
+ requiredMcpCount: mcpReport.counts.required,
260
+ promptTemplateCount: SITE_PROMPT_TEMPLATES.length,
261
+ },
262
+ nodes,
263
+ edges,
264
+ boundaries: [
265
+ "deterministic-local",
266
+ "no-external-mcp-calls",
267
+ "no-target-repo-mutation",
268
+ "no-new-dependencies",
269
+ ],
270
+ };
271
+ }
272
+
273
+ export function formatSiteWorkflowGraphJson(graph) {
274
+ return JSON.stringify(graph, null, 2);
275
+ }
276
+
277
+ export function formatSiteWorkflowGraphMarkdown(graph) {
278
+ return [
279
+ `# Website improvement workflow graph: ${graph.site.name}`,
280
+ "",
281
+ "## Summary",
282
+ `- Source: ${graph.filePath}`,
283
+ `- Status: ${graph.status}`,
284
+ `- Workspace status: ${graph.workspaceStatus}`,
285
+ `- MCP status: ${graph.mcpStatus}`,
286
+ `- Nodes: ${graph.summary.nodeCount}`,
287
+ `- Edges: ${graph.summary.edgeCount}`,
288
+ `- Tasks: ${graph.summary.taskCount}`,
289
+ `- Prompt templates: ${graph.summary.promptTemplateCount}`,
290
+ `- External calls: ${graph.externalCalls ? "yes" : "no"}`,
291
+ "",
292
+ "## Nodes",
293
+ markdownTable(
294
+ ["ID", "Type", "Status", "Label"],
295
+ graph.nodes.map((node) => [node.id, node.type, node.status, node.label]),
296
+ ),
297
+ "",
298
+ "## Edges",
299
+ markdownTable(
300
+ ["From", "To", "Type", "Label"],
301
+ graph.edges.map((edge) => [edge.from, edge.to, edge.type, edge.label]),
302
+ ),
303
+ "",
304
+ "## Boundaries",
305
+ "- This graph is deterministic and local.",
306
+ "- No external MCP calls are made.",
307
+ "- It does not mutate the target website repo, run Lighthouse/axe, crawl pages, add dependencies, or write to external systems.",
308
+ ].join("\n");
309
+ }