infra-kit 0.3.12 → 0.3.13

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.
@@ -1,2 +1,2 @@
1
- import{f as C,i as f,j as g}from"./chunk-VISEADOF.js";import{B as u,C as b,D as y,F as k,P as x,X as v}from"./chunk-DWZSB6O6.js";import{e as w}from"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import O from"@inquirer/checkbox";import _ from"@inquirer/confirm";import j,{Separator as I}from"@inquirer/select";import{loadDev as K}from"@slip-stream-kit/config/internal";import U from"node:path";import m from"node:process";var W=e=>e.split("/")[0],A=e=>new Map(e.apps.map(r=>[r.name,r])),D=e=>e.localCapable&&e.cloudCapable,N=(e,r,t)=>D(r)?t[`${e} ${r.path}`]??(r.cloudCapable?"cloud":"local"):r.localCapable?"local":"cloud",$=(e,r,t)=>{let a=new Set,o=new Map;for(let n of e){let s=r.get(W(n));for(let c of s?.backends??[]){o.set(c.packageName,c.ownerApp);for(let l of c.routes)N(n,l,t)==="local"&&a.add(c.packageName)}}return{localPkgs:a,ownerByPkg:o}},B=(e,r)=>{let t={},a=!1;for(let o of e?.backends??[]){let n=r.has(o.packageName);for(let s of o.routes){let c=s.localCapable&&n?"local":"cloud";t[s.path]=c,c==="cloud"&&(a=!0)}}return{overrides:t,anyCloud:a}},z=(e,r)=>{let t=A(r),a=e.targets.filter(p=>p.endsWith("/ui")),o=e.targets.filter(p=>p.endsWith("/api")),{localPkgs:n,ownerByPkg:s}=$(a,t,e.sources),c={},l=!1;for(let p of a){let{overrides:d,anyCloud:i}=B(t.get(W(p)),n);i&&(l=!0),c[p]=Object.keys(d).length>0?{proxy:d}:{}}for(let p of o)c[p]??={};for(let p of n){let d=s.get(p);d!=null&&(c[`${d}/api`]??={})}return{presetDef:{apps:c,cmux:e.cmux},anyCloudRoute:l,targetKeys:Object.keys(c).sort()}},M=(e,r)=>{let t=[`--target=${e.targetKeys.join(",")}`];return r.watch&&t.push("--watch"),r.cmux&&t.push("--cmux"),{flags:t.join(" ")}};var h={output:m.stderr,clearPromptOnDone:!0},q={select:e=>g(r=>j({message:e.message,choices:e.choices,default:e.default},r),h),checkbox:e=>g(r=>O({message:e.message,choices:e.choices},r),h),confirm:e=>g(r=>_({message:e.message,default:e.default},r),h)},E=(e,r)=>{let t=new Map;for(let[a,o]of Object.entries(e)){let n={path:a,localCapable:o.from.includes("local"),cloudCapable:o.from.includes("cloud"),default:o.default},s=t.get(o.packageName);s?(s.routes.push(n),s.localCapable=s.localCapable||n.localCapable,s.cloudCapable=s.cloudCapable||n.cloudCapable):t.set(o.packageName,{packageName:o.packageName,routes:[n],localCapable:n.localCapable,cloudCapable:n.cloudCapable,ownerApp:r.get(o.packageName)})}return[...t.values()]},T=async(e,r,t)=>{try{let a=(await K(e))?.proxy?.routes;return a?E(a,t):[]}catch(a){return u.warn(`\u26A0\uFE0F Skipping ${r}: its dev config failed to load \u2014 ${a instanceof Error?a.message:String(a)}`),[]}},V=async e=>{let r=y(e),t=k(e),a=await v(),o=new Map(r.map(i=>[i.packageName,i.name])),n=new Map(r.map(i=>[i.name,i.packageName])),s=new Set(t.map(i=>i.name)),c=new Set(r.map(i=>i.name)),l=[...new Set([...c,...s])].sort(),p=await Promise.all(l.map(async i=>{let P=s.has(i);return{name:i,hasApi:c.has(i),hasUi:P,apiPackage:n.get(i),backends:P?await T(U.join(e,"apps",i,"ui"),i,o):[]}})),d=await C();return{apps:p,presets:Object.keys(a.devServersPresets??{}),environments:Object.keys(d?.envs??{}).sort()}},F=e=>{let r=[];for(let t of e.apps){if(t.hasUi){let a=t.backends.flatMap(n=>n.routes.map(s=>s.path)),o=a.length>0?`frontend \u2014 proxies ${[...a].sort().join(", ")}`:"frontend";r.push({name:`${t.name}/ui`,value:`${t.name}/ui`,description:o})}t.hasApi&&!t.hasUi&&r.push({name:`${t.name}/api`,value:`${t.name}/api`,description:"backend"})}return r},L=e=>{let r={api:e.apps.filter(o=>o.hasApi).map(o=>o.name),ui:e.apps.filter(o=>o.hasUi).map(o=>o.name)},t={},a=new Map;for(let o of e.apps){o.apiPackage!=null&&(t[o.name]=o.apiPackage);for(let n of o.backends)for(let s of n.routes)a.set(`${o.name} ${s.path}`,n.packageName)}return{discovered:r,apiPkgByApp:t,routePkg:(o,n)=>a.get(`${o} ${n}`)}},X=(e,r)=>x({__wizard__:e},L(r)).map(t=>t.message),Z="INFRA_KIT_DEV_WIZARD_CMUX",H=()=>m.env[Z]==="1",G=async(e,r,t)=>{let a=new Map(r.apps.map(n=>[n.name,n])),o={};for(let n of t){let s=a.get(n.split("/")[0]);for(let c of s?.backends??[])for(let l of c.routes){if(!l.localCapable||!l.cloudCapable)continue;let p=await e.select({message:`\u{1F500} ${n} ${l.path} \u2192 local or cloud?`,choices:[{name:"local (this machine)",value:"local"},{name:"cloud",value:"cloud"}],default:l.default??"local"});o[`${n} ${l.path}`]=p}}return o},J=(e,r,t)=>e.apps.find(a=>a.name===r)?.backends.flatMap(a=>a.routes).find(a=>a.path===t),Q=(e,r)=>{let t=[];for(let[a,o]of Object.entries(e.presetDef.apps??{})){if(!a.endsWith("/ui")||!o.proxy)continue;let n=a.split("/")[0];for(let[s,c]of Object.entries(o.proxy)){let l=J(r,n,s),p=l&&l.localCapable&&l.cloudCapable?"":" (only option)";t.push(` ${a} ${s} \u2192 ${c}${p}`)}}if(t.length!==0){u.info("Resolved routes:");for(let a of[...t].sort())u.info(a)}},R=async(e,r)=>{if(r.apps.length===0)return u.warn("No apps discovered to run."),null;let t=await e.checkbox({message:"\u{1F4E6} Which packages?",choices:F(r)});if(t.length===0)return u.warn("No packages selected."),null;let a=t.filter(i=>i.endsWith("/ui")),o=await G(e,r,a),n=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1}),s=H()?await e.confirm({message:"\u{1F9E9} Run each app in its own cmux pane?",default:!1}):!1,c={targets:t,sources:o,watch:n,cmux:s},l=z(c,r);if(l.anyCloudRoute){if(r.environments.length===0)return u.warn("\u2601\uFE0F This selection routes to a cloud environment, but no environment token is loaded."),u.warn(" Run `infra-kit env-load` to add one, then re-run the wizard."),null;c.env=await e.select({message:"\u2601\uFE0F Point cloud routes at which environment?",choices:r.environments.map(i=>({name:i,value:i}))}),m.env[w]=c.env}let p=X(l.presetDef,r);if(p.length>0){u.warn("\u26A0\uFE0F Proxy audit found issues with this selection:");for(let i of p)u.warn(` \u2022 ${i}`);return null}Q(l,r),Y(l,c);let d=l.targetKeys.filter(i=>i.endsWith("/api")).map(i=>i.split("/")[0]);return s&&d.length>0?{include:d,presetDef:l.presetDef,watch:n,cmux:!0}:(s&&u.info("\u2139\uFE0F cmux needs at least one local backend (panes are backend-only) \u2014 running in-process instead."),{presetDef:l.presetDef,watch:n,cmux:!1})},Y=(e,r)=>{f.setInteractive();let t=M(e,r);f.addOption(t.flags,!0),f.print(),u.info("\u2139\uFE0F Prefer a short name? Save this selection as a devPreset and run `infra-kit dev <name>`.")},ee=async(e,r)=>{let t=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1});return f.setInteractive(),f.addOption(r,!0),t&&f.addOption("--watch",!0),f.print(),{preset:r,watch:t,cmux:!1}},S=" manual",re=async(e,r)=>{if(r.presets.length===0)return R(e,r);let t=await e.select({message:"\u{1F680} Start from a preset, or configure manually?",choices:[...r.presets.map(a=>({name:a,value:a})),new I(" "),{name:"Manual (custom)\u2026",value:S}]});return t===S?R(e,r):ee(e,t)},be=async(e=q,r=b(m.cwd()))=>re(e,await V(r));export{S as MANUAL_CHOICE,Z as WIZARD_CMUX_VAR,X as auditManualPlan,q as defaultPrompts,V as gatherWizardModel,T as loadBackends,be as runDevWizard,re as runWizardFlow};
2
- //# sourceMappingURL=dev-wizard-run-4SVW4W3I.js.map
1
+ import{f as C,i as f,j as g}from"./chunk-QLAQ7F4M.js";import{B as u,C as b,D as y,F as k,P as x,X as v}from"./chunk-SSBYKOHY.js";import{e as w}from"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import O from"@inquirer/checkbox";import _ from"@inquirer/confirm";import j,{Separator as I}from"@inquirer/select";import{loadDev as K}from"@slip-stream-kit/config/internal";import U from"node:path";import m from"node:process";var W=e=>e.split("/")[0],A=e=>new Map(e.apps.map(r=>[r.name,r])),D=e=>e.localCapable&&e.cloudCapable,N=(e,r,t)=>D(r)?t[`${e} ${r.path}`]??(r.cloudCapable?"cloud":"local"):r.localCapable?"local":"cloud",$=(e,r,t)=>{let a=new Set,o=new Map;for(let n of e){let s=r.get(W(n));for(let c of s?.backends??[]){o.set(c.packageName,c.ownerApp);for(let l of c.routes)N(n,l,t)==="local"&&a.add(c.packageName)}}return{localPkgs:a,ownerByPkg:o}},B=(e,r)=>{let t={},a=!1;for(let o of e?.backends??[]){let n=r.has(o.packageName);for(let s of o.routes){let c=s.localCapable&&n?"local":"cloud";t[s.path]=c,c==="cloud"&&(a=!0)}}return{overrides:t,anyCloud:a}},z=(e,r)=>{let t=A(r),a=e.targets.filter(p=>p.endsWith("/ui")),o=e.targets.filter(p=>p.endsWith("/api")),{localPkgs:n,ownerByPkg:s}=$(a,t,e.sources),c={},l=!1;for(let p of a){let{overrides:d,anyCloud:i}=B(t.get(W(p)),n);i&&(l=!0),c[p]=Object.keys(d).length>0?{proxy:d}:{}}for(let p of o)c[p]??={};for(let p of n){let d=s.get(p);d!=null&&(c[`${d}/api`]??={})}return{presetDef:{apps:c,cmux:e.cmux},anyCloudRoute:l,targetKeys:Object.keys(c).sort()}},M=(e,r)=>{let t=[`--target=${e.targetKeys.join(",")}`];return r.watch&&t.push("--watch"),r.cmux&&t.push("--cmux"),{flags:t.join(" ")}};var h={output:m.stderr,clearPromptOnDone:!0},q={select:e=>g(r=>j({message:e.message,choices:e.choices,default:e.default},r),h),checkbox:e=>g(r=>O({message:e.message,choices:e.choices},r),h),confirm:e=>g(r=>_({message:e.message,default:e.default},r),h)},E=(e,r)=>{let t=new Map;for(let[a,o]of Object.entries(e)){let n={path:a,localCapable:o.from.includes("local"),cloudCapable:o.from.includes("cloud"),default:o.default},s=t.get(o.packageName);s?(s.routes.push(n),s.localCapable=s.localCapable||n.localCapable,s.cloudCapable=s.cloudCapable||n.cloudCapable):t.set(o.packageName,{packageName:o.packageName,routes:[n],localCapable:n.localCapable,cloudCapable:n.cloudCapable,ownerApp:r.get(o.packageName)})}return[...t.values()]},T=async(e,r,t)=>{try{let a=(await K(e))?.proxy?.routes;return a?E(a,t):[]}catch(a){return u.warn(`\u26A0\uFE0F Skipping ${r}: its dev config failed to load \u2014 ${a instanceof Error?a.message:String(a)}`),[]}},V=async e=>{let r=y(e),t=k(e),a=await v(),o=new Map(r.map(i=>[i.packageName,i.name])),n=new Map(r.map(i=>[i.name,i.packageName])),s=new Set(t.map(i=>i.name)),c=new Set(r.map(i=>i.name)),l=[...new Set([...c,...s])].sort(),p=await Promise.all(l.map(async i=>{let P=s.has(i);return{name:i,hasApi:c.has(i),hasUi:P,apiPackage:n.get(i),backends:P?await T(U.join(e,"apps",i,"ui"),i,o):[]}})),d=await C();return{apps:p,presets:Object.keys(a.devServersPresets??{}),environments:Object.keys(d?.envs??{}).sort()}},F=e=>{let r=[];for(let t of e.apps){if(t.hasUi){let a=t.backends.flatMap(n=>n.routes.map(s=>s.path)),o=a.length>0?`frontend \u2014 proxies ${[...a].sort().join(", ")}`:"frontend";r.push({name:`${t.name}/ui`,value:`${t.name}/ui`,description:o})}t.hasApi&&!t.hasUi&&r.push({name:`${t.name}/api`,value:`${t.name}/api`,description:"backend"})}return r},L=e=>{let r={api:e.apps.filter(o=>o.hasApi).map(o=>o.name),ui:e.apps.filter(o=>o.hasUi).map(o=>o.name)},t={},a=new Map;for(let o of e.apps){o.apiPackage!=null&&(t[o.name]=o.apiPackage);for(let n of o.backends)for(let s of n.routes)a.set(`${o.name} ${s.path}`,n.packageName)}return{discovered:r,apiPkgByApp:t,routePkg:(o,n)=>a.get(`${o} ${n}`)}},X=(e,r)=>x({__wizard__:e},L(r)).map(t=>t.message),Z="INFRA_KIT_DEV_WIZARD_CMUX",H=()=>m.env[Z]==="1",G=async(e,r,t)=>{let a=new Map(r.apps.map(n=>[n.name,n])),o={};for(let n of t){let s=a.get(n.split("/")[0]);for(let c of s?.backends??[])for(let l of c.routes){if(!l.localCapable||!l.cloudCapable)continue;let p=await e.select({message:`\u{1F500} ${n} ${l.path} \u2192 local or cloud?`,choices:[{name:"local (this machine)",value:"local"},{name:"cloud",value:"cloud"}],default:l.default??"local"});o[`${n} ${l.path}`]=p}}return o},J=(e,r,t)=>e.apps.find(a=>a.name===r)?.backends.flatMap(a=>a.routes).find(a=>a.path===t),Q=(e,r)=>{let t=[];for(let[a,o]of Object.entries(e.presetDef.apps??{})){if(!a.endsWith("/ui")||!o.proxy)continue;let n=a.split("/")[0];for(let[s,c]of Object.entries(o.proxy)){let l=J(r,n,s),p=l&&l.localCapable&&l.cloudCapable?"":" (only option)";t.push(` ${a} ${s} \u2192 ${c}${p}`)}}if(t.length!==0){u.info("Resolved routes:");for(let a of[...t].sort())u.info(a)}},R=async(e,r)=>{if(r.apps.length===0)return u.warn("No apps discovered to run."),null;let t=await e.checkbox({message:"\u{1F4E6} Which packages?",choices:F(r)});if(t.length===0)return u.warn("No packages selected."),null;let a=t.filter(i=>i.endsWith("/ui")),o=await G(e,r,a),n=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1}),s=H()?await e.confirm({message:"\u{1F9E9} Run each app in its own cmux pane?",default:!1}):!1,c={targets:t,sources:o,watch:n,cmux:s},l=z(c,r);if(l.anyCloudRoute){if(r.environments.length===0)return u.warn("\u2601\uFE0F This selection routes to a cloud environment, but no environment token is loaded."),u.warn(" Run `infra-kit env-load` to add one, then re-run the wizard."),null;c.env=await e.select({message:"\u2601\uFE0F Point cloud routes at which environment?",choices:r.environments.map(i=>({name:i,value:i}))}),m.env[w]=c.env}let p=X(l.presetDef,r);if(p.length>0){u.warn("\u26A0\uFE0F Proxy audit found issues with this selection:");for(let i of p)u.warn(` \u2022 ${i}`);return null}Q(l,r),Y(l,c);let d=l.targetKeys.filter(i=>i.endsWith("/api")).map(i=>i.split("/")[0]);return s&&d.length>0?{include:d,presetDef:l.presetDef,watch:n,cmux:!0}:(s&&u.info("\u2139\uFE0F cmux needs at least one local backend (panes are backend-only) \u2014 running in-process instead."),{presetDef:l.presetDef,watch:n,cmux:!1})},Y=(e,r)=>{f.setInteractive();let t=M(e,r);f.addOption(t.flags,!0),f.print(),u.info("\u2139\uFE0F Prefer a short name? Save this selection as a devPreset and run `infra-kit dev <name>`.")},ee=async(e,r)=>{let t=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1});return f.setInteractive(),f.addOption(r,!0),t&&f.addOption("--watch",!0),f.print(),{preset:r,watch:t,cmux:!1}},S=" manual",re=async(e,r)=>{if(r.presets.length===0)return R(e,r);let t=await e.select({message:"\u{1F680} Start from a preset, or configure manually?",choices:[...r.presets.map(a=>({name:a,value:a})),new I(" "),{name:"Manual (custom)\u2026",value:S}]});return t===S?R(e,r):ee(e,t)},be=async(e=q,r=b(m.cwd()))=>re(e,await V(r));export{S as MANUAL_CHOICE,Z as WIZARD_CMUX_VAR,X as auditManualPlan,q as defaultPrompts,V as gatherWizardModel,T as loadBackends,be as runDevWizard,re as runWizardFlow};
2
+ //# sourceMappingURL=dev-wizard-run-XM5L23UP.js.map
package/dist/mcp.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a as d,aa as h,d as p,da as S,r as y}from"./chunk-M5FC2MOJ.js";import"./chunk-ADCSGQAU.js";import{a as v}from"./chunk-LJVPQQ75.js";import"./chunk-LKKKDB6V.js";import{i as x}from"./chunk-VISEADOF.js";import{A as l,B as c,X as g,c as u,z as a}from"./chunk-DWZSB6O6.js";import"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import{StdioServerTransport as O}from"@modelcontextprotocol/sdk/server/stdio.js";import E from"node:process";import n from"node:process";var C=e=>{n.on("SIGINT",()=>{e.info({msg:"Received SIGINT. Shutting down..."}),n.exit(0)}),n.on("SIGTERM",()=>{e.info({msg:"Received SIGTERM. Shutting down..."}),n.exit(0)}),n.on("uncaughtException",r=>{e.fatal({err:r,msg:"Uncaught Exception"}),e.error(`Uncaught Exception! Check ${a}. Shutting down...`),e.flush(),n.exit(1)}),n.on("unhandledRejection",(r,o)=>{e.fatal({reason:r,promise:o,msg:"Unhandled Rejection"}),e.error(`Unhandled Rejection! Check ${a}. Shutting down...`),e.flush(),n.exit(1)})};import{McpServer as H}from"@modelcontextprotocol/sdk/server/mcp.js";var T=async e=>{};var j="infra-kit://config",M="infra-kit://dev-context",b={loadConfig:g,readDevContext:()=>p()},m=(e,r)=>({contents:[{uri:e,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}),R=async(e,r=b)=>{e.registerResource("infra-kit-config",j,{title:"infra-kit config",description:"The merged infra-kit.json configuration (all override layers applied). Read-only.",mimeType:"application/json"},async o=>{try{return m(o.toString(),await r.loadConfig())}catch(t){return m(o.toString(),{error:t instanceof Error?t.message:String(t)})}}),e.registerResource("infra-kit-dev-context",M,{title:"infra-kit dev context",description:"What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.",mimeType:"application/json"},o=>m(o.toString(),r.readDevContext()))};var D=e=>typeof e=="object"&&e!==null&&e.confirm===!0,I=(e,r)=>{let o=typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).filter(([s])=>s!=="confirm")):{},t={status:"confirmation_required",tool:e,resolvedArgs:o,message:`${e} mutates external state and is gated. It was NOT executed. Re-call ${e} with the same arguments plus "confirm": true to execute.`};return{content:d(JSON.stringify(t,null,2)),structuredContent:t,isError:!0}},f=({toolName:e,handler:r,requiresHumanConfirm:o})=>async t=>{c.info({msg:`Tool execution started: ${e}`,params:t});try{if(await y(),x.reset(),o===!0&&!D(t))return c.info({msg:`Tool execution gated (awaiting confirm): ${e}`}),I(e,t);let s=await r({...t,confirmedCommand:!0});return c.info({msg:`Tool execution successful: ${e}`}),s}catch(s){throw c.error({err:s,params:t,msg:`Tool execution failed: ${e}`}),s}};var w=async e=>{for(let r of h())e.registerTool(r.name,{description:r.description,inputSchema:r.inputSchema,outputSchema:r.outputSchema},f({toolName:r.name,handler:r.handler,requiresHumanConfirm:r.requiresHumanConfirm}))};async function k(){u.enabled=!0;let e=new H({name:"infra-kit",version:v.version},{capabilities:{resources:{listChanged:!0},tools:{},prompts:{}}});return await T(e),await R(e),await w(e),e}S();var i=l(),P=async()=>{let e;try{e=await k(),i.info("MCP Server instance created")}catch(r){i.error({err:r,msg:"Failed to create MCP server"}),i.error("Fatal error during server creation."),E.exit(1)}try{let r=new O;await e.connect(r),i.info({msg:"Server connected to transport. Ready."})}catch(r){i.error({err:r,msg:"Failed to initialize server"}),i.error("Fatal error during server transport init."),E.exit(1)}};C(i);P();
1
+ import{a as d,aa as h,d as p,da as S,r as y}from"./chunk-LMAO6FEM.js";import"./chunk-SHFPI4QA.js";import{a as v}from"./chunk-DPCWCXJD.js";import"./chunk-LKKKDB6V.js";import{i as x}from"./chunk-QLAQ7F4M.js";import{A as l,B as c,X as g,c as u,z as a}from"./chunk-SSBYKOHY.js";import"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import{StdioServerTransport as O}from"@modelcontextprotocol/sdk/server/stdio.js";import E from"node:process";import n from"node:process";var C=e=>{n.on("SIGINT",()=>{e.info({msg:"Received SIGINT. Shutting down..."}),n.exit(0)}),n.on("SIGTERM",()=>{e.info({msg:"Received SIGTERM. Shutting down..."}),n.exit(0)}),n.on("uncaughtException",r=>{e.fatal({err:r,msg:"Uncaught Exception"}),e.error(`Uncaught Exception! Check ${a}. Shutting down...`),e.flush(),n.exit(1)}),n.on("unhandledRejection",(r,o)=>{e.fatal({reason:r,promise:o,msg:"Unhandled Rejection"}),e.error(`Unhandled Rejection! Check ${a}. Shutting down...`),e.flush(),n.exit(1)})};import{McpServer as H}from"@modelcontextprotocol/sdk/server/mcp.js";var T=async e=>{};var j="infra-kit://config",M="infra-kit://dev-context",b={loadConfig:g,readDevContext:()=>p()},m=(e,r)=>({contents:[{uri:e,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}),R=async(e,r=b)=>{e.registerResource("infra-kit-config",j,{title:"infra-kit config",description:"The merged infra-kit.json configuration (all override layers applied). Read-only.",mimeType:"application/json"},async o=>{try{return m(o.toString(),await r.loadConfig())}catch(t){return m(o.toString(),{error:t instanceof Error?t.message:String(t)})}}),e.registerResource("infra-kit-dev-context",M,{title:"infra-kit dev context",description:"What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.",mimeType:"application/json"},o=>m(o.toString(),r.readDevContext()))};var D=e=>typeof e=="object"&&e!==null&&e.confirm===!0,I=(e,r)=>{let o=typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).filter(([s])=>s!=="confirm")):{},t={status:"confirmation_required",tool:e,resolvedArgs:o,message:`${e} mutates external state and is gated. It was NOT executed. Re-call ${e} with the same arguments plus "confirm": true to execute.`};return{content:d(JSON.stringify(t,null,2)),structuredContent:t,isError:!0}},f=({toolName:e,handler:r,requiresHumanConfirm:o})=>async t=>{c.info({msg:`Tool execution started: ${e}`,params:t});try{if(await y(),x.reset(),o===!0&&!D(t))return c.info({msg:`Tool execution gated (awaiting confirm): ${e}`}),I(e,t);let s=await r({...t,confirmedCommand:!0});return c.info({msg:`Tool execution successful: ${e}`}),s}catch(s){throw c.error({err:s,params:t,msg:`Tool execution failed: ${e}`}),s}};var w=async e=>{for(let r of h())e.registerTool(r.name,{description:r.description,inputSchema:r.inputSchema,outputSchema:r.outputSchema},f({toolName:r.name,handler:r.handler,requiresHumanConfirm:r.requiresHumanConfirm}))};async function k(){u.enabled=!0;let e=new H({name:"infra-kit",version:v.version},{capabilities:{resources:{listChanged:!0},tools:{},prompts:{}}});return await T(e),await R(e),await w(e),e}S();var i=l(),P=async()=>{let e;try{e=await k(),i.info("MCP Server instance created")}catch(r){i.error({err:r,msg:"Failed to create MCP server"}),i.error("Fatal error during server creation."),E.exit(1)}try{let r=new O;await e.connect(r),i.info({msg:"Server connected to transport. Ready."})}catch(r){i.error({err:r,msg:"Failed to initialize server"}),i.error("Fatal error during server transport init."),E.exit(1)}};C(i);P();
2
2
  //# sourceMappingURL=mcp.js.map
package/dist/mcp.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/entry/mcp.ts", "../src/lib/error-handlers/index.ts", "../src/mcp/server.ts", "../src/mcp/prompts/index.ts", "../src/mcp/resources/index.ts", "../src/lib/tool-handler/tool-handler.ts", "../src/mcp/tools/index.ts"],
4
- "sourcesContent": ["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport process from 'node:process'\n\nimport { setupErrorHandlers } from 'src/lib/error-handlers'\nimport { initLoggerMcp } from 'src/lib/logger'\nimport { suppressTypelessPackageJsonWarning } from 'src/lib/node-warnings'\n\nimport { createMcpServer } from '../mcp/server'\n\n// The MCP tools run the same commands as the CLI, so they hit the same consumer `.ts` configs.\n// This keeps the client's log pane clean; it cannot affect protocol framing either way, since\n// the stdio transport frames JSON-RPC on stdout and `emitWarning` only ever writes to stderr.\nsuppressTypelessPackageJsonWarning()\n\nconst logger = initLoggerMcp()\n\nconst startServer = async () => {\n let server\n\n try {\n server = await createMcpServer()\n\n logger.info('MCP Server instance created')\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to create MCP server' })\n logger.error(`Fatal error during server creation.`)\n\n process.exit(1)\n }\n\n try {\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n logger.info({ msg: 'Server connected to transport. Ready.' })\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to initialize server' })\n logger.error(`Fatal error during server transport init.`)\n\n process.exit(1)\n }\n}\n\n// Setup error handlers\nsetupErrorHandlers(logger)\n\n// Start the server\nstartServer()\n", "import process from 'node:process'\nimport type { Logger } from 'pino'\n\nimport { LOG_FILE_PATH } from '../logger/index'\n\n/**\n * Setup error handlers for the application\n * @param logger - The logger instance\n *\n * ONLY FOR SERVER!\n */\nexport const setupErrorHandlers = (logger: Logger) => {\n process.on('SIGINT', () => {\n logger.info({ msg: 'Received SIGINT. Shutting down...' })\n process.exit(0)\n })\n\n process.on('SIGTERM', () => {\n logger.info({ msg: 'Received SIGTERM. Shutting down...' })\n process.exit(0)\n })\n\n process.on('uncaughtException', (error) => {\n logger.fatal({ err: error, msg: 'Uncaught Exception' })\n logger.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason, promise) => {\n logger.fatal({ reason, promise, msg: 'Unhandled Rejection' })\n logger.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n}\n", "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { mcpMode } from 'src/lib/mcp-mode'\n\nimport packageJson from '../../package.json' with { type: 'json' }\nimport { initializePrompts } from './prompts'\nimport { initializeResources } from './resources'\nimport { initializeTools } from './tools'\n\nexport async function createMcpServer() {\n // Marks `process.stdin` as the JSON-RPC transport for every prompt guard in the\n // process. Set HERE rather than in `entry/mcp.ts` (the sole caller) because that\n // module starts a server at import time and so can never be unit-tested \u2014 a test\n // there could only stub the flag, which proves nothing about it ever being set.\n // This runs before `server.connect`, so no tool handler can outrun it.\n mcpMode.enabled = true\n\n const server = new McpServer(\n {\n name: 'infra-kit',\n version: packageJson.version,\n },\n {\n capabilities: {\n // `initializeResources` registers read-only resources below; the SDK's\n // `registerResource` also declares `resources.listChanged` on top of this.\n resources: { listChanged: true },\n tools: {},\n prompts: {},\n },\n },\n )\n\n await initializePrompts(server)\n await initializeResources(server)\n await initializeTools(server)\n\n return server\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nexport const initializePrompts = async (_server: McpServer) => {}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport type { InfraKitConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\n\nimport type { DevContextSnapshot } from './dev-context'\nimport { readDevContext } from './dev-context'\n\n/** Stable URI of the merged-config resource. */\nexport const CONFIG_RESOURCE_URI = 'infra-kit://config'\n\n/** Stable URI of the dev-context resource. */\nexport const DEV_CONTEXT_RESOURCE_URI = 'infra-kit://dev-context'\n\n/**\n * The two disk reads the resources need, injected so the registration is unit-testable without touching\n * the filesystem or the config-loader's mtime cache. Production uses the real readers by default.\n */\nexport interface ResourceDeps {\n /** Loads the merged `infra-kit.json` (all override layers applied). May throw when no config exists. */\n loadConfig: () => Promise<InfraKitConfig>\n /** Reads the dev-context fragments `infra-kit dev` last wrote. Never throws; absent session \u21D2 empty. */\n readDevContext: () => DevContextSnapshot\n}\n\nconst defaultDeps: ResourceDeps = {\n loadConfig: getInfraKitConfig,\n readDevContext: () => {\n return readDevContext()\n },\n}\n\n/** Serialize a resource body as pretty JSON text \u2014 the wire form every MCP client can read. */\nconst jsonResource = (uri: string, value: unknown): { contents: { uri: string; mimeType: string; text: string }[] } => {\n return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(value, null, 2) }] }\n}\n\n/**\n * Register infra-kit's READ-ONLY MCP resources so an agent can inspect the repo's config and dev state\n * without calling a tool (or mutating anything):\n *\n * - `infra-kit://config` \u2014 the merged `infra-kit.json` an agent would run against.\n * - `infra-kit://dev-context` \u2014 what `infra-kit dev` last wrote (backends up, ports, freshness); an\n * absent dev session resolves to an empty `session: 'none'` payload, NOT\n * an error.\n *\n * Both handlers are side-effect free and swallow their reader's failure into an `{ error }` payload rather\n * than throwing, so a bad on-disk config can never crash the long-lived MCP server.\n */\nexport const initializeResources = async (server: McpServer, deps: ResourceDeps = defaultDeps) => {\n server.registerResource(\n 'infra-kit-config',\n CONFIG_RESOURCE_URI,\n {\n title: 'infra-kit config',\n description: 'The merged infra-kit.json configuration (all override layers applied). Read-only.',\n mimeType: 'application/json',\n },\n async (uri) => {\n try {\n return jsonResource(uri.toString(), await deps.loadConfig())\n } catch (error) {\n return jsonResource(uri.toString(), { error: error instanceof Error ? error.message : String(error) })\n }\n },\n )\n\n server.registerResource(\n 'infra-kit-dev-context',\n DEV_CONTEXT_RESOURCE_URI,\n {\n title: 'infra-kit dev context',\n description:\n 'What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment ' +\n 'freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.',\n mimeType: 'application/json',\n },\n // The SDK's `ReadResourceCallback` accepts a synchronous return; the disk read is sync, so no `async`.\n (uri) => {\n return jsonResource(uri.toString(), deps.readDevContext())\n },\n )\n}\n", "import { commandEcho } from 'src/lib/command-echo'\nimport { ensureUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { logger } from 'src/lib/logger'\nimport { textContent } from 'src/types'\nimport type { ToolsExecutionResult } from 'src/types'\n\ninterface ToolHandlerArgs {\n toolName: string\n handler: (params: any) => Promise<ToolsExecutionResult>\n /**\n * When true, this tool is gated by the destructive-op confirm gate below. Sourced from the\n * catalog tool's {@link CatalogMcpTool.requiresHumanConfirm} at registration (`mcp/tools/index.ts`).\n */\n requiresHumanConfirm?: boolean\n}\n\n/** True when the incoming MCP params carry an explicit `confirm:true` (the call-2 execute signal). */\nconst isConfirmed = (params: unknown): boolean => {\n return typeof params === 'object' && params !== null && (params as { confirm?: unknown }).confirm === true\n}\n\n/**\n * The call-1 gate response for a `requiresHumanConfirm` tool: it names the tool and echoes the\n * resolved args (minus the `confirm` flag itself) and tells the caller to re-invoke with\n * `confirm:true`. Crucially it sets `isError: true` \u2014 the MCP SDK validates a result's\n * `structuredContent` against the tool's `outputSchema` UNLESS `isError` is set (server/mcp.js\n * `validateToolOutput`), and every gated tool declares an outputSchema the gate payload does not\n * match, so without `isError` the real server would throw an output-validation error instead of\n * returning the gate. This is a soft stop, not a failure: the tool did NOT run.\n */\nconst buildConfirmGate = (toolName: string, params: unknown): ToolsExecutionResult => {\n const resolvedArgs =\n typeof params === 'object' && params !== null\n ? Object.fromEntries(\n Object.entries(params as Record<string, unknown>).filter(([key]) => {\n return key !== 'confirm'\n }),\n )\n : {}\n\n const structuredContent = {\n status: 'confirmation_required' as const,\n tool: toolName,\n resolvedArgs,\n message: `${toolName} mutates external state and is gated. It was NOT executed. Re-call ${toolName} with the same arguments plus \"confirm\": true to execute.`,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n isError: true,\n }\n}\n\nexport const createToolHandler = ({\n toolName,\n handler,\n requiresHumanConfirm,\n}: ToolHandlerArgs): ((params: unknown) => Promise<ToolsExecutionResult>) => {\n return async (params: unknown) => {\n logger.info({ msg: `Tool execution started: ${toolName}`, params })\n try {\n // MCP entry-boundary seed. This wrapper is the sole chokepoint for every exposed tool\n // (`src/mcp/tools/index.ts` holds the only `registerTool` call), and the `mcp` command itself is\n // in program.ts's SEED_EXCLUDED \u2014 so an MCP server seeds lazily, on its FIRST tool invocation,\n // and a server that never receives one never writes to $HOME. The once-per-process guard inside\n // ensureUserProjectConfig makes calls 2..N free on this long-lived process.\n //\n // Deliberately INSIDE the try, not before it: defense-in-depth. ensureUserProjectConfig is\n // contractually never-throw, but if that contract ever broke, an unhandled rejection here would\n // take down the long-lived server. Inside the try it degrades to an ordinary tool error.\n await ensureUserProjectConfig()\n\n // The command handlers record their resolved flags into the `commandEcho` singleton. On the CLI,\n // Commander's `preAction` clears it before every command; this long-lived server never runs that\n // hook, so without a reset here one tool call's flags would leak into the next one's snapshot and\n // the options array would grow for the life of the process.\n commandEcho.reset()\n\n // Orthogonal destructive-op confirm gate. It sits BEFORE the handler and is INDEPENDENT of the\n // `confirmedCommand:true` injected below \u2014 that flag is a prompt-skip / behavior discriminator\n // (e.g. worktrees-remove keys `allowEditorRelaunch` off it) and MUST keep being injected on the\n // real call, or the non-TTY server would hang on an inquirer prompt and the Zed relaunch would\n // re-enable. When a tool is flagged and the caller has not opted in with `confirm:true`, return\n // the resolved-args gate and DO NOT run the handler; a second call carrying `confirm:true` falls\n // through and executes exactly as an unflagged tool would.\n if (requiresHumanConfirm === true && !isConfirmed(params)) {\n logger.info({ msg: `Tool execution gated (awaiting confirm): ${toolName}` })\n\n return buildConfirmGate(toolName, params)\n }\n\n const payload = await handler({ ...(params as object), confirmedCommand: true })\n\n logger.info({ msg: `Tool execution successful: ${toolName}` })\n\n return payload\n } catch (error) {\n logger.error({\n err: error,\n params,\n msg: `Tool execution failed: ${toolName}`,\n })\n\n throw error\n }\n }\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { getExposedMcpTools } from 'src/lib/command-catalog'\nimport { createToolHandler } from 'src/lib/tool-handler'\n\nexport const initializeTools = async (server: McpServer) => {\n // The registered tool set is derived from the single command catalog, filtered\n // by its explicit `mcpExposed` allowlist. doctor is intentionally excluded there\n // (host-inspecting) and must never be registered here.\n for (const tool of getExposedMcpTools()) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n },\n createToolHandler({\n toolName: tool.name,\n handler: tool.handler,\n requiresHumanConfirm: tool.requiresHumanConfirm,\n }),\n )\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport process from 'node:process'\n\nimport { setupErrorHandlers } from 'src/lib/error-handlers'\nimport { initLoggerMcp } from 'src/lib/logger'\nimport { suppressTypelessPackageJsonWarning } from 'src/lib/node-warnings'\n\nimport { createMcpServer } from '../mcp/server'\n\n// The MCP tools run the same commands as the CLI, so they hit the same consumer `.ts` configs.\n// This keeps the client's log pane clean; it cannot affect protocol framing either way, since\n// the stdio transport frames JSON-RPC on stdout and `emitWarning` only ever writes to stderr.\nsuppressTypelessPackageJsonWarning()\n\nconst logger = initLoggerMcp()\n\nconst startServer = async () => {\n let server\n\n try {\n server = await createMcpServer()\n\n logger.info('MCP Server instance created')\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to create MCP server' })\n logger.error(`Fatal error during server creation.`)\n\n process.exit(1)\n }\n\n try {\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n logger.info({ msg: 'Server connected to transport. Ready.' })\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to initialize server' })\n logger.error(`Fatal error during server transport init.`)\n\n process.exit(1)\n }\n}\n\n// Setup error handlers\nsetupErrorHandlers(logger)\n\n// Start the server\nstartServer()\n", "import process from 'node:process'\nimport type { Logger } from 'pino'\n\nimport { LOG_FILE_PATH } from '../logger/index'\n\n/**\n * Setup error handlers for the application\n *\n * @param logger - The logger instance\n *\n * ONLY FOR SERVER!\n */\nexport const setupErrorHandlers = (logger: Logger) => {\n process.on('SIGINT', () => {\n logger.info({ msg: 'Received SIGINT. Shutting down...' })\n process.exit(0)\n })\n\n process.on('SIGTERM', () => {\n logger.info({ msg: 'Received SIGTERM. Shutting down...' })\n process.exit(0)\n })\n\n process.on('uncaughtException', (error) => {\n logger.fatal({ err: error, msg: 'Uncaught Exception' })\n logger.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason, promise) => {\n logger.fatal({ reason, promise, msg: 'Unhandled Rejection' })\n logger.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n}\n", "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { mcpMode } from 'src/lib/mcp-mode'\n\nimport packageJson from '../../package.json' with { type: 'json' }\nimport { initializePrompts } from './prompts'\nimport { initializeResources } from './resources'\nimport { initializeTools } from './tools'\n\nexport async function createMcpServer() {\n // Marks `process.stdin` as the JSON-RPC transport for every prompt guard in the\n // process. Set HERE rather than in `entry/mcp.ts` (the sole caller) because that\n // module starts a server at import time and so can never be unit-tested \u2014 a test\n // there could only stub the flag, which proves nothing about it ever being set.\n // This runs before `server.connect`, so no tool handler can outrun it.\n mcpMode.enabled = true\n\n const server = new McpServer(\n {\n name: 'infra-kit',\n version: packageJson.version,\n },\n {\n capabilities: {\n // `initializeResources` registers read-only resources below; the SDK's\n // `registerResource` also declares `resources.listChanged` on top of this.\n resources: { listChanged: true },\n tools: {},\n prompts: {},\n },\n },\n )\n\n await initializePrompts(server)\n await initializeResources(server)\n await initializeTools(server)\n\n return server\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nexport const initializePrompts = async (_server: McpServer) => {}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport type { InfraKitConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\n\nimport type { DevContextSnapshot } from './dev-context'\nimport { readDevContext } from './dev-context'\n\n/** Stable URI of the merged-config resource. */\nexport const CONFIG_RESOURCE_URI = 'infra-kit://config'\n\n/** Stable URI of the dev-context resource. */\nexport const DEV_CONTEXT_RESOURCE_URI = 'infra-kit://dev-context'\n\n/**\n * The two disk reads the resources need, injected so the registration is unit-testable without touching\n * the filesystem or the config-loader's mtime cache. Production uses the real readers by default.\n */\nexport interface ResourceDeps {\n /** Loads the merged `infra-kit.json` (all override layers applied). May throw when no config exists. */\n loadConfig: () => Promise<InfraKitConfig>\n /** Reads the dev-context fragments `infra-kit dev` last wrote. Never throws; absent session \u21D2 empty. */\n readDevContext: () => DevContextSnapshot\n}\n\nconst defaultDeps: ResourceDeps = {\n loadConfig: getInfraKitConfig,\n readDevContext: () => {\n return readDevContext()\n },\n}\n\n/** Serialize a resource body as pretty JSON text \u2014 the wire form every MCP client can read. */\nconst jsonResource = (uri: string, value: unknown): { contents: { uri: string; mimeType: string; text: string }[] } => {\n return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(value, null, 2) }] }\n}\n\n/**\n * Register infra-kit's READ-ONLY MCP resources so an agent can inspect the repo's config and dev state\n * without calling a tool (or mutating anything):\n *\n * - `infra-kit://config` \u2014 the merged `infra-kit.json` an agent would run against.\n * - `infra-kit://dev-context` \u2014 what `infra-kit dev` last wrote (backends up, ports, freshness); an\n * absent dev session resolves to an empty `session: 'none'` payload, NOT\n * an error.\n *\n * Both handlers are side-effect free and swallow their reader's failure into an `{ error }` payload rather\n * than throwing, so a bad on-disk config can never crash the long-lived MCP server.\n */\nexport const initializeResources = async (server: McpServer, deps: ResourceDeps = defaultDeps) => {\n server.registerResource(\n 'infra-kit-config',\n CONFIG_RESOURCE_URI,\n {\n title: 'infra-kit config',\n description: 'The merged infra-kit.json configuration (all override layers applied). Read-only.',\n mimeType: 'application/json',\n },\n async (uri) => {\n try {\n return jsonResource(uri.toString(), await deps.loadConfig())\n } catch (error) {\n return jsonResource(uri.toString(), { error: error instanceof Error ? error.message : String(error) })\n }\n },\n )\n\n server.registerResource(\n 'infra-kit-dev-context',\n DEV_CONTEXT_RESOURCE_URI,\n {\n title: 'infra-kit dev context',\n description:\n 'What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment ' +\n 'freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.',\n mimeType: 'application/json',\n },\n // The SDK's `ReadResourceCallback` accepts a synchronous return; the disk read is sync, so no `async`.\n (uri) => {\n return jsonResource(uri.toString(), deps.readDevContext())\n },\n )\n}\n", "import { commandEcho } from 'src/lib/command-echo'\nimport { ensureUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { logger } from 'src/lib/logger'\nimport { textContent } from 'src/types'\nimport type { ToolsExecutionResult } from 'src/types'\n\ninterface ToolHandlerArgs {\n toolName: string\n handler: (params: any) => Promise<ToolsExecutionResult>\n /**\n * When true, this tool is gated by the destructive-op confirm gate below. Sourced from the\n * catalog tool's {@link CatalogMcpTool.requiresHumanConfirm} at registration (`mcp/tools/index.ts`).\n */\n requiresHumanConfirm?: boolean\n}\n\n/** True when the incoming MCP params carry an explicit `confirm:true` (the call-2 execute signal). */\nconst isConfirmed = (params: unknown): boolean => {\n return typeof params === 'object' && params !== null && (params as { confirm?: unknown }).confirm === true\n}\n\n/**\n * The call-1 gate response for a `requiresHumanConfirm` tool: it names the tool and echoes the\n * resolved args (minus the `confirm` flag itself) and tells the caller to re-invoke with\n * `confirm:true`. Crucially it sets `isError: true` \u2014 the MCP SDK validates a result's\n * `structuredContent` against the tool's `outputSchema` UNLESS `isError` is set (server/mcp.js\n * `validateToolOutput`), and every gated tool declares an outputSchema the gate payload does not\n * match, so without `isError` the real server would throw an output-validation error instead of\n * returning the gate. This is a soft stop, not a failure: the tool did NOT run.\n */\nconst buildConfirmGate = (toolName: string, params: unknown): ToolsExecutionResult => {\n const resolvedArgs =\n typeof params === 'object' && params !== null\n ? Object.fromEntries(\n Object.entries(params as Record<string, unknown>).filter(([key]) => {\n return key !== 'confirm'\n }),\n )\n : {}\n\n const structuredContent = {\n status: 'confirmation_required' as const,\n tool: toolName,\n resolvedArgs,\n message: `${toolName} mutates external state and is gated. It was NOT executed. Re-call ${toolName} with the same arguments plus \"confirm\": true to execute.`,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n isError: true,\n }\n}\n\nexport const createToolHandler = ({\n toolName,\n handler,\n requiresHumanConfirm,\n}: ToolHandlerArgs): ((params: unknown) => Promise<ToolsExecutionResult>) => {\n return async (params: unknown) => {\n logger.info({ msg: `Tool execution started: ${toolName}`, params })\n try {\n // MCP entry-boundary seed. This wrapper is the sole chokepoint for every exposed tool\n // (`src/mcp/tools/index.ts` holds the only `registerTool` call), and the `mcp` command itself is\n // in program.ts's SEED_EXCLUDED \u2014 so an MCP server seeds lazily, on its FIRST tool invocation,\n // and a server that never receives one never writes to $HOME. The once-per-process guard inside\n // ensureUserProjectConfig makes calls 2..N free on this long-lived process.\n //\n // Deliberately INSIDE the try, not before it: defense-in-depth. ensureUserProjectConfig is\n // contractually never-throw, but if that contract ever broke, an unhandled rejection here would\n // take down the long-lived server. Inside the try it degrades to an ordinary tool error.\n await ensureUserProjectConfig()\n\n // The command handlers record their resolved flags into the `commandEcho` singleton. On the CLI,\n // Commander's `preAction` clears it before every command; this long-lived server never runs that\n // hook, so without a reset here one tool call's flags would leak into the next one's snapshot and\n // the options array would grow for the life of the process.\n commandEcho.reset()\n\n // Orthogonal destructive-op confirm gate. It sits BEFORE the handler and is INDEPENDENT of the\n // `confirmedCommand:true` injected below \u2014 that flag is a prompt-skip / behavior discriminator\n // (e.g. worktrees-remove keys `allowEditorRelaunch` off it) and MUST keep being injected on the\n // real call, or the non-TTY server would hang on an inquirer prompt and the Zed relaunch would\n // re-enable. When a tool is flagged and the caller has not opted in with `confirm:true`, return\n // the resolved-args gate and DO NOT run the handler; a second call carrying `confirm:true` falls\n // through and executes exactly as an unflagged tool would.\n if (requiresHumanConfirm === true && !isConfirmed(params)) {\n logger.info({ msg: `Tool execution gated (awaiting confirm): ${toolName}` })\n\n return buildConfirmGate(toolName, params)\n }\n\n const payload = await handler({ ...(params as object), confirmedCommand: true })\n\n logger.info({ msg: `Tool execution successful: ${toolName}` })\n\n return payload\n } catch (error) {\n logger.error({\n err: error,\n params,\n msg: `Tool execution failed: ${toolName}`,\n })\n\n throw error\n }\n }\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { getExposedMcpTools } from 'src/lib/command-catalog'\nimport { createToolHandler } from 'src/lib/tool-handler'\n\nexport const initializeTools = async (server: McpServer) => {\n // The registered tool set is derived from the single command catalog, filtered\n // by its explicit `mcpExposed` allowlist. doctor is intentionally excluded there\n // (host-inspecting) and must never be registered here.\n for (const tool of getExposedMcpTools()) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n },\n createToolHandler({\n toolName: tool.name,\n handler: tool.handler,\n requiresHumanConfirm: tool.requiresHumanConfirm,\n }),\n )\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["StdioServerTransport", "process", "process", "setupErrorHandlers", "logger", "process", "error", "LOG_FILE_PATH", "reason", "promise", "McpServer", "initializePrompts", "_server", "CONFIG_RESOURCE_URI", "DEV_CONTEXT_RESOURCE_URI", "defaultDeps", "getInfraKitConfig", "readDevContext", "jsonResource", "uri", "value", "initializeResources", "server", "deps", "error", "isConfirmed", "params", "buildConfirmGate", "toolName", "resolvedArgs", "key", "structuredContent", "textContent", "createToolHandler", "handler", "requiresHumanConfirm", "logger", "ensureUserProjectConfig", "commandEcho", "payload", "error", "initializeTools", "server", "tool", "getExposedMcpTools", "createToolHandler", "createMcpServer", "mcpMode", "server", "McpServer", "package_default", "initializePrompts", "initializeResources", "initializeTools", "suppressTypelessPackageJsonWarning", "logger", "initLoggerMcp", "startServer", "server", "createMcpServer", "error", "process", "transport", "StdioServerTransport", "setupErrorHandlers"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{h as i}from"./chunk-2QJAIOPI.js";import{a as t}from"./chunk-LJVPQQ75.js";import"./chunk-LKKKDB6V.js";import"./chunk-CHETBZ6M.js";import a from"node:fs";import o from"node:process";import{fileURLToPath as s}from"node:url";var m=r=>{let n=r.indexOf("--parent-pid");if(n===-1)return;let e=Number(r[n+1]);return Number.isInteger(e)&&e>0?e:void 0},p=()=>a.realpathSync(s(new URL("./cli.js",import.meta.url))),d=async()=>{await i(t.version,{selfRealPath:p(),parentPid:m(o.argv)})};d().catch(()=>{o.exitCode=0});
1
+ import{h as i}from"./chunk-2QJAIOPI.js";import{a as t}from"./chunk-DPCWCXJD.js";import"./chunk-LKKKDB6V.js";import"./chunk-CHETBZ6M.js";import a from"node:fs";import o from"node:process";import{fileURLToPath as s}from"node:url";var m=r=>{let n=r.indexOf("--parent-pid");if(n===-1)return;let e=Number(r[n+1]);return Number.isInteger(e)&&e>0?e:void 0},p=()=>a.realpathSync(s(new URL("./cli.js",import.meta.url))),d=async()=>{await i(t.version,{selfRealPath:p(),parentPid:m(o.argv)})};d().catch(()=>{o.exitCode=0});
2
2
  //# sourceMappingURL=update-check.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.3.12",
4
+ "version": "0.3.13",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
@@ -42,15 +42,15 @@
42
42
  "@inquirer/password": "^5.0.2",
43
43
  "@inquirer/select": "^5.2.1",
44
44
  "@modelcontextprotocol/sdk": "^1.30.0",
45
- "@slip-stream-kit/config": "^0.3.3",
45
+ "@slip-stream-kit/config": "^0.3.13",
46
46
  "chalk": "^6.0.0",
47
47
  "chokidar": "^5.0.0",
48
48
  "commander": "^15.0.0",
49
- "fastify": "5.10.0",
49
+ "fastify": "catalog:",
50
50
  "ink": "^7.1.1",
51
51
  "pino": "^10.3.1",
52
52
  "pino-pretty": "^13.1.3",
53
- "portless": "^0.15.4",
53
+ "portless": "^0.15.5",
54
54
  "react": "19.2.8",
55
55
  "yaml": "^2.9.0",
56
56
  "zod": "^4.4.3",
@@ -61,7 +61,7 @@
61
61
  "@types/react": "19.2.17",
62
62
  "@wl/eslint-config": "workspace:*",
63
63
  "@wl/vitest-config": "workspace:*",
64
- "esbuild": "^0.28.1",
64
+ "esbuild": "^0.28.2",
65
65
  "ink-testing-library": "^4.0.0",
66
66
  "typescript": "^6.0.3"
67
67
  }