infra-kit 0.1.129 → 0.1.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot-5GFZBDKL.js +2 -0
- package/dist/boot-5GFZBDKL.js.map +7 -0
- package/dist/chunk-4UUVKJYG.js +2 -0
- package/dist/chunk-4UUVKJYG.js.map +7 -0
- package/dist/chunk-52WL2IQX.js +4 -0
- package/dist/chunk-52WL2IQX.js.map +7 -0
- package/dist/chunk-6FU2TRU5.js +2 -0
- package/dist/chunk-6FU2TRU5.js.map +7 -0
- package/dist/chunk-6YAKVQZN.js +4 -0
- package/dist/chunk-6YAKVQZN.js.map +7 -0
- package/dist/chunk-C2HRONYA.js +6 -0
- package/dist/chunk-C2HRONYA.js.map +7 -0
- package/dist/chunk-CHETBZ6M.js +3 -0
- package/dist/chunk-CHETBZ6M.js.map +7 -0
- package/dist/chunk-F6VCGS3D.js +2 -0
- package/dist/chunk-F6VCGS3D.js.map +7 -0
- package/dist/chunk-LENH44GY.js +215 -0
- package/dist/chunk-LENH44GY.js.map +7 -0
- package/dist/chunk-LTKR3F4N.js +2 -0
- package/dist/chunk-LTKR3F4N.js.map +7 -0
- package/dist/chunk-O3YJM6IR.js +2 -0
- package/dist/chunk-O3YJM6IR.js.map +7 -0
- package/dist/chunk-SR2GFEY7.js +2 -0
- package/dist/chunk-SR2GFEY7.js.map +7 -0
- package/dist/chunk-TKZINCST.js +2 -0
- package/dist/chunk-TKZINCST.js.map +7 -0
- package/dist/chunk-VJPLVBRA.js +5 -0
- package/dist/chunk-VJPLVBRA.js.map +7 -0
- package/dist/chunk-X2L4F2VM.js +3 -0
- package/dist/chunk-X2L4F2VM.js.map +7 -0
- package/dist/cli.js +4 -19
- package/dist/cli.js.map +4 -4
- package/dist/dev-server.js +20 -16
- package/dist/dev-server.js.map +4 -4
- package/dist/dev-wizard-run-7HEKSAS2.js +2 -0
- package/dist/dev-wizard-run-7HEKSAS2.js.map +7 -0
- package/dist/lib/release-slug/release-slug.d.ts +26 -2
- package/dist/lib/vite/vite.d.ts +18 -4
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +3 -3
- package/dist/persistent-ink-dev-ui-4U4B2B7C.js +8 -0
- package/dist/persistent-ink-dev-ui-4U4B2B7C.js.map +7 -0
- package/dist/program.js +2 -0
- package/dist/program.js.map +7 -0
- package/dist/update-check.js +2 -0
- package/dist/update-check.js.map +7 -0
- package/dist/vite.js +1 -1
- package/package.json +6 -3
- package/dist/boot-SGM5RVLJ.js +0 -2
- package/dist/boot-SGM5RVLJ.js.map +0 -7
- package/dist/chunk-2PZRQHWF.js +0 -2
- package/dist/chunk-2PZRQHWF.js.map +0 -7
- package/dist/chunk-6RRAK2QO.js +0 -5
- package/dist/chunk-6RRAK2QO.js.map +0 -7
- package/dist/chunk-IX2A34UU.js +0 -2
- package/dist/chunk-IX2A34UU.js.map +0 -7
- package/dist/chunk-V5IDN7ZM.js +0 -162
- package/dist/chunk-V5IDN7ZM.js.map +0 -7
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/release-slug/release-slug.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared, dependency-light release-slug helper.\n *\n * Extracted from `lib/vite/vite.ts` so BOTH the published `infra-kit/vite` helper\n * (which re-exports it) and the dev-server's dev-context fragment writer derive the\n * `<release>` hostname segment from ONE implementation \u2014 the recorded slug and the\n * helper-computed slug can never drift. Pure (regex only, no imports) so importing it\n * into the lightweight `infra-kit/vite` bundle stays cheap.\n */\n\n/**\n * Slugify an arbitrary string into a single DNS label: lowercase, collapse every\n * non-alphanumeric run to `-`, and drop leading/trailing separators. Returns `''`\n * when the input carries no alphanumeric run (the caller must treat that as \"no label\").\n *\n * portless rejects any hostname outside `[a-z0-9.-]`, so every segment fed into a\n * `<release>.<packageName>.localhost` alias must pass through here. A scoped npm name\n * (`@hulyo/client-ui`) is the motivating case: registering it raw fails with\n * `Invalid hostname`, and because the driver swallows that into a best-effort `false`,\n * the whole hero-URL path degrades silently to `localhost:<port>`.\n *\n * Distinct from {@link slugifyRelease}: this does NOT strip a git-flow prefix, so a\n * package legitimately named `fix-utils` keeps its `fix-` prefix.\n *\n * @example\n * slugifyHostLabel('@hulyo/client-ui') // => 'hulyo-client-ui'\n * slugifyHostLabel('backend-api') // => 'backend-api'\n */\nexport const slugifyHostLabel = (label: string): string => {\n // Collect the alphanumeric runs and join with `-`. Doing it this way (rather\n // than collapse-then-trim) is linear and sidesteps a super-linear trim regex,\n // while inherently dropping any leading/trailing separators.\n const runs = label.toLowerCase().match(/[a-z0-9]+/g)\n\n return runs ? runs.join('-') : ''\n}\n\n/**\n * Slugify a git branch into a `<release>` token: strip a leading git-flow prefix\n * (`feature/`, `release/`, \u2026), then reduce the remainder to a single DNS label.\n *\n * @example\n * slugifyRelease('release/2.4') // => '2-4'\n * slugifyRelease('feature/HUL-123') // => 'hul-123'\n */\nexport const slugifyRelease = (branch: string): string => {\n return slugifyHostLabel(branch.replace(/^(?:feature|feat|release|hotfix|bugfix|fix|chore)\\//i, ''))\n}\n\n/**\n * The `<release>` label used when no git branch resolves (outside a repo, or a branch that slugifies to\n * nothing). Both the dev-server's alias writer and `infra-kit/vite`'s template interpolation fall back\n * to this SAME constant \u2014 a divergence here would emit a hostname no alias backs.\n */\nexport const DEFAULT_RELEASE_SLUG = 'local'\n"],
|
|
5
|
+
"mappings": "AA4BO,IAAMA,EAAoBC,GAA0B,CAIzD,IAAMC,EAAOD,EAAM,YAAY,EAAE,MAAM,YAAY,EAEnD,OAAOC,EAAOA,EAAK,KAAK,GAAG,EAAI,EACjC,EAUaC,EAAkBC,GACtBJ,EAAiBI,EAAO,QAAQ,uDAAwD,EAAE,CAAC,EAQvFC,EAAuB",
|
|
6
|
+
"names": ["slugifyHostLabel", "label", "runs", "slugifyRelease", "branch", "DEFAULT_RELEASE_SLUG"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as y,b as C,d as w,e as k}from"./chunk-F6VCGS3D.js";import{a as P}from"./chunk-6FU2TRU5.js";import{m as p,q as g}from"./chunk-CHETBZ6M.js";import{spawnSync as X}from"node:child_process";import{homedir as Z}from"node:os";import h from"node:process";import i from"node:fs";import b from"node:path";import O from"node:process";var V="update-check.lock",D=600*1e3,j=()=>b.join(p(),V),q=(t,e)=>{try{e-i.statSync(t).mtimeMs>D&&i.rmSync(t,{force:!0})}catch{}},S=(t={})=>{let e=t.nowMs??Date.now(),r=t.lockPath??j();try{i.mkdirSync(b.dirname(r),{recursive:!0})}catch{return null}let n=()=>{try{return i.openSync(r,"wx",384)}catch{return null}},o=n();if(o===null&&(q(r,e),o=n()),o===null)return null;try{i.writeFileSync(o,String(O.pid))}catch{}return()=>{try{i.closeSync(o)}catch{}try{i.rmSync(r,{force:!0})}catch{}}};var J="https://registry.npmjs.org",z=2500,G=t=>{let e=t.npm_config_registry,r=e!=null&&e!==""?e:J;for(;r.endsWith("/");)r=r.slice(0,-1);return r},E=async(t,e=fetch)=>{let r=new AbortController,n=setTimeout(()=>{r.abort()},z);try{let o=await e(`${G(t)}/${y}/latest`,{signal:r.signal,headers:{accept:"application/json"}});if(!o.ok)return null;let s=(await o.json())?.version;return typeof s=="string"&&s!==""?s:null}catch{return null}finally{clearTimeout(n)}};var H=/^(\d+)\.(\d+)\.(\d+)$/,U=t=>{let[e=""]=t.trim().split("+"),[r="",...n]=e.split("-"),o=H.exec(r);if(!o)return null;let[l,s,u]=[o[1],o[2],o[3]].map(Number);return{release:[l,s,u],prerelease:n.length>0?n.join("-").split("."):[]}},v=/^\d+$/,K=(t,e)=>{let r=v.test(t),n=v.test(e);return r&&n?Number(t)-Number(e):r!==n?r?-1:1:t<e?-1:1},$=(t,e)=>{for(let r=0;r<Math.max(t.length,e.length);r+=1){let n=t[r],o=e[r];if(n===void 0)return-1;if(o===void 0)return 1;if(n!==o)return K(n,o)}return 0},x=(t,e)=>{let r=U(t),n=U(e);if(!r||!n)return!1;for(let s=0;s<3;s+=1){let u=r.release[s],m=n.release[s];if(u!==m)return u>m}let o=r.prerelease.length===0,l=n.prerelease.length===0;return o!==l?o:$(r.prerelease,n.prerelease)>0};import N from"node:fs";import L from"node:path";var A="update-check.json",W=1440*60*1e3,B=()=>L.join(p(),A),Y=t=>Array.isArray(t)&&t.every(e=>typeof e=="string"),Q=t=>{if(typeof t!="object"||t===null)return!1;let{lastCheckMs:e,latestVersion:r,updateCommand:n}=t;return typeof e=="number"&&Number.isFinite(e)&&(r===null||typeof r=="string")&&(n===null||Y(n))},Ce=(t=e=>N.readFileSync(e,"utf8"))=>{try{let e=JSON.parse(t(B()));return Q(e)?e:null}catch{return null}},M=t=>{let e=p();N.mkdirSync(e,{recursive:!0}),g(L.join(e,A),JSON.stringify(t),384)},we=(t,e)=>{if(!t)return!0;let r=e-t.lastCheckMs;return r>=W||r<0};var ee=200,te=300*1e3,re=t=>{try{return h.kill(t,0),!0}catch{return!1}},ne=t=>new Promise(e=>{setTimeout(e,t)}),oe=async(t,e)=>{let r=e.clock()+te;for(;e.clock()<r;){if(!e.isProcessAlive(t))return!0;await e.sleep(ee)}return!e.isProcessAlive(t)},Ae=async(t,e)=>{let n=(e.acquireLock??S)();if(!n)return"already-running";try{return await se(t,e)}finally{n()}},se=async(t,e)=>{let r=e.env??h.env,n=e.nowMs??Date.now(),o=e.fetchLatest??E,l=e.writeCache??M,s=e.isProcessAlive??re,u=e.sleep??ne,m=e.clock??Date.now,R=e.lazyNpmRoot??w,_=e.spawnSync??X,a=await o(r),c=(I,F)=>(l({lastCheckMs:n,...F}),I);if(a===null)return c("fetch-failed",{latestVersion:null,updateCommand:null});if(!x(a,t))return c("up-to-date",{latestVersion:a,updateCommand:null});let{canSelfSpawn:T,updateCommand:f}=C({selfRealPath:e.selfRealPath,env:r,realpath:k,lazyNpmRoot:R});if(!T)return c("cannot-self-spawn",{latestVersion:a,updateCommand:f});if(e.parentPid==null)return c("parent-unknown",{latestVersion:a,updateCommand:null});if(!await oe(e.parentPid,{isProcessAlive:s,sleep:u,clock:m}))return c("parent-still-running",{latestVersion:a,updateCommand:null});let d=_(f[0],f.slice(1),{stdio:"ignore",shell:h.platform==="win32",cwd:Z(),env:P(r),windowsHide:!0});return d.error||d.signal||d.status!==0?c("install-failed",{latestVersion:a,updateCommand:f}):c("installed",{latestVersion:null,updateCommand:null})};export{x as a,Ce as b,we as c,Ae as d};
|
|
2
|
+
//# sourceMappingURL=chunk-O3YJM6IR.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/update-check/run-update-check.ts", "../src/lib/update-check/lock.ts", "../src/lib/update-check/registry.ts", "../src/lib/update-check/semver.ts", "../src/lib/update-check/update-cache.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The CHILD half of the auto-update, spawned detached by `maybeAutoUpdate`. It outlives the CLI\n * invocation that started it, so it may take its time and it may replace the binary.\n *\n * WHY IT WAITS FOR THE PARENT TO EXIT \u2014 the load-bearing invariant of this whole feature:\n * `scripts/build.js` sets esbuild `splitting: true`, so `dist/cli.js` lazily imports sibling\n * `chunk-*.js` files at runtime (that is how the Ink TUI stays off the fast path). A package manager\n * installing over `dist/` mid-command deletes chunks the parent has not imported yet, and the parent\n * dies on a dynamic import of a file that no longer exists. Waiting for the parent to exit is what\n * makes a silent background install safe rather than a random crash under `infra-kit dev`.\n */\nimport { spawnSync } from 'node:child_process'\nimport { homedir } from 'node:os'\nimport process from 'node:process'\n\nimport { defaultLazyNpmRoot, detectInstallManager, safeRealpath } from 'src/lib/install-manager'\nimport { withoutPackageManagerEnv } from 'src/lib/pm-env'\n\nimport { acquireUpdateLock } from './lock'\nimport { fetchLatestVersion } from './registry'\nimport { isNewerVersion } from './semver'\nimport { writeUpdateCache } from './update-cache'\nimport type { UpdateCache } from './update-cache'\n\n/** How often to re-check whether the parent is gone. */\nexport const PARENT_POLL_INTERVAL_MS = 200\n\n/**\n * Give up waiting after this long. A long-lived parent (`infra-kit dev` runs for hours) must not leave\n * an immortal child pinned to a stale version: we simply skip this cycle. `lastCheckMs` is already\n * persisted by then, so the next short-lived command re-checks after the normal 24h window.\n */\nexport const PARENT_WAIT_TIMEOUT_MS = 5 * 60 * 1000\n\nexport interface RunUpdateCheckDeps {\n env?: NodeJS.ProcessEnv\n nowMs?: number\n fetchLatest?: (env: NodeJS.ProcessEnv) => Promise<string | null>\n writeCache?: typeof writeUpdateCache\n isProcessAlive?: (pid: number) => boolean\n sleep?: (ms: number) => Promise<void>\n /** Monotonic-ish source for the parent-wait deadline. Injected so the timeout is testable without real time. */\n clock?: () => number\n /** `npm root -g` probe. Defaults to the real subprocess; this child is detached, so it can afford one. */\n lazyNpmRoot?: () => string | undefined\n /** Single-flight guard. Returns a release fn, or null when another worker already holds the lock. */\n acquireLock?: () => (() => void) | null\n spawnSync?: typeof spawnSync\n /** Realpath of the installed `dist/cli.js`, used to identify the owning package manager. */\n selfRealPath: string\n parentPid?: number\n}\n\n/** Signal 0 performs the permission/existence check without delivering anything. */\nconst defaultIsProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0)\n\n return true\n } catch {\n return false\n }\n}\n\nconst defaultSleep = (ms: number): Promise<void> => {\n return new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n}\n\n/**\n * Block until `parentPid` exits or {@link PARENT_WAIT_TIMEOUT_MS} elapses. Returns whether the parent\n * is actually gone \u2014 the caller must not install on a timeout.\n */\nconst waitForParentExit = async (\n parentPid: number,\n deps: Required<Pick<RunUpdateCheckDeps, 'isProcessAlive' | 'sleep' | 'clock'>>,\n): Promise<boolean> => {\n const deadline = deps.clock() + PARENT_WAIT_TIMEOUT_MS\n\n while (deps.clock() < deadline) {\n if (!deps.isProcessAlive(parentPid)) return true\n\n await deps.sleep(PARENT_POLL_INTERVAL_MS)\n }\n\n return !deps.isProcessAlive(parentPid)\n}\n\nexport type UpdateCheckOutcome =\n | 'installed'\n | 'install-failed'\n | 'up-to-date'\n | 'fetch-failed'\n | 'cannot-self-spawn'\n | 'parent-still-running'\n | 'parent-unknown'\n | 'already-running'\n\n/**\n * Fetch, decide, and (when safe) install \u2014 returning WHY it did what it did so tests can distinguish\n * \"no update\" from \"could not install\". Never throws.\n *\n * `lastCheckMs` is written from the ATTEMPT, before any early return. If it were written only on\n * success, an offline user would re-spawn a doomed child on every single command.\n *\n * @example\n * await runUpdateCheck('0.1.130', { selfRealPath: '/usr/local/lib/node_modules/infra-kit/dist/cli.js' })\n * // => 'installed'\n */\nexport const runUpdateCheck = async (currentVersion: string, deps: RunUpdateCheckDeps): Promise<UpdateCheckOutcome> => {\n const acquireLock = deps.acquireLock ?? acquireUpdateLock\n\n // Single-flight. N shells launched at once all read the same stale cache and each spawns a worker;\n // the cache throttle cannot stop them because it is only written after the fetch returns. Without\n // this, a pending update means N concurrent `npm install -g` over one global directory.\n const release = acquireLock()\n\n if (!release) return 'already-running'\n\n try {\n return await runUpdateCheckLocked(currentVersion, deps)\n } finally {\n release()\n }\n}\n\nconst runUpdateCheckLocked = async (currentVersion: string, deps: RunUpdateCheckDeps): Promise<UpdateCheckOutcome> => {\n const env = deps.env ?? process.env\n const nowMs = deps.nowMs ?? Date.now()\n const fetchLatest = deps.fetchLatest ?? fetchLatestVersion\n const writeCache = deps.writeCache ?? writeUpdateCache\n const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive\n const sleep = deps.sleep ?? defaultSleep\n const clock = deps.clock ?? Date.now\n const lazyNpmRoot = deps.lazyNpmRoot ?? defaultLazyNpmRoot\n const spawn = deps.spawnSync ?? spawnSync\n\n const latestVersion = await fetchLatest(env)\n\n // Every path below writes the cache EXACTLY once, and always with `lastCheckMs: nowMs` \u2014 the throttle\n // burns on the ATTEMPT, never on success. If it burned only on success, an offline user would respawn\n // a doomed child on every command.\n const finish = (outcome: UpdateCheckOutcome, cache: Omit<UpdateCache, 'lastCheckMs'>): UpdateCheckOutcome => {\n writeCache({ lastCheckMs: nowMs, ...cache })\n\n return outcome\n }\n\n if (latestVersion === null) return finish('fetch-failed', { latestVersion: null, updateCommand: null })\n if (!isNewerVersion(latestVersion, currentVersion))\n return finish('up-to-date', { latestVersion, updateCommand: null })\n\n // `lazyNpmRoot` is what makes the COMMON case work: a plain `npm i -g infra-kit` leaves no\n // `npm_config_prefix` in the user's shell, so every cheap matcher misses and detection would report\n // `unknown` / `canSelfSpawn: false`. Without this probe the auto-update would silently degrade to a\n // notice for the majority of installs. The subprocess is affordable here and nowhere else.\n const { canSelfSpawn, updateCommand } = detectInstallManager({\n selfRealPath: deps.selfRealPath,\n env,\n realpath: safeRealpath,\n lazyNpmRoot,\n })\n\n // Homebrew relinks its prefix and may prompt; an unknown location means the command is a guess.\n // Both stay the user's call, so record the command for `maybeAutoUpdate` to print next invocation.\n if (!canSelfSpawn) return finish('cannot-self-spawn', { latestVersion, updateCommand })\n\n // Fail SAFE. Without a parent to outlive we cannot know whether a live CLI is still lazily importing\n // `chunk-*.js` out of the `dist/` we are about to replace, so we skip the cycle rather than install\n // blind. The real spawn always passes `--parent-pid`; only a hand-run worker lands here.\n if (deps.parentPid == null) return finish('parent-unknown', { latestVersion, updateCommand: null })\n\n const parentGone = await waitForParentExit(deps.parentPid, { isProcessAlive, sleep, clock })\n\n // A long-lived parent (`infra-kit dev`) outlasted the wait. Stay silent and retry next window.\n if (!parentGone) return finish('parent-still-running', { latestVersion, updateCommand: null })\n\n // `shell` on win32 so the `.cmd` shims npm/pnpm/yarn ship as global bins resolve.\n // `withoutPackageManagerEnv` strips inherited `npm_*` vars, which otherwise make pnpm/portless-style\n // tools believe they were invoked via `npx`/`dlx` and refuse to run.\n //\n // `cwd` is pinned to the home directory, and this is a SECURITY control, not tidiness: npm resolves\n // `registry=` from an `.npmrc` on disk relative to the cwd. Inheriting the caller's cwd would let any\n // repo containing a hostile `.npmrc` silently redirect this unattended `install -g` to an attacker's\n // registry, executing its lifecycle scripts. Stripping `npm_config_registry` from the env does NOT\n // close that hole, because the redirect lives in a file, not the environment.\n const result = spawn(updateCommand[0] as string, updateCommand.slice(1), {\n stdio: 'ignore',\n shell: process.platform === 'win32',\n cwd: homedir(),\n env: withoutPackageManagerEnv(env),\n windowsHide: true,\n })\n\n // Record the manual command so a persistently failing silent install (EACCES on a root-owned global\n // dir, say) still surfaces ONE actionable line, instead of failing invisibly forever.\n if (result.error || result.signal || result.status !== 0) {\n return finish('install-failed', { latestVersion, updateCommand })\n }\n\n // The installed version is now `latestVersion`; clear it so the next run does not re-notify.\n return finish('installed', { latestVersion: null, updateCommand: null })\n}\n", "/**\n * Single-flight lock for the background update worker.\n *\n * Without it, N shells starting at once all read the same stale cache and each spawns a worker \u2014 and\n * once a newer version exists, each of those runs `npm install -g` concurrently, over the same global\n * directory. (Measured: five concurrent `ik` invocations spawn five workers.) The throttle in the cache\n * cannot prevent this: it is only written AFTER the fetch returns, long after the other workers launched.\n *\n * `openSync(path, 'wx')` is the primitive \u2014 an atomic create-if-absent, so exactly one worker wins even\n * if all of them call it in the same millisecond.\n */\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { getCacheRoot } from 'src/lib/constants'\n\nexport const LOCK_FILE_NAME = 'update-check.lock'\n\n/**\n * A lock older than this is assumed to belong to a worker that was killed before it could clean up.\n * Must exceed the worker's own worst case (a 5-minute parent wait plus a 2.5s fetch), or a long-lived\n * `infra-kit dev` session would let a healthy lock be stolen out from under its worker.\n */\nexport const LOCK_STALE_MS = 10 * 60 * 1000\n\nexport const lockFilePath = (): string => {\n return path.join(getCacheRoot(), LOCK_FILE_NAME)\n}\n\nexport interface LockDeps {\n nowMs?: number\n lockPath?: string\n}\n\n/** Delete a lock whose mtime predates the staleness window. Best-effort: losing the race is harmless. */\nconst reapIfStale = (lockPath: string, nowMs: number): void => {\n try {\n if (nowMs - fs.statSync(lockPath).mtimeMs > LOCK_STALE_MS) fs.rmSync(lockPath, { force: true })\n } catch {\n // Vanished under us \u2014 another worker reaped it. Nothing to do.\n }\n}\n\n/**\n * Take the lock, or return null when another worker already holds it.\n *\n * Returns a release function rather than a boolean so the caller cannot forget which path releases:\n * there is exactly one handle, and it is the only thing that can unlink the file.\n *\n * @example\n * const release = acquireUpdateLock()\n * if (!release) return 'already-running'\n * try { ... } finally { release() }\n */\nexport const acquireUpdateLock = (deps: LockDeps = {}): (() => void) | null => {\n const nowMs = deps.nowMs ?? Date.now()\n const lockPath = deps.lockPath ?? lockFilePath()\n\n try {\n fs.mkdirSync(path.dirname(lockPath), { recursive: true })\n } catch {\n return null\n }\n\n const open = (): number | null => {\n try {\n // 'wx' fails with EEXIST if the file is already there: an atomic test-and-set.\n return fs.openSync(lockPath, 'wx', 0o600)\n } catch {\n return null\n }\n }\n\n let fd = open()\n\n if (fd === null) {\n reapIfStale(lockPath, nowMs)\n // One retry only. If a live worker holds the lock, we are the loser and must simply stand down.\n fd = open()\n }\n\n if (fd === null) return null\n\n try {\n fs.writeFileSync(fd, String(process.pid))\n } catch {\n // The pid is a debugging aid, not part of the protocol; the lock is held either way.\n }\n\n return () => {\n try {\n fs.closeSync(fd)\n } catch {\n // Already closed.\n }\n\n try {\n fs.rmSync(lockPath, { force: true })\n } catch {\n // Already gone; a later worker will reap it via LOCK_STALE_MS regardless.\n }\n }\n}\n", "/**\n * Ask the npm registry for the `latest` dist-tag. Node >= 24 (see `engines`), so global `fetch` is\n * available and this needs no dependency.\n */\nimport { PACKAGE_NAME } from 'src/lib/install-manager'\n\nexport const DEFAULT_REGISTRY = 'https://registry.npmjs.org'\n\n/** Bounded so a hanging registry can never keep a detached child alive indefinitely. */\nexport const FETCH_TIMEOUT_MS = 2_500\n\n/**\n * The registry this install actually talks to. A user behind a corporate mirror has `npm_config_registry`\n * set; hitting registry.npmjs.org directly would either fail closed (firewall) or, worse, report a public\n * version they cannot install.\n *\n * @example\n * registryUrl({ npm_config_registry: 'https://nexus.corp/repo/npm/' }) // => 'https://nexus.corp/repo/npm'\n */\nexport const registryUrl = (env: NodeJS.ProcessEnv): string => {\n const configured = env.npm_config_registry\n\n let base = configured != null && configured !== '' ? configured : DEFAULT_REGISTRY\n\n // A `/\\/+$/` regex would do this in one line, but its backtracking is super-linear on a hostile input.\n while (base.endsWith('/')) {\n base = base.slice(0, -1)\n }\n\n return base\n}\n\n/**\n * The published `latest` version, or null on ANY failure (offline, timeout, non-200, malformed body).\n * Never throws: a failed check must be indistinguishable from \"no update available\" to every caller.\n *\n * @example\n * await fetchLatestVersion(process.env) // => '0.1.131' | null\n */\nexport const fetchLatestVersion = async (\n env: NodeJS.ProcessEnv,\n fetchFn: typeof fetch = fetch,\n): Promise<string | null> => {\n const controller = new AbortController()\n const timer = setTimeout(() => {\n controller.abort()\n }, FETCH_TIMEOUT_MS)\n\n try {\n const response = await fetchFn(`${registryUrl(env)}/${PACKAGE_NAME}/latest`, {\n signal: controller.signal,\n headers: { accept: 'application/json' },\n })\n\n if (!response.ok) return null\n\n const body: unknown = await response.json()\n const version = (body as { version?: unknown } | null)?.version\n\n return typeof version === 'string' && version !== '' ? version : null\n } catch {\n return null\n } finally {\n clearTimeout(timer)\n }\n}\n", "/**\n * Registry-safe version comparison for the auto-update check.\n *\n * Deliberately NOT `src/lib/version-utils`: `parseVersion` there does `versionStr.slice(1)` because it\n * only ever sees `v`-prefixed release tags, so it turns a bare registry version (`0.1.130`) into\n * `[NaN, 1, 130]`. Feeding npm's `dist-tags.latest` through it silently compares NaNs and never fires.\n * These inputs are bare semver from `registry.npmjs.org` and from our own `package.json`.\n */\n\n/** `1.2.3-beta.4+build` \u2192 the `[1, 2, 3]` release triple and the `beta.4` prerelease, or null if unparsable. */\ninterface ParsedVersion {\n release: [number, number, number]\n /** Dot-separated prerelease identifiers, empty when this is a final release. */\n prerelease: string[]\n}\n\nconst RELEASE_PATTERN = /^(\\d+)\\.(\\d+)\\.(\\d+)$/\n\n/**\n * Parse bare semver. Returns null (never throws, never NaNs) for anything that is not\n * `major.minor.patch` with optional `-prerelease` and `+build` \u2014 a garbled registry body must read as\n * \"no update\", not as \"update to NaN\".\n *\n * @example\n * parseSemver('0.1.130') // => { release: [0, 1, 130], prerelease: [] }\n * parseSemver('1.0.0-rc.1+abc') // => { release: [1, 0, 0], prerelease: ['rc', '1'] }\n * parseSemver('v1.0.0') // => null\n */\nexport const parseSemver = (version: string): ParsedVersion | null => {\n // Build metadata is ignored entirely by semver precedence rules.\n const [withoutBuild = ''] = version.trim().split('+')\n const [core = '', ...prereleaseParts] = withoutBuild.split('-')\n const match = RELEASE_PATTERN.exec(core)\n\n if (!match) return null\n\n const [major, minor, patch] = [match[1], match[2], match[3]].map(Number) as [number, number, number]\n\n return {\n release: [major, minor, patch],\n // Re-join on '-' so `1.0.0-rc-1` keeps its hyphen inside a single identifier.\n prerelease: prereleaseParts.length > 0 ? prereleaseParts.join('-').split('.') : [],\n }\n}\n\nconst NUMERIC_IDENTIFIER = /^\\d+$/\n\n/** Compare two unequal prerelease identifiers per semver \u00A711. Numeric ones rank below alphanumeric ones. */\nconst compareIdentifier = (left: string, right: string): number => {\n const leftNumeric = NUMERIC_IDENTIFIER.test(left)\n const rightNumeric = NUMERIC_IDENTIFIER.test(right)\n\n if (leftNumeric && rightNumeric) return Number(left) - Number(right)\n if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1\n\n return left < right ? -1 : 1\n}\n\n/** Compare prerelease identifier lists. A shorter list has lower precedence: `1.0.0-rc` < `1.0.0-rc.1`. */\nconst comparePrerelease = (a: string[], b: string[]): number => {\n for (let index = 0; index < Math.max(a.length, b.length); index += 1) {\n const left = a[index]\n const right = b[index]\n\n if (left === undefined) return -1\n if (right === undefined) return 1\n if (left !== right) return compareIdentifier(left, right)\n }\n\n return 0\n}\n\n/**\n * Is `latest` strictly newer than `current`? False when either is unparsable, so a bad registry\n * response can never trigger an install.\n *\n * The load-bearing case is NUMERIC, not lexical, comparison: `0.1.9` must be older than `0.1.130`.\n * A string compare would order them the other way and pin every user to the older build forever.\n *\n * A final release outranks its own prereleases (`1.0.0` > `1.0.0-rc.1`), so a user on `rc` is offered\n * the release, and a user on the release is never \"downgraded\" to an rc.\n *\n * @example\n * isNewerVersion('0.1.130', '0.1.9') // => true (numeric, not lexical)\n * isNewerVersion('1.0.0', '1.0.0-rc.1') // => true\n * isNewerVersion('0.1.130', '0.1.130') // => false\n * isNewerVersion('garbage', '0.1.0') // => false\n */\nexport const isNewerVersion = (latest: string, current: string): boolean => {\n const parsedLatest = parseSemver(latest)\n const parsedCurrent = parseSemver(current)\n\n if (!parsedLatest || !parsedCurrent) return false\n\n for (let index = 0; index < 3; index += 1) {\n const left = parsedLatest.release[index] as number\n const right = parsedCurrent.release[index] as number\n\n if (left !== right) return left > right\n }\n\n const latestIsFinal = parsedLatest.prerelease.length === 0\n const currentIsFinal = parsedCurrent.prerelease.length === 0\n\n if (latestIsFinal !== currentIsFinal) return latestIsFinal\n\n return comparePrerelease(parsedLatest.prerelease, parsedCurrent.prerelease) > 0\n}\n", "/**\n * The throttle + notice state for the auto-update check, at `$cacheRoot/update-check.json`.\n *\n * `getCacheRoot()` \u2014 NOT `getSessionCacheDir()`, which throws unless `INFRA_KIT_SESSION` is set. A user\n * who installed this CLI globally and never ran `infra-kit init` has no session, and the update check\n * must still work for exactly that person.\n */\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { atomicWriteFileSync, getCacheRoot } from 'src/lib/constants'\n\nexport const CACHE_FILE_NAME = 'update-check.json'\n\n/** Refresh at most once a day. A background check is cheap, but not once per shell command. */\nexport const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000\n\nexport interface UpdateCache {\n /**\n * When the last check was ATTEMPTED \u2014 never \"when it last succeeded\". An offline user whose fetch\n * throws must still burn their 24h window, or every single command spawns another doomed child.\n */\n lastCheckMs: number\n /** Latest version seen on the registry, or null when the last attempt failed. */\n latestVersion: string | null\n /**\n * The command the USER must run, set only when the worker was not allowed to install for them\n * (Homebrew, or an install location it could not identify). Null means \"handled, say nothing\".\n *\n * The worker decides this, not the reader: identifying the owning package manager can cost an\n * `npm root -g` subprocess, and the CLI startup path must never pay for one. The background child\n * already pays it, so it writes the verdict down.\n */\n updateCommand: string[] | null\n}\n\nexport const cacheFilePath = (): string => {\n return path.join(getCacheRoot(), CACHE_FILE_NAME)\n}\n\nconst isStringArray = (value: unknown): value is string[] => {\n return (\n Array.isArray(value) &&\n value.every((entry) => {\n return typeof entry === 'string'\n })\n )\n}\n\nconst isUpdateCache = (value: unknown): value is UpdateCache => {\n if (typeof value !== 'object' || value === null) return false\n\n const { lastCheckMs, latestVersion, updateCommand } = value as Partial<UpdateCache>\n\n return (\n typeof lastCheckMs === 'number' &&\n Number.isFinite(lastCheckMs) &&\n (latestVersion === null || typeof latestVersion === 'string') &&\n (updateCommand === null || isStringArray(updateCommand))\n )\n}\n\n/**\n * Read the cache, or null when it is missing/unreadable/corrupt. A null read means \"stale\" to every\n * caller, so a first run and a hand-mangled file behave identically: check again.\n *\n * @example\n * readUpdateCache() // => { lastCheckMs: 1770000000000, latestVersion: '0.1.131' } | null\n */\nexport const readUpdateCache = (\n readFile: (p: string) => string = (p) => {\n return fs.readFileSync(p, 'utf8')\n },\n): UpdateCache | null => {\n try {\n const parsed: unknown = JSON.parse(readFile(cacheFilePath()))\n\n return isUpdateCache(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\n/**\n * Persist the check result. Creates `$cacheRoot` first: `atomicWriteFileSync` writes a temp file\n * beside the target and renames, so it throws ENOENT on a machine that has never had a `~/.cache/infra-kit`.\n * Without this mkdir the write fails, `lastCheckMs` never lands, and the throttle degrades into a\n * detached-child spawn on every invocation.\n *\n * @example\n * writeUpdateCache({ lastCheckMs: Date.now(), latestVersion: '0.1.131' })\n */\nexport const writeUpdateCache = (cache: UpdateCache): void => {\n const root = getCacheRoot()\n\n fs.mkdirSync(root, { recursive: true })\n atomicWriteFileSync(path.join(root, CACHE_FILE_NAME), JSON.stringify(cache), 0o600)\n}\n\n/**\n * Has the throttle window elapsed? A missing cache is stale by definition (first run).\n *\n * A `lastCheckMs` in the future (clock skew, or a restored backup) also reads as stale rather than\n * locking the user out of updates until their clock catches up.\n *\n * @example\n * isStale(null, 1_000) // => true\n * isStale({ lastCheckMs: 0, latestVersion: null }, CHECK_INTERVAL_MS + 1) // => true\n */\nexport const isStale = (cache: UpdateCache | null, nowMs: number): boolean => {\n if (!cache) return true\n\n const elapsed = nowMs - cache.lastCheckMs\n\n return elapsed >= CHECK_INTERVAL_MS || elapsed < 0\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["spawnSync", "homedir", "process", "fs", "path", "process", "LOCK_FILE_NAME", "LOCK_STALE_MS", "lockFilePath", "path", "getCacheRoot", "reapIfStale", "lockPath", "nowMs", "fs", "acquireUpdateLock", "deps", "open", "fd", "process", "DEFAULT_REGISTRY", "FETCH_TIMEOUT_MS", "registryUrl", "env", "configured", "base", "fetchLatestVersion", "fetchFn", "controller", "timer", "response", "PACKAGE_NAME", "version", "RELEASE_PATTERN", "parseSemver", "version", "withoutBuild", "core", "prereleaseParts", "match", "major", "minor", "patch", "NUMERIC_IDENTIFIER", "compareIdentifier", "left", "right", "leftNumeric", "rightNumeric", "comparePrerelease", "a", "b", "index", "isNewerVersion", "latest", "current", "parsedLatest", "parsedCurrent", "latestIsFinal", "currentIsFinal", "fs", "path", "CACHE_FILE_NAME", "CHECK_INTERVAL_MS", "cacheFilePath", "path", "getCacheRoot", "isStringArray", "value", "entry", "isUpdateCache", "lastCheckMs", "latestVersion", "updateCommand", "readUpdateCache", "readFile", "p", "fs", "parsed", "writeUpdateCache", "cache", "root", "atomicWriteFileSync", "isStale", "nowMs", "elapsed", "PARENT_POLL_INTERVAL_MS", "PARENT_WAIT_TIMEOUT_MS", "defaultIsProcessAlive", "pid", "process", "defaultSleep", "ms", "resolve", "waitForParentExit", "parentPid", "deps", "deadline", "runUpdateCheck", "currentVersion", "release", "acquireUpdateLock", "runUpdateCheckLocked", "env", "nowMs", "fetchLatest", "fetchLatestVersion", "writeCache", "writeUpdateCache", "isProcessAlive", "sleep", "clock", "lazyNpmRoot", "defaultLazyNpmRoot", "spawn", "spawnSync", "latestVersion", "finish", "outcome", "cache", "isNewerVersion", "canSelfSpawn", "updateCommand", "detectInstallManager", "safeRealpath", "result", "homedir", "withoutPackageManagerEnv"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var i={name:"infra-kit",type:"module",version:"0.1.131",files:["dist"],description:"infra-kit",main:"dist/index.js",module:"dist/index.js",types:"dist/entry/index.d.ts",exports:{".":{types:"./dist/entry/index.d.ts",import:"./dist/index.js"},"./vite":{types:"./dist/entry/vite.d.ts",import:"./dist/vite.js"}},bin:{"infra-kit":"dist/cli.js",ik:"dist/cli.js"},engines:{node:">=24.x"},scripts:{inspector:"npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug",build:"pnpm run clean-artifacts && node ./scripts/build.js",prepack:"pnpm run build",prepublishOnly:"pnpm run build","infra-kit-check":"pnpm exec infra-kit audit","clean-artifacts":"rm -rf dist","clean-cache":"rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc","prettier-fix":"pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore","prettier-check":"pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore","eslint-check":"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src","eslint-fix":"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix","ts-check":"tsc --noEmit",test:"pnpm exec vitest run --reporter=minimal","test-watch":"pnpm exec vitest --watch --silent passed-only","test-ui":"pnpm exec vitest --ui --silent passed-only","test-report":"pnpm exec vitest run --coverage --silent passed-only",qa:"pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo \u2705 Success",fix:"pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa"},dependencies:{"@aws-lambda-powertools/logger":"^2.33.1","@inquirer/checkbox":"^5.2.1","@inquirer/confirm":"^6.1.1","@inquirer/select":"^5.2.1","@modelcontextprotocol/sdk":"^1.29.0",chalk:"^5.6.2",chokidar:"^5.0.0",commander:"^15.0.0",fastify:"5.10.0",ink:"^7.1.0",pino:"^10.3.1","pino-pretty":"^13.1.3",portless:"^0.15.1",react:"19.2.7",yaml:"^2.9.0",zod:"^4.4.3",zx:"^8.8.5"},devDependencies:{"@types/aws-lambda":"^8.10.162","@types/react":"19.2.17","@wl/eslint-config":"workspace:*","@wl/vitest-config":"workspace:*",esbuild:"^0.28.1","ink-testing-library":"^4.0.0",typescript:"^6.0.3"}};export{i as a};
|
|
2
|
+
//# sourceMappingURL=chunk-SR2GFEY7.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../package.json"],
|
|
4
|
+
"sourcesContent": ["{\n \"name\": \"infra-kit\",\n \"type\": \"module\",\n \"version\": \"0.1.131\",\n \"files\": [\n \"dist\"\n ],\n \"description\": \"infra-kit\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.js\",\n \"types\": \"dist/entry/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/entry/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./vite\": {\n \"types\": \"./dist/entry/vite.d.ts\",\n \"import\": \"./dist/vite.js\"\n }\n },\n \"bin\": {\n \"infra-kit\": \"dist/cli.js\",\n \"ik\": \"dist/cli.js\"\n },\n \"engines\": {\n \"node\": \">=24.x\"\n },\n \"scripts\": {\n \"inspector\": \"npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug\",\n \"build\": \"pnpm run clean-artifacts && node ./scripts/build.js\",\n \"prepack\": \"pnpm run build\",\n \"prepublishOnly\": \"pnpm run build\",\n \"infra-kit-check\": \"pnpm exec infra-kit audit\",\n \"clean-artifacts\": \"rm -rf dist\",\n \"clean-cache\": \"rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc\",\n \"prettier-fix\": \"pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore\",\n \"prettier-check\": \"pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore\",\n \"eslint-check\": \"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src\",\n \"eslint-fix\": \"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix\",\n \"ts-check\": \"tsc --noEmit\",\n \"test\": \"pnpm exec vitest run --reporter=minimal\",\n \"test-watch\": \"pnpm exec vitest --watch --silent passed-only\",\n \"test-ui\": \"pnpm exec vitest --ui --silent passed-only\",\n \"test-report\": \"pnpm exec vitest run --coverage --silent passed-only\",\n \"qa\": \"pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo \u2705 Success\",\n \"fix\": \"pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa\"\n },\n \"dependencies\": {\n \"@aws-lambda-powertools/logger\": \"^2.33.1\",\n \"@inquirer/checkbox\": \"^5.2.1\",\n \"@inquirer/confirm\": \"^6.1.1\",\n \"@inquirer/select\": \"^5.2.1\",\n \"@modelcontextprotocol/sdk\": \"^1.29.0\",\n \"chalk\": \"^5.6.2\",\n \"chokidar\": \"^5.0.0\",\n \"commander\": \"^15.0.0\",\n \"fastify\": \"5.10.0\",\n \"ink\": \"^7.1.0\",\n \"pino\": \"^10.3.1\",\n \"pino-pretty\": \"^13.1.3\",\n \"portless\": \"^0.15.1\",\n \"react\": \"19.2.7\",\n \"yaml\": \"^2.9.0\",\n \"zod\": \"^4.4.3\",\n \"zx\": \"^8.8.5\"\n },\n \"devDependencies\": {\n \"@types/aws-lambda\": \"^8.10.162\",\n \"@types/react\": \"19.2.17\",\n \"@wl/eslint-config\": \"workspace:*\",\n \"@wl/vitest-config\": \"workspace:*\",\n \"esbuild\": \"^0.28.1\",\n \"ink-testing-library\": \"^4.0.0\",\n \"typescript\": \"^6.0.3\"\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,IAAAA,EAAA,CACE,KAAQ,YACR,KAAQ,SACR,QAAW,UACX,MAAS,CACP,MACF,EACA,YAAe,YACf,KAAQ,gBACR,OAAU,gBACV,MAAS,wBACT,QAAW,CACT,IAAK,CACH,MAAS,0BACT,OAAU,iBACZ,EACA,SAAU,CACR,MAAS,yBACT,OAAU,gBACZ,CACF,EACA,IAAO,CACL,YAAa,cACb,GAAM,aACR,EACA,QAAW,CACT,KAAQ,QACV,EACA,QAAW,CACT,UAAa,iEACb,MAAS,sDACT,QAAW,iBACX,eAAkB,iBAClB,kBAAmB,4BACnB,kBAAmB,cACnB,cAAe,2EACf,eAAgB,4HAChB,iBAAkB,4HAClB,eAAgB,4EAChB,aAAc,kFACd,WAAY,eACZ,KAAQ,0CACR,aAAc,gDACd,UAAW,6CACX,cAAe,uDACf,GAAM,gHACN,IAAO,6DACT,EACA,aAAgB,CACd,gCAAiC,UACjC,qBAAsB,SACtB,oBAAqB,SACrB,mBAAoB,SACpB,4BAA6B,UAC7B,MAAS,SACT,SAAY,SACZ,UAAa,UACb,QAAW,SACX,IAAO,SACP,KAAQ,UACR,cAAe,UACf,SAAY,UACZ,MAAS,SACT,KAAQ,SACR,IAAO,SACP,GAAM,QACR,EACA,gBAAmB,CACjB,oBAAqB,YACrB,eAAgB,UAChB,oBAAqB,cACrB,oBAAqB,cACrB,QAAW,UACX,sBAAuB,SACvB,WAAc,QAChB,CACF",
|
|
6
|
+
"names": ["package_default"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{C as c,E as u,G as s,I as i,K as d,N as g,P as T,R as f,T as v,V as h,X as x,Z as E,aa as G,b as p,ca as M,ea as N,ga as P,ia as w,o as m,q as l,s as t,v as n,x as a}from"./chunk-LENH44GY.js";var o=[{cliName:"merge-dev",menuGroup:"release",mcpTool:c,mcpExposed:!0,groupPath:["release","merge-dev"]},{cliName:"release-list",menuGroup:"release",mcpTool:d,mcpExposed:!0,groupPath:["release","list"]},{cliName:"release-create",menuGroup:"release",mcpTool:g,mcpExposed:!0,groupPath:["release","create"]},{cliName:"release-desc-edit",menuGroup:"release",mcpTool:T,mcpExposed:!0,groupPath:["release","desc-edit"]},{cliName:"release-deploy-all",menuGroup:"release",mcpTool:s,mcpExposed:!0,groupPath:["release","deploy-all"]},{cliName:"release-deploy-selected",menuGroup:"release",mcpTool:i,mcpExposed:!0,groupPath:["release","deploy-selected"]},{cliName:"release-deliver",menuGroup:"release",mcpTool:u,mcpExposed:!1,groupPath:["release","deliver"]},{cliName:"worktrees-add",menuGroup:"worktrees",mcpTool:G,mcpExposed:!0,groupPath:["worktrees","add"]},{cliName:"worktrees-list",menuGroup:"worktrees",mcpTool:M,mcpExposed:!0,groupPath:["worktrees","list"]},{cliName:"worktrees-reload",menuGroup:"worktrees",mcpTool:N,mcpExposed:!0,groupPath:["worktrees","reload"]},{cliName:"worktrees-remove",menuGroup:"worktrees",mcpTool:P,mcpExposed:!1,groupPath:["worktrees","remove"]},{cliName:"worktrees-sync",menuGroup:"worktrees",mcpTool:w,mcpExposed:!0,groupPath:["worktrees","sync"]},{cliName:"audit",menuGroup:"environment",mcpTool:p,mcpExposed:!0,groupPath:["audit"]},{cliName:"vendor-check",menuGroup:"environment",mcpTool:f,mcpExposed:!0,groupPath:["vendor","check"]},{cliName:"vendor-diff",menuGroup:"environment",mcpTool:v,mcpExposed:!0,groupPath:["vendor","diff"]},{cliName:"vendor-config",menuGroup:"environment",mcpTool:null,mcpExposed:!1,groupPath:["vendor","config"]},{cliName:"config-path",menuGroup:"environment",mcpTool:null,mcpExposed:!1,groupPath:["config","path"]},{cliName:"config-edit",menuGroup:"environment",mcpTool:null,mcpExposed:!1,groupPath:["config","edit"],ownsScreen:!0},{cliName:"doctor",menuGroup:"environment",mcpTool:m,mcpExposed:!1,groupPath:["doctor"]},{cliName:"init",menuGroup:"environment",mcpTool:null,mcpExposed:!1,groupPath:["init"]},{cliName:"version",menuGroup:"environment",mcpTool:E,mcpExposed:!0,groupPath:["version"]},{cliName:"env-status",menuGroup:"environment",mcpTool:a,mcpExposed:!0,groupPath:["env-status"]},{cliName:"env-list",menuGroup:"environment",mcpTool:t,mcpExposed:!0,groupPath:["env-list"]},{cliName:"env-load",menuGroup:"environment",mcpTool:n,mcpExposed:!0,groupPath:["env-load"],sessionEnvNotice:!0},{cliName:"env-clear",menuGroup:"environment",mcpTool:l,mcpExposed:!0,groupPath:["env-clear"],sessionEnvNotice:!0},{cliName:"vendor",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["vendor"]},{cliName:"config",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["config"]},{cliName:"dev",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["dev"]},{cliName:"env-autoload",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["env-autoload"]},{cliName:"self-update",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["self-update"]},{cliName:"mcp",menuGroup:null,mcpTool:null,mcpExposed:!1,groupPath:["mcp"]},{cliName:"vendor-manifest",menuGroup:null,mcpTool:h,mcpExposed:!1,groupPath:["vendor","manifest"]},{cliName:"vendor-sync",menuGroup:null,mcpTool:x,mcpExposed:!1,groupPath:["vendor","sync"]}],k=()=>o.flatMap(e=>e.mcpExposed&&e.mcpTool?[e.mcpTool]:[]),y=e=>o.flatMap(r=>r.menuGroup===e?[r.cliName]:[]);export{o as a,k as b,y as c};
|
|
2
|
+
//# sourceMappingURL=chunk-TKZINCST.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/command-catalog/command-catalog.ts"],
|
|
4
|
+
"sourcesContent": ["import type { z } from 'zod'\n\nimport { auditMcpTool } from 'src/commands/audit'\nimport { doctorMcpTool } from 'src/commands/doctor'\nimport { envClearMcpTool } from 'src/commands/env-clear'\nimport { envListMcpTool } from 'src/commands/env-list'\nimport { envLoadMcpTool } from 'src/commands/env-load'\nimport { envStatusMcpTool } from 'src/commands/env-status'\nimport { ghMergeDevMcpTool } from 'src/commands/gh-merge-dev'\nimport { ghReleaseDeliverMcpTool } from 'src/commands/gh-release-deliver'\nimport { ghReleaseDeployAllMcpTool } from 'src/commands/gh-release-deploy-all'\nimport { ghReleaseDeploySelectedMcpTool } from 'src/commands/gh-release-deploy-selected'\nimport { ghReleaseListMcpTool } from 'src/commands/gh-release-list'\nimport { releaseCreateMcpTool } from 'src/commands/release-create'\nimport { releaseDescEditMcpTool } from 'src/commands/release-desc-edit'\nimport { vendorCheckMcpTool } from 'src/commands/vendor-check'\nimport { vendorDiffMcpTool } from 'src/commands/vendor-diff'\nimport { vendorManifestMcpTool } from 'src/commands/vendor-manifest'\nimport { vendorSyncMcpTool } from 'src/commands/vendor-sync'\nimport { versionMcpTool } from 'src/commands/version'\nimport { worktreesAddMcpTool } from 'src/commands/worktrees-add'\nimport { worktreesListMcpTool } from 'src/commands/worktrees-list'\nimport { worktreesReloadMcpTool } from 'src/commands/worktrees-reload'\nimport { worktreesRemoveMcpTool } from 'src/commands/worktrees-remove'\nimport { worktreesSyncMcpTool } from 'src/commands/worktrees-sync'\nimport type { ToolsExecutionResult } from 'src/types'\n\n/**\n * Registration-facing shape of an MCP tool. The concrete `*McpTool` definitions\n * are generic over their Zod input/output shapes (and invariant), so they cannot\n * share one precise `McpTool<...>` element type in an array. This widened, non-\n * generic view exposes exactly what registration needs and every concrete tool\n * assigns to it. Matches the loose handler typing already used in tool-handler.\n */\nexport interface CatalogMcpTool {\n name: string\n description: string\n inputSchema: z.ZodRawShape\n outputSchema: z.ZodRawShape\n // Heterogeneous tool params; loose `any` mirrors the existing tool-handler typing.\n handler: (params: any) => Promise<ToolsExecutionResult>\n}\n\n/**\n * Single source of truth for the CLI command surface. It consolidates what used\n * to live in three hand-maintained places (the MCP `tools[]` array and the\n * three no-arg-menu name arrays) into one list, so they can no longer drift.\n *\n * It does NOT replace Commander's `.command().option()` wiring in entry/cli.ts \u2014\n * that stays the source of truth for argument parsing. This catalog only carries\n * cross-surface metadata: the canonical names, which menu group a command shows\n * in, and whether the command is exposed as an MCP tool.\n */\n\n/** Top-level menu group for the no-arg interactive picker (null = not shown). */\nexport type MenuGroup = 'release' | 'worktrees' | 'environment'\n\nexport interface CommandCatalogEntry {\n /** CLI command name as registered in Commander (flat form, e.g. `merge-dev`). */\n cliName: string\n /** Menu group, or null for subcommands not shown at the top level. */\n menuGroup: MenuGroup | null\n /** The co-located MCP tool, or null for CLI-only commands (init/config/vendor group). */\n mcpTool: CatalogMcpTool | null\n /**\n * Whether the command is registered as an MCP tool. Explicit allowlist:\n * `doctor`, `vendor-sync`, and `vendor-manifest` are deliberately UNEXPOSED\n * (vendor-sync/manifest mutate consumer repos; doctor is host-inspecting), so\n * they must never become agent-callable by accident.\n */\n mcpExposed: boolean\n /**\n * Canonical Commander argv for this command (grouped form, e.g. `['vendor','check']`). The session\n * shell spawns `infra-kit <...groupPath>` so a menu pick runs the preferred grouped surface (not the\n * deprecated/hidden flat alias) and shows that as the replayable equivalent line.\n */\n groupPath: string[]\n /**\n * The command drives a full-screen child (an `$EDITOR`) that owns and restores the terminal itself.\n * The session shell must NOT wrap it in the alternate-screen buffer (a nested `rmcup` would fight\n * the parent's), and it quiets the child's own log lines instead. Only `config-edit` today.\n */\n ownsScreen?: boolean\n /**\n * Running this from inside the session cannot mutate the parent shell's env (a child can't). The\n * transcript entry appends a notice that the change applies only after the session exits. `env-load`\n * / `env-clear`.\n */\n sessionEnvNotice?: boolean\n}\n\n/**\n * Authored in no-arg-menu display order so the interactive picker derives\n * directly from this list (see entry/cli.ts). MCP registration filters this\n * list by `mcpExposed`; MCP tool order is not contractual (clients address\n * tools by name), so the registration order need not match the array order.\n */\nexport const commandCatalog: CommandCatalogEntry[] = [\n // --- Release Management (menu group) ---\n {\n cliName: 'merge-dev',\n menuGroup: 'release',\n mcpTool: ghMergeDevMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'merge-dev'],\n },\n {\n cliName: 'release-list',\n menuGroup: 'release',\n mcpTool: ghReleaseListMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'list'],\n },\n {\n cliName: 'release-create',\n menuGroup: 'release',\n mcpTool: releaseCreateMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'create'],\n },\n {\n cliName: 'release-desc-edit',\n menuGroup: 'release',\n mcpTool: releaseDescEditMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'desc-edit'],\n },\n {\n cliName: 'release-deploy-all',\n menuGroup: 'release',\n mcpTool: ghReleaseDeployAllMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'deploy-all'],\n },\n {\n cliName: 'release-deploy-selected',\n menuGroup: 'release',\n mcpTool: ghReleaseDeploySelectedMcpTool,\n mcpExposed: true,\n groupPath: ['release', 'deploy-selected'],\n },\n // release-deliver does prod delivery + admin-merge \u2014 genuinely irreversible,\n // so it is CLI-only by design (mirrors the vendor-sync/manifest rationale).\n {\n cliName: 'release-deliver',\n menuGroup: 'release',\n mcpTool: ghReleaseDeliverMcpTool,\n mcpExposed: false,\n groupPath: ['release', 'deliver'],\n },\n\n // --- Worktrees (menu group) ---\n {\n cliName: 'worktrees-add',\n menuGroup: 'worktrees',\n mcpTool: worktreesAddMcpTool,\n mcpExposed: true,\n groupPath: ['worktrees', 'add'],\n },\n {\n cliName: 'worktrees-list',\n menuGroup: 'worktrees',\n mcpTool: worktreesListMcpTool,\n mcpExposed: true,\n groupPath: ['worktrees', 'list'],\n },\n {\n cliName: 'worktrees-reload',\n menuGroup: 'worktrees',\n mcpTool: worktreesReloadMcpTool,\n mcpExposed: true,\n groupPath: ['worktrees', 'reload'],\n },\n // worktrees-remove runs `git worktree remove` on each leaf worktree \u2014\n // genuinely irreversible (uncommitted work is lost), so it is CLI-only by\n // design (mirrors the vendor-sync/manifest rationale).\n {\n cliName: 'worktrees-remove',\n menuGroup: 'worktrees',\n mcpTool: worktreesRemoveMcpTool,\n mcpExposed: false,\n groupPath: ['worktrees', 'remove'],\n },\n {\n cliName: 'worktrees-sync',\n menuGroup: 'worktrees',\n mcpTool: worktreesSyncMcpTool,\n mcpExposed: true,\n groupPath: ['worktrees', 'sync'],\n },\n\n // --- Environment (menu group) ---\n // Every menu-eligible entry must be a Commander LEAF (an action, no subcommands) so the session\n // shell's report discriminator holds. The bare `vendor`/`config` GROUPS are menuGroup:null \u2014 a bare\n // group prints help and exits non-zero, which the shell would misreport. Their useful leaves\n // (vendor-check/diff/config, config-path/edit) are surfaced here instead, each with a hidden flat\n // Commander alias (see src/entry/program.ts) so the palette can introspect + single-token dispatch.\n { cliName: 'audit', menuGroup: 'environment', mcpTool: auditMcpTool, mcpExposed: true, groupPath: ['audit'] },\n {\n cliName: 'vendor-check',\n menuGroup: 'environment',\n mcpTool: vendorCheckMcpTool,\n mcpExposed: true,\n groupPath: ['vendor', 'check'],\n },\n {\n cliName: 'vendor-diff',\n menuGroup: 'environment',\n mcpTool: vendorDiffMcpTool,\n mcpExposed: true,\n groupPath: ['vendor', 'diff'],\n },\n {\n cliName: 'vendor-config',\n menuGroup: 'environment',\n mcpTool: null,\n mcpExposed: false,\n groupPath: ['vendor', 'config'],\n },\n { cliName: 'config-path', menuGroup: 'environment', mcpTool: null, mcpExposed: false, groupPath: ['config', 'path'] },\n {\n cliName: 'config-edit',\n menuGroup: 'environment',\n mcpTool: null,\n mcpExposed: false,\n groupPath: ['config', 'edit'],\n ownsScreen: true,\n },\n { cliName: 'doctor', menuGroup: 'environment', mcpTool: doctorMcpTool, mcpExposed: false, groupPath: ['doctor'] },\n { cliName: 'init', menuGroup: 'environment', mcpTool: null, mcpExposed: false, groupPath: ['init'] },\n { cliName: 'version', menuGroup: 'environment', mcpTool: versionMcpTool, mcpExposed: true, groupPath: ['version'] },\n {\n cliName: 'env-status',\n menuGroup: 'environment',\n mcpTool: envStatusMcpTool,\n mcpExposed: true,\n groupPath: ['env-status'],\n },\n { cliName: 'env-list', menuGroup: 'environment', mcpTool: envListMcpTool, mcpExposed: true, groupPath: ['env-list'] },\n {\n cliName: 'env-load',\n menuGroup: 'environment',\n mcpTool: envLoadMcpTool,\n mcpExposed: true,\n groupPath: ['env-load'],\n sessionEnvNotice: true,\n },\n {\n cliName: 'env-clear',\n menuGroup: 'environment',\n mcpTool: envClearMcpTool,\n mcpExposed: true,\n groupPath: ['env-clear'],\n sessionEnvNotice: true,\n },\n\n // --- Not menu items (groups, long-running, or internal) ---\n // Bare groups: help + non-zero exit, so they never belong in the leaf-only menu.\n { cliName: 'vendor', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['vendor'] },\n { cliName: 'config', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['config'] },\n // Long-running local dev server (fastify + chokidar). Not an MCP tool \u2014 it never\n // returns, so it can't fit the request/response tool contract. menuGroup null:\n // the no-arg picker drives one-shot commands, not a blocking foreground process.\n { cliName: 'dev', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['dev'] },\n // Internal shell-startup trigger; hidden from the menu and never an MCP tool\n // (it can't apply env to a shell \u2014 only the zsh integration sources the file).\n { cliName: 'env-autoload', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['env-autoload'] },\n // The MCP boundary auto-confirms every tool, so an agent-triggered unattended global package install\n // must never be reachable there. menuGroup null keeps it off the no-arg picker too \u2014 updating the CLI\n // is a deliberate act, not something to land on by arrowing through a menu.\n { cliName: 'self-update', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['self-update'] },\n // Launcher for the MCP server itself; it blocks on a stdio transport, so it is neither a one-shot menu\n // command nor expressible as a request/response tool.\n { cliName: 'mcp', menuGroup: null, mcpTool: null, mcpExposed: false, groupPath: ['mcp'] },\n\n // --- vendor subcommands (not top-level menu items; MCP tools where applicable) ---\n {\n cliName: 'vendor-manifest',\n menuGroup: null,\n mcpTool: vendorManifestMcpTool,\n mcpExposed: false,\n groupPath: ['vendor', 'manifest'],\n },\n {\n cliName: 'vendor-sync',\n menuGroup: null,\n mcpTool: vendorSyncMcpTool,\n mcpExposed: false,\n groupPath: ['vendor', 'sync'],\n },\n]\n\n/** The MCP tools to register: catalog entries that are exposed and carry a tool. */\nexport const getExposedMcpTools = (): CatalogMcpTool[] => {\n return commandCatalog.flatMap((entry) => {\n return entry.mcpExposed && entry.mcpTool ? [entry.mcpTool] : []\n })\n}\n\n/** CLI command names for a menu group, in catalog (display) order. */\nexport const getMenuGroupCommands = (group: MenuGroup): string[] => {\n return commandCatalog.flatMap((entry) => {\n return entry.menuGroup === group ? [entry.cliName] : []\n })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["commandCatalog", "ghMergeDevMcpTool", "ghReleaseListMcpTool", "releaseCreateMcpTool", "releaseDescEditMcpTool", "ghReleaseDeployAllMcpTool", "ghReleaseDeploySelectedMcpTool", "ghReleaseDeliverMcpTool", "worktreesAddMcpTool", "worktreesListMcpTool", "worktreesReloadMcpTool", "worktreesRemoveMcpTool", "worktreesSyncMcpTool", "auditMcpTool", "vendorCheckMcpTool", "vendorDiffMcpTool", "doctorMcpTool", "versionMcpTool", "envStatusMcpTool", "envListMcpTool", "envLoadMcpTool", "envClearMcpTool", "vendorManifestMcpTool", "vendorSyncMcpTool", "getExposedMcpTools", "entry", "getMenuGroupCommands", "group"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{$ as De,A as ve,B as ye,D as he,F as we,H as ke,J as Se,L as Ce,M as Re,O as xe,Q as Ee,S as Ae,U as Le,W as be,Y as Pe,_ as N,a as X,ba as Ie,c as y,d as u,da as Te,e as Y,f as Q,fa as je,g as Z,h as D,ha as Ne,i as ee,j as oe,k as I,l as te,m as re,n as de,p as me,r as pe,t as fe,u as ue,w as ge,y as x,z as s}from"./chunk-LENH44GY.js";import{a as le}from"./chunk-52WL2IQX.js";import{R as P,S as z,U as B,m as H,v as c}from"./chunk-X2L4F2VM.js";import{e as j}from"./chunk-Z6KTUVIC.js";import{b as _e,d as $e,e as Me}from"./chunk-F6VCGS3D.js";import{a as E}from"./chunk-6FU2TRU5.js";import{a as R,b as ne,d as ie,f as ae,g as se,j as T,k as ce,n as g}from"./chunk-CHETBZ6M.js";import{Command as Jo}from"commander";import S from"node:process";import Oe from"node:process";import{$ as ko}from"zx";var _=async()=>{let e=await P(),o=await Promise.all([{label:"project (committed)",path:e.main},{label:"user global",path:e.userGlobal},{label:"user project",path:e.userProject}].map(async r=>({...r,exists:await y(r.path)}))),t=o.at(-1)?.exists===!0,i=await te(e.userProject,t),a=t?re(i):"";c.info(`Project name: ${e.projectName}
|
|
2
|
+
`),c.info(`Config merge chain (later overrides earlier):
|
|
3
|
+
`);for(let r of o){let d=r.exists?" [\u2713]":" [ ]",m=r.path===e.userProject&&a!==""?` ${a}`:"";c.info(`${d} ${r.label.padEnd(22)} ${u(r.path)}${m}`)}let n={projectName:e.projectName,layers:o.map(r=>({label:r.label,path:r.path,exists:r.exists})),hasOverrides:i.hasOverrides,overrideKeys:i.overrideKeys};return{content:[{type:"text",text:JSON.stringify(n,null,2)}],structuredContent:n}},$=async()=>{let e=await P(),o=Oe.env.EDITOR||Oe.env.VISUAL||"vi",t=await Y(e);t.createdConfig&&c.info(Q(t)),c.info(`Opening ${u(e.userProject)} in ${o}`),await ko({stdio:"inherit"})`${o} ${e.userProject}`,B();let i={path:e.userProject,editor:o};return{content:[{type:"text",text:JSON.stringify(i,null,2)}],structuredContent:i}};import p from"node:fs";import v from"node:path";import w from"node:process";var So="autoload-warn-misconfig.flag",Co="autoload-warn-fail.flag",M="autoload-fail.flag",Ro=3e4,Ve=async(e=!0)=>{let o;try{o=await z()}catch{return null}let t=o.envAutoLoad;return t?o.environments.includes(t.config)?{trigger:t.trigger,config:t.config,project:o.envManagement.config.name}:(e&&Ge(`infra-kit: envAutoLoad.config "${t.config}" is not one of environments [${o.environments.join(", ")}] \u2014 env auto-load disabled.`,So),null):null},Ue=e=>{let{trigger:o,expectedTrigger:t,targetConfig:i,targetProject:a,env:n,force:r}=e;return o!==t||!n.session||n.cleared||n.currentConfig&&!n.autoLoadedMarker||!r&&n.autoLoadedMarker&&n.currentConfig===i&&n.currentProject===a?"skip":"load"},k=async({expectedTrigger:e,projectDir:o,force:t})=>{let i=e==="cli-invocation";try{let a=await Ve(i);if(!a||Ue({trigger:a.trigger,expectedTrigger:e,targetConfig:a.config,targetProject:a.project,env:xo(),force:t})==="skip"||Fe()||Lo())return null;let r=Eo(),d=await fe({config:a.config,autoLoaded:!0,projectDir:o,beforeWrite:()=>!Fe()&&!Ao(r)});return d?(Po(),d.filePath):null}catch(a){let n=a.message;return bo(),i?Ge(`infra-kit: env auto-load failed \u2014 ${n} (will retry later)`,Co):c.debug(`env auto-load skipped: ${n}`),null}},xo=()=>({session:w.env[ie],cleared:w.env[ce],currentConfig:w.env[ae],currentProject:w.env[se],autoLoadedMarker:w.env[T]}),Eo=()=>{try{return p.statSync(v.join(g(),R)).mtimeMs}catch{return null}},Ao=e=>{try{let o=v.join(g(),R);if(!p.existsSync(o))return!1;let t=p.statSync(o).mtimeMs;return e!==null&&t<=e?!1:new RegExp(`^unset ${T}$`,"m").test(p.readFileSync(o,"utf-8"))}catch{return!1}},Fe=()=>{try{let e=g(),o=v.join(e,ne);if(!p.existsSync(o))return!1;let t=v.join(e,R);return p.existsSync(t)?p.statSync(o).mtimeMs>=p.statSync(t).mtimeMs:!0}catch{return!1}},Lo=()=>{try{let e=v.join(g(),M);return p.existsSync(e)?Date.now()-p.statSync(e).mtimeMs<Ro:!1}catch{return!1}},bo=()=>{try{let e=g();p.mkdirSync(e,{recursive:!0,mode:448}),p.writeFileSync(v.join(e,M),"",{mode:384})}catch{}},Po=()=>{try{p.rmSync(v.join(g(),M),{force:!0})}catch{}},Ge=(e,o)=>{try{let t=g(),i=v.join(t,o);if(p.existsSync(i))return;p.mkdirSync(t,{recursive:!0,mode:448}),p.writeFileSync(i,"",{mode:384})}catch{}c.warn(e)};var O=async({projectDir:e}={})=>{await k({expectedTrigger:"shell-startup",projectDir:e,force:!0})};import{spawn as Do}from"node:child_process";import A from"node:process";import{fileURLToPath as Io}from"node:url";var To=["SIGINT","SIGTERM"],We=()=>Io(new URL("./mcp.js",import.meta.url)),F=(e={})=>{let o=e.spawn??Do,t=e.exit??(r=>A.exit(r)),i=e.env??A.env,a=e.onError??(r=>c.error(r)),n=o(A.execPath,[We()],{stdio:"inherit",env:E(i)});n.on("error",r=>{a(`failed to launch the MCP server: ${r.message}`),t(1)}),To.forEach(r=>{A.on(r,()=>{n.kill(r)})}),n.on("exit",(r,d)=>{t(d?1:r??1)})};import{spawnSync as jo}from"node:child_process";import{realpathSync as No}from"node:fs";import V from"node:process";import{fileURLToPath as _o}from"node:url";var $o=()=>No(_o(import.meta.url)),Mo=(e,o,t,i)=>e.error?(t(`${o} not found on PATH: ${e.error.message}`),i(1)):e.signal?(t(`update terminated by signal ${e.signal}`),i(1)):i(e.status??1),U=({dryRun:e},o={})=>{let t=o.spawnSync??jo,i=o.print??(b=>c.info(b)),a=o.exit??(b=>V.exit(b)),n=o.env??V.env,r=o.selfRealPath??$o(),d=o.lazyNpmRoot??$e,{manager:m,updateCommand:f,canSelfSpawn:h}=_e({selfRealPath:r,env:n,realpath:Me,lazyNpmRoot:d}),C=f.join(" ");if(e){i(`Detected install manager: ${m}`),i(`Would run: ${C}`);return}if(!h){i(`Detected install manager: ${m}`),i(`Run this yourself: ${C}`),i(m==="homebrew"?"Not run for you: Homebrew manages this install; running a package manager would create a split-brain install.":"Not run for you: the install location is unrecognized, so the command above is a guess \u2014 a guessed global install is worse than a printed one.");return}let wo=t(f[0],f.slice(1),{stdio:"inherit",shell:V.platform==="win32",env:E(n)});Mo(wo,m,i,a)};import G from"node:fs/promises";import W from"node:path";import Ke from"node:process";import{pathToFileURL as Oo}from"node:url";var Je="~/projects",K=async(e={})=>{if(e.init){await Vo(e.cwd);return}await Fo()},Fo=async()=>{let e=D(),o=await y(e);if(c.info(`Factory config: ${u(e)} ${o?"[\u2713]":"[ ]"}`),!o){c.info("\nNot found \u2014 run `infra-kit vendor-config --init` to scaffold it."),Ke.exitCode=1;return}let{workspaceDir:t,targets:i}=await oe(),a=ee(t),n=await y(a);c.info(`workspaceDir: ${t} (resolved: ${a}) ${n?"[\u2713 exists]":"[ ] not found"}`),c.info("Targets:");let r=n;for(let d of i){let m=W.join(a,d),f=await y(m);f||(r=!1);let h=f?"[\u2713]":"[ ]",C=f?"":" (not found \u2014 clone or remove)";c.info(` ${h} ${d} ${u(m)}${C}`)}r||(Ke.exitCode=1)},Vo=async e=>{let o=D();if(await y(o)){c.info(`Factory config already exists at ${u(o)} \u2014 leaving it untouched.`);return}let t=e??await H(),i=await Uo(t);await G.mkdir(W.dirname(o),{recursive:!0}),await G.writeFile(o,Go(i),"utf-8"),c.info(`\u2713 Created ${u(o)}`),i.length>0&&c.info(` Seeded ${i.length} target(s) from the source ${j}.`),c.info(` Edit \`workspaceDir\` (placeholder: ${Je}) to point at where your repos live.`),i.length===0&&c.info(" Add at least one repo name to `targets` before running vendor sync/manifest/diff.")},Uo=async e=>{try{let o=W.join(e,j),t=await G.stat(o),n=(await import(`${Oo(o).href}?mtime=${Number(t.mtimeMs)}`)).default,r=typeof n=="function"?await n():n;if(r&&typeof r=="object"&&"targets"in r){let d=r.targets;if(Array.isArray(d)&&d.every(m=>typeof m=="string"))return d}}catch{}return[]},Go=e=>`${JSON.stringify({workspaceDir:Je,targets:e},null,2)}
|
|
4
|
+
`;var qe=(e,o=!0)=>({line:e,reproducible:o});import L from"node:fs";import Wo from"node:os";import Ko from"node:path";import Ye from"node:process";var He="INFRA_KIT_SESSION_REPORT",J=null,ze=!1,Be=[],mr=(e=Ye.env)=>{ze||(J=e[He]??null,ze=!0,delete e[He])};var Qe=(e,o)=>{if(!J)return;let t=e.summary??(Be.length>0?[...Be]:void 0),i={...e,...t?{summary:t}:{}},a=o?.write??((n,r)=>{L.writeFileSync(n,r)});try{a(J,JSON.stringify(i))}catch{}},Xe=0,pr=e=>{let o=e?.tmpdir?.()??Wo.tmpdir(),t=e?.pid??Ye.pid;return Xe+=1,Ko.join(o,`infra-kit-session-${t}-${Xe}.json`)},lr=(e,o)=>{if(!(o?.exists??(r=>L.existsSync(r)))(e))return null;let i=o?.read??(r=>L.readFileSync(r,"utf-8")),a=o?.unlink??(r=>L.unlinkSync(r)),n;try{n=i(e)}catch{return null}finally{try{a(e)}catch{}}try{return JSON.parse(n)}catch{return null}};var qo=(e,o)=>[...o,e],q=e=>typeof e=="string"?e.split(",").filter(Boolean):void 0,Ze=(e,o)=>{if(!(typeof e>"u")){if(e===!0)return"workspace";if(e===!1)return"none";if(typeof e=="string"&&N.includes(e))return e;throw new Error(`Invalid ${o} value "${String(e)}". Expected one of: ${N.join(", ")}.`)}},Ho={value:!1},l=(e,o)=>e.hook("preAction",()=>{Ho.value||c.warn(`"${e.name()}" is a deprecated alias; use "${o}" instead.`)}),eo=e=>e.description("Merge dev branch into every release branch").option("-a, --all","Select all active release branches").option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await ye({all:o.all,confirmedCommand:o.yes}))}),oo=e=>e.description("List all release branches").action(async()=>{s(await Se())}),to=e=>e.description("Create one or more release branches (each entry can mix regular/hotfix and its own description)").option("-r, --release <spec>",'Release spec "<version|next|name>[:type[:description]]" (repeatable). The token is a semver ("1.2.5"), the literal "next", or a kebab-case name ("checkout-redesign"). Type is regular|hotfix (default regular). Examples: "1.2.5", "1.2.5:hotfix", "next:regular:Holiday backend", "checkout-redesign:regular:Q3 redesign".',qo,[]).option("-y, --yes","Skip confirmation prompt").action(async o=>{let i=o.release.map(Ce),a=i.length>0?i:void 0;s(await Re({releases:a,confirmedCommand:o.yes}))}),ro=e=>e.description("Edit a release's description in Jira and in the matching GitHub PR body").option("-v, --version <version>","Release version (e.g. 1.2.5) or release name (e.g. checkout-redesign)").option("-d, --description <description>",'New description (use "" to clear)').option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await xe({version:o.version,description:o.description,confirmedCommand:o.yes}))}),no=e=>e.description("Deploy any release branch to any environment").option("-v, --version <version>",'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; "dev" deploys from the dev branch').option("-e, --env <env>","Specify the environment to deploy to, e.g. dev").option("--skip-terraform","Skip terraform deployment step").option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await we({version:o.version,env:o.env,skipTerraform:o.skipTerraform,confirmedCommand:o.yes}))}),io=e=>e.description("Deploy selected services from release branch to any environment").option("-v, --version <version>",'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; "dev" deploys from the dev branch').option("-e, --env <env>","Specify the environment to deploy to, e.g. dev").option("-s, --services <services...>","Specify services to deploy, e.g. client-be client-fe").option("--skip-terraform","Skip terraform deployment step").option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await ke({version:o.version,env:o.env,services:o.services,skipTerraform:o.skipTerraform,confirmedCommand:o.yes}))}),ao=e=>e.description("Release a new version to production").option("-v, --version <version>","Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deliver").option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await he({version:o.version,confirmedCommand:o.yes}))}),so=e=>e.description("Remove release worktrees whose PRs are no longer open").option("-y, --yes","Skip confirmation prompt").action(async o=>{s(await Ne({confirmedCommand:o.yes}))}),co=e=>e.description("Add git worktrees for release branches").option("-y, --yes","Skip confirmation prompt").option("-a, --all","Select all active release branches").option("-v, --versions <versions>","Specify versions by comma, e.g. 1.2.5, 1.2.6").option("-i, --ide [mode]","Editor mode for created worktrees: workspace (default) | none").option("--no-ide","Skip the editor (alias for --ide none)").option("-c, --cursor [mode]","Deprecated alias for --ide").option("--no-cursor","Deprecated alias for --no-ide").option("-g, --github-desktop","Open created worktrees in GitHub Desktop").option("--no-github-desktop","Skip GitHub Desktop prompt").option("-m, --cmux","Open created worktrees in cmux (3-pane layout)").option("--no-cmux","Skip cmux prompt").action(async o=>{let t=Ze(o.ide,"--ide")??Ze(o.cursor,"--cursor");s(await De({confirmedCommand:o.yes,all:o.all,versions:o.versions,ide:t,githubDesktop:o.githubDesktop,cmux:o.cmux}))}),mo=e=>e.description("List all git worktrees with detailed information").action(async()=>{s(await Ie())}),po=e=>e.description("Remove git worktrees for release branches").option("-y, --yes","Skip confirmation prompt").option("-a, --all","Select all active release branches").option("-v, --versions <versions>","Specify versions by comma, e.g. 1.2.5, 1.2.6").action(async o=>{s(await je({confirmedCommand:o.yes,all:o.all,versions:o.versions}))}),lo=e=>e.description("Close all cmux/editor worktree windows, then reopen the current release worktrees (also cold-start restore)").action(async()=>{s(await Te())}),fo=e=>e.description("Show the machine-local factory config (~/.infra-kit/vendor.json) or scaffold it with --init").option("--init","Scaffold ~/.infra-kit/vendor.json (skips if it already exists)").action(async o=>{s(await K({init:o.init}))}),uo=e=>e.description("Verify vendor/ matches vendor/.sync-manifest.json (self-contained; for any consumer repo)").action(async()=>{let o=await Ee();s(o),o.structuredContent.ok||(S.exitCode=1)}),go=e=>e.description("Source-aware drift check (rsync dry-run) of each target vendored subtree vs the source").option("-r, --repos <repos>","Restrict to comma-separated target repo names").action(async o=>{let t=await Ae({repos:q(o.repos)});s(t),t.structuredContent.ok||(S.exitCode=1)}),vo=e=>e.description("Show the resolved config merge chain and file paths").action(async()=>{s(await _())}),yo=e=>e.description("Open the user-scope per-project override file in $EDITOR").action(async()=>{s(await $())}),zo=new Set(["init","doctor","version","dev","self-update","mcp"]),Bo=e=>e.startsWith("env-")||zo.has(e),Xo=new Set(["env-autoload","mcp","version","self-update"]),ho=e=>{let o=[];for(let t=e;t&&t.parent;t=t.parent)o.unshift(t.name());return o.join(" ")},en=()=>{let e=new Jo,o=e.command("release").description("Release management commands");eo(o.command("merge-dev")),oo(o.command("list")),to(o.command("create")),ro(o.command("desc-edit")),no(o.command("deploy-all")),io(o.command("deploy-selected")),ao(o.command("deliver"));let t=e.command("worktrees").description("Git worktree management commands");co(t.command("add")),mo(t.command("list")),po(t.command("remove")),so(t.command("sync")),lo(t.command("reload")),l(eo(e.command("merge-dev")),"release merge-dev"),l(oo(e.command("release-list")),"release list"),l(to(e.command("release-create")),"release create"),l(ro(e.command("release-desc-edit")),"release desc-edit"),l(no(e.command("release-deploy-all")),"release deploy-all"),l(io(e.command("release-deploy-selected")),"release deploy-selected"),l(ao(e.command("release-deliver")),"release deliver"),l(co(e.command("worktrees-add")),"worktrees add"),l(mo(e.command("worktrees-list")),"worktrees list"),l(po(e.command("worktrees-remove")),"worktrees remove"),l(so(e.command("worktrees-sync")),"worktrees sync"),l(lo(e.command("worktrees-reload")),"worktrees reload");let i=e.command("config").description("Manage infra-kit configuration files");vo(i.command("path")),yo(i.command("edit")),vo(e.command("config-path",{hidden:!0})),yo(e.command("config-edit",{hidden:!0})),e.command("audit").description("Audit against infra-kit.config.ts rules (--all for every package, --root for the monorepo root)").option("-a, --all","Audit every non-vendor workspace package").option("-r, --root","Audit the monorepo root (turbo pipeline + root commands)").action(async n=>{let r=await X({all:n.all,root:n.root});s(r),r.structuredContent.allPassed||(S.exitCode=1)});let a=e.command("vendor").description("Verify and sync the mirrored vendor/ tree");return uo(a.command("check")),a.command("sync").description("Copy vendored files from the source repo into each target and regenerate manifests").option("-y, --yes","Skip confirmation prompt").option("-r, --repos <repos>","Restrict to comma-separated target repo names").action(async n=>{s(await be({confirmedCommand:n.yes,repos:q(n.repos)}))}),a.command("manifest").description("Regenerate each target vendor/.sync-manifest.json + README from current content (no copy)").option("-r, --repos <repos>","Restrict to comma-separated target repo names").action(async n=>{s(await Le({confirmedCommand:!0,repos:q(n.repos)}))}),go(a.command("diff")),fo(a.command("config")),l(fo(e.command("vendor-config")),"vendor config"),uo(e.command("vendor-check",{hidden:!0})),go(e.command("vendor-diff",{hidden:!0})),e.command("doctor").description("Check installation and authentication status of gh and doppler CLIs").action(async()=>{s(await de())}),e.command("self-update").description("Update this CLI using the package manager that installed it").option("--dry-run","Print the detected manager and the command that would run; install nothing").action(n=>{U({dryRun:!!n.dryRun})}),e.command("mcp").description("Run the infra-kit MCP server (stdio transport)").action(()=>{F()}),e.command("dev").description("Run local dev servers for a named devServersPresets preset (or all apps); api + ui").argument("[preset]","Named preset from devServersPresets (omit to run every app)").option("-w, --watch","Rebuild and restart on file save").option("--app <names>","Further narrow to these app folder names (comma-separated)").option("--target <keys>","Run exactly these <app>/api|<app>/ui packages (comma-separated); part-level, unlike --app").option("--cmux","Run each app in its own cmux pane (one workspace, N panes; falls back to single terminal if cmux is unavailable)").option("--self","Run only the app of the current directory (infer from cwd; use inside apps/<app>/\u2026)").option("-V, --verbose","Print full boot narration (default: quiet; full detail always in the session log)").option("--routes","Print each app\u2019s registered METHOD /path routes at startup (default: off)").option("--proxy-port <port>","Portless proxy listen port for <release>.<package>.localhost URLs (default: 80)").action(async(n,r)=>{let{runDevServerCli:d}=await import("./dev-server.js"),m=!!(S.stdout.isTTY&&S.stdin.isTTY);await d({...r,preset:n},m,x.enabled)}),e.command("version").description("Print the installed infra-kit CLI version").action(async()=>{s(await Pe())}),e.command("env-status").description("Show which env is loaded in this session (local introspection; no Doppler call)").action(async()=>{s(await ge())}),e.command("env-list").description("List available Doppler configs for the detected project").action(async()=>{s(await pe())}),e.command("init").description("Inject shell integration into .zshrc and sync repo agent-instruction files").action(async()=>{s(await I())}),e.command("env-load").description("Load Doppler env vars for a config. Source the returned file path to apply.").option("-c, --config <config>","Environment config name to load (e.g. dev, arthur)").action(async n=>{s(await ue({config:n.config}))}),e.command("env-clear").description("Clear loaded env vars. Source the returned file path to apply.").option("--purge","Also delete this project's warm cache outright (durable disable)").action(async n=>{s(await me({purge:!!n.purge}))}),e.command("env-autoload",{hidden:!0}).description("Internal: prime env for the shell-startup auto-load trigger").option("--project-dir <dir>","Canonical project dir for the warm-cache key (shell-startup only)").action(async n=>{await O({projectDir:n.projectDir})}),e.commands.forEach(ve),e.hook("preAction",async(n,r)=>{x.enabled=!!r.optsWithGlobals().json,x.enabled&&(c.level="warn"),Xo.has(ho(r))||await Z(),Bo(r.name())||await k({expectedTrigger:"cli-invocation"})}),e.hook("postAction",(n,r)=>{let m=le.snapshot()?.formattedOptions??"",f=m?` ${m}`:"",h=`infra-kit ${ho(r)}${f}`;Qe({equivalent:qe(h,!0)})}),e};export{He as a,mr as b,pr as c,lr as d,qe as e,Ho as f,en as g};
|
|
5
|
+
//# sourceMappingURL=chunk-VJPLVBRA.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/entry/program.ts", "../src/commands/config/config.ts", "../src/lib/env-autoload/env-autoload.ts", "../src/commands/env-autoload/env-autoload.ts", "../src/commands/mcp/mcp.ts", "../src/commands/self-update/self-update.ts", "../src/commands/vendor-config/vendor-config.ts", "../src/lib/session/equivalent.ts", "../src/lib/session/report.ts"],
|
|
4
|
+
"sourcesContent": ["import { Command } from 'commander'\nimport process from 'node:process'\n\nimport { audit } from 'src/commands/audit'\nimport { configEdit, configPath } from 'src/commands/config'\nimport { doctor } from 'src/commands/doctor'\nimport { envAutoload } from 'src/commands/env-autoload'\nimport { envClear } from 'src/commands/env-clear'\nimport { envList } from 'src/commands/env-list'\nimport { envLoad } from 'src/commands/env-load'\nimport { envStatus } from 'src/commands/env-status'\nimport { ghMergeDev } from 'src/commands/gh-merge-dev'\nimport { ghReleaseDeliver } from 'src/commands/gh-release-deliver'\nimport { ghReleaseDeployAll } from 'src/commands/gh-release-deploy-all'\nimport { ghReleaseDeploySelected } from 'src/commands/gh-release-deploy-selected'\nimport { ghReleaseList } from 'src/commands/gh-release-list'\nimport { init } from 'src/commands/init'\nimport { runMcp } from 'src/commands/mcp'\nimport { releaseCreate } from 'src/commands/release-create'\nimport { releaseDescEdit } from 'src/commands/release-desc-edit'\nimport { runSelfUpdate } from 'src/commands/self-update'\nimport { vendorCheck } from 'src/commands/vendor-check'\nimport { vendorConfig } from 'src/commands/vendor-config'\nimport { vendorDiff } from 'src/commands/vendor-diff'\nimport { vendorManifest } from 'src/commands/vendor-manifest'\nimport { vendorSync } from 'src/commands/vendor-sync'\nimport { version } from 'src/commands/version'\nimport { worktreesAdd } from 'src/commands/worktrees-add'\nimport { worktreesList } from 'src/commands/worktrees-list'\nimport { worktreesReload } from 'src/commands/worktrees-reload'\nimport { worktreesRemove } from 'src/commands/worktrees-remove'\nimport { worktreesSync } from 'src/commands/worktrees-sync'\nimport { IDE_MODES } from 'src/integrations/ide'\nimport type { IdeMode } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { ensureUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { runEnvAutoLoad } from 'src/lib/env-autoload'\nimport { addJsonOption, emit, jsonOutput } from 'src/lib/json-output'\nimport { logger } from 'src/lib/logger'\nimport { equivalentLine } from 'src/lib/session/equivalent'\nimport { writeSessionReport } from 'src/lib/session/report'\nimport { parseReleaseSpec } from 'src/lib/version-utils'\nimport type { ReleaseInput } from 'src/lib/version-utils'\n\n/**\n * Side-effect-free construction of the Commander program. It is deliberately isolated from\n * `src/entry/cli.ts` (which runs `warnIfLocalInstall()`, `maybeAutoUpdate()`, and a top-level `await`\n * at module load) so a test \u2014 or the session shell \u2014 can import and walk the command tree WITHOUT\n * triggering those boot side effects. `cli.ts` calls `buildProgram()` once and owns everything else.\n */\n\nconst collectReleaseSpec = (value: string, prev: string[]): string[] => {\n return [...prev, value]\n}\n\n/** Parse a `--repos a,b,c` option into a target-name list (undefined = all). */\nconst parseRepos = (value: unknown): string[] | undefined => {\n return typeof value === 'string' ? value.split(',').filter(Boolean) : undefined\n}\n\nconst normalizeIdeMode = (value: unknown, flagName: '--ide' | '--cursor'): IdeMode | undefined => {\n if (typeof value === 'undefined') {\n return undefined\n }\n\n if (value === true) {\n return 'workspace'\n }\n\n if (value === false) {\n return 'none'\n }\n\n if (typeof value === 'string' && (IDE_MODES as readonly string[]).includes(value)) {\n return value as IdeMode\n }\n\n throw new Error(`Invalid ${flagName} value \"${String(value)}\". Expected one of: ${IDE_MODES.join(', ')}.`)\n}\n\n// --- Deprecation support for flat command aliases (Phase 3 grouping) ---\n// Flat names (`release-create`, `worktrees-add`, `vendor-config`, ...) are kept\n// as working aliases of the grouped forms (`release create`, ...) for one\n// release cycle. They warn once when invoked directly, but stay silent when the\n// interactive no-arg menu drives them (the menu is a guided surface). The flag is\n// a shared singleton so `cli.ts`'s menu path can silence the warning.\nexport const invokedViaMenu = { value: false }\n\nconst deprecatedAlias = (cmd: Command, preferred: string): Command => {\n return cmd.hook('preAction', () => {\n if (!invokedViaMenu.value) {\n logger.warn(`\"${cmd.name()}\" is a deprecated alias; use \"${preferred}\" instead.`)\n }\n })\n}\n\n// --- Command configurators (one source of options + action, shared by the\n// grouped form and its flat alias so the two can never diverge) ---\nconst configureMergeDev = (cmd: Command): Command => {\n return cmd\n .description('Merge dev branch into every release branch')\n .option('-a, --all', 'Select all active release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await ghMergeDev({ all: options.all, confirmedCommand: options.yes }))\n })\n}\n\nconst configureReleaseList = (cmd: Command): Command => {\n return cmd.description('List all release branches').action(async () => {\n emit(await ghReleaseList())\n })\n}\n\nconst configureReleaseCreate = (cmd: Command): Command => {\n return cmd\n .description('Create one or more release branches (each entry can mix regular/hotfix and its own description)')\n .option(\n '-r, --release <spec>',\n 'Release spec \"<version|next|name>[:type[:description]]\" (repeatable). The token is a semver (\"1.2.5\"), the literal \"next\", or a kebab-case name (\"checkout-redesign\"). Type is regular|hotfix (default regular). Examples: \"1.2.5\", \"1.2.5:hotfix\", \"next:regular:Holiday backend\", \"checkout-redesign:regular:Q3 redesign\".',\n collectReleaseSpec,\n [],\n )\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n const specs = options.release as string[]\n const inputs: ReleaseInput[] = specs.map(parseReleaseSpec)\n const releases = inputs.length > 0 ? inputs : undefined\n\n emit(\n await releaseCreate({\n releases,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDescEdit = (cmd: Command): Command => {\n return cmd\n .description(\"Edit a release's description in Jira and in the matching GitHub PR body\")\n .option('-v, --version <version>', 'Release version (e.g. 1.2.5) or release name (e.g. checkout-redesign)')\n .option('-d, --description <description>', 'New description (use \"\" to clear)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await releaseDescEdit({\n version: options.version,\n description: options.description,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeployAll = (cmd: Command): Command => {\n return cmd\n .description('Deploy any release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await ghReleaseDeployAll({\n version: options.version,\n env: options.env,\n skipTerraform: options.skipTerraform,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeploySelected = (cmd: Command): Command => {\n return cmd\n .description('Deploy selected services from release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('-s, --services <services...>', 'Specify services to deploy, e.g. client-be client-fe')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await ghReleaseDeploySelected({\n version: options.version,\n env: options.env,\n services: options.services,\n skipTerraform: options.skipTerraform,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeliver = (cmd: Command): Command => {\n return cmd\n .description('Release a new version to production')\n .option('-v, --version <version>', 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deliver')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await ghReleaseDeliver({ version: options.version, confirmedCommand: options.yes }))\n })\n}\n\nconst configureWorktreesSync = (cmd: Command): Command => {\n return cmd\n .description('Remove release worktrees whose PRs are no longer open')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await worktreesSync({ confirmedCommand: options.yes }))\n })\n}\n\nconst configureWorktreesAdd = (cmd: Command): Command => {\n return cmd\n .description('Add git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .option('-i, --ide [mode]', 'Editor mode for created worktrees: workspace (default) | none')\n .option('--no-ide', 'Skip the editor (alias for --ide none)')\n .option('-c, --cursor [mode]', 'Deprecated alias for --ide')\n .option('--no-cursor', 'Deprecated alias for --no-ide')\n .option('-g, --github-desktop', 'Open created worktrees in GitHub Desktop')\n .option('--no-github-desktop', 'Skip GitHub Desktop prompt')\n .option('-m, --cmux', 'Open created worktrees in cmux (3-pane layout)')\n .option('--no-cmux', 'Skip cmux prompt')\n .action(async (options) => {\n // `--ide` wins over the deprecated `--cursor` alias when both are provided.\n const ide = normalizeIdeMode(options.ide, '--ide') ?? normalizeIdeMode(options.cursor, '--cursor')\n\n emit(\n await worktreesAdd({\n confirmedCommand: options.yes,\n all: options.all,\n versions: options.versions,\n ide,\n githubDesktop: options.githubDesktop,\n cmux: options.cmux,\n }),\n )\n })\n}\n\nconst configureWorktreesList = (cmd: Command): Command => {\n return cmd.description('List all git worktrees with detailed information').action(async () => {\n emit(await worktreesList())\n })\n}\n\nconst configureWorktreesRemove = (cmd: Command): Command => {\n return cmd\n .description('Remove git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .action(async (options) => {\n emit(await worktreesRemove({ confirmedCommand: options.yes, all: options.all, versions: options.versions }))\n })\n}\n\nconst configureWorktreesReload = (cmd: Command): Command => {\n return cmd\n .description(\n 'Close all cmux/editor worktree windows, then reopen the current release worktrees (also cold-start restore)',\n )\n .action(async () => {\n emit(await worktreesReload())\n })\n}\n\nconst configureVendorConfig = (cmd: Command): Command => {\n return cmd\n .description('Show the machine-local factory config (~/.infra-kit/vendor.json) or scaffold it with --init')\n .option('--init', 'Scaffold ~/.infra-kit/vendor.json (skips if it already exists)')\n .action(async (options) => {\n emit(await vendorConfig({ init: options.init }))\n })\n}\n\nconst configureVendorCheck = (cmd: Command): Command => {\n return cmd\n .description('Verify vendor/ matches vendor/.sync-manifest.json (self-contained; for any consumer repo)')\n .action(async () => {\n const result = await vendorCheck()\n\n emit(result)\n\n if (!result.structuredContent.ok) {\n process.exitCode = 1\n }\n })\n}\n\nconst configureVendorDiff = (cmd: Command): Command => {\n return cmd\n .description('Source-aware drift check (rsync dry-run) of each target vendored subtree vs the source')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n const result = await vendorDiff({ repos: parseRepos(options.repos) })\n\n emit(result)\n\n if (!result.structuredContent.ok) {\n process.exitCode = 1\n }\n })\n}\n\nconst configureConfigPath = (cmd: Command): Command => {\n return cmd.description('Show the resolved config merge chain and file paths').action(async () => {\n emit(await configPath())\n })\n}\n\nconst configureConfigEdit = (cmd: Command): Command => {\n return cmd.description('Open the user-scope per-project override file in $EDITOR').action(async () => {\n emit(await configEdit())\n })\n}\n\n// Commands excluded from the cli-invocation auto-load trigger: the env-* family\n// (avoids recursion \u2014 `env-autoload`/`env-load` would re-enter), plus the\n// host-inspecting / meta commands where priming Doppler env would be surprising\n// (`init` bootstraps the shell block, `doctor` inspects auth, `version` prints a\n// string, `dev` is a long-running server that manages its own env,\n// `self-update` replaces this binary, and `mcp` hands its stdio to a child).\n// `--help`/`--version`/the bare-arg menu don't fire preAction at all.\nconst AUTO_LOAD_EXCLUDED = new Set(['init', 'doctor', 'version', 'dev', 'self-update', 'mcp'])\n\nconst isAutoLoadExcludedCommand = (name: string): boolean => {\n return name.startsWith('env-') || AUTO_LOAD_EXCLUDED.has(name)\n}\n\n// Commands excluded from the layer-3 config auto-seed. A SEPARATE, much SMALLER set than\n// AUTO_LOAD_EXCLUDED above \u2014 the asymmetry is intentional, not an oversight:\n// - `env-autoload` is the hidden command the zsh precmd hook fires BACKGROUNDED on every prompt\n// (see the shell body in init.ts). It runs constantly; the seed has no business on that path.\n// - `mcp` is excluded for LAZINESS, not cwd: the MCP server seeds at its first TOOL INVOCATION\n// (lib/tool-handler), so a server that never receives a tool call never writes to $HOME.\n// - `version` / `self-update` touch config ZERO times today, so seeding is pure new cost on the two\n// fastest paths; `self-update` also re-execs the binary.\n// Everything else DOES seed \u2014 `doctor`, `config path`, `dev` and `init` included (they are all in\n// AUTO_LOAD_EXCLUDED, but that set answers a different question), as does the whole `env-*` family\n// apart from `env-autoload`.\nconst SEED_EXCLUDED = new Set(['env-autoload', 'mcp', 'version', 'self-update'])\n\n/**\n * Canonical space-joined command path for a leaf (e.g. the `check` leaf of `vendor` \u2192 \"vendor check\").\n * Stops at the root program (a node with no parent) so its name \u2014 the bin basename like \"cli\" \u2014 never\n * leaks into the equivalent line.\n */\nconst commandPath = (leaf: Command): string => {\n const parts: string[] = []\n\n for (let node: Command | null = leaf; node && node.parent; node = node.parent) {\n parts.unshift(node.name())\n }\n\n return parts.join(' ')\n}\n\n/**\n * Build the full Commander program (grouped surface, deprecated flat aliases, hidden menu-leaf\n * aliases, `--json` on every command, and the pre-action auto-load hook). Pure: no I/O, no top-level\n * await, no process mutation \u2014 safe to import from a test to introspect the command tree.\n *\n * @example\n * const program = buildProgram()\n * program.commands.some((c) => c.name() === 'audit') // => true\n */\nexport const buildProgram = (): Command => {\n const program = new Command()\n\n // --- Grouped command surface (preferred form) ---\n const releaseGroup = program.command('release').description('Release management commands')\n\n configureMergeDev(releaseGroup.command('merge-dev'))\n configureReleaseList(releaseGroup.command('list'))\n configureReleaseCreate(releaseGroup.command('create'))\n configureReleaseDescEdit(releaseGroup.command('desc-edit'))\n configureReleaseDeployAll(releaseGroup.command('deploy-all'))\n configureReleaseDeploySelected(releaseGroup.command('deploy-selected'))\n configureReleaseDeliver(releaseGroup.command('deliver'))\n\n const worktreesGroup = program.command('worktrees').description('Git worktree management commands')\n\n configureWorktreesAdd(worktreesGroup.command('add'))\n configureWorktreesList(worktreesGroup.command('list'))\n configureWorktreesRemove(worktreesGroup.command('remove'))\n configureWorktreesSync(worktreesGroup.command('sync'))\n configureWorktreesReload(worktreesGroup.command('reload'))\n\n // --- Deprecated flat aliases (kept one release cycle; warn when used directly) ---\n deprecatedAlias(configureMergeDev(program.command('merge-dev')), 'release merge-dev')\n deprecatedAlias(configureReleaseList(program.command('release-list')), 'release list')\n deprecatedAlias(configureReleaseCreate(program.command('release-create')), 'release create')\n deprecatedAlias(configureReleaseDescEdit(program.command('release-desc-edit')), 'release desc-edit')\n deprecatedAlias(configureReleaseDeployAll(program.command('release-deploy-all')), 'release deploy-all')\n deprecatedAlias(configureReleaseDeploySelected(program.command('release-deploy-selected')), 'release deploy-selected')\n deprecatedAlias(configureReleaseDeliver(program.command('release-deliver')), 'release deliver')\n deprecatedAlias(configureWorktreesAdd(program.command('worktrees-add')), 'worktrees add')\n deprecatedAlias(configureWorktreesList(program.command('worktrees-list')), 'worktrees list')\n deprecatedAlias(configureWorktreesRemove(program.command('worktrees-remove')), 'worktrees remove')\n deprecatedAlias(configureWorktreesSync(program.command('worktrees-sync')), 'worktrees sync')\n deprecatedAlias(configureWorktreesReload(program.command('worktrees-reload')), 'worktrees reload')\n\n const configCmd = program.command('config').description('Manage infra-kit configuration files')\n\n configureConfigPath(configCmd.command('path'))\n configureConfigEdit(configCmd.command('edit'))\n\n // Hidden flat menu-leaf aliases: the no-arg palette invokes leaves by a single top-level token, so\n // the group subcommands (`config path`, `vendor check`) get a flat sibling the menu can dispatch and\n // introspect for its description. Hidden keeps them out of `--help`; they are NOT deprecated aliases,\n // so they do not warn.\n configureConfigPath(program.command('config-path', { hidden: true }))\n configureConfigEdit(program.command('config-edit', { hidden: true }))\n\n program\n .command('audit')\n .description('Audit against infra-kit.config.ts rules (--all for every package, --root for the monorepo root)')\n .option('-a, --all', 'Audit every non-vendor workspace package')\n .option('-r, --root', 'Audit the monorepo root (turbo pipeline + root commands)')\n .action(async (options) => {\n const result = await audit({ all: options.all, root: options.root })\n\n emit(result)\n\n if (!result.structuredContent.allPassed) {\n process.exitCode = 1\n }\n })\n\n const vendorCmd = program.command('vendor').description('Verify and sync the mirrored vendor/ tree')\n\n configureVendorCheck(vendorCmd.command('check'))\n\n vendorCmd\n .command('sync')\n .description('Copy vendored files from the source repo into each target and regenerate manifests')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n emit(await vendorSync({ confirmedCommand: options.yes, repos: parseRepos(options.repos) }))\n })\n\n vendorCmd\n .command('manifest')\n .description('Regenerate each target vendor/.sync-manifest.json + README from current content (no copy)')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n emit(await vendorManifest({ confirmedCommand: true, repos: parseRepos(options.repos) }))\n })\n\n configureVendorDiff(vendorCmd.command('diff'))\n\n // Grouped form (preferred); the flat `vendor-config` below is a deprecated alias.\n configureVendorConfig(vendorCmd.command('config'))\n\n deprecatedAlias(configureVendorConfig(program.command('vendor-config')), 'vendor config')\n\n // Hidden flat menu-leaf aliases for the vendor subcommands the palette offers.\n configureVendorCheck(program.command('vendor-check', { hidden: true }))\n configureVendorDiff(program.command('vendor-diff', { hidden: true }))\n\n program\n .command('doctor')\n .description('Check installation and authentication status of gh and doppler CLIs')\n .action(async () => {\n emit(await doctor())\n })\n\n // No `update` alias: the `update` verb is reserved.\n program\n .command('self-update')\n .description('Update this CLI using the package manager that installed it')\n .option('--dry-run', 'Print the detected manager and the command that would run; install nothing')\n .action((options) => {\n runSelfUpdate({ dryRun: Boolean(options.dryRun) })\n })\n\n program\n .command('mcp')\n .description('Run the infra-kit MCP server (stdio transport)')\n .action(() => {\n runMcp()\n })\n\n program\n .command('dev')\n .description('Run local dev servers for a named devServersPresets preset (or all apps); api + ui')\n .argument('[preset]', 'Named preset from devServersPresets (omit to run every app)')\n .option('-w, --watch', 'Rebuild and restart on file save')\n .option('--app <names>', 'Further narrow to these app folder names (comma-separated)')\n .option(\n '--target <keys>',\n 'Run exactly these <app>/api|<app>/ui packages (comma-separated); part-level, unlike --app',\n )\n .option(\n '--cmux',\n 'Run each app in its own cmux pane (one workspace, N panes; falls back to single terminal if cmux is unavailable)',\n )\n .option('--self', 'Run only the app of the current directory (infer from cwd; use inside apps/<app>/\u2026)')\n .option('-V, --verbose', 'Print full boot narration (default: quiet; full detail always in the session log)')\n .option('--routes', 'Print each app\u2019s registered METHOD /path routes at startup (default: off)')\n .option('--proxy-port <port>', 'Portless proxy listen port for <release>.<package>.localhost URLs (default: 80)')\n .action(async (preset, options) => {\n // Lazy import so fastify/chokidar (and the whole dev stack, plus the wizard's inquirer/config\n // graph) never load on the eager cli graph \u2014 they land in a split chunk reached only for `dev`.\n const { runDevServerCli } = await import('src/entry/dev-server')\n\n // A bare `infra-kit dev` in a TTY launches the interactive wizard; any flag/preset/pipe/--json\n // runs directly. `runDevServerCli` owns that decision (see `shouldRunWizard`).\n const tty = Boolean(process.stdout.isTTY && process.stdin.isTTY)\n\n await runDevServerCli({ ...options, preset }, tty, jsonOutput.enabled)\n })\n\n program\n .command('version')\n .description('Print the installed infra-kit CLI version')\n .action(async () => {\n emit(await version())\n })\n\n program\n .command('env-status')\n .description('Show which env is loaded in this session (local introspection; no Doppler call)')\n .action(async () => {\n emit(await envStatus())\n })\n\n program\n .command('env-list')\n .description('List available Doppler configs for the detected project')\n .action(async () => {\n emit(await envList())\n })\n\n program\n .command('init')\n .description('Inject shell integration into .zshrc and sync repo agent-instruction files')\n .action(async () => {\n emit(await init())\n })\n\n program\n .command('env-load')\n .description('Load Doppler env vars for a config. Source the returned file path to apply.')\n .option('-c, --config <config>', 'Environment config name to load (e.g. dev, arthur)')\n .action(async (options) => {\n emit(await envLoad({ config: options.config }))\n })\n\n program\n .command('env-clear')\n .description('Clear loaded env vars. Source the returned file path to apply.')\n .option('--purge', \"Also delete this project's warm cache outright (durable disable)\")\n .action(async (options) => {\n emit(await envClear({ purge: Boolean(options.purge) }))\n })\n\n // Internal: driven by the init shell-startup integration (backgrounded). Writes\n // env-load.sh when envAutoLoad is configured + eligible; the precmd hook sources\n // it. Hidden + no stdout output so it never pollutes the shell or the menu.\n program\n .command('env-autoload', { hidden: true })\n .description('Internal: prime env for the shell-startup auto-load trigger')\n // The shell passes its already-canonicalized (`${dir:A}`) project dir so node can\n // key the warm cache identically; see writeEnvLoadFile / shouldWriteWarm.\n .option('--project-dir <dir>', 'Canonical project dir for the warm-cache key (shell-startup only)')\n .action(async (options) => {\n await envAutoload({ projectDir: options.projectDir })\n })\n\n // Register `--json` on every command, then resolve the flag before each action\n // runs. In JSON mode we lower the logger to `warn` so the human-oriented info\n // lines stop cluttering stderr while errors still surface; the structured\n // payload is written to stdout by `emit`. No handler logic is affected.\n program.commands.forEach(addJsonOption)\n\n program.hook('preAction', async (_thisCommand, actionCommand) => {\n // `optsWithGlobals` (not `opts`) so `--json` is seen on grouped subcommands:\n // for `release list --json` Commander binds the post-subcommand flag to the\n // parent `release` group, so the leaf's own `opts()` would not carry it.\n jsonOutput.enabled = Boolean(actionCommand.optsWithGlobals().json)\n\n if (jsonOutput.enabled) {\n logger.level = 'warn'\n }\n\n // Layer-3 config auto-seed: ensure ~/.infra-kit/projects/<main-repo>/infra-kit.json exists (plus\n // its annotated .example.jsonc sibling) so a user always has a per-project override file to edit.\n // Self-gating: no-ops outside a git repo, and when the repo has no committed `infra-kit.json`.\n // Never throws, never changes the exit code, and performs zero writes in the steady state.\n //\n // Gated on `commandPath()`, NOT `actionCommand.name()`: a leaf's `name()` is only its last\n // segment (`config path`'s name() is just 'path'), so a name-keyed set cannot distinguish grouped\n // leaves and would collide. Nothing in SEED_EXCLUDED is a grouped leaf today, but the set must be\n // able to express one without a silent trap.\n //\n // Placed after the `--json` warn downgrade purely so a first-run `logger.info` stays out of a\n // machine consumer's stderr. That is COSMETIC, not stdout safety: `logger` is pino with\n // `destination: 2` (stderr) and `emit()` is the sole stdout writer, so the seed's log line could\n // never corrupt `--json` stdout.\n if (!SEED_EXCLUDED.has(commandPath(actionCommand))) {\n await ensureUserProjectConfig()\n }\n\n // cli-invocation auto-load: primes the shell env for SUBSEQUENT commands. The\n // current command does NOT see these vars \u2014 a child process can't mutate its\n // parent shell; the precmd hook sources the written file on the next prompt.\n // runEnvAutoLoad self-gates on config trigger and swallows transient failures,\n // so this is a no-op unless configured for cli-invocation and never blocks.\n if (!isAutoLoadExcludedCommand(actionCommand.name())) {\n await runEnvAutoLoad({ expectedTrigger: 'cli-invocation' })\n }\n })\n\n // Session-shell side channel: after a leaf action RESOLVES (Commander runs postAction only on\n // success \u2014 never when the action throws or calls process.exit), write the report file the parent\n // reads. Its presence is what lets the parent tell a completed run from a cancel. A no-op outside a\n // session (no captured report path) and never on the MCP path (that never builds this program).\n program.hook('postAction', (_thisCommand, actionCommand) => {\n const snapshot = commandEcho.snapshot()\n const flags = snapshot?.formattedOptions ?? ''\n const suffix = flags ? ` ${flags}` : ''\n const line = `infra-kit ${commandPath(actionCommand)}${suffix}`\n\n writeSessionReport({ equivalent: equivalentLine(line, true) })\n })\n\n return program\n}\n", "import process from 'node:process'\nimport { $ } from 'zx'\n\nimport { seedCreatedMessage, seedUserProjectConfig } from 'src/lib/config-bootstrap'\nimport { describeOverrides, readOverrideSummary } from 'src/lib/config-overrides'\nimport { getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { fileExists, tildify } from 'src/lib/path-display'\nimport type { ToolsExecutionResult } from 'src/types'\n\n/**\n * Print the file paths that participate in the config merge chain along with existence markers, so\n * the user can see at a glance which override layers are active. The user-project row additionally\n * reports its CONTENT \u2014 an auto-seeded empty file is indistinguishable from a real one by existence\n * alone, since every command now seeds layer 3.\n *\n * `layers[].exists` keeps its original meaning (the file exists) and still drives the markers;\n * `hasOverrides` / `overrideKeys` are top-level additions describing the user-project layer only.\n *\n * @example\n * // CLI: `infra-kit config path`\n * // INFO: Project name: api\n * // INFO: Config merge chain (later overrides earlier):\n * // INFO: [\u2713] project (committed) ~/projects/api/infra-kit.json\n * // INFO: [ ] user global ~/.infra-kit/infra-kit.json\n * // INFO: [\u2713] user project ~/.infra-kit/projects/api/infra-kit.json (2 override(s): ide, dev)\n */\nexport const configPath = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n\n const rows: { label: string; path: string; exists: boolean }[] = await Promise.all(\n [\n { label: 'project (committed)', path: paths.main },\n { label: 'user global', path: paths.userGlobal },\n { label: 'user project', path: paths.userProject },\n ].map(async (row) => {\n return { ...row, exists: await fileExists(row.path) }\n }),\n )\n\n const userProjectExists = rows.at(-1)?.exists === true\n const summary = await readOverrideSummary(paths.userProject, userProjectExists)\n // Absent layer-3: no suffix \u2014 the `[ ]` marker already says it. (`doctor` owns the louder\n // \"the seed should have created this\" reading of the same state.)\n const note = userProjectExists ? describeOverrides(summary) : ''\n\n logger.info(`Project name: ${paths.projectName}\\n`)\n logger.info('Config merge chain (later overrides earlier):\\n')\n\n for (const row of rows) {\n const marker = row.exists ? ' [\u2713]' : ' [ ]'\n const suffix = row.path === paths.userProject && note !== '' ? ` ${note}` : ''\n\n logger.info(`${marker} ${row.label.padEnd(22)} ${tildify(row.path)}${suffix}`)\n }\n\n const structuredContent = {\n projectName: paths.projectName,\n layers: rows.map((r) => {\n return { label: r.label, path: r.path, exists: r.exists }\n }),\n hasOverrides: summary.hasOverrides,\n overrideKeys: summary.overrideKeys,\n }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n\n/**\n * Open the user-scope per-project override file in $EDITOR, creating it (and refreshing its\n * annotated `.example.jsonc` sibling) on first use. Resets the config cache after the editor exits\n * so subsequent reads pick up the user's edits without a restart.\n *\n * This double-seeds in practice: the program's preAction hook already ran the gated\n * `ensureUserProjectConfig()`, and this runs the ungated primitive again. `seedUserProjectConfig` is\n * idempotent (zero writes in steady state), so that is harmless \u2014 and the ungated call must STAY: it\n * is what makes `config edit` work in a context where the gate declined (no committed project\n * config, `INFRA_KIT_NO_SEED`, or a seed that failed). Asking to edit the file is consent to create\n * it.\n *\n * @example\n * // CLI: `infra-kit config edit`\n * // first run \u2014 creates ~/.infra-kit/projects/api/infra-kit.json ({}) + a sibling\n * // infra-kit.example.jsonc reference, then $EDITOR opens the .json\n * // subsequent runs \u2014 opens the existing file as-is (a stale example is refreshed silently)\n */\nexport const configEdit = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi'\n\n const seed = await seedUserProjectConfig(paths)\n\n if (seed.createdConfig) {\n logger.info(seedCreatedMessage(seed))\n }\n\n logger.info(`Opening ${tildify(paths.userProject)} in ${editor}`)\n\n await $({ stdio: 'inherit' })`${editor} ${paths.userProject}`\n\n resetInfraKitConfigCache()\n\n const structuredContent = { path: paths.userProject, editor }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n", "import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { writeEnvLoadFile } from 'src/commands/env-load'\nimport {\n ENV_CLEAR_FILE,\n ENV_LOAD_FILE,\n INFRA_KIT_ENV_AUTOLOADED_VAR,\n INFRA_KIT_ENV_CLEARED_VAR,\n INFRA_KIT_ENV_CONFIG_VAR,\n INFRA_KIT_ENV_PROJECT_VAR,\n INFRA_KIT_SESSION_VAR,\n getSessionCacheDir,\n} from 'src/lib/constants'\nimport type { EnvAutoLoadConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\n\n/** Which moment a concrete callsite represents. Matches the config `trigger`. */\nexport type AutoLoadTrigger = EnvAutoLoadConfig['trigger']\n\n/** Per-session flag de-duping the MISCONFIG warning (bad envAutoLoad.config). */\nconst WARN_MISCONFIG_SENTINEL_FILE = 'autoload-warn-misconfig.flag'\n/** Per-session flag de-duping the transient-FAILURE warning (Doppler down/unauth). */\nconst WARN_FAIL_SENTINEL_FILE = 'autoload-warn-fail.flag'\n\n/** Per-session marker recording the last auto-load failure (mtime = when). */\nconst FAIL_SENTINEL_FILE = 'autoload-fail.flag'\n\n/**\n * After a failed auto-load, suppress retries for this long so a down/unauthenticated\n * Doppler isn't re-probed on every cli-invocation. A new shell starts a fresh\n * session cache dir, so this only throttles within one session.\n */\nconst FAIL_BACKOFF_MS = 30_000\n\n/** Resolved auto-load inputs: the chosen trigger + the env config and Doppler project to load. */\nexport interface ResolvedEnvAutoLoad {\n trigger: AutoLoadTrigger\n config: string\n project: string\n}\n\n/**\n * Read the resolved + validated env auto-load inputs, or `null` when auto-load\n * should not run. Returns `null` (never throws) when:\n * - we're not inside an infra-kit project (getInfraKitConfig throws), or config is unreadable;\n * - `envAutoLoad` is absent (feature off);\n * - `envAutoLoad.config` is not one of `environments` \u2014 warns once per session, then disables.\n *\n * Validation lives here (not in the schema) so a typo only disables this optional\n * feature instead of throwing inside the merged-config parse and breaking every command.\n * Resolves the Doppler project from the SAME config read (no second getInfraKitConfig),\n * so the skip path stays cheap.\n *\n * `canWarn` gates the misconfig warning: the shell-startup callsite runs backgrounded\n * with stderr discarded, so warning there is invisible AND would write the dedup flag,\n * poisoning the only channel (cli-invocation / interactive) that can actually surface\n * it. So shell-startup passes `false`; interactive callsites pass `true`.\n */\nexport const resolveEnvAutoLoad = async (canWarn = true): Promise<ResolvedEnvAutoLoad | null> => {\n let config\n\n try {\n config = await getInfraKitConfig()\n } catch {\n return null\n }\n\n const autoLoad = config.envAutoLoad\n\n if (!autoLoad) return null\n\n if (!config.environments.includes(autoLoad.config)) {\n if (canWarn) {\n warnOnce(\n `infra-kit: envAutoLoad.config \"${autoLoad.config}\" is not one of environments [${config.environments.join(\n ', ',\n )}] \u2014 env auto-load disabled.`,\n WARN_MISCONFIG_SENTINEL_FILE,\n )\n }\n\n return null\n }\n\n return {\n trigger: autoLoad.trigger,\n config: autoLoad.config,\n project: config.envManagement.config.name,\n }\n}\n\n/** The env-var snapshot the freshness/suppression guards read. */\nexport interface AutoLoadEnvSnapshot {\n session?: string\n cleared?: string\n currentConfig?: string\n currentProject?: string\n autoLoadedMarker?: string\n}\n\nexport interface AutoLoadDecisionInput {\n /** The configured trigger. */\n trigger: AutoLoadTrigger\n /** Which trigger this callsite represents. */\n expectedTrigger: AutoLoadTrigger\n targetConfig: string\n targetProject: string\n env: AutoLoadEnvSnapshot\n /**\n * Bypass ONLY the \"already auto-loaded, same config+project\" no-op skip, forcing\n * a fresh Doppler fetch. The shell-startup refresh sets this: after a WARM source\n * the shell has already exported INFRA_KIT_ENV_AUTOLOADED + the same config, which\n * the child process inherits \u2014 without `force` the refresh would self-skip and the\n * warm (possibly rotated) secrets would never be replaced this session. Does NOT\n * relax the clear/manual-load guards.\n */\n force?: boolean\n}\n\nexport type AutoLoadDecision = 'load' | 'skip'\n\n/**\n * Pure decision: should this callsite (auto-)load env right now? Encodes the full\n * guard matrix so it is exhaustively unit-testable without Doppler or a shell:\n * - the configured trigger must match this callsite;\n * - a session must exist (the cache dir is session-scoped);\n * - an explicit clear suppresses auto-load (M2);\n * - a MANUAL load (config set, no auto marker) is never clobbered (C1);\n * - an auto-load already fresh for the same config AND project is a no-op\n * (project-aware so two same-named configs across different-repo worktrees\n * sharing one session don't leak each other's secrets).\n */\nexport const decideAutoLoad = (input: AutoLoadDecisionInput): AutoLoadDecision => {\n const { trigger, expectedTrigger, targetConfig, targetProject, env, force } = input\n\n if (trigger !== expectedTrigger) return 'skip'\n\n if (!env.session) return 'skip'\n\n if (env.cleared) return 'skip'\n\n // Manual load present (a config is loaded but it wasn't auto-loaded) \u2014 leave it.\n if (env.currentConfig && !env.autoLoadedMarker) return 'skip'\n\n // Our own auto-load already matches the target config+project \u2014 normally a no-op,\n // but `force` (the shell-startup warm refresh) must re-fetch: the shell just warm\n // -sourced these same markers, so skipping here would strand stale secrets.\n if (!force && env.autoLoadedMarker && env.currentConfig === targetConfig && env.currentProject === targetProject) {\n return 'skip'\n }\n\n return 'load'\n}\n\nexport interface RunEnvAutoLoadArgs {\n expectedTrigger: AutoLoadTrigger\n /**\n * Canonical (realpath'd) project dir, forwarded to `writeEnvLoadFile` to enable\n * the project-scoped WARM cache. Only the shell-startup spawn passes it (via\n * `--project-dir`); the cli-invocation trigger omits it, so warm is a\n * shell-startup-only optimization.\n */\n projectDir?: string\n /**\n * Force a fresh fetch past the \"already auto-loaded, same config\" no-op skip. The\n * shell-startup refresh sets this so a preceding WARM source (which exports the\n * same markers the child inherits) is always replaced by fresh secrets. See\n * {@link decideAutoLoad}. The cli-invocation trigger leaves it false.\n */\n force?: boolean\n}\n\n/**\n * Resolve config, evaluate the guards, and (if it should) produce env-load.sh with\n * the auto-load marker. Returns the written file path, or `null` when auto-load was\n * skipped or failed. NEVER throws. Transient failures (Doppler offline / not\n * authenticated / network) record a backoff marker so they aren't re-probed on every\n * command, and are surfaced once per session on the interactive (cli-invocation)\n * channel. No producer-side lock \u2014 a rare cold-shell double-fetch is tolerated (the\n * second write is atomic and idempotent).\n */\nexport const runEnvAutoLoad = async ({\n expectedTrigger,\n projectDir,\n force,\n}: RunEnvAutoLoadArgs): Promise<string | null> => {\n // Only the cli-invocation / interactive callsite reaches a TTY; the shell-startup\n // spawn discards stderr, so warning there is invisible and would poison the dedup.\n const canWarn = expectedTrigger === 'cli-invocation'\n\n try {\n const resolved = await resolveEnvAutoLoad(canWarn)\n\n if (!resolved) return null\n\n const decision = decideAutoLoad({\n trigger: resolved.trigger,\n expectedTrigger,\n targetConfig: resolved.config,\n targetProject: resolved.project,\n env: readAutoLoadEnvSnapshot(),\n force,\n })\n\n if (decision === 'skip') return null\n\n // Disk-level clear signal: a clear that hasn't yet been sourced into this\n // process's env still suppresses auto-load (clear file newer than load file).\n if (isClearedOnDisk()) return null\n\n // Back off after a recent failure so a down/unauthenticated Doppler isn't\n // re-probed on every command in the same session.\n if (recentlyFailed()) return null\n\n const preWriteMtime = readLoadFileMtime()\n const result = await writeEnvLoadFile({\n config: resolved.config,\n autoLoaded: true,\n projectDir,\n // Re-check after the slow Doppler download: abort if a clear or a manual load\n // landed meanwhile, so a backgrounded auto-load never clobbers a deliberate action.\n beforeWrite: () => {\n return !isClearedOnDisk() && !manualLoadLandedSince(preWriteMtime)\n },\n })\n\n if (!result) return null\n\n clearFailure()\n\n return result.filePath\n } catch (error) {\n const reason = (error as Error).message\n\n recordFailure()\n\n // Surface the failure once per session on the interactive channel; stay silent\n // (debug only) on the backgrounded shell-startup path.\n if (canWarn) {\n warnOnce(`infra-kit: env auto-load failed \u2014 ${reason} (will retry later)`, WARN_FAIL_SENTINEL_FILE)\n } else {\n logger.debug(`env auto-load skipped: ${reason}`)\n }\n\n return null\n }\n}\n\n/** Snapshot the env vars the guards depend on. */\nconst readAutoLoadEnvSnapshot = (): AutoLoadEnvSnapshot => {\n return {\n session: process.env[INFRA_KIT_SESSION_VAR],\n cleared: process.env[INFRA_KIT_ENV_CLEARED_VAR],\n currentConfig: process.env[INFRA_KIT_ENV_CONFIG_VAR],\n currentProject: process.env[INFRA_KIT_ENV_PROJECT_VAR],\n autoLoadedMarker: process.env[INFRA_KIT_ENV_AUTOLOADED_VAR],\n }\n}\n\n/** mtime of the on-disk env-load.sh, or null if absent/unreadable. */\nconst readLoadFileMtime = (): number | null => {\n try {\n return fs.statSync(path.join(getSessionCacheDir(), ENV_LOAD_FILE)).mtimeMs\n } catch {\n return null\n }\n}\n\n/**\n * True when a MANUAL env-load landed on disk after `sinceMtime` (the file now\n * exists, is newer, and carries the manual-load `unset INFRA_KIT_ENV_AUTOLOADED`\n * line). Used to abort an in-flight auto-load so it never clobbers a deliberate load.\n */\nconst manualLoadLandedSince = (sinceMtime: number | null): boolean => {\n try {\n const p = path.join(getSessionCacheDir(), ENV_LOAD_FILE)\n\n if (!fs.existsSync(p)) return false\n\n const mtime = fs.statSync(p).mtimeMs\n\n if (sinceMtime !== null && mtime <= sinceMtime) return false\n\n // Anchor to a whole line so the marker can't match inside a single-quoted\n // secret value that happens to contain this literal text.\n const manualMarker = new RegExp(`^unset ${INFRA_KIT_ENV_AUTOLOADED_VAR}$`, 'm')\n\n return manualMarker.test(fs.readFileSync(p, 'utf-8'))\n } catch {\n return false\n }\n}\n\n/**\n * True when a clear is pending on disk: an env-clear.sh exists and is at least as\n * new as env-load.sh (or no load file remains). Belt-and-suspenders next to the\n * INFRA_KIT_ENV_CLEARED env guard for the window before the shell sources the clear.\n */\nconst isClearedOnDisk = (): boolean => {\n try {\n const dir = getSessionCacheDir()\n const clearPath = path.join(dir, ENV_CLEAR_FILE)\n\n if (!fs.existsSync(clearPath)) return false\n\n const loadPath = path.join(dir, ENV_LOAD_FILE)\n\n if (!fs.existsSync(loadPath)) return true\n\n return fs.statSync(clearPath).mtimeMs >= fs.statSync(loadPath).mtimeMs\n } catch {\n return false\n }\n}\n\n/** True when an auto-load failed within the backoff window (suppress retries). */\nconst recentlyFailed = (): boolean => {\n try {\n const flagPath = path.join(getSessionCacheDir(), FAIL_SENTINEL_FILE)\n\n if (!fs.existsSync(flagPath)) return false\n\n return Date.now() - fs.statSync(flagPath).mtimeMs < FAIL_BACKOFF_MS\n } catch {\n return false\n }\n}\n\n/** Record an auto-load failure (refreshes the backoff window). */\nconst recordFailure = (): void => {\n try {\n const dir = getSessionCacheDir()\n\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 })\n fs.writeFileSync(path.join(dir, FAIL_SENTINEL_FILE), '', { mode: 0o600 })\n } catch {\n // No session cache dir \u2014 nothing to back off against.\n }\n}\n\n/** Clear the failure marker after a successful load. */\nconst clearFailure = (): void => {\n try {\n fs.rmSync(path.join(getSessionCacheDir(), FAIL_SENTINEL_FILE), { force: true })\n } catch {\n // No session cache dir \u2014 nothing to clear.\n }\n}\n\n/**\n * Emit a warning at most once per shell session. Keyed on a flag file in the\n * session cache dir so a misconfigured `envAutoLoad.config` (or a repeated failure)\n * does not spam a warning on every cli-invocation. Falls back to a plain warn when\n * no session cache dir is available.\n */\nconst warnOnce = (message: string, sentinelFile: string): void => {\n try {\n const dir = getSessionCacheDir()\n const flagPath = path.join(dir, sentinelFile)\n\n if (fs.existsSync(flagPath)) return\n\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 })\n fs.writeFileSync(flagPath, '', { mode: 0o600 })\n } catch {\n // No session cache dir (e.g. INFRA_KIT_SESSION unset) \u2014 warn without de-dup.\n }\n\n logger.warn(message)\n}\n", "import { runEnvAutoLoad } from 'src/lib/env-autoload'\n\nexport interface EnvAutoloadArgs {\n /**\n * Canonical (realpath'd) project dir the shell computed (`${dir:A}`) and passed\n * via `--project-dir`. Forwarded to enable the project-scoped warm cache; absent\n * when invoked without the flag (then no warm copy is written).\n */\n projectDir?: string\n}\n\n/**\n * Internal command invoked (backgrounded) by the `infra-kit init` shell-startup\n * integration. Runs the 'shell-startup' trigger, writing env-load.sh when\n * envAutoLoad is configured for it + eligible; the shell precmd hook sources it on\n * a subsequent prompt. Intentionally writes NOTHING to stdout and never throws \u2014\n * auto-load must never disrupt shell startup.\n */\nexport const envAutoload = async ({ projectDir }: EnvAutoloadArgs = {}): Promise<void> => {\n // `force`: the shell may have just WARM-sourced the same config (exporting the\n // auto-load marker this process inherits); without it the refresh would self-skip\n // and stale warm secrets would never be replaced this session.\n await runEnvAutoLoad({ expectedTrigger: 'shell-startup', projectDir, force: true })\n}\n", "/**\n * Launch the infra-kit MCP server (stdio transport) as a CHILD process.\n *\n * It must never be imported in-process: src/entry/mcp.ts calls `startServer()` at top-level module load,\n * connecting the stdio transport as a side effect, and `emit()` in src/lib/json-output writes to\n * `process.stdout`. Any stdout write on the CLI dispatch path would corrupt the JSON-RPC framing.\n * Spawning gives the child pristine stdio by construction.\n *\n * `dist/mcp.js` is emitted as a sibling of `dist/cli.js` (esbuild `splitting: true`; both import the\n * shared `chunk-*.js`), so `new URL('./mcp.js', import.meta.url)` resolves correctly from the bundle.\n */\nimport { spawn } from 'node:child_process'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\n\nimport { logger } from 'src/lib/logger'\nimport { withoutPackageManagerEnv } from 'src/lib/pm-env'\n\nexport interface McpDeps {\n spawn?: typeof spawn\n exit?: (code: number) => void\n env?: NodeJS.ProcessEnv\n onError?: (message: string) => void\n}\n\nconst FORWARDED_SIGNALS = ['SIGINT', 'SIGTERM'] as const\n\n/** Resolve the server entry next to this bundle rather than importing it (see module doc). */\nexport const mcpServerPath = (): string => {\n return fileURLToPath(new URL('./mcp.js', import.meta.url))\n}\n\nexport const runMcp = (deps: McpDeps = {}): void => {\n const spawnFn = deps.spawn ?? spawn\n const exit =\n deps.exit ??\n ((code: number) => {\n return process.exit(code)\n })\n const env = deps.env ?? process.env\n const onError =\n deps.onError ??\n ((message: string) => {\n return logger.error(message)\n })\n\n const child = spawnFn(process.execPath, [mcpServerPath()], {\n stdio: 'inherit',\n env: withoutPackageManagerEnv(env),\n })\n\n // An unhandled 'error' event throws. Spawning `process.execPath` should never fail, but a launcher\n // that dies by uncaught exception instead of a named exit is the worst possible failure for a client\n // reading our stdio.\n child.on('error', (error) => {\n onError(`failed to launch the MCP server: ${error.message}`)\n exit(1)\n })\n\n // Forward the client's shutdown signals so the server can close its transport cleanly.\n FORWARDED_SIGNALS.forEach((signal) => {\n process.on(signal, () => {\n child.kill(signal)\n })\n })\n\n child.on('exit', (code, signal) => {\n exit(signal ? 1 : (code ?? 1))\n })\n}\n", "/**\n * Update this CLI in place, using the package manager that actually owns the install.\n *\n * `process.exit` is used directly (rather than `process.exitCode`) because this command is CLI-only and\n * is NEVER exposed over MCP \u2014 see the `self-update` entry in src/lib/command-catalog. Exiting from a\n * long-lived MCP server would kill it; there is no such server on this path.\n *\n * Every process interaction is injected via {@link SelfUpdateDeps} (same seam shape as\n * src/dev/proxy/portless-driver.ts) so tests assert the exact argv and env without shelling out.\n */\nimport { spawnSync } from 'node:child_process'\nimport { realpathSync } from 'node:fs'\nimport process from 'node:process'\nimport { fileURLToPath } from 'node:url'\n\nimport { defaultLazyNpmRoot, detectInstallManager, safeRealpath } from 'src/lib/install-manager'\nimport { logger } from 'src/lib/logger'\nimport { withoutPackageManagerEnv } from 'src/lib/pm-env'\n\nexport interface SelfUpdateDeps {\n spawnSync?: typeof spawnSync\n print?: (line: string) => void\n exit?: (code: number) => never\n env?: NodeJS.ProcessEnv\n selfRealPath?: string\n lazyNpmRoot?: () => string | undefined\n}\n\n/** The realpath of THIS module. A global bin is a symlink, but `import.meta.url` already resolves it. */\nconst defaultSelfRealPath = (): string => {\n return realpathSync(fileURLToPath(import.meta.url))\n}\n\n/**\n * Translate a spawn outcome into an exit. Kept separate from the spawn so each failure mode names itself:\n * a bare `exit(status ?? 1)` would turn a missing binary and a SIGKILL into the same silent `1`.\n */\nconst exitFromResult = (\n result: ReturnType<typeof spawnSync>,\n manager: string,\n print: (line: string) => void,\n exit: (code: number) => never,\n): never => {\n if (result.error) {\n print(`${manager} not found on PATH: ${result.error.message}`)\n\n return exit(1)\n }\n\n if (result.signal) {\n print(`update terminated by signal ${result.signal}`)\n\n return exit(1)\n }\n\n return exit(result.status ?? 1)\n}\n\n/**\n * An EACCES from `npm i -g` (root-owned global dir) surfaces the package manager's own error verbatim\n * through `stdio: 'inherit'`. We NEVER auto-retry with sudo \u2014 silently escalating privileges to write to\n * a global directory is not something a self-updater may do.\n */\nexport const runSelfUpdate = ({ dryRun }: { dryRun: boolean }, deps: SelfUpdateDeps = {}): void => {\n const spawn = deps.spawnSync ?? spawnSync\n const print =\n deps.print ??\n ((line: string) => {\n return logger.info(line)\n })\n const exit =\n deps.exit ??\n ((code: number) => {\n return process.exit(code)\n })\n const env = deps.env ?? process.env\n const selfRealPath = deps.selfRealPath ?? defaultSelfRealPath()\n const lazyNpmRoot = deps.lazyNpmRoot ?? defaultLazyNpmRoot\n\n const { manager, updateCommand, canSelfSpawn } = detectInstallManager({\n selfRealPath,\n env,\n realpath: safeRealpath,\n lazyNpmRoot,\n })\n const printable = updateCommand.join(' ')\n\n if (dryRun) {\n print(`Detected install manager: ${manager}`)\n print(`Would run: ${printable}`)\n\n return\n }\n\n if (!canSelfSpawn) {\n print(`Detected install manager: ${manager}`)\n print(`Run this yourself: ${printable}`)\n print(\n manager === 'homebrew'\n ? 'Not run for you: Homebrew manages this install; running a package manager would create a split-brain install.'\n : 'Not run for you: the install location is unrecognized, so the command above is a guess \u2014 a guessed global install is worse than a printed one.',\n )\n\n return\n }\n\n // `shell` on win32 so the `.cmd` shims npm/pnpm/yarn ship as their global bins resolve.\n const result = spawn(updateCommand[0]!, updateCommand.slice(1), {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n env: withoutPackageManagerEnv(env),\n })\n\n exitFromResult(result, manager, print, exit)\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { pathToFileURL } from 'node:url'\n\nimport { getProjectRoot } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { fileExists, tildify } from 'src/lib/path-display'\nimport { VENDOR_CONFIG_FILE } from 'src/lib/vendor/config-schema'\nimport { expandTilde, getFactoryConfigPath, loadFactoryConfig } from 'src/lib/vendor/factory-config'\n\ninterface VendorConfigOptions {\n /** Scaffold `~/.infra-kit/vendor.json` instead of printing the current one. */\n init?: boolean\n /** Source repo root used for legacy `targets` auto-seeding. Defaults to the git toplevel. */\n cwd?: string\n}\n\n/** Placeholder workspace dir written by `--init`; the user edits it to their layout. */\nconst PLACEHOLDER_WORKSPACE_DIR = '~/projects'\n\n/**\n * Surface or scaffold the machine-local factory config\n * (`~/.infra-kit/vendor.json`). CLI-only \u2014 NOT an MCP tool; returns nothing\n * and signals problems via `process.exitCode`.\n *\n * Without `--init`: prints the factory file path + existence, the resolved\n * `workspaceDir` + existence, and per-target reachability (`[\u2713]`/`[ ]`). Exits\n * non-zero if the file is missing, the workspace dir is missing, or any target\n * is unreachable, so it is usable as a doctor check.\n *\n * With `--init`: scaffolds the file (skipping if it already exists), seeding\n * `targets` from a legacy source `vendor.config.ts` when one is readable.\n */\nexport const vendorConfig = async (options: VendorConfigOptions = {}): Promise<void> => {\n if (options.init) {\n await initFactoryConfig(options.cwd)\n\n return\n }\n\n await printFactoryConfig()\n}\n\n/** Render the factory config chain with `[\u2713]`/`[ ]` reachability markers. */\nconst printFactoryConfig = async (): Promise<void> => {\n const factoryPath = getFactoryConfigPath()\n const exists = await fileExists(factoryPath)\n\n logger.info(`Factory config: ${tildify(factoryPath)} ${exists ? '[\u2713]' : '[ ]'}`)\n\n if (!exists) {\n logger.info('\\nNot found \u2014 run `infra-kit vendor-config --init` to scaffold it.')\n process.exitCode = 1\n\n return\n }\n\n const { workspaceDir, targets } = await loadFactoryConfig()\n const resolvedWorkspace = expandTilde(workspaceDir)\n const workspaceExists = await fileExists(resolvedWorkspace)\n\n logger.info(\n `workspaceDir: ${workspaceDir} (resolved: ${resolvedWorkspace}) ${workspaceExists ? '[\u2713 exists]' : '[ ] not found'}`,\n )\n logger.info('Targets:')\n\n let allReachable = workspaceExists\n\n for (const repo of targets) {\n const targetPath = path.join(resolvedWorkspace, repo)\n const reachable = await fileExists(targetPath)\n\n if (!reachable) {\n allReachable = false\n }\n\n const marker = reachable ? '[\u2713]' : '[ ]'\n const suffix = reachable ? '' : ' (not found \u2014 clone or remove)'\n\n logger.info(` ${marker} ${repo} ${tildify(targetPath)}${suffix}`)\n }\n\n if (!allReachable) {\n process.exitCode = 1\n }\n}\n\n/** Scaffold `~/.infra-kit/vendor.json`, skipping if it already exists. */\nconst initFactoryConfig = async (cwd?: string): Promise<void> => {\n const factoryPath = getFactoryConfigPath()\n\n if (await fileExists(factoryPath)) {\n logger.info(`Factory config already exists at ${tildify(factoryPath)} \u2014 leaving it untouched.`)\n\n return\n }\n\n const sourceRoot = cwd ?? (await getProjectRoot())\n const seededTargets = await readLegacyTargets(sourceRoot)\n\n await fs.mkdir(path.dirname(factoryPath), { recursive: true })\n await fs.writeFile(factoryPath, buildScaffold(seededTargets), 'utf-8')\n\n logger.info(`\u2713 Created ${tildify(factoryPath)}`)\n\n if (seededTargets.length > 0) {\n logger.info(` Seeded ${seededTargets.length} target(s) from the source ${VENDOR_CONFIG_FILE}.`)\n }\n\n logger.info(` Edit \\`workspaceDir\\` (placeholder: ${PLACEHOLDER_WORKSPACE_DIR}) to point at where your repos live.`)\n\n if (seededTargets.length === 0) {\n logger.info(' Add at least one repo name to `targets` before running vendor sync/manifest/diff.')\n }\n}\n\n/**\n * Best-effort read of a legacy `targets` array from the source repo's\n * `vendor.config.ts`. The current schema no longer accepts `targets`, so this\n * reads the raw default export directly (bypassing validation). Returns `[]` on\n * any failure \u2014 seeding is a convenience, never a hard requirement.\n */\nconst readLegacyTargets = async (sourceRoot: string): Promise<string[]> => {\n try {\n const configPath = path.join(sourceRoot, VENDOR_CONFIG_FILE)\n const stat = await fs.stat(configPath)\n const moduleUrl = `${pathToFileURL(configPath).href}?mtime=${Number(stat.mtimeMs)}`\n const imported = (await import(moduleUrl)) as { default?: unknown }\n const raw = imported.default\n const resolved = typeof raw === 'function' ? await (raw as () => unknown)() : raw\n\n if (resolved && typeof resolved === 'object' && 'targets' in resolved) {\n const targets = (resolved as { targets?: unknown }).targets\n\n if (\n Array.isArray(targets) &&\n targets.every((t) => {\n return typeof t === 'string'\n })\n ) {\n return targets as string[]\n }\n }\n } catch {\n // Absent or unreadable source config \u2014 fall through to an empty placeholder.\n }\n\n return []\n}\n\n/**\n * Render the scaffold file body as strict JSON (`vendor.json`). The factory config\n * is static JSON, loaded with `JSON.parse` \u2014 no comments, no executable code. When\n * `targets` is empty the stub writes `\"targets\": []`, which fails the schema's\n * `targets.min(1)` on load: this is intentional \u2014 `--init` produces an incomplete\n * stub the user must edit before running vendor sync/manifest/diff. The annotated\n * guidance lives in the sibling `vendor.example.jsonc` (seeded by `infra-kit init`).\n */\nconst buildScaffold = (targets: string[]): string => {\n return `${JSON.stringify({ workspaceDir: PLACEHOLDER_WORKSPACE_DIR, targets }, null, 2)}\\n`\n}\n", "/**\n * The shared \"equivalent line\" shape \u2014 the replayable, non-interactive invocation\n * a session prints so the user can rerun the same selection without prompts. Kept\n * command-agnostic (dev, vendor, audit \u2026 all emit one) and structural so it never\n * has to import a specific command's wizard types. Pure data + a tiny constructor.\n */\n\n/** One replayable invocation line, plus whether it reproduces the selection exactly. */\nexport interface EquivalentLine {\n /** The full replayable invocation, e.g. \"infra-kit vendor check\". */\n line: string\n /** True when the line reproduces the selection exactly (false \u21D2 it would re-prompt). */\n reproducible: boolean\n}\n\n/**\n * Construct an {@link EquivalentLine}. Defaults to `reproducible: true` for the\n * common case where the printed line replays the selection verbatim.\n *\n * @example\n * equivalentLine('infra-kit vendor check') // => { line: 'infra-kit vendor check', reproducible: true }\n * equivalentLine('infra-kit dev --app=client', false) // => { line: '\u2026', reproducible: false }\n */\nexport const equivalentLine = (line: string, reproducible = true): EquivalentLine => {\n return { line, reproducible }\n}\n", "import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport type { EquivalentLine } from './equivalent'\n\n/**\n * Session-private side channel from a spawned command child back to the session-shell parent. The\n * child writes a small JSON record at the path in `INFRA_KIT_SESSION_REPORT`; the parent reads it to\n * derive the transcript entry. The record is NOT `ToolsExecutionResult` and never touches the `--json`\n * / MCP machine contract \u2014 it exists only so the parent can show a rich `equivalent + report` block.\n *\n * The file's PRESENCE is load-bearing: a decline/cancel path exits before the write, so an absent file\n * (with exit 0) is how the parent tells \"cancelled\" from \"ok\". See `classifyOutcome`.\n */\n\nexport const SESSION_REPORT_ENV = 'INFRA_KIT_SESSION_REPORT'\n\nexport interface SessionReportRecord {\n /** The replayable equivalent line for this invocation (resolved flags folded in when interactive). */\n equivalent?: EquivalentLine\n /** Optional human summary lines a command opted to surface (e.g. \"found 3 violations\"). */\n summary?: string[]\n}\n\n// The child captures the report path ONCE at CLI entry and deletes the env var so no grandchild\n// (gh / git / a hook / $EDITOR) inherits it and clobbers the file. `captured` guards a double-capture.\nlet capturedReportPath: string | null = null\nlet captured = false\nconst summaryLines: string[] = []\n\n/**\n * Capture `INFRA_KIT_SESSION_REPORT` into a module local and delete it from the env so descendants do\n * not inherit it. Call once at CLI entry (in every process); a non-session process simply captures\n * `null`. Idempotent.\n *\n * @example\n * const env = { INFRA_KIT_SESSION_REPORT: '/tmp/r.json' }\n * captureSessionReportPath(env)\n * env.INFRA_KIT_SESSION_REPORT // => undefined (deleted so grandchildren don't inherit)\n */\nexport const captureSessionReportPath = (env: NodeJS.ProcessEnv = process.env): void => {\n if (captured) {\n return\n }\n\n capturedReportPath = env[SESSION_REPORT_ENV] ?? null\n captured = true\n delete env[SESSION_REPORT_ENV]\n}\n\n/** True when this process is running as a session-shell child (a report path was captured). */\nexport const isSessionChild = (): boolean => {\n return capturedReportPath != null\n}\n\n/**\n * Reset the captured path + accumulated summary. For tests only (the process-lifetime singleton is\n * captured exactly once at CLI entry in real use). Mirrors `commandEcho.reset()`.\n *\n * @example\n * resetSessionReport()\n * isSessionChild() // => false\n */\nexport const resetSessionReport = (): void => {\n capturedReportPath = null\n captured = false\n summaryLines.length = 0\n}\n\n/**\n * Accumulate optional human summary lines for this invocation's transcript entry. A no-op outside a\n * session; commands may call it to enrich the report without knowing whether a session is active.\n *\n * @example\n * addSessionSummary('found 3 violations')\n */\nexport const addSessionSummary = (...lines: string[]): void => {\n summaryLines.push(...lines)\n}\n\n/**\n * Write the session report to the captured path. No-op when not running under a session (path null).\n * Best-effort: a write failure never throws (the parent falls back to exit-code-derived status).\n *\n * @example\n * writeSessionReport({ equivalent: { line: 'infra-kit vendor check', reproducible: true } })\n */\nexport const writeSessionReport = (\n record: SessionReportRecord,\n deps?: { write?: (file: string, data: string) => void },\n): void => {\n if (!capturedReportPath) {\n return\n }\n\n const summary = record.summary ?? (summaryLines.length > 0 ? [...summaryLines] : undefined)\n const payload: SessionReportRecord = { ...record, ...(summary ? { summary } : {}) }\n const write =\n deps?.write ??\n ((file: string, data: string) => {\n fs.writeFileSync(file, data)\n })\n\n try {\n write(capturedReportPath, JSON.stringify(payload))\n } catch {\n // Best-effort: an unwritable report degrades the transcript to exit-code-only, never a crash.\n }\n}\n\n// --- Parent side (session shell) -----------------------------------------\n\nlet reportCounter = 0\n\n/**\n * A fresh, unique report path under the OS temp dir for one spawned command. Never uses\n * `getSessionCacheDir()` (which throws when `INFRA_KIT_SESSION` is unset) \u2014 this ephemeral IPC needs\n * no session scoping. Uniqueness comes from pid + a monotonic counter, so no `Math.random` is needed.\n *\n * @example\n * newReportPath() // => '/var/folders/\u2026/infra-kit-session-4123-1.json'\n */\nexport const newReportPath = (deps?: { tmpdir?: () => string; pid?: number }): string => {\n const tmp = deps?.tmpdir?.() ?? os.tmpdir()\n const pid = deps?.pid ?? process.pid\n\n reportCounter += 1\n\n return path.join(tmp, `infra-kit-session-${pid}-${reportCounter}.json`)\n}\n\n/**\n * Read and delete a child's report file. Returns the parsed record, or `null` when the file is absent\n * (the child cancelled / crashed before writing) or unparseable.\n *\n * @example\n * const record = readAndUnlinkReport('/tmp/r.json')\n * record?.equivalent?.line\n */\nexport const readAndUnlinkReport = (\n reportPath: string,\n deps?: { read?: (file: string) => string; unlink?: (file: string) => void; exists?: (file: string) => boolean },\n): SessionReportRecord | null => {\n const exists =\n deps?.exists ??\n ((file: string) => {\n return fs.existsSync(file)\n })\n\n if (!exists(reportPath)) {\n return null\n }\n\n const read =\n deps?.read ??\n ((file: string) => {\n return fs.readFileSync(file, 'utf-8')\n })\n const unlink =\n deps?.unlink ??\n ((file: string) => {\n return fs.unlinkSync(file)\n })\n\n let raw: string\n\n try {\n raw = read(reportPath)\n } catch {\n return null\n } finally {\n try {\n unlink(reportPath)\n } catch {\n // A leftover temp file is harmless; the next iteration uses a fresh counter-suffixed name.\n }\n }\n\n try {\n return JSON.parse(raw) as SessionReportRecord\n } catch {\n return null\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Command", "process", "process", "$", "configPath", "paths", "getInfraKitConfigPaths", "rows", "row", "fileExists", "userProjectExists", "summary", "readOverrideSummary", "note", "describeOverrides", "logger", "marker", "suffix", "tildify", "structuredContent", "configEdit", "editor", "process", "seed", "seedUserProjectConfig", "seedCreatedMessage", "$", "resetInfraKitConfigCache", "fs", "path", "process", "WARN_MISCONFIG_SENTINEL_FILE", "WARN_FAIL_SENTINEL_FILE", "FAIL_SENTINEL_FILE", "FAIL_BACKOFF_MS", "resolveEnvAutoLoad", "canWarn", "config", "getInfraKitConfig", "autoLoad", "warnOnce", "decideAutoLoad", "input", "trigger", "expectedTrigger", "targetConfig", "targetProject", "env", "force", "runEnvAutoLoad", "projectDir", "resolved", "readAutoLoadEnvSnapshot", "isClearedOnDisk", "recentlyFailed", "preWriteMtime", "readLoadFileMtime", "result", "writeEnvLoadFile", "manualLoadLandedSince", "clearFailure", "error", "reason", "recordFailure", "logger", "process", "INFRA_KIT_SESSION_VAR", "INFRA_KIT_ENV_CLEARED_VAR", "INFRA_KIT_ENV_CONFIG_VAR", "INFRA_KIT_ENV_PROJECT_VAR", "INFRA_KIT_ENV_AUTOLOADED_VAR", "fs", "path", "getSessionCacheDir", "ENV_LOAD_FILE", "sinceMtime", "p", "mtime", "dir", "clearPath", "ENV_CLEAR_FILE", "loadPath", "flagPath", "message", "sentinelFile", "envAutoload", "projectDir", "runEnvAutoLoad", "spawn", "process", "fileURLToPath", "FORWARDED_SIGNALS", "mcpServerPath", "fileURLToPath", "runMcp", "deps", "spawnFn", "spawn", "exit", "code", "process", "env", "onError", "message", "logger", "child", "withoutPackageManagerEnv", "error", "signal", "spawnSync", "realpathSync", "process", "fileURLToPath", "defaultSelfRealPath", "realpathSync", "fileURLToPath", "exitFromResult", "result", "manager", "print", "exit", "runSelfUpdate", "dryRun", "deps", "spawn", "spawnSync", "line", "logger", "code", "process", "env", "selfRealPath", "lazyNpmRoot", "defaultLazyNpmRoot", "updateCommand", "canSelfSpawn", "detectInstallManager", "safeRealpath", "printable", "withoutPackageManagerEnv", "fs", "path", "process", "pathToFileURL", "PLACEHOLDER_WORKSPACE_DIR", "vendorConfig", "options", "initFactoryConfig", "printFactoryConfig", "factoryPath", "getFactoryConfigPath", "exists", "fileExists", "logger", "tildify", "process", "workspaceDir", "targets", "loadFactoryConfig", "resolvedWorkspace", "expandTilde", "workspaceExists", "allReachable", "repo", "targetPath", "path", "reachable", "marker", "suffix", "cwd", "sourceRoot", "getProjectRoot", "seededTargets", "readLegacyTargets", "fs", "buildScaffold", "VENDOR_CONFIG_FILE", "configPath", "stat", "raw", "pathToFileURL", "resolved", "t", "equivalentLine", "line", "reproducible", "fs", "os", "path", "process", "SESSION_REPORT_ENV", "capturedReportPath", "captured", "summaryLines", "captureSessionReportPath", "env", "writeSessionReport", "record", "deps", "capturedReportPath", "summary", "summaryLines", "payload", "write", "file", "data", "fs", "reportCounter", "newReportPath", "tmp", "os", "pid", "process", "path", "readAndUnlinkReport", "reportPath", "read", "unlink", "raw", "collectReleaseSpec", "value", "prev", "parseRepos", "normalizeIdeMode", "flagName", "IDE_MODES", "invokedViaMenu", "deprecatedAlias", "cmd", "preferred", "logger", "configureMergeDev", "options", "emit", "ghMergeDev", "configureReleaseList", "ghReleaseList", "configureReleaseCreate", "inputs", "parseReleaseSpec", "releases", "releaseCreate", "configureReleaseDescEdit", "releaseDescEdit", "configureReleaseDeployAll", "ghReleaseDeployAll", "configureReleaseDeploySelected", "ghReleaseDeploySelected", "configureReleaseDeliver", "ghReleaseDeliver", "configureWorktreesSync", "worktreesSync", "configureWorktreesAdd", "ide", "worktreesAdd", "configureWorktreesList", "worktreesList", "configureWorktreesRemove", "worktreesRemove", "configureWorktreesReload", "worktreesReload", "configureVendorConfig", "vendorConfig", "configureVendorCheck", "result", "vendorCheck", "process", "configureVendorDiff", "vendorDiff", "configureConfigPath", "configPath", "configureConfigEdit", "configEdit", "AUTO_LOAD_EXCLUDED", "isAutoLoadExcludedCommand", "name", "SEED_EXCLUDED", "commandPath", "leaf", "parts", "node", "buildProgram", "program", "Command", "releaseGroup", "worktreesGroup", "configCmd", "audit", "vendorCmd", "vendorSync", "vendorManifest", "doctor", "runSelfUpdate", "runMcp", "preset", "runDevServerCli", "tty", "jsonOutput", "version", "envStatus", "envList", "init", "envLoad", "envClear", "envAutoload", "addJsonOption", "_thisCommand", "actionCommand", "ensureUserProjectConfig", "runEnvAutoLoad", "flags", "commandEcho", "suffix", "line", "writeSessionReport", "equivalentLine"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import T from"node:process";import C from"pino";import te from"pino-pretty";var _="/tmp/mcp-infra-kit.log",Rt=()=>{let e=T.argv.includes("--debug")?"debug":"info",t=C({level:e},C.destination({dest:_}));return t.info(`Logger initialized with level: ${e}. Logging to: ${_}`),t},re=()=>{let e=T.argv.includes("--debug")?"debug":"info",t=["time","pid","hostname"];return e==="debug"&&t.push("level"),C({level:e},te({destination:2,ignore:t.join(","),colorize:!0}))},wt=re();import*as p from"node:fs";import*as a from"node:path";function ne(e){let t=e;for(let r=0;r<10;r++){let n=a.join(t,"pnpm-workspace.yaml");if(p.existsSync(n))return t;t=a.dirname(t)}throw new Error("Could not find monorepo root (pnpm-workspace.yaml)")}function K(e,t){let r=a.join(e,"package.json");if(!p.existsSync(r))return t;try{let n=JSON.parse(p.readFileSync(r,"utf-8"));return typeof n.name=="string"?n.name:t}catch{return t}}function Ct(e){let t=a.join(e,"apps"),r=[];if(!p.existsSync(t))throw new Error(`Apps directory not found: ${t}`);let n=p.readdirSync(t,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of n){let i=a.join(t,s,"api"),c=a.join(i,"serverless.yml");p.existsSync(c)&&r.push({name:s,packageName:K(i,s),path:i})}return r}var se=["vite.config.ts","vite.config.mts","vite.config.cts","vite.config.js","vite.config.mjs","vite.config.cjs"];function oe(e){for(let t of se){let r=a.join(e,t);if(p.existsSync(r))try{return p.readFileSync(r,"utf-8").includes("infra-kit/vite")}catch{return!1}}return!1}function ie(e){let t=a.join(e,"package.json");if(!p.existsSync(t))return!1;try{let r=JSON.parse(p.readFileSync(t,"utf-8"));return typeof r.scripts?.dev=="string"&&r.scripts.dev.length>0}catch{return!1}}function St(e){let t=a.join(e,"apps"),r=[];if(!p.existsSync(t))return r;let n=p.readdirSync(t,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of n){let i=a.join(t,s,"ui");p.existsSync(i)&&ie(i)&&r.push({name:s,packageName:K(i,s),path:i,managedPort:oe(i)})}return r}function Dt(e){let t=e?.filter(Boolean)??[];return t.length>0?t:null}function It(e){let t=ne(e),r=a.relative(a.join(t,"apps"),e),n=r.split(a.sep)[0];if(r===""||r.startsWith("..")||a.isAbsolute(r)||!n)throw new Error(`--self: not inside an apps/<app> directory (cwd: ${e}). Run from an app folder or use --app=<name>.`);return n}var ae=new Set(["api","ui"]),O=e=>{let t=a.join(e,"dist");return p.existsSync(t)&&p.statSync(t).isDirectory()?t:void 0},S=e=>p.existsSync(e)?p.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()).map(t=>t.name):[];function jt(e){let t=[];for(let n of S(a.join(e,"packages"))){let s=O(a.join(e,"packages",n));s!==void 0&&t.push(s)}let r=a.join(e,"apps");for(let n of S(r))for(let s of S(a.join(r,n))){if(ae.has(s))continue;let i=a.join(r,n,s);if(!p.existsSync(a.join(i,"package.json")))continue;let c=O(i);c!==void 0&&t.push(c)}return t}function Et(e){return e.map(t=>a.join(t.path,"dist")).filter(t=>p.existsSync(t))}function At(e,t,r){let n=a.normalize(e),s=r.find(c=>n.startsWith(a.normalize(c)));return s?{kind:"package",packageDir:s}:{kind:"app",app:t.find(c=>n.startsWith(a.normalize(c)))}}var ce={"*/api":{},"*/ui":{}},F=e=>{let t=e.split("/"),[r,n]=t;return t.length!==2||!r?`devServersPresets: invalid target "${e}" (expected "<app>/api" or "<app>/ui")`:n!=="api"&&n!=="ui"?`devServersPresets: invalid target part "${n}" in "${e}" (expected "api" or "ui")`:null},pe=e=>{let t=F(e);if(t)throw new Error(t);let[r,n]=e.split("/");return{appGlob:r,part:n}},Lt=e=>{let t=[];for(let[r,n]of Object.entries(e))for(let s of Object.keys(n.apps??{})){let i=F(s);i&&t.push({preset:r,key:s,message:`preset "${r}": ${i}`})}return t},le=(e,t)=>t==="api"?e.api:e.ui,ue=e=>[...new Set([...e.api,...e.ui])].sort(),M=(e,t)=>`${e}/${t}`,fe=e=>e?0:1,ge=(e,t)=>t.watchDeps===void 0?e??{watchDeps:!0,rank:t.rank,explicitValue:!1}:!e||!e.explicitValue?{watchDeps:t.watchDeps,rank:t.rank,explicitValue:!0}:t.rank>e.rank?{watchDeps:t.watchDeps,rank:t.rank,explicitValue:!0}:e,de=(e,t,r)=>{let{app:n,part:s,watchDeps:i,isGlob:c}=r;if(!le(t,s).includes(n)){c||e.unmatched.push(M(n,s));return}let l=M(n,s),u=ge(e.targets.get(l),{watchDeps:i,rank:fe(c)});e.targets.set(l,{app:n,part:s,...u})},me=(e,t)=>{let r=Object.entries(e.apps??ce),n={targets:new Map,proxy:{},unmatched:[]};for(let[c,l]of r){let{appGlob:u,part:h}=pe(c),k=u==="*",R=k?ue(t):[u];for(let b of R)de(n,t,{app:b,part:h,watchDeps:l.watchDeps,isGlob:k}),l.proxy&&(n.proxy[b]={...n.proxy[b]??{},...l.proxy})}let s=[...n.targets.values()].map(({app:c,part:l,watchDeps:u})=>({app:c,part:l,watchDeps:u})),i=[...new Set(s.filter(c=>c.part==="api").map(c=>c.app))];return{targets:s,cmux:e.cmux??!1,proxy:n.proxy,localApps:i,unmatched:n.unmatched}},Nt=e=>{if(e.preset!=null)return e.preset;if(e.running.length===0)return"nothing";let t=new Set(e.running);return e.discovered.every(n=>t.has(n))?"*":[...t].sort().join(" + ")},he=(e,t)=>Object.keys(e).find(r=>e[r]===t),ve=({preset:e,app:t,route:r,launchedPkgs:n,ctx:s})=>{let i=s.routePkg(t,r);if(i===void 0)return{preset:e,app:t,route:r,kind:"unknown-route",message:`preset "${e}": proxy override "${r}" on "${t}" names a route not declared in ${t}'s infra-kit.config.ts dev.proxy.routes`};if(n.has(i))return null;let c=he(s.apiPkgByApp,i),l=c?`add "${c}/api" to the preset`:`launch the api whose package is "${i}"`;return{preset:e,app:t,route:r,pkg:i,kind:"backend-not-launched",message:`preset "${e}": proxy override "${r}" \u2192 "local" requires backend "${i}" to run locally, but the preset does not launch it \u2014 ${l}, or set "${r}" to "cloud"`}},_t=(e,t)=>{let r=[];for(let[n,s]of Object.entries(e)){let i=me(s,t.discovered),c=new Set(i.localApps.map(l=>t.apiPkgByApp[l]).filter(l=>l!==void 0));for(let[l,u]of Object.entries(i.proxy))for(let[h,k]of Object.entries(u)){if(k!=="local")continue;let R=ve({preset:n,app:l,route:h,launchedPkgs:c,ctx:t});R&&r.push(R)}}return r};import L from"node:fs/promises";import J from"node:os";import x from"node:path";import Oe from"node:process";import{z as o}from"zod";import d from"node:path";import{$ as f}from"zx";var ye=/^v?(\d+)\.(\d+)\.(\d+)$/,xe=/^(\d+)\.(\d+)\.(\d+)$/,Pe=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,w="release/",D="release/v",B="refs/heads/",ke="next";var G=new Set(["dev","main","next","hotfix","regular","release"]),g=class extends Error{constructor(t){super(t),this.name="InvalidReleaseNameError"}},v=class extends Error{constructor(t){super(t),this.name="InvalidReleaseRefError"}},U=e=>e.startsWith(B)?e.slice(B.length):e,V=(e,t,r)=>({kind:"version",semver:{major:e,minor:t,patch:r},raw:`${e}.${t}.${r}`}),I=e=>{if(e.length===0)throw new g('Release name is empty. Provide a kebab-case name like "checkout-redesign".');if(e.length>50)throw new g(`Release name "${e}" is ${e.length} characters; the maximum is 50.`);if(!Pe.test(e))throw new g(`Release name "${e}" is not kebab-case. Use lowercase letters, digits, and single hyphens, e.g. "checkout-redesign".`);if(G.has(e))throw new g(`Release name "${e}" is reserved. Reserved names: ${[...G].join(", ")}.`)},j=e=>{let t=U(e.trim());if(!t.startsWith(w))return null;if(t.startsWith(D)){let n=t.slice(D.length),s=xe.exec(n);if(s)return V(Number(s[1]),Number(s[2]),Number(s[3]))}let r=t.slice(w.length);try{I(r)}catch{return null}return{kind:"name",name:r,raw:r}},Re=e=>{let t=e.trim();if(U(t).startsWith(w)){let s=j(t);if(!s)throw new v(`"${e}" looks like a release branch but is not a valid release/v<semver> or release/<name> ref.`);return s}let n=ye.exec(t);if(n)return V(Number(n[1]),Number(n[2]),Number(n[3]));if(t.toLowerCase()===ke)throw new v('The "next" token must be resolved to a concrete version (via computeNextVersion) before parsing a release ref.');try{I(t)}catch(s){let i=s instanceof Error?s.message:String(s);throw new v(`Cannot parse "${e}" as a release ref: ${i}`)}return{kind:"name",name:t,raw:t}},we=e=>e.kind==="version"?`${D}${e.raw}`:`${w}${e.name}`,be=(e,t)=>{let r=t==="hotfix"?"Hotfix":"Release";return e.kind==="version"?`${r} v${e.raw}`:`${r} ${e.name}`},Ce=e=>e.kind==="version"?`Release v${e.raw} (RC)`:`Release ${e.name} (RC)`,Se=e=>e.kind==="version"?`v${e.raw}`:e.name,De=e=>e.raw,E=e=>e==null?!1:j(e)!==null,z=e=>{if(e===void 0)return null;let t=e instanceof Date?e.getTime():new Date(e).getTime();return Number.isNaN(t)?null:t},Ie=(e,t,r)=>{if(e.kind==="version"&&t.kind==="version")return e.semver.major!==t.semver.major?e.semver.major-t.semver.major:e.semver.minor!==t.semver.minor?e.semver.minor-t.semver.minor:e.semver.patch-t.semver.patch;if(e.kind==="version")return-1;if(t.kind==="version")return 1;let n=z(r?.a),s=z(r?.b);return n!==null&&s!==null&&n!==s?n-s:e.name<t.name?-1:e.name>t.name?1:0};var je=async e=>{let r=(await f`git worktree list`).stdout.split(`
|
|
2
|
+
`).filter(Boolean),n={release:Ee,feature:Ae};return r.map(n[e]).filter(s=>s!==null)},W=e=>{let t=e.trimEnd();if(!t.endsWith("]"))return null;let r=t.lastIndexOf("[");if(r===-1)return null;let n=t.slice(r+1,-1);return n.length>0?n:null},Ee=e=>{let t=W(e);return E(t)?t:null},Ae=e=>{let t=W(e);return t?.startsWith("feature/")?t:null},y=async()=>(await f`git rev-parse --show-toplevel`).stdout.trim(),A=async e=>{let t=e??await y(),r=(await f({cwd:t})`git rev-parse --git-common-dir`).stdout.trim(),n=d.resolve(t,r);return n.includes(`${d.sep}.git${d.sep}modules${d.sep}`)?t:d.dirname(n)},H=async()=>(await f`git rev-parse --abbrev-ref HEAD`).stdout.trim(),$e=async()=>(await f`git status --porcelain`).stdout.trim().length===0,Le=async()=>{let e=await y(),[t,r]=await Promise.all([f({cwd:e})`git rev-parse --absolute-git-dir`,f({cwd:e})`git rev-parse --git-common-dir`]),n=t.stdout.trim(),s=d.resolve(e,r.stdout.trim());return n!==s},Ne=async()=>{let e=await y();return d.basename(e)},_e=async e=>{(await f`git branch --list ${e}`).stdout.trim().length!==0&&await H()!==e&&await f`git branch -D ${e}`},Te=async e=>{(await f`git ls-remote --heads origin ${e}`).stdout.trim().length!==0&&await f`git push origin --delete ${e}`};var X="infra-kit.json",Y=".infra-kit",Ke="infra-kit.json",Me="projects",Fe=o.object({provider:o.literal("doppler"),config:o.object({name:o.string().min(1)})}),Be=o.discriminatedUnion("provider",[Fe]),Ge=o.object({workspaceConfigPath:o.string().min(1)}),ze=o.object({provider:o.literal("cursor"),config:Ge}),Ue=o.object({}),Ve=o.object({provider:o.literal("zed"),config:Ue}),q=o.discriminatedUnion("provider",[ze,Ve]),We=o.union([q,o.array(q).min(1)]),He=o.object({provider:o.literal("jira"),config:o.object({baseUrl:o.string().url(),projectId:o.number().int().positive()})}),Xe=o.discriminatedUnion("provider",[He]),qe=["two-columns","three-pane"],Je=o.object({layout:o.enum(qe).optional()}),Ye=o.object({openInGithubDesktop:o.boolean().optional(),openInCmux:o.boolean().optional(),cmux:Je.optional()}),Qe=o.object({port:o.number().int().positive().optional(),prefixUrl:o.string().min(1).optional()}).strict(),Ze=o.record(o.string().min(1),Qe),et=o.enum(["local","cloud"]),tt=o.object({watchDeps:o.boolean().optional(),proxy:o.record(o.string().min(1),et).optional()}).strict(),rt=o.object({apps:o.record(o.string().min(1),tt).optional(),cmux:o.boolean().optional()}).strict(),nt=o.record(o.string().min(1),rt),st=o.object({port:o.number().int().positive().optional()}).strict(),ot=o.object({trigger:o.enum(["shell-startup","cli-invocation"]),config:o.string().min(1)}).strict(),N=o.object({environments:o.array(o.string().min(1)).min(1),envManagement:Be,ide:We.optional(),taskManager:Xe.optional(),worktrees:Ye.optional(),envAutoLoad:ot.optional(),dev:Ze.optional(),devServersPresets:nt.optional(),devProxy:st.optional()}).strict(),it=80,at=1024,ct=1355,Q=N.superRefine((e,t)=>{if(!Array.isArray(e.ide))return;let r=new Set;for(let n of e.ide){if(r.has(n.provider)){t.addIssue({code:"custom",message:"each IDE provider may appear at most once",path:["ide"]});return}r.add(n.provider)}}),Z=N.partial(),pt=e=>{let t=e.ide;return t?Array.isArray(t)?t:[t]:[]},lt="two-columns",ut=e=>e.worktrees?.cmux?.layout??lt,m=null,P=null,ft=()=>`${Oe.cwd()} ${J.homedir()}`,ee=async()=>{let e=ft();if(P&&P.key===e)return P.value;let t=await y(),r=await A(t),n=x.basename(r),s=x.join(J.homedir(),Y),i={main:x.join(t,X),userGlobal:x.join(s,Ke),userProject:x.join(s,Me,n,X),projectName:n};return P={key:e,value:i},i},gt=async()=>{let e=await ee(),t;try{t=await L.stat(e.main)}catch{m=null;let u=e.main.replace(/\.json$/,".yml");throw await $(u)?new Error(`infra-kit.json not found at ${e.main}. A legacy infra-kit.yml exists \u2014 run \`infra-kit init\` to convert it.`):new Error(`infra-kit.json not found at ${e.main}`)}let[r,n]=await Promise.all([$(e.userGlobal),$(e.userProject)]),s={main:Number(t.mtimeMs),userGlobal:r?Number(r.mtimeMs):null,userProject:n?Number(n.mtimeMs):null};if(m&&vt(m.mtimes,s))return m.value;let i=[{label:"infra-kit.json",path:e.main,required:!0},{label:"~/.infra-kit/infra-kit.json",path:e.userGlobal,required:!1},{label:`~/.infra-kit/projects/${e.projectName}/infra-kit.json`,path:e.userProject,required:!1}],c={};for(let u of i){let h=await yt(u);h!==null&&(c={...c,...h})}let l=Q.safeParse(c);if(!l.success)throw new Error(`Invalid merged infra-kit config: ${o.prettifyError(l.error)}`);return m={mtimes:s,value:l.data},l.data},dt=()=>{m=null},mt=()=>{m=null,P=null},$=async e=>{try{return await L.stat(e)}catch{return null}},ht=async e=>{try{return await L.readFile(e,"utf-8")}catch{return null}},vt=(e,t)=>{let r=Object.keys(e);return r.length!==Object.keys(t).length?!1:r.every(n=>e[n]===t[n])},yt=async e=>{let t=await ht(e.path);if(t===null){if(e.required)throw new Error(`${e.label} not found at ${e.path}`);return null}let r;try{r=t.trim()===""?{}:JSON.parse(t)}catch(s){throw new Error(`Invalid JSON in ${e.label} at ${e.path}: ${s.message}`)}let n=Z.safeParse(r);if(!n.success)throw new Error(`Invalid ${e.label} at ${e.path}: ${o.prettifyError(n.error)}`);return n.data};export{g as a,I as b,j as c,Re as d,we as e,be as f,Ce as g,Se as h,De as i,E as j,Ie as k,je as l,y as m,H as n,$e as o,Le as p,Ne as q,_e as r,Te as s,_ as t,Rt as u,wt as v,ne as w,Ct as x,St as y,Dt as z,It as A,jt as B,Et as C,At as D,F as E,Lt as F,me as G,Nt as H,_t as I,Y as J,it as K,at as L,ct as M,Q as N,Z as O,pt as P,ut as Q,ee as R,gt as S,dt as T,mt as U};
|
|
3
|
+
//# sourceMappingURL=chunk-X2L4F2VM.js.map
|