@vpxa/aikit 0.1.51 → 0.1.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/aikit",
3
- "version": "0.1.51",
3
+ "version": "0.1.52",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@ interface FlowManifest {
39
39
  install: string[];
40
40
  }
41
41
  /** Source type for flow installation */
42
- type FlowSourceType = 'builtin' | 'git' | 'local';
42
+ type FlowSourceType = 'builtin' | 'git' | 'local' | 'npm-global';
43
43
  /** Detected format of the flow source */
44
44
  type FlowFormat = 'native' | 'claude-plugin' | 'copilot' | 'openspec';
45
45
  /** Registry entry for an installed flow */
@@ -1 +1 @@
1
- import{getToolMeta as e}from"../tool-metadata.js";import{existsSync as t}from"node:fs";import{basename as n,join as r,resolve as i}from"node:path";import{homedir as a}from"node:os";import{z as o}from"zod";import{readFile as s}from"node:fs/promises";import{createLogger as c,getGlobalDataDir as l,serializeError as u}from"../../../core/dist/index.js";const d=c(`flow-tools`);function f(e){return{content:[{type:`text`,text:e}]}}function p(e){return e instanceof Error?e.message:String(e)}function m(c,m){function h(){return m.sources?.[0]?.path??process.cwd()}function g(){return r(l(),`flows`,`registry.json`)}function _(){return r(m.stateDir??r(h(),`.aikit-state`),`flows`,`state.json`)}function v(e,r){let o=r?.installPath?n(r.installPath):e.replaceAll(`:`,`-`),s=i(a(),`.copilot`,`flows`,o).replaceAll(`\\`,`/`);if(t(s))return s;let c=i(a(),`.claude`,`flows`,o).replaceAll(`\\`,`/`);if(t(c))return c;let l=i(h(),`.github`,`flows`,o).replaceAll(`\\`,`/`);return t(l)?l:r?.installPath&&t(r.installPath)?r.installPath.replaceAll(`\\`,`/`):null}function y(e,t){let n=v(e.name,e);return n?i(n,t).replaceAll(`\\`,`/`):t}async function b(){let{FlowRegistryManager:e,FlowStateMachine:t,FlowLoader:n,GitInstaller:i}=await import(`../../../flows/dist/index.js`),a=r(m.stateDir??r(h(),`.aikit-state`),`flows`,`installed`);return{registry:new e(g()),stateMachine:new t(_()),loader:new n,installer:new i(a)}}let x=e(`flow_list`);c.registerTool(`flow_list`,{title:x.title,description:`List all installed flows and their steps`,annotations:x.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t,installer:n}=await b(),r=e.list(),i=t.getStatus(),a={flows:r.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let r=n.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:r.success&&r.data?r.data.hasUpdates:void 0}}return t}),activeFlow:i.success&&i.data?{flow:i.data.flow,status:i.data.status,currentStep:i.data.currentStep}:null};return f(JSON.stringify(a,null,2))}catch(e){return d.error(`flow_list failed`,u(e)),f(`Error: ${p(e)}`)}});let S=e(`flow_info`);c.registerTool(`flow_info`,{title:S.title,description:`Show detailed information about a specific flow`,annotations:S.annotations,inputSchema:{name:o.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t,installer:n}=await b(),r=t.get(e);if(!r)return f(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=r.commitSha??null,a;if(r.sourceType===`git`&&r.installPath){let e=n.hasUpdates(r.installPath);a=e.success&&e.data?e.data.hasUpdates:void 0}let o={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:i,updateAvailable:a,installPath:v(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:y(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return f(JSON.stringify(o,null,2))}catch(e){return d.error(`flow_info failed`,u(e)),f(`Error: ${p(e)}`)}});let C=e(`flow_start`);c.registerTool(`flow_start`,{title:C.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:C.annotations,inputSchema:{flow:o.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await b(),r=t.get(e);if(!r)return f(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=n.start(r.name,r.manifest);if(!i.success||!i.data)return f(`Cannot start: ${i.error}`);let a=i.data,o=r.manifest.steps.find(e=>e.id===a.currentStep),s={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepInstruction:r&&o?y(r,o.instruction):null,currentStepDescription:o?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return f(JSON.stringify(s,null,2))}catch(e){return d.error(`flow_start failed`,u(e)),f(`Error: ${p(e)}`)}});let w=e(`flow_step`);c.registerTool(`flow_step`,{title:w.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:w.annotations,inputSchema:{action:o.enum([`next`,`skip`,`redo`]).describe(`next: mark current step done and advance. skip: skip current step. redo: repeat current step.`)}},async({action:e})=>{try{let{registry:t,stateMachine:n}=await b(),r=n.load();if(!r)return f(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return f(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return f(`Cannot ${e}: ${a.error}`);let o=a.data,s=o.currentStep?i.manifest.steps.find(e=>e.id===o.currentStep):null,c={flow:o.flow,status:o.status,action:e,currentStep:o.currentStep,currentStepInstruction:i&&s?y(i,s.instruction):null,currentStepDescription:s?.description??null,completedSteps:o.completedSteps,skippedSteps:o.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!o.completedSteps.includes(e.id)&&!o.skippedSteps.includes(e.id)&&e.id!==o.currentStep).map(e=>e.id)};return f(JSON.stringify(c,null,2))}catch(e){return d.error(`flow_step failed`,u(e)),f(`Error: ${p(e)}`)}});let T=e(`flow_status`);c.registerTool(`flow_status`,{title:T.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:T.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await b(),n=t.getStatus();if(!n.success||!n.data)return f(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let r=n.data,i=e.get(r.flow),a=i?.manifest.steps.find(e=>e.id===r.currentStep),o=i&&a?y(i,a.instruction):null,s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepInstruction:o,instructionPath:o,currentStepDescription:a?.description??null,completedSteps:r.completedSteps,skippedSteps:r.skippedSteps,artifacts:r.artifacts,startedAt:r.startedAt,updatedAt:r.updatedAt,totalSteps:i?.manifest.steps.length??0,progress:i?`${r.completedSteps.length+r.skippedSteps.length}/${i.manifest.steps.length}`:`unknown`};return f(JSON.stringify(s,null,2))}catch(e){return d.error(`flow_status failed`,u(e)),f(`Error: ${p(e)}`)}});let E=e(`flow_read_instruction`);c.registerTool(`flow_read_instruction`,{title:E.title===`flow_read_instruction`?`Flow Read Instruction`:E.title,description:`Read the instruction content for a flow step. If step is omitted, reads the current step.`,annotations:E.title===`flow_read_instruction`?{readOnlyHint:!0,idempotentHint:!0}:E.annotations,inputSchema:{step:o.string().optional().describe(`Step id or name to read. Defaults to the current step.`)}},async({step:e})=>{try{let{registry:t,stateMachine:n}=await b(),r=n.getStatus();if(!r.success||!r.data)return f(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let i=r.data,a=t.get(i.flow);if(!a)return f(`Flow "${i.flow}" not found in registry.`);let o=e??i.currentStep;if(!o)return f(`No current step is available for the active flow.`);let c=a.manifest.steps.find(e=>e.id===o||e.name===o);return f(c?await s(y(a,c.instruction),`utf-8`):`Step "${o}" not found in flow "${i.flow}".`)}catch(e){return d.error(`flow_read_instruction failed`,u(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?f(`Could not read instruction file: ${e.message}`):f(`Error: ${p(e)}`)}});let D=e(`flow_reset`);c.registerTool(`flow_reset`,{title:D.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:D.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await b(),t=e.reset();return t.success?f(`Flow state reset. Use flow_start to begin a new flow.`):f(`Reset failed: ${t.error}`)}catch(e){return d.error(`flow_reset failed`,u(e)),f(`Error: ${p(e)}`)}});let O=e(`flow_add`);c.registerTool(`flow_add`,{title:O.title,description:`Install a new development flow from a git repository URL or local directory path. Use when the user wants to add, install, import, or onboard a new workflow — for example: "use this as a flow", "add this flow", "add this flow URL", "install a flow", or "onboard a flow". Accepts git URLs (https://..., git@...) and local filesystem paths.`,annotations:O.annotations,inputSchema:{source:o.string().describe(`Git repository URL (https://... or git@...) or absolute/local directory path containing a flow definition.`),name:o.string().optional().describe(`Optional override for the installed flow name. If omitted, the name comes from the flow manifest.`)}},async({source:e,name:t})=>{try{let{registry:r,loader:a,installer:o}=await b(),s=/^https?:\/\/|^git@/.test(e),c;if(s){let t=o.clone(e);if(!t.success||!t.data)return f(`Failed to clone flow: ${t.error}`);c=t.data}else{let r=i(e),a=t||n(r)||`custom-flow`,s=o.copyLocal(r,a);if(!s.success||!s.data)return f(`Failed to copy flow: ${s.error}`);c=s.data}let l=await a.load(c);if(!l.success||!l.data)return o.remove(c),f(`Failed to load flow manifest: ${l.error}`);let{manifest:u,format:d}=l.data,p=t||u.name;if(r.has(p))return o.remove(c),f(`Flow "${p}" is already installed. Use flow_update to update it, or flow_remove then flow_add to replace.`);if(u.install.length>0){let e=o.runInstallDeps(u.install);if(!e.success)return o.remove(c),f(`Dependency install failed: ${e.error}`)}let m=new Date().toISOString(),h=s?o.getLocalCommit(c):void 0,g=r.register({name:p,version:u.version,source:e,sourceType:s?`git`:`local`,installPath:c,format:d,registeredAt:m,updatedAt:m,manifest:u,...h?{commitSha:h}:{}});if(!g.success)return o.remove(c),f(`Failed to register flow: ${g.error}`);let _=u.steps.length;return f(`Flow "${p}" installed successfully (${_} steps). Use flow_start({ flow: "${p}" }) to begin.`)}catch(e){return d.error(`flow_add failed`,u(e)),f(`Error: ${p(e)}`)}});let k=e(`flow_remove`);c.registerTool(`flow_remove`,{title:k.title,description:`Remove an installed flow by name. Unregisters it and deletes its files when applicable. Builtin flows cannot be removed.`,annotations:k.annotations,inputSchema:{name:o.string().describe(`Name of the flow to remove.`)}},async({name:e})=>{try{let{registry:t,installer:n}=await b();if(!t.has(e))return f(`Flow "${e}" is not installed.`);let r=t.get(e);if(!r)return f(`Flow "${e}" is not installed.`);if(r.sourceType===`builtin`)return f(`Cannot remove builtin flow "${e}".`);let i=n.remove(r.installPath);if(!i.success)return f(`Failed to remove flow files: ${i.error}`);let a=t.unregister(e);return a.success?f(`Flow "${e}" removed successfully.`):f(`Failed to unregister flow: ${a.error}`)}catch(e){return d.error(`flow_remove failed`,u(e)),f(`Error: ${p(e)}`)}});let A=e(`flow_update`);c.registerTool(`flow_update`,{title:A.title,description:`Update an installed git-based flow to its latest version by pulling changes. Only works for flows installed from git repositories.`,annotations:A.annotations,inputSchema:{name:o.string().describe(`Name of the flow to update.`)}},async({name:e})=>{try{let{registry:t,loader:n,installer:r}=await b();if(!t.has(e))return f(`Flow "${e}" is not installed.`);let i=t.get(e);if(!i||i.sourceType!==`git`)return f(`Flow "${e}" was not installed from git — cannot update. Remove and re-add instead.`);let a=r.update(i.installPath);if(!a.success)return f(`Update failed: ${a.error}`);let o=await n.load(i.installPath,{forceAssetSync:!0}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:i.format;if(s){let e=r.getLocalCommit(i.installPath),n=t.register({...i,version:s.version,format:c,manifest:s,updatedAt:new Date().toISOString(),...e?{commitSha:e}:{}});if(!n.success)return f(`Failed to refresh flow registry entry: ${n.error}`)}let l=s?.install??i.manifest.install;if(l.length>0){let e=r.runInstallDeps(l);if(!e.success)return f(`Dependency install failed: ${e.error}`)}return f(`Flow "${e}" updated successfully.`)}catch(e){return d.error(`flow_update failed`,u(e)),f(`Error: ${p(e)}`)}})}export{m as registerFlowTools};
1
+ import{getToolMeta as e}from"../tool-metadata.js";import{existsSync as t}from"node:fs";import{basename as n,join as r,resolve as i}from"node:path";import{homedir as a}from"node:os";import{z as o}from"zod";import{readFile as s}from"node:fs/promises";import{createLogger as c,getGlobalDataDir as l,serializeError as u}from"../../../core/dist/index.js";import{execSync as d}from"node:child_process";const f=c(`flow-tools`);function p(e){return{content:[{type:`text`,text:e}]}}function m(e){return e instanceof Error?e.message:String(e)}function h(c,h){function g(){return h.sources?.[0]?.path??process.cwd()}function _(){return r(l(),`flows`,`registry.json`)}function v(){return r(h.stateDir??r(g(),`.aikit-state`),`flows`,`state.json`)}function y(e,r){let o=r?.installPath?n(r.installPath):e.replaceAll(`:`,`-`),s=i(a(),`.copilot`,`flows`,o).replaceAll(`\\`,`/`);if(t(s))return s;let c=i(a(),`.claude`,`flows`,o).replaceAll(`\\`,`/`);if(t(c))return c;let l=i(g(),`.github`,`flows`,o).replaceAll(`\\`,`/`);return t(l)?l:r?.installPath&&t(r.installPath)?r.installPath.replaceAll(`\\`,`/`):null}function b(e,t){let n=y(e.name,e);return n?i(n,t).replaceAll(`\\`,`/`):t}function x(){try{let e=r(d(`npm root -g`,{encoding:`utf-8`}).trim(),`@fission-ai`,`openspec`);if(t(e))return{path:e,sourceType:`npm-global`,isGit:!1}}catch{}return{path:`https://github.com/Fission-AI/OpenSpec.git`,sourceType:`git`,isGit:!0}}async function S(){let{FlowRegistryManager:e,FlowStateMachine:t,FlowLoader:n,GitInstaller:i}=await import(`../../../flows/dist/index.js`),a=r(h.stateDir??r(g(),`.aikit-state`),`flows`,`installed`);return{registry:new e(_()),stateMachine:new t(v()),loader:new n,installer:new i(a)}}let C=e(`flow_list`);c.registerTool(`flow_list`,{title:C.title,description:`List all installed flows and their steps`,annotations:C.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t,installer:n}=await S(),r=e.list(),i=t.getStatus(),a={flows:r.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let r=n.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:r.success&&r.data?r.data.hasUpdates:void 0}}return t}),activeFlow:i.success&&i.data?{flow:i.data.flow,status:i.data.status,currentStep:i.data.currentStep}:null};return p(JSON.stringify(a,null,2))}catch(e){return f.error(`flow_list failed`,u(e)),p(`Error: ${m(e)}`)}});let w=e(`flow_info`);c.registerTool(`flow_info`,{title:w.title,description:`Show detailed information about a specific flow`,annotations:w.annotations,inputSchema:{name:o.string().describe(`Flow name to get info for`)}},async({name:e})=>{try{let{registry:t,installer:n}=await S(),r=t.get(e);if(!r)return p(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=r.commitSha??null,a;if(r.sourceType===`git`&&r.installPath){let e=n.hasUpdates(r.installPath);a=e.success&&e.data?e.data.hasUpdates:void 0}let o={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:i,updateAvailable:a,installPath:y(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:b(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return p(JSON.stringify(o,null,2))}catch(e){return f.error(`flow_info failed`,u(e)),p(`Error: ${m(e)}`)}});let T=e(`flow_start`);c.registerTool(`flow_start`,{title:T.title,description:`Start a flow. Sets the active flow and positions at the first step.`,annotations:T.annotations,inputSchema:{flow:o.string().describe(`Flow name to start (use flow_list to see options)`)}},async({flow:e})=>{try{let{registry:t,stateMachine:n}=await S(),r=t.get(e);if(!r)return p(`Flow "${e}" not found. Use flow_list to see available flows.`);let i=n.start(r.name,r.manifest);if(!i.success||!i.data)return p(`Cannot start: ${i.error}`);let a=i.data,o=r.manifest.steps.find(e=>e.id===a.currentStep),s={started:!0,flow:a.flow,currentStep:a.currentStep,currentStepInstruction:r&&o?b(r,o.instruction):null,currentStepDescription:o?.description??null,totalSteps:r.manifest.steps.length,stepSequence:r.manifest.steps.map(e=>e.id),artifactsDir:r.manifest.artifacts_dir};return p(JSON.stringify(s,null,2))}catch(e){return f.error(`flow_start failed`,u(e)),p(`Error: ${m(e)}`)}});let E=e(`flow_step`);c.registerTool(`flow_step`,{title:E.title,description:`Advance the active flow: complete current step and move to next, skip current step, or redo current step.`,annotations:E.annotations,inputSchema:{action:o.enum([`next`,`skip`,`redo`]).describe(`next: mark current step done and advance. skip: skip current step. redo: repeat current step.`)}},async({action:e})=>{try{let{registry:t,stateMachine:n}=await S(),r=n.load();if(!r)return p(`No active flow. Use flow_start first.`);let i=t.get(r.flow);if(!i)return p(`Flow "${r.flow}" not found in registry.`);let a=n.step(e,i.manifest);if(!a.success||!a.data)return p(`Cannot ${e}: ${a.error}`);let o=a.data,s=o.currentStep?i.manifest.steps.find(e=>e.id===o.currentStep):null,c={flow:o.flow,status:o.status,action:e,currentStep:o.currentStep,currentStepInstruction:i&&s?b(i,s.instruction):null,currentStepDescription:s?.description??null,completedSteps:o.completedSteps,skippedSteps:o.skippedSteps,totalSteps:i.manifest.steps.length,remaining:i.manifest.steps.filter(e=>!o.completedSteps.includes(e.id)&&!o.skippedSteps.includes(e.id)&&e.id!==o.currentStep).map(e=>e.id)};return p(JSON.stringify(c,null,2))}catch(e){return f.error(`flow_step failed`,u(e)),p(`Error: ${m(e)}`)}});let D=e(`flow_status`);c.registerTool(`flow_status`,{title:D.title,description:`Show the current flow execution state — which flow is active, current step, completed steps, and artifacts.`,annotations:D.annotations,inputSchema:{}},async()=>{try{let{registry:e,stateMachine:t}=await S(),n=t.getStatus();if(!n.success||!n.data)return p(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let r=n.data,i=e.get(r.flow),a=i?.manifest.steps.find(e=>e.id===r.currentStep),o=i&&a?b(i,a.instruction):null,s={flow:r.flow,status:r.status,currentStep:r.currentStep,currentStepInstruction:o,instructionPath:o,currentStepDescription:a?.description??null,completedSteps:r.completedSteps,skippedSteps:r.skippedSteps,artifacts:r.artifacts,startedAt:r.startedAt,updatedAt:r.updatedAt,totalSteps:i?.manifest.steps.length??0,progress:i?`${r.completedSteps.length+r.skippedSteps.length}/${i.manifest.steps.length}`:`unknown`};return p(JSON.stringify(s,null,2))}catch(e){return f.error(`flow_status failed`,u(e)),p(`Error: ${m(e)}`)}});let O=e(`flow_read_instruction`);c.registerTool(`flow_read_instruction`,{title:O.title===`flow_read_instruction`?`Flow Read Instruction`:O.title,description:`Read the instruction content for a flow step. If step is omitted, reads the current step.`,annotations:O.title===`flow_read_instruction`?{readOnlyHint:!0,idempotentHint:!0}:O.annotations,inputSchema:{step:o.string().optional().describe(`Step id or name to read. Defaults to the current step.`)}},async({step:e})=>{try{let{registry:t,stateMachine:n}=await S(),r=n.getStatus();if(!r.success||!r.data)return p(`No active flow. Use flow_start to begin one, or flow_list to see available flows.`);let i=r.data,a=t.get(i.flow);if(!a)return p(`Flow "${i.flow}" not found in registry.`);let o=e??i.currentStep;if(!o)return p(`No current step is available for the active flow.`);let c=a.manifest.steps.find(e=>e.id===o||e.name===o);return p(c?await s(b(a,c.instruction),`utf-8`):`Step "${o}" not found in flow "${i.flow}".`)}catch(e){return f.error(`flow_read_instruction failed`,u(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?p(`Could not read instruction file: ${e.message}`):p(`Error: ${m(e)}`)}});let k=e(`flow_reset`);c.registerTool(`flow_reset`,{title:k.title,description:`Reset the active flow, clearing all state. Use to start over or switch to a different flow.`,annotations:k.annotations,inputSchema:{}},async()=>{try{let{stateMachine:e}=await S(),t=e.reset();return t.success?p(`Flow state reset. Use flow_start to begin a new flow.`):p(`Reset failed: ${t.error}`)}catch(e){return f.error(`flow_reset failed`,u(e)),p(`Error: ${m(e)}`)}});let A=e(`flow_add`);c.registerTool(`flow_add`,{title:A.title,description:`Install a new development flow from a git repository URL or local directory path. Use when the user wants to add, install, import, or onboard a new workflow — for example: "use this as a flow", "add this flow", "add this flow URL", "install a flow", or "onboard a flow". Accepts git URLs (https://..., git@...) and local filesystem paths. Also accepts the shorthand "openspec" to install the OpenSpec flow (auto-detects local npm global install or clones from GitHub).`,annotations:A.annotations,inputSchema:{source:o.string().describe(`Git repository URL (https://... or git@...) or absolute/local directory path containing a flow definition. Use "openspec" as a shorthand to auto-resolve the OpenSpec flow.`),name:o.string().optional().describe(`Optional override for the installed flow name. If omitted, the name comes from the flow manifest.`)}},async({source:e,name:t})=>{try{let{registry:r,loader:a,installer:o}=await S(),s=e===`openspec`||e.startsWith(`openspec:`),c,l=e;if(s){let e=x();l=e.path,c=e.sourceType}let u=/^https?:\/\/|^git@/.test(l),d;if(u){let e=o.clone(l);if(!e.success||!e.data)return p(`Failed to clone flow: ${e.error}`);d=e.data}else{let e=i(l),r=t||n(e)||`custom-flow`,a=o.copyLocal(e,r);if(!a.success||!a.data)return p(`Failed to copy flow: ${a.error}`);d=a.data}let f=await a.load(d);if(!f.success||!f.data)return o.remove(d),p(`Failed to load flow manifest: ${f.error}`);let{manifest:m,format:h}=f.data,g=t||m.name;if(r.has(g))return o.remove(d),p(`Flow "${g}" is already installed. Use flow_update to update it, or flow_remove then flow_add to replace.`);if(m.install.length>0){let e=o.runInstallDeps(m.install);if(!e.success)return o.remove(d),p(`Dependency install failed: ${e.error}`)}let _=new Date().toISOString(),v=u?o.getLocalCommit(d):void 0,y=r.register({name:g,version:m.version,source:e,sourceType:c??(u?`git`:`local`),installPath:d,format:h,registeredAt:_,updatedAt:_,manifest:m,...v?{commitSha:v}:{}});if(!y.success)return o.remove(d),p(`Failed to register flow: ${y.error}`);let b=m.steps.length;return p(`Flow "${g}" installed successfully (${b} steps). Use flow_start({ flow: "${g}" }) to begin.`)}catch(e){return f.error(`flow_add failed`,u(e)),p(`Error: ${m(e)}`)}});let j=e(`flow_remove`);c.registerTool(`flow_remove`,{title:j.title,description:`Remove an installed flow by name. Unregisters it and deletes its files when applicable. Builtin flows cannot be removed.`,annotations:j.annotations,inputSchema:{name:o.string().describe(`Name of the flow to remove.`)}},async({name:e})=>{try{let{registry:t,installer:n}=await S();if(!t.has(e))return p(`Flow "${e}" is not installed.`);let r=t.get(e);if(!r)return p(`Flow "${e}" is not installed.`);if(r.sourceType===`builtin`)return p(`Cannot remove builtin flow "${e}".`);let i=n.remove(r.installPath);if(!i.success)return p(`Failed to remove flow files: ${i.error}`);let a=t.unregister(e);return a.success?p(`Flow "${e}" removed successfully.`):p(`Failed to unregister flow: ${a.error}`)}catch(e){return f.error(`flow_remove failed`,u(e)),p(`Error: ${m(e)}`)}});let M=e(`flow_update`);c.registerTool(`flow_update`,{title:M.title,description:`Update an installed flow to its latest version. For git-based flows, pulls the latest changes. For npm-global flows (e.g. OpenSpec), runs npm update.`,annotations:M.annotations,inputSchema:{name:o.string().describe(`Name of the flow to update.`)}},async({name:e})=>{try{let{registry:t,loader:n,installer:r}=await S();if(!t.has(e))return p(`Flow "${e}" is not installed.`);let i=t.get(e);if(!i||i.sourceType!==`git`&&i.sourceType!==`npm-global`)return p(`Flow "${e}" was not installed from git or npm — cannot update. Remove and re-add instead.`);if(i.sourceType===`npm-global`){try{d(`npm update -g @fission-ai/openspec`,{encoding:`utf-8`,stdio:`pipe`})}catch(e){return p(`npm update failed: ${m(e)}`)}let r=x(),a=await n.load(r.path,{forceAssetSync:!0}),o=a.success&&a.data?a.data.manifest:null,s=a.success&&a.data?a.data.format:i.format;if(o){let e=t.register({...i,version:o.version,format:s,installPath:r.path,manifest:o,updatedAt:new Date().toISOString()});if(!e.success)return p(`Failed to refresh flow registry entry: ${e.error}`)}return p(`Flow "${e}" updated via npm successfully.`)}let a=r.update(i.installPath);if(!a.success)return p(`Update failed: ${a.error}`);let o=await n.load(i.installPath,{forceAssetSync:!0}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:i.format;if(s){let e=r.getLocalCommit(i.installPath),n=t.register({...i,version:s.version,format:c,manifest:s,updatedAt:new Date().toISOString(),...e?{commitSha:e}:{}});if(!n.success)return p(`Failed to refresh flow registry entry: ${n.error}`)}let l=s?.install??i.manifest.install;if(l.length>0){let e=r.runInstallDeps(l);if(!e.success)return p(`Dependency install failed: ${e.error}`)}return p(`Flow "${e}" updated successfully.`)}catch(e){return f.error(`flow_update failed`,u(e)),p(`Error: ${m(e)}`)}})}export{h as registerFlowTools};