@ornexus/neocortex 4.60.42 → 4.60.43

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.
@@ -1,9 +1,9 @@
1
- import{YoloopClientStateStore as j}from"./yoloop-client-state-store.js";import{isYoloopInvocation as F}from"./target-normalization.js";import{applyStateMigration as T,StateMigrationApplyError as M}from"../migrations/state-json.js";function N(e){return F(e)}const V=/^\s*\*?(yoloop|auto-yolo|epic-runner|story-runner|loop-yolo|auto-epic)\b/i;function Z(e){if(typeof e.args!="string"||e.args.length===0)return;const r=e.args.match(V);if(!r)return;const i=r[0];if(e.args.slice(i.length).trim()!=="")return;let a=!1;try{const o=require("node:fs"),d=require("node:path").join(e.projectRoot,"docs","epics");a=o.statSync(d).isDirectory()}catch(o){const c=o instanceof Error?o.message:String(o);e.logger?.warn?.(`[Neocortex] Zero-config *yoloop hook (P121.05): could not stat docs/epics/: ${c}. Proceeding with raw args.`);return}a&&(e.args=`${i} @docs/epics/`,e.logger?.info?.("[Neocortex] Zero-config *yoloop (P121.05): auto-resolved empty args to @docs/epics/"))}async function B(e,r,i){if(N(e))try{return await new j(r).readAll(i)}catch(t){process.stderr.write(`[yoloop] Failed to read local state: ${t.message}. Continuing without state.
2
- `);return}}async function L(e,r,i){if(!e)return;const t=e.yoloopStateUpdate;if(!(!t||!Array.isArray(t.operations)||t.operations.length===0))try{await new j(r).applyUpdate(t,i)}catch(a){const o=a.message??String(a);process.stderr.write(`[yoloop] Failed to persist state: ${o}. Your next *yoloop may repeat or skip an operation. Run *yoloop again to retry.
3
- `)}}function n(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function z(e,r){return Array.isArray(e)&&e.length<=r&&e.every(i=>typeof i=="string"&&i.length>0&&i.length<=160&&/^[A-Za-z0-9_.:+-]+$/.test(i))}function R(e){return n(e.scope)?e.scope.kind==="projected"||typeof e.scope.omittedStoryCount=="number"&&e.scope.omittedStoryCount>0||typeof e.scope.omittedEpicCount=="number"&&e.scope.omittedEpicCount>0:!1}function H(e){const r={...e};return delete r.scope,delete r.stateSummary,delete r.graphRetrieval,delete r.runnerBootstrap,delete r.projectEvidence,delete r.continuity,delete r.implementCheckpoint,r}function D(e){return typeof e=="string"&&["done","completed","merged"].includes(e.trim().toLowerCase())}async function G(e,r){const i=e.syntheticStory;if(!n(i))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-mutation-missing"};const t=i.storyId,a=i.storyPath,o=i.deterministicKey,c=i.storyContent;if(typeof t!="string"||!/^P\d+(?:\.\d+){2}$/.test(t)||typeof a!="string"||a!==`docs/stories/${t}.story.md`||typeof o!="string"||!/^[a-f0-9]{16}$/.test(o)||typeof c!="string"||c.length===0||c.length>131072||i.publicSafe!==!0||i.sanitized!==!0)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-mutation-invalid"};const d=await import("node:fs/promises"),u=await import("node:path"),O=await import("node:crypto"),b=u.join(r,".neocortex"),w=u.join(b,"state.json"),h=u.join(r,...a.split("/"));let I;try{I=await d.readFile(w,"utf8")}catch{return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-missing"}}let p;try{p=JSON.parse(I)}catch{return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-corrupt"}}if(!n(p)||!n(p.stories)||!n(p.epics)||R(p))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-not-full"};const s=p.stories[t];if(s!==void 0&&(!n(s)||s.epic_id!=="P174"||s.story_file!==a||!n(s.inlineYolo)||s.inlineYolo.deterministicKey!==o))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-conflict"};const g=p.epics.P174;if(g!==void 0&&(!n(g)||g.id!==void 0&&g.id!=="P174"||!Array.isArray(g.stories)))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-conflict"};const k=n(g)?g:{},f=Array.isArray(k.stories)?k.stories:[];if(f.some(l=>typeof l!="string")||new Set(f).size!==f.length)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-story-list-invalid"};for(const l of f){const m=p.stories[l];if(!n(m)||m.id!==l||m.epic_id!=="P174")return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-ownership-conflict"}}try{const l=await d.readFile(h,"utf8"),m=l.includes(`id: ${t}`)&&l.includes(`synthetic_key: ${o}`);if(l!==c&&!m)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-file-conflict"}}catch(l){if(l.code!=="ENOENT")return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-file-unreadable"}}const y=f.includes(t)?[...f]:[...f,t],S={...p.stories,[t]:{...n(s)?s:{},id:t,epic_id:"P174",title:"Synthetic inline USER STORY for yolo",status:n(s)&&typeof s.status=="string"?s.status:"backlog",steps_completed:n(s)&&Array.isArray(s.steps_completed)?s.steps_completed:[],last_step:n(s)?s.last_step??null:null,branch_name:n(s)?s.branch_name??null:null,story_file:a,source:"inline-yolo-materialization",inlineYolo:{...n(s)&&n(s.inlineYolo)?s.inlineYolo:{},schemaVersion:1,deterministicKey:o,publicSafe:!0,sanitized:!0,materializedBeforeExecution:!0,ephemeralExecutionForbidden:!0}}},C=y.filter(l=>n(S[l])&&D(S[l].status)).length,P=n(p.inlineYolo)?p.inlineYolo:{},Y=n(P.materializations)?P.materializations:{},x=H({...p,stories:S,epics:{...p.epics,P174:{...k,id:"P174",status:C===y.length&&y.length>0?"done":"in-progress",stories:y,total_stories:y.length,completed_stories:C,...C===y.length&&y.length>0?{}:{completed_at:null}}},inlineYolo:{...P,schemaVersion:1,materializations:{...Y,[t]:{schemaVersion:1,storyId:t,storyPath:a,deterministicKey:o,publicSafe:!0,sanitized:!0,materializedBeforeExecution:!0,ephemeralExecutionForbidden:!0,pipelineTrigger:`*yolo @${a}`,reasonCodes:Array.isArray(i.reasonCodes)?i.reasonCodes:[]}}},last_updated:new Date().toISOString()}),_=`${Date.now()}-${O.randomBytes(6).toString("hex")}`,A=u.join(b,`state.json.tmp.${_}`),$=`${h}.tmp.${_}`,E=u.join(b,`state.json.backup-${new Date().toISOString().replace(/[:.]/g,"-")}`);let v=!1;try{await d.mkdir(b,{recursive:!0}),await d.mkdir(u.dirname(h),{recursive:!0});try{await d.access(h)}catch{await d.writeFile($,c,{encoding:"utf8",flag:"wx"}),await d.rename($,h),v=!0}return await d.copyFile(w,E),await d.writeFile(A,JSON.stringify(x,null,2),{encoding:"utf8",flag:"wx"}),await d.rename(A,w),process.stderr.write(`[Neocortex] inline yolo story materialized with bounded full-state merge; story=${t}; backup=${u.basename(E)}.
1
+ import{statSync as F}from"node:fs";import{join as T}from"node:path";import{YoloopClientStateStore as j}from"./yoloop-client-state-store.js";import{isYoloopInvocation as M}from"./target-normalization.js";import{applyStateMigration as N,StateMigrationApplyError as V}from"../migrations/state-json.js";function H(e){return M(e)}const D=/^\s*\*?(yoloop|auto-yolo|epic-runner|story-runner|loop-yolo|auto-epic)\b/i;function Q(e){if(typeof e.args!="string"||e.args.length===0)return;const r=e.args.match(D);if(!r)return;const i=r[0];if(e.args.slice(i.length).trim()!=="")return;let a=!1;try{const o=T(e.projectRoot,"docs","epics");a=F(o).isDirectory()}catch(o){const c=o instanceof Error?o.message:String(o);e.logger?.warn?.(`[Neocortex] Zero-config *yoloop hook (P121.05): could not stat docs/epics/: ${c}. Proceeding with raw args.`);return}a&&(e.args=`${i} @docs/epics/`,e.logger?.info?.("[Neocortex] Zero-config *yoloop (P121.05): auto-resolved empty args to @docs/epics/"))}async function W(e,r,i){if(H(e))try{return await new j(r).readAll(i)}catch(t){process.stderr.write(`[yoloop] Failed to read local state: ${t.message}. Continuing without state.
2
+ `);return}}async function X(e,r,i){if(!e)return;const t=e.yoloopStateUpdate;if(!(!t||!Array.isArray(t.operations)||t.operations.length===0))try{await new j(r).applyUpdate(t,i)}catch(a){const o=a.message??String(a);process.stderr.write(`[yoloop] Failed to persist state: ${o}. Your next *yoloop may repeat or skip an operation. Run *yoloop again to retry.
3
+ `)}}function n(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function z(e,r){return Array.isArray(e)&&e.length<=r&&e.every(i=>typeof i=="string"&&i.length>0&&i.length<=160&&/^[A-Za-z0-9_.:+-]+$/.test(i))}function R(e){return n(e.scope)?e.scope.kind==="projected"||typeof e.scope.omittedStoryCount=="number"&&e.scope.omittedStoryCount>0||typeof e.scope.omittedEpicCount=="number"&&e.scope.omittedEpicCount>0:!1}function G(e){const r={...e};return delete r.scope,delete r.stateSummary,delete r.graphRetrieval,delete r.runnerBootstrap,delete r.projectEvidence,delete r.continuity,delete r.implementCheckpoint,r}function U(e){return typeof e=="string"&&["done","completed","merged"].includes(e.trim().toLowerCase())}async function K(e,r){const i=e.syntheticStory;if(!n(i))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-mutation-missing"};const t=i.storyId,a=i.storyPath,o=i.deterministicKey,c=i.storyContent;if(typeof t!="string"||!/^P\d+(?:\.\d+){2}$/.test(t)||typeof a!="string"||a!==`docs/stories/${t}.story.md`||typeof o!="string"||!/^[a-f0-9]{16}$/.test(o)||typeof c!="string"||c.length===0||c.length>131072||i.publicSafe!==!0||i.sanitized!==!0)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-mutation-invalid"};const d=await import("node:fs/promises"),u=await import("node:path"),O=await import("node:crypto"),b=u.join(r,".neocortex"),w=u.join(b,"state.json"),h=u.join(r,...a.split("/"));let I;try{I=await d.readFile(w,"utf8")}catch{return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-missing"}}let p;try{p=JSON.parse(I)}catch{return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-corrupt"}}if(!n(p)||!n(p.stories)||!n(p.epics)||R(p))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-state-not-full"};const s=p.stories[t];if(s!==void 0&&(!n(s)||s.epic_id!=="P174"||s.story_file!==a||!n(s.inlineYolo)||s.inlineYolo.deterministicKey!==o))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-conflict"};const g=p.epics.P174;if(g!==void 0&&(!n(g)||g.id!==void 0&&g.id!=="P174"||!Array.isArray(g.stories)))return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-conflict"};const k=n(g)?g:{},f=Array.isArray(k.stories)?k.stories:[];if(f.some(l=>typeof l!="string")||new Set(f).size!==f.length)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-story-list-invalid"};for(const l of f){const m=p.stories[l];if(!n(m)||m.id!==l||m.epic_id!=="P174")return{applied:!1,blocking:!0,reasonCode:"inline-yolo-epic-ownership-conflict"}}try{const l=await d.readFile(h,"utf8"),m=l.includes(`id: ${t}`)&&l.includes(`synthetic_key: ${o}`);if(l!==c&&!m)return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-file-conflict"}}catch(l){if(l.code!=="ENOENT")return{applied:!1,blocking:!0,reasonCode:"inline-yolo-story-file-unreadable"}}const y=f.includes(t)?[...f]:[...f,t],S={...p.stories,[t]:{...n(s)?s:{},id:t,epic_id:"P174",title:"Synthetic inline USER STORY for yolo",status:n(s)&&typeof s.status=="string"?s.status:"backlog",steps_completed:n(s)&&Array.isArray(s.steps_completed)?s.steps_completed:[],last_step:n(s)?s.last_step??null:null,branch_name:n(s)?s.branch_name??null:null,story_file:a,source:"inline-yolo-materialization",inlineYolo:{...n(s)&&n(s.inlineYolo)?s.inlineYolo:{},schemaVersion:1,deterministicKey:o,publicSafe:!0,sanitized:!0,materializedBeforeExecution:!0,ephemeralExecutionForbidden:!0}}},C=y.filter(l=>n(S[l])&&U(S[l].status)).length,P=n(p.inlineYolo)?p.inlineYolo:{},Y=n(P.materializations)?P.materializations:{},x=G({...p,stories:S,epics:{...p.epics,P174:{...k,id:"P174",status:C===y.length&&y.length>0?"done":"in-progress",stories:y,total_stories:y.length,completed_stories:C,...C===y.length&&y.length>0?{}:{completed_at:null}}},inlineYolo:{...P,schemaVersion:1,materializations:{...Y,[t]:{schemaVersion:1,storyId:t,storyPath:a,deterministicKey:o,publicSafe:!0,sanitized:!0,materializedBeforeExecution:!0,ephemeralExecutionForbidden:!0,pipelineTrigger:`*yolo @${a}`,reasonCodes:Array.isArray(i.reasonCodes)?i.reasonCodes:[]}}},last_updated:new Date().toISOString()}),_=`${Date.now()}-${O.randomBytes(6).toString("hex")}`,A=u.join(b,`state.json.tmp.${_}`),$=`${h}.tmp.${_}`,E=u.join(b,`state.json.backup-${new Date().toISOString().replace(/[:.]/g,"-")}`);let v=!1;try{await d.mkdir(b,{recursive:!0}),await d.mkdir(u.dirname(h),{recursive:!0});try{await d.access(h)}catch{await d.writeFile($,c,{encoding:"utf8",flag:"wx"}),await d.rename($,h),v=!0}return await d.copyFile(w,E),await d.writeFile(A,JSON.stringify(x,null,2),{encoding:"utf8",flag:"wx"}),await d.rename(A,w),process.stderr.write(`[Neocortex] inline yolo story materialized with bounded full-state merge; story=${t}; backup=${u.basename(E)}.
4
4
  `),{applied:!0,blocking:!1,reasonCode:"inline-yolo-materialized"}}catch(l){await Promise.allSettled([d.unlink(A),d.unlink($)]),v&&await d.unlink(h).catch(()=>{});const m=l.message??String(l);return process.stderr.write(`[Neocortex] inline yolo materialization failed: ${m}.
5
- `),{applied:!1,blocking:!0,reasonCode:"inline-yolo-persistence-failed"}}}async function J(e,r){if(!e||e.stateMutated!==!0)return{applied:!1,blocking:!1,reasonCode:"state-writeback-not-requested"};if(e.stateMutationStrategy==="merge-inline-yolo-v1"||e.stateMutationReason==="inline-yolo-materialized-synthetic-story")return G(e,r);if(e.stateMutationStrategy==="state-migration-v1"||e.stateMigrationPlan!==void 0){const t=e.stateMigrationPlan,a=new Set(["schemaVersion","operationId","sourceSchemaVersion","targetSchemaVersion","sourceCanonicalHash","targetCanonicalHash","steps","migratedEpicIds","migratedStoryIds","preservedUnknownFieldCount","reasonCodes"]);if(!n(t)||Object.keys(t).some(o=>!a.has(o))||t.schemaVersion!=="StateMigrationPlan/1.0"||typeof t.operationId!="string"||!/^smig_[a-f0-9]{32}$/.test(t.operationId)||typeof t.sourceCanonicalHash!="string"||!/^[a-f0-9]{64}$/.test(t.sourceCanonicalHash)||typeof t.targetCanonicalHash!="string"||!/^[a-f0-9]{64}$/.test(t.targetCanonicalHash)||![0,1,"absent"].includes(t.sourceSchemaVersion)||t.targetSchemaVersion!==1||!Array.isArray(t.steps)||t.steps.length>8192||t.steps.some(o=>!n(o)||Object.keys(o).some(c=>!["kind","source","target"].includes(c))||!["initialize-collection","merge-epic","merge-story","preserve-legacy","remove-legacy","set-schema-version"].includes(String(o.kind))||typeof o.target!="string"||o.target.length>512||!/^[A-Za-z0-9_.:[\]-]+$/.test(o.target)||o.source!==void 0&&(typeof o.source!="string"||o.source.length>512||!/^[A-Za-z0-9_.:[\]-]+$/.test(o.source)))||!z(t.migratedEpicIds,4096)||!z(t.migratedStoryIds,4096)||!z(t.reasonCodes,32)||!Number.isSafeInteger(t.preservedUnknownFieldCount)||t.preservedUnknownFieldCount<0)return{applied:!1,blocking:!0,reasonCode:"state-migration-plan-missing-or-invalid"};try{const o=T(r,t),c=`.neocortex/state.json.migration-backup-${o.operationId}`;return process.stderr.write(`[P220-EV-STATE-MIGRATION] outcome=${o.outcome}; operation=${o.operationId}; backup=${o.backupHash?c:"none"}.
6
- `),{applied:o.outcome==="applied",blocking:!1,reasonCode:o.outcome==="applied"?"state-migration-applied":"state-migration-replay-verified"}}catch(o){const c=o instanceof M?o.reasonCode:"state-migration-apply-failed";return process.stderr.write(`[P220-EV-STATE-MIGRATION] blocked=${c}.
5
+ `),{applied:!1,blocking:!0,reasonCode:"inline-yolo-persistence-failed"}}}async function ee(e,r){if(!e||e.stateMutated!==!0)return{applied:!1,blocking:!1,reasonCode:"state-writeback-not-requested"};if(e.stateMutationStrategy==="merge-inline-yolo-v1"||e.stateMutationReason==="inline-yolo-materialized-synthetic-story")return K(e,r);if(e.stateMutationStrategy==="state-migration-v1"||e.stateMigrationPlan!==void 0){const t=e.stateMigrationPlan,a=new Set(["schemaVersion","operationId","sourceSchemaVersion","targetSchemaVersion","sourceCanonicalHash","targetCanonicalHash","steps","migratedEpicIds","migratedStoryIds","preservedUnknownFieldCount","reasonCodes"]);if(!n(t)||Object.keys(t).some(o=>!a.has(o))||t.schemaVersion!=="StateMigrationPlan/1.0"||typeof t.operationId!="string"||!/^smig_[a-f0-9]{32}$/.test(t.operationId)||typeof t.sourceCanonicalHash!="string"||!/^[a-f0-9]{64}$/.test(t.sourceCanonicalHash)||typeof t.targetCanonicalHash!="string"||!/^[a-f0-9]{64}$/.test(t.targetCanonicalHash)||![0,1,"absent"].includes(t.sourceSchemaVersion)||t.targetSchemaVersion!==1||!Array.isArray(t.steps)||t.steps.length>8192||t.steps.some(o=>!n(o)||Object.keys(o).some(c=>!["kind","source","target"].includes(c))||!["initialize-collection","merge-epic","merge-story","preserve-legacy","remove-legacy","set-schema-version"].includes(String(o.kind))||typeof o.target!="string"||o.target.length>512||!/^[A-Za-z0-9_.:[\]-]+$/.test(o.target)||o.source!==void 0&&(typeof o.source!="string"||o.source.length>512||!/^[A-Za-z0-9_.:[\]-]+$/.test(o.source)))||!z(t.migratedEpicIds,4096)||!z(t.migratedStoryIds,4096)||!z(t.reasonCodes,32)||!Number.isSafeInteger(t.preservedUnknownFieldCount)||t.preservedUnknownFieldCount<0)return{applied:!1,blocking:!0,reasonCode:"state-migration-plan-missing-or-invalid"};try{const o=N(r,t),c=`.neocortex/state.json.migration-backup-${o.operationId}`;return process.stderr.write(`[P220-EV-STATE-MIGRATION] outcome=${o.outcome}; operation=${o.operationId}; backup=${o.backupHash?c:"none"}.
6
+ `),{applied:o.outcome==="applied",blocking:!1,reasonCode:o.outcome==="applied"?"state-migration-applied":"state-migration-replay-verified"}}catch(o){const c=o instanceof V?o.reasonCode:"state-migration-apply-failed";return process.stderr.write(`[P220-EV-STATE-MIGRATION] blocked=${c}.
7
7
  `),{applied:!1,blocking:!0,reasonCode:c}}}const i=e.migratedState;return!i||typeof i!="object"||Array.isArray(i)?{applied:!1,blocking:!0,reasonCode:"state-writeback-payload-missing"}:R(i)?(process.stderr.write(`[Neocortex] Refused projected/partial state replacement; canonical state was not modified.
8
8
  `),{applied:!1,blocking:!0,reasonCode:"state-writeback-partial-rejected"}):(process.stderr.write(`[P220-EV-STATE-MIGRATION] blocked=state-migration-plan-missing-or-invalid; canonical state was not modified.
9
- `),{applied:!1,blocking:!0,reasonCode:"state-migration-plan-missing-or-invalid"})}async function Q(e){if(!e.featureFlag)return{applied:!1,added:Object.freeze([]),skipped:Object.freeze([]),storiesAdded:0,reason:"flag off"};try{return await(await import("./discovery-hook.js")).runDiscoveryHook(e)}catch(r){const i=r instanceof Error?r.message:String(r);return e.logger?.warn?.(`[neocortex] discovery hook (lazy load) failed: ${i}. Proceeding without enrichment.`),{applied:!1,added:Object.freeze([]),skipped:Object.freeze([]),storiesAdded:0,reason:`lazy load error: ${i}`}}}async function W(e){if(!e.featureFlag)return{applied:!1,reason:"flag_off"};try{return await(await import("../graph-retrieval/pre-command-hook.js")).runGraphRetrievalHook(e)}catch(r){const i=r instanceof Error?r.message:String(r);return e.logger?.warn?.(`[neocortex] graph retrieval hook (lazy load) failed: ${i}. Proceeding without enrichment.`),{applied:!1,reason:"hook_error",warning:i}}}export{N as isYoloopTrigger,Z as maybeAutoResolveYoloopArgs,Q as maybeRunDiscoveryHook,W as maybeRunGraphRetrievalHook,J as persistMigratedStateFromResponse,L as persistYoloopFromResponse,B as readYoloopForRequest};
9
+ `),{applied:!1,blocking:!0,reasonCode:"state-migration-plan-missing-or-invalid"})}async function te(e){if(!e.featureFlag)return{applied:!1,added:Object.freeze([]),skipped:Object.freeze([]),storiesAdded:0,reason:"flag off"};try{return await(await import("./discovery-hook.js")).runDiscoveryHook(e)}catch(r){const i=r instanceof Error?r.message:String(r);return e.logger?.warn?.(`[neocortex] discovery hook (lazy load) failed: ${i}. Proceeding without enrichment.`),{applied:!1,added:Object.freeze([]),skipped:Object.freeze([]),storiesAdded:0,reason:`lazy load error: ${i}`}}}async function oe(e){if(!e.featureFlag)return{applied:!1,reason:"flag_off"};try{return await(await import("../graph-retrieval/pre-command-hook.js")).runGraphRetrievalHook(e)}catch(r){const i=r instanceof Error?r.message:String(r);return e.logger?.warn?.(`[neocortex] graph retrieval hook (lazy load) failed: ${i}. Proceeding without enrichment.`),{applied:!1,reason:"hook_error",warning:i}}}export{H as isYoloopTrigger,Q as maybeAutoResolveYoloopArgs,te as maybeRunDiscoveryHook,oe as maybeRunGraphRetrievalHook,ee as persistMigratedStateFromResponse,X as persistYoloopFromResponse,W as readYoloopForRequest};
@@ -271,9 +271,9 @@ export interface MergeResult {
271
271
  * preserved). Critical for `/loop` iteration which may re-invoke discovery
272
272
  * between stories.
273
273
  *
274
- * **Mutation semantics**: state is mutated in place for performance (state.json
275
- * can have hundreds of entries). Caller (P120.04 client hook) is responsible
276
- * for deep cloning before merge if needed for diffing/audit.
274
+ * **Mutation semantics**: merge work is staged on cloned maps and committed to
275
+ * the caller-owned container only after every identity and aggregate invariant
276
+ * passes. Validation failures therefore provide strong exception safety.
277
277
  *
278
278
  * @param state target state object (`null`/`undefined` ok -- treated as empty)
279
279
  * @param discovered discovery result (epics + warnings + skipped)
@@ -1 +1 @@
1
- const me=Object.freeze({epicId:"P{number}",epicFilename:"docs/epics/epic-P{number}.md",storyId:"P{number}.NN",storyFilename:"docs/stories/P{number}.NN.story.md",acceptedOnly:Object.freeze({epicFilenames:Object.freeze(["docs/epics/epic-{number}.md","docs/epics/EPIC-{number}-{slug}.md","docs/epics/EPIC-{number}_{slug}.md","docs/epics/epic-{slug}.md"]),storyFilenames:Object.freeze(["docs/stories/{number}.NN.story.md","docs/stories/story-P{number}.NN.md","docs/stories/story-{number}.NN.md","docs/stories/EPIC-{number}.STORY-{number}.md"])})}),E=Object.freeze([/^epic-(P?\d+(?:\.\d+)?)\.md$/i,/^EPIC-(\d+)(?:[-_].*)?\.md$/,/^epic-([a-z0-9][a-z0-9_-]*)\.md$/i]),j=Object.freeze([/^(P?\d+\.\d+(?:\.\d+)?)\.story\.md$/i,/^story-(P?\d+\.\d+)\.md$/i,/^EPIC-(\d+)\.STORY-(\d+)\.md$/]),k=Object.freeze([".archive","_archive","_archives","_drafts","archive","archives","archived","drafts"]),A=/^---\s*\n([\s\S]*?)\n---/;function w(t,e){const i=new RegExp(`^${e}:\\s*(.+?)\\s*$`,"mi"),n=t.match(i);if(!n)return;let c=n[1].trim();return(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'"))&&(c=c.slice(1,-1)),c||void 0}function M(t){if(typeof t!="string"||t.length===0)return{};const e=t.match(A);if(!e)return{};const i=e[1];return{id:w(i,"id"),title:w(i,"title"),status:w(i,"status"),epic_id:w(i,"epic_id"),depends_on:Q(i),files_to_modify:R(i,"files_to_modify"),total_stories:D(w(i,"total_stories"))}}const C=32,G=4096,Y=/^\s*\*\*([^*\r\n]+?):\*\*\s*(.*?)\s*$/,B=new Set(["backlog","pending","ready","planning","in-progress","done","completed","merged","cancelled","canceled","abandoned","draft","template","archived","branch-ready","diagnose","research","write-spec","create-tasks","implemented","refactor-suggest-done","property-tests-emitted","tests-validated","qa-gate-passed","memory-updated","committed","synced","pr-created","pr-reviewed","partial"]);function W(t){let e=t.trim();return e.startsWith("`")&&e.endsWith("`")&&e.length>=2&&(e=e.slice(1,-1).trim()),(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))&&(e=e.slice(1,-1).trim()),e}function D(t){if(t===void 0||!/^\d{1,5}$/.test(t.trim()))return;const e=Number(t);return Number.isSafeInteger(e)?e:void 0}function H(t){const e=W(t).toLowerCase().replace(/[_\s]+/g,"-"),n={planned:"planning",complete:"completed",closed:"done",finished:"done"}[e]??e;return B.has(n)?n:void 0}function U(t){const e=t.trim().toLowerCase().replace(/[_-]+/g," ").replace(/\s+/g," ");if(e==="id"||e==="epic id")return"id";if(e==="title"||e==="titulo")return"title";if(e==="status")return"status";if(e==="total stories"||e==="total de stories")return"total_stories"}function Z(t){const e=t.find(c=>/^#\s+\S/.test(c));if(!e)return;const i=e.replace(/^#\s+/,"").trim();return(i.replace(/^(?:Epic|Story)\s+\S+\s*(?:(?:--?|:)|[\u2013\u2014])\s*/i,"")||i).slice(0,200)}function v(t,e,i,n){const c=[...new Set(t.map(W).filter(Boolean))];if(c.length>1){n.push(`legacy metadata ambiguous for '${e}' in '${i}': conflicting values ignored`);return}return c[0]}function X(t,e){const i=[],n=[],c=t.slice(0,G).split(/\r?\n/,C);for(const d of c){if(n.length>0&&(/^\s*---\s*$/.test(d)||/^##\s+/.test(d)))break;n.push(d)}const o=new Map;for(const d of n){const g=d.match(Y);if(!g)continue;const m=U(g[1]);if(!m)continue;const u=o.get(m)??[];u.push(g[2]),o.set(m,u)}const l=v(o.get("id")??[],"id",e,i),f=v(o.get("title")??[],"title",e,i),h=v(o.get("status")??[],"status",e,i),_=v(o.get("total_stories")??[],"total_stories",e,i),p=h===void 0?void 0:H(h);h!==void 0&&p===void 0&&i.push(`legacy metadata status unrecognized in '${e}': value ignored`);const y=D(_);_!==void 0&&y===void 0&&i.push(`legacy metadata total_stories invalid in '${e}': value ignored`);const b=l&&/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(l)?l:void 0;l!==void 0&&b===void 0&&i.push(`legacy metadata id invalid in '${e}': value ignored`);const r=Z(n),s=f??r;return{metadata:{...b?{id:b}:{},...s?{title:s.slice(0,200)}:{},...p?{status:p}:{},...y!==void 0?{total_stories:y}:{}},source:"legacy-metadata",warnings:Object.freeze(i)}}function q(t){return/^[A-Za-z0-9._-]{1,160}$/.test(t)?t:"markdown-target.md"}function K(t){return new TextEncoder().encode(t).length}function V(t){let e=!1;for(const i of t.split(/\r?\n/)){if(!i.trim()||i.trimStart().startsWith("#"))continue;const n=i.match(/^\s+-\s+(.+?)\s*$/);if(n){if(!e)return!0;const l=n[1].trim();if(l.startsWith('"')&&!l.endsWith('"')||l.startsWith("'")&&!l.endsWith("'"))return!0;continue}if(/^\s+/.test(i))return!0;const c=i.match(/^[A-Za-z0-9_-]+:\s*(.*?)\s*$/);if(!c)return!0;const o=c[1].trim();if(e=o.length===0,o.startsWith('"')&&!o.endsWith('"')||o.startsWith("'")&&!o.endsWith("'"))return!0}return!1}function J(t,e,i){const n=q(e),c=t.match(A);if(!c)return Object.freeze([`metadata-frontmatter reason=frontmatter-malformed file='${n}': repair the bounded leading YAML envelope; source content omitted`]);const o=c[1];return K(o)>8*1024||o.split(/\r?\n/).length>128?Object.freeze([`metadata-frontmatter reason=frontmatter-oversized file='${n}': reduce the leading YAML envelope; source content omitted`]):V(o)||o.trim().length>0&&Object.keys(i).length===0?Object.freeze([`metadata-frontmatter reason=frontmatter-unsupported-value file='${n}': use bounded scalar fields or string lists; source content omitted`]):Object.freeze([])}function F(t,e){if(/^---(?:\s*\r?\n|\s*$)/.test(t)){const i=M(t);return{metadata:i,source:"frontmatter",warnings:J(t,e,i)}}return typeof t!="string"||t.length===0?{metadata:{},source:"none",warnings:Object.freeze([])}:X(t,e)}function L(t){let e=t.trim();if((e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))&&(e=e.slice(1,-1).trim()),!!e&&!/^(null|undefined|true|false)$/i.test(e))return e}function Q(t){return R(t,"depends_on")}function R(t,e){const i=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=t.match(new RegExp(`^${i}:[ \\t]*(.+?)[ \\t]*$`,"mi"))?.[1]?.trim();if(c!==void 0){const _=(c.startsWith("[")&&c.endsWith("]")?c.slice(1,-1).split(","):[c]).map(L).filter(p=>typeof p=="string"&&p.length>0);return _.length>0?Object.freeze(_):void 0}const o=t.split(/\r?\n/),l=[];let f=!1;for(const h of o){if(!f){new RegExp(`^${i}:\\s*$`,"i").test(h.trim())&&(f=!0);continue}if(/^[A-Za-z0-9_-]+:\s*/.test(h))break;const _=h.match(/^\s*-\s*(.+?)\s*$/);if(!_)continue;const p=L(_[1]);p&&l.push(p)}return l.length>0?Object.freeze(l):void 0}function N(t){return t.startsWith("_")||t.startsWith(".")}function ee(t){return k.includes(t)}async function ge(){const t=await import("node:fs"),e=await import("node:path");return{isDirectory(i){try{return t.statSync(i).isDirectory()}catch{return!1}},readdir(i){try{return t.readdirSync(i)}catch{return[]}},readFile(i){try{return t.readFileSync(i,"utf8")}catch{return""}},join(...i){try{return e.join(...i)}catch{return i.join("/")}}}}function te(t,e){let i=!1,n=null,c=null;for(let o=0;o<E.length;o++){const l=E[o],f=t.match(l);if(f){i=!0,n=f[1],c=o===2?"filename-slug":"filename-canonical";break}}return i?e.id&&e.id.length>0?{id:e.id,source:"frontmatter"}:{id:n,source:c}:null}function ie(t){for(const e of E){const i=t.match(e);if(i)return i[1]}return null}function O(t){const e=t.trim();return/^\d+(?:\.\d+)*$/i.test(e)?`P${e}`.toUpperCase():e.toUpperCase()}function ne(t){const e=O(t);return/^P\d+(?:\.\d+)?$/i.test(e)?`epic-${e}.md`:`epic-${t}.md`}function se(t){const e=O(t);return/^P\d+\.\d+(?:\.\d+)?$/i.test(e)?`${e}.story.md`:`${t}.story.md`}function P(t,e){return!t||!e?!1:O(t)!==O(e)}function re(t,e,i){return`frontmatter/filename mismatch: epic '${t}' has frontmatter id '${e}' but filename implies '${i}'. Repair by using generated canonical '${ne(e)}' or changing frontmatter id to '${i}'.`}function oe(t,e,i){return`frontmatter/filename mismatch: story '${t}' has frontmatter id '${e}' but filename implies '${i}'. Repair by using generated canonical '${se(e)}' or changing frontmatter id to '${i}'.`}function ce(t){let e=t.match(j[0]);if(e){const i=e[1],n=i.indexOf(".");return{id:i,epic_id_hint:n>0?i.slice(0,n):null}}if(e=t.match(j[1]),e){const i=e[1],n=i.indexOf(".");return{id:i,epic_id_hint:n>0?i.slice(0,n):null}}if(e=t.match(j[2]),e){const i=e[1],n=e[2];return{id:`${i}.${n}`,epic_id_hint:i}}return null}function ae(t,e){return e.join(t,"..","stories")}function he(t,e){const i=[],n=[],c=[],o=new Date().toISOString();if(typeof t!="string"||t.length===0)return Object.freeze({epics:Object.freeze([]),warnings:Object.freeze([]),skipped:Object.freeze([])});if(!e.isDirectory(t))return Object.freeze({epics:Object.freeze([]),warnings:Object.freeze([]),skipped:Object.freeze([])});const l=[...e.readdir(t)].sort(),f=[];for(const r of l){const s=e.join(t,r);if(N(r)){n.push(`${r}: ignored (draft or hidden prefix)`);continue}if(e.isDirectory(s)){if(ee(r)){n.push(`${r}: ignored subdirectory`);continue}n.push(`${r}: subdirectory not recursed`);continue}if(!r.endsWith(".md"))continue;if(!E.some(S=>S.test(r))){n.push(`${r}: did not match any EPIC_FILE_PATTERNS`);continue}const d=e.readFile(s),g=F(d,r);i.push(...g.warnings);const m=g.metadata,u=ie(r);m.id&&P(m.id,u)&&i.push(g.source==="frontmatter"?re(r,m.id,u):`legacy metadata/filename mismatch: epic '${r}' id does not match its filename`),f.push({filename:r,fullPath:s,metadata:m,metadataSource:g.source})}const h=new Map,_=[];for(const r of f){const s=te(r.filename,r.metadata);if(s===null){n.push(`${r.filename}: id resolution returned null`);continue}let a=s.id;const d=a,g=h.get(d)??0;g>0&&(a=`${d}-${g+1}`,i.push(`epic ID collision: '${d}' resolved to '${a}' for ${r.filename}`)),h.set(d,g+1),_.push({candidate:r,finalId:a,idSource:r.metadataSource==="legacy-metadata"&&r.metadata.id?"legacy-metadata":s.source})}const p=new Map,y=ae(t,e);if(e.isDirectory(y)){const r=[...e.readdir(y)].sort();for(const s of r){if(N(s)||!s.endsWith(".md"))continue;const a=e.join(y,s);if(e.isDirectory(a))continue;const d=ce(s);if(!d)continue;const g=e.readFile(a),m=F(g,s);i.push(...m.warnings);const u=m.metadata;u.id&&P(u.id,d.id)&&i.push(m.source==="frontmatter"?oe(s,u.id,d.id):`legacy metadata/filename mismatch: story '${s}' id does not match its filename`);const S=u.epic_id??d.epic_id_hint;if(!S){i.push(`story '${s}' has no epic_id (frontmatter or filename pattern)`);continue}const x=Object.freeze({id:d.id,epic_id:S,filename:s,path:a,...u.title?{title:u.title}:{},...u.status?{status:u.status}:{},...u.depends_on?{depends_on:u.depends_on}:{},...u.files_to_modify?{files_to_modify:u.files_to_modify}:{}});p.has(S)||p.set(S,[]),p.get(S).push(x)}}for(const r of _){const s=p.get(r.finalId)??[],a=Object.freeze({id:r.finalId,filename:r.candidate.filename,path:r.candidate.fullPath,...r.candidate.metadata.title?{title:r.candidate.metadata.title}:{},...r.candidate.metadata.status?{status:r.candidate.metadata.status}:{},...r.candidate.metadata.total_stories!==void 0?{total_stories:r.candidate.metadata.total_stories}:{},...r.candidate.metadata.depends_on?{depends_on:r.candidate.metadata.depends_on}:{},source:"discovered",discovered_at:o,stories:Object.freeze([...s]),t:r.idSource,e:r.candidate.metadataSource});c.push(a)}const b=new Set(c.map(r=>r.id));for(const[r,s]of p.entries())if(!b.has(r))for(const a of s)i.push(`orphan story '${a.filename}' references unknown epic '${r}'`);return Object.freeze({epics:Object.freeze(c),warnings:Object.freeze(i),skipped:Object.freeze(n)})}function de(t){return I(t)}function I(t){const e=ue(t);return e==="done"||e==="completed"||e==="merged"}function z(t){return I(t)}function ue(t){return typeof t=="string"?t.trim().toLowerCase().replace(/[_\s]+/g,"-"):""}function T(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function $(t){throw new Error(`epic-aggregate-writer:${t}`)}function fe(t){const e=[],i=new Set;for(const n of t)(typeof n!="string"||n.length===0)&&$("epic_aggregate_story_ref_invalid"),i.has(n)&&$("epic_aggregate_story_ref_duplicate"),i.add(n),e.push(n);return e}function le(t,e,i){const n=i[e];return n===void 0&&$("epic_aggregate_story_missing"),T(n)||$("epic_aggregate_story_not_object"),n.id!==e&&$("epic_aggregate_story_id_conflict"),n.epic_id!==t&&$("epic_aggregate_story_epic_conflict"),n}function pe(t,e,i,n,c){const o=e[t];T(o)||$("epic_aggregate_epic_not_object"),o.id!==t&&$("epic_aggregate_epic_id_conflict"),Array.isArray(o.stories)||$("epic_aggregate_story_list_not_array");const l=fe(o.stories),f=l.length,h=l.filter(s=>I(le(t,s,i).status)).length,_=c?.total_stories,p=c?.e==="legacy-metadata"&&z(o.status),y=p?_??f:f>0?f:_??0,b=p||f===0&&y>0&&z(o.status)?y:h,r=f>0&&h===f;z(o.status)&&!p&&!r&&f>0&&$("epic_aggregate_terminal_incomplete_conflict"),o.total_stories=y,o.completed_stories=b,!z(o.status)&&r&&(o.status="done",(o.completed_at===void 0||o.completed_at===null)&&(o.completed_at=n))}function _e(t,e,i){const n=t??{};(!n.epics||typeof n.epics!="object")&&(n.epics={}),(!n.stories||typeof n.stories!="object")&&(n.stories={});const c=n.epics,o=n.stories,l=[],f=[],h=new Set,_=new Map;let p=0;const y=i?.forceOverwrite===!0,b=i?.nowIso??new Date().toISOString(),r=new Set;for(const s of e.epics)r.add(s.id),_.set(s.id,s);for(const s of e.epics){const a=c[s.id],d=a;if(d&&(d.branch_mode==="epic"||typeof d.execution_branch=="string")){f.push({id:s.id,reason:"epic Git lifecycle preserved"});continue}if(a&&a.source==="create-epic"&&!y){f.push({id:s.id,reason:"create-epic source preserved (defense)"});continue}if(a&&a.source==="discovered"&&!y){const m=a;m.depends_on=s.depends_on??[],m.stories=s.stories.map(u=>u.id),s.title!==void 0&&(m.title=s.title),s.status!==void 0&&!z(m.status)&&(m.status=s.status),h.add(s.id);continue}const g={id:s.id,title:s.title??"",status:s.status??"planning",source:"discovered",discovered_at:b,merged_at:b,stories:s.stories.map(m=>m.id),depends_on:s.depends_on??[]};c[s.id]=g,h.add(s.id),l.push(s.id)}for(const s of e.epics)for(const a of s.stories){const d=o[a.id],g=c[s.id];if(d&&g&&(g.branch_mode==="epic"||typeof g.execution_branch=="string")){f.push({id:a.id,reason:"story Git lifecycle preserved"});continue}if(d&&d.source==="create-epic"&&!y){f.push({id:a.id,reason:"create-epic source preserved (defense, story)"});continue}if(d&&de(d.status)&&!y){const u=d;u.depends_on=a.depends_on??[],u.files_to_modify=a.files_to_modify??[];continue}if(d&&d.source==="discovered"&&!y){const u=d;u.depends_on=a.depends_on??[],u.files_to_modify=a.files_to_modify??[];continue}const m={id:a.id,epic_id:a.epic_id,title:a.title??"",status:a.status??"backlog",source:"discovered",discovered_at:b,depends_on:a.depends_on??[],files_to_modify:a.files_to_modify??[]};o[a.id]=m,p++}for(const s of h)pe(s,c,o,b,_.get(s));return{state:n,added:Object.freeze([...l]),skipped:Object.freeze([...f]),storiesAdded:p}}export{E as EPIC_FILE_PATTERNS,me as GENERATED_NAMING_CONTRACT,j as STORY_FILE_PATTERNS,ge as buildDefaultDiscoveryFs,he as discoverEpicsFromDir,te as getEpicIdFromDescriptor,_e as mergeDiscoveredIntoState};
1
+ const ge=Object.freeze({epicId:"P{number}",epicFilename:"docs/epics/epic-P{number}.md",storyId:"P{number}.NN",storyFilename:"docs/stories/P{number}.NN.story.md",acceptedOnly:Object.freeze({epicFilenames:Object.freeze(["docs/epics/epic-{number}.md","docs/epics/EPIC-{number}-{slug}.md","docs/epics/EPIC-{number}_{slug}.md","docs/epics/epic-{slug}.md"]),storyFilenames:Object.freeze(["docs/stories/{number}.NN.story.md","docs/stories/story-P{number}.NN.md","docs/stories/story-{number}.NN.md","docs/stories/EPIC-{number}.STORY-{number}.md"])})}),O=Object.freeze([/^epic-(P?\d+(?:\.\d+)?)\.md$/i,/^EPIC-(\d+)(?:[-_].*)?\.md$/,/^epic-([a-z0-9][a-z0-9_-]*)\.md$/i]),D=Object.freeze([/^(P?\d+\.\d+(?:\.\d+)?)\.story\.md$/i,/^story-(P?\d+\.\d+)\.md$/i,/^EPIC-(\d+)\.STORY-(\d+)\.md$/]),k=Object.freeze([".archive","_archive","_archives","_drafts","archive","archives","archived","drafts"]),F=/^---\s*\n([\s\S]*?)\n---/;function z(t,e){const i=new RegExp(`^${e}:\\s*(.+?)\\s*$`,"mi"),n=t.match(i);if(!n)return;let c=n[1].trim();return(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'"))&&(c=c.slice(1,-1)),c||void 0}function G(t){if(typeof t!="string"||t.length===0)return{};const e=t.match(F);if(!e)return{};const i=e[1];return{id:z(i,"id"),title:z(i,"title"),status:z(i,"status"),epic_id:z(i,"epic_id"),depends_on:te(i),files_to_modify:P(i,"files_to_modify"),total_stories:x(z(i,"total_stories"))}}const Y=32,B=4096,H=/^\s*\*\*([^*\r\n]+?):\*\*\s*(.*?)\s*$/,U=new Set(["backlog","pending","ready","planning","in-progress","done","completed","merged","cancelled","canceled","abandoned","draft","template","archived","branch-ready","diagnose","research","write-spec","create-tasks","implemented","refactor-suggest-done","property-tests-emitted","tests-validated","qa-gate-passed","memory-updated","committed","synced","pr-created","pr-reviewed","partial"]);function L(t){let e=t.trim();return e.startsWith("`")&&e.endsWith("`")&&e.length>=2&&(e=e.slice(1,-1).trim()),(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))&&(e=e.slice(1,-1).trim()),e}function x(t){if(t===void 0||!/^\d{1,5}$/.test(t.trim()))return;const e=Number(t);return Number.isSafeInteger(e)?e:void 0}function Z(t){const e=L(t).toLowerCase().replace(/[_\s]+/g,"-"),n={planned:"planning",complete:"completed",closed:"done",finished:"done"}[e]??e;return U.has(n)?n:void 0}function X(t){const e=t.trim().toLowerCase().replace(/[_-]+/g," ").replace(/\s+/g," ");if(e==="id"||e==="epic id")return"id";if(e==="title"||e==="titulo")return"title";if(e==="status")return"status";if(e==="total stories"||e==="total de stories")return"total_stories"}function q(t){const e=t.find(c=>/^#\s+\S/.test(c));if(!e)return;const i=e.replace(/^#\s+/,"").trim();return(i.replace(/^(?:Epic|Story)\s+\S+\s*(?:(?:--?|:)|[\u2013\u2014])\s*/i,"")||i).slice(0,200)}function j(t,e,i,n){const c=[...new Set(t.map(L).filter(Boolean))];if(c.length>1){n.push(`legacy metadata ambiguous for '${e}' in '${i}': conflicting values ignored`);return}return c[0]}function K(t,e){const i=[],n=[],c=t.slice(0,B).split(/\r?\n/,Y);for(const m of c){if(n.length>0&&(/^\s*---\s*$/.test(m)||/^##\s+/.test(m)))break;n.push(m)}const o=new Map;for(const m of n){const r=m.match(H);if(!r)continue;const a=X(r[1]);if(!a)continue;const d=o.get(a)??[];d.push(r[2]),o.set(a,d)}const f=j(o.get("id")??[],"id",e,i),l=j(o.get("title")??[],"title",e,i),_=j(o.get("status")??[],"status",e,i),g=j(o.get("total_stories")??[],"total_stories",e,i),p=_===void 0?void 0:Z(_);_!==void 0&&p===void 0&&i.push(`legacy metadata status unrecognized in '${e}': value ignored`);const b=x(g);g!==void 0&&b===void 0&&i.push(`legacy metadata total_stories invalid in '${e}': value ignored`);const $=f&&/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(f)?f:void 0;f!==void 0&&$===void 0&&i.push(`legacy metadata id invalid in '${e}': value ignored`);const s=q(n),u=l??s;return{metadata:{...$?{id:$}:{},...u?{title:u.slice(0,200)}:{},...p?{status:p}:{},...b!==void 0?{total_stories:b}:{}},source:"legacy-metadata",warnings:Object.freeze(i)}}function V(t){return/^[A-Za-z0-9._-]{1,160}$/.test(t)?t:"markdown-target.md"}function J(t){return new TextEncoder().encode(t).length}function Q(t){let e=!1;for(const i of t.split(/\r?\n/)){if(!i.trim()||i.trimStart().startsWith("#"))continue;const n=i.match(/^\s+-\s+(.+?)\s*$/);if(n){if(!e)return!0;const f=n[1].trim();if(f.startsWith('"')&&!f.endsWith('"')||f.startsWith("'")&&!f.endsWith("'"))return!0;continue}if(/^\s+/.test(i))return!0;const c=i.match(/^[A-Za-z0-9_-]+:\s*(.*?)\s*$/);if(!c)return!0;const o=c[1].trim();if(e=o.length===0,o.startsWith('"')&&!o.endsWith('"')||o.startsWith("'")&&!o.endsWith("'"))return!0}return!1}function ee(t,e,i){const n=V(e),c=t.match(F);if(!c)return Object.freeze([`metadata-frontmatter reason=frontmatter-malformed file='${n}': repair the bounded leading YAML envelope; source content omitted`]);const o=c[1];return J(o)>8*1024||o.split(/\r?\n/).length>128?Object.freeze([`metadata-frontmatter reason=frontmatter-oversized file='${n}': reduce the leading YAML envelope; source content omitted`]):Q(o)||o.trim().length>0&&Object.keys(i).length===0?Object.freeze([`metadata-frontmatter reason=frontmatter-unsupported-value file='${n}': use bounded scalar fields or string lists; source content omitted`]):Object.freeze([])}function N(t,e){if(/^---(?:\s*\r?\n|\s*$)/.test(t)){const i=G(t);return{metadata:i,source:"frontmatter",warnings:ee(t,e,i)}}return typeof t!="string"||t.length===0?{metadata:{},source:"none",warnings:Object.freeze([])}:K(t,e)}function R(t){let e=t.trim();if((e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))&&(e=e.slice(1,-1).trim()),!!e&&!/^(null|undefined|true|false)$/i.test(e))return e}function te(t){return P(t,"depends_on")}function P(t,e){const i=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=t.match(new RegExp(`^${i}:[ \\t]*(.+?)[ \\t]*$`,"mi"))?.[1]?.trim();if(c!==void 0){const g=(c.startsWith("[")&&c.endsWith("]")?c.slice(1,-1).split(","):[c]).map(R).filter(p=>typeof p=="string"&&p.length>0);return g.length>0?Object.freeze(g):void 0}const o=t.split(/\r?\n/),f=[];let l=!1;for(const _ of o){if(!l){new RegExp(`^${i}:\\s*$`,"i").test(_.trim())&&(l=!0);continue}if(/^[A-Za-z0-9_-]+:\s*/.test(_))break;const g=_.match(/^\s*-\s*(.+?)\s*$/);if(!g)continue;const p=R(g[1]);p&&f.push(p)}return f.length>0?Object.freeze(f):void 0}function T(t){return t.startsWith("_")||t.startsWith(".")}function ie(t){return k.includes(t)}async function he(){const t=await import("node:fs"),e=await import("node:path");return{isDirectory(i){try{return t.statSync(i).isDirectory()}catch{return!1}},readdir(i){try{return t.readdirSync(i)}catch{return[]}},readFile(i){try{return t.readFileSync(i,"utf8")}catch{return""}},join(...i){try{return e.join(...i)}catch{return i.join("/")}}}}function ne(t,e){let i=!1,n=null,c=null;for(let o=0;o<O.length;o++){const f=O[o],l=t.match(f);if(l){i=!0,n=l[1],c=o===2?"filename-slug":"filename-canonical";break}}return i?e.id&&e.id.length>0?{id:e.id,source:"frontmatter"}:{id:n,source:c}:null}function se(t){for(const e of O){const i=t.match(e);if(i)return i[1]}return null}function I(t){const e=t.trim();return/^\d+(?:\.\d+)*$/i.test(e)?`P${e}`.toUpperCase():e.toUpperCase()}function re(t){const e=I(t);return/^P\d+(?:\.\d+)?$/i.test(e)?`epic-${e}.md`:`epic-${t}.md`}function oe(t){const e=I(t);return/^P\d+\.\d+(?:\.\d+)?$/i.test(e)?`${e}.story.md`:`${t}.story.md`}function C(t,e){return!t||!e?!1:I(t)!==I(e)}function ce(t,e,i){return`frontmatter/filename mismatch: epic '${t}' has frontmatter id '${e}' but filename implies '${i}'. Repair by using generated canonical '${re(e)}' or changing frontmatter id to '${i}'.`}function ae(t,e,i){return`frontmatter/filename mismatch: story '${t}' has frontmatter id '${e}' but filename implies '${i}'. Repair by using generated canonical '${oe(e)}' or changing frontmatter id to '${i}'.`}function de(t){let e=t.match(D[0]);if(e){const i=e[1],n=i.indexOf(".");return{id:i,epic_id_hint:n>0?i.slice(0,n):null}}if(e=t.match(D[1]),e){const i=e[1],n=i.indexOf(".");return{id:i,epic_id_hint:n>0?i.slice(0,n):null}}if(e=t.match(D[2]),e){const i=e[1],n=e[2];return{id:`${i}.${n}`,epic_id_hint:i}}return null}function ue(t,e){return e.join(t,"..","stories")}function _e(t,e){const i=[],n=[],c=[],o=new Date().toISOString();if(typeof t!="string"||t.length===0)return Object.freeze({epics:Object.freeze([]),warnings:Object.freeze([]),skipped:Object.freeze([])});if(!e.isDirectory(t))return Object.freeze({epics:Object.freeze([]),warnings:Object.freeze([]),skipped:Object.freeze([])});const f=[...e.readdir(t)].sort(),l=[];for(const s of f){const u=e.join(t,s);if(T(s)){n.push(`${s}: ignored (draft or hidden prefix)`);continue}if(e.isDirectory(u)){if(ie(s)){n.push(`${s}: ignored subdirectory`);continue}n.push(`${s}: subdirectory not recursed`);continue}if(!s.endsWith(".md"))continue;if(!O.some(h=>h.test(s))){n.push(`${s}: did not match any EPIC_FILE_PATTERNS`);continue}const m=e.readFile(u),r=N(m,s);i.push(...r.warnings);const a=r.metadata,d=se(s);a.id&&C(a.id,d)&&i.push(r.source==="frontmatter"?ce(s,a.id,d):`legacy metadata/filename mismatch: epic '${s}' id does not match its filename`),l.push({filename:s,fullPath:u,metadata:a,metadataSource:r.source})}const _=new Map,g=[];for(const s of l){const u=ne(s.filename,s.metadata);if(u===null){n.push(`${s.filename}: id resolution returned null`);continue}let y=u.id;const m=y,r=_.get(m)??0;r>0&&(y=`${m}-${r+1}`,i.push(`epic ID collision: '${m}' resolved to '${y}' for ${s.filename}`)),_.set(m,r+1),g.push({candidate:s,finalId:y,idSource:s.metadataSource==="legacy-metadata"&&s.metadata.id?"legacy-metadata":u.source})}const p=new Map,b=ue(t,e);if(e.isDirectory(b)){const s=[...e.readdir(b)].sort();for(const u of s){if(T(u)||!u.endsWith(".md"))continue;const y=e.join(b,u);if(e.isDirectory(y))continue;const m=de(u);if(!m)continue;const r=e.readFile(y),a=N(r,u);i.push(...a.warnings);const d=a.metadata;d.id&&C(d.id,m.id)&&i.push(a.source==="frontmatter"?ae(u,d.id,m.id):`legacy metadata/filename mismatch: story '${u}' id does not match its filename`);const h=d.epic_id??m.epic_id_hint;if(!h){i.push(`story '${u}' has no epic_id (frontmatter or filename pattern)`);continue}const S=Object.freeze({id:m.id,epic_id:h,filename:u,path:y,...d.title?{title:d.title}:{},...d.status?{status:d.status}:{},...d.depends_on?{depends_on:d.depends_on}:{},...d.files_to_modify?{files_to_modify:d.files_to_modify}:{}});p.has(h)||p.set(h,[]),p.get(h).push(S)}}for(const s of g){const u=p.get(s.finalId)??[],y=Object.freeze({id:s.finalId,filename:s.candidate.filename,path:s.candidate.fullPath,...s.candidate.metadata.title?{title:s.candidate.metadata.title}:{},...s.candidate.metadata.status?{status:s.candidate.metadata.status}:{},...s.candidate.metadata.total_stories!==void 0?{total_stories:s.candidate.metadata.total_stories}:{},...s.candidate.metadata.depends_on?{depends_on:s.candidate.metadata.depends_on}:{},source:"discovered",discovered_at:o,stories:Object.freeze([...u]),t:s.idSource,e:s.candidate.metadataSource});c.push(y)}const $=new Set(c.map(s=>s.id));for(const[s,u]of p.entries())if(!$.has(s))for(const y of u)i.push(`orphan story '${y.filename}' references unknown epic '${s}'`);return Object.freeze({epics:Object.freeze(c),warnings:Object.freeze(i),skipped:Object.freeze(n)})}function M(t){const e=fe(t);return e==="done"||e==="completed"||e==="merged"}function A(t){return M(t)}function fe(t){return typeof t=="string"?t.trim().toLowerCase().replace(/[_\s]+/g,"-"):""}function E(t){return!!t&&typeof t=="object"&&!Array.isArray(t)}function w(t){throw new Error(`epic-aggregate-writer:${t}`)}function le(t){const e=[],i=new Set;for(const n of t)(typeof n!="string"||n.length===0)&&w("epic_aggregate_story_ref_invalid"),i.has(n)&&w("epic_aggregate_story_ref_duplicate"),i.add(n),e.push(n);return e}function pe(t,e,i){const n=i[e];return n===void 0&&w("epic_aggregate_story_missing"),E(n)||w("epic_aggregate_story_not_object"),n.id!==e&&w("epic_aggregate_story_id_conflict"),n.epic_id!==t&&w("epic_aggregate_story_epic_conflict"),n}function me(t,e,i,n,c){const o=e[t];E(o)||w("epic_aggregate_epic_not_object"),o.id!==t&&w("epic_aggregate_epic_id_conflict"),Array.isArray(o.stories)||w("epic_aggregate_story_list_not_array");const f=le(o.stories),l=f.length,_=f.filter(u=>M(pe(t,u,i).status)).length,g=c?.total_stories,p=c?.e==="legacy-metadata"&&A(o.status),b=p?g??l:l>0?l:g??0,$=p||l===0&&b>0&&A(o.status)?b:_,s=l>0&&_===l;A(o.status)&&!p&&!s&&l>0&&w("epic_aggregate_terminal_incomplete_conflict"),o.total_stories=b,o.completed_stories=$,!A(o.status)&&s&&(o.status="done",(o.completed_at===void 0||o.completed_at===null)&&(o.completed_at=n))}function ye(t,e,i){const n=t??{},c=E(n.epics)?n.epics:{},o=E(n.stories)?n.stories:{},f=structuredClone(c),l=structuredClone(o),_=[],g=[],p=new Set,b=new Map;let $=0;const s=i?.forceOverwrite===!0,u=i?.nowIso??new Date().toISOString(),y=new Set,m=new Map;for(const r of e.epics){if(!r.id||y.has(r.id))throw new Error("discovery_epic_identity_conflict");y.add(r.id),b.set(r.id,r);const a=f[r.id];if(a!==void 0&&(!E(a)||a.id!==void 0&&a.id!==r.id))throw new Error("discovery_epic_identity_conflict");for(const d of r.stories){if(!d.id||d.epic_id!==r.id||m.has(d.id))throw new Error("discovery_story_identity_conflict");m.set(d.id,r.id);const h=l[d.id];if(h!==void 0&&(!E(h)||h.id!==void 0&&h.id!==d.id||h.epic_id!==void 0&&h.epic_id!==r.id))throw new Error("discovery_story_identity_conflict")}}for(const r of e.epics){const a=f[r.id],d=a;if(d&&(d.branch_mode==="epic"||typeof d.execution_branch=="string")){g.push({id:r.id,reason:"epic Git lifecycle preserved"});continue}if(a&&a.source==="create-epic"&&!s){g.push({id:r.id,reason:"create-epic source preserved (defense)"});continue}if(a){const S=a;S.depends_on=r.depends_on??[];const v=Array.isArray(S.stories)?S.stories.filter(W=>typeof W=="string"):[];S.stories=[...new Set([...v,...r.stories.map(W=>W.id)])],r.title!==void 0&&(S.title=r.title),a.source!=="create-epic"&&p.add(r.id);continue}const h={id:r.id,title:r.title??"",status:r.status??"planning",source:"discovered",discovered_at:u,merged_at:u,stories:r.stories.map(S=>S.id),depends_on:r.depends_on??[]};f[r.id]=h,p.add(r.id),_.push(r.id)}for(const r of e.epics)for(const a of r.stories){const d=l[a.id],h=f[r.id];if(d&&h&&(h.branch_mode==="epic"||typeof h.execution_branch=="string")){g.push({id:a.id,reason:"story Git lifecycle preserved"});continue}if(d&&d.source==="create-epic"&&!s){g.push({id:a.id,reason:"create-epic source preserved (defense, story)"});continue}if(d){const v=d;a.title!==void 0&&(v.title=a.title),v.depends_on=a.depends_on??[],v.files_to_modify=a.files_to_modify??[];continue}const S={id:a.id,epic_id:a.epic_id,title:a.title??"",status:"backlog",source:"discovered",discovered_at:u,depends_on:a.depends_on??[],files_to_modify:a.files_to_modify??[]};l[a.id]=S,$++}for(const r of p)me(r,f,l,u,b.get(r));return n.epics=f,n.stories=l,{state:n,added:Object.freeze([..._]),skipped:Object.freeze([...g]),storiesAdded:$}}export{O as EPIC_FILE_PATTERNS,ge as GENERATED_NAMING_CONTRACT,D as STORY_FILE_PATTERNS,he as buildDefaultDiscoveryFs,_e as discoverEpicsFromDir,ne as getEpicIdFromDescriptor,ye as mergeDiscoveredIntoState};
@@ -1,4 +1,4 @@
1
- # 🧠 Neocortex v4.60.42 | OrNexus Team
1
+ # 🧠 Neocortex v4.60.43 | OrNexus Team
2
2
 
3
3
  This project uses Neocortex, a Development Orchestrator.
4
4
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: neocortex
3
- description: "🧠 Neocortex v4.60.42 | OrNexus Team"
3
+ description: "🧠 Neocortex v4.60.43 | OrNexus Team"
4
4
  ---
5
5
 
6
6
  <!--
@@ -4,7 +4,7 @@ agent:
4
4
  name: 'Neocortex Root Agent'
5
5
  title: 'Development Orchestrator (Root)'
6
6
  icon: '>'
7
- version: '4.60.42'
7
+ version: '4.60.43'
8
8
  architecture: 'thin-client'
9
9
  module: stand-alone
10
10
  hasSidecar: false
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: neocortex-root
3
- description: "🧠 Neocortex Root Agent v4.60.42 | OrNexus Team"
3
+ description: "🧠 Neocortex Root Agent v4.60.43 | 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.42 │
111
+ │ ### ######## v4.60.43 │
112
112
  │ ######### ##### │
113
113
  │ ## ############## Development Orchestrator │
114
114
  │ ## ### ###### ## OrNexus Team │
@@ -4,7 +4,7 @@ agent:
4
4
  name: 'Neocortex'
5
5
  title: 'Development Orchestrator'
6
6
  icon: '>'
7
- version: '4.60.42'
7
+ version: '4.60.43'
8
8
  architecture: 'thin-client'
9
9
  module: stand-alone
10
10
  hasSidecar: false
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: neocortex
3
- description: "🧠 Neocortex v4.60.42 | OrNexus Team"
3
+ description: "🧠 Neocortex v4.60.43 | 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.42 │
107
+ │ ### ######## v4.60.43 │
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.42 | OrNexus Team
31
+ # Neocortex v4.60.43 | 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.42 | OrNexus Team"
3
+ description: "🧠 Neocortex v4.60.43 | 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.42 │
67
+ │ ### ######## v4.60.43 │
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.42 | OrNexus Team"
3
+ description: "🧠 Neocortex v4.60.43 | 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.42 │
65
+ │ ### ######## v4.60.43 │
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.42 │
61
+ │ ### ######## v4.60.43 │
62
62
  │ ######### ##### │
63
63
  │ ## ############## Development Orchestrator │
64
64
  │ ## ### ###### ## OrNexus Team │
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "neocortex"
3
- description: "Neocortex v4.60.42 | OrNexus Team"
3
+ description: "Neocortex v4.60.43 | OrNexus Team"
4
4
  tools:
5
5
  # Read / Edit (built-in tool sets)
6
6
  - read
@@ -68,7 +68,7 @@ SEMPRE que este agente for invocado, imprima o banner abaixo como PRIMEIRO outpu
68
68
  ┌────────────────────────────────────────────────────────────┐
69
69
  │ │
70
70
  │ ####### N E O C O R T E X │
71
- │ ### ######## v4.60.42 │
71
+ │ ### ######## v4.60.43 │
72
72
  │ ######### ##### │
73
73
  │ ## ############## Development Orchestrator │
74
74
  │ ## ### ###### ## OrNexus Team │