sillyspec 3.20.2 → 3.20.4
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 +21 -21
- package/.claude/skills/sillyspec-auto/SKILL.md +83 -83
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +44 -44
- package/.claude/skills/sillyspec-commit/SKILL.md +106 -106
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -45
- package/.claude/skills/sillyspec-doctor/SKILL.md +31 -31
- package/.claude/skills/sillyspec-execute/SKILL.md +30 -30
- package/.claude/skills/sillyspec-explore/SKILL.md +109 -109
- package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
- package/.claude/skills/sillyspec-plan/SKILL.md +21 -21
- package/.claude/skills/sillyspec-propose/SKILL.md +21 -21
- package/.claude/skills/sillyspec-quick/SKILL.md +21 -21
- package/.claude/skills/sillyspec-resume/SKILL.md +68 -68
- package/.claude/skills/sillyspec-scan/SKILL.md +21 -21
- package/.claude/skills/sillyspec-state/SKILL.md +54 -54
- package/.claude/skills/sillyspec-status/SKILL.md +21 -21
- package/.claude/skills/sillyspec-verify/SKILL.md +21 -21
- package/.claude/skills/sillyspec-workspace/SKILL.md +157 -157
- package/.husky/pre-push +13 -13
- package/CLAUDE.md +18 -18
- package/README.md +198 -188
- package/SKILL.md +90 -91
- package/bin/sillyspec.js +2 -2
- package/docs/brainstorm-plan-contract.md +64 -64
- package/docs/plan-execute-contract.md +123 -123
- package/docs/platform-scan-protocol.md +298 -298
- package/docs/revision-mode.md +115 -115
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -99
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -218
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -167
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -148
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +211 -193
- package/docs/sillyspec/file-lifecycle.md +125 -125
- package/docs/workflow-contract-regression.md +106 -106
- package/docs/worktree-isolation.md +252 -252
- package/package.json +40 -40
- 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/index.html +15 -15
- package/packages/dashboard/package-lock.json +2384 -2384
- package/packages/dashboard/package.json +25 -25
- package/packages/dashboard/server/executor.js +86 -86
- package/packages/dashboard/server/index.js +588 -588
- package/packages/dashboard/server/parser.js +526 -526
- package/packages/dashboard/server/watcher.js +344 -344
- package/packages/dashboard/src/App.vue +558 -558
- package/packages/dashboard/src/components/ActionBar.vue +93 -93
- package/packages/dashboard/src/components/CommandPalette.vue +96 -96
- package/packages/dashboard/src/components/DetailPanel.vue +137 -137
- package/packages/dashboard/src/components/LogStream.vue +65 -65
- package/packages/dashboard/src/components/PipelineStage.vue +95 -95
- package/packages/dashboard/src/components/PipelineView.vue +156 -156
- package/packages/dashboard/src/components/ProjectList.vue +210 -210
- package/packages/dashboard/src/components/StageBadge.vue +67 -67
- package/packages/dashboard/src/components/StepCard.vue +94 -94
- package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +61 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +43 -43
- package/packages/dashboard/src/composables/useDashboard.js +170 -170
- package/packages/dashboard/src/composables/useKeyboard.js +119 -119
- package/packages/dashboard/src/composables/useWebSocket.js +129 -129
- package/packages/dashboard/src/main.js +8 -8
- package/packages/dashboard/src/style.css +132 -132
- package/packages/dashboard/vite.config.js +18 -18
- package/src/brainstorm-postcheck.js +158 -158
- package/src/change-list.js +52 -52
- package/src/change-risk-profile.js +352 -352
- package/src/classify-change.js +73 -73
- package/src/constants.js +70 -70
- package/src/contract-matrix.js +278 -278
- package/src/db.js +201 -201
- package/src/endpoint-extractor.js +315 -315
- package/src/hooks/claude-pre-tool-use.cjs +125 -125
- package/src/hooks/worktree-guard.js +653 -653
- package/src/index.js +922 -900
- package/src/init.js +431 -431
- package/src/knowledge-match.js +130 -130
- package/src/migrate.js +117 -117
- package/src/modules.js +482 -482
- package/src/progress.js +1734 -1734
- package/src/run.js +3465 -3358
- package/src/scan-postcheck.js +387 -383
- package/src/setup.js +398 -398
- package/src/stage-contract.js +700 -700
- package/src/stages/archive.js +160 -160
- package/src/stages/brainstorm-auto.js +229 -229
- package/src/stages/brainstorm.js +645 -645
- package/src/stages/doctor.js +365 -365
- package/src/stages/execute.js +625 -625
- 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 +511 -513
- package/src/stages/plan.js +582 -582
- package/src/stages/propose.js +174 -174
- package/src/stages/quick.js +82 -82
- package/src/stages/scan.js +558 -558
- package/src/stages/status.js +65 -65
- package/src/stages/verify.js +322 -322
- package/src/sync.js +497 -497
- package/src/task-review.js +346 -346
- package/src/workflow.js +785 -785
- package/src/worktree-apply.js +549 -549
- package/src/worktree-deps.js +185 -0
- package/src/worktree.js +982 -932
- package/templates/workflows/archive-impact.yaml +79 -79
- package/templates/workflows/scan-docs.yaml +132 -132
- package/test/brainstorm-plan-contract.test.mjs +273 -273
- package/test/check-syntax.mjs +26 -26
- package/test/contract-artifacts.test.mjs +323 -323
- package/test/decision-supersede.test.mjs +277 -277
- package/test/knowledge-match.test.mjs +231 -231
- package/test/plan-execute-contract.test.mjs +330 -330
- package/test/plan-optimization.test.mjs +572 -572
- package/test/platform-artifacts.test.mjs +166 -166
- package/test/platform-failure-samples.test.mjs +199 -199
- package/test/platform-recovery-chain.test.mjs +167 -167
- package/test/platform-recovery.test.mjs +136 -136
- package/test/platform-scan-p0.test.mjs +168 -168
- package/test/revision-v1.test.mjs +1145 -1145
- package/test/run-scan-project-parse.test.mjs +200 -200
- package/test/run-tests.mjs +48 -48
- package/test/scan-knowledge.test.mjs +175 -175
- package/test/scan-paths.test.mjs +68 -68
- package/test/scan-postcheck.test.mjs +197 -197
- package/test/spec-dir.test.mjs +206 -206
- package/test/stage-contract.test.mjs +299 -299
- package/test/stage-definitions.test.mjs +39 -39
- package/test/wait-gates.test.mjs +496 -496
- package/test/worktree-deps-provision.test.mjs +148 -0
- package/test/worktree-guard.test.mjs +71 -71
- package/test/worktree-native-overlay.test.mjs +188 -188
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Claude Code PreToolUse hook 入口
|
|
4
|
-
*
|
|
5
|
-
* 从 stdin 读取 JSON,调用 worktree-guard 判断是否拦截。
|
|
6
|
-
*
|
|
7
|
-
* Claude Code hooks.json 配置:
|
|
8
|
-
* {
|
|
9
|
-
* "hooks": {
|
|
10
|
-
* "PreToolUse": [
|
|
11
|
-
* {
|
|
12
|
-
* "matcher": "Edit|Write|MultiEdit|Bash",
|
|
13
|
-
* "hooks": [
|
|
14
|
-
* {
|
|
15
|
-
* "type": "command",
|
|
16
|
-
* "command": "node /path/to/sillyspec/src/hooks/claude-pre-tool-use.cjs"
|
|
17
|
-
* }
|
|
18
|
-
* ]
|
|
19
|
-
* }
|
|
20
|
-
* ]
|
|
21
|
-
* }
|
|
22
|
-
* }
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
'use strict'
|
|
26
|
-
|
|
27
|
-
const path = require('path')
|
|
28
|
-
const fs = require('fs')
|
|
29
|
-
|
|
30
|
-
// 动态 import ESM 模块
|
|
31
|
-
async function main() {
|
|
32
|
-
// Claude Code hook 通过 stdin 传入 JSON
|
|
33
|
-
let input = ''
|
|
34
|
-
try {
|
|
35
|
-
input = await readStdin()
|
|
36
|
-
} catch {
|
|
37
|
-
// 无法读取 stdin → 放行(安全优先于阻断)
|
|
38
|
-
process.exit(0)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let parsed
|
|
42
|
-
try {
|
|
43
|
-
parsed = JSON.parse(input)
|
|
44
|
-
} catch {
|
|
45
|
-
// 非法 JSON → 放行
|
|
46
|
-
process.exit(0)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// 解析 Claude Code hook 输入格式
|
|
50
|
-
// 格式:{ tool_name: string, tool_input: { ... } }
|
|
51
|
-
const toolName = parsed.tool_name || parsed.tool || ''
|
|
52
|
-
const toolInput = parsed.tool_input || {}
|
|
53
|
-
|
|
54
|
-
// 转换为 shouldBlock 的输入格式
|
|
55
|
-
const toolMap = {
|
|
56
|
-
'Write': 'Write',
|
|
57
|
-
'Edit': 'Edit',
|
|
58
|
-
'MultiEdit': 'MultiEdit',
|
|
59
|
-
'Bash': 'Bash',
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const mappedTool = toolMap[toolName]
|
|
63
|
-
if (!mappedTool) {
|
|
64
|
-
// 不在拦截范围内的工具 → 放行
|
|
65
|
-
process.exit(0)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// 构造 opts
|
|
69
|
-
const opts = { tool: mappedTool }
|
|
70
|
-
if (mappedTool === 'Bash') {
|
|
71
|
-
opts.command = toolInput.command || ''
|
|
72
|
-
} else {
|
|
73
|
-
// Write/Edit/MultiEdit
|
|
74
|
-
const fp = toolInput.file_path || toolInput.filePath
|
|
75
|
-
if (fp) opts.filePath = fp
|
|
76
|
-
// MultiEdit 可能有多个文件
|
|
77
|
-
if (mappedTool === 'MultiEdit') {
|
|
78
|
-
const fps = toolInput.edits
|
|
79
|
-
? toolInput.edits.map(e => e.file_path || e.filePath).filter(Boolean)
|
|
80
|
-
: []
|
|
81
|
-
if (fps.length > 0) opts.filePaths = fps
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 加载 worktree-guard(ESM)
|
|
86
|
-
let shouldBlock
|
|
87
|
-
try {
|
|
88
|
-
const mod = await import('./worktree-guard.js')
|
|
89
|
-
shouldBlock = mod.shouldBlock
|
|
90
|
-
} catch (e) {
|
|
91
|
-
// 模块加载失败 → 放行(不因为 hook 出错阻断工作流)
|
|
92
|
-
// eslint-disable-next-line no-console
|
|
93
|
-
console.error(`[sillyspec-hook] 模块加载失败: ${e.message}`)
|
|
94
|
-
process.exit(0)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const result = shouldBlock(opts)
|
|
98
|
-
|
|
99
|
-
if (result.blocked) {
|
|
100
|
-
// 输出错误信息(Claude Code 会显示给 agent)
|
|
101
|
-
// eslint-disable-next-line no-console
|
|
102
|
-
console.error(`[sillyspec] ❌ ${result.reason || 'blocked by worktree guard'}`)
|
|
103
|
-
process.exit(2) // exit code 2 = 阻止工具执行
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 放行
|
|
107
|
-
process.exit(0)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function readStdin() {
|
|
111
|
-
return new Promise((resolve, reject) => {
|
|
112
|
-
const chunks = []
|
|
113
|
-
process.stdin.setEncoding('utf8')
|
|
114
|
-
process.stdin.on('data', chunk => chunks.push(chunk))
|
|
115
|
-
process.stdin.on('end', () => resolve(chunks.join('')))
|
|
116
|
-
process.stdin.on('error', reject)
|
|
117
|
-
// 超时保护(3秒)
|
|
118
|
-
setTimeout(() => {
|
|
119
|
-
process.stdin.destroy()
|
|
120
|
-
resolve('')
|
|
121
|
-
}, 3000)
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
main().catch(() => process.exit(0))
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code PreToolUse hook 入口
|
|
4
|
+
*
|
|
5
|
+
* 从 stdin 读取 JSON,调用 worktree-guard 判断是否拦截。
|
|
6
|
+
*
|
|
7
|
+
* Claude Code hooks.json 配置:
|
|
8
|
+
* {
|
|
9
|
+
* "hooks": {
|
|
10
|
+
* "PreToolUse": [
|
|
11
|
+
* {
|
|
12
|
+
* "matcher": "Edit|Write|MultiEdit|Bash",
|
|
13
|
+
* "hooks": [
|
|
14
|
+
* {
|
|
15
|
+
* "type": "command",
|
|
16
|
+
* "command": "node /path/to/sillyspec/src/hooks/claude-pre-tool-use.cjs"
|
|
17
|
+
* }
|
|
18
|
+
* ]
|
|
19
|
+
* }
|
|
20
|
+
* ]
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use strict'
|
|
26
|
+
|
|
27
|
+
const path = require('path')
|
|
28
|
+
const fs = require('fs')
|
|
29
|
+
|
|
30
|
+
// 动态 import ESM 模块
|
|
31
|
+
async function main() {
|
|
32
|
+
// Claude Code hook 通过 stdin 传入 JSON
|
|
33
|
+
let input = ''
|
|
34
|
+
try {
|
|
35
|
+
input = await readStdin()
|
|
36
|
+
} catch {
|
|
37
|
+
// 无法读取 stdin → 放行(安全优先于阻断)
|
|
38
|
+
process.exit(0)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let parsed
|
|
42
|
+
try {
|
|
43
|
+
parsed = JSON.parse(input)
|
|
44
|
+
} catch {
|
|
45
|
+
// 非法 JSON → 放行
|
|
46
|
+
process.exit(0)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 解析 Claude Code hook 输入格式
|
|
50
|
+
// 格式:{ tool_name: string, tool_input: { ... } }
|
|
51
|
+
const toolName = parsed.tool_name || parsed.tool || ''
|
|
52
|
+
const toolInput = parsed.tool_input || {}
|
|
53
|
+
|
|
54
|
+
// 转换为 shouldBlock 的输入格式
|
|
55
|
+
const toolMap = {
|
|
56
|
+
'Write': 'Write',
|
|
57
|
+
'Edit': 'Edit',
|
|
58
|
+
'MultiEdit': 'MultiEdit',
|
|
59
|
+
'Bash': 'Bash',
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const mappedTool = toolMap[toolName]
|
|
63
|
+
if (!mappedTool) {
|
|
64
|
+
// 不在拦截范围内的工具 → 放行
|
|
65
|
+
process.exit(0)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 构造 opts
|
|
69
|
+
const opts = { tool: mappedTool }
|
|
70
|
+
if (mappedTool === 'Bash') {
|
|
71
|
+
opts.command = toolInput.command || ''
|
|
72
|
+
} else {
|
|
73
|
+
// Write/Edit/MultiEdit
|
|
74
|
+
const fp = toolInput.file_path || toolInput.filePath
|
|
75
|
+
if (fp) opts.filePath = fp
|
|
76
|
+
// MultiEdit 可能有多个文件
|
|
77
|
+
if (mappedTool === 'MultiEdit') {
|
|
78
|
+
const fps = toolInput.edits
|
|
79
|
+
? toolInput.edits.map(e => e.file_path || e.filePath).filter(Boolean)
|
|
80
|
+
: []
|
|
81
|
+
if (fps.length > 0) opts.filePaths = fps
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 加载 worktree-guard(ESM)
|
|
86
|
+
let shouldBlock
|
|
87
|
+
try {
|
|
88
|
+
const mod = await import('./worktree-guard.js')
|
|
89
|
+
shouldBlock = mod.shouldBlock
|
|
90
|
+
} catch (e) {
|
|
91
|
+
// 模块加载失败 → 放行(不因为 hook 出错阻断工作流)
|
|
92
|
+
// eslint-disable-next-line no-console
|
|
93
|
+
console.error(`[sillyspec-hook] 模块加载失败: ${e.message}`)
|
|
94
|
+
process.exit(0)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = shouldBlock(opts)
|
|
98
|
+
|
|
99
|
+
if (result.blocked) {
|
|
100
|
+
// 输出错误信息(Claude Code 会显示给 agent)
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
102
|
+
console.error(`[sillyspec] ❌ ${result.reason || 'blocked by worktree guard'}`)
|
|
103
|
+
process.exit(2) // exit code 2 = 阻止工具执行
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 放行
|
|
107
|
+
process.exit(0)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function readStdin() {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const chunks = []
|
|
113
|
+
process.stdin.setEncoding('utf8')
|
|
114
|
+
process.stdin.on('data', chunk => chunks.push(chunk))
|
|
115
|
+
process.stdin.on('end', () => resolve(chunks.join('')))
|
|
116
|
+
process.stdin.on('error', reject)
|
|
117
|
+
// 超时保护(3秒)
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
process.stdin.destroy()
|
|
120
|
+
resolve('')
|
|
121
|
+
}, 3000)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
main().catch(() => process.exit(0))
|