sillyspec 3.28.2 → 3.28.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-auto/SKILL.md +16 -55
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +1 -1
- package/.claude/skills/sillyspec-continue/SKILL.md +8 -38
- package/.claude/skills/sillyspec-execute/SKILL.md +10 -2
- package/.claude/skills/sillyspec-knowledge/SKILL.md +19 -249
- package/.claude/skills/sillyspec-plan/SKILL.md +1 -1
- package/.claude/skills/sillyspec-propose/SKILL.md +6 -77
- package/.claude/skills/sillyspec-resume/SKILL.md +8 -57
- package/.claude/skills/sillyspec-state/SKILL.md +7 -46
- package/.claude/skills/sillyspec-workspace/SKILL.md +14 -156
- package/AGENTS.md +24 -0
- package/INSTRUCTIONS.md +12 -0
- package/package.json +1 -1
- package/src/archive-delta.js +127 -2
- package/src/change-delete.js +2 -1
- package/src/change-list.js +7 -2
- package/src/change-risk-profile.js +77 -6
- package/src/config-cat.js +12 -1
- package/src/constants.js +9 -1
- package/src/design-facts.js +64 -0
- package/src/dispatch/backends/sillyhub-mcp.js +17 -5
- package/src/docs-check.js +153 -27
- package/src/docs-migrate.js +124 -0
- package/src/doctor-diagnostics.js +441 -5
- package/src/foreign-declared.js +53 -2
- package/src/index.js +353 -28
- package/src/module-impact.js +77 -12
- package/src/plan-adopt-waves.js +13 -5
- package/src/progress/change-registry.js +35 -0
- package/src/progress.js +64 -1
- package/src/quick-recommend.js +6 -1
- package/src/quicklog.js +10 -2
- package/src/run/command.js +159 -13
- package/src/run/complete-handlers.js +162 -9
- package/src/run/complete.js +104 -5
- package/src/run/gates.js +116 -8
- package/src/run/progress-confirm.js +66 -0
- package/src/run/prompt.js +235 -36
- package/src/run/quick-audit.js +12 -5
- package/src/run/scan-profile.js +20 -2
- package/src/run/shared.js +84 -11
- package/src/run/stage.js +42 -0
- package/src/runtime-hygiene.js +84 -0
- package/src/scan-postcheck.js +5 -1
- package/src/spec-sync.js +63 -8
- package/src/stage-contract.js +83 -3
- package/src/stage-review.js +3 -0
- package/src/stages/archive.js +4 -4
- package/src/stages/brainstorm-auto.js +2 -1
- package/src/stages/brainstorm.js +11 -25
- package/src/stages/doctor.js +41 -515
- package/src/stages/execute.js +10 -14
- package/src/stages/plan-postcheck.js +191 -7
- package/src/stages/plan.js +7 -27
- package/src/stages/quick.js +15 -13
- package/src/stages/verify.js +23 -21
- package/src/sync-noise.js +158 -0
- package/src/sync.js +42 -17
- package/src/task-review.js +225 -1
- package/src/verify-facts-schema.js +141 -0
- package/src/verify-postcheck.js +421 -49
- package/src/verify-probes.js +142 -13
- package/src/workflow.js +6 -0
- package/src/worktree-apply.js +51 -13
- package/src/worktree.js +5 -1
- package/templates/agents-instruction.md +1 -1
- package/.claude/skills/verify-per-user/SKILL.md +0 -6
package/src/run/gates.js
CHANGED
|
@@ -552,7 +552,33 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
552
552
|
// runtimeRoot 进 context(坑 verify-receipt-runtime-split):verify 回执写入方
|
|
553
553
|
// reapVerifyServices 落 resolveRuntimeRoot(platformOpts, specBase),校验器读侧不透传时
|
|
554
554
|
// 平台/漂移模式恒读不到回执 → 证据门退回纯字面匹配(回执机制正是为消灭它而生)
|
|
555
|
-
|
|
555
|
+
//
|
|
556
|
+
// ── verify 收尾前置:facts slot-backfill + verifyStartAt(2026-09-08-ir-verify-facts FR-03)──
|
|
557
|
+
// 执行次序(design Phase 3):backfill(结论/证据/回执槽固化)先行 → runValidators(结论门/
|
|
558
|
+
// 集成证据门读得到固化值与 context.verifyStartAt)→ verify 专属块(test 实测 → tests 段二次
|
|
559
|
+
// 回填 → cannot_verify 硬门)。verifyStartAt = DB execute 行 completed_at(只读;缺省 null →
|
|
560
|
+
// 证据核验走 R-05 design created_at fallback)。
|
|
561
|
+
let verifyStartAtIso = null
|
|
562
|
+
if (stageName === 'verify') {
|
|
563
|
+
try {
|
|
564
|
+
verifyStartAtIso = pm.getStageCompletedAt(cwd, changeName, 'execute')
|
|
565
|
+
} catch { verifyStartAtIso = null }
|
|
566
|
+
try {
|
|
567
|
+
const verifyMdPath = join(specBase, 'changes', changeName, 'verify-result.md')
|
|
568
|
+
if (existsSync(verifyMdPath)) {
|
|
569
|
+
const verifyMd = readFileSync(verifyMdPath, 'utf8')
|
|
570
|
+
const { backfillFactsFromMdAndTests } = await import('../verify-probes.js')
|
|
571
|
+
const { extractVerifyConclusionSlot } = await import('../stage-contract.js')
|
|
572
|
+
backfillFactsFromMdAndTests(join(specBase, 'changes', changeName, 'verify-facts.json'), {
|
|
573
|
+
verifyMd,
|
|
574
|
+
conclusion: extractVerifyConclusionSlot(verifyMd),
|
|
575
|
+
})
|
|
576
|
+
}
|
|
577
|
+
} catch (e) {
|
|
578
|
+
console.warn(`⚠️ facts slot-backfill 失败(fail-soft,不阻断;门禁仍读 md 槽): ${e && e.message ? e.message : e}`)
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
const contractResult = runValidators(stageName, cwd, changeName, { projectName, specRoot: platformOpts?.specRoot, runtimeRoot: resolveRuntimeRoot(platformOpts, specBase), ...(verifyStartAtIso ? { verifyStartAt: verifyStartAtIso } : {}) })
|
|
556
582
|
if (contractResult.errors.length > 0) {
|
|
557
583
|
console.error(`\n❌ 阶段 ${stageName} 校验失败:`)
|
|
558
584
|
for (const err of contractResult.errors) {
|
|
@@ -584,7 +610,9 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
584
610
|
try {
|
|
585
611
|
const { resolveApplyAllowSet } = await import('../worktree-apply.js')
|
|
586
612
|
const { warnFacadeCandidateFiles } = await import('../facade-hint.js')
|
|
587
|
-
|
|
613
|
+
// specBase 显式传(2026-09-08 平台模式修复):changes/ 实体在 specRoot,本地目录常空——
|
|
614
|
+
// 旧硬编码在平台模式 allow 集恒空,facade 候选预检对空集全量误报
|
|
615
|
+
const allowMap = resolveApplyAllowSet(cwd, changeName, { specBase })
|
|
588
616
|
warnFacadeCandidateFiles({ cwd, changeName, allowSet: allowMap.get('main') })
|
|
589
617
|
} catch { /* 预检失败不阻断 plan 完成 */ }
|
|
590
618
|
}
|
|
@@ -598,6 +626,21 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
598
626
|
console.log(`\n⏳ Verify 测试对账:CLI 亲自执行 local.yaml 的 commands.test(同步,耗时可能较长,请等待…)`)
|
|
599
627
|
const testCheck = runVerifyTestCheck({ cwd, specBase, changeName, ctx })
|
|
600
628
|
printVerifyTestCheck(testCheck)
|
|
629
|
+
// tests 段二次回填(2026-09-08-ir-verify-facts FR-03 次序:实测在 runValidators 之后,
|
|
630
|
+
// tests 快照此刻才可得;不参与门禁——供 P3d 追溯)
|
|
631
|
+
try {
|
|
632
|
+
const verifyMdPath2 = join(specBase, 'changes', changeName, 'verify-result.md')
|
|
633
|
+
if (existsSync(verifyMdPath2)) {
|
|
634
|
+
const { backfillFactsFromMdAndTests } = await import('../verify-probes.js')
|
|
635
|
+
const { extractVerifyConclusionSlot } = await import('../stage-contract.js')
|
|
636
|
+
const verifyMd2 = readFileSync(verifyMdPath2, 'utf8')
|
|
637
|
+
backfillFactsFromMdAndTests(join(specBase, 'changes', changeName, 'verify-facts.json'), {
|
|
638
|
+
verifyMd: verifyMd2,
|
|
639
|
+
conclusion: extractVerifyConclusionSlot(verifyMd2),
|
|
640
|
+
testCheckResult: testCheck,
|
|
641
|
+
})
|
|
642
|
+
}
|
|
643
|
+
} catch { /* fail-soft:回填失败不影响门禁 */ }
|
|
601
644
|
if (testCheck.status === 'failed') {
|
|
602
645
|
console.error('\n❌ verify 阶段被阻断:verify-result.md 自报告通过,但 CLI 实测测试失败。')
|
|
603
646
|
// 并行 WIP 归因鉴别(坑 verify-reconcile-foreign-wip):实测跑在主仓共享工作区,并行会话
|
|
@@ -650,6 +693,19 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
650
693
|
console.log(`\n⏳ Verify lint 对账:CLI 亲自执行 local.yaml 的 commands.lint…`)
|
|
651
694
|
}
|
|
652
695
|
printVerifyLintCheck(lintCheck)
|
|
696
|
+
// lint 硬门(2026-09-09 升硬:观察期 14 次 5 败全真阳性,pre-push 本就硬拦——fail-fast 前移;
|
|
697
|
+
// 逃生 SILLYSPEC_VERIFY_LINT_GATE=advisory)
|
|
698
|
+
const { shouldBlockVerifyLint } = await import('../verify-postcheck.js')
|
|
699
|
+
if (shouldBlockVerifyLint(lintCheck)) {
|
|
700
|
+
console.error('\n❌ verify 阶段被阻断:CLI 亲自实测 lint 失败(agent 的 lint 自报告与实测不符时以实测为准)。')
|
|
701
|
+
if (lintCheck.outputTail) {
|
|
702
|
+
const tail = lintCheck.outputTail.split('\n').slice(-8).join('\n')
|
|
703
|
+
console.error(' 输出(末尾):')
|
|
704
|
+
for (const line of tail.split('\n')) console.error(` | ${line}`)
|
|
705
|
+
}
|
|
706
|
+
console.error(' 修复后重跑 --done(进度不丢);确认要跳过实测请设 SILLYSPEC_VERIFY_LINT_GATE=advisory(审计留痕)。')
|
|
707
|
+
return await rollbackCompletionAndReturn(pm, progress, stageData, steps, currentIdx, cwd, changeName, platformOpts)
|
|
708
|
+
}
|
|
653
709
|
// 契约 parity 对账:扫前端 API 调用 vs execute 提取的 provider endpoint artifact。
|
|
654
710
|
// 接线自 contract-matrix pipeline(verifyApiParity 的 CLI 入口)。
|
|
655
711
|
const { runVerifyParityCheck, printVerifyParityCheck } = await import('../verify-postcheck.js')
|
|
@@ -660,12 +716,26 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
660
716
|
const { runVerifyDeletionCheck, printVerifyDeletionCheck } = await import('../verify-postcheck.js')
|
|
661
717
|
const deletionCheck = runVerifyDeletionCheck({ cwd, specBase, changeName })
|
|
662
718
|
printVerifyDeletionCheck(deletionCheck)
|
|
663
|
-
// ── required-evidence 对账(
|
|
664
|
-
// execute Task Review Gate 把 cannot_verify 任务的 evidence 落盘 verify-required-evidence.json
|
|
665
|
-
//
|
|
719
|
+
// ── required-evidence 对账(2026-09-08-ir-verify-facts FR-03:v2 起 cannot_verify 不闭环阻断)──
|
|
720
|
+
// execute Task Review Gate 把 cannot_verify 任务的 evidence 落盘 verify-required-evidence.json。
|
|
721
|
+
// v2 槽优先分类核验(FR-02):blocked = missing 无豁免或 satisfied 核验不过 → 阻断 verify 完成
|
|
722
|
+
// (此前 advisory 只查「提及」——死链不闭环);无槽存量 md 降级 legacy 子串对账(warning 不阻断)。
|
|
666
723
|
const { runVerifyRequiredEvidenceCheck, printVerifyRequiredEvidenceCheck } = await import('../verify-postcheck.js')
|
|
667
|
-
const evidenceCheck = runVerifyRequiredEvidenceCheck({ cwd, specBase, changeName })
|
|
724
|
+
const evidenceCheck = runVerifyRequiredEvidenceCheck({ cwd, specBase, changeName, verifyStartAt: verifyStartAtIso })
|
|
668
725
|
printVerifyRequiredEvidenceCheck(evidenceCheck)
|
|
726
|
+
if (evidenceCheck.status === 'blocked') {
|
|
727
|
+
console.error(`\n❌ verify 阶段被阻断:cannot_verify 证据账未闭环(${evidenceCheck.summary})。`)
|
|
728
|
+
for (const d of (evidenceCheck.detailed || [])) {
|
|
729
|
+
console.error(` - ${d.task} [${d.status}${d.exempt ? '/豁免' : ''}] ${d.reason}`)
|
|
730
|
+
for (const v of (d.verification || [])) {
|
|
731
|
+
if (v && v.reason) console.error(` · ${v.path || '(无路径)'} [${v.pathClass || '?'}] ${v.reason}(filesExist=${v.filesExist} mtimeOk=${v.mtimeOk} diffHit=${v.diffHit})`)
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
console.error(` 修复:在 verify-result.md「## 证据账(cannot_verify 任务)」槽段逐 task 一行——`)
|
|
735
|
+
console.error(` - task-NN: satisfied | verifiedFiles: <精确路径>(CLI 核验:代码类 存在×mtime×diff 交集;日志/文档类豁免 diff)`)
|
|
736
|
+
console.error(` - 确实无法验证 → 填 missing 并加(豁免:<一句话理由>)后缀;部分满足 → partial + 已核验路径`)
|
|
737
|
+
return await rollbackCompletionAndReturn(pm, progress, stageData, steps, currentIdx, cwd, changeName, platformOpts)
|
|
738
|
+
}
|
|
669
739
|
// ── target_files 声明 ↔ 实际改动 对账(task-05 / ir-stage-p3a:②ERROR 阻断 / ③WARNING 放行)──
|
|
670
740
|
// 「计划落空」(task 卡声明没做)此前全盲区:review.json changedFiles 是 agent 手写不能当
|
|
671
741
|
// 事实源,execute 的 scope creep 只有 symbol-impact 试图抓。reconcileTargetFiles 用 git 三源
|
|
@@ -674,13 +744,15 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
674
744
|
// 声明=scope creep)启发式噪音面大(并行 WIP 剔除后仍可能有工具产物),WARNING 放行留审计;
|
|
675
745
|
// skipped/degraded(无 task 卡 / 全无声明 / git 不可用)降级不误红(存量变更零红门禁)。
|
|
676
746
|
// 阻断形态照 runVerifyTestCheck 先例:逐条列 task + path + 修复提示 + rollbackCompletionAndReturn。
|
|
677
|
-
const { reconcileTargetFiles } = await import('../verify-postcheck.js')
|
|
747
|
+
const { reconcileTargetFiles, isStrictChange } = await import('../verify-postcheck.js')
|
|
678
748
|
const reconcileRuntimeRoot = resolveRuntimeRoot(platformOpts, specBase)
|
|
679
749
|
const reconcileCheck = reconcileTargetFiles({
|
|
680
750
|
cwd, specBase, changeName,
|
|
681
751
|
// runtimeRoot 口径与上方 parity 对账同源(B3 apply-pathspec 兜底源在此根下;平台模式下
|
|
682
752
|
// specBase 与 .runtime 分离,不传会读不到兜底清单 → 假降级)
|
|
683
753
|
runtimeRoot: reconcileRuntimeRoot,
|
|
754
|
+
// IR 严格档(2026-09-07-ir-hardening D-003@v1):主仓卡全零声明 → strictViolation → ERROR
|
|
755
|
+
strictMode: isStrictChange({ pm, cwd, changeName }),
|
|
684
756
|
})
|
|
685
757
|
const reconcileEnvelope = buildReconcileTargetFilesEnvelope(reconcileCheck)
|
|
686
758
|
const reconcileBlocked = printReconcileTargetFilesCheck(reconcileCheck, reconcileEnvelope)
|
|
@@ -705,6 +777,9 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
705
777
|
// 的锚点产物实际都在 changeDir,此参为统一传参签名对齐预留,口径一处定义不二算
|
|
706
778
|
cwd, specBase, changeName,
|
|
707
779
|
runtimeRoot: reconcileRuntimeRoot,
|
|
780
|
+
// IR 严格档(2026-09-07-ir-hardening D-002@v1):created_at ≥ IR_STRICT_SINCE 的变更
|
|
781
|
+
// 探针子节全缺 = ERROR(存量 skip 语义零变化);fail-open(读不到 → false 落豁免)
|
|
782
|
+
strictMode: isStrictChange({ pm, cwd, changeName }),
|
|
708
783
|
})
|
|
709
784
|
const probeEnvelope = buildProbeConsistencyEnvelope(probeCheck)
|
|
710
785
|
const probeBlocked = printProbeConsistencyCheck(probeCheck, probeEnvelope)
|
|
@@ -716,6 +791,24 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
716
791
|
if (probeBlocked) {
|
|
717
792
|
return await rollbackCompletionAndReturn(pm, progress, stageData, steps, currentIdx, cwd, changeName, platformOpts)
|
|
718
793
|
}
|
|
794
|
+
// ── 行号漂移自动重锚(2026-09-09 §7-6:quick --done 已接,verify/archive 收尾补接)──
|
|
795
|
+
// 本变更 diff 中的 .md 文档经 autoReanchorDocRefs 定点重锚(fixable 唯一/优选命中才改 +
|
|
796
|
+
// 同口径回执),消灭「src 改动平移行号 → 下次 docs gate 拦」的人工往返。挂 verify 收尾即
|
|
797
|
+
// 覆盖 archive 面(漂移源是 src 改动,archive 的文档同步步不产生新 src 平移)。fail-open。
|
|
798
|
+
try {
|
|
799
|
+
const { resolveVerifyChangedFiles } = await import('../verify-postcheck.js')
|
|
800
|
+
const mdChangedVa = (resolveVerifyChangedFiles(cwd, changeName, null, { includeWorkingTree: true, specBase }) || [])
|
|
801
|
+
.filter(f => f.endsWith('.md') && !f.startsWith('.sillyspec/changes/'))
|
|
802
|
+
if (mdChangedVa.length > 0) {
|
|
803
|
+
const { autoReanchorDocRefs, readDocsCheckConfig } = await import('../docs-check.js')
|
|
804
|
+
let fixCfgVa = {}
|
|
805
|
+
try { fixCfgVa = readDocsCheckConfig(cwd) || {} } catch { fixCfgVa = {} }
|
|
806
|
+
const rVa = autoReanchorDocRefs(cwd, mdChangedVa, fixCfgVa)
|
|
807
|
+
if (rVa.applied > 0) {
|
|
808
|
+
console.log(`🔧 文档行号漂移自动重锚(${stageName} 收尾):${rVa.applied} 处已改写(${rVa.invalidBefore} → ${rVa.invalidAfter};剩余 ${rVa.remaining} 处需人工 sillyspec docs check)`)
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
} catch { /* 自动重锚失败不影响收尾(docs gate 兜底) */ }
|
|
719
812
|
// ── module-impact 死信探针(blocking,债单 D-1/D-5):更新结果表 pending/待办行 → 阻断 verify ──
|
|
720
813
|
// 与 archive 移动前校验(extractPendingDocSyncRows)同一口径,把死信号从 archive 提前到 verify:
|
|
721
814
|
// agent 在 verify 阶段就须完成文档同步并回填 done/skipped,而非拖到归档被拦(修复 perf-remediation
|
|
@@ -1357,6 +1450,14 @@ export function printReconcileTargetFilesCheck(r, envelope = buildReconcileTarge
|
|
|
1357
1450
|
console.warn(` 对账口径 actual=${(r.sources || []).join(' + ') || 'n/a'}(③类误报先核对 sources 与并行会话剔除提示)。`)
|
|
1358
1451
|
return false
|
|
1359
1452
|
}
|
|
1453
|
+
// IR 严格档(2026-09-07-ir-hardening D-003):strictViolation → ERROR 阻断(与②类同处置)
|
|
1454
|
+
if (r.status === 'skipped' && r.strictViolation) {
|
|
1455
|
+
console.error(`
|
|
1456
|
+
❌ target_files 对账阻断:${r.skipReason}`)
|
|
1457
|
+
console.error(` ${r.strictViolation.message}`)
|
|
1458
|
+
console.error(` 信封 code: ${r.strictViolation.code}`)
|
|
1459
|
+
return true
|
|
1460
|
+
}
|
|
1360
1461
|
// 降级(skipped/degraded):WARNING 放行,skipReason 一句话(存量卡/git 不可用,不误红)
|
|
1361
1462
|
if (r.status === 'skipped' || r.status === 'degraded') {
|
|
1362
1463
|
console.warn(`\n⚠️ target_files 对账${r.status === 'degraded' ? '降级' : '跳过'}(不阻断):${r.skipReason}`)
|
|
@@ -1385,6 +1486,12 @@ export function printReconcileTargetFilesCheck(r, envelope = buildReconcileTarge
|
|
|
1385
1486
|
export function buildProbeConsistencyEnvelope(r) {
|
|
1386
1487
|
const blocked = r.status === 'mismatch' && r.severity === 'error'
|
|
1387
1488
|
const drifted = r.status === 'mismatch' && !blocked
|
|
1489
|
+
// IR 严格档独立 code(2026-09-07-ir-hardening D-002):首条 mismatch 携带
|
|
1490
|
+
// probe_prefill_missing_strict 时路由专用 code(平台/上游按 code 分支可区分
|
|
1491
|
+
// 「篡改预填段」与「从未生成预填段」两类 ERROR)
|
|
1492
|
+
const strictMissing = blocked
|
|
1493
|
+
&& Array.isArray(r.mismatches) && r.mismatches.length > 0
|
|
1494
|
+
&& r.mismatches[0] && r.mismatches[0].code === 'probe_prefill_missing_strict'
|
|
1388
1495
|
const supportedFixes = []
|
|
1389
1496
|
if (blocked) {
|
|
1390
1497
|
supportedFixes.push('如实重生成:跑 `sillyspec verify-probes --change <变更名> --init` 重新落盘机械预填段,再基于新预填段如实补写正文结论(删改预填段过门是 Step7 防篡改纪律红线)')
|
|
@@ -1396,7 +1503,8 @@ export function buildProbeConsistencyEnvelope(r) {
|
|
|
1396
1503
|
}
|
|
1397
1504
|
return {
|
|
1398
1505
|
// code 机器路由键(task-02 JSDoc):四状态→四 code,供平台/上游按 code 分支
|
|
1399
|
-
code:
|
|
1506
|
+
code: strictMissing ? 'probe_prefill_missing_strict'
|
|
1507
|
+
: blocked ? 'probe_consistency_mismatch'
|
|
1400
1508
|
: drifted ? 'probe_consistency_drift'
|
|
1401
1509
|
: (r.status === 'ok' ? 'probe_consistency_ok' : 'probe_consistency_skipped'),
|
|
1402
1510
|
name: 'probe_consistency',
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* progressConfirm — 主流程 Step1「进度确认」的 noAI 动作(brainstorm / execute / verify)
|
|
3
|
+
* (2026-09-07 noAI 主流程首批;机制先例:scan 系 noAI 步 + planPostcheck,见 run/stage.js noAI 分支)
|
|
4
|
+
*
|
|
5
|
+
* noAI 化依据(step1 职责在历次加固后已全部机械化):
|
|
6
|
+
* - 阶段路由:`run <stage>` 显式调用即写 currentStage(run/stage.js D-003@v1),
|
|
7
|
+
* 阶段顺序违规由 checkTransition 拦截——原 prompt 的「阶段不符则停止」检查已残留化
|
|
8
|
+
* ({PROGRESS_SNAPSHOT} 注入文案本就写着「CLI 已路由到本阶段」);
|
|
9
|
+
* - 进度摘要:快照三行(变更/阶段/步骤位置)由 CLI 注入,agent 的「输出当前进度摘要」
|
|
10
|
+
* 只是把注入内容复述一遍再 --done——整轮往返零判断增量;
|
|
11
|
+
* - brainstorm 变更名检查:自动名在创建时 CLI 已打印 rename 提示(run/command.js),
|
|
12
|
+
* 此处机械复检一次模式命中;命中只打印 ⚠️ 建议(noAI 步的 console 输出仍在 CLI 工具
|
|
13
|
+
* 结果里,agent 可见、可在后续步骤与用户交互改名)——不 throw、不阻塞推进。
|
|
14
|
+
* - execute 执行范围:$ARGUMENTS 是会话层信息,CLI 不掺入;本步只补 tasks 勾选计数
|
|
15
|
+
* (readPlanCheckboxStatus 既有机器事实),范围以用户在会话中给出的为准。
|
|
16
|
+
* - verify 测试提示:原 prompt 首段的「CLI 在 --done 统一跑测试」要点改为 console 提示。
|
|
17
|
+
*
|
|
18
|
+
* 输出纪律:只 console 打印(noAI 步不写 step output,与 scan 系动作一致);
|
|
19
|
+
* 纯确认步无失败语义,不 throw。
|
|
20
|
+
*/
|
|
21
|
+
import { join } from 'node:path'
|
|
22
|
+
|
|
23
|
+
/** brainstorm 自动生成变更名的模式(run/command.js:1083 `${date}-new-change-${hex}`) */
|
|
24
|
+
const AUTO_CHANGE_NAME_RE = /^\d{4}-\d{2}-\d{2}-new-change-[a-f0-9]+$/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 执行「进度确认」noAI 动作:打印进度快照 + 阶段专属机械提示。
|
|
28
|
+
*
|
|
29
|
+
* @param {object} opts
|
|
30
|
+
* @param {string} opts.stageName - brainstorm / execute / verify
|
|
31
|
+
* @param {string} opts.cwd
|
|
32
|
+
* @param {object} opts.stageData - progress.stages[stageName](steps 数组)
|
|
33
|
+
* @param {string|null} opts.changeName
|
|
34
|
+
* @param {object|null} [opts.pm] - ProgressManager(execute 档 tasks 勾选计数用;缺省跳过该段)
|
|
35
|
+
*/
|
|
36
|
+
export function executeProgressConfirm({ stageName, cwd, stageData, changeName, pm = null }) {
|
|
37
|
+
const steps = Array.isArray(stageData?.steps) ? stageData.steps : []
|
|
38
|
+
const done = steps.filter(s => s.status === 'completed').length
|
|
39
|
+
console.log('📊 进度快照(CLI 注入,无需跑 progress show):')
|
|
40
|
+
console.log(` - 变更:${changeName || '(未知)'}`)
|
|
41
|
+
console.log(` - 阶段:${stageName}(CLI 已路由到本阶段)`)
|
|
42
|
+
console.log(` - 步骤:${done}/${steps.length} 已完成;本步已由 CLI 自动确认`)
|
|
43
|
+
|
|
44
|
+
if (stageName === 'brainstorm' && changeName && AUTO_CHANGE_NAME_RE.test(changeName)) {
|
|
45
|
+
console.log('')
|
|
46
|
+
console.log(`⚠️ 变更名「${changeName}」疑似自动生成——建议与用户确认语义化名称后执行:`)
|
|
47
|
+
console.log(` sillyspec change-rename ${changeName} <新名称>(勿用 mv,会漏改进度库引用)`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (stageName === 'execute' && pm && changeName) {
|
|
51
|
+
try {
|
|
52
|
+
const changeDir = join(pm._getSpecDir(cwd), 'changes', changeName)
|
|
53
|
+
const plan = pm.readPlanCheckboxStatus(changeDir)
|
|
54
|
+
if (plan && plan.total > 0) {
|
|
55
|
+
console.log(` - 任务勾选:tasks ${plan.checked}/${plan.total}(执行范围以用户会话指定为准,未指定则全部 Wave)`)
|
|
56
|
+
}
|
|
57
|
+
} catch { /* 勾选计数 fail-soft:plan.md 缺失/解析失败不阻塞确认步 */ }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (stageName === 'verify') {
|
|
61
|
+
console.log('')
|
|
62
|
+
console.log('💡 `run verify` 只下发指令不跑测试——全量测试由 CLI 在最后 --done 统一执行')
|
|
63
|
+
console.log(' (local.yaml 的 commands.test,同步对账可能耗时较长);后续「运行测试和质量扫描」')
|
|
64
|
+
console.log(' 步骤无需手动跑全量,只做 lint/静态检查 + 可选快速冒烟。')
|
|
65
|
+
}
|
|
66
|
+
}
|