sillyspec 3.26.10 → 3.26.13
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 +85 -85
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -114
- package/.claude/skills/sillyspec-commit/SKILL.md +109 -109
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -45
- package/.claude/skills/sillyspec-doctor/SKILL.md +76 -76
- package/.claude/skills/sillyspec-execute/SKILL.md +200 -200
- package/.claude/skills/sillyspec-explore/SKILL.md +95 -95
- package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
- package/.claude/skills/sillyspec-plan/SKILL.md +148 -148
- package/.claude/skills/sillyspec-quick/SKILL.md +115 -111
- package/.claude/skills/sillyspec-resume/SKILL.md +68 -68
- package/.claude/skills/sillyspec-scan/SKILL.md +79 -79
- package/.claude/skills/sillyspec-state/SKILL.md +64 -64
- package/.claude/skills/sillyspec-status/SKILL.md +54 -54
- package/.claude/skills/sillyspec-verify/SKILL.md +83 -83
- package/.claude/skills/sillyspec-workspace/SKILL.md +169 -169
- package/.gitattributes +2 -0
- package/.husky/pre-push +20 -20
- package/README.md +203 -201
- package/SKILL.md +91 -90
- package/package.json +39 -39
- package/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -7446
- package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -1
- package/packages/dashboard/dist/index.html +16 -16
- package/packages/dashboard/package.json +25 -25
- package/packages/dashboard/server/executor.js +95 -86
- package/packages/dashboard/server/index.js +663 -601
- package/packages/dashboard/server/parser.js +526 -526
- package/src/change-risk-profile.js +254 -254
- package/src/classify-change.js +109 -109
- package/src/config-schema.js +313 -310
- package/src/contract-matrix.js +388 -379
- package/src/db.js +370 -350
- package/src/dispatch/backends/local-agent.js +155 -155
- package/src/dispatch/backends/sillyhub-mcp.js +245 -245
- package/src/dispatch/probe.js +246 -210
- package/src/dispatch/strategy.js +121 -121
- package/src/docs-check.js +188 -16
- package/src/docs-debt.js +6 -2
- package/src/docs-gate.js +1 -0
- package/src/doctor-diagnostics.js +898 -711
- package/src/endpoint-extractor.js +401 -401
- package/src/fs-atomic.js +71 -69
- package/src/git-helper.js +82 -79
- package/src/hooks/claude-pre-tool-use.cjs +125 -125
- package/src/hooks/worktree-guard.js +854 -848
- package/src/index.js +251 -20
- package/src/init.js +624 -623
- package/src/knowledge-match.js +130 -130
- package/src/local-detect.js +128 -120
- package/src/machine-interface.js +543 -543
- package/src/migrate.js +127 -127
- package/src/modules.js +7 -5
- package/src/progress/change-registry.js +297 -260
- package/src/progress/consistency-doctor.js +355 -355
- package/src/progress/shared.js +36 -36
- package/src/progress/stage-machine.js +589 -550
- package/src/progress/step-store.js +261 -261
- package/src/progress.js +1285 -1127
- package/src/quicklog.js +724 -693
- package/src/review-tier.js +77 -77
- package/src/run/command.js +1408 -1364
- package/src/run/complete-handlers.js +1450 -1399
- package/src/run/complete.js +1181 -920
- package/src/run/gates.js +878 -755
- package/src/run/prompt.js +765 -761
- package/src/run/quick-audit.js +155 -146
- package/src/run/shared.js +1348 -1215
- package/src/run/stage.js +527 -479
- package/src/scan-postcheck.js +371 -371
- package/src/setup.js +414 -416
- package/src/sillyhub-mcp/client.js +597 -529
- package/src/spec-dir-typo.js +3 -24
- package/src/spec-sync.js +358 -319
- package/src/stage-contract.js +871 -897
- package/src/stage-review.js +549 -549
- package/src/stages/archive.js +156 -155
- package/src/stages/brainstorm-auto.js +236 -236
- package/src/stages/brainstorm.js +597 -597
- package/src/stages/cmd-existence.js +145 -145
- package/src/stages/doctor.js +386 -371
- package/src/stages/execute.js +1014 -1003
- package/src/stages/explore.js +34 -34
- package/src/stages/index.js +29 -29
- package/src/stages/knowledge.js +498 -498
- package/src/stages/plan-postcheck.js +1323 -1302
- package/src/stages/plan.js +642 -623
- package/src/stages/quick.js +153 -151
- package/src/stages/scan.js +607 -607
- package/src/stages/status.js +64 -64
- package/src/stages/verify.js +264 -264
- package/src/sync.js +1325 -1135
- package/src/task-review.js +1204 -1019
- package/src/taskcard.js +178 -0
- package/src/verify-postcheck.js +1199 -1186
- package/src/workflow.js +600 -600
- package/src/worktree-apply.js +1237 -1136
- package/src/worktree-deps.js +453 -353
- package/src/worktree.js +1527 -1481
- package/templates/workflows/archive-impact.yaml +79 -79
- package/templates/workflows/scan-docs.yaml +132 -132
package/src/migrate.js
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, renameSync, copyFileSync, statSync, cpSync } from 'fs';
|
|
2
|
-
import { basename, join, resolve } from 'path';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Migrate old .sillyspec/ structure to unified .sillyspec/docs/<project>/ structure
|
|
7
|
-
* @param {string} projectDir - Path to the project directory
|
|
8
|
-
*/
|
|
9
|
-
export function migrateDocs(projectDir) {
|
|
10
|
-
const sillyspecDir = join(projectDir, '.sillyspec');
|
|
11
|
-
if (!existsSync(sillyspecDir)) {
|
|
12
|
-
console.error('❌ .sillyspec/ 目录不存在');
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Determine project name from projects/*.yaml or directory name
|
|
17
|
-
let projectName = basename(resolve(projectDir));
|
|
18
|
-
const projectsDir = join(sillyspecDir, 'projects');
|
|
19
|
-
if (existsSync(projectsDir)) {
|
|
20
|
-
const yamlFiles = readdirSync(projectsDir).filter(f => f.endsWith('.yaml'));
|
|
21
|
-
if (yamlFiles.length > 0) {
|
|
22
|
-
projectName = yamlFiles[0].replace('.yaml', '');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log(chalk.cyan(`📦 迁移项目: ${projectName}`));
|
|
27
|
-
console.log('');
|
|
28
|
-
|
|
29
|
-
const docsBase = join(sillyspecDir, 'docs', projectName);
|
|
30
|
-
let migrated = 0;
|
|
31
|
-
|
|
32
|
-
// 1. codebase/ → .sillyspec/docs/<project>/scan/
|
|
33
|
-
const codebaseDir = join(sillyspecDir, 'codebase');
|
|
34
|
-
if (existsSync(codebaseDir)) {
|
|
35
|
-
const targetDir = join(docsBase, 'scan');
|
|
36
|
-
mkdirSync(targetDir, { recursive: true });
|
|
37
|
-
const files = readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
|
|
38
|
-
for (const file of files) {
|
|
39
|
-
const src = join(codebaseDir, file);
|
|
40
|
-
const dest = join(targetDir, file);
|
|
41
|
-
if (!existsSync(dest)) {
|
|
42
|
-
copyFileSync(src, dest);
|
|
43
|
-
console.log(chalk.green(' ✅') + ` scan/${file}`);
|
|
44
|
-
migrated++;
|
|
45
|
-
} else {
|
|
46
|
-
console.log(chalk.yellow(' ⏭️') + ` scan/${file} (已存在)`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 2. specs/ is deprecated — designs live in changes/<变更名>/design.md
|
|
52
|
-
|
|
53
|
-
// 3. changes/archive/ → .sillyspec/docs/<project>/archive/
|
|
54
|
-
const archiveDir = join(sillyspecDir, 'changes', 'archive');
|
|
55
|
-
if (existsSync(archiveDir)) {
|
|
56
|
-
const targetDir = join(docsBase, 'archive');
|
|
57
|
-
mkdirSync(targetDir, { recursive: true });
|
|
58
|
-
const entries = readdirSync(archiveDir);
|
|
59
|
-
for (const entry of entries) {
|
|
60
|
-
const src = join(archiveDir, entry);
|
|
61
|
-
const dest = join(targetDir, entry);
|
|
62
|
-
if (!existsSync(dest)) {
|
|
63
|
-
// 归档变更本身是目录(含 design.md 等),copyFileSync 对目录源抛 EISDIR;
|
|
64
|
-
// 按类型分发:目录用 cpSync 递归、文件用 copyFileSync,单条失败 try/catch 不中断整体迁移
|
|
65
|
-
try {
|
|
66
|
-
if (statSync(src).isDirectory()) {
|
|
67
|
-
cpSync(src, dest, { recursive: true });
|
|
68
|
-
} else {
|
|
69
|
-
copyFileSync(src, dest);
|
|
70
|
-
}
|
|
71
|
-
console.log(chalk.green(' ✅') + ` archive/${entry}`);
|
|
72
|
-
migrated++;
|
|
73
|
-
} catch (err) {
|
|
74
|
-
console.log(chalk.yellow(' ⚠️') + ` archive/${entry} 迁移失败: ${err.message}`);
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
console.log(chalk.yellow(' ⏭️') + ` archive/${entry} (已存在)`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 4. knowledge/ → .sillyspec/docs/<project>/archive/ (append knowledge files)
|
|
83
|
-
const knowledgeDir = join(sillyspecDir, 'knowledge');
|
|
84
|
-
if (existsSync(knowledgeDir)) {
|
|
85
|
-
const targetDir = join(docsBase, 'archive');
|
|
86
|
-
mkdirSync(targetDir, { recursive: true });
|
|
87
|
-
const files = readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
|
|
88
|
-
for (const file of files) {
|
|
89
|
-
const src = join(knowledgeDir, file);
|
|
90
|
-
const dest = join(targetDir, `knowledge-${file}`);
|
|
91
|
-
if (!existsSync(dest)) {
|
|
92
|
-
copyFileSync(src, dest);
|
|
93
|
-
console.log(chalk.green(' ✅') + ` archive/knowledge-${file}`);
|
|
94
|
-
migrated++;
|
|
95
|
-
} else {
|
|
96
|
-
console.log(chalk.yellow(' ⏭️') + ` archive/knowledge-${file} (已存在)`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// 5. quicklog/ → .sillyspec/docs/<project>/quicklog/
|
|
102
|
-
const quicklogDir = join(sillyspecDir, 'quicklog');
|
|
103
|
-
if (existsSync(quicklogDir)) {
|
|
104
|
-
const targetDir = join(docsBase, 'quicklog');
|
|
105
|
-
mkdirSync(targetDir, { recursive: true });
|
|
106
|
-
const files = readdirSync(quicklogDir).filter(f => f.endsWith('.md'));
|
|
107
|
-
for (const file of files) {
|
|
108
|
-
const src = join(quicklogDir, file);
|
|
109
|
-
const dest = join(targetDir, file);
|
|
110
|
-
if (!existsSync(dest)) {
|
|
111
|
-
copyFileSync(src, dest);
|
|
112
|
-
console.log(chalk.green(' ✅') + ` quicklog/${file}`);
|
|
113
|
-
migrated++;
|
|
114
|
-
} else {
|
|
115
|
-
console.log(chalk.yellow(' ⏭️') + ` quicklog/${file} (已存在)`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.log('');
|
|
121
|
-
if (migrated > 0) {
|
|
122
|
-
console.log(chalk.green(` ✅ 迁移完成,共迁移 ${migrated} 个文件`));
|
|
123
|
-
console.log(chalk.dim(' 旧文件保留在原位,确认无误后可手动删除'));
|
|
124
|
-
} else {
|
|
125
|
-
console.log(chalk.yellow(' 没有需要迁移的文件'));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, renameSync, copyFileSync, statSync, cpSync } from 'fs';
|
|
2
|
+
import { basename, join, resolve } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Migrate old .sillyspec/ structure to unified .sillyspec/docs/<project>/ structure
|
|
7
|
+
* @param {string} projectDir - Path to the project directory
|
|
8
|
+
*/
|
|
9
|
+
export function migrateDocs(projectDir) {
|
|
10
|
+
const sillyspecDir = join(projectDir, '.sillyspec');
|
|
11
|
+
if (!existsSync(sillyspecDir)) {
|
|
12
|
+
console.error('❌ .sillyspec/ 目录不存在');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Determine project name from projects/*.yaml or directory name
|
|
17
|
+
let projectName = basename(resolve(projectDir));
|
|
18
|
+
const projectsDir = join(sillyspecDir, 'projects');
|
|
19
|
+
if (existsSync(projectsDir)) {
|
|
20
|
+
const yamlFiles = readdirSync(projectsDir).filter(f => f.endsWith('.yaml'));
|
|
21
|
+
if (yamlFiles.length > 0) {
|
|
22
|
+
projectName = yamlFiles[0].replace('.yaml', '');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(chalk.cyan(`📦 迁移项目: ${projectName}`));
|
|
27
|
+
console.log('');
|
|
28
|
+
|
|
29
|
+
const docsBase = join(sillyspecDir, 'docs', projectName);
|
|
30
|
+
let migrated = 0;
|
|
31
|
+
|
|
32
|
+
// 1. codebase/ → .sillyspec/docs/<project>/scan/
|
|
33
|
+
const codebaseDir = join(sillyspecDir, 'codebase');
|
|
34
|
+
if (existsSync(codebaseDir)) {
|
|
35
|
+
const targetDir = join(docsBase, 'scan');
|
|
36
|
+
mkdirSync(targetDir, { recursive: true });
|
|
37
|
+
const files = readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
const src = join(codebaseDir, file);
|
|
40
|
+
const dest = join(targetDir, file);
|
|
41
|
+
if (!existsSync(dest)) {
|
|
42
|
+
copyFileSync(src, dest);
|
|
43
|
+
console.log(chalk.green(' ✅') + ` scan/${file}`);
|
|
44
|
+
migrated++;
|
|
45
|
+
} else {
|
|
46
|
+
console.log(chalk.yellow(' ⏭️') + ` scan/${file} (已存在)`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 2. specs/ is deprecated — designs live in changes/<变更名>/design.md
|
|
52
|
+
|
|
53
|
+
// 3. changes/archive/ → .sillyspec/docs/<project>/archive/
|
|
54
|
+
const archiveDir = join(sillyspecDir, 'changes', 'archive');
|
|
55
|
+
if (existsSync(archiveDir)) {
|
|
56
|
+
const targetDir = join(docsBase, 'archive');
|
|
57
|
+
mkdirSync(targetDir, { recursive: true });
|
|
58
|
+
const entries = readdirSync(archiveDir);
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const src = join(archiveDir, entry);
|
|
61
|
+
const dest = join(targetDir, entry);
|
|
62
|
+
if (!existsSync(dest)) {
|
|
63
|
+
// 归档变更本身是目录(含 design.md 等),copyFileSync 对目录源抛 EISDIR;
|
|
64
|
+
// 按类型分发:目录用 cpSync 递归、文件用 copyFileSync,单条失败 try/catch 不中断整体迁移
|
|
65
|
+
try {
|
|
66
|
+
if (statSync(src).isDirectory()) {
|
|
67
|
+
cpSync(src, dest, { recursive: true });
|
|
68
|
+
} else {
|
|
69
|
+
copyFileSync(src, dest);
|
|
70
|
+
}
|
|
71
|
+
console.log(chalk.green(' ✅') + ` archive/${entry}`);
|
|
72
|
+
migrated++;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.log(chalk.yellow(' ⚠️') + ` archive/${entry} 迁移失败: ${err.message}`);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
console.log(chalk.yellow(' ⏭️') + ` archive/${entry} (已存在)`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 4. knowledge/ → .sillyspec/docs/<project>/archive/ (append knowledge files)
|
|
83
|
+
const knowledgeDir = join(sillyspecDir, 'knowledge');
|
|
84
|
+
if (existsSync(knowledgeDir)) {
|
|
85
|
+
const targetDir = join(docsBase, 'archive');
|
|
86
|
+
mkdirSync(targetDir, { recursive: true });
|
|
87
|
+
const files = readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
const src = join(knowledgeDir, file);
|
|
90
|
+
const dest = join(targetDir, `knowledge-${file}`);
|
|
91
|
+
if (!existsSync(dest)) {
|
|
92
|
+
copyFileSync(src, dest);
|
|
93
|
+
console.log(chalk.green(' ✅') + ` archive/knowledge-${file}`);
|
|
94
|
+
migrated++;
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.yellow(' ⏭️') + ` archive/knowledge-${file} (已存在)`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 5. quicklog/ → .sillyspec/docs/<project>/quicklog/
|
|
102
|
+
const quicklogDir = join(sillyspecDir, 'quicklog');
|
|
103
|
+
if (existsSync(quicklogDir)) {
|
|
104
|
+
const targetDir = join(docsBase, 'quicklog');
|
|
105
|
+
mkdirSync(targetDir, { recursive: true });
|
|
106
|
+
const files = readdirSync(quicklogDir).filter(f => f.endsWith('.md'));
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
const src = join(quicklogDir, file);
|
|
109
|
+
const dest = join(targetDir, file);
|
|
110
|
+
if (!existsSync(dest)) {
|
|
111
|
+
copyFileSync(src, dest);
|
|
112
|
+
console.log(chalk.green(' ✅') + ` quicklog/${file}`);
|
|
113
|
+
migrated++;
|
|
114
|
+
} else {
|
|
115
|
+
console.log(chalk.yellow(' ⏭️') + ` quicklog/${file} (已存在)`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log('');
|
|
121
|
+
if (migrated > 0) {
|
|
122
|
+
console.log(chalk.green(` ✅ 迁移完成,共迁移 ${migrated} 个文件`));
|
|
123
|
+
console.log(chalk.dim(' 旧文件保留在原位,确认无误后可手动删除'));
|
|
124
|
+
} else {
|
|
125
|
+
console.log(chalk.yellow(' 没有需要迁移的文件'));
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/modules.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { gitQuiet } from './git-helper.js';
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* 查找项目下的 _module-map.yaml 路径
|
|
@@ -114,8 +115,8 @@ export async function rebuildModuleMap(cwd, { force = false } = {}) {
|
|
|
114
115
|
const now = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
115
116
|
let headCommit = '';
|
|
116
117
|
try {
|
|
117
|
-
|
|
118
|
-
headCommit =
|
|
118
|
+
// QUAL-01 收口:走 git-helper 统一入口(safe.directory + 数组形式)
|
|
119
|
+
headCommit = gitQuiet(cwd, ['rev-parse', '--short', 'HEAD']) || '';
|
|
119
120
|
} catch { /* ignore */ }
|
|
120
121
|
|
|
121
122
|
let yaml = `schema_version: 2\n`;
|
|
@@ -193,8 +194,9 @@ export async function showModuleStatus(cwd) {
|
|
|
193
194
|
|
|
194
195
|
const content = readFileSync(mapPath, 'utf8');
|
|
195
196
|
|
|
196
|
-
//
|
|
197
|
-
|
|
197
|
+
// 简单解析(CRLF 兼容:坑 verify-modules-crlf-blanket-fallback 同类——`$` 锚定正则在
|
|
198
|
+
// Windows 编辑器写出的 CRLF 文件上模块条目全失配,模块数恒显示 0)
|
|
199
|
+
const lines = content.split(/\r?\n/);
|
|
198
200
|
const modules = [];
|
|
199
201
|
let currentModule = null;
|
|
200
202
|
let needsReview = false;
|