@fyeeme/pi-peon-ping 1.0.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/index.ts +234 -0
- package/package.json +54 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.0.0] - 2025-07-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Initial release of pi-peon-ping
|
|
8
|
+
- Route pi lifecycle events through peon.sh:
|
|
9
|
+
- `session_start` → `SessionStart`
|
|
10
|
+
- `turn_start` → `UserPromptSubmit`
|
|
11
|
+
- `turn_end` → `Stop`
|
|
12
|
+
- `tool_result` (isError) → `PostToolUseFailure`
|
|
13
|
+
- `session_shutdown` → `SessionEnd`
|
|
14
|
+
- Terminal tab title updates with visual status indicators
|
|
15
|
+
- Auto-discovery of peon.sh at standard install paths
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 fyeeme
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# pi-peon-ping
|
|
2
|
+
|
|
3
|
+
peon-ping adapter for [pi](https://github.com/earendil-works/pi-coding-agent). Routes pi lifecycle events through `peon.sh` for sound packs, desktop notifications, and trainer reminders.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Sound packs** — Warcraft, StarCraft, Portal, Red Alert, and 160+ game character voice packs
|
|
8
|
+
- **Desktop notifications** — overlay banners when the terminal is not focused
|
|
9
|
+
- **Trainer reminders** — Pavel-style daily exercise nagging
|
|
10
|
+
- **SSH/devcontainer relay** — sounds play on your local machine, not the remote
|
|
11
|
+
- **Mobile notifications** — push to your phone via ntfy, Pushover, or Telegram
|
|
12
|
+
- **Tab title updates** — `● project: working...` / `✓ project: done` / `✗ project: error`
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Install [peon-ping](https://github.com/PeonPing/peon-ping) first:
|
|
17
|
+
|
|
18
|
+
**Option 1: Homebrew**
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
brew install PeonPing/tap/peon-ping
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Option 2: Installer script (macOS, Linux, WSL2)**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
curl -fsSL https://raw.githubusercontent.com/PeonPing/peon-ping/main/install.sh | bash
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### As a pi package
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pi install @fyeeme/pi-peon-ping
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Manual (development)
|
|
39
|
+
|
|
40
|
+
Copy `index.ts` to `~/.pi/agent/extensions/pi-peon-ping/` (global) or `.pi/extensions/pi-peon-ping/` (project-local), then restart pi.
|
|
41
|
+
|
|
42
|
+
### From the monorepo
|
|
43
|
+
|
|
44
|
+
This package lives at `packages/extensions/pi-peon-ping/`. To use it locally, symlink or copy the `index.ts` to your extensions directory:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ln -s $(pwd)/packages/extensions/pi-peon-ping ~/.pi/agent/extensions/pi-peon-ping
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Event Mapping
|
|
51
|
+
|
|
52
|
+
| pi event | peon-ping event | Occurs when |
|
|
53
|
+
|------------------------------|------------------------|---------------------------------|
|
|
54
|
+
| `session_start` | `SessionStart` | Pi starts or resumes a session |
|
|
55
|
+
| `turn_start` | `UserPromptSubmit` | You submit a prompt |
|
|
56
|
+
| `turn_end` | `Stop` | Agent finishes responding |
|
|
57
|
+
| `tool_result` (isError) | `PostToolUseFailure` | A tool call fails |
|
|
58
|
+
| `session_shutdown` | `SessionEnd` | Session ends |
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
### Environment variable
|
|
63
|
+
|
|
64
|
+
| Variable | Description |
|
|
65
|
+
|----------|-------------|
|
|
66
|
+
| `PEON_SH` | Absolute path to `peon.sh` / `peon.ps1`. Overrides all automatic discovery. |
|
|
67
|
+
|
|
68
|
+
### peon.sh Discovery
|
|
69
|
+
|
|
70
|
+
pi-peon-ping 自动查找已安装的 `peon.sh`,优先级如下(高 → 低):
|
|
71
|
+
|
|
72
|
+
| 优先级 | 来源 | 路径 |
|
|
73
|
+
|--------|------|------|
|
|
74
|
+
| 1 | `$PEON_SH` 环境变量 | 用户指定 |
|
|
75
|
+
| 2 | Homebrew (macOS) | `$(brew --prefix peon-ping)/libexec/peon.sh` |
|
|
76
|
+
| 3 | curl 安装 (Linux/macOS) | `~/.claude/hooks/peon-ping/peon.sh` |
|
|
77
|
+
| 4 | `--openpeon` 模式 | `~/.openpeon/hooks/peon-ping/peon.sh` |
|
|
78
|
+
| 5 | OpenClaw 安装 | `~/.openclaw/hooks/peon-ping/peon.sh` |
|
|
79
|
+
| 6 | Windows/Git Bash WSL2 回退 | `~/.claude/hooks/peon-ping/peon.ps1` |
|
|
80
|
+
|
|
81
|
+
当找到 `.ps1` 文件时,自动使用 `powershell` 而非 `bash` 执行。
|
|
82
|
+
|
|
83
|
+
### peon-ping 配置
|
|
84
|
+
|
|
85
|
+
所有 peon-ping 的功能配置通过 `peon` CLI 进行:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
peon packs use glados # Switch sound pack
|
|
89
|
+
peon packs install --all # Install all packs
|
|
90
|
+
peon trainer on # Enable trainer mode
|
|
91
|
+
peon notifications off # Mute popups but keep sounds
|
|
92
|
+
peon mobile ntfy my-topic # Push notifications to phone
|
|
93
|
+
peon ssh-audio relay # Route audio for remote sessions
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Uninstall
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
rm -rf ~/.pi/agent/extensions/pi-peon-ping
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## How It Works
|
|
103
|
+
|
|
104
|
+
This is a thin adapter — it does not play sounds or send notifications directly. Instead, it finds `peon.sh` (from the peon-ping install) and spawns it with a JSON payload on each lifecycle event. `peon.sh` handles all sound selection, playback, notifications, and trainer logic.
|
|
105
|
+
|
|
106
|
+
The tab title is updated to reflect current agent state: `● working...` during a turn, `✓ done` on completion, `✗ error` on tool failures.
|
|
107
|
+
|
|
108
|
+
## Credits
|
|
109
|
+
|
|
110
|
+
Based on the [oh-my-pi (omp) adapter](https://github.com/PeonPing/peon-ping/tree/main/adapters/omp) from the peon-ping project. Sound packs by [OpenPeon](https://openpeon.com/).
|
package/index.ts
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-peon-ping — peon-ping adapter for pi
|
|
3
|
+
*
|
|
4
|
+
* Routes pi ExtensionAPI lifecycle events through peon.sh, giving pi users
|
|
5
|
+
* access to ALL peon-ping features:
|
|
6
|
+
* - Sound packs & rotation (Warcraft, StarCraft, Portal, etc.)
|
|
7
|
+
* - Desktop notifications
|
|
8
|
+
* - Trainer reminders (pushups, squats, etc.)
|
|
9
|
+
* - Spam detection
|
|
10
|
+
* - SSH/devcontainer relay
|
|
11
|
+
* - All config options via `peon` CLI
|
|
12
|
+
* - Tab title updates
|
|
13
|
+
*
|
|
14
|
+
* Event mapping (pi ExtensionAPI → peon.sh hook_event_name):
|
|
15
|
+
* session_start → SessionStart
|
|
16
|
+
* turn_start → UserPromptSubmit
|
|
17
|
+
* turn_end → Stop
|
|
18
|
+
* tool_result (event.isError === true) → PostToolUseFailure
|
|
19
|
+
* session_shutdown → SessionEnd
|
|
20
|
+
*
|
|
21
|
+
* peon.sh discovery (first match wins):
|
|
22
|
+
* 1. $PEON_SH env var (explicit override)
|
|
23
|
+
* 2. brew --prefix peon-ping (macOS Homebrew)
|
|
24
|
+
* 3. ~/.claude/hooks/peon-ping/peon.sh (curl installer, Linux/macOS)
|
|
25
|
+
* 4. ~/.openpeon/hooks/peon-ping/peon.sh (tool-agnostic install)
|
|
26
|
+
* 5. ~/.openclaw/hooks/peon-ping/peon.sh (OpenClaw install)
|
|
27
|
+
* 6. ~/.claude/hooks/peon-ping/peon.ps1 (Windows/Git Bash WSL2 fallback)
|
|
28
|
+
*
|
|
29
|
+
* Requires peon-ping installed:
|
|
30
|
+
* brew install PeonPing/tap/peon-ping
|
|
31
|
+
* # or: curl -fsSL peonping.com/install | bash
|
|
32
|
+
*
|
|
33
|
+
* Based on the oh-my-pi (omp) adapter from:
|
|
34
|
+
* https://github.com/PeonPing/peon-ping/tree/main/adapters/omp
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { spawn, execFileSync } from "node:child_process";
|
|
38
|
+
import { existsSync } from "node:fs";
|
|
39
|
+
import { homedir, platform } from "node:os";
|
|
40
|
+
import { basename, join } from "node:path";
|
|
41
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Constants
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
/** Template paths for peon.sh discovery. $HOME is resolved at runtime. */
|
|
48
|
+
export const PEON_SH_TEMPLATES = [
|
|
49
|
+
// Homebrew (macOS)
|
|
50
|
+
"$(brew --prefix peon-ping)/libexec/peon.sh",
|
|
51
|
+
// curl installer default (Linux/macOS)
|
|
52
|
+
"$HOME/.claude/hooks/peon-ping/peon.sh",
|
|
53
|
+
// --openpeon mode (tool-agnostic root)
|
|
54
|
+
"$HOME/.openpeon/hooks/peon-ping/peon.sh",
|
|
55
|
+
// OpenClaw install
|
|
56
|
+
"$HOME/.openclaw/hooks/peon-ping/peon.sh",
|
|
57
|
+
// Windows/Git Bash WSL2 fallback
|
|
58
|
+
"$HOME/.claude/hooks/peon-ping/peon.ps1",
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// peon.sh discovery
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
export function resolvePeonShPaths(): string[] {
|
|
66
|
+
const home = homedir();
|
|
67
|
+
return PEON_SH_TEMPLATES.map((t) => t.replace("$HOME", home));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Try to resolve the Homebrew peon-ping prefix.
|
|
72
|
+
* Returns the libexec/peon.sh path, or undefined if brew is unavailable.
|
|
73
|
+
*/
|
|
74
|
+
export function tryBrewPrefix(): string | undefined {
|
|
75
|
+
if (platform() !== "darwin") return undefined;
|
|
76
|
+
try {
|
|
77
|
+
const prefix = execFileSync("brew", ["--prefix", "peon-ping"], {
|
|
78
|
+
encoding: "utf-8",
|
|
79
|
+
timeout: 3000,
|
|
80
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
81
|
+
}).trim();
|
|
82
|
+
if (!prefix) return undefined;
|
|
83
|
+
const shPath = join(prefix, "libexec", "peon.sh");
|
|
84
|
+
return existsSync(shPath) ? shPath : undefined;
|
|
85
|
+
} catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function findPeonSh(): string | null {
|
|
91
|
+
// 1. PEON_SH env var override
|
|
92
|
+
const envPath = process.env.PEON_SH;
|
|
93
|
+
if (envPath) {
|
|
94
|
+
try {
|
|
95
|
+
if (existsSync(envPath)) return envPath;
|
|
96
|
+
} catch {
|
|
97
|
+
// permission denied
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 2. Homebrew prefix (macOS only)
|
|
102
|
+
const brewPath = tryBrewPrefix();
|
|
103
|
+
if (brewPath) return brewPath;
|
|
104
|
+
|
|
105
|
+
// 3-6. Static paths
|
|
106
|
+
for (const p of resolvePeonShPaths()) {
|
|
107
|
+
try {
|
|
108
|
+
if (existsSync(p)) return p;
|
|
109
|
+
} catch {
|
|
110
|
+
// permission denied or other fs error
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Shell detection
|
|
118
|
+
// ============================================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Returns the shell command to use for spawning peon.
|
|
122
|
+
* On Windows (Git Bash / WSL2), peon.sh may be peon.ps1 and needs powershell.
|
|
123
|
+
*/
|
|
124
|
+
export function resolveShellAndScript(
|
|
125
|
+
peonPath: string,
|
|
126
|
+
): { shell: string; script: string } {
|
|
127
|
+
if (peonPath.endsWith(".ps1")) {
|
|
128
|
+
return { shell: "powershell", script: peonPath };
|
|
129
|
+
}
|
|
130
|
+
return { shell: "bash", script: peonPath };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Terminal tab title helpers
|
|
135
|
+
// ============================================================================
|
|
136
|
+
|
|
137
|
+
export function setTabTitle(title: string): void {
|
|
138
|
+
process.stdout.write(`\x1b]0;${title}\x07`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Session ID helpers
|
|
143
|
+
// ============================================================================
|
|
144
|
+
|
|
145
|
+
export function getSessionId(ctx: ExtensionContext): string {
|
|
146
|
+
try {
|
|
147
|
+
const sm = ctx.sessionManager as { getSessionFile?: () => string | undefined };
|
|
148
|
+
const file = sm.getSessionFile?.();
|
|
149
|
+
if (file) return file;
|
|
150
|
+
} catch {
|
|
151
|
+
// session manager not available
|
|
152
|
+
}
|
|
153
|
+
return `pi-${Date.now()}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// peon.sh invocation
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
export function firePeon(
|
|
161
|
+
peonPath: string,
|
|
162
|
+
event: string,
|
|
163
|
+
cwd: string,
|
|
164
|
+
sessionId: string,
|
|
165
|
+
): void {
|
|
166
|
+
const payload = JSON.stringify({
|
|
167
|
+
hook_event_name: event,
|
|
168
|
+
notification_type: "",
|
|
169
|
+
cwd,
|
|
170
|
+
session_id: sessionId,
|
|
171
|
+
permission_mode: "",
|
|
172
|
+
source: "pi",
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const { shell, script } = resolveShellAndScript(peonPath);
|
|
177
|
+
const proc = spawn(shell, [script], {
|
|
178
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
179
|
+
});
|
|
180
|
+
proc.stdin.write(payload);
|
|
181
|
+
proc.stdin.end();
|
|
182
|
+
proc.unref();
|
|
183
|
+
} catch {
|
|
184
|
+
// best-effort, silently ignore
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Extension
|
|
190
|
+
// ============================================================================
|
|
191
|
+
|
|
192
|
+
export default function peonPingExtension(pi: ExtensionAPI): void {
|
|
193
|
+
const peonPath = findPeonSh();
|
|
194
|
+
if (!peonPath) {
|
|
195
|
+
console.warn("[pi-peon-ping] peon.sh not found. Install peon-ping first:");
|
|
196
|
+
console.warn(" brew install PeonPing/tap/peon-ping");
|
|
197
|
+
console.warn(" # or: curl -fsSL peonping.com/install | bash");
|
|
198
|
+
console.warn(" # or: set PEON_SH=/path/to/peon.sh");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const cwd = process.cwd();
|
|
203
|
+
const projectName = basename(cwd) || "pi";
|
|
204
|
+
|
|
205
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
206
|
+
const sessionId = getSessionId(ctx);
|
|
207
|
+
if (ctx.hasUI) setTabTitle(`● ${projectName}: ready`);
|
|
208
|
+
firePeon(peonPath, "SessionStart", cwd, sessionId);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
pi.on("turn_start", async (_event, ctx) => {
|
|
212
|
+
const sessionId = getSessionId(ctx);
|
|
213
|
+
if (ctx.hasUI) setTabTitle(`● ${projectName}: working...`);
|
|
214
|
+
firePeon(peonPath, "UserPromptSubmit", cwd, sessionId);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
218
|
+
const sessionId = getSessionId(ctx);
|
|
219
|
+
if (ctx.hasUI) setTabTitle(`✓ ${projectName}: done`);
|
|
220
|
+
firePeon(peonPath, "Stop", cwd, sessionId);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
224
|
+
if (!event.isError) return;
|
|
225
|
+
const sessionId = getSessionId(ctx);
|
|
226
|
+
if (ctx.hasUI) setTabTitle(`✗ ${projectName}: error`);
|
|
227
|
+
firePeon(peonPath, "PostToolUseFailure", cwd, sessionId);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
231
|
+
const sessionId = getSessionId(ctx);
|
|
232
|
+
firePeon(peonPath, "SessionEnd", cwd, sessionId);
|
|
233
|
+
});
|
|
234
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fyeeme/pi-peon-ping",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "peon-ping adapter for pi — routes lifecycle events through peon.sh for sound packs, notifications, and trainer reminders.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "fyeeme",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/fyeeme/pi-packages"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/fyeeme/pi-packages/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/fyeeme/pi-packages#readme",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"pi-package",
|
|
24
|
+
"pi",
|
|
25
|
+
"peon-ping",
|
|
26
|
+
"sounds",
|
|
27
|
+
"notifications",
|
|
28
|
+
"lifecycle",
|
|
29
|
+
"omp"
|
|
30
|
+
],
|
|
31
|
+
"files": [
|
|
32
|
+
"index.ts",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"CHANGELOG.md"
|
|
36
|
+
],
|
|
37
|
+
"pi": {
|
|
38
|
+
"extensions": [
|
|
39
|
+
"./index.ts"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "vitest --run",
|
|
44
|
+
"typecheck": "tsc"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@earendil-works/pi-coding-agent": ">=0.77.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@earendil-works/pi-coding-agent": "0.77.0",
|
|
51
|
+
"@types/node": "22.19.19",
|
|
52
|
+
"typescript": "5.9.3"
|
|
53
|
+
}
|
|
54
|
+
}
|