@design-ai/cli 4.55.0 → 4.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +109 -25
- package/CHANGELOG.md +75 -0
- package/README.ko.md +15 -32
- package/README.md +18 -31
- package/cli/bin/design-ai.mjs +1 -0
- package/cli/commands/help.mjs +7 -4
- package/cli/commands/index.mjs +292 -0
- package/cli/commands/learn-help.mjs +149 -0
- package/cli/commands/learn-print-profile.mjs +373 -0
- package/cli/commands/learn-print-restore.mjs +349 -0
- package/cli/commands/learn-print-signals.mjs +453 -0
- package/cli/commands/learn.mjs +60 -1281
- package/cli/commands/pack.mjs +7 -3
- package/cli/commands/prompt.mjs +7 -3
- package/cli/commands/search.mjs +94 -1
- package/cli/lib/dispatch.mjs +3 -0
- package/cli/lib/embedding-index.mjs +199 -0
- package/cli/lib/embedding-provider.mjs +121 -0
- package/cli/lib/embedding-rerank.mjs +52 -0
- package/cli/lib/learn-args.mjs +490 -0
- package/cli/lib/learn-backup.mjs +748 -0
- package/cli/lib/learn-curation.mjs +612 -0
- package/cli/lib/learn-eval.mjs +459 -0
- package/cli/lib/learn-profile.mjs +763 -0
- package/cli/lib/learn-select.mjs +223 -0
- package/cli/lib/learn-shared.mjs +158 -0
- package/cli/lib/learn-test-support.mjs +218 -0
- package/cli/lib/learn-usage.mjs +360 -0
- package/cli/lib/learn.mjs +83 -3694
- package/cli/lib/lexical.mjs +137 -0
- package/cli/lib/local-config.mjs +110 -0
- package/cli/lib/mcp-server.mjs +221 -13
- package/cli/lib/pack.mjs +31 -4
- package/cli/lib/prompt.mjs +42 -4
- package/cli/lib/recall.mjs +193 -0
- package/cli/lib/retrieval-index.mjs +0 -0
- package/cli/lib/search-ranked.mjs +170 -0
- package/cli/lib/search.mjs +11 -1
- package/cli/lib/signals-backlog-commands.mjs +673 -0
- package/cli/lib/signals-backlog.mjs +361 -0
- package/cli/lib/signals-eval.mjs +176 -0
- package/cli/lib/signals-readiness.mjs +247 -0
- package/cli/lib/signals-registry.mjs +377 -0
- package/cli/lib/signals-render.mjs +478 -0
- package/cli/lib/signals-shared.mjs +75 -0
- package/cli/lib/signals.mjs +16 -2337
- package/cli/lib/site-analysis.mjs +297 -0
- package/cli/lib/site-args.mjs +433 -0
- package/cli/lib/site-bundle-build.mjs +127 -0
- package/cli/lib/site-bundle-check.mjs +454 -0
- package/cli/lib/site-bundle-commands.mjs +95 -0
- package/cli/lib/site-bundle-compare.mjs +157 -0
- package/cli/lib/site-bundle-contract.mjs +79 -0
- package/cli/lib/site-bundle-files.mjs +87 -0
- package/cli/lib/site-bundle-handoff-expected.mjs +173 -0
- package/cli/lib/site-bundle-handoff-runbook-action-summary.mjs +332 -0
- package/cli/lib/site-bundle-handoff-runbook-actions.mjs +113 -0
- package/cli/lib/site-bundle-handoff-runbook-evidence-fields.mjs +164 -0
- package/cli/lib/site-bundle-handoff-runbook-evidence.mjs +334 -0
- package/cli/lib/site-bundle-handoff-runbook-format.mjs +31 -0
- package/cli/lib/site-bundle-handoff-runbook-human-lines.mjs +167 -0
- package/cli/lib/site-bundle-handoff-runbook-maps.mjs +238 -0
- package/cli/lib/site-bundle-handoff-runbook-next-step.mjs +278 -0
- package/cli/lib/site-bundle-handoff-runbook-stage-metadata.mjs +84 -0
- package/cli/lib/site-bundle-handoff-runbook.mjs +444 -0
- package/cli/lib/site-bundle-handoff-summary.mjs +183 -0
- package/cli/lib/site-bundle-handoff.mjs +271 -0
- package/cli/lib/site-bundle-readme.mjs +98 -0
- package/cli/lib/site-bundle-repair-report.mjs +143 -0
- package/cli/lib/site-bundle-repair.mjs +68 -0
- package/cli/lib/site-content.mjs +399 -0
- package/cli/lib/site-evidence.mjs +35 -0
- package/cli/lib/site-mcp-commands.mjs +28 -0
- package/cli/lib/site-mcp-probes.mjs +159 -0
- package/cli/lib/site-mcp-readiness.mjs +157 -0
- package/cli/lib/site-mcp-report.mjs +324 -0
- package/cli/lib/site-next-actions.mjs +333 -0
- package/cli/lib/site-options.mjs +104 -0
- package/cli/lib/site-prompts.mjs +332 -0
- package/cli/lib/site-starter.mjs +153 -0
- package/cli/lib/site-strings.mjs +23 -0
- package/cli/lib/site-tasks.mjs +93 -0
- package/cli/lib/site-test-support.mjs +68 -0
- package/cli/lib/site-workflow-graph.mjs +309 -0
- package/cli/lib/site-workspace.mjs +492 -0
- package/cli/lib/site.mjs +108 -6617
- package/cli/lib/skill-proposals-apply-commands.mjs +135 -0
- package/cli/lib/skill-proposals-apply-contract.mjs +750 -0
- package/cli/lib/skill-proposals-apply-plan.mjs +118 -0
- package/cli/lib/skill-proposals-generate.mjs +298 -0
- package/cli/lib/skill-proposals-render.mjs +532 -0
- package/cli/lib/skill-proposals-review.mjs +262 -0
- package/cli/lib/skill-proposals.mjs +15 -2046
- package/cli/lib/workspace-args.mjs +83 -0
- package/cli/lib/workspace-git.mjs +169 -0
- package/cli/lib/workspace-learning.mjs +483 -0
- package/cli/lib/workspace-repo.mjs +139 -0
- package/cli/lib/workspace-report.mjs +283 -0
- package/cli/lib/workspace-test-support.mjs +99 -0
- package/cli/lib/workspace.mjs +30 -1056
- package/docs/AI-LEARNING-PHASE2.md +215 -0
- package/docs/DISTRIBUTION.ko.md +35 -6
- package/docs/DISTRIBUTION.md +35 -8
- package/docs/NEXT-SURFACE-DECISION.md +125 -0
- package/docs/PRODUCT-READINESS.md +3 -3
- package/docs/RELEASE-CHECKLIST.md +20 -3
- package/docs/RELEASE-GATES.ko.md +35 -0
- package/docs/RELEASE-GATES.md +234 -0
- package/docs/ROADMAP.md +2232 -8
- package/docs/external-status.md +20 -7
- package/docs/inspection-20260630.md +169 -0
- package/docs/integrations/design-ai-mcp-server.md +35 -3
- package/docs/integrations/vscode-walkthrough.ko.md +3 -3
- package/docs/integrations/vscode-walkthrough.md +3 -3
- package/docs/reference/ant-design.md +413 -0
- package/docs/reference/awesome-design-md.md +439 -0
- package/docs/reference/mui.md +783 -0
- package/docs/reference/shadcn-ui.md +298 -0
- package/docs/site-overrides/main.html +1 -1
- package/examples/component-accordion-actions.md +5 -5
- package/examples/component-accordion-details.md +5 -5
- package/examples/component-accordion-summary.md +5 -5
- package/examples/component-accordion.md +3 -3
- package/examples/component-affix.md +1 -1
- package/examples/component-alert-dialog.md +1 -1
- package/examples/component-alert-title.md +1 -1
- package/examples/component-alert.md +3 -3
- package/examples/component-anchor.md +1 -1
- package/examples/component-app-bar.md +1 -1
- package/examples/component-aspect-ratio.md +1 -1
- package/examples/component-auto-complete.md +2 -2
- package/examples/component-avatar-group.md +5 -5
- package/examples/component-avatar.md +3 -3
- package/examples/component-back-top.md +1 -1
- package/examples/component-backdrop.md +1 -1
- package/examples/component-badge.md +3 -3
- package/examples/component-border-beam.md +3 -3
- package/examples/component-bottom-navigation.md +1 -1
- package/examples/component-box.md +1 -1
- package/examples/component-breadcrumb.md +3 -3
- package/examples/component-button-base.md +3 -3
- package/examples/component-button-group.md +2 -2
- package/examples/component-button.md +3 -3
- package/examples/component-calendar.md +2 -2
- package/examples/component-card-actions.md +1 -1
- package/examples/component-card-content.md +1 -1
- package/examples/component-card-header.md +1 -1
- package/examples/component-card-media.md +1 -1
- package/examples/component-card.md +3 -3
- package/examples/component-carousel.md +2 -2
- package/examples/component-cascader.md +1 -1
- package/examples/component-chart.md +1 -1
- package/examples/component-checkbox.md +3 -3
- package/examples/component-click-away-listener.md +1 -1
- package/examples/component-code.md +1 -1
- package/examples/component-collapsible.md +1 -1
- package/examples/component-color-picker.md +1 -1
- package/examples/component-combobox.md +1 -1
- package/examples/component-command.md +1 -1
- package/examples/component-config-provider.md +3 -3
- package/examples/component-context-menu.md +1 -1
- package/examples/component-css-baseline.md +3 -3
- package/examples/component-date-picker.md +2 -2
- package/examples/component-descriptions.md +1 -1
- package/examples/component-dialog-actions.md +1 -1
- package/examples/component-dialog-content-text.md +1 -1
- package/examples/component-dialog-content.md +1 -1
- package/examples/component-dialog-title.md +1 -1
- package/examples/component-dialog.md +2 -2
- package/examples/component-divider.md +3 -3
- package/examples/component-drawer.md +3 -3
- package/examples/component-dropdown.md +3 -3
- package/examples/component-empty.md +2 -2
- package/examples/component-fade.md +1 -1
- package/examples/component-field.md +1 -1
- package/examples/component-filled-input.md +1 -1
- package/examples/component-flex.md +1 -1
- package/examples/component-float-button.md +2 -2
- package/examples/component-form-control-label.md +1 -1
- package/examples/component-form-control.md +1 -1
- package/examples/component-form-controls.md +1 -1
- package/examples/component-form-group.md +1 -1
- package/examples/component-form-helper-text.md +1 -1
- package/examples/component-form-label.md +1 -1
- package/examples/component-form.md +2 -2
- package/examples/component-grid.md +2 -2
- package/examples/component-grow.md +1 -1
- package/examples/component-hover-card.md +1 -1
- package/examples/component-icon-button.md +1 -1
- package/examples/component-icon.md +1 -1
- package/examples/component-image-list.md +1 -1
- package/examples/component-image.md +1 -1
- package/examples/component-input-adornment.md +1 -1
- package/examples/component-input-base.md +1 -1
- package/examples/component-input-number.md +1 -1
- package/examples/component-input-otp.md +2 -2
- package/examples/component-input.md +3 -3
- package/examples/component-item.md +1 -1
- package/examples/component-label.md +1 -1
- package/examples/component-layout.md +1 -1
- package/examples/component-link.md +1 -1
- package/examples/component-list-item-avatar.md +1 -1
- package/examples/component-list-item-button.md +1 -1
- package/examples/component-list-item-icon.md +1 -1
- package/examples/component-list-item-text.md +1 -1
- package/examples/component-list-item.md +1 -1
- package/examples/component-list-subheader.md +1 -1
- package/examples/component-list.md +2 -2
- package/examples/component-masonry.md +1 -1
- package/examples/component-mentions.md +1 -1
- package/examples/component-menu-item.md +1 -1
- package/examples/component-menu-list.md +1 -1
- package/examples/component-menu.md +1 -1
- package/examples/component-menubar.md +1 -1
- package/examples/component-message.md +1 -1
- package/examples/component-mobile-stepper.md +1 -1
- package/examples/component-modal.md +5 -5
- package/examples/component-navigation-menu.md +1 -1
- package/examples/component-notification.md +1 -1
- package/examples/component-outlined-input.md +1 -1
- package/examples/component-pagination.md +3 -3
- package/examples/component-paper.md +1 -1
- package/examples/component-popconfirm.md +1 -1
- package/examples/component-popover.md +3 -3
- package/examples/component-popper.md +1 -1
- package/examples/component-progress.md +2 -2
- package/examples/component-qr-code.md +1 -1
- package/examples/component-radio.md +3 -3
- package/examples/component-rate.md +2 -2
- package/examples/component-resizable.md +1 -1
- package/examples/component-result.md +1 -1
- package/examples/component-scroll-area.md +1 -1
- package/examples/component-segmented.md +3 -3
- package/examples/component-select.md +3 -3
- package/examples/component-separator.md +1 -1
- package/examples/component-sheet.md +1 -1
- package/examples/component-sidebar.md +1 -1
- package/examples/component-skeleton.md +3 -3
- package/examples/component-slide.md +1 -1
- package/examples/component-slider.md +3 -3
- package/examples/component-snackbar-content.md +1 -1
- package/examples/component-snackbar.md +1 -1
- package/examples/component-sonner.md +1 -1
- package/examples/component-space.md +1 -1
- package/examples/component-speed-dial-action.md +1 -1
- package/examples/component-speed-dial.md +1 -1
- package/examples/component-spin.md +2 -2
- package/examples/component-spinner.md +1 -1
- package/examples/component-splitter.md +2 -2
- package/examples/component-stack.md +1 -1
- package/examples/component-statistic.md +1 -1
- package/examples/component-step-button.md +4 -4
- package/examples/component-step-connector.md +4 -4
- package/examples/component-step-content.md +1 -1
- package/examples/component-step-icon.md +1 -1
- package/examples/component-step-label.md +1 -1
- package/examples/component-step.md +2 -2
- package/examples/component-steps.md +2 -2
- package/examples/component-swipeable-drawer.md +1 -1
- package/examples/component-switch.md +3 -3
- package/examples/component-tab-scroll-button.md +5 -5
- package/examples/component-tab.md +1 -1
- package/examples/component-table-body.md +1 -1
- package/examples/component-table-cell.md +1 -1
- package/examples/component-table-container.md +1 -1
- package/examples/component-table-footer.md +1 -1
- package/examples/component-table-head.md +1 -1
- package/examples/component-table-pagination.md +1 -1
- package/examples/component-table-row.md +1 -1
- package/examples/component-table-sort-label.md +1 -1
- package/examples/component-table.md +2 -2
- package/examples/component-tabs.md +3 -3
- package/examples/component-tag-badge.md +2 -2
- package/examples/component-tag.md +1 -1
- package/examples/component-textarea-autosize.md +1 -1
- package/examples/component-textarea.md +1 -1
- package/examples/component-time-picker.md +1 -1
- package/examples/component-timeline.md +1 -1
- package/examples/component-toast.md +4 -4
- package/examples/component-toggle-button.md +1 -1
- package/examples/component-toggle.md +1 -1
- package/examples/component-toolbar.md +1 -1
- package/examples/component-tooltip.md +3 -3
- package/examples/component-tour.md +1 -1
- package/examples/component-transfer.md +1 -1
- package/examples/component-tree-select.md +1 -1
- package/examples/component-tree.md +1 -1
- package/examples/component-typography.md +2 -2
- package/examples/component-upload.md +1 -1
- package/examples/component-watermark.md +1 -1
- package/examples/component-zoom.md +1 -1
- package/knowledge/COVERAGE.md +4 -3
- package/knowledge/components/INDEX.md +202 -202
- package/knowledge/patterns/brand-references.md +72 -72
- package/package.json +1 -1
- package/tools/audit/local-ci.py +16 -1
- package/tools/audit/package-smoke.py +717 -9
- package/tools/audit/registry-smoke.py +912 -10
- package/tools/audit/release-metadata.py +47 -1
- package/tools/audit/smoke_assertions.py +998 -35
- package/tools/migrations/refs-links-to-reference-pages.py +179 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// Prompt and handoff report builders for Website Improvement workspaces.
|
|
2
|
+
|
|
3
|
+
import { normalizeImplementationEvidence } from "./site-evidence.mjs";
|
|
4
|
+
import { SITE_PROMPT_TEMPLATE_IDS, SITE_PROMPT_TEMPLATES } from "./site-content.mjs";
|
|
5
|
+
import { AUDIT_CATEGORIES, MCP_ITEMS, PRIORITY_OPTIONS, categoryById } from "./site-options.mjs";
|
|
6
|
+
import { markdownList } from "./site-strings.mjs";
|
|
7
|
+
|
|
8
|
+
export function profileBlock(workspace) {
|
|
9
|
+
const profile = workspace.siteProfile;
|
|
10
|
+
return [
|
|
11
|
+
"Site profile:",
|
|
12
|
+
`- Name: ${profile.name}`,
|
|
13
|
+
`- Live URL: ${profile.liveUrl || "not provided"}`,
|
|
14
|
+
`- Repo URL: ${profile.repoUrl || "not provided"}`,
|
|
15
|
+
`- Local path: ${profile.localPath || "not provided"}`,
|
|
16
|
+
`- Figma URL: ${profile.figmaUrl || "not provided"}`,
|
|
17
|
+
`- Deploy: ${profile.deployProvider}`,
|
|
18
|
+
`- Sentry: ${profile.sentryProject || "not provided"}`,
|
|
19
|
+
`- CMS: ${profile.cms}`,
|
|
20
|
+
`- Database: ${profile.database}`,
|
|
21
|
+
`- Viewports: ${profile.viewports.join(", ")}`,
|
|
22
|
+
"",
|
|
23
|
+
"Priority pages:",
|
|
24
|
+
markdownList(profile.pages, "No pages listed"),
|
|
25
|
+
"",
|
|
26
|
+
"User flows:",
|
|
27
|
+
markdownList(profile.userFlows, "No user flows listed"),
|
|
28
|
+
"",
|
|
29
|
+
"Brand/design notes:",
|
|
30
|
+
profile.brandNotes || "No brand notes provided.",
|
|
31
|
+
].join("\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function auditBlock(workspace) {
|
|
35
|
+
return AUDIT_CATEGORIES.map((category) => {
|
|
36
|
+
const row = workspace.auditChecklist[category.id];
|
|
37
|
+
return [
|
|
38
|
+
`- ${category.label} [${row.status}]`,
|
|
39
|
+
` Notes: ${row.notes || "none"}`,
|
|
40
|
+
` Findings: ${row.findings.length ? row.findings.join("; ") : "none"}`,
|
|
41
|
+
].join("\n");
|
|
42
|
+
}).join("\n");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function mcpBlock(workspace) {
|
|
46
|
+
return MCP_ITEMS.map(([key, label]) => `- ${label}: ${workspace.mcpReadiness[key]}`).join("\n");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function taskBlock(task) {
|
|
50
|
+
if (!task) return "No refactor task selected. Use the Refactor Plan section first.";
|
|
51
|
+
return [
|
|
52
|
+
"Selected task:",
|
|
53
|
+
`- Task ID: ${task.id}`,
|
|
54
|
+
`- Title: ${task.title}`,
|
|
55
|
+
`- Category: ${categoryById(task.category).label}`,
|
|
56
|
+
`- Problem: ${task.problem}`,
|
|
57
|
+
`- Evidence: ${task.evidence || "not provided"}`,
|
|
58
|
+
`- Impact: ${task.impact}`,
|
|
59
|
+
`- Effort: ${task.effort}`,
|
|
60
|
+
`- Priority: ${task.priority}`,
|
|
61
|
+
`- Pages: ${task.pages.join(", ") || "not specified"}`,
|
|
62
|
+
`- Recommended MCP: ${task.recommendedMcp.join(", ") || "none"}`,
|
|
63
|
+
"",
|
|
64
|
+
"Verification:",
|
|
65
|
+
markdownList(task.verification, "Run target repo verification"),
|
|
66
|
+
"",
|
|
67
|
+
"Risks:",
|
|
68
|
+
markdownList(task.risks, "No risks listed"),
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function primaryTask(workspace) {
|
|
73
|
+
return orderedRefactorTasks(workspace)[0] || null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function orderedRefactorTasks(workspace) {
|
|
77
|
+
return workspace.refactorTasks
|
|
78
|
+
.map((task, index) => ({ task, index }))
|
|
79
|
+
.sort((a, b) => {
|
|
80
|
+
const priorityDelta = PRIORITY_OPTIONS.indexOf(a.task.priority) - PRIORITY_OPTIONS.indexOf(b.task.priority);
|
|
81
|
+
if (priorityDelta !== 0) return priorityDelta;
|
|
82
|
+
return a.index - b.index;
|
|
83
|
+
})
|
|
84
|
+
.map((item) => item.task);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function resolveSitePromptTask(workspace, selector = "") {
|
|
88
|
+
const tasks = orderedRefactorTasks(workspace);
|
|
89
|
+
const trimmed = String(selector || "").trim();
|
|
90
|
+
if (!trimmed) return primaryTask(workspace);
|
|
91
|
+
|
|
92
|
+
const byId = workspace.refactorTasks.find((task) => task.id === trimmed);
|
|
93
|
+
if (byId) return byId;
|
|
94
|
+
|
|
95
|
+
if (/^[1-9]\d*$/.test(trimmed)) {
|
|
96
|
+
const index = Number.parseInt(trimmed, 10) - 1;
|
|
97
|
+
if (tasks[index]) return tasks[index];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const ids = tasks.map((task, index) => `${index + 1}:${task.id}`).join(", ");
|
|
101
|
+
throw new Error(`Unknown refactor task: ${trimmed}. Use one of: ${ids || "no tasks available"}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function buildSitePrompt(workspace, templateId, { taskSelector = "" } = {}) {
|
|
105
|
+
const profile = profileBlock(workspace);
|
|
106
|
+
const audit = auditBlock(workspace);
|
|
107
|
+
const mcp = mcpBlock(workspace);
|
|
108
|
+
const task = taskBlock(resolveSitePromptTask(workspace, taskSelector));
|
|
109
|
+
const commonRules = [
|
|
110
|
+
"Rules:",
|
|
111
|
+
"- Work in the target website repository, not in this design-ai repository.",
|
|
112
|
+
"- Inspect existing architecture, components, state, styling, and design tokens before editing.",
|
|
113
|
+
"- Keep changes scoped and avoid new dependencies unless clearly justified.",
|
|
114
|
+
"- Preserve accessibility: keyboard reachability, visible focus, semantic HTML, screen-reader labels, and WCAG 2.1 AA contrast.",
|
|
115
|
+
"- Verify desktop, tablet, and mobile layouts.",
|
|
116
|
+
].join("\n");
|
|
117
|
+
|
|
118
|
+
const map = {
|
|
119
|
+
"codex-repo-intake": [
|
|
120
|
+
"# Codex repo intake prompt",
|
|
121
|
+
profile,
|
|
122
|
+
"",
|
|
123
|
+
"Goal: inspect the target website repo and produce a concise implementation plan for website improvement work.",
|
|
124
|
+
"",
|
|
125
|
+
commonRules,
|
|
126
|
+
"",
|
|
127
|
+
"Read first:",
|
|
128
|
+
"- package/dependency manifest",
|
|
129
|
+
"- app/router entrypoints",
|
|
130
|
+
"- layout and design system primitives",
|
|
131
|
+
"- styling/token setup",
|
|
132
|
+
"- test/build scripts",
|
|
133
|
+
"",
|
|
134
|
+
"Return: repo structure, routing, reusable components, state/data model, likely touch points, risks, and exact verification commands.",
|
|
135
|
+
],
|
|
136
|
+
"codex-implementation": [
|
|
137
|
+
"# Codex implementation prompt",
|
|
138
|
+
profile,
|
|
139
|
+
"",
|
|
140
|
+
task,
|
|
141
|
+
"",
|
|
142
|
+
commonRules,
|
|
143
|
+
"",
|
|
144
|
+
"Implement the smallest safe fix. After editing, run the target repo's most relevant lint/typecheck/build/test command and summarize changed files plus verification.",
|
|
145
|
+
],
|
|
146
|
+
"codex-visual-qa": [
|
|
147
|
+
"# Codex visual QA prompt",
|
|
148
|
+
profile,
|
|
149
|
+
"",
|
|
150
|
+
"Audit checklist state:",
|
|
151
|
+
audit,
|
|
152
|
+
"",
|
|
153
|
+
`Use Browser/Playwright if available. Verify the priority pages across ${workspace.siteProfile.viewports.join(", ")}. Check layout, typography, CTA hierarchy, forms, focus indicators, console errors, and broken assets.`,
|
|
154
|
+
],
|
|
155
|
+
"codex-deployment": [
|
|
156
|
+
"# Codex deployment verification prompt",
|
|
157
|
+
profile,
|
|
158
|
+
"",
|
|
159
|
+
"MCP readiness:",
|
|
160
|
+
mcp,
|
|
161
|
+
"",
|
|
162
|
+
"Verify the deployment or preview URL, runtime logs, environment assumptions, SEO metadata, and major user flows. Report pass/fail evidence and remaining launch risks.",
|
|
163
|
+
],
|
|
164
|
+
"claude-design-review": [
|
|
165
|
+
"# Claude design review prompt",
|
|
166
|
+
profile,
|
|
167
|
+
"",
|
|
168
|
+
"Review the live site or screenshots as a senior product designer. Focus on visual hierarchy, layout rhythm, typography, color, spacing, CTA clarity, responsive behavior, and accessibility concerns. Provide one best path and cite concrete evidence.",
|
|
169
|
+
],
|
|
170
|
+
"claude-competitor": [
|
|
171
|
+
"# Claude competitor research prompt",
|
|
172
|
+
profile,
|
|
173
|
+
"",
|
|
174
|
+
"Research 3-5 relevant competitors or peer websites. Compare homepage structure, conversion path, proof points, pricing presentation, visual tone, content clarity, and SEO positioning. Return a concise opportunity map, not a generic benchmark.",
|
|
175
|
+
],
|
|
176
|
+
"claude-copy-ux": [
|
|
177
|
+
"# Claude copy/UX critique prompt",
|
|
178
|
+
profile,
|
|
179
|
+
"",
|
|
180
|
+
"Critique the site's copy, information architecture, trust signals, CTA language, and conversion flow. Rewrite only the highest-impact sections and explain why the edits reduce user uncertainty.",
|
|
181
|
+
],
|
|
182
|
+
"handoff-report": [
|
|
183
|
+
"# Final handoff report prompt",
|
|
184
|
+
profile,
|
|
185
|
+
"",
|
|
186
|
+
"Refactor plan:",
|
|
187
|
+
workspace.refactorTasks.map((item) => `- [${item.priority}] ${item.title}: ${item.problem}`).join("\n") || "- No tasks listed",
|
|
188
|
+
"",
|
|
189
|
+
"Create a final handoff report with target site info, audit summary, priority recommendations, executed work, verification results, remaining risks, and next actions.",
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return (map[templateId] || map["codex-repo-intake"]).join("\n");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function buildSitePromptBundle(workspace) {
|
|
197
|
+
return [
|
|
198
|
+
`# Website improvement prompt bundle: ${workspace.siteProfile.name}`,
|
|
199
|
+
"",
|
|
200
|
+
"> Generated by design-ai site from a Website Improvement Console workspace export.",
|
|
201
|
+
"",
|
|
202
|
+
...SITE_PROMPT_TEMPLATE_IDS.flatMap((templateId) => [
|
|
203
|
+
`## ${templateId}`,
|
|
204
|
+
"",
|
|
205
|
+
buildSitePrompt(workspace, templateId),
|
|
206
|
+
"",
|
|
207
|
+
]),
|
|
208
|
+
].join("\n").trimEnd();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function buildSiteBundleImplementationPrompt(workspace) {
|
|
212
|
+
const tasks = orderedRefactorTasks(workspace);
|
|
213
|
+
if (tasks.length > 0) {
|
|
214
|
+
return buildSitePrompt(workspace, "codex-implementation", { taskSelector: "1" });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return [
|
|
218
|
+
"# Codex implementation prompt",
|
|
219
|
+
profileBlock(workspace),
|
|
220
|
+
"",
|
|
221
|
+
mcpBlock(workspace),
|
|
222
|
+
"",
|
|
223
|
+
"Task ID: no-refactor-task-yet",
|
|
224
|
+
"Goal: inspect the target website repository, confirm the website improvement workspace facts, and produce concrete audit findings before implementation starts.",
|
|
225
|
+
"",
|
|
226
|
+
"Rules:",
|
|
227
|
+
"- Work in the target website repository, not in this design-ai repository.",
|
|
228
|
+
"- Do not modify production code until you identify specific audit findings and implementation tasks.",
|
|
229
|
+
"- Inspect existing architecture, components, state, styling, and design tokens before proposing edits.",
|
|
230
|
+
"- Preserve accessibility: keyboard reachability, visible focus, semantic HTML, screen-reader labels, and WCAG 2.1 AA contrast.",
|
|
231
|
+
"- Verify desktop, tablet, and mobile layouts before recommending implementation scope.",
|
|
232
|
+
"",
|
|
233
|
+
"Next step:",
|
|
234
|
+
"- Add audit findings to the Website Improvement workspace, then run `design-ai site website-workspace.json --tasks --out website-workspace.tasks.json` and regenerate this implementation prompt with `design-ai site website-workspace.tasks.json --prompt codex-implementation --task 1 --out codex-implementation.md`.",
|
|
235
|
+
].join("\n");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function formatSitePromptTemplatesJson() {
|
|
239
|
+
return JSON.stringify({
|
|
240
|
+
count: SITE_PROMPT_TEMPLATES.length,
|
|
241
|
+
templates: SITE_PROMPT_TEMPLATES,
|
|
242
|
+
}, null, 2);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function formatSitePromptTemplatesHuman() {
|
|
246
|
+
return [
|
|
247
|
+
"Website Improvement prompt templates",
|
|
248
|
+
"",
|
|
249
|
+
...SITE_PROMPT_TEMPLATES.flatMap((template, index) => [
|
|
250
|
+
`${index + 1}. ${template.id}`,
|
|
251
|
+
` Label: ${template.label}`,
|
|
252
|
+
` Agent: ${template.agent}`,
|
|
253
|
+
` Output: ${template.output}`,
|
|
254
|
+
` Task selectable: ${template.taskSelectable ? "yes" : "no"}`,
|
|
255
|
+
` ${template.description}`,
|
|
256
|
+
]),
|
|
257
|
+
"",
|
|
258
|
+
"Use:",
|
|
259
|
+
" design-ai site <workspace.json> --prompt <template-id>",
|
|
260
|
+
" design-ai site <workspace.json> --prompt codex-implementation --task <id-or-number>",
|
|
261
|
+
].join("\n");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function buildSiteHandoffReport(workspace) {
|
|
265
|
+
const profile = workspace.siteProfile;
|
|
266
|
+
const tasks = workspace.refactorTasks;
|
|
267
|
+
const evidence = normalizeImplementationEvidence(workspace.implementationEvidence);
|
|
268
|
+
return [
|
|
269
|
+
`# Website improvement handoff: ${profile.name}`,
|
|
270
|
+
"",
|
|
271
|
+
"> Generated by design-ai site from a Website Improvement Console workspace export.",
|
|
272
|
+
"",
|
|
273
|
+
"## Target site",
|
|
274
|
+
"",
|
|
275
|
+
`- Live URL: ${profile.liveUrl || "not provided"}`,
|
|
276
|
+
`- Repo URL: ${profile.repoUrl || "not provided"}`,
|
|
277
|
+
`- Local path: ${profile.localPath || "not provided"}`,
|
|
278
|
+
`- Figma URL: ${profile.figmaUrl || "not provided"}`,
|
|
279
|
+
`- Deploy provider: ${profile.deployProvider}`,
|
|
280
|
+
`- CMS: ${profile.cms}`,
|
|
281
|
+
`- Database: ${profile.database}`,
|
|
282
|
+
`- Viewports: ${profile.viewports.join(", ")}`,
|
|
283
|
+
"",
|
|
284
|
+
"## Diagnostic summary",
|
|
285
|
+
"",
|
|
286
|
+
auditBlock(workspace),
|
|
287
|
+
"",
|
|
288
|
+
"## MCP Readiness",
|
|
289
|
+
"",
|
|
290
|
+
mcpBlock(workspace),
|
|
291
|
+
"",
|
|
292
|
+
"## Priority improvement plan",
|
|
293
|
+
"",
|
|
294
|
+
tasks.length ? tasks.map((task) => [
|
|
295
|
+
`### [${task.priority.toUpperCase()}] ${task.title}`,
|
|
296
|
+
"",
|
|
297
|
+
`- Category: ${categoryById(task.category).label}`,
|
|
298
|
+
`- Impact: ${task.impact}`,
|
|
299
|
+
`- Effort: ${task.effort}`,
|
|
300
|
+
`- Pages: ${task.pages.join(", ") || "not specified"}`,
|
|
301
|
+
`- MCP: ${task.recommendedMcp.join(", ") || "none"}`,
|
|
302
|
+
`- Problem: ${task.problem}`,
|
|
303
|
+
`- Evidence: ${task.evidence || "not provided"}`,
|
|
304
|
+
"",
|
|
305
|
+
"Verification:",
|
|
306
|
+
markdownList(task.verification, "Run target repo verification"),
|
|
307
|
+
"",
|
|
308
|
+
"Risks:",
|
|
309
|
+
markdownList(task.risks, "No risks listed"),
|
|
310
|
+
].join("\n")).join("\n\n") : "No refactor tasks generated yet.",
|
|
311
|
+
"",
|
|
312
|
+
"## Executed work",
|
|
313
|
+
"",
|
|
314
|
+
markdownList(evidence.executedWork, "Not recorded yet. Add implementation notes after running Codex in the target repo."),
|
|
315
|
+
"",
|
|
316
|
+
"## Verification results",
|
|
317
|
+
"",
|
|
318
|
+
markdownList(evidence.verificationResults, "Not recorded yet. Paste target repo lint/typecheck/build, Browser QA, and deployment checks here."),
|
|
319
|
+
"",
|
|
320
|
+
"## Remaining risks",
|
|
321
|
+
"",
|
|
322
|
+
markdownList(evidence.remainingRisks, "No remaining risks recorded."),
|
|
323
|
+
"",
|
|
324
|
+
"## Next actions",
|
|
325
|
+
"",
|
|
326
|
+
markdownList(evidence.nextActions, "No next actions recorded."),
|
|
327
|
+
"",
|
|
328
|
+
"## Notes",
|
|
329
|
+
"",
|
|
330
|
+
workspace.reportNotes || "No notes recorded.",
|
|
331
|
+
].join("\n");
|
|
332
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Starter artifacts for Website Improvement workspaces.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SITE_INTAKE_TEMPLATE_MARKDOWN,
|
|
5
|
+
SITE_INTAKE_TEMPLATE_MARKDOWN_KO,
|
|
6
|
+
SITE_INTAKE_TEMPLATE_SECTIONS,
|
|
7
|
+
} from "./site-content.mjs";
|
|
8
|
+
import { DEFAULT_IMPLEMENTATION_RISKS } from "./site-evidence.mjs";
|
|
9
|
+
import { SITE_INTAKE_TEMPLATE_LANGUAGE_OPTIONS } from "./site-options.mjs";
|
|
10
|
+
|
|
11
|
+
export function buildSiteIntakeTemplateMarkdown({ language = "en" } = {}) {
|
|
12
|
+
if (!SITE_INTAKE_TEMPLATE_LANGUAGE_OPTIONS.includes(language)) {
|
|
13
|
+
throw new Error(`language must be one of: ${SITE_INTAKE_TEMPLATE_LANGUAGE_OPTIONS.join(", ")}`);
|
|
14
|
+
}
|
|
15
|
+
return language === "ko" ? SITE_INTAKE_TEMPLATE_MARKDOWN_KO : SITE_INTAKE_TEMPLATE_MARKDOWN;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function formatSiteIntakeTemplateJson({ language = "en" } = {}) {
|
|
19
|
+
const content = buildSiteIntakeTemplateMarkdown({ language });
|
|
20
|
+
return JSON.stringify({
|
|
21
|
+
kind: "website-improvement-intake-template",
|
|
22
|
+
version: 1,
|
|
23
|
+
format: "markdown",
|
|
24
|
+
language,
|
|
25
|
+
recommendedFileName: language === "ko" ? "company-website-intake.ko.md" : "company-website-intake.md",
|
|
26
|
+
sections: SITE_INTAKE_TEMPLATE_SECTIONS,
|
|
27
|
+
privacy: {
|
|
28
|
+
storesCredentials: false,
|
|
29
|
+
storesProductionSecrets: false,
|
|
30
|
+
storesCustomerData: false,
|
|
31
|
+
},
|
|
32
|
+
commands: {
|
|
33
|
+
nextActions: "design-ai site --init --name \"<site name>\" --live-url <live-url> --local-path <absolute-target-repo-path> --next-actions --out website-next-actions.md --force",
|
|
34
|
+
bundle: "design-ai site --init --name \"<site name>\" --live-url <live-url> --local-path <absolute-target-repo-path> --bundle --out website-handoff-bundle --strict --force",
|
|
35
|
+
bundleCheck: "design-ai site website-handoff-bundle --bundle-check --strict --json --out website-bundle-check.json --force",
|
|
36
|
+
bundleHandoff: "design-ai site website-handoff-bundle --bundle-handoff --strict --out target-repo-handoff.md --force",
|
|
37
|
+
},
|
|
38
|
+
content,
|
|
39
|
+
}, null, 2);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function createSampleSiteWorkspace() {
|
|
43
|
+
return {
|
|
44
|
+
version: 1,
|
|
45
|
+
updatedAt: "2026-05-30T00:00:00.000Z",
|
|
46
|
+
siteProfile: {
|
|
47
|
+
id: "sample-korean-saas",
|
|
48
|
+
name: "Korean SaaS marketing site",
|
|
49
|
+
liveUrl: "https://example.com",
|
|
50
|
+
repoUrl: "https://github.com/acme/korean-saas-site",
|
|
51
|
+
localPath: "/Users/you/dev/korean-saas-site",
|
|
52
|
+
figmaUrl: "https://figma.com/file/example",
|
|
53
|
+
brandNotes: "Quiet B2B SaaS tone, Pretendard typography, dense but readable Korean product copy, indigo accent only for action and focus.",
|
|
54
|
+
deployProvider: "vercel",
|
|
55
|
+
sentryProject: "acme/korean-saas-web",
|
|
56
|
+
cms: "sanity",
|
|
57
|
+
database: "none",
|
|
58
|
+
pages: ["/", "/pricing", "/signup", "/docs"],
|
|
59
|
+
userFlows: [
|
|
60
|
+
"Visitor compares pricing and starts signup",
|
|
61
|
+
"Existing customer finds feature proof before contacting sales",
|
|
62
|
+
],
|
|
63
|
+
viewports: ["desktop", "tablet", "mobile"],
|
|
64
|
+
},
|
|
65
|
+
auditChecklist: {
|
|
66
|
+
"visual-design": {
|
|
67
|
+
status: "in-progress",
|
|
68
|
+
notes: "Hero hierarchy and CTA contrast need review before company pilot.",
|
|
69
|
+
findings: ["Primary CTA competes with secondary link on the homepage"],
|
|
70
|
+
},
|
|
71
|
+
"ux-flow": {
|
|
72
|
+
status: "todo",
|
|
73
|
+
notes: "Map visitor path from landing page to pricing and signup.",
|
|
74
|
+
findings: [],
|
|
75
|
+
},
|
|
76
|
+
responsive: {
|
|
77
|
+
status: "todo",
|
|
78
|
+
notes: "Check 1440, 1024, 390, and 360 width layouts.",
|
|
79
|
+
findings: [],
|
|
80
|
+
},
|
|
81
|
+
accessibility: {
|
|
82
|
+
status: "todo",
|
|
83
|
+
notes: "Keyboard and focus audit required for nav, pricing toggle, and forms.",
|
|
84
|
+
findings: ["Focus state is not yet documented for the mobile menu"],
|
|
85
|
+
},
|
|
86
|
+
performance: {
|
|
87
|
+
status: "todo",
|
|
88
|
+
notes: "Run Lighthouse after visual pass.",
|
|
89
|
+
findings: [],
|
|
90
|
+
},
|
|
91
|
+
seo: {
|
|
92
|
+
status: "todo",
|
|
93
|
+
notes: "Inspect title, description, heading order, canonical, OG.",
|
|
94
|
+
findings: [],
|
|
95
|
+
},
|
|
96
|
+
"technical-quality": {
|
|
97
|
+
status: "todo",
|
|
98
|
+
notes: "Confirm component reuse before editing target repo.",
|
|
99
|
+
findings: [],
|
|
100
|
+
},
|
|
101
|
+
"runtime-issues": {
|
|
102
|
+
status: "todo",
|
|
103
|
+
notes: "Open console/network once preview deploy is available.",
|
|
104
|
+
findings: [],
|
|
105
|
+
},
|
|
106
|
+
"content-quality": {
|
|
107
|
+
status: "in-progress",
|
|
108
|
+
notes: "Copy should lead with proof and reduce generic SaaS phrasing.",
|
|
109
|
+
findings: ["Pricing page does not explain plan fit in the first viewport"],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
mcpReadiness: {
|
|
113
|
+
github: "required",
|
|
114
|
+
figma: "optional",
|
|
115
|
+
browser: "required",
|
|
116
|
+
chromeDevtools: "optional",
|
|
117
|
+
deploy: "required",
|
|
118
|
+
sentry: "optional",
|
|
119
|
+
database: "unused",
|
|
120
|
+
cms: "optional",
|
|
121
|
+
collaboration: "optional",
|
|
122
|
+
research: "optional",
|
|
123
|
+
},
|
|
124
|
+
refactorTasks: [
|
|
125
|
+
{
|
|
126
|
+
id: "task-homepage-cta",
|
|
127
|
+
title: "Clarify homepage CTA hierarchy",
|
|
128
|
+
category: "visual-design",
|
|
129
|
+
problem: "Primary and secondary actions compete in the hero, which weakens the visitor's first decision.",
|
|
130
|
+
evidence: "Sample finding: Primary CTA competes with secondary link on the homepage.",
|
|
131
|
+
impact: "high",
|
|
132
|
+
effort: "medium",
|
|
133
|
+
priority: "p1",
|
|
134
|
+
pages: ["/"],
|
|
135
|
+
recommendedMcp: ["browser", "figma"],
|
|
136
|
+
codexPrompt: "Inspect the target homepage implementation, preserve existing design system patterns, and revise the hero CTA hierarchy so the primary signup action is visually dominant while the secondary action remains available.",
|
|
137
|
+
verification: [
|
|
138
|
+
"Run target repo lint/build",
|
|
139
|
+
"Verify desktop/tablet/mobile hero layout",
|
|
140
|
+
"Confirm focus indicators and text contrast",
|
|
141
|
+
],
|
|
142
|
+
risks: ["Could change conversion copy without stakeholder approval"],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
implementationEvidence: {
|
|
146
|
+
executedWork: [],
|
|
147
|
+
verificationResults: [],
|
|
148
|
+
remainingRisks: [...DEFAULT_IMPLEMENTATION_RISKS],
|
|
149
|
+
nextActions: [],
|
|
150
|
+
},
|
|
151
|
+
reportNotes: "MVP audit is a planning console. Run the generated prompts inside the target website repo before marking implementation complete.",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Shared string helpers for Website Improvement workspace reports.
|
|
2
|
+
|
|
3
|
+
export function normalizeStringArray(value, fallback = []) {
|
|
4
|
+
const source = Array.isArray(value) ? value : fallback;
|
|
5
|
+
return source
|
|
6
|
+
.map((item) => String(item || "").trim())
|
|
7
|
+
.filter(Boolean);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function markdownTable(headers, rows) {
|
|
11
|
+
const escapeCell = (value) => String(value || "").replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
12
|
+
return [
|
|
13
|
+
`| ${headers.map(escapeCell).join(" | ")} |`,
|
|
14
|
+
`| ${headers.map(() => "---").join(" | ")} |`,
|
|
15
|
+
...rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`),
|
|
16
|
+
].join("\n");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function markdownList(items, fallback) {
|
|
20
|
+
const normalized = normalizeStringArray(items);
|
|
21
|
+
if (normalized.length === 0) return `- ${fallback}`;
|
|
22
|
+
return normalized.map((item) => `- ${item}`).join("\n");
|
|
23
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Website Improvement task generation helpers.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AUDIT_CATEGORIES,
|
|
5
|
+
categoryById,
|
|
6
|
+
} from "./site-options.mjs";
|
|
7
|
+
import { normalizeSiteWorkspace } from "./site-workspace.mjs";
|
|
8
|
+
|
|
9
|
+
function recommendedMcpForCategory(categoryId) {
|
|
10
|
+
const map = {
|
|
11
|
+
"visual-design": ["browser", "figma"],
|
|
12
|
+
"ux-flow": ["browser", "github"],
|
|
13
|
+
responsive: ["browser", "chromeDevtools"],
|
|
14
|
+
accessibility: ["browser", "chromeDevtools"],
|
|
15
|
+
performance: ["chromeDevtools", "deploy"],
|
|
16
|
+
seo: ["browser", "deploy"],
|
|
17
|
+
"technical-quality": ["github"],
|
|
18
|
+
"runtime-issues": ["browser", "chromeDevtools", "sentry"],
|
|
19
|
+
"content-quality": ["figma", "research", "cms"],
|
|
20
|
+
};
|
|
21
|
+
return map[categoryId] || ["github"];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function buildCodexTaskPrompt(workspace, categoryId, finding) {
|
|
25
|
+
const profile = workspace.siteProfile;
|
|
26
|
+
return [
|
|
27
|
+
"You are working in the target website repo, not in design-ai.",
|
|
28
|
+
`Site: ${profile.name}`,
|
|
29
|
+
`Live URL: ${profile.liveUrl}`,
|
|
30
|
+
`Category: ${categoryById(categoryId).label}`,
|
|
31
|
+
`Problem: ${finding}`,
|
|
32
|
+
"",
|
|
33
|
+
"Inspect the target repo first. Reuse existing architecture, UI components, state patterns, styling conventions, and design tokens. Do not add dependencies unless the existing codebase clearly requires them.",
|
|
34
|
+
"",
|
|
35
|
+
"Implement the smallest safe improvement, then verify desktop/tablet/mobile behavior, keyboard focus, screen-reader semantics where relevant, and the target repo's lint/typecheck/build commands.",
|
|
36
|
+
].join("\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function taskFromCategory(workspace, category, finding) {
|
|
40
|
+
const priority = category.id === "accessibility" || category.id === "runtime-issues" ? "p0" : "p1";
|
|
41
|
+
const impact = priority === "p0" ? "high" : "medium";
|
|
42
|
+
return {
|
|
43
|
+
id: `task-${category.id}`,
|
|
44
|
+
title: `Resolve ${category.label} finding`,
|
|
45
|
+
category: category.id,
|
|
46
|
+
problem: finding,
|
|
47
|
+
evidence: "Audit finding captured in the Website Improvement Console.",
|
|
48
|
+
impact,
|
|
49
|
+
effort: "medium",
|
|
50
|
+
priority,
|
|
51
|
+
pages: workspace.siteProfile.pages.slice(0, 3),
|
|
52
|
+
recommendedMcp: recommendedMcpForCategory(category.id),
|
|
53
|
+
codexPrompt: buildCodexTaskPrompt(workspace, category.id, finding),
|
|
54
|
+
verification: [
|
|
55
|
+
...category.defaultVerification,
|
|
56
|
+
"Run target repo lint/typecheck/build when available",
|
|
57
|
+
],
|
|
58
|
+
risks: [
|
|
59
|
+
"Target repo architecture may constrain the fix",
|
|
60
|
+
"Manual stakeholder review may be needed before changing copy or brand language",
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function generateSiteRefactorTasks(workspaceInput) {
|
|
66
|
+
const workspace = normalizeSiteWorkspace(workspaceInput);
|
|
67
|
+
const existingIds = new Set(workspace.refactorTasks.map((task) => task.id));
|
|
68
|
+
const existingCategories = new Set(workspace.refactorTasks.map((task) => task.category));
|
|
69
|
+
const created = [];
|
|
70
|
+
|
|
71
|
+
for (const category of AUDIT_CATEGORIES) {
|
|
72
|
+
if (existingCategories.has(category.id)) continue;
|
|
73
|
+
const row = workspace.auditChecklist[category.id];
|
|
74
|
+
const findings = row.findings;
|
|
75
|
+
if (findings.length === 0) continue;
|
|
76
|
+
|
|
77
|
+
const task = taskFromCategory(workspace, category, findings[0]);
|
|
78
|
+
if (existingIds.has(task.id)) continue;
|
|
79
|
+
created.push(task);
|
|
80
|
+
existingIds.add(task.id);
|
|
81
|
+
existingCategories.add(category.id);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
workspace: {
|
|
86
|
+
...workspace,
|
|
87
|
+
updatedAt: workspace.updatedAt,
|
|
88
|
+
refactorTasks: workspace.refactorTasks.concat(created),
|
|
89
|
+
},
|
|
90
|
+
created,
|
|
91
|
+
skippedCount: AUDIT_CATEGORIES.filter((category) => existingCategories.has(category.id)).length - created.length,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Shared test helpers for the site.* test suite.
|
|
2
|
+
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
SITE_BUNDLE_CHECKSUM_FILES,
|
|
10
|
+
analyzeSiteWorkspace,
|
|
11
|
+
buildSiteBundleHandoffReport,
|
|
12
|
+
buildSiteHandoffBundle,
|
|
13
|
+
createSampleSiteWorkspace,
|
|
14
|
+
formatSiteBundleHandoffHuman,
|
|
15
|
+
formatSiteBundleHandoffJson,
|
|
16
|
+
} from "./site.mjs";
|
|
17
|
+
|
|
18
|
+
export function sha256HexForTest(content) {
|
|
19
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export function bundleDigestForTest(checksumFiles) {
|
|
24
|
+
const manifest = SITE_BUNDLE_CHECKSUM_FILES.map((filePath) => `${filePath}\t${checksumFiles[filePath] || ""}`).join("\n");
|
|
25
|
+
return sha256HexForTest(`${manifest}\n`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function captureConsole(fn) {
|
|
29
|
+
const stdout = [];
|
|
30
|
+
const originalLog = console.log;
|
|
31
|
+
const originalExitCode = process.exitCode;
|
|
32
|
+
console.log = (...args) => {
|
|
33
|
+
stdout.push(args.join(" "));
|
|
34
|
+
};
|
|
35
|
+
process.exitCode = undefined;
|
|
36
|
+
try {
|
|
37
|
+
await fn();
|
|
38
|
+
return {
|
|
39
|
+
stdout: stdout.join("\n"),
|
|
40
|
+
exitCode: process.exitCode,
|
|
41
|
+
};
|
|
42
|
+
} finally {
|
|
43
|
+
console.log = originalLog;
|
|
44
|
+
process.exitCode = originalExitCode;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function withTempDir(fn) {
|
|
49
|
+
const dir = mkdtempSync(path.join(tmpdir(), "design-ai-site-"));
|
|
50
|
+
try {
|
|
51
|
+
return await fn(dir);
|
|
52
|
+
} finally {
|
|
53
|
+
rmSync(dir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function buildHandoffFixture(dir) {
|
|
58
|
+
const workspace = createSampleSiteWorkspace();
|
|
59
|
+
const { summary } = analyzeSiteWorkspace(workspace, { filePath: "stdin" });
|
|
60
|
+
const bundle = buildSiteHandoffBundle(workspace, summary);
|
|
61
|
+
for (const file of bundle.files) {
|
|
62
|
+
writeFileSync(path.join(dir, file.path), file.content, "utf8");
|
|
63
|
+
}
|
|
64
|
+
const report = buildSiteBundleHandoffReport({ target: dir });
|
|
65
|
+
const json = JSON.parse(formatSiteBundleHandoffJson(report));
|
|
66
|
+
const human = formatSiteBundleHandoffHuman(report);
|
|
67
|
+
return { workspace, summary, bundle, report, json, human };
|
|
68
|
+
}
|