sillyspec 3.15.2 → 3.16.1
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/.husky/pre-push +13 -0
- package/README.md +1 -1
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -0
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -0
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -0
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -0
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +193 -0
- package/docs/sillyspec/file-lifecycle.md +106 -1167
- package/docs/worktree-isolation.md +57 -2
- package/package.json +5 -1
- package/src/db.js +17 -0
- package/src/hooks/worktree-guard.js +166 -47
- package/src/index.js +44 -3
- package/src/progress.js +79 -0
- package/src/run.js +447 -55
- package/src/stage-contract.js +347 -0
- package/src/stages/archive.js +6 -10
- package/src/stages/brainstorm.js +4 -1
- package/src/stages/doctor.js +43 -2
- package/src/stages/execute.js +32 -5
- package/src/stages/propose.js +4 -1
- package/src/stages/quick.js +3 -3
- package/src/stages/scan.js +18 -18
- package/src/workflow.js +6 -2
- package/src/worktree-apply.js +14 -0
- package/src/worktree.js +201 -11
- package/test/check-syntax.mjs +26 -0
- package/test/run-tests.mjs +20 -0
- package/test/scan-paths.test.mjs +68 -0
- package/test/stage-contract.test.mjs +128 -0
- package/test/stage-definitions.test.mjs +43 -0
- package/test/worktree-guard.test.mjs +78 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import { shouldBlock } from '../src/hooks/worktree-guard.js'
|
|
6
|
+
|
|
7
|
+
const root = join(tmpdir(), `sillyspec-guard-test-${Date.now()}`)
|
|
8
|
+
const changeName = '2026-06-04-guard-test'
|
|
9
|
+
const runtimeDir = join(root, '.sillyspec', '.runtime')
|
|
10
|
+
const registeredWorktree = join(runtimeDir, 'worktrees', changeName)
|
|
11
|
+
const unregisteredWorktree = join(runtimeDir, 'worktrees', 'other-change')
|
|
12
|
+
|
|
13
|
+
mkdirSync(registeredWorktree, { recursive: true })
|
|
14
|
+
mkdirSync(unregisteredWorktree, { recursive: true })
|
|
15
|
+
writeFileSync(join(runtimeDir, 'gate-status.json'), JSON.stringify({
|
|
16
|
+
stage: 'execute',
|
|
17
|
+
changes: [changeName],
|
|
18
|
+
updatedAt: new Date().toISOString(),
|
|
19
|
+
}, null, 2))
|
|
20
|
+
writeFileSync(join(registeredWorktree, 'meta.json'), JSON.stringify({
|
|
21
|
+
changeName,
|
|
22
|
+
worktreePath: registeredWorktree,
|
|
23
|
+
mode: 'worktree',
|
|
24
|
+
}, null, 2))
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
assert.equal(
|
|
28
|
+
shouldBlock({ tool: 'Write', filePath: join(registeredWorktree, 'src', 'ok.js'), cwd: root }).blocked,
|
|
29
|
+
false,
|
|
30
|
+
'registered worktree writes should be allowed'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assert.equal(
|
|
34
|
+
shouldBlock({ tool: 'Bash', command: 'npm run build', cwd: registeredWorktree }).blocked,
|
|
35
|
+
false,
|
|
36
|
+
'bash commands from a registered worktree cwd should be allowed'
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
assert.equal(
|
|
40
|
+
shouldBlock({ tool: 'Write', filePath: join(unregisteredWorktree, 'src', 'blocked.js'), cwd: root }).blocked,
|
|
41
|
+
true,
|
|
42
|
+
'unregistered worktree storage writes should be blocked'
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
assert.equal(
|
|
46
|
+
shouldBlock({ tool: 'Write', filePath: join(root, '.sillyspec', 'docs', 'note.md'), cwd: root }).blocked,
|
|
47
|
+
false,
|
|
48
|
+
'ordinary .sillyspec docs should remain writable'
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
rmSync(join(runtimeDir, 'gate-status.json'), { force: true })
|
|
52
|
+
writeFileSync(join(root, '.sillyspec', 'local.yaml'), [
|
|
53
|
+
'worktreeHook:',
|
|
54
|
+
' readonlyCommands:',
|
|
55
|
+
' - custom-read',
|
|
56
|
+
'',
|
|
57
|
+
].join('\n'))
|
|
58
|
+
assert.equal(
|
|
59
|
+
shouldBlock({ tool: 'Bash', command: 'custom-read status', cwd: root }).blocked,
|
|
60
|
+
false,
|
|
61
|
+
'.sillyspec/local.yaml readonlyCommands should extend the bash whitelist'
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
writeFileSync(join(runtimeDir, 'gate-status.json'), JSON.stringify({
|
|
65
|
+
stage: 'quick',
|
|
66
|
+
changes: [changeName],
|
|
67
|
+
updatedAt: new Date().toISOString(),
|
|
68
|
+
}, null, 2))
|
|
69
|
+
assert.equal(
|
|
70
|
+
shouldBlock({ tool: 'Write', filePath: join(root, 'src', 'quick.js'), cwd: root }).blocked,
|
|
71
|
+
false,
|
|
72
|
+
'quick writes should still be allowed in the main workspace'
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
console.log('✅ worktree guard regression checks passed')
|
|
76
|
+
} finally {
|
|
77
|
+
rmSync(root, { recursive: true, force: true })
|
|
78
|
+
}
|