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,175 +1,175 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P0 补丁验证 — 4 类测试
|
|
3
|
-
*
|
|
4
|
-
* 1. 平台 scan prompt 不含正向写入 .sillyspec/ 指令
|
|
5
|
-
* 2. 安全说明文字不被 prompt 自检误杀
|
|
6
|
-
* 3. 平台模式不执行 git add {SPEC_ROOT}
|
|
7
|
-
* 4. source_root 污染检查覆盖所有子目录/文件
|
|
8
|
-
* 5. run.js 占位符替换补齐(平台+本地)
|
|
9
|
-
*
|
|
10
|
-
* 跑法: node test/platform-scan-p0.test.mjs
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { join, basename } from 'path'
|
|
14
|
-
import { existsSync, mkdirSync, writeFileSync, rmSync, readdirSync } from 'fs'
|
|
15
|
-
import { execSync } from 'child_process'
|
|
16
|
-
import { readFile } from 'fs/promises'
|
|
17
|
-
import { fileURLToPath } from 'url'
|
|
18
|
-
|
|
19
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
20
|
-
const passed = []
|
|
21
|
-
const failed = []
|
|
22
|
-
|
|
23
|
-
function assert(label, condition, detail) {
|
|
24
|
-
if (condition) {
|
|
25
|
-
passed.push(label)
|
|
26
|
-
} else {
|
|
27
|
-
failed.push({ label, detail })
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ── 测试 1:scan.js 模板不含裸 .sillyspec 输出路径 ──
|
|
32
|
-
{
|
|
33
|
-
const { definition } = await import('../src/stages/scan.js')
|
|
34
|
-
const prompts = definition.steps.map(s => s.prompt).join('\n')
|
|
35
|
-
|
|
36
|
-
// 所有 .sillyspec 出现都应该是「禁止说明」,不是写入指令
|
|
37
|
-
const writePatterns = [
|
|
38
|
-
/write.*\.sillyspec\/docs/i,
|
|
39
|
-
/save.*\.sillyspec\/docs/i,
|
|
40
|
-
/create.*\.sillyspec\/docs/i,
|
|
41
|
-
/mkdir.*\.sillyspec\/docs/i,
|
|
42
|
-
]
|
|
43
|
-
for (const p of writePatterns) {
|
|
44
|
-
assert(`scan 模板无写入 .sillyspec/docs: ${p}`, !p.test(prompts),
|
|
45
|
-
p.test(prompts) ? `命中: ${prompts.match(p)[0]}` : '')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 应该使用占位符
|
|
49
|
-
assert('scan 模板使用 {WORKFLOWS_ROOT}', prompts.includes('{WORKFLOWS_ROOT}'))
|
|
50
|
-
assert('scan 模板使用 {SPEC_ROOT}', prompts.includes('{SPEC_ROOT}'))
|
|
51
|
-
assert('scan 模板使用 {DOCS_ROOT}', prompts.includes('{DOCS_ROOT}'))
|
|
52
|
-
|
|
53
|
-
// 平台模式下 git add 应该是条件判断
|
|
54
|
-
assert('scan 模板平台模式跳过 git add', prompts.includes('如果平台模式:跳过 git add'))
|
|
55
|
-
assert('scan 模板非平台模式 git add .sillyspec/', prompts.includes('git add .sillyspec/'))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ── 测试 2:prompt 自检不误杀安全说明 ──
|
|
59
|
-
{
|
|
60
|
-
// 导入 run.js 中的正则
|
|
61
|
-
const writeCtxRe = /(?<!不要|禁止|严禁)(?:save[\s.]+to|write|create|mkdir|git add|写入|保存到|写入到)[^a-zA-Z]*\.sillyspec\/[a-z]/i
|
|
62
|
-
|
|
63
|
-
// 安全说明 — 不应命中
|
|
64
|
-
const safeLines = [
|
|
65
|
-
'严禁写入源码目录或相对路径 `.sillyspec/`',
|
|
66
|
-
'⚠️ 不要写入 .sillyspec/docs',
|
|
67
|
-
'source_root 下存在 .sillyspec/docs 文件',
|
|
68
|
-
'不允许从 cwd 推导 .sillyspec 路径',
|
|
69
|
-
]
|
|
70
|
-
for (const line of safeLines) {
|
|
71
|
-
assert(`安全说明不误杀: "${line.slice(0, 40)}"`, !writeCtxRe.test(line),
|
|
72
|
-
'误杀! 命中了安全说明文字')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 写入指令 — 应该命中
|
|
76
|
-
const badLines = [
|
|
77
|
-
'写入 `.sillyspec/docs/ARCHITECTURE.md`',
|
|
78
|
-
'save to `.sillyspec/docs/ARCHITECTURE.md`',
|
|
79
|
-
'create `.sillyspec/docs/ARCH.md`',
|
|
80
|
-
'git add .sillyspec/docs/',
|
|
81
|
-
'write 到 .sillyspec/docs/',
|
|
82
|
-
]
|
|
83
|
-
for (const line of badLines) {
|
|
84
|
-
assert(`写入指令应命中: "${line.slice(0, 40)}"`, writeCtxRe.test(line),
|
|
85
|
-
'漏杀! 没有捕获写入指令')
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ── 测试 3:safeGit 使用 -c safe.directory(不污染全局 config) ──
|
|
90
|
-
{
|
|
91
|
-
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
92
|
-
|
|
93
|
-
assert('safeGit 不含 --global', !runSrc.includes('git config --global'),
|
|
94
|
-
'发现 --global,会污染容器 git config')
|
|
95
|
-
|
|
96
|
-
assert('safeGit 使用 -c safe.directory', runSrc.includes("safe.directory=${cwd}"),
|
|
97
|
-
'未发现 -c safe.directory per-command 参数')
|
|
98
|
-
|
|
99
|
-
assert('safeGit 使用 -C cwd', runSrc.includes("-C', cwd"),
|
|
100
|
-
'未发现 -C cwd 参数')
|
|
101
|
-
|
|
102
|
-
assert('safeGit 返回 { value, error }', runSrc.includes("return { value, error: "),
|
|
103
|
-
'safeGit 返回值不是 { value, error } 结构')
|
|
104
|
-
|
|
105
|
-
assert('manifest 包含 source_commit_error 字段',
|
|
106
|
-
runSrc.includes("source_commit_error:"), 'manifest 缺少 source_commit_error')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ── 测试 4:postcheck 污染检查覆盖所有子目录 ──
|
|
110
|
-
{
|
|
111
|
-
const postcheckSrc = await readFile(join(__dirname, '..', 'src', 'scan-postcheck.js'), 'utf8')
|
|
112
|
-
|
|
113
|
-
const requiredSubs = ['docs', 'projects', 'workflows', 'knowledge']
|
|
114
|
-
for (const sub of requiredSubs) {
|
|
115
|
-
assert(`postcheck 检查 ${sub} 污染`,
|
|
116
|
-
postcheckSrc.includes(`'${sub}'`) && postcheckSrc.includes("'.sillyspec', sub)"),
|
|
117
|
-
`postcheck 未检查 .sillyspec/${sub}/ 污染`)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
assert('postcheck 检查 manifest.json', postcheckSrc.includes('manifest.json'))
|
|
121
|
-
assert('postcheck 检查 local.yaml', postcheckSrc.includes('local.yaml'))
|
|
122
|
-
assert('污染 severity 使用枚举', postcheckSrc.includes('CHECK_SEVERITY'))
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ── 测试 5:run.js 占位符替换补齐 ──
|
|
126
|
-
{
|
|
127
|
-
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
128
|
-
|
|
129
|
-
// 平台模式块
|
|
130
|
-
const platformMarker = 'promptText.replace(/\\{WORKFLOWS_ROOT\\}'
|
|
131
|
-
assert('平台模式替换 {WORKFLOWS_ROOT}', runSrc.includes('{WORKFLOWS_ROOT}') && runSrc.includes('workflowsRoot'))
|
|
132
|
-
assert('平台模式替换 {KNOWLEDGE_ROOT}', runSrc.includes('{KNOWLEDGE_ROOT}') && runSrc.includes('knowledgeRoot'))
|
|
133
|
-
assert('平台模式替换 {SPEC_ROOT}', runSrc.includes('{SPEC_ROOT}') && runSrc.includes("specSillyspec"))
|
|
134
|
-
|
|
135
|
-
// 非平台模式块
|
|
136
|
-
assert('非平台模式替换 {WORKFLOWS_ROOT}', runSrc.includes('workflowsRoot'))
|
|
137
|
-
assert('非平台模式替换 {KNOWLEDGE_ROOT}', runSrc.includes('knowledgeRoot'))
|
|
138
|
-
assert('非平台模式替换 {SPEC_ROOT}', runSrc.includes('{SPEC_ROOT}'))
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// ── 测试 6:quick step 1 prompt 强制要求 quicklog ──
|
|
142
|
-
{
|
|
1
|
+
/**
|
|
2
|
+
* P0 补丁验证 — 4 类测试
|
|
3
|
+
*
|
|
4
|
+
* 1. 平台 scan prompt 不含正向写入 .sillyspec/ 指令
|
|
5
|
+
* 2. 安全说明文字不被 prompt 自检误杀
|
|
6
|
+
* 3. 平台模式不执行 git add {SPEC_ROOT}
|
|
7
|
+
* 4. source_root 污染检查覆盖所有子目录/文件
|
|
8
|
+
* 5. run.js 占位符替换补齐(平台+本地)
|
|
9
|
+
*
|
|
10
|
+
* 跑法: node test/platform-scan-p0.test.mjs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { join, basename } from 'path'
|
|
14
|
+
import { existsSync, mkdirSync, writeFileSync, rmSync, readdirSync } from 'fs'
|
|
15
|
+
import { execSync } from 'child_process'
|
|
16
|
+
import { readFile } from 'fs/promises'
|
|
17
|
+
import { fileURLToPath } from 'url'
|
|
18
|
+
|
|
19
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
20
|
+
const passed = []
|
|
21
|
+
const failed = []
|
|
22
|
+
|
|
23
|
+
function assert(label, condition, detail) {
|
|
24
|
+
if (condition) {
|
|
25
|
+
passed.push(label)
|
|
26
|
+
} else {
|
|
27
|
+
failed.push({ label, detail })
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── 测试 1:scan.js 模板不含裸 .sillyspec 输出路径 ──
|
|
32
|
+
{
|
|
33
|
+
const { definition } = await import('../src/stages/scan.js')
|
|
34
|
+
const prompts = definition.steps.map(s => s.prompt).join('\n')
|
|
35
|
+
|
|
36
|
+
// 所有 .sillyspec 出现都应该是「禁止说明」,不是写入指令
|
|
37
|
+
const writePatterns = [
|
|
38
|
+
/write.*\.sillyspec\/docs/i,
|
|
39
|
+
/save.*\.sillyspec\/docs/i,
|
|
40
|
+
/create.*\.sillyspec\/docs/i,
|
|
41
|
+
/mkdir.*\.sillyspec\/docs/i,
|
|
42
|
+
]
|
|
43
|
+
for (const p of writePatterns) {
|
|
44
|
+
assert(`scan 模板无写入 .sillyspec/docs: ${p}`, !p.test(prompts),
|
|
45
|
+
p.test(prompts) ? `命中: ${prompts.match(p)[0]}` : '')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 应该使用占位符
|
|
49
|
+
assert('scan 模板使用 {WORKFLOWS_ROOT}', prompts.includes('{WORKFLOWS_ROOT}'))
|
|
50
|
+
assert('scan 模板使用 {SPEC_ROOT}', prompts.includes('{SPEC_ROOT}'))
|
|
51
|
+
assert('scan 模板使用 {DOCS_ROOT}', prompts.includes('{DOCS_ROOT}'))
|
|
52
|
+
|
|
53
|
+
// 平台模式下 git add 应该是条件判断
|
|
54
|
+
assert('scan 模板平台模式跳过 git add', prompts.includes('如果平台模式:跳过 git add'))
|
|
55
|
+
assert('scan 模板非平台模式 git add .sillyspec/', prompts.includes('git add .sillyspec/'))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── 测试 2:prompt 自检不误杀安全说明 ──
|
|
59
|
+
{
|
|
60
|
+
// 导入 run.js 中的正则
|
|
61
|
+
const writeCtxRe = /(?<!不要|禁止|严禁)(?:save[\s.]+to|write|create|mkdir|git add|写入|保存到|写入到)[^a-zA-Z]*\.sillyspec\/[a-z]/i
|
|
62
|
+
|
|
63
|
+
// 安全说明 — 不应命中
|
|
64
|
+
const safeLines = [
|
|
65
|
+
'严禁写入源码目录或相对路径 `.sillyspec/`',
|
|
66
|
+
'⚠️ 不要写入 .sillyspec/docs',
|
|
67
|
+
'source_root 下存在 .sillyspec/docs 文件',
|
|
68
|
+
'不允许从 cwd 推导 .sillyspec 路径',
|
|
69
|
+
]
|
|
70
|
+
for (const line of safeLines) {
|
|
71
|
+
assert(`安全说明不误杀: "${line.slice(0, 40)}"`, !writeCtxRe.test(line),
|
|
72
|
+
'误杀! 命中了安全说明文字')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 写入指令 — 应该命中
|
|
76
|
+
const badLines = [
|
|
77
|
+
'写入 `.sillyspec/docs/ARCHITECTURE.md`',
|
|
78
|
+
'save to `.sillyspec/docs/ARCHITECTURE.md`',
|
|
79
|
+
'create `.sillyspec/docs/ARCH.md`',
|
|
80
|
+
'git add .sillyspec/docs/',
|
|
81
|
+
'write 到 .sillyspec/docs/',
|
|
82
|
+
]
|
|
83
|
+
for (const line of badLines) {
|
|
84
|
+
assert(`写入指令应命中: "${line.slice(0, 40)}"`, writeCtxRe.test(line),
|
|
85
|
+
'漏杀! 没有捕获写入指令')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── 测试 3:safeGit 使用 -c safe.directory(不污染全局 config) ──
|
|
90
|
+
{
|
|
91
|
+
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
92
|
+
|
|
93
|
+
assert('safeGit 不含 --global', !runSrc.includes('git config --global'),
|
|
94
|
+
'发现 --global,会污染容器 git config')
|
|
95
|
+
|
|
96
|
+
assert('safeGit 使用 -c safe.directory', runSrc.includes("safe.directory=${cwd}"),
|
|
97
|
+
'未发现 -c safe.directory per-command 参数')
|
|
98
|
+
|
|
99
|
+
assert('safeGit 使用 -C cwd', runSrc.includes("-C', cwd"),
|
|
100
|
+
'未发现 -C cwd 参数')
|
|
101
|
+
|
|
102
|
+
assert('safeGit 返回 { value, error }', runSrc.includes("return { value, error: "),
|
|
103
|
+
'safeGit 返回值不是 { value, error } 结构')
|
|
104
|
+
|
|
105
|
+
assert('manifest 包含 source_commit_error 字段',
|
|
106
|
+
runSrc.includes("source_commit_error:"), 'manifest 缺少 source_commit_error')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── 测试 4:postcheck 污染检查覆盖所有子目录 ──
|
|
110
|
+
{
|
|
111
|
+
const postcheckSrc = await readFile(join(__dirname, '..', 'src', 'scan-postcheck.js'), 'utf8')
|
|
112
|
+
|
|
113
|
+
const requiredSubs = ['docs', 'projects', 'workflows', 'knowledge']
|
|
114
|
+
for (const sub of requiredSubs) {
|
|
115
|
+
assert(`postcheck 检查 ${sub} 污染`,
|
|
116
|
+
postcheckSrc.includes(`'${sub}'`) && postcheckSrc.includes("'.sillyspec', sub)"),
|
|
117
|
+
`postcheck 未检查 .sillyspec/${sub}/ 污染`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
assert('postcheck 检查 manifest.json', postcheckSrc.includes('manifest.json'))
|
|
121
|
+
assert('postcheck 检查 local.yaml', postcheckSrc.includes('local.yaml'))
|
|
122
|
+
assert('污染 severity 使用枚举', postcheckSrc.includes('CHECK_SEVERITY'))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── 测试 5:run.js 占位符替换补齐 ──
|
|
126
|
+
{
|
|
127
|
+
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
128
|
+
|
|
129
|
+
// 平台模式块
|
|
130
|
+
const platformMarker = 'promptText.replace(/\\{WORKFLOWS_ROOT\\}'
|
|
131
|
+
assert('平台模式替换 {WORKFLOWS_ROOT}', runSrc.includes('{WORKFLOWS_ROOT}') && runSrc.includes('workflowsRoot'))
|
|
132
|
+
assert('平台模式替换 {KNOWLEDGE_ROOT}', runSrc.includes('{KNOWLEDGE_ROOT}') && runSrc.includes('knowledgeRoot'))
|
|
133
|
+
assert('平台模式替换 {SPEC_ROOT}', runSrc.includes('{SPEC_ROOT}') && runSrc.includes("specSillyspec"))
|
|
134
|
+
|
|
135
|
+
// 非平台模式块
|
|
136
|
+
assert('非平台模式替换 {WORKFLOWS_ROOT}', runSrc.includes('workflowsRoot'))
|
|
137
|
+
assert('非平台模式替换 {KNOWLEDGE_ROOT}', runSrc.includes('knowledgeRoot'))
|
|
138
|
+
assert('非平台模式替换 {SPEC_ROOT}', runSrc.includes('{SPEC_ROOT}'))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── 测试 6:quick step 1 prompt 强制要求 quicklog ──
|
|
142
|
+
{
|
|
143
143
|
const { definition } = await import('../src/stages/quick.js')
|
|
144
144
|
const step1Prompt = definition.steps[0].prompt
|
|
145
145
|
const step3Prompt = definition.steps[2].prompt
|
|
146
|
-
|
|
147
|
-
assert('quick step 1 包含 ⛔ 标记', step1Prompt.includes('⛔'))
|
|
148
|
-
assert('quick step 1 包含「不能跳过」', step1Prompt.includes('不能跳过'))
|
|
146
|
+
|
|
147
|
+
assert('quick step 1 包含 ⛔ 标记', step1Prompt.includes('⛔'))
|
|
148
|
+
assert('quick step 1 包含「不能跳过」', step1Prompt.includes('不能跳过'))
|
|
149
149
|
assert('quick step 1 包含 quicklog 未创建 warning', step1Prompt.includes('quicklog 未创建'))
|
|
150
150
|
assert('quick step 1 输出要求 quicklog 第一行', step1Prompt.includes('第一行确认'))
|
|
151
151
|
assert('quick step 3 禁止 git add -A', step3Prompt.includes('禁止使用 `git add -A`'))
|
|
152
152
|
assert('quick step 3 使用 scoped git add', step3Prompt.includes('git add -- <file...>'))
|
|
153
|
-
|
|
154
|
-
// run.js 审计包含 quicklog 检查
|
|
155
|
-
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
156
|
-
assert('quick 审计检查 quicklog 目录存在', runSrc.includes('quicklog 目录不存在'))
|
|
157
|
-
assert('quick 审计检查 quicklog 为空', runSrc.includes('quicklog 目录为空'))
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ── 结果 ──
|
|
161
|
-
console.log(`\n${'='.repeat(50)}`)
|
|
162
|
-
console.log(`✅ 通过: ${passed.length}`)
|
|
163
|
-
console.log(`❌ 失败: ${failed.length}`)
|
|
164
|
-
console.log(`${'='.repeat(50)}`)
|
|
165
|
-
|
|
166
|
-
if (failed.length > 0) {
|
|
167
|
-
console.log('\n失败详情:')
|
|
168
|
-
for (const f of failed) {
|
|
169
|
-
console.log(` ❌ ${f.label}`)
|
|
170
|
-
if (f.detail) console.log(` ${f.detail}`)
|
|
171
|
-
}
|
|
172
|
-
throw new Error("test failed")
|
|
173
|
-
} else {
|
|
174
|
-
console.log('\n🎉 全部 P0 测试通过!')
|
|
175
|
-
}
|
|
153
|
+
|
|
154
|
+
// run.js 审计包含 quicklog 检查
|
|
155
|
+
const runSrc = await readFile(join(__dirname, '..', 'src', 'run.js'), 'utf8')
|
|
156
|
+
assert('quick 审计检查 quicklog 目录存在', runSrc.includes('quicklog 目录不存在'))
|
|
157
|
+
assert('quick 审计检查 quicklog 为空', runSrc.includes('quicklog 目录为空'))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── 结果 ──
|
|
161
|
+
console.log(`\n${'='.repeat(50)}`)
|
|
162
|
+
console.log(`✅ 通过: ${passed.length}`)
|
|
163
|
+
console.log(`❌ 失败: ${failed.length}`)
|
|
164
|
+
console.log(`${'='.repeat(50)}`)
|
|
165
|
+
|
|
166
|
+
if (failed.length > 0) {
|
|
167
|
+
console.log('\n失败详情:')
|
|
168
|
+
for (const f of failed) {
|
|
169
|
+
console.log(` ❌ ${f.label}`)
|
|
170
|
+
if (f.detail) console.log(` ${f.detail}`)
|
|
171
|
+
}
|
|
172
|
+
throw new Error("test failed")
|
|
173
|
+
} else {
|
|
174
|
+
console.log('\n🎉 全部 P0 测试通过!')
|
|
175
|
+
}
|