@rpamis/comet 0.4.0-beta.4 → 0.4.0-beta.6
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/LICENSE +21 -21
- package/README.md +11 -4
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/SKILL.md +30 -28
- package/assets/skills/comet/reference/auto-transition.md +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +8 -4
- package/assets/skills/comet/reference/context-recovery.md +2 -2
- package/assets/skills/comet/reference/decision-point.md +11 -0
- package/assets/skills/comet/reference/subagent-dispatch.md +6 -5
- package/assets/skills/comet/rules/comet-phase-guard.en.md +23 -28
- package/assets/skills/comet/rules/comet-phase-guard.md +22 -28
- package/assets/skills/comet/scripts/comet-runtime.mjs +682 -309
- package/assets/skills/comet-any/SKILL.md +1 -1
- package/assets/skills/comet-any/reference/authored-zone-example.md +10 -5
- package/assets/skills/comet-any/reference/subagents/pause-points-author.md +14 -11
- package/assets/skills/comet-any/reference/subagents/skill-reviewer.md +2 -0
- package/assets/skills/comet-any/reference/subagents/workflow-entry-author.md +5 -4
- package/assets/skills/comet-archive/SKILL.md +33 -13
- package/assets/skills/comet-build/SKILL.md +37 -29
- package/assets/skills/comet-design/SKILL.md +23 -22
- package/assets/skills/comet-hotfix/SKILL.md +46 -31
- package/assets/skills/comet-open/SKILL.md +97 -58
- package/assets/skills/comet-tweak/SKILL.md +34 -19
- package/assets/skills/comet-verify/SKILL.md +37 -59
- package/assets/skills-zh/comet/SKILL.md +30 -28
- package/assets/skills-zh/comet/reference/auto-transition.md +1 -1
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +8 -4
- package/assets/skills-zh/comet/reference/context-recovery.md +2 -2
- package/assets/skills-zh/comet/reference/decision-point.md +11 -0
- package/assets/skills-zh/comet/reference/subagent-dispatch.md +6 -5
- package/assets/skills-zh/comet-any/SKILL.md +1 -1
- package/assets/skills-zh/comet-any/reference/authored-zone-example.md +10 -5
- package/assets/skills-zh/comet-any/reference/subagents/pause-points-author.md +14 -12
- package/assets/skills-zh/comet-any/reference/subagents/skill-reviewer.md +2 -0
- package/assets/skills-zh/comet-any/reference/subagents/workflow-entry-author.md +5 -4
- package/assets/skills-zh/comet-archive/SKILL.md +33 -13
- package/assets/skills-zh/comet-build/SKILL.md +37 -29
- package/assets/skills-zh/comet-design/SKILL.md +23 -22
- package/assets/skills-zh/comet-hotfix/SKILL.md +45 -30
- package/assets/skills-zh/comet-open/SKILL.md +96 -57
- package/assets/skills-zh/comet-tweak/SKILL.md +33 -18
- package/assets/skills-zh/comet-verify/SKILL.md +37 -59
- package/dist/app/commands/doctor.d.ts.map +1 -1
- package/dist/app/commands/doctor.js +62 -15
- package/dist/app/commands/doctor.js.map +1 -1
- package/dist/app/commands/init.d.ts +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +58 -14
- package/dist/app/commands/init.js.map +1 -1
- package/dist/app/commands/status.d.ts +1 -0
- package/dist/app/commands/status.d.ts.map +1 -1
- package/dist/app/commands/status.js +10 -0
- package/dist/app/commands/status.js.map +1 -1
- package/dist/app/commands/uninstall.d.ts +3 -0
- package/dist/app/commands/uninstall.d.ts.map +1 -1
- package/dist/app/commands/uninstall.js +70 -36
- package/dist/app/commands/uninstall.js.map +1 -1
- package/dist/app/commands/update.d.ts.map +1 -1
- package/dist/app/commands/update.js +213 -34
- package/dist/app/commands/update.js.map +1 -1
- package/dist/domains/bundle/bundle-platform.d.ts +1 -0
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +6 -2
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/comet-classic/classic-branch-binding.d.ts +51 -0
- package/dist/domains/comet-classic/classic-branch-binding.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-branch-binding.js +107 -0
- package/dist/domains/comet-classic/classic-branch-binding.js.map +1 -0
- package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-current-change.js +37 -20
- package/dist/domains/comet-classic/classic-current-change.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +50 -16
- package/dist/domains/comet-classic/classic-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.js +138 -21
- package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-resolver.js +1 -1
- package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.js +113 -14
- package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
- package/dist/domains/comet-classic/classic-state-events.d.ts +1 -1
- package/dist/domains/comet-classic/classic-state-events.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state.d.ts +4 -2
- package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state.js +16 -1
- package/dist/domains/comet-classic/classic-state.js.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.js +17 -2
- package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.js +13 -1
- package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
- package/dist/domains/dashboard/web/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- package/dist/domains/dashboard/web/assets/arc-TGVUG2WN.js +1 -0
- package/dist/domains/dashboard/web/assets/architectureDiagram-3BPJPVTR-ASHmiHoP.js +36 -0
- package/dist/domains/dashboard/web/assets/blockDiagram-GPEHLZMM-CwASxBKe.js +132 -0
- package/dist/domains/dashboard/web/assets/c4Diagram-AAUBKEIU-BU8z_WNk.js +10 -0
- package/dist/domains/dashboard/web/assets/channel-kp6Ng2JJ.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-2J33WTMH-CBGlUx4_.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-4BX2VUAB-CS-iGcFz.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-55IACEB6-BUtCVJat.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-727SXJPM-C94tj_pf.js +206 -0
- package/dist/domains/dashboard/web/assets/chunk-AQP2D5EJ-BFOKcpdG.js +231 -0
- package/dist/domains/dashboard/web/assets/chunk-FMBD7UC4-Dmx8B-st.js +15 -0
- package/dist/domains/dashboard/web/assets/chunk-ND2GUHAM-DYV00CNn.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-QZHKN3VN-DMJJyQnw.js +1 -0
- package/dist/domains/dashboard/web/assets/classDiagram-4FO5ZUOK-yBDjgMY_.js +1 -0
- package/dist/domains/dashboard/web/assets/classDiagram-v2-Q7XG4LA2-yBDjgMY_.js +1 -0
- package/dist/domains/dashboard/web/assets/cose-bilkent-S5V4N54A-P4nE2rea.js +1 -0
- package/dist/domains/dashboard/web/assets/cynefin-VYW2F7L2-C-R1HXDv.js +166 -0
- package/dist/domains/dashboard/web/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
- package/dist/domains/dashboard/web/assets/dagre-BM42HDAG-BH8d-C9z.js +4 -0
- package/dist/domains/dashboard/web/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/domains/dashboard/web/assets/diagram-2AECGRRQ-DpXTgQIH.js +43 -0
- package/dist/domains/dashboard/web/assets/diagram-5GNKFQAL-DSiFJzSw.js +10 -0
- package/dist/domains/dashboard/web/assets/diagram-KO2AKTUF-DULMkben.js +3 -0
- package/dist/domains/dashboard/web/assets/diagram-LMA3HP47-Pi8m_NO9.js +24 -0
- package/dist/domains/dashboard/web/assets/diagram-OG6HWLK6-BSe6bCWm.js +24 -0
- package/dist/domains/dashboard/web/assets/erDiagram-TEJ5UH35-zb-FEcbq.js +85 -0
- package/dist/domains/dashboard/web/assets/flowDiagram-I6XJVG4X-Dr-Gk0z2.js +162 -0
- package/dist/domains/dashboard/web/assets/ganttDiagram-6RSMTGT7-qs6Zb2A6.js +292 -0
- package/dist/domains/dashboard/web/assets/gitGraphDiagram-PVQCEYII-BQ314orT.js +106 -0
- package/dist/domains/dashboard/web/assets/graph--OzhPTMs.js +1 -0
- package/dist/domains/dashboard/web/assets/index-BLAfkNTu.css +1 -0
- package/dist/domains/dashboard/web/assets/index-DlSYK56b.js +139 -0
- package/dist/domains/dashboard/web/assets/index-DtLUOcAW.js +24 -0
- package/dist/domains/dashboard/web/assets/index-QO0z6F4w.js +10 -0
- package/dist/domains/dashboard/web/assets/infoDiagram-5YYISTIA-O0bQp98A.js +2 -0
- package/dist/domains/dashboard/web/assets/init-Gi6I4Gst.js +1 -0
- package/dist/domains/dashboard/web/assets/ishikawaDiagram-YF4QCWOH-BPC7wbKh.js +70 -0
- package/dist/domains/dashboard/web/assets/journeyDiagram-JHISSGLW-ohViOd4b.js +139 -0
- package/dist/domains/dashboard/web/assets/kanban-definition-UN3LZRKU-CHleNdbG.js +89 -0
- package/dist/domains/dashboard/web/assets/katex-HP8lGamR.js +257 -0
- package/dist/domains/dashboard/web/assets/layout-SsrduOYp.js +1 -0
- package/dist/domains/dashboard/web/assets/linear-CyqiW--Q.js +1 -0
- package/dist/domains/dashboard/web/assets/marked.esm-DECB3bxB.js +64 -0
- package/dist/domains/dashboard/web/assets/mermaid.core-qS9XvtaK.js +301 -0
- package/dist/domains/dashboard/web/assets/mindmap-definition-RKZ34NQL-oaGkqO9l.js +96 -0
- package/dist/domains/dashboard/web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/domains/dashboard/web/assets/pieDiagram-4H26LBE5-CPcB-AFh.js +30 -0
- package/dist/domains/dashboard/web/assets/purify.es-VaSPOPhr.js +3 -0
- package/dist/domains/dashboard/web/assets/quadrantDiagram-W4KKPZXB-LFy52Qtj.js +7 -0
- package/dist/domains/dashboard/web/assets/requirementDiagram-4Y6WPE33-BdjeaYP_.js +84 -0
- package/dist/domains/dashboard/web/assets/sankeyDiagram-5OEKKPKP-DDJ4styL.js +40 -0
- package/dist/domains/dashboard/web/assets/sequenceDiagram-3UESZ5HK-BL5bFNoz.js +162 -0
- package/dist/domains/dashboard/web/assets/stateDiagram-AJRCARHV-BNUfikui.js +1 -0
- package/dist/domains/dashboard/web/assets/stateDiagram-v2-BHNVJYJU-DGrsmWts.js +1 -0
- package/dist/domains/dashboard/web/assets/timeline-definition-PNZ67QCA--ps2uu6L.js +120 -0
- package/dist/domains/dashboard/web/assets/vennDiagram-CIIHVFJN-C2q8q26c.js +34 -0
- package/dist/domains/dashboard/web/assets/wardleyDiagram-YWT4CUSO-BUH9gXqd.js +78 -0
- package/dist/domains/dashboard/web/assets/xychartDiagram-2RQKCTM6-B-DielEy.js +7 -0
- package/dist/domains/dashboard/web/index.html +16 -16
- package/dist/domains/factory/package.d.ts.map +1 -1
- package/dist/domains/factory/package.js +20 -6
- package/dist/domains/factory/package.js.map +1 -1
- package/dist/domains/integrations/openspec.d.ts +4 -1
- package/dist/domains/integrations/openspec.d.ts.map +1 -1
- package/dist/domains/integrations/openspec.js +56 -4
- package/dist/domains/integrations/openspec.js.map +1 -1
- package/dist/domains/skill/find.d.ts.map +1 -1
- package/dist/domains/skill/find.js +7 -1
- package/dist/domains/skill/find.js.map +1 -1
- package/dist/domains/skill/json-object.d.ts +13 -0
- package/dist/domains/skill/json-object.d.ts.map +1 -0
- package/dist/domains/skill/json-object.js +24 -0
- package/dist/domains/skill/json-object.js.map +1 -0
- package/dist/domains/skill/platform-inspect.d.ts +9 -0
- package/dist/domains/skill/platform-inspect.d.ts.map +1 -0
- package/dist/domains/skill/platform-inspect.js +149 -0
- package/dist/domains/skill/platform-inspect.js.map +1 -0
- package/dist/domains/skill/platform-install.d.ts +16 -6
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +277 -144
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/uninstall.d.ts.map +1 -1
- package/dist/domains/skill/uninstall.js +204 -141
- package/dist/domains/skill/uninstall.js.map +1 -1
- package/dist/platform/fs/file-system.d.ts +3 -3
- package/dist/platform/fs/file-system.d.ts.map +1 -1
- package/dist/platform/fs/file-system.js +21 -11
- package/dist/platform/fs/file-system.js.map +1 -1
- package/dist/platform/install/platforms.d.ts +4 -0
- package/dist/platform/install/platforms.d.ts.map +1 -1
- package/dist/platform/install/platforms.js +2 -0
- package/dist/platform/install/platforms.js.map +1 -1
- package/dist/platform/install/project-registry.d.ts +1 -0
- package/dist/platform/install/project-registry.d.ts.map +1 -1
- package/dist/platform/install/project-registry.js +9 -1
- package/dist/platform/install/project-registry.js.map +1 -1
- package/dist/platform/install/skill-root-owner.d.ts +15 -0
- package/dist/platform/install/skill-root-owner.d.ts.map +1 -0
- package/dist/platform/install/skill-root-owner.js +68 -0
- package/dist/platform/install/skill-root-owner.js.map +1 -0
- package/package.json +6 -1
- package/dist/domains/dashboard/web/assets/index-CIvN-PL8.js +0 -22
- package/dist/domains/dashboard/web/assets/index-DcyRPBnT.css +0 -1
- package/eval/.env +0 -28
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare function liveGitBranch(cwd: string): string | null;
|
|
2
|
+
export declare function isGitWorkTree(cwd: string): boolean;
|
|
3
|
+
export type BranchBindingVerdict = {
|
|
4
|
+
status: 'not-applicable';
|
|
5
|
+
} | {
|
|
6
|
+
status: 'ok';
|
|
7
|
+
} | {
|
|
8
|
+
status: 'needs-heal';
|
|
9
|
+
branch: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: 'unbound-detached';
|
|
12
|
+
} | {
|
|
13
|
+
status: 'drift';
|
|
14
|
+
boundBranch: string;
|
|
15
|
+
currentBranch: string | null;
|
|
16
|
+
};
|
|
17
|
+
export declare const BOUND_BRANCH_ISOLATIONS: readonly ["current", "branch", "worktree"];
|
|
18
|
+
export declare function requiresBranchBinding(isolation: string | null): boolean;
|
|
19
|
+
export declare function evaluateBranchBinding(input: {
|
|
20
|
+
isolation: string | null;
|
|
21
|
+
boundBranch: string | null;
|
|
22
|
+
currentBranch: string | null;
|
|
23
|
+
gitWorkTree?: boolean;
|
|
24
|
+
}): BranchBindingVerdict;
|
|
25
|
+
/**
|
|
26
|
+
* A `BranchBindingVerdict` joined with the live git facts it was computed
|
|
27
|
+
* from, so callers never re-derive them (or re-read the state file).
|
|
28
|
+
*/
|
|
29
|
+
export type BranchBindingOutcome = (BranchBindingVerdict | {
|
|
30
|
+
status: 'healed';
|
|
31
|
+
branch: string;
|
|
32
|
+
}) & {
|
|
33
|
+
bindingRequired: boolean;
|
|
34
|
+
currentBranch: string | null;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Single entry point for every consumer of the branch binding: reads
|
|
38
|
+
* isolation/bound_branch straight from `.comet.yaml` (typed — a yaml `null`
|
|
39
|
+
* is a JS null, never a "null" string), spawns git lazily, and optionally
|
|
40
|
+
* performs the lazy heal. Read-only paths (the PreToolUse hook) must pass
|
|
41
|
+
* `heal: false` so resolving never writes to disk.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveBranchBinding(changeDir: string, options: {
|
|
44
|
+
heal: boolean;
|
|
45
|
+
cwd: string;
|
|
46
|
+
}): Promise<BranchBindingOutcome>;
|
|
47
|
+
export declare function healBoundBranch(changeDir: string, branch: string): Promise<void>;
|
|
48
|
+
export declare function driftBlockedMessage(change: string, boundBranch: string, currentBranch: string | null): string;
|
|
49
|
+
export declare function driftStaleReason(change: string, boundBranch: string, currentBranch: string | null): string;
|
|
50
|
+
export declare function unboundDetachedMessage(change: string): string;
|
|
51
|
+
//# sourceMappingURL=classic-branch-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classic-branch-binding.d.ts","sourceRoot":"","sources":["../../../domains/comet-classic/classic-branch-binding.ts"],"names":[],"mappings":"AAMA,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWxD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYlD;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAC5B;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAChB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC9B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE3E,eAAO,MAAM,uBAAuB,4CAA6C,CAAC;AAElF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,oBAAoB,CAYvB;AAED;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,oBAAoB,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG;IACjG,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAwB/B;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtF;AAMD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CAKR;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CAER;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { parseDocument } from 'yaml';
|
|
6
|
+
export function liveGitBranch(cwd) {
|
|
7
|
+
try {
|
|
8
|
+
const branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
9
|
+
cwd,
|
|
10
|
+
encoding: 'utf8',
|
|
11
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
12
|
+
}).trim();
|
|
13
|
+
return branch && branch !== 'HEAD' ? branch : null;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function isGitWorkTree(cwd) {
|
|
20
|
+
try {
|
|
21
|
+
return (execFileSync('git', ['rev-parse', '--is-inside-work-tree'], {
|
|
22
|
+
cwd,
|
|
23
|
+
encoding: 'utf8',
|
|
24
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
25
|
+
}).trim() === 'true');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export const BOUND_BRANCH_ISOLATIONS = ['current', 'branch', 'worktree'];
|
|
32
|
+
export function requiresBranchBinding(isolation) {
|
|
33
|
+
return BOUND_BRANCH_ISOLATIONS.includes(isolation);
|
|
34
|
+
}
|
|
35
|
+
export function evaluateBranchBinding(input) {
|
|
36
|
+
if (!requiresBranchBinding(input.isolation))
|
|
37
|
+
return { status: 'not-applicable' };
|
|
38
|
+
if (input.boundBranch === null && input.currentBranch === null && input.gitWorkTree === false) {
|
|
39
|
+
return { status: 'not-applicable' };
|
|
40
|
+
}
|
|
41
|
+
if (input.boundBranch === null) {
|
|
42
|
+
return input.currentBranch === null
|
|
43
|
+
? { status: 'unbound-detached' }
|
|
44
|
+
: { status: 'needs-heal', branch: input.currentBranch };
|
|
45
|
+
}
|
|
46
|
+
if (input.currentBranch === input.boundBranch)
|
|
47
|
+
return { status: 'ok' };
|
|
48
|
+
return { status: 'drift', boundBranch: input.boundBranch, currentBranch: input.currentBranch };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Single entry point for every consumer of the branch binding: reads
|
|
52
|
+
* isolation/bound_branch straight from `.comet.yaml` (typed — a yaml `null`
|
|
53
|
+
* is a JS null, never a "null" string), spawns git lazily, and optionally
|
|
54
|
+
* performs the lazy heal. Read-only paths (the PreToolUse hook) must pass
|
|
55
|
+
* `heal: false` so resolving never writes to disk.
|
|
56
|
+
*/
|
|
57
|
+
export async function resolveBranchBinding(changeDir, options) {
|
|
58
|
+
const file = path.join(changeDir, '.comet.yaml');
|
|
59
|
+
const document = parseDocument(await fs.readFile(file, 'utf8'), { uniqueKeys: false });
|
|
60
|
+
if (document.errors.length > 0) {
|
|
61
|
+
throw new Error(`Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
62
|
+
}
|
|
63
|
+
const record = (document.toJS() ?? {});
|
|
64
|
+
const isolation = typeof record.isolation === 'string' ? record.isolation : null;
|
|
65
|
+
const boundBranch = typeof record.bound_branch === 'string' && record.bound_branch !== ''
|
|
66
|
+
? record.bound_branch
|
|
67
|
+
: null;
|
|
68
|
+
const bindingRequired = requiresBranchBinding(isolation);
|
|
69
|
+
const currentBranch = liveGitBranch(options.cwd);
|
|
70
|
+
const gitWorkTree = bindingRequired && boundBranch === null && currentBranch === null
|
|
71
|
+
? isGitWorkTree(options.cwd)
|
|
72
|
+
: true;
|
|
73
|
+
const verdict = evaluateBranchBinding({ isolation, boundBranch, currentBranch, gitWorkTree });
|
|
74
|
+
if (verdict.status === 'needs-heal' && options.heal) {
|
|
75
|
+
await healBoundBranch(changeDir, verdict.branch);
|
|
76
|
+
return { status: 'healed', branch: verdict.branch, bindingRequired, currentBranch };
|
|
77
|
+
}
|
|
78
|
+
return { ...verdict, bindingRequired, currentBranch };
|
|
79
|
+
}
|
|
80
|
+
export async function healBoundBranch(changeDir, branch) {
|
|
81
|
+
const file = path.join(changeDir, '.comet.yaml');
|
|
82
|
+
const document = parseDocument(await fs.readFile(file, 'utf8'), { uniqueKeys: false });
|
|
83
|
+
document.set('bound_branch', branch);
|
|
84
|
+
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
85
|
+
try {
|
|
86
|
+
await fs.writeFile(temporary, document.toString(), 'utf8');
|
|
87
|
+
await fs.rename(temporary, file);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
await fs.rm(temporary, { force: true });
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function branchLabel(currentBranch) {
|
|
95
|
+
return currentBranch ?? 'detached HEAD';
|
|
96
|
+
}
|
|
97
|
+
export function driftBlockedMessage(change, boundBranch, currentBranch) {
|
|
98
|
+
return (`change '${change}' is bound to branch '${boundBranch}', but current branch is '${branchLabel(currentBranch)}'.\n` +
|
|
99
|
+
`Next: ask the user to confirm — switch back to '${boundBranch}', or run \`comet state rebind ${change}\` after explicit confirmation.`);
|
|
100
|
+
}
|
|
101
|
+
export function driftStaleReason(change, boundBranch, currentBranch) {
|
|
102
|
+
return `change '${change}' is bound to branch '${boundBranch}', but current branch is '${branchLabel(currentBranch)}'`;
|
|
103
|
+
}
|
|
104
|
+
export function unboundDetachedMessage(change) {
|
|
105
|
+
return `change '${change}' uses a branch-bound workspace mode but has no bound branch and HEAD is detached; checkout a branch first before continuing.`;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=classic-branch-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classic-branch-binding.js","sourceRoot":"","sources":["../../../domains/comet-classic/classic-branch-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classic-current-change.d.ts","sourceRoot":"","sources":["../../../domains/comet-classic/classic-current-change.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"classic-current-change.d.ts","sourceRoot":"","sources":["../../../domains/comet-classic/classic-current-change.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,sBAAsB,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAgED,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,CA4BjC;AAED,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAkDhG;AAED,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E"}
|
|
@@ -1,25 +1,12 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
2
1
|
import { randomUUID } from 'crypto';
|
|
3
2
|
import { promises as fs } from 'fs';
|
|
4
3
|
import path from 'path';
|
|
4
|
+
import { driftStaleReason, resolveBranchBinding, unboundDetachedMessage, } from './classic-branch-binding.js';
|
|
5
5
|
import { assertOpenSpecChangeName } from './classic-paths.js';
|
|
6
6
|
import { readClassicState } from './classic-store.js';
|
|
7
7
|
export function currentChangeFile(projectRoot) {
|
|
8
8
|
return path.join(projectRoot, '.comet', 'current-change.json');
|
|
9
9
|
}
|
|
10
|
-
function currentBranch(projectRoot) {
|
|
11
|
-
try {
|
|
12
|
-
const branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
13
|
-
cwd: projectRoot,
|
|
14
|
-
encoding: 'utf8',
|
|
15
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
16
|
-
}).trim();
|
|
17
|
-
return branch && branch !== 'HEAD' ? branch : null;
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
10
|
function changeDirectory(projectRoot, changeName) {
|
|
24
11
|
return path.join(projectRoot, 'openspec', 'changes', changeName);
|
|
25
12
|
}
|
|
@@ -64,21 +51,32 @@ function parseSelection(source) {
|
|
|
64
51
|
throw new Error('current change selection change must be a string');
|
|
65
52
|
}
|
|
66
53
|
assertOpenSpecChangeName(record.change);
|
|
67
|
-
|
|
54
|
+
// `branch` may be absent in files written by early 0.4.0-beta.6 builds.
|
|
55
|
+
if (record.branch !== undefined && record.branch !== null && typeof record.branch !== 'string') {
|
|
68
56
|
throw new Error('current change selection branch must be a string or null');
|
|
69
57
|
}
|
|
70
58
|
return {
|
|
71
59
|
version: 1,
|
|
72
60
|
change: record.change,
|
|
73
|
-
branch: record.branch,
|
|
61
|
+
branch: record.branch ?? null,
|
|
74
62
|
};
|
|
75
63
|
}
|
|
76
64
|
export async function selectCurrentChange(projectRoot, changeName) {
|
|
77
65
|
await validateActiveChange(projectRoot, changeName);
|
|
66
|
+
const outcome = await resolveBranchBinding(changeDirectory(projectRoot, changeName), {
|
|
67
|
+
heal: true,
|
|
68
|
+
cwd: projectRoot,
|
|
69
|
+
});
|
|
70
|
+
if (outcome.status === 'drift') {
|
|
71
|
+
throw new Error(driftStaleReason(changeName, outcome.boundBranch, outcome.currentBranch));
|
|
72
|
+
}
|
|
73
|
+
if (outcome.status === 'unbound-detached') {
|
|
74
|
+
throw new Error(unboundDetachedMessage(changeName));
|
|
75
|
+
}
|
|
78
76
|
const selection = {
|
|
79
77
|
version: 1,
|
|
80
78
|
change: changeName,
|
|
81
|
-
branch: currentBranch
|
|
79
|
+
branch: outcome.currentBranch,
|
|
82
80
|
};
|
|
83
81
|
const file = currentChangeFile(projectRoot);
|
|
84
82
|
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
@@ -117,11 +115,30 @@ export async function resolveCurrentChange(projectRoot) {
|
|
|
117
115
|
reason: error instanceof Error ? error.message : String(error),
|
|
118
116
|
};
|
|
119
117
|
}
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
// Resolution is a read path (the PreToolUse hook runs it on every tool
|
|
119
|
+
// call), so it never heals: heal happens on select/check/guard instead.
|
|
120
|
+
const outcome = await resolveBranchBinding(changeDirectory(projectRoot, selection.change), {
|
|
121
|
+
heal: false,
|
|
122
|
+
cwd: projectRoot,
|
|
123
|
+
});
|
|
124
|
+
if (outcome.status === 'drift') {
|
|
125
|
+
return {
|
|
126
|
+
status: 'stale',
|
|
127
|
+
reason: driftStaleReason(selection.change, outcome.boundBranch, outcome.currentBranch),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (outcome.status === 'unbound-detached') {
|
|
131
|
+
return { status: 'stale', reason: unboundDetachedMessage(selection.change) };
|
|
132
|
+
}
|
|
133
|
+
if (outcome.status === 'ok') {
|
|
134
|
+
return { status: 'selected', selection };
|
|
135
|
+
}
|
|
136
|
+
// No bound branch governs yet (isolation unset or binding not healed):
|
|
137
|
+
// fall back to comparing against the branch recorded at selection time.
|
|
138
|
+
if (selection.branch !== null && outcome.currentBranch !== selection.branch) {
|
|
122
139
|
return {
|
|
123
140
|
status: 'stale',
|
|
124
|
-
reason: `current change '${selection.change}' was selected on branch '${selection.branch}', current branch is '${
|
|
141
|
+
reason: `current change '${selection.change}' was selected on branch '${selection.branch}', current branch is '${outcome.currentBranch ?? 'detached HEAD'}'`,
|
|
125
142
|
};
|
|
126
143
|
}
|
|
127
144
|
return { status: 'selected', selection };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classic-current-change.js","sourceRoot":"","sources":["../../../domains/comet-classic/classic-current-change.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"classic-current-change.js","sourceRoot":"","sources":["../../../domains/comet-classic/classic-current-change.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classic-guard.d.ts","sourceRoot":"","sources":["../../../domains/comet-classic/classic-guard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAwB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"classic-guard.d.ts","sourceRoot":"","sources":["../../../domains/comet-classic/classic-guard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAwB,MAAM,kBAAkB,CAAC;AAu7BpF,eAAO,MAAM,mBAAmB,EAAE,qBAmDjC,CAAC"}
|
|
@@ -12,6 +12,7 @@ import { CLASSIC_GUARD_TRANSITION_EVENT, applyClassicTransition } from './classi
|
|
|
12
12
|
import { classicValidateCommand } from './classic-validate-command.js';
|
|
13
13
|
import { readClassicState } from './classic-store.js';
|
|
14
14
|
import { readClassicConfigValue } from './classic-project-config.js';
|
|
15
|
+
import { driftBlockedMessage, resolveBranchBinding, unboundDetachedMessage, } from './classic-branch-binding.js';
|
|
15
16
|
const GREEN = '\u001b[32m';
|
|
16
17
|
const RED = '\u001b[31m';
|
|
17
18
|
const YELLOW = '\u001b[33m';
|
|
@@ -411,17 +412,43 @@ async function planTasksAllDone(changeDir) {
|
|
|
411
412
|
}
|
|
412
413
|
return pass();
|
|
413
414
|
}
|
|
415
|
+
async function boundBranchMatches(changeDir, change) {
|
|
416
|
+
let outcome;
|
|
417
|
+
try {
|
|
418
|
+
outcome = await resolveBranchBinding(changeDir, { heal: true, cwd: process.cwd() });
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
throw new GuardFailure(`ERROR: ${error instanceof Error ? error.message : String(error)}`);
|
|
422
|
+
}
|
|
423
|
+
switch (outcome.status) {
|
|
424
|
+
case 'drift':
|
|
425
|
+
return fail(driftBlockedMessage(change, outcome.boundBranch, outcome.currentBranch));
|
|
426
|
+
case 'unbound-detached':
|
|
427
|
+
return fail(unboundDetachedMessage(change));
|
|
428
|
+
case 'healed':
|
|
429
|
+
return pass(`bound_branch lazily set to ${outcome.branch}`);
|
|
430
|
+
case 'needs-heal':
|
|
431
|
+
case 'ok':
|
|
432
|
+
case 'not-applicable':
|
|
433
|
+
return pass();
|
|
434
|
+
default: {
|
|
435
|
+
const exhaustive = outcome;
|
|
436
|
+
throw new Error(`unhandled branch binding status: ${JSON.stringify(exhaustive)}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
414
440
|
async function isolationSelected(changeDir, change) {
|
|
415
441
|
const isolation = await readField(changeDir, 'isolation');
|
|
416
|
-
if (isolation === 'branch' || isolation === 'worktree')
|
|
442
|
+
if (isolation === 'current' || isolation === 'branch' || isolation === 'worktree')
|
|
417
443
|
return pass();
|
|
418
|
-
|
|
444
|
+
const allowedValues = '<current|branch|worktree>';
|
|
445
|
+
return fail(`isolation must be current, branch, or worktree, got '${isolation || 'null'}'\nNext: choose a valid workspace mode, prepare it when needed, then run:\n comet state set ${change} isolation ${allowedValues}`);
|
|
419
446
|
}
|
|
420
447
|
async function buildModeSelected(changeDir, change) {
|
|
421
448
|
const buildMode = await readField(changeDir, 'build_mode');
|
|
422
449
|
if (['subagent-driven-development', 'executing-plans', 'direct'].includes(buildMode))
|
|
423
450
|
return pass();
|
|
424
|
-
return fail(`build_mode must be selected before leaving build, got '${buildMode || 'null'}'\nNext: ask the user to choose an execution mode, then run:\n
|
|
451
|
+
return fail(`build_mode must be selected before leaving build, got '${buildMode || 'null'}'\nNext: ask the user to choose an execution mode, then run:\n comet state set ${change} build_mode <subagent-driven-development|executing-plans>`);
|
|
425
452
|
}
|
|
426
453
|
async function buildModeAllowedForWorkflow(changeDir) {
|
|
427
454
|
const workflow = await readField(changeDir, 'workflow');
|
|
@@ -442,7 +469,7 @@ async function subagentDispatchConfirmed(changeDir, change) {
|
|
|
442
469
|
return pass();
|
|
443
470
|
if (subagentDispatch === 'confirmed')
|
|
444
471
|
return pass();
|
|
445
|
-
return fail(`subagent_dispatch must be confirmed before using build_mode=subagent-driven-development\nNext: confirm the current platform has a real background subagent/Task/multi-agent dispatcher, then run:\n
|
|
472
|
+
return fail(`subagent_dispatch must be confirmed before using build_mode=subagent-driven-development\nNext: confirm the current platform has a real background subagent/Task/multi-agent dispatcher, then run:\n comet state set ${change} subagent_dispatch confirmed\nIf dispatch is unavailable, return to /comet-build Step 2 with subagent-driven-development removed. When executing-plans is the only valid mode, run:\n comet state set ${change} build_mode executing-plans`);
|
|
446
473
|
}
|
|
447
474
|
async function tddModeSelected(changeDir, change) {
|
|
448
475
|
const workflow = await readField(changeDir, 'workflow');
|
|
@@ -451,7 +478,7 @@ async function tddModeSelected(changeDir, change) {
|
|
|
451
478
|
const tddMode = await readField(changeDir, 'tdd_mode');
|
|
452
479
|
if (tddMode === 'tdd' || tddMode === 'direct')
|
|
453
480
|
return pass();
|
|
454
|
-
return fail(`tdd_mode must be tdd or direct for full workflow, got '${tddMode || 'null'}'\nNext: ask the user to choose TDD enforcement level, then run:\n
|
|
481
|
+
return fail(`tdd_mode must be tdd or direct for full workflow, got '${tddMode || 'null'}'\nNext: ask the user to choose TDD enforcement level, then run:\n comet state set ${change} tdd_mode <tdd|direct>`);
|
|
455
482
|
}
|
|
456
483
|
async function reviewModeSelected(changeDir, change) {
|
|
457
484
|
const workflow = await readField(changeDir, 'workflow');
|
|
@@ -461,7 +488,7 @@ async function reviewModeSelected(changeDir, change) {
|
|
|
461
488
|
if (reviewMode === 'off' || reviewMode === 'standard' || reviewMode === 'thorough') {
|
|
462
489
|
return pass();
|
|
463
490
|
}
|
|
464
|
-
return fail(`review_mode must be off, standard, or thorough before leaving build, got '${reviewMode || 'null'}'\nNext: ask the user to choose review strength, then run:\n
|
|
491
|
+
return fail(`review_mode must be off, standard, or thorough before leaving build, got '${reviewMode || 'null'}'\nNext: ask the user to choose review strength, then run:\n comet state set ${change} review_mode <off|standard|thorough>`);
|
|
465
492
|
}
|
|
466
493
|
async function verificationReportExists(changeDir) {
|
|
467
494
|
const report = await readField(changeDir, 'verification_report');
|
|
@@ -493,7 +520,7 @@ async function designDocRecorded(changeDir, change) {
|
|
|
493
520
|
const designDoc = await readField(changeDir, 'design_doc');
|
|
494
521
|
if (designDoc && designDoc !== 'null' && existsSync(designDoc))
|
|
495
522
|
return pass();
|
|
496
|
-
return fail(`design_doc must point to an existing Superpowers Design Doc for full workflow before leaving design.\nNext: create the Design Doc and run:
|
|
523
|
+
return fail(`design_doc must point to an existing Superpowers Design Doc for full workflow before leaving design.\nNext: create the Design Doc and run: comet state set ${change} design_doc <path>`);
|
|
497
524
|
}
|
|
498
525
|
async function designHandoffContextValid(changeDir, change) {
|
|
499
526
|
const context = await readField(changeDir, 'handoff_context');
|
|
@@ -502,18 +529,18 @@ async function designHandoffContextValid(changeDir, change) {
|
|
|
502
529
|
return fail(`handoff_context is missing from .comet.yaml\nNext: run node "$COMET_HANDOFF" ${change} design --write before invoking Superpowers.`);
|
|
503
530
|
}
|
|
504
531
|
if (!(await nonempty(context))) {
|
|
505
|
-
return fail(`handoff_context does not point to a non-empty file: ${context}\nNext: regenerate the design handoff with comet
|
|
532
|
+
return fail(`handoff_context does not point to a non-empty file: ${context}\nNext: regenerate the design handoff with comet handoff ${change} design --write.`);
|
|
506
533
|
}
|
|
507
534
|
if (!/^[a-f0-9]{64}$/u.test(recordedHash)) {
|
|
508
|
-
return fail(`handoff_hash is missing or invalid: ${recordedHash || 'null'}\nNext: regenerate the design handoff with comet
|
|
535
|
+
return fail(`handoff_hash is missing or invalid: ${recordedHash || 'null'}\nNext: regenerate the design handoff with comet handoff ${change} design --write.`);
|
|
509
536
|
}
|
|
510
537
|
const actualHash = await computeHandoffHash(changeDir);
|
|
511
538
|
if (actualHash !== recordedHash) {
|
|
512
|
-
return fail(`OpenSpec artifacts changed after handoff was generated.\nExpected handoff_hash: ${recordedHash}\nActual handoff_hash: ${actualHash}\nNext:
|
|
539
|
+
return fail(`OpenSpec artifacts changed after handoff was generated.\nExpected handoff_hash: ${recordedHash}\nActual handoff_hash: ${actualHash}\nNext: run comet handoff ${change} design --write so Superpowers receives the current OpenSpec context.`);
|
|
513
540
|
}
|
|
514
541
|
const markdown = `${context.replace(/\.json$/u, '')}.md`;
|
|
515
542
|
if (!(await nonempty(markdown))) {
|
|
516
|
-
return fail(`design handoff markdown is missing or empty: ${markdown}\nNext: regenerate the design handoff with comet
|
|
543
|
+
return fail(`design handoff markdown is missing or empty: ${markdown}\nNext: regenerate the design handoff with comet handoff ${change} design --write.`);
|
|
517
544
|
}
|
|
518
545
|
return pass();
|
|
519
546
|
}
|
|
@@ -660,6 +687,7 @@ async function guardDesignChecks(output, changeDir, change) {
|
|
|
660
687
|
}
|
|
661
688
|
async function guardBuildChecks(output, changeDir, change, run) {
|
|
662
689
|
return runChecks(output, [
|
|
690
|
+
check('bound branch matches workspace mode', () => boundBranchMatches(changeDir, change)),
|
|
663
691
|
check('isolation selected', () => isolationSelected(changeDir, change)),
|
|
664
692
|
check('build_mode selected', () => buildModeSelected(changeDir, change)),
|
|
665
693
|
check('build_mode allowed for workflow', () => buildModeAllowedForWorkflow(changeDir)),
|
|
@@ -686,6 +714,7 @@ async function guardBuildChecks(output, changeDir, change, run) {
|
|
|
686
714
|
}
|
|
687
715
|
async function guardVerifyChecks(output, changeDir, change, run) {
|
|
688
716
|
return runChecks(output, [
|
|
717
|
+
check('bound branch matches workspace mode', () => boundBranchMatches(changeDir, change)),
|
|
689
718
|
check('tasks.md all tasks checked', () => tasksAllDone(changeDir)),
|
|
690
719
|
// Verification command runs after tasks check — no point running tests
|
|
691
720
|
// if tasks.md is incomplete.
|
|
@@ -700,21 +729,26 @@ async function guardVerifyChecks(output, changeDir, change, run) {
|
|
|
700
729
|
return pass();
|
|
701
730
|
return documentLanguageMatchesConfigured(changeDir, report);
|
|
702
731
|
}),
|
|
703
|
-
check('branch_status=handled', async () => (await branchStatusHandled(changeDir)) ? pass() : fail('')),
|
|
704
732
|
]);
|
|
705
733
|
}
|
|
706
|
-
async function guardArchiveChecks(output, changeDir) {
|
|
734
|
+
async function guardArchiveChecks(output, changeDir, change) {
|
|
707
735
|
return runChecks(output, [
|
|
736
|
+
check('bound branch matches workspace mode', () => boundBranchMatches(changeDir, change)),
|
|
708
737
|
check('archived is true', async () => ((await archivedIsTrue(changeDir)) ? pass() : fail(''))),
|
|
709
738
|
check('proposal.md exists', async () => (await nonempty(path.join(changeDir, 'proposal.md'))) ? pass() : fail('')),
|
|
710
739
|
check('design.md exists', async () => (await nonempty(path.join(changeDir, 'design.md'))) ? pass() : fail('')),
|
|
711
740
|
check('tasks.md all tasks checked', () => tasksAllDone(changeDir)),
|
|
741
|
+
check('branch_status=handled', async () => (await branchStatusHandled(changeDir)) ? pass() : fail('')),
|
|
712
742
|
]);
|
|
713
743
|
}
|
|
714
|
-
async function applyStateUpdate(output, change, changeDir, phase
|
|
744
|
+
async function applyStateUpdate(output, change, changeDir, phase) {
|
|
715
745
|
const event = CLASSIC_GUARD_TRANSITION_EVENT[phase];
|
|
716
746
|
if (!event)
|
|
717
747
|
return;
|
|
748
|
+
// Re-read instead of reusing the run context captured before the checks:
|
|
749
|
+
// boundBranchMatches may have lazily healed bound_branch on disk, and a
|
|
750
|
+
// stale projection would write the pre-heal null back over it.
|
|
751
|
+
const context = await ensureClassicRuntimeRun(changeDir);
|
|
718
752
|
const result = applyClassicTransition(context.classic, event);
|
|
719
753
|
await transitionClassicRuntimeRun(changeDir, result.classic, context.run, {
|
|
720
754
|
event,
|
|
@@ -768,7 +802,7 @@ export const classicGuardCommand = async (args, options) => {
|
|
|
768
802
|
else if (phase === 'verify')
|
|
769
803
|
blocked = await guardVerifyChecks(output, changeDir, change, runContext.run);
|
|
770
804
|
else
|
|
771
|
-
blocked = await guardArchiveChecks(output, changeDir);
|
|
805
|
+
blocked = await guardArchiveChecks(output, changeDir, change);
|
|
772
806
|
if (blocked) {
|
|
773
807
|
output.stderr.push('');
|
|
774
808
|
output.stderr.push(red('BLOCKED — fix failing checks before proceeding to next phase'));
|
|
@@ -777,7 +811,7 @@ export const classicGuardCommand = async (args, options) => {
|
|
|
777
811
|
output.stderr.push('');
|
|
778
812
|
output.stderr.push(green('ALL CHECKS PASSED — ready for next phase'));
|
|
779
813
|
if (flag === '--apply') {
|
|
780
|
-
await applyStateUpdate(output, change, changeDir, phase
|
|
814
|
+
await applyStateUpdate(output, change, changeDir, phase);
|
|
781
815
|
}
|
|
782
816
|
return output.toResult(0);
|
|
783
817
|
}
|