@adhd/dispatch-base-spec 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.1.1 (2026-08-07)
2
+
3
+
4
+ ### 🚀 Features
5
+
6
+ - **dispatch-base-spec:** split DispatchUnit.prompt into systemPrompt/prompt, add execution_mode
7
+
8
+
9
+ ### 🩹 Fixes
10
+
11
+ - **dispatch-base-spec:** enforce DispatchLogEntry.provider enum in validateDagJson
12
+
13
+ - **apigen-cli:** restore 2768 files mass-deleted by 0117eb22 (BUG-APIGEN-052)
14
+
15
+
16
+ ### ❤️ Thank You
17
+
18
+ - parity-harness-self-test
19
+ - pseudosky
20
+
1
21
  ## 0.0.6 (2026-07-25)
2
22
 
3
23
 
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { BlastRadiusEntry, CodeKind, Confidence, ConfigKind, CrossPlanDep, DagJson, DagSnapshot, DispatchKind, DispatchLogEntry, DispatchNote, DispatchResult, DispatchUnit, DispatchUnitStatus, EffortTier, GuardResult, IOptimizerDeps, KindFamily, KiSource, MilestoneDag, MilestoneGuardResult, MilestoneSnapshot, MilestoneStatus, ModelTier, OpenQuestion, OperationAction, OperationConflict, OperationDag, OperationSnapshot, OperationStatus, OperationType, OptimizationConfig, PairwiseOverlapMap, PlanKind, Provenance, ProviderConfig, ProviderType, RetryConfig, SentinelFanoutConfig, SentinelRole, Shape, ShapeCode, ShapeCodeSnapshot, ShapeConfig, ShapeConfigSnapshot, ShapeDoc, ShapeKind, ShapeNull, ShapeOpDag, ShapeOpSnapshot, ShapeOpType, ShapeSnapshot, ShapeStructuredOutput, SnapshotOptimization, Turn, ValidationError, ValidationResult, } from './lib/types.js';
1
+ export type { BlastRadiusEntry, CodeKind, Confidence, ConfigKind, CrossPlanDep, DagJson, DagSnapshot, DispatchExecutionMode, DispatchKind, DispatchLogEntry, DispatchNote, DispatchResult, DispatchUnit, DispatchUnitStatus, EffortTier, GuardResult, IOptimizerDeps, KindFamily, KiSource, MilestoneDag, MilestoneGuardResult, MilestoneSnapshot, MilestoneStatus, ModelTier, OpenQuestion, OperationAction, OperationConflict, OperationDag, OperationSnapshot, OperationStatus, OperationType, OptimizationConfig, PairwiseOverlapMap, PlanKind, Provenance, ProviderConfig, ProviderType, RetryConfig, SentinelFanoutConfig, SentinelRole, Shape, ShapeCode, ShapeCodeSnapshot, ShapeConfig, ShapeConfigSnapshot, ShapeDoc, ShapeKind, ShapeNull, ShapeOpDag, ShapeOpSnapshot, ShapeOpType, ShapeSnapshot, ShapeStructuredOutput, SnapshotOptimization, Turn, ValidationError, ValidationResult, } from './lib/types.js';
2
2
  export { isValidOpForKind, VALID_OPS_BY_KIND, WRITE_CLASS_ACTIONS, } from './lib/types.js';
3
3
  export { assertValidDagJson, assertValidSnapshot, validateDagJson, validateSnapshot, } from './lib/validate.js';
4
4
  export { migrateDag } from './lib/migrate.js';
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=new Set(["create","modify-signature","modify-body","add-export","remove-export","rename"]),x={function:new Set(["add-param","remove-param","rename-param","retype-param","change-param-optional","reorder-params","change-return"]),interface:new Set(["add-field","remove-field","rename-field","retype-field","change-field-optional","add-generic","remove-generic","constrain-generic","add-extends","remove-extends"]),type:new Set(["add-field","remove-field","retype-field"]),class:new Set(["add-field","remove-field","rename-field","retype-field","change-field-optional","add-param","add-generic","remove-generic","constrain-generic","add-extends","remove-extends"]),enum:new Set(["add-field","remove-field","rename-field"]),const:new Set(["add-var","remove-var","rename-var","change-default"]),config:new Set(["set-key","remove-key","rename-key","add-entry","remove-entry","update-entry","bump-version","update-checksum"]),env:new Set(["set-key","remove-key","rename-key"]),schema:new Set(["add-table","remove-table","add-column","remove-column","rename-column","retype-column","change-nullable","add-index","remove-index"]),manifest:new Set(["add-entry","remove-entry","bump-version"]),doc:new Set(["add-section","remove-section","rename-section","update-section"]),"structured-output":new Set([]),script:new Set(["add-param","remove-param","rename-param","retype-param","change-param-optional","reorder-params","change-return","add-field","remove-field","rename-field","retype-field","change-field-optional","add-generic","remove-generic","constrain-generic","add-extends","remove-extends","set-key","remove-key","rename-key","add-array-item","remove-array-item","add-var","remove-var","rename-var","change-default","add-section","remove-section","rename-section","update-section","add-table","remove-table","add-column","remove-column","rename-column","retype-column","change-nullable","add-index","remove-index","add-entry","remove-entry","update-entry","bump-version","update-checksum","add-export"])};function j(t,e){const i=x[t];return i?i.has(e):!1}const T=new Set(["pending","pending-surfaced","in_progress","complete","failed","skipped"]),q=new Set(["pending","in_progress","complete","failed","skipped"]),E=new Set(["automated","tool-call","generative"]),N=new Set(["function","interface","type","class","enum","const","script","config","env","schema","manifest","doc","structured-output"]);function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function d(t){return typeof t=="string"}function n(t,e,i){return{path:t,message:e,value:i}}function L(t){var l,y;const e=Object.keys(t),i=new Map,r=new Map;for(const s of e)i.set(s,0),r.set(s,[]);for(const s of e)for(const a of((l=t[s])==null?void 0:l.depends_on)??[])t[a]&&((y=r.get(a))==null||y.push(s),i.set(s,(i.get(s)??0)+1));const p=e.filter(s=>(i.get(s)??0)===0),c=new Set;for(;p.length>0;){const s=p.shift();if(s!==void 0){c.add(s);for(const a of r.get(s)??[]){const u=(i.get(a)??1)-1;i.set(a,u),u===0&&p.push(a)}}}return c.size!==e.length?e.filter(s=>!c.has(s)).map(s=>({slug:s})):null}function R(t,e){for(const i of t){if(!f(i))continue;const r=d(i.id)?i.id:"?",p=i.turns;if(!Array.isArray(p)){e.push(n(`dispatch_log[${r}].turns`,"must be an array",p));continue}for(let c=0;c<p.length;c++){const l=p[c],y=`dispatch_log[${r}].turns[${c}]`;if(!f(l)){e.push(n(y,"must be an object",l));continue}(typeof l.turn!="number"||!Number.isInteger(l.turn)||l.turn<1)&&e.push(n(`${y}.turn`,"must be a positive integer",l.turn)),typeof l.input_tokens!="number"&&e.push(n(`${y}.input_tokens`,"must be a number",l.input_tokens)),typeof l.output_tokens!="number"&&e.push(n(`${y}.output_tokens`,"must be a number",l.output_tokens)),d(l.t)||e.push(n(`${y}.t`,"must be a string",l.t));const s=l.model_calls;s!=null&&typeof s!="number"&&e.push(n(`${y}.model_calls`,"must be a number or null if present",s))}}}function O(t){const e=[];if(!f(t))return{valid:!1,errors:[n("","root must be an object")]};for(const c of["description","problem","approach","executor"]){const l=t[c];(!d(l)||l.trim()==="")&&e.push(n(c,"required string field missing/empty",l))}typeof t.schema_version!="number"&&e.push(n("schema_version","must be a number",t.schema_version));const i=t.plan_kind;i!=="brownfield"&&i!=="greenfield"&&e.push(n("plan_kind",'must be "brownfield" or "greenfield"',i)),Array.isArray(t.phases)?t.phases.length===0&&e.push(n("phases","must have at least one entry")):e.push(n("phases","must be an array",t.phases));const r=t.terminal;!d(r)&&!Array.isArray(r)&&e.push(n("terminal","must be a string or array",r)),Array.isArray(t.dispatch_log)?R(t.dispatch_log,e):e.push(n("dispatch_log","must be an array",t.dispatch_log)),f(t.optimization)||e.push(n("optimization","must be an object",t.optimization)),f(t.providers)||e.push(n("providers","must be an object",t.providers)),f(t.effort_max_tokens)||e.push(n("effort_max_tokens","must be an object",t.effort_max_tokens));const p=t.milestones;if(!f(p))e.push(n("milestones","must be an object",p));else{const c=Object.keys(p);c.length===0&&e.push(n("milestones","must have at least one entry"));const l=new Set(c);for(const u of c){const o=p[u];if(!f(o)){e.push(n(`milestones.${u}`,"must be an object",o));continue}if((!d(o.description)||o.description.trim()==="")&&e.push(n(`milestones.${u}.description`,"required string",o.description)),!Array.isArray(o.depends_on))e.push(n(`milestones.${u}.depends_on`,"must be an array",o.depends_on));else for(const _ of o.depends_on)d(_)?l.has(_)||e.push(n(`milestones.${u}.depends_on`,`unknown milestone "${_}"`)):e.push(n(`milestones.${u}.depends_on[]`,"must be a string",_));const b=o.phase;(!d(b)||b.trim()==="")&&e.push(n(`milestones.${u}.phase`,"required string",b)),(!d(o.authored_by)||o.authored_by.trim()==="")&&e.push(n(`milestones.${u}.authored_by`,"required string",o.authored_by));const m=o.model;m!=null&&!["Haiku","Sonnet","Opus"].includes(m)&&e.push(n(`milestones.${u}.model`,"invalid model tier",m));const h=o.effort;h!=null&&!["low","medium","high","xhigh","max"].includes(h)&&e.push(n(`milestones.${u}.effort`,"invalid effort tier",h)),o.two_stage!==void 0&&typeof o.two_stage!="boolean"&&e.push(n(`milestones.${u}.two_stage`,"must be a boolean",o.two_stage)),Array.isArray(o.read_only)||e.push(n(`milestones.${u}.read_only`,"must be an array",o.read_only))}const y=L(p);if(y)for(const{slug:u}of y)e.push(n(`milestones.${u}`,"dependency cycle detected"));if(d(r)&&!l.has(r))e.push(n("terminal",`unknown milestone "${r}"`));else if(Array.isArray(r))for(const u of r)l.has(u)||e.push(n("terminal[]",`unknown milestone "${u}"`));const s=t.operations,a=new Set;if(!Array.isArray(s)&&!f(s))e.push(n("operations","must be an array or object",s));else{const u=Array.isArray(s)?s:Object.values(s);for(const o of u){if(!f(o)){e.push(n("operations[]","must be an object",o));continue}const b=o.id;if(!d(b)){e.push(n("operations[?]","missing/invalid id",b));continue}const m=b;a.add(m);const h=o.milestone;d(h)?l.has(h)||e.push(n(`operations[${m}].milestone`,`unknown milestone "${h}"`)):e.push(n(`operations[${m}].milestone`,"required string",h));const _=o.type;d(_)&&!E.has(_)&&e.push(n(`operations[${m}].type`,"invalid type",_));const v=o.shape;if(f(v)){const g=v.kind;g!=null&&d(g)&&!N.has(g)&&e.push(n(`operations[${m}].shape.kind`,"invalid shape kind",g));const $=v.ops;if(Array.isArray($)&&d(g))for(let w=0;w<$.length;w++){const k=$[w];if(!f(k))continue;const A=k.op;d(A)&&!j(g,A)&&e.push(n(`operations[${m}].shape.ops[${w}]`,`op "${A}" not valid for kind "${g}"`))}}Array.isArray(o.depends_on)||e.push(n(`operations[${m}].depends_on`,"must be an array",o.depends_on))}for(const o of u){if(!f(o))continue;const b=o.id;if(!d(b))continue;const m=o.depends_on;if(Array.isArray(m))for(const h of m)d(h)&&!a.has(h)&&e.push(n(`operations[${b}].depends_on`,`unknown operation "${h}"`))}}}return{valid:e.length===0,errors:e}}function I(t){const e=[];if(!f(t))return{valid:!1,errors:[n("","root must be an object")]};for(const r of["snapshot_at","description"])d(t[r])||e.push(n(r,"required string field missing",t[r]));d(t.plan)||e.push(n("plan","required string",t.plan));const i=t.milestones;if(!f(i))e.push(n("milestones","must be an object",i));else{const r=Object.keys(i),p=new Set(r);for(const s of r){const a=i[s];if(!f(a)){e.push(n(`milestones.${s}`,"must be an object",a));continue}const u=a.eligible,o=a.pending;u===!0&&o!==null&&o!==void 0&&e.push(n(`milestones.${s}`,"D-07 violation: eligible=true but pending not null")),typeof u!="boolean"&&e.push(n(`milestones.${s}.eligible`,"must be boolean",u));const b=a.status;(!d(b)||!T.has(b))&&e.push(n(`milestones.${s}.status`,"invalid status",b));const m=a.wave;(typeof m!="number"||!Number.isInteger(m)||m<0)&&e.push(n(`milestones.${s}.wave`,"must be non-negative integer",m));const h=a.ki_estimate;h!=null&&typeof h!="number"&&e.push(n(`milestones.${s}.ki_estimate`,"must be number|null",h));for(const _ of["tokens_estimated","tokens_actual"]){const v=a[_];v!=null&&typeof v!="number"&&e.push(n(`milestones.${s}.${_}`,"must be number|null",v))}Array.isArray(a.artifacts)||e.push(n(`milestones.${s}.artifacts`,"must be an array",a.artifacts)),typeof a.si_bytes!="number"&&e.push(n(`milestones.${s}.si_bytes`,"must be a number",a.si_bytes))}const c=t.operations;if(!Array.isArray(c))e.push(n("operations","must be an array",c));else for(const s of c){if(!f(s))continue;const a=d(s.id)?s.id:"?",u=s.milestone;d(u)&&!p.has(u)&&e.push(n(`operations[${a}].milestone`,`unknown milestone "${u}"`));const o=s.status;(!d(o)||!q.has(o))&&e.push(n(`operations[${a}].status`,"invalid operation status",o)),Array.isArray(s.dispatch_ids)||e.push(n(`operations[${a}].dispatch_ids`,"must be an array",s.dispatch_ids)),typeof s.attempt_count!="number"&&e.push(n(`operations[${a}].attempt_count`,"must be a number",s.attempt_count)),Array.isArray(s.blast_radius)||e.push(n(`operations[${a}].blast_radius`,"must be an array",s.blast_radius))}const l=t.open_questions;if(!Array.isArray(l))e.push(n("open_questions","must be an array",l));else for(const s of l){if(!f(s))continue;const a=s.blocking;(!d(a)||!p.has(a))&&e.push(n("open_questions",`unknown blocking milestone "${a}"`)),typeof s.surfaced!="boolean"&&e.push(n(`open_questions[${s.id}]`,"surfaced must be boolean",s.surfaced)),typeof s.answered!="boolean"&&e.push(n(`open_questions[${s.id}]`,"answered must be boolean",s.answered))}const y=t.dispatch_units;if(y!==void 0)if(!Array.isArray(y))e.push(n("dispatch_units","must be an array if present",y));else for(const s of y){if(!f(s))continue;const a=s.fits_context_window;typeof a!="boolean"&&e.push(n(`dispatch_units[${s.id}]`,"fits_context_window must be boolean",a));const u=s.milestones;if(Array.isArray(u))for(const o of u)d(o)&&!p.has(o)&&e.push(n(`dispatch_units[${s.id}].milestones`,`unknown milestone "${o}"`))}f(t.pairwise_overlap)||e.push(n("pairwise_overlap","must be an object",t.pairwise_overlap))}return{valid:e.length===0,errors:e}}function K(t){const e=O(t);if(!e.valid)throw new Error(`DagJson validation failed:
2
- ${e.errors.map(i=>` ${i.path}: ${i.message}`).join(`
3
- `)}`)}function P(t){const e=I(t);if(!e.valid)throw new Error(`Snapshot validation failed:
4
- ${e.errors.map(i=>` ${i.path}: ${i.message}`).join(`
5
- `)}`)}const S=[{from:2,to:3,apply:t=>{!t.milestones&&t.nodes&&(t.milestones=t.nodes,delete t.nodes);const e=t.operations;e&&typeof e=="object"&&!Array.isArray(e)&&(t.operations=Object.values(e))}},{from:3,to:4,apply:t=>{(!t.providers||Object.keys(t.providers).length===0)&&(t.providers={Haiku:{type:"claudecli",model_id:"claude-haiku-4-5",env_secret:null,base_url:null,timeout_ms:6e4,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}},Sonnet:{type:"claudecli",model_id:"claude-sonnet-4-5",env_secret:null,base_url:null,timeout_ms:12e4,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}},Opus:{type:"claudecli",model_id:"claude-opus-4-5",env_secret:null,base_url:null,timeout_ms:3e5,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}}}),(!t.effort_max_tokens||Object.keys(t.effort_max_tokens).length===0)&&(t.effort_max_tokens={low:1024,medium:4096,high:8192,xhigh:16384,max:32768}),t.optimization||(t.optimization={sentinel_fanout:{enabled:!0,write_multiplier:1.25,read_multiplier:.1,hit_probability:.9},b_per_tier:{Haiku:8e3,Sonnet:15e3,Opus:27e3},context_window_per_tier:{Haiku:16e3,Sonnet:16e3,Opus:32e3},context_window_override:null,b_override:null});let e=[];Array.isArray(t.operations)?e=t.operations:t.operations&&typeof t.operations=="object"&&(e=Object.values(t.operations));for(const i of e)if(typeof i=="object"&&i!==null){const r=i;r.type===void 0&&(r.type="generative"),r.criteria===void 0&&(r.criteria=[]),r.tool===void 0&&(r.tool=null),r.args===void 0&&(r.args=null)}}}];function V(t,e,i){if(t===e)return;let r=t;for(const p of[...S].sort((c,l)=>c.from-l.from))if(p.from===r&&(p.apply(i),r=p.to,r===e)){i.schema_version=e;return}throw new Error(`migrateDag: no path from v${t} to v${e}. Available: [${S.map(p=>`v${p.from}→v${p.to}`).join(", ")}]`)}exports.VALID_OPS_BY_KIND=x;exports.WRITE_CLASS_ACTIONS=D;exports.assertValidDagJson=K;exports.assertValidSnapshot=P;exports.isValidOpForKind=j;exports.migrateDag=V;exports.validateDagJson=O;exports.validateSnapshot=I;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=new Set(["create","modify-signature","modify-body","add-export","remove-export","rename"]),x={function:new Set(["add-param","remove-param","rename-param","retype-param","change-param-optional","reorder-params","change-return"]),interface:new Set(["add-field","remove-field","rename-field","retype-field","change-field-optional","add-generic","remove-generic","constrain-generic","add-extends","remove-extends"]),type:new Set(["add-field","remove-field","retype-field"]),class:new Set(["add-field","remove-field","rename-field","retype-field","change-field-optional","add-param","add-generic","remove-generic","constrain-generic","add-extends","remove-extends"]),enum:new Set(["add-field","remove-field","rename-field"]),const:new Set(["add-var","remove-var","rename-var","change-default"]),config:new Set(["set-key","remove-key","rename-key","add-entry","remove-entry","update-entry","bump-version","update-checksum"]),env:new Set(["set-key","remove-key","rename-key"]),schema:new Set(["add-table","remove-table","add-column","remove-column","rename-column","retype-column","change-nullable","add-index","remove-index"]),manifest:new Set(["add-entry","remove-entry","bump-version"]),doc:new Set(["add-section","remove-section","rename-section","update-section"]),"structured-output":new Set([]),script:new Set(["add-param","remove-param","rename-param","retype-param","change-param-optional","reorder-params","change-return","add-field","remove-field","rename-field","retype-field","change-field-optional","add-generic","remove-generic","constrain-generic","add-extends","remove-extends","set-key","remove-key","rename-key","add-array-item","remove-array-item","add-var","remove-var","rename-var","change-default","add-section","remove-section","rename-section","update-section","add-table","remove-table","add-column","remove-column","rename-column","retype-column","change-nullable","add-index","remove-index","add-entry","remove-entry","update-entry","bump-version","update-checksum","add-export"])};function j(t,e){const r=x[t];return r?r.has(e):!1}const T=new Set(["pending","pending-surfaced","in_progress","complete","failed","skipped"]),q=new Set(["pending","in_progress","complete","failed","skipped"]),E=new Set(["automated","tool-call","generative"]),L=new Set(["anthropic","openai","deepseek","google","local","claudecli","teammate"]),N=new Set(["function","interface","type","class","enum","const","script","config","env","schema","manifest","doc","structured-output"]);function h(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function l(t){return typeof t=="string"}function n(t,e,r){return{path:t,message:e,value:r}}function R(t){var c,d;const e=Object.keys(t),r=new Map,a=new Map;for(const s of e)r.set(s,0),a.set(s,[]);for(const s of e)for(const i of((c=t[s])==null?void 0:c.depends_on)??[])t[i]&&((d=a.get(i))==null||d.push(s),r.set(s,(r.get(s)??0)+1));const p=e.filter(s=>(r.get(s)??0)===0),m=new Set;for(;p.length>0;){const s=p.shift();if(s!==void 0){m.add(s);for(const i of a.get(s)??[]){const u=(r.get(i)??1)-1;r.set(i,u),u===0&&p.push(i)}}}return m.size!==e.length?e.filter(s=>!m.has(s)).map(s=>({slug:s})):null}function V(t,e){for(const r of t){if(!h(r))continue;const a=l(r.id)?r.id:"?",p=r.provider;(!l(p)||!L.has(p))&&e.push(n(`dispatch_log[${a}].provider`,"invalid provider",p));const m=r.turns;if(!Array.isArray(m)){e.push(n(`dispatch_log[${a}].turns`,"must be an array",m));continue}for(let c=0;c<m.length;c++){const d=m[c],s=`dispatch_log[${a}].turns[${c}]`;if(!h(d)){e.push(n(s,"must be an object",d));continue}(typeof d.turn!="number"||!Number.isInteger(d.turn)||d.turn<1)&&e.push(n(`${s}.turn`,"must be a positive integer",d.turn)),typeof d.input_tokens!="number"&&e.push(n(`${s}.input_tokens`,"must be a number",d.input_tokens)),typeof d.output_tokens!="number"&&e.push(n(`${s}.output_tokens`,"must be a number",d.output_tokens)),l(d.t)||e.push(n(`${s}.t`,"must be a string",d.t));const i=d.model_calls;i!=null&&typeof i!="number"&&e.push(n(`${s}.model_calls`,"must be a number or null if present",i))}}}function O(t){const e=[];if(!h(t))return{valid:!1,errors:[n("","root must be an object")]};for(const m of["description","problem","approach","executor"]){const c=t[m];(!l(c)||c.trim()==="")&&e.push(n(m,"required string field missing/empty",c))}typeof t.schema_version!="number"&&e.push(n("schema_version","must be a number",t.schema_version));const r=t.plan_kind;r!=="brownfield"&&r!=="greenfield"&&e.push(n("plan_kind",'must be "brownfield" or "greenfield"',r)),Array.isArray(t.phases)?t.phases.length===0&&e.push(n("phases","must have at least one entry")):e.push(n("phases","must be an array",t.phases));const a=t.terminal;!l(a)&&!Array.isArray(a)&&e.push(n("terminal","must be a string or array",a)),Array.isArray(t.dispatch_log)?V(t.dispatch_log,e):e.push(n("dispatch_log","must be an array",t.dispatch_log)),h(t.optimization)||e.push(n("optimization","must be an object",t.optimization)),h(t.providers)||e.push(n("providers","must be an object",t.providers)),h(t.effort_max_tokens)||e.push(n("effort_max_tokens","must be an object",t.effort_max_tokens));const p=t.milestones;if(!h(p))e.push(n("milestones","must be an object",p));else{const m=Object.keys(p);m.length===0&&e.push(n("milestones","must have at least one entry"));const c=new Set(m);for(const u of m){const o=p[u];if(!h(o)){e.push(n(`milestones.${u}`,"must be an object",o));continue}if((!l(o.description)||o.description.trim()==="")&&e.push(n(`milestones.${u}.description`,"required string",o.description)),!Array.isArray(o.depends_on))e.push(n(`milestones.${u}.depends_on`,"must be an array",o.depends_on));else for(const b of o.depends_on)l(b)?c.has(b)||e.push(n(`milestones.${u}.depends_on`,`unknown milestone "${b}"`)):e.push(n(`milestones.${u}.depends_on[]`,"must be a string",b));const _=o.phase;(!l(_)||_.trim()==="")&&e.push(n(`milestones.${u}.phase`,"required string",_)),(!l(o.authored_by)||o.authored_by.trim()==="")&&e.push(n(`milestones.${u}.authored_by`,"required string",o.authored_by));const f=o.model;f!=null&&!["Haiku","Sonnet","Opus"].includes(f)&&e.push(n(`milestones.${u}.model`,"invalid model tier",f));const y=o.effort;y!=null&&!["low","medium","high","xhigh","max"].includes(y)&&e.push(n(`milestones.${u}.effort`,"invalid effort tier",y)),o.two_stage!==void 0&&typeof o.two_stage!="boolean"&&e.push(n(`milestones.${u}.two_stage`,"must be a boolean",o.two_stage)),Array.isArray(o.read_only)||e.push(n(`milestones.${u}.read_only`,"must be an array",o.read_only))}const d=R(p);if(d)for(const{slug:u}of d)e.push(n(`milestones.${u}`,"dependency cycle detected"));if(l(a)&&!c.has(a))e.push(n("terminal",`unknown milestone "${a}"`));else if(Array.isArray(a))for(const u of a)c.has(u)||e.push(n("terminal[]",`unknown milestone "${u}"`));const s=t.operations,i=new Set;if(!Array.isArray(s)&&!h(s))e.push(n("operations","must be an array or object",s));else{const u=Array.isArray(s)?s:Object.values(s);for(const o of u){if(!h(o)){e.push(n("operations[]","must be an object",o));continue}const _=o.id;if(!l(_)){e.push(n("operations[?]","missing/invalid id",_));continue}const f=_;i.add(f);const y=o.milestone;l(y)?c.has(y)||e.push(n(`operations[${f}].milestone`,`unknown milestone "${y}"`)):e.push(n(`operations[${f}].milestone`,"required string",y));const b=o.type;l(b)&&!E.has(b)&&e.push(n(`operations[${f}].type`,"invalid type",b));const v=o.shape;if(h(v)){const g=v.kind;g!=null&&l(g)&&!N.has(g)&&e.push(n(`operations[${f}].shape.kind`,"invalid shape kind",g));const $=v.ops;if(Array.isArray($)&&l(g))for(let w=0;w<$.length;w++){const k=$[w];if(!h(k))continue;const A=k.op;l(A)&&!j(g,A)&&e.push(n(`operations[${f}].shape.ops[${w}]`,`op "${A}" not valid for kind "${g}"`))}}Array.isArray(o.depends_on)||e.push(n(`operations[${f}].depends_on`,"must be an array",o.depends_on))}for(const o of u){if(!h(o))continue;const _=o.id;if(!l(_))continue;const f=o.depends_on;if(Array.isArray(f))for(const y of f)l(y)&&!i.has(y)&&e.push(n(`operations[${_}].depends_on`,`unknown operation "${y}"`))}}}return{valid:e.length===0,errors:e}}function I(t){const e=[];if(!h(t))return{valid:!1,errors:[n("","root must be an object")]};for(const a of["snapshot_at","description"])l(t[a])||e.push(n(a,"required string field missing",t[a]));l(t.plan)||e.push(n("plan","required string",t.plan));const r=t.milestones;if(!h(r))e.push(n("milestones","must be an object",r));else{const a=Object.keys(r),p=new Set(a);for(const s of a){const i=r[s];if(!h(i)){e.push(n(`milestones.${s}`,"must be an object",i));continue}const u=i.eligible,o=i.pending;u===!0&&o!==null&&o!==void 0&&e.push(n(`milestones.${s}`,"D-07 violation: eligible=true but pending not null")),typeof u!="boolean"&&e.push(n(`milestones.${s}.eligible`,"must be boolean",u));const _=i.status;(!l(_)||!T.has(_))&&e.push(n(`milestones.${s}.status`,"invalid status",_));const f=i.wave;(typeof f!="number"||!Number.isInteger(f)||f<0)&&e.push(n(`milestones.${s}.wave`,"must be non-negative integer",f));const y=i.ki_estimate;y!=null&&typeof y!="number"&&e.push(n(`milestones.${s}.ki_estimate`,"must be number|null",y));for(const b of["tokens_estimated","tokens_actual"]){const v=i[b];v!=null&&typeof v!="number"&&e.push(n(`milestones.${s}.${b}`,"must be number|null",v))}Array.isArray(i.artifacts)||e.push(n(`milestones.${s}.artifacts`,"must be an array",i.artifacts)),typeof i.si_bytes!="number"&&e.push(n(`milestones.${s}.si_bytes`,"must be a number",i.si_bytes))}const m=t.operations;if(!Array.isArray(m))e.push(n("operations","must be an array",m));else for(const s of m){if(!h(s))continue;const i=l(s.id)?s.id:"?",u=s.milestone;l(u)&&!p.has(u)&&e.push(n(`operations[${i}].milestone`,`unknown milestone "${u}"`));const o=s.status;(!l(o)||!q.has(o))&&e.push(n(`operations[${i}].status`,"invalid operation status",o)),Array.isArray(s.dispatch_ids)||e.push(n(`operations[${i}].dispatch_ids`,"must be an array",s.dispatch_ids)),typeof s.attempt_count!="number"&&e.push(n(`operations[${i}].attempt_count`,"must be a number",s.attempt_count)),Array.isArray(s.blast_radius)||e.push(n(`operations[${i}].blast_radius`,"must be an array",s.blast_radius))}const c=t.open_questions;if(!Array.isArray(c))e.push(n("open_questions","must be an array",c));else for(const s of c){if(!h(s))continue;const i=s.blocking;(!l(i)||!p.has(i))&&e.push(n("open_questions",`unknown blocking milestone "${i}"`)),typeof s.surfaced!="boolean"&&e.push(n(`open_questions[${s.id}]`,"surfaced must be boolean",s.surfaced)),typeof s.answered!="boolean"&&e.push(n(`open_questions[${s.id}]`,"answered must be boolean",s.answered))}const d=t.dispatch_units;if(d!==void 0)if(!Array.isArray(d))e.push(n("dispatch_units","must be an array if present",d));else for(const s of d){if(!h(s))continue;const i=s.fits_context_window;typeof i!="boolean"&&e.push(n(`dispatch_units[${s.id}]`,"fits_context_window must be boolean",i));const u=s.milestones;if(Array.isArray(u))for(const o of u)l(o)&&!p.has(o)&&e.push(n(`dispatch_units[${s.id}].milestones`,`unknown milestone "${o}"`))}h(t.pairwise_overlap)||e.push(n("pairwise_overlap","must be an object",t.pairwise_overlap))}return{valid:e.length===0,errors:e}}function P(t){const e=O(t);if(!e.valid)throw new Error(`DagJson validation failed:
2
+ ${e.errors.map(r=>` ${r.path}: ${r.message}`).join(`
3
+ `)}`)}function K(t){const e=I(t);if(!e.valid)throw new Error(`Snapshot validation failed:
4
+ ${e.errors.map(r=>` ${r.path}: ${r.message}`).join(`
5
+ `)}`)}const S=[{from:2,to:3,apply:t=>{!t.milestones&&t.nodes&&(t.milestones=t.nodes,delete t.nodes);const e=t.operations;e&&typeof e=="object"&&!Array.isArray(e)&&(t.operations=Object.values(e))}},{from:3,to:4,apply:t=>{(!t.providers||Object.keys(t.providers).length===0)&&(t.providers={Haiku:{type:"claudecli",model_id:"claude-haiku-4-5",env_secret:null,base_url:null,timeout_ms:6e4,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}},Sonnet:{type:"claudecli",model_id:"claude-sonnet-4-5",env_secret:null,base_url:null,timeout_ms:12e4,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}},Opus:{type:"claudecli",model_id:"claude-opus-4-5",env_secret:null,base_url:null,timeout_ms:3e5,retry_config:{retries:3,min_timeout:1e3,max_timeout:3e4,factor:2}}}),(!t.effort_max_tokens||Object.keys(t.effort_max_tokens).length===0)&&(t.effort_max_tokens={low:1024,medium:4096,high:8192,xhigh:16384,max:32768}),t.optimization||(t.optimization={sentinel_fanout:{enabled:!0,write_multiplier:1.25,read_multiplier:.1,hit_probability:.9},b_per_tier:{Haiku:8e3,Sonnet:15e3,Opus:27e3},context_window_per_tier:{Haiku:16e3,Sonnet:16e3,Opus:32e3},context_window_override:null,b_override:null});let e=[];Array.isArray(t.operations)?e=t.operations:t.operations&&typeof t.operations=="object"&&(e=Object.values(t.operations));for(const r of e)if(typeof r=="object"&&r!==null){const a=r;a.type===void 0&&(a.type="generative"),a.criteria===void 0&&(a.criteria=[]),a.tool===void 0&&(a.tool=null),a.args===void 0&&(a.args=null)}}}];function z(t,e,r){if(t===e)return;let a=t;for(const p of[...S].sort((m,c)=>m.from-c.from))if(p.from===a&&(p.apply(r),a=p.to,a===e)){r.schema_version=e;return}throw new Error(`migrateDag: no path from v${t} to v${e}. Available: [${S.map(p=>`v${p.from}→v${p.to}`).join(", ")}]`)}exports.VALID_OPS_BY_KIND=x;exports.WRITE_CLASS_ACTIONS=D;exports.assertValidDagJson=P;exports.assertValidSnapshot=K;exports.isValidOpForKind=j;exports.migrateDag=z;exports.validateDagJson=O;exports.validateSnapshot=I;
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const R = /* @__PURE__ */ new Set([
1
+ const z = /* @__PURE__ */ new Set([
2
2
  "create",
3
3
  "modify-signature",
4
4
  "modify-body",
@@ -127,8 +127,8 @@ const R = /* @__PURE__ */ new Set([
127
127
  ])
128
128
  };
129
129
  function j(t, e) {
130
- const i = x[t];
131
- return i ? i.has(e) : !1;
130
+ const r = x[t];
131
+ return r ? r.has(e) : !1;
132
132
  }
133
133
  const O = /* @__PURE__ */ new Set([
134
134
  "pending",
@@ -143,7 +143,15 @@ const O = /* @__PURE__ */ new Set([
143
143
  "complete",
144
144
  "failed",
145
145
  "skipped"
146
- ]), q = /* @__PURE__ */ new Set(["automated", "tool-call", "generative"]), D = /* @__PURE__ */ new Set([
146
+ ]), D = /* @__PURE__ */ new Set(["automated", "tool-call", "generative"]), q = /* @__PURE__ */ new Set([
147
+ "anthropic",
148
+ "openai",
149
+ "deepseek",
150
+ "google",
151
+ "local",
152
+ "claudecli",
153
+ "teammate"
154
+ ]), E = /* @__PURE__ */ new Set([
147
155
  "function",
148
156
  "interface",
149
157
  "type",
@@ -158,227 +166,229 @@ const O = /* @__PURE__ */ new Set([
158
166
  "doc",
159
167
  "structured-output"
160
168
  ]);
161
- function f(t) {
169
+ function h(t) {
162
170
  return typeof t == "object" && t !== null && !Array.isArray(t);
163
171
  }
164
- function c(t) {
172
+ function l(t) {
165
173
  return typeof t == "string";
166
174
  }
167
- function n(t, e, i) {
168
- return { path: t, message: e, value: i };
175
+ function n(t, e, r) {
176
+ return { path: t, message: e, value: r };
169
177
  }
170
178
  function T(t) {
171
- var l, y;
172
- const e = Object.keys(t), i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
173
- for (const s of e)
174
- i.set(s, 0), r.set(s, []);
175
- for (const s of e)
176
- for (const a of ((l = t[s]) == null ? void 0 : l.depends_on) ?? [])
177
- t[a] && ((y = r.get(a)) == null || y.push(s), i.set(s, (i.get(s) ?? 0) + 1));
178
- const p = e.filter((s) => (i.get(s) ?? 0) === 0), d = /* @__PURE__ */ new Set();
179
+ var d, c;
180
+ const e = Object.keys(t), r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map();
181
+ for (const o of e)
182
+ r.set(o, 0), a.set(o, []);
183
+ for (const o of e)
184
+ for (const i of ((d = t[o]) == null ? void 0 : d.depends_on) ?? [])
185
+ t[i] && ((c = a.get(i)) == null || c.push(o), r.set(o, (r.get(o) ?? 0) + 1));
186
+ const p = e.filter((o) => (r.get(o) ?? 0) === 0), m = /* @__PURE__ */ new Set();
179
187
  for (; p.length > 0; ) {
180
- const s = p.shift();
181
- if (s !== void 0) {
182
- d.add(s);
183
- for (const a of r.get(s) ?? []) {
184
- const u = (i.get(a) ?? 1) - 1;
185
- i.set(a, u), u === 0 && p.push(a);
188
+ const o = p.shift();
189
+ if (o !== void 0) {
190
+ m.add(o);
191
+ for (const i of a.get(o) ?? []) {
192
+ const u = (r.get(i) ?? 1) - 1;
193
+ r.set(i, u), u === 0 && p.push(i);
186
194
  }
187
195
  }
188
196
  }
189
- return d.size !== e.length ? e.filter((s) => !d.has(s)).map((s) => ({ slug: s })) : null;
197
+ return m.size !== e.length ? e.filter((o) => !m.has(o)).map((o) => ({ slug: o })) : null;
190
198
  }
191
- function E(t, e) {
192
- for (const i of t) {
193
- if (!f(i))
199
+ function R(t, e) {
200
+ for (const r of t) {
201
+ if (!h(r))
194
202
  continue;
195
- const r = c(i.id) ? i.id : "?", p = i.turns;
196
- if (!Array.isArray(p)) {
203
+ const a = l(r.id) ? r.id : "?", p = r.provider;
204
+ (!l(p) || !q.has(p)) && e.push(n(`dispatch_log[${a}].provider`, "invalid provider", p));
205
+ const m = r.turns;
206
+ if (!Array.isArray(m)) {
197
207
  e.push(
198
- n(`dispatch_log[${r}].turns`, "must be an array", p)
208
+ n(`dispatch_log[${a}].turns`, "must be an array", m)
199
209
  );
200
210
  continue;
201
211
  }
202
- for (let d = 0; d < p.length; d++) {
203
- const l = p[d], y = `dispatch_log[${r}].turns[${d}]`;
204
- if (!f(l)) {
205
- e.push(n(y, "must be an object", l));
212
+ for (let d = 0; d < m.length; d++) {
213
+ const c = m[d], o = `dispatch_log[${a}].turns[${d}]`;
214
+ if (!h(c)) {
215
+ e.push(n(o, "must be an object", c));
206
216
  continue;
207
217
  }
208
- (typeof l.turn != "number" || !Number.isInteger(l.turn) || l.turn < 1) && e.push(n(`${y}.turn`, "must be a positive integer", l.turn)), typeof l.input_tokens != "number" && e.push(
209
- n(`${y}.input_tokens`, "must be a number", l.input_tokens)
210
- ), typeof l.output_tokens != "number" && e.push(
211
- n(`${y}.output_tokens`, "must be a number", l.output_tokens)
212
- ), c(l.t) || e.push(n(`${y}.t`, "must be a string", l.t));
213
- const s = l.model_calls;
214
- s != null && typeof s != "number" && e.push(
218
+ (typeof c.turn != "number" || !Number.isInteger(c.turn) || c.turn < 1) && e.push(n(`${o}.turn`, "must be a positive integer", c.turn)), typeof c.input_tokens != "number" && e.push(
219
+ n(`${o}.input_tokens`, "must be a number", c.input_tokens)
220
+ ), typeof c.output_tokens != "number" && e.push(
221
+ n(`${o}.output_tokens`, "must be a number", c.output_tokens)
222
+ ), l(c.t) || e.push(n(`${o}.t`, "must be a string", c.t));
223
+ const i = c.model_calls;
224
+ i != null && typeof i != "number" && e.push(
215
225
  n(
216
- `${y}.model_calls`,
226
+ `${o}.model_calls`,
217
227
  "must be a number or null if present",
218
- s
228
+ i
219
229
  )
220
230
  );
221
231
  }
222
232
  }
223
233
  }
224
- function N(t) {
234
+ function L(t) {
225
235
  const e = [];
226
- if (!f(t))
236
+ if (!h(t))
227
237
  return { valid: !1, errors: [n("", "root must be an object")] };
228
- for (const d of ["description", "problem", "approach", "executor"]) {
229
- const l = t[d];
230
- (!c(l) || l.trim() === "") && e.push(n(d, "required string field missing/empty", l));
238
+ for (const m of ["description", "problem", "approach", "executor"]) {
239
+ const d = t[m];
240
+ (!l(d) || d.trim() === "") && e.push(n(m, "required string field missing/empty", d));
231
241
  }
232
242
  typeof t.schema_version != "number" && e.push(
233
243
  n("schema_version", "must be a number", t.schema_version)
234
244
  );
235
- const i = t.plan_kind;
236
- i !== "brownfield" && i !== "greenfield" && e.push(n("plan_kind", 'must be "brownfield" or "greenfield"', i)), Array.isArray(t.phases) ? t.phases.length === 0 && e.push(n("phases", "must have at least one entry")) : e.push(n("phases", "must be an array", t.phases));
237
- const r = t.terminal;
238
- !c(r) && !Array.isArray(r) && e.push(n("terminal", "must be a string or array", r)), Array.isArray(t.dispatch_log) ? E(t.dispatch_log, e) : e.push(n("dispatch_log", "must be an array", t.dispatch_log)), f(t.optimization) || e.push(n("optimization", "must be an object", t.optimization)), f(t.providers) || e.push(n("providers", "must be an object", t.providers)), f(t.effort_max_tokens) || e.push(
245
+ const r = t.plan_kind;
246
+ r !== "brownfield" && r !== "greenfield" && e.push(n("plan_kind", 'must be "brownfield" or "greenfield"', r)), Array.isArray(t.phases) ? t.phases.length === 0 && e.push(n("phases", "must have at least one entry")) : e.push(n("phases", "must be an array", t.phases));
247
+ const a = t.terminal;
248
+ !l(a) && !Array.isArray(a) && e.push(n("terminal", "must be a string or array", a)), Array.isArray(t.dispatch_log) ? R(t.dispatch_log, e) : e.push(n("dispatch_log", "must be an array", t.dispatch_log)), h(t.optimization) || e.push(n("optimization", "must be an object", t.optimization)), h(t.providers) || e.push(n("providers", "must be an object", t.providers)), h(t.effort_max_tokens) || e.push(
239
249
  n("effort_max_tokens", "must be an object", t.effort_max_tokens)
240
250
  );
241
251
  const p = t.milestones;
242
- if (!f(p))
252
+ if (!h(p))
243
253
  e.push(n("milestones", "must be an object", p));
244
254
  else {
245
- const d = Object.keys(p);
246
- d.length === 0 && e.push(n("milestones", "must have at least one entry"));
247
- const l = new Set(d);
248
- for (const u of d) {
249
- const o = p[u];
250
- if (!f(o)) {
251
- e.push(n(`milestones.${u}`, "must be an object", o));
255
+ const m = Object.keys(p);
256
+ m.length === 0 && e.push(n("milestones", "must have at least one entry"));
257
+ const d = new Set(m);
258
+ for (const u of m) {
259
+ const s = p[u];
260
+ if (!h(s)) {
261
+ e.push(n(`milestones.${u}`, "must be an object", s));
252
262
  continue;
253
263
  }
254
- if ((!c(o.description) || o.description.trim() === "") && e.push(
264
+ if ((!l(s.description) || s.description.trim() === "") && e.push(
255
265
  n(
256
266
  `milestones.${u}.description`,
257
267
  "required string",
258
- o.description
268
+ s.description
259
269
  )
260
- ), !Array.isArray(o.depends_on))
270
+ ), !Array.isArray(s.depends_on))
261
271
  e.push(
262
272
  n(
263
273
  `milestones.${u}.depends_on`,
264
274
  "must be an array",
265
- o.depends_on
275
+ s.depends_on
266
276
  )
267
277
  );
268
278
  else
269
- for (const _ of o.depends_on)
270
- c(_) ? l.has(_) || e.push(
279
+ for (const _ of s.depends_on)
280
+ l(_) ? d.has(_) || e.push(
271
281
  n(`milestones.${u}.depends_on`, `unknown milestone "${_}"`)
272
282
  ) : e.push(
273
283
  n(`milestones.${u}.depends_on[]`, "must be a string", _)
274
284
  );
275
- const b = o.phase;
276
- (!c(b) || b.trim() === "") && e.push(n(`milestones.${u}.phase`, "required string", b)), (!c(o.authored_by) || o.authored_by.trim() === "") && e.push(
285
+ const b = s.phase;
286
+ (!l(b) || b.trim() === "") && e.push(n(`milestones.${u}.phase`, "required string", b)), (!l(s.authored_by) || s.authored_by.trim() === "") && e.push(
277
287
  n(
278
288
  `milestones.${u}.authored_by`,
279
289
  "required string",
280
- o.authored_by
290
+ s.authored_by
281
291
  )
282
292
  );
283
- const m = o.model;
284
- m != null && !["Haiku", "Sonnet", "Opus"].includes(m) && e.push(
285
- n(`milestones.${u}.model`, "invalid model tier", m)
293
+ const f = s.model;
294
+ f != null && !["Haiku", "Sonnet", "Opus"].includes(f) && e.push(
295
+ n(`milestones.${u}.model`, "invalid model tier", f)
286
296
  );
287
- const h = o.effort;
288
- h != null && !["low", "medium", "high", "xhigh", "max"].includes(h) && e.push(
289
- n(`milestones.${u}.effort`, "invalid effort tier", h)
290
- ), o.two_stage !== void 0 && typeof o.two_stage != "boolean" && e.push(
297
+ const y = s.effort;
298
+ y != null && !["low", "medium", "high", "xhigh", "max"].includes(y) && e.push(
299
+ n(`milestones.${u}.effort`, "invalid effort tier", y)
300
+ ), s.two_stage !== void 0 && typeof s.two_stage != "boolean" && e.push(
291
301
  n(
292
302
  `milestones.${u}.two_stage`,
293
303
  "must be a boolean",
294
- o.two_stage
304
+ s.two_stage
295
305
  )
296
- ), Array.isArray(o.read_only) || e.push(
306
+ ), Array.isArray(s.read_only) || e.push(
297
307
  n(
298
308
  `milestones.${u}.read_only`,
299
309
  "must be an array",
300
- o.read_only
310
+ s.read_only
301
311
  )
302
312
  );
303
313
  }
304
- const y = T(
314
+ const c = T(
305
315
  p
306
316
  );
307
- if (y)
308
- for (const { slug: u } of y)
317
+ if (c)
318
+ for (const { slug: u } of c)
309
319
  e.push(n(`milestones.${u}`, "dependency cycle detected"));
310
- if (c(r) && !l.has(r))
311
- e.push(n("terminal", `unknown milestone "${r}"`));
312
- else if (Array.isArray(r))
313
- for (const u of r)
314
- l.has(u) || e.push(n("terminal[]", `unknown milestone "${u}"`));
315
- const s = t.operations, a = /* @__PURE__ */ new Set();
316
- if (!Array.isArray(s) && !f(s))
317
- e.push(n("operations", "must be an array or object", s));
320
+ if (l(a) && !d.has(a))
321
+ e.push(n("terminal", `unknown milestone "${a}"`));
322
+ else if (Array.isArray(a))
323
+ for (const u of a)
324
+ d.has(u) || e.push(n("terminal[]", `unknown milestone "${u}"`));
325
+ const o = t.operations, i = /* @__PURE__ */ new Set();
326
+ if (!Array.isArray(o) && !h(o))
327
+ e.push(n("operations", "must be an array or object", o));
318
328
  else {
319
- const u = Array.isArray(s) ? s : Object.values(s);
320
- for (const o of u) {
321
- if (!f(o)) {
322
- e.push(n("operations[]", "must be an object", o));
329
+ const u = Array.isArray(o) ? o : Object.values(o);
330
+ for (const s of u) {
331
+ if (!h(s)) {
332
+ e.push(n("operations[]", "must be an object", s));
323
333
  continue;
324
334
  }
325
- const b = o.id;
326
- if (!c(b)) {
335
+ const b = s.id;
336
+ if (!l(b)) {
327
337
  e.push(n("operations[?]", "missing/invalid id", b));
328
338
  continue;
329
339
  }
330
- const m = b;
331
- a.add(m);
332
- const h = o.milestone;
333
- c(h) ? l.has(h) || e.push(
334
- n(`operations[${m}].milestone`, `unknown milestone "${h}"`)
340
+ const f = b;
341
+ i.add(f);
342
+ const y = s.milestone;
343
+ l(y) ? d.has(y) || e.push(
344
+ n(`operations[${f}].milestone`, `unknown milestone "${y}"`)
335
345
  ) : e.push(
336
- n(`operations[${m}].milestone`, "required string", h)
346
+ n(`operations[${f}].milestone`, "required string", y)
337
347
  );
338
- const _ = o.type;
339
- c(_) && !q.has(_) && e.push(n(`operations[${m}].type`, "invalid type", _));
340
- const v = o.shape;
341
- if (f(v)) {
348
+ const _ = s.type;
349
+ l(_) && !D.has(_) && e.push(n(`operations[${f}].type`, "invalid type", _));
350
+ const v = s.shape;
351
+ if (h(v)) {
342
352
  const g = v.kind;
343
- g != null && c(g) && !D.has(g) && e.push(
344
- n(`operations[${m}].shape.kind`, "invalid shape kind", g)
353
+ g != null && l(g) && !E.has(g) && e.push(
354
+ n(`operations[${f}].shape.kind`, "invalid shape kind", g)
345
355
  );
346
356
  const $ = v.ops;
347
- if (Array.isArray($) && c(g))
357
+ if (Array.isArray($) && l(g))
348
358
  for (let w = 0; w < $.length; w++) {
349
359
  const A = $[w];
350
- if (!f(A))
360
+ if (!h(A))
351
361
  continue;
352
362
  const k = A.op;
353
- c(k) && !j(g, k) && e.push(
363
+ l(k) && !j(g, k) && e.push(
354
364
  n(
355
- `operations[${m}].shape.ops[${w}]`,
365
+ `operations[${f}].shape.ops[${w}]`,
356
366
  `op "${k}" not valid for kind "${g}"`
357
367
  )
358
368
  );
359
369
  }
360
370
  }
361
- Array.isArray(o.depends_on) || e.push(
371
+ Array.isArray(s.depends_on) || e.push(
362
372
  n(
363
- `operations[${m}].depends_on`,
373
+ `operations[${f}].depends_on`,
364
374
  "must be an array",
365
- o.depends_on
375
+ s.depends_on
366
376
  )
367
377
  );
368
378
  }
369
- for (const o of u) {
370
- if (!f(o))
379
+ for (const s of u) {
380
+ if (!h(s))
371
381
  continue;
372
- const b = o.id;
373
- if (!c(b))
382
+ const b = s.id;
383
+ if (!l(b))
374
384
  continue;
375
- const m = o.depends_on;
376
- if (Array.isArray(m))
377
- for (const h of m)
378
- c(h) && !a.has(h) && e.push(
385
+ const f = s.depends_on;
386
+ if (Array.isArray(f))
387
+ for (const y of f)
388
+ l(y) && !i.has(y) && e.push(
379
389
  n(
380
390
  `operations[${b}].depends_on`,
381
- `unknown operation "${h}"`
391
+ `unknown operation "${y}"`
382
392
  )
383
393
  );
384
394
  }
@@ -386,151 +396,151 @@ function N(t) {
386
396
  }
387
397
  return { valid: e.length === 0, errors: e };
388
398
  }
389
- function L(t) {
399
+ function N(t) {
390
400
  const e = [];
391
- if (!f(t))
401
+ if (!h(t))
392
402
  return { valid: !1, errors: [n("", "root must be an object")] };
393
- for (const r of ["snapshot_at", "description"])
394
- c(t[r]) || e.push(n(r, "required string field missing", t[r]));
395
- c(t.plan) || e.push(n("plan", "required string", t.plan));
396
- const i = t.milestones;
397
- if (!f(i))
398
- e.push(n("milestones", "must be an object", i));
403
+ for (const a of ["snapshot_at", "description"])
404
+ l(t[a]) || e.push(n(a, "required string field missing", t[a]));
405
+ l(t.plan) || e.push(n("plan", "required string", t.plan));
406
+ const r = t.milestones;
407
+ if (!h(r))
408
+ e.push(n("milestones", "must be an object", r));
399
409
  else {
400
- const r = Object.keys(i), p = new Set(r);
401
- for (const s of r) {
402
- const a = i[s];
403
- if (!f(a)) {
404
- e.push(n(`milestones.${s}`, "must be an object", a));
410
+ const a = Object.keys(r), p = new Set(a);
411
+ for (const o of a) {
412
+ const i = r[o];
413
+ if (!h(i)) {
414
+ e.push(n(`milestones.${o}`, "must be an object", i));
405
415
  continue;
406
416
  }
407
- const u = a.eligible, o = a.pending;
408
- u === !0 && o !== null && o !== void 0 && e.push(
417
+ const u = i.eligible, s = i.pending;
418
+ u === !0 && s !== null && s !== void 0 && e.push(
409
419
  n(
410
- `milestones.${s}`,
420
+ `milestones.${o}`,
411
421
  "D-07 violation: eligible=true but pending not null"
412
422
  )
413
423
  ), typeof u != "boolean" && e.push(
414
- n(`milestones.${s}.eligible`, "must be boolean", u)
424
+ n(`milestones.${o}.eligible`, "must be boolean", u)
415
425
  );
416
- const b = a.status;
417
- (!c(b) || !O.has(b)) && e.push(n(`milestones.${s}.status`, "invalid status", b));
418
- const m = a.wave;
419
- (typeof m != "number" || !Number.isInteger(m) || m < 0) && e.push(
420
- n(`milestones.${s}.wave`, "must be non-negative integer", m)
426
+ const b = i.status;
427
+ (!l(b) || !O.has(b)) && e.push(n(`milestones.${o}.status`, "invalid status", b));
428
+ const f = i.wave;
429
+ (typeof f != "number" || !Number.isInteger(f) || f < 0) && e.push(
430
+ n(`milestones.${o}.wave`, "must be non-negative integer", f)
421
431
  );
422
- const h = a.ki_estimate;
423
- h != null && typeof h != "number" && e.push(
424
- n(`milestones.${s}.ki_estimate`, "must be number|null", h)
432
+ const y = i.ki_estimate;
433
+ y != null && typeof y != "number" && e.push(
434
+ n(`milestones.${o}.ki_estimate`, "must be number|null", y)
425
435
  );
426
436
  for (const _ of ["tokens_estimated", "tokens_actual"]) {
427
- const v = a[_];
428
- v != null && typeof v != "number" && e.push(n(`milestones.${s}.${_}`, "must be number|null", v));
437
+ const v = i[_];
438
+ v != null && typeof v != "number" && e.push(n(`milestones.${o}.${_}`, "must be number|null", v));
429
439
  }
430
- Array.isArray(a.artifacts) || e.push(
440
+ Array.isArray(i.artifacts) || e.push(
431
441
  n(
432
- `milestones.${s}.artifacts`,
442
+ `milestones.${o}.artifacts`,
433
443
  "must be an array",
434
- a.artifacts
444
+ i.artifacts
435
445
  )
436
- ), typeof a.si_bytes != "number" && e.push(
437
- n(`milestones.${s}.si_bytes`, "must be a number", a.si_bytes)
446
+ ), typeof i.si_bytes != "number" && e.push(
447
+ n(`milestones.${o}.si_bytes`, "must be a number", i.si_bytes)
438
448
  );
439
449
  }
440
- const d = t.operations;
441
- if (!Array.isArray(d))
442
- e.push(n("operations", "must be an array", d));
450
+ const m = t.operations;
451
+ if (!Array.isArray(m))
452
+ e.push(n("operations", "must be an array", m));
443
453
  else
444
- for (const s of d) {
445
- if (!f(s))
454
+ for (const o of m) {
455
+ if (!h(o))
446
456
  continue;
447
- const a = c(s.id) ? s.id : "?", u = s.milestone;
448
- c(u) && !p.has(u) && e.push(
457
+ const i = l(o.id) ? o.id : "?", u = o.milestone;
458
+ l(u) && !p.has(u) && e.push(
449
459
  n(
450
- `operations[${a}].milestone`,
460
+ `operations[${i}].milestone`,
451
461
  `unknown milestone "${u}"`
452
462
  )
453
463
  );
454
- const o = s.status;
455
- (!c(o) || !I.has(o)) && e.push(
464
+ const s = o.status;
465
+ (!l(s) || !I.has(s)) && e.push(
456
466
  n(
457
- `operations[${a}].status`,
467
+ `operations[${i}].status`,
458
468
  "invalid operation status",
459
- o
469
+ s
460
470
  )
461
- ), Array.isArray(s.dispatch_ids) || e.push(
471
+ ), Array.isArray(o.dispatch_ids) || e.push(
462
472
  n(
463
- `operations[${a}].dispatch_ids`,
473
+ `operations[${i}].dispatch_ids`,
464
474
  "must be an array",
465
- s.dispatch_ids
475
+ o.dispatch_ids
466
476
  )
467
- ), typeof s.attempt_count != "number" && e.push(
477
+ ), typeof o.attempt_count != "number" && e.push(
468
478
  n(
469
- `operations[${a}].attempt_count`,
479
+ `operations[${i}].attempt_count`,
470
480
  "must be a number",
471
- s.attempt_count
481
+ o.attempt_count
472
482
  )
473
- ), Array.isArray(s.blast_radius) || e.push(
483
+ ), Array.isArray(o.blast_radius) || e.push(
474
484
  n(
475
- `operations[${a}].blast_radius`,
485
+ `operations[${i}].blast_radius`,
476
486
  "must be an array",
477
- s.blast_radius
487
+ o.blast_radius
478
488
  )
479
489
  );
480
490
  }
481
- const l = t.open_questions;
482
- if (!Array.isArray(l))
483
- e.push(n("open_questions", "must be an array", l));
491
+ const d = t.open_questions;
492
+ if (!Array.isArray(d))
493
+ e.push(n("open_questions", "must be an array", d));
484
494
  else
485
- for (const s of l) {
486
- if (!f(s))
495
+ for (const o of d) {
496
+ if (!h(o))
487
497
  continue;
488
- const a = s.blocking;
489
- (!c(a) || !p.has(a)) && e.push(
490
- n("open_questions", `unknown blocking milestone "${a}"`)
491
- ), typeof s.surfaced != "boolean" && e.push(
498
+ const i = o.blocking;
499
+ (!l(i) || !p.has(i)) && e.push(
500
+ n("open_questions", `unknown blocking milestone "${i}"`)
501
+ ), typeof o.surfaced != "boolean" && e.push(
492
502
  n(
493
- `open_questions[${s.id}]`,
503
+ `open_questions[${o.id}]`,
494
504
  "surfaced must be boolean",
495
- s.surfaced
505
+ o.surfaced
496
506
  )
497
- ), typeof s.answered != "boolean" && e.push(
507
+ ), typeof o.answered != "boolean" && e.push(
498
508
  n(
499
- `open_questions[${s.id}]`,
509
+ `open_questions[${o.id}]`,
500
510
  "answered must be boolean",
501
- s.answered
511
+ o.answered
502
512
  )
503
513
  );
504
514
  }
505
- const y = t.dispatch_units;
506
- if (y !== void 0)
507
- if (!Array.isArray(y))
515
+ const c = t.dispatch_units;
516
+ if (c !== void 0)
517
+ if (!Array.isArray(c))
508
518
  e.push(
509
- n("dispatch_units", "must be an array if present", y)
519
+ n("dispatch_units", "must be an array if present", c)
510
520
  );
511
521
  else
512
- for (const s of y) {
513
- if (!f(s))
522
+ for (const o of c) {
523
+ if (!h(o))
514
524
  continue;
515
- const a = s.fits_context_window;
516
- typeof a != "boolean" && e.push(
525
+ const i = o.fits_context_window;
526
+ typeof i != "boolean" && e.push(
517
527
  n(
518
- `dispatch_units[${s.id}]`,
528
+ `dispatch_units[${o.id}]`,
519
529
  "fits_context_window must be boolean",
520
- a
530
+ i
521
531
  )
522
532
  );
523
- const u = s.milestones;
533
+ const u = o.milestones;
524
534
  if (Array.isArray(u))
525
- for (const o of u)
526
- c(o) && !p.has(o) && e.push(
535
+ for (const s of u)
536
+ l(s) && !p.has(s) && e.push(
527
537
  n(
528
- `dispatch_units[${s.id}].milestones`,
529
- `unknown milestone "${o}"`
538
+ `dispatch_units[${o.id}].milestones`,
539
+ `unknown milestone "${s}"`
530
540
  )
531
541
  );
532
542
  }
533
- f(t.pairwise_overlap) || e.push(
543
+ h(t.pairwise_overlap) || e.push(
534
544
  n(
535
545
  "pairwise_overlap",
536
546
  "must be an object",
@@ -540,21 +550,21 @@ function L(t) {
540
550
  }
541
551
  return { valid: e.length === 0, errors: e };
542
552
  }
543
- function z(t) {
544
- const e = N(t);
553
+ function P(t) {
554
+ const e = L(t);
545
555
  if (!e.valid)
546
556
  throw new Error(
547
557
  `DagJson validation failed:
548
- ${e.errors.map((i) => ` ${i.path}: ${i.message}`).join(`
558
+ ${e.errors.map((r) => ` ${r.path}: ${r.message}`).join(`
549
559
  `)}`
550
560
  );
551
561
  }
552
562
  function H(t) {
553
- const e = L(t);
563
+ const e = N(t);
554
564
  if (!e.valid)
555
565
  throw new Error(
556
566
  `Snapshot validation failed:
557
- ${e.errors.map((i) => ` ${i.path}: ${i.message}`).join(`
567
+ ${e.errors.map((r) => ` ${r.path}: ${r.message}`).join(`
558
568
  `)}`
559
569
  );
560
570
  }
@@ -632,21 +642,21 @@ const S = [
632
642
  });
633
643
  let e = [];
634
644
  Array.isArray(t.operations) ? e = t.operations : t.operations && typeof t.operations == "object" && (e = Object.values(t.operations));
635
- for (const i of e)
636
- if (typeof i == "object" && i !== null) {
637
- const r = i;
638
- r.type === void 0 && (r.type = "generative"), r.criteria === void 0 && (r.criteria = []), r.tool === void 0 && (r.tool = null), r.args === void 0 && (r.args = null);
645
+ for (const r of e)
646
+ if (typeof r == "object" && r !== null) {
647
+ const a = r;
648
+ a.type === void 0 && (a.type = "generative"), a.criteria === void 0 && (a.criteria = []), a.tool === void 0 && (a.tool = null), a.args === void 0 && (a.args = null);
639
649
  }
640
650
  }
641
651
  }
642
652
  ];
643
- function K(t, e, i) {
653
+ function K(t, e, r) {
644
654
  if (t === e)
645
655
  return;
646
- let r = t;
647
- for (const p of [...S].sort((d, l) => d.from - l.from))
648
- if (p.from === r && (p.apply(i), r = p.to, r === e)) {
649
- i.schema_version = e;
656
+ let a = t;
657
+ for (const p of [...S].sort((m, d) => m.from - d.from))
658
+ if (p.from === a && (p.apply(r), a = p.to, a === e)) {
659
+ r.schema_version = e;
650
660
  return;
651
661
  }
652
662
  throw new Error(
@@ -657,11 +667,11 @@ function K(t, e, i) {
657
667
  }
658
668
  export {
659
669
  x as VALID_OPS_BY_KIND,
660
- R as WRITE_CLASS_ACTIONS,
661
- z as assertValidDagJson,
670
+ z as WRITE_CLASS_ACTIONS,
671
+ P as assertValidDagJson,
662
672
  H as assertValidSnapshot,
663
673
  j as isValidOpForKind,
664
674
  K as migrateDag,
665
- N as validateDagJson,
666
- L as validateSnapshot
675
+ L as validateDagJson,
676
+ N as validateSnapshot
667
677
  };
package/lib/types.d.ts CHANGED
@@ -17,6 +17,7 @@ export type ShapeKind = CodeKind | ConfigKind | 'doc' | 'structured-output';
17
17
  export type KindFamily = 'code-config' | 'doc' | 'structured' | 'tool-call';
18
18
  export type MilestoneStatus = 'pending' | 'pending-surfaced' | 'in_progress' | 'complete' | 'failed' | 'skipped';
19
19
  export type DispatchUnitStatus = 'pending' | 'in_progress' | 'complete' | 'failed';
20
+ export type DispatchExecutionMode = 'model-dispatch' | 'guard-only';
20
21
  export type OperationStatus = 'pending' | 'in_progress' | 'complete' | 'failed' | 'skipped';
21
22
  export type GuardResult = 'pass' | 'fail';
22
23
  export type MilestoneGuardResult = 'pass' | 'fail' | 'pending';
@@ -38,6 +39,7 @@ export interface ShapeOpDag {
38
39
  to: string | null;
39
40
  position: number | null;
40
41
  required: boolean | null;
42
+ type_spec?: Record<string, string> | null;
41
43
  }
42
44
  export interface ShapeOpSnapshot extends ShapeOpDag {
43
45
  from: string | null;
@@ -323,9 +325,11 @@ export interface DispatchUnit {
323
325
  two_stage: boolean;
324
326
  provider: ProviderConfig | null;
325
327
  agent_name: string;
328
+ execution_mode: DispatchExecutionMode;
326
329
  mcp_servers: Record<string, unknown> | null;
327
330
  resolved_max_tokens: number | null;
328
331
  background: true;
332
+ systemPrompt: string | null;
329
333
  prompt: string | null;
330
334
  context_files: string[];
331
335
  si_bytes: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhd/dispatch-base-spec",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "dependencies": {},
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",