diff --git a/CHANGELOG.md b/CHANGELOG.md index f794f18..f7a2e6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,28 @@ All notable changes to `@pi-vault/pi-usage` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.1] - 2026-08-31 + +### Added + +- Parsed Command Code rolling `5h` and weekly rate-limit windows from the live usage API and surfaced them in the Current Usage tab. + +### Changed + +- Split Command Code live usage parsing into `src/providers/command-code/usage-parser.ts` so the provider module focuses on HTTP and snapshot assembly. +- Strengthened Command Code numeric parsing with a `strictFinite` helper that rejects empty-string inputs and ignores non-finite values. +- Updated `@biomejs/biome` to `^2.5.11`, `@earendil-works/pi-coding-agent` to `^0.84.4`, `@earendil-works/pi-tui` to `^0.84.4`, `@types/node` to `^26.4.0`, `typebox` to `^1.3.22`, `typescript` to `^7.0.2`, and `vitest` to `^4.1.11`. The `biome.json` schema URL was updated to match the new biome version. + +### Fixed + +- Recognized the `minimax-openai` model provider string as a MiniMax usage provider so models such as `MiniMax-M3` exposed through a MiniMax OpenAI-compatible proxy are attributed correctly. + +### Compatibility + +- Public API unchanged: `/usage`, `/usage:refresh`, exported events, exported types all retain their previous surface. +- Peer dependencies unchanged: `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`. +- Node.js requirement unchanged: `>=24.15.0`. + ## [0.7.0] - 2026-07-28 ### Changed diff --git a/biome.json b/biome.json index dc4ef09..a137335 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.5.5/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.11/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-1-usage-parser.md b/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-1-usage-parser.md deleted file mode 100644 index 8311f95..0000000 --- a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-1-usage-parser.md +++ /dev/null @@ -1,431 +0,0 @@ -# Command Code Usage Refactor Phase 1: Usage Parser Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Build and verify the pure Command Code payload parser that Phase 2 will connect to the live provider. - -**Architecture:** Add one provider-local pure parser with no network or cache responsibilities. It emits only reliable 5-hour and weekly percentages/reset timing, preserves existing balances and plan names, and deliberately does not synthesize a monthly window from unrelated API values. The existing live adapter remains unchanged in this phase. - -**Tech Stack:** TypeScript 6, Node.js `>=24.15.0`, native Fetch API, Vitest 4, pnpm 11, Biome. - -**Spec:** `docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md` - -**Parent Plan:** `docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md` - -**Atomic Result:** A tested, reusable `parseCommandCodeUsage()` implementation exists, and the existing Command Code provider test suite still passes. - -## Global Constraints - -- Change only `pi-usage`; `/Users/lanh/Developer/pi-packages/pi` and `/Users/lanh/Developer/pi-packages/codexbar` are read-only references. -- Keep Node.js support at `>=24.15.0`. -- Add no dependencies, public exports, shared usage types, environment variables, local estimates, or static plan-price catalog. -- Preserve the existing monthly and purchased USD balances, request/token balances, and plan-name behavior. -- Do not synthesize a monthly window from `summary.totalCost` and `credits.monthlyCredits`. -- Rolling windows expose percentage and reset timing only; do not expose raw `used`, `limit`, or `unit` fields. -- Do not modify the live provider or registry in Phase 1. - ---- - -### Task 1: Build the Pure Command Code Usage Parser - -**Files:** - -- Create: `src/providers/command-code/usage-parser.ts` -- Modify: `tests/provider-command-code.test.ts` - -**Interfaces:** - -- Consumes: `LiveUsageWindow`, `ProviderUsageSnapshot`, `clampPercent()`, `parseEpochMs()`, and `toFinite()` from the existing shared/provider runtime. -- Produces: - -```ts -export interface CommandCodePayloads { - summary?: Record; - credits?: Record; - subscription?: Record; -} - -export function parseCommandCodeUsage( - payloads: CommandCodePayloads, -): Pick; -``` - -- [ ] **Step 1: Add the failing root-payload parser test** - -Add this import to `tests/provider-command-code.test.ts`: - -```ts -import { parseCommandCodeUsage } from "../src/providers/command-code/usage-parser.ts"; -``` - -Add this block before the existing provider tests: - -```ts -describe("Command Code usage parser", () => { - it("parses root rolling windows and preserves balances without a monthly window", () => { - const parsed = parseCommandCodeUsage({ - summary: { totalCost: 4, totalCount: 42, totalTokens: 1_234 }, - credits: { - credits: { monthlyCredits: 6, purchasedCredits: 5 }, - windowLimits: { - fiveHour: { cap: 3, used: 0.75, resetAt: 1_780_000_000_000 }, - weekly: { cap: 15, used: 1.5, resetAt: 1_780_100_000_000 }, - }, - }, - subscription: { data: { planId: "individual-go" } }, - }); - - expect(parsed.windows).toEqual([ - { - key: "fiveHour", - label: "5h", - usedPercent: 25, - resetAt: 1_780_000_000_000, - windowDurationMins: 300, - }, - { - key: "weekly", - label: "Weekly", - usedPercent: 10, - resetAt: 1_780_100_000_000, - windowDurationMins: 10_080, - }, - ]); - expect(parsed.balances).toEqual([ - { label: "Monthly remaining", remaining: 6, unit: "USD" }, - { label: "Purchased remaining", remaining: 5, unit: "USD" }, - { label: "Requests", remaining: 42, unit: "count" }, - { label: "Tokens", remaining: 1_234, unit: "tok" }, - ]); - expect(parsed.planName).toBe("Go"); - }); -}); -``` - -- [ ] **Step 2: Run the focused test and confirm the parser is missing** - -Run: - -```bash -pnpm exec vitest run tests/provider-command-code.test.ts -``` - -Expected: FAIL because `src/providers/command-code/usage-parser.ts` does not exist. - -- [ ] **Step 3: Implement the parser** - -Create `src/providers/command-code/usage-parser.ts` with this complete implementation: - -```ts -import type { - LiveUsageWindow, - ProviderUsageSnapshot, -} from "../../shared/types.ts"; -import { clampPercent, parseEpochMs, toFinite } from "../runtime.ts"; - -export interface CommandCodePayloads { - summary?: Record; - credits?: Record; - subscription?: Record; -} - -const PLAN_NAMES: Record = { - "individual-go": "Go", - "individual-goat": "GOAT", - "individual-pro": "Pro", - "individual-pro-v1": "Pro", - "individual-max": "Max", - "individual-ultra": "Ultra", -}; - -function asRecord(value: unknown): Record | undefined { - return value && typeof value === "object" && !Array.isArray(value) - ? (value as Record) - : undefined; -} - -function strictFinite(value: unknown): number | undefined { - return typeof value === "string" && !value.trim() ? undefined : toFinite(value); -} - -function parseTimestamp(value: unknown): number | undefined { - const numeric = strictFinite(value); - if (numeric != null) return numeric > 0 ? parseEpochMs(numeric) : undefined; - if (typeof value !== "string") return undefined; - const parsed = Date.parse(value); - return Number.isFinite(parsed) ? parsed : undefined; -} - -function parseRateWindow( - value: unknown, - key: string, - label: string, - windowDurationMins: number, -): LiveUsageWindow | undefined { - const record = asRecord(value); - const limit = strictFinite(record?.cap); - if (limit == null || limit <= 0) return undefined; - const used = strictFinite(record?.used) ?? 0; - return { - key, - label, - usedPercent: clampPercent((used / limit) * 100), - resetAt: parseTimestamp(record?.resetAt), - windowDurationMins, - }; -} - -export function parseCommandCodeUsage( - payloads: CommandCodePayloads, -): Pick { - const credits = asRecord(payloads.credits?.credits); - const windowLimits = - asRecord(payloads.credits?.windowLimits) ?? asRecord(credits?.windowLimits); - const subscription = asRecord(payloads.subscription?.data); - - const windows: LiveUsageWindow[] = []; - const fiveHour = parseRateWindow( - windowLimits?.fiveHour, - "fiveHour", - "5h", - 5 * 60, - ); - const weekly = parseRateWindow( - windowLimits?.weekly, - "weekly", - "Weekly", - 7 * 24 * 60, - ); - if (fiveHour) windows.push(fiveHour); - if (weekly) windows.push(weekly); - - const balances: ProviderUsageSnapshot["balances"] = []; - const monthlyCredits = strictFinite(credits?.monthlyCredits); - const purchasedCredits = strictFinite(credits?.purchasedCredits) ?? 0; - if (monthlyCredits != null) { - balances.push({ - label: "Monthly remaining", - remaining: monthlyCredits, - unit: "USD", - }); - } - if (purchasedCredits > 0) { - balances.push({ - label: "Purchased remaining", - remaining: purchasedCredits, - unit: "USD", - }); - } - - const totalCount = strictFinite(payloads.summary?.totalCount); - const totalTokens = strictFinite(payloads.summary?.totalTokens); - const totalTokensIn = strictFinite(payloads.summary?.totalTokensIn); - const totalTokensOut = strictFinite(payloads.summary?.totalTokensOut); - if (totalCount != null) { - balances.push({ label: "Requests", remaining: totalCount, unit: "count" }); - } - if (totalTokens != null) { - balances.push({ label: "Tokens", remaining: totalTokens, unit: "tok" }); - } else { - if (totalTokensIn != null) { - balances.push({ - label: "Tokens in", - remaining: totalTokensIn, - unit: "tok", - }); - } - if (totalTokensOut != null) { - balances.push({ - label: "Tokens out", - remaining: totalTokensOut, - unit: "tok", - }); - } - } - - const planId = - typeof subscription?.planId === "string" ? subscription.planId : undefined; - return { - windows, - balances, - planName: planId ? (PLAN_NAMES[planId.toLowerCase()] ?? planId) : undefined, - }; -} -``` - -- [ ] **Step 4: Run the focused test and confirm it passes** - -Run: - -```bash -pnpm exec vitest run tests/provider-command-code.test.ts -``` - -Expected: PASS, including the new parser case and all existing provider cases. - -- [ ] **Step 5: Add nested payload, coercion, cap, token, and plan regressions** - -Add these tests inside `describe("Command Code usage parser", ...)`: - -```ts -it("parses nested string windows and supported reset formats", () => { - const parsed = parseCommandCodeUsage({ - credits: { - credits: { - monthlyCredits: "7.25", - windowLimits: { - fiveHour: { cap: "4", used: "1", resetAt: "1780200000" }, - weekly: { - cap: "20", - used: "4", - resetAt: "2026-06-01T00:00:00Z", - }, - }, - }, - }, - }); - - expect(parsed.windows.map((window) => window.usedPercent)).toEqual([25, 20]); - expect(parsed.windows[0].resetAt).toBe(1_780_200_000_000); - expect(parsed.windows[1].resetAt).toBe(Date.parse("2026-06-01T00:00:00Z")); - expect(parsed.balances).toContainEqual({ - label: "Monthly remaining", - remaining: 7.25, - unit: "USD", - }); -}); - -it.each(["0", 0, "-1", -1])( - "rejects non-positive numeric reset sentinel %j", - (resetAt) => { - const parsed = parseCommandCodeUsage({ - credits: { - windowLimits: { fiveHour: { cap: 1, resetAt } }, - }, - }); - - expect(parsed.windows[0].resetAt).toBeUndefined(); - }, -); - -it("omits invalid caps, defaults missing usage, and clamps overuse", () => { - const parsed = parseCommandCodeUsage({ - credits: { - windowLimits: { - fiveHour: { cap: 3 }, - weekly: { cap: 0, used: 2 }, - }, - }, - }); - expect(parsed.windows).toEqual([ - { - key: "fiveHour", - label: "5h", - usedPercent: 0, - resetAt: undefined, - windowDurationMins: 300, - }, - ]); - - const overused = parseCommandCodeUsage({ - credits: { - windowLimits: { fiveHour: { cap: 3, used: 4 } }, - }, - }); - expect(overused.windows[0].usedPercent).toBe(100); - - const fractional = parseCommandCodeUsage({ - credits: { - windowLimits: { fiveHour: { cap: 3, used: 1 } }, - }, - }); - expect(fractional.windows[0].usedPercent).toBeCloseTo(100 / 3); - - const negative = parseCommandCodeUsage({ - credits: { - windowLimits: { fiveHour: { cap: 3, used: -1 } }, - }, - }); - expect(negative.windows[0].usedPercent).toBe(0); -}); - -it("uses combined tokens before separate input and output totals", () => { - expect( - parseCommandCodeUsage({ - summary: { totalTokens: 30, totalTokensIn: 10, totalTokensOut: 20 }, - }).balances, - ).toEqual([{ label: "Tokens", remaining: 30, unit: "tok" }]); - expect( - parseCommandCodeUsage({ - summary: { totalTokensIn: 10, totalTokensOut: 20 }, - }).balances, - ).toEqual([ - { label: "Tokens in", remaining: 10, unit: "tok" }, - { label: "Tokens out", remaining: 20, unit: "tok" }, - ]); -}); - -it("ignores blank numeric fields and retains separate token totals", () => { - const parsed = parseCommandCodeUsage({ - summary: { - totalCount: " ", - totalTokens: "", - totalTokensIn: 10, - totalTokensOut: 20, - }, - credits: { - credits: { monthlyCredits: "", purchasedCredits: " " }, - }, - }); - - expect(parsed.balances).toEqual([ - { label: "Tokens in", remaining: 10, unit: "tok" }, - { label: "Tokens out", remaining: 20, unit: "tok" }, - ]); -}); - -it.each([ - ["individual-go", "Go"], - ["individual-goat", "GOAT"], - ["individual-pro", "Pro"], - ["individual-pro-v1", "Pro"], - ["individual-max", "Max"], - ["individual-ultra", "Ultra"], - ["team-future", "team-future"], -])("maps plan %s to %s", (planId, expected) => { - expect( - parseCommandCodeUsage({ subscription: { data: { planId } } }).planName, - ).toBe(expected); -}); -``` - -- [ ] **Step 6: Run focused tests, type checking, and the full project check** - -Run: - -```bash -pnpm exec vitest run tests/provider-command-code.test.ts -pnpm typecheck -pnpm check -``` - -Expected: all commands exit 0 on Node.js `>=24.15.0`. The full check runs Biome lint, TypeScript compilation, and every Vitest suite. - -- [ ] **Step 7: Review the Phase 1 diff** - -Run: - -```bash -git diff --check -git status --short -git diff -- src/providers/command-code/usage-parser.ts tests/provider-command-code.test.ts -``` - -Expected: `git diff --check` exits 0; Phase 1 changes only the parser and Command Code test file, in addition to the already-updated planning documents. - -- [ ] **Step 8: Commit the pure parser** - -```bash -git add src/providers/command-code/usage-parser.ts tests/provider-command-code.test.ts docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-1-usage-parser.md docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-2-provider-integration.md -git commit -m "feat(command-code): parse rolling usage windows" -``` diff --git a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-2-provider-integration.md b/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-2-provider-integration.md deleted file mode 100644 index 926242c..0000000 --- a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-2-provider-integration.md +++ /dev/null @@ -1,310 +0,0 @@ -# Command Code Usage Refactor Phase 2: Provider Integration Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Wire the Phase 1 parser into the existing Command Code provider so live snapshots expose 5-hour and weekly windows with all existing balances. - -**Architecture:** Keep `src/providers/command-code.ts` as the provider entrypoint and `src/providers/command-code/usage-parser.ts` as the pure parser. Replace the provider's duplicate payload interpretation with `parseCommandCodeUsage()`, extend its accepted cookie aliases, and preserve its current requests, diagnostics, cache runtime, and failure priority. - -**Tech Stack:** TypeScript 6, Node.js `>=24.15.0`, native Fetch API, Vitest 4, pnpm 11, Biome. - -**Spec:** `docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md` - -**Parent Plan:** `docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md` - -**Prerequisite:** Phase 1 is complete: `parseCommandCodeUsage()` and `CommandCodePayloads` exist and `pnpm exec vitest run tests/provider-command-code.test.ts` passes. - -## Global Constraints - -- Change only `pi-usage`; `/Users/lanh/Developer/pi-packages/pi` and `/Users/lanh/Developer/pi-packages/codexbar` are read-only references. -- Keep Node.js support at `>=24.15.0`. -- Add no files, dependencies, public exports, shared usage types, environment variables, local estimates, or static plan-price catalog. -- Preserve `COMMAND_CODE_COOKIE_HEADER`, all three current endpoint requests, provider cache/backoff behavior, request/token balances, and partial-success behavior. -- Preserve monthly and purchased credits as balances; do not synthesize a monthly usage window. -- Rolling windows expose percentages and reset timing, not currency-valued ratios. -- Keep the provider registry import unchanged. - -## Reference Findings - -- Command Code documents 5-hour and weekly rolling caps over included monthly credits; purchased credits bypass both limits: . -- Current CodexBar reads both rolling windows from `/internal/billing/credits`, accepts root and nested `windowLimits`, and supports `commandcode_prod_.session_token` plus `__Host-commandcode_prod_.session_token`. -- Pi has no Command Code usage-limit integration to reuse or modify. - ---- - -### Task 2: Wire the Parser into the Existing Provider - -**Files:** - -- Modify: `src/providers/command-code.ts` -- Modify: `tests/provider-command-code.test.ts` - -**Interfaces:** - -- Consumes: `parseCommandCodeUsage(payloads: CommandCodePayloads): Pick` from Phase 1; existing `fetchWithTimeout()`, `readJsonObject()`, `retryAfterMs()`, and `fetchWithLiveRuntime()`. -- Produces: unchanged `createCommandCodeProvider(deps: UsageDeps): UsageProviderAdapter` behavior with rolling windows supplied by the parser. - -- [ ] **Step 1: Confirm the supported runtime and clean starting state** - -Run: - -```bash -node --version -git status --short -pnpm exec vitest run tests/provider-command-code.test.ts -``` - -Expected: Node.js is `v24.15.0` or newer, `git status --short` is empty, and all focused tests pass. If Node.js is older, switch to a supported runtime before using later test results as completion evidence. - -- [ ] **Step 2: Update provider integration coverage** - -In `tests/provider-command-code.test.ts`, rename `uses cookie auth and parses aggregate usage` to `uses cookie auth and exposes rolling usage with balances`. Change its credits response to: - -```ts -if (url.toString().includes("/billing/credits")) { - return new Response( - JSON.stringify({ - credits: { monthlyCredits: 5.7112, purchasedCredits: 5 }, - windowLimits: { - fiveHour: { cap: 3, used: 0.75, resetAt: 1_780_000_000_000 }, - weekly: { cap: 15, used: 1.5, resetAt: 1_780_100_000_000 }, - }, - }), - { status: 200 }, - ); -} -``` - -Replace its current-cycle assertions with: - -```ts -expect(snapshot.status).toBe("live"); -expect(snapshot.windows.map((window) => [window.key, window.label])).toEqual([ - ["fiveHour", "5h"], - ["weekly", "Weekly"], -]); -expect(snapshot.balances).toEqual( - expect.arrayContaining([ - { label: "Monthly remaining", remaining: 5.7112, unit: "USD" }, - { label: "Purchased remaining", remaining: 5, unit: "USD" }, - { label: "Requests", remaining: 42, unit: "count" }, - { label: "Tokens", remaining: 1_234, unit: "tok" }, - ]), -); -expect(snapshot.planName).toBe("Go"); -expect(snapshot.sourceLabel).toContain("Command Code"); -expect(fetchImpl).toHaveBeenCalledTimes(3); -``` - -Replace `keeps aggregate usage when subscription enrichment fails` with this stronger partial-success regression: - -```ts -it("keeps rolling limits when summary and subscription fail", async () => { - const root = mkTmp(); - const fetchImpl = vi.fn(async (url) => { - if (url.toString().includes("/billing/credits")) { - return new Response( - JSON.stringify({ - credits: { monthlyCredits: 6 }, - windowLimits: { - fiveHour: { cap: 3, used: 1, resetAt: 1_780_000_000_000 }, - weekly: { cap: 15, used: 2, resetAt: 1_780_100_000_000 }, - }, - }), - { status: 200 }, - ); - } - throw new Error("endpoint unavailable"); - }); - - const snapshot = ( - await commandCodeProvider( - createLiveDeps(root, () => 1_000, fetchImpl, { - COMMAND_CODE_COOKIE_HEADER: "abc", - }), - ).fetch() - ).snapshot; - expect(snapshot.status).toBe("live"); - expect(snapshot.windows.map((window) => window.key)).toEqual([ - "fiveHour", - "weekly", - ]); - expect(snapshot.balances).toContainEqual({ - label: "Monthly remaining", - remaining: 6, - unit: "USD", - }); - expect(snapshot.diagnostics).toEqual( - expect.arrayContaining([ - "Summary endpoint unavailable.", - "Subscription endpoint unavailable.", - ]), - ); - rmSync(root, { recursive: true, force: true }); -}); -``` - -Add cookie-alias coverage: - -```ts -it.each([ - "commandcode_prod_.session_token", - "__Host-commandcode_prod_.session_token", -])("accepts current Command Code cookie alias %s", async (cookieName) => { - const root = mkTmp(); - const fetchImpl = vi.fn(async (url, init) => { - expect(new Headers(init?.headers).get("cookie")).toBe( - `${cookieName}=token`, - ); - if (url.toString().includes("/billing/credits")) { - return new Response( - JSON.stringify({ credits: { monthlyCredits: 0 } }), - { status: 200 }, - ); - } - return new Response("{}", { status: 200 }); - }); - - const snapshot = ( - await commandCodeProvider( - createLiveDeps(root, () => 1_000, fetchImpl, { - COMMAND_CODE_COOKIE_HEADER: `${cookieName}=token`, - }), - ).fetch() - ).snapshot; - expect(snapshot.status).toBe("live"); - expect(fetchImpl).toHaveBeenCalledTimes(3); - rmSync(root, { recursive: true, force: true }); -}); -``` - -Add compact status-classification coverage: - -```ts -it.each([ - { status: 429, diagnostic: "Rate limited.", hasRetry: true }, - { status: 401, diagnostic: "session expired", hasRetry: false }, -])( - "classifies primary $status responses", - async ({ status, diagnostic, hasRetry }) => { - const root = mkTmp(); - const fetchImpl = vi.fn(async () => - new Response("{}", { status }), - ); - const outcome = await commandCodeProvider( - createLiveDeps(root, () => 1_000, fetchImpl, { - COMMAND_CODE_COOKIE_HEADER: "abc", - }), - ).fetch(); - - expect(outcome.snapshot.available).toBe(false); - expect(outcome.snapshot.diagnostics.join(" ")).toContain(diagnostic); - expect(Boolean(outcome.nextRetryAt)).toBe(hasRetry); - rmSync(root, { recursive: true, force: true }); - }, -); -``` - -- [ ] **Step 3: Run the focused test and verify the old provider fails the new expectations** - -Run: - -```bash -pnpm exec vitest run tests/provider-command-code.test.ts -``` - -Expected: FAIL because the existing provider still emits `current-cycle` and rejects the two newly covered cookie aliases. - -- [ ] **Step 4: Replace duplicate provider parsing with the Phase 1 parser** - -In `src/providers/command-code.ts`, reduce the type import to `UsageProviderAdapter`, remove `toFinite` from the runtime import, remove the local `asRecord()` helper, and add: - -```ts -import { parseCommandCodeUsage } from "./command-code/usage-parser.ts"; -``` - -Extend the existing `cookieNames` array without changing its current entries or bare-token default: - -```ts -const cookieNames = [ - "__Secure-commandcode_prod_.session_token", - "commandcode_prod_.session_token", - "__Host-commandcode_prod_.session_token", - "__Host-better-auth.session_token", - "__Secure-better-auth.session_token", - "better-auth.session_token", -]; -``` - -After decoding the three endpoint responses, replace the local cost, window, balance, and plan parsing block with: - -```ts -const summary = await readJson(summaryRes, "Summary"); -const credits = await readJson(creditsRes, "Credits"); -const subscription = await readJson(subsRes, "Subscription"); -const parsed = parseCommandCodeUsage({ summary, credits, subscription }); -``` - -Change the empty-result check to: - -```ts -if (parsed.windows.length === 0 && parsed.balances.length === 0) { -``` - -Keep the existing primary-response status classification unchanged. In the successful snapshot, remove the old `balances`, `windows`, and `planName` fields and spread the parser result after diagnostics: - -```ts -snapshot: { - providerId: "command-code", - providerLabel: PROVIDER_LABELS["command-code"], - available: true, - diagnostic: "", - fetchedAt: now, - expiresAt: now + PROVIDER_TTLS_MS["command-code"], - status: "live", - sourceLabel: "Command Code web usage API", - sourceKind: "live", - diagnostics, - ...parsed, -}, -``` - -- [ ] **Step 5: Run the focused provider suite** - -Run: - -```bash -pnpm exec vitest run tests/provider-command-code.test.ts -``` - -Expected: PASS. The provider emits only `fiveHour` and `weekly` windows, retains all balances, accepts all covered cookies, preserves partial success, and classifies primary 429/401 responses. - -- [ ] **Step 6: Run type checking and the complete project check** - -Run under Node.js `>=24.15.0`: - -```bash -pnpm typecheck -pnpm check -``` - -Expected: both commands exit 0. `pnpm check` runs Biome lint, TypeScript compilation, and every Vitest suite without an unsupported-engine warning. - -- [ ] **Step 7: Review scope and commit the integration** - -Run: - -```bash -git diff --check -git status --short -git diff -- src/providers/command-code.ts tests/provider-command-code.test.ts -``` - -Expected: `git diff --check` exits 0 and implementation changes are limited to the provider and its test. - -Commit: - -```bash -git add src/providers/command-code.ts tests/provider-command-code.test.ts -git commit -m "refactor(command-code): expose usage limit windows" -``` diff --git a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md b/docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md deleted file mode 100644 index 5d56834..0000000 --- a/docs/superpowers/plans/2026-08-30-command-code-usage-refactor.md +++ /dev/null @@ -1,46 +0,0 @@ -# Command Code Usage Refactor Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Refactor the Command Code provider into two focused modules and publish its reliable 5-hour and weekly limits with existing balance data. - -**Architecture:** A pure parser converts Command Code JSON payloads into rolling windows, balances, and a plan name. The existing provider entrypoint keeps authentication, endpoint, cache-runtime, and error-classification behavior and delegates payload interpretation to that parser. The phase plans below are authoritative and intentionally avoid duplicating their implementation steps here. - -**Tech Stack:** TypeScript 6, Node.js `>=24.15.0`, native Fetch API, Vitest 4, pnpm 11, Biome. - -**Spec:** `docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md` - -## Global Constraints - -- Change only `pi-usage`; `/Users/lanh/Developer/pi-packages/pi` and `/Users/lanh/Developer/pi-packages/codexbar` are read-only references. -- Keep Node.js support at `>=24.15.0`. -- Add no dependencies, public exports, shared usage types, environment variables, local estimates, or static plan-price catalog. -- Preserve the existing `COMMAND_CODE_COOKIE_HEADER` configuration, provider cache/backoff behavior, monthly and purchased balances, request/token balances, and partial-success behavior. -- Do not synthesize a monthly usage window from request-history cost and remaining credits. -- Rolling windows expose percentages and reset timing, not currency-valued ratios. - ---- - -### Phase 1: Build the Pure Usage Parser - -**Plan:** `docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-1-usage-parser.md` - -**Atomic Result:** A tested `parseCommandCodeUsage()` implementation exists. It emits reliable 5-hour and weekly windows, preserves balances and plan names, and leaves the live adapter unchanged. - -- [ ] Execute every Phase 1 checkbox in order. -- [ ] Confirm `pnpm exec vitest run tests/provider-command-code.test.ts` passes. -- [ ] Confirm the Phase 1 commit exists before starting Phase 2. - -### Phase 2: Integrate the Parser with the Provider - -**Plan:** `docs/superpowers/plans/2026-08-30-command-code-usage-refactor-phase-2-provider-integration.md` - -**Prerequisite:** Phase 1 is complete and its focused tests pass. - -**Atomic Result:** The existing provider uses the parser, snapshots expose available rolling windows and balances, partial failures retain usable data, and the complete project check passes. - -- [ ] Execute every Phase 2 checkbox in order. -- [ ] Confirm `pnpm exec vitest run tests/provider-command-code.test.ts` passes. -- [ ] Confirm `pnpm typecheck` passes. -- [ ] Confirm `pnpm check` passes on Node.js `>=24.15.0`. -- [ ] Confirm `git diff --check` exits 0 and the final diff stays within the planned provider, registry, tests, spec, and plan files. diff --git a/docs/superpowers/plans/2026-08-30-minimax-openai-provider-alias.md b/docs/superpowers/plans/2026-08-30-minimax-openai-provider-alias.md deleted file mode 100644 index 114ecf7..0000000 --- a/docs/superpowers/plans/2026-08-30-minimax-openai-provider-alias.md +++ /dev/null @@ -1,123 +0,0 @@ -# MiniMax OpenAI Provider Alias Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Show the existing MiniMax five-hour and weekly usage windows when the active Pi model uses the trusted custom provider ID `minimax-openai`. - -**Architecture:** Canonicalize the exact custom provider ID `minimax-openai` to the existing `minimax` usage provider inside `detectProviderFromModel()`. Preserve the current provider-isolation rule: every other non-empty provider remains authoritative and cannot be overridden by a MiniMax-looking model ID. - -**Tech Stack:** TypeScript 6, Node.js `>=24.15.0`, Vitest 4, pnpm 11, Biome. - -**Spec:** `docs/superpowers/specs/2026-08-31-minimax-openai-provider-alias-design.md` - -## Global Constraints - -- Treat `minimax-openai` as a trusted local alias, not a built-in Pi provider. -- Return canonical provider ID `minimax`; do not add a public provider ID or provider adapter. -- Keep model-ID fallback limited to models whose provider field is empty. -- Do not add aliases for `minimax-cn` or other MiniMax routes. -- Do not change provider fetching, caching, state projection, events, configuration, or consumers. -- Modify only `src/shared/provider-detection.ts` and `tests/provider-registry.test.ts`. -- Add no dependency or abstraction for the single alias. - ---- - -### Task 1: Canonicalize the Trusted MiniMax OpenAI Provider - -**Files:** - -- Modify: `tests/provider-registry.test.ts` -- Modify: `src/shared/provider-detection.ts` - -**Interfaces:** - -- Consumes: `detectProviderFromModel(model: { provider?: string; id?: string; name?: string } | undefined)` from `src/shared/provider-detection.ts`. -- Produces: canonical provider ID `"minimax"` for normalized explicit provider `"minimax-openai"`; all other detection behavior remains unchanged. - -- [ ] **Step 1: Add the positive alias and negative isolation regressions** - -In the existing `provider detection` test in `tests/provider-registry.test.ts`, add these assertions after the direct `minimax` assertion: - -```ts -expect( - detectProviderFromModel({ - provider: "minimax-openai", - id: "MiniMax-M3", - }), -).toBe("minimax"); -expect( - detectProviderFromModel({ - provider: "custom-proxy", - id: "MiniMax-M3", - }), -).toBeUndefined(); -``` - -- [ ] **Step 2: Run the focused test and verify the positive regression fails** - -Run: - -```bash -./node_modules/.bin/vitest run tests/provider-registry.test.ts -``` - -Expected: FAIL because the `minimax-openai` call receives `undefined` instead of `"minimax"`. The `custom-proxy` assertion passes. - -- [ ] **Step 3: Implement the exact alias** - -In `src/shared/provider-detection.ts`, replace the current direct MiniMax condition with: - -```ts -if (p === "minimax" || p === "minimax-openai") return "minimax"; -``` - -Do not move or weaken the later `if (p) return undefined;` guard. - -- [ ] **Step 4: Run the focused test and verify it passes** - -Run: - -```bash -./node_modules/.bin/vitest run tests/provider-registry.test.ts -``` - -Expected: PASS. The trusted alias resolves to `minimax`, while `custom-proxy` remains unrecognized. - -- [ ] **Step 5: Verify the required Node.js runtime** - -Run: - -```bash -node --version -``` - -Expected: `v24.15.0` or newer. - -- [ ] **Step 6: Run the complete project check** - -Run: - -```bash -pnpm check -``` - -Expected: Biome, TypeScript, and all Vitest suites exit 0. - -- [ ] **Step 7: Review formatting and scope** - -Run: - -```bash -git diff --check -git status --short -git diff -- src/shared/provider-detection.ts tests/provider-registry.test.ts -``` - -Expected: no whitespace errors; implementation changes are limited to the detector and its regression test. The previously committed design spec and this plan document may also appear in repository history or status, but no provider adapter, parser, projection, configuration, or consumer file changes. - -- [ ] **Step 8: Commit the implementation** - -```bash -git add src/shared/provider-detection.ts tests/provider-registry.test.ts -git commit -m "fix: recognize MiniMax OpenAI provider alias" -``` diff --git a/docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md b/docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md deleted file mode 100644 index 7245e3e..0000000 --- a/docs/superpowers/specs/2026-08-30-command-code-usage-refactor-design.md +++ /dev/null @@ -1,49 +0,0 @@ -# Command Code Usage Refactor Design - -## Goal - -Refactor the Command Code provider into focused modules and expose its reliable 5-hour and weekly usage windows alongside the existing credit and activity balances. - -## Context - -- Command Code documents two rolling limits—5 hours and 7 days—on top of the included monthly credit pool. Purchased credits bypass those rolling limits. -- CodexBar's captured production payloads show `windowLimits.fiveHour` and `windowLimits.weekly`, each containing `cap`, `used`, and `resetAt`. `windowLimits` may appear at the response root or inside `credits`. -- The rolling values are credit-value quotas, not a universally safe USD ratio. CodexBar therefore retains their percentage and reset timing without presenting a currency ratio. -- `summary.totalCost` is request-history cost, while `credits.monthlyCredits` is the remaining included grant. Purchased usage can increase the former without reducing the latter, so the two values cannot reliably reconstruct a monthly allowance. -- `pi-usage` already has the required `LiveUsageWindow` model, cache runtime, balance model, and dashboard rendering. Pi itself has no usage-limit integration to change. - -Reference: - -## Architecture - -Keep the existing provider entrypoint and the Phase 1 parser as two focused modules: - -- `src/providers/command-code.ts` owns cookie normalization, concurrent endpoint fetching, response diagnostics, cache-runtime integration, and final error classification. -- `src/providers/command-code/usage-parser.ts` is a pure payload parser that returns rolling windows, balances, and the display plan name. - -Wire the parser into the existing provider instead of adding a single-consumer API-client module. The provider registry remains unchanged. Add the current `commandcode_prod_` host and non-secure cookie-name variants observed in CodexBar while preserving all existing accepted cookie forms. No public exports, shared types, configuration keys, dependencies, or TUI code change. - -## Usage Semantics - -Emit reliable rolling windows in this order: - -1. `fiveHour`, labeled `5h`, with a 300-minute duration. -2. `weekly`, labeled `Weekly`, with a 10,080-minute duration. - -For each rolling window, require a positive `cap`, default missing `used` to zero, and clamp the calculated percentage to 0–100 without discarding fractional precision. Accept reset timestamps expressed as epoch seconds, epoch milliseconds, numeric strings, or ISO strings. Expose only the window key, label, percentage, reset timestamp, and duration; do not label raw rolling values as USD or render a ratio. - -Do not synthesize a monthly usage window from `summary.totalCost` and `credits.monthlyCredits`. Preserve `monthlyCredits` and positive `purchasedCredits` as separate USD balances. Preserve existing request/token balances and their precedence: use `totalTokens` when available, otherwise retain the separate input/output totals. - -Recognize `individual-go`, `individual-goat`, `individual-pro`, `individual-pro-v1`, `individual-max`, and `individual-ultra` display names; use an unknown plan ID verbatim. - -## Failure Behavior - -Fetch summary, credits, and subscription concurrently. Summary and credits are primary endpoints; subscription is enrichment only. - -Publish a live snapshot whenever parsing yields at least one window or balance, attaching diagnostics for any failed endpoint. When no usable data exists, preserve the existing priority: a primary 429 response produces rate-limited state, a primary 401/403 response produces credential state, and all other cases produce a generic live-source error. Existing cache and backoff behavior remains unchanged. - -## Verification - -Extend the existing Command Code tests with pure parser coverage for both payload locations, value coercion, reset formats, invalid caps, percentage clamping, window ordering, the absence of a synthesized monthly window, balance preservation, token precedence, and plan names. Preserve the cookie, subscription-enrichment, and partial-failure integration coverage. - -The provider integration must assert rolling windows, monthly and purchased balances, request and token balances, plan enrichment, supported cookie aliases, primary rate-limit handling, and expired-session handling. Run the focused provider test and then the complete project check on Node.js `>=24.15.0`; a pass on an unsupported Node.js version is not sufficient completion evidence. diff --git a/docs/superpowers/specs/2026-08-31-minimax-openai-provider-alias-design.md b/docs/superpowers/specs/2026-08-31-minimax-openai-provider-alias-design.md deleted file mode 100644 index 11c92c8..0000000 --- a/docs/superpowers/specs/2026-08-31-minimax-openai-provider-alias-design.md +++ /dev/null @@ -1,52 +0,0 @@ -# MiniMax OpenAI Provider Alias Design - -## Problem - -`pi-usage` selects the live usage snapshot from the active Pi model's provider ID. A trusted custom Pi provider named `minimax-openai` serves `MiniMax-M3`, but `detectProviderFromModel()` recognizes only `minimax`. Because explicit unknown providers intentionally bypass model-name inference, the current provider remains unset and compatible MiniMax usage windows are not published to consumers. - -Pi itself does not define `minimax-openai`. Its built-in MiniMax provider is `minimax`, while custom provider IDs may be arbitrary strings. The new mapping is therefore a local, explicit contract for this trusted custom route rather than an upstream Pi alias. - -## References - -- Pi `dcd461925`: `packages/ai/src/providers/minimax.ts` defines the built-in provider ID as `minimax`; `packages/ai/src/types.ts` permits custom string provider IDs; `packages/coding-agent/docs/models.md` documents custom providers. -- CodexBar `89765dc2b`: `MiniMaxUsageSnapshot.toUsageSnapshot()` owns fetched coding-plan usage under canonical provider identity `.minimax`, independently of the model transport used by another client. -- CodexBar's provider-scoped pricing tests reject fallback across providers. The same isolation rule applies here: a MiniMax-looking model name must not override an unrelated explicit provider ID. - -## Considered Approaches - -### Exact detector alias - -Map normalized `minimax-openai` to the existing `minimax` usage provider at the detection boundary. This is the smallest change and preserves downstream provider identity and provider isolation. - -### Alias table or configuration - -Move provider aliases into a table or user configuration. This adds indirection and a new configuration contract for one known alias, so it is not justified. - -### Rename the external provider - -Require the custom Pi configuration to use `minimax`. This avoids a code change but obscures that the model transport uses OpenAI compatibility and changes configuration outside this repository. - -## Design - -Extend the existing explicit MiniMax condition in `src/shared/provider-detection.ts` so normalized provider IDs `minimax` and `minimax-openai` both return canonical provider ID `minimax`. - -Keep the existing early return for every other non-empty provider. In particular, `{ provider: "custom-proxy", id: "MiniMax-M3" }` must remain unrecognized. Model-ID fallback continues to apply only when the provider field is empty. - -No provider registry, MiniMax adapter, cache, state projection, event, public type, configuration, or consumer changes are needed. Once detection returns `minimax`, the existing state flow selects the already-fetched MiniMax snapshot and publishes its compatible five-hour and weekly windows. - -## Error Handling - -The alias introduces no new I/O or failure mode. Missing credentials, unavailable MiniMax usage, stale cache handling, and absent compatible windows retain their current behavior. Unknown explicit providers continue to produce no selected live usage provider instead of being guessed from a model name. - -## Testing - -Add two assertions to the existing provider-detection test: - -1. `minimax-openai` with `MiniMax-M3` resolves to `minimax`. -2. An unrelated explicit provider with `MiniMax-M3` remains unrecognized. - -Run the focused provider-registry test first, then `pnpm check` under the repository's required Node.js version. The full check already covers provider parsing, state projection, usage-core behavior, formatting, and type checking, so no additional intermediate suite is required. - -## Scope - -Only `src/shared/provider-detection.ts` and `tests/provider-registry.test.ts` will change during implementation. Support for other MiniMax aliases, generalized model-name inference, configuration-driven aliases, and consumer changes are out of scope. diff --git a/package.json b/package.json index c969edf..c13262f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pi-vault/pi-usage", - "version": "0.7.0", + "version": "0.7.1", "type": "module", "description": "Pi extension that tracks Pi usage across your sessions in one dashboard", "author": "Lanh Hoang ", @@ -48,13 +48,13 @@ "README.md" ], "devDependencies": { - "@biomejs/biome": "^2.5.5", - "@earendil-works/pi-coding-agent": "^0.82.0", - "@earendil-works/pi-tui": "^0.82.0", - "@types/node": "^26.1.0", - "typebox": "^1.3.3", - "typescript": "^6.0.3", - "vitest": "^4.1.10" + "@biomejs/biome": "^2.5.11", + "@earendil-works/pi-coding-agent": "^0.84.4", + "@earendil-works/pi-tui": "^0.84.4", + "@types/node": "^26.4.0", + "typebox": "^1.3.22", + "typescript": "^7.0.2", + "vitest": "^4.1.11" }, "peerDependencies": { "@earendil-works/pi-coding-agent": "*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bdbaf8..85ace1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,26 +9,26 @@ importers: .: devDependencies: '@biomejs/biome': - specifier: ^2.5.5 - version: 2.5.5 + specifier: ^2.5.11 + version: 2.5.11 '@earendil-works/pi-coding-agent': - specifier: ^0.82.0 - version: 0.82.1(ws@8.21.0)(zod@4.4.3) + specifier: ^0.84.4 + version: 0.84.4(ws@8.21.0)(zod@4.4.3) '@earendil-works/pi-tui': - specifier: ^0.82.0 - version: 0.82.1 + specifier: ^0.84.4 + version: 0.84.4 '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.4.0 + version: 26.4.0 typebox: - specifier: ^1.3.3 - version: 1.3.3 + specifier: ^1.3.22 + version: 1.3.22 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vitest: - specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.0)(vite@8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)) + specifier: ^4.1.11 + version: 4.1.11(@opentelemetry/api@1.9.0)(@types/node@26.4.0)(vite@8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) packages: @@ -146,79 +146,91 @@ packages: resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.5.5': - resolution: {integrity: sha512-r1S8nFsAG1MY+vJFZALzIvwXAJv6ejDQ0mxP21Tgr9YK3ZFtjrvbBwDdNhx1rUqvccEIeNg20cYCNzl6Cr69pQ==} + '@biomejs/biome@2.5.11': + resolution: {integrity: sha512-Tj0dnkLPdW0ASjHfj2D/ZkkvPU2wrFmnE1jWTD2xzV1ycapV1DutbYXk4NDnR3rYTi1ZCbNFD4G2gRMEY65WaA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.5.5': - resolution: {integrity: sha512-kUrAhXVWUrwmAUnV2iXSK7umxKFysTwvqK+Ty6ptUcLY/7T3SnCAjUowE4uvwaEej6nXZ7hu/dTtbokKdsPeag==} + '@biomejs/cli-darwin-arm64@2.5.11': + resolution: {integrity: sha512-6SGZxoKbXvUjMn1t6A98HqWISPnGNbYs0R/Rt2JarmXBSev+lva4QxUMWEBX9lX1Wo1XTJ78uk5xVDtG58SRZg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.5.5': - resolution: {integrity: sha512-DamiYc5bUYZ2uxlfc+RLEPtz1Abb6PO5eTbOkufLpSGwd/7AMQAdxhFYiXmwwkJL8IsT8S7GvdgwDHqaMFAvKw==} + '@biomejs/cli-darwin-x64@2.5.11': + resolution: {integrity: sha512-nYkXY7tLBEgnGbYapDKAyKzgt44ZEyG+AKalvTXtCWKYgepI9dw327q+cVgedxm+Udi1ZzHKUyZrIusHi/KQbw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.5.5': - resolution: {integrity: sha512-U4WMl/sy/E/Q73vf15VspakLRRs2LDFcCeBxJnQfXzssb88zpV6PJPaQ3ezhQ7H6Ht2/8bvuZeHgJWzmoxllZg==} + '@biomejs/cli-linux-arm64-musl@2.5.11': + resolution: {integrity: sha512-qhyZUMyCbWYFV2bAwRNVvfMVZ+hv7WYl6mossGrxC+uiQQXhvsuWWU8zz6jYX0mChZd9MgQZbm4vozTmG/5iGw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64@2.5.5': - resolution: {integrity: sha512-lRKF/pH/1RiYiBKExi3TCZVAtvzEm77aifrvcNiDFrR9WxeAnDUjDnseb6y2XV85mjitLs6SILGm2XG77cHtSQ==} + '@biomejs/cli-linux-arm64@2.5.11': + resolution: {integrity: sha512-3PVLSTD9RR73rvVPt5G3T1gc+ycggWEGfTD7RvzzbtcDPD27NxgxBbAFfpm7DXJKW6VLHWE1lLMGvFt2Qxjcow==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64-musl@2.5.5': - resolution: {integrity: sha512-m7wC7tjX5Lrmo69dc4md8FeKpPU1NTCY1v7xUoQQ2vadWwNnBS0KZOG8471otFPHrTHihQJAjQPgMObpLvDe6A==} + '@biomejs/cli-linux-x64-musl@2.5.11': + resolution: {integrity: sha512-oRRlrchG5EfrEL/EmtT1qUjSNHk3/5LGeZhQqADBBAJF1b1ET6964xEKe7aGlGARzDfza8H/seEsFJl7S6Ql9w==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] - '@biomejs/cli-linux-x64@2.5.5': - resolution: {integrity: sha512-H/O39nJEw/2Zm/fm7hrmxxoF8kK/aU1uCoPp70ruXVbomaAdLpJJnCmL11Q2JotT8QVHH06So04Oq53lCSwSwQ==} + '@biomejs/cli-linux-x64@2.5.11': + resolution: {integrity: sha512-JOytptlsgM33B2MMFUg8iBrb4IKpbD5JnJrSeYiaFEeAj4vuXx0iQSQZ4qK7sqyMtfjZxxPdNdMZZVL4y/mFyA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] - '@biomejs/cli-win32-arm64@2.5.5': - resolution: {integrity: sha512-7BryINPuYypLUAH3o/o5ZdgomJ4zn3EDR0ChZJst7n32S6ZhKbgHXuYydLu+YAnx59ehGFR0z/MG6qnzQi3Yyw==} + '@biomejs/cli-win32-arm64@2.5.11': + resolution: {integrity: sha512-e49E6K9hzH/ohJNx8Y26mY8HaV4I4ZViIeoqhKsmoXLKHhQnMeBAVqCgsGf2Wa3lXlS7RkporDXMHHWkzvZzFw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.5.5': - resolution: {integrity: sha512-bIBFo+n6MIxdNcVFy5CrurbKiZQiUciK3bt8+O9I4wjFZNTfXLpi+giq47522eXqW5NBc9ulx7dR1SlZKi2J5g==} + '@biomejs/cli-win32-x64@2.5.11': + resolution: {integrity: sha512-QSQr/KjOgXA7OzXJUWS+oguKyAZ3Q0l/lnlDGbu397eKo83atuWUjBPJrsqbKNF6CARGw8XXJLGzpHC8Ryhd4Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] - '@earendil-works/pi-agent-core@0.82.1': - resolution: {integrity: sha512-Z3kloziJIE2dmrisRckZX8zDca/gIv9/YdFAzeoqpHiLV2wsni6bL4hInNSjVKLbqT+4kqLIkph2JQLKvSepjg==} + '@earendil-works/pi-agent-core@0.84.4': + resolution: {integrity: sha512-HyUnjaOXj6oN/6SNcr8A1J/ElRQA50FtIE0XUTSKAQVqmdlb9qdojOyUQwF/jULE5+yOEtGuVgi/N1RnBiNG+g==} engines: {node: '>=22.19.0'} - '@earendil-works/pi-ai@0.82.1': - resolution: {integrity: sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==} + '@earendil-works/pi-ai@0.84.4': + resolution: {integrity: sha512-AClAZxf5+c4RRu44NJPS6wyQy+Nmq+Mzyyrdvm4ZVMNuixelO02RZX4G4Aq1F145Yzp43wnM5S+hLlSI7ypfVw==} engines: {node: '>=22.19.0'} hasBin: true - '@earendil-works/pi-coding-agent@0.82.1': - resolution: {integrity: sha512-zbkAhoIuDPMF3pKuja0ajZabrMWU29FUMV9A/XMXT/XC1yXs5xt6t6t13GogQFsDrDqbFP4DkZQO1w8rWRAzYA==} + '@earendil-works/pi-client@0.84.4': + resolution: {integrity: sha512-q398WY/3ZQHTizk7IKxApzqFV0xt4yM9LkSkwyqeLK5Bj5RwRjOWxESt26z4LgNp4O+8hqhqFPf/8fj4H5rE4A==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-coding-agent@0.84.4': + resolution: {integrity: sha512-jmOlrqUmvhh/siNWFRXjYLJzhKFIHNsAQaysRwzQPQFnPAaV/vhqHsLH/MBsIISA1Rjj7WTUFR3nJrpXoLx39w==} engines: {node: '>=22.19.0'} hasBin: true - '@earendil-works/pi-tui@0.82.1': - resolution: {integrity: sha512-9yN8hALfKaxZq7n54EMxqhFCWnMi6LHkraMJ/1YjHiATq75XrI6XDMVppn9EDtiK7Fks8hUe1SDXUTrIvwRWfQ==} + '@earendil-works/pi-protocol@0.84.4': + resolution: {integrity: sha512-acyE9ozxkMiWiz/xyWpU0O9vwnYv0hyG889Vniv6Sg9c9zfsX+8MePnDNphBacY2Fvm1rxdsGmiVDSZl9yuDFA==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-telemetry@0.84.4': + resolution: {integrity: sha512-8e2CuxM+ht+hedQXTZmi5JVl6/xDK9RpSDL2+MbITevKYQhMZ/z6lJOTFgox3HQyGxO8mOZEtYGVeQNaD4OzqA==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-tui@0.84.4': + resolution: {integrity: sha512-nPUnwDkLtupPXnZQYrCwPFcuTydCDqTY6ZbFqhsL4S4kVq0AT418kPa/6uXwtaCD+MjBNBltb7ScTYX65yeE1w==} engines: {node: '>=22.19.0'} '@emnapi/core@1.10.0': @@ -310,14 +322,6 @@ packages: resolution: {integrity: sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==} engines: {node: '>= 10'} - '@mistralai/mistralai@2.2.6': - resolution: {integrity: sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: @@ -331,10 +335,6 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@opentelemetry/semantic-conventions@1.41.1': - resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} - engines: {node: '>=14'} - '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} @@ -527,14 +527,137 @@ packages: '@types/node@26.1.0': resolution: {integrity: sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==} + '@types/node@26.4.0': + resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} + '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} - '@vitest/expect@4.1.10': - resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] - '@vitest/mocker@4.1.10': - resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -544,20 +667,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.10': - resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.10': - resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.10': - resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.10': - resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.10': - resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} @@ -680,10 +803,6 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} - engines: {node: 18 || 20 || >=22} - google-auth-library@10.6.2: resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} @@ -695,6 +814,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grok-mermaid@0.2.2: + resolution: {integrity: sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA==} + engines: {node: '>=18'} + highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -827,10 +950,6 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -851,9 +970,8 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - openai@6.26.0: - resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} - hasBin: true + openai@6.40.0: + resolution: {integrity: sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA==} peerDependencies: ws: ^8.18.0 zod: ^3.25 || ^4.0 @@ -878,10 +996,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -972,22 +1086,22 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - typebox@1.1.38: - resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + typebox@1.3.22: + resolution: {integrity: sha512-YoX6QdtuJR/+YpP/qXf9gJXTxvSuiUlKYgW3AilsOSLlsZe/VH6ILR5vhoJM5QXY//uzIRE7NYij3h2+nG9vRQ==} - typebox@1.3.3: - resolution: {integrity: sha512-URXGUE31PJDQC+PtRMJeLdF4kmmOdFoVPikPCtV2oOIhUpNpppEdIz7W8bH8cFYPYHdDpaRvqwdegMTmHliudg==} + typebox@1.3.7: + resolution: {integrity: sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg==} - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@8.5.0: - resolution: {integrity: sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==} + undici@8.9.0: + resolution: {integrity: sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==} engines: {node: '>=22.19.0'} vite@8.0.14: @@ -1033,20 +1147,20 @@ packages: yaml: optional: true - vitest@4.1.10: - resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.10 - '@vitest/browser-preview': 4.1.10 - '@vitest/browser-webdriverio': 4.1.10 - '@vitest/coverage-istanbul': 4.1.10 - '@vitest/coverage-v8': 4.1.10 - '@vitest/ui': 4.1.10 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1109,11 +1223,6 @@ packages: engines: {node: '>= 14.6'} hasBin: true - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -1350,47 +1459,48 @@ snapshots: '@babel/runtime@7.29.7': {} - '@biomejs/biome@2.5.5': + '@biomejs/biome@2.5.11': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.5.5 - '@biomejs/cli-darwin-x64': 2.5.5 - '@biomejs/cli-linux-arm64': 2.5.5 - '@biomejs/cli-linux-arm64-musl': 2.5.5 - '@biomejs/cli-linux-x64': 2.5.5 - '@biomejs/cli-linux-x64-musl': 2.5.5 - '@biomejs/cli-win32-arm64': 2.5.5 - '@biomejs/cli-win32-x64': 2.5.5 - - '@biomejs/cli-darwin-arm64@2.5.5': + '@biomejs/cli-darwin-arm64': 2.5.11 + '@biomejs/cli-darwin-x64': 2.5.11 + '@biomejs/cli-linux-arm64': 2.5.11 + '@biomejs/cli-linux-arm64-musl': 2.5.11 + '@biomejs/cli-linux-x64': 2.5.11 + '@biomejs/cli-linux-x64-musl': 2.5.11 + '@biomejs/cli-win32-arm64': 2.5.11 + '@biomejs/cli-win32-x64': 2.5.11 + + '@biomejs/cli-darwin-arm64@2.5.11': optional: true - '@biomejs/cli-darwin-x64@2.5.5': + '@biomejs/cli-darwin-x64@2.5.11': optional: true - '@biomejs/cli-linux-arm64-musl@2.5.5': + '@biomejs/cli-linux-arm64-musl@2.5.11': optional: true - '@biomejs/cli-linux-arm64@2.5.5': + '@biomejs/cli-linux-arm64@2.5.11': optional: true - '@biomejs/cli-linux-x64-musl@2.5.5': + '@biomejs/cli-linux-x64-musl@2.5.11': optional: true - '@biomejs/cli-linux-x64@2.5.5': + '@biomejs/cli-linux-x64@2.5.11': optional: true - '@biomejs/cli-win32-arm64@2.5.5': + '@biomejs/cli-win32-arm64@2.5.11': optional: true - '@biomejs/cli-win32-x64@2.5.5': + '@biomejs/cli-win32-x64@2.5.11': optional: true - '@earendil-works/pi-agent-core@0.82.1(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-agent-core@0.84.4(ws@8.21.0)(zod@4.4.3)': dependencies: - '@earendil-works/pi-ai': 0.82.1(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-ai': 0.84.4(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-telemetry': 0.84.4 diff: 8.0.4 ignore: 7.0.5 - typebox: 1.1.38 + typebox: 1.3.7 yaml: 2.9.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -1400,19 +1510,18 @@ snapshots: - ws - zod - '@earendil-works/pi-ai@0.82.1(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-ai@0.84.4(ws@8.21.0)(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@earendil-works/pi-telemetry': 0.84.4 '@google/genai': 1.52.0 - '@mistralai/mistralai': 2.2.6(@opentelemetry/api@1.9.0) - '@opentelemetry/api': 1.9.0 '@smithy/node-http-handler': 4.7.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 - openai: 6.26.0(ws@8.21.0)(zod@4.4.3) + openai: 6.40.0(ws@8.21.0)(zod@4.4.3) partial-json: 0.1.7 - typebox: 1.1.38 + typebox: 1.3.7 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bufferutil @@ -1421,16 +1530,22 @@ snapshots: - ws - zod - '@earendil-works/pi-coding-agent@0.82.1(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-client@0.84.4': + dependencies: + '@earendil-works/pi-protocol': 0.84.4 + + '@earendil-works/pi-coding-agent@0.84.4(ws@8.21.0)(zod@4.4.3)': dependencies: - '@earendil-works/pi-agent-core': 0.82.1(ws@8.21.0)(zod@4.4.3) - '@earendil-works/pi-ai': 0.82.1(ws@8.21.0)(zod@4.4.3) - '@earendil-works/pi-tui': 0.82.1 + '@earendil-works/pi-agent-core': 0.84.4(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-ai': 0.84.4(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-client': 0.84.4 + '@earendil-works/pi-protocol': 0.84.4 + '@earendil-works/pi-tui': 0.84.4 '@silvia-odwyer/photon-node': 0.3.4 chalk: 5.6.2 cross-spawn: 7.0.6 diff: 8.0.4 - glob: 13.0.6 + grok-mermaid: 0.2.2 highlight.js: 10.7.3 hosted-git-info: 9.0.3 ignore: 7.0.5 @@ -1438,8 +1553,8 @@ snapshots: minimatch: 10.2.5 proper-lockfile: 4.1.2 semver: 7.8.0 - typebox: 1.1.38 - undici: 8.5.0 + typebox: 1.3.7 + undici: 8.9.0 yaml: 2.9.0 optionalDependencies: '@mariozechner/clipboard': 0.3.9 @@ -1451,7 +1566,13 @@ snapshots: - ws - zod - '@earendil-works/pi-tui@0.82.1': + '@earendil-works/pi-protocol@0.84.4': + dependencies: + typebox: 1.3.7 + + '@earendil-works/pi-telemetry@0.84.4': {} + + '@earendil-works/pi-tui@0.84.4': dependencies: get-east-asian-width: 1.6.0 marked: 18.0.5 @@ -1529,18 +1650,6 @@ snapshots: '@mariozechner/clipboard-win32-x64-msvc': 0.3.9 optional: true - '@mistralai/mistralai@2.2.6(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/semantic-conventions': 1.41.1 - ws: 8.21.0 - zod: 4.4.3 - zod-to-json-schema: 3.25.2(zod@4.4.3) - optionalDependencies: - '@opentelemetry/api': 1.9.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -1550,9 +1659,8 @@ snapshots: '@nodable/entities@2.1.1': {} - '@opentelemetry/api@1.9.0': {} - - '@opentelemetry/semantic-conventions@1.41.1': {} + '@opentelemetry/api@1.9.0': + optional: true '@oxc-project/types@0.132.0': {} @@ -1705,46 +1813,110 @@ snapshots: dependencies: undici-types: 8.3.0 + '@types/node@26.4.0': + dependencies: + undici-types: 8.3.0 + '@types/retry@0.12.0': {} - '@vitest/expect@4.1.10': + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.10': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.10': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.10': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.10': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.10': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -1848,12 +2020,6 @@ snapshots: get-east-asian-width@1.6.0: {} - glob@13.0.6: - dependencies: - minimatch: 10.2.5 - minipass: 7.1.3 - path-scurry: 2.0.2 - google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 @@ -1869,6 +2035,8 @@ snapshots: graceful-fs@4.2.11: {} + grok-mermaid@0.2.2: {} + highlight.js@10.7.3: {} hosted-git-info@9.0.3: @@ -1978,8 +2146,6 @@ snapshots: dependencies: brace-expansion: 5.0.6 - minipass@7.1.3: {} - ms@2.1.3: {} nanoid@3.3.12: {} @@ -1994,7 +2160,7 @@ snapshots: obug@2.1.1: {} - openai@6.26.0(ws@8.21.0)(zod@4.4.3): + openai@6.40.0(ws@8.21.0)(zod@4.4.3): optionalDependencies: ws: 8.21.0 zod: 4.4.3 @@ -2010,11 +2176,6 @@ snapshots: path-key@3.1.1: {} - path-scurry@2.0.2: - dependencies: - lru-cache: 11.5.1 - minipass: 7.1.3 - pathe@2.0.3: {} picocolors@1.1.1: {} @@ -2110,17 +2271,38 @@ snapshots: tslib@2.8.1: {} - typebox@1.1.38: {} + typebox@1.3.22: {} - typebox@1.3.3: {} + typebox@1.3.7: {} - typescript@6.0.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 undici-types@8.3.0: {} - undici@8.5.0: {} + undici@8.9.0: {} - vite@8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0): + vite@8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -2128,20 +2310,20 @@ snapshots: rolldown: 1.0.2 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.4.0 fsevents: 2.3.3 jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.0)(vite@8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.11(@opentelemetry/api@1.9.0)(@types/node@26.4.0)(vite@8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -2153,11 +2335,11 @@ snapshots: tinyexec: 1.2.3 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.14(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.0.14(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - '@types/node': 26.1.0 + '@types/node': 26.4.0 transitivePeerDependencies: - msw @@ -2178,8 +2360,5 @@ snapshots: yaml@2.9.0: {} - zod-to-json-schema@3.25.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - - zod@4.4.3: {} + zod@4.4.3: + optional: true