@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
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* State management — reads/writes companion data to the buddy state dir.
|
|
3
|
-
*
|
|
4
|
-
* The state dir resolves via server/paths.ts (honors CLAUDE_CONFIG_DIR).
|
|
5
|
-
* Default: ~/.claude-buddy/. With CLAUDE_CONFIG_DIR set:
|
|
6
|
-
* $CLAUDE_CONFIG_DIR/buddy-state/.
|
|
7
|
-
*
|
|
8
|
-
* Storage layout (v3 — single manifest):
|
|
9
|
-
* <state-dir>/
|
|
10
|
-
* menagerie.json <- SSOT: { active, companions: { [slot]: Companion } }
|
|
11
|
-
* reaction.$SID.json <- transient reaction state (session-scoped)
|
|
12
|
-
* status.json <- compact state for the status-line shell script
|
|
13
|
-
* config.json <- user preferences (cooldown, bubble style, etc.)
|
|
14
|
-
*
|
|
15
|
-
* Rules:
|
|
16
|
-
* - saveCompanionSlot() APPENDS only — throws if the slot already exists
|
|
17
|
-
* - saveCompanion() UPDATES the currently-active slot (rename / personality)
|
|
18
|
-
* - All manifest writes are atomic (write tmp -> rename)
|
|
19
|
-
*
|
|
20
|
-
* Combined: PR #4 menagerie + PR #6 session isolation + config
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import {
|
|
24
|
-
readFileSync,
|
|
25
|
-
writeFileSync,
|
|
26
|
-
mkdirSync,
|
|
27
|
-
existsSync,
|
|
28
|
-
readdirSync,
|
|
29
|
-
renameSync,
|
|
30
|
-
rmSync,
|
|
31
|
-
} from "fs";
|
|
32
|
-
import { join } from "path";
|
|
33
|
-
import type { Companion } from "../../../core/engine.ts";
|
|
34
|
-
import { getBuddyStateDir } from "./paths.ts";
|
|
35
|
-
|
|
36
|
-
export const STATE_DIR = getBuddyStateDir();
|
|
37
|
-
const MANIFEST_FILE = join(STATE_DIR, "menagerie.json");
|
|
38
|
-
const CONFIG_FILE = join(STATE_DIR, "config.json");
|
|
39
|
-
|
|
40
|
-
// ─── Session ID (PR #6: tmux session isolation) ─────────────────────────────
|
|
41
|
-
|
|
42
|
-
function sessionId(): string {
|
|
43
|
-
const pane = process.env.TMUX_PANE;
|
|
44
|
-
if (!pane) return "default";
|
|
45
|
-
return pane.replace(/^%/, "");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function reactionFile(): string {
|
|
49
|
-
return join(STATE_DIR, `reaction.${sessionId()}.json`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─── Manifest schema ─────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
interface Manifest {
|
|
55
|
-
active: string;
|
|
56
|
-
companions: Record<string, Companion>;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function emptyManifest(): Manifest {
|
|
60
|
-
return { active: "buddy", companions: {} };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ─── Atomic manifest I/O ─────────────────────────────────────────────────────
|
|
64
|
-
|
|
65
|
-
function loadManifest(): Manifest {
|
|
66
|
-
try {
|
|
67
|
-
const raw = readFileSync(MANIFEST_FILE, "utf8");
|
|
68
|
-
const m = JSON.parse(raw) as Manifest;
|
|
69
|
-
if (!m.companions) m.companions = {};
|
|
70
|
-
return m;
|
|
71
|
-
} catch {
|
|
72
|
-
return emptyManifest();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function saveManifest(m: Manifest): void {
|
|
77
|
-
mkdirSync(STATE_DIR, { recursive: true });
|
|
78
|
-
const tmp = MANIFEST_FILE + ".tmp";
|
|
79
|
-
writeFileSync(tmp, JSON.stringify(m, null, 2));
|
|
80
|
-
renameSync(tmp, MANIFEST_FILE); // atomic on same filesystem
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ─── Slot helpers ────────────────────────────────────────────────────────────
|
|
84
|
-
|
|
85
|
-
/** Normalise a string to a safe slot key (a-z0-9-, max 14 chars). */
|
|
86
|
-
export function slugify(name: string): string {
|
|
87
|
-
return (
|
|
88
|
-
name
|
|
89
|
-
.toLowerCase()
|
|
90
|
-
.replace(/[^a-z0-9-]/g, "-")
|
|
91
|
-
.replace(/-+/g, "-")
|
|
92
|
-
.replace(/^-|-$/g, "")
|
|
93
|
-
.slice(0, 14) || "buddy"
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Return a random fallback name whose slug is not already in the manifest.
|
|
99
|
-
* Falls back to "buddy-<random 3 digits>" if all names are taken.
|
|
100
|
-
*/
|
|
101
|
-
export function unusedName(): string {
|
|
102
|
-
const { generateFallbackName } =
|
|
103
|
-
require("../../../core/reactions.ts") as typeof import("../../../core/reactions.ts");
|
|
104
|
-
const taken = new Set(Object.keys(loadManifest().companions));
|
|
105
|
-
for (let i = 0; i < 50; i++) {
|
|
106
|
-
const n = generateFallbackName();
|
|
107
|
-
if (!taken.has(slugify(n))) return n;
|
|
108
|
-
}
|
|
109
|
-
let suffix = 0;
|
|
110
|
-
while (taken.has(`buddy-${suffix}`)) suffix++;
|
|
111
|
-
return `buddy-${suffix}`;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ─── Active slot ─────────────────────────────────────────────────────────────
|
|
115
|
-
|
|
116
|
-
export function loadActiveSlot(): string {
|
|
117
|
-
const m = loadManifest();
|
|
118
|
-
if (m.active && m.companions[m.active]) return m.active;
|
|
119
|
-
const first = Object.keys(m.companions)[0];
|
|
120
|
-
if (first) {
|
|
121
|
-
m.active = first;
|
|
122
|
-
saveManifest(m);
|
|
123
|
-
return first;
|
|
124
|
-
}
|
|
125
|
-
return "buddy";
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function saveActiveSlot(slot: string): void {
|
|
129
|
-
const m = loadManifest();
|
|
130
|
-
m.active = slot;
|
|
131
|
-
saveManifest(m);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ─── Companion slot API ───────────────────────────────────────────────────────
|
|
135
|
-
|
|
136
|
-
export function loadCompanionSlot(slot: string): Companion | null {
|
|
137
|
-
return loadManifest().companions[slot] ?? null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* APPEND a new companion to the manifest.
|
|
142
|
-
* Throws if the slot already exists — use saveCompanion() to update an existing buddy.
|
|
143
|
-
*/
|
|
144
|
-
export function saveCompanionSlot(companion: Companion, slot: string): void {
|
|
145
|
-
const m = loadManifest();
|
|
146
|
-
if (m.companions[slot]) {
|
|
147
|
-
throw new Error(`Slot "${slot}" already exists. Choose a different name.`);
|
|
148
|
-
}
|
|
149
|
-
m.companions[slot] = companion;
|
|
150
|
-
saveManifest(m);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* UPDATE an existing (possibly non-active) companion slot.
|
|
155
|
-
* Throws if the slot does not exist.
|
|
156
|
-
*/
|
|
157
|
-
export function updateCompanionSlot(slot: string, companion: Companion): void {
|
|
158
|
-
const m = loadManifest();
|
|
159
|
-
if (!m.companions[slot]) {
|
|
160
|
-
throw new Error(`Slot "${slot}" does not exist.`);
|
|
161
|
-
}
|
|
162
|
-
m.companions[slot] = companion;
|
|
163
|
-
saveManifest(m);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function deleteCompanionSlot(slot: string): void {
|
|
167
|
-
const m = loadManifest();
|
|
168
|
-
delete m.companions[slot];
|
|
169
|
-
if (m.active === slot) {
|
|
170
|
-
m.active = Object.keys(m.companions)[0] ?? "buddy";
|
|
171
|
-
}
|
|
172
|
-
saveManifest(m);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function listCompanionSlots(): Array<{
|
|
176
|
-
slot: string;
|
|
177
|
-
companion: Companion;
|
|
178
|
-
}> {
|
|
179
|
-
return Object.entries(loadManifest().companions).map(([slot, companion]) => ({
|
|
180
|
-
slot,
|
|
181
|
-
companion,
|
|
182
|
-
}));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ─── Primary companion API ────────────────────────────────────────────────────
|
|
186
|
-
|
|
187
|
-
export function loadCompanion(): Companion | null {
|
|
188
|
-
migrateIfNeeded();
|
|
189
|
-
const m = loadManifest();
|
|
190
|
-
return m.companions[m.active] ?? null;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* UPDATE the currently-active companion (rename, personality changes, etc.).
|
|
195
|
-
* This is the ONLY intentional in-place update path.
|
|
196
|
-
*/
|
|
197
|
-
export function saveCompanion(companion: Companion): void {
|
|
198
|
-
const m = loadManifest();
|
|
199
|
-
m.companions[m.active] = companion;
|
|
200
|
-
saveManifest(m);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// ─── Migration: legacy companion.json -> single manifest ────────────────────
|
|
204
|
-
|
|
205
|
-
function migrateIfNeeded(): void {
|
|
206
|
-
if (existsSync(MANIFEST_FILE)) return;
|
|
207
|
-
|
|
208
|
-
const companions: Record<string, Companion> = {};
|
|
209
|
-
let active = "buddy";
|
|
210
|
-
|
|
211
|
-
// Absorb menagerie/<slot>.json files
|
|
212
|
-
const menagerieDir = join(STATE_DIR, "menagerie");
|
|
213
|
-
if (existsSync(menagerieDir)) {
|
|
214
|
-
try {
|
|
215
|
-
for (const f of readdirSync(menagerieDir).filter((f) =>
|
|
216
|
-
f.endsWith(".json"),
|
|
217
|
-
)) {
|
|
218
|
-
const slot = f.slice(0, -5);
|
|
219
|
-
try {
|
|
220
|
-
companions[slot] = JSON.parse(
|
|
221
|
-
readFileSync(join(menagerieDir, f), "utf8"),
|
|
222
|
-
);
|
|
223
|
-
} catch {
|
|
224
|
-
/* skip malformed */
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
} catch {
|
|
228
|
-
/* noop */
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Absorb legacy companion.json
|
|
233
|
-
const legacyFile = join(STATE_DIR, "companion.json");
|
|
234
|
-
if (existsSync(legacyFile) && Object.keys(companions).length === 0) {
|
|
235
|
-
try {
|
|
236
|
-
const c: Companion = JSON.parse(readFileSync(legacyFile, "utf8"));
|
|
237
|
-
const slot = slugify(c.name);
|
|
238
|
-
companions[slot] = c;
|
|
239
|
-
active = slot;
|
|
240
|
-
} catch {
|
|
241
|
-
/* noop */
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Read active pointer if it exists
|
|
246
|
-
const activeFile = join(STATE_DIR, "active");
|
|
247
|
-
if (existsSync(activeFile)) {
|
|
248
|
-
try {
|
|
249
|
-
const a = readFileSync(activeFile, "utf8").trim();
|
|
250
|
-
if (a && companions[a]) active = a;
|
|
251
|
-
} catch {
|
|
252
|
-
/* noop */
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (Object.keys(companions).length > 0) {
|
|
257
|
-
active = active && companions[active] ? active : Object.keys(companions)[0];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
saveManifest({ active, companions });
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// ─── Reaction state (session-scoped for tmux isolation) ──────────────────────
|
|
264
|
-
|
|
265
|
-
export interface ReactionState {
|
|
266
|
-
reaction: string;
|
|
267
|
-
timestamp: number;
|
|
268
|
-
reason: string;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export function loadReaction(): ReactionState | null {
|
|
272
|
-
try {
|
|
273
|
-
const data: ReactionState = JSON.parse(readFileSync(reactionFile(), "utf8"));
|
|
274
|
-
const { reactionTTL } = loadConfig();
|
|
275
|
-
if (reactionTTL > 0 && Date.now() - data.timestamp > reactionTTL * 1000) return null;
|
|
276
|
-
return data;
|
|
277
|
-
} catch {
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function saveReaction(reaction: string, reason: string): void {
|
|
283
|
-
mkdirSync(STATE_DIR, { recursive: true });
|
|
284
|
-
const state: ReactionState = { reaction, timestamp: Date.now(), reason };
|
|
285
|
-
writeFileSync(reactionFile(), JSON.stringify(state));
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// ─── Config persistence (PR #6: tmux popup settings) ─────────────────────────
|
|
289
|
-
|
|
290
|
-
export interface BuddyConfig {
|
|
291
|
-
commentCooldown: number;
|
|
292
|
-
reactionTTL: number;
|
|
293
|
-
bubbleStyle: "classic" | "round";
|
|
294
|
-
bubblePosition: "top" | "left";
|
|
295
|
-
showRarity: boolean;
|
|
296
|
-
statusLineEnabled: boolean;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const DEFAULT_CONFIG: BuddyConfig = {
|
|
300
|
-
commentCooldown: 30,
|
|
301
|
-
reactionTTL: 0,
|
|
302
|
-
bubbleStyle: "classic",
|
|
303
|
-
bubblePosition: "top",
|
|
304
|
-
showRarity: true,
|
|
305
|
-
statusLineEnabled: false,
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
export function loadConfig(): BuddyConfig {
|
|
309
|
-
try {
|
|
310
|
-
const data = JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
|
|
311
|
-
return { ...DEFAULT_CONFIG, ...data };
|
|
312
|
-
} catch {
|
|
313
|
-
return { ...DEFAULT_CONFIG };
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export function saveConfig(config: Partial<BuddyConfig>): BuddyConfig {
|
|
318
|
-
mkdirSync(STATE_DIR, { recursive: true });
|
|
319
|
-
const current = loadConfig();
|
|
320
|
-
const merged = { ...current, ...config };
|
|
321
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
|
|
322
|
-
return merged;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// ─── Status line state (compact JSON for the shell script) ───────────────────
|
|
326
|
-
|
|
327
|
-
export interface StatusState {
|
|
328
|
-
name: string;
|
|
329
|
-
species: string;
|
|
330
|
-
rarity: string;
|
|
331
|
-
stars: string;
|
|
332
|
-
face: string;
|
|
333
|
-
eye: string;
|
|
334
|
-
shiny: boolean;
|
|
335
|
-
hat: string;
|
|
336
|
-
reaction: string;
|
|
337
|
-
muted: boolean;
|
|
338
|
-
achievement: string;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export function writeStatusState(
|
|
342
|
-
companion: Companion,
|
|
343
|
-
reaction?: string,
|
|
344
|
-
muted?: boolean,
|
|
345
|
-
achievement?: string,
|
|
346
|
-
): void {
|
|
347
|
-
mkdirSync(STATE_DIR, { recursive: true });
|
|
348
|
-
const { renderFace, RARITY_STARS } =
|
|
349
|
-
require("../../../core/engine.ts") as typeof import("../../../core/engine.ts");
|
|
350
|
-
const state: StatusState = {
|
|
351
|
-
name: companion.name,
|
|
352
|
-
species: companion.bones.species,
|
|
353
|
-
rarity: companion.bones.rarity,
|
|
354
|
-
stars: RARITY_STARS[companion.bones.rarity],
|
|
355
|
-
face: renderFace(companion.bones.species, companion.bones.eye),
|
|
356
|
-
eye: companion.bones.eye,
|
|
357
|
-
shiny: companion.bones.shiny,
|
|
358
|
-
hat: companion.bones.hat,
|
|
359
|
-
reaction: reaction ?? "",
|
|
360
|
-
muted: muted ?? false,
|
|
361
|
-
achievement: achievement ?? "",
|
|
362
|
-
};
|
|
363
|
-
writeFileSync(join(STATE_DIR, "status.json"), JSON.stringify(state));
|
|
364
|
-
}
|
|
365
|
-
|
package/adapters/pi/README.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# Pi adapter
|
|
2
|
-
|
|
3
|
-
Native pi extension for `coding-buddy`.
|
|
4
|
-
|
|
5
|
-
## Load locally during development
|
|
6
|
-
|
|
7
|
-
Project-local in pi:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
mkdir -p .pi/extensions
|
|
11
|
-
ln -sf ../../adapters/pi/index.ts .pi/extensions/coding-buddy.ts
|
|
12
|
-
pi
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Or run directly:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
pi -e ./adapters/pi/index.ts
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Install as a pi package
|
|
22
|
-
|
|
23
|
-
Because the root `package.json` now declares:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"pi": {
|
|
28
|
-
"extensions": ["./adapters/pi/index.ts"]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
pi can install this repo/package directly:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
pi install /absolute/path/to/claude-buddy
|
|
37
|
-
# or
|
|
38
|
-
pi install npm:@ramarivera/coding-buddy
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## What the extension provides
|
|
42
|
-
|
|
43
|
-
- `/buddy`
|
|
44
|
-
- `/buddy pet`
|
|
45
|
-
- `/buddy stats`
|
|
46
|
-
- `/buddy rename <name>`
|
|
47
|
-
- `/buddy personality <text>`
|
|
48
|
-
- `/buddy off` / `/buddy on`
|
|
49
|
-
- `/buddy save [slot]`
|
|
50
|
-
- `/buddy summon [slot]`
|
|
51
|
-
- `/buddy list`
|
|
52
|
-
- `/buddy dismiss <slot>`
|
|
53
|
-
- `/buddy achievements`
|
|
54
|
-
|
|
55
|
-
Passive behavior:
|
|
56
|
-
|
|
57
|
-
- initializes on `session_start`
|
|
58
|
-
- reacts to buddy-name mentions on `input`
|
|
59
|
-
- reacts to some tool failures and large diffs on `tool_result`
|
|
60
|
-
- refreshes widget/status on `turn_end`
|
|
61
|
-
|
|
62
|
-
Persistence lives under:
|
|
63
|
-
|
|
64
|
-
- `~/.pi/agent/buddy/`
|
|
65
|
-
|
|
66
|
-
## Config
|
|
67
|
-
|
|
68
|
-
Buddy config is stored in:
|
|
69
|
-
|
|
70
|
-
- `~/.pi/agent/buddy/config.json`
|
|
71
|
-
|
|
72
|
-
You can optionally force the end-of-turn buddy comment generator to use a different model than the main pi session:
|
|
73
|
-
|
|
74
|
-
```json
|
|
75
|
-
{
|
|
76
|
-
"turnCommentModel": {
|
|
77
|
-
"provider": "google",
|
|
78
|
-
"model": "gemini-2.5-flash"
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
If `turnCommentModel` is unset, or the configured model cannot be found, buddy falls back to the active session model.
|
package/adapters/pi/tools.ts
DELETED
package/server/engine.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../core/engine.ts";
|
package/server/reactions.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../core/reactions.ts";
|