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.
Files changed (101) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +85 -85
  2. package/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -114
  3. package/.claude/skills/sillyspec-commit/SKILL.md +109 -109
  4. package/.claude/skills/sillyspec-continue/SKILL.md +45 -45
  5. package/.claude/skills/sillyspec-doctor/SKILL.md +76 -76
  6. package/.claude/skills/sillyspec-execute/SKILL.md +200 -200
  7. package/.claude/skills/sillyspec-explore/SKILL.md +95 -95
  8. package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
  9. package/.claude/skills/sillyspec-plan/SKILL.md +148 -148
  10. package/.claude/skills/sillyspec-quick/SKILL.md +115 -111
  11. package/.claude/skills/sillyspec-resume/SKILL.md +68 -68
  12. package/.claude/skills/sillyspec-scan/SKILL.md +79 -79
  13. package/.claude/skills/sillyspec-state/SKILL.md +64 -64
  14. package/.claude/skills/sillyspec-status/SKILL.md +54 -54
  15. package/.claude/skills/sillyspec-verify/SKILL.md +83 -83
  16. package/.claude/skills/sillyspec-workspace/SKILL.md +169 -169
  17. package/.gitattributes +2 -0
  18. package/.husky/pre-push +20 -20
  19. package/README.md +203 -201
  20. package/SKILL.md +91 -90
  21. package/package.json +39 -39
  22. package/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -7446
  23. package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -1
  24. package/packages/dashboard/dist/index.html +16 -16
  25. package/packages/dashboard/package.json +25 -25
  26. package/packages/dashboard/server/executor.js +95 -86
  27. package/packages/dashboard/server/index.js +663 -601
  28. package/packages/dashboard/server/parser.js +526 -526
  29. package/src/change-risk-profile.js +254 -254
  30. package/src/classify-change.js +109 -109
  31. package/src/config-schema.js +313 -310
  32. package/src/contract-matrix.js +388 -379
  33. package/src/db.js +370 -350
  34. package/src/dispatch/backends/local-agent.js +155 -155
  35. package/src/dispatch/backends/sillyhub-mcp.js +245 -245
  36. package/src/dispatch/probe.js +246 -210
  37. package/src/dispatch/strategy.js +121 -121
  38. package/src/docs-check.js +188 -16
  39. package/src/docs-debt.js +6 -2
  40. package/src/docs-gate.js +1 -0
  41. package/src/doctor-diagnostics.js +898 -711
  42. package/src/endpoint-extractor.js +401 -401
  43. package/src/fs-atomic.js +71 -69
  44. package/src/git-helper.js +82 -79
  45. package/src/hooks/claude-pre-tool-use.cjs +125 -125
  46. package/src/hooks/worktree-guard.js +854 -848
  47. package/src/index.js +251 -20
  48. package/src/init.js +624 -623
  49. package/src/knowledge-match.js +130 -130
  50. package/src/local-detect.js +128 -120
  51. package/src/machine-interface.js +543 -543
  52. package/src/migrate.js +127 -127
  53. package/src/modules.js +7 -5
  54. package/src/progress/change-registry.js +297 -260
  55. package/src/progress/consistency-doctor.js +355 -355
  56. package/src/progress/shared.js +36 -36
  57. package/src/progress/stage-machine.js +589 -550
  58. package/src/progress/step-store.js +261 -261
  59. package/src/progress.js +1285 -1127
  60. package/src/quicklog.js +724 -693
  61. package/src/review-tier.js +77 -77
  62. package/src/run/command.js +1408 -1364
  63. package/src/run/complete-handlers.js +1450 -1399
  64. package/src/run/complete.js +1181 -920
  65. package/src/run/gates.js +878 -755
  66. package/src/run/prompt.js +765 -761
  67. package/src/run/quick-audit.js +155 -146
  68. package/src/run/shared.js +1348 -1215
  69. package/src/run/stage.js +527 -479
  70. package/src/scan-postcheck.js +371 -371
  71. package/src/setup.js +414 -416
  72. package/src/sillyhub-mcp/client.js +597 -529
  73. package/src/spec-dir-typo.js +3 -24
  74. package/src/spec-sync.js +358 -319
  75. package/src/stage-contract.js +871 -897
  76. package/src/stage-review.js +549 -549
  77. package/src/stages/archive.js +156 -155
  78. package/src/stages/brainstorm-auto.js +236 -236
  79. package/src/stages/brainstorm.js +597 -597
  80. package/src/stages/cmd-existence.js +145 -145
  81. package/src/stages/doctor.js +386 -371
  82. package/src/stages/execute.js +1014 -1003
  83. package/src/stages/explore.js +34 -34
  84. package/src/stages/index.js +29 -29
  85. package/src/stages/knowledge.js +498 -498
  86. package/src/stages/plan-postcheck.js +1323 -1302
  87. package/src/stages/plan.js +642 -623
  88. package/src/stages/quick.js +153 -151
  89. package/src/stages/scan.js +607 -607
  90. package/src/stages/status.js +64 -64
  91. package/src/stages/verify.js +264 -264
  92. package/src/sync.js +1325 -1135
  93. package/src/task-review.js +1204 -1019
  94. package/src/taskcard.js +178 -0
  95. package/src/verify-postcheck.js +1199 -1186
  96. package/src/workflow.js +600 -600
  97. package/src/worktree-apply.js +1237 -1136
  98. package/src/worktree-deps.js +453 -353
  99. package/src/worktree.js +1527 -1481
  100. package/templates/workflows/archive-impact.yaml +79 -79
  101. 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 { DB } from './db.js';
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
- const { execSync } = await import('child_process');
118
- headCommit = execSync('git rev-parse --short HEAD', { cwd, encoding: 'utf8', timeout: 5000 }).trim();
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
- const lines = content.split('\n');
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;