@fluid-app/fluid-cli-mist 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["STATE_COLOR","POLL_MS","sleep","path"],"sources":["../src/api/client.ts","../src/api/id-resolver.ts","../src/api/mists.ts","../src/lib/hostable.ts","../src/lib/slug-resolver.ts","../src/lib/error-handler.ts","../src/lib/output.ts","../src/commands/list.ts","../src/commands/show.ts","../src/commands/create.ts","../src/commands/update.ts","../src/commands/delete.ts","../src/commands/restore.ts","../src/api/git_credential.ts","../src/lib/git.ts","../src/commands/clone.ts","../src/api/deployments.ts","../src/api/me.ts","../src/commands/push.ts","../src/commands/pull.ts","../src/commands/open.ts","../src/commands/deployments.ts","../src/api/logs.ts","../src/commands/logs.ts","../src/api/env_vars.ts","../src/commands/env/list.ts","../src/commands/env/set.ts","../src/commands/env/unset.ts","../src/commands/env/pull.ts","../src/commands/env/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Generic fetch wrapper for the Mist Rails API.\n *\n * Spec: `features/mist/cli-spec.md` §4.\n * - Base URL: `https://api.fluid.app` (overridable via FLUID_API_BASE)\n * - Auth: `Authorization: Bearer <token>` from the standard fluid-cli token\n * store; the host CLI's PluginContext provides `getAuthToken()`.\n * - Errors: maps API responses to a typed `MistApiError` that the\n * error-handler turns into the spec's exit codes (1/2/3/4).\n */\n\nimport { getAuthToken } from \"@fluid-app/fluid-cli\";\n\nconst DEFAULT_BASE = \"https://api.fluid.app\";\n\nexport interface MistApiErrorBody {\n error?: {\n message?: string;\n details?: Record<string, unknown>;\n };\n status?: number;\n}\n\nexport class MistApiError extends Error {\n /** HTTP status, or 0 for network-level failures. */\n readonly status: number;\n readonly details: Record<string, unknown> | undefined;\n /** Best-guess exit code per the spec: 2 for 4xx, 3 for 5xx/vendor, 4 for net. */\n readonly exitCode: 2 | 3 | 4;\n\n constructor(\n message: string,\n status: number,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = \"MistApiError\";\n this.status = status;\n this.details = details;\n if (status === 0) this.exitCode = 4;\n else if (status >= 500) this.exitCode = 3;\n else this.exitCode = 2;\n }\n}\n\nfunction apiBase(): string {\n return process.env[\"FLUID_API_BASE\"] ?? DEFAULT_BASE;\n}\n\nexport interface MistClient {\n get<T>(path: string, query?: Record<string, unknown>): Promise<T>;\n post<T>(path: string, body?: unknown): Promise<T>;\n patch<T>(path: string, body?: unknown): Promise<T>;\n delete<T>(path: string, body?: unknown): Promise<T>;\n /** Raw `fetch` for streaming endpoints (logs polling). */\n request(path: string, init?: RequestInit): Promise<Response>;\n}\n\n/** Build a typed Mist API client. Throws if the user isn't logged in. */\nexport function createMistClient(): MistClient {\n const token = getAuthToken();\n if (!token) {\n throw new MistApiError(\n \"No active Fluid session — run `fluid login` first.\",\n 401,\n );\n }\n const base = apiBase();\n\n function buildUrl(path: string, query?: Record<string, unknown>): string {\n const url = new URL(path.startsWith(\"/\") ? path : `/${path}`, base);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v == null) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n }\n\n async function call<T>(\n method: string,\n path: string,\n opts?: { body?: unknown; query?: Record<string, unknown> },\n ): Promise<T> {\n const url = buildUrl(path, opts?.query);\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n ...(opts?.body !== undefined\n ? { \"Content-Type\": \"application/json\" }\n : {}),\n },\n ...(opts?.body !== undefined\n ? { body: JSON.stringify(opts.body) }\n : {}),\n });\n } catch (err) {\n throw new MistApiError(\n `Network error: ${err instanceof Error ? err.message : String(err)}`,\n 0,\n );\n }\n\n // 204 No Content\n if (response.status === 204) return undefined as T;\n\n const text = await response.text();\n let parsed: unknown;\n try {\n parsed = text.length > 0 ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body — treat as opaque error if non-2xx.\n if (!response.ok) {\n throw new MistApiError(\n `HTTP ${response.status}: ${text.slice(0, 200)}`,\n response.status,\n );\n }\n return undefined as T;\n }\n\n if (!response.ok) {\n const body = parsed as MistApiErrorBody;\n const message = body.error?.message ?? `HTTP ${response.status}`;\n throw new MistApiError(message, response.status, body.error?.details);\n }\n return parsed as T;\n }\n\n return {\n get: (path, query) => call(\"GET\", path, { query }),\n post: (path, body) => call(\"POST\", path, { body }),\n patch: (path, body) => call(\"PATCH\", path, { body }),\n delete: (path, body) =>\n call(\"DELETE\", path, body !== undefined ? { body } : undefined),\n async request(path, init) {\n const url = buildUrl(path);\n return fetch(url, {\n ...init,\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n ...(init?.headers ?? {}),\n },\n });\n },\n };\n}\n","/**\n * Slug → UUID id resolver.\n *\n * Despite the spec describing `/api/v202604/mists/:id` as accepting the\n * 6-char slug, the Rails route only accepts the UUID `id`. Every command\n * the user invokes (`show`, `delete`, `restore`, `clone`, `push`, `env *`,\n * `deployments`, `logs`) takes a slug and would otherwise 404. We hide\n * the lookup here so the API surface (`showMist`, `deleteMist`, etc.)\n * keeps accepting `slug` strings — they internally call this resolver\n * once and use the returned UUID.\n *\n * The cache is process-local; one terminal invocation hits the list\n * endpoint at most once.\n */\n\nimport type { MistClient } from \"./client.js\";\nimport type { MistListResponse } from \"../types.js\";\n\n// We deliberately don't import listMists from ./mists here — that\n// would create a cycle (mists.ts imports resolveMistId from this\n// file). Instead, hit the same endpoint directly. Kept private to\n// this module since it's just the cycle-breaker.\nconst MISTS_BASE = \"/api/v202604/mists\";\nfunction listMistsForResolve(\n client: MistClient,\n params: { limit?: number } = {},\n): Promise<MistListResponse> {\n return client.get<MistListResponse>(\n MISTS_BASE,\n params as Record<string, unknown>,\n );\n}\n\nconst cache = new Map<string, string>();\n\nconst UUID_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Returns true if the input already looks like a UUID we can use as-is. */\nfunction isUuid(s: string): boolean {\n return UUID_REGEX.test(s.trim());\n}\n\n/**\n * Resolve a user-supplied slug-or-id to the API's canonical UUID id.\n * No-op when the input already looks like a UUID.\n */\nexport async function resolveMistId(\n client: MistClient,\n slugOrId: string,\n): Promise<string> {\n const key = slugOrId.trim();\n if (!key) throw new Error(\"Empty mist identifier.\");\n if (isUuid(key)) return key;\n const hit = cache.get(key);\n if (hit) return hit;\n // The slug isn't a UUID — look it up via the list endpoint. limit=100\n // covers the vast majority of users; if the user has more than 100\n // mists and the one they want isn't on page 1, we'd need to paginate.\n // For now we keep it cheap and accept that pagination is a follow-up.\n const response = await listMistsForResolve(client, { limit: 100 });\n for (const m of response.mists ?? []) {\n if (m.slug) cache.set(m.slug, m.id);\n }\n const found = cache.get(key);\n if (!found) {\n throw new Error(\n `No mist found with slug \"${key}\". Try \\`fluid mist list\\` to see what's available.`,\n );\n }\n return found;\n}\n","/**\n * Mist CRUD over `/api/v202604/mists`. Mirrors the spec's endpoint table\n * one-for-one — no business logic.\n */\n\nimport type { MistClient } from \"./client.js\";\nimport type {\n MistCreateRequest,\n MistListResponse,\n MistShowResponse,\n MistUpdateRequest,\n} from \"../types.js\";\nimport { resolveMistId } from \"./id-resolver.js\";\n\nconst BASE = \"/api/v202604/mists\";\n\nexport interface ListMistsParams {\n state?: \"live\" | \"provisioning\" | \"failed\" | \"pending_destroy\" | \"archived\";\n kind?: \"next_app\";\n limit?: number;\n cursor?: string;\n}\n\nexport function listMists(\n client: MistClient,\n params: ListMistsParams = {},\n): Promise<MistListResponse> {\n return client.get<MistListResponse>(BASE, params as Record<string, unknown>);\n}\n\nexport async function showMist(\n client: MistClient,\n slug: string,\n): Promise<MistShowResponse> {\n const id = await resolveMistId(client, slug);\n return client.get<MistShowResponse>(`${BASE}/${id}`);\n}\n\nexport function createMist(\n client: MistClient,\n body: MistCreateRequest,\n): Promise<MistShowResponse> {\n return client.post<MistShowResponse>(BASE, body);\n}\n\nexport async function updateMist(\n client: MistClient,\n slug: string,\n body: MistUpdateRequest,\n): Promise<MistShowResponse> {\n const id = await resolveMistId(client, slug);\n return client.patch<MistShowResponse>(`${BASE}/${id}`, body);\n}\n\nexport async function deleteMist(\n client: MistClient,\n slug: string,\n): Promise<MistShowResponse> {\n const id = await resolveMistId(client, slug);\n return client.delete<MistShowResponse>(`${BASE}/${id}`);\n}\n\nexport async function restoreMist(\n client: MistClient,\n slug: string,\n): Promise<MistShowResponse> {\n const id = await resolveMistId(client, slug);\n return client.post<MistShowResponse>(`${BASE}/${id}/restore`);\n}\n","/**\n * Hostable reference parser. Accepts `<type>:<id>` shorthand and maps the\n * type half to the canonical Rails class name the API expects.\n *\n * Wire mapping (spec table):\n * droplet → Droplet::Application\n * mobile_widget → MobileWidget\n * drop_zone → DropZone\n *\n * The shorthand is forgiving (case-insensitive, accepts dashes or\n * underscores), but the output is exact so the Rails `included_in?`\n * check accepts it.\n */\n\nimport type { HostableType } from \"../types.js\";\n\nconst SHORTHAND: Record<string, HostableType> = {\n droplet: \"Droplet::Application\",\n droplets: \"Droplet::Application\",\n mobile_widget: \"MobileWidget\",\n \"mobile-widget\": \"MobileWidget\",\n mobilewidget: \"MobileWidget\",\n widget: \"MobileWidget\",\n drop_zone: \"DropZone\",\n \"drop-zone\": \"DropZone\",\n dropzone: \"DropZone\",\n};\n\n/** Friendly label for help text + error output. */\nexport const SHORTHAND_LIST = \"droplet, mobile_widget, drop_zone\";\n\nexport class HostableParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"HostableParseError\";\n }\n}\n\nexport interface HostablePair {\n hostable_type: HostableType;\n hostable_id: number;\n}\n\n/**\n * Parse a `<type>:<id>` shorthand, or accept already-canonical\n * `Droplet::Application:42` if the user prefers the Rails-style form.\n */\nexport function parseHostableRef(raw: string): HostablePair {\n const trimmed = raw.trim();\n if (!trimmed) {\n throw new HostableParseError(\n `Empty hostable reference. Use <type>:<id> where <type> is one of ${SHORTHAND_LIST}.`,\n );\n }\n // Split on the LAST colon so `Droplet::Application:42` still works.\n const lastColon = trimmed.lastIndexOf(\":\");\n if (lastColon <= 0 || lastColon === trimmed.length - 1) {\n throw new HostableParseError(\n `Invalid hostable reference \"${raw}\". Expected <type>:<id>, e.g. droplet:42.`,\n );\n }\n const typePart = trimmed.slice(0, lastColon).trim();\n const idPart = trimmed.slice(lastColon + 1).trim();\n const id = Number(idPart);\n if (!Number.isInteger(id) || id <= 0) {\n throw new HostableParseError(\n `Invalid hostable id \"${idPart}\". Must be a positive integer.`,\n );\n }\n const canonical = canonicalizeHostableType(typePart);\n return { hostable_type: canonical, hostable_id: id };\n}\n\n/** Map an input string to the canonical Rails class name, throwing on miss. */\nexport function canonicalizeHostableType(typePart: string): HostableType {\n const exact: HostableType[] = [\n \"Droplet::Application\",\n \"MobileWidget\",\n \"DropZone\",\n ];\n if (exact.includes(typePart as HostableType)) return typePart as HostableType;\n const looked = SHORTHAND[typePart.toLowerCase().replace(/\\s+/g, \"\")];\n if (looked) return looked;\n throw new HostableParseError(\n `Unknown hostable type \"${typePart}\". Use one of: ${SHORTHAND_LIST}.`,\n );\n}\n","/**\n * Slug resolution — spec §3 conventions:\n * 1. If a slug arg is passed, use it.\n * 2. Otherwise look for a `.mist` file in CWD (written by `fluid mist\n * clone`) and use the slug from it.\n * 3. Otherwise error: tell the user to pass a slug or cd into a cloned dir.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Mist, MistFile } from \"../types.js\";\n\nconst MIST_FILE = \".mist\";\n\nexport class SlugResolutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SlugResolutionError\";\n }\n}\n\nfunction readMistFile(dir: string): MistFile | null {\n const filePath = join(dir, MIST_FILE);\n if (!existsSync(filePath)) return null;\n try {\n const raw = readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\") return null;\n const obj = parsed as Record<string, unknown>;\n if (typeof obj[\"slug\"] !== \"string\") return null;\n return {\n slug: obj[\"slug\"] as string,\n vendor_name:\n typeof obj[\"vendor_name\"] === \"string\"\n ? (obj[\"vendor_name\"] as string)\n : \"\",\n public_url:\n typeof obj[\"public_url\"] === \"string\"\n ? (obj[\"public_url\"] as string)\n : null,\n };\n } catch {\n return null;\n }\n}\n\n/** Returns the slug from arg or `.mist` file; throws if neither is present. */\nexport function resolveSlug(arg?: string, cwd: string = process.cwd()): string {\n if (arg && arg.trim().length > 0) return arg.trim();\n const file = readMistFile(cwd);\n if (file) return file.slug;\n throw new SlugResolutionError(\n \"No slug provided and no `.mist` file in this directory. Pass the slug as an argument or cd into a cloned mist.\",\n );\n}\n\n/** Write a `.mist` file after `fluid mist clone`. */\nexport function writeMistFile(dir: string, mist: Mist): void {\n const payload: MistFile = {\n slug: mist.slug,\n vendor_name: mist.vendor_name,\n public_url: mist.public_url,\n };\n writeFileSync(\n join(dir, MIST_FILE),\n JSON.stringify(payload, null, 2) + \"\\n\",\n \"utf8\",\n );\n}\n\nexport function readMistFileFrom(dir: string = process.cwd()): MistFile | null {\n return readMistFile(dir);\n}\n","/**\n * Centralized error handling — maps thrown errors to spec'd exit codes\n * and friendly messages. Imported by every command's `.action()` so each\n * file doesn't repeat the same try/catch.\n *\n * Exit codes (spec §3 \"Conventions\"):\n * 0 success | 1 user error | 2 API 4xx | 3 API 5xx / vendor | 4 network\n */\n\nimport chalk from \"chalk\";\nimport { MistApiError } from \"../api/client.js\";\nimport { HostableParseError } from \"./hostable.js\";\nimport { SlugResolutionError } from \"./slug-resolver.js\";\n\n/** Run an async action and translate failures into pretty output + exit. */\nexport async function runAction(fn: () => Promise<void> | void): Promise<void> {\n try {\n await fn();\n } catch (err) {\n handle(err);\n }\n}\n\nfunction handle(err: unknown): never {\n if (err instanceof SlugResolutionError) {\n console.error(chalk.red(err.message));\n process.exit(1);\n }\n if (err instanceof HostableParseError) {\n console.error(chalk.red(err.message));\n process.exit(1);\n }\n if (err instanceof MistApiError) {\n // Friendlier messages for the well-known cases from the spec.\n if (err.status === 403) {\n const action = err.details?.[\"permission\"];\n console.error(\n chalk.red(\n action\n ? `Your role doesn't include \\`mist.${String(action)}\\` — ask your Fluid admin to grant it.`\n : err.message,\n ),\n );\n } else if (err.status === 409) {\n const date = err.details?.[\"scheduled_destroy_at\"];\n console.error(\n chalk.yellow(\n typeof date === \"string\"\n ? `This mist is scheduled for destruction on ${date.slice(0, 10)}. Run \\`fluid mist restore <slug>\\` first.`\n : err.message,\n ),\n );\n } else if (err.status === 422) {\n // Hostable-related 422s come back with structured `details` per the\n // spec. Surface them as a one-line hint above the raw API message.\n const details = err.details ?? {};\n const idErrors = details[\"hostable_id\"];\n if (\n Array.isArray(idErrors) &&\n idErrors.some((e) => /already taken/i.test(String(e)))\n ) {\n console.error(\n chalk.yellow(\n \"That hostable is already attached to another mist. Detach it first or pick a different one.\",\n ),\n );\n } else if (\n typeof err.message === \"string\" &&\n /hostable_type and hostable_id/.test(err.message)\n ) {\n console.error(\n chalk.yellow(\n \"Pass `--hostable <type>:<id>` (or both `--hostable-type` and `--hostable-id`).\",\n ),\n );\n } else if (\n typeof err.message === \"string\" &&\n /Hostable not found/.test(err.message)\n ) {\n const t = details[\"hostable_type\"];\n const id = details[\"hostable_id\"];\n console.error(\n chalk.yellow(\n `Couldn't find ${typeof t === \"string\" ? t : \"hostable\"}${id != null ? ` #${String(id)}` : \"\"} in this company.`,\n ),\n );\n } else {\n console.error(chalk.red(err.message));\n }\n } else if (err.status === 410) {\n console.error(\n chalk.red(\n \"Grace period expired — vendor teardown is in flight. Create a fresh mist with `fluid mist create`.\",\n ),\n );\n } else {\n console.error(chalk.red(err.message));\n }\n process.exit(err.exitCode);\n }\n // Unknown — print and exit 1 (user/programmer error)\n if (err instanceof Error) {\n console.error(chalk.red(err.message));\n } else {\n console.error(chalk.red(String(err)));\n }\n process.exit(1);\n}\n","/**\n * Output helpers — human-readable by default, `--json` emits raw API\n * payload. NO_COLOR respected via chalk's built-in detection.\n */\n\nimport chalk from \"chalk\";\nimport type { Mist } from \"../types.js\";\n\nexport function printJson(payload: unknown): void {\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\");\n}\n\nconst STATE_COLOR: Record<Mist[\"state\"], (s: string) => string> = {\n pending: chalk.gray,\n provisioning: chalk.yellow,\n live: chalk.green,\n failed: chalk.red,\n pending_destroy: chalk.magenta,\n archived: chalk.dim,\n};\n\nexport function colorState(state: Mist[\"state\"]): string {\n return STATE_COLOR[state](state);\n}\n\n/** Pad columns to width — cheap manual table; avoids cli-table3 dep for v1. */\nexport function printTable(rows: string[][]): void {\n if (rows.length === 0) return;\n const widths: number[] = [];\n for (const row of rows) {\n row.forEach((cell, i) => {\n const visible = stripAnsi(cell).length;\n widths[i] = Math.max(widths[i] ?? 0, visible);\n });\n }\n for (const row of rows) {\n const padded = row.map((cell, i) => {\n const w = widths[i] ?? 0;\n return cell + \" \".repeat(Math.max(0, w - stripAnsi(cell).length));\n });\n process.stdout.write(padded.join(\" \") + \"\\n\");\n }\n}\n\n// Chalk respects NO_COLOR, but our padding math needs the visible length —\n// strip ANSI escape sequences for measurement only.\nfunction stripAnsi(s: string): string {\n // eslint-disable-next-line no-control-regex\n return s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\nexport function relativeDate(iso: string | null): string {\n if (!iso) return \"—\";\n const diff = Date.now() - new Date(iso).getTime();\n const minutes = Math.floor(diff / 60_000);\n if (minutes < 1) return \"just now\";\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n return new Date(iso).toISOString().slice(0, 10);\n}\n\n/** Human-friendly absolute date for one-off prints (scheduled_destroy_at). */\nexport function formatAbsolute(iso: string): string {\n const d = new Date(iso);\n return d.toISOString().slice(0, 10);\n}\n","/** `fluid mist list` — GET /mists with optional filters. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { listMists, type ListMistsParams } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport {\n colorState,\n printJson,\n printTable,\n relativeDate,\n} from \"../lib/output.js\";\n\ninterface Opts {\n state?: ListMistsParams[\"state\"];\n kind?: ListMistsParams[\"kind\"];\n limit?: string;\n json?: boolean;\n}\n\nexport const listCommand = new Command(\"list\")\n .description(\"List the mists you have access to\")\n .option(\n \"--state <state>\",\n \"Filter by state: live | provisioning | failed | pending_destroy | archived\",\n )\n .option(\"--kind <kind>\", \"Filter by kind (default: next_app)\")\n .option(\"--limit <n>\", \"Page size 1..100 (default 25)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((opts: Opts) =>\n runAction(async () => {\n const client = createMistClient();\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n const response = await listMists(client, {\n ...(opts.state ? { state: opts.state } : {}),\n ...(opts.kind ? { kind: opts.kind } : {}),\n ...(limit && Number.isFinite(limit) ? { limit } : {}),\n });\n if (opts.json) return printJson(response);\n const mists = response.mists ?? [];\n if (mists.length === 0) {\n console.log(chalk.dim(\"No mists found.\"));\n return;\n }\n const header = [\n chalk.bold(\"SLUG\"),\n chalk.bold(\"NAME\"),\n chalk.bold(\"STATE\"),\n chalk.bold(\"ATTACHED\"),\n chalk.bold(\"UPDATED\"),\n ];\n const rows = mists.map((m) => [\n m.slug,\n m.name ?? m.droplet?.name ?? m.vendor_name,\n colorState(m.state),\n m.hostable_type ?? chalk.dim(\"standalone\"),\n relativeDate(m.updated_at),\n ]);\n printTable([header, ...rows]);\n }),\n );\n","/** `fluid mist show <slug>` — single mist detail. Surfaces\n * scheduled_destroy_at when state is pending_destroy. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { showMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport {\n colorState,\n formatAbsolute,\n printJson,\n relativeDate,\n} from \"../lib/output.js\";\n\ninterface Opts {\n json?: boolean;\n}\n\nexport const showCommand = new Command(\"show\")\n .description(\"Show one mist by slug\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const { mist } = await showMist(client, resolved);\n if (opts.json) return printJson({ mist });\n const lines: string[] = [];\n const label = mist.name ?? mist.droplet?.name ?? mist.vendor_name;\n lines.push(`${chalk.bold(label)} ${chalk.dim(mist.slug)}`);\n if (mist.name && mist.name !== mist.vendor_name) {\n lines.push(` vendor ${chalk.dim(mist.vendor_name)}`);\n }\n lines.push(` state ${colorState(mist.state)}`);\n if (mist.kind) lines.push(` kind ${mist.kind}`);\n if (mist.public_url)\n lines.push(` url ${chalk.cyan(mist.public_url)}`);\n if (mist.hostable_type) lines.push(` attached ${mist.hostable_type}`);\n if (mist.droplet)\n lines.push(` droplet ${mist.droplet.name} (#${mist.droplet.id})`);\n if (mist.provisioned_at)\n lines.push(` live ${relativeDate(mist.provisioned_at)}`);\n lines.push(` updated ${relativeDate(mist.updated_at)}`);\n if (mist.scheduled_destroy_at) {\n lines.push(\n chalk.magenta(\n ` destroy scheduled ${formatAbsolute(mist.scheduled_destroy_at)} (run \\`fluid mist restore ${mist.slug}\\` to undo)`,\n ),\n );\n }\n console.log(lines.join(\"\\n\"));\n }),\n );\n","/**\n * `fluid mist create` — POST /mists. Synchronous; 30–60s.\n *\n * Updated for `fluid` PR #18678: the API no longer creates Droplets inline.\n * Pass an existing hostable via `--hostable <type>:<id>` (shorthand) or the\n * pair `--hostable-type` / `--hostable-id`. Optional `--name <label>` sets\n * the display label; if blank, the API falls back to the hostable's name.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { createMistClient } from \"../api/client.js\";\nimport { createMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { colorState, printJson } from \"../lib/output.js\";\nimport {\n canonicalizeHostableType,\n parseHostableRef,\n SHORTHAND_LIST,\n} from \"../lib/hostable.js\";\nimport type { HostableType, MistCreateRequest } from \"../types.js\";\n\ninterface Opts {\n name?: string;\n hostable?: string;\n hostableType?: string;\n hostableId?: string;\n kind?: \"next_app\";\n json?: boolean;\n}\n\nexport const createCommand = new Command(\"create\")\n .description(\n `Provision a new mist (optionally attached to an existing hostable: ${SHORTHAND_LIST})`,\n )\n .option(\n \"--hostable <ref>\",\n \"Attach to an existing hostable. Shorthand: <type>:<id> (e.g. droplet:42)\",\n )\n .option(\n \"--hostable-type <type>\",\n `Hostable type when not using shorthand (${SHORTHAND_LIST})`,\n )\n .option(\"--hostable-id <id>\", \"Hostable id when not using shorthand\")\n .option(\n \"--name <label>\",\n \"Optional display label (defaults to hostable name)\",\n )\n .option(\"--kind <kind>\", \"Mist kind (default: next_app)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((opts: Opts) =>\n runAction(async () => {\n const mist: MistCreateRequest[\"mist\"] = {};\n if (opts.kind) mist.kind = opts.kind;\n if (opts.name?.trim()) mist.name = opts.name.trim();\n\n // Resolve hostable pair. Either --hostable shorthand, OR both\n // --hostable-type + --hostable-id, OR neither (standalone).\n const hasShorthand = !!opts.hostable;\n const hasPair = !!opts.hostableType || !!opts.hostableId;\n if (hasShorthand && hasPair) {\n throw new Error(\n \"Use either `--hostable <type>:<id>` OR `--hostable-type` + `--hostable-id`, not both.\",\n );\n }\n if (hasShorthand) {\n const pair = parseHostableRef(opts.hostable!);\n mist.hostable_type = pair.hostable_type;\n mist.hostable_id = pair.hostable_id;\n } else if (hasPair) {\n if (!opts.hostableType || !opts.hostableId) {\n throw new Error(\n \"`--hostable-type` and `--hostable-id` must be passed together.\",\n );\n }\n const id = Number(opts.hostableId);\n if (!Number.isInteger(id) || id <= 0) {\n throw new Error(\n `Invalid --hostable-id \"${opts.hostableId}\". Must be a positive integer.`,\n );\n }\n mist.hostable_type = canonicalizeHostableType(opts.hostableType);\n mist.hostable_id = id;\n }\n\n const client = createMistClient();\n const spinner = ora(\"Setting up your Mist Cloud environment…\").start();\n try {\n const response = await createMist(client, { mist });\n spinner.succeed(\"Provisioned\");\n if (opts.json) return printJson(response);\n const m = response.mist;\n console.log();\n const label = m.name ?? m.droplet?.name ?? m.vendor_name;\n console.log(\n `${chalk.bold(label)} ${chalk.dim(m.slug)} ${colorState(m.state)}`,\n );\n if (m.public_url) console.log(` ${chalk.cyan(m.public_url)}`);\n if (m.hostable_type && m.hostable_id != null) {\n console.log(\n chalk.dim(` attached: ${m.hostable_type} #${m.hostable_id}`),\n );\n }\n console.log();\n console.log(chalk.dim(`Clone with: fluid mist clone ${m.slug}`));\n } catch (err) {\n spinner.fail(\"Provisioning failed\");\n throw err;\n }\n }),\n );\n\n// re-export the type so future callers can introspect without reaching into\n// the impl (unused now but cheap to expose).\nexport type { HostableType };\n","/**\n * `fluid mist update` — PATCH /mists/:id. Covers three operations on one\n * endpoint:\n *\n * - Rename: --name <label>\n * - Attach: --hostable <type>:<id>\n * - Detach: --detach (sends explicit nulls for both keys)\n *\n * `--hostable` and `--detach` are mutually exclusive at the CLI surface so\n * the user can't accidentally express contradictory intent. The wire-level\n * rule (both keys must be paired or both null) is enforced server-side.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { updateMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { parseHostableRef, SHORTHAND_LIST } from \"../lib/hostable.js\";\nimport { colorState, printJson } from \"../lib/output.js\";\nimport type { MistUpdateRequest } from \"../types.js\";\n\ninterface Opts {\n name?: string;\n hostable?: string;\n detach?: boolean;\n json?: boolean;\n}\n\nexport const updateCommand = new Command(\"update\")\n .description(\"Rename a mist, attach/replace a hostable, or detach one\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--name <label>\", \"Set the display label\")\n .option(\n \"--hostable <ref>\",\n `Attach or replace the hostable. Shorthand: <type>:<id> (${SHORTHAND_LIST})`,\n )\n .option(\"--detach\", \"Detach the hostable (sends explicit nulls)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n if (opts.hostable && opts.detach) {\n throw new Error(\n \"Pass either `--hostable` OR `--detach`, not both — they're mutually exclusive.\",\n );\n }\n if (!opts.name && !opts.hostable && !opts.detach) {\n throw new Error(\n \"Nothing to do — pass at least one of `--name`, `--hostable`, or `--detach`.\",\n );\n }\n\n const body: MistUpdateRequest = { mist: {} };\n if (opts.name?.trim()) body.mist.name = opts.name.trim();\n if (opts.hostable) {\n const pair = parseHostableRef(opts.hostable);\n body.mist.hostable_type = pair.hostable_type;\n body.mist.hostable_id = pair.hostable_id;\n }\n if (opts.detach) {\n // Explicit nulls — `maybe(...)` on the Rails schema requires the\n // keys to be present-with-null, not absent.\n body.mist.hostable_type = null;\n body.mist.hostable_id = null;\n }\n\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const response = await updateMist(client, resolved, body);\n if (opts.json) return printJson(response);\n\n const m = response.mist;\n const label = m.name ?? m.droplet?.name ?? m.vendor_name;\n console.log(\n `${chalk.bold(label)} ${chalk.dim(m.slug)} ${colorState(m.state)}`,\n );\n if (m.hostable_type && m.hostable_id != null) {\n console.log(\n chalk.dim(` attached: ${m.hostable_type} #${m.hostable_id}`),\n );\n } else {\n console.log(chalk.dim(` standalone (no hostable)`));\n }\n }),\n );\n","/**\n * `fluid mist delete` — scheduled teardown 15 days out (spec §3 \"15-day\n * grace period\"). DO NOT poll for completion.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport prompts from \"prompts\";\nimport { createMistClient } from \"../api/client.js\";\nimport { deleteMist, showMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { formatAbsolute, printJson } from \"../lib/output.js\";\n\ninterface Opts {\n yes?: boolean;\n json?: boolean;\n}\n\nexport const deleteCommand = new Command(\"delete\")\n .description(\"Schedule a mist for destruction (15-day grace window)\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n\n if (!opts.yes) {\n // Fetch first so the prompt shows what's about to happen.\n const { mist } = await showMist(client, resolved);\n const fifteenDaysOut = new Date(Date.now() + 15 * 86_400_000)\n .toISOString()\n .slice(0, 10);\n console.log();\n console.log(\n `About to schedule ${chalk.bold(mist.vendor_name)} (${chalk.dim(mist.slug)}) for destruction on ${chalk.yellow(fifteenDaysOut)}.`,\n );\n console.log(\n chalk.dim(\n `Vendor resources stay alive until then; run \\`fluid mist restore ${mist.slug}\\` to undo.`,\n ),\n );\n const { confirmed } = await prompts(\n {\n type: \"confirm\",\n name: \"confirmed\",\n message: \"Continue?\",\n initial: false,\n },\n { onCancel: () => process.exit(130) },\n );\n if (!confirmed) {\n console.log(chalk.dim(\"Aborted.\"));\n process.exit(0);\n }\n }\n\n const { mist } = await deleteMist(client, resolved);\n if (opts.json) return printJson({ mist });\n console.log(\n chalk.magenta(\n `Scheduled for destruction on ${mist.scheduled_destroy_at ? formatAbsolute(mist.scheduled_destroy_at) : \"the 15-day mark\"}.`,\n ),\n );\n console.log(\n chalk.dim(\n `Vendor resources stay alive until then; run \\`fluid mist restore ${mist.slug}\\` to undo.`,\n ),\n );\n }),\n );\n","/** `fluid mist restore` — un-delete within the 15-day window. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { restoreMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { colorState, printJson } from \"../lib/output.js\";\n\ninterface Opts {\n json?: boolean;\n}\n\nexport const restoreCommand = new Command(\"restore\")\n .description(\"Cancel a scheduled mist destruction (15-day window)\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const { mist } = await restoreMist(client, resolved);\n if (opts.json) return printJson({ mist });\n console.log(\n `Restored: ${mist.public_url ? chalk.cyan(mist.public_url) : mist.vendor_name} (${colorState(mist.state)})`,\n );\n }),\n );\n","/**\n * `POST /git_credential` — mints a short-lived (~1h) remote URL with an\n * embedded installation token. The CLI calls this immediately before any\n * git op and discards the URL after. NEVER persist it.\n */\n\nimport type { MistClient } from \"./client.js\";\nimport type { GitCredentialResponse } from \"../types.js\";\nimport { resolveMistId } from \"./id-resolver.js\";\n\nexport async function createGitCredential(\n client: MistClient,\n slug: string,\n): Promise<GitCredentialResponse> {\n const id = await resolveMistId(client, slug);\n return client.post<GitCredentialResponse>(\n `/api/v202604/mists/${id}/git_credential`,\n );\n}\n","/**\n * Git wrapper — shells out to system `git` via execa. Spec §11.1: we\n * deliberately do NOT bundle git or use a pure-JS impl; users are expected\n * to have it installed.\n *\n * Security: token-bearing `remote_url` from POST /git_credential must never\n * be logged, persisted, *or* exposed in the process table. The token is\n * stripped from the URL and handed to git through a GIT_ASKPASS script via\n * env vars (MIST_GIT_USER / MIST_GIT_PASS) — so it never appears in argv\n * (visible to `ps aux` on macOS, `/proc/<pid>/cmdline` on Linux) and is\n * never written to `.git/config`.\n */\n\nimport { chmodSync, existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { execa, type ExecaError } from \"execa\";\n\nexport class GitError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"GitError\";\n this.exitCode = exitCode;\n }\n}\n\n/** execa throws ENOENT when the git binary itself is missing — the\n * single most common failure on non-developer machines. Translate it\n * into an actionable message instead of \"git <verb> failed (exit 1)\".\n * Returns null for every other failure so call sites keep their\n * specific messages. */\nfunction gitMissingError(err: unknown): GitError | null {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code !== \"ENOENT\") return null;\n return new GitError(\n \"Git isn't installed on this machine. In Mist Desktop, use the Install button in the yellow banner at the top of the app. From a terminal: macOS `xcode-select --install`, or download from https://git-scm.com/downloads.\",\n 127,\n );\n}\n\n/**\n * Split a token-bearing remote URL into the userless URL + creds. Used\n * to keep the token off git's argv: we pass `cleanUrl` to git and feed\n * `username` / `password` back through GIT_ASKPASS env vars.\n *\n * If the URL has no embedded credentials, returns empty strings — fine\n * for public repos where git won't even invoke askpass.\n */\nfunction splitRemoteCredentials(remoteUrl: string): {\n cleanUrl: string;\n username: string;\n password: string;\n} {\n const u = new URL(remoteUrl);\n const username = decodeURIComponent(u.username);\n const password = decodeURIComponent(u.password);\n u.username = \"\";\n u.password = \"\";\n return { cleanUrl: u.toString(), username, password };\n}\n\n/**\n * Write a stub GIT_ASKPASS script (shell on POSIX, .cmd on Windows) to\n * a per-process tmpdir and return its path. The script itself contains\n * no secret — it just echoes back whichever env var (MIST_GIT_USER /\n * MIST_GIT_PASS) matches git's prompt (\"Username for …\" / \"Password\n * for …\"). The credentials only live in the spawned git process's env\n * for the duration of the call.\n *\n * Idempotent: subsequent calls reuse the same script path.\n */\nlet askpassPath: string | null = null;\nfunction ensureAskpassScript(): string {\n if (askpassPath && existsSync(askpassPath)) return askpassPath;\n const dir = path.join(os.tmpdir(), `mist-cli-askpass-${process.pid}`);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n if (process.platform === \"win32\") {\n const p = path.join(dir, \"askpass.cmd\");\n // Git on Windows passes the prompt as the first arg. Detect\n // \"Username\" vs anything-else (Password) by the first letter; the\n // `<nul set /p=` trick prints the env value without a trailing\n // newline (git is picky about trailing whitespace on creds).\n writeFileSync(\n p,\n `@echo off\\r\\nset \"p=%~1\"\\r\\nif /i \"%p:~0,1%\"==\"U\" (<nul set /p=%MIST_GIT_USER%) else (<nul set /p=%MIST_GIT_PASS%)\\r\\n`,\n );\n askpassPath = p;\n } else {\n const p = path.join(dir, \"askpass.sh\");\n writeFileSync(\n p,\n `#!/bin/sh\\ncase \"$1\" in\\n Username*) printf '%s' \"$MIST_GIT_USER\" ;;\\n *) printf '%s' \"$MIST_GIT_PASS\" ;;\\nesac\\n`,\n { mode: 0o700 },\n );\n chmodSync(p, 0o700);\n askpassPath = p;\n }\n return askpassPath;\n}\n\n/**\n * Build the spawn env + cleaned URL for a credentialed git invocation.\n * Returns:\n * - `cleanUrl`: URL with userinfo stripped — safe to pass as argv.\n * - `env`: parent env plus GIT_ASKPASS + MIST_GIT_USER / MIST_GIT_PASS.\n * GIT_TERMINAL_PROMPT=0 prevents the TTY-prompt fallback if\n * the credentials are empty (we want auth to fail fast, not\n * hang the desktop waiting for interactive input).\n */\nfunction gitAuthSpawn(remoteUrl: string): {\n cleanUrl: string;\n env: NodeJS.ProcessEnv;\n} {\n const { cleanUrl, username, password } = splitRemoteCredentials(remoteUrl);\n return {\n cleanUrl,\n env: {\n ...process.env,\n GIT_ASKPASS: ensureAskpassScript(),\n GIT_TERMINAL_PROMPT: \"0\",\n MIST_GIT_USER: username,\n MIST_GIT_PASS: password,\n },\n };\n}\n\n/** Confirm git is installed. Cheap call once at startup. */\nexport async function ensureGitAvailable(): Promise<void> {\n try {\n await execa(\"git\", [\"--version\"]);\n } catch {\n throw new GitError(\n \"`git` is required but not found on your PATH. Install it from https://git-scm.com/downloads or via `brew install git`.\",\n );\n }\n}\n\n/**\n * `git clone <cleanUrl> <targetDir>`. The original remoteUrl carries a\n * token; gitAuthSpawn strips it from the URL and re-injects it via\n * GIT_ASKPASS so it never appears in argv. `credential.helper=` stops\n * git from caching what askpass returned to any system credential\n * store.\n */\nexport async function gitClone(\n remoteUrl: string,\n targetDir: string,\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"clone\", \"--quiet\", cleanUrl, targetDir],\n { env, stdio: [\"ignore\", \"inherit\", \"inherit\"] },\n );\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `git clone failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/** `git push origin <branch>` — credentials supplied via GIT_ASKPASS,\n * never in argv. The `.extraheader=` override clears any cached\n * Authorization header that a CI-style git config might inject. */\nexport async function gitPush(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\n \"-c\",\n \"credential.helper=\",\n \"-c\",\n `http.https://github.com/.extraheader=`,\n \"push\",\n cleanUrl,\n `HEAD:${branch}`,\n ],\n { cwd, env, stdio: [\"ignore\", \"inherit\", \"inherit\"] },\n );\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `git push failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/** `git pull origin <branch>`. Token supplied via GIT_ASKPASS, same as push. */\nexport async function gitPull(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"pull\", \"--ff-only\", cleanUrl, branch],\n { cwd, env, stdio: [\"ignore\", \"inherit\", \"inherit\"] },\n );\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `git pull failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/** Read `git remote get-url origin` (or null if no origin). */\nexport async function getOriginUrl(cwd: string): Promise<string | null> {\n try {\n const { stdout } = await execa(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n cwd,\n });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\n/** Set `origin` to the given URL. Used by `fluid mist remote restore`. */\nexport async function setOriginUrl(cwd: string, url: string): Promise<void> {\n try {\n await execa(\"git\", [\"remote\", \"set-url\", \"origin\", url], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(`git remote set-url failed`, e.exitCode ?? 1);\n }\n}\n\n/**\n * Are there uncommitted changes (working tree or index) in this repo?\n * `git status --porcelain` is empty when everything is clean, non-empty\n * otherwise — so the count is just \"is the output non-trivial\".\n */\nexport async function hasUncommittedChanges(cwd: string): Promise<boolean> {\n try {\n const { stdout } = await execa(\"git\", [\"status\", \"--porcelain\"], { cwd });\n return stdout.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch the given branch from the token-bearing remote URL, writing\n * `FETCH_HEAD` so `git rev-list HEAD...FETCH_HEAD` is meaningful.\n *\n * Same security stance as gitPush — installation token comes through\n * GIT_ASKPASS, never argv or `.git/config`.\n */\nexport async function gitFetch(\n cwd: string,\n remoteUrl: string,\n branch = \"main\",\n): Promise<void> {\n const { cleanUrl, env } = gitAuthSpawn(remoteUrl);\n try {\n await execa(\n \"git\",\n [\"-c\", \"credential.helper=\", \"fetch\", \"--quiet\", cleanUrl, branch],\n { cwd, env },\n );\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `git fetch failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/**\n * Count commits in local HEAD vs `FETCH_HEAD` (after `gitFetch`). Returns\n * `{ahead, behind}`: how many commits HEAD has that the remote doesn't,\n * and vice versa. A `0/0` result means \"in sync\".\n */\nexport async function gitAheadBehindVsFetchHead(\n cwd: string,\n): Promise<{ ahead: number; behind: number }> {\n try {\n const { stdout } = await execa(\n \"git\",\n [\"rev-list\", \"--left-right\", \"--count\", \"HEAD...FETCH_HEAD\"],\n { cwd },\n );\n const [a, b] = stdout.trim().split(/\\s+/);\n const ahead = Number.parseInt(a ?? \"0\", 10);\n const behind = Number.parseInt(b ?? \"0\", 10);\n return {\n ahead: Number.isFinite(ahead) ? ahead : 0,\n behind: Number.isFinite(behind) ? behind : 0,\n };\n } catch {\n // No FETCH_HEAD yet → treat as \"no remote info\". Caller decides.\n return { ahead: 0, behind: 0 };\n }\n}\n\n/** Fast-forward `HEAD` to `FETCH_HEAD`. Fails (non-zero exit) if not\n * fast-forwardable — caller must check ahead-count first. */\nexport async function gitMergeFastForward(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"merge\", \"--ff-only\", \"FETCH_HEAD\"], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `git fast-forward merge failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/**\n * Stash working-tree + untracked changes with a Mist-tagged message.\n * Returns the stash ref (`stash@{0}`) we created. Callers should pair\n * this with `gitStashPop` after the dangerous step is done.\n */\nexport async function gitStash(cwd: string, message: string): Promise<void> {\n try {\n await execa(\n \"git\",\n [\"stash\", \"push\", \"--include-untracked\", \"--message\", message],\n { cwd },\n );\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(`git stash push failed`, e.exitCode ?? 1);\n }\n}\n\n/**\n * Pop the most recent stash. Throws on conflict so callers can surface\n * the situation (the working tree will have conflict markers; the user\n * needs to resolve manually).\n */\nexport async function gitStashPop(cwd: string): Promise<void> {\n try {\n await execa(\"git\", [\"stash\", \"pop\"], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(\n `Couldn't restore your local changes after pulling — the file edits collided with a teammate's. Run \\`git stash list\\` and resolve manually.`,\n e.exitCode ?? 1,\n );\n }\n}\n\n/**\n * `git add -A && git commit -m <message>` in `cwd`.\n *\n * Mist Desktop's \"Publish\" UX target is non-technical: the user expects\n * \"ship my changes\" to ship the changes they made, not to know about\n * staging or commit messages. This helper bundles working-tree edits\n * into one commit per publish so push has something to send.\n *\n * The commit author falls back to the repo's configured user; if there\n * isn't one we pass `-c user.email=… -c user.name=…` flags pointing at a\n * synthetic bot identity so the commit isn't rejected by git.\n */\nexport async function gitAutoCommit(\n cwd: string,\n message: string,\n): Promise<void> {\n // Stage everything (including deletes).\n try {\n await execa(\"git\", [\"add\", \"-A\"], { cwd });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n throw new GitError(`git add failed`, e.exitCode ?? 1);\n }\n // Commit. Use the existing user.name / user.email if set, else fall back\n // to a synthetic bot identity so the commit goes through regardless of\n // the user's git config. Probing both keys keeps us from overriding a\n // user who only configured one (rare, but possible with `--global` vs\n // `--local` interleaving).\n let hasName = false;\n let hasEmail = false;\n try {\n const r = await execa(\"git\", [\"config\", \"user.name\"], { cwd });\n hasName = r.stdout.trim().length > 0;\n } catch {\n // exit 1 from `git config <key>` just means the key is unset.\n }\n try {\n const r = await execa(\"git\", [\"config\", \"user.email\"], { cwd });\n hasEmail = r.stdout.trim().length > 0;\n } catch {\n // ditto.\n }\n const identityArgs = [\n ...(hasName ? [] : [\"-c\", \"user.name=Mist Desktop\"]),\n ...(hasEmail ? [] : [\"-c\", \"user.email=mist@fluid.app\"]),\n ];\n try {\n await execa(\"git\", [...identityArgs, \"commit\", \"-m\", message], {\n cwd,\n stdio: [\"ignore\", \"inherit\", \"inherit\"],\n });\n } catch (err) {\n const missing = gitMissingError(err);\n if (missing) throw missing;\n const e = err as ExecaError;\n // exit 1 with \"nothing to commit\" means there was nothing actually\n // staged (race or .gitignore). Treat as a no-op rather than an error.\n if (typeof e.stderr === \"string\" && /nothing to commit/i.test(e.stderr)) {\n return;\n }\n throw new GitError(\n `git commit failed${e.exitCode != null ? ` (exit ${e.exitCode})` : \"\"}`,\n e.exitCode ?? 1,\n );\n }\n}\n","/**\n * `fluid mist clone <slug>` — mints a fresh git credential and clones\n * into ./<vendor-name>/, writes a `.mist` marker file. Spec §3 + §11.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { createMistClient } from \"../api/client.js\";\nimport { showMist } from \"../api/mists.js\";\nimport { createGitCredential } from \"../api/git_credential.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug, writeMistFile } from \"../lib/slug-resolver.js\";\nimport { ensureGitAvailable, gitClone } from \"../lib/git.js\";\n\ninterface Opts {\n dir?: string;\n}\n\nexport const cloneCommand = new Command(\"clone\")\n .description(\"Clone the mist's GitHub repo (mints a fresh token per call)\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--dir <dir>\", \"Target directory (defaults to ./<vendor-name>/)\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n await ensureGitAvailable();\n const resolvedSlug = resolveSlug(slug);\n const client = createMistClient();\n\n const spinner = ora(\"Resolving mist…\").start();\n const { mist } = await showMist(client, resolvedSlug);\n spinner.text = \"Minting git credential…\";\n const { git_credential: cred } = await createGitCredential(\n client,\n mist.slug,\n );\n const targetDir = resolve(opts.dir ?? mist.vendor_name);\n if (existsSync(targetDir)) {\n spinner.fail(\n `Directory ${targetDir} already exists. Pass --dir or remove it first.`,\n );\n process.exit(1);\n }\n spinner.text = `Cloning into ${mist.vendor_name}/…`;\n try {\n // Pass the token-bearing URL inline — never written to .git/config.\n await gitClone(cred.remote_url, targetDir);\n } catch (err) {\n spinner.fail(\"git clone failed\");\n throw err;\n }\n // Drop a `.mist` so future commands run in this dir can skip the slug.\n writeMistFile(targetDir, mist);\n spinner.succeed(`Cloned into ${chalk.cyan(targetDir)}`);\n console.log(chalk.dim(` cd ${join(\".\", mist.vendor_name)}`));\n if (mist.public_url)\n console.log(chalk.dim(` ${chalk.cyan(mist.public_url)}`));\n }),\n );\n","/** Deployments — `--watch` polls these. Spec §4. */\n\nimport type { MistClient } from \"./client.js\";\nimport type {\n DeploymentShowResponse,\n DeploymentsListResponse,\n} from \"../types.js\";\nimport { resolveMistId } from \"./id-resolver.js\";\n\nexport async function listDeployments(\n client: MistClient,\n slug: string,\n limit?: number,\n): Promise<DeploymentsListResponse> {\n const id = await resolveMistId(client, slug);\n return client.get<DeploymentsListResponse>(\n `/api/v202604/mists/${id}/deployments`,\n limit != null ? { limit } : undefined,\n );\n}\n\nexport async function showDeployment(\n client: MistClient,\n slug: string,\n deploymentId: string,\n): Promise<DeploymentShowResponse> {\n const id = await resolveMistId(client, slug);\n return client.get<DeploymentShowResponse>(\n `/api/v202604/mists/${id}/deployments/${deploymentId}`,\n );\n}\n","/**\n * `GET /api/me` — fetch the authenticated user's identity. Used by the\n * push command to stamp commits with `<full_name> (<public_id>):` so\n * deploy history can be traced back to a real person even when the\n * underlying git author falls through to the synthetic bot identity.\n */\n\nimport type { MistClient } from \"./client.js\";\n\nexport interface MistMe {\n id: number;\n public_id: string;\n full_name: string | null;\n first_name: string | null;\n last_name: string | null;\n email: string | null;\n}\n\ninterface MeResponse {\n id: number;\n public_id?: string;\n full_name?: string;\n first_name?: string;\n last_name?: string;\n email?: string;\n}\n\nexport async function fetchCurrentUser(client: MistClient): Promise<MistMe> {\n const raw = await client.get<MeResponse>(\"/api/me\");\n const composed = [raw.first_name, raw.last_name]\n .filter(Boolean)\n .join(\" \")\n .trim();\n const fullName = raw.full_name ?? (composed.length > 0 ? composed : null);\n return {\n id: raw.id,\n public_id: raw.public_id ?? String(raw.id),\n full_name: fullName,\n first_name: raw.first_name ?? null,\n last_name: raw.last_name ?? null,\n email: raw.email ?? null,\n };\n}\n","/**\n * `fluid mist push [--watch]` — mints a credential, pushes to origin, and\n * (with --watch) polls /deployments until READY/ERROR. Spec §3 + §4.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { createMistClient } from \"../api/client.js\";\nimport { createGitCredential } from \"../api/git_credential.js\";\nimport { listDeployments, showDeployment } from \"../api/deployments.js\";\nimport { fetchCurrentUser } from \"../api/me.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport {\n ensureGitAvailable,\n gitAheadBehindVsFetchHead,\n gitAutoCommit,\n gitFetch,\n gitMergeFastForward,\n gitPush,\n gitStash,\n gitStashPop,\n hasUncommittedChanges,\n} from \"../lib/git.js\";\n\ninterface Opts {\n watch?: boolean;\n branch?: string;\n /** Skip the auto-commit step. Power users who manage their own\n * commits can pass --no-commit to fall back to a bare git push. */\n commit?: boolean;\n /** Custom commit message for the auto-commit. Defaults to a\n * timestamped \"Publish from Mist\" line. */\n message?: string;\n}\n\nconst POLL_MS = 2_000;\nconst LOCATE_TIMEOUT_MS = 2 * 60_000; // 2 minutes to find the deployment id\nconst READY_TIMEOUT_MS = 5 * 60_000; // 5 minutes for it to flip to ready\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nexport const pushCommand = new Command(\"push\")\n .description(\n \"Commit working-tree changes and push to the Mist-managed remote (triggers a Vercel deploy)\",\n )\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--watch\", \"Poll /deployments until ready or error\")\n .option(\"--branch <name>\", \"Branch to push (default: main)\")\n .option(\n \"--no-commit\",\n \"Skip the auto-commit step (push existing commits only)\",\n )\n .option(\n \"-m, --message <message>\",\n \"Commit message for the auto-commit (default: timestamped Publish)\",\n )\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n await ensureGitAvailable();\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const branch = opts.branch ?? \"main\";\n const cwd = process.cwd();\n\n // Step 0: detect remote drift. Fetch origin/main and check how\n // far HEAD is from it. If a teammate pushed since we last\n // synced, fast-forward in (auto-pull). Stash any dirty files\n // first so the FF can land cleanly; pop after.\n //\n // Diverged histories (we have local commits AND the remote moved)\n // would need a real rebase + conflict resolution — we bail\n // explicitly so the user knows to handle that case in a terminal.\n // For solo developers and non-overlapping concurrent edits, this\n // path Just Works.\n const driftSpinner = ora(\"Checking for remote changes…\").start();\n try {\n // Mint a short-lived credential for the fetch. We'll mint\n // another one later for push (tokens are ~1h but minting\n // again costs nothing and keeps the failure boundaries clear).\n const { git_credential: fetchCred } = await createGitCredential(\n client,\n resolved,\n );\n await gitFetch(cwd, fetchCred.remote_url, branch);\n const { ahead, behind } = await gitAheadBehindVsFetchHead(cwd);\n if (behind > 0 && ahead === 0) {\n // Safe auto-pull case.\n const wasDirty = await hasUncommittedChanges(cwd);\n driftSpinner.text = `Pulling ${behind} commit${behind === 1 ? \"\" : \"s\"} from origin/main…`;\n if (wasDirty) {\n await gitStash(cwd, \"mist-push: pre-pull stash\");\n }\n try {\n await gitMergeFastForward(cwd);\n } finally {\n if (wasDirty) {\n await gitStashPop(cwd); // throws GitError on conflict\n }\n }\n driftSpinner.succeed(\n `Pulled ${behind} commit${behind === 1 ? \"\" : \"s\"} from origin/main`,\n );\n } else if (behind > 0 && ahead > 0) {\n driftSpinner.fail(\n `Your branch and origin/main have diverged (you're ${ahead} ahead, ${behind} behind).`,\n );\n console.error(\n chalk.yellow(\n \" Resolve in a terminal: `git pull --rebase`, fix any conflicts, then re-run Publish.\",\n ),\n );\n process.exit(1);\n } else {\n driftSpinner.succeed(\"Up to date with origin/main\");\n }\n } catch (err) {\n // Wrap fetch/merge errors with context — the spinner already\n // failed via the explicit branch above when we knew enough.\n // Anything that throws past the auto-pull path is unexpected.\n if (\n err instanceof Error &&\n err.message.includes(\"Resolve in a terminal\")\n ) {\n throw err;\n }\n driftSpinner.fail(\"Couldn't sync with origin/main\");\n throw err;\n }\n\n // Step 1: auto-commit working-tree changes (unless --no-commit).\n // Mist Desktop's Publish UX expects \"ship my changes\" to actually\n // include the changes — without this, `git push` is a no-op against\n // a clean HEAD and Vercel never builds.\n const wantAutoCommit = opts.commit !== false;\n if (wantAutoCommit) {\n const dirty = await hasUncommittedChanges(cwd);\n if (dirty) {\n const baseMessage =\n opts.message ??\n `Publish from Mist Desktop · ${new Date().toISOString().slice(0, 19).replace(\"T\", \" \")}`;\n // Stamp the commit with the Fluid user so deploy history\n // traces back to a real person. Format:\n // \"Mike Tingey: Updated header (0182d21e-…)\"\n // Name + description go first so the prose stays scannable\n // in `git log --oneline` — the long UUID at the end won't\n // truncate the message. Best-effort: if /api/me fails,\n // hangs, or returns a malformed body, we still commit with\n // the bare message — publish is essential, the stamp is not.\n let namePrefix = \"\";\n let idSuffix = \"\";\n try {\n const me = await Promise.race([\n fetchCurrentUser(client),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(\"timed out after 5s\")),\n 5_000,\n ),\n ),\n ]);\n const name =\n (me.full_name && me.full_name.trim()) ||\n me.email ||\n (Number.isFinite(me.id) ? `user-${me.id}` : null);\n const id = me.public_id && me.public_id.trim();\n if (name) namePrefix = `${name}: `;\n if (id) idSuffix = ` (${id})`;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(\n chalk.yellow(\n ` (skipping user-stamp on commit — couldn't fetch /api/me: ${reason})`,\n ),\n );\n }\n const message = `${namePrefix}${baseMessage}${idSuffix}`;\n const commitSpinner = ora(\n `Committing changes (${message.length > 60 ? message.slice(0, 57) + \"…\" : message})…`,\n ).start();\n try {\n await gitAutoCommit(cwd, message);\n commitSpinner.succeed(\"Committed\");\n } catch (err) {\n commitSpinner.fail(\"Commit failed\");\n throw err;\n }\n }\n }\n\n const spinner = ora(\"Minting git credential…\").start();\n const { git_credential: cred } = await createGitCredential(\n client,\n resolved,\n );\n spinner.text = `Pushing ${branch} to origin…`;\n try {\n await gitPush(cwd, cred.remote_url, branch);\n } catch (err) {\n spinner.fail(\"git push failed\");\n throw err;\n }\n spinner.succeed(\"Push complete\");\n\n if (!opts.watch) return;\n\n // Snapshot the commit sha we just pushed so we can match the right\n // deployment in the (common) case where older deployments already\n // exist on this mist. Best-effort: if `git rev-parse HEAD` fails we\n // fall back to taking the newest entry.\n let pushedSha: string | null = null;\n try {\n const { execa } = await import(\"execa\");\n const r = await execa(\"git\", [\"rev-parse\", \"HEAD\"], { cwd });\n pushedSha = r.stdout.trim();\n } catch {\n // git unavailable / not a repo — fall back to newest-deployment heuristic\n }\n\n // Find the deployment our push triggered. We poll /deployments\n // for an entry whose commit_sha matches what we just pushed.\n // Without this, the loop used to grab whatever was first in the\n // list — including a stale ready deploy from a prior push that\n // skipped Vercel — and exit immediately as \"ready\".\n const locateStart = Date.now();\n let deploymentId: string | null = null;\n let attempt = 0;\n while (Date.now() - locateStart < LOCATE_TIMEOUT_MS) {\n attempt++;\n const { deployments } = await listDeployments(client, resolved, 5);\n const match = pushedSha\n ? deployments.find((d) => d.commit_sha === pushedSha)\n : deployments[0];\n if (match) {\n deploymentId = match.id;\n // Print so users see something happen even in non-TTY where\n // ora's spinner doesn't redraw.\n console.log(`Located deployment ${match.id} (${match.state})`);\n break;\n }\n if (attempt === 1) {\n console.log(\n `Locating deployment for commit ${pushedSha?.slice(0, 7) ?? \"(unknown)\"}…`,\n );\n } else if (attempt % 5 === 0) {\n // Status ping every 10s so the user knows we're still working.\n console.log(` …still waiting (${attempt * 2}s elapsed)`);\n }\n await sleep(POLL_MS);\n }\n if (!deploymentId) {\n console.error(\n `No deployment matching ${pushedSha?.slice(0, 7) ?? \"the push\"} appeared within ${LOCATE_TIMEOUT_MS / 1000}s.`,\n );\n console.error(\n \"Vercel may still be queueing — run `fluid mist deployments` to check.\",\n );\n process.exit(3);\n }\n\n // Watch the located deployment until it's in a terminal state.\n const readyStart = Date.now();\n let lastState: string | null = null;\n while (Date.now() - readyStart < READY_TIMEOUT_MS) {\n const { deployment } = await showDeployment(\n client,\n resolved,\n deploymentId,\n );\n if (deployment.state !== lastState) {\n console.log(` ${deployment.state}…`);\n lastState = deployment.state;\n }\n if (deployment.state === \"ready\") {\n console.log(`✔ Ready: ${chalk.cyan(deployment.url ?? \"(no url)\")}`);\n return;\n }\n if (deployment.state === \"error\" || deployment.state === \"canceled\") {\n console.error(`✘ Deployment ${deployment.state}`);\n process.exit(3);\n }\n await sleep(POLL_MS);\n }\n console.error(\n `Watch timed out after ${READY_TIMEOUT_MS / 1000}s. Last state: ${lastState}.`,\n );\n console.error(\"Run `fluid mist deployments` to check the latest state.\");\n process.exit(3);\n }),\n );\n","/** `fluid mist pull` — git pull origin main. Spec §3. */\n\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { createMistClient } from \"../api/client.js\";\nimport { createGitCredential } from \"../api/git_credential.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { ensureGitAvailable, gitPull } from \"../lib/git.js\";\n\ninterface Opts {\n branch?: string;\n}\n\nexport const pullCommand = new Command(\"pull\")\n .description(\"git pull from the Mist-managed remote\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--branch <name>\", \"Branch to pull (default: main)\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n await ensureGitAvailable();\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const branch = opts.branch ?? \"main\";\n const spinner = ora(\"Minting git credential…\").start();\n const { git_credential: cred } = await createGitCredential(\n client,\n resolved,\n );\n spinner.text = `Pulling ${branch}…`;\n try {\n await gitPull(process.cwd(), cred.remote_url, branch);\n } catch (err) {\n spinner.fail(\"git pull failed\");\n throw err;\n }\n spinner.succeed(\"Pull complete\");\n }),\n );\n","/** `fluid mist open` — opens public_url in the default browser. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport open from \"open\";\nimport { createMistClient } from \"../api/client.js\";\nimport { showMist } from \"../api/mists.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\n\nexport const openCommand = new Command(\"open\")\n .description(\"Open the mist's public URL in your browser\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .action((slug: string | undefined) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const { mist } = await showMist(client, resolved);\n if (!mist.public_url) {\n console.error(\n chalk.yellow(\n `Mist ${mist.slug} has no public URL yet (state: ${mist.state}).`,\n ),\n );\n process.exit(1);\n }\n console.log(chalk.cyan(mist.public_url));\n await open(mist.public_url);\n }),\n );\n","/** `fluid mist deployments` — list recent deployments. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { listDeployments } from \"../api/deployments.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { printJson, printTable, relativeDate } from \"../lib/output.js\";\n\ninterface Opts {\n limit?: string;\n json?: boolean;\n}\n\nconst STATE_COLOR: Record<string, (s: string) => string> = {\n ready: chalk.green,\n building: chalk.yellow,\n queued: chalk.dim,\n error: chalk.red,\n canceled: chalk.red,\n};\n\nexport const deploymentsCommand = new Command(\"deployments\")\n .description(\"List recent deployments for a mist\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--limit <n>\", \"How many to fetch (default 10)\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const limit = opts.limit ? parseInt(opts.limit, 10) : 10;\n const response = await listDeployments(client, resolved, limit);\n if (opts.json) return printJson(response);\n const deployments = response.deployments ?? [];\n if (deployments.length === 0) {\n console.log(chalk.dim(\"No deployments yet.\"));\n return;\n }\n const header = [\n chalk.bold(\"ID\"),\n chalk.bold(\"STATE\"),\n chalk.bold(\"COMMIT\"),\n chalk.bold(\"MESSAGE\"),\n chalk.bold(\"AGE\"),\n ];\n const rows = deployments.map((d) => [\n d.id,\n (STATE_COLOR[d.state] ?? chalk.white)(d.state),\n d.commit_sha ? d.commit_sha.slice(0, 7) : chalk.dim(\"—\"),\n d.commit_message ? d.commit_message.slice(0, 48) : chalk.dim(\"—\"),\n relativeDate(d.created_at),\n ]);\n printTable([header, ...rows]);\n }),\n );\n","/** Logs — `--tail` polls every 2s with `since`. Spec §4. */\n\nimport type { MistClient } from \"./client.js\";\nimport type { LogsResponse } from \"../types.js\";\nimport { resolveMistId } from \"./id-resolver.js\";\n\nexport interface FetchLogsParams {\n deployment_id?: string;\n /** ISO-8601 — only logs newer than this. Used by --tail. */\n since?: string;\n limit?: number;\n}\n\nexport async function fetchLogs(\n client: MistClient,\n slug: string,\n params: FetchLogsParams = {},\n): Promise<LogsResponse> {\n const id = await resolveMistId(client, slug);\n return client.get<LogsResponse>(\n `/api/v202604/mists/${id}/logs`,\n params as Record<string, unknown>,\n );\n}\n","/** `fluid mist logs [--tail]` — poll /logs?since=<last> every 2s. Spec §4. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../api/client.js\";\nimport { fetchLogs } from \"../api/logs.js\";\nimport { runAction } from \"../lib/error-handler.js\";\nimport { resolveSlug } from \"../lib/slug-resolver.js\";\nimport { printJson } from \"../lib/output.js\";\nimport type { LogEntry } from \"../types.js\";\n\ninterface Opts {\n tail?: boolean;\n limit?: string;\n deployment?: string;\n json?: boolean;\n}\n\nconst POLL_MS = 2_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction levelColor(level: LogEntry[\"level\"]): (s: string) => string {\n return level === \"stderr\" ? chalk.red : chalk.dim;\n}\n\nfunction printLine(entry: LogEntry): void {\n const ts = entry.timestamp.slice(11, 19);\n process.stdout.write(\n `${chalk.dim(ts)} ${levelColor(entry.level)(entry.level.padEnd(6))} ${entry.message}\\n`,\n );\n}\n\nexport const logsCommand = new Command(\"logs\")\n .description(\"Fetch deployment logs (use --tail to stream)\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--tail\", \"Stream new logs every 2s\")\n .option(\"--limit <n>\", \"Initial fetch size (default 200)\")\n .option(\"--deployment <id>\", \"Logs from a specific deployment ID\")\n .option(\"--json\", \"Emit raw API JSON (one batch; ignored when --tail)\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const limit = opts.limit ? parseInt(opts.limit, 10) : 200;\n\n const initial = await fetchLogs(client, resolved, {\n ...(opts.deployment ? { deployment_id: opts.deployment } : {}),\n limit,\n });\n if (opts.json && !opts.tail) return printJson(initial);\n for (const entry of initial.logs) printLine(entry);\n\n if (!opts.tail) return;\n\n let since =\n initial.logs.length > 0\n ? initial.logs[initial.logs.length - 1]!.timestamp\n : new Date().toISOString();\n\n // Tail until Ctrl-C. Plain polling loop, no fancy backoff.\n while (true) {\n await sleep(POLL_MS);\n const batch = await fetchLogs(client, resolved, {\n ...(opts.deployment ? { deployment_id: opts.deployment } : {}),\n since,\n limit,\n });\n for (const entry of batch.logs) {\n printLine(entry);\n since = entry.timestamp;\n }\n }\n }),\n );\n","/** Env-var sub-resource. Spec §4 + §3 \"Env vars\". */\n\nimport type { MistClient } from \"./client.js\";\nimport type { EnvVar, EnvVarsListResponse } from \"../types.js\";\nimport { resolveMistId } from \"./id-resolver.js\";\n\nfunction path(id: string, key?: string) {\n return key\n ? `/api/v202604/mists/${id}/env_vars/${encodeURIComponent(key)}`\n : `/api/v202604/mists/${id}/env_vars`;\n}\n\nexport async function listEnvVars(\n client: MistClient,\n slug: string,\n): Promise<EnvVarsListResponse> {\n const id = await resolveMistId(client, slug);\n return client.get<EnvVarsListResponse>(path(id));\n}\n\ninterface UpsertResponse {\n env_var: EnvVar;\n meta: unknown;\n}\n\n/** Create a new env var (the spec routes `set` to POST for new keys). */\nexport async function createEnvVar(\n client: MistClient,\n slug: string,\n key: string,\n value: string,\n targets?: EnvVar[\"targets\"],\n): Promise<UpsertResponse> {\n const id = await resolveMistId(client, slug);\n return client.post<UpsertResponse>(path(id), {\n env_var: { key, value, targets },\n });\n}\n\n/** Update an existing env var (the spec routes `set` to PATCH for existing keys). */\nexport async function updateEnvVar(\n client: MistClient,\n slug: string,\n key: string,\n value: string,\n targets?: EnvVar[\"targets\"],\n): Promise<UpsertResponse> {\n const id = await resolveMistId(client, slug);\n return client.patch<UpsertResponse>(path(id, key), {\n env_var: { value, targets },\n });\n}\n\nexport async function deleteEnvVar(\n client: MistClient,\n slug: string,\n key: string,\n): Promise<void> {\n const id = await resolveMistId(client, slug);\n return client.delete<void>(path(id, key));\n}\n","/** `fluid mist env list` — list env vars; mark managed_by entries. Spec §4. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../../api/client.js\";\nimport { listEnvVars } from \"../../api/env_vars.js\";\nimport { runAction } from \"../../lib/error-handler.js\";\nimport { resolveSlug } from \"../../lib/slug-resolver.js\";\nimport { printJson, printTable } from \"../../lib/output.js\";\n\ninterface Opts {\n json?: boolean;\n showValues?: boolean;\n}\n\nfunction maskValue(value: string): string {\n if (value.length <= 8) return \"•\".repeat(value.length);\n return `${value.slice(0, 4)}${\"•\".repeat(8)}${value.slice(-2)}`;\n}\n\nexport const envListCommand = new Command(\"list\")\n .description(\"List a mist's env vars\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--show-values\", \"Print full values instead of masking them\")\n .option(\"--json\", \"Emit raw API JSON\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const response = await listEnvVars(client, resolved);\n if (opts.json) return printJson(response);\n const vars = response.env_vars ?? [];\n if (vars.length === 0) {\n console.log(chalk.dim(\"No env vars.\"));\n return;\n }\n const header = [\n chalk.bold(\"KEY\"),\n chalk.bold(\"VALUE\"),\n chalk.bold(\"TARGETS\"),\n chalk.bold(\"MANAGED\"),\n ];\n const rows = vars.map((v) => [\n v.key,\n opts.showValues ? v.value : maskValue(v.value),\n v.targets.join(\",\"),\n v.managed_by === \"mist\" ? chalk.magenta(\"mist\") : chalk.dim(\"user\"),\n ]);\n printTable([header, ...rows]);\n }),\n );\n","/**\n * `fluid mist env set <slug> KEY=value [KEY=value ...]` — POST for new\n * keys, PATCH for existing. Spec §3 + §4.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../../api/client.js\";\nimport { createEnvVar, listEnvVars, updateEnvVar } from \"../../api/env_vars.js\";\nimport { runAction } from \"../../lib/error-handler.js\";\nimport { resolveSlug } from \"../../lib/slug-resolver.js\";\n\ninterface Opts {\n json?: boolean;\n}\n\nfunction parsePair(pair: string): { key: string; value: string } {\n const eq = pair.indexOf(\"=\");\n if (eq <= 0) {\n throw new Error(\n `Invalid pair \"${pair}\". Use KEY=value (no leading spaces).`,\n );\n }\n return { key: pair.slice(0, eq), value: pair.slice(eq + 1) };\n}\n\nexport const envSetCommand = new Command(\"set\")\n .description(\"Set one or more env vars (KEY=value KEY=value …)\")\n .argument(\"<slug-or-pair>\", \"The mist slug, or the first KEY=value pair\")\n .argument(\"[pairs...]\", \"Additional KEY=value pairs\")\n .action(async (slugOrPair: string, pairs: string[]) => {\n await runAction(async () => {\n // Allow both shapes: `env set <slug> KEY=val` and `env set KEY=val`\n // (with slug coming from .mist file). We detect by checking if the\n // first arg contains an `=`.\n let slug: string;\n let rawPairs: string[];\n if (slugOrPair.includes(\"=\")) {\n slug = resolveSlug();\n rawPairs = [slugOrPair, ...pairs];\n } else {\n slug = resolveSlug(slugOrPair);\n rawPairs = pairs;\n }\n if (rawPairs.length === 0) {\n console.error(chalk.red(\"Pass at least one KEY=value pair.\"));\n process.exit(1);\n }\n const client = createMistClient();\n // Fetch existing to decide POST vs PATCH per key.\n const existing = await listEnvVars(client, slug);\n const existingKeys = new Set((existing.env_vars ?? []).map((v) => v.key));\n for (const raw of rawPairs) {\n const { key, value } = parsePair(raw);\n if (existingKeys.has(key)) {\n await updateEnvVar(client, slug, key, value);\n console.log(`${chalk.green(\"updated\")} ${key}`);\n } else {\n await createEnvVar(client, slug, key, value);\n console.log(`${chalk.cyan(\"created\")} ${key}`);\n }\n }\n });\n });\n","/** `fluid mist env unset <slug> KEY [KEY ...]` — DELETE per key. Spec §3. */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { createMistClient } from \"../../api/client.js\";\nimport { deleteEnvVar } from \"../../api/env_vars.js\";\nimport { runAction } from \"../../lib/error-handler.js\";\nimport { resolveSlug } from \"../../lib/slug-resolver.js\";\n\nexport const envUnsetCommand = new Command(\"unset\")\n .description(\"Delete one or more env vars\")\n .argument(\n \"<slug-or-key>\",\n \"The mist slug, or the first KEY (if .mist file is present)\",\n )\n .argument(\"[keys...]\", \"Additional keys\")\n .action(async (slugOrKey: string, keys: string[]) => {\n await runAction(async () => {\n // Heuristic: KEYs are env-var-shaped (UPPERCASE_WITH_UNDERSCORES);\n // slugs are 6 lowercase alnum chars. We only need it to be specific\n // enough for the common case.\n let slug: string;\n let toDelete: string[];\n if (/^[A-Z_][A-Z0-9_]*$/.test(slugOrKey)) {\n slug = resolveSlug();\n toDelete = [slugOrKey, ...keys];\n } else {\n slug = resolveSlug(slugOrKey);\n toDelete = keys;\n }\n if (toDelete.length === 0) {\n console.error(chalk.red(\"Pass at least one KEY.\"));\n process.exit(1);\n }\n const client = createMistClient();\n for (const key of toDelete) {\n await deleteEnvVar(client, slug, key);\n console.log(`${chalk.red(\"deleted\")} ${key}`);\n }\n });\n });\n","/**\n * `fluid mist env pull` — writes `.env.local` with user-managed vars only.\n * Skips `managed_by: \"mist\"` entries (DATABASE_URL, FLUID_*) since local\n * dev uses PGlite, not the production database. Spec §4 + §5.\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createMistClient } from \"../../api/client.js\";\nimport { listEnvVars } from \"../../api/env_vars.js\";\nimport { runAction } from \"../../lib/error-handler.js\";\nimport { resolveSlug } from \"../../lib/slug-resolver.js\";\n\ninterface Opts {\n out?: string;\n}\n\nfunction escapeValue(v: string): string {\n // Quote if value has whitespace, `#`, or quotes — bash-safe.\n if (/[\\s#\"']/.test(v)) {\n return `\"${v.replace(/([\"\\\\$`])/g, \"\\\\$1\")}\"`;\n }\n return v;\n}\n\nexport const envPullCommand = new Command(\"pull\")\n .description(\"Write user-managed env vars to .env.local in the CWD\")\n .argument(\"[slug]\", \"The mist slug (defaults to .mist file in CWD)\")\n .option(\"--out <path>\", \"Output path (default: .env.local)\")\n .action((slug: string | undefined, opts: Opts) =>\n runAction(async () => {\n const resolved = resolveSlug(slug);\n const client = createMistClient();\n const { env_vars } = await listEnvVars(client, resolved);\n const user = env_vars.filter((v) => v.managed_by === \"user\");\n const skipped = env_vars.filter((v) => v.managed_by === \"mist\");\n const target = join(process.cwd(), opts.out ?? \".env.local\");\n const body = user\n .map((v) => `${v.key}=${escapeValue(v.value)}`)\n .join(\"\\n\");\n writeFileSync(target, body + (body.length ? \"\\n\" : \"\"), \"utf8\");\n console.log(\n chalk.green(\n `Wrote ${user.length} var(s) to ${target.replace(process.cwd() + \"/\", \"\")}.`,\n ),\n );\n if (skipped.length > 0) {\n console.log(\n chalk.dim(\n `Skipped ${skipped.length} Mist-managed var(s): ${skipped.map((v) => v.key).join(\", \")} (local dev uses PGlite)`,\n ),\n );\n }\n }),\n );\n","/** `fluid mist env` — sub-command aggregator. */\n\nimport { Command } from \"commander\";\nimport { envListCommand } from \"./list.js\";\nimport { envSetCommand } from \"./set.js\";\nimport { envUnsetCommand } from \"./unset.js\";\nimport { envPullCommand } from \"./pull.js\";\n\nexport const envCommand = new Command(\"env\")\n .description(\"Manage a mist's environment variables\")\n .addCommand(envListCommand)\n .addCommand(envSetCommand)\n .addCommand(envUnsetCommand)\n .addCommand(envPullCommand);\n","/**\n * @fluid-app/fluid-cli-mist\n *\n * Fluid CLI plugin for managing Mist hosted extensions. Auto-discovered\n * by @fluid-app/fluid-cli via the `fluid-cli-*` naming convention.\n *\n * Source of truth for command surface + behavior:\n * fluid (sibling repo) features/mist/cli-spec.md\n */\n\nimport { Command } from \"commander\";\nimport type { FluidPlugin, PluginContext } from \"@fluid-app/fluid-cli\";\nimport { listCommand } from \"./commands/list.js\";\nimport { showCommand } from \"./commands/show.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { updateCommand } from \"./commands/update.js\";\nimport { deleteCommand } from \"./commands/delete.js\";\nimport { restoreCommand } from \"./commands/restore.js\";\nimport { cloneCommand } from \"./commands/clone.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { openCommand } from \"./commands/open.js\";\nimport { deploymentsCommand } from \"./commands/deployments.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { envCommand } from \"./commands/env/index.js\";\n\nconst plugin: FluidPlugin = {\n name: \"fluid-cli-mist\",\n version: \"0.1.0\",\n async register(ctx: PluginContext) {\n const mist = new Command(\"mist\").description(\n \"Create, manage, and deploy Mist hosted extensions\",\n );\n\n mist.addCommand(listCommand);\n mist.addCommand(showCommand);\n mist.addCommand(createCommand);\n mist.addCommand(updateCommand);\n mist.addCommand(deleteCommand);\n mist.addCommand(restoreCommand);\n mist.addCommand(cloneCommand);\n mist.addCommand(pushCommand);\n mist.addCommand(pullCommand);\n mist.addCommand(openCommand);\n mist.addCommand(deploymentsCommand);\n mist.addCommand(logsCommand);\n mist.addCommand(envCommand);\n\n ctx.program.addCommand(mist);\n },\n};\n\nexport default plugin;\nexport type * from \"./types.js\";\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@fluid-app/fluid-cli-mist",
3
+ "version": "0.1.0",
4
+ "description": "Fluid CLI plugin for managing Mist hosted extensions",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "type": "module",
9
+ "main": "./dist/index.mjs",
10
+ "types": "./dist/index.d.mts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "types": "./dist/index.d.mts"
15
+ }
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "dependencies": {
21
+ "chalk": "^5.3.0",
22
+ "commander": "^12.0.0",
23
+ "execa": "^8.0.0",
24
+ "open": "^10.1.0",
25
+ "ora": "^8.0.0",
26
+ "prompts": "^2.4.2",
27
+ "@fluid-app/fluid-cli": "0.1.12"
28
+ },
29
+ "devDependencies": {
30
+ "@swc/core": "^1.15.18",
31
+ "@swc/jest": "^0.2.39",
32
+ "@types/jest": "^29.5.14",
33
+ "@types/prompts": "^2.4.9",
34
+ "jest": "^29.7.0",
35
+ "tsdown": "^0.21.0",
36
+ "typescript": "^5",
37
+ "@fluid-app/typescript-config": "0.0.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ },
42
+ "scripts": {
43
+ "build": "tsdown",
44
+ "dev": "tsdown --watch",
45
+ "lint": "oxlint",
46
+ "lint:fix": "oxlint --fix",
47
+ "typecheck": "tsgo --noEmit",
48
+ "test": "jest",
49
+ "test:watch": "jest --watch"
50
+ }
51
+ }