@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.
- package/{adapters/claude/plugin → .claude-plugin}/marketplace.json +11 -6
- package/{adapters/claude/plugin → .claude-plugin}/plugin.json +7 -3
- package/LICENSE +1 -1
- package/README.md +88 -37
- package/adapters/omp/commands.ts +201 -0
- package/adapters/omp/context.ts +22 -0
- package/adapters/omp/events.ts +551 -0
- package/adapters/omp/identity.ts +10 -0
- package/adapters/omp/index.ts +39 -0
- package/adapters/omp/logger.ts +52 -0
- package/adapters/omp/prompt.ts +60 -0
- package/adapters/omp/renderers.ts +73 -0
- package/adapters/omp/storage.ts +25 -0
- package/adapters/omp/ui.ts +85 -0
- package/adapters/pi/commands.ts +64 -37
- package/adapters/pi/events.ts +147 -72
- package/adapters/pi/index.ts +9 -4
- package/adapters/pi/storage.ts +14 -285
- package/adapters/pi/ui.ts +56 -5
- package/adapters/shared/file-storage.ts +526 -0
- package/{adapters/claude/install → cli}/backup.ts +130 -33
- package/cli/buddy-shell.ts +1 -1
- package/{adapters/claude/install → cli}/disable.ts +19 -32
- package/cli/doctor.ts +231 -0
- package/{adapters/claude/install → cli}/hunt.ts +7 -9
- package/cli/index.ts +30 -26
- package/{adapters/claude/install → cli}/install.ts +65 -83
- package/{adapters/claude/install → cli}/pick.ts +111 -50
- package/{adapters/claude/install → cli}/settings.ts +2 -2
- package/{adapters/claude/install → cli}/show.ts +4 -4
- package/{adapters/claude/install → cli}/test-statusline.sh +2 -2
- package/{adapters/claude/install → cli}/test-statusline.ts +21 -11
- package/cli/tui.tsx +106 -17
- package/{adapters/claude/install → cli}/uninstall.ts +40 -47
- package/cli/upgrade.ts +2 -2
- package/cli/validate-species.ts +209 -0
- package/cli/verify.ts +3 -3
- package/core/achievements.ts +12 -20
- package/core/art-data.ts +26 -0
- package/core/command-service.ts +99 -97
- package/core/engine.ts +83 -1
- package/core/ports.ts +10 -0
- package/core/reactions.ts +533 -95
- package/core/slot-slug.ts +22 -0
- package/{adapters/claude/hooks → hooks}/buddy-comment.sh +19 -1
- package/hooks/file-type-react.sh +401 -0
- package/hooks/hooks.json +52 -0
- package/hooks/mood-react.sh +208 -0
- package/{adapters/claude/hooks → hooks}/name-react.sh +1 -1
- package/hooks/react.sh +1368 -0
- package/hooks/suggest.sh +55 -0
- package/package.json +70 -31
- package/scripts/gen-emoji-widths.ts +34 -0
- package/scripts/paths.sh +17 -1
- package/scripts/postinstall.cjs +42 -0
- package/scripts/snapshot-statusline.sh +54 -0
- package/server/achievements.ts +1419 -15
- package/server/art.ts +450 -1
- package/server/award-xp.ts +48 -0
- package/server/check-suggestions.ts +102 -0
- package/server/consolidate.ts +33 -0
- package/{adapters/claude/server → server}/index.ts +556 -95
- package/server/mcp-launcher.sh +16 -6
- package/server/memory.ts +404 -0
- package/server/mood.ts +254 -0
- package/server/path.ts +70 -18
- package/server/shift-mood.ts +43 -0
- package/server/state.ts +540 -3
- package/server/suggestions.ts +335 -0
- package/server/theme.ts +53 -0
- package/server/xp.ts +435 -0
- package/{adapters/claude/skills → skills}/buddy/SKILL.md +36 -7
- package/statusline/buddy-status.sh +397 -0
- package/statusline/combined-status.sh +134 -0
- package/statusline/emoji-widths.data +4 -0
- package/adapters/claude/hooks/hooks.json +0 -35
- package/adapters/claude/hooks/react.sh +0 -207
- package/adapters/claude/install/doctor.ts +0 -172
- package/adapters/claude/rendering/art.ts +0 -264
- package/adapters/claude/server/instructions.ts +0 -24
- package/adapters/claude/server/path.ts +0 -12
- package/adapters/claude/server/resources.ts +0 -38
- package/adapters/claude/statusline/buddy-status.sh +0 -408
- package/adapters/claude/storage/achievements.ts +0 -253
- package/adapters/claude/storage/identity.ts +0 -13
- package/adapters/claude/storage/paths.ts +0 -33
- package/adapters/claude/storage/settings.ts +0 -91
- package/adapters/claude/storage/state.ts +0 -365
- package/adapters/pi/README.md +0 -83
- package/adapters/pi/tools.ts +0 -6
- package/server/engine.ts +0 -1
- 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 "../
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} from "
|
|
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
|
|
83
|
-
const RA_OPTS
|
|
84
|
-
const SH_OPTS
|
|
85
|
-
const ST_OPTS
|
|
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:
|
|
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:
|
|
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"
|
|
265
|
-
: s.mode === "criteria"
|
|
266
|
-
: s.mode === "
|
|
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 = `
|
|
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"
|
|
288
|
-
s.mode === "criteria"
|
|
289
|
-
s.mode === "
|
|
290
|
-
s.mode === "
|
|
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
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
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
|
|
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 (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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)
|
|
332
|
-
if (wantRa !== null && bones.rarity !== wantRa)
|
|
333
|
-
if (wantShiny !== null && bones.shiny !== wantShiny)
|
|
334
|
-
if (wantPeak !== null && bones.peak !== wantPeak)
|
|
335
|
-
if (wantDump !== null && bones.dump !== wantDump)
|
|
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:
|
|
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.
|
|
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 "../
|
|
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
|
-
|
|
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
|
-
*
|
|
2
|
+
* coding-buddy show — display current companion in terminal
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { renderBuddy, renderFace, RARITY_STARS } from "
|
|
6
|
-
import { loadCompanion, loadReaction } from "../
|
|
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 '
|
|
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
|
-
#
|
|
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}---
|
|
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
|
-
*
|
|
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 {
|
|
17
|
+
import { buddyStateDir, claudeSettingsPath } from "../server/path.ts";
|
|
17
18
|
|
|
18
|
-
const SETTINGS =
|
|
19
|
-
const STATE_DIR =
|
|
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}
|
|
42
|
+
console.log(`\n${BOLD}coding-buddy test status line installer${NC}\n`);
|
|
39
43
|
|
|
40
44
|
if (!existsSync(SETTINGS)) {
|
|
41
|
-
err(
|
|
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}
|
|
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(
|
|
122
|
+
console.log(`Usage: bun run test-statusline [install|restore]`);
|
|
113
123
|
process.exit(1);
|