sillyspec 3.25.0 → 3.25.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/package.json +1 -1
- package/src/db.js +28 -8
- package/src/hooks/worktree-guard.js +9 -2
- package/src/index.js +5 -5
- package/src/machine-interface.js +13 -7
- package/src/progress.js +22 -6
- package/src/run/command.js +1011 -0
- package/src/run/complete-handlers.js +873 -0
- package/src/run/complete.js +695 -0
- package/src/run/gates.js +321 -0
- package/src/run/prompt.js +604 -0
- package/src/run/quick-audit.js +102 -0
- package/src/run/scan-profile.js +238 -0
- package/src/run/shared.js +375 -0
- package/src/run/stage.js +414 -0
- package/src/run.js +23 -4379
- package/src/stage-contract.js +4 -2
- package/src/worktree.js +17 -8
package/src/stage-contract.js
CHANGED
|
@@ -661,7 +661,7 @@ export function checkExecuteCodeEvidence(cwd, changeName) {
|
|
|
661
661
|
* 防止"勾选 checkbox = 完成 execute"的谎报路径。
|
|
662
662
|
*/
|
|
663
663
|
function validateExecuteOutputs(cwd, changeName, context = {}) {
|
|
664
|
-
const { specRoot } = context
|
|
664
|
+
const { specRoot, evidence: passedEvidence } = context
|
|
665
665
|
const errors = []
|
|
666
666
|
const warnings = []
|
|
667
667
|
|
|
@@ -674,7 +674,9 @@ function validateExecuteOutputs(cwd, changeName, context = {}) {
|
|
|
674
674
|
const hasTasks = /^\s*[-*]\s*\[[ xX]\]\s*task-\d+/m.test(planContent)
|
|
675
675
|
if (!hasTasks) return { ok: true, errors, warnings }
|
|
676
676
|
|
|
677
|
-
|
|
677
|
+
// W4-G (D-008):evidence 可由调用方(runGate)预先算好传入,避免与 execute-evidence check
|
|
678
|
+
// 重复 spawn git(gate execute 一次省 2 个 git 进程 ≈ 60-200ms on Windows)。未传则内部算(向后兼容)。
|
|
679
|
+
const evidence = passedEvidence || checkExecuteCodeEvidence(cwd, changeName)
|
|
678
680
|
if (evidence.status === 'unchanged') {
|
|
679
681
|
errors.push(`execute 代码变更核验失败:plan.md 声明了任务,但 ${evidence.detail} — 勾选 checkbox 不等于完成实现`)
|
|
680
682
|
} else if (evidence.status === 'unknown') {
|
package/src/worktree.js
CHANGED
|
@@ -13,6 +13,11 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync
|
|
|
13
13
|
import { join, resolve, dirname } from 'path';
|
|
14
14
|
import { createHash } from 'crypto';
|
|
15
15
|
import { provisionDeps, lockfileHash } from './worktree-deps.js';
|
|
16
|
+
import { writeAtomicSync } from './fs-atomic.js';
|
|
17
|
+
|
|
18
|
+
// meta.json 会被 hook 进程与其它 CLI 进程并发读取(worktree-guard / getMeta / create 幽灵判定),
|
|
19
|
+
// 必须原子写:半截 JSON 会让 getMeta 返回 null → 触发幽灵 worktree 强删(可能丢 gitignored 改动)。
|
|
20
|
+
const writeMetaAtomic = (metaPath, meta) => writeAtomicSync(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
16
21
|
|
|
17
22
|
const WORKTREES_REL = '.sillyspec/.runtime/worktrees';
|
|
18
23
|
const BRANCH_PREFIX = 'sillyspec/';
|
|
@@ -414,8 +419,12 @@ export class WorktreeManager {
|
|
|
414
419
|
createdAt: new Date().toISOString(),
|
|
415
420
|
provisioning: true,
|
|
416
421
|
};
|
|
417
|
-
|
|
418
|
-
} catch {
|
|
422
|
+
writeMetaAtomic(join(worktreePath, META_FILE), placeholderMeta);
|
|
423
|
+
} catch (e) {
|
|
424
|
+
// 占位 meta 是「防 create 中断 → 幽灵强删」的守卫。写失败不能静默:否则中断后
|
|
425
|
+
// getMeta 仍返回 null,下次 create 会把含 gitignored 改动的 worktree 当幽灵删掉。
|
|
426
|
+
console.warn(`⚠️ 占位 meta 写入失败: ${e.message}(若 create 中断,下次可能误判幽灵 worktree)`);
|
|
427
|
+
}
|
|
419
428
|
|
|
420
429
|
// 5.5 base 同步检测(只读:不 ff、不改 HEAD;best-effort fetch 失败降级用缓存)。
|
|
421
430
|
// 旧逻辑 fetch + merge --ff-only:分叉时 ff 失败被静默吞(syncStatus=failed),成功时
|
|
@@ -468,7 +477,7 @@ export class WorktreeManager {
|
|
|
468
477
|
};
|
|
469
478
|
|
|
470
479
|
const metaPath = join(worktreePath, META_FILE);
|
|
471
|
-
|
|
480
|
+
writeMetaAtomic(metaPath, meta);
|
|
472
481
|
|
|
473
482
|
return { branch, worktreePath, baseHash, mode: meta.mode, syncDiagnostic };
|
|
474
483
|
}
|
|
@@ -499,7 +508,7 @@ export class WorktreeManager {
|
|
|
499
508
|
if (!existsSync(this.worktreeBase)) mkdirSync(this.worktreeBase, { recursive: true })
|
|
500
509
|
const metaDir = join(this.worktreeBase, name)
|
|
501
510
|
if (!existsSync(metaDir)) mkdirSync(metaDir, { recursive: true })
|
|
502
|
-
|
|
511
|
+
writeMetaAtomic(join(metaDir, META_FILE), meta)
|
|
503
512
|
console.log(`🔗 native-worktree meta 已恢复: ${metaDir}/meta.json`)
|
|
504
513
|
return { branch: meta.branch, worktreePath, baseHash, mode: meta.mode }
|
|
505
514
|
}
|
|
@@ -552,7 +561,7 @@ export class WorktreeManager {
|
|
|
552
561
|
if (!existsSync(this.worktreeBase)) mkdirSync(this.worktreeBase, { recursive: true })
|
|
553
562
|
const metaDir = join(this.worktreeBase, name)
|
|
554
563
|
if (!existsSync(metaDir)) mkdirSync(metaDir, { recursive: true })
|
|
555
|
-
|
|
564
|
+
writeMetaAtomic(join(metaDir, META_FILE), meta)
|
|
556
565
|
return { branch: meta.branch, worktreePath, baseHash, mode: meta.mode }
|
|
557
566
|
}
|
|
558
567
|
|
|
@@ -596,7 +605,7 @@ export class WorktreeManager {
|
|
|
596
605
|
if (!existsSync(metaDir)) {
|
|
597
606
|
mkdirSync(metaDir, { recursive: true });
|
|
598
607
|
}
|
|
599
|
-
|
|
608
|
+
writeMetaAtomic(metaPath, meta);
|
|
600
609
|
|
|
601
610
|
return { branch: meta.branch, worktreePath, baseHash, mode: meta.mode };
|
|
602
611
|
}
|
|
@@ -817,7 +826,7 @@ export class WorktreeManager {
|
|
|
817
826
|
const deps = provisionDeps(wtPath, this.cwd, { specBase: join(this.cwd, '.sillyspec') }) || {};
|
|
818
827
|
const metaPath = join(this.getWorktreePath(name), META_FILE);
|
|
819
828
|
const meta = this.getMeta(name) || {};
|
|
820
|
-
|
|
829
|
+
writeMetaAtomic(metaPath, { ...meta, ...deps });
|
|
821
830
|
return { ok: true, msg: `re-provisioned ${name}: depsStatus=${deps.depsStatus}` };
|
|
822
831
|
} catch (e) {
|
|
823
832
|
return { ok: false, msg: `re-provision failed for ${name}: ${e.message}` };
|
|
@@ -1094,7 +1103,7 @@ export class WorktreeManager {
|
|
|
1094
1103
|
const dst = join(worktreePath, f);
|
|
1095
1104
|
if (existsSync(src)) {
|
|
1096
1105
|
mkdirSync(dirname(dst), { recursive: true });
|
|
1097
|
-
try { writeFileSync(dst, readFileSync(src)); files.push(f); } catch {}
|
|
1106
|
+
try { writeFileSync(dst, readFileSync(src)); files.push(f); } catch (e) { errors.push(`untracked ${f}: ${e.message}`); }
|
|
1098
1107
|
}
|
|
1099
1108
|
}
|
|
1100
1109
|
}
|