@cad0p/pi-tree-navigator 0.1.0 → 0.1.1-20260809.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 +35 -0
- package/README.md +23 -20
- package/extensions/navigate-tree/index.ts +101 -27
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.1] - 2026-07-31
|
|
6
|
+
|
|
7
|
+
<!-- USER-EDITABLE SECTION START -->
|
|
8
|
+
Patch release: restores the mid-loop context refresh on pi ≥0.80.3. No behavior change on pi ≤0.80.2.
|
|
9
|
+
|
|
10
|
+
**The bug (pi ≥0.80.3):** pi 0.80.3 added `AgentSession._installAgentNextTurnRefresh()`, which installs pi's own `agent.prepareNextTurnWithContext` in the constructor, and pi-agent-core's `Agent.createLoopConfig` now prefers that field over `agent.prepareNextTurn`. Since this extension only wrapped `prepareNextTurn`, its mid-loop context replacement was dead code: after a `rewind`, the branch summary landed correctly, but every remaining turn of the same loop still sent the full pre-rewind context to the API, and the footer's context-% re-anchored on that stale usage (jumping back up right after the rewind). Rewinds only actually saved context on the *next* user prompt.
|
|
11
|
+
|
|
12
|
+
**The fix:** `installPrepareNextTurn` now wraps both hook fields with the same marker/`__prior` chaining discipline. On pi ≥0.80.3 the `prepareNextTurnWithContext` wrapper chains pi's own (keeping its per-turn `systemPrompt`/`tools`/`model`/`thinkingLevel` refreshes) and overrides only `messages`; on pi ≤0.80.2 the new field is never read and `prepareNextTurn` does the work as before.
|
|
13
|
+
|
|
14
|
+
Verified live on pi 0.83.0 (persisted session): after a rewind at 31.5% context, the footer stays at ~1.6% for the rest of the loop (previously bounced back to ~33.5%), and the post-rewind API call goes out with ~3.7k tokens instead of ~80.5k.
|
|
15
|
+
<!-- USER-EDITABLE SECTION END -->
|
|
16
|
+
|
|
17
|
+
### 🚀 Features
|
|
18
|
+
|
|
19
|
+
- Discriminated-union schema makes summaryFocus required at the wire level ([#1](https://github.com/cad0p/pi-tree-navigator/pull/1))
|
|
20
|
+
|
|
21
|
+
### 🐛 Bug Fixes
|
|
22
|
+
|
|
23
|
+
- Revert discriminated-union parameters — Kiro rejects non-object root schemas ([#2](https://github.com/cad0p/pi-tree-navigator/pull/2))
|
|
24
|
+
- Wrap prepareNextTurnWithContext — in-loop context refresh dead since pi 0.80.3 ([#8](https://github.com/cad0p/pi-tree-navigator/pull/8))
|
|
25
|
+
|
|
26
|
+
### 🚜 Refactor
|
|
27
|
+
|
|
28
|
+
- Nest extension under extensions/navigate-tree/ per pi-napkin convention
|
|
29
|
+
|
|
30
|
+
### 📚 Documentation
|
|
31
|
+
|
|
32
|
+
- Promote npm install and publishing ([#4](https://github.com/cad0p/pi-tree-navigator/pull/4))
|
|
33
|
+
|
|
34
|
+
### ⚙️ Miscellaneous Tasks
|
|
35
|
+
|
|
36
|
+
- Release-grade cleanup for v0.1.0 ([#3](https://github.com/cad0p/pi-tree-navigator/pull/3))
|
|
37
|
+
- Switch from bun to node + pnpm for local dev and CI ([#6](https://github.com/cad0p/pi-tree-navigator/pull/6))
|
|
38
|
+
|
|
39
|
+
|
|
5
40
|
## [0.1.0] - 2026-05-25
|
|
6
41
|
|
|
7
42
|
<!-- USER-EDITABLE SECTION START -->
|
package/README.md
CHANGED
|
@@ -6,28 +6,31 @@ Lets a pi agent anchor named milestones in its own conversation, then collapse w
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
+
Stable npm release:
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
|
-
pi install
|
|
12
|
+
pi install npm:@cad0p/pi-tree-navigator
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
Pre-release npm snapshots from `main` are published with the `next` dist-tag:
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:@cad0p/pi-tree-navigator@next
|
|
19
|
+
```
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
You can also install directly from the git source when testing unreleased branches:
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
```bash
|
|
24
|
+
pi install git:github.com/cad0p/pi-tree-navigator
|
|
25
|
+
```
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
## Publishing
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
pi install npm:@cad0p/pi-tree-navigator@next
|
|
28
|
-
```
|
|
29
|
+
This repo uses [`cad0p/semver-calver-release`](https://github.com/cad0p/semver-calver-release)'s npm-package workflow:
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
- Pushes to `main` compute the next hybrid SemVer + CalVer version, tag a GitHub prerelease, and publish to npm with the `next` dist-tag.
|
|
32
|
+
- Curated release PRs from `release/from-v*` branches bump the base `package.json` version and publish stable npm releases.
|
|
33
|
+
- npm publishing uses GitHub OIDC / npm trusted publishing via `.github/workflows/release.yml` (`id-token: write`) and `publishConfig.access: public`.
|
|
31
34
|
|
|
32
35
|
### Requirements
|
|
33
36
|
|
|
@@ -36,7 +39,7 @@ pi install git:github.com/cad0p/pi-tree-navigator
|
|
|
36
39
|
- `@earendil-works/pi-coding-agent >=0.74.0`
|
|
37
40
|
- `@earendil-works/pi-agent-core >=0.74.0`
|
|
38
41
|
- `typebox ^1.0.0` (used to declare the tool's parameter schema; bundled with pi but listed explicitly so a standalone install resolves correctly).
|
|
39
|
-
- The reflection bootstrap depends on
|
|
42
|
+
- The reflection bootstrap depends on six plain (not `#`-private) internal pi/agent fields: `AgentSession.prototype.prompt`, `agent.state.messages`, `agent.state.systemPrompt`, `agent.state.tools`, `agent.prepareNextTurn` (pi ≤0.80.2), and `agent.prepareNextTurnWithContext` (preferred by pi ≥0.80.3). Verified against pi 0.75.5 and pi 0.83.0.
|
|
40
43
|
|
|
41
44
|
## What you get
|
|
42
45
|
|
|
@@ -90,7 +93,7 @@ The synthetic assistant we inject after each rewind carries the **post-rewind ch
|
|
|
90
93
|
|
|
91
94
|
## Limitations
|
|
92
95
|
|
|
93
|
-
- **Brittle to pi version bumps.** The fix uses
|
|
96
|
+
- **Brittle to pi version bumps.** The fix uses six independent reflection points on internals that aren't part of pi's public API: `AgentSession.prototype.prompt`, `agent.state.messages`, `agent.state.systemPrompt`, `agent.state.tools`, `agent.prepareNextTurn`, and `agent.prepareNextTurnWithContext`. This is not hypothetical: pi 0.80.3 added `prepareNextTurnWithContext` and made the loop prefer it, silently dead-ending the `prepareNextTurn`-only hook until v0.1.1. If a future pi release renames any of these, switches them to private (`#`) fields, or restructures the class hierarchy, this breaks. The extension fails loudly: `anchor` still works, `rewind` reports `⚠ reflection bootstrap missing — the rewind landed on disk but the next assistant turn may still see the pre-rewind context. Run \`/reload\` (or restart pi) to recover.`, and you'd see context corruption return on the next prompt.
|
|
94
97
|
|
|
95
98
|
- **Anchor early in the turn.** Whatever's in `agent.state.messages` *before* the `anchor` tool call stays in the kept chain. Everything after gets summarized. Anchor at the *start* of a stage for maximum context savings.
|
|
96
99
|
|
|
@@ -107,13 +110,13 @@ The synthetic assistant we inject after each rewind carries the **post-rewind ch
|
|
|
107
110
|
## Development
|
|
108
111
|
|
|
109
112
|
```bash
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
pnpm install
|
|
114
|
+
pnpm test # helpers + dispatch / reflection bootstrap / salvage path
|
|
115
|
+
pnpm run lint # biome check extensions/
|
|
116
|
+
pnpm run typecheck # tsc --noEmit
|
|
114
117
|
```
|
|
115
118
|
|
|
116
|
-
Tests cover `extensions/navigate-tree/helpers.ts` (pure helpers in `helpers.test.ts`) and `extensions/navigate-tree/index.ts` (action dispatch, schema shape, synthetic-assistant injection, reflection bootstrap, salvage path — in `index.test.ts`). The `summarize` factory option injects a stub for `generateBranchSummary` so no real LLM call fires during rewind tests. Additional manual e2e validation against pi 0.
|
|
119
|
+
Tests cover `extensions/navigate-tree/helpers.ts` (pure helpers in `helpers.test.ts`) and `extensions/navigate-tree/index.ts` (action dispatch, schema shape, synthetic-assistant injection, reflection bootstrap, salvage path — in `index.test.ts`). The `summarize` factory option injects a stub for `generateBranchSummary` so no real LLM call fires during rewind tests. Additional manual e2e validation against the current pi release (0.83.x at time of writing) is recommended for any pi version bump (the reflection bootstrap depends on internal field shapes).
|
|
117
120
|
|
|
118
121
|
## License
|
|
119
122
|
|
|
@@ -22,18 +22,20 @@
|
|
|
22
22
|
* this.agent.state.messages = this.sessionManager.buildSessionContext().messages;
|
|
23
23
|
*
|
|
24
24
|
* Risks of the reflection approach:
|
|
25
|
-
* • If pi switches any of the
|
|
25
|
+
* • If pi switches any of the six fields this extension reads —
|
|
26
26
|
* `AgentSession.prototype.prompt`, `agent.state.messages`,
|
|
27
|
-
* `agent.state.systemPrompt`, `agent.state.tools`,
|
|
28
|
-
* `agent.prepareNextTurn` —
|
|
29
|
-
* fundamentally.
|
|
27
|
+
* `agent.state.systemPrompt`, `agent.state.tools`,
|
|
28
|
+
* `agent.prepareNextTurn`, or `agent.prepareNextTurnWithContext` —
|
|
29
|
+
* to ES `#` private fields, this breaks fundamentally.
|
|
30
30
|
* • If pi renames or restructures any of these fields, this breaks.
|
|
31
31
|
* • Patches `AgentSession.prototype.prompt` globally on import; not
|
|
32
32
|
* reversible without a process restart; affects every session in
|
|
33
33
|
* the pi process, including sessions that never call
|
|
34
34
|
* `navigate_tree`.
|
|
35
35
|
*
|
|
36
|
-
* Verified against pi 0.75.5.
|
|
36
|
+
* Verified against pi 0.75.5 (`prepareNextTurn` path) and pi 0.83.0
|
|
37
|
+
* (`prepareNextTurnWithContext` path — required since pi 0.80.3, see
|
|
38
|
+
* `installPrepareNextTurn`).
|
|
37
39
|
*/
|
|
38
40
|
|
|
39
41
|
import { estimateContextTokens } from "@earendil-works/pi-agent-core";
|
|
@@ -116,6 +118,7 @@ const LIST_PCT_COL_WIDTH = 5;
|
|
|
116
118
|
// hint column visible without truncating common names.
|
|
117
119
|
const LIST_LABEL_COL_WIDTH = 28;
|
|
118
120
|
const PNT_MARKER = Symbol.for("navigate-tree.pnt-installed");
|
|
121
|
+
const PNTWC_MARKER = Symbol.for("navigate-tree.pntwc-installed");
|
|
119
122
|
const ORIG_PROMPT_KEY = Symbol.for("navigate-tree.orig-prompt");
|
|
120
123
|
|
|
121
124
|
// Two warnings: list-site (read-only path; warns about the next turn's
|
|
@@ -144,6 +147,10 @@ interface PiInternals {
|
|
|
144
147
|
tools: unknown[];
|
|
145
148
|
};
|
|
146
149
|
prepareNextTurn?: unknown;
|
|
150
|
+
// Preferred over `prepareNextTurn` by `Agent.createLoopConfig`
|
|
151
|
+
// when set; pi's own AgentSession always sets it (via
|
|
152
|
+
// `_installAgentNextTurnRefresh`) since pi-coding-agent 0.80.3.
|
|
153
|
+
prepareNextTurnWithContext?: unknown;
|
|
147
154
|
};
|
|
148
155
|
sessionManager: SessionManager;
|
|
149
156
|
}
|
|
@@ -163,14 +170,22 @@ type PntResult = {
|
|
|
163
170
|
thinkingLevel?: unknown;
|
|
164
171
|
};
|
|
165
172
|
// pi 0.75.5 invokes `agent.prepareNextTurn(signal)` from
|
|
166
|
-
// `Agent.createLoopConfig` — a single AbortSignal argument.
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
173
|
+
// `Agent.createLoopConfig` — a single AbortSignal argument. Since pi
|
|
174
|
+
// 0.80.3 the loop instead invokes
|
|
175
|
+
// `agent.prepareNextTurnWithContext(nextTurnContext, signal)` (and only
|
|
176
|
+
// falls back to `prepareNextTurn` when the WithContext field is unset).
|
|
177
|
+
// Both differ from the documented
|
|
178
|
+
// `AgentLoopConfig.prepareNextTurn(context: PrepareNextTurnContext)`
|
|
179
|
+
// shape, which `Agent` is bridging. We accept whatever pi passes and
|
|
180
|
+
// forward it verbatim to the prior wrapper so we don't fight a future
|
|
181
|
+
// signature alignment. Verified against pi-coding-agent 0.75.5 and
|
|
182
|
+
// 0.83.0; revisit if the call site changes.
|
|
172
183
|
type PntFn = (...args: unknown[]) => Promise<PntResult> | PntResult;
|
|
173
|
-
type MarkedPntFn = PntFn & {
|
|
184
|
+
type MarkedPntFn = PntFn & {
|
|
185
|
+
[PNT_MARKER]?: boolean;
|
|
186
|
+
[PNTWC_MARKER]?: boolean;
|
|
187
|
+
__prior?: PntFn;
|
|
188
|
+
};
|
|
174
189
|
|
|
175
190
|
// =============================================================================
|
|
176
191
|
// Reflection bootstrap & in-loop refresh
|
|
@@ -218,17 +233,32 @@ function patchAgentSessionPrototype(): void {
|
|
|
218
233
|
}
|
|
219
234
|
|
|
220
235
|
/**
|
|
221
|
-
* Wire
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
236
|
+
* Wire the in-flight agent loop to refresh its context from sessionManager
|
|
237
|
+
* between turns within the same prompt() call. Without this, the loop
|
|
238
|
+
* snapshots agent.state.messages once at prompt start and pushes new
|
|
239
|
+
* messages onto its own array — a rewind issued mid-loop doesn't reduce
|
|
240
|
+
* the next API call's size until the user sends a new prompt.
|
|
241
|
+
*
|
|
242
|
+
* Two hook fields, by pi version:
|
|
243
|
+
* • pi ≤0.80.2: `Agent.createLoopConfig` reads `agent.prepareNextTurn`.
|
|
244
|
+
* • pi ≥0.80.3: AgentSession's constructor installs its own
|
|
245
|
+
* `agent.prepareNextTurnWithContext` (`_installAgentNextTurnRefresh`),
|
|
246
|
+
* and `createLoopConfig` prefers that field over `prepareNextTurn`.
|
|
247
|
+
* Pi's wrapper refreshes systemPrompt/tools/model/thinkingLevel per
|
|
248
|
+
* turn but leaves `messages` stale — so wrapping only
|
|
249
|
+
* `prepareNextTurn` silently dead-ends (footer % and the wire context
|
|
250
|
+
* stay pre-rewind for the rest of the loop).
|
|
251
|
+
*
|
|
252
|
+
* We install on BOTH fields, each with the same marker/__prior chaining
|
|
253
|
+
* discipline: on new pi the WithContext wrapper chains pi's own (keeping
|
|
254
|
+
* its per-turn refreshes) and overrides only `messages`; on old pi the
|
|
255
|
+
* WithContext field is never read and `prepareNextTurn` does the work.
|
|
226
256
|
*
|
|
227
|
-
* The Agent class's `createLoopConfig` dereferences
|
|
228
|
-
*
|
|
229
|
-
* But it gates the closure on
|
|
230
|
-
* creation — so we have to set this BEFORE prompt() runs, hence wiring
|
|
231
|
-
* from inside the prompt patch.
|
|
257
|
+
* The Agent class's `createLoopConfig` dereferences both fields at the
|
|
258
|
+
* closure call site, so the values here are read at every turn boundary.
|
|
259
|
+
* But it gates the closure on either field being truthy at config
|
|
260
|
+
* creation — so we have to set this BEFORE prompt() runs, hence wiring
|
|
261
|
+
* it from inside the prompt patch.
|
|
232
262
|
*/
|
|
233
263
|
function installPrepareNextTurn(session: AgentSession): void {
|
|
234
264
|
const internals = asInternals(session);
|
|
@@ -237,15 +267,22 @@ function installPrepareNextTurn(session: AgentSession): void {
|
|
|
237
267
|
|
|
238
268
|
const sm = internals.sessionManager;
|
|
239
269
|
|
|
240
|
-
// If the existing
|
|
241
|
-
// extension, recover the
|
|
242
|
-
// strand other extensions' closures across /reload. Preserve any
|
|
243
|
-
// extension's
|
|
270
|
+
// If the existing hooks were installed by a previous load of THIS
|
|
271
|
+
// extension, recover the chains they captured (their `__prior`) so we
|
|
272
|
+
// don't strand other extensions' closures across /reload. Preserve any
|
|
273
|
+
// other extension's (or pi's own) hooks so we compose with them.
|
|
244
274
|
const existing = agent.prepareNextTurn as MarkedPntFn | undefined;
|
|
245
275
|
const prior: PntFn | undefined =
|
|
246
276
|
typeof existing === "function" && existing[PNT_MARKER]
|
|
247
277
|
? existing.__prior
|
|
248
278
|
: (existing as PntFn | undefined);
|
|
279
|
+
const existingWc = agent.prepareNextTurnWithContext as
|
|
280
|
+
| MarkedPntFn
|
|
281
|
+
| undefined;
|
|
282
|
+
const priorWc: PntFn | undefined =
|
|
283
|
+
typeof existingWc === "function" && existingWc[PNTWC_MARKER]
|
|
284
|
+
? existingWc.__prior
|
|
285
|
+
: (existingWc as PntFn | undefined);
|
|
249
286
|
|
|
250
287
|
const next: MarkedPntFn = async (...args: unknown[]) => {
|
|
251
288
|
let priorResult: PntResult | undefined;
|
|
@@ -273,6 +310,40 @@ function installPrepareNextTurn(session: AgentSession): void {
|
|
|
273
310
|
next[PNT_MARKER] = true;
|
|
274
311
|
next.__prior = prior;
|
|
275
312
|
agent.prepareNextTurn = next;
|
|
313
|
+
|
|
314
|
+
const nextWc: MarkedPntFn = async (...args: unknown[]) => {
|
|
315
|
+
// On pi ≥0.80.3 the loop calls this as (nextTurnContext, signal),
|
|
316
|
+
// where nextTurnContext = { message, toolResults, context,
|
|
317
|
+
// newMessages }. Forward args verbatim to the prior (pi's own
|
|
318
|
+
// wrapper expects exactly this shape).
|
|
319
|
+
const turn = args[0] as { context?: PntResult["context"] } | undefined;
|
|
320
|
+
let priorResult: PntResult | undefined;
|
|
321
|
+
if (typeof priorWc === "function") {
|
|
322
|
+
priorResult = await priorWc(...args);
|
|
323
|
+
}
|
|
324
|
+
// Same wholesale-replacement rationale as the prepareNextTurn
|
|
325
|
+
// wrapper above. When no prior result exists, fall back to the
|
|
326
|
+
// turn's live context (mirrors pi's own wrapper, which does
|
|
327
|
+
// `previousSnapshot?.context ?? turn.context`) so systemPrompt and
|
|
328
|
+
// tools are never dropped. `messages` is owned by this wrapper —
|
|
329
|
+
// this override is the entire point of the hook on pi ≥0.80.3, whose
|
|
330
|
+
// own wrapper refreshes every other field but leaves messages stale.
|
|
331
|
+
const priorContext = priorResult?.context ?? turn?.context;
|
|
332
|
+
return {
|
|
333
|
+
...priorResult,
|
|
334
|
+
context: {
|
|
335
|
+
...priorContext,
|
|
336
|
+
systemPrompt: priorContext?.systemPrompt ?? agent.state.systemPrompt,
|
|
337
|
+
tools: priorContext?.tools ?? agent.state.tools,
|
|
338
|
+
messages: sm.buildSessionContext().messages,
|
|
339
|
+
},
|
|
340
|
+
model: priorResult?.model,
|
|
341
|
+
thinkingLevel: priorResult?.thinkingLevel,
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
nextWc[PNTWC_MARKER] = true;
|
|
345
|
+
nextWc.__prior = priorWc;
|
|
346
|
+
agent.prepareNextTurnWithContext = nextWc;
|
|
276
347
|
}
|
|
277
348
|
|
|
278
349
|
function findOwningSession(sm: SessionManager): AgentSession | null {
|
|
@@ -934,8 +1005,11 @@ export const __testHooks = {
|
|
|
934
1005
|
installPrepareNextTurn,
|
|
935
1006
|
refreshAgentMessages,
|
|
936
1007
|
captureSession,
|
|
937
|
-
/**
|
|
1008
|
+
/** Symbols used to mark the wrappers installed by `installPrepareNextTurn`
|
|
1009
|
+
* (`PNT_MARKER` on `agent.prepareNextTurn`, `PNTWC_MARKER` on
|
|
1010
|
+
* `agent.prepareNextTurnWithContext` — the field pi ≥0.80.3 prefers). */
|
|
938
1011
|
PNT_MARKER,
|
|
1012
|
+
PNTWC_MARKER,
|
|
939
1013
|
/** Read-only view of captured-session ref count for reaping assertions. */
|
|
940
1014
|
sessionRefCount(): number {
|
|
941
1015
|
return sessionInstances.length;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cad0p/pi-tree-navigator",
|
|
3
|
-
"version": "0.1.0",
|
|
3
|
+
"version": "0.1.1-20260809.0",
|
|
4
4
|
"description": "agent-callable session tree navigation for pi: anchor named milestones, rewind work into a branch summary, free up context for long autonomous sessions",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
]
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"lint": "
|
|
40
|
-
"lint:fix": "
|
|
41
|
-
"typecheck": "
|
|
42
|
-
"test": "
|
|
39
|
+
"lint": "biome check extensions/",
|
|
40
|
+
"lint:fix": "biome check --write extensions/",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"test": "node --test extensions/**/*.test.ts"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@biomejs/biome": "^2.3.14",
|
|
46
|
-
"@types/
|
|
46
|
+
"@types/node": "^22.0.0",
|
|
47
47
|
"typescript": "^5.8.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|