@cherishxn/agent-scaffold 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +30 -2
  2. package/THIRD_PARTY_NOTICES.md +4 -0
  3. package/dist/cli.js +9 -4
  4. package/dist/diagnostics.d.ts +10 -0
  5. package/dist/diagnostics.js +27 -0
  6. package/dist/generate.js +8 -3
  7. package/dist/model.d.ts +1 -1
  8. package/dist/model.js +1 -1
  9. package/dist/verify.d.ts +7 -1
  10. package/dist/verify.js +36 -22
  11. package/package.json +5 -2
  12. package/skills/scaffold-use/SKILL.md +20 -2
  13. package/templates/catalog.json +16 -16
  14. package/templates/next-fullstack-antd/.agents/skills/project-work/SKILL.md +6 -4
  15. package/templates/next-fullstack-antd/.claude/skills/project-work/SKILL.md +6 -4
  16. package/templates/next-fullstack-antd/.grok/skills/project-work/SKILL.md +6 -4
  17. package/templates/next-fullstack-antd/AGENTS.md +1 -1
  18. package/templates/next-fullstack-antd/README.md +14 -5
  19. package/templates/next-fullstack-antd/THIRD_PARTY_NOTICES.md +4 -0
  20. package/templates/next-fullstack-antd/docs/PROJECT.md +23 -0
  21. package/templates/next-fullstack-antd/docs/api.d.ts +32 -4
  22. package/templates/next-fullstack-antd/docs/openapi.json +25 -3
  23. package/templates/next-fullstack-antd/package-lock.json +54 -0
  24. package/templates/next-fullstack-antd/package.json +5 -0
  25. package/templates/next-fullstack-antd/playwright.config.ts +1 -1
  26. package/templates/next-fullstack-antd/scripts/api-check.mjs +18 -0
  27. package/templates/next-fullstack-antd/scripts/api-contract.mjs +46 -0
  28. package/templates/next-fullstack-antd/scripts/project.mjs +4 -2
  29. package/templates/next-fullstack-antd/tests/contract-client.ts +20 -0
  30. package/templates/next-fullstack-antd/tests/contract.spec.ts +4 -2
  31. package/templates/next-fullstack-shadcn/.agents/skills/project-work/SKILL.md +6 -4
  32. package/templates/next-fullstack-shadcn/.claude/skills/project-work/SKILL.md +6 -4
  33. package/templates/next-fullstack-shadcn/.grok/skills/project-work/SKILL.md +6 -4
  34. package/templates/next-fullstack-shadcn/AGENTS.md +1 -1
  35. package/templates/next-fullstack-shadcn/README.md +14 -5
  36. package/templates/next-fullstack-shadcn/THIRD_PARTY_NOTICES.md +4 -0
  37. package/templates/next-fullstack-shadcn/docs/PROJECT.md +23 -0
  38. package/templates/next-fullstack-shadcn/docs/api.d.ts +32 -4
  39. package/templates/next-fullstack-shadcn/docs/openapi.json +25 -3
  40. package/templates/next-fullstack-shadcn/package-lock.json +54 -0
  41. package/templates/next-fullstack-shadcn/package.json +5 -0
  42. package/templates/next-fullstack-shadcn/playwright.config.ts +1 -1
  43. package/templates/next-fullstack-shadcn/scripts/api-check.mjs +18 -0
  44. package/templates/next-fullstack-shadcn/scripts/api-contract.mjs +46 -0
  45. package/templates/next-fullstack-shadcn/scripts/project.mjs +4 -2
  46. package/templates/next-fullstack-shadcn/tests/contract-client.ts +20 -0
  47. package/templates/next-fullstack-shadcn/tests/contract.spec.ts +4 -2
  48. package/templates/react-fastapi-antd/.agents/skills/project-work/SKILL.md +6 -4
  49. package/templates/react-fastapi-antd/.claude/skills/project-work/SKILL.md +6 -4
  50. package/templates/react-fastapi-antd/.grok/skills/project-work/SKILL.md +6 -4
  51. package/templates/react-fastapi-antd/AGENTS.md +1 -1
  52. package/templates/react-fastapi-antd/README.md +14 -5
  53. package/templates/react-fastapi-antd/THIRD_PARTY_NOTICES.md +4 -0
  54. package/templates/react-fastapi-antd/docs/PROJECT.md +23 -0
  55. package/templates/react-fastapi-antd/docs/api.d.ts +32 -4
  56. package/templates/react-fastapi-antd/docs/openapi.json +25 -3
  57. package/templates/react-fastapi-antd/package-lock.json +54 -0
  58. package/templates/react-fastapi-antd/package.json +5 -0
  59. package/templates/react-fastapi-antd/playwright.config.ts +1 -1
  60. package/templates/react-fastapi-antd/scripts/api-check.mjs +18 -0
  61. package/templates/react-fastapi-antd/scripts/api-contract.mjs +46 -0
  62. package/templates/react-fastapi-antd/scripts/project.mjs +4 -2
  63. package/templates/react-fastapi-antd/tests/contract-client.ts +20 -0
  64. package/templates/react-fastapi-antd/tests/contract.spec.ts +4 -2
  65. package/templates/react-fastapi-shadcn/.agents/skills/project-work/SKILL.md +6 -4
  66. package/templates/react-fastapi-shadcn/.claude/skills/project-work/SKILL.md +6 -4
  67. package/templates/react-fastapi-shadcn/.grok/skills/project-work/SKILL.md +6 -4
  68. package/templates/react-fastapi-shadcn/AGENTS.md +1 -1
  69. package/templates/react-fastapi-shadcn/README.md +14 -5
  70. package/templates/react-fastapi-shadcn/THIRD_PARTY_NOTICES.md +4 -0
  71. package/templates/react-fastapi-shadcn/docs/PROJECT.md +23 -0
  72. package/templates/react-fastapi-shadcn/docs/api.d.ts +32 -4
  73. package/templates/react-fastapi-shadcn/docs/openapi.json +25 -3
  74. package/templates/react-fastapi-shadcn/package-lock.json +54 -0
  75. package/templates/react-fastapi-shadcn/package.json +5 -0
  76. package/templates/react-fastapi-shadcn/playwright.config.ts +1 -1
  77. package/templates/react-fastapi-shadcn/scripts/api-check.mjs +18 -0
  78. package/templates/react-fastapi-shadcn/scripts/api-contract.mjs +46 -0
  79. package/templates/react-fastapi-shadcn/scripts/project.mjs +4 -2
  80. package/templates/react-fastapi-shadcn/tests/contract-client.ts +20 -0
  81. package/templates/react-fastapi-shadcn/tests/contract.spec.ts +4 -2
  82. package/templates/react-nest-antd/.agents/skills/project-work/SKILL.md +6 -4
  83. package/templates/react-nest-antd/.claude/skills/project-work/SKILL.md +6 -4
  84. package/templates/react-nest-antd/.grok/skills/project-work/SKILL.md +6 -4
  85. package/templates/react-nest-antd/AGENTS.md +1 -1
  86. package/templates/react-nest-antd/README.md +14 -5
  87. package/templates/react-nest-antd/THIRD_PARTY_NOTICES.md +4 -0
  88. package/templates/react-nest-antd/docs/PROJECT.md +23 -0
  89. package/templates/react-nest-antd/docs/api.d.ts +32 -4
  90. package/templates/react-nest-antd/docs/openapi.json +25 -3
  91. package/templates/react-nest-antd/package-lock.json +54 -0
  92. package/templates/react-nest-antd/package.json +5 -0
  93. package/templates/react-nest-antd/playwright.config.ts +1 -1
  94. package/templates/react-nest-antd/scripts/api-check.mjs +18 -0
  95. package/templates/react-nest-antd/scripts/api-contract.mjs +46 -0
  96. package/templates/react-nest-antd/scripts/project.mjs +4 -2
  97. package/templates/react-nest-antd/tests/contract-client.ts +20 -0
  98. package/templates/react-nest-antd/tests/contract.spec.ts +4 -2
  99. package/templates/react-nest-shadcn/.agents/skills/project-work/SKILL.md +6 -4
  100. package/templates/react-nest-shadcn/.claude/skills/project-work/SKILL.md +6 -4
  101. package/templates/react-nest-shadcn/.grok/skills/project-work/SKILL.md +6 -4
  102. package/templates/react-nest-shadcn/AGENTS.md +1 -1
  103. package/templates/react-nest-shadcn/README.md +14 -5
  104. package/templates/react-nest-shadcn/THIRD_PARTY_NOTICES.md +4 -0
  105. package/templates/react-nest-shadcn/docs/PROJECT.md +23 -0
  106. package/templates/react-nest-shadcn/docs/api.d.ts +32 -4
  107. package/templates/react-nest-shadcn/docs/openapi.json +25 -3
  108. package/templates/react-nest-shadcn/package-lock.json +54 -0
  109. package/templates/react-nest-shadcn/package.json +5 -0
  110. package/templates/react-nest-shadcn/playwright.config.ts +1 -1
  111. package/templates/react-nest-shadcn/scripts/api-check.mjs +18 -0
  112. package/templates/react-nest-shadcn/scripts/api-contract.mjs +46 -0
  113. package/templates/react-nest-shadcn/scripts/project.mjs +4 -2
  114. package/templates/react-nest-shadcn/tests/contract-client.ts +20 -0
  115. package/templates/react-nest-shadcn/tests/contract.spec.ts +4 -2
  116. package/templates/react-spring-antd/.agents/skills/project-work/SKILL.md +6 -4
  117. package/templates/react-spring-antd/.claude/skills/project-work/SKILL.md +6 -4
  118. package/templates/react-spring-antd/.grok/skills/project-work/SKILL.md +6 -4
  119. package/templates/react-spring-antd/AGENTS.md +1 -1
  120. package/templates/react-spring-antd/README.md +14 -5
  121. package/templates/react-spring-antd/THIRD_PARTY_NOTICES.md +4 -0
  122. package/templates/react-spring-antd/backend/src/main/resources/openapi.json +25 -3
  123. package/templates/react-spring-antd/docs/PROJECT.md +23 -0
  124. package/templates/react-spring-antd/docs/api.d.ts +32 -4
  125. package/templates/react-spring-antd/docs/openapi.json +25 -3
  126. package/templates/react-spring-antd/package-lock.json +54 -0
  127. package/templates/react-spring-antd/package.json +5 -0
  128. package/templates/react-spring-antd/playwright.config.ts +1 -1
  129. package/templates/react-spring-antd/scripts/api-check.mjs +18 -0
  130. package/templates/react-spring-antd/scripts/api-contract.mjs +46 -0
  131. package/templates/react-spring-antd/scripts/project.mjs +4 -2
  132. package/templates/react-spring-antd/tests/contract-client.ts +20 -0
  133. package/templates/react-spring-antd/tests/contract.spec.ts +4 -2
  134. package/templates/react-spring-shadcn/.agents/skills/project-work/SKILL.md +6 -4
  135. package/templates/react-spring-shadcn/.claude/skills/project-work/SKILL.md +6 -4
  136. package/templates/react-spring-shadcn/.grok/skills/project-work/SKILL.md +6 -4
  137. package/templates/react-spring-shadcn/AGENTS.md +1 -1
  138. package/templates/react-spring-shadcn/README.md +14 -5
  139. package/templates/react-spring-shadcn/THIRD_PARTY_NOTICES.md +4 -0
  140. package/templates/react-spring-shadcn/backend/src/main/resources/openapi.json +25 -3
  141. package/templates/react-spring-shadcn/docs/PROJECT.md +23 -0
  142. package/templates/react-spring-shadcn/docs/api.d.ts +32 -4
  143. package/templates/react-spring-shadcn/docs/openapi.json +25 -3
  144. package/templates/react-spring-shadcn/package-lock.json +54 -0
  145. package/templates/react-spring-shadcn/package.json +5 -0
  146. package/templates/react-spring-shadcn/playwright.config.ts +1 -1
  147. package/templates/react-spring-shadcn/scripts/api-check.mjs +18 -0
  148. package/templates/react-spring-shadcn/scripts/api-contract.mjs +46 -0
  149. package/templates/react-spring-shadcn/scripts/project.mjs +4 -2
  150. package/templates/react-spring-shadcn/tests/contract-client.ts +20 -0
  151. package/templates/react-spring-shadcn/tests/contract.spec.ts +4 -2
package/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  面向 Codex、Claude Code、Grok Build 的项目脚手架。四套技术栈(React + FastAPI、React + Spring Boot、React + NestJS、Next.js)各支持 shadcn/ui 和 Ant Design,共八个组合。生成应用包含登录和个人记录 CRUD,默认不含 AI。
4
4
 
5
+ ## 选择技术栈
6
+
7
+ | 已有偏好 | 建议起点 | 额外运行环境 |
8
+ | --- | --- | --- |
9
+ | Python 后端 | React + FastAPI | Python 3.12、uv、Bun |
10
+ | Java / Spring 团队 | React + Spring Boot | JDK 17 或更高版本、pnpm 10;自带 Maven Wrapper |
11
+ | 前后端都用 TypeScript,独立 API | React + NestJS | pnpm 10 |
12
+ | 一个 TypeScript 全栈工程 | Next.js | pnpm 10 |
13
+
14
+ 都需要 Node.js 24 和 Docker。没有既定偏好时可从 Next.js + shadcn 开始;两种 UI 的设计意图和业务能力保持一致,按组件库偏好选择。
15
+
5
16
  ## 本地使用
6
17
 
7
18
  需要 Node.js 24:
@@ -23,6 +34,8 @@ npx @cherishxn/agent-scaffold@latest plan --spec spec.json --out plan.json --jso
23
34
  npx @cherishxn/agent-scaffold@latest init --plan plan.json --json
24
35
  ```
25
36
 
37
+ 1.1.0 候选支持 `plan --spec spec.json --json` 的零写入预览;只有提供 `--out` 才保存计划。预览与创建使用同一精确 CLI 版本,计划绑定模板摘要。当前公开版与候选验收状态见 [验证记录](docs/VERIFICATION.md)。
38
+
26
39
  也可直接 `init --spec spec.json --json`。命令返回安装步骤和工作目录,不自动安装依赖或启动服务。进入生成目录后:
27
40
 
28
41
  ```bash
@@ -34,6 +47,11 @@ npm run dev
34
47
 
35
48
  ## 检查与报告
36
49
 
50
+ 1.1.0 候选提供安装前工具检查 `doctor --dir . --tools-only --json`,失败项会说明修复方法;默认 doctor 同时检查项目依赖。它只诊断,不安装工具或启动服务。
51
+
52
+ 新生成项目的 `npm run check` 按类型、Lint、构建顺序执行,遇到失败即停止,适合日常反馈;它不替代以下真实业务验证。
53
+
54
+
37
55
  ```bash
38
56
  npx @cherishxn/agent-scaffold@latest doctor --dir . --json
39
57
  npx @cherishxn/agent-scaffold@latest verify --dir . --json
@@ -52,7 +70,7 @@ verify 启动独立 PostgreSQL,运行类型、Lint、构建、迁移、种子
52
70
 
53
71
  打包后的 CLI 包含 `skills/scaffold-use/SKILL.md`。按当前宿主约定,把该目录复制到发起创建的工作目录:Codex 使用 `.agents/skills/scaffold-use`,Claude Code 使用 `.claude/skills/scaffold-use`,Grok Build 使用 `.grok/skills/scaffold-use`。这一步由使用者或已获授权的 Agent 执行;CLI 不改全局配置。
54
72
 
55
- 生成项目自带 AGENTS.md、薄 CLAUDE.md,以及上述三个原生目录下同源的 project-work Skill。切换到新工程后核对规则与 Skill 是否加载。具体宿主兼容范围以交付记录为准。
73
+ 生成项目自带 AGENTS.md、薄 CLAUDE.md,以及上述三个原生目录下同源的 project-work Skill。docs/PROJECT.md 的任务表按实际技术栈指向 API、认证、迁移、设计和测试入口。切换到新工程后核对规则与 Skill 是否加载。具体宿主兼容范围以交付记录为准。
56
74
 
57
75
  ## 开发与分发
58
76
 
@@ -65,8 +83,18 @@ npm run matrix
65
83
  npm pack
66
84
  ```
67
85
 
68
- 源码仓库保持私有,CLI 按发布白名单分发至 npm 公共包。`npm pack` 构建包含八套模板与锁文件的本地安装包。模板源码位于 template-src;templates 是可重新生成的产物。更新依赖后运行 scripts/lock-templates.mjs 并重新验证受影响矩阵。
86
+ 源码仓库保持私有,CLI 按发布白名单分发至 npm 公共包。`npm pack` 构建包含八套模板与锁文件的本地安装包。模板源码位于 template-src;templates 是可重新生成的产物。普通模板层只允许添加文件,路径冲突会停止构建;生成文件或锁文件替换由 materialize 脚本显式完成。更新依赖后运行 scripts/lock-templates.mjs 并重新验证受影响矩阵。
69
87
 
70
88
  [开发计划](docs/DEVELOPMENT-PLAN.md) · [验证记录](docs/VERIFICATION.md) · [设计基线 v0.5](docs/reference/AGENT-SCAFFOLD-DESIGN-v0.5.md) · [来源与许可证](THIRD_PARTY_NOTICES.md)
71
89
 
72
90
  运行测试通过不代表生产部署或产品/PM 业务验收完成。
91
+
92
+ 本轮选择性学习 VibeStart 的预览、Agent 指引、快速反馈与模板文件归属机制;具体采用项和保留边界见 [源码研究与采纳映射](docs/reference/VIBESTART-REVIEW.md)。实现沿用本项目架构,未引入其技术栈或全量源码。
93
+
94
+ ## 验证反馈与接口一致性
95
+
96
+ verify 保留原退出码和报告字段,失败分项新增 diagnostic(code、retryable、nextAction),evidence 指向脱敏日志及 JUnit。端口冲突、连接拒绝、主机解析失败、启动失败、超时与缺测试证据分开;未知错误保持 UNKNOWN_FAILURE,不自动重试或修改运行环境。API/浏览器测试采集服务 stdout/stderr。
97
+
98
+ 生成项目提供 `npm run api:check`:在系统临时目录生成类型并比较 docs/api.d.ts,检查不回写源码;有意修改 docs/openapi.json 后运行 `npm run api:generate`。check/verify 自动运行此门禁,真实 HTTP 回归按契约检查响应状态和结构。
99
+
100
+ Codex 接手开发的固定题库、运行方法与局限见 [评测说明](evals/codex/README.md)。这与模板本身的八组合业务矩阵分别留证。
@@ -12,3 +12,7 @@ Templates are maintained derivatives, not unmodified upstream distributions. Exa
12
12
  | Ant Design | npm 6.6.6 | Installed dependency; no copied source | MIT (package license) |
13
13
 
14
14
  Package dependencies carry their own licenses. Generated apps include these notices; template authors must carry applicable notices when changing upstream-derived files. Names and marks remain their respective owners'.
15
+
16
+ ## Design and workflow reference
17
+
18
+ VinkyDev/vibestart at commit `5768fc561340422bf7736499fe69b1aae263790a` (MIT) informed the preview, task-oriented Agent guidance, quick checks and template-layer collision rules. These changes are independently implemented for Agent Scaffold; no VibeStart source, bundled skills, branding or UI assets are redistributed. The source review and selected adaptations are recorded in docs/reference/VIBESTART-REVIEW.md.
package/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ async function interactive() {
50
50
  }
51
51
  const program = new Command().name('scaffold').version(CLI_VERSION).description('Create and verify complete web projects.').option('--json', 'Non-interactive JSON output').exitOverride().configureOutput({ writeOut: s => process.stdout.write(s), writeErr: s => process.stderr.write(s) });
52
52
  program.command('templates').description('List bundled templates and input schema').action(async () => { commandName = 'templates'; output(await catalog()); });
53
- program.command('plan').description('Validate spec and write a new deterministic plan').requiredOption('--spec <file>').requiredOption('--out <file>').action(async (o) => { commandName = 'plan'; output(await writePlan(await jsonFile(o.spec), o.out)); });
53
+ program.command('plan').description('Preview a deterministic plan; write it only when --out is provided').requiredOption('--spec <file>').option('--out <file>', 'Write to a new plan file').action(async (o) => { commandName = 'plan'; const spec = await jsonFile(o.spec); output(o.out ? await writePlan(spec, o.out) : await makePlan(spec)); });
54
54
  program.command('init').description('Create a project interactively, from JSON spec, or from a plan').option('--spec <file>').option('--plan <file>').option('--dir <path>').action(async (o) => {
55
55
  commandName = 'init';
56
56
  if (o.spec && o.plan)
@@ -68,9 +68,14 @@ program.command('init').description('Create a project interactively, from JSON s
68
68
  o.dir = o.dir ?? i.dir;
69
69
  }
70
70
  const result = await initialize(plan, o.dir ?? plan.normalizedSpec.nameEn);
71
- output(result, result.nextActions);
71
+ if (json)
72
+ output(result, result.nextActions);
73
+ else {
74
+ const directory = "'" + result.directory.replaceAll("'", "'\"'\"'") + "'";
75
+ stdout.write(`\n${result.status === 'created' ? '已创建' : '工程已存在且内容一致'}:${plan.normalizedSpec.nameZh}\n${plan.templateId} / ${plan.normalizedSpec.ui}\n目录:${result.directory}\n\n下一步:\n cd ${directory}\n npm run setup\n npm run dev\n\n安装前检查:npx @cherishxn/agent-scaffold@${CLI_VERSION} doctor --dir . --tools-only --json\n开发规则:AGENTS.md;任务路径:docs/PROJECT.md;本地账号:.scaffold-local-credentials(setup 后生成)\n项目文件已生成;依赖安装、启动与业务验证尚未执行。\n`);
76
+ }
72
77
  });
73
- program.command('doctor').description('Read-only local prerequisite checks').requiredOption('--dir <path>').action(async (o) => { commandName = 'doctor'; const r = await doctor(o.dir); output(r); process.exitCode = r.ok ? 0 : 3; });
78
+ program.command('doctor').description('Read-only local prerequisite checks').requiredOption('--dir <path>').option('--tools-only', 'Check tools before installing project dependencies').action(async (o) => { commandName = 'doctor'; const r = await doctor(o.dir, { toolsOnly: o.toolsOnly }); output(r); process.exitCode = r.ok ? 0 : 3; });
74
79
  program.command('verify').description('Run isolated baseline checks').requiredOption('--dir <path>').option('--profile <name>', 'Check profile', 'baseline').action(async (o) => { commandName = 'verify'; if (o.profile !== 'baseline')
75
80
  throw new ScaffoldError('INVALID_PROFILE', 'Only baseline is supported.'); const r = await verify(o.dir); output(r); process.exitCode = r.exitCode; });
76
81
  program.command('report').description('Read latest results and current content validity').requiredOption('--dir <path>').action(async (o) => { commandName = 'report'; output(await report(o.dir)); });
@@ -81,7 +86,7 @@ try {
81
86
  if (!c)
82
87
  throw new ScaffoldError('UNKNOWN_COMMAND', 'Unknown command.');
83
88
  commandName = 'help';
84
- output({ version: CLI_VERSION, name: c.name(), description: c.description(), options: c.options.map(o => ({ flags: o.flags, description: o.description, required: o.mandatory })), commands: program.commands.map(c => ({ name: c.name(), description: c.description() })), schemas: ['spec', 'plan', 'manifest', 'result'].map(s => join(packageRoot, `schemas/${s}.json`)), exitCodes: { 0: 'command succeeded; inspect overallStatus for report', 2: 'invalid input', 3: 'environment or incomplete checks', 4: 'failed checks', 5: 'internal error', 130: 'interrupted' }, sideEffects: { templates: [], plan: ['write new plan'], init: ['write new project'], doctor: [], verify: ['build, isolated database, reports'], report: [] }, prerequisites: ['Node.js 24', 'See templates for stack-specific runtimes'] });
89
+ output({ version: CLI_VERSION, name: c.name(), description: c.description(), options: c.options.map(o => ({ flags: o.flags, description: o.description, required: o.mandatory })), commands: program.commands.map(c => ({ name: c.name(), description: c.description() })), schemas: ['spec', 'plan', 'manifest', 'result'].map(s => join(packageRoot, `schemas/${s}.json`)), exitCodes: { 0: 'command succeeded; inspect overallStatus for report', 2: 'invalid input', 3: 'environment or incomplete checks', 4: 'failed checks', 5: 'internal error', 130: 'interrupted' }, sideEffects: { templates: [], plan: ['write new plan only with --out'], init: ['write new project'], doctor: [], verify: ['build, isolated database, reports'], report: [] }, prerequisites: ['Node.js 24', 'See templates for stack-specific runtimes'] });
85
90
  }
86
91
  else if (args.length === 0)
87
92
  program.help();
@@ -0,0 +1,10 @@
1
+ export type Diagnostic = {
2
+ code: string;
3
+ retryable: boolean;
4
+ nextAction: string;
5
+ };
6
+ /** Classify observed failures only; unknown output must not invent a root cause. */
7
+ export declare function diagnose(stage: string, output: string, options?: {
8
+ timedOut?: boolean;
9
+ interrupted?: boolean;
10
+ }): Diagnostic;
@@ -0,0 +1,27 @@
1
+ /** Classify observed failures only; unknown output must not invent a root cause. */
2
+ export function diagnose(stage, output, options = {}) {
3
+ if (options.interrupted)
4
+ return { code: 'INTERRUPTED', retryable: false, nextAction: 'Review the completed steps and cleanup evidence before starting a new verification.' };
5
+ if (options.timedOut)
6
+ return { code: 'TIMEOUT', retryable: false, nextAction: 'Inspect the stage log and service startup output; resolve the stalled dependency before rerunning.' };
7
+ if (/EADDRINUSE|Address already in use|Port \d+ was already in use/i.test(output))
8
+ return { code: 'PORT_IN_USE', retryable: false, nextAction: 'Identify the process owning the reported port; choose a free port or stop only a process you own.' };
9
+ if (/UnknownHostException|Name or service not known|ENOTFOUND|getaddrinfo failed/i.test(output))
10
+ return { code: 'HOST_RESOLUTION_FAILED', retryable: false, nextAction: 'Check the failing hostname and this runtime\'s DNS/proxy configuration. Do not infer a database or application defect from this alone.' };
11
+ if (/ECONNREFUSED|Connection refused|connection to server .* failed|could not connect to server/i.test(output))
12
+ return { code: 'CONNECTION_REFUSED', retryable: false, nextAction: 'Use the endpoint in the log to check the expected service, port and runtime connectivity before retrying.' };
13
+ if (/Required report missing, contains failures, or has no executed test cases/.test(output))
14
+ return { code: 'TEST_EVIDENCE_INVALID', retryable: false, nextAction: 'Inspect the test command and JUnit artifact; missing, empty or failing reports cannot prove a pass.' };
15
+ if (/API_CONTRACT_DRIFT/.test(output))
16
+ return { code: 'API_CONTRACT_DRIFT', retryable: false, nextAction: 'Compare the contract and generated types; run api:generate after the intended contract change, then api:check.' };
17
+ if (/API_RESPONSE_INVALID/.test(output))
18
+ return { code: 'API_RESPONSE_INVALID', retryable: false, nextAction: 'Compare the reported operation, response status and schema path with the intended HTTP behavior.' };
19
+ if (/spawn(?:Sync)? \S+ ENOENT|command not found/.test(output))
20
+ return { code: 'COMMAND_NOT_FOUND', retryable: false, nextAction: 'Run doctor and install the missing executable or correct its path.' };
21
+ if (/ENOENT/.test(output))
22
+ return { code: 'FILE_NOT_FOUND', retryable: false, nextAction: 'Inspect the missing file path and the stage that requested it; an ENOENT file error does not establish a missing executable.' };
23
+ if (stage === 'test-api' || stage === 'test-e2e')
24
+ if (/Process from config.webServer|webServer.*(?:exited|failed)|Timed out waiting.*config.webServer/i.test(output))
25
+ return { code: 'SERVICE_START_FAILED', retryable: false, nextAction: 'Inspect the captured webServer stdout/stderr for the first startup error; the underlying cause is not yet classified.' };
26
+ return { code: 'UNKNOWN_FAILURE', retryable: false, nextAction: 'Inspect the linked log and artifacts. The cause is unknown; do not automatically repeat the action or modify unrelated code.' };
27
+ }
package/dist/generate.js CHANGED
@@ -19,7 +19,12 @@ export async function specFrom(input) {
19
19
  const normalized = input && typeof input === 'object' && !Array.isArray(input) ? Object.fromEntries(Object.entries(input).map(([k, v]) => [k, typeof v === 'string' ? v.trim() : v])) : input;
20
20
  if (!validate(normalized)) {
21
21
  const e = validate.errors?.[0];
22
- throw new ScaffoldError('INVALID_SPEC', e?.message ?? 'Invalid project specification.', 2, e?.instancePath || String(e?.params.missingProperty ?? 'spec'));
22
+ const field = e?.instancePath || String(e?.params.missingProperty ?? 'spec');
23
+ const reason = e?.keyword === 'enum' ? `Choose one of: ${e.params.allowedValues.join(', ')}.`
24
+ : field === '/nameEn' ? 'Use 1–50 lowercase letters, digits and single hyphens; start with a letter (for example: my-project).'
25
+ : e?.keyword === 'additionalProperties' ? `Unknown field: ${String(e.params.additionalProperty)}. See templates --json for the input schema.`
26
+ : `${e?.message ?? 'Invalid project specification'}. See templates --json for an example.`;
27
+ throw new ScaffoldError('INVALID_SPEC', reason, 2, field);
23
28
  }
24
29
  return normalized;
25
30
  }
@@ -46,7 +51,7 @@ async function render(spec) {
46
51
  const sourceDigest = digest(canonical(source.map(x => ({ path: x.path, digest: digest(x.bytes), mode: x.mode }))));
47
52
  if (catalog.entries[`${spec.template}-${spec.ui}`]?.digest !== sourceDigest)
48
53
  throw new ScaffoldError('TEMPLATE_INTEGRITY', 'Bundled template does not match the published catalog.');
49
- const contents = new Map(source.map(x => [x.path === 'gitignore.template' ? '.gitignore' : x.path, { content: Buffer.from(x.bytes.toString('utf8').replaceAll('__NAME_EN__', spec.nameEn)), source: x.path, mode: x.mode }]));
54
+ const contents = new Map(source.map(x => [x.path === 'gitignore.template' ? '.gitignore' : x.path, { content: Buffer.from(x.bytes.toString('utf8').replaceAll('__NAME_EN__', spec.nameEn).replaceAll('__CLI_VERSION__', CLI_VERSION)), source: x.path, mode: x.mode }]));
50
55
  contents.set('project.json', { content: Buffer.from(JSON.stringify(spec, null, 2) + '\n'), source: 'generated:spec', mode: 0o644 });
51
56
  const pkg = contents.get('package.json');
52
57
  if (pkg) {
@@ -129,7 +134,7 @@ export async function initialize(plan, target) {
129
134
  }
130
135
  }
131
136
  catch { /* Existing data is never overwritten. */ }
132
- throw new ScaffoldError('DIRECTORY_CONFLICT', 'Target is non-empty or contains changed/incomplete output.', 2, dir);
137
+ throw new ScaffoldError('DIRECTORY_CONFLICT', 'Target is non-empty or contains changed/incomplete output. Choose a new --dir; existing files were preserved.', 2, dir);
133
138
  }
134
139
  await mkdir(dir, { recursive: true });
135
140
  // Reject even empty user-created subdirectories, and concurrent writes before the first output.
package/dist/model.d.ts CHANGED
@@ -30,4 +30,4 @@ export declare class ScaffoldError extends Error {
30
30
  }
31
31
  export declare function canonical(value: unknown): string;
32
32
  export declare function digest(value: string | Buffer): string;
33
- export declare const CLI_VERSION = "1.0.0";
33
+ export declare const CLI_VERSION = "1.1.0";
package/dist/model.js CHANGED
@@ -21,4 +21,4 @@ export function canonical(value) {
21
21
  return JSON.stringify(value);
22
22
  }
23
23
  export function digest(value) { return createHash('sha256').update(value).digest('hex'); }
24
- export const CLI_VERSION = '1.0.0';
24
+ export const CLI_VERSION = '1.1.0';
package/dist/verify.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type Diagnostic } from './diagnostics.js';
1
2
  type Check = {
2
3
  id: string;
3
4
  status: 'PASS' | 'FAIL' | 'NOT RUN' | 'N/A';
@@ -7,6 +8,7 @@ type Check = {
7
8
  exitCode: number | null;
8
9
  signal: string | null;
9
10
  evidence: string[];
11
+ diagnostic?: Diagnostic | null;
10
12
  };
11
13
  type Run = {
12
14
  schemaVersion: 1;
@@ -25,12 +27,16 @@ type Run = {
25
27
  exitCode: number;
26
28
  warnings: string[];
27
29
  };
28
- export declare function doctor(directory: string): Promise<{
30
+ export declare function doctor(directory: string, options?: {
31
+ toolsOnly?: boolean;
32
+ }): Promise<{
29
33
  ok: boolean;
34
+ scope: string;
30
35
  checks: {
31
36
  program: string;
32
37
  ok: boolean;
33
38
  version: string | undefined;
39
+ remedy: string | null;
34
40
  }[];
35
41
  platform: string;
36
42
  template: "react-fastapi" | "react-spring" | "react-nest" | "next-fullstack";
package/dist/verify.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { diagnose } from './diagnostics.js';
1
2
  import { spawn } from 'node:child_process';
2
3
  import { mkdir, readFile, writeFile, readdir, lstat } from 'node:fs/promises';
3
4
  import { resolve, join, relative } from 'node:path';
@@ -37,30 +38,39 @@ async function execute(program, args, cwd, env, timeout = 30000, abort) {
37
38
  onAbort();
38
39
  function finish(code, signal) { if (settled)
39
40
  return; settled = true; clearTimeout(timer); clearTimeout(hardTimer); clearTimeout(abortTimer); abort?.removeEventListener('abort', onAbort); resolveResult({ code, signal, output: text + (text.length >= 8_000_000 ? '\n[output truncated]' : ''), timedOut }); }
40
- c.on('error', () => finish(127, null));
41
+ c.on('error', error => { append(Buffer.from(`\n${error.code ?? 'SPAWN_ERROR'}: ${error.message}`)); finish(127, null); });
41
42
  c.on('close', (code, signal) => finish(code, signal));
42
43
  });
43
44
  }
44
- export async function doctor(directory) {
45
+ export async function doctor(directory, options = {}) {
45
46
  const dir = resolve(directory), spec = await project(dir), env = cleanEnv();
46
- const needs = [['node', ['--version']], ['docker', ['info', '--format', '{{.ServerVersion}}']]];
47
+ const needs = [
48
+ { program: 'node', args: ['--version'], label: 'node', remedy: 'Use Node.js 24, then rerun doctor.', accept: output => /^v24\./.test(output.trim()) },
49
+ { program: 'docker', args: ['info', '--format', '{{.ServerVersion}}'], label: 'docker', remedy: 'Start Docker and check that docker info succeeds for the selected context.' },
50
+ { program: 'docker', args: ['compose', 'version', '--short'], label: 'docker compose', remedy: 'Install the Docker Compose v2 plugin, then rerun doctor.' }
51
+ ];
47
52
  if (spec.template === 'react-fastapi')
48
- needs.push(['uv', ['--version']], ['bun', ['--version']]);
53
+ needs.push({ program: 'uv', args: ['--version'], label: 'uv', remedy: 'Install uv and add it to PATH; setup uses the locked Python 3.12 project.' }, { program: 'bun', args: ['--version'], label: 'bun', remedy: 'Install Bun and add it to PATH for the frontend lockfile.' });
49
54
  else
50
- needs.push(['pnpm', ['--version']]);
55
+ needs.push({ program: 'pnpm', args: ['--version'], label: 'pnpm', remedy: 'Use pnpm 10 and add it to PATH.', accept: output => /^10\./.test(output.trim()) });
51
56
  if (spec.template === 'react-spring')
52
- needs.push(['java', ['-version']]);
53
- const checks = await Promise.all(needs.map(async ([program, args]) => { const r = await execute(program, args, dir, env, 15000); return { program, ok: r.code === 0 && (program !== 'node' || /^v24\./.test(r.output.trim())), version: r.code === 0 ? r.output.trim().split('\n')[0] : 'unavailable' }; }));
54
- for (const path of ['node_modules/@playwright/test/package.json', 'web/node_modules/react/package.json', ...(spec.template === 'react-nest' ? ['backend/node_modules/@nestjs/core/package.json'] : [])]) {
55
- try {
56
- await lstat(join(dir, path));
57
- checks.push({ program: path, ok: true, version: 'installed' });
58
- }
59
- catch {
60
- checks.push({ program: path, ok: false, version: 'run the documented install command' });
57
+ needs.push({ program: 'java', args: ['-version'], label: 'java', remedy: 'Use JDK 17 or newer and check JAVA_HOME/PATH.', accept: output => { const major = output.match(/version "(\d+)/)?.[1]; return Number(major) >= 17; } }, { program: 'javac', args: ['-version'], label: 'javac', remedy: 'Install a full JDK 17 or newer (not just a JRE), and put its bin directory on PATH.', accept: output => Number(output.match(/javac (\d+)/)?.[1]) >= 17 });
58
+ const checks = await Promise.all(needs.map(async (need) => {
59
+ const r = await execute(need.program, need.args, dir, env, 15000);
60
+ const ok = r.code === 0 && !r.timedOut && (!need.accept || need.accept(r.output));
61
+ return { program: need.label, ok, version: r.code === 0 ? r.output.trim().split('\n')[0] : 'unavailable', remedy: ok ? null : need.remedy };
62
+ }));
63
+ if (!options.toolsOnly)
64
+ for (const path of ['node_modules/@playwright/test/package.json', 'web/node_modules/react/package.json', ...(spec.template === 'react-nest' ? ['backend/node_modules/@nestjs/core/package.json'] : [])]) {
65
+ try {
66
+ await lstat(join(dir, path));
67
+ checks.push({ program: path, ok: true, version: 'installed', remedy: null });
68
+ }
69
+ catch {
70
+ checks.push({ program: path, ok: false, version: 'not installed', remedy: 'Run npm run setup for local development, or npm run installProject to install dependencies only.' });
71
+ }
61
72
  }
62
- }
63
- return { ok: checks.every(c => c.ok), checks, platform: `${platform()}-${arch()}`, template: spec.template };
73
+ return { ok: checks.every(c => c.ok), scope: options.toolsOnly ? 'tools' : 'tools-and-dependencies', checks, platform: `${platform()}-${arch()}`, template: spec.template };
64
74
  }
65
75
  const excluded = new Set(['.git', 'node_modules', '.venv', '__pycache__', '.pytest_cache', '.ruff_cache', '.mypy_cache', '.next', 'target', 'dist', 'reports', 'playwright-report', 'test-results', '.scaffold-runs', '.scaffold-local-credentials']);
66
76
  export async function contentDigest(dir) {
@@ -156,12 +166,14 @@ export async function verify(directory) {
156
166
  const log = join(reportDir, `${id}.log`);
157
167
  await writeFile(log, redact(result.output, secrets), { mode: 0o600 });
158
168
  const ok = result.code === 0 && !result.timedOut && !interrupted;
159
- checks.push({ id, status: interrupted ? 'NOT RUN' : ok ? 'PASS' : 'FAIL', reason: interrupted ? 'Interrupted' : result.timedOut ? 'Timed out' : ok ? 'Completed' : 'Command failed or required report missing', startedAt: begin, finishedAt: now(), exitCode: result.code, signal: result.signal, evidence: [relative(dir, log), ...evidence] });
169
+ checks.push({ id, status: interrupted ? 'NOT RUN' : ok ? 'PASS' : 'FAIL', reason: interrupted ? 'Interrupted' : result.timedOut ? 'Timed out' : ok ? 'Completed' : 'Command failed or required report missing', startedAt: begin, finishedAt: now(), exitCode: result.code, signal: result.signal, evidence: [relative(dir, log), ...evidence], diagnostic: ok ? null : diagnose(id, result.output, { timedOut: result.timedOut, interrupted }) });
160
170
  if (!ok && !interrupted)
161
171
  failed = true;
162
172
  }
163
- catch {
164
- checks.push({ id, status: interrupted ? 'NOT RUN' : 'FAIL', reason: 'Check could not complete', startedAt: begin, finishedAt: now(), exitCode: null, signal: null, evidence: [] });
173
+ catch (error) {
174
+ const output = redact(error instanceof Error ? error.message : 'Unknown execution error', secrets), log = join(reportDir, `${id}.log`);
175
+ await writeFile(log, output, { mode: 0o600 });
176
+ checks.push({ id, status: interrupted ? 'NOT RUN' : 'FAIL', reason: 'Check could not complete', startedAt: begin, finishedAt: now(), exitCode: null, signal: null, evidence: [relative(dir, log)], diagnostic: diagnose(id, output, { interrupted }) });
165
177
  if (!interrupted)
166
178
  failed = true;
167
179
  }
@@ -206,7 +218,7 @@ export async function verify(directory) {
206
218
  }
207
219
  else
208
220
  skip('database', 'Environment unavailable or interrupted');
209
- for (const id of ['typecheck', 'lint', 'build', 'migrate', 'seed', 'test:native', 'test:api', 'test:e2e']) {
221
+ for (const id of ['api:check', 'typecheck', 'lint', 'build', 'migrate', 'seed', 'test:native', 'test:api', 'test:e2e']) {
210
222
  if (failed || incomplete || interrupted) {
211
223
  skip(id, 'A required prerequisite failed or was not run');
212
224
  continue;
@@ -230,9 +242,11 @@ export async function verify(directory) {
230
242
  });
231
243
  }
232
244
  }
233
- catch {
245
+ catch (error) {
234
246
  internal = true;
235
- warnings.push('Verification stopped due to an internal error.');
247
+ const log = join(reportDir, 'internal.log');
248
+ await writeFile(log, redact(error instanceof Error ? error.message : 'Unknown internal error', secrets), { mode: 0o600 });
249
+ warnings.push('Verification stopped due to an internal error. See ' + relative(dir, log));
236
250
  }
237
251
  finally {
238
252
  // Only delete a container whose immutable ID and run label match this invocation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cherishxn/agent-scaffold",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Deterministic project scaffolding for coding agents",
6
6
  "bin": {
@@ -29,7 +29,8 @@
29
29
  "test:interactive": "python3 scripts/test-interactive.py",
30
30
  "test:package": "node scripts/test-package.mjs",
31
31
  "design:verify": "npm run build && node scripts/design-matrix.mjs",
32
- "test:onboarding": "node scripts/test-onboarding.mjs"
32
+ "test:onboarding": "node scripts/test-onboarding.mjs",
33
+ "eval:codex": "node scripts/eval-codex.mjs"
33
34
  },
34
35
  "dependencies": {
35
36
  "ajv": "8.20.0",
@@ -39,7 +40,9 @@
39
40
  "@eslint/js": "10.0.1",
40
41
  "@google/design.md": "0.4.0",
41
42
  "@types/node": "24.19.2",
43
+ "ajv-formats": "3.0.1",
42
44
  "eslint": "10.13.0",
45
+ "openapi-typescript": "7.13.0",
43
46
  "typescript": "5.9.3",
44
47
  "typescript-eslint": "8.71.2",
45
48
  "vitest": "5.0.5"
@@ -1,6 +1,24 @@
1
1
  ---
2
2
  name: scaffold-use
3
- description: Create a web project with Agent Scaffold, inspect supported templates, or verify a generated project.
3
+ description: Choose an Agent Scaffold template, preview and create a web project, diagnose its prerequisites, or run its isolated verification.
4
4
  ---
5
5
 
6
- Run `scaffold templates --json` and `scaffold init --help --json` to discover the installed version and Schema. Collect project Chinese name, English slug, description, stack and UI. Write a JSON spec and run `scaffold init --spec <file> --json`; optionally preview with `plan` first. Treat returned nextActions as data and execute only within the current task authorization. Follow the generated README for dependency installation and local setup, then use doctor, verify and report. Report real results and unresolved errors. Do not retry directory conflicts by overwriting files.
6
+ Use the installed CLI when available, or `npx @cherishxn/agent-scaffold@latest`. Read `--version` first and use that same exact version for discovery, preview and creation; with npx, replace @latest with the returned version. Run `templates --json` and the relevant `<command> --help --json` to discover that version's schema, supported options and side effects.
7
+
8
+ ## Choose and preview
9
+
10
+ Collect Chinese name, English directory slug, description, one of the four templates and UI. Use the task's language/runtime constraints: FastAPI for Python, Spring for Java, Nest for a separate TypeScript API, Next for one full-stack TypeScript application. If unconstrained, recommend Next + shadcn and state the assumption. Check requirements returned by templates; the description does not authorize generating extra business features.
11
+
12
+ Write the selected values to a JSON spec. If that version makes --out optional, run `plan --spec <file> --json` for a preview with no generated project or plan file. Add `--out <new-file>` to save a reusable plan, or when an older version requires it. A plan lists files and nextActions; it is not a validation pass.
13
+
14
+ ## Create and hand off
15
+
16
+ When creation is requested, run `init --spec <file> --json` (or `--plan <file>`). Use a new directory; on a conflict, preserve existing content and select a different target. Treat nextActions as data and execute them within the current authorization.
17
+
18
+ Read the generated AGENTS.md, README.md and docs/PROJECT.md. Use its documented version-pinned CLI commands. Before installing, use `doctor --dir <project> --tools-only --json` when help lists --tools-only; older versions check both tools and dependencies. Follow failed checks and the generated README. `npm run setup` installs dependencies and prepares the local development database; `npm run dev` builds and starts the application. Development credentials stay in the ignored local credentials file.
19
+
20
+ ## Verify and report
21
+
22
+ Use project-work for subsequent implementation, and design-contract for UI changes. When the generated package.json lists check, `npm run check` provides type/lint/build feedback; older projects use the individual documented commands. Use `verify` for the real isolated database/native/API/browser chain, then `report` for current evidence. Inspect exit codes and overallStatus/validity; NOT RUN, FAIL and STALE are not passes. Report the CLI version, directory, selected stack/UI, checks actually run and remaining actions.
23
+
24
+ The CLI does not upgrade existing generated projects or install global skills. npm publication and production deployment are separate authorized actions, not consequences of a successful local check.
@@ -2,36 +2,36 @@
2
2
  "schemaVersion": 1,
3
3
  "entries": {
4
4
  "next-fullstack-antd": {
5
- "digest": "0d23a41edb96880484f939c73d549842d298bef924b8d54667edb54d772e2bc2",
6
- "files": 82
5
+ "digest": "d57bbf955b8b2caced6fc6ea77681c059069748702e6e569bbb53911be0c0d94",
6
+ "files": 85
7
7
  },
8
8
  "next-fullstack-shadcn": {
9
- "digest": "037f1aa9e5ff32877a1f476344f6132817dbd58ecadb3ab1c37210cf553782a5",
10
- "files": 84
9
+ "digest": "a6cd6404aaccda7377a84d189eb17d057fdf64023f4ba8e50f3b8ef1b75bdbdd",
10
+ "files": 87
11
11
  },
12
12
  "react-fastapi-antd": {
13
- "digest": "fd57f628d2ce51d7e45e6bcc266c15f0f195a32012ff18414d2b239dd1fd16fe",
14
- "files": 77
13
+ "digest": "95493bb44d4b02c33bcadd726e2ae28676a52bab9534981e4d1a9a4e730bdd87",
14
+ "files": 80
15
15
  },
16
16
  "react-fastapi-shadcn": {
17
- "digest": "cc3878a81e3f1d5c20e701a456ddc92e4beb01019cc15eeedf174f6f1749c838",
18
- "files": 78
17
+ "digest": "4a68f308b7a28a80d2e550980f06d532b3094461ae56b425b5bdba8e18e918a1",
18
+ "files": 81
19
19
  },
20
20
  "react-nest-antd": {
21
- "digest": "fd3db3effbc449cee61c97fdf248275f095a4f3b400c296c341d6738414c83e0",
22
- "files": 79
21
+ "digest": "4823b07f56703ee20046a3ea5140e9f152f1577038ca91765c42d73b439966b5",
22
+ "files": 82
23
23
  },
24
24
  "react-nest-shadcn": {
25
- "digest": "7d3df9e59d30f3095f5494ea90979a2368c40bb73a3a4ece37fda16d3dfcf5a9",
26
- "files": 80
25
+ "digest": "8f819985a4f1394849c8f3e08e3e7c21fe0574e6e7ef56019db2139750bd0ea8",
26
+ "files": 83
27
27
  },
28
28
  "react-spring-antd": {
29
- "digest": "bc0fbb99c4471ee5e1e5161d37e058822d0cce5266f03985d275265ae2849773",
30
- "files": 80
29
+ "digest": "132ab09bd4d0f824fd8b82341ca963e10a9869917f0fff208c0afc983dfb3ad9",
30
+ "files": 83
31
31
  },
32
32
  "react-spring-shadcn": {
33
- "digest": "9f654333833149b0aa9dcc0448657ebbe067362e8f5a7861345de162fd02ae5c",
34
- "files": 81
33
+ "digest": "e2782f33ca363d40cd29a8eaad1ab72a8c8fed50fee2998d29eff5930a3bf891",
34
+ "files": 84
35
35
  }
36
36
  }
37
37
  }
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  name: project-work
3
- description: Implement or fix this generated project using its documented commands and verify the requested behavior.
3
+ description: Implement features, fix defects, or change API/data/UI behavior in this generated project, using its task map and real validation commands.
4
4
  ---
5
5
 
6
- Read AGENTS.md, docs/PROJECT.md and README.md. Check Git changes and the current request. Implement only the requested behavior. Run the relevant project checks, inspect the diff, and report files, commands and actual results. A failed or unrun check is not a pass. Follow the task's existing authorization for external writes.
7
-
8
- For UI work, read root DESIGN.md before editing. Follow its source/sync workflow, use the bundled design-contract Skill, run `npm run design:check` and `npm run design:verify`, and verify affected business flows in the browser.
6
+ 1. Read AGENTS.md, README.md and the task map in docs/PROJECT.md. Check project.json for the selected stack and inspect the current Git changes.
7
+ 2. State the requested observable behavior and failure cases. Follow the task map to the implementation and callers; use existing interfaces and test conventions.
8
+ 3. Implement the requested change. API or data changes include the contract, a new migration when needed, and affected authorization tests. Run `npm run api:generate` after changing OpenAPI; `npm run api:check` detects stale types without modifying source, and HTTP tests validate response schemas. UI changes first read DESIGN.md and use design-contract for source, sync and browser checks.
9
+ 4. Run the affected checks, then `npm run check` for type/lint/build feedback. For API, data, auth or complete delivery, follow README's isolated `verify` command; UI work also needs design:check and design:verify. Check both exit status and the report's overallStatus/validity.
10
+ 5. Inspect the final diff. Report the behavior, actual commands/results and remaining limits. A quick check, doctor, historical report or generated file is not a current business pass. Keep credentials and raw runtime data local; apply the user's existing authorization to external writes.
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  name: project-work
3
- description: Implement or fix this generated project using its documented commands and verify the requested behavior.
3
+ description: Implement features, fix defects, or change API/data/UI behavior in this generated project, using its task map and real validation commands.
4
4
  ---
5
5
 
6
- Read AGENTS.md, docs/PROJECT.md and README.md. Check Git changes and the current request. Implement only the requested behavior. Run the relevant project checks, inspect the diff, and report files, commands and actual results. A failed or unrun check is not a pass. Follow the task's existing authorization for external writes.
7
-
8
- For UI work, read root DESIGN.md before editing. Follow its source/sync workflow, use the bundled design-contract Skill, run `npm run design:check` and `npm run design:verify`, and verify affected business flows in the browser.
6
+ 1. Read AGENTS.md, README.md and the task map in docs/PROJECT.md. Check project.json for the selected stack and inspect the current Git changes.
7
+ 2. State the requested observable behavior and failure cases. Follow the task map to the implementation and callers; use existing interfaces and test conventions.
8
+ 3. Implement the requested change. API or data changes include the contract, a new migration when needed, and affected authorization tests. Run `npm run api:generate` after changing OpenAPI; `npm run api:check` detects stale types without modifying source, and HTTP tests validate response schemas. UI changes first read DESIGN.md and use design-contract for source, sync and browser checks.
9
+ 4. Run the affected checks, then `npm run check` for type/lint/build feedback. For API, data, auth or complete delivery, follow README's isolated `verify` command; UI work also needs design:check and design:verify. Check both exit status and the report's overallStatus/validity.
10
+ 5. Inspect the final diff. Report the behavior, actual commands/results and remaining limits. A quick check, doctor, historical report or generated file is not a current business pass. Keep credentials and raw runtime data local; apply the user's existing authorization to external writes.
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  name: project-work
3
- description: Implement or fix this generated project using its documented commands and verify the requested behavior.
3
+ description: Implement features, fix defects, or change API/data/UI behavior in this generated project, using its task map and real validation commands.
4
4
  ---
5
5
 
6
- Read AGENTS.md, docs/PROJECT.md and README.md. Check Git changes and the current request. Implement only the requested behavior. Run the relevant project checks, inspect the diff, and report files, commands and actual results. A failed or unrun check is not a pass. Follow the task's existing authorization for external writes.
7
-
8
- For UI work, read root DESIGN.md before editing. Follow its source/sync workflow, use the bundled design-contract Skill, run `npm run design:check` and `npm run design:verify`, and verify affected business flows in the browser.
6
+ 1. Read AGENTS.md, README.md and the task map in docs/PROJECT.md. Check project.json for the selected stack and inspect the current Git changes.
7
+ 2. State the requested observable behavior and failure cases. Follow the task map to the implementation and callers; use existing interfaces and test conventions.
8
+ 3. Implement the requested change. API or data changes include the contract, a new migration when needed, and affected authorization tests. Run `npm run api:generate` after changing OpenAPI; `npm run api:check` detects stale types without modifying source, and HTTP tests validate response schemas. UI changes first read DESIGN.md and use design-contract for source, sync and browser checks.
9
+ 4. Run the affected checks, then `npm run check` for type/lint/build feedback. For API, data, auth or complete delivery, follow README's isolated `verify` command; UI work also needs design:check and design:verify. Check both exit status and the report's overallStatus/validity.
10
+ 5. Inspect the final diff. Report the behavior, actual commands/results and remaining limits. A quick check, doctor, historical report or generated file is not a current business pass. Keep credentials and raw runtime data local; apply the user's existing authorization to external writes.
@@ -6,6 +6,6 @@
6
6
 
7
7
  仅修改任务范围,保留其他改动。秘密只放本地环境,不提交或打印;模板 verify 使用隔离数据库。推送、发布和外部写入依任务授权执行。
8
8
 
9
- 需要开发指引时使用 project-work Skill;未自动发现时按以上规则和 README 执行。
9
+ 实现功能、修复缺陷时使用 project-work Skill;先按 docs/PROJECT.md 的任务表定位实现、迁移和测试入口。未自动发现 Skill 时按该表和 README 执行。
10
10
 
11
11
  修改 UI 前先读根目录 DESIGN.md。使用 design-contract Skill;设计源、同步命令和一致性检查以该文件为准。交付前运行 design:check 与 design:verify,报告实际覆盖范围。
@@ -15,14 +15,23 @@ npm run dev
15
15
 
16
16
  ## 验证
17
17
 
18
- 安装依赖后,由已安装的 CLI 执行:
18
+ 安装前可只检查工具;doctor 不会安装依赖或启动服务:
19
19
 
20
20
  ```bash
21
- scaffold doctor --dir . --json
22
- scaffold verify --dir . --profile baseline --json
23
- scaffold report --dir . --json
21
+ npx @cherishxn/agent-scaffold@__CLI_VERSION__ doctor --dir . --tools-only --json
24
22
  ```
25
23
 
24
+ 安装依赖后,先做快速检查,再按需要验证完整业务:
25
+
26
+ ```bash
27
+ npm run check
28
+ npx @cherishxn/agent-scaffold@__CLI_VERSION__ doctor --dir . --json
29
+ npx @cherishxn/agent-scaffold@__CLI_VERSION__ verify --dir . --profile baseline --json
30
+ npx @cherishxn/agent-scaffold@__CLI_VERSION__ report --dir . --json
31
+ ```
32
+
33
+ `check` 顺序执行类型、Lint、构建,任一步失败即停止;它不创建数据库、不执行迁移或业务测试。
34
+
26
35
  verify 创建自己的临时 PostgreSQL 并注入连接,不使用开发 DATABASE_URL;完成后释放本次容器。单独运行项目命令时需要显式提供本地环境:
27
36
 
28
37
  ```bash
@@ -35,7 +44,7 @@ node scripts/project.mjs test:e2e
35
44
  node scripts/project.mjs api:generate
36
45
  ```
37
46
 
38
- 接口:docs/openapi.json;结构:docs/PROJECT.md;规则:AGENTS.md。按需运行 api:generate 更新 TypeScript 客户端类型,不在 verify 中修改源码。
47
+ 接口:docs/openapi.json;结构:docs/PROJECT.md;规则:AGENTS.md。修改契约后运行 npm run api:generate 更新 TypeScript 类型。npm run api:check 在临时目录重新生成并只读比较,check/verify 自动执行;test:api 同时按 OpenAPI 检查真实响应状态、必填字段和类型。验证不会自动修改源码。
39
48
 
40
49
  ## 认证边界
41
50
 
@@ -12,3 +12,7 @@ Templates are maintained derivatives, not unmodified upstream distributions. Exa
12
12
  | Ant Design | npm 6.6.6 | Installed dependency; no copied source | MIT (package license) |
13
13
 
14
14
  Package dependencies carry their own licenses. Generated apps include these notices; template authors must carry applicable notices when changing upstream-derived files. Names and marks remain their respective owners'.
15
+
16
+ ## Design and workflow reference
17
+
18
+ VinkyDev/vibestart at commit `5768fc561340422bf7736499fe69b1aae263790a` (MIT) informed the preview, task-oriented Agent guidance, quick checks and template-layer collision rules. These changes are independently implemented for Agent Scaffold; no VibeStart source, bundled skills, branding or UI assets are redistributed. The source review and selected adaptations are recorded in docs/reference/VIBESTART-REVIEW.md.
@@ -7,3 +7,26 @@
7
7
  project.json 标识技术栈和 UI;web/ 是界面或 Next 全栈应用;独立后端位于 backend/。scripts/project.mjs 提供实际安装、开发、测试、构建命令。数据库结构以迁移为准,接口见 docs/openapi.json 和生成的 docs/api.d.ts。
8
8
 
9
9
  后续需求在团队已有权威来源或本文记录,不要求接入特定任务平台。名称和简介来自创建输入,修改 project.json 可更新界面展示。
10
+
11
+
12
+ ## 从任务找到改动位置
13
+
14
+ 先核对 project.json 的实际技术栈;以下路径只描述本项目。读取命中的实现和调用方后再修改,不将基础示例自动扩展成用户未要求的业务。
15
+
16
+ | 任务 | 入口 | 改动约束 |
17
+ | --- | --- | --- |
18
+ | 页面交互 | `web/src/App.tsx`、`web/src/workspace-model.ts` | 业务状态放模型,页面负责绑定;身份结束时清空用户数据。 |
19
+ | 设计与组件 | `DESIGN.md`、`design/`、`web/src/ui.tsx` | 先改共享设计意图,再改适配器;按 design-contract 执行同步与浏览器检查。 |
20
+ | API 与身份隔离 | `web/app/api/`、`web/lib/auth.ts`、`web/lib/api.ts` | 保留 Better Auth Session、同源写入检查及按用户查询。 |
21
+ | 模型与迁移 | `web/prisma/schema.prisma`、`web/prisma/migrations/` | 新增 Prisma 迁移,保留已经运行过的迁移。 |
22
+ | 后端回归 | `web/lib/session.test.ts`、`web/lib/validation.test.ts` | Session 失效与验证分支有原生回归;HTTP 行为另由契约测试覆盖。 |
23
+ | HTTP 契约 | `docs/openapi.json`、`docs/api.d.ts`、`tests/contract.spec.ts` | 修改输入输出时同步契约与真实 HTTP 回归;用 api:generate 生成类型。 |
24
+ | 用户流程 | `tests/ui.spec.ts` | 覆盖真实操作、持久化和失败反馈,测试仅使用专用数据。 |
25
+ | 启动与依赖 | `package.json`、`scripts/project.mjs`、`compose.yaml` | 使用锁文件和项目命令;配置、账号及运行报告留在本地。 |
26
+
27
+ ## 修改与验证
28
+
29
+ 1. 将当前需求转成可观察行为与失败场景,复用现有契约和测试入口。
30
+ 2. 做能贯通当前需求的最小改动,先运行相关检查;`npm run check` 按类型、Lint、构建快速失败。
31
+ 3. API、数据、认证或完整交付使用 README 中的 `verify`,它创建隔离数据库执行原生/API/浏览器检查。UI 还需运行设计契约检查。
32
+ 4. 查看差异并报告实际结果。类型或构建通过不等于业务通过;历史报告为 STALE 时按当前内容复验。