@vortex-os/base 0.10.0 → 0.11.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,"sources":["../../plugins/session-rituals/src/statusline.ts","../../plugins/session-rituals/src/ensure-hooks.ts"],"sourcesContent":["/**\n * `vortex statusline` — a Claude Code statusLine renderer.\n *\n * Claude Code pipes a JSON snapshot of the session (model, context window,\n * cost, rate limits, workspace) to the configured statusLine command on every\n * refresh and renders whatever the command prints. This module turns that\n * snapshot into a colored status bar:\n *\n * full (default, 3 lines + a VortEX line inside an instance):\n * 🧠 Fable 5 │ █ max │ █░░░░░░░░░ 12% · 120K/1M │ 🕐 22:25 │ 💰 $9.22\n * 5h ██████░░ 75%(2h13m) │ 7d ███████░ 96%(0d8h) │ 📦 cache 98%\n * 📁 my-project │ ⎇ main 2b0949d │ ⏱ 1h19m │ +78 -38 │ ⧉ 1\n * 🌀 VortEX v0.11.0 │ last: 2026-06-10_0452-….md\n *\n * lite (1 line):\n * 📁 my-project │ ⎇ main │ 🧠 Fable 5 │ █ max │ ░░░░░░░░ 12% · 120K/1M │ 5h 75% · 7d 96% │ ⧉ 1 │ 🌀 v0.11.0 │ 🕐 22:25\n *\n * Design notes:\n * - Rendering is PURE (`renderStatusline(data, probes, mode)`) — every\n * environment lookup (git, process list, clock, VortEX instance files) is\n * collected separately in `collectStatuslineProbes`, so the composition is\n * unit-testable without a repo or a terminal.\n * - Reasoning effort is shown as one bar whose height + color encode the\n * level. Claude Code reports `ultracode` as plain `xhigh` (ultracode is\n * \"xhigh + workflow orchestration\"), so when the level reads `xhigh` we\n * additionally sniff the session transcript for the last `/effort` change\n * notice — a best-effort heuristic that degrades to showing `xhigh`.\n * - Every probe is wrapped: a statusline must NEVER throw or block the bar —\n * on any failure a segment silently falls back to a neutral value.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { closeSync, existsSync, openSync, readSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parseSettings, serializeSettings, type ClaudeSettings } from \"./ensure-hooks.js\";\n\n// --- ANSI palette (kept as raw escapes so the bar renders in any ANSI terminal) ---\nconst RST = \"\\x1b[0m\";\nconst CYAN = \"\\x1b[36m\";\nconst GREEN = \"\\x1b[32m\";\nconst YELLOW = \"\\x1b[33m\";\nconst RED = \"\\x1b[31m\";\nconst DIM = \"\\x1b[2m\";\nconst BOLD = \"\\x1b[1m\";\nconst WHITE = \"\\x1b[37m\";\nconst MAGENTA = \"\\x1b[35m\";\nconst BLUE = \"\\x1b[34m\";\nconst GREY = \"\\x1b[38;5;242m\";\nconst ORANGE = \"\\x1b[38;5;208m\";\n\nconst SEP = ` ${DIM}│${RST} `;\n\n/** The slice of Claude Code's statusLine input JSON this renderer consumes. */\nexport interface StatuslineData {\n readonly modelName: string;\n /** Reasoning effort level as reported (`effort.level`), or null. */\n readonly effortLevel: string | null;\n readonly transcriptPath: string | null;\n /** Project directory (workspace.current_dir, falling back to cwd). */\n readonly dir: string | null;\n readonly contextWindowSize: number;\n /** Context used, percent — kept as reported (may be fractional). */\n readonly usedPercentage: number;\n readonly cacheReadTokens: number;\n readonly cacheCreationTokens: number;\n readonly costUsd: number;\n readonly durationMs: number;\n readonly linesAdded: number;\n readonly linesRemoved: number;\n readonly fiveHourUsedPct: number;\n readonly fiveHourResetsAt: number;\n readonly sevenDayUsedPct: number;\n readonly sevenDayResetsAt: number;\n}\n\n/** Environment lookups the renderer composes in — collected impurely, injected purely. */\nexport interface StatuslineProbes {\n readonly gitBranch: string;\n readonly gitHash: string;\n readonly sessionCount: number;\n /** Set when `dir` is a VortEX instance root; lastWorklog is the newest worklog file name. */\n readonly vortex: { readonly version: string | null; readonly lastWorklog: string | null } | null;\n /** Effort level after the ultracode transcript sniff (null → use data.effortLevel). */\n readonly effortLevel: string | null;\n readonly now: Date;\n}\n\nfunction num(v: unknown, fallback = 0): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n/** Non-negative numeric field (counters, costs, sizes — a negative is sender garbage). */\nfunction nonneg(v: unknown, fallback = 0): number {\n return Math.max(0, num(v, fallback));\n}\n/** Clamp a reported percentage into the displayable 0..100 range. */\nfunction clampPct(v: number): number {\n return Math.min(100, Math.max(0, v));\n}\n/**\n * Make a dynamic string safe to put in a single-line ANSI bar: drop control\n * chars (incl. ESC — no injected sequences/newlines), collapse whitespace, and\n * truncate long values. The bar must render intact whatever a branch name,\n * model name, or worklog filename contains.\n */\nexport function safeSegment(s: string, max = 60): string {\n // eslint-disable-next-line no-control-regex\n const cleaned = s.replace(/[\\u0000-\\u001f\\u007f]/g, \" \").replace(/\\s+/g, \" \").trim();\n return cleaned.length > max ? cleaned.slice(0, max - 1) + \"…\" : cleaned;\n}\nfunction str(v: unknown): string | null {\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\nfunction obj(v: unknown): Record<string, unknown> {\n return typeof v === \"object\" && v !== null ? (v as Record<string, unknown>) : {};\n}\n\n/** Parse Claude Code's statusLine stdin JSON into the fields the bar uses. Never throws on shape — only on non-JSON. */\nexport function parseStatuslineInput(text: string): StatuslineData {\n const root = obj(JSON.parse(text));\n const model = obj(root.model);\n const effort = obj(root.effort);\n const workspace = obj(root.workspace);\n const cost = obj(root.cost);\n const ctx = obj(root.context_window);\n const usage = obj(ctx.current_usage);\n const limits = obj(root.rate_limits);\n const five = obj(limits.five_hour);\n const seven = obj(limits.seven_day);\n\n const rawName = str(model.display_name) ?? \"Claude\";\n const windowSize = nonneg(ctx.context_window_size, 200_000);\n return {\n modelName: rawName.replace(/^Claude\\s+/, \"\"),\n effortLevel: str(effort.level),\n transcriptPath: str(root.transcript_path),\n dir: str(workspace.current_dir) ?? str(root.cwd),\n contextWindowSize: windowSize > 0 ? windowSize : 200_000,\n usedPercentage: clampPct(num(ctx.used_percentage)),\n cacheReadTokens: nonneg(usage.cache_read_input_tokens),\n cacheCreationTokens: nonneg(usage.cache_creation_input_tokens),\n costUsd: nonneg(cost.total_cost_usd),\n durationMs: nonneg(cost.total_duration_ms),\n linesAdded: nonneg(cost.total_lines_added),\n linesRemoved: nonneg(cost.total_lines_removed),\n fiveHourUsedPct: clampPct(num(five.used_percentage)),\n fiveHourResetsAt: nonneg(five.resets_at),\n sevenDayUsedPct: clampPct(num(seven.used_percentage)),\n sevenDayResetsAt: nonneg(seven.resets_at),\n };\n}\n\n/** One-character effort meter: height + color encode the level (`█✦` for ultracode). */\nexport function effortMeter(level: string | null): { meter: string; color: string } | null {\n switch (level) {\n case \"low\":\n return { meter: \"▂\", color: GREY };\n case \"medium\":\n return { meter: \"▄\", color: GREEN };\n case \"high\":\n return { meter: \"▆\", color: YELLOW };\n case \"xhigh\":\n return { meter: \"▇\", color: ORANGE };\n case \"max\":\n return { meter: \"█\", color: RED };\n case \"ultracode\":\n return { meter: \"█✦\", color: MAGENTA };\n default:\n return null;\n }\n}\n\n/** `7` → `7`, `70_000` → `70K`, `1_200_000` → `1.2M` (token quantities). */\nexport function formatTokens(t: number): string {\n if (t >= 1_000_000) return `${Math.floor(t / 1_000_000)}.${Math.floor((t % 1_000_000) / 100_000)}M`;\n if (t >= 1_000) return `${Math.floor(t / 1_000)}K`;\n return String(Math.floor(t));\n}\n\n/** Window sizes render without a decimal: `200_000` → `200K`, `1_000_000` → `1M`. */\nexport function formatWindow(t: number): string {\n if (t >= 1_000_000) return `${Math.floor(t / 1_000_000)}M`;\n if (t >= 1_000) return `${Math.floor(t / 1_000)}K`;\n return String(Math.floor(t));\n}\n\n/** `█`-filled gauge, `width` cells, floor-scaled so 100% and only 100% fills it. */\nexport function makeBar(pct: number, width: number): string {\n const filled = Math.min(width, Math.max(0, Math.floor((pct * width) / 100)));\n return \"█\".repeat(filled) + \"░\".repeat(width - filled);\n}\n\n/** Color for a USAGE percentage (high = bad): <50 green, <80 yellow, else red. */\nfunction usageColor(pct: number): string {\n if (pct >= 80) return RED;\n if (pct >= 50) return YELLOW;\n return GREEN;\n}\n\n/** Color for a REMAINING percentage (low = bad): <=30 red, <=60 yellow, else green. */\nfunction healthColor(remaining: number): string {\n if (remaining <= 30) return RED;\n if (remaining <= 60) return YELLOW;\n return GREEN;\n}\n\nfunction formatDuration(ms: number): string {\n const totalMin = Math.floor(ms / 60_000);\n if (totalMin >= 60) return `${Math.floor(totalMin / 60)}h${totalMin % 60}m`;\n return `${totalMin}m${Math.floor(ms / 1000) % 60}s`;\n}\n\n/** `(2h13m)` until an epoch-seconds reset, or \"\" when absent/past. */\nfunction untilReset(resetsAtSec: number, now: Date): string {\n if (resetsAtSec <= 0) return \"\";\n const diffSec = resetsAtSec - Math.floor(now.getTime() / 1000);\n if (diffSec <= 0) return \"\";\n if (diffSec >= 86_400) return `${Math.floor(diffSec / 86_400)}d${Math.floor((diffSec % 86_400) / 3600)}h`;\n return `${Math.floor(diffSec / 3600)}h${Math.floor((diffSec % 3600) / 60)}m`;\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** Compose the status bar. Pure — see `collectStatuslineProbes` for the impure half. */\nexport function renderStatusline(\n d: StatuslineData,\n p: StatuslineProbes,\n mode: \"full\" | \"lite\" = \"full\",\n): string {\n const usedPctDisplay = Math.round(d.usedPercentage);\n const ctxColor = usageColor(usedPctDisplay);\n const ctxUsedTokens = Math.round((d.usedPercentage * d.contextWindowSize) / 100);\n const ctxText = `${WHITE}${formatTokens(ctxUsedTokens)}/${formatWindow(d.contextWindowSize)}${RST}`;\n const clock = `🕐 ${WHITE}${pad2(p.now.getHours())}:${pad2(p.now.getMinutes())}${RST}`;\n\n const level = p.effortLevel ?? d.effortLevel;\n const effort = effortMeter(level);\n const effortSeg = effort\n ? `${effort.color}${effort.meter}${RST} ${GREY}${safeSegment(level ?? \"\")}${RST}`\n : null;\n const modelSeg = `🧠 ${BOLD}${CYAN}${safeSegment(d.modelName, 30)}${RST}`;\n\n const fiveRemain = Math.max(0, 100 - Math.round(d.fiveHourUsedPct));\n const sevenRemain = Math.max(0, 100 - Math.round(d.sevenDayUsedPct));\n const fiveColor = healthColor(fiveRemain);\n const sevenColor = healthColor(sevenRemain);\n const sessionSeg = `${WHITE}⧉ ${Math.max(1, Math.floor(p.sessionCount))}${RST}`;\n\n const project = safeSegment(\n p.vortex || d.dir ? (d.dir ?? \"\").replace(/[\\\\/]+$/, \"\").split(/[\\\\/]/).pop() || \"?\" : \"?\",\n 40,\n );\n const gitBranch = safeSegment(p.gitBranch, 40);\n const gitHash = safeSegment(p.gitHash, 16);\n\n if (mode === \"lite\") {\n const parts = [\n `📁 ${BLUE}${project}${RST}`,\n `${WHITE}⎇${RST} ${YELLOW}${gitBranch}${RST}`,\n effortSeg ? `${modelSeg}${SEP}${effortSeg}` : modelSeg,\n `${ctxColor}${makeBar(usedPctDisplay, 8)} ${usedPctDisplay}%${RST} ${DIM}·${RST} ${ctxText}`,\n `${GREY}5h${RST} ${fiveColor}${fiveRemain}%${RST} ${DIM}·${RST} ${GREY}7d${RST} ${sevenColor}${sevenRemain}%${RST}`,\n sessionSeg,\n ...(p.vortex?.version ? [`🌀 ${MAGENTA}v${safeSegment(p.vortex.version, 20)}${RST}`] : []),\n clock,\n ];\n return parts.join(SEP);\n }\n\n const l1 = [\n effortSeg ? `${modelSeg}${SEP}${effortSeg}` : modelSeg,\n `${ctxColor}${makeBar(usedPctDisplay, 10)} ${usedPctDisplay}%${RST} ${DIM}·${RST} ${ctxText}`,\n clock,\n `💰 ${BOLD}${YELLOW}$${d.costUsd.toFixed(2)}${RST}`,\n ].join(SEP);\n\n const cacheTotal = d.cacheReadTokens + d.cacheCreationTokens;\n const cachePct = cacheTotal > 0 ? Math.floor((d.cacheReadTokens * 100) / cacheTotal) : 0;\n const fiveReset = untilReset(d.fiveHourResetsAt, p.now);\n const sevenReset = untilReset(d.sevenDayResetsAt, p.now);\n const l2 = [\n `${GREY}5h${RST} ${fiveColor}${makeBar(fiveRemain, 8)} ${fiveRemain}%${RST}` +\n (fiveReset ? `${GREY}(${fiveReset})${RST}` : \"\"),\n `${GREY}7d${RST} ${sevenColor}${makeBar(sevenRemain, 8)} ${sevenRemain}%${RST}` +\n (sevenReset ? `${GREY}(${sevenReset})${RST}` : \"\"),\n `📦 ${GREEN}cache ${cachePct}%${RST}`,\n ].join(SEP);\n\n const l3 = [\n `📁 ${BLUE}${project}${RST}`,\n `${WHITE}⎇${RST} ${YELLOW}${gitBranch}${RST} ${GREY}${gitHash}${RST}`,\n `⏱ ${MAGENTA}${formatDuration(d.durationMs)}${RST}`,\n `${GREEN}+${d.linesAdded}${RST} ${RED}-${d.linesRemoved}${RST}`,\n sessionSeg,\n ].join(SEP);\n\n const lines = [l1, l2, l3];\n if (p.vortex) {\n let vx = `🌀 ${BOLD}${MAGENTA}VortEX${RST}`;\n if (p.vortex.version) vx += ` ${GREY}v${safeSegment(p.vortex.version, 20)}${RST}`;\n if (p.vortex.lastWorklog) vx += `${SEP}${GREY}last:${RST} ${safeSegment(p.vortex.lastWorklog, 70)}`;\n lines.push(vx);\n }\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Impure probes — every lookup is individually guarded; a failure falls back.\n// ---------------------------------------------------------------------------\n\nfunction gitOut(dir: string, args: readonly string[]): string {\n return execFileSync(\"git\", [\"-C\", dir, ...args], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n}\n\n/**\n * Claude Code reports `ultracode` as `xhigh`; the transcript keeps the last\n * `/effort` change notice. Read the transcript tail and return the level named\n * by the LAST such notice, or null. Best-effort by design — a format change\n * simply degrades the display to `xhigh`.\n */\nexport function sniffEffortFromTranscript(transcriptPath: string, maxBytes = 4_000_000): string | null {\n try {\n const size = statSync(transcriptPath).size;\n const start = Math.max(0, size - maxBytes);\n const length = size - start;\n if (length <= 0) return null;\n const buf = Buffer.alloc(length);\n const fd = openSync(transcriptPath, \"r\");\n try {\n readSync(fd, buf, 0, length, start);\n } finally {\n closeSync(fd);\n }\n const text = buf.toString(\"utf8\");\n const matches = text.match(/Set effort level to [a-z]+/g);\n if (!matches || matches.length === 0) return null;\n return matches[matches.length - 1]!.slice(\"Set effort level to \".length);\n } catch {\n return null;\n }\n}\n\n/** Count open Claude Code sessions (one `claude` process per session). Falls back to 1. */\nfunction countClaudeSessions(): number {\n try {\n if (process.platform === \"win32\") {\n const out = execFileSync(\"tasklist\", [], { encoding: \"utf8\", stdio: [\"ignore\", \"pipe\", \"ignore\"] });\n const n = (out.match(/claude\\.exe/gi) ?? []).length;\n return n > 0 ? n : 1;\n }\n const out = execFileSync(\"pgrep\", [\"-x\", \"claude\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n const n = out.split(/\\r?\\n/).filter(Boolean).length;\n return n > 0 ? n : 1;\n } catch {\n return 1;\n }\n}\n\n/** Newest worklog file name under `data/worklog` — by name, which sorts chronologically. */\nfunction newestWorklogName(repoRoot: string): string | null {\n try {\n const dir = join(repoRoot, \"data\", \"worklog\");\n const entries = readdirSync(dir, { recursive: true }) as string[];\n let best: string | null = null;\n for (const rel of entries) {\n const s = String(rel);\n if (!s.endsWith(\".md\") || s.endsWith(\"_INDEX.md\")) continue;\n if (best === null || s > best) best = s;\n }\n return best ? best.replace(/\\\\/g, \"/\").split(\"/\").pop()! : null;\n } catch {\n return null;\n }\n}\n\n/** Collect every environment lookup the renderer needs for this input. */\nexport function collectStatuslineProbes(d: StatuslineData, now = new Date()): StatuslineProbes {\n const dir = d.dir ?? process.cwd();\n\n let gitBranch = \"-\";\n let gitHash = \"-\";\n try {\n const branch = gitOut(dir, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n gitBranch = branch === \"HEAD\" ? \"detached\" : branch || \"-\";\n gitHash = gitOut(dir, [\"rev-parse\", \"--short\", \"HEAD\"]) || \"-\";\n } catch {\n // not a git repo / git absent — keep \"-\"\n }\n\n let vortex: StatuslineProbes[\"vortex\"] = null;\n try {\n if (existsSync(join(dir, \".agent\", \"vortex.json\"))) {\n let version: string | null = null;\n try {\n const pkg = JSON.parse(\n readFileSync(join(dir, \"node_modules\", \"@vortex-os\", \"base\", \"package.json\"), \"utf8\"),\n ) as { version?: string };\n version = typeof pkg.version === \"string\" ? pkg.version : null;\n } catch {\n // base not installed locally — show the VortEX line without a version\n }\n vortex = { version, lastWorklog: newestWorklogName(dir) };\n }\n } catch {\n vortex = null;\n }\n\n let effortLevel: string | null = null;\n if (d.effortLevel === \"xhigh\" && d.transcriptPath) {\n const sniffed = sniffEffortFromTranscript(d.transcriptPath);\n if (sniffed === \"ultracode\") effortLevel = \"ultracode\";\n }\n\n return {\n gitBranch,\n gitHash,\n sessionCount: countClaudeSessions(),\n vortex,\n effortLevel,\n now,\n };\n}\n\n// ---------------------------------------------------------------------------\n// `vortex statusline install [--lite]` — merge-safe settings wiring.\n// ---------------------------------------------------------------------------\n\n/** The statusLine command written by `install`. Mirrors the session hooks: bin-name resolution, fail-closed, self-silencing. */\nexport function statuslineCommand(lite: boolean): string {\n return `npx --no-install vortex statusline${lite ? \" lite\" : \"\"} || exit 0`;\n}\n\nexport interface StatuslineInstallResult {\n readonly status: \"installed\" | \"already-ours\" | \"kept-existing\";\n readonly settingsPath: string;\n readonly command?: string;\n /** Present when status is \"kept-existing\": the command we refused to overwrite. */\n readonly existing?: string;\n}\n\n/**\n * Merge `statusLine` into a settings object. NON-DESTRUCTIVE: an existing\n * statusLine that is not ours is kept (the user owns their bar) unless `force`.\n * Switching full↔lite of our own command counts as ours and is updated.\n */\nexport function ensureStatusline(\n existing: ClaudeSettings,\n lite: boolean,\n force = false,\n): { settings: ClaudeSettings; status: StatuslineInstallResult[\"status\"]; existing?: string } {\n const command = statuslineCommand(lite);\n const current = existing.statusLine as { type?: string; command?: string } | undefined;\n const currentCmd = typeof current?.command === \"string\" ? current.command : undefined;\n const isOurs =\n currentCmd === statuslineCommand(false) || currentCmd === statuslineCommand(true);\n // `already-ours` requires the whole entry to be well-formed — a matching\n // command under a wrong/missing `type` is rewritten (repaired) below.\n if (currentCmd === command && current?.type === \"command\") {\n return { settings: existing, status: \"already-ours\" };\n }\n if (current && !isOurs && !force) {\n return { settings: existing, status: \"kept-existing\", existing: currentCmd ?? JSON.stringify(current) };\n }\n return {\n settings: { ...existing, statusLine: { type: \"command\", command } },\n status: \"installed\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// CLI entry — `vortex statusline [lite] [install [--lite] [--force]]`\n// ---------------------------------------------------------------------------\n\n/**\n * Run the statusline CLI. `install` wires `.claude/settings.json` (at\n * `repoRoot`); anything else renders the bar from stdin JSON. A render must\n * never break the bar: bad/absent input prints nothing and exits 0.\n */\nexport async function runStatuslineCli(\n argv: readonly string[],\n repoRoot: string,\n out: (s: string) => void,\n err: (s: string) => void,\n): Promise<number> {\n if (argv[0] === \"install\") {\n const lite = argv.includes(\"--lite\");\n const force = argv.includes(\"--force\");\n const settingsPath = join(repoRoot, \".claude\", \"settings.json\");\n const existingText = existsSync(settingsPath) ? readFileSync(settingsPath, \"utf8\") : null;\n const parsed = parseSettings(existingText);\n const result = ensureStatusline(parsed, lite, force);\n if (result.status === \"installed\") {\n const { mkdirSync, writeFileSync } = await import(\"node:fs\");\n mkdirSync(join(repoRoot, \".claude\"), { recursive: true });\n writeFileSync(settingsPath, serializeSettings(result.settings), \"utf8\");\n }\n const payload: StatuslineInstallResult = {\n status: result.status,\n settingsPath,\n ...(result.status !== \"kept-existing\" ? { command: statuslineCommand(lite) } : {}),\n ...(result.existing !== undefined ? { existing: result.existing } : {}),\n };\n out(JSON.stringify(payload, null, 2) + \"\\n\");\n if (result.status === \"kept-existing\") {\n err(\n \"[vortex] statusLine already configured with a different command — kept it. Re-run with --force to replace.\\n\",\n );\n }\n return 0;\n }\n\n const mode: \"full\" | \"lite\" = argv[0] === \"lite\" ? \"lite\" : \"full\";\n if (process.stdin.isTTY) {\n // Typed by hand with no piped JSON — don't block waiting on stdin.\n err(\n \"[vortex] statusline renders Claude Code's statusLine stdin JSON — pipe it in, \" +\n \"or wire it up with `vortex statusline install [--lite]`.\\n\",\n );\n return 0;\n }\n let raw = \"\";\n try {\n raw = readFileSync(0, \"utf8\");\n } catch {\n raw = \"\";\n }\n if (!raw.trim()) return 0; // no input — print nothing, never an error in the bar\n let data: StatuslineData;\n try {\n data = parseStatuslineInput(raw);\n } catch {\n return 0; // malformed input — keep the bar blank rather than erroring\n }\n out(renderStatusline(data, collectStatuslineProbes(data), mode));\n return 0;\n}\n","/**\r\n * Hook wiring for `/vortex init`: make sure the instance's\r\n * `.claude/settings.json` registers the VortEX SessionStart / SessionEnd hooks,\r\n * so the boot report + worklog-net fire automatically without the user knowing\r\n * any command. NON-DESTRUCTIVE — like the MCP install merge, this preserves\r\n * every other hook and top-level field and only adds our two entries if absent.\r\n *\r\n * Pure functions here (parse / merge / detect); the command does the actual\r\n * file read/write around them. Keeping them pure makes the merge unit-testable\r\n * and the \"writes only what's missing\" guarantee verifiable.\r\n */\r\n\r\n// Hook commands invoke the published CLI via `npx`, NOT checkout-relative\r\n// `node plugins/...` paths. An npm-installed instance (`npm i @vortex-os/base`)\r\n// has no monorepo checkout — but it does have the `vortex` bin on disk (the\r\n// instance's local `node_modules/.bin`, or the global npm bin on PATH), so\r\n// `npx --no-install vortex session-{start,end}` runs it. Two deliberate choices:\r\n// • `--no-install` — a SessionStart/End hook fires automatically; bare\r\n// `npx vortex` would silently install an arbitrary `vortex` package from the\r\n// network on a cache miss. `--no-install` fails closed instead.\r\n// • Resolve by BIN NAME (no `-p @vortex-os/base`) — npx searches the current\r\n// folder's `node_modules/.bin` FIRST, then PATH, which includes a global\r\n// `npm i -g @vortex-os/base`. This is what makes `vortex global-setup` fire in\r\n// EVERY folder: a `-p <pkg>` form (this command's earlier shape) resolves only\r\n// a LOCAL install and ignores the global one — so the GLOBAL hook silently\r\n// no-opped everywhere except the instance folder, defeating global-setup's one\r\n// job. Resolving the bin instead keeps \"local install wins\" (so the instance's\r\n// pinned version still runs there) while letting the global bin cover all other\r\n// folders. The cost: a same-named `vortex` bin earlier on PATH/local could\r\n// shadow ours — but `--no-install` still blocks the network-install case and a\r\n// colliding bin is unlikely, an acceptable trade for the any-folder guarantee.\r\n// These map to the `session-start` / `session-end` subcommands of the CLI.\r\n//\r\n// The trailing `|| exit 0` makes the hook SELF-SILENCING: the global hook fires in\r\n// every folder, but `npx --no-install` still fails where NO `vortex` is resolvable\r\n// (no local install AND nothing on PATH) — and Claude Code surfaces a non-zero\r\n// SessionStart hook as a \"hook error\" to the user. `|| exit 0` swallows that\r\n// (exit 0 → no error notice; stderr not injected) so such folders stay quiet.\r\n// `||` + `exit 0` are valid in both cmd.exe (the default Windows child-process\r\n// shell) and POSIX sh. Keeping the per-instance and global commands BYTE-IDENTICAL\r\n// is what lets Claude Code dedup them (no double session-start in the instance).\r\nexport const SESSION_START_COMMAND =\r\n \"npx --no-install vortex session-start || exit 0\";\r\nexport const SESSION_END_COMMAND =\r\n \"npx --no-install vortex session-end || exit 0\";\r\n\r\n// Older command shapes a prior `init`/`global-setup` may have written. On the next\r\n// `ensureVortexHooks` run each migrates IN PLACE to the current command, so the\r\n// per-instance hook keeps matching the global one (and stays dedup-able). Covers\r\n// the `-p @vortex-os/base` form (self-silencing and its pre-`|| exit 0` variant)\r\n// that this command carried before resolution moved to the bare bin name.\r\nconst LEGACY_COMMANDS: Record<\"SessionStart\" | \"SessionEnd\", readonly string[]> = {\r\n SessionStart: [\r\n \"npx --no-install -p @vortex-os/base vortex session-start || exit 0\",\r\n \"npx --no-install -p @vortex-os/base vortex session-start\",\r\n ],\r\n SessionEnd: [\r\n \"npx --no-install -p @vortex-os/base vortex session-end || exit 0\",\r\n \"npx --no-install -p @vortex-os/base vortex session-end\",\r\n ],\r\n};\r\n\r\ninterface HookCommand {\r\n readonly type: \"command\";\r\n readonly command: string;\r\n}\r\ninterface HookGroup {\r\n readonly hooks: readonly HookCommand[];\r\n readonly matcher?: string;\r\n}\r\nexport interface ClaudeSettings {\r\n hooks?: {\r\n SessionStart?: HookGroup[];\r\n SessionEnd?: HookGroup[];\r\n [event: string]: HookGroup[] | undefined;\r\n };\r\n [key: string]: unknown;\r\n}\r\n\r\nexport interface EnsureHooksResult {\r\n readonly settings: ClaudeSettings;\r\n /**\r\n * Hook events that CHANGED — a VortEX entry was added, or a legacy one was\r\n * migrated/de-duplicated in place (empty when nothing changed). Callers should\r\n * key \"did we need to write?\" off `alreadyWired`, not the name \"added\".\r\n */\r\n readonly added: readonly (\"SessionStart\" | \"SessionEnd\")[];\r\n /** True when nothing changed — every VortEX hook was already present. */\r\n readonly alreadyWired: boolean;\r\n}\r\n\r\n/**\r\n * Parse existing settings.json text. Empty/whitespace → `{}` (fresh). Throws on\r\n * malformed JSON so the caller aborts rather than clobbering a hand-edited file.\r\n */\r\nexport function parseSettings(text: string | null | undefined): ClaudeSettings {\r\n const trimmed = (text ?? \"\").trim();\r\n if (trimmed.length === 0) return {};\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(trimmed);\r\n } catch (e) {\r\n throw new Error(\r\n `.claude/settings.json is not valid JSON — refusing to overwrite. Fix or remove it first. (${(e as Error).message})`,\r\n );\r\n }\r\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\r\n throw new Error(\".claude/settings.json is not a JSON object — refusing to overwrite.\");\r\n }\r\n return parsed as ClaudeSettings;\r\n}\r\n\r\n/**\r\n * Merge the VortEX hooks into an existing settings object WITHOUT mutating the\r\n * input. A hook event is left untouched if it already references our command\r\n * (idempotent); otherwise our group is appended alongside any existing groups.\r\n */\r\nexport function ensureVortexHooks(existing: ClaudeSettings | null | undefined): EnsureHooksResult {\r\n const base: ClaudeSettings = existing && typeof existing === \"object\" ? existing : {};\r\n const hooks = { ...(base.hooks ?? {}) };\r\n const added: (\"SessionStart\" | \"SessionEnd\")[] = [];\r\n\r\n const wire = (event: \"SessionStart\" | \"SessionEnd\", command: string) => {\r\n const legacy = LEGACY_COMMANDS[event];\r\n const src = hooks[event] ?? [];\r\n let changed = false;\r\n let kept = false; // already retained one entry with the current command?\r\n const groups: HookGroup[] = [];\r\n for (const g of src) {\r\n const hookList: HookCommand[] = [];\r\n for (const h of g.hooks ?? []) {\r\n // Migrate a LEGACY VortEX command to the current one (in place, so the\r\n // group's other hooks and its `matcher` are preserved).\r\n const migrated = legacy.includes(h.command);\r\n const cmd = migrated ? command : h.command;\r\n if (cmd === command) {\r\n if (kept) {\r\n changed = true; // drop a duplicate VortEX hook (e.g. legacy + current)\r\n continue;\r\n }\r\n kept = true;\r\n if (migrated) changed = true;\r\n hookList.push(migrated ? { ...h, command } : h);\r\n } else {\r\n hookList.push(h);\r\n }\r\n }\r\n if (hookList.length > 0) groups.push({ ...g, hooks: hookList });\r\n else changed = true; // group held only legacy/duplicate VortEX hooks → drop it\r\n }\r\n if (!kept) {\r\n groups.push({ hooks: [{ type: \"command\", command }] });\r\n changed = true;\r\n }\r\n hooks[event] = groups;\r\n if (changed) added.push(event);\r\n };\r\n\r\n wire(\"SessionStart\", SESSION_START_COMMAND);\r\n wire(\"SessionEnd\", SESSION_END_COMMAND);\r\n\r\n const settings: ClaudeSettings = { ...base, hooks };\r\n return { settings, added, alreadyWired: added.length === 0 };\r\n}\r\n\r\n/** Serialize settings the way Claude writes them (2-space, trailing newline). */\r\nexport function serializeSettings(settings: ClaudeSettings): string {\r\n return JSON.stringify(settings, null, 2) + \"\\n\";\r\n}\r\n"],"mappings":"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","names":["out","n"]}
package/dist/index.d.ts CHANGED
@@ -3334,6 +3334,130 @@ interface CatchUpOptions {
3334
3334
  }
3335
3335
  declare function catchUpSessions(ctx: ModuleContext, opts?: CatchUpOptions): Promise<CatchUpResult>;
3336
3336
 
3337
+ /**
3338
+ * `vortex statusline` — a Claude Code statusLine renderer.
3339
+ *
3340
+ * Claude Code pipes a JSON snapshot of the session (model, context window,
3341
+ * cost, rate limits, workspace) to the configured statusLine command on every
3342
+ * refresh and renders whatever the command prints. This module turns that
3343
+ * snapshot into a colored status bar:
3344
+ *
3345
+ * full (default, 3 lines + a VortEX line inside an instance):
3346
+ * 🧠 Fable 5 │ █ max │ █░░░░░░░░░ 12% · 120K/1M │ 🕐 22:25 │ 💰 $9.22
3347
+ * 5h ██████░░ 75%(2h13m) │ 7d ███████░ 96%(0d8h) │ 📦 cache 98%
3348
+ * 📁 my-project │ ⎇ main 2b0949d │ ⏱ 1h19m │ +78 -38 │ ⧉ 1
3349
+ * 🌀 VortEX v0.11.0 │ last: 2026-06-10_0452-….md
3350
+ *
3351
+ * lite (1 line):
3352
+ * 📁 my-project │ ⎇ main │ 🧠 Fable 5 │ █ max │ ░░░░░░░░ 12% · 120K/1M │ 5h 75% · 7d 96% │ ⧉ 1 │ 🌀 v0.11.0 │ 🕐 22:25
3353
+ *
3354
+ * Design notes:
3355
+ * - Rendering is PURE (`renderStatusline(data, probes, mode)`) — every
3356
+ * environment lookup (git, process list, clock, VortEX instance files) is
3357
+ * collected separately in `collectStatuslineProbes`, so the composition is
3358
+ * unit-testable without a repo or a terminal.
3359
+ * - Reasoning effort is shown as one bar whose height + color encode the
3360
+ * level. Claude Code reports `ultracode` as plain `xhigh` (ultracode is
3361
+ * "xhigh + workflow orchestration"), so when the level reads `xhigh` we
3362
+ * additionally sniff the session transcript for the last `/effort` change
3363
+ * notice — a best-effort heuristic that degrades to showing `xhigh`.
3364
+ * - Every probe is wrapped: a statusline must NEVER throw or block the bar —
3365
+ * on any failure a segment silently falls back to a neutral value.
3366
+ */
3367
+
3368
+ /** The slice of Claude Code's statusLine input JSON this renderer consumes. */
3369
+ interface StatuslineData {
3370
+ readonly modelName: string;
3371
+ /** Reasoning effort level as reported (`effort.level`), or null. */
3372
+ readonly effortLevel: string | null;
3373
+ readonly transcriptPath: string | null;
3374
+ /** Project directory (workspace.current_dir, falling back to cwd). */
3375
+ readonly dir: string | null;
3376
+ readonly contextWindowSize: number;
3377
+ /** Context used, percent — kept as reported (may be fractional). */
3378
+ readonly usedPercentage: number;
3379
+ readonly cacheReadTokens: number;
3380
+ readonly cacheCreationTokens: number;
3381
+ readonly costUsd: number;
3382
+ readonly durationMs: number;
3383
+ readonly linesAdded: number;
3384
+ readonly linesRemoved: number;
3385
+ readonly fiveHourUsedPct: number;
3386
+ readonly fiveHourResetsAt: number;
3387
+ readonly sevenDayUsedPct: number;
3388
+ readonly sevenDayResetsAt: number;
3389
+ }
3390
+ /** Environment lookups the renderer composes in — collected impurely, injected purely. */
3391
+ interface StatuslineProbes {
3392
+ readonly gitBranch: string;
3393
+ readonly gitHash: string;
3394
+ readonly sessionCount: number;
3395
+ /** Set when `dir` is a VortEX instance root; lastWorklog is the newest worklog file name. */
3396
+ readonly vortex: {
3397
+ readonly version: string | null;
3398
+ readonly lastWorklog: string | null;
3399
+ } | null;
3400
+ /** Effort level after the ultracode transcript sniff (null → use data.effortLevel). */
3401
+ readonly effortLevel: string | null;
3402
+ readonly now: Date;
3403
+ }
3404
+ /**
3405
+ * Make a dynamic string safe to put in a single-line ANSI bar: drop control
3406
+ * chars (incl. ESC — no injected sequences/newlines), collapse whitespace, and
3407
+ * truncate long values. The bar must render intact whatever a branch name,
3408
+ * model name, or worklog filename contains.
3409
+ */
3410
+ declare function safeSegment(s: string, max?: number): string;
3411
+ /** Parse Claude Code's statusLine stdin JSON into the fields the bar uses. Never throws on shape — only on non-JSON. */
3412
+ declare function parseStatuslineInput(text: string): StatuslineData;
3413
+ /** One-character effort meter: height + color encode the level (`█✦` for ultracode). */
3414
+ declare function effortMeter(level: string | null): {
3415
+ meter: string;
3416
+ color: string;
3417
+ } | null;
3418
+ /** `7` → `7`, `70_000` → `70K`, `1_200_000` → `1.2M` (token quantities). */
3419
+ declare function formatTokens(t: number): string;
3420
+ /** Window sizes render without a decimal: `200_000` → `200K`, `1_000_000` → `1M`. */
3421
+ declare function formatWindow(t: number): string;
3422
+ /** `█`-filled gauge, `width` cells, floor-scaled so 100% and only 100% fills it. */
3423
+ declare function makeBar(pct: number, width: number): string;
3424
+ /** Compose the status bar. Pure — see `collectStatuslineProbes` for the impure half. */
3425
+ declare function renderStatusline(d: StatuslineData, p: StatuslineProbes, mode?: "full" | "lite"): string;
3426
+ /**
3427
+ * Claude Code reports `ultracode` as `xhigh`; the transcript keeps the last
3428
+ * `/effort` change notice. Read the transcript tail and return the level named
3429
+ * by the LAST such notice, or null. Best-effort by design — a format change
3430
+ * simply degrades the display to `xhigh`.
3431
+ */
3432
+ declare function sniffEffortFromTranscript(transcriptPath: string, maxBytes?: number): string | null;
3433
+ /** Collect every environment lookup the renderer needs for this input. */
3434
+ declare function collectStatuslineProbes(d: StatuslineData, now?: Date): StatuslineProbes;
3435
+ /** The statusLine command written by `install`. Mirrors the session hooks: bin-name resolution, fail-closed, self-silencing. */
3436
+ declare function statuslineCommand(lite: boolean): string;
3437
+ interface StatuslineInstallResult {
3438
+ readonly status: "installed" | "already-ours" | "kept-existing";
3439
+ readonly settingsPath: string;
3440
+ readonly command?: string;
3441
+ /** Present when status is "kept-existing": the command we refused to overwrite. */
3442
+ readonly existing?: string;
3443
+ }
3444
+ /**
3445
+ * Merge `statusLine` into a settings object. NON-DESTRUCTIVE: an existing
3446
+ * statusLine that is not ours is kept (the user owns their bar) unless `force`.
3447
+ * Switching full↔lite of our own command counts as ours and is updated.
3448
+ */
3449
+ declare function ensureStatusline(existing: ClaudeSettings, lite: boolean, force?: boolean): {
3450
+ settings: ClaudeSettings;
3451
+ status: StatuslineInstallResult["status"];
3452
+ existing?: string;
3453
+ };
3454
+ /**
3455
+ * Run the statusline CLI. `install` wires `.claude/settings.json` (at
3456
+ * `repoRoot`); anything else renders the bar from stdin JSON. A render must
3457
+ * never break the bar: bad/absent input prints nothing and exits 0.
3458
+ */
3459
+ declare function runStatuslineCli(argv: readonly string[], repoRoot: string, out: (s: string) => void, err: (s: string) => void): Promise<number>;
3460
+
3337
3461
  interface ReindexResult {
3338
3462
  readonly dir: string;
3339
3463
  readonly status: "written" | "unchanged" | "missing";
@@ -4037,6 +4161,9 @@ declare const index_d_SESSION_END_COMMAND: typeof SESSION_END_COMMAND;
4037
4161
  declare const index_d_SESSION_START_COMMAND: typeof SESSION_START_COMMAND;
4038
4162
  type index_d_SessionStartHookReport = SessionStartHookReport;
4039
4163
  type index_d_SessionStartReport = SessionStartReport;
4164
+ type index_d_StatuslineData = StatuslineData;
4165
+ type index_d_StatuslineInstallResult = StatuslineInstallResult;
4166
+ type index_d_StatuslineProbes = StatuslineProbes;
4040
4167
  type index_d_UpdateCheckResult = UpdateCheckResult;
4041
4168
  type index_d_UpdateFileAction = UpdateFileAction;
4042
4169
  type index_d_UpdateFileActionKind = UpdateFileActionKind;
@@ -4063,6 +4190,7 @@ declare const index_d_checkBaseUpdate: typeof checkBaseUpdate;
4063
4190
  declare const index_d_collectAgenda: typeof collectAgenda;
4064
4191
  declare const index_d_collectCarryover: typeof collectCarryover;
4065
4192
  declare const index_d_collectSessionStartReport: typeof collectSessionStartReport;
4193
+ declare const index_d_collectStatuslineProbes: typeof collectStatuslineProbes;
4066
4194
  declare const index_d_compareSemver: typeof compareSemver;
4067
4195
  declare const index_d_computeCurateFingerprint: typeof computeCurateFingerprint;
4068
4196
  declare const index_d_countUncommitted: typeof countUncommitted;
@@ -4073,10 +4201,14 @@ declare const index_d_curateCommand: typeof curateCommand;
4073
4201
  declare const index_d_decisionCommand: typeof decisionCommand;
4074
4202
  declare const index_d_detectInterruptedGitOp: typeof detectInterruptedGitOp;
4075
4203
  declare const index_d_detectWorklogGaps: typeof detectWorklogGaps;
4204
+ declare const index_d_effortMeter: typeof effortMeter;
4205
+ declare const index_d_ensureStatusline: typeof ensureStatusline;
4076
4206
  declare const index_d_ensureVortexHooks: typeof ensureVortexHooks;
4077
4207
  declare const index_d_ensureWorklogEntry: typeof ensureWorklogEntry;
4078
4208
  declare const index_d_extractNextUp: typeof extractNextUp;
4079
4209
  declare const index_d_extractOpenTasks: typeof extractOpenTasks;
4210
+ declare const index_d_formatTokens: typeof formatTokens;
4211
+ declare const index_d_formatWindow: typeof formatWindow;
4080
4212
  declare const index_d_gapWindowSinceArg: typeof gapWindowSinceArg;
4081
4213
  declare const index_d_globalMemoryPath: typeof globalMemoryPath;
4082
4214
  declare const index_d_globalSettingsHasHook: typeof globalSettingsHasHook;
@@ -4089,9 +4221,11 @@ declare const index_d_isInstanceRoot: typeof isInstanceRoot;
4089
4221
  declare const index_d_isNewer: typeof isNewer;
4090
4222
  declare const index_d_isStableUpdate: typeof isStableUpdate;
4091
4223
  declare const index_d_logCommand: typeof logCommand;
4224
+ declare const index_d_makeBar: typeof makeBar;
4092
4225
  declare const index_d_ownershipManifestPath: typeof ownershipManifestPath;
4093
4226
  declare const index_d_parseAdoptArgs: typeof parseAdoptArgs;
4094
4227
  declare const index_d_parseSettings: typeof parseSettings;
4228
+ declare const index_d_parseStatuslineInput: typeof parseStatuslineInput;
4095
4229
  declare const index_d_pruneHandoffs: typeof pruneHandoffs;
4096
4230
  declare const index_d_queryNpmLatest: typeof queryNpmLatest;
4097
4231
  declare const index_d_readGlobalInstancePointer: typeof readGlobalInstancePointer;
@@ -4102,24 +4236,29 @@ declare const index_d_reindexCommand: typeof reindexCommand;
4102
4236
  declare const index_d_renderAgenda: typeof renderAgenda;
4103
4237
  declare const index_d_renderGlobalBlock: typeof renderGlobalBlock;
4104
4238
  declare const index_d_renderSessionStartReport: typeof renderSessionStartReport;
4239
+ declare const index_d_renderStatusline: typeof renderStatusline;
4105
4240
  declare const index_d_repairOwnershipManifest: typeof repairOwnershipManifest;
4106
4241
  declare const index_d_resolveRepoRoot: typeof resolveRepoRoot;
4107
4242
  declare const index_d_runCurateAccept: typeof runCurateAccept;
4108
4243
  declare const index_d_runCurateCandidates: typeof runCurateCandidates;
4109
4244
  declare const index_d_runCurateDecline: typeof runCurateDecline;
4110
4245
  declare const index_d_runCuratePreview: typeof runCuratePreview;
4246
+ declare const index_d_runStatuslineCli: typeof runStatuslineCli;
4111
4247
  declare const index_d_runTemplatesUpdate: typeof runTemplatesUpdate;
4112
4248
  declare const index_d_runVortexCli: typeof runVortexCli;
4249
+ declare const index_d_safeSegment: typeof safeSegment;
4113
4250
  declare const index_d_scanHandoffs: typeof scanHandoffs;
4114
4251
  declare const index_d_serializeSettings: typeof serializeSettings;
4115
4252
  declare const index_d_sessionStartCommand: typeof sessionStartCommand;
4253
+ declare const index_d_sniffEffortFromTranscript: typeof sniffEffortFromTranscript;
4254
+ declare const index_d_statuslineCommand: typeof statuslineCommand;
4116
4255
  declare const index_d_templateDestRelPath: typeof templateDestRelPath;
4117
4256
  declare const index_d_upsertGlobalBlock: typeof upsertGlobalBlock;
4118
4257
  declare const index_d_validateCuratePayload: typeof validateCuratePayload;
4119
4258
  declare const index_d_vortexCommand: typeof vortexCommand;
4120
4259
  declare const index_d_writeOwnershipManifest: typeof writeOwnershipManifest;
4121
4260
  declare namespace index_d {
4122
- export { type index_d_AgendaReport as AgendaReport, type index_d_AmbientRecallFactoryOptions as AmbientRecallFactoryOptions, type index_d_CatchUpOptions as CatchUpOptions, type index_d_CatchUpResult as CatchUpResult, type index_d_ClaudeSettings as ClaudeSettings, type index_d_CliIo as CliIo, type index_d_CollectAgendaOptions as CollectAgendaOptions, type index_d_CurateAcceptResult as CurateAcceptResult, type index_d_CurateActionKind as CurateActionKind, type index_d_CurateAnyProposal as CurateAnyProposal, type index_d_CurateCandidate as CurateCandidate, type index_d_CurateCandidatesResult as CurateCandidatesResult, type index_d_CurateDeclineResult as CurateDeclineResult, type index_d_CurateOptions as CurateOptions, type index_d_CuratePayload as CuratePayload, type index_d_CuratePayloadValidation as CuratePayloadValidation, type index_d_CuratePreviewResult as CuratePreviewResult, type index_d_CurateResult as CurateResult, index_d_DEFAULT_GAP_WINDOW_DAYS as DEFAULT_GAP_WINDOW_DAYS, type index_d_EnsureHooksResult as EnsureHooksResult, type index_d_EnsureWorklogResult as EnsureWorklogResult, type index_d_GitPullResult as GitPullResult, index_d_HANDOFF_ARCHIVE_DIR as HANDOFF_ARCHIVE_DIR, index_d_HANDOFF_DIR as HANDOFF_DIR, type index_d_HandoffCreateResult as HandoffCreateResult, type index_d_HandoffSummary as HandoffSummary, type index_d_HandoffWriteResult as HandoffWriteResult, type index_d_NewDecisionResult as NewDecisionResult, index_d_OWNERSHIP_SCHEMA as OWNERSHIP_SCHEMA, type index_d_OpenDecision as OpenDecision, type index_d_OpenTask as OpenTask, type index_d_OwnershipDiagnosis as OwnershipDiagnosis, type index_d_OwnershipEntry as OwnershipEntry, type index_d_OwnershipManifest as OwnershipManifest, type index_d_RecallOptions as RecallOptions, type index_d_RecentWorklog as RecentWorklog, type index_d_ReindexResult as ReindexResult, type index_d_RitualRegistryOptions as RitualRegistryOptions, index_d_SESSION_END_COMMAND as SESSION_END_COMMAND, index_d_SESSION_START_COMMAND as SESSION_START_COMMAND, type index_d_SessionStartHookReport as SessionStartHookReport, type index_d_SessionStartReport as SessionStartReport, type index_d_UpdateCheckResult as UpdateCheckResult, type index_d_UpdateFileAction as UpdateFileAction, type index_d_UpdateFileActionKind as UpdateFileActionKind, type index_d_VortexHelpResult as VortexHelpResult, type index_d_VortexInitResult as VortexInitResult, type index_d_VortexPlannedResult as VortexPlannedResult, type index_d_VortexResult as VortexResult, type index_d_VortexSyncResult as VortexSyncResult, type index_d_VortexSyncStep as VortexSyncStep, type index_d_VortexSyncStepId as VortexSyncStepId, type index_d_VortexSyncStepStatus as VortexSyncStepStatus, type index_d_VortexUpdateResult as VortexUpdateResult, type index_d_WorklogAppendResult as WorklogAppendResult, index_d_agendaCommand as agendaCommand, index_d_aggregateHandoff as aggregateHandoff, index_d_applyGlobalSetup as applyGlobalSetup, index_d_argvToSlash as argvToSlash, index_d_autoReindexMemory as autoReindexMemory, index_d_buildInstallCommand as buildInstallCommand, index_d_buildOwnershipManifest as buildOwnershipManifest, index_d_buildRegistry as buildRegistry, index_d_catchUpSessions as catchUpSessions, index_d_checkBaseUpdate as checkBaseUpdate, index_d_collectAgenda as collectAgenda, index_d_collectCarryover as collectCarryover, index_d_collectSessionStartReport as collectSessionStartReport, index_d_compareSemver as compareSemver, index_d_computeCurateFingerprint as computeCurateFingerprint, index_d_countUncommitted as countUncommitted, index_d_createAmbientRecaller as createAmbientRecaller, index_d_createHandoffSkeleton as createHandoffSkeleton, index_d_createRitualRegistry as createRitualRegistry, index_d_curateCommand as curateCommand, index_d_decisionCommand as decisionCommand, index_d_detectInterruptedGitOp as detectInterruptedGitOp, index_d_detectWorklogGaps as detectWorklogGaps, index_d_ensureVortexHooks as ensureVortexHooks, index_d_ensureWorklogEntry as ensureWorklogEntry, index_d_extractNextUp as extractNextUp, index_d_extractOpenTasks as extractOpenTasks, index_d_gapWindowSinceArg as gapWindowSinceArg, index_d_globalMemoryPath as globalMemoryPath, index_d_globalSettingsHasHook as globalSettingsHasHook, index_d_globalSettingsPath as globalSettingsPath, index_d_globalStatePath as globalStatePath, index_d_handoffCommand as handoffCommand, index_d_inspectGlobalSetup as inspectGlobalSetup, index_d_inspectOwnership as inspectOwnership, index_d_isInstanceRoot as isInstanceRoot, index_d_isNewer as isNewer, index_d_isStableUpdate as isStableUpdate, index_d_logCommand as logCommand, index_d_ownershipManifestPath as ownershipManifestPath, index_d_parseAdoptArgs as parseAdoptArgs, index_d_parseSettings as parseSettings, index_d_pruneHandoffs as pruneHandoffs, index_d_queryNpmLatest as queryNpmLatest, index_d_readGlobalInstancePointer as readGlobalInstancePointer, index_d_readInstalledBaseVersion as readInstalledBaseVersion, index_d_recallCommand as recallCommand, index_d_recordGlobalSetupDecline as recordGlobalSetupDecline, index_d_reindexCommand as reindexCommand, index_d_renderAgenda as renderAgenda, index_d_renderGlobalBlock as renderGlobalBlock, index_d_renderSessionStartReport as renderSessionStartReport, index_d_repairOwnershipManifest as repairOwnershipManifest, index_d_resolveRepoRoot as resolveRepoRoot, index_d_runCurateAccept as runCurateAccept, index_d_runCurateCandidates as runCurateCandidates, index_d_runCurateDecline as runCurateDecline, index_d_runCuratePreview as runCuratePreview, index_d_runTemplatesUpdate as runTemplatesUpdate, index_d_runVortexCli as runVortexCli, index_d_scanHandoffs as scanHandoffs, index_d_serializeSettings as serializeSettings, index_d_sessionStartCommand as sessionStartCommand, index_d_templateDestRelPath as templateDestRelPath, index_d_upsertGlobalBlock as upsertGlobalBlock, index_d_validateCuratePayload as validateCuratePayload, index_d_vortexCommand as vortexCommand, index_d_writeOwnershipManifest as writeOwnershipManifest };
4261
+ export { type index_d_AgendaReport as AgendaReport, type index_d_AmbientRecallFactoryOptions as AmbientRecallFactoryOptions, type index_d_CatchUpOptions as CatchUpOptions, type index_d_CatchUpResult as CatchUpResult, type index_d_ClaudeSettings as ClaudeSettings, type index_d_CliIo as CliIo, type index_d_CollectAgendaOptions as CollectAgendaOptions, type index_d_CurateAcceptResult as CurateAcceptResult, type index_d_CurateActionKind as CurateActionKind, type index_d_CurateAnyProposal as CurateAnyProposal, type index_d_CurateCandidate as CurateCandidate, type index_d_CurateCandidatesResult as CurateCandidatesResult, type index_d_CurateDeclineResult as CurateDeclineResult, type index_d_CurateOptions as CurateOptions, type index_d_CuratePayload as CuratePayload, type index_d_CuratePayloadValidation as CuratePayloadValidation, type index_d_CuratePreviewResult as CuratePreviewResult, type index_d_CurateResult as CurateResult, index_d_DEFAULT_GAP_WINDOW_DAYS as DEFAULT_GAP_WINDOW_DAYS, type index_d_EnsureHooksResult as EnsureHooksResult, type index_d_EnsureWorklogResult as EnsureWorklogResult, type index_d_GitPullResult as GitPullResult, index_d_HANDOFF_ARCHIVE_DIR as HANDOFF_ARCHIVE_DIR, index_d_HANDOFF_DIR as HANDOFF_DIR, type index_d_HandoffCreateResult as HandoffCreateResult, type index_d_HandoffSummary as HandoffSummary, type index_d_HandoffWriteResult as HandoffWriteResult, type index_d_NewDecisionResult as NewDecisionResult, index_d_OWNERSHIP_SCHEMA as OWNERSHIP_SCHEMA, type index_d_OpenDecision as OpenDecision, type index_d_OpenTask as OpenTask, type index_d_OwnershipDiagnosis as OwnershipDiagnosis, type index_d_OwnershipEntry as OwnershipEntry, type index_d_OwnershipManifest as OwnershipManifest, type index_d_RecallOptions as RecallOptions, type index_d_RecentWorklog as RecentWorklog, type index_d_ReindexResult as ReindexResult, type index_d_RitualRegistryOptions as RitualRegistryOptions, index_d_SESSION_END_COMMAND as SESSION_END_COMMAND, index_d_SESSION_START_COMMAND as SESSION_START_COMMAND, type index_d_SessionStartHookReport as SessionStartHookReport, type index_d_SessionStartReport as SessionStartReport, type index_d_StatuslineData as StatuslineData, type index_d_StatuslineInstallResult as StatuslineInstallResult, type index_d_StatuslineProbes as StatuslineProbes, type index_d_UpdateCheckResult as UpdateCheckResult, type index_d_UpdateFileAction as UpdateFileAction, type index_d_UpdateFileActionKind as UpdateFileActionKind, type index_d_VortexHelpResult as VortexHelpResult, type index_d_VortexInitResult as VortexInitResult, type index_d_VortexPlannedResult as VortexPlannedResult, type index_d_VortexResult as VortexResult, type index_d_VortexSyncResult as VortexSyncResult, type index_d_VortexSyncStep as VortexSyncStep, type index_d_VortexSyncStepId as VortexSyncStepId, type index_d_VortexSyncStepStatus as VortexSyncStepStatus, type index_d_VortexUpdateResult as VortexUpdateResult, type index_d_WorklogAppendResult as WorklogAppendResult, index_d_agendaCommand as agendaCommand, index_d_aggregateHandoff as aggregateHandoff, index_d_applyGlobalSetup as applyGlobalSetup, index_d_argvToSlash as argvToSlash, index_d_autoReindexMemory as autoReindexMemory, index_d_buildInstallCommand as buildInstallCommand, index_d_buildOwnershipManifest as buildOwnershipManifest, index_d_buildRegistry as buildRegistry, index_d_catchUpSessions as catchUpSessions, index_d_checkBaseUpdate as checkBaseUpdate, index_d_collectAgenda as collectAgenda, index_d_collectCarryover as collectCarryover, index_d_collectSessionStartReport as collectSessionStartReport, index_d_collectStatuslineProbes as collectStatuslineProbes, index_d_compareSemver as compareSemver, index_d_computeCurateFingerprint as computeCurateFingerprint, index_d_countUncommitted as countUncommitted, index_d_createAmbientRecaller as createAmbientRecaller, index_d_createHandoffSkeleton as createHandoffSkeleton, index_d_createRitualRegistry as createRitualRegistry, index_d_curateCommand as curateCommand, index_d_decisionCommand as decisionCommand, index_d_detectInterruptedGitOp as detectInterruptedGitOp, index_d_detectWorklogGaps as detectWorklogGaps, index_d_effortMeter as effortMeter, index_d_ensureStatusline as ensureStatusline, index_d_ensureVortexHooks as ensureVortexHooks, index_d_ensureWorklogEntry as ensureWorklogEntry, index_d_extractNextUp as extractNextUp, index_d_extractOpenTasks as extractOpenTasks, index_d_formatTokens as formatTokens, index_d_formatWindow as formatWindow, index_d_gapWindowSinceArg as gapWindowSinceArg, index_d_globalMemoryPath as globalMemoryPath, index_d_globalSettingsHasHook as globalSettingsHasHook, index_d_globalSettingsPath as globalSettingsPath, index_d_globalStatePath as globalStatePath, index_d_handoffCommand as handoffCommand, index_d_inspectGlobalSetup as inspectGlobalSetup, index_d_inspectOwnership as inspectOwnership, index_d_isInstanceRoot as isInstanceRoot, index_d_isNewer as isNewer, index_d_isStableUpdate as isStableUpdate, index_d_logCommand as logCommand, index_d_makeBar as makeBar, index_d_ownershipManifestPath as ownershipManifestPath, index_d_parseAdoptArgs as parseAdoptArgs, index_d_parseSettings as parseSettings, index_d_parseStatuslineInput as parseStatuslineInput, index_d_pruneHandoffs as pruneHandoffs, index_d_queryNpmLatest as queryNpmLatest, index_d_readGlobalInstancePointer as readGlobalInstancePointer, index_d_readInstalledBaseVersion as readInstalledBaseVersion, index_d_recallCommand as recallCommand, index_d_recordGlobalSetupDecline as recordGlobalSetupDecline, index_d_reindexCommand as reindexCommand, index_d_renderAgenda as renderAgenda, index_d_renderGlobalBlock as renderGlobalBlock, index_d_renderSessionStartReport as renderSessionStartReport, index_d_renderStatusline as renderStatusline, index_d_repairOwnershipManifest as repairOwnershipManifest, index_d_resolveRepoRoot as resolveRepoRoot, index_d_runCurateAccept as runCurateAccept, index_d_runCurateCandidates as runCurateCandidates, index_d_runCurateDecline as runCurateDecline, index_d_runCuratePreview as runCuratePreview, index_d_runStatuslineCli as runStatuslineCli, index_d_runTemplatesUpdate as runTemplatesUpdate, index_d_runVortexCli as runVortexCli, index_d_safeSegment as safeSegment, index_d_scanHandoffs as scanHandoffs, index_d_serializeSettings as serializeSettings, index_d_sessionStartCommand as sessionStartCommand, index_d_sniffEffortFromTranscript as sniffEffortFromTranscript, index_d_statuslineCommand as statuslineCommand, index_d_templateDestRelPath as templateDestRelPath, index_d_upsertGlobalBlock as upsertGlobalBlock, index_d_validateCuratePayload as validateCuratePayload, index_d_vortexCommand as vortexCommand, index_d_writeOwnershipManifest as writeOwnershipManifest };
4123
4262
  }
4124
4263
 
4125
4264
  export { index_d$9 as aiCodingPitfalls, index_d$d as core, index_d$a as dataLint, index_d$5 as decisionLog, index_d$4 as indexGenerator, index_d$2 as linkRewriter, index_d$b as memorySystem, index_d$1 as proactiveCurator, index_d$7 as reportGenerator, index_d$3 as runbooks, index_d as sessionRituals, index_d$c as slashCommands, index_d$8 as toolRules, index_d$6 as worklog };
package/dist/index.js CHANGED
@@ -1,6 +1,25 @@
1
+ import {
2
+ SESSION_END_COMMAND,
3
+ SESSION_START_COMMAND,
4
+ collectStatuslineProbes,
5
+ effortMeter,
6
+ ensureStatusline,
7
+ ensureVortexHooks,
8
+ formatTokens,
9
+ formatWindow,
10
+ makeBar,
11
+ parseSettings,
12
+ parseStatuslineInput,
13
+ renderStatusline,
14
+ runStatuslineCli,
15
+ safeSegment,
16
+ serializeSettings,
17
+ sniffEffortFromTranscript,
18
+ statuslineCommand
19
+ } from "./chunk-DWANI3LV.js";
1
20
  import {
2
21
  catchUpSessions
3
- } from "./chunk-7SNLVGBO.js";
22
+ } from "./chunk-3L5DLEGP.js";
4
23
  import {
5
24
  __export
6
25
  } from "./chunk-PZ5AY32C.js";
@@ -4258,6 +4277,7 @@ __export(dist_exports14, {
4258
4277
  collectAgenda: () => collectAgenda,
4259
4278
  collectCarryover: () => collectCarryover,
4260
4279
  collectSessionStartReport: () => collectSessionStartReport,
4280
+ collectStatuslineProbes: () => collectStatuslineProbes,
4261
4281
  compareSemver: () => compareSemver,
4262
4282
  computeCurateFingerprint: () => computeCurateFingerprint,
4263
4283
  countUncommitted: () => countUncommitted,
@@ -4268,10 +4288,14 @@ __export(dist_exports14, {
4268
4288
  decisionCommand: () => decisionCommand,
4269
4289
  detectInterruptedGitOp: () => detectInterruptedGitOp,
4270
4290
  detectWorklogGaps: () => detectWorklogGaps,
4291
+ effortMeter: () => effortMeter,
4292
+ ensureStatusline: () => ensureStatusline,
4271
4293
  ensureVortexHooks: () => ensureVortexHooks,
4272
4294
  ensureWorklogEntry: () => ensureWorklogEntry,
4273
4295
  extractNextUp: () => extractNextUp,
4274
4296
  extractOpenTasks: () => extractOpenTasks,
4297
+ formatTokens: () => formatTokens,
4298
+ formatWindow: () => formatWindow,
4275
4299
  gapWindowSinceArg: () => gapWindowSinceArg,
4276
4300
  globalMemoryPath: () => globalMemoryPath,
4277
4301
  globalSettingsHasHook: () => globalSettingsHasHook,
@@ -4284,9 +4308,11 @@ __export(dist_exports14, {
4284
4308
  isNewer: () => isNewer,
4285
4309
  isStableUpdate: () => isStableUpdate,
4286
4310
  logCommand: () => logCommand,
4311
+ makeBar: () => makeBar,
4287
4312
  ownershipManifestPath: () => ownershipManifestPath,
4288
4313
  parseAdoptArgs: () => parseAdoptArgs,
4289
4314
  parseSettings: () => parseSettings,
4315
+ parseStatuslineInput: () => parseStatuslineInput,
4290
4316
  pruneHandoffs: () => pruneHandoffs,
4291
4317
  queryNpmLatest: () => queryNpmLatest,
4292
4318
  readGlobalInstancePointer: () => readGlobalInstancePointer,
@@ -4297,17 +4323,22 @@ __export(dist_exports14, {
4297
4323
  renderAgenda: () => renderAgenda,
4298
4324
  renderGlobalBlock: () => renderGlobalBlock,
4299
4325
  renderSessionStartReport: () => renderSessionStartReport,
4326
+ renderStatusline: () => renderStatusline,
4300
4327
  repairOwnershipManifest: () => repairOwnershipManifest,
4301
4328
  resolveRepoRoot: () => resolveRepoRoot,
4302
4329
  runCurateAccept: () => runCurateAccept,
4303
4330
  runCurateCandidates: () => runCurateCandidates,
4304
4331
  runCurateDecline: () => runCurateDecline,
4305
4332
  runCuratePreview: () => runCuratePreview,
4333
+ runStatuslineCli: () => runStatuslineCli,
4306
4334
  runTemplatesUpdate: () => runTemplatesUpdate,
4307
4335
  runVortexCli: () => runVortexCli,
4336
+ safeSegment: () => safeSegment,
4308
4337
  scanHandoffs: () => scanHandoffs,
4309
4338
  serializeSettings: () => serializeSettings,
4310
4339
  sessionStartCommand: () => sessionStartCommand,
4340
+ sniffEffortFromTranscript: () => sniffEffortFromTranscript,
4341
+ statuslineCommand: () => statuslineCommand,
4311
4342
  templateDestRelPath: () => templateDestRelPath,
4312
4343
  upsertGlobalBlock: () => upsertGlobalBlock,
4313
4344
  validateCuratePayload: () => validateCuratePayload,
@@ -5209,84 +5240,6 @@ import { copyFile as copyFile2, mkdir as mkdir9, readdir as readdir16, readFile
5209
5240
  import { basename as basename7, dirname as dirname5, extname as extname11, join as join26, relative as relative5 } from "path";
5210
5241
  import { fileURLToPath } from "url";
5211
5242
 
5212
- // ../plugins/session-rituals/dist/ensure-hooks.js
5213
- var SESSION_START_COMMAND = "npx --no-install vortex session-start || exit 0";
5214
- var SESSION_END_COMMAND = "npx --no-install vortex session-end || exit 0";
5215
- var LEGACY_COMMANDS = {
5216
- SessionStart: [
5217
- "npx --no-install -p @vortex-os/base vortex session-start || exit 0",
5218
- "npx --no-install -p @vortex-os/base vortex session-start"
5219
- ],
5220
- SessionEnd: [
5221
- "npx --no-install -p @vortex-os/base vortex session-end || exit 0",
5222
- "npx --no-install -p @vortex-os/base vortex session-end"
5223
- ]
5224
- };
5225
- function parseSettings(text) {
5226
- const trimmed = (text ?? "").trim();
5227
- if (trimmed.length === 0)
5228
- return {};
5229
- let parsed;
5230
- try {
5231
- parsed = JSON.parse(trimmed);
5232
- } catch (e) {
5233
- throw new Error(`.claude/settings.json is not valid JSON \u2014 refusing to overwrite. Fix or remove it first. (${e.message})`);
5234
- }
5235
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
5236
- throw new Error(".claude/settings.json is not a JSON object \u2014 refusing to overwrite.");
5237
- }
5238
- return parsed;
5239
- }
5240
- function ensureVortexHooks(existing) {
5241
- const base = existing && typeof existing === "object" ? existing : {};
5242
- const hooks = { ...base.hooks ?? {} };
5243
- const added = [];
5244
- const wire = (event, command) => {
5245
- const legacy = LEGACY_COMMANDS[event];
5246
- const src = hooks[event] ?? [];
5247
- let changed = false;
5248
- let kept = false;
5249
- const groups = [];
5250
- for (const g of src) {
5251
- const hookList = [];
5252
- for (const h of g.hooks ?? []) {
5253
- const migrated = legacy.includes(h.command);
5254
- const cmd = migrated ? command : h.command;
5255
- if (cmd === command) {
5256
- if (kept) {
5257
- changed = true;
5258
- continue;
5259
- }
5260
- kept = true;
5261
- if (migrated)
5262
- changed = true;
5263
- hookList.push(migrated ? { ...h, command } : h);
5264
- } else {
5265
- hookList.push(h);
5266
- }
5267
- }
5268
- if (hookList.length > 0)
5269
- groups.push({ ...g, hooks: hookList });
5270
- else
5271
- changed = true;
5272
- }
5273
- if (!kept) {
5274
- groups.push({ hooks: [{ type: "command", command }] });
5275
- changed = true;
5276
- }
5277
- hooks[event] = groups;
5278
- if (changed)
5279
- added.push(event);
5280
- };
5281
- wire("SessionStart", SESSION_START_COMMAND);
5282
- wire("SessionEnd", SESSION_END_COMMAND);
5283
- const settings = { ...base, hooks };
5284
- return { settings, added, alreadyWired: added.length === 0 };
5285
- }
5286
- function serializeSettings(settings) {
5287
- return JSON.stringify(settings, null, 2) + "\n";
5288
- }
5289
-
5290
5243
  // ../plugins/session-rituals/dist/global-setup.js
5291
5244
  import { homedir } from "os";
5292
5245
  import { existsSync as existsSync10, readFileSync as readFileSync2 } from "fs";
@@ -8785,8 +8738,13 @@ function readCuratePayload(args) {
8785
8738
  async function runVortexCli(argv, io) {
8786
8739
  const out = io?.stdout ?? ((s) => process.stdout.write(s));
8787
8740
  const err = io?.stderr ?? ((s) => process.stderr.write(s));
8788
- const repoRoot = resolveRepoRoot();
8789
8741
  try {
8742
+ if (argv[0] === "statusline") {
8743
+ const { runStatuslineCli: runStatuslineCli2 } = await import("./statusline-NQKJ3NWD.js");
8744
+ const statuslineRoot = process.env.VORTEX_REPO_ROOT?.trim() || process.cwd();
8745
+ return runStatuslineCli2(argv.slice(1), statuslineRoot, out, err);
8746
+ }
8747
+ const repoRoot = resolveRepoRoot();
8790
8748
  if (argv[0] === "session-start") {
8791
8749
  await runSessionStart(repoRoot, out);
8792
8750
  return 0;
@@ -8825,6 +8783,7 @@ ${names}
8825
8783
  session-start \u2014 emit the start-of-session boot report (git pull + data counts + catch-up)
8826
8784
  session-end \u2014 no-op (kept for hook compatibility; worklog gap handling is at session-start)
8827
8785
  check-updates \u2014 check the npm registry for a newer @vortex-os/base (read-only; prints the exact update command)
8786
+ statusline \u2014 render the Claude Code status bar from stdin JSON (\`lite\` for 1-line; \`install [--lite]\` wires .claude/settings.json)
8828
8787
 
8829
8788
  Instance shortcuts (also available as \`/vortex <sub>\`):
8830
8789
  init \u2014 first-time setup: routers + data/ + hooks + slash-commands
@@ -8978,7 +8937,7 @@ async function runVectorizeSetup(repoRoot, out, err) {
8978
8937
  return;
8979
8938
  }
8980
8939
  cleanTmp();
8981
- const { vectorizeIndex } = await import("./vectorize-RBDBTSTW.js");
8940
+ const { vectorizeIndex } = await import("./vectorize-PN4Y7XMO.js");
8982
8941
  const result = await vectorizeIndex(ctx, { dbPath: tmpDb, allowDownload: true });
8983
8942
  const sqliteSpecifier = "better-sqlite3";
8984
8943
  const mod = await import(sqliteSpecifier);
@@ -9055,7 +9014,7 @@ async function runSessionStart(repoRoot, out) {
9055
9014
  let catchUp = null;
9056
9015
  if (config.autoRecord.archive) {
9057
9016
  try {
9058
- const { catchUpSessions: catchUpSessions2 } = await import("./catch-up-KIHTAUPX.js");
9017
+ const { catchUpSessions: catchUpSessions2 } = await import("./catch-up-GDDKPZHJ.js");
9059
9018
  catchUp = await catchUpSessions2(ctx);
9060
9019
  } catch {
9061
9020
  }
@@ -9084,7 +9043,7 @@ async function runSessionStart(repoRoot, out) {
9084
9043
  });
9085
9044
  if (action === "inline") {
9086
9045
  try {
9087
- const { vectorizeIndex } = await import("./vectorize-RBDBTSTW.js");
9046
+ const { vectorizeIndex } = await import("./vectorize-PN4Y7XMO.js");
9088
9047
  vectorized = await vectorizeIndex(ctx);
9089
9048
  } catch {
9090
9049
  }