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.
package/README.md CHANGED
@@ -9,20 +9,58 @@ path and disableable.
9
9
  npx ccsidekick
10
10
  ```
11
11
 
12
- Running `ccsidekick` in a terminal opens the setup TUI: it picks a Claude config dir, lets you choose
13
- a character, and wires the status line and the tool-call hooks into your `settings.json`. Remove it
14
- with `npx ccsidekick uninstall`.
12
+ Running `ccsidekick` in a terminal opens the setup UI: a first run walks you through a short guided
13
+ wizard (character, theme, comments), a later run opens the full dashboard. Either way it picks a
14
+ Claude config dir and wires the status line and the tool-call hooks into your `settings.json`.
15
+ Remove it with `npx ccsidekick uninstall`.
16
+
17
+ ## Non-interactive setup (for scripts and AI agents)
18
+
19
+ No TTY required. `ccsidekick setup` configures and wires everything from flags, so an agent can
20
+ install it in one command:
21
+
22
+ ```bash
23
+ ccsidekick setup --character batman --theme houston --mode fixed
24
+ ```
25
+
26
+ Only the flags you pass are applied (a partial patch onto the existing config, or the defaults on a
27
+ fresh install), then it writes `config.toml` and wires `settings.json` exactly like the TUI.
28
+
29
+ | Flag | Sets |
30
+ | ------------------------ | --------------------------------------------------------------- |
31
+ | `--character <name>` | the fixed character |
32
+ | `--mode <fixed\|random>` | fixed one character, or rotate the roster |
33
+ | `--roster <a,b,c>` | the random-mode roster |
34
+ | `--theme <name>` | a theme, or `character` (the default) to match the character |
35
+ | `--currency <code>` | statusline currency, e.g. `USD` |
36
+ | `--budget <usd>` | monthly budget |
37
+ | `--comments <on\|off>` | the character's comment line |
38
+ | `--helpful <on\|off>` | the helpful-tip line |
39
+ | `--min-severity <sev>` | `low\|medium\|high\|critical` |
40
+ | `--widgets <a,b,c>` | statusline widgets to enable (others turn off) |
41
+ | `--global` / `--local` | save target (default global) |
42
+ | `--config-dir <path>` | Claude config dir (default `$CLAUDE_CONFIG_DIR` or `~/.claude`) |
43
+
44
+ Discover valid values for scripting, and see every flag:
45
+
46
+ ```bash
47
+ ccsidekick list characters # also: themes, widgets
48
+ ccsidekick setup --help
49
+ ```
50
+
51
+ An unknown value (e.g. a misspelled theme) exits non-zero and prints the valid set — it never
52
+ silently falls back.
15
53
 
16
54
  ## The two binaries
17
55
 
18
56
  - **`ccsidekick-render`** is the hot path. Claude Code calls `ccsidekick-render render` on every
19
- status-line tick and `ccsidekick-render classify` on every tool call. It loads no UI and runs under
20
- plain Node.
21
- - **`ccsidekick`** is the setup TUI and `uninstall`. It is the only entry point that loads the Ink
22
- interface.
57
+ status-line tick and `ccsidekick-render classify` on every tool call. It loads no UI and runs
58
+ under plain Node.
59
+ - **`ccsidekick`** is the user-facing entry: the setup UI, plus `setup`, `list`, and `uninstall`.
60
+ Only the TUI loads the Ink interface; `setup`/`list`/`uninstall` run under plain Node.
23
61
 
24
- Characters ship as separate `@ccsidekick/pack-<name>` packages; `batman` is bundled as a runtime
25
- dependency so a fresh install always has a character.
62
+ Every character ships bundled as a runtime dependency, so a fresh install has them all — there is no
63
+ download or install step, and no network to pick a character.
26
64
 
27
65
  For the full feature tour, configuration reference, and contributor docs, see the
28
66
  [repository README](https://github.com/krayong/ccsidekick#readme).
@@ -2428,11 +2428,10 @@ var DEFAULT_WIDGETS = {
2428
2428
  var DEFAULT_CONFIG = {
2429
2429
  schema_version: 1,
2430
2430
  character: { enabled: true, mode: "random", name: "batman", roster: [] },
2431
- comments: { enabled: true },
2432
- helpful: { enabled: true, min_severity: "low" },
2433
- line: { currency: defaultCurrency(), widgets: DEFAULT_WIDGETS },
2434
- theme: { name: "houston", banding: "solid", mood_shift: false, icons: {} },
2435
- network: { fx_refresh: true, usage_fetch: true, balance_path: "" }
2431
+ theme: { name: "character", banding: "solid", mood_shift: false, icons: {} },
2432
+ comments: { character: true, helpful: true, min_severity: "low" },
2433
+ network: { fx_refresh: true, usage_fetch: true, balance_path: "" },
2434
+ statusline: { currency: defaultCurrency(), widgets: DEFAULT_WIDGETS }
2436
2435
  };
2437
2436
  var obj = (v) => v !== null && typeof v === "object" ? v : {};
2438
2437
  var bool = (v, d) => typeof v === "boolean" ? v : d;
@@ -2475,10 +2474,9 @@ function loadConfig(globalToml = "", projectToml = "") {
2475
2474
  const p = safeParse(projectToml);
2476
2475
  const character = section(g, p, "character");
2477
2476
  const comments = section(g, p, "comments");
2478
- const helpful = section(g, p, "helpful");
2479
- const line = section(g, p, "line");
2480
2477
  const theme = section(g, p, "theme");
2481
2478
  const network = section(g, p, "network");
2479
+ const statusline = section(g, p, "statusline");
2482
2480
  const d = DEFAULT_CONFIG;
2483
2481
  return {
2484
2482
  schema_version: numv(p["schema_version"] ?? g["schema_version"], d.schema_version),
@@ -2488,21 +2486,6 @@ function loadConfig(globalToml = "", projectToml = "") {
2488
2486
  name: str(character["name"], d.character.name),
2489
2487
  roster: stringArray(character["roster"], d.character.roster)
2490
2488
  },
2491
- comments: {
2492
- enabled: bool(comments["enabled"], d.comments.enabled)
2493
- },
2494
- helpful: {
2495
- enabled: bool(helpful["enabled"], d.helpful.enabled),
2496
- min_severity: oneOf(helpful["min_severity"], ["low", "medium", "high", "critical"], d.helpful.min_severity)
2497
- },
2498
- line: {
2499
- currency: str(line["currency"], d.line.currency),
2500
- ...typeof line["budget"] === "number" ? { budget: line["budget"] } : {},
2501
- widgets: mergeWidgets({
2502
- ...obj(obj(g["line"])["widgets"]),
2503
- ...obj(obj(p["line"])["widgets"])
2504
- })
2505
- },
2506
2489
  theme: {
2507
2490
  name: str(theme["name"], d.theme.name),
2508
2491
  ...typeof theme["statusline"] === "string" ? { statusline: theme["statusline"] } : {},
@@ -2515,10 +2498,23 @@ function loadConfig(globalToml = "", projectToml = "") {
2515
2498
  ...obj(obj(p["theme"])["icons"])
2516
2499
  })
2517
2500
  },
2501
+ comments: {
2502
+ character: bool(comments["character"], d.comments.character),
2503
+ helpful: bool(comments["helpful"], d.comments.helpful),
2504
+ min_severity: oneOf(comments["min_severity"], ["low", "medium", "high", "critical"], d.comments.min_severity)
2505
+ },
2518
2506
  network: {
2519
2507
  fx_refresh: bool(network["fx_refresh"], d.network.fx_refresh),
2520
2508
  usage_fetch: bool(network["usage_fetch"], d.network.usage_fetch),
2521
2509
  balance_path: str(network["balance_path"], d.network.balance_path)
2510
+ },
2511
+ statusline: {
2512
+ currency: str(statusline["currency"], d.statusline.currency),
2513
+ ...typeof statusline["budget"] === "number" ? { budget: statusline["budget"] } : {},
2514
+ widgets: mergeWidgets({
2515
+ ...obj(obj(g["statusline"])["widgets"]),
2516
+ ...obj(obj(p["statusline"])["widgets"])
2517
+ })
2522
2518
  }
2523
2519
  };
2524
2520
  }
@@ -6490,22 +6486,22 @@ var HELPFUL_CATALOG = [
6490
6486
  render: (i) => `Large diff: +${i.git?.insertions ?? 0}/-${i.git?.deletions ?? 0}. Review in chunks.`
6491
6487
  },
6492
6488
  {
6493
- id: "behind_upstream",
6489
+ id: "diverged",
6494
6490
  severity: "medium",
6495
6491
  category: "git",
6496
6492
  momentary: false,
6497
- template: "{behind} behind upstream. Pull before your next commit knots the merge.",
6498
- test: (i) => behind(i.git) > 0,
6499
- render: (i) => `${behind(i.git)} behind upstream. Pull before your next commit knots the merge.`
6493
+ template: "Diverged {ahead}↑ {behind}↓. `git pull --rebase` keeps history linear.",
6494
+ test: (i) => ahead(i.git) > 0 && behind(i.git) > 0,
6495
+ render: (i) => `Diverged ${ahead(i.git)}↑ ${behind(i.git)}↓. \`git pull --rebase\` keeps history linear.`
6500
6496
  },
6501
6497
  {
6502
- id: "diverged",
6498
+ id: "behind_upstream",
6503
6499
  severity: "medium",
6504
6500
  category: "git",
6505
6501
  momentary: false,
6506
- template: "Diverged {ahead}↑ {behind}↓. `git pull --rebase` keeps history linear.",
6507
- test: (i) => ahead(i.git) > 0 && behind(i.git) > 0,
6508
- render: (i) => `Diverged ${ahead(i.git)}↑ ${behind(i.git)}↓. \`git pull --rebase\` keeps history linear.`
6502
+ template: "{behind} behind upstream. Pull before your next commit knots the merge.",
6503
+ test: (i) => behind(i.git) > 0,
6504
+ render: (i) => `${behind(i.git)} behind upstream. Pull before your next commit knots the merge.`
6509
6505
  },
6510
6506
  {
6511
6507
  id: "dirty_default_branch",
@@ -7185,8 +7181,11 @@ function build(stdin, env, term, clock, overrides) {
7185
7181
  git,
7186
7182
  payload,
7187
7183
  scan,
7188
- widgets: config.line.widgets,
7189
- currency: { code: config.line.currency, rate: fxTable[config.line.currency] ?? 0 },
7184
+ widgets: config.statusline.widgets,
7185
+ currency: {
7186
+ code: config.statusline.currency,
7187
+ rate: fxTable[config.statusline.currency] ?? 0
7188
+ },
7190
7189
  homeDir: env["HOME"] ?? ""
7191
7190
  };
7192
7191
  const composed = composeStatusline(composeInputs);
@@ -7204,7 +7203,7 @@ function build(stdin, env, term, clock, overrides) {
7204
7203
  creds,
7205
7204
  balance
7206
7205
  };
7207
- const helpfulResult = config.helpful.enabled ? resolveHelpful(helpfulInputs, sessionState, clock, config.helpful.min_severity) : { comment: null, nextHelpful: sessionState.helpful };
7206
+ const helpfulResult = config.comments.helpful ? resolveHelpful(helpfulInputs, sessionState, clock, config.comments.min_severity) : { comment: null, nextHelpful: sessionState.helpful };
7208
7207
  const helpful = helpfulResult.comment;
7209
7208
  const pending = pendingMilestones(familiarity, clock);
7210
7209
  const charBase = {
@@ -7225,7 +7224,7 @@ function build(stdin, env, term, clock, overrides) {
7225
7224
  state: sessionState,
7226
7225
  clock,
7227
7226
  session,
7228
- config: { enabled: config.comments.enabled }
7227
+ config: { enabled: config.comments.character }
7229
7228
  });
7230
7229
  } catch {
7231
7230
  charResult = { comment: null, nextState: charBase };