infra-kit 0.3.13 → 0.3.15

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-KATIE633.js +247 -0
  3. package/dist/chunk-KATIE633.js.map +7 -0
  4. package/dist/chunk-MKMT6KQT.js +10 -0
  5. package/dist/chunk-MKMT6KQT.js.map +7 -0
  6. package/dist/chunk-OKO3DKIM.js +7 -0
  7. package/dist/{chunk-QLAQ7F4M.js.map → chunk-OKO3DKIM.js.map} +4 -4
  8. package/dist/{chunk-RVTI3AL2.js → chunk-VDBJ73LS.js} +5 -5
  9. package/dist/chunk-VDBJ73LS.js.map +7 -0
  10. package/dist/{chunk-DPCWCXJD.js → chunk-VFU2USJG.js} +2 -2
  11. package/dist/{chunk-DPCWCXJD.js.map → chunk-VFU2USJG.js.map} +2 -2
  12. package/dist/chunk-XR6HR4LL.js +6 -0
  13. package/dist/{chunk-SSBYKOHY.js.map → chunk-XR6HR4LL.js.map} +4 -4
  14. package/dist/chunk-YDW6324A.js +2 -0
  15. package/dist/chunk-YDW6324A.js.map +7 -0
  16. package/dist/cli.js +9 -9
  17. package/dist/cli.js.map +3 -3
  18. package/dist/dev-server.js +24 -32
  19. package/dist/dev-server.js.map +4 -4
  20. package/dist/dev-wizard-run-AU7SZJV7.js +2 -0
  21. package/dist/{dev-wizard-run-XM5L23UP.js.map → dev-wizard-run-AU7SZJV7.js.map} +1 -1
  22. package/dist/mcp.js +1 -1
  23. package/dist/mcp.js.map +4 -4
  24. package/dist/persistent-ink-dev-ui-QNFTO2B2.js +2 -0
  25. package/dist/persistent-ink-dev-ui-QNFTO2B2.js.map +7 -0
  26. package/dist/update-check.js +1 -1
  27. package/dist/update-check.js.map +1 -1
  28. package/package.json +28 -28
  29. package/readme.md +1 -1
  30. package/dist/chunk-2QJAIOPI.js +0 -2
  31. package/dist/chunk-2QJAIOPI.js.map +0 -7
  32. package/dist/chunk-LMAO6FEM.js +0 -238
  33. package/dist/chunk-LMAO6FEM.js.map +0 -7
  34. package/dist/chunk-QLAQ7F4M.js +0 -7
  35. package/dist/chunk-RVTI3AL2.js.map +0 -7
  36. package/dist/chunk-SHFPI4QA.js +0 -2
  37. package/dist/chunk-SHFPI4QA.js.map +0 -7
  38. package/dist/chunk-SSBYKOHY.js +0 -4
  39. package/dist/dev-wizard-run-XM5L23UP.js +0 -2
  40. package/dist/persistent-ink-dev-ui-PLLSRSGL.js +0 -2
  41. package/dist/persistent-ink-dev-ui-PLLSRSGL.js.map +0 -7
@@ -0,0 +1,2 @@
1
+ import{f as C,i as f,k as g}from"./chunk-OKO3DKIM.js";import{J as u,K as b,L as y,N as k,X as x,da as v}from"./chunk-XR6HR4LL.js";import{e as w}from"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import O from"@inquirer/checkbox";import _ from"@inquirer/confirm";import j,{Separator as I}from"@inquirer/select";import{loadDev as K}from"@slip-stream-kit/config/internal";import U from"node:path";import m from"node:process";var W=e=>e.split("/")[0],A=e=>new Map(e.apps.map(r=>[r.name,r])),D=e=>e.localCapable&&e.cloudCapable,N=(e,r,t)=>D(r)?t[`${e} ${r.path}`]??(r.cloudCapable?"cloud":"local"):r.localCapable?"local":"cloud",$=(e,r,t)=>{let a=new Set,o=new Map;for(let n of e){let s=r.get(W(n));for(let c of s?.backends??[]){o.set(c.packageName,c.ownerApp);for(let l of c.routes)N(n,l,t)==="local"&&a.add(c.packageName)}}return{localPkgs:a,ownerByPkg:o}},B=(e,r)=>{let t={},a=!1;for(let o of e?.backends??[]){let n=r.has(o.packageName);for(let s of o.routes){let c=s.localCapable&&n?"local":"cloud";t[s.path]=c,c==="cloud"&&(a=!0)}}return{overrides:t,anyCloud:a}},z=(e,r)=>{let t=A(r),a=e.targets.filter(p=>p.endsWith("/ui")),o=e.targets.filter(p=>p.endsWith("/api")),{localPkgs:n,ownerByPkg:s}=$(a,t,e.sources),c={},l=!1;for(let p of a){let{overrides:d,anyCloud:i}=B(t.get(W(p)),n);i&&(l=!0),c[p]=Object.keys(d).length>0?{proxy:d}:{}}for(let p of o)c[p]??={};for(let p of n){let d=s.get(p);d!=null&&(c[`${d}/api`]??={})}return{presetDef:{apps:c,cmux:e.cmux},anyCloudRoute:l,targetKeys:Object.keys(c).sort()}},M=(e,r)=>{let t=[`--target=${e.targetKeys.join(",")}`];return r.watch&&t.push("--watch"),r.cmux&&t.push("--cmux"),{flags:t.join(" ")}};var h={output:m.stderr,clearPromptOnDone:!0},q={select:e=>g(r=>j({message:e.message,choices:e.choices,default:e.default},r),h),checkbox:e=>g(r=>O({message:e.message,choices:e.choices},r),h),confirm:e=>g(r=>_({message:e.message,default:e.default},r),h)},E=(e,r)=>{let t=new Map;for(let[a,o]of Object.entries(e)){let n={path:a,localCapable:o.from.includes("local"),cloudCapable:o.from.includes("cloud"),default:o.default},s=t.get(o.packageName);s?(s.routes.push(n),s.localCapable=s.localCapable||n.localCapable,s.cloudCapable=s.cloudCapable||n.cloudCapable):t.set(o.packageName,{packageName:o.packageName,routes:[n],localCapable:n.localCapable,cloudCapable:n.cloudCapable,ownerApp:r.get(o.packageName)})}return[...t.values()]},T=async(e,r,t)=>{try{let a=(await K(e))?.proxy?.routes;return a?E(a,t):[]}catch(a){return u.warn(`\u26A0\uFE0F Skipping ${r}: its dev config failed to load \u2014 ${a instanceof Error?a.message:String(a)}`),[]}},V=async e=>{let r=y(e),t=k(e),a=await v(),o=new Map(r.map(i=>[i.packageName,i.name])),n=new Map(r.map(i=>[i.name,i.packageName])),s=new Set(t.map(i=>i.name)),c=new Set(r.map(i=>i.name)),l=[...new Set([...c,...s])].sort(),p=await Promise.all(l.map(async i=>{let P=s.has(i);return{name:i,hasApi:c.has(i),hasUi:P,apiPackage:n.get(i),backends:P?await T(U.join(e,"apps",i,"ui"),i,o):[]}})),d=await C();return{apps:p,presets:Object.keys(a.devServersPresets??{}),environments:Object.keys(d?.envs??{}).sort()}},F=e=>{let r=[];for(let t of e.apps){if(t.hasUi){let a=t.backends.flatMap(n=>n.routes.map(s=>s.path)),o=a.length>0?`frontend \u2014 proxies ${[...a].sort().join(", ")}`:"frontend";r.push({name:`${t.name}/ui`,value:`${t.name}/ui`,description:o})}t.hasApi&&!t.hasUi&&r.push({name:`${t.name}/api`,value:`${t.name}/api`,description:"backend"})}return r},L=e=>{let r={api:e.apps.filter(o=>o.hasApi).map(o=>o.name),ui:e.apps.filter(o=>o.hasUi).map(o=>o.name)},t={},a=new Map;for(let o of e.apps){o.apiPackage!=null&&(t[o.name]=o.apiPackage);for(let n of o.backends)for(let s of n.routes)a.set(`${o.name} ${s.path}`,n.packageName)}return{discovered:r,apiPkgByApp:t,routePkg:(o,n)=>a.get(`${o} ${n}`)}},X=(e,r)=>x({__wizard__:e},L(r)).map(t=>t.message),Z="INFRA_KIT_DEV_WIZARD_CMUX",H=()=>m.env[Z]==="1",G=async(e,r,t)=>{let a=new Map(r.apps.map(n=>[n.name,n])),o={};for(let n of t){let s=a.get(n.split("/")[0]);for(let c of s?.backends??[])for(let l of c.routes){if(!l.localCapable||!l.cloudCapable)continue;let p=await e.select({message:`\u{1F500} ${n} ${l.path} \u2192 local or cloud?`,choices:[{name:"local (this machine)",value:"local"},{name:"cloud",value:"cloud"}],default:l.default??"local"});o[`${n} ${l.path}`]=p}}return o},J=(e,r,t)=>e.apps.find(a=>a.name===r)?.backends.flatMap(a=>a.routes).find(a=>a.path===t),Q=(e,r)=>{let t=[];for(let[a,o]of Object.entries(e.presetDef.apps??{})){if(!a.endsWith("/ui")||!o.proxy)continue;let n=a.split("/")[0];for(let[s,c]of Object.entries(o.proxy)){let l=J(r,n,s),p=l&&l.localCapable&&l.cloudCapable?"":" (only option)";t.push(` ${a} ${s} \u2192 ${c}${p}`)}}if(t.length!==0){u.info("Resolved routes:");for(let a of[...t].sort())u.info(a)}},R=async(e,r)=>{if(r.apps.length===0)return u.warn("No apps discovered to run."),null;let t=await e.checkbox({message:"\u{1F4E6} Which packages?",choices:F(r)});if(t.length===0)return u.warn("No packages selected."),null;let a=t.filter(i=>i.endsWith("/ui")),o=await G(e,r,a),n=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1}),s=H()?await e.confirm({message:"\u{1F9E9} Run each app in its own cmux pane?",default:!1}):!1,c={targets:t,sources:o,watch:n,cmux:s},l=z(c,r);if(l.anyCloudRoute){if(r.environments.length===0)return u.warn("\u2601\uFE0F This selection routes to a cloud environment, but no environment token is loaded."),u.warn(" Run `infra-kit env-load` to add one, then re-run the wizard."),null;c.env=await e.select({message:"\u2601\uFE0F Point cloud routes at which environment?",choices:r.environments.map(i=>({name:i,value:i}))}),m.env[w]=c.env}let p=X(l.presetDef,r);if(p.length>0){u.warn("\u26A0\uFE0F Proxy audit found issues with this selection:");for(let i of p)u.warn(` \u2022 ${i}`);return null}Q(l,r),Y(l,c);let d=l.targetKeys.filter(i=>i.endsWith("/api")).map(i=>i.split("/")[0]);return s&&d.length>0?{include:d,presetDef:l.presetDef,watch:n,cmux:!0}:(s&&u.info("\u2139\uFE0F cmux needs at least one local backend (panes are backend-only) \u2014 running in-process instead."),{presetDef:l.presetDef,watch:n,cmux:!1})},Y=(e,r)=>{f.setInteractive();let t=M(e,r);f.addOption(t.flags,!0),f.print(),u.info("\u2139\uFE0F Prefer a short name? Save this selection as a devPreset and run `infra-kit dev <name>`.")},ee=async(e,r)=>{let t=await e.confirm({message:"\u{1F440} Rebuild & restart on save (watch)?",default:!1});return f.setInteractive(),f.addOption(r,!0),t&&f.addOption("--watch",!0),f.print(),{preset:r,watch:t,cmux:!1}},S=" manual",re=async(e,r)=>{if(r.presets.length===0)return R(e,r);let t=await e.select({message:"\u{1F680} Start from a preset, or configure manually?",choices:[...r.presets.map(a=>({name:a,value:a})),new I(" "),{name:"Manual (custom)\u2026",value:S}]});return t===S?R(e,r):ee(e,t)},be=async(e=q,r=b(m.cwd()))=>re(e,await V(r));export{S as MANUAL_CHOICE,Z as WIZARD_CMUX_VAR,X as auditManualPlan,q as defaultPrompts,V as gatherWizardModel,T as loadBackends,be as runDevWizard,re as runWizardFlow};
2
+ //# sourceMappingURL=dev-wizard-run-AU7SZJV7.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` / MCP 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 return withEscape((context) => {\n return inquirerSelect({ message: cfg.message, choices: cfg.choices, default: cfg.default }, context)\n }, promptContext)\n },\n checkbox: (cfg) => {\n return withEscape((context) => {\n return inquirerCheckbox({ message: cfg.message, choices: cfg.choices }, context)\n }, promptContext)\n },\n confirm: (cfg) => {\n return withEscape((context) => {\n return inquirerConfirm({ message: cfg.message, default: cfg.default }, context)\n }, promptContext)\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-cmux) \u2014 passed through as `options.presetDef`. */\n presetDef?: DevPreset\n /**\n * App-name include list for the cmux 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 * (cmux panes are opened per API app). Unset for the non-cmux manual path.\n */\n include?: string[]\n watch: boolean\n cmux: 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 cmux 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. `--cmux`\n * on the command line is a separate path and stays live either way.\n */\nexport const WIZARD_CMUX_VAR = 'INFRA_KIT_DEV_WIZARD_CMUX'\n\nconst asksCmux = (): boolean => {\n return process.env[WIZARD_CMUX_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 + cmux \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 cmux = asksCmux()\n ? await prompts.confirm({ message: '\uD83E\uDDE9 Run each app in its own cmux pane?', default: false })\n : false\n\n const selection: ManualSelection = { targets: selectedTargets, sources, watch, cmux }\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 // cmux 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 cmux run EVERY api app,\n // so a cmux run with no selected backends (e.g. an all-frontend selection) falls back to in-process.\n if (cmux && apiApps.length > 0) {\n return { include: apiApps, presetDef: plan.presetDef, watch, cmux: true }\n }\n\n if (cmux) {\n logger.info('\u2139\uFE0F cmux needs at least one local backend (panes are backend-only) \u2014 running in-process instead.')\n }\n\n return { presetDef: plan.presetDef, watch, cmux: 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, cmux: 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 cmux pane per app. */\n cmux: 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, cmux: false },\n * { apps: [{ name: 'client', hasApi: true, hasUi: true,\n * backends: [{ packageName: 'client-api', cloudCapable: true, localCapable: true,\n * routes: [{ path: '/api', localCapable: true, cloudCapable: true }],\n * ownerApp: 'client' }] }],\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, cmux: selection.cmux },\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] [--cmux]` 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.cmux) parts.push('--cmux')\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_CMUX_VAR", "asksCmux", "promptRouteSources", "prompts", "uiKeys", "sources", "key", "backend", "answer", "findRouteCap", "routePath", "recapSources", "plan", "lines", "source", "suffix", "line", "runManualBranch", "selectedTargets", "t", "watch", "cmux", "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.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a as d,aa as h,d as p,da as S,r as y}from"./chunk-LMAO6FEM.js";import"./chunk-SHFPI4QA.js";import{a as v}from"./chunk-DPCWCXJD.js";import"./chunk-LKKKDB6V.js";import{i as x}from"./chunk-QLAQ7F4M.js";import{A as l,B as c,X as g,c as u,z as a}from"./chunk-SSBYKOHY.js";import"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import{StdioServerTransport as O}from"@modelcontextprotocol/sdk/server/stdio.js";import E from"node:process";import n from"node:process";var C=e=>{n.on("SIGINT",()=>{e.info({msg:"Received SIGINT. Shutting down..."}),n.exit(0)}),n.on("SIGTERM",()=>{e.info({msg:"Received SIGTERM. Shutting down..."}),n.exit(0)}),n.on("uncaughtException",r=>{e.fatal({err:r,msg:"Uncaught Exception"}),e.error(`Uncaught Exception! Check ${a}. Shutting down...`),e.flush(),n.exit(1)}),n.on("unhandledRejection",(r,o)=>{e.fatal({reason:r,promise:o,msg:"Unhandled Rejection"}),e.error(`Unhandled Rejection! Check ${a}. Shutting down...`),e.flush(),n.exit(1)})};import{McpServer as H}from"@modelcontextprotocol/sdk/server/mcp.js";var T=async e=>{};var j="infra-kit://config",M="infra-kit://dev-context",b={loadConfig:g,readDevContext:()=>p()},m=(e,r)=>({contents:[{uri:e,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}),R=async(e,r=b)=>{e.registerResource("infra-kit-config",j,{title:"infra-kit config",description:"The merged infra-kit.json configuration (all override layers applied). Read-only.",mimeType:"application/json"},async o=>{try{return m(o.toString(),await r.loadConfig())}catch(t){return m(o.toString(),{error:t instanceof Error?t.message:String(t)})}}),e.registerResource("infra-kit-dev-context",M,{title:"infra-kit dev context",description:"What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.",mimeType:"application/json"},o=>m(o.toString(),r.readDevContext()))};var D=e=>typeof e=="object"&&e!==null&&e.confirm===!0,I=(e,r)=>{let o=typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).filter(([s])=>s!=="confirm")):{},t={status:"confirmation_required",tool:e,resolvedArgs:o,message:`${e} mutates external state and is gated. It was NOT executed. Re-call ${e} with the same arguments plus "confirm": true to execute.`};return{content:d(JSON.stringify(t,null,2)),structuredContent:t,isError:!0}},f=({toolName:e,handler:r,requiresHumanConfirm:o})=>async t=>{c.info({msg:`Tool execution started: ${e}`,params:t});try{if(await y(),x.reset(),o===!0&&!D(t))return c.info({msg:`Tool execution gated (awaiting confirm): ${e}`}),I(e,t);let s=await r({...t,confirmedCommand:!0});return c.info({msg:`Tool execution successful: ${e}`}),s}catch(s){throw c.error({err:s,params:t,msg:`Tool execution failed: ${e}`}),s}};var w=async e=>{for(let r of h())e.registerTool(r.name,{description:r.description,inputSchema:r.inputSchema,outputSchema:r.outputSchema},f({toolName:r.name,handler:r.handler,requiresHumanConfirm:r.requiresHumanConfirm}))};async function k(){u.enabled=!0;let e=new H({name:"infra-kit",version:v.version},{capabilities:{resources:{listChanged:!0},tools:{},prompts:{}}});return await T(e),await R(e),await w(e),e}S();var i=l(),P=async()=>{let e;try{e=await k(),i.info("MCP Server instance created")}catch(r){i.error({err:r,msg:"Failed to create MCP server"}),i.error("Fatal error during server creation."),E.exit(1)}try{let r=new O;await e.connect(r),i.info({msg:"Server connected to transport. Ready."})}catch(r){i.error({err:r,msg:"Failed to initialize server"}),i.error("Fatal error during server transport init."),E.exit(1)}};C(i);P();
1
+ import{a as d,ba as h,d as p,ea as S,r as y}from"./chunk-KATIE633.js";import"./chunk-MKMT6KQT.js";import{a as v}from"./chunk-VFU2USJG.js";import"./chunk-LKKKDB6V.js";import{i as x}from"./chunk-OKO3DKIM.js";import{H as c,I as l,J as a,c as u,da as g}from"./chunk-XR6HR4LL.js";import"./chunk-CHETBZ6M.js";import"./chunk-X46DP23W.js";import{StdioServerTransport as P}from"@modelcontextprotocol/server/stdio";import j from"node:process";import n from"node:process";var C=e=>{n.on("SIGINT",()=>{e.info({msg:"Received SIGINT. Shutting down..."}),n.exit(0)}),n.on("SIGTERM",()=>{e.info({msg:"Received SIGTERM. Shutting down..."}),n.exit(0)}),n.on("uncaughtException",r=>{e.fatal({err:r,msg:"Uncaught Exception"}),e.error(`Uncaught Exception! Check ${c}. Shutting down...`),e.flush(),n.exit(1)}),n.on("unhandledRejection",(r,o)=>{e.fatal({reason:r,promise:o,msg:"Unhandled Rejection"}),e.error(`Unhandled Rejection! Check ${c}. Shutting down...`),e.flush(),n.exit(1)})};import{McpServer as O}from"@modelcontextprotocol/server";var T=async e=>{};var b="infra-kit://config",M="infra-kit://dev-context",D={loadConfig:g,readDevContext:()=>p()},m=(e,r)=>({contents:[{uri:e,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}),R=async(e,r=D)=>{e.registerResource("infra-kit-config",b,{title:"infra-kit config",description:"The merged infra-kit.json configuration (all override layers applied). Read-only.",mimeType:"application/json"},async o=>{try{return m(o.toString(),await r.loadConfig())}catch(t){return m(o.toString(),{error:t instanceof Error?t.message:String(t)})}}),e.registerResource("infra-kit-dev-context",M,{title:"infra-kit dev context",description:"What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.",mimeType:"application/json"},o=>m(o.toString(),r.readDevContext()))};import{z as w}from"zod";var I=e=>typeof e=="object"&&e!==null&&e.confirm===!0,H=(e,r)=>{let o=typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).filter(([s])=>s!=="confirm")):{},t={status:"confirmation_required",tool:e,resolvedArgs:o,message:`${e} mutates external state and is gated. It was NOT executed. Re-call ${e} with the same arguments plus "confirm": true to execute.`};return{content:d(JSON.stringify(t,null,2)),structuredContent:t,isError:!0}},f=({toolName:e,handler:r,requiresHumanConfirm:o})=>async t=>{a.info({msg:`Tool execution started: ${e}`,params:t});try{if(await y(),x.reset(),o===!0&&!I(t))return a.info({msg:`Tool execution gated (awaiting confirm): ${e}`}),H(e,t);let s=await r({...t,confirmedCommand:!0});return a.info({msg:`Tool execution successful: ${e}`}),s}catch(s){throw a.error({err:s,params:t,msg:`Tool execution failed: ${e}`}),s}};var E=async e=>{for(let r of h())e.registerTool(r.name,{description:r.description,inputSchema:w.object(r.inputSchema),outputSchema:w.object(r.outputSchema)},f({toolName:r.name,handler:r.handler,requiresHumanConfirm:r.requiresHumanConfirm}))};async function k(){u.enabled=!0;let e=new O({name:"infra-kit",version:v.version},{capabilities:{resources:{listChanged:!0},tools:{},prompts:{}}});return await T(e),await R(e),await E(e),e}S();var i=l(),U=async()=>{let e;try{e=await k(),i.info("MCP Server instance created")}catch(r){i.error({err:r,msg:"Failed to create MCP server"}),i.error("Fatal error during server creation."),j.exit(1)}try{let r=new P;await e.connect(r),i.info({msg:"Server connected to transport. Ready."})}catch(r){i.error({err:r,msg:"Failed to initialize server"}),i.error("Fatal error during server transport init."),j.exit(1)}};C(i);U();
2
2
  //# sourceMappingURL=mcp.js.map
package/dist/mcp.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/entry/mcp.ts", "../src/lib/error-handlers/index.ts", "../src/mcp/server.ts", "../src/mcp/prompts/index.ts", "../src/mcp/resources/index.ts", "../src/lib/tool-handler/tool-handler.ts", "../src/mcp/tools/index.ts"],
4
- "sourcesContent": ["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport process from 'node:process'\n\nimport { setupErrorHandlers } from 'src/lib/error-handlers'\nimport { initLoggerMcp } from 'src/lib/logger'\nimport { suppressTypelessPackageJsonWarning } from 'src/lib/node-warnings'\n\nimport { createMcpServer } from '../mcp/server'\n\n// The MCP tools run the same commands as the CLI, so they hit the same consumer `.ts` configs.\n// This keeps the client's log pane clean; it cannot affect protocol framing either way, since\n// the stdio transport frames JSON-RPC on stdout and `emitWarning` only ever writes to stderr.\nsuppressTypelessPackageJsonWarning()\n\nconst logger = initLoggerMcp()\n\nconst startServer = async () => {\n let server\n\n try {\n server = await createMcpServer()\n\n logger.info('MCP Server instance created')\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to create MCP server' })\n logger.error(`Fatal error during server creation.`)\n\n process.exit(1)\n }\n\n try {\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n logger.info({ msg: 'Server connected to transport. Ready.' })\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to initialize server' })\n logger.error(`Fatal error during server transport init.`)\n\n process.exit(1)\n }\n}\n\n// Setup error handlers\nsetupErrorHandlers(logger)\n\n// Start the server\nstartServer()\n", "import process from 'node:process'\nimport type { Logger } from 'pino'\n\nimport { LOG_FILE_PATH } from '../logger/index'\n\n/**\n * Setup error handlers for the application\n *\n * @param logger - The logger instance\n *\n * ONLY FOR SERVER!\n */\nexport const setupErrorHandlers = (logger: Logger) => {\n process.on('SIGINT', () => {\n logger.info({ msg: 'Received SIGINT. Shutting down...' })\n process.exit(0)\n })\n\n process.on('SIGTERM', () => {\n logger.info({ msg: 'Received SIGTERM. Shutting down...' })\n process.exit(0)\n })\n\n process.on('uncaughtException', (error) => {\n logger.fatal({ err: error, msg: 'Uncaught Exception' })\n logger.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason, promise) => {\n logger.fatal({ reason, promise, msg: 'Unhandled Rejection' })\n logger.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n}\n", "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { mcpMode } from 'src/lib/mcp-mode'\n\nimport packageJson from '../../package.json' with { type: 'json' }\nimport { initializePrompts } from './prompts'\nimport { initializeResources } from './resources'\nimport { initializeTools } from './tools'\n\nexport async function createMcpServer() {\n // Marks `process.stdin` as the JSON-RPC transport for every prompt guard in the\n // process. Set HERE rather than in `entry/mcp.ts` (the sole caller) because that\n // module starts a server at import time and so can never be unit-tested \u2014 a test\n // there could only stub the flag, which proves nothing about it ever being set.\n // This runs before `server.connect`, so no tool handler can outrun it.\n mcpMode.enabled = true\n\n const server = new McpServer(\n {\n name: 'infra-kit',\n version: packageJson.version,\n },\n {\n capabilities: {\n // `initializeResources` registers read-only resources below; the SDK's\n // `registerResource` also declares `resources.listChanged` on top of this.\n resources: { listChanged: true },\n tools: {},\n prompts: {},\n },\n },\n )\n\n await initializePrompts(server)\n await initializeResources(server)\n await initializeTools(server)\n\n return server\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nexport const initializePrompts = async (_server: McpServer) => {}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport type { InfraKitConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\n\nimport type { DevContextSnapshot } from './dev-context'\nimport { readDevContext } from './dev-context'\n\n/** Stable URI of the merged-config resource. */\nexport const CONFIG_RESOURCE_URI = 'infra-kit://config'\n\n/** Stable URI of the dev-context resource. */\nexport const DEV_CONTEXT_RESOURCE_URI = 'infra-kit://dev-context'\n\n/**\n * The two disk reads the resources need, injected so the registration is unit-testable without touching\n * the filesystem or the config-loader's mtime cache. Production uses the real readers by default.\n */\nexport interface ResourceDeps {\n /** Loads the merged `infra-kit.json` (all override layers applied). May throw when no config exists. */\n loadConfig: () => Promise<InfraKitConfig>\n /** Reads the dev-context fragments `infra-kit dev` last wrote. Never throws; absent session \u21D2 empty. */\n readDevContext: () => DevContextSnapshot\n}\n\nconst defaultDeps: ResourceDeps = {\n loadConfig: getInfraKitConfig,\n readDevContext: () => {\n return readDevContext()\n },\n}\n\n/** Serialize a resource body as pretty JSON text \u2014 the wire form every MCP client can read. */\nconst jsonResource = (uri: string, value: unknown): { contents: { uri: string; mimeType: string; text: string }[] } => {\n return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(value, null, 2) }] }\n}\n\n/**\n * Register infra-kit's READ-ONLY MCP resources so an agent can inspect the repo's config and dev state\n * without calling a tool (or mutating anything):\n *\n * - `infra-kit://config` \u2014 the merged `infra-kit.json` an agent would run against.\n * - `infra-kit://dev-context` \u2014 what `infra-kit dev` last wrote (backends up, ports, freshness); an\n * absent dev session resolves to an empty `session: 'none'` payload, NOT\n * an error.\n *\n * Both handlers are side-effect free and swallow their reader's failure into an `{ error }` payload rather\n * than throwing, so a bad on-disk config can never crash the long-lived MCP server.\n */\nexport const initializeResources = async (server: McpServer, deps: ResourceDeps = defaultDeps) => {\n server.registerResource(\n 'infra-kit-config',\n CONFIG_RESOURCE_URI,\n {\n title: 'infra-kit config',\n description: 'The merged infra-kit.json configuration (all override layers applied). Read-only.',\n mimeType: 'application/json',\n },\n async (uri) => {\n try {\n return jsonResource(uri.toString(), await deps.loadConfig())\n } catch (error) {\n return jsonResource(uri.toString(), { error: error instanceof Error ? error.message : String(error) })\n }\n },\n )\n\n server.registerResource(\n 'infra-kit-dev-context',\n DEV_CONTEXT_RESOURCE_URI,\n {\n title: 'infra-kit dev context',\n description:\n 'What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment ' +\n 'freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.',\n mimeType: 'application/json',\n },\n // The SDK's `ReadResourceCallback` accepts a synchronous return; the disk read is sync, so no `async`.\n (uri) => {\n return jsonResource(uri.toString(), deps.readDevContext())\n },\n )\n}\n", "import { commandEcho } from 'src/lib/command-echo'\nimport { ensureUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { logger } from 'src/lib/logger'\nimport { textContent } from 'src/types'\nimport type { ToolsExecutionResult } from 'src/types'\n\ninterface ToolHandlerArgs {\n toolName: string\n handler: (params: any) => Promise<ToolsExecutionResult>\n /**\n * When true, this tool is gated by the destructive-op confirm gate below. Sourced from the\n * catalog tool's {@link CatalogMcpTool.requiresHumanConfirm} at registration (`mcp/tools/index.ts`).\n */\n requiresHumanConfirm?: boolean\n}\n\n/** True when the incoming MCP params carry an explicit `confirm:true` (the call-2 execute signal). */\nconst isConfirmed = (params: unknown): boolean => {\n return typeof params === 'object' && params !== null && (params as { confirm?: unknown }).confirm === true\n}\n\n/**\n * The call-1 gate response for a `requiresHumanConfirm` tool: it names the tool and echoes the\n * resolved args (minus the `confirm` flag itself) and tells the caller to re-invoke with\n * `confirm:true`. Crucially it sets `isError: true` \u2014 the MCP SDK validates a result's\n * `structuredContent` against the tool's `outputSchema` UNLESS `isError` is set (server/mcp.js\n * `validateToolOutput`), and every gated tool declares an outputSchema the gate payload does not\n * match, so without `isError` the real server would throw an output-validation error instead of\n * returning the gate. This is a soft stop, not a failure: the tool did NOT run.\n */\nconst buildConfirmGate = (toolName: string, params: unknown): ToolsExecutionResult => {\n const resolvedArgs =\n typeof params === 'object' && params !== null\n ? Object.fromEntries(\n Object.entries(params as Record<string, unknown>).filter(([key]) => {\n return key !== 'confirm'\n }),\n )\n : {}\n\n const structuredContent = {\n status: 'confirmation_required' as const,\n tool: toolName,\n resolvedArgs,\n message: `${toolName} mutates external state and is gated. It was NOT executed. Re-call ${toolName} with the same arguments plus \"confirm\": true to execute.`,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n isError: true,\n }\n}\n\nexport const createToolHandler = ({\n toolName,\n handler,\n requiresHumanConfirm,\n}: ToolHandlerArgs): ((params: unknown) => Promise<ToolsExecutionResult>) => {\n return async (params: unknown) => {\n logger.info({ msg: `Tool execution started: ${toolName}`, params })\n try {\n // MCP entry-boundary seed. This wrapper is the sole chokepoint for every exposed tool\n // (`src/mcp/tools/index.ts` holds the only `registerTool` call), and the `mcp` command itself is\n // in program.ts's SEED_EXCLUDED \u2014 so an MCP server seeds lazily, on its FIRST tool invocation,\n // and a server that never receives one never writes to $HOME. The once-per-process guard inside\n // ensureUserProjectConfig makes calls 2..N free on this long-lived process.\n //\n // Deliberately INSIDE the try, not before it: defense-in-depth. ensureUserProjectConfig is\n // contractually never-throw, but if that contract ever broke, an unhandled rejection here would\n // take down the long-lived server. Inside the try it degrades to an ordinary tool error.\n await ensureUserProjectConfig()\n\n // The command handlers record their resolved flags into the `commandEcho` singleton. On the CLI,\n // Commander's `preAction` clears it before every command; this long-lived server never runs that\n // hook, so without a reset here one tool call's flags would leak into the next one's snapshot and\n // the options array would grow for the life of the process.\n commandEcho.reset()\n\n // Orthogonal destructive-op confirm gate. It sits BEFORE the handler and is INDEPENDENT of the\n // `confirmedCommand:true` injected below \u2014 that flag is a prompt-skip / behavior discriminator\n // (e.g. worktrees-remove keys `allowEditorRelaunch` off it) and MUST keep being injected on the\n // real call, or the non-TTY server would hang on an inquirer prompt and the Zed relaunch would\n // re-enable. When a tool is flagged and the caller has not opted in with `confirm:true`, return\n // the resolved-args gate and DO NOT run the handler; a second call carrying `confirm:true` falls\n // through and executes exactly as an unflagged tool would.\n if (requiresHumanConfirm === true && !isConfirmed(params)) {\n logger.info({ msg: `Tool execution gated (awaiting confirm): ${toolName}` })\n\n return buildConfirmGate(toolName, params)\n }\n\n const payload = await handler({ ...(params as object), confirmedCommand: true })\n\n logger.info({ msg: `Tool execution successful: ${toolName}` })\n\n return payload\n } catch (error) {\n logger.error({\n err: error,\n params,\n msg: `Tool execution failed: ${toolName}`,\n })\n\n throw error\n }\n }\n}\n", "import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { getExposedMcpTools } from 'src/lib/command-catalog'\nimport { createToolHandler } from 'src/lib/tool-handler'\n\nexport const initializeTools = async (server: McpServer) => {\n // The registered tool set is derived from the single command catalog, filtered\n // by its explicit `mcpExposed` allowlist. doctor is intentionally excluded there\n // (host-inspecting) and must never be registered here.\n for (const tool of getExposedMcpTools()) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n },\n createToolHandler({\n toolName: tool.name,\n handler: tool.handler,\n requiresHumanConfirm: tool.requiresHumanConfirm,\n }),\n )\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["StdioServerTransport", "process", "process", "setupErrorHandlers", "logger", "process", "error", "LOG_FILE_PATH", "reason", "promise", "McpServer", "initializePrompts", "_server", "CONFIG_RESOURCE_URI", "DEV_CONTEXT_RESOURCE_URI", "defaultDeps", "getInfraKitConfig", "readDevContext", "jsonResource", "uri", "value", "initializeResources", "server", "deps", "error", "isConfirmed", "params", "buildConfirmGate", "toolName", "resolvedArgs", "key", "structuredContent", "textContent", "createToolHandler", "handler", "requiresHumanConfirm", "logger", "ensureUserProjectConfig", "commandEcho", "payload", "error", "initializeTools", "server", "tool", "getExposedMcpTools", "createToolHandler", "createMcpServer", "mcpMode", "server", "McpServer", "package_default", "initializePrompts", "initializeResources", "initializeTools", "suppressTypelessPackageJsonWarning", "logger", "initLoggerMcp", "startServer", "server", "createMcpServer", "error", "process", "transport", "StdioServerTransport", "setupErrorHandlers"]
3
+ "sources": ["../src/entry/mcp.ts", "../src/lib/error-handlers/index.ts", "../src/mcp/server.ts", "../src/mcp/prompts/index.ts", "../src/mcp/resources/index.ts", "../src/mcp/tools/index.ts", "../src/lib/tool-handler/tool-handler.ts"],
4
+ "sourcesContent": ["import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'\nimport process from 'node:process'\n\nimport { setupErrorHandlers } from 'src/lib/error-handlers'\nimport { initLoggerMcp } from 'src/lib/logger'\nimport { suppressTypelessPackageJsonWarning } from 'src/lib/node-warnings'\n\nimport { createMcpServer } from '../mcp/server'\n\n// The MCP tools run the same commands as the CLI, so they hit the same consumer `.ts` configs.\n// This keeps the client's log pane clean; it cannot affect protocol framing either way, since\n// the stdio transport frames JSON-RPC on stdout and `emitWarning` only ever writes to stderr.\nsuppressTypelessPackageJsonWarning()\n\nconst logger = initLoggerMcp()\n\nconst startServer = async () => {\n let server\n\n try {\n server = await createMcpServer()\n\n logger.info('MCP Server instance created')\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to create MCP server' })\n logger.error(`Fatal error during server creation.`)\n\n process.exit(1)\n }\n\n try {\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n logger.info({ msg: 'Server connected to transport. Ready.' })\n } catch (error) {\n logger.error({ err: error, msg: 'Failed to initialize server' })\n logger.error(`Fatal error during server transport init.`)\n\n process.exit(1)\n }\n}\n\n// Setup error handlers\nsetupErrorHandlers(logger)\n\n// Start the server\nstartServer()\n", "import process from 'node:process'\nimport type { Logger } from 'pino'\n\nimport { LOG_FILE_PATH } from '../logger/index'\n\n/**\n * Setup error handlers for the application\n *\n * @param logger - The logger instance\n *\n * ONLY FOR SERVER!\n */\nexport const setupErrorHandlers = (logger: Logger) => {\n process.on('SIGINT', () => {\n logger.info({ msg: 'Received SIGINT. Shutting down...' })\n process.exit(0)\n })\n\n process.on('SIGTERM', () => {\n logger.info({ msg: 'Received SIGTERM. Shutting down...' })\n process.exit(0)\n })\n\n process.on('uncaughtException', (error) => {\n logger.fatal({ err: error, msg: 'Uncaught Exception' })\n logger.error(`Uncaught Exception! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n\n process.on('unhandledRejection', (reason, promise) => {\n logger.fatal({ reason, promise, msg: 'Unhandled Rejection' })\n logger.error(`Unhandled Rejection! Check ${LOG_FILE_PATH}. Shutting down...`)\n logger.flush()\n process.exit(1)\n })\n}\n", "import { McpServer } from '@modelcontextprotocol/server'\n\nimport { mcpMode } from 'src/lib/mcp-mode'\n\nimport packageJson from '../../package.json' with { type: 'json' }\nimport { initializePrompts } from './prompts'\nimport { initializeResources } from './resources'\nimport { initializeTools } from './tools'\n\nexport async function createMcpServer() {\n // Marks `process.stdin` as the JSON-RPC transport for every prompt guard in the\n // process. Set HERE rather than in `entry/mcp.ts` (the sole caller) because that\n // module starts a server at import time and so can never be unit-tested \u2014 a test\n // there could only stub the flag, which proves nothing about it ever being set.\n // This runs before `server.connect`, so no tool handler can outrun it.\n mcpMode.enabled = true\n\n const server = new McpServer(\n {\n name: 'infra-kit',\n version: packageJson.version,\n },\n {\n capabilities: {\n // `initializeResources` registers read-only resources below; the SDK's\n // `registerResource` also declares `resources.listChanged` on top of this.\n resources: { listChanged: true },\n tools: {},\n prompts: {},\n },\n },\n )\n\n await initializePrompts(server)\n await initializeResources(server)\n await initializeTools(server)\n\n return server\n}\n", "import type { McpServer } from '@modelcontextprotocol/server'\n\nexport const initializePrompts = async (_server: McpServer) => {}\n", "import type { McpServer } from '@modelcontextprotocol/server'\n\nimport type { InfraKitConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\n\nimport type { DevContextSnapshot } from './dev-context'\nimport { readDevContext } from './dev-context'\n\n/** Stable URI of the merged-config resource. */\nexport const CONFIG_RESOURCE_URI = 'infra-kit://config'\n\n/** Stable URI of the dev-context resource. */\nexport const DEV_CONTEXT_RESOURCE_URI = 'infra-kit://dev-context'\n\n/**\n * The two disk reads the resources need, injected so the registration is unit-testable without touching\n * the filesystem or the config-loader's mtime cache. Production uses the real readers by default.\n */\nexport interface ResourceDeps {\n /** Loads the merged `infra-kit.json` (all override layers applied). May throw when no config exists. */\n loadConfig: () => Promise<InfraKitConfig>\n /** Reads the dev-context fragments `infra-kit dev` last wrote. Never throws; absent session \u21D2 empty. */\n readDevContext: () => DevContextSnapshot\n}\n\nconst defaultDeps: ResourceDeps = {\n loadConfig: getInfraKitConfig,\n readDevContext: () => {\n return readDevContext()\n },\n}\n\n/** Serialize a resource body as pretty JSON text \u2014 the wire form every MCP client can read. */\nconst jsonResource = (uri: string, value: unknown): { contents: { uri: string; mimeType: string; text: string }[] } => {\n return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(value, null, 2) }] }\n}\n\n/**\n * Register infra-kit's READ-ONLY MCP resources so an agent can inspect the repo's config and dev state\n * without calling a tool (or mutating anything):\n *\n * - `infra-kit://config` \u2014 the merged `infra-kit.json` an agent would run against.\n * - `infra-kit://dev-context` \u2014 what `infra-kit dev` last wrote (backends up, ports, freshness); an\n * absent dev session resolves to an empty `session: 'none'` payload, NOT\n * an error.\n *\n * Both handlers are side-effect free and swallow their reader's failure into an `{ error }` payload rather\n * than throwing, so a bad on-disk config can never crash the long-lived MCP server.\n */\nexport const initializeResources = async (server: McpServer, deps: ResourceDeps = defaultDeps) => {\n server.registerResource(\n 'infra-kit-config',\n CONFIG_RESOURCE_URI,\n {\n title: 'infra-kit config',\n description: 'The merged infra-kit.json configuration (all override layers applied). Read-only.',\n mimeType: 'application/json',\n },\n async (uri) => {\n try {\n return jsonResource(uri.toString(), await deps.loadConfig())\n } catch (error) {\n return jsonResource(uri.toString(), { error: error instanceof Error ? error.message : String(error) })\n }\n },\n )\n\n server.registerResource(\n 'infra-kit-dev-context',\n DEV_CONTEXT_RESOURCE_URI,\n {\n title: 'infra-kit dev context',\n description:\n 'What `infra-kit dev` last wrote: backends currently up, their ports/origins, and fragment ' +\n 'freshness. Read-only and advisory (no liveness probe). No active session resolves to an empty payload.',\n mimeType: 'application/json',\n },\n // The SDK's `ReadResourceCallback` accepts a synchronous return; the disk read is sync, so no `async`.\n (uri) => {\n return jsonResource(uri.toString(), deps.readDevContext())\n },\n )\n}\n", "import type { McpServer } from '@modelcontextprotocol/server'\nimport { z } from 'zod'\n\nimport { getExposedMcpTools } from 'src/lib/command-catalog'\nimport { createToolHandler } from 'src/lib/tool-handler'\n\nexport const initializeTools = async (server: McpServer) => {\n // The registered tool set is derived from the single command catalog, filtered\n // by its explicit `mcpExposed` allowlist. doctor is intentionally excluded there\n // (host-inspecting) and must never be registered here.\n for (const tool of getExposedMcpTools()) {\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n // Wrapped HERE, at the single `registerTool` call site, rather than in the 24\n // `defineMcpTool` definitions or in `CatalogMcpTool`. SDK v2 offers a deprecated\n // raw-shape overload that would auto-wrap, but it types the shape as its own\n // `ZodRawShape` (`Record<string, ZodType>`) while zod 4's `z.ZodRawShape` is the\n // looser `Readonly<{ [k: string]: $ZodType }>` \u2014 `$ZodType` lacks `def`/`type`/`_def`\n // and ~42 other members, so the raw shape is NOT assignable and the overload is\n // unreachable for us. `z.object()` closes that gap and lands on v2's PREFERRED\n // (non-deprecated) Standard Schema overload, since a `ZodObject` carries `~standard`.\n //\n // Wrapping here keeps the authoring shape in all 24 `src/commands/**` definitions\n // unchanged and leaves `defineMcpTool`'s `z.infer<z.ZodObject<TIn>>` handler typing\n // untouched \u2014 the migration needs zero edits under `src/commands/`.\n inputSchema: z.object(tool.inputSchema),\n outputSchema: z.object(tool.outputSchema),\n },\n createToolHandler({\n toolName: tool.name,\n handler: tool.handler,\n requiresHumanConfirm: tool.requiresHumanConfirm,\n }),\n )\n }\n}\n", "import { commandEcho } from 'src/lib/command-echo'\nimport { ensureUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { logger } from 'src/lib/logger'\nimport { textContent } from 'src/types'\nimport type { ToolsExecutionResult } from 'src/types'\n\ninterface ToolHandlerArgs {\n toolName: string\n handler: (params: any) => Promise<ToolsExecutionResult>\n /**\n * When true, this tool is gated by the destructive-op confirm gate below. Sourced from the\n * catalog tool's {@link CatalogMcpTool.requiresHumanConfirm} at registration (`mcp/tools/index.ts`).\n */\n requiresHumanConfirm?: boolean\n}\n\n/** True when the incoming MCP params carry an explicit `confirm:true` (the call-2 execute signal). */\nconst isConfirmed = (params: unknown): boolean => {\n return typeof params === 'object' && params !== null && (params as { confirm?: unknown }).confirm === true\n}\n\n/**\n * The call-1 gate response for a `requiresHumanConfirm` tool: it names the tool and echoes the\n * resolved args (minus the `confirm` flag itself) and tells the caller to re-invoke with\n * `confirm:true`. Crucially it sets `isError: true` \u2014 the MCP SDK validates a result's\n * `structuredContent` against the tool's `outputSchema` UNLESS `isError` is set (server/mcp.js\n * `validateToolOutput`), and every gated tool declares an outputSchema the gate payload does not\n * match, so without `isError` the real server would throw an output-validation error instead of\n * returning the gate. This is a soft stop, not a failure: the tool did NOT run.\n */\nconst buildConfirmGate = (toolName: string, params: unknown): ToolsExecutionResult => {\n const resolvedArgs =\n typeof params === 'object' && params !== null\n ? Object.fromEntries(\n Object.entries(params as Record<string, unknown>).filter(([key]) => {\n return key !== 'confirm'\n }),\n )\n : {}\n\n const structuredContent = {\n status: 'confirmation_required' as const,\n tool: toolName,\n resolvedArgs,\n message: `${toolName} mutates external state and is gated. It was NOT executed. Re-call ${toolName} with the same arguments plus \"confirm\": true to execute.`,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n isError: true,\n }\n}\n\nexport const createToolHandler = ({\n toolName,\n handler,\n requiresHumanConfirm,\n}: ToolHandlerArgs): ((params: unknown) => Promise<ToolsExecutionResult>) => {\n return async (params: unknown) => {\n logger.info({ msg: `Tool execution started: ${toolName}`, params })\n try {\n // MCP entry-boundary seed. This wrapper is the sole chokepoint for every exposed tool\n // (`src/mcp/tools/index.ts` holds the only `registerTool` call), and the `mcp` command itself is\n // in program.ts's SEED_EXCLUDED \u2014 so an MCP server seeds lazily, on its FIRST tool invocation,\n // and a server that never receives one never writes to $HOME. The once-per-process guard inside\n // ensureUserProjectConfig makes calls 2..N free on this long-lived process.\n //\n // Deliberately INSIDE the try, not before it: defense-in-depth. ensureUserProjectConfig is\n // contractually never-throw, but if that contract ever broke, an unhandled rejection here would\n // take down the long-lived server. Inside the try it degrades to an ordinary tool error.\n await ensureUserProjectConfig()\n\n // The command handlers record their resolved flags into the `commandEcho` singleton. On the CLI,\n // Commander's `preAction` clears it before every command; this long-lived server never runs that\n // hook, so without a reset here one tool call's flags would leak into the next one's snapshot and\n // the options array would grow for the life of the process.\n commandEcho.reset()\n\n // Orthogonal destructive-op confirm gate. It sits BEFORE the handler and is INDEPENDENT of the\n // `confirmedCommand:true` injected below \u2014 that flag is a prompt-skip / behavior discriminator\n // (e.g. worktrees-remove keys `allowEditorRelaunch` off it) and MUST keep being injected on the\n // real call, or the non-TTY server would hang on an inquirer prompt and the Zed relaunch would\n // re-enable. When a tool is flagged and the caller has not opted in with `confirm:true`, return\n // the resolved-args gate and DO NOT run the handler; a second call carrying `confirm:true` falls\n // through and executes exactly as an unflagged tool would.\n if (requiresHumanConfirm === true && !isConfirmed(params)) {\n logger.info({ msg: `Tool execution gated (awaiting confirm): ${toolName}` })\n\n return buildConfirmGate(toolName, params)\n }\n\n const payload = await handler({ ...(params as object), confirmedCommand: true })\n\n logger.info({ msg: `Tool execution successful: ${toolName}` })\n\n return payload\n } catch (error) {\n logger.error({\n err: error,\n params,\n msg: `Tool execution failed: ${toolName}`,\n })\n\n throw error\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["StdioServerTransport", "process", "process", "setupErrorHandlers", "logger", "process", "error", "LOG_FILE_PATH", "reason", "promise", "McpServer", "initializePrompts", "_server", "CONFIG_RESOURCE_URI", "DEV_CONTEXT_RESOURCE_URI", "defaultDeps", "getInfraKitConfig", "readDevContext", "jsonResource", "uri", "value", "initializeResources", "server", "deps", "error", "z", "isConfirmed", "params", "buildConfirmGate", "toolName", "resolvedArgs", "key", "structuredContent", "textContent", "createToolHandler", "handler", "requiresHumanConfirm", "logger", "ensureUserProjectConfig", "commandEcho", "payload", "error", "initializeTools", "server", "tool", "getExposedMcpTools", "z", "createToolHandler", "createMcpServer", "mcpMode", "server", "McpServer", "package_default", "initializePrompts", "initializeResources", "initializeTools", "suppressTypelessPackageJsonWarning", "logger", "initLoggerMcp", "startServer", "server", "createMcpServer", "error", "process", "transport", "StdioServerTransport", "setupErrorHandlers"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ import{b as p}from"./chunk-VDBJ73LS.js";import{a as l}from"./chunk-TPVXMJ7N.js";import{render as z}from"ink";import T from"node:process";import{Box as u,Text as h}from"ink";import{useEffect as x,useState as F}from"react";import{jsx as f,jsxs as m}from"react/jsx-runtime";var v=r=>{let{phase:e,narration:t}=r,[i,n]=F(0);return x(()=>{let a=setInterval(()=>{n(o=>o+1)},S);return()=>{clearInterval(a)}},[]),m(u,{flexDirection:"column",children:[m(u,{children:[f(h,{color:"cyan",children:c[i%c.length]}),f(h,{dimColor:!0,children:` ${e}`})]}),t?f(h,{dimColor:!0,children:t}):null]})},c=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],S=80;import{Box as b,Static as w,Text as L}from"ink";import{Fragment as D,jsx as s,jsxs as B}from"react/jsx-runtime";var g=r=>{let{headerLines:e,logLines:t,footerLines:i}=r,n=[...e,...t],a=P(i,r.maxFooterLines);return B(D,{children:[s(w,{items:n,children:(o,d)=>s(L,{children:o},d)}),s(b,{flexDirection:"column",children:a.map((o,d)=>s(L,{children:o},d))})]})},P=(r,e)=>{if(e==null||e<1||r.length<=e)return r;let t=r.slice(0,e-1);return[...t,` \u2026 +${r.length-t.length} more`]};import{jsx as y}from"react/jsx-runtime";var R=class{renderer;renderFn;stdout;verbose;now;instance=null;finalized=!1;persistent=!1;phase="";narration="";headerLines=[];logLines=[];footerLines=[];constructor(e){this.verbose=e.verbose??!1,this.renderFn=e.render??z,this.stdout=e.stdout??l(T.stdout),this.now=e.now??(()=>new Date),this.renderer=new p({appendLog:e.appendLog,verbose:this.verbose,isTTY:!0,write:t=>{this.stdout.write(t)},now:this.now})}logFn=(e,t="info")=>{this.log(e,t)};renderBoot(){let e=y(v,{phase:this.phase,narration:this.narration});if(this.instance){this.instance.rerender(e);return}this.instance=this.renderFn(e,{stdout:this.stdout,exitOnCtrlC:!1,patchConsole:!1})}unmount(){this.instance&&(this.instance.unmount(),this.instance=null)}narrate(e){if(this.renderer.teeOnly(e,"info"),this.persistent){this.verbose&&(this.logLines.push(e),this.rerenderPersistent());return}this.finalized||(this.narration=e,this.instance&&this.renderBoot())}log(e,t="info",i={}){let n=t!=="debug"||this.verbose;if(this.persistent){i.tee!==!1&&this.renderer.teeOnly(e,t),n&&(this.logLines.push(e),this.rerenderPersistent());return}n&&this.unmount(),this.renderer.log(e,t,i)}bootStep(e){this.renderer.teeOnly(e,"info"),!this.finalized&&(this.phase=e,this.renderBoot())}ready(e){this.headerLines=this.renderer.formatHeaderLines(e),this.footerLines=this.renderer.formatFooterLines(e),this.logLines=[];for(let t of this.headerLines)this.renderer.teeOnly(t,"info");this.finalized=!0,this.persistent=!0,typeof this.stdout.on=="function"&&this.stdout.on("resize",this.onResize),this.rerenderPersistent()}maxFooterLines(){return Math.max(3,(this.stdout.rows??24)-6)}rerenderPersistent(){let e=y(g,{headerLines:this.headerLines,logLines:this.logLines,footerLines:this.footerLines,maxFooterLines:this.maxFooterLines()});if(this.instance){this.instance.rerender(e);return}this.instance=this.renderFn(e,{stdout:this.stdout,exitOnCtrlC:!1,patchConsole:!1})}onResize=()=>{this.persistent&&this.rerenderPersistent()};refresh(e){this.persistent&&(this.footerLines=this.renderer.formatFooterLines(e),this.rerenderPersistent())}dispose(){this.persistent&&(this.rerenderPersistent(),typeof this.stdout.off=="function"&&this.stdout.off("resize",this.onResize)),this.finalized=!0,this.persistent=!1,this.unmount()}};export{R as PersistentInkDevUi};
2
+ //# sourceMappingURL=persistent-ink-dev-ui-QNFTO2B2.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tui/dev-ui/persistent-ink-dev-ui.tsx", "../src/tui/dev-ui/boot-region.tsx", "../src/tui/dev-ui/live-region.tsx"],
4
+ "sourcesContent": ["import { render as inkRender } from 'ink'\nimport process from 'node:process'\nimport type { ReactElement } from 'react'\n\nimport type { DevUi, LogLevel, LogOptions, ReadySummary } from 'src/dev/dev-ui'\nimport { DevRenderer } from 'src/dev/render'\nimport { createSafeStream } from 'src/tui/safe-stderr'\n\nimport { BootRegion } from './boot-region'\nimport { LiveRegion } from './live-region'\n\n/**\n * Ink-backed {@link DevUi} for `infra-kit dev`: a boot region that collapses into a PERSISTENT status\n * panel. It is the UI on any interactive TTY.\n *\n * There is one shape of session now, not two. Until recently `ready` branched on `summary.hasUiChild`\n * and, for a UI session, unmounted Ink and handed off to a DECSTBM scroll-region UI \u2014 because the\n * `turbo run dev` child's piped output produced an unbounded tail, Ink repaints its live region on every\n * appended line, and a pinned footer can only survive a scrolling stream if the TERMINAL is told to\n * confine it.\n *\n * That tail no longer exists. Framework lines and request lines go to their per-service log files and\n * are never printed, so there is nothing to scroll past the panel and nothing for a scroll region to\n * defend it from. The branch, the handoff, and the whole DECSTBM machinery were deleted with the stream\n * that justified them.\n *\n * What still prints above the panel is only what the RUNNER says \u2014 a restart, an unhealthy app, a dead\n * engine. Those are rare and they are events, not logs.\n *\n * The embedded {@link DevRenderer} owns the file-tee format (`teeOnly`); in persistent mode it is used\n * ONLY for teeing, never its direct stdout write, which would collide with the live region. Every\n * component here is OUTPUT-ONLY (no `useInput`) \u2014 see live-region.tsx.\n */\n\n/** The subset of an Ink render handle this UI drives \u2014 shared by `ink` and `ink-testing-library`. */\ninterface RenderHandle {\n rerender: (tree: ReactElement) => void\n unmount: () => void\n}\n\n/** Render seam: `ink`'s `render` by default; `ink-testing-library`'s `render` is injected in tests. */\ntype RenderFn = (tree: ReactElement, options?: unknown) => RenderHandle\n\nexport interface PersistentInkDevUiDeps {\n /** File tee \u2014 the same appender the runner hands the plain renderer. */\n appendLog: (text: string) => void\n /** Mirrors the renderer's verbose gate: only in verbose does a `debug` log reach the terminal. */\n verbose?: boolean\n /** Clock seam (for deterministic tee + event timestamps in tests). */\n now?: () => Date\n /** Render seam (default `ink`'s `render`); tests inject `ink-testing-library`'s `render`. */\n render?: RenderFn\n /**\n * Target stream (default: `process.stdout` behind the scrollback-safe filter).\n *\n * The runner injects a stream whose `write` BYPASSES the output interceptor. That is not optional:\n * the interceptor owns `process.stdout` for the life of the session, so a panel painted through the\n * raw stream would have its frames filed into a log file instead of drawn \u2014 a blank screen, with no\n * error and no failing test.\n */\n stdout?: NodeJS.WriteStream\n}\n\nexport class PersistentInkDevUi implements DevUi {\n private readonly renderer: DevRenderer\n private readonly renderFn: RenderFn\n private readonly stdout: NodeJS.WriteStream\n private readonly verbose: boolean\n private readonly now: () => Date\n /** Live Ink handle, or `null` when not mounted. */\n private instance: RenderHandle | null = null\n /** True once boot is done: never mount the boot region again. */\n private finalized = false\n /** True while the persistent panel owns the terminal (after ready). */\n private persistent = false\n private phase = ''\n private narration = ''\n private headerLines: string[] = []\n private logLines: string[] = []\n private footerLines: string[] = []\n\n constructor(deps: PersistentInkDevUiDeps) {\n this.verbose = deps.verbose ?? false\n this.renderFn = deps.render ?? (inkRender as RenderFn)\n // NOT raw `process.stdout`: Ink writes `ESC[3J` (erase saved lines) whenever a frame overflows the\n // viewport, which wipes the terminal's SCROLLBACK \u2014 the user's history, and every previous command's\n // output when `dev` runs as a session-shell child. `createSafeStream` drops that one escape and\n // forwards everything else live.\n this.stdout = deps.stdout ?? createSafeStream(process.stdout as NodeJS.WriteStream)\n this.now =\n deps.now ??\n ((): Date => {\n return new Date()\n })\n this.renderer = new DevRenderer({\n appendLog: deps.appendLog,\n verbose: this.verbose,\n isTTY: true,\n write: (text) => {\n this.stdout.write(text)\n },\n now: this.now,\n })\n }\n\n /** `LogFn`-shaped adapter for the build runner seam. */\n readonly logFn = (message: string, level: LogLevel = 'info'): void => {\n this.log(message, level)\n }\n\n // ---- boot ---------------------------------------------------------------\n\n /** Mount the Ink boot region (or rerender it in place) with the current phase + narration. */\n private renderBoot(): void {\n const tree = <BootRegion phase={this.phase} narration={this.narration} />\n\n if (this.instance) {\n this.instance.rerender(tree)\n\n return\n }\n this.instance = this.renderFn(tree, { stdout: this.stdout, exitOnCtrlC: false, patchConsole: false })\n }\n\n /** Unmount Ink if mounted (idempotent). */\n private unmount(): void {\n if (this.instance) {\n this.instance.unmount()\n this.instance = null\n }\n }\n\n narrate(message: string): void {\n this.renderer.teeOnly(message, 'info')\n if (this.persistent) {\n // Visible only in verbose (matches the plain renderer); tee already happened above.\n if (this.verbose) {\n this.logLines.push(message)\n this.rerenderPersistent()\n }\n\n return\n }\n if (this.finalized) {\n return\n }\n this.narration = message\n if (this.instance) {\n this.renderBoot()\n }\n }\n\n log(message: string, level: LogLevel = 'info', options: LogOptions = {}): void {\n const willWrite = level !== 'debug' || this.verbose\n\n if (this.persistent) {\n // Never the embedded renderer's direct stdout write here \u2014 append to the live region instead.\n // `tee: false` means the caller has ALREADY filed this line (see `DevServerRunner.reportFault`);\n // teeing it again would put a second copy of every fault into `runner.log`.\n if (options.tee !== false) {\n this.renderer.teeOnly(message, level)\n }\n if (willWrite) {\n this.logLines.push(message)\n this.rerenderPersistent()\n }\n\n return\n }\n if (willWrite) {\n this.unmount()\n }\n this.renderer.log(message, level, options)\n }\n\n bootStep(phase: string): void {\n this.renderer.teeOnly(phase, 'info')\n if (this.finalized) {\n return\n }\n this.phase = phase\n this.renderBoot()\n }\n\n // ---- the persistent panel ----------------------------------------------\n\n /** Commit the header, tee it, mount the live panel, and STAY mounted for the rest of the session. */\n ready(summary: ReadySummary): void {\n this.headerLines = this.renderer.formatHeaderLines(summary)\n this.footerLines = this.renderer.formatFooterLines(summary)\n this.logLines = []\n for (const line of this.headerLines) {\n this.renderer.teeOnly(line, 'info')\n }\n this.finalized = true\n this.persistent = true\n // Re-clamp the panel when the terminal resizes. Guarded: an injected (test/piped) stream may not\n // be an EventEmitter TTY.\n if (typeof this.stdout.on === 'function') {\n this.stdout.on('resize', this.onResize)\n }\n this.rerenderPersistent()\n }\n\n /**\n * Cap for the pinned panel: it is a live region and cannot scroll, so it must never exceed the\n * viewport. Reserve rows for the runner's occasional lines above it; fall back to an 80\u00D724 assumption\n * when the stream reports no row count (piped / test stdout).\n */\n private maxFooterLines(): number {\n return Math.max(3, (this.stdout.rows ?? 24) - 6)\n }\n\n /** Mount or repaint the live region from the current header / logs / panel snapshot. */\n private rerenderPersistent(): void {\n const tree = (\n <LiveRegion\n headerLines={this.headerLines}\n logLines={this.logLines}\n footerLines={this.footerLines}\n maxFooterLines={this.maxFooterLines()}\n />\n )\n\n if (this.instance) {\n this.instance.rerender(tree)\n\n return\n }\n this.instance = this.renderFn(tree, { stdout: this.stdout, exitOnCtrlC: false, patchConsole: false })\n }\n\n /** Re-clamp + repaint on terminal resize (SIGWINCH), so a shrink never overflows the viewport. */\n private readonly onResize = (): void => {\n if (this.persistent) {\n this.rerenderPersistent()\n }\n }\n\n /**\n * Repaint the live status rows in place from a fresh summary (header + runner lines untouched).\n *\n * This is the panel's heartbeat. With no log tail on screen, a panel whose numbers never move is\n * indistinguishable from a hung process \u2014 so this is what proves the session is alive.\n */\n refresh(summary: ReadySummary): void {\n // A session still in boot has no panel to refresh.\n if (!this.persistent) {\n return\n }\n this.footerLines = this.renderer.formatFooterLines(summary)\n this.rerenderPersistent()\n }\n\n dispose(): void {\n if (this.persistent) {\n // Commit the last panel state, then release the terminal.\n this.rerenderPersistent()\n if (typeof this.stdout.off === 'function') {\n this.stdout.off('resize', this.onResize)\n }\n }\n this.finalized = true\n this.persistent = false\n this.unmount()\n }\n}\n", "import { Box, Text } from 'ink'\nimport { useEffect, useState } from 'react'\n\n/**\n * The Ink boot region for `infra-kit dev`: an animated spinner + phase line while the server boots.\n *\n * The ready header is NOT painted here. `PersistentInkDevUi.ready()` commits it through the persistent\n * panel instead, so this component only ever renders the transient spinner.\n *\n * HARD INVARIANT \u2014 this component (and every boot component under `src/tui/dev-ui/`) is OUTPUT-ONLY.\n * It MUST NEVER call `useInput`. `useInput` arms Ink's raw mode + Ctrl-C interception, which would\n * steal SIGINT from the process signal handler that owns dev-server shutdown. The spinner animates via\n * a self-contained interval only; there is no keyboard input during boot. Do not add `useInput` here.\n */\n\nexport interface BootRegionProps {\n /** Current boot phase, shown beside the spinner. */\n phase: string\n /** Latest narration detail (dim subtitle under the spinner); empty hides the line. */\n narration: string\n}\n\n/** Animated boot spinner with a phase line and an optional narration subtitle. */\nexport const BootRegion = (props: BootRegionProps) => {\n const { phase, narration } = props\n\n const [frame, setFrame] = useState(0)\n\n useEffect(() => {\n const timer = setInterval(() => {\n setFrame((f) => {\n return f + 1\n })\n }, SPINNER_INTERVAL_MS)\n\n return () => {\n clearInterval(timer)\n }\n }, [])\n\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color=\"cyan\">{SPINNER_FRAMES[frame % SPINNER_FRAMES.length]}</Text>\n <Text dimColor>{` ${phase}`}</Text>\n </Box>\n {narration ? <Text dimColor>{narration}</Text> : null}\n </Box>\n )\n}\n\nconst SPINNER_FRAMES = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F']\nconst SPINNER_INTERVAL_MS = 80\n", "import { Box, Static, Text } from 'ink'\n\n/**\n * The persistent Ink live region for `infra-kit dev` (backend-only sessions): the committed header +\n * growing log scrollback above, and a live health footer re-rendered in place below.\n *\n * HARD INVARIANT \u2014 this component (and every component under `src/tui/dev-ui/`) is OUTPUT-ONLY. It\n * MUST NEVER call `useInput`. `useInput` arms Ink's raw mode + Ctrl-C interception, which would steal\n * SIGINT from the process signal handler that owns dev-server shutdown. There is no keyboard input in\n * the live region \u2014 it is props only, with no state, no effects, no input. Do not add `useInput` here.\n */\n\nexport interface LiveRegionProps {\n /** Reference header, committed once to scrollback via `<Static>` (from `formatHeaderLines`). */\n headerLines: string[]\n /** Log lines committed above the footer as they arrive (also via the SAME `<Static>`). */\n logLines: string[]\n /** Live footer, re-rendered in place on every health change (from `formatFooterLines`). */\n footerLines: string[]\n /**\n * Cap on rendered footer rows so a many-backend session never eats a short viewport (the footer is a\n * live region \u2014 it cannot scroll). Overflow collapses into a trailing dim `\u2026 +N more` line. Omit for\n * no cap. The pinned footer must stay short; the full health picture is always in the log file.\n */\n maxFooterLines?: number\n}\n\n/**\n * A SINGLE `<Static>` streams the header then the growing logs (Ink writes only newly-appended items\n * each commit, so the header lands first and logs accrete beneath it \u2014 one block, never two). The\n * footer is an ordinary `<Box>`, so it repaints in place on each rerender without touching scrollback.\n */\nexport const LiveRegion = (props: LiveRegionProps) => {\n const { headerLines, logLines, footerLines } = props\n\n const staticItems = [...headerLines, ...logLines]\n const footer = clampFooter(footerLines, props.maxFooterLines)\n\n return (\n <>\n <Static items={staticItems}>\n {(line, index) => {\n return <Text key={index}>{line}</Text>\n }}\n </Static>\n <Box flexDirection=\"column\">\n {footer.map((line, index) => {\n return <Text key={index}>{line}</Text>\n })}\n </Box>\n </>\n )\n}\n\n/** Cap the footer to `max` rows, collapsing the overflow into one trailing ` \u2026 +N more` line. */\nexport const clampFooter = (lines: string[], max?: number): string[] => {\n if (max == null || max < 1 || lines.length <= max) {\n return lines\n }\n\n const shown = lines.slice(0, max - 1)\n\n return [...shown, ` \u2026 +${lines.length - shown.length} more`]\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["inkRender", "process", "Box", "Text", "useEffect", "useState", "jsx", "jsxs", "BootRegion", "props", "phase", "narration", "frame", "setFrame", "timer", "f", "SPINNER_INTERVAL_MS", "SPINNER_FRAMES", "Box", "Static", "Text", "Fragment", "jsx", "jsxs", "LiveRegion", "props", "headerLines", "logLines", "footerLines", "staticItems", "footer", "clampFooter", "line", "index", "lines", "max", "shown", "jsx", "PersistentInkDevUi", "deps", "inkRender", "createSafeStream", "process", "DevRenderer", "text", "message", "level", "tree", "BootRegion", "options", "willWrite", "phase", "summary", "line", "LiveRegion"]
7
+ }
@@ -1,2 +1,2 @@
1
- import{h as i}from"./chunk-2QJAIOPI.js";import{a as t}from"./chunk-DPCWCXJD.js";import"./chunk-LKKKDB6V.js";import"./chunk-CHETBZ6M.js";import a from"node:fs";import o from"node:process";import{fileURLToPath as s}from"node:url";var m=r=>{let n=r.indexOf("--parent-pid");if(n===-1)return;let e=Number(r[n+1]);return Number.isInteger(e)&&e>0?e:void 0},p=()=>a.realpathSync(s(new URL("./cli.js",import.meta.url))),d=async()=>{await i(t.version,{selfRealPath:p(),parentPid:m(o.argv)})};d().catch(()=>{o.exitCode=0});
1
+ import{i}from"./chunk-YDW6324A.js";import{a as t}from"./chunk-VFU2USJG.js";import"./chunk-LKKKDB6V.js";import"./chunk-CHETBZ6M.js";import a from"node:fs";import o from"node:process";import{fileURLToPath as s}from"node:url";var m=r=>{let n=r.indexOf("--parent-pid");if(n===-1)return;let e=Number(r[n+1]);return Number.isInteger(e)&&e>0?e:void 0},p=()=>a.realpathSync(s(new URL("./cli.js",import.meta.url))),d=async()=>{await i(t.version,{selfRealPath:p(),parentPid:m(o.argv)})};d().catch(()=>{o.exitCode=0});
2
2
  //# sourceMappingURL=update-check.js.map
@@ -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.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": "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",
5
+ "mappings": "mIAYA,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.3.13",
4
+ "version": "0.3.15",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
@@ -13,27 +13,6 @@
13
13
  "engines": {
14
14
  "node": ">=24.x"
15
15
  },
16
- "scripts": {
17
- "inspector": "npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug",
18
- "build": "pnpm run clean-artifacts && node ./scripts/build.js",
19
- "prepack": "pnpm run build",
20
- "prepublishOnly": "pnpm run build",
21
- "infra-kit-check": "pnpm exec infra-kit audit",
22
- "clean-artifacts": "rm -rf dist",
23
- "clean-cache": "rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc",
24
- "prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore",
25
- "prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore",
26
- "eslint-check": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src",
27
- "eslint-fix": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix",
28
- "ts-check": "tsc --noEmit",
29
- "test": "pnpm exec vitest run --reporter=minimal",
30
- "test-watch": "pnpm exec vitest --watch --silent passed-only",
31
- "test-ui": "pnpm exec vitest --ui --silent passed-only",
32
- "test-report": "pnpm exec vitest run --coverage --silent passed-only",
33
- "qa:pty": "INFRA_KIT_REQUIRE_PTY=1 pnpm exec vitest run --reporter=minimal src/tui/__tests__/stdin-pause-pty.test.ts src/entry/__tests__/quit-keys-pty.test.ts",
34
- "qa": "pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo ✅ Success",
35
- "fix": "pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa"
36
- },
37
16
  "dependencies": {
38
17
  "@aws-lambda-powertools/logger": "^2.33.1",
39
18
  "@inquirer/checkbox": "^5.2.1",
@@ -41,12 +20,12 @@
41
20
  "@inquirer/input": "^5.1.2",
42
21
  "@inquirer/password": "^5.0.2",
43
22
  "@inquirer/select": "^5.2.1",
44
- "@modelcontextprotocol/sdk": "^1.30.0",
23
+ "@modelcontextprotocol/server": "^2.0.0",
45
24
  "@slip-stream-kit/config": "^0.3.13",
46
25
  "chalk": "^6.0.0",
47
26
  "chokidar": "^5.0.0",
48
27
  "commander": "^15.0.0",
49
- "fastify": "catalog:",
28
+ "fastify": "5.11.2",
50
29
  "ink": "^7.1.1",
51
30
  "pino": "^10.3.1",
52
31
  "pino-pretty": "^13.1.3",
@@ -57,12 +36,33 @@
57
36
  "zx": "^8.8.5"
58
37
  },
59
38
  "devDependencies": {
39
+ "@modelcontextprotocol/client": "^2.0.0",
40
+ "@modelcontextprotocol/sdk": "^1.30.0",
60
41
  "@types/aws-lambda": "^8.10.162",
61
42
  "@types/react": "19.2.17",
62
- "@wl/eslint-config": "workspace:*",
63
- "@wl/vitest-config": "workspace:*",
64
43
  "esbuild": "^0.28.2",
65
44
  "ink-testing-library": "^4.0.0",
66
- "typescript": "^6.0.3"
45
+ "typescript": "^6.0.3",
46
+ "@wl/eslint-config": "0.1.0",
47
+ "@wl/vitest-config": "0.1.0"
48
+ },
49
+ "scripts": {
50
+ "inspector": "npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug",
51
+ "build": "pnpm run clean-artifacts && node ./scripts/build.js",
52
+ "infra-kit-check": "pnpm exec infra-kit audit",
53
+ "clean-artifacts": "rm -rf dist",
54
+ "clean-cache": "rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc",
55
+ "prettier-fix": "pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore",
56
+ "prettier-check": "pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore",
57
+ "eslint-check": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src",
58
+ "eslint-fix": "pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix",
59
+ "ts-check": "tsc --noEmit",
60
+ "test": "pnpm exec vitest run --reporter=minimal",
61
+ "test-watch": "pnpm exec vitest --watch --silent passed-only",
62
+ "test-ui": "pnpm exec vitest --ui --silent passed-only",
63
+ "test-report": "pnpm exec vitest run --coverage --silent passed-only",
64
+ "qa:pty": "INFRA_KIT_REQUIRE_PTY=1 pnpm exec vitest run --reporter=minimal src/tui/__tests__/stdin-pause-pty.test.ts src/entry/__tests__/quit-keys-pty.test.ts",
65
+ "qa": "pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo ✅ Success",
66
+ "fix": "pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa"
67
67
  }
68
- }
68
+ }
package/readme.md CHANGED
@@ -46,7 +46,7 @@ Strict schema file that declares audit rules (`requiredScripts`, `requiredFiles`
46
46
  |-------|---------|---------|
47
47
  | **Develop** | `dev` | Start local dev server with portless proxy (interactive wizard, long-running) |
48
48
  | | `dev-status` | Report what `infra-kit dev` currently has running (read-only; finds the fragment dir by searching upward, so it works from any subdirectory) |
49
- | **Release** | `release merge-dev` | Merge `origin/dev` into every open release branch and push |
49
+ | **Release** | `release merge-dev` | Merge `origin/dev` into open release branches in a scratch worktree, then push atomically (`--dry-run`, `--versions`) |
50
50
  | | `release list` | List available releases |
51
51
  | | `release create` | Create a new release |
52
52
  | | `release desc-edit` | Edit release notes |
@@ -1,2 +0,0 @@
1
- import{b as P}from"./chunk-LKKKDB6V.js";import{m as f,q as E}from"./chunk-CHETBZ6M.js";import u from"node:path";var m="infra-kit",g=`${m}@latest`,S=(t,e,n)=>{let r=u.relative(n(u.resolve(t)),u.resolve(e));return r!==""&&!r.startsWith("..")&&!u.isAbsolute(r)},l=(t,e)=>u.resolve(t).split(u.sep).includes(e),z=(t,e)=>{let n=u.resolve(t).split(u.sep),r=n.indexOf("Cellar");return r!==-1&&n[r+1]===e},C=(t,e,n,r)=>{let o=t[e];return o!=null&&o!==""&&S(o,n,r)},H=[{manager:"volta",test:({selfRealPath:t,env:e,realpath:n})=>C(e,"VOLTA_HOME",t,n)||l(t,".volta")||l(t,"volta"),updateCommand:["volta","install",m],canSelfSpawn:!0},{manager:"homebrew",test:({selfRealPath:t})=>z(t,m),updateCommand:["brew","upgrade",m],canSelfSpawn:!1},{manager:"pnpm",test:({selfRealPath:t,env:e,realpath:n})=>C(e,"PNPM_HOME",t,n)||l(t,"pnpm")&&l(t,"global"),updateCommand:["pnpm","add","-g",g],canSelfSpawn:!0},{manager:"bun",test:({selfRealPath:t,env:e,realpath:n})=>C(e,"BUN_INSTALL",t,n)||l(t,".bun"),updateCommand:["bun","add","-g",g],canSelfSpawn:!0},{manager:"yarn",test:({selfRealPath:t})=>l(t,".yarn")||l(t,"yarn")&&l(t,"global"),updateCommand:["yarn","global","add",g],canSelfSpawn:!0},{manager:"npm",test:({selfRealPath:t,env:e,realpath:n})=>C(e,"npm_config_prefix",t,n),updateCommand:["npm","install","-g",g],canSelfSpawn:!0}],I=["npm","install","-g",g],b=t=>{let{selfRealPath:e,env:n,realpath:r,lazyNpmRoot:o}=t,s=H.find(({test:i})=>i({selfRealPath:e,env:n,realpath:r}));if(s)return{manager:s.manager,updateCommand:s.updateCommand,canSelfSpawn:s.canSelfSpawn};let a=o?.();return a!=null&&a!==""&&S(a,e,r)?{manager:"npm",updateCommand:I,canSelfSpawn:!0}:{manager:"unknown",updateCommand:I,canSelfSpawn:!1}},K=(t,e,n)=>l(t,"node_modules")&&S(e,t,n);import{realpathSync as G}from"node:fs";import $ from"node:path";var M=t=>{try{return G(t)}catch{return $.resolve(t)}};import{execFileSync as W}from"node:child_process";import B from"node:process";var Y=3e3,k=()=>{try{let e=W("npm",["root","-g"],{encoding:"utf-8",timeout:Y,stdio:["ignore","pipe","ignore"],shell:B.platform==="win32"}).trim();return e===""?void 0:e}catch{return}};import{spawnSync as de}from"node:child_process";import{homedir as fe}from"node:os";import v from"node:process";import d from"node:fs";import N from"node:path";import Q from"node:process";var X="update-check.lock",Z=1800*1e3,ee=()=>N.join(f(),X),te=(t,e)=>{try{e-d.statSync(t).mtimeMs>Z&&d.rmSync(t,{force:!0})}catch{}},A=(t={})=>{let e=t.nowMs??Date.now(),n=t.lockPath??ee();try{d.mkdirSync(N.dirname(n),{recursive:!0})}catch{return null}let r=()=>{try{return d.openSync(n,"wx",384)}catch{return null}},o=r();if(o===null&&(te(n,e),o=r()),o===null)return null;try{d.writeFileSync(o,String(Q.pid))}catch{}return()=>{try{d.closeSync(o)}catch{}try{d.rmSync(n,{force:!0})}catch{}}};var ne="https://registry.npmjs.org",re=5e3,oe=t=>Object.entries(t).find(([n,r])=>/^npm_config_registry$/i.test(n)&&r!=null&&r!=="")?.[1],ae=t=>{let e=oe(t),n=e!=null&&e!==""?e:ne;for(;n.endsWith("/");)n=n.slice(0,-1);return n},R=async(t,e=fetch)=>{let n=new AbortController,r=setTimeout(()=>{n.abort()},re);try{let o=await e(`${ae(t)}/${m}/latest`,{signal:n.signal,headers:{accept:"application/json"}});if(!o.ok)return null;let a=(await o.json())?.version;return typeof a=="string"&&a!==""?a:null}catch{return null}finally{clearTimeout(r)}};var se=/^(\d+)\.(\d+)\.(\d+)$/,_=t=>{let[e=""]=t.trim().split("+"),[n="",...r]=e.split("-"),o=se.exec(n);if(!o)return null;let[s,a,i]=[o[1],o[2],o[3]].map(Number);return{release:[s,a,i],prerelease:r.length>0?r.join("-").split("."):[]}},L=/^\d+$/,le=(t,e)=>{let n=L.test(t),r=L.test(e);return n&&r?Number(t)-Number(e):n!==r?n?-1:1:t<e?-1:1},ie=(t,e)=>{for(let n=0;n<Math.max(t.length,e.length);n+=1){let r=t[n],o=e[n];if(r===void 0)return-1;if(o===void 0)return 1;if(r!==o)return le(r,o)}return 0},U=(t,e)=>{let n=_(t),r=_(e);if(!n||!r)return!1;for(let a=0;a<3;a+=1){let i=n.release[a],h=r.release[a];if(i!==h)return i>h}let o=n.prerelease.length===0,s=r.prerelease.length===0;return o!==s?o:ie(n.prerelease,r.prerelease)>0};import T from"node:fs";import O from"node:path";var F="update-check.json",ce=1200*1e3,ue=()=>O.join(f(),F),pe=t=>Array.isArray(t)&&t.every(e=>typeof e=="string"),me=t=>{if(typeof t!="object"||t===null)return!1;let{lastCheckMs:e,latestVersion:n,updateCommand:r,outcome:o}=t;return typeof e=="number"&&Number.isFinite(e)&&(n===null||typeof n=="string")&&(r===null||pe(r))&&(o==null||typeof o=="string")},Ke=(t=e=>T.readFileSync(e,"utf8"))=>{try{let e=JSON.parse(t(ue()));return me(e)?e:null}catch{return null}},D=t=>{let e=f();T.mkdirSync(e,{recursive:!0}),E(O.join(e,F),JSON.stringify(t),384)},Ge=(t,e)=>{if(!t)return!0;let n=e-t.lastCheckMs;return n<0?!0:n>=ce};var ge=200,he=300*1e3,ye=t=>{try{return v.kill(t,0),!0}catch{return!1}},Ce=t=>new Promise(e=>{setTimeout(e,t)}),we=async(t,e)=>{let n=e.clock()+he;for(;e.clock()<n;){if(!e.isProcessAlive(t))return!0;await e.sleep(ge)}return!e.isProcessAlive(t)},rt=async(t,e)=>{let r=(e.acquireLock??A)();if(!r)return"already-running";try{return await Se(t,e)}finally{r()}},Se=async(t,e)=>{let n=e.env??v.env,r=e.nowMs??Date.now(),o=e.fetchLatest??R,s=e.writeCache??D,a=e.isProcessAlive??ye,i=e.sleep??Ce,h=e.clock??Date.now,V=e.lazyNpmRoot??k,j=e.spawnSync??de,c=await o(n),p=(x,q)=>(s({lastCheckMs:r,...q,outcome:x}),x);if(c===null)return p("fetch-failed",{latestVersion:null,updateCommand:null});if(!U(c,t))return p("up-to-date",{latestVersion:c,updateCommand:null});let{canSelfSpawn:J,updateCommand:y}=b({selfRealPath:e.selfRealPath,env:n,realpath:M,lazyNpmRoot:V});if(!J)return p("cannot-self-spawn",{latestVersion:c,updateCommand:y});if(e.parentPid==null)return p("parent-unknown",{latestVersion:c,updateCommand:null});if(s({lastCheckMs:r,latestVersion:c,updateCommand:null,outcome:"installing"}),!await we(e.parentPid,{isProcessAlive:a,sleep:i,clock:h}))return p("parent-still-running",{latestVersion:c,updateCommand:null});let w=j(y[0],y.slice(1),{stdio:"ignore",shell:v.platform==="win32",cwd:fe(),env:P(n),windowsHide:!0});return w.error||w.signal||w.status!==0?p("install-failed",{latestVersion:c,updateCommand:y}):p("installed",{latestVersion:null,updateCommand:null})};export{b as a,K as b,k as c,M as d,U as e,Ke as f,Ge as g,rt as h};
2
- //# sourceMappingURL=chunk-2QJAIOPI.js.map