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.
- package/.claude/skills/sillyspec-archive/SKILL.md +1 -5
- package/.claude/skills/sillyspec-auto/SKILL.md +2 -8
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +1 -28
- package/.claude/skills/sillyspec-commit/SKILL.md +3 -4
- package/.claude/skills/sillyspec-continue/SKILL.md +4 -5
- package/.claude/skills/sillyspec-doctor/SKILL.md +3 -12
- package/.claude/skills/sillyspec-execute/SKILL.md +2 -15
- package/.claude/skills/sillyspec-explore/SKILL.md +1 -14
- package/.claude/skills/sillyspec-plan/SKILL.md +36 -5
- package/.claude/skills/sillyspec-propose/SKILL.md +0 -4
- package/.claude/skills/sillyspec-quick/SKILL.md +1 -5
- package/.claude/skills/sillyspec-resume/SKILL.md +66 -23
- package/.claude/skills/sillyspec-scan/SKILL.md +1 -5
- package/.claude/skills/sillyspec-state/SKILL.md +8 -8
- package/.claude/skills/sillyspec-status/SKILL.md +1 -5
- package/.claude/skills/sillyspec-verify/SKILL.md +1 -5
- package/.claude/skills/sillyspec-workspace/SKILL.md +3 -11
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
- package/.sillyspec/changes/auto-mode/design.md +50 -0
- package/.sillyspec/changes/auto-mode/proposal.md +19 -0
- package/.sillyspec/changes/auto-mode/requirements.md +21 -0
- package/.sillyspec/changes/auto-mode/tasks.md +7 -0
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +206 -0
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
- package/.sillyspec/changes/dashboard/design.md +219 -0
- package/.sillyspec/changes/dashboard/design.md.braindraft +206 -0
- package/.sillyspec/changes/run-command-design/design.md +1230 -0
- package/.sillyspec/changes/unified-docs-design/design.md +199 -0
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +8 -0
- package/.sillyspec/knowledge/uncategorized.md +3 -0
- package/.sillyspec/plans/2026-04-05-dashboard.md +737 -0
- package/.sillyspec/projects/sillyspec.yaml +3 -0
- package/README.md +11 -13
- package/SKILL.md +40 -44
- package/dist/steps/brainstorm/01-load-context.md +30 -0
- package/dist/steps/brainstorm/02-reuse-check.md +6 -0
- package/dist/steps/brainstorm/03-prototype-analysis.md +11 -0
- package/dist/steps/brainstorm/04-module-split.md +23 -0
- package/dist/steps/brainstorm/05-dialog-explore.md +8 -0
- package/dist/steps/brainstorm/06-propose-approaches.md +3 -0
- package/dist/steps/brainstorm/07-present-design.md +3 -0
- package/dist/steps/brainstorm/08-write-design.md +21 -0
- package/dist/steps/brainstorm/09-self-review.md +15 -0
- package/dist/steps/brainstorm/10-user-confirm.md +3 -0
- package/dist/steps/brainstorm/11-output-spec.md +7 -0
- package/dist/steps/brainstorm/manifest.yaml +26 -0
- package/dist/steps/execute/01-load-context.md +41 -0
- package/dist/steps/execute/02-scan-conventions.md +47 -0
- package/dist/steps/execute/03-skill-mcp.md +19 -0
- package/dist/steps/execute/04-assign-task.md +22 -0
- package/dist/steps/execute/04b-prompt-template.md +54 -0
- package/dist/steps/execute/05-write-test.md +7 -0
- package/dist/steps/execute/06-write-code.md +8 -0
- package/dist/steps/execute/07-run-test.md +26 -0
- package/dist/steps/execute/08-fix-issues.md +28 -0
- package/dist/steps/execute/09-next-task.md +33 -0
- package/dist/steps/execute/manifest.yaml +28 -0
- package/dist/steps/plan/01-load-context.md +22 -0
- package/dist/steps/plan/02-anchor-confirm.md +1 -0
- package/dist/steps/plan/03-expand-tasks.md +33 -0
- package/dist/steps/plan/04-mark-order.md +15 -0
- package/dist/steps/plan/05-e2e-planning.md +17 -0
- package/dist/steps/plan/06-self-check.md +16 -0
- package/dist/steps/plan/07-save.md +1 -0
- package/dist/steps/plan/manifest.yaml +18 -0
- package/dist/steps/scan/01-env-detect.md +51 -0
- package/dist/steps/scan/02-tech-stack.md +16 -0
- package/dist/steps/scan/03-conventions.md +16 -0
- package/dist/steps/scan/04-structure.md +19 -0
- package/dist/steps/scan/05-quality.md +18 -0
- package/dist/steps/scan/06-complete.md +49 -0
- package/dist/steps/scan/manifest.yaml +16 -0
- package/dist/steps/verify/01-load-specs.md +28 -0
- package/dist/steps/verify/02-check-tasks.md +1 -0
- package/dist/steps/verify/03-check-design.md +6 -0
- package/dist/steps/verify/04-run-tests.md +7 -0
- package/dist/steps/verify/05-e2e-tests.md +27 -0
- package/dist/steps/verify/05b-e2e-fix.md +33 -0
- package/dist/steps/verify/06-code-quality.md +25 -0
- package/dist/steps/verify/07-lint-check.md +27 -0
- package/dist/steps/verify/08-output-report.md +14 -0
- package/dist/steps/verify/manifest.yaml +22 -0
- package/package.json +2 -8
- package/packages/dashboard/dist/assets/{index-Bq_Z2hne.js → index-D1EVTLmc.js} +1264 -1264
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package-lock.json +6 -6
- package/packages/dashboard/server/executor.js +1 -1
- package/packages/dashboard/server/index.js +18 -98
- package/packages/dashboard/server/parser.js +71 -139
- package/packages/dashboard/server/watcher.js +6 -14
- package/packages/dashboard/src/App.vue +185 -418
- package/packages/dashboard/src/components/ActionBar.vue +1 -10
- package/packages/dashboard/src/components/CommandPalette.vue +1 -5
- package/packages/dashboard/src/components/DocPreview.vue +8 -105
- package/packages/dashboard/src/components/DocTree.vue +19 -75
- package/packages/dashboard/src/components/PipelineStage.vue +2 -22
- package/packages/dashboard/src/components/PipelineView.vue +5 -32
- package/packages/dashboard/src/components/ProjectOverview.vue +139 -113
- package/packages/dashboard/src/components/StageBadge.vue +3 -17
- package/packages/dashboard/src/components/StepCard.vue +2 -7
- package/packages/dashboard/src/composables/useDashboard.js +0 -28
- package/src/derive.js +147 -0
- package/src/index.js +40 -685
- package/src/init.js +63 -119
- package/src/migrate.js +7 -7
- package/src/progress.js +248 -1474
- package/src/run.js +302 -2920
- package/src/setup.js +64 -2
- package/src/stages/archive.js +17 -123
- package/src/stages/brainstorm.js +48 -454
- package/src/stages/doctor.js +46 -99
- package/src/stages/execute.js +59 -420
- package/src/stages/index.js +18 -12
- package/src/stages/plan.js +189 -492
- package/src/stages/propose.js +11 -70
- package/src/stages/quick.js +13 -52
- package/src/stages/scan.js +68 -468
- package/src/stages/status.js +1 -1
- package/src/stages/verify.js +16 -203
- package/src/step.js +543 -0
- package/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.husky/pre-push +0 -13
- package/.npmrc-tmp +0 -1
- package/CLAUDE.md +0 -18
- package/docs/brainstorm-plan-contract.md +0 -64
- package/docs/plan-execute-contract.md +0 -123
- package/docs/platform-scan-protocol.md +0 -298
- package/docs/revision-mode.md +0 -115
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +0 -99
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +0 -218
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +0 -167
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +0 -148
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +0 -193
- package/docs/sillyspec/file-lifecycle.md +0 -125
- package/docs/workflow-contract-regression.md +0 -106
- package/docs/worktree-isolation.md +0 -252
- package/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/packages/dashboard/dist/prototype-overview.html +0 -256
- package/packages/dashboard/public/prototype-dashboard.html +0 -836
- package/packages/dashboard/public/prototype-overview.html +0 -256
- package/packages/dashboard/src/components/HResizeHandle.vue +0 -48
- package/packages/dashboard/src/components/ProjectCard.vue +0 -187
- package/packages/dashboard/src/components/VResizeHandle.vue +0 -61
- package/packages/dashboard/src/composables/useLayout.js +0 -131
- package/src/brainstorm-postcheck.js +0 -158
- package/src/change-list.js +0 -52
- package/src/change-risk-profile.js +0 -352
- package/src/classify-change.js +0 -73
- package/src/constants.js +0 -70
- package/src/contract-matrix.js +0 -278
- package/src/db.js +0 -201
- package/src/endpoint-extractor.js +0 -315
- package/src/hooks/claude-pre-tool-use.cjs +0 -125
- package/src/hooks/worktree-guard.js +0 -761
- package/src/knowledge-match.js +0 -130
- package/src/modules.js +0 -482
- package/src/scan-postcheck.js +0 -380
- package/src/stage-contract.js +0 -700
- package/src/stages/brainstorm-auto.js +0 -229
- package/src/stages/explore.js +0 -34
- package/src/stages/knowledge.js +0 -498
- package/src/stages/plan-postcheck.js +0 -513
- package/src/sync.js +0 -497
- package/src/task-review.js +0 -346
- package/src/workflow.js +0 -785
- package/src/worktree-apply.js +0 -549
- package/src/worktree.js +0 -932
- package/templates/workflows/archive-impact.yaml +0 -79
- package/templates/workflows/scan-docs.yaml +0 -132
- package/test/brainstorm-plan-contract.test.mjs +0 -273
- package/test/check-syntax.mjs +0 -26
- package/test/cli-top-level-aliases.test.mjs +0 -174
- package/test/contract-artifacts.test.mjs +0 -323
- package/test/decision-supersede.test.mjs +0 -277
- package/test/knowledge-match.test.mjs +0 -231
- package/test/plan-execute-contract.test.mjs +0 -330
- package/test/plan-optimization.test.mjs +0 -572
- package/test/platform-artifacts.test.mjs +0 -190
- package/test/platform-failure-samples.test.mjs +0 -199
- package/test/platform-recovery-chain.test.mjs +0 -179
- package/test/platform-recovery.test.mjs +0 -167
- package/test/platform-scan-p0.test.mjs +0 -175
- package/test/revision-v1.test.mjs +0 -1145
- package/test/run-sanitize-project-name.test.mjs +0 -51
- package/test/run-scan-postcheck-fail.test.mjs +0 -64
- package/test/run-scan-project-parse.test.mjs +0 -77
- package/test/run-tests.mjs +0 -48
- package/test/scan-docs-yaml-placeholders.test.mjs +0 -84
- package/test/scan-knowledge.test.mjs +0 -175
- package/test/scan-paths.test.mjs +0 -68
- package/test/scan-postcheck-project-priority.test.mjs +0 -85
- package/test/scan-postcheck.test.mjs +0 -183
- package/test/scan-workflow-anyfailed-block.test.mjs +0 -52
- package/test/spec-dir.test.mjs +0 -206
- package/test/stage-contract-failed-post-check.test.mjs +0 -102
- package/test/stage-contract.test.mjs +0 -299
- package/test/stage-definitions.test.mjs +0 -39
- package/test/wait-gates.test.mjs +0 -501
- package/test/workflow-spec-base.test.mjs +0 -142
- package/test/worktree-guard.test.mjs +0 -136
- package/test/worktree-native-overlay.test.mjs +0 -188
package/src/init.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync,
|
|
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.
|
|
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 = []
|
|
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
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
186
|
-
mkdirSync(join(
|
|
132
|
+
mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
|
|
133
|
+
mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
|
|
187
134
|
|
|
188
135
|
// 创建知识库骨架
|
|
189
|
-
const knowledgeDir = join(
|
|
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(
|
|
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
|
-
//
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
|
205
|
+
console.log(chalk.yellow(' ⚠ 未找到 skills 目录,跳过 Claude Code skills 同步'));
|
|
260
206
|
}
|
|
261
207
|
}
|
|
262
208
|
|
|
263
209
|
// ── 安装完成总结 ──
|
|
264
210
|
|
|
265
|
-
function showSummary(version, tools
|
|
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(
|
|
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
|
|
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
|
|
399
|
-
showSummary(version, selectedTools
|
|
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
|
|
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
|
-
|
|
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 {
|
|
2
|
+
import { join, resolve } from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Migrate old .sillyspec/ structure to unified
|
|
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 =
|
|
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/ →
|
|
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/ →
|
|
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/ →
|
|
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/ →
|
|
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');
|