pi-caveman 1.0.10 → 1.0.12
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 +1 -1
- package/extensions/caveman.ts +39 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ When active, a status bar displays caveman level and an animated campfire flicke
|
|
|
82
82
|
|
|
83
83
|
## How It Works
|
|
84
84
|
|
|
85
|
-
The extension hooks `before_agent_start` to
|
|
85
|
+
The extension hooks `before_agent_start` to add caveman communication rules at the selected intensity. On Pi hosts with `systemPromptOptions.sections`, it writes a `caveman` section so later extensions can still add their own prompt sections, and removes that section when disabled. Older hosts use whole-prompt replacement, preserving ordered prompt blocks on OMP. Within a session, the active level is stored as a custom session entry and restored on resume. Across sessions, persistent config (`~/.pi/agent/caveman.json` by default, or `$XDG_CONFIG_HOME/pi/agent/caveman.json` when `XDG_CONFIG_HOME` is set; `PI_CODING_AGENT_DIR` overrides both) provides the default level and status bar preference. Auto-clarity rules tell the model to drop caveman mode for security warnings or irreversible actions.
|
|
86
86
|
|
|
87
87
|
## Warning
|
|
88
88
|
|
package/extensions/caveman.ts
CHANGED
|
@@ -212,6 +212,7 @@ export default function caveman(pi: ExtensionAPI) {
|
|
|
212
212
|
let config: CavemanConfig = { ...DEFAULT_CONFIG };
|
|
213
213
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
214
214
|
let frameIndex = 0;
|
|
215
|
+
let animationGeneration = 0;
|
|
215
216
|
let isActive = false;
|
|
216
217
|
let configLoadPromise: Promise<void> | null = null;
|
|
217
218
|
|
|
@@ -230,6 +231,7 @@ export default function caveman(pi: ExtensionAPI) {
|
|
|
230
231
|
// -- Animation helpers --
|
|
231
232
|
|
|
232
233
|
function stopAnimation() {
|
|
234
|
+
animationGeneration++;
|
|
233
235
|
if (timer) {
|
|
234
236
|
clearInterval(timer);
|
|
235
237
|
timer = null;
|
|
@@ -240,32 +242,34 @@ export default function caveman(pi: ExtensionAPI) {
|
|
|
240
242
|
function syncStatus(ctx: Pick<ExtensionContext, "ui">) {
|
|
241
243
|
stopAnimation();
|
|
242
244
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
const generation = animationGeneration;
|
|
246
|
+
const anim = level === "off" ? null : ANIMATIONS[level];
|
|
247
|
+
const renderFrame = () => {
|
|
248
|
+
if (generation !== animationGeneration) return false;
|
|
249
|
+
try {
|
|
250
|
+
if (!anim || !config.showStatus) {
|
|
251
|
+
ctx.ui.setStatus("caveman", "");
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
+
// Hosts like pi-web-ui may expose setStatus without a TUI theme.
|
|
256
|
+
const theme = ctx.ui.theme;
|
|
257
|
+
if (!theme?.fg) return false;
|
|
258
|
+
const frame = anim.frames[frameIndex % anim.frames.length]!;
|
|
259
|
+
ctx.ui.setStatus("caveman", frame + " " + theme.fg("muted", "caveman level: ") + theme.fg("text", anim.label));
|
|
260
|
+
frameIndex++;
|
|
261
|
+
return true;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
// Timer callbacks run outside Pi's event-handler error boundary.
|
|
264
|
+
stopAnimation();
|
|
265
|
+
if (!(error instanceof Error) || !error.message.includes("stale after session replacement")) throw error;
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
255
268
|
};
|
|
256
269
|
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
return;
|
|
270
|
+
if (renderFrame() && isActive && anim) {
|
|
271
|
+
timer = setInterval(renderFrame, anim.interval);
|
|
260
272
|
}
|
|
261
|
-
|
|
262
|
-
const renderFrame = () => {
|
|
263
|
-
setFrame(anim.frames[frameIndex % anim.frames.length]!);
|
|
264
|
-
frameIndex++;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
renderFrame();
|
|
268
|
-
timer = setInterval(renderFrame, anim.interval);
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
// -- Restore state on session load --
|
|
@@ -439,13 +443,25 @@ export default function caveman(pi: ExtensionAPI) {
|
|
|
439
443
|
|
|
440
444
|
pi.on("before_agent_start", async (event) => {
|
|
441
445
|
await ensureConfigLoaded();
|
|
442
|
-
|
|
446
|
+
// Use a structural check so older Pi/OMP hosts can still use the legacy path.
|
|
447
|
+
const sections = (event as { systemPromptOptions?: { sections?: Record<string, string> } })
|
|
448
|
+
.systemPromptOptions?.sections;
|
|
449
|
+
const hasSections = sections !== null && typeof sections === "object" && !Array.isArray(sections);
|
|
450
|
+
if (level === "off") {
|
|
451
|
+
if (hasSections) delete sections.caveman;
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
443
454
|
const addition =
|
|
444
455
|
level === "micro"
|
|
445
456
|
? MICRO_PROMPT
|
|
446
457
|
: level === "lite"
|
|
447
458
|
? `${INTENSITY.lite}\n\n${SAFETY}`
|
|
448
459
|
: `${BASE}\n\n${INTENSITY[level]}\n\n${SAFETY}`;
|
|
460
|
+
if (hasSections) {
|
|
461
|
+
// Returning a whole prompt freezes it before later handlers add their sections.
|
|
462
|
+
sections.caveman = addition;
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
449
465
|
return {
|
|
450
466
|
systemPrompt: appendSystemPrompt(
|
|
451
467
|
event.systemPrompt as string | string[] | null | undefined,
|
package/package.json
CHANGED