@contentful/experience-design-system-cli 2.37.1-dev-build-a67bc4a4.0 → 2.37.1-dev-build-5efcf6e5.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.
package/dist/app.js CHANGED
@@ -32,7 +32,7 @@ var init_package_root = __esm({
32
32
  }
33
33
  });
34
34
 
35
- // packages/experience-design-system-cli/src/tui/home/version.ts
35
+ // packages/experience-design-system-cli/src/tui/upgrade/version.ts
36
36
  import { readFileSync as readFileSync2 } from "node:fs";
37
37
  import { join as join2 } from "node:path";
38
38
  import semver from "semver";
@@ -65,7 +65,7 @@ async function checkForUpgrade() {
65
65
  }
66
66
  var PACKAGE_NAME, TAGS_URL;
67
67
  var init_version = __esm({
68
- "packages/experience-design-system-cli/src/tui/home/version.ts"() {
68
+ "packages/experience-design-system-cli/src/tui/upgrade/version.ts"() {
69
69
  "use strict";
70
70
  init_package_root();
71
71
  PACKAGE_NAME = "@contentful/experience-design-system-cli";
@@ -837,7 +837,7 @@ async function runAgent(options) {
837
837
  promptLen: prompt.length,
838
838
  promptHead: prompt.slice(0, 500)
839
839
  });
840
- return new Promise((resolve27) => {
840
+ return new Promise((resolve28) => {
841
841
  const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : void 0;
842
842
  const child = spawn(binary, args, {
843
843
  stdio: ["pipe", "pipe", "pipe"],
@@ -886,7 +886,7 @@ async function runAgent(options) {
886
886
  stderrLen: stderr.length,
887
887
  stderrTail: stderr.slice(-1e3)
888
888
  });
889
- resolve27(result);
889
+ resolve28(result);
890
890
  });
891
891
  });
892
892
  }
@@ -908,7 +908,7 @@ async function checkAgentAuth(agent) {
908
908
  return "not-found";
909
909
  if (agent !== "claude")
910
910
  return "ok";
911
- return new Promise((resolve27) => {
911
+ return new Promise((resolve28) => {
912
912
  const child = spawn2(binary, ["auth", "status", "--json"], { stdio: ["ignore", "pipe", "pipe"] });
913
913
  let stdout = "";
914
914
  let done = false;
@@ -917,7 +917,7 @@ async function checkAgentAuth(agent) {
917
917
  return;
918
918
  done = true;
919
919
  child.kill("SIGTERM");
920
- resolve27("unauthenticated");
920
+ resolve28("unauthenticated");
921
921
  }, 5e3);
922
922
  child.stdout?.on("data", (chunk) => {
923
923
  stdout += chunk.toString();
@@ -928,14 +928,14 @@ async function checkAgentAuth(agent) {
928
928
  done = true;
929
929
  clearTimeout(timer);
930
930
  if (code !== 0) {
931
- resolve27("unauthenticated");
931
+ resolve28("unauthenticated");
932
932
  return;
933
933
  }
934
934
  try {
935
935
  const status = JSON.parse(stdout);
936
- resolve27(status.loggedIn ? "ok" : "unauthenticated");
936
+ resolve28(status.loggedIn ? "ok" : "unauthenticated");
937
937
  } catch {
938
- resolve27("unauthenticated");
938
+ resolve28("unauthenticated");
939
939
  }
940
940
  });
941
941
  });
@@ -945,9 +945,9 @@ async function binaryIsOnPath(binary) {
945
945
  const fs = await import("node:fs/promises");
946
946
  return fs.access(binary).then(() => true, () => false);
947
947
  }
948
- return new Promise((resolve27) => {
948
+ return new Promise((resolve28) => {
949
949
  const child = spawn2(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
950
- child.on("close", (code) => resolve27(code === 0));
950
+ child.on("close", (code) => resolve28(code === 0));
951
951
  });
952
952
  }
953
953
  var init_check_agent_auth = __esm({
@@ -2329,8 +2329,8 @@ var init_debug_store = __esm({
2329
2329
  });
2330
2330
 
2331
2331
  // packages/experience-design-system-cli/app.tsx
2332
- import { join as join25 } from "node:path";
2333
- import { useEffect as useEffect25, useState as useState32 } from "react";
2332
+ import { join as join26 } from "node:path";
2333
+ import { useEffect as useEffect28, useState as useState37 } from "react";
2334
2334
 
2335
2335
  // packages/experience-design-system-cli/src/tui/home/home.tsx
2336
2336
  import { useEffect as useEffect2, useState as useState2 } from "react";
@@ -2431,14 +2431,18 @@ var SUBTITLE = "Let's import your design system into Contentful";
2431
2431
  var MIN_TERMINAL_WIDTH = 164;
2432
2432
  var START_ITEMS = [
2433
2433
  { label: "Import", screen: "import" },
2434
+ { label: "Upgrade Version", screen: "upgrade" },
2434
2435
  { label: "Settings", screen: "settings" },
2435
2436
  { label: "Help", screen: "help" }
2436
2437
  ];
2437
- function versionStatus(upgradeCheck) {
2438
+ function upgradeItemDisplay(upgradeCheck) {
2438
2439
  if (upgradeCheck?.status === "update-available") {
2439
- return { text: ` (upgrade available v${upgradeCheck.latest})`, color: PALETTE.success };
2440
+ return { label: `Upgrade Version (v${upgradeCheck.latest} available)`, color: PALETTE.warning };
2440
2441
  }
2441
- return void 0;
2442
+ if (upgradeCheck?.status === "up-to-date") {
2443
+ return { label: "Upgrade Version (up to date)", color: PALETTE.muted };
2444
+ }
2445
+ return { label: "Upgrade Version" };
2442
2446
  }
2443
2447
  function HomeScreen({ onNavigate }) {
2444
2448
  const [focusIdx, setFocusIdx] = useState2(0);
@@ -2446,7 +2450,7 @@ function HomeScreen({ onNavigate }) {
2446
2450
  const { exit } = useApp();
2447
2451
  const terminalWidth = useTerminalWidth();
2448
2452
  const tooNarrow = terminalWidth < MIN_TERMINAL_WIDTH;
2449
- const status = versionStatus(upgradeCheck);
2453
+ const upgradeDisabled = upgradeCheck?.status === "up-to-date";
2450
2454
  useEffect2(() => {
2451
2455
  checkForUpgrade().then(setUpgradeCheck).catch(() => setUpgradeCheck({ status: "error" }));
2452
2456
  }, []);
@@ -2466,6 +2470,7 @@ function HomeScreen({ onNavigate }) {
2466
2470
  }
2467
2471
  if (key.return) {
2468
2472
  const item = START_ITEMS[focusIdx];
2473
+ if (item.screen === "upgrade" && upgradeDisabled) return;
2469
2474
  onNavigate(item.screen);
2470
2475
  return;
2471
2476
  }
@@ -2483,16 +2488,26 @@ function HomeScreen({ onNavigate }) {
2483
2488
  /* @__PURE__ */ jsx2(Text2, { color: PALETTE.muted, children: SUBTITLE }),
2484
2489
  /* @__PURE__ */ jsxs(Text2, { color: PALETTE.muted, children: [
2485
2490
  "v",
2486
- VERSION,
2487
- status && /* @__PURE__ */ jsx2(Text2, { color: status.color, children: status.text })
2491
+ VERSION
2488
2492
  ] })
2489
2493
  ] }),
2490
2494
  /* @__PURE__ */ jsx2(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: START_ITEMS.map((item, i) => {
2491
2495
  const focused = i === focusIdx;
2492
- return /* @__PURE__ */ jsxs(Text2, { bold: focused, color: focused ? PALETTE.accent : void 0, children: [
2493
- focused ? `${FOCUS_MARKER} ` : " ",
2496
+ const isUpgradeItem = item.screen === "upgrade";
2497
+ const display = isUpgradeItem ? upgradeItemDisplay(upgradeCheck) : { label: item.label };
2498
+ const dimmed = isUpgradeItem && upgradeDisabled;
2499
+ return /* @__PURE__ */ jsxs(
2500
+ Text2,
2501
+ {
2502
+ bold: focused && !dimmed,
2503
+ color: dimmed ? PALETTE.muted : focused ? PALETTE.accent : display.color,
2504
+ children: [
2505
+ focused ? `${FOCUS_MARKER} ` : " ",
2506
+ display.label
2507
+ ]
2508
+ },
2494
2509
  item.label
2495
- ] }, item.label);
2510
+ );
2496
2511
  }) }) }),
2497
2512
  /* @__PURE__ */ jsx2(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx2(
2498
2513
  ControlHints,
@@ -8438,10 +8453,10 @@ function extractVueSlotsFromSetup(options) {
8438
8453
  if (!body)
8439
8454
  return [];
8440
8455
  const slotsByName = /* @__PURE__ */ new Map();
8441
- for (const access6 of body.getDescendantsOfKind(SyntaxKind5.PropertyAccessExpression)) {
8442
- if (access6.getExpression().getText() !== slotsName)
8456
+ for (const access7 of body.getDescendantsOfKind(SyntaxKind5.PropertyAccessExpression)) {
8457
+ if (access7.getExpression().getText() !== slotsName)
8443
8458
  continue;
8444
- const slotName = access6.getName();
8459
+ const slotName = access7.getName();
8445
8460
  if (!slotsByName.has(slotName)) {
8446
8461
  slotsByName.set(slotName, {
8447
8462
  name: slotName,
@@ -13831,7 +13846,7 @@ function errorMessage(error) {
13831
13846
  return error instanceof Error && error.message ? error.message : String(error);
13832
13847
  }
13833
13848
  function defaultSleep(delayMs) {
13834
- return new Promise((resolve27) => setTimeout(resolve27, delayMs));
13849
+ return new Promise((resolve28) => setTimeout(resolve28, delayMs));
13835
13850
  }
13836
13851
 
13837
13852
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js
@@ -14072,7 +14087,7 @@ var ApiClient = class {
14072
14087
  const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
14073
14088
  const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
14074
14089
  const jitter = Math.random() * baseDelay * 0.15;
14075
- await new Promise((resolve27) => setTimeout(resolve27, baseDelay + jitter));
14090
+ await new Promise((resolve28) => setTimeout(resolve28, baseDelay + jitter));
14076
14091
  }
14077
14092
  }
14078
14093
  throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
@@ -14557,6 +14572,7 @@ function readTokensFromPath2(request) {
14557
14572
  init_agents();
14558
14573
  init_agent_name();
14559
14574
  init_models();
14575
+ init_binaries();
14560
14576
  init_is_agent_name();
14561
14577
  init_agent_supports_bedrock();
14562
14578
  init_check_agent_auth();
@@ -15115,11 +15131,11 @@ function setCommandContext(context) {
15115
15131
  mergeContext(state.pending.context, context);
15116
15132
  mergeContext(state.pending.completion, context);
15117
15133
  }
15118
- function enrichCommandResult(fields) {
15134
+ function enrichCommandResult(fields2) {
15119
15135
  if (!state.pending)
15120
15136
  return;
15121
- Object.assign(state.pending.completion, fields);
15122
- mergeContext(state.pending.context, fields);
15137
+ Object.assign(state.pending.completion, fields2);
15138
+ mergeContext(state.pending.context, fields2);
15123
15139
  }
15124
15140
 
15125
15141
  // packages/experience-design-system-backend-pipeline/dist/src/analytics/os.js
@@ -16381,7 +16397,7 @@ async function retryDatabaseWrite(operation, attempts = 8) {
16381
16397
  const message = error instanceof Error ? error.message : String(error);
16382
16398
  if (!/database is locked|database is busy/i.test(message) || attempt >= attempts)
16383
16399
  throw error;
16384
- await new Promise((resolve27) => setTimeout(resolve27, Math.min(250 * attempt, 2e3)));
16400
+ await new Promise((resolve28) => setTimeout(resolve28, Math.min(250 * attempt, 2e3)));
16385
16401
  }
16386
16402
  }
16387
16403
  }
@@ -22328,16 +22344,16 @@ function SlotRow({
22328
22344
  ] });
22329
22345
  }
22330
22346
  function propFields(prop) {
22331
- const fields = ["description", "required", "type"];
22347
+ const fields2 = ["description", "required", "type"];
22332
22348
  if (prop.type === "token") {
22333
- fields.push("tokenKind");
22349
+ fields2.push("tokenKind");
22334
22350
  }
22335
- if (prop.type === "enum") fields.push("values");
22351
+ if (prop.type === "enum") fields2.push("values");
22336
22352
  if (prop.type !== "richtext" && prop.type !== "media" && prop.type !== "link") {
22337
- fields.push("default");
22353
+ fields2.push("default");
22338
22354
  }
22339
- if (prop.type === "token" && prop.category === "design") fields.push("allowed");
22340
- return fields;
22355
+ if (prop.type === "token" && prop.category === "design") fields2.push("allowed");
22356
+ return fields2;
22341
22357
  }
22342
22358
  var SLOT_FIELDS = ["description", "required", "allowedComponents"];
22343
22359
  function simulateGraphWithCandidate(projectSlotGraph, selfName, currentSlots, targetSlotName, candidate) {
@@ -22876,8 +22892,8 @@ function FieldEditor({
22876
22892
  return;
22877
22893
  }
22878
22894
  if (focusLevel === "field") {
22879
- const fields = inSlots ? SLOT_FIELDS : currentProp ? propFields(currentProp) : [];
22880
- const currentFieldIdx = fields.indexOf(activeField);
22895
+ const fields2 = inSlots ? SLOT_FIELDS : currentProp ? propFields(currentProp) : [];
22896
+ const currentFieldIdx = fields2.indexOf(activeField);
22881
22897
  const isValuesNav = activeField === "values" || activeField === "allowedComponents";
22882
22898
  const arrowUp = key.upArrow;
22883
22899
  const arrowDown = key.downArrow;
@@ -22891,10 +22907,10 @@ function FieldEditor({
22891
22907
  const navPrevious = arrowUp || arrowLeft;
22892
22908
  const navNext = arrowDown || arrowRight || input === "j";
22893
22909
  const navBack = navPrevious || input === "k";
22894
- if ((navBack || navNext) && fields.length > 0) {
22895
- const lastIdx = fields.length - 1;
22910
+ if ((navBack || navNext) && fields2.length > 0) {
22911
+ const lastIdx = fields2.length - 1;
22896
22912
  const targetIdx = navNext ? currentFieldIdx >= lastIdx ? 0 : currentFieldIdx + 1 : currentFieldIdx <= 0 ? lastIdx : currentFieldIdx - 1;
22897
- const next = fields[targetIdx];
22913
+ const next = fields2[targetIdx];
22898
22914
  setActiveField(next);
22899
22915
  if (next === "description") {
22900
22916
  const desc = inSlots ? currentSlot?.description ?? "" : currentProp?.description ?? "";
@@ -28015,7 +28031,7 @@ var realSaveDeps = () => ({
28015
28031
  writeFile: (path5, contents) => writeFile7(path5, contents),
28016
28032
  appendRun,
28017
28033
  buildSourceFingerprint,
28018
- sleep: (ms) => new Promise((resolve27) => setTimeout(resolve27, ms)),
28034
+ sleep: (ms) => new Promise((resolve28) => setTimeout(resolve28, ms)),
28019
28035
  warn: (message) => process.stderr.write(message)
28020
28036
  });
28021
28037
  async function runPrintFiles(input, deps, onPatch) {
@@ -28405,12 +28421,44 @@ init_config();
28405
28421
  init_debug_store();
28406
28422
  init_debug_mode_store();
28407
28423
  init_version();
28424
+
28425
+ // packages/experience-design-system-cli/src/tui/help/file-locations.ts
28426
+ import { join as join25, resolve as resolve27 } from "node:path";
28427
+ function describeFileLocations({
28428
+ contentfulBaseDir,
28429
+ debugModeEnabled,
28430
+ currentSessionDir: currentSessionDir2
28431
+ }) {
28432
+ if (!debugModeEnabled) {
28433
+ return {
28434
+ debugLogs: "none while Debug Mode is off",
28435
+ importFiles: `${join25("<project>", ".contentful")}/ (tokens.json, components.json)`
28436
+ };
28437
+ }
28438
+ const base = contentfulBaseDir ? resolve27(contentfulBaseDir) : "<project>";
28439
+ const session = currentSessionDir2 ?? join25(base, ".contentful", "<date>-session-<n>");
28440
+ return {
28441
+ debugLogs: join25(session, "debug"),
28442
+ importFiles: `${join25(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
28443
+ };
28444
+ }
28445
+
28446
+ // packages/experience-design-system-cli/src/tui/help/help-info.ts
28408
28447
  async function readHelpInfo() {
28409
- const debugMode = await readDebugModeSetting();
28448
+ const [debugMode, settings] = await Promise.all([readDebugModeSetting(), readSettings2()]);
28449
+ const base = settings["contentfulBaseDir"];
28450
+ const locations = describeFileLocations({
28451
+ contentfulBaseDir: typeof base === "string" ? base : "",
28452
+ debugModeEnabled: debugMode.enabled,
28453
+ currentSessionDir: currentSessionDir()
28454
+ });
28410
28455
  return {
28411
28456
  storage: [
28412
28457
  { label: "Config folder", value: configRoot2() },
28413
- { label: "Settings file", value: configFilePath2() }
28458
+ { label: "Settings file", value: configFilePath2() },
28459
+ { label: "Agent settings", value: `${configFilePath2()} (keys: agent, agentModel, agents)` },
28460
+ { label: "Debug logs", value: locations.debugLogs },
28461
+ { label: "Import files", value: locations.importFiles }
28414
28462
  ],
28415
28463
  troubleshooting: [
28416
28464
  { label: "CLI version", value: readPackageVersion() },
@@ -28431,7 +28479,7 @@ function Section({ title, rows }) {
28431
28479
  return /* @__PURE__ */ jsxs43(Box42, { flexDirection: "column", children: [
28432
28480
  /* @__PURE__ */ jsx53(Text44, { bold: true, color: PALETTE.accent, children: title }),
28433
28481
  rows.map((row) => /* @__PURE__ */ jsxs43(Box42, { gap: 1, children: [
28434
- /* @__PURE__ */ jsx53(Box42, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx53(Text44, { color: PALETTE.muted, children: row.label }) }),
28482
+ /* @__PURE__ */ jsx53(Box42, { width: 16, flexShrink: 0, children: /* @__PURE__ */ jsx53(Text44, { color: PALETTE.muted, children: row.label }) }),
28435
28483
  /* @__PURE__ */ jsx53(Text44, { children: row.value })
28436
28484
  ] }, row.label))
28437
28485
  ] });
@@ -28530,17 +28578,695 @@ function SettingsScreen({
28530
28578
  ] });
28531
28579
  }
28532
28580
 
28533
- // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
28534
- import { useEffect as useEffect22, useState as useState29 } from "react";
28535
- import { Box as Box44, Text as Text46, useInput as useInput11 } from "ink";
28536
- import TextInput4 from "ink-text-input";
28581
+ // packages/experience-design-system-cli/src/tui/settings/configuration/ConfigurationScreen.tsx
28582
+ import { useState as useState33 } from "react";
28583
+ import { Box as Box48, Text as Text51, useInput as useInput13 } from "ink";
28584
+
28585
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentsScreen.tsx
28586
+ import { useEffect as useEffect23, useState as useState31 } from "react";
28587
+ import { Box as Box46, Text as Text49, useInput as useInput12 } from "ink";
28588
+ init_debug_store();
28537
28589
 
28538
- // packages/experience-design-system-cli/src/tui/settings/utils/v1-store.ts
28590
+ // packages/experience-design-system-cli/src/tui/settings/shared/v1-store.ts
28539
28591
  init_config();
28540
28592
  var readV1Store = readSettings2;
28541
28593
  var writeV1Store = writeSettings2;
28542
28594
 
28543
- // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/config-store.ts
28595
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-store.ts
28596
+ var AGENT_LABELS = {
28597
+ claude: "Claude Code",
28598
+ codex: "OpenAI Codex",
28599
+ opencode: "OpenCode",
28600
+ cursor: "Cursor",
28601
+ copilot: "GitHub Copilot"
28602
+ };
28603
+ var asString = (value) => typeof value === "string" ? value : "";
28604
+ function emptyAgents() {
28605
+ return Object.fromEntries(AGENT_NAMES.map((name) => [name, { model: "", binary: "" }]));
28606
+ }
28607
+ async function readAgentConfig() {
28608
+ const store = await readV1Store();
28609
+ const stored = asString(store["agent"]);
28610
+ const defaultAgent = isAgentName(stored) ? stored : DEFAULT_AGENT_NAME;
28611
+ const agents = emptyAgents();
28612
+ const saved = store["agents"];
28613
+ if (saved && typeof saved === "object") {
28614
+ for (const name of AGENT_NAMES) {
28615
+ const entry = saved[name];
28616
+ if (entry && typeof entry === "object") {
28617
+ const fields2 = entry;
28618
+ agents[name] = { model: asString(fields2["model"]), binary: asString(fields2["binary"]) };
28619
+ }
28620
+ }
28621
+ }
28622
+ const legacyModel = asString(store["agentModel"]);
28623
+ if (legacyModel && !agents[defaultAgent].model)
28624
+ agents[defaultAgent] = { ...agents[defaultAgent], model: legacyModel };
28625
+ return { defaultAgent, agents };
28626
+ }
28627
+ async function writeAgentConfig(config) {
28628
+ const existing = await readV1Store();
28629
+ const merged = { ...existing };
28630
+ const agents = {};
28631
+ for (const name of AGENT_NAMES) {
28632
+ const model = config.agents[name].model.trim();
28633
+ const binary = config.agents[name].binary.trim();
28634
+ if (model || binary) agents[name] = { ...model ? { model } : {}, ...binary ? { binary } : {} };
28635
+ }
28636
+ merged["agent"] = config.defaultAgent;
28637
+ const defaultModel = agents[config.defaultAgent]?.model;
28638
+ if (defaultModel) merged["agentModel"] = defaultModel;
28639
+ else delete merged["agentModel"];
28640
+ if (Object.keys(agents).length > 0) merged["agents"] = agents;
28641
+ else delete merged["agents"];
28642
+ await writeV1Store(merged);
28643
+ }
28644
+
28645
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-status.ts
28646
+ import { execFile as execFile2 } from "node:child_process";
28647
+ import { access as access6, constants } from "node:fs/promises";
28648
+ var VERSION_TIMEOUT_MS = 5e3;
28649
+ var PROMPT_TIMEOUT_MS = 6e4;
28650
+ var TEST_PROMPT = "Reply with the single word: ok";
28651
+ var INSTALL_HINTS = {
28652
+ claude: "npm install -g @anthropic-ai/claude-code",
28653
+ codex: "npm install -g @openai/codex",
28654
+ opencode: "npm install -g opencode-ai",
28655
+ cursor: "install Cursor\u2019s `cursor-agent` command",
28656
+ copilot: "npm install -g @github/copilot"
28657
+ };
28658
+ var LOGIN_HINTS = {
28659
+ claude: "run `claude login`",
28660
+ codex: "set OPENAI_API_KEY, or sign in with a ChatGPT account",
28661
+ opencode: "run `opencode auth`",
28662
+ cursor: "sign in from Cursor",
28663
+ copilot: "run `copilot` and sign in"
28664
+ };
28665
+ function effectiveBinary(name, savedBinary) {
28666
+ return savedBinary.trim() || AGENT_BINARIES[name];
28667
+ }
28668
+ function defaultModelLabel(name) {
28669
+ const model = DEFAULT_MODELS[name];
28670
+ return model && model !== "Auto" ? model : "chosen by the agent";
28671
+ }
28672
+ var fail3 = (step, detail) => ({ step, ok: false, detail });
28673
+ var pass = (step, detail) => ({ step, ok: true, detail });
28674
+ function resolveOnPath(binary) {
28675
+ if (binary.includes("/")) {
28676
+ return access6(binary, constants.X_OK).then(
28677
+ () => binary,
28678
+ () => null
28679
+ );
28680
+ }
28681
+ return new Promise((resolve28) => {
28682
+ execFile2(
28683
+ process.platform === "win32" ? "where" : "which",
28684
+ [binary],
28685
+ (error, stdout) => resolve28(error ? null : stdout.split("\n")[0]?.trim() ?? null)
28686
+ );
28687
+ });
28688
+ }
28689
+ function readVersion(binary) {
28690
+ return new Promise((resolve28) => {
28691
+ execFile2(binary, ["--version"], { timeout: VERSION_TIMEOUT_MS }, (error, stdout) => {
28692
+ const line = stdout.split("\n")[0]?.trim() ?? "";
28693
+ if (!error && line) resolve28(pass("version", line));
28694
+ else resolve28(fail3("version", "runs, but did not report a version"));
28695
+ });
28696
+ });
28697
+ }
28698
+ async function inspect(name, binary) {
28699
+ const target = effectiveBinary(name, binary);
28700
+ const found = await resolveOnPath(target);
28701
+ if (!found) return { checks: [fail3("path", `\`${target}\` was not found or is not executable`)], found: null };
28702
+ const checks = [pass("path", found)];
28703
+ checks.push(await readVersion(found));
28704
+ if (name === "claude") {
28705
+ const auth = await withBinaryEnv(name, found, () => checkAgentAuth(name));
28706
+ checks.push(
28707
+ auth === "ok" ? pass("login", "logged in") : fail3("login", auth === "not-found" ? "binary not found" : `not logged in: ${LOGIN_HINTS.claude}`)
28708
+ );
28709
+ }
28710
+ return { checks, found };
28711
+ }
28712
+ async function inspectAgent(name, binary) {
28713
+ return (await inspect(name, binary)).checks;
28714
+ }
28715
+ async function testAgent(name, binary, model) {
28716
+ const { checks, found } = await inspect(name, binary);
28717
+ if (!found || !checks.every((check) => check.step === "version" || check.ok)) return checks;
28718
+ const started = Date.now();
28719
+ const result = await withBinaryEnv(
28720
+ name,
28721
+ found,
28722
+ () => createLocalCliAgentInvoker().invoke({
28723
+ agent: name,
28724
+ ...model.trim() ? { model: model.trim() } : {},
28725
+ prompt: TEST_PROMPT,
28726
+ timeoutMs: PROMPT_TIMEOUT_MS
28727
+ })
28728
+ );
28729
+ const seconds = ((Date.now() - started) / 1e3).toFixed(1);
28730
+ if (result.timedOut) {
28731
+ return [...checks, { ...fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`), timedOut: true }];
28732
+ }
28733
+ if (result.exitCode !== 0) {
28734
+ const reason = result.stderr.trim().split("\n").pop()?.slice(0, 160) || `exited with code ${result.exitCode}`;
28735
+ return [...checks, fail3("prompt", reason)];
28736
+ }
28737
+ return [...checks, pass("prompt", `answered in ${seconds}s`)];
28738
+ }
28739
+ function statusFromChecks(name, checks, savedBinary) {
28740
+ if (checks.length === 0) return "checking";
28741
+ if (checks.some((check) => check.step === "path" && !check.ok)) {
28742
+ return savedBinary.trim() ? "not-found" : "not-configured";
28743
+ }
28744
+ const prompt = checks.find((check) => check.step === "prompt");
28745
+ if (prompt) {
28746
+ if (prompt.ok) return "ready";
28747
+ return prompt.timedOut ? "timed-out" : "test-failed";
28748
+ }
28749
+ const login = checks.find((check) => check.step === "login");
28750
+ if (login) return login.ok ? "ready" : "not-logged-in";
28751
+ return name === "claude" ? "ready" : "unknown";
28752
+ }
28753
+ function setupHint(name, status) {
28754
+ if (status === "not-configured") return `${INSTALL_HINTS[name]}, or set its command path in settings`;
28755
+ if (status === "not-found") return `${INSTALL_HINTS[name]}, or correct the command path in settings`;
28756
+ if (status === "not-logged-in") return LOGIN_HINTS[name];
28757
+ if (status === "test-failed") return `read the test message; if it is a login problem, ${LOGIN_HINTS[name]}`;
28758
+ if (status === "timed-out") return "it may be slow or waiting for input; run the test again, or try it in a terminal";
28759
+ if (status === "unknown") return "run a full test to confirm it is logged in";
28760
+ return "";
28761
+ }
28762
+ function testOutcome(checks) {
28763
+ const prompt = checks?.find((check) => check.step === "prompt");
28764
+ if (!prompt) return void 0;
28765
+ if (prompt.ok) return { ok: true, text: `Test passed: ${prompt.detail}` };
28766
+ if (prompt.timedOut) return { ok: false, text: `Test timed out: ${prompt.detail}` };
28767
+ return { ok: false, text: `Test failed: ${prompt.detail}` };
28768
+ }
28769
+ var LIST_STATUS = {
28770
+ checking: { symbol: "\u2026", text: "checking", tone: "muted" },
28771
+ ready: { symbol: "\u25CF", text: "ready", tone: "ok" },
28772
+ "not-configured": { symbol: "\u25CB", text: "not installed", tone: "muted" },
28773
+ "not-found": { symbol: "\u25CB", text: "not installed", tone: "bad" },
28774
+ "not-logged-in": { symbol: "\u25D0", text: "not logged in", tone: "bad" },
28775
+ "test-failed": { symbol: "\u2717", text: "test failed", tone: "bad" },
28776
+ "timed-out": { symbol: "\u2717", text: "test timed out", tone: "bad" },
28777
+ unknown: { symbol: "\u25D0", text: "installed, login unknown", tone: "muted" }
28778
+ };
28779
+ function modelLine(name, savedModel) {
28780
+ const model = savedModel.trim();
28781
+ return model ? model : `${defaultModelLabel(name)} (built-in default)`;
28782
+ }
28783
+ function baseRows(name, checks, savedBinary) {
28784
+ const path5 = checks.find((check) => check.step === "path");
28785
+ const version = checks.find((check) => check.step === "version");
28786
+ const hint = setupHint(name, statusFromChecks(name, checks, savedBinary));
28787
+ const setup = hint ? { label: "Setup", value: hint, tone: "muted" } : void 0;
28788
+ if (!path5?.ok) {
28789
+ const saved = savedBinary.trim() !== "";
28790
+ const command = {
28791
+ label: "Command",
28792
+ value: saved ? path5?.detail ?? "not found" : "not configured (not on the PATH)",
28793
+ tone: saved ? "bad" : "muted"
28794
+ };
28795
+ return { command, version: void 0, setup, found: false };
28796
+ }
28797
+ return {
28798
+ command: { label: "Command", value: path5.detail, tone: "ok" },
28799
+ version: {
28800
+ label: "Version",
28801
+ value: version?.ok ? version.detail : "could not be read",
28802
+ tone: version?.ok ? "ok" : "muted"
28803
+ },
28804
+ setup,
28805
+ found: true
28806
+ };
28807
+ }
28808
+ var checking = [{ label: "Command", value: "checking...", tone: "muted" }];
28809
+ function panelRows(name, checks, settings) {
28810
+ if (!checks) return checking;
28811
+ const { command, version, setup, found } = baseRows(name, checks, settings.binary);
28812
+ const model = { label: "Model", value: modelLine(name, settings.model), tone: "muted" };
28813
+ return [command, ...found ? [...version?.tone === "ok" ? [version] : [], model] : [], ...setup ? [setup] : []];
28814
+ }
28815
+ function statusRows(name, checks, savedBinary) {
28816
+ if (!checks) return checking;
28817
+ const { command, version, setup, found } = baseRows(name, checks, savedBinary);
28818
+ if (!found) return [command];
28819
+ const login = checks.find((check) => check.step === "login");
28820
+ const prompt = checks.find((check) => check.step === "prompt");
28821
+ let loginRow;
28822
+ if (login) {
28823
+ loginRow = { label: "Login", value: login.detail, tone: login.ok ? "ok" : "bad" };
28824
+ } else if (prompt) {
28825
+ loginRow = {
28826
+ label: "Login",
28827
+ value: prompt.ok ? "confirmed by the test" : prompt.timedOut ? "unknown (the test timed out)" : "see the test result",
28828
+ tone: prompt.ok ? "ok" : prompt.timedOut ? "muted" : "bad"
28829
+ };
28830
+ } else {
28831
+ loginRow = { label: "Login", value: "not checked (use Run test)", tone: "muted" };
28832
+ }
28833
+ const testRow = prompt ? [{ label: "Test", value: prompt.detail, tone: prompt.ok ? "ok" : "bad" }] : [];
28834
+ return [command, ...version ? [version] : [], loginRow, ...testRow, ...setup ? [setup] : []];
28835
+ }
28836
+ async function withBinaryEnv(name, binary, run) {
28837
+ const key = `EDS_AGENT_BINARY_${name.toUpperCase()}`;
28838
+ const previous = process.env[key];
28839
+ process.env[key] = binary;
28840
+ try {
28841
+ return await run();
28842
+ } finally {
28843
+ if (previous === void 0) delete process.env[key];
28844
+ else process.env[key] = previous;
28845
+ }
28846
+ }
28847
+
28848
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentDetail.tsx
28849
+ import { useEffect as useEffect22, useState as useState30 } from "react";
28850
+ import { Box as Box45, Text as Text48 } from "ink";
28851
+
28852
+ // packages/experience-design-system-cli/src/tui/settings/shared/FieldForm.tsx
28853
+ import { useState as useState29 } from "react";
28854
+ import { Box as Box44, Text as Text46, useInput as useInput11 } from "ink";
28855
+ import TextInput4 from "ink-text-input";
28856
+ import { Fragment as Fragment17, jsx as jsx55, jsxs as jsxs45 } from "react/jsx-runtime";
28857
+ function FieldForm({
28858
+ title,
28859
+ subtitle,
28860
+ fields: fields2,
28861
+ values,
28862
+ onChange,
28863
+ onSave,
28864
+ onQuit,
28865
+ actions = [],
28866
+ notice,
28867
+ busy = false,
28868
+ children
28869
+ }) {
28870
+ const [active, setActive] = useState29(0);
28871
+ const [editing, setEditing] = useState29(false);
28872
+ const [valueBeforeEdit, setValueBeforeEdit] = useState29("");
28873
+ const rowCount = fields2.length + actions.length;
28874
+ const labelWidth = Math.max(
28875
+ ...fields2.map((field) => field.label.length),
28876
+ ...actions.map((action) => action.label.length)
28877
+ );
28878
+ const currentField = active < fields2.length ? fields2[active] : void 0;
28879
+ const currentAction = currentField ? void 0 : actions[active - fields2.length];
28880
+ useInput11((input, key) => {
28881
+ if (busy) return;
28882
+ if (editing) {
28883
+ if (key.escape && currentField) {
28884
+ onChange(currentField.key, valueBeforeEdit);
28885
+ setEditing(false);
28886
+ }
28887
+ return;
28888
+ }
28889
+ if (key.escape || input === "q") {
28890
+ onQuit();
28891
+ return;
28892
+ }
28893
+ if (input === "s") {
28894
+ onSave();
28895
+ return;
28896
+ }
28897
+ if (input === "c" && currentField) {
28898
+ onChange(currentField.key, "");
28899
+ return;
28900
+ }
28901
+ if (key.tab || key.downArrow) {
28902
+ setActive((i) => (i + 1) % rowCount);
28903
+ return;
28904
+ }
28905
+ if (key.upArrow) {
28906
+ setActive((i) => (i - 1 + rowCount) % rowCount);
28907
+ return;
28908
+ }
28909
+ if (key.return) {
28910
+ if (currentField) {
28911
+ setValueBeforeEdit(values[currentField.key]);
28912
+ setEditing(true);
28913
+ } else {
28914
+ currentAction?.onRun();
28915
+ }
28916
+ }
28917
+ });
28918
+ const pointer = (isActive) => /* @__PURE__ */ jsx55(Text46, { color: isActive ? PALETTE.accent : void 0, children: isActive ? "\u276F" : " " });
28919
+ return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28920
+ /* @__PURE__ */ jsx55(Text46, { bold: true, children: title }),
28921
+ subtitle && /* @__PURE__ */ jsx55(Text46, { color: PALETTE.muted, children: subtitle }),
28922
+ /* @__PURE__ */ jsx55(Text46, { children: " " }),
28923
+ /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", children: [
28924
+ fields2.map((field, index) => {
28925
+ const isActive = index === active;
28926
+ const value = values[field.key];
28927
+ const display = field.masked ? "\u2022".repeat(value.length) : value;
28928
+ return /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
28929
+ pointer(isActive),
28930
+ /* @__PURE__ */ jsx55(Box44, { width: labelWidth, flexShrink: 0, children: /* @__PURE__ */ jsx55(Text46, { bold: isActive, color: isActive ? PALETTE.accent : PALETTE.muted, children: field.label }) }),
28931
+ isActive && editing ? /* @__PURE__ */ jsx55(
28932
+ TextInput4,
28933
+ {
28934
+ value,
28935
+ onChange: (next) => onChange(field.key, next),
28936
+ onSubmit: () => setEditing(false),
28937
+ mask: field.masked ? "\u2022" : void 0
28938
+ }
28939
+ ) : /* @__PURE__ */ jsx55(Text46, { bold: !!display, children: display || (field.hint ? "" : /* @__PURE__ */ jsx55(Text46, { color: PALETTE.muted, children: "(empty)" })) }),
28940
+ field.hint && /* @__PURE__ */ jsx55(Text46, { color: PALETTE.muted, children: field.hint })
28941
+ ] }, field.key);
28942
+ }),
28943
+ actions.map((action, index) => {
28944
+ const isActive = fields2.length + index === active;
28945
+ return /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
28946
+ pointer(isActive),
28947
+ /* @__PURE__ */ jsx55(Box44, { width: labelWidth, flexShrink: 0, children: /* @__PURE__ */ jsx55(Text46, { bold: isActive, color: isActive ? PALETTE.accent : PALETTE.muted, children: action.label }) }),
28948
+ /* @__PURE__ */ jsx55(Text46, { color: action.running ? PALETTE.accent : PALETTE.muted, children: action.running ? action.runningText ?? "running..." : action.description })
28949
+ ] }, action.label);
28950
+ })
28951
+ ] }),
28952
+ notice && /* @__PURE__ */ jsxs45(Fragment17, { children: [
28953
+ /* @__PURE__ */ jsx55(Text46, { children: " " }),
28954
+ /* @__PURE__ */ jsxs45(Text46, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
28955
+ notice.kind === "success" ? "\u2713" : "\u2717",
28956
+ " ",
28957
+ notice.text
28958
+ ] })
28959
+ ] }),
28960
+ children,
28961
+ /* @__PURE__ */ jsx55(Text46, { children: " " }),
28962
+ /* @__PURE__ */ jsx55(
28963
+ ControlHints,
28964
+ {
28965
+ hints: editing ? [
28966
+ { keys: "type", label: "edit" },
28967
+ { keys: "\u2190/\u2192", label: "move cursor" },
28968
+ { keys: "\u23CE", label: "done" },
28969
+ { keys: "Esc", label: "cancel edit" }
28970
+ ] : [
28971
+ { keys: "\u2191/\u2193", label: "move" },
28972
+ { keys: "\u23CE", label: currentAction ? currentAction.hint : "edit" },
28973
+ ...currentField ? [{ keys: "c", label: "clear" }] : [],
28974
+ { keys: "s", label: "save" },
28975
+ { keys: "Esc/q", label: "back without saving" }
28976
+ ]
28977
+ }
28978
+ )
28979
+ ] });
28980
+ }
28981
+
28982
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentStatusBadge.tsx
28983
+ import { Text as Text47 } from "ink";
28984
+ import { jsx as jsx56 } from "react/jsx-runtime";
28985
+ var TONE_COLOR = {
28986
+ ok: PALETTE.success,
28987
+ bad: PALETTE.error,
28988
+ muted: PALETTE.muted
28989
+ };
28990
+ function AgentStatusBadge({
28991
+ name,
28992
+ checks,
28993
+ binary
28994
+ }) {
28995
+ const { symbol, text, tone } = LIST_STATUS[checks ? statusFromChecks(name, checks, binary) : "checking"];
28996
+ return /* @__PURE__ */ jsx56(Text47, { color: TONE_COLOR[tone], children: `${symbol} ${text}` });
28997
+ }
28998
+
28999
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/apply-binary-overrides.ts
29000
+ var shellValues = /* @__PURE__ */ new Map();
29001
+ function applyBinaryOverrides(config) {
29002
+ for (const name of AGENT_NAMES) {
29003
+ const key = `EDS_AGENT_BINARY_${name.toUpperCase()}`;
29004
+ const binary = config.agents[name].binary.trim();
29005
+ if (binary) {
29006
+ if (!shellValues.has(key)) shellValues.set(key, process.env[key]);
29007
+ process.env[key] = binary;
29008
+ } else if (shellValues.has(key)) {
29009
+ const shellValue = shellValues.get(key);
29010
+ if (shellValue === void 0) delete process.env[key];
29011
+ else process.env[key] = shellValue;
29012
+ shellValues.delete(key);
29013
+ }
29014
+ }
29015
+ }
29016
+
29017
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentDetail.tsx
29018
+ import { jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
29019
+ var fields = (name) => [
29020
+ { key: "binary", label: "Command path", hint: `(empty: \`${AGENT_BINARIES[name]}\` from the PATH)` },
29021
+ { key: "model", label: "Model", hint: `(empty: ${defaultModelLabel(name)})` }
29022
+ ];
29023
+ var LABEL_WIDTH = "Command path".length;
29024
+ var LABEL_GAP = 2;
29025
+ var POINTER_WIDTH = 2;
29026
+ function Row2({ label, children }) {
29027
+ return /* @__PURE__ */ jsxs46(Box45, { children: [
29028
+ /* @__PURE__ */ jsx57(Box45, { width: POINTER_WIDTH + LABEL_WIDTH + LABEL_GAP, flexShrink: 0, children: /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: label }) }),
29029
+ children
29030
+ ] });
29031
+ }
29032
+ function StatusHeading() {
29033
+ return /* @__PURE__ */ jsxs46(Box45, { gap: 1, children: [
29034
+ /* @__PURE__ */ jsx57(Text48, { bold: true, color: PALETTE.muted, children: "STATUS" }),
29035
+ /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "\xB7 read only" })
29036
+ ] });
29037
+ }
29038
+ function AgentDetail({
29039
+ name,
29040
+ config,
29041
+ setConfig,
29042
+ onBack
29043
+ }) {
29044
+ const settings = config.agents[name];
29045
+ const [saving, setSaving] = useState30(false);
29046
+ const [testing, setTesting] = useState30(false);
29047
+ const [notice, setNotice] = useState30(null);
29048
+ const [checks, setChecks] = useState30(void 0);
29049
+ useEffect22(() => {
29050
+ let active = true;
29051
+ setChecks(void 0);
29052
+ void inspectAgent(name, settings.binary).then((result) => active && setChecks(result));
29053
+ return () => {
29054
+ active = false;
29055
+ };
29056
+ }, [name, settings.binary]);
29057
+ const save = () => {
29058
+ setSaving(true);
29059
+ setNotice(null);
29060
+ writeAgentConfig(config).then(() => {
29061
+ applyBinaryOverrides(config);
29062
+ setNotice({ kind: "success", text: `Saved: ${AGENT_LABELS[name]} settings are written to config.json` });
29063
+ }).catch(
29064
+ (err) => setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` })
29065
+ ).finally(() => setSaving(false));
29066
+ };
29067
+ const runTest = () => {
29068
+ setTesting(true);
29069
+ setNotice(null);
29070
+ testAgent(name, settings.binary, settings.model).then((result) => {
29071
+ setChecks(result);
29072
+ const outcome = testOutcome(result);
29073
+ setNotice(
29074
+ outcome ? { kind: outcome.ok ? "success" : "error", text: outcome.text } : { kind: "error", text: "Test not run: the agent could not be started (see Status)" }
29075
+ );
29076
+ }).catch(
29077
+ (err) => setNotice({ kind: "error", text: `Test could not run: ${err instanceof Error ? err.message : String(err)}` })
29078
+ ).finally(() => setTesting(false));
29079
+ };
29080
+ const action = {
29081
+ label: "Run test",
29082
+ description: "sends one small prompt (uses a few tokens)",
29083
+ running: testing,
29084
+ hint: "run test",
29085
+ onRun: runTest
29086
+ };
29087
+ return /* @__PURE__ */ jsx57(
29088
+ FieldForm,
29089
+ {
29090
+ title: AGENT_LABELS[name],
29091
+ subtitle: config.defaultAgent === name ? "This is the default agent." : `Runs the \`${AGENT_BINARIES[name]}\` command.`,
29092
+ fields: fields(name),
29093
+ values: { binary: settings.binary, model: settings.model },
29094
+ onChange: (key, value) => {
29095
+ setConfig({ ...config, agents: { ...config.agents, [name]: { ...settings, [key]: value } } });
29096
+ setNotice(null);
29097
+ },
29098
+ onSave: save,
29099
+ onQuit: onBack,
29100
+ actions: [action],
29101
+ notice: testing ? null : notice,
29102
+ busy: saving || testing,
29103
+ children: /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", marginTop: 1, children: [
29104
+ /* @__PURE__ */ jsx57(StatusHeading, {}),
29105
+ statusRows(name, checks, settings.binary).map((row) => /* @__PURE__ */ jsx57(Row2, { label: row.label, children: /* @__PURE__ */ jsx57(Text48, { color: TONE_COLOR[row.tone], children: row.value }) }, row.label))
29106
+ ] })
29107
+ }
29108
+ );
29109
+ }
29110
+
29111
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentsScreen.tsx
29112
+ import { Fragment as Fragment18, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
29113
+ var NAME_WIDTH = 16;
29114
+ var PANEL_LABEL_WIDTH = "Command".length;
29115
+ function AgentsScreen({ onDone }) {
29116
+ const [config, setConfig] = useState31(null);
29117
+ const [focus, setFocus] = useState31(0);
29118
+ const [open, setOpen] = useState31(null);
29119
+ const [notice, setNotice] = useState31(null);
29120
+ const [saving, setSaving] = useState31(false);
29121
+ const [checks, setChecks] = useState31({});
29122
+ const inspectAll = (loaded) => {
29123
+ for (const name of AGENT_NAMES) {
29124
+ void inspectAgent(name, loaded.agents[name].binary).then(
29125
+ (result) => setChecks((previous) => ({ ...previous, [name]: result }))
29126
+ );
29127
+ }
29128
+ };
29129
+ useEffect23(() => {
29130
+ void readAgentConfig().then((loaded) => {
29131
+ setConfig(loaded);
29132
+ inspectAll(loaded);
29133
+ startDebugRun({
29134
+ flow: "settings/agents",
29135
+ step: "01-agents",
29136
+ menuOption: "Configuration > Agents",
29137
+ inputs: { default_agent: loaded.defaultAgent }
29138
+ });
29139
+ });
29140
+ }, []);
29141
+ const makeDefault = (name) => {
29142
+ if (!config || saving) return;
29143
+ if (name === config.defaultAgent) {
29144
+ setNotice({ kind: "success", text: `${AGENT_LABELS[name]} is already the default agent` });
29145
+ return;
29146
+ }
29147
+ setSaving(true);
29148
+ setNotice(null);
29149
+ writeAgentConfig({ ...config, defaultAgent: name }).then(() => {
29150
+ setConfig((current) => current ? { ...current, defaultAgent: name } : current);
29151
+ setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[name]}` });
29152
+ }).catch(
29153
+ (err) => setNotice({
29154
+ kind: "error",
29155
+ text: `Default agent not changed: ${err instanceof Error ? err.message : String(err)}`
29156
+ })
29157
+ ).finally(() => setSaving(false));
29158
+ };
29159
+ useInput12((input, key) => {
29160
+ if (!config || open || saving) return;
29161
+ const focused = AGENT_NAMES[focus];
29162
+ if (key.upArrow || key.downArrow || key.tab) setNotice(null);
29163
+ if (key.upArrow) {
29164
+ setFocus((i) => (i - 1 + AGENT_NAMES.length) % AGENT_NAMES.length);
29165
+ return;
29166
+ }
29167
+ if (key.downArrow || key.tab) {
29168
+ setFocus((i) => (i + 1) % AGENT_NAMES.length);
29169
+ return;
29170
+ }
29171
+ if (key.return) {
29172
+ makeDefault(focused);
29173
+ return;
29174
+ }
29175
+ if (key.rightArrow) {
29176
+ setNotice(null);
29177
+ setOpen(focused);
29178
+ return;
29179
+ }
29180
+ if (key.escape || input === "q") {
29181
+ void finishDebugRun({ outputs: { default_agent: config.defaultAgent }, status: "success", exitMethod: "saved" });
29182
+ onDone();
29183
+ }
29184
+ });
29185
+ if (!config) {
29186
+ return /* @__PURE__ */ jsxs47(Box46, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29187
+ /* @__PURE__ */ jsx58(Text49, { bold: true, children: "Agents" }),
29188
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29189
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.accent, children: "Loading..." })
29190
+ ] });
29191
+ }
29192
+ if (open) {
29193
+ return /* @__PURE__ */ jsx58(
29194
+ AgentDetail,
29195
+ {
29196
+ name: open,
29197
+ config,
29198
+ setConfig,
29199
+ onBack: () => {
29200
+ setOpen(null);
29201
+ void readAgentConfig().then((saved) => {
29202
+ setConfig(saved);
29203
+ inspectAll(saved);
29204
+ });
29205
+ }
29206
+ }
29207
+ );
29208
+ }
29209
+ const focusedAgent = AGENT_NAMES[focus];
29210
+ return /* @__PURE__ */ jsxs47(Box46, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29211
+ /* @__PURE__ */ jsx58(Text49, { bold: true, children: "Agents" }),
29212
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: "The coding agent the CLI runs, and what was found for each one." }),
29213
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29214
+ /* @__PURE__ */ jsxs47(Box46, { gap: 1, children: [
29215
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: "Default agent" }),
29216
+ /* @__PURE__ */ jsx58(Text49, { bold: true, children: AGENT_LABELS[config.defaultAgent] }),
29217
+ saving && /* @__PURE__ */ jsx58(Text49, { color: PALETTE.accent, children: "\u2026 saving" })
29218
+ ] }),
29219
+ /* @__PURE__ */ jsxs47(Box46, { marginTop: 1, gap: 1, children: [
29220
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29221
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29222
+ /* @__PURE__ */ jsx58(Box46, { width: NAME_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: "AGENT" }) }),
29223
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: "STATUS" })
29224
+ ] }),
29225
+ AGENT_NAMES.map((name) => {
29226
+ const isFocused = focusedAgent === name;
29227
+ return /* @__PURE__ */ jsxs47(Box46, { gap: 1, children: [
29228
+ /* @__PURE__ */ jsx58(Text49, { color: isFocused ? PALETTE.accent : void 0, children: isFocused ? "\u276F" : " " }),
29229
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.success, children: name === config.defaultAgent ? "\u2605" : " " }),
29230
+ /* @__PURE__ */ jsx58(Box46, { width: NAME_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx58(Text49, { bold: isFocused, color: isFocused ? PALETTE.accent : void 0, children: AGENT_LABELS[name] }) }),
29231
+ /* @__PURE__ */ jsx58(AgentStatusBadge, { name, checks: checks[name], binary: config.agents[name].binary })
29232
+ ] }, name);
29233
+ }),
29234
+ /* @__PURE__ */ jsxs47(Box46, { flexDirection: "column", marginTop: 1, children: [
29235
+ /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: `\u2500 ${AGENT_LABELS[focusedAgent]} ${"\u2500".repeat(30)}` }),
29236
+ panelRows(focusedAgent, checks[focusedAgent], config.agents[focusedAgent]).map((row) => /* @__PURE__ */ jsxs47(Box46, { gap: 1, paddingLeft: 1, children: [
29237
+ /* @__PURE__ */ jsx58(Box46, { width: PANEL_LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: row.label }) }),
29238
+ /* @__PURE__ */ jsx58(Text49, { color: TONE_COLOR[row.tone], children: row.value })
29239
+ ] }, row.label))
29240
+ ] }),
29241
+ notice && /* @__PURE__ */ jsxs47(Fragment18, { children: [
29242
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29243
+ /* @__PURE__ */ jsxs47(Text49, { bold: true, color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29244
+ notice.kind === "success" ? "\u2713" : "\u2717",
29245
+ " ",
29246
+ notice.text
29247
+ ] })
29248
+ ] }),
29249
+ /* @__PURE__ */ jsx58(Text49, { children: " " }),
29250
+ /* @__PURE__ */ jsx58(
29251
+ ControlHints,
29252
+ {
29253
+ hints: [
29254
+ { keys: "\u2191/\u2193", label: "move" },
29255
+ { keys: "\u23CE", label: "make default" },
29256
+ { keys: "\u2192", label: "settings and test" },
29257
+ { keys: "Esc/q", label: "back" }
29258
+ ]
29259
+ }
29260
+ )
29261
+ ] });
29262
+ }
29263
+
29264
+ // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
29265
+ import { useEffect as useEffect24, useState as useState32 } from "react";
29266
+ import { Box as Box47, Text as Text50 } from "ink";
29267
+ init_debug_store();
29268
+
29269
+ // packages/experience-design-system-cli/src/tui/settings/configuration/project/project-store.ts
28544
29270
  async function readCredentials() {
28545
29271
  const store = await readV1Store();
28546
29272
  return {
@@ -28565,17 +29291,16 @@ async function writeCredentials(config) {
28565
29291
  await writeV1Store(merged);
28566
29292
  }
28567
29293
 
28568
- // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
28569
- init_debug_store();
28570
- import { Fragment as Fragment17, jsx as jsx55, jsxs as jsxs45 } from "react/jsx-runtime";
28571
- var FIELD_ORDER = [
28572
- "spaceId",
28573
- "environmentId",
28574
- "cmaToken",
28575
- "host",
28576
- "defaultComponentDir",
28577
- "defaultTokenFile",
28578
- "contentfulBaseDir"
29294
+ // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
29295
+ import { jsx as jsx59, jsxs as jsxs48 } from "react/jsx-runtime";
29296
+ var FIELDS2 = [
29297
+ { key: "spaceId", label: "Space ID" },
29298
+ { key: "environmentId", label: "Environment ID" },
29299
+ { key: "cmaToken", label: "CMA Token", masked: true },
29300
+ { key: "host", label: "API Host" },
29301
+ { key: "defaultComponentDir", label: "Default component directory" },
29302
+ { key: "defaultTokenFile", label: "Default token file" },
29303
+ { key: "contentfulBaseDir", label: "Root Project Directory", hint: "(where .contentful goes)" }
28579
29304
  ];
28580
29305
  function debugFields(config) {
28581
29306
  return {
@@ -28588,156 +29313,114 @@ function debugFields(config) {
28588
29313
  contentful_base_dir: config?.contentfulBaseDir ?? ""
28589
29314
  };
28590
29315
  }
28591
- var FIELD_LABELS = {
28592
- spaceId: "Space ID",
28593
- environmentId: "Environment ID",
28594
- cmaToken: "CMA Token",
28595
- host: "API Host",
28596
- defaultComponentDir: "Default component directory",
28597
- defaultTokenFile: "Default token file",
28598
- contentfulBaseDir: "Root Project Directory"
28599
- };
28600
- var FIELD_HINTS = {
28601
- contentfulBaseDir: "(where .contentful goes)"
28602
- };
28603
- var LABEL_WIDTH = Math.max(...Object.values(FIELD_LABELS).map((label) => label.length));
28604
- function ConfigurationScreen({ onDone }) {
28605
- const [stage, setStage] = useState29("loading");
28606
- const [config, setConfig] = useState29(null);
28607
- const [activeField, setActiveField] = useState29("spaceId");
28608
- const [notice, setNotice] = useState29(null);
28609
- const [lastSaved, setLastSaved] = useState29(null);
28610
- const [editing, setEditing] = useState29(false);
28611
- const [valueBeforeEdit, setValueBeforeEdit] = useState29("");
28612
- useEffect22(() => {
28613
- readCredentials().then((cfg) => {
29316
+ var valuesOf = (config) => Object.fromEntries(FIELDS2.map(({ key }) => [key, config[key] || ""]));
29317
+ function ProjectScreen({ onDone }) {
29318
+ const [config, setConfig] = useState32(null);
29319
+ const [saving, setSaving] = useState32(false);
29320
+ const [notice, setNotice] = useState32(null);
29321
+ const [lastSaved, setLastSaved] = useState32(null);
29322
+ useEffect24(() => {
29323
+ void readCredentials().then((cfg) => {
28614
29324
  setConfig(cfg);
28615
- setStage("form");
28616
29325
  startDebugRun({
28617
29326
  flow: "settings/contentful-configuration",
28618
29327
  step: "01-configuration",
28619
- menuOption: "Configuration",
29328
+ menuOption: "Configuration > Project",
28620
29329
  inputs: debugFields(cfg)
28621
29330
  });
28622
29331
  });
28623
29332
  }, []);
28624
- function fieldValue(field) {
28625
- if (!config) return "";
28626
- return config[field] || "";
28627
- }
28628
- function setFieldValue(field, value) {
28629
- if (!config) return;
28630
- setConfig({ ...config, [field]: value });
28631
- setNotice(null);
29333
+ if (!config) {
29334
+ return /* @__PURE__ */ jsxs48(Box47, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29335
+ /* @__PURE__ */ jsx59(Text50, { bold: true, children: "Project" }),
29336
+ /* @__PURE__ */ jsx59(Text50, { children: " " }),
29337
+ /* @__PURE__ */ jsx59(Text50, { color: PALETTE.accent, children: "Loading..." })
29338
+ ] });
28632
29339
  }
28633
- function handleSave() {
28634
- if (!config) return;
28635
- setStage("saving");
29340
+ const save = () => {
29341
+ setSaving(true);
28636
29342
  setNotice(null);
28637
29343
  writeCredentials(config).then(() => {
28638
29344
  setLastSaved(config);
28639
29345
  if (config.contentfulBaseDir) void startDebugSessionIn(config.contentfulBaseDir, { replace: true });
28640
- setNotice({ kind: "success", text: "Configuration saved" });
28641
- setStage("form");
29346
+ setNotice({ kind: "success", text: "Project settings saved" });
28642
29347
  }).catch((err) => {
28643
29348
  setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" });
28644
- setStage("form");
28645
- });
28646
- }
28647
- function quit() {
29349
+ }).finally(() => setSaving(false));
29350
+ };
29351
+ const quit = () => {
28648
29352
  void finishDebugRun(
28649
29353
  lastSaved ? { outputs: debugFields(lastSaved), status: "success", exitMethod: "saved" } : { outputs: {}, status: "success", exitMethod: "discarded" }
28650
29354
  );
28651
29355
  onDone();
28652
- }
28653
- useInput11((input, key) => {
28654
- if (stage === "loading" || stage === "saving") return;
28655
- if (editing) {
28656
- if (key.escape) {
28657
- setFieldValue(activeField, valueBeforeEdit);
28658
- setEditing(false);
28659
- }
28660
- return;
28661
- }
28662
- if (key.escape || input === "q") {
28663
- quit();
28664
- return;
28665
- }
28666
- if (input === "s") {
28667
- handleSave();
28668
- return;
28669
- }
28670
- if (input === "c") {
28671
- setFieldValue(activeField, "");
28672
- return;
29356
+ };
29357
+ return /* @__PURE__ */ jsx59(
29358
+ FieldForm,
29359
+ {
29360
+ title: "Project",
29361
+ subtitle: "The Contentful space and where the CLI keeps its files.",
29362
+ fields: FIELDS2,
29363
+ values: valuesOf(config),
29364
+ onChange: (key, value) => {
29365
+ setConfig({ ...config, [key]: value });
29366
+ setNotice(null);
29367
+ },
29368
+ onSave: save,
29369
+ onQuit: quit,
29370
+ notice,
29371
+ busy: saving
28673
29372
  }
28674
- if (key.tab || key.downArrow) {
28675
- const idx = FIELD_ORDER.indexOf(activeField);
28676
- setActiveField(FIELD_ORDER[(idx + 1) % FIELD_ORDER.length]);
29373
+ );
29374
+ }
29375
+
29376
+ // packages/experience-design-system-cli/src/tui/settings/configuration/ConfigurationScreen.tsx
29377
+ import { jsx as jsx60, jsxs as jsxs49 } from "react/jsx-runtime";
29378
+ var SECTIONS = [
29379
+ {
29380
+ id: "project",
29381
+ label: "Project",
29382
+ description: "Contentful space, credentials, defaults and where .contentful goes"
29383
+ },
29384
+ { id: "agents", label: "Agents", description: "Which coding agent the CLI uses, and each agent\u2019s settings" }
29385
+ ];
29386
+ function ConfigurationScreen({ onDone }) {
29387
+ const [focus, setFocus] = useState33(0);
29388
+ const [open, setOpen] = useState33(null);
29389
+ const close = () => setOpen(null);
29390
+ useInput13((input, key) => {
29391
+ if (open) return;
29392
+ if (key.upArrow) {
29393
+ setFocus((i) => (i - 1 + SECTIONS.length) % SECTIONS.length);
28677
29394
  return;
28678
29395
  }
28679
- if (key.upArrow) {
28680
- const idx = FIELD_ORDER.indexOf(activeField);
28681
- setActiveField(FIELD_ORDER[(idx - 1 + FIELD_ORDER.length) % FIELD_ORDER.length]);
29396
+ if (key.downArrow || key.tab) {
29397
+ setFocus((i) => (i + 1) % SECTIONS.length);
28682
29398
  return;
28683
29399
  }
28684
29400
  if (key.return) {
28685
- setValueBeforeEdit(fieldValue(activeField));
28686
- setEditing(true);
29401
+ setOpen(SECTIONS[focus].id);
29402
+ return;
28687
29403
  }
29404
+ if (key.escape || input === "q") onDone();
28688
29405
  });
28689
- if (stage === "loading") {
28690
- return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28691
- /* @__PURE__ */ jsx55(Text46, { bold: true, children: "Configuration" }),
28692
- /* @__PURE__ */ jsx55(Text46, { children: " " }),
28693
- /* @__PURE__ */ jsx55(Text46, { color: PALETTE.accent, children: "Loading..." })
28694
- ] });
28695
- }
28696
- return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28697
- /* @__PURE__ */ jsx55(Text46, { bold: true, children: "Configuration" }),
28698
- /* @__PURE__ */ jsx55(Text46, { children: " " }),
28699
- /* @__PURE__ */ jsx55(Box44, { flexDirection: "column", children: FIELD_ORDER.map((field) => {
28700
- const isActive = activeField === field;
28701
- const value = fieldValue(field);
28702
- const display = field === "cmaToken" ? "\u2022".repeat(value.length) : value;
28703
- return /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
28704
- /* @__PURE__ */ jsx55(Text46, { color: isActive ? PALETTE.accent : void 0, children: isActive ? "\u276F" : " " }),
28705
- /* @__PURE__ */ jsx55(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx55(Text46, { bold: isActive, color: isActive ? PALETTE.accent : PALETTE.muted, children: FIELD_LABELS[field] }) }),
28706
- isActive && editing ? /* @__PURE__ */ jsx55(
28707
- TextInput4,
28708
- {
28709
- value,
28710
- onChange: (next) => setFieldValue(field, next),
28711
- onSubmit: () => setEditing(false),
28712
- mask: field === "cmaToken" ? "\u2022" : void 0
28713
- }
28714
- ) : /* @__PURE__ */ jsx55(Text46, { bold: !!display, children: display || (FIELD_HINTS[field] ? "" : /* @__PURE__ */ jsx55(Text46, { color: PALETTE.muted, children: "(empty)" })) }),
28715
- FIELD_HINTS[field] && /* @__PURE__ */ jsx55(Text46, { color: PALETTE.muted, children: FIELD_HINTS[field] })
28716
- ] }, field);
28717
- }) }),
28718
- notice && /* @__PURE__ */ jsxs45(Fragment17, { children: [
28719
- /* @__PURE__ */ jsx55(Text46, { children: " " }),
28720
- /* @__PURE__ */ jsxs45(Text46, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
28721
- notice.kind === "success" ? "\u2713" : "\u2717",
28722
- " ",
28723
- notice.text
28724
- ] })
28725
- ] }),
28726
- /* @__PURE__ */ jsx55(Text46, { children: " " }),
28727
- /* @__PURE__ */ jsx55(
29406
+ if (open === "project") return /* @__PURE__ */ jsx60(ProjectScreen, { onDone: close });
29407
+ if (open === "agents") return /* @__PURE__ */ jsx60(AgentsScreen, { onDone: close });
29408
+ return /* @__PURE__ */ jsxs49(Box48, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29409
+ /* @__PURE__ */ jsx60(Text51, { bold: true, children: "Configuration" }),
29410
+ /* @__PURE__ */ jsx60(Text51, { children: " " }),
29411
+ SECTIONS.map((section, index) => /* @__PURE__ */ jsxs49(Box48, { gap: 1, children: [
29412
+ /* @__PURE__ */ jsx60(Text51, { color: index === focus ? PALETTE.accent : void 0, children: index === focus ? "\u276F" : " " }),
29413
+ /* @__PURE__ */ jsx60(Box48, { width: 9, flexShrink: 0, children: /* @__PURE__ */ jsx60(Text51, { bold: index === focus, color: index === focus ? PALETTE.accent : void 0, children: section.label }) }),
29414
+ /* @__PURE__ */ jsx60(Text51, { color: PALETTE.muted, children: section.description })
29415
+ ] }, section.id)),
29416
+ /* @__PURE__ */ jsx60(Text51, { children: " " }),
29417
+ /* @__PURE__ */ jsx60(
28728
29418
  ControlHints,
28729
29419
  {
28730
- hints: editing ? [
28731
- { keys: "type", label: "edit" },
28732
- { keys: "\u2190/\u2192", label: "move cursor" },
28733
- { keys: "\u23CE", label: "done" },
28734
- { keys: "Esc", label: "cancel edit" }
28735
- ] : [
29420
+ hints: [
28736
29421
  { keys: "\u2191/\u2193", label: "move" },
28737
- { keys: "\u23CE", label: "edit" },
28738
- { keys: "c", label: "clear" },
28739
- { keys: "s", label: "save" },
28740
- { keys: "Esc/q", label: "quit without saving" }
29422
+ { keys: "\u23CE", label: "open" },
29423
+ { keys: "Esc/q", label: "back" }
28741
29424
  ]
28742
29425
  }
28743
29426
  )
@@ -28745,8 +29428,8 @@ function ConfigurationScreen({ onDone }) {
28745
29428
  }
28746
29429
 
28747
29430
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
28748
- import { useEffect as useEffect23, useState as useState30 } from "react";
28749
- import { Box as Box45, Text as Text47, useInput as useInput12 } from "ink";
29431
+ import { useEffect as useEffect25, useState as useState34 } from "react";
29432
+ import { Box as Box49, Text as Text52, useInput as useInput14 } from "ink";
28750
29433
 
28751
29434
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/analytics-store.ts
28752
29435
  async function readAnalyticsSetting() {
@@ -28765,11 +29448,11 @@ async function writeAnalyticsSetting(setting) {
28765
29448
 
28766
29449
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
28767
29450
  init_debug_store();
28768
- import { Fragment as Fragment18, jsx as jsx56, jsxs as jsxs46 } from "react/jsx-runtime";
29451
+ import { Fragment as Fragment19, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
28769
29452
  function OptInAnalyticsScreen({ onDone }) {
28770
- const [loading, setLoading] = useState30(true);
28771
- const [enabled, setEnabled] = useState30(true);
28772
- useEffect23(() => {
29453
+ const [loading, setLoading] = useState34(true);
29454
+ const [enabled, setEnabled] = useState34(true);
29455
+ useEffect25(() => {
28773
29456
  readAnalyticsSetting().then((setting) => {
28774
29457
  setEnabled(setting.enabled);
28775
29458
  setLoading(false);
@@ -28781,7 +29464,7 @@ function OptInAnalyticsScreen({ onDone }) {
28781
29464
  });
28782
29465
  });
28783
29466
  }, []);
28784
- useInput12((input, key) => {
29467
+ useInput14((input, key) => {
28785
29468
  if (loading) return;
28786
29469
  if (key.return || input === " ") {
28787
29470
  setEnabled((current) => {
@@ -28796,21 +29479,21 @@ function OptInAnalyticsScreen({ onDone }) {
28796
29479
  onDone();
28797
29480
  }
28798
29481
  });
28799
- return /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28800
- /* @__PURE__ */ jsx56(Text47, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
28801
- /* @__PURE__ */ jsx56(Text47, { children: " " }),
28802
- loading ? /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs46(Fragment18, { children: [
28803
- /* @__PURE__ */ jsxs46(Text47, { children: [
29482
+ return /* @__PURE__ */ jsxs50(Box49, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29483
+ /* @__PURE__ */ jsx61(Text52, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
29484
+ /* @__PURE__ */ jsx61(Text52, { children: " " }),
29485
+ loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment19, { children: [
29486
+ /* @__PURE__ */ jsxs50(Text52, { children: [
28804
29487
  "Share anonymous usage data:",
28805
29488
  " ",
28806
- /* @__PURE__ */ jsx56(Text47, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
29489
+ /* @__PURE__ */ jsx61(Text52, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
28807
29490
  ] }),
28808
- /* @__PURE__ */ jsx56(Text47, { children: " " }),
28809
- /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: "Shares which CLI commands are used and where imports succeed or fail." }),
28810
- /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: "Never includes source code, file paths, credentials, or authored content." })
29491
+ /* @__PURE__ */ jsx61(Text52, { children: " " }),
29492
+ /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Shares which CLI commands are used and where imports succeed or fail." }),
29493
+ /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Never includes source code, file paths, credentials, or authored content." })
28811
29494
  ] }),
28812
- /* @__PURE__ */ jsx56(Text47, { children: " " }),
28813
- /* @__PURE__ */ jsx56(
29495
+ /* @__PURE__ */ jsx61(Text52, { children: " " }),
29496
+ /* @__PURE__ */ jsx61(
28814
29497
  ControlHints,
28815
29498
  {
28816
29499
  hints: [
@@ -28822,16 +29505,89 @@ function OptInAnalyticsScreen({ onDone }) {
28822
29505
  ] });
28823
29506
  }
28824
29507
 
29508
+ // packages/experience-design-system-cli/src/tui/upgrade/PageContainer.tsx
29509
+ import { useEffect as useEffect26, useState as useState35 } from "react";
29510
+ import { Box as Box50, Text as Text53, useInput as useInput15 } from "ink";
29511
+ init_version();
29512
+ init_debug_store();
29513
+ import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
29514
+ var UPGRADE_COMMANDS = ["git pull", "pnpm install", "pnpm build"];
29515
+ function UpgradeScreen({ onDone }) {
29516
+ const [upgradeCheck, setUpgradeCheck] = useState35();
29517
+ useEffect26(() => {
29518
+ startDebugRun({
29519
+ flow: "upgrade",
29520
+ step: "01-upgrade",
29521
+ menuOption: "Upgrade",
29522
+ inputs: { currentVersion: readPackageVersion() }
29523
+ });
29524
+ checkForUpgrade().then(setUpgradeCheck).catch(() => setUpgradeCheck({ status: "error" }));
29525
+ }, []);
29526
+ useInput15((_input, key) => {
29527
+ if (key.return) {
29528
+ void finishDebugRun({
29529
+ outputs: upgradeCheck ?? {},
29530
+ status: upgradeCheck?.status === "error" ? "error" : "success",
29531
+ exitMethod: "saved"
29532
+ });
29533
+ onDone();
29534
+ return;
29535
+ }
29536
+ });
29537
+ return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29538
+ /* @__PURE__ */ jsx62(Text53, { bold: true, children: "Upgrade" }),
29539
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
29540
+ renderBody(upgradeCheck),
29541
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
29542
+ /* @__PURE__ */ jsxs51(Text53, { bold: true, color: PALETTE.accent, children: [
29543
+ FOCUS_MARKER,
29544
+ " Go Back"
29545
+ ] })
29546
+ ] });
29547
+ }
29548
+ function renderBody(upgradeCheck) {
29549
+ if (!upgradeCheck) {
29550
+ return /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Checking for updates\u2026" });
29551
+ }
29552
+ if (upgradeCheck.status === "error") {
29553
+ return /* @__PURE__ */ jsx62(Text53, { color: PALETTE.warning, children: "Couldn't check for updates \u2014 check your network connection and try again." });
29554
+ }
29555
+ if (upgradeCheck.status === "up-to-date") {
29556
+ return /* @__PURE__ */ jsxs51(Text53, { color: PALETTE.success, children: [
29557
+ "You're already on the latest version (v",
29558
+ upgradeCheck.current,
29559
+ ")."
29560
+ ] });
29561
+ }
29562
+ return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", children: [
29563
+ /* @__PURE__ */ jsxs51(Text53, { color: PALETTE.muted, children: [
29564
+ /* @__PURE__ */ jsxs51(Text53, { bold: true, color: PALETTE.success, children: [
29565
+ "v",
29566
+ upgradeCheck.latest
29567
+ ] }),
29568
+ " ",
29569
+ "is available (you're on ",
29570
+ /* @__PURE__ */ jsxs51(Text53, { bold: true, children: [
29571
+ "v",
29572
+ upgradeCheck.current
29573
+ ] }),
29574
+ "). Exit this program, cd into the root of your local clone of contentful/experience-design-system-sdk-public, then run:"
29575
+ ] }),
29576
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
29577
+ /* @__PURE__ */ jsx62(Box50, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.border, paddingX: 1, children: UPGRADE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx62(Text53, { bold: true, children: cmd }, cmd)) })
29578
+ ] });
29579
+ }
29580
+
28825
29581
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
28826
- import { useEffect as useEffect24, useState as useState31 } from "react";
28827
- import { Box as Box46, Text as Text48, useInput as useInput13 } from "ink";
29582
+ import { useEffect as useEffect27, useState as useState36 } from "react";
29583
+ import { Box as Box51, Text as Text54, useInput as useInput16 } from "ink";
28828
29584
  init_debug_mode_store();
28829
29585
  init_debug_store();
28830
- import { jsx as jsx57, jsxs as jsxs47 } from "react/jsx-runtime";
29586
+ import { jsx as jsx63, jsxs as jsxs52 } from "react/jsx-runtime";
28831
29587
  function DebugModeScreen({ onDone }) {
28832
- const [loading, setLoading] = useState31(true);
28833
- const [enabled, setEnabled] = useState31(true);
28834
- useEffect24(() => {
29588
+ const [loading, setLoading] = useState36(true);
29589
+ const [enabled, setEnabled] = useState36(true);
29590
+ useEffect27(() => {
28835
29591
  readDebugModeSetting().then((setting) => {
28836
29592
  setEnabled(setting.enabled);
28837
29593
  setLoading(false);
@@ -28843,7 +29599,7 @@ function DebugModeScreen({ onDone }) {
28843
29599
  });
28844
29600
  });
28845
29601
  }, []);
28846
- useInput13((input, key) => {
29602
+ useInput16((input, key) => {
28847
29603
  if (loading) return;
28848
29604
  if (key.return || input === " ") {
28849
29605
  setEnabled((current) => {
@@ -28858,16 +29614,16 @@ function DebugModeScreen({ onDone }) {
28858
29614
  onDone();
28859
29615
  }
28860
29616
  });
28861
- return /* @__PURE__ */ jsxs47(Box46, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28862
- /* @__PURE__ */ jsx57(Text48, { bold: true, children: "Settings \u203A Debug Mode" }),
28863
- /* @__PURE__ */ jsx57(Text48, { children: " " }),
28864
- loading ? /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs47(Text48, { children: [
29617
+ return /* @__PURE__ */ jsxs52(Box51, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29618
+ /* @__PURE__ */ jsx63(Text54, { bold: true, children: "Settings \u203A Debug Mode" }),
29619
+ /* @__PURE__ */ jsx63(Text54, { children: " " }),
29620
+ loading ? /* @__PURE__ */ jsx63(Text54, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs52(Text54, { children: [
28865
29621
  "Debug logging:",
28866
29622
  " ",
28867
- /* @__PURE__ */ jsx57(Text48, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
29623
+ /* @__PURE__ */ jsx63(Text54, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
28868
29624
  ] }),
28869
- /* @__PURE__ */ jsx57(Text48, { children: " " }),
28870
- /* @__PURE__ */ jsx57(
29625
+ /* @__PURE__ */ jsx63(Text54, { children: " " }),
29626
+ /* @__PURE__ */ jsx63(
28871
29627
  ControlHints,
28872
29628
  {
28873
29629
  hints: [
@@ -28880,18 +29636,18 @@ function DebugModeScreen({ onDone }) {
28880
29636
  }
28881
29637
 
28882
29638
  // packages/experience-design-system-cli/app.tsx
28883
- import { Fragment as Fragment19, jsx as jsx58 } from "react/jsx-runtime";
29639
+ import { Fragment as Fragment20, jsx as jsx64 } from "react/jsx-runtime";
28884
29640
  function App({ importOptions, inkClear }) {
28885
- const [screen, setScreen] = useState32("start");
28886
- const [importExitCode, setImportExitCode] = useState32();
29641
+ const [screen, setScreen] = useState37("start");
29642
+ const [importExitCode, setImportExitCode] = useState37();
28887
29643
  const showImportResult = importExitCode !== void 0;
28888
- const [projectPath, setProjectPath] = useState32();
28889
- const [tokensPath, setTokensPath] = useState32();
28890
- const [scannedFiles, setScannedFiles] = useState32();
28891
- const [pendingLaunch, setPendingLaunch] = useState32();
28892
- const [extractionRun, setExtractionRun] = useState32();
29644
+ const [projectPath, setProjectPath] = useState37();
29645
+ const [tokensPath, setTokensPath] = useState37();
29646
+ const [scannedFiles, setScannedFiles] = useState37();
29647
+ const [pendingLaunch, setPendingLaunch] = useState37();
29648
+ const [extractionRun, setExtractionRun] = useState37();
28893
29649
  const extraction = useExtraction(extractionRun?.input);
28894
- const [scopeRun, setScopeRun] = useState32();
29650
+ const [scopeRun, setScopeRun] = useState37();
28895
29651
  const scopeFlow = useScopeGateFlow(
28896
29652
  scopeRun && {
28897
29653
  sessionId: scopeRun.extraction.sessionId,
@@ -28906,12 +29662,12 @@ function App({ importOptions, inkClear }) {
28906
29662
  }
28907
29663
  }
28908
29664
  );
28909
- const [generationInput, setGenerationInput] = useState32();
29665
+ const [generationInput, setGenerationInput] = useState37();
28910
29666
  const generation = useGeneration(generationInput);
28911
- const [flowStart, setFlowStart] = useState32();
29667
+ const [flowStart, setFlowStart] = useState37();
28912
29668
  const flow = useFlow(flowStart, { beforeStepChange: inkClear });
28913
- const [importDefaults, setImportDefaults] = useState32();
28914
- useEffect25(() => {
29669
+ const [importDefaults, setImportDefaults] = useState37();
29670
+ useEffect28(() => {
28915
29671
  if (screen !== "import") {
28916
29672
  setImportDefaults(void 0);
28917
29673
  return;
@@ -28929,7 +29685,7 @@ function App({ importOptions, inkClear }) {
28929
29685
  const launch = { projectPath: projectPath2, tokens, filePaths, ...importOptions };
28930
29686
  const state2 = await inspectTokens({
28931
29687
  rawTokensPath: tokens,
28932
- contentfulDir: join25(resolveUserPath(projectPath2), ".contentful"),
29688
+ contentfulDir: join26(resolveUserPath(projectPath2), ".contentful"),
28933
29689
  cache: importOptions.cache
28934
29690
  });
28935
29691
  if (state2.kind === "cached") {
@@ -28971,12 +29727,12 @@ function App({ importOptions, inkClear }) {
28971
29727
  }
28972
29728
  });
28973
29729
  };
28974
- useEffect25(() => {
29730
+ useEffect28(() => {
28975
29731
  if (!extractionRun || extraction?.status !== "done" || !extraction.result.ok) return;
28976
29732
  setExtractionRun(void 0);
28977
29733
  setScopeRun({ ...extractionRun, extraction: extraction.result.extraction });
28978
29734
  }, [extraction, extractionRun]);
28979
- useEffect25(() => {
29735
+ useEffect28(() => {
28980
29736
  if (!scopeRun || scopeFlow?.status !== "confirmed" || generationInput) return;
28981
29737
  const { extraction: produced, input, generatePromptPath } = scopeRun;
28982
29738
  setGenerationInput({
@@ -28994,7 +29750,7 @@ function App({ importOptions, inkClear }) {
28994
29750
  ...generatePromptPath ? { generatePromptPath } : {}
28995
29751
  });
28996
29752
  }, [scopeFlow, scopeRun, generationInput]);
28997
- useEffect25(() => {
29753
+ useEffect28(() => {
28998
29754
  if (!scopeRun || generation?.status !== "done" || !generation.result.ok) return;
28999
29755
  const { credentialsSkipped, tokenStrategy, extraction: produced, input, generatePromptPath } = scopeRun;
29000
29756
  inkClear();
@@ -29037,9 +29793,9 @@ function App({ importOptions, inkClear }) {
29037
29793
  };
29038
29794
  switch (screen) {
29039
29795
  case "import":
29040
- if (showImportResult) return /* @__PURE__ */ jsx58(ImportScreen, { exitCode: importExitCode, onDone: finishImportResult });
29796
+ if (showImportResult) return /* @__PURE__ */ jsx64(ImportScreen, { exitCode: importExitCode, onDone: finishImportResult });
29041
29797
  if (flow && flowStart) {
29042
- return /* @__PURE__ */ jsx58(
29798
+ return /* @__PURE__ */ jsx64(
29043
29799
  FlowScreen,
29044
29800
  {
29045
29801
  state: flow.state,
@@ -29049,12 +29805,12 @@ function App({ importOptions, inkClear }) {
29049
29805
  }
29050
29806
  );
29051
29807
  }
29052
- if (importDefaults === void 0) return /* @__PURE__ */ jsx58(Fragment19, {});
29808
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx64(Fragment20, {});
29053
29809
  if (projectPath === void 0) {
29054
- return /* @__PURE__ */ jsx58(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29810
+ return /* @__PURE__ */ jsx64(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29055
29811
  }
29056
29812
  if (tokensPath === void 0) {
29057
- return /* @__PURE__ */ jsx58(
29813
+ return /* @__PURE__ */ jsx64(
29058
29814
  TokenInputScreen,
29059
29815
  {
29060
29816
  initialPath: importDefaults.tokenFile,
@@ -29064,7 +29820,7 @@ function App({ importOptions, inkClear }) {
29064
29820
  );
29065
29821
  }
29066
29822
  if (scannedFiles === void 0) {
29067
- return /* @__PURE__ */ jsx58(
29823
+ return /* @__PURE__ */ jsx64(
29068
29824
  PathValidationScreen,
29069
29825
  {
29070
29826
  projectPath,
@@ -29076,10 +29832,10 @@ function App({ importOptions, inkClear }) {
29076
29832
  }
29077
29833
  if (extractionRun) {
29078
29834
  if (extraction?.status === "done" && !extraction.result.ok) {
29079
- return /* @__PURE__ */ jsx58(ErrorStep, { stepName: extraction.result.step, message: extraction.result.message, onExit: leaveImport });
29835
+ return /* @__PURE__ */ jsx64(ErrorStep, { stepName: extraction.result.step, message: extraction.result.message, onExit: leaveImport });
29080
29836
  }
29081
29837
  if (extraction?.status === "running") {
29082
- return /* @__PURE__ */ jsx58(
29838
+ return /* @__PURE__ */ jsx64(
29083
29839
  ExtractionScreen,
29084
29840
  {
29085
29841
  progress: extraction.progress,
@@ -29088,14 +29844,14 @@ function App({ importOptions, inkClear }) {
29088
29844
  }
29089
29845
  );
29090
29846
  }
29091
- return /* @__PURE__ */ jsx58(Fragment19, {});
29847
+ return /* @__PURE__ */ jsx64(Fragment20, {});
29092
29848
  }
29093
29849
  if (scopeRun && scopeFlow) {
29094
29850
  if (scopeFlow.status === "failed") {
29095
- return /* @__PURE__ */ jsx58(ErrorStep, { stepName: "scope gate", message: scopeFlow.message, onExit: leaveImport });
29851
+ return /* @__PURE__ */ jsx64(ErrorStep, { stepName: "scope gate", message: scopeFlow.message, onExit: leaveImport });
29096
29852
  }
29097
29853
  if (scopeFlow.status === "deciding") {
29098
- return /* @__PURE__ */ jsx58(
29854
+ return /* @__PURE__ */ jsx64(
29099
29855
  ScopeGateScreen,
29100
29856
  {
29101
29857
  components: scopeFlow.load.components,
@@ -29105,7 +29861,7 @@ function App({ importOptions, inkClear }) {
29105
29861
  );
29106
29862
  }
29107
29863
  if (generation?.status === "done" && !generation.result.ok) {
29108
- return /* @__PURE__ */ jsx58(ErrorStep, { stepName: generation.result.step, message: generation.result.message, onExit: leaveImport });
29864
+ return /* @__PURE__ */ jsx64(ErrorStep, { stepName: generation.result.step, message: generation.result.message, onExit: leaveImport });
29109
29865
  }
29110
29866
  if (generation?.status === "running") {
29111
29867
  const hasRawTokens = scopeRun.input.rawTokensPath !== "";
@@ -29113,7 +29869,7 @@ function App({ importOptions, inkClear }) {
29113
29869
  hasRawTokens,
29114
29870
  mapTokensEligible: generation.progress.mapTokensEligible
29115
29871
  });
29116
- return /* @__PURE__ */ jsx58(
29872
+ return /* @__PURE__ */ jsx64(
29117
29873
  GenerationScreen,
29118
29874
  {
29119
29875
  progress: generation.progress,
@@ -29125,10 +29881,10 @@ function App({ importOptions, inkClear }) {
29125
29881
  }
29126
29882
  );
29127
29883
  }
29128
- return /* @__PURE__ */ jsx58(Fragment19, {});
29884
+ return /* @__PURE__ */ jsx64(Fragment20, {});
29129
29885
  }
29130
29886
  if (pendingLaunch?.cached) {
29131
- return /* @__PURE__ */ jsx58(
29887
+ return /* @__PURE__ */ jsx64(
29132
29888
  TokenReuseScreen,
29133
29889
  {
29134
29890
  tokensPath: pendingLaunch.cached.tokensPath,
@@ -29139,7 +29895,7 @@ function App({ importOptions, inkClear }) {
29139
29895
  }
29140
29896
  );
29141
29897
  }
29142
- return /* @__PURE__ */ jsx58(
29898
+ return /* @__PURE__ */ jsx64(
29143
29899
  CredentialsScreen,
29144
29900
  {
29145
29901
  initial: importDefaults.credentials,
@@ -29148,17 +29904,19 @@ function App({ importOptions, inkClear }) {
29148
29904
  }
29149
29905
  );
29150
29906
  case "help":
29151
- return /* @__PURE__ */ jsx58(HelpScreen, { onDone: goToStart });
29907
+ return /* @__PURE__ */ jsx64(HelpScreen, { onDone: goToStart });
29908
+ case "upgrade":
29909
+ return /* @__PURE__ */ jsx64(UpgradeScreen, { onDone: goToStart });
29152
29910
  case "settings":
29153
- return /* @__PURE__ */ jsx58(SettingsScreen, { onNavigate: setScreen, onBack: goToStart });
29911
+ return /* @__PURE__ */ jsx64(SettingsScreen, { onNavigate: setScreen, onBack: goToStart });
29154
29912
  case "settings-configuration":
29155
- return /* @__PURE__ */ jsx58(ConfigurationScreen, { onDone: goToSettings });
29913
+ return /* @__PURE__ */ jsx64(ConfigurationScreen, { onDone: goToSettings });
29156
29914
  case "settings-opt-in-analytics":
29157
- return /* @__PURE__ */ jsx58(OptInAnalyticsScreen, { onDone: goToSettings });
29915
+ return /* @__PURE__ */ jsx64(OptInAnalyticsScreen, { onDone: goToSettings });
29158
29916
  case "settings-debug-mode":
29159
- return /* @__PURE__ */ jsx58(DebugModeScreen, { onDone: goToSettings });
29917
+ return /* @__PURE__ */ jsx64(DebugModeScreen, { onDone: goToSettings });
29160
29918
  case "start":
29161
- return /* @__PURE__ */ jsx58(HomeScreen, { onNavigate: setScreen });
29919
+ return /* @__PURE__ */ jsx64(HomeScreen, { onNavigate: setScreen });
29162
29920
  }
29163
29921
  }
29164
29922
  async function runApp(renderApp, importOptions) {
@@ -29166,7 +29924,7 @@ async function runApp(renderApp, importOptions) {
29166
29924
  instance.clear?.();
29167
29925
  process.stdout.write("\x1B[H\x1B[0J");
29168
29926
  };
29169
- const instance = renderApp(/* @__PURE__ */ jsx58(App, { importOptions, inkClear }));
29927
+ const instance = renderApp(/* @__PURE__ */ jsx64(App, { importOptions, inkClear }));
29170
29928
  await instance.waitUntilExit();
29171
29929
  }
29172
29930
  export {