@ramarivera/coding-buddy 0.4.0-alpha.9 → 0.6.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.
Files changed (92) hide show
  1. package/{adapters/claude/plugin → .claude-plugin}/marketplace.json +11 -6
  2. package/{adapters/claude/plugin → .claude-plugin}/plugin.json +7 -3
  3. package/LICENSE +1 -1
  4. package/README.md +88 -37
  5. package/adapters/omp/commands.ts +201 -0
  6. package/adapters/omp/context.ts +22 -0
  7. package/adapters/omp/events.ts +551 -0
  8. package/adapters/omp/identity.ts +10 -0
  9. package/adapters/omp/index.ts +39 -0
  10. package/adapters/omp/logger.ts +52 -0
  11. package/adapters/omp/prompt.ts +60 -0
  12. package/adapters/omp/renderers.ts +73 -0
  13. package/adapters/omp/storage.ts +25 -0
  14. package/adapters/omp/ui.ts +85 -0
  15. package/adapters/pi/commands.ts +64 -37
  16. package/adapters/pi/events.ts +147 -72
  17. package/adapters/pi/index.ts +9 -4
  18. package/adapters/pi/storage.ts +14 -285
  19. package/adapters/pi/ui.ts +56 -5
  20. package/adapters/shared/file-storage.ts +526 -0
  21. package/{adapters/claude/install → cli}/backup.ts +130 -33
  22. package/cli/buddy-shell.ts +1 -1
  23. package/{adapters/claude/install → cli}/disable.ts +19 -32
  24. package/cli/doctor.ts +231 -0
  25. package/{adapters/claude/install → cli}/hunt.ts +7 -9
  26. package/cli/index.ts +30 -26
  27. package/{adapters/claude/install → cli}/install.ts +65 -83
  28. package/{adapters/claude/install → cli}/pick.ts +111 -50
  29. package/{adapters/claude/install → cli}/settings.ts +2 -2
  30. package/{adapters/claude/install → cli}/show.ts +4 -4
  31. package/{adapters/claude/install → cli}/test-statusline.sh +2 -2
  32. package/{adapters/claude/install → cli}/test-statusline.ts +21 -11
  33. package/cli/tui.tsx +106 -17
  34. package/{adapters/claude/install → cli}/uninstall.ts +40 -47
  35. package/cli/upgrade.ts +2 -2
  36. package/cli/validate-species.ts +209 -0
  37. package/cli/verify.ts +3 -3
  38. package/core/achievements.ts +12 -20
  39. package/core/art-data.ts +26 -0
  40. package/core/command-service.ts +99 -97
  41. package/core/engine.ts +83 -1
  42. package/core/ports.ts +10 -0
  43. package/core/reactions.ts +533 -95
  44. package/core/slot-slug.ts +22 -0
  45. package/{adapters/claude/hooks → hooks}/buddy-comment.sh +19 -1
  46. package/hooks/file-type-react.sh +401 -0
  47. package/hooks/hooks.json +52 -0
  48. package/hooks/mood-react.sh +208 -0
  49. package/{adapters/claude/hooks → hooks}/name-react.sh +1 -1
  50. package/hooks/react.sh +1368 -0
  51. package/hooks/suggest.sh +55 -0
  52. package/package.json +70 -31
  53. package/scripts/gen-emoji-widths.ts +34 -0
  54. package/scripts/paths.sh +17 -1
  55. package/scripts/postinstall.cjs +42 -0
  56. package/scripts/snapshot-statusline.sh +54 -0
  57. package/server/achievements.ts +1419 -15
  58. package/server/art.ts +450 -1
  59. package/server/award-xp.ts +48 -0
  60. package/server/check-suggestions.ts +102 -0
  61. package/server/consolidate.ts +33 -0
  62. package/{adapters/claude/server → server}/index.ts +556 -95
  63. package/server/mcp-launcher.sh +16 -6
  64. package/server/memory.ts +404 -0
  65. package/server/mood.ts +254 -0
  66. package/server/path.ts +70 -18
  67. package/server/shift-mood.ts +43 -0
  68. package/server/state.ts +540 -3
  69. package/server/suggestions.ts +335 -0
  70. package/server/theme.ts +53 -0
  71. package/server/xp.ts +435 -0
  72. package/{adapters/claude/skills → skills}/buddy/SKILL.md +36 -7
  73. package/statusline/buddy-status.sh +397 -0
  74. package/statusline/combined-status.sh +134 -0
  75. package/statusline/emoji-widths.data +4 -0
  76. package/adapters/claude/hooks/hooks.json +0 -35
  77. package/adapters/claude/hooks/react.sh +0 -207
  78. package/adapters/claude/install/doctor.ts +0 -172
  79. package/adapters/claude/rendering/art.ts +0 -264
  80. package/adapters/claude/server/instructions.ts +0 -24
  81. package/adapters/claude/server/path.ts +0 -12
  82. package/adapters/claude/server/resources.ts +0 -38
  83. package/adapters/claude/statusline/buddy-status.sh +0 -408
  84. package/adapters/claude/storage/achievements.ts +0 -253
  85. package/adapters/claude/storage/identity.ts +0 -13
  86. package/adapters/claude/storage/paths.ts +0 -33
  87. package/adapters/claude/storage/settings.ts +0 -91
  88. package/adapters/claude/storage/state.ts +0 -365
  89. package/adapters/pi/README.md +0 -83
  90. package/adapters/pi/tools.ts +0 -6
  91. package/server/engine.ts +0 -1
  92. package/server/reactions.ts +0 -1
@@ -18,12 +18,11 @@
18
18
  import {
19
19
  loadActiveSlot, saveActiveSlot, listCompanionSlots,
20
20
  loadCompanionSlot, saveCompanionSlot, slugify, unusedName, writeStatusState,
21
- } from "../storage/state.ts";
22
- import {
23
- generateBones, SPECIES, RARITIES, STAT_NAMES, RARITY_STARS,
24
- type Species, type Rarity, type StatName, type BuddyBones, type Companion,
25
- } from "../../../core/engine.ts";
26
- import { renderCompanionCard } from "../rendering/art.ts";
21
+ } from "../server/state.ts";
22
+ import { generateBones, generatePersonality, SPECIES, RARITIES, STAT_NAMES, RARITY_STARS, EYES, HATS,
23
+ type Species, type Rarity, type StatName, type Eye, type Hat,
24
+ type BuddyBones, type Companion, } from "../core/engine.ts"
25
+ import { renderCompanionCard } from "../server/art.ts";
27
26
  import { randomBytes } from "crypto";
28
27
 
29
28
  // ─── ANSI ─────────────────────────────────────────────────────────────────────
@@ -79,32 +78,46 @@ function rpad(s: string, w: number): string {
79
78
 
80
79
  // ─── Option lists ─────────────────────────────────────────────────────────────
81
80
 
82
- const SP_OPTS = ["any", ...SPECIES] as const;
83
- const RA_OPTS = ["any", ...RARITIES] as const;
84
- const SH_OPTS = ["any", "yes", "no"] as const;
85
- const ST_OPTS = ["any", ...STAT_NAMES] as const;
81
+ const SP_OPTS = ["any", ...SPECIES] as const;
82
+ const RA_OPTS = ["any", ...RARITIES] as const;
83
+ const SH_OPTS = ["any", "yes", "no"] as const;
84
+ const ST_OPTS = ["any", ...STAT_NAMES] as const;
85
+ const EY_OPTS = ["any", ...EYES] as const;
86
+ const HA_OPTS = ["any", ...HATS] as const;
87
+ const MIN_OPTS = ["any", "5", "10", "15", "20", "25", "30", "35", "40", "45",
88
+ "50", "55", "60", "65", "70", "75", "80", "85", "90", "95"] as const;
89
+ const AVG_OPTS = MIN_OPTS;
86
90
 
87
91
  const CRITERIA_ROWS: Array<{ label: string; opts: readonly string[] }> = [
88
- { label: "Species", opts: SP_OPTS },
89
- { label: "Rarity ", opts: RA_OPTS },
90
- { label: "Shiny ", opts: SH_OPTS },
91
- { label: "Peak ", opts: ST_OPTS },
92
- { label: "Dump ", opts: ST_OPTS },
92
+ { label: "Species", opts: SP_OPTS },
93
+ { label: "Rarity ", opts: RA_OPTS },
94
+ { label: "Shiny ", opts: SH_OPTS },
95
+ { label: "Peak ", opts: ST_OPTS },
96
+ { label: "Dump ", opts: ST_OPTS },
97
+ { label: "Eye ", opts: EY_OPTS },
98
+ { label: "Hat ", opts: HA_OPTS },
99
+ { label: "Min avg", opts: AVG_OPTS },
100
+ { label: "Min DBG", opts: MIN_OPTS },
101
+ { label: "Min PAT", opts: MIN_OPTS },
102
+ { label: "Min CHA", opts: MIN_OPTS },
103
+ { label: "Min WIS", opts: MIN_OPTS },
104
+ { label: "Min SNK", opts: MIN_OPTS },
93
105
  ];
94
106
 
95
107
  // ─── State ────────────────────────────────────────────────────────────────────
96
108
 
97
- type Mode = "saved" | "criteria" | "results" | "naming";
109
+ type Mode = "saved" | "criteria" | "searching" | "results" | "naming";
98
110
  interface SlotEntry { slot: string; companion: Companion; }
99
111
  interface BuddyResult { userId: string; bones: BuddyBones; }
100
112
 
101
113
  interface State {
102
114
  mode: Mode;
115
+ searching: boolean;
103
116
  savedSlots: SlotEntry[];
104
117
  savedCursor: number;
105
118
  activeSlot: string;
106
119
  criteriaFocus: number;
107
- ci: number[]; // [speciesIdx, rarityIdx, shinyIdx, peakIdx, dumpIdx]
120
+ ci: number[]; // [speciesIdx, rarityIdx, shinyIdx, peakIdx, dumpIdx, eyeIdx, hatIdx, avgIdx, dbgIdx, patIdx, chaIdx, wisIdx, snkIdx]
108
121
  results: BuddyResult[];
109
122
  resultCursor: number;
110
123
  searchStatus: string;
@@ -116,12 +129,13 @@ interface State {
116
129
  function fresh(): State {
117
130
  return {
118
131
  mode: "saved",
132
+ searching: false,
119
133
  savedSlots: listCompanionSlots(),
120
134
  savedCursor: 0,
121
135
  activeSlot: loadActiveSlot(),
122
136
  criteriaFocus: 0,
123
- // Default criteria: legendary, any species
124
- ci: [0, RA_OPTS.indexOf("legendary"), 0, 0, 0],
137
+ // Default criteria: legendary, any species/shiny/peak/dump/eye/hat/avg/stats
138
+ ci: [0, RA_OPTS.indexOf("legendary"), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
125
139
  results: [],
126
140
  resultCursor: 0,
127
141
  searchStatus: "",
@@ -185,6 +199,16 @@ function criteriaPane(s: State): string[] {
185
199
  return lines;
186
200
  }
187
201
 
202
+ function searchingPane(s: State): string[] {
203
+ const lines: string[] = [];
204
+ lines.push(`${B} Searching...${N}`);
205
+ lines.push(GR + " " + "─".repeat(LEFT_W - 2) + N);
206
+ lines.push(` ${YL}${s.searchStatus || "starting..."}${N}`);
207
+ lines.push(` ${GR}any key to stop${N}`);
208
+ lines.push(GR + " " + "─".repeat(LEFT_W - 2) + N);
209
+ return lines;
210
+ }
211
+
188
212
  function resultsPane(s: State): string[] {
189
213
  const lines: string[] = [];
190
214
  lines.push(`${B} Results${N} ${GR}${s.results.length} found${N}`);
@@ -236,14 +260,14 @@ function previewPane(s: State): string[] {
236
260
  const r = s.results[s.resultCursor];
237
261
  if (r) c = {
238
262
  bones: r.bones, name: "???",
239
- personality: `A ${r.bones.rarity} ${r.bones.species}`,
263
+ personality: generatePersonality(r.bones, r.userId),
240
264
  hatchedAt: Date.now(), userId: r.userId,
241
265
  };
242
266
  } else if (s.mode === "naming" && s.pendingResult) {
243
267
  const r = s.pendingResult;
244
268
  c = {
245
269
  bones: r.bones, name: s.nameInput || "???",
246
- personality: `A ${r.bones.rarity} ${r.bones.species} who watches code with quiet intensity.`,
270
+ personality: generatePersonality(r.bones, r.userId),
247
271
  hatchedAt: Date.now(), userId: r.userId,
248
272
  };
249
273
  }
@@ -261,9 +285,10 @@ function drawScreen(s: State): void {
261
285
  const cols = Math.max(80, process.stdout.columns || 80);
262
286
  const rows = Math.max(20, process.stdout.rows || 24);
263
287
 
264
- const leftLines = s.mode === "saved" ? savedPane(s)
265
- : s.mode === "criteria" ? criteriaPane(s)
266
- : s.mode === "results" ? resultsPane(s)
288
+ const leftLines = s.mode === "saved" ? savedPane(s)
289
+ : s.mode === "criteria" ? criteriaPane(s)
290
+ : s.mode === "searching" ? searchingPane(s)
291
+ : s.mode === "results" ? resultsPane(s)
267
292
  : namingPane(s);
268
293
  const rightLines = previewPane(s);
269
294
  const contentH = rows - 2;
@@ -271,7 +296,7 @@ function drawScreen(s: State): void {
271
296
  let out = "\x1b[2J\x1b[H"; // clear + home
272
297
 
273
298
  // Title bar
274
- const title = ` claude-buddy pick `;
299
+ const title = ` coding-buddy pick `;
275
300
  const fill = "─".repeat(Math.max(0, cols - title.length - 2));
276
301
  out += `${CY}─${B}${title}${N}${CY}${fill}─${N}\n`;
277
302
 
@@ -284,10 +309,11 @@ function drawScreen(s: State): void {
284
309
 
285
310
  // Footer — mode-specific help
286
311
  const helpText =
287
- s.mode === "saved" ? "↑↓ navigate enter summon r random s search q quit" :
288
- s.mode === "criteria" ? "↑↓ field ←→ value enter search esc back" :
289
- s.mode === "results" ? "↑↓ navigate enter name+save esc back q quit" :
290
- s.mode === "naming" ? "type name enter save esc cancel" : "";
312
+ s.mode === "saved" ? "↑↓ navigate enter summon r random s search q quit" :
313
+ s.mode === "criteria" ? "↑↓ field ←→ value enter search esc back" :
314
+ s.mode === "searching" ? "any key to stop and show results so far" :
315
+ s.mode === "results" ? "↑↓ navigate enter name+save esc back q quit" :
316
+ s.mode === "naming" ? "type name enter save esc cancel" : "";
291
317
  out += `${GR}─${N} ${GR}${helpText}${N} ${GR}${"─".repeat(Math.max(0, cols - helpText.length - 4))}${N}`;
292
318
 
293
319
  // Message overlay on last line
@@ -300,13 +326,26 @@ function drawScreen(s: State): void {
300
326
 
301
327
  // ─── Search ───────────────────────────────────────────────────────────────────
302
328
 
303
- function runSearch(s: State): void {
304
- const wantSp = SP_OPTS[s.ci[0]] !== "any" ? SP_OPTS[s.ci[0]] as Species : null;
305
- const wantRa = RA_OPTS[s.ci[1]] !== "any" ? RA_OPTS[s.ci[1]] as Rarity : null;
306
- const wantShiny = SH_OPTS[s.ci[2]] === "yes" ? true
307
- : SH_OPTS[s.ci[2]] === "no" ? false : null;
308
- const wantPeak = ST_OPTS[s.ci[3]] !== "any" ? ST_OPTS[s.ci[3]] as StatName : null;
309
- const wantDump = ST_OPTS[s.ci[4]] !== "any" ? ST_OPTS[s.ci[4]] as StatName : null;
329
+ function avgStat(bones: BuddyBones): number {
330
+ const vals = Object.values(bones.stats) as number[];
331
+ return vals.reduce((a, b) => a + b, 0) / vals.length;
332
+ }
333
+
334
+ async function runSearch(s: State): Promise<void> {
335
+ const wantSp = SP_OPTS[s.ci[0]] !== "any" ? SP_OPTS[s.ci[0]] as Species : null;
336
+ const wantRa = RA_OPTS[s.ci[1]] !== "any" ? RA_OPTS[s.ci[1]] as Rarity : null;
337
+ const wantShiny = SH_OPTS[s.ci[2]] === "yes" ? true
338
+ : SH_OPTS[s.ci[2]] === "no" ? false : null;
339
+ const wantPeak = ST_OPTS[s.ci[3]] !== "any" ? ST_OPTS[s.ci[3]] as StatName : null;
340
+ const wantDump = ST_OPTS[s.ci[4]] !== "any" ? ST_OPTS[s.ci[4]] as StatName : null;
341
+ const wantEye = EY_OPTS[s.ci[5]] !== "any" ? EY_OPTS[s.ci[5]] as Eye : null;
342
+ const wantHat = HA_OPTS[s.ci[6]] !== "any" ? HA_OPTS[s.ci[6]] as Hat : null;
343
+ const minAvg = AVG_OPTS[s.ci[7]] !== "any" ? Number(AVG_OPTS[s.ci[7]]) : null;
344
+ const minDBG = MIN_OPTS[s.ci[8]] !== "any" ? Number(MIN_OPTS[s.ci[8]]) : null;
345
+ const minPAT = MIN_OPTS[s.ci[9]] !== "any" ? Number(MIN_OPTS[s.ci[9]]) : null;
346
+ const minCHA = MIN_OPTS[s.ci[10]] !== "any" ? Number(MIN_OPTS[s.ci[10]]) : null;
347
+ const minWIS = MIN_OPTS[s.ci[11]] !== "any" ? Number(MIN_OPTS[s.ci[11]]) : null;
348
+ const minSNK = MIN_OPTS[s.ci[12]] !== "any" ? Number(MIN_OPTS[s.ci[12]]) : null;
310
349
 
311
350
  // Scale attempt budget to rarity difficulty
312
351
  const maxAttempts =
@@ -315,32 +354,47 @@ function runSearch(s: State): void {
315
354
  wantRa === "rare" ? 20_000_000 : 10_000_000;
316
355
 
317
356
  const results: BuddyResult[] = [];
318
- const progressRow = (process.stdout.rows || 24) - 1;
357
+ const YIELD_EVERY = 5_000_000;
358
+ const PROGRESS_EVERY = 1_000_000;
319
359
 
320
360
  for (let i = 0; i < maxAttempts && results.length < 20; i++) {
321
- if (i > 0 && i % 1_000_000 === 0) {
322
- s.searchStatus = `${(i / 1e6).toFixed(0)}M checked — ${results.length} found`;
323
- process.stdout.write(
324
- `\x1b[${progressRow};1H ${YL}${s.searchStatus}${N} \x1b[K`,
325
- );
361
+ if (!s.searching) break;
362
+
363
+ if (i > 0 && i % YIELD_EVERY === 0) {
364
+ await new Promise<void>(resolve => setImmediate(resolve));
365
+ }
366
+
367
+ if (i > 0 && i % PROGRESS_EVERY === 0) {
368
+ s.searchStatus = `${(i / 1e6).toFixed(1)}M checked — ${results.length} found`;
369
+ drawScreen(s);
326
370
  }
327
371
 
328
372
  const userId = randomBytes(16).toString("hex");
329
373
  const bones = generateBones(userId);
330
374
 
331
- if (wantSp !== null && bones.species !== wantSp) continue;
332
- if (wantRa !== null && bones.rarity !== wantRa) continue;
333
- if (wantShiny !== null && bones.shiny !== wantShiny) continue;
334
- if (wantPeak !== null && bones.peak !== wantPeak) continue;
335
- if (wantDump !== null && bones.dump !== wantDump) continue;
375
+ if (wantSp !== null && bones.species !== wantSp) continue;
376
+ if (wantRa !== null && bones.rarity !== wantRa) continue;
377
+ if (wantShiny !== null && bones.shiny !== wantShiny) continue;
378
+ if (wantPeak !== null && bones.peak !== wantPeak) continue;
379
+ if (wantDump !== null && bones.dump !== wantDump) continue;
380
+ if (wantEye !== null && bones.eye !== wantEye) continue;
381
+ if (wantHat !== null && bones.hat !== wantHat) continue;
382
+ if (minAvg !== null && avgStat(bones) < minAvg) continue;
383
+ if (minDBG !== null && bones.stats.DEBUGGING < minDBG) continue;
384
+ if (minPAT !== null && bones.stats.PATIENCE < minPAT) continue;
385
+ if (minCHA !== null && bones.stats.CHAOS < minCHA) continue;
386
+ if (minWIS !== null && bones.stats.WISDOM < minWIS) continue;
387
+ if (minSNK !== null && bones.stats.SNARK < minSNK) continue;
336
388
 
337
389
  results.push({ userId, bones });
338
390
  }
339
391
 
392
+ s.searching = false;
340
393
  s.searchStatus = `${results.length} found`;
341
394
  s.results = results;
342
395
  s.resultCursor = 0;
343
396
  s.mode = "results";
397
+ drawScreen(s);
344
398
  }
345
399
 
346
400
  // ─── Key handlers ─────────────────────────────────────────────────────────────
@@ -367,7 +421,7 @@ function onKey(key: string, s: State): boolean {
367
421
  const r = s.pendingResult!;
368
422
  const companion: Companion = {
369
423
  bones: r.bones, name,
370
- personality: `A ${r.bones.rarity} ${r.bones.species} who watches code with quiet intensity.`,
424
+ personality: generatePersonality(r.bones, r.userId),
371
425
  hatchedAt: Date.now(), userId: r.userId,
372
426
  };
373
427
  saveCompanionSlot(companion, slot);
@@ -422,13 +476,20 @@ function onKey(key: string, s: State): boolean {
422
476
  const len = CRITERIA_ROWS[s.criteriaFocus].opts.length;
423
477
  s.ci[s.criteriaFocus] = (s.ci[s.criteriaFocus] - 1 + len) % len;
424
478
  } else if (key === "\r" || key === "\n") {
425
- s.searchStatus = "Starting search...";
479
+ s.mode = "searching";
480
+ s.searching = true;
481
+ s.searchStatus = "starting...";
426
482
  drawScreen(s);
427
- runSearch(s);
483
+ runSearch(s); // fire-and-forget async; updates state and redraws when done
428
484
  }
429
485
  break;
430
486
  }
431
487
 
488
+ case "searching": {
489
+ s.searching = false; // any key stops; runSearch will drain and switch to results
490
+ break;
491
+ }
492
+
432
493
  case "results": {
433
494
  if (key === "q") return true;
434
495
  if (key === "\x1b") { s.mode = "criteria"; break; }
@@ -7,7 +7,7 @@
7
7
  * bun run settings cooldown 0 Set comment cooldown (0-300 seconds)
8
8
  */
9
9
 
10
- import { loadConfig, saveConfig } from "../storage/state.ts";
10
+ import { loadConfig, saveConfig } from "../server/state.ts";
11
11
 
12
12
  const args = process.argv.slice(2);
13
13
  const key = args[0];
@@ -16,7 +16,7 @@ const value = args[1];
16
16
  if (!key) {
17
17
  const cfg = loadConfig();
18
18
  console.log(`
19
- claude-buddy settings
19
+ coding-buddy settings
20
20
  ─────────────────────
21
21
  Comment cooldown: ${cfg.commentCooldown}s (0 = no throttling, default 30)
22
22
  Reaction TTL: ${cfg.reactionTTL}s (0 = permanent, default 0)
@@ -1,9 +1,9 @@
1
1
  /**
2
- * claude-buddy show — display current companion in terminal
2
+ * coding-buddy show — display current companion in terminal
3
3
  */
4
4
 
5
- import { renderBuddy, renderFace, RARITY_STARS } from "../../../core/engine.ts";
6
- import { loadCompanion, loadReaction } from "../storage/state.ts";
5
+ import { renderBuddy, renderFace, RARITY_STARS } from "../core/engine.ts"
6
+ import { loadCompanion, loadReaction } from "../server/state.ts";
7
7
 
8
8
  const BOLD = "\x1b[1m";
9
9
  const DIM = "\x1b[2m";
@@ -12,7 +12,7 @@ const NC = "\x1b[0m";
12
12
  const companion = loadCompanion();
13
13
 
14
14
  if (!companion) {
15
- console.log("No companion found. Run 'claude-buddy install' first.");
15
+ console.log("No companion found. Run 'coding-buddy install' first.");
16
16
  process.exit(1);
17
17
  }
18
18
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # claude-buddy diagnostic test status line
2
+ # coding-buddy diagnostic test status line
3
3
  # Outputs multiple padding strategies + multi-line check + width check
4
4
 
5
5
  cat > /dev/null # drain stdin
@@ -12,7 +12,7 @@ GREEN=$'\033[38;2;78;186;101m'
12
12
  BLUE=$'\033[38;2;87;105;247m'
13
13
 
14
14
  # Header
15
- echo "${DIM}--- claude-buddy statusline test ---${NC}"
15
+ echo "${DIM}--- coding-buddy statusline test ---${NC}"
16
16
 
17
17
  # Multi-line check
18
18
  echo "LINE_1_top"
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
- * claude-buddy test-statusline — temporarily install a test status line
3
+ * coding-buddy test-statusline — temporarily install a test status line
4
4
  *
5
5
  * Run: bun run test-statusline # install test
6
6
  * bun run test-statusline restore # restore original
@@ -8,15 +8,16 @@
8
8
  * The test status line outputs multiple padding strategies side-by-side
9
9
  * so you can see in actual Claude Code which one renders correctly.
10
10
  *
11
- * Your original statusLine config is backed up to <state-dir>/statusline.bak.
11
+ * Your original statusLine config is backed up to <state-dir>/statusline.bak
12
+ * (state dir resolves via server/paths.ts).
12
13
  */
13
14
 
14
15
  import { readFileSync, writeFileSync, existsSync, copyFileSync, chmodSync, mkdirSync } from "fs";
15
16
  import { join, dirname, resolve } from "path";
16
- import { getBuddyStateDir, getClaudeSettingsPath } from "../storage/paths.ts";
17
+ import { buddyStateDir, claudeSettingsPath } from "../server/path.ts";
17
18
 
18
- const SETTINGS = getClaudeSettingsPath();
19
- const STATE_DIR = getBuddyStateDir();
19
+ const SETTINGS = claudeSettingsPath();
20
+ const STATE_DIR = buddyStateDir();
20
21
  const BACKUP = join(STATE_DIR, "statusline.bak");
21
22
  const TEST_SCRIPT = join(STATE_DIR, "test-statusline.sh");
22
23
  const SOURCE_SCRIPT = resolve(import.meta.dir, "test-statusline.sh");
@@ -29,22 +30,27 @@ const BOLD = "\x1b[1m";
29
30
  const NC = "\x1b[0m";
30
31
 
31
32
  function ok(msg: string) { console.log(`${GREEN}✓${NC} ${msg}`); }
33
+ function info(msg: string) { console.log(`${CYAN}→${NC} ${msg}`); }
32
34
  function warn(msg: string) { console.log(`${YELLOW}⚠${NC} ${msg}`); }
33
35
  function err(msg: string) { console.log(`${RED}✗${NC} ${msg}`); }
34
36
 
35
37
  const action = process.argv[2] || "install";
36
38
 
39
+ // ─── Install ────────────────────────────────────────────────────────────────
40
+
37
41
  if (action === "install") {
38
- console.log(`\n${BOLD}claude-buddy test status line installer${NC}\n`);
42
+ console.log(`\n${BOLD}coding-buddy test status line installer${NC}\n`);
39
43
 
40
44
  if (!existsSync(SETTINGS)) {
41
- err(`Claude settings not found: ${SETTINGS}`);
45
+ err(`${SETTINGS} not found`);
42
46
  process.exit(1);
43
47
  }
44
48
  if (!existsSync(SOURCE_SCRIPT)) {
45
49
  err(`Source test script missing: ${SOURCE_SCRIPT}`);
46
50
  process.exit(1);
47
51
  }
52
+
53
+ // Backup
48
54
  if (existsSync(BACKUP)) {
49
55
  warn(`Backup already exists at ${BACKUP}`);
50
56
  warn("Run 'bun run test-statusline restore' first to revert");
@@ -55,10 +61,12 @@ if (action === "install") {
55
61
  copyFileSync(SETTINGS, BACKUP);
56
62
  ok(`Backed up settings to ${BACKUP}`);
57
63
 
64
+ // Copy the test script (no inline TS interpolation issues)
58
65
  copyFileSync(SOURCE_SCRIPT, TEST_SCRIPT);
59
66
  chmodSync(TEST_SCRIPT, 0o755);
60
67
  ok(`Test script copied to ${TEST_SCRIPT}`);
61
68
 
69
+ // Update settings to use test script
62
70
  const settings = JSON.parse(readFileSync(SETTINGS, "utf8"));
63
71
  settings.statusLine = {
64
72
  type: "command",
@@ -88,8 +96,10 @@ ${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━
88
96
  process.exit(0);
89
97
  }
90
98
 
99
+ // ─── Restore ────────────────────────────────────────────────────────────────
100
+
91
101
  if (action === "restore") {
92
- console.log(`\n${BOLD}claude-buddy test status line restore${NC}\n`);
102
+ console.log(`\n${BOLD}coding-buddy test status line restore${NC}\n`);
93
103
 
94
104
  if (!existsSync(BACKUP)) {
95
105
  err(`No backup found at ${BACKUP}`);
@@ -101,13 +111,13 @@ if (action === "restore") {
101
111
  ok("Original settings.json restored");
102
112
 
103
113
  const { unlinkSync } = require("fs");
104
- try { unlinkSync(BACKUP); ok("Backup file removed"); } catch {}
105
- try { unlinkSync(TEST_SCRIPT); ok("Test script removed"); } catch {}
114
+ try { unlinkSync(BACKUP); ok("Backup file removed"); } catch { /* noop */ }
115
+ try { unlinkSync(TEST_SCRIPT); ok("Test script removed"); } catch { /* noop */ }
106
116
 
107
117
  console.log(`\n${GREEN}Done.${NC} Restart Claude Code to apply.\n`);
108
118
  process.exit(0);
109
119
  }
110
120
 
111
121
  err(`Unknown action: ${action}`);
112
- console.log("Usage: bun run test-statusline [install|restore]");
122
+ console.log(`Usage: bun run test-statusline [install|restore]`);
113
123
  process.exit(1);