@adhd/dispatch-base-spec 0.1.4 → 0.1.6

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,18 @@
1
+ ## 0.1.6 (2026-10-06)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **dispatch-orchestrator:** dag.session_id producer stamps every DispatchUnit (fa9d3079/03145a46) ([e8271d77](https://github.com/PseudoSky/adhd/commit/e8271d77))
6
+ - **dispatch-orchestrator:** thread session_id through DispatchUnit + fire (fa9d3079) ([e3d3aa26](https://github.com/PseudoSky/adhd/commit/e3d3aa26))
7
+
8
+ ### 🩹 Fixes
9
+
10
+ - **dispatch-orchestrator,dispatch-cli:** make HITL reachable from dispatch ([57f53429](https://github.com/PseudoSky/adhd/commit/57f53429))
11
+
12
+ ### ❤️ Thank You
13
+
14
+ - pseudosky
15
+
1
16
  ## 0.1.4 (2026-09-26)
2
17
 
3
18
  ### 🚀 Features
@@ -46,6 +46,7 @@
46
46
  { "type": "object" }
47
47
  ]
48
48
  },
49
+ "session_id": { "type": ["string", "null"] },
49
50
  "optimization": {
50
51
  "type": "object",
51
52
  "required": ["sentinel_fanout", "b_per_tier", "context_window_per_tier"],
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=new Set([`create`,`modify-signature`,`modify-body`,`add-export`,`remove-export`,`rename`]),t={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`.split(`.`))};function n(e,n){let r=t[e];return r?r.has(n):!1}var r=new Set([`pending`,`pending-surfaced`,`in_progress`,`complete`,`failed`,`skipped`]),i=new Set([`pending`,`in_progress`,`complete`,`failed`,`skipped`]),a=new Set([`automated`,`tool-call`,`generative`]),o=new Set([`anthropic`,`openai`,`deepseek`,`google`,`local`,`claudecli`,`teammate`]),s=new Set([`function`,`interface`,`type`,`class`,`enum`,`const`,`script`,`config`,`env`,`schema`,`manifest`,`doc`,`structured-output`]);function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e){return typeof e==`string`}function u(e,t,n){return{path:e,message:t,value:n}}function d(e){let t=Object.keys(e),n=new Map,r=new Map;for(let e of t)n.set(e,0),r.set(e,[]);for(let i of t)for(let t of e[i]?.depends_on??[])e[t]&&(r.get(t)?.push(i),n.set(i,(n.get(i)??0)+1));let i=t.filter(e=>(n.get(e)??0)===0),a=new Set;for(;i.length>0;){let e=i.shift();if(e!==void 0){a.add(e);for(let t of r.get(e)??[]){let e=(n.get(t)??1)-1;n.set(t,e),e===0&&i.push(t)}}}return a.size===t.length?null:t.filter(e=>!a.has(e)).map(e=>({slug:e}))}function f(e,t){for(let n of e){if(!c(n))continue;let e=l(n.id)?n.id:`?`,r=n.provider;(!l(r)||!o.has(r))&&t.push(u(`dispatch_log[${e}].provider`,`invalid provider`,r));let i=n.turns;if(!Array.isArray(i)){t.push(u(`dispatch_log[${e}].turns`,`must be an array`,i));continue}for(let n=0;n<i.length;n++){let r=i[n],a=`dispatch_log[${e}].turns[${n}]`;if(!c(r)){t.push(u(a,`must be an object`,r));continue}(typeof r.turn!=`number`||!Number.isInteger(r.turn)||r.turn<1)&&t.push(u(`${a}.turn`,`must be a positive integer`,r.turn)),typeof r.input_tokens!=`number`&&t.push(u(`${a}.input_tokens`,`must be a number`,r.input_tokens)),typeof r.output_tokens!=`number`&&t.push(u(`${a}.output_tokens`,`must be a number`,r.output_tokens)),l(r.t)||t.push(u(`${a}.t`,`must be a string`,r.t));let o=r.model_calls;o!=null&&typeof o!=`number`&&t.push(u(`${a}.model_calls`,`must be a number or null if present`,o))}}}function p(e){let t=[];if(!c(e))return{valid:!1,errors:[u(``,`root must be an object`)]};for(let n of[`description`,`problem`,`approach`,`executor`]){let r=e[n];(!l(r)||r.trim()===``)&&t.push(u(n,`required string field missing/empty`,r))}typeof e.schema_version!=`number`&&t.push(u(`schema_version`,`must be a number`,e.schema_version));let r=e.plan_kind;r!==`brownfield`&&r!==`greenfield`&&t.push(u(`plan_kind`,`must be "brownfield" or "greenfield"`,r)),Array.isArray(e.phases)?e.phases.length===0&&t.push(u(`phases`,`must have at least one entry`)):t.push(u(`phases`,`must be an array`,e.phases));let i=e.terminal;!l(i)&&!Array.isArray(i)&&t.push(u(`terminal`,`must be a string or array`,i)),Array.isArray(e.dispatch_log)?f(e.dispatch_log,t):t.push(u(`dispatch_log`,`must be an array`,e.dispatch_log)),c(e.optimization)||t.push(u(`optimization`,`must be an object`,e.optimization)),c(e.providers)||t.push(u(`providers`,`must be an object`,e.providers)),c(e.effort_max_tokens)||t.push(u(`effort_max_tokens`,`must be an object`,e.effort_max_tokens));let o=e.milestones;if(!c(o))t.push(u(`milestones`,`must be an object`,o));else{let r=Object.keys(o);r.length===0&&t.push(u(`milestones`,`must have at least one entry`));let f=new Set(r);for(let e of r){let n=o[e];if(!c(n)){t.push(u(`milestones.${e}`,`must be an object`,n));continue}if((!l(n.description)||n.description.trim()===``)&&t.push(u(`milestones.${e}.description`,`required string`,n.description)),!Array.isArray(n.depends_on))t.push(u(`milestones.${e}.depends_on`,`must be an array`,n.depends_on));else for(let r of n.depends_on)l(r)?f.has(r)||t.push(u(`milestones.${e}.depends_on`,`unknown milestone "${r}"`)):t.push(u(`milestones.${e}.depends_on[]`,`must be a string`,r));let r=n.phase;(!l(r)||r.trim()===``)&&t.push(u(`milestones.${e}.phase`,`required string`,r)),(!l(n.authored_by)||n.authored_by.trim()===``)&&t.push(u(`milestones.${e}.authored_by`,`required string`,n.authored_by));let i=n.model;i!=null&&![`Haiku`,`Sonnet`,`Opus`].includes(i)&&t.push(u(`milestones.${e}.model`,`invalid model tier`,i));let a=n.effort;a!=null&&![`low`,`medium`,`high`,`xhigh`,`max`].includes(a)&&t.push(u(`milestones.${e}.effort`,`invalid effort tier`,a)),n.two_stage!==void 0&&typeof n.two_stage!=`boolean`&&t.push(u(`milestones.${e}.two_stage`,`must be a boolean`,n.two_stage)),Array.isArray(n.read_only)||t.push(u(`milestones.${e}.read_only`,`must be an array`,n.read_only))}let p=d(o);if(p)for(let{slug:e}of p)t.push(u(`milestones.${e}`,`dependency cycle detected`));if(l(i)&&!f.has(i))t.push(u(`terminal`,`unknown milestone "${i}"`));else if(Array.isArray(i))for(let e of i)f.has(e)||t.push(u(`terminal[]`,`unknown milestone "${e}"`));let m=e.operations,h=new Set;if(!Array.isArray(m)&&!c(m))t.push(u(`operations`,`must be an array or object`,m));else{let e=Array.isArray(m)?m:Object.values(m);for(let r of e){if(!c(r)){t.push(u(`operations[]`,`must be an object`,r));continue}let e=r.id;if(!l(e)){t.push(u(`operations[?]`,`missing/invalid id`,e));continue}let i=e;h.add(i);let o=r.milestone;l(o)?f.has(o)||t.push(u(`operations[${i}].milestone`,`unknown milestone "${o}"`)):t.push(u(`operations[${i}].milestone`,`required string`,o));let d=r.type;l(d)&&!a.has(d)&&t.push(u(`operations[${i}].type`,`invalid type`,d));let p=r.shape;if(c(p)){let e=p.kind;e!=null&&l(e)&&!s.has(e)&&t.push(u(`operations[${i}].shape.kind`,`invalid shape kind`,e));let r=p.ops;if(Array.isArray(r)&&l(e))for(let a=0;a<r.length;a++){let o=r[a];if(!c(o))continue;let s=o.op;l(s)&&!n(e,s)&&t.push(u(`operations[${i}].shape.ops[${a}]`,`op "${s}" not valid for kind "${e}"`))}}Array.isArray(r.depends_on)||t.push(u(`operations[${i}].depends_on`,`must be an array`,r.depends_on))}for(let n of e){if(!c(n))continue;let e=n.id;if(!l(e))continue;let r=n.depends_on;if(Array.isArray(r))for(let n of r)l(n)&&!h.has(n)&&t.push(u(`operations[${e}].depends_on`,`unknown operation "${n}"`))}}}return{valid:t.length===0,errors:t}}function m(e){let t=[];if(!c(e))return{valid:!1,errors:[u(``,`root must be an object`)]};for(let n of[`snapshot_at`,`description`])l(e[n])||t.push(u(n,`required string field missing`,e[n]));l(e.plan)||t.push(u(`plan`,`required string`,e.plan));let n=e.milestones;if(!c(n))t.push(u(`milestones`,`must be an object`,n));else{let a=Object.keys(n),o=new Set(a);for(let e of a){let i=n[e];if(!c(i)){t.push(u(`milestones.${e}`,`must be an object`,i));continue}let a=i.eligible,o=i.pending;a===!0&&o!=null&&t.push(u(`milestones.${e}`,`D-07 violation: eligible=true but pending not null`)),typeof a!=`boolean`&&t.push(u(`milestones.${e}.eligible`,`must be boolean`,a));let s=i.status;(!l(s)||!r.has(s))&&t.push(u(`milestones.${e}.status`,`invalid status`,s)),a===!0&&s===`complete`&&t.push(u(`milestones.${e}`,`D-07 violation: eligible=true but status is complete`));let d=i.wave;(typeof d!=`number`||!Number.isInteger(d)||d<0)&&t.push(u(`milestones.${e}.wave`,`must be non-negative integer`,d));let f=i.ki_estimate;f!=null&&typeof f!=`number`&&t.push(u(`milestones.${e}.ki_estimate`,`must be number|null`,f));for(let n of[`tokens_estimated`,`tokens_actual`]){let r=i[n];r!=null&&typeof r!=`number`&&t.push(u(`milestones.${e}.${n}`,`must be number|null`,r))}Array.isArray(i.artifacts)||t.push(u(`milestones.${e}.artifacts`,`must be an array`,i.artifacts)),typeof i.si_bytes!=`number`&&t.push(u(`milestones.${e}.si_bytes`,`must be a number`,i.si_bytes))}let s=e.operations;if(!Array.isArray(s))t.push(u(`operations`,`must be an array`,s));else for(let e of s){if(!c(e))continue;let n=l(e.id)?e.id:`?`,r=e.milestone;l(r)&&!o.has(r)&&t.push(u(`operations[${n}].milestone`,`unknown milestone "${r}"`));let a=e.status;(!l(a)||!i.has(a))&&t.push(u(`operations[${n}].status`,`invalid operation status`,a)),Array.isArray(e.dispatch_ids)||t.push(u(`operations[${n}].dispatch_ids`,`must be an array`,e.dispatch_ids)),typeof e.attempt_count!=`number`&&t.push(u(`operations[${n}].attempt_count`,`must be a number`,e.attempt_count)),Array.isArray(e.blast_radius)||t.push(u(`operations[${n}].blast_radius`,`must be an array`,e.blast_radius))}let d=e.open_questions;if(!Array.isArray(d))t.push(u(`open_questions`,`must be an array`,d));else for(let e of d){if(!c(e))continue;let n=e.blocking;(!l(n)||!o.has(n))&&t.push(u(`open_questions`,`unknown blocking milestone "${n}"`)),typeof e.surfaced!=`boolean`&&t.push(u(`open_questions[${e.id}]`,`surfaced must be boolean`,e.surfaced)),typeof e.answered!=`boolean`&&t.push(u(`open_questions[${e.id}]`,`answered must be boolean`,e.answered))}let f=e.dispatch_units;if(f!==void 0){if(!Array.isArray(f))t.push(u(`dispatch_units`,`must be an array if present`,f));else for(let e of f){if(!c(e))continue;let n=e.fits_context_window;typeof n!=`boolean`&&t.push(u(`dispatch_units[${e.id}]`,`fits_context_window must be boolean`,n));let r=e.milestones;if(Array.isArray(r))for(let n of r)l(n)&&!o.has(n)&&t.push(u(`dispatch_units[${e.id}].milestones`,`unknown milestone "${n}"`))}}c(e.pairwise_overlap)||t.push(u(`pairwise_overlap`,`must be an object`,e.pairwise_overlap))}return{valid:t.length===0,errors:t}}function h(e){let t=p(e);if(!t.valid)throw Error(`DagJson validation failed:\n${t.errors.map(e=>` ${e.path}: ${e.message}`).join(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=new Set([`create`,`modify-signature`,`modify-body`,`add-export`,`remove-export`,`rename`]),t={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`.split(`.`))};function n(e,n){let r=t[e];return r?r.has(n):!1}var r=new Set([`pending`,`pending-surfaced`,`in_progress`,`complete`,`failed`,`skipped`,`awaiting_input`]),i=new Set([`pending`,`in_progress`,`complete`,`failed`,`skipped`]),a=new Set([`automated`,`tool-call`,`generative`]),o=new Set([`anthropic`,`openai`,`deepseek`,`google`,`local`,`claudecli`,`teammate`]),s=new Set([`function`,`interface`,`type`,`class`,`enum`,`const`,`script`,`config`,`env`,`schema`,`manifest`,`doc`,`structured-output`]);function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function l(e){return typeof e==`string`}function u(e,t,n){return{path:e,message:t,value:n}}function d(e){let t=Object.keys(e),n=new Map,r=new Map;for(let e of t)n.set(e,0),r.set(e,[]);for(let i of t)for(let t of e[i]?.depends_on??[])e[t]&&(r.get(t)?.push(i),n.set(i,(n.get(i)??0)+1));let i=t.filter(e=>(n.get(e)??0)===0),a=new Set;for(;i.length>0;){let e=i.shift();if(e!==void 0){a.add(e);for(let t of r.get(e)??[]){let e=(n.get(t)??1)-1;n.set(t,e),e===0&&i.push(t)}}}return a.size===t.length?null:t.filter(e=>!a.has(e)).map(e=>({slug:e}))}function f(e,t){for(let n of e){if(!c(n))continue;let e=l(n.id)?n.id:`?`,r=n.provider;(!l(r)||!o.has(r))&&t.push(u(`dispatch_log[${e}].provider`,`invalid provider`,r));let i=n.turns;if(!Array.isArray(i)){t.push(u(`dispatch_log[${e}].turns`,`must be an array`,i));continue}for(let n=0;n<i.length;n++){let r=i[n],a=`dispatch_log[${e}].turns[${n}]`;if(!c(r)){t.push(u(a,`must be an object`,r));continue}(typeof r.turn!=`number`||!Number.isInteger(r.turn)||r.turn<1)&&t.push(u(`${a}.turn`,`must be a positive integer`,r.turn)),typeof r.input_tokens!=`number`&&t.push(u(`${a}.input_tokens`,`must be a number`,r.input_tokens)),typeof r.output_tokens!=`number`&&t.push(u(`${a}.output_tokens`,`must be a number`,r.output_tokens)),l(r.t)||t.push(u(`${a}.t`,`must be a string`,r.t));let o=r.model_calls;o!=null&&typeof o!=`number`&&t.push(u(`${a}.model_calls`,`must be a number or null if present`,o))}}}function p(e){let t=[];if(!c(e))return{valid:!1,errors:[u(``,`root must be an object`)]};for(let n of[`description`,`problem`,`approach`,`executor`]){let r=e[n];(!l(r)||r.trim()===``)&&t.push(u(n,`required string field missing/empty`,r))}typeof e.schema_version!=`number`&&t.push(u(`schema_version`,`must be a number`,e.schema_version));let r=e.plan_kind;r!==`brownfield`&&r!==`greenfield`&&t.push(u(`plan_kind`,`must be "brownfield" or "greenfield"`,r)),Array.isArray(e.phases)?e.phases.length===0&&t.push(u(`phases`,`must have at least one entry`)):t.push(u(`phases`,`must be an array`,e.phases));let i=e.terminal;!l(i)&&!Array.isArray(i)&&t.push(u(`terminal`,`must be a string or array`,i)),Array.isArray(e.dispatch_log)?f(e.dispatch_log,t):t.push(u(`dispatch_log`,`must be an array`,e.dispatch_log)),c(e.optimization)||t.push(u(`optimization`,`must be an object`,e.optimization)),c(e.providers)||t.push(u(`providers`,`must be an object`,e.providers)),c(e.effort_max_tokens)||t.push(u(`effort_max_tokens`,`must be an object`,e.effort_max_tokens));let o=e.milestones;if(!c(o))t.push(u(`milestones`,`must be an object`,o));else{let r=Object.keys(o);r.length===0&&t.push(u(`milestones`,`must have at least one entry`));let f=new Set(r);for(let e of r){let n=o[e];if(!c(n)){t.push(u(`milestones.${e}`,`must be an object`,n));continue}if((!l(n.description)||n.description.trim()===``)&&t.push(u(`milestones.${e}.description`,`required string`,n.description)),!Array.isArray(n.depends_on))t.push(u(`milestones.${e}.depends_on`,`must be an array`,n.depends_on));else for(let r of n.depends_on)l(r)?f.has(r)||t.push(u(`milestones.${e}.depends_on`,`unknown milestone "${r}"`)):t.push(u(`milestones.${e}.depends_on[]`,`must be a string`,r));let r=n.phase;(!l(r)||r.trim()===``)&&t.push(u(`milestones.${e}.phase`,`required string`,r)),(!l(n.authored_by)||n.authored_by.trim()===``)&&t.push(u(`milestones.${e}.authored_by`,`required string`,n.authored_by));let i=n.model;i!=null&&![`Haiku`,`Sonnet`,`Opus`].includes(i)&&t.push(u(`milestones.${e}.model`,`invalid model tier`,i));let a=n.effort;a!=null&&![`low`,`medium`,`high`,`xhigh`,`max`].includes(a)&&t.push(u(`milestones.${e}.effort`,`invalid effort tier`,a)),n.two_stage!==void 0&&typeof n.two_stage!=`boolean`&&t.push(u(`milestones.${e}.two_stage`,`must be a boolean`,n.two_stage)),Array.isArray(n.read_only)||t.push(u(`milestones.${e}.read_only`,`must be an array`,n.read_only))}let p=d(o);if(p)for(let{slug:e}of p)t.push(u(`milestones.${e}`,`dependency cycle detected`));if(l(i)&&!f.has(i))t.push(u(`terminal`,`unknown milestone "${i}"`));else if(Array.isArray(i))for(let e of i)f.has(e)||t.push(u(`terminal[]`,`unknown milestone "${e}"`));let m=e.operations,h=new Set;if(!Array.isArray(m)&&!c(m))t.push(u(`operations`,`must be an array or object`,m));else{let e=Array.isArray(m)?m:Object.values(m);for(let r of e){if(!c(r)){t.push(u(`operations[]`,`must be an object`,r));continue}let e=r.id;if(!l(e)){t.push(u(`operations[?]`,`missing/invalid id`,e));continue}let i=e;h.add(i);let o=r.milestone;l(o)?f.has(o)||t.push(u(`operations[${i}].milestone`,`unknown milestone "${o}"`)):t.push(u(`operations[${i}].milestone`,`required string`,o));let d=r.type;l(d)&&!a.has(d)&&t.push(u(`operations[${i}].type`,`invalid type`,d));let p=r.shape;if(c(p)){let e=p.kind;e!=null&&l(e)&&!s.has(e)&&t.push(u(`operations[${i}].shape.kind`,`invalid shape kind`,e));let r=p.ops;if(Array.isArray(r)&&l(e))for(let a=0;a<r.length;a++){let o=r[a];if(!c(o))continue;let s=o.op;l(s)&&!n(e,s)&&t.push(u(`operations[${i}].shape.ops[${a}]`,`op "${s}" not valid for kind "${e}"`))}}Array.isArray(r.depends_on)||t.push(u(`operations[${i}].depends_on`,`must be an array`,r.depends_on))}for(let n of e){if(!c(n))continue;let e=n.id;if(!l(e))continue;let r=n.depends_on;if(Array.isArray(r))for(let n of r)l(n)&&!h.has(n)&&t.push(u(`operations[${e}].depends_on`,`unknown operation "${n}"`))}}}return{valid:t.length===0,errors:t}}function m(e){let t=[];if(!c(e))return{valid:!1,errors:[u(``,`root must be an object`)]};for(let n of[`snapshot_at`,`description`])l(e[n])||t.push(u(n,`required string field missing`,e[n]));l(e.plan)||t.push(u(`plan`,`required string`,e.plan));let n=e.milestones;if(!c(n))t.push(u(`milestones`,`must be an object`,n));else{let a=Object.keys(n),o=new Set(a);for(let e of a){let i=n[e];if(!c(i)){t.push(u(`milestones.${e}`,`must be an object`,i));continue}let a=i.eligible,o=i.pending;a===!0&&o!=null&&t.push(u(`milestones.${e}`,`D-07 violation: eligible=true but pending not null`)),typeof a!=`boolean`&&t.push(u(`milestones.${e}.eligible`,`must be boolean`,a));let s=i.status;(!l(s)||!r.has(s))&&t.push(u(`milestones.${e}.status`,`invalid status`,s)),a===!0&&s===`complete`&&t.push(u(`milestones.${e}`,`D-07 violation: eligible=true but status is complete`));let d=i.wave;(typeof d!=`number`||!Number.isInteger(d)||d<0)&&t.push(u(`milestones.${e}.wave`,`must be non-negative integer`,d));let f=i.ki_estimate;f!=null&&typeof f!=`number`&&t.push(u(`milestones.${e}.ki_estimate`,`must be number|null`,f));for(let n of[`tokens_estimated`,`tokens_actual`]){let r=i[n];r!=null&&typeof r!=`number`&&t.push(u(`milestones.${e}.${n}`,`must be number|null`,r))}Array.isArray(i.artifacts)||t.push(u(`milestones.${e}.artifacts`,`must be an array`,i.artifacts)),typeof i.si_bytes!=`number`&&t.push(u(`milestones.${e}.si_bytes`,`must be a number`,i.si_bytes))}let s=e.operations;if(!Array.isArray(s))t.push(u(`operations`,`must be an array`,s));else for(let e of s){if(!c(e))continue;let n=l(e.id)?e.id:`?`,r=e.milestone;l(r)&&!o.has(r)&&t.push(u(`operations[${n}].milestone`,`unknown milestone "${r}"`));let a=e.status;(!l(a)||!i.has(a))&&t.push(u(`operations[${n}].status`,`invalid operation status`,a)),Array.isArray(e.dispatch_ids)||t.push(u(`operations[${n}].dispatch_ids`,`must be an array`,e.dispatch_ids)),typeof e.attempt_count!=`number`&&t.push(u(`operations[${n}].attempt_count`,`must be a number`,e.attempt_count)),Array.isArray(e.blast_radius)||t.push(u(`operations[${n}].blast_radius`,`must be an array`,e.blast_radius))}let d=e.open_questions;if(!Array.isArray(d))t.push(u(`open_questions`,`must be an array`,d));else for(let e of d){if(!c(e))continue;let n=e.blocking;(!l(n)||!o.has(n))&&t.push(u(`open_questions`,`unknown blocking milestone "${n}"`)),typeof e.surfaced!=`boolean`&&t.push(u(`open_questions[${e.id}]`,`surfaced must be boolean`,e.surfaced)),typeof e.answered!=`boolean`&&t.push(u(`open_questions[${e.id}]`,`answered must be boolean`,e.answered))}let f=e.dispatch_units;if(f!==void 0){if(!Array.isArray(f))t.push(u(`dispatch_units`,`must be an array if present`,f));else for(let e of f){if(!c(e))continue;let n=e.fits_context_window;typeof n!=`boolean`&&t.push(u(`dispatch_units[${e.id}]`,`fits_context_window must be boolean`,n));let r=e.milestones;if(Array.isArray(r))for(let n of r)l(n)&&!o.has(n)&&t.push(u(`dispatch_units[${e.id}].milestones`,`unknown milestone "${n}"`))}}c(e.pairwise_overlap)||t.push(u(`pairwise_overlap`,`must be an object`,e.pairwise_overlap))}return{valid:t.length===0,errors:t}}function h(e){let t=p(e);if(!t.valid)throw Error(`DagJson validation failed:\n${t.errors.map(e=>` ${e.path}: ${e.message}`).join(`
2
2
  `)}`)}function g(e){let t=m(e);if(!t.valid)throw Error(`Snapshot validation failed:\n${t.errors.map(e=>` ${e.path}: ${e.message}`).join(`
3
3
  `)}`)}var _=[{from:2,to:3,apply:e=>{!e.milestones&&e.nodes&&(e.milestones=e.nodes,delete e.nodes);let t=e.operations;t&&typeof t==`object`&&!Array.isArray(t)&&(e.operations=Object.values(t))}},{from:3,to:4,apply:e=>{(!e.providers||Object.keys(e.providers).length===0)&&(e.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}}}),(!e.effort_max_tokens||Object.keys(e.effort_max_tokens).length===0)&&(e.effort_max_tokens={low:1024,medium:4096,high:8192,xhigh:16384,max:32768}),e.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 t=[];Array.isArray(e.operations)?t=e.operations:e.operations&&typeof e.operations==`object`&&(t=Object.values(e.operations));for(let e of t)if(typeof e==`object`&&e){let t=e;t.type===void 0&&(t.type=`generative`),t.criteria===void 0&&(t.criteria=[]),t.tool===void 0&&(t.tool=null),t.args===void 0&&(t.args=null)}}}];function v(e,t,n){if(e===t)return;let r=e;for(let e of[..._].sort((e,t)=>e.from-t.from))if(e.from===r&&(e.apply(n),r=e.to,r===t)){n.schema_version=t;return}throw Error(`migrateDag: no path from v${e} to v${t}. Available: [${_.map(e=>`v${e.from}→v${e.to}`).join(`, `)}]`)}exports.VALID_OPS_BY_KIND=t,exports.WRITE_CLASS_ACTIONS=e,exports.assertValidDagJson=h,exports.assertValidSnapshot=g,exports.isValidOpForKind=n,exports.migrateDag=v,exports.validateDagJson=p,exports.validateSnapshot=m;
package/index.mjs CHANGED
@@ -109,7 +109,8 @@ var r = /* @__PURE__ */ new Set([
109
109
  "in_progress",
110
110
  "complete",
111
111
  "failed",
112
- "skipped"
112
+ "skipped",
113
+ "awaiting_input"
113
114
  ]), i = /* @__PURE__ */ new Set([
114
115
  "pending",
115
116
  "in_progress",
package/lib/types.d.ts CHANGED
@@ -15,7 +15,16 @@ export type CodeKind = 'function' | 'interface' | 'type' | 'class' | 'enum' | 'c
15
15
  export type ConfigKind = 'config' | 'env' | 'schema' | 'manifest';
16
16
  export type ShapeKind = CodeKind | ConfigKind | 'doc' | 'structured-output';
17
17
  export type KindFamily = 'code-config' | 'doc' | 'structured' | 'tool-call';
18
- export type MilestoneStatus = 'pending' | 'pending-surfaced' | 'in_progress' | 'complete' | 'failed' | 'skipped';
18
+ export type MilestoneStatus = 'pending' | 'pending-surfaced' | 'in_progress' | 'complete' | 'failed' | 'skipped'
19
+ /**
20
+ * The milestone's dispatch fired a sessioned agent-mcp task that suspended
21
+ * for human input (HITL: `request_human_input` -> `awaiting_input`). The work
22
+ * is PAUSED, not failed — an operator resumes it with `task_resume` (using the
23
+ * `resumeToken` recorded on the dispatch_log entry's `suspension`). Distinct
24
+ * from `failed` so `dispatch-cli status` can surface a resumable suspension
25
+ * instead of a terminal failure (FEAT; backlog 03145a46).
26
+ */
27
+ | 'awaiting_input';
19
28
  export type DispatchUnitStatus = 'pending' | 'in_progress' | 'complete' | 'failed';
20
29
  export type DispatchExecutionMode = 'model-dispatch' | 'guard-only';
21
30
  export type OperationStatus = 'pending' | 'in_progress' | 'complete' | 'failed' | 'skipped';
@@ -171,6 +180,21 @@ export interface DispatchLogEntry {
171
180
  turns: Turn[];
172
181
  results: DispatchResult[];
173
182
  notes: DispatchNote[];
183
+ /**
184
+ * Set when this entry's agent-mcp task suspended to `awaiting_input` (HITL —
185
+ * backlog 03145a46) instead of reaching a terminal status. Carries the
186
+ * suspended task's id and the opaque `resumeToken` `task_resume` requires, so
187
+ * `dispatch-cli status` (`statusCore`) can surface the suspension and an
188
+ * operator can release it. Absent for every non-suspended dispatch.
189
+ *
190
+ * NOTE — a suspended dispatch is NOT a failure: the milestone's derived status
191
+ * is `awaiting_input`, its guards are deliberately NOT run and no correction is
192
+ * injected (verification is meaningless until the task actually completes).
193
+ */
194
+ suspension?: {
195
+ taskId: string;
196
+ resumeToken: string;
197
+ } | null;
174
198
  }
175
199
  export interface OperationDag {
176
200
  id: string;
@@ -277,6 +301,20 @@ export interface DagJson {
277
301
  terminal: string | string[];
278
302
  assumed_baseline?: string[] | Record<string, unknown>;
279
303
  cross_plan_deps?: CrossPlanDep[];
304
+ /**
305
+ * Optional top-level agent-mcp session stamped onto every `DispatchUnit` the
306
+ * orchestrator fires (FEAT-DISPATCH-SESSION-001 producer, backlog fa9d3079 /
307
+ * 03145a46). When set, the run's units fire as SESSIONED tasks in that
308
+ * agent-mcp session instead of cold ephemeral ones — which is what makes
309
+ * HITL (`request_human_input` -> awaiting_input) reachable from dispatch and
310
+ * lets consecutive units share conversational context.
311
+ *
312
+ * The caller supplies an existing session id (created via agent-mcp's
313
+ * `agent` tool). A per-unit `DispatchUnit.session_id`, when already set by
314
+ * the optimizer, wins over this default. `null`/omitted preserves the
315
+ * pre-existing ephemeral behavior exactly.
316
+ */
317
+ session_id?: string | null;
280
318
  optimization: OptimizationConfig;
281
319
  providers: Record<string, ProviderConfig>;
282
320
  effort_max_tokens: Record<string, number>;
@@ -338,6 +376,14 @@ export interface DispatchUnit {
338
376
  sentinel_role: SentinelRole | null;
339
377
  dispatch_log_id: string | null;
340
378
  remote_task_id: string | null;
379
+ /**
380
+ * agent-mcp session this unit runs in (FEAT-DISPATCH-SESSION-001 / backlog
381
+ * fa9d3079). When set, `AgentMcpRunner.fire` forwards it to agent-mcp's
382
+ * `task` tool, so consecutive units sharing a session keep conversational
383
+ * context instead of each being a cold, session-less (ephemeral) task.
384
+ * `null`/omitted preserves the pre-existing ephemeral behavior exactly.
385
+ */
386
+ session_id?: string | null;
341
387
  result: string | null;
342
388
  status: DispatchUnitStatus;
343
389
  started_at: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhd/dispatch-base-spec",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "dependencies": {},
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",