@ornexus/neocortex 4.60.57 → 4.60.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sbom.cdx.json +23 -23
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +2 -2
- package/packages/client/dist/commands/invoke.d.ts +1 -1
- package/packages/client/dist/commands/invoke.js +57 -57
- package/packages/client/dist/private-execution/delivery.d.ts +22 -4
- package/packages/client/dist/private-execution/delivery.js +2 -2
- package/packages/client/dist/private-execution/isolated-admission.d.ts +9 -1
- package/packages/client/dist/private-execution/isolated-admission.js +2 -2
- package/packages/client/dist/private-execution/isolated-workspace.d.ts +2 -1
- package/packages/client/dist/private-execution/isolated-workspace.js +1 -1
- package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +15 -1
- package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +5 -1
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1
- 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/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -42,7 +42,21 @@ export interface PrivateExecutionPublicStepBindingV2 {
|
|
|
42
42
|
readonly hostKind: 'codex-cli';
|
|
43
43
|
readonly hostVersion: string;
|
|
44
44
|
}
|
|
45
|
-
export
|
|
45
|
+
export interface PrivateExecutionPublicEpicClaimBindingV3 {
|
|
46
|
+
readonly schemaVersion: 3;
|
|
47
|
+
readonly authorityKind: 'epic-claim';
|
|
48
|
+
readonly projectId: string;
|
|
49
|
+
readonly commandId: 'create-epic';
|
|
50
|
+
readonly stepId: string;
|
|
51
|
+
readonly claimId: string;
|
|
52
|
+
readonly epicId: string;
|
|
53
|
+
readonly stateSnapshotSha256: string;
|
|
54
|
+
readonly generationId: string;
|
|
55
|
+
readonly inputSha256: string;
|
|
56
|
+
readonly hostKind: 'codex-cli';
|
|
57
|
+
readonly hostVersion: string;
|
|
58
|
+
}
|
|
59
|
+
export type PrivateExecutionPublicBinding = PrivateExecutionPublicBindingV1 | PrivateExecutionPublicStepBindingV2 | PrivateExecutionPublicEpicClaimBindingV3;
|
|
46
60
|
export interface PrivateExecutionDescriptorV1 {
|
|
47
61
|
readonly schemaVersion: 1;
|
|
48
62
|
readonly leaseId: string;
|
|
@@ -57,9 +71,13 @@ export interface PrivateExecutionDescriptorV2 extends Omit<PrivateExecutionDescr
|
|
|
57
71
|
readonly schemaVersion: 2;
|
|
58
72
|
readonly binding: PrivateExecutionPublicStepBindingV2;
|
|
59
73
|
}
|
|
60
|
-
export
|
|
74
|
+
export interface PrivateExecutionDescriptorV3 extends Omit<PrivateExecutionDescriptorV1, 'schemaVersion' | 'binding'> {
|
|
75
|
+
readonly schemaVersion: 3;
|
|
76
|
+
readonly binding: PrivateExecutionPublicEpicClaimBindingV3;
|
|
77
|
+
}
|
|
78
|
+
export type PrivateExecutionDescriptor = PrivateExecutionDescriptorV1 | PrivateExecutionDescriptorV2 | PrivateExecutionDescriptorV3;
|
|
61
79
|
export declare function privateExecutionStateSnapshotSha256(stateSnapshot: unknown): string;
|
|
62
|
-
export declare function parsePrivateExecutionDescriptor(value: unknown, expected?:
|
|
80
|
+
export declare function parsePrivateExecutionDescriptor(value: unknown, expected?: Readonly<Record<string, unknown>>): PrivateExecutionDescriptor;
|
|
63
81
|
export declare function verifyPrivateExecutionMaterial(descriptor: PrivateExecutionDescriptor, material: unknown, nowMs?: number): string;
|
|
64
82
|
export interface PrivateExecutionDeliveryResponseV1 {
|
|
65
83
|
readonly schemaVersion: 1;
|
|
@@ -69,6 +87,6 @@ export interface PrivateExecutionDeliveryResponseV1 {
|
|
|
69
87
|
* The transport implementation must keep request and response bodies in memory.
|
|
70
88
|
* No retry is safe after a one-time lease may have been consumed.
|
|
71
89
|
*/
|
|
72
|
-
export declare function consumePrivateExecutionDelivery(rawDescriptor: unknown, expected:
|
|
90
|
+
export declare function consumePrivateExecutionDelivery(rawDescriptor: unknown, expected: Readonly<Record<string, unknown>>, postOnce: (body: {
|
|
73
91
|
readonly leaseId: string;
|
|
74
92
|
} & PrivateExecutionPublicBinding) => Promise<unknown>, nowMs?: number): Promise<string>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
import{createHash as m}from"node:crypto";const g=`# Neocortex private execution pending
|
|
2
2
|
|
|
3
|
-
The authorized Codex CLI executor must consume the one-time delivery and produce a physical receipt.`;function
|
|
3
|
+
The authorized Codex CLI executor must consume the one-time delivery and produce a physical receipt.`;function l(r){if(!r||typeof r!="object"||Array.isArray(r))return!1;const o=r,t=o.metadata;if(Object.keys(o).sort().join(",")!=="instructions,metadata"||o.instructions!==g||!t||typeof t!="object"||Array.isArray(t))return!1;const e=t,s=e.privateExecution;let i;try{i=u(s)}catch{return!1}if(i.schemaVersion===2)return Object.keys(e).sort().join(",")===["mode","storyId","stepId","resolvedTrigger","privateExecution"].sort().join(",")&&(e.mode==="step"&&(e.resolvedTrigger==="research"||e.resolvedTrigger==="write-spec")&&i.binding.commandId===e.resolvedTrigger||e.mode==="pipeline"&&e.resolvedTrigger==="exec"&&i.binding.commandId==="exec")&&e.storyId===i.binding.storyId&&e.stepId===i.binding.stepId;if(i.schemaVersion===3){const y=e.epicClaim,d=y&&typeof y=="object"&&!Array.isArray(y)?y:void 0;return Object.keys(e).sort().join(",")===["mode","stepId","resolvedTrigger","privateExecution","epicClaim"].sort().join(",")&&e.mode==="create-epic"&&e.resolvedTrigger==="create-epic"&&e.stepId===i.binding.stepId&&i.binding.commandId==="create-epic"&&!!d&&Object.keys(d).sort().join(",")===["schemaVersion","claimId","epicId","outcome","publicSafe"].sort().join(",")&&d.schemaVersion===1&&d.outcome==="reserved"&&d.publicSafe===!0&&d.claimId===i.binding.claimId&&d.epicId===i.binding.epicId}const a=e.privateExecutionRootAction,c=["mode","storyId","stepId","resolvedTrigger","gitLifecycleGraphAuthority","privateExecution",...a===void 0?[]:["privateExecutionRootAction"]],h=e.gitLifecycleGraphAuthority,p=h&&typeof h=="object"&&!Array.isArray(h)?h:void 0,n=a&&typeof a=="object"&&!Array.isArray(a)?a:void 0;return Object.keys(e).sort().join(",")===c.sort().join(",")&&e.mode==="yolo"&&e.resolvedTrigger==="yolo"&&typeof e.storyId=="string"&&typeof e.stepId=="string"&&!!p&&p.storyId===e.storyId&&p.graphRevision===i.binding.graphRevision&&i.binding.commandId==="yolo"&&i.binding.stepId===e.stepId&&(a===void 0||!!n&&Object.keys(n).sort().join(",")===["schemaVersion","action","storyId","executionBranch","graphRevision","publicSafe",...n.action==="checkpoint-epic-story"?["stepId"]:[]].sort().join(",")&&n.schemaVersion===1&&(n.action==="prepare-epic-checkout"||n.action==="checkpoint-epic-story")&&(n.action!=="checkpoint-epic-story"||n.stepId===e.stepId)&&n.publicSafe===!0&&n.storyId===e.storyId&&n.storyId===p.storyId&&n.executionBranch===p.executionBranch&&n.graphRevision===p.graphRevision)}function b(r){return m("sha256").update("private-step-state-v1\0").update(JSON.stringify(r)).digest("hex")}function u(r,o){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("private-execution-descriptor-invalid");const t=r,e=t.binding,s=t.schemaVersion===2||t.schemaVersion===3,i=s?["schemaVersion","authorityKind","projectId","commandId","stepId",...t.schemaVersion===3?["claimId","epicId"]:["storyId"],"stateSnapshotSha256","generationId","inputSha256","hostKind","hostVersion"]:["commandId","generationId","graphRevision","hostKind","hostVersion","inputSha256","projectId","stepId"];if(Object.keys(t).sort().join(",")!==["schemaVersion","leaseId","materialSha256","byteLength","expiresAt","delivery","publicSafe","binding"].sort().join(",")||t.schemaVersion!==1&&!s||t.delivery!=="private-one-time"||t.publicSafe!==!0||typeof t.leaseId!="string"||!/^px_[a-f0-9]{48}$/.test(t.leaseId)||typeof t.materialSha256!="string"||!/^[a-f0-9]{64}$/.test(t.materialSha256)||!Number.isSafeInteger(t.byteLength)||t.byteLength<1||t.byteLength>256*1024||typeof t.expiresAt!="string"||!Number.isFinite(Date.parse(t.expiresAt))||!e||Object.keys(e).sort().join(",")!==i.sort().join(",")||Object.entries(e).some(([a,c])=>a!=="schemaVersion"&&(typeof c!="string"||c.length<1||c.length>256))||!/^[a-f0-9]{64}$/.test(String(e.inputSha256))||e.hostKind!=="codex-cli"||s&&!/^[a-f0-9]{64}$/.test(String(e.stateSnapshotSha256))||t.schemaVersion===2&&(e.schemaVersion!==2||e.authorityKind!=="state-snapshot"||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(String(e.storyId)))||t.schemaVersion===3&&(e.schemaVersion!==3||e.authorityKind!=="epic-claim"||e.commandId!=="create-epic"||!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(String(e.claimId))||!/^P[1-9][0-9]*$/.test(String(e.epicId)))||o&&Object.entries(o).some(([a,c])=>e[a]!==c))throw new Error("private-execution-descriptor-invalid");return t}function I(r,o,t=Date.now()){if(typeof o!="string"||t>=Date.parse(r.expiresAt)||Buffer.byteLength(o,"utf8")!==r.byteLength||m("sha256").update(o,"utf8").digest("hex")!==r.materialSha256)throw new Error("private-execution-material-invalid");return o}async function v(r,o,t,e=Date.now()){const s=u(r,o);if(e>=Date.parse(s.expiresAt))throw new Error("private-execution-material-expired");const i=await t({leaseId:s.leaseId,...s.binding});if(!i||typeof i!="object"||Array.isArray(i)||Object.keys(i).sort().join(",")!=="material,schemaVersion"||i.schemaVersion!==1)throw new Error("private-execution-delivery-invalid");return I(s,i.material,Math.max(e,Date.now()))}export{g as PRIVATE_EXECUTION_PUBLIC_INSTRUCTION_V1,v as consumePrivateExecutionDelivery,l as isPrivateExecutionPublicEnvelope,u as parsePrivateExecutionDescriptor,b as privateExecutionStateSnapshotSha256,I as verifyPrivateExecutionMaterial};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PrivateYoloIsolatedWorkspaceV1 } from './isolated-workspace.js';
|
|
2
2
|
export interface PrivateYoloIsolatedAdmissionV1 {
|
|
3
3
|
readonly schemaVersion: 1;
|
|
4
4
|
readonly outcome: 'admitted-unverified';
|
|
@@ -11,3 +11,11 @@ export interface PrivateYoloIsolatedAdmissionV1 {
|
|
|
11
11
|
export declare function verifyPrivateYoloSnapshotBoundary(workspace: PrivateYoloIsolatedWorkspaceV1, frozenPaths: readonly string[], snapshotSha: string): void;
|
|
12
12
|
/** Bind one-shot admission to the physically verified C01 claim and graph. */
|
|
13
13
|
export declare function admitPrivateYoloFrozenWorkspace(workspace: PrivateYoloIsolatedWorkspaceV1, storyId: string, graphRevision: string, snapshotSha?: string): Promise<PrivateYoloIsolatedAdmissionV1>;
|
|
14
|
+
/**
|
|
15
|
+
* Admit only a generated epic whose physical artifacts agree with the reserved
|
|
16
|
+
* epic ID. The claim is still unverified: this checks structure and write scope,
|
|
17
|
+
* not the quality of the agent's planning or story acceptance criteria.
|
|
18
|
+
*/
|
|
19
|
+
export declare function admitPrivateEpicClaimWorkspace(workspace: PrivateYoloIsolatedWorkspaceV1, claimId: string, epicId: string, logicalFingerprint: string, pendingSidecarSha256: string): PrivateYoloIsolatedAdmissionV1;
|
|
20
|
+
/** Admit a state-bound step without granting the agent direct source writes. */
|
|
21
|
+
export declare function admitPrivateStateBoundStepWorkspace(workspace: PrivateYoloIsolatedWorkspaceV1, storyId: string): PrivateYoloIsolatedAdmissionV1;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execFileSync as
|
|
2
|
-
`)])));if(
|
|
1
|
+
import{execFileSync as st,spawnSync as X}from"node:child_process";import{createHash as z}from"node:crypto";import{existsSync as nt,lstatSync as l,readFileSync as y,realpathSync as C}from"node:fs";import{isAbsolute as D,join as d,relative as j,sep as Z}from"node:path";import{isDeepStrictEqual as A}from"node:util";import{readPrivateYoloFrozenWriteSet as ct,verifyPrivateYoloCandidateWriteSet as at,verifyPrivateYoloCleanBaseline as ut}from"./clean-baseline.js";import{PRIVATE_EPIC_PENDING_SIDECAR as $}from"./isolated-workspace.js";const R=16*1024*1024,H=1024;function q(){const t={...process.env};for(const e 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 t[e];return t}function w(t,e){return st("git",[...e],{cwd:t,env:q(),stdio:["ignore","pipe","pipe"],timeout:3e4,maxBuffer:R})}function m(t,e){return w(t,e).toString("utf8").trim()}function S(t,e=!1){return w(t,["status","--porcelain=v1","-z","--untracked-files=all",...e?["--ignored=matching"]:[]])}function F(t){return!!t&&!D(t)&&!t.includes("\\")&&!t.includes("\0")&&!t.split("/").some(e=>!e||e==="."||e===".."||e===".git")}function x(t,e){const r=e.split("/");let o=t;for(const i of r.slice(0,-1)){o=d(o,i);try{const s=l(o);if(!s.isDirectory()||s.isSymbolicLink())throw new Error("path-boundary")}catch(s){if(s.code==="ENOENT")return;throw s}}try{const i=l(d(t,e));if(!i.isFile()||i.isSymbolicLink()||i.size>R)throw new Error("path-boundary")}catch(i){if(i.code!=="ENOENT")throw i}}function G(t,e=!1,r=!1){const o=[],i=[];for(const s of t.toString("utf8").split("\0").filter(Boolean)){if(s.length<4||s[2]!==" ")throw new Error("status-invalid");const n=s.slice(0,2),u=s.slice(3);if(!F(u)||n!=="??"&&n!==" M"&&n!==" D"&&!(r&&n==="!!"&&u===$))throw new Error("status-invalid");o.push(u),n==="??"&&i.push(u)}if(!e&&o.length===0||o.length>H||new Set(o).size!==o.length)throw new Error("status-invalid");return{paths:o.sort(),untracked:i.sort()}}function dt(t,e,r,o){const i=w(e,["ls-tree","-z",r,"--",o]).toString("utf8");if(!i)try{return l(d(t,o)),!1}catch(n){return n.code==="ENOENT"}const s=/^([0-7]{6}) blob [a-f0-9]{40,64}\t([^\0]+)\0$/.exec(i);if(!s||s[2]!==o||!["100644","100755"].includes(s[1]))return!1;try{const n=l(d(t,o));return!n.isFile()||n.isSymbolicLink()||n.size>R||!!(n.mode&73)!=(s[1]==="100755")?!1:y(d(t,o)).equals(w(e,["show",`${r}:${o}`]))}catch{return!1}}function M(t,e){try{const r=d(t,$),o=l(d(t,".neocortex")),i=l(r);return o.isDirectory()&&!o.isSymbolicLink()&&o.uid===process.getuid?.()&&(o.mode&18)===0&&i.isFile()&&!i.isSymbolicLink()&&i.uid===process.getuid?.()&&(i.mode&63)===0&&i.size>0&&i.size<=128*1024&&z("sha256").update(y(r)).digest("hex")===e}catch{return!1}}function W(t,e,r,o,i){const s=new Set(o),n=G(S(t),!0,!!i);return(!i||M(t,i))&&n.paths.every(u=>s.has(u)||u===$&&!!i&&M(t,i))&&o.every(u=>dt(t,e,r,u))}function ft(t,e){const r=X("git",["diff","--no-index","--binary","--no-ext-diff","--","/dev/null",e],{cwd:t,env:q(),encoding:"buffer",timeout:3e4,maxBuffer:R});if(r.error||r.status!==1||!Buffer.isBuffer(r.stdout)||r.stdout.byteLength===0)throw new Error("patch-invalid");return r.stdout}function K(t,e,r){const o=X("git",["apply",...r?["--check"]:[],"--binary","-"],{cwd:t,env:q(),input:e,encoding:"buffer",timeout:3e4,maxBuffer:R});if(o.error||o.status!==0)throw new Error("apply-failed")}function lt(t,e,r){const o=d(t,r),i=d(e,r);try{const s=l(o),n=l(i);return s.isFile()&&n.isFile()&&(s.mode&73)===(n.mode&73)&&y(o).equals(y(i))}catch(s){if(s.code!=="ENOENT")return!1;try{return l(o),!1}catch(n){if(n.code!=="ENOENT")return!1}try{return l(i),!1}catch(n){return n.code==="ENOENT"}}}function Tt(t,e,r){try{if(process.platform!=="linux"||t.schemaVersion!==1||!D(t.sourceRoot)||!D(t.workspacePath)||C(t.sourceRoot)!==t.sourceRoot||C(t.workspacePath)!==t.workspacePath||!l(t.workspacePath).isDirectory()||(l(t.workspacePath).mode&63)!==0||j(t.sourceRoot,t.workspacePath)===""||j(t.sourceRoot,t.workspacePath).split(Z)[0]!==".."||!/^[a-f0-9]{40,64}$/.test(t.baseSha)||!/^[a-f0-9]{40,64}$/.test(r)||m(t.sourceRoot,["rev-parse","--show-toplevel"])!==t.sourceRoot||m(t.workspacePath,["rev-parse","--show-toplevel"])!==t.workspacePath||m(t.sourceRoot,["rev-parse","HEAD"])!==t.baseSha||m(t.workspacePath,["rev-parse","HEAD"])!==r||m(t.sourceRoot,["symbolic-ref","--short","HEAD"])!==t.executionBranch||m(t.workspacePath,["symbolic-ref","--short","HEAD"])!==t.executionBranch||nt(d(t.workspacePath,".git","objects","info","alternates"))||S(t.workspacePath,!0).byteLength!==0||e.length===0||e.length>H||e.some(o=>!F(o))||new Set(e).size!==e.length)throw new Error("boundary-invalid");if(w(t.workspacePath,["merge-base","--is-ancestor",t.baseSha,r]),!W(t.sourceRoot,t.workspacePath,r,e))throw new Error("boundary-raced")}catch{throw new Error("private-execution-isolated-snapshot-unverified")}}function I(t,e,r,o){try{if(process.platform!=="linux"||t.schemaVersion!==1||!D(t.sourceRoot)||!D(t.workspacePath)||C(t.sourceRoot)!==t.sourceRoot||C(t.workspacePath)!==t.workspacePath||!l(t.workspacePath).isDirectory()||(l(t.workspacePath).mode&63)!==0||j(t.sourceRoot,t.workspacePath)===""||j(t.sourceRoot,t.workspacePath).split(Z)[0]!==".."||m(t.sourceRoot,["rev-parse","--show-toplevel"])!==t.sourceRoot||m(t.workspacePath,["rev-parse","--show-toplevel"])!==t.workspacePath||m(t.sourceRoot,["rev-parse","HEAD"])!==t.baseSha||!/^[a-f0-9]{40,64}$/.test(r)||m(t.workspacePath,["rev-parse","HEAD"])!==r||m(t.sourceRoot,["symbolic-ref","--short","HEAD"])!==t.executionBranch||m(t.workspacePath,["symbolic-ref","--short","HEAD"])!==t.executionBranch||e.length===0||e.length>H||e.some(c=>!F(c))||new Set(e).size!==e.length)throw new Error("authority-invalid");if(w(t.workspacePath,["merge-base","--is-ancestor",t.baseSha,r]),!W(t.sourceRoot,t.workspacePath,r,e,o))throw new Error("source-snapshot-mismatch");const i=S(t.workspacePath,!0),s=G(i),n=new Set(e);if(s.paths.some(c=>!n.has(c)))throw new Error("path-unclaimed");for(const c of s.paths)x(t.workspacePath,c),x(t.sourceRoot,c);const E=[w(t.workspacePath,["diff","--binary","--no-ext-diff","--no-textconv","HEAD","--"]),...s.untracked.map(c=>ft(t.workspacePath,c))],f=Buffer.concat(E.map(c=>Buffer.concat([c,Buffer.from(`
|
|
2
|
+
`)])));if(f.byteLength===0||f.byteLength>R||!S(t.workspacePath,!0).equals(i)||!W(t.sourceRoot,t.workspacePath,r,e,o))throw new Error("patch-raced");if(K(t.sourceRoot,f,!0),!S(t.workspacePath,!0).equals(i)||!W(t.sourceRoot,t.workspacePath,r,e,o))throw new Error("patch-raced");if(K(t.sourceRoot,f,!1),G(S(t.sourceRoot),!0,!!o).paths.some(c=>!n.has(c)&&c!==$)||o&&!M(t.sourceRoot,o)||e.some(c=>!lt(t.workspacePath,t.sourceRoot,c))||m(t.sourceRoot,["rev-parse","HEAD"])!==t.baseSha||m(t.sourceRoot,["symbolic-ref","--short","HEAD"])!==t.executionBranch)throw new Error("admission-raced");return Object.freeze({schemaVersion:1,outcome:"admitted-unverified",baseSha:t.baseSha,executionBranch:t.executionBranch,changedPaths:Object.freeze([...s.paths]),patchSha256:z("sha256").update(f).digest("hex")})}catch{throw new Error("private-execution-isolated-admission-unverified")}}async function Bt(t,e,r,o=t.baseSha){try{const i=await ct(t.sourceRoot,e,t.executionBranch,r),s=d(t.workspacePath,".neocortex","state.json"),n=l(s);if(!n.isFile()||n.isSymbolicLink()||n.size>R)throw new Error("candidate-state-invalid");at(y(s,"utf8"),e,i);const u=I(t,i,o);return await ut(t.sourceRoot,e,t.executionBranch,r),u}catch{throw new Error("private-execution-isolated-admission-unverified")}}function Dt(t,e,r,o,i){try{if(!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(e)||!/^P[1-9][0-9]*$/.test(r)||!/^[a-f0-9]{64}$/.test(o)||!/^[a-f0-9]{64}$/.test(i)||!M(t.sourceRoot,i))throw new Error("claim-invalid");const s=JSON.parse(y(d(t.sourceRoot,$),"utf8")),n=s&&typeof s=="object"&&!Array.isArray(s)?s.operations?.[o]:void 0;if(!n||typeof n!="object"||Array.isArray(n)||n.claimId!==e||n.epicId!==r)throw new Error("claim-sidecar-mismatch");const u=G(S(t.workspacePath,!0)),E=`docs/epics/epic-${r}.md`,f=".neocortex/state.json",v=new RegExp(`^docs/stories/${r}\\.[0-9]{2}\\.story\\.md$`),c=u.paths.filter(a=>v.test(a));if(!u.paths.includes(E)||!u.paths.includes(f)||c.length===0||c.length>99||u.paths.some(a=>a!==E&&a!==f&&a!=="NEOCORTEX.md"&&!v.test(a)))throw new Error("artifact-scope-invalid");const g=c.map(a=>a.slice(13,-9)).sort();if(g.some((a,h)=>a!==`${r}.${String(h+1).padStart(2,"0")}`))throw new Error("story-sequence-invalid");for(const a of[E,...c])try{throw l(d(t.sourceRoot,a)),new Error("artifact-already-exists")}catch(h){if(h.code!=="ENOENT")throw h}const N=(a,h)=>{x(t.workspacePath,a);const V=y(d(t.workspacePath,a),"utf8");return Buffer.byteLength(V)>R?null:/^---\r?\n([\s\S]{1,8192}?)\r?\n---(?:\r?\n|$)/.exec(V)?.[1]?.split(/\r?\n/).find(it=>it.startsWith(`${h}:`))?.slice(h.length+1).trim()?.replace(/^(["'])(.*)\1$/,"$2")??null};if(N(E,"id")!==r||c.some((a,h)=>N(a,"id")!==g[h]||N(a,"epic_id")!==r))throw new Error("artifact-id-invalid");x(t.workspacePath,f);const T=JSON.parse(y(d(t.workspacePath,f),"utf8"));if(!T||typeof T!="object"||Array.isArray(T))throw new Error("state-invalid");const b=T,Y=b.epics,L=b.stories,P=Y?.[r],O=b.epic_id_ledger;if(b.schema_version!==1||!P||P.id!==r||P.status!=="memory-updated"||!Array.isArray(P.stories)||P.stories.length!==g.length||P.stories.some((a,h)=>a!==g[h])||!L||g.some(a=>{const h=L[a];return!h||h.id!==a||h.epic_id!==r})||!O||!Array.isArray(O.reserved_ids)||!O.reserved_ids.includes(r))throw new Error("state-claim-mismatch");x(t.sourceRoot,f);const _=JSON.parse(y(d(t.sourceRoot,f),"utf8")),B=_.epics,p=_.stories;if(!B||!p||B[r]!==void 0||g.some(a=>p[a]!==void 0))throw new Error("state-claim-conflict");const{[r]:ht,...Q}=Y,U={...L};for(const a of g)delete U[a];const{epic_id_ledger:mt,last_updated:yt,...k}=_,{epic_id_ledger:Et,last_updated:_t,...tt}=b;if(!A(Q,B)||!A(U,p)||!A({...tt,epics:void 0,stories:void 0},{...k,epics:void 0,stories:void 0}))throw new Error("state-unrelated-drift");const J=_.epic_id_ledger&&typeof _.epic_id_ledger=="object"?_.epic_id_ledger.reserved_ids:void 0,{reserved_ids:vt,...et}=O,rt=_.epic_id_ledger&&typeof _.epic_id_ledger=="object"?_.epic_id_ledger:{schema_version:1},{reserved_ids:gt,...ot}=rt;if(J!==void 0&&(!Array.isArray(J)||J.some(a=>!O.reserved_ids.includes(a)))||!A(et,ot))throw new Error("ledger-drift");return I(t,u.paths,t.baseSha,i)}catch{throw new Error("private-execution-epic-claim-admission-unverified")}}function $t(t,e){try{if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(e))throw new Error("story-id-invalid");const r=".neocortex/state.json";x(t.sourceRoot,r),x(t.workspacePath,r);const o=JSON.parse(y(d(t.sourceRoot,r),"utf8")),i=JSON.parse(y(d(t.workspacePath,r),"utf8"));if(!o||typeof o!="object"||Array.isArray(o)||!i||typeof i!="object"||Array.isArray(i))throw new Error("state-invalid");const s=o,n=i,u=s.stories,E=n.stories,f=u?.[e],v=E?.[e],c=f?.files_to_modify;if(s.schema_version!==1||n.schema_version!==1||!u||!E||!f||!v||f.id!==e||v.id!==e||v.epic_id!==f.epic_id||!Array.isArray(c)||c.length===0||c.length>H||c.some(p=>typeof p!="string"||!F(p)||p.length>1024)||new Set(c).size!==c.length||!A(v.files_to_modify,c))throw new Error("write-set-invalid");const{[e]:g,...N}=u,{[e]:T,...b}=E,{stories:Y,last_updated:L,...P}=s,{stories:O,last_updated:_,...B}=n;if(!A(b,N)||!A(B,P))throw new Error("state-unrelated-drift");return I(t,[...c].sort(),t.baseSha)}catch{throw new Error("private-execution-state-step-admission-unverified")}}export{Dt as admitPrivateEpicClaimWorkspace,$t as admitPrivateStateBoundStepWorkspace,Bt as admitPrivateYoloFrozenWorkspace,Tt as verifyPrivateYoloSnapshotBoundary};
|
|
@@ -5,9 +5,10 @@ export interface PrivateYoloIsolatedWorkspaceV1 {
|
|
|
5
5
|
readonly baseSha: string;
|
|
6
6
|
readonly executionBranch: string;
|
|
7
7
|
}
|
|
8
|
+
export declare const PRIVATE_EPIC_PENDING_SIDECAR = ".neocortex/pending-epic-claims.json";
|
|
8
9
|
/**
|
|
9
10
|
* Build a separate object store and index from a clean, committed checkout.
|
|
10
11
|
* The caller must retain the workspace until its bytes are independently
|
|
11
12
|
* admitted into the root; this function never stages, commits, or deletes it.
|
|
12
13
|
*/
|
|
13
|
-
export declare function preparePrivateYoloIsolatedWorkspace(projectRoot: string, workspaceParent: string): PrivateYoloIsolatedWorkspaceV1;
|
|
14
|
+
export declare function preparePrivateYoloIsolatedWorkspace(projectRoot: string, workspaceParent: string, allowPendingEpicSidecar?: boolean): PrivateYoloIsolatedWorkspaceV1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as
|
|
1
|
+
import{execFileSync as I}from"node:child_process";import{chmodSync as d,existsSync as _,lstatSync as p,mkdtempSync as D,realpathSync as f}from"node:fs";import{isAbsolute as E,join as l,resolve as h}from"node:path";const m=".neocortex/pending-epic-claims.json";function u(r,n){const c={...process.env};for(const e 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 c[e];return I("git",[...n],{cwd:r,env:c,stdio:["ignore","pipe","pipe"],timeout:3e4,maxBuffer:16*1024*1024})}function a(r,n){return u(r,n).toString("utf8").trim()}function y(r,n,c,e=!1){const i=u(r,["status","--porcelain=v1","-z","--untracked-files=all"]).toString("utf8");let s=!e;if(e)try{const o=p(l(r,".neocortex")),t=p(l(r,m));s=o.isDirectory()&&!o.isSymbolicLink()&&o.uid===process.getuid?.()&&(o.mode&18)===0&&t.isFile()&&!t.isSymbolicLink()&&t.uid===process.getuid?.()&&(t.mode&63)===0&&t.size>0&&t.size<=128*1024}catch{s=!1}return a(r,["rev-parse","HEAD"])===n&&a(r,["symbolic-ref","--quiet","--short","HEAD"])===c&&s&&(i.length===0||e&&i===`?? ${m}\0`)}function R(r,n,c=!1){let e,i;try{if(process.platform!=="linux"||typeof process.getuid!="function"||!E(r)||!E(n))throw new Error("path-invalid");if(e=h(r),i=h(n),f(e)!==e||!p(e).isDirectory()||f(i)!==i||!p(i).isDirectory()||p(i).uid!==process.getuid()||(p(i).mode&18)!==0||a(e,["rev-parse","--show-toplevel"])!==e)throw new Error("path-invalid");const s=a(e,["rev-parse","HEAD"]),o=a(e,["symbolic-ref","--quiet","--short","HEAD"]);if(!/^[a-f0-9]{40,64}$/.test(s)||!o||!y(e,s,o,c))throw new Error("source-dirty");const t=D(l(i,"p222-private-yolo-"));if(d(t,448),u(t,["init","-q"]),u(t,["fetch","-q","--no-tags","--depth=1",e,s]),u(t,["checkout","-q","-b",o,"FETCH_HEAD"]),!y(e,s,o,c)||a(t,["rev-parse","HEAD"])!==s||a(t,["symbolic-ref","--quiet","--short","HEAD"])!==o||u(t,["status","--porcelain=v1","-z","--untracked-files=all"]).byteLength!==0||_(l(t,".git","objects","info","alternates")))throw new Error("physical-mismatch");return Object.freeze({schemaVersion:1,sourceRoot:e,workspacePath:t,baseSha:s,executionBranch:o})}catch{throw new Error("private-execution-isolated-workspace-unverified")}}export{m as PRIVATE_EPIC_PENDING_SIDECAR,R as preparePrivateYoloIsolatedWorkspace};
|
|
@@ -27,7 +27,7 @@ export type YoloopSessionMode = 'directory' | 'epic-file' | 'epic-id';
|
|
|
27
27
|
export type YoloopLockOwnerKind = 'client' | 'server';
|
|
28
28
|
export type YoloopLockOwnerPidState = 'live' | 'stale' | 'unknown';
|
|
29
29
|
export type YoloopLockLeaseState = 'active' | 'expired' | 'unknown';
|
|
30
|
-
export type YoloopPersistenceCapability = 'rollover-session-v1' | 'successor-transition-v1';
|
|
30
|
+
export type YoloopPersistenceCapability = 'rollover-session-v1' | 'successor-transition-v1' | 'continuation-replan-v1';
|
|
31
31
|
/** Lock file payload. Mirrors server-internal `LockMetadata` (v1.1 schema). */
|
|
32
32
|
export interface YoloopPersistedLock {
|
|
33
33
|
readonly pid: number;
|
|
@@ -226,6 +226,8 @@ export interface YoloopPersistedCounters {
|
|
|
226
226
|
readonly pendingContinuationAuthorities?: readonly Readonly<Record<string, unknown>>[];
|
|
227
227
|
readonly continuationReceipts?: readonly Readonly<Record<string, unknown>>[];
|
|
228
228
|
readonly continuationRecoveryReceipts?: readonly Readonly<Record<string, unknown>>[];
|
|
229
|
+
/** Auditable retirement of an undelegated authority when an explicit new run changes the graph. */
|
|
230
|
+
readonly continuationReplanReceipts?: readonly Readonly<Record<string, unknown>>[];
|
|
229
231
|
/**
|
|
230
232
|
* P104.06: FIFO bounded audit trail of self-healing recovery attempts.
|
|
231
233
|
* Optional for backward compat (clients pre-P104.06 omit the field; readers
|
|
@@ -336,6 +338,18 @@ export type YoloopStateOperation = {
|
|
|
336
338
|
readonly payloadHash: string;
|
|
337
339
|
readonly next: YoloopPersistedCounters;
|
|
338
340
|
readonly receipt: YoloopSessionRolloverReceiptV1;
|
|
341
|
+
} | {
|
|
342
|
+
readonly type: 'replan_continuation_session';
|
|
343
|
+
readonly operationId: string;
|
|
344
|
+
readonly idempotencyKey: string;
|
|
345
|
+
readonly expectedRunId: string;
|
|
346
|
+
readonly expectedRevision: number;
|
|
347
|
+
readonly expectedSnapshotHash: string | null;
|
|
348
|
+
readonly expectedSessionHash: string;
|
|
349
|
+
readonly expectedPendingHash: string;
|
|
350
|
+
readonly nextSession: Readonly<Record<string, unknown>>;
|
|
351
|
+
readonly payloadHash: string;
|
|
352
|
+
readonly receipt: Readonly<Record<string, unknown>>;
|
|
339
353
|
} | {
|
|
340
354
|
readonly type: 'recovery_attempted';
|
|
341
355
|
readonly attempt: YoloopRecoveryAttemptRef;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* setSecureFilePermissions helper from secure-config.ts.
|
|
24
24
|
*/
|
|
25
25
|
import type { YoloopPersistedCounters, YoloopPersistedState, YoloopRecoveryAttemptRef, YoloopRunControlV1, YoloopRunTransitionReceiptV1, YoloopStateOperation, YoloopStateUpdate } from './shared-yoloop-types.js';
|
|
26
|
-
export declare const YOLOOP_PERSISTENCE_CAPABILITIES: readonly ["rollover-session-v1", "successor-transition-v1"];
|
|
26
|
+
export declare const YOLOOP_PERSISTENCE_CAPABILITIES: readonly ["rollover-session-v1", "successor-transition-v1", "continuation-replan-v1"];
|
|
27
27
|
type YoloopSessionRolloverOperation = Extract<YoloopStateOperation, {
|
|
28
28
|
readonly type: 'rollover_session';
|
|
29
29
|
}>;
|
|
@@ -82,6 +82,7 @@ export declare class YoloopClientStateStore {
|
|
|
82
82
|
private acknowledgeContinuationAuthority;
|
|
83
83
|
private repairContinuationAuthority;
|
|
84
84
|
private switchContinuationPolicy;
|
|
85
|
+
private replanContinuationSession;
|
|
85
86
|
/**
|
|
86
87
|
* Append a new recovery attempt to `state.recovery_history[]`. FIFO cap
|
|
87
88
|
* via `capRecoveryHistory`. Idempotent against retry storms: duplicate
|
|
@@ -168,6 +169,9 @@ export declare class YoloopClientStateStore {
|
|
|
168
169
|
/** Remove `yoloop-state.json.tmp.*` orphans from crashed writes. */
|
|
169
170
|
private cleanupOrphanTempFiles;
|
|
170
171
|
}
|
|
172
|
+
export declare function buildYoloopContinuationReplanPayloadHash(payload: Omit<Extract<YoloopStateOperation, {
|
|
173
|
+
readonly type: 'replan_continuation_session';
|
|
174
|
+
}>, 'type' | 'payloadHash' | 'receipt'>): string;
|
|
171
175
|
export declare function fingerprintYoloopSession(session: NonNullable<YoloopPersistedCounters['currentSession']>): string;
|
|
172
176
|
export declare function buildYoloopSessionRolloverPayloadHash(operation: Omit<YoloopSessionRolloverOperation, 'type' | 'payloadHash' | 'receipt'>): string;
|
|
173
177
|
export declare function buildYoloopSuccessorRunPayloadHash(operation: Omit<Extract<YoloopStateOperation, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{promises as u}from"node:fs";import{createHash as b}from"node:crypto";import{join as _,dirname as V}from"node:path";import{hostname as S}from"node:os";import{setSecureFilePermissions as $,setSecureDirPermissions as q}from"../config/secure-config.js";import{RECOVERY_HISTORY_CAP as C}from"./shared-yoloop-types.js";const B=".neocortex",g="yoloop-state.json",j="yoloop.lock",J="yoloop-state.mutation.lock",P="yoloop-session-rollover.json",A="yoloop-successor-transition.json",z=360*60*1e3,W=3e4,G=200,x=Object.freeze(["rollover-session-v1","successor-transition-v1"]),X={warn:()=>{},info:()=>{},error:()=>{}};function w(t){const e=t.slice(0,10);return{version:"1.1",lastResetAt:t,storiesRunToday:0,iterationsToday:0,iterationsTodayDate:e,tokensUsedToday:0,lastRunAt:null,coolDownUntil:null,totalRunsAllTime:0,totalStoriesAllTime:0,currentSession:null,continuationPolicy:"p205-finite-resume-v2",pendingContinuationAuthorities:[],continuationReceipts:[],continuationRecoveryReceipts:[]}}function we(t){return{lock:null,state:w(t),capabilities:x}}class fe{stateDir;statePath;lockPath;mutationLockPath;rolloverManifestPath;successorTransitionManifestPath;logger;constructor(e,s=X){this.stateDir=_(e,B),this.statePath=_(this.stateDir,g),this.lockPath=_(this.stateDir,j),this.mutationLockPath=_(this.stateDir,J),this.rolloverManifestPath=_(this.stateDir,P),this.successorTransitionManifestPath=_(this.stateDir,A),this.logger=s}async readAll(e){const s=e??new Date().toISOString();await this.cleanupOrphanTempFiles(),await this.recoverSessionRolloverIfPresent(s),await this.recoverSuccessorTransitionIfPresent(s);const[n,r]=await Promise.all([this.readLock(),this.readState(s)]);return{lock:await this.prepareLockForSnapshot(n,s),state:r,capabilities:x}}async applyUpdate(e,s){const n=s??new Date().toISOString();await this.ensureDir(),await this.recoverSessionRolloverIfPresent(n),await this.recoverSuccessorTransitionIfPresent(n);for(const r of e.operations)await this.applyOperation(r,n)}async requestRunTransition(e,s){const n=s??new Date().toISOString();return await this.ensureDir(),this.withMutationLock(()=>this.transitionRun(e,n))}async requestLifecycleAction(e,s={},n){const r=n??new Date().toISOString();return await this.ensureDir(),this.withMutationLock(async()=>{const i=(await this.readState(r)).runControl;if(!i)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");const a=Date.parse(r).toString(36),c=s.operationId??`op-${e}-${a}`,l=s.idempotencyKey??`idem-${e}-${a}`,h=i.receipts.find(O=>O.operationId===c||O.idempotencyKey===l);if(h){if(h.operationId===c&&h.idempotencyKey===l)return h;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}const y=ae(i.status,e);if(!y)throw new Error(E.has(i.status)?"YOLOOP_RUN_TERMINAL":"YOLOOP_RUN_TRANSITION_INVALID");return this.transitionRun(ce({current:i,action:e,target:y,operationId:c,idempotencyKey:l,occurredAt:r}),r)})}async applyOperation(e,s){switch(e.type){case"acquire_lock":await this.acquireLock(e.lock,s);return;case"release_lock":await this.releaseLock(e);return;case"write_state":await this.withMutationLock(async()=>{const n=await this.readState(s),{runControl:r,...o}=e.state;await this.writeState({...o,...n.runControl?{version:"1.2",runControl:n.runControl}:{}})});return;case"advance_epic":await this.advanceEpic(e.nextEpicIndex,e.nextEpicId,s);return;case"no_op":this.logger.info({event:"yoloop_noop"},"yoloop server sent no-op");return;case"reserve_continuation_authority":await this.reserveContinuationAuthority(e.authority,s);return;case"acknowledge_continuation_authority":await this.acknowledgeContinuationAuthority(e.idempotencyKey,e.receipt,s);return;case"repair_continuation_authority":await this.repairContinuationAuthority(e.beforeHash,e.authority,e.receipt,s);return;case"switch_continuation_policy":await this.switchContinuationPolicy(e.policy,e.session,s);return;case"transition_run":await this.requestRunTransition(e,s);return;case"start_successor_run":await this.withMutationLock(()=>this.startSuccessorRun(e,s));return;case"commit_successor_transition":await this.withMutationLock(()=>this.commitSuccessorTransition(e,s));return;case"rollover_session":await this.withMutationLock(()=>this.rolloverSession(e,s));return;case"recovery_attempted":await this.appendRecoveryAttempt(e.attempt,s);return;case"recovery_resolved":await this.resolveRecoveryAttempt(e.attempt_id,e.outcome,s);return;default:{const n=e;throw this.logger.error({event:"yoloop_unknown_op",op:n},"unknown yoloop operation rejected"),new Error("YOLOOP_STATE_OPERATION_UNSUPPORTED")}}}async reserveContinuationAuthority(e,s){const n=await this.readState(s),r=n.pendingContinuationAuthorities??[],o=typeof e.idempotencyKey=="string"?e.idempotencyKey:"";if(!o)throw new Error("YOLOOP_CONTINUATION_AUTHORITY_INVALID");const i=r.find(a=>a.idempotencyKey===o);if(i){if(d(i)===d(e))return;throw new Error("YOLOOP_CONTINUATION_AUTHORITY_CONFLICT")}if(r.length>=64)throw new Error("YOLOOP_PENDING_AUTHORITY_CAPACITY_EXCEEDED");await this.writeState({...n,pendingContinuationAuthorities:[...r,e]})}async acknowledgeContinuationAuthority(e,s,n){const r=await this.readState(n),o=r.pendingContinuationAuthorities??[],i=o.findIndex(h=>h.idempotencyKey===e);if(i<0)throw new Error("YOLOOP_CONTINUATION_RECEIPT_ORPHAN");const a=o[i];if(s.idempotencyKey!==e||s.sessionId!==a.sessionId||JSON.stringify(s.storyIds)!==JSON.stringify(a.storyIds))throw new Error("YOLOOP_CONTINUATION_RECEIPT_MISMATCH");const c=o.filter((h,y)=>y!==i),l=r.continuationReceipts??[];await this.writeState({...r,pendingContinuationAuthorities:c,continuationReceipts:[...l.slice(-63),s]})}async repairContinuationAuthority(e,s,n,r){const o=await this.readState(r),i=o.pendingContinuationAuthorities??[],a=o.continuationRecoveryReceipts??[],c=typeof n.idempotencyKey=="string"?n.idempotencyKey:"",l=a.find(O=>O.idempotencyKey===c);if(l){if(d(l)===d(n))return;throw new Error("YOLOOP_CONTINUATION_RECOVERY_RECEIPT_CONFLICT")}if(i.length!==1||p("p208-legacy-authority-before-v1",i[0])!==e)throw new Error("YOLOOP_CONTINUATION_RECOVERY_BEFORE_MISMATCH");const h=p("p208-legacy-authority-after-v1",s);if(n.beforeHash!==e||n.afterHash!==h)throw new Error("YOLOOP_CONTINUATION_RECOVERY_HASH_MISMATCH");const y={...n};if(delete y.idempotencyKey,!c||p("p208-legacy-authority-recovery-receipt-v1",y)!==c)throw new Error("YOLOOP_CONTINUATION_RECOVERY_RECEIPT_INVALID");await this.writeState({...o,pendingContinuationAuthorities:[s],continuationRecoveryReceipts:[...a.slice(-63),n]})}async switchContinuationPolicy(e,s,n){const r=await this.readState(n);if(r.currentSession||(r.pendingContinuationAuthorities?.length??0)>0)throw new Error("YOLOOP_POLICY_SWITCH_ACTIVE");try{await u.copyFile(this.statePath,`${this.statePath}.policy-backup`)}catch(o){if(o.code!=="ENOENT")throw o}await this.writeState({...r,continuationPolicy:e,continuationSession:s})}async appendRecoveryAttempt(e,s){const n=await this.readState(s),r=n.recovery_history??[];if(r.some(c=>c.attempted_at===e.attempted_at&&c.story_id===e.story_id)){this.logger.warn({event:"recovery_attempted_duplicate",story_id:e.story_id},"duplicate recovery_attempted op; skipping");return}const i=K([...r,e]),a={...n,recovery_history:i};await this.writeState(a),this.logger.info({event:"recovery_attempted_persisted",story_id:e.story_id,history_size:i.length},"recovery attempt persisted")}async resolveRecoveryAttempt(e,s,n){const r=await this.readState(n),o=r.recovery_history??[],i=o.findIndex(h=>h.recovery_step_id_tokenized===e);if(i===-1){this.logger.warn({event:"recovery_resolve_orphan",attempt_id:e},"recovery_resolved op had no matching attempt; skipping");return}const a=o[i];if(a.outcome===s&&a.finished_at){this.logger.info({event:"recovery_resolved_duplicate",attempt_id:e,outcome:s},"duplicate recovery_resolved op; skipping");return}const c=o.slice();c[i]={...a,outcome:s,finished_at:n};const l={...r,recovery_history:c};await this.writeState(l),this.logger.info({event:"recovery_resolved_persisted",attempt_id:e,outcome:s},"recovery attempt resolved")}async acquireLock(e,s){const n={...e,pid:process.pid,hostname:S(),ownerKind:"client",startedAt:e.startedAt||s,leaseId:e.leaseId??le(e.sessionId,s),leaseState:"active",leaseAcquiredAt:e.leaseAcquiredAt??s,leaseDurationMs:e.leaseDurationMs??z,leaseExpiresAt:e.leaseExpiresAt??e.ttlExpiresAt},r=JSON.stringify(n,null,2);try{const o=await u.open(this.lockPath,"wx");try{await o.writeFile(r,"utf8")}finally{await o.close()}this.trySetFilePerms(this.lockPath),this.logger.info({event:"yoloop_lock_acquired",pid:n.pid,sessionId:n.sessionId},"yoloop lock acquired");return}catch(o){const i=o;if(i.code!=="EEXIST")throw this.logger.error({event:"yoloop_lock_acquire_error",err:i.message},"failed to acquire yoloop lock"),o;const a=await this.readLock();if(a&&this.isSameClientSessionLock(a,n)){this.logger.info({event:"yoloop_lock_acquire_duplicate",sessionId:n.sessionId},"duplicate acquire_lock for current yoloop session; treating as no-op");return}if(!await this.maybeRecoverOrphanLock(s))throw this.logger.warn({event:"yoloop_lock_held"},"yoloop lock held by another live process"),o;const l=await u.open(this.lockPath,"wx");try{await l.writeFile(r,"utf8")}finally{await l.close()}this.trySetFilePerms(this.lockPath),this.logger.info({event:"yoloop_lock_acquired_after_recovery",pid:n.pid},"yoloop lock acquired after orphan recovery")}}async releaseLock(e){const s=await this.readState(new Date().toISOString()),n=await this.readLock();if(s.runControl){if(!e.expectedRunId||!e.expectedSessionId||!e.expectedLeaseId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(e.expectedRunId!==s.runControl.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(!n||e.expectedSessionId!==n.sessionId||e.expectedLeaseId!==n.leaseId)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}try{await u.unlink(this.lockPath),this.logger.info({event:"yoloop_lock_released"},"yoloop lock released")}catch(r){const o=r;if(o.code==="ENOENT"){this.logger.info({event:"yoloop_lock_release_noop"},"yoloop lock release noop (file absent)");return}this.logger.warn({event:"yoloop_lock_release_error",err:o.message},"unexpected error releasing yoloop lock")}}async readLock(){try{const e=await u.readFile(this.lockPath,"utf8"),s=JSON.parse(e),n=s.currentEpicId??s.epicId??"";return{pid:s.pid??0,hostname:s.hostname??"",...s.ownerKind?{ownerKind:s.ownerKind}:{},...s.ownerPidState?{ownerPidState:s.ownerPidState}:{},...typeof s.leaseId=="string"?{leaseId:s.leaseId}:{},...s.leaseState?{leaseState:s.leaseState}:{},...typeof s.leaseAcquiredAt=="string"?{leaseAcquiredAt:s.leaseAcquiredAt}:{},...typeof s.leaseDurationMs=="number"?{leaseDurationMs:s.leaseDurationMs}:{},...typeof s.leaseExpiresAt=="string"?{leaseExpiresAt:s.leaseExpiresAt}:{},startedAt:s.startedAt??"",sessionId:s.sessionId??"",mode:s.mode??"epic-id",inputPath:s.inputPath??"",epicQueue:s.epicQueue??(n?[n]:[]),currentEpicIndex:s.currentEpicIndex??0,currentEpicId:n,ttlExpiresAt:s.ttlExpiresAt??"",epicId:s.epicId??n}}catch{return null}}async readState(e){try{const s=await u.readFile(this.statePath,"utf8"),n=JSON.parse(s);return he(n,e)}catch(s){const n=s;return n.code!=="ENOENT"&&this.logger.warn({event:"yoloop_state_read_error",err:n.message},"yoloop state file unreadable; using defaults"),w(e)}}async writeState(e){const s=`${this.statePath}.tmp.${process.pid}.${Date.now()}`,n=JSON.stringify(e,null,2);try{const r=await u.open(s,"w",384);try{await r.writeFile(n,"utf8"),await r.sync()}finally{await r.close()}this.trySetFilePerms(s),await u.rename(s,this.statePath),await this.syncStateDirectory()}catch(r){const o=r;this.logger.error({event:"yoloop_state_write_error",err:o.message},"failed to write yoloop state");try{await u.unlink(s)}catch{}throw r}}async rolloverSession(e,s){v(e);const n=await this.readRolloverManifest();if(n){if(oe(n.operation,e)){if(n.operation.payloadHash!==e.payloadHash)throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT");if(n.phase==="applied")return;await this.completePreparedSessionRollover(n.operation,s);return}else if(n.phase==="prepared")throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT")}const r=await this.readState(s),o=await this.readLock();H(e,r,o),await this.writeRolloverManifest({schemaVersion:"YoloopSessionRolloverManifest/1.0",phase:"prepared",operation:e}),await this.completePreparedSessionRollover(e,s)}async completePreparedSessionRollover(e,s){const n=await this.readState(s);let r=d(n)===d(e.next);if(!r){const i=await this.readLock();H(e,n,i),await this.writeState(e.next),r=!0}const o=await this.readLock();if(e.expectedSessionId===null||e.expectedLeaseId===null){if(e.expectedSessionId!==null||e.expectedLeaseId!==null||o)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}else if(o){if(o.sessionId!==e.expectedSessionId||o.leaseId!==e.expectedLeaseId)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");await u.unlink(this.lockPath),await this.syncStateDirectory()}else if(!r)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");await this.writeRolloverManifest({schemaVersion:"YoloopSessionRolloverManifest/1.0",phase:"applied",operation:e}),this.logger.info({event:"yoloop_session_rollover_applied",runId:e.runId,operationId:e.operationId,coolDownUntil:e.coolDownUntil},"yoloop per-run-cap session rollover applied")}async recoverSessionRolloverIfPresent(e){try{await u.access(this.rolloverManifestPath)}catch(s){if(s.code==="ENOENT")return;throw s}await this.ensureDir(),await this.withMutationLock(async()=>{const s=await this.readRolloverManifest();s?.phase==="prepared"&&await this.completePreparedSessionRollover(s.operation,e)})}async readRolloverManifest(){try{const e=JSON.parse(await u.readFile(this.rolloverManifestPath,"utf8"));if(e.schemaVersion!=="YoloopSessionRolloverManifest/1.0"||e.phase!=="prepared"&&e.phase!=="applied"||!e.operation||e.operation.type!=="rollover_session")throw new Error("YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT");return v(e.operation),e}catch(e){if(e.code==="ENOENT")return null;throw e.message==="YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT"?e:new Error("YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT")}}async writeRolloverManifest(e){const s=`${this.rolloverManifestPath}.tmp.${process.pid}.${Date.now()}`,n=await u.open(s,"w",384);try{await n.writeFile(JSON.stringify(e,null,2),"utf8"),await n.sync()}finally{await n.close()}this.trySetFilePerms(s),await u.rename(s,this.rolloverManifestPath),await this.syncStateDirectory()}async commitSuccessorTransition(e,s){f(e);const n=await this.readSuccessorTransitionManifest();if(n){if(se(n.operation,e)){if(n.operation.payloadHash!==e.payloadHash)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT");if(n.phase==="applied")return;await this.completePreparedSuccessorTransition(n.operation,s);return}if(n.phase==="prepared")throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT")}const r=await this.readState(s);if(R(e,r)){await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"applied",operation:e});return}k(e,r),await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"prepared",operation:e}),await this.completePreparedSuccessorTransition(e,s)}async completePreparedSuccessorTransition(e,s){let n=await this.readState(s);if(!R(e,n)){d(n.runControl)===d(e.successor.next)||(await this.startSuccessorRun(e.successor,s),n=await this.readState(s));const o=re(e,n);await this.writeState(o),n=await this.readState(s)}if(!R(e,n))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_STATE_CONFLICT");await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"applied",operation:e}),this.logger.info({event:"yoloop_successor_transition_applied",runId:e.successor.runId,operationId:e.operationId},"yoloop successor transition applied")}async recoverSuccessorTransitionIfPresent(e){try{await u.access(this.successorTransitionManifestPath)}catch(s){if(s.code==="ENOENT")return;throw s}await this.ensureDir(),await this.withMutationLock(async()=>{const s=await this.readSuccessorTransitionManifest();s?.phase==="prepared"&&await this.completePreparedSuccessorTransition(s.operation,e)})}async readSuccessorTransitionManifest(){try{const e=JSON.parse(await u.readFile(this.successorTransitionManifestPath,"utf8"));if(e.schemaVersion!=="YoloopSuccessorTransitionManifest/1.0"||e.phase!=="prepared"&&e.phase!=="applied"||!e.operation||e.operation.type!=="commit_successor_transition")throw new Error("YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT");return f(e.operation),e}catch(e){if(e.code==="ENOENT")return null;throw e.message==="YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT"?e:new Error("YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT")}}async writeSuccessorTransitionManifest(e){const s=`${this.successorTransitionManifestPath}.tmp.${process.pid}.${Date.now()}`,n=await u.open(s,"w",384);try{await n.writeFile(JSON.stringify(e,null,2),"utf8"),await n.sync()}finally{await n.close()}this.trySetFilePerms(s),await u.rename(s,this.successorTransitionManifestPath),await this.syncStateDirectory()}async advanceEpic(e,s,n){const r=await this.readState(n);if(!r.currentSession){this.logger.warn({event:"yoloop_advance_no_session",nextEpicId:s},"advance_epic with no active session; skipping");return}const o={...r,currentSession:{...r.currentSession,currentEpicIndex:e}};await this.writeState(o),this.logger.info({event:"yoloop_epic_advance",nextEpicId:s,nextIndex:e},"yoloop advanced to next epic")}async ensureDir(){try{await u.mkdir(this.stateDir,{recursive:!0}),this.trySetDirPerms(this.stateDir)}catch(e){const s=e;throw this.logger.error({event:"yoloop_mkdir_error",err:s.message,path:this.stateDir},"failed to ensure .neocortex/ directory"),e}}async syncStateDirectory(){try{const e=await u.open(this.stateDir,"r");try{await e.sync()}finally{await e.close()}}catch(e){const s=e.code;if(s!=="EINVAL"&&s!=="EISDIR"&&s!=="ENOTSUP"&&s!=="EPERM")throw e}}async withMutationLock(e){let s=null;for(let n=0;n<G;n+=1)try{s=await u.open(this.mutationLockPath,"wx",384),await s.writeFile(JSON.stringify({pid:process.pid,acquiredAt:new Date().toISOString()})),await s.sync();break}catch(r){if(r.code!=="EEXIST")throw r;try{const o=await u.stat(this.mutationLockPath);if(Date.now()-o.mtimeMs>W){await u.unlink(this.mutationLockPath);continue}}catch{continue}await new Promise(o=>setTimeout(o,5))}if(!s)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");try{return await e()}finally{await s.close().catch(()=>{}),await u.unlink(this.mutationLockPath).catch(()=>{})}}async transitionRun(e,s){T(e);const n=await this.readState(s),r=n.runControl,o=r?.receipts.find(l=>l.operationId===e.operationId||l.idempotencyKey===e.idempotencyKey);if(o){if(o.operationId===e.operationId&&o.idempotencyKey===e.idempotencyKey&&o.payloadHash===e.payloadHash)return o;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}if(r&&r.runId!==e.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if((r?.revision??0)!==e.expectedRevision)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if((r?.latestSnapshotHash??null)!==e.expectedSnapshotHash)throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT");L(r,e);const c=e.next.receipts.at(-1);if(!c)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT");return await this.writeState({...n,version:"1.2",runControl:e.next}),this.logger.info({event:"yoloop_run_transition_committed",runId:e.runId,operationId:e.operationId,revision:c.revision,status:c.status},"yoloop run transition committed"),c}async startSuccessorRun(e,s){Y(e);const n=await this.readState(s),r=n.runControl,o={schemaVersion:"YoloopRunPredecessor/1.0",runId:e.previousRunId,revision:e.expectedRevision,snapshotHash:e.expectedSnapshotHash,successorOperationId:e.operationId,publicSafe:!0},i=r?.receipts.find(l=>l.operationId===e.operationId||l.idempotencyKey===e.idempotencyKey);if(i){if(i.operationId===e.operationId&&i.idempotencyKey===e.idempotencyKey&&e.next.receipts.at(-1)?.payloadHash===i.payloadHash&&d(r?.predecessor)===d(o))return i;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}if(!r||r.runId!==e.previousRunId||!["exhausted","success"].includes(r.status)||r.revision!==e.expectedRevision||r.latestSnapshotHash!==e.expectedSnapshotHash||n.currentSession!==null)throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT");const a=e.next.receipts.at(-1);if(!a||d(e.next.predecessor)!==d(o))throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT");const c={type:"transition_run",runId:e.runId,operationId:e.operationId,idempotencyKey:e.idempotencyKey,expectedRevision:0,expectedSnapshotHash:null,payloadHash:a.payloadHash,next:e.next};return T(c),L(void 0,c),await this.writeState({...n,version:"1.2",runControl:e.next}),a}trySetFilePerms(e){try{$(e)}catch{}}trySetDirPerms(e){try{q(e)}catch{}}async prepareLockForSnapshot(e,s){if(!e)return null;if(e.ownerKind!=="client")return e;const n=F(e,s),r={...e,leaseState:n};if(n==="expired")return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"lease_expired"},"expired client-owned yoloop lock lease recovered before snapshot echo"),null;if(!r.pid||r.pid<=0)return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"invalid_pid"},"invalid PID in client-owned yoloop lock; recovered"),null;if(r.hostname&&r.hostname!==S())return{...r,ownerPidState:"unknown"};try{return process.kill(r.pid,0),{...r,ownerPidState:"live"}}catch{return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"dead_pid"},"stale client-owned yoloop lock recovered before snapshot echo"),null}}async maybeRecoverOrphanLock(e){const s=await this.readLock();if(!s)return!0;if(F(s,e)==="expired")return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"lease_expired"},"expired yoloop lock lease recovered"),!0;if(!s.pid||s.pid<=0)return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"invalid_pid"},"invalid PID in lock file; recovered"),!0;if(s.hostname&&s.hostname!==S())return this.logger.warn({event:"yoloop_lock_remote_host",ownerKind:s.ownerKind??"server",ownerPidState:"unknown"},"lock held by a remote host; honoring"),!1;try{return process.kill(s.pid,0),!1}catch{return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"dead_pid"},"orphan yoloop lock recovered"),!0}}async deleteLockBestEffort(){try{await u.unlink(this.lockPath)}catch{}}isSameClientSessionLock(e,s){return e.ownerKind==="client"&&e.sessionId===s.sessionId&&e.pid===process.pid&&e.hostname===S()}async cleanupOrphanTempFiles(){try{const e=V(this.statePath),s=await u.readdir(e),n=[`${g}.tmp.`,`${P}.tmp.`,`${A}.tmp.`],r=s.filter(o=>n.some(i=>o.startsWith(i)));for(const o of r)try{await u.unlink(_(e,o))}catch{}}catch{}}}function d(t){return t===null||typeof t!="object"?JSON.stringify(t):Array.isArray(t)?`[${t.map(d).join(",")}]`:`{${Object.entries(t).filter(([,e])=>e!==void 0).sort(([e],[s])=>e.localeCompare(s)).map(([e,s])=>`${JSON.stringify(e)}:${d(s)}`).join(",")}}`}function p(t,e){return b("sha256").update(`${t}\0${d(e)}`).digest("hex")}function Z(t){return p("p9390812898200217364-yoloop-session-v1",t)}function Q(t){return p("p9390812898200217364-yoloop-rollover-v1",t)}function ee(t){return p("p9390812898200217364-yoloop-successor-run-v1",t)}function te(t){return p("p9046281030721413419-yoloop-successor-transition-v1",t)}function se(t,e){return t.operationId===e.operationId&&t.idempotencyKey===e.idempotencyKey}function f(t){const e=/^[A-Za-z0-9._:-]{1,128}$/;Y(t.successor);const s={operationId:t.operationId,idempotencyKey:t.idempotencyKey,successor:t.successor,state:t.state,...t.acknowledgement?{acknowledgement:t.acknowledgement}:{},...t.reservation?{reservation:t.reservation}:{}},n=t.acknowledgement?.idempotencyKey,r=t.acknowledgement?.receipt.idempotencyKey,o=t.reservation?.authority.idempotencyKey;if(t.successor.type!=="start_successor_run"||!e.test(t.operationId)||!e.test(t.idempotencyKey)||t.operationId!==t.successor.operationId||t.idempotencyKey!==t.successor.idempotencyKey||!/^[a-f0-9]{64}$/.test(t.payloadHash)||t.payloadHash!==te(s)||Buffer.byteLength(d(s),"utf8")>1048576||t.acknowledgement!==void 0&&(t.acknowledgement.type!=="acknowledge_continuation_authority"||typeof n!="string"||!e.test(n)||r!==n)||t.reservation!==void 0&&(t.reservation.type!=="reserve_continuation_authority"||typeof o!="string"||!e.test(o))||n!==void 0&&o===n)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT")}function k(t,e){if(f(t),!(d(e.runControl)===d(t.successor.next))){const n=e.runControl;if(!n||n.runId!==t.successor.previousRunId||!["exhausted","success"].includes(n.status)||n.revision!==t.successor.expectedRevision||n.latestSnapshotHash!==t.successor.expectedSnapshotHash||e.currentSession!==null)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_STATE_CONFLICT")}ne(t,e)}function ne(t,e){const s=e.pendingContinuationAuthorities??[],n=e.continuationReceipts??[],r=t.acknowledgement;if(r){const l=s.find(O=>O.idempotencyKey===r.idempotencyKey);if(!l||r.receipt.sessionId!==l.sessionId||d(r.receipt.storyIds)!==d(l.storyIds))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");const h=s.filter(O=>O.idempotencyKey!==r.idempotencyKey),y=[...n.slice(-63),r.receipt];if(d(t.state.pendingContinuationAuthorities??[])!==d(h)||d(t.state.continuationReceipts??[])!==d(y))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT")}else if(d(t.state.pendingContinuationAuthorities??[])!==d(s)||d(t.state.continuationReceipts??[])!==d(n))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");const o=t.reservation?.authority;if(!o)return;const i=String(o.idempotencyKey??""),a=t.state.pendingContinuationAuthorities??[],c=a.find(l=>l.idempotencyKey===i);if(c&&d(c)!==d(o))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");if(!c&&a.length>=64)throw new Error("YOLOOP_PENDING_AUTHORITY_CAPACITY_EXCEEDED")}function re(t,e){k(t,e);const s=t.reservation?.authority,n=[...t.state.pendingContinuationAuthorities??[]];return s&&!n.some(r=>r.idempotencyKey===s.idempotencyKey)&&n.push(s),{...t.state,version:"1.2",runControl:t.successor.next,...s||t.state.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:n}:{}}}function R(t,e){const s=t.reservation?.authority,n=[...t.state.pendingContinuationAuthorities??[]];s&&!n.some(o=>o.idempotencyKey===s.idempotencyKey)&&n.push(s);const r={...t.state,version:"1.2",runControl:t.successor.next,...s||t.state.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:n}:{}};return d(e)===d(r)}function oe(t,e){return t.operationId===e.operationId&&t.idempotencyKey===e.idempotencyKey}function v(t){const e=/^[A-Za-z0-9._:-]{1,128}$/,s={runId:t.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,expectedSessionId:t.expectedSessionId,expectedSessionFingerprint:t.expectedSessionFingerprint,expectedLeaseId:t.expectedLeaseId,coolDownUntil:t.coolDownUntil,reason:t.reason,exhaustedRun:t.exhaustedRun,next:t.next};if(!e.test(t.runId)||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.expectedSessionFingerprint)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<0||!Number.isFinite(Date.parse(t.coolDownUntil))||!["YOLOOP_PER_RUN_CAP_REACHED","YOLOOP_SESSION_TIMEOUT"].includes(t.reason)||t.payloadHash!==Q(s)||t.receipt.schemaVersion!=="YoloopSessionRolloverReceipt/1.0"||t.receipt.runId!==t.runId||t.receipt.operationId!==t.operationId||t.receipt.idempotencyKey!==t.idempotencyKey||t.receipt.payloadHash!==t.payloadHash||t.receipt.coolDownUntil!==t.coolDownUntil||t.receipt.revision!==(t.exhaustedRun?.revision??0)||t.receipt.snapshotHash!==(t.exhaustedRun?.latestSnapshotHash??null)||t.receipt.status!=="exhausted"||t.receipt.publicSafe!==!0)throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT");if(t.expectedSessionId===null!=(t.expectedLeaseId===null)||t.expectedSessionId!==null&&!e.test(t.expectedSessionId)||t.expectedLeaseId!==null&&!e.test(t.expectedLeaseId))throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}function Y(t){const e=/^[A-Za-z0-9._:-]{1,128}$/,s={runId:t.runId,previousRunId:t.previousRunId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,next:t.next};if(!e.test(t.runId)||!e.test(t.previousRunId)||t.runId===t.previousRunId||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<1||t.payloadHash!==ee(s))throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT")}function H(t,e,s){v(t);const n=e.currentSession;if(!n||Z(n)!==t.expectedSessionFingerprint)throw new Error("YOLOOP_SESSION_ROLLOVER_SESSION_CONFLICT");const r=e.runControl;if((r?.revision??0)!==t.expectedRevision||(r?.latestSnapshotHash??null)!==t.expectedSnapshotHash||r&&r.runId!==t.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(t.expectedSessionId===null||t.expectedLeaseId===null){if(s)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}else if(!s||s.sessionId!==t.expectedSessionId||s.leaseId!==t.expectedLeaseId)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");const o=t.exhaustedRun;if(r)if(r.status==="exhausted"){if(d(o)!==d(r))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}else{if(!o||o.status!=="exhausted")throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT");const a=o.receipts.at(-1);if(!a)throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT");const c={type:"transition_run",runId:r.runId,operationId:a.operationId,idempotencyKey:a.idempotencyKey,expectedRevision:r.revision,expectedSnapshotHash:r.latestSnapshotHash,payloadHash:a.payloadHash,next:o};T(c),L(r,c)}else{const a=o?.receipts[0],c=o?.receipts[1];if(o&&(o.runId!==t.runId||o.status!=="exhausted"||o.revision!==2||o.events.length!==2||o.progressSnapshots.length!==4||o.receipts.length!==2||a?.runId!==t.runId||a.revision!==1||a.status!=="created"||c?.runId!==t.runId||c.revision!==2||c.status!=="exhausted"||c.operationId!==`${t.operationId}:run`||c.idempotencyKey!==`${t.idempotencyKey}:run`||o.latestSnapshotHash!==c.snapshotHash||o.predecessor!==void 0))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}const i={...e,version:"1.2",coolDownUntil:t.coolDownUntil,currentSession:null,...o?{runControl:o}:{}};if(d(i)!==d(t.next))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}function U(t){const{receipts:e,...s}=t.next;return p("p220-yoloop-run-transition-payload-v1",{runId:t.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,next:s})}const E=new Set(["success","partial","blocked","failure","exhausted","cancelled"]),ie={created:["running","cancelling","exhausted"],running:["pausing","cancelling","success","partial","blocked","failure","exhausted"],pausing:["paused","cancelling","failure","exhausted"],paused:["resuming","cancelling","exhausted"],resuming:["running","cancelling","failure","exhausted"],cancelling:["cancelled","failure","exhausted"]};function ae(t,e){return e==="pause"?t==="running"?"pausing":null:e==="resume"?t==="paused"?"resuming":null:E.has(t)||t==="cancelling"?null:"cancelling"}function ce(t){const e=t.current.revision+1,s=t.action==="cancel"?["YOLOOP_RUN_CANCEL_REQUESTED"]:[],n={schemaVersion:"YoloopOperationalBudgetSummary/1.0",limits:t.current.operationalBudget.limits,usage:t.current.usage,exhaustedDimension:null},r={schemaVersion:"ProgressSnapshot/1.0",runId:t.current.runId,sequence:t.current.progressSnapshots.length+1,revision:e,operationId:t.operationId,boundary:t.action,phase:"before",status:t.current.status,occurredAt:t.occurredAt,parentSnapshotHash:t.current.latestSnapshotHash,budget:n,reasonCodes:s,publicSafe:!0},o=p("p220-yoloop-progress-snapshot-id-v1",{runId:r.runId,operationId:r.operationId,sequence:r.sequence,phase:r.phase}),i={...r,snapshotId:o,snapshotHash:p("p220-yoloop-progress-snapshot-v1",{...r,snapshotId:o})},a={...r,sequence:i.sequence+1,phase:"after",status:t.target,parentSnapshotHash:i.snapshotHash},c=p("p220-yoloop-progress-snapshot-id-v1",{runId:a.runId,operationId:a.operationId,sequence:a.sequence,phase:a.phase}),l={...a,snapshotId:c,snapshotHash:p("p220-yoloop-progress-snapshot-v1",{...a,snapshotId:c})},h={schemaVersion:"YoloopRunEvent/1.0",runId:t.current.runId,operationId:t.operationId,kind:"intent",sequence:t.current.events.length+1,revision:e,occurredAt:t.occurredAt,fromStatus:t.current.status,toStatus:t.target,reasonCodes:s,budgetDimension:null,parentEventHash:t.current.events.at(-1)?.eventHash??null,publicSafe:!0},y=p("p220-yoloop-run-event-id-v1",{runId:h.runId,operationId:h.operationId,sequence:h.sequence}),O={...h,eventId:y,eventHash:p("p220-yoloop-run-event-v1",{...h,eventId:y})},I={...t.current,revision:e,status:t.target,events:[...t.current.events,O],progressSnapshots:[...t.current.progressSnapshots,i,l],latestSnapshotHash:l.snapshotHash,receipts:[...t.current.receipts]},N={runId:t.current.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.current.revision,expectedSnapshotHash:t.current.latestSnapshotHash,next:I},m=U(N),M={schemaVersion:"YoloopRunTransitionReceipt/1.0",runId:t.current.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,payloadHash:m,revision:e,snapshotHash:l.snapshotHash,status:t.target};return{type:"transition_run",...N,payloadHash:m,next:{...I,receipts:[...I.receipts,M]}}}function T(t){const e=/^[A-Za-z0-9._:-]{1,128}$/;if(!e.test(t.runId)||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<0)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT");if(t.payloadHash!==U(t))throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}function L(t,e){const s=e.next,n=t?.events??[],r=t?.progressSnapshots??[],o=t?.receipts??[];if(s.schemaVersion!=="YoloopRunControl/1.0"||s.runId!==e.runId||s.revision!==e.expectedRevision+1||s.events.length!==n.length+1||s.progressSnapshots.length!==r.length+2||s.receipts.length!==o.length+1||d(s.events.slice(0,n.length))!==d(n)||d(s.progressSnapshots.slice(0,r.length))!==d(r)||d(s.receipts.slice(0,o.length))!==d(o))throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(t){if(E.has(t.status))throw new Error("YOLOOP_RUN_TERMINAL");const h=s.progressSnapshots.at(-2)?.boundary,y=t.status===s.status&&(h==="budget"||h==="retry");if(!(ie[t.status]??[]).includes(s.status)&&!y)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(t.startedAt!==s.startedAt||t.deadlineAt!==s.deadlineAt)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(d(t.predecessor)!==d(s.predecessor))throw new Error("YOLOOP_RUN_TRANSITION_INVALID")}else if(s.status!=="created")throw new Error("YOLOOP_RUN_TRANSITION_INVALID");const i=s.progressSnapshots.at(-2),a=s.progressSnapshots.at(-1),c=s.events.at(-1),l=s.receipts.at(-1);if(!i||!a||!c||!l||i.phase!=="before"||a.phase!=="after"||i.operationId!==e.operationId||a.operationId!==e.operationId||c.operationId!==e.operationId||i.runId!==e.runId||a.runId!==e.runId||c.runId!==e.runId||i.revision!==s.revision||a.revision!==s.revision||c.revision!==s.revision||i.parentSnapshotHash!==(t?.latestSnapshotHash??null)||a.parentSnapshotHash!==i.snapshotHash||s.latestSnapshotHash!==a.snapshotHash||l.schemaVersion!=="YoloopRunTransitionReceipt/1.0"||l.runId!==e.runId||l.operationId!==e.operationId||l.idempotencyKey!==e.idempotencyKey||l.payloadHash!==e.payloadHash||l.revision!==s.revision||l.snapshotHash!==s.latestSnapshotHash||l.status!==s.status||Date.parse(s.deadlineAt)<=Date.parse(s.startedAt))throw new Error("YOLOOP_RUN_TRANSITION_INVALID");D(i),D(a),de(c,n.at(-1)?.eventHash??null)}function D(t){const{snapshotHash:e,...s}=t;if(e!==p("p220-yoloop-progress-snapshot-v1",s))throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT")}function de(t,e){const{eventHash:s,...n}=t;if(t.parentEventHash!==e||s!==p("p220-yoloop-run-event-v1",n))throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT")}function le(t,e){return`lease-${ue(`${t}:${e}`)}`}function ue(t){let e=2166136261;for(let s=0;s<t.length;s+=1)e^=t.charCodeAt(s),e=Math.imul(e,16777619)>>>0;return e.toString(36).padStart(7,"0")}function F(t,e){const s=t.leaseExpiresAt??t.ttlExpiresAt,n=Date.parse(s),r=Date.parse(e);return!Number.isFinite(n)||!Number.isFinite(r)?"unknown":n<=r?"expired":"active"}function he(t,e){const s=w(e);return{...t,version:t.version==="1.2"?"1.2":"1.1",lastResetAt:t.lastResetAt??s.lastResetAt,storiesRunToday:t.storiesRunToday??0,iterationsToday:t.iterationsToday??0,iterationsTodayDate:t.iterationsTodayDate??s.iterationsTodayDate,tokensUsedToday:t.tokensUsedToday??0,lastRunAt:t.lastRunAt??null,coolDownUntil:t.coolDownUntil??null,totalRunsAllTime:t.totalRunsAllTime??0,totalStoriesAllTime:t.totalStoriesAllTime??0,currentSession:t.currentSession??null,...t.runControl!==void 0?{runControl:t.runControl}:{},...t.continuationPolicy!==void 0?{continuationPolicy:t.continuationPolicy}:{},...t.continuationSession!==void 0?{continuationSession:t.continuationSession}:{},...t.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:t.pendingContinuationAuthorities}:{},...t.continuationReceipts!==void 0?{continuationReceipts:t.continuationReceipts}:{},...t.continuationRecoveryReceipts!==void 0?{continuationRecoveryReceipts:t.continuationRecoveryReceipts}:{},recovery_history:Array.isArray(t.recovery_history)?K(t.recovery_history):[]}}function K(t){return t.length<=C?t:t.slice(t.length-C)}export{x as YOLOOP_PERSISTENCE_CAPABILITIES,fe as YoloopClientStateStore,U as buildYoloopRunTransitionPayloadHash,Q as buildYoloopSessionRolloverPayloadHash,ee as buildYoloopSuccessorRunPayloadHash,te as buildYoloopSuccessorTransitionPayloadHash,K as capRecoveryHistory,w as createDefaultCounters,we as createDefaultState,Z as fingerprintYoloopSession};
|
|
1
|
+
import{promises as u}from"node:fs";import{createHash as V}from"node:crypto";import{join as S,dirname as $}from"node:path";import{hostname as w}from"node:os";import{setSecureFilePermissions as q,setSecureDirPermissions as B}from"../config/secure-config.js";import{RECOVERY_HISTORY_CAP as m}from"./shared-yoloop-types.js";const j=".neocortex",g="yoloop-state.json",J="yoloop.lock",z="yoloop-state.mutation.lock",A="yoloop-session-rollover.json",P="yoloop-successor-transition.json",W=360*60*1e3,G=3e4,X=200,x=Object.freeze(["rollover-session-v1","successor-transition-v1","continuation-replan-v1"]),Z={warn:()=>{},info:()=>{},error:()=>{}};function f(t){const e=t.slice(0,10);return{version:"1.1",lastResetAt:t,storiesRunToday:0,iterationsToday:0,iterationsTodayDate:e,tokensUsedToday:0,lastRunAt:null,coolDownUntil:null,totalRunsAllTime:0,totalStoriesAllTime:0,currentSession:null,continuationPolicy:"p205-finite-resume-v2",pendingContinuationAuthorities:[],continuationReceipts:[],continuationRecoveryReceipts:[]}}function Re(t){return{lock:null,state:f(t),capabilities:x}}class ve{stateDir;statePath;lockPath;mutationLockPath;rolloverManifestPath;successorTransitionManifestPath;logger;constructor(e,s=Z){this.stateDir=S(e,j),this.statePath=S(this.stateDir,g),this.lockPath=S(this.stateDir,J),this.mutationLockPath=S(this.stateDir,z),this.rolloverManifestPath=S(this.stateDir,A),this.successorTransitionManifestPath=S(this.stateDir,P),this.logger=s}async readAll(e){const s=e??new Date().toISOString();await this.cleanupOrphanTempFiles(),await this.recoverSessionRolloverIfPresent(s),await this.recoverSuccessorTransitionIfPresent(s);const[n,o]=await Promise.all([this.readLock(),this.readState(s)]);return{lock:await this.prepareLockForSnapshot(n,s),state:o,capabilities:x}}async applyUpdate(e,s){const n=s??new Date().toISOString();await this.ensureDir(),await this.recoverSessionRolloverIfPresent(n),await this.recoverSuccessorTransitionIfPresent(n);for(const o of e.operations)await this.applyOperation(o,n)}async requestRunTransition(e,s){const n=s??new Date().toISOString();return await this.ensureDir(),this.withMutationLock(()=>this.transitionRun(e,n))}async requestLifecycleAction(e,s={},n){const o=n??new Date().toISOString();return await this.ensureDir(),this.withMutationLock(async()=>{const c=(await this.readState(o)).runControl;if(!c)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");const a=Date.parse(o).toString(36),i=s.operationId??`op-${e}-${a}`,l=s.idempotencyKey??`idem-${e}-${a}`,h=c.receipts.find(y=>y.operationId===i||y.idempotencyKey===l);if(h){if(h.operationId===i&&h.idempotencyKey===l)return h;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}const O=de(c.status,e);if(!O)throw new Error(T.has(c.status)?"YOLOOP_RUN_TERMINAL":"YOLOOP_RUN_TRANSITION_INVALID");return this.transitionRun(le({current:c,action:e,target:O,operationId:i,idempotencyKey:l,occurredAt:o}),o)})}async applyOperation(e,s){switch(e.type){case"acquire_lock":await this.withMutationLock(()=>this.acquireLock(e.lock,s));return;case"release_lock":await this.withMutationLock(()=>this.releaseLock(e));return;case"write_state":await this.withMutationLock(async()=>{const n=await this.readState(s),{runControl:o,...r}=e.state;await this.writeState({...r,...n.runControl?{version:"1.2",runControl:n.runControl}:{}})});return;case"advance_epic":await this.advanceEpic(e.nextEpicIndex,e.nextEpicId,s);return;case"no_op":this.logger.info({event:"yoloop_noop"},"yoloop server sent no-op");return;case"reserve_continuation_authority":await this.reserveContinuationAuthority(e.authority,s);return;case"acknowledge_continuation_authority":await this.acknowledgeContinuationAuthority(e.idempotencyKey,e.receipt,s);return;case"repair_continuation_authority":await this.repairContinuationAuthority(e.beforeHash,e.authority,e.receipt,s);return;case"switch_continuation_policy":await this.switchContinuationPolicy(e.policy,e.session,s);return;case"transition_run":await this.requestRunTransition(e,s);return;case"start_successor_run":await this.withMutationLock(()=>this.startSuccessorRun(e,s));return;case"commit_successor_transition":await this.withMutationLock(()=>this.commitSuccessorTransition(e,s));return;case"rollover_session":await this.withMutationLock(()=>this.rolloverSession(e,s));return;case"replan_continuation_session":await this.withMutationLock(()=>this.replanContinuationSession(e,s));return;case"recovery_attempted":await this.appendRecoveryAttempt(e.attempt,s);return;case"recovery_resolved":await this.resolveRecoveryAttempt(e.attempt_id,e.outcome,s);return;default:{const n=e;throw this.logger.error({event:"yoloop_unknown_op",op:n},"unknown yoloop operation rejected"),new Error("YOLOOP_STATE_OPERATION_UNSUPPORTED")}}}async reserveContinuationAuthority(e,s){const n=await this.readState(s),o=n.pendingContinuationAuthorities??[],r=typeof e.idempotencyKey=="string"?e.idempotencyKey:"";if(!r)throw new Error("YOLOOP_CONTINUATION_AUTHORITY_INVALID");const c=o.find(a=>a.idempotencyKey===r);if(c){if(d(c)===d(e))return;throw new Error("YOLOOP_CONTINUATION_AUTHORITY_CONFLICT")}if(o.length>=64)throw new Error("YOLOOP_PENDING_AUTHORITY_CAPACITY_EXCEEDED");await this.writeState({...n,pendingContinuationAuthorities:[...o,e]})}async acknowledgeContinuationAuthority(e,s,n){const o=await this.readState(n),r=o.pendingContinuationAuthorities??[],c=r.findIndex(h=>h.idempotencyKey===e);if(c<0)throw new Error("YOLOOP_CONTINUATION_RECEIPT_ORPHAN");const a=r[c];if(s.idempotencyKey!==e||s.sessionId!==a.sessionId||JSON.stringify(s.storyIds)!==JSON.stringify(a.storyIds))throw new Error("YOLOOP_CONTINUATION_RECEIPT_MISMATCH");const i=r.filter((h,O)=>O!==c),l=o.continuationReceipts??[];await this.writeState({...o,pendingContinuationAuthorities:i,continuationReceipts:[...l.slice(-63),s]})}async repairContinuationAuthority(e,s,n,o){const r=await this.readState(o),c=r.pendingContinuationAuthorities??[],a=r.continuationRecoveryReceipts??[],i=typeof n.idempotencyKey=="string"?n.idempotencyKey:"",l=a.find(y=>y.idempotencyKey===i);if(l){if(d(l)===d(n))return;throw new Error("YOLOOP_CONTINUATION_RECOVERY_RECEIPT_CONFLICT")}if(c.length!==1||p("p208-legacy-authority-before-v1",c[0])!==e)throw new Error("YOLOOP_CONTINUATION_RECOVERY_BEFORE_MISMATCH");const h=p("p208-legacy-authority-after-v1",s);if(n.beforeHash!==e||n.afterHash!==h)throw new Error("YOLOOP_CONTINUATION_RECOVERY_HASH_MISMATCH");const O={...n};if(delete O.idempotencyKey,!i||p("p208-legacy-authority-recovery-receipt-v1",O)!==i)throw new Error("YOLOOP_CONTINUATION_RECOVERY_RECEIPT_INVALID");await this.writeState({...r,pendingContinuationAuthorities:[s],continuationRecoveryReceipts:[...a.slice(-63),n]})}async switchContinuationPolicy(e,s,n){const o=await this.readState(n);if(o.currentSession||(o.pendingContinuationAuthorities?.length??0)>0)throw new Error("YOLOOP_POLICY_SWITCH_ACTIVE");try{await u.copyFile(this.statePath,`${this.statePath}.policy-backup`)}catch(r){if(r.code!=="ENOENT")throw r}await this.writeState({...o,continuationPolicy:e,continuationSession:s})}async replanContinuationSession(e,s){const{type:n,payloadHash:o,receipt:r,...c}=e;if(Q(c)!==e.payloadHash||!k(e.nextSession))throw new Error("YOLOOP_CONTINUATION_REPLAN_PAYLOAD_INVALID");const a={schemaVersion:"YoloopContinuationReplanReceipt/1.0",operationId:e.operationId,idempotencyKey:e.idempotencyKey,runId:e.expectedRunId,previousSessionHash:e.expectedSessionHash,nextSessionHash:p("p222-yoloop-replan-session-v1",e.nextSession),retiredAuthorityHash:e.expectedPendingHash,retiredAuthorityCount:e.expectedPendingHash===p("p222-yoloop-replan-pending-v1",[])?0:1,payloadHash:e.payloadHash,outcome:"graph-replanned",publicSafe:!0};if(d(e.receipt)!==d(a))throw new Error("YOLOOP_CONTINUATION_REPLAN_RECEIPT_INVALID");const i=await this.readState(s);if(await this.readLock()||i.currentSession!==null)throw new Error("YOLOOP_CONTINUATION_REPLAN_ACTIVE");const l=i.runControl;if(!l||l.runId!==e.expectedRunId||!["success","exhausted"].includes(l.status)||l.revision!==e.expectedRevision||l.latestSnapshotHash!==e.expectedSnapshotHash||i.continuationPolicy!=="p205-finite-resume-v2")throw new Error("YOLOOP_CONTINUATION_REPLAN_RUN_CONFLICT");const h=i.continuationReplanReceipts??[],O=h.find(_=>_.idempotencyKey===e.idempotencyKey||_.operationId===e.operationId);if(O){if(d(O)===d(a)&&d(i.continuationSession)===d(e.nextSession)&&(i.pendingContinuationAuthorities?.length??0)===0)return;throw new Error("YOLOOP_CONTINUATION_REPLAN_REPLAY_CONFLICT")}const y=i.continuationSession,I=i.pendingContinuationAuthorities??[];if(!k(y)||p("p222-yoloop-replan-session-v1",y)!==e.expectedSessionHash||p("p222-yoloop-replan-pending-v1",I)!==e.expectedPendingHash||I.length>1||I.some(_=>_.delegated!==!1||_.sessionId!==y.sessionId||!_.certificate||_.certificate.sessionId!==y.sessionId))throw new Error("YOLOOP_CONTINUATION_REPLAN_AUTHORITY_CONFLICT");await this.writeState({...i,continuationSession:e.nextSession,pendingContinuationAuthorities:[],continuationReplanReceipts:[...h.slice(-63),a]})}async appendRecoveryAttempt(e,s){const n=await this.readState(s),o=n.recovery_history??[];if(o.some(i=>i.attempted_at===e.attempted_at&&i.story_id===e.story_id)){this.logger.warn({event:"recovery_attempted_duplicate",story_id:e.story_id},"duplicate recovery_attempted op; skipping");return}const c=M([...o,e]),a={...n,recovery_history:c};await this.writeState(a),this.logger.info({event:"recovery_attempted_persisted",story_id:e.story_id,history_size:c.length},"recovery attempt persisted")}async resolveRecoveryAttempt(e,s,n){const o=await this.readState(n),r=o.recovery_history??[],c=r.findIndex(h=>h.recovery_step_id_tokenized===e);if(c===-1){this.logger.warn({event:"recovery_resolve_orphan",attempt_id:e},"recovery_resolved op had no matching attempt; skipping");return}const a=r[c];if(a.outcome===s&&a.finished_at){this.logger.info({event:"recovery_resolved_duplicate",attempt_id:e,outcome:s},"duplicate recovery_resolved op; skipping");return}const i=r.slice();i[c]={...a,outcome:s,finished_at:n};const l={...o,recovery_history:i};await this.writeState(l),this.logger.info({event:"recovery_resolved_persisted",attempt_id:e,outcome:s},"recovery attempt resolved")}async acquireLock(e,s){const n={...e,pid:process.pid,hostname:w(),ownerKind:"client",startedAt:e.startedAt||s,leaseId:e.leaseId??he(e.sessionId,s),leaseState:"active",leaseAcquiredAt:e.leaseAcquiredAt??s,leaseDurationMs:e.leaseDurationMs??W,leaseExpiresAt:e.leaseExpiresAt??e.ttlExpiresAt},o=JSON.stringify(n,null,2);try{const r=await u.open(this.lockPath,"wx");try{await r.writeFile(o,"utf8")}finally{await r.close()}this.trySetFilePerms(this.lockPath),this.logger.info({event:"yoloop_lock_acquired",pid:n.pid,sessionId:n.sessionId},"yoloop lock acquired");return}catch(r){const c=r;if(c.code!=="EEXIST")throw this.logger.error({event:"yoloop_lock_acquire_error",err:c.message},"failed to acquire yoloop lock"),r;const a=await this.readLock();if(a&&this.isSameClientSessionLock(a,n)){this.logger.info({event:"yoloop_lock_acquire_duplicate",sessionId:n.sessionId},"duplicate acquire_lock for current yoloop session; treating as no-op");return}if(!await this.maybeRecoverOrphanLock(s))throw this.logger.warn({event:"yoloop_lock_held"},"yoloop lock held by another live process"),r;const l=await u.open(this.lockPath,"wx");try{await l.writeFile(o,"utf8")}finally{await l.close()}this.trySetFilePerms(this.lockPath),this.logger.info({event:"yoloop_lock_acquired_after_recovery",pid:n.pid},"yoloop lock acquired after orphan recovery")}}async releaseLock(e){const s=await this.readState(new Date().toISOString()),n=await this.readLock();if(s.runControl){if(!e.expectedRunId||!e.expectedSessionId||!e.expectedLeaseId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(e.expectedRunId!==s.runControl.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(!n||e.expectedSessionId!==n.sessionId||e.expectedLeaseId!==n.leaseId)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}try{await u.unlink(this.lockPath),this.logger.info({event:"yoloop_lock_released"},"yoloop lock released")}catch(o){const r=o;if(r.code==="ENOENT"){this.logger.info({event:"yoloop_lock_release_noop"},"yoloop lock release noop (file absent)");return}this.logger.warn({event:"yoloop_lock_release_error",err:r.message},"unexpected error releasing yoloop lock")}}async readLock(){try{const e=await u.readFile(this.lockPath,"utf8"),s=JSON.parse(e),n=s.currentEpicId??s.epicId??"";return{pid:s.pid??0,hostname:s.hostname??"",...s.ownerKind?{ownerKind:s.ownerKind}:{},...s.ownerPidState?{ownerPidState:s.ownerPidState}:{},...typeof s.leaseId=="string"?{leaseId:s.leaseId}:{},...s.leaseState?{leaseState:s.leaseState}:{},...typeof s.leaseAcquiredAt=="string"?{leaseAcquiredAt:s.leaseAcquiredAt}:{},...typeof s.leaseDurationMs=="number"?{leaseDurationMs:s.leaseDurationMs}:{},...typeof s.leaseExpiresAt=="string"?{leaseExpiresAt:s.leaseExpiresAt}:{},startedAt:s.startedAt??"",sessionId:s.sessionId??"",mode:s.mode??"epic-id",inputPath:s.inputPath??"",epicQueue:s.epicQueue??(n?[n]:[]),currentEpicIndex:s.currentEpicIndex??0,currentEpicId:n,ttlExpiresAt:s.ttlExpiresAt??"",epicId:s.epicId??n}}catch{return null}}async readState(e){try{const s=await u.readFile(this.statePath,"utf8"),n=JSON.parse(s);return Oe(n,e)}catch(s){const n=s;return n.code!=="ENOENT"&&this.logger.warn({event:"yoloop_state_read_error",err:n.message},"yoloop state file unreadable; using defaults"),f(e)}}async writeState(e){const s=`${this.statePath}.tmp.${process.pid}.${Date.now()}`,n=JSON.stringify(e,null,2);try{const o=await u.open(s,"w",384);try{await o.writeFile(n,"utf8"),await o.sync()}finally{await o.close()}this.trySetFilePerms(s),await u.rename(s,this.statePath),await this.syncStateDirectory()}catch(o){const r=o;this.logger.error({event:"yoloop_state_write_error",err:r.message},"failed to write yoloop state");try{await u.unlink(s)}catch{}throw o}}async rolloverSession(e,s){E(e);const n=await this.readRolloverManifest();if(n){if(ae(n.operation,e)){if(n.operation.payloadHash!==e.payloadHash)throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT");if(n.phase==="applied")return;await this.completePreparedSessionRollover(n.operation,s);return}else if(n.phase==="prepared")throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT")}const o=await this.readState(s),r=await this.readLock();U(e,o,r),await this.writeRolloverManifest({schemaVersion:"YoloopSessionRolloverManifest/1.0",phase:"prepared",operation:e}),await this.completePreparedSessionRollover(e,s)}async completePreparedSessionRollover(e,s){const n=await this.readState(s);let o=d(n)===d(e.next);if(!o){const c=await this.readLock();U(e,n,c),await this.writeState(e.next),o=!0}const r=await this.readLock();if(e.expectedSessionId===null||e.expectedLeaseId===null){if(e.expectedSessionId!==null||e.expectedLeaseId!==null||r)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}else if(r){if(r.sessionId!==e.expectedSessionId||r.leaseId!==e.expectedLeaseId)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");await u.unlink(this.lockPath),await this.syncStateDirectory()}else if(!o)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");await this.writeRolloverManifest({schemaVersion:"YoloopSessionRolloverManifest/1.0",phase:"applied",operation:e}),this.logger.info({event:"yoloop_session_rollover_applied",runId:e.runId,operationId:e.operationId,coolDownUntil:e.coolDownUntil},"yoloop per-run-cap session rollover applied")}async recoverSessionRolloverIfPresent(e){try{await u.access(this.rolloverManifestPath)}catch(s){if(s.code==="ENOENT")return;throw s}await this.ensureDir(),await this.withMutationLock(async()=>{const s=await this.readRolloverManifest();s?.phase==="prepared"&&await this.completePreparedSessionRollover(s.operation,e)})}async readRolloverManifest(){try{const e=JSON.parse(await u.readFile(this.rolloverManifestPath,"utf8"));if(e.schemaVersion!=="YoloopSessionRolloverManifest/1.0"||e.phase!=="prepared"&&e.phase!=="applied"||!e.operation||e.operation.type!=="rollover_session")throw new Error("YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT");return E(e.operation),e}catch(e){if(e.code==="ENOENT")return null;throw e.message==="YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT"?e:new Error("YOLOOP_SESSION_ROLLOVER_MANIFEST_CORRUPT")}}async writeRolloverManifest(e){const s=`${this.rolloverManifestPath}.tmp.${process.pid}.${Date.now()}`,n=await u.open(s,"w",384);try{await n.writeFile(JSON.stringify(e,null,2),"utf8"),await n.sync()}finally{await n.close()}this.trySetFilePerms(s),await u.rename(s,this.rolloverManifestPath),await this.syncStateDirectory()}async commitSuccessorTransition(e,s){R(e);const n=await this.readSuccessorTransitionManifest();if(n){if(oe(n.operation,e)){if(n.operation.payloadHash!==e.payloadHash)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT");if(n.phase==="applied")return;await this.completePreparedSuccessorTransition(n.operation,s);return}if(n.phase==="prepared")throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT")}const o=await this.readState(s);if(v(e,o)){await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"applied",operation:e});return}H(e,o),await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"prepared",operation:e}),await this.completePreparedSuccessorTransition(e,s)}async completePreparedSuccessorTransition(e,s){let n=await this.readState(s);if(!v(e,n)){d(n.runControl)===d(e.successor.next)||(await this.startSuccessorRun(e.successor,s),n=await this.readState(s));const r=ie(e,n);await this.writeState(r),n=await this.readState(s)}if(!v(e,n))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_STATE_CONFLICT");await this.writeSuccessorTransitionManifest({schemaVersion:"YoloopSuccessorTransitionManifest/1.0",phase:"applied",operation:e}),this.logger.info({event:"yoloop_successor_transition_applied",runId:e.successor.runId,operationId:e.operationId},"yoloop successor transition applied")}async recoverSuccessorTransitionIfPresent(e){try{await u.access(this.successorTransitionManifestPath)}catch(s){if(s.code==="ENOENT")return;throw s}await this.ensureDir(),await this.withMutationLock(async()=>{const s=await this.readSuccessorTransitionManifest();s?.phase==="prepared"&&await this.completePreparedSuccessorTransition(s.operation,e)})}async readSuccessorTransitionManifest(){try{const e=JSON.parse(await u.readFile(this.successorTransitionManifestPath,"utf8"));if(e.schemaVersion!=="YoloopSuccessorTransitionManifest/1.0"||e.phase!=="prepared"&&e.phase!=="applied"||!e.operation||e.operation.type!=="commit_successor_transition")throw new Error("YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT");return R(e.operation),e}catch(e){if(e.code==="ENOENT")return null;throw e.message==="YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT"?e:new Error("YOLOOP_SUCCESSOR_TRANSITION_MANIFEST_CORRUPT")}}async writeSuccessorTransitionManifest(e){const s=`${this.successorTransitionManifestPath}.tmp.${process.pid}.${Date.now()}`,n=await u.open(s,"w",384);try{await n.writeFile(JSON.stringify(e,null,2),"utf8"),await n.sync()}finally{await n.close()}this.trySetFilePerms(s),await u.rename(s,this.successorTransitionManifestPath),await this.syncStateDirectory()}async advanceEpic(e,s,n){const o=await this.readState(n);if(!o.currentSession){this.logger.warn({event:"yoloop_advance_no_session",nextEpicId:s},"advance_epic with no active session; skipping");return}const r={...o,currentSession:{...o.currentSession,currentEpicIndex:e}};await this.writeState(r),this.logger.info({event:"yoloop_epic_advance",nextEpicId:s,nextIndex:e},"yoloop advanced to next epic")}async ensureDir(){try{await u.mkdir(this.stateDir,{recursive:!0}),this.trySetDirPerms(this.stateDir)}catch(e){const s=e;throw this.logger.error({event:"yoloop_mkdir_error",err:s.message,path:this.stateDir},"failed to ensure .neocortex/ directory"),e}}async syncStateDirectory(){try{const e=await u.open(this.stateDir,"r");try{await e.sync()}finally{await e.close()}}catch(e){const s=e.code;if(s!=="EINVAL"&&s!=="EISDIR"&&s!=="ENOTSUP"&&s!=="EPERM")throw e}}async withMutationLock(e){let s=null;for(let n=0;n<X;n+=1)try{s=await u.open(this.mutationLockPath,"wx",384),await s.writeFile(JSON.stringify({pid:process.pid,acquiredAt:new Date().toISOString()})),await s.sync();break}catch(o){if(o.code!=="EEXIST")throw o;try{const r=await u.stat(this.mutationLockPath);if(Date.now()-r.mtimeMs>G){await u.unlink(this.mutationLockPath);continue}}catch{continue}await new Promise(r=>setTimeout(r,5))}if(!s)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");try{return await e()}finally{await s.close().catch(()=>{}),await u.unlink(this.mutationLockPath).catch(()=>{})}}async transitionRun(e,s){N(e);const n=await this.readState(s),o=n.runControl,r=o?.receipts.find(l=>l.operationId===e.operationId||l.idempotencyKey===e.idempotencyKey);if(r){if(r.operationId===e.operationId&&r.idempotencyKey===e.idempotencyKey&&r.payloadHash===e.payloadHash)return r;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}if(o&&o.runId!==e.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if((o?.revision??0)!==e.expectedRevision)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if((o?.latestSnapshotHash??null)!==e.expectedSnapshotHash)throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT");L(o,e);const i=e.next.receipts.at(-1);if(!i)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT");return await this.writeState({...n,version:"1.2",runControl:e.next}),this.logger.info({event:"yoloop_run_transition_committed",runId:e.runId,operationId:e.operationId,revision:i.revision,status:i.status},"yoloop run transition committed"),i}async startSuccessorRun(e,s){Y(e);const n=await this.readState(s),o=n.runControl,r={schemaVersion:"YoloopRunPredecessor/1.0",runId:e.previousRunId,revision:e.expectedRevision,snapshotHash:e.expectedSnapshotHash,successorOperationId:e.operationId,publicSafe:!0},c=o?.receipts.find(l=>l.operationId===e.operationId||l.idempotencyKey===e.idempotencyKey);if(c){if(c.operationId===e.operationId&&c.idempotencyKey===e.idempotencyKey&&e.next.receipts.at(-1)?.payloadHash===c.payloadHash&&d(o?.predecessor)===d(r))return c;throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}if(!o||o.runId!==e.previousRunId||!["exhausted","success"].includes(o.status)||o.revision!==e.expectedRevision||o.latestSnapshotHash!==e.expectedSnapshotHash||n.currentSession!==null)throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT");const a=e.next.receipts.at(-1);if(!a||d(e.next.predecessor)!==d(r))throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT");const i={type:"transition_run",runId:e.runId,operationId:e.operationId,idempotencyKey:e.idempotencyKey,expectedRevision:0,expectedSnapshotHash:null,payloadHash:a.payloadHash,next:e.next};return N(i),L(void 0,i),await this.writeState({...n,version:"1.2",runControl:e.next}),a}trySetFilePerms(e){try{q(e)}catch{}}trySetDirPerms(e){try{B(e)}catch{}}async prepareLockForSnapshot(e,s){if(!e)return null;if(e.ownerKind!=="client")return e;const n=K(e,s),o={...e,leaseState:n};if(n==="expired")return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"lease_expired"},"expired client-owned yoloop lock lease recovered before snapshot echo"),null;if(!o.pid||o.pid<=0)return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"invalid_pid"},"invalid PID in client-owned yoloop lock; recovered"),null;if(o.hostname&&o.hostname!==w())return{...o,ownerPidState:"unknown"};try{return process.kill(o.pid,0),{...o,ownerPidState:"live"}}catch{return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_client_lock_recovered",reason:"dead_pid"},"stale client-owned yoloop lock recovered before snapshot echo"),null}}async maybeRecoverOrphanLock(e){const s=await this.readLock();if(!s)return!0;if(K(s,e)==="expired")return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"lease_expired"},"expired yoloop lock lease recovered"),!0;if(!s.pid||s.pid<=0)return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"invalid_pid"},"invalid PID in lock file; recovered"),!0;if(s.hostname&&s.hostname!==w())return this.logger.warn({event:"yoloop_lock_remote_host",ownerKind:s.ownerKind??"server",ownerPidState:"unknown"},"lock held by a remote host; honoring"),!1;try{return process.kill(s.pid,0),!1}catch{return await this.deleteLockBestEffort(),this.logger.warn({event:"yoloop_orphan_lock_recovered",reason:"dead_pid"},"orphan yoloop lock recovered"),!0}}async deleteLockBestEffort(){try{await u.unlink(this.lockPath)}catch{}}isSameClientSessionLock(e,s){return e.ownerKind==="client"&&e.sessionId===s.sessionId&&e.pid===process.pid&&e.hostname===w()}async cleanupOrphanTempFiles(){try{const e=$(this.statePath),s=await u.readdir(e),n=[`${g}.tmp.`,`${A}.tmp.`,`${P}.tmp.`],o=s.filter(r=>n.some(c=>r.startsWith(c)));for(const r of o)try{await u.unlink(S(e,r))}catch{}}catch{}}}function d(t){return t===null||typeof t!="object"?JSON.stringify(t):Array.isArray(t)?`[${t.map(d).join(",")}]`:`{${Object.entries(t).filter(([,e])=>e!==void 0).sort(([e],[s])=>e.localeCompare(s)).map(([e,s])=>`${JSON.stringify(e)}:${d(s)}`).join(",")}}`}function p(t,e){return V("sha256").update(`${t}\0${d(e)}`).digest("hex")}function Q(t){return p("p222-yoloop-continuation-replan-v1",t)}function k(t){if(!t||typeof t!="object"||Array.isArray(t))return!1;const{sessionId:e,...s}=t;return typeof e=="string"&&/^[a-f0-9]{64}$/.test(e)&&e===p("p205-yoloop-session-v1",s)}function ee(t){return p("p9390812898200217364-yoloop-session-v1",t)}function te(t){return p("p9390812898200217364-yoloop-rollover-v1",t)}function se(t){return p("p9390812898200217364-yoloop-successor-run-v1",t)}function ne(t){return p("p9046281030721413419-yoloop-successor-transition-v1",t)}function oe(t,e){return t.operationId===e.operationId&&t.idempotencyKey===e.idempotencyKey}function R(t){const e=/^[A-Za-z0-9._:-]{1,128}$/;Y(t.successor);const s={operationId:t.operationId,idempotencyKey:t.idempotencyKey,successor:t.successor,state:t.state,...t.acknowledgement?{acknowledgement:t.acknowledgement}:{},...t.reservation?{reservation:t.reservation}:{}},n=t.acknowledgement?.idempotencyKey,o=t.acknowledgement?.receipt.idempotencyKey,r=t.reservation?.authority.idempotencyKey;if(t.successor.type!=="start_successor_run"||!e.test(t.operationId)||!e.test(t.idempotencyKey)||t.operationId!==t.successor.operationId||t.idempotencyKey!==t.successor.idempotencyKey||!/^[a-f0-9]{64}$/.test(t.payloadHash)||t.payloadHash!==ne(s)||Buffer.byteLength(d(s),"utf8")>1048576||t.acknowledgement!==void 0&&(t.acknowledgement.type!=="acknowledge_continuation_authority"||typeof n!="string"||!e.test(n)||o!==n)||t.reservation!==void 0&&(t.reservation.type!=="reserve_continuation_authority"||typeof r!="string"||!e.test(r))||n!==void 0&&r===n)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_CONFLICT")}function H(t,e){if(R(t),!(d(e.runControl)===d(t.successor.next))){const n=e.runControl;if(!n||n.runId!==t.successor.previousRunId||!["exhausted","success"].includes(n.status)||n.revision!==t.successor.expectedRevision||n.latestSnapshotHash!==t.successor.expectedSnapshotHash||e.currentSession!==null)throw new Error("YOLOOP_SUCCESSOR_TRANSITION_STATE_CONFLICT")}re(t,e)}function re(t,e){const s=e.pendingContinuationAuthorities??[],n=e.continuationReceipts??[],o=t.acknowledgement;if(o){const l=s.find(y=>y.idempotencyKey===o.idempotencyKey);if(!l||o.receipt.sessionId!==l.sessionId||d(o.receipt.storyIds)!==d(l.storyIds))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");const h=s.filter(y=>y.idempotencyKey!==o.idempotencyKey),O=[...n.slice(-63),o.receipt];if(d(t.state.pendingContinuationAuthorities??[])!==d(h)||d(t.state.continuationReceipts??[])!==d(O))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT")}else if(d(t.state.pendingContinuationAuthorities??[])!==d(s)||d(t.state.continuationReceipts??[])!==d(n))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");const r=t.reservation?.authority;if(!r)return;const c=String(r.idempotencyKey??""),a=t.state.pendingContinuationAuthorities??[],i=a.find(l=>l.idempotencyKey===c);if(i&&d(i)!==d(r))throw new Error("YOLOOP_SUCCESSOR_TRANSITION_AUTHORITY_CONFLICT");if(!i&&a.length>=64)throw new Error("YOLOOP_PENDING_AUTHORITY_CAPACITY_EXCEEDED")}function ie(t,e){H(t,e);const s=t.reservation?.authority,n=[...t.state.pendingContinuationAuthorities??[]];return s&&!n.some(o=>o.idempotencyKey===s.idempotencyKey)&&n.push(s),{...t.state,version:"1.2",runControl:t.successor.next,...s||t.state.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:n}:{}}}function v(t,e){const s=t.reservation?.authority,n=[...t.state.pendingContinuationAuthorities??[]];s&&!n.some(r=>r.idempotencyKey===s.idempotencyKey)&&n.push(s);const o={...t.state,version:"1.2",runControl:t.successor.next,...s||t.state.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:n}:{}};return d(e)===d(o)}function ae(t,e){return t.operationId===e.operationId&&t.idempotencyKey===e.idempotencyKey}function E(t){const e=/^[A-Za-z0-9._:-]{1,128}$/,s={runId:t.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,expectedSessionId:t.expectedSessionId,expectedSessionFingerprint:t.expectedSessionFingerprint,expectedLeaseId:t.expectedLeaseId,coolDownUntil:t.coolDownUntil,reason:t.reason,exhaustedRun:t.exhaustedRun,next:t.next};if(!e.test(t.runId)||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.expectedSessionFingerprint)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<0||!Number.isFinite(Date.parse(t.coolDownUntil))||!["YOLOOP_PER_RUN_CAP_REACHED","YOLOOP_SESSION_TIMEOUT"].includes(t.reason)||t.payloadHash!==te(s)||t.receipt.schemaVersion!=="YoloopSessionRolloverReceipt/1.0"||t.receipt.runId!==t.runId||t.receipt.operationId!==t.operationId||t.receipt.idempotencyKey!==t.idempotencyKey||t.receipt.payloadHash!==t.payloadHash||t.receipt.coolDownUntil!==t.coolDownUntil||t.receipt.revision!==(t.exhaustedRun?.revision??0)||t.receipt.snapshotHash!==(t.exhaustedRun?.latestSnapshotHash??null)||t.receipt.status!=="exhausted"||t.receipt.publicSafe!==!0)throw new Error("YOLOOP_SESSION_ROLLOVER_CONFLICT");if(t.expectedSessionId===null!=(t.expectedLeaseId===null)||t.expectedSessionId!==null&&!e.test(t.expectedSessionId)||t.expectedLeaseId!==null&&!e.test(t.expectedLeaseId))throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}function Y(t){const e=/^[A-Za-z0-9._:-]{1,128}$/,s={runId:t.runId,previousRunId:t.previousRunId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,next:t.next};if(!e.test(t.runId)||!e.test(t.previousRunId)||t.runId===t.previousRunId||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<1||t.payloadHash!==se(s))throw new Error("YOLOOP_RUN_SUCCESSOR_CONFLICT")}function U(t,e,s){E(t);const n=e.currentSession;if(!n||ee(n)!==t.expectedSessionFingerprint)throw new Error("YOLOOP_SESSION_ROLLOVER_SESSION_CONFLICT");const o=e.runControl;if((o?.revision??0)!==t.expectedRevision||(o?.latestSnapshotHash??null)!==t.expectedSnapshotHash||o&&o.runId!==t.runId)throw new Error("YOLOOP_RUN_REVISION_CONFLICT");if(t.expectedSessionId===null||t.expectedLeaseId===null){if(s)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT")}else if(!s||s.sessionId!==t.expectedSessionId||s.leaseId!==t.expectedLeaseId)throw new Error("YOLOOP_SESSION_ROLLOVER_LOCK_CONFLICT");const r=t.exhaustedRun;if(o)if(o.status==="exhausted"){if(d(r)!==d(o))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}else{if(!r||r.status!=="exhausted")throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT");const a=r.receipts.at(-1);if(!a)throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT");const i={type:"transition_run",runId:o.runId,operationId:a.operationId,idempotencyKey:a.idempotencyKey,expectedRevision:o.revision,expectedSnapshotHash:o.latestSnapshotHash,payloadHash:a.payloadHash,next:r};N(i),L(o,i)}else{const a=r?.receipts[0],i=r?.receipts[1];if(r&&(r.runId!==t.runId||r.status!=="exhausted"||r.revision!==2||r.events.length!==2||r.progressSnapshots.length!==4||r.receipts.length!==2||a?.runId!==t.runId||a.revision!==1||a.status!=="created"||i?.runId!==t.runId||i.revision!==2||i.status!=="exhausted"||i.operationId!==`${t.operationId}:run`||i.idempotencyKey!==`${t.idempotencyKey}:run`||r.latestSnapshotHash!==i.snapshotHash||r.predecessor!==void 0))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}const c={...e,version:"1.2",coolDownUntil:t.coolDownUntil,currentSession:null,...r?{runControl:r}:{}};if(d(c)!==d(t.next))throw new Error("YOLOOP_SESSION_ROLLOVER_STATE_CONFLICT")}function D(t){const{receipts:e,...s}=t.next;return p("p220-yoloop-run-transition-payload-v1",{runId:t.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.expectedRevision,expectedSnapshotHash:t.expectedSnapshotHash,next:s})}const T=new Set(["success","partial","blocked","failure","exhausted","cancelled"]),ce={created:["running","cancelling","exhausted"],running:["pausing","cancelling","success","partial","blocked","failure","exhausted"],pausing:["paused","cancelling","failure","exhausted"],paused:["resuming","cancelling","exhausted"],resuming:["running","cancelling","failure","exhausted"],cancelling:["cancelled","failure","exhausted"]};function de(t,e){return e==="pause"?t==="running"?"pausing":null:e==="resume"?t==="paused"?"resuming":null:T.has(t)||t==="cancelling"?null:"cancelling"}function le(t){const e=t.current.revision+1,s=t.action==="cancel"?["YOLOOP_RUN_CANCEL_REQUESTED"]:[],n={schemaVersion:"YoloopOperationalBudgetSummary/1.0",limits:t.current.operationalBudget.limits,usage:t.current.usage,exhaustedDimension:null},o={schemaVersion:"ProgressSnapshot/1.0",runId:t.current.runId,sequence:t.current.progressSnapshots.length+1,revision:e,operationId:t.operationId,boundary:t.action,phase:"before",status:t.current.status,occurredAt:t.occurredAt,parentSnapshotHash:t.current.latestSnapshotHash,budget:n,reasonCodes:s,publicSafe:!0},r=p("p220-yoloop-progress-snapshot-id-v1",{runId:o.runId,operationId:o.operationId,sequence:o.sequence,phase:o.phase}),c={...o,snapshotId:r,snapshotHash:p("p220-yoloop-progress-snapshot-v1",{...o,snapshotId:r})},a={...o,sequence:c.sequence+1,phase:"after",status:t.target,parentSnapshotHash:c.snapshotHash},i=p("p220-yoloop-progress-snapshot-id-v1",{runId:a.runId,operationId:a.operationId,sequence:a.sequence,phase:a.phase}),l={...a,snapshotId:i,snapshotHash:p("p220-yoloop-progress-snapshot-v1",{...a,snapshotId:i})},h={schemaVersion:"YoloopRunEvent/1.0",runId:t.current.runId,operationId:t.operationId,kind:"intent",sequence:t.current.events.length+1,revision:e,occurredAt:t.occurredAt,fromStatus:t.current.status,toStatus:t.target,reasonCodes:s,budgetDimension:null,parentEventHash:t.current.events.at(-1)?.eventHash??null,publicSafe:!0},O=p("p220-yoloop-run-event-id-v1",{runId:h.runId,operationId:h.operationId,sequence:h.sequence}),y={...h,eventId:O,eventHash:p("p220-yoloop-run-event-v1",{...h,eventId:O})},I={...t.current,revision:e,status:t.target,events:[...t.current.events,y],progressSnapshots:[...t.current.progressSnapshots,c,l],latestSnapshotHash:l.snapshotHash,receipts:[...t.current.receipts]},_={runId:t.current.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,expectedRevision:t.current.revision,expectedSnapshotHash:t.current.latestSnapshotHash,next:I},C=D(_),b={schemaVersion:"YoloopRunTransitionReceipt/1.0",runId:t.current.runId,operationId:t.operationId,idempotencyKey:t.idempotencyKey,payloadHash:C,revision:e,snapshotHash:l.snapshotHash,status:t.target};return{type:"transition_run",..._,payloadHash:C,next:{...I,receipts:[...I.receipts,b]}}}function N(t){const e=/^[A-Za-z0-9._:-]{1,128}$/;if(!e.test(t.runId)||!e.test(t.operationId)||!e.test(t.idempotencyKey)||!/^[a-f0-9]{64}$/.test(t.payloadHash)||!Number.isSafeInteger(t.expectedRevision)||t.expectedRevision<0)throw new Error("YOLOOP_RUN_OPERATION_CONFLICT");if(t.payloadHash!==D(t))throw new Error("YOLOOP_RUN_OPERATION_CONFLICT")}function L(t,e){const s=e.next,n=t?.events??[],o=t?.progressSnapshots??[],r=t?.receipts??[];if(s.schemaVersion!=="YoloopRunControl/1.0"||s.runId!==e.runId||s.revision!==e.expectedRevision+1||s.events.length!==n.length+1||s.progressSnapshots.length!==o.length+2||s.receipts.length!==r.length+1||d(s.events.slice(0,n.length))!==d(n)||d(s.progressSnapshots.slice(0,o.length))!==d(o)||d(s.receipts.slice(0,r.length))!==d(r))throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(t){if(T.has(t.status))throw new Error("YOLOOP_RUN_TERMINAL");const h=s.progressSnapshots.at(-2)?.boundary,O=t.status===s.status&&(h==="budget"||h==="retry");if(!(ce[t.status]??[]).includes(s.status)&&!O)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(t.startedAt!==s.startedAt||t.deadlineAt!==s.deadlineAt)throw new Error("YOLOOP_RUN_TRANSITION_INVALID");if(d(t.predecessor)!==d(s.predecessor))throw new Error("YOLOOP_RUN_TRANSITION_INVALID")}else if(s.status!=="created")throw new Error("YOLOOP_RUN_TRANSITION_INVALID");const c=s.progressSnapshots.at(-2),a=s.progressSnapshots.at(-1),i=s.events.at(-1),l=s.receipts.at(-1);if(!c||!a||!i||!l||c.phase!=="before"||a.phase!=="after"||c.operationId!==e.operationId||a.operationId!==e.operationId||i.operationId!==e.operationId||c.runId!==e.runId||a.runId!==e.runId||i.runId!==e.runId||c.revision!==s.revision||a.revision!==s.revision||i.revision!==s.revision||c.parentSnapshotHash!==(t?.latestSnapshotHash??null)||a.parentSnapshotHash!==c.snapshotHash||s.latestSnapshotHash!==a.snapshotHash||l.schemaVersion!=="YoloopRunTransitionReceipt/1.0"||l.runId!==e.runId||l.operationId!==e.operationId||l.idempotencyKey!==e.idempotencyKey||l.payloadHash!==e.payloadHash||l.revision!==s.revision||l.snapshotHash!==s.latestSnapshotHash||l.status!==s.status||Date.parse(s.deadlineAt)<=Date.parse(s.startedAt))throw new Error("YOLOOP_RUN_TRANSITION_INVALID");F(c),F(a),ue(i,n.at(-1)?.eventHash??null)}function F(t){const{snapshotHash:e,...s}=t;if(e!==p("p220-yoloop-progress-snapshot-v1",s))throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT")}function ue(t,e){const{eventHash:s,...n}=t;if(t.parentEventHash!==e||s!==p("p220-yoloop-run-event-v1",n))throw new Error("YOLOOP_RUN_SNAPSHOT_CONFLICT")}function he(t,e){return`lease-${pe(`${t}:${e}`)}`}function pe(t){let e=2166136261;for(let s=0;s<t.length;s+=1)e^=t.charCodeAt(s),e=Math.imul(e,16777619)>>>0;return e.toString(36).padStart(7,"0")}function K(t,e){const s=t.leaseExpiresAt??t.ttlExpiresAt,n=Date.parse(s),o=Date.parse(e);return!Number.isFinite(n)||!Number.isFinite(o)?"unknown":n<=o?"expired":"active"}function Oe(t,e){const s=f(e);return{...t,version:t.version==="1.2"?"1.2":"1.1",lastResetAt:t.lastResetAt??s.lastResetAt,storiesRunToday:t.storiesRunToday??0,iterationsToday:t.iterationsToday??0,iterationsTodayDate:t.iterationsTodayDate??s.iterationsTodayDate,tokensUsedToday:t.tokensUsedToday??0,lastRunAt:t.lastRunAt??null,coolDownUntil:t.coolDownUntil??null,totalRunsAllTime:t.totalRunsAllTime??0,totalStoriesAllTime:t.totalStoriesAllTime??0,currentSession:t.currentSession??null,...t.runControl!==void 0?{runControl:t.runControl}:{},...t.continuationPolicy!==void 0?{continuationPolicy:t.continuationPolicy}:{},...t.continuationSession!==void 0?{continuationSession:t.continuationSession}:{},...t.pendingContinuationAuthorities!==void 0?{pendingContinuationAuthorities:t.pendingContinuationAuthorities}:{},...t.continuationReceipts!==void 0?{continuationReceipts:t.continuationReceipts}:{},...t.continuationRecoveryReceipts!==void 0?{continuationRecoveryReceipts:t.continuationRecoveryReceipts}:{},...t.continuationReplanReceipts!==void 0?{continuationReplanReceipts:t.continuationReplanReceipts}:{},recovery_history:Array.isArray(t.recovery_history)?M(t.recovery_history):[]}}function M(t){return t.length<=m?t:t.slice(t.length-m)}export{x as YOLOOP_PERSISTENCE_CAPABILITIES,ve as YoloopClientStateStore,Q as buildYoloopContinuationReplanPayloadHash,D as buildYoloopRunTransitionPayloadHash,te as buildYoloopSessionRolloverPayloadHash,se as buildYoloopSuccessorRunPayloadHash,ne as buildYoloopSuccessorTransitionPayloadHash,M as capRecoveryHistory,f as createDefaultCounters,Re as createDefaultState,ee as fingerprintYoloopSession};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: neocortex-root
|
|
3
|
-
description: "🧠 Neocortex Root Agent v4.60.
|
|
3
|
+
description: "🧠 Neocortex Root Agent v4.60.59 | OrNexus Team"
|
|
4
4
|
model: opus
|
|
5
5
|
color: blue
|
|
6
6
|
tools:
|
|
@@ -108,7 +108,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
|
|
|
108
108
|
┌────────────────────────────────────────────────────────────┐
|
|
109
109
|
│ │
|
|
110
110
|
│ ####### N E O C O R T E X │
|
|
111
|
-
│ ### ######## v4.60.
|
|
111
|
+
│ ### ######## v4.60.59 │
|
|
112
112
|
│ ######### ##### │
|
|
113
113
|
│ ## ############## Development Orchestrator │
|
|
114
114
|
│ ## ### ###### ## OrNexus Team │
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: neocortex
|
|
3
|
-
description: "🧠 Neocortex v4.60.
|
|
3
|
+
description: "🧠 Neocortex v4.60.59 | OrNexus Team"
|
|
4
4
|
model: opus
|
|
5
5
|
color: blue
|
|
6
6
|
permissionMode: bypassPermissions
|
|
@@ -104,7 +104,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
|
|
|
104
104
|
┌────────────────────────────────────────────────────────────┐
|
|
105
105
|
│ │
|
|
106
106
|
│ ####### N E O C O R T E X │
|
|
107
|
-
│ ### ######## v4.60.
|
|
107
|
+
│ ### ######## v4.60.59 │
|
|
108
108
|
│ ######### ##### │
|
|
109
109
|
│ ## ############## Development Orchestrator │
|
|
110
110
|
│ ## ### ###### ## OrNexus Team │
|
|
@@ -28,7 +28,7 @@ Codex built-in commands or actions.
|
|
|
28
28
|
|
|
29
29
|
<!-- END: Plugin Conflict Prevention -->
|
|
30
30
|
|
|
31
|
-
# Neocortex v4.60.
|
|
31
|
+
# Neocortex v4.60.59 | OrNexus Team
|
|
32
32
|
|
|
33
33
|
You are a Development Orchestrator. All orchestration logic is delivered by the remote Neocortex server.
|
|
34
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: neocortex
|
|
3
|
-
description: "🧠 Neocortex v4.60.
|
|
3
|
+
description: "🧠 Neocortex v4.60.59 | OrNexus Team"
|
|
4
4
|
model: inherit
|
|
5
5
|
readonly: false
|
|
6
6
|
is_background: false
|
|
@@ -64,7 +64,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
|
|
|
64
64
|
┌────────────────────────────────────────────────────────────┐
|
|
65
65
|
│ │
|
|
66
66
|
│ ####### N E O C O R T E X │
|
|
67
|
-
│ ### ######## v4.60.
|
|
67
|
+
│ ### ######## v4.60.59 │
|
|
68
68
|
│ ######### ##### │
|
|
69
69
|
│ ## ############## Development Orchestrator │
|
|
70
70
|
│ ## ### ###### ## OrNexus Team │
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: neocortex-root
|
|
3
|
-
description: "🧠 Neocortex v4.60.
|
|
3
|
+
description: "🧠 Neocortex v4.60.59 | OrNexus Team"
|
|
4
4
|
kind: local
|
|
5
5
|
tools:
|
|
6
6
|
# File operations (Gemini CLI built-ins)
|
|
@@ -62,7 +62,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
|
|
|
62
62
|
┌────────────────────────────────────────────────────────────┐
|
|
63
63
|
│ │
|
|
64
64
|
│ ####### N E O C O R T E X │
|
|
65
|
-
│ ### ######## v4.60.
|
|
65
|
+
│ ### ######## v4.60.59 │
|
|
66
66
|
│ ######### ##### │
|
|
67
67
|
│ ## ############## Development Orchestrator │
|
|
68
68
|
│ ## ### ###### ## OrNexus Team │
|
|
@@ -58,7 +58,7 @@ explicit server opt-in rather than a local assumption.
|
|
|
58
58
|
┌────────────────────────────────────────────────────────────┐
|
|
59
59
|
│ │
|
|
60
60
|
│ ####### N E O C O R T E X │
|
|
61
|
-
│ ### ######## v4.60.
|
|
61
|
+
│ ### ######## v4.60.59 │
|
|
62
62
|
│ ######### ##### │
|
|
63
63
|
│ ## ############## Development Orchestrator │
|
|
64
64
|
│ ## ### ###### ## OrNexus Team │
|