sillyspec 3.31.0 → 3.32.0
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-auto/SKILL.md +1 -1
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +2 -2
- package/.claude/skills/sillyspec-commit/SKILL.md +1 -1
- package/.claude/skills/sillyspec-flow/SKILL.md +10 -6
- package/.claude/skills/sillyspec-quick/SKILL.md +105 -7
- package/.zcodeignore +66 -0
- package/AGENTS.md +16 -16
- package/assets/command-cards/flow.md +9 -3
- package/assets/command-cards/run-quick.md +4 -1
- package/package.json +2 -2
- package/src/agent-session-log.js +27 -5
- package/src/config-schema.js +21 -0
- package/src/datetime.js +51 -0
- package/src/db.js +10 -3
- package/src/decision-distill.js +21 -12
- package/src/design-facts.js +46 -6
- package/src/flow-draft.js +468 -95
- package/src/flow-parity.js +62 -4
- package/src/flow-review.js +136 -6
- package/src/flow.js +729 -125
- package/src/foreign-declared.js +71 -3
- package/src/fr-index.js +148 -162
- package/src/git-helper.js +16 -3
- package/src/hooks/worktree-guard.js +16 -5
- package/src/hunk-attribution.js +28 -5
- package/src/index.js +186 -19
- package/src/knowledge-classify.js +3 -1
- package/src/knowledge-digest.js +55 -26
- package/src/knowledge-match.js +135 -7
- package/src/knowledge-stats.js +66 -4
- package/src/knowledge-vector.js +160 -0
- package/src/machine-interface.js +90 -2
- package/src/module-impact.js +22 -1
- package/src/modules.js +9 -0
- package/src/progress/change-registry.js +20 -0
- package/src/progress/stage-machine.js +4 -7
- package/src/progress.js +8 -1
- package/src/quicklog.js +20 -0
- package/src/redomain.js +23 -7
- package/src/route-hindsight.js +276 -0
- package/src/run/archive-distill.js +3 -1
- package/src/run/command.js +65 -12
- package/src/run/complete-handlers.js +219 -5
- package/src/run/complete.js +77 -11
- package/src/run/gate-snapshot.js +15 -0
- package/src/run/gates.js +60 -4
- package/src/run/prompt.js +159 -31
- package/src/run/quick-audit.js +66 -7
- package/src/run/shared.js +6 -11
- package/src/run/stage.js +5 -1
- package/src/run/verify-quality-scan.js +84 -0
- package/src/scan-facts.js +2 -1
- package/src/scope-audit.js +9 -2
- package/src/sentinel-assertions.js +67 -16
- package/src/stage-contract-engine.js +4 -1
- package/src/stage-contract-spec.js +103 -4
- package/src/stage-contract.js +55 -7
- package/src/stages/brainstorm.js +27 -14
- package/src/stages/knowledge.js +4 -3
- package/src/stages/plan-postcheck.js +98 -3
- package/src/stages/plan.js +22 -2
- package/src/stages/quick.js +1 -1
- package/src/stages/verify.js +2 -1
- package/src/task-review.js +1 -1
- package/src/task-tick.js +121 -0
- package/src/taskcard-frontmatter.js +31 -0
- package/src/ui-visual.js +43 -8
- package/src/verify-postcheck.js +509 -37
- package/src/verify-probes.js +216 -5
- package/src/watcher.js +1067 -1031
- package/src/worktree-apply.js +9 -1
- package/src/worktree.js +21 -6
- package/templates/agents-instruction.md +15 -15
- package/templates/prompts/taskcard-rules.md +1 -0
package/src/decision-distill.js
CHANGED
|
@@ -195,20 +195,29 @@ export function parseModulePathsSubset(content) {
|
|
|
195
195
|
let cur = null
|
|
196
196
|
let key = null
|
|
197
197
|
for (const line of content.replace(/\r\n/g, '\n').split('\n')) {
|
|
198
|
+
// 空行/注释行:保状态(列表块内允许空行与注释穿插)
|
|
199
|
+
if (line.trim() === '' || line.trim().startsWith('#')) continue
|
|
198
200
|
const mm = line.match(/^ ([a-zA-Z0-9_-]+):$/)
|
|
199
201
|
if (mm) { cur = mm[1]; modules[cur] = { paths: [] }; key = null; continue }
|
|
200
202
|
if (!cur) continue
|
|
203
|
+
const item = line.match(/^ - (.+)$/)
|
|
204
|
+
if (item && key) { modules[cur][key].push(item[1].trim().replace(/^['"]|['"]$/g, '')); continue }
|
|
201
205
|
const inline = line.match(/^ (paths|core_files): \[(.*)\]$/)
|
|
202
206
|
if (inline) {
|
|
203
207
|
modules[cur][inline[1]] = inline[2].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, '')).filter(Boolean)
|
|
204
208
|
key = null; continue
|
|
205
209
|
}
|
|
206
|
-
const block = line.match(/^ (paths|core_files)
|
|
210
|
+
const block = line.match(/^ (paths|core_files):\s*$/)
|
|
207
211
|
if (block) { key = block[1]; modules[cur][key] = modules[cur][key] || []; continue }
|
|
208
212
|
const doc = line.match(/^ doc: (.+)$/)
|
|
209
213
|
if (doc) { modules[cur].doc = doc[1].trim().replace(/^['"]|['"]$/g, ''); key = null; continue }
|
|
210
|
-
|
|
211
|
-
|
|
214
|
+
// 结构守卫(坑 module-map-list-leak,2026-10-06-wallclock-entry 实测发现):list 收集只在
|
|
215
|
+
// 「6 缩进项行 / 空行 / 注释」上存活,其余任何行——字段头(字段名开放集不枚举)、顶层段
|
|
216
|
+
// (span_risk:/blast:)、异缩进项(2 缩进 "- prefixes:")——终结收集。此前 paths: 块后的
|
|
217
|
+
// tags/aliases/entrypoints/depends_on 字段项与顶层 blast prefixes 全部漏进 paths(8 项目
|
|
218
|
+
// map 500 实声明 vs 1375 泄漏项;散文斜杠词 git/DB/JSON 前缀命中 tag 'git' 误路由触达域、
|
|
219
|
+
// bin 模块双重归属 src/db.js)。
|
|
220
|
+
key = null
|
|
212
221
|
}
|
|
213
222
|
return modules
|
|
214
223
|
}
|
|
@@ -518,17 +527,17 @@ export function distillIntoKnowledge(changeDir, knowledgeRoot, headHash, moduleI
|
|
|
518
527
|
const waitParts = []
|
|
519
528
|
const distillable = []
|
|
520
529
|
for (const e of selected) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
530
|
+
// 标题必填(2026-09-29-decision-route-vocab:裸号条目检索面不可见——路由词形派生与回显
|
|
531
|
+
// 排序都吃标题,缺标题=知识入库即隐身);rejected 缺否决理由/复潮条件 → 不写盘(其余照常)
|
|
532
|
+
const missing = []
|
|
533
|
+
if (!e.title) missing.push('标题(## D-xxx@vN 后接短标题——检索词形来源,裸号条目入库即隐身)')
|
|
534
|
+
if (e.selected === 'rejected' && !e.rejectReason) missing.push('否决理由')
|
|
535
|
+
if (e.selected === 'rejected' && !e.revisitWhen) missing.push('复潮条件')
|
|
536
|
+
if (missing.length > 0) waitParts.push(`${e.id} 缺${missing.join('、')}`)
|
|
537
|
+
else distillable.push(e)
|
|
529
538
|
}
|
|
530
539
|
const needsWait = waitParts.length > 0
|
|
531
|
-
? `${waitParts.join(';')}
|
|
540
|
+
? `${waitParts.join(';')}——条目必填字段缺失,补齐后重跑提炼`
|
|
532
541
|
: null
|
|
533
542
|
if (distillable.length === 0) return { written: [], skipped: null, needsWait }
|
|
534
543
|
|
package/src/design-facts.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* decision_module_check_skipped(skipped 原因字符串,接线层包 code)。
|
|
23
23
|
*/
|
|
24
24
|
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
25
|
-
import { join } from 'node:path'
|
|
25
|
+
import { join, relative } from 'node:path'
|
|
26
26
|
import { parseDecisions } from './decision-distill.js'
|
|
27
27
|
import { parseFileChangeListDetailed } from './change-list.js'
|
|
28
28
|
import { parseDesignCoverageByRepo, parseRepoRegistry } from './stages/plan-postcheck.js'
|
|
@@ -295,7 +295,9 @@ export function generateDesignSkeleton({ changeName, decisionsText, author, now
|
|
|
295
295
|
// P2-e provenance 戳(noai-ir-roadmap §5):CLI 骨架出品的可审计标记——铁律 8 收窄为
|
|
296
296
|
//「骨架优先,仅手写补文档才手填元数据」的依据(validateMetadata 未来可据此只认 CLI 戳)
|
|
297
297
|
lines.push(`generated_by: sillyspec-design-init`)
|
|
298
|
-
|
|
298
|
+
// scale 不预填(2026-09-29-brainstorm-exit-thin-default):此前预填 large 是静默厚默认——
|
|
299
|
+
// 不主动改就是五阶段;现由 brainstorm Step 8 规模评估按复杂度/上下文轴落值,拿不准默认 small
|
|
300
|
+
lines.push('scale: "" # TODO:Step 8 规模评估落值——单上下文可吞吐=small(flow start 收编);需 Wave 编排/上下文分片/多阶段治理=large(run plan);拿不准 small')
|
|
299
301
|
lines.push('---')
|
|
300
302
|
lines.push('')
|
|
301
303
|
lines.push(`# 设计文档(Design)— ${change}`)
|
|
@@ -339,7 +341,8 @@ export function generateDesignSkeleton({ changeName, decisionsText, author, now
|
|
|
339
341
|
|
|
340
342
|
lines.push('## 接口定义')
|
|
341
343
|
lines.push('')
|
|
342
|
-
lines.push('<!-- TODO
|
|
344
|
+
lines.push('<!-- TODO(代码类任务必填):方法签名、数据结构。本变更无接口改动时,把下面这行声明粘贴到本节正文(探针矩阵认该声明行,同义式「无接口变更/不涉及接口/零端点」亦可;留在本注释内不生效——2026-10-06-verify-friction-fix): -->')
|
|
345
|
+
lines.push('<!-- 本变更接口面:0 端点(无接口变更) -->')
|
|
343
346
|
lines.push('')
|
|
344
347
|
|
|
345
348
|
lines.push('## 生命周期契约表')
|
|
@@ -415,14 +418,47 @@ function stripPathPlaceholders(p) {
|
|
|
415
418
|
* @param {{ changeDir: string, cwd: string }} opts
|
|
416
419
|
* @returns {{ ok: boolean, errors: Array<{path, message}>, warnings: string[] }}
|
|
417
420
|
*/
|
|
421
|
+
/**
|
|
422
|
+
* 相近既有路径建议(2026-10-07-flow-friction-batch3 task-02):design 清单幻觉路径的
|
|
423
|
+
* basename did-you-mean。受控 BFS:跳过 node_modules/.git/dist/build/venv 类重目录与
|
|
424
|
+
* 隐藏目录,扫描量上限 8000 文件(超限即止——建议是锦上添花不是承诺);只收 basename
|
|
425
|
+
* 全等命中,至多 3 条按路径长度升序(最短=最像根级缺前缀的正确答案)。纯读无副作用。
|
|
426
|
+
* @param {string} root 仓根(或跨仓根)
|
|
427
|
+
* @param {string} normalized 失效路径(已剥占位符)
|
|
428
|
+
* @returns {string[]} 仓根相对 posix 路径建议(≤3 条,零命中返回 [])
|
|
429
|
+
*/
|
|
430
|
+
function suggestClosePaths(root, normalized) {
|
|
431
|
+
const base = normalized.split('/').pop().toLowerCase()
|
|
432
|
+
if (!base || base.length < 3) return []
|
|
433
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'out', 'venv', '.venv', '__pycache__', '.runtime', 'coverage', 'target', '.sillyspec'])
|
|
434
|
+
const hits = []
|
|
435
|
+
let scanned = 0
|
|
436
|
+
const queue = [root]
|
|
437
|
+
while (queue.length > 0 && hits.length < 3 && scanned < 8000) {
|
|
438
|
+
const dir = queue.shift()
|
|
439
|
+
let entries
|
|
440
|
+
try { entries = readdirSync(dir, { withFileTypes: true }) } catch { continue }
|
|
441
|
+
for (const e of entries) {
|
|
442
|
+
if (e.name.startsWith('.') || SKIP_DIRS.has(e.name)) continue
|
|
443
|
+
const abs = join(dir, e.name)
|
|
444
|
+
if (e.isDirectory()) { queue.push(abs); continue }
|
|
445
|
+
scanned++
|
|
446
|
+
if (e.name.toLowerCase() === base) {
|
|
447
|
+
hits.push(relative(root, abs).split('\\').join('/'))
|
|
448
|
+
if (hits.length >= 3) break
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return hits.sort((a, b) => a.length - b.length)
|
|
453
|
+
}
|
|
454
|
+
|
|
418
455
|
export function validateDesignFileList({ changeDir, cwd } = {}) {
|
|
419
456
|
const errors = []
|
|
420
457
|
const warnings = []
|
|
421
458
|
try {
|
|
422
459
|
if (!changeDir || !cwd) {
|
|
423
460
|
return { ok: true, errors, warnings: ['design 清单核验跳过:缺少 changeDir/cwd'] }
|
|
424
|
-
}
|
|
425
|
-
const designPath = join(changeDir, 'design.md')
|
|
461
|
+
} const designPath = join(changeDir, 'design.md')
|
|
426
462
|
if (!existsSync(designPath)) {
|
|
427
463
|
return { ok: true, errors, warnings: ['design 清单核验跳过:design.md 不存在'] }
|
|
428
464
|
}
|
|
@@ -440,9 +476,13 @@ export function validateDesignFileList({ changeDir, cwd } = {}) {
|
|
|
440
476
|
const normalized = stripPathPlaceholders(rawPath)
|
|
441
477
|
if (!normalized || normalized === '.') continue
|
|
442
478
|
if (!existsSync(join(root, normalized))) {
|
|
479
|
+
// 相近路径指路(2026-10-07-flow-friction-batch3 task-02):幻觉路径多为缺目录前缀
|
|
480
|
+
// (如漏 backend/)或近似书写——basename did-you-mean 把「三轮试错」压成「一眼改对」;
|
|
481
|
+
// 无相近命中不附建议段(不加噪)
|
|
482
|
+
const close = suggestClosePaths(root, normalized)
|
|
443
483
|
errors.push({
|
|
444
484
|
path: rawPath,
|
|
445
|
-
message: `design_file_ref_invalid:文件变更清单条目「${rawPath}」在${repoLabel}(${root})下不存在且无 NEW: 前缀(幻觉路径/书写错误)——修正路径,或计划新建的文件改为 NEW:${rawPath}
|
|
485
|
+
message: `design_file_ref_invalid:文件变更清单条目「${rawPath}」在${repoLabel}(${root})下不存在且无 NEW: 前缀(幻觉路径/书写错误)——修正路径,或计划新建的文件改为 NEW:${rawPath} 前缀${close.length > 0 ? `;相近既有路径:${close.join('、')}` : ''}`,
|
|
446
486
|
})
|
|
447
487
|
}
|
|
448
488
|
}
|