ccsidekick 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2362,22 +2362,22 @@ var init_catalog = __esm(() => {
2362
2362
  render: (i) => `Large diff: +${i.git?.insertions ?? 0}/-${i.git?.deletions ?? 0}. Review in chunks.`
2363
2363
  },
2364
2364
  {
2365
- id: "behind_upstream",
2365
+ id: "diverged",
2366
2366
  severity: "medium",
2367
2367
  category: "git",
2368
2368
  momentary: false,
2369
- template: "{behind} behind upstream. Pull before your next commit knots the merge.",
2370
- test: (i) => behind(i.git) > 0,
2371
- render: (i) => `${behind(i.git)} behind upstream. Pull before your next commit knots the merge.`
2369
+ template: "Diverged {ahead}↑ {behind}↓. `git pull --rebase` keeps history linear.",
2370
+ test: (i) => ahead(i.git) > 0 && behind(i.git) > 0,
2371
+ render: (i) => `Diverged ${ahead(i.git)}↑ ${behind(i.git)}↓. \`git pull --rebase\` keeps history linear.`
2372
2372
  },
2373
2373
  {
2374
- id: "diverged",
2374
+ id: "behind_upstream",
2375
2375
  severity: "medium",
2376
2376
  category: "git",
2377
2377
  momentary: false,
2378
- template: "Diverged {ahead}↑ {behind}↓. `git pull --rebase` keeps history linear.",
2379
- test: (i) => ahead(i.git) > 0 && behind(i.git) > 0,
2380
- render: (i) => `Diverged ${ahead(i.git)}↑ ${behind(i.git)}↓. \`git pull --rebase\` keeps history linear.`
2378
+ template: "{behind} behind upstream. Pull before your next commit knots the merge.",
2379
+ test: (i) => behind(i.git) > 0,
2380
+ render: (i) => `${behind(i.git)} behind upstream. Pull before your next commit knots the merge.`
2381
2381
  },
2382
2382
  {
2383
2383
  id: "dirty_default_branch",
@@ -4007,9 +4007,9 @@ var init_load = __esm(() => {
4007
4007
  });
4008
4008
 
4009
4009
  // src/packs/registry.ts
4010
- var FIRST_PARTY_PACKS, BUNDLED_PACK = "batman";
4010
+ var PACKS;
4011
4011
  var init_registry = __esm(() => {
4012
- FIRST_PARTY_PACKS = [
4012
+ PACKS = [
4013
4013
  "barbie",
4014
4014
  "batman",
4015
4015
  "harry-potter",
@@ -4022,7 +4022,6 @@ var init_registry = __esm(() => {
4022
4022
 
4023
4023
  // src/packs/index.ts
4024
4024
  var init_packs = __esm(() => {
4025
- init_allowlist();
4026
4025
  init_load();
4027
4026
  init_registry();
4028
4027
  });
@@ -5452,10 +5451,9 @@ function loadConfig(globalToml = "", projectToml = "") {
5452
5451
  const p = safeParse(projectToml);
5453
5452
  const character = section(g, p, "character");
5454
5453
  const comments = section(g, p, "comments");
5455
- const helpful = section(g, p, "helpful");
5456
- const line = section(g, p, "line");
5457
5454
  const theme = section(g, p, "theme");
5458
5455
  const network = section(g, p, "network");
5456
+ const statusline = section(g, p, "statusline");
5459
5457
  const d = DEFAULT_CONFIG;
5460
5458
  return {
5461
5459
  schema_version: numv(p["schema_version"] ?? g["schema_version"], d.schema_version),
@@ -5465,21 +5463,6 @@ function loadConfig(globalToml = "", projectToml = "") {
5465
5463
  name: str(character["name"], d.character.name),
5466
5464
  roster: stringArray(character["roster"], d.character.roster)
5467
5465
  },
5468
- comments: {
5469
- enabled: bool(comments["enabled"], d.comments.enabled)
5470
- },
5471
- helpful: {
5472
- enabled: bool(helpful["enabled"], d.helpful.enabled),
5473
- min_severity: oneOf(helpful["min_severity"], ["low", "medium", "high", "critical"], d.helpful.min_severity)
5474
- },
5475
- line: {
5476
- currency: str(line["currency"], d.line.currency),
5477
- ...typeof line["budget"] === "number" ? { budget: line["budget"] } : {},
5478
- widgets: mergeWidgets({
5479
- ...obj(obj(g["line"])["widgets"]),
5480
- ...obj(obj(p["line"])["widgets"])
5481
- })
5482
- },
5483
5466
  theme: {
5484
5467
  name: str(theme["name"], d.theme.name),
5485
5468
  ...typeof theme["statusline"] === "string" ? { statusline: theme["statusline"] } : {},
@@ -5492,10 +5475,23 @@ function loadConfig(globalToml = "", projectToml = "") {
5492
5475
  ...obj(obj(p["theme"])["icons"])
5493
5476
  })
5494
5477
  },
5478
+ comments: {
5479
+ character: bool(comments["character"], d.comments.character),
5480
+ helpful: bool(comments["helpful"], d.comments.helpful),
5481
+ min_severity: oneOf(comments["min_severity"], ["low", "medium", "high", "critical"], d.comments.min_severity)
5482
+ },
5495
5483
  network: {
5496
5484
  fx_refresh: bool(network["fx_refresh"], d.network.fx_refresh),
5497
5485
  usage_fetch: bool(network["usage_fetch"], d.network.usage_fetch),
5498
5486
  balance_path: str(network["balance_path"], d.network.balance_path)
5487
+ },
5488
+ statusline: {
5489
+ currency: str(statusline["currency"], d.statusline.currency),
5490
+ ...typeof statusline["budget"] === "number" ? { budget: statusline["budget"] } : {},
5491
+ widgets: mergeWidgets({
5492
+ ...obj(obj(g["statusline"])["widgets"]),
5493
+ ...obj(obj(p["statusline"])["widgets"])
5494
+ })
5499
5495
  }
5500
5496
  };
5501
5497
  }
@@ -5544,11 +5540,10 @@ var init_config = __esm(() => {
5544
5540
  DEFAULT_CONFIG = {
5545
5541
  schema_version: 1,
5546
5542
  character: { enabled: true, mode: "random", name: "batman", roster: [] },
5547
- comments: { enabled: true },
5548
- helpful: { enabled: true, min_severity: "low" },
5549
- line: { currency: defaultCurrency(), widgets: DEFAULT_WIDGETS },
5550
- theme: { name: "houston", banding: "solid", mood_shift: false, icons: {} },
5551
- network: { fx_refresh: true, usage_fetch: true, balance_path: "" }
5543
+ theme: { name: "character", banding: "solid", mood_shift: false, icons: {} },
5544
+ comments: { character: true, helpful: true, min_severity: "low" },
5545
+ network: { fx_refresh: true, usage_fetch: true, balance_path: "" },
5546
+ statusline: { currency: defaultCurrency(), widgets: DEFAULT_WIDGETS }
5552
5547
  };
5553
5548
  });
5554
5549
 
@@ -7592,8 +7587,11 @@ function build(stdin, env, term, clock, overrides) {
7592
7587
  git,
7593
7588
  payload,
7594
7589
  scan,
7595
- widgets: config.line.widgets,
7596
- currency: { code: config.line.currency, rate: fxTable[config.line.currency] ?? 0 },
7590
+ widgets: config.statusline.widgets,
7591
+ currency: {
7592
+ code: config.statusline.currency,
7593
+ rate: fxTable[config.statusline.currency] ?? 0
7594
+ },
7597
7595
  homeDir: env["HOME"] ?? ""
7598
7596
  };
7599
7597
  const composed = composeStatusline(composeInputs);
@@ -7611,7 +7609,7 @@ function build(stdin, env, term, clock, overrides) {
7611
7609
  creds,
7612
7610
  balance
7613
7611
  };
7614
- const helpfulResult = config.helpful.enabled ? resolveHelpful(helpfulInputs, sessionState, clock, config.helpful.min_severity) : { comment: null, nextHelpful: sessionState.helpful };
7612
+ const helpfulResult = config.comments.helpful ? resolveHelpful(helpfulInputs, sessionState, clock, config.comments.min_severity) : { comment: null, nextHelpful: sessionState.helpful };
7615
7613
  const helpful = helpfulResult.comment;
7616
7614
  const pending = pendingMilestones(familiarity, clock);
7617
7615
  const charBase = {
@@ -7632,7 +7630,7 @@ function build(stdin, env, term, clock, overrides) {
7632
7630
  state: sessionState,
7633
7631
  clock,
7634
7632
  session,
7635
- config: { enabled: config.comments.enabled }
7633
+ config: { enabled: config.comments.character }
7636
7634
  });
7637
7635
  } catch {
7638
7636
  charResult = { comment: null, nextState: charBase };
@@ -7820,9 +7818,261 @@ var init_settings = __esm(() => {
7820
7818
  HOOK_EVENTS = ["PostToolUse", "PostToolUseFailure", "PostToolBatch"];
7821
7819
  });
7822
7820
 
7821
+ // src/cli/setup.ts
7822
+ import { readFileSync as readFileSync11 } from "node:fs";
7823
+ import { join as join17 } from "node:path";
7824
+ function themeNames() {
7825
+ return [CHARACTER_THEME, ...Object.keys(THEMES), ...PACKS];
7826
+ }
7827
+ function listValues(kind) {
7828
+ if (kind === "characters")
7829
+ return PACKS;
7830
+ if (kind === "themes")
7831
+ return themeNames();
7832
+ if (kind === "widgets")
7833
+ return WIDGET_IDS;
7834
+ return null;
7835
+ }
7836
+ function tokenize2(argv) {
7837
+ const pairs = new Map;
7838
+ const bools = new Set;
7839
+ const errors = [];
7840
+ for (let i = 0;i < argv.length; i++) {
7841
+ const tok = argv[i] ?? "";
7842
+ if (!tok.startsWith("--")) {
7843
+ errors.push(`ccsidekick: unexpected argument "${tok}"`);
7844
+ continue;
7845
+ }
7846
+ const body = tok.slice(2);
7847
+ const eq = body.indexOf("=");
7848
+ const key = eq >= 0 ? body.slice(0, eq) : body;
7849
+ if (BOOL_FLAGS.has(key)) {
7850
+ bools.add(key);
7851
+ continue;
7852
+ }
7853
+ if (!VALUE_FLAGS.has(key)) {
7854
+ errors.push(`ccsidekick: unknown flag "--${key}"`);
7855
+ continue;
7856
+ }
7857
+ if (eq >= 0) {
7858
+ pairs.set(key, body.slice(eq + 1));
7859
+ continue;
7860
+ }
7861
+ const next = argv[i + 1];
7862
+ if (next === undefined || next.startsWith("--")) {
7863
+ errors.push(`ccsidekick: --${key} needs a value`);
7864
+ continue;
7865
+ }
7866
+ pairs.set(key, next);
7867
+ i++;
7868
+ }
7869
+ return { pairs, bools, errors };
7870
+ }
7871
+ function enumInto(value, valid, flag, errors, set) {
7872
+ if (memberOf(value, valid))
7873
+ set(value);
7874
+ else
7875
+ errors.push(invalid(flag, value, valid));
7876
+ }
7877
+ function listInto(value, valid, flag, errors, set) {
7878
+ const list = splitList(value);
7879
+ const bad = list.filter((x) => !memberOf(x, valid));
7880
+ if (bad.length > 0)
7881
+ errors.push(invalid(flag, bad.join(","), valid));
7882
+ else
7883
+ set(list);
7884
+ }
7885
+ function parseSetup(argv, homeDir, env) {
7886
+ const { pairs, bools, errors } = tokenize2(argv);
7887
+ const flags = {};
7888
+ for (const [key, value] of pairs)
7889
+ VALIDATORS[key]?.(value, flags, errors);
7890
+ if (bools.has("global") && bools.has("local"))
7891
+ errors.push("ccsidekick: pass only one of --global / --local");
7892
+ const scope = bools.has("local") ? "local" : "global";
7893
+ const dir = pairs.get("config-dir") ?? env["CLAUDE_CONFIG_DIR"] ?? join17(homeDir, ".claude");
7894
+ return { flags, target: { scope, dir }, errors };
7895
+ }
7896
+ function applySetup(base, flags) {
7897
+ const mode = flags.mode ?? (flags.character !== undefined ? "fixed" : base.character.mode);
7898
+ const character = {
7899
+ ...base.character,
7900
+ mode,
7901
+ ...flags.character !== undefined ? { name: flags.character } : {},
7902
+ ...flags.roster !== undefined ? { roster: flags.roster } : {}
7903
+ };
7904
+ const statusline = {
7905
+ ...base.statusline,
7906
+ ...flags.currency !== undefined ? { currency: flags.currency } : {},
7907
+ ...flags.budget !== undefined ? { budget: flags.budget } : {},
7908
+ ...flags.widgets !== undefined ? {
7909
+ widgets: Object.fromEntries(WIDGET_IDS.map((id) => [id, flags.widgets?.includes(id) ?? false]))
7910
+ } : {}
7911
+ };
7912
+ return {
7913
+ ...base,
7914
+ character,
7915
+ statusline,
7916
+ comments: {
7917
+ ...base.comments,
7918
+ ...flags.comments !== undefined ? { character: flags.comments } : {},
7919
+ ...flags.helpful !== undefined ? { helpful: flags.helpful } : {},
7920
+ ...flags.minSeverity !== undefined ? { min_severity: flags.minSeverity } : {}
7921
+ },
7922
+ theme: flags.theme !== undefined ? { ...base.theme, name: flags.theme } : base.theme
7923
+ };
7924
+ }
7925
+ function existingConfigPath(target, cwd) {
7926
+ return target.scope === "global" ? join17(target.dir, "ccsidekick", "config.toml") : join17(cwd, ".ccsidekick", "config.toml");
7927
+ }
7928
+ function runSetup(argv, deps) {
7929
+ const parsed = parseSetup(argv, deps.homeDir, deps.env);
7930
+ if (parsed.errors.length > 0) {
7931
+ for (const e of parsed.errors)
7932
+ deps.err(`${e}
7933
+ `);
7934
+ return 1;
7935
+ }
7936
+ const existingText = deps.readConfig(existingConfigPath(parsed.target, deps.cwd));
7937
+ const base = existingText !== null ? loadConfig(existingText) : DEFAULT_CONFIG;
7938
+ const config = applySetup(base, parsed.flags);
7939
+ try {
7940
+ deps.save(config, parsed.target.scope, parsed.target.dir, deps.renderBin, {
7941
+ cwd: deps.cwd,
7942
+ wireLocalSettings: parsed.target.scope === "local"
7943
+ });
7944
+ } catch (e) {
7945
+ deps.err(`ccsidekick: ${e instanceof Error ? e.message : String(e)}
7946
+ `);
7947
+ return 1;
7948
+ }
7949
+ deps.out(`ccsidekick: configured ${config.character.name} (${config.character.mode}), theme ${config.theme.name}. ` + `Wired ${parsed.target.scope} at ${parsed.target.dir}.
7950
+ `);
7951
+ return 0;
7952
+ }
7953
+ function runList(kind, out, err) {
7954
+ const values = kind === undefined ? null : listValues(kind);
7955
+ if (values === null) {
7956
+ err(`ccsidekick: list expects one of: characters, themes, widgets
7957
+ `);
7958
+ return 1;
7959
+ }
7960
+ out(`${values.join(`
7961
+ `)}
7962
+ `);
7963
+ return 0;
7964
+ }
7965
+ function setupHelp() {
7966
+ return [
7967
+ "ccsidekick setup — configure and wire ccsidekick without the TUI",
7968
+ "",
7969
+ "Usage: ccsidekick setup [flags]",
7970
+ "",
7971
+ "Flags (only the ones you pass are applied):",
7972
+ ` --character <name> ${PACKS.join(", ")}`,
7973
+ ` --mode <mode> ${MODES.join(", ")}`,
7974
+ " --roster <a,b,c> characters for random mode (from --character's list)",
7975
+ ` --theme <name> ${themeNames().join(", ")}`,
7976
+ " --currency <code> e.g. USD, EUR, INR",
7977
+ " --budget <usd> monthly budget, a number >= 0",
7978
+ " --comments <on|off> the character's own comment line",
7979
+ " --helpful <on|off> the helpful-tip line",
7980
+ ` --min-severity <sev> ${SEVERITIES.join(", ")}`,
7981
+ " --widgets <a,b,c> statusline widgets to enable (others are turned off)",
7982
+ " --global | --local save target (default: global)",
7983
+ " --config-dir <path> Claude config dir (default: $CLAUDE_CONFIG_DIR or ~/.claude)",
7984
+ "",
7985
+ "List valid values for scripting: ccsidekick list characters|themes|widgets",
7986
+ ""
7987
+ ].join(`
7988
+ `);
7989
+ }
7990
+ function defaultReadConfig(path) {
7991
+ try {
7992
+ return readFileSync11(path, "utf8");
7993
+ } catch {
7994
+ return null;
7995
+ }
7996
+ }
7997
+ var WIDGET_IDS, MODES, SEVERITIES, VALUE_FLAGS, BOOL_FLAGS, splitList = (raw) => raw.split(",").map((s) => s.trim()).filter((s) => s !== ""), invalid = (flag, value, valid) => `ccsidekick: invalid --${flag} "${value}". Valid: ${valid.join(", ")}`, parseOnOff = (flag, value, errors) => {
7998
+ if (value === "on")
7999
+ return true;
8000
+ if (value === "off")
8001
+ return false;
8002
+ errors.push(invalid(flag, value, ["on", "off"]));
8003
+ return;
8004
+ }, memberOf = (value, valid) => valid.includes(value), VALIDATORS;
8005
+ var init_setup = __esm(() => {
8006
+ init_data();
8007
+ init_packs();
8008
+ init_render();
8009
+ init_sources();
8010
+ WIDGET_IDS = Object.keys(DEFAULT_CONFIG.statusline.widgets);
8011
+ MODES = ["fixed", "random"];
8012
+ SEVERITIES = ["low", "medium", "high", "critical"];
8013
+ VALUE_FLAGS = new Set([
8014
+ "character",
8015
+ "mode",
8016
+ "roster",
8017
+ "theme",
8018
+ "currency",
8019
+ "budget",
8020
+ "comments",
8021
+ "helpful",
8022
+ "min-severity",
8023
+ "widgets",
8024
+ "config-dir"
8025
+ ]);
8026
+ BOOL_FLAGS = new Set(["global", "local"]);
8027
+ VALIDATORS = {
8028
+ character: (v, f, e) => {
8029
+ enumInto(v, PACKS, "character", e, (x) => f.character = x);
8030
+ },
8031
+ mode: (v, f, e) => {
8032
+ enumInto(v, MODES, "mode", e, (x) => f.mode = x);
8033
+ },
8034
+ roster: (v, f, e) => {
8035
+ listInto(v, PACKS, "roster", e, (x) => f.roster = x);
8036
+ },
8037
+ theme: (v, f, e) => {
8038
+ enumInto(v, themeNames(), "theme", e, (x) => f.theme = x);
8039
+ },
8040
+ currency: (v, f, e) => {
8041
+ const u = v.trim().toUpperCase();
8042
+ if (u === "")
8043
+ e.push("ccsidekick: --currency needs a code");
8044
+ else
8045
+ f.currency = u;
8046
+ },
8047
+ budget: (v, f, e) => {
8048
+ const n = Number(v);
8049
+ if (Number.isFinite(n) && n >= 0)
8050
+ f.budget = n;
8051
+ else
8052
+ e.push(`ccsidekick: invalid --budget "${v}" (want a number >= 0)`);
8053
+ },
8054
+ comments: (v, f, e) => {
8055
+ const b = parseOnOff("comments", v, e);
8056
+ if (b !== undefined)
8057
+ f.comments = b;
8058
+ },
8059
+ helpful: (v, f, e) => {
8060
+ const b = parseOnOff("helpful", v, e);
8061
+ if (b !== undefined)
8062
+ f.helpful = b;
8063
+ },
8064
+ "min-severity": (v, f, e) => {
8065
+ enumInto(v, SEVERITIES, "min-severity", e, (x) => f.minSeverity = x);
8066
+ },
8067
+ widgets: (v, f, e) => {
8068
+ listInto(v, WIDGET_IDS, "widgets", e, (x) => f.widgets = x);
8069
+ }
8070
+ };
8071
+ });
8072
+
7823
8073
  // src/cli/uninstall.ts
7824
- import { existsSync as existsSync4, readFileSync as readFileSync11, readdirSync as readdirSync6 } from "node:fs";
7825
- import { basename as basename4, dirname as dirname8, join as join17 } from "node:path";
8074
+ import { existsSync as existsSync4, readFileSync as readFileSync12, readdirSync as readdirSync6 } from "node:fs";
8075
+ import { basename as basename4, dirname as dirname8, join as join18 } from "node:path";
7826
8076
  function asRecord2(v) {
7827
8077
  return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
7828
8078
  }
@@ -7868,7 +8118,7 @@ function restoreNewestBackup(settingsPath) {
7868
8118
  }
7869
8119
  if (newest === undefined)
7870
8120
  return null;
7871
- atomicWrite(settingsPath, readFileSync11(join17(dir, newest.name), "utf8"));
8121
+ atomicWrite(settingsPath, readFileSync12(join18(dir, newest.name), "utf8"));
7872
8122
  return newest.name;
7873
8123
  }
7874
8124
  function runRestore(settingsPath, emit) {
@@ -7922,7 +8172,7 @@ function runUninstall(opts) {
7922
8172
  return;
7923
8173
  }
7924
8174
  if (existsSync4(settingsPath)) {
7925
- const parsed = parseJsonObject2(readFileSync11(settingsPath, "utf8"));
8175
+ const parsed = parseJsonObject2(readFileSync12(settingsPath, "utf8"));
7926
8176
  if (parsed === null) {
7927
8177
  throw new Error(`ccsidekick: refusing to modify unparseable settings at ${settingsPath}`);
7928
8178
  }
@@ -7945,25 +8195,26 @@ var init_uninstall = __esm(() => {
7945
8195
  var init_cli = __esm(() => {
7946
8196
  init_render2();
7947
8197
  init_settings();
8198
+ init_setup();
7948
8199
  init_uninstall();
7949
8200
  });
7950
8201
 
7951
8202
  // src/tui/configDirs.ts
7952
8203
  import { existsSync as existsSync5, readdirSync as readdirSync7 } from "node:fs";
7953
- import { join as join18 } from "node:path";
8204
+ import { join as join19 } from "node:path";
7954
8205
  function discoverConfigDirs(homeDir, suggested) {
7955
- const home = join18(homeDir, ".claude");
8206
+ const home = join19(homeDir, ".claude");
7956
8207
  const set = new Set([home]);
7957
8208
  try {
7958
8209
  for (const entry of readdirSync7(homeDir, { withFileTypes: true })) {
7959
8210
  if (entry.isDirectory() && entry.name.startsWith(".claude")) {
7960
- set.add(join18(homeDir, entry.name));
8211
+ set.add(join19(homeDir, entry.name));
7961
8212
  }
7962
8213
  }
7963
8214
  } catch {}
7964
8215
  if (suggested !== undefined && suggested !== "")
7965
8216
  set.add(suggested);
7966
- const dirs = [...set].filter((d) => existsSync5(join18(d, "settings.json"))).sort();
8217
+ const dirs = [...set].filter((d) => existsSync5(join19(d, "settings.json"))).sort();
7967
8218
  let suggestedIndex = 0;
7968
8219
  if (suggested !== undefined && suggested !== "" && dirs.includes(suggested)) {
7969
8220
  suggestedIndex = dirs.indexOf(suggested);
@@ -8004,7 +8255,7 @@ var ACCENT = "#ffd700", FRAME = "gray", DANGER = "red";
8004
8255
 
8005
8256
  // src/tui/save.ts
8006
8257
  import { mkdirSync as mkdirSync4 } from "node:fs";
8007
- import { join as join19 } from "node:path";
8258
+ import { join as join20 } from "node:path";
8008
8259
  function defaultResolveVerbs(name) {
8009
8260
  const loaded = loadPack(name);
8010
8261
  return loaded.ok ? loaded.pack.spinnerVerbs : [];
@@ -8040,16 +8291,16 @@ function save(config, scope, dir, renderBin, opts = {}) {
8040
8291
  const normalized = normalize(config);
8041
8292
  const spinnerVerbs = spinnerVerbUnion(normalized, resolveVerbs, installed);
8042
8293
  if (scope === "global") {
8043
- writeConfigToml(join19(dir, "ccsidekick"), normalized);
8044
- installSettings({ settingsPath: join19(dir, "settings.json"), renderBin, spinnerVerbs });
8294
+ writeConfigToml(join20(dir, "ccsidekick"), normalized);
8295
+ installSettings({ settingsPath: join20(dir, "settings.json"), renderBin, spinnerVerbs });
8045
8296
  return;
8046
8297
  }
8047
- writeConfigToml(join19(cwd, ".ccsidekick"), normalized);
8298
+ writeConfigToml(join20(cwd, ".ccsidekick"), normalized);
8048
8299
  if (opts.wireLocalSettings === true) {
8049
- const claudeDir = join19(cwd, ".claude");
8300
+ const claudeDir = join20(cwd, ".claude");
8050
8301
  mkdirSync4(claudeDir, { recursive: true });
8051
8302
  installSettings({
8052
- settingsPath: join19(claudeDir, "settings.json"),
8303
+ settingsPath: join20(claudeDir, "settings.json"),
8053
8304
  renderBin,
8054
8305
  spinnerVerbs
8055
8306
  });
@@ -8089,13 +8340,14 @@ var init_keymap_data = __esm(() => {
8089
8340
  KEYMAP = [
8090
8341
  { keys: "w a s d", label: "move (also ↑↓←→, h j k l)", group: "Navigate" },
8091
8342
  { keys: "tab", label: "sidebar / content", group: "Navigate" },
8092
- { keys: "1-8", label: "jump to a section", group: "Navigate" },
8343
+ { keys: "1-7", label: "jump to a section", group: "Navigate" },
8093
8344
  { keys: "↵", label: "open, select, toggle", group: "Navigate" },
8094
8345
  { keys: "esc", label: "back, close, quit", group: "Navigate" },
8095
8346
  { keys: "/", label: "find", group: "Find & preview" },
8096
8347
  { keys: "?", label: "help", group: "Find & preview" },
8097
8348
  { keys: "ctrl+p", label: "preview", group: "Find & preview" },
8098
8349
  { keys: "ctrl+s", label: "save & install", group: "Actions" },
8350
+ { keys: "ctrl+w", label: "switch to wizard", group: "Actions" },
8099
8351
  { keys: "q", label: "quit", group: "Actions" }
8100
8352
  ];
8101
8353
  });
@@ -8145,7 +8397,7 @@ function dispatchCommand(state, ev, dirty2) {
8145
8397
  if (key.tab === true) {
8146
8398
  return stay({ ...state, zone: state.zone === "sidebar" ? "content" : "sidebar" });
8147
8399
  }
8148
- if (/^[1-8]$/.test(input)) {
8400
+ if (/^[1-7]$/.test(input)) {
8149
8401
  return stay({ ...state, section: Number(input) - 1, zone: "sidebar" });
8150
8402
  }
8151
8403
  return null;
@@ -8212,6 +8464,7 @@ function hintsFor(state) {
8212
8464
  { key: "/", label: "find" },
8213
8465
  { key: "^p", label: "preview" },
8214
8466
  { key: "^s", label: "save" },
8467
+ { key: "^w", label: "wizard" },
8215
8468
  { key: "?", label: "help" },
8216
8469
  { key: "q", label: "quit" }
8217
8470
  ];
@@ -8222,6 +8475,7 @@ function hintsFor(state) {
8222
8475
  { key: "/", label: "find" },
8223
8476
  { key: "^p", label: "preview" },
8224
8477
  { key: "^s", label: "save" },
8478
+ { key: "^w", label: "wizard" },
8225
8479
  { key: "?", label: "help" },
8226
8480
  { key: "q", label: "quit" }
8227
8481
  ];
@@ -8231,8 +8485,7 @@ var init_keymap = __esm(() => {
8231
8485
  SECTIONS = [
8232
8486
  "Character",
8233
8487
  "Theme",
8234
- "Voice",
8235
- "Tips",
8488
+ "Comments",
8236
8489
  "Network",
8237
8490
  "Statusline",
8238
8491
  "Statistics",
@@ -8314,15 +8567,6 @@ var init_glyphs = __esm(() => {
8314
8567
  };
8315
8568
  });
8316
8569
 
8317
- // src/tui/theme/motion.ts
8318
- function detectReducedMotion(env) {
8319
- if (env["NO_COLOR"] !== undefined)
8320
- return true;
8321
- if (env["CCSIDEKICK_REDUCE_MOTION"] !== undefined)
8322
- return true;
8323
- return false;
8324
- }
8325
-
8326
8570
  // src/tui/theme/tokens.ts
8327
8571
  function hexForXterm(index) {
8328
8572
  const [r, g, b] = xtermToRgb(index);
@@ -9800,1868 +10044,133 @@ var init_select = __esm(() => {
9800
10044
  init_use_select();
9801
10045
  });
9802
10046
 
9803
- // ../../node_modules/.bun/cli-spinners@3.4.0/node_modules/cli-spinners/spinners.json
9804
- var spinners_default;
9805
- var init_spinners = __esm(() => {
9806
- spinners_default = {
9807
- dots: {
9808
- interval: 80,
9809
- frames: [
9810
- "⠋",
9811
- "⠙",
9812
- "⠹",
9813
- "⠸",
9814
- "⠼",
9815
- "⠴",
9816
- "⠦",
9817
- "⠧",
9818
- "⠇",
9819
- "⠏"
9820
- ]
9821
- },
9822
- dots2: {
9823
- interval: 80,
9824
- frames: [
9825
- "⣾",
9826
- "⣽",
9827
- "⣻",
9828
- "⢿",
9829
- "⡿",
9830
- "⣟",
9831
- "⣯",
9832
- "⣷"
9833
- ]
9834
- },
9835
- dots3: {
9836
- interval: 80,
9837
- frames: [
9838
- "⠋",
9839
- "⠙",
9840
- "⠚",
9841
- "⠞",
9842
- "⠖",
9843
- "⠦",
9844
- "⠴",
9845
- "⠲",
9846
- "⠳",
9847
- "⠓"
9848
- ]
10047
+ // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/use-spinner.js
10048
+ import { useEffect as useEffect4, useState as useState5 } from "react";
10049
+ var init_use_spinner = () => {};
10050
+
10051
+ // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/spinner.js
10052
+ import React11 from "react";
10053
+ import { Box as Box13, Text as Text16 } from "ink";
10054
+ var init_spinner = __esm(() => {
10055
+ init_theme16();
10056
+ init_use_spinner();
10057
+ });
10058
+
10059
+ // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/index.js
10060
+ var init_spinner2 = __esm(() => {
10061
+ init_spinner();
10062
+ init_use_spinner();
10063
+ });
10064
+
10065
+ // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/text-input/use-text-input-state.js
10066
+ import { useReducer as useReducer3, useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo4 } from "react";
10067
+ var init_use_text_input_state = () => {};
10068
+
10069
+ // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
10070
+ function assembleStyles() {
10071
+ const codes = new Map;
10072
+ for (const [groupName, group] of Object.entries(styles)) {
10073
+ for (const [styleName, style] of Object.entries(group)) {
10074
+ styles[styleName] = {
10075
+ open: `\x1B[${style[0]}m`,
10076
+ close: `\x1B[${style[1]}m`
10077
+ };
10078
+ group[styleName] = styles[styleName];
10079
+ codes.set(style[0], style[1]);
10080
+ }
10081
+ Object.defineProperty(styles, groupName, {
10082
+ value: group,
10083
+ enumerable: false
10084
+ });
10085
+ }
10086
+ Object.defineProperty(styles, "codes", {
10087
+ value: codes,
10088
+ enumerable: false
10089
+ });
10090
+ styles.color.close = "\x1B[39m";
10091
+ styles.bgColor.close = "\x1B[49m";
10092
+ styles.color.ansi = wrapAnsi16();
10093
+ styles.color.ansi256 = wrapAnsi256();
10094
+ styles.color.ansi16m = wrapAnsi16m();
10095
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
10096
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
10097
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
10098
+ Object.defineProperties(styles, {
10099
+ rgbToAnsi256: {
10100
+ value(red, green, blue) {
10101
+ if (red === green && green === blue) {
10102
+ if (red < 8) {
10103
+ return 16;
10104
+ }
10105
+ if (red > 248) {
10106
+ return 231;
10107
+ }
10108
+ return Math.round((red - 8) / 247 * 24) + 232;
10109
+ }
10110
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
10111
+ },
10112
+ enumerable: false
9849
10113
  },
9850
- dots4: {
9851
- interval: 80,
9852
- frames: [
9853
- "⠄",
9854
- "⠆",
9855
- "⠇",
9856
- "⠋",
9857
- "⠙",
9858
- "⠸",
9859
- "⠰",
9860
- "⠠",
9861
- "⠰",
9862
- "⠸",
9863
- "⠙",
9864
- "⠋",
9865
- "⠇",
9866
- "⠆"
9867
- ]
10114
+ hexToRgb: {
10115
+ value(hex) {
10116
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
10117
+ if (!matches) {
10118
+ return [0, 0, 0];
10119
+ }
10120
+ let [colorString] = matches;
10121
+ if (colorString.length === 3) {
10122
+ colorString = [...colorString].map((character) => character + character).join("");
10123
+ }
10124
+ const integer = Number.parseInt(colorString, 16);
10125
+ return [
10126
+ integer >> 16 & 255,
10127
+ integer >> 8 & 255,
10128
+ integer & 255
10129
+ ];
10130
+ },
10131
+ enumerable: false
9868
10132
  },
9869
- dots5: {
9870
- interval: 80,
9871
- frames: [
9872
- "⠋",
9873
- "⠙",
9874
- "⠚",
9875
- "⠒",
9876
- "⠂",
9877
- "⠂",
9878
- "⠒",
9879
- "⠲",
9880
- "⠴",
9881
- "⠦",
9882
- "⠖",
9883
- "⠒",
9884
- "⠐",
9885
- "⠐",
9886
- "⠒",
9887
- "⠓",
9888
- "⠋"
9889
- ]
10133
+ hexToAnsi256: {
10134
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
10135
+ enumerable: false
9890
10136
  },
9891
- dots6: {
9892
- interval: 80,
9893
- frames: [
9894
- "⠁",
9895
- "⠉",
9896
- "⠙",
9897
- "⠚",
9898
- "⠒",
9899
- "⠂",
9900
- "⠂",
9901
- "⠒",
9902
- "⠲",
9903
- "⠴",
9904
- "⠤",
9905
- "⠄",
9906
- "⠄",
9907
- "⠤",
9908
- "⠴",
9909
- "⠲",
9910
- "⠒",
9911
- "⠂",
9912
- "⠂",
9913
- "⠒",
9914
- "⠚",
9915
- "⠙",
9916
- "⠉",
9917
- "⠁"
9918
- ]
10137
+ ansi256ToAnsi: {
10138
+ value(code) {
10139
+ if (code < 8) {
10140
+ return 30 + code;
10141
+ }
10142
+ if (code < 16) {
10143
+ return 90 + (code - 8);
10144
+ }
10145
+ let red;
10146
+ let green;
10147
+ let blue;
10148
+ if (code >= 232) {
10149
+ red = ((code - 232) * 10 + 8) / 255;
10150
+ green = red;
10151
+ blue = red;
10152
+ } else {
10153
+ code -= 16;
10154
+ const remainder = code % 36;
10155
+ red = Math.floor(code / 36) / 5;
10156
+ green = Math.floor(remainder / 6) / 5;
10157
+ blue = remainder % 6 / 5;
10158
+ }
10159
+ const value = Math.max(red, green, blue) * 2;
10160
+ if (value === 0) {
10161
+ return 30;
10162
+ }
10163
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
10164
+ if (value === 2) {
10165
+ result += 60;
10166
+ }
10167
+ return result;
10168
+ },
10169
+ enumerable: false
9919
10170
  },
9920
- dots7: {
9921
- interval: 80,
9922
- frames: [
9923
- "⠈",
9924
- "⠉",
9925
- "⠋",
9926
- "⠓",
9927
- "⠒",
9928
- "⠐",
9929
- "⠐",
9930
- "⠒",
9931
- "⠖",
9932
- "⠦",
9933
- "⠤",
9934
- "⠠",
9935
- "⠠",
9936
- "⠤",
9937
- "⠦",
9938
- "⠖",
9939
- "⠒",
9940
- "⠐",
9941
- "⠐",
9942
- "⠒",
9943
- "⠓",
9944
- "⠋",
9945
- "⠉",
9946
- "⠈"
9947
- ]
9948
- },
9949
- dots8: {
9950
- interval: 80,
9951
- frames: [
9952
- "⠁",
9953
- "⠁",
9954
- "⠉",
9955
- "⠙",
9956
- "⠚",
9957
- "⠒",
9958
- "⠂",
9959
- "⠂",
9960
- "⠒",
9961
- "⠲",
9962
- "⠴",
9963
- "⠤",
9964
- "⠄",
9965
- "⠄",
9966
- "⠤",
9967
- "⠠",
9968
- "⠠",
9969
- "⠤",
9970
- "⠦",
9971
- "⠖",
9972
- "⠒",
9973
- "⠐",
9974
- "⠐",
9975
- "⠒",
9976
- "⠓",
9977
- "⠋",
9978
- "⠉",
9979
- "⠈",
9980
- "⠈"
9981
- ]
9982
- },
9983
- dots9: {
9984
- interval: 80,
9985
- frames: [
9986
- "⢹",
9987
- "⢺",
9988
- "⢼",
9989
- "⣸",
9990
- "⣇",
9991
- "⡧",
9992
- "⡗",
9993
- "⡏"
9994
- ]
9995
- },
9996
- dots10: {
9997
- interval: 80,
9998
- frames: [
9999
- "⢄",
10000
- "⢂",
10001
- "⢁",
10002
- "⡁",
10003
- "⡈",
10004
- "⡐",
10005
- "⡠"
10006
- ]
10007
- },
10008
- dots11: {
10009
- interval: 100,
10010
- frames: [
10011
- "⠁",
10012
- "⠂",
10013
- "⠄",
10014
- "⡀",
10015
- "⢀",
10016
- "⠠",
10017
- "⠐",
10018
- "⠈"
10019
- ]
10020
- },
10021
- dots12: {
10022
- interval: 80,
10023
- frames: [
10024
- "⢀⠀",
10025
- "⡀⠀",
10026
- "⠄⠀",
10027
- "⢂⠀",
10028
- "⡂⠀",
10029
- "⠅⠀",
10030
- "⢃⠀",
10031
- "⡃⠀",
10032
- "⠍⠀",
10033
- "⢋⠀",
10034
- "⡋⠀",
10035
- "⠍⠁",
10036
- "⢋⠁",
10037
- "⡋⠁",
10038
- "⠍⠉",
10039
- "⠋⠉",
10040
- "⠋⠉",
10041
- "⠉⠙",
10042
- "⠉⠙",
10043
- "⠉⠩",
10044
- "⠈⢙",
10045
- "⠈⡙",
10046
- "⢈⠩",
10047
- "⡀⢙",
10048
- "⠄⡙",
10049
- "⢂⠩",
10050
- "⡂⢘",
10051
- "⠅⡘",
10052
- "⢃⠨",
10053
- "⡃⢐",
10054
- "⠍⡐",
10055
- "⢋⠠",
10056
- "⡋⢀",
10057
- "⠍⡁",
10058
- "⢋⠁",
10059
- "⡋⠁",
10060
- "⠍⠉",
10061
- "⠋⠉",
10062
- "⠋⠉",
10063
- "⠉⠙",
10064
- "⠉⠙",
10065
- "⠉⠩",
10066
- "⠈⢙",
10067
- "⠈⡙",
10068
- "⠈⠩",
10069
- "⠀⢙",
10070
- "⠀⡙",
10071
- "⠀⠩",
10072
- "⠀⢘",
10073
- "⠀⡘",
10074
- "⠀⠨",
10075
- "⠀⢐",
10076
- "⠀⡐",
10077
- "⠀⠠",
10078
- "⠀⢀",
10079
- "⠀⡀"
10080
- ]
10081
- },
10082
- dots13: {
10083
- interval: 80,
10084
- frames: [
10085
- "⣼",
10086
- "⣹",
10087
- "⢻",
10088
- "⠿",
10089
- "⡟",
10090
- "⣏",
10091
- "⣧",
10092
- "⣶"
10093
- ]
10094
- },
10095
- dots14: {
10096
- interval: 80,
10097
- frames: [
10098
- "⠉⠉",
10099
- "⠈⠙",
10100
- "⠀⠹",
10101
- "⠀⢸",
10102
- "⠀⣰",
10103
- "⢀⣠",
10104
- "⣀⣀",
10105
- "⣄⡀",
10106
- "⣆⠀",
10107
- "⡇⠀",
10108
- "⠏⠀",
10109
- "⠋⠁"
10110
- ]
10111
- },
10112
- dots8Bit: {
10113
- interval: 80,
10114
- frames: [
10115
- "⠀",
10116
- "⠁",
10117
- "⠂",
10118
- "⠃",
10119
- "⠄",
10120
- "⠅",
10121
- "⠆",
10122
- "⠇",
10123
- "⡀",
10124
- "⡁",
10125
- "⡂",
10126
- "⡃",
10127
- "⡄",
10128
- "⡅",
10129
- "⡆",
10130
- "⡇",
10131
- "⠈",
10132
- "⠉",
10133
- "⠊",
10134
- "⠋",
10135
- "⠌",
10136
- "⠍",
10137
- "⠎",
10138
- "⠏",
10139
- "⡈",
10140
- "⡉",
10141
- "⡊",
10142
- "⡋",
10143
- "⡌",
10144
- "⡍",
10145
- "⡎",
10146
- "⡏",
10147
- "⠐",
10148
- "⠑",
10149
- "⠒",
10150
- "⠓",
10151
- "⠔",
10152
- "⠕",
10153
- "⠖",
10154
- "⠗",
10155
- "⡐",
10156
- "⡑",
10157
- "⡒",
10158
- "⡓",
10159
- "⡔",
10160
- "⡕",
10161
- "⡖",
10162
- "⡗",
10163
- "⠘",
10164
- "⠙",
10165
- "⠚",
10166
- "⠛",
10167
- "⠜",
10168
- "⠝",
10169
- "⠞",
10170
- "⠟",
10171
- "⡘",
10172
- "⡙",
10173
- "⡚",
10174
- "⡛",
10175
- "⡜",
10176
- "⡝",
10177
- "⡞",
10178
- "⡟",
10179
- "⠠",
10180
- "⠡",
10181
- "⠢",
10182
- "⠣",
10183
- "⠤",
10184
- "⠥",
10185
- "⠦",
10186
- "⠧",
10187
- "⡠",
10188
- "⡡",
10189
- "⡢",
10190
- "⡣",
10191
- "⡤",
10192
- "⡥",
10193
- "⡦",
10194
- "⡧",
10195
- "⠨",
10196
- "⠩",
10197
- "⠪",
10198
- "⠫",
10199
- "⠬",
10200
- "⠭",
10201
- "⠮",
10202
- "⠯",
10203
- "⡨",
10204
- "⡩",
10205
- "⡪",
10206
- "⡫",
10207
- "⡬",
10208
- "⡭",
10209
- "⡮",
10210
- "⡯",
10211
- "⠰",
10212
- "⠱",
10213
- "⠲",
10214
- "⠳",
10215
- "⠴",
10216
- "⠵",
10217
- "⠶",
10218
- "⠷",
10219
- "⡰",
10220
- "⡱",
10221
- "⡲",
10222
- "⡳",
10223
- "⡴",
10224
- "⡵",
10225
- "⡶",
10226
- "⡷",
10227
- "⠸",
10228
- "⠹",
10229
- "⠺",
10230
- "⠻",
10231
- "⠼",
10232
- "⠽",
10233
- "⠾",
10234
- "⠿",
10235
- "⡸",
10236
- "⡹",
10237
- "⡺",
10238
- "⡻",
10239
- "⡼",
10240
- "⡽",
10241
- "⡾",
10242
- "⡿",
10243
- "⢀",
10244
- "⢁",
10245
- "⢂",
10246
- "⢃",
10247
- "⢄",
10248
- "⢅",
10249
- "⢆",
10250
- "⢇",
10251
- "⣀",
10252
- "⣁",
10253
- "⣂",
10254
- "⣃",
10255
- "⣄",
10256
- "⣅",
10257
- "⣆",
10258
- "⣇",
10259
- "⢈",
10260
- "⢉",
10261
- "⢊",
10262
- "⢋",
10263
- "⢌",
10264
- "⢍",
10265
- "⢎",
10266
- "⢏",
10267
- "⣈",
10268
- "⣉",
10269
- "⣊",
10270
- "⣋",
10271
- "⣌",
10272
- "⣍",
10273
- "⣎",
10274
- "⣏",
10275
- "⢐",
10276
- "⢑",
10277
- "⢒",
10278
- "⢓",
10279
- "⢔",
10280
- "⢕",
10281
- "⢖",
10282
- "⢗",
10283
- "⣐",
10284
- "⣑",
10285
- "⣒",
10286
- "⣓",
10287
- "⣔",
10288
- "⣕",
10289
- "⣖",
10290
- "⣗",
10291
- "⢘",
10292
- "⢙",
10293
- "⢚",
10294
- "⢛",
10295
- "⢜",
10296
- "⢝",
10297
- "⢞",
10298
- "⢟",
10299
- "⣘",
10300
- "⣙",
10301
- "⣚",
10302
- "⣛",
10303
- "⣜",
10304
- "⣝",
10305
- "⣞",
10306
- "⣟",
10307
- "⢠",
10308
- "⢡",
10309
- "⢢",
10310
- "⢣",
10311
- "⢤",
10312
- "⢥",
10313
- "⢦",
10314
- "⢧",
10315
- "⣠",
10316
- "⣡",
10317
- "⣢",
10318
- "⣣",
10319
- "⣤",
10320
- "⣥",
10321
- "⣦",
10322
- "⣧",
10323
- "⢨",
10324
- "⢩",
10325
- "⢪",
10326
- "⢫",
10327
- "⢬",
10328
- "⢭",
10329
- "⢮",
10330
- "⢯",
10331
- "⣨",
10332
- "⣩",
10333
- "⣪",
10334
- "⣫",
10335
- "⣬",
10336
- "⣭",
10337
- "⣮",
10338
- "⣯",
10339
- "⢰",
10340
- "⢱",
10341
- "⢲",
10342
- "⢳",
10343
- "⢴",
10344
- "⢵",
10345
- "⢶",
10346
- "⢷",
10347
- "⣰",
10348
- "⣱",
10349
- "⣲",
10350
- "⣳",
10351
- "⣴",
10352
- "⣵",
10353
- "⣶",
10354
- "⣷",
10355
- "⢸",
10356
- "⢹",
10357
- "⢺",
10358
- "⢻",
10359
- "⢼",
10360
- "⢽",
10361
- "⢾",
10362
- "⢿",
10363
- "⣸",
10364
- "⣹",
10365
- "⣺",
10366
- "⣻",
10367
- "⣼",
10368
- "⣽",
10369
- "⣾",
10370
- "⣿"
10371
- ]
10372
- },
10373
- dotsCircle: {
10374
- interval: 80,
10375
- frames: [
10376
- "⢎ ",
10377
- "⠎⠁",
10378
- "⠊⠑",
10379
- "⠈⠱",
10380
- " ⡱",
10381
- "⢀⡰",
10382
- "⢄⡠",
10383
- "⢆⡀"
10384
- ]
10385
- },
10386
- sand: {
10387
- interval: 80,
10388
- frames: [
10389
- "⠁",
10390
- "⠂",
10391
- "⠄",
10392
- "⡀",
10393
- "⡈",
10394
- "⡐",
10395
- "⡠",
10396
- "⣀",
10397
- "⣁",
10398
- "⣂",
10399
- "⣄",
10400
- "⣌",
10401
- "⣔",
10402
- "⣤",
10403
- "⣥",
10404
- "⣦",
10405
- "⣮",
10406
- "⣶",
10407
- "⣷",
10408
- "⣿",
10409
- "⡿",
10410
- "⠿",
10411
- "⢟",
10412
- "⠟",
10413
- "⡛",
10414
- "⠛",
10415
- "⠫",
10416
- "⢋",
10417
- "⠋",
10418
- "⠍",
10419
- "⡉",
10420
- "⠉",
10421
- "⠑",
10422
- "⠡",
10423
- "⢁"
10424
- ]
10425
- },
10426
- line: {
10427
- interval: 130,
10428
- frames: [
10429
- "-",
10430
- "\\",
10431
- "|",
10432
- "/"
10433
- ]
10434
- },
10435
- line2: {
10436
- interval: 100,
10437
- frames: [
10438
- "⠂",
10439
- "-",
10440
- "–",
10441
- "—",
10442
- "–",
10443
- "-"
10444
- ]
10445
- },
10446
- rollingLine: {
10447
- interval: 80,
10448
- frames: [
10449
- "/ ",
10450
- " - ",
10451
- " \\ ",
10452
- " |",
10453
- " |",
10454
- " \\ ",
10455
- " - ",
10456
- "/ "
10457
- ]
10458
- },
10459
- pipe: {
10460
- interval: 100,
10461
- frames: [
10462
- "┤",
10463
- "┘",
10464
- "┴",
10465
- "└",
10466
- "├",
10467
- "┌",
10468
- "┬",
10469
- "┐"
10470
- ]
10471
- },
10472
- simpleDots: {
10473
- interval: 400,
10474
- frames: [
10475
- ". ",
10476
- ".. ",
10477
- "...",
10478
- " "
10479
- ]
10480
- },
10481
- simpleDotsScrolling: {
10482
- interval: 200,
10483
- frames: [
10484
- ". ",
10485
- ".. ",
10486
- "...",
10487
- " ..",
10488
- " .",
10489
- " "
10490
- ]
10491
- },
10492
- star: {
10493
- interval: 70,
10494
- frames: [
10495
- "✶",
10496
- "✸",
10497
- "✹",
10498
- "✺",
10499
- "✹",
10500
- "✷"
10501
- ]
10502
- },
10503
- star2: {
10504
- interval: 80,
10505
- frames: [
10506
- "+",
10507
- "x",
10508
- "*"
10509
- ]
10510
- },
10511
- flip: {
10512
- interval: 70,
10513
- frames: [
10514
- "_",
10515
- "_",
10516
- "_",
10517
- "-",
10518
- "`",
10519
- "`",
10520
- "'",
10521
- "´",
10522
- "-",
10523
- "_",
10524
- "_",
10525
- "_"
10526
- ]
10527
- },
10528
- hamburger: {
10529
- interval: 100,
10530
- frames: [
10531
- "☱",
10532
- "☲",
10533
- "☴"
10534
- ]
10535
- },
10536
- growVertical: {
10537
- interval: 120,
10538
- frames: [
10539
- "▁",
10540
- "▃",
10541
- "▄",
10542
- "▅",
10543
- "▆",
10544
- "▇",
10545
- "▆",
10546
- "▅",
10547
- "▄",
10548
- "▃"
10549
- ]
10550
- },
10551
- growHorizontal: {
10552
- interval: 120,
10553
- frames: [
10554
- "▏",
10555
- "▎",
10556
- "▍",
10557
- "▌",
10558
- "▋",
10559
- "▊",
10560
- "▉",
10561
- "▊",
10562
- "▋",
10563
- "▌",
10564
- "▍",
10565
- "▎"
10566
- ]
10567
- },
10568
- balloon: {
10569
- interval: 140,
10570
- frames: [
10571
- " ",
10572
- ".",
10573
- "o",
10574
- "O",
10575
- "@",
10576
- "*",
10577
- " "
10578
- ]
10579
- },
10580
- balloon2: {
10581
- interval: 120,
10582
- frames: [
10583
- ".",
10584
- "o",
10585
- "O",
10586
- "°",
10587
- "O",
10588
- "o",
10589
- "."
10590
- ]
10591
- },
10592
- noise: {
10593
- interval: 100,
10594
- frames: [
10595
- "▓",
10596
- "▒",
10597
- "░"
10598
- ]
10599
- },
10600
- bounce: {
10601
- interval: 120,
10602
- frames: [
10603
- "⠁",
10604
- "⠂",
10605
- "⠄",
10606
- "⠂"
10607
- ]
10608
- },
10609
- boxBounce: {
10610
- interval: 120,
10611
- frames: [
10612
- "▖",
10613
- "▘",
10614
- "▝",
10615
- "▗"
10616
- ]
10617
- },
10618
- boxBounce2: {
10619
- interval: 100,
10620
- frames: [
10621
- "▌",
10622
- "▀",
10623
- "▐",
10624
- "▄"
10625
- ]
10626
- },
10627
- triangle: {
10628
- interval: 50,
10629
- frames: [
10630
- "◢",
10631
- "◣",
10632
- "◤",
10633
- "◥"
10634
- ]
10635
- },
10636
- binary: {
10637
- interval: 80,
10638
- frames: [
10639
- "010010",
10640
- "001100",
10641
- "100101",
10642
- "111010",
10643
- "111101",
10644
- "010111",
10645
- "101011",
10646
- "111000",
10647
- "110011",
10648
- "110101"
10649
- ]
10650
- },
10651
- arc: {
10652
- interval: 100,
10653
- frames: [
10654
- "◜",
10655
- "◠",
10656
- "◝",
10657
- "◞",
10658
- "◡",
10659
- "◟"
10660
- ]
10661
- },
10662
- circle: {
10663
- interval: 120,
10664
- frames: [
10665
- "◡",
10666
- "⊙",
10667
- "◠"
10668
- ]
10669
- },
10670
- squareCorners: {
10671
- interval: 180,
10672
- frames: [
10673
- "◰",
10674
- "◳",
10675
- "◲",
10676
- "◱"
10677
- ]
10678
- },
10679
- circleQuarters: {
10680
- interval: 120,
10681
- frames: [
10682
- "◴",
10683
- "◷",
10684
- "◶",
10685
- "◵"
10686
- ]
10687
- },
10688
- circleHalves: {
10689
- interval: 50,
10690
- frames: [
10691
- "◐",
10692
- "◓",
10693
- "◑",
10694
- "◒"
10695
- ]
10696
- },
10697
- squish: {
10698
- interval: 100,
10699
- frames: [
10700
- "╫",
10701
- "╪"
10702
- ]
10703
- },
10704
- toggle: {
10705
- interval: 250,
10706
- frames: [
10707
- "⊶",
10708
- "⊷"
10709
- ]
10710
- },
10711
- toggle2: {
10712
- interval: 80,
10713
- frames: [
10714
- "▫",
10715
- "▪"
10716
- ]
10717
- },
10718
- toggle3: {
10719
- interval: 120,
10720
- frames: [
10721
- "□",
10722
- "■"
10723
- ]
10724
- },
10725
- toggle4: {
10726
- interval: 100,
10727
- frames: [
10728
- "■",
10729
- "□",
10730
- "▪",
10731
- "▫"
10732
- ]
10733
- },
10734
- toggle5: {
10735
- interval: 100,
10736
- frames: [
10737
- "▮",
10738
- "▯"
10739
- ]
10740
- },
10741
- toggle6: {
10742
- interval: 300,
10743
- frames: [
10744
- "ဝ",
10745
- "၀"
10746
- ]
10747
- },
10748
- toggle7: {
10749
- interval: 80,
10750
- frames: [
10751
- "⦾",
10752
- "⦿"
10753
- ]
10754
- },
10755
- toggle8: {
10756
- interval: 100,
10757
- frames: [
10758
- "◍",
10759
- "◌"
10760
- ]
10761
- },
10762
- toggle9: {
10763
- interval: 100,
10764
- frames: [
10765
- "◉",
10766
- "◎"
10767
- ]
10768
- },
10769
- toggle10: {
10770
- interval: 100,
10771
- frames: [
10772
- "㊂",
10773
- "㊀",
10774
- "㊁"
10775
- ]
10776
- },
10777
- toggle11: {
10778
- interval: 50,
10779
- frames: [
10780
- "⧇",
10781
- "⧆"
10782
- ]
10783
- },
10784
- toggle12: {
10785
- interval: 120,
10786
- frames: [
10787
- "☗",
10788
- "☖"
10789
- ]
10790
- },
10791
- toggle13: {
10792
- interval: 80,
10793
- frames: [
10794
- "=",
10795
- "*",
10796
- "-"
10797
- ]
10798
- },
10799
- arrow: {
10800
- interval: 100,
10801
- frames: [
10802
- "←",
10803
- "↖",
10804
- "↑",
10805
- "↗",
10806
- "→",
10807
- "↘",
10808
- "↓",
10809
- "↙"
10810
- ]
10811
- },
10812
- arrow2: {
10813
- interval: 80,
10814
- frames: [
10815
- "⬆️ ",
10816
- "↗️ ",
10817
- "➡️ ",
10818
- "↘️ ",
10819
- "⬇️ ",
10820
- "↙️ ",
10821
- "⬅️ ",
10822
- "↖️ "
10823
- ]
10824
- },
10825
- arrow3: {
10826
- interval: 120,
10827
- frames: [
10828
- "▹▹▹▹▹",
10829
- "▸▹▹▹▹",
10830
- "▹▸▹▹▹",
10831
- "▹▹▸▹▹",
10832
- "▹▹▹▸▹",
10833
- "▹▹▹▹▸"
10834
- ]
10835
- },
10836
- bouncingBar: {
10837
- interval: 80,
10838
- frames: [
10839
- "[ ]",
10840
- "[= ]",
10841
- "[== ]",
10842
- "[=== ]",
10843
- "[====]",
10844
- "[ ===]",
10845
- "[ ==]",
10846
- "[ =]",
10847
- "[ ]",
10848
- "[ =]",
10849
- "[ ==]",
10850
- "[ ===]",
10851
- "[====]",
10852
- "[=== ]",
10853
- "[== ]",
10854
- "[= ]"
10855
- ]
10856
- },
10857
- bouncingBall: {
10858
- interval: 80,
10859
- frames: [
10860
- "( ● )",
10861
- "( ● )",
10862
- "( ● )",
10863
- "( ● )",
10864
- "( ●)",
10865
- "( ● )",
10866
- "( ● )",
10867
- "( ● )",
10868
- "( ● )",
10869
- "(● )"
10870
- ]
10871
- },
10872
- smiley: {
10873
- interval: 200,
10874
- frames: [
10875
- "😄 ",
10876
- "😝 "
10877
- ]
10878
- },
10879
- monkey: {
10880
- interval: 300,
10881
- frames: [
10882
- "🙈 ",
10883
- "🙈 ",
10884
- "🙉 ",
10885
- "🙊 "
10886
- ]
10887
- },
10888
- hearts: {
10889
- interval: 100,
10890
- frames: [
10891
- "💛 ",
10892
- "💙 ",
10893
- "💜 ",
10894
- "💚 ",
10895
- "💗 "
10896
- ]
10897
- },
10898
- clock: {
10899
- interval: 100,
10900
- frames: [
10901
- "🕛 ",
10902
- "🕐 ",
10903
- "🕑 ",
10904
- "🕒 ",
10905
- "🕓 ",
10906
- "🕔 ",
10907
- "🕕 ",
10908
- "🕖 ",
10909
- "🕗 ",
10910
- "🕘 ",
10911
- "🕙 ",
10912
- "🕚 "
10913
- ]
10914
- },
10915
- earth: {
10916
- interval: 180,
10917
- frames: [
10918
- "🌍 ",
10919
- "🌎 ",
10920
- "🌏 "
10921
- ]
10922
- },
10923
- material: {
10924
- interval: 17,
10925
- frames: [
10926
- "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10927
- "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10928
- "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10929
- "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10930
- "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10931
- "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
10932
- "███████▁▁▁▁▁▁▁▁▁▁▁▁▁",
10933
- "████████▁▁▁▁▁▁▁▁▁▁▁▁",
10934
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10935
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10936
- "██████████▁▁▁▁▁▁▁▁▁▁",
10937
- "███████████▁▁▁▁▁▁▁▁▁",
10938
- "█████████████▁▁▁▁▁▁▁",
10939
- "██████████████▁▁▁▁▁▁",
10940
- "██████████████▁▁▁▁▁▁",
10941
- "▁██████████████▁▁▁▁▁",
10942
- "▁██████████████▁▁▁▁▁",
10943
- "▁██████████████▁▁▁▁▁",
10944
- "▁▁██████████████▁▁▁▁",
10945
- "▁▁▁██████████████▁▁▁",
10946
- "▁▁▁▁█████████████▁▁▁",
10947
- "▁▁▁▁██████████████▁▁",
10948
- "▁▁▁▁██████████████▁▁",
10949
- "▁▁▁▁▁██████████████▁",
10950
- "▁▁▁▁▁██████████████▁",
10951
- "▁▁▁▁▁██████████████▁",
10952
- "▁▁▁▁▁▁██████████████",
10953
- "▁▁▁▁▁▁██████████████",
10954
- "▁▁▁▁▁▁▁█████████████",
10955
- "▁▁▁▁▁▁▁█████████████",
10956
- "▁▁▁▁▁▁▁▁████████████",
10957
- "▁▁▁▁▁▁▁▁████████████",
10958
- "▁▁▁▁▁▁▁▁▁███████████",
10959
- "▁▁▁▁▁▁▁▁▁███████████",
10960
- "▁▁▁▁▁▁▁▁▁▁██████████",
10961
- "▁▁▁▁▁▁▁▁▁▁██████████",
10962
- "▁▁▁▁▁▁▁▁▁▁▁▁████████",
10963
- "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
10964
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████",
10965
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
10966
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
10967
- "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
10968
- "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
10969
- "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
10970
- "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
10971
- "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
10972
- "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
10973
- "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
10974
- "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█",
10975
- "████████▁▁▁▁▁▁▁▁▁▁▁▁",
10976
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10977
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10978
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10979
- "█████████▁▁▁▁▁▁▁▁▁▁▁",
10980
- "███████████▁▁▁▁▁▁▁▁▁",
10981
- "████████████▁▁▁▁▁▁▁▁",
10982
- "████████████▁▁▁▁▁▁▁▁",
10983
- "██████████████▁▁▁▁▁▁",
10984
- "██████████████▁▁▁▁▁▁",
10985
- "▁██████████████▁▁▁▁▁",
10986
- "▁██████████████▁▁▁▁▁",
10987
- "▁▁▁█████████████▁▁▁▁",
10988
- "▁▁▁▁▁████████████▁▁▁",
10989
- "▁▁▁▁▁████████████▁▁▁",
10990
- "▁▁▁▁▁▁███████████▁▁▁",
10991
- "▁▁▁▁▁▁▁▁█████████▁▁▁",
10992
- "▁▁▁▁▁▁▁▁█████████▁▁▁",
10993
- "▁▁▁▁▁▁▁▁▁█████████▁▁",
10994
- "▁▁▁▁▁▁▁▁▁█████████▁▁",
10995
- "▁▁▁▁▁▁▁▁▁▁█████████▁",
10996
- "▁▁▁▁▁▁▁▁▁▁▁████████▁",
10997
- "▁▁▁▁▁▁▁▁▁▁▁████████▁",
10998
- "▁▁▁▁▁▁▁▁▁▁▁▁███████▁",
10999
- "▁▁▁▁▁▁▁▁▁▁▁▁███████▁",
11000
- "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
11001
- "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
11002
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
11003
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
11004
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
11005
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
11006
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
11007
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
11008
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
11009
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
11010
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
11011
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
11012
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
11013
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
11014
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
11015
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
11016
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
11017
- "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁"
11018
- ]
11019
- },
11020
- moon: {
11021
- interval: 80,
11022
- frames: [
11023
- "🌑 ",
11024
- "🌒 ",
11025
- "🌓 ",
11026
- "🌔 ",
11027
- "🌕 ",
11028
- "🌖 ",
11029
- "🌗 ",
11030
- "🌘 "
11031
- ]
11032
- },
11033
- runner: {
11034
- interval: 140,
11035
- frames: [
11036
- "🚶 ",
11037
- "🏃 "
11038
- ]
11039
- },
11040
- pong: {
11041
- interval: 80,
11042
- frames: [
11043
- "▐⠂ ▌",
11044
- "▐⠈ ▌",
11045
- "▐ ⠂ ▌",
11046
- "▐ ⠠ ▌",
11047
- "▐ ⡀ ▌",
11048
- "▐ ⠠ ▌",
11049
- "▐ ⠂ ▌",
11050
- "▐ ⠈ ▌",
11051
- "▐ ⠂ ▌",
11052
- "▐ ⠠ ▌",
11053
- "▐ ⡀ ▌",
11054
- "▐ ⠠ ▌",
11055
- "▐ ⠂ ▌",
11056
- "▐ ⠈ ▌",
11057
- "▐ ⠂▌",
11058
- "▐ ⠠▌",
11059
- "▐ ⡀▌",
11060
- "▐ ⠠ ▌",
11061
- "▐ ⠂ ▌",
11062
- "▐ ⠈ ▌",
11063
- "▐ ⠂ ▌",
11064
- "▐ ⠠ ▌",
11065
- "▐ ⡀ ▌",
11066
- "▐ ⠠ ▌",
11067
- "▐ ⠂ ▌",
11068
- "▐ ⠈ ▌",
11069
- "▐ ⠂ ▌",
11070
- "▐ ⠠ ▌",
11071
- "▐ ⡀ ▌",
11072
- "▐⠠ ▌"
11073
- ]
11074
- },
11075
- shark: {
11076
- interval: 120,
11077
- frames: [
11078
- "▐|\\____________▌",
11079
- "▐_|\\___________▌",
11080
- "▐__|\\__________▌",
11081
- "▐___|\\_________▌",
11082
- "▐____|\\________▌",
11083
- "▐_____|\\_______▌",
11084
- "▐______|\\______▌",
11085
- "▐_______|\\_____▌",
11086
- "▐________|\\____▌",
11087
- "▐_________|\\___▌",
11088
- "▐__________|\\__▌",
11089
- "▐___________|\\_▌",
11090
- "▐____________|\\▌",
11091
- "▐____________/|▌",
11092
- "▐___________/|_▌",
11093
- "▐__________/|__▌",
11094
- "▐_________/|___▌",
11095
- "▐________/|____▌",
11096
- "▐_______/|_____▌",
11097
- "▐______/|______▌",
11098
- "▐_____/|_______▌",
11099
- "▐____/|________▌",
11100
- "▐___/|_________▌",
11101
- "▐__/|__________▌",
11102
- "▐_/|___________▌",
11103
- "▐/|____________▌"
11104
- ]
11105
- },
11106
- dqpb: {
11107
- interval: 100,
11108
- frames: [
11109
- "d",
11110
- "q",
11111
- "p",
11112
- "b"
11113
- ]
11114
- },
11115
- weather: {
11116
- interval: 100,
11117
- frames: [
11118
- "☀️ ",
11119
- "☀️ ",
11120
- "☀️ ",
11121
- "🌤 ",
11122
- "⛅️ ",
11123
- "🌥 ",
11124
- "☁️ ",
11125
- "🌧 ",
11126
- "🌨 ",
11127
- "🌧 ",
11128
- "🌨 ",
11129
- "🌧 ",
11130
- "🌨 ",
11131
- "⛈ ",
11132
- "🌨 ",
11133
- "🌧 ",
11134
- "🌨 ",
11135
- "☁️ ",
11136
- "🌥 ",
11137
- "⛅️ ",
11138
- "🌤 ",
11139
- "☀️ ",
11140
- "☀️ "
11141
- ]
11142
- },
11143
- christmas: {
11144
- interval: 400,
11145
- frames: [
11146
- "🌲",
11147
- "🎄"
11148
- ]
11149
- },
11150
- grenade: {
11151
- interval: 80,
11152
- frames: [
11153
- "، ",
11154
- "′ ",
11155
- " ´ ",
11156
- " ‾ ",
11157
- " ⸌",
11158
- " ⸊",
11159
- " |",
11160
- " ⁎",
11161
- " ⁕",
11162
- " ෴ ",
11163
- " ⁓",
11164
- " ",
11165
- " ",
11166
- " "
11167
- ]
11168
- },
11169
- point: {
11170
- interval: 125,
11171
- frames: [
11172
- "∙∙∙",
11173
- "●∙∙",
11174
- "∙●∙",
11175
- "∙∙●",
11176
- "∙∙∙"
11177
- ]
11178
- },
11179
- layer: {
11180
- interval: 150,
11181
- frames: [
11182
- "-",
11183
- "=",
11184
- "≡"
11185
- ]
11186
- },
11187
- betaWave: {
11188
- interval: 80,
11189
- frames: [
11190
- "ρββββββ",
11191
- "βρβββββ",
11192
- "ββρββββ",
11193
- "βββρβββ",
11194
- "ββββρββ",
11195
- "βββββρβ",
11196
- "ββββββρ"
11197
- ]
11198
- },
11199
- fingerDance: {
11200
- interval: 160,
11201
- frames: [
11202
- "🤘 ",
11203
- "🤟 ",
11204
- "🖖 ",
11205
- "✋ ",
11206
- "🤚 ",
11207
- "👆 "
11208
- ]
11209
- },
11210
- fistBump: {
11211
- interval: 80,
11212
- frames: [
11213
- "🤜    🤛 ",
11214
- "🤜    🤛 ",
11215
- "🤜    🤛 ",
11216
- " 🤜  🤛  ",
11217
- "  🤜🤛   ",
11218
- " 🤜✨🤛   ",
11219
- "🤜 ✨ 🤛  "
11220
- ]
11221
- },
11222
- soccerHeader: {
11223
- interval: 80,
11224
- frames: [
11225
- " 🧑⚽️ 🧑 ",
11226
- "🧑 ⚽️ 🧑 ",
11227
- "🧑 ⚽️ 🧑 ",
11228
- "🧑 ⚽️ 🧑 ",
11229
- "🧑 ⚽️ 🧑 ",
11230
- "🧑 ⚽️ 🧑 ",
11231
- "🧑 ⚽️🧑 ",
11232
- "🧑 ⚽️ 🧑 ",
11233
- "🧑 ⚽️ 🧑 ",
11234
- "🧑 ⚽️ 🧑 ",
11235
- "🧑 ⚽️ 🧑 ",
11236
- "🧑 ⚽️ 🧑 "
11237
- ]
11238
- },
11239
- mindblown: {
11240
- interval: 160,
11241
- frames: [
11242
- "😐 ",
11243
- "😐 ",
11244
- "😮 ",
11245
- "😮 ",
11246
- "😦 ",
11247
- "😦 ",
11248
- "😧 ",
11249
- "😧 ",
11250
- "🤯 ",
11251
- "💥 ",
11252
- "✨ ",
11253
- "  ",
11254
- "  ",
11255
- "  "
11256
- ]
11257
- },
11258
- speaker: {
11259
- interval: 160,
11260
- frames: [
11261
- "🔈 ",
11262
- "🔉 ",
11263
- "🔊 ",
11264
- "🔉 "
11265
- ]
11266
- },
11267
- orangePulse: {
11268
- interval: 100,
11269
- frames: [
11270
- "🔸 ",
11271
- "🔶 ",
11272
- "🟠 ",
11273
- "🟠 ",
11274
- "🔶 "
11275
- ]
11276
- },
11277
- bluePulse: {
11278
- interval: 100,
11279
- frames: [
11280
- "🔹 ",
11281
- "🔷 ",
11282
- "🔵 ",
11283
- "🔵 ",
11284
- "🔷 "
11285
- ]
11286
- },
11287
- orangeBluePulse: {
11288
- interval: 100,
11289
- frames: [
11290
- "🔸 ",
11291
- "🔶 ",
11292
- "🟠 ",
11293
- "🟠 ",
11294
- "🔶 ",
11295
- "🔹 ",
11296
- "🔷 ",
11297
- "🔵 ",
11298
- "🔵 ",
11299
- "🔷 "
11300
- ]
11301
- },
11302
- timeTravel: {
11303
- interval: 100,
11304
- frames: [
11305
- "🕛 ",
11306
- "🕚 ",
11307
- "🕙 ",
11308
- "🕘 ",
11309
- "🕗 ",
11310
- "🕖 ",
11311
- "🕕 ",
11312
- "🕔 ",
11313
- "🕓 ",
11314
- "🕒 ",
11315
- "🕑 ",
11316
- "🕐 "
11317
- ]
11318
- },
11319
- aesthetic: {
11320
- interval: 80,
11321
- frames: [
11322
- "▰▱▱▱▱▱▱",
11323
- "▰▰▱▱▱▱▱",
11324
- "▰▰▰▱▱▱▱",
11325
- "▰▰▰▰▱▱▱",
11326
- "▰▰▰▰▰▱▱",
11327
- "▰▰▰▰▰▰▱",
11328
- "▰▰▰▰▰▰▰",
11329
- "▰▱▱▱▱▱▱"
11330
- ]
11331
- },
11332
- dwarfFortress: {
11333
- interval: 80,
11334
- frames: [
11335
- " ██████£££ ",
11336
- "☺██████£££ ",
11337
- "☺██████£££ ",
11338
- "☺▓█████£££ ",
11339
- "☺▓█████£££ ",
11340
- "☺▒█████£££ ",
11341
- "☺▒█████£££ ",
11342
- "☺░█████£££ ",
11343
- "☺░█████£££ ",
11344
- "☺ █████£££ ",
11345
- " ☺█████£££ ",
11346
- " ☺█████£££ ",
11347
- " ☺▓████£££ ",
11348
- " ☺▓████£££ ",
11349
- " ☺▒████£££ ",
11350
- " ☺▒████£££ ",
11351
- " ☺░████£££ ",
11352
- " ☺░████£££ ",
11353
- " ☺ ████£££ ",
11354
- " ☺████£££ ",
11355
- " ☺████£££ ",
11356
- " ☺▓███£££ ",
11357
- " ☺▓███£££ ",
11358
- " ☺▒███£££ ",
11359
- " ☺▒███£££ ",
11360
- " ☺░███£££ ",
11361
- " ☺░███£££ ",
11362
- " ☺ ███£££ ",
11363
- " ☺███£££ ",
11364
- " ☺███£££ ",
11365
- " ☺▓██£££ ",
11366
- " ☺▓██£££ ",
11367
- " ☺▒██£££ ",
11368
- " ☺▒██£££ ",
11369
- " ☺░██£££ ",
11370
- " ☺░██£££ ",
11371
- " ☺ ██£££ ",
11372
- " ☺██£££ ",
11373
- " ☺██£££ ",
11374
- " ☺▓█£££ ",
11375
- " ☺▓█£££ ",
11376
- " ☺▒█£££ ",
11377
- " ☺▒█£££ ",
11378
- " ☺░█£££ ",
11379
- " ☺░█£££ ",
11380
- " ☺ █£££ ",
11381
- " ☺█£££ ",
11382
- " ☺█£££ ",
11383
- " ☺▓£££ ",
11384
- " ☺▓£££ ",
11385
- " ☺▒£££ ",
11386
- " ☺▒£££ ",
11387
- " ☺░£££ ",
11388
- " ☺░£££ ",
11389
- " ☺ £££ ",
11390
- " ☺£££ ",
11391
- " ☺£££ ",
11392
- " ☺▓££ ",
11393
- " ☺▓££ ",
11394
- " ☺▒££ ",
11395
- " ☺▒££ ",
11396
- " ☺░££ ",
11397
- " ☺░££ ",
11398
- " ☺ ££ ",
11399
- " ☺££ ",
11400
- " ☺££ ",
11401
- " ☺▓£ ",
11402
- " ☺▓£ ",
11403
- " ☺▒£ ",
11404
- " ☺▒£ ",
11405
- " ☺░£ ",
11406
- " ☺░£ ",
11407
- " ☺ £ ",
11408
- " ☺£ ",
11409
- " ☺£ ",
11410
- " ☺▓ ",
11411
- " ☺▓ ",
11412
- " ☺▒ ",
11413
- " ☺▒ ",
11414
- " ☺░ ",
11415
- " ☺░ ",
11416
- " ☺ ",
11417
- " ☺ &",
11418
- " ☺ ☼&",
11419
- " ☺ ☼ &",
11420
- " ☺☼ &",
11421
- " ☺☼ & ",
11422
- " ‼ & ",
11423
- " ☺ & ",
11424
- " ‼ & ",
11425
- " ☺ & ",
11426
- " ‼ & ",
11427
- " ☺ & ",
11428
- "‼ & ",
11429
- " & ",
11430
- " & ",
11431
- " & ░ ",
11432
- " & ▒ ",
11433
- " & ▓ ",
11434
- " & £ ",
11435
- " & ░£ ",
11436
- " & ▒£ ",
11437
- " & ▓£ ",
11438
- " & ££ ",
11439
- " & ░££ ",
11440
- " & ▒££ ",
11441
- "& ▓££ ",
11442
- "& £££ ",
11443
- " ░£££ ",
11444
- " ▒£££ ",
11445
- " ▓£££ ",
11446
- " █£££ ",
11447
- " ░█£££ ",
11448
- " ▒█£££ ",
11449
- " ▓█£££ ",
11450
- " ██£££ ",
11451
- " ░██£££ ",
11452
- " ▒██£££ ",
11453
- " ▓██£££ ",
11454
- " ███£££ ",
11455
- " ░███£££ ",
11456
- " ▒███£££ ",
11457
- " ▓███£££ ",
11458
- " ████£££ ",
11459
- " ░████£££ ",
11460
- " ▒████£££ ",
11461
- " ▓████£££ ",
11462
- " █████£££ ",
11463
- " ░█████£££ ",
11464
- " ▒█████£££ ",
11465
- " ▓█████£££ ",
11466
- " ██████£££ ",
11467
- " ██████£££ "
11468
- ]
11469
- },
11470
- fish: {
11471
- interval: 80,
11472
- frames: [
11473
- "~~~~~~~~~~~~~~~~~~~~",
11474
- "> ~~~~~~~~~~~~~~~~~~",
11475
- "º> ~~~~~~~~~~~~~~~~~",
11476
- "(º> ~~~~~~~~~~~~~~~~",
11477
- "((º> ~~~~~~~~~~~~~~~",
11478
- "<((º> ~~~~~~~~~~~~~~",
11479
- "><((º> ~~~~~~~~~~~~~",
11480
- " ><((º> ~~~~~~~~~~~~",
11481
- "~ ><((º> ~~~~~~~~~~~",
11482
- "~~ <>((º> ~~~~~~~~~~",
11483
- "~~~ ><((º> ~~~~~~~~~",
11484
- "~~~~ <>((º> ~~~~~~~~",
11485
- "~~~~~ ><((º> ~~~~~~~",
11486
- "~~~~~~ <>((º> ~~~~~~",
11487
- "~~~~~~~ ><((º> ~~~~~",
11488
- "~~~~~~~~ <>((º> ~~~~",
11489
- "~~~~~~~~~ ><((º> ~~~",
11490
- "~~~~~~~~~~ <>((º> ~~",
11491
- "~~~~~~~~~~~ ><((º> ~",
11492
- "~~~~~~~~~~~~ <>((º> ",
11493
- "~~~~~~~~~~~~~ ><((º>",
11494
- "~~~~~~~~~~~~~~ <>((º",
11495
- "~~~~~~~~~~~~~~~ ><((",
11496
- "~~~~~~~~~~~~~~~~ <>(",
11497
- "~~~~~~~~~~~~~~~~~ ><",
11498
- "~~~~~~~~~~~~~~~~~~ <",
11499
- "~~~~~~~~~~~~~~~~~~~~"
11500
- ]
11501
- }
11502
- };
11503
- });
11504
-
11505
- // ../../node_modules/.bun/cli-spinners@3.4.0/node_modules/cli-spinners/index.js
11506
- var cli_spinners_default, spinnersList;
11507
- var init_cli_spinners = __esm(() => {
11508
- init_spinners();
11509
- cli_spinners_default = spinners_default;
11510
- spinnersList = Object.keys(spinners_default);
11511
- });
11512
-
11513
- // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/use-spinner.js
11514
- import { useEffect as useEffect4, useState as useState5 } from "react";
11515
- function useSpinner({ type = "dots" }) {
11516
- const [frame, setFrame] = useState5(0);
11517
- const spinner = cli_spinners_default[type];
11518
- useEffect4(() => {
11519
- const timer = setInterval(() => {
11520
- setFrame((previousFrame) => {
11521
- const isLastFrame = previousFrame === spinner.frames.length - 1;
11522
- return isLastFrame ? 0 : previousFrame + 1;
11523
- });
11524
- }, spinner.interval);
11525
- return () => {
11526
- clearInterval(timer);
11527
- };
11528
- }, [spinner]);
11529
- return {
11530
- frame: spinner.frames[frame] ?? ""
11531
- };
11532
- }
11533
- var init_use_spinner = __esm(() => {
11534
- init_cli_spinners();
11535
- });
11536
-
11537
- // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/spinner.js
11538
- import React11 from "react";
11539
- import { Box as Box13, Text as Text16 } from "ink";
11540
- function Spinner({ label, type }) {
11541
- const { frame } = useSpinner({ type });
11542
- const { styles } = useComponentTheme("Spinner");
11543
- return React11.createElement(Box13, { ...styles.container() }, React11.createElement(Text16, { ...styles.frame() }, frame), label && React11.createElement(Text16, { ...styles.label() }, label));
11544
- }
11545
- var init_spinner = __esm(() => {
11546
- init_theme16();
11547
- init_use_spinner();
11548
- });
11549
-
11550
- // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/spinner/index.js
11551
- var init_spinner2 = __esm(() => {
11552
- init_spinner();
11553
- init_use_spinner();
11554
- });
11555
-
11556
- // ../../node_modules/.bun/@inkjs+ui@2.0.0+fa875fef9f949ebd/node_modules/@inkjs/ui/build/components/text-input/use-text-input-state.js
11557
- import { useReducer as useReducer3, useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo4 } from "react";
11558
- var init_use_text_input_state = () => {};
11559
-
11560
- // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
11561
- function assembleStyles() {
11562
- const codes = new Map;
11563
- for (const [groupName, group] of Object.entries(styles)) {
11564
- for (const [styleName, style] of Object.entries(group)) {
11565
- styles[styleName] = {
11566
- open: `\x1B[${style[0]}m`,
11567
- close: `\x1B[${style[1]}m`
11568
- };
11569
- group[styleName] = styles[styleName];
11570
- codes.set(style[0], style[1]);
11571
- }
11572
- Object.defineProperty(styles, groupName, {
11573
- value: group,
11574
- enumerable: false
11575
- });
11576
- }
11577
- Object.defineProperty(styles, "codes", {
11578
- value: codes,
11579
- enumerable: false
11580
- });
11581
- styles.color.close = "\x1B[39m";
11582
- styles.bgColor.close = "\x1B[49m";
11583
- styles.color.ansi = wrapAnsi16();
11584
- styles.color.ansi256 = wrapAnsi256();
11585
- styles.color.ansi16m = wrapAnsi16m();
11586
- styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
11587
- styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
11588
- styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
11589
- Object.defineProperties(styles, {
11590
- rgbToAnsi256: {
11591
- value(red, green, blue) {
11592
- if (red === green && green === blue) {
11593
- if (red < 8) {
11594
- return 16;
11595
- }
11596
- if (red > 248) {
11597
- return 231;
11598
- }
11599
- return Math.round((red - 8) / 247 * 24) + 232;
11600
- }
11601
- return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
11602
- },
11603
- enumerable: false
11604
- },
11605
- hexToRgb: {
11606
- value(hex) {
11607
- const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
11608
- if (!matches) {
11609
- return [0, 0, 0];
11610
- }
11611
- let [colorString] = matches;
11612
- if (colorString.length === 3) {
11613
- colorString = [...colorString].map((character) => character + character).join("");
11614
- }
11615
- const integer = Number.parseInt(colorString, 16);
11616
- return [
11617
- integer >> 16 & 255,
11618
- integer >> 8 & 255,
11619
- integer & 255
11620
- ];
11621
- },
11622
- enumerable: false
11623
- },
11624
- hexToAnsi256: {
11625
- value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
11626
- enumerable: false
11627
- },
11628
- ansi256ToAnsi: {
11629
- value(code) {
11630
- if (code < 8) {
11631
- return 30 + code;
11632
- }
11633
- if (code < 16) {
11634
- return 90 + (code - 8);
11635
- }
11636
- let red;
11637
- let green;
11638
- let blue;
11639
- if (code >= 232) {
11640
- red = ((code - 232) * 10 + 8) / 255;
11641
- green = red;
11642
- blue = red;
11643
- } else {
11644
- code -= 16;
11645
- const remainder = code % 36;
11646
- red = Math.floor(code / 36) / 5;
11647
- green = Math.floor(remainder / 6) / 5;
11648
- blue = remainder % 6 / 5;
11649
- }
11650
- const value = Math.max(red, green, blue) * 2;
11651
- if (value === 0) {
11652
- return 30;
11653
- }
11654
- let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
11655
- if (value === 2) {
11656
- result += 60;
11657
- }
11658
- return result;
11659
- },
11660
- enumerable: false
11661
- },
11662
- rgbToAnsi: {
11663
- value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
11664
- enumerable: false
10171
+ rgbToAnsi: {
10172
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
10173
+ enumerable: false
11665
10174
  },
11666
10175
  hexToAnsi: {
11667
10176
  value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
@@ -12395,9 +10904,9 @@ function applyRailKey(state, ev, catLen, itemLen) {
12395
10904
  return { state: { ...state, focus: clampFocus(state.focus - 1) }, exit: false, act: false };
12396
10905
  }
12397
10906
  if (right) {
12398
- if (state.focus === 2)
12399
- return { state, exit: false, act: false };
12400
- return { state: { ...state, focus: clampFocus(state.focus + 1) }, exit: false, act: false };
10907
+ if (state.focus >= 1)
10908
+ return still;
10909
+ return { state: { ...state, focus: 1 }, exit: false, act: false };
12401
10910
  }
12402
10911
  if (up || down)
12403
10912
  return {
@@ -12489,9 +10998,9 @@ var init_PreviewPanel = __esm(() => {
12489
10998
  import { execFileSync } from "node:child_process";
12490
10999
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, mkdtempSync, realpathSync, writeFileSync as writeFileSync4 } from "node:fs";
12491
11000
  import { tmpdir } from "node:os";
12492
- import { join as join20 } from "node:path";
11001
+ import { join as join21 } from "node:path";
12493
11002
  function seedTranscriptFixture(workdir) {
12494
- const path = join20(workdir, "preview-transcript.jsonl");
11003
+ const path = join21(workdir, "preview-transcript.jsonl");
12495
11004
  try {
12496
11005
  mkdirSync5(workdir, { recursive: true });
12497
11006
  if (!existsSync6(path)) {
@@ -12562,7 +11071,7 @@ function gitEnv() {
12562
11071
  function setupGitFixture(workdir) {
12563
11072
  try {
12564
11073
  mkdirSync5(workdir, { recursive: true });
12565
- if (existsSync6(join20(workdir, ".git")))
11074
+ if (existsSync6(join21(workdir, ".git")))
12566
11075
  return;
12567
11076
  const env2 = gitEnv();
12568
11077
  const git = (...args) => {
@@ -12572,20 +11081,20 @@ function setupGitFixture(workdir) {
12572
11081
  git("config", "user.email", "wayne@example.com");
12573
11082
  git("config", "user.name", "Bruce Wayne");
12574
11083
  git("remote", "add", "origin", "https://github.com/wayne/ccsidekick.git");
12575
- writeFileSync4(join20(workdir, "README.md"), `# ccsidekick
11084
+ writeFileSync4(join21(workdir, "README.md"), `# ccsidekick
12576
11085
 
12577
11086
  original line
12578
11087
  keep me
12579
11088
  `);
12580
11089
  git("add", "README.md");
12581
11090
  git("commit", "-q", "-m", "initial commit");
12582
- writeFileSync4(join20(workdir, "README.md"), `# ccsidekick
11091
+ writeFileSync4(join21(workdir, "README.md"), `# ccsidekick
12583
11092
 
12584
11093
  edited line
12585
11094
  keep me
12586
11095
  new line
12587
11096
  `);
12588
- writeFileSync4(join20(workdir, "src.ts"), `export const answer = 42;
11097
+ writeFileSync4(join21(workdir, "src.ts"), `export const answer = 42;
12589
11098
  `);
12590
11099
  git("add", "src.ts");
12591
11100
  } catch {}
@@ -12607,24 +11116,24 @@ function transcriptLine(id, model, inputTokens, outputTokens) {
12607
11116
  });
12608
11117
  }
12609
11118
  function seedCostFixture(root, workdir) {
12610
- const projectsRoot = join20(root, "projects");
12611
- const currentProjectDir = join20(projectsRoot, workdir.replace(/[/.]/g, "-"));
12612
- const otherProjectDir = join20(projectsRoot, "-other-project");
11119
+ const projectsRoot = join21(root, "projects");
11120
+ const currentProjectDir = join21(projectsRoot, workdir.replace(/[/.]/g, "-"));
11121
+ const otherProjectDir = join21(projectsRoot, "-other-project");
12613
11122
  mkdirSync5(currentProjectDir, { recursive: true });
12614
11123
  mkdirSync5(otherProjectDir, { recursive: true });
12615
- writeFileSync4(join20(currentProjectDir, "sess-a.jsonl"), `${transcriptLine("sess-a-1", "claude-opus-4-8", 1e5, 20000)}
11124
+ writeFileSync4(join21(currentProjectDir, "sess-a.jsonl"), `${transcriptLine("sess-a-1", "claude-opus-4-8", 1e5, 20000)}
12616
11125
  `);
12617
- writeFileSync4(join20(otherProjectDir, "sess-b.jsonl"), `${transcriptLine("sess-b-1", "claude-opus-4-8", 200000, 50000)}
11126
+ writeFileSync4(join21(otherProjectDir, "sess-b.jsonl"), `${transcriptLine("sess-b-1", "claude-opus-4-8", 200000, 50000)}
12618
11127
  `);
12619
11128
  }
12620
11129
  function scratchRoot(scratchDir) {
12621
11130
  if (scratchDir !== undefined)
12622
11131
  return scratchDir;
12623
- sharedScratch ??= mkdtempSync(join20(tmpdir(), "ccsidekick-preview-"));
11132
+ sharedScratch ??= mkdtempSync(join21(tmpdir(), "ccsidekick-preview-"));
12624
11133
  return sharedScratch;
12625
11134
  }
12626
11135
  function previewEnv(root, extra) {
12627
- const homeBase = join20(root, "home");
11136
+ const homeBase = join21(root, "home");
12628
11137
  mkdirSync5(homeBase, { recursive: true });
12629
11138
  let home = homeBase;
12630
11139
  try {
@@ -12701,15 +11210,15 @@ var init_scenarios = __esm(() => {
12701
11210
  });
12702
11211
 
12703
11212
  // src/tui/preview/render.ts
12704
- import { join as join21 } from "node:path";
11213
+ import { join as join22 } from "node:path";
12705
11214
  function renderScenario(scenario, draft, opts) {
12706
11215
  try {
12707
11216
  const clock = opts.clock ?? DEFAULT_CLOCK;
12708
11217
  const root = scratchRoot(opts.scratchDir);
12709
- writeConfigToml(join21(root, "ccsidekick"), draft);
11218
+ writeConfigToml(join22(root, "ccsidekick"), draft);
12710
11219
  const env2 = previewEnv(root, scenario.env ?? {});
12711
11220
  const home = env2["HOME"] ?? root;
12712
- const workdir = join21(home, "ccsidekick");
11221
+ const workdir = join22(home, "ccsidekick");
12713
11222
  setupGitFixture(workdir);
12714
11223
  seedCostFixture(root, workdir);
12715
11224
  const term = { columns: opts.columns, noColor: opts.noColor, isTTY: true };
@@ -12734,48 +11243,19 @@ var init_preview = __esm(() => {
12734
11243
  init_scenarios();
12735
11244
  });
12736
11245
 
12737
- // src/tui/sections/catalog.tsx
12738
- var ENGINE_ROOT;
12739
- var init_catalog2 = __esm(() => {
12740
- init_sources();
12741
- ENGINE_ROOT = engineRoot(import.meta.url);
12742
- });
12743
-
12744
11246
  // src/tui/sections/CharacterSection.tsx
12745
11247
  import { Box as Box21, Text as Text26 } from "ink";
12746
11248
  import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
12747
11249
  function CharacterSection(props) {
12748
- const {
12749
- state,
12750
- packs,
12751
- installed,
12752
- activeIds,
12753
- mode,
12754
- detail,
12755
- installStatus,
12756
- errorMsg,
12757
- reducedMotion = false,
12758
- rows,
12759
- tokens,
12760
- glyphs,
12761
- hues,
12762
- nowMs,
12763
- moodShift
12764
- } = props;
12765
- const rosterItems = [
12766
- { id: MODE_ROW, label: `Mode ${glyphs.marker} ${mode}` },
12767
- ...packs.map((id) => ({
12768
- id,
12769
- label: `${activeIds.includes(id) ? glyphs.tabActive : glyphs.tabInactive} ${id}`
12770
- }))
12771
- ];
12772
- const browseItems = packs.map((id) => ({
11250
+ const { state, packs, activeIds, mode, detail, rows, tokens, glyphs, hues, nowMs, moodShift } = props;
11251
+ const modeItems = ["fixed", "random"].map((m) => ({
11252
+ id: m,
11253
+ label: `${mode === m ? glyphs.tabActive : glyphs.tabInactive} ${m}`
11254
+ }));
11255
+ const rosterItems = packs.map((id) => ({
12773
11256
  id,
12774
- label: `${installed.includes(id) ? glyphs.tabActive : glyphs.tabInactive} ${id}`
11257
+ label: `${activeIds.includes(id) ? glyphs.tabActive : glyphs.tabInactive} ${id}`
12775
11258
  }));
12776
- const otherPacks = packs.filter((id) => id !== BUNDLED_PACK);
12777
- const browseEmpty = otherPacks.length === 0;
12778
- const selectedId = packs[Math.min(state.itemCursor, packs.length - 1)] ?? packs[0] ?? "";
12779
11259
  const figW = Math.max(1, ...detail.figure.map((r) => Array.from(r).length));
12780
11260
  const figH = Math.max(1, detail.figure.length);
12781
11261
  const figureRows2 = detail.figure.map((row, y) => /* @__PURE__ */ jsxDEV13(Text26, {
@@ -12785,7 +11265,7 @@ function CharacterSection(props) {
12785
11265
  children: ch
12786
11266
  }, `c-${String(x)}`, false, undefined, this)) : row
12787
11267
  }, `fig-${String(y)}`, false, undefined, this));
12788
- const rosterDetail = detail.ok ? /* @__PURE__ */ jsxDEV13(Box21, {
11268
+ const figure = detail.ok ? /* @__PURE__ */ jsxDEV13(Box21, {
12789
11269
  flexDirection: "column",
12790
11270
  children: [
12791
11271
  /* @__PURE__ */ jsxDEV13(Text26, {
@@ -12810,57 +11290,32 @@ function CharacterSection(props) {
12810
11290
  }, undefined, false, undefined, this)
12811
11291
  ]
12812
11292
  }, undefined, true, undefined, this);
12813
- const browseDetail = /* @__PURE__ */ jsxDEV13(Box21, {
11293
+ const detailNode = state.catCursor === 0 ? /* @__PURE__ */ jsxDEV13(Box21, {
12814
11294
  flexDirection: "column",
12815
11295
  children: [
12816
11296
  /* @__PURE__ */ jsxDEV13(Text26, {
12817
- ...tokens.accent,
12818
- children: detail.displayName
12819
- }, undefined, false, undefined, this),
12820
- installStatus === "installing" ? reducedMotion ? /* @__PURE__ */ jsxDEV13(Text26, {
12821
11297
  ...tokens.textMuted,
12822
- children: [
12823
- "Installing",
12824
- glyphs.ellipsis
12825
- ]
12826
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV13(Spinner, {
12827
- label: "Installing..."
12828
- }, undefined, false, undefined, this) : null,
12829
- installStatus === "error" ? /* @__PURE__ */ jsxDEV13(Text26, {
12830
- ...tokens.critical,
12831
- children: [
12832
- "! ",
12833
- errorMsg ?? "install failed"
12834
- ]
12835
- }, undefined, true, undefined, this) : null,
12836
- installStatus === "idle" && installed.includes(selectedId) ? /* @__PURE__ */ jsxDEV13(Text26, {
12837
- ...tokens.nominal,
12838
- children: "installed"
12839
- }, undefined, false, undefined, this) : null,
12840
- installStatus === "idle" && !installed.includes(selectedId) ? /* @__PURE__ */ jsxDEV13(Text26, {
12841
- ...tokens.textMuted,
12842
- children: "[enter] install"
12843
- }, undefined, false, undefined, this) : null
11298
+ children: mode === "fixed" ? "Shows one fixed character." : "Rotates through the roster each session."
11299
+ }, undefined, false, undefined, this),
11300
+ /* @__PURE__ */ jsxDEV13(Text26, {
11301
+ children: " "
11302
+ }, undefined, false, undefined, this),
11303
+ figure
12844
11304
  ]
12845
- }, undefined, true, undefined, this);
12846
- const items = state.catCursor === 0 ? rosterItems : browseEmpty ? [] : browseItems;
12847
- const body = state.catCursor === 0 ? rosterDetail : browseEmpty ? /* @__PURE__ */ jsxDEV13(Text26, {
12848
- ...tokens.textMuted,
12849
- children: "no other packs available"
12850
- }, undefined, false, undefined, this) : browseDetail;
11305
+ }, undefined, true, undefined, this) : figure;
11306
+ const items = state.catCursor === 0 ? modeItems : rosterItems;
12851
11307
  return /* @__PURE__ */ jsxDEV13(Rail, {
12852
- categories: ["Roster", "Browse"],
11308
+ categories: ["Mode", "Roster"],
12853
11309
  items,
12854
- detail: body,
11310
+ detail: detailNode,
12855
11311
  state,
12856
11312
  rows,
12857
11313
  tokens,
12858
11314
  glyphs
12859
11315
  }, undefined, false, undefined, this);
12860
11316
  }
12861
- var isBlank = (ch) => ch === " " || ch === "⠀", MODE_ROW = "__mode__";
11317
+ var isBlank = (ch) => ch === " " || ch === "⠀";
12862
11318
  var init_CharacterSection = __esm(() => {
12863
- init_packs();
12864
11319
  init_render();
12865
11320
  init_theme2();
12866
11321
  init_widgets();
@@ -13181,35 +11636,41 @@ function statuslineFields(d) {
13181
11636
  id: "currency",
13182
11637
  label: "Currency",
13183
11638
  kind: "text",
13184
- value: d.line.currency,
13185
- raw: d.line.currency,
11639
+ value: d.statusline.currency,
11640
+ raw: d.statusline.currency,
13186
11641
  commit: (c, raw) => {
13187
11642
  const v = raw.trim().toUpperCase();
13188
- return v === "" ? c : { ...c, line: { ...c.line, currency: v } };
11643
+ return v === "" ? c : { ...c, statusline: { ...c.statusline, currency: v } };
13189
11644
  }
13190
11645
  };
13191
11646
  const budget = {
13192
11647
  id: "budget",
13193
11648
  label: "Budget (USD/mo)",
13194
11649
  kind: "number",
13195
- value: d.line.budget === undefined ? "off" : String(d.line.budget),
13196
- raw: d.line.budget === undefined ? "" : String(d.line.budget),
11650
+ value: d.statusline.budget === undefined ? "off" : String(d.statusline.budget),
11651
+ raw: d.statusline.budget === undefined ? "" : String(d.statusline.budget),
13197
11652
  commit: (c, raw) => {
13198
11653
  const t = raw.trim();
13199
11654
  if (t === "")
13200
- return { ...c, line: { currency: c.line.currency, widgets: c.line.widgets } };
11655
+ return {
11656
+ ...c,
11657
+ statusline: { currency: c.statusline.currency, widgets: c.statusline.widgets }
11658
+ };
13201
11659
  const n = Number(t);
13202
- return Number.isFinite(n) && n >= 0 ? { ...c, line: { ...c.line, budget: n } } : c;
11660
+ return Number.isFinite(n) && n >= 0 ? { ...c, statusline: { ...c.statusline, budget: n } } : c;
13203
11661
  }
13204
11662
  };
13205
- const widgets = WIDGET_IDS.map((id) => ({
11663
+ const widgets = WIDGET_IDS2.map((id) => ({
13206
11664
  id: `widget:${id}`,
13207
11665
  label: id,
13208
11666
  kind: "toggle",
13209
- value: onOff(d.line.widgets[id]),
11667
+ value: onOff(d.statusline.widgets[id]),
13210
11668
  toggle: (c) => ({
13211
11669
  ...c,
13212
- line: { ...c.line, widgets: { ...c.line.widgets, [id]: !c.line.widgets[id] } }
11670
+ statusline: {
11671
+ ...c.statusline,
11672
+ widgets: { ...c.statusline.widgets, [id]: !c.statusline.widgets[id] }
11673
+ }
13213
11674
  })
13214
11675
  }));
13215
11676
  return [currency, budget, ...widgets];
@@ -13235,40 +11696,32 @@ function themeSettingsFields(d) {
13235
11696
  }
13236
11697
  ];
13237
11698
  }
13238
- function voiceFields(d) {
13239
- return [
13240
- {
13241
- id: "comments_enabled",
13242
- label: "Comments",
13243
- kind: "toggle",
13244
- value: onOff(d.comments.enabled),
13245
- toggle: (c) => ({ ...c, comments: { enabled: !c.comments.enabled } })
13246
- }
13247
- ];
13248
- }
13249
- function tipsFields(d) {
13250
- return [
13251
- {
13252
- id: "helpful_enabled",
13253
- label: "Enabled",
13254
- kind: "toggle",
13255
- value: onOff(d.helpful.enabled),
13256
- toggle: (c) => ({ ...c, helpful: { ...c.helpful, enabled: !c.helpful.enabled } })
13257
- },
13258
- {
13259
- id: "min_severity",
13260
- label: "Min severity",
13261
- kind: "cycle",
13262
- value: d.helpful.min_severity,
13263
- next: (c) => ({
13264
- ...c,
13265
- helpful: {
13266
- ...c.helpful,
13267
- min_severity: step(SEVERITIES, c.helpful.min_severity, 1)
13268
- }
13269
- })
13270
- }
13271
- ];
11699
+ function commentsFields(d) {
11700
+ const characterComments = {
11701
+ id: "comments_character",
11702
+ label: "Character Comments",
11703
+ kind: "toggle",
11704
+ value: onOff(d.comments.character),
11705
+ toggle: (c) => ({ ...c, comments: { ...c.comments, character: !c.comments.character } })
11706
+ };
11707
+ const helpfulComments = {
11708
+ id: "comments_helpful",
11709
+ label: "Helpful Comments",
11710
+ kind: "toggle",
11711
+ value: onOff(d.comments.helpful),
11712
+ toggle: (c) => ({ ...c, comments: { ...c.comments, helpful: !c.comments.helpful } })
11713
+ };
11714
+ const minSeverity = {
11715
+ id: "min_severity",
11716
+ label: "Min severity",
11717
+ kind: "cycle",
11718
+ value: d.comments.min_severity,
11719
+ next: (c) => ({
11720
+ ...c,
11721
+ comments: { ...c.comments, min_severity: step(SEVERITIES2, c.comments.min_severity, 1) }
11722
+ })
11723
+ };
11724
+ return d.comments.helpful ? [characterComments, helpfulComments, minSeverity] : [characterComments, helpfulComments];
13272
11725
  }
13273
11726
  function networkFields(d) {
13274
11727
  return [
@@ -13304,26 +11757,24 @@ function sectionFields(section2, d) {
13304
11757
  case 1:
13305
11758
  return themeSettingsFields(d);
13306
11759
  case 2:
13307
- return voiceFields(d);
11760
+ return commentsFields(d);
13308
11761
  case 3:
13309
- return tipsFields(d);
13310
- case 4:
13311
11762
  return networkFields(d);
13312
- case 5:
11763
+ case 4:
13313
11764
  return statuslineFields(d);
13314
11765
  default:
13315
11766
  return [];
13316
11767
  }
13317
11768
  }
13318
- var onOff = (b) => b ? "on" : "off", WIDGET_IDS, SEVERITIES, BANDINGS, step = (arr, cur, dir) => {
11769
+ var onOff = (b) => b ? "on" : "off", WIDGET_IDS2, SEVERITIES2, BANDINGS, step = (arr, cur, dir) => {
13319
11770
  const n = arr.length;
13320
11771
  const i = arr.indexOf(cur);
13321
11772
  return arr[((i + dir) % n + n) % n] ?? cur;
13322
11773
  };
13323
11774
  var init_forms = __esm(() => {
13324
11775
  init_sources();
13325
- WIDGET_IDS = Object.keys(DEFAULT_CONFIG.line.widgets);
13326
- SEVERITIES = ["low", "medium", "high", "critical"];
11776
+ WIDGET_IDS2 = Object.keys(DEFAULT_CONFIG.statusline.widgets);
11777
+ SEVERITIES2 = ["low", "medium", "high", "critical"];
13327
11778
  BANDINGS = ["solid", "cycle"];
13328
11779
  });
13329
11780
 
@@ -13384,42 +11835,6 @@ var init_FormSection = __esm(() => {
13384
11835
  init_widgets();
13385
11836
  });
13386
11837
 
13387
- // src/tui/sections/installAsync.ts
13388
- import { spawn } from "node:child_process";
13389
- function installPackAsync(name, engineDir = ENGINE_ROOT, run = spawn) {
13390
- const pkg = packPackageName(name);
13391
- if (!isAllowedPackPackage(pkg)) {
13392
- return Promise.reject(new Error(`ccsidekick: refusing to install off-allowlist pack "${name}"`));
13393
- }
13394
- return new Promise((resolve3, reject) => {
13395
- const child = run("npm", ["install", pkg, "--ignore-scripts"], {
13396
- cwd: engineDir,
13397
- stdio: ["ignore", "ignore", "pipe"]
13398
- });
13399
- let stderr = "";
13400
- child.stderr?.on("data", (chunk) => {
13401
- stderr += String(chunk);
13402
- });
13403
- child.on("error", (err) => {
13404
- reject(err instanceof Error ? err : new Error(String(err)));
13405
- });
13406
- child.on("close", (code) => {
13407
- if (code === 0) {
13408
- resolve3();
13409
- return;
13410
- }
13411
- const detail = stderr.trim();
13412
- const tail = detail.length > 500 ? detail.slice(-500) : detail;
13413
- reject(new Error(`ccsidekick: npm install ${pkg} exited ${String(code)}${tail ? `
13414
- ${tail}` : ""}`));
13415
- });
13416
- });
13417
- }
13418
- var init_installAsync = __esm(() => {
13419
- init_packs();
13420
- init_catalog2();
13421
- });
13422
-
13423
11838
  // src/tui/sections/InstallPanel.tsx
13424
11839
  import { Box as Box24, Text as Text29 } from "ink";
13425
11840
  import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
@@ -14002,7 +12417,7 @@ function StatuslineSection(props) {
14002
12417
  const widgets = group?.widgets ?? [];
14003
12418
  const widgetItems = widgets.map((id) => ({
14004
12419
  id,
14005
- label: `${config.line.widgets[id] ? glyphs.tabActive : glyphs.tabInactive} ${id}`
12420
+ label: `${config.statusline.widgets[id] ? glyphs.tabActive : glyphs.tabInactive} ${id}`
14006
12421
  }));
14007
12422
  const items = isFormat ? formatItems : widgetItems;
14008
12423
  const formatIdx = Math.min(state.itemCursor, 1);
@@ -14185,13 +12600,11 @@ var init_ThemeSection = __esm(() => {
14185
12600
 
14186
12601
  // src/tui/sections/index.ts
14187
12602
  var init_sections = __esm(() => {
14188
- init_catalog2();
14189
12603
  init_CharacterSection();
14190
12604
  init_configdir();
14191
12605
  init_currencyModel();
14192
12606
  init_forms();
14193
12607
  init_FormSection();
14194
- init_installAsync();
14195
12608
  init_InstallPanel();
14196
12609
  init_StatsSection();
14197
12610
  init_statsView();
@@ -14200,32 +12613,6 @@ var init_sections = __esm(() => {
14200
12613
  init_widgetGroups();
14201
12614
  });
14202
12615
 
14203
- // src/tui/shell/useTransitionFade.ts
14204
- import { useEffect as useEffect8, useState as useState7 } from "react";
14205
- function useTransitionFade(transitionKey, reducedMotion) {
14206
- const [step2, setStep] = useState7(reducedMotion ? FADE_STEPS : 0);
14207
- useEffect8(() => {
14208
- if (reducedMotion) {
14209
- setStep(FADE_STEPS);
14210
- return;
14211
- }
14212
- setStep(0);
14213
- let current = 0;
14214
- const id = setInterval(() => {
14215
- current += 1;
14216
- setStep(current);
14217
- if (current >= FADE_STEPS)
14218
- clearInterval(id);
14219
- }, FADE_STEP_MS);
14220
- return () => {
14221
- clearInterval(id);
14222
- };
14223
- }, [transitionKey, reducedMotion]);
14224
- return step2 / FADE_STEPS;
14225
- }
14226
- var FADE_STEPS = 2, FADE_STEP_MS = 90;
14227
- var init_useTransitionFade = () => {};
14228
-
14229
12616
  // src/tui/shell/AppShell.tsx
14230
12617
  import { Box as Box28, Text as Text33 } from "ink";
14231
12618
  import { jsxDEV as jsxDEV20, Fragment } from "react/jsx-dev-runtime";
@@ -14351,19 +12738,16 @@ function HintBar({ nav, tokens }) {
14351
12738
  }, h.key + h.label, true, undefined, this))
14352
12739
  }, undefined, false, undefined, this);
14353
12740
  }
14354
- function Content({ nav, tokens, glyphs, children, reducedMotion }) {
12741
+ function Content({ nav, tokens, glyphs, children }) {
14355
12742
  const focused = nav.zone === "content";
14356
12743
  const eyebrow = `${focused ? `${glyphs.marker} ` : ""}${SECTIONS[nav.section]?.toUpperCase() ?? ""}`;
14357
- const fade = useTransitionFade(nav.section, reducedMotion ?? false);
14358
- const settled = focused ? tokens.accent : tokens.textMuted;
14359
- const eyebrowStyle = fade >= 1 ? settled : fade > 0 ? { ...tokens.accent, dimColor: true } : tokens.textMuted;
14360
12744
  return /* @__PURE__ */ jsxDEV20(Box28, {
14361
12745
  flexDirection: "column",
14362
12746
  flexGrow: 1,
14363
12747
  paddingLeft: 2,
14364
12748
  children: [
14365
12749
  /* @__PURE__ */ jsxDEV20(Text33, {
14366
- ...eyebrowStyle,
12750
+ ...tokens.accent,
14367
12751
  children: eyebrow
14368
12752
  }, undefined, false, undefined, this),
14369
12753
  /* @__PURE__ */ jsxDEV20(Box28, {
@@ -14419,7 +12803,6 @@ var POPUP_CHROME_ROWS = 6, CONTENT_CHROME_ROWS = 6, CONTENT_CHROME_COLS = 27;
14419
12803
  var init_AppShell = __esm(() => {
14420
12804
  init_nav();
14421
12805
  init_widgets();
14422
- init_useTransitionFade();
14423
12806
  });
14424
12807
 
14425
12808
  // src/tui/shell/findIndex.ts
@@ -14439,7 +12822,7 @@ function buildFindIndex(deps) {
14439
12822
  run: deps.focusField(section2, fieldIndex)
14440
12823
  }));
14441
12824
  });
14442
- const toggles = WIDGET_IDS.map((id) => ({
12825
+ const toggles = WIDGET_IDS2.map((id) => ({
14443
12826
  id: `toggle:${id}`,
14444
12827
  label: `Toggle ${id}`,
14445
12828
  kind: "action",
@@ -14475,7 +12858,7 @@ var init_findIndex = __esm(() => {
14475
12858
  init_nav();
14476
12859
  init_sections();
14477
12860
  init_widgets();
14478
- FORM_SECTIONS = [2, 3, 4];
12861
+ FORM_SECTIONS = [2, 3];
14479
12862
  });
14480
12863
 
14481
12864
  // src/tui/shell/inputRoute.ts
@@ -14487,7 +12870,7 @@ function overlayRoute(overlay, section2, ev) {
14487
12870
  const { input, key } = ev;
14488
12871
  if (overlay === "save")
14489
12872
  return "save";
14490
- if (section2 === 7 && overlay === "none" && key.return === true)
12873
+ if (section2 === 6 && overlay === "none" && key.return === true)
14491
12874
  return "saveSection";
14492
12875
  if (overlay === "find")
14493
12876
  return "find";
@@ -14502,9 +12885,9 @@ function sectionRoute(section2, ev) {
14502
12885
  return "character";
14503
12886
  if (section2 === 1 && isFieldNavKey(ev))
14504
12887
  return "theme";
14505
- if (section2 === 6 && isStatsKey(ev))
12888
+ if (section2 === 5 && isStatsKey(ev))
14506
12889
  return "stats";
14507
- if (section2 === 5 && isFieldNavKey(ev))
12890
+ if (section2 === 4 && isFieldNavKey(ev))
14508
12891
  return "statusline";
14509
12892
  return null;
14510
12893
  }
@@ -14520,7 +12903,7 @@ function routeKey(ctx, ev) {
14520
12903
  if (sectionR !== null)
14521
12904
  return sectionR;
14522
12905
  }
14523
- if (section2 === 7 && overlay === "none" && ev.input === " ")
12906
+ if (section2 === 6 && overlay === "none" && ev.input === " ")
14524
12907
  return "saveToggle";
14525
12908
  if (overlay === "none" && zone === "content" && isFieldNavKey(ev))
14526
12909
  return "content";
@@ -14533,8 +12916,8 @@ var init_inputRoute = __esm(() => {
14533
12916
  });
14534
12917
 
14535
12918
  // src/tui/shell/saveTarget.ts
14536
- import { existsSync as existsSync8, readFileSync as readFileSync12 } from "node:fs";
14537
- import { join as join22 } from "node:path";
12919
+ import { existsSync as existsSync8, readFileSync as readFileSync13 } from "node:fs";
12920
+ import { join as join23 } from "node:path";
14538
12921
  function chipFor(targets) {
14539
12922
  if (targets.every((t) => t.scope === "global"))
14540
12923
  return "global";
@@ -14546,19 +12929,19 @@ function alreadyWired(settingsPath) {
14546
12929
  if (!existsSync8(settingsPath))
14547
12930
  return false;
14548
12931
  try {
14549
- const parsed = JSON.parse(readFileSync12(settingsPath, "utf8"));
12932
+ const parsed = JSON.parse(readFileSync13(settingsPath, "utf8"));
14550
12933
  return isOurStatusLine(parsed.statusLine);
14551
12934
  } catch {
14552
12935
  return false;
14553
12936
  }
14554
12937
  }
14555
12938
  function projectTarget(cwd, _homeDir) {
14556
- const dir = join22(cwd, ".claude");
12939
+ const dir = join23(cwd, ".claude");
14557
12940
  return {
14558
12941
  dir,
14559
12942
  scope: "local",
14560
12943
  cwd,
14561
- wireLocalSettings: !alreadyWired(join22(dir, "settings.json"))
12944
+ wireLocalSettings: !alreadyWired(join23(dir, "settings.json"))
14562
12945
  };
14563
12946
  }
14564
12947
  var init_saveTarget = __esm(() => {
@@ -14664,10 +13047,10 @@ function savePreviewSet(config, installed, packs) {
14664
13047
  }
14665
13048
 
14666
13049
  // src/tui/shell/scenarioBodies.ts
14667
- import { useEffect as useEffect9, useState as useState8 } from "react";
13050
+ import { useEffect as useEffect8, useState as useState7 } from "react";
14668
13051
  function usePreviewBody(active, scenario, draft, columns, noColor) {
14669
- const [body, setBody] = useState8("");
14670
- useEffect9(() => {
13052
+ const [body, setBody] = useState7("");
13053
+ useEffect8(() => {
14671
13054
  if (!active) {
14672
13055
  setBody("");
14673
13056
  return;
@@ -14675,9 +13058,9 @@ function usePreviewBody(active, scenario, draft, columns, noColor) {
14675
13058
  const id = setTimeout(() => {
14676
13059
  const previewConfig = {
14677
13060
  ...draft,
14678
- line: {
14679
- ...draft.line,
14680
- widgets: { ...draft.line.widgets, compactions: true, todo: true }
13061
+ statusline: {
13062
+ ...draft.statusline,
13063
+ widgets: { ...draft.statusline.widgets, compactions: true, todo: true }
14681
13064
  }
14682
13065
  };
14683
13066
  setBody(renderScenario(scenario, previewConfig, { columns, noColor }));
@@ -14689,8 +13072,8 @@ function usePreviewBody(active, scenario, draft, columns, noColor) {
14689
13072
  return body;
14690
13073
  }
14691
13074
  function useSaveCharacterBody(active, character, draft, columns) {
14692
- const [body, setBody] = useState8("");
14693
- useEffect9(() => {
13075
+ const [body, setBody] = useState7("");
13076
+ useEffect8(() => {
14694
13077
  if (!active) {
14695
13078
  setBody("");
14696
13079
  return;
@@ -14704,9 +13087,9 @@ function useSaveCharacterBody(active, character, draft, columns) {
14704
13087
  const previewConfig = {
14705
13088
  ...draft,
14706
13089
  character: { ...draft.character, mode: "fixed", name: character },
14707
- line: {
14708
- ...draft.line,
14709
- widgets: { ...draft.line.widgets, compactions: true, todo: true }
13090
+ statusline: {
13091
+ ...draft.statusline,
13092
+ widgets: { ...draft.statusline.widgets, compactions: true, todo: true }
14710
13093
  }
14711
13094
  };
14712
13095
  setBody(renderScenario(scenario, previewConfig, { columns, noColor: false }));
@@ -14718,8 +13101,8 @@ function useSaveCharacterBody(active, character, draft, columns) {
14718
13101
  return body;
14719
13102
  }
14720
13103
  function useThemeDetailBody(active, itemCursor, themeKeys, scenarioIndex, draft, columns) {
14721
- const [body, setBody] = useState8("");
14722
- useEffect9(() => {
13104
+ const [body, setBody] = useState7("");
13105
+ useEffect8(() => {
14723
13106
  if (!active) {
14724
13107
  setBody("");
14725
13108
  return;
@@ -14751,7 +13134,7 @@ var init_scenarioBodies = __esm(() => {
14751
13134
 
14752
13135
  // src/tui/shell/useMouseWheel.ts
14753
13136
  import { useStdin } from "ink";
14754
- import { useEffect as useEffect10 } from "react";
13137
+ import { useEffect as useEffect9 } from "react";
14755
13138
  function parseMouseWheel(data) {
14756
13139
  let dx = 0;
14757
13140
  let dy = 0;
@@ -14777,7 +13160,7 @@ function parseMouseWheel(data) {
14777
13160
  }
14778
13161
  function useMouseWheel(active, onScroll) {
14779
13162
  const { stdin, setRawMode, isRawModeSupported } = useStdin();
14780
- useEffect10(() => {
13163
+ useEffect9(() => {
14781
13164
  if (!active || !isRawModeSupported)
14782
13165
  return;
14783
13166
  setRawMode(true);
@@ -14800,16 +13183,10 @@ var init_useMouseWheel = __esm(() => {
14800
13183
  });
14801
13184
 
14802
13185
  // src/tui/shell/Dashboard.tsx
14803
- import { readFileSync as readFileSync13 } from "node:fs";
14804
- import { join as join23 } from "node:path";
13186
+ import { readFileSync as readFileSync14 } from "node:fs";
13187
+ import { join as join24 } from "node:path";
14805
13188
  import { Box as Box30, Text as Text35, useApp as useApp2, useInput as useInput8 } from "ink";
14806
- import {
14807
- useCallback as useCallback6,
14808
- useEffect as useEffect11,
14809
- useMemo as useMemo9,
14810
- useRef,
14811
- useState as useState9
14812
- } from "react";
13189
+ import { useCallback as useCallback6, useMemo as useMemo9, useState as useState8 } from "react";
14813
13190
  import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
14814
13191
  function Dashboard(props) {
14815
13192
  const {
@@ -14822,63 +13199,52 @@ function Dashboard(props) {
14822
13199
  rows
14823
13200
  } = props;
14824
13201
  const app = useApp2();
14825
- const mounted = useRef(true);
14826
- useEffect11(() => {
14827
- mounted.current = true;
14828
- return () => {
14829
- mounted.current = false;
14830
- };
14831
- }, []);
14832
- const [nav, setNav] = useState9(INITIAL_NAV);
14833
- const [targets, setTargets] = useState9(props.targets);
13202
+ const [nav, setNav] = useState8(INITIAL_NAV);
13203
+ const [targets, setTargets] = useState8(props.targets);
14834
13204
  const configDir2 = targets[0]?.dir ?? "";
14835
- const root = join23(configDir2, "ccsidekick");
14836
- const [draft, setDraft] = useState9(() => seed(configDir2, initialConfig));
14837
- const [dirty2, setDirty] = useState9(false);
14838
- const [cursor4, setCursor] = useState9(0);
14839
- const [editing, setEditing] = useState9(false);
14840
- const [buffer, setBuffer] = useState9("");
14841
- const [error, setError] = useState9(null);
14842
- const [scenarioIndex, setScenarioIndex] = useState9(0);
14843
- const [previewNoColor, setPreviewNoColor] = useState9(false);
14844
- const [previewNarrow, setPreviewNarrow] = useState9(false);
14845
- const [installedScan, setInstalled] = useState9(() => props.installed ?? listInstalledPacks(ENGINE_ROOT));
14846
- const installed = useMemo9(() => installedScan.includes(BUNDLED_PACK) ? installedScan : [BUNDLED_PACK, ...installedScan], [installedScan]);
14847
- const [characterRail, setCharacterRail] = useState9({
13205
+ const root = join24(configDir2, "ccsidekick");
13206
+ const [draft, setDraft] = useState8(() => seed(configDir2, initialConfig));
13207
+ const [dirty2, setDirty] = useState8(props.initialDirty ?? false);
13208
+ const [cursor4, setCursor] = useState8(0);
13209
+ const [editing, setEditing] = useState8(false);
13210
+ const [buffer, setBuffer] = useState8("");
13211
+ const [error, setError] = useState8(null);
13212
+ const [scenarioIndex, setScenarioIndex] = useState8(0);
13213
+ const [previewNoColor, setPreviewNoColor] = useState8(false);
13214
+ const [previewNarrow, setPreviewNarrow] = useState8(false);
13215
+ const [characterRail, setCharacterRail] = useState8({
14848
13216
  focus: 0,
14849
13217
  catCursor: 0,
14850
13218
  itemCursor: 0
14851
13219
  });
14852
- const [themeRail, setThemeRail] = useState9({
13220
+ const [themeRail, setThemeRail] = useState8({
14853
13221
  focus: 0,
14854
13222
  catCursor: 0,
14855
13223
  itemCursor: 0
14856
13224
  });
14857
- const [statuslineRail, setStatuslineRail] = useState9({
13225
+ const [statuslineRail, setStatuslineRail] = useState8({
14858
13226
  focus: 0,
14859
13227
  catCursor: 0,
14860
13228
  itemCursor: 0
14861
13229
  });
14862
- const [installStatus, setInstallStatus] = useState9("idle");
14863
- const [installError, setInstallError] = useState9(null);
14864
- const [query, setQuery] = useState9("");
14865
- const [overlayCursor, setOverlayCursor] = useState9(0);
14866
- const [currencyQuery, setCurrencyQuery] = useState9("");
14867
- const [statsDimension, setStatsDimension] = useState9(0);
14868
- const [statsWindow, setStatsWindow] = useState9(0);
14869
- const [statsFocus, setStatsFocus] = useState9(0);
14870
- const [statsEntry, setStatsEntry] = useState9(0);
14871
- const [statsScrollX, setStatsScrollX] = useState9(0);
14872
- const [statsScrollY, setStatsScrollY] = useState9(0);
14873
- const [saveCharIdx, setSaveCharIdx] = useState9(0);
14874
- const [saveScrollX, setSaveScrollX] = useState9(0);
14875
- const [saveScrollY, setSaveScrollY] = useState9(0);
14876
- const packs = props.packs ?? dedupe([...FIRST_PARTY_PACKS, ...installed]);
13230
+ const [query, setQuery] = useState8("");
13231
+ const [overlayCursor, setOverlayCursor] = useState8(0);
13232
+ const [currencyQuery, setCurrencyQuery] = useState8("");
13233
+ const [statsDimension, setStatsDimension] = useState8(0);
13234
+ const [statsWindow, setStatsWindow] = useState8(0);
13235
+ const [statsFocus, setStatsFocus] = useState8(0);
13236
+ const [statsEntry, setStatsEntry] = useState8(0);
13237
+ const [statsScrollX, setStatsScrollX] = useState8(0);
13238
+ const [statsScrollY, setStatsScrollY] = useState8(0);
13239
+ const [saveCharIdx, setSaveCharIdx] = useState8(0);
13240
+ const [saveScrollX, setSaveScrollX] = useState8(0);
13241
+ const [saveScrollY, setSaveScrollY] = useState8(0);
13242
+ const [done, setDone] = useState8(false);
13243
+ const packs = props.packs ?? [...PACKS];
13244
+ const installed = packs;
14877
13245
  const rosterList = packs;
14878
- const browseList = packs;
14879
- const install = props.install ?? installPackAsync;
14880
13246
  const themeSettingRows = themeSettingsFields(draft);
14881
- const activeIds = draft.character.mode === "fixed" ? [draft.character.name] : draft.character.roster;
13247
+ const activeIds = draft.character.mode === "fixed" ? [draft.character.name] : draft.character.roster.length > 0 ? draft.character.roster : packs;
14882
13248
  const savePreviewChars = savePreviewSet(draft, installed, packs);
14883
13249
  const saveCharIdxClamped = Math.min(saveCharIdx, savePreviewChars.length - 1);
14884
13250
  const saveCharName = savePreviewChars[saveCharIdxClamped] ?? "batman";
@@ -14886,7 +13252,9 @@ function Dashboard(props) {
14886
13252
  const ch = draft.character;
14887
13253
  if (ch.mode === "fixed")
14888
13254
  return { ...draft, character: { ...ch, name: id } };
14889
- const roster = ch.roster.includes(id) ? ch.roster.filter((r) => r !== id) : [...ch.roster, id];
13255
+ const current = ch.roster.length > 0 ? ch.roster : packs;
13256
+ const next = current.includes(id) ? current.filter((r) => r !== id) : [...current, id];
13257
+ const roster = next.length === packs.length || next.length === 0 ? [] : next;
14890
13258
  return { ...draft, character: { ...ch, roster } };
14891
13259
  };
14892
13260
  const columns = cols ?? 80;
@@ -14920,7 +13288,6 @@ function Dashboard(props) {
14920
13288
  const theme15 = themeTable[draft.theme.name] ?? THEMES.houston;
14921
13289
  const tokens = resolveTokens(theme15, capability);
14922
13290
  const glyphs = glyphSet(false);
14923
- const reducedMotion = props.reducedMotion ?? detectReducedMotion(env2);
14924
13291
  const fields = sectionFields(nav.section, draft);
14925
13292
  const change = (next) => {
14926
13293
  setDraft(next);
@@ -14970,13 +13337,13 @@ function Dashboard(props) {
14970
13337
  change(spec.toggle(draft));
14971
13338
  },
14972
13339
  openCurrencyPicker: () => {
14973
- setNav({ ...nav, section: 5, zone: "content", overlay: "currency" });
13340
+ setNav({ ...nav, section: 4, zone: "content", overlay: "currency" });
14974
13341
  setStatuslineRail((s) => ({ ...s, focus: 1, catCursor: 0, itemCursor: 0 }));
14975
13342
  setCurrencyQuery("");
14976
13343
  setOverlayCursor(0);
14977
13344
  },
14978
13345
  beginBudgetEdit: () => {
14979
- setNav({ ...nav, section: 5, zone: "content", overlay: "none" });
13346
+ setNav({ ...nav, section: 4, zone: "content", overlay: "none" });
14980
13347
  setStatuslineRail((s) => ({ ...s, focus: 1, catCursor: 0, itemCursor: 1 }));
14981
13348
  setCursor(1);
14982
13349
  setBuffer(statuslineFields(draft)[1]?.raw ?? "");
@@ -15053,7 +13420,7 @@ function Dashboard(props) {
15053
13420
  setCurrencyQuery("");
15054
13421
  setOverlayCursor(0);
15055
13422
  if (code !== undefined)
15056
- change({ ...draft, line: { ...draft.line, currency: code } });
13423
+ change({ ...draft, statusline: { ...draft.statusline, currency: code } });
15057
13424
  return;
15058
13425
  }
15059
13426
  if (key.backspace || key.delete) {
@@ -15078,59 +13445,22 @@ function Dashboard(props) {
15078
13445
  };
15079
13446
  const activateCharacter = (state) => {
15080
13447
  if (state.catCursor === 0) {
15081
- if (state.itemCursor === 0) {
15082
- const ch = draft.character;
15083
- change({
15084
- ...draft,
15085
- character: { ...ch, mode: ch.mode === "fixed" ? "random" : "fixed" }
15086
- });
15087
- return;
15088
- }
15089
- const id2 = rosterList[state.itemCursor - 1];
15090
- if (id2 !== undefined)
15091
- change(selectCharacter(id2));
13448
+ const mode = state.itemCursor === 0 ? "fixed" : "random";
13449
+ change({ ...draft, character: { ...draft.character, mode } });
15092
13450
  return;
15093
13451
  }
15094
- const id = browseList[Math.min(state.itemCursor, browseList.length - 1)];
15095
- if (id === undefined)
15096
- return;
15097
- if (installStatus === "installing")
15098
- return;
15099
- if (!installed.includes(id)) {
15100
- setInstallStatus("installing");
15101
- setInstallError(null);
15102
- install(id).then(() => {
15103
- if (!mounted.current)
15104
- return;
15105
- setInstalled((prev) => prev.includes(id) ? prev : [...prev, id]);
15106
- setInstallStatus("idle");
15107
- }).catch((e) => {
15108
- if (!mounted.current)
15109
- return;
15110
- setInstallStatus("error");
15111
- setInstallError(e instanceof Error ? e.message : String(e));
15112
- });
15113
- return;
15114
- }
15115
- change(selectCharacter(id));
13452
+ const id = rosterList[Math.min(state.itemCursor, rosterList.length - 1)];
13453
+ if (id !== undefined)
13454
+ change(selectCharacter(id));
15116
13455
  };
15117
13456
  const handleCharacterKey = (input, key) => {
15118
- const listLength = characterRail.catCursor === 0 ? rosterList.length + 1 : browseList.length;
15119
- const r = applyRailKey(characterRail, { input, key }, 2, listLength);
15120
- let next = r.state;
15121
- if (r.state.catCursor !== characterRail.catCursor) {
15122
- const delta = r.state.catCursor === 0 ? 1 : -1;
15123
- const nextLen = r.state.catCursor === 0 ? rosterList.length + 1 : browseList.length;
15124
- next = {
15125
- ...r.state,
15126
- itemCursor: Math.max(0, Math.min(nextLen - 1, r.state.itemCursor + delta))
15127
- };
15128
- }
15129
- setCharacterRail(next);
13457
+ const listLen = characterRail.catCursor === 0 ? 2 : rosterList.length;
13458
+ const r = applyRailKey(characterRail, { input, key }, 2, listLen);
13459
+ setCharacterRail(r.state);
15130
13460
  if (r.exit)
15131
13461
  setNav({ ...nav, zone: "sidebar" });
15132
13462
  if (r.act)
15133
- activateCharacter(next);
13463
+ activateCharacter(r.state);
15134
13464
  };
15135
13465
  const activateThemeRow = (state) => {
15136
13466
  if (state.catCursor === 0) {
@@ -15243,7 +13573,7 @@ function Dashboard(props) {
15243
13573
  const handleSaveKey = (input, key) => {
15244
13574
  if (input === "y" || key.return) {
15245
13575
  if (runInstall())
15246
- setNav({ ...nav, overlay: "none" });
13576
+ setDone(true);
15247
13577
  } else if (key.escape) {
15248
13578
  setNav({ ...nav, overlay: "none" });
15249
13579
  } else if (key.leftArrow) {
@@ -15319,6 +13649,14 @@ function Dashboard(props) {
15319
13649
  quitNow();
15320
13650
  };
15321
13651
  useInput8((input, key) => {
13652
+ if (done) {
13653
+ quitNow();
13654
+ return;
13655
+ }
13656
+ if (key.ctrl && input === "w" && props.onWizard) {
13657
+ props.onWizard(draft, dirty2);
13658
+ return;
13659
+ }
15322
13660
  const route = routeKey({ editing, zone: nav.zone, overlay: nav.overlay, section: nav.section }, { input, key });
15323
13661
  switch (route) {
15324
13662
  case "editing":
@@ -15366,8 +13704,9 @@ function Dashboard(props) {
15366
13704
  const themeDetailCols = Math.max(20, columns - 73);
15367
13705
  const scenario = useMemo9(() => SCENARIOS[scenarioIndex] ?? SCENARIOS[0] ?? { label: "none" }, [scenarioIndex]);
15368
13706
  const previewBody = usePreviewBody(nav.overlay === "preview", scenario, draft, previewBodyCols, previewNoColor);
15369
- const detailIdx = characterRail.catCursor === 0 ? Math.max(0, Math.min(characterRail.itemCursor - 1, rosterList.length - 1)) : Math.min(characterRail.itemCursor, browseList.length - 1);
15370
- const selectedCharId = (characterRail.catCursor === 0 ? rosterList : browseList)[detailIdx] ?? packs[0] ?? "batman";
13707
+ const rosterIdx = Math.max(0, Math.min(characterRail.itemCursor, rosterList.length - 1));
13708
+ const selectedCharId = characterRail.catCursor === 1 ? rosterList[rosterIdx] ?? packs[0] ?? "batman" : packs.includes(draft.character.name) ? draft.character.name : packs[0] ?? "batman";
13709
+ const figureHues = draft.theme.name === CHARACTER_THEME ? themeTable[selectedCharId]?.hues ?? THEMES.houston.hues : theme15.hues;
15371
13710
  const characterDetail = useMemo9(() => {
15372
13711
  const res = loadPack(selectedCharId);
15373
13712
  if (!res.ok)
@@ -15396,7 +13735,7 @@ function Dashboard(props) {
15396
13735
  const themeDetailBody = useThemeDetailBody(nav.section === 1 && themeRail.catCursor === 0, themeRail.itemCursor, themeKeys, scenarioIndex, draft, themeDetailCols);
15397
13736
  const clock = props.clock ?? systemClock;
15398
13737
  const metrics = useMemo9(() => props.metrics ?? loadMetrics(root, clock), [props.metrics, root, clock]);
15399
- const statsBoard = statsView(metrics, statsDimension, statsWindow, statsEntry, draft.line.budget);
13738
+ const statsBoard = statsView(metrics, statsDimension, statsWindow, statsEntry, draft.statusline.budget);
15400
13739
  const statsAxisCount = statsBoard.entry !== null ? 3 : 2;
15401
13740
  const contentRows = Math.max(1, height - CONTENT_CHROME_ROWS);
15402
13741
  const contentCols = Math.max(20, columns - CONTENT_CHROME_COLS);
@@ -15409,7 +13748,7 @@ function Dashboard(props) {
15409
13748
  setStatsScrollX((x) => clampScroll(x + dx, statsBoardW, contentCols));
15410
13749
  setStatsScrollY((y) => clampScroll(y + dy, statsBoardH, statsBoardViewRows));
15411
13750
  }, [statsBoardW, contentCols, statsBoardH, statsBoardViewRows]);
15412
- const statsFocused = nav.section === 6 && nav.zone === "content" && nav.overlay === "none";
13751
+ const statsFocused = nav.section === 5 && nav.zone === "content" && nav.overlay === "none";
15413
13752
  const wheelActive = nav.overlay === "save" || statsFocused;
15414
13753
  const onWheel = useCallback6((dx, dy) => {
15415
13754
  if (nav.overlay === "save")
@@ -15418,6 +13757,36 @@ function Dashboard(props) {
15418
13757
  scrollStats(dx, dy);
15419
13758
  }, [nav.overlay, scrollSave, scrollStats]);
15420
13759
  useMouseWheel(wheelActive, onWheel);
13760
+ if (done) {
13761
+ return /* @__PURE__ */ jsxDEV22(Box30, {
13762
+ width: columns,
13763
+ height,
13764
+ flexDirection: "column",
13765
+ paddingX: 1,
13766
+ borderStyle: "round",
13767
+ borderColor: tokens.frame.color ?? "gray",
13768
+ children: [
13769
+ /* @__PURE__ */ jsxDEV22(Text35, {
13770
+ ...tokens.accent,
13771
+ children: "ccsidekick"
13772
+ }, undefined, false, undefined, this),
13773
+ /* @__PURE__ */ jsxDEV22(Box30, {
13774
+ marginTop: 1,
13775
+ flexDirection: "column",
13776
+ children: [
13777
+ /* @__PURE__ */ jsxDEV22(Text35, {
13778
+ ...tokens.nominal,
13779
+ children: "✓ Saved. Press any key to finish."
13780
+ }, undefined, false, undefined, this),
13781
+ /* @__PURE__ */ jsxDEV22(Text35, {
13782
+ ...tokens.textMuted,
13783
+ children: "Restart Claude Code to see your status line."
13784
+ }, undefined, false, undefined, this)
13785
+ ]
13786
+ }, undefined, true, undefined, this)
13787
+ ]
13788
+ }, undefined, true, undefined, this);
13789
+ }
15421
13790
  if (breakpoint === "floor") {
15422
13791
  return /* @__PURE__ */ jsxDEV22(Popup, {
15423
13792
  title: "Terminal too small",
@@ -15438,7 +13807,7 @@ function Dashboard(props) {
15438
13807
  }, undefined, true, undefined, this);
15439
13808
  }
15440
13809
  const buildSectionBody = () => {
15441
- if (nav.section === 7)
13810
+ if (nav.section === 6)
15442
13811
  return /* @__PURE__ */ jsxDEV22(InstallPanel, {
15443
13812
  scope: chipFor(targets),
15444
13813
  dirty: dirty2,
@@ -15449,17 +13818,13 @@ function Dashboard(props) {
15449
13818
  return /* @__PURE__ */ jsxDEV22(CharacterSection, {
15450
13819
  state: characterRail,
15451
13820
  packs,
15452
- installed,
15453
13821
  activeIds,
15454
13822
  mode: draft.character.mode,
15455
13823
  detail: characterDetail,
15456
- installStatus,
15457
- ...installError !== null ? { errorMsg: installError } : {},
15458
13824
  rows: contentRows,
15459
- reducedMotion,
15460
13825
  tokens,
15461
13826
  glyphs,
15462
- hues: theme15.hues,
13827
+ hues: figureHues,
15463
13828
  nowMs: 0,
15464
13829
  moodShift: draft.theme.mood_shift
15465
13830
  }, undefined, false, undefined, this);
@@ -15475,7 +13840,7 @@ function Dashboard(props) {
15475
13840
  tokens,
15476
13841
  glyphs
15477
13842
  }, undefined, false, undefined, this);
15478
- if (nav.section === 5)
13843
+ if (nav.section === 4)
15479
13844
  return /* @__PURE__ */ jsxDEV22(StatuslineSection, {
15480
13845
  state: statuslineRail,
15481
13846
  config: draft,
@@ -15485,7 +13850,7 @@ function Dashboard(props) {
15485
13850
  tokens,
15486
13851
  glyphs
15487
13852
  }, undefined, false, undefined, this);
15488
- if (nav.section === 6)
13853
+ if (nav.section === 5)
15489
13854
  return /* @__PURE__ */ jsxDEV22(StatsSection, {
15490
13855
  dimension: statsDimension,
15491
13856
  windowIdx: statsWindow,
@@ -15606,7 +13971,6 @@ function Dashboard(props) {
15606
13971
  configDir: configDir2,
15607
13972
  scope: chipFor(targets),
15608
13973
  dirty: dirty2,
15609
- reducedMotion,
15610
13974
  columns,
15611
13975
  rows: height,
15612
13976
  collapsed: breakpoint === "narrow" && nav.zone === "content",
@@ -15614,11 +13978,11 @@ function Dashboard(props) {
15614
13978
  children: content
15615
13979
  }, undefined, false, undefined, this);
15616
13980
  }
15617
- var dedupe = (xs) => [...new Set(xs)], seed = (configDir2, initial) => {
13981
+ var seed = (configDir2, initial) => {
15618
13982
  if (initial)
15619
13983
  return initial;
15620
13984
  try {
15621
- return loadConfig(readFileSync13(join23(configDir2, "ccsidekick", "config.toml"), "utf8"));
13985
+ return loadConfig(readFileSync14(join24(configDir2, "ccsidekick", "config.toml"), "utf8"));
15622
13986
  } catch {
15623
13987
  return loadConfig("");
15624
13988
  }
@@ -15650,99 +14014,30 @@ var init_wordmark = __esm(() => {
15650
14014
  " ██████╗ ██████╗███████╗██╗██████╗ ███████╗██╗ ██╗██╗ ██████╗██╗ ██╗",
15651
14015
  "██╔════╝██╔════╝██╔════╝██║██╔══██╗██╔════╝██║ ██╔╝██║██╔════╝██║ ██╔╝",
15652
14016
  "██║ ██║ ███████╗██║██║ ██║█████╗ █████╔╝ ██║██║ █████╔╝ ",
15653
- "██║ ██║ ╚════██║██║██║ ██║██╔══╝ ██╔═██╗ ██║██║ ██╔═██╗ ",
15654
- "╚██████╗╚██████╗███████║██║██████╔╝███████╗██║ ██╗██║╚██████╗██║ ██╗",
15655
- " ╚═════╝ ╚═════╝╚══════╝╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝╚═╝ ╚═╝"
15656
- ];
15657
- LOGO_MIN_COLUMNS = WORDMARK_WIDTH + 2;
15658
- });
15659
-
15660
- // src/tui/shell/wordmarkColor.ts
15661
- var rgbToHsv = ([r, g, b]) => {
15662
- const rn = r / 255;
15663
- const gn = g / 255;
15664
- const bn = b / 255;
15665
- const mx = Math.max(rn, gn, bn);
15666
- const mn = Math.min(rn, gn, bn);
15667
- const d = mx - mn;
15668
- let h = 0;
15669
- if (d !== 0) {
15670
- if (mx === rn)
15671
- h = (gn - bn) / d % 6;
15672
- else if (mx === gn)
15673
- h = (bn - rn) / d + 2;
15674
- else
15675
- h = (rn - gn) / d + 4;
15676
- h *= 60;
15677
- if (h < 0)
15678
- h += 360;
15679
- }
15680
- const s = mx === 0 ? 0 : d / mx;
15681
- return [h, s, mx];
15682
- }, hsvToRgb = ([h, s, v]) => {
15683
- const c = v * s;
15684
- const hp = h / 60;
15685
- const x = c * (1 - Math.abs(hp % 2 - 1));
15686
- let r = 0;
15687
- let g = 0;
15688
- let b = 0;
15689
- if (hp < 1)
15690
- [r, g, b] = [c, x, 0];
15691
- else if (hp < 2)
15692
- [r, g, b] = [x, c, 0];
15693
- else if (hp < 3)
15694
- [r, g, b] = [0, c, x];
15695
- else if (hp < 4)
15696
- [r, g, b] = [0, x, c];
15697
- else if (hp < 5)
15698
- [r, g, b] = [x, 0, c];
15699
- else
15700
- [r, g, b] = [c, 0, x];
15701
- const m = v - c;
15702
- return [(r + m) * 255, (g + m) * 255, (b + m) * 255];
15703
- }, lerpHue = (a, b, t) => {
15704
- let diff = b - a;
15705
- if (diff > 180)
15706
- diff -= 360;
15707
- else if (diff < -180)
15708
- diff += 360;
15709
- let h = a + diff * t;
15710
- if (h < 0)
15711
- h += 360;
15712
- else if (h >= 360)
15713
- h -= 360;
15714
- return h;
15715
- }, lerp2 = (a, b, t) => a + (b - a) * t, frac2 = (x) => x - Math.floor(x), smoothstep2 = (x) => x * x * (3 - 2 * x), wordmarkColor = (stops, x, y, w, h, nowMs) => {
15716
- const phase = frac2(nowMs / SHIMMER_PERIOD_MS);
15717
- const t = (x / Math.max(1, w - 1) + y / Math.max(1, h - 1)) / 2 + phase;
15718
- const n = stops.length;
15719
- const p = frac2(t) * n;
15720
- const i = Math.floor(p);
15721
- const f = smoothstep2(p - i);
15722
- const a = rgbToHsv(xtermToRgb(stops[i % n] ?? 0));
15723
- const b = rgbToHsv(xtermToRgb(stops[(i + 1) % n] ?? 0));
15724
- const hsv = [lerpHue(a[0], b[0], f), lerp2(a[1], b[1], f), lerp2(a[2], b[2], f)];
15725
- return rgbToXterm(hsvToRgb(hsv));
15726
- };
15727
- var init_wordmarkColor = __esm(() => {
15728
- init_domain();
15729
- init_render();
14017
+ "██║ ██║ ╚════██║██║██║ ██║██╔══╝ ██╔═██╗ ██║██║ ██╔═██╗ ",
14018
+ "╚██████╗╚██████╗███████║██║██████╔╝███████╗██║ ██╗██║╚██████╗██║ ██╗",
14019
+ " ╚═════╝ ╚═════╝╚══════╝╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝╚═╝ ╚═╝"
14020
+ ];
14021
+ LOGO_MIN_COLUMNS = WORDMARK_WIDTH + 2;
15730
14022
  });
15731
14023
 
15732
14024
  // src/tui/shell/Logo.tsx
15733
14025
  import { Box as Box31, Text as Text36 } from "ink";
15734
14026
  import { jsxDEV as jsxDEV23 } from "react/jsx-dev-runtime";
15735
- function Logo({ hues, capability, reducedMotion, nowMs, tokens }) {
15736
- const w = WORDMARK_WIDTH;
15737
- const h = WORDMARK.length;
15738
- const frozen = capability === "full" && reducedMotion ? gradient(hues, w) : null;
15739
- const solidStyle = (x, y) => {
14027
+ function brighten(index) {
14028
+ const [r, g, b] = xtermToRgb(index);
14029
+ const mx = Math.max(r, g, b, 1);
14030
+ const scale = 255 / mx;
14031
+ return rgbToXterm([r * scale, g * scale, b * scale]);
14032
+ }
14033
+ function Logo({ hues, capability, tokens }) {
14034
+ const ramp = capability === "full" ? gradient(hues, WORDMARK_WIDTH).map(brighten) : null;
14035
+ const solidStyle = (x) => {
15740
14036
  if (capability === "none")
15741
14037
  return { bold: true };
15742
14038
  if (capability === "basic")
15743
14039
  return tokens.accent;
15744
- const idx = frozen !== null ? frozen[x] ?? hues[0] ?? 0 : wordmarkColor(hues, x, y, w, h, nowMs);
15745
- return { color: hexForXterm(idx), bold: true };
14040
+ return { color: hexForXterm(ramp?.[x] ?? brighten(hues[0] ?? 0)), bold: true };
15746
14041
  };
15747
14042
  return /* @__PURE__ */ jsxDEV23(Box31, {
15748
14043
  flexDirection: "column",
@@ -15755,7 +14050,7 @@ function Logo({ hues, capability, reducedMotion, nowMs, tokens }) {
15755
14050
  }, key, false, undefined, this);
15756
14051
  if (ch === SOLID)
15757
14052
  return /* @__PURE__ */ jsxDEV23(Text36, {
15758
- ...solidStyle(x, y),
14053
+ ...solidStyle(x),
15759
14054
  children: ch
15760
14055
  }, key, false, undefined, this);
15761
14056
  return /* @__PURE__ */ jsxDEV23(Text36, {
@@ -15770,7 +14065,6 @@ var init_Logo = __esm(() => {
15770
14065
  init_render();
15771
14066
  init_theme2();
15772
14067
  init_wordmark();
15773
- init_wordmarkColor();
15774
14068
  init_wordmark();
15775
14069
  });
15776
14070
 
@@ -15788,8 +14082,6 @@ function Welcome({
15788
14082
  atFloor,
15789
14083
  hues,
15790
14084
  capability,
15791
- reducedMotion,
15792
- nowMs,
15793
14085
  tokens
15794
14086
  }) {
15795
14087
  const showLogo = columns >= LOGO_MIN_COLUMNS;
@@ -15801,8 +14093,6 @@ function Welcome({
15801
14093
  showLogo ? /* @__PURE__ */ jsxDEV24(Logo, {
15802
14094
  hues,
15803
14095
  capability,
15804
- reducedMotion,
15805
- nowMs,
15806
14096
  tokens
15807
14097
  }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV24(Text37, {
15808
14098
  ...tokens.accent,
@@ -15877,27 +14167,470 @@ var init_Welcome = __esm(() => {
15877
14167
  init_wordmark();
15878
14168
  });
15879
14169
 
15880
- // src/tui/shell/App.tsx
15881
- import { readFileSync as readFileSync14 } from "node:fs";
15882
- import { homedir as homedir6 } from "node:os";
15883
- import { join as join24 } from "node:path";
15884
- import { useInput as useInput9 } from "ink";
15885
- import { useEffect as useEffect12, useMemo as useMemo10, useState as useState10 } from "react";
14170
+ // src/tui/shell/Wizard.tsx
14171
+ import { Box as Box33, Text as Text38, useApp as useApp3, useInput as useInput9 } from "ink";
14172
+ import { useState as useState9 } from "react";
15886
14173
  import { jsxDEV as jsxDEV25 } from "react/jsx-dev-runtime";
15887
- function useShimmerNow(reducedMotion, active) {
15888
- const [now, setNow] = useState10(() => Date.now());
15889
- useEffect12(() => {
15890
- if (reducedMotion || !active)
15891
- return;
15892
- const id = setInterval(() => {
15893
- setNow(Date.now());
15894
- }, 120);
15895
- return () => {
15896
- clearInterval(id);
14174
+ function ThemeStep(props) {
14175
+ const { themeCursor, selectedName, contentRows, preview, tokens, glyphs } = props;
14176
+ const start = Math.max(0, themeCursor - contentRows + 2);
14177
+ const selKey = THEME_KEYS[themeCursor];
14178
+ const selData = selKey !== undefined ? THEMES[selKey] : undefined;
14179
+ return /* @__PURE__ */ jsxDEV25(Box33, {
14180
+ flexDirection: "row",
14181
+ children: [
14182
+ /* @__PURE__ */ jsxDEV25(Box33, {
14183
+ flexDirection: "column",
14184
+ width: 28,
14185
+ children: THEME_ENTRIES.slice(start, start + (contentRows - 1)).map((entry, i) => {
14186
+ const active = start + i === themeCursor;
14187
+ const selected = entry.key === selectedName;
14188
+ return /* @__PURE__ */ jsxDEV25(Text38, {
14189
+ ...active ? tokens.accent : tokens.text,
14190
+ children: [
14191
+ active ? glyphs.marker : " ",
14192
+ " ",
14193
+ selected ? glyphs.tabActive : glyphs.tabInactive,
14194
+ " ",
14195
+ entry.label
14196
+ ]
14197
+ }, entry.key, true, undefined, this);
14198
+ })
14199
+ }, undefined, false, undefined, this),
14200
+ /* @__PURE__ */ jsxDEV25(Box33, {
14201
+ flexDirection: "column",
14202
+ flexGrow: 1,
14203
+ paddingLeft: 2,
14204
+ children: [
14205
+ selKey === CHARACTER_THEME ? /* @__PURE__ */ jsxDEV25(Text38, {
14206
+ ...tokens.textMuted,
14207
+ children: "Follows the active character's palette."
14208
+ }, undefined, false, undefined, this) : selData !== undefined ? /* @__PURE__ */ jsxDEV25(Box33, {
14209
+ flexDirection: "column",
14210
+ children: [
14211
+ /* @__PURE__ */ jsxDEV25(Box33, {
14212
+ children: selData.hues.map((h, i) => /* @__PURE__ */ jsxDEV25(Text38, {
14213
+ color: hexForXterm(h),
14214
+ children: "██"
14215
+ }, `h${String(i)}`, false, undefined, this))
14216
+ }, undefined, false, undefined, this),
14217
+ /* @__PURE__ */ jsxDEV25(Box33, {
14218
+ children: [
14219
+ /* @__PURE__ */ jsxDEV25(Text38, {
14220
+ color: hexForXterm(selData.signals.nominal),
14221
+ children: "● "
14222
+ }, undefined, false, undefined, this),
14223
+ /* @__PURE__ */ jsxDEV25(Text38, {
14224
+ color: hexForXterm(selData.signals.caution),
14225
+ children: "● "
14226
+ }, undefined, false, undefined, this),
14227
+ /* @__PURE__ */ jsxDEV25(Text38, {
14228
+ color: hexForXterm(selData.signals.critical),
14229
+ children: "● "
14230
+ }, undefined, false, undefined, this)
14231
+ ]
14232
+ }, undefined, true, undefined, this)
14233
+ ]
14234
+ }, undefined, true, undefined, this) : null,
14235
+ preview !== "" ? /* @__PURE__ */ jsxDEV25(Box33, {
14236
+ marginTop: 1,
14237
+ children: /* @__PURE__ */ jsxDEV25(Text38, {
14238
+ children: preview
14239
+ }, undefined, false, undefined, this)
14240
+ }, undefined, false, undefined, this) : null
14241
+ ]
14242
+ }, undefined, true, undefined, this)
14243
+ ]
14244
+ }, undefined, true, undefined, this);
14245
+ }
14246
+ function packThemeHues(id) {
14247
+ const res = loadPack(id);
14248
+ return res.ok && res.pack.theme ? res.pack.theme.hues : THEMES.houston.hues;
14249
+ }
14250
+ function characterDetailFor(id) {
14251
+ const res = loadPack(id);
14252
+ if (!res.ok)
14253
+ return {
14254
+ ok: false,
14255
+ displayName: id,
14256
+ figure: [],
14257
+ moods: [],
14258
+ artist: "",
14259
+ source: "",
14260
+ tone: "",
14261
+ emblem: ""
15897
14262
  };
15898
- }, [reducedMotion, active]);
15899
- return now;
14263
+ const p = res.pack;
14264
+ return {
14265
+ ok: true,
14266
+ displayName: p.displayName,
14267
+ figure: p.art,
14268
+ moods: Object.keys(p.lines.mood),
14269
+ artist: p.attribution.artist,
14270
+ source: p.attribution.source,
14271
+ tone: p.tone,
14272
+ emblem: p.emblem
14273
+ };
14274
+ }
14275
+ function Wizard(props) {
14276
+ const { targets, renderBin = "ccsidekick-render", onAdvanced, onQuit, onSave } = props;
14277
+ const env2 = props.env ?? process.env;
14278
+ const columns = props.cols ?? 80;
14279
+ const rows = props.rows ?? 24;
14280
+ const app = useApp3();
14281
+ const [step2, setStep] = useState9(0);
14282
+ const [draft, setDraft] = useState9(props.initialConfig ?? DEFAULT_CONFIG);
14283
+ const [characterRail, setCharacterRail] = useState9({
14284
+ focus: 0,
14285
+ catCursor: 0,
14286
+ itemCursor: 0
14287
+ });
14288
+ const [themeCursor, setThemeCursor] = useState9(0);
14289
+ const [commentsCursor, setCommentsCursor] = useState9(0);
14290
+ const [error, setError] = useState9(null);
14291
+ const [done, setDone] = useState9(false);
14292
+ const capability = detectCapability(env2);
14293
+ const theme15 = THEMES[draft.theme.name] ?? THEMES.houston;
14294
+ const tokens = resolveTokens(theme15, capability);
14295
+ const glyphs = glyphSet(false);
14296
+ const packs = [...PACKS];
14297
+ const activeIds = draft.character.mode === "fixed" ? [draft.character.name] : draft.character.roster.length > 0 ? draft.character.roster : packs;
14298
+ const selectedCharId = characterRail.catCursor === 1 ? packs[Math.max(0, Math.min(characterRail.itemCursor, packs.length - 1))] ?? packs[0] ?? "batman" : packs.includes(draft.character.name) ? draft.character.name : packs[0] ?? "batman";
14299
+ const characterDetail = characterDetailFor(selectedCharId);
14300
+ const commentFields = commentsFields(draft);
14301
+ const figureHues = draft.theme.name === CHARACTER_THEME ? packThemeHues(selectedCharId) : theme15.hues;
14302
+ const previewCols = Math.max(24, columns - 46);
14303
+ const themePreview = useThemeDetailBody(step2 === 1, themeCursor, THEME_KEYS, 0, draft, previewCols);
14304
+ const quit = () => {
14305
+ if (onQuit)
14306
+ onQuit();
14307
+ else
14308
+ app.exit();
14309
+ };
14310
+ const nextStep = () => {
14311
+ setStep((s) => Math.min(STEPS.length - 1, s + 1));
14312
+ };
14313
+ const prevStep = () => {
14314
+ setStep((s) => Math.max(0, s - 1));
14315
+ };
14316
+ const selectCharacter = (id) => {
14317
+ setDraft((d) => {
14318
+ const ch = d.character;
14319
+ if (ch.mode === "fixed")
14320
+ return { ...d, character: { ...ch, name: id } };
14321
+ const current = ch.roster.length > 0 ? ch.roster : packs;
14322
+ const next = current.includes(id) ? current.filter((r) => r !== id) : [...current, id];
14323
+ const roster = next.length === packs.length || next.length === 0 ? [] : next;
14324
+ return { ...d, character: { ...ch, roster } };
14325
+ });
14326
+ };
14327
+ const activateCharacter = (state) => {
14328
+ if (state.catCursor === 0) {
14329
+ const mode = state.itemCursor === 0 ? "fixed" : "random";
14330
+ setDraft((d) => ({ ...d, character: { ...d.character, mode } }));
14331
+ return;
14332
+ }
14333
+ const id = packs[Math.min(state.itemCursor, packs.length - 1)];
14334
+ if (id !== undefined)
14335
+ selectCharacter(id);
14336
+ };
14337
+ const handleCharacter = (input, key) => {
14338
+ const listLen = characterRail.catCursor === 0 ? 2 : packs.length;
14339
+ const r = applyRailKey(characterRail, { input, key }, 2, listLen);
14340
+ setCharacterRail(r.state);
14341
+ if (r.exit)
14342
+ prevStep();
14343
+ if (r.act)
14344
+ activateCharacter(r.state);
14345
+ };
14346
+ const handleTheme = (input, key) => {
14347
+ if (key.leftArrow || input === "a") {
14348
+ prevStep();
14349
+ return;
14350
+ }
14351
+ if (key.upArrow || input === "k" || input === "w") {
14352
+ setThemeCursor((c) => Math.max(0, c - 1));
14353
+ return;
14354
+ }
14355
+ if (key.downArrow || input === "j" || input === "s") {
14356
+ setThemeCursor((c) => Math.min(THEME_ENTRIES.length - 1, c + 1));
14357
+ return;
14358
+ }
14359
+ if (key.return || input === " ") {
14360
+ const entry = THEME_ENTRIES[themeCursor];
14361
+ if (entry !== undefined)
14362
+ setDraft((d) => ({ ...d, theme: { ...d.theme, name: entry.key } }));
14363
+ }
14364
+ };
14365
+ const handleComments = (input, key) => {
14366
+ const r = applyContentKey(draft, commentFields, commentsCursor, { input, key });
14367
+ setCommentsCursor(r.cursor);
14368
+ if (r.changed)
14369
+ setDraft(r.draft);
14370
+ if (r.exit)
14371
+ prevStep();
14372
+ };
14373
+ const doSave = () => {
14374
+ try {
14375
+ for (const t of targets) {
14376
+ const opts = {
14377
+ ...t.cwd !== undefined ? { cwd: t.cwd } : {},
14378
+ ...t.wireLocalSettings !== undefined ? { wireLocalSettings: t.wireLocalSettings } : {}
14379
+ };
14380
+ if (onSave)
14381
+ onSave(draft, t);
14382
+ else
14383
+ save(draft, t.scope, t.dir, renderBin, opts);
14384
+ }
14385
+ setError(null);
14386
+ setDone(true);
14387
+ } catch (e) {
14388
+ setError(e instanceof Error ? e.message : String(e));
14389
+ }
14390
+ };
14391
+ const handleReview = (input, key) => {
14392
+ if (key.leftArrow || input === "a")
14393
+ prevStep();
14394
+ else if (key.return || input === "y")
14395
+ doSave();
14396
+ };
14397
+ const onEscape = () => {
14398
+ if (props.initialDirty === true && onAdvanced)
14399
+ onAdvanced(draft);
14400
+ else
14401
+ quit();
14402
+ };
14403
+ const routeStep = (input, key) => {
14404
+ if (step2 === 0)
14405
+ handleCharacter(input, key);
14406
+ else if (step2 === 1)
14407
+ handleTheme(input, key);
14408
+ else if (step2 === 2)
14409
+ handleComments(input, key);
14410
+ else
14411
+ handleReview(input, key);
14412
+ };
14413
+ useInput9((input, key) => {
14414
+ if (done) {
14415
+ quit();
14416
+ return;
14417
+ }
14418
+ if (key.escape) {
14419
+ onEscape();
14420
+ return;
14421
+ }
14422
+ if (key.ctrl && input === "d") {
14423
+ if (onAdvanced)
14424
+ onAdvanced(draft);
14425
+ return;
14426
+ }
14427
+ if (key.tab) {
14428
+ if (key.shift)
14429
+ prevStep();
14430
+ else
14431
+ nextStep();
14432
+ return;
14433
+ }
14434
+ routeStep(input, key);
14435
+ });
14436
+ const contentRows = Math.max(3, rows - 8);
14437
+ const body = (() => {
14438
+ if (done)
14439
+ return /* @__PURE__ */ jsxDEV25(Box33, {
14440
+ flexDirection: "column",
14441
+ children: [
14442
+ /* @__PURE__ */ jsxDEV25(Text38, {
14443
+ ...tokens.nominal,
14444
+ children: "✓ ccsidekick is set up. Press any key to finish."
14445
+ }, undefined, false, undefined, this),
14446
+ /* @__PURE__ */ jsxDEV25(Text38, {
14447
+ ...tokens.textMuted,
14448
+ children: "Restart Claude Code to see your status line."
14449
+ }, undefined, false, undefined, this)
14450
+ ]
14451
+ }, undefined, true, undefined, this);
14452
+ if (step2 === 0)
14453
+ return /* @__PURE__ */ jsxDEV25(CharacterSection, {
14454
+ state: characterRail,
14455
+ packs,
14456
+ activeIds,
14457
+ mode: draft.character.mode,
14458
+ detail: characterDetail,
14459
+ rows: contentRows,
14460
+ tokens,
14461
+ glyphs,
14462
+ hues: figureHues,
14463
+ nowMs: 0,
14464
+ moodShift: draft.theme.mood_shift
14465
+ }, undefined, false, undefined, this);
14466
+ if (step2 === 1)
14467
+ return /* @__PURE__ */ jsxDEV25(ThemeStep, {
14468
+ themeCursor,
14469
+ selectedName: draft.theme.name,
14470
+ contentRows,
14471
+ preview: themePreview,
14472
+ tokens,
14473
+ glyphs
14474
+ }, undefined, false, undefined, this);
14475
+ if (step2 === 2)
14476
+ return /* @__PURE__ */ jsxDEV25(FormSection, {
14477
+ fields: commentFields,
14478
+ cursor: commentsCursor,
14479
+ editing: false,
14480
+ buffer: "",
14481
+ rows: contentRows,
14482
+ tokens,
14483
+ glyphs
14484
+ }, undefined, false, undefined, this);
14485
+ return /* @__PURE__ */ jsxDEV25(Box33, {
14486
+ flexDirection: "column",
14487
+ children: [
14488
+ /* @__PURE__ */ jsxDEV25(Text38, {
14489
+ ...tokens.accent,
14490
+ children: "Review"
14491
+ }, undefined, false, undefined, this),
14492
+ /* @__PURE__ */ jsxDEV25(Text38, {
14493
+ ...tokens.text,
14494
+ children: [
14495
+ "Character: ",
14496
+ draft.character.mode === "fixed" ? draft.character.name : "random",
14497
+ draft.character.mode === "random" ? ` (${draft.character.roster.length > 0 ? draft.character.roster.join(", ") : "all"})` : ""
14498
+ ]
14499
+ }, undefined, true, undefined, this),
14500
+ /* @__PURE__ */ jsxDEV25(Text38, {
14501
+ ...tokens.text,
14502
+ children: [
14503
+ "Theme: ",
14504
+ draft.theme.name
14505
+ ]
14506
+ }, undefined, true, undefined, this),
14507
+ /* @__PURE__ */ jsxDEV25(Text38, {
14508
+ ...tokens.text,
14509
+ children: [
14510
+ "Character Comments: ",
14511
+ draft.comments.character ? "on" : "off"
14512
+ ]
14513
+ }, undefined, true, undefined, this),
14514
+ /* @__PURE__ */ jsxDEV25(Text38, {
14515
+ ...tokens.text,
14516
+ children: [
14517
+ "Helpful Comments: ",
14518
+ draft.comments.helpful ? "on" : "off"
14519
+ ]
14520
+ }, undefined, true, undefined, this),
14521
+ /* @__PURE__ */ jsxDEV25(Text38, {
14522
+ ...tokens.text,
14523
+ children: [
14524
+ "Save to: ",
14525
+ chipFor(targets)
14526
+ ]
14527
+ }, undefined, true, undefined, this),
14528
+ /* @__PURE__ */ jsxDEV25(Box33, {
14529
+ marginTop: 1,
14530
+ children: /* @__PURE__ */ jsxDEV25(Text38, {
14531
+ ...tokens.nominal,
14532
+ children: "Press ↵ to save and wire ccsidekick."
14533
+ }, undefined, false, undefined, this)
14534
+ }, undefined, false, undefined, this)
14535
+ ]
14536
+ }, undefined, true, undefined, this);
14537
+ })();
14538
+ const hints = done ? "any key to finish" : step2 === 3 ? "↵ save · shift+tab back · ^d advanced · esc quit" : "tab next · shift+tab back · ↵ select · ^d advanced · esc quit";
14539
+ return /* @__PURE__ */ jsxDEV25(Box33, {
14540
+ width: columns,
14541
+ height: rows,
14542
+ flexDirection: "column",
14543
+ paddingX: 1,
14544
+ borderStyle: "round",
14545
+ borderColor: tokens.frame.color ?? "gray",
14546
+ children: [
14547
+ /* @__PURE__ */ jsxDEV25(Box33, {
14548
+ justifyContent: "space-between",
14549
+ flexShrink: 0,
14550
+ children: [
14551
+ /* @__PURE__ */ jsxDEV25(Text38, {
14552
+ ...tokens.accent,
14553
+ children: "ccsidekick setup"
14554
+ }, undefined, false, undefined, this),
14555
+ /* @__PURE__ */ jsxDEV25(Text38, {
14556
+ ...tokens.textMuted,
14557
+ children: [
14558
+ "Step ",
14559
+ Math.min(step2 + 1, STEPS.length),
14560
+ " of ",
14561
+ STEPS.length
14562
+ ]
14563
+ }, undefined, true, undefined, this)
14564
+ ]
14565
+ }, undefined, true, undefined, this),
14566
+ /* @__PURE__ */ jsxDEV25(Box33, {
14567
+ flexShrink: 0,
14568
+ children: STEPS.map((name, i) => {
14569
+ const mark = i < step2 ? glyphs.tabActive : i === step2 ? glyphs.marker : glyphs.tabInactive;
14570
+ const style = i === step2 ? tokens.accent : i < step2 ? tokens.text : tokens.textMuted;
14571
+ return /* @__PURE__ */ jsxDEV25(Text38, {
14572
+ ...style,
14573
+ children: [
14574
+ mark,
14575
+ " ",
14576
+ name,
14577
+ " "
14578
+ ]
14579
+ }, name, true, undefined, this);
14580
+ })
14581
+ }, undefined, false, undefined, this),
14582
+ error !== null ? /* @__PURE__ */ jsxDEV25(Text38, {
14583
+ ...tokens.critical,
14584
+ children: [
14585
+ "! ",
14586
+ error
14587
+ ]
14588
+ }, undefined, true, undefined, this) : null,
14589
+ /* @__PURE__ */ jsxDEV25(Box33, {
14590
+ marginTop: 1,
14591
+ flexGrow: 1,
14592
+ children: body
14593
+ }, undefined, false, undefined, this),
14594
+ /* @__PURE__ */ jsxDEV25(Box33, {
14595
+ flexShrink: 0,
14596
+ children: /* @__PURE__ */ jsxDEV25(Text38, {
14597
+ ...tokens.textMuted,
14598
+ children: hints
14599
+ }, undefined, false, undefined, this)
14600
+ }, undefined, false, undefined, this)
14601
+ ]
14602
+ }, undefined, true, undefined, this);
15900
14603
  }
14604
+ var STEPS, THEME_ENTRIES, THEME_KEYS;
14605
+ var init_Wizard = __esm(() => {
14606
+ init_tui();
14607
+ init_data();
14608
+ init_packs();
14609
+ init_render();
14610
+ init_sources();
14611
+ init_sections();
14612
+ init_theme2();
14613
+ init_widgets();
14614
+ init_saveTarget();
14615
+ init_scenarioBodies();
14616
+ STEPS = ["Character", "Theme", "Comments", "Review"];
14617
+ THEME_ENTRIES = [
14618
+ { key: CHARACTER_THEME, label: "Match Character" },
14619
+ ...Object.entries(THEMES).map(([key, t]) => ({
14620
+ key,
14621
+ label: t.displayName
14622
+ }))
14623
+ ];
14624
+ THEME_KEYS = THEME_ENTRIES.map((e) => e.key);
14625
+ });
14626
+
14627
+ // src/tui/shell/App.tsx
14628
+ import { existsSync as existsSync9, readFileSync as readFileSync15 } from "node:fs";
14629
+ import { homedir as homedir6 } from "node:os";
14630
+ import { join as join25 } from "node:path";
14631
+ import { useInput as useInput10 } from "ink";
14632
+ import { useMemo as useMemo10, useState as useState10 } from "react";
14633
+ import { jsxDEV as jsxDEV26 } from "react/jsx-dev-runtime";
15901
14634
  function pickTheme(name) {
15902
14635
  if (name === undefined)
15903
14636
  return THEMES.houston;
@@ -15907,7 +14640,7 @@ function welcomeTheme(suggestedDir) {
15907
14640
  if (suggestedDir === undefined || suggestedDir === "")
15908
14641
  return THEMES.houston;
15909
14642
  try {
15910
- const text = readFileSync14(join24(suggestedDir, "ccsidekick", "config.toml"), "utf8");
14643
+ const text = readFileSync15(join25(suggestedDir, "ccsidekick", "config.toml"), "utf8");
15911
14644
  return pickTheme(loadConfig(text).theme.name);
15912
14645
  } catch {
15913
14646
  return THEMES.houston;
@@ -15916,22 +14649,46 @@ function welcomeTheme(suggestedDir) {
15916
14649
  function initialChosenDirs(configDir2) {
15917
14650
  return configDir2 === undefined ? null : [{ dir: configDir2, scope: "global" }];
15918
14651
  }
14652
+ function configPathFor(t) {
14653
+ return t.scope === "global" ? join25(t.dir, "ccsidekick", "config.toml") : join25(t.cwd ?? "", ".ccsidekick", "config.toml");
14654
+ }
14655
+ function isFirstRun(targets) {
14656
+ return !targets.some((t) => existsSync9(configPathFor(t)));
14657
+ }
15919
14658
  function onQuitProp(onQuit) {
15920
14659
  return onQuit !== undefined ? { onQuit } : {};
15921
14660
  }
14661
+ function entryExtras(props) {
14662
+ return {
14663
+ ...props.renderBin !== undefined ? { renderBin: props.renderBin } : {},
14664
+ ...props.onSave !== undefined ? { onSave: props.onSave } : {}
14665
+ };
14666
+ }
14667
+ function seedProp(seed2) {
14668
+ return seed2 !== undefined ? { initialConfig: seed2 } : {};
14669
+ }
14670
+ function dashboardBaseProps(props, env2, columns, rows) {
14671
+ return {
14672
+ env: env2,
14673
+ cols: columns,
14674
+ rows,
14675
+ ...props.themeName !== undefined ? { themeName: props.themeName } : {},
14676
+ ...props.packs !== undefined ? { packs: props.packs } : {},
14677
+ ...onQuitProp(props.onQuit),
14678
+ ...entryExtras(props)
14679
+ };
14680
+ }
15922
14681
  function App(props) {
15923
14682
  const env2 = props.env ?? process.env;
15924
14683
  const capability = detectCapability(env2);
15925
- const reducedMotion = detectReducedMotion(env2);
15926
14684
  const tokens = resolveTokens(THEMES.houston, capability);
15927
14685
  const [chosen, setChosen] = useState10(() => initialChosenDirs(props.configDir));
14686
+ const [override, setOverride] = useState10(null);
15928
14687
  const live = useTermSize();
15929
14688
  const columns = props.cols ?? live.columns;
15930
14689
  const rows = props.rows ?? live.rows;
15931
14690
  const atFloor = breakpointFor(columns, rows) === "floor";
15932
- useInput9(() => {});
15933
- const animating = chosen === null && capability === "full" && columns >= LOGO_MIN_COLUMNS && !atFloor;
15934
- const nowMs = useShimmerNow(reducedMotion, animating);
14691
+ useInput10(() => {});
15935
14692
  const home = props.homeDir ?? homedir6();
15936
14693
  const cwd = props.cwd ?? process.cwd();
15937
14694
  const suggested = props.suggestedDir ?? env2["CLAUDE_CONFIG_DIR"];
@@ -15943,22 +14700,9 @@ function App(props) {
15943
14700
  const isDuplicate = homeTargets.some((t) => t.dir === project.dir);
15944
14701
  return isDuplicate ? homeTargets : [...homeTargets, project];
15945
14702
  }, [dirs, cwd, home]);
15946
- const dashboardProps = {
15947
- env: env2,
15948
- reducedMotion,
15949
- cols: columns,
15950
- rows,
15951
- ...props.themeName !== undefined ? { themeName: props.themeName } : {},
15952
- ...onQuitProp(props.onQuit),
15953
- ...props.onSave !== undefined ? { onSave: props.onSave } : {},
15954
- ...props.renderBin !== undefined ? { renderBin: props.renderBin } : {},
15955
- ...props.initialConfig !== undefined ? { initialConfig: props.initialConfig } : {},
15956
- ...props.packs !== undefined ? { packs: props.packs } : {},
15957
- ...props.installed !== undefined ? { installed: props.installed } : {},
15958
- ...props.install !== undefined ? { install: props.install } : {}
15959
- };
14703
+ const dashboardProps = dashboardBaseProps(props, env2, columns, rows);
15960
14704
  if (chosen === null) {
15961
- return /* @__PURE__ */ jsxDEV25(Welcome, {
14705
+ return /* @__PURE__ */ jsxDEV26(Welcome, {
15962
14706
  dirs: options,
15963
14707
  suggestedIndex,
15964
14708
  onChosen: setChosen,
@@ -15967,16 +14711,36 @@ function App(props) {
15967
14711
  atFloor,
15968
14712
  hues: wordmarkHues,
15969
14713
  capability,
15970
- reducedMotion,
15971
- nowMs,
15972
14714
  tokens,
15973
14715
  ...suggested !== undefined ? { suggested } : {},
15974
14716
  ...onQuitProp(props.onQuit)
15975
14717
  }, undefined, false, undefined, this);
15976
14718
  }
15977
- return /* @__PURE__ */ jsxDEV25(Dashboard, {
14719
+ const view = override?.view ?? (isFirstRun(chosen) ? "wizard" : "dashboard");
14720
+ const seed2 = override?.draft ?? props.initialConfig;
14721
+ if (view === "wizard") {
14722
+ return /* @__PURE__ */ jsxDEV26(Wizard, {
14723
+ targets: chosen,
14724
+ cols: columns,
14725
+ rows,
14726
+ env: env2,
14727
+ initialDirty: override?.dirty ?? false,
14728
+ onAdvanced: (draft) => {
14729
+ setOverride({ view: "dashboard", draft, dirty: true });
14730
+ },
14731
+ ...onQuitProp(props.onQuit),
14732
+ ...entryExtras(props),
14733
+ ...seedProp(seed2)
14734
+ }, undefined, false, undefined, this);
14735
+ }
14736
+ return /* @__PURE__ */ jsxDEV26(Dashboard, {
15978
14737
  ...dashboardProps,
15979
- targets: chosen
14738
+ targets: chosen,
14739
+ initialDirty: override?.dirty ?? false,
14740
+ onWizard: (draft, dirty2) => {
14741
+ setOverride({ view: "wizard", draft, dirty: dirty2 });
14742
+ },
14743
+ ...seedProp(seed2)
15980
14744
  }, undefined, false, undefined, this);
15981
14745
  }
15982
14746
  var init_App = __esm(() => {
@@ -15988,14 +14752,12 @@ var init_App = __esm(() => {
15988
14752
  init_Dashboard();
15989
14753
  init_saveTarget();
15990
14754
  init_Welcome();
15991
- init_wordmark();
14755
+ init_Wizard();
15992
14756
  });
15993
14757
 
15994
14758
  // src/tui/shell/index.ts
15995
14759
  var exports_shell = {};
15996
14760
  __export(exports_shell, {
15997
- useTransitionFade: () => useTransitionFade,
15998
- useShimmerNow: () => useShimmerNow,
15999
14761
  useMouseWheel: () => useMouseWheel,
16000
14762
  routeKey: () => routeKey,
16001
14763
  rankFind: () => rankFind,
@@ -16004,6 +14766,7 @@ __export(exports_shell, {
16004
14766
  chipFor: () => chipFor,
16005
14767
  buildSaveConfirm: () => buildSaveConfirm,
16006
14768
  buildFindIndex: () => buildFindIndex,
14769
+ Wizard: () => Wizard,
16007
14770
  Welcome: () => Welcome,
16008
14771
  WORDMARK_WIDTH: () => WORDMARK_WIDTH,
16009
14772
  WORDMARK: () => WORDMARK,
@@ -16027,22 +14790,22 @@ var init_shell = __esm(() => {
16027
14790
  init_SaveConfirmPopup();
16028
14791
  init_saveTarget();
16029
14792
  init_Logo();
16030
- init_useTransitionFade();
16031
14793
  init_useMouseWheel();
16032
14794
  init_Welcome();
14795
+ init_Wizard();
16033
14796
  init_wordmark();
16034
14797
  });
16035
14798
 
16036
14799
  // src/bin/ccsidekick.ts
16037
14800
  init_cli();
16038
14801
  init_domain();
16039
- init_sources();
14802
+ init_tui();
16040
14803
  import { homedir as homedir7 } from "node:os";
16041
- import { join as join25 } from "node:path";
14804
+ import { join as join26 } from "node:path";
16042
14805
  import { fileURLToPath as fileURLToPath3 } from "node:url";
16043
14806
  var sub = process.argv[2];
16044
14807
  function claudeDir() {
16045
- return process.env["CLAUDE_CONFIG_DIR"] ?? join25(homedir7(), ".claude");
14808
+ return process.env["CLAUDE_CONFIG_DIR"] ?? join26(homedir7(), ".claude");
16046
14809
  }
16047
14810
  function printHelp() {
16048
14811
  process.stdout.write([
@@ -16050,6 +14813,8 @@ function printHelp() {
16050
14813
  "",
16051
14814
  "Usage:",
16052
14815
  " ccsidekick launch the setup TUI (needs a terminal)",
14816
+ " ccsidekick setup [flags] configure + wire without the TUI (see: setup --help)",
14817
+ " ccsidekick list <what> list valid characters | themes | widgets",
16053
14818
  " ccsidekick uninstall remove the status line + hooks from settings.json",
16054
14819
  " ccsidekick uninstall --restore-backup restore the pre-install settings backup",
16055
14820
  " ccsidekick help | --help | -h show this help",
@@ -16070,7 +14835,7 @@ function printManualSetup() {
16070
14835
  "Run `ccsidekick` directly in your terminal to configure and wire it.",
16071
14836
  "",
16072
14837
  "To wire it by hand, add to your Claude Code settings.json:",
16073
- ` • settings.json: ${join25(dir, "settings.json")}`,
14838
+ ` • settings.json: ${join26(dir, "settings.json")}`,
16074
14839
  ` • "statusLine": { "type": "command", "command": "ccsidekick-render render", "refreshInterval": ${String(REFRESH_INTERVAL_SEC)} }`,
16075
14840
  ' • three hooks, each running "ccsidekick-render classify" with the same matcher:',
16076
14841
  ' "PostToolUse", "PostToolUseFailure", and "PostToolBatch"',
@@ -16082,14 +14847,11 @@ async function launchTui() {
16082
14847
  const { render } = await import("ink");
16083
14848
  const { createElement } = await import("react");
16084
14849
  const { App: App2 } = await Promise.resolve().then(() => (init_shell(), exports_shell));
16085
- const engineDir = engineRoot(import.meta.url);
16086
14850
  const renderBin = fileURLToPath3(new URL("ccsidekick-render.js", import.meta.url));
16087
- const installed = listInstalledPacks(engineDir);
16088
14851
  const suggested = process.env["CLAUDE_CONFIG_DIR"];
16089
14852
  const instance = render(createElement(App2, {
16090
14853
  homeDir: homedir7(),
16091
14854
  renderBin,
16092
- installed,
16093
14855
  ...suggested !== undefined ? { suggestedDir: suggested } : {}
16094
14856
  }));
16095
14857
  await instance.waitUntilExit();
@@ -16101,11 +14863,33 @@ async function main() {
16101
14863
  }
16102
14864
  if (sub === "uninstall") {
16103
14865
  runUninstall({
16104
- settingsPath: join25(claudeDir(), "settings.json"),
14866
+ settingsPath: join26(claudeDir(), "settings.json"),
16105
14867
  restoreBackup: process.argv.includes("--restore-backup")
16106
14868
  });
16107
14869
  process.exit(0);
16108
14870
  }
14871
+ if (sub === "list") {
14872
+ const code = runList(process.argv[3], (s) => process.stdout.write(s), (s) => process.stderr.write(s));
14873
+ process.exit(code);
14874
+ }
14875
+ if (sub === "setup") {
14876
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
14877
+ process.stdout.write(setupHelp());
14878
+ process.exit(0);
14879
+ }
14880
+ const renderBin = fileURLToPath3(new URL("ccsidekick-render.js", import.meta.url));
14881
+ const code = runSetup(process.argv.slice(3), {
14882
+ save,
14883
+ renderBin,
14884
+ readConfig: defaultReadConfig,
14885
+ cwd: process.cwd(),
14886
+ homeDir: homedir7(),
14887
+ env: process.env,
14888
+ out: (s) => process.stdout.write(s),
14889
+ err: (s) => process.stderr.write(s)
14890
+ });
14891
+ process.exit(code);
14892
+ }
16109
14893
  if (!process.stdout.isTTY || !process.stdin.isTTY) {
16110
14894
  printManualSetup();
16111
14895
  process.exit(1);