@fyeeme/pi-peon-ping 1.1.0 → 1.1.2
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/CHANGELOG.md +15 -0
- package/README.md +2 -2
- package/index.ts +72 -45
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.1.2] - 2026-09-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- peon.sh discovery (including the up-to-3s `brew --prefix` probe) no longer runs at extension load time; it is deferred to the first session event per the extensions doc's factory rule.
|
|
10
|
+
- `PermissionRequest` (input.required) now fires from `ui_prompt_start` — any blocking `ctx.ui` dialog — instead of sniffing the omp-only `ask_user_question` tool name, which does not exist in pi.
|
|
11
|
+
- Tab-title project name and event payloads use `ctx.cwd` instead of a stale factory-time `process.cwd()`.
|
|
12
|
+
|
|
13
|
+
## [1.1.1] - 2026-08-08
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Tab 标题改用 provided API:删除手写 ANSI `setTabTitle`(`process.stdout.write(\x1b]0;...\x07)`),四处调用点(`session_start`/`before_agent_start`/`agent_settled`/`tool_result`,均在 `ctx.hasUI` 守卫下)改为 `ctx.ui.setTitle(...)`——mode 感知,print/json 模式自动 no-op,不再向 stdout 写裸 ANSI。
|
|
18
|
+
- `Stop` 事件映射从 `agent_end` 改为 `agent_settled`(与 ExtensionAPI 实际事件名一致)。
|
|
19
|
+
|
|
5
20
|
## [1.1.0] - 2026-07-26
|
|
6
21
|
|
|
7
22
|
### Added
|
package/README.md
CHANGED
|
@@ -97,9 +97,9 @@ pi-peon-ping auto-discovers the installed `peon.sh` with the following priority
|
|
|
97
97
|
|
|
98
98
|
When a `.ps1` file is found, it is automatically run with `powershell` instead of `bash`.
|
|
99
99
|
|
|
100
|
-
### peon-ping
|
|
100
|
+
### peon-ping configuration
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
All peon-ping feature configuration is done through the `peon` CLI:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
105
|
peon packs use glados # Switch sound pack
|
package/index.ts
CHANGED
|
@@ -14,8 +14,13 @@
|
|
|
14
14
|
* Event mapping (pi ExtensionAPI → peon.sh hook_event_name):
|
|
15
15
|
* session_start → SessionStart
|
|
16
16
|
* turn_start → UserPromptSubmit
|
|
17
|
-
*
|
|
17
|
+
* agent_settled → Stop
|
|
18
18
|
* tool_result (event.isError === true) → PostToolUseFailure
|
|
19
|
+
* ui_prompt_start → PermissionRequest (input.required:
|
|
20
|
+
* any blocking ctx.ui dialog —
|
|
21
|
+
* replaces omp's ask_user_question
|
|
22
|
+
* tool_call sniff, which doesn't
|
|
23
|
+
* exist in pi)
|
|
19
24
|
* session_shutdown → SessionEnd
|
|
20
25
|
*
|
|
21
26
|
* peon.sh discovery (first match wins):
|
|
@@ -131,13 +136,9 @@ export function resolveShellAndScript(
|
|
|
131
136
|
}
|
|
132
137
|
|
|
133
138
|
// ============================================================================
|
|
134
|
-
// Terminal tab title
|
|
139
|
+
// Terminal tab title (via pi's mode-aware ctx.ui.setTitle)
|
|
135
140
|
// ============================================================================
|
|
136
141
|
|
|
137
|
-
export function setTabTitle(title: string): void {
|
|
138
|
-
process.stdout.write(`\x1b]0;${title}\x07`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
142
|
// ============================================================================
|
|
142
143
|
// Session ID helpers
|
|
143
144
|
// ============================================================================
|
|
@@ -301,18 +302,23 @@ export async function execPeonCli(
|
|
|
301
302
|
// ============================================================================
|
|
302
303
|
|
|
303
304
|
export default function peonPingExtension(pi: ExtensionAPI): void {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
305
|
+
// Doc (Long-lived resources): extension factories may run in invocations
|
|
306
|
+
// that never start a session — discovery (which may execFileSync `brew`,
|
|
307
|
+
// up to 3s) must not run here. Resolve lazily on first session_start and
|
|
308
|
+
// memoize per extension instance.
|
|
309
|
+
let peonPath: string | null | undefined;
|
|
310
|
+
const resolvePeon = (): string | null => {
|
|
311
|
+
if (peonPath === undefined) {
|
|
312
|
+
peonPath = findPeonSh();
|
|
313
|
+
if (!peonPath) {
|
|
314
|
+
console.warn("[pi-peon-ping] peon.sh not found. Install peon-ping first:");
|
|
315
|
+
console.warn(" brew install PeonPing/tap/peon-ping");
|
|
316
|
+
console.warn(" # or: curl -fsSL peonping.com/install | bash");
|
|
317
|
+
console.warn(" # or: set PEON_SH=/path/to/peon.sh");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return peonPath;
|
|
321
|
+
};
|
|
316
322
|
|
|
317
323
|
// -----------------------------------------------------------------------
|
|
318
324
|
// Lifecycle event forwarding (respect peon-ping category toggles)
|
|
@@ -321,65 +327,84 @@ export default function peonPingExtension(pi: ExtensionAPI): void {
|
|
|
321
327
|
// -----------------------------------------------------------------------
|
|
322
328
|
|
|
323
329
|
pi.on("session_start", async (_event, ctx) => {
|
|
324
|
-
const
|
|
330
|
+
const peon = resolvePeon();
|
|
331
|
+
if (!peon) return;
|
|
332
|
+
const config = readPeonConfig(peon);
|
|
325
333
|
const sessionId = getSessionId(ctx);
|
|
326
|
-
|
|
327
|
-
|
|
334
|
+
const projectName = basename(ctx.cwd) || "pi";
|
|
335
|
+
if (ctx.hasUI) ctx.ui.setTitle(`● ${projectName}: ready`);
|
|
336
|
+
firePeon(peon, "SessionStart", ctx.cwd, sessionId, config);
|
|
328
337
|
});
|
|
329
338
|
|
|
330
339
|
pi.on("before_agent_start", async (_event, ctx) => {
|
|
331
|
-
const
|
|
340
|
+
const peon = resolvePeon();
|
|
341
|
+
if (!peon) return;
|
|
342
|
+
const config = readPeonConfig(peon);
|
|
332
343
|
const sessionId = getSessionId(ctx);
|
|
333
|
-
|
|
334
|
-
|
|
344
|
+
const projectName = basename(ctx.cwd) || "pi";
|
|
345
|
+
if (ctx.hasUI) ctx.ui.setTitle(`● ${projectName}: working...`);
|
|
346
|
+
firePeon(peon, "UserPromptSubmit", ctx.cwd, sessionId, config);
|
|
335
347
|
});
|
|
336
348
|
|
|
337
349
|
pi.on("session_before_compact", async (_event, ctx) => {
|
|
338
|
-
const
|
|
350
|
+
const peon = resolvePeon();
|
|
351
|
+
if (!peon) return;
|
|
352
|
+
const config = readPeonConfig(peon);
|
|
339
353
|
const sessionId = getSessionId(ctx);
|
|
340
|
-
firePeon(
|
|
354
|
+
firePeon(peon, "PreCompact", ctx.cwd, sessionId, config);
|
|
341
355
|
});
|
|
342
356
|
|
|
343
|
-
pi.on("
|
|
344
|
-
const
|
|
357
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
358
|
+
const peon = resolvePeon();
|
|
359
|
+
if (!peon) return;
|
|
360
|
+
const config = readPeonConfig(peon);
|
|
345
361
|
const sessionId = getSessionId(ctx);
|
|
346
|
-
|
|
347
|
-
|
|
362
|
+
const projectName = basename(ctx.cwd) || "pi";
|
|
363
|
+
if (ctx.hasUI) ctx.ui.setTitle(`✓ ${projectName}: done`);
|
|
364
|
+
firePeon(peon, "Stop", ctx.cwd, sessionId, config);
|
|
348
365
|
});
|
|
349
366
|
|
|
350
367
|
pi.on("tool_result", async (event, ctx) => {
|
|
351
368
|
if (!event.isError) return;
|
|
352
|
-
const
|
|
369
|
+
const peon = resolvePeon();
|
|
370
|
+
if (!peon) return;
|
|
371
|
+
const config = readPeonConfig(peon);
|
|
353
372
|
const sessionId = getSessionId(ctx);
|
|
354
|
-
|
|
355
|
-
|
|
373
|
+
const projectName = basename(ctx.cwd) || "pi";
|
|
374
|
+
if (ctx.hasUI) ctx.ui.setTitle(`✗ ${projectName}: error`);
|
|
375
|
+
firePeon(peon, "PostToolUseFailure", ctx.cwd, sessionId, config);
|
|
356
376
|
});
|
|
357
377
|
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
378
|
+
// pi is asking the user something (any blocking ctx.ui dialog: select /
|
|
379
|
+
// confirm / input / editor / custom — ask_user, permission gates, …) →
|
|
380
|
+
// peon-ping "input.required" category. ui_prompt_start fires for every
|
|
381
|
+
// such span, so no per-tool sniffing is needed.
|
|
382
|
+
pi.on("ui_prompt_start", async (_event, ctx) => {
|
|
383
|
+
const peon = resolvePeon();
|
|
384
|
+
if (!peon) return;
|
|
385
|
+
const config = readPeonConfig(peon);
|
|
363
386
|
const sessionId = getSessionId(ctx);
|
|
364
|
-
firePeon(
|
|
387
|
+
firePeon(peon, "PermissionRequest", ctx.cwd, sessionId, config);
|
|
365
388
|
});
|
|
366
389
|
|
|
367
390
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
368
|
-
const
|
|
391
|
+
const peon = resolvePeon();
|
|
392
|
+
if (!peon) return;
|
|
393
|
+
const config = readPeonConfig(peon);
|
|
369
394
|
const sessionId = getSessionId(ctx);
|
|
370
|
-
firePeon(
|
|
395
|
+
firePeon(peon, "SessionEnd", ctx.cwd, sessionId, config);
|
|
371
396
|
});
|
|
372
397
|
|
|
373
398
|
// -----------------------------------------------------------------------
|
|
374
399
|
// Commands
|
|
375
400
|
// -----------------------------------------------------------------------
|
|
376
401
|
|
|
377
|
-
if (!cliPath) return;
|
|
378
|
-
|
|
379
402
|
pi.registerCommand("peon-ping-toggle", {
|
|
380
403
|
description: "Toggle peon-ping mute on/off",
|
|
381
404
|
handler: async (_args, ctx) => {
|
|
382
|
-
const
|
|
405
|
+
const cli = findPeonCli(resolvePeon());
|
|
406
|
+
if (!cli) return;
|
|
407
|
+
const result = await execPeonCli(cli, ["toggle"]);
|
|
383
408
|
if (result.exitCode !== 0) {
|
|
384
409
|
ctx.ui.notify(result.stdout || "toggle failed", "error");
|
|
385
410
|
} else {
|
|
@@ -391,12 +416,14 @@ export default function peonPingExtension(pi: ExtensionAPI): void {
|
|
|
391
416
|
pi.registerCommand("peon-ping-use", {
|
|
392
417
|
description: "Switch sound pack: /peon-ping-use <name>",
|
|
393
418
|
handler: async (args, ctx) => {
|
|
419
|
+
const cli = findPeonCli(resolvePeon());
|
|
420
|
+
if (!cli) return;
|
|
394
421
|
const name = args.trim();
|
|
395
422
|
if (!name) {
|
|
396
423
|
ctx.ui.notify("Usage: /peon-ping-use <pack-name>", "warning");
|
|
397
424
|
return;
|
|
398
425
|
}
|
|
399
|
-
const result = await execPeonCli(
|
|
426
|
+
const result = await execPeonCli(cli, ["packs", "use", "--install", name]);
|
|
400
427
|
if (result.exitCode !== 0) {
|
|
401
428
|
ctx.ui.notify(result.stdout || `Failed to switch to ${name}`, "error");
|
|
402
429
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fyeeme/pi-peon-ping",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "peon-ping adapter for pi — routes lifecycle events through peon.sh for sound packs, notifications, and trainer reminders.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"typecheck": "tsc"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
47
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
50
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
51
51
|
"@types/node": "22.19.19",
|
|
52
52
|
"typescript": "5.9.3"
|
|
53
53
|
}
|