zelari-code 1.8.3 → 1.9.2

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.
@@ -30754,12 +30754,12 @@ var init_fixPath = __esm({
30754
30754
  });
30755
30755
 
30756
30756
  // src/cli/main.ts
30757
- import React14 from "react";
30757
+ import React15 from "react";
30758
30758
  import { render } from "ink";
30759
30759
 
30760
30760
  // src/cli/app.tsx
30761
- import React9, { useState as useState8, useMemo, useCallback as useCallback5, useEffect as useEffect7, useRef as useRef6 } from "react";
30762
- import { Box as Box8, Static, useInput as useInput2, useStdin as useStdin2 } from "ink";
30761
+ import React10, { useState as useState8, useMemo, useCallback as useCallback5, useEffect as useEffect7 } from "react";
30762
+ import { Box as Box9, Static, useInput as useInput2, useStdin as useStdin2 } from "ink";
30763
30763
 
30764
30764
  // src/cli/components/InputBar.tsx
30765
30765
  import React from "react";
@@ -31273,8 +31273,7 @@ function StatusBar({
31273
31273
  costUsd = 0,
31274
31274
  cachedTokens = 0,
31275
31275
  contextUsed = 0,
31276
- contextLimit = 0,
31277
- brandVersion
31276
+ contextLimit = 0
31278
31277
  }) {
31279
31278
  const ctxLabel = contextLimit > 0 ? `${formatTokens(contextUsed)}/${formatTokens(contextLimit)}` : contextUsed > 0 ? formatTokens(contextUsed) : null;
31280
31279
  return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: phase2 === "plan" ? "yellow" : "green" }, phase2 === "plan" ? "\u25C7 plan" : "\u25C6 build"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(
@@ -31284,7 +31283,7 @@ function StatusBar({
31284
31283
  color: mode === "council" ? "magenta" : mode === "zelari" ? "green" : "cyan"
31285
31284
  },
31286
31285
  mode === "council" ? "council" : mode === "zelari" ? "zelari" : "agent"
31287
- ), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, brandVersion ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "white" }, "ZELARI"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " v", brandVersion), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId))));
31286
+ ), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, ctxLabel ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, ctxLabel), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, costUsd > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, formatCost(costUsd)), cachedTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", formatTokens(cachedTokens), " cached)") : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId))));
31288
31287
  }
31289
31288
 
31290
31289
  // src/cli/components/SelectList.tsx
@@ -31332,14 +31331,47 @@ function SelectList({
31332
31331
  // src/cli/components/Sidebar.tsx
31333
31332
  import React8 from "react";
31334
31333
  import { Box as Box7, Text as Text8 } from "ink";
31334
+
31335
+ // src/cli/components/brandArt.ts
31336
+ var BRAND_LOGO_ASCII = [
31337
+ " -#%=",
31338
+ " +%%%%#.",
31339
+ " :#%%%%%%%-",
31340
+ ":%%@@@@@@@@=",
31341
+ "-%@@@@@@@@@@@+",
31342
+ ":%@@@@@@%@@@@@@=",
31343
+ "-%%@@@@@.+%@@%@+",
31344
+ " -@@@@@@:%++%@=",
31345
+ "=*%@@@@@@:@@%=*@#+.",
31346
+ "%%%%%@@@@:+++-*%@@*",
31347
+ ".%%%%%@@@@@+%+=:%@@@@:",
31348
+ "*@@@@@@@@@@@@@%@@@@@@*"
31349
+ ].join("\n");
31350
+ var BRAND_LOGO_COMPACT = [
31351
+ " -#%=",
31352
+ " +%%%%#.",
31353
+ ":%%@@@@=",
31354
+ "*@@@@@@*"
31355
+ ].join("\n");
31356
+
31357
+ // src/cli/components/Sidebar.tsx
31358
+ var EMBLEM_BRAILLE = `\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F4\u28FF\u28F7\u28C6\u2840
31359
+ \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28F6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6\u2840
31360
+ \u2800\u2800\u2800\u2800\u2800\u2800\u28F0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6
31361
+ \u2800\u2800\u2800\u2800\u28A0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F7\u2844
31362
+ \u2800\u2800\u2800\u2800\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2819\u283B\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2806
31363
+ \u2800\u2800\u2800\u2800\u28C8\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2800\u28F7\u28EC\u285B\u28BF\u28FF\u28DF\u28C1
31364
+ \u2800\u2880\u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2800\u287F\u28BF\u287F\u2883\u28C8\u28FB\u28FF\u28FF\u28F6
31365
+ \u2800\u28FC\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E0\u28F4\u28C6\u283B\u280E\u28BF\u28FF\u28FF\u28FF\u28FF\u28E7
31366
+ \u28F0\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u2847`;
31335
31367
  var SIDEBAR_WIDTH = 28;
31336
31368
  var SIDEBAR_MIN_COLUMNS = 96;
31337
31369
  var SIDEBAR_HIDE_COLUMNS = 88;
31338
31370
  var SIDEBAR_MIN_ROWS = 16;
31339
31371
  var SIDEBAR_HIDE_ROWS = 14;
31340
- var MAX_FILES_SHORT = 4;
31341
- var MAX_FILES_TALL = 8;
31342
- var SIDEBAR_CHROME_LINES = 4;
31372
+ var BRAILLE_MIN_ROWS = 28;
31373
+ var MAX_FILES_SHORT = 6;
31374
+ var MAX_FILES_TALL = 10;
31343
31375
  function shouldShowSidebar(columns, rows) {
31344
31376
  return columns >= SIDEBAR_MIN_COLUMNS && rows >= SIDEBAR_MIN_ROWS;
31345
31377
  }
@@ -31349,18 +31381,19 @@ function sidebarVisibility(columns, rows, currentlyVisible) {
31349
31381
  }
31350
31382
  return shouldShowSidebar(columns, rows);
31351
31383
  }
31352
- function maxSidebarFiles(rows) {
31353
- const budget = Math.max(2, rows - 14 - SIDEBAR_CHROME_LINES);
31354
- const cap = rows >= 28 ? MAX_FILES_TALL : MAX_FILES_SHORT;
31355
- return Math.min(cap, budget);
31356
- }
31357
31384
  function truncatePath(p3, max) {
31358
31385
  if (p3.length <= max) return p3;
31359
31386
  return `\u2026${p3.slice(-(max - 1))}`;
31360
31387
  }
31388
+ function preferAsciiLogo() {
31389
+ if (process.env.ZELARI_ASCII_LOGO === "1") return true;
31390
+ if (process.env.ZELARI_ASCII_LOGO === "0") return false;
31391
+ return process.platform === "win32";
31392
+ }
31361
31393
  function Sidebar({ version: version2, changes, rows }) {
31362
- void version2;
31363
- const maxFiles = maxSidebarFiles(rows);
31394
+ const useBraille = !preferAsciiLogo() && rows >= BRAILLE_MIN_ROWS;
31395
+ const logoLines = useBraille ? EMBLEM_BRAILLE.split("\n") : BRAND_LOGO_COMPACT.split("\n");
31396
+ const maxFiles = rows >= BRAILLE_MIN_ROWS + 8 ? MAX_FILES_TALL : MAX_FILES_SHORT;
31364
31397
  const visible = changes.files.slice(0, maxFiles);
31365
31398
  const hidden = changes.files.length - visible.length;
31366
31399
  const innerWidth = SIDEBAR_WIDTH - 4;
@@ -31372,65 +31405,42 @@ function Sidebar({ version: version2, changes, rows }) {
31372
31405
  borderStyle: "single",
31373
31406
  borderColor: "gray",
31374
31407
  paddingX: 1,
31375
- flexShrink: 0,
31376
- height: Math.min(rows - 8, SIDEBAR_CHROME_LINES + maxFiles + 2),
31377
- overflow: "hidden"
31408
+ flexShrink: 0
31378
31409
  },
31379
- /* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, changes.branch ? truncatePath(changes.branch, 18) : "git")),
31410
+ /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", alignItems: "center" }, logoLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text8, { key: i, color: "cyan" }, line))),
31411
+ /* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "white" }, "ZELARI CODE")),
31412
+ /* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "v", version2, changes.branch ? ` \xB7 ${truncatePath(changes.branch, 12)}` : "")),
31380
31413
  /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "\u2500".repeat(innerWidth)),
31381
31414
  !changes.isRepo ? /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, italic: true }, "not a git repo") : changes.files.length === 0 ? /* @__PURE__ */ React8.createElement(Text8, { dimColor: true, italic: true }, "no changes") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "changes (", changes.files.length, ")"), visible.map((f) => /* @__PURE__ */ React8.createElement(FileRow, { key: f.path, file: f, pathWidth: innerWidth - 10 })), hidden > 0 && /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, " +", hidden, " more\u2026"))
31382
31415
  );
31383
31416
  }
31384
- function FileRow({ file: file2, pathWidth }) {
31417
+ function FileRow({
31418
+ file: file2,
31419
+ pathWidth
31420
+ }) {
31385
31421
  const name = truncatePath(file2.path, Math.max(6, pathWidth));
31386
31422
  return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text8, { wrap: "truncate" }, /* @__PURE__ */ React8.createElement(Text8, { color: file2.untracked ? "yellow" : "white" }, name), file2.untracked ? /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, " new") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, " +", file2.added ?? "\xB7"), /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, " -", file2.removed ?? "\xB7"))));
31387
31423
  }
31388
31424
 
31389
- // src/cli/components/brandArt.ts
31390
- var BRAND_LOGO_ASCII = [
31391
- " -#%=",
31392
- " +%%%%#.",
31393
- " :#%%%%%%%-",
31394
- ":%%@@@@@@@@=",
31395
- "-%@@@@@@@@@@@+",
31396
- ":%@@@@@@%@@@@@@=",
31397
- "-%%@@@@@.+%@@%@+",
31398
- " -@@@@@@:%++%@=",
31399
- "=*%@@@@@@:@@%=*@#+.",
31400
- "%%%%%@@@@:+++-*%@@*",
31401
- ".%%%%%@@@@@+%+=:%@@@@:",
31402
- "*@@@@@@@@@@@@@%@@@@@@*"
31403
- ].join("\n");
31404
- var BRAND_LOGO_COMPACT = [
31405
- " -#%=",
31406
- " +%%%%#.",
31407
- ":%%@@@@=",
31408
- "*@@@@@@*"
31409
- ].join("\n");
31410
- function formatBannerWithLogoRight(opts) {
31411
- const logoSrc = opts.compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII;
31412
- const logoLines = logoSrc.split("\n");
31413
- const logoWidth = Math.max(...logoLines.map((l) => l.length));
31414
- const cols = Math.max(logoWidth + 20, Math.min(opts.columns, 120));
31415
- const left = [...opts.leftLines];
31416
- const wordmark = `ZELARI CODE v${opts.version}`;
31417
- const rightExtra = [wordmark];
31418
- const rightBlock = [...logoLines, ...rightExtra];
31419
- const rows = Math.max(left.length, rightBlock.length);
31420
- const out = [];
31421
- for (let i = 0; i < rows; i++) {
31422
- const L = left[i] ?? "";
31423
- const R = rightBlock[i] ?? "";
31424
- if (!R) {
31425
- out.push(L);
31426
- continue;
31427
- }
31428
- const maxLeft = Math.max(0, cols - R.length - 2);
31429
- const leftClipped = L.length > maxLeft ? L.slice(0, Math.max(0, maxLeft - 1)) + "\u2026" : L;
31430
- const pad = Math.max(2, cols - leftClipped.length - R.length);
31431
- out.push(leftClipped + " ".repeat(pad) + R);
31432
- }
31433
- return out.join("\n");
31425
+ // src/cli/components/StartupBanner.tsx
31426
+ import React9 from "react";
31427
+ import { Box as Box8, Text as Text9 } from "ink";
31428
+ function StartupBanner({
31429
+ version: version2,
31430
+ providerId,
31431
+ model,
31432
+ cwd,
31433
+ columns,
31434
+ rows
31435
+ }) {
31436
+ const compact = columns < 72 || rows < 20;
31437
+ const logo = (compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII).split("\n");
31438
+ const leftLines = [
31439
+ `zelari-code v${version2} \u2014 ${providerId}/${model}`,
31440
+ `cwd: ${cwd}`,
31441
+ `/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode`
31442
+ ];
31443
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, width: "100%" }, /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexGrow: 1, marginRight: 2 }, leftLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text9, { key: i, color: i === 0 ? "cyan" : void 0, dimColor: i > 0 }, line))), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexShrink: 0, alignItems: "flex-end" }, logo.map((line, i) => /* @__PURE__ */ React9.createElement(Text9, { key: i, color: "cyan" }, line)), /* @__PURE__ */ React9.createElement(Text9, { bold: true, color: "white" }, "ZELARI CODE"), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "v", version2)));
31434
31444
  }
31435
31445
 
31436
31446
  // src/cli/modelDiscovery.ts
@@ -36311,6 +36321,10 @@ function nextMode(current) {
36311
36321
  const i = MODES.indexOf(current);
36312
36322
  return MODES[(i + 1) % MODES.length] ?? "agent";
36313
36323
  }
36324
+ function parseMode(input) {
36325
+ const v = input.trim().toLowerCase();
36326
+ return MODES.includes(v) ? v : null;
36327
+ }
36314
36328
  function describeMode(mode) {
36315
36329
  switch (mode) {
36316
36330
  case "council":
@@ -38065,89 +38079,73 @@ function App() {
38065
38079
  }
38066
38080
  setPicker(null);
38067
38081
  }, [picker]);
38068
- const bannerColsRef = useRef6(null);
38069
- if (bannerColsRef.current === null) {
38070
- bannerColsRef.current = size.columns > 0 ? size.columns : 80;
38071
- }
38072
38082
  const banner = useMemo(() => {
38073
- const cols = bannerColsRef.current ?? 80;
38074
- const content = formatBannerWithLogoRight({
38075
- leftLines: [
38076
- `zelari-code \xB7 ${activeProviderSpec.id}/${activeModel}`,
38077
- `cwd: ${cwd}`,
38078
- `/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode`
38079
- ],
38080
- version: VERSION,
38081
- columns: cols,
38082
- compact: cols < 72
38083
- });
38084
38083
  return {
38085
38084
  id: "banner-once",
38086
38085
  role: "system",
38087
38086
  ts: 0,
38088
- content
38087
+ content: ""
38089
38088
  };
38090
- }, [activeProviderSpec.id, activeModel, cwd]);
38089
+ }, []);
38091
38090
  const [sidebarOpen, setSidebarOpen] = useState8(false);
38092
38091
  useEffect7(() => {
38093
38092
  setSidebarOpen((prev2) => sidebarVisibility(size.columns, size.rows, prev2));
38094
38093
  }, [size.columns, size.rows]);
38095
38094
  const staticKey = `${session.sessionId || "pre-bootstrap"}-${clearEpoch}`;
38096
38095
  const staticItems = session.sessionId ? [banner, ...session.messages] : [];
38097
- const dynamicMaxRows = Math.max(8, Math.min(18, size.rows - 2));
38098
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Static, { key: staticKey, items: staticItems }, (item) => renderMessage(item)), /* @__PURE__ */ React9.createElement(
38099
- Box8,
38096
+ return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Static, { key: staticKey, items: staticItems }, (item) => item.id === "banner-once" ? /* @__PURE__ */ React10.createElement(
38097
+ StartupBanner,
38100
38098
  {
38101
- flexDirection: "row",
38102
- width: size.columns > 0 ? size.columns : void 0,
38103
- height: dynamicMaxRows,
38104
- overflow: "hidden"
38105
- },
38106
- /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexGrow: 1, paddingX: 1, overflow: "hidden" }, /* @__PURE__ */ React9.createElement(LiveRegion, { live: session.live, busy, elapsedMs: timer.elapsedMs }), picker ? /* @__PURE__ */ React9.createElement(
38107
- SelectList,
38108
- {
38109
- title: picker.title,
38110
- items: picker.items,
38111
- onSelect: onPickerSelect,
38112
- onCancel: onPickerCancel,
38113
- maxVisible: Math.max(3, Math.min(8, size.rows - 12))
38114
- }
38115
- ) : /* @__PURE__ */ React9.createElement(
38116
- InputBar,
38117
- {
38118
- value: input,
38119
- onChange: setInput,
38120
- onSubmit: handleSubmit,
38121
- disabled: busy
38122
- }
38123
- ), /* @__PURE__ */ React9.createElement(
38124
- StatusBar,
38125
- {
38126
- model: activeModel,
38127
- provider: activeProviderSpec.id,
38128
- sessionId: session.sessionId ? session.sessionId.slice(0, 8) : "...",
38129
- sessionActive: session.sessionActive,
38130
- queueCount: chatTurn.queueCount,
38131
- busy,
38132
- mode,
38133
- phase: phase2,
38134
- cwd,
38135
- elapsedMs: timer.elapsedMs,
38136
- lastMs: timer.lastMs,
38137
- costUsd: sessionStats.totalCostUsd,
38138
- cachedTokens: sessionStats.cachedTokens,
38139
- contextUsed: sessionStats.contextTokens || 0,
38140
- contextLimit: Number(process.env.ZELARI_CONTEXT_LIMIT) || 2e5,
38141
- brandVersion: VERSION
38142
- }
38143
- )),
38144
- sidebarOpen && /* @__PURE__ */ React9.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })
38145
- ));
38099
+ key: item.id,
38100
+ version: VERSION,
38101
+ providerId: activeProviderSpec.id,
38102
+ model: activeModel,
38103
+ cwd,
38104
+ columns: size.columns || 80,
38105
+ rows: size.rows || 24
38106
+ }
38107
+ ) : renderMessage(item)), /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", flexGrow: 1, paddingX: 1 }, /* @__PURE__ */ React10.createElement(LiveRegion, { live: session.live, busy, elapsedMs: timer.elapsedMs }), picker ? /* @__PURE__ */ React10.createElement(
38108
+ SelectList,
38109
+ {
38110
+ title: picker.title,
38111
+ items: picker.items,
38112
+ onSelect: onPickerSelect,
38113
+ onCancel: onPickerCancel,
38114
+ maxVisible: Math.max(4, Math.min(10, size.rows - 10))
38115
+ }
38116
+ ) : /* @__PURE__ */ React10.createElement(
38117
+ InputBar,
38118
+ {
38119
+ value: input,
38120
+ onChange: setInput,
38121
+ onSubmit: handleSubmit,
38122
+ disabled: busy
38123
+ }
38124
+ ), /* @__PURE__ */ React10.createElement(
38125
+ StatusBar,
38126
+ {
38127
+ model: activeModel,
38128
+ provider: activeProviderSpec.id,
38129
+ sessionId: session.sessionId ? session.sessionId.slice(0, 8) : "...",
38130
+ sessionActive: session.sessionActive,
38131
+ queueCount: chatTurn.queueCount,
38132
+ busy,
38133
+ mode,
38134
+ phase: phase2,
38135
+ cwd,
38136
+ elapsedMs: timer.elapsedMs,
38137
+ lastMs: timer.lastMs,
38138
+ costUsd: sessionStats.totalCostUsd,
38139
+ cachedTokens: sessionStats.cachedTokens,
38140
+ contextUsed: sessionStats.contextTokens || 0,
38141
+ contextLimit: Number(process.env.ZELARI_CONTEXT_LIMIT) || 2e5
38142
+ }
38143
+ )), sidebarOpen && /* @__PURE__ */ React10.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })));
38146
38144
  }
38147
38145
 
38148
38146
  // src/cli/components/SplashScreen.tsx
38149
- import React10, { useEffect as useEffect8, useState as useState9 } from "react";
38150
- import { Box as Box9, Text as Text10, useInput as useInput3, useStdin as useStdin3 } from "ink";
38147
+ import React11, { useEffect as useEffect8, useState as useState9 } from "react";
38148
+ import { Box as Box10, Text as Text11, useInput as useInput3, useStdin as useStdin3 } from "ink";
38151
38149
  var SPLASH_DURATION_MS = 2e3;
38152
38150
  var EMBLEM_LARGE = ` =%@*-
38153
38151
  =%@@@@@#:
@@ -38283,8 +38281,8 @@ function Splash({ onDone, version: version2 }) {
38283
38281
  { isActive: isRawModeSupported === true }
38284
38282
  );
38285
38283
  if (!picked) return null;
38286
- return /* @__PURE__ */ React10.createElement(
38287
- Box9,
38284
+ return /* @__PURE__ */ React11.createElement(
38285
+ Box10,
38288
38286
  {
38289
38287
  flexDirection: "column",
38290
38288
  alignItems: "center",
@@ -38292,10 +38290,10 @@ function Splash({ onDone, version: version2 }) {
38292
38290
  width: columns,
38293
38291
  height: rows - 1
38294
38292
  },
38295
- /* @__PURE__ */ React10.createElement(Text10, { color: "cyan" }, picked.art),
38296
- /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text10, { bold: true, color: "white" }, "Z E L A R I C O D E")),
38297
- !picked.compact && /* @__PURE__ */ React10.createElement(Text10, { dimColor: true }, `${version2 ? `v${version2} \u2014 ` : ""}N-THEM Studio`),
38298
- !picked.compact && /* @__PURE__ */ React10.createElement(Text10, { dimColor: true, italic: true }, "press any key to skip")
38293
+ /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, picked.art),
38294
+ /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text11, { bold: true, color: "white" }, "Z E L A R I C O D E")),
38295
+ !picked.compact && /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, `${version2 ? `v${version2} \u2014 ` : ""}N-THEM Studio`),
38296
+ !picked.compact && /* @__PURE__ */ React11.createElement(Text11, { dimColor: true, italic: true }, "press any key to skip")
38299
38297
  );
38300
38298
  }
38301
38299
  function SplashGate({
@@ -38311,14 +38309,14 @@ function SplashGate({
38311
38309
  })
38312
38310
  );
38313
38311
  if (show) {
38314
- return /* @__PURE__ */ React10.createElement(Splash, { onDone: () => setShow(false), version: version2 });
38312
+ return /* @__PURE__ */ React11.createElement(Splash, { onDone: () => setShow(false), version: version2 });
38315
38313
  }
38316
- return /* @__PURE__ */ React10.createElement(React10.Fragment, null, children);
38314
+ return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
38317
38315
  }
38318
38316
 
38319
38317
  // src/cli/components/PluginGate.tsx
38320
- import React11, { useEffect as useEffect9, useState as useState10, useCallback as useCallback6 } from "react";
38321
- import { Box as Box10, Text as Text11, useStdin as useStdin4 } from "ink";
38318
+ import React12, { useEffect as useEffect9, useState as useState10, useCallback as useCallback6 } from "react";
38319
+ import { Box as Box11, Text as Text12, useStdin as useStdin4 } from "ink";
38322
38320
  init_registry2();
38323
38321
  init_prefs();
38324
38322
  var CHOICE_INSTALL = "__install__";
@@ -38407,20 +38405,20 @@ function PluginGate({ cwd, children }) {
38407
38405
  [current, cwd, advance]
38408
38406
  );
38409
38407
  if (phase2 === "done") {
38410
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
38408
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, children);
38411
38409
  }
38412
38410
  if (phase2 === "detecting") {
38413
- return /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "Checking for optional tool plugins\u2026"));
38411
+ return /* @__PURE__ */ React12.createElement(Box11, { paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "Checking for optional tool plugins\u2026"));
38414
38412
  }
38415
38413
  if (!current) {
38416
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
38414
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, children);
38417
38415
  }
38418
38416
  if (phase2 === "installing") {
38419
- return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, "\u23F3 Installing ", current.label, "\u2026"), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "npm install ", current.installScope === "global" ? "-g" : "-D", " ", current.npmPackage));
38417
+ return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, "\u23F3 Installing ", current.label, "\u2026"), /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "npm install ", current.installScope === "global" ? "-g" : "-D", " ", current.npmPackage));
38420
38418
  }
38421
38419
  if (phase2 === "result") {
38422
38420
  const ok = result?.ok === true;
38423
- return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: ok ? "green" : "red" }, ok ? "\u2713" : "\u2717", " ", ok ? "Installed" : "Install failed", ": ", current.label), !ok && result?.error ? /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, result.error) : null, ok && current.postInstallHint ? /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, " \u2192 ", current.postInstallHint) : null, /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "Press any key to continue\u2026"), /* @__PURE__ */ React11.createElement(ContinueKey, { onContinue: advance }));
38421
+ return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: ok ? "green" : "red" }, ok ? "\u2713" : "\u2717", " ", ok ? "Installed" : "Install failed", ": ", current.label), !ok && result?.error ? /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, result.error) : null, ok && current.postInstallHint ? /* @__PURE__ */ React12.createElement(Text12, { color: "yellow" }, " \u2192 ", current.postInstallHint) : null, /* @__PURE__ */ React12.createElement(Text12, { dimColor: true }, "Press any key to continue\u2026"), /* @__PURE__ */ React12.createElement(ContinueKey, { onContinue: advance }));
38424
38422
  }
38425
38423
  const items = [
38426
38424
  {
@@ -38431,7 +38429,7 @@ function PluginGate({ cwd, children }) {
38431
38429
  { value: CHOICE_LATER, label: "Maybe later" },
38432
38430
  { value: CHOICE_NEVER, label: "Don't ask again" }
38433
38431
  ];
38434
- return /* @__PURE__ */ React11.createElement(
38432
+ return /* @__PURE__ */ React12.createElement(
38435
38433
  SelectList,
38436
38434
  {
38437
38435
  title: `Optional plugin missing: ${current.label}`,
@@ -38493,15 +38491,15 @@ function parseWizardFlags(argv) {
38493
38491
  }
38494
38492
 
38495
38493
  // src/cli/wizard/runWizard.tsx
38496
- import React13, { useEffect as useEffect10, useState as useState11 } from "react";
38497
- import { Box as Box12, Text as Text13 } from "ink";
38494
+ import React14, { useEffect as useEffect10, useState as useState11 } from "react";
38495
+ import { Box as Box13, Text as Text14 } from "ink";
38498
38496
  import { useInput as useInput4 } from "ink";
38499
38497
  init_keyStore();
38500
38498
  init_providerConfig();
38501
38499
 
38502
38500
  // src/cli/wizard/index.tsx
38503
- import React12 from "react";
38504
- import { Box as Box11, Text as Text12 } from "ink";
38501
+ import React13 from "react";
38502
+ import { Box as Box12, Text as Text13 } from "ink";
38505
38503
 
38506
38504
  // src/cli/wizard/useWizardState.ts
38507
38505
  init_providerConfig();
@@ -38617,16 +38615,16 @@ var API_KEY_OPTIONS = ["env", "keystore", "skip"];
38617
38615
 
38618
38616
  // src/cli/wizard/index.tsx
38619
38617
  function Frame({ children }) {
38620
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, children);
38618
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, children);
38621
38619
  }
38622
38620
  function Step(props) {
38623
- return /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text12, { color: props.active ? "cyan" : "gray", inverse: props.active }, " ", props.index, "/", props.total, " ", props.name, " "));
38621
+ return /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text13, { color: props.active ? "cyan" : "gray", inverse: props.active }, " ", props.index, "/", props.total, " ", props.name, " "));
38624
38622
  }
38625
38623
  function renderProviderList(providers, cursor) {
38626
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, providers.map((p3, i) => {
38624
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, providers.map((p3, i) => {
38627
38625
  const arrow = i === cursor ? "\u279C " : " ";
38628
38626
  const color = i === cursor ? "cyan" : void 0;
38629
- return /* @__PURE__ */ React12.createElement(Text12, { key: p3.id, color }, arrow, p3.displayName, " ", /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "(", p3.id, ", uses env ", p3.envVar, ")"));
38627
+ return /* @__PURE__ */ React13.createElement(Text13, { key: p3.id, color }, arrow, p3.displayName, " ", /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "(", p3.id, ", uses env ", p3.envVar, ")"));
38630
38628
  }));
38631
38629
  }
38632
38630
  function renderApiKeyOptions(cursor) {
@@ -38635,18 +38633,18 @@ function renderApiKeyOptions(cursor) {
38635
38633
  keystore: "Save to local keyStore (encrypted)",
38636
38634
  skip: "Skip for now (chat will fail until key is set)"
38637
38635
  };
38638
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, API_KEY_OPTIONS.map((choice, i) => {
38636
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, API_KEY_OPTIONS.map((choice, i) => {
38639
38637
  const arrow = i === cursor ? "\u279C " : " ";
38640
38638
  const color = i === cursor ? "cyan" : void 0;
38641
- return /* @__PURE__ */ React12.createElement(Text12, { key: choice, color }, arrow, labels[choice]);
38639
+ return /* @__PURE__ */ React13.createElement(Text13, { key: choice, color }, arrow, labels[choice]);
38642
38640
  }));
38643
38641
  }
38644
38642
  function Wizard({ state: state2, providers }) {
38645
38643
  const s = state2.state;
38646
38644
  if (s.committed) {
38647
- return /* @__PURE__ */ React12.createElement(Frame, null, /* @__PURE__ */ React12.createElement(Text12, { color: "green" }, "\u2713 Setup complete!"), /* @__PURE__ */ React12.createElement(Text12, null, "Provider: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId), " | ", "Model: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.model), " | ", "API key: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.apiKeyChoice ?? "n/a")), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "Launching zelari-code\u2026 (press any key)")));
38645
+ return /* @__PURE__ */ React13.createElement(Frame, null, /* @__PURE__ */ React13.createElement(Text13, { color: "green" }, "\u2713 Setup complete!"), /* @__PURE__ */ React13.createElement(Text13, null, "Provider: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId), " | ", "Model: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.model), " | ", "API key: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.apiKeyChoice ?? "n/a")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "Launching zelari-code\u2026 (press any key)")));
38648
38646
  }
38649
- return /* @__PURE__ */ React12.createElement(Frame, null, /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", bold: true }, "zelari-code v", VERSION, " \u2014 first-time setup"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, marginBottom: 1, flexDirection: "row" }, /* @__PURE__ */ React12.createElement(Step, { index: 1, total: 5, name: "welcome", active: s.step === "welcome" }), /* @__PURE__ */ React12.createElement(Step, { index: 2, total: 5, name: "provider", active: s.step === "provider" }), /* @__PURE__ */ React12.createElement(Step, { index: 3, total: 5, name: "model", active: s.step === "model" }), /* @__PURE__ */ React12.createElement(Step, { index: 4, total: 5, name: "apikey", active: s.step === "apikey" }), /* @__PURE__ */ React12.createElement(Step, { index: 5, total: 5, name: "confirm", active: s.step === "confirm" })), s.step === "welcome" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Welcome! Let's get you coding in under two minutes."), /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "We'll pick a provider, default model, and how to handle your API key."), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press "), /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", inverse: true }, " Enter "), /* @__PURE__ */ React12.createElement(Text12, null, " to continue, or "), /* @__PURE__ */ React12.createElement(Text12, { color: "red", inverse: true }, " Q "), /* @__PURE__ */ React12.createElement(Text12, null, " to quit (re-run with "), /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "--no-wizard"), /* @__PURE__ */ React12.createElement(Text12, null, " to skip later)."))), s.step === "provider" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Choose your LLM provider:"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, renderProviderList(providers, s.providerCursor)), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "model" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Model for ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId), ":"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, s.model ?? "(empty)")), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", inverse: true }, " Enter "), "to accept, or type a new name. ", /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "(default kept on empty input)")))), s.step === "apikey" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "How should we handle the API key?"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, renderApiKeyOptions(s.apiKeyCursor)), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "confirm" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Confirm your setup:"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Text12, null, "Provider: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId)), /* @__PURE__ */ React12.createElement(Text12, null, "Model: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.model)), /* @__PURE__ */ React12.createElement(Text12, null, "API key: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.apiKeyChoice ?? "(unset)"))), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press ", /* @__PURE__ */ React12.createElement(Text12, { color: "green", inverse: true }, " Enter "), "to save and launch, or ", /* @__PURE__ */ React12.createElement(Text12, { color: "yellow", inverse: true }, " B "), "to go back."))));
38647
+ return /* @__PURE__ */ React13.createElement(Frame, null, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "zelari-code v", VERSION, " \u2014 first-time setup"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, marginBottom: 1, flexDirection: "row" }, /* @__PURE__ */ React13.createElement(Step, { index: 1, total: 5, name: "welcome", active: s.step === "welcome" }), /* @__PURE__ */ React13.createElement(Step, { index: 2, total: 5, name: "provider", active: s.step === "provider" }), /* @__PURE__ */ React13.createElement(Step, { index: 3, total: 5, name: "model", active: s.step === "model" }), /* @__PURE__ */ React13.createElement(Step, { index: 4, total: 5, name: "apikey", active: s.step === "apikey" }), /* @__PURE__ */ React13.createElement(Step, { index: 5, total: 5, name: "confirm", active: s.step === "confirm" })), s.step === "welcome" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Welcome! Let's get you coding in under two minutes."), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "We'll pick a provider, default model, and how to handle your API key."), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", inverse: true }, " Enter "), /* @__PURE__ */ React13.createElement(Text13, null, " to continue, or "), /* @__PURE__ */ React13.createElement(Text13, { color: "red", inverse: true }, " Q "), /* @__PURE__ */ React13.createElement(Text13, null, " to quit (re-run with "), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "--no-wizard"), /* @__PURE__ */ React13.createElement(Text13, null, " to skip later)."))), s.step === "provider" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Choose your LLM provider:"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, renderProviderList(providers, s.providerCursor)), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "model" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Model for ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId), ":"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, s.model ?? "(empty)")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", inverse: true }, " Enter "), "to accept, or type a new name. ", /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "(default kept on empty input)")))), s.step === "apikey" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "How should we handle the API key?"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, renderApiKeyOptions(s.apiKeyCursor)), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "confirm" && /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Confirm your setup:"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, null, "Provider: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.providerId)), /* @__PURE__ */ React13.createElement(Text13, null, "Model: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.model)), /* @__PURE__ */ React13.createElement(Text13, null, "API key: ", /* @__PURE__ */ React13.createElement(Text13, { color: "cyan" }, s.apiKeyChoice ?? "(unset)"))), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, null, "Press ", /* @__PURE__ */ React13.createElement(Text13, { color: "green", inverse: true }, " Enter "), "to save and launch, or ", /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", inverse: true }, " B "), "to go back."))));
38650
38648
  }
38651
38649
 
38652
38650
  // src/cli/wizard/runWizard.tsx
@@ -38722,9 +38720,9 @@ function RunWizard(_props) {
38722
38720
  }
38723
38721
  });
38724
38722
  if (wiz.state.committed) {
38725
- return /* @__PURE__ */ React13.createElement(PostCommitBridge, null);
38723
+ return /* @__PURE__ */ React14.createElement(PostCommitBridge, null);
38726
38724
  }
38727
- return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Wizard, { state: wiz, providers: PROVIDERS }));
38725
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React14.createElement(Wizard, { state: wiz, providers: PROVIDERS }));
38728
38726
  }
38729
38727
  function PostCommitBridge() {
38730
38728
  const [showApp, setShowApp] = useState11(false);
@@ -38733,22 +38731,26 @@ function PostCommitBridge() {
38733
38731
  return () => clearTimeout(t);
38734
38732
  }, []);
38735
38733
  if (showApp) {
38736
- return /* @__PURE__ */ React13.createElement(App, null);
38734
+ return /* @__PURE__ */ React14.createElement(App, null);
38737
38735
  }
38738
- return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, { color: "green", bold: true }, "\u2713 Setup complete! Launching zelari-code\u2026"), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "Press Ctrl+C any time to exit.")));
38736
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text14, { color: "green", bold: true }, "\u2713 Setup complete! Launching zelari-code\u2026"), /* @__PURE__ */ React14.createElement(Text14, { color: "gray" }, "Press Ctrl+C any time to exit.")));
38739
38737
  }
38740
38738
 
38741
38739
  // src/cli/headless.ts
38742
38740
  init_keyStore();
38743
38741
  init_providerConfig();
38744
38742
  init_openai_compatible();
38743
+ init_phase();
38745
38744
  function parseHeadlessFlags(argv) {
38746
38745
  if (!argv.includes("--headless")) {
38747
38746
  return { options: null };
38748
38747
  }
38749
38748
  let task;
38750
38749
  let output = "json";
38751
- let useCouncil = false;
38750
+ let mode = "agent";
38751
+ let phase2 = "build";
38752
+ let modeExplicit = false;
38753
+ let councilFlag = false;
38752
38754
  let provider;
38753
38755
  let model;
38754
38756
  for (let i = 0; i < argv.length; i++) {
@@ -38769,7 +38771,30 @@ function parseHeadlessFlags(argv) {
38769
38771
  task = argv[i + 1];
38770
38772
  i++;
38771
38773
  } else if (arg === "--council") {
38772
- useCouncil = true;
38774
+ councilFlag = true;
38775
+ } else if (arg === "--mode") {
38776
+ const next = argv[i + 1];
38777
+ const parsed = next ? parseMode(next) : null;
38778
+ if (!parsed) {
38779
+ return {
38780
+ options: null,
38781
+ error: `--mode requires 'agent', 'council', or 'zelari', got '${next ?? "(missing)"}'`
38782
+ };
38783
+ }
38784
+ mode = parsed;
38785
+ modeExplicit = true;
38786
+ i++;
38787
+ } else if (arg === "--phase") {
38788
+ const next = argv[i + 1];
38789
+ const parsed = next ? parsePhase(next) : null;
38790
+ if (!parsed) {
38791
+ return {
38792
+ options: null,
38793
+ error: `--phase requires 'plan' or 'build', got '${next ?? "(missing)"}'`
38794
+ };
38795
+ }
38796
+ phase2 = parsed;
38797
+ i++;
38773
38798
  } else if (arg === "--provider") {
38774
38799
  provider = argv[i + 1];
38775
38800
  i++;
@@ -38778,11 +38803,27 @@ function parseHeadlessFlags(argv) {
38778
38803
  i++;
38779
38804
  }
38780
38805
  }
38806
+ if (councilFlag && !modeExplicit) {
38807
+ mode = "council";
38808
+ } else if (councilFlag && modeExplicit && mode !== "council") {
38809
+ return {
38810
+ options: null,
38811
+ error: `--council conflicts with --mode ${mode}`
38812
+ };
38813
+ }
38781
38814
  if (!task || task.trim().length === 0) {
38782
38815
  return { options: null, error: "--headless requires --task <prompt>" };
38783
38816
  }
38784
38817
  return {
38785
- options: { task, output, useCouncil, provider, model }
38818
+ options: {
38819
+ task,
38820
+ output,
38821
+ mode,
38822
+ phase: phase2,
38823
+ useCouncil: mode === "council",
38824
+ provider,
38825
+ model
38826
+ }
38786
38827
  };
38787
38828
  }
38788
38829
  async function resolveHeadlessKey(providerId) {
@@ -38817,7 +38858,10 @@ init_harness();
38817
38858
  init_toolRegistry();
38818
38859
  init_skills2();
38819
38860
  init_envNumber();
38861
+ init_phaseState();
38862
+ init_phase();
38820
38863
  async function runHeadless(opts) {
38864
+ setPhase(opts.phase ?? "build");
38821
38865
  const { provider, model } = resolveHeadlessProvider(opts);
38822
38866
  const key = await resolveHeadlessKey(provider);
38823
38867
  if ("error" in key) {
@@ -38831,14 +38875,34 @@ async function runHeadless(opts) {
38831
38875
  baseUrl: key.baseUrl,
38832
38876
  model
38833
38877
  });
38834
- if (opts.useCouncil) {
38878
+ const mode = opts.mode ?? (opts.useCouncil ? "council" : "agent");
38879
+ if (opts.output === "json") {
38880
+ emitEvent({
38881
+ type: "log",
38882
+ message: `[headless] mode=${mode} phase=${opts.phase ?? "build"} provider=${provider} model=${model}`
38883
+ });
38884
+ } else {
38885
+ process.stderr.write(
38886
+ `[zelari-code --headless] mode=${mode} phase=${describePhase(opts.phase ?? "build")}
38887
+ `
38888
+ );
38889
+ }
38890
+ if (mode === "zelari") {
38891
+ return runHeadlessZelari(opts, provider, model, providerStream);
38892
+ }
38893
+ if (mode === "council" || opts.useCouncil) {
38835
38894
  return runHeadlessCouncil(opts, provider, model, providerStream);
38836
38895
  }
38837
38896
  return runHeadlessSingle(opts, provider, model, providerStream);
38838
38897
  }
38898
+ function planModeFromOpts(opts) {
38899
+ return (opts.phase ?? "build") === "plan";
38900
+ }
38839
38901
  async function runHeadlessSingle(opts, provider, model, providerStream) {
38840
38902
  const sessionId = crypto.randomUUID();
38841
- const { registry: toolRegistry } = createBuiltinToolRegistry();
38903
+ const { registry: toolRegistry } = createBuiltinToolRegistry({
38904
+ planMode: planModeFromOpts(opts)
38905
+ });
38842
38906
  const tools = toolRegistry.toOpenAITools().map((t) => ({
38843
38907
  name: t.function.name,
38844
38908
  description: t.function.description,
@@ -38861,10 +38925,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
38861
38925
  color: "#00d9a3",
38862
38926
  avatar: "\u25C6",
38863
38927
  tools: toolNames,
38864
- // v1.7.0 fix (agy audit): include platform/shell context in the role
38865
- // prompt so the agent knows its cwd and shell — previously this was
38866
- // empty (systemPrompt: '') and the agent lacked the platform block
38867
- // the TUI single-agent path gets.
38868
38928
  systemPrompt: [
38869
38929
  "# Platform",
38870
38930
  `platform: ${process.platform}`,
@@ -38873,7 +38933,10 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
38873
38933
  "# Working Directory",
38874
38934
  `You are running in: ${process.cwd()}`,
38875
38935
  "All relative file paths are resolved against this directory.",
38876
- "The shell is NON-INTERACTIVE (stdin closed): pass non-interactive flags (--yes, --force, --template)."
38936
+ "The shell is NON-INTERACTIVE (stdin closed): pass non-interactive flags (--yes, --force, --template).",
38937
+ "",
38938
+ `# Work phase: ${opts.phase ?? "build"}`,
38939
+ (opts.phase ?? "build") === "plan" ? "PLAN phase: explore and design only. Do not write project source files (write_file/edit_file/bash blocked). Plan artifacts under .zelari are allowed." : "BUILD phase: full tools; implement changes."
38877
38940
  ].join("\n")
38878
38941
  };
38879
38942
  systemPrompt = buildSystemPrompt(headlessRole, {
@@ -38952,18 +39015,11 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
38952
39015
  if (finalReason === "error") return 3;
38953
39016
  return exitCode;
38954
39017
  }
38955
- async function runHeadlessCouncil(opts, provider, model, providerStream) {
38956
- const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
38957
- const sessionId = crypto.randomUUID();
38958
- const { registry: toolRegistry } = createBuiltinToolRegistry();
38959
- const workspaceCtx = {
38960
- projectRoot: process.cwd(),
38961
- getActiveBranch: () => null
38962
- };
39018
+ async function buildCouncilToolRegistry(planMode) {
39019
+ const { registry: toolRegistry } = createBuiltinToolRegistry({ planMode });
38963
39020
  const { createWorkspaceContext: createWorkspaceContext2, createWorkspaceStubs: createWorkspaceStubs2 } = await Promise.resolve().then(() => (init_stubs(), stubs_exports));
38964
39021
  const { createWorkspaceToolRegistry: createWorkspaceToolRegistry2 } = await Promise.resolve().then(() => (init_toolRegistry2(), toolRegistry_exports2));
38965
39022
  const { setWorkspaceStubs: setWorkspaceStubs2 } = await Promise.resolve().then(() => (init_skills2(), skills_exports));
38966
- const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
38967
39023
  const realCtx = createWorkspaceContext2();
38968
39024
  const realReg = createWorkspaceToolRegistry2(realCtx);
38969
39025
  for (const name of realReg.list()) {
@@ -38971,6 +39027,13 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
38971
39027
  if (td) toolRegistry.register(td);
38972
39028
  }
38973
39029
  setWorkspaceStubs2(createWorkspaceStubs2(realCtx));
39030
+ return { toolRegistry, workspaceCtx: realCtx };
39031
+ }
39032
+ async function runHeadlessCouncil(opts, provider, model, providerStream) {
39033
+ const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
39034
+ const sessionId = crypto.randomUUID();
39035
+ const { toolRegistry } = await buildCouncilToolRegistry(planModeFromOpts(opts));
39036
+ const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
38974
39037
  const feedbackStore = new FeedbackStore2();
38975
39038
  let exitCode = 0;
38976
39039
  try {
@@ -38981,7 +39044,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
38981
39044
  providerStream,
38982
39045
  sessionId,
38983
39046
  tools: toolRegistry,
38984
- feedbackStore
39047
+ feedbackStore,
39048
+ runMode: planModeFromOpts(opts) ? "design-phase" : "implementation"
38985
39049
  })) {
38986
39050
  if (opts.output === "json") {
38987
39051
  emitEvent(event);
@@ -39002,6 +39066,378 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
39002
39066
  }
39003
39067
  return exitCode;
39004
39068
  }
39069
+ async function runHeadlessZelari(opts, provider, model, providerStream) {
39070
+ const projectRoot = process.cwd();
39071
+ const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
39072
+ const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
39073
+ const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
39074
+ const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
39075
+ const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
39076
+ const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
39077
+ const { runPostCouncilHook: runPostCouncilHook2 } = await Promise.resolve().then(() => (init_postCouncilHook(), postCouncilHook_exports));
39078
+ const brief = buildMissionBrief2({
39079
+ userMessage: opts.task,
39080
+ hasPlan: hasWorkspacePlan2(projectRoot)
39081
+ });
39082
+ const memory = await getMemoryBackend2(projectRoot);
39083
+ const { toolRegistry, workspaceCtx } = await buildCouncilToolRegistry(planModeFromOpts(opts));
39084
+ const feedbackStore = new FeedbackStore2();
39085
+ const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
39086
+ default: 30,
39087
+ min: 1
39088
+ });
39089
+ const emit = (message) => {
39090
+ if (opts.output === "json") {
39091
+ emitEvent({ type: "log", message });
39092
+ } else {
39093
+ process.stderr.write(message + "\n");
39094
+ }
39095
+ };
39096
+ emit(`[zelari] mission brief
39097
+ ${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMvp?.title }, null, 0)}`);
39098
+ let exitCode = 0;
39099
+ try {
39100
+ const state2 = await runZelariMission2(opts.task, brief, {
39101
+ projectRoot,
39102
+ memory,
39103
+ emit,
39104
+ runSlice: async ({ userMessage: slicePrompt, runMode, ragContext }) => {
39105
+ const sessionId = crypto.randomUUID();
39106
+ const fullPrompt = ragContext ? `${slicePrompt}
39107
+
39108
+ ## Memory context
39109
+ ${ragContext}` : slicePrompt;
39110
+ let synthesisText = "";
39111
+ let writeCount = 0;
39112
+ let chairmanErrored = false;
39113
+ let membersCompleted = 0;
39114
+ for await (const event of dispatchCouncil2(fullPrompt, {
39115
+ apiKey: "REDACTED",
39116
+ model,
39117
+ provider: "openai-compatible",
39118
+ providerStream,
39119
+ sessionId,
39120
+ tools: toolRegistry,
39121
+ feedbackStore,
39122
+ runMode: planModeFromOpts(opts) ? "design-phase" : runMode,
39123
+ maxToolCallsChairman: chairmanBudget
39124
+ })) {
39125
+ if (opts.output === "json") {
39126
+ emitEvent(event);
39127
+ } else if (event.type === "message_delta") {
39128
+ process.stdout.write(event.delta);
39129
+ }
39130
+ if (event.type === "message_delta" && typeof event.delta === "string") {
39131
+ synthesisText += event.delta;
39132
+ }
39133
+ if (event.type === "tool_execution_end") {
39134
+ const name = event.toolName ?? event.name ?? "";
39135
+ if (name === "write_file" || name === "edit_file" || name === "apply_diff") {
39136
+ writeCount += 1;
39137
+ }
39138
+ }
39139
+ if (event.type === "agent_end") {
39140
+ membersCompleted += 1;
39141
+ if (event.reason === "error") chairmanErrored = true;
39142
+ }
39143
+ if (event.type === "error" && event.severity === "fatal") {
39144
+ chairmanErrored = true;
39145
+ exitCode = 2;
39146
+ }
39147
+ }
39148
+ let completionOk = false;
39149
+ let degraded = false;
39150
+ try {
39151
+ const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
39152
+ const d = detectDegradedRun2({
39153
+ chairmanErrored,
39154
+ councilAborted: false,
39155
+ luciferWriteCount: writeCount,
39156
+ synthesisText,
39157
+ runMode
39158
+ });
39159
+ degraded = d.degraded;
39160
+ const hook = await runPostCouncilHook2(workspaceCtx, {
39161
+ runMode,
39162
+ userMessage: opts.task,
39163
+ synthesisText: synthesisText || void 0,
39164
+ degradedRun: d.degraded,
39165
+ degradedReasons: d.reasons
39166
+ });
39167
+ completionOk = hook.completion?.completion?.ok ?? false;
39168
+ if (completionOk) {
39169
+ emit(`[zelari] slice completion ok`);
39170
+ }
39171
+ } catch {
39172
+ }
39173
+ return {
39174
+ completionOk,
39175
+ ran: membersCompleted > 0 || synthesisText.length > 0,
39176
+ synthesisText: synthesisText || void 0,
39177
+ writeCount,
39178
+ degraded
39179
+ };
39180
+ }
39181
+ });
39182
+ if (state2.status === "error") exitCode = exitCode || 3;
39183
+ else if (state2.status === "success") exitCode = 0;
39184
+ else if (state2.status === "stalled" || state2.status === "stopped") exitCode = exitCode || 0;
39185
+ } catch (err) {
39186
+ process.stderr.write(
39187
+ `[zelari-code --headless] zelari error: ${err instanceof Error ? err.message : String(err)}
39188
+ `
39189
+ );
39190
+ return 2;
39191
+ } finally {
39192
+ await memory.close().catch(() => void 0);
39193
+ }
39194
+ return exitCode;
39195
+ }
39196
+
39197
+ // src/cli/desktopConfig.ts
39198
+ init_keyStore();
39199
+ init_providerConfig();
39200
+ init_updater();
39201
+ function wantsPrintConfig(argv) {
39202
+ return argv.includes("--print-config");
39203
+ }
39204
+ function wantsSetKey(argv) {
39205
+ return argv.includes("--set-key");
39206
+ }
39207
+ function wantsDiscoverModels(argv) {
39208
+ return argv.includes("--discover-models");
39209
+ }
39210
+ function parseSetConfigFlags(argv) {
39211
+ if (!argv.includes("--set-config")) {
39212
+ return { request: null };
39213
+ }
39214
+ let provider;
39215
+ let model;
39216
+ let endpoint;
39217
+ let endpointClear = false;
39218
+ for (let i = 0; i < argv.length; i++) {
39219
+ const arg = argv[i];
39220
+ if (arg === "--provider") {
39221
+ provider = argv[i + 1];
39222
+ i++;
39223
+ } else if (arg === "--model") {
39224
+ model = argv[i + 1];
39225
+ i++;
39226
+ } else if (arg === "--endpoint") {
39227
+ endpoint = argv[i + 1];
39228
+ i++;
39229
+ } else if (arg === "--endpoint-clear") {
39230
+ endpointClear = true;
39231
+ }
39232
+ }
39233
+ if (!provider && !model && !endpoint && !endpointClear) {
39234
+ return {
39235
+ request: null,
39236
+ error: "--set-config requires --provider, --model, --endpoint, and/or --endpoint-clear"
39237
+ };
39238
+ }
39239
+ if (provider !== void 0 && provider.trim().length === 0) {
39240
+ return { request: null, error: "--provider cannot be empty" };
39241
+ }
39242
+ if (model !== void 0 && model.trim().length === 0) {
39243
+ return { request: null, error: "--model cannot be empty" };
39244
+ }
39245
+ if (endpoint !== void 0 && endpoint.trim().length === 0) {
39246
+ return { request: null, error: "--endpoint cannot be empty" };
39247
+ }
39248
+ if (endpoint && endpointClear) {
39249
+ return { request: null, error: "--endpoint and --endpoint-clear conflict" };
39250
+ }
39251
+ return {
39252
+ request: {
39253
+ provider: provider?.trim(),
39254
+ model: model?.trim(),
39255
+ endpoint: endpoint?.trim(),
39256
+ endpointClear: endpointClear || void 0
39257
+ }
39258
+ };
39259
+ }
39260
+ function parseSetKeyFlags(argv) {
39261
+ if (!argv.includes("--set-key")) {
39262
+ return { request: null };
39263
+ }
39264
+ let provider;
39265
+ let key;
39266
+ for (let i = 0; i < argv.length; i++) {
39267
+ const arg = argv[i];
39268
+ if (arg === "--provider") {
39269
+ provider = argv[i + 1];
39270
+ i++;
39271
+ } else if (arg === "--key") {
39272
+ key = argv[i + 1];
39273
+ i++;
39274
+ }
39275
+ }
39276
+ if (!provider || provider.trim().length === 0) {
39277
+ return { request: null, error: "--set-key requires --provider <id>" };
39278
+ }
39279
+ if (!key || key.trim().length === 0) {
39280
+ return { request: null, error: "--set-key requires --key <secret>" };
39281
+ }
39282
+ return {
39283
+ request: {
39284
+ provider: provider.trim(),
39285
+ key: key.trim()
39286
+ }
39287
+ };
39288
+ }
39289
+ function parseDiscoverModelsFlags(argv) {
39290
+ if (!argv.includes("--discover-models")) {
39291
+ return { provider: null, present: false };
39292
+ }
39293
+ let provider;
39294
+ for (let i = 0; i < argv.length; i++) {
39295
+ if (argv[i] === "--provider") {
39296
+ provider = argv[i + 1];
39297
+ i++;
39298
+ }
39299
+ }
39300
+ return {
39301
+ present: true,
39302
+ provider: provider?.trim() || null
39303
+ };
39304
+ }
39305
+ function buildDesktopConfigSnapshot() {
39306
+ const config2 = getProviderConfig();
39307
+ const providers = PROVIDERS.map((p3) => {
39308
+ const cached2 = getCachedModels(p3.id);
39309
+ const models = cached2?.models.map((m) => m.id) ?? [];
39310
+ const defaultModel = config2.modelByProvider[p3.id] ?? "";
39311
+ if (defaultModel && !models.includes(defaultModel)) {
39312
+ models.unshift(defaultModel);
39313
+ }
39314
+ const custom2 = getCustomEndpoint(p3.id);
39315
+ const builtin = p3.baseUrl ?? null;
39316
+ return {
39317
+ id: p3.id,
39318
+ displayName: p3.displayName,
39319
+ hasKey: !!resolveApiKey(p3.id),
39320
+ envVar: p3.envVar,
39321
+ models,
39322
+ defaultModel,
39323
+ endpoint: custom2 ?? null,
39324
+ baseUrl: custom2 ?? builtin
39325
+ };
39326
+ });
39327
+ return {
39328
+ activeProviderId: config2.activeProviderId,
39329
+ modelByProvider: { ...config2.modelByProvider },
39330
+ providers,
39331
+ cliVersion: getCurrentVersion(),
39332
+ configPaths: {
39333
+ provider: getProviderConfigPath(),
39334
+ keys: getKeyStorePath()
39335
+ }
39336
+ };
39337
+ }
39338
+ function printDesktopConfig() {
39339
+ const snap = buildDesktopConfigSnapshot();
39340
+ process.stdout.write(JSON.stringify(snap, null, 2) + "\n");
39341
+ }
39342
+ function applySetConfig(req) {
39343
+ try {
39344
+ const config2 = getProviderConfig();
39345
+ let targetProvider = req.provider ?? config2.activeProviderId;
39346
+ if (req.provider) {
39347
+ const exists = PROVIDERS.some((p3) => p3.id === req.provider);
39348
+ if (!exists) {
39349
+ return {
39350
+ ok: false,
39351
+ error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p3) => p3.id).join(", ")}`
39352
+ };
39353
+ }
39354
+ setActiveProviderId(req.provider);
39355
+ targetProvider = req.provider;
39356
+ }
39357
+ if (req.endpointClear) {
39358
+ clearCustomEndpoint(targetProvider);
39359
+ }
39360
+ if (req.endpoint) {
39361
+ setCustomEndpoint(targetProvider, req.endpoint);
39362
+ }
39363
+ if (req.model) {
39364
+ setModelForProvider(targetProvider, req.model);
39365
+ }
39366
+ const after = getProviderConfig();
39367
+ const ep = getCustomEndpoint(after.activeProviderId);
39368
+ return {
39369
+ ok: true,
39370
+ message: `activeProvider=${after.activeProviderId} model=${after.modelByProvider[after.activeProviderId]}` + (ep ? ` endpoint=${ep}` : "")
39371
+ };
39372
+ } catch (err) {
39373
+ return {
39374
+ ok: false,
39375
+ error: err instanceof Error ? err.message : String(err)
39376
+ };
39377
+ }
39378
+ }
39379
+ function applySetKey(req) {
39380
+ try {
39381
+ const exists = PROVIDERS.some((p3) => p3.id === req.provider);
39382
+ if (!exists) {
39383
+ return {
39384
+ ok: false,
39385
+ error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p3) => p3.id).join(", ")}`
39386
+ };
39387
+ }
39388
+ setApiKey(req.provider, req.key);
39389
+ setActiveProviderId(req.provider);
39390
+ return {
39391
+ ok: true,
39392
+ provider: req.provider,
39393
+ masked: maskKey(req.key)
39394
+ };
39395
+ } catch (err) {
39396
+ return {
39397
+ ok: false,
39398
+ error: err instanceof Error ? err.message : String(err)
39399
+ };
39400
+ }
39401
+ }
39402
+ var DISCOVERABLE = [
39403
+ "grok",
39404
+ "glm",
39405
+ "minimax",
39406
+ "deepseek",
39407
+ "openai-compatible"
39408
+ ];
39409
+ async function runDiscoverModels(providerArg) {
39410
+ const config2 = getProviderConfig();
39411
+ const providerId = (providerArg ?? config2.activeProviderId).trim();
39412
+ if (!DISCOVERABLE.includes(providerId)) {
39413
+ if (providerId === "custom") {
39414
+ } else {
39415
+ return {
39416
+ ok: false,
39417
+ error: `provider '${providerId}' is not discoverable. Use: ${DISCOVERABLE.join(", ")}`
39418
+ };
39419
+ }
39420
+ }
39421
+ const discoveryId = providerId === "custom" ? "openai-compatible" : providerId;
39422
+ try {
39423
+ const entry = await discoverModelsForProvider(discoveryId);
39424
+ return {
39425
+ ok: true,
39426
+ payload: {
39427
+ ok: true,
39428
+ provider: providerId,
39429
+ models: entry.models.map((m) => m.id),
39430
+ fetchedAt: entry.fetchedAt,
39431
+ baseUrl: entry.baseUrl
39432
+ }
39433
+ };
39434
+ } catch (err) {
39435
+ return {
39436
+ ok: false,
39437
+ error: err instanceof Error ? err.message : String(err)
39438
+ };
39439
+ }
39440
+ }
39005
39441
 
39006
39442
  // src/cli/skillsMd.ts
39007
39443
  init_skills2();
@@ -39211,10 +39647,85 @@ function pickRootComponent() {
39211
39647
  }
39212
39648
  if (argv.includes("--help") || argv.includes("-h")) {
39213
39649
  console.log(
39214
- "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --council Use the 6-member council pipeline\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
39650
+ "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode agent|council|zelari Dispatch mode (default: agent)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --print-config Print provider/model config as JSON (no secrets)\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
39215
39651
  );
39216
39652
  process.exit(0);
39217
39653
  }
39654
+ if (wantsPrintConfig(argv)) {
39655
+ try {
39656
+ printDesktopConfig();
39657
+ process.exit(0);
39658
+ } catch (err) {
39659
+ console.error(
39660
+ `[zelari-code --print-config] ${err instanceof Error ? err.message : String(err)}`
39661
+ );
39662
+ process.exit(1);
39663
+ }
39664
+ }
39665
+ const setConfigParse = parseSetConfigFlags(argv);
39666
+ if (setConfigParse.error) {
39667
+ console.error(`[zelari-code --set-config] ${setConfigParse.error}`);
39668
+ process.exit(1);
39669
+ }
39670
+ if (setConfigParse.request) {
39671
+ const result = applySetConfig(setConfigParse.request);
39672
+ if (!result.ok) {
39673
+ console.error(`[zelari-code --set-config] ${result.error}`);
39674
+ process.exit(1);
39675
+ }
39676
+ console.log(JSON.stringify({ ok: true, message: result.message }));
39677
+ process.exit(0);
39678
+ }
39679
+ if (wantsSetKey(argv)) {
39680
+ const keyParse = parseSetKeyFlags(argv);
39681
+ if (keyParse.error || !keyParse.request) {
39682
+ console.error(
39683
+ `[zelari-code --set-key] ${keyParse.error ?? "invalid arguments"}`
39684
+ );
39685
+ process.exit(1);
39686
+ }
39687
+ const result = applySetKey(keyParse.request);
39688
+ if (!result.ok) {
39689
+ console.error(`[zelari-code --set-key] ${result.error}`);
39690
+ process.exit(1);
39691
+ }
39692
+ console.log(
39693
+ JSON.stringify({
39694
+ ok: true,
39695
+ provider: result.provider,
39696
+ masked: result.masked
39697
+ })
39698
+ );
39699
+ process.exit(0);
39700
+ }
39701
+ if (wantsDiscoverModels(argv)) {
39702
+ const disc = parseDiscoverModelsFlags(argv);
39703
+ void runDiscoverModels(disc.provider).then(async (result) => {
39704
+ if (!result.ok) {
39705
+ console.error(JSON.stringify({ ok: false, error: result.error }));
39706
+ await new Promise((r) => setImmediate(r));
39707
+ process.exit(1);
39708
+ return;
39709
+ }
39710
+ console.log(JSON.stringify(result.payload));
39711
+ try {
39712
+ await getMetricsLogger().flush();
39713
+ } catch {
39714
+ }
39715
+ await new Promise((r) => setImmediate(r));
39716
+ process.exit(0);
39717
+ }).catch(async (err) => {
39718
+ console.error(
39719
+ JSON.stringify({
39720
+ ok: false,
39721
+ error: err instanceof Error ? err.message : String(err)
39722
+ })
39723
+ );
39724
+ await new Promise((r) => setImmediate(r));
39725
+ process.exit(1);
39726
+ });
39727
+ return { kind: "done" };
39728
+ }
39218
39729
  const headlessParse = parseHeadlessFlags(argv);
39219
39730
  if (headlessParse.options !== null) {
39220
39731
  return { kind: "headless", headlessOpts: headlessParse.options };
@@ -39232,16 +39743,16 @@ function pickRootComponent() {
39232
39743
  });
39233
39744
  if (decision.shouldRun) {
39234
39745
  console.error(`[zelari-code] starting wizard: ${decision.reason}`);
39235
- return { kind: "wizard", element: React14.createElement(RunWizard) };
39746
+ return { kind: "wizard", element: React15.createElement(RunWizard) };
39236
39747
  }
39237
39748
  return {
39238
39749
  kind: "app",
39239
- element: React14.createElement(
39750
+ element: React15.createElement(
39240
39751
  SplashGate,
39241
39752
  { version: VERSION },
39242
- React14.createElement(PluginGate, {
39753
+ React15.createElement(PluginGate, {
39243
39754
  cwd: process.cwd(),
39244
- children: React14.createElement(App)
39755
+ children: React15.createElement(App)
39245
39756
  })
39246
39757
  )
39247
39758
  };
@@ -39267,10 +39778,27 @@ function main() {
39267
39778
  runPreflight();
39268
39779
  loadUserSkills();
39269
39780
  if (picked.kind === "headless") {
39270
- void runHeadless(picked.headlessOpts).then((code) => {
39271
- void getMetricsLogger().flush().catch(() => {
39272
- });
39781
+ void runHeadless(picked.headlessOpts).then(async (code) => {
39782
+ try {
39783
+ await getMetricsLogger().flush();
39784
+ } catch {
39785
+ }
39786
+ try {
39787
+ const { closeMcpClients: closeMcpClients2 } = await Promise.resolve().then(() => (init_mcpManager(), mcpManager_exports));
39788
+ closeMcpClients2();
39789
+ } catch {
39790
+ }
39791
+ await new Promise((resolve) => setImmediate(resolve));
39273
39792
  process.exit(code);
39793
+ }).catch(async (err) => {
39794
+ console.error(
39795
+ `[zelari-code --headless] fatal: ${err instanceof Error ? err.message : String(err)}`
39796
+ );
39797
+ try {
39798
+ await getMetricsLogger().flush();
39799
+ } catch {
39800
+ }
39801
+ process.exit(2);
39274
39802
  });
39275
39803
  return;
39276
39804
  }