@andares/pi-toolkits 0.7.1 → 0.7.3

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.
@@ -11,8 +11,11 @@
11
11
  * before running its own compaction
12
12
  * - prompts, message assembly, split-turn handling, output budgets, and the
13
13
  * summary file-list tail are verbatim pi built-in behavior (copied from
14
- * 0.87.1, verified unchanged through 1.0.2) — only the executing model
15
- * differs
14
+ * 0.87.1, byte-identical across every published version of the supported
15
+ * window, 0.99.0 → 1.2.0) — only the executing model differs. The one
16
+ * exception is `serializeConversation`, which is imported from the host
17
+ * instead of mirrored, so it tracks whatever the running host does
18
+ * (1.2.0 stopped feeding assistant thinking into the request).
16
19
  * - lossless fallback: unset config, unavailable model, empty/failed
17
20
  * summary, or user abort → return undefined and pi's default compaction
18
21
  * (session model) runs untouched. The extension can never make
@@ -116,7 +119,7 @@ async function completeSummary(
116
119
  }
117
120
 
118
121
  /**
119
- * pi's output-budget formula (compaction.js, 0.87.1 → 1.0.2 unchanged): a
122
+ * pi's output-budget formula (compaction.js, 0.87.1 → 1.2.0 unchanged): a
120
123
  * fraction of reserveTokens clamped by the model's own output cap.
121
124
  */
122
125
  function summarizationBudget(
@@ -132,7 +135,8 @@ function summarizationBudget(
132
135
 
133
136
  /**
134
137
  * Run the full compaction summarization with the configured model,
135
- * replicating pi's compact() (0.87.1, verified unchanged through 1.0.2):
138
+ * replicating pi's compact() (0.87.1, byte-identical across the supported
139
+ * 0.99.0 → 1.2.0 window):
136
140
  * history summary (first-connection or iterative-update prompt, custom
137
141
  * focus appended), plus a separate turn-prefix checkpoint when the cut point
138
142
  * splits a turn, merged into one summary with the file-list tail. Returns
@@ -5,9 +5,15 @@
5
5
  * compaction (dist/core/compaction/compaction.js and utils.js) so that
6
6
  * summaries produced by the configured compact model are formatted exactly
7
7
  * like pi's own compaction output. Only the executing model differs.
8
- * Verified byte-identical against pi 1.0.2 (0.88–0.98 were never published;
9
- * the only 0.87.1→1.0.2 change there is a combineUsage refactor into a
10
- * shared module, no prompt or budget change).
8
+ * Verified byte-identical against every published version of the supported
9
+ * window (0.99.0 → 1.2.0): dist/core/compaction/compaction.js and
10
+ * core/usage-totals.js are unchanged files across that span, and the only
11
+ * utils.js change (1.2.0 dropping assistant thinking from
12
+ * serializeConversation) does not touch the strings mirrored here — that
13
+ * serializer is imported from the host, not mirrored. 0.87.0 shipped a
14
+ * different split-turn prefix prompt; the text mirrored here is 0.87.1's
15
+ * fix, and the mirror is the only variant any supported host gets —
16
+ * intentional.
11
17
  *
12
18
  * Update these strings whenever pi changes its built-in prompts (diff
13
19
  * dist/core/compaction/compaction.js between versions).
@@ -196,7 +202,9 @@ export function formatFileOperations(
196
202
 
197
203
  /**
198
204
  * Combine two provider usage records field-wise (pi 0.87.1 compaction.js
199
- * combineUsage): used when a split turn produces two summarization calls.
205
+ * combineUsage, moved verbatim to core/usage-totals.js in 0.99.0 and
206
+ * unchanged through 1.2.0): used when
207
+ * a split turn produces two summarization calls.
200
208
  */
201
209
  export function combineUsage<T extends UsageLike>(first: T, second: T): T {
202
210
  return {
@@ -8,7 +8,8 @@
8
8
  * bindings — only the cycle semantics change (patch-cycle.ts), so no
9
9
  * keybinding conflicts arise.
10
10
  *
11
- * Verified against pi 0.86.0 / 0.87.0 / 0.99.0 / 1.0.2 / 1.0.4 keybinding
11
+ * Verified against every published version of the supported window
12
+ * (0.99.0 → 1.2.0) keybinding
12
13
  * tables + pi-tui input dispatch on WSL2 + Windows Terminal; re-run
13
14
  * `pnpm check:keybindings` after every host upgrade before trusting this.
14
15
  */
@@ -25,15 +26,15 @@ export const FAVORITES_FILE = "pi-toolkits-favorites.json";
25
26
  * missed — audit trail below; re-run `pnpm check:keybindings` on upgrades.
26
27
  *
27
28
  * Why ctrl+f is dead: fullscreen became pi's default `tuiMode` in 1.0
28
- * (0.86–0.99 defaulted to `regular`, where the binding is inert). On
29
+ * (0.87–0.99 defaulted to `regular`, where the binding is inert). On
29
30
  * Windows/WSL `tui.altScreen.search` resolves to ctrl+f, and
30
31
  * `TuiAltScreen.handleViewportInput()` checks it before
31
32
  * `shouldDeferViewportInputToOverlay()`, so the keystroke opens transcript
32
- * search and the selector never sees it (verified in pi-tui 1.0.4
33
+ * search and the selector never sees it (verified in pi-tui 1.2.0
33
34
  * `dist/tui-alt-screen.js`: the search check is the first key branch and
34
35
  * returns `{ consume: true }` unconditionally).
35
36
  *
36
- * Why ctrl+alt+f was discarded: clean at the pi layer across 0.86–1.0 (only
37
+ * Why ctrl+alt+f was discarded: clean at the pi layer across 0.99–1.2 (only
37
38
  * ctrl+alt+] is taken from that family) and byte-distinguishable without
38
39
  * kitty — but grabbed at the OS/app layer on the author's machine by a
39
40
  * Windows screenshot tool, so it never reached the terminal. Lesson: a key
@@ -14,7 +14,8 @@
14
14
  * - with exactly one favorite, already on it → undefined (stock "only one
15
15
  * model available" feedback); otherwise jump to it
16
16
  * - the apply logic mirrors pi's _cycleScopedModel/_cycleAvailableModel
17
- * (byte-identical across every published version in 0.86.0 → 1.0.2:
17
+ * (byte-identical across every published version in the supported window
18
+ * 0.99.0 → 1.2.0:
18
19
  * state swap, session persistence, default-model persistence only when
19
20
  * `options.persist` is set, thinking-level re-clamp, model_select emit
20
21
  * with source "cycle")
@@ -30,9 +31,9 @@ import { getFavoritesStore, modelKey } from "./store.js";
30
31
 
31
32
  /**
32
33
  * pi's `Model<any>` — the exact type of `ModelCycleResult.model`
33
- * (pi-coding-agent 0.86–1.0; the field is unchanged across that span).
34
+ * (pi-coding-agent 0.99–1.2; the field is unchanged across that span).
34
35
  * Derived here instead of importing `Model` from @earendil-works/pi-ai,
35
- * whose index.d.ts (0.86 through 1.0.2 alike) re-exports it via an
36
+ * whose index.d.ts (0.99 through 1.2.0 alike) re-exports it via an
36
37
  * extensioned `"./types.ts"` specifier that not every TS resolver substitutes
37
38
  * to `types.d.ts` (tsc 5.9 bundler does; other tsserver builds don't).
38
39
  */
@@ -56,7 +57,7 @@ interface CycleSessionInternals {
56
57
  setDefaultModelAndProvider(provider: string, id: string): void;
57
58
  };
58
59
  /**
59
- * pi 0.87: keeps a persisted default usable when cycling inside a
60
+ * pi 0.99–1.2: keeps a persisted default usable when cycling inside a
60
61
  * non-empty --models scope.
61
62
  */
62
63
  _addPersistedDefaultToNonEmptyScope(model: unknown): void;
@@ -97,7 +98,7 @@ function nextCycleIndex(
97
98
  : (currentIndex - 1 + len) % len;
98
99
  }
99
100
 
100
- /** Options accepted by pi 0.87's cycleModel (persist gates default-model persistence). */
101
+ /** Options accepted by pi's cycleModel (persist gates default-model persistence). */
101
102
  interface CycleOptions {
102
103
  persist?: boolean;
103
104
  }
@@ -139,7 +140,7 @@ export function applyCyclePatch(): boolean {
139
140
  return original.call(this, direction, options);
140
141
  }
141
142
 
142
- // Same source and availability filtering as pi 0.87's stock cycling.
143
+ // Same source and availability filtering as pi's stock cycling (0.99–1.2).
143
144
  const scoped = this._scopedModels.length > 0;
144
145
  let candidates: CycleCandidate[];
145
146
  if (scoped) {
@@ -184,7 +185,7 @@ export function applyCyclePatch(): boolean {
184
185
  : this._getThinkingLevelForModelSwitch();
185
186
  this.agent.state.model = next.model;
186
187
  this.sessionManager.appendModelChange(next.model.provider, next.model.id);
187
- // pi 0.87: only persist the default model when the caller asked for it.
188
+ // pi 0.99–1.2: only persist the default model when the caller asked for it.
188
189
  if (options.persist) {
189
190
  this.settingsManager.setDefaultModelAndProvider(
190
191
  next.model.provider,
@@ -22,7 +22,7 @@
22
22
  * keeps loading and ctrl+p falls back to stock behavior. The prototype
23
23
  * shape touched here (handleInput/updateList/filterModels and the instance
24
24
  * fields below) is byte-identical across every published version in
25
- * pi 0.86.0 → 1.0.4.
25
+ * pi 0.99.0 → 1.2.0 (and 0.87.0 → 1.1.0 before the floor moved).
26
26
  */
27
27
  import {
28
28
  ModelSelectorComponent,
@@ -61,7 +61,7 @@ interface SelectorPatchTarget {
61
61
  handleInput(keyData: string): void;
62
62
  updateList(): void;
63
63
  filterModels(query: string): void;
64
- /** pi 0.87: default-model badge source. */
64
+ /** pi 0.99–1.2: default-model badge source. */
65
65
  isDefaultModel(model: ModelRef): boolean;
66
66
  listContainer: ListContainerLike;
67
67
  searchInput: SearchInputLike;
@@ -116,7 +116,7 @@ let patched = false;
116
116
  export function applyModelSelectorPatches(): boolean {
117
117
  if (patched) return true;
118
118
  // SAFETY: ModelSelectorComponent's members are TS-private (compile-time
119
- // only); the structural view matches pi 0.86–1.0's prototype shape
119
+ // only); the structural view matches pi 0.99–1.2's prototype shape
120
120
  // (byte-identical across that span) and every touched method is
121
121
  // existence-checked below before any patching happens.
122
122
  const proto =
@@ -155,7 +155,7 @@ export function applyModelSelectorPatches(): boolean {
155
155
  };
156
156
 
157
157
  // ── 2. List rendering: hint row + bold bright yellow favorites ────────
158
- // Replicates the built-in updateList layout (pi 0.86–1.0: fixed-width cursor
158
+ // Replicates the built-in updateList layout (pi 0.99–1.2: fixed-width cursor
159
159
  // and ✓ current-marker columns, provider badge, `· default` badge, scroll
160
160
  // indicator, empty/error states, refresh status, Model Name footer) with
161
161
  // one change: favorited model ids render in the favorite style.
@@ -21,7 +21,7 @@ import type { KeyId } from "@earendil-works/pi-tui";
21
21
  /**
22
22
  * Stash hotkey.
23
23
  *
24
- * Compatibility rationale (verified against pi 0.84 keybindings, live
24
+ * Compatibility rationale (verified against pi 0.99.0–1.2.0 keybindings, live
25
25
  * matchesKey probes and terminal/OS behavior):
26
26
  * - pi: no default binding for ctrl+alt+<letter> (only ctrl+alt+] is taken);
27
27
  * extension shortcuts dispatch first while the editor is focused
@@ -4,8 +4,8 @@
4
4
  * (review, compact-model — favorites keeps its own store-local key logic).
5
5
  *
6
6
  * Types are derived from pi-coding-agent's own exports (ModelRegistry)
7
- * rather than imported from @earendil-works/pi-ai: pi-ai's index.d.ts (0.87
8
- * through 1.0.2 alike) re-exports `Model`/`Api` via extensioned
7
+ * rather than imported from @earendil-works/pi-ai: pi-ai's index.d.ts (0.99
8
+ * through 1.2.0 alike) re-exports `Model`/`Api` via extensioned
9
9
  * `./types.ts` specifiers, which tsc 5.9 bundler resolution substitutes to
10
10
  * `.d.ts` but some tsserver builds do not. Deriving from ModelRegistry keeps
11
11
  * every resolver in agreement with the exact type
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * The component is driven through a small ModelRuntime facade backed by
11
11
  * ctx.modelRegistry (pi's extension-facing wrapper). SAFETY: verified
12
- * against pi 0.86–1.0 dist (modes/interactive/components/model-selector.js +
12
+ * against pi 0.99.0–1.2.0 dist (modes/interactive/components/model-selector.js +
13
13
  * model-catalog-refresh.js — byte-identical across that span) — the
14
14
  * component only calls getAvailableSnapshot, getModel, getError and refresh
15
15
  * on modelRuntime, and ModelRegistry provides exactly those
@@ -42,7 +42,7 @@ function modelRuntimeFacade(ctx: ExtensionContext): ModelRuntime {
42
42
  refresh: (options?: { signal?: AbortSignal }) =>
43
43
  ctx.modelRegistry.refresh(options),
44
44
  };
45
- // SAFETY: the selector only touches the four members above (pi 0.86–1.0
45
+ // SAFETY: the selector only touches the four members above (pi 0.99–1.2
46
46
  // model-selector.js); everything else on ModelRuntime is never reached
47
47
  // from this component.
48
48
  return facade as unknown as ModelRuntime;
package/src/lib/tools.ts CHANGED
@@ -8,9 +8,11 @@ export function snapshotActiveTools(pi: ExtensionAPI): string[] {
8
8
  return [...pi.getActiveTools()];
9
9
  }
10
10
 
11
- /** Restore a previously snapshotted tool set. No-op when the snapshot is empty. */
12
- export function restoreActiveTools(pi: ExtensionAPI, snapshot: string[]): void {
13
- if (snapshot.length === 0) return;
11
+ /** Restore a previously snapshotted tool set (an empty snapshot = no tools). */
12
+ export function restoreActiveTools(
13
+ pi: ExtensionAPI,
14
+ snapshot: readonly string[],
15
+ ): void {
14
16
  pi.setActiveTools([...snapshot]);
15
17
  }
16
18