yaml-flow 8.1.1 → 8.2.0
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/browser/asset-integrity.json +3 -3
- package/browser/board-livecards-localstorage.js +5 -5
- package/cli/browser-api/board-live-cards-browser-adapter.d.ts +1 -1
- package/cli/node/board-live-cards-cli.js +6 -6
- package/cli/node/card-store-cli.js +4 -4
- package/cli/node/fs-board-adapter.d.ts +2 -2
- package/cli/node/fs-board-adapter.js +7 -7
- package/cli/node/step-machine-cli.js +3 -3
- package/cli/{types-D2XnLbBj.d.ts → types-CSiGbY__.d.ts} +1 -1
- package/examples/board/demo-chat-copilot.flow.json +38 -0
- package/examples/board/{demo-chat-handler.js → demo-chat-copilot.js} +55 -39
- package/examples/board/demo-chat-echo.flow.json +38 -0
- package/examples/board/demo-chat-echo.js +92 -0
- package/examples/board/demo-server-config.copilot-chat.json +10 -0
- package/examples/board/demo-server-config.json +2 -2
- package/examples/board/demo-server.js +57 -8
- package/examples/board/demo-shell-with-server.html +2 -2
- package/examples/board/test/demo-http-test.js +45 -0
- package/examples/board-local/demo-shell-localstorage.html +3 -3
- package/lib/{artifacts-store-lib-public-BWC3YuLa.d.ts → artifacts-store-lib-public-BPW_C15z.d.ts} +1 -1
- package/lib/{artifacts-store-lib-public-DBICnGL6.d.cts → artifacts-store-lib-public-DfU9t5-S.d.cts} +1 -1
- package/lib/artifacts-store-public.d.cts +2 -2
- package/lib/artifacts-store-public.d.ts +2 -2
- package/lib/board-live-cards-node.cjs +7 -7
- package/lib/board-live-cards-node.d.cts +5 -5
- package/lib/board-live-cards-node.d.ts +5 -5
- package/lib/board-live-cards-node.js +7 -7
- package/lib/{board-live-cards-public-dJAl5IL-.d.ts → board-live-cards-public-B8b_0k_j.d.ts} +1 -1
- package/lib/{board-live-cards-public-BF9FP0mL.d.cts → board-live-cards-public-W2zK59m0.d.cts} +1 -1
- package/lib/board-live-cards-public.cjs +2 -2
- package/lib/board-live-cards-public.d.cts +1 -1
- package/lib/board-live-cards-public.d.ts +1 -1
- package/lib/board-live-cards-public.js +2 -2
- package/lib/board-live-cards-server-runtime.cjs +5 -5
- package/lib/board-live-cards-server-runtime.d.cts +2 -2
- package/lib/board-live-cards-server-runtime.d.ts +2 -2
- package/lib/board-live-cards-server-runtime.js +5 -5
- package/lib/card-store-public.d.cts +1 -1
- package/lib/card-store-public.d.ts +1 -1
- package/lib/server-runtime/index.cjs +5 -5
- package/lib/server-runtime/index.d.cts +3 -3
- package/lib/server-runtime/index.d.ts +3 -3
- package/lib/server-runtime/index.js +5 -5
- package/lib/step-machine-public/index.cjs +3 -3
- package/lib/step-machine-public/index.d.cts +26 -9
- package/lib/step-machine-public/index.d.ts +26 -9
- package/lib/step-machine-public/index.js +3 -3
- package/lib/{types-D48hpnTR.d.ts → types-Bm7IFD7r.d.ts} +22 -2
- package/lib/{types-CXBzvC0s.d.cts → types-seTI8zta.d.cts} +22 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import*as m from'fs';import {existsSync}from'fs';import*as v from'path';import {dirname,resolve}from'path';import'ajv-formats';import {createRequire}from'module';import {fileURLToPath}from'url';import {spawn,execFile,execFileSync}from'child_process';import*as Rt from'os';import'net';import {randomUUID}from'crypto';import'proper-lockfile';function K(e,t,n,r){let s=e.steps[n];if(!s)throw new Error(`Step "${n}" not found in flow configuration`);if(r.result==="failure"&&s.retry){let i=t.retryCounts[n]??0;if(i<s.retry.max_attempts)return {newState:{...t,retryCounts:{...t.retryCounts,[n]:i+1},updatedAt:Date.now()},nextStep:n,isTerminal:false,isCircuitBroken:false,shouldRetry:true}}let o=s.failure_transitions?.[r.result]??s.transitions[r.result];if(!o)throw new Error(`No transition defined for result "${r.result}" in step "${n}"`);let a=!!e.terminal_states[o];return {newState:{...t,currentStep:o,stepHistory:[...t.stepHistory,n],retryCounts:{...t.retryCounts,[n]:0},updatedAt:Date.now()},nextStep:o,isTerminal:a,isCircuitBroken:false,shouldRetry:false}}function U(e,t,n){let r=e.steps[n];if(!r?.circuit_breaker)return {broken:false,newState:{...t,iterationCounts:{...t.iterationCounts,[n]:(t.iterationCounts[n]??0)+1},updatedAt:Date.now()}};let s=t.iterationCounts[n]??0;return s>=r.circuit_breaker.max_iterations?{broken:true,redirectStep:r.circuit_breaker.on_open,newState:{...t,currentStep:r.circuit_breaker.on_open,updatedAt:Date.now()}}:{broken:false,newState:{...t,iterationCounts:{...t.iterationCounts,[n]:s+1},updatedAt:Date.now()}}}function q(e,t,n){let r=e.steps[t];if(!r)throw new Error(`Step "${t}" not found`);if(r.expects_data){let s={};for(let o of r.expects_data)s[o]=n[o];return s}return {...n}}function z(e,t){if(e===false||e===void 0)return {};if(typeof e=="string")return {[e]:t[e]};if(Array.isArray(e)){let n={};for(let r of e)n[r]=t[r];return n}return {}}function V(e,t){let n=Date.now();return {runId:t,flowId:e.id??"unnamed",currentStep:e.settings.start_step,status:"running",stepHistory:[],iterationCounts:{},retryCounts:{},startedAt:n,updatedAt:n}}var k=class{runs=new Map;data=new Map;async saveRunState(t,n){this.runs.set(t,{...n});}async loadRunState(t){let n=this.runs.get(t);return n?{...n}:null}async deleteRunState(t){this.runs.delete(t),this.data.delete(t);}async setData(t,n,r){this.data.has(t)||this.data.set(t,{});let s=this.data.get(t);s[n]=r;}async getData(t,n){return this.data.get(t)?.[n]}async getAllData(t){return {...this.data.get(t)??{}}}async clearData(t){this.data.delete(t);}async listRuns(){return Array.from(this.runs.keys())}clear(){this.runs.clear(),this.data.clear();}};function Pt(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return (e==="x"?t:t&3|8).toString(16)})}var O=class{flow;handlers;store;components;options;listeners=new Map;aborted=false;constructor(t,n,r={}){this.flow=t,this.handlers=new Map(Object.entries(n)),this.store=r.store??new k,this.components=r.components??{},this.options=r,r.signal&&r.signal.addEventListener("abort",()=>{this.aborted=true;}),this.validateFlow();}validateFlow(){let{settings:t,steps:n,terminal_states:r}=this.flow;if(!t?.start_step)throw new Error("Flow must have settings.start_step defined");if(!n||Object.keys(n).length===0)throw new Error("Flow must have at least one step defined");if(!r||Object.keys(r).length===0)throw new Error("Flow must have at least one terminal_state defined");if(!n[t.start_step]&&!r[t.start_step])throw new Error(`Start step "${t.start_step}" not found`);for(let[s,o]of Object.entries(n)){for(let[a,i]of Object.entries(o.transitions))if(!n[i]&&!r[i])throw new Error(`Step "${s}" transition "${a}" points to unknown step "${i}"`);if(o.failure_transitions){for(let[a,i]of Object.entries(o.failure_transitions))if(!n[i]&&!r[i])throw new Error(`Step "${s}" failure_transition "${a}" points to unknown step "${i}"`)}}}on(t,n){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(n);}off(t,n){this.listeners.get(t)?.delete(n);}emit(t){let n=this.listeners.get(t.type);if(n)for(let r of n)try{r(t);}catch{}}sleep(t){return new Promise(n=>setTimeout(n,t))}async run(t){let n=Pt(),r=V(this.flow,n);if(await this.store.saveRunState(n,r),t)for(let[s,o]of Object.entries(t))await this.store.setData(n,s,o);this.emit({type:"flow:start",runId:n,timestamp:r.startedAt,data:{initialData:t??{}}});try{return await this.executeLoop(n,r)}catch(s){let o=s instanceof Error?s:new Error(String(s));return this.emit({type:"flow:error",runId:n,timestamp:Date.now(),data:{error:o.message}}),this.options.onError?.(o),r={...r,status:"failed",updatedAt:Date.now()},await this.store.saveRunState(n,r),{runId:n,status:"failed",data:await this.store.getAllData(n),finalStep:r.currentStep,stepHistory:r.stepHistory,durationMs:Date.now()-r.startedAt,error:o}}}async resume(t){let n=await this.store.loadRunState(t);if(!n)throw new Error(`No run found with ID: ${t}`);if(n.status==="completed"||n.status==="failed")throw new Error(`Cannot resume a ${n.status} run`);let r={...n,status:"running",pausedAt:void 0,updatedAt:Date.now()};return await this.store.saveRunState(t,r),this.emit({type:"flow:resumed",runId:t,timestamp:Date.now(),data:{currentStep:r.currentStep}}),this.executeLoop(t,r)}async pause(t){let n=await this.store.loadRunState(t);if(!n)throw new Error(`No run found with ID: ${t}`);let r={...n,status:"paused",pausedAt:Date.now(),updatedAt:Date.now()};await this.store.saveRunState(t,r),this.emit({type:"flow:paused",runId:t,timestamp:Date.now(),data:{currentStep:r.currentStep}});}async executeLoop(t,n){let r=this.flow.settings.max_total_steps??100,s=this.flow.settings.timeout_ms,o=n,a=0;for(;a<r;){if(this.aborted)return o={...o,status:"cancelled",updatedAt:Date.now()},await this.store.saveRunState(t,o),{runId:t,status:"cancelled",data:await this.store.getAllData(t),finalStep:o.currentStep,stepHistory:o.stepHistory,durationMs:Date.now()-o.startedAt};if(s&&Date.now()-o.startedAt>s)return o={...o,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,o),{runId:t,status:"timeout",intent:"timeout",data:await this.store.getAllData(t),finalStep:o.currentStep,stepHistory:o.stepHistory,durationMs:Date.now()-o.startedAt};let i=o.currentStep,u=this.flow.terminal_states[i];if(u){o={...o,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,o);let p=await this.store.getAllData(t),g={runId:t,status:"completed",intent:u.return_intent,data:z(u.return_artifacts,p),finalStep:i,stepHistory:o.stepHistory,durationMs:Date.now()-o.startedAt};return this.emit({type:"flow:complete",runId:t,timestamp:Date.now(),data:{...g}}),this.options.onComplete?.(g),g}let c=U(this.flow,o,i);if(c.broken){o=c.newState,await this.store.saveRunState(t,o),a++;continue}o=c.newState;let d=await this.store.getAllData(t),l=q(this.flow,i,d),f={runId:t,stepName:i,components:this.components,store:this.store,signal:this.options.signal,emit:(p,g)=>{this.emit({type:"step:complete",runId:t,timestamp:Date.now(),data:{event:p,payload:g}});}};this.emit({type:"step:start",runId:t,timestamp:Date.now(),data:{step:i,input:l}});let h;try{let p=this.handlers.get(i);if(!p)throw new Error(`No handler registered for step "${i}"`);h=await p(l,f);}catch(p){let g=p instanceof Error?p:new Error(String(p));this.emit({type:"step:error",runId:t,timestamp:Date.now(),data:{step:i,error:g.message}}),h={result:"failure",data:{error:g.message}};}if(h.data)for(let[p,g]of Object.entries(h.data))await this.store.setData(t,p,g);this.emit({type:"step:complete",runId:t,timestamp:Date.now(),data:{step:i,result:h.result}}),this.options.onStep?.(i,h);let w=K(this.flow,o,i,h);if(o=w.newState,w.shouldRetry){await this.store.saveRunState(t,o);let p=this.flow.steps[i];if(p.retry?.delay_ms){let g=o.retryCounts[i]??0,x=p.retry.backoff_multiplier?p.retry.delay_ms*Math.pow(p.retry.backoff_multiplier,g-1):p.retry.delay_ms;await this.sleep(x);}a++;continue}await this.store.saveRunState(t,o),this.emit({type:"transition",runId:t,timestamp:Date.now(),data:{from:i,to:o.currentStep,result:h.result}}),this.options.onTransition?.(i,o.currentStep),a++;}return o={...o,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,o),{runId:t,status:"max_iterations",intent:"max_iterations",data:await this.store.getAllData(t),finalStep:o.currentStep,stepHistory:o.stepHistory,durationMs:Date.now()-o.startedAt}}};function H(e,t,n){return new O(e,t,n)}async function W(e){return (await import('yaml')).parse(e)}async function Mt(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to load flow from ${e}: ${t.statusText}`);let n=t.headers.get("content-type")??"",r=await t.text();return n.includes("json")||e.endsWith(".json")?JSON.parse(r):W(r)}async function Ot(e){let n=await(await import('fs/promises')).readFile(e,"utf-8");return e.endsWith(".json")?JSON.parse(n):W(n)}function nt(e){let t=[];if(!e||typeof e!="object")return ["Flow must be an object"];let n=e;if(!n.settings||typeof n.settings!="object"?t.push('Flow must have a "settings" object'):typeof n.settings.start_step!="string"&&t.push("settings.start_step must be a string"),!n.steps||typeof n.steps!="object")t.push('Flow must have a "steps" object');else {let r=n.steps;for(let[s,o]of Object.entries(r)){if(!o||typeof o!="object"){t.push(`Step "${s}" must be an object`);continue}let a=o;(!a.transitions||typeof a.transitions!="object")&&t.push(`Step "${s}" must have a "transitions" object`),a.failure_transitions!==void 0&&typeof a.failure_transitions!="object"&&t.push(`Step "${s}" failure_transitions must be an object when provided`);}}if(!n.terminal_states||typeof n.terminal_states!="object")t.push('Flow must have a "terminal_states" object');else {let r=n.terminal_states;for(let[s,o]of Object.entries(r)){if(!o||typeof o!="object"){t.push(`Terminal state "${s}" must be an object`);continue}typeof o.return_intent!="string"&&t.push(`Terminal state "${s}" must have a "return_intent" string`);}}return t}async function I(e){let t;typeof e=="string"?e.startsWith("http://")||e.startsWith("https://")?t=await Mt(e):e.includes("{")?t=JSON.parse(e):t=await Ot(e):t=e;let n=nt(t);if(n.length>0)throw new Error(`Invalid step flow configuration:
|
|
1
|
+
import*as m from'fs';import {existsSync}from'fs';import*as k from'path';import {dirname,resolve}from'path';import'ajv-formats';import {createRequire}from'module';import {fileURLToPath}from'url';import {spawn,execFile,execFileSync}from'child_process';import*as xt from'os';import'net';import {randomUUID}from'crypto';import'proper-lockfile';function U(e,t,n,r){let o=e.steps[n];if(!o)throw new Error(`Step "${n}" not found in flow configuration`);if(r.result==="failure"&&o.retry){let i=t.retryCounts[n]??0;if(i<o.retry.max_attempts)return {newState:{...t,retryCounts:{...t.retryCounts,[n]:i+1},updatedAt:Date.now()},nextStep:n,isTerminal:false,isCircuitBroken:false,shouldRetry:true}}let s=o.failure_transitions?.[r.result]??o.transitions[r.result];if(!s)throw new Error(`No transition defined for result "${r.result}" in step "${n}"`);let a=!!e.terminal_states[s];return {newState:{...t,currentStep:s,stepHistory:[...t.stepHistory,n],retryCounts:{...t.retryCounts,[n]:0},updatedAt:Date.now()},nextStep:s,isTerminal:a,isCircuitBroken:false,shouldRetry:false}}function q(e,t,n){let r=e.steps[n];if(!r?.circuit_breaker)return {broken:false,newState:{...t,iterationCounts:{...t.iterationCounts,[n]:(t.iterationCounts[n]??0)+1},updatedAt:Date.now()}};let o=t.iterationCounts[n]??0;return o>=r.circuit_breaker.max_iterations?{broken:true,redirectStep:r.circuit_breaker.on_open,newState:{...t,currentStep:r.circuit_breaker.on_open,updatedAt:Date.now()}}:{broken:false,newState:{...t,iterationCounts:{...t.iterationCounts,[n]:o+1},updatedAt:Date.now()}}}function z(e,t,n){let r=e.steps[t];if(!r)throw new Error(`Step "${t}" not found`);if(r.expects_data){let o={};for(let s of r.expects_data)o[s]=n[s];return o}return {...n}}function V(e,t){if(e===false||e===void 0)return {};if(typeof e=="string")return {[e]:t[e]};if(Array.isArray(e)){let n={};for(let r of e)n[r]=t[r];return n}return {}}function W(e,t){let n=Date.now();return {runId:t,flowId:e.id??"unnamed",currentStep:e.settings.start_step,status:"running",stepHistory:[],iterationCounts:{},retryCounts:{},startedAt:n,updatedAt:n}}var v=class{runs=new Map;data=new Map;async saveRunState(t,n){this.runs.set(t,{...n});}async loadRunState(t){let n=this.runs.get(t);return n?{...n}:null}async deleteRunState(t){this.runs.delete(t),this.data.delete(t);}async setData(t,n,r){this.data.has(t)||this.data.set(t,{});let o=this.data.get(t);o[n]=r;}async getData(t,n){return this.data.get(t)?.[n]}async getAllData(t){return {...this.data.get(t)??{}}}async clearData(t){this.data.delete(t);}async listRuns(){return Array.from(this.runs.keys())}clear(){this.runs.clear(),this.data.clear();}};function Mt(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return (e==="x"?t:t&3|8).toString(16)})}var I=class{flow;handlers;store;components;options;listeners=new Map;aborted=false;constructor(t,n,r={}){this.flow=t,this.handlers=new Map(Object.entries(n)),this.store=r.store??new v,this.components=r.components??{},this.options=r,r.signal&&r.signal.addEventListener("abort",()=>{this.aborted=true;}),this.validateFlow();}validateFlow(){let{settings:t,steps:n,terminal_states:r}=this.flow;if(!t?.start_step)throw new Error("Flow must have settings.start_step defined");if(!n||Object.keys(n).length===0)throw new Error("Flow must have at least one step defined");if(!r||Object.keys(r).length===0)throw new Error("Flow must have at least one terminal_state defined");if(!n[t.start_step]&&!r[t.start_step])throw new Error(`Start step "${t.start_step}" not found`);for(let[o,s]of Object.entries(n)){for(let[a,i]of Object.entries(s.transitions))if(!n[i]&&!r[i])throw new Error(`Step "${o}" transition "${a}" points to unknown step "${i}"`);if(s.failure_transitions){for(let[a,i]of Object.entries(s.failure_transitions))if(!n[i]&&!r[i])throw new Error(`Step "${o}" failure_transition "${a}" points to unknown step "${i}"`)}}}on(t,n){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(n);}off(t,n){this.listeners.get(t)?.delete(n);}emit(t){let n=this.listeners.get(t.type);if(n)for(let r of n)try{r(t);}catch{}}sleep(t){return new Promise(n=>setTimeout(n,t))}async run(t){let n=Mt(),r=W(this.flow,n);if(await this.store.saveRunState(n,r),t)for(let[o,s]of Object.entries(t))await this.store.setData(n,o,s);this.emit({type:"flow:start",runId:n,timestamp:r.startedAt,data:{initialData:t??{}}});try{return await this.executeLoop(n,r)}catch(o){let s=o instanceof Error?o:new Error(String(o));return this.emit({type:"flow:error",runId:n,timestamp:Date.now(),data:{error:s.message}}),this.options.onError?.(s),r={...r,status:"failed",updatedAt:Date.now()},await this.store.saveRunState(n,r),{runId:n,status:"failed",data:await this.store.getAllData(n),finalStep:r.currentStep,stepHistory:r.stepHistory,durationMs:Date.now()-r.startedAt,error:s}}}async resume(t){let n=await this.store.loadRunState(t);if(!n)throw new Error(`No run found with ID: ${t}`);if(n.status==="completed"||n.status==="failed")throw new Error(`Cannot resume a ${n.status} run`);let r={...n,status:"running",pausedAt:void 0,updatedAt:Date.now()};return await this.store.saveRunState(t,r),this.emit({type:"flow:resumed",runId:t,timestamp:Date.now(),data:{currentStep:r.currentStep}}),this.executeLoop(t,r)}async pause(t){let n=await this.store.loadRunState(t);if(!n)throw new Error(`No run found with ID: ${t}`);let r={...n,status:"paused",pausedAt:Date.now(),updatedAt:Date.now()};await this.store.saveRunState(t,r),this.emit({type:"flow:paused",runId:t,timestamp:Date.now(),data:{currentStep:r.currentStep}});}async executeLoop(t,n){let r=this.flow.settings.max_total_steps??100,o=this.flow.settings.timeout_ms,s=n,a=0;for(;a<r;){if(this.aborted)return s={...s,status:"cancelled",updatedAt:Date.now()},await this.store.saveRunState(t,s),{runId:t,status:"cancelled",data:await this.store.getAllData(t),finalStep:s.currentStep,stepHistory:s.stepHistory,durationMs:Date.now()-s.startedAt};if(o&&Date.now()-s.startedAt>o)return s={...s,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,s),{runId:t,status:"timeout",intent:"timeout",data:await this.store.getAllData(t),finalStep:s.currentStep,stepHistory:s.stepHistory,durationMs:Date.now()-s.startedAt};let i=s.currentStep,u=this.flow.terminal_states[i];if(u){s={...s,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,s);let p=await this.store.getAllData(t),g={runId:t,status:"completed",intent:u.return_intent,data:V(u.return_artifacts,p),finalStep:i,stepHistory:s.stepHistory,durationMs:Date.now()-s.startedAt};return this.emit({type:"flow:complete",runId:t,timestamp:Date.now(),data:{...g}}),this.options.onComplete?.(g),g}let c=q(this.flow,s,i);if(c.broken){s=c.newState,await this.store.saveRunState(t,s),a++;continue}s=c.newState;let d=await this.store.getAllData(t),l=z(this.flow,i,d),f={runId:t,stepName:i,components:this.components,store:this.store,signal:this.options.signal,emit:(p,g)=>{this.emit({type:"step:complete",runId:t,timestamp:Date.now(),data:{event:p,payload:g}});}};this.emit({type:"step:start",runId:t,timestamp:Date.now(),data:{step:i,input:l}});let h;try{let p=this.handlers.get(i);if(!p)throw new Error(`No handler registered for step "${i}"`);h=await p(l,f);}catch(p){let g=p instanceof Error?p:new Error(String(p));this.emit({type:"step:error",runId:t,timestamp:Date.now(),data:{step:i,error:g.message}}),h={result:"failure",data:{error:g.message}};}if(h.data)for(let[p,g]of Object.entries(h.data))await this.store.setData(t,p,g);this.emit({type:"step:complete",runId:t,timestamp:Date.now(),data:{step:i,result:h.result}}),this.options.onStep?.(i,h);let w=U(this.flow,s,i,h);if(s=w.newState,w.shouldRetry){await this.store.saveRunState(t,s);let p=this.flow.steps[i];if(p.retry?.delay_ms){let g=s.retryCounts[i]??0,R=p.retry.backoff_multiplier?p.retry.delay_ms*Math.pow(p.retry.backoff_multiplier,g-1):p.retry.delay_ms;await this.sleep(R);}a++;continue}await this.store.saveRunState(t,s),this.emit({type:"transition",runId:t,timestamp:Date.now(),data:{from:i,to:s.currentStep,result:h.result}}),this.options.onTransition?.(i,s.currentStep),a++;}return s={...s,status:"completed",updatedAt:Date.now()},await this.store.saveRunState(t,s),{runId:t,status:"max_iterations",intent:"max_iterations",data:await this.store.getAllData(t),finalStep:s.currentStep,stepHistory:s.stepHistory,durationMs:Date.now()-s.startedAt}}};function T(e,t,n){return new I(e,t,n)}async function G(e){return (await import('yaml')).parse(e)}async function Pt(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to load flow from ${e}: ${t.statusText}`);let n=t.headers.get("content-type")??"",r=await t.text();return n.includes("json")||e.endsWith(".json")?JSON.parse(r):G(r)}async function Ot(e){let n=await(await import('fs/promises')).readFile(e,"utf-8");return e.endsWith(".json")?JSON.parse(n):G(n)}function nt(e){let t=[];if(!e||typeof e!="object")return ["Flow must be an object"];let n=e;if(!n.settings||typeof n.settings!="object"?t.push('Flow must have a "settings" object'):typeof n.settings.start_step!="string"&&t.push("settings.start_step must be a string"),!n.steps||typeof n.steps!="object")t.push('Flow must have a "steps" object');else {let r=n.steps;for(let[o,s]of Object.entries(r)){if(!s||typeof s!="object"){t.push(`Step "${o}" must be an object`);continue}let a=s;(!a.transitions||typeof a.transitions!="object")&&t.push(`Step "${o}" must have a "transitions" object`),a.failure_transitions!==void 0&&typeof a.failure_transitions!="object"&&t.push(`Step "${o}" failure_transitions must be an object when provided`);}}if(!n.terminal_states||typeof n.terminal_states!="object")t.push('Flow must have a "terminal_states" object');else {let r=n.terminal_states;for(let[o,s]of Object.entries(r)){if(!s||typeof s!="object"){t.push(`Terminal state "${o}" must be an object`);continue}typeof s.return_intent!="string"&&t.push(`Terminal state "${o}" must have a "return_intent" string`);}}return t}async function H(e){let t;typeof e=="string"?e.startsWith("http://")||e.startsWith("https://")?t=await Pt(e):e.includes("{")?t=JSON.parse(e):t=await Ot(e):t=e;let n=nt(t);if(n.length>0)throw new Error(`Invalid step flow configuration:
|
|
2
2
|
- ${n.join(`
|
|
3
|
-
- `)}`);return t}function G(e){return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function rt(e){return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var j=class{constructor(t){this.kv=t;}kv;stateKey(t){return `state_${G(t)}`}dataPrefix(t){return `data_${G(t)}_`}dataKey(t,n){return `${this.dataPrefix(t)}${G(n)}`}async saveRunState(t,n){this.kv.write(this.stateKey(t),n);}async loadRunState(t){let n=this.kv.read(this.stateKey(t));return n!=null&&typeof n=="object"?n:null}async deleteRunState(t){this.kv.delete(this.stateKey(t));for(let n of this.kv.listKeys(this.dataPrefix(t)))this.kv.delete(n);}async setData(t,n,r){this.kv.write(this.dataKey(t,n),r);}async getData(t,n){return this.kv.read(this.dataKey(t,n))}async getAllData(t){let n=this.dataPrefix(t),r={};for(let s of this.kv.listKeys(n))r[rt(s.slice(n.length))]=this.kv.read(s);return r}async clearData(t){for(let n of this.kv.listKeys(this.dataPrefix(t)))this.kv.delete(n);}async listRuns(){return this.kv.listKeys("state_").map(t=>rt(t.slice(6)))}};var ot=dirname(fileURLToPath(import.meta.url)),Dt=createRequire(import.meta.url);function Bt(){let e=resolve(ot,"./jsonata-sync.cjs");return existsSync(e)?e:resolve(ot,"../card-compute/jsonata-sync.cjs")}var $=Dt(Bt());function it(e,t){if(!e||typeof e!="object")throw new Error(`[step-machine-public] Step "${t}" returned a non-object result.`);let n=e,r=n.result??n.status;if(typeof r=="string"&&r.trim().length>0){let s=n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?{...n.data}:{},o=typeof n.error=="string"?n.error:void 0;return o&&!("error"in s)&&(s.error=o),{result:r,data:s,...o?{error:o}:{}}}return {result:"success",data:{...n}}}function at(e,t){if(!t||t.length===0)return e;let n={};for(let r of t)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function X(e,t){return async(n,r)=>{let s=await e(n,r),o=it(s,r?.stepName??"unknown");return {result:o.result,data:at(o.data,t),...o.error?{error:o.error}:{}}}}function ct(e,t,n){if(!t||t.length===0)return null;for(let r of t)try{if(!$(r).evaluate(e))return {result:"failure",data:{error:`[${n}] input validation failed: ${r}`}}}catch(s){let o=s instanceof Error?s.message:String(s);return {result:"failure",data:{error:`[${n}] input validation error on "${r}": ${o}`}}}return null}function Y(e,t,n){return !t||t.length===0?e:async(r,s)=>{let o=ct(r,t,n);return o||e(r,s)}}var lt=dirname(fileURLToPath(import.meta.url)),qt=createRequire(import.meta.url);function zt(){let e=resolve(lt,"./jsonata-sync.cjs");return existsSync(e)?e:resolve(lt,"../../card-compute/jsonata-sync.cjs")}var R=qt(zt());function pt(e,t,n){if(!e||typeof e!="object")return {};let r={};if(Array.isArray(e.cmdTemplate)){let s=[];for(let o of e.cmdTemplate)try{s.push(String(R(o).evaluate(t)));}catch(a){let i=a instanceof Error?a.message:String(a);throw new Error(`[${n}] argsMassaging.cmdTemplate failed on "${o}": ${i}`)}r.cmdArgs=s;}if(typeof e.stdinTemplate=="string")try{r.stdin=R(e.stdinTemplate).evaluate(t);}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[${n}] argsMassaging.stdinTemplate failed: ${o}`)}if(typeof e.urlTemplate=="string")try{r.url=String(R(e.urlTemplate).evaluate(t));}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[${n}] argsMassaging.urlTemplate failed: ${o}`)}if(typeof e.headerTemplate=="string")try{let s=R(e.headerTemplate).evaluate(t);if(typeof s!="object"||s===null)throw new Error(`headerTemplate must produce an object, got: ${JSON.stringify(s)}`);r.headers=s;}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[${n}] argsMassaging.headerTemplate failed: ${o}`)}if(typeof e.bodyTemplate=="string")try{r.body=R(e.bodyTemplate).evaluate(t);}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[${n}] argsMassaging.bodyTemplate failed: ${o}`)}return r}function dt(e,t,n){if(!e||typeof e!="object")return t;let r={output:t},s=t.result,o=t.data,a=t.error;if(typeof e.resultExpr=="string")try{let i=R(e.resultExpr).evaluate(r);if(typeof i!="string"||!i.trim())throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(i)})`);s=i;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.resultExpr failed: ${u}`)}if(typeof e.dataTemplate=="string")try{let i=R(e.dataTemplate).evaluate(r);if(!i||typeof i!="object"||Array.isArray(i))throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(i)})`);o=i;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.dataTemplate failed: ${u}`)}if(typeof e.errorExpr=="string")try{let i=R(e.errorExpr).evaluate(r);a=i!=null?String(i):void 0;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.errorExpr failed: ${u}`)}return a!==void 0?{result:s,data:o,error:a}:{result:s,data:o}}var _="b64:";function Vt(e){let t=new TextEncoder().encode(e),n=globalThis.Buffer,r;if(n)r=n.from(t).toString("base64");else if(typeof btoa=="function"){let s="";for(let o of t)s+=String.fromCharCode(o);r=btoa(s);}else throw new Error("No base64 encoder available in this runtime");return r.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function Wt(e){let t=e.replace(/-/g,"+").replace(/_/g,"/")+"=".repeat((4-e.length%4)%4),n=globalThis.Buffer;if(n)return n.from(t,"base64").toString("utf8");if(typeof atob=="function"){let r=atob(t),s=new Uint8Array(r.length);for(let o=0;o<r.length;o+=1)s[o]=r.charCodeAt(o);return new TextDecoder().decode(s)}throw new Error("No base64 decoder available in this runtime")}function J(e){return `${_}${Vt(JSON.stringify(e))}`}function D(e){if(!e.startsWith(_))throw new Error(`Invalid ref format (expected ${_}<base64url(json)>): ${e}`);let t;try{t=JSON.parse(Wt(e.slice(_.length)));}catch{throw new Error(`Invalid ref format (malformed base64url/json): ${e}`)}if(!t||typeof t!="object")throw new Error(`Invalid ref format (expected object payload): ${e}`);let n=t;if(typeof n.kind!="string"||typeof n.value!="string")throw new Error(`Invalid ref format (payload must contain string kind/value): ${e}`);return {kind:n.kind,value:n.value}}function ft(e){return !!e&&typeof e=="object"&&e.type==="compute-jsonata"&&Array.isArray(e.expr)&&e.expr.length>0}function gt(e){if(!e||typeof e!="object")return false;let t=e;if(t.type!=="ref"||typeof t.howToRun!="string")return false;if(typeof t.whatToRun=="string")return true;if(t.whatToRun&&typeof t.whatToRun=="object"){let n=t.whatToRun;return typeof n.kind=="string"&&typeof n.value=="string"}return false}function Gt(e){if(typeof e=="string"){let t=e.indexOf("=");if(t<1)throw new Error(`[step-machine-public] Invalid compute expression (missing "="): "${e}"`);return {bindTo:e.slice(0,t).trim(),expr:e.slice(t+1).trim()}}if(e&&typeof e=="object"&&typeof e.bindTo=="string"&&typeof e.expr=="string")return e;throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(e)}`)}function Xt(e,t,n){let r=t.split("."),s=e;for(let o=0;o<r.length-1;o++){let a=r[o];(s[a]==null||typeof s[a]!="object")&&(s[a]={}),s=s[a];}s[r[r.length-1]]=n;}function mt(e,t,n){let r=e.expr.map(Gt);return async s=>{let o=s&&typeof s=="object"&&!Array.isArray(s)?{...s}:{},a={},i={expects_data:o,data:a,...n?{config:n}:{}},u,c;for(let d of r)try{let l=$(d.expr).evaluate(i);if(d.bindTo==="result")u=l!=null?String(l):"success";else if(d.bindTo==="error")c=l!=null?String(l):void 0;else if(d.bindTo.startsWith("data."))Xt(a,d.bindTo.slice(5),l);else return {result:"failure",data:{},error:`[${t}] invalid bindTo "${d.bindTo}": must be "result", "error", or start with "data."`}}catch(l){let f=l instanceof Error?l.message:String(l);return {result:"failure",data:{},error:`[${t}] compute "${d.bindTo}" failed: ${f}`}}return u===void 0?{result:"failure",data:{},error:`[${t}] compute-jsonata: no "result" binding declared \u2014 add '- result = "success"' to expr`}:c?{result:u,data:a,error:c}:{result:u,data:a}}}function ht(e,t,n,r){let{type:s,...o}=e,a={...o,whatToRun:typeof o.whatToRun=="object"?J(o.whatToRun):o.whatToRun};return async i=>{let u=i&&typeof i=="object"&&!Array.isArray(i)?{...i}:{};r&&(u.config=r);try{let c=await n(a,u);if(!e.outputTransforms)return c;try{return dt(e.outputTransforms,c,t)}catch(d){let l=d instanceof Error?d.message:String(d);return {result:"failure",data:{},error:l}}}catch(c){let d=c instanceof Error?c.message:String(c);return {result:"failure",data:{error:`[step-machine-public] step "${t}" invoke threw: ${d}`}}}}}function yt(){return async e=>({result:"success",data:e&&typeof e=="object"&&!Array.isArray(e)?e:{}})}function Yt(e,t,n){return async(r,s)=>{let o=r?.[t.items];if(!Array.isArray(o))return {result:"failure",data:{},error:`[${n}] forEach: "${t.items}" is not an array (got ${typeof o})`};let a=o,i=t.collectAs??`${t.items}_results`;if(a.length===0)return {result:"success",data:{[i]:[]}};let{[t.items]:u,...c}=r,d=Math.max(1,t.concurrency??1),l=new Array(a.length),f=0,h=0,w=0;return await new Promise(p=>{function g(){for(;f<d&&h<a.length;){let x=h++;f++;let P={...c,[t.as]:a[x]};e(P,s).then(S=>{l[x]=S;}).catch(S=>{let y=S instanceof Error?S.message:String(S);l[x]={result:"failure",data:{},error:y};}).finally(()=>{f--,l[x]?.result==="failure"&&w++,h>=a.length&&f===0?p():g();});}f===0&&h>=a.length&&p();}g();}),w>0?{result:"failure",data:{errors:l.filter(g=>g.result==="failure").map(g=>g.error)},error:`[${n}] forEach: ${w}/${a.length} items failed`}:{result:"success",data:{[i]:l.map(p=>p.data)}}}}function wt(e,t,n){let r=Array.isArray(t?.produces_data)?t?.produces_data:void 0,s=Array.isArray(t?.input_validations)?t?.input_validations:void 0,o=t?.config??void 0,a=t?.handler,i;return ft(a)?i=mt(a,e,o):gt(a)?i=ht(a,e,n.invoke,o):i=yt(),t?.forEach&&(i=Yt(i,t.forEach,e)),Y(X(i,r),s,e)}function Q(e,t){let n={};for(let[r,s]of Object.entries(e.steps??{}))n[r]=wt(r,s,t);return n}function ee(e){if(typeof e=="object"&&e!==null){let{command:n,args:r=[],...s}=e,o=xt(n,r);return {...s,command:o.command,args:o.args}}let t=vt(e);if(t.length===0)throw new Error(`Empty command spec: ${JSON.stringify(e)}`);return xt(t[0],t.slice(1))}function xt(e,t){return /^(node|node\.exe)$/i.test(e)?{command:process.execPath,args:t}:/\.m?js$/i.test(e)?{command:process.execPath,args:[e,...t]}:{command:e,args:t}}function vt(e){let t=[],n="",r=null;for(let s of e.trim()){if(r){s===r?r=null:n+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){n&&(t.push(n),n="");continue}n+=s;}if(r)throw new Error(`Unterminated quote in command: ${e}`);return n&&t.push(n),t}function Z(e){return process.platform==="win32"&&/\.(cmd|bat)$/i.test(e)}function kt(e,t){let{command:n,args:r=[],cwd:s,env:o,timeoutMs:a}=e;return execFileSync(n,r,{shell:Z(n),timeout:a,encoding:t?.encoding??"utf-8",cwd:s,windowsHide:true,env:o?{...process.env,...o}:void 0,input:t?.input})}function ne(e,t){let{command:n,args:r=[],cwd:s,env:o,timeoutMs:a=3e4}=e;execFile(n,r,{shell:Z(n),encoding:"utf8",windowsHide:true,timeout:a,maxBuffer:10*1024*1024,cwd:s,env:o?{...process.env,...o}:void 0},(i,u,c)=>t(i??null,u,c));}v.join(Rt.tmpdir(),".board-live-cards-git-bash-cache.json");function bt(e){let{command:t,args:n=[]}=e;if(process.platform==="win32"){spawn(t,n,{detached:true,stdio:"ignore",windowsHide:true,shell:Z(t)}).unref();return}spawn(t,n,{detached:true,stdio:"ignore"}).unref();}function Et(e,t,n){let r=v.join(e,"board-live-cards-cli.js");if(m.existsSync(r))return {cmd:process.execPath,args:[r,t,...n]};let s=v.join(e,"board-live-cards-cli.ts"),o=v.join(e,"..","..","node_modules","tsx","dist","cli.mjs"),a=v.join(e,"..","..","node_modules",".bin","tsx"),i=m.existsSync(o)?o:a;return m.existsSync(s)&&m.existsSync(i)?{cmd:process.execPath,args:[i,s,t,...n]}:{cmd:process.platform==="win32"?"npx.cmd":"npx",args:["tsx",s,t,...n]}}function At(){return {executeSync(e,t,n){return kt({command:e,args:t,cwd:n?.cwd,timeoutMs:n?.timeout,env:n?.env},{encoding:n?.encoding,input:n?.input})},executeAsync(e,t,n){ne({command:e,args:t},n);},resolveInvocation(e,t){let n=ee({command:e,args:t});return {cmd:n.command,args:n.args??[]}},splitCommand:vt,spawnDetached(e,t){bt({command:e,args:t});}}}function re(e,t){let n=typeof e=="object"?e.value:D(e).value;switch(n){case "source-cli-task-executor":{let r=v.join(t,"source-cli-task-executor.js");if(m.existsSync(r))return {command:process.execPath,args:[r]};let s=v.join(t,"source-cli-task-executor.ts"),o=v.join(t,"..","..","node_modules","tsx","dist","cli.mjs"),a=v.join(t,"..","..","node_modules",".bin","tsx"),i=m.existsSync(o)?o:a;return m.existsSync(s)&&m.existsSync(i)?{command:process.execPath,args:[i,s]}:{command:process.execPath,args:[r]}}case "board-live-cards":{let{cmd:r,args:s}=Et(t,"_",[]);return {command:r,args:s}}default:throw new Error(`resolveBuiltIn: unknown built-in name "${n}". Supported: source-cli-task-executor, board-live-cards`)}}function se(e,t){if(e.howToRun==="built-in"){let{command:r,args:s}=re(e.whatToRun,t);return {command:r,baseArgs:s}}let n=typeof e.whatToRun=="object"?e.whatToRun.value:D(e.whatToRun).value;switch(e.howToRun){case "local-node":return {command:process.execPath,baseArgs:[n]};case "local-python":return {command:process.platform==="win32"?"python":"python3",baseArgs:[n]};case "local-process":return {command:n,baseArgs:[]};default:throw new Error(`resolveBaseInvocation: howToRun "${e.howToRun}" is not a local transport`)}}function oe(e,t){return se(e,t)}function ie(e){let t=e.trim();if(!t)throw new Error("empty stdout");try{return JSON.parse(t)}catch{let n=t.split(/\r?\n/).filter(Boolean),r=n[n.length-1];return JSON.parse(r)}}function ae(e){let t=e.whatToRun;return typeof t=="object"?t.value:D(t).value}function ce(e,t){return {...t,whatToRun:ae(e),...e.extra?{extra:e.extra}:{}}}function ue(e,t,n="invokeExecutionRef"){return pt(e,t,n)}function le(e){return e&&typeof e=="object"&&!Array.isArray(e)&&typeof e.result=="string"&&e.data&&typeof e.data=="object"&&!Array.isArray(e.data)?e:{result:"success",data:e&&typeof e=="object"&&!Array.isArray(e)?e:{stdout:e}}}function N(e){return {result:"failure",data:{error:e}}}function B(e,t,n){let r=n?.label??"invokeExecutionRefSync",s=n?.cliDir??n?.cwd??process.cwd(),o;try{o=ue(e.argsMassaging,ce(e,t),r);}catch(l){let f=l instanceof Error?l.message:String(l);return N(f)}let a;try{a=oe(e,s);}catch(l){let f=l instanceof Error?l.message:String(l);return N(`[${r}] ref resolution failed: ${f}`)}let i=[...a.baseArgs,...o.cmdArgs??[]],u=JSON.stringify(o.stdin??t),c=At(),d;try{d=c.executeSync(a.command,i,{timeout:n?.timeoutMs??3e4,encoding:"utf-8",cwd:n?.cwd,input:u});}catch(l){let f=l,h=(f.stderr?String(f.stderr):"").trim(),w=typeof f.status=="number"?f.status:"unknown",p=h||f.message;return N(`[${r}] ref exited with status ${w}${p?`: ${p}`:""}`)}try{return le(ie(d))}catch{return {result:"success",data:{stdout:d.trim()}}}}var pe={"local-node":B,"local-python":B,"local-process":B,"built-in":B};function de(e,t,n){let r=n?.syncTransports?.[e.howToRun]??pe[e.howToRun];return r?r(e,t,n):N(`[${n?.label??"invokeExecutionRefSync"}] unsupported sync howToRun: ${e.howToRun}`)}function jt(e,t,n){return de(e,t,n)}function ge(e,t){if(process.platform!=="win32"){m.renameSync(e,t);return}let n=[10,20,40,80,160];for(let r=0;r<=n.length;r++)try{m.renameSync(e,t);return}catch(s){let o=s.code;if((o==="EPERM"||o==="EBUSY")&&r<n.length){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,n[r]);continue}throw s}}function Tt(e){function t(r){return v.join(e,...r.split("/"))+".json"}function n(r,s,o,a){if(m.existsSync(r))for(let i of m.readdirSync(r,{withFileTypes:true})){let u=s?`${s}/${i.name}`:i.name;if(i.isDirectory()){n(v.join(r,i.name),u,o,a);continue}if(!i.isFile()||!i.name.endsWith(".json"))continue;let c=u.replace(/\.json$/,"");(!o||c.startsWith(o))&&a.push(c);}}return {read(r){let s=t(r);if(!m.existsSync(s))return null;try{return JSON.parse(m.readFileSync(s,"utf-8"))}catch{return null}},write(r,s){let o=t(r),a=`${o}.${process.pid}.${randomUUID()}.tmp`;m.mkdirSync(v.dirname(o),{recursive:true}),m.writeFileSync(a,JSON.stringify(s,null,2),"utf-8"),ge(a,o);},delete(r){let s=t(r);try{m.existsSync(s)&&m.unlinkSync(s);}catch{}},listKeys(r){let s=[];return n(e,"",r,s),s.sort()}}}var L=class extends Error{constructor(n,r){super(r);this.code=n;this.name="CliExitError";}code},me=".pause";async function qn(e){let t=he(e);if(t.help||e.length===0)throw be(),new L(e.length===0?1:0);let{flowArg:n,dataArg:r,storeArg:s,storeDirArg:o,resumeRequested:a,pauseRequested:i,statusRequested:u}=t;if((i||u)&&(r||a||n))throw new Error("[step-machine-cli] --pause and --status are store-level operations. Do not provide flow, data, or --resume.");if(a&&r)throw new Error("[step-machine-cli] --initial-data cannot be combined with --resume.");let c=ye(s,o);if(u){await xe(c);return}if(i){await we(c);return}if(!n)throw new Error("[step-machine-cli] Flow path is required for run/resume operations.");let d=Ft(n),l=v.dirname(d),f=Re(r),{store:h}=c,w=await I(d),p=ke(w,l);$t(c);let g=new AbortController,x=false,P=H(w,p,{store:h,signal:g.signal,onStep:()=>{!x&&et(c)&&(x=true,g.abort());}}),S;if(a){if(S=await Ct(c),!S){console.warn("[step-machine-cli] No paused run found in store directory."),console.log(JSON.stringify({status:"noop",reason:"no-paused-run"},null,2));return}}else c.storeType==="file"&&!f&&(S=await Ct(c));let y=S?await P.resume(S):await P.run(f);if(x&&y.status==="cancelled"){let M=await Se(h,y.runId);$t(c),console.log(JSON.stringify({runId:y.runId,status:"paused",currentStep:M?.currentStep,pausedAt:M?.pausedAt,stepHistory:y.stepHistory,data:y.data},null,2));return}if(y.status!=="completed"){let M=y.error?.message??y.intent??y.status;throw console.error(`[step-machine-cli] Run failed: ${M}`),new L(1)}console.log(JSON.stringify({runId:y.runId,status:y.status,intent:y.intent,finalStep:y.finalStep,stepHistory:y.stepHistory,data:y.data},null,2));}function he(e){let t=new Set(["--initial-data","--store","--store-dir"]),n={},r=[],s=false,o=false,a=false,i=false;for(let u=0;u<e.length;u++){let c=e[u];if(c==="-h"||c==="--help"){s=true;continue}if(c==="--resume"){o=true;continue}if(c==="--pause"){a=true;continue}if(c==="--status"){i=true;continue}if(t.has(c)){let d=e[u+1];if(!d||d.startsWith("--"))throw new Error(`[step-machine-cli] Missing value for ${c}.`);n[c]=d,u++;continue}if(c.startsWith("--"))throw new Error(`[step-machine-cli] Unknown flag: ${c}`);r.push(c);}if([o,a,i].filter(Boolean).length>1)throw new Error("[step-machine-cli] Use only one of --resume, --pause, or --status at a time.");return {help:s,flowArg:r[0],dataArg:n["--initial-data"],storeArg:String(n["--store"]??"memory").toLowerCase(),storeDirArg:n["--store-dir"],resumeRequested:o,pauseRequested:a,statusRequested:i}}function Ft(e){return v.isAbsolute(e)?e:v.resolve(process.cwd(),e)}function ye(e,t){if(e!=="memory"&&e!=="file")throw new Error(`[step-machine-cli] Invalid --store value "${e}". Expected "memory" or "file".`);if(e==="memory")return {storeType:e,storeDir:void 0,pauseFilePath:void 0,store:new k};if(!t||t.trim().length===0)throw new Error("[step-machine-cli] --store file requires --store-dir <directory>.");let n=Ft(t);return {storeType:e,storeDir:n,pauseFilePath:v.join(n,me),store:new j(Tt(n))}}async function tt(e){if(!e.listRuns)return [];let t=await e.listRuns(),n=[];for(let r of t){let s=await e.loadRunState(r);s&&n.push(s);}return n.sort((r,s)=>(s.updatedAt??s.startedAt??0)-(r.updatedAt??r.startedAt??0)),n}function et(e){return e.storeType!=="file"||!e.pauseFilePath?false:m.existsSync(e.pauseFilePath)}function $t(e){et(e)&&m.unlinkSync(e.pauseFilePath);}async function we(e){if(e.storeType!=="file"||!e.pauseFilePath)throw new Error("[step-machine-cli] --pause requires --store file --store-dir <directory>.");let t=await tt(e.store);if(t.length===0){console.warn("[step-machine-cli] No runs found in store directory. Pause is a no-op."),console.log(JSON.stringify({status:"noop",reason:"no-runs"},null,2));return}if(!t.find(r=>r.status==="running")){console.warn("[step-machine-cli] No running run found. Pause is a no-op."),console.log(JSON.stringify({status:"noop",reason:"no-running-run"},null,2));return}m.mkdirSync(e.storeDir,{recursive:true}),m.writeFileSync(e.pauseFilePath,JSON.stringify({requestedAt:Date.now()}),"utf-8"),console.log(JSON.stringify({status:"pause-requested",storeDir:e.storeDir},null,2));}async function Ct(e){let n=(await tt(e.store)).filter(r=>r.status==="paused");if(n.length!==0)return n.length>1&&console.warn("[step-machine-cli] Multiple paused runs found; resuming the most recently updated run."),n[0].runId}async function Se(e,t){let n=await e.loadRunState(t);if(!n)return null;let r={...n,status:"paused",pausedAt:Date.now(),updatedAt:Date.now()};return await e.saveRunState(t,r),r}async function xe(e){if(e.storeType!=="file")throw new Error("[step-machine-cli] --status requires --store file --store-dir <directory>.");let t=await tt(e.store),n={store:"file",storeDir:e.storeDir,pauseRequested:et(e),totalRuns:t.length,runs:t.map(r=>({runId:r.runId,status:r.status,currentStep:r.currentStep,startedAt:r.startedAt,updatedAt:r.updatedAt,pausedAt:r.pausedAt}))};console.log(JSON.stringify(n,null,2));}function Re(e){if(e)try{let t=JSON.parse(e);if(!t||typeof t!="object"||Array.isArray(t))throw new Error("Initial data must be a JSON object.");return t}catch(t){let n=t instanceof Error?t.message:String(t);throw new Error(`[step-machine-cli] Invalid --initial-data value: ${n}`)}}function ve(e){if(!e||typeof e!="object")return e;let t=e;if(typeof t.whatToRun!="string"||!t.whatToRun.startsWith("b64:"))return e;try{let n=t.whatToRun.slice(4),r=n+"=".repeat((4-n.length%4)%4),s=Buffer.from(r.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"),o=JSON.parse(s);return !o||typeof o!="object"||typeof o.value!="string"?e:{...t,whatToRun:o}}catch{return e}}function ke(e,t){return Q(e,{invoke:(r,s)=>jt(ve(r),s,{cliDir:t,cwd:t})})}function be(){console.error("Usage: step-machine-cli <step-flow.yaml> [--initial-data <json>] [--store <memory|file>] [--store-dir <directory>] [--resume]"),console.error(" step-machine-cli --store file --store-dir <directory> --pause"),console.error(" step-machine-cli --store file --store-dir <directory> --status"),console.error(""),console.error("Example:"),console.error(' step-machine-cli examples/cli/step-machine-demo/two-step-math.flow.yaml --initial-data "{"a":3,"b":4}"'),console.error(" step-machine-cli ./flow.yaml --store file --store-dir ./.runs"),console.error(" step-machine-cli ./flow.yaml --store file --store-dir ./.runs --resume"),console.error(" step-machine-cli --store file --store-dir ./.runs --pause"),console.error(" step-machine-cli --store file --store-dir ./.runs --status");}
|
|
4
|
-
export{
|
|
3
|
+
- `)}`);return t}function X(e){return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function rt(e){return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var j=class{constructor(t){this.kv=t;}kv;stateKey(t){return `state_${X(t)}`}dataPrefix(t){return `data_${X(t)}_`}dataKey(t,n){return `${this.dataPrefix(t)}${X(n)}`}async saveRunState(t,n){this.kv.write(this.stateKey(t),n);}async loadRunState(t){let n=this.kv.read(this.stateKey(t));return n!=null&&typeof n=="object"?n:null}async deleteRunState(t){this.kv.delete(this.stateKey(t));for(let n of this.kv.listKeys(this.dataPrefix(t)))this.kv.delete(n);}async setData(t,n,r){this.kv.write(this.dataKey(t,n),r);}async getData(t,n){return this.kv.read(this.dataKey(t,n))}async getAllData(t){let n=this.dataPrefix(t),r={};for(let o of this.kv.listKeys(n))r[rt(o.slice(n.length))]=this.kv.read(o);return r}async clearData(t){for(let n of this.kv.listKeys(this.dataPrefix(t)))this.kv.delete(n);}async listRuns(){return this.kv.listKeys("state_").map(t=>rt(t.slice(6)))}};var st=dirname(fileURLToPath(import.meta.url)),Dt=createRequire(import.meta.url);function Bt(){let e=resolve(st,"./jsonata-sync.cjs");return existsSync(e)?e:resolve(st,"../card-compute/jsonata-sync.cjs")}var F=Dt(Bt());function it(e,t){if(!e||typeof e!="object")throw new Error(`[step-machine-public] Step "${t}" returned a non-object result.`);let n=e,r=n.result??n.status;if(typeof r=="string"&&r.trim().length>0){let o=n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?{...n.data}:{},s=typeof n.error=="string"?n.error:void 0;return s&&!("error"in o)&&(o.error=s),{result:r,data:o,...s?{error:s}:{}}}return {result:"success",data:{...n}}}function at(e,t){if(!t||t.length===0)return e;let n={};for(let r of t)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function Y(e,t){return async(n,r)=>{let o=await e(n,r),s=it(o,r?.stepName??"unknown");return {result:s.result,data:at(s.data,t),...s.error?{error:s.error}:{}}}}function ct(e,t,n){if(!t||t.length===0)return null;for(let r of t)try{if(!F(r).evaluate(e))return {result:"failure",data:{error:`[${n}] input validation failed: ${r}`}}}catch(o){let s=o instanceof Error?o.message:String(o);return {result:"failure",data:{error:`[${n}] input validation error on "${r}": ${s}`}}}return null}function Q(e,t,n){return !t||t.length===0?e:async(r,o)=>{let s=ct(r,t,n);return s||e(r,o)}}var lt=dirname(fileURLToPath(import.meta.url)),qt=createRequire(import.meta.url);function zt(){let e=resolve(lt,"./jsonata-sync.cjs");return existsSync(e)?e:resolve(lt,"../../card-compute/jsonata-sync.cjs")}var x=qt(zt());function pt(e,t,n){if(!e||typeof e!="object")return {};let r={};if(Array.isArray(e.cmdTemplate)){let o=[];for(let s of e.cmdTemplate)try{o.push(String(x(s).evaluate(t)));}catch(a){let i=a instanceof Error?a.message:String(a);throw new Error(`[${n}] argsMassaging.cmdTemplate failed on "${s}": ${i}`)}r.cmdArgs=o;}if(typeof e.stdinTemplate=="string")try{r.stdin=x(e.stdinTemplate).evaluate(t);}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[${n}] argsMassaging.stdinTemplate failed: ${s}`)}if(typeof e.urlTemplate=="string")try{r.url=String(x(e.urlTemplate).evaluate(t));}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[${n}] argsMassaging.urlTemplate failed: ${s}`)}if(typeof e.headerTemplate=="string")try{let o=x(e.headerTemplate).evaluate(t);if(typeof o!="object"||o===null)throw new Error(`headerTemplate must produce an object, got: ${JSON.stringify(o)}`);r.headers=o;}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[${n}] argsMassaging.headerTemplate failed: ${s}`)}if(typeof e.bodyTemplate=="string")try{r.body=x(e.bodyTemplate).evaluate(t);}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[${n}] argsMassaging.bodyTemplate failed: ${s}`)}return r}function dt(e,t,n){if(!e||typeof e!="object")return t;let r={output:t},o=t.result,s=t.data,a=t.error;if(typeof e.resultExpr=="string")try{let i=x(e.resultExpr).evaluate(r);if(typeof i!="string"||!i.trim())throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(i)})`);o=i;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.resultExpr failed: ${u}`)}if(typeof e.dataTemplate=="string")try{let i=x(e.dataTemplate).evaluate(r);if(!i||typeof i!="object"||Array.isArray(i))throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(i)})`);s=i;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.dataTemplate failed: ${u}`)}if(typeof e.errorExpr=="string")try{let i=x(e.errorExpr).evaluate(r);a=i!=null?String(i):void 0;}catch(i){let u=i instanceof Error?i.message:String(i);throw new Error(`[${n}] outputTransforms.errorExpr failed: ${u}`)}return a!==void 0?{result:o,data:s,error:a}:{result:o,data:s}}var _="b64:";function Vt(e){let t=new TextEncoder().encode(e),n=globalThis.Buffer,r;if(n)r=n.from(t).toString("base64");else if(typeof btoa=="function"){let o="";for(let s of t)o+=String.fromCharCode(s);r=btoa(o);}else throw new Error("No base64 encoder available in this runtime");return r.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function Wt(e){let t=e.replace(/-/g,"+").replace(/_/g,"/")+"=".repeat((4-e.length%4)%4),n=globalThis.Buffer;if(n)return n.from(t,"base64").toString("utf8");if(typeof atob=="function"){let r=atob(t),o=new Uint8Array(r.length);for(let s=0;s<r.length;s+=1)o[s]=r.charCodeAt(s);return new TextDecoder().decode(o)}throw new Error("No base64 decoder available in this runtime")}function J(e){return `${_}${Vt(JSON.stringify(e))}`}function D(e){if(!e.startsWith(_))throw new Error(`Invalid ref format (expected ${_}<base64url(json)>): ${e}`);let t;try{t=JSON.parse(Wt(e.slice(_.length)));}catch{throw new Error(`Invalid ref format (malformed base64url/json): ${e}`)}if(!t||typeof t!="object")throw new Error(`Invalid ref format (expected object payload): ${e}`);let n=t;if(typeof n.kind!="string"||typeof n.value!="string")throw new Error(`Invalid ref format (payload must contain string kind/value): ${e}`);return {kind:n.kind,value:n.value}}function ft(e){return !!e&&typeof e=="object"&&e.type==="compute-jsonata"&&Array.isArray(e.expr)&&e.expr.length>0}function gt(e){if(!e||typeof e!="object")return false;let t=e;if(t.type!=="ref"||typeof t.howToRun!="string")return false;if(typeof t.whatToRun=="string")return true;if(t.whatToRun&&typeof t.whatToRun=="object"){let n=t.whatToRun;return typeof n.kind=="string"&&typeof n.value=="string"}return false}function Gt(e){if(typeof e=="string"){let t=e.indexOf("=");if(t<1)throw new Error(`[step-machine-public] Invalid compute expression (missing "="): "${e}"`);return {bindTo:e.slice(0,t).trim(),expr:e.slice(t+1).trim()}}if(e&&typeof e=="object"&&typeof e.bindTo=="string"&&typeof e.expr=="string")return e;throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(e)}`)}function Xt(e,t,n){let r=t.split("."),o=e;for(let s=0;s<r.length-1;s++){let a=r[s];(o[a]==null||typeof o[a]!="object")&&(o[a]={}),o=o[a];}o[r[r.length-1]]=n;}function mt(e,t,n){let r=e.expr.map(Gt);return async o=>{let s=o&&typeof o=="object"&&!Array.isArray(o)?{...o}:{},a={},i={expects_data:s,data:a,...n?{config:n}:{}},u,c;for(let d of r)try{let l=F(d.expr).evaluate(i);if(d.bindTo==="result")u=l!=null?String(l):"success";else if(d.bindTo==="error")c=l!=null?String(l):void 0;else if(d.bindTo.startsWith("data."))Xt(a,d.bindTo.slice(5),l);else return {result:"failure",data:{},error:`[${t}] invalid bindTo "${d.bindTo}": must be "result", "error", or start with "data."`}}catch(l){let f=l instanceof Error?l.message:String(l);return {result:"failure",data:{},error:`[${t}] compute "${d.bindTo}" failed: ${f}`}}return u===void 0?{result:"failure",data:{},error:`[${t}] compute-jsonata: no "result" binding declared \u2014 add '- result = "success"' to expr`}:c?{result:u,data:a,error:c}:{result:u,data:a}}}function ht(e,t,n,r){let{type:o,...s}=e,a={...s,whatToRun:typeof s.whatToRun=="object"?J(s.whatToRun):s.whatToRun};return async i=>{let u=i&&typeof i=="object"&&!Array.isArray(i)?{...i}:{};r&&(u.config=r);try{let c=await n(a,u);if(!e.outputTransforms)return c;try{return dt(e.outputTransforms,c,t)}catch(d){let l=d instanceof Error?d.message:String(d);return {result:"failure",data:{},error:l}}}catch(c){let d=c instanceof Error?c.message:String(c);return {result:"failure",data:{error:`[step-machine-public] step "${t}" invoke threw: ${d}`}}}}}function yt(){return async e=>({result:"success",data:e&&typeof e=="object"&&!Array.isArray(e)?e:{}})}function Yt(e,t,n){return async(r,o)=>{let s=r?.[t.items];if(!Array.isArray(s))return {result:"failure",data:{},error:`[${n}] forEach: "${t.items}" is not an array (got ${typeof s})`};let a=s,i=t.collectAs??`${t.items}_results`;if(a.length===0)return {result:"success",data:{[i]:[]}};let{[t.items]:u,...c}=r,d=Math.max(1,t.concurrency??1),l=new Array(a.length),f=0,h=0,w=0;return await new Promise(p=>{function g(){for(;f<d&&h<a.length;){let R=h++;f++;let P={...c,[t.as]:a[R]};e(P,o).then(S=>{l[R]=S;}).catch(S=>{let y=S instanceof Error?S.message:String(S);l[R]={result:"failure",data:{},error:y};}).finally(()=>{f--,l[R]?.result==="failure"&&w++,h>=a.length&&f===0?p():g();});}f===0&&h>=a.length&&p();}g();}),w>0?{result:"failure",data:{errors:l.filter(g=>g.result==="failure").map(g=>g.error)},error:`[${n}] forEach: ${w}/${a.length} items failed`}:{result:"success",data:{[i]:l.map(p=>p.data)}}}}function wt(e,t,n){let r=Array.isArray(t?.produces_data)?t?.produces_data:void 0,o=Array.isArray(t?.input_validations)?t?.input_validations:void 0,s=t?.config??void 0,a=t?.handler,i;return ft(a)?i=mt(a,e,s):gt(a)?i=ht(a,e,n.invoke,s):i=yt(),t?.forEach&&(i=Yt(i,t.forEach,e)),Q(Y(i,r),o,e)}function B(e,t){let n={};for(let[r,o]of Object.entries(e.steps??{}))n[r]=wt(r,o,t);return n}function ee(e){if(typeof e=="object"&&e!==null){let{command:n,args:r=[],...o}=e,s=Rt(n,r);return {...o,command:s.command,args:s.args}}let t=vt(e);if(t.length===0)throw new Error(`Empty command spec: ${JSON.stringify(e)}`);return Rt(t[0],t.slice(1))}function Rt(e,t){return /^(node|node\.exe)$/i.test(e)?{command:process.execPath,args:t}:/\.m?js$/i.test(e)?{command:process.execPath,args:[e,...t]}:{command:e,args:t}}function vt(e){let t=[],n="",r=null;for(let o of e.trim()){if(r){o===r?r=null:n+=o;continue}if(o==='"'||o==="'"){r=o;continue}if(/\s/.test(o)){n&&(t.push(n),n="");continue}n+=o;}if(r)throw new Error(`Unterminated quote in command: ${e}`);return n&&t.push(n),t}function Z(e){return process.platform==="win32"&&/\.(cmd|bat)$/i.test(e)}function kt(e,t){let{command:n,args:r=[],cwd:o,env:s,timeoutMs:a}=e;return execFileSync(n,r,{shell:Z(n),timeout:a,encoding:t?.encoding??"utf-8",cwd:o,windowsHide:true,env:s?{...process.env,...s}:void 0,input:t?.input})}function ne(e,t){let{command:n,args:r=[],cwd:o,env:s,timeoutMs:a=3e4}=e;execFile(n,r,{shell:Z(n),encoding:"utf8",windowsHide:true,timeout:a,maxBuffer:10*1024*1024,cwd:o,env:s?{...process.env,...s}:void 0},(i,u,c)=>t(i??null,u,c));}k.join(xt.tmpdir(),".board-live-cards-git-bash-cache.json");function bt(e){let{command:t,args:n=[]}=e;if(process.platform==="win32"){spawn(t,n,{detached:true,stdio:"ignore",windowsHide:true,shell:Z(t)}).unref();return}spawn(t,n,{detached:true,stdio:"ignore"}).unref();}function Et(e,t,n){let r=k.join(e,"board-live-cards-cli.js");if(m.existsSync(r))return {cmd:process.execPath,args:[r,t,...n]};let o=k.join(e,"board-live-cards-cli.ts"),s=k.join(e,"..","..","node_modules","tsx","dist","cli.mjs"),a=k.join(e,"..","..","node_modules",".bin","tsx"),i=m.existsSync(s)?s:a;return m.existsSync(o)&&m.existsSync(i)?{cmd:process.execPath,args:[i,o,t,...n]}:{cmd:process.platform==="win32"?"npx.cmd":"npx",args:["tsx",o,t,...n]}}function At(){return {executeSync(e,t,n){return kt({command:e,args:t,cwd:n?.cwd,timeoutMs:n?.timeout,env:n?.env},{encoding:n?.encoding,input:n?.input})},executeAsync(e,t,n){ne({command:e,args:t},n);},resolveInvocation(e,t){let n=ee({command:e,args:t});return {cmd:n.command,args:n.args??[]}},splitCommand:vt,spawnDetached(e,t){bt({command:e,args:t});}}}function re(e,t){let n=typeof e=="object"?e.value:D(e).value;switch(n){case "source-cli-task-executor":{let r=k.join(t,"source-cli-task-executor.js");if(m.existsSync(r))return {command:process.execPath,args:[r]};let o=k.join(t,"source-cli-task-executor.ts"),s=k.join(t,"..","..","node_modules","tsx","dist","cli.mjs"),a=k.join(t,"..","..","node_modules",".bin","tsx"),i=m.existsSync(s)?s:a;return m.existsSync(o)&&m.existsSync(i)?{command:process.execPath,args:[i,o]}:{command:process.execPath,args:[r]}}case "board-live-cards":{let{cmd:r,args:o}=Et(t,"_",[]);return {command:r,args:o}}default:throw new Error(`resolveBuiltIn: unknown built-in name "${n}". Supported: source-cli-task-executor, board-live-cards`)}}function oe(e,t){if(e.howToRun==="built-in"){let{command:r,args:o}=re(e.whatToRun,t);return {command:r,baseArgs:o}}let n=typeof e.whatToRun=="object"?e.whatToRun.value:D(e.whatToRun).value;switch(e.howToRun){case "local-node":return {command:process.execPath,baseArgs:[n]};case "local-python":return {command:process.platform==="win32"?"python":"python3",baseArgs:[n]};case "local-process":return {command:n,baseArgs:[]};default:throw new Error(`resolveBaseInvocation: howToRun "${e.howToRun}" is not a local transport`)}}function se(e,t){return oe(e,t)}function ie(e){let t=e.trim();if(!t)throw new Error("empty stdout");try{return JSON.parse(t)}catch{let n=t.split(/\r?\n/).filter(Boolean),r=n[n.length-1];return JSON.parse(r)}}function ae(e){let t=e.whatToRun;return typeof t=="object"?t.value:D(t).value}function ce(e,t){return {...t,whatToRun:ae(e),...e.extra?{extra:e.extra}:{}}}function ue(e,t,n="invokeExecutionRef"){return pt(e,t,n)}function le(e){return e&&typeof e=="object"&&!Array.isArray(e)&&typeof e.result=="string"&&e.data&&typeof e.data=="object"&&!Array.isArray(e.data)?e:{result:"success",data:e&&typeof e=="object"&&!Array.isArray(e)?e:{stdout:e}}}function L(e){return {result:"failure",data:{error:e}}}function N(e,t,n){let r=n?.label??"invokeExecutionRefSync",o=n?.cliDir??n?.cwd??process.cwd(),s;try{s=ue(e.argsMassaging,ce(e,t),r);}catch(l){let f=l instanceof Error?l.message:String(l);return L(f)}let a;try{a=se(e,o);}catch(l){let f=l instanceof Error?l.message:String(l);return L(`[${r}] ref resolution failed: ${f}`)}let i=[...a.baseArgs,...s.cmdArgs??[]],u=JSON.stringify(s.stdin??t),c=At(),d;try{d=c.executeSync(a.command,i,{timeout:n?.timeoutMs??3e4,encoding:"utf-8",cwd:n?.cwd,input:u});}catch(l){let f=l,h=(f.stderr?String(f.stderr):"").trim(),w=typeof f.status=="number"?f.status:"unknown",p=h||f.message;return L(`[${r}] ref exited with status ${w}${p?`: ${p}`:""}`)}try{return le(ie(d))}catch{return {result:"success",data:{stdout:d.trim()}}}}var pe={"local-node":N,"local-python":N,"local-process":N,"built-in":N};function de(e,t,n){let r=n?.syncTransports?.[e.howToRun]??pe[e.howToRun];return r?r(e,t,n):L(`[${n?.label??"invokeExecutionRefSync"}] unsupported sync howToRun: ${e.howToRun}`)}function jt(e,t,n){return de(e,t,n)}function ge(e,t){if(process.platform!=="win32"){m.renameSync(e,t);return}let n=[10,20,40,80,160];for(let r=0;r<=n.length;r++)try{m.renameSync(e,t);return}catch(o){let s=o.code;if((s==="EPERM"||s==="EBUSY")&&r<n.length){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,n[r]);continue}throw o}}function Ct(e){function t(r){return k.join(e,...r.split("/"))+".json"}function n(r,o,s,a){if(m.existsSync(r))for(let i of m.readdirSync(r,{withFileTypes:true})){let u=o?`${o}/${i.name}`:i.name;if(i.isDirectory()){n(k.join(r,i.name),u,s,a);continue}if(!i.isFile()||!i.name.endsWith(".json"))continue;let c=u.replace(/\.json$/,"");(!s||c.startsWith(s))&&a.push(c);}}return {read(r){let o=t(r);if(!m.existsSync(o))return null;try{return JSON.parse(m.readFileSync(o,"utf-8"))}catch{return null}},write(r,o){let s=t(r),a=`${s}.${process.pid}.${randomUUID()}.tmp`;m.mkdirSync(k.dirname(s),{recursive:true}),m.writeFileSync(a,JSON.stringify(o,null,2),"utf-8"),ge(a,s);},delete(r){let o=t(r);try{m.existsSync(o)&&m.unlinkSync(o);}catch{}},listKeys(r){let o=[];return n(e,"",r,o),o.sort()}}}var K=class extends Error{constructor(n,r){super(r);this.code=n;this.name="CliExitError";}code},me=".pause";async function Yn(e){let t=he(e);if(t.help||e.length===0)throw be(),new K(e.length===0?1:0);let{flowArg:n,dataArg:r,storeArg:o,storeDirArg:s,resumeRequested:a,pauseRequested:i,statusRequested:u}=t;if((i||u)&&(r||a||n))throw new Error("[step-machine-cli] --pause and --status are store-level operations. Do not provide flow, data, or --resume.");if(a&&r)throw new Error("[step-machine-cli] --initial-data cannot be combined with --resume.");let c=ye(o,s);if(u){await Re(c);return}if(i){await we(c);return}if(!n)throw new Error("[step-machine-cli] Flow path is required for run/resume operations.");let d=$t(n),l=k.dirname(d),f=xe(r),{store:h}=c,w=await H(d),p=ke(w,l);Tt(c);let g=new AbortController,R=false,P=T(w,p,{store:h,signal:g.signal,onStep:()=>{!R&&et(c)&&(R=true,g.abort());}}),S;if(a){if(S=await Ft(c),!S){console.warn("[step-machine-cli] No paused run found in store directory."),console.log(JSON.stringify({status:"noop",reason:"no-paused-run"},null,2));return}}else c.storeType==="file"&&!f&&(S=await Ft(c));let y=S?await P.resume(S):await P.run(f);if(R&&y.status==="cancelled"){let O=await Se(h,y.runId);Tt(c),console.log(JSON.stringify({runId:y.runId,status:"paused",currentStep:O?.currentStep,pausedAt:O?.pausedAt,stepHistory:y.stepHistory,data:y.data},null,2));return}if(y.status!=="completed"){let O=y.error?.message??y.intent??y.status;throw console.error(`[step-machine-cli] Run failed: ${O}`),new K(1)}console.log(JSON.stringify({runId:y.runId,status:y.status,intent:y.intent,finalStep:y.finalStep,stepHistory:y.stepHistory,data:y.data},null,2));}function he(e){let t=new Set(["--initial-data","--store","--store-dir"]),n={},r=[],o=false,s=false,a=false,i=false;for(let u=0;u<e.length;u++){let c=e[u];if(c==="-h"||c==="--help"){o=true;continue}if(c==="--resume"){s=true;continue}if(c==="--pause"){a=true;continue}if(c==="--status"){i=true;continue}if(t.has(c)){let d=e[u+1];if(!d||d.startsWith("--"))throw new Error(`[step-machine-cli] Missing value for ${c}.`);n[c]=d,u++;continue}if(c.startsWith("--"))throw new Error(`[step-machine-cli] Unknown flag: ${c}`);r.push(c);}if([s,a,i].filter(Boolean).length>1)throw new Error("[step-machine-cli] Use only one of --resume, --pause, or --status at a time.");return {help:o,flowArg:r[0],dataArg:n["--initial-data"],storeArg:String(n["--store"]??"memory").toLowerCase(),storeDirArg:n["--store-dir"],resumeRequested:s,pauseRequested:a,statusRequested:i}}function $t(e){return k.isAbsolute(e)?e:k.resolve(process.cwd(),e)}function ye(e,t){if(e!=="memory"&&e!=="file")throw new Error(`[step-machine-cli] Invalid --store value "${e}". Expected "memory" or "file".`);if(e==="memory")return {storeType:e,storeDir:void 0,pauseFilePath:void 0,store:new v};if(!t||t.trim().length===0)throw new Error("[step-machine-cli] --store file requires --store-dir <directory>.");let n=$t(t);return {storeType:e,storeDir:n,pauseFilePath:k.join(n,me),store:new j(Ct(n))}}async function tt(e){if(!e.listRuns)return [];let t=await e.listRuns(),n=[];for(let r of t){let o=await e.loadRunState(r);o&&n.push(o);}return n.sort((r,o)=>(o.updatedAt??o.startedAt??0)-(r.updatedAt??r.startedAt??0)),n}function et(e){return e.storeType!=="file"||!e.pauseFilePath?false:m.existsSync(e.pauseFilePath)}function Tt(e){et(e)&&m.unlinkSync(e.pauseFilePath);}async function we(e){if(e.storeType!=="file"||!e.pauseFilePath)throw new Error("[step-machine-cli] --pause requires --store file --store-dir <directory>.");let t=await tt(e.store);if(t.length===0){console.warn("[step-machine-cli] No runs found in store directory. Pause is a no-op."),console.log(JSON.stringify({status:"noop",reason:"no-runs"},null,2));return}if(!t.find(r=>r.status==="running")){console.warn("[step-machine-cli] No running run found. Pause is a no-op."),console.log(JSON.stringify({status:"noop",reason:"no-running-run"},null,2));return}m.mkdirSync(e.storeDir,{recursive:true}),m.writeFileSync(e.pauseFilePath,JSON.stringify({requestedAt:Date.now()}),"utf-8"),console.log(JSON.stringify({status:"pause-requested",storeDir:e.storeDir},null,2));}async function Ft(e){let n=(await tt(e.store)).filter(r=>r.status==="paused");if(n.length!==0)return n.length>1&&console.warn("[step-machine-cli] Multiple paused runs found; resuming the most recently updated run."),n[0].runId}async function Se(e,t){let n=await e.loadRunState(t);if(!n)return null;let r={...n,status:"paused",pausedAt:Date.now(),updatedAt:Date.now()};return await e.saveRunState(t,r),r}async function Re(e){if(e.storeType!=="file")throw new Error("[step-machine-cli] --status requires --store file --store-dir <directory>.");let t=await tt(e.store),n={store:"file",storeDir:e.storeDir,pauseRequested:et(e),totalRuns:t.length,runs:t.map(r=>({runId:r.runId,status:r.status,currentStep:r.currentStep,startedAt:r.startedAt,updatedAt:r.updatedAt,pausedAt:r.pausedAt}))};console.log(JSON.stringify(n,null,2));}function xe(e){if(e)try{let t=JSON.parse(e);if(!t||typeof t!="object"||Array.isArray(t))throw new Error("Initial data must be a JSON object.");return t}catch(t){let n=t instanceof Error?t.message:String(t);throw new Error(`[step-machine-cli] Invalid --initial-data value: ${n}`)}}function ve(e){if(!e||typeof e!="object")return e;let t=e;if(typeof t.whatToRun!="string"||!t.whatToRun.startsWith("b64:"))return e;try{let n=t.whatToRun.slice(4),r=n+"=".repeat((4-n.length%4)%4),o=Buffer.from(r.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"),s=JSON.parse(o);return !s||typeof s!="object"||typeof s.value!="string"?e:{...t,whatToRun:s}}catch{return e}}function ke(e,t){return B(e,{invoke:(r,o)=>jt(ve(r),o,{cliDir:t,cwd:t})})}function be(){console.error("Usage: step-machine-cli <step-flow.yaml> [--initial-data <json>] [--store <memory|file>] [--store-dir <directory>] [--resume]"),console.error(" step-machine-cli --store file --store-dir <directory> --pause"),console.error(" step-machine-cli --store file --store-dir <directory> --status"),console.error(""),console.error("Example:"),console.error(' step-machine-cli examples/cli/step-machine-demo/two-step-math.flow.yaml --initial-data "{"a":3,"b":4}"'),console.error(" step-machine-cli ./flow.yaml --store file --store-dir ./.runs"),console.error(" step-machine-cli ./flow.yaml --store file --store-dir ./.runs --resume"),console.error(" step-machine-cli --store file --store-dir ./.runs --pause"),console.error(" step-machine-cli --store file --store-dir ./.runs --status");}
|
|
4
|
+
export{K as CliExitError,Yn as cli};//# sourceMappingURL=step-machine-cli.js.map
|
|
5
5
|
//# sourceMappingURL=step-machine-cli.js.map
|
|
@@ -138,7 +138,7 @@ interface BoardPlatformAdapter {
|
|
|
138
138
|
* KV storage factory — scoped by namespace.
|
|
139
139
|
* Namespaces used by the public layer:
|
|
140
140
|
* 'state-snapshot' — board graph snapshot (StateSnapshotStorageAdapter, built internally)
|
|
141
|
-
* 'config' — board configuration (.task-executor, .chat-handler, .card-store-ref)
|
|
141
|
+
* 'config' — board configuration (.task-executor, .chat-handler, .chat-handler-flow, .card-store-ref)
|
|
142
142
|
* 'card-upsert' — card upsert dedup index
|
|
143
143
|
* 'execution-requests' — queued execution requests (keyed by journalId)
|
|
144
144
|
* 'card-runtime' — card runtime state snapshots
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "demo-chat-copilot",
|
|
3
|
+
"settings": {
|
|
4
|
+
"start_step": "respond",
|
|
5
|
+
"max_total_steps": 5,
|
|
6
|
+
"timeout_ms": 120000
|
|
7
|
+
},
|
|
8
|
+
"steps": {
|
|
9
|
+
"respond": {
|
|
10
|
+
"description": "Run the Copilot-backed chat responder example",
|
|
11
|
+
"handler": {
|
|
12
|
+
"type": "ref",
|
|
13
|
+
"howToRun": "local-node",
|
|
14
|
+
"whatToRun": {
|
|
15
|
+
"kind": "fs-path",
|
|
16
|
+
"value": "./demo-chat-copilot.js"
|
|
17
|
+
},
|
|
18
|
+
"meta": "chat-handler"
|
|
19
|
+
},
|
|
20
|
+
"transitions": {
|
|
21
|
+
"success": "completed",
|
|
22
|
+
"failure": "failed"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"terminal_states": {
|
|
27
|
+
"completed": {
|
|
28
|
+
"description": "Copilot chat response completed",
|
|
29
|
+
"return_intent": "success",
|
|
30
|
+
"return_artifacts": false
|
|
31
|
+
},
|
|
32
|
+
"failed": {
|
|
33
|
+
"description": "Copilot chat response failed",
|
|
34
|
+
"return_intent": "failure",
|
|
35
|
+
"return_artifacts": false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
* demo-chat-
|
|
1
|
+
/**
|
|
2
|
+
* demo-chat-copilot.js - Copilot-backed chat handler example for example-board.
|
|
3
3
|
*
|
|
4
4
|
* Invoked by reusable-server-runtime after a user message is persisted:
|
|
5
|
-
* node demo-chat-
|
|
5
|
+
* node demo-chat-copilot.js --boardId <id> --cardId <id> --extraEncJson <base64json>
|
|
6
6
|
*
|
|
7
7
|
* extraEncJson decodes to:
|
|
8
8
|
* boardSetupRoot — absolute path to board root (parent of runtime/, surface/, runtime-out/)
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* serverUrl — base URL of hosting server (e.g. http://127.0.0.1:7799), optional
|
|
16
16
|
*
|
|
17
17
|
* Invokes copilot_wrapper.bat with a prompt built from conversation history.
|
|
18
|
-
* Session dir is per-card: os.tmpdir()/demo-chat-
|
|
18
|
+
* Session dir is per-card: os.tmpdir()/demo-chat-copilot-sessions/<boardId>_<cardId>
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import * as fs from 'node:fs';
|
|
@@ -26,9 +26,6 @@ import { fileURLToPath } from 'node:url';
|
|
|
26
26
|
|
|
27
27
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
28
|
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Args
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
29
|
const args = process.argv.slice(2);
|
|
33
30
|
function getArg(name) {
|
|
34
31
|
const idx = args.indexOf(name);
|
|
@@ -39,25 +36,53 @@ const boardId = getArg('--boardId') || '';
|
|
|
39
36
|
const cardId = getArg('--cardId') || '';
|
|
40
37
|
const extraStr = getArg('--extraEncJson') || '';
|
|
41
38
|
|
|
39
|
+
function readJsonStdin() {
|
|
40
|
+
try {
|
|
41
|
+
const raw = fs.readFileSync(0, 'utf-8').trim();
|
|
42
|
+
if (!raw) return {};
|
|
43
|
+
const parsed = JSON.parse(raw);
|
|
44
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
45
|
+
} catch {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
let extra = {};
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
if (extraStr) {
|
|
52
|
+
try { extra = JSON.parse(Buffer.from(extraStr, 'base64').toString('utf-8')); }
|
|
53
|
+
catch { console.error('[demo-chat-copilot] bad --extraEncJson'); process.exit(0); }
|
|
54
|
+
} else {
|
|
55
|
+
extra = readJsonStdin();
|
|
56
|
+
}
|
|
45
57
|
|
|
46
|
-
const {
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
const {
|
|
59
|
+
boardSetupRoot,
|
|
60
|
+
boardRuntimeDir,
|
|
61
|
+
runtimeStatusDir,
|
|
62
|
+
cardsDir,
|
|
63
|
+
chatDir,
|
|
64
|
+
chatsBlobBasePath,
|
|
65
|
+
chatsKeyPrefix,
|
|
66
|
+
chatProcessingMarkerKey,
|
|
67
|
+
lastChatFile,
|
|
68
|
+
serverUrl,
|
|
69
|
+
} = extra;
|
|
70
|
+
|
|
71
|
+
const chatDirAbs = chatDir || (
|
|
72
|
+
chatsBlobBasePath && chatsKeyPrefix
|
|
73
|
+
? path.join(String(chatsBlobBasePath), String(chatsKeyPrefix).split('/')[0])
|
|
74
|
+
: null
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!boardSetupRoot || !chatDirAbs || !lastChatFile) {
|
|
78
|
+
console.error('[demo-chat-copilot] missing boardSetupRoot/chatDir/lastChatFile');
|
|
49
79
|
process.exit(0);
|
|
50
80
|
}
|
|
51
81
|
|
|
52
|
-
// Resolve absolute paths from the structured extra fields
|
|
53
82
|
const boardRuntimeDirAbs = path.join(boardSetupRoot, boardRuntimeDir || 'runtime');
|
|
54
83
|
const runtimeStatusDirAbs = path.join(boardSetupRoot, runtimeStatusDir || 'runtime-out');
|
|
55
84
|
const cardsDirAbs = path.join(boardSetupRoot, cardsDir || path.join('surface', 'tmp-cards'));
|
|
56
|
-
const chatDirAbs = chatDir;
|
|
57
85
|
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
// Read conversation history
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
86
|
function readHistory(dir) {
|
|
62
87
|
try {
|
|
63
88
|
return fs.readdirSync(dir)
|
|
@@ -72,14 +97,11 @@ function readHistory(dir) {
|
|
|
72
97
|
} catch { return []; }
|
|
73
98
|
}
|
|
74
99
|
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
// Build prompt
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
100
|
function buildPrompt(cId, bId, history, responseFileRel) {
|
|
79
101
|
const cardSetupDirRel = path.join(cardsDir, cId).replace(/\\/g, '/');
|
|
80
102
|
const runtimeDirRel = boardRuntimeDir || 'runtime';
|
|
81
103
|
const statusDirRel = runtimeStatusDir || 'runtime-out';
|
|
82
|
-
const chatDirRel = path.relative(boardSetupRoot,
|
|
104
|
+
const chatDirRel = path.relative(boardSetupRoot, chatDirAbs).replace(/\\/g, '/');
|
|
83
105
|
const lastQueryFileRel = path.join(chatDirRel, lastChatFile).replace(/\\/g, '/');
|
|
84
106
|
|
|
85
107
|
const contextBlock = [
|
|
@@ -93,6 +115,7 @@ function buildPrompt(cId, bId, history, responseFileRel) {
|
|
|
93
115
|
'The conversation history can be found in ' + chatDirRel + ' and the last query is in ' + lastQueryFileRel + '.',
|
|
94
116
|
'Write your response to the user in ' + responseFileRel + ' (relative to your working directory).',
|
|
95
117
|
'Give me only a bare minimum log line on what you did — the response in ' + responseFileRel + ' is what the user will see.',
|
|
118
|
+
serverUrl ? 'The host server is available at ' + serverUrl + '.' : '',
|
|
96
119
|
].join(' ');
|
|
97
120
|
|
|
98
121
|
return [
|
|
@@ -103,15 +126,12 @@ function buildPrompt(cId, bId, history, responseFileRel) {
|
|
|
103
126
|
].join('\n');
|
|
104
127
|
}
|
|
105
128
|
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
// Invoke copilot_wrapper.bat
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
129
|
function runWrapper(prompt, sessionDir, workingDir) {
|
|
110
130
|
const wrapperPath = path.join(__dirname, 'scripts', 'copilot_wrapper.bat');
|
|
111
131
|
const tmpBase = os.tmpdir();
|
|
112
132
|
const ts = Date.now();
|
|
113
|
-
const outFile = path.join(tmpBase, '
|
|
114
|
-
const promptFile = path.join(tmpBase, '
|
|
133
|
+
const outFile = path.join(tmpBase, 'dcc-out-' + cardId + '-' + ts + '.txt');
|
|
134
|
+
const promptFile = path.join(tmpBase, 'dcc-prompt-' + cardId + '-' + ts + '.txt');
|
|
115
135
|
|
|
116
136
|
fs.mkdirSync(sessionDir, { recursive: true });
|
|
117
137
|
fs.writeFileSync(promptFile, prompt, 'utf-8');
|
|
@@ -124,7 +144,7 @@ function runWrapper(prompt, sessionDir, workingDir) {
|
|
|
124
144
|
workingDir,
|
|
125
145
|
'@' + promptFile,
|
|
126
146
|
'raw',
|
|
127
|
-
'demo-chat',
|
|
147
|
+
'demo-chat-copilot',
|
|
128
148
|
], { stdio: 'inherit', timeout: 120000 });
|
|
129
149
|
|
|
130
150
|
return fs.existsSync(outFile) ? fs.readFileSync(outFile, 'utf-8').trim() : '';
|
|
@@ -134,30 +154,26 @@ function runWrapper(prompt, sessionDir, workingDir) {
|
|
|
134
154
|
}
|
|
135
155
|
}
|
|
136
156
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
const nextSerial = serialMatch ? parseInt(serialMatch[1], 10) + 1 : 1;
|
|
142
|
-
const nextName = String(nextSerial).padStart(3, '0') + '-assistant.txt';
|
|
143
|
-
const responseFileRel = path.relative(boardSetupRoot, path.join(chatDir, nextName)).replace(/\\/g, '/');
|
|
157
|
+
const serialMatch = String(lastChatFile).match(/^(\d+)/);
|
|
158
|
+
const nextSerial = serialMatch ? parseInt(serialMatch[1], 10) + 1 : 1;
|
|
159
|
+
const nextName = String(nextSerial).padStart(3, '0') + '-assistant.txt';
|
|
160
|
+
const responseFileRel = path.relative(boardSetupRoot, path.join(chatDirAbs, nextName)).replace(/\\/g, '/');
|
|
144
161
|
|
|
145
162
|
const history = readHistory(chatDirAbs);
|
|
146
|
-
const sessionDir = path.join(os.tmpdir(), 'demo-chat-
|
|
163
|
+
const sessionDir = path.join(os.tmpdir(), 'demo-chat-copilot-sessions', boardId + '_' + cardId);
|
|
147
164
|
const workingDir = boardSetupRoot;
|
|
148
165
|
const prompt = buildPrompt(cardId, boardId, history, responseFileRel);
|
|
149
166
|
|
|
150
167
|
try {
|
|
151
168
|
runWrapper(prompt, sessionDir, workingDir);
|
|
152
|
-
console.log('[demo-chat-
|
|
169
|
+
console.log('[demo-chat-copilot] cardId="' + cardId + '" copilot invoked, response expected at ' + responseFileRel);
|
|
153
170
|
} catch (err) {
|
|
154
|
-
console.error('[demo-chat-
|
|
171
|
+
console.error('[demo-chat-copilot] wrapper failed: ' + (err?.message ?? err));
|
|
155
172
|
} finally {
|
|
156
173
|
cleanupProcessingMarker();
|
|
157
174
|
}
|
|
175
|
+
|
|
158
176
|
function cleanupProcessingMarker() {
|
|
159
|
-
// Prefer artifacts-style marker key from extra payload so runtime/handler contract
|
|
160
|
-
// does not rely on passing an absolute file path argument.
|
|
161
177
|
if (chatProcessingMarkerKey) {
|
|
162
178
|
try {
|
|
163
179
|
const markerPath = path.join(cardsDirAbs, chatProcessingMarkerKey);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "demo-chat-echo",
|
|
3
|
+
"settings": {
|
|
4
|
+
"start_step": "respond",
|
|
5
|
+
"max_total_steps": 5,
|
|
6
|
+
"timeout_ms": 10000
|
|
7
|
+
},
|
|
8
|
+
"steps": {
|
|
9
|
+
"respond": {
|
|
10
|
+
"description": "Echo the latest chat message back into the card chat log",
|
|
11
|
+
"handler": {
|
|
12
|
+
"type": "ref",
|
|
13
|
+
"howToRun": "local-node",
|
|
14
|
+
"whatToRun": {
|
|
15
|
+
"kind": "fs-path",
|
|
16
|
+
"value": "./demo-chat-echo.js"
|
|
17
|
+
},
|
|
18
|
+
"meta": "chat-handler"
|
|
19
|
+
},
|
|
20
|
+
"transitions": {
|
|
21
|
+
"success": "completed",
|
|
22
|
+
"failure": "failed"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"terminal_states": {
|
|
27
|
+
"completed": {
|
|
28
|
+
"description": "Echo chat response written",
|
|
29
|
+
"return_intent": "success",
|
|
30
|
+
"return_artifacts": false
|
|
31
|
+
},
|
|
32
|
+
"failed": {
|
|
33
|
+
"description": "Echo chat response failed",
|
|
34
|
+
"return_intent": "failure",
|
|
35
|
+
"return_artifacts": false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {
|
|
6
|
+
createArtifactsStore,
|
|
7
|
+
createChatArtifactsStore,
|
|
8
|
+
createFsBoardPlatformAdapter,
|
|
9
|
+
parseRef,
|
|
10
|
+
serializeRef,
|
|
11
|
+
} from 'yaml-flow/board-live-cards-node';
|
|
12
|
+
|
|
13
|
+
function readJsonStdin() {
|
|
14
|
+
try {
|
|
15
|
+
const raw = fs.readFileSync(0, 'utf-8').trim();
|
|
16
|
+
if (!raw) return {};
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveChatDir(extra) {
|
|
25
|
+
if (typeof extra.chatDir === 'string' && extra.chatDir.trim()) return extra.chatDir;
|
|
26
|
+
if (typeof extra.chatsBlobBasePath === 'string' && typeof extra.chatsKeyPrefix === 'string') {
|
|
27
|
+
const cardPart = String(extra.chatsKeyPrefix).split('/')[0];
|
|
28
|
+
return path.join(extra.chatsBlobBasePath, cardPart);
|
|
29
|
+
}
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolveChatStoreContext(extra, chatDir) {
|
|
34
|
+
if (typeof extra.chatsBlobBasePath === 'string' && typeof extra.chatsKeyPrefix === 'string') {
|
|
35
|
+
return {
|
|
36
|
+
chatsRoot: extra.chatsBlobBasePath,
|
|
37
|
+
cardPrefix: String(extra.chatsKeyPrefix).split('/')[0],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (chatDir) {
|
|
41
|
+
return {
|
|
42
|
+
chatsRoot: path.dirname(chatDir),
|
|
43
|
+
cardPrefix: path.basename(chatDir),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return { chatsRoot: '', cardPrefix: '' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const extra = readJsonStdin();
|
|
50
|
+
const chatDir = resolveChatDir(extra);
|
|
51
|
+
const { chatsRoot, cardPrefix } = resolveChatStoreContext(extra, chatDir);
|
|
52
|
+
const lastChatFile = typeof extra.lastChatFile === 'string' ? extra.lastChatFile : '';
|
|
53
|
+
|
|
54
|
+
if (!chatDir || !lastChatFile || !chatsRoot || !cardPrefix) {
|
|
55
|
+
console.log(JSON.stringify({ result: 'failure', data: {}, error: 'missing chatDir/lastChatFile' }));
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const lastChatPath = path.join(chatDir, lastChatFile);
|
|
60
|
+
let userText = '';
|
|
61
|
+
try {
|
|
62
|
+
userText = fs.readFileSync(lastChatPath, 'utf-8').trim();
|
|
63
|
+
} catch {
|
|
64
|
+
console.log(JSON.stringify({ result: 'failure', data: {}, error: 'could not read last chat file' }));
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const replyText = `Echo: ${userText}`;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const baseRef = parseRef(serializeRef({ kind: 'fs-path', value: chatsRoot }));
|
|
72
|
+
const adapter = createFsBoardPlatformAdapter(baseRef, { suppressSpawn: true });
|
|
73
|
+
const artifacts = createArtifactsStore(adapter.blobStorage(''));
|
|
74
|
+
const chats = createChatArtifactsStore(artifacts, { indexFileName: '.index.json' });
|
|
75
|
+
const serial = chats.nextSerial(cardPrefix);
|
|
76
|
+
const storedName = `${String(serial).padStart(3, '0')}_assistant.txt`;
|
|
77
|
+
|
|
78
|
+
artifacts.putText(`${cardPrefix}/${storedName}`, replyText + '\n', 'text/plain; charset=utf-8');
|
|
79
|
+
chats.appendIndexRecord(cardPrefix, {
|
|
80
|
+
serial,
|
|
81
|
+
role: 'assistant',
|
|
82
|
+
stored_name: storedName,
|
|
83
|
+
path: `${cardPrefix}/chats/${storedName}`,
|
|
84
|
+
updated_at: new Date().toISOString(),
|
|
85
|
+
});
|
|
86
|
+
if (typeof extra.chatProcessingMarkerKey === 'string' && extra.chatProcessingMarkerKey.trim()) {
|
|
87
|
+
artifacts.remove(extra.chatProcessingMarkerKey.trim());
|
|
88
|
+
}
|
|
89
|
+
console.log(JSON.stringify({ result: 'success', data: { replyFile: storedName, replyText } }));
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.log(JSON.stringify({ result: 'failure', data: {}, error: err instanceof Error ? err.message : String(err) }));
|
|
92
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"port": 7799,
|
|
3
|
+
"cardsDir": "./cards",
|
|
4
|
+
"taskExecutorPath": "./demo-task-executor.js",
|
|
5
|
+
"chatHandlerFlowPath": "./demo-chat-copilot.flow.json",
|
|
6
|
+
"chatSessionsDir": "",
|
|
7
|
+
"gandalfCardsDir": "./gandalf-cards",
|
|
8
|
+
"gandalfTaskExecutorPath": "./demo-task-executor.js",
|
|
9
|
+
"gandalfChatHandlerFlowPath": "./demo-chat-copilot.flow.json"
|
|
10
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"port": 7799,
|
|
3
3
|
"cardsDir": "./cards",
|
|
4
4
|
"taskExecutorPath": "./demo-task-executor.js",
|
|
5
|
-
"
|
|
5
|
+
"chatHandlerFlowPath": "./demo-chat-echo.flow.json",
|
|
6
6
|
"chatSessionsDir": "",
|
|
7
7
|
"gandalfCardsDir": "./gandalf-cards",
|
|
8
8
|
"gandalfTaskExecutorPath": "./demo-task-executor.js",
|
|
9
|
-
"
|
|
9
|
+
"gandalfChatHandlerFlowPath": "./demo-chat-echo.flow.json"
|
|
10
10
|
}
|