@pixel-point/toolcraft 0.0.12 → 0.0.14
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/README.md +4 -2
- package/package.json +1 -1
- package/src/cli.mjs +18 -45
- package/src/cli.test.mjs +141 -6
- package/src/command-runner.mjs +71 -0
- package/src/dependency-install.mjs +87 -0
- package/src/generate.mjs +32 -4
- package/src/generate.test.mjs +116 -15
- package/src/package-json.mjs +11 -2
- package/src/package-json.test.mjs +27 -0
- package/src/package-manager.mjs +123 -0
- package/src/package-manager.test.mjs +80 -0
- package/templates/runtime/contracts/component-contracts.test.ts +1 -1
- package/templates/runtime/contracts/component-contracts.ts +1 -1
- package/templates/starter/AGENTS.md +4 -3
- package/templates/starter/docs/toolcraft/README.md +15 -0
- package/templates/starter/docs/toolcraft/acceptance-testing.md +2 -0
- package/templates/starter/docs/toolcraft/assembly-workflow.md +35 -171
- package/templates/starter/docs/toolcraft/component-rules.md +12 -188
- package/templates/starter/docs/toolcraft/core/control-selection.md +93 -0
- package/templates/starter/docs/toolcraft/core/layout.md +104 -0
- package/templates/starter/docs/toolcraft/core/media-upload.md +85 -0
- package/templates/starter/docs/toolcraft/core/performance.md +83 -0
- package/templates/starter/docs/toolcraft/core/reference-study.md +115 -0
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +53 -0
- package/templates/starter/docs/toolcraft/core/setup-export.md +86 -0
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +67 -0
- package/templates/starter/docs/toolcraft/custom-controls.md +2 -0
- package/templates/starter/docs/toolcraft/performance.md +2 -0
- package/templates/starter/docs/toolcraft/renderer-technique.md +2 -0
- package/templates/starter/docs/toolcraft/schema-reference.md +117 -367
- package/templates/starter/docs/toolcraft/workflow.md +12 -10
- package/templates/starter/package.json +1 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +28 -6
- package/templates/starter/scripts/run-vite-on-free-port.mjs +25 -6
- package/templates/starter/src/app/starter-acceptance.test.ts +24 -15
- package/templates/starter/src/app/starter-performance.test.ts +17 -7
|
@@ -17,22 +17,24 @@ Before planning or editing app code, runtime code, controls, canvas, panels, ren
|
|
|
17
17
|
|
|
18
18
|
Do not edit implementation files until this preflight is complete.
|
|
19
19
|
|
|
20
|
+
Core modules are required reading when listed by the routing table. Read each listed module fully. Do not rely on a truncated terminal excerpt; reopen the specific module or use a narrower range when a tool output is clipped.
|
|
21
|
+
|
|
20
22
|
## Task Routing
|
|
21
23
|
|
|
22
24
|
Use the smallest reading set that covers the changed surface. If a task touches multiple surfaces, combine every matching row instead of picking only the closest one.
|
|
23
25
|
|
|
24
26
|
| Task type | Read before editing |
|
|
25
27
|
| --- | --- |
|
|
26
|
-
| App assembly, route structure, generated app porting | `assembly-workflow.md`, `decision-contract.md` |
|
|
27
|
-
| Reference app study, audit, or port | `assembly-workflow.md`, `schema-reference.md`, `acceptance-testing.md`, `decision-contract.md` |
|
|
28
|
-
| Schema, controls, defaults, persistence, actions | `schema-reference.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
29
|
-
| Custom controls | `custom-controls.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
30
|
-
| Renderer, canvas output, visual technique | `renderer-technique.md`, `performance.md`, `acceptance-testing.md` |
|
|
31
|
-
| Timeline, keyframes, animation transport | `decision-contract.md`, `component-rules.md`, `acceptance-testing.md
|
|
32
|
-
| Layers | `decision-contract.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
33
|
-
| Export, copy, media, background | `schema-reference.md`, `component-rules.md`, `acceptance-testing.md`, `performance.md` |
|
|
34
|
-
| Broken control, visual mismatch, failed build, export bug, performance issue | `decision-contract.md`, the relevant component/runtime doc, and the failing test/log first |
|
|
35
|
-
| Figma implementation | Use Figma MCP/design context, then `assembly-workflow.md
|
|
28
|
+
| App assembly, route structure, generated app porting | `core/runtime-boundary.md`, `assembly-workflow.md`, `decision-contract.md` |
|
|
29
|
+
| Reference app study, audit, or port | `core/reference-study.md`, `core/runtime-boundary.md`, `assembly-workflow.md`, `schema-reference.md`, `acceptance-testing.md`, `decision-contract.md` |
|
|
30
|
+
| Schema, controls, defaults, persistence, actions | `core/control-selection.md`, `core/layout.md`, `schema-reference.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
31
|
+
| Custom controls | `core/control-selection.md`, `core/layout.md`, `custom-controls.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
32
|
+
| Renderer, canvas output, visual technique | `core/runtime-boundary.md`, `core/performance.md`, `renderer-technique.md`, `performance.md`, `acceptance-testing.md` |
|
|
33
|
+
| Timeline, keyframes, animation transport | `core/timeline-animation.md`, `core/performance.md`, `decision-contract.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
34
|
+
| Layers | `core/runtime-boundary.md`, `core/layout.md`, `decision-contract.md`, `component-rules.md`, `acceptance-testing.md` |
|
|
35
|
+
| Export, copy, media, background | `core/setup-export.md`, `core/media-upload.md`, `schema-reference.md`, `component-rules.md`, `acceptance-testing.md`, `performance.md` |
|
|
36
|
+
| Broken control, visual mismatch, failed build, export bug, performance issue | `decision-contract.md`, the relevant `core/*` module, the relevant component/runtime doc, and the failing test/log first |
|
|
37
|
+
| Figma implementation | Use Figma MCP/design context, then `core/reference-study.md`, `core/runtime-boundary.md`, `assembly-workflow.md`, and the relevant component docs |
|
|
36
38
|
|
|
37
39
|
## Worklog Gate
|
|
38
40
|
|
|
@@ -19,6 +19,17 @@ const requiredDocs = [
|
|
|
19
19
|
"component-rules.md",
|
|
20
20
|
];
|
|
21
21
|
|
|
22
|
+
const requiredCoreDocs = [
|
|
23
|
+
"core/runtime-boundary.md",
|
|
24
|
+
"core/setup-export.md",
|
|
25
|
+
"core/control-selection.md",
|
|
26
|
+
"core/layout.md",
|
|
27
|
+
"core/media-upload.md",
|
|
28
|
+
"core/timeline-animation.md",
|
|
29
|
+
"core/performance.md",
|
|
30
|
+
"core/reference-study.md",
|
|
31
|
+
];
|
|
32
|
+
|
|
22
33
|
const requiredProjectFiles = ["LICENSE.md", "NOTICE.md"];
|
|
23
34
|
|
|
24
35
|
const requiredRuleIds = [
|
|
@@ -43,17 +54,21 @@ const requiredRuleIds = [
|
|
|
43
54
|
"workflow-required",
|
|
44
55
|
];
|
|
45
56
|
|
|
46
|
-
const
|
|
57
|
+
const requiredAgentsEntryLinks = [
|
|
47
58
|
"workflow.md",
|
|
59
|
+
"core/",
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const requiredWorkflowLinks = [
|
|
63
|
+
...requiredCoreDocs,
|
|
48
64
|
"assembly-workflow.md",
|
|
49
65
|
"decision-contract.md",
|
|
50
66
|
"schema-reference.md",
|
|
67
|
+
"component-rules.md",
|
|
51
68
|
"acceptance-testing.md",
|
|
52
69
|
"performance.md",
|
|
53
70
|
"renderer-technique.md",
|
|
54
|
-
"agent-worklog.md",
|
|
55
71
|
"custom-controls.md",
|
|
56
|
-
"component-rules.md",
|
|
57
72
|
];
|
|
58
73
|
|
|
59
74
|
const requiredWorkflowTerms = [
|
|
@@ -90,7 +105,7 @@ async function fileExists(relativePath) {
|
|
|
90
105
|
|
|
91
106
|
const failures = [];
|
|
92
107
|
|
|
93
|
-
for (const fileName of requiredDocs) {
|
|
108
|
+
for (const fileName of [...requiredDocs, ...requiredCoreDocs]) {
|
|
94
109
|
const relativePath = `docs/toolcraft/${fileName}`;
|
|
95
110
|
|
|
96
111
|
if (!(await fileExists(relativePath))) {
|
|
@@ -118,12 +133,13 @@ for (const ruleId of requiredRuleIds) {
|
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
135
|
|
|
121
|
-
for (const fileName of requiredDocs) {
|
|
136
|
+
for (const fileName of [...requiredDocs, ...requiredCoreDocs]) {
|
|
122
137
|
const source = await readText(`docs/toolcraft/${fileName}`);
|
|
123
138
|
docsSources.push(source);
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
const combinedSource = docsSources.join("\n");
|
|
142
|
+
const workflowSource = await readText("docs/toolcraft/workflow.md");
|
|
127
143
|
|
|
128
144
|
for (const pattern of forbiddenTextPatterns) {
|
|
129
145
|
if (pattern.test(combinedSource)) {
|
|
@@ -131,12 +147,18 @@ for (const pattern of forbiddenTextPatterns) {
|
|
|
131
147
|
}
|
|
132
148
|
}
|
|
133
149
|
|
|
134
|
-
for (const localDoc of
|
|
150
|
+
for (const localDoc of requiredAgentsEntryLinks) {
|
|
135
151
|
if (!agentsSource.includes(`docs/toolcraft/${localDoc}`)) {
|
|
136
152
|
failures.push(`AGENTS.md must link docs/toolcraft/${localDoc}`);
|
|
137
153
|
}
|
|
138
154
|
}
|
|
139
155
|
|
|
156
|
+
for (const localDoc of requiredWorkflowLinks) {
|
|
157
|
+
if (!workflowSource.includes(localDoc)) {
|
|
158
|
+
failures.push(`docs/toolcraft/workflow.md must route to ${localDoc}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
for (const term of requiredWorkflowTerms) {
|
|
141
163
|
if (!agentsSource.includes(term)) {
|
|
142
164
|
failures.push(`AGENTS.md must mention "${term}"`);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
import spawn from "cross-spawn";
|
|
4
8
|
|
|
5
9
|
import {
|
|
6
10
|
findAvailablePort,
|
|
@@ -14,6 +18,8 @@ import {
|
|
|
14
18
|
} from "./toolcraft-port.mjs";
|
|
15
19
|
|
|
16
20
|
const viteCommand = process.argv[2] ?? "dev";
|
|
21
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const projectDir = join(scriptDir, "..");
|
|
17
23
|
const restartArg = "--toolcraft-restart";
|
|
18
24
|
const rawPassthroughArgs = process.argv.slice(3).filter((arg) => arg !== "--");
|
|
19
25
|
const restartSamePort =
|
|
@@ -49,7 +55,7 @@ if (savedPort) {
|
|
|
49
55
|
process.exit(0);
|
|
50
56
|
} catch (error) {
|
|
51
57
|
console.error(
|
|
52
|
-
`Saved Toolcraft port ${savedPort} is busy, but it is not serving this app. Use
|
|
58
|
+
`Saved Toolcraft port ${savedPort} is busy, but it is not serving this app. Use the restart script to reclaim the saved port, or remove .toolcraft/server-port.json to assign a new port. ${error?.message ?? ""}`.trim(),
|
|
53
59
|
);
|
|
54
60
|
process.exit(1);
|
|
55
61
|
}
|
|
@@ -66,12 +72,25 @@ if (!port) {
|
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
const
|
|
75
|
+
const viteBinPath = join(
|
|
76
|
+
projectDir,
|
|
77
|
+
"node_modules",
|
|
78
|
+
".bin",
|
|
79
|
+
process.platform === "win32" ? "vite.cmd" : "vite",
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await access(viteBinPath);
|
|
84
|
+
} catch {
|
|
85
|
+
console.error(
|
|
86
|
+
"Vite is not installed. Run this app's dependency installation command before starting the dev server.",
|
|
87
|
+
);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
70
91
|
const child = spawn(
|
|
71
|
-
|
|
92
|
+
viteBinPath,
|
|
72
93
|
[
|
|
73
|
-
"exec",
|
|
74
|
-
"vite",
|
|
75
94
|
viteCommand,
|
|
76
95
|
"--host",
|
|
77
96
|
"127.0.0.1",
|
|
@@ -554,8 +554,12 @@ function escapeRegExp(value: string): string {
|
|
|
554
554
|
|
|
555
555
|
const incompleteRequiredCheckPattern =
|
|
556
556
|
/\b(?:fail(?:ed|s|ing)?|not complete|not completed|incomplete|pending|blocked|planned|todo|to do|to run|will run|not run|not started|not yet|queued)\b/i;
|
|
557
|
+
const packageScriptPrefixPattern = String.raw`(?:pnpm\s+|npm\s+run\s+)?`;
|
|
557
558
|
const requiredCheckNamePattern =
|
|
558
|
-
|
|
559
|
+
new RegExp(
|
|
560
|
+
String.raw`\b(?:${packageScriptPrefixPattern}(?:verify:final|verify:perf|test:browser:perf|test:browser|verify:quick|test|build)|browser performance checkpoint|agent-browser|playwright-fallback)\b`,
|
|
561
|
+
"i",
|
|
562
|
+
);
|
|
559
563
|
const browserPerformanceCheckpointPattern =
|
|
560
564
|
/\b(?:agent-browser|browser performance checkpoint|performance checkpoint|verify:perf|test:browser:perf|playwright-fallback)\b/i;
|
|
561
565
|
const fallbackPerfReasonPattern =
|
|
@@ -599,7 +603,7 @@ function isPassedAgentBrowserPerfRunLine(line: string): boolean {
|
|
|
599
603
|
function isPassedPlaywrightFallbackPerfRunLine(line: string): boolean {
|
|
600
604
|
return (
|
|
601
605
|
isVerificationEvidenceLine(line) &&
|
|
602
|
-
(/\
|
|
606
|
+
(/\b(?:pnpm\s+verify:perf|npm\s+run\s+verify:perf|verify:perf)\b/i.test(line) ||
|
|
603
607
|
(/\bplaywright-fallback\b/i.test(line) &&
|
|
604
608
|
/\b(?:performance|perf|checkpoint)\b/i.test(line))) &&
|
|
605
609
|
!isIncompleteOrSkippedLine(line)
|
|
@@ -643,7 +647,7 @@ function getAgentWorklogVerificationGateErrors(source: string): string[] {
|
|
|
643
647
|
|
|
644
648
|
if (!hasPassedPerfRun && !hasAllowedPerfSkip) {
|
|
645
649
|
errors.push(
|
|
646
|
-
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or
|
|
650
|
+
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or this app's verify:perf script with an explicit fallback reason when no agent browser or CI/non-agent automation is used.",
|
|
647
651
|
);
|
|
648
652
|
}
|
|
649
653
|
|
|
@@ -721,7 +725,11 @@ function getAgentWorklogValidationErrors(source: string): string[] {
|
|
|
721
725
|
);
|
|
722
726
|
}
|
|
723
727
|
|
|
724
|
-
if (
|
|
728
|
+
if (
|
|
729
|
+
!/\b(?:pnpm\s+(?:verify|test|build|typecheck)|npm\s+run\s+(?:verify|test|build|typecheck)|browser|Playwright|perf)\b/i.test(
|
|
730
|
+
verificationBody,
|
|
731
|
+
)
|
|
732
|
+
) {
|
|
725
733
|
errors.push("agent-worklog.md Verification must list concrete test/build/browser/performance checks.");
|
|
726
734
|
}
|
|
727
735
|
|
|
@@ -3182,19 +3190,20 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3182
3190
|
});
|
|
3183
3191
|
|
|
3184
3192
|
it("documents control selection inventory and custom built-in fit checks", () => {
|
|
3185
|
-
const
|
|
3193
|
+
const coreControlSelection = readToolcraftDoc("core/control-selection.md");
|
|
3186
3194
|
const componentRules = readToolcraftDoc("component-rules.md");
|
|
3187
3195
|
const acceptanceTesting = readToolcraftDoc("acceptance-testing.md");
|
|
3188
3196
|
|
|
3189
|
-
expect(
|
|
3190
|
-
expect(
|
|
3191
|
-
expect(
|
|
3192
|
-
expect(
|
|
3197
|
+
expect(coreControlSelection).toContain("Control Selection Inventory");
|
|
3198
|
+
expect(coreControlSelection).toContain("Product need:");
|
|
3199
|
+
expect(coreControlSelection).toContain("Candidate built-ins checked:");
|
|
3200
|
+
expect(coreControlSelection).toContain("Best built-in:");
|
|
3201
|
+
expect(coreControlSelection).toContain("Rejected alternatives:");
|
|
3202
|
+
expect(coreControlSelection).toContain("Target:");
|
|
3203
|
+
expect(coreControlSelection).toContain("Custom Control Gate");
|
|
3193
3204
|
|
|
3194
3205
|
expect(componentRules).toContain("Control Decision Catalog");
|
|
3195
|
-
expect(componentRules).toContain("
|
|
3196
|
-
expect(componentRules).toContain("Best fit");
|
|
3197
|
-
expect(componentRules).toContain("Custom escape hatch");
|
|
3206
|
+
expect(componentRules).toContain("core/control-selection.md");
|
|
3198
3207
|
|
|
3199
3208
|
expect(acceptanceTesting).toContain("wrong-substitution");
|
|
3200
3209
|
expect(acceptanceTesting).toContain("built-in fit check");
|
|
@@ -3689,7 +3698,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3689
3698
|
expect.arrayContaining([
|
|
3690
3699
|
"agent-worklog.md required checks must be passed before final delivery; do not report failed, incomplete, pending, or blocked verification.",
|
|
3691
3700
|
"agent-worklog.md must not list required checks as skipped unless they are explicitly not required for a post-first-working non-performance edit.",
|
|
3692
|
-
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or
|
|
3701
|
+
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or this app's verify:perf script with an explicit fallback reason when no agent browser or CI/non-agent automation is used.",
|
|
3693
3702
|
]),
|
|
3694
3703
|
);
|
|
3695
3704
|
});
|
|
@@ -3775,7 +3784,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3775
3784
|
`;
|
|
3776
3785
|
|
|
3777
3786
|
expect(getAgentWorklogValidationErrors(missingPerfWorklog)).toContain(
|
|
3778
|
-
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or
|
|
3787
|
+
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or this app's verify:perf script with an explicit fallback reason when no agent browser or CI/non-agent automation is used.",
|
|
3779
3788
|
);
|
|
3780
3789
|
});
|
|
3781
3790
|
|
|
@@ -3992,7 +4001,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3992
4001
|
`;
|
|
3993
4002
|
|
|
3994
4003
|
expect(getAgentWorklogValidationErrors(missingFallbackReasonWorklog)).toContain(
|
|
3995
|
-
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or
|
|
4004
|
+
"agent-worklog.md Verification must record the browser performance checkpoint for first working product delivery: use agent-browser when available, or this app's verify:perf script with an explicit fallback reason when no agent browser or CI/non-agent automation is used.",
|
|
3996
4005
|
);
|
|
3997
4006
|
});
|
|
3998
4007
|
|
|
@@ -321,6 +321,8 @@ describe("Toolcraft template app performance coverage", () => {
|
|
|
321
321
|
const packageJson = JSON.parse(readFileSync(join(projectDir, "package.json"), "utf8")) as {
|
|
322
322
|
scripts?: Record<string, string>;
|
|
323
323
|
};
|
|
324
|
+
const runScriptPattern = (scriptName: string) =>
|
|
325
|
+
`(?:pnpm ${scriptName}|npm run ${scriptName})`;
|
|
324
326
|
|
|
325
327
|
expect(
|
|
326
328
|
packageJson.scripts?.["test:browser"],
|
|
@@ -332,14 +334,22 @@ describe("Toolcraft template app performance coverage", () => {
|
|
|
332
334
|
).toBe(
|
|
333
335
|
'playwright install chromium && playwright test --grep "browser perf:" --workers=1 --pass-with-no-tests',
|
|
334
336
|
);
|
|
335
|
-
expect(packageJson.scripts?.["verify:quick"]).
|
|
336
|
-
|
|
337
|
-
expect(packageJson.scripts?.["verify:perf"]).toBe("pnpm test:browser:perf");
|
|
338
|
-
expect(packageJson.scripts?.["verify:perf:playwright"]).toBe(
|
|
339
|
-
"pnpm test:browser:perf",
|
|
337
|
+
expect(packageJson.scripts?.["verify:quick"]).toMatch(
|
|
338
|
+
new RegExp(`^${runScriptPattern("ai:check")} && ${runScriptPattern("test")}$`),
|
|
340
339
|
);
|
|
341
|
-
expect(packageJson.scripts?.["verify:
|
|
342
|
-
"
|
|
340
|
+
expect(packageJson.scripts?.["verify:ui"]).toMatch(
|
|
341
|
+
new RegExp(`^${runScriptPattern("test:browser")}$`),
|
|
342
|
+
);
|
|
343
|
+
expect(packageJson.scripts?.["verify:perf"]).toMatch(
|
|
344
|
+
new RegExp(`^${runScriptPattern("test:browser:perf")}$`),
|
|
345
|
+
);
|
|
346
|
+
expect(packageJson.scripts?.["verify:perf:playwright"]).toMatch(
|
|
347
|
+
new RegExp(`^${runScriptPattern("test:browser:perf")}$`),
|
|
348
|
+
);
|
|
349
|
+
expect(packageJson.scripts?.["verify:final"]).toMatch(
|
|
350
|
+
new RegExp(
|
|
351
|
+
`^${runScriptPattern("ai:check")} && ${runScriptPattern("test")} && ${runScriptPattern("build")} && ${runScriptPattern("test:browser")}$`,
|
|
352
|
+
),
|
|
343
353
|
);
|
|
344
354
|
});
|
|
345
355
|
|