@ornexus/neocortex 4.60.23 → 4.60.24
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/dist/sbom.cdx.json +23 -23
- package/install.js +67 -10
- package/install.ps1 +39 -8
- package/install.sh +18 -6
- package/package.json +5 -2
- package/packages/client/dist/adapters/adapter-registry.d.ts +2 -2
- package/packages/client/dist/adapters/adapter-registry.js +1 -1
- package/packages/client/dist/adapters/grok-adapter.d.ts +11 -0
- package/packages/client/dist/adapters/grok-adapter.js +2 -0
- package/packages/client/dist/adapters/index.d.ts +1 -0
- package/packages/client/dist/adapters/index.js +1 -1
- package/packages/client/dist/adapters/platform-detector.d.ts +1 -1
- package/packages/client/dist/adapters/platform-detector.js +1 -1
- package/packages/client/dist/agent/refresh-stubs.js +2 -2
- package/packages/client/dist/cli.js +21 -2
- package/packages/client/dist/commands/invoke.d.ts +20 -21
- package/packages/client/dist/commands/invoke.js +59 -55
- package/packages/client/dist/commands/story-checkpoint.d.ts +15 -0
- package/packages/client/dist/commands/story-checkpoint.js +1 -0
- package/packages/client/dist/config.js +1 -1
- package/packages/client/dist/generated/command-registry.generated.d.ts +18 -52
- package/packages/client/dist/generated/command-registry.generated.js +1 -1
- package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +67 -0
- package/packages/client/dist/git/direct-yolo-checkpoint.js +3 -0
- package/packages/client/dist/git/git-lifecycle-store.d.ts +198 -0
- package/packages/client/dist/git/git-lifecycle-store.js +4 -0
- package/packages/client/dist/git/secure-filesystem-boundary.d.ts +26 -0
- package/packages/client/dist/git/secure-filesystem-boundary.js +123 -0
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -1
- package/packages/client/dist/index.d.ts +2 -0
- package/packages/client/dist/index.js +1 -1
- package/packages/client/dist/memory/shared-project-memory-types.d.ts +29 -2
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -2
- package/packages/client/dist/policy/subagent-approval-policy.js +1 -1
- package/packages/client/dist/runner/headless/continuous-story-workspace.d.ts +131 -0
- package/packages/client/dist/runner/headless/continuous-story-workspace.js +58 -0
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.d.ts +23 -0
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -0
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +15 -0
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +28 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +12 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +134 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -0
- package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -1
- package/packages/client/dist/runner/headless/run-yolo.js +1 -1
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +7 -2
- package/packages/client/dist/runner/headless/run-yoloop.js +8 -1
- package/packages/client/dist/runner/headless/types.d.ts +1 -1
- package/packages/client/dist/runner/headless/types.js +2 -2
- package/packages/client/dist/runner-cli.js +0 -0
- package/packages/client/dist/state/project-state-snapshot.js +1 -1
- package/packages/client/dist/state/state-json-repair.d.ts +9 -0
- package/packages/client/dist/state/state-json-repair.js +3 -3
- package/packages/client/dist/tier/tier-aware-client.js +1 -1
- package/packages/client/dist/yoloop/invoke-hooks.d.ts +13 -10
- package/packages/client/dist/yoloop/invoke-hooks.js +8 -5
- package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1
- package/packages/shared/dist/generated/command-registry.generated.js +18 -66
- package/packages/shared/dist/generated/invocation-schema.generated.js +5 -25
- package/packages/shared/dist/invocation/index.d.ts +1 -1
- package/packages/shared/dist/yoloop/epic-terminal-git.js +227 -0
- package/packages/shared/dist/yoloop/planning-graph.js +119 -0
- package/packages/shared/dist/yoloop/public-story-write-set.js +27 -0
- package/packages/shared/dist/yoloop/wave-decision-receipt.js +19 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/neocortex.md +18 -0
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +21 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +20 -1
- package/targets-stubs/cursor/agent.md +20 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/gemini-cli/gemini.md +18 -0
- package/targets-stubs/grok/README.md +13 -0
- package/targets-stubs/grok/SKILL.md +50 -0
- package/targets-stubs/grok/config-mcp.toml +22 -0
- package/targets-stubs/grok/install-grok.sh +31 -0
- package/targets-stubs/kimi/neocortex.md +18 -0
- package/targets-stubs/openclaw/SKILL.md +18 -0
- package/targets-stubs/opencode/neocortex-root.md +20 -1
- package/targets-stubs/vscode/neocortex.agent.md +20 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import{execFile as at,spawn as Je}from"node:child_process";import{createHash as G,randomBytes as Me}from"node:crypto";import{lstat as le,readFile as B,realpath as X,stat as ct}from"node:fs/promises";import{basename as $,dirname as O,isAbsolute as Ke,join as D,relative as st,resolve as dt}from"node:path";import{promisify as ut}from"node:util";import{admitPreparedStoryBundle as ht}from"./prepared-story-bundle.js";import{acquireGitLifecyclePhysicalIntegrationLock as ft,assertGitLifecyclePrivateDirectory as q,assertGitLifecyclePrivateFile as V,applyGitLifecycleRuntimeOverlay as re,computeImmutableStoryQaEvidenceDigest as pt,computeP205StoryQaEvidenceDigest as lt,ensureGitLifecyclePrivateChildDirectory as be,ensureRuntimeEpic as ye,ensureRuntimeStory as yt,gitLifecycleRuntimeDirectory as wt,mutateGitLifecycleRuntime as Y,P205_COMPLETE_COMMAND as mt,readGitLifecycleRuntime as F,releaseGitLifecyclePhysicalIntegrationLock as gt,removeGitLifecyclePrivateDirectory as oe,verifyAcceptedGitLifecycleStoryCheckpoint as Re,verifyGitLifecyclePhysicalIntegrationLock as ke}from"../../git/git-lifecycle-store.js";import{anchoredAtomicWriteFile as St,anchoredCreateDirectory as xe,anchoredDirectoryIdentity as It,anchoredExecuteGit as Ee,anchoredEnsureDirectory as vt,anchoredRemoveFile as bt}from"../../git/secure-filesystem-boundary.js";const Ae=ut(at),Rt=String.raw`
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const cp = require('node:child_process');
|
|
4
|
+
const [expectedParentDev, expectedParentIno, name, expectedChildDev, expectedChildIno, encoded, handshake] = process.argv.slice(1);
|
|
5
|
+
const fail = (code) => { process.stderr.write(code); process.exit(73); };
|
|
6
|
+
const safeName = typeof name === 'string' && name.length > 0 && name.length <= 255
|
|
7
|
+
&& !name.includes('/') && !name.includes('\\') && !name.includes('\0') && name !== '.' && name !== '..';
|
|
8
|
+
if (!safeName) fail('continuous-child-name-invalid');
|
|
9
|
+
const parent = fs.statSync('.', { bigint: true });
|
|
10
|
+
if (!parent.isDirectory() || String(parent.dev) !== expectedParentDev || String(parent.ino) !== expectedParentIno) {
|
|
11
|
+
fail('continuous-child-parent-anchor-mismatch');
|
|
12
|
+
}
|
|
13
|
+
const childEntry = fs.lstatSync(name, { bigint: true });
|
|
14
|
+
if (!childEntry.isDirectory() || childEntry.isSymbolicLink()
|
|
15
|
+
|| String(childEntry.dev) !== expectedChildDev || String(childEntry.ino) !== expectedChildIno) {
|
|
16
|
+
fail('continuous-child-anchor-mismatch');
|
|
17
|
+
}
|
|
18
|
+
process.chdir(name);
|
|
19
|
+
const handed = fs.statSync('.', { bigint: true });
|
|
20
|
+
if (!handed.isDirectory() || String(handed.dev) !== expectedChildDev || String(handed.ino) !== expectedChildIno) {
|
|
21
|
+
fail('continuous-child-handoff-mismatch');
|
|
22
|
+
}
|
|
23
|
+
if (handshake === '1') {
|
|
24
|
+
process.stderr.write('continuous-child-handoff-ready\n');
|
|
25
|
+
fs.readFileSync(0);
|
|
26
|
+
}
|
|
27
|
+
let invocation;
|
|
28
|
+
try { invocation = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8')); } catch { fail('continuous-child-invocation-invalid'); }
|
|
29
|
+
if (!invocation || typeof invocation.command !== 'string' || invocation.command.length === 0 || invocation.command.length > 4096
|
|
30
|
+
|| invocation.command.includes('\0') || !Array.isArray(invocation.args) || invocation.args.length > 512
|
|
31
|
+
|| invocation.args.some((arg) => typeof arg !== 'string' || arg.length > 32768 || arg.includes('\0'))) {
|
|
32
|
+
fail('continuous-child-invocation-invalid');
|
|
33
|
+
}
|
|
34
|
+
process.umask(0o077);
|
|
35
|
+
const childEnv = { ...process.env };
|
|
36
|
+
for (const key of ['GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_OBJECT_DIRECTORY',
|
|
37
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES', 'GIT_COMMON_DIR', 'GIT_NAMESPACE', 'GIT_CEILING_DIRECTORIES']) delete childEnv[key];
|
|
38
|
+
const runtime = cp.spawn(invocation.command, invocation.args, { cwd: '.', env: childEnv, shell: false, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
39
|
+
runtime.stdout.pipe(process.stdout);
|
|
40
|
+
runtime.stderr.pipe(process.stderr);
|
|
41
|
+
const forward = (signal) => { try { runtime.kill(signal); } catch {} };
|
|
42
|
+
process.on('SIGTERM', () => forward('SIGTERM'));
|
|
43
|
+
process.on('SIGINT', () => forward('SIGINT'));
|
|
44
|
+
runtime.on('error', (error) => fail('continuous-child-command-error:' + String(error && error.code || 'UNKNOWN')));
|
|
45
|
+
runtime.on('close', (code, signal) => {
|
|
46
|
+
if (signal) process.kill(process.pid, signal);
|
|
47
|
+
else process.exit(Number.isInteger(code) ? code : 1);
|
|
48
|
+
});
|
|
49
|
+
`;function cr(e,r={}){return async(t,o,n={})=>Ot(e,t,o,n,r)}function sr(e={}){let r=Promise.resolve();return{async prepare(t){if((e.platform??process.platform)==="win32")return f("continuous-sandbox-platform-unsupported");if(!/^[a-f0-9]{64}$/.test(t.dispatchId))return f("continuous-sandbox-dispatch-invalid");if(!ce(t.targetRef))return f("continuous-sandbox-target-invalid");if(!Wt(t.executionBranch))return f("continuous-execution-branch-invalid");if(!/^[a-f0-9]{64}$/.test(t.graphRevision))return f("continuous-graph-revision-invalid");const o=qt(t.authorizedWriteSet);if(o.length===0||o.length!==t.authorizedWriteSet.length)return f("continuous-authorized-write-set-invalid");const n=ze(o),a=r;let c=()=>{};r=new Promise(s=>{c=s}),await a;let i,d;try{const s=await xt(t.projectRoot),g=await P(s,["rev-parse","HEAD"]),S=await Se(s,t.epicId,t.storyId),v=S.revision,A=await wt(s),w=await be(A,"leases"),j=D(w,t.dispatchId);try{await xe(w,t.dispatchId),await q(j,w)}catch(m){if(!W(m,"EEXIST"))throw m;await q(j,w);const l=await ue(j,w);if(l!==void 0&&Vt(l.pid))return f("continuous-sandbox-lease-active");if(!l||!await oe(j,w,async E=>tt(await ue(E,w),l)))return f("continuous-sandbox-lease-owner-replaced");await xe(w,t.dispatchId),await q(j,w)}i=j,d=Object.freeze({pid:process.pid,createdAt:new Date().toISOString(),nonce:Me(16).toString("hex")}),await te(j,"owner.json",Buffer.from(JSON.stringify(d)),e.beforeSandboxWriteCommit),await V(D(j,"owner.json"),j);const b=await be(A,"sandboxes"),p=D(b,t.dispatchId.slice(0,20)),I=await Te(p,b);let R,u;const k=I?.preparedAt??new Date().toISOString(),x=I?.workspaceOwnerNonce??Me(16).toString("hex");if(I){if(I.projectRoot!==s||I.storyId!==t.storyId||I.targetRef!==t.targetRef||I.dispatchId!==t.dispatchId||I.epicId!==t.epicId||I.executionBranch!==t.executionBranch||I.graphRevision!==t.graphRevision||I.claimRevision!==n||I.graphAuthorityRevision!==v||I.graphAuthorityEpoch!==S.epoch||I.graphAuthorityStoryStatus!==S.storyStatus||!et(I.authorizedWriteSet,o)||(R=I.contextSnapshots.map(m=>({path:m.path,...m.contentBase64!==void 0?{content:Buffer.from(m.contentBase64,"base64")}:{}})),u=await It(p),u.dev!==I.workspaceIdentity.dev||u.ino!==I.workspaceIdentity.ino))return f("continuous-sandbox-recovery-mismatch")}else await oe(p,b),u=await xe(b,$(p)),await q(p,b),await ne(b,$(p),u,["init","--quiet"]),await At(s,p),await Et(s,b,$(p),u),await ne(b,$(p),u,["remote","add","neocortex-root",s]),await ne(b,$(p),u,["fetch","--quiet","--no-tags","neocortex-root",g]),await ne(b,$(p),u,["checkout","--quiet","--detach","FETCH_HEAD"]),R=await kt(s,p,t.epicId,t.targetRef,e.beforeSandboxWriteCommit),await Ft(p,b,{schemaVersion:1,projectRoot:s,storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,dispatchId:t.dispatchId,baseSha:g,preparedAt:k,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:R.map(m=>({path:m.path,...m.content!==void 0?{contentBase64:m.content.toString("base64")}:{}}))},e.beforeSandboxWriteCommit);return i=void 0,{ok:!0,value:{projectRoot:s,workspacePath:p,workspaceStrategy:"branchless_sandbox",storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,baseSha:I?.baseSha??g,dispatchId:t.dispatchId,preparedAt:k,leasePath:j,leaseOwnerNonce:d.nonce,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:R}}}catch{if(i&&d){const s=i,g=d;await oe(s,O(s),async S=>tt(await ue(S,O(s)),g)).catch(()=>{})}return f("continuous-sandbox-prepare-failed")}finally{c()}},async integrate(t,o){const n=await ue(t.leasePath,O(t.leasePath)).catch(()=>{}),a=await Te(t.workspacePath,O(t.workspacePath)).catch(()=>{});if(!n||n.nonce!==t.leaseOwnerNonce||a?.workspaceOwnerNonce!==t.workspaceOwnerNonce||a.dispatchId!==t.dispatchId||a.storyId!==t.storyId)return f("continuous-sandbox-owner-mismatch");const c=Ue(o?.nowIso??new Date().toISOString()),i=await ft(t.projectRoot,{kind:"continuous",storyId:t.storyId,sessionId:t.dispatchId,idempotencyKey:t.dispatchId,expiresAt:new Date(Date.parse(c)+1800*1e3).toISOString(),persistent:!1,createdAt:c});if(!i.ok)return f(i.reasonCode==="git-lifecycle-integration-backpressure"?"continuous-integration-backpressure":"continuous-integration-lease-failed");let d=[],s=!1,g=!1;try{const S=(await ie(t,["status","--porcelain"])).trimEnd(),v=await je(t,["rev-parse","HEAD"]);if(await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==t.executionBranch)return f("continuous-execution-branch-mismatch");const w=O(O(t.leasePath)),j=await be(w,"integrated"),b=D(j,t.dispatchId),p=await Qt(b,j);if(p?.childHeadSha===v&&p.bundle.storyId===t.storyId&&p.bundle.epicId===t.epicId&&p.bundle.executionBranch===t.executionBranch&&p.bundle.graphRevision===t.graphRevision&&p.bundle.claimRevision===t.claimRevision&&et(p.bundle.authorizedWriteSet,t.authorizedWriteSet)&&p.checkpoint.idempotencyKey===t.dispatchId&&p.checkpoint.bundleId===p.bundle.bundleId&&p.checkpoint.bundleDigest===p.bundle.bundleDigest&&p.checkpoint.graphRevision===t.graphRevision&&p.checkpoint.claimRevision===t.claimRevision&&await ae(t.projectRoot,["merge-base","--is-ancestor",p.rootHeadSha,"HEAD"])&&await Zt(t,p.checkpoint))return{ok:!0,value:{headSha:p.rootHeadSha,alreadyIntegrated:!0,bundle:p.bundle,checkpoint:p.checkpoint}};if(v!==t.baseSha)return f("continuous-sandbox-child-git-authority-denied");if(S.length===0)return f("continuous-bundle-empty");const I=S.split(`
|
|
50
|
+
`).some(y=>y.length>0&&y[0]!==" "&&y[0]!=="?");I||await je(t,["add","-A"]);const R=L(await ie(t,["diff","--cached","--name-only","-z",t.baseSha]));if(R.length===0||R.some(y=>!ce(y)))return f("continuous-integration-write-set-invalid");if(!await jt(t,["merge-base","--is-ancestor",t.baseSha,v]))return f("continuous-bundle-base-not-ancestor");if(!await ae(t.projectRoot,["merge-base","--is-ancestor",t.baseSha,"HEAD"]))return f("continuous-root-base-not-ancestor");const u=o?.nowIso??new Date().toISOString(),k=Mt(o?.receiptRefs,t.dispatchId),x=await ie(t,["diff","--cached","--binary",t.baseSha]),m={schemaVersion:1,storyId:t.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:t.baseSha,bundleDigest:G("sha256").update(x).digest("hex"),graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,contextDigests:Object.fromEntries(t.contextSnapshots.map(y=>[y.path,G("sha256").update(y.content??Buffer.alloc(0)).digest("hex")])),validationRefs:k,createdAt:t.preparedAt,expiresAt:new Date(Date.parse(t.preparedAt)+1440*60*1e3).toISOString(),branchless:!0},l=Object.freeze({...m,bundleId:ze(m)}),E=await Xt(t,l);if(E){const y=await Ut(t,l,E);if(y)return await Le(b,v,E.headSha,l,y,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:y}}}if(!E&&await Jt(t.projectRoot,t.epicId)!==t.graphAuthorityRevision)return f("continuous-graph-revision-stale");if(E){const y=await Ze({lease:t,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!y.ok)return y;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:E.headSha});const N=await Qe({lease:t,physicalLock:i,checkpointAuthority:E.checkpointAuthority,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:[...k,`bundle:${l.bundleId}`,y.value.qaReceipt.receiptRef,y.value.reviewReceipt.receiptRef],qaReceipt:y.value.qaReceipt,reviewReceipt:y.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return N.ok?(await Le(b,v,E.headSha,l,N.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:N.value}}):N}if(I)return f("continuous-sandbox-child-git-authority-denied");if(L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])).length>0)return f("continuous-integration-root-index-dirty");const J=new Set(t.contextSnapshots.map(y=>y.path));if(R.filter(y=>!t.authorizedWriteSet.some(N=>ge(N,y))).length>0)return f("continuous-bundle-write-set-unauthorized");const M=R.filter(y=>!J.has(y)),ve=new Set(L(await z(t.projectRoot,["diff","--name-only","-z",`${t.baseSha}..HEAD`])));if(M.some(y=>ve.has(y)))return f("continuous-bundle-intervening-conflict");const he=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(M.some(y=>he.has(y)))return f("continuous-integration-root-conflict");d=await Bt(t.projectRoot,[...new Set([...R,".neocortex/state.json"])]);const H=await Pt(t,u);if(!H.ok)return H;const K=ht({bundle:l,payload:Buffer.from(x),expected:{epicId:t.epicId,storyId:t.storyId,executionBranch:t.executionBranch,baseSha:t.baseSha,graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,nowIso:u},writerLease:H.value});if(K.length>0)return await Ne(t.projectRoot,d),f(`continuous-bundle-admission-${K[0]}`);const fe=await P(t.projectRoot,["rev-parse","HEAD"]);let Q;await e.beforeRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:fe});try{await Y(t.projectRoot,y=>{const N=h(ye(y,t.epicId).branch_lease);if(N?.ownerStoryId!==t.storyId||N.sessionId!==t.dispatchId||N.idempotencyKey!==t.dispatchId||Date.parse(String(N.expiresAt))<=Date.now())throw new Error("continuous-checkpoint-writer-lease-lost")},{preCommit:async y=>{const N=await Se(t.projectRoot,t.epicId,t.storyId,y);if(N.revision!==t.graphAuthorityRevision||N.epoch!==t.graphAuthorityEpoch||N.storyStatus!==t.graphAuthorityStoryStatus)throw new Error("continuous-graph-revision-stale");if(!await ke(i.path,i.owner))throw new Error("continuous-integration-lock-raced");const rt=await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),ot=await P(t.projectRoot,["rev-parse","HEAD"]);if(rt!==t.executionBranch||ot!==fe)throw new Error("continuous-integration-head-raced");const nt=L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])),it=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(nt.length>0)throw new Error("continuous-integration-root-index-dirty");if(M.some(_=>it.has(_)))throw new Error("continuous-integration-root-conflict");if(g=!0,M.length>0){const _=await ie(t,["diff","--cached","--binary",t.baseSha,"--",...M]);if(_.length>0&&!await Nt(t.projectRoot,["apply","--index","--3way","--whitespace=nowarn"],_))throw new Error("continuous-integration-conflict")}for(const _ of t.contextSnapshots){if(!R.includes(_.path))continue;const qe=await De(D(t.projectRoot,_.path)),We=await Dt(t,_.path),He=_.path===".neocortex/state.json"?Lt(_.content,qe,zt(_.content,We,t.storyId)):Gt(_.content,qe,We);if(!He.ok)throw new Error(_.path===".neocortex/state.json"?"continuous-state-merge-conflict":"continuous-context-merge-conflict");await te(t.projectRoot,_.path,He.value),await P(t.projectRoot,["add","-A","--",_.path])}if(R.includes(".neocortex/state.json")&&await P(t.projectRoot,["add","-A","--",".neocortex/state.json"]),await ae(t.projectRoot,["diff","--cached","--quiet"]))throw new Error("continuous-integration-empty-after-admission");Q=await Se(t.projectRoot,t.epicId,t.storyId,y),await P(t.projectRoot,["commit","-m",`feat(yoloop): integrate ${t.storyId}`,"-m",`Neocortex-Story: ${t.storyId}`,"-m",`Neocortex-Epic: ${t.epicId}`,"-m",`Neocortex-Execution-Branch: ${t.executionBranch}`,"-m",`Neocortex-Prepared-Base: ${t.baseSha}`,"-m",`Neocortex-Dispatch: ${t.dispatchId}`,"-m",`Neocortex-Bundle: ${l.bundleId}`,"-m",`Neocortex-Bundle-Digest: ${l.bundleDigest}`,"-m",`Neocortex-Graph-Revision: ${t.graphRevision}`,"-m",`Neocortex-Claim-Revision: ${t.claimRevision}`,"-m",`Neocortex-Checkpoint-Authority: ${Q.revision}`,"-m",`Neocortex-Checkpoint-Epoch: ${Q.epoch??"null"}`,"-m",`Neocortex-Checkpoint-Story-Status: ${Q.storyStatus??"null"}`]),s=!0}})}catch(y){g&&!s&&await Ne(t.projectRoot,d);const N=y instanceof Error&&/^continuous-/.test(y.message)?y.message:"continuous-integration-failed";return f(N)}const Z=await P(t.projectRoot,["rev-parse","HEAD"]);if(!Q)return f("continuous-checkpoint-authority-missing");await e.afterRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const U=await Ze({lease:t,bundle:l,baseSha:fe,headSha:Z,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!U.ok)return U;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const pe=await Qe({lease:t,physicalLock:i,checkpointAuthority:Q,bundle:l,baseSha:fe,headSha:Z,receiptRefs:[...k,`bundle:${l.bundleId}`,U.value.qaReceipt.receiptRef,U.value.reviewReceipt.receiptRef],qaReceipt:U.value.qaReceipt,reviewReceipt:U.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return pe.ok?(await Le(b,v,Z,l,pe.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:Z,alreadyIntegrated:!1,bundle:l,checkpoint:pe.value}}):pe}catch{return g&&!s&&d.length>0&&await Ne(t.projectRoot,d),f("continuous-integration-failed")}finally{await $t(t).catch(()=>{}),await gt(i.path,i.owner).catch(()=>{})}},async release(t,o){o||await oe(t.workspacePath,O(t.workspacePath),async n=>{const a=await Te(n,O(t.workspacePath)).catch(()=>{});return a?.workspaceOwnerNonce===t.workspaceOwnerNonce&&a.dispatchId===t.dispatchId&&a.storyId===t.storyId}),await oe(t.leasePath,O(t.leasePath),async n=>(await ue(n,O(t.leasePath)).catch(()=>{}))?.nonce===t.leaseOwnerNonce)}}}async function kt(e,r,t,o,n){const a=[...new Set([".neocortex/state.json",o,`docs/epics/epic-${Kt(t)}.md`])],c=[];for(const i of a){if(!ce(i))continue;const d=await De(D(e,i));c.push({path:i,...d!==void 0?{content:d}:{}}),d!==void 0&&await te(r,i,d,n)}return c}async function xt(e){const r=await P(e,["rev-parse","--show-toplevel"]),[t,o]=await Promise.all([X(r),X(e)]);if(t!==o)throw new Error("project root mismatch");return t}async function Et(e,r,t,o){for(const n of["user.name","user.email"]){const a=await ee(e,["config","--get",n]);a&&await ne(r,t,o,["config",n,a])}}async function At(e,r){const t=await F(e);await Y(r,o=>{for(const[n,a]of Object.entries(t.epics))o.epics[n]={...structuredClone(a),branch_lease:null};for(const[n,a]of Object.entries(t.stories))o.stories[n]=structuredClone(a)})}async function ne(e,r,t,o){return(await Ee(e,r,t,o)).toString("utf8").trim()}async function ie(e,r){return(await Ee(O(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,r)).toString("utf8")}async function je(e,r){return(await ie(e,r)).trim()}async function jt(e,r){try{return await je(e,r),!0}catch{return!1}}async function Dt(e,r){try{return await Ee(O(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,["show",`:${r}`])}catch{return}}async function Ot(e,r,t,o,n){const a=Date.now(),c=A=>({exitCode:null,timedOut:!1,durationMs:Date.now()-a,stdout:"",stderr:"",stdoutBytes:0,stderrBytes:0,...A});if(o.signal?.aborted)return c({signal:"SIGTERM",cancelled:!0});if(!r||r.length>4096||r.includes("\0")||t.length>512||t.some(A=>A.length>32768||A.includes("\0")))return c({exitCode:73,stderr:"continuous-child-invocation-invalid",stderrBytes:35});const i=O(e.workspacePath),d=await le(i,{bigint:!0}),s=await ct(i,{bigint:!0});if(!d.isDirectory()||d.isSymbolicLink()||!s.isDirectory()||d.dev!==s.dev||d.ino!==s.ino)return c({exitCode:73,stderr:"continuous-child-parent-invalid",stderrBytes:31});await n.beforeHandoff?.();const g=Buffer.from(JSON.stringify({command:r,args:[...t]})).toString("base64url"),S=o.maxOutputBytes??64e3,v=Math.max(1,Math.min(o.timeoutMs??600*1e3,1800*1e3));return await new Promise(A=>{const w=Je(process.execPath,["-e",Rt,String(s.dev),String(s.ino),$(e.workspacePath),e.workspaceIdentity.dev,e.workspaceIdentity.ino,g,n.afterHandoff?"1":"0"],{cwd:i,env:o.env,stdio:["pipe","pipe","pipe"]});let j="",b="",p=0,I=0,R=!1,u=!1,k=!1,x=!n.afterHandoff;const m=(C,J)=>{R||(R=!0,clearTimeout(E),o.signal?.removeEventListener("abort",l),A({exitCode:C,...J?{signal:J}:{},timedOut:u,...k?{cancelled:!0}:{},durationMs:Date.now()-a,stdout:j,stderr:b,stdoutBytes:p,stderrBytes:I}))},l=()=>{k=!0,w.kill("SIGTERM")};o.signal?.addEventListener("abort",l,{once:!0});const E=setTimeout(()=>{u=!0,w.kill("SIGTERM")},v);w.stdout.on("data",C=>{p+=C.length,p+I>S?w.kill("SIGTERM"):j+=C.toString("utf8")}),w.stderr.on("data",C=>{I+=C.length,p+I>S?w.kill("SIGTERM"):b+=C.toString("utf8"),!x&&b.includes(`continuous-child-handoff-ready
|
|
51
|
+
`)&&(x=!0,Promise.resolve(n.afterHandoff?.()).then(()=>w.stdin.end()).catch(()=>w.kill("SIGTERM")))}),w.once("error",()=>m(null)),w.once("close",(C,J)=>m(C,J)),n.afterHandoff||w.stdin.end()})}async function P(e,r){return(await z(e,r)).trim()}async function z(e,r){const t=await Ae("git",r,{cwd:e,encoding:"utf8",maxBuffer:16777216});return String(t.stdout)}async function ee(e,r){try{return await P(e,r)}catch(t){if(W(t,"ENOENT"))return;throw t}}async function ae(e,r){try{return await P(e,r),!0}catch{return!1}}async function Nt(e,r,t){return await new Promise(o=>{const n=Je("git",[...r],{cwd:e,stdio:["pipe","ignore","ignore"]});n.once("error",()=>o(!1)),n.once("close",a=>o(a===0)),n.stdin.end(t)})}async function dr(e,r,t){try{const o=await Ae("git",["show",`${r}:${t}`],{cwd:e,encoding:"buffer",maxBuffer:16777216});return Buffer.from(o.stdout)}catch(o){if(W(o,"ENOENT"))return;throw o}}async function De(e){try{return await B(e)}catch(r){if(W(r,"ENOENT"))return;throw r}}async function te(e,r,t,o){const n=se(r);if(!ce(n))throw new Error("continuous-sandbox-write-path-invalid");const a=await X(e);if(a!==dt(e))throw new Error("continuous-sandbox-write-root-symlink");const c=O(n)==="."?"":O(n),i=await Ct(a,c),d=await Ve(i),s=D(i,$(n));if(await we(s,a,!0),t===void 0){await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Fe(i,a,d),await we(s,a,!0),await bt(i,$(n));return}await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Fe(i,a,d),await we(s,a,!0),await St(i,$(n),t),await we(s,a,!1)}async function Ct(e,r){let t=e;for(const o of r.split("/").filter(Boolean)){t=D(t,o),await vt(O(t),$(t));const n=await le(t);if(!n.isDirectory()||n.isSymbolicLink()||await X(t)!==t)throw new Error("continuous-sandbox-write-component-unsafe");Oe(e,t)}return t}async function we(e,r,t){Oe(r,e);try{const o=await le(e);if(o.isSymbolicLink()||!o.isFile())throw new Error("continuous-sandbox-write-destination-unsafe");if(await X(e)!==e)throw new Error("continuous-sandbox-write-destination-symlink")}catch(o){if(t&&W(o,"ENOENT"))return;throw o}}function Oe(e,r){const t=st(e,r);if(t===""||t.startsWith("..")||Ke(t))throw new Error("continuous-sandbox-write-containment-invalid")}async function Ve(e){const r=await le(e,{bigint:!0});if(!r.isDirectory()||r.isSymbolicLink())throw new Error("continuous-sandbox-write-parent-unsafe");return{dev:r.dev,ino:r.ino}}async function _t(e,r,t){try{if(e!==r&&Oe(r,e),await X(e)!==e)return!1;const o=await Ve(e);return o.dev===t.dev&&o.ino===t.ino}catch{return!1}}async function Fe(e,r,t){if(!await _t(e,r,t))throw new Error("continuous-sandbox-write-parent-raced")}async function Bt(e,r){return await Promise.all(r.map(async t=>{const o=await De(D(e,t));return{path:t,...o!==void 0?{content:o}:{}}}))}async function Ne(e,r){const t=r.map(o=>o.path);t.length>0&&await ae(e,["reset","--quiet","HEAD","--",...t]);for(const o of r)await te(e,o.path,o.content)}async function Pt(e,r){try{const t=D(e.projectRoot,".neocortex/state.json"),o=T(JSON.parse((await B(t)).toString("utf8"))),n=h(h(o.epics)?.[e.epicId]),a=h(n?.branch_lease),c=Object.freeze({schemaVersion:1,ownerStoryId:e.storyId,sessionId:e.dispatchId,idempotencyKey:e.dispatchId,acquiredAt:r,expiresAt:new Date(Date.parse(r)+600*1e3).toISOString()});let i=!1;return await Y(e.projectRoot,d=>{const s=ye(d,e.epicId),g=h(s.branch_lease)??a;if(g&&typeof g.expiresAt=="string"&&g.expiresAt>r&&(g.ownerStoryId!==e.storyId||g.idempotencyKey!==e.dispatchId)){i=!0;return}s.branch_mode="epic",s.execution_branch=e.executionBranch,s.branch_lease=c}),i?f("continuous-epic-checkout-writer-active"):{ok:!0,value:c}}catch{return f("continuous-writer-lease-persist-failed")}}async function $t(e){await Y(e.projectRoot,r=>{const t=ye(r,e.epicId),o=h(t.branch_lease);o?.ownerStoryId===e.storyId&&o.idempotencyKey===e.dispatchId&&(t.branch_lease=null)})}async function Qe(e){try{const r=D(e.lease.projectRoot,".neocortex/state.json"),t=Object.freeze({schemaVersion:1,storyId:e.lease.storyId,epicId:e.lease.epicId,branch:e.lease.executionBranch,baseSha:e.baseSha,headSha:e.headSha,commits:Object.freeze([e.headSha]),idempotencyKey:e.lease.dispatchId,dispatchId:e.lease.dispatchId,bundleId:e.bundle.bundleId,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,claimRevision:e.lease.claimRevision,receiptRefs:Object.freeze([...new Set(e.receiptRefs)]),qaVerdict:"passed",reviewVerdict:"approved",qaReceipt:e.qaReceipt,reviewReceipt:e.reviewReceipt,recordedAt:e.recordedAt}),o=T(JSON.parse((await B(r)).toString("utf8"))),n=h(h(o.stories)?.[e.lease.storyId]);let a="persisted",c,i,d,s,g=!1,S;const v=async(u,k,x)=>{const m=await ee(e.lease.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),l=await P(e.lease.projectRoot,["rev-parse","HEAD"]);if(m!==e.lease.executionBranch||l!==e.headSha)throw new Error("continuous-checkpoint-head-raced");if(u.graphRevision!==e.lease.graphRevision||u.claimRevision!==e.lease.claimRevision||u.bundleId!==e.bundle.bundleId||u.bundleDigest!==e.bundle.bundleDigest)throw new Error("continuous-checkpoint-graph-raced");const E=x??T(JSON.parse((await B(r)).toString("utf8"))),C=re(E,k??await F(e.lease.projectRoot)),J=h(h(C.epics)?.[e.lease.epicId]),Ie=h(h(C.stories)?.[e.lease.storyId]),M=Array.isArray(Ie?.depends_on)?Ie.depends_on.filter(H=>typeof H=="string"):[],ve=h(C.stories);if(J?.execution_branch!==e.lease.executionBranch||M.some(H=>{const K=h(ve?.[H]);return!K||!["done","completed","merged"].includes(String(K.status))}))throw new Error("continuous-checkpoint-dependency-raced");const he=L(await z(e.lease.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",e.headSha]));if(he.length===0||he.some(H=>!e.lease.authorizedWriteSet.some(K=>ge(K,H))))throw new Error("continuous-checkpoint-write-set-raced");if(!await Re(e.lease.projectRoot,u,e.lease.storyId,e.lease.epicId,e.lease.executionBranch,void 0,e.lease.authorizedWriteSet))throw new Error("continuous-checkpoint-receipt-revalidation-failed")},A=await F(e.lease.projectRoot,{required:!0}),w=h(h(A.epics[e.lease.epicId])?.branch_lease);if(w?.ownerStoryId!==e.lease.storyId||w.idempotencyKey!==e.lease.dispatchId||w.sessionId!==e.lease.dispatchId||typeof w.expiresAt!="string"||Date.parse(w.expiresAt)<=(e.checkpointNow?.("before-mutation")??Date.now()))return f("continuous-checkpoint-writer-lease-lost");if(!await ke(e.physicalLock.path,e.physicalLock.owner))return f("continuous-checkpoint-integration-lock-raced");const j=await B(r),b=G("sha256").update(j).digest("hex");await v(t,A);const p=Pe(T(JSON.parse(j.toString("utf8"))),A,e.lease.epicId,e.lease.storyId);if(p.revision!==e.checkpointAuthority.revision||p.epoch!==e.checkpointAuthority.epoch||p.storyStatus!==e.checkpointAuthority.storyStatus)return f("continuous-graph-revision-stale");const I=await Y(e.lease.projectRoot,u=>{const k=ye(u,e.lease.epicId),x=h(k.branch_lease);i=x===void 0?void 0:structuredClone(x),d=structuredClone(u),g=u.stories[e.lease.storyId]!==void 0,s=structuredClone(u.stories[e.lease.storyId]??{}),S=structuredClone(k.branch_lease);const m=yt(u,e.lease.storyId),l=h(m.checkpoint)??h(n?.checkpoint);if(l?.idempotencyKey===e.lease.dispatchId){l.baseSha!==e.baseSha||l.headSha!==e.headSha||l.bundleId!==e.bundle.bundleId||l.bundleDigest!==e.bundle.bundleDigest||l.graphRevision!==e.lease.graphRevision||l.claimRevision!==e.lease.claimRevision?a="conflict":(a="reused",c=l,k.branch_lease=null);return}if(x?.ownerStoryId!==e.lease.storyId||x.idempotencyKey!==e.lease.dispatchId||x.sessionId!==e.lease.dispatchId){a="lease-lost";return}m.checkpoint=t,m.status="done",m.last_step="step-c-11-review-pr";const E=Array.isArray(m.steps_completed)?m.steps_completed.filter(C=>typeof C=="string"):[];m.steps_completed=[...new Set([...E,"step-c-08-commit-push","step-c-11-review-pr"])],k.branch_lease=null},{expectedRevision:A.revision,preCommit:async u=>{if(i?.ownerStoryId!==e.lease.storyId||i.idempotencyKey!==e.lease.dispatchId||i.sessionId!==e.lease.dispatchId||typeof i.expiresAt!="string"||Date.parse(i.expiresAt)<=(e.checkpointNow?.("pre-commit")??Date.now()))throw new Error("continuous-checkpoint-writer-lease-lost");if(await e.insideCheckpointPreCommit?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),!await ke(e.physicalLock.path,e.physicalLock.owner))throw new Error("continuous-checkpoint-integration-lock-raced");await v(c??t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==b)throw new Error("continuous-graph-revision-stale");if(!d)throw new Error("continuous-checkpoint-authority-missing");const x=T(JSON.parse(k.toString("utf8"))),m=Pe(x,d,e.lease.epicId,e.lease.storyId);if(m.revision!==e.checkpointAuthority.revision||m.epoch!==e.checkpointAuthority.epoch||m.storyStatus!==e.checkpointAuthority.storyStatus)throw new Error("continuous-graph-revision-stale");if(a==="persisted"&&!$e(x,u,e.lease,t))throw new Error("continuous-checkpoint-projection-raced")}}),R=a;if(R==="conflict")return f("continuous-checkpoint-idempotency-conflict");if(R==="lease-lost")return f("continuous-checkpoint-writer-lease-lost");if(R==="reused"&&c)try{return await v(c),{ok:!0,value:c}}catch{return f("continuous-checkpoint-reused-evidence-invalid")}try{await e.afterCheckpointPersist?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha});const u=await F(e.lease.projectRoot,{required:!0});if(u.revision!==I.document.revision)throw new Error("continuous-checkpoint-post-persist-runtime-raced");await v(t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==b)throw new Error("continuous-checkpoint-post-persist-authority-raced");const x=T(JSON.parse(k.toString("utf8")));if(!$e(x,u,e.lease,t))throw new Error("continuous-checkpoint-post-persist-projection-raced")}catch{const u=await B(r).catch(()=>{}),k=u===void 0||G("sha256").update(u).digest("hex")!==b;return await Y(e.lease.projectRoot,x=>{const m=h(x.epics[e.lease.epicId]),l=h(x.stories[e.lease.storyId]),E=u===void 0?void 0:T(JSON.parse(u.toString("utf8")));if(!m||!l||!E||!$e(E,x,e.lease,t))throw new Error("continuous-checkpoint-cleanup-cas-conflict");if(k){g?Ht(l,s??{}):delete x.stories[e.lease.storyId],S===void 0?delete m.branch_lease:m.branch_lease=structuredClone(S);return}l.checkpoint=null,l.status="blocked",m.branch_lease=null},{expectedRevision:I.document.revision}).catch(()=>{}),f("continuous-checkpoint-post-persist-raced")}return{ok:!0,value:t}}catch(r){const t=r instanceof Error&&/^continuous-/.test(r.message)?r.message:"continuous-checkpoint-persist-failed";return f(t)}}async function Ze(e){try{if(await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-evidence-head-raced");const r=await B(D(e.lease.projectRoot,"config","release-gates.v2.json"),"utf8"),t=JSON.parse(r),o=Array.isArray(t.requiredCompleteClasses)?t.requiredCompleteClasses.filter(R=>typeof R=="string"&&/^[a-z0-9-]+$/.test(R)):[];if(t.contract!=="P205-CI-02"||o.length===0)return f("continuous-story-qa-manifest-invalid");const n=String((await Ae(process.execPath,["scripts/test-root.mjs","--gate","complete"],{cwd:e.lease.projectRoot,encoding:"utf8",maxBuffer:32*1024*1024})).stdout);if(await e.qaRunner?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-qa-head-raced");const a=Ue(e.nowIso),c=await P(e.lease.projectRoot,["rev-list","--count",`${e.baseSha}..${e.headSha}`]),i=await z(e.lease.projectRoot,["show","--no-patch","--format=%H%n%P%n%B",e.headSha]),d=L(await z(e.lease.projectRoot,["diff","--name-only","-z",`${e.baseSha}..${e.headSha}`])),s=pt({storyId:e.lease.storyId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,commitBody:i,changedPaths:d}),g=G("sha256").update(r).digest("hex"),S=G("sha256").update(n).digest("hex"),v=lt({gitEvidenceDigest:s,headSha:e.headSha,graphRevision:e.lease.graphRevision,manifestDigest:g,gateIds:o,resultDigest:S}),A=`story-qa:${v}`,w=Object.freeze({schemaVersion:1,kind:"story_qa_evidence",producer:"local-yolo-tdd",evidenceVersion:"p205-execution-v2",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,contract:"P205-CI-02",command:mt,manifestDigest:g,gateIds:Object.freeze(o),resultDigest:S,sourceEvidenceDigest:v,verdict:"passed",checkedAt:a,receiptRef:A}),j=[`Neocortex-Story: ${e.lease.storyId}`,`Neocortex-Epic: ${e.lease.epicId}`,`Neocortex-Bundle-Digest: ${e.bundle.bundleDigest}`,`Neocortex-Graph-Revision: ${e.lease.graphRevision}`];if(c!=="1"||!j.every(R=>i.includes(R))||d.length===0||d.some(R=>!e.lease.authorizedWriteSet.some(u=>ge(u,R))))return f("continuous-story-review-evidence-rejected");const b=G("sha256").update(["root-commit-range-review-v1",e.lease.storyId,e.baseSha,e.headSha,e.bundle.bundleDigest,e.lease.graphRevision,A,G("sha256").update(i).digest("hex"),[...d].sort().join(",")].join("\0")).digest("hex"),p=`story-review:${b}`,I=Object.freeze({schemaVersion:1,kind:"story_review_evidence",producer:"root-commit-range-review",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,sourceEvidenceDigest:b,qaReceiptRef:A,verdict:"approved",reviewedAt:a,receiptRef:p});return{ok:!0,value:{qaReceipt:w,reviewReceipt:I}}}catch{return f("continuous-story-evidence-production-failed")}}function Ue(e){return Number.isFinite(Date.parse(e))?new Date(Date.parse(e)).toISOString():new Date().toISOString()}function zt(e,r,t){if(r!==void 0)try{const o=e===void 0?{}:T(JSON.parse(e.toString("utf8"))),n=T(JSON.parse(r.toString("utf8"))),a=structuredClone(o),c=h(h(o.stories)?.[t]),i=h(h(n.stories)?.[t]),d=Tt(a,"stories"),s=structuredClone(c??{});for(const g of["status","last_step","steps_completed","last_updated","blocked_reason","blocked_at","implementation_evidence","validation_evidence","qa_gate"])i&&Object.prototype.hasOwnProperty.call(i,g)&&(s[g]=structuredClone(i[g]));return d[t]=s,Buffer.from(`${JSON.stringify(a,null,2)}
|
|
52
|
+
`)}catch{return Buffer.from("{invalid-child-state")}}function Tt(e,r){const t=h(e[r]);if(t)return t;const o={};return e[r]=o,o}function T(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("record expected");return e}function h(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function Gt(e,r,t){return Be(t,e)||Be(r,t)?{ok:!0,value:r}:Be(r,e)?{ok:!0,value:t}:f("continuous-context-merge-conflict")}function Lt(e,r,t){try{const o=Xe(Ce(e),Ce(r),Ce(t));return o.ok?{ok:!0,value:o.value===void 0?void 0:Buffer.from(`${JSON.stringify(o.value,null,2)}
|
|
53
|
+
`)}:o}catch{return f("continuous-state-merge-invalid")}}function Ce(e){return e===void 0?void 0:JSON.parse(e.toString("utf8"))}function Xe(e,r,t){if(me(t,e)||me(r,t))return{ok:!0,value:r};if(me(r,e))return{ok:!0,value:t};if(_e(e)&&_e(r)&&_e(t)){const o={};for(const n of[...new Set([...Object.keys(e),...Object.keys(r),...Object.keys(t)])].sort()){const a=Xe(e[n],r[n],t[n]);if(!a.ok)return a;a.value!==void 0&&(o[n]=a.value)}return{ok:!0,value:o}}if(Array.isArray(e)&&Array.isArray(r)&&Array.isArray(t)&&Ye(e,r)&&Ye(e,t)){const o=[...e,...r.slice(e.length),...t.slice(e.length)],n=new Set;return{ok:!0,value:o.filter(a=>{const c=JSON.stringify(a);return n.has(c)?!1:(n.add(c),!0)})}}return f("continuous-state-merge-conflict")}function _e(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function Ye(e,r){return e.length<=r.length&&e.every((t,o)=>me(t,r[o]))}function me(e,r){return JSON.stringify(e)===JSON.stringify(r)}function Be(e,r){return e===void 0||r===void 0?e===r:e.equals(r)}function L(e){return e.split("\0").filter(Boolean)}function ce(e){const r=se(e);return r.length>0&&r.length<=1024&&!Ke(r)&&!/^[A-Za-z]:\//.test(r)&&!r.split("/").includes("..")&&!r.includes("\0")&&!r.startsWith("/")}function se(e){return e.replaceAll("\\","/").replace(/^\.\//,"").replace(/\/{2,}/g,"/")}function qt(e){const r=e.map(se).filter(ce);return[...new Set(r)].sort()}function ge(e,r){const t=se(e),o=se(r);return t===o||t.endsWith("/")&&o.startsWith(t)}function Wt(e){return e.length>0&&e.length<=240&&!e.startsWith("-")&&!e.startsWith("/")&&!e.endsWith("/")&&!e.endsWith(".lock")&&!e.includes("..")&&!e.includes("\\")&&!e.includes("@{")&&!e.includes("//")&&/^[A-Za-z0-9._/-]+$/.test(e)}function et(e,r){return e.length===r.length&&e.every((t,o)=>t===r[o])}async function Se(e,r,t,o){const n=T(JSON.parse(await B(D(e,".neocortex/state.json"),"utf8")));return Pe(n,o??await F(e),r,t)}function Pe(e,r,t,o){const n=re(e,r),a=h(n.epics),c=h(n.stories),i=h(a?.[t])??{},d=(Array.isArray(i.stories)?i.stories:Array.isArray(i.story_ids)?i.story_ids:[]).filter(v=>typeof v=="string"),s=d.length>0?d:Object.entries(c??{}).filter(([v,A])=>h(A)?.epic_id===t||v.startsWith(`${t}.`)).map(([v])=>v).sort(),g=["status","depends_on","files_to_modify","contracts","contract_refs","shared_surfaces","steps_completed","last_step","branch_name","physicalMergeStatus","merged","checkpoint","planning","attempts","retry_count","rollback_receipt","cancelled_at"],S=Object.fromEntries(s.map(v=>{const A=h(c?.[v])??{};return[v,Object.fromEntries(g.filter(w=>Object.prototype.hasOwnProperty.call(A,w)).map(w=>[w,A[w]]))]}));return{revision:ze({epicId:t,epic:{stories:s,status:i.status??null,branch_mode:i.branch_mode??null,execution_branch:i.execution_branch??null,graph_revision:i.graph_revision??null,depends_on:i.depends_on??null,planning:i.planning??null,execution_plan:i.execution_plan??null,waves:i.waves??null,current_wave:i.current_wave??null,replan:i.replan??null,replan_revision:i.replan_revision??null,dependency_graph:i.dependency_graph??null,scheduler:i.scheduler??null,attempts:i.attempts??null,retry_count:i.retry_count??null},stories:S}),epoch:typeof i.graph_revision=="string"?i.graph_revision:null,storyStatus:typeof h(c?.[o])?.status=="string"?String(h(c?.[o])?.status):null}}function $e(e,r,t,o){const n=re(e,r),a=h(h(n.epics)?.[t.epicId]),c=h(h(n.stories)?.[t.storyId]),i=Array.isArray(c?.steps_completed)?c.steps_completed.filter(d=>typeof d=="string"):[];return!!(a&&c&&a.branch_lease===null&&c.status==="done"&&c.last_step==="step-c-11-review-pr"&&i.includes("step-c-08-commit-push")&&i.includes("step-c-11-review-pr")&&de(c.checkpoint)===de(o))}function Ht(e,r){for(const t of Object.keys(e))delete e[t];Object.assign(e,structuredClone(r))}async function Jt(e,r){return(await Se(e,r,"")).revision}function ze(e){return G("sha256").update(de(e)).digest("hex")}function de(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(de).join(",")}]`:`{${Object.entries(e).sort(([r],[t])=>r.localeCompare(t)).map(([r,t])=>`${JSON.stringify(r)}:${de(t)}`).join(",")}}`}function Mt(e,r){const t=(e??[]).filter(o=>/^[A-Za-z0-9._/:@#-]{1,200}$/.test(o)&&!o.includes(".."));return Object.freeze([...new Set(t.length>0?t:[`dispatch:${r}`])].sort())}function Kt(e){return e.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,80)}function f(e){return{ok:!1,reasonCode:e}}function W(e,r){return e instanceof Error&&"code"in e&&e.code===r}async function ue(e,r){try{await q(e,r);const t=D(e,"owner.json");await V(t,e);const o=JSON.parse(await B(t,"utf8"));if(!Number.isSafeInteger(o.pid)||Number(o.pid)<=0||typeof o.createdAt!="string"||!Number.isFinite(Date.parse(o.createdAt))||typeof o.nonce!="string"||!/^[a-f0-9]{32}$/.test(o.nonce))throw new Error("continuous-sandbox-lease-owner-invalid");return{pid:Number(o.pid),createdAt:o.createdAt,nonce:o.nonce}}catch(t){if(W(t,"ENOENT"))return;throw t}}function tt(e,r){return e?.pid===r.pid&&e.createdAt===r.createdAt&&e.nonce===r.nonce}function Vt(e){try{return process.kill(e,0),!0}catch(r){return W(r,"EPERM")}}async function Te(e,r){try{await q(e,r);const t=D(e,".git");await q(t,e);const o=D(t,"neocortex-sandbox.json");await V(o,t);const n=JSON.parse(await B(o,"utf8"));if(n.schemaVersion!==1||typeof n.workspaceOwnerNonce!="string"||!/^[a-f0-9]{32}$/.test(n.workspaceOwnerNonce)||!/^[a-f0-9]{64}$/.test(n.graphAuthorityRevision)||!(n.graphAuthorityEpoch===null||/^[a-f0-9]{64}$/.test(n.graphAuthorityEpoch))||!(n.graphAuthorityStoryStatus===null||typeof n.graphAuthorityStoryStatus=="string"&&n.graphAuthorityStoryStatus.length<=80)||typeof n.workspaceIdentity?.dev!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.dev)||typeof n.workspaceIdentity?.ino!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.ino))throw new Error("continuous-sandbox-metadata-invalid");return n}catch(t){if(W(t,"ENOENT"))return;throw t}}async function Ft(e,r,t,o){await q(e,r);const n=D(e,".git");await q(n,e);const a=D(n,"neocortex-sandbox.json");await te(e,".git/neocortex-sandbox.json",Buffer.from(`${JSON.stringify(t,null,2)}
|
|
54
|
+
`),o),await V(a,n)}async function Qt(e,r){try{await V(e,r);const t=JSON.parse(await B(e,"utf8"));return typeof t.childHeadSha=="string"&&typeof t.rootHeadSha=="string"&&/^[a-f0-9]{40,64}$/.test(t.childHeadSha)&&/^[a-f0-9]{40,64}$/.test(t.rootHeadSha)&&t.bundle?.schemaVersion===1&&t.checkpoint?.schemaVersion===1?t:void 0}catch(t){if(W(t,"ENOENT"))return;throw t}}async function Zt(e,r){try{const t=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),o=re(t,await F(e.projectRoot)),n=h(h(o.stories)?.[e.storyId]),a=h(n?.checkpoint);return a?.idempotencyKey===r.idempotencyKey&&a.headSha===r.headSha&&a.bundleDigest===r.bundleDigest&&h(h(o.epics)?.[e.epicId])?.branch_lease===null&&await Re(e.projectRoot,a,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)}catch{return!1}}async function Ut(e,r,t){try{const o=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),n=re(o,await F(e.projectRoot)),a=h(h(n.stories)?.[e.storyId]),c=h(a?.checkpoint);return c?.schemaVersion!==1||c.storyId!==e.storyId||c.epicId!==e.epicId||c.branch!==e.executionBranch||c.baseSha!==t.baseSha||c.headSha!==t.headSha||c.idempotencyKey!==e.dispatchId||c.dispatchId!==e.dispatchId||c.bundleId!==r.bundleId||c.bundleDigest!==r.bundleDigest||c.graphRevision!==e.graphRevision||c.claimRevision!==e.claimRevision||h(h(n.epics)?.[e.epicId])?.branch_lease!==null||!await Re(e.projectRoot,c,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)?void 0:c}catch{return}}async function Xt(e,r){const t=(await ee(e.projectRoot,["log","--format=%H","--fixed-strings",`--grep=Neocortex-Dispatch: ${e.dispatchId}`]))?.split(`
|
|
55
|
+
`).filter(S=>/^[a-f0-9]{40,64}$/.test(S))??[];if(t.length!==1)return;const o=t[0];if(!await ae(e.projectRoot,["merge-base","--is-ancestor",o,"HEAD"]))return;const n=await P(e.projectRoot,["show","-s","--format=%B",o]),a=new Set(n.split(`
|
|
56
|
+
`).map(S=>S.trim()));for(const S of[`Neocortex-Story: ${e.storyId}`,`Neocortex-Epic: ${e.epicId}`,`Neocortex-Execution-Branch: ${e.executionBranch}`,`Neocortex-Prepared-Base: ${e.baseSha}`,`Neocortex-Dispatch: ${e.dispatchId}`,`Neocortex-Bundle: ${r.bundleId}`,`Neocortex-Bundle-Digest: ${r.bundleDigest}`,`Neocortex-Graph-Revision: ${e.graphRevision}`,`Neocortex-Claim-Revision: ${e.claimRevision}`])if(!a.has(S))return;const c=Ge(n,"Neocortex-Checkpoint-Authority"),i=Ge(n,"Neocortex-Checkpoint-Epoch"),d=Ge(n,"Neocortex-Checkpoint-Story-Status");if(!c||!/^[a-f0-9]{64}$/.test(c)||!i||!(i==="null"||/^[a-f0-9]{64}$/.test(i))||!d||d.length>80)return;const s=await ee(e.projectRoot,["rev-parse",`${o}^`]);if(!s||!/^[a-f0-9]{40,64}$/.test(s))return;const g=L(await z(e.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",o]));if(!(g.length===0||g.some(S=>!r.authorizedWriteSet.some(v=>ge(v,S)))))return{baseSha:s,headSha:o,checkpointAuthority:{revision:c,epoch:i==="null"?null:i,storyStatus:d==="null"?null:d}}}function Ge(e,r){const t=`${r}: `,o=e.split(`
|
|
57
|
+
`).map(n=>n.trim()).filter(n=>n.startsWith(t));return o.length===1?o[0].slice(t.length):void 0}async function Le(e,r,t,o,n,a){const c=O(e);await q(c,O(c));try{await V(e,c)}catch(i){if(!W(i,"ENOENT"))throw i}await te(c,$(e),Buffer.from(`${JSON.stringify({childHeadSha:r,rootHeadSha:t,bundle:o,checkpoint:n})}
|
|
58
|
+
`),a),await V(e,c)}export{cr as createAnchoredContinuousStoryCommandRunner,sr as createBranchlessContinuousStoryWorkspaceManager};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Bounded ownership inventory. Names alone never establish managed ownership. */
|
|
2
|
+
import type { GitOwnershipEvidence } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
3
|
+
export interface GitResourceOwnership {
|
|
4
|
+
readonly epicId: string;
|
|
5
|
+
readonly branch: string;
|
|
6
|
+
readonly origin: string;
|
|
7
|
+
readonly active: boolean;
|
|
8
|
+
readonly proofs: readonly {
|
|
9
|
+
readonly head: string;
|
|
10
|
+
readonly evidence: readonly GitOwnershipEvidence[];
|
|
11
|
+
readonly mergeSha?: string;
|
|
12
|
+
readonly pushedSha?: string;
|
|
13
|
+
}[];
|
|
14
|
+
readonly prNumbers: readonly number[];
|
|
15
|
+
}
|
|
16
|
+
export declare const GIT_INVENTORY_REF_LIMIT = 2048;
|
|
17
|
+
export declare function collectGitResourceOwnership(state: {
|
|
18
|
+
readonly epics?: Record<string, Record<string, unknown>>;
|
|
19
|
+
readonly stories?: Record<string, Record<string, unknown>>;
|
|
20
|
+
}): {
|
|
21
|
+
readonly claims: ReadonlyMap<string, readonly GitResourceOwnership[]>;
|
|
22
|
+
readonly origins: ReadonlySet<string>;
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const I=2048;function S(e){const s=new Map,u=new Set,f=Object.entries(e.epics??{}),b=Object.entries(e.stories??{});if(f.length+b.length>1e4)throw new Error("git-reconciliation-state-inventory-limit");const _=t=>{!t.branch||!t.origin||s.set(t.branch,[...s.get(t.branch)??[],t])};for(const[t,r]of f){const i=c(r.execution_branch),o=c(r.origin_branch);o&&u.add(o);const n=d(r.terminal_git_receipt),a=n?.physicalStatus==="pushed"&&n.epicId===t&&n.executionBranch===i&&n.originBranch===o&&h(n.executionHeadSha)&&h(n.mergeSha)&&h(n.pushedSha),p=m(r.branch_lease)||(r.status===void 0?!a:!g(r.status));_({epicId:t,branch:i,origin:o,active:p,proofs:a?[{head:c(n.executionHeadSha),evidence:["terminal_receipt","canonical_convention","managed_metadata"],mergeSha:c(n.mergeSha),pushedSha:c(n.pushedSha)}]:[],prNumbers:l(r.pr_number)})}for(const[t,r]of b){const i=c(r.epic_id)||t.split(".")[0],o=e.epics?.[i],n=d(r.checkpoint),a=c(r.branch_name)||c(n?.branch);if(!o||a===c(o.execution_branch))continue;const p=n?.branch===a&&h(n.headSha);_({epicId:i,branch:a,origin:c(o.origin_branch),active:!g(r.status)||m(r.branch_lease),proofs:p?[{head:c(n.headSha),evidence:["state_reference","canonical_convention","managed_metadata"]}]:[],prNumbers:l(r.pr_number)})}for(const[t,r]of s)s.set(t,r.map(i=>({...i,proofs:i.proofs.map(o=>({...o,evidence:o.evidence.filter(n=>n!=="canonical_convention"||t===`epic/${i.epicId}`||t.startsWith(`epic/${i.epicId}/`)||t.startsWith(`story/${i.epicId}.`)||t.startsWith(`story/${i.epicId}/`))}))})));return{claims:s,origins:u}}function c(e){return typeof e=="string"?e:""}function d(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function h(e){return typeof e=="string"&&/^[a-f0-9]{40,64}$/.test(e)}function g(e){return["done","completed","merged","superseded","cancelled","archived","rolled-back"].includes(c(e))}function m(e){const s=d(e);return!!(s&&Date.parse(c(s.expiresAt))>Date.now())}function l(e){return Number.isSafeInteger(e)&&Number(e)>0?[Number(e)]:[]}export{I as GIT_INVENTORY_REF_LIMIT,S as collectGitResourceOwnership};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EpicMergeCandidateQaReceipt } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
2
|
+
export interface EpicMergeCandidateBinding {
|
|
3
|
+
readonly originHeadSha: string;
|
|
4
|
+
readonly executionHeadSha: string;
|
|
5
|
+
readonly mergeSha: string;
|
|
6
|
+
readonly graphRevision: string;
|
|
7
|
+
}
|
|
8
|
+
export interface EpicMergeCandidateQaAuthority {
|
|
9
|
+
readonly __epicMergeCandidateOpaqueAuthority: never;
|
|
10
|
+
}
|
|
11
|
+
export declare function verifiedEpicMergeCandidateReceipt(authority: EpicMergeCandidateQaAuthority | undefined, binding: EpicMergeCandidateBinding): EpicMergeCandidateQaReceipt | undefined;
|
|
12
|
+
export declare function executeEpicMergeCandidateQa(projectRoot: string, binding: EpicMergeCandidateBinding, nowIso?: string): Promise<{
|
|
13
|
+
readonly candidateQa: EpicMergeCandidateQaReceipt;
|
|
14
|
+
readonly candidateAuthority: EpicMergeCandidateQaAuthority;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{execFile as D}from"node:child_process";import{createHash as x,randomBytes as H}from"node:crypto";import{join as j}from"node:path";import{promisify as A}from"node:util";import{assertGitLifecyclePrivateDirectory as O,ensureGitLifecyclePrivateChildDirectory as L,executeP205TransientAuthority as C,gitLifecycleRuntimeDirectory as P,P205_COMPLETE_COMMAND as R,p205TransientAuthorityMatchesAggregate as q,projectP205TransientExecutionEvidence as I,removeGitLifecyclePrivateDirectory as M}from"../../git/git-lifecycle-store.js";import{anchoredCreateDirectory as N,anchoredDirectoryIdentity as y,anchoredExecuteGit as T,anchoredExecuteNode as _,anchoredExecuteNpm as $,secureFilesystemBoundaryAvailable as z}from"../../git/secure-filesystem-boundary.js";const G=A(D),v=new WeakMap;function U(c,e){const s=c&&v.get(c);if(!s||!q(s.p205,e.mergeSha,e.graphRevision))return;const h=Date.now()-s.acceptedAt;if(h<0||h>1800*1e3)return;const r=s.receipt;return r.originHeadSha===e.originHeadSha&&r.executionHeadSha===e.executionHeadSha&&r.mergeSha===e.mergeSha&&r.graphRevision===e.graphRevision?r:void 0}async function Z(c,e,s=new Date().toISOString()){if(!z())throw new Error("epic-merge-candidate-platform-unsupported");if(![e.originHeadSha,e.executionHeadSha,e.mergeSha].every(a=>/^[a-f0-9]{40,64}$/.test(a))||!/^[a-f0-9]{64}$/.test(e.graphRevision))throw new Error("epic-merge-candidate-binding-invalid");const h=async(...a)=>String((await G("git",a,{cwd:c,encoding:"utf8"})).stdout).trim(),r=(await h("rev-list","--parents","-n","1",e.mergeSha)).split(/\s+/);if(r.length!==3||r[1]!==e.originHeadSha||r[2]!==e.executionHeadSha)throw new Error("epic-merge-candidate-parents-invalid");const f=await h("rev-parse",`${e.mergeSha}^{tree}`),S=await P(c),n=await L(S,"merge-candidates"),p=`${e.mergeSha.slice(0,16)}-${H(8).toString("hex")}`,o=await N(n,p),u=j(n,p),t=async(...a)=>(await T(n,p,o,a)).toString("utf8").trim();let w;try{if(await t("init","--quiet","--template="),await t("fetch","--quiet","--no-tags",c,e.mergeSha),await t("checkout","--quiet","--detach","FETCH_HEAD"),await t("rev-parse","HEAD")!==e.mergeSha||await t("rev-parse","HEAD^{tree}")!==f)throw new Error("epic-merge-candidate-checkout-invalid");const a=(await t("ls-files","--stage","-z","--","package.json","*/package.json","package-lock.json","*/package-lock.json","npm-shrinkwrap.json","*/npm-shrinkwrap.json",".npmrc","*/.npmrc")).split("\0").filter(Boolean);if(a.length>1024||a.some(l=>!/^100(?:644|755) [a-f0-9]{40,64} 0\t/.test(l)))throw new Error("epic-merge-candidate-dependency-entry-unsafe");const m=(await t("ls-files","-z","--","package-lock.json","*/package-lock.json","npm-shrinkwrap.json","*/npm-shrinkwrap.json")).split("\0").filter(Boolean);if(m.length>32)throw new Error("epic-merge-candidate-dependency-limit");const d=JSON.parse((await _(n,p,o,["-e",`
|
|
2
|
+
const fs=require('node:fs'); const path=require('node:path'); const locks=JSON.parse(process.argv[1]);
|
|
3
|
+
// npm-shrinkwrap wins over package-lock in the same installation root.
|
|
4
|
+
// Validate every selected root, not only the repository's top-level lock.
|
|
5
|
+
const selected=new Map();
|
|
6
|
+
for(const file of locks){
|
|
7
|
+
const dir=path.dirname(file);
|
|
8
|
+
if(!selected.has(dir)||path.basename(file)==='npm-shrinkwrap.json') selected.set(dir,file);
|
|
9
|
+
}
|
|
10
|
+
const cwd=fs.realpathSync('.');
|
|
11
|
+
const contained=p=>p===cwd||p.startsWith(cwd+path.sep);
|
|
12
|
+
const workspacePaths=new Set(); let unsafeLinks=false; let linkCount=0;
|
|
13
|
+
for(const [dir,file] of selected){
|
|
14
|
+
const lock=JSON.parse(fs.readFileSync(file,'utf8'));
|
|
15
|
+
for(const entry of Object.values(lock?.packages??{})){
|
|
16
|
+
if(entry?.link!==true) continue;
|
|
17
|
+
const p=entry.resolved; linkCount++;
|
|
18
|
+
if(linkCount>128||typeof p!=='string'||path.isAbsolute(p)){unsafeLinks=true;continue;}
|
|
19
|
+
const target=path.resolve(dir,p);
|
|
20
|
+
if(!contained(target)){unsafeLinks=true;continue;}
|
|
21
|
+
try{if(!contained(fs.realpathSync(target))){unsafeLinks=true;continue;}}
|
|
22
|
+
catch{unsafeLinks=true;continue;}
|
|
23
|
+
workspacePaths.add(path.relative(cwd,target)||'.');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
process.stdout.write(JSON.stringify({unsafeLinks,roots:[...selected.keys()]
|
|
27
|
+
.filter(p=>!workspacePaths.has(p)).sort((a,b)=>a.length-b.length)}));
|
|
28
|
+
`,JSON.stringify(m)])).toString("utf8"));if(d.unsafeLinks)throw new Error("epic-merge-candidate-dependency-link-unsafe");if(d.roots.length>16)throw new Error("epic-merge-candidate-dependency-limit");for(const l of d.roots){if(l!=="."&&!/^[A-Za-z0-9_.\/-]+$/.test(l)||l.split("/").includes(".."))throw new Error("epic-merge-candidate-dependency-path-invalid");await $(n,p,o,["--prefix",l,"ci","--include=dev","--no-audit","--no-fund"])}if(await t("status","--porcelain","--untracked-files=normal"))throw new Error("epic-merge-candidate-dirty");if(w=await C(u,{headSha:e.mergeSha,graphRevision:e.graphRevision,nowIso:s,anchoredWorkspace:{parent:n,name:p,identity:o}}),await t("status","--porcelain","--untracked-files=normal")||await t("rev-parse","HEAD")!==e.mergeSha||await t("rev-parse","HEAD^{tree}")!==f)throw new Error("epic-merge-candidate-raced")}finally{await O(u,n);const a=await y(u);if(a.dev!==o.dev||a.ino!==o.ino)throw new Error("epic-merge-candidate-cleanup-owner-raced");if(!await M(u,n,async m=>{const d=await y(m);return d.dev===o.dev&&d.ino===o.ino}))throw new Error("epic-merge-candidate-cleanup-unverified")}const i=I(w);if(!i||i.executionHeadSha!==e.mergeSha)throw new Error("epic-merge-candidate-authority-missing");const E=`merge-qa:${x("sha256").update(["epic-merge-candidate-qa-v1",e.originHeadSha,e.executionHeadSha,e.mergeSha,f,e.graphRevision,i.manifestDigest,i.resultDigest,i.gateIds.join(",")].join("\0")).digest("hex")}`,g=Object.freeze({schemaVersion:1,kind:"epic_merge_candidate_qa",contract:"P205-CI-02",command:R,...e,treeSha:f,manifestDigest:i.manifestDigest,resultDigest:i.resultDigest,gateIds:Object.freeze([...i.gateIds]),checkedAt:i.executedAt,receiptRef:E}),k=Object.freeze(Object.create(null));return v.set(k,{receipt:g,p205:w,acceptedAt:Date.now()}),{candidateQa:g,candidateAuthority:k}}export{Z as executeEpicMergeCandidateQa,U as verifiedEpicMergeCandidateReceipt};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EpicTerminalGitAdapter } from './epic-terminal-git-runner.js';
|
|
2
|
+
export interface CliEpicTerminalGitAdapterOptions {
|
|
3
|
+
/** Test observer after canonical P205; cannot replace the command or result. */
|
|
4
|
+
readonly aggregateQaRunner?: (input: {
|
|
5
|
+
readonly projectRoot: string;
|
|
6
|
+
readonly gateIds: readonly string[];
|
|
7
|
+
}) => Promise<unknown>;
|
|
8
|
+
/** Command seams keep provider-destructive tests inside temporary fixtures. */
|
|
9
|
+
readonly gitRunner?: (...args: readonly string[]) => Promise<string>;
|
|
10
|
+
readonly providerRunner?: (...args: readonly string[]) => Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare function createCliEpicTerminalGitAdapter(projectRoot: string, options?: CliEpicTerminalGitAdapterOptions): EpicTerminalGitAdapter;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{execFile as pe}from"node:child_process";import{createHash as I}from"node:crypto";import{readFile as te}from"node:fs/promises";import{join as me}from"node:path";import{promisify as ye}from"node:util";import{classifyGitReconciliationCandidate as ae,reconcileTerminalReceipt as we}from"../../../../shared/dist/yoloop/epic-terminal-git.js";import{collectGitResourceOwnership as be,GIT_INVENTORY_REF_LIMIT as L}from"./epic-git-reconciliation-inventory.js";import{executeEpicMergeCandidateQa as ie,verifiedEpicMergeCandidateReceipt as W}from"./epic-merge-candidate-qa.js";import{applyGitLifecycleRuntimeOverlay as Se,ensureRuntimeEpic as T,executeP205TransientAuthority as _e,P205_COMPLETE_COMMAND as Q,projectP205TransientExecutionEvidence as xe,verifyAcceptedGitLifecycleStoryCheckpoint as ne,mutateGitLifecycleRuntime as J,readGitLifecycleRuntime as ve}from"../../git/git-lifecycle-store.js";const Re=ye(pe);function We(r,a={}){const c=me(r,".neocortex","state.json"),t=a.gitRunner??((...e)=>se("git",e,r)),d=a.providerRunner??((...e)=>se("gh",e,r)),g=new Map;return{async prepareLifecycleEvidence(e){try{try{await te(c,"utf8")}catch(y){if(Ee(y,"ENOENT"))return{ok:!0,originBindingCaptured:!1,aggregateQaRecorded:!1};throw y}const n=(await D(r,c)).epics?.[e.epicId];if(!n)return o("epic-state-missing",!1,!1);if(_(n.branch_mode)!=="epic")return{ok:!0,originBindingCaptured:!1,aggregateQaRecorded:!1};const s=_(n.execution_branch),u=_(n.origin_branch);if(!s||!A(s))return o("epic-execution-branch-missing",!1,!1);let h=await t("symbolic-ref","--quiet","--short","HEAD").catch(()=>""),f=await t("rev-parse","HEAD"),p=S(n.origin_binding)?n.origin_binding:null,l=!1;if(p){if(p.executionBranch!==s||p.originBranch!==u||h!==s&&h!==p.originBranch||!await U(t,p.originHeadSha)||!await R(t,p.originHeadSha,f))return o("epic-origin-binding-physical-drift",!1,!1)}else{if(!h||h===s||!A(h))return o("epic-origin-binding-capture-window-missed",!1,!1);if(u&&u!==h)return o("epic-origin-binding-recorded-origin-drift",!1,!1);p={schemaVersion:1,originBranch:h,originHeadSha:f,executionBranch:s,capturedFromCurrentCheckout:!0,capturedAt:e.nowIso},await J(r,y=>{const v=T(y,e.epicId);if(v.origin_binding&&JSON.stringify(v.origin_binding)!==JSON.stringify(p))throw new Error("origin-binding-cas-conflict");v.origin_branch=h,v.origin_binding=p}),l=!0}if(h!==s){const y=await ue(t,`refs/heads/${s}`);try{if(y){if(!await R(t,p.originHeadSha,y))return o("epic-execution-branch-origin-drift",!1,!1);await t("switch",s)}else await t("switch","-c",s,p.originHeadSha)}catch{const v=await t("status","--porcelain","--untracked-files=normal").catch(()=>"");return o(v?"epic-execution-branch-switch-blocked-by-user-changes":"epic-execution-branch-switch-failed",!0,!1)}if(h=await t("symbolic-ref","--quiet","--short","HEAD"),f=await t("rev-parse","HEAD"),h!==s)return o("epic-execution-branch-switch-unverified",!0,!1)}const m=await D(r,c,!0),w=m.epics?.[e.epicId];if(!w)return o("epic-state-missing",!1,!1);const x=j(w),b=await Promise.all(x.map(y=>ne(r,m.stories?.[y]?.checkpoint,y,e.epicId,s).then(v=>v&&le(m.stories?.[y]?.checkpoint))));if(!(x.length>0&&b.every(Boolean)))return{ok:!0,originBindingCaptured:l,aggregateQaRecorded:!1};if(h!==s)return o("epic-aggregate-qa-execution-checkout-required",!0,!1);const $=_(w.graph_revision);if(!/^[a-f0-9]{64}$/i.test($))return o("epic-aggregate-qa-graph-required",!1,!1);if(await fe(t))return o("epic-aggregate-qa-checkout-dirty",!0,!1);const q=await _e(r,{headSha:f,graphRevision:$,nowIso:e.nowIso}),B=xe(q);if(!B)return o("epic-aggregate-qa-authority-invalid",!1,!1);if(await a.aggregateQaRunner?.({projectRoot:r,gateIds:B.gateIds}),await t("rev-parse","HEAD")!==f||await fe(t))return o("epic-aggregate-qa-head-raced",!0,!1);const M=`local-yolo-tdd:${I("sha256").update(["epic-aggregate-p205-execution-v2",Q,f,$,B.manifestDigest,B.gateIds.join(","),B.resultDigest].join("\0")).digest("hex")}`,G={schemaVersion:1,evidenceVersion:"p205-execution-v2",producer:"local-yolo-tdd",contract:"P205-CI-02",command:Q,verdict:"passed",executionHeadSha:f,graphRevision:$,manifestDigest:B.manifestDigest,resultDigest:B.resultDigest,checkedAt:B.executedAt,receiptRef:M,gateIds:B.gateIds};return await J(r,y=>{const v=T(y,e.epicId);v.aggregate_qa_receipt=G}),{ok:!0,originBindingCaptured:l,aggregateQaRecorded:!0,p205Authority:q}}catch{return o("epic-lifecycle-evidence-production-failed",!0,!1)}},async inspect(e){try{const i=await D(r,c,!0),n=i.epics?.[e.epicId];if(!n)return o("epic-state-missing",!1,!1);if(_(n.execution_branch)!==e.executionBranch||_(n.origin_branch)!==e.originBranch)return o("epic-branch-boundary-drift",!1,!1);const s=await t("rev-parse",`refs/heads/${e.executionBranch}`),u=await N(t,e.originBranch);await P(t,e.originBranch,u);const h=await Y(r,i,n,e.epicId,e.executionBranch);let f=S(n.terminal_git_receipt)?n.terminal_git_receipt:null;f?.physicalStatus==="pushed"&&(f.pushedSha&&await R(t,f.executionHeadSha,f.pushedSha)&&await R(t,f.pushedSha,u)||(f=null)),f||(f=await Ne({directive:e,executionHeadSha:s,originHeadSha:u,git:t}));const p=new Set((Array.isArray(n.git_reconciliation_receipts)?n.git_reconciliation_receipts:[]).filter(S).filter(z).map(H=>_(H.resourceId)).filter(Boolean)),l=await t("symbolic-ref","--quiet","--short","HEAD").catch(()=>""),m=e.reconcile.enabled?await oe({state:i,epic:n,directive:e,currentBranch:l,originHeadSha:u,receiptIds:p,git:t,gh:d}):[],w=S(n.origin_binding)?n.origin_binding:null,x=w&&w.originBranch===e.originBranch&&w.executionBranch===e.executionBranch&&await U(t,w.originHeadSha)&&await R(t,w.originHeadSha,s)?w:null;return{ok:!0,snapshot:{executionHeadSha:s,originHeadSha:u,..._(n.graph_revision)?{graphRevision:_(n.graph_revision)}:{},writerLeaseActive:ee(n.branch_lease),acceptedCheckpointIds:h,existingReceipt:f,aggregateQaReceipt:S(n.aggregate_qa_receipt)?n.aggregate_qa_receipt:null,originBinding:x,reconciliationCandidates:m}}}catch(i){return o(ce(i)??"epic-terminal-inspection-failed",!0,!1)}},async prepareMergeObject(e){let i;try{const n=await t("merge-tree","--write-tree",e.originHeadSha,e.executionHeadSha);i=await t("commit-tree",n,"-p",e.originHeadSha,"-p",e.executionHeadSha,"-m",e.message)}catch{return o("epic-terminal-merge-conflict",!1,!1)}try{const n=await ie(r,{mergeSha:i,originHeadSha:e.originHeadSha,executionHeadSha:e.executionHeadSha,graphRevision:e.graphRevision},e.nowIso);return g.set(i,n.candidateAuthority),{ok:!0,mergeSha:i,...n}}catch{return o("epic-merge-candidate-qa-failed",!0,!1)}},async inspectReconciliation(e){try{const i=await D(r,c,!0),n=i.epics?.[e.epicId];if(!n)return o("epic-state-missing",!1,!1);if(_(n.execution_branch)!==e.executionBranch||_(n.origin_branch)!==e.originBranch)return o("epic-branch-boundary-drift",!1,!1);const s=await N(t,e.originBranch);await P(t,e.originBranch,s);const u=new Set((Array.isArray(n.git_reconciliation_receipts)?n.git_reconciliation_receipts:[]).filter(S).filter(z).map(p=>_(p.resourceId)).filter(Boolean)),h=await t("symbolic-ref","--quiet","--short","HEAD").catch(()=>"");return{ok:!0,candidates:await oe({state:i,epic:n,directive:e,currentBranch:h,originHeadSha:s,receiptIds:u,git:t,gh:d})}}catch(i){return o(ce(i)??"git-reconciliation-inspection-failed",!0,!1)}},async pushMergeObject(e){try{if(!W(e.candidateAuthority,{mergeSha:e.mergeSha,originHeadSha:e.expectedOriginSha,executionHeadSha:e.executionHeadSha,graphRevision:e.graphRevision}))return o("epic-merge-candidate-authority-required",!1,!1);const n=await D(r,c,!0),s=n.epics?.[e.epicId];if(!s||s.execution_branch!==e.executionBranch||s.origin_branch!==e.originBranch||s.graph_revision!==e.graphRevision||ee(s.branch_lease)||await t("rev-parse",`refs/heads/${e.executionBranch}`)!==e.executionHeadSha)return o("epic-merge-candidate-authority-raced",!0,!1);const u=await Y(r,n,s,e.epicId,e.executionBranch);if(!X(u,e.storyCheckpointIds)||!X(j(s),e.storyCheckpointIds))return o("epic-checkpoint-set-revalidation-drift",!0,!1);const h=S(s.aggregate_qa_receipt)?s.aggregate_qa_receipt:null;if(!de(h,e.executionHeadSha,e.graphRevision,e.nowIso)||h.receiptRef!==e.aggregateQaReceipt.receiptRef)return o("epic-terminal-aggregate-qa-revalidation-drift",!0,!1);if(await N(t,e.originBranch)!==e.expectedOriginSha)return o("epic-origin-head-raced",!0,!1);await t("push","--porcelain","origin",`${e.mergeSha}:refs/heads/${e.originBranch}`);const p=await N(t,e.originBranch);return p!==e.mergeSha?o("epic-terminal-push-unverified",!0,!1):{ok:!0,pushedSha:p}}catch(i){return re(i)?o("epic-terminal-remote-policy-denied",!0,!0):o("epic-terminal-push-failed",!0,!1)}},async ensureSingleEpicPullRequest(e){try{const i=W(e.candidateAuthority,{mergeSha:e.expectedPullRequestHeadSha,originHeadSha:e.candidateQa.originHeadSha,executionHeadSha:e.expectedStoryHeadSha,graphRevision:e.candidateQa.graphRevision});if(!i||i!==e.candidateQa||!await R(t,e.candidateQa.originHeadSha,e.expectedPullRequestHeadSha)||!await R(t,e.expectedStoryHeadSha,e.expectedPullRequestHeadSha))return o("epic-merge-candidate-authority-required",!1,!1);const n=await O(t,d);if(!n)return o("git-resource-provider-repository-unverified",!0,!0);const s=`https://github.com/${n.nameWithOwner}`,u=await C(t,e.executionBranch);if(u&&u!==e.expectedPullRequestHeadSha){if(await P(t,e.executionBranch,u),!await R(t,u,e.expectedPullRequestHeadSha))return o("epic-terminal-execution-remote-head-drift",!0,!0);await t("push","--porcelain","origin",`${e.expectedPullRequestHeadSha}:refs/heads/${e.executionBranch}`)}if(u||await t("push","--porcelain","origin",`${e.expectedPullRequestHeadSha}:refs/heads/${e.executionBranch}`),await N(t,e.executionBranch)!==e.expectedPullRequestHeadSha)return o("epic-terminal-execution-publish-unverified",!0,!0);const h=await d("pr","list","--repo",s,"--state","all","--head",e.executionBranch,"--base",e.originBranch,"--json","number,state,headRefName,headRefOid,baseRefName,mergeCommit","--limit","100"),f=JSON.parse(h),p=f.filter(b=>b.headRefName===e.executionBranch&&b.baseRefName===e.originBranch&&b.headRefOid===e.expectedPullRequestHeadSha&&(b.state==="OPEN"||b.state==="MERGED"));if(p.length>1)return o("epic-terminal-duplicate-prs",!1,!0);if(typeof p[0]?.number=="number")return{ok:!0,prNumber:p[0].number};if(f.some(b=>b.state==="OPEN"))return o("epic-terminal-stale-pr",!1,!0);const m=(await d("pr","create","--repo",s,"--head",e.executionBranch,"--base",e.originBranch,"--title",`[${e.epicId}] Terminal epic integration`,"--body",`Autonomous terminal integration receipt: ${e.idempotencyKey}`)).match(/\/(\d+)(?:\s*)$/);if(!m)return o("epic-terminal-pr-number-unverified",!0,!0);const w=Number(m[1]),x=await K(d,n.nameWithOwner,w);return!x||x.state!=="OPEN"||x.headRefName!==e.executionBranch||x.baseRefName!==e.originBranch||x.headRefOid!==e.expectedPullRequestHeadSha?o("epic-terminal-pr-create-unverified",!0,!0):{ok:!0,prNumber:w}}catch(i){return o("epic-terminal-pr-create-denied",!0,re(i))}},async mergeEpicPullRequest(e){try{const i=await O(t,d);if(!i)return o("git-resource-provider-repository-unverified",!0,!0);const n=e.candidateQa&&W(e.candidateAuthority,{mergeSha:e.expectedPullRequestHeadSha,graphRevision:e.candidateQa.graphRevision,originHeadSha:e.expectedOriginHeadSha,executionHeadSha:e.expectedStoryHeadSha});if(!n||n!==e.candidateQa)return o("epic-merge-candidate-authority-required",!1,!1);const s=await K(d,i.nameWithOwner,e.prNumber),u=await C(t,e.executionBranch),h=await N(t,e.originBranch);if(!s||s.headRefName!==e.executionBranch||s.baseRefName!==e.originBranch||s.headRefOid!==e.expectedPullRequestHeadSha||u&&u!==e.expectedPullRequestHeadSha||!await R(t,e.expectedOriginHeadSha,e.expectedPullRequestHeadSha)||!await R(t,e.expectedStoryHeadSha,e.expectedPullRequestHeadSha))return o("epic-terminal-pr-revalidation-drift",!0,!0);if(s.state==="OPEN"&&h!==e.expectedOriginHeadSha)return o("epic-terminal-pr-origin-raced",!0,!0);let f;if(s.state==="OPEN"){const b=await $e(d,i.nameWithOwner,e.originBranch,e.expectedPullRequestHeadSha,e.expectedOriginHeadSha,e.nowIso);if(!b.ok)return o(b.reasonCode,!0,!0);if(f=b.receipt,await N(t,e.originBranch)!==e.expectedOriginHeadSha)return o("epic-terminal-pr-origin-raced",!0,!0);await d("pr","merge",String(e.prNumber),"--repo",`https://github.com/${i.nameWithOwner}`,"--merge","--match-head-commit",e.expectedPullRequestHeadSha)}else{if(s.state!=="MERGED")return o("epic-terminal-pr-not-open-or-merged",!1,!0);f={schemaVersion:1,provider:"github",mode:"recovered_exact_tree",source:"physical_recovery",prHeadSha:e.expectedPullRequestHeadSha,originHeadSha:e.expectedOriginHeadSha,checkedAt:e.nowIso,publicSafe:!0}}const p=await K(d,i.nameWithOwner,e.prNumber),l=p?.mergeCommit?.oid;if(p?.state!=="MERGED"||!l)return o("epic-terminal-pr-merge-unverified",!0,!0);const m=await N(t,e.originBranch);if(await P(t,e.originBranch,m),!await R(t,e.expectedStoryHeadSha,m)||!await R(t,e.expectedPullRequestHeadSha,m)||!await R(t,l,m))return o("epic-terminal-pr-merge-ancestry-unproven",!0,!0);const[w,x]=await Promise.all([t("rev-parse",`${e.expectedPullRequestHeadSha}^{tree}`),t("rev-parse",`${l}^{tree}`)]);return w!==e.candidateQa.treeSha||x!==w?o("epic-terminal-pr-merged-tree-mismatch",!1,!0):{ok:!0,mergeSha:e.expectedPullRequestHeadSha,pushedSha:l,providerGuard:f}}catch(i){return o("epic-terminal-pr-merge-denied",!0,re(i))}},async verifyTerminalReceipt(e,i,n){try{if(i.physicalStatus!=="pushed"||!i.pushedSha||!i.mergeSha)return o("epic-terminal-physical-revalidation-required",!0,!1);const s=await D(r,c,!0),u=s.epics?.[e.epicId];if(!u||_(u.execution_branch)!==e.executionBranch||_(u.origin_branch)!==e.originBranch||_(u.graph_revision)!==e.graphRevision)return o("epic-terminal-state-revalidation-drift",!0,!1);const h=await t("rev-parse",`refs/heads/${e.executionBranch}`);if(h!==e.expectedExecutionHeadSha||i.executionHeadSha!==h)return o("epic-terminal-execution-revalidation-drift",!0,!1);const f=S(u.origin_binding)?u.origin_binding:null;if(!f||f.originBranch!==e.originBranch||f.executionBranch!==e.executionBranch||!await U(t,f.originHeadSha)||!await R(t,f.originHeadSha,h))return o("epic-origin-binding-revalidation-drift",!0,!1);const p=await Y(r,s,u,e.epicId,e.executionBranch);if(ee(u.branch_lease)||!X(p,e.storyCheckpointIds))return o("epic-checkpoint-set-revalidation-drift",!0,!1);const l=S(u.aggregate_qa_receipt)?u.aggregate_qa_receipt:null;if(!de(l,h,e.graphRevision,n)||l?.receiptRef!==e.localGates.aggregateQaReceipt.receiptRef)return o("epic-terminal-aggregate-qa-revalidation-drift",!0,!1);const m=await N(t,e.originBranch);if(await P(t,e.originBranch,m),!await R(t,h,m)||!await R(t,i.mergeSha,m)||!await R(t,i.pushedSha,m))return o("epic-terminal-physical-ancestry-unproven",!0,!1);const w={originHeadSha:i.baseSha,executionHeadSha:h,mergeSha:i.mergeSha,graphRevision:e.graphRevision};let x=g.get(i.mergeSha),b=W(x,w);if(!b){const $=await ie(r,w,n);x=$.candidateAuthority,b=$.candidateQa,g.set(i.mergeSha,x)}if(i.candidateQa&&(i.candidateQa.originHeadSha!==b.originHeadSha||i.candidateQa.executionHeadSha!==b.executionHeadSha||i.candidateQa.graphRevision!==b.graphRevision||i.candidateQa.treeSha!==b.treeSha))return o("epic-merge-candidate-receipt-drift",!0,!1);let H=i.providerGuard;if(i.strategy==="single_pr"){if(!i.prNumber)return o("epic-terminal-pr-merge-unverified",!0,!1);if(await t("rev-parse",`${i.pushedSha}^{tree}`)!==b.treeSha)return o("epic-terminal-pr-merged-tree-mismatch",!1,!1);if(H&&!qe(H,i))return o("epic-terminal-pr-base-guard-unverifiable",!1,!1);H??={schemaVersion:1,provider:"github",mode:"recovered_exact_tree",source:"physical_recovery",prHeadSha:i.mergeSha,originHeadSha:i.baseSha,checkedAt:n,publicSafe:!0}}else if(H)return o("epic-terminal-pr-base-guard-unverifiable",!1,!1);return{ok:!0,candidateQa:b,candidateAuthority:x,...H?{providerGuard:H}:{}}}catch{return o("epic-terminal-physical-revalidation-failed",!0,!1)}},async applyReconciliation(e,i,n){if(i.action==="preserve")return o("git-reconciliation-preserve-not-actionable",!1,!1);if(n)return{ok:!0,outcome:"dry_run"};if(i.action==="no_op")return{ok:!0,outcome:"already_absent"};if(i.action==="delete_remote_branch")return He(e,i,t,d);try{const s=await F({candidate:e,decision:i,git:t,gh:d});if(!s.ok)return o(s.reasonCode,!0,!1);if(s.alreadyAbsent)return{ok:!0,outcome:"already_absent"};if(i.action==="delete_local_branch")await t("update-ref","-d",`refs/heads/${e.branchName}`,e.headSha);else if(i.action==="close_pull_request"){if(!e.prNumber)return o("git-reconciliation-pr-number-missing",!1,!1);const u=await O(t,d);if(!u)return o("git-resource-provider-repository-unverified",!0,!0);const h=`https://github.com/${u.nameWithOwner}`,f=`neocortex-reconciliation:${I("sha256").update(e.resourceId).digest("hex")}`,p=JSON.parse(await d("pr","view",String(e.prNumber),"--repo",h,"--json","comments"));if(!S(p)||!Array.isArray(p.comments)||p.comments.length>1e3||p.comments.some(w=>!S(w)||typeof w.body!="string"))return o("git-reconciliation-pr-comments-unverified",!0,!0);p.comments.some(w=>String(w.body).includes(f))||await d("pr","comment",String(e.prNumber),"--repo",h,"--body",`Neocortex reconciliation verified managed ownership and integrated content; requesting closure. [${f}]`);const l=await F({candidate:e,decision:i,git:t,gh:d});if(!l.ok)return o(l.reasonCode,!0,!1);if(l.alreadyAbsent)return{ok:!0,outcome:"already_absent"};await d("pr","close",String(e.prNumber),"--repo",h);const m=await F({candidate:e,decision:i,git:t,gh:d});if(!m.ok)return o(m.reasonCode,!0,!1);if(!m.alreadyAbsent)return o("git-reconciliation-pr-close-unverified",!0,!0)}return{ok:!0,outcome:"applied"}}catch{return o("git-reconciliation-effect-failed",!0,!1)}},async persist(e){try{let i;return await J(r,n=>{const s=T(n,e.terminalReceipt.epicId),u=Array.isArray(s.git_reconciliation_receipts)?s.git_reconciliation_receipts.filter(S):[],h=new Map(u.map(l=>[l.idempotencyKey,l]));for(const l of e.reconciliationReceipts)z(h.get(l.idempotencyKey))||h.set(l.idempotencyKey,l);const f=S(s.terminal_git_receipt)?s.terminal_git_receipt:null,p=we(f,e.terminalReceipt);if(p.kind==="blocked"){i=p.reasonCode;return}s.terminal_git_receipt=p.receipt,s.git_reconciliation_receipts=[...h.values()],s.physicalMergeStatus=e.terminalReceipt.physicalStatus==="pushed"?"merged":e.terminalReceipt.physicalStatus,s.pr_number=e.terminalReceipt.prNumber??s.pr_number??null,s.git_reconciliation_debt=ge(s.git_reconciliation_debt,e.preservedDecisions)}),i?o(i,!1,!1):{ok:!0}}catch{return o("epic-terminal-state-persist-failed",!0,!1)}},async persistReconciliation(e){try{return await J(r,i=>{const n=T(i,e.epicId),s=Array.isArray(n.git_reconciliation_receipts)?n.git_reconciliation_receipts.filter(S):[],u=new Map(s.map(h=>[h.idempotencyKey,h]));for(const h of e.reconciliationReceipts)z(u.get(h.idempotencyKey))||u.set(h.idempotencyKey,h);n.git_reconciliation_receipts=[...u.values()],n.git_reconciliation_debt=ge(n.git_reconciliation_debt,e.preservedDecisions)}),{ok:!0}}catch{return o("git-reconciliation-state-persist-failed",!0,!1)}}}}async function O(r,a){try{const c=await r("remote","get-url","origin"),t=c.match(/^https:\/\/github\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?\/?$/)?.[1]??c.match(/^git@github\.com:([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?$/)?.[1];if(!t)return null;const d=JSON.parse(await a("repo","view",`https://github.com/${t}`,"--json","id,nameWithOwner,url"));return d.nameWithOwner!==t||d.url!==`https://github.com/${t}`||typeof d.id!="string"||!/^[A-Za-z0-9_=-]{1,256}$/.test(d.id)?null:{id:d.id,nameWithOwner:t}}catch{return null}}async function He(r,a,c,t){try{if(r.kind!=="remote_branch"||a.resourceId!==r.resourceId||!r.baseBranch||r.baseBranch===r.branchName||!A(r.branchName)||!A(r.baseBranch)||!/^[a-f0-9]{40}$/.test(r.headSha)||!/^[a-f0-9]{40}$/.test(r.integrationHeadSha))return o("git-reconciliation-candidate-no-longer-safe",!1,!1);const d=await O(c,t);if(!d)return o("git-resource-remote-delete-cas-unavailable",!1,!1);if(!await C(c,r.branchName))return{ok:!0,outcome:"already_absent"};const e=await F({candidate:r,decision:a,git:c,gh:t});if(!e.ok)return o(e.reasonCode,!0,!1);if((await O(c,t))?.id!==d.id)return o("git-resource-provider-repository-raced",!0,!1);const n=I("sha256").update(["managed-remote-delete-v1",d.id,r.branchName,r.headSha,r.baseBranch,r.integrationHeadSha].join("\0")).digest("hex"),s=(f,p,l)=>`{name:${JSON.stringify(`refs/heads/${f}`)},beforeOid:${JSON.stringify(p)},afterOid:${JSON.stringify(l)},force:false}`,u=`mutation{updateRefs(input:{repositoryId:${JSON.stringify(d.id)},clientMutationId:${JSON.stringify(n)},refUpdates:[`+s(r.branchName,r.headSha,"0".repeat(40))+","+s(r.baseBranch,r.integrationHeadSha,r.integrationHeadSha)+"]}){clientMutationId}}",h=JSON.parse(await t("api","graphql","--hostname","github.com","-f",`query=${u}`));return h.errors||h.data?.updateRefs?.clientMutationId!==n?o("git-resource-remote-delete-cas-unverified",!0,!0):await C(c,r.branchName)?o("git-resource-remote-delete-recreated-or-unverified",!0,!1):{ok:!0,outcome:"applied"}}catch{return o("git-resource-remote-delete-cas-rejected",!0,!0)}}async function F(r){const{candidate:a,decision:c,git:t,gh:d}=r;if(!c.managed||!a.providerVerified||a.current||a.origin||a.protected||a.lifecycle==="active"||a.hasExclusiveCommits||a.worktreeActive)return{ok:!1,reasonCode:"git-reconciliation-candidate-no-longer-safe"};const g=await t("symbolic-ref","--quiet","--short","HEAD").catch(()=>""),e=await he(t);if(g===a.branchName||e.has(a.branchName))return{ok:!1,reasonCode:"git-resource-worktree-active"};if(a.kind==="local_branch"){const u=await ue(t,`refs/heads/${a.branchName}`);return u?u!==a.headSha?{ok:!1,reasonCode:"git-resource-expected-oid-raced"}:!a.baseBranch||await N(t,a.baseBranch)!==a.integrationHeadSha||!await R(t,u,a.integrationHeadSha)?{ok:!1,reasonCode:"git-resource-integration-unproven"}:{ok:!0}:{ok:!0,alreadyAbsent:!0}}if(a.kind==="remote_branch"){const u=await C(t,a.branchName);if(!u)return{ok:!0};if(u!==a.headSha)return{ok:!1,reasonCode:"git-resource-expected-oid-raced"};const h=await O(t,d);return h?await Z(d,h.nameWithOwner,a.branchName)!=="unprotected"?{ok:!1,reasonCode:"git-resource-protected"}:!a.baseBranch||await N(t,a.baseBranch)!==a.integrationHeadSha?{ok:!1,reasonCode:"git-resource-integration-unproven"}:(await t("fetch","--quiet","--no-tags","origin",`refs/heads/${a.branchName}`),await t("rev-parse","FETCH_HEAD")!==a.headSha||!await R(t,a.headSha,a.integrationHeadSha)?{ok:!1,reasonCode:"git-resource-integration-unproven"}:{ok:!0}):{ok:!1,reasonCode:"git-resource-provider-repository-unverified"}}if(!a.prNumber||!a.baseBranch)return{ok:!1,reasonCode:"git-reconciliation-pr-proof-missing"};const i=await O(t,d);if(!i)return{ok:!1,reasonCode:"git-resource-provider-repository-unverified"};const n=await K(d,i.nameWithOwner,a.prNumber);if(!n||n.headRefName!==a.branchName||n.baseRefName!==a.baseBranch||n.headRefOid!==a.headSha)return{ok:!1,reasonCode:"git-resource-expected-oid-raced"};if(n.state==="CLOSED"||n.state==="MERGED")return{ok:!0,alreadyAbsent:!0};if(await Z(d,i.nameWithOwner,a.branchName)!=="unprotected")return{ok:!1,reasonCode:"git-resource-protected"};const s=await C(t,a.branchName);return!n||n.state!=="OPEN"||n.headRefName!==a.branchName||n.baseRefName!==a.baseBranch||n.headRefOid!==a.headSha||s!==a.headSha?{ok:!1,reasonCode:"git-resource-expected-oid-raced"}:(await t("fetch","--quiet","--no-tags","origin",`refs/heads/${a.branchName}`),await t("rev-parse","FETCH_HEAD")!==a.headSha||await N(t,a.baseBranch)!==a.integrationHeadSha||!await R(t,a.headSha,a.integrationHeadSha)?{ok:!1,reasonCode:"git-resource-integration-unproven"}:{ok:!0})}async function oe(r){const a=[],c=await he(r.git),t=be(r.state),d=await O(r.git,r.gh),g=l=>{const m=l.split(`
|
|
2
|
+
`).filter(Boolean).map(x=>x.split(/\s+/));if(m.length>L)throw new Error("git-reconciliation-ref-inventory-limit");const w=new Map;for(const[x,b]of m){const H=b?.replace(/^refs\/heads\//,"");if(!H||!A(H)||!/^[a-f0-9]{40,64}$/.test(x??"")||w.has(H))throw new Error("git-reconciliation-ref-inventory-invalid");w.set(H,x)}return w},e=g(await r.git("for-each-ref",`--count=${L+1}`,"--format=%(objectname) %(refname)","refs/heads")),i=g(await r.git("ls-remote","--heads","origin")),n=d?await Be(r.gh,d.nameWithOwner):[],s=new Map([[r.directive.originBranch,r.originHeadSha]]),u=async l=>{if(s.has(l))return s.get(l);const m=i.get(l);return m?(await P(r.git,l,m),s.set(l,m),m):""},h=new Map,f=async(l,m)=>{const w=`${l}:${m}`;return h.has(w)||h.set(w,!!(l&&m)&&await R(r.git,l,m)),h.get(w)},p=new Set([...e.keys(),...i.keys(),...t.claims.keys(),...n.map(l=>l.headRefName)]);if(p.size>L)throw new Error("git-reconciliation-ref-inventory-limit");for(const l of[...p].sort()){if(!A(l))continue;const m=t.claims.get(l)??[],w=new Set(m.map(y=>`${y.epicId}:${y.origin}`)),x=w.size===1?m[0].origin:r.directive.originBranch,b=await u(x),H=m.length===0||m.some(y=>y.active),$=e.get(l),q=i.get(l);q&&await P(r.git,l,q);const B=d&&q?await Z(r.gh,d.nameWithOwner,l):"unknown",M=async y=>{if(w.size!==1)return[];const v=new Set;for(const E of m)for(const k of E.proofs)k.head===y&&(k.mergeSha&&(!k.pushedSha||!await f(y,k.mergeSha)||!await f(k.mergeSha,k.pushedSha)||!await f(k.pushedSha,b))||k.evidence.forEach(V=>v.add(V)));return[...v]},G={schemaVersion:1,branchName:l,baseBranch:x,integrationHeadSha:b,lifecycle:H?"active":"integrated",current:l===r.currentBranch,origin:t.origins.has(l)||l===r.directive.originBranch,worktreeActive:c.has(l),contentEquivalent:!1,publicSafe:!0};for(const[y,v]of[["local_branch",$],["remote_branch",q]]){if(!v)continue;const E=`${y}:${I("sha256").update(l).digest("hex")}:${v}`,k=await f(v,b);a.push({...G,resourceId:E,kind:y,headSha:v,ownershipEvidence:await M(v),protected:!!q&&B!=="unprotected",providerVerified:y==="local_branch"?!0:!!d&&B!=="unknown",...y==="remote_branch"&&d?{remoteDeletionCas:"github-update-refs-v1"}:{},commitsReachable:k,hasExclusiveCommits:!k,previouslyReconciled:r.receiptIds.has(E)})}for(const y of n.filter(v=>v.headRefName===l)){const v=y.baseRefName===x&&y.sameRepository,E=await M(y.headRefOid);v&&E.includes("managed_metadata")&&E.push("pr_head_base_match");const k=`pr:${y.number}:${y.headRefOid}:${I("sha256").update(y.baseRefName).digest("hex")}`,V=await f(y.headRefOid,b);a.push({...G,resourceId:k,kind:"pull_request",prNumber:y.number,headSha:y.headRefOid,lifecycle:y.state!=="OPEN"?"already_absent":H?"active":"superseded",ownershipEvidence:E,providerVerified:v,protected:B!=="unprotected",commitsReachable:V,hasExclusiveCommits:!V,previouslyReconciled:r.receiptIds.has(k)})}}return ke(r.epic,a),a}function ke(r,a){const c=new Set((Array.isArray(r.git_reconciliation_receipts)?r.git_reconciliation_receipts:[]).filter(S).map(g=>_(g.idempotencyKey))),t=new Set((Array.isArray(r.git_reconciliation_debt)?r.git_reconciliation_debt:[]).filter(S).map(g=>_(g.resourceId))),d=new Set(a.filter(g=>g.kind==="pull_request"&&ae(g).action==="close_pull_request").map(g=>g.branchName));for(const g of a){const e=ae(g);e.action==="preserve"?t.add(g.resourceId):(c.add(`reconciliation:v2:${I("sha256").update([g.resourceId,e.action].join("\0")).digest("hex")}`),g.kind!=="pull_request"&&d.has(g.branchName)&&t.add(g.resourceId))}if(c.size>1024)throw new Error("git-reconciliation-receipt-capacity");if(t.size>1024)throw new Error("git-reconciliation-debt-capacity")}function ce(r){const a=new Set(["git-reconciliation-state-inventory-limit","git-reconciliation-ref-inventory-limit","git-reconciliation-ref-inventory-invalid","git-reconciliation-pr-inventory-limit","git-reconciliation-pr-inventory-invalid","git-reconciliation-receipt-capacity","git-reconciliation-debt-capacity"]);return r instanceof Error&&a.has(r.message)?r.message:void 0}async function Be(r,a){const c=[],t=new Set;for(let d=1;d<=11;d+=1){const g=JSON.parse(await r("api",`repos/${a}/pulls?state=all&per_page=100&page=${d}`,"--hostname","github.com"));if(!Array.isArray(g)||g.length>100||d===11&&g.length>0)throw new Error("git-reconciliation-pr-inventory-limit");for(const e of g){if(!S(e)||!Number.isSafeInteger(e.number)||Number(e.number)<=0||t.has(Number(e.number))||!S(e.head)||!S(e.base)||!A(_(e.head.ref))||!A(_(e.base.ref))||!/^[a-f0-9]{40,64}$/.test(_(e.head.sha))||!["open","closed"].includes(_(e.state)))throw new Error("git-reconciliation-pr-inventory-invalid");t.add(Number(e.number)),c.push({number:Number(e.number),state:_(e.state).toUpperCase(),headRefName:_(e.head.ref),headRefOid:_(e.head.sha),baseRefName:_(e.base.ref),sameRepository:S(e.head.repo)&&S(e.base.repo)&&e.head.repo.full_name===a&&e.base.repo.full_name===a})}if(g.length<100)return c}throw new Error("git-reconciliation-pr-inventory-limit")}function z(r){return S(r)&&(r.outcome==="applied"||r.outcome==="already_absent")}async function Ne(r){try{const a=(await r.git("log",r.originHeadSha,"--format=%H","--fixed-strings",`--grep=Neocortex-Idempotency: ${r.directive.idempotencyKey}`)).split(`
|
|
3
|
+
`).filter(s=>/^[a-f0-9]{40,64}$/i.test(s));if(a.length!==1)return null;const c=a[0],t=(await r.git("rev-list","--parents","-n","1",c)).split(/\s+/),d=await r.git("show","-s","--format=%B",c),[g]=d.split(`
|
|
4
|
+
`),e=`merge(${r.directive.epicId}): integrate ${r.directive.executionBranch} into ${r.directive.originBranch}`;if(t.length!==3||t[2]!==r.executionHeadSha||g!==e)return null;const i=new Set(d.split(`
|
|
5
|
+
`).map(s=>s.trim()));for(const s of[`Neocortex-Epic: ${r.directive.epicId}`,`Neocortex-Origin-Branch: ${r.directive.originBranch}`,`Neocortex-Execution-Branch: ${r.directive.executionBranch}`,`Neocortex-Execution-Head: ${r.executionHeadSha}`,`Neocortex-Origin-Base: ${t[1]}`,`Neocortex-Graph-Revision: ${r.directive.graphRevision}`,`Neocortex-Aggregate-QA: ${r.directive.localGates.aggregateQaReceipt.receiptRef}`,`Neocortex-Idempotency: ${r.directive.idempotencyKey}`])if(!i.has(s))return null;const n=await r.git("show","-s","--format=%cI",c);return{schemaVersion:1,epicId:r.directive.epicId,executionBranch:r.directive.executionBranch,originBranch:r.directive.originBranch,baseSha:t[1],executionHeadSha:r.executionHeadSha,mergeSha:c,pushedSha:c,strategy:"direct",physicalStatus:"pushed",localGateReceiptRefs:r.directive.localGates.receiptRefs,idempotencyKey:r.directive.idempotencyKey,attemptStartedAt:n,completedAt:n,retryEligible:!1,reasonCodes:["epic-terminal-recovered-physical-push"],publicSafe:!0}}catch{return null}}async function Z(r,a,c){try{if(!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(a))return"unknown";const t=await r("api",`repos/${a}/branches/${encodeURIComponent(c)}`,"--hostname","github.com","--jq",".protected");return t==="false"?"unprotected":t==="true"?"protected":"unknown"}catch{return"unknown"}}async function K(r,a,c){try{const t=JSON.parse(await r("pr","view",String(c),"--repo",`https://github.com/${a}`,"--json","state,headRefName,headRefOid,baseRefName,mergeCommit"));return[t.state,t.headRefName,t.headRefOid,t.baseRefName].every(d=>typeof d=="string")?t:null}catch{return null}}async function $e(r,a,c,t,d,g){if(!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(a)||!A(c)||!/^[a-f0-9]{40,64}$/i.test(t)||!/^[a-f0-9]{40,64}$/i.test(d)||Number.isNaN(Date.parse(g)))return{ok:!1,reasonCode:"epic-terminal-pr-base-guard-unverifiable"};let e;try{const u=JSON.parse(await r("api",`repos/${a}/rules/branches/${encodeURIComponent(c)}`,"--hostname","github.com","--paginate","--slurp")),h=Array.isArray(u)&&u.every(Array.isArray)?u.flat():u;if(!Array.isArray(h)||h.length>256||h.some(f=>!S(f)))return{ok:!1,reasonCode:"epic-terminal-pr-base-guard-unverifiable"};e=h}catch{return{ok:!1,reasonCode:"epic-terminal-pr-base-guard-unverifiable"}}if(e.some(u=>u.type==="merge_queue"))return{ok:!1,reasonCode:"epic-terminal-pr-merge-queue-local-gate-required"};const i=e.some(u=>u.type==="required_status_checks"&&S(u.parameters)&&u.parameters.strict_required_status_checks_policy===!0);let n=!1;try{const u=JSON.parse(await r("api",`repos/${a}/branches/${encodeURIComponent(c)}/protection/required_status_checks`,"--hostname","github.com"));if(!S(u)||typeof u.strict!="boolean")return{ok:!1,reasonCode:"epic-terminal-pr-base-guard-unverifiable"};n=u.strict}catch(u){if(!Ae(u))return{ok:!1,reasonCode:"epic-terminal-pr-base-guard-unverifiable"}}return!i&&!n?{ok:!1,reasonCode:"epic-terminal-pr-strict-base-guard-required"}:{ok:!0,receipt:{schemaVersion:1,provider:"github",mode:"strict_up_to_date_expected_head",source:i&&n?"branch_protection_and_ruleset":i?"ruleset":"branch_protection",prHeadSha:t,originHeadSha:d,checkedAt:g,publicSafe:!0}}}function Ae(r){return r instanceof Error&&/(?:HTTP\s*)?404\b|not found/i.test(r.message)}function qe(r,a){const c=r.mode==="recovered_exact_tree"?r.source==="physical_recovery":r.mode==="strict_up_to_date_expected_head"&&["branch_protection","ruleset","branch_protection_and_ruleset"].includes(r.source);return r.schemaVersion===1&&r.provider==="github"&&c&&r.publicSafe===!0&&!Number.isNaN(Date.parse(r.checkedAt))&&r.prHeadSha===a.mergeSha&&r.originHeadSha===a.baseSha}async function se(r,a,c){return(await Re(r,[...a],{cwd:c,encoding:"utf8",maxBuffer:16777216})).stdout.trim()}async function D(r,a,c=!1){const t=JSON.parse(await te(a,"utf8"));return Se(t,await ve(r,{required:c}))}function de(r,a,c,t){if(!r||r.schemaVersion!==1||r.evidenceVersion!=="p205-execution-v2"||r.producer!=="local-yolo-tdd"||r.contract!=="P205-CI-02"||r.command!==Q||r.verdict!=="passed"||r.executionHeadSha!==a||r.graphRevision!==c||!/^[a-f0-9]{64}$/i.test(r.manifestDigest??"")||!/^[a-f0-9]{64}$/i.test(r.resultDigest??"")||r.gateIds.length===0)return!1;const d=`local-yolo-tdd:${I("sha256").update(["epic-aggregate-p205-execution-v2",Q,a,c,r.manifestDigest,r.gateIds.join(","),r.resultDigest].join("\0")).digest("hex")}`;if(r.receiptRef!==d)return!1;const g=Date.parse(r.checkedAt),e=Date.parse(t);return Number.isFinite(g)&&Number.isFinite(e)&&e-g<=1800*1e3&&g-e<=300*1e3}async function N(r,a){const c=await C(r,a);if(!c)throw new Error("origin-ref-missing");return c}async function C(r,a){if(!A(a))throw new Error("branch-ref-invalid");const t=(await r("ls-remote","--heads","origin",`refs/heads/${a}`)).split(`
|
|
6
|
+
`).filter(Boolean).map(d=>d.split(/\s+/));if(t.length!==0){if(t.length!==1||t[0].length!==2||t[0][1]!==`refs/heads/${a}`||!/^[a-f0-9]{40,64}$/i.test(t[0][0]??""))throw new Error("remote-ref-query-invalid");return t[0][0]}}async function P(r,a,c){if(await r("fetch","--quiet","--no-tags","origin",`refs/heads/${a}`),await r("rev-parse","FETCH_HEAD")!==c)throw new Error("remote-head-raced")}async function ue(r,a){try{return await r("rev-parse","--verify",a)}catch{return}}async function R(r,a,c){try{return await r("merge-base","--is-ancestor",a,c),!0}catch{return!1}}async function U(r,a){if(!/^[a-f0-9]{40,64}$/i.test(a))return!1;try{return await r("cat-file","-t",a)==="commit"}catch{return!1}}async function he(r){const a=new Set,c=await r("worktree","list","--porcelain");for(const t of c.split(`
|
|
7
|
+
`))t.startsWith("branch refs/heads/")&&a.add(t.slice(18));return a}function o(r,a,c){return{ok:!1,reasonCode:r,retryEligible:a,externalPolicy:c}}function _(r){return typeof r=="string"?r.trim():""}function A(r){return r.length>0&&r.length<=240&&!r.startsWith("-")&&!r.startsWith("/")&&!r.endsWith("/")&&!r.endsWith(".lock")&&!r.includes("..")&&!r.includes("\\")&&!r.includes("@{")&&!r.includes("//")&&/^[A-Za-z0-9._/-]+$/.test(r)}function S(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function Ee(r,a){return r instanceof Error&&"code"in r&&r.code===a}function j(r){return(Array.isArray(r.stories)?r.stories:Array.isArray(r.story_ids)?r.story_ids:[]).filter(c=>typeof c=="string")}async function Y(r,a,c,t,d){const g=j(c),e=await Promise.all(g.map(i=>ne(r,a.stories?.[i]?.checkpoint,i,t,d).then(n=>n&&le(a.stories?.[i]?.checkpoint))));return g.filter((i,n)=>e[n])}function le(r){const a=S(r)?r:void 0,c=a&&S(a.qaReceipt)?a.qaReceipt:void 0;return!!(c&&c.evidenceVersion==="p205-execution-v2"&&c.producer==="local-yolo-tdd"&&c.contract==="P205-CI-02"&&c.command===Q&&/^[a-f0-9]{64}$/i.test(_(c.manifestDigest))&&/^[a-f0-9]{64}$/i.test(_(c.resultDigest))&&Array.isArray(c.gateIds)&&c.gateIds.length>0)}function X(r,a){return r.length===a.length&&[...r].sort().every((c,t)=>c===[...a].sort()[t])}function ee(r){return S(r)&&typeof r.expiresAt=="string"&&r.expiresAt>new Date().toISOString()}async function fe(r){const a=new Set([".neocortex/yoloop.lock",".neocortex/yoloop-state.json",".neocortex/continuity/continuity.sqlite",".neocortex/continuity/continuity.sqlite-shm",".neocortex/continuity/continuity.sqlite-wal"]);return(await r("status","--porcelain","--untracked-files=all")).split(`
|
|
8
|
+
`).filter(Boolean).some(c=>!c.startsWith("?? ")||!a.has(c.slice(3)))}function re(r){const a=r instanceof Error?r.message:"";return/protected branch|branch protection|required pull request|GH006|GH013|ruleset|review required/i.test(a)}function ge(r,a){const c=Array.isArray(r)?r.filter(S):[],t=new Map(c.map(d=>[_(d.resourceId),d]));for(const d of a)t.set(d.resourceId,d);return[...t.values()]}export{We as createCliEpicTerminalGitAdapter};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type EpicGitReconciliationDirective, type EpicTerminalGitDirective, type EpicTerminalGitReceipt, type GitReconciliationCandidate, type GitReconciliationDecision, type GitReconciliationReceipt } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
2
|
+
import { type P205TransientExecutionAuthority } from '../../git/git-lifecycle-store.js';
|
|
3
|
+
import { type EpicMergeCandidateQaAuthority } from './epic-merge-candidate-qa.js';
|
|
4
|
+
import type { EpicMergeCandidateQaReceipt } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
5
|
+
import type { EpicPullRequestMergeGuardReceipt } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
6
|
+
export interface EpicTerminalGitSnapshot {
|
|
7
|
+
readonly executionHeadSha: string;
|
|
8
|
+
readonly originHeadSha: string;
|
|
9
|
+
readonly graphRevision?: string;
|
|
10
|
+
readonly writerLeaseActive: boolean;
|
|
11
|
+
readonly acceptedCheckpointIds: readonly string[];
|
|
12
|
+
readonly existingReceipt?: EpicTerminalGitReceipt | null;
|
|
13
|
+
readonly aggregateQaReceipt?: import('../../../../shared/dist/yoloop/epic-terminal-git.js').EpicAggregateQaReceipt | null;
|
|
14
|
+
readonly originBinding?: import('../../../../shared/dist/yoloop/epic-terminal-git.js').EpicOriginBindingEvidence | null;
|
|
15
|
+
readonly nowIso?: string;
|
|
16
|
+
readonly reconciliationCandidates: readonly GitReconciliationCandidate[];
|
|
17
|
+
}
|
|
18
|
+
export type EpicTerminalEffectResult<T extends object = object> = ({
|
|
19
|
+
readonly ok: true;
|
|
20
|
+
} & T) | {
|
|
21
|
+
readonly ok: false;
|
|
22
|
+
readonly reasonCode: string;
|
|
23
|
+
readonly retryEligible: boolean;
|
|
24
|
+
readonly externalPolicy: boolean;
|
|
25
|
+
};
|
|
26
|
+
export interface EpicTerminalGitAdapter {
|
|
27
|
+
/** Produce missing physical origin/aggregate-QA evidence before server projection. */
|
|
28
|
+
prepareLifecycleEvidence?(input: {
|
|
29
|
+
readonly epicId: string;
|
|
30
|
+
readonly nowIso: string;
|
|
31
|
+
}): Promise<EpicTerminalEffectResult<{
|
|
32
|
+
readonly originBindingCaptured: boolean;
|
|
33
|
+
readonly aggregateQaRecorded: boolean;
|
|
34
|
+
readonly p205Authority?: P205TransientExecutionAuthority;
|
|
35
|
+
}>>;
|
|
36
|
+
inspect(directive: EpicTerminalGitDirective): Promise<EpicTerminalEffectResult<{
|
|
37
|
+
readonly snapshot: EpicTerminalGitSnapshot;
|
|
38
|
+
}>>;
|
|
39
|
+
prepareMergeObject(input: {
|
|
40
|
+
readonly originBranch: string;
|
|
41
|
+
readonly executionBranch: string;
|
|
42
|
+
readonly originHeadSha: string;
|
|
43
|
+
readonly executionHeadSha: string;
|
|
44
|
+
readonly message: string;
|
|
45
|
+
readonly graphRevision: string;
|
|
46
|
+
readonly nowIso: string;
|
|
47
|
+
}): Promise<EpicTerminalEffectResult<{
|
|
48
|
+
readonly mergeSha: string;
|
|
49
|
+
readonly candidateQa?: EpicMergeCandidateQaReceipt;
|
|
50
|
+
readonly candidateAuthority?: EpicMergeCandidateQaAuthority;
|
|
51
|
+
}>>;
|
|
52
|
+
pushMergeObject(input: {
|
|
53
|
+
readonly epicId: string;
|
|
54
|
+
readonly originBranch: string;
|
|
55
|
+
readonly executionBranch: string;
|
|
56
|
+
readonly executionHeadSha: string;
|
|
57
|
+
readonly expectedOriginSha: string;
|
|
58
|
+
readonly mergeSha: string;
|
|
59
|
+
readonly graphRevision: string;
|
|
60
|
+
readonly candidateAuthority: EpicMergeCandidateQaAuthority;
|
|
61
|
+
readonly storyCheckpointIds: readonly string[];
|
|
62
|
+
readonly aggregateQaReceipt: EpicTerminalGitDirective['localGates']['aggregateQaReceipt'];
|
|
63
|
+
readonly nowIso: string;
|
|
64
|
+
}): Promise<EpicTerminalEffectResult<{
|
|
65
|
+
readonly pushedSha: string;
|
|
66
|
+
}>>;
|
|
67
|
+
ensureSingleEpicPullRequest(input: {
|
|
68
|
+
readonly epicId: string;
|
|
69
|
+
readonly originBranch: string;
|
|
70
|
+
readonly executionBranch: string;
|
|
71
|
+
readonly expectedStoryHeadSha: string;
|
|
72
|
+
readonly expectedPullRequestHeadSha: string;
|
|
73
|
+
readonly candidateQa: EpicMergeCandidateQaReceipt;
|
|
74
|
+
readonly candidateAuthority: EpicMergeCandidateQaAuthority;
|
|
75
|
+
readonly idempotencyKey: string;
|
|
76
|
+
}): Promise<EpicTerminalEffectResult<{
|
|
77
|
+
readonly prNumber: number;
|
|
78
|
+
}>>;
|
|
79
|
+
mergeEpicPullRequest(input: {
|
|
80
|
+
readonly prNumber: number;
|
|
81
|
+
readonly originBranch: string;
|
|
82
|
+
readonly executionBranch: string;
|
|
83
|
+
readonly expectedStoryHeadSha: string;
|
|
84
|
+
readonly expectedPullRequestHeadSha: string;
|
|
85
|
+
readonly expectedOriginHeadSha: string;
|
|
86
|
+
readonly candidateQa?: EpicMergeCandidateQaReceipt;
|
|
87
|
+
readonly candidateAuthority?: EpicMergeCandidateQaAuthority;
|
|
88
|
+
readonly nowIso: string;
|
|
89
|
+
}): Promise<EpicTerminalEffectResult<{
|
|
90
|
+
readonly mergeSha: string;
|
|
91
|
+
readonly pushedSha: string;
|
|
92
|
+
readonly providerGuard: EpicPullRequestMergeGuardReceipt;
|
|
93
|
+
}>>;
|
|
94
|
+
/** Fresh physical proof after direct push or provider merge, before persistence/cleanup. */
|
|
95
|
+
verifyTerminalReceipt(directive: EpicTerminalGitDirective, receipt: EpicTerminalGitReceipt, nowIso: string): Promise<EpicTerminalEffectResult<{
|
|
96
|
+
readonly candidateQa?: EpicMergeCandidateQaReceipt;
|
|
97
|
+
readonly candidateAuthority?: EpicMergeCandidateQaAuthority;
|
|
98
|
+
readonly providerGuard?: EpicPullRequestMergeGuardReceipt;
|
|
99
|
+
}>>;
|
|
100
|
+
applyReconciliation(candidate: GitReconciliationCandidate, decision: GitReconciliationDecision, dryRun: boolean): Promise<EpicTerminalEffectResult<{
|
|
101
|
+
readonly outcome: 'applied' | 'already_absent' | 'dry_run';
|
|
102
|
+
}>>;
|
|
103
|
+
inspectReconciliation(directive: EpicGitReconciliationDirective): Promise<EpicTerminalEffectResult<{
|
|
104
|
+
readonly candidates: readonly GitReconciliationCandidate[];
|
|
105
|
+
}>>;
|
|
106
|
+
persistReconciliation(input: {
|
|
107
|
+
readonly epicId: string;
|
|
108
|
+
readonly reconciliationReceipts: readonly GitReconciliationReceipt[];
|
|
109
|
+
readonly preservedDecisions: readonly GitReconciliationDecision[];
|
|
110
|
+
}): Promise<EpicTerminalEffectResult>;
|
|
111
|
+
persist(input: {
|
|
112
|
+
readonly terminalReceipt: EpicTerminalGitReceipt;
|
|
113
|
+
readonly reconciliationReceipts: readonly GitReconciliationReceipt[];
|
|
114
|
+
readonly preservedDecisions: readonly GitReconciliationDecision[];
|
|
115
|
+
}): Promise<EpicTerminalEffectResult>;
|
|
116
|
+
}
|
|
117
|
+
export interface EpicTerminalGitExecutionResult {
|
|
118
|
+
readonly ok: boolean;
|
|
119
|
+
readonly receipt: EpicTerminalGitReceipt;
|
|
120
|
+
readonly reconciliationReceipts: readonly GitReconciliationReceipt[];
|
|
121
|
+
readonly preservedDecisions: readonly GitReconciliationDecision[];
|
|
122
|
+
readonly reasonCodes: readonly string[];
|
|
123
|
+
readonly publicSafe: true;
|
|
124
|
+
}
|
|
125
|
+
export interface EpicGitReconciliationExecutionResult {
|
|
126
|
+
readonly ok: boolean;
|
|
127
|
+
readonly reconciliationReceipts: readonly GitReconciliationReceipt[];
|
|
128
|
+
readonly preservedDecisions: readonly GitReconciliationDecision[];
|
|
129
|
+
readonly reasonCodes: readonly string[];
|
|
130
|
+
readonly publicSafe: true;
|
|
131
|
+
}
|
|
132
|
+
/** Run the same fail-closed reconciler at start/resume or explicit audit. */
|
|
133
|
+
export declare function executeEpicGitReconciliation(directive: EpicGitReconciliationDirective, adapter: EpicTerminalGitAdapter, now: () => string): Promise<EpicGitReconciliationExecutionResult>;
|
|
134
|
+
export declare function executeEpicTerminalGit(directive: EpicTerminalGitDirective, adapter: EpicTerminalGitAdapter, now: () => string, preparedAuthority?: P205TransientExecutionAuthority): Promise<EpicTerminalGitExecutionResult>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createHash as G}from"node:crypto";import{EPIC_TERMINAL_GIT_REASON_CODES as x,classifyGitReconciliationCandidate as w,validateEpicTerminalGitDirective as N}from"../../../../shared/dist/yoloop/epic-terminal-git.js";import{p205TransientAuthorityMatchesAggregate as q}from"../../git/git-lifecycle-store.js";import{verifiedEpicMergeCandidateReceipt as _}from"./epic-merge-candidate-qa.js";async function O(e,o,t){const c=await o.inspectReconciliation(e);if(!c.ok)return{ok:!1,reconciliationReceipts:[],preservedDecisions:[],reasonCodes:[c.reasonCode],publicSafe:!0};const a=await E({idempotencyKey:e.idempotencyKey,enabled:!0,dryRun:e.dryRun},c.candidates,o,t),l=await o.persistReconciliation({epicId:e.epicId,reconciliationReceipts:a.receipts,preservedDecisions:a.preserved}),h=R([...a.reasonCodes,...l.ok?[]:[l.reasonCode]]);return{ok:a.ok&&l.ok,reconciliationReceipts:a.receipts,preservedDecisions:a.preserved,reasonCodes:h,publicSafe:!0}}async function T(e,o,t,c){const a=t();if(!o.prepareLifecycleEvidence)return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-producer-required",retryEligible:!1,externalPolicy:!1},a);const l=c?{ok:!0,originBindingCaptured:!1,aggregateQaRecorded:!0,p205Authority:c}:await o.prepareLifecycleEvidence({epicId:e.epicId,nowIso:a});if(!l.ok)return m(e,l,a);if(!l.p205Authority)return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-authority-required",retryEligible:!1,externalPolicy:!1},a);const h=await o.inspect(e);if(!h.ok)return m(e,h,a);const r=h.snapshot;if(!q(l.p205Authority,r.executionHeadSha,e.graphRevision))return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-authority-binding-mismatch",retryEligible:!1,externalPolicy:!1},a);const p=N(e,{...r,nowIso:a});if(!p.ready)return y(!1,f(e,r,a,{strategy:e.strategy==="single_pr"?"single_pr":"direct",physicalStatus:"blocked_local_or_repo",retryEligible:p.reasonCodes.some(n=>n.endsWith("mismatch")||n.endsWith("active")),reasonCodes:p.reasonCodes}),[],[],p.reasonCodes);if(p.reasonCodes.includes(x.ALREADY_COMPLETE)&&r.existingReceipt){const n=await o.verifyTerminalReceipt(e,r.existingReceipt,a);if(!n.ok)return y(!1,r.existingReceipt,[],[],[n.reasonCode]);const k=_(n.candidateAuthority,{mergeSha:r.existingReceipt.mergeSha,originHeadSha:r.existingReceipt.baseSha,executionHeadSha:r.existingReceipt.executionHeadSha,graphRevision:e.graphRevision});if(!k)return y(!1,r.existingReceipt,[],[],["epic-merge-candidate-authority-required"]);const B={...r.existingReceipt,candidateQa:k,...n.providerGuard?{providerGuard:n.providerGuard}:{}},S=await E({idempotencyKey:e.idempotencyKey,enabled:e.reconcile.enabled,dryRun:e.reconcile.dryRun},r.reconciliationCandidates,o,t),b=await o.persist({terminalReceipt:B,reconciliationReceipts:S.receipts,preservedDecisions:S.preserved}),A=R([...p.reasonCodes,...S.reasonCodes,...b.ok?[]:[b.reasonCode]]);return y(b.ok&&S.ok,B,S.receipts,S.preserved,A)}let i;const s=await o.prepareMergeObject({originBranch:e.originBranch,executionBranch:e.executionBranch,originHeadSha:r.originHeadSha,executionHeadSha:r.executionHeadSha,graphRevision:e.graphRevision,nowIso:a,message:[`merge(${e.epicId}): integrate ${e.executionBranch} into ${e.originBranch}`,"",`Neocortex-Epic: ${e.epicId}`,`Neocortex-Origin-Branch: ${e.originBranch}`,`Neocortex-Execution-Branch: ${e.executionBranch}`,`Neocortex-Execution-Head: ${r.executionHeadSha}`,`Neocortex-Origin-Base: ${r.originHeadSha}`,`Neocortex-Graph-Revision: ${e.graphRevision}`,`Neocortex-Aggregate-QA: ${e.localGates.aggregateQaReceipt.receiptRef}`,`Neocortex-Idempotency: ${e.idempotencyKey}`].join(`
|
|
2
|
+
`)});if(!s.ok)return i=f(e,r,a,{strategy:"direct",physicalStatus:"blocked_local_or_repo",retryEligible:s.retryEligible,reasonCodes:[s.reasonCode]}),await o.persist({terminalReceipt:i,reconciliationReceipts:[],preservedDecisions:[]}),y(!1,i,[],[],i.reasonCodes);const d=_(s.candidateAuthority,{originHeadSha:r.originHeadSha,executionHeadSha:r.executionHeadSha,mergeSha:s.mergeSha,graphRevision:e.graphRevision});if(!d)return m(e,{ok:!1,reasonCode:"epic-merge-candidate-authority-required",retryEligible:!1,externalPolicy:!1},a);if(e.strategy!=="single_pr"){const n=await o.pushMergeObject({epicId:e.epicId,originBranch:e.originBranch,executionBranch:e.executionBranch,executionHeadSha:r.executionHeadSha,expectedOriginSha:r.originHeadSha,mergeSha:s.mergeSha,graphRevision:e.graphRevision,candidateAuthority:s.candidateAuthority,storyCheckpointIds:e.storyCheckpointIds,aggregateQaReceipt:e.localGates.aggregateQaReceipt,nowIso:t()});n.ok?i=f(e,r,a,{strategy:"direct",mergeSha:s.mergeSha,pushedSha:n.pushedSha,candidateQa:d,physicalStatus:"pushed",retryEligible:!1,reasonCodes:[x.READY],completedAt:t()}):e.strategy==="direct_or_single_pr"&&n.externalPolicy?i=await I(e,r,o,a,t,d,s.candidateAuthority):i=f(e,r,a,{strategy:"direct",mergeSha:s.mergeSha,physicalStatus:n.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:n.retryEligible,reasonCodes:[n.reasonCode,...n.retryEligible?[x.RETRY_ELIGIBLE]:[]]})}else i=await I(e,r,o,a,t,d,s.candidateAuthority);const u=i.physicalStatus==="pushed"?await o.verifyTerminalReceipt(e,i,t()):null;if(u&&!u.ok){const n=f(e,r,a,{...i,physicalStatus:"blocked_local_or_repo",retryEligible:u.retryEligible,reasonCodes:[u.reasonCode]});return await o.persist({terminalReceipt:n,reconciliationReceipts:[],preservedDecisions:[]}),y(!1,n,[],[],n.reasonCodes)}if(u?.ok){const n=_(u.candidateAuthority,{mergeSha:i.mergeSha,originHeadSha:i.baseSha,executionHeadSha:i.executionHeadSha,graphRevision:e.graphRevision});if(!n)return y(!1,i,[],[],["epic-merge-candidate-authority-required"]);i={...i,candidateQa:n,...u.providerGuard?{providerGuard:u.providerGuard}:{}}}const g=i.physicalStatus==="pushed"?await E({idempotencyKey:e.idempotencyKey,enabled:e.reconcile.enabled,dryRun:e.reconcile.dryRun},r.reconciliationCandidates,o,t):{ok:!0,receipts:[],preserved:[],reasonCodes:[]},C=await o.persist({terminalReceipt:i,reconciliationReceipts:g.receipts,preservedDecisions:g.preserved}),H=R([...i.reasonCodes,...g.reasonCodes,...C.ok?[]:[C.reasonCode]]);return y(i.physicalStatus==="pushed"&&g.ok&&C.ok,i,g.receipts,g.preserved,H)}async function I(e,o,t,c,a,l,h){const r=await t.ensureSingleEpicPullRequest({epicId:e.epicId,originBranch:e.originBranch,executionBranch:e.executionBranch,expectedStoryHeadSha:o.executionHeadSha,expectedPullRequestHeadSha:l.mergeSha,candidateQa:l,candidateAuthority:h,idempotencyKey:e.idempotencyKey});if(!r.ok)return f(e,o,c,{strategy:"single_pr",physicalStatus:r.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:r.retryEligible,reasonCodes:[r.reasonCode]});const p=await t.mergeEpicPullRequest({prNumber:r.prNumber,originBranch:e.originBranch,executionBranch:e.executionBranch,expectedStoryHeadSha:o.executionHeadSha,expectedPullRequestHeadSha:l.mergeSha,expectedOriginHeadSha:o.originHeadSha,candidateQa:l,candidateAuthority:h,nowIso:a()});return p.ok?f(e,o,c,{strategy:"single_pr",prNumber:r.prNumber,mergeSha:p.mergeSha,pushedSha:p.pushedSha,candidateQa:l,providerGuard:p.providerGuard,physicalStatus:"pushed",retryEligible:!1,reasonCodes:[x.READY],completedAt:a()}):f(e,o,c,{strategy:"single_pr",prNumber:r.prNumber,physicalStatus:p.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:p.retryEligible,reasonCodes:[p.reasonCode,...p.retryEligible?[x.RETRY_ELIGIBLE]:[]]})}async function E(e,o,t,c){if(!e.enabled)return{ok:!0,receipts:[],preserved:[],reasonCodes:[]};const a=[],l=[],h=[];let r=!0;const p=new Set,i={pull_request:0,local_branch:1,remote_branch:2};for(const s of[...o].sort((d,u)=>i[d.kind]-i[u.kind]||d.resourceId.localeCompare(u.resourceId))){const d=w(s);if(h.push(...d.reasonCodes),d.action==="preserve"){l.push(d);continue}if(s.kind!=="pull_request"&&p.has(s.branchName)){l.push({...d,action:"preserve",reasonCodes:["git-resource-related-pr-close-pending"]}),h.push("git-resource-related-pr-close-pending");continue}const u=`reconciliation:v2:${G("sha256").update([s.resourceId,d.action].join("\0")).digest("hex")}`,g=await t.applyReconciliation(s,d,e.dryRun);if(!g.ok){r=!1,s.kind==="pull_request"&&p.add(s.branchName),h.push(g.reasonCode),a.push({schemaVersion:1,resourceId:s.resourceId,action:d.action,outcome:"failed",idempotencyKey:u,reasonCodes:[g.reasonCode],recordedAt:c(),publicSafe:!0});continue}a.push({schemaVersion:1,resourceId:s.resourceId,action:d.action,outcome:g.outcome,idempotencyKey:u,reasonCodes:d.reasonCodes,recordedAt:c(),publicSafe:!0})}return{ok:r,receipts:a,preserved:l,reasonCodes:R(h)}}function f(e,o,t,c){return Object.freeze({schemaVersion:1,epicId:e.epicId,executionBranch:e.executionBranch,originBranch:e.originBranch,baseSha:o.originHeadSha,executionHeadSha:o.executionHeadSha,localGateReceiptRefs:e.localGates.receiptRefs,idempotencyKey:e.idempotencyKey,attemptStartedAt:t,publicSafe:!0,...c})}function m(e,o,t){const c="0".repeat(40),a={schemaVersion:1,epicId:e.epicId,executionBranch:e.executionBranch,originBranch:e.originBranch,baseSha:c,executionHeadSha:e.expectedExecutionHeadSha,strategy:e.strategy==="single_pr"?"single_pr":"direct",physicalStatus:o.externalPolicy?"denied_external_gate":"blocked_local_or_repo",localGateReceiptRefs:e.localGates.receiptRefs,idempotencyKey:e.idempotencyKey,attemptStartedAt:t,retryEligible:o.retryEligible,reasonCodes:[o.reasonCode],publicSafe:!0};return y(!1,a,[],[],a.reasonCodes)}function y(e,o,t,c,a){return{ok:e,receipt:o,reconciliationReceipts:t,preservedDecisions:c,reasonCodes:R(a),publicSafe:!0}}function R(e){return[...new Set(e)]}export{O as executeEpicGitReconciliation,T as executeEpicTerminalGit};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as u}from"node:crypto";import{validateYoloopPreparationBundle as
|
|
1
|
+
import{createHash as u}from"node:crypto";import{validateYoloopPreparationBundle as h}from"../../../../shared/dist/yoloop/wave-decision-receipt.js";function f(e){const r=[],s=Array.isArray(e.phases)?e.phases.filter(a):[],i=a(e.budgets)?e.budgets:{};(e.version!==2||!c(e.graphRevision))&&r.push("phased-plan-invalid"),i.maxWriteConcurrency!==1&&r.push("writer-concurrency-invalid");for(const t of s)(!Number.isInteger(t.maxConcurrency)||Number(t.maxConcurrency)<1)&&r.push("phase-concurrency-invalid"),(t.mutatesEpicCheckout===!0||t.mutatesEpicWorktree===!0)&&(t.maxConcurrency!==1||!["epic-writer-lease","commit-range"].includes(String(t.isolation)))&&r.push("mutating-phase-not-serialized");["read-only-analysis","isolated-build-test","patch-preparation","single-writer-integration","story-checkpoint-review"].some(t=>!s.some(n=>n.kind===t))&&r.push("phase-missing");const o=Array.isArray(e.decisionReceiptIds)?e.decisionReceiptIds:[];(o.length===0||o.some(t=>!c(t)))&&r.push("decision-receipt-invalid");const d=Math.max(1,...s.filter(t=>t.mutatesEpicCheckout!==!0&&t.mutatesEpicWorktree!==!0).map(t=>Number(t.maxConcurrency)||1));return{ok:r.length===0,preparationConcurrency:d,childExecutionConcurrency:1,reasonCodes:[...new Set(r)].sort()}}function g(e){const r=[...h(e.bundle,e.expected)];return e.bundle.claimRevision!==e.expected.claimRevision&&r.push("bundle-claims-stale"),l(e.bundle.authorizedWriteSet,e.expected.authorizedWriteSet??[])||r.push("bundle-write-set-stale"),u("sha256").update(e.payload).digest("hex")!==e.bundle.bundleDigest&&r.push("bundle-payload-digest-mismatch"),(!e.writerLease||e.writerLease.ownerStoryId!==e.bundle.storyId||e.writerLease.expiresAt<=e.expected.nowIso)&&r.push("bundle-writer-lease-missing"),[...new Set(r)].sort()}function a(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function c(e){return typeof e=="string"&&/^[a-f0-9]{40,64}$/.test(e)}function l(e,r){return e.length===r.length&&e.every((s,i)=>s===r[i])}export{g as admitPreparedStoryBundle,f as validatePhasedYoloopPlan};
|