infra-kit 0.10.0 → 0.11.10

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.
Files changed (36) hide show
  1. package/dist/{chunk-WUTG6VMP.js → chunk-ATGBWGER.js} +5 -5
  2. package/dist/chunk-ATGBWGER.js.map +7 -0
  3. package/dist/chunk-GBPW4ERM.js +3 -0
  4. package/dist/chunk-GBPW4ERM.js.map +7 -0
  5. package/dist/chunk-J6BHN362.js +11 -0
  6. package/dist/chunk-J6BHN362.js.map +7 -0
  7. package/dist/chunk-KPRFMZCX.js +3 -0
  8. package/dist/chunk-KPRFMZCX.js.map +7 -0
  9. package/dist/chunk-LAHHNH3T.js +2 -0
  10. package/dist/chunk-LAHHNH3T.js.map +7 -0
  11. package/dist/{chunk-OPL7C5H6.js → chunk-SREJWU57.js} +2 -2
  12. package/dist/chunk-ZZ7HCY2S.js +4 -0
  13. package/dist/chunk-ZZ7HCY2S.js.map +7 -0
  14. package/dist/cli.js +113 -168
  15. package/dist/cli.js.map +4 -4
  16. package/dist/dev-server.js +2 -2
  17. package/dist/dev-server.js.map +2 -2
  18. package/dist/dev-wizard-run-NQM3VPQA.js +2 -0
  19. package/dist/{dev-wizard-run-ITRFKMTL.js.map → dev-wizard-run-NQM3VPQA.js.map} +1 -1
  20. package/dist/mcp-proxy.js +9 -9
  21. package/dist/mcp-proxy.js.map +2 -2
  22. package/dist/update-check.js +1 -1
  23. package/dist/update-check.js.map +1 -1
  24. package/package.json +3 -3
  25. package/readme.md +33 -31
  26. package/dist/chunk-7AMRJ4IW.js +0 -9
  27. package/dist/chunk-7AMRJ4IW.js.map +0 -7
  28. package/dist/chunk-JUNJK2YC.js +0 -3
  29. package/dist/chunk-JUNJK2YC.js.map +0 -7
  30. package/dist/chunk-MOVRKV3I.js +0 -4
  31. package/dist/chunk-MOVRKV3I.js.map +0 -7
  32. package/dist/chunk-WUTG6VMP.js.map +0 -7
  33. package/dist/chunk-YYC3QGGC.js +0 -2
  34. package/dist/chunk-YYC3QGGC.js.map +0 -7
  35. package/dist/dev-wizard-run-ITRFKMTL.js +0 -2
  36. /package/dist/{chunk-OPL7C5H6.js.map → chunk-SREJWU57.js.map} +0 -0
@@ -0,0 +1,2 @@
1
+ import{c as x,g as f,j as g}from"./chunk-ATGBWGER.js";import{N as u,_ as y,ba as k,ca as v,ea as w,oa as C}from"./chunk-J6BHN362.js";import"./chunk-MFAFQVTW.js";import"./chunk-LAHHNH3T.js";import{e as b}from"./chunk-ZZ7HCY2S.js";import"./chunk-QWVLAZ6N.js";import B 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 q 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,a)=>D(r)?a[`${e} ${r.path}`]??(r.cloudCapable?"cloud":"local"):r.localCapable?"local":"cloud",$=(e,r,a)=>{let t=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,a)==="local"&&t.add(c.packageName)}}return{localPkgs:t,ownerByPkg:o}},O=(e,r)=>{let a={},t=!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";a[s.path]=c,c==="cloud"&&(t=!0)}}return{overrides:a,anyCloud:t}},z=(e,r)=>{let a=A(r),t=e.targets.filter(p=>p.endsWith("/ui")),o=e.targets.filter(p=>p.endsWith("/api")),{localPkgs:n,ownerByPkg:s}=$(t,a,e.sources),c={},l=!1;for(let p of t){let{overrides:d,anyCloud:i}=O(a.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,orca:e.orca},anyCloudRoute:l,targetKeys:Object.keys(c).sort()}},R=(e,r)=>{let a=[`--target=${e.targetKeys.join(",")}`];return r.watch&&a.push("--watch"),r.orca&&a.push("--orca"),{flags:a.join(" ")}};var h={output:m.stderr,clearPromptOnDone:!0},E={select:e=>g(r=>j({message:e.message,choices:e.choices,default:e.default},r),{...h,whenHeadless:"refuse"}),checkbox:e=>g(r=>B({message:e.message,choices:e.choices},r),{...h,whenHeadless:"refuse"}),confirm:e=>g(r=>_({message:e.message,default:e.default},r),{...h,whenHeadless:"refuse"})},T=(e,r)=>{let a=new Map;for(let[t,o]of Object.entries(e)){let n={path:t,localCapable:o.from.includes("local"),cloudCapable:o.from.includes("cloud"),default:o.default},s=a.get(o.packageName);s?(s.routes.push(n),s.localCapable=s.localCapable||n.localCapable,s.cloudCapable=s.cloudCapable||n.cloudCapable):a.set(o.packageName,{packageName:o.packageName,routes:[n],localCapable:n.localCapable,cloudCapable:n.cloudCapable,ownerApp:r.get(o.packageName)})}return[...a.values()]},U=async(e,r,a)=>{try{let t=(await K(e))?.proxy?.routes;return t?T(t,a):[]}catch(t){return u.warn(`\u26A0\uFE0F Skipping ${r}: its dev config failed to load \u2014 ${t instanceof Error?t.message:String(t)}`),[]}},H=async e=>{let r=v(e),a=w(e),t=await y(),o=new Map(r.map(i=>[i.packageName,i.name])),n=new Map(r.map(i=>[i.name,i.packageName])),s=new Set(a.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 U(q.join(e,"apps",i,"ui"),i,o):[]}})),d=await x();return{apps:p,presets:Object.keys(t.devServersPresets??{}),environments:Object.keys(d?.envs??{}).sort()}},V=e=>{let r=[];for(let a of e.apps){if(a.hasUi){let t=a.backends.flatMap(n=>n.routes.map(s=>s.path)),o=t.length>0?`frontend \u2014 proxies ${[...t].sort().join(", ")}`:"frontend";r.push({name:`${a.name}/ui`,value:`${a.name}/ui`,description:o})}a.hasApi&&!a.hasUi&&r.push({name:`${a.name}/api`,value:`${a.name}/api`,description:"backend"})}return r},F=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)},a={},t=new Map;for(let o of e.apps){o.apiPackage!=null&&(a[o.name]=o.apiPackage);for(let n of o.backends)for(let s of n.routes)t.set(`${o.name} ${s.path}`,n.packageName)}return{discovered:r,apiPkgByApp:a,routePkg:(o,n)=>t.get(`${o} ${n}`)}},L=(e,r)=>C({__wizard__:e},F(r)).map(a=>a.message),Z="INFRA_KIT_DEV_WIZARD_ORCA",G=()=>m.env[Z]==="1",J=async(e,r,a)=>{let t=new Map(r.apps.map(n=>[n.name,n])),o={};for(let n of a){let s=t.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},Q=(e,r,a)=>e.apps.find(t=>t.name===r)?.backends.flatMap(t=>t.routes).find(t=>t.path===a),X=(e,r)=>{let a=[];for(let[t,o]of Object.entries(e.presetDef.apps??{})){if(!t.endsWith("/ui")||!o.proxy)continue;let n=t.split("/")[0];for(let[s,c]of Object.entries(o.proxy)){let l=Q(r,n,s),p=l&&l.localCapable&&l.cloudCapable?"":" (only option)";a.push(` ${t} ${s} \u2192 ${c}${p}`)}}if(a.length!==0){u.info("Resolved routes:");for(let t of[...a].sort())u.info(t)}},M=async(e,r)=>{if(r.apps.length===0)return u.warn("No apps discovered to run."),null;let a=await e.checkbox({message:"\u{1F4E6} Which packages?",choices:V(r)});if(a.length===0)return u.warn("No packages selected."),null;let t=a.filter(i=>i.endsWith("/ui")),o=await J(e,r,t),n=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1}),s=G()?await e.confirm({message:"\u{1F9E9} Run each app in its own Orca pane?",default:!1}):!1,c={targets:a,sources:o,watch:n,orca: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[b]=c.env}let p=L(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}X(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,orca:!0}:(s&&u.info("\u2139\uFE0F Orca needs at least one local backend (panes are backend-only) \u2014 running in-process instead."),{presetDef:l.presetDef,watch:n,orca:!1})},Y=(e,r)=>{f.setInteractive();let a=R(e,r);f.addOption(a.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 a=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1});return f.setInteractive(),f.addOption(r,!0),a&&f.addOption("--watch",!0),f.print(),{preset:r,watch:a,orca:!1}},S=" manual",re=async(e,r)=>{if(r.presets.length===0)return M(e,r);let a=await e.select({message:"\u{1F680} Start from a preset, or configure manually?",choices:[...r.presets.map(t=>({name:t,value:t})),new I(" "),{name:"Manual (custom)\u2026",value:S}]});return a===S?M(e,r):ee(e,a)},be=async(e=E,r=k(m.cwd()))=>re(e,await H(r));export{S as MANUAL_CHOICE,Z as WIZARD_ORCA_VAR,L as auditManualPlan,E as defaultPrompts,H as gatherWizardModel,U as loadBackends,be as runDevWizard,re as runWizardFlow};
2
+ //# sourceMappingURL=dev-wizard-run-NQM3VPQA.js.map
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/dev/dev-wizard-run.ts", "../src/dev/dev-wizard.ts"],
4
4
  "sourcesContent": ["/**\n * Impure driver for the interactive `infra-kit dev` wizard: filesystem/config discovery, the inquirer\n * prompt flow (step-0 preset-or-manual, then the manual matrix), the pre-flight proxy audit, and the\n * `commandEcho` teaching line. The pure answer\u2192plan mapping lives in {@link file://./dev-wizard.ts}.\n *\n * Prompts are behind the injectable {@link WizardPrompts} seam so the flow is testable without a TTY.\n * This module is reached ONLY from the bare-invocation TTY branch of the entry point; every flagged /\n * non-TTY / `--json` / `--agent` invocation bypasses it entirely.\n */\nimport inquirerCheckbox from '@inquirer/checkbox'\nimport inquirerConfirm from '@inquirer/confirm'\nimport inquirerSelect, { Separator } from '@inquirer/select'\nimport { loadDev } from '@slip-stream-kit/config/internal'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { discoverApiApps, discoverUiApps, findMonorepoRoot } from 'src/dev/discovery'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { INFRA_KIT_ENV_VAR } from 'src/lib/constants'\nimport { readTokenStore } from 'src/lib/env-tokens'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport type { DevPreset, ProxySource } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { withEscape } from 'src/lib/prompts/escapable-context'\n\nimport { deriveManualPlan, equivalentCommand } from './dev-wizard.js'\nimport type { DerivedPlan, ManualSelection, ProxyBackend, RouteCap, WizardApp, WizardModel } from './dev-wizard.js'\nimport { validatePresetProxy } from './presets.js'\nimport type { DiscoveredParts, PresetProxyContext } from './presets.js'\n\n/** A wizard prompt choice \u2014 all values are strings, so the seam needs no generics. */\nexport interface WizardChoice {\n name: string\n value: string\n description?: string\n checked?: boolean\n disabled?: boolean | string\n}\n\n/**\n * Injectable prompt seam (a string-valued subset of `@inquirer/*`). The default implementation\n * ({@link defaultPrompts}) delegates to the real prompts, rendering to stderr so the dev-server's\n * stdout stays clean. Tests pass a scripted object.\n */\nexport interface WizardPrompts {\n select: (cfg: { message: string; choices: (WizardChoice | Separator)[]; default?: string }) => Promise<string>\n checkbox: (cfg: { message: string; choices: WizardChoice[] }) => Promise<string[]>\n confirm: (cfg: { message: string; default?: boolean }) => Promise<boolean>\n}\n\n/**\n * Shared `@inquirer/*` context. Rendered to stderr (mirrors the bare-`infra-kit` command palette).\n *\n * `clearPromptOnDone` erases each answered prompt instead of leaving a `\u2714 <question> <answer>` line\n * behind, so the wizard collapses to nothing once it finishes and the dev-server's ready header lands\n * at the top of a clean screen. The choices are not lost: {@link echoManual} / {@link runPresetBranch}\n * print the equivalent flag command, which is the durable record of what was picked.\n */\nconst promptContext = { output: process.stderr, clearPromptOnDone: true }\n\n/**\n * Real `@inquirer/*` prompts, rendered to stderr and erased once answered.\n *\n * Every one goes through {@link withEscape}, which binds Esc to cancellation. The wrap is here rather\n * than around the {@link WizardPrompts} seam so the scripted prompts the tests inject stay untouched:\n * the seam is the test boundary, `defaultPrompts` is the only implementation that talks to a terminal.\n *\n * Esc rejects with an `AbortPromptError`, which `entry/cli.ts` catches as a cancellation \u2192 exit 0. The\n * wizard therefore needs no cancel branch of its own: a cancelled prompt never returns here at all, so\n * no server is started.\n */\nexport const defaultPrompts: WizardPrompts = {\n select: (cfg) => {\n // The wizard is TTY-only by construction (`shouldRunWizard`); the declaration is for the sweep,\n // which roots `entry/dev-server.ts` and reads the policy off the literal.\n return withEscape(\n (context) => {\n return inquirerSelect({ message: cfg.message, choices: cfg.choices, default: cfg.default }, context)\n },\n { ...promptContext, whenHeadless: 'refuse' },\n )\n },\n checkbox: (cfg) => {\n return withEscape(\n (context) => {\n return inquirerCheckbox({ message: cfg.message, choices: cfg.choices }, context)\n },\n { ...promptContext, whenHeadless: 'refuse' },\n )\n },\n confirm: (cfg) => {\n return withEscape(\n (context) => {\n return inquirerConfirm({ message: cfg.message, default: cfg.default }, context)\n },\n { ...promptContext, whenHeadless: 'refuse' },\n )\n },\n}\n\n/** What the wizard hands back to the entry point (merged into `DevServerOptions`), or null on cancel. */\nexport interface WizardResult {\n /** Named preset (preset branch) \u2014 passed through as `options.preset`. */\n preset?: string\n /** In-memory preset (manual branch, non-Orca) \u2014 passed through as `options.presetDef`. */\n presetDef?: DevPreset\n /**\n * App-name include list for the Orca path only: which discovered API apps get a pane. Paired with\n * `presetDef`, which tells each pane the exact parts to run. An app selected UI-only gets no pane\n * (Orca panes are opened per API app). Unset for the non-Orca manual path.\n */\n include?: string[]\n watch: boolean\n orca: boolean\n}\n\n/** Group one frontend's `dev.proxy.routes` into {@link ProxyBackend}s keyed by backend package. */\nconst groupBackends = (\n routes: Record<string, { packageName: string; from: readonly string[]; default?: 'local' | 'cloud' }>,\n ownerByPkg: Map<string, string>,\n): ProxyBackend[] => {\n const byPkg = new Map<string, ProxyBackend>()\n\n for (const [route, def] of Object.entries(routes)) {\n const cap: RouteCap = {\n path: route,\n localCapable: def.from.includes('local'),\n cloudCapable: def.from.includes('cloud'),\n default: def.default,\n }\n const existing = byPkg.get(def.packageName)\n\n if (existing) {\n existing.routes.push(cap)\n existing.localCapable = existing.localCapable || cap.localCapable\n existing.cloudCapable = existing.cloudCapable || cap.cloudCapable\n } else {\n byPkg.set(def.packageName, {\n packageName: def.packageName,\n routes: [cap],\n localCapable: cap.localCapable,\n cloudCapable: cap.cloudCapable,\n ownerApp: ownerByPkg.get(def.packageName),\n })\n }\n }\n\n return [...byPkg.values()]\n}\n\n/**\n * Load one frontend's proxy routes and group them into backends. A config that throws \u2014 schema-invalid\n * or an import-time error \u2014 degrades THAT app to zero backends with a named warning instead of rejecting.\n * Without this, a single broken `apps/<x>/ui/infra-kit.config.ts` fails the whole `Promise.all` in\n * {@link gatherWizardModel} and takes the entire wizard down, so `infra-kit dev` becomes unusable for every\n * other app in the monorepo. Mirrors the audit path's per-app guard ({@link file://../commands/audit/preset-proxy-check.ts}).\n */\nexport const loadBackends = async (\n uiDir: string,\n name: string,\n ownerByPkg: Map<string, string>,\n): Promise<ProxyBackend[]> => {\n try {\n const routes = (await loadDev(uiDir))?.proxy?.routes\n\n return routes ? groupBackends(routes, ownerByPkg) : []\n } catch (error) {\n logger.warn(\n `\u26A0\uFE0F Skipping ${name}: its dev config failed to load \u2014 ${error instanceof Error ? error.message : String(error)}`,\n )\n\n return []\n }\n}\n\n/** Discover apps + configs and assemble the {@link WizardModel} (backends resolved per frontend). */\nexport const gatherWizardModel = async (root: string): Promise<WizardModel> => {\n const apiApps = discoverApiApps(root)\n const uiApps = discoverUiApps(root)\n const config = await getInfraKitConfig()\n\n const ownerByPkg = new Map(\n apiApps.map((a) => {\n return [a.packageName, a.name] as const\n }),\n )\n const apiPkgByName = new Map(\n apiApps.map((a) => {\n return [a.name, a.packageName] as const\n }),\n )\n const uiNames = new Set(\n uiApps.map((a) => {\n return a.name\n }),\n )\n const apiNames = new Set(\n apiApps.map((a) => {\n return a.name\n }),\n )\n const allNames = [...new Set([...apiNames, ...uiNames])].sort()\n\n const apps: WizardApp[] = await Promise.all(\n allNames.map(async (name): Promise<WizardApp> => {\n const hasUi = uiNames.has(name)\n\n return {\n name,\n hasApi: apiNames.has(name),\n hasUi,\n apiPackage: apiPkgByName.get(name),\n backends: hasUi ? await loadBackends(path.join(root, 'apps', name, 'ui'), name, ownerByPkg) : [],\n }\n }),\n )\n\n // The cloud-env choices are the envs we hold a token for \u2014 the same authority as `env-load`, because\n // it is the same question. This picker writes INFRA_KIT_ENV, which `@slip-stream-kit/config/vite`\n // reads to build the cloud backend's URL, and whose only other writer is `env-load` (which cannot run\n // without a Doppler token). Sourcing it from the workflow options instead would put `prod` in the list\n // for everyone \u2014 including a developer holding no prod credential \u2014 and point a local UI at\n // production. No token, no entry.\n const store = await readTokenStore()\n\n return {\n apps,\n presets: Object.keys(config.devServersPresets ?? {}),\n environments: Object.keys(store?.envs ?? {}).sort(),\n }\n}\n\n/**\n * Build the checkbox choices: one `<app>/ui` per frontend, plus `<app>/api` ONLY for api-only apps\n * (an api with no ui). A full-stack `<app>/api` is deliberately NOT offered \u2014 a full-stack backend is\n * launched by choosing `local` for one of its frontend's routes (asked per-route afterwards), so the\n * checkbox stays a pick of frontends + standalone backends.\n *\n * Nothing starts checked: the manual branch is opt-in, so a run only ever launches what was explicitly\n * ticked. Pre-checking every part would make the fast path (accept the defaults) boot the whole monorepo\n * \u2014 the exact opposite of why someone reached for \"Manual\" over a preset.\n */\nconst buildPartChoices = (model: WizardModel): WizardChoice[] => {\n const choices: WizardChoice[] = []\n\n for (const app of model.apps) {\n if (app.hasUi) {\n const paths = app.backends.flatMap((b) => {\n return b.routes.map((r) => {\n return r.path\n })\n })\n const description = paths.length > 0 ? `frontend \u2014 proxies ${[...paths].sort().join(', ')}` : 'frontend'\n\n choices.push({ name: `${app.name}/ui`, value: `${app.name}/ui`, description })\n }\n if (app.hasApi && !app.hasUi) {\n choices.push({ name: `${app.name}/api`, value: `${app.name}/api`, description: 'backend' })\n }\n }\n\n return choices\n}\n\n/** Build the audit context from the gathered model (no re-reading of configs). */\nconst buildAuditContext = (model: WizardModel): PresetProxyContext => {\n const discovered: DiscoveredParts = {\n api: model.apps\n .filter((a) => {\n return a.hasApi\n })\n .map((a) => {\n return a.name\n }),\n ui: model.apps\n .filter((a) => {\n return a.hasUi\n })\n .map((a) => {\n return a.name\n }),\n }\n const apiPkgByApp: Record<string, string> = {}\n const routeToPkg = new Map<string, string>()\n\n for (const app of model.apps) {\n // Map EVERY discovered api app to its own api package \u2014 including api-only apps a frontend proxies\n // to cross-app \u2014 so `launchedPkgs` in validatePresetProxy is faithful (mirrors preset-proxy-check.ts).\n // Deriving this from proxy backends alone would miss api-only owners and false-positive the audit.\n if (app.apiPackage != null) apiPkgByApp[app.name] = app.apiPackage\n for (const b of app.backends) {\n for (const route of b.routes) {\n routeToPkg.set(`${app.name} ${route.path}`, b.packageName)\n }\n }\n }\n\n return {\n discovered,\n apiPkgByApp,\n routePkg: (app, route) => {\n return routeToPkg.get(`${app} ${route}`)\n },\n }\n}\n\n/**\n * Run the assembled plan through the SAME proxy-locality rule the root audit uses. Returns issue\n * messages (empty when clean). Catches a `local` override whose backend won't launch \u2014 the wizard's\n * derivation launches owners, so a hit means the backend has no discoverable owning app.\n */\nexport const auditManualPlan = (presetDef: DevPreset, model: WizardModel): string[] => {\n return validatePresetProxy({ __wizard__: presetDef }, buildAuditContext(model)).map((i) => {\n return i.message\n })\n}\n\n/**\n * Opt back into the Orca question: set to exactly `'1'`. The prompt is temporarily off \u2014 the manual\n * branch always runs in-process \u2014 but the derivation below is kept whole for when it returns. `--orca`\n * on the command line is a separate path and stays live either way.\n */\nexport const WIZARD_ORCA_VAR = 'INFRA_KIT_DEV_WIZARD_ORCA'\n\nconst asksOrca = (): boolean => {\n return process.env[WIZARD_ORCA_VAR] === '1'\n}\n\n/**\n * Ask, per selected frontend, an EXPLICIT local/cloud choice for every TWO-OPTION route (its `from`\n * lists both). Single-option routes are auto-picked in the pure mapping, so they are never prompted.\n * The answers are keyed `${app}/ui ${routePath}` to match {@link ManualSelection.sources}; the select's\n * default seeds from the route's declared `default` when it has one.\n */\nconst promptRouteSources = async (\n prompts: WizardPrompts,\n model: WizardModel,\n uiKeys: string[],\n): Promise<Record<string, ProxySource>> => {\n const apps = new Map(\n model.apps.map((a) => {\n return [a.name, a] as const\n }),\n )\n const sources: Record<string, ProxySource> = {}\n\n for (const key of uiKeys) {\n const app = apps.get(key.split('/')[0]!)\n\n for (const backend of app?.backends ?? []) {\n for (const route of backend.routes) {\n if (!route.localCapable || !route.cloudCapable) continue\n\n const answer = await prompts.select({\n message: `\uD83D\uDD00 ${key} ${route.path} \u2192 local or cloud?`,\n choices: [\n { name: 'local (this machine)', value: 'local' },\n { name: 'cloud', value: 'cloud' },\n ],\n default: route.default ?? 'local',\n })\n\n sources[`${key} ${route.path}`] = answer as ProxySource\n }\n }\n }\n\n return sources\n}\n\n/** Look up a frontend route's capability in the model (for the recap's \"only option\" annotation). */\nconst findRouteCap = (model: WizardModel, app: string, routePath: string): RouteCap | undefined => {\n return model.apps\n .find((a) => {\n return a.name === app\n })\n ?.backends.flatMap((b) => {\n return b.routes\n })\n .find((r) => {\n return r.path === routePath\n })\n}\n\n/**\n * Print a one-line-per-route recap of what each frontend route resolved to, so the chosen sources are\n * visible before launch. A single-option route is annotated `(only option)` \u2014 it was auto-picked, not\n * asked. This is in addition to {@link echoManual}'s pasteable `--target` command.\n */\nconst recapSources = (plan: DerivedPlan, model: WizardModel): void => {\n const lines: string[] = []\n\n for (const [key, cfg] of Object.entries(plan.presetDef.apps ?? {})) {\n if (!key.endsWith('/ui') || !cfg.proxy) continue\n\n const app = key.split('/')[0]!\n\n for (const [routePath, source] of Object.entries(cfg.proxy)) {\n const cap = findRouteCap(model, app, routePath)\n const suffix = cap && cap.localCapable && cap.cloudCapable ? '' : ' (only option)'\n\n lines.push(` ${key} ${routePath} \u2192 ${source}${suffix}`)\n }\n }\n\n if (lines.length === 0) return\n logger.info('Resolved routes:')\n for (const line of [...lines].sort()) {\n logger.info(line)\n }\n}\n\n/** The manual-branch flow: frontends + per-route source + env + watch + orca \u2192 audited plan \u2192 recap \u2192 echo. */\nconst runManualBranch = async (prompts: WizardPrompts, model: WizardModel): Promise<WizardResult | null> => {\n if (model.apps.length === 0) {\n logger.warn('No apps discovered to run.')\n\n return null\n }\n\n const selectedTargets = await prompts.checkbox({ message: '\uD83D\uDCE6 Which packages?', choices: buildPartChoices(model) })\n\n if (selectedTargets.length === 0) {\n logger.warn('No packages selected.')\n\n return null\n }\n\n const uiKeys = selectedTargets.filter((t) => {\n return t.endsWith('/ui')\n })\n const sources = await promptRouteSources(prompts, model, uiKeys)\n\n const watch = await prompts.confirm({ message: '\uD83D\uDC40 Rebuild & restart on save (watch)?', default: false })\n const orca = asksOrca()\n ? await prompts.confirm({ message: '\uD83E\uDDE9 Run each app in its own Orca pane?', default: false })\n : false\n\n const selection: ManualSelection = { targets: selectedTargets, sources, watch, orca }\n const plan = deriveManualPlan(selection, model)\n\n if (plan.anyCloudRoute) {\n // A cloud route needs an environment to point at, and the only environments we can offer are those we\n // hold a token for. With none loaded, the `select` below would be handed zero choices and `@inquirer/select`\n // throws `No selectable choices` \u2014 a raw stack on a realistic first-run path (fresh clone, no `env-load`).\n // Back out cleanly with guidance instead, and BEFORE mutating `process.env`, so a refused run leaks nothing.\n if (model.environments.length === 0) {\n logger.warn('\u2601\uFE0F This selection routes to a cloud environment, but no environment token is loaded.')\n logger.warn(' Run `infra-kit env-load` to add one, then re-run the wizard.')\n\n return null\n }\n\n selection.env = await prompts.select({\n message: '\u2601\uFE0F Point cloud routes at which environment?',\n choices: model.environments.map((e) => {\n return { name: e, value: e }\n }),\n })\n process.env[INFRA_KIT_ENV_VAR] = selection.env\n }\n\n const issues = auditManualPlan(plan.presetDef, model)\n\n if (issues.length > 0) {\n logger.warn('\u26A0\uFE0F Proxy audit found issues with this selection:')\n for (const issue of issues) {\n logger.warn(` \u2022 ${issue}`)\n }\n\n return null\n }\n\n recapSources(plan, model)\n echoManual(plan, selection)\n\n // Orca opens one pane per selected API app. `include` picks WHICH apps get a pane; `presetDef` tells\n // each pane exactly which of its parts to run. Without the latter a pane runs `--app=<name>`, which\n // expands to every part the app has \u2014 silently starting a UI the user just unticked.\n const apiApps = plan.targetKeys\n .filter((k) => {\n return k.endsWith('/api')\n })\n .map((k) => {\n return k.split('/')[0]!\n })\n\n // An empty include would collapse to `null` in `normalizeAppInclude` and make Orca run EVERY api app,\n // so an Orca run with no selected backends (e.g. an all-frontend selection) falls back to in-process.\n if (orca && apiApps.length > 0) {\n return { include: apiApps, presetDef: plan.presetDef, watch, orca: true }\n }\n\n if (orca) {\n logger.info('\u2139\uFE0F Orca needs at least one local backend (panes are backend-only) \u2014 running in-process instead.')\n }\n\n return { presetDef: plan.presetDef, watch, orca: false }\n}\n\n/** Print the equivalent (`--target=\u2026`) flag command, plus a save-as-preset ergonomics hint. */\nconst echoManual = (plan: DerivedPlan, selection: ManualSelection): void => {\n commandEcho.setInteractive()\n\n const eq = equivalentCommand(plan, selection)\n\n commandEcho.addOption(eq.flags, true)\n commandEcho.print()\n\n // The `--target=\u2026` line reproduces the selection exactly; the preset is pure convenience \u2014 a short,\n // memorable name instead of retyping the target keys.\n logger.info('\u2139\uFE0F Prefer a short name? Save this selection as a devPreset and run `infra-kit dev <name>`.')\n}\n\n/** The preset-branch flow: run a named preset, asking only whether to watch (presets can't encode it). */\nconst runPresetBranch = async (prompts: WizardPrompts, preset: string): Promise<WizardResult> => {\n const watch = await prompts.confirm({ message: '\uD83D\uDC40 Rebuild & restart on save (watch)?', default: false })\n\n commandEcho.setInteractive()\n commandEcho.addOption(preset, true)\n if (watch) commandEcho.addOption('--watch', true)\n commandEcho.print()\n\n return { preset, watch, orca: false }\n}\n\n/** Sentinel value for the \"Manual (custom)\" step-0 choice (a preset name can never be empty). */\nexport const MANUAL_CHOICE = ' manual'\n\n/**\n * Drive the wizard's branch flow over an ALREADY-gathered model (no disk/config access). Split from\n * {@link runDevWizard} so the flow is unit-testable with scripted prompts + a fixture model.\n */\nexport const runWizardFlow = async (prompts: WizardPrompts, model: WizardModel): Promise<WizardResult | null> => {\n if (model.presets.length === 0) {\n return runManualBranch(prompts, model)\n }\n\n const choice = await prompts.select({\n message: '\uD83D\uDE80 Start from a preset, or configure manually?',\n choices: [\n ...model.presets.map((p) => {\n return { name: p, value: p }\n }),\n new Separator(' '),\n { name: 'Manual (custom)\u2026', value: MANUAL_CHOICE },\n ],\n })\n\n return choice === MANUAL_CHOICE ? runManualBranch(prompts, model) : runPresetBranch(prompts, choice)\n}\n\n/**\n * Gather the model from disk/config, then drive the wizard flow, returning the resolved run options (or\n * null on cancel / empty selection). The entry point calls this on a bare TTY `infra-kit dev`.\n */\nexport const runDevWizard = async (\n prompts: WizardPrompts = defaultPrompts,\n root: string = findMonorepoRoot(process.cwd()),\n): Promise<WizardResult | null> => {\n return runWizardFlow(prompts, await gatherWizardModel(root))\n}\n", "/**\n * Pure core of the interactive `infra-kit dev` wizard (the no-args, TTY path).\n *\n * The wizard is FRONTEND-CENTRIC: you pick which frontends to run, and for each frontend you choose,\n * every proxy route that has TWO real options (its `from` lists both `local` and `cloud`) is decided\n * EXPLICITLY \u2014 local (its backend is launched \u2192 the route resolves local) or cloud (the route proxies\n * to the `<env>` cloud target). Single-option routes are auto-picked. Because a backend runs local OR\n * cloud as a whole, routes that share one backend package RECONCILE: if any of them resolved local, the\n * backend runs local and all its local-capable routes follow. This module turns those answers into an\n * in-memory {@link DevPreset} the runner consumes verbatim (part-level targets the app-name-only `--app`\n * include cannot express) \u2014 and is side-effect-free so the mapping is fully unit-testable. The impure\n * I/O (discovery, inquirer prompts, audit, launch) lives in {@link file://./dev-wizard-run.ts}.\n */\nimport type { DevPreset, ProxySource } from 'src/lib/infra-kit-config'\n\n/**\n * One proxy route's per-route capability, carried through grouping so the wizard can decide whether it\n * even needs to ask about the route (only a `local`+`cloud` route is a real choice).\n */\nexport interface RouteCap {\n /** Route path (e.g. `/api`). */\n path: string\n /** `from` includes `local` \u2014 the route can resolve to a locally-launched backend. */\n localCapable: boolean\n /** `from` includes `cloud` \u2014 the route can resolve to the cloud target. */\n cloudCapable: boolean\n /** The route's declared `default` source when it has one (present iff `from` lists >1 source) \u2014 seeds the prompt's default. */\n default?: ProxySource\n}\n\n/**\n * One backend a frontend's proxy routes can be pointed at, grouped by the backend package. A frontend\n * that maps `/api` and `/media` to the same package yields ONE {@link ProxyBackend} with both routes \u2014\n * launching the package flips every one of its `local`-capable routes together (the reconcile in\n * {@link deriveManualPlan}).\n */\nexport interface ProxyBackend {\n /** Backend package name (a route's `packageName`). */\n packageName: string\n /** The routes that resolve to this package, each with its own local/cloud capability. */\n routes: RouteCap[]\n /** True when at least one of `routes` lists `local` in its `from` capabilities \u2014 i.e. it is launchable-local. */\n localCapable: boolean\n /** True when at least one of `routes` lists `cloud` \u2014 i.e. it can stay on the cloud target. */\n cloudCapable: boolean\n /** App folder whose `api` package is {@link packageName}, or undefined when no discovered app owns it (a `local` choice then has nothing to launch \u2014 the audit flags it). */\n ownerApp?: string\n}\n\n/** A discovered app as the wizard sees it: which parts exist + which backends its frontend proxies to. */\nexport interface WizardApp {\n /** App folder name (e.g. `client`). */\n name: string\n /** Has `apps/<app>/api` (a launchable backend). */\n hasApi: boolean\n /** Has `apps/<app>/ui` (a launchable frontend). */\n hasUi: boolean\n /**\n * This app's OWN `api` package name (from `apps/<app>/api`), or undefined when it has no api. Carried\n * so the audit can build a faithful `app \u2192 apiPackage` map for EVERY discovered api app \u2014 including\n * api-only apps a frontend proxies to cross-app \u2014 mirroring the root audit (`preset-proxy-check.ts`).\n */\n apiPackage?: string\n /** Backends this app's frontend proxies to (empty for api-only apps or a frontend with no `dev.proxy`). */\n backends: ProxyBackend[]\n}\n\n/** Everything the wizard needs, gathered impurely by {@link file://./dev-wizard-run.ts}. */\nexport interface WizardModel {\n /** All discovered apps (api and/or ui), sorted by name. */\n apps: WizardApp[]\n /** `devServersPresets` names (drives the preset-or-manual step-0). */\n presets: string[]\n /** Configured `environments` (the cloud-env `select` options). */\n environments: string[]\n}\n\n/** The manual-branch answers collected from the prompts, fed to {@link deriveManualPlan}. */\nexport interface ManualSelection {\n /**\n * The target keys the user ticked directly: every selected `<app>/ui` frontend, plus any api-only\n * `<app>/api` backend (apps with an api but no ui). A full-stack backend is NOT ticked here \u2014 it is\n * launched by choosing `local` for one of its frontend's routes (recorded in {@link sources}).\n */\n targets: string[]\n /**\n * Explicit per-route choice for every TWO-OPTION route, keyed `${app}/ui ${routePath}` (e.g.\n * `client/ui /api`). Single-option routes are absent (auto-picked). Missing two-option answers fall\n * back to the route's cloud/local capability in {@link deriveManualPlan}.\n */\n sources: Record<string, ProxySource>\n /** Chosen cloud env for cloud routes (undefined when nothing resolves cloud). */\n env?: string\n /** Rebuild + restart on save. */\n watch: boolean\n /** One Orca pane per app. */\n orca: boolean\n}\n\n/** The resolved run plan derived from a {@link ManualSelection}. */\nexport interface DerivedPlan {\n /** In-memory preset handed to the runner (`options.presetDef`). */\n presetDef: DevPreset\n /** At least one route resolves to cloud \u2192 an env must be chosen (pre-flight gate). */\n anyCloudRoute: boolean\n /** Resolved `<app>/<part>` target keys, sorted \u2014 for the echo + audit display. */\n targetKeys: string[]\n}\n\n/** App folder name from an `<app>/<part>` target key. */\nconst appOf = (key: string): string => {\n return key.split('/')[0]!\n}\n\n/** Index a model's apps by folder name for O(1) lookup. */\nconst byName = (model: WizardModel): Map<string, WizardApp> => {\n return new Map(\n model.apps.map((a) => {\n return [a.name, a]\n }),\n )\n}\n\n/** Is this route a real choice (both local and cloud reachable)? */\nconst isTwoOption = (route: RouteCap): boolean => {\n return route.localCapable && route.cloudCapable\n}\n\n/**\n * The source a single route resolves to BEFORE per-backend reconciliation:\n * - two-option: the user's recorded answer, else 'cloud' when cloud-capable else 'local';\n * - single local-only: always 'local';\n * - single cloud-only: always 'cloud'.\n */\nconst rawSource = (uiKey: string, route: RouteCap, sources: Record<string, ProxySource>): ProxySource => {\n if (isTwoOption(route)) {\n return sources[`${uiKey} ${route.path}`] ?? (route.cloudCapable ? 'cloud' : 'local')\n }\n\n return route.localCapable ? 'local' : 'cloud'\n}\n\n/**\n * Pass 1: which backend packages resolve local (any of their routes did), plus each package's owner app.\n * A package's local verdict is shared across every frontend that proxies to it \u2014 that is the reconcile.\n */\nconst collectLocalPackages = (\n uiKeys: string[],\n apps: Map<string, WizardApp>,\n sources: Record<string, ProxySource>,\n): { localPkgs: Set<string>; ownerByPkg: Map<string, string | undefined> } => {\n const localPkgs = new Set<string>()\n const ownerByPkg = new Map<string, string | undefined>()\n\n for (const key of uiKeys) {\n const app = apps.get(appOf(key))\n\n for (const backend of app?.backends ?? []) {\n ownerByPkg.set(backend.packageName, backend.ownerApp)\n for (const route of backend.routes) {\n if (rawSource(key, route, sources) === 'local') localPkgs.add(backend.packageName)\n }\n }\n }\n\n return { localPkgs, ownerByPkg }\n}\n\n/**\n * Pass 2 for ONE frontend: its per-route overrides after the per-package verdict, and whether any route\n * went cloud. A local-capable route on a local package is `local` (reconciled up); everything else `cloud`.\n */\nconst frontendOverrides = (\n app: WizardApp | undefined,\n localPkgs: ReadonlySet<string>,\n): { overrides: Record<string, ProxySource>; anyCloud: boolean } => {\n const overrides: Record<string, ProxySource> = {}\n let anyCloud = false\n\n for (const backend of app?.backends ?? []) {\n const backendLocal = localPkgs.has(backend.packageName)\n\n for (const route of backend.routes) {\n const source: ProxySource = route.localCapable && backendLocal ? 'local' : 'cloud'\n\n overrides[route.path] = source\n if (source === 'cloud') anyCloud = true\n }\n }\n\n return { overrides, anyCloud }\n}\n\n/**\n * Turn the manual {@link ManualSelection} into an in-memory {@link DevPreset}. The frontend checkbox picks\n * which UIs (and standalone api-only backends) to run; the per-route answers in {@link ManualSelection.sources}\n * decide each two-option route. Resolution is two passes so same-backend routes stay coherent:\n *\n * 1. Resolve every route of every selected frontend to its raw source; a package is LOCAL iff any of its\n * routes resolved local.\n * 2. Re-resolve each route against that per-package verdict: a local-capable route on a local package is\n * `local` (reconciled up even if it was individually answered cloud); a cloud-only route stays `cloud`.\n *\n * Launched backends are the ticked api-only parts \u222A every package that resolved local (added as\n * `${ownerApp}/api` when the owner is discoverable \u2014 a local override on an owner-less package is still\n * emitted, and the audit flags it).\n *\n * @example\n * // client frontend, its /api answered local \u2192 launches client/api + client/ui, /api resolves local:\n * deriveManualPlan(\n * { targets: ['client/ui'], sources: { 'client/ui /api': 'local' }, watch: false, orca: false },\n * { apps: [{ name: 'client', hasApi: true, hasUi: true, backends: [{ packageName: 'client-api',\n * cloudCapable: true, localCapable: true, ownerApp: 'client',\n * routes: [{ path: '/api', localCapable: true, cloudCapable: true }] }] }],\n * presets: [], environments: ['dev'] },\n * ).targetKeys // => ['client/api', 'client/ui']\n */\nexport const deriveManualPlan = (selection: ManualSelection, model: WizardModel): DerivedPlan => {\n const apps = byName(model)\n const uiKeys = selection.targets.filter((t) => {\n return t.endsWith('/ui')\n })\n const apiOnlyKeys = selection.targets.filter((t) => {\n return t.endsWith('/api')\n })\n\n // Pass 1: a package is local iff any of its routes (across every selected frontend) resolved local.\n const { localPkgs, ownerByPkg } = collectLocalPackages(uiKeys, apps, selection.sources)\n\n // Pass 2: re-resolve each route against the per-package verdict + build per-frontend overrides.\n const presetApps: Record<string, { proxy?: Record<string, ProxySource> }> = {}\n let anyCloud = false\n\n for (const key of uiKeys) {\n const { overrides, anyCloud: cloud } = frontendOverrides(apps.get(appOf(key)), localPkgs)\n\n if (cloud) anyCloud = true\n presetApps[key] = Object.keys(overrides).length > 0 ? { proxy: overrides } : {}\n }\n\n // Launch: the ticked api-only backends, plus every package that resolved local (via its owner app).\n for (const key of apiOnlyKeys) {\n presetApps[key] ??= {}\n }\n for (const pkg of localPkgs) {\n const owner = ownerByPkg.get(pkg)\n\n if (owner != null) presetApps[`${owner}/api`] ??= {}\n }\n\n return {\n presetDef: { apps: presetApps, orca: selection.orca },\n anyCloudRoute: anyCloud,\n targetKeys: Object.keys(presetApps).sort(),\n }\n}\n\n/** The equivalent non-interactive command for a derived plan. */\nexport interface EquivalentCommand {\n /** The `--target=<app>/<part>,\u2026`-form flag string (no leading `infra-kit dev`). */\n flags: string\n}\n\n/**\n * Build the equivalent `infra-kit dev --target=\u2026 [--watch] [--orca]` flag string for a derived plan.\n * Always exact: `--target` names packages at `<app>/<part>` granularity \u2014 the same grammar the plan's\n * `targetKeys` already use \u2014 so every wizard selection, whole-app or part-level, round-trips into a\n * pasteable command. (`--app` is deliberately NOT used here: its app-name granularity over-launches a\n * part-level pick \u2014 `--app=client` starts `client/api` even when only `client/ui` was ticked.)\n */\nexport const equivalentCommand = (plan: DerivedPlan, selection: ManualSelection): EquivalentCommand => {\n const parts = [`--target=${plan.targetKeys.join(',')}`]\n\n if (selection.watch) parts.push('--watch')\n if (selection.orca) parts.push('--orca')\n\n return { flags: parts.join(' ') }\n}\n"],
5
- "mappings": "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",
5
+ "mappings": "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",
6
6
  "names": ["inquirerCheckbox", "inquirerConfirm", "inquirerSelect", "Separator", "loadDev", "path", "process", "appOf", "key", "byName", "model", "a", "isTwoOption", "route", "rawSource", "uiKey", "sources", "collectLocalPackages", "uiKeys", "apps", "localPkgs", "ownerByPkg", "app", "backend", "frontendOverrides", "overrides", "anyCloud", "backendLocal", "source", "deriveManualPlan", "selection", "t", "apiOnlyKeys", "presetApps", "cloud", "pkg", "owner", "equivalentCommand", "plan", "parts", "promptContext", "process", "defaultPrompts", "cfg", "withEscape", "context", "inquirerSelect", "inquirerCheckbox", "inquirerConfirm", "groupBackends", "routes", "ownerByPkg", "byPkg", "route", "def", "cap", "existing", "loadBackends", "uiDir", "name", "loadDev", "error", "logger", "gatherWizardModel", "root", "apiApps", "discoverApiApps", "uiApps", "discoverUiApps", "config", "getInfraKitConfig", "a", "apiPkgByName", "uiNames", "apiNames", "allNames", "apps", "hasUi", "path", "store", "readTokenStore", "buildPartChoices", "model", "choices", "app", "paths", "b", "r", "description", "buildAuditContext", "discovered", "apiPkgByApp", "routeToPkg", "auditManualPlan", "presetDef", "validatePresetProxy", "i", "WIZARD_ORCA_VAR", "asksOrca", "promptRouteSources", "prompts", "uiKeys", "sources", "key", "backend", "answer", "findRouteCap", "routePath", "recapSources", "plan", "lines", "source", "suffix", "line", "runManualBranch", "selectedTargets", "t", "watch", "orca", "selection", "deriveManualPlan", "e", "INFRA_KIT_ENV_VAR", "issues", "issue", "echoManual", "k", "commandEcho", "eq", "equivalentCommand", "runPresetBranch", "preset", "MANUAL_CHOICE", "runWizardFlow", "choice", "p", "Separator", "runDevWizard", "findMonorepoRoot"]
7
7
  }
package/dist/mcp-proxy.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{u as G}from"./chunk-YYC3QGGC.js";import"./chunk-AWFGP6GY.js";import{a as M}from"./chunk-MFAFQVTW.js";import{a as W,d as H,n as T,o as E,s as K}from"./chunk-MOVRKV3I.js";import m from"node:process";var ve=/^[a-z][a-z0-9-]*$/,ye=/^[A-Z_]\w*$/i,Pe=(e,n,r)=>n==="--name"?e.name!==null?"--name given twice":ve.test(r)?(e.name=r,null):`--name "${r}" must be lowercase letters, digits and hyphens`:n==="--env"||n==="--unset"?ye.test(r)?M.has(r)?`${n} "${r}" is process plumbing, not a credential`:(n==="--env"?e.env.push(r):e.unset.push(r),null):`${n} "${r}" is not an environment-variable name`:`unknown flag ${n}`,Se=(e,n)=>{let r=0;for(;r<e.length;){let o=e[r];if(o==="--")return{separator:r};if(!o.startsWith("--"))return{problem:`missing "--" before the upstream command (saw "${o}")`};let a=e[r+1];if(a===void 0||a.startsWith("--"))return{problem:`${o} needs a value`};let p=Pe(n,o,a);if(p!==null)return{problem:p};r+=2}return{problem:'missing "--" before the upstream command'}},Q=e=>{let n={name:null,env:[],unset:[]},r=Se(e,n);if("problem"in r)return{ok:!1,problem:r.problem};if(n.name===null)return{ok:!1,problem:"missing --name"};if(n.env.length===0)return{ok:!1,problem:"missing --env (at least one variable to read)"};let o=e[r.separator+1];return o===void 0||o.length===0?{ok:!1,problem:'missing upstream command after "--"'}:{ok:!0,spec:{name:n.name,command:o,args:e.slice(r.separator+2),env:n.env,unset:n.unset}}};import{spawnSync as xe}from"node:child_process";import C from"node:fs";import x from"node:path";import O from"node:process";var Y=e=>x.join(E(),"mcp-proxy",e),be=e=>e.replaceAll(/[^\w.-]/g,"_").slice(0,64),Z=(e,n)=>x.join(n,`profile-${be(e)}.json`),A=(e,n)=>{let r=x.isAbsolute(e)?[e]:(n??O.env.PATH??"").split(x.delimiter).map(o=>x.join(o,e));for(let o of r)try{let a=C.statSync(o);return`stat-${a.size}-${Math.trunc(a.mtimeMs)}`}catch{}return"unknown"},X=(e,n=["--version"],r)=>{try{let o=xe(e,[...n],{encoding:"utf8",timeout:5e3,env:r==null?O.env:{...O.env,PATH:r}});if(o.status!==0)return A(e,r);let a=`${o.stdout}`.trim().split(`
3
- `)[0]?.trim()??"";return a.length>0?a:A(e,r)}catch{return A(e,r)}},ee=(e,n)=>{try{let r=JSON.parse(C.readFileSync(Z(e,n),"utf8"));return r.version!==e||!Array.isArray(r.tools)?null:{version:e,protocolVersion:typeof r.protocolVersion=="string"?r.protocolVersion:"",capabilities:r.capabilities??{},tools:r.tools}}catch{return null}},re=(e,n)=>{try{return C.mkdirSync(n,{recursive:!0}),K(Z(e.version,n),`${JSON.stringify(e)}
4
- `,384),!0}catch{return!1}};import we from"node:path";import L from"node:process";var Ee="no-session",Me="IK_MCP_ENV_FILE",Re=()=>{let e=L.env[H];return e!=null&&e.length>0?e:Ee},R=()=>{let e=L.env[Me];return e!=null&&e.length>0?e:we.join(E(),Re(),W)},$e=(e,n)=>{let r=e[n];if(r!=null&&r.length>0)return r;let o=L.env[n];return o!=null&&o.length>0?o:""},ne=(e,n=R())=>{let r=T(n),o={};for(let a of e){let p=$e(r,a);if(p.length===0)return null;o[a]=p}return o},te=(e,n=R())=>{let r=new Set(e);return Object.keys(T(n)).filter(o=>!r.has(o))};var $=(e,n)=>{let r="";e.setEncoding("utf8"),e.on("data",o=>{r+=o;let a=r.indexOf(`
5
- `);for(;a!==-1;){let p=r.slice(0,a);r=r.slice(a+1);let f=p.endsWith("\r")?p.slice(0,-1):p;f.trim().length>0&&n(f),a=r.indexOf(`
6
- `)}})};import{spawn as ke}from"node:child_process";import Je from"node:os";import F from"node:path";import k from"node:process";var Ie=()=>{let e=k.env.GOBIN;if(e!=null&&e.length>0)return e;let n=k.env.GOPATH;return F.join(n!=null&&n.length>0?n:F.join(Je.homedir(),"go"),"bin")},Ve=15e3,_e=12e4,Ne=M,oe=(e,n={})=>{let r=e.command,o=e.args,a=n.readyTimeoutMs??Ve,p=n.requestTimeoutMs??_e,f=n.log??(()=>{}),ce=n.onServerMessage??(()=>{}),de=`${Ie()}${F.delimiter}${k.env.PATH??""}`,z={},d=null,y=null,_=0,ue=(t,i)=>{for(let s of t.pending.values())s.reject(new Error(i));t.pending.clear()},P=(t,i)=>{t.closed||(t.closed=!0,ue(t,`${e.name} upstream ${i}`),t.child.kill())},me=(t,i)=>{let s;try{s=JSON.parse(i)}catch{f(`ignoring non-JSON line from ${r}`);return}if(s.method!=null){if(s.id==null){ce(s);return}f(`refusing server-initiated request ${s.method}`),w(t,{jsonrpc:"2.0",id:s.id,error:{code:-32601,message:"client requests are not supported by this shim"}});return}if(s.id==null)return;let l=t.pending.get(Number(s.id));l&&(t.pending.delete(Number(s.id)),l.resolve(l.clientId===void 0?s:{...s,id:l.clientId}))},w=(t,i)=>{t.closed||t.child.stdin.write(`${JSON.stringify(i)}
7
- `)},q=(t,i,s)=>{if(t.closed)return Promise.reject(new Error(`${e.name} upstream is closed`));let l=t.nextId;return t.nextId+=1,new Promise((c,S)=>{let B=setTimeout(()=>{t.pending.delete(l),S(new Error(`${r} did not answer ${i.method??"request"} within ${p}ms`))},p);t.pending.set(l,{clientId:s,resolve:N=>{clearTimeout(B),c(N)},reject:N=>{clearTimeout(B),S(N)}}),w(t,{...i,jsonrpc:"2.0",id:l})})},pe=async t=>{let i,s=new Promise((l,c)=>{i=setTimeout(()=>{c(new Error(`${r} did not answer initialize within ${a}ms`))},a)});try{return await Promise.race([t,s])}finally{i&&clearTimeout(i)}},fe=t=>{let i={...k.env,...n.extraEnv,PATH:de,...t};for(let s of e.unset)i[s]="";for(let s of n.stripFromChildEnv?.()??[])Ne.has(s)||delete i[s];return ke(r,[...o],{env:i,stdio:["pipe","pipe","pipe"]})},ge=async(t,i)=>{let s=fe(t),l={child:s,key:JSON.stringify(t),generation:i,pending:new Map,nextId:1,handshake:null,closed:!1};$(s.stdout,c=>{me(l,c)}),s.stderr.on("data",c=>{for(let S of c.toString().trimEnd().split(`
8
- `))S.length>0&&f(`${r}: ${S}`)}),s.on("error",c=>{P(l,`failed to start: ${c.message}`)}),s.on("exit",c=>{P(l,`exited with code ${String(c)}`)});try{l.handshake=await pe(q(l,{method:"initialize",params:z}))}catch(c){throw P(l,"handshake failed"),c}return w(l,{jsonrpc:"2.0",method:"notifications/initialized"}),f(`serving ${e.name} (${r})`),l},he=async t=>{let i=JSON.stringify(t);if(d&&!d.closed&&d.key===i)return d;if(y&&y.key===i)return y.promise;_+=1;let s=_;d&&f(`${e.name}: a listed variable changed \u2014 replacing upstream`);let l=(async()=>{let c=await ge(t,s);if(s!==_)throw P(c,"superseded by a newer target"),new Error(`${e.name} upstream superseded by a newer target`);return d&&P(d,"replaced"),d=c,c})();y={key:i,generation:s,promise:l};try{return await l}finally{y?.generation===s&&(y=null)}};return{setInitializeParams:t=>{z=t},request:async(t,i)=>{let s=await he(i);return q(s,{method:t.method,params:t.params},t.id)},notifyIfActive:t=>!d||d.closed?!1:(w(d,{jsonrpc:"2.0",method:t.method,params:t.params}),!0),handshake:()=>d?.handshake??null,dispose:()=>{d&&P(d,"disposed"),d=null}}};var Te=Number(m.env.IK_MCP_POLL_MS??2e3),ie="2025-06-18",ae={tools:{listChanged:!0}},g=e=>{m.stderr.write(`ik-mcp: ${e}
9
- `)},h=e=>{m.stdout.write(`${JSON.stringify(e)}
10
- `)};G((e,n)=>{e.outcome==="failed"&&g(`${n} failed: ${e.link} -> ${e.target}`)});var I=Q(m.argv.slice(2)),j=I.ok?null:`${I.problem} \u2014 run \`ik setup\` to regenerate this .mcp.json entry`,u=I.ok?I.spec:null,v=u===null?null:oe(u,{log:g,onServerMessage:h,stripFromChildEnv:()=>te(u.env)}),D=()=>u===null?null:ne(u.env),se=null,J,V=()=>(se??=u===null?"unknown":X(u.command,["--version"],m.env.PATH),se),le=()=>u===null?null:Y(u.name),b=()=>{if(J===void 0){let e=le();J=e===null?null:ee(V(),e)}return J},Ae=e=>{let n=le();if(n===null)return;let r=b(),o={version:V(),protocolVersion:e.protocolVersion??r?.protocolVersion??ie,capabilities:e.capabilities??r?.capabilities??ae,tools:e.tools??r?.tools??[]};J=o,re(o,n)},Oe=e=>{h({jsonrpc:"2.0",id:e.id,result:{protocolVersion:b()?.protocolVersion??ie,capabilities:b()?.capabilities??ae,serverInfo:{name:u?.name??"ik-mcp",version:V()}}})},U=!1,Ce=()=>{let e=setInterval(()=>{U||D()===null||(U=!0,clearInterval(e),g("credentials appeared \u2014 announcing tools/list_changed"),h({jsonrpc:"2.0",method:"notifications/tools/list_changed"}))},Te);e.unref()},Le=async(e,n)=>{let r=await v.request(e,n),o=r.result?.tools;if(Array.isArray(o)){let a=v.handshake()?.result;Ae({tools:o,capabilities:a?.capabilities,protocolVersion:a?.protocolVersion})}h(r)},Fe=e=>{h({jsonrpc:"2.0",id:e.id,result:{tools:b()?.tools??[]}})},je=e=>{if(v?.setInitializeParams(e.params),Oe(e),j!==null){g(`degraded: ${j}`);return}if(g(`${u.name}: env file ${R()}; reads ${u.env.join(", ")}; upstream ${u.command} ${V()}; cache ${b()?"warm":"cold"}`),D()!==null){U=!0;return}g("no credentials yet \u2014 deferring"),Ce()},Ue=e=>{if(e.method==="tools/list"){Fe(e);return}e.id!=null&&h({jsonrpc:"2.0",id:e.id,error:{code:-32e3,message:j??`${u.name}: credentials are not loaded yet (${u.env.join(", ")}) \u2014 run 'ik env-load'`}})},De=async e=>{if(e.method==null)return;if(e.method==="initialize"){je(e);return}let n=D();if(n===null||v===null){Ue(e);return}if(e.id==null){e.method!=="notifications/initialized"&&v.notifyIfActive(e);return}if(e.method==="tools/list"){await Le(e,n);return}h(await v.request(e,n))},ze=e=>{let n;try{n=JSON.parse(e)}catch{g("ignoring non-JSON line from client");return}De(n).catch(r=>{let o=r instanceof Error?r.message:String(r);g(o),n.id!=null&&h({jsonrpc:"2.0",id:n.id,error:{code:-32e3,message:o}})})};m.on("exit",()=>{v?.dispose()});m.on("SIGTERM",()=>{m.exit(0)});m.on("SIGINT",()=>{m.exit(0)});$(m.stdin,ze);m.stdin.on("end",()=>{m.exit(0)});
2
+ import{x as G}from"./chunk-KPRFMZCX.js";import"./chunk-AWFGP6GY.js";import{a as M}from"./chunk-MFAFQVTW.js";import{a as W,c as H,k as T,m as E,o as K}from"./chunk-ZZ7HCY2S.js";import p from"node:process";var ve=/^[a-z][a-z0-9-]*$/,ye=/^[A-Z_]\w*$/i,Pe=(e,r,n)=>r==="--name"?e.name!==null?"--name given twice":ve.test(n)?(e.name=n,null):`--name "${n}" must be lowercase letters, digits and hyphens`:r==="--env"||r==="--unset"?ye.test(n)?M.has(n)?`${r} "${n}" is process plumbing, not a credential`:(r==="--env"?e.env.push(n):e.unset.push(n),null):`${r} "${n}" is not an environment-variable name`:`unknown flag ${r}`,Se=(e,r)=>{let n=0;for(;n<e.length;){let o=e[n];if(o==="--")return{separator:n};if(!o.startsWith("--"))return{problem:`missing "--" before the upstream command (saw "${o}")`};let a=e[n+1];if(a===void 0||a.startsWith("--"))return{problem:`${o} needs a value`};let m=Pe(r,o,a);if(m!==null)return{problem:m};n+=2}return{problem:'missing "--" before the upstream command'}},Q=e=>{let r={name:null,env:[],unset:[]},n=Se(e,r);if("problem"in n)return{ok:!1,problem:n.problem};if(r.name===null)return{ok:!1,problem:"missing --name"};if(r.env.length===0)return{ok:!1,problem:"missing --env (at least one variable to read)"};let o=e[n.separator+1];return o===void 0||o.length===0?{ok:!1,problem:'missing upstream command after "--"'}:{ok:!0,spec:{name:r.name,command:o,args:e.slice(n.separator+2),env:r.env,unset:r.unset}}};import{spawnSync as xe}from"node:child_process";import C from"node:fs";import x from"node:path";import O from"node:process";var Y=e=>x.join(E(),"mcp-proxy",e),be=e=>e.replaceAll(/[^\w.-]/g,"_").slice(0,64),Z=(e,r)=>x.join(r,`profile-${be(e)}.json`),A=(e,r)=>{let n=x.isAbsolute(e)?[e]:(r??O.env.PATH??"").split(x.delimiter).map(o=>x.join(o,e));for(let o of n)try{let a=C.statSync(o);return`stat-${a.size}-${Math.trunc(a.mtimeMs)}`}catch{}return"unknown"},X=(e,r=["--version"],n)=>{try{let o=xe(e,[...r],{encoding:"utf8",timeout:5e3,env:n==null?O.env:{...O.env,PATH:n}});if(o.status!==0)return A(e,n);let a=`${o.stdout}`.trim().split(`
3
+ `)[0]?.trim()??"";return a.length>0?a:A(e,n)}catch{return A(e,n)}},ee=(e,r)=>{try{let n=JSON.parse(C.readFileSync(Z(e,r),"utf8"));return n.version!==e||!Array.isArray(n.tools)?null:{version:e,protocolVersion:typeof n.protocolVersion=="string"?n.protocolVersion:"",capabilities:n.capabilities??{},tools:n.tools}}catch{return null}},ne=(e,r)=>{try{return C.mkdirSync(r,{recursive:!0}),K(Z(e.version,r),`${JSON.stringify(e)}
4
+ `,384),!0}catch{return!1}};import we from"node:path";import L from"node:process";var Ee="no-session",Me="IK_MCP_ENV_FILE",Re=()=>{let e=L.env[H];return e!=null&&e.length>0?e:Ee},R=()=>{let e=L.env[Me];return e!=null&&e.length>0?e:we.join(E(),Re(),W)},$e=(e,r)=>{let n=e[r];if(n!=null&&n.length>0)return n;let o=L.env[r];return o!=null&&o.length>0?o:""},re=(e,r=R())=>{let n=T(r),o={};for(let a of e){let m=$e(n,a);if(m.length===0)return null;o[a]=m}return o},te=(e,r=R())=>{let n=new Set(e);return Object.keys(T(r)).filter(o=>!n.has(o))};var $=(e,r)=>{let n="";e.setEncoding("utf8"),e.on("data",o=>{n+=o;let a=n.indexOf(`
5
+ `);for(;a!==-1;){let m=n.slice(0,a);n=n.slice(a+1);let f=m.endsWith("\r")?m.slice(0,-1):m;f.trim().length>0&&r(f),a=n.indexOf(`
6
+ `)}})};import{spawn as ke}from"node:child_process";import Je from"node:os";import F from"node:path";import k from"node:process";var Ie=()=>{let e=k.env.GOBIN;if(e!=null&&e.length>0)return e;let r=k.env.GOPATH;return F.join(r!=null&&r.length>0?r:F.join(Je.homedir(),"go"),"bin")},Ve=15e3,_e=12e4,Ne=M,oe=(e,r={})=>{let n=e.command,o=e.args,a=r.readyTimeoutMs??Ve,m=r.requestTimeoutMs??_e,f=r.log??(()=>{}),ce=r.onServerMessage??(()=>{}),de=`${Ie()}${F.delimiter}${k.env.PATH??""}`,z={},d=null,y=null,_=0,ue=(t,i)=>{for(let s of t.pending.values())s.reject(new Error(i));t.pending.clear()},P=(t,i)=>{t.closed||(t.closed=!0,ue(t,`${e.name} upstream ${i}`),t.child.kill())},pe=(t,i)=>{let s;try{s=JSON.parse(i)}catch{f(`ignoring non-JSON line from ${n}`);return}if(s.method!=null){if(s.id==null){ce(s);return}f(`refusing server-initiated request ${s.method}`),w(t,{jsonrpc:"2.0",id:s.id,error:{code:-32601,message:"client requests are not supported by this shim"}});return}if(s.id==null)return;let l=t.pending.get(Number(s.id));l&&(t.pending.delete(Number(s.id)),l.resolve(l.clientId===void 0?s:{...s,id:l.clientId}))},w=(t,i)=>{t.closed||t.child.stdin.write(`${JSON.stringify(i)}
7
+ `)},q=(t,i,s)=>{if(t.closed)return Promise.reject(new Error(`${e.name} upstream is closed`));let l=t.nextId;return t.nextId+=1,new Promise((c,S)=>{let B=setTimeout(()=>{t.pending.delete(l),S(new Error(`${n} did not answer ${i.method??"request"} within ${m}ms`))},m);t.pending.set(l,{clientId:s,resolve:N=>{clearTimeout(B),c(N)},reject:N=>{clearTimeout(B),S(N)}}),w(t,{...i,jsonrpc:"2.0",id:l})})},me=async t=>{let i,s=new Promise((l,c)=>{i=setTimeout(()=>{c(new Error(`${n} did not answer initialize within ${a}ms`))},a)});try{return await Promise.race([t,s])}finally{i&&clearTimeout(i)}},fe=t=>{let i={...k.env,...r.extraEnv,PATH:de,...t};for(let s of e.unset)i[s]="";for(let s of r.stripFromChildEnv?.()??[])Ne.has(s)||delete i[s];return ke(n,[...o],{env:i,stdio:["pipe","pipe","pipe"]})},ge=async(t,i)=>{let s=fe(t),l={child:s,key:JSON.stringify(t),generation:i,pending:new Map,nextId:1,handshake:null,closed:!1};$(s.stdout,c=>{pe(l,c)}),s.stderr.on("data",c=>{for(let S of c.toString().trimEnd().split(`
8
+ `))S.length>0&&f(`${n}: ${S}`)}),s.on("error",c=>{P(l,`failed to start: ${c.message}`)}),s.on("exit",c=>{P(l,`exited with code ${String(c)}`)});try{l.handshake=await me(q(l,{method:"initialize",params:z}))}catch(c){throw P(l,"handshake failed"),c}return w(l,{jsonrpc:"2.0",method:"notifications/initialized"}),f(`serving ${e.name} (${n})`),l},he=async t=>{let i=JSON.stringify(t);if(d&&!d.closed&&d.key===i)return d;if(y&&y.key===i)return y.promise;_+=1;let s=_;d&&f(`${e.name}: a listed variable changed \u2014 replacing upstream`);let l=(async()=>{let c=await ge(t,s);if(s!==_)throw P(c,"superseded by a newer target"),new Error(`${e.name} upstream superseded by a newer target`);return d&&P(d,"replaced"),d=c,c})();y={key:i,generation:s,promise:l};try{return await l}finally{y?.generation===s&&(y=null)}};return{setInitializeParams:t=>{z=t},request:async(t,i)=>{let s=await he(i);return q(s,{method:t.method,params:t.params},t.id)},notifyIfActive:t=>!d||d.closed?!1:(w(d,{jsonrpc:"2.0",method:t.method,params:t.params}),!0),handshake:()=>d?.handshake??null,dispose:()=>{d&&P(d,"disposed"),d=null}}};var Te=Number(p.env.IK_MCP_POLL_MS??2e3),ie="2025-06-18",ae={tools:{listChanged:!0}},g=e=>{p.stderr.write(`ik-mcp: ${e}
9
+ `)},h=e=>{p.stdout.write(`${JSON.stringify(e)}
10
+ `)};G((e,r)=>{e.outcome==="failed"&&g(e.kind==="link"?`${r} failed: ${e.link} -> ${e.target}`:`${r} failed: ${e.node} <- ${e.source}`)});var I=Q(p.argv.slice(2)),j=I.ok?null:`${I.problem} \u2014 run \`ik setup\` to regenerate this .mcp.json entry`,u=I.ok?I.spec:null,v=u===null?null:oe(u,{log:g,onServerMessage:h,stripFromChildEnv:()=>te(u.env)}),D=()=>u===null?null:re(u.env),se=null,J,V=()=>(se??=u===null?"unknown":X(u.command,["--version"],p.env.PATH),se),le=()=>u===null?null:Y(u.name),b=()=>{if(J===void 0){let e=le();J=e===null?null:ee(V(),e)}return J},Ae=e=>{let r=le();if(r===null)return;let n=b(),o={version:V(),protocolVersion:e.protocolVersion??n?.protocolVersion??ie,capabilities:e.capabilities??n?.capabilities??ae,tools:e.tools??n?.tools??[]};J=o,ne(o,r)},Oe=e=>{h({jsonrpc:"2.0",id:e.id,result:{protocolVersion:b()?.protocolVersion??ie,capabilities:b()?.capabilities??ae,serverInfo:{name:u?.name??"ik-mcp",version:V()}}})},U=!1,Ce=()=>{let e=setInterval(()=>{U||D()===null||(U=!0,clearInterval(e),g("credentials appeared \u2014 announcing tools/list_changed"),h({jsonrpc:"2.0",method:"notifications/tools/list_changed"}))},Te);e.unref()},Le=async(e,r)=>{let n=await v.request(e,r),o=n.result?.tools;if(Array.isArray(o)){let a=v.handshake()?.result;Ae({tools:o,capabilities:a?.capabilities,protocolVersion:a?.protocolVersion})}h(n)},Fe=e=>{h({jsonrpc:"2.0",id:e.id,result:{tools:b()?.tools??[]}})},je=e=>{if(v?.setInitializeParams(e.params),Oe(e),j!==null){g(`degraded: ${j}`);return}if(g(`${u.name}: env file ${R()}; reads ${u.env.join(", ")}; upstream ${u.command} ${V()}; cache ${b()?"warm":"cold"}`),D()!==null){U=!0;return}g("no credentials yet \u2014 deferring"),Ce()},Ue=e=>{if(e.method==="tools/list"){Fe(e);return}e.id!=null&&h({jsonrpc:"2.0",id:e.id,error:{code:-32e3,message:j??`${u.name}: credentials are not loaded yet (${u.env.join(", ")}) \u2014 run 'ik env-load'`}})},De=async e=>{if(e.method==null)return;if(e.method==="initialize"){je(e);return}let r=D();if(r===null||v===null){Ue(e);return}if(e.id==null){e.method!=="notifications/initialized"&&v.notifyIfActive(e);return}if(e.method==="tools/list"){await Le(e,r);return}h(await v.request(e,r))},ze=e=>{let r;try{r=JSON.parse(e)}catch{g("ignoring non-JSON line from client");return}De(r).catch(n=>{let o=n instanceof Error?n.message:String(n);g(o),r.id!=null&&h({jsonrpc:"2.0",id:r.id,error:{code:-32e3,message:o}})})};p.on("exit",()=>{v?.dispose()});p.on("SIGTERM",()=>{p.exit(0)});p.on("SIGINT",()=>{p.exit(0)});$(p.stdin,ze);p.stdin.on("end",()=>{p.exit(0)});
11
11
  //# sourceMappingURL=mcp-proxy.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/entry/mcp-proxy.ts", "../src/lib/mcp-proxy/argv.ts", "../src/lib/mcp-proxy/cache.ts", "../src/lib/mcp-proxy/env-vars.ts", "../src/lib/mcp-proxy/line-stream.ts", "../src/lib/mcp-proxy/upstream.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n// The hashbang must stay on line 1: this entry is published as the `ik-mcp` bin and is exec'd\n// directly by the MCP client, not invoked as `node dist/mcp-proxy.js`.\nimport process from 'node:process'\n\nimport { bootPortlessLink } from 'src/dev/proxy/portless-link'\nimport { parseProxyArgv } from 'src/lib/mcp-proxy/argv'\nimport { proxyCacheDir, readBinaryVersion, readProfile, writeProfile } from 'src/lib/mcp-proxy/cache'\nimport type { UpstreamProfile } from 'src/lib/mcp-proxy/cache'\nimport { readListedVars, readUnlistedNames, resolveEnvFilePath } from 'src/lib/mcp-proxy/env-vars'\nimport type { ProxyVars } from 'src/lib/mcp-proxy/env-vars'\nimport { onEachLine } from 'src/lib/mcp-proxy/line-stream'\nimport { createUpstream } from 'src/lib/mcp-proxy/upstream'\nimport type { JsonRpcMessage, ProxySpec, Upstream } from 'src/lib/mcp-proxy/upstream'\n\nconst CREDENTIAL_POLL_MS = Number(process.env.IK_MCP_POLL_MS ?? 2000)\n\n/**\n * Answered on a cold cache, when no upstream has ever been observed on this machine. Pinned rather\n * than echoed from the client: echoing back whatever a client asks for claims support for a\n * revision nothing here has ever spoken. Only `tools` is claimed \u2014 every MCP server has tools, not\n * every one has resources, and claiming `resources` for one that lacks them makes a client issue\n * `resources/list` and get \"method not found\".\n */\nconst FALLBACK_PROTOCOL_VERSION = '2025-06-18'\nconst FALLBACK_CAPABILITIES = { tools: { listChanged: true } }\n\nconst log = (message: string): void => {\n process.stderr.write(`ik-mcp: ${message}\\n`)\n}\n\nconst write = (payload: JsonRpcMessage): void => {\n process.stdout.write(`${JSON.stringify(payload)}\\n`)\n}\n\n// This bin is the process Claude Code keeps alive, so it is where `~/.infra-kit/portless` converges on\n// a machine that only ever runs the MCP surface. fs-only and synchronous \u2014 nothing is spawned before the\n// handshake \u2014 and stdout is the transport, so only a failure earns a stderr line; the ordinary outcomes\n// are `doctor`'s to show.\nbootPortlessLink((result, message) => {\n if (result.outcome === 'failed') log(`${message} failed: ${result.link} -> ${result.target}`)\n})\n\nconst parsed = parseProxyArgv(process.argv.slice(2))\n\n/**\n * Bad argv is the same state as \"no credentials yet\", not a crash: the handshake is answered, the\n * tool list is empty, and every other request says what is wrong and how to fix it. A proxy that\n * exits on a typo in `.mcp.json` is a dead server the client cannot recover.\n */\nconst degraded: string | null = parsed.ok\n ? null\n : `${parsed.problem} \u2014 run \\`ik setup\\` to regenerate this .mcp.json entry`\nconst spec: ProxySpec | null = parsed.ok ? parsed.spec : null\n\nconst upstream: Upstream | null =\n spec === null\n ? null\n : createUpstream(spec, {\n log,\n // Server-initiated notifications belong to the client and travel verbatim.\n onServerMessage: write,\n // Everything the launching shell picked up from the same env file, minus the listed names,\n // is deleted from the child's inherited environment.\n stripFromChildEnv: () => {\n return readUnlistedNames(spec.env)\n },\n })\n\nconst readVars = (): ProxyVars | null => {\n return spec === null ? null : readListedVars(spec.env)\n}\n\n// Both are resolved on first use, never at module load: `readBinaryVersion` spawns a process and\n// can block for up to its timeout, and doing that before stdin is wired delays the handshake of\n// every session \u2014 including ones that never touch the upstream.\nlet versionCache: string | null = null\nlet profileCache: UpstreamProfile | null | undefined\n\nconst binaryVersion = (): string => {\n versionCache ??=\n // No spec means no upstream to ask, and importing package.json for a version string would drag\n // the whole manifest \u2014 dependency names included \u2014 into a bundle the guard keeps flat.\n spec === null ? 'unknown' : readBinaryVersion(spec.command, ['--version'], process.env.PATH)\n\n return versionCache\n}\n\nconst cacheDir = (): string | null => {\n return spec === null ? null : proxyCacheDir(spec.name)\n}\n\nconst profile = (): UpstreamProfile | null => {\n if (profileCache === undefined) {\n const dir = cacheDir()\n\n profileCache = dir === null ? null : readProfile(binaryVersion(), dir)\n }\n\n return profileCache\n}\n\n/** Fold whatever the live upstream just told us into the on-disk profile. */\nconst rememberProfile = (patch: Partial<UpstreamProfile>): void => {\n const dir = cacheDir()\n\n if (dir === null) return\n\n const current = profile()\n\n const next: UpstreamProfile = {\n version: binaryVersion(),\n protocolVersion: patch.protocolVersion ?? current?.protocolVersion ?? FALLBACK_PROTOCOL_VERSION,\n capabilities: patch.capabilities ?? current?.capabilities ?? FALLBACK_CAPABILITIES,\n tools: patch.tools ?? current?.tools ?? [],\n }\n\n profileCache = next\n writeProfile(next, dir)\n}\n\n/**\n * Answer `initialize` without spawning anything.\n *\n * Spawning here would forfeit lazy start \u2014 a session that never touches the upstream would still\n * pay for a child. The cost is that a first-ever session reports the pinned fallback capabilities\n * and is corrected once a real handshake has been seen; MCP has no capability-change notification,\n * so that correction lands on the NEXT session.\n */\nconst answerInitialize = (message: JsonRpcMessage): void => {\n write({\n jsonrpc: '2.0',\n id: message.id,\n result: {\n protocolVersion: profile()?.protocolVersion ?? FALLBACK_PROTOCOL_VERSION,\n capabilities: profile()?.capabilities ?? FALLBACK_CAPABILITIES,\n serverInfo: { name: spec?.name ?? 'ik-mcp', version: binaryVersion() },\n },\n })\n}\n\nlet announced = false\n\n/**\n * Credentials arrive mid-session, and stdio keeps a server-to-client channel open the whole time \u2014\n * so the moment they appear the client can be told to list again. Polls the env file ONLY: there is\n * no config to poll, so there is no mid-edit \"invalid config\" window and no path by which a watcher\n * could tear down a live upstream.\n */\nconst watchForCredentials = (): void => {\n const timer = setInterval(() => {\n if (announced || readVars() === null) return\n\n announced = true\n clearInterval(timer)\n log('credentials appeared \u2014 announcing tools/list_changed')\n write({ jsonrpc: '2.0', method: 'notifications/tools/list_changed' })\n }, CREDENTIAL_POLL_MS)\n\n timer.unref()\n}\n\nconst forwardToolsList = async (message: JsonRpcMessage, vars: ProxyVars): Promise<void> => {\n const response = await upstream!.request(message, vars)\n const tools = (response.result as { tools?: unknown[] } | undefined)?.tools\n\n if (Array.isArray(tools)) {\n const handshake = upstream!.handshake()?.result as { protocolVersion?: string; capabilities?: unknown } | undefined\n\n rememberProfile({ tools, capabilities: handshake?.capabilities, protocolVersion: handshake?.protocolVersion })\n }\n\n write(response)\n}\n\n/** Before credentials exist, the tool list is answered from cache \u2014 never with an error. */\nconst answerToolsListFromCache = (message: JsonRpcMessage): void => {\n write({ jsonrpc: '2.0', id: message.id, result: { tools: profile()?.tools ?? [] } })\n}\n\n/** Answers the handshake and arms the watcher; deliberately spawns nothing. */\nconst handleInitialize = (message: JsonRpcMessage): void => {\n upstream?.setInitializeParams(message.params)\n answerInitialize(message)\n\n if (degraded !== null) {\n log(`degraded: ${degraded}`)\n\n return\n }\n\n // Always name the resolved path and the spec: when either is wrong (a stale XDG_CACHE_HOME, a\n // session id the client never inherited, a drifted .mcp.json) nothing else in the session says so.\n // Names only \u2014 the VALUES are credentials.\n log(\n `${spec!.name}: env file ${resolveEnvFilePath()}; reads ${spec!.env.join(', ')}; upstream ${spec!.command} ${binaryVersion()}; cache ${profile() ? 'warm' : 'cold'}`,\n )\n\n if (readVars() !== null) {\n announced = true\n\n return\n }\n\n log('no credentials yet \u2014 deferring')\n watchForCredentials()\n}\n\n/** The pre-`env-load` state (or bad argv), which is normal and must never look like a protocol failure. */\nconst answerWithoutCredentials = (message: JsonRpcMessage): void => {\n if (message.method === 'tools/list') {\n answerToolsListFromCache(message)\n\n return\n }\n\n if (message.id == null) return\n\n write({\n jsonrpc: '2.0',\n id: message.id,\n error: {\n code: -32000,\n message:\n degraded ?? `${spec!.name}: credentials are not loaded yet (${spec!.env.join(', ')}) \u2014 run 'ik env-load'`,\n },\n })\n}\n\nconst handle = async (message: JsonRpcMessage): Promise<void> => {\n // An id with no method is a RESPONSE, not a request. A well-behaved client sends none \u2014 the\n // proxy refuses server-initiated requests, so there is nothing to answer \u2014 and treating one as a\n // request would spawn an upstream and reply `no method undefined`.\n if (message.method == null) return\n\n if (message.method === 'initialize') {\n handleInitialize(message)\n\n return\n }\n\n const vars = readVars()\n\n if (vars === null || upstream === null) {\n answerWithoutCredentials(message)\n\n return\n }\n\n if (message.id == null) {\n // Never spawns. `notifications/initialized` in particular is answered by not relaying it at\n // all: every child gets its own from the handshake replay, and forwarding the client's would\n // make the mandatory handshake defeat lazy start.\n if (message.method !== 'notifications/initialized') upstream.notifyIfActive(message)\n\n return\n }\n\n if (message.method === 'tools/list') {\n await forwardToolsList(message, vars)\n\n return\n }\n\n write(await upstream.request(message, vars))\n}\n\nconst onLine = (line: string): void => {\n let message: JsonRpcMessage\n\n try {\n message = JSON.parse(line) as JsonRpcMessage\n } catch {\n log('ignoring non-JSON line from client')\n\n return\n }\n\n handle(message).catch((error: unknown) => {\n const detail = error instanceof Error ? error.message : String(error)\n\n log(detail)\n\n if (message.id != null) {\n write({ jsonrpc: '2.0', id: message.id, error: { code: -32000, message: detail } })\n }\n })\n}\n\nprocess.on('exit', () => {\n upstream?.dispose()\n})\nprocess.on('SIGTERM', () => {\n process.exit(0)\n})\nprocess.on('SIGINT', () => {\n process.exit(0)\n})\n\nonEachLine(process.stdin, onLine)\n\n// The client closing its end is the ordinary way this server ends.\nprocess.stdin.on('end', () => {\n process.exit(0)\n})\n", "import { PROTECTED_CHILD_ENV_NAMES } from './protected-env'\nimport type { ProxySpec } from './upstream'\n\n/** Mirrors the config schema's name rule; re-checked here because the name becomes a cache subdir. */\nconst NAME_PATTERN = /^[a-z][a-z0-9-]*$/\n/** Mirrors `envVarName` in the config schema. */\nconst ENV_VAR_PATTERN = /^[A-Z_]\\w*$/i\n\nexport type ParsedArgv = { ok: true; spec: ProxySpec } | { ok: false; problem: string }\n\ninterface Flags {\n name: string | null\n env: string[]\n unset: string[]\n}\n\n/** Apply one `--flag value` pair, or say why it cannot be applied. */\nconst applyFlag = (flags: Flags, flag: string, value: string): string | null => {\n if (flag === '--name') {\n if (flags.name !== null) return '--name given twice'\n if (!NAME_PATTERN.test(value)) return `--name \"${value}\" must be lowercase letters, digits and hyphens`\n\n flags.name = value\n\n return null\n }\n\n if (flag === '--env' || flag === '--unset') {\n if (!ENV_VAR_PATTERN.test(value)) return `${flag} \"${value}\" is not an environment-variable name`\n // Mirrors the schema refinement, because hand-written argv (the `claude mcp add --scope local`\n // path) never passes through the schema \u2014 and `--unset PATH` would blank PATH and ENOENT the spawn.\n if (PROTECTED_CHILD_ENV_NAMES.has(value)) return `${flag} \"${value}\" is process plumbing, not a credential`\n\n if (flag === '--env') flags.env.push(value)\n else flags.unset.push(value)\n\n return null\n }\n\n return `unknown flag ${flag}`\n}\n\n/** Walk the flag half; returns the index of the `--` separator or a problem. */\nconst readFlags = (argv: readonly string[], flags: Flags): { separator: number } | { problem: string } => {\n let index = 0\n\n while (index < argv.length) {\n const flag = argv[index]!\n\n if (flag === '--') return { separator: index }\n\n // A bare word where a flag belongs is the upstream command arriving early \u2014 the separator\n // is what is missing, and that is the more useful thing to say than \"cmd needs a value\".\n if (!flag.startsWith('--')) return { problem: `missing \"--\" before the upstream command (saw \"${flag}\")` }\n\n const value = argv[index + 1]\n\n // A value that looks like a flag (`--env --`) would otherwise eat the separator and turn the\n // upstream command into a flag \u2014 the case that spawns the wrong binary instead of refusing.\n if (value === undefined || value.startsWith('--')) return { problem: `${flag} needs a value` }\n\n const problem = applyFlag(flags, flag, value)\n\n if (problem !== null) return { problem }\n\n index += 2\n }\n\n return { problem: 'missing \"--\" before the upstream command' }\n}\n\n/**\n * Parse the argv `ik setup` derived: `--name N (--env V)+ (--unset V)* -- <command> [args...]`.\n *\n * Every flag VALUE is validated, not only `--name`. The first `--` in flag position ends our half;\n * everything after it is the upstream's, verbatim, `--`s and all.\n */\n// Node builtins only, on purpose. Pulling commander in here would drag it into the proxy bundle,\n// which the chunk-isolation guard forbids \u2014 and a four-flag grammar does not need it.\nexport const parseProxyArgv = (argv: readonly string[]): ParsedArgv => {\n const flags: Flags = { name: null, env: [], unset: [] }\n const walked = readFlags(argv, flags)\n\n if ('problem' in walked) return { ok: false, problem: walked.problem }\n if (flags.name === null) return { ok: false, problem: 'missing --name' }\n if (flags.env.length === 0) return { ok: false, problem: 'missing --env (at least one variable to read)' }\n\n const command = argv[walked.separator + 1]\n\n if (command === undefined || command.length === 0)\n return { ok: false, problem: 'missing upstream command after \"--\"' }\n\n return {\n ok: true,\n spec: { name: flags.name, command, args: argv.slice(walked.separator + 2), env: flags.env, unset: flags.unset },\n }\n}\n", "import { spawnSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { atomicWriteFileSync, getCacheRoot } from 'src/lib/constants'\n\n/**\n * What a session can answer with before any child exists: the tool list and the\n * capability payload the upstream last reported.\n *\n * Capabilities are cached alongside the tools because MCP has no\n * capability-change notification \u2014 a deferred `initialize` must state them up front\n * and can never correct itself, so the honest answer has to come from disk.\n */\nexport interface UpstreamProfile {\n version: string\n protocolVersion: string\n capabilities: unknown\n tools: unknown[]\n}\n\n/**\n * Proxy state lives under the CACHE root, never `~/.infra-kit` \u2014 that is\n * `USER_CONFIG_DIR_NAME`, the auto-seeded project-config registry, where a\n * throwaway derived file has no business living. One subdir per configured name.\n */\nexport const proxyCacheDir = (name: string): string => {\n return path.join(getCacheRoot(), 'mcp-proxy', name)\n}\n\n/** Keeps a version string usable as one path segment. */\nconst safeSegment = (version: string): string => {\n return version.replaceAll(/[^\\w.-]/g, '_').slice(0, 64)\n}\n\nexport const profilePath = (version: string, dir: string): string => {\n return path.join(dir, `profile-${safeSegment(version)}.json`)\n}\n\n/**\n * A cache key for a binary that does not answer `--version`: its resolved path's size and mtime.\n *\n * Both change on every upgrade, which is all the key has to guarantee. Hashing the file would too,\n * but a Go binary is tens of megabytes and this runs at session start.\n */\nexport const binaryFingerprint = (binary: string, searchPath?: string): string => {\n const candidates = path.isAbsolute(binary)\n ? [binary]\n : (searchPath ?? process.env.PATH ?? '').split(path.delimiter).map((dir) => {\n return path.join(dir, binary)\n })\n\n for (const candidate of candidates) {\n try {\n const stat = fs.statSync(candidate)\n\n return `stat-${stat.size}-${Math.trunc(stat.mtimeMs)}`\n } catch {\n // not here; try the next PATH entry\n }\n }\n\n return 'unknown'\n}\n\n/**\n * The upstream binary's self-reported version, falling back to {@link binaryFingerprint}.\n * This is the cache key, so an upgrade that changes the tool set can never be served\n * a stale list \u2014 the new version simply looks at a different file.\n */\nexport const readBinaryVersion = (\n binary: string,\n versionArgs: readonly string[] = ['--version'],\n searchPath?: string,\n): string => {\n try {\n // The same PATH the upstream spawn uses. Without it, a `go install` layout \u2014 where\n // mcp-grafana lives only in GOBIN \u2014 probes as ENOENT, every version collapses into\n // one 'unknown' cache bucket, and an upgrade is served the previous tool list.\n const result = spawnSync(binary, [...versionArgs], {\n encoding: 'utf8',\n timeout: 5000,\n env: searchPath == null ? process.env : { ...process.env, PATH: searchPath },\n })\n\n if (result.status !== 0) return binaryFingerprint(binary, searchPath)\n\n const reported = `${result.stdout}`.trim().split('\\n')[0]?.trim() ?? ''\n\n return reported.length > 0 ? reported : binaryFingerprint(binary, searchPath)\n } catch {\n return binaryFingerprint(binary, searchPath)\n }\n}\n\n/**\n * The cached profile for this binary version, or null.\n *\n * Every failure is a null, never a throw: a torn or truncated file must degrade to\n * \"no cache yet\", because the alternative is an exception on the deferred\n * `initialize` path \u2014 which would kill the session the cache exists to rescue.\n */\nexport const readProfile = (version: string, dir: string): UpstreamProfile | null => {\n try {\n const parsed = JSON.parse(fs.readFileSync(profilePath(version, dir), 'utf8')) as Partial<UpstreamProfile>\n\n if (parsed.version !== version || !Array.isArray(parsed.tools)) return null\n\n return {\n version,\n protocolVersion: typeof parsed.protocolVersion === 'string' ? parsed.protocolVersion : '',\n capabilities: parsed.capabilities ?? {},\n tools: parsed.tools,\n }\n } catch {\n return null\n }\n}\n\n/**\n * Persist a profile. Best-effort: a cache that cannot be written is a slower next\n * session, not a broken one.\n */\nexport const writeProfile = (profile: UpstreamProfile, dir: string): boolean => {\n try {\n fs.mkdirSync(dir, { recursive: true })\n // Atomic, because two sessions can write this concurrently and a half-written\n // file reads back as \"no tools\" \u2014 a silently toolless session with no error.\n atomicWriteFileSync(profilePath(profile.version, dir), `${JSON.stringify(profile)}\\n`, 0o600)\n\n return true\n } catch {\n return false\n }\n}\n", "import path from 'node:path'\nimport process from 'node:process'\n\nimport { ENV_LOAD_FILE, INFRA_KIT_SESSION_VAR, getCacheRoot, parseVarsFromEnvFile } from 'src/lib/constants'\n\n/**\n * Session id used when the proxy inherits none. `getSessionCacheDir()` THROWS in that case,\n * which is correct for a command and fatal for a server \u2014 a proxy that throws at startup is a\n * dead MCP server, so it degrades to a fixed dir instead.\n */\nexport const NO_SESSION = 'no-session'\n\n/** Escape hatch for tests and for pointing the proxy at a hand-written file. */\nexport const ENV_FILE_OVERRIDE_VAR = 'IK_MCP_ENV_FILE'\n\n/** The listed variables' values, keyed by name, in the order the spec listed them. */\nexport type ProxyVars = Record<string, string>\n\nexport const resolveSessionId = (): string => {\n const session = process.env[INFRA_KIT_SESSION_VAR]\n\n return session != null && session.length > 0 ? session : NO_SESSION\n}\n\n/**\n * Where `ik env-load` writes for this session. Goes through `getCacheRoot()` so\n * `XDG_CACHE_HOME` is honoured \u2014 a hardcoded `~/.cache` would silently read a path\n * nothing ever writes on any box that sets it.\n */\nexport const resolveEnvFilePath = (): string => {\n const override = process.env[ENV_FILE_OVERRIDE_VAR]\n\n if (override != null && override.length > 0) return override\n\n return path.join(getCacheRoot(), resolveSessionId(), ENV_LOAD_FILE)\n}\n\n/** The file wins over the inherited environment, per name. */\nconst pick = (fileVars: Record<string, string>, name: string): string => {\n const fromFile = fileVars[name]\n\n if (fromFile != null && fromFile.length > 0) return fromFile\n\n const fromEnv = process.env[name]\n\n return fromEnv != null && fromEnv.length > 0 ? fromEnv : ''\n}\n\n/**\n * The values of `names`, or null while any of them is missing \u2014 the normal state before\n * `ik env-load` runs, which must never be an error.\n *\n * Built by iterating `names`, not the file, so the record's key order \u2014 and therefore its\n * JSON, which is the respawn key \u2014 is stable however Doppler happens to order the file.\n */\nexport const readListedVars = (names: readonly string[], filePath: string = resolveEnvFilePath()): ProxyVars | null => {\n const fileVars = parseVarsFromEnvFile(filePath)\n const vars: ProxyVars = {}\n\n for (const name of names) {\n const value = pick(fileVars, name)\n\n if (value.length === 0) return null\n\n vars[name] = value\n }\n\n return vars\n}\n\n/**\n * Every name the env file defines that the spec does NOT list.\n *\n * The child inherits this process's environment, and this process was launched from a shell\n * that had normally sourced the very file these came from \u2014 so without stripping them by name,\n * every production secret reaches the child by inheritance regardless of what the spec lists.\n */\nexport const readUnlistedNames = (names: readonly string[], filePath: string = resolveEnvFilePath()): string[] => {\n const listed = new Set(names)\n\n return Object.keys(parseVarsFromEnvFile(filePath)).filter((name) => {\n return !listed.has(name)\n })\n}\n", "/**\n * Newline framing for a JSON-RPC stdio stream.\n *\n * Deliberately not `node:readline`. That module is fenced off outside\n * `src/lib/prompts/` because it is the shape a future interactive stdin reader would\n * take, and the prompts module owns the stdin refcount. This is a transport, not a\n * prompt \u2014 but the fence has no exemptions and is worth more intact than this is worth\n * saving, and hand framing is a dozen lines with no buffering semantics to inherit.\n */\nexport const onEachLine = (stream: NodeJS.ReadableStream, visit: (line: string) => void): void => {\n let buffer = ''\n\n stream.setEncoding('utf8')\n stream.on('data', (chunk: string) => {\n buffer += chunk\n\n let boundary = buffer.indexOf('\\n')\n\n while (boundary !== -1) {\n const raw = buffer.slice(0, boundary)\n\n buffer = buffer.slice(boundary + 1)\n\n // A peer that writes CRLF must not hand us a trailing CR inside the JSON.\n const line = raw.endsWith('\\r') ? raw.slice(0, -1) : raw\n\n if (line.trim().length > 0) visit(line)\n\n boundary = buffer.indexOf('\\n')\n }\n })\n}\n", "import type { Buffer } from 'node:buffer'\nimport { spawn } from 'node:child_process'\nimport type { ChildProcessWithoutNullStreams } from 'node:child_process'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport type { ProxyVars } from './env-vars'\nimport { onEachLine } from './line-stream'\nimport { PROTECTED_CHILD_ENV_NAMES } from './protected-env'\n\nexport interface JsonRpcMessage {\n jsonrpc?: string\n id?: string | number\n method?: string\n params?: unknown\n result?: unknown\n error?: { code: number; message: string }\n}\n\n/**\n * What one configured server is: the argv-borne half of an `mcp.<name>` entry.\n *\n * `env` names are injected inline from {@link ProxyVars}; `unset` names are forced empty so a stale\n * file-based credential can never outrank the inline one (measured for mcp-grafana: an inline token\n * takes precedence over `..._TOKEN_FILE`, but only if the file variable is not also set).\n */\nexport interface ProxySpec {\n name: string\n command: string\n args: readonly string[]\n env: readonly string[]\n unset: readonly string[]\n}\n\nexport interface UpstreamOptions {\n extraEnv?: NodeJS.ProcessEnv\n readyTimeoutMs?: number\n /**\n * Per-request ceiling. A child that answers the handshake and then goes silent must\n * not hang every later request for the rest of the session.\n */\n requestTimeoutMs?: number\n /**\n * Names to DELETE from the child's inherited environment \u2014 the unlisted secrets the\n * launching shell picked up from the same env file.\n */\n stripFromChildEnv?: () => readonly string[]\n log?: (message: string) => void\n /** Notifications and server-initiated requests, which travel to the client verbatim. */\n onServerMessage?: (message: JsonRpcMessage) => void\n}\n\n/** `go install` lands the binary in GOBIN, which a GUI-launched process never has on PATH. */\nconst goBinDir = (): string => {\n const explicit = process.env.GOBIN\n\n if (explicit != null && explicit.length > 0) return explicit\n\n const goPath = process.env.GOPATH\n\n return path.join(goPath != null && goPath.length > 0 ? goPath : path.join(os.homedir(), 'go'), 'bin')\n}\n\nconst DEFAULT_READY_TIMEOUT_MS = 15_000\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000\n\nconst NEVER_STRIP = PROTECTED_CHILD_ENV_NAMES\n\ninterface Deferred {\n /** Absent for the shim's OWN requests, whose answers must never reach the client. */\n clientId?: string | number\n resolve: (message: JsonRpcMessage) => void\n reject: (error: Error) => void\n}\n\ninterface Session {\n child: ChildProcessWithoutNullStreams\n /** JSON of the ordered vars record \u2014 the respawn key. */\n key: string\n generation: number\n pending: Map<number, Deferred>\n nextId: number\n handshake: JsonRpcMessage | null\n closed: boolean\n}\n\nexport interface Upstream {\n setInitializeParams: (params: unknown) => void\n request: (message: JsonRpcMessage, vars: ProxyVars) => Promise<JsonRpcMessage>\n /** Forwards only when an upstream already exists; never spawns one. */\n notifyIfActive: (message: JsonRpcMessage) => boolean\n /** The upstream's own `initialize` result, once one has been observed. */\n handshake: () => JsonRpcMessage | null\n dispose: () => void\n}\n\nexport const createUpstream = (spec: ProxySpec, options: UpstreamOptions = {}): Upstream => {\n const binary = spec.command\n const args = spec.args\n const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS\n const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n const log = options.log ?? ((): void => {})\n const onServerMessage = options.onServerMessage ?? ((): void => {})\n\n const searchPath = `${goBinDir()}${path.delimiter}${process.env.PATH ?? ''}`\n\n let initializeParams: unknown = {}\n let active: Session | null = null\n let starting: { key: string; generation: number; promise: Promise<Session> } | null = null\n let generation = 0\n\n const failPending = (session: Session, reason: string): void => {\n for (const deferred of session.pending.values()) deferred.reject(new Error(reason))\n session.pending.clear()\n }\n\n const closeSession = (session: Session, reason: string): void => {\n if (session.closed) return\n\n session.closed = true\n // In-flight work is ERRORED, never silently dropped: a caller waiting on a killed\n // upstream would otherwise hang for the rest of the session.\n failPending(session, `${spec.name} upstream ${reason}`)\n session.child.kill()\n }\n\n // A response carries an id and no method; anything with a method is server-initiated\n // and belongs to the client. Routing on `method` first is what keeps the shim's own\n // ids from ever being confused with the client's.\n const handleLine = (session: Session, line: string): void => {\n let message: JsonRpcMessage\n\n try {\n message = JSON.parse(line) as JsonRpcMessage\n } catch {\n log(`ignoring non-JSON line from ${binary}`)\n\n return\n }\n\n if (message.method != null) {\n if (message.id == null) {\n onServerMessage(message)\n\n return\n }\n\n // A server-initiated REQUEST carries the upstream's own id. Relaying it would send\n // the client an id from a namespace it does not own, and the client's answer would\n // re-enter as a fresh request with no method. mcp-grafana initiates none today, so\n // refusing is honest and cannot mis-route.\n log(`refusing server-initiated request ${message.method}`)\n send(session, {\n jsonrpc: '2.0',\n id: message.id,\n error: { code: -32601, message: 'client requests are not supported by this shim' },\n })\n\n return\n }\n\n if (message.id == null) return\n\n const deferred = session.pending.get(Number(message.id))\n\n if (!deferred) return\n\n session.pending.delete(Number(message.id))\n\n // Map back: the client only ever sees the id IT chose. Resolving with the wire id\n // would hand the client an answer labelled with the shim's private numbering.\n deferred.resolve(deferred.clientId === undefined ? message : { ...message, id: deferred.clientId })\n }\n\n const send = (session: Session, message: JsonRpcMessage): void => {\n if (session.closed) return\n\n session.child.stdin.write(`${JSON.stringify(message)}\\n`)\n }\n\n /**\n * Send on the shim's OWN id namespace and await the answer.\n *\n * `clientId` is what makes the namespace real: present, the answer is re-labelled and\n * relayed; absent, it is consumed here. The replayed handshake takes the absent form,\n * so a client request numbered `0` can never collide with it.\n */\n const sendRequest = (\n session: Session,\n message: JsonRpcMessage,\n clientId?: string | number,\n ): Promise<JsonRpcMessage> => {\n // A session can be closed between `ensure` resolving and the write landing \u2014 a\n // dispose, a crash, a swap. Registering here anyway would leave the caller pending\n // forever, because the rejection sweep has already run.\n if (session.closed) return Promise.reject(new Error(`${spec.name} upstream is closed`))\n\n const upstreamId = session.nextId\n\n session.nextId += 1\n\n return new Promise<JsonRpcMessage>((resolve, reject) => {\n const timer = setTimeout(() => {\n session.pending.delete(upstreamId)\n reject(new Error(`${binary} did not answer ${message.method ?? 'request'} within ${requestTimeoutMs}ms`))\n }, requestTimeoutMs)\n\n session.pending.set(upstreamId, {\n clientId,\n resolve: (answer: JsonRpcMessage): void => {\n clearTimeout(timer)\n resolve(answer)\n },\n reject: (error: Error): void => {\n clearTimeout(timer)\n reject(error)\n },\n })\n send(session, { ...message, jsonrpc: '2.0', id: upstreamId })\n })\n }\n\n const withDeadline = async (promise: Promise<JsonRpcMessage>): Promise<JsonRpcMessage> => {\n let timer: NodeJS.Timeout | undefined\n\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(new Error(`${binary} did not answer initialize within ${readyTimeoutMs}ms`))\n }, readyTimeoutMs)\n })\n\n try {\n return await Promise.race([promise, deadline])\n } finally {\n if (timer) clearTimeout(timer)\n }\n }\n\n const spawnChild = (vars: ProxyVars): ChildProcessWithoutNullStreams => {\n // Listed variables go INLINE \u2014 no credential is written to disk by this proxy at all.\n const childEnv: NodeJS.ProcessEnv = { ...process.env, ...options.extraEnv, PATH: searchPath, ...vars }\n\n // Forced empty rather than deleted: a deleted name would be re-inherited by anything the\n // child spawns from ITS parent's environment; an empty string is an explicit \"no\".\n for (const name of spec.unset) childEnv[name] = ''\n\n // Applied LAST, over the fully merged environment, so no earlier layer can put a\n // secret back. The proxy is normally launched from a shell that sourced the very env\n // file these names came from, and inheritance \u2014 not the listed-names read filter \u2014 is\n // the path by which a production secret would otherwise reach the child.\n for (const name of options.stripFromChildEnv?.() ?? []) {\n if (!NEVER_STRIP.has(name)) delete childEnv[name]\n }\n\n return spawn(binary, [...args], {\n env: childEnv,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as ChildProcessWithoutNullStreams\n }\n\n const startSession = async (vars: ProxyVars, gen: number): Promise<Session> => {\n const child = spawnChild(vars)\n\n const session: Session = {\n child,\n key: JSON.stringify(vars),\n generation: gen,\n pending: new Map(),\n nextId: 1,\n handshake: null,\n closed: false,\n }\n\n onEachLine(child.stdout, (line) => {\n handleLine(session, line)\n })\n\n child.stderr.on('data', (chunk: Buffer) => {\n // Per LINE, not per chunk: mcp-grafana emits several log lines in one write, and\n // prefixing only the first leaves the rest looking like they came from elsewhere \u2014\n // which matters, because this is the only window into the upstream a user gets.\n for (const line of chunk.toString().trimEnd().split('\\n')) {\n if (line.length > 0) log(`${binary}: ${line}`)\n }\n })\n\n child.on('error', (error: Error) => {\n closeSession(session, `failed to start: ${error.message}`)\n })\n\n child.on('exit', (code) => {\n closeSession(session, `exited with code ${String(code)}`)\n })\n\n try {\n // A child that spawns and never answers must not hang every later request, so the\n // handshake \u2014 not the spawn \u2014 is what readiness means, and it is bounded.\n session.handshake = await withDeadline(sendRequest(session, { method: 'initialize', params: initializeParams }))\n } catch (error) {\n closeSession(session, 'handshake failed')\n throw error\n }\n\n send(session, { jsonrpc: '2.0', method: 'notifications/initialized' })\n log(`serving ${spec.name} (${binary})`)\n\n return session\n }\n\n const ensure = async (vars: ProxyVars): Promise<Session> => {\n const key = JSON.stringify(vars)\n\n if (active && !active.closed && active.key === key) return active\n if (starting && starting.key === key) return starting.promise\n\n generation += 1\n\n const gen = generation\n\n // Which variable changed is deliberately not logged: the values are credentials.\n if (active) log(`${spec.name}: a listed variable changed \u2014 replacing upstream`)\n\n const promise = (async (): Promise<Session> => {\n const session = await startSession(vars, gen)\n\n // A newer target superseded this start while it was in flight. Binding to it now\n // would serve the OLD credentials for the rest of the session.\n if (gen !== generation) {\n closeSession(session, 'superseded by a newer target')\n throw new Error(`${spec.name} upstream superseded by a newer target`)\n }\n\n if (active) closeSession(active, 'replaced')\n active = session\n\n return session\n })()\n\n starting = { key, generation: gen, promise }\n\n try {\n return await promise\n } finally {\n if (starting?.generation === gen) starting = null\n }\n }\n\n return {\n setInitializeParams: (params: unknown): void => {\n initializeParams = params\n },\n request: async (message: JsonRpcMessage, vars: ProxyVars): Promise<JsonRpcMessage> => {\n const session = await ensure(vars)\n\n return sendRequest(session, { method: message.method, params: message.params }, message.id)\n },\n notifyIfActive: (message: JsonRpcMessage): boolean => {\n // Deliberately does NOT call `ensure`. A client notification arriving before any\n // request would otherwise spawn an upstream for a session that has asked the\n // server nothing \u2014 which is exactly what lazy start exists to avoid.\n if (!active || active.closed) return false\n\n send(active, { jsonrpc: '2.0', method: message.method, params: message.params })\n\n return true\n },\n handshake: (): JsonRpcMessage | null => {\n return active?.handshake ?? null\n },\n dispose: (): void => {\n if (active) closeSession(active, 'disposed')\n active = null\n },\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\n// The hashbang must stay on line 1: this entry is published as the `ik-mcp` bin and is exec'd\n// directly by the MCP client, not invoked as `node dist/mcp-proxy.js`.\nimport process from 'node:process'\n\nimport { bootPortlessLink } from 'src/dev/proxy/portless-link'\nimport { parseProxyArgv } from 'src/lib/mcp-proxy/argv'\nimport { proxyCacheDir, readBinaryVersion, readProfile, writeProfile } from 'src/lib/mcp-proxy/cache'\nimport type { UpstreamProfile } from 'src/lib/mcp-proxy/cache'\nimport { readListedVars, readUnlistedNames, resolveEnvFilePath } from 'src/lib/mcp-proxy/env-vars'\nimport type { ProxyVars } from 'src/lib/mcp-proxy/env-vars'\nimport { onEachLine } from 'src/lib/mcp-proxy/line-stream'\nimport { createUpstream } from 'src/lib/mcp-proxy/upstream'\nimport type { JsonRpcMessage, ProxySpec, Upstream } from 'src/lib/mcp-proxy/upstream'\n\nconst CREDENTIAL_POLL_MS = Number(process.env.IK_MCP_POLL_MS ?? 2000)\n\n/**\n * Answered on a cold cache, when no upstream has ever been observed on this machine. Pinned rather\n * than echoed from the client: echoing back whatever a client asks for claims support for a\n * revision nothing here has ever spoken. Only `tools` is claimed \u2014 every MCP server has tools, not\n * every one has resources, and claiming `resources` for one that lacks them makes a client issue\n * `resources/list` and get \"method not found\".\n */\nconst FALLBACK_PROTOCOL_VERSION = '2025-06-18'\nconst FALLBACK_CAPABILITIES = { tools: { listChanged: true } }\n\nconst log = (message: string): void => {\n process.stderr.write(`ik-mcp: ${message}\\n`)\n}\n\nconst write = (payload: JsonRpcMessage): void => {\n process.stdout.write(`${JSON.stringify(payload)}\\n`)\n}\n\n// This bin is the process Claude Code keeps alive, so it is where `~/.infra-kit/portless` converges on\n// a machine that only ever runs the MCP surface. fs-only and synchronous \u2014 nothing is spawned before the\n// handshake \u2014 and stdout is the transport, so only a failure earns a stderr line; the ordinary outcomes\n// are `doctor`'s to show.\nbootPortlessLink((result, message) => {\n if (result.outcome === 'failed')\n log(\n result.kind === 'link'\n ? `${message} failed: ${result.link} -> ${result.target}`\n : `${message} failed: ${result.node} <- ${result.source}`,\n )\n})\n\nconst parsed = parseProxyArgv(process.argv.slice(2))\n\n/**\n * Bad argv is the same state as \"no credentials yet\", not a crash: the handshake is answered, the\n * tool list is empty, and every other request says what is wrong and how to fix it. A proxy that\n * exits on a typo in `.mcp.json` is a dead server the client cannot recover.\n */\nconst degraded: string | null = parsed.ok\n ? null\n : `${parsed.problem} \u2014 run \\`ik setup\\` to regenerate this .mcp.json entry`\nconst spec: ProxySpec | null = parsed.ok ? parsed.spec : null\n\nconst upstream: Upstream | null =\n spec === null\n ? null\n : createUpstream(spec, {\n log,\n // Server-initiated notifications belong to the client and travel verbatim.\n onServerMessage: write,\n // Everything the launching shell picked up from the same env file, minus the listed names,\n // is deleted from the child's inherited environment.\n stripFromChildEnv: () => {\n return readUnlistedNames(spec.env)\n },\n })\n\nconst readVars = (): ProxyVars | null => {\n return spec === null ? null : readListedVars(spec.env)\n}\n\n// Both are resolved on first use, never at module load: `readBinaryVersion` spawns a process and\n// can block for up to its timeout, and doing that before stdin is wired delays the handshake of\n// every session \u2014 including ones that never touch the upstream.\nlet versionCache: string | null = null\nlet profileCache: UpstreamProfile | null | undefined\n\nconst binaryVersion = (): string => {\n versionCache ??=\n // No spec means no upstream to ask, and importing package.json for a version string would drag\n // the whole manifest \u2014 dependency names included \u2014 into a bundle the guard keeps flat.\n spec === null ? 'unknown' : readBinaryVersion(spec.command, ['--version'], process.env.PATH)\n\n return versionCache\n}\n\nconst cacheDir = (): string | null => {\n return spec === null ? null : proxyCacheDir(spec.name)\n}\n\nconst profile = (): UpstreamProfile | null => {\n if (profileCache === undefined) {\n const dir = cacheDir()\n\n profileCache = dir === null ? null : readProfile(binaryVersion(), dir)\n }\n\n return profileCache\n}\n\n/** Fold whatever the live upstream just told us into the on-disk profile. */\nconst rememberProfile = (patch: Partial<UpstreamProfile>): void => {\n const dir = cacheDir()\n\n if (dir === null) return\n\n const current = profile()\n\n const next: UpstreamProfile = {\n version: binaryVersion(),\n protocolVersion: patch.protocolVersion ?? current?.protocolVersion ?? FALLBACK_PROTOCOL_VERSION,\n capabilities: patch.capabilities ?? current?.capabilities ?? FALLBACK_CAPABILITIES,\n tools: patch.tools ?? current?.tools ?? [],\n }\n\n profileCache = next\n writeProfile(next, dir)\n}\n\n/**\n * Answer `initialize` without spawning anything.\n *\n * Spawning here would forfeit lazy start \u2014 a session that never touches the upstream would still\n * pay for a child. The cost is that a first-ever session reports the pinned fallback capabilities\n * and is corrected once a real handshake has been seen; MCP has no capability-change notification,\n * so that correction lands on the NEXT session.\n */\nconst answerInitialize = (message: JsonRpcMessage): void => {\n write({\n jsonrpc: '2.0',\n id: message.id,\n result: {\n protocolVersion: profile()?.protocolVersion ?? FALLBACK_PROTOCOL_VERSION,\n capabilities: profile()?.capabilities ?? FALLBACK_CAPABILITIES,\n serverInfo: { name: spec?.name ?? 'ik-mcp', version: binaryVersion() },\n },\n })\n}\n\nlet announced = false\n\n/**\n * Credentials arrive mid-session, and stdio keeps a server-to-client channel open the whole time \u2014\n * so the moment they appear the client can be told to list again. Polls the env file ONLY: there is\n * no config to poll, so there is no mid-edit \"invalid config\" window and no path by which a watcher\n * could tear down a live upstream.\n */\nconst watchForCredentials = (): void => {\n const timer = setInterval(() => {\n if (announced || readVars() === null) return\n\n announced = true\n clearInterval(timer)\n log('credentials appeared \u2014 announcing tools/list_changed')\n write({ jsonrpc: '2.0', method: 'notifications/tools/list_changed' })\n }, CREDENTIAL_POLL_MS)\n\n timer.unref()\n}\n\nconst forwardToolsList = async (message: JsonRpcMessage, vars: ProxyVars): Promise<void> => {\n const response = await upstream!.request(message, vars)\n const tools = (response.result as { tools?: unknown[] } | undefined)?.tools\n\n if (Array.isArray(tools)) {\n const handshake = upstream!.handshake()?.result as { protocolVersion?: string; capabilities?: unknown } | undefined\n\n rememberProfile({ tools, capabilities: handshake?.capabilities, protocolVersion: handshake?.protocolVersion })\n }\n\n write(response)\n}\n\n/** Before credentials exist, the tool list is answered from cache \u2014 never with an error. */\nconst answerToolsListFromCache = (message: JsonRpcMessage): void => {\n write({ jsonrpc: '2.0', id: message.id, result: { tools: profile()?.tools ?? [] } })\n}\n\n/** Answers the handshake and arms the watcher; deliberately spawns nothing. */\nconst handleInitialize = (message: JsonRpcMessage): void => {\n upstream?.setInitializeParams(message.params)\n answerInitialize(message)\n\n if (degraded !== null) {\n log(`degraded: ${degraded}`)\n\n return\n }\n\n // Always name the resolved path and the spec: when either is wrong (a stale XDG_CACHE_HOME, a\n // session id the client never inherited, a drifted .mcp.json) nothing else in the session says so.\n // Names only \u2014 the VALUES are credentials.\n log(\n `${spec!.name}: env file ${resolveEnvFilePath()}; reads ${spec!.env.join(', ')}; upstream ${spec!.command} ${binaryVersion()}; cache ${profile() ? 'warm' : 'cold'}`,\n )\n\n if (readVars() !== null) {\n announced = true\n\n return\n }\n\n log('no credentials yet \u2014 deferring')\n watchForCredentials()\n}\n\n/** The pre-`env-load` state (or bad argv), which is normal and must never look like a protocol failure. */\nconst answerWithoutCredentials = (message: JsonRpcMessage): void => {\n if (message.method === 'tools/list') {\n answerToolsListFromCache(message)\n\n return\n }\n\n if (message.id == null) return\n\n write({\n jsonrpc: '2.0',\n id: message.id,\n error: {\n code: -32000,\n message:\n degraded ?? `${spec!.name}: credentials are not loaded yet (${spec!.env.join(', ')}) \u2014 run 'ik env-load'`,\n },\n })\n}\n\nconst handle = async (message: JsonRpcMessage): Promise<void> => {\n // An id with no method is a RESPONSE, not a request. A well-behaved client sends none \u2014 the\n // proxy refuses server-initiated requests, so there is nothing to answer \u2014 and treating one as a\n // request would spawn an upstream and reply `no method undefined`.\n if (message.method == null) return\n\n if (message.method === 'initialize') {\n handleInitialize(message)\n\n return\n }\n\n const vars = readVars()\n\n if (vars === null || upstream === null) {\n answerWithoutCredentials(message)\n\n return\n }\n\n if (message.id == null) {\n // Never spawns. `notifications/initialized` in particular is answered by not relaying it at\n // all: every child gets its own from the handshake replay, and forwarding the client's would\n // make the mandatory handshake defeat lazy start.\n if (message.method !== 'notifications/initialized') upstream.notifyIfActive(message)\n\n return\n }\n\n if (message.method === 'tools/list') {\n await forwardToolsList(message, vars)\n\n return\n }\n\n write(await upstream.request(message, vars))\n}\n\nconst onLine = (line: string): void => {\n let message: JsonRpcMessage\n\n try {\n message = JSON.parse(line) as JsonRpcMessage\n } catch {\n log('ignoring non-JSON line from client')\n\n return\n }\n\n handle(message).catch((error: unknown) => {\n const detail = error instanceof Error ? error.message : String(error)\n\n log(detail)\n\n if (message.id != null) {\n write({ jsonrpc: '2.0', id: message.id, error: { code: -32000, message: detail } })\n }\n })\n}\n\nprocess.on('exit', () => {\n upstream?.dispose()\n})\nprocess.on('SIGTERM', () => {\n process.exit(0)\n})\nprocess.on('SIGINT', () => {\n process.exit(0)\n})\n\nonEachLine(process.stdin, onLine)\n\n// The client closing its end is the ordinary way this server ends.\nprocess.stdin.on('end', () => {\n process.exit(0)\n})\n", "import { PROTECTED_CHILD_ENV_NAMES } from './protected-env'\nimport type { ProxySpec } from './upstream'\n\n/** Mirrors the config schema's name rule; re-checked here because the name becomes a cache subdir. */\nconst NAME_PATTERN = /^[a-z][a-z0-9-]*$/\n/** Mirrors `envVarName` in the config schema. */\nconst ENV_VAR_PATTERN = /^[A-Z_]\\w*$/i\n\nexport type ParsedArgv = { ok: true; spec: ProxySpec } | { ok: false; problem: string }\n\ninterface Flags {\n name: string | null\n env: string[]\n unset: string[]\n}\n\n/** Apply one `--flag value` pair, or say why it cannot be applied. */\nconst applyFlag = (flags: Flags, flag: string, value: string): string | null => {\n if (flag === '--name') {\n if (flags.name !== null) return '--name given twice'\n if (!NAME_PATTERN.test(value)) return `--name \"${value}\" must be lowercase letters, digits and hyphens`\n\n flags.name = value\n\n return null\n }\n\n if (flag === '--env' || flag === '--unset') {\n if (!ENV_VAR_PATTERN.test(value)) return `${flag} \"${value}\" is not an environment-variable name`\n // Mirrors the schema refinement, because hand-written argv (the `claude mcp add --scope local`\n // path) never passes through the schema \u2014 and `--unset PATH` would blank PATH and ENOENT the spawn.\n if (PROTECTED_CHILD_ENV_NAMES.has(value)) return `${flag} \"${value}\" is process plumbing, not a credential`\n\n if (flag === '--env') flags.env.push(value)\n else flags.unset.push(value)\n\n return null\n }\n\n return `unknown flag ${flag}`\n}\n\n/** Walk the flag half; returns the index of the `--` separator or a problem. */\nconst readFlags = (argv: readonly string[], flags: Flags): { separator: number } | { problem: string } => {\n let index = 0\n\n while (index < argv.length) {\n const flag = argv[index]!\n\n if (flag === '--') return { separator: index }\n\n // A bare word where a flag belongs is the upstream command arriving early \u2014 the separator\n // is what is missing, and that is the more useful thing to say than \"cmd needs a value\".\n if (!flag.startsWith('--')) return { problem: `missing \"--\" before the upstream command (saw \"${flag}\")` }\n\n const value = argv[index + 1]\n\n // A value that looks like a flag (`--env --`) would otherwise eat the separator and turn the\n // upstream command into a flag \u2014 the case that spawns the wrong binary instead of refusing.\n if (value === undefined || value.startsWith('--')) return { problem: `${flag} needs a value` }\n\n const problem = applyFlag(flags, flag, value)\n\n if (problem !== null) return { problem }\n\n index += 2\n }\n\n return { problem: 'missing \"--\" before the upstream command' }\n}\n\n/**\n * Parse the argv `ik setup` derived: `--name N (--env V)+ (--unset V)* -- <command> [args...]`.\n *\n * Every flag VALUE is validated, not only `--name`. The first `--` in flag position ends our half;\n * everything after it is the upstream's, verbatim, `--`s and all.\n */\n// Node builtins only, on purpose. Pulling commander in here would drag it into the proxy bundle,\n// which the chunk-isolation guard forbids \u2014 and a four-flag grammar does not need it.\nexport const parseProxyArgv = (argv: readonly string[]): ParsedArgv => {\n const flags: Flags = { name: null, env: [], unset: [] }\n const walked = readFlags(argv, flags)\n\n if ('problem' in walked) return { ok: false, problem: walked.problem }\n if (flags.name === null) return { ok: false, problem: 'missing --name' }\n if (flags.env.length === 0) return { ok: false, problem: 'missing --env (at least one variable to read)' }\n\n const command = argv[walked.separator + 1]\n\n if (command === undefined || command.length === 0)\n return { ok: false, problem: 'missing upstream command after \"--\"' }\n\n return {\n ok: true,\n spec: { name: flags.name, command, args: argv.slice(walked.separator + 2), env: flags.env, unset: flags.unset },\n }\n}\n", "import { spawnSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { atomicWriteFileSync, getCacheRoot } from 'src/lib/constants'\n\n/**\n * What a session can answer with before any child exists: the tool list and the\n * capability payload the upstream last reported.\n *\n * Capabilities are cached alongside the tools because MCP has no\n * capability-change notification \u2014 a deferred `initialize` must state them up front\n * and can never correct itself, so the honest answer has to come from disk.\n */\nexport interface UpstreamProfile {\n version: string\n protocolVersion: string\n capabilities: unknown\n tools: unknown[]\n}\n\n/**\n * Proxy state lives under the CACHE root, never `~/.infra-kit` \u2014 that is\n * `USER_CONFIG_DIR_NAME`, the auto-seeded project-config registry, where a\n * throwaway derived file has no business living. One subdir per configured name.\n */\nexport const proxyCacheDir = (name: string): string => {\n return path.join(getCacheRoot(), 'mcp-proxy', name)\n}\n\n/** Keeps a version string usable as one path segment. */\nconst safeSegment = (version: string): string => {\n return version.replaceAll(/[^\\w.-]/g, '_').slice(0, 64)\n}\n\nexport const profilePath = (version: string, dir: string): string => {\n return path.join(dir, `profile-${safeSegment(version)}.json`)\n}\n\n/**\n * A cache key for a binary that does not answer `--version`: its resolved path's size and mtime.\n *\n * Both change on every upgrade, which is all the key has to guarantee. Hashing the file would too,\n * but a Go binary is tens of megabytes and this runs at session start.\n */\nexport const binaryFingerprint = (binary: string, searchPath?: string): string => {\n const candidates = path.isAbsolute(binary)\n ? [binary]\n : (searchPath ?? process.env.PATH ?? '').split(path.delimiter).map((dir) => {\n return path.join(dir, binary)\n })\n\n for (const candidate of candidates) {\n try {\n const stat = fs.statSync(candidate)\n\n return `stat-${stat.size}-${Math.trunc(stat.mtimeMs)}`\n } catch {\n // not here; try the next PATH entry\n }\n }\n\n return 'unknown'\n}\n\n/**\n * The upstream binary's self-reported version, falling back to {@link binaryFingerprint}.\n * This is the cache key, so an upgrade that changes the tool set can never be served\n * a stale list \u2014 the new version simply looks at a different file.\n */\nexport const readBinaryVersion = (\n binary: string,\n versionArgs: readonly string[] = ['--version'],\n searchPath?: string,\n): string => {\n try {\n // The same PATH the upstream spawn uses. Without it, a `go install` layout \u2014 where\n // mcp-grafana lives only in GOBIN \u2014 probes as ENOENT, every version collapses into\n // one 'unknown' cache bucket, and an upgrade is served the previous tool list.\n const result = spawnSync(binary, [...versionArgs], {\n encoding: 'utf8',\n timeout: 5000,\n env: searchPath == null ? process.env : { ...process.env, PATH: searchPath },\n })\n\n if (result.status !== 0) return binaryFingerprint(binary, searchPath)\n\n const reported = `${result.stdout}`.trim().split('\\n')[0]?.trim() ?? ''\n\n return reported.length > 0 ? reported : binaryFingerprint(binary, searchPath)\n } catch {\n return binaryFingerprint(binary, searchPath)\n }\n}\n\n/**\n * The cached profile for this binary version, or null.\n *\n * Every failure is a null, never a throw: a torn or truncated file must degrade to\n * \"no cache yet\", because the alternative is an exception on the deferred\n * `initialize` path \u2014 which would kill the session the cache exists to rescue.\n */\nexport const readProfile = (version: string, dir: string): UpstreamProfile | null => {\n try {\n const parsed = JSON.parse(fs.readFileSync(profilePath(version, dir), 'utf8')) as Partial<UpstreamProfile>\n\n if (parsed.version !== version || !Array.isArray(parsed.tools)) return null\n\n return {\n version,\n protocolVersion: typeof parsed.protocolVersion === 'string' ? parsed.protocolVersion : '',\n capabilities: parsed.capabilities ?? {},\n tools: parsed.tools,\n }\n } catch {\n return null\n }\n}\n\n/**\n * Persist a profile. Best-effort: a cache that cannot be written is a slower next\n * session, not a broken one.\n */\nexport const writeProfile = (profile: UpstreamProfile, dir: string): boolean => {\n try {\n fs.mkdirSync(dir, { recursive: true })\n // Atomic, because two sessions can write this concurrently and a half-written\n // file reads back as \"no tools\" \u2014 a silently toolless session with no error.\n atomicWriteFileSync(profilePath(profile.version, dir), `${JSON.stringify(profile)}\\n`, 0o600)\n\n return true\n } catch {\n return false\n }\n}\n", "import path from 'node:path'\nimport process from 'node:process'\n\nimport { ENV_LOAD_FILE, INFRA_KIT_SESSION_VAR, getCacheRoot, parseVarsFromEnvFile } from 'src/lib/constants'\n\n/**\n * Session id used when the proxy inherits none. `getSessionCacheDir()` THROWS in that case,\n * which is correct for a command and fatal for a server \u2014 a proxy that throws at startup is a\n * dead MCP server, so it degrades to a fixed dir instead.\n */\nexport const NO_SESSION = 'no-session'\n\n/** Escape hatch for tests and for pointing the proxy at a hand-written file. */\nexport const ENV_FILE_OVERRIDE_VAR = 'IK_MCP_ENV_FILE'\n\n/** The listed variables' values, keyed by name, in the order the spec listed them. */\nexport type ProxyVars = Record<string, string>\n\nexport const resolveSessionId = (): string => {\n const session = process.env[INFRA_KIT_SESSION_VAR]\n\n return session != null && session.length > 0 ? session : NO_SESSION\n}\n\n/**\n * Where `ik env-load` writes for this session. Goes through `getCacheRoot()` so\n * `XDG_CACHE_HOME` is honoured \u2014 a hardcoded `~/.cache` would silently read a path\n * nothing ever writes on any box that sets it.\n */\nexport const resolveEnvFilePath = (): string => {\n const override = process.env[ENV_FILE_OVERRIDE_VAR]\n\n if (override != null && override.length > 0) return override\n\n return path.join(getCacheRoot(), resolveSessionId(), ENV_LOAD_FILE)\n}\n\n/** The file wins over the inherited environment, per name. */\nconst pick = (fileVars: Record<string, string>, name: string): string => {\n const fromFile = fileVars[name]\n\n if (fromFile != null && fromFile.length > 0) return fromFile\n\n const fromEnv = process.env[name]\n\n return fromEnv != null && fromEnv.length > 0 ? fromEnv : ''\n}\n\n/**\n * The values of `names`, or null while any of them is missing \u2014 the normal state before\n * `ik env-load` runs, which must never be an error.\n *\n * Built by iterating `names`, not the file, so the record's key order \u2014 and therefore its\n * JSON, which is the respawn key \u2014 is stable however Doppler happens to order the file.\n */\nexport const readListedVars = (names: readonly string[], filePath: string = resolveEnvFilePath()): ProxyVars | null => {\n const fileVars = parseVarsFromEnvFile(filePath)\n const vars: ProxyVars = {}\n\n for (const name of names) {\n const value = pick(fileVars, name)\n\n if (value.length === 0) return null\n\n vars[name] = value\n }\n\n return vars\n}\n\n/**\n * Every name the env file defines that the spec does NOT list.\n *\n * The child inherits this process's environment, and this process was launched from a shell\n * that had normally sourced the very file these came from \u2014 so without stripping them by name,\n * every production secret reaches the child by inheritance regardless of what the spec lists.\n */\nexport const readUnlistedNames = (names: readonly string[], filePath: string = resolveEnvFilePath()): string[] => {\n const listed = new Set(names)\n\n return Object.keys(parseVarsFromEnvFile(filePath)).filter((name) => {\n return !listed.has(name)\n })\n}\n", "/**\n * Newline framing for a JSON-RPC stdio stream.\n *\n * Deliberately not `node:readline`. That module is fenced off outside\n * `src/lib/prompts/` because it is the shape a future interactive stdin reader would\n * take, and the prompts module owns the stdin refcount. This is a transport, not a\n * prompt \u2014 but the fence has no exemptions and is worth more intact than this is worth\n * saving, and hand framing is a dozen lines with no buffering semantics to inherit.\n */\nexport const onEachLine = (stream: NodeJS.ReadableStream, visit: (line: string) => void): void => {\n let buffer = ''\n\n stream.setEncoding('utf8')\n stream.on('data', (chunk: string) => {\n buffer += chunk\n\n let boundary = buffer.indexOf('\\n')\n\n while (boundary !== -1) {\n const raw = buffer.slice(0, boundary)\n\n buffer = buffer.slice(boundary + 1)\n\n // A peer that writes CRLF must not hand us a trailing CR inside the JSON.\n const line = raw.endsWith('\\r') ? raw.slice(0, -1) : raw\n\n if (line.trim().length > 0) visit(line)\n\n boundary = buffer.indexOf('\\n')\n }\n })\n}\n", "import type { Buffer } from 'node:buffer'\nimport { spawn } from 'node:child_process'\nimport type { ChildProcessWithoutNullStreams } from 'node:child_process'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport type { ProxyVars } from './env-vars'\nimport { onEachLine } from './line-stream'\nimport { PROTECTED_CHILD_ENV_NAMES } from './protected-env'\n\nexport interface JsonRpcMessage {\n jsonrpc?: string\n id?: string | number\n method?: string\n params?: unknown\n result?: unknown\n error?: { code: number; message: string }\n}\n\n/**\n * What one configured server is: the argv-borne half of an `mcp.<name>` entry.\n *\n * `env` names are injected inline from {@link ProxyVars}; `unset` names are forced empty so a stale\n * file-based credential can never outrank the inline one (measured for mcp-grafana: an inline token\n * takes precedence over `..._TOKEN_FILE`, but only if the file variable is not also set).\n */\nexport interface ProxySpec {\n name: string\n command: string\n args: readonly string[]\n env: readonly string[]\n unset: readonly string[]\n}\n\nexport interface UpstreamOptions {\n extraEnv?: NodeJS.ProcessEnv\n readyTimeoutMs?: number\n /**\n * Per-request ceiling. A child that answers the handshake and then goes silent must\n * not hang every later request for the rest of the session.\n */\n requestTimeoutMs?: number\n /**\n * Names to DELETE from the child's inherited environment \u2014 the unlisted secrets the\n * launching shell picked up from the same env file.\n */\n stripFromChildEnv?: () => readonly string[]\n log?: (message: string) => void\n /** Notifications and server-initiated requests, which travel to the client verbatim. */\n onServerMessage?: (message: JsonRpcMessage) => void\n}\n\n/** `go install` lands the binary in GOBIN, which a GUI-launched process never has on PATH. */\nconst goBinDir = (): string => {\n const explicit = process.env.GOBIN\n\n if (explicit != null && explicit.length > 0) return explicit\n\n const goPath = process.env.GOPATH\n\n return path.join(goPath != null && goPath.length > 0 ? goPath : path.join(os.homedir(), 'go'), 'bin')\n}\n\nconst DEFAULT_READY_TIMEOUT_MS = 15_000\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000\n\nconst NEVER_STRIP = PROTECTED_CHILD_ENV_NAMES\n\ninterface Deferred {\n /** Absent for the shim's OWN requests, whose answers must never reach the client. */\n clientId?: string | number\n resolve: (message: JsonRpcMessage) => void\n reject: (error: Error) => void\n}\n\ninterface Session {\n child: ChildProcessWithoutNullStreams\n /** JSON of the ordered vars record \u2014 the respawn key. */\n key: string\n generation: number\n pending: Map<number, Deferred>\n nextId: number\n handshake: JsonRpcMessage | null\n closed: boolean\n}\n\nexport interface Upstream {\n setInitializeParams: (params: unknown) => void\n request: (message: JsonRpcMessage, vars: ProxyVars) => Promise<JsonRpcMessage>\n /** Forwards only when an upstream already exists; never spawns one. */\n notifyIfActive: (message: JsonRpcMessage) => boolean\n /** The upstream's own `initialize` result, once one has been observed. */\n handshake: () => JsonRpcMessage | null\n dispose: () => void\n}\n\nexport const createUpstream = (spec: ProxySpec, options: UpstreamOptions = {}): Upstream => {\n const binary = spec.command\n const args = spec.args\n const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS\n const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n const log = options.log ?? ((): void => {})\n const onServerMessage = options.onServerMessage ?? ((): void => {})\n\n const searchPath = `${goBinDir()}${path.delimiter}${process.env.PATH ?? ''}`\n\n let initializeParams: unknown = {}\n let active: Session | null = null\n let starting: { key: string; generation: number; promise: Promise<Session> } | null = null\n let generation = 0\n\n const failPending = (session: Session, reason: string): void => {\n for (const deferred of session.pending.values()) deferred.reject(new Error(reason))\n session.pending.clear()\n }\n\n const closeSession = (session: Session, reason: string): void => {\n if (session.closed) return\n\n session.closed = true\n // In-flight work is ERRORED, never silently dropped: a caller waiting on a killed\n // upstream would otherwise hang for the rest of the session.\n failPending(session, `${spec.name} upstream ${reason}`)\n session.child.kill()\n }\n\n // A response carries an id and no method; anything with a method is server-initiated\n // and belongs to the client. Routing on `method` first is what keeps the shim's own\n // ids from ever being confused with the client's.\n const handleLine = (session: Session, line: string): void => {\n let message: JsonRpcMessage\n\n try {\n message = JSON.parse(line) as JsonRpcMessage\n } catch {\n log(`ignoring non-JSON line from ${binary}`)\n\n return\n }\n\n if (message.method != null) {\n if (message.id == null) {\n onServerMessage(message)\n\n return\n }\n\n // A server-initiated REQUEST carries the upstream's own id. Relaying it would send\n // the client an id from a namespace it does not own, and the client's answer would\n // re-enter as a fresh request with no method. mcp-grafana initiates none today, so\n // refusing is honest and cannot mis-route.\n log(`refusing server-initiated request ${message.method}`)\n send(session, {\n jsonrpc: '2.0',\n id: message.id,\n error: { code: -32601, message: 'client requests are not supported by this shim' },\n })\n\n return\n }\n\n if (message.id == null) return\n\n const deferred = session.pending.get(Number(message.id))\n\n if (!deferred) return\n\n session.pending.delete(Number(message.id))\n\n // Map back: the client only ever sees the id IT chose. Resolving with the wire id\n // would hand the client an answer labelled with the shim's private numbering.\n deferred.resolve(deferred.clientId === undefined ? message : { ...message, id: deferred.clientId })\n }\n\n const send = (session: Session, message: JsonRpcMessage): void => {\n if (session.closed) return\n\n session.child.stdin.write(`${JSON.stringify(message)}\\n`)\n }\n\n /**\n * Send on the shim's OWN id namespace and await the answer.\n *\n * `clientId` is what makes the namespace real: present, the answer is re-labelled and\n * relayed; absent, it is consumed here. The replayed handshake takes the absent form,\n * so a client request numbered `0` can never collide with it.\n */\n const sendRequest = (\n session: Session,\n message: JsonRpcMessage,\n clientId?: string | number,\n ): Promise<JsonRpcMessage> => {\n // A session can be closed between `ensure` resolving and the write landing \u2014 a\n // dispose, a crash, a swap. Registering here anyway would leave the caller pending\n // forever, because the rejection sweep has already run.\n if (session.closed) return Promise.reject(new Error(`${spec.name} upstream is closed`))\n\n const upstreamId = session.nextId\n\n session.nextId += 1\n\n return new Promise<JsonRpcMessage>((resolve, reject) => {\n const timer = setTimeout(() => {\n session.pending.delete(upstreamId)\n reject(new Error(`${binary} did not answer ${message.method ?? 'request'} within ${requestTimeoutMs}ms`))\n }, requestTimeoutMs)\n\n session.pending.set(upstreamId, {\n clientId,\n resolve: (answer: JsonRpcMessage): void => {\n clearTimeout(timer)\n resolve(answer)\n },\n reject: (error: Error): void => {\n clearTimeout(timer)\n reject(error)\n },\n })\n send(session, { ...message, jsonrpc: '2.0', id: upstreamId })\n })\n }\n\n const withDeadline = async (promise: Promise<JsonRpcMessage>): Promise<JsonRpcMessage> => {\n let timer: NodeJS.Timeout | undefined\n\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(new Error(`${binary} did not answer initialize within ${readyTimeoutMs}ms`))\n }, readyTimeoutMs)\n })\n\n try {\n return await Promise.race([promise, deadline])\n } finally {\n if (timer) clearTimeout(timer)\n }\n }\n\n const spawnChild = (vars: ProxyVars): ChildProcessWithoutNullStreams => {\n // Listed variables go INLINE \u2014 no credential is written to disk by this proxy at all.\n const childEnv: NodeJS.ProcessEnv = { ...process.env, ...options.extraEnv, PATH: searchPath, ...vars }\n\n // Forced empty rather than deleted: a deleted name would be re-inherited by anything the\n // child spawns from ITS parent's environment; an empty string is an explicit \"no\".\n for (const name of spec.unset) childEnv[name] = ''\n\n // Applied LAST, over the fully merged environment, so no earlier layer can put a\n // secret back. The proxy is normally launched from a shell that sourced the very env\n // file these names came from, and inheritance \u2014 not the listed-names read filter \u2014 is\n // the path by which a production secret would otherwise reach the child.\n for (const name of options.stripFromChildEnv?.() ?? []) {\n if (!NEVER_STRIP.has(name)) delete childEnv[name]\n }\n\n return spawn(binary, [...args], {\n env: childEnv,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as ChildProcessWithoutNullStreams\n }\n\n const startSession = async (vars: ProxyVars, gen: number): Promise<Session> => {\n const child = spawnChild(vars)\n\n const session: Session = {\n child,\n key: JSON.stringify(vars),\n generation: gen,\n pending: new Map(),\n nextId: 1,\n handshake: null,\n closed: false,\n }\n\n onEachLine(child.stdout, (line) => {\n handleLine(session, line)\n })\n\n child.stderr.on('data', (chunk: Buffer) => {\n // Per LINE, not per chunk: mcp-grafana emits several log lines in one write, and\n // prefixing only the first leaves the rest looking like they came from elsewhere \u2014\n // which matters, because this is the only window into the upstream a user gets.\n for (const line of chunk.toString().trimEnd().split('\\n')) {\n if (line.length > 0) log(`${binary}: ${line}`)\n }\n })\n\n child.on('error', (error: Error) => {\n closeSession(session, `failed to start: ${error.message}`)\n })\n\n child.on('exit', (code) => {\n closeSession(session, `exited with code ${String(code)}`)\n })\n\n try {\n // A child that spawns and never answers must not hang every later request, so the\n // handshake \u2014 not the spawn \u2014 is what readiness means, and it is bounded.\n session.handshake = await withDeadline(sendRequest(session, { method: 'initialize', params: initializeParams }))\n } catch (error) {\n closeSession(session, 'handshake failed')\n throw error\n }\n\n send(session, { jsonrpc: '2.0', method: 'notifications/initialized' })\n log(`serving ${spec.name} (${binary})`)\n\n return session\n }\n\n const ensure = async (vars: ProxyVars): Promise<Session> => {\n const key = JSON.stringify(vars)\n\n if (active && !active.closed && active.key === key) return active\n if (starting && starting.key === key) return starting.promise\n\n generation += 1\n\n const gen = generation\n\n // Which variable changed is deliberately not logged: the values are credentials.\n if (active) log(`${spec.name}: a listed variable changed \u2014 replacing upstream`)\n\n const promise = (async (): Promise<Session> => {\n const session = await startSession(vars, gen)\n\n // A newer target superseded this start while it was in flight. Binding to it now\n // would serve the OLD credentials for the rest of the session.\n if (gen !== generation) {\n closeSession(session, 'superseded by a newer target')\n throw new Error(`${spec.name} upstream superseded by a newer target`)\n }\n\n if (active) closeSession(active, 'replaced')\n active = session\n\n return session\n })()\n\n starting = { key, generation: gen, promise }\n\n try {\n return await promise\n } finally {\n if (starting?.generation === gen) starting = null\n }\n }\n\n return {\n setInitializeParams: (params: unknown): void => {\n initializeParams = params\n },\n request: async (message: JsonRpcMessage, vars: ProxyVars): Promise<JsonRpcMessage> => {\n const session = await ensure(vars)\n\n return sendRequest(session, { method: message.method, params: message.params }, message.id)\n },\n notifyIfActive: (message: JsonRpcMessage): boolean => {\n // Deliberately does NOT call `ensure`. A client notification arriving before any\n // request would otherwise spawn an upstream for a session that has asked the\n // server nothing \u2014 which is exactly what lazy start exists to avoid.\n if (!active || active.closed) return false\n\n send(active, { jsonrpc: '2.0', method: message.method, params: message.params })\n\n return true\n },\n handshake: (): JsonRpcMessage | null => {\n return active?.handshake ?? null\n },\n dispose: (): void => {\n if (active) closeSession(active, 'disposed')\n active = null\n },\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["process", "NAME_PATTERN", "ENV_VAR_PATTERN", "applyFlag", "flags", "flag", "value", "PROTECTED_CHILD_ENV_NAMES", "readFlags", "argv", "index", "problem", "parseProxyArgv", "walked", "command", "spawnSync", "fs", "path", "process", "proxyCacheDir", "name", "path", "getCacheRoot", "safeSegment", "version", "profilePath", "dir", "binaryFingerprint", "binary", "searchPath", "candidates", "process", "candidate", "stat", "fs", "readBinaryVersion", "versionArgs", "result", "spawnSync", "reported", "readProfile", "parsed", "writeProfile", "profile", "atomicWriteFileSync", "path", "process", "NO_SESSION", "ENV_FILE_OVERRIDE_VAR", "resolveSessionId", "session", "process", "INFRA_KIT_SESSION_VAR", "resolveEnvFilePath", "override", "path", "getCacheRoot", "ENV_LOAD_FILE", "pick", "fileVars", "name", "fromFile", "fromEnv", "readListedVars", "names", "filePath", "parseVarsFromEnvFile", "vars", "value", "readUnlistedNames", "listed", "onEachLine", "stream", "visit", "buffer", "chunk", "boundary", "raw", "line", "spawn", "os", "path", "process", "goBinDir", "explicit", "process", "goPath", "path", "os", "DEFAULT_READY_TIMEOUT_MS", "DEFAULT_REQUEST_TIMEOUT_MS", "NEVER_STRIP", "PROTECTED_CHILD_ENV_NAMES", "createUpstream", "spec", "options", "binary", "args", "readyTimeoutMs", "requestTimeoutMs", "log", "onServerMessage", "searchPath", "initializeParams", "active", "starting", "generation", "failPending", "session", "reason", "deferred", "closeSession", "handleLine", "line", "message", "send", "sendRequest", "clientId", "upstreamId", "resolve", "reject", "timer", "answer", "error", "withDeadline", "promise", "deadline", "_resolve", "spawnChild", "vars", "childEnv", "name", "spawn", "startSession", "gen", "child", "onEachLine", "chunk", "code", "ensure", "key", "params", "CREDENTIAL_POLL_MS", "process", "FALLBACK_PROTOCOL_VERSION", "FALLBACK_CAPABILITIES", "log", "message", "write", "payload", "bootPortlessLink", "result", "parsed", "parseProxyArgv", "degraded", "spec", "upstream", "createUpstream", "readUnlistedNames", "readVars", "readListedVars", "versionCache", "profileCache", "binaryVersion", "readBinaryVersion", "cacheDir", "proxyCacheDir", "profile", "dir", "readProfile", "rememberProfile", "patch", "current", "next", "writeProfile", "answerInitialize", "announced", "watchForCredentials", "timer", "forwardToolsList", "vars", "response", "tools", "handshake", "answerToolsListFromCache", "handleInitialize", "resolveEnvFilePath", "answerWithoutCredentials", "handle", "onLine", "line", "error", "detail", "onEachLine"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{l as t,q as i}from"./chunk-JUNJK2YC.js";import"./chunk-AWFGP6GY.js";import"./chunk-MOVRKV3I.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{p as i}from"./chunk-GBPW4ERM.js";import"./chunk-AWFGP6GY.js";import{a as t}from"./chunk-LAHHNH3T.js";import"./chunk-ZZ7HCY2S.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
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/entry/update-check.ts"],
4
4
  "sourcesContent": ["/**\n * Background auto-update worker. Spawned detached by `maybeAutoUpdate` as\n * `node dist/update-check.js --parent-pid <pid>`, and NEVER run by a human.\n *\n * This is a dedicated bundle, a sibling of `dist/cli.js`, for the same reason `dist/mcp-proxy.js` is: booting\n * `cli.js` here would re-run commander, the command catalog, `warnIfLocalInstall()`, and\n * `maybeAutoUpdate()` itself as top-level side effects \u2014 the last of which would spawn another child,\n * and another. Importing nothing from `src/entry/cli.ts` is a hard invariant, guarded by a test.\n *\n * It carries NO hashbang: nothing execs it directly, and `dist-shebang.test.ts` asserts its absence.\n * It writes nothing to stdout (it is spawned with `stdio: 'ignore'`, so there is nowhere to write).\n */\nimport fs from 'node:fs'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\n\n// Deep import, not the `src/lib/update-check` barrel: the barrel re-exports `maybeAutoUpdate`, which would\n// drag the parent-side spawn path (and pino) into this worker's bundle for no reason.\nimport { runUpdateCheck } from 'src/lib/update-check/run-update-check'\n\nimport packageJson from '../../package.json' with { type: 'json' }\n\n/** `--parent-pid <pid>`, or undefined when absent/malformed (then we install without waiting). */\nconst parseParentPid = (argv: string[]): number | undefined => {\n const index = argv.indexOf('--parent-pid')\n\n if (index === -1) return undefined\n\n const pid = Number(argv[index + 1])\n\n return Number.isInteger(pid) && pid > 0 ? pid : undefined\n}\n\n/** The installed `dist/cli.js` beside this bundle \u2014 the path whose owning package manager we detect. */\nconst selfRealPath = (): string => {\n return fs.realpathSync(fileURLToPath(new URL('./cli.js', import.meta.url)))\n}\n\nconst main = async (): Promise<void> => {\n await runUpdateCheck(packageJson.version, {\n selfRealPath: selfRealPath(),\n parentPid: parseParentPid(process.argv),\n })\n}\n\n// A detached background worker must never surface a crash, a non-zero exit, or an unhandled rejection \u2014\n// there is no one to see it and nothing depends on it. `runUpdateCheck` already swallows its own\n// failures; this is the last line of defence around path resolution and JSON import.\nmain().catch(() => {\n process.exitCode = 0\n})\n"],
5
- "mappings": "uGAYA,OAAOA,MAAQ,UACf,OAAOC,MAAa,eACpB,OAAS,iBAAAC,MAAqB,WAS9B,IAAMC,EAAkBC,GAAuC,CAC7D,IAAMC,EAAQD,EAAK,QAAQ,cAAc,EAEzC,GAAIC,IAAU,GAAI,OAElB,IAAMC,EAAM,OAAOF,EAAKC,EAAQ,CAAC,CAAC,EAElC,OAAO,OAAO,UAAUC,CAAG,GAAKA,EAAM,EAAIA,EAAM,MAClD,EAGMC,EAAe,IACZC,EAAG,aAAaC,EAAc,IAAI,IAAI,WAAY,YAAY,GAAG,CAAC,CAAC,EAGtEC,EAAO,SAA2B,CACtC,MAAMC,EAAeC,EAAY,QAAS,CACxC,aAAcL,EAAa,EAC3B,UAAWJ,EAAeU,EAAQ,IAAI,CACxC,CAAC,CACH,EAKAH,EAAK,EAAE,MAAM,IAAM,CACjBG,EAAQ,SAAW,CACrB,CAAC",
5
+ "mappings": "wIAYA,OAAOA,MAAQ,UACf,OAAOC,MAAa,eACpB,OAAS,iBAAAC,MAAqB,WAS9B,IAAMC,EAAkBC,GAAuC,CAC7D,IAAMC,EAAQD,EAAK,QAAQ,cAAc,EAEzC,GAAIC,IAAU,GAAI,OAElB,IAAMC,EAAM,OAAOF,EAAKC,EAAQ,CAAC,CAAC,EAElC,OAAO,OAAO,UAAUC,CAAG,GAAKA,EAAM,EAAIA,EAAM,MAClD,EAGMC,EAAe,IACZC,EAAG,aAAaC,EAAc,IAAI,IAAI,WAAY,YAAY,GAAG,CAAC,CAAC,EAGtEC,EAAO,SAA2B,CACtC,MAAMC,EAAeC,EAAY,QAAS,CACxC,aAAcL,EAAa,EAC3B,UAAWJ,EAAeU,EAAQ,IAAI,CACxC,CAAC,CACH,EAKAH,EAAK,EAAE,MAAM,IAAM,CACjBG,EAAQ,SAAW,CACrB,CAAC",
6
6
  "names": ["fs", "process", "fileURLToPath", "parseParentPid", "argv", "index", "pid", "selfRealPath", "fs", "fileURLToPath", "main", "runUpdateCheck", "package_default", "process"]
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.10.0",
4
+ "version": "0.11.10",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
@@ -21,7 +21,7 @@
21
21
  "@inquirer/input": "^5.1.6",
22
22
  "@inquirer/password": "^5.2.2",
23
23
  "@inquirer/select": "^5.2.5",
24
- "@slip-stream-kit/config": "^0.10.0",
24
+ "@slip-stream-kit/config": "^0.11.10",
25
25
  "chalk": "^6.0.0",
26
26
  "chokidar": "^5.0.0",
27
27
  "commander": "^15.0.0",
@@ -36,7 +36,7 @@
36
36
  "zx": "^8.8.5"
37
37
  },
38
38
  "devDependencies": {
39
- "@slip-stream-kit/eslint-plugin": "0.10.0",
39
+ "@slip-stream-kit/eslint-plugin": "0.11.10",
40
40
  "@types/aws-lambda": "^8.10.163",
41
41
  "@types/react": "19.3.0",
42
42
  "@wl/eslint-config": "0.1.0",