sillyspec 3.20.1 → 3.20.3

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 (209) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +1 -5
  2. package/.claude/skills/sillyspec-auto/SKILL.md +2 -8
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +1 -28
  4. package/.claude/skills/sillyspec-commit/SKILL.md +3 -4
  5. package/.claude/skills/sillyspec-continue/SKILL.md +4 -5
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +3 -12
  7. package/.claude/skills/sillyspec-execute/SKILL.md +2 -15
  8. package/.claude/skills/sillyspec-explore/SKILL.md +1 -14
  9. package/.claude/skills/sillyspec-plan/SKILL.md +36 -5
  10. package/.claude/skills/sillyspec-propose/SKILL.md +0 -4
  11. package/.claude/skills/sillyspec-quick/SKILL.md +1 -5
  12. package/.claude/skills/sillyspec-resume/SKILL.md +66 -23
  13. package/.claude/skills/sillyspec-scan/SKILL.md +1 -5
  14. package/.claude/skills/sillyspec-state/SKILL.md +8 -8
  15. package/.claude/skills/sillyspec-status/SKILL.md +1 -5
  16. package/.claude/skills/sillyspec-verify/SKILL.md +1 -5
  17. package/.claude/skills/sillyspec-workspace/SKILL.md +3 -11
  18. package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
  19. package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
  20. package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
  21. package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
  22. package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
  23. package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
  24. package/.sillyspec/changes/auto-mode/design.md +50 -0
  25. package/.sillyspec/changes/auto-mode/proposal.md +19 -0
  26. package/.sillyspec/changes/auto-mode/requirements.md +21 -0
  27. package/.sillyspec/changes/auto-mode/tasks.md +7 -0
  28. package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +206 -0
  29. package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
  30. package/.sillyspec/changes/dashboard/design.md +219 -0
  31. package/.sillyspec/changes/dashboard/design.md.braindraft +206 -0
  32. package/.sillyspec/changes/run-command-design/design.md +1230 -0
  33. package/.sillyspec/changes/unified-docs-design/design.md +199 -0
  34. package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
  35. package/.sillyspec/knowledge/INDEX.md +8 -0
  36. package/.sillyspec/knowledge/uncategorized.md +3 -0
  37. package/.sillyspec/plans/2026-04-05-dashboard.md +737 -0
  38. package/.sillyspec/projects/sillyspec.yaml +3 -0
  39. package/README.md +11 -13
  40. package/SKILL.md +40 -44
  41. package/dist/steps/brainstorm/01-load-context.md +30 -0
  42. package/dist/steps/brainstorm/02-reuse-check.md +6 -0
  43. package/dist/steps/brainstorm/03-prototype-analysis.md +11 -0
  44. package/dist/steps/brainstorm/04-module-split.md +23 -0
  45. package/dist/steps/brainstorm/05-dialog-explore.md +8 -0
  46. package/dist/steps/brainstorm/06-propose-approaches.md +3 -0
  47. package/dist/steps/brainstorm/07-present-design.md +3 -0
  48. package/dist/steps/brainstorm/08-write-design.md +21 -0
  49. package/dist/steps/brainstorm/09-self-review.md +15 -0
  50. package/dist/steps/brainstorm/10-user-confirm.md +3 -0
  51. package/dist/steps/brainstorm/11-output-spec.md +7 -0
  52. package/dist/steps/brainstorm/manifest.yaml +26 -0
  53. package/dist/steps/execute/01-load-context.md +41 -0
  54. package/dist/steps/execute/02-scan-conventions.md +47 -0
  55. package/dist/steps/execute/03-skill-mcp.md +19 -0
  56. package/dist/steps/execute/04-assign-task.md +22 -0
  57. package/dist/steps/execute/04b-prompt-template.md +54 -0
  58. package/dist/steps/execute/05-write-test.md +7 -0
  59. package/dist/steps/execute/06-write-code.md +8 -0
  60. package/dist/steps/execute/07-run-test.md +26 -0
  61. package/dist/steps/execute/08-fix-issues.md +28 -0
  62. package/dist/steps/execute/09-next-task.md +33 -0
  63. package/dist/steps/execute/manifest.yaml +28 -0
  64. package/dist/steps/plan/01-load-context.md +22 -0
  65. package/dist/steps/plan/02-anchor-confirm.md +1 -0
  66. package/dist/steps/plan/03-expand-tasks.md +33 -0
  67. package/dist/steps/plan/04-mark-order.md +15 -0
  68. package/dist/steps/plan/05-e2e-planning.md +17 -0
  69. package/dist/steps/plan/06-self-check.md +16 -0
  70. package/dist/steps/plan/07-save.md +1 -0
  71. package/dist/steps/plan/manifest.yaml +18 -0
  72. package/dist/steps/scan/01-env-detect.md +51 -0
  73. package/dist/steps/scan/02-tech-stack.md +16 -0
  74. package/dist/steps/scan/03-conventions.md +16 -0
  75. package/dist/steps/scan/04-structure.md +19 -0
  76. package/dist/steps/scan/05-quality.md +18 -0
  77. package/dist/steps/scan/06-complete.md +49 -0
  78. package/dist/steps/scan/manifest.yaml +16 -0
  79. package/dist/steps/verify/01-load-specs.md +28 -0
  80. package/dist/steps/verify/02-check-tasks.md +1 -0
  81. package/dist/steps/verify/03-check-design.md +6 -0
  82. package/dist/steps/verify/04-run-tests.md +7 -0
  83. package/dist/steps/verify/05-e2e-tests.md +27 -0
  84. package/dist/steps/verify/05b-e2e-fix.md +33 -0
  85. package/dist/steps/verify/06-code-quality.md +25 -0
  86. package/dist/steps/verify/07-lint-check.md +27 -0
  87. package/dist/steps/verify/08-output-report.md +14 -0
  88. package/dist/steps/verify/manifest.yaml +22 -0
  89. package/package.json +2 -8
  90. package/packages/dashboard/dist/assets/{index-Bq_Z2hne.js → index-D1EVTLmc.js} +1264 -1264
  91. package/packages/dashboard/dist/assets/index-DGe8CqeP.css +1 -0
  92. package/packages/dashboard/dist/index.html +2 -2
  93. package/packages/dashboard/package-lock.json +6 -6
  94. package/packages/dashboard/server/executor.js +1 -1
  95. package/packages/dashboard/server/index.js +18 -98
  96. package/packages/dashboard/server/parser.js +71 -139
  97. package/packages/dashboard/server/watcher.js +6 -14
  98. package/packages/dashboard/src/App.vue +185 -418
  99. package/packages/dashboard/src/components/ActionBar.vue +1 -10
  100. package/packages/dashboard/src/components/CommandPalette.vue +1 -5
  101. package/packages/dashboard/src/components/DocPreview.vue +8 -105
  102. package/packages/dashboard/src/components/DocTree.vue +19 -75
  103. package/packages/dashboard/src/components/PipelineStage.vue +2 -22
  104. package/packages/dashboard/src/components/PipelineView.vue +5 -32
  105. package/packages/dashboard/src/components/ProjectOverview.vue +139 -113
  106. package/packages/dashboard/src/components/StageBadge.vue +3 -17
  107. package/packages/dashboard/src/components/StepCard.vue +2 -7
  108. package/packages/dashboard/src/composables/useDashboard.js +0 -28
  109. package/src/derive.js +147 -0
  110. package/src/index.js +40 -685
  111. package/src/init.js +63 -119
  112. package/src/migrate.js +7 -7
  113. package/src/progress.js +248 -1474
  114. package/src/run.js +302 -2920
  115. package/src/setup.js +64 -2
  116. package/src/stages/archive.js +17 -123
  117. package/src/stages/brainstorm.js +48 -454
  118. package/src/stages/doctor.js +46 -99
  119. package/src/stages/execute.js +59 -420
  120. package/src/stages/index.js +18 -12
  121. package/src/stages/plan.js +189 -492
  122. package/src/stages/propose.js +11 -70
  123. package/src/stages/quick.js +13 -52
  124. package/src/stages/scan.js +68 -468
  125. package/src/stages/status.js +1 -1
  126. package/src/stages/verify.js +16 -203
  127. package/src/step.js +543 -0
  128. package/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  129. package/.husky/pre-push +0 -13
  130. package/.npmrc-tmp +0 -1
  131. package/CLAUDE.md +0 -18
  132. package/docs/brainstorm-plan-contract.md +0 -64
  133. package/docs/plan-execute-contract.md +0 -123
  134. package/docs/platform-scan-protocol.md +0 -298
  135. package/docs/revision-mode.md +0 -115
  136. package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +0 -99
  137. package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +0 -218
  138. package/docs/sillyspec/file-lifecycle/stage-artifacts.md +0 -167
  139. package/docs/sillyspec/file-lifecycle/storage-and-state.md +0 -148
  140. package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +0 -193
  141. package/docs/sillyspec/file-lifecycle.md +0 -125
  142. package/docs/workflow-contract-regression.md +0 -106
  143. package/docs/worktree-isolation.md +0 -252
  144. package/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  145. package/packages/dashboard/dist/prototype-dashboard.html +0 -836
  146. package/packages/dashboard/dist/prototype-overview.html +0 -256
  147. package/packages/dashboard/public/prototype-dashboard.html +0 -836
  148. package/packages/dashboard/public/prototype-overview.html +0 -256
  149. package/packages/dashboard/src/components/HResizeHandle.vue +0 -48
  150. package/packages/dashboard/src/components/ProjectCard.vue +0 -187
  151. package/packages/dashboard/src/components/VResizeHandle.vue +0 -61
  152. package/packages/dashboard/src/composables/useLayout.js +0 -131
  153. package/src/brainstorm-postcheck.js +0 -158
  154. package/src/change-list.js +0 -52
  155. package/src/change-risk-profile.js +0 -352
  156. package/src/classify-change.js +0 -73
  157. package/src/constants.js +0 -70
  158. package/src/contract-matrix.js +0 -278
  159. package/src/db.js +0 -201
  160. package/src/endpoint-extractor.js +0 -315
  161. package/src/hooks/claude-pre-tool-use.cjs +0 -125
  162. package/src/hooks/worktree-guard.js +0 -761
  163. package/src/knowledge-match.js +0 -130
  164. package/src/modules.js +0 -482
  165. package/src/scan-postcheck.js +0 -380
  166. package/src/stage-contract.js +0 -700
  167. package/src/stages/brainstorm-auto.js +0 -229
  168. package/src/stages/explore.js +0 -34
  169. package/src/stages/knowledge.js +0 -498
  170. package/src/stages/plan-postcheck.js +0 -513
  171. package/src/sync.js +0 -497
  172. package/src/task-review.js +0 -346
  173. package/src/workflow.js +0 -785
  174. package/src/worktree-apply.js +0 -549
  175. package/src/worktree.js +0 -932
  176. package/templates/workflows/archive-impact.yaml +0 -79
  177. package/templates/workflows/scan-docs.yaml +0 -132
  178. package/test/brainstorm-plan-contract.test.mjs +0 -273
  179. package/test/check-syntax.mjs +0 -26
  180. package/test/cli-top-level-aliases.test.mjs +0 -174
  181. package/test/contract-artifacts.test.mjs +0 -323
  182. package/test/decision-supersede.test.mjs +0 -277
  183. package/test/knowledge-match.test.mjs +0 -231
  184. package/test/plan-execute-contract.test.mjs +0 -330
  185. package/test/plan-optimization.test.mjs +0 -572
  186. package/test/platform-artifacts.test.mjs +0 -190
  187. package/test/platform-failure-samples.test.mjs +0 -199
  188. package/test/platform-recovery-chain.test.mjs +0 -179
  189. package/test/platform-recovery.test.mjs +0 -167
  190. package/test/platform-scan-p0.test.mjs +0 -175
  191. package/test/revision-v1.test.mjs +0 -1145
  192. package/test/run-sanitize-project-name.test.mjs +0 -51
  193. package/test/run-scan-postcheck-fail.test.mjs +0 -64
  194. package/test/run-scan-project-parse.test.mjs +0 -77
  195. package/test/run-tests.mjs +0 -48
  196. package/test/scan-docs-yaml-placeholders.test.mjs +0 -84
  197. package/test/scan-knowledge.test.mjs +0 -175
  198. package/test/scan-paths.test.mjs +0 -68
  199. package/test/scan-postcheck-project-priority.test.mjs +0 -85
  200. package/test/scan-postcheck.test.mjs +0 -183
  201. package/test/scan-workflow-anyfailed-block.test.mjs +0 -52
  202. package/test/spec-dir.test.mjs +0 -206
  203. package/test/stage-contract-failed-post-check.test.mjs +0 -102
  204. package/test/stage-contract.test.mjs +0 -299
  205. package/test/stage-definitions.test.mjs +0 -39
  206. package/test/wait-gates.test.mjs +0 -501
  207. package/test/workflow-spec-base.test.mjs +0 -142
  208. package/test/worktree-guard.test.mjs +0 -136
  209. package/test/worktree-native-overlay.test.mjs +0 -188
package/src/init.js CHANGED
@@ -1,6 +1,7 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync } from 'fs';
2
2
  import { join, resolve, dirname, basename } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { homedir } from 'os';
4
5
  import { checkbox, confirm, input } from '@inquirer/prompts';
5
6
  import { ProgressManager } from './progress.js';
6
7
  import chalk from 'chalk';
@@ -27,10 +28,11 @@ function copyDirSync(src, dst) {
27
28
 
28
29
 
29
30
 
30
- const VALID_TOOLS = ['claude', 'cursor', 'openclaw', 'codex', 'gemini', 'opencode'];
31
+ const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'openclaw', 'codex', 'gemini', 'opencode'];
31
32
 
32
33
  const TOOL_LABELS = {
33
34
  claude: 'Claude Code',
35
+ claude_skills: 'Claude Skills',
34
36
  cursor: 'Cursor',
35
37
  openclaw: 'OpenClaw',
36
38
  codex: 'OpenAI Codex (通过 AGENTS.md)',
@@ -56,7 +58,7 @@ const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
56
58
  - 遵循 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\` 中的代码风格
57
59
 
58
60
  ### 工作流程
59
- - 读取 sillyspec.db 确认当前阶段(使用 \`sillyspec progress show\`)
61
+ - 读取 \`.sillyspec/.runtime/progress.json\` 确认当前阶段(使用 \`sillyspec progress show\`)
60
62
  - 各阶段产出文件位于 \`.sillyspec/changes/<变更名>/\` 下
61
63
  `;
62
64
 
@@ -86,6 +88,7 @@ function injectInstructions(tool, projectDir) {
86
88
  function detectTools(projectDir) {
87
89
  const found = [];
88
90
  if (existsSync(join(projectDir, '.claude'))) found.push('claude');
91
+ if (existsSync(join(projectDir, '.claude', 'skills'))) found.push('claude_skills');
89
92
  if (existsSync(join(projectDir, '.cursor'))) found.push('cursor');
90
93
  if (existsSync(join(projectDir, '.openclaw'))) found.push('openclaw');
91
94
  if (existsSync(join(projectDir, 'AGENTS.md'))) found.push('codex');
@@ -103,90 +106,34 @@ function isTTY() {
103
106
 
104
107
  // ── 核心安装逻辑 ──
105
108
 
106
- async function doInstall(projectDir, tools, subprojects = [], specDir = null) {
107
- // specDir: 规范目录(默认 projectDir/.sillyspec)
108
- // projectDir: 源码项目根目录(用于工具检测、指令注入、.gitignore)
109
- const spec = specDir || join(projectDir, '.sillyspec');
110
-
111
- // 外部 specDir 时清理旧版本残留的 cwd/.sillyspec/(防止源码污染)。
112
- // ⚠️ 必须保护真实资产:若本地 .sillyspec 含 changes/(非空)、projects/(非空)
113
- // 或 sillyspec.db(进度库),说明该项目本身就用 SillySpec 管理,整体删除会丢资产。
114
- // 此时只清运行时残留,拒绝整删;确无资产时才视为旧残留清理。
115
- const legacyDir = join(projectDir, '.sillyspec');
116
- if (specDir && existsSync(legacyDir)) {
117
- let hasChanges = false;
118
- try {
119
- const changesDir = join(legacyDir, 'changes');
120
- if (existsSync(changesDir)) hasChanges = readdirSync(changesDir).length > 0;
121
- } catch {}
122
- let hasProjects = false;
123
- try {
124
- const projectsDir = join(legacyDir, 'projects');
125
- if (existsSync(projectsDir)) hasProjects = readdirSync(projectsDir).length > 0;
126
- } catch {}
127
- const hasDb = existsSync(join(legacyDir, 'sillyspec.db'));
128
-
129
- if (hasChanges || hasProjects || hasDb) {
130
- // 真实资产存在:拒绝整体删除,仅清理运行时残留
131
- console.error('❌ [sillyspec] 拒绝删除源码目录的 .sillyspec/:检测到真实资产(changes/、projects/ 或 sillyspec.db)。');
132
- console.error(' 该项目似乎本身就用 SillySpec 管理。如需改用外部 spec 目录,请先手动迁移/备份。');
133
- console.error(' 本次仅清理运行时残留(.runtime/、local.yaml、codebase/)。');
134
- for (const residue of ['.runtime', 'local.yaml', 'codebase']) {
135
- const p = join(legacyDir, residue);
136
- if (existsSync(p)) { try { rmSync(p, { recursive: true, force: true }) } catch {} }
137
- }
138
- } else {
139
- // 无真实资产:确属旧版本残留,安全删除
140
- try { rmSync(legacyDir, { recursive: true, force: true }) } catch {}
141
- if (!existsSync(legacyDir)) console.log('🧹 已清理旧版本残留的源码 .sillyspec/ 目录');
142
- else console.error('⚠️ 清理残留 .sillyspec/ 失败');
143
- }
144
- }
145
-
109
+ async function doInstall(projectDir, tools, subprojects = []) {
146
110
  // 创建基础目录
147
- // spec/projects/ → 项目注册表
148
- // spec/docs/<name>/ → 统一文档中心
149
- // spec/knowledge/ → 跨项目共享知识库
150
- // spec/.runtime/ → progress (gitignored)
111
+ // .sillyspec/projects/ → 项目注册表
112
+ // .sillyspec/docs/<name>/ → 统一文档中心
113
+ // .sillyspec/knowledge/ → 跨项目共享知识库
114
+ // .sillyspec/.runtime/ → progress (gitignored)
151
115
 
152
116
  // 注册当前项目到 projects/
153
117
  const projectName = basename(projectDir) || 'project';
154
- const projectsDir = join(spec, 'projects');
118
+ const projectsDir = join(projectDir, '.sillyspec', 'projects');
155
119
  mkdirSync(projectsDir, { recursive: true });
156
120
  const projectYamlPath = join(projectsDir, `${projectName}.yaml`);
157
121
  if (!existsSync(projectYamlPath)) {
158
- // path 相对于 specDir,跨平台可寻址
159
- writeFileSync(projectYamlPath, `name: ${projectName}\npath: ${projectDir}\nstatus: active\n`);
122
+ writeFileSync(projectYamlPath, `name: ${projectName}\npath: .\nstatus: active\n`);
160
123
  }
161
124
 
162
125
  // 创建 docs/<projectName>/scan/ 子目录(代码扫描结果)
163
- const scanDir = join(spec, 'docs', projectName, 'scan');
126
+ const scanDir = join(projectDir, '.sillyspec', 'docs', projectName, 'scan');
164
127
  mkdirSync(scanDir, { recursive: true });
165
128
  const gitkeepPath = join(scanDir, '.gitkeep');
166
129
  if (!existsSync(gitkeepPath)) writeFileSync(gitkeepPath, '');
167
130
 
168
- // 复制 workflow 模板到 workflows/
169
- const workflowsDir = join(spec, 'workflows');
170
- const templatesDir = join(__dirname, '..', 'templates', 'workflows');
171
- if (existsSync(templatesDir)) {
172
- mkdirSync(workflowsDir, { recursive: true });
173
- for (const file of readdirSync(templatesDir)) {
174
- if (file.endsWith('.yaml')) {
175
- const srcPath = join(templatesDir, file);
176
- const dstPath = join(workflowsDir, file);
177
- if (!existsSync(dstPath)) {
178
- writeFileSync(dstPath, readFileSync(srcPath));
179
- }
180
- }
181
- }
182
- }
183
-
184
131
  // 创建 shared/workspace 目录
185
- mkdirSync(join(spec, 'shared'), { recursive: true });
186
- mkdirSync(join(spec, 'workspace'), { recursive: true });
132
+ mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
133
+ mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
187
134
 
188
135
  // 创建知识库骨架
189
- const knowledgeDir = join(spec, 'knowledge');
136
+ const knowledgeDir = join(projectDir, '.sillyspec', 'knowledge');
190
137
  mkdirSync(knowledgeDir, { recursive: true });
191
138
  const indexPath = join(knowledgeDir, 'INDEX.md');
192
139
  if (!existsSync(indexPath)) {
@@ -197,33 +144,38 @@ async function doInstall(projectDir, tools, subprojects = [], specDir = null) {
197
144
  writeFileSync(uncatPath, `# 未分类知识\n\n> execute/quick 执行中发现的坑暂存于此,用户审阅后归类到对应文件并更新 INDEX.md。\n`);
198
145
  }
199
146
 
200
- // 创建 .runtime/ 目录结构(全局状态)
201
- const runtimeDir = join(spec, '.runtime');
147
+ // 创建 .sillyspec/.runtime/ 目录结构
148
+ const runtimeDir = join(projectDir, '.sillyspec', '.runtime');
202
149
  for (const sub of ['artifacts', 'history', 'logs', 'templates']) {
203
150
  mkdirSync(join(runtimeDir, sub), { recursive: true });
204
151
  }
205
152
 
206
- // 初始化 SQLite 数据库
207
- const pm = new ProgressManager({ specDir: spec });
208
- await pm.init(projectDir);
209
-
210
- // .gitignore 只在 specDir 在项目内时才修改
211
- const isExternalSpec = specDir && resolve(spec) !== resolve(projectDir, '.sillyspec');
212
- if (!isExternalSpec) {
213
- const gitignorePath = join(projectDir, '.gitignore');
214
- const ignoreRules = ['.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml', '.sillyspec/.runtime/'];
215
- if (existsSync(gitignorePath)) {
216
- const content = readFileSync(gitignorePath, 'utf8');
217
- let updated = content.trimEnd();
218
- for (const rule of ignoreRules) {
219
- if (!updated.includes(rule)) {
220
- updated += '\n' + rule;
221
- }
153
+ // 创建初始 progress.json
154
+ const progressPath = join(runtimeDir, 'progress.json');
155
+ if (!existsSync(progressPath)) {
156
+ const pm = new ProgressManager();
157
+ pm.init(projectDir);
158
+ }
159
+
160
+ // 创建初始 user-inputs.md
161
+ const inputsPath = join(runtimeDir, 'user-inputs.md');
162
+ if (!existsSync(inputsPath)) {
163
+ writeFileSync(inputsPath, '# 用户输入记录\n\n> 每步完成时由 AI 自动追加,记录用户所有原话。\n\n');
164
+ }
165
+
166
+ const gitignorePath = join(projectDir, '.gitignore');
167
+ const ignoreRules = ['.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml', '.sillyspec/.runtime/'];
168
+ if (existsSync(gitignorePath)) {
169
+ const content = readFileSync(gitignorePath, 'utf8');
170
+ let updated = content.trimEnd();
171
+ for (const rule of ignoreRules) {
172
+ if (!updated.includes(rule)) {
173
+ updated += '\n' + rule;
222
174
  }
223
- writeFileSync(gitignorePath, updated + '\n');
224
- } else {
225
- writeFileSync(gitignorePath, ignoreRules.join('\n') + '\n');
226
175
  }
176
+ writeFileSync(gitignorePath, updated + '\n');
177
+ } else {
178
+ writeFileSync(gitignorePath, ignoreRules.join('\n') + '\n');
227
179
  }
228
180
 
229
181
  // 注入指令文件(codex/gemini/opencode)
@@ -234,35 +186,29 @@ async function doInstall(projectDir, tools, subprojects = [], specDir = null) {
234
186
  }
235
187
  }
236
188
 
237
- // 复制 skills 到各工具目录
238
- const skillToolDirs = {
239
- claude: '.claude/skills',
240
- codex: '.codex/skills',
241
- openclaw: '.openclaw/skills',
242
- opencode: '.opencode/skills',
243
- }
244
- const skillsSource = join(__dirname, '..', '.claude', 'skills');
245
- if (existsSync(skillsSource)) {
189
+ // 复制 skills 到 .claude/skills/(给 Claude Code 使用)
190
+ const claudeSkillsDir = join(projectDir, '.claude', 'skills');
191
+ // 优先从 npm 包自带位置复制,其次从 ~/.agents/skills/
192
+ const npmSkillsDir = join(__dirname, '..', '.claude', 'skills');
193
+ const localSkillsDir = join(homedir(), '.agents', 'skills');
194
+ const skillsSource = existsSync(npmSkillsDir) ? npmSkillsDir : existsSync(localSkillsDir) ? localSkillsDir : null;
195
+ if (skillsSource) {
246
196
  const sillyspecSkills = readdirSync(skillsSource).filter(f => f.startsWith('sillyspec-') && statSync(join(skillsSource, f)).isDirectory());
247
197
  if (sillyspecSkills.length > 0) {
248
- for (const [tool, dir] of Object.entries(skillToolDirs)) {
249
- if (!tools.includes(tool)) continue
250
- const targetDir = join(projectDir, dir)
251
- mkdirSync(targetDir, { recursive: true })
252
- for (const skill of sillyspecSkills) {
253
- copyDirSync(join(skillsSource, skill), join(targetDir, skill))
254
- }
255
- console.log(chalk.green(` ✓ ${TOOL_LABELS[tool]} skills 已同步 (${sillyspecSkills.length} 个)`))
198
+ mkdirSync(claudeSkillsDir, { recursive: true });
199
+ for (const skill of sillyspecSkills) {
200
+ copyDirSync(join(skillsSource, skill), join(claudeSkillsDir, skill));
256
201
  }
202
+ console.log(chalk.green(' ✓ Claude Code skills 已同步 (' + sillyspecSkills.length + ' 个)'));
257
203
  }
258
204
  } else {
259
- console.log(chalk.yellow(' ⚠ 未找到 skills 目录(npm 包内无 .claude/skills/),跳过同步'));
205
+ console.log(chalk.yellow(' ⚠ 未找到 skills 目录,跳过 Claude Code skills 同步'));
260
206
  }
261
207
  }
262
208
 
263
209
  // ── 安装完成总结 ──
264
210
 
265
- function showSummary(version, tools, specDir) {
211
+ function showSummary(version, tools) {
266
212
  const toolLabels = tools.map(t => TOOL_LABELS[t] || t);
267
213
 
268
214
  console.log('');
@@ -271,7 +217,7 @@ function showSummary(version, tools, specDir) {
271
217
  console.log(chalk.green(' ═══════════════════════════════════════'));
272
218
  console.log('');
273
219
  console.log(` 已安装工具: ${chalk.cyan(toolLabels.join(', '))}`);
274
- console.log(` 📁 规范目录: ${chalk.cyan(specDir || '.sillyspec')}`);
220
+ console.log(' 📁 .sillyspec/ 项目规范目录');
275
221
  console.log('');
276
222
  console.log(' 下一步:使用 AI 技能开始工作');
277
223
  console.log(' OpenClaw: ' + chalk.bold('/sillyspec:brainstorm'));
@@ -295,9 +241,8 @@ export function getVersion() {
295
241
  // ── 主命令 ──
296
242
 
297
243
  export async function cmdInit(projectDir, options = {}) {
298
- const { tool, interactive, specDir } = options;
244
+ const { tool, interactive } = options;
299
245
  const version = getVersion();
300
- const resolvedSpecDir = specDir ? resolve(specDir) : null;
301
246
 
302
247
  // ── 交互式模式(--interactive 或 -i)──
303
248
  if (interactive && isTTY()) {
@@ -328,7 +273,7 @@ export async function cmdInit(projectDir, options = {}) {
328
273
  validate: (answer) => answer.length > 0 || '至少选择一个工具',
329
274
  });
330
275
 
331
- // 子项目引导(仅交互模式)
276
+ // 子项目引导(始终执行)
332
277
  let subprojects = [];
333
278
  {
334
279
  console.log('');
@@ -395,8 +340,8 @@ export async function cmdInit(projectDir, options = {}) {
395
340
  }
396
341
 
397
342
  console.log('');
398
- await doInstall(projectDir, selectedTools, subprojects, resolvedSpecDir);
399
- showSummary(version, selectedTools, resolvedSpecDir);
343
+ await doInstall(projectDir, selectedTools, subprojects);
344
+ showSummary(version, selectedTools);
400
345
  return;
401
346
  }
402
347
 
@@ -414,13 +359,12 @@ export async function cmdInit(projectDir, options = {}) {
414
359
  tools = detectTools(projectDir);
415
360
  }
416
361
 
417
- await doInstall(projectDir, tools, [], resolvedSpecDir);
362
+ await doInstall(projectDir, tools);
418
363
 
419
364
  console.log('');
420
365
  console.log(chalk.green(` ✅ SillySpec v${version} 安装完成!`));
421
366
  console.log('');
422
- const specDisplay = resolvedSpecDir || '.sillyspec';
423
- console.log(` 📁 规范目录: ${chalk.cyan(specDisplay)}`);
367
+ console.log(' 📁 .sillyspec/ 项目规范目录');
424
368
  console.log('');
425
369
  console.log(' 下一步:使用 AI 技能开始工作');
426
370
  console.log(` OpenClaw: ${chalk.bold('/sillyspec:brainstorm')}`);
package/src/migrate.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, renameSync, copyFileSync } from 'fs';
2
- import { basename, join, resolve } from 'path';
2
+ import { join, resolve } from 'path';
3
3
  import chalk from 'chalk';
4
4
 
5
5
  /**
6
- * Migrate old .sillyspec/ structure to unified .sillyspec/docs/<project>/ structure
6
+ * Migrate old .sillyspec/ structure to unified docs/<project>/ structure
7
7
  * @param {string} projectDir - Path to the project directory
8
8
  */
9
9
  export function migrateDocs(projectDir) {
@@ -14,7 +14,7 @@ export function migrateDocs(projectDir) {
14
14
  }
15
15
 
16
16
  // Determine project name from projects/*.yaml or directory name
17
- let projectName = basename(resolve(projectDir));
17
+ let projectName = projectDir.split('/').pop();
18
18
  const projectsDir = join(sillyspecDir, 'projects');
19
19
  if (existsSync(projectsDir)) {
20
20
  const yamlFiles = readdirSync(projectsDir).filter(f => f.endsWith('.yaml'));
@@ -29,7 +29,7 @@ export function migrateDocs(projectDir) {
29
29
  const docsBase = join(sillyspecDir, 'docs', projectName);
30
30
  let migrated = 0;
31
31
 
32
- // 1. codebase/ → .sillyspec/docs/<project>/scan/
32
+ // 1. codebase/ → docs/<project>/scan/
33
33
  const codebaseDir = join(sillyspecDir, 'codebase');
34
34
  if (existsSync(codebaseDir)) {
35
35
  const targetDir = join(docsBase, 'scan');
@@ -50,7 +50,7 @@ export function migrateDocs(projectDir) {
50
50
 
51
51
  // 2. specs/ is deprecated — designs live in changes/<变更名>/design.md
52
52
 
53
- // 3. changes/archive/ → .sillyspec/docs/<project>/archive/
53
+ // 3. changes/archive/ → docs/<project>/archive/
54
54
  const archiveDir = join(sillyspecDir, 'changes', 'archive');
55
55
  if (existsSync(archiveDir)) {
56
56
  const targetDir = join(docsBase, 'archive');
@@ -69,7 +69,7 @@ export function migrateDocs(projectDir) {
69
69
  }
70
70
  }
71
71
 
72
- // 4. knowledge/ → .sillyspec/docs/<project>/archive/ (append knowledge files)
72
+ // 4. knowledge/ → docs/<project>/archive/ (append knowledge files)
73
73
  const knowledgeDir = join(sillyspecDir, 'knowledge');
74
74
  if (existsSync(knowledgeDir)) {
75
75
  const targetDir = join(docsBase, 'archive');
@@ -88,7 +88,7 @@ export function migrateDocs(projectDir) {
88
88
  }
89
89
  }
90
90
 
91
- // 5. quicklog/ → .sillyspec/docs/<project>/quicklog/
91
+ // 5. quicklog/ → docs/<project>/quicklog/
92
92
  const quicklogDir = join(sillyspecDir, 'quicklog');
93
93
  if (existsSync(quicklogDir)) {
94
94
  const targetDir = join(docsBase, 'quicklog');