sillyspec 3.28.8 → 3.28.10
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/full.json +1 -0
- package/.claude/skills/sillyspec-execute/SKILL.md +222 -224
- package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
- package/.claude/skills/sillyspec-quick/SKILL.md +118 -117
- package/AGENTS.md +3 -2
- package/README.md +35 -11
- package/SKILL.md +24 -10
- package/SillySpec-/350/203/275/345/212/233/344/272/256/347/202/271/345/205/250/346/231/257-2026-09-14.pptx +0 -0
- package/package.json +1 -1
- package/src/change-list.js +73 -20
- package/src/change-risk-profile.js +20 -0
- package/src/config-schema.js +62 -0
- package/src/contract-matrix.js +84 -5
- package/src/cross-repo-reconcile.js +134 -0
- package/src/db.js +11 -3
- package/src/decision-distill.js +15 -3
- package/src/design-facts.js +89 -20
- package/src/docs-gate.js +105 -6
- package/src/doctor-diagnostics.js +224 -2
- package/src/friction-ledger.js +171 -0
- package/src/hooks/worktree-guard.js +13 -1
- package/src/index.js +206 -18
- package/src/knowledge-classify.js +382 -0
- package/src/knowledge-hits.js +74 -0
- package/src/knowledge-stats.js +180 -0
- package/src/probe7-anchor-check.js +69 -0
- package/src/progress/change-registry.js +183 -8
- package/src/progress/shared.js +3 -2
- package/src/progress.js +100 -8
- package/src/quick-gate-profile.js +251 -0
- package/src/quicklog.js +164 -18
- package/src/review-dispatch.js +2 -1
- package/src/run/command.js +131 -13
- package/src/run/complete-handlers.js +511 -21
- package/src/run/complete.js +123 -23
- package/src/run/concurrent-detect.js +98 -0
- package/src/run/gate-snapshot.js +110 -2
- package/src/run/gates.js +141 -16
- package/src/run/prompt.js +221 -11
- package/src/run/quick-audit.js +111 -13
- package/src/run/shared.js +147 -11
- package/src/run/stage.js +6 -0
- package/src/scan-diff.js +61 -30
- package/src/scan-postcheck.js +74 -0
- package/src/scan-refresh.js +477 -0
- package/src/scan-staleness.js +25 -13
- package/src/scope-audit.js +456 -56
- package/src/stage-contract.js +185 -2
- package/src/stage-review.js +23 -7
- package/src/stages/brainstorm.js +6 -0
- package/src/stages/cmd-existence.js +9 -3
- package/src/stages/execute.js +85 -3
- package/src/stages/knowledge.js +76 -6
- package/src/stages/plan-postcheck.js +32 -5
- package/src/stages/quick.js +1 -1
- package/src/stages/verify.js +1 -0
- package/src/sync-noise.js +170 -6
- package/src/sync.js +141 -9
- package/src/task-review.js +366 -46
- package/src/verify-postcheck.js +212 -55
- package/src/verify-probes.js +727 -16
- package/src/worktree-apply.js +685 -48
- package/src/worktree-deps.js +124 -3
- package/src/worktree.js +391 -15
- package/templates/agents-instruction.md +2 -2
- package/templates/prompts/testcase-design.md +2 -1
- package/templates/prompts/verify-probes.md +4 -1
- package/.patch16-tmp.mjs +0 -169
- package/sa-rename-probe/src/new.js +0 -4
package/src/run/command.js
CHANGED
|
@@ -30,7 +30,7 @@ import { outputStep, collectStageWaitHistory } from './prompt.js'
|
|
|
30
30
|
import { completeStep, skipStep, waitStep, continueStep, synthesizeStepOutput } from './complete.js'
|
|
31
31
|
import { runStage } from './stage.js'
|
|
32
32
|
import { sanitizeDesc } from '../quicklog.js'
|
|
33
|
-
import { ProgressManager } from '../progress.js'
|
|
33
|
+
import { ProgressManager, resolveSessionIdentity } from '../progress.js'
|
|
34
34
|
import { validateChangeExists, checkTransition } from '../stage-contract.js'
|
|
35
35
|
import { READONLY_AUXILIARY_STAGES } from '../constants.js'
|
|
36
36
|
import { stageRegistry, auxiliaryStages } from '../stages/index.js'
|
|
@@ -48,6 +48,7 @@ const VALUE_FLAGS = new Set([
|
|
|
48
48
|
'--req', '--cause', '--solution', '--result', // quick 末步四字段参数(合成 --output,见 outputText 解析段)
|
|
49
49
|
'--ql', // quick --cancel 显式指定 qlId(缺省读会话 guard.json)
|
|
50
50
|
'--base', // scan diff 基线 commit(吃值;只在 run scan --diff 转发路径消费)
|
|
51
|
+
'--session', // 显式会话标识(吃值;2026-09-14-change-ownership-guards task-02 所有权三级解析最高优先级层,启动 claim 消费)
|
|
51
52
|
])
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -329,6 +330,10 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
329
330
|
process.exit(2)
|
|
330
331
|
}
|
|
331
332
|
const fromStepValue = getFlagValue('--from-step')
|
|
333
|
+
// 意图断言(坑 execute-concurrent-done-skips-next-wave 终解,2026-09-08 实证):--done --step
|
|
334
|
+
// <名|序号> 显式声明本次要完成的步骤——CLI 校验与当前待完成步一致才放行。并发 --done 落到
|
|
335
|
+
// 错误 Wave(后到会话用旧摘要完成未实现的下一步)只有显式声明能硬拦(CLI 短进程无法读心)。
|
|
336
|
+
const stepAssertValue = getFlagValue('--step')
|
|
332
337
|
const isConfirm = flags.includes('--confirm')
|
|
333
338
|
const isSkipApproval = flags.includes('--skip-approval')
|
|
334
339
|
const isWait = flags.includes('--wait')
|
|
@@ -622,6 +627,9 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
622
627
|
// 历史写法,语义与「指定变更名」冲突,新用法建议改用 --linked-changes)
|
|
623
628
|
let changeName = null
|
|
624
629
|
let linkedChanges = []
|
|
630
|
+
// 机器自动关联溯源(坑 quick-single-change-auto-link):resolveQuickLinkedChanges 单候选
|
|
631
|
+
// 信号门控命中时标记,guard 落 linkedChangesAuto,--done 归档闸对这类变更不触发轻量归档
|
|
632
|
+
let linkedAuto = []
|
|
625
633
|
const changeValue = getFlagValue('--change')
|
|
626
634
|
if (changeValue !== null) {
|
|
627
635
|
changeName = changeValue
|
|
@@ -692,6 +700,11 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
692
700
|
if (!quickSessionId) {
|
|
693
701
|
quickSessionId = 'quick-' + randomUUID().slice(0, 8)
|
|
694
702
|
quickSidFresh = true
|
|
703
|
+
// 坑 quick-sync-block-filenotes-and-quicklog-mixed-commit 坑1③:新会话 ID 生成即打印
|
|
704
|
+
// 第一行——后续 agent-log push / spec-sync 等 best-effort 网络动作(平台慢时分钟级)
|
|
705
|
+
// 若把命令拖过 exec 超时,调用方仍能从输出头部拿到 sessionId 续用(--status / guard.json
|
|
706
|
+
// 核对),不会误开空壳新会话。
|
|
707
|
+
console.log(`📌 quick 会话已建立: ${quickSessionId}(后续若超时/中断,用 --change ${quickSessionId} 续用)`)
|
|
695
708
|
}
|
|
696
709
|
changeName = quickSessionId
|
|
697
710
|
} else {
|
|
@@ -799,17 +812,29 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
799
812
|
const isAllowDelete = flags.includes('--allow-delete')
|
|
800
813
|
const isForceBaseline = flags.includes('--force-baseline')
|
|
801
814
|
const isForceRescan = flags.includes('--force-rescan')
|
|
815
|
+
// --no-docs(2026-09-14-quick-exit-tiered-gates task-02,no-docs-flag):L2 门禁文档认领的显式
|
|
816
|
+
// 豁免布尔 flag(先例上方同款 includes 解析)——只影响 gate 画像 docClaim(exempt-no-docs)
|
|
817
|
+
// 与 [gate] 落账留痕,不改 status/exit code(D-003 advisory),审计链经 completeStep options 透传。
|
|
818
|
+
const isNoDocs = flags.includes('--no-docs')
|
|
819
|
+
// --skip-apply(2026-09-14-change-ownership-guards task-03,D-002@v1):归档收口门(archive
|
|
820
|
+
// step3 归档移动前 applyWorktree checkOnly 探测未 apply 交付面)的显式跳过布尔 flag——
|
|
821
|
+
// 语义出口在 completeStep → handleArchiveConfirmStep → archiveChangeDirectory(task-02 只
|
|
822
|
+
// 注册白名单透传,本行补 includes 解析进 completeStep options,isNoDocs 同款先例)。
|
|
823
|
+
const isSkipApply = flags.includes('--skip-apply')
|
|
802
824
|
|
|
803
825
|
// F10b(ql-20260818-010):语义别名定向提示。did-you-mean 按编辑距离猜形近 flag,猜中的常是
|
|
804
826
|
// 形近但语义错的(--title → --files,ql-20260818-003 负面③实证)。常见「语义别名」在此登记
|
|
805
827
|
// 定向指引:命中时替代 did-you-mean 打印,引导到真正承载该语义的 flag/机制。
|
|
828
|
+
// 2026-09-14-change-ownership-guards task-02:原 '--session' 条目(quick 会话名提示)随
|
|
829
|
+
// --session 升格为真实 flag(所有权会话标识)而移除——提示只对未知 flag 生效,已知 flag
|
|
830
|
+
// 挂提示是死代码;'--session-id' 是最常见形近拼法,改挂新语义指引(所有权三级标识)。
|
|
806
831
|
const FLAG_SEMANTIC_HINTS = {
|
|
807
832
|
'--title': 'QUICKLOG 条目标题无独立参数——从 --output 的「需求:」字段自动提取(写成一句语义化短标题即可)',
|
|
808
833
|
'--message': '结果摘要用 --output(quick 末步须含 需求:/根因:/方案:/结果: 四字段)',
|
|
809
834
|
'--summary': '结果摘要用 --output(quick 末步须含 需求:/根因:/方案:/结果: 四字段)',
|
|
810
835
|
'--result': '结果摘要用 --output(quick 末步须含 需求:/根因:/方案:/结果: 四字段)',
|
|
811
836
|
'--name': 'quick 会话名由 CLI 自动分配(quick-<hash>),恢复会话用 --change <quick-session-id>;关联变更用 --linked-changes',
|
|
812
|
-
'--session': '
|
|
837
|
+
'--session-id': '会话标识用 --session <id>(所有权三级解析最高优先级层;缺省 env SILLYSPEC_SESSION_ID,再缺省 anon@<host> 机器级降级)',
|
|
813
838
|
'--note': '文件括注用 --file-notes "path::注 || path::注";启动时任务描述用 --input',
|
|
814
839
|
'--notes': '文件括注用 --file-notes "path::注 || path::注"',
|
|
815
840
|
'--desc': '启动时任务描述用 --input;QUICKLOG 标题从 --output「需求:」自动提取',
|
|
@@ -826,12 +851,16 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
826
851
|
'--req', '--cause', '--solution', '--result',
|
|
827
852
|
'--spec-dir', '--spec-root', '--runtime-root', '--workspace-id', '--scan-run-id',
|
|
828
853
|
'--files', '--file-notes', '--allow-new', '--allow-delete', '--force-baseline', '--force-rescan',
|
|
854
|
+
'--no-docs', // L2 门禁文档认领显式豁免(task-02:布尔 flag 不吃值,audit 链 docClaim → exempt-no-docs)
|
|
829
855
|
'--json', '--dir', '--help',
|
|
830
856
|
'--reopen', '--from-step', '--mode',
|
|
831
857
|
'--deep', '--quick', '--standard', // scan profile 三档显式选择(scan-profile.js 从 argv 读;互斥见下方 PROFILE_FLAGS 检测)
|
|
832
858
|
'--adopt-branch', // execute 显式收编既有 sillyspec/<change> 分支为 worktree 工作分支(坑 worktree-user-branch-conflict)
|
|
833
859
|
'--diff', '--base', '--full', '--report', // scan diff(D-001:command.js 只补 flag,裸 token 解析归 index.js 子命令拦截)
|
|
834
860
|
'--meta', // P1-3:渲染 SS-META 机器块(布尔 flag,不吃值)
|
|
861
|
+
'--session', // 显式会话标识(吃值,VALUE_FLAGS 同步登记;2026-09-14-change-ownership-guards task-02:启动 claim 消费,所有权三级解析最高优先级层)
|
|
862
|
+
'--takeover', // 所有权护栏显式强制接管(task-02 / FR-01:本层只注册透传,实际消费在 index.js apply/cleanup 子命令层——run 侧带上不报未知参数,语义出口在 worktree 命令)
|
|
863
|
+
'--skip-apply', // 归档收口跳过 apply 校验(task-02 只注册透传不改行为,消费归 task-03 archive 接线)
|
|
835
864
|
'-h',
|
|
836
865
|
])
|
|
837
866
|
for (let i = 0; i < flags.length; i++) {
|
|
@@ -894,6 +923,7 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
894
923
|
// D-002:guard 按 session 存(.runtime/quick-sessions/<sessionId>/guard.json)。
|
|
895
924
|
// sessionId == changeName == quick-<uuid8>(上面参数解析已确定)。回退读旧单文件 quick-guard.json(task-03 前兼容)。
|
|
896
925
|
let persistedLinked = null
|
|
926
|
+
let persistedAuto = null
|
|
897
927
|
try {
|
|
898
928
|
const sessionGuardFile = join(specRoot, '.runtime', 'quick-sessions', changeName, 'guard.json')
|
|
899
929
|
const legacyGuardFile = join(specRoot, '.runtime', 'quick-guard.json')
|
|
@@ -901,15 +931,20 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
901
931
|
? JSON.parse(readFileSync(sessionGuardFile, 'utf8'))
|
|
902
932
|
: (existsSync(legacyGuardFile) ? JSON.parse(readFileSync(legacyGuardFile, 'utf8')) : null)
|
|
903
933
|
if (g && Array.isArray(g.linkedChanges)) persistedLinked = g.linkedChanges
|
|
934
|
+
if (g && Array.isArray(g.linkedChangesAuto)) persistedAuto = g.linkedChangesAuto
|
|
904
935
|
} catch {}
|
|
905
936
|
if (persistedLinked) {
|
|
906
937
|
linkedChanges = persistedLinked
|
|
938
|
+
// autoLinked 溯源同步恢复(--done 复用启动 guard 的关联时,归档闸同样要看到「机器猜的」标记)
|
|
939
|
+
if (persistedAuto) linkedAuto = persistedAuto
|
|
907
940
|
} else {
|
|
908
|
-
|
|
941
|
+
const resolved = await resolveQuickLinkedChanges({
|
|
909
942
|
pm, cwd, specDir: specRoot, quickFiles,
|
|
910
943
|
taskDescription: inputText || '',
|
|
911
944
|
nonInteractive: isNonInteractive,
|
|
912
945
|
})
|
|
946
|
+
linkedChanges = resolved.changes
|
|
947
|
+
linkedAuto = resolved.autoLinked
|
|
913
948
|
}
|
|
914
949
|
}
|
|
915
950
|
|
|
@@ -1011,12 +1046,27 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1011
1046
|
}
|
|
1012
1047
|
|
|
1013
1048
|
if (!progress) {
|
|
1049
|
+
// ── 辅助阶段 default 行亲和(坑 default-empty-dir-materialized 配套,2026-09-14 用户反馈①)──
|
|
1050
|
+
// default 行是辅助阶段(explore 等)不带 --change 启动时的进度容器(下方 isAuxiliary
|
|
1051
|
+
// 兜底 'default')。此前「续跑也锚回 default」靠的是 changes/default/ 目录在目录计数
|
|
1052
|
+
// 解析里的存在感——目录停建后(initChange 对系统 key 不再物化)该隐式锚定失效,
|
|
1053
|
+
// 「default 在途 + 恰好一个其他变更目录」会把辅助阶段挂到别人的变更行。这里显式化:
|
|
1054
|
+
// 无 --change 且 default 行有在途(非 completed)的本阶段 steps → 锚回 default。
|
|
1055
|
+
// 显式 --change 恒优先;非辅助阶段(brainstorm/execute 等)从不落 default,不适用。
|
|
1056
|
+
if (!changeName && isAuxiliary) {
|
|
1057
|
+
const affinity = resolveAuxiliaryDefaultAffinity(pm, cwd, stageName)
|
|
1058
|
+
if (affinity) {
|
|
1059
|
+
changeName = affinity
|
|
1060
|
+
progress = pm.read(cwd, affinity)
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1014
1063
|
// ── done-like 存在性守卫(坑 done-phantom-change-silent-create,2026-09-04 事故元凶①)──
|
|
1015
1064
|
// --done/--skip/--wait/--continue/--reset/--reopen 都预设「目标 change 已存在于当前进度库」。
|
|
1016
1065
|
// 此前 !progress 时无条件 initChange 静默新建——接管指针切库/换库后 --change 指向旧库的
|
|
1017
1066
|
// 变更名,新库里凭空建幻影变更再把动作记上去。目标已物化(changes/ 目录或 quick 会话
|
|
1018
1067
|
// guard 存在)仍放行走下方 initChange 自愈(DB 重建/迁移后从目录物化是合法恢复路径)。
|
|
1019
|
-
|
|
1068
|
+
// !progress 前置:上方亲和已锚到 default 行(DB 在途)时目标已确证存在,不走磁盘物化判据。
|
|
1069
|
+
if (!progress && (isDone || isSkip || isWait || isContinue || isReset || isReopen)) {
|
|
1020
1070
|
const actionFlag = isDone ? '--done' : isSkip ? '--skip' : isWait ? '--wait'
|
|
1021
1071
|
: isContinue ? '--continue' : isReset ? '--reset' : '--reopen'
|
|
1022
1072
|
const guardTarget = changeName || resolveChangeNameAuto(cwd, specRoot)
|
|
@@ -1042,6 +1092,13 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1042
1092
|
}
|
|
1043
1093
|
if (stageName === 'quick' || /^quick-[0-9a-f]{8}$/.test(guardTarget || '')) {
|
|
1044
1094
|
console.error(` ③ quick 会话跨进程恢复须带 --change <quick-session-id>;本库无该会话 guard——会话可能属于旧库`)
|
|
1095
|
+
} else if (stageName === 'explore' && activeList.includes('default')) {
|
|
1096
|
+
// 坑 explore-done-change-default-hint(2026-09-14 用户反馈①):explore 不带 --change 启动
|
|
1097
|
+
// 时进度按约定挂 default 变更行(isAuxiliary 兜底),多活跃变更库(多 agent 并行常态)
|
|
1098
|
+
// 目标解析失败被拒时,③ 只指 brainstorm 新建路径——对「进度就在 default 行」的 explore
|
|
1099
|
+
// 会话是误导(用户实证要靠 --status 才摸出来)。default 在活跃列表 = 有辅助阶段在途,
|
|
1100
|
+
// 补指向自身的 --change default 出口。
|
|
1101
|
+
console.error(` ③ explore 阶段进度默认挂在 default 变更行——本库 default 在活跃列表,重试加 --change default`)
|
|
1045
1102
|
} else {
|
|
1046
1103
|
console.error(` ③ 确要新建变更:先 sillyspec run brainstorm --change <名>(不带 ${actionFlag})`)
|
|
1047
1104
|
}
|
|
@@ -1190,6 +1247,28 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1190
1247
|
// 注册变更到全局活跃列表(如果尚未注册)
|
|
1191
1248
|
if (effectiveChange) {
|
|
1192
1249
|
pm.registerChange(cwd, effectiveChange)
|
|
1250
|
+
// ── 所有权首建 claim(2026-09-14-change-ownership-guards task-02 / FR-01 / D-001@v1)──
|
|
1251
|
+
// run <stage> 启动即认领 owner(claimChangeOwner 守卫语义:已有值不覆盖——他人持有不抢
|
|
1252
|
+
// 也不拒;拒绝语义只锁接管类操作,见 index.js apply/cleanup/assess 接线)。会话标识三级:
|
|
1253
|
+
// quick 会话=changeName 本身(quick-<8hex>,既有 sessionId 机制——guard 按 change 名落盘
|
|
1254
|
+
// 天然跨进程,selfSession==changeName 恒 self);full-flow=--session > env
|
|
1255
|
+
// SILLYSPEC_SESSION_ID > anon@host 机器级降级(降级时一次性教学 warning)。
|
|
1256
|
+
// default 容器行不认领:辅助阶段共享容器非真实变更,挂伪所有权没有消费者还添噪声。
|
|
1257
|
+
// fail-open:claim 失败不阻断启动(护栏判定退回 no-owner 放行)。
|
|
1258
|
+
try {
|
|
1259
|
+
if (effectiveChange !== 'default') {
|
|
1260
|
+
const ident = resolveSessionIdentity({
|
|
1261
|
+
flagSession: getFlagValue('--session'),
|
|
1262
|
+
quickChangeName: stageName === 'quick' ? effectiveChange : null,
|
|
1263
|
+
// anon 降级教学 marker 落盘根用 dirname(specRoot)(锚定后的主仓根)而非裸 cwd:
|
|
1264
|
+
// worktree 副本 cwd(execute 在 .sillyspec/.runtime/worktrees/<c>/ 内跑)会把
|
|
1265
|
+
// marker mkdir 进副本 .runtime(worktree-execute-spec-drift AC-A6 副本零写入实证),
|
|
1266
|
+
// 且副本随 cleanup 删除、marker 永不跨会话去重——落到持久主仓根才是教学降频语义。
|
|
1267
|
+
cwd: dirname(specRoot),
|
|
1268
|
+
})
|
|
1269
|
+
pm.claimChangeOwner(cwd, effectiveChange, ident.session)
|
|
1270
|
+
}
|
|
1271
|
+
} catch { /* claim 失败不阻断启动 */ }
|
|
1193
1272
|
}
|
|
1194
1273
|
|
|
1195
1274
|
// --reset
|
|
@@ -1306,7 +1385,26 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1306
1385
|
} catch { /* guard 损坏 → 下面按找不到报错 */ }
|
|
1307
1386
|
}
|
|
1308
1387
|
if (!qlId) {
|
|
1309
|
-
|
|
1388
|
+
// 坑 quick-cancel-blind-after-quicklog-rotation ②③(2026-09-16 实证):空壳会话
|
|
1389
|
+
//(启动即被拒/未写任何条目)无 ql-ID 可传,「显式传 --ql」指引逻辑上不可执行。
|
|
1390
|
+
// 两层出口:① guard 缺失但进度库会话行零步骤完成 → 空壳直清(进度注销+目录清理即
|
|
1391
|
+
// 成功,条目定位对无条目会话本无意义);② 仍有疑虑时 --force 跳过条目清理强清。
|
|
1392
|
+
const forceCancel = flags.includes('--force')
|
|
1393
|
+
let emptyShell = false
|
|
1394
|
+
try {
|
|
1395
|
+
const sessProgress = pm.read(cwd, cancelSessionRaw)
|
|
1396
|
+
const qSteps = sessProgress?.stages?.quick?.steps
|
|
1397
|
+
const doneCount = Array.isArray(qSteps) ? qSteps.filter(s => s?.status === 'completed' || s?.status === 'skipped').length : 0
|
|
1398
|
+
emptyShell = doneCount === 0
|
|
1399
|
+
} catch { /* 读不到进度 → 按非空壳走原报错 */ }
|
|
1400
|
+
if (forceCancel || emptyShell) {
|
|
1401
|
+
try { pm.unregisterChange(cwd, cancelSessionRaw) } catch { /* 无行可注销不算失败 */ }
|
|
1402
|
+
try { rmSync(join(resolveQuickSessionsDir(platformOpts, specBase), cancelSessionRaw), { recursive: true, force: true }) } catch { /* 目录不存在即无事 */ }
|
|
1403
|
+
console.log(`🗑️ 已${emptyShell ? '清空壳会话(零步骤完成,无 QUICKLOG 条目可清)' : '强制取消(--force,跳过条目清理)'}: ${cancelSessionRaw}`)
|
|
1404
|
+
console.log(' 进度行注销 + 会话目录清理完成')
|
|
1405
|
+
return
|
|
1406
|
+
}
|
|
1407
|
+
console.error(`❌ 无法定位会话 ${cancelSessionRaw} 的 qlId(guard.json 缺失/损坏)——显式传 --ql <ql-xxx>(QUICKLOG 条目头);确认该会话确无条目可清时可用 --force 跳过条目清理`)
|
|
1310
1408
|
process.exit(1)
|
|
1311
1409
|
}
|
|
1312
1410
|
let gitUser = 'unknown'
|
|
@@ -1391,18 +1489,20 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1391
1489
|
}
|
|
1392
1490
|
}
|
|
1393
1491
|
|
|
1394
|
-
// --file-notes
|
|
1395
|
-
//
|
|
1396
|
-
//
|
|
1397
|
-
|
|
1492
|
+
// --file-notes 非末步硬拒绝(坑 quick-file-notes-nonfinal-ignored → quick-sync-block
|
|
1493
|
+
// 坑2 升级,2026-09-13 实证:warn 版仍「先收下再丢弃再告知」——9 条括注静默丢失需凭记忆
|
|
1494
|
+
// 重传)。改为 exit 2 直接拒绝:调用方立刻知道参数传错了时机,不做静默丢弃。末步 --done
|
|
1495
|
+
//(唯一 pending)是消费点,正常消费。
|
|
1398
1496
|
if (quickFileNotes !== '' && stageName === 'quick' && !isStatus) {
|
|
1399
1497
|
try {
|
|
1400
1498
|
const qSteps = progress?.stages?.quick?.steps
|
|
1401
1499
|
const pendingCount = Array.isArray(qSteps) ? qSteps.filter(st => ['pending', 'in-progress'].includes(st?.status)).length : 0
|
|
1402
1500
|
if (!isDone || pendingCount > 1) {
|
|
1403
|
-
console.
|
|
1501
|
+
console.error(`❌ --file-notes 此时不生效(拒绝执行而非静默丢弃):它只在 quick 末步 --done 时随收尾消费——CLI 是短进程,非末步注入随进程结束即丢。`)
|
|
1502
|
+
console.error(` 请去掉 --file-notes 重跑本条命令;括注内容留到末步 --done 时连同 --output 一起传。`)
|
|
1503
|
+
process.exit(2)
|
|
1404
1504
|
}
|
|
1405
|
-
} catch { /*
|
|
1505
|
+
} catch { /* 判定失败不阻断(fail-open 维持旧行为) */ }
|
|
1406
1506
|
}
|
|
1407
1507
|
|
|
1408
1508
|
// --status
|
|
@@ -1447,11 +1547,29 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1447
1547
|
}
|
|
1448
1548
|
}
|
|
1449
1549
|
const doneAnswer = getFlagValue('--answer')
|
|
1450
|
-
|
|
1550
|
+
// isSkipApply/sessionFlag(task-03):--skip-apply 归档收口跳过 + --session 所有权会话标识,
|
|
1551
|
+
// 随 completeStep options 透传(isNoDocs 同款链路)——消费点 archive/quick 收尾 handler。
|
|
1552
|
+
return await completeStep(pm, progress, stageName, cwd, outputText, inputText, { confirm: isConfirm, changeName: effectiveChange, nonInteractive: isNonInteractive && !isInteractive, platformOpts, doneAnswer, isForceBaseline, isAllowNew, isAllowDelete, isNoDocs, isSkipApply, sessionFlag: getFlagValue('--session'), quickFiles, stepAssert: stepAssertValue })
|
|
1451
1553
|
}
|
|
1452
1554
|
|
|
1453
1555
|
// 默认:输出当前步骤
|
|
1454
|
-
return await runStage(pm, progress, stageName, cwd, effectiveChange, isSkipApproval, platformOpts, { quickFiles, isAllowNew, isAllowDelete, isForceBaseline, isForceRescan, linkedChanges, taskDescription: inputText, adoptBranch: stageName === 'execute' && flags.includes('--adopt-branch') })
|
|
1556
|
+
return await runStage(pm, progress, stageName, cwd, effectiveChange, isSkipApproval, platformOpts, { quickFiles, isAllowNew, isAllowDelete, isForceBaseline, isForceRescan, linkedChanges, linkedChangesAuto: linkedAuto, taskDescription: inputText, adoptBranch: stageName === 'execute' && flags.includes('--adopt-branch') })
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* 辅助阶段 default 行亲和:default 行有在途(非 completed、steps 已物化)的本阶段时返回 'default'。
|
|
1561
|
+
* steps>0 门槛排除「从未跑过」的空壳行(initChange 播的 pending 空表)——那种行不是在途会话,
|
|
1562
|
+
* 不锚(防凭空把 --done 记上去)。只读不抛(无行/读失败 → null)。目录停建后辅助阶段续跑的
|
|
1563
|
+
* 显式锚定(见 !progress 块内注释)。completed 永不锚(辅助阶段收尾会 reset 回 pending 可重跑,
|
|
1564
|
+
* 见 gates.js auxiliary 重置——reset 后 pending+steps>0 照样锚,即「下一轮 explore 续用 default 行」)。
|
|
1565
|
+
*/
|
|
1566
|
+
function resolveAuxiliaryDefaultAffinity(pm, cwd, stageName) {
|
|
1567
|
+
try {
|
|
1568
|
+
const p = pm.read(cwd, 'default')
|
|
1569
|
+
const st = p && p.stages && p.stages[stageName]
|
|
1570
|
+
if (st && st.status && st.status !== 'completed' && Array.isArray(st.steps) && st.steps.length > 0) return 'default'
|
|
1571
|
+
} catch { /* 读失败不猜(fail-closed,走原解析链) */ }
|
|
1572
|
+
return null
|
|
1455
1573
|
}
|
|
1456
1574
|
|
|
1457
1575
|
/**
|