@ornexus/neocortex 4.60.63 → 4.60.65
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/release-source.json +1 -1
- package/dist/sbom.cdx.json +31 -38
- package/install.js +1 -0
- package/install.ps1 +34 -3
- package/install.sh +35 -3
- package/package.json +5 -3
- package/packages/client/dist/cli.js +8 -3
- package/packages/client/dist/commands/activate.js +8 -8
- package/packages/client/dist/commands/architecture-memory-terminal.js +4 -2
- package/packages/client/dist/commands/architecture-non-ui-continuation.d.ts +3 -0
- package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -0
- package/packages/client/dist/commands/invoke.d.ts +19 -16
- package/packages/client/dist/commands/invoke.js +80 -75
- package/packages/client/dist/commands/mutation-qa-run.js +2 -2
- package/packages/client/dist/commands/planning-generation.js +1 -1
- package/packages/client/dist/commands/planning-memory.d.ts +1 -0
- package/packages/client/dist/commands/planning-memory.js +1 -0
- package/packages/client/dist/commands/private-session.d.ts +1 -0
- package/packages/client/dist/commands/private-session.js +1 -0
- package/packages/client/dist/commands/qa-control.d.ts +4 -0
- package/packages/client/dist/commands/qa-control.js +1 -0
- package/packages/client/dist/commands/qa-scan-browser-launch.d.ts +8 -0
- package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -0
- package/packages/client/dist/commands/qa-scan-browser-route.d.ts +3 -0
- package/packages/client/dist/commands/qa-scan-browser-route.js +1 -0
- package/packages/client/dist/commands/qa-scan-capture.d.ts +43 -0
- package/packages/client/dist/commands/qa-scan-capture.js +5 -5
- package/packages/client/dist/commands/qa-scan-discovery.d.ts +7 -0
- package/packages/client/dist/commands/qa-scan-discovery.js +3 -3
- package/packages/client/dist/commands/qa-scan-review.d.ts +8 -1
- package/packages/client/dist/commands/qa-scan-review.js +5 -5
- package/packages/client/dist/commands/qa-synthetic-backend-capture.d.ts +62 -0
- package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -0
- package/packages/client/dist/commands/qa-synthetic-backend-review.d.ts +104 -0
- package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -0
- package/packages/client/dist/commands/qa-synthetic-backend.d.ts +52 -0
- package/packages/client/dist/commands/qa-synthetic-backend.js +7 -0
- package/packages/client/dist/commands/qa-synthetic-broker-port.d.ts +30 -0
- package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -0
- package/packages/client/dist/commands/qa-synthetic-browser.d.ts +1 -0
- package/packages/client/dist/commands/qa-synthetic-browser.js +1 -0
- package/packages/client/dist/commands/refactor-characterization.d.ts +4 -2
- package/packages/client/dist/commands/refactor-characterization.js +21 -12
- package/packages/client/dist/commands/refactor-control.d.ts +9 -0
- package/packages/client/dist/commands/refactor-control.js +3 -0
- package/packages/client/dist/commands/refactor-cpp-assertions.d.ts +4 -0
- package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -0
- package/packages/client/dist/commands/refactor-review.js +5 -5
- package/packages/client/dist/commands/refactor-root.d.ts +8 -1
- package/packages/client/dist/commands/refactor-root.js +7 -7
- package/packages/client/dist/commands/refresh-memory.d.ts +1 -0
- package/packages/client/dist/commands/refresh-memory.js +3 -3
- package/packages/client/dist/commands/shared-architecture-non-ui.d.ts +18 -0
- package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -0
- package/packages/client/dist/errors/error-messages.js +1 -1
- package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +5 -1
- package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -4
- package/packages/client/dist/git/git-lifecycle-store.d.ts +2 -0
- package/packages/client/dist/git/git-lifecycle-store.js +9 -8
- package/packages/client/dist/license/license-client.d.ts +3 -1
- package/packages/client/dist/license/license-client.js +1 -1
- package/packages/client/dist/memory/project-memory-path-scope.d.ts +4 -0
- package/packages/client/dist/memory/project-memory-path-scope.js +1 -0
- package/packages/client/dist/memory/project-memory-writer.d.ts +4 -1
- package/packages/client/dist/memory/project-memory-writer.js +16 -16
- package/packages/client/dist/private-execution/codex-executor.d.ts +24 -4
- package/packages/client/dist/private-execution/codex-executor.js +4 -2
- package/packages/client/dist/private-execution/codex-host-runtime.d.ts +10 -0
- package/packages/client/dist/private-execution/codex-host-runtime.js +1 -0
- package/packages/client/dist/private-execution/codex-lifecycle-guard.d.ts +4 -0
- package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -0
- package/packages/client/dist/private-execution/codex-scoped-permissions.d.ts +8 -0
- package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -0
- package/packages/client/dist/private-execution/delivery.d.ts +17 -1
- package/packages/client/dist/private-execution/delivery.js +11 -3
- package/packages/client/dist/private-execution/diagnosis-root-review.d.ts +112 -0
- package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -0
- package/packages/client/dist/private-execution/frozen-handoff.d.ts +2 -0
- package/packages/client/dist/private-execution/frozen-handoff.js +6 -0
- package/packages/client/dist/private-execution/implementation-validation.d.ts +15 -0
- package/packages/client/dist/private-execution/implementation-validation.js +2 -0
- package/packages/client/dist/private-execution/isolated-admission.d.ts +11 -7
- package/packages/client/dist/private-execution/isolated-admission.js +17 -10
- package/packages/client/dist/private-execution/isolated-session.d.ts +68 -0
- package/packages/client/dist/private-execution/isolated-session.js +5 -2
- package/packages/client/dist/private-execution/pact-test-source.d.ts +1 -1
- package/packages/client/dist/private-execution/pact-test-source.js +1 -1
- package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.d.ts +2 -0
- package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -5
- package/packages/client/dist/private-execution/planning-generation-checkpoint.d.ts +13 -0
- package/packages/client/dist/private-execution/planning-generation-checkpoint.js +4 -3
- package/packages/client/dist/private-execution/planning-memory-checkpoint.d.ts +32 -0
- package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -0
- package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -4
- package/packages/client/dist/private-execution/root-checkpoint.js +1 -1
- package/packages/client/dist/private-execution/root-memory-git-evidence.d.ts +30 -0
- package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -0
- package/packages/client/dist/private-execution/root-memory-recovery.d.ts +16 -0
- package/packages/client/dist/private-execution/root-memory-recovery.js +1 -0
- package/packages/client/dist/private-execution/root-memory-request.d.ts +28 -0
- package/packages/client/dist/private-execution/root-memory-request.js +1 -0
- package/packages/client/dist/private-execution/root-memory-scope.d.ts +28 -0
- package/packages/client/dist/private-execution/root-memory-scope.js +1 -0
- package/packages/client/dist/private-execution/root-memory-writer.d.ts +22 -0
- package/packages/client/dist/private-execution/root-memory-writer.js +1 -0
- package/packages/client/dist/private-execution/session-lease.d.ts +19 -0
- package/packages/client/dist/private-execution/session-lease.js +1 -0
- package/packages/client/dist/private-execution/shared-private-admission-types.d.ts +34 -0
- package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -0
- package/packages/client/dist/private-execution/shared-project-validation.d.ts +17 -0
- package/packages/client/dist/private-execution/shared-project-validation.js +1 -0
- package/packages/client/dist/private-execution/shared-root-memory-types.d.ts +37 -0
- package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -0
- package/packages/client/dist/runner/binary.d.ts +1 -1
- package/packages/client/dist/runner/binary.js +1 -1
- package/packages/client/dist/runner/headless/opencode-adapter.js +2 -2
- package/packages/client/dist/yolo/change-evidence-collector.d.ts +2 -2
- package/packages/client/dist/yolo/change-evidence-collector.js +1 -1
- package/packages/client/dist/yolo/spec-envelope-collector.js +2 -2
- package/packages/shared/dist/planning/diagnosis-state.js +5 -2
- package/packages/shared/dist/project-memory-targets.js +243 -0
- package/packages/shared/dist/yolo/change-evidence.js +35 -0
- package/packages/shared/dist/yoloop/branch-unit.js +10 -1
- package/packages/shared/dist/yoloop/root-memory-effect.js +57 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- 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 +2 -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 +1 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/deepseek-harness/SKILL.md +64 -0
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RootProjectMemoryEffect } from './shared-root-memory-types.js';
|
|
1
2
|
import { type PrivateYoloIsolatedAdmissionV1 } from './isolated-admission.js';
|
|
2
3
|
import { type PrivateYoloIsolatedWorkspaceV1 } from './isolated-workspace.js';
|
|
3
4
|
export interface PrivateYoloIsolatedSessionV1 {
|
|
@@ -12,7 +13,43 @@ export interface PrivateYoloIsolatedSessionV1 {
|
|
|
12
13
|
readonly snapshotSha: string;
|
|
13
14
|
readonly sequence: number;
|
|
14
15
|
readonly lastPatchSha256: string | null;
|
|
16
|
+
readonly rootMemoryEffect?: RootProjectMemoryEffect;
|
|
15
17
|
}
|
|
18
|
+
/** Root-owned C07. The child may propose notes; only this controller runs the writer. */
|
|
19
|
+
export declare function acceptPrivateYoloProjectMemoryRootReview(projectRoot: string, request: unknown, options?: {
|
|
20
|
+
/** Root fault observation only; never replaces the writer, proof or accepted result. */
|
|
21
|
+
readonly fault?: (point: 'after-prepared-journal' | 'after-source-admission' | 'before-session-pin') => void | Promise<void>;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
schemaVersion: number;
|
|
24
|
+
outcome: string;
|
|
25
|
+
storyId: string;
|
|
26
|
+
graphRevision: string;
|
|
27
|
+
receiptId: string;
|
|
28
|
+
snapshotSha: string;
|
|
29
|
+
reused: boolean;
|
|
30
|
+
sourceStateUnchanged: boolean;
|
|
31
|
+
phaseRecovered: boolean;
|
|
32
|
+
independentStoryQaAccepted: boolean;
|
|
33
|
+
terminalAccepted: boolean;
|
|
34
|
+
publicSafe: boolean;
|
|
35
|
+
preparedRecovered?: undefined;
|
|
36
|
+
sourceWriteReused?: undefined;
|
|
37
|
+
} | {
|
|
38
|
+
schemaVersion: number;
|
|
39
|
+
outcome: string;
|
|
40
|
+
storyId: string;
|
|
41
|
+
graphRevision: string;
|
|
42
|
+
receiptId: string;
|
|
43
|
+
snapshotSha: string;
|
|
44
|
+
reused: boolean;
|
|
45
|
+
sourceStateUnchanged: boolean;
|
|
46
|
+
preparedRecovered: boolean;
|
|
47
|
+
sourceWriteReused: boolean;
|
|
48
|
+
independentStoryQaAccepted: boolean;
|
|
49
|
+
terminalAccepted: boolean;
|
|
50
|
+
publicSafe: boolean;
|
|
51
|
+
phaseRecovered?: undefined;
|
|
52
|
+
}>;
|
|
16
53
|
/** Reserve one clone for the exact C01 session, without launching an agent. */
|
|
17
54
|
export declare function beginPrivateYoloIsolatedSession(workspace: PrivateYoloIsolatedWorkspaceV1, storyId: string, graphRevision: string): Promise<PrivateYoloIsolatedSessionV1>;
|
|
18
55
|
/** Require a previously admitted patch before accepting a new server graph. */
|
|
@@ -39,3 +76,34 @@ export interface PrivateYoloStagedBundleV1 {
|
|
|
39
76
|
* immutable base-to-snapshot patch. QA and checkpoint remain separate gates.
|
|
40
77
|
*/
|
|
41
78
|
export declare function stagePrivateYoloIsolatedSessionBundle(projectRoot: string, storyId: string, graphRevision: string): Promise<PrivateYoloStagedBundleV1>;
|
|
79
|
+
export interface PrivateYoloRejectedCandidateInspectionV1 {
|
|
80
|
+
readonly schemaVersion: 'PrivateYoloRejectedCandidateInspection/1';
|
|
81
|
+
readonly storyId: string;
|
|
82
|
+
readonly graphRevision: string;
|
|
83
|
+
readonly snapshotSha: string;
|
|
84
|
+
readonly sourceHead: string;
|
|
85
|
+
readonly sequence: number;
|
|
86
|
+
readonly candidateDigest: string;
|
|
87
|
+
readonly changedPaths: readonly string[];
|
|
88
|
+
readonly publicSafe: true;
|
|
89
|
+
}
|
|
90
|
+
/** The parent must first observe executor termination. Never resets a source or changes a pin. */
|
|
91
|
+
export declare function inspectPrivateYoloRejectedCandidate(projectRoot: string, storyId: string, graphRevision: string, executorStopped: boolean): Promise<PrivateYoloRejectedCandidateInspectionV1>;
|
|
92
|
+
/** Discard only the explicitly inspected unaccepted delta, after encrypted custody. */
|
|
93
|
+
export declare function discardPrivateYoloRejectedCandidate(projectRoot: string, storyId: string, graphRevision: string, input: {
|
|
94
|
+
readonly expectedCandidateDigest: string;
|
|
95
|
+
readonly executorStopped: true;
|
|
96
|
+
readonly authorizeDiscard: true;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
readonly schemaVersion: 'PrivateYoloRejectedCandidateRecovery/1';
|
|
99
|
+
readonly outcome: 'candidate-discarded';
|
|
100
|
+
readonly archiveId: string;
|
|
101
|
+
readonly archiveSha256: string;
|
|
102
|
+
readonly candidateDigest: string;
|
|
103
|
+
readonly snapshotSha: string;
|
|
104
|
+
readonly sourceHead: string;
|
|
105
|
+
readonly sessionPinPreserved: true;
|
|
106
|
+
readonly sourcePreserved: true;
|
|
107
|
+
readonly checkpointAccepted: false;
|
|
108
|
+
readonly publicSafe: true;
|
|
109
|
+
}>;
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import{execFileSync as
|
|
2
|
-
`)
|
|
1
|
+
import{execFileSync as ge,spawnSync as _e}from"node:child_process";import{createCipheriv as Ae,createHash as T,randomBytes as Ee,randomUUID as Oe}from"node:crypto";import{existsSync as Y,lstatSync as U,mkdirSync as qe,readFileSync as R,unlinkSync as Te}from"node:fs";import{homedir as De}from"node:os";import{basename as Ge,dirname as Be,join as v,resolve as _}from"node:path";import{isRootProjectMemoryEffect as Ce,rootProjectMemoryPaths as Me}from"./shared-root-memory-types.js";import{readPrivateRootMemoryScope as Ne,privateRootMemoryEffect as xe}from"./root-memory-scope.js";import{executeRootMemoryWriter as ze,rootMemoryFileState as Re,verifyRootMemoryWriterExecution as He}from"./root-memory-writer.js";import{rootMemoryGitFileState as $e,verifyRootMemoryEffectGitEvidence as Le}from"./root-memory-git-evidence.js";import{parsePrivateRootMemoryRequest as Ye}from"./root-memory-request.js";import{rootMemoryOperationJournalName as Je,readVerifiedPreparedRootMemory as Ve}from"./root-memory-recovery.js";import{assertProjectMemoryPaths as Fe}from"../memory/project-memory-path-scope.js";import{isDeepStrictEqual as J}from"node:util";import{acquireGitLifecyclePhysicalIntegrationLock as We,applyGitLifecycleRuntimeOverlay as Qe,assertGitLifecyclePrivateFile as X,ensureGitLifecyclePrivateChildDirectory as Z,gitLifecycleRuntimeDirectory as ke,mutateGitLifecycleRuntime as Ke,readGitLifecycleRuntimeSync as ue,releaseGitLifecyclePhysicalIntegrationLock as Ue}from"../git/git-lifecycle-store.js";import{anchoredAtomicWriteFile as z,anchoredDirectoryIdentity as Xe,anchoredExecuteGit as Ze}from"../git/secure-filesystem-boundary.js";import{privateYoloRootOnlySetupReady as et,readPrivateYoloFrozenWriteSet as M,readPrivateYoloFrozenWriteSetForTransition as tt}from"./clean-baseline.js";import{admitPrivateYoloFrozenWorkspace as at,verifyPrivateYoloSnapshotBoundary as V,verifyPrivateYoloRejectedCandidateOrigin as ot}from"./isolated-admission.js";import{preparePrivateYoloIsolatedWorkspace as st}from"./isolated-workspace.js";async function bt(t,a,e={}){const o=Ye(a),{directive:r,review:s}=o,i=_(t),n=r.storyId,f=n.split(".")[0],p=d=>T("sha256").update(d).digest("hex");let h="session";const u=()=>{throw new Error(`private-root-memory-acceptance-${h}-unverified`)};try{return await G(i,n,I(i,n),async()=>{const d=ue(i,{required:!0}),m=d.epics[f],l=m?.branch_lease,c=await D(i,n);if(!c||m?.graph_revision!==r.graphRevision||l?.ownerStoryId!==n||typeof l.expiresAt!="string"||Date.parse(l.expiresAt)<=Date.now()||c.workspace.executionBranch!==r.executionBranch)return u();te(c,i,n,r.graphRevision);const S=await Z(await ke(i),"private-execution"),H=Je(c,o),B=c.rootMemoryEffect===void 0&&Y(v(S,H));B||await A(c,i,n,r.graphRevision);const W=await Xe(i);h="source-evidence",Fe(i,[".neocortex/state.json",`.neocortex/stories/${n}/validation-evidence.md`]);const E=R(v(i,".neocortex/state.json"));if(p(E)!==s.sourceStateSha256)return u();const y=Qe(JSON.parse(E.toString("utf8")),d).stories?.[n];if(!y||y.checkpoint!==void 0||!Array.isArray(y.steps_completed))return u();const ae=[...y.steps_completed],oe=`.neocortex/stories/${n}/validation-evidence.md`,$=U(v(i,oe));if(!$.isFile()||$.isSymbolicLink()||$.nlink!==1||$.size<128||$.size>256*1024||p(R(v(i,oe)))!==s.proposalSha256)return u();const we=v(S,`qa-review-${s.rootQaReceiptId}.json`);h="qa-predecessor",await X(we,S);const se=R(we);if(se.length>16384||p(se)!==s.rootQaReceiptId)return u();const q=JSON.parse(se.toString("utf8"));if(q.kind!=="private-qa-root-review"||q.storyId!==n||q.sourceHeadSha!==c.workspace.baseSha||q.precommitQaAccepted!==!0||q.independentStoryQaAccepted!==!1||q.terminalAccepted!==!1)return u();const re=p(JSON.stringify(s.notes)),ie=w=>`memory-review-${p(JSON.stringify(w))}.json`,me=y.status==="qa-gate-passed"&&typeof y.last_step=="string"&&p(y.last_step)==="8721319de90ade506bc9b72a908d8296856b34a11bc640629178bed3fe32e373"&&ae.at(-1)===y.last_step,Se=async w=>{await Ke(i,j=>{if(!J(j.epics[f],m)||!J(j.stories[n],d.stories[n]))return u();j.stories[n]={...j.stories[n],status:"memory-updated",last_step:s.rawStepId,steps_completed:[...ae,s.rawStepId]}},{expectedRevision:d.revision,preCommit:async()=>{await A(w,i,n,r.graphRevision)}})};if(c.rootMemoryEffect){if(h="replay",c.rootMemoryEffect.sourceSnapshotSha!==s.snapshotSha||c.rootMemoryEffect.proposalSha256!==re||c.rootMemoryEffect.rootQaReceiptId!==s.rootQaReceiptId)return u();const w=v(S,ie(c.rootMemoryEffect));await X(w,S);const j=R(w),k=JSON.parse(j.toString("utf8"));if(k.proposalSha256!==s.proposalSha256||k.notesSha256!==re||!J(k.rootMemoryEffect,c.rootMemoryEffect))return u();const C=y.status==="memory-updated"&&y.last_step===s.rawStepId&&ae.at(-1)===s.rawStepId;return!C&&!me?u():(C||(h="phase-recovery",await Se(c)),{schemaVersion:1,outcome:"project-memory-root-accepted",storyId:n,graphRevision:r.graphRevision,receiptId:p(j),snapshotSha:c.snapshotSha,reused:!0,sourceStateUnchanged:!0,phaseRecovered:!C,independentStoryQaAccepted:!1,terminalAccepted:!1,publicSafe:!0})}if(c.snapshotSha!==s.snapshotSha||!me)return u();const P=c.workspace.workspacePath;g(P,["merge-base","--is-ancestor",q.snapshotSha,c.snapshotSha]);const Pe=[`.neocortex/stories/${n}/qa-gate-result.json`,oe,`.neocortex/stories/${n}/tdd-evidence.md`,`docs/stories/${n}.rtm.md`];if(b(P,["diff","--name-only","-z",q.snapshotSha,c.snapshotSha]).toString("utf8").split("\0").filter(Boolean).some(w=>!Pe.includes(w)))return u();const ne=await M(i,n,r.executionBranch,r.graphRevision);if(!fe(i,["diff","--cached","--quiet"]))return u();const je=b(i,["status","--porcelain=v1","-z","--untracked-files=all"]);let x,Q,N,K=!1;if(B){h="prepared-recovery";const w=await Ve({projectRoot:i,parent:S,current:c,request:o,childPaths:ne});x=w.effect,Q=w.receipt,N=w.patch,K=w.sourceAlreadyApplied}else{for(const L of Me())if(ne.includes(L)||!J(Re(i,L),$e(P,c.snapshotSha,L)))return u();h="writer";const w=await Z(S,"memory-backups"),j=ze({snapshotRoot:P,expectedSnapshotSha:c.snapshotSha,notes:s.notes,backupDirectory:w}),k=He(j);h="writer-snapshot",k.files.length&&(g(P,["add","-A","--",...k.files.map(L=>L.path)]),g(P,["-c","core.hooksPath=/dev/null","-c","commit.gpgsign=false","-c","user.name=Neocortex Private Session","-c","user.email=private-session@neocortex.invalid","commit","-q","-m",`private root memory ${n} ${c.sequence+1}`]));const C=g(P,["rev-parse","HEAD"]);x={schemaVersion:"RootProjectMemoryEffect/1",producer:"root-project-memory",storyId:n,epicId:f,executionBranch:r.executionBranch,sourceHeadSha:c.workspace.baseSha,sourceSnapshotSha:c.snapshotSha,memorySnapshotSha:C,graphRevision:r.graphRevision,childClaimRevision:p([...ne].sort().join("\0")),setupSessionId:c.setupSessionId,rootQaReceiptId:s.rootQaReceiptId,proposalSha256:k.notesSha256,canonicalSha256:k.verification.canonicalSha256,projectionSha256:k.verification.projectionSha256,projectionFileCount:k.verification.fileCount,files:k.files,recordedAt:s.reviewedAt,publicSafe:!0},h="git-evidence",Le(P,x,{storyId:n,graphRevision:r.graphRevision,childClaimRevision:x.childClaimRevision,setupSessionId:c.setupSessionId,sourceHeadSha:c.workspace.baseSha,executionBranch:r.executionBranch}),N=b(P,["diff","--binary","--full-index",c.snapshotSha,C]),Q={schemaVersion:1,kind:"private-project-memory-root-review",storyId:n,graphRevision:r.graphRevision,sourceHeadSha:c.workspace.baseSha,snapshotSha:C,proposalSha256:s.proposalSha256,notesSha256:re,sourceStateSha256:s.sourceStateSha256,checks:s.checks,reviewedAt:s.reviewedAt,rootMemoryEffect:x,independentStoryQaAccepted:!1,terminalAccepted:!1},h="prepared-journal",await z(S,H,JSON.stringify({schemaVersion:1,kind:"prepared-root-memory-effect",previousSession:c,receipt:Q,patchSha256:p(N)})+`
|
|
2
|
+
`),await e.fault?.("after-prepared-journal")}const ce=JSON.stringify(Q)+`
|
|
3
|
+
`,ye=x.memorySnapshotSha;if(h="source-admission",!b(i,["status","--porcelain=v1","-z","--untracked-files=all"]).equals(je)||g(i,["rev-parse","HEAD"])!==c.workspace.baseSha||g(i,["symbolic-ref","--short","HEAD"])!==r.executionBranch)return u();if(!K){for(const w of x.files)if(!J(Re(i,w.path),w.before))return u()}const ve=w=>Ze(Be(i),Ge(i),W,["apply",...w?["--check"]:[],"--binary","-"],N);if(N.length&&!K&&(await ve(!0),await ve(!1)),await e.fault?.("after-source-admission"),!R(v(i,".neocortex/state.json")).equals(E))return u();const pe=v(S,ie(x));if(Y(pe)){if(await X(pe,S),R(pe,"utf8")!==ce)return u()}else await z(S,ie(x),ce);const he=Object.freeze({...c,snapshotSha:ye,sequence:c.sequence+(x.files.length?1:0),lastPatchSha256:x.files.length?p(N):c.lastPatchSha256,rootMemoryEffect:x});return h="session-pin",await e.fault?.("before-session-pin"),await F(i,he),await A(he,i,n,r.graphRevision),h="phase-transition",await Se(he),{schemaVersion:1,outcome:"project-memory-root-accepted",storyId:n,graphRevision:r.graphRevision,receiptId:p(ce),snapshotSha:ye,reused:B,sourceStateUnchanged:!0,preparedRecovered:B,sourceWriteReused:K,independentStoryQaAccepted:!1,terminalAccepted:!1,publicSafe:!0}})}catch(d){if(d instanceof Error&&/^(private-root-memory|private-execution-isolated)-[a-z0-9-]+$/.test(d.message)?d.message:void 0)throw new Error(`private-root-memory-acceptance-${h}-unverified`,{cause:d});return u()}}function g(t,a){const e={...process.env};for(const o of["GIT_DIR","GIT_WORK_TREE","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_COMMON_DIR","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES"])delete e[o];return ge("git",[...a],{cwd:t,env:e,encoding:"utf8",stdio:["ignore","pipe","pipe"],timeout:3e4,maxBuffer:16*1024*1024}).trim()}function b(t,a){const e={...process.env};for(const o of["GIT_DIR","GIT_WORK_TREE","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_COMMON_DIR","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES"])delete e[o];return ge("git",[...a],{cwd:t,env:e,stdio:["ignore","pipe","pipe"],timeout:3e4,maxBuffer:16*1024*1024})}function fe(t,a){const e={...process.env};for(const r of["GIT_DIR","GIT_WORK_TREE","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_COMMON_DIR","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES"])delete e[r];const o=_e("git",[...a],{cwd:t,env:e,stdio:"ignore",timeout:3e4});if(o.error||o.signal)throw new Error("git-unverified");return o.status===0}async function de(t,a){const e=await ke(t),o=await Z(e,"private-execution"),r=`session-${T("sha256").update(a).digest("hex")}.json`;return{parent:o,name:r,path:v(o,r)}}function I(t,a){const e=a.split(".")[0],r=ue(t,{required:!0}).epics[e]?.branch_lease,s=r&&typeof r=="object"&&!Array.isArray(r)?r:void 0,i=s?.sessionId;if(s?.ownerStoryId!==a||typeof i!="string"||!/^setup-[a-f0-9]{64}$/.test(i)||i!==s.idempotencyKey)throw new Error("session-lease-invalid");return i}function be(t,a){const e=ue(t,{required:!0}).stories[a];return et(e)}function rt(t){const a=JSON.parse(t);if(!a||typeof a!="object"||Array.isArray(a))throw new Error("session-invalid");const e=a,o=e.workspace;if(Object.keys(e).sort().join(",")!==["schemaVersion","kind","storyId","initialGraphRevision","graphRevision","graphHistory","setupSessionId","workspace","snapshotSha","sequence","lastPatchSha256",...e.rootMemoryEffect===void 0?[]:["rootMemoryEffect"]].sort().join(",")||e.schemaVersion!==1||e.kind!=="private-yolo-isolated-session"||typeof e.storyId!="string"||!/^[A-Za-z][A-Za-z0-9_-]*\.[A-Za-z0-9._-]+$/.test(e.storyId)||typeof e.initialGraphRevision!="string"||!/^[a-f0-9]{64}$/.test(e.initialGraphRevision)||typeof e.graphRevision!="string"||!/^[a-f0-9]{64}$/.test(e.graphRevision)||!Array.isArray(e.graphHistory)||e.graphHistory.length<1||e.graphHistory.length>65||e.graphHistory.some(s=>typeof s!="string"||!/^[a-f0-9]{64}$/.test(s))||new Set(e.graphHistory).size!==e.graphHistory.length||e.graphHistory[0]!==e.initialGraphRevision||e.graphHistory[e.graphHistory.length-1]!==e.graphRevision||typeof e.setupSessionId!="string"||!/^setup-[a-f0-9]{64}$/.test(e.setupSessionId)||typeof e.snapshotSha!="string"||!/^[a-f0-9]{40,64}$/.test(e.snapshotSha)||!Number.isSafeInteger(e.sequence)||Number(e.sequence)<0||Number(e.sequence)>64||Number(e.sequence)===0&&e.initialGraphRevision!==e.graphRevision&&e.graphHistory.length!==2||Number(e.sequence)===0&&e.lastPatchSha256!==null||Number(e.sequence)>0&&e.lastPatchSha256===null||e.lastPatchSha256!==null&&(typeof e.lastPatchSha256!="string"||!/^[a-f0-9]{64}$/.test(e.lastPatchSha256))||e.rootMemoryEffect!==void 0&&!Ce(e.rootMemoryEffect)||!o||typeof o!="object"||Array.isArray(o))throw new Error("session-invalid");const r=o;if(Object.keys(r).sort().join(",")!==["schemaVersion","sourceRoot","workspacePath","baseSha","executionBranch"].sort().join(",")||r.schemaVersion!==1||typeof r.sourceRoot!="string"||typeof r.workspacePath!="string"||typeof r.baseSha!="string"||!/^[a-f0-9]{40,64}$/.test(r.baseSha)||typeof r.executionBranch!="string"||!r.executionBranch)throw new Error("session-invalid");return e}async function D(t,a){const e=await de(t,a);if(Y(e.path))return await X(e.path,e.parent),rt(R(e.path,"utf8"))}async function F(t,a){const e=await de(t,a.storyId);await z(e.parent,e.name,`${JSON.stringify(a)}
|
|
4
|
+
`)}async function G(t,a,e,o){const r=await We(t,{kind:"direct",storyId:a,sessionId:e,idempotencyKey:e,expiresAt:new Date(Date.now()+3e5).toISOString(),persistent:!1});if(!r.ok)throw new Error("private-execution-isolated-session-backpressure");try{return await o()}finally{if(!await Ue(r.path,r.owner))throw new Error("private-execution-isolated-session-lock-unverified")}}async function A(t,a,e,o){te(t,a,e,o);const r=await M(a,e,t.workspace.executionBranch,o),s=await ee(t,r);return V(t.workspace,r,t.snapshotSha,s),s}async function ee(t,a){if(t.rootMemoryEffect===void 0)return;const e=await Ne({projectRoot:t.workspace.sourceRoot,storyId:t.storyId,snapshotRoot:t.workspace.workspacePath,snapshotSha:t.snapshotSha,sourceHeadSha:t.workspace.baseSha,executionBranch:t.workspace.executionBranch,graphRevision:t.graphRevision,setupSessionId:t.setupSessionId,childPaths:a});if(!e||JSON.stringify(xe(e))!==JSON.stringify(t.rootMemoryEffect))throw new Error("private-root-memory-scope-unverified");return e}function te(t,a,e,o){if(t.storyId!==e||t.graphRevision!==o||t.workspace.sourceRoot!==a||t.setupSessionId!==I(a,e)||t.sequence===0&&t.snapshotSha!==t.workspace.baseSha||t.sequence===0&&t.graphHistory.length>1&&!be(a,e)||t.sequence>0&&t.snapshotSha===t.workspace.baseSha)throw new Error("session-binding-invalid")}async function It(t,a,e){const o=_(t.sourceRoot);try{const r=I(o,a);return await G(o,a,r,async()=>{const s=await D(o,a);if(s){if(await A(s,o,a,e),s.workspace.workspacePath!==t.workspacePath)throw new Error("session-replacement-denied");return s}const i=await M(o,a,t.executionBranch,e);V(t,i,t.baseSha);const n=Object.freeze({schemaVersion:1,kind:"private-yolo-isolated-session",storyId:a,initialGraphRevision:e,graphRevision:e,graphHistory:[e],setupSessionId:r,workspace:t,snapshotSha:t.baseSha,sequence:0,lastPatchSha256:null});return await F(o,n),n})}catch{throw new Error("private-execution-isolated-session-unverified")}}async function Ie(t,a,e,o){if(t.graphRevision===o)return await A(t,a,e,o),t;if(t.storyId!==e||t.workspace.sourceRoot!==a||t.setupSessionId!==I(a,e)||t.sequence===0&&(t.graphHistory.length!==1||t.lastPatchSha256!==null||!be(a,e))||t.sequence>0&&t.lastPatchSha256===null||t.graphHistory.includes(o)||t.graphHistory.length>=65)throw new Error("session-graph-transition-invalid");const r=await tt(a,e,t.workspace.executionBranch,t.initialGraphRevision,o);V(t.workspace,r,t.snapshotSha,await ee(t,r));const s=Object.freeze({...t,graphRevision:o,graphHistory:Object.freeze([...t.graphHistory,o])});return await F(a,s),await A(s,a,e,o),s}async function Pt(t,a,e){const o=_(t);try{const r=I(o,a);return await G(o,a,r,async()=>{const s=await D(o,a);if(!s)throw new Error("session-missing");return Ie(s,o,a,e)})}catch{throw new Error("private-execution-isolated-session-unverified")}}async function jt(t,a,e,o){const r=_(t);try{const s=I(r,a);return await G(r,a,s,async()=>{const i=await D(r,a);if(i)return Ie(i,r,a,e);const n=o??v(De(),".local","share","neocortex","private-yolo-workspaces");o===void 0&&qe(n,{recursive:!0,mode:448});const f=st(r,n),p=await M(r,a,f.executionBranch,e);V(f,p,f.baseSha);const h=Object.freeze({schemaVersion:1,kind:"private-yolo-isolated-session",storyId:a,initialGraphRevision:e,graphRevision:e,graphHistory:[e],setupSessionId:s,workspace:f,snapshotSha:f.baseSha,sequence:0,lastPatchSha256:null});return await F(r,h),h})}catch{throw new Error("private-execution-isolated-session-unverified")}}async function _t(t,a,e){const o=_(t);try{const r=await D(o,a);if(!r)throw new Error("session-missing");return await A(r,o,a,e),r}catch{throw new Error("private-execution-isolated-session-unverified")}}async function At(t,a,e){const o=_(t);try{const r=I(o,a);return await G(o,a,r,async()=>{const s=await D(o,a);if(!s)throw new Error("session-missing");te(s,o,a,e);const i=await M(o,a,s.workspace.executionBranch,e),n=await ee(s,i),f=await at(s.workspace,a,e,s.snapshotSha,!1,n);g(s.workspace.workspacePath,["add","-A","--",...f.changedPaths]),g(s.workspace.workspacePath,["-c","core.hooksPath=/dev/null","-c","commit.gpgsign=false","-c","user.name=Neocortex Private Session","-c","user.email=private-session@neocortex.invalid","commit","-q","-m",`private snapshot ${a} ${s.sequence+1}`]);const p=g(s.workspace.workspacePath,["rev-parse","HEAD"]);V(s.workspace,i,p,n);const h=Object.freeze({...s,snapshotSha:p,sequence:s.sequence+1,lastPatchSha256:f.patchSha256});return await F(o,h),{session:h,admission:f}})}catch{throw new Error("private-execution-isolated-session-unverified")}}async function Ot(t,a,e){const o=_(t);try{const r=I(o,a);return await G(o,a,r,async()=>{const s=await D(o,a);if(!s||s.sequence<1)throw new Error("session-incomplete");const i=await A(s,o,a,e),n=await M(o,a,s.workspace.executionBranch,e),f=s.workspace.workspacePath,p=b(f,["diff","--name-only","-z",s.workspace.baseSha,s.snapshotSha]).toString("utf8").split("\0").filter(Boolean).sort(),h=[".neocortex/state.json",`docs/stories/${a}.story.md`,`.neocortex/stories/${a}/qa-gate-result.json`,`.neocortex/stories/${a}/validation-evidence.md`,`.neocortex/stories/${a}/review.md`];if(p.length===0||p.length>1024||new Set(p).size!==p.length||p.some(l=>!n.includes(l)&&!(i&&xe(i).files.some(c=>c.path===l)))||h.some(l=>!p.includes(l)))throw new Error("bundle-incomplete");if(!fe(o,["diff","--cached","--quiet"])||b(o,["ls-files","-u","-z"]).byteLength!==0)throw new Error("index-not-clean");const u=b(f,["diff","--binary","--full-index",s.workspace.baseSha,s.snapshotSha]);if(u.byteLength===0)throw new Error("bundle-empty");g(o,["add","-A","--",...p]);const d=b(o,["diff","--cached","--binary","--full-index"]),m=b(o,["diff","--cached","--name-only","-z"]).toString("utf8").split("\0").filter(Boolean).sort();if(!d.equals(u)||m.length!==p.length||m.some((l,c)=>l!==p[c])||!fe(o,["diff","--quiet"])||g(o,["rev-parse","HEAD"])!==s.workspace.baseSha||g(o,["symbolic-ref","--quiet","--short","HEAD"])!==s.workspace.executionBranch)throw new Error("bundle-raced");return Object.freeze({schemaVersion:1,outcome:"staged-unverified",snapshotSha:s.snapshotSha,bundleSha256:T("sha256").update(d).digest("hex"),changedPaths:Object.freeze(p)})})}catch{throw new Error("private-execution-root-stage-unverified")}}function it(t){const a=t.workspace.workspacePath,e=b(a,["status","--porcelain=v1","-z","-uall"]),o=e.toString("utf8").split("\0").filter(Boolean);if(o.length<1||o.length>1024)throw new Error("rejected-candidate-invalid");let r=0;const s=o.map(n=>{const f=n.slice(0,2),p=n.slice(3);if(![" M"," D","??"].includes(f)||p.length<1||p.length>1024||p.startsWith("/")||/[\\\x00-\x1f\x7f]/.test(p)||p.split("/").some(l=>!l||l==="."||l===".."||l===".git"))throw new Error("rejected-candidate-path-invalid");const h=p.split("/");for(let l=1;l<h.length;l++){const c=v(a,...h.slice(0,l));if(!Y(c))break;const S=U(c);if(!S.isDirectory()||S.isSymbolicLink()||S.uid!==process.getuid?.())throw new Error("rejected-candidate-parent-invalid")}const u=v(a,p);if(f===" D"){if(Y(u))throw new Error("rejected-candidate-raced");return{path:p,code:f,mode:null,sha256:null,content:null}}const d=U(u);if(!d.isFile()||d.isSymbolicLink()||d.nlink!==1||d.uid!==process.getuid?.()||d.size>16*1024*1024)throw new Error("rejected-candidate-file-invalid");const m=R(u);if(r+=m.byteLength,r>16*1024*1024)throw new Error("rejected-candidate-too-large");return{path:p,code:f,mode:d.mode&511,sha256:T("sha256").update(m).digest("hex"),content:m}});if(new Set(s.map(n=>n.path)).size!==s.length)throw new Error("rejected-candidate-path-invalid");const i={schemaVersion:"PrivateYoloRejectedCandidateInspection/1",storyId:t.storyId,graphRevision:t.graphRevision,snapshotSha:t.snapshotSha,sourceHead:t.workspace.baseSha,sequence:t.sequence,statusSha256:T("sha256").update(e).digest("hex"),files:s.map(({content:n,...f})=>f)};return{files:s,inspection:{schemaVersion:i.schemaVersion,storyId:i.storyId,graphRevision:i.graphRevision,snapshotSha:i.snapshotSha,sourceHead:i.sourceHead,sequence:i.sequence,candidateDigest:T("sha256").update(JSON.stringify(i)).digest("hex"),changedPaths:s.map(n=>n.path),publicSafe:!0}}}async function le(t,a,e){const o=await D(t,a);if(!o)throw new Error("session-missing");te(o,t,a,e);const r=await M(t,a,o.workspace.executionBranch,e);return ot(o.workspace,r,o.snapshotSha,await ee(o,r)),{record:o,...it(o)}}async function qt(t,a,e,o){if(o!==!0)throw new Error("private-execution-rejected-candidate-executor-not-stopped");const r=_(t);try{return await G(r,a,I(r,a),async()=>(await le(r,a,e)).inspection)}catch{throw new Error("private-execution-rejected-candidate-unverified")}}async function Tt(t,a,e,o){if(o.executorStopped!==!0||o.authorizeDiscard!==!0||!/^[a-f0-9]{64}$/.test(o.expectedCandidateDigest))throw new Error("private-execution-rejected-candidate-input-invalid");const r=_(t);try{return await G(r,a,I(r,a),async()=>{const s=await le(r,a,e);if(s.inspection.candidateDigest!==o.expectedCandidateDigest)throw new Error("candidate-review-stale");const i=await de(r,a),n=R(i.path),f=`rejected-${Oe()}`,p=await Z(i.parent,f),h=Ee(32),u=Ee(12),d=Buffer.from(JSON.stringify({schemaVersion:"PrivateYoloRejectedCandidateArchive/1",inspection:s.inspection,files:s.files.map(({content:E,...O})=>({...O,contentBase64:E?.toString("base64")??null}))})),m=Ae("aes-256-gcm",h,u);m.setAAD(Buffer.from("private-yolo-rejected-candidate-v1"));const l=Buffer.concat([m.update(d),m.final()]);d.fill(0);const c=Buffer.concat([u,m.getAuthTag(),l]);try{await z(p,"candidate.key",h),await z(p,"candidate.aesgcm",c)}finally{h.fill(0)}if((await le(r,a,e)).inspection.candidateDigest!==o.expectedCandidateDigest||!R(i.path).equals(n))throw new Error("candidate-raced");const H=s.record.workspace.workspacePath,B=s.files.filter(E=>E.code!=="??").map(E=>E.path);B.length&&g(H,["restore","--source",s.record.snapshotSha,"--worktree","--",...B]);for(const E of s.files.filter(O=>O.code==="??")){const O=v(H,E.path),y=U(O);if(!y.isFile()||y.isSymbolicLink()||y.nlink!==1||T("sha256").update(R(O)).digest("hex")!==E.sha256)throw new Error("candidate-raced");Te(O)}if(await A(s.record,r,a,e),!R(i.path).equals(n))throw new Error("session-pin-raced");const W={schemaVersion:"PrivateYoloRejectedCandidateRecovery/1",outcome:"candidate-discarded",archiveId:f,archiveSha256:T("sha256").update(c).digest("hex"),candidateDigest:o.expectedCandidateDigest,snapshotSha:s.record.snapshotSha,sourceHead:s.record.workspace.baseSha,sessionPinPreserved:!0,sourcePreserved:!0,checkpointAccepted:!1,publicSafe:!0};return await z(p,"recovery.json",`${JSON.stringify(W)}
|
|
5
|
+
`),W})}catch{throw new Error("private-execution-rejected-candidate-recovery-unverified")}}export{bt as acceptPrivateYoloProjectMemoryRootReview,At as admitPrivateYoloIsolatedSessionStep,It as beginPrivateYoloIsolatedSession,Tt as discardPrivateYoloRejectedCandidate,jt as ensurePrivateYoloIsolatedSession,qt as inspectPrivateYoloRejectedCandidate,Pt as reconcilePrivateYoloIsolatedSession,_t as resumePrivateYoloIsolatedSession,Ot as stagePrivateYoloIsolatedSessionBundle};
|
|
@@ -6,4 +6,4 @@ export interface PactSourceInspectionV1 {
|
|
|
6
6
|
readonly publicSafe: true;
|
|
7
7
|
}
|
|
8
8
|
/** Reject comment-only, malformed and non-Pact files before a root patch effect. */
|
|
9
|
-
export declare function validatePactTestSource(path: string, source: string, brokerUrl: string | null, expectedInteraction?: PactInteractionV1, projectRoot?: string): PactSourceInspectionV1;
|
|
9
|
+
export declare function validatePactTestSource(path: string, source: string, brokerUrl: string | null, expectedInteraction?: PactInteractionV1, projectRoot?: string, matchersAggressive?: boolean): PactSourceInspectionV1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parse as T}from"@babel/parser";import{lstatSync as
|
|
1
|
+
import{parse as T}from"@babel/parser";import{lstatSync as A,realpathSync as C}from"node:fs";import{join as k,posix as S,resolve as I}from"node:path";const V=256*1024,_=1e5;function a(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function O(e){const n=new Set;if(!Array.isArray(e.specifiers))return n;for(const s of e.specifiers)!a(s)||s.type!=="ImportSpecifier"||!a(s.imported)||typeof s.imported.name!="string"||n.add(s.imported.name);return n}function q(e,n,s){const t=a(e.source)?e.source.value:void 0;if(typeof t!="string"||t.length>240||!/^\.\.?\/[A-Za-z0-9_./-]+$/.test(t)||e.importKind==="type"||!Array.isArray(e.specifiers)||e.specifiers.length<1||e.specifiers.length>16)throw new Error("private-execution-pact-source-invalid");const r=S.normalize(S.join(S.dirname(n),t));if(!/^(?:src|app|lib|packages|clients)\/[A-Za-z0-9_./-]+$/.test(r)||r.split("/").some(o=>o===".."||o==="."))throw new Error("private-execution-pact-source-invalid");const m=I(s);if(C(m)!==m||!A(m).isDirectory())throw new Error("private-execution-pact-source-invalid");const c=/\.(?:ts|tsx|js|mjs)$/.test(r)?[r,...r.endsWith(".js")?[`${r.slice(0,-3)}.ts`,`${r.slice(0,-3)}.tsx`]:[]]:[`${r}.ts`,`${r}.tsx`,`${r}.js`,`${r}.mjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.js`],l=[];for(const o of c){let d=m;try{const y=o.split("/");for(const[x,E]of y.entries()){d=k(d,E);const v=A(d);if(v.isSymbolicLink()||(x===y.length-1?!v.isFile()||v.size<1||v.size>1024*1024:!v.isDirectory()))throw new Error("private-execution-pact-source-invalid")}l.push(o)}catch(y){if(y.code!=="ENOENT")throw new Error("private-execution-pact-source-invalid")}}if(l.length!==1)throw new Error("private-execution-pact-source-invalid");const h=new Set;for(const o of e.specifiers){if(!a(o)||!["ImportSpecifier","ImportDefaultSpecifier"].includes(o.type)||o.importKind==="type"||!a(o.local)||o.local.type!=="Identifier"||typeof o.local.name!="string")throw new Error("private-execution-pact-source-invalid");h.add(o.local.name)}return h}function b(e){if(!(!a(e)||e.type!=="MemberExpression"||e.computed===!0||!a(e.property)||e.property.type!=="Identifier"))return typeof e.property.name=="string"?e.property.name:void 0}function z(e){if(!a(e)||e.type!=="ObjectExpression"||!Array.isArray(e.properties))return;let n,s;for(const t of e.properties){if(!a(t)||t.type!=="ObjectProperty"||t.computed===!0||!a(t.key)||!a(t.value))return;const r=t.key.type==="Identifier"?t.key.name:t.key.type==="StringLiteral"?t.key.value:void 0;if(r==="method"||r==="path"){if(t.value.type!=="StringLiteral"||typeof t.value.value!="string")return;if(r==="method"){if(n!==void 0)return;n=t.value.value}else{if(s!==void 0)return;s=t.value.value}}}return n!==void 0&&s!==void 0?{method:n,path:s}:void 0}function L(e,n){if(e.length>180||n.length>2048||/[?#]/.test(n))return!1;const s=e.split("/"),t=n.split("/");return s.length!==t.length?!1:s.every((r,m)=>{const c=t[m];if(!r.includes("{")&&!r.includes("}"))return r===c;const l=/^([^{}]*)\{[^{}]+\}([^{}]*)$/.exec(r);return!l||!c.startsWith(l[1])||!c.endsWith(l[2])?!1:c.length>l[1].length+l[2].length})}function M(e,n,s,t,r,m){const c=e==="tests/pact/provider/verify.test.ts"?"provider":"consumer";if(c==="consumer"&&!/^tests\/pact\/consumer\/[a-z0-9-]+\.test\.ts$/.test(e)||typeof n!="string"||Buffer.byteLength(n,"utf8")<80||Buffer.byteLength(n,"utf8")>V||s!==null&&n.includes(s))throw new Error("private-execution-pact-source-invalid");let l;try{l=T(n,{sourceType:"module",plugins:["typescript"]})}catch{throw new Error("private-execution-pact-source-invalid")}const h=new Set,o=new Set,d=new Set;for(const p of l.program.body){if(p.type!=="ImportDeclaration")continue;const i=p.source.value;if(i!=="@pact-foundation/pact"&&i!=="vitest"){if(c!=="consumer"||!r)throw new Error("private-execution-pact-source-invalid");for(const f of q(p,e,r)){if(d.has(f)||["fetch","describe","it","expect","PactV3","MatchersV3","Verifier"].includes(f))throw new Error("private-execution-pact-source-invalid");d.add(f)}continue}const u=O(p);for(const f of u)(i==="@pact-foundation/pact"?h:o).add(f)}if(!o.has("describe")||!o.has("it")||c==="consumer"&&(!h.has("PactV3")||!o.has("expect"))||c==="provider"&&!h.has("Verifier")||[...d].some(p=>h.has(p)||o.has(p)))throw new Error("private-execution-pact-source-invalid");if(c==="consumer"&&m===!1&&[...h].some(p=>p!=="PactV3"))throw new Error("private-execution-pact-source-invalid");const y=new Set,x=new Set;let E=!1,v=!1,j=!1;const g=[{node:l.program,inExecuteTest:!1}];let $=0;for(;g.length>0;){const p=g.pop(),i=p.node;if(a(i)){if(++$>_)throw new Error("private-execution-pact-source-invalid");if(i.type==="NewExpression"&&a(i.callee)&&i.callee.type==="Identifier"&&typeof i.callee.name=="string"&&(x.add(i.callee.name),p.inExecuteTest&&d.has(i.callee.name)&&(j=!0)),i.type==="CallExpression"){const u=i.callee;a(u)&&u.type==="Identifier"&&typeof u.name=="string"&&(y.add(u.name),p.inExecuteTest&&d.has(u.name)&&(j=!0));const f=b(u);if(f&&y.add(f),f==="withRequest"&&t&&Array.isArray(i.arguments)){const w=z(i.arguments[0]);v||=w?.method.toUpperCase()===t.method&&L(t.endpointPath,w?.path??"")}}i.type==="MemberExpression"&&b(i)==="PACT_BROKER_URL"&&a(i.object)&&b(i.object)==="env"&&a(i.object.object)&&i.object.object.type==="Identifier"&&i.object.object.name==="process"&&(E=!0);for(const[u,f]of Object.entries(i)){if(u==="loc"||u==="extra"||u==="comments"||u==="leadingComments"||u==="trailingComments"||u==="innerComments")continue;const w=p.inExecuteTest||i.type==="CallExpression"&&b(i.callee)==="executeTest"&&u==="arguments";if(Array.isArray(f))for(const P of f)g.push({node:P,inExecuteTest:w});else a(f)&&g.push({node:f,inExecuteTest:w})}}}if((c==="consumer"?["describe","it","withRequest","willRespondWith","executeTest","expect"]:["describe","it","verifyProvider"]).some(p=>!y.has(p))||!x.has(c==="consumer"?"PactV3":"Verifier")||c==="consumer"&&t!==void 0&&(t.filePath!==e||!v)||c==="provider"&&s!==null&&!E)throw new Error("private-execution-pact-source-invalid");return Object.freeze({schemaVersion:1,consumerBinding:c==="provider"?"provider-template":j?"app-import-candidate":"mock-only-scaffold",executionVerified:!1,publicSafe:!0})}export{M as validatePactTestSource};
|
|
@@ -22,6 +22,8 @@ export interface PlanningDiagnosisRootReviewV1 {
|
|
|
22
22
|
readonly intake: Readonly<Record<string, unknown>>;
|
|
23
23
|
readonly artifactSummary: string;
|
|
24
24
|
}
|
|
25
|
+
/** Read only an owner-private pending claim file; absence is an explicit snapshot. */
|
|
26
|
+
export declare function planningPendingSidecarDigest(root: string): string | undefined;
|
|
25
27
|
export declare function planningPhysicalPatchDigest(root: string, paths: Readonly<Record<string, string>>, ownTemporaryPath?: string, allowPendingSidecar?: boolean): string;
|
|
26
28
|
/** P02 may consume only a physically sealed P01 for the same durable claim. */
|
|
27
29
|
export declare function acceptedPlanningDiagnosisPredecessor(stateInput: unknown, claimId: string, epicId: string, allowResearched?: boolean): {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{execFileSync as q,spawnSync as
|
|
2
|
-
`))?.[1];if(!
|
|
3
|
-
`),
|
|
4
|
-
`)]))))}function oi(i){if(!o(i)||Object.keys(i).sort().join("|")!==["schemaVersion","verdict","claimId","epicId","logicalFingerprint","sourceHead","sourceBranch","sourceStateSha256","admission","artifactDigests","qaEvidenceId","intake","artifactSummary"].sort().join("|")||i.schemaVersion!=="PlanningDiagnosisRootReview/1"||i.verdict!=="accepted"||typeof i.claimId!="string"||!ci.test(i.claimId)||typeof i.epicId!="string"||!si.test(i.epicId)||typeof i.logicalFingerprint!="string"||!
|
|
5
|
-
`),_(
|
|
1
|
+
import{execFileSync as q,spawnSync as Y}from"node:child_process";import{createHash as v,randomUUID as ii}from"node:crypto";import{closeSync as D,fsyncSync as _,lstatSync as w,mkdirSync as ni,openSync as j,readFileSync as V,realpathSync as J,renameSync as ei,unlinkSync as L,writeFileSync as T}from"node:fs";import{isAbsolute as ti,join as m,resolve as B}from"node:path";import{isDeepStrictEqual as b}from"node:util";import{canonicalPlanningIntake as H,createPlanningReceiptV1 as N,planningIntakeRevision as F,projectDiagnosedEpicState as M}from"../../../shared/dist/planning/diagnosis-state.js";const x=/^[a-f0-9]{64}$/,si=/^P[1-9][0-9]{0,11}$/,ci=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,A=["idea","diagnosis","enrichment","index"],G="acd455ed0e39d98b90fb57391db75e366e4c5604db043e03a89a20e33d643c3c",ai="81f50aaa801c1660eabe46e645501acbfb3e9873410c991e1496c014ca75c369";function o(i){return i!==null&&typeof i=="object"&&!Array.isArray(i)}function S(i){return v("sha256").update(i).digest("hex")}function O(i,n){return q("git",[...n],{cwd:i,encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:65536}).trim()}function I(i,n,e){const t=m(i,n),c=w(t);if(!c.isFile()||c.isSymbolicLink()||c.size<1||c.size>e)throw new Error("planning-diagnosis-physical-artifact-invalid");return V(t)}function U(i,n){return typeof i=="string"&&i.length<=128&&S(i)===n}function Z(i,n,e){const t=/^---\n([\s\S]{1,8192}?)\n---\n/.exec(i.replace(/\r\n/g,`
|
|
2
|
+
`))?.[1];if(!t)return!1;const c=t.split(`
|
|
3
|
+
`),a=d=>{const g=c.filter(r=>r.startsWith(`${d}:`));return g.length===1?g[0].slice(d.length+1).trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2"):void 0};return a("epic_id")===n&&a("status")==="completed"&&U(a("step"),e)}function mi(i){const n=m(i,".neocortex/pending-epic-claims.json");let e;try{e=w(n)}catch(a){if(a.code==="ENOENT")return;throw a}const t=w(m(i,".neocortex"));if(!t.isDirectory()||t.isSymbolicLink()||t.uid!==process.getuid?.()||(t.mode&18)!==0||!e.isFile()||e.isSymbolicLink()||e.uid!==process.getuid?.()||(e.mode&63)!==0||e.size<1||e.size>128*1024)throw new Error("planning-pending-sidecar-invalid");const c=V(n);if(c.length!==e.size)throw new Error("planning-pending-sidecar-invalid");return S(c)}function ri(i,n,e,t=!0){const c=new Set(Object.values(n)),a=new Set([".neocortex/state.json.planning.lock",...e?[e]:[]]),d=q("git",["status","--porcelain=v1","-z","--untracked-files=all"],{cwd:i,stdio:["ignore","pipe","ignore"],maxBuffer:128*1024}).toString("utf8").split("\0").filter(Boolean),g=[],r=new Set;for(const l of d){const h=l.slice(0,2),s=l.slice(3);if(!(a.has(s)&&h==="??")){if(l[2]!==" "||!c.has(s)&&(!t||s!==".neocortex/pending-epic-claims.json")||s===".neocortex/pending-epic-claims.json"&&h!=="??"||s!==".neocortex/pending-epic-claims.json"&&h!=="??"&&h!==" M"||r.has(s))throw new Error("planning-diagnosis-write-scope-conflict");r.add(s),h==="??"&&c.has(s)&&g.push(s)}}if([...c].some(l=>!r.has(l)))throw new Error("planning-diagnosis-write-scope-conflict");const p=[q("git",["diff","--binary","--no-ext-diff","--no-textconv","HEAD","--"],{cwd:i,stdio:["ignore","pipe","ignore"],maxBuffer:2*1024*1024})];for(const l of g.sort()){const h=Y("git",["diff","--no-index","--binary","--no-ext-diff","--","/dev/null",l],{cwd:i,encoding:"buffer",maxBuffer:2097152});if(h.status!==1||!Buffer.isBuffer(h.stdout))throw new Error("planning-diagnosis-patch-invalid");p.push(h.stdout)}return S(Buffer.concat(p.map(l=>Buffer.concat([l,Buffer.from(`
|
|
4
|
+
`)]))))}function oi(i){if(!o(i)||Object.keys(i).sort().join("|")!==["schemaVersion","verdict","claimId","epicId","logicalFingerprint","sourceHead","sourceBranch","sourceStateSha256","admission","artifactDigests","qaEvidenceId","intake","artifactSummary"].sort().join("|")||i.schemaVersion!=="PlanningDiagnosisRootReview/1"||i.verdict!=="accepted"||typeof i.claimId!="string"||!ci.test(i.claimId)||typeof i.epicId!="string"||!si.test(i.epicId)||typeof i.logicalFingerprint!="string"||!x.test(i.logicalFingerprint)||typeof i.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(i.sourceHead)||typeof i.sourceBranch!="string"||!/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/.test(i.sourceBranch)||typeof i.sourceStateSha256!="string"||!x.test(i.sourceStateSha256)||!o(i.admission)||i.admission.schemaVersion!==1||i.admission.outcome!=="admitted-unverified"||i.admission.baseSha!==i.sourceHead||i.admission.executionBranch!==i.sourceBranch||typeof i.admission.patchSha256!="string"||!x.test(i.admission.patchSha256)||typeof i.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(i.qaEvidenceId)||!o(i.artifactDigests)||Object.keys(i.artifactDigests).sort().join("|")!==[...A].sort().join("|")||A.some(n=>typeof i.artifactDigests[n]!="string"||!x.test(i.artifactDigests[n])))throw new Error("planning-diagnosis-review-invalid");H(i.intake),N({kind:"diagnosis",epicId:i.epicId,intakeRevision:F(i.intake),artifactSummary:i.artifactSummary,accepted:!0})}function W(i,n,e,t){if(O(i,["rev-parse","HEAD"])!==n.sourceHead||O(i,["symbolic-ref","--quiet","--short","HEAD"])!==n.sourceBranch)throw new Error("planning-diagnosis-head-conflict");const c=w(m(i,".neocortex")),a=w(m(i,".neocortex/pending-epic-claims.json"));if(!c.isDirectory()||c.isSymbolicLink()||(c.mode&18)!==0||!a.isFile()||a.isSymbolicLink()||a.uid!==process.getuid?.()||(a.mode&63)!==0)throw new Error("planning-diagnosis-claim-boundary-invalid");const d=JSON.parse(I(i,".neocortex/pending-epic-claims.json",128*1024).toString("utf8")),g=o(d)&&o(d.operations)?d.operations[n.logicalFingerprint]:void 0;if(!o(g)||g.claimId!==n.claimId||g.epicId!==n.epicId)throw new Error("planning-diagnosis-claim-conflict");const r=`.neocortex/planning/epic-${n.epicId}`,f={idea:`${r}/idea.json`,diagnosis:`${r}/diagnosis.md`,enrichment:`${r}/enriched-prompt.md`,index:".neocortex/planning/planning.json"};if(!Array.isArray(n.admission.changedPaths)||[...n.admission.changedPaths].sort().join("|")!==Object.values(f).sort().join("|")||e&&ri(i,f,t)!==n.admission.patchSha256)throw new Error("planning-diagnosis-admission-patch-conflict");const p={idea:I(i,f.idea,32*1024),diagnosis:I(i,f.diagnosis,256*1024),enrichment:I(i,f.enrichment,256*1024),index:I(i,f.index,128*1024)};for(const P of A)if(S(p[P])!==n.artifactDigests[P])throw new Error("planning-diagnosis-artifact-conflict");const l=JSON.parse(p.idea.toString("utf8")),h=JSON.parse(p.index.toString("utf8")),s=H(n.intake),u=o(h)&&o(h.epics)?h.epics[n.epicId]:void 0,y=o(u)?u.output_files:void 0;if(!o(l)||l.epic_id!==n.epicId||l.status!=="diagnosed"||l.raw_input!==s.rawIntent||!o(u)||u.id!==n.epicId||u.idea!==s.rawIntent||u.status!=="diagnosed"||!Z(p.diagnosis.toString("utf8"),n.epicId,G)||!Z(p.enrichment.toString("utf8"),n.epicId,ai)||!Array.isArray(u.steps_completed)||u.steps_completed.length!==1||!U(u.steps_completed[0],G)||!o(y)||!b(y,{diagnosis:f.diagnosis})||typeof u.created_at!="string"||!Number.isFinite(Date.parse(u.created_at))||u.completed_at!==null)throw new Error("planning-diagnosis-artifact-identity-conflict");if(typeof s.goal!="string"||!s.goal.trim()||typeof s.desiredOutcome!="string"||!s.desiredOutcome.trim()||!Array.isArray(s.users)||s.users.length===0||!Array.isArray(s.surfaces)||s.surfaces.length===0)throw new Error("planning-diagnosis-critical-intake-missing");const E=F(s),k=N({kind:"diagnosis",epicId:n.epicId,intakeRevision:E,artifactSummary:n.artifactSummary,accepted:!0});return{checkpoint:{schemaVersion:1,epicId:n.epicId,intake:s,intakeRevision:E,diagnosisReceipt:k},receiptId:k.receiptId}}function X(i,n,e){const t=W(i,n,!0,e),c=I(i,".neocortex/state.json",8*1024*1024);if(S(c)!==n.sourceStateSha256)throw new Error("planning-diagnosis-state-conflict");const a=JSON.parse(c.toString("utf8"));if(!o(a)||o(a.scope)&&a.scope.kind==="projected")throw new Error("planning-diagnosis-state-invalid");return M(a,{claimId:n.claimId,epicId:n.epicId,checkpoint:t.checkpoint}),{stateRaw:c,state:a,...t}}function K(i,n){const e={schemaVersion:"PlanningDiagnosisPhysicalAcceptance/1",claimId:i.claimId,epicId:i.epicId,diagnosisReceiptId:n,qaEvidenceId:i.qaEvidenceId,sourceHead:i.sourceHead,sourceStateSha256:i.sourceStateSha256,admissionPatchSha256:i.admission.patchSha256,artifactDigests:i.artifactDigests};return{...e,receiptId:S(JSON.stringify(e)),publicSafe:!0}}function yi(i,n,e,t=!1){const c=o(i)?i:void 0,d=(c&&o(c.epics)?c.epics:void 0)?.[e];if(!o(d)||d.id!==e||d.source!=="create-epic"||d.status!=="diagnosed"&&!(t&&d.status==="researched")||!o(d.createEpicPlanningClaim)||d.createEpicPlanningClaim.claimId!==n||d.createEpicPlanningClaim.epicId!==e||!o(d.createEpicPlanning)||!o(d.createEpicPlanningPhysical))throw new Error("planning-research-predecessor-invalid");const g=d.createEpicPlanning,r=d.createEpicPlanningPhysical,f=o(r.artifactDigests)?r.artifactDigests:void 0,p=H(g.intake),l=F(p),h=c&&o(c.epic_id_ledger)?c.epic_id_ledger:void 0,s=o(g.diagnosisReceipt)?g.diagnosisReceipt:void 0;if(g.schemaVersion!==1||g.epicId!==e||g.intakeRevision!==l||!t&&g.researchReceipt!==void 0||typeof p.goal!="string"||!p.goal.trim()||typeof p.desiredOutcome!="string"||!p.desiredOutcome.trim()||typeof p.rawIntent!="string"||!p.rawIntent.trim()||!Array.isArray(p.users)||p.users.length===0||!Array.isArray(p.surfaces)||p.surfaces.length===0||!Array.isArray(h?.reserved_ids)||!h.reserved_ids.includes(e)||!s||s.kind!=="diagnosis"||s.epicId!==e||s.intakeRevision!==l||s.accepted!==!0||typeof s.artifactSummary!="string"||!b(s,N({kind:"diagnosis",epicId:e,intakeRevision:l,artifactSummary:s.artifactSummary,accepted:!0}))||r.schemaVersion!=="PlanningDiagnosisPhysicalAcceptance/1"||r.claimId!==n||r.epicId!==e||r.diagnosisReceiptId!==s.receiptId||typeof r.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(r.qaEvidenceId)||typeof r.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(r.sourceHead)||typeof r.sourceStateSha256!="string"||!x.test(r.sourceStateSha256)||typeof r.admissionPatchSha256!="string"||!x.test(r.admissionPatchSha256)||!f||Object.keys(f).sort().join("|")!==[...A].sort().join("|")||A.some(y=>typeof f[y]!="string"||!x.test(f[y])))throw new Error("planning-research-predecessor-invalid");const u={schemaVersion:r.schemaVersion,claimId:n,epicId:e,diagnosisReceiptId:s.receiptId,qaEvidenceId:r.qaEvidenceId,sourceHead:r.sourceHead,sourceStateSha256:r.sourceStateSha256,admissionPatchSha256:r.admissionPatchSha256,artifactDigests:f};if(!b(r,{...u,receiptId:S(JSON.stringify(u)),publicSafe:!0}))throw new Error("planning-research-predecessor-invalid");return{intakeRevision:l,diagnosisReceiptId:s.receiptId,rawIntent:p.rawIntent}}function di(i,n){const e=W(i,n,!1),t=JSON.parse(I(i,".neocortex/state.json",8*1024*1024).toString("utf8")),a=(o(t)&&o(t.epics)?t.epics:void 0)?.[n.epicId],d=o(t)&&o(t.epic_id_ledger)?t.epic_id_ledger:void 0;if(!o(a)||!o(a.createEpicPlanning)||!o(a.createEpicPlanningClaim)||a.createEpicPlanningClaim.claimId!==n.claimId||a.createEpicPlanningClaim.epicId!==n.epicId||a.createEpicPlanning.epicId!==n.epicId||a.createEpicPlanning.intakeRevision!==e.checkpoint.intakeRevision||!b(a.createEpicPlanning.intake,e.checkpoint.intake)||!b(a.createEpicPlanning.diagnosisReceipt,e.checkpoint.diagnosisReceipt)||!b(a.createEpicPlanningPhysical,K(n,e.receiptId))||!Array.isArray(d?.reserved_ids)||!d.reserved_ids.includes(n.epicId))throw new Error("planning-diagnosis-replay-conflict");return e.receiptId}function Si(i,n){oi(n);const e=n,t=B(i);if(J(t)!==t||O(t,["rev-parse","--show-toplevel"])!==t)throw new Error("planning-diagnosis-root-invalid");const c=m(t,".neocortex"),a=m(c,"state.json.planning.lock"),d=j(a,"wx",384);let g;try{const r=I(t,".neocortex/state.json",8388608);if(S(r)!==e.sourceStateSha256){const Q=di(t,e);return{epicId:e.epicId,diagnosisReceiptId:Q,qaEvidenceId:e.qaEvidenceId}}const f=X(t,e),p=M(f.state,{claimId:e.claimId,epicId:e.epicId,checkpoint:f.checkpoint});if(p===f.state)throw new Error("planning-diagnosis-already-sealed");const l=K(e,f.receiptId),h=p.epics,s={...p,epics:{...h,[e.epicId]:{...h[e.epicId],createEpicPlanningPhysical:l}}},u=O(t,["rev-parse","--git-common-dir"]),y=ti(u)?B(u):B(t,u);if(J(y)!==y||w(y).isSymbolicLink())throw new Error("planning-diagnosis-backup-dir-invalid");const E=m(y,"neocortex-planning");ni(E,{recursive:!0,mode:448});const k=w(E);if(!k.isDirectory()||k.isSymbolicLink()||k.uid!==process.getuid?.()||(k.mode&63)!==0)throw new Error("planning-diagnosis-backup-dir-invalid");const R=ii(),P=j(m(E,`state-backup-${R}.json`),"wx",384);try{T(P,f.stateRaw),_(P)}finally{D(P)}const C=j(E,"r");try{_(C)}finally{D(C)}g=m(c,`state.json.planning-tmp-${R}`);const $=j(g,"wx",384);try{T($,`${JSON.stringify(s,null,2)}
|
|
5
|
+
`),_($)}finally{D($)}if(!X(t,e,`.neocortex/state.json.planning-tmp-${R}`).stateRaw.equals(f.stateRaw))throw new Error("planning-diagnosis-state-conflict");ei(g,m(c,"state.json")),g=void 0;const z=j(c,"r");try{_(z)}finally{D(z)}return{epicId:e.epicId,diagnosisReceiptId:f.receiptId,qaEvidenceId:e.qaEvidenceId}}finally{if(g)try{L(g)}catch{}D(d),L(a)}}export{yi as acceptedPlanningDiagnosisPredecessor,mi as planningPendingSidecarDigest,ri as planningPhysicalPatchDigest,Si as sealPlanningDiagnosis};
|
|
@@ -25,6 +25,19 @@ export interface PlanningGenerationRootReviewV1 {
|
|
|
25
25
|
readonly qaEvidenceId: string;
|
|
26
26
|
readonly artifactSummary: string;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Reopen an already sealed and committed P03 before root memory work. This is
|
|
30
|
+
* physical consistency verification, not new QA, a claim or terminal authority.
|
|
31
|
+
* The sealer intentionally stays bound to its original pre-commit HEAD.
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyCommittedPlanningGeneration(projectRoot: string, claimId: string, epicId: string): {
|
|
34
|
+
readonly epicId: string;
|
|
35
|
+
readonly physicalAcceptanceReceiptId: string;
|
|
36
|
+
readonly storyIds: readonly string[];
|
|
37
|
+
readonly verifiedHead: string;
|
|
38
|
+
readonly stateSha256: string;
|
|
39
|
+
readonly publicSafe: true;
|
|
40
|
+
};
|
|
28
41
|
/** The root supplies independent QA; this CAS persists the accepted P03 checkpoint. */
|
|
29
42
|
export declare function sealPlanningGeneration(projectRoot: string, reviewInput: unknown): {
|
|
30
43
|
readonly epicId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import{execFileSync as
|
|
1
|
+
import{execFileSync as lt,spawnSync as st}from"node:child_process";import{createHash as ht,randomUUID as mt}from"node:crypto";import{closeSync as U,fsyncSync as Z,lstatSync as X,mkdirSync as yt,openSync as W,readFileSync as ut,realpathSync as Y,renameSync as St,unlinkSync as it,writeFileSync as nt}from"node:fs";import{isAbsolute as It,join as N,resolve as K}from"node:path";import{isDeepStrictEqual as G}from"node:util";import{planningPendingSidecarDigest as ct,planningPhysicalPatchDigest as Dt}from"./planning-diagnosis-checkpoint.js";import{acceptedPlanningResearchPredecessor as rt}from"./planning-research-checkpoint.js";const _=/^[a-f0-9]{64}$/,ot=/^P[1-9][0-9]{0,11}$/,at=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,pt="acd455ed0e39d98b90fb57391db75e366e4c5604db043e03a89a20e33d643c3c",dt="fa2194f89c01f07e225fd6f39e98e679f628e072239b6cd0af3ee527f0722518",gt="8636f22ec5950410902448ee1e9cb4947359ac98df518742bddbbb367468e3ae";function r(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function l(t){return ht("sha256").update(t).digest("hex")}function V(t,e,s=128*1024){return lt("git",[...e],{cwd:t,encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:s}).trim()}function q(t,e,s){const i=X(N(t,e));if(!i.isFile()||i.isSymbolicLink()||i.size<1||i.size>s)throw new Error("planning-generation-physical-artifact-invalid");return ut(N(t,e))}function J(t,e,s,i="HEAD"){const c=st("git",["show",`${i}:${e}`],{cwd:t,encoding:"buffer",maxBuffer:s});if(c.status!==0||!Buffer.isBuffer(c.stdout)||c.stdout.length<1||c.stdout.length>s)throw new Error("planning-generation-predecessor-uncommitted");return c.stdout}function v(t,e){for(const s of[".neocortex",".neocortex/planning",`.neocortex/planning/epic-${e}`,"docs","docs/epics","docs/stories"]){const i=X(N(t,s));if(!i.isDirectory()||i.isSymbolicLink()||i.uid!==process.getuid?.()||s===".neocortex"&&(i.mode&18)!==0)throw new Error("planning-generation-directory-boundary-invalid")}}function H(t,e){const i=/^---\n([\s\S]{1,8192}?)\n---\n/.exec(t.replace(/\r\n/g,`
|
|
2
2
|
`))?.[1]?.split(`
|
|
3
|
-
`).filter(
|
|
4
|
-
`),
|
|
3
|
+
`).filter(c=>c.startsWith(`${e}:`))??[];return i.length===1?i[0].slice(e.length+1).trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2"):void 0}function L(t,e){return typeof t=="string"&&t.length<=128&&l(t)===e}function Q(t,e){return Array.from({length:e},(s,i)=>`docs/stories/${t}.${String(i+1).padStart(2,"0")}.story.md`)}function bt(t){if(!r(t)||Object.keys(t).sort().join("|")!==["schemaVersion","verdict","claimId","epicId","diagnosisReceiptId","researchReceiptId","intakeRevision","sourceHead","sourceBranch","sourceStateSha256","admission","artifactDigests","qaEvidenceId","artifactSummary"].sort().join("|")||t.schemaVersion!=="PlanningGenerationRootReview/1"||t.verdict!=="accepted"||typeof t.claimId!="string"||!at.test(t.claimId)||typeof t.epicId!="string"||!ot.test(t.epicId)||typeof t.diagnosisReceiptId!="string"||!_.test(t.diagnosisReceiptId)||typeof t.researchReceiptId!="string"||!_.test(t.researchReceiptId)||typeof t.intakeRevision!="string"||!_.test(t.intakeRevision)||typeof t.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(t.sourceHead)||typeof t.sourceBranch!="string"||!/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/.test(t.sourceBranch)||typeof t.sourceStateSha256!="string"||!_.test(t.sourceStateSha256)||!r(t.admission)||Object.keys(t.admission).sort().join("|")!==["schemaVersion","outcome","baseSha","executionBranch","changedPaths","patchSha256"].sort().join("|")||t.admission.schemaVersion!==1||t.admission.outcome!=="admitted-unverified"||t.admission.baseSha!==t.sourceHead||t.admission.executionBranch!==t.sourceBranch||typeof t.admission.patchSha256!="string"||!_.test(t.admission.patchSha256)||!r(t.artifactDigests)||Object.keys(t.artifactDigests).sort().join("|")!=="epic|index|stories"||typeof t.artifactDigests.epic!="string"||!_.test(t.artifactDigests.epic)||typeof t.artifactDigests.index!="string"||!_.test(t.artifactDigests.index)||!r(t.artifactDigests.stories)||Object.keys(t.artifactDigests.stories).length<1||Object.keys(t.artifactDigests.stories).length>24||Object.values(t.artifactDigests.stories).some(s=>typeof s!="string"||!_.test(s))||typeof t.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(t.qaEvidenceId)||typeof t.artifactSummary!="string"||t.artifactSummary.length<16||t.artifactSummary.length>2048)throw new Error("planning-generation-review-invalid");const e=Q(t.epicId,Object.keys(t.artifactDigests.stories).length);if(!G(Object.keys(t.artifactDigests.stories).sort(),[...e].sort()))throw new Error("planning-generation-review-invalid")}function Et(t){const e={schemaVersion:"PlanningGenerationPhysicalAcceptance/1",claimId:t.claimId,epicId:t.epicId,diagnosisReceiptId:t.diagnosisReceiptId,researchReceiptId:t.researchReceiptId,intakeRevision:t.intakeRevision,qaEvidenceId:t.qaEvidenceId,sourceHead:t.sourceHead,sourceStateSha256:t.sourceStateSha256,admissionPatchSha256:t.admission.patchSha256,artifactDigests:t.artifactDigests};return{...e,receiptId:l(JSON.stringify(e)),publicSafe:!0}}function tt(t,e,s,i,c){if(v(t,e.epicId),V(t,["rev-parse","HEAD"])!==e.sourceHead||V(t,["symbolic-ref","--quiet","--short","HEAD"])!==e.sourceBranch)throw new Error("planning-generation-head-conflict");const y=`.neocortex/planning/epic-${e.epicId}`,u=`docs/epics/epic-${e.epicId}.md`,o=".neocortex/planning/planning.json",h=Q(e.epicId,Object.keys(e.artifactDigests.stories).length),n={index:o,epic:u,...Object.fromEntries(h.map((m,f)=>[`story${f}`,m]))};if(!Array.isArray(e.admission.changedPaths)||!G([...e.admission.changedPaths].sort(),Object.values(n).sort())||s&&Dt(t,n,i,!0)!==e.admission.patchSha256)throw new Error("planning-generation-admission-patch-conflict");const B=q(t,o,128*1024),R=q(t,u,512*1024),S=h.map(m=>q(t,m,128*1024));if(l(B)!==e.artifactDigests.index||l(R)!==e.artifactDigests.epic||h.some((m,f)=>l(S[f])!==e.artifactDigests.stories[m]))throw new Error("planning-generation-artifact-conflict");const $=R.toString("utf8"),T=H($,"title");if(H($,"id")!==e.epicId||H($,"stories_count")!==String(h.length)||!T||T.length>200||!$.includes("## Stories"))throw new Error("planning-generation-epic-invalid");for(const[m,f]of S.entries()){const d=f.toString("utf8"),D=/^---\n([\s\S]{1,8192}?)\n---\n/.exec(d.replace(/\r\n/g,`
|
|
4
|
+
`))?.[1]??"",C=H(d,"epic_id"),g=C===e.epicId&&!/^\s*epic\s*:/m.test(D)||!s&&C===void 0&&!/^\s*epic_id\s*:/m.test(D)&&H(d,"epic")===e.epicId;if(H(d,"id")!==`${e.epicId}.${String(m+1).padStart(2,"0")}`||!g||H(d,"status")!=="backlog"||!H(d,"title")||!d.includes("## Acceptance Criteria")||!/\bGiven\b[\s\S]*\bWhen\b[\s\S]*\bThen\b/.test(d))throw new Error("planning-generation-story-invalid")}const b=c??q(t,".neocortex/state.json",8*1024*1024),a=JSON.parse(b.toString("utf8"));if(!r(a)||!r(a.epics)||!r(a.stories))throw new Error("planning-generation-state-invalid");const E=rt(a,e.claimId,e.epicId);if(E.diagnosisReceiptId!==e.diagnosisReceiptId||E.researchReceiptId!==e.researchReceiptId||E.intakeRevision!==e.intakeRevision||s&&l(b)!==e.sourceStateSha256)throw new Error("planning-generation-state-conflict");const k=a.epics[e.epicId];if(!r(k)||h.some((m,f)=>Object.hasOwn(a.stories,`${e.epicId}.${String(f+1).padStart(2,"0")}`)))throw new Error("planning-generation-story-collision");const P=k.createEpicPlanningPhysical,x=k.createEpicPlanningResearchPhysical;if(!r(P)||!r(x)||!r(P.artifactDigests)||!r(x.artifactDigests))throw new Error("planning-generation-predecessor-invalid");for(const[m,f]of Object.entries({idea:`${y}/idea.json`,diagnosis:`${y}/diagnosis.md`,enrichment:`${y}/enriched-prompt.md`,research:`${y}/research.md`})){const d=m==="research"?x.artifactDigests.research:P.artifactDigests[m],D=q(t,f,m==="idea"?32*1024:256*1024);if(l(D)!==d||!D.equals(J(t,f,512*1024)))throw new Error("planning-generation-predecessor-artifact-drift")}const j=J(t,o,128*1024);if(l(j)!==x.artifactDigests.index)throw new Error("planning-generation-predecessor-index-drift");const A=JSON.parse(j.toString("utf8")),w=JSON.parse(B.toString("utf8"));if(!r(A)||!r(A.epics)||!r(w)||!r(w.epics))throw new Error("planning-generation-index-invalid");const p=A.epics[e.epicId],I=w.epics[e.epicId];if(!r(p)||p.id!==e.epicId||p.status!=="researched"||!Array.isArray(p.steps_completed)||p.steps_completed.length!==2||!L(p.steps_completed[0],pt)||!L(p.steps_completed[1],dt)||!G(p.output_files,{diagnosis:`${y}/diagnosis.md`,research:`${y}/research.md`})||!r(I)||!Array.isArray(I.steps_completed)||!L(I.steps_completed[2],gt))throw new Error("planning-generation-index-predecessor-invalid");const O={...A,last_scan:w.last_scan,epics:{...A.epics,[e.epicId]:{...p,status:"generated",steps_completed:[...p.steps_completed,I.steps_completed[2]],completed_at:I.completed_at,output_files:{...p.output_files,epic:u,stories:h}}}};if(typeof w.last_scan!="string"||!Number.isFinite(Date.parse(w.last_scan))||typeof I.completed_at!="string"||!Number.isFinite(Date.parse(I.completed_at))||!G(w,O))throw new Error("planning-generation-index-transition-invalid");return{stateRaw:b,state:a,title:T,stories:h,storyBytes:S,completedAt:I.completed_at}}function et(t,e,s){const i=t.state,c=t.stories.map(o=>o.slice(13,-9)),y=i.epics[e.epicId],u={...i.stories};for(const[o,h]of c.entries())u[h]={id:h,epic_id:e.epicId,title:H(t.storyBytes[o].toString("utf8"),"title"),status:"backlog"};return{...i,epics:{...i.epics,[e.epicId]:{...y,title:t.title,status:"generated",stories:c,total_stories:c.length,completed_stories:0,createEpicPlanningGenerationPhysical:s}},stories:u,last_updated:t.completedAt}}function kt(t,e,s){const i=()=>new Error("planning-generation-committed-evidence-invalid"),c=K(t);if(!at.test(e)||!ot.test(s)||Y(c)!==c||V(c,["rev-parse","--show-toplevel"])!==c)throw i();v(c,s);const y=V(c,["rev-parse","HEAD"]),u=q(c,".neocortex/state.json",8*1024*1024);if(!u.equals(J(c,".neocortex/state.json",8*1024*1024)))throw i();const o=JSON.parse(u.toString("utf8")),h=r(o)&&r(o.epics)?o.epics[s]:void 0,n=r(h)?h.createEpicPlanningGenerationPhysical:void 0;if(!r(n)||n.schemaVersion!=="PlanningGenerationPhysicalAcceptance/1"||n.claimId!==e||n.epicId!==s||typeof n.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(n.sourceHead)||typeof n.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(n.qaEvidenceId)||["diagnosisReceiptId","researchReceiptId","intakeRevision","sourceStateSha256","admissionPatchSha256"].some(g=>typeof n[g]!="string"||!_.test(n[g]))||!r(n.artifactDigests)||Object.keys(n.artifactDigests).sort().join("|")!=="epic|index|stories"||typeof n.artifactDigests.epic!="string"||!_.test(n.artifactDigests.epic)||typeof n.artifactDigests.index!="string"||!_.test(n.artifactDigests.index)||!r(n.artifactDigests.stories))throw i();const B=Object.keys(n.artifactDigests.stories).length,R=Q(s,B);if(B<1||B>24||!G(Object.keys(n.artifactDigests.stories).sort(),[...R].sort())||Object.values(n.artifactDigests.stories).some(g=>typeof g!="string"||!_.test(g)))throw i();const S={schemaVersion:"PlanningGenerationPhysicalAcceptance/1",claimId:e,epicId:s,diagnosisReceiptId:n.diagnosisReceiptId,researchReceiptId:n.researchReceiptId,intakeRevision:n.intakeRevision,qaEvidenceId:n.qaEvidenceId,sourceHead:n.sourceHead,sourceStateSha256:n.sourceStateSha256,admissionPatchSha256:n.admissionPatchSha256,artifactDigests:n.artifactDigests},$={...S,receiptId:l(JSON.stringify(S)),publicSafe:!0};if(!G(n,$)||st("git",["merge-base","--is-ancestor",n.sourceHead,"HEAD"],{cwd:c,stdio:"ignore"}).status!==0)throw i();const b=J(c,".neocortex/state.json",8*1024*1024,n.sourceHead);if(l(b)!==n.sourceStateSha256)throw i();const a=JSON.parse(b.toString("utf8")),E=rt(a,e,s);if(E.diagnosisReceiptId!==n.diagnosisReceiptId||E.researchReceiptId!==n.researchReceiptId||E.intakeRevision!==n.intakeRevision||!r(a)||!r(a.epics)||!r(a.epics[s]))throw i();const k=a.epics[s],P=k.createEpicPlanningPhysical,x=k.createEpicPlanningResearchPhysical;if(!r(P)||!r(P.artifactDigests)||!r(x)||!r(x.artifactDigests))throw i();const j=`.neocortex/planning/epic-${s}`;for(const[g,M,z]of[["idea",`${j}/idea.json`,32*1024],["diagnosis",`${j}/diagnosis.md`,256*1024],["enrichment",`${j}/enriched-prompt.md`,256*1024],["research",`${j}/research.md`,256*1024]]){const F=q(c,M,z),ft=g==="research"?x.artifactDigests.research:P.artifactDigests[g];if(l(F)!==ft||!F.equals(J(c,M,z))||!F.equals(J(c,M,z,n.sourceHead)))throw i()}const A=(g,M,z)=>{const F=q(c,g,z);if(l(F)!==M||!F.equals(J(c,g,z)))throw i();return F},w=A(`docs/epics/epic-${s}.md`,S.artifactDigests.epic,512*1024),p=R.map(g=>A(g,S.artifactDigests.stories[g],128*1024)),I=".neocortex/planning/planning.json",O=JSON.parse(A(I,S.artifactDigests.index,128*1024).toString("utf8")),m=J(c,I,128*1024,n.sourceHead);if(l(m)!==x.artifactDigests.index)throw i();const f=JSON.parse(m.toString("utf8"));if(!r(O)||!r(O.epics)||!r(O.epics[s])||!r(f)||!r(f.epics)||!r(f.epics[s]))throw i();const d=O.epics[s],D=f.epics[s];if(!Array.isArray(D.steps_completed)||D.steps_completed.length!==2||!L(D.steps_completed[0],pt)||!L(D.steps_completed[1],dt)||!Array.isArray(d.steps_completed)||!L(d.steps_completed[2],gt)||typeof d.completed_at!="string"||!Number.isFinite(Date.parse(d.completed_at))||typeof O.last_scan!="string"||!Number.isFinite(Date.parse(O.last_scan))||!G(O,{...f,last_scan:O.last_scan,epics:{...f.epics,[s]:{...D,status:"generated",steps_completed:[...D.steps_completed,d.steps_completed[2]],completed_at:d.completed_at,output_files:{...D.output_files,epic:`docs/epics/epic-${s}.md`,stories:R}}}}))throw i();const C=H(w.toString("utf8"),"title");if(!C||!G(o,et({stateRaw:b,state:a,title:C,stories:R,storyBytes:p,completedAt:d.completed_at},{epicId:s},$))||V(c,["rev-parse","HEAD"])!==y||!q(c,".neocortex/state.json",8*1024*1024).equals(u))throw i();return{epicId:s,physicalAcceptanceReceiptId:$.receiptId,storyIds:R.map(g=>g.slice(13,-9)),verifiedHead:y,stateSha256:l(u),publicSafe:!0}}function At(t,e){bt(e);const s=e,i=K(t);if(Y(i)!==i||V(i,["rev-parse","--show-toplevel"])!==i)throw new Error("planning-generation-root-invalid");v(i,s.epicId);const c=N(i,".neocortex"),y=N(c,"state.json.planning.lock"),u=W(y,"wx",384);let o;try{const h=ct(i),n=Et(s),B=Q(s.epicId,Object.keys(s.artifactDigests.stories).length).map(p=>p.slice(13,-9)),R=q(i,".neocortex/state.json",8*1024*1024);if(l(R)!==s.sourceStateSha256){const p=J(i,".neocortex/state.json",8388608);if(l(p)!==s.sourceStateSha256)throw new Error("planning-generation-replay-conflict");const I=tt(i,s,!1,void 0,p);if(!G(JSON.parse(R.toString("utf8")),et(I,s,n)))throw new Error("planning-generation-replay-conflict");return{epicId:s.epicId,physicalAcceptanceReceiptId:n.receiptId,qaEvidenceId:s.qaEvidenceId,storyIds:B}}const S=tt(i,s,!0),$=et(S,s,n),T=V(i,["rev-parse","--git-common-dir"]),b=It(T)?K(T):K(i,T);if(Y(b)!==b||X(b).isSymbolicLink())throw new Error("planning-generation-backup-dir-invalid");const a=N(b,"neocortex-planning");yt(a,{recursive:!0,mode:448});const E=X(a);if(!E.isDirectory()||E.isSymbolicLink()||E.uid!==process.getuid?.()||(E.mode&63)!==0)throw new Error("planning-generation-backup-dir-invalid");const k=mt(),P=W(N(a,`state-backup-${k}.json`),"wx",384);try{nt(P,S.stateRaw),Z(P)}finally{U(P)}const x=W(a,"r");try{Z(x)}finally{U(x)}o=N(c,`state.json.planning-tmp-${k}`);const j=W(o,"wx",384);try{nt(j,`${JSON.stringify($,null,2)}
|
|
5
|
+
`),Z(j)}finally{U(j)}if(!tt(i,s,!0,`.neocortex/state.json.planning-tmp-${k}`).stateRaw.equals(S.stateRaw))throw new Error("planning-generation-state-conflict");if(ct(i)!==h)throw new Error("planning-generation-pending-conflict");St(o,N(c,"state.json")),o=void 0;const w=W(c,"r");try{Z(w)}finally{U(w)}return{epicId:s.epicId,physicalAcceptanceReceiptId:n.receiptId,qaEvidenceId:s.qaEvidenceId,storyIds:B}}finally{if(o)try{it(o)}catch{}U(u),it(y)}}export{At as sealPlanningGeneration,kt as verifyCommittedPlanningGeneration};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface PlanningMemoryRootReviewV1 {
|
|
2
|
+
readonly schemaVersion: 'PlanningMemoryRootReview/1';
|
|
3
|
+
readonly verdict: 'accepted';
|
|
4
|
+
readonly claimId: string;
|
|
5
|
+
readonly epicId: string;
|
|
6
|
+
readonly sourceHead: string;
|
|
7
|
+
readonly generationReceiptId: string;
|
|
8
|
+
readonly canonicalSha256: string;
|
|
9
|
+
readonly projectionSha256: string;
|
|
10
|
+
readonly fileCount: number;
|
|
11
|
+
readonly qaEvidenceId: string;
|
|
12
|
+
readonly artifactSummary: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PlanningMemoryPhysicalAcceptanceV1 {
|
|
15
|
+
readonly schemaVersion: 'PlanningMemoryPhysicalAcceptance/1';
|
|
16
|
+
readonly claimId: string;
|
|
17
|
+
readonly epicId: string;
|
|
18
|
+
readonly sourceHead: string;
|
|
19
|
+
readonly generationReceiptId: string;
|
|
20
|
+
readonly stateSha256: string;
|
|
21
|
+
readonly canonicalSha256: string;
|
|
22
|
+
readonly projectionSha256: string;
|
|
23
|
+
readonly fileCount: number;
|
|
24
|
+
readonly qaEvidenceId: string;
|
|
25
|
+
readonly artifactSummary: string;
|
|
26
|
+
readonly receiptId: string;
|
|
27
|
+
readonly publicSafe: true;
|
|
28
|
+
}
|
|
29
|
+
/** Only a typed independent root review can create this receipt. No canonical state is rewritten. */
|
|
30
|
+
export declare function sealPlanningMemory(projectRoot: string, input: unknown): PlanningMemoryPhysicalAcceptanceV1;
|
|
31
|
+
/** Fresh read-only physical verification; metadata, a digest or an old receipt is insufficient. */
|
|
32
|
+
export declare function verifyCommittedPlanningMemory(projectRoot: string, claimId: string, epicId: string): PlanningMemoryPhysicalAcceptanceV1;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{execFileSync as q,spawnSync as x}from"node:child_process";import{createHash as A}from"node:crypto";import{closeSync as h,existsSync as $,fsyncSync as H,lstatSync as g,openSync as S,readFileSync as I,readlinkSync as M,realpathSync as D,unlinkSync as F,writeFileSync as N}from"node:fs";import{join as d,resolve as b}from"node:path";import{isDeepStrictEqual as w}from"node:util";import{canonicalPlanningIntake as B}from"../../../shared/dist/planning/diagnosis-state.js";import{parseRefreshMemoryArgs as O,refreshProjectMemoryTargets as v,verifyProjectMemoryTargets as J}from"../commands/refresh-memory.js";import{planningPendingSidecarDigest as P}from"./planning-diagnosis-checkpoint.js";import{verifyCommittedPlanningGeneration as k}from"./planning-generation-checkpoint.js";const L=e=>A("sha256").update(e).digest("hex"),r=()=>new Error("planning-memory-physical-evidence-invalid"),E=e=>!!e&&typeof e=="object"&&!Array.isArray(e),y=(e,...t)=>q("git",t,{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:1024*1024}).trim(),R=e=>`.neocortex/planning/epic-${e}/memory-acceptance.json`;function C(e,t){const i=x("git",["show",`HEAD:${t}`],{cwd:e,encoding:"buffer",maxBuffer:1048576});if(i.status!==0||!Buffer.isBuffer(i.stdout))throw r();return i.stdout}function V(e,t,i){if(D(e)!==e||y(e,"rev-parse","--show-toplevel")!==e)throw r();const o=k(e,t,i),c=O(["--project-root",e,"--verify"]),m=J(c),l=[...new Set(v(c).flatMap(n=>n.files.map(s=>s.relativeFile)))].sort();for(const n of l){const s=d(e,n),a=g(s);if(!(a.isSymbolicLink()?Buffer.from(M(s)):I(s)).equals(C(e,n)))throw r();const f=y(e,"ls-tree","HEAD","--",n).split(" ")[0];if(a.isSymbolicLink()?f!=="120000":!a.isFile()||!["100644","100755"].includes(f))throw r()}if(y(e,"rev-parse","HEAD")!==o.verifiedHead)throw r();return{generation:o,memory:m,files:l}}function u(e){if(!E(e)||Object.keys(e).sort().join("|")!==["schemaVersion","verdict","claimId","epicId","sourceHead","generationReceiptId","canonicalSha256","projectionSha256","fileCount","qaEvidenceId","artifactSummary"].sort().join("|")||e.schemaVersion!=="PlanningMemoryRootReview/1"||e.verdict!=="accepted"||typeof e.claimId!="string"||!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(e.claimId)||typeof e.epicId!="string"||!/^P[1-9][0-9]{0,11}$/.test(e.epicId)||typeof e.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(e.sourceHead)||[e.generationReceiptId,e.canonicalSha256,e.projectionSha256].some(t=>typeof t!="string"||!/^[a-f0-9]{64}$/.test(t))||!Number.isInteger(e.fileCount)||Number(e.fileCount)<1||Number(e.fileCount)>64||typeof e.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(e.qaEvidenceId)||typeof e.artifactSummary!="string"||!e.artifactSummary.trim())throw r();B({goal:e.artifactSummary})}function j(e,t){u(t);const{generation:i,memory:o}=V(e,t.claimId,t.epicId);if(i.physicalAcceptanceReceiptId!==t.generationReceiptId||o.canonicalSha256!==t.canonicalSha256||o.projectionSha256!==t.projectionSha256||o.fileCount!==t.fileCount||x("git",["merge-base","--is-ancestor",t.sourceHead,"HEAD"],{cwd:e,stdio:"ignore"}).status!==0)throw r();const c={schemaVersion:"PlanningMemoryPhysicalAcceptance/1",claimId:t.claimId,epicId:t.epicId,sourceHead:t.sourceHead,generationReceiptId:t.generationReceiptId,stateSha256:i.stateSha256,canonicalSha256:t.canonicalSha256,projectionSha256:t.projectionSha256,fileCount:t.fileCount,qaEvidenceId:t.qaEvidenceId,artifactSummary:t.artifactSummary};return{...c,receiptId:L(JSON.stringify(c)),publicSafe:!0}}function Z(e,t){u(t);const i=b(e),o=R(t.epicId);k(i,t.claimId,t.epicId);const c=d(i,".neocortex/state.json.planning.lock"),m=S(c,"wx",384);try{const l=P(i),n=j(i,t);if($(d(i,o))){const f=g(d(i,o));if(!f.isFile()||f.isSymbolicLink()||f.size>16384||!w(JSON.parse(I(d(i,o),"utf8")),n))throw r();return n}if(y(i,"rev-parse","HEAD")!==t.sourceHead||y(i,"diff","--name-only")||y(i,"diff","--cached","--name-only")||y(i,"ls-files","--others","--exclude-standard").split(`
|
|
2
|
+
`).filter(Boolean).some(f=>f!==".neocortex/pending-epic-claims.json"&&f!==".neocortex/state.json.planning.lock")||P(i)!==l||!w(j(i,t),n))throw r();const a=S(d(i,o),"wx",384);try{N(a,`${JSON.stringify(n,null,2)}
|
|
3
|
+
`),H(a)}finally{h(a)}const p=S(d(i,".neocortex/planning",`epic-${t.epicId}`),"r");try{H(p)}finally{h(p)}return n}finally{h(m),F(c)}}function _(e,t,i){if(!/^P[1-9][0-9]{0,11}$/.test(i))throw r();const o=b(e),c=R(i),m=g(d(o,c));if(!m.isFile()||m.isSymbolicLink()||m.size>16384)throw r();const l=I(d(o,c));if(!l.equals(C(o,c)))throw r();const n=JSON.parse(l.toString("utf8"));if(!E(n)||n.claimId!==t||n.epicId!==i)throw r();const s={schemaVersion:"PlanningMemoryRootReview/1",verdict:"accepted",claimId:t,epicId:i,sourceHead:n.sourceHead,generationReceiptId:n.generationReceiptId,canonicalSha256:n.canonicalSha256,projectionSha256:n.projectionSha256,fileCount:n.fileCount,qaEvidenceId:n.qaEvidenceId,artifactSummary:n.artifactSummary};u(s);const a=j(o,s);if(!w(n,a))throw r();return a}export{Z as sealPlanningMemory,_ as verifyCommittedPlanningMemory};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{execFileSync as
|
|
2
|
-
`),n=/^---\n([\s\S]{1,8192}?)\n---\n/.exec(i)?.[1];if(!n)return;const
|
|
3
|
-
`),
|
|
4
|
-
`),q(
|
|
1
|
+
import{execFileSync as W,spawnSync as X}from"node:child_process";import{createHash as K,randomUUID as Q}from"node:crypto";import{closeSync as D,fsyncSync as q,lstatSync as A,mkdirSync as Y,openSync as b,readFileSync as v,realpathSync as J,renameSync as ee,unlinkSync as F,writeFileSync as L}from"node:fs";import{isAbsolute as te,join as y,resolve as B}from"node:path";import{isDeepStrictEqual as P}from"node:util";import{createPlanningReceiptV1 as V}from"../../../shared/dist/planning/diagnosis-state.js";import{acceptedPlanningDiagnosisPredecessor as T,planningPendingSidecarDigest as C,planningPhysicalPatchDigest as ie}from"./planning-diagnosis-checkpoint.js";const l=/^[a-f0-9]{64}$/,ne=/^P[1-9][0-9]{0,11}$/,se=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,ce="acd455ed0e39d98b90fb57391db75e366e4c5604db043e03a89a20e33d643c3c",re="fa2194f89c01f07e225fd6f39e98e679f628e072239b6cd0af3ee527f0722518";function p(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function u(e){return K("sha256").update(e).digest("hex")}function _(e,t,i=128*1024){return W("git",[...t],{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:i}).trim()}function w(e,t,i){const n=A(y(e,t));if(!n.isFile()||n.isSymbolicLink()||n.size<1||n.size>i)throw new Error("planning-research-physical-artifact-invalid");return v(y(e,t))}function G(e,t){for(const i of[".neocortex",".neocortex/planning",`.neocortex/planning/epic-${t}`]){const n=A(y(e,i));if(!n.isDirectory()||n.isSymbolicLink()||n.uid!==process.getuid?.()||i===".neocortex"&&(n.mode&18)!==0)throw new Error("planning-research-directory-boundary-invalid")}}function M(e,t){return typeof e=="string"&&e.length<=128&&u(e)===t}function ae(e,t){const i=e.replace(/\r\n/g,`
|
|
2
|
+
`),n=/^---\n([\s\S]{1,8192}?)\n---\n/.exec(i)?.[1];if(!n)return;const a=n.split(`
|
|
3
|
+
`),r=c=>{const s=a.filter(o=>o.startsWith(`${c}:`));return s.length===1?s[0].slice(c.length+1).trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2"):void 0},g=r("step");return r("epic_id")===t&&r("status")==="completed"&&M(g,re)&&i.slice(n.length+9).trim().length>0?g:void 0}function oe(e){if(!p(e)||Object.keys(e).sort().join("|")!==["schemaVersion","verdict","claimId","epicId","diagnosisReceiptId","intakeRevision","sourceHead","sourceBranch","sourceStateSha256","admission","artifactDigests","qaEvidenceId","artifactSummary"].sort().join("|")||e.schemaVersion!=="PlanningResearchRootReview/1"||e.verdict!=="accepted"||typeof e.claimId!="string"||!se.test(e.claimId)||typeof e.epicId!="string"||!ne.test(e.epicId)||typeof e.diagnosisReceiptId!="string"||!l.test(e.diagnosisReceiptId)||typeof e.intakeRevision!="string"||!l.test(e.intakeRevision)||typeof e.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(e.sourceHead)||typeof e.sourceBranch!="string"||!/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/.test(e.sourceBranch)||typeof e.sourceStateSha256!="string"||!l.test(e.sourceStateSha256)||!p(e.admission)||Object.keys(e.admission).sort().join("|")!==["schemaVersion","outcome","baseSha","executionBranch","changedPaths","patchSha256"].sort().join("|")||e.admission.schemaVersion!==1||e.admission.outcome!=="admitted-unverified"||e.admission.baseSha!==e.sourceHead||e.admission.executionBranch!==e.sourceBranch||typeof e.admission.patchSha256!="string"||!l.test(e.admission.patchSha256)||!p(e.artifactDigests)||Object.keys(e.artifactDigests).sort().join("|")!=="index|research"||typeof e.artifactDigests.index!="string"||!l.test(e.artifactDigests.index)||typeof e.artifactDigests.research!="string"||!l.test(e.artifactDigests.research)||typeof e.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(e.qaEvidenceId)||typeof e.artifactSummary!="string")throw new Error("planning-research-review-invalid");V({kind:"research",epicId:e.epicId,intakeRevision:e.intakeRevision,predecessorReceiptId:e.diagnosisReceiptId,artifactSummary:e.artifactSummary,accepted:!0})}function U(e,t){const i={schemaVersion:"PlanningResearchPhysicalAcceptance/1",claimId:e.claimId,epicId:e.epicId,diagnosisReceiptId:e.diagnosisReceiptId,researchReceiptId:t,intakeRevision:e.intakeRevision,qaEvidenceId:e.qaEvidenceId,sourceHead:e.sourceHead,sourceStateSha256:e.sourceStateSha256,admissionPatchSha256:e.admission.patchSha256,artifactDigests:e.artifactDigests};return{...i,receiptId:u(JSON.stringify(i)),publicSafe:!0}}function z(e,t,i,n){if(G(e,t.epicId),_(e,["rev-parse","HEAD"])!==t.sourceHead||_(e,["symbolic-ref","--quiet","--short","HEAD"])!==t.sourceBranch)throw new Error("planning-research-head-conflict");const a={research:`.neocortex/planning/epic-${t.epicId}/research.md`,index:".neocortex/planning/planning.json"};if(!Array.isArray(t.admission.changedPaths)||[...t.admission.changedPaths].sort().join("|")!==Object.values(a).sort().join("|")||i&&ie(e,a,n,!0)!==t.admission.patchSha256)throw new Error("planning-research-admission-patch-conflict");const r={research:w(e,a.research,256*1024),index:w(e,a.index,128*1024)},g=ae(r.research.toString("utf8"),t.epicId);if(u(r.research)!==t.artifactDigests.research||u(r.index)!==t.artifactDigests.index||!g)throw new Error("planning-research-artifact-conflict");const c=w(e,".neocortex/state.json",8*1024*1024),s=JSON.parse(c.toString("utf8")),o=T(s,t.claimId,t.epicId,!i);if(o.diagnosisReceiptId!==t.diagnosisReceiptId||o.intakeRevision!==t.intakeRevision||i&&u(c)!==t.sourceStateSha256)throw new Error("planning-research-state-conflict");const j=s.epics[t.epicId].createEpicPlanningPhysical.artifactDigests,I=`.neocortex/planning/epic-${t.epicId}`;for(const[x,$]of Object.entries({idea:`${I}/idea.json`,diagnosis:`${I}/diagnosis.md`,enrichment:`${I}/enriched-prompt.md`}))if(u(w(e,$,x==="idea"?32*1024:256*1024))!==j[x])throw new Error("planning-research-predecessor-artifact-drift");const R=X("git",["show",`HEAD:${a.index}`],{cwd:e,encoding:"buffer",maxBuffer:128*1024});if(R.status!==0||!Buffer.isBuffer(R.stdout)||u(R.stdout)!==j.index)throw new Error("planning-research-predecessor-index-drift");const m=JSON.parse(R.stdout.toString("utf8")),f=JSON.parse(r.index.toString("utf8"));if(!p(m)||!p(m.epics)||!p(f)||!p(f.epics))throw new Error("planning-research-index-invalid");const d=m.epics[t.epicId];if(!p(d)||d.id!==t.epicId||d.idea!==o.rawIntent||d.status!=="diagnosed"||!Array.isArray(d.steps_completed)||d.steps_completed.length!==1||!M(d.steps_completed[0],ce)||!P(d.output_files,{diagnosis:`${I}/diagnosis.md`}))throw new Error("planning-research-index-predecessor-invalid");const E={...m,last_scan:f.last_scan,epics:{...m.epics,[t.epicId]:{...d,status:"researched",steps_completed:[...d.steps_completed,g],output_files:{diagnosis:`${I}/diagnosis.md`,research:a.research}}}};if(typeof f.last_scan!="string"||!Number.isFinite(Date.parse(f.last_scan))||!P(f,E))throw new Error("planning-research-index-transition-invalid");const k=V({kind:"research",epicId:t.epicId,intakeRevision:t.intakeRevision,predecessorReceiptId:t.diagnosisReceiptId,artifactSummary:t.artifactSummary,accepted:!0});return{stateRaw:c,state:s,receipt:k}}function de(e,t){const i=z(e,t,!1),a=i.state.epics[t.epicId],r=a.createEpicPlanning;if(a.status!=="researched"||!P(r.researchReceipt,i.receipt)||!P(a.createEpicPlanningResearchPhysical,U(t,i.receipt.receiptId)))throw new Error("planning-research-replay-conflict");return i.receipt.receiptId}function Ie(e,t,i){const n=T(e,t,i,!0),r=e.epics[i],g=p(r?.createEpicPlanning)?r.createEpicPlanning:void 0,c=p(g?.researchReceipt)?g.researchReceipt:void 0,s=p(r?.createEpicPlanningResearchPhysical)?r.createEpicPlanningResearchPhysical:void 0,o=p(s?.artifactDigests)?s.artifactDigests:void 0;if(r?.status!=="researched"||!c||!s||!o||typeof c.artifactSummary!="string"||!P(c,V({kind:"research",epicId:i,intakeRevision:n.intakeRevision,predecessorReceiptId:n.diagnosisReceiptId,artifactSummary:c.artifactSummary,accepted:!0}))||s.schemaVersion!=="PlanningResearchPhysicalAcceptance/1"||s.claimId!==t||s.epicId!==i||s.diagnosisReceiptId!==n.diagnosisReceiptId||s.researchReceiptId!==c.receiptId||s.intakeRevision!==n.intakeRevision||typeof s.qaEvidenceId!="string"||!/^qa-[a-z0-9-]{8,80}$/.test(s.qaEvidenceId)||typeof s.sourceHead!="string"||!/^[a-f0-9]{40}$/.test(s.sourceHead)||typeof s.sourceStateSha256!="string"||!l.test(s.sourceStateSha256)||typeof s.admissionPatchSha256!="string"||!l.test(s.admissionPatchSha256)||Object.keys(o).sort().join("|")!=="index|research"||typeof o.index!="string"||!l.test(o.index)||typeof o.research!="string"||!l.test(o.research))throw new Error("planning-generation-predecessor-invalid");const h={schemaVersion:s.schemaVersion,claimId:t,epicId:i,diagnosisReceiptId:n.diagnosisReceiptId,researchReceiptId:c.receiptId,intakeRevision:n.intakeRevision,qaEvidenceId:s.qaEvidenceId,sourceHead:s.sourceHead,sourceStateSha256:s.sourceStateSha256,admissionPatchSha256:s.admissionPatchSha256,artifactDigests:o},S={...h,receiptId:u(JSON.stringify(h)),publicSafe:!0};if(!P(s,S))throw new Error("planning-generation-predecessor-invalid");return{intakeRevision:n.intakeRevision,diagnosisReceiptId:n.diagnosisReceiptId,researchReceiptId:c.receiptId,physicalAcceptanceReceiptId:S.receiptId}}function Se(e,t){oe(t);const i=t,n=B(e);if(J(n)!==n||_(n,["rev-parse","--show-toplevel"])!==n)throw new Error("planning-research-root-invalid");G(n,i.epicId);const a=y(n,".neocortex"),r=y(a,"state.json.planning.lock"),g=b(r,"wx",384);let c;try{const s=C(n),o=w(n,".neocortex/state.json",8*1024*1024);if(u(o)!==i.sourceStateSha256){const Z=de(n,i);return{epicId:i.epicId,researchReceiptId:Z,qaEvidenceId:i.qaEvidenceId}}const h=z(n,i,!0),S=h.state.epics,H=S[i.epicId],j=H.createEpicPlanning,I=U(i,h.receipt.receiptId),R={...h.state,epics:{...S,[i.epicId]:{...H,status:"researched",createEpicPlanning:{...j,researchReceipt:h.receipt},createEpicPlanningResearchPhysical:I}}},m=_(n,["rev-parse","--git-common-dir"]),f=te(m)?B(m):B(n,m);if(J(f)!==f||A(f).isSymbolicLink())throw new Error("planning-research-backup-dir-invalid");const d=y(f,"neocortex-planning");Y(d,{recursive:!0,mode:448});const E=A(d);if(!E.isDirectory()||E.isSymbolicLink()||E.uid!==process.getuid?.()||(E.mode&63)!==0)throw new Error("planning-research-backup-dir-invalid");const k=Q(),x=b(y(d,`state-backup-${k}.json`),"wx",384);try{L(x,h.stateRaw),q(x)}finally{D(x)}const $=b(d,"r");try{q($)}finally{D($)}c=y(a,`state.json.planning-tmp-${k}`);const O=b(c,"wx",384);try{L(O,`${JSON.stringify(R,null,2)}
|
|
4
|
+
`),q(O)}finally{D(O)}if(!z(n,i,!0,`.neocortex/state.json.planning-tmp-${k}`).stateRaw.equals(h.stateRaw))throw new Error("planning-research-state-conflict");if(C(n)!==s)throw new Error("planning-research-pending-conflict");ee(c,y(a,"state.json")),c=void 0;const N=b(a,"r");try{q(N)}finally{D(N)}return{epicId:i.epicId,researchReceiptId:h.receipt.receiptId,qaEvidenceId:i.qaEvidenceId}}finally{if(c)try{F(c)}catch{}D(g),F(r)}}export{Ie as acceptedPlanningResearchPredecessor,Se as sealPlanningResearch};
|