@contentful/experience-design-system-cli 2.37.1-dev-build-9afe163e.0 → 2.37.1-dev-build-91ca3bb8.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
@@ -28735,7 +28735,9 @@ async function testAgent(name, binary, model) {
28735
28735
  })
28736
28736
  );
28737
28737
  const seconds = ((Date.now() - started) / 1e3).toFixed(1);
28738
- if (result.timedOut) return [...checks, fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`)];
28738
+ if (result.timedOut) {
28739
+ return [...checks, { ...fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`), timedOut: true }];
28740
+ }
28739
28741
  if (result.exitCode !== 0) {
28740
28742
  const reason = result.stderr.trim().split("\n").pop()?.slice(0, 160) || `exited with code ${result.exitCode}`;
28741
28743
  return [...checks, fail3("prompt", reason)];
@@ -28747,25 +28749,39 @@ function statusFromChecks(name, checks, savedBinary) {
28747
28749
  if (checks.some((check) => check.step === "path" && !check.ok)) {
28748
28750
  return savedBinary.trim() ? "not-found" : "not-configured";
28749
28751
  }
28752
+ const prompt = checks.find((check) => check.step === "prompt");
28753
+ if (prompt) {
28754
+ if (prompt.ok) return "ready";
28755
+ return prompt.timedOut ? "timed-out" : "test-failed";
28756
+ }
28750
28757
  const login = checks.find((check) => check.step === "login");
28751
28758
  if (login) return login.ok ? "ready" : "not-logged-in";
28752
- const prompt = checks.find((check) => check.step === "prompt");
28753
- if (prompt) return prompt.ok ? "ready" : "not-logged-in";
28754
28759
  return name === "claude" ? "ready" : "unknown";
28755
28760
  }
28756
- function nextStepHint(name, status) {
28757
- if (status === "not-configured") return `${INSTALL_HINTS[name]}, or set the command path below`;
28758
- if (status === "not-found") return `${INSTALL_HINTS[name]}, or fix the command path`;
28761
+ function setupHint(name, status) {
28762
+ if (status === "not-configured") return `${INSTALL_HINTS[name]}, or set its command path in settings`;
28763
+ if (status === "not-found") return `${INSTALL_HINTS[name]}, or correct the command path in settings`;
28759
28764
  if (status === "not-logged-in") return LOGIN_HINTS[name];
28765
+ if (status === "test-failed") return `read the test message; if it is a login problem, ${LOGIN_HINTS[name]}`;
28766
+ if (status === "timed-out") return "it may be slow or waiting for input; run the test again, or try it in a terminal";
28760
28767
  if (status === "unknown") return "run a full test to confirm it is logged in";
28761
28768
  return "";
28762
28769
  }
28770
+ function testOutcome(checks) {
28771
+ const prompt = checks?.find((check) => check.step === "prompt");
28772
+ if (!prompt) return void 0;
28773
+ if (prompt.ok) return { ok: true, text: `Test passed: ${prompt.detail}` };
28774
+ if (prompt.timedOut) return { ok: false, text: `Test timed out: ${prompt.detail}` };
28775
+ return { ok: false, text: `Test failed: ${prompt.detail}` };
28776
+ }
28763
28777
  var LIST_STATUS = {
28764
28778
  checking: { symbol: "\u2026", text: "checking", tone: "muted" },
28765
28779
  ready: { symbol: "\u25CF", text: "ready", tone: "ok" },
28766
28780
  "not-configured": { symbol: "\u25CB", text: "not installed", tone: "muted" },
28767
28781
  "not-found": { symbol: "\u25CB", text: "not installed", tone: "bad" },
28768
28782
  "not-logged-in": { symbol: "\u25D0", text: "not logged in", tone: "bad" },
28783
+ "test-failed": { symbol: "\u2717", text: "test failed", tone: "bad" },
28784
+ "timed-out": { symbol: "\u2717", text: "test timed out", tone: "bad" },
28769
28785
  unknown: { symbol: "\u25D0", text: "installed, login unknown", tone: "muted" }
28770
28786
  };
28771
28787
  function modelLine(name, savedModel) {
@@ -28784,16 +28800,16 @@ function panelRows(name, checks, settings) {
28784
28800
  tone: settings.binary.trim() ? "bad" : "muted"
28785
28801
  }
28786
28802
  ];
28787
- const hint2 = nextStepHint(name, status);
28788
- if (hint2) rows2.push({ label: "Next", value: hint2, tone: "muted" });
28803
+ const hint2 = setupHint(name, status);
28804
+ if (hint2) rows2.push({ label: "Setup", value: hint2, tone: "muted" });
28789
28805
  return rows2;
28790
28806
  }
28791
28807
  const rows = [{ label: "Command", value: path5.detail, tone: "ok" }];
28792
28808
  const version = checks.find((check) => check.step === "version");
28793
28809
  if (version?.ok) rows.push({ label: "Version", value: version.detail, tone: "ok" });
28794
28810
  rows.push({ label: "Model", value: modelLine(name, settings.model), tone: "muted" });
28795
- const hint = nextStepHint(name, status);
28796
- if (hint) rows.push({ label: "Next", value: hint, tone: "muted" });
28811
+ const hint = setupHint(name, status);
28812
+ if (hint) rows.push({ label: "Setup", value: hint, tone: "muted" });
28797
28813
  return rows;
28798
28814
  }
28799
28815
  function statusRows(_name, checks, savedBinary) {
@@ -28820,8 +28836,8 @@ function statusRows(_name, checks, savedBinary) {
28820
28836
  } else if (prompt) {
28821
28837
  rows.push({
28822
28838
  label: "Login",
28823
- value: prompt.ok ? "confirmed by the test" : "see the test result",
28824
- tone: prompt.ok ? "ok" : "bad"
28839
+ value: prompt.ok ? "confirmed by the test" : prompt.timedOut ? "unknown (the test timed out)" : "see the test result",
28840
+ tone: prompt.ok ? "ok" : prompt.timedOut ? "muted" : "bad"
28825
28841
  });
28826
28842
  } else {
28827
28843
  rows.push({ label: "Login", value: "not checked (use Run test)", tone: "muted" });
@@ -28882,15 +28898,37 @@ function applyBinaryOverrides(config) {
28882
28898
  }
28883
28899
 
28884
28900
  // packages/experience-design-system-cli/src/tui/settings/agents/AgentDetail.tsx
28885
- import { Fragment as Fragment17, jsx as jsx56, jsxs as jsxs45 } from "react/jsx-runtime";
28901
+ import { jsx as jsx56, jsxs as jsxs45 } from "react/jsx-runtime";
28886
28902
  var FOCUS_ORDER = ["binary", "model", "test"];
28887
28903
  var FIELDS2 = ["binary", "model"];
28888
28904
  var FIELD_LABEL = { binary: "Command path", model: "Model" };
28889
28905
  var LABEL_WIDTH = "Command path".length;
28906
+ var LABEL_GAP = 2;
28907
+ var POINTER_WIDTH = 2;
28890
28908
  var fieldHint = (name, field) => field === "binary" ? `(empty: \`${AGENT_HINTS[name]}\` from the PATH)` : `(empty: ${defaultModelLabel(name)})`;
28891
- function Section2({ title, children }) {
28909
+ function Row2({
28910
+ pointer,
28911
+ label,
28912
+ labelProps,
28913
+ children
28914
+ }) {
28915
+ return /* @__PURE__ */ jsxs45(Box44, { children: [
28916
+ /* @__PURE__ */ jsx56(Box44, { width: POINTER_WIDTH, flexShrink: 0, children: pointer }),
28917
+ /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH + LABEL_GAP, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, ...labelProps, children: label }) }),
28918
+ children
28919
+ ] });
28920
+ }
28921
+ function Section2({
28922
+ title,
28923
+ note,
28924
+ interactive = false,
28925
+ children
28926
+ }) {
28892
28927
  return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", marginTop: 1, children: [
28893
- /* @__PURE__ */ jsx56(Text47, { bold: true, color: PALETTE.muted, children: title }),
28928
+ /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
28929
+ /* @__PURE__ */ jsx56(Text47, { bold: true, color: interactive ? PALETTE.accent : PALETTE.muted, children: title }),
28930
+ /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: `\xB7 ${note}` })
28931
+ ] }),
28894
28932
  children
28895
28933
  ] });
28896
28934
  }
@@ -28925,17 +28963,22 @@ function AgentDetail({
28925
28963
  setNotice(null);
28926
28964
  writeAgentConfig(config).then(() => {
28927
28965
  applyBinaryOverrides(config);
28928
- setNotice({ kind: "success", text: `${AGENT_LABELS[name]} settings saved` });
28966
+ setNotice({ kind: "success", text: `Saved: ${AGENT_LABELS[name]} settings are written to config.json` });
28929
28967
  }).catch(
28930
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" })
28968
+ (err) => setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` })
28931
28969
  ).finally(() => setSaving(false));
28932
28970
  };
28933
28971
  const runTest = () => {
28934
28972
  setTesting(true);
28935
28973
  setNotice(null);
28936
- setChecks(void 0);
28937
- testAgent(name, settings.binary, settings.model).then(setChecks).catch(
28938
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "The test could not run" })
28974
+ testAgent(name, settings.binary, settings.model).then((result) => {
28975
+ setChecks(result);
28976
+ const outcome = testOutcome(result);
28977
+ setNotice(
28978
+ outcome ? { kind: outcome.ok ? "success" : "error", text: outcome.text } : { kind: "error", text: "Test not run: the agent could not be started (see Status)" }
28979
+ );
28980
+ }).catch(
28981
+ (err) => setNotice({ kind: "error", text: `Test could not run: ${err instanceof Error ? err.message : String(err)}` })
28939
28982
  ).finally(() => setTesting(false));
28940
28983
  };
28941
28984
  const focused = FOCUS_ORDER[focusIndex];
@@ -28979,50 +29022,45 @@ function AgentDetail({
28979
29022
  }
28980
29023
  });
28981
29024
  const status = checks ? statusFromChecks(name, checks, settings.binary) : "checking";
28982
- const hint = nextStepHint(name, status);
29025
+ const hint = setupHint(name, status);
28983
29026
  const pointer = (isFocused) => /* @__PURE__ */ jsx56(Text47, { color: isFocused ? PALETTE.accent : void 0, children: isFocused ? "\u276F" : " " });
28984
29027
  return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
28985
29028
  /* @__PURE__ */ jsx56(Text47, { bold: true, children: AGENT_LABELS[name] }),
28986
29029
  /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: config.defaultAgent === name ? "This is the default agent." : `Runs the \`${AGENT_HINTS[name]}\` command.` }),
28987
- /* @__PURE__ */ jsxs45(Section2, { title: "STATUS", children: [
28988
- statusRows(name, checks, settings.binary).map((row) => /* @__PURE__ */ jsxs45(Box44, { gap: 1, paddingLeft: 2, children: [
28989
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: row.label }) }),
28990
- /* @__PURE__ */ jsx56(Text47, { color: TONE_COLOR[row.tone], children: row.value })
28991
- ] }, row.label)),
28992
- hint && /* @__PURE__ */ jsx56(Box44, { paddingLeft: 2, children: /* @__PURE__ */ jsxs45(Text47, { color: PALETTE.muted, children: [
28993
- "Next: ",
28994
- hint
28995
- ] }) })
28996
- ] }),
28997
- /* @__PURE__ */ jsx56(Section2, { title: "SETTINGS", children: FIELDS2.map((field) => {
28998
- const isFocused = focused === field;
28999
- const value = settings[field];
29000
- return /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
29001
- pointer(isFocused),
29002
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { bold: isFocused, color: isFocused ? PALETTE.accent : PALETTE.muted, children: FIELD_LABEL[field] }) }),
29003
- isFocused && editing ? /* @__PURE__ */ jsx56(
29004
- TextInput4,
29005
- {
29006
- value,
29007
- onChange: (next) => setField(field, next),
29008
- onSubmit: () => setEditing(false)
29009
- }
29010
- ) : /* @__PURE__ */ jsx56(Text47, { bold: true, children: value }),
29011
- !value && /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: fieldHint(name, field) })
29012
- ] }, field);
29013
- }) }),
29014
- /* @__PURE__ */ jsx56(Section2, { title: "ACTIONS", children: /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
29015
- pointer(focused === "test"),
29016
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { bold: focused === "test", color: focused === "test" ? PALETTE.accent : PALETTE.muted, children: "Run test" }) }),
29017
- /* @__PURE__ */ jsx56(Text47, { color: testing ? PALETTE.accent : PALETTE.muted, children: testing ? "running..." : "sends one small prompt (uses a few tokens)" })
29030
+ (notice || testing || saving) && /* @__PURE__ */ jsx56(Box44, { marginTop: 1, children: testing || saving ? /* @__PURE__ */ jsx56(Text47, { color: PALETTE.accent, children: testing ? "\u2026 Running the test (up to 60s)" : "\u2026 Saving" }) : notice && /* @__PURE__ */ jsxs45(Text47, { bold: true, color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29031
+ notice.kind === "success" ? "\u2713" : "\u2717",
29032
+ " ",
29033
+ notice.text
29018
29034
  ] }) }),
29019
- notice && /* @__PURE__ */ jsxs45(Fragment17, { children: [
29020
- /* @__PURE__ */ jsx56(Text47, { children: " " }),
29021
- /* @__PURE__ */ jsxs45(Text47, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29022
- notice.kind === "success" ? "\u2713" : "\u2717",
29023
- " ",
29024
- notice.text
29025
- ] })
29035
+ /* @__PURE__ */ jsxs45(Section2, { title: "CONFIGURE", note: "you can change these", interactive: true, children: [
29036
+ FIELDS2.map((field) => {
29037
+ const isFocused = focused === field;
29038
+ const value = settings[field];
29039
+ const display = isFocused && editing ? /* @__PURE__ */ jsx56(TextInput4, { value, onChange: (next) => setField(field, next), onSubmit: () => setEditing(false) }) : value ? /* @__PURE__ */ jsx56(Text47, { bold: true, children: value }) : /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: fieldHint(name, field) });
29040
+ return /* @__PURE__ */ jsx56(
29041
+ Row2,
29042
+ {
29043
+ pointer: pointer(isFocused),
29044
+ label: FIELD_LABEL[field],
29045
+ labelProps: { bold: isFocused, color: isFocused ? PALETTE.accent : PALETTE.muted },
29046
+ children: display
29047
+ },
29048
+ field
29049
+ );
29050
+ }),
29051
+ /* @__PURE__ */ jsx56(
29052
+ Row2,
29053
+ {
29054
+ pointer: pointer(focused === "test"),
29055
+ label: "Run test",
29056
+ labelProps: { bold: focused === "test", color: focused === "test" ? PALETTE.accent : PALETTE.muted },
29057
+ children: /* @__PURE__ */ jsx56(Text47, { color: testing ? PALETTE.accent : PALETTE.muted, children: testing ? "running..." : "sends one small prompt (uses a few tokens)" })
29058
+ }
29059
+ )
29060
+ ] }),
29061
+ /* @__PURE__ */ jsxs45(Section2, { title: "STATUS", note: "read only", children: [
29062
+ statusRows(name, checks, settings.binary).map((row) => /* @__PURE__ */ jsx56(Row2, { pointer: null, label: row.label, children: /* @__PURE__ */ jsx56(Text47, { color: TONE_COLOR[row.tone], children: row.value }) }, row.label)),
29063
+ hint && /* @__PURE__ */ jsx56(Row2, { pointer: null, label: "Setup", children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: hint }) })
29026
29064
  ] }),
29027
29065
  /* @__PURE__ */ jsx56(Text47, { children: " " }),
29028
29066
  /* @__PURE__ */ jsx56(
@@ -29046,8 +29084,7 @@ function AgentDetail({
29046
29084
  }
29047
29085
 
29048
29086
  // packages/experience-design-system-cli/src/tui/settings/agents/AgentScreens.tsx
29049
- import { Fragment as Fragment18, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
29050
- var ROWS = [{ kind: "default" }, ...AGENT_NAMES.map((name) => ({ kind: "agent", name }))];
29087
+ import { Fragment as Fragment17, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
29051
29088
  var NAME_WIDTH = 16;
29052
29089
  var PANEL_LABEL_WIDTH = "Command".length;
29053
29090
  function AgentsScreen({ onDone }) {
@@ -29055,6 +29092,7 @@ function AgentsScreen({ onDone }) {
29055
29092
  const [focus, setFocus] = useState30(0);
29056
29093
  const [open, setOpen] = useState30(null);
29057
29094
  const [notice, setNotice] = useState30(null);
29095
+ const [saving, setSaving] = useState30(false);
29058
29096
  const [checks, setChecks] = useState30({});
29059
29097
  const inspectAll = (loaded) => {
29060
29098
  for (const name of AGENT_NAMES) {
@@ -29075,38 +29113,43 @@ function AgentsScreen({ onDone }) {
29075
29113
  });
29076
29114
  });
29077
29115
  }, []);
29078
- const cycleDefault = (step) => {
29079
- if (!config) return;
29080
- const index = AGENT_NAMES.indexOf(config.defaultAgent);
29081
- const next = { ...config, defaultAgent: AGENT_NAMES[(index + step + AGENT_NAMES.length) % AGENT_NAMES.length] };
29082
- setConfig(next);
29083
- writeAgentConfig(next).then(() => setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[next.defaultAgent]}` })).catch(
29084
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" })
29085
- );
29116
+ const makeDefault = (name) => {
29117
+ if (!config || saving) return;
29118
+ if (name === config.defaultAgent) {
29119
+ setNotice({ kind: "success", text: `${AGENT_LABELS[name]} is already the default agent` });
29120
+ return;
29121
+ }
29122
+ setSaving(true);
29123
+ setNotice(null);
29124
+ writeAgentConfig({ ...config, defaultAgent: name }).then(() => {
29125
+ setConfig((current) => current ? { ...current, defaultAgent: name } : current);
29126
+ setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[name]}` });
29127
+ }).catch(
29128
+ (err) => setNotice({
29129
+ kind: "error",
29130
+ text: `Default agent not changed: ${err instanceof Error ? err.message : String(err)}`
29131
+ })
29132
+ ).finally(() => setSaving(false));
29086
29133
  };
29087
29134
  useInput12((input, key) => {
29088
- if (!config || open) return;
29089
- const row = ROWS[focus];
29135
+ if (!config || open || saving) return;
29136
+ const focused = AGENT_NAMES[focus];
29090
29137
  if (key.upArrow || key.downArrow || key.tab) setNotice(null);
29091
29138
  if (key.upArrow) {
29092
- setFocus((i) => (i - 1 + ROWS.length) % ROWS.length);
29139
+ setFocus((i) => (i - 1 + AGENT_NAMES.length) % AGENT_NAMES.length);
29093
29140
  return;
29094
29141
  }
29095
29142
  if (key.downArrow || key.tab) {
29096
- setFocus((i) => (i + 1) % ROWS.length);
29143
+ setFocus((i) => (i + 1) % AGENT_NAMES.length);
29097
29144
  return;
29098
29145
  }
29099
- if (row.kind === "default" && key.leftArrow) {
29100
- cycleDefault(-1);
29101
- return;
29102
- }
29103
- if (row.kind === "default" && key.rightArrow) {
29104
- cycleDefault(1);
29146
+ if (key.return) {
29147
+ makeDefault(focused);
29105
29148
  return;
29106
29149
  }
29107
- if (key.return) {
29108
- if (row.kind === "default") cycleDefault(1);
29109
- else setOpen(row.name);
29150
+ if (key.rightArrow) {
29151
+ setNotice(null);
29152
+ setOpen(focused);
29110
29153
  return;
29111
29154
  }
29112
29155
  if (key.escape || input === "q") {
@@ -29138,23 +29181,15 @@ function AgentsScreen({ onDone }) {
29138
29181
  }
29139
29182
  );
29140
29183
  }
29141
- const focusedRow = ROWS[focus];
29142
- const focusedAgent = focusedRow.kind === "agent" ? focusedRow.name : null;
29184
+ const focusedAgent = AGENT_NAMES[focus];
29143
29185
  return /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29144
29186
  /* @__PURE__ */ jsx57(Text48, { bold: true, children: "Agents" }),
29145
29187
  /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "The coding agent the CLI runs, and what was found for each one." }),
29146
29188
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
29147
29189
  /* @__PURE__ */ jsxs46(Box45, { gap: 1, children: [
29148
- /* @__PURE__ */ jsx57(Text48, { color: focusedRow.kind === "default" ? PALETTE.accent : void 0, children: focusedRow.kind === "default" ? "\u276F" : " " }),
29149
- /* @__PURE__ */ jsx57(
29150
- Text48,
29151
- {
29152
- bold: focusedRow.kind === "default",
29153
- color: focusedRow.kind === "default" ? PALETTE.accent : PALETTE.muted,
29154
- children: "Default agent"
29155
- }
29156
- ),
29157
- /* @__PURE__ */ jsx57(Text48, { bold: true, children: `\u2039 ${AGENT_LABELS[config.defaultAgent]} \u203A` })
29190
+ /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "Default agent" }),
29191
+ /* @__PURE__ */ jsx57(Text48, { bold: true, children: AGENT_LABELS[config.defaultAgent] }),
29192
+ saving && /* @__PURE__ */ jsx57(Text48, { color: PALETTE.accent, children: "\u2026 saving" })
29158
29193
  ] }),
29159
29194
  /* @__PURE__ */ jsxs46(Box45, { marginTop: 1, gap: 1, children: [
29160
29195
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
@@ -29171,16 +29206,16 @@ function AgentsScreen({ onDone }) {
29171
29206
  /* @__PURE__ */ jsx57(AgentStatusBadge, { name, checks: checks[name], binary: config.agents[name].binary })
29172
29207
  ] }, name);
29173
29208
  }),
29174
- focusedAgent && /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", marginTop: 1, children: [
29209
+ /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", marginTop: 1, children: [
29175
29210
  /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: `\u2500 ${AGENT_LABELS[focusedAgent]} ${"\u2500".repeat(30)}` }),
29176
29211
  panelRows(focusedAgent, checks[focusedAgent], config.agents[focusedAgent]).map((row) => /* @__PURE__ */ jsxs46(Box45, { gap: 1, paddingLeft: 1, children: [
29177
29212
  /* @__PURE__ */ jsx57(Box45, { width: PANEL_LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: row.label }) }),
29178
29213
  /* @__PURE__ */ jsx57(Text48, { color: TONE_COLOR[row.tone], children: row.value })
29179
29214
  ] }, row.label))
29180
29215
  ] }),
29181
- notice && /* @__PURE__ */ jsxs46(Fragment18, { children: [
29216
+ notice && /* @__PURE__ */ jsxs46(Fragment17, { children: [
29182
29217
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
29183
- /* @__PURE__ */ jsxs46(Text48, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29218
+ /* @__PURE__ */ jsxs46(Text48, { bold: true, color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29184
29219
  notice.kind === "success" ? "\u2713" : "\u2717",
29185
29220
  " ",
29186
29221
  notice.text
@@ -29190,13 +29225,10 @@ function AgentsScreen({ onDone }) {
29190
29225
  /* @__PURE__ */ jsx57(
29191
29226
  ControlHints,
29192
29227
  {
29193
- hints: focusedRow.kind === "default" ? [
29194
- { keys: "\u2191/\u2193", label: "move" },
29195
- { keys: "\u2190/\u2192", label: "change default agent" },
29196
- { keys: "Esc/q", label: "back" }
29197
- ] : [
29228
+ hints: [
29198
29229
  { keys: "\u2191/\u2193", label: "move" },
29199
- { keys: "\u23CE", label: "settings and test" },
29230
+ { keys: "\u23CE", label: "make default" },
29231
+ { keys: "\u2192", label: "settings and test" },
29200
29232
  { keys: "Esc/q", label: "back" }
29201
29233
  ]
29202
29234
  }
@@ -29213,7 +29245,7 @@ init_debug_store();
29213
29245
  import { useState as useState31 } from "react";
29214
29246
  import { Box as Box46, Text as Text49, useInput as useInput13 } from "ink";
29215
29247
  import TextInput5 from "ink-text-input";
29216
- import { Fragment as Fragment19, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
29248
+ import { Fragment as Fragment18, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
29217
29249
  function FieldForm({
29218
29250
  title,
29219
29251
  subtitle,
@@ -29288,7 +29320,7 @@ function FieldForm({
29288
29320
  field.hint && /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: field.hint })
29289
29321
  ] }, field.key);
29290
29322
  }) }),
29291
- notice && /* @__PURE__ */ jsxs47(Fragment19, { children: [
29323
+ notice && /* @__PURE__ */ jsxs47(Fragment18, { children: [
29292
29324
  /* @__PURE__ */ jsx58(Text49, { children: " " }),
29293
29325
  /* @__PURE__ */ jsxs47(Text49, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29294
29326
  notice.kind === "success" ? "\u2713" : "\u2717",
@@ -29500,7 +29532,7 @@ async function writeAnalyticsSetting(setting) {
29500
29532
 
29501
29533
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
29502
29534
  init_debug_store();
29503
- import { Fragment as Fragment20, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
29535
+ import { Fragment as Fragment19, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
29504
29536
  function OptInAnalyticsScreen({ onDone }) {
29505
29537
  const [loading, setLoading] = useState34(true);
29506
29538
  const [enabled, setEnabled] = useState34(true);
@@ -29534,7 +29566,7 @@ function OptInAnalyticsScreen({ onDone }) {
29534
29566
  return /* @__PURE__ */ jsxs50(Box49, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29535
29567
  /* @__PURE__ */ jsx61(Text52, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
29536
29568
  /* @__PURE__ */ jsx61(Text52, { children: " " }),
29537
- loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment20, { children: [
29569
+ loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment19, { children: [
29538
29570
  /* @__PURE__ */ jsxs50(Text52, { children: [
29539
29571
  "Share anonymous usage data:",
29540
29572
  " ",
@@ -29688,7 +29720,7 @@ function DebugModeScreen({ onDone }) {
29688
29720
  }
29689
29721
 
29690
29722
  // packages/experience-design-system-cli/app.tsx
29691
- import { Fragment as Fragment21, jsx as jsx64 } from "react/jsx-runtime";
29723
+ import { Fragment as Fragment20, jsx as jsx64 } from "react/jsx-runtime";
29692
29724
  function App({ importOptions, inkClear }) {
29693
29725
  const [screen, setScreen] = useState37("start");
29694
29726
  const [importExitCode, setImportExitCode] = useState37();
@@ -29857,7 +29889,7 @@ function App({ importOptions, inkClear }) {
29857
29889
  }
29858
29890
  );
29859
29891
  }
29860
- if (importDefaults === void 0) return /* @__PURE__ */ jsx64(Fragment21, {});
29892
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx64(Fragment20, {});
29861
29893
  if (projectPath === void 0) {
29862
29894
  return /* @__PURE__ */ jsx64(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29863
29895
  }
@@ -29896,7 +29928,7 @@ function App({ importOptions, inkClear }) {
29896
29928
  }
29897
29929
  );
29898
29930
  }
29899
- return /* @__PURE__ */ jsx64(Fragment21, {});
29931
+ return /* @__PURE__ */ jsx64(Fragment20, {});
29900
29932
  }
29901
29933
  if (scopeRun && scopeFlow) {
29902
29934
  if (scopeFlow.status === "failed") {
@@ -29933,7 +29965,7 @@ function App({ importOptions, inkClear }) {
29933
29965
  }
29934
29966
  );
29935
29967
  }
29936
- return /* @__PURE__ */ jsx64(Fragment21, {});
29968
+ return /* @__PURE__ */ jsx64(Fragment20, {});
29937
29969
  }
29938
29970
  if (pendingLaunch?.cached) {
29939
29971
  return /* @__PURE__ */ jsx64(
package/dist/index.js CHANGED
@@ -33172,7 +33172,9 @@ async function testAgent(name, binary, model) {
33172
33172
  })
33173
33173
  );
33174
33174
  const seconds = ((Date.now() - started) / 1e3).toFixed(1);
33175
- if (result.timedOut) return [...checks, fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`)];
33175
+ if (result.timedOut) {
33176
+ return [...checks, { ...fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`), timedOut: true }];
33177
+ }
33176
33178
  if (result.exitCode !== 0) {
33177
33179
  const reason = result.stderr.trim().split("\n").pop()?.slice(0, 160) || `exited with code ${result.exitCode}`;
33178
33180
  return [...checks, fail3("prompt", reason)];
@@ -33184,19 +33186,31 @@ function statusFromChecks(name, checks, savedBinary) {
33184
33186
  if (checks.some((check) => check.step === "path" && !check.ok)) {
33185
33187
  return savedBinary.trim() ? "not-found" : "not-configured";
33186
33188
  }
33189
+ const prompt = checks.find((check) => check.step === "prompt");
33190
+ if (prompt) {
33191
+ if (prompt.ok) return "ready";
33192
+ return prompt.timedOut ? "timed-out" : "test-failed";
33193
+ }
33187
33194
  const login = checks.find((check) => check.step === "login");
33188
33195
  if (login) return login.ok ? "ready" : "not-logged-in";
33189
- const prompt = checks.find((check) => check.step === "prompt");
33190
- if (prompt) return prompt.ok ? "ready" : "not-logged-in";
33191
33196
  return name === "claude" ? "ready" : "unknown";
33192
33197
  }
33193
- function nextStepHint(name, status) {
33194
- if (status === "not-configured") return `${INSTALL_HINTS[name]}, or set the command path below`;
33195
- if (status === "not-found") return `${INSTALL_HINTS[name]}, or fix the command path`;
33198
+ function setupHint(name, status) {
33199
+ if (status === "not-configured") return `${INSTALL_HINTS[name]}, or set its command path in settings`;
33200
+ if (status === "not-found") return `${INSTALL_HINTS[name]}, or correct the command path in settings`;
33196
33201
  if (status === "not-logged-in") return LOGIN_HINTS[name];
33202
+ if (status === "test-failed") return `read the test message; if it is a login problem, ${LOGIN_HINTS[name]}`;
33203
+ if (status === "timed-out") return "it may be slow or waiting for input; run the test again, or try it in a terminal";
33197
33204
  if (status === "unknown") return "run a full test to confirm it is logged in";
33198
33205
  return "";
33199
33206
  }
33207
+ function testOutcome(checks) {
33208
+ const prompt = checks?.find((check) => check.step === "prompt");
33209
+ if (!prompt) return void 0;
33210
+ if (prompt.ok) return { ok: true, text: `Test passed: ${prompt.detail}` };
33211
+ if (prompt.timedOut) return { ok: false, text: `Test timed out: ${prompt.detail}` };
33212
+ return { ok: false, text: `Test failed: ${prompt.detail}` };
33213
+ }
33200
33214
  function modelLine(name, savedModel) {
33201
33215
  const model = savedModel.trim();
33202
33216
  return model ? model : `${defaultModelLabel(name)} (built-in default)`;
@@ -33213,16 +33227,16 @@ function panelRows(name, checks, settings) {
33213
33227
  tone: settings.binary.trim() ? "bad" : "muted"
33214
33228
  }
33215
33229
  ];
33216
- const hint2 = nextStepHint(name, status);
33217
- if (hint2) rows2.push({ label: "Next", value: hint2, tone: "muted" });
33230
+ const hint2 = setupHint(name, status);
33231
+ if (hint2) rows2.push({ label: "Setup", value: hint2, tone: "muted" });
33218
33232
  return rows2;
33219
33233
  }
33220
33234
  const rows = [{ label: "Command", value: path5.detail, tone: "ok" }];
33221
33235
  const version = checks.find((check) => check.step === "version");
33222
33236
  if (version?.ok) rows.push({ label: "Version", value: version.detail, tone: "ok" });
33223
33237
  rows.push({ label: "Model", value: modelLine(name, settings.model), tone: "muted" });
33224
- const hint = nextStepHint(name, status);
33225
- if (hint) rows.push({ label: "Next", value: hint, tone: "muted" });
33238
+ const hint = setupHint(name, status);
33239
+ if (hint) rows.push({ label: "Setup", value: hint, tone: "muted" });
33226
33240
  return rows;
33227
33241
  }
33228
33242
  function statusRows(_name, checks, savedBinary) {
@@ -33249,8 +33263,8 @@ function statusRows(_name, checks, savedBinary) {
33249
33263
  } else if (prompt) {
33250
33264
  rows.push({
33251
33265
  label: "Login",
33252
- value: prompt.ok ? "confirmed by the test" : "see the test result",
33253
- tone: prompt.ok ? "ok" : "bad"
33266
+ value: prompt.ok ? "confirmed by the test" : prompt.timedOut ? "unknown (the test timed out)" : "see the test result",
33267
+ tone: prompt.ok ? "ok" : prompt.timedOut ? "muted" : "bad"
33254
33268
  });
33255
33269
  } else {
33256
33270
  rows.push({ label: "Login", value: "not checked (use Run test)", tone: "muted" });
@@ -33299,6 +33313,8 @@ var init_agent_status = __esm({
33299
33313
  "not-configured": { symbol: "\u25CB", text: "not installed", tone: "muted" },
33300
33314
  "not-found": { symbol: "\u25CB", text: "not installed", tone: "bad" },
33301
33315
  "not-logged-in": { symbol: "\u25D0", text: "not logged in", tone: "bad" },
33316
+ "test-failed": { symbol: "\u2717", text: "test failed", tone: "bad" },
33317
+ "timed-out": { symbol: "\u2717", text: "test timed out", tone: "bad" },
33302
33318
  unknown: { symbol: "\u25D0", text: "installed, login unknown", tone: "muted" }
33303
33319
  };
33304
33320
  }
@@ -33333,10 +33349,30 @@ var init_AgentStatusBadge = __esm({
33333
33349
  import { useEffect as useEffect22, useState as useState29 } from "react";
33334
33350
  import { Box as Box44, Text as Text47, useInput as useInput11 } from "ink";
33335
33351
  import TextInput4 from "ink-text-input";
33336
- import { Fragment as Fragment17, jsx as jsx56, jsxs as jsxs45 } from "react/jsx-runtime";
33337
- function Section2({ title, children }) {
33352
+ import { jsx as jsx56, jsxs as jsxs45 } from "react/jsx-runtime";
33353
+ function Row2({
33354
+ pointer,
33355
+ label,
33356
+ labelProps,
33357
+ children
33358
+ }) {
33359
+ return /* @__PURE__ */ jsxs45(Box44, { children: [
33360
+ /* @__PURE__ */ jsx56(Box44, { width: POINTER_WIDTH, flexShrink: 0, children: pointer }),
33361
+ /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH + LABEL_GAP, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, ...labelProps, children: label }) }),
33362
+ children
33363
+ ] });
33364
+ }
33365
+ function Section2({
33366
+ title,
33367
+ note,
33368
+ interactive = false,
33369
+ children
33370
+ }) {
33338
33371
  return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", marginTop: 1, children: [
33339
- /* @__PURE__ */ jsx56(Text47, { bold: true, color: PALETTE.muted, children: title }),
33372
+ /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
33373
+ /* @__PURE__ */ jsx56(Text47, { bold: true, color: interactive ? PALETTE.accent : PALETTE.muted, children: title }),
33374
+ /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: `\xB7 ${note}` })
33375
+ ] }),
33340
33376
  children
33341
33377
  ] });
33342
33378
  }
@@ -33371,17 +33407,22 @@ function AgentDetail({
33371
33407
  setNotice(null);
33372
33408
  writeAgentConfig(config).then(() => {
33373
33409
  applyBinaryOverrides(config);
33374
- setNotice({ kind: "success", text: `${AGENT_LABELS[name]} settings saved` });
33410
+ setNotice({ kind: "success", text: `Saved: ${AGENT_LABELS[name]} settings are written to config.json` });
33375
33411
  }).catch(
33376
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" })
33412
+ (err) => setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` })
33377
33413
  ).finally(() => setSaving(false));
33378
33414
  };
33379
33415
  const runTest = () => {
33380
33416
  setTesting(true);
33381
33417
  setNotice(null);
33382
- setChecks(void 0);
33383
- testAgent(name, settings.binary, settings.model).then(setChecks).catch(
33384
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "The test could not run" })
33418
+ testAgent(name, settings.binary, settings.model).then((result) => {
33419
+ setChecks(result);
33420
+ const outcome = testOutcome(result);
33421
+ setNotice(
33422
+ outcome ? { kind: outcome.ok ? "success" : "error", text: outcome.text } : { kind: "error", text: "Test not run: the agent could not be started (see Status)" }
33423
+ );
33424
+ }).catch(
33425
+ (err) => setNotice({ kind: "error", text: `Test could not run: ${err instanceof Error ? err.message : String(err)}` })
33385
33426
  ).finally(() => setTesting(false));
33386
33427
  };
33387
33428
  const focused = FOCUS_ORDER[focusIndex];
@@ -33425,50 +33466,45 @@ function AgentDetail({
33425
33466
  }
33426
33467
  });
33427
33468
  const status = checks ? statusFromChecks(name, checks, settings.binary) : "checking";
33428
- const hint = nextStepHint(name, status);
33469
+ const hint = setupHint(name, status);
33429
33470
  const pointer = (isFocused) => /* @__PURE__ */ jsx56(Text47, { color: isFocused ? PALETTE.accent : void 0, children: isFocused ? "\u276F" : " " });
33430
33471
  return /* @__PURE__ */ jsxs45(Box44, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
33431
33472
  /* @__PURE__ */ jsx56(Text47, { bold: true, children: AGENT_LABELS[name] }),
33432
33473
  /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: config.defaultAgent === name ? "This is the default agent." : `Runs the \`${AGENT_HINTS[name]}\` command.` }),
33433
- /* @__PURE__ */ jsxs45(Section2, { title: "STATUS", children: [
33434
- statusRows(name, checks, settings.binary).map((row) => /* @__PURE__ */ jsxs45(Box44, { gap: 1, paddingLeft: 2, children: [
33435
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: row.label }) }),
33436
- /* @__PURE__ */ jsx56(Text47, { color: TONE_COLOR[row.tone], children: row.value })
33437
- ] }, row.label)),
33438
- hint && /* @__PURE__ */ jsx56(Box44, { paddingLeft: 2, children: /* @__PURE__ */ jsxs45(Text47, { color: PALETTE.muted, children: [
33439
- "Next: ",
33440
- hint
33441
- ] }) })
33442
- ] }),
33443
- /* @__PURE__ */ jsx56(Section2, { title: "SETTINGS", children: FIELDS2.map((field) => {
33444
- const isFocused = focused === field;
33445
- const value = settings[field];
33446
- return /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
33447
- pointer(isFocused),
33448
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { bold: isFocused, color: isFocused ? PALETTE.accent : PALETTE.muted, children: FIELD_LABEL[field] }) }),
33449
- isFocused && editing ? /* @__PURE__ */ jsx56(
33450
- TextInput4,
33451
- {
33452
- value,
33453
- onChange: (next) => setField(field, next),
33454
- onSubmit: () => setEditing(false)
33455
- }
33456
- ) : /* @__PURE__ */ jsx56(Text47, { bold: true, children: value }),
33457
- !value && /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: fieldHint(name, field) })
33458
- ] }, field);
33459
- }) }),
33460
- /* @__PURE__ */ jsx56(Section2, { title: "ACTIONS", children: /* @__PURE__ */ jsxs45(Box44, { gap: 1, children: [
33461
- pointer(focused === "test"),
33462
- /* @__PURE__ */ jsx56(Box44, { width: LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx56(Text47, { bold: focused === "test", color: focused === "test" ? PALETTE.accent : PALETTE.muted, children: "Run test" }) }),
33463
- /* @__PURE__ */ jsx56(Text47, { color: testing ? PALETTE.accent : PALETTE.muted, children: testing ? "running..." : "sends one small prompt (uses a few tokens)" })
33474
+ (notice || testing || saving) && /* @__PURE__ */ jsx56(Box44, { marginTop: 1, children: testing || saving ? /* @__PURE__ */ jsx56(Text47, { color: PALETTE.accent, children: testing ? "\u2026 Running the test (up to 60s)" : "\u2026 Saving" }) : notice && /* @__PURE__ */ jsxs45(Text47, { bold: true, color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
33475
+ notice.kind === "success" ? "\u2713" : "\u2717",
33476
+ " ",
33477
+ notice.text
33464
33478
  ] }) }),
33465
- notice && /* @__PURE__ */ jsxs45(Fragment17, { children: [
33466
- /* @__PURE__ */ jsx56(Text47, { children: " " }),
33467
- /* @__PURE__ */ jsxs45(Text47, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
33468
- notice.kind === "success" ? "\u2713" : "\u2717",
33469
- " ",
33470
- notice.text
33471
- ] })
33479
+ /* @__PURE__ */ jsxs45(Section2, { title: "CONFIGURE", note: "you can change these", interactive: true, children: [
33480
+ FIELDS2.map((field) => {
33481
+ const isFocused = focused === field;
33482
+ const value = settings[field];
33483
+ const display = isFocused && editing ? /* @__PURE__ */ jsx56(TextInput4, { value, onChange: (next) => setField(field, next), onSubmit: () => setEditing(false) }) : value ? /* @__PURE__ */ jsx56(Text47, { bold: true, children: value }) : /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: fieldHint(name, field) });
33484
+ return /* @__PURE__ */ jsx56(
33485
+ Row2,
33486
+ {
33487
+ pointer: pointer(isFocused),
33488
+ label: FIELD_LABEL[field],
33489
+ labelProps: { bold: isFocused, color: isFocused ? PALETTE.accent : PALETTE.muted },
33490
+ children: display
33491
+ },
33492
+ field
33493
+ );
33494
+ }),
33495
+ /* @__PURE__ */ jsx56(
33496
+ Row2,
33497
+ {
33498
+ pointer: pointer(focused === "test"),
33499
+ label: "Run test",
33500
+ labelProps: { bold: focused === "test", color: focused === "test" ? PALETTE.accent : PALETTE.muted },
33501
+ children: /* @__PURE__ */ jsx56(Text47, { color: testing ? PALETTE.accent : PALETTE.muted, children: testing ? "running..." : "sends one small prompt (uses a few tokens)" })
33502
+ }
33503
+ )
33504
+ ] }),
33505
+ /* @__PURE__ */ jsxs45(Section2, { title: "STATUS", note: "read only", children: [
33506
+ statusRows(name, checks, settings.binary).map((row) => /* @__PURE__ */ jsx56(Row2, { pointer: null, label: row.label, children: /* @__PURE__ */ jsx56(Text47, { color: TONE_COLOR[row.tone], children: row.value }) }, row.label)),
33507
+ hint && /* @__PURE__ */ jsx56(Row2, { pointer: null, label: "Setup", children: /* @__PURE__ */ jsx56(Text47, { color: PALETTE.muted, children: hint }) })
33472
33508
  ] }),
33473
33509
  /* @__PURE__ */ jsx56(Text47, { children: " " }),
33474
33510
  /* @__PURE__ */ jsx56(
@@ -33490,7 +33526,7 @@ function AgentDetail({
33490
33526
  )
33491
33527
  ] });
33492
33528
  }
33493
- var FOCUS_ORDER, FIELDS2, FIELD_LABEL, LABEL_WIDTH, fieldHint;
33529
+ var FOCUS_ORDER, FIELDS2, FIELD_LABEL, LABEL_WIDTH, LABEL_GAP, POINTER_WIDTH, fieldHint;
33494
33530
  var init_AgentDetail = __esm({
33495
33531
  "packages/experience-design-system-cli/src/tui/settings/agents/AgentDetail.tsx"() {
33496
33532
  "use strict";
@@ -33504,6 +33540,8 @@ var init_AgentDetail = __esm({
33504
33540
  FIELDS2 = ["binary", "model"];
33505
33541
  FIELD_LABEL = { binary: "Command path", model: "Model" };
33506
33542
  LABEL_WIDTH = "Command path".length;
33543
+ LABEL_GAP = 2;
33544
+ POINTER_WIDTH = 2;
33507
33545
  fieldHint = (name, field) => field === "binary" ? `(empty: \`${AGENT_HINTS[name]}\` from the PATH)` : `(empty: ${defaultModelLabel(name)})`;
33508
33546
  }
33509
33547
  });
@@ -33511,12 +33549,13 @@ var init_AgentDetail = __esm({
33511
33549
  // packages/experience-design-system-cli/src/tui/settings/agents/AgentScreens.tsx
33512
33550
  import { useEffect as useEffect23, useState as useState30 } from "react";
33513
33551
  import { Box as Box45, Text as Text48, useInput as useInput12 } from "ink";
33514
- import { Fragment as Fragment18, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
33552
+ import { Fragment as Fragment17, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
33515
33553
  function AgentsScreen({ onDone }) {
33516
33554
  const [config, setConfig] = useState30(null);
33517
33555
  const [focus, setFocus] = useState30(0);
33518
33556
  const [open, setOpen] = useState30(null);
33519
33557
  const [notice, setNotice] = useState30(null);
33558
+ const [saving, setSaving] = useState30(false);
33520
33559
  const [checks, setChecks] = useState30({});
33521
33560
  const inspectAll = (loaded) => {
33522
33561
  for (const name of AGENT_NAMES) {
@@ -33537,38 +33576,43 @@ function AgentsScreen({ onDone }) {
33537
33576
  });
33538
33577
  });
33539
33578
  }, []);
33540
- const cycleDefault = (step) => {
33541
- if (!config) return;
33542
- const index = AGENT_NAMES.indexOf(config.defaultAgent);
33543
- const next = { ...config, defaultAgent: AGENT_NAMES[(index + step + AGENT_NAMES.length) % AGENT_NAMES.length] };
33544
- setConfig(next);
33545
- writeAgentConfig(next).then(() => setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[next.defaultAgent]}` })).catch(
33546
- (err) => setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" })
33547
- );
33579
+ const makeDefault = (name) => {
33580
+ if (!config || saving) return;
33581
+ if (name === config.defaultAgent) {
33582
+ setNotice({ kind: "success", text: `${AGENT_LABELS[name]} is already the default agent` });
33583
+ return;
33584
+ }
33585
+ setSaving(true);
33586
+ setNotice(null);
33587
+ writeAgentConfig({ ...config, defaultAgent: name }).then(() => {
33588
+ setConfig((current) => current ? { ...current, defaultAgent: name } : current);
33589
+ setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[name]}` });
33590
+ }).catch(
33591
+ (err) => setNotice({
33592
+ kind: "error",
33593
+ text: `Default agent not changed: ${err instanceof Error ? err.message : String(err)}`
33594
+ })
33595
+ ).finally(() => setSaving(false));
33548
33596
  };
33549
33597
  useInput12((input, key) => {
33550
- if (!config || open) return;
33551
- const row = ROWS[focus];
33598
+ if (!config || open || saving) return;
33599
+ const focused = AGENT_NAMES[focus];
33552
33600
  if (key.upArrow || key.downArrow || key.tab) setNotice(null);
33553
33601
  if (key.upArrow) {
33554
- setFocus((i) => (i - 1 + ROWS.length) % ROWS.length);
33602
+ setFocus((i) => (i - 1 + AGENT_NAMES.length) % AGENT_NAMES.length);
33555
33603
  return;
33556
33604
  }
33557
33605
  if (key.downArrow || key.tab) {
33558
- setFocus((i) => (i + 1) % ROWS.length);
33606
+ setFocus((i) => (i + 1) % AGENT_NAMES.length);
33559
33607
  return;
33560
33608
  }
33561
- if (row.kind === "default" && key.leftArrow) {
33562
- cycleDefault(-1);
33563
- return;
33564
- }
33565
- if (row.kind === "default" && key.rightArrow) {
33566
- cycleDefault(1);
33609
+ if (key.return) {
33610
+ makeDefault(focused);
33567
33611
  return;
33568
33612
  }
33569
- if (key.return) {
33570
- if (row.kind === "default") cycleDefault(1);
33571
- else setOpen(row.name);
33613
+ if (key.rightArrow) {
33614
+ setNotice(null);
33615
+ setOpen(focused);
33572
33616
  return;
33573
33617
  }
33574
33618
  if (key.escape || input === "q") {
@@ -33600,23 +33644,15 @@ function AgentsScreen({ onDone }) {
33600
33644
  }
33601
33645
  );
33602
33646
  }
33603
- const focusedRow = ROWS[focus];
33604
- const focusedAgent = focusedRow.kind === "agent" ? focusedRow.name : null;
33647
+ const focusedAgent = AGENT_NAMES[focus];
33605
33648
  return /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
33606
33649
  /* @__PURE__ */ jsx57(Text48, { bold: true, children: "Agents" }),
33607
33650
  /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "The coding agent the CLI runs, and what was found for each one." }),
33608
33651
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
33609
33652
  /* @__PURE__ */ jsxs46(Box45, { gap: 1, children: [
33610
- /* @__PURE__ */ jsx57(Text48, { color: focusedRow.kind === "default" ? PALETTE.accent : void 0, children: focusedRow.kind === "default" ? "\u276F" : " " }),
33611
- /* @__PURE__ */ jsx57(
33612
- Text48,
33613
- {
33614
- bold: focusedRow.kind === "default",
33615
- color: focusedRow.kind === "default" ? PALETTE.accent : PALETTE.muted,
33616
- children: "Default agent"
33617
- }
33618
- ),
33619
- /* @__PURE__ */ jsx57(Text48, { bold: true, children: `\u2039 ${AGENT_LABELS[config.defaultAgent]} \u203A` })
33653
+ /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: "Default agent" }),
33654
+ /* @__PURE__ */ jsx57(Text48, { bold: true, children: AGENT_LABELS[config.defaultAgent] }),
33655
+ saving && /* @__PURE__ */ jsx57(Text48, { color: PALETTE.accent, children: "\u2026 saving" })
33620
33656
  ] }),
33621
33657
  /* @__PURE__ */ jsxs46(Box45, { marginTop: 1, gap: 1, children: [
33622
33658
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
@@ -33633,16 +33669,16 @@ function AgentsScreen({ onDone }) {
33633
33669
  /* @__PURE__ */ jsx57(AgentStatusBadge, { name, checks: checks[name], binary: config.agents[name].binary })
33634
33670
  ] }, name);
33635
33671
  }),
33636
- focusedAgent && /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", marginTop: 1, children: [
33672
+ /* @__PURE__ */ jsxs46(Box45, { flexDirection: "column", marginTop: 1, children: [
33637
33673
  /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: `\u2500 ${AGENT_LABELS[focusedAgent]} ${"\u2500".repeat(30)}` }),
33638
33674
  panelRows(focusedAgent, checks[focusedAgent], config.agents[focusedAgent]).map((row) => /* @__PURE__ */ jsxs46(Box45, { gap: 1, paddingLeft: 1, children: [
33639
33675
  /* @__PURE__ */ jsx57(Box45, { width: PANEL_LABEL_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx57(Text48, { color: PALETTE.muted, children: row.label }) }),
33640
33676
  /* @__PURE__ */ jsx57(Text48, { color: TONE_COLOR[row.tone], children: row.value })
33641
33677
  ] }, row.label))
33642
33678
  ] }),
33643
- notice && /* @__PURE__ */ jsxs46(Fragment18, { children: [
33679
+ notice && /* @__PURE__ */ jsxs46(Fragment17, { children: [
33644
33680
  /* @__PURE__ */ jsx57(Text48, { children: " " }),
33645
- /* @__PURE__ */ jsxs46(Text48, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
33681
+ /* @__PURE__ */ jsxs46(Text48, { bold: true, color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
33646
33682
  notice.kind === "success" ? "\u2713" : "\u2717",
33647
33683
  " ",
33648
33684
  notice.text
@@ -33652,20 +33688,17 @@ function AgentsScreen({ onDone }) {
33652
33688
  /* @__PURE__ */ jsx57(
33653
33689
  ControlHints,
33654
33690
  {
33655
- hints: focusedRow.kind === "default" ? [
33656
- { keys: "\u2191/\u2193", label: "move" },
33657
- { keys: "\u2190/\u2192", label: "change default agent" },
33658
- { keys: "Esc/q", label: "back" }
33659
- ] : [
33691
+ hints: [
33660
33692
  { keys: "\u2191/\u2193", label: "move" },
33661
- { keys: "\u23CE", label: "settings and test" },
33693
+ { keys: "\u23CE", label: "make default" },
33694
+ { keys: "\u2192", label: "settings and test" },
33662
33695
  { keys: "Esc/q", label: "back" }
33663
33696
  ]
33664
33697
  }
33665
33698
  )
33666
33699
  ] });
33667
33700
  }
33668
- var ROWS, NAME_WIDTH, PANEL_LABEL_WIDTH;
33701
+ var NAME_WIDTH, PANEL_LABEL_WIDTH;
33669
33702
  var init_AgentScreens = __esm({
33670
33703
  "packages/experience-design-system-cli/src/tui/settings/agents/AgentScreens.tsx"() {
33671
33704
  "use strict";
@@ -33677,7 +33710,6 @@ var init_AgentScreens = __esm({
33677
33710
  init_agent_status();
33678
33711
  init_AgentDetail();
33679
33712
  init_AgentStatusBadge();
33680
- ROWS = [{ kind: "default" }, ...AGENT_NAMES.map((name) => ({ kind: "agent", name }))];
33681
33713
  NAME_WIDTH = 16;
33682
33714
  PANEL_LABEL_WIDTH = "Command".length;
33683
33715
  }
@@ -33687,7 +33719,7 @@ var init_AgentScreens = __esm({
33687
33719
  import { useState as useState31 } from "react";
33688
33720
  import { Box as Box46, Text as Text49, useInput as useInput13 } from "ink";
33689
33721
  import TextInput5 from "ink-text-input";
33690
- import { Fragment as Fragment19, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
33722
+ import { Fragment as Fragment18, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
33691
33723
  function FieldForm({
33692
33724
  title,
33693
33725
  subtitle,
@@ -33762,7 +33794,7 @@ function FieldForm({
33762
33794
  field.hint && /* @__PURE__ */ jsx58(Text49, { color: PALETTE.muted, children: field.hint })
33763
33795
  ] }, field.key);
33764
33796
  }) }),
33765
- notice && /* @__PURE__ */ jsxs47(Fragment19, { children: [
33797
+ notice && /* @__PURE__ */ jsxs47(Fragment18, { children: [
33766
33798
  /* @__PURE__ */ jsx58(Text49, { children: " " }),
33767
33799
  /* @__PURE__ */ jsxs47(Text49, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
33768
33800
  notice.kind === "success" ? "\u2713" : "\u2717",
@@ -33993,7 +34025,7 @@ var init_ContentfulConfigScreen = __esm({
33993
34025
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
33994
34026
  import { useEffect as useEffect25, useState as useState34 } from "react";
33995
34027
  import { Box as Box49, Text as Text52, useInput as useInput15 } from "ink";
33996
- import { Fragment as Fragment20, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
34028
+ import { Fragment as Fragment19, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
33997
34029
  function OptInAnalyticsScreen({ onDone }) {
33998
34030
  const [loading, setLoading] = useState34(true);
33999
34031
  const [enabled, setEnabled] = useState34(true);
@@ -34027,7 +34059,7 @@ function OptInAnalyticsScreen({ onDone }) {
34027
34059
  return /* @__PURE__ */ jsxs50(Box49, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
34028
34060
  /* @__PURE__ */ jsx61(Text52, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
34029
34061
  /* @__PURE__ */ jsx61(Text52, { children: " " }),
34030
- loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment20, { children: [
34062
+ loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment19, { children: [
34031
34063
  /* @__PURE__ */ jsxs50(Text52, { children: [
34032
34064
  "Share anonymous usage data:",
34033
34065
  " ",
@@ -34210,7 +34242,7 @@ __export(app_exports, {
34210
34242
  });
34211
34243
  import { join as join28 } from "node:path";
34212
34244
  import { useEffect as useEffect28, useState as useState37 } from "react";
34213
- import { Fragment as Fragment21, jsx as jsx64 } from "react/jsx-runtime";
34245
+ import { Fragment as Fragment20, jsx as jsx64 } from "react/jsx-runtime";
34214
34246
  function App({ importOptions, inkClear }) {
34215
34247
  const [screen, setScreen] = useState37("start");
34216
34248
  const [importExitCode, setImportExitCode] = useState37();
@@ -34379,7 +34411,7 @@ function App({ importOptions, inkClear }) {
34379
34411
  }
34380
34412
  );
34381
34413
  }
34382
- if (importDefaults === void 0) return /* @__PURE__ */ jsx64(Fragment21, {});
34414
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx64(Fragment20, {});
34383
34415
  if (projectPath === void 0) {
34384
34416
  return /* @__PURE__ */ jsx64(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
34385
34417
  }
@@ -34418,7 +34450,7 @@ function App({ importOptions, inkClear }) {
34418
34450
  }
34419
34451
  );
34420
34452
  }
34421
- return /* @__PURE__ */ jsx64(Fragment21, {});
34453
+ return /* @__PURE__ */ jsx64(Fragment20, {});
34422
34454
  }
34423
34455
  if (scopeRun && scopeFlow) {
34424
34456
  if (scopeFlow.status === "failed") {
@@ -34455,7 +34487,7 @@ function App({ importOptions, inkClear }) {
34455
34487
  }
34456
34488
  );
34457
34489
  }
34458
- return /* @__PURE__ */ jsx64(Fragment21, {});
34490
+ return /* @__PURE__ */ jsx64(Fragment20, {});
34459
34491
  }
34460
34492
  if (pendingLaunch?.cached) {
34461
34493
  return /* @__PURE__ */ jsx64(
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-9afe163e.0",
3
+ "version": "2.37.1-dev-build-91ca3bb8.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
2
  /**
3
- * Settings > Configuration > Agents. The list holds only what is needed to pick a row: the name, a star on the default,
3
+ * Settings > Configuration > Agents. The list holds only what is needed to pick an agent: the name, a star on the default,
4
4
  * and a one-word status. Below it, a panel shows the full detail for the focused agent and follows the cursor, so nothing
5
- * has to be opened to read it. Enter opens the agent's own screen, where its path and model are edited and the test is run.
6
- * The first row picks the default agent (←/→ or Enter cycles it, and the change is saved at once).
5
+ * has to be opened to read it. The "Default agent" line at the top is read-only: ↑/↓ move through the agents, Enter makes
6
+ * the focused one the default (saved at once), and → opens its own screen, where its path and model are edited and the
7
+ * test is run.
7
8
  */
8
9
  export declare function AgentsScreen({ onDone }: {
9
10
  onDone: () => void;
@@ -5,12 +5,14 @@ export type AgentCheck = {
5
5
  ok: boolean;
6
6
  /** One line for the user: the version string, the reason it failed, or what to run next. */
7
7
  detail: string;
8
+ /** Only on the prompt step: the agent did not answer in time. That is not the same as a failure or a missing login. */
9
+ timedOut?: boolean;
8
10
  };
9
11
  /**
10
12
  * The one-word state shown on an agent's row. `not-configured` means no path is saved and the command is not on the
11
13
  * PATH; `not-found` means a saved path does not work. `unknown` means it runs but its login cannot be checked.
12
14
  */
13
- export type AgentStatus = 'checking' | 'ready' | 'not-configured' | 'not-found' | 'not-logged-in' | 'unknown';
15
+ export type AgentStatus = 'checking' | 'ready' | 'not-configured' | 'not-found' | 'not-logged-in' | 'test-failed' | 'timed-out' | 'unknown';
14
16
  /**
15
17
  * The binary the import will actually run for this agent: the saved path if there is one, otherwise the built-in
16
18
  * command name. Shown in the form so the user sees what is used when the field is empty.
@@ -27,13 +29,25 @@ export declare function inspectAgent(name: AgentName, binary: string): Promise<A
27
29
  export declare function testAgent(name: AgentName, binary: string, model: string): Promise<AgentCheck[]>;
28
30
  /** Collapses a list of checks into the status shown on the row. */
29
31
  export declare function statusFromChecks(name: AgentName, checks: readonly AgentCheck[], savedBinary: string): AgentStatus;
30
- /** What to tell a user whose agent is not ready: the install command, or the login command. Empty when nothing is needed. */
31
- export declare function nextStepHint(name: AgentName, status: AgentStatus): string;
32
+ /**
33
+ * What to tell a user whose agent is not ready: the install command, or the login command. Empty when nothing is needed.
34
+ * Shown on the list's panel and on the agent's own screen, so it cannot say where the command path is ("below"): it
35
+ * names the settings instead, which is the same place from both.
36
+ */
37
+ export declare function setupHint(name: AgentName, status: AgentStatus): string;
32
38
  export type StatusRow = {
33
39
  label: string;
34
40
  value: string;
35
41
  tone: 'ok' | 'bad' | 'muted';
36
42
  };
43
+ /**
44
+ * How a full test went, in one line for a banner on the agent's screen. Undefined when no test has run (the quick checks
45
+ * alone are not a test), so the banner only appears after the user asked for one.
46
+ */
47
+ export declare function testOutcome(checks: readonly AgentCheck[] | undefined): {
48
+ ok: boolean;
49
+ text: string;
50
+ } | undefined;
37
51
  /**
38
52
  * The short form of a status for the list, where every row has to be scannable at a glance. The wording is plainer than
39
53
  * the detail panel's: "not installed" covers both "nothing saved" and "saved path broken", which the panel tells apart.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-9afe163e.0",
3
+ "version": "2.37.1-dev-build-91ca3bb8.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-9afe163e.0",
3
+ "version": "2.37.1-dev-build-91ca3bb8.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,8 +45,8 @@
45
45
  "ts-morph": "^27.0.2",
46
46
  "typescript": "^5.9.3",
47
47
  "zod": "^4.6.5",
48
- "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-9afe163e.0",
49
- "@contentful/experience-design-system-types": "2.37.1-dev-build-9afe163e.0"
48
+ "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-91ca3bb8.0",
49
+ "@contentful/experience-design-system-types": "2.37.1-dev-build-91ca3bb8.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@tsconfig/node24": "^24.0.4",