@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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +39 -0
- package/README.ko.md +7 -7
- package/README.md +9 -9
- package/cli/lib/mcp-server.mjs +208 -10
- 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-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-stage-metadata.mjs +84 -0
- package/cli/lib/site-bundle-handoff-runbook.mjs +1331 -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-workflow-graph.mjs +309 -0
- package/cli/lib/site-workspace.mjs +492 -0
- package/cli/lib/site.mjs +108 -6617
- package/docs/DISTRIBUTION.ko.md +35 -6
- package/docs/DISTRIBUTION.md +35 -8
- package/docs/RELEASE-CHECKLIST.md +20 -3
- package/docs/ROADMAP.md +2179 -0
- package/docs/external-status.md +22 -7
- package/docs/integrations/design-ai-mcp-server.md +32 -0
- package/docs/integrations/vscode-walkthrough.ko.md +3 -3
- package/docs/integrations/vscode-walkthrough.md +3 -3
- package/docs/site-overrides/main.html +1 -1
- package/package.json +1 -1
- package/tools/audit/package-smoke.py +106 -0
- package/tools/audit/registry-smoke.py +378 -10
- package/tools/audit/smoke_assertions.py +83 -22
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildBundleCheckCommand,
|
|
3
|
+
buildBundleCheckCommandArgs,
|
|
4
|
+
buildBundleHandoffCommand,
|
|
5
|
+
buildBundleHandoffCommandArgs,
|
|
6
|
+
buildBundleSourceCommandSafety,
|
|
7
|
+
buildBundleTaskHandoffCommand,
|
|
8
|
+
buildBundleTaskHandoffCommandArgs,
|
|
9
|
+
buildBundleTaskHandoffCommandSafety,
|
|
10
|
+
taskHandoffOutFile,
|
|
11
|
+
} from "./site-bundle-commands.mjs";
|
|
12
|
+
import { orderedRefactorTasks } from "./site-prompts.mjs";
|
|
13
|
+
import { normalizeStringArray } from "./site-strings.mjs";
|
|
14
|
+
|
|
15
|
+
export const SITE_TARGET_REPO_EXECUTION_CHECKLIST = [
|
|
16
|
+
{
|
|
17
|
+
id: "confirm-target-repo",
|
|
18
|
+
label: "Confirm target repo working directory",
|
|
19
|
+
required: true,
|
|
20
|
+
evidence: "State the target repo path and confirm it is not the design-ai repo before editing.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "inspect-architecture",
|
|
24
|
+
label: "Inspect existing architecture and design system",
|
|
25
|
+
required: true,
|
|
26
|
+
evidence: "Name the routing, component, styling, token, and test/build surfaces inspected before implementation.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "apply-focused-task",
|
|
30
|
+
label: "Apply one focused Website Improvement task",
|
|
31
|
+
required: true,
|
|
32
|
+
evidence: "Identify the completed task id/title, changed files, and why the scope stayed limited.",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "verify-quality-gates",
|
|
36
|
+
label: "Run target repo quality gates",
|
|
37
|
+
required: true,
|
|
38
|
+
evidence: "Record lint/typecheck/build/test results plus browser, viewport, accessibility, and deployment checks that were available.",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "record-handoff-evidence",
|
|
42
|
+
label: "Record implementation evidence and remaining risks",
|
|
43
|
+
required: true,
|
|
44
|
+
evidence: "Return executed work, verification results, remaining risks, next actions, and the bundle digest used.",
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
function summarizeBundleTaskItem(task, index, directory) {
|
|
49
|
+
return {
|
|
50
|
+
number: index + 1,
|
|
51
|
+
id: task.id,
|
|
52
|
+
title: task.title,
|
|
53
|
+
category: task.category,
|
|
54
|
+
priority: task.priority,
|
|
55
|
+
impact: task.impact,
|
|
56
|
+
effort: task.effort,
|
|
57
|
+
pages: normalizeStringArray(task.pages),
|
|
58
|
+
recommendedMcp: normalizeStringArray(task.recommendedMcp),
|
|
59
|
+
handoffTaskArg: task.id,
|
|
60
|
+
handoffOutFile: taskHandoffOutFile(task),
|
|
61
|
+
handoffCommand: buildBundleTaskHandoffCommand(directory, task),
|
|
62
|
+
handoffCommandArgs: buildBundleTaskHandoffCommandArgs(directory, task),
|
|
63
|
+
handoffCommandRunPolicy: "writes-local-file",
|
|
64
|
+
handoffCommandSafety: buildBundleTaskHandoffCommandSafety(task),
|
|
65
|
+
strictHandoffCommand: buildBundleTaskHandoffCommand(directory, task, { strict: true }),
|
|
66
|
+
strictHandoffCommandArgs: buildBundleTaskHandoffCommandArgs(directory, task, { strict: true }),
|
|
67
|
+
strictHandoffCommandRunPolicy: "writes-local-file",
|
|
68
|
+
strictHandoffCommandSafety: buildBundleTaskHandoffCommandSafety(task, { strict: true }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function summarizeBundleTaskCatalog(workspace, directory, selectedTask = null) {
|
|
73
|
+
const items = orderedRefactorTasks(workspace).map((task, index) => summarizeBundleTaskItem(task, index, directory));
|
|
74
|
+
const selectedTaskId = selectedTask?.id || "";
|
|
75
|
+
return {
|
|
76
|
+
source: "website-workspace.tasks.json",
|
|
77
|
+
count: items.length,
|
|
78
|
+
defaultTaskId: items[0]?.id || "",
|
|
79
|
+
selectedTaskId,
|
|
80
|
+
selectionMode: selectedTaskId ? "explicit" : "bundled-default",
|
|
81
|
+
items,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function emptyBundleTaskCatalog(error = "") {
|
|
86
|
+
return {
|
|
87
|
+
source: "website-workspace.tasks.json",
|
|
88
|
+
count: 0,
|
|
89
|
+
defaultTaskId: "",
|
|
90
|
+
selectedTaskId: "",
|
|
91
|
+
selectionMode: "unavailable",
|
|
92
|
+
items: [],
|
|
93
|
+
error,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function summarizeSelectedTask(task, taskSelector, source, directory = "") {
|
|
98
|
+
if (!task) return null;
|
|
99
|
+
return {
|
|
100
|
+
id: task.id,
|
|
101
|
+
title: task.title,
|
|
102
|
+
category: task.category,
|
|
103
|
+
priority: task.priority,
|
|
104
|
+
impact: task.impact,
|
|
105
|
+
effort: task.effort,
|
|
106
|
+
selector: String(taskSelector || "").trim(),
|
|
107
|
+
source,
|
|
108
|
+
handoffTaskArg: task.id,
|
|
109
|
+
handoffOutFile: taskHandoffOutFile(task),
|
|
110
|
+
handoffCommand: directory ? buildBundleTaskHandoffCommand(directory, task) : "",
|
|
111
|
+
handoffCommandArgs: directory ? buildBundleTaskHandoffCommandArgs(directory, task) : [],
|
|
112
|
+
handoffCommandRunPolicy: directory ? "writes-local-file" : "",
|
|
113
|
+
handoffCommandSafety: directory ? buildBundleTaskHandoffCommandSafety(task) : null,
|
|
114
|
+
strictHandoffCommand: directory ? buildBundleTaskHandoffCommand(directory, task, { strict: true }) : "",
|
|
115
|
+
strictHandoffCommandArgs: directory ? buildBundleTaskHandoffCommandArgs(directory, task, { strict: true }) : [],
|
|
116
|
+
strictHandoffCommandRunPolicy: directory ? "writes-local-file" : "",
|
|
117
|
+
strictHandoffCommandSafety: directory ? buildBundleTaskHandoffCommandSafety(task, { strict: true }) : null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function formatBundleHandoffTaskCatalogLines(taskCatalog) {
|
|
122
|
+
if (!taskCatalog || !Array.isArray(taskCatalog.items) || taskCatalog.items.length === 0) {
|
|
123
|
+
const reason = taskCatalog?.error ? ` ${taskCatalog.error}` : "";
|
|
124
|
+
return [`- No bundle task catalog is available.${reason}`];
|
|
125
|
+
}
|
|
126
|
+
return taskCatalog.items.map((task) => {
|
|
127
|
+
const pages = task.pages.length ? task.pages.join(", ") : "all pages";
|
|
128
|
+
const mcps = task.recommendedMcp.length ? task.recommendedMcp.join(", ") : "none";
|
|
129
|
+
const command = task.strictHandoffCommand || task.handoffCommand || `design-ai site <bundle-dir> --bundle-handoff --task ${task.handoffTaskArg}`;
|
|
130
|
+
return `- ${task.number}. [${task.priority}/${task.impact}/${task.effort}] ${task.id}: ${task.title} (pages: ${pages}; MCP: ${mcps}; command: \`${command}\`)`;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function formatBundleHandoffIssueLines(issues) {
|
|
135
|
+
const actionable = issues.filter((issue) => issue.level !== "pass");
|
|
136
|
+
if (actionable.length === 0) return "- No blocking bundle-check issues were found.";
|
|
137
|
+
return actionable.map((issue) => `- [${issue.level}] ${issue.id}: ${issue.message}`).join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function buildSiteBundleHandoffBoundaries(checkReport) {
|
|
141
|
+
return Array.from(new Set([
|
|
142
|
+
...normalizeStringArray(checkReport?.boundaries),
|
|
143
|
+
"target-repo-work-after-handoff",
|
|
144
|
+
]));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function summarizeSiteBundleHandoffSource(checkReport) {
|
|
148
|
+
return {
|
|
149
|
+
directory: checkReport.directory,
|
|
150
|
+
sourceWorkspace: checkReport.summary.source || "",
|
|
151
|
+
siteName: checkReport.summary.siteName || "",
|
|
152
|
+
status: checkReport.status,
|
|
153
|
+
valid: checkReport.valid,
|
|
154
|
+
workspaceStatus: checkReport.workspaceStatus || "unknown",
|
|
155
|
+
mcpStatus: checkReport.mcpStatus || "unknown",
|
|
156
|
+
mcpProbeStatus: checkReport.mcpProbeStatus || "unknown",
|
|
157
|
+
checksumAlgorithm: checkReport.summary.checksumAlgorithm || "",
|
|
158
|
+
checksumBundleDigest: checkReport.summary.checksumBundleDigest || "",
|
|
159
|
+
verifiedChecksumFiles: checkReport.counts.verifiedChecksumFiles,
|
|
160
|
+
expectedChecksumFiles: checkReport.counts.expectedChecksumFiles,
|
|
161
|
+
verifiedGeneratedFiles: checkReport.counts.verifiedGeneratedFiles,
|
|
162
|
+
expectedGeneratedFiles: checkReport.counts.expectedGeneratedFiles,
|
|
163
|
+
issueCount: checkReport.issues.length,
|
|
164
|
+
warningCount: checkReport.counts.warnings,
|
|
165
|
+
failureCount: checkReport.counts.failures,
|
|
166
|
+
checkCommand: buildBundleCheckCommand(checkReport.directory),
|
|
167
|
+
checkCommandArgs: buildBundleCheckCommandArgs(checkReport.directory),
|
|
168
|
+
checkCommandRunPolicy: "read-only",
|
|
169
|
+
checkCommandSafety: buildBundleSourceCommandSafety(),
|
|
170
|
+
strictCheckCommand: buildBundleCheckCommand(checkReport.directory, { strict: true }),
|
|
171
|
+
strictCheckCommandArgs: buildBundleCheckCommandArgs(checkReport.directory, { strict: true }),
|
|
172
|
+
strictCheckCommandRunPolicy: "read-only",
|
|
173
|
+
strictCheckCommandSafety: buildBundleSourceCommandSafety({ strict: true }),
|
|
174
|
+
handoffCommand: buildBundleHandoffCommand(checkReport.directory),
|
|
175
|
+
handoffCommandArgs: buildBundleHandoffCommandArgs(checkReport.directory),
|
|
176
|
+
handoffCommandRunPolicy: "read-only",
|
|
177
|
+
handoffCommandSafety: buildBundleSourceCommandSafety(),
|
|
178
|
+
strictHandoffCommand: buildBundleHandoffCommand(checkReport.directory, { strict: true }),
|
|
179
|
+
strictHandoffCommandArgs: buildBundleHandoffCommandArgs(checkReport.directory, { strict: true }),
|
|
180
|
+
strictHandoffCommandRunPolicy: "read-only",
|
|
181
|
+
strictHandoffCommandSafety: buildBundleSourceCommandSafety({ strict: true }),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// Target-repo handoff reports for Website Improvement bundles.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
existsSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
statSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
buildSitePrompt,
|
|
12
|
+
resolveSitePromptTask,
|
|
13
|
+
} from "./site-prompts.mjs";
|
|
14
|
+
import { analyzeSiteWorkspace } from "./site-analysis.mjs";
|
|
15
|
+
import { buildBundleCheckCommand } from "./site-bundle-commands.mjs";
|
|
16
|
+
import { formatBundleRepairGuidanceLines } from "./site-bundle-repair.mjs";
|
|
17
|
+
import { buildSiteBundleCheckReport } from "./site-bundle-check.mjs";
|
|
18
|
+
import {
|
|
19
|
+
buildBundleHandoffCommandManifest,
|
|
20
|
+
buildBundleHandoffOperatorRunbook,
|
|
21
|
+
formatBundleHandoffOperatorRunbookLines,
|
|
22
|
+
} from "./site-bundle-handoff-runbook.mjs";
|
|
23
|
+
import {
|
|
24
|
+
SITE_TARGET_REPO_EXECUTION_CHECKLIST,
|
|
25
|
+
buildSiteBundleHandoffBoundaries,
|
|
26
|
+
emptyBundleTaskCatalog,
|
|
27
|
+
formatBundleHandoffIssueLines,
|
|
28
|
+
formatBundleHandoffTaskCatalogLines,
|
|
29
|
+
summarizeBundleTaskCatalog,
|
|
30
|
+
summarizeSelectedTask,
|
|
31
|
+
summarizeSiteBundleHandoffSource,
|
|
32
|
+
} from "./site-bundle-handoff-summary.mjs";
|
|
33
|
+
import { readBundleTextIfPresent } from "./site-bundle-files.mjs";
|
|
34
|
+
import { formatGeneratedContractDriftSummary } from "./site-bundle-contract.mjs";
|
|
35
|
+
|
|
36
|
+
function loadSiteBundleWorkspace(directory) {
|
|
37
|
+
const relativePath = "website-workspace.tasks.json";
|
|
38
|
+
const targetPath = path.join(directory, relativePath);
|
|
39
|
+
if (!existsSync(targetPath) || !statSync(targetPath).isFile()) {
|
|
40
|
+
throw new Error(`Cannot select a handoff task because ${relativePath} is missing from the bundle`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let raw;
|
|
44
|
+
try {
|
|
45
|
+
raw = JSON.parse(readFileSync(targetPath, "utf8"));
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(`Cannot select a handoff task because ${relativePath} is invalid JSON: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return analyzeSiteWorkspace(raw, { filePath: targetPath }).workspace;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildSiteBundleHandoffPrompt(checkReport, bundleTexts) {
|
|
54
|
+
const bundleDigest = checkReport.summary.checksumBundleDigest || "not recorded";
|
|
55
|
+
const checksumStatus = `${checkReport.counts.verifiedChecksumFiles}/${checkReport.counts.expectedChecksumFiles} verified`;
|
|
56
|
+
const handoffBoundaries = buildSiteBundleHandoffBoundaries(checkReport);
|
|
57
|
+
const taskSelectionLine = bundleTexts.selectedTask
|
|
58
|
+
? `${bundleTexts.selectedTask.id} (${bundleTexts.selectedTask.title}; ${bundleTexts.selectedTask.source})`
|
|
59
|
+
: "bundled codex-implementation.md default";
|
|
60
|
+
const bundleReadinessLine = checkReport.status === "pass"
|
|
61
|
+
? "The bundle passed local bundle-check validation. Proceed in the target website repo after confirming the repo path."
|
|
62
|
+
: "The bundle did not fully pass local bundle-check validation. Resolve the listed bundle issues before treating this as implementation authority.";
|
|
63
|
+
return [
|
|
64
|
+
"# Website improvement target-repo handoff prompt",
|
|
65
|
+
"",
|
|
66
|
+
"You are Codex working in the target website repository, not in the design-ai repository.",
|
|
67
|
+
"Use this verified Website Improvement handoff bundle as read-only planning evidence. Do not modify the design-ai repo while executing this prompt.",
|
|
68
|
+
"",
|
|
69
|
+
"## Verified Bundle",
|
|
70
|
+
`- Bundle directory: ${checkReport.directory}`,
|
|
71
|
+
`- Source bundle provenance: ${checkReport.status}/${checkReport.valid ? "valid" : "invalid"} from ${checkReport.directory}`,
|
|
72
|
+
`- Source bundle strict check command: \`${buildBundleCheckCommand(checkReport.directory, { strict: true })}\``,
|
|
73
|
+
`- Site: ${checkReport.summary.siteName || "unknown"}`,
|
|
74
|
+
`- Source workspace: ${checkReport.summary.source || "unknown"}`,
|
|
75
|
+
`- Bundle status: ${checkReport.status}`,
|
|
76
|
+
`- Workspace status: ${checkReport.workspaceStatus}`,
|
|
77
|
+
`- MCP status: ${checkReport.mcpStatus}`,
|
|
78
|
+
`- MCP probe status: ${checkReport.mcpProbeStatus}`,
|
|
79
|
+
`- MCP probes: ${checkReport.mcpProbeCounts.pass}/${checkReport.mcpProbeCounts.count} passing, ${checkReport.mcpProbeCounts.warn} warning, ${checkReport.mcpProbeCounts.fail} failing`,
|
|
80
|
+
`- Tasks: ${checkReport.summary.totalTasks}`,
|
|
81
|
+
`- Primary task selection: ${taskSelectionLine}`,
|
|
82
|
+
`- Evidence counts: executed work ${checkReport.summary.implementationEvidence.executedWork}, verification ${checkReport.summary.implementationEvidence.verificationResults}, risks ${checkReport.summary.implementationEvidence.remainingRisks}, next actions ${checkReport.summary.implementationEvidence.nextActions}`,
|
|
83
|
+
`- Generated files: ${checkReport.counts.verifiedGeneratedFiles}/${checkReport.counts.expectedGeneratedFiles} match the current CLI bundle contract`,
|
|
84
|
+
`- Generated drift files: ${formatGeneratedContractDriftSummary(checkReport.generatedContract)}`,
|
|
85
|
+
`- SHA-256 bundle digest: ${bundleDigest}`,
|
|
86
|
+
`- Checksums: ${checksumStatus}`,
|
|
87
|
+
`- Handoff generation boundary flags: external calls no; target repo mutation no`,
|
|
88
|
+
`- Handoff boundaries: ${handoffBoundaries.join(", ")}`,
|
|
89
|
+
"",
|
|
90
|
+
"## Available Bundle Tasks",
|
|
91
|
+
`Task catalog source: ${bundleTexts.taskCatalog?.source || "unknown"}`,
|
|
92
|
+
`Default task: ${bundleTexts.taskCatalog?.defaultTaskId || "none"}`,
|
|
93
|
+
...(bundleTexts.defaultTask?.strictHandoffCommand
|
|
94
|
+
? [`Default task strict command: \`${bundleTexts.defaultTask.strictHandoffCommand}\``]
|
|
95
|
+
: []),
|
|
96
|
+
`Selected task: ${bundleTexts.taskCatalog?.selectedTaskId || "none"}`,
|
|
97
|
+
...(bundleTexts.selectedTask?.strictHandoffCommand
|
|
98
|
+
? [`Selected task strict command: \`${bundleTexts.selectedTask.strictHandoffCommand}\``]
|
|
99
|
+
: []),
|
|
100
|
+
`Effective task: ${bundleTexts.effectiveTask?.id || "none"}`,
|
|
101
|
+
...(bundleTexts.effectiveTask?.strictHandoffCommand
|
|
102
|
+
? [`Effective task strict command: \`${bundleTexts.effectiveTask.strictHandoffCommand}\``]
|
|
103
|
+
: []),
|
|
104
|
+
"To choose a specific task, re-run this handoff with `--task <number-or-id>`.",
|
|
105
|
+
...formatBundleHandoffTaskCatalogLines(bundleTexts.taskCatalog),
|
|
106
|
+
"",
|
|
107
|
+
"## Operator Runbook",
|
|
108
|
+
`Runbook stages: ${bundleTexts.operatorRunbook?.stageCount || 0} (${bundleTexts.operatorRunbook?.requiredStageCount || 0} required, ${bundleTexts.operatorRunbook?.optionalStageCount || 0} optional)`,
|
|
109
|
+
`Next command key: ${bundleTexts.operatorRunbook?.nextCommandKey || "none"}`,
|
|
110
|
+
...formatBundleHandoffOperatorRunbookLines(bundleTexts.operatorRunbook),
|
|
111
|
+
"",
|
|
112
|
+
"## Bundle Gate",
|
|
113
|
+
bundleReadinessLine,
|
|
114
|
+
formatBundleHandoffIssueLines(checkReport.issues),
|
|
115
|
+
"",
|
|
116
|
+
"Repair guidance:",
|
|
117
|
+
...formatBundleRepairGuidanceLines(checkReport.repairGuidance),
|
|
118
|
+
"",
|
|
119
|
+
"## Operating Rules",
|
|
120
|
+
"1. Confirm the current working directory is the target website repo before editing files.",
|
|
121
|
+
"2. Inspect the target repo architecture, existing components, design tokens, routing, styling, and test scripts before implementation.",
|
|
122
|
+
"3. Reuse existing UI/system patterns and keep the change scoped to the selected improvement task.",
|
|
123
|
+
"4. Do not add production dependencies unless the target repo clearly requires them and the tradeoff is documented.",
|
|
124
|
+
"5. Preserve WCAG 2.1 AA expectations: visible focus, keyboard reachability, semantic structure, and text contrast.",
|
|
125
|
+
"6. Verify desktop, tablet, and mobile behavior plus target repo lint/typecheck/build commands when available.",
|
|
126
|
+
"7. Keep the handoff bundle files read-only; record implementation evidence in the target repo final response or report.",
|
|
127
|
+
"",
|
|
128
|
+
"## Target Repo Execution Checklist",
|
|
129
|
+
...SITE_TARGET_REPO_EXECUTION_CHECKLIST.map((item) => `- [ ] ${item.label}: ${item.evidence}`),
|
|
130
|
+
"",
|
|
131
|
+
"## Primary Codex Implementation Prompt",
|
|
132
|
+
bundleTexts.codexImplementation || "_codex-implementation.md was not readable from the bundle._",
|
|
133
|
+
"",
|
|
134
|
+
"## Additional Bundle Context",
|
|
135
|
+
"Use these files only as supporting evidence:",
|
|
136
|
+
"- `website-handoff.md`: audit summary, priority recommendations, and remaining risk context.",
|
|
137
|
+
"- `mcp-probes.json`: read-only MCP probe evidence for repo, Figma, Browser, and deployment references.",
|
|
138
|
+
"- `mcp-action-plan.md`: MCP readiness gaps and operator sequence.",
|
|
139
|
+
"- `website-prompts.md`: alternate Codex/Claude review, QA, deployment, research, and copy prompts.",
|
|
140
|
+
"- `summary.json`: bundle manifest, source workspace, task count, and checksum digest.",
|
|
141
|
+
"",
|
|
142
|
+
"### Handoff Report Snapshot",
|
|
143
|
+
bundleTexts.websiteHandoff || "_website-handoff.md was not readable from the bundle._",
|
|
144
|
+
"",
|
|
145
|
+
"## Required Final Response",
|
|
146
|
+
"Return a concise implementation report with:",
|
|
147
|
+
"- Files changed in the target repo",
|
|
148
|
+
"- The specific website improvement task completed",
|
|
149
|
+
"- Verification commands and browser/viewport checks performed",
|
|
150
|
+
"- Remaining risks or follow-up work",
|
|
151
|
+
`- Bundle digest used for handoff: ${bundleDigest}`,
|
|
152
|
+
].join("\n");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function buildSiteBundleHandoffReport({
|
|
156
|
+
target,
|
|
157
|
+
cwd = process.cwd(),
|
|
158
|
+
taskSelector = "",
|
|
159
|
+
} = {}) {
|
|
160
|
+
const checkReport = buildSiteBundleCheckReport({ target, cwd });
|
|
161
|
+
const includedFilePaths = [
|
|
162
|
+
"summary.json",
|
|
163
|
+
"mcp-probes.json",
|
|
164
|
+
"mcp-action-plan.md",
|
|
165
|
+
"website-handoff.md",
|
|
166
|
+
"website-prompts.md",
|
|
167
|
+
"codex-implementation.md",
|
|
168
|
+
];
|
|
169
|
+
let bundleWorkspace = null;
|
|
170
|
+
let taskCatalogError = "";
|
|
171
|
+
let selectedTask = null;
|
|
172
|
+
let codexImplementation = readBundleTextIfPresent(checkReport.directory, "codex-implementation.md");
|
|
173
|
+
try {
|
|
174
|
+
bundleWorkspace = loadSiteBundleWorkspace(checkReport.directory);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
taskCatalogError = error.message;
|
|
177
|
+
}
|
|
178
|
+
if (String(taskSelector || "").trim()) {
|
|
179
|
+
if (!bundleWorkspace) {
|
|
180
|
+
throw new Error(taskCatalogError || "Cannot select a handoff task because the bundle workspace is unavailable");
|
|
181
|
+
}
|
|
182
|
+
const task = resolveSitePromptTask(bundleWorkspace, taskSelector);
|
|
183
|
+
selectedTask = summarizeSelectedTask(task, taskSelector, "bundle-workspace", checkReport.directory);
|
|
184
|
+
codexImplementation = buildSitePrompt(bundleWorkspace, "codex-implementation", { taskSelector });
|
|
185
|
+
}
|
|
186
|
+
const taskCatalog = bundleWorkspace
|
|
187
|
+
? summarizeBundleTaskCatalog(bundleWorkspace, checkReport.directory, selectedTask)
|
|
188
|
+
: emptyBundleTaskCatalog(taskCatalogError);
|
|
189
|
+
const defaultTask = taskCatalog.items[0] || null;
|
|
190
|
+
const effectiveTask = selectedTask || defaultTask;
|
|
191
|
+
|
|
192
|
+
const bundleTexts = {
|
|
193
|
+
taskCatalog,
|
|
194
|
+
defaultTask,
|
|
195
|
+
effectiveTask,
|
|
196
|
+
selectedTask,
|
|
197
|
+
codexImplementation,
|
|
198
|
+
websiteHandoff: readBundleTextIfPresent(checkReport.directory, "website-handoff.md"),
|
|
199
|
+
};
|
|
200
|
+
const boundaries = buildSiteBundleHandoffBoundaries(checkReport);
|
|
201
|
+
const sourceBundle = summarizeSiteBundleHandoffSource(checkReport);
|
|
202
|
+
const commandManifest = buildBundleHandoffCommandManifest({
|
|
203
|
+
sourceBundle,
|
|
204
|
+
taskCatalog,
|
|
205
|
+
defaultTask,
|
|
206
|
+
selectedTask,
|
|
207
|
+
effectiveTask,
|
|
208
|
+
});
|
|
209
|
+
const operatorRunbook = buildBundleHandoffOperatorRunbook(commandManifest);
|
|
210
|
+
const runbookPrompt = buildSiteBundleHandoffPrompt(checkReport, {
|
|
211
|
+
...bundleTexts,
|
|
212
|
+
operatorRunbook,
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
status: checkReport.status,
|
|
216
|
+
valid: checkReport.valid,
|
|
217
|
+
directory: checkReport.directory,
|
|
218
|
+
sourceBundle,
|
|
219
|
+
commandManifest,
|
|
220
|
+
operatorRunbook,
|
|
221
|
+
boundaries,
|
|
222
|
+
externalCalls: false,
|
|
223
|
+
targetRepoMutation: false,
|
|
224
|
+
bundle: {
|
|
225
|
+
directory: checkReport.directory,
|
|
226
|
+
siteName: checkReport.summary.siteName || "",
|
|
227
|
+
source: checkReport.summary.source || "",
|
|
228
|
+
sourceBundle,
|
|
229
|
+
workspaceStatus: checkReport.workspaceStatus || "unknown",
|
|
230
|
+
mcpStatus: checkReport.mcpStatus || "unknown",
|
|
231
|
+
mcpProbeStatus: checkReport.mcpProbeStatus || "unknown",
|
|
232
|
+
mcpProbeCounts: { ...checkReport.mcpProbeCounts },
|
|
233
|
+
totalTasks: checkReport.summary.totalTasks || 0,
|
|
234
|
+
implementationEvidence: { ...checkReport.summary.implementationEvidence },
|
|
235
|
+
checksumAlgorithm: checkReport.summary.checksumAlgorithm || "",
|
|
236
|
+
checksumBundleDigest: checkReport.summary.checksumBundleDigest || "",
|
|
237
|
+
expectedChecksumFiles: checkReport.counts.expectedChecksumFiles,
|
|
238
|
+
verifiedChecksumFiles: checkReport.counts.verifiedChecksumFiles,
|
|
239
|
+
checksumFailures: checkReport.counts.checksumFailures,
|
|
240
|
+
expectedGeneratedFiles: checkReport.counts.expectedGeneratedFiles,
|
|
241
|
+
verifiedGeneratedFiles: checkReport.counts.verifiedGeneratedFiles,
|
|
242
|
+
generatedFailures: checkReport.counts.generatedFailures,
|
|
243
|
+
generatedDriftFiles: [...checkReport.generatedContract.driftFiles],
|
|
244
|
+
taskCatalog,
|
|
245
|
+
defaultTask,
|
|
246
|
+
effectiveTask,
|
|
247
|
+
selectedTask,
|
|
248
|
+
commandManifest,
|
|
249
|
+
operatorRunbook,
|
|
250
|
+
boundaries,
|
|
251
|
+
externalCalls: false,
|
|
252
|
+
targetRepoMutation: false,
|
|
253
|
+
repairGuidance: { ...checkReport.repairGuidance },
|
|
254
|
+
executionChecklist: SITE_TARGET_REPO_EXECUTION_CHECKLIST,
|
|
255
|
+
},
|
|
256
|
+
prompt: runbookPrompt,
|
|
257
|
+
files: checkReport.files.map((file) => ({
|
|
258
|
+
...file,
|
|
259
|
+
included: includedFilePaths.includes(file.path),
|
|
260
|
+
})),
|
|
261
|
+
issues: checkReport.issues,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function formatSiteBundleHandoffJson(report) {
|
|
266
|
+
return JSON.stringify(report, null, 2);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function formatSiteBundleHandoffHuman(report) {
|
|
270
|
+
return report.prompt;
|
|
271
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// README and handoff guidance builders for Website Improvement bundles.
|
|
2
|
+
|
|
3
|
+
import { markdownTable } from "./site-strings.mjs";
|
|
4
|
+
import { SITE_TARGET_REPO_EXECUTION_CHECKLIST } from "./site-bundle-handoff-summary.mjs";
|
|
5
|
+
|
|
6
|
+
export function buildSiteBundleHandoffGuidance(bundleStatus) {
|
|
7
|
+
const strictCommand = "design-ai site <bundle-dir> --bundle-handoff --strict --out target-repo-handoff.md";
|
|
8
|
+
const draftCommand = "design-ai site <bundle-dir> --bundle-handoff --out target-repo-handoff.md";
|
|
9
|
+
const verifyCommand = "design-ai site <bundle-dir> --bundle-check --strict --json";
|
|
10
|
+
const strictReady = bundleStatus === "pass";
|
|
11
|
+
return {
|
|
12
|
+
strictReady,
|
|
13
|
+
readiness: strictReady ? "ready-for-strict-handoff" : "review-warnings-before-strict-handoff",
|
|
14
|
+
recommendedCommand: strictReady ? strictCommand : draftCommand,
|
|
15
|
+
strictCommand,
|
|
16
|
+
draftCommand,
|
|
17
|
+
verifyCommand,
|
|
18
|
+
note: strictReady
|
|
19
|
+
? "Use the strict handoff command before target-repo implementation."
|
|
20
|
+
: "Use the draft handoff command only for planning while readiness warnings remain; use the strict handoff command before treating the bundle as implementation authority.",
|
|
21
|
+
executionChecklist: SITE_TARGET_REPO_EXECUTION_CHECKLIST,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildSiteBundleReadme(workspace, bundleSummary, mcpReport, mcpProbeReport, filePaths) {
|
|
26
|
+
const commandTarget = bundleSummary.source === "stdin" ? "<workspace.json>" : bundleSummary.source;
|
|
27
|
+
const handoff = bundleSummary.handoff;
|
|
28
|
+
return [
|
|
29
|
+
`# Website improvement handoff bundle: ${workspace.siteProfile.name}`,
|
|
30
|
+
"",
|
|
31
|
+
"> Generated by `design-ai site --bundle` from a Website Improvement Console workspace export.",
|
|
32
|
+
"",
|
|
33
|
+
"## Contents",
|
|
34
|
+
markdownTable(
|
|
35
|
+
["File", "Purpose"],
|
|
36
|
+
filePaths.map((filePath) => {
|
|
37
|
+
const purpose = {
|
|
38
|
+
"summary.json": "Machine-readable bundle manifest and readiness summary",
|
|
39
|
+
"website-workspace.tasks.json": "Workspace JSON with deterministic starter refactor tasks added",
|
|
40
|
+
"mcp-check.json": "Machine-readable MCP readiness gate output",
|
|
41
|
+
"mcp-probes.json": "Machine-readable read-only MCP probe readiness output",
|
|
42
|
+
"mcp-action-plan.md": "Operator-facing MCP readiness action plan",
|
|
43
|
+
"website-handoff.md": "Markdown handoff report for implementation planning",
|
|
44
|
+
"website-prompts.md": "Full Codex and Claude prompt bundle",
|
|
45
|
+
"codex-implementation.md": "Top-priority Codex implementation prompt",
|
|
46
|
+
}[filePath] || "Bundle artifact";
|
|
47
|
+
return [filePath, purpose];
|
|
48
|
+
}),
|
|
49
|
+
),
|
|
50
|
+
"",
|
|
51
|
+
"## Status",
|
|
52
|
+
`- Bundle status: ${mcpReport.status}`,
|
|
53
|
+
`- Workspace status: ${bundleSummary.workspaceStatus}`,
|
|
54
|
+
`- Source: ${bundleSummary.source}`,
|
|
55
|
+
`- Site: ${workspace.siteProfile.name}`,
|
|
56
|
+
`- Live URL: ${workspace.siteProfile.liveUrl || "not provided"}`,
|
|
57
|
+
`- Repo: ${workspace.siteProfile.repoUrl || workspace.siteProfile.localPath || "not provided"}`,
|
|
58
|
+
`- Tasks: ${bundleSummary.taskGeneration.totalTasks}`,
|
|
59
|
+
`- Evidence entries: ${bundleSummary.implementationEvidence.executedWork + bundleSummary.implementationEvidence.verificationResults}`,
|
|
60
|
+
`- MCP ready: ${mcpReport.counts.ready}/${mcpReport.counts.total}`,
|
|
61
|
+
`- MCP probes: ${mcpProbeReport.pass}/${mcpProbeReport.count} passing`,
|
|
62
|
+
"",
|
|
63
|
+
"## Handoff Readiness",
|
|
64
|
+
`- Strict-ready: ${handoff.strictReady ? "yes" : "no"}`,
|
|
65
|
+
`- Readiness: ${handoff.readiness}`,
|
|
66
|
+
`- Recommended command: \`${handoff.recommendedCommand}\``,
|
|
67
|
+
`- Strict command: \`${handoff.strictCommand}\``,
|
|
68
|
+
`- Draft command: \`${handoff.draftCommand}\``,
|
|
69
|
+
`- Verify command: \`${handoff.verifyCommand}\``,
|
|
70
|
+
`- Note: ${handoff.note}`,
|
|
71
|
+
"",
|
|
72
|
+
"## Target Repo Execution Checklist",
|
|
73
|
+
...handoff.executionChecklist.map((item) => `- [ ] ${item.label}: ${item.evidence}`),
|
|
74
|
+
"",
|
|
75
|
+
"## Suggested Sequence",
|
|
76
|
+
"1. Read `summary.json`, `mcp-check.json`, `mcp-probes.json`, and `mcp-action-plan.md` first.",
|
|
77
|
+
"2. Run `design-ai site <bundle-dir> --bundle-check --strict --json`; if it exits non-zero, review the warnings or failures before implementation.",
|
|
78
|
+
"3. Run the recommended handoff command above. Use the draft command only for planning while readiness warnings remain.",
|
|
79
|
+
"4. Use `codex-implementation.md` in the target website repo for the top-priority task when you need the raw task prompt.",
|
|
80
|
+
"5. Use `website-prompts.md` for deeper Codex/Claude review, visual QA, deployment verification, competitor research, and final handoff.",
|
|
81
|
+
"6. Record target-repo executed work, verification results, remaining risks, and next actions in `website-handoff.md` after implementation.",
|
|
82
|
+
"",
|
|
83
|
+
"## Regenerate",
|
|
84
|
+
`- \`design-ai site ${commandTarget} --bundle --out website-handoff-bundle --force\``,
|
|
85
|
+
`- \`design-ai site ${commandTarget} --mcp-check --strict --json\``,
|
|
86
|
+
`- \`design-ai site website-handoff-bundle --bundle-check --strict --json\``,
|
|
87
|
+
`- \`design-ai site website-handoff-bundle --bundle-handoff --strict --out target-repo-handoff.md\``,
|
|
88
|
+
"",
|
|
89
|
+
"## Checksum Verification",
|
|
90
|
+
"- `summary.json` records SHA-256 checksums for every generated bundle file except `summary.json` itself.",
|
|
91
|
+
"- `summary.json.checksums.bundleDigest` records a deterministic fingerprint of the checksum manifest for quick bundle identity comparison.",
|
|
92
|
+
"- `design-ai site <bundle-dir> --bundle-check --strict --json` recomputes those checksums so transferred or manually edited bundles fail before target-repo handoff.",
|
|
93
|
+
"",
|
|
94
|
+
"## Boundaries",
|
|
95
|
+
"- This bundle is deterministic and local.",
|
|
96
|
+
"- It does not call external MCPs, mutate the target website repo, run Lighthouse/axe, capture screenshots, or write to deployment/CMS/Sentry systems.",
|
|
97
|
+
].join("\n");
|
|
98
|
+
}
|