@ornexus/neocortex 4.60.22 → 4.60.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/sbom.cdx.json +24 -24
  2. package/install.js +67 -10
  3. package/install.ps1 +39 -8
  4. package/install.sh +18 -6
  5. package/package.json +9 -3
  6. package/packages/client/dist/adapters/adapter-registry.d.ts +2 -2
  7. package/packages/client/dist/adapters/adapter-registry.js +1 -1
  8. package/packages/client/dist/adapters/grok-adapter.d.ts +11 -0
  9. package/packages/client/dist/adapters/grok-adapter.js +2 -0
  10. package/packages/client/dist/adapters/index.d.ts +1 -0
  11. package/packages/client/dist/adapters/index.js +1 -1
  12. package/packages/client/dist/adapters/platform-detector.d.ts +1 -1
  13. package/packages/client/dist/adapters/platform-detector.js +1 -1
  14. package/packages/client/dist/agent/refresh-stubs.js +2 -2
  15. package/packages/client/dist/cli.js +21 -2
  16. package/packages/client/dist/commands/invoke.d.ts +39 -26
  17. package/packages/client/dist/commands/invoke.js +56 -50
  18. package/packages/client/dist/commands/story-checkpoint.d.ts +15 -0
  19. package/packages/client/dist/commands/story-checkpoint.js +1 -0
  20. package/packages/client/dist/config.js +1 -1
  21. package/packages/client/dist/continuity/invoke-hooks.js +1 -1
  22. package/packages/client/dist/fs/atomic-state-replace.d.ts +16 -0
  23. package/packages/client/dist/fs/atomic-state-replace.js +1 -0
  24. package/packages/client/dist/generated/command-registry.generated.d.ts +51 -51
  25. package/packages/client/dist/generated/command-registry.generated.js +1 -1
  26. package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +67 -0
  27. package/packages/client/dist/git/direct-yolo-checkpoint.js +3 -0
  28. package/packages/client/dist/git/git-lifecycle-store.d.ts +198 -0
  29. package/packages/client/dist/git/git-lifecycle-store.js +4 -0
  30. package/packages/client/dist/git/secure-filesystem-boundary.d.ts +26 -0
  31. package/packages/client/dist/git/secure-filesystem-boundary.js +123 -0
  32. package/packages/client/dist/graph-retrieval/pre-command-hook.d.ts +11 -0
  33. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -1
  34. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -1
  35. package/packages/client/dist/index.d.ts +2 -0
  36. package/packages/client/dist/index.js +1 -1
  37. package/packages/client/dist/invocation/invoke-input.d.ts +9 -0
  38. package/packages/client/dist/invocation/invoke-input.js +1 -0
  39. package/packages/client/dist/memory/shared-project-memory-types.d.ts +29 -2
  40. package/packages/client/dist/memory/shared-project-memory-types.js +2 -2
  41. package/packages/client/dist/migrations/project-identity-capability.d.ts +13 -0
  42. package/packages/client/dist/migrations/project-identity-capability.js +1 -0
  43. package/packages/client/dist/migrations/project-identity.d.ts +41 -0
  44. package/packages/client/dist/migrations/project-identity.js +7 -0
  45. package/packages/client/dist/policy/subagent-approval-policy.js +1 -1
  46. package/packages/client/dist/runner/headless/continuous-story-workspace.d.ts +131 -0
  47. package/packages/client/dist/runner/headless/continuous-story-workspace.js +58 -0
  48. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.d.ts +23 -0
  49. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -0
  50. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +15 -0
  51. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +28 -0
  52. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +12 -0
  53. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -0
  54. package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +134 -0
  55. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -0
  56. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -1
  57. package/packages/client/dist/runner/headless/run-yolo.js +1 -1
  58. package/packages/client/dist/runner/headless/run-yoloop.d.ts +7 -2
  59. package/packages/client/dist/runner/headless/run-yoloop.js +8 -1
  60. package/packages/client/dist/runner/headless/types.d.ts +1 -1
  61. package/packages/client/dist/runner/headless/types.js +2 -2
  62. package/packages/client/dist/state/invocation-shape.d.ts +9 -0
  63. package/packages/client/dist/state/invocation-shape.js +1 -0
  64. package/packages/client/dist/state/project-state-snapshot.d.ts +9 -3
  65. package/packages/client/dist/state/project-state-snapshot.js +1 -1
  66. package/packages/client/dist/state/state-json-repair.d.ts +9 -0
  67. package/packages/client/dist/state/state-json-repair.js +3 -3
  68. package/packages/client/dist/state/structural-dag-projection.d.ts +24 -0
  69. package/packages/client/dist/state/structural-dag-projection.js +1 -0
  70. package/packages/client/dist/tier/tier-aware-client.js +1 -1
  71. package/packages/client/dist/yoloop/invoke-hooks.d.ts +13 -10
  72. package/packages/client/dist/yoloop/invoke-hooks.js +8 -5
  73. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1
  74. package/packages/shared/dist/generated/command-registry.generated.js +64 -65
  75. package/packages/shared/dist/generated/invocation-schema.generated.js +16 -24
  76. package/packages/shared/dist/invocation/index.d.ts +6 -2
  77. package/packages/shared/dist/invocation/index.js +5 -0
  78. package/packages/shared/dist/invocation/input-envelope.d.ts +37 -0
  79. package/packages/shared/dist/invocation/input-envelope.js +98 -0
  80. package/packages/shared/dist/invocation/project-identity-migration.d.ts +28 -0
  81. package/packages/shared/dist/invocation/project-identity-migration.js +83 -0
  82. package/packages/shared/dist/invocation/public-diagnostics.d.ts +87 -0
  83. package/packages/shared/dist/invocation/public-diagnostics.js +181 -0
  84. package/packages/shared/dist/invocation/state-projection.d.ts +21 -0
  85. package/packages/shared/dist/invocation/state-projection.js +1 -0
  86. package/packages/shared/dist/invocation/strict-effect-receipt.d.ts +12 -0
  87. package/packages/shared/dist/invocation/strict-effect-receipt.js +43 -0
  88. package/packages/shared/dist/yoloop/epic-terminal-git.js +227 -0
  89. package/packages/shared/dist/yoloop/planning-graph.js +119 -0
  90. package/packages/shared/dist/yoloop/public-story-write-set.js +27 -0
  91. package/packages/shared/dist/yoloop/wave-decision-receipt.js +19 -0
  92. package/targets-stubs/antigravity/gemini.md +1 -1
  93. package/targets-stubs/antigravity/neocortex.md +18 -0
  94. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  95. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  96. package/targets-stubs/claude-code/neocortex-root.md +21 -2
  97. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  98. package/targets-stubs/claude-code/neocortex.md +2 -2
  99. package/targets-stubs/codex/AGENTS.md +20 -1
  100. package/targets-stubs/cursor/agent.md +20 -2
  101. package/targets-stubs/gemini-cli/agent.md +2 -2
  102. package/targets-stubs/gemini-cli/gemini.md +18 -0
  103. package/targets-stubs/grok/README.md +13 -0
  104. package/targets-stubs/grok/SKILL.md +50 -0
  105. package/targets-stubs/grok/config-mcp.toml +22 -0
  106. package/targets-stubs/grok/install-grok.sh +31 -0
  107. package/targets-stubs/kimi/neocortex.md +18 -0
  108. package/targets-stubs/openclaw/SKILL.md +18 -0
  109. package/targets-stubs/opencode/neocortex-root.md +20 -1
  110. package/targets-stubs/vscode/neocortex.agent.md +20 -2
@@ -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$/]),x=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 a=n[1].trim();return(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),a||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,Y=4096,G=/^\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(a=>/^#\s+\S/.test(a));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 a=[...new Set(t.map(W).filter(Boolean))];if(a.length>1){n.push(`legacy metadata ambiguous for '${e}' in '${i}': conflicting values ignored`);return}return a[0]}function X(t,e){const i=[],n=[],a=t.slice(0,Y).split(/\r?\n/,C);for(const d of a){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 u=d.match(G);if(!u)continue;const m=U(u[1]);if(!m)continue;const h=o.get(m)??[];h.push(u[2]),o.set(m,h)}const f=v(o.get("id")??[],"id",e,i),l=v(o.get("title")??[],"title",e,i),g=v(o.get("status")??[],"status",e,i),_=v(o.get("total_stories")??[],"total_stories",e,i),p=g===void 0?void 0:H(g);g!==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=f&&/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(f)?f:void 0;f!==void 0&&b===void 0&&i.push(`legacy metadata id invalid in '${e}': value ignored`);const r=Z(n),s=l??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 f=n[1].trim();if(f.startsWith('"')&&!f.endsWith('"')||f.startsWith("'")&&!f.endsWith("'"))return!0;continue}if(/^\s+/.test(i))return!0;const a=i.match(/^[A-Za-z0-9_-]+:\s*(.*?)\s*$/);if(!a)return!0;const o=a[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),a=t.match(A);if(!a)return Object.freeze([`metadata-frontmatter reason=frontmatter-malformed file='${n}': repair the bounded leading YAML envelope; source content omitted`]);const o=a[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,"\\$&"),a=t.match(new RegExp(`^${i}:[ \\t]*(.+?)[ \\t]*$`,"mi"))?.[1]?.trim();if(a!==void 0){const _=(a.startsWith("[")&&a.endsWith("]")?a.slice(1,-1).split(","):[a]).map(L).filter(p=>typeof p=="string"&&p.length>0);return _.length>0?Object.freeze(_):void 0}const o=t.split(/\r?\n/),f=[];let l=!1;for(const g of o){if(!l){new RegExp(`^${i}:\\s*$`,"i").test(g.trim())&&(l=!0);continue}if(/^[A-Za-z0-9_-]+:\s*/.test(g))break;const _=g.match(/^\s*-\s*(.+?)\s*$/);if(!_)continue;const p=L(_[1]);p&&f.push(p)}return f.length>0?Object.freeze(f):void 0}function N(t){return t.startsWith("_")||t.startsWith(".")}function ee(t){return x.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,a=null;for(let o=0;o<E.length;o++){const f=E[o],l=t.match(f);if(l){i=!0,n=l[1],a=o===2?"filename-slug":"filename-canonical";break}}return i?e.id&&e.id.length>0?{id:e.id,source:"frontmatter"}:{id:n,source:a}: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 ae(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 ce(t,e){return e.join(t,"..","stories")}function he(t,e){const i=[],n=[],a=[],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 r of f){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),u=F(d,r);i.push(...u.warnings);const m=u.metadata,h=ie(r);m.id&&P(m.id,h)&&i.push(u.source==="frontmatter"?re(r,m.id,h):`legacy metadata/filename mismatch: epic '${r}' id does not match its filename`),l.push({filename:r,fullPath:s,metadata:m,metadataSource:u.source})}const g=new Map,_=[];for(const r of l){const s=te(r.filename,r.metadata);if(s===null){n.push(`${r.filename}: id resolution returned null`);continue}let c=s.id;const d=c,u=g.get(d)??0;u>0&&(c=`${d}-${u+1}`,i.push(`epic ID collision: '${d}' resolved to '${c}' for ${r.filename}`)),g.set(d,u+1),_.push({candidate:r,finalId:c,idSource:r.metadataSource==="legacy-metadata"&&r.metadata.id?"legacy-metadata":s.source})}const p=new Map,y=ce(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 c=e.join(y,s);if(e.isDirectory(c))continue;const d=ae(s);if(!d)continue;const u=e.readFile(c),m=F(u,s);i.push(...m.warnings);const h=m.metadata;h.id&&P(h.id,d.id)&&i.push(m.source==="frontmatter"?oe(s,h.id,d.id):`legacy metadata/filename mismatch: story '${s}' id does not match its filename`);const S=h.epic_id??d.epic_id_hint;if(!S){i.push(`story '${s}' has no epic_id (frontmatter or filename pattern)`);continue}const k=Object.freeze({id:d.id,epic_id:S,filename:s,path:c,...h.title?{title:h.title}:{},...h.status?{status:h.status}:{},...h.depends_on?{depends_on:h.depends_on}:{},...h.files_to_modify?{files_to_modify:h.files_to_modify}:{}});p.has(S)||p.set(S,[]),p.get(S).push(k)}}for(const r of _){const s=p.get(r.finalId)??[],c=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});a.push(c)}const b=new Set(a.map(r=>r.id));for(const[r,s]of p.entries())if(!b.has(r))for(const c of s)i.push(`orphan story '${c.filename}' references unknown epic '${r}'`);return Object.freeze({epics:Object.freeze(a),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,a){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 f=fe(o.stories),l=f.length,g=f.filter(s=>I(le(t,s,i).status)).length,_=a?.total_stories,p=a?.e==="legacy-metadata"&&z(o.status),y=p?_??l:l>0?l:_??0,b=p||l===0&&y>0&&z(o.status)?y:g,r=l>0&&g===l;z(o.status)&&!p&&!r&&l>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 a=n.epics,o=n.stories,f=[],l=[],g=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 c=a[s.id];if(c&&c.source==="create-epic"&&!y){l.push({id:s.id,reason:"create-epic source preserved (defense)"});continue}if(c&&c.source==="discovered"&&!y){const u=c;u.depends_on=s.depends_on??[],u.stories=s.stories.map(m=>m.id),s.title!==void 0&&(u.title=s.title),s.status!==void 0&&!z(u.status)&&(u.status=s.status),g.add(s.id);continue}const d={id:s.id,title:s.title??"",status:s.status??"planning",source:"discovered",discovered_at:b,merged_at:b,stories:s.stories.map(u=>u.id),depends_on:s.depends_on??[]};a[s.id]=d,g.add(s.id),f.push(s.id)}for(const s of e.epics)for(const c of s.stories){const d=o[c.id];if(d&&d.source==="create-epic"&&!y){l.push({id:c.id,reason:"create-epic source preserved (defense, story)"});continue}if(d&&de(d.status)&&!y){const m=d;m.depends_on=c.depends_on??[],m.files_to_modify=c.files_to_modify??[];continue}if(d&&d.source==="discovered"&&!y){const m=d;m.depends_on=c.depends_on??[],m.files_to_modify=c.files_to_modify??[];continue}const u={id:c.id,epic_id:c.epic_id,title:c.title??"",status:c.status??"backlog",source:"discovered",discovered_at:b,depends_on:c.depends_on??[],files_to_modify:c.files_to_modify??[]};o[c.id]=u,p++}for(const s of g)pe(s,a,o,b,_.get(s));return{state:n,added:Object.freeze([...f]),skipped:Object.freeze([...l]),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 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,41 +1,41 @@
1
1
  /** Generated by scripts/generate-command-registry.mjs. Do not edit. */
2
2
  export const COMMAND_REGISTRY_SCHEMA_VERSION = 1;
3
3
  export const COMMAND_REGISTRY_VERSION = "1.0.0";
4
- export const COMMAND_REGISTRY_CHECKSUM = "b8fcdb246f7e22f820f667442f7a489bf3f53376b6540280d59fb89495ff4520";
4
+ export const COMMAND_REGISTRY_CHECKSUM = "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6";
5
5
  export const COMMAND_REGISTRY_PROJECTION_MANIFEST = {
6
6
  "schemaVersion": 1,
7
7
  "registryVersion": "1.0.0",
8
- "registryChecksum": "b8fcdb246f7e22f820f667442f7a489bf3f53376b6540280d59fb89495ff4520",
8
+ "registryChecksum": "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6",
9
9
  "projections": [
10
10
  {
11
11
  "kind": "admin",
12
12
  "entryCount": 62,
13
- "sha256": "4ca10e54b2028a01dad3b492dacead708d858842ba5ba23bcca70faa8c5b9689"
13
+ "sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
14
14
  },
15
15
  {
16
16
  "kind": "client",
17
17
  "entryCount": 62,
18
- "sha256": "4ca10e54b2028a01dad3b492dacead708d858842ba5ba23bcca70faa8c5b9689"
18
+ "sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
19
19
  },
20
20
  {
21
21
  "kind": "docs",
22
22
  "entryCount": 62,
23
- "sha256": "4ca10e54b2028a01dad3b492dacead708d858842ba5ba23bcca70faa8c5b9689"
23
+ "sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
24
24
  },
25
25
  {
26
26
  "kind": "metrics",
27
27
  "entryCount": 62,
28
- "sha256": "4ca10e54b2028a01dad3b492dacead708d858842ba5ba23bcca70faa8c5b9689"
28
+ "sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
29
29
  },
30
30
  {
31
31
  "kind": "server",
32
32
  "entryCount": 67,
33
- "sha256": "682d4238281ea4e00d110fdf7d67257cc9ee8c029a87232b26c8fc3f00604884"
33
+ "sha256": "1b3e29b3b462a8fb283a308e311ca681d7b106f986723d4c08b84805c878a00a"
34
34
  },
35
35
  {
36
36
  "kind": "shared",
37
37
  "entryCount": 67,
38
- "sha256": "f82436b633efc99f247aa0f0e755d66fe538ba3afd205dcec49e4a5fdb7d9928"
38
+ "sha256": "0d181e8f869891e7c3e09b76ad00b122ca7c5a4ca530e86391d64517d14b7bc8"
39
39
  }
40
40
  ]
41
41
  };
@@ -1130,14 +1130,14 @@ export const GENERATED_SHARED_COMMANDS = [
1130
1130
  "name": "Diagnosticar Story ou Contexto",
1131
1131
  "number": 25,
1132
1132
  "policy": {
1133
- "billingClass": "billable",
1134
- "idempotencyClass": "logical-supported",
1133
+ "billingClass": "non-billable",
1134
+ "idempotencyClass": "none",
1135
1135
  "minimumTier": "free",
1136
- "mutationClass": "stateful",
1136
+ "mutationClass": "read-only",
1137
1137
  "privilege": "authenticated",
1138
- "quotaClass": "workflow",
1138
+ "quotaClass": "none",
1139
1139
  "replayClass": "signed-request",
1140
- "strictReadOnly": "deny"
1140
+ "strictReadOnly": "allow"
1141
1141
  },
1142
1142
  "projections": [
1143
1143
  "admin",
@@ -2022,54 +2022,6 @@ export const GENERATED_SHARED_COMMANDS = [
2022
2022
  "visibility": "public",
2023
2023
  "subcommands": []
2024
2024
  },
2025
- {
2026
- "aliases": [
2027
- "inicializar"
2028
- ],
2029
- "category": "quick-start",
2030
- "compatibility": {
2031
- "deprecatedIn": null,
2032
- "introducedIn": "1.0.0",
2033
- "removedIn": null,
2034
- "replacement": null
2035
- },
2036
- "description": {
2037
- "en": "Initialize project",
2038
- "es": "Inicializar proyecto",
2039
- "pt-BR": "Inicializar projeto"
2040
- },
2041
- "examples": [
2042
- "@neocortex *init",
2043
- "@neocortex init",
2044
- "@neocortex 2"
2045
- ],
2046
- "id": "init",
2047
- "inputShape": "epics",
2048
- "mode": "utility",
2049
- "name": "Inicializar + Enrichment",
2050
- "number": 2,
2051
- "policy": {
2052
- "billingClass": "billable",
2053
- "idempotencyClass": "logical-supported",
2054
- "minimumTier": "free",
2055
- "mutationClass": "stateful",
2056
- "privilege": "authenticated",
2057
- "quotaClass": "workflow",
2058
- "replayClass": "signed-request",
2059
- "strictReadOnly": "deny"
2060
- },
2061
- "projections": [
2062
- "admin",
2063
- "client",
2064
- "docs",
2065
- "metrics",
2066
- "server",
2067
- "shared"
2068
- ],
2069
- "stepId": "step-u-init",
2070
- "visibility": "public",
2071
- "subcommands": []
2072
- },
2073
2025
  {
2074
2026
  "aliases": [
2075
2027
  "continuity-jobs",
@@ -2746,6 +2698,53 @@ export const GENERATED_SHARED_COMMANDS = [
2746
2698
  "visibility": "public",
2747
2699
  "subcommands": []
2748
2700
  },
2701
+ {
2702
+ "aliases": [
2703
+ "migrate-project",
2704
+ "project-id-migrate"
2705
+ ],
2706
+ "category": "recovery",
2707
+ "compatibility": {
2708
+ "deprecatedIn": null,
2709
+ "introducedIn": "1.0.0",
2710
+ "removedIn": null,
2711
+ "replacement": null
2712
+ },
2713
+ "description": {
2714
+ "en": "Migrate stable project identity with backup and remote seed.",
2715
+ "es": "Migra la identidad estable del proyecto con respaldo y seed remoto.",
2716
+ "pt-BR": "Migra a identidade estavel do projeto com backup e seed remoto."
2717
+ },
2718
+ "examples": [
2719
+ "@neocortex *migrate-project-id"
2720
+ ],
2721
+ "id": "migrate-project-id",
2722
+ "inputShape": "standalone",
2723
+ "mode": "utility",
2724
+ "name": "Migrate Project Identity",
2725
+ "number": 63,
2726
+ "policy": {
2727
+ "billingClass": "non-billable",
2728
+ "idempotencyClass": "logical-required",
2729
+ "minimumTier": "free",
2730
+ "mutationClass": "stateful",
2731
+ "privilege": "authenticated",
2732
+ "quotaClass": "none",
2733
+ "replayClass": "signed-request",
2734
+ "strictReadOnly": "deny"
2735
+ },
2736
+ "projections": [
2737
+ "admin",
2738
+ "client",
2739
+ "docs",
2740
+ "metrics",
2741
+ "server",
2742
+ "shared"
2743
+ ],
2744
+ "stepId": "step-u-migrate-project-id",
2745
+ "visibility": "public",
2746
+ "subcommands": []
2747
+ },
2749
2748
  {
2750
2749
  "aliases": [
2751
2750
  "migrate",
@@ -3528,9 +3527,9 @@ export const GENERATED_SHARED_COMMANDS = [
3528
3527
  "replacement": null
3529
3528
  },
3530
3529
  "description": {
3531
- "en": "Setup branch",
3532
- "es": "Configurar branch",
3533
- "pt-BR": "Configurar branch"
3530
+ "en": "Set up branch in the current checkout",
3531
+ "es": "Configurar branch en el checkout actual",
3532
+ "pt-BR": "Configurar branch no checkout atual"
3534
3533
  },
3535
3534
  "examples": [
3536
3535
  "@neocortex *setup-branch @docs/stories/P126.01.story.md"
@@ -3538,7 +3537,7 @@ export const GENERATED_SHARED_COMMANDS = [
3538
3537
  "id": "setup-branch",
3539
3538
  "inputShape": "story",
3540
3539
  "mode": "step",
3541
- "name": "Configurar Branch & Worktree",
3540
+ "name": "Configurar Branch",
3542
3541
  "number": 24,
3543
3542
  "policy": {
3544
3543
  "billingClass": "billable",
@@ -2,13 +2,13 @@
2
2
  export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
3
3
  "schemaVersion": "p205-invocation-schema-v1",
4
4
  "registryVersion": "1.0.0",
5
- "registryChecksum": "b8fcdb246f7e22f820f667442f7a489bf3f53376b6540280d59fb89495ff4520",
6
- "schemaChecksum": "667c67ed7a55553d74eab12ec46c2e0f12b0529ad01303d4ca9cae14d49270bd",
5
+ "registryChecksum": "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6",
6
+ "schemaChecksum": "c3252fa75c16cc81bd0ea0e8b33868d121c2e45258f9b425c310af9337cfbd6f",
7
7
  "commandCount": 62,
8
8
  "optionCount": 47,
9
- "positionalCount": 44,
9
+ "positionalCount": 43,
10
10
  "operationCount": 33,
11
- "projectionSha256": "84ffc9791306d642d0603ce81e0b0a12ee48a2ebbc6bf4ad3bb45b9eb940abff",
11
+ "projectionSha256": "9843f3f7155ed3a6244c020a324c2d2818c5d4fd2d7590eeb78b9e055bc18e75",
12
12
  "commands": [
13
13
  {
14
14
  "commandId": "arch-api-contracts",
@@ -830,26 +830,6 @@ export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
830
830
  ],
831
831
  "terminator": true
832
832
  },
833
- {
834
- "commandId": "init",
835
- "inputShape": "epics",
836
- "operation": {
837
- "required": false,
838
- "unknownAsPositional": false,
839
- "operations": []
840
- },
841
- "options": [],
842
- "positionals": [
843
- {
844
- "cardinality": "one",
845
- "id": "epics",
846
- "kind": "target-ref",
847
- "order": 0,
848
- "required": false
849
- }
850
- ],
851
- "terminator": true
852
- },
853
833
  {
854
834
  "commandId": "jobs",
855
835
  "inputShape": "continuity-jobs",
@@ -1128,6 +1108,18 @@ export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
1128
1108
  ],
1129
1109
  "terminator": true
1130
1110
  },
1111
+ {
1112
+ "commandId": "migrate-project-id",
1113
+ "inputShape": "standalone",
1114
+ "operation": {
1115
+ "required": false,
1116
+ "unknownAsPositional": false,
1117
+ "operations": []
1118
+ },
1119
+ "options": [],
1120
+ "positionals": [],
1121
+ "terminator": true
1122
+ },
1131
1123
  {
1132
1124
  "commandId": "migrate-state",
1133
1125
  "inputShape": "standalone",
@@ -1,3 +1,8 @@
1
+ export * from './input-envelope.js';
2
+ export * from './project-identity-migration.js';
3
+ export * from './state-projection.js';
4
+ export * from './strict-effect-receipt.js';
5
+ export * from './public-diagnostics.js';
1
6
  export declare const EXACT_INVOCATION_POLICY: "p205-exact-invocation-v1";
2
7
  export declare const INVOCATION_SCHEMA_VERSION: "p205-invocation-schema-v1";
3
8
  export declare const INVOCATION_LIMITS: Readonly<{
@@ -115,7 +120,7 @@ export interface InvocationCommandSchemaV1 {
115
120
  readonly positionals: readonly InvocationPositionalSchemaV1[];
116
121
  readonly terminator: true;
117
122
  }
118
- export declare const INVOCATION_SCHEMA_CHECKSUM: "667c67ed7a55553d74eab12ec46c2e0f12b0529ad01303d4ca9cae14d49270bd";
123
+ export declare const INVOCATION_SCHEMA_CHECKSUM: "c3252fa75c16cc81bd0ea0e8b33868d121c2e45258f9b425c310af9337cfbd6f";
119
124
  export interface InvocationSchemaManifestV1 {
120
125
  readonly schemaVersion: typeof INVOCATION_SCHEMA_VERSION;
121
126
  readonly registryVersion: string;
@@ -172,4 +177,3 @@ export interface InvocationDeprecationCountV1 {
172
177
  }
173
178
  /** Count-only migration telemetry; raw input is intentionally not accepted. */
174
179
  export declare function createInvocationDeprecationCount(result: RejectedInvocationAdmissionV1): InvocationDeprecationCountV1;
175
- export {};
@@ -9,6 +9,11 @@ import { createHash } from 'node:crypto';
9
9
  import { COMMAND_REGISTRY_CHECKSUM, COMMAND_REGISTRY_VERSION, GENERATED_SHARED_COMMANDS, } from '../generated/command-registry.generated.js';
10
10
  import { GENERATED_INVOCATION_SCHEMA_MANIFEST, GENERATED_INVOCATION_SCHEMAS, } from '../generated/invocation-schema.generated.js';
11
11
  import { canonicalizeCommandRegistryJcs } from '../command-registry-contract.js';
12
+ export * from './input-envelope.js';
13
+ export * from './project-identity-migration.js';
14
+ export * from './state-projection.js';
15
+ export * from './strict-effect-receipt.js';
16
+ export * from './public-diagnostics.js';
12
17
  export const EXACT_INVOCATION_POLICY = 'p205-exact-invocation-v1';
13
18
  export const INVOCATION_SCHEMA_VERSION = 'p205-invocation-schema-v1';
14
19
  export const INVOCATION_LIMITS = Object.freeze({
@@ -0,0 +1,37 @@
1
+ export declare const INVOKE_INPUT_ENVELOPE_VERSION: 2;
2
+ export declare const INVOKE_HTTP_BODY_LIMIT_BYTES: number;
3
+ export type InvokeInputSourceV2 = 'args' | 'stdin' | 'args-file';
4
+ export type InvokeNewlineStyleV2 = 'none' | 'lf' | 'crlf' | 'mixed';
5
+ export interface InvokeInputEnvelopeV2 {
6
+ readonly version: typeof INVOKE_INPUT_ENVELOPE_VERSION;
7
+ readonly source: InvokeInputSourceV2;
8
+ readonly rawArgs: string;
9
+ readonly byteLength: number;
10
+ readonly sha256: string;
11
+ readonly newlineStyle: InvokeNewlineStyleV2;
12
+ readonly admissionView: string;
13
+ }
14
+ export declare const INVOKE_INPUT_EVIDENCE_VERSION: 1;
15
+ /** Public-safe transport projection; rawArgs remains the single args field. */
16
+ export interface InvokeInputEvidenceV1 {
17
+ readonly version: typeof INVOKE_INPUT_EVIDENCE_VERSION;
18
+ readonly source: InvokeInputSourceV2;
19
+ readonly byteLength: number;
20
+ readonly sha256: string;
21
+ readonly newlineStyle: InvokeNewlineStyleV2;
22
+ }
23
+ export type InvocationMalformedInputReasonV1 = 'multiple-input-sources' | 'missing-input-value' | 'unexpected-cli-token' | 'invalid-utf8' | 'invalid-control-character' | 'unterminated-quote' | 'input-limit-exceeded';
24
+ export interface InvocationInputDiagnosticV1 {
25
+ readonly code: 'INVOCATION_MALFORMED_INPUT';
26
+ readonly reason: InvocationMalformedInputReasonV1;
27
+ readonly source?: InvokeInputSourceV2;
28
+ readonly byteLength?: number;
29
+ readonly remediation: string;
30
+ }
31
+ export declare function classifyNewlineStyle(value: string): InvokeNewlineStyleV2;
32
+ export declare function isInvokeHttpBodyBelowLimit(byteLength: number): boolean;
33
+ export declare function invokeInputSha256(rawArgs: string): string;
34
+ export declare function createInvokeInputEnvelopeV2(source: InvokeInputSourceV2, rawArgs: string): InvokeInputEnvelopeV2;
35
+ export declare function projectInvokeInputEvidenceV1(envelope: InvokeInputEnvelopeV2): InvokeInputEvidenceV1;
36
+ export declare function assertInvokeInputEvidenceV1(value: unknown, rawArgs?: string): asserts value is InvokeInputEvidenceV1;
37
+ export declare function assertInvokeInputEnvelopeV2(value: unknown): asserts value is InvokeInputEnvelopeV2;
@@ -0,0 +1,98 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { SHA256_HEX_PATTERN } from './project-identity-migration.js';
3
+ export const INVOKE_INPUT_ENVELOPE_VERSION = 2;
4
+ export const INVOKE_HTTP_BODY_LIMIT_BYTES = 256 * 1024;
5
+ export const INVOKE_INPUT_EVIDENCE_VERSION = 1;
6
+ export function classifyNewlineStyle(value) {
7
+ const withoutCrlf = value.replaceAll('\r\n', '');
8
+ const hasCrlf = withoutCrlf.length !== value.length;
9
+ const hasLf = withoutCrlf.includes('\n');
10
+ const hasBareCr = withoutCrlf.includes('\r');
11
+ if (!hasCrlf && !hasLf && !hasBareCr)
12
+ return 'none';
13
+ if (hasCrlf && !hasLf && !hasBareCr)
14
+ return 'crlf';
15
+ if (!hasCrlf && hasLf && !hasBareCr)
16
+ return 'lf';
17
+ return 'mixed';
18
+ }
19
+ export function isInvokeHttpBodyBelowLimit(byteLength) {
20
+ return Number.isSafeInteger(byteLength) && byteLength >= 0 && byteLength < INVOKE_HTTP_BODY_LIMIT_BYTES;
21
+ }
22
+ export function invokeInputSha256(rawArgs) {
23
+ return createHash('sha256').update(rawArgs, 'utf8').digest('hex');
24
+ }
25
+ export function createInvokeInputEnvelopeV2(source, rawArgs) {
26
+ return Object.freeze({
27
+ version: INVOKE_INPUT_ENVELOPE_VERSION,
28
+ source,
29
+ rawArgs,
30
+ byteLength: Buffer.byteLength(rawArgs, 'utf8'),
31
+ sha256: invokeInputSha256(rawArgs),
32
+ newlineStyle: classifyNewlineStyle(rawArgs),
33
+ admissionView: rawArgs.trim(),
34
+ });
35
+ }
36
+ export function projectInvokeInputEvidenceV1(envelope) {
37
+ assertInvokeInputEnvelopeV2(envelope);
38
+ return Object.freeze({
39
+ version: INVOKE_INPUT_EVIDENCE_VERSION,
40
+ source: envelope.source,
41
+ byteLength: envelope.byteLength,
42
+ sha256: envelope.sha256,
43
+ newlineStyle: envelope.newlineStyle,
44
+ });
45
+ }
46
+ export function assertInvokeInputEvidenceV1(value, rawArgs) {
47
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
48
+ throw new Error('INVOKE_INPUT_EVIDENCE_INVALID');
49
+ }
50
+ const candidate = value;
51
+ const expectedKeys = ['byteLength', 'newlineStyle', 'sha256', 'source', 'version'];
52
+ const actualKeys = Object.keys(candidate).sort();
53
+ if (actualKeys.length !== expectedKeys.length
54
+ || actualKeys.some((key, index) => key !== expectedKeys[index])
55
+ || candidate.version !== INVOKE_INPUT_EVIDENCE_VERSION
56
+ || !['args', 'stdin', 'args-file'].includes(String(candidate.source))
57
+ || !Number.isSafeInteger(candidate.byteLength)
58
+ || candidate.byteLength < 0
59
+ || typeof candidate.sha256 !== 'string'
60
+ || !SHA256_HEX_PATTERN.test(candidate.sha256)
61
+ || !['none', 'lf', 'crlf', 'mixed'].includes(String(candidate.newlineStyle))) {
62
+ throw new Error('INVOKE_INPUT_EVIDENCE_INVALID');
63
+ }
64
+ if (rawArgs !== undefined
65
+ && (candidate.byteLength !== Buffer.byteLength(rawArgs, 'utf8')
66
+ || candidate.sha256 !== invokeInputSha256(rawArgs)
67
+ || candidate.newlineStyle !== classifyNewlineStyle(rawArgs))) {
68
+ throw new Error('INVOKE_INPUT_EVIDENCE_CONFLICT');
69
+ }
70
+ }
71
+ export function assertInvokeInputEnvelopeV2(value) {
72
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
73
+ throw new Error('INVOKE_INPUT_ENVELOPE_INVALID');
74
+ }
75
+ const candidate = value;
76
+ if (candidate.version !== INVOKE_INPUT_ENVELOPE_VERSION) {
77
+ throw new Error('INVOKE_INPUT_ENVELOPE_VERSION_UNSUPPORTED');
78
+ }
79
+ const expectedKeys = ['admissionView', 'byteLength', 'newlineStyle', 'rawArgs', 'sha256', 'source', 'version'];
80
+ const actualKeys = Object.keys(candidate).sort();
81
+ if (actualKeys.length !== expectedKeys.length
82
+ || actualKeys.some((key, index) => key !== expectedKeys[index])
83
+ || !['args', 'stdin', 'args-file'].includes(String(candidate.source))
84
+ || typeof candidate.rawArgs !== 'string'
85
+ || !Number.isSafeInteger(candidate.byteLength)
86
+ || typeof candidate.sha256 !== 'string'
87
+ || !SHA256_HEX_PATTERN.test(candidate.sha256)
88
+ || !['none', 'lf', 'crlf', 'mixed'].includes(String(candidate.newlineStyle))
89
+ || typeof candidate.admissionView !== 'string') {
90
+ throw new Error('INVOKE_INPUT_ENVELOPE_INVALID');
91
+ }
92
+ if (candidate.byteLength !== Buffer.byteLength(candidate.rawArgs, 'utf8')
93
+ || candidate.sha256 !== invokeInputSha256(candidate.rawArgs)
94
+ || candidate.newlineStyle !== classifyNewlineStyle(candidate.rawArgs)
95
+ || candidate.admissionView !== candidate.rawArgs.trim()) {
96
+ throw new Error('INVOKE_INPUT_ENVELOPE_INTEGRITY');
97
+ }
98
+ }
@@ -0,0 +1,28 @@
1
+ export declare const PROJECT_IDENTITY_MIGRATION_VERSION: 1;
2
+ export declare const PROJECT_IDENTITY_MIGRATION_CAPABILITY: "project-identity-migration-v1";
3
+ export declare const PROJECT_ID_PATTERN: RegExp;
4
+ export declare const PROJECT_IDENTITY_OPERATION_PATTERN: RegExp;
5
+ export declare const SHA256_HEX_PATTERN: RegExp;
6
+ export declare const MAX_LEGACY_EPIC_FLOOR: number;
7
+ export interface ProjectIdentityMigrationRequestV1 {
8
+ readonly version: typeof PROJECT_IDENTITY_MIGRATION_VERSION;
9
+ readonly operationId: string;
10
+ readonly projectId: string;
11
+ readonly localStateDigest: string;
12
+ readonly legacyEpicFloor: number;
13
+ readonly phase: 'prepare' | 'seed';
14
+ }
15
+ export interface ProjectIdentityMigrationReceiptV1 {
16
+ readonly version: typeof PROJECT_IDENTITY_MIGRATION_VERSION;
17
+ readonly operationId: string;
18
+ readonly projectId: string;
19
+ readonly status: 'seeded' | 'already-seeded';
20
+ readonly acceptedLegacyFloor: number;
21
+ readonly nextEpicNumber: number;
22
+ readonly serverCapability: typeof PROJECT_IDENTITY_MIGRATION_CAPABILITY;
23
+ readonly receiptDigest: string;
24
+ }
25
+ export type ProjectIdentityMigrationReceiptBodyV1 = Omit<ProjectIdentityMigrationReceiptV1, 'receiptDigest'>;
26
+ export declare function computeProjectIdentityMigrationReceiptDigestV1(receipt: ProjectIdentityMigrationReceiptBodyV1): string;
27
+ export declare function assertProjectIdentityMigrationRequestV1(value: unknown): asserts value is ProjectIdentityMigrationRequestV1;
28
+ export declare function assertProjectIdentityMigrationReceiptV1(value: unknown): asserts value is ProjectIdentityMigrationReceiptV1;
@@ -0,0 +1,83 @@
1
+ export const PROJECT_IDENTITY_MIGRATION_VERSION = 1;
2
+ export const PROJECT_IDENTITY_MIGRATION_CAPABILITY = 'project-identity-migration-v1';
3
+ export const PROJECT_ID_PATTERN = /^prj_[a-f0-9]{32}$/;
4
+ export const PROJECT_IDENTITY_OPERATION_PATTERN = /^mig_[a-f0-9]{32}$/;
5
+ export const SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
6
+ export const MAX_LEGACY_EPIC_FLOOR = Number.MAX_SAFE_INTEGER - 1;
7
+ export function computeProjectIdentityMigrationReceiptDigestV1(receipt) {
8
+ const canonicalBody = {
9
+ version: receipt.version,
10
+ operationId: receipt.operationId,
11
+ projectId: receipt.projectId,
12
+ status: receipt.status,
13
+ acceptedLegacyFloor: receipt.acceptedLegacyFloor,
14
+ nextEpicNumber: receipt.nextEpicNumber,
15
+ serverCapability: receipt.serverCapability,
16
+ };
17
+ return createHash('sha256')
18
+ .update(`nx-project-identity-migration-receipt-v1\0${JSON.stringify(canonicalBody)}`, 'utf8')
19
+ .digest('hex');
20
+ }
21
+ function record(value) {
22
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
23
+ ? value
24
+ : null;
25
+ }
26
+ function exactKeys(value, expected) {
27
+ const actual = Object.keys(value).sort();
28
+ return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
29
+ }
30
+ function validFloor(value) {
31
+ return Number.isSafeInteger(value) && value >= 0;
32
+ }
33
+ export function assertProjectIdentityMigrationRequestV1(value) {
34
+ const candidate = record(value);
35
+ if (candidate?.version !== PROJECT_IDENTITY_MIGRATION_VERSION) {
36
+ throw new Error('PROJECT_IDENTITY_MIGRATION_VERSION_UNSUPPORTED');
37
+ }
38
+ const keys = ['legacyEpicFloor', 'localStateDigest', 'operationId', 'phase', 'projectId', 'version'];
39
+ if (!exactKeys(candidate, keys)
40
+ || typeof candidate.operationId !== 'string'
41
+ || !PROJECT_IDENTITY_OPERATION_PATTERN.test(candidate.operationId)
42
+ || typeof candidate.projectId !== 'string'
43
+ || !PROJECT_ID_PATTERN.test(candidate.projectId)
44
+ || typeof candidate.localStateDigest !== 'string'
45
+ || !SHA256_HEX_PATTERN.test(candidate.localStateDigest)
46
+ || (candidate.phase !== 'prepare' && candidate.phase !== 'seed')
47
+ || !validFloor(candidate.legacyEpicFloor)) {
48
+ throw new Error('PROJECT_IDENTITY_MIGRATION_INVALID');
49
+ }
50
+ if (candidate.legacyEpicFloor > MAX_LEGACY_EPIC_FLOOR) {
51
+ throw new Error('PROJECT_IDENTITY_MIGRATION_FLOOR_LIMIT');
52
+ }
53
+ }
54
+ export function assertProjectIdentityMigrationReceiptV1(value) {
55
+ const candidate = record(value);
56
+ if (candidate?.version !== PROJECT_IDENTITY_MIGRATION_VERSION) {
57
+ throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_VERSION_UNSUPPORTED');
58
+ }
59
+ const keys = [
60
+ 'acceptedLegacyFloor', 'nextEpicNumber', 'operationId', 'projectId',
61
+ 'receiptDigest', 'serverCapability', 'status', 'version',
62
+ ];
63
+ if (!exactKeys(candidate, keys)
64
+ || typeof candidate.operationId !== 'string'
65
+ || !PROJECT_IDENTITY_OPERATION_PATTERN.test(candidate.operationId)
66
+ || typeof candidate.projectId !== 'string'
67
+ || !PROJECT_ID_PATTERN.test(candidate.projectId)
68
+ || (candidate.status !== 'seeded' && candidate.status !== 'already-seeded')
69
+ || !validFloor(candidate.acceptedLegacyFloor)
70
+ || candidate.acceptedLegacyFloor > MAX_LEGACY_EPIC_FLOOR
71
+ || !Number.isSafeInteger(candidate.nextEpicNumber)
72
+ || candidate.nextEpicNumber <= candidate.acceptedLegacyFloor
73
+ || candidate.serverCapability !== PROJECT_IDENTITY_MIGRATION_CAPABILITY
74
+ || typeof candidate.receiptDigest !== 'string'
75
+ || !SHA256_HEX_PATTERN.test(candidate.receiptDigest)) {
76
+ throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_INVALID');
77
+ }
78
+ const receipt = candidate;
79
+ if (receipt.receiptDigest !== computeProjectIdentityMigrationReceiptDigestV1(receipt)) {
80
+ throw new Error('PROJECT_IDENTITY_MIGRATION_RECEIPT_INVALID');
81
+ }
82
+ }
83
+ import { createHash } from 'node:crypto';