From f1f7cd50c35dbcb922ea074e8a7f141e20c2952a Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 12:37:36 +0200 Subject: [PATCH 01/15] test: speed up provider payload coverage --- .../test/anthropic-thinking-disable.test.ts | 15 ++- .../ai/test/bedrock-thinking-payload.test.ts | 19 ++-- packages/ai/test/cache-retention.test.ts | 102 +++++++++--------- packages/ai/test/openai-codex-stream.test.ts | 28 +++-- test.sh | 14 ++- 5 files changed, 106 insertions(+), 72 deletions(-) diff --git a/packages/ai/test/anthropic-thinking-disable.test.ts b/packages/ai/test/anthropic-thinking-disable.test.ts index 8f871514c..ea53043c0 100644 --- a/packages/ai/test/anthropic-thinking-disable.test.ts +++ b/packages/ai/test/anthropic-thinking-disable.test.ts @@ -1,13 +1,20 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamSimple } from "../src/stream.js"; -import type { Context, Model, SimpleStreamOptions } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamSimple } from "../src/stream.ts"; +import type { Context, Model, SimpleStreamOptions } from "../src/types.ts"; interface AnthropicThinkingPayload { thinking?: { type: string; budget_tokens?: number; display?: string }; output_config?: { effort?: string }; } +class PayloadCaptured extends Error { + constructor() { + super("payload captured"); + this.name = "PayloadCaptured"; + } +} + function makePayloadCaptureContext(): Context { return { messages: [{ role: "user", content: "Hello", timestamp: Date.now() }], @@ -29,7 +36,7 @@ async function capturePayload( apiKey: "fake-key", onPayload: (payload) => { capturedPayload = payload as AnthropicThinkingPayload; - return payload; + throw new PayloadCaptured(); }, }); diff --git a/packages/ai/test/bedrock-thinking-payload.test.ts b/packages/ai/test/bedrock-thinking-payload.test.ts index 63ed88455..55b9e82b7 100644 --- a/packages/ai/test/bedrock-thinking-payload.test.ts +++ b/packages/ai/test/bedrock-thinking-payload.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { type BedrockOptions, streamBedrock } from "../src/providers/amazon-bedrock.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { type BedrockOptions, streamBedrock } from "../src/providers/amazon-bedrock.ts"; +import type { Context, Model } from "../src/types.ts"; interface BedrockThinkingPayload { additionalModelRequestFields?: { @@ -11,6 +11,13 @@ interface BedrockThinkingPayload { }; } +class PayloadCaptured extends Error { + constructor() { + super("payload captured"); + this.name = "PayloadCaptured"; + } +} + function makeContext(): Context { return { messages: [{ role: "user", content: "Hello", timestamp: Date.now() }], @@ -25,10 +32,9 @@ async function capturePayload( const s = streamBedrock(model, makeContext(), { ...options, reasoning: options?.reasoning ?? "high", - signal: AbortSignal.abort(), onPayload: (payload) => { capturedPayload = payload as BedrockThinkingPayload; - return payload; + throw new PayloadCaptured(); }, }); @@ -137,10 +143,9 @@ describe("Application inference profile support", () => { messages: [{ role: "user", content: "Hello", timestamp: Date.now() }], }, { - signal: AbortSignal.abort(), onPayload: (payload) => { capturedPayload = payload; - return payload; + throw new PayloadCaptured(); }, }, ); diff --git a/packages/ai/test/cache-retention.test.ts b/packages/ai/test/cache-retention.test.ts index 2f234ab08..8828ba864 100644 --- a/packages/ai/test/cache-retention.test.ts +++ b/packages/ai/test/cache-retention.test.ts @@ -1,7 +1,24 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { stream } from "../src/stream.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamAnthropic } from "../src/providers/anthropic.ts"; +import { streamOpenAICompletions } from "../src/providers/openai-completions.ts"; +import { streamOpenAIResponses } from "../src/providers/openai-responses.ts"; +import { stream } from "../src/stream.ts"; +import type { Context, Model } from "../src/types.ts"; + +class PayloadCaptured extends Error { + constructor() { + super("payload captured"); + this.name = "PayloadCaptured"; + } +} + +function stopAfterPayload(capture: (payload: TPayload) => void): (payload: unknown) => never { + return (payload: unknown): never => { + capture(payload as TPayload); + throw new PayloadCaptured(); + }; +} describe("Cache Retention (PI_CACHE_RETENTION)", () => { const originalEnv = process.env.PI_CACHE_RETENTION; @@ -31,9 +48,9 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { let capturedPayload: any = null; const s = stream(model, context, { - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // Consume the stream to trigger the request @@ -54,9 +71,9 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { let capturedPayload: any = null; const s = stream(model, context, { - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // Consume the stream to trigger the request @@ -88,14 +105,13 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { // Since we can't easily test this without mocking, we'll skip the actual API call // and just verify the helper logic works correctly - const { streamAnthropic } = await import("../src/providers/anthropic.js"); try { const s = streamAnthropic(proxyModel, context, { apiKey: "fake-key", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // This will fail since we're using a fake key and fake proxy, but the payload should be captured @@ -119,15 +135,13 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { }; let capturedPayload: any = null; - const { streamAnthropic } = await import("../src/providers/anthropic.js"); - try { const s = streamAnthropic(proxyModel, context, { apiKey: "fake-key", cacheRetention: "long", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -145,15 +159,13 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { const baseModel = getModel("anthropic", "claude-haiku-4-5"); let capturedPayload: any = null; - const { streamAnthropic } = await import("../src/providers/anthropic.js"); - try { const s = streamAnthropic(baseModel, context, { apiKey: "fake-key", cacheRetention: "none", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -171,14 +183,12 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { const baseModel = getModel("anthropic", "claude-haiku-4-5"); let capturedPayload: any = null; - const { streamAnthropic } = await import("../src/providers/anthropic.js"); - try { const s = streamAnthropic(baseModel, context, { apiKey: "fake-key", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -199,15 +209,13 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { const baseModel = getModel("anthropic", "claude-haiku-4-5"); let capturedPayload: any = null; - const { streamAnthropic } = await import("../src/providers/anthropic.js"); - try { const s = streamAnthropic(baseModel, context, { apiKey: "fake-key", cacheRetention: "long", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -230,9 +238,9 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { let capturedPayload: any = null; const s = stream(model, context, { - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // Consume the stream to trigger the request @@ -253,9 +261,9 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { let capturedPayload: any = null; const s = stream(model, context, { - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // Consume the stream to trigger the request @@ -280,14 +288,12 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { let capturedPayload: any = null; - const { streamOpenAIResponses } = await import("../src/providers/openai-responses.js"); - try { const s = streamOpenAIResponses(proxyModel, context, { apiKey: "fake-key", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); // This will fail since we're using a fake key and fake proxy, but the payload should be captured @@ -309,16 +315,14 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { }; let capturedPayload: any = null; - const { streamOpenAIResponses } = await import("../src/providers/openai-responses.js"); - try { const s = streamOpenAIResponses(model, context, { apiKey: "fake-key", cacheRetention: "long", sessionId: "session-compat-false", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -336,16 +340,14 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { const model = getModel("openai", "gpt-4o-mini"); let capturedPayload: any = null; - const { streamOpenAIResponses } = await import("../src/providers/openai-responses.js"); - try { const s = streamOpenAIResponses(model, context, { apiKey: "fake-key", cacheRetention: "none", sessionId: "session-1", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -364,16 +366,14 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { const model = getModel("openai", "gpt-4o-mini"); let capturedPayload: any = null; - const { streamOpenAIResponses } = await import("../src/providers/openai-responses.js"); - try { const s = streamOpenAIResponses(model, context, { apiKey: "fake-key", cacheRetention: "long", sessionId: "session-2", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -408,16 +408,15 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { it("should set prompt_cache_retention for non-api.openai.com baseUrl by default", async () => { let capturedPayload: any = null; - const { streamOpenAICompletions } = await import("../src/providers/openai-completions.js"); try { const s = streamOpenAICompletions(createCompletionsModel(), context, { apiKey: "fake-key", cacheRetention: "long", sessionId: "session-completions", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { @@ -434,16 +433,15 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { it("should omit prompt_cache_retention when supportsLongCacheRetention is false", async () => { let capturedPayload: any = null; - const { streamOpenAICompletions } = await import("../src/providers/openai-completions.js"); try { const s = streamOpenAICompletions(createCompletionsModel({ supportsLongCacheRetention: false }), context, { apiKey: "fake-key", cacheRetention: "long", sessionId: "session-completions-false", - onPayload: (payload) => { + onPayload: stopAfterPayload((payload) => { capturedPayload = payload; - }, + }), }); for await (const event of s) { diff --git a/packages/ai/test/openai-codex-stream.test.ts b/packages/ai/test/openai-codex-stream.test.ts index 5c54fdb49..e50111c95 100644 --- a/packages/ai/test/openai-codex-stream.test.ts +++ b/packages/ai/test/openai-codex-stream.test.ts @@ -7,8 +7,8 @@ import { resetOpenAICodexWebSocketDebugStats, streamOpenAICodexResponses, streamSimpleOpenAICodexResponses, -} from "../src/providers/openai-codex-responses.js"; -import type { Context, Model } from "../src/types.js"; +} from "../src/providers/openai-codex-responses.ts"; +import type { Context, Model } from "../src/types.ts"; const originalAgentDir = process.env.PI_CODING_AGENT_DIR; @@ -173,7 +173,7 @@ describe("openai-codex streaming", () => { messages: [{ role: "user", content: "Say hello", timestamp: Date.now() }], }; - const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token }); + const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token, transport: "sse" }); let sawTextDelta = false; let sawDone = false; @@ -407,7 +407,7 @@ describe("openai-codex streaming", () => { messages: [{ role: "user", content: "Say hello", timestamp: Date.now() }], }; - const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token, sessionId }); + const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token, sessionId, transport: "sse" }); await streamResult.result(); }); @@ -513,7 +513,11 @@ describe("openai-codex streaming", () => { messages: [{ role: "user", content: "Say hello", timestamp: Date.now() }], }; - await streamSimpleOpenAICodexResponses(model, context, { apiKey: token, reasoning: "xhigh" }).result(); + await streamSimpleOpenAICodexResponses(model, context, { + apiKey: token, + reasoning: "xhigh", + transport: "sse", + }).result(); expect(requestedReasoning).toEqual({ effort: "xhigh", summary: "auto" }); }); @@ -559,6 +563,7 @@ describe("openai-codex streaming", () => { })}`, ].join("\n\n")}\n\n`; + let requestedReasoning: unknown; const encoder = new TextEncoder(); const stream = new ReadableStream({ start(controller) { @@ -577,7 +582,7 @@ describe("openai-codex streaming", () => { } if (url === "https://chatgpt.com/backend-api/codex/responses") { const body = typeof init?.body === "string" ? (JSON.parse(init.body) as Record) : null; - expect(body?.reasoning).toEqual({ effort: "low", summary: "auto" }); + requestedReasoning = body?.reasoning; return new Response(stream, { status: 200, @@ -596,6 +601,7 @@ describe("openai-codex streaming", () => { provider: "openai-codex", baseUrl: "https://chatgpt.com/backend-api", reasoning: true, + thinkingLevelMap: { minimal: "low" }, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 400000, @@ -610,8 +616,10 @@ describe("openai-codex streaming", () => { const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token, reasoningEffort: "minimal", + transport: "sse", }); await streamResult.result(); + expect(requestedReasoning).toEqual({ effort: "low", summary: "auto" }); }); it.each([ @@ -701,7 +709,11 @@ describe("openai-codex streaming", () => { messages: [{ role: "user", content: "Say hello", timestamp: Date.now() }], }; - const result = await streamOpenAICodexResponses(model, context, { apiKey: token, serviceTier }).result(); + const result = await streamOpenAICodexResponses(model, context, { + apiKey: token, + serviceTier, + transport: "sse", + }).result(); expect(result.usage.cost.input).toBe(1 * multiplier); expect(result.usage.cost.output).toBe(2 * multiplier); @@ -801,7 +813,7 @@ describe("openai-codex streaming", () => { }; // No sessionId provided - const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token }); + const streamResult = streamOpenAICodexResponses(model, context, { apiKey: token, transport: "sse" }); await streamResult.result(); }); it("forwards auto transport from streamSimple options and uses cached websocket context", async () => { diff --git a/test.sh b/test.sh index 67aaaeaf7..5f231845b 100755 --- a/test.sh +++ b/test.sh @@ -26,7 +26,10 @@ export PI_NO_LOCAL_LLM=1 unset ANTHROPIC_API_KEY unset ANTHROPIC_OAUTH_TOKEN unset OPENAI_API_KEY +unset AZURE_OPENAI_API_KEY +unset DEEPSEEK_API_KEY unset GEMINI_API_KEY +unset GOOGLE_CLOUD_API_KEY unset GROQ_API_KEY unset CEREBRAS_API_KEY unset XAI_API_KEY @@ -35,10 +38,20 @@ unset ZAI_API_KEY unset MISTRAL_API_KEY unset MINIMAX_API_KEY unset MINIMAX_CN_API_KEY +unset MOONSHOT_API_KEY unset KIMI_API_KEY unset HF_TOKEN +unset FIREWORKS_API_KEY +unset TOGETHER_API_KEY unset AI_GATEWAY_API_KEY unset OPENCODE_API_KEY +unset CLOUDFLARE_API_KEY +unset CLOUDFLARE_ACCOUNT_ID +unset CLOUDFLARE_GATEWAY_ID +unset XIAOMI_API_KEY +unset XIAOMI_TOKEN_PLAN_CN_API_KEY +unset XIAOMI_TOKEN_PLAN_AMS_API_KEY +unset XIAOMI_TOKEN_PLAN_SGP_API_KEY unset COPILOT_GITHUB_TOKEN unset GH_TOKEN unset GITHUB_TOKEN @@ -57,7 +70,6 @@ unset AWS_CONTAINER_CREDENTIALS_RELATIVE_URI unset AWS_CONTAINER_CREDENTIALS_FULL_URI unset AWS_WEB_IDENTITY_TOKEN_FILE unset BEDROCK_EXTENSIVE_MODEL_TEST -unset FIREWORKS_API_KEY echo "Running tests without API keys..." npm test From 849f9d9c5af90ec61371f97648ef40fd4a0a0479 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 20 May 2026 12:45:00 +0200 Subject: [PATCH 02/15] fix(coding-agent): configure HTTP idle timeout (#4759) --- packages/coding-agent/src/cli.ts | 15 ++--- .../coding-agent/src/core/http-dispatcher.ts | 55 +++++++++++++++++++ .../coding-agent/src/core/settings-manager.ts | 23 ++++++++ packages/coding-agent/src/main.ts | 2 + .../components/settings-selector.ts | 18 ++++++ .../src/modes/interactive/interactive-mode.ts | 9 +++ .../test/settings-manager.test.ts | 26 ++++++++- 7 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 packages/coding-agent/src/core/http-dispatcher.ts diff --git a/packages/coding-agent/src/cli.ts b/packages/coding-agent/src/cli.ts index 4f09675eb..b0b11ca5c 100644 --- a/packages/coding-agent/src/cli.ts +++ b/packages/coding-agent/src/cli.ts @@ -5,23 +5,16 @@ * * Test with: npx tsx src/cli-new.ts [args...] */ -import * as undici from "undici"; import { APP_NAME } from "./config.ts"; +import { configureHttpDispatcher } from "./core/http-dispatcher.ts"; import { main } from "./main.ts"; process.title = APP_NAME; process.env.PI_CODING_AGENT = "true"; process.emitWarning = (() => {}) as typeof process.emitWarning; -// bodyTimeout/headersTimeout default to 300s in undici; long local-LLM stalls -// (e.g. vLLM buffering a large tool call) exceed that and abort the SSE stream -// with UND_ERR_BODY_TIMEOUT. Disable both — provider SDKs enforce their own -// AbortController-based deadlines via retry.provider.timeoutMs. -undici.setGlobalDispatcher(new undici.EnvHttpProxyAgent({ allowH2: false, bodyTimeout: 0, headersTimeout: 0 })); - -// Keep fetch and the dispatcher on the same undici implementation. Node 26.0's -// bundled fetch can otherwise consume compressed responses through npm undici's -// dispatcher without decompressing them, causing response.json() failures. -undici.install?.(); +// Configure undici's global dispatcher before provider SDKs issue requests. +// Runtime settings are applied once SettingsManager has loaded global/project settings. +configureHttpDispatcher(); main(process.argv.slice(2)); diff --git a/packages/coding-agent/src/core/http-dispatcher.ts b/packages/coding-agent/src/core/http-dispatcher.ts new file mode 100644 index 000000000..12ce9fb03 --- /dev/null +++ b/packages/coding-agent/src/core/http-dispatcher.ts @@ -0,0 +1,55 @@ +import * as undici from "undici"; + +export const DEFAULT_HTTP_IDLE_TIMEOUT_MS = 300_000; + +export const HTTP_IDLE_TIMEOUT_CHOICES = [ + { label: "30 sec", timeoutMs: 30_000 }, + { label: "1 min", timeoutMs: 60_000 }, + { label: "2 min", timeoutMs: 120_000 }, + { label: "5 min", timeoutMs: 300_000 }, + { label: "disabled", timeoutMs: 0 }, +] as const; + +export function parseHttpIdleTimeoutMs(value: unknown): number | undefined { + if (typeof value === "string") { + const trimmed = value.trim(); + if (trimmed.toLowerCase() === "disabled") { + return 0; + } + if (trimmed.length === 0) { + return undefined; + } + return parseHttpIdleTimeoutMs(Number(trimmed)); + } + + if (typeof value !== "number" || !Number.isFinite(value) || value < 0) { + return undefined; + } + return Math.floor(value); +} + +export function formatHttpIdleTimeoutMs(timeoutMs: number): string { + const choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.timeoutMs === timeoutMs); + if (choice) { + return choice.label; + } + return `${timeoutMs / 1000} sec`; +} + +export function configureHttpDispatcher(timeoutMs: number = DEFAULT_HTTP_IDLE_TIMEOUT_MS): void { + const normalizedTimeoutMs = parseHttpIdleTimeoutMs(timeoutMs); + if (normalizedTimeoutMs === undefined) { + throw new Error(`Invalid HTTP idle timeout: ${String(timeoutMs)}`); + } + undici.setGlobalDispatcher( + new undici.EnvHttpProxyAgent({ + allowH2: false, + bodyTimeout: normalizedTimeoutMs, + headersTimeout: normalizedTimeoutMs, + }), + ); + // Keep fetch and the dispatcher on the same undici implementation. Node 26.0's + // bundled fetch can otherwise consume compressed responses through npm undici's + // dispatcher without decompressing them, causing response.json() failures. + undici.install?.(); +} diff --git a/packages/coding-agent/src/core/settings-manager.ts b/packages/coding-agent/src/core/settings-manager.ts index 7dc6931e4..2fedad359 100644 --- a/packages/coding-agent/src/core/settings-manager.ts +++ b/packages/coding-agent/src/core/settings-manager.ts @@ -4,6 +4,7 @@ import { homedir } from "os"; import { dirname, join } from "path"; import lockfile from "proper-lockfile"; import { CONFIG_DIR_NAME, getAgentDir } from "../config.ts"; +import { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from "./http-dispatcher.ts"; export interface CompactionSettings { enabled?: boolean; // default: true @@ -110,6 +111,7 @@ export interface Settings { markdown?: MarkdownSettings; warnings?: WarningSettings; sessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag) + httpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it } /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */ @@ -726,6 +728,27 @@ export class SettingsManager { }; } + getHttpIdleTimeoutMs(): number { + const value = this.settings.httpIdleTimeoutMs; + const timeoutMs = parseHttpIdleTimeoutMs(value); + if (timeoutMs !== undefined) { + return timeoutMs; + } + if (value !== undefined) { + throw new Error(`Invalid httpIdleTimeoutMs setting: ${String(value)}`); + } + return DEFAULT_HTTP_IDLE_TIMEOUT_MS; + } + + setHttpIdleTimeoutMs(timeoutMs: number): void { + if (!Number.isFinite(timeoutMs) || timeoutMs < 0) { + throw new Error(`Invalid httpIdleTimeoutMs setting: ${String(timeoutMs)}`); + } + this.globalSettings.httpIdleTimeoutMs = Math.floor(timeoutMs); + this.markModified("httpIdleTimeoutMs"); + this.save(); + } + getProviderRetrySettings(): { timeoutMs?: number; maxRetries?: number; maxRetryDelayMs: number } { return { timeoutMs: this.settings.retry?.provider?.timeoutMs, diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index 141a34e75..47f53c3db 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -26,6 +26,7 @@ import { formatNoModelsAvailableMessage } from "./core/auth-guidance.ts"; import { AuthStorage } from "./core/auth-storage.ts"; import { exportFromFile } from "./core/export-html/index.ts"; import type { ExtensionFactory } from "./core/extensions/types.ts"; +import { configureHttpDispatcher } from "./core/http-dispatcher.ts"; import { KeybindingsManager } from "./core/keybindings.ts"; import type { ModelRegistry } from "./core/model-registry.ts"; import { resolveCliModel, resolveModelScope, type ScopedModel } from "./core/model-resolver.ts"; @@ -617,6 +618,7 @@ export async function main(args: string[], options?: MainOptions) { }); const { services, session, modelFallbackMessage } = runtime; const { settingsManager, modelRegistry, resourceLoader } = services; + configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs()); if (parsed.help) { const extensionFlags = resourceLoader diff --git a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts index f99d73814..7d210028a 100644 --- a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts @@ -11,6 +11,7 @@ import { Spacer, Text, } from "@earendil-works/pi-tui"; +import { formatHttpIdleTimeoutMs, HTTP_IDLE_TIMEOUT_CHOICES } from "../../../core/http-dispatcher.ts"; import type { WarningSettings } from "../../../core/settings-manager.ts"; import { getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme.ts"; import { DynamicBorder } from "./dynamic-border.ts"; @@ -40,6 +41,7 @@ export interface SettingsConfig { steeringMode: "all" | "one-at-a-time"; followUpMode: "all" | "one-at-a-time"; transport: Transport; + httpIdleTimeoutMs: number; thinkingLevel: ThinkingLevel; availableThinkingLevels: ThinkingLevel[]; currentTheme: string; @@ -68,6 +70,7 @@ export interface SettingsCallbacks { onSteeringModeChange: (mode: "all" | "one-at-a-time") => void; onFollowUpModeChange: (mode: "all" | "one-at-a-time") => void; onTransportChange: (transport: Transport) => void; + onHttpIdleTimeoutMsChange: (timeoutMs: number) => void; onThinkingLevelChange: (level: ThinkingLevel) => void; onThemeChange: (theme: string) => void; onThemePreview?: (theme: string) => void; @@ -238,6 +241,14 @@ export class SettingsSelectorComponent extends Container { currentValue: config.transport, values: ["sse", "websocket", "websocket-cached", "auto"], }, + { + id: "http-idle-timeout", + label: "HTTP idle timeout", + description: + "Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.", + currentValue: formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs), + values: HTTP_IDLE_TIMEOUT_CHOICES.map((choice) => choice.label), + }, { id: "hide-thinking", label: "Hide thinking", @@ -482,6 +493,13 @@ export class SettingsSelectorComponent extends Container { case "transport": callbacks.onTransportChange(newValue as Transport); break; + case "http-idle-timeout": { + const choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.label === newValue); + if (choice) { + callbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs); + } + break; + } case "hide-thinking": callbacks.onHideThinkingBlockChange(newValue === "true"); break; diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index c93beb93a..aa8db52b7 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -71,6 +71,7 @@ import type { ExtensionWidgetOptions, } from "../../core/extensions/index.ts"; import { FooterDataProvider, type ReadonlyFooterDataProvider } from "../../core/footer-data-provider.ts"; +import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.ts"; import { type AppKeybinding, KeybindingsManager } from "../../core/keybindings.ts"; import { createCompactionSummaryMessage } from "../../core/messages.ts"; import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope } from "../../core/model-resolver.ts"; @@ -1566,6 +1567,7 @@ export class InteractiveMode { } private applyRuntimeSettings(): void { + configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs()); this.footer.setSession(this.session); this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled); this.footerDataProvider.setCwd(this.sessionManager.getCwd()); @@ -3846,6 +3848,7 @@ export class InteractiveMode { steeringMode: this.session.steeringMode, followUpMode: this.session.followUpMode, transport: this.settingsManager.getTransport(), + httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(), thinkingLevel: this.session.thinkingLevel, availableThinkingLevels: this.session.getAvailableThinkingLevels(), currentTheme: this.settingsManager.getTheme() || "dark", @@ -3904,6 +3907,11 @@ export class InteractiveMode { this.settingsManager.setTransport(transport); this.session.agent.transport = transport; }, + onHttpIdleTimeoutMsChange: (timeoutMs) => { + this.settingsManager.setHttpIdleTimeoutMs(timeoutMs); + configureHttpDispatcher(timeoutMs); + this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`); + }, onThinkingLevelChange: (level) => { this.session.setThinkingLevel(level); this.footer.invalidate(); @@ -4891,6 +4899,7 @@ export class InteractiveMode { try { await this.session.reload(); + configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs()); this.keybindings.reload(); const activeHeader = this.customHeader ?? this.builtInHeader; if (isExpandable(activeHeader)) { diff --git a/packages/coding-agent/test/settings-manager.test.ts b/packages/coding-agent/test/settings-manager.test.ts index d01b1363d..a503e3ccc 100644 --- a/packages/coding-agent/test/settings-manager.test.ts +++ b/packages/coding-agent/test/settings-manager.test.ts @@ -2,7 +2,8 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"; import { homedir } from "os"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { DEFAULT_HTTP_IDLE_TIMEOUT_MS } from "../src/core/http-dispatcher.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; describe("SettingsManager", () => { const testDir = join(process.cwd(), "test-settings-tmp"); @@ -257,6 +258,29 @@ describe("SettingsManager", () => { }); }); + describe("httpIdleTimeoutMs", () => { + it("should default to 5 minutes", () => { + const manager = SettingsManager.create(projectDir, agentDir); + expect(manager.getHttpIdleTimeoutMs()).toBe(DEFAULT_HTTP_IDLE_TIMEOUT_MS); + }); + + it("should use merged global and project settings", () => { + writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ httpIdleTimeoutMs: 300000 })); + writeFileSync(join(projectDir, ".pi", "settings.json"), JSON.stringify({ httpIdleTimeoutMs: 0 })); + + const manager = SettingsManager.create(projectDir, agentDir); + + expect(manager.getHttpIdleTimeoutMs()).toBe(0); + }); + + it("should reject invalid timeout values", () => { + writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ httpIdleTimeoutMs: -1 })); + const manager = SettingsManager.create(projectDir, agentDir); + + expect(() => manager.getHttpIdleTimeoutMs()).toThrow("Invalid httpIdleTimeoutMs setting"); + }); + }); + describe("shellCommandPrefix", () => { it("should load shellCommandPrefix from settings", () => { const settingsPath = join(agentDir, "settings.json"); From 2e02c74dcb9787e3feca7fad67082faed4a1b3cd Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 12:44:04 +0200 Subject: [PATCH 03/15] chore: pin dependencies and use native TypeScript --- package-lock.json | 140 ++++++++---------- package.json | 17 +-- packages/agent/package.json | 14 +- packages/agent/test/agent-loop.test.ts | 4 +- packages/agent/test/agent.test.ts | 2 +- packages/agent/test/e2e.test.ts | 4 +- .../test/harness/agent-harness-stream.test.ts | 10 +- .../agent/test/harness/agent-harness.test.ts | 16 +- .../agent/test/harness/compaction.test.ts | 10 +- .../agent/test/harness/nodejs-env.test.ts | 8 +- .../test/harness/prompt-templates.test.ts | 6 +- packages/agent/test/harness/repo.test.ts | 8 +- .../test/harness/resource-formatting.test.ts | 4 +- .../agent/test/harness/session-uuid.test.ts | 2 +- packages/agent/test/harness/session.test.ts | 12 +- packages/agent/test/harness/skills.test.ts | 6 +- packages/agent/test/harness/storage.test.ts | 10 +- .../agent/test/harness/system-prompt.test.ts | 2 +- packages/agent/test/harness/truncate.test.ts | 2 +- packages/agent/test/scratch/simple.ts | 7 +- packages/agent/test/utils/calculate.ts | 2 +- packages/agent/test/utils/get-current-time.ts | 2 +- packages/ai/package.json | 26 ++-- packages/ai/scripts/generate-image-models.ts | 4 +- packages/ai/scripts/generate-models.ts | 12 +- packages/ai/scripts/generate-test-image.ts | 5 +- packages/ai/test/abort.test.ts | 12 +- .../anthropic-eager-tool-input-compat.test.ts | 4 +- .../anthropic-eager-tool-input-e2e.test.ts | 10 +- ...anthropic-long-cache-retention-e2e.test.ts | 10 +- packages/ai/test/anthropic-oauth.test.ts | 2 +- .../ai/test/anthropic-opus-4-7-smoke.test.ts | 6 +- .../ai/test/anthropic-sse-parsing.test.ts | 6 +- .../anthropic-tool-name-normalization.test.ts | 8 +- .../ai/test/azure-openai-base-url.test.ts | 6 +- .../ai/test/bedrock-convert-messages.test.ts | 6 +- .../test/bedrock-endpoint-resolution.test.ts | 6 +- packages/ai/test/bedrock-models.test.ts | 8 +- .../ai/test/codex-websocket-cached-probe.ts | 12 +- packages/ai/test/context-overflow.test.ts | 14 +- .../ai/test/cross-provider-handoff.test.ts | 12 +- packages/ai/test/empty.test.ts | 14 +- packages/ai/test/env-api-keys.test.ts | 2 +- packages/ai/test/faux-provider.test.ts | 4 +- packages/ai/test/fireworks-models.test.ts | 8 +- .../ai/test/github-copilot-anthropic.test.ts | 6 +- packages/ai/test/github-copilot-oauth.test.ts | 2 +- .../test/google-shared-convert-tools.test.ts | 4 +- ...-shared-gemini3-unsigned-tool-call.test.ts | 4 +- ...e-shared-image-tool-result-routing.test.ts | 4 +- .../ai/test/google-thinking-disable.test.ts | 6 +- .../ai/test/google-thinking-signature.test.ts | 2 +- .../google-vertex-api-key-resolution.test.ts | 6 +- packages/ai/test/image-tool-result.test.ts | 12 +- packages/ai/test/images.test.ts | 6 +- packages/ai/test/interleaved-thinking.test.ts | 12 +- packages/ai/test/lazy-module-load.test.ts | 5 +- .../ai/test/mistral-reasoning-mode.test.ts | 6 +- packages/ai/test/mistral-tool-schema.test.ts | 6 +- packages/ai/test/node-http-proxy.test.ts | 2 +- packages/ai/test/oauth.ts | 4 +- .../openai-codex-cache-affinity-e2e.test.ts | 8 +- packages/ai/test/openai-codex-oauth.test.ts | 2 +- ...i-completions-cache-control-format.test.ts | 6 +- .../openai-completions-empty-tools.test.ts | 4 +- .../openai-completions-prompt-cache.test.ts | 6 +- .../openai-completions-response-model.test.ts | 4 +- ...penai-completions-thinking-as-text.test.ts | 4 +- .../openai-completions-tool-choice.test.ts | 8 +- ...nai-completions-tool-result-images.test.ts | 6 +- ...penai-responses-cache-affinity-e2e.test.ts | 6 +- .../openai-responses-copilot-provider.test.ts | 6 +- ...enai-responses-foreign-toolcall-id.test.ts | 8 +- ...nai-responses-partial-json-cleanup.test.ts | 6 +- ...nai-responses-reasoning-replay-e2e.test.ts | 6 +- ...penai-responses-tool-result-images.test.ts | 8 +- .../test/openrouter-cache-write-repro.test.ts | 4 +- packages/ai/test/openrouter-images.test.ts | 4 +- packages/ai/test/overflow.test.ts | 4 +- packages/ai/test/responseid.test.ts | 10 +- packages/ai/test/stream.test.ts | 16 +- packages/ai/test/supports-xhigh.test.ts | 2 +- packages/ai/test/together-models.test.ts | 4 +- packages/ai/test/tokens.test.ts | 14 +- .../test/tool-call-id-normalization.test.ts | 8 +- .../ai/test/tool-call-without-result.test.ts | 14 +- packages/ai/test/total-tokens.test.ts | 14 +- ...ssages-copilot-openai-to-anthropic.test.ts | 4 +- packages/ai/test/unicode-surrogate.test.ts | 14 +- packages/ai/test/validation.test.ts | 4 +- packages/ai/test/xhigh.test.ts | 6 +- packages/ai/test/zen.test.ts | 6 +- .../custom-provider-anthropic/package.json | 2 +- .../custom-provider-gitlab-duo/test.ts | 2 +- .../extensions/doom-overlay/doom-component.ts | 4 +- .../examples/extensions/doom-overlay/index.ts | 6 +- .../examples/extensions/plan-mode/index.ts | 2 +- .../examples/extensions/sandbox/package.json | 2 +- .../examples/extensions/subagent/index.ts | 2 +- .../extensions/with-deps/package.json | 4 +- packages/coding-agent/package.json | 48 +++--- ...gent-session-auto-compaction-queue.test.ts | 12 +- .../test/agent-session-branching.test.ts | 10 +- .../test/agent-session-compaction.test.ts | 14 +- .../test/agent-session-concurrent.test.ts | 14 +- .../agent-session-dynamic-provider.test.ts | 12 +- .../test/agent-session-dynamic-tools.test.ts | 8 +- .../test/agent-session-retry.test.ts | 12 +- .../test/agent-session-runtime-events.test.ts | 8 +- .../test/agent-session-stats.test.ts | 12 +- .../agent-session-tree-navigation.test.ts | 2 +- packages/coding-agent/test/ansi-utils.test.ts | 2 +- packages/coding-agent/test/args.test.ts | 2 +- .../test/assistant-message.test.ts | 4 +- .../coding-agent/test/auth-storage.test.ts | 4 +- .../test/bash-close-hang-windows.test.ts | 4 +- .../test/bash-execution-width.test.ts | 4 +- .../coding-agent/test/block-images.test.ts | 6 +- .../clipboard-image-bmp-conversion.test.ts | 2 +- .../coding-agent/test/clipboard-image.test.ts | 10 +- packages/coding-agent/test/clipboard.test.ts | 2 +- .../compaction-extensions-example.test.ts | 2 +- .../test/compaction-extensions.test.ts | 18 +-- .../test/compaction-serialization.test.ts | 2 +- .../test/compaction-summary-reasoning.test.ts | 2 +- packages/coding-agent/test/compaction.test.ts | 4 +- packages/coding-agent/test/config.test.ts | 2 +- .../test/edit-tool-legacy-input.test.ts | 4 +- .../test/edit-tool-no-full-redraw.test.ts | 8 +- .../test/export-html-whitespace.test.ts | 8 +- .../test/extensions-discovery.test.ts | 6 +- .../test/extensions-input-event.test.ts | 10 +- .../test/extensions-runner.test.ts | 14 +- .../test/file-mutation-queue.test.ts | 6 +- .../test/footer-data-provider.test.ts | 2 +- .../coding-agent/test/footer-width.test.ts | 8 +- .../coding-agent/test/frontmatter.test.ts | 2 +- .../coding-agent/test/git-ssh-url.test.ts | 2 +- packages/coding-agent/test/git-update.test.ts | 4 +- .../test/image-processing.test.ts | 4 +- .../test/image-resize-callers.test.ts | 6 +- .../coding-agent/test/initial-message.test.ts | 4 +- ...interactive-mode-anthropic-warning.test.ts | 2 +- .../interactive-mode-clone-command.test.ts | 2 +- .../test/interactive-mode-compaction.test.ts | 2 +- .../interactive-mode-import-command.test.ts | 4 +- .../test/interactive-mode-status.test.ts | 8 +- .../test/interactive-mode-suspend.test.ts | 2 +- .../test/keybindings-migration.test.ts | 6 +- .../coding-agent/test/model-registry.test.ts | 4 +- .../coding-agent/test/model-resolver.test.ts | 2 +- .../coding-agent/test/oauth-selector.test.ts | 14 +- .../test/package-command-paths.test.ts | 4 +- .../test/package-manager-ssh.test.ts | 4 +- .../coding-agent/test/package-manager.test.ts | 8 +- packages/coding-agent/test/path-utils.test.ts | 2 +- packages/coding-agent/test/paths.test.ts | 2 +- .../coding-agent/test/pi-user-agent.test.ts | 2 +- .../coding-agent/test/plan-mode-utils.test.ts | 2 +- packages/coding-agent/test/print-mode.test.ts | 4 +- .../test/prompt-templates.test.ts | 4 +- .../coding-agent/test/resource-loader.test.ts | 16 +- .../test/restore-sandbox-env.test.ts | 2 +- .../test/rpc-client-clone.test.ts | 2 +- packages/coding-agent/test/rpc-example.ts | 2 +- packages/coding-agent/test/rpc-jsonl.test.ts | 2 +- .../rpc-prompt-response-semantics.test.ts | 16 +- packages/coding-agent/test/rpc.test.ts | 2 +- .../test/sdk-codex-cache-probe-tool-loop.ts | 22 +-- .../test/sdk-openrouter-attribution.test.ts | 10 +- .../test/sdk-session-manager.test.ts | 4 +- packages/coding-agent/test/sdk-skills.test.ts | 10 +- .../coding-agent/test/session-cwd.test.ts | 6 +- .../session-info-modified-timestamp.test.ts | 6 +- .../session-manager/build-context.test.ts | 2 +- .../session-manager/custom-session-id.test.ts | 2 +- .../session-manager/file-operations.test.ts | 2 +- .../test/session-manager/labels.test.ts | 2 +- .../test/session-manager/migration.test.ts | 2 +- .../test/session-manager/save-entry.test.ts | 2 +- .../session-manager/tree-traversal.test.ts | 4 +- .../test/session-selector-path-delete.test.ts | 8 +- .../test/session-selector-rename.test.ts | 8 +- .../test/session-selector-search.test.ts | 4 +- .../test/settings-manager-bug.test.ts | 2 +- packages/coding-agent/test/skills.test.ts | 6 +- .../test/stdout-cleanliness.test.ts | 5 +- .../test/streaming-render-debug.ts | 4 +- .../agent-session-bash-persistence.test.ts | 4 +- .../suite/agent-session-compaction.test.ts | 2 +- .../agent-session-model-extension.test.ts | 4 +- .../test/suite/agent-session-prompt.test.ts | 8 +- .../test/suite/agent-session-queue.test.ts | 2 +- .../suite/agent-session-retry-events.test.ts | 2 +- .../test/suite/agent-session-runtime.test.ts | 8 +- packages/coding-agent/test/suite/harness.ts | 20 +-- ...113-agent-session-event-settlement.test.ts | 2 +- ...2023-queued-slash-command-followup.test.ts | 2 +- ...753-reload-stale-resource-settings.test.ts | 6 +- .../2781-skill-collision-precedence.test.ts | 2 +- .../2791-fswatch-error-crash.test.ts | 4 +- ...-allowlist-filters-extension-tools.test.ts | 8 +- .../2860-replaced-session-context.test.ts | 10 +- .../3217-scoped-model-order.test.ts | 12 +- .../regressions/3302-find-path-glob.test.ts | 2 +- .../3303-find-nested-gitignore.test.ts | 2 +- ...3317-network-connection-lost-retry.test.ts | 2 +- ...uiltin-tools-keeps-extension-tools.test.ts | 10 +- .../3616-settings-inmemory-reload.test.ts | 4 +- .../3686-session-name-event.test.ts | 4 +- .../3688-tree-cancel-compacting.test.ts | 4 +- .../3982-message-end-cost-override.test.ts | 2 +- ...hinking-toggle-pending-tool-render.test.ts | 12 +- .../test/syntax-highlight.test.ts | 2 +- .../coding-agent/test/system-prompt.test.ts | 2 +- .../coding-agent/test/test-harness.test.ts | 2 +- packages/coding-agent/test/test-harness.ts | 16 +- .../coding-agent/test/test-theme-colors.ts | 2 +- .../coding-agent/test/theme-detection.test.ts | 2 +- .../coding-agent/test/theme-export.test.ts | 2 +- .../test/tool-execution-component.test.ts | 16 +- packages/coding-agent/test/tools.test.ts | 10 +- .../coding-agent/test/tree-selector.test.ts | 8 +- .../test/trigger-compact-extension.test.ts | 4 +- .../coding-agent/test/user-message.test.ts | 4 +- packages/coding-agent/test/utilities.ts | 20 +-- .../coding-agent/test/version-check.test.ts | 2 +- packages/tui/package.json | 14 +- packages/tui/test/autocomplete.test.ts | 2 +- ...ression-isimageline-startswith-bug.test.ts | 20 +-- packages/tui/test/chat-simple.ts | 16 +- packages/tui/test/editor.test.ts | 12 +- packages/tui/test/fuzzy.test.ts | 2 +- packages/tui/test/image-test.ts | 12 +- packages/tui/test/input.test.ts | 4 +- packages/tui/test/key-tester.ts | 6 +- packages/tui/test/keybindings.test.ts | 2 +- packages/tui/test/keys.test.ts | 2 +- packages/tui/test/markdown.test.ts | 10 +- .../tui/test/overlay-non-capturing.test.ts | 6 +- packages/tui/test/overlay-options.test.ts | 6 +- .../tui/test/overlay-short-content.test.ts | 4 +- ...egression-regional-indicator-width.test.ts | 2 +- packages/tui/test/select-list.test.ts | 4 +- packages/tui/test/stdin-buffer.test.ts | 2 +- packages/tui/test/terminal-image.test.ts | 4 +- packages/tui/test/terminal.test.ts | 2 +- packages/tui/test/test-themes.ts | 2 +- packages/tui/test/truncate-to-width.test.ts | 2 +- packages/tui/test/truncated-text.test.ts | 4 +- packages/tui/test/tui-cell-size-input.test.ts | 6 +- .../tui/test/tui-overlay-style-leak.test.ts | 4 +- packages/tui/test/tui-render.test.ts | 6 +- packages/tui/test/viewport-overwrite-repro.ts | 4 +- packages/tui/test/virtual-terminal.ts | 2 +- packages/tui/test/wrap-ansi.test.ts | 2 +- scripts/cost.ts | 2 +- scripts/session-transcripts.ts | 6 +- scripts/stats.ts | 2 +- scripts/tool-stats.ts | 2 +- 260 files changed, 862 insertions(+), 897 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38e1232f8..9af10d5bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,19 +14,16 @@ "packages/coding-agent/examples/extensions/custom-provider-gitlab-duo", "packages/coding-agent/examples/extensions/sandbox" ], - "dependencies": { - "@earendil-works/pi-coding-agent": "^0.30.2" - }, "devDependencies": { - "@anthropic-ai/sandbox-runtime": "^0.0.26", + "@anthropic-ai/sandbox-runtime": "0.0.26", "@biomejs/biome": "2.3.5", - "@types/node": "^22.10.5", + "@types/node": "22.19.19", "@typescript/native-preview": "7.0.0-dev.20260120.1", - "husky": "^9.1.7", - "jiti": "^2.7.0", - "shx": "^0.4.0", - "tsx": "^4.20.3", - "typescript": "^5.9.2" + "esbuild": "0.28.0", + "husky": "9.1.7", + "jiti": "2.7.0", + "shx": "0.4.0", + "typescript": "5.9.3" }, "engines": { "node": ">=22.19.0" @@ -5089,25 +5086,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz", - "integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6004,15 +5982,15 @@ "license": "MIT", "dependencies": { "@earendil-works/pi-ai": "^0.75.3", - "ignore": "^7.0.5", - "typebox": "^1.1.24", - "yaml": "^2.8.2" + "ignore": "7.0.5", + "typebox": "1.1.38", + "yaml": "2.9.0" }, "devDependencies": { - "@types/node": "^24.3.0", - "@vitest/coverage-v8": "^3.2.4", - "typescript": "^5.7.3", - "vitest": "^3.2.4" + "@types/node": "24.12.4", + "@vitest/coverage-v8": "3.2.4", + "typescript": "5.9.3", + "vitest": "3.2.4" }, "engines": { "node": ">=22.19.0" @@ -6040,23 +6018,23 @@ "version": "0.75.3", "license": "MIT", "dependencies": { - "@anthropic-ai/sdk": "^0.91.1", - "@aws-sdk/client-bedrock-runtime": "^3.1030.0", - "@google/genai": "^1.40.0", - "@mistralai/mistralai": "^2.2.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.1", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", "openai": "6.26.0", - "partial-json": "^0.1.7", - "typebox": "^1.1.24" + "partial-json": "0.1.7", + "typebox": "1.1.38" }, "bin": { "pi-ai": "dist/cli.js" }, "devDependencies": { - "@types/node": "^24.3.0", - "canvas": "^3.2.0", - "vitest": "^3.2.4" + "@types/node": "24.12.4", + "canvas": "3.2.3", + "vitest": "3.2.4" }, "engines": { "node": ">=22.19.0" @@ -6087,47 +6065,47 @@ "@earendil-works/pi-agent-core": "^0.75.3", "@earendil-works/pi-ai": "^0.75.3", "@earendil-works/pi-tui": "^0.75.3", - "@silvia-odwyer/photon-node": "^0.3.4", - "chalk": "^5.5.0", - "cross-spawn": "^7.0.6", - "diff": "^8.0.2", - "glob": "^13.0.1", - "highlight.js": "^10.7.3", - "hosted-git-info": "^9.0.2", - "ignore": "^7.0.5", - "jiti": "^2.7.0", - "minimatch": "^10.2.3", - "proper-lockfile": "^4.1.2", - "typebox": "^1.1.24", - "undici": "^8.3.0", - "yaml": "^2.8.2" + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "glob": "13.0.6", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "typebox": "1.1.38", + "undici": "8.3.0", + "yaml": "2.9.0" }, "bin": { "pi": "dist/cli.js" }, "devDependencies": { - "@types/cross-spawn": "^6.0.6", - "@types/diff": "^7.0.2", - "@types/hosted-git-info": "^3.0.5", - "@types/ms": "^2.1.0", - "@types/node": "^24.3.0", - "@types/proper-lockfile": "^4.1.4", - "shx": "^0.4.0", - "typescript": "^5.7.3", - "vitest": "^3.2.4" + "@types/cross-spawn": "6.0.6", + "@types/diff": "7.0.2", + "@types/hosted-git-info": "3.0.5", + "@types/ms": "2.1.0", + "@types/node": "24.12.4", + "@types/proper-lockfile": "4.1.4", + "shx": "0.4.0", + "typescript": "5.9.3", + "vitest": "3.2.4" }, "engines": { "node": ">=22.19.0" }, "optionalDependencies": { - "@mariozechner/clipboard": "^0.3.6" + "@mariozechner/clipboard": "0.3.6" } }, "packages/coding-agent/examples/extensions/custom-provider-anthropic": { "name": "pi-extension-custom-provider-anthropic", "version": "0.75.3", "dependencies": { - "@anthropic-ai/sdk": "^0.52.0" + "@anthropic-ai/sdk": "0.52.0" } }, "packages/coding-agent/examples/extensions/custom-provider-gitlab-duo": { @@ -6138,17 +6116,17 @@ "name": "pi-extension-sandbox", "version": "1.5.3", "dependencies": { - "@anthropic-ai/sandbox-runtime": "^0.0.26" + "@anthropic-ai/sandbox-runtime": "0.0.26" } }, "packages/coding-agent/examples/extensions/with-deps": { "name": "pi-extension-with-deps", "version": "0.75.3", "dependencies": { - "ms": "^2.1.3" + "ms": "2.1.3" }, "devDependencies": { - "@types/ms": "^2.1.0" + "@types/ms": "2.1.0" } }, "packages/coding-agent/node_modules/@anthropic-ai/sdk": { @@ -6182,19 +6160,19 @@ "version": "0.75.3", "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.3.0", - "marked": "^15.0.12" + "get-east-asian-width": "1.6.0", + "marked": "15.0.12" }, "devDependencies": { - "@xterm/headless": "^5.5.0", - "@xterm/xterm": "^5.5.0", - "chalk": "^5.5.0" + "@xterm/headless": "5.5.0", + "@xterm/xterm": "5.5.0", + "chalk": "5.6.2" }, "engines": { "node": ">=22.19.0" }, "optionalDependencies": { - "koffi": "^2.9.0" + "koffi": "2.16.2" } } } diff --git a/package.json b/package.json index c0b10fe0b..cd0fed1a6 100644 --- a/package.json +++ b/package.json @@ -30,23 +30,20 @@ "prepare": "husky" }, "devDependencies": { - "@anthropic-ai/sandbox-runtime": "^0.0.26", + "@anthropic-ai/sandbox-runtime": "0.0.26", "@biomejs/biome": "2.3.5", - "@types/node": "^22.10.5", + "@types/node": "22.19.19", "@typescript/native-preview": "7.0.0-dev.20260120.1", - "husky": "^9.1.7", - "jiti": "^2.7.0", - "tsx": "^4.20.3", - "typescript": "^5.9.2", - "shx": "^0.4.0" + "esbuild": "0.28.0", + "husky": "9.1.7", + "jiti": "2.7.0", + "shx": "0.4.0", + "typescript": "5.9.3" }, "engines": { "node": ">=22.19.0" }, "version": "0.0.3", - "dependencies": { - "@earendil-works/pi-coding-agent": "^0.30.2" - }, "overrides": { "rimraf": "6.1.2", "gaxios": { diff --git a/packages/agent/package.json b/packages/agent/package.json index 37e666bab..d8bf0656c 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -30,9 +30,9 @@ }, "dependencies": { "@earendil-works/pi-ai": "^0.75.3", - "ignore": "^7.0.5", - "typebox": "^1.1.24", - "yaml": "^2.8.2" + "ignore": "7.0.5", + "typebox": "1.1.38", + "yaml": "2.9.0" }, "keywords": [ "ai", @@ -52,9 +52,9 @@ "node": ">=22.19.0" }, "devDependencies": { - "@types/node": "^24.3.0", - "@vitest/coverage-v8": "^3.2.4", - "typescript": "^5.7.3", - "vitest": "^3.2.4" + "@types/node": "24.12.4", + "@vitest/coverage-v8": "3.2.4", + "typescript": "5.9.3", + "vitest": "3.2.4" } } diff --git a/packages/agent/test/agent-loop.test.ts b/packages/agent/test/agent-loop.test.ts index 261b42fc7..62eadf810 100644 --- a/packages/agent/test/agent-loop.test.ts +++ b/packages/agent/test/agent-loop.test.ts @@ -8,8 +8,8 @@ import { } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { agentLoop, agentLoopContinue } from "../src/agent-loop.js"; -import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentTool } from "../src/types.js"; +import { agentLoop, agentLoopContinue } from "../src/agent-loop.ts"; +import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentTool } from "../src/types.ts"; // Mock stream for testing - mimics MockAssistantStream class MockAssistantStream extends EventStream { diff --git a/packages/agent/test/agent.test.ts b/packages/agent/test/agent.test.ts index 9c38ae8c1..82cc58dee 100644 --- a/packages/agent/test/agent.test.ts +++ b/packages/agent/test/agent.test.ts @@ -1,6 +1,6 @@ import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@earendil-works/pi-ai"; import { describe, expect, it } from "vitest"; -import { Agent } from "../src/index.js"; +import { Agent } from "../src/index.ts"; // Mock stream that mimics AssistantMessageEventStream class MockAssistantStream extends EventStream { diff --git a/packages/agent/test/e2e.test.ts b/packages/agent/test/e2e.test.ts index b75645b06..309536ad2 100644 --- a/packages/agent/test/e2e.test.ts +++ b/packages/agent/test/e2e.test.ts @@ -11,8 +11,8 @@ import { type UserMessage, } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { Agent, type AgentEvent } from "../src/index.js"; -import { calculateTool } from "./utils/calculate.js"; +import { Agent, type AgentEvent } from "../src/index.ts"; +import { calculateTool } from "./utils/calculate.ts"; const registrations: FauxProviderRegistration[] = []; diff --git a/packages/agent/test/harness/agent-harness-stream.test.ts b/packages/agent/test/harness/agent-harness-stream.test.ts index dba98f91e..ee79564bf 100644 --- a/packages/agent/test/harness/agent-harness-stream.test.ts +++ b/packages/agent/test/harness/agent-harness-stream.test.ts @@ -1,10 +1,10 @@ import { fauxAssistantMessage, fauxToolCall, registerFauxProvider, type StreamOptions } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { AgentHarness } from "../../src/harness/agent-harness.js"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.js"; -import { Session } from "../../src/harness/session/session.js"; -import { calculateTool } from "../utils/calculate.js"; +import { AgentHarness } from "../../src/harness/agent-harness.ts"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts"; +import { Session } from "../../src/harness/session/session.ts"; +import { calculateTool } from "../utils/calculate.ts"; const registrations: Array<{ unregister(): void }> = []; diff --git a/packages/agent/test/harness/agent-harness.test.ts b/packages/agent/test/harness/agent-harness.test.ts index 6ded341c8..8a3955324 100644 --- a/packages/agent/test/harness/agent-harness.test.ts +++ b/packages/agent/test/harness/agent-harness.test.ts @@ -1,13 +1,13 @@ import { fauxAssistantMessage, fauxToolCall, getModel, registerFauxProvider } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { AgentHarness } from "../../src/harness/agent-harness.js"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.js"; -import { Session } from "../../src/harness/session/session.js"; -import type { PromptTemplate, Skill } from "../../src/harness/types.js"; -import type { AgentMessage, AgentTool } from "../../src/types.js"; -import { calculateTool } from "../utils/calculate.js"; -import { getCurrentTimeTool } from "../utils/get-current-time.js"; +import { AgentHarness } from "../../src/harness/agent-harness.ts"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts"; +import { Session } from "../../src/harness/session/session.ts"; +import type { PromptTemplate, Skill } from "../../src/harness/types.ts"; +import type { AgentMessage, AgentTool } from "../../src/types.ts"; +import { calculateTool } from "../utils/calculate.ts"; +import { getCurrentTimeTool } from "../utils/get-current-time.ts"; interface AppSkill extends Skill { source: "project" | "user"; diff --git a/packages/agent/test/harness/compaction.test.ts b/packages/agent/test/harness/compaction.test.ts index 25d740ca5..b694d9f5b 100644 --- a/packages/agent/test/harness/compaction.test.ts +++ b/packages/agent/test/harness/compaction.test.ts @@ -22,8 +22,8 @@ import { prepareCompaction, serializeConversation, shouldCompact, -} from "../../src/harness/compaction/compaction.js"; -import { buildSessionContext } from "../../src/harness/session/session.js"; +} from "../../src/harness/compaction/compaction.ts"; +import { buildSessionContext } from "../../src/harness/session/session.ts"; import type { BranchSummaryEntry, CompactionEntry, @@ -33,9 +33,9 @@ import type { ModelChangeEntry, SessionTreeEntry, ThinkingLevelChangeEntry, -} from "../../src/harness/types.js"; -import { getOrThrow } from "../../src/harness/types.js"; -import type { AgentMessage } from "../../src/types.js"; +} from "../../src/harness/types.ts"; +import { getOrThrow } from "../../src/harness/types.ts"; +import type { AgentMessage } from "../../src/types.ts"; let nextId = 0; function createId(): string { diff --git a/packages/agent/test/harness/nodejs-env.test.ts b/packages/agent/test/harness/nodejs-env.test.ts index aef098be6..758d5f593 100644 --- a/packages/agent/test/harness/nodejs-env.test.ts +++ b/packages/agent/test/harness/nodejs-env.test.ts @@ -1,10 +1,10 @@ import { access, chmod, realpath, symlink } from "node:fs/promises"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { FileError, getOrThrow } from "../../src/harness/types.js"; -import { executeShellWithCapture } from "../../src/harness/utils/shell-output.js"; -import { createTempDir } from "./session-test-utils.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { FileError, getOrThrow } from "../../src/harness/types.ts"; +import { executeShellWithCapture } from "../../src/harness/utils/shell-output.ts"; +import { createTempDir } from "./session-test-utils.ts"; const chmodRestorePaths: string[] = []; diff --git a/packages/agent/test/harness/prompt-templates.test.ts b/packages/agent/test/harness/prompt-templates.test.ts index adb11006b..8e118ad49 100644 --- a/packages/agent/test/harness/prompt-templates.test.ts +++ b/packages/agent/test/harness/prompt-templates.test.ts @@ -1,13 +1,13 @@ import { symlink } from "node:fs/promises"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; import { formatPromptTemplateInvocation, loadPromptTemplates, loadSourcedPromptTemplates, -} from "../../src/harness/prompt-templates.js"; -import { createTempDir } from "./session-test-utils.js"; +} from "../../src/harness/prompt-templates.ts"; +import { createTempDir } from "./session-test-utils.ts"; describe("loadPromptTemplates", () => { it("loads markdown templates non-recursively from one or more dirs", async () => { diff --git a/packages/agent/test/harness/repo.test.ts b/packages/agent/test/harness/repo.test.ts index fda51b03b..b768fc1a1 100644 --- a/packages/agent/test/harness/repo.test.ts +++ b/packages/agent/test/harness/repo.test.ts @@ -1,9 +1,9 @@ import { existsSync } from "node:fs"; import { describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { JsonlSessionRepo } from "../../src/harness/session/jsonl-repo.js"; -import { InMemorySessionRepo } from "../../src/harness/session/memory-repo.js"; -import { createAssistantMessage, createTempDir, createUserMessage } from "./session-test-utils.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { JsonlSessionRepo } from "../../src/harness/session/jsonl-repo.ts"; +import { InMemorySessionRepo } from "../../src/harness/session/memory-repo.ts"; +import { createAssistantMessage, createTempDir, createUserMessage } from "./session-test-utils.ts"; describe("InMemorySessionRepo", () => { it("opens, deletes, and forks by metadata", async () => { diff --git a/packages/agent/test/harness/resource-formatting.test.ts b/packages/agent/test/harness/resource-formatting.test.ts index fe3fed406..45d4553f9 100644 --- a/packages/agent/test/harness/resource-formatting.test.ts +++ b/packages/agent/test/harness/resource-formatting.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { formatPromptTemplateInvocation } from "../../src/harness/prompt-templates.js"; -import { formatSkillInvocation } from "../../src/harness/skills.js"; +import { formatPromptTemplateInvocation } from "../../src/harness/prompt-templates.ts"; +import { formatSkillInvocation } from "../../src/harness/skills.ts"; describe("resource formatting helpers", () => { it("formats skill invocations with additional instructions", () => { diff --git a/packages/agent/test/harness/session-uuid.test.ts b/packages/agent/test/harness/session-uuid.test.ts index 247f31776..b8d571f4e 100644 --- a/packages/agent/test/harness/session-uuid.test.ts +++ b/packages/agent/test/harness/session-uuid.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { uuidv7 } from "../../src/harness/session/uuid.js"; +import { uuidv7 } from "../../src/harness/session/uuid.ts"; const UUID_V7_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; const TIMESTAMP = 0x0123456789ab; diff --git a/packages/agent/test/harness/session.test.ts b/packages/agent/test/harness/session.test.ts index 96510ea46..c9598da8d 100644 --- a/packages/agent/test/harness/session.test.ts +++ b/packages/agent/test/harness/session.test.ts @@ -1,12 +1,12 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { JsonlSessionStorage } from "../../src/harness/session/jsonl-storage.js"; -import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.js"; -import { Session } from "../../src/harness/session/session.js"; -import type { SessionStorage } from "../../src/harness/types.js"; -import { createAssistantMessage, createTempDir, createUserMessage, getLatestTempDir } from "./session-test-utils.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { JsonlSessionStorage } from "../../src/harness/session/jsonl-storage.ts"; +import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts"; +import { Session } from "../../src/harness/session/session.ts"; +import type { SessionStorage } from "../../src/harness/types.ts"; +import { createAssistantMessage, createTempDir, createUserMessage, getLatestTempDir } from "./session-test-utils.ts"; async function runSessionSuite( name: string, diff --git a/packages/agent/test/harness/skills.test.ts b/packages/agent/test/harness/skills.test.ts index 41840a3eb..bd769ea91 100644 --- a/packages/agent/test/harness/skills.test.ts +++ b/packages/agent/test/harness/skills.test.ts @@ -1,9 +1,9 @@ import { symlink } from "node:fs/promises"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { loadSkills, loadSourcedSkills } from "../../src/harness/skills.js"; -import { createTempDir } from "./session-test-utils.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { loadSkills, loadSourcedSkills } from "../../src/harness/skills.ts"; +import { createTempDir } from "./session-test-utils.ts"; describe("loadSkills", () => { it("loads SKILL.md files through the execution environment", async () => { diff --git a/packages/agent/test/harness/storage.test.ts b/packages/agent/test/harness/storage.test.ts index ff6a6a959..e8383ce45 100644 --- a/packages/agent/test/harness/storage.test.ts +++ b/packages/agent/test/harness/storage.test.ts @@ -1,11 +1,11 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { JsonlSessionStorage, loadJsonlSessionMetadata } from "../../src/harness/session/jsonl-storage.js"; -import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.js"; -import { type MessageEntry, ok, type SessionMetadata } from "../../src/harness/types.js"; -import { createAssistantMessage, createTempDir, createUserMessage } from "./session-test-utils.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { JsonlSessionStorage, loadJsonlSessionMetadata } from "../../src/harness/session/jsonl-storage.ts"; +import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts"; +import { type MessageEntry, ok, type SessionMetadata } from "../../src/harness/types.ts"; +import { createAssistantMessage, createTempDir, createUserMessage } from "./session-test-utils.ts"; describe("InMemorySessionStorage", () => { it("returns configured session metadata", async () => { diff --git a/packages/agent/test/harness/system-prompt.test.ts b/packages/agent/test/harness/system-prompt.test.ts index 46ce884bf..f20fbd166 100644 --- a/packages/agent/test/harness/system-prompt.test.ts +++ b/packages/agent/test/harness/system-prompt.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { formatSkillsForSystemPrompt } from "../../src/harness/system-prompt.js"; +import { formatSkillsForSystemPrompt } from "../../src/harness/system-prompt.ts"; const visibleSkill = { name: "visible", diff --git a/packages/agent/test/harness/truncate.test.ts b/packages/agent/test/harness/truncate.test.ts index f712cc2c5..3784a52c9 100644 --- a/packages/agent/test/harness/truncate.test.ts +++ b/packages/agent/test/harness/truncate.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { truncateHead, truncateTail } from "../../src/harness/utils/truncate.js"; +import { truncateHead, truncateTail } from "../../src/harness/utils/truncate.ts"; const encoder = new TextEncoder(); diff --git a/packages/agent/test/scratch/simple.ts b/packages/agent/test/scratch/simple.ts index 2b8fed114..de6ba3a26 100644 --- a/packages/agent/test/scratch/simple.ts +++ b/packages/agent/test/scratch/simple.ts @@ -1,8 +1,8 @@ import { homedir } from "node:os"; import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; -import { NodeExecutionEnv } from "../../src/harness/env/nodejs.js"; -import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.js"; +import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts"; +import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts"; import { AgentHarness, formatSkillsForSystemPrompt, @@ -11,13 +11,14 @@ import { type PromptTemplate, Session, type Skill, -} from "../../src/index.js"; +} from "../../src/index.ts"; type Source = { type: "project" | "user" | "path"; dir: string }; type SourcedSkill = Skill & { source: Source }; type SourcedPromptTemplate = PromptTemplate & { source: Source }; const env = new NodeExecutionEnv({ cwd: process.cwd() }); + const source = (type: Source["type"], dir: string) => ({ path: dir, source: { type, dir } }); const { skills: sourcedSkills } = await loadSourcedSkills( env, diff --git a/packages/agent/test/utils/calculate.ts b/packages/agent/test/utils/calculate.ts index cd2a3777b..6158efbde 100644 --- a/packages/agent/test/utils/calculate.ts +++ b/packages/agent/test/utils/calculate.ts @@ -1,5 +1,5 @@ import { type Static, Type } from "typebox"; -import type { AgentTool, AgentToolResult } from "../../src/types.js"; +import type { AgentTool, AgentToolResult } from "../../src/types.ts"; export interface CalculateResult extends AgentToolResult { content: Array<{ type: "text"; text: string }>; diff --git a/packages/agent/test/utils/get-current-time.ts b/packages/agent/test/utils/get-current-time.ts index b7075d9bc..a83a82af3 100644 --- a/packages/agent/test/utils/get-current-time.ts +++ b/packages/agent/test/utils/get-current-time.ts @@ -1,5 +1,5 @@ import { type Static, Type } from "typebox"; -import type { AgentTool, AgentToolResult } from "../../src/types.js"; +import type { AgentTool, AgentToolResult } from "../../src/types.ts"; export interface GetCurrentTimeResult extends AgentToolResult<{ utcTimestamp: number }> {} diff --git a/packages/ai/package.json b/packages/ai/package.json index 2fa04afc8..16fa3be7a 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -60,22 +60,22 @@ ], "scripts": { "clean": "shx rm -rf dist", - "generate-models": "npx tsx scripts/generate-models.ts", - "generate-image-models": "npx tsx scripts/generate-image-models.ts", + "generate-models": "node scripts/generate-models.ts", + "generate-image-models": "node scripts/generate-image-models.ts", "build": "npm run generate-models && npm run generate-image-models && tsgo -p tsconfig.build.json", "test": "vitest --run", "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { - "@anthropic-ai/sdk": "^0.91.1", - "@aws-sdk/client-bedrock-runtime": "^3.1030.0", - "@google/genai": "^1.40.0", - "@mistralai/mistralai": "^2.2.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.1", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", "openai": "6.26.0", - "partial-json": "^0.1.7", - "typebox": "^1.1.24" + "partial-json": "0.1.7", + "typebox": "1.1.38" }, "keywords": [ "ai", @@ -98,8 +98,8 @@ "node": ">=22.19.0" }, "devDependencies": { - "@types/node": "^24.3.0", - "canvas": "^3.2.0", - "vitest": "^3.2.4" + "@types/node": "24.12.4", + "canvas": "3.2.3", + "vitest": "3.2.4" } } diff --git a/packages/ai/scripts/generate-image-models.ts b/packages/ai/scripts/generate-image-models.ts index c312f3e4f..2744da487 100644 --- a/packages/ai/scripts/generate-image-models.ts +++ b/packages/ai/scripts/generate-image-models.ts @@ -1,9 +1,9 @@ -#!/usr/bin/env tsx +#!/usr/bin/env node import { writeFileSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; -import type { ImagesModel } from "../src/types.js"; +import type { ImagesModel } from "../src/types.ts"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index e896726c4..0c025c68b 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env tsx +#!/usr/bin/env node import { writeFileSync } from "fs"; import { join, dirname } from "path"; @@ -8,14 +8,8 @@ import { CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL, CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL, CLOUDFLARE_WORKERS_AI_BASE_URL, -} from "../src/providers/cloudflare.js"; -import { - Api, - type AnthropicMessagesCompat, - KnownProvider, - Model, - type OpenAICompletionsCompat, -} from "../src/types.js"; +} from "../src/providers/cloudflare.ts"; +import type { AnthropicMessagesCompat, Api, KnownProvider, Model, OpenAICompletionsCompat } from "../src/types.ts"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/ai/scripts/generate-test-image.ts b/packages/ai/scripts/generate-test-image.ts index 29a473d46..da3df2661 100644 --- a/packages/ai/scripts/generate-test-image.ts +++ b/packages/ai/scripts/generate-test-image.ts @@ -1,7 +1,7 @@ -#!/usr/bin/env tsx +#!/usr/bin/env node import { createCanvas } from "canvas"; -import { writeFileSync } from "fs"; +import { mkdirSync, writeFileSync } from "fs"; import { join, dirname } from "path"; import { fileURLToPath } from "url"; @@ -27,7 +27,6 @@ const buffer = canvas.toBuffer("image/png"); const outputPath = join(__dirname, "..", "test", "data", "red-circle.png"); // Ensure the directory exists -import { mkdirSync } from "fs"; mkdirSync(join(__dirname, "..", "test", "data"), { recursive: true }); writeFileSync(outputPath, buffer); diff --git a/packages/ai/test/abort.test.ts b/packages/ai/test/abort.test.ts index cd46a6297..27c274aac 100644 --- a/packages/ai/test/abort.test.ts +++ b/packages/ai/test/abort.test.ts @@ -1,13 +1,13 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete, stream } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete, stream } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const [openaiCodexToken] = await Promise.all([resolveApiKey("openai-codex")]); diff --git a/packages/ai/test/anthropic-eager-tool-input-compat.test.ts b/packages/ai/test/anthropic-eager-tool-input-compat.test.ts index e73a00a03..c6df9c3ef 100644 --- a/packages/ai/test/anthropic-eager-tool-input-compat.test.ts +++ b/packages/ai/test/anthropic-eager-tool-input-compat.test.ts @@ -2,8 +2,8 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht import type { AddressInfo } from "node:net"; import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { streamAnthropic } from "../src/providers/anthropic.js"; -import type { Context, Model, Tool } from "../src/types.js"; +import { streamAnthropic } from "../src/providers/anthropic.ts"; +import type { Context, Model, Tool } from "../src/types.ts"; interface CapturedRequest { headers: IncomingMessage["headers"]; diff --git a/packages/ai/test/anthropic-eager-tool-input-e2e.test.ts b/packages/ai/test/anthropic-eager-tool-input-e2e.test.ts index 3fed7ce26..2483e1a4b 100644 --- a/packages/ai/test/anthropic-eager-tool-input-e2e.test.ts +++ b/packages/ai/test/anthropic-eager-tool-input-e2e.test.ts @@ -1,10 +1,10 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getEnvApiKey } from "../src/env-api-keys.js"; -import { getModels, getProviders } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, KnownProvider, Model, ProviderStreamOptions, Tool } from "../src/types.js"; -import { resolveApiKey } from "./oauth.js"; +import { getEnvApiKey } from "../src/env-api-keys.ts"; +import { getModels, getProviders } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, KnownProvider, Model, ProviderStreamOptions, Tool } from "../src/types.ts"; +import { resolveApiKey } from "./oauth.ts"; const githubCopilotToken = await resolveApiKey("github-copilot"); diff --git a/packages/ai/test/anthropic-long-cache-retention-e2e.test.ts b/packages/ai/test/anthropic-long-cache-retention-e2e.test.ts index d900aa719..2b7667d7e 100644 --- a/packages/ai/test/anthropic-long-cache-retention-e2e.test.ts +++ b/packages/ai/test/anthropic-long-cache-retention-e2e.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; -import { getEnvApiKey } from "../src/env-api-keys.js"; -import { getModels, getProviders } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, KnownProvider, Model, ProviderStreamOptions } from "../src/types.js"; -import { resolveApiKey } from "./oauth.js"; +import { getEnvApiKey } from "../src/env-api-keys.ts"; +import { getModels, getProviders } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, KnownProvider, Model, ProviderStreamOptions } from "../src/types.ts"; +import { resolveApiKey } from "./oauth.ts"; const githubCopilotToken = await resolveApiKey("github-copilot"); diff --git a/packages/ai/test/anthropic-oauth.test.ts b/packages/ai/test/anthropic-oauth.test.ts index f8e066c66..36585a5fd 100644 --- a/packages/ai/test/anthropic-oauth.test.ts +++ b/packages/ai/test/anthropic-oauth.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { loginAnthropic, refreshAnthropicToken } from "../src/utils/oauth/anthropic.js"; +import { loginAnthropic, refreshAnthropicToken } from "../src/utils/oauth/anthropic.ts"; function jsonResponse(body: unknown, status: number = 200): Response { return new Response(JSON.stringify(body), { diff --git a/packages/ai/test/anthropic-opus-4-7-smoke.test.ts b/packages/ai/test/anthropic-opus-4-7-smoke.test.ts index 29626d1f8..7314f8af3 100644 --- a/packages/ai/test/anthropic-opus-4-7-smoke.test.ts +++ b/packages/ai/test/anthropic-opus-4-7-smoke.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamSimple } from "../src/stream.js"; -import type { Context } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamSimple } from "../src/stream.ts"; +import type { Context } from "../src/types.ts"; interface AnthropicThinkingPayload { thinking?: { type: string }; diff --git a/packages/ai/test/anthropic-sse-parsing.test.ts b/packages/ai/test/anthropic-sse-parsing.test.ts index 5bbc7d729..030249664 100644 --- a/packages/ai/test/anthropic-sse-parsing.test.ts +++ b/packages/ai/test/anthropic-sse-parsing.test.ts @@ -1,9 +1,9 @@ import type Anthropic from "@anthropic-ai/sdk"; import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamAnthropic } from "../src/providers/anthropic.js"; -import type { Context, ToolCall } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamAnthropic } from "../src/providers/anthropic.ts"; +import type { Context, ToolCall } from "../src/types.ts"; function createSseResponse(events: Array<{ event: string; data: string }>): Response { const body = events.map(({ event, data }) => `event: ${event}\ndata: ${data}\n`).join("\n"); diff --git a/packages/ai/test/anthropic-tool-name-normalization.test.ts b/packages/ai/test/anthropic-tool-name-normalization.test.ts index 1ea6bdb21..bb4540811 100644 --- a/packages/ai/test/anthropic-tool-name-normalization.test.ts +++ b/packages/ai/test/anthropic-tool-name-normalization.test.ts @@ -1,9 +1,9 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { stream } from "../src/stream.js"; -import type { Context, Tool } from "../src/types.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { stream } from "../src/stream.ts"; +import type { Context, Tool } from "../src/types.ts"; +import { resolveApiKey } from "./oauth.ts"; const oauthToken = await resolveApiKey("anthropic"); diff --git a/packages/ai/test/azure-openai-base-url.test.ts b/packages/ai/test/azure-openai-base-url.test.ts index cdaebc4e3..530c5f473 100644 --- a/packages/ai/test/azure-openai-base-url.test.ts +++ b/packages/ai/test/azure-openai-base-url.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamAzureOpenAIResponses } from "../src/providers/azure-openai-responses.js"; -import type { Context } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamAzureOpenAIResponses } from "../src/providers/azure-openai-responses.ts"; +import type { Context } from "../src/types.ts"; interface CapturedAzureClientOptions { apiKey: string; diff --git a/packages/ai/test/bedrock-convert-messages.test.ts b/packages/ai/test/bedrock-convert-messages.test.ts index d96087632..d62abd1b9 100644 --- a/packages/ai/test/bedrock-convert-messages.test.ts +++ b/packages/ai/test/bedrock-convert-messages.test.ts @@ -44,9 +44,9 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => { }; }); -import { getModel } from "../src/models.js"; -import { streamBedrock } from "../src/providers/amazon-bedrock.js"; -import type { Context, Message } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamBedrock } from "../src/providers/amazon-bedrock.ts"; +import type { Context, Message } from "../src/types.ts"; const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0"); diff --git a/packages/ai/test/bedrock-endpoint-resolution.test.ts b/packages/ai/test/bedrock-endpoint-resolution.test.ts index 374599a47..a45bc6cfc 100644 --- a/packages/ai/test/bedrock-endpoint-resolution.test.ts +++ b/packages/ai/test/bedrock-endpoint-resolution.test.ts @@ -44,9 +44,9 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => { }; }); -import { getModel } from "../src/models.js"; -import { streamBedrock } from "../src/providers/amazon-bedrock.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamBedrock } from "../src/providers/amazon-bedrock.ts"; +import type { Context, Model } from "../src/types.ts"; const context: Context = { messages: [{ role: "user", content: "hello", timestamp: Date.now() }], diff --git a/packages/ai/test/bedrock-models.test.ts b/packages/ai/test/bedrock-models.test.ts index 453a39537..2cfd8fb99 100644 --- a/packages/ai/test/bedrock-models.test.ts +++ b/packages/ai/test/bedrock-models.test.ts @@ -17,10 +17,10 @@ */ import { describe, expect, it } from "vitest"; -import { getModels } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Context } from "../src/types.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; +import { getModels } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Context } from "../src/types.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; describe("Amazon Bedrock Models", () => { const models = getModels("amazon-bedrock"); diff --git a/packages/ai/test/codex-websocket-cached-probe.ts b/packages/ai/test/codex-websocket-cached-probe.ts index ccc875f85..7317035cb 100644 --- a/packages/ai/test/codex-websocket-cached-probe.ts +++ b/packages/ai/test/codex-websocket-cached-probe.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env tsx +#!/usr/bin/env node /** * Live probe for OpenAI Codex Responses websocket-cached mode. * @@ -9,15 +9,15 @@ import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { Type } from "typebox"; -import { AuthStorage } from "../../coding-agent/src/core/auth-storage.js"; -import { getModel } from "../src/models.js"; +import { AuthStorage } from "../../coding-agent/src/core/auth-storage.ts"; +import { getModel } from "../src/models.ts"; import { closeOpenAICodexWebSocketSessions, getOpenAICodexWebSocketDebugStats, resetOpenAICodexWebSocketDebugStats, streamOpenAICodexResponses, -} from "../src/providers/openai-codex-responses.js"; -import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.js"; +} from "../src/providers/openai-codex-responses.ts"; +import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.ts"; type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh"; @@ -85,7 +85,7 @@ function required(value: string | undefined, flag: string): string { } function printHelp(): void { - console.log(`Usage: npx tsx test/codex-websocket-cached-probe.ts [options] + console.log(`Usage: node test/codex-websocket-cached-probe.ts [options] Options: --turns Number of user turns. Default: ${DEFAULT_TURNS} diff --git a/packages/ai/test/context-overflow.test.ts b/packages/ai/test/context-overflow.test.ts index 718800bf1..164ca75d8 100644 --- a/packages/ai/test/context-overflow.test.ts +++ b/packages/ai/test/context-overflow.test.ts @@ -14,13 +14,13 @@ import type { ChildProcess } from "child_process"; import { execSync, spawn } from "child_process"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { AssistantMessage, Context, Model, Usage } from "../src/types.js"; -import { isContextOverflow } from "../src/utils/overflow.js"; -import { hasAzureOpenAICredentials } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { AssistantMessage, Context, Model, Usage } from "../src/types.ts"; +import { isContextOverflow } from "../src/utils/overflow.ts"; +import { hasAzureOpenAICredentials } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([resolveApiKey("github-copilot"), resolveApiKey("openai-codex")]); diff --git a/packages/ai/test/cross-provider-handoff.test.ts b/packages/ai/test/cross-provider-handoff.test.ts index a133241a5..23593394f 100644 --- a/packages/ai/test/cross-provider-handoff.test.ts +++ b/packages/ai/test/cross-provider-handoff.test.ts @@ -25,12 +25,12 @@ import { writeFileSync } from "fs"; import { Type } from "typebox"; import { beforeAll, describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { completeSimple, getEnvApiKey } from "../src/stream.js"; -import type { Api, AssistantMessage, Message, Model, Tool, ToolResultMessage } from "../src/types.js"; -import { hasAzureOpenAICredentials } from "./azure-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { completeSimple, getEnvApiKey } from "../src/stream.ts"; +import type { Api, AssistantMessage, Message, Model, Tool, ToolResultMessage } from "../src/types.ts"; +import { hasAzureOpenAICredentials } from "./azure-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Simple tool for testing const testToolSchema = Type.Object({ diff --git a/packages/ai/test/empty.test.ts b/packages/ai/test/empty.test.ts index 121c07b97..7df7de2c4 100644 --- a/packages/ai/test/empty.test.ts +++ b/packages/ai/test/empty.test.ts @@ -1,14 +1,14 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, AssistantMessage, Context, Model, StreamOptions, UserMessage } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, AssistantMessage, Context, Model, StreamOptions, UserMessage } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([ diff --git a/packages/ai/test/env-api-keys.test.ts b/packages/ai/test/env-api-keys.test.ts index 6889743dc..61fec9128 100644 --- a/packages/ai/test/env-api-keys.test.ts +++ b/packages/ai/test/env-api-keys.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it } from "vitest"; -import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.js"; +import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts"; const originalCopilotGitHubToken = process.env.COPILOT_GITHUB_TOKEN; const originalGhToken = process.env.GH_TOKEN; diff --git a/packages/ai/test/faux-provider.test.ts b/packages/ai/test/faux-provider.test.ts index 16f338839..4f110c542 100644 --- a/packages/ai/test/faux-provider.test.ts +++ b/packages/ai/test/faux-provider.test.ts @@ -8,8 +8,8 @@ import { registerFauxProvider, stream, Type, -} from "../src/index.js"; -import type { AssistantMessageEvent, Context } from "../src/types.js"; +} from "../src/index.ts"; +import type { AssistantMessageEvent, Context } from "../src/types.ts"; async function collectEvents(streamResult: ReturnType): Promise { const events: AssistantMessageEvent[] = []; diff --git a/packages/ai/test/fireworks-models.test.ts b/packages/ai/test/fireworks-models.test.ts index 35427c10c..0260a910c 100644 --- a/packages/ai/test/fireworks-models.test.ts +++ b/packages/ai/test/fireworks-models.test.ts @@ -2,10 +2,10 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht import type { AddressInfo } from "node:net"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.js"; -import { getModel } from "../src/models.js"; -import { streamAnthropic } from "../src/providers/anthropic.js"; -import type { Context, Model, Tool } from "../src/types.js"; +import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts"; +import { getModel } from "../src/models.ts"; +import { streamAnthropic } from "../src/providers/anthropic.ts"; +import type { Context, Model, Tool } from "../src/types.ts"; const originalFireworksApiKey = process.env.FIREWORKS_API_KEY; diff --git a/packages/ai/test/github-copilot-anthropic.test.ts b/packages/ai/test/github-copilot-anthropic.test.ts index 7fda4a45d..ee3de3e85 100644 --- a/packages/ai/test/github-copilot-anthropic.test.ts +++ b/packages/ai/test/github-copilot-anthropic.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamAnthropic } from "../src/providers/anthropic.js"; -import type { Context } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamAnthropic } from "../src/providers/anthropic.ts"; +import type { Context } from "../src/types.ts"; const mockState = vi.hoisted(() => ({ constructorOpts: undefined as Record | undefined, diff --git a/packages/ai/test/github-copilot-oauth.test.ts b/packages/ai/test/github-copilot-oauth.test.ts index 0367892cb..085b1cf00 100644 --- a/packages/ai/test/github-copilot-oauth.test.ts +++ b/packages/ai/test/github-copilot-oauth.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { loginGitHubCopilot } from "../src/utils/oauth/github-copilot.js"; +import { loginGitHubCopilot } from "../src/utils/oauth/github-copilot.ts"; function jsonResponse(body: unknown, status: number = 200): Response { return new Response(JSON.stringify(body), { diff --git a/packages/ai/test/google-shared-convert-tools.test.ts b/packages/ai/test/google-shared-convert-tools.test.ts index 6cce3175e..c7b10b419 100644 --- a/packages/ai/test/google-shared-convert-tools.test.ts +++ b/packages/ai/test/google-shared-convert-tools.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { convertTools } from "../src/providers/google-shared.js"; -import type { Tool } from "../src/types.js"; +import { convertTools } from "../src/providers/google-shared.ts"; +import type { Tool } from "../src/types.ts"; function makeTool(parameters: Record): Tool { return { diff --git a/packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts b/packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts index 1822e9dd7..920c6a4e7 100644 --- a/packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts +++ b/packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { convertMessages } from "../src/providers/google-shared.js"; -import type { Context, Model } from "../src/types.js"; +import { convertMessages } from "../src/providers/google-shared.ts"; +import type { Context, Model } from "../src/types.ts"; function makeGemini3Model( api: TApi, diff --git a/packages/ai/test/google-shared-image-tool-result-routing.test.ts b/packages/ai/test/google-shared-image-tool-result-routing.test.ts index 27150dbae..1430a0849 100644 --- a/packages/ai/test/google-shared-image-tool-result-routing.test.ts +++ b/packages/ai/test/google-shared-image-tool-result-routing.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { convertMessages } from "../src/providers/google-shared.js"; -import type { Context, Model } from "../src/types.js"; +import { convertMessages } from "../src/providers/google-shared.ts"; +import type { Context, Model } from "../src/types.ts"; function makeModel( api: TApi, diff --git a/packages/ai/test/google-thinking-disable.test.ts b/packages/ai/test/google-thinking-disable.test.ts index e8720ff8d..30df3638b 100644 --- a/packages/ai/test/google-thinking-disable.test.ts +++ b/packages/ai/test/google-thinking-disable.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamSimple } from "../src/stream.js"; -import type { Api, Context, Model, SimpleStreamOptions } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamSimple } from "../src/stream.ts"; +import type { Api, Context, Model, SimpleStreamOptions } from "../src/types.ts"; type SimpleOptionsWithExtras = SimpleStreamOptions & Record; diff --git a/packages/ai/test/google-thinking-signature.test.ts b/packages/ai/test/google-thinking-signature.test.ts index c90f7caae..83b17cccd 100644 --- a/packages/ai/test/google-thinking-signature.test.ts +++ b/packages/ai/test/google-thinking-signature.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { isThinkingPart, retainThoughtSignature } from "../src/providers/google-shared.js"; +import { isThinkingPart, retainThoughtSignature } from "../src/providers/google-shared.ts"; describe("Google thinking detection (thoughtSignature)", () => { it("treats part.thought === true as thinking", () => { diff --git a/packages/ai/test/google-vertex-api-key-resolution.test.ts b/packages/ai/test/google-vertex-api-key-resolution.test.ts index d05702c3a..5f66649c3 100644 --- a/packages/ai/test/google-vertex-api-key-resolution.test.ts +++ b/packages/ai/test/google-vertex-api-key-resolution.test.ts @@ -45,9 +45,9 @@ vi.mock("@google/genai", () => { }; }); -import { getModel } from "../src/models.js"; -import { streamGoogleVertex } from "../src/providers/google-vertex.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamGoogleVertex } from "../src/providers/google-vertex.ts"; +import type { Context, Model } from "../src/types.ts"; const model = getModel("google-vertex", "gemini-3-flash-preview"); const context: Context = { diff --git a/packages/ai/test/image-tool-result.test.ts b/packages/ai/test/image-tool-result.test.ts index 9d1276d59..542b23857 100644 --- a/packages/ai/test/image-tool-result.test.ts +++ b/packages/ai/test/image-tool-result.test.ts @@ -2,15 +2,15 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import type { Api, Context, Model, Tool, ToolResultMessage } from "../src/index.js"; -import { complete, getModel } from "../src/index.js"; -import type { StreamOptions } from "../src/types.js"; +import type { Api, Context, Model, Tool, ToolResultMessage } from "../src/index.ts"; +import { complete, getModel } from "../src/index.ts"; +import type { StreamOptions } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([ diff --git a/packages/ai/test/images.test.ts b/packages/ai/test/images.test.ts index 59912c70b..c45cc215e 100644 --- a/packages/ai/test/images.test.ts +++ b/packages/ai/test/images.test.ts @@ -2,9 +2,9 @@ import { readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; -import { getImageModel } from "../src/image-models.js"; -import { generateImages } from "../src/images.js"; -import type { ImageContent, ImagesContext, ImagesModel, ProviderImagesOptions } from "../src/types.js"; +import { getImageModel } from "../src/image-models.ts"; +import { generateImages } from "../src/images.ts"; +import type { ImageContent, ImagesContext, ImagesModel, ProviderImagesOptions } from "../src/types.ts"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/ai/test/interleaved-thinking.test.ts b/packages/ai/test/interleaved-thinking.test.ts index fabc3c40b..4cf387ce0 100644 --- a/packages/ai/test/interleaved-thinking.test.ts +++ b/packages/ai/test/interleaved-thinking.test.ts @@ -1,11 +1,11 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getEnvApiKey } from "../src/env-api-keys.js"; -import { getModel } from "../src/models.js"; -import { completeSimple } from "../src/stream.js"; -import type { Api, Context, Model, StopReason, Tool, ToolCall, ToolResultMessage } from "../src/types.js"; -import { StringEnum } from "../src/utils/typebox-helpers.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; +import { getEnvApiKey } from "../src/env-api-keys.ts"; +import { getModel } from "../src/models.ts"; +import { completeSimple } from "../src/stream.ts"; +import type { Api, Context, Model, StopReason, Tool, ToolCall, ToolResultMessage } from "../src/types.ts"; +import { StringEnum } from "../src/utils/typebox-helpers.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; const calculatorSchema = Type.Object({ a: Type.Number({ description: "First number" }), diff --git a/packages/ai/test/lazy-module-load.test.ts b/packages/ai/test/lazy-module-load.test.ts index c94669abf..e21f0d12d 100644 --- a/packages/ai/test/lazy-module-load.test.ts +++ b/packages/ai/test/lazy-module-load.test.ts @@ -1,11 +1,8 @@ import { spawnSync } from "node:child_process"; -import { createRequire } from "node:module"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; -const require = createRequire(import.meta.url); -const tsxLoader = require.resolve("tsx/esm"); const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const aiEntryUrl = new URL("../src/index.ts", import.meta.url).href; @@ -42,7 +39,7 @@ function runProbe(action: string): ProbeResult { console.log(JSON.stringify({ loadedSpecifiers: [...new Set(loaded)] })); `; - const result = spawnSync(process.execPath, ["--import", tsxLoader, "--input-type=module", "--eval", script], { + const result = spawnSync(process.execPath, ["--input-type=module", "--eval", script], { cwd: packageRoot, encoding: "utf8", }); diff --git a/packages/ai/test/mistral-reasoning-mode.test.ts b/packages/ai/test/mistral-reasoning-mode.test.ts index 28ff52086..35a5b96be 100644 --- a/packages/ai/test/mistral-reasoning-mode.test.ts +++ b/packages/ai/test/mistral-reasoning-mode.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamSimple } from "../src/stream.js"; -import type { Context, Model, SimpleStreamOptions } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamSimple } from "../src/stream.ts"; +import type { Context, Model, SimpleStreamOptions } from "../src/types.ts"; interface MistralPayload { promptMode?: "reasoning"; diff --git a/packages/ai/test/mistral-tool-schema.test.ts b/packages/ai/test/mistral-tool-schema.test.ts index 623e9a3a5..c6898fc64 100644 --- a/packages/ai/test/mistral-tool-schema.test.ts +++ b/packages/ai/test/mistral-tool-schema.test.ts @@ -1,8 +1,8 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Context, Model } from "../src/types.ts"; interface MistralToolPayload { tools?: Array<{ diff --git a/packages/ai/test/node-http-proxy.test.ts b/packages/ai/test/node-http-proxy.test.ts index 0057d9bd4..f4c9b735c 100644 --- a/packages/ai/test/node-http-proxy.test.ts +++ b/packages/ai/test/node-http-proxy.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it } from "vitest"; -import { resolveHttpProxyUrlForTarget, UNSUPPORTED_PROXY_PROTOCOL_MESSAGE } from "../src/utils/node-http-proxy.js"; +import { resolveHttpProxyUrlForTarget, UNSUPPORTED_PROXY_PROTOCOL_MESSAGE } from "../src/utils/node-http-proxy.ts"; const PROXY_ENV_KEYS = [ "HTTP_PROXY", diff --git a/packages/ai/test/oauth.ts b/packages/ai/test/oauth.ts index 8dd302a79..8ee7c94d8 100644 --- a/packages/ai/test/oauth.ts +++ b/packages/ai/test/oauth.ts @@ -8,8 +8,8 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import { homedir } from "os"; import { dirname, join } from "path"; -import { getOAuthApiKey } from "../src/utils/oauth/index.js"; -import type { OAuthCredentials, OAuthProvider } from "../src/utils/oauth/types.js"; +import { getOAuthApiKey } from "../src/utils/oauth/index.ts"; +import type { OAuthCredentials, OAuthProvider } from "../src/utils/oauth/types.ts"; const AUTH_PATH = join(homedir(), ".pi", "agent", "auth.json"); diff --git a/packages/ai/test/openai-codex-cache-affinity-e2e.test.ts b/packages/ai/test/openai-codex-cache-affinity-e2e.test.ts index 0d929724c..0abb46f63 100644 --- a/packages/ai/test/openai-codex-cache-affinity-e2e.test.ts +++ b/packages/ai/test/openai-codex-cache-affinity-e2e.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Context } from "../src/types.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Context } from "../src/types.ts"; +import { resolveApiKey } from "./oauth.ts"; const codexToken = await resolveApiKey("openai-codex"); diff --git a/packages/ai/test/openai-codex-oauth.test.ts b/packages/ai/test/openai-codex-oauth.test.ts index 276abe1bf..0157f6f66 100644 --- a/packages/ai/test/openai-codex-oauth.test.ts +++ b/packages/ai/test/openai-codex-oauth.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { refreshOpenAICodexToken } from "../src/utils/oauth/openai-codex.js"; +import { refreshOpenAICodexToken } from "../src/utils/oauth/openai-codex.ts"; describe("OpenAI Codex OAuth", () => { afterEach(() => { diff --git a/packages/ai/test/openai-completions-cache-control-format.test.ts b/packages/ai/test/openai-completions-cache-control-format.test.ts index de69d02ac..7d8ee9c4d 100644 --- a/packages/ai/test/openai-completions-cache-control-format.test.ts +++ b/packages/ai/test/openai-completions-cache-control-format.test.ts @@ -1,8 +1,8 @@ import { Type } from "typebox"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamOpenAICompletions } from "../src/providers/openai-completions.js"; -import type { Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamOpenAICompletions } from "../src/providers/openai-completions.ts"; +import type { Model } from "../src/types.ts"; interface CacheControl { type: "ephemeral"; diff --git a/packages/ai/test/openai-completions-empty-tools.test.ts b/packages/ai/test/openai-completions-empty-tools.test.ts index 8e5d49c78..a743351c0 100644 --- a/packages/ai/test/openai-completions-empty-tools.test.ts +++ b/packages/ai/test/openai-completions-empty-tools.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamSimple } from "../src/stream.js"; +import { getModel } from "../src/models.ts"; +import { streamSimple } from "../src/stream.ts"; // Empty tools arrays must NOT be serialized as `tools: []` — some OpenAI-compatible // backends (e.g. DashScope / Aliyun Qwen via compatible-mode) reject the request with diff --git a/packages/ai/test/openai-completions-prompt-cache.test.ts b/packages/ai/test/openai-completions-prompt-cache.test.ts index b1846421a..75098fc13 100644 --- a/packages/ai/test/openai-completions-prompt-cache.test.ts +++ b/packages/ai/test/openai-completions-prompt-cache.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamOpenAICompletions } from "../src/providers/openai-completions.js"; -import type { Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamOpenAICompletions } from "../src/providers/openai-completions.ts"; +import type { Model } from "../src/types.ts"; interface FakeOpenAIClientOptions { apiKey: string; diff --git a/packages/ai/test/openai-completions-response-model.test.ts b/packages/ai/test/openai-completions-response-model.test.ts index 32d4edf72..aab20dea8 100644 --- a/packages/ai/test/openai-completions-response-model.test.ts +++ b/packages/ai/test/openai-completions-response-model.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { complete } from "../src/stream.js"; -import type { Model } from "../src/types.js"; +import { complete } from "../src/stream.ts"; +import type { Model } from "../src/types.ts"; // Router/virtual ids (e.g. OpenRouter `auto`) keep `model` pinned to the // requested id and surface the routed concrete id on `responseModel`. diff --git a/packages/ai/test/openai-completions-thinking-as-text.test.ts b/packages/ai/test/openai-completions-thinking-as-text.test.ts index a0bb65197..1c49aad3b 100644 --- a/packages/ai/test/openai-completions-thinking-as-text.test.ts +++ b/packages/ai/test/openai-completions-thinking-as-text.test.ts @@ -2,7 +2,7 @@ import { once } from "node:events"; import http from "node:http"; import type { AddressInfo } from "node:net"; import { afterEach, describe, expect, it } from "vitest"; -import { convertMessages, streamOpenAICompletions } from "../src/providers/openai-completions.js"; +import { convertMessages, streamOpenAICompletions } from "../src/providers/openai-completions.ts"; import type { AssistantMessage, AssistantMessageEvent, @@ -10,7 +10,7 @@ import type { Model, OpenAICompletionsCompat, Usage, -} from "../src/types.js"; +} from "../src/types.ts"; const emptyUsage: Usage = { input: 0, diff --git a/packages/ai/test/openai-completions-tool-choice.test.ts b/packages/ai/test/openai-completions-tool-choice.test.ts index 5401ac830..ec98427b8 100644 --- a/packages/ai/test/openai-completions-tool-choice.test.ts +++ b/packages/ai/test/openai-completions-tool-choice.test.ts @@ -1,9 +1,9 @@ import { Type } from "typebox"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { convertMessages } from "../src/providers/openai-completions.js"; -import { streamSimple } from "../src/stream.js"; -import type { AssistantMessage, Model, Tool, ToolResultMessage } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { convertMessages } from "../src/providers/openai-completions.ts"; +import { streamSimple } from "../src/stream.ts"; +import type { AssistantMessage, Model, Tool, ToolResultMessage } from "../src/types.ts"; const mockState = vi.hoisted(() => ({ lastParams: undefined as unknown, diff --git a/packages/ai/test/openai-completions-tool-result-images.test.ts b/packages/ai/test/openai-completions-tool-result-images.test.ts index cd4d6436e..3510f3967 100644 --- a/packages/ai/test/openai-completions-tool-result-images.test.ts +++ b/packages/ai/test/openai-completions-tool-result-images.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { convertMessages } from "../src/providers/openai-completions.js"; +import { getModel } from "../src/models.ts"; +import { convertMessages } from "../src/providers/openai-completions.ts"; import type { AssistantMessage, Context, @@ -8,7 +8,7 @@ import type { OpenAICompletionsCompat, ToolResultMessage, Usage, -} from "../src/types.js"; +} from "../src/types.ts"; const emptyUsage: Usage = { input: 0, diff --git a/packages/ai/test/openai-responses-cache-affinity-e2e.test.ts b/packages/ai/test/openai-responses-cache-affinity-e2e.test.ts index a2fd0d0eb..d173694f9 100644 --- a/packages/ai/test/openai-responses-cache-affinity-e2e.test.ts +++ b/packages/ai/test/openai-responses-cache-affinity-e2e.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Context } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Context } from "../src/types.ts"; describe.skipIf(!process.env.OPENAI_API_KEY)("openai responses cache affinity e2e", () => { it("handles direct OpenAI Responses requests with aligned cache-affinity identifiers", { retry: 2 }, async () => { diff --git a/packages/ai/test/openai-responses-copilot-provider.test.ts b/packages/ai/test/openai-responses-copilot-provider.test.ts index c956030df..04236feda 100644 --- a/packages/ai/test/openai-responses-copilot-provider.test.ts +++ b/packages/ai/test/openai-responses-copilot-provider.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamOpenAIResponses } from "../src/providers/openai-responses.js"; -import type { Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { streamOpenAIResponses } from "../src/providers/openai-responses.ts"; +import type { Model } from "../src/types.ts"; type CapturedHeaders = Headers | string[][] | Record | undefined; diff --git a/packages/ai/test/openai-responses-foreign-toolcall-id.test.ts b/packages/ai/test/openai-responses-foreign-toolcall-id.test.ts index 52de262b0..10f063779 100644 --- a/packages/ai/test/openai-responses-foreign-toolcall-id.test.ts +++ b/packages/ai/test/openai-responses-foreign-toolcall-id.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { convertResponsesMessages } from "../src/providers/openai-responses-shared.js"; -import type { AssistantMessage, Context, ToolResultMessage, Usage } from "../src/types.js"; -import { shortHash } from "../src/utils/hash.js"; +import { getModel } from "../src/models.ts"; +import { convertResponsesMessages } from "../src/providers/openai-responses-shared.ts"; +import type { AssistantMessage, Context, ToolResultMessage, Usage } from "../src/types.ts"; +import { shortHash } from "../src/utils/hash.ts"; const COPILOT_RAW_TOOL_CALL_ID = "call_4VnzVawQXPB9MgYib7CiQFEY|I9b95oN1wD/cHXKTw3PpRkL6KkCtzTJhUxMouMWYwHeTo2j3htzfSk7YPx2vifiIM4g3A8XXyOj8q4Bt6SLUG7gqY1E3ELkrkVQNHglRfUmWj84lqxJY+Puieb3VKyX0FB+83TUzn91cDMF/4gzt990IzqVrc+nIb9RRscRD070Du16q1glydVjWR0SBJsE6TbY/esOjFpqplogQqrajm1eI++f3eLi73R6q7hVusY0QbeFySVxABCjhN0lXB04caBe1rzHjYzul6MAXj7uq+0r17VLq+yrtyYhN12wkmFqHeqTyEei6EFPbMy24Nc+IbJlkP0OCg02W+gOnyBFcbi2ctvJFSOhSjt1CqBdqCnnhwUqXjbWiT0wh3DmLScRgTHmGkaI+oAcQQjfic65nxj+TnEkReA=="; diff --git a/packages/ai/test/openai-responses-partial-json-cleanup.test.ts b/packages/ai/test/openai-responses-partial-json-cleanup.test.ts index c34350de7..76b16ad3f 100644 --- a/packages/ai/test/openai-responses-partial-json-cleanup.test.ts +++ b/packages/ai/test/openai-responses-partial-json-cleanup.test.ts @@ -1,8 +1,8 @@ import type { ResponseStreamEvent } from "openai/resources/responses/responses.js"; import { describe, expect, it, vi } from "vitest"; -import { processResponsesStream } from "../src/providers/openai-responses-shared.js"; -import type { AssistantMessage, AssistantMessageEvent, Model } from "../src/types.js"; -import { AssistantMessageEventStream } from "../src/utils/event-stream.js"; +import { processResponsesStream } from "../src/providers/openai-responses-shared.ts"; +import type { AssistantMessage, AssistantMessageEvent, Model } from "../src/types.ts"; +import { AssistantMessageEventStream } from "../src/utils/event-stream.ts"; function createOutput(model: Model<"openai-responses">): AssistantMessage { return { diff --git a/packages/ai/test/openai-responses-reasoning-replay-e2e.test.ts b/packages/ai/test/openai-responses-reasoning-replay-e2e.test.ts index 2f78ddc78..aa6f2e239 100644 --- a/packages/ai/test/openai-responses-reasoning-replay-e2e.test.ts +++ b/packages/ai/test/openai-responses-reasoning-replay-e2e.test.ts @@ -1,8 +1,8 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete, getEnvApiKey } from "../src/stream.js"; -import type { AssistantMessage, Context, Message, Tool, ToolCall } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete, getEnvApiKey } from "../src/stream.ts"; +import type { AssistantMessage, Context, Message, Tool, ToolCall } from "../src/types.ts"; const testToolSchema = Type.Object({ value: Type.Number({ description: "A number to double" }), diff --git a/packages/ai/test/openai-responses-tool-result-images.test.ts b/packages/ai/test/openai-responses-tool-result-images.test.ts index 48ab8d08b..c6131d912 100644 --- a/packages/ai/test/openai-responses-tool-result-images.test.ts +++ b/packages/ai/test/openai-responses-tool-result-images.test.ts @@ -4,10 +4,10 @@ import { fileURLToPath } from "node:url"; import type { ResponseFunctionCallOutputItemList } from "openai/resources/responses/responses.js"; import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import type { Api, Context, Model, StreamOptions, Tool, ToolResultMessage } from "../src/index.js"; -import { complete, getModel } from "../src/index.js"; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import type { Api, Context, Model, StreamOptions, Tool, ToolResultMessage } from "../src/index.ts"; +import { complete, getModel } from "../src/index.ts"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; type StreamOptionsWithExtras = StreamOptions & Record; diff --git a/packages/ai/test/openrouter-cache-write-repro.test.ts b/packages/ai/test/openrouter-cache-write-repro.test.ts index ca4929677..4bdeb2868 100644 --- a/packages/ai/test/openrouter-cache-write-repro.test.ts +++ b/packages/ai/test/openrouter-cache-write-repro.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { completeSimple } from "../src/stream.js"; +import { getModel } from "../src/models.ts"; +import { completeSimple } from "../src/stream.ts"; function createLongSystemPrompt(): string { const nonce = `${Date.now()}-${Math.random()}`; diff --git a/packages/ai/test/openrouter-images.test.ts b/packages/ai/test/openrouter-images.test.ts index de2ddbba8..31882bec3 100644 --- a/packages/ai/test/openrouter-images.test.ts +++ b/packages/ai/test/openrouter-images.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { generateImages } from "../src/images.js"; -import type { ImagesContext, ImagesModel } from "../src/types.js"; +import { generateImages } from "../src/images.ts"; +import type { ImagesContext, ImagesModel } from "../src/types.ts"; const mockState = vi.hoisted(() => ({ lastParams: undefined as unknown, diff --git a/packages/ai/test/overflow.test.ts b/packages/ai/test/overflow.test.ts index ca6fde243..b26948e2b 100644 --- a/packages/ai/test/overflow.test.ts +++ b/packages/ai/test/overflow.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { AssistantMessage } from "../src/types.js"; -import { isContextOverflow } from "../src/utils/overflow.js"; +import type { AssistantMessage } from "../src/types.ts"; +import { isContextOverflow } from "../src/utils/overflow.ts"; function createErrorMessage(errorMessage: string): AssistantMessage { return { diff --git a/packages/ai/test/responseid.test.ts b/packages/ai/test/responseid.test.ts index 61df764b9..d250f5f41 100644 --- a/packages/ai/test/responseid.test.ts +++ b/packages/ai/test/responseid.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions } from "../src/types.js"; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions } from "../src/types.ts"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; type StreamOptionsWithExtras = StreamOptions & Record; diff --git a/packages/ai/test/stream.test.ts b/packages/ai/test/stream.test.ts index 21199d386..298104dd4 100644 --- a/packages/ai/test/stream.test.ts +++ b/packages/ai/test/stream.test.ts @@ -4,17 +4,17 @@ import { dirname, join } from "path"; import { Type } from "typebox"; import { fileURLToPath } from "url"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete, stream } from "../src/stream.js"; -import type { Api, Context, ImageContent, Model, StreamOptions, Tool, ToolResultMessage } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete, stream } from "../src/stream.ts"; +import type { Api, Context, ImageContent, Model, StreamOptions, Tool, ToolResultMessage } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { StringEnum } from "../src/utils/typebox-helpers.js"; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { StringEnum } from "../src/utils/typebox-helpers.ts"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/ai/test/supports-xhigh.test.ts b/packages/ai/test/supports-xhigh.test.ts index 6a66ee94c..4fb6f3b2a 100644 --- a/packages/ai/test/supports-xhigh.test.ts +++ b/packages/ai/test/supports-xhigh.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { getModel, getSupportedThinkingLevels } from "../src/models.js"; +import { getModel, getSupportedThinkingLevels } from "../src/models.ts"; describe("getSupportedThinkingLevels", () => { it("includes xhigh for Anthropic Opus 4.6 on anthropic-messages API", () => { diff --git a/packages/ai/test/together-models.test.ts b/packages/ai/test/together-models.test.ts index 140314471..cb5ea9433 100644 --- a/packages/ai/test/together-models.test.ts +++ b/packages/ai/test/together-models.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from "vitest"; -import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.js"; -import { getModel } from "../src/models.js"; +import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts"; +import { getModel } from "../src/models.ts"; const originalTogetherApiKey = process.env.TOGETHER_API_KEY; diff --git a/packages/ai/test/tokens.test.ts b/packages/ai/test/tokens.test.ts index 86a70cd23..f8da26a85 100644 --- a/packages/ai/test/tokens.test.ts +++ b/packages/ai/test/tokens.test.ts @@ -1,14 +1,14 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { stream } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { stream } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([ diff --git a/packages/ai/test/tool-call-id-normalization.test.ts b/packages/ai/test/tool-call-id-normalization.test.ts index 33ea327ff..0672181b2 100644 --- a/packages/ai/test/tool-call-id-normalization.test.ts +++ b/packages/ai/test/tool-call-id-normalization.test.ts @@ -12,10 +12,10 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { completeSimple, getEnvApiKey } from "../src/stream.js"; -import type { AssistantMessage, Message, Tool, ToolResultMessage } from "../src/types.js"; -import { resolveApiKey } from "./oauth.js"; +import { getModel } from "../src/models.ts"; +import { completeSimple, getEnvApiKey } from "../src/stream.ts"; +import type { AssistantMessage, Message, Tool, ToolResultMessage } from "../src/types.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve API keys const copilotToken = await resolveApiKey("github-copilot"); diff --git a/packages/ai/test/tool-call-without-result.test.ts b/packages/ai/test/tool-call-without-result.test.ts index fdab93944..2b1950b99 100644 --- a/packages/ai/test/tool-call-without-result.test.ts +++ b/packages/ai/test/tool-call-without-result.test.ts @@ -1,15 +1,15 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions, Tool } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions, Tool } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([ diff --git a/packages/ai/test/total-tokens.test.ts b/packages/ai/test/total-tokens.test.ts index 47303da4c..bd782c2c0 100644 --- a/packages/ai/test/total-tokens.test.ts +++ b/packages/ai/test/total-tokens.test.ts @@ -13,16 +13,16 @@ */ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions, Usage } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions, Usage } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Resolve OAuth tokens at module level (async, runs before tests) const oauthTokens = await Promise.all([ diff --git a/packages/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts b/packages/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts index 1db3bad69..4d858835a 100644 --- a/packages/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts +++ b/packages/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { transformMessages } from "../src/providers/transform-messages.js"; -import type { AssistantMessage, Message, Model, ToolCall } from "../src/types.js"; +import { transformMessages } from "../src/providers/transform-messages.ts"; +import type { AssistantMessage, Message, Model, ToolCall } from "../src/types.ts"; // Normalize function matching what anthropic.ts uses function anthropicNormalizeToolCallId( diff --git a/packages/ai/test/unicode-surrogate.test.ts b/packages/ai/test/unicode-surrogate.test.ts index 568de1747..afe48d5c5 100644 --- a/packages/ai/test/unicode-surrogate.test.ts +++ b/packages/ai/test/unicode-surrogate.test.ts @@ -1,15 +1,15 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { complete } from "../src/stream.js"; -import type { Api, Context, Model, StreamOptions, ToolResultMessage } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { complete } from "../src/stream.ts"; +import type { Api, Context, Model, StreamOptions, ToolResultMessage } from "../src/types.ts"; type StreamOptionsWithExtras = StreamOptions & Record; -import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.js"; -import { hasBedrockCredentials } from "./bedrock-utils.js"; -import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.js"; -import { resolveApiKey } from "./oauth.js"; +import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts"; +import { hasBedrockCredentials } from "./bedrock-utils.ts"; +import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts"; +import { resolveApiKey } from "./oauth.ts"; // Empty schema for test tools - must be proper OBJECT type for Cloud Code Assist const emptySchema = Type.Object({}); diff --git a/packages/ai/test/validation.test.ts b/packages/ai/test/validation.test.ts index fd9d0164f..dcbe9ebe9 100644 --- a/packages/ai/test/validation.test.ts +++ b/packages/ai/test/validation.test.ts @@ -1,7 +1,7 @@ import { Type } from "typebox"; import { describe, expect, it } from "vitest"; -import type { Tool, ToolCall } from "../src/types.js"; -import { validateToolArguments } from "../src/utils/validation.js"; +import type { Tool, ToolCall } from "../src/types.ts"; +import { validateToolArguments } from "../src/utils/validation.ts"; function createToolCallWithPlainSchema( schema: Tool["parameters"], diff --git a/packages/ai/test/xhigh.test.ts b/packages/ai/test/xhigh.test.ts index ef487369f..3c2798635 100644 --- a/packages/ai/test/xhigh.test.ts +++ b/packages/ai/test/xhigh.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { getModel } from "../src/models.js"; -import { stream } from "../src/stream.js"; -import type { Context, Model } from "../src/types.js"; +import { getModel } from "../src/models.ts"; +import { stream } from "../src/stream.ts"; +import type { Context, Model } from "../src/types.ts"; function makeContext(): Context { return { diff --git a/packages/ai/test/zen.test.ts b/packages/ai/test/zen.test.ts index 567af8613..8ca80014e 100644 --- a/packages/ai/test/zen.test.ts +++ b/packages/ai/test/zen.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import { MODELS } from "../src/models.generated.js"; -import { complete } from "../src/stream.js"; -import type { Model } from "../src/types.js"; +import { MODELS } from "../src/models.generated.ts"; +import { complete } from "../src/stream.ts"; +import type { Model } from "../src/types.ts"; describe.skipIf(!process.env.OPENCODE_API_KEY)("OpenCode Models Smoke Test", () => { const providers = [ diff --git a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json index d8e358c5d..a2f796cf7 100644 --- a/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json +++ b/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json @@ -14,6 +14,6 @@ ] }, "dependencies": { - "@anthropic-ai/sdk": "^0.52.0" + "@anthropic-ai/sdk": "0.52.0" } } diff --git a/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts b/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts index c79637325..0077aca83 100644 --- a/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts +++ b/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts @@ -12,7 +12,7 @@ import { type Api, type Context, type Model, registerApiProvider, streamSimple } import { readFileSync } from "fs"; import { getAgentDir } from "packages/coding-agent/src/config.js"; import { join } from "path"; -import { MODELS, streamGitLabDuo } from "./index.js"; +import { MODELS, streamGitLabDuo } from "./index.ts"; const MODEL_MAP = new Map(MODELS.map((m) => [m.id, m])); diff --git a/packages/coding-agent/examples/extensions/doom-overlay/doom-component.ts b/packages/coding-agent/examples/extensions/doom-overlay/doom-component.ts index dbc795b91..ddc2e98f5 100644 --- a/packages/coding-agent/examples/extensions/doom-overlay/doom-component.ts +++ b/packages/coding-agent/examples/extensions/doom-overlay/doom-component.ts @@ -7,8 +7,8 @@ import type { Component } from "@earendil-works/pi-tui"; import { isKeyRelease, type TUI } from "@earendil-works/pi-tui"; -import type { DoomEngine } from "./doom-engine.js"; -import { DoomKeys, mapKeyToDoom } from "./doom-keys.js"; +import type { DoomEngine } from "./doom-engine.ts"; +import { DoomKeys, mapKeyToDoom } from "./doom-keys.ts"; function renderHalfBlock( rgba: Uint8Array, diff --git a/packages/coding-agent/examples/extensions/doom-overlay/index.ts b/packages/coding-agent/examples/extensions/doom-overlay/index.ts index 434f0be1b..9d9dad13f 100644 --- a/packages/coding-agent/examples/extensions/doom-overlay/index.ts +++ b/packages/coding-agent/examples/extensions/doom-overlay/index.ts @@ -10,9 +10,9 @@ */ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; -import { DoomOverlayComponent } from "./doom-component.js"; -import { DoomEngine } from "./doom-engine.js"; -import { ensureWadFile } from "./wad-finder.js"; +import { DoomOverlayComponent } from "./doom-component.ts"; +import { DoomEngine } from "./doom-engine.ts"; +import { ensureWadFile } from "./wad-finder.ts"; // Persistent engine instance - survives between invocations let activeEngine: DoomEngine | null = null; diff --git a/packages/coding-agent/examples/extensions/plan-mode/index.ts b/packages/coding-agent/examples/extensions/plan-mode/index.ts index 709741d1e..40db408c9 100644 --- a/packages/coding-agent/examples/extensions/plan-mode/index.ts +++ b/packages/coding-agent/examples/extensions/plan-mode/index.ts @@ -16,7 +16,7 @@ import type { AgentMessage } from "@earendil-works/pi-agent-core"; import type { AssistantMessage, TextContent } from "@earendil-works/pi-ai"; import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; import { Key } from "@earendil-works/pi-tui"; -import { extractTodoItems, isSafeCommand, markCompletedSteps, type TodoItem } from "./utils.js"; +import { extractTodoItems, isSafeCommand, markCompletedSteps, type TodoItem } from "./utils.ts"; // Tools const PLAN_MODE_TOOLS = ["read", "bash", "grep", "find", "ls", "questionnaire"]; diff --git a/packages/coding-agent/examples/extensions/sandbox/package.json b/packages/coding-agent/examples/extensions/sandbox/package.json index 785ca4079..1fd94b35e 100644 --- a/packages/coding-agent/examples/extensions/sandbox/package.json +++ b/packages/coding-agent/examples/extensions/sandbox/package.json @@ -14,6 +14,6 @@ ] }, "dependencies": { - "@anthropic-ai/sandbox-runtime": "^0.0.26" + "@anthropic-ai/sandbox-runtime": "0.0.26" } } diff --git a/packages/coding-agent/examples/extensions/subagent/index.ts b/packages/coding-agent/examples/extensions/subagent/index.ts index 2853ad78b..92b471a34 100644 --- a/packages/coding-agent/examples/extensions/subagent/index.ts +++ b/packages/coding-agent/examples/extensions/subagent/index.ts @@ -22,7 +22,7 @@ import { StringEnum } from "@earendil-works/pi-ai"; import { type ExtensionAPI, getMarkdownTheme, withFileMutationQueue } from "@earendil-works/pi-coding-agent"; import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui"; import { Type } from "typebox"; -import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js"; +import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.ts"; const MAX_PARALLEL_TASKS = 8; const MAX_CONCURRENCY = 4; diff --git a/packages/coding-agent/examples/extensions/with-deps/package.json b/packages/coding-agent/examples/extensions/with-deps/package.json index eb66a8a9b..2d7cc7286 100644 --- a/packages/coding-agent/examples/extensions/with-deps/package.json +++ b/packages/coding-agent/examples/extensions/with-deps/package.json @@ -14,9 +14,9 @@ ] }, "dependencies": { - "ms": "^2.1.3" + "ms": "2.1.3" }, "devDependencies": { - "@types/ms": "^2.1.0" + "@types/ms": "2.1.0" } } diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 82b5ec763..cd83c3807 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -40,20 +40,20 @@ "@earendil-works/pi-agent-core": "^0.75.3", "@earendil-works/pi-ai": "^0.75.3", "@earendil-works/pi-tui": "^0.75.3", - "@silvia-odwyer/photon-node": "^0.3.4", - "chalk": "^5.5.0", - "cross-spawn": "^7.0.6", - "diff": "^8.0.2", - "glob": "^13.0.1", - "highlight.js": "^10.7.3", - "hosted-git-info": "^9.0.2", - "ignore": "^7.0.5", - "jiti": "^2.7.0", - "minimatch": "^10.2.3", - "proper-lockfile": "^4.1.2", - "typebox": "^1.1.24", - "undici": "^8.3.0", - "yaml": "^2.8.2" + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "glob": "13.0.6", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "typebox": "1.1.38", + "undici": "8.3.0", + "yaml": "2.9.0" }, "overrides": { "rimraf": "6.1.2", @@ -62,18 +62,18 @@ } }, "optionalDependencies": { - "@mariozechner/clipboard": "^0.3.6" + "@mariozechner/clipboard": "0.3.6" }, "devDependencies": { - "@types/cross-spawn": "^6.0.6", - "@types/diff": "^7.0.2", - "@types/hosted-git-info": "^3.0.5", - "@types/ms": "^2.1.0", - "@types/node": "^24.3.0", - "@types/proper-lockfile": "^4.1.4", - "shx": "^0.4.0", - "typescript": "^5.7.3", - "vitest": "^3.2.4" + "@types/cross-spawn": "6.0.6", + "@types/diff": "7.0.2", + "@types/hosted-git-info": "3.0.5", + "@types/ms": "2.1.0", + "@types/node": "24.12.4", + "@types/proper-lockfile": "4.1.4", + "shx": "0.4.0", + "typescript": "5.9.3", + "vitest": "3.2.4" }, "keywords": [ "coding-agent", diff --git a/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts b/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts index 1dd01c9b4..1abe3e288 100644 --- a/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts +++ b/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts @@ -4,12 +4,12 @@ import { join } from "node:path"; import { Agent } from "@earendil-works/pi-agent-core"; import { type AssistantMessage, getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createTestResourceLoader } from "./utilities.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createTestResourceLoader } from "./utilities.ts"; vi.mock("../src/core/compaction/index.js", () => ({ calculateContextTokens: (usage: { diff --git a/packages/coding-agent/test/agent-session-branching.test.ts b/packages/coding-agent/test/agent-session-branching.test.ts index 8590ad746..f516e6d65 100644 --- a/packages/coding-agent/test/agent-session-branching.test.ts +++ b/packages/coding-agent/test/agent-session-branching.test.ts @@ -12,17 +12,17 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import type { AgentSession } from "../src/core/agent-session.js"; +import type { AgentSession } from "../src/core/agent-session.ts"; import { type AgentSessionRuntime, type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, -} from "../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { API_KEY } from "./utilities.js"; +} from "../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { API_KEY } from "./utilities.ts"; describe.skipIf(!API_KEY)("AgentSession forking", () => { let session: AgentSession; diff --git a/packages/coding-agent/test/agent-session-compaction.test.ts b/packages/coding-agent/test/agent-session-compaction.test.ts index da52aecac..5724d6842 100644 --- a/packages/coding-agent/test/agent-session-compaction.test.ts +++ b/packages/coding-agent/test/agent-session-compaction.test.ts @@ -13,13 +13,13 @@ import { join } from "node:path"; import { Agent } from "@earendil-works/pi-agent-core"; import { getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AgentSession, type AgentSessionEvent } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createCodingTools } from "../src/index.js"; -import { API_KEY, createTestResourceLoader } from "./utilities.js"; +import { AgentSession, type AgentSessionEvent } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createCodingTools } from "../src/index.ts"; +import { API_KEY, createTestResourceLoader } from "./utilities.ts"; describe.skipIf(!API_KEY)("AgentSession compaction e2e", () => { let session: AgentSession; diff --git a/packages/coding-agent/test/agent-session-concurrent.test.ts b/packages/coding-agent/test/agent-session-concurrent.test.ts index 876883f21..81f400eae 100644 --- a/packages/coding-agent/test/agent-session-concurrent.test.ts +++ b/packages/coding-agent/test/agent-session-concurrent.test.ts @@ -16,13 +16,13 @@ import { } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import type { BuildSystemPromptOptions } from "../src/core/system-prompt.js"; -import { createTestExtensionsResult, createTestResourceLoader } from "./utilities.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import type { BuildSystemPromptOptions } from "../src/core/system-prompt.ts"; +import { createTestExtensionsResult, createTestResourceLoader } from "./utilities.ts"; // Mock stream that mimics AssistantMessageEventStream class MockAssistantStream extends EventStream { diff --git a/packages/coding-agent/test/agent-session-dynamic-provider.test.ts b/packages/coding-agent/test/agent-session-dynamic-provider.test.ts index e527ca35a..a6da8c9ed 100644 --- a/packages/coding-agent/test/agent-session-dynamic-provider.test.ts +++ b/packages/coding-agent/test/agent-session-dynamic-provider.test.ts @@ -3,12 +3,12 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { DefaultResourceLoader } from "../src/core/resource-loader.js"; -import type { ExtensionFactory } from "../src/core/sdk.js"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { DefaultResourceLoader } from "../src/core/resource-loader.ts"; +import type { ExtensionFactory } from "../src/core/sdk.ts"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; describe("AgentSession dynamic provider registration", () => { let tempDir: string; diff --git a/packages/coding-agent/test/agent-session-dynamic-tools.test.ts b/packages/coding-agent/test/agent-session-dynamic-tools.test.ts index 6c020defe..e58ea22fc 100644 --- a/packages/coding-agent/test/agent-session-dynamic-tools.test.ts +++ b/packages/coding-agent/test/agent-session-dynamic-tools.test.ts @@ -4,10 +4,10 @@ import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultResourceLoader } from "../src/core/resource-loader.js"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { DefaultResourceLoader } from "../src/core/resource-loader.ts"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; describe("AgentSession dynamic tool registration", () => { let tempDir: string; diff --git a/packages/coding-agent/test/agent-session-retry.test.ts b/packages/coding-agent/test/agent-session-retry.test.ts index 25dfd2092..ebba143b3 100644 --- a/packages/coding-agent/test/agent-session-retry.test.ts +++ b/packages/coding-agent/test/agent-session-retry.test.ts @@ -5,12 +5,12 @@ import { Agent, type AgentEvent, type AgentTool } from "@earendil-works/pi-agent import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createTestResourceLoader } from "./utilities.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createTestResourceLoader } from "./utilities.ts"; class MockAssistantStream extends EventStream { constructor() { diff --git a/packages/coding-agent/test/agent-session-runtime-events.test.ts b/packages/coding-agent/test/agent-session-runtime-events.test.ts index dcd705779..42b01fe12 100644 --- a/packages/coding-agent/test/agent-session-runtime-events.test.ts +++ b/packages/coding-agent/test/agent-session-runtime-events.test.ts @@ -8,16 +8,16 @@ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, -} from "../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { SessionManager } from "../src/core/session-manager.js"; +} from "../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; import type { ExtensionFactory, SessionBeforeForkEvent, SessionBeforeSwitchEvent, SessionShutdownEvent, SessionStartEvent, -} from "../src/index.js"; +} from "../src/index.ts"; type RecordedSessionEvent = | SessionBeforeSwitchEvent diff --git a/packages/coding-agent/test/agent-session-stats.test.ts b/packages/coding-agent/test/agent-session-stats.test.ts index 27788b8f6..b435246e6 100644 --- a/packages/coding-agent/test/agent-session-stats.test.ts +++ b/packages/coding-agent/test/agent-session-stats.test.ts @@ -1,12 +1,12 @@ import { Agent } from "@earendil-works/pi-agent-core"; import { type AssistantMessage, getModel, type Usage } from "@earendil-works/pi-ai"; import { describe, expect, it } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createTestResourceLoader } from "./utilities.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createTestResourceLoader } from "./utilities.ts"; const model = getModel("anthropic", "claude-sonnet-4-5")!; diff --git a/packages/coding-agent/test/agent-session-tree-navigation.test.ts b/packages/coding-agent/test/agent-session-tree-navigation.test.ts index 35abae1e5..361e5bffb 100644 --- a/packages/coding-agent/test/agent-session-tree-navigation.test.ts +++ b/packages/coding-agent/test/agent-session-tree-navigation.test.ts @@ -10,7 +10,7 @@ */ import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { API_KEY, createTestSession, type TestSessionContext } from "./utilities.js"; +import { API_KEY, createTestSession, type TestSessionContext } from "./utilities.ts"; describe.skipIf(!API_KEY)("AgentSession tree navigation e2e", () => { let ctx: TestSessionContext; diff --git a/packages/coding-agent/test/ansi-utils.test.ts b/packages/coding-agent/test/ansi-utils.test.ts index 862f04017..15bb43140 100644 --- a/packages/coding-agent/test/ansi-utils.test.ts +++ b/packages/coding-agent/test/ansi-utils.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { stripAnsi } from "../src/utils/ansi.js"; +import { stripAnsi } from "../src/utils/ansi.ts"; function referenceAnsiRegex(): RegExp { const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)"; diff --git a/packages/coding-agent/test/args.test.ts b/packages/coding-agent/test/args.test.ts index ab3ce2a5b..3bf41473c 100644 --- a/packages/coding-agent/test/args.test.ts +++ b/packages/coding-agent/test/args.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "vitest"; -import { parseArgs } from "../src/cli/args.js"; +import { parseArgs } from "../src/cli/args.ts"; describe("parseArgs", () => { describe("--version flag", () => { diff --git a/packages/coding-agent/test/assistant-message.test.ts b/packages/coding-agent/test/assistant-message.test.ts index 9af2a4a2f..137376a5b 100644 --- a/packages/coding-agent/test/assistant-message.test.ts +++ b/packages/coding-agent/test/assistant-message.test.ts @@ -1,7 +1,7 @@ import type { AssistantMessage } from "@earendil-works/pi-ai"; import { describe, expect, test } from "vitest"; -import { AssistantMessageComponent } from "../src/modes/interactive/components/assistant-message.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { AssistantMessageComponent } from "../src/modes/interactive/components/assistant-message.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; const OSC133_ZONE_START = "\x1b]133;A\x07"; const OSC133_ZONE_END = "\x1b]133;B\x07"; diff --git a/packages/coding-agent/test/auth-storage.test.ts b/packages/coding-agent/test/auth-storage.test.ts index ddaef67e8..9ec971001 100644 --- a/packages/coding-agent/test/auth-storage.test.ts +++ b/packages/coding-agent/test/auth-storage.test.ts @@ -4,8 +4,8 @@ import { join } from "node:path"; import { registerOAuthProvider } from "@earendil-works/pi-ai/oauth"; import lockfile from "proper-lockfile"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { clearConfigValueCache } from "../src/core/resolve-config-value.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { clearConfigValueCache } from "../src/core/resolve-config-value.ts"; describe("AuthStorage", () => { let tempDir: string; diff --git a/packages/coding-agent/test/bash-close-hang-windows.test.ts b/packages/coding-agent/test/bash-close-hang-windows.test.ts index 10ae6414e..a17834e24 100644 --- a/packages/coding-agent/test/bash-close-hang-windows.test.ts +++ b/packages/coding-agent/test/bash-close-hang-windows.test.ts @@ -3,8 +3,8 @@ import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { executeBashWithOperations } from "../src/core/bash-executor.js"; -import { createBashTool, createLocalBashOperations } from "../src/core/tools/bash.js"; +import { executeBashWithOperations } from "../src/core/bash-executor.ts"; +import { createBashTool, createLocalBashOperations } from "../src/core/tools/bash.ts"; function toBashSingleQuotedArg(value: string): string { return `'${value.replace(/\\/g, "/").replace(/'/g, `'"'"'`)}'`; diff --git a/packages/coding-agent/test/bash-execution-width.test.ts b/packages/coding-agent/test/bash-execution-width.test.ts index 12a8bb518..9cc64e8c1 100644 --- a/packages/coding-agent/test/bash-execution-width.test.ts +++ b/packages/coding-agent/test/bash-execution-width.test.ts @@ -4,8 +4,8 @@ */ import { visibleWidth } from "@earendil-works/pi-tui"; import { beforeAll, describe, expect, it } from "vitest"; -import { BashExecutionComponent } from "../src/modes/interactive/components/bash-execution.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { BashExecutionComponent } from "../src/modes/interactive/components/bash-execution.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; /** Minimal TUI stub that only exposes terminal.columns */ function createTuiStub(columns: number): { columns: number; stub: any } { diff --git a/packages/coding-agent/test/block-images.test.ts b/packages/coding-agent/test/block-images.test.ts index 2c599276e..19b434595 100644 --- a/packages/coding-agent/test/block-images.test.ts +++ b/packages/coding-agent/test/block-images.test.ts @@ -2,9 +2,9 @@ import { mkdirSync, rmSync, writeFileSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { processFileArguments } from "../src/cli/file-processor.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createReadTool } from "../src/core/tools/read.js"; +import { processFileArguments } from "../src/cli/file-processor.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createReadTool } from "../src/core/tools/read.ts"; // 1x1 red PNG image as base64 (smallest valid PNG) const TINY_PNG_BASE64 = diff --git a/packages/coding-agent/test/clipboard-image-bmp-conversion.test.ts b/packages/coding-agent/test/clipboard-image-bmp-conversion.test.ts index 95107506b..be3a9d953 100644 --- a/packages/coding-agent/test/clipboard-image-bmp-conversion.test.ts +++ b/packages/coding-agent/test/clipboard-image-bmp-conversion.test.ts @@ -68,7 +68,7 @@ vi.mock("@mariozechner/clipboard", () => ({ describe("readClipboardImage BMP conversion", () => { test("converts BMP to PNG on Wayland/WSLg", async () => { - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); // Simulate Wayland session (WSLg) const image = await readClipboardImage({ diff --git a/packages/coding-agent/test/clipboard-image.test.ts b/packages/coding-agent/test/clipboard-image.test.ts index eda61a29e..b7416a4c6 100644 --- a/packages/coding-agent/test/clipboard-image.test.ts +++ b/packages/coding-agent/test/clipboard-image.test.ts @@ -70,7 +70,7 @@ describe("readClipboardImage", () => { throw new Error(`Unexpected spawnSync call: ${command} ${args.join(" ")}`); }); - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); const result = await readClipboardImage({ platform: "linux", env: { WAYLAND_DISPLAY: "1" } }); expect(result).not.toBeNull(); expect(result?.mimeType).toBe("image/png"); @@ -101,7 +101,7 @@ describe("readClipboardImage", () => { return spawnOk(Buffer.alloc(0)); }); - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); const result = await readClipboardImage({ platform: "linux", env: { XDG_SESSION_TYPE: "wayland" } }); expect(result).not.toBeNull(); expect(result?.mimeType).toBe("image/png"); @@ -138,7 +138,7 @@ describe("readClipboardImage", () => { throw new Error(`Unexpected spawnSync call: ${command} ${args.join(" ")}`); }); - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); const result = await readClipboardImage({ platform: "linux", env: { WSL_DISTRO_NAME: "Ubuntu" } }); expect(result).not.toBeNull(); expect(result?.mimeType).toBe("image/png"); @@ -153,7 +153,7 @@ describe("readClipboardImage", () => { mocks.clipboard.hasImage.mockReturnValue(true); mocks.clipboard.getImageBinary.mockResolvedValue(new Uint8Array([7])); - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); const result = await readClipboardImage({ platform: "linux", env: {} }); expect(result).not.toBeNull(); expect(result?.mimeType).toBe("image/png"); @@ -167,7 +167,7 @@ describe("readClipboardImage", () => { mocks.clipboard.hasImage.mockReturnValue(false); - const { readClipboardImage } = await import("../src/utils/clipboard-image.js"); + const { readClipboardImage } = await import("../src/utils/clipboard-image.ts"); const result = await readClipboardImage({ platform: "linux", env: {} }); expect(result).toBeNull(); }); diff --git a/packages/coding-agent/test/clipboard.test.ts b/packages/coding-agent/test/clipboard.test.ts index ea231b572..6ea3a6852 100644 --- a/packages/coding-agent/test/clipboard.test.ts +++ b/packages/coding-agent/test/clipboard.test.ts @@ -1,7 +1,7 @@ import { execSync, spawn } from "child_process"; import { platform } from "os"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import { copyToClipboard } from "../src/utils/clipboard.js"; +import { copyToClipboard } from "../src/utils/clipboard.ts"; const mocks = vi.hoisted(() => { return { diff --git a/packages/coding-agent/test/compaction-extensions-example.test.ts b/packages/coding-agent/test/compaction-extensions-example.test.ts index 4f5e33597..db2f40824 100644 --- a/packages/coding-agent/test/compaction-extensions-example.test.ts +++ b/packages/coding-agent/test/compaction-extensions-example.test.ts @@ -3,7 +3,7 @@ */ import { describe, expect, it } from "vitest"; -import type { ExtensionAPI, SessionBeforeCompactEvent, SessionCompactEvent } from "../src/core/extensions/index.js"; +import type { ExtensionAPI, SessionBeforeCompactEvent, SessionCompactEvent } from "../src/core/extensions/index.ts"; describe("Documentation example", () => { it("custom compaction example should type-check correctly", () => { diff --git a/packages/coding-agent/test/compaction-extensions.test.ts b/packages/coding-agent/test/compaction-extensions.test.ts index 1a134e7bf..2c41210e3 100644 --- a/packages/coding-agent/test/compaction-extensions.test.ts +++ b/packages/coding-agent/test/compaction-extensions.test.ts @@ -8,21 +8,21 @@ import { join } from "node:path"; import { Agent } from "@earendil-works/pi-agent-core"; import { getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; import { createExtensionRuntime, type Extension, type SessionBeforeCompactEvent, type SessionCompactEvent, type SessionEvent, -} from "../src/core/extensions/index.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createSyntheticSourceInfo } from "../src/core/source-info.js"; -import { createCodingTools } from "../src/index.js"; -import { createTestResourceLoader } from "./utilities.js"; +} from "../src/core/extensions/index.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createSyntheticSourceInfo } from "../src/core/source-info.ts"; +import { createCodingTools } from "../src/index.ts"; +import { createTestResourceLoader } from "./utilities.ts"; const API_KEY = process.env.ANTHROPIC_OAUTH_TOKEN || process.env.ANTHROPIC_API_KEY; diff --git a/packages/coding-agent/test/compaction-serialization.test.ts b/packages/coding-agent/test/compaction-serialization.test.ts index 9b11bb0f1..91ca9251a 100644 --- a/packages/coding-agent/test/compaction-serialization.test.ts +++ b/packages/coding-agent/test/compaction-serialization.test.ts @@ -1,6 +1,6 @@ import type { Message } from "@earendil-works/pi-ai"; import { describe, expect, it } from "vitest"; -import { serializeConversation } from "../src/core/compaction/utils.js"; +import { serializeConversation } from "../src/core/compaction/utils.ts"; describe("serializeConversation", () => { it("should truncate long tool results", () => { diff --git a/packages/coding-agent/test/compaction-summary-reasoning.test.ts b/packages/coding-agent/test/compaction-summary-reasoning.test.ts index ea52016bf..6609aca16 100644 --- a/packages/coding-agent/test/compaction-summary-reasoning.test.ts +++ b/packages/coding-agent/test/compaction-summary-reasoning.test.ts @@ -1,7 +1,7 @@ import type { AgentMessage } from "@earendil-works/pi-agent-core"; import type { AssistantMessage, Model } from "@earendil-works/pi-ai"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { type CompactionPreparation, compact, generateSummary } from "../src/core/compaction/index.js"; +import { type CompactionPreparation, compact, generateSummary } from "../src/core/compaction/index.ts"; const { completeSimpleMock } = vi.hoisted(() => ({ completeSimpleMock: vi.fn(), diff --git a/packages/coding-agent/test/compaction.test.ts b/packages/coding-agent/test/compaction.test.ts index ca665543c..929d06ec5 100644 --- a/packages/coding-agent/test/compaction.test.ts +++ b/packages/coding-agent/test/compaction.test.ts @@ -14,7 +14,7 @@ import { getLastAssistantUsage, prepareCompaction, shouldCompact, -} from "../src/core/compaction/index.js"; +} from "../src/core/compaction/index.ts"; import { buildSessionContext, type CompactionEntry, @@ -24,7 +24,7 @@ import { type SessionEntry, type SessionMessageEntry, type ThinkingLevelChangeEntry, -} from "../src/core/session-manager.js"; +} from "../src/core/session-manager.ts"; // ============================================================================ // Test fixtures diff --git a/packages/coding-agent/test/config.test.ts b/packages/coding-agent/test/config.test.ts index 71c4b48b5..c22ff12b4 100644 --- a/packages/coding-agent/test/config.test.ts +++ b/packages/coding-agent/test/config.test.ts @@ -7,7 +7,7 @@ import { getSelfUpdateCommand, getSelfUpdateUnavailableInstruction, getUpdateInstruction, -} from "../src/config.js"; +} from "../src/config.ts"; const execPathDescriptor = Object.getOwnPropertyDescriptor(process, "execPath"); const originalPath = process.env.PATH; diff --git a/packages/coding-agent/test/edit-tool-legacy-input.test.ts b/packages/coding-agent/test/edit-tool-legacy-input.test.ts index 13a8bbeb5..26a550d26 100644 --- a/packages/coding-agent/test/edit-tool-legacy-input.test.ts +++ b/packages/coding-agent/test/edit-tool-legacy-input.test.ts @@ -2,8 +2,8 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { ExtensionContext } from "../src/core/extensions/types.js"; -import { createEditToolDefinition } from "../src/core/tools/edit.js"; +import type { ExtensionContext } from "../src/core/extensions/types.ts"; +import { createEditToolDefinition } from "../src/core/tools/edit.ts"; const tempDirs: string[] = []; diff --git a/packages/coding-agent/test/edit-tool-no-full-redraw.test.ts b/packages/coding-agent/test/edit-tool-no-full-redraw.test.ts index 21d4e7d58..1da9f0df7 100644 --- a/packages/coding-agent/test/edit-tool-no-full-redraw.test.ts +++ b/packages/coding-agent/test/edit-tool-no-full-redraw.test.ts @@ -3,10 +3,10 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { Container, type Terminal, Text, TUI } from "@earendil-works/pi-tui"; import { afterEach, beforeAll, describe, expect, it } from "vitest"; -import { createEditToolDefinition } from "../src/core/tools/edit.js"; -import { computeEditsDiff, type Edit } from "../src/core/tools/edit-diff.js"; -import { ToolExecutionComponent } from "../src/modes/interactive/components/tool-execution.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { createEditToolDefinition } from "../src/core/tools/edit.ts"; +import { computeEditsDiff, type Edit } from "../src/core/tools/edit-diff.ts"; +import { ToolExecutionComponent } from "../src/modes/interactive/components/tool-execution.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; class FakeTerminal implements Terminal { columns = 80; diff --git a/packages/coding-agent/test/export-html-whitespace.test.ts b/packages/coding-agent/test/export-html-whitespace.test.ts index 4336c63cb..9d2a0e84d 100644 --- a/packages/coding-agent/test/export-html-whitespace.test.ts +++ b/packages/coding-agent/test/export-html-whitespace.test.ts @@ -1,10 +1,10 @@ import type { Component } from "@earendil-works/pi-tui"; import { readFileSync } from "fs"; import { describe, expect, it } from "vitest"; -import { ansiLinesToHtml } from "../src/core/export-html/ansi-to-html.js"; -import { createToolHtmlRenderer } from "../src/core/export-html/tool-renderer.js"; -import type { ToolDefinition } from "../src/core/extensions/types.js"; -import type { Theme } from "../src/modes/interactive/theme/theme.js"; +import { ansiLinesToHtml } from "../src/core/export-html/ansi-to-html.ts"; +import { createToolHtmlRenderer } from "../src/core/export-html/tool-renderer.ts"; +import type { ToolDefinition } from "../src/core/extensions/types.ts"; +import type { Theme } from "../src/modes/interactive/theme/theme.ts"; describe("export HTML tool output whitespace", () => { it("preserves whitespace for plain-text tool output lines without preserving template whitespace", () => { diff --git a/packages/coding-agent/test/extensions-discovery.test.ts b/packages/coding-agent/test/extensions-discovery.test.ts index 52029d2cf..3613e9026 100644 --- a/packages/coding-agent/test/extensions-discovery.test.ts +++ b/packages/coding-agent/test/extensions-discovery.test.ts @@ -3,7 +3,7 @@ import * as os from "node:os"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { discoverAndLoadExtensions } from "../src/core/extensions/loader.js"; +import { discoverAndLoadExtensions } from "../src/core/extensions/loader.ts"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -440,7 +440,7 @@ describe("extensions discovery", () => { fs.writeFileSync(explicitPath, extensionCodeWithTool("explicit")); // Use loadExtensions directly to skip discovery - const { loadExtensions } = await import("../src/core/extensions/loader.js"); + const { loadExtensions } = await import("../src/core/extensions/loader.ts"); const result = await loadExtensions([explicitPath], tempDir); expect(result.errors).toHaveLength(0); @@ -454,7 +454,7 @@ describe("extensions discovery", () => { fs.writeFileSync(path.join(extensionsDir, "discovered.ts"), extensionCode); // Use loadExtensions directly with empty paths - const { loadExtensions } = await import("../src/core/extensions/loader.js"); + const { loadExtensions } = await import("../src/core/extensions/loader.ts"); const result = await loadExtensions([], tempDir); expect(result.errors).toHaveLength(0); diff --git a/packages/coding-agent/test/extensions-input-event.test.ts b/packages/coding-agent/test/extensions-input-event.test.ts index 5c08fd2ce..3d5ae5cc0 100644 --- a/packages/coding-agent/test/extensions-input-event.test.ts +++ b/packages/coding-agent/test/extensions-input-event.test.ts @@ -2,11 +2,11 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { discoverAndLoadExtensions } from "../src/core/extensions/loader.js"; -import { ExtensionRunner } from "../src/core/extensions/runner.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { discoverAndLoadExtensions } from "../src/core/extensions/loader.ts"; +import { ExtensionRunner } from "../src/core/extensions/runner.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; describe("Input Event", () => { let tempDir: string; diff --git a/packages/coding-agent/test/extensions-runner.test.ts b/packages/coding-agent/test/extensions-runner.test.ts index 67c462358..03de2d775 100644 --- a/packages/coding-agent/test/extensions-runner.test.ts +++ b/packages/coding-agent/test/extensions-runner.test.ts @@ -6,13 +6,13 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { createExtensionRuntime, discoverAndLoadExtensions } from "../src/core/extensions/loader.js"; -import { ExtensionRunner } from "../src/core/extensions/runner.js"; -import type { ExtensionActions, ExtensionContextActions, ProviderConfig } from "../src/core/extensions/types.js"; -import { KeybindingsManager, type KeyId } from "../src/core/keybindings.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { createExtensionRuntime, discoverAndLoadExtensions } from "../src/core/extensions/loader.ts"; +import { ExtensionRunner } from "../src/core/extensions/runner.ts"; +import type { ExtensionActions, ExtensionContextActions, ProviderConfig } from "../src/core/extensions/types.ts"; +import { KeybindingsManager, type KeyId } from "../src/core/keybindings.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; describe("ExtensionRunner", () => { let tempDir: string; diff --git a/packages/coding-agent/test/file-mutation-queue.test.ts b/packages/coding-agent/test/file-mutation-queue.test.ts index 8b839fe20..73d20c6d4 100644 --- a/packages/coding-agent/test/file-mutation-queue.test.ts +++ b/packages/coding-agent/test/file-mutation-queue.test.ts @@ -2,9 +2,9 @@ import { access, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promi import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { createEditTool } from "../src/core/tools/edit.js"; -import { withFileMutationQueue } from "../src/core/tools/file-mutation-queue.js"; -import { createWriteTool } from "../src/core/tools/write.js"; +import { createEditTool } from "../src/core/tools/edit.ts"; +import { withFileMutationQueue } from "../src/core/tools/file-mutation-queue.ts"; +import { createWriteTool } from "../src/core/tools/write.ts"; function delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/packages/coding-agent/test/footer-data-provider.test.ts b/packages/coding-agent/test/footer-data-provider.test.ts index 3a6e1d47a..4ad9a23a1 100644 --- a/packages/coding-agent/test/footer-data-provider.test.ts +++ b/packages/coding-agent/test/footer-data-provider.test.ts @@ -37,7 +37,7 @@ vi.mock("child_process", () => ({ }), })); -import { FooterDataProvider } from "../src/core/footer-data-provider.js"; +import { FooterDataProvider } from "../src/core/footer-data-provider.ts"; type WorktreeFixture = { worktreeDir: string; diff --git a/packages/coding-agent/test/footer-width.test.ts b/packages/coding-agent/test/footer-width.test.ts index dd158f365..2d9126473 100644 --- a/packages/coding-agent/test/footer-width.test.ts +++ b/packages/coding-agent/test/footer-width.test.ts @@ -1,9 +1,9 @@ import { visibleWidth } from "@earendil-works/pi-tui"; import { beforeAll, describe, expect, it } from "vitest"; -import type { AgentSession } from "../src/core/agent-session.js"; -import type { ReadonlyFooterDataProvider } from "../src/core/footer-data-provider.js"; -import { FooterComponent } from "../src/modes/interactive/components/footer.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import type { AgentSession } from "../src/core/agent-session.ts"; +import type { ReadonlyFooterDataProvider } from "../src/core/footer-data-provider.ts"; +import { FooterComponent } from "../src/modes/interactive/components/footer.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; type AssistantUsage = { input: number; diff --git a/packages/coding-agent/test/frontmatter.test.ts b/packages/coding-agent/test/frontmatter.test.ts index 3879fedf6..43a92985e 100644 --- a/packages/coding-agent/test/frontmatter.test.ts +++ b/packages/coding-agent/test/frontmatter.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { parseFrontmatter, stripFrontmatter } from "../src/utils/frontmatter.js"; +import { parseFrontmatter, stripFrontmatter } from "../src/utils/frontmatter.ts"; describe("parseFrontmatter", () => { it("parses keys, strips quotes, and returns body", () => { diff --git a/packages/coding-agent/test/git-ssh-url.test.ts b/packages/coding-agent/test/git-ssh-url.test.ts index a7d242673..6913b70c4 100644 --- a/packages/coding-agent/test/git-ssh-url.test.ts +++ b/packages/coding-agent/test/git-ssh-url.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { parseGitUrl } from "../src/utils/git.js"; +import { parseGitUrl } from "../src/utils/git.ts"; describe("Git URL Parsing", () => { describe("protocol URLs (accepted without git: prefix)", () => { diff --git a/packages/coding-agent/test/git-update.test.ts b/packages/coding-agent/test/git-update.test.ts index 2cfcb4041..0f574ba6f 100644 --- a/packages/coding-agent/test/git-update.test.ts +++ b/packages/coding-agent/test/git-update.test.ts @@ -12,8 +12,8 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultPackageManager } from "../src/core/package-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { DefaultPackageManager } from "../src/core/package-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; // Helper to run git commands in a directory function git(args: string[], cwd: string): string { diff --git a/packages/coding-agent/test/image-processing.test.ts b/packages/coding-agent/test/image-processing.test.ts index 4dba6f2d9..40f264a83 100644 --- a/packages/coding-agent/test/image-processing.test.ts +++ b/packages/coding-agent/test/image-processing.test.ts @@ -3,8 +3,8 @@ */ import { describe, expect, it } from "vitest"; -import { convertToPng } from "../src/utils/image-convert.js"; -import { formatDimensionNote, resizeImage } from "../src/utils/image-resize.js"; +import { convertToPng } from "../src/utils/image-convert.ts"; +import { formatDimensionNote, resizeImage } from "../src/utils/image-resize.ts"; // Small 2x2 red PNG image (base64) - generated with ImageMagick const TINY_PNG = diff --git a/packages/coding-agent/test/image-resize-callers.test.ts b/packages/coding-agent/test/image-resize-callers.test.ts index 5d1c1a79b..2337ae8ca 100644 --- a/packages/coding-agent/test/image-resize-callers.test.ts +++ b/packages/coding-agent/test/image-resize-callers.test.ts @@ -8,9 +8,9 @@ vi.mock("../src/utils/image-resize.js", () => ({ formatDimensionNote: vi.fn(() => undefined), })); -import { processFileArguments } from "../src/cli/file-processor.js"; -import { createReadTool } from "../src/core/tools/read.js"; -import { resizeImage } from "../src/utils/image-resize.js"; +import { processFileArguments } from "../src/cli/file-processor.ts"; +import { createReadTool } from "../src/core/tools/read.ts"; +import { resizeImage } from "../src/utils/image-resize.ts"; const TINY_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="; diff --git a/packages/coding-agent/test/initial-message.test.ts b/packages/coding-agent/test/initial-message.test.ts index 22b1612da..fae479f78 100644 --- a/packages/coding-agent/test/initial-message.test.ts +++ b/packages/coding-agent/test/initial-message.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest"; -import type { Args } from "../src/cli/args.js"; -import { buildInitialMessage } from "../src/cli/initial-message.js"; +import type { Args } from "../src/cli/args.ts"; +import { buildInitialMessage } from "../src/cli/initial-message.ts"; function createArgs(messages: string[] = []): Args { return { diff --git a/packages/coding-agent/test/interactive-mode-anthropic-warning.test.ts b/packages/coding-agent/test/interactive-mode-anthropic-warning.test.ts index 16ca930a2..10e351928 100644 --- a/packages/coding-agent/test/interactive-mode-anthropic-warning.test.ts +++ b/packages/coding-agent/test/interactive-mode-anthropic-warning.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test, vi } from "vitest"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; function createSettingsManager(warnings: { anthropicExtraUsage?: boolean } = {}) { return { diff --git a/packages/coding-agent/test/interactive-mode-clone-command.test.ts b/packages/coding-agent/test/interactive-mode-clone-command.test.ts index 9388b89fd..fea69c5d3 100644 --- a/packages/coding-agent/test/interactive-mode-clone-command.test.ts +++ b/packages/coding-agent/test/interactive-mode-clone-command.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; type CloneCommandContext = { sessionManager: { getLeafId: () => string | null }; diff --git a/packages/coding-agent/test/interactive-mode-compaction.test.ts b/packages/coding-agent/test/interactive-mode-compaction.test.ts index 85e8e919b..0fc90454e 100644 --- a/packages/coding-agent/test/interactive-mode-compaction.test.ts +++ b/packages/coding-agent/test/interactive-mode-compaction.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test, vi } from "vitest"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; describe("InteractiveMode compaction events", () => { test("rebuilds chat and appends a synthetic compaction summary at the bottom", async () => { diff --git a/packages/coding-agent/test/interactive-mode-import-command.test.ts b/packages/coding-agent/test/interactive-mode-import-command.test.ts index 85575ec03..c2e5ae1fe 100644 --- a/packages/coding-agent/test/interactive-mode-import-command.test.ts +++ b/packages/coding-agent/test/interactive-mode-import-command.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import { SessionImportFileNotFoundError } from "../src/core/agent-session-runtime.js"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; +import { SessionImportFileNotFoundError } from "../src/core/agent-session-runtime.ts"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; type PathCommand = "/export" | "/import"; diff --git a/packages/coding-agent/test/interactive-mode-status.test.ts b/packages/coding-agent/test/interactive-mode-status.test.ts index ba2b46c5f..d5a2c1594 100644 --- a/packages/coding-agent/test/interactive-mode-status.test.ts +++ b/packages/coding-agent/test/interactive-mode-status.test.ts @@ -2,10 +2,10 @@ import { homedir } from "node:os"; import * as path from "node:path"; import { type AutocompleteProvider, CombinedAutocompleteProvider, Container } from "@earendil-works/pi-tui"; import { beforeAll, describe, expect, test, vi } from "vitest"; -import type { AutocompleteProviderFactory } from "../src/core/extensions/types.js"; -import type { SourceInfo } from "../src/core/source-info.js"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import type { AutocompleteProviderFactory } from "../src/core/extensions/types.ts"; +import type { SourceInfo } from "../src/core/source-info.ts"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; function renderLastLine(container: Container, width = 120): string { const last = container.children[container.children.length - 1]; diff --git a/packages/coding-agent/test/interactive-mode-suspend.test.ts b/packages/coding-agent/test/interactive-mode-suspend.test.ts index 3f41fe2ea..996d2f1ab 100644 --- a/packages/coding-agent/test/interactive-mode-suspend.test.ts +++ b/packages/coding-agent/test/interactive-mode-suspend.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, test, vi } from "vitest"; -import { InteractiveMode } from "../src/modes/interactive/interactive-mode.js"; +import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts"; type FakeUi = { start: () => void; diff --git a/packages/coding-agent/test/keybindings-migration.test.ts b/packages/coding-agent/test/keybindings-migration.test.ts index 0799ff253..f393687c4 100644 --- a/packages/coding-agent/test/keybindings-migration.test.ts +++ b/packages/coding-agent/test/keybindings-migration.test.ts @@ -2,9 +2,9 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { ENV_AGENT_DIR } from "../src/config.js"; -import { KeybindingsManager } from "../src/core/keybindings.js"; -import { runMigrations } from "../src/migrations.js"; +import { ENV_AGENT_DIR } from "../src/config.ts"; +import { KeybindingsManager } from "../src/core/keybindings.ts"; +import { runMigrations } from "../src/migrations.ts"; describe("keybindings migration", () => { const tempDirs: string[] = []; diff --git a/packages/coding-agent/test/model-registry.test.ts b/packages/coding-agent/test/model-registry.test.ts index 03434ea81..ad706ab5e 100644 --- a/packages/coding-agent/test/model-registry.test.ts +++ b/packages/coding-agent/test/model-registry.test.ts @@ -5,8 +5,8 @@ import type { AnthropicMessagesCompat, Api, Context, Model, OpenAICompletionsCom import { getApiProvider } from "@earendil-works/pi-ai"; import { getOAuthProvider } from "@earendil-works/pi-ai/oauth"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { clearApiKeyCache, ModelRegistry, type ProviderConfigInput } from "../src/core/model-registry.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { clearApiKeyCache, ModelRegistry, type ProviderConfigInput } from "../src/core/model-registry.ts"; describe("ModelRegistry", () => { let tempDir: string; diff --git a/packages/coding-agent/test/model-resolver.test.ts b/packages/coding-agent/test/model-resolver.test.ts index 69afd7565..7339200bc 100644 --- a/packages/coding-agent/test/model-resolver.test.ts +++ b/packages/coding-agent/test/model-resolver.test.ts @@ -5,7 +5,7 @@ import { findInitialModel, parseModelPattern, resolveCliModel, -} from "../src/core/model-resolver.js"; +} from "../src/core/model-resolver.ts"; // Mock models for testing const mockModels: Model<"anthropic-messages">[] = [ diff --git a/packages/coding-agent/test/oauth-selector.test.ts b/packages/coding-agent/test/oauth-selector.test.ts index 26fd993b4..7164db54b 100644 --- a/packages/coding-agent/test/oauth-selector.test.ts +++ b/packages/coding-agent/test/oauth-selector.test.ts @@ -1,12 +1,12 @@ import { setKeybindings } from "@earendil-works/pi-tui"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { KeybindingsManager } from "../src/core/keybindings.js"; -import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../src/core/provider-display-names.js"; -import { OAuthSelectorComponent } from "../src/modes/interactive/components/oauth-selector.js"; -import { isApiKeyLoginProvider } from "../src/modes/interactive/interactive-mode.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; -import { stripAnsi } from "../src/utils/ansi.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { KeybindingsManager } from "../src/core/keybindings.ts"; +import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../src/core/provider-display-names.ts"; +import { OAuthSelectorComponent } from "../src/modes/interactive/components/oauth-selector.ts"; +import { isApiKeyLoginProvider } from "../src/modes/interactive/interactive-mode.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; +import { stripAnsi } from "../src/utils/ansi.ts"; const originalOpenAiApiKey = process.env.OPENAI_API_KEY; diff --git a/packages/coding-agent/test/package-command-paths.test.ts b/packages/coding-agent/test/package-command-paths.test.ts index 03c8f4ca4..5e4a1a48a 100644 --- a/packages/coding-agent/test/package-command-paths.test.ts +++ b/packages/coding-agent/test/package-command-paths.test.ts @@ -2,8 +2,8 @@ import { mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "no import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { ENV_AGENT_DIR, PACKAGE_NAME, VERSION } from "../src/config.js"; -import { main } from "../src/main.js"; +import { ENV_AGENT_DIR, PACKAGE_NAME, VERSION } from "../src/config.ts"; +import { main } from "../src/main.ts"; describe("package commands", () => { let tempDir: string; diff --git a/packages/coding-agent/test/package-manager-ssh.test.ts b/packages/coding-agent/test/package-manager-ssh.test.ts index 3dc04ab1d..1fa9b9173 100644 --- a/packages/coding-agent/test/package-manager-ssh.test.ts +++ b/packages/coding-agent/test/package-manager-ssh.test.ts @@ -2,8 +2,8 @@ import { mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultPackageManager } from "../src/core/package-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { DefaultPackageManager } from "../src/core/package-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; describe("Package Manager git source parsing", () => { let tempDir: string; diff --git a/packages/coding-agent/test/package-manager.test.ts b/packages/coding-agent/test/package-manager.test.ts index cc6afbc4f..9466d7338 100644 --- a/packages/coding-agent/test/package-manager.test.ts +++ b/packages/coding-agent/test/package-manager.test.ts @@ -4,8 +4,8 @@ import { tmpdir } from "node:os"; import { join, relative } from "node:path"; import { PassThrough } from "node:stream"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { DefaultPackageManager, type ProgressEvent, type ResolvedResource } from "../src/core/package-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { DefaultPackageManager, type ProgressEvent, type ResolvedResource } from "../src/core/package-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; function normalizeForMatch(value: string): string { return value.replace(/\\/g, "/"); @@ -1747,7 +1747,7 @@ Content`, // Main entry point writeFileSync( join(pkgDir, "extensions", "subagent", "index.ts"), - `import { helper } from "./agents.js"; + `import { helper } from "./agents.ts"; export default function(api) { api.registerTool({ name: "test", description: "test", execute: async () => helper() }); }`, ); // Helper module (should NOT be loaded as standalone extension) @@ -1803,7 +1803,7 @@ export default function(api) { api.registerTool({ name: "test", description: "te // Subdirectory with index.ts + helpers writeFileSync( join(pkgDir, "extensions", "complex", "index.ts"), - "import { a } from './a.js'; export default function(api) {}", + "import { a } from './a.ts'; export default function(api) {}", ); writeFileSync(join(pkgDir, "extensions", "complex", "a.ts"), "export const a = 1;"); writeFileSync(join(pkgDir, "extensions", "complex", "b.ts"), "export const b = 2;"); diff --git a/packages/coding-agent/test/path-utils.test.ts b/packages/coding-agent/test/path-utils.test.ts index 2ddf127c4..85c2605f4 100644 --- a/packages/coding-agent/test/path-utils.test.ts +++ b/packages/coding-agent/test/path-utils.test.ts @@ -2,7 +2,7 @@ import { mkdtempSync, readdirSync, rmdirSync, unlinkSync, writeFileSync } from " import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { expandPath, resolveReadPath, resolveToCwd } from "../src/core/tools/path-utils.js"; +import { expandPath, resolveReadPath, resolveToCwd } from "../src/core/tools/path-utils.ts"; describe("path-utils", () => { describe("expandPath", () => { diff --git a/packages/coding-agent/test/paths.test.ts b/packages/coding-agent/test/paths.test.ts index 208da3f91..01151635d 100644 --- a/packages/coding-agent/test/paths.test.ts +++ b/packages/coding-agent/test/paths.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync, writeFileSyn import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { canonicalizePath, getCwdRelativePath, isLocalPath } from "../src/utils/paths.js"; +import { canonicalizePath, getCwdRelativePath, isLocalPath } from "../src/utils/paths.ts"; let tempDir: string; diff --git a/packages/coding-agent/test/pi-user-agent.test.ts b/packages/coding-agent/test/pi-user-agent.test.ts index 64439b210..1c49ca29d 100644 --- a/packages/coding-agent/test/pi-user-agent.test.ts +++ b/packages/coding-agent/test/pi-user-agent.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { getPiUserAgent } from "../src/utils/pi-user-agent.js"; +import { getPiUserAgent } from "../src/utils/pi-user-agent.ts"; describe("getPiUserAgent", () => { it("formats the user agent expected by pi.dev", () => { diff --git a/packages/coding-agent/test/plan-mode-utils.test.ts b/packages/coding-agent/test/plan-mode-utils.test.ts index 8d71ba956..db4b31ec1 100644 --- a/packages/coding-agent/test/plan-mode-utils.test.ts +++ b/packages/coding-agent/test/plan-mode-utils.test.ts @@ -6,7 +6,7 @@ import { isSafeCommand, markCompletedSteps, type TodoItem, -} from "../examples/extensions/plan-mode/utils.js"; +} from "../examples/extensions/plan-mode/utils.ts"; describe("isSafeCommand", () => { describe("safe commands", () => { diff --git a/packages/coding-agent/test/print-mode.test.ts b/packages/coding-agent/test/print-mode.test.ts index bbf6756e0..30d7251de 100644 --- a/packages/coding-agent/test/print-mode.test.ts +++ b/packages/coding-agent/test/print-mode.test.ts @@ -1,7 +1,7 @@ import type { AssistantMessage, ImageContent } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { SessionShutdownEvent } from "../src/index.js"; -import { runPrintMode } from "../src/modes/print-mode.js"; +import type { SessionShutdownEvent } from "../src/index.ts"; +import { runPrintMode } from "../src/modes/print-mode.ts"; type EmitEvent = SessionShutdownEvent; diff --git a/packages/coding-agent/test/prompt-templates.test.ts b/packages/coding-agent/test/prompt-templates.test.ts index 10cecaca7..1e4bcf5ca 100644 --- a/packages/coding-agent/test/prompt-templates.test.ts +++ b/packages/coding-agent/test/prompt-templates.test.ts @@ -12,13 +12,13 @@ import { mkdirSync, rmSync, writeFileSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { afterAll, describe, expect, test } from "vitest"; -import { getAgentDir } from "../src/config.js"; +import { getAgentDir } from "../src/config.ts"; import { expandPromptTemplate, loadPromptTemplates, parseCommandArgs, substituteArgs, -} from "../src/core/prompt-templates.js"; +} from "../src/core/prompt-templates.ts"; // ============================================================================ // substituteArgs diff --git a/packages/coding-agent/test/resource-loader.test.ts b/packages/coding-agent/test/resource-loader.test.ts index 01adc9b36..f023855a3 100644 --- a/packages/coding-agent/test/resource-loader.test.ts +++ b/packages/coding-agent/test/resource-loader.test.ts @@ -2,14 +2,14 @@ import { mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "nod import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ExtensionRunner } from "../src/core/extensions/runner.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { DefaultResourceLoader } from "../src/core/resource-loader.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import type { Skill } from "../src/core/skills.js"; -import { createSyntheticSourceInfo } from "../src/core/source-info.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ExtensionRunner } from "../src/core/extensions/runner.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { DefaultResourceLoader } from "../src/core/resource-loader.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import type { Skill } from "../src/core/skills.ts"; +import { createSyntheticSourceInfo } from "../src/core/source-info.ts"; describe("DefaultResourceLoader", () => { let tempDir: string; diff --git a/packages/coding-agent/test/restore-sandbox-env.test.ts b/packages/coding-agent/test/restore-sandbox-env.test.ts index fa9036eb2..2fb2767f6 100644 --- a/packages/coding-agent/test/restore-sandbox-env.test.ts +++ b/packages/coding-agent/test/restore-sandbox-env.test.ts @@ -6,7 +6,7 @@ vi.mock("node:fs", () => ({ readFileSync, })); -const { restoreSandboxEnv } = await import("../src/bun/restore-sandbox-env.js"); +const { restoreSandboxEnv } = await import("../src/bun/restore-sandbox-env.ts"); describe("restoreSandboxEnv", () => { it("does nothing when not running under bun", () => { diff --git a/packages/coding-agent/test/rpc-client-clone.test.ts b/packages/coding-agent/test/rpc-client-clone.test.ts index f05caa4a6..083f20c99 100644 --- a/packages/coding-agent/test/rpc-client-clone.test.ts +++ b/packages/coding-agent/test/rpc-client-clone.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import { RpcClient } from "../src/modes/rpc/rpc-client.js"; +import { RpcClient } from "../src/modes/rpc/rpc-client.ts"; type RpcClientPrivate = { send: (command: { type: string }) => Promise; diff --git a/packages/coding-agent/test/rpc-example.ts b/packages/coding-agent/test/rpc-example.ts index d82bd9349..aaa24fb1f 100644 --- a/packages/coding-agent/test/rpc-example.ts +++ b/packages/coding-agent/test/rpc-example.ts @@ -1,7 +1,7 @@ import { dirname, join } from "node:path"; import * as readline from "node:readline"; import { fileURLToPath } from "node:url"; -import { RpcClient } from "../src/modes/rpc/rpc-client.js"; +import { RpcClient } from "../src/modes/rpc/rpc-client.ts"; const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/packages/coding-agent/test/rpc-jsonl.test.ts b/packages/coding-agent/test/rpc-jsonl.test.ts index f8ca4538f..c8fc89e13 100644 --- a/packages/coding-agent/test/rpc-jsonl.test.ts +++ b/packages/coding-agent/test/rpc-jsonl.test.ts @@ -1,6 +1,6 @@ import { Readable } from "node:stream"; import { describe, expect, test } from "vitest"; -import { attachJsonlLineReader, serializeJsonLine } from "../src/modes/rpc/jsonl.js"; +import { attachJsonlLineReader, serializeJsonLine } from "../src/modes/rpc/jsonl.ts"; describe("RPC JSONL framing", () => { test("serializes strict JSONL records without escaping Unicode separators", () => { diff --git a/packages/coding-agent/test/rpc-prompt-response-semantics.test.ts b/packages/coding-agent/test/rpc-prompt-response-semantics.test.ts index 07fac54d5..1504a6227 100644 --- a/packages/coding-agent/test/rpc-prompt-response-semantics.test.ts +++ b/packages/coding-agent/test/rpc-prompt-response-semantics.test.ts @@ -10,14 +10,14 @@ import { type Model, } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { AgentSession } from "../src/core/agent-session.js"; -import type { AgentSessionRuntime } from "../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { runRpcMode } from "../src/modes/rpc/rpc-mode.js"; -import { createTestResourceLoader } from "./utilities.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import type { AgentSessionRuntime } from "../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { runRpcMode } from "../src/modes/rpc/rpc-mode.ts"; +import { createTestResourceLoader } from "./utilities.ts"; const rpcIo = vi.hoisted(() => ({ outputLines: [] as string[], diff --git a/packages/coding-agent/test/rpc.test.ts b/packages/coding-agent/test/rpc.test.ts index 9d4a97d49..87447d3bf 100644 --- a/packages/coding-agent/test/rpc.test.ts +++ b/packages/coding-agent/test/rpc.test.ts @@ -4,7 +4,7 @@ import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import type { AgentEvent } from "@earendil-works/pi-agent-core"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; -import { RpcClient } from "../src/modes/rpc/rpc-client.js"; +import { RpcClient } from "../src/modes/rpc/rpc-client.ts"; const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/packages/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts b/packages/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts index fe349646d..a6338d144 100644 --- a/packages/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts +++ b/packages/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env tsx +#!/usr/bin/env node /** * Manual SDK probe for OpenAI Codex prompt caching through the tool loop. * @@ -24,15 +24,15 @@ import { import { getOpenAICodexWebSocketDebugStats, streamSimpleOpenAICodexResponses, -} from "../../ai/src/providers/openai-codex-responses.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { createExtensionRuntime } from "../src/core/extensions/loader.js"; -import type { ToolDefinition } from "../src/core/extensions/types.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import type { ResourceLoader } from "../src/core/resource-loader.js"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +} from "../../ai/src/providers/openai-codex-responses.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { createExtensionRuntime } from "../src/core/extensions/loader.ts"; +import type { ToolDefinition } from "../src/core/extensions/types.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import type { ResourceLoader } from "../src/core/resource-loader.ts"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; type Transport = "sse" | "websocket" | "websocket-cached" | "auto"; @@ -123,7 +123,7 @@ function parseArgs(argv: string[]): Args { } function printHelp(): void { - console.log(`Usage: npx tsx test/sdk-codex-cache-probe-tool-loop.ts [options] + console.log(`Usage: node test/sdk-codex-cache-probe-tool-loop.ts [options] Options: --turns Number of turns to run. Must be between ${MIN_TURNS} and ${MAX_TURNS}. Default: ${DEFAULT_TURNS} diff --git a/packages/coding-agent/test/sdk-openrouter-attribution.test.ts b/packages/coding-agent/test/sdk-openrouter-attribution.test.ts index e667accf8..70bb87091 100644 --- a/packages/coding-agent/test/sdk-openrouter-attribution.test.ts +++ b/packages/coding-agent/test/sdk-openrouter-attribution.test.ts @@ -9,11 +9,11 @@ import { type SimpleStreamOptions, } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; describe("createAgentSession OpenRouter attribution headers", () => { let tempDir: string; diff --git a/packages/coding-agent/test/sdk-session-manager.test.ts b/packages/coding-agent/test/sdk-session-manager.test.ts index 51498f507..cb7e505c7 100644 --- a/packages/coding-agent/test/sdk-session-manager.test.ts +++ b/packages/coding-agent/test/sdk-session-manager.test.ts @@ -3,8 +3,8 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; describe("createAgentSession session manager defaults", () => { let tempDir: string; diff --git a/packages/coding-agent/test/sdk-skills.test.ts b/packages/coding-agent/test/sdk-skills.test.ts index 5f95e67b9..49ade057e 100644 --- a/packages/coding-agent/test/sdk-skills.test.ts +++ b/packages/coding-agent/test/sdk-skills.test.ts @@ -2,11 +2,11 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createExtensionRuntime } from "../src/core/extensions/loader.js"; -import type { ResourceLoader } from "../src/core/resource-loader.js"; -import { createAgentSession } from "../src/core/sdk.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { createSyntheticSourceInfo } from "../src/core/source-info.js"; +import { createExtensionRuntime } from "../src/core/extensions/loader.ts"; +import type { ResourceLoader } from "../src/core/resource-loader.ts"; +import { createAgentSession } from "../src/core/sdk.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { createSyntheticSourceInfo } from "../src/core/source-info.ts"; describe("createAgentSession skills option", () => { let tempDir: string; diff --git a/packages/coding-agent/test/session-cwd.test.ts b/packages/coding-agent/test/session-cwd.test.ts index 72ce6014b..8a7d23fca 100644 --- a/packages/coding-agent/test/session-cwd.test.ts +++ b/packages/coding-agent/test/session-cwd.test.ts @@ -2,9 +2,9 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from "../src/core/agent-session-runtime.js"; -import { getMissingSessionCwdIssue, MissingSessionCwdError } from "../src/core/session-cwd.js"; -import { SessionManager } from "../src/core/session-manager.js"; +import { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from "../src/core/agent-session-runtime.ts"; +import { getMissingSessionCwdIssue, MissingSessionCwdError } from "../src/core/session-cwd.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; function createTempDir(name: string): string { const dir = join(tmpdir(), `${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`); diff --git a/packages/coding-agent/test/session-info-modified-timestamp.test.ts b/packages/coding-agent/test/session-info-modified-timestamp.test.ts index 1dd1cb415..a4322e460 100644 --- a/packages/coding-agent/test/session-info-modified-timestamp.test.ts +++ b/packages/coding-agent/test/session-info-modified-timestamp.test.ts @@ -3,9 +3,9 @@ import { stat } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; -import type { SessionHeader } from "../src/core/session-manager.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import type { SessionHeader } from "../src/core/session-manager.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; function createSessionFile(path: string): void { const header: SessionHeader = { diff --git a/packages/coding-agent/test/session-manager/build-context.test.ts b/packages/coding-agent/test/session-manager/build-context.test.ts index 5bc336a66..a0d8c8e89 100644 --- a/packages/coding-agent/test/session-manager/build-context.test.ts +++ b/packages/coding-agent/test/session-manager/build-context.test.ts @@ -7,7 +7,7 @@ import { type SessionEntry, type SessionMessageEntry, type ThinkingLevelChangeEntry, -} from "../../src/core/session-manager.js"; +} from "../../src/core/session-manager.ts"; function msg(id: string, parentId: string | null, role: "user" | "assistant", text: string): SessionMessageEntry { const base = { type: "message" as const, id, parentId, timestamp: "2025-01-01T00:00:00Z" }; diff --git a/packages/coding-agent/test/session-manager/custom-session-id.test.ts b/packages/coding-agent/test/session-manager/custom-session-id.test.ts index 72eed4658..f9c6ad0d7 100644 --- a/packages/coding-agent/test/session-manager/custom-session-id.test.ts +++ b/packages/coding-agent/test/session-manager/custom-session-id.test.ts @@ -2,7 +2,7 @@ import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { SessionManager } from "../../src/core/session-manager.js"; +import { SessionManager } from "../../src/core/session-manager.ts"; const UUID_V7_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; diff --git a/packages/coding-agent/test/session-manager/file-operations.test.ts b/packages/coding-agent/test/session-manager/file-operations.test.ts index 16ef89e66..c744c3c35 100644 --- a/packages/coding-agent/test/session-manager/file-operations.test.ts +++ b/packages/coding-agent/test/session-manager/file-operations.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { findMostRecentSession, loadEntriesFromFile, SessionManager } from "../../src/core/session-manager.js"; +import { findMostRecentSession, loadEntriesFromFile, SessionManager } from "../../src/core/session-manager.ts"; describe("loadEntriesFromFile", () => { let tempDir: string; diff --git a/packages/coding-agent/test/session-manager/labels.test.ts b/packages/coding-agent/test/session-manager/labels.test.ts index e703abf81..7500746e1 100644 --- a/packages/coding-agent/test/session-manager/labels.test.ts +++ b/packages/coding-agent/test/session-manager/labels.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { type LabelEntry, SessionManager } from "../../src/core/session-manager.js"; +import { type LabelEntry, SessionManager } from "../../src/core/session-manager.ts"; describe("SessionManager labels", () => { it("sets and gets labels", () => { diff --git a/packages/coding-agent/test/session-manager/migration.test.ts b/packages/coding-agent/test/session-manager/migration.test.ts index 1142da378..057742310 100644 --- a/packages/coding-agent/test/session-manager/migration.test.ts +++ b/packages/coding-agent/test/session-manager/migration.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { type FileEntry, migrateSessionEntries } from "../../src/core/session-manager.js"; +import { type FileEntry, migrateSessionEntries } from "../../src/core/session-manager.ts"; describe("migrateSessionEntries", () => { it("should add id/parentId to v1 entries", () => { diff --git a/packages/coding-agent/test/session-manager/save-entry.test.ts b/packages/coding-agent/test/session-manager/save-entry.test.ts index a384a0742..91019b93d 100644 --- a/packages/coding-agent/test/session-manager/save-entry.test.ts +++ b/packages/coding-agent/test/session-manager/save-entry.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { type CustomEntry, SessionManager } from "../../src/core/session-manager.js"; +import { type CustomEntry, SessionManager } from "../../src/core/session-manager.ts"; describe("SessionManager.saveCustomEntry", () => { it("saves custom entries and includes them in tree traversal", () => { diff --git a/packages/coding-agent/test/session-manager/tree-traversal.test.ts b/packages/coding-agent/test/session-manager/tree-traversal.test.ts index 2cfb10bc4..e47ec9095 100644 --- a/packages/coding-agent/test/session-manager/tree-traversal.test.ts +++ b/packages/coding-agent/test/session-manager/tree-traversal.test.ts @@ -2,8 +2,8 @@ import { existsSync, mkdirSync, readFileSync, rmSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { describe, expect, it } from "vitest"; -import { type CustomEntry, SessionManager } from "../../src/core/session-manager.js"; -import { assistantMsg, userMsg } from "../utilities.js"; +import { type CustomEntry, SessionManager } from "../../src/core/session-manager.ts"; +import { assistantMsg, userMsg } from "../utilities.ts"; describe("SessionManager append and tree traversal", () => { describe("append operations", () => { diff --git a/packages/coding-agent/test/session-selector-path-delete.test.ts b/packages/coding-agent/test/session-selector-path-delete.test.ts index 618ceef75..52cae4860 100644 --- a/packages/coding-agent/test/session-selector-path-delete.test.ts +++ b/packages/coding-agent/test/session-selector-path-delete.test.ts @@ -3,10 +3,10 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { setKeybindings } from "@earendil-works/pi-tui"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { KeybindingsManager } from "../src/core/keybindings.js"; -import type { SessionInfo } from "../src/core/session-manager.js"; -import { SessionSelectorComponent } from "../src/modes/interactive/components/session-selector.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { KeybindingsManager } from "../src/core/keybindings.ts"; +import type { SessionInfo } from "../src/core/session-manager.ts"; +import { SessionSelectorComponent } from "../src/modes/interactive/components/session-selector.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; type Deferred = { promise: Promise; diff --git a/packages/coding-agent/test/session-selector-rename.test.ts b/packages/coding-agent/test/session-selector-rename.test.ts index f91d6ebf6..d535496c8 100644 --- a/packages/coding-agent/test/session-selector-rename.test.ts +++ b/packages/coding-agent/test/session-selector-rename.test.ts @@ -1,9 +1,9 @@ import { setKeybindings } from "@earendil-works/pi-tui"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { KeybindingsManager } from "../src/core/keybindings.js"; -import type { SessionInfo } from "../src/core/session-manager.js"; -import { SessionSelectorComponent } from "../src/modes/interactive/components/session-selector.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { KeybindingsManager } from "../src/core/keybindings.ts"; +import type { SessionInfo } from "../src/core/session-manager.ts"; +import { SessionSelectorComponent } from "../src/modes/interactive/components/session-selector.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; async function flushPromises(): Promise { await new Promise((resolve) => { diff --git a/packages/coding-agent/test/session-selector-search.test.ts b/packages/coding-agent/test/session-selector-search.test.ts index f2ffbe1c5..c1aed7137 100644 --- a/packages/coding-agent/test/session-selector-search.test.ts +++ b/packages/coding-agent/test/session-selector-search.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { SessionInfo } from "../src/core/session-manager.js"; -import { filterAndSortSessions } from "../src/modes/interactive/components/session-selector-search.js"; +import type { SessionInfo } from "../src/core/session-manager.ts"; +import { filterAndSortSessions } from "../src/modes/interactive/components/session-selector-search.ts"; function makeSession( overrides: Partial & { id: string; modified: Date; allMessagesText: string }, diff --git a/packages/coding-agent/test/settings-manager-bug.test.ts b/packages/coding-agent/test/settings-manager-bug.test.ts index b79fd9f65..92cc3a821 100644 --- a/packages/coding-agent/test/settings-manager-bug.test.ts +++ b/packages/coding-agent/test/settings-manager-bug.test.ts @@ -1,7 +1,7 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { SettingsManager } from "../src/core/settings-manager.js"; +import { SettingsManager } from "../src/core/settings-manager.ts"; /** * Tests for the fix to a bug where external file changes to arrays were overwritten. diff --git a/packages/coding-agent/test/skills.test.ts b/packages/coding-agent/test/skills.test.ts index 36c02e872..039801994 100644 --- a/packages/coding-agent/test/skills.test.ts +++ b/packages/coding-agent/test/skills.test.ts @@ -1,9 +1,9 @@ import { homedir } from "os"; import { join, resolve } from "path"; import { describe, expect, it } from "vitest"; -import type { ResourceDiagnostic } from "../src/core/diagnostics.js"; -import { formatSkillsForPrompt, loadSkills, loadSkillsFromDir, type Skill } from "../src/core/skills.js"; -import { createSyntheticSourceInfo } from "../src/core/source-info.js"; +import type { ResourceDiagnostic } from "../src/core/diagnostics.ts"; +import { formatSkillsForPrompt, loadSkills, loadSkillsFromDir, type Skill } from "../src/core/skills.ts"; +import { createSyntheticSourceInfo } from "../src/core/source-info.ts"; const fixturesDir = resolve(__dirname, "fixtures/skills"); const collisionFixturesDir = resolve(__dirname, "fixtures/skills-collision"); diff --git a/packages/coding-agent/test/stdout-cleanliness.test.ts b/packages/coding-agent/test/stdout-cleanliness.test.ts index f9455f89c..f6c426a19 100644 --- a/packages/coding-agent/test/stdout-cleanliness.test.ts +++ b/packages/coding-agent/test/stdout-cleanliness.test.ts @@ -3,10 +3,9 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { ENV_AGENT_DIR } from "../src/config.js"; +import { ENV_AGENT_DIR } from "../src/config.ts"; const cliPath = resolve(__dirname, "../src/cli.ts"); -const tsxPath = resolve(__dirname, "../../../node_modules/tsx/dist/cli.mjs"); const tempDirs: string[] = []; @@ -55,7 +54,7 @@ async function runCli(args: string[]): Promise<{ stdout: string; stderr: string; ); return await new Promise((resolvePromise, reject) => { - const child = spawn(process.execPath, [tsxPath, cliPath, ...args], { + const child = spawn(process.execPath, [cliPath, ...args], { cwd: projectDir, env: { ...process.env, diff --git a/packages/coding-agent/test/streaming-render-debug.ts b/packages/coding-agent/test/streaming-render-debug.ts index ffd4cc89b..315c664dd 100644 --- a/packages/coding-agent/test/streaming-render-debug.ts +++ b/packages/coding-agent/test/streaming-render-debug.ts @@ -9,8 +9,8 @@ import { ProcessTerminal, TUI } from "@earendil-works/pi-tui"; import { readFileSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; -import { AssistantMessageComponent } from "../src/modes/interactive/components/assistant-message.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { AssistantMessageComponent } from "../src/modes/interactive/components/assistant-message.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/coding-agent/test/suite/agent-session-bash-persistence.test.ts b/packages/coding-agent/test/suite/agent-session-bash-persistence.test.ts index f59146b40..efd51cfcf 100644 --- a/packages/coding-agent/test/suite/agent-session-bash-persistence.test.ts +++ b/packages/coding-agent/test/suite/agent-session-bash-persistence.test.ts @@ -3,8 +3,8 @@ import type { AgentTool } from "@earendil-works/pi-agent-core"; import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import type { BashOperations } from "../../src/core/tools/bash.js"; -import { createHarness, type Harness } from "./harness.js"; +import type { BashOperations } from "../../src/core/tools/bash.ts"; +import { createHarness, type Harness } from "./harness.ts"; function getEntryTypes(harness: Harness): string[] { return harness.sessionManager.getEntries().map((entry) => entry.type); diff --git a/packages/coding-agent/test/suite/agent-session-compaction.test.ts b/packages/coding-agent/test/suite/agent-session-compaction.test.ts index 8ca5d0e5c..e04732d08 100644 --- a/packages/coding-agent/test/suite/agent-session-compaction.test.ts +++ b/packages/coding-agent/test/suite/agent-session-compaction.test.ts @@ -5,7 +5,7 @@ import { type Model, } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { createHarness, type Harness } from "./harness.js"; +import { createHarness, type Harness } from "./harness.ts"; type SessionWithCompactionInternals = { _checkCompaction: (assistantMessage: AssistantMessage, skipAbortedCheck?: boolean) => Promise; diff --git a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts index 552711477..f6469884b 100644 --- a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts +++ b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts @@ -2,8 +2,8 @@ import type { AgentTool, ThinkingLevel } from "@earendil-works/pi-agent-core"; import { fauxAssistantMessage, fauxToolCall, type Model } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import type { ExtensionAPI } from "../../src/index.js"; -import { createHarness, getAssistantTexts, type Harness } from "./harness.js"; +import type { ExtensionAPI } from "../../src/index.ts"; +import { createHarness, getAssistantTexts, type Harness } from "./harness.ts"; describe("AgentSession model and extension characterization", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/agent-session-prompt.test.ts b/packages/coding-agent/test/suite/agent-session-prompt.test.ts index e40a4fe37..dde25f61e 100644 --- a/packages/coding-agent/test/suite/agent-session-prompt.test.ts +++ b/packages/coding-agent/test/suite/agent-session-prompt.test.ts @@ -5,10 +5,10 @@ import type { AgentTool } from "@earendil-works/pi-agent-core"; import { fauxAssistantMessage, fauxToolCall, type Model } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import type { PromptTemplate } from "../../src/core/prompt-templates.js"; -import { createSyntheticSourceInfo } from "../../src/core/source-info.js"; -import { createTestResourceLoader } from "../utilities.js"; -import { createHarness, getMessageText, type Harness } from "./harness.js"; +import type { PromptTemplate } from "../../src/core/prompt-templates.ts"; +import { createSyntheticSourceInfo } from "../../src/core/source-info.ts"; +import { createTestResourceLoader } from "../utilities.ts"; +import { createHarness, getMessageText, type Harness } from "./harness.ts"; describe("AgentSession prompt characterization", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/agent-session-queue.test.ts b/packages/coding-agent/test/suite/agent-session-queue.test.ts index 06aebcf87..3db7c14b3 100644 --- a/packages/coding-agent/test/suite/agent-session-queue.test.ts +++ b/packages/coding-agent/test/suite/agent-session-queue.test.ts @@ -3,7 +3,7 @@ import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai"; import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, getAssistantTexts, getMessageText, getUserTexts, type Harness } from "./harness.js"; +import { createHarness, getAssistantTexts, getMessageText, getUserTexts, type Harness } from "./harness.ts"; async function createWaitingHarness( options: { diff --git a/packages/coding-agent/test/suite/agent-session-retry-events.test.ts b/packages/coding-agent/test/suite/agent-session-retry-events.test.ts index ff3e5e95a..946f4da9e 100644 --- a/packages/coding-agent/test/suite/agent-session-retry-events.test.ts +++ b/packages/coding-agent/test/suite/agent-session-retry-events.test.ts @@ -2,7 +2,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core"; import { fauxAssistantMessage, fauxThinking, fauxToolCall } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, type Harness } from "./harness.js"; +import { createHarness, type Harness } from "./harness.ts"; function normalizeEventOrder(events: Harness["events"]): string[] { const normalized: string[] = []; diff --git a/packages/coding-agent/test/suite/agent-session-runtime.test.ts b/packages/coding-agent/test/suite/agent-session-runtime.test.ts index fb8b21679..4d839ecfb 100644 --- a/packages/coding-agent/test/suite/agent-session-runtime.test.ts +++ b/packages/coding-agent/test/suite/agent-session-runtime.test.ts @@ -8,9 +8,9 @@ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, -} from "../../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../../src/core/auth-storage.js"; -import { SessionManager } from "../../src/core/session-manager.js"; +} from "../../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../../src/core/auth-storage.ts"; +import { SessionManager } from "../../src/core/session-manager.ts"; import type { ExtensionAPI, ExtensionFactory, @@ -18,7 +18,7 @@ import type { SessionBeforeSwitchEvent, SessionShutdownEvent, SessionStartEvent, -} from "../../src/index.js"; +} from "../../src/index.ts"; type RecordedSessionEvent = | SessionBeforeSwitchEvent diff --git a/packages/coding-agent/test/suite/harness.ts b/packages/coding-agent/test/suite/harness.ts index 16a8182ec..090d56837 100644 --- a/packages/coding-agent/test/suite/harness.ts +++ b/packages/coding-agent/test/suite/harness.ts @@ -9,20 +9,20 @@ import type { AgentMessage, AgentTool } from "@earendil-works/pi-agent-core"; import { Agent } from "@earendil-works/pi-agent-core"; import type { FauxModelDefinition, FauxProviderRegistration, FauxResponseStep, Model } from "@earendil-works/pi-ai"; import { registerFauxProvider } from "@earendil-works/pi-ai"; -import { AgentSession, type AgentSessionEvent } from "../../src/core/agent-session.js"; -import { AuthStorage } from "../../src/core/auth-storage.js"; -import type { ExtensionRunner } from "../../src/core/extensions/index.js"; -import { convertToLlm } from "../../src/core/messages.js"; -import { ModelRegistry } from "../../src/core/model-registry.js"; -import { SessionManager } from "../../src/core/session-manager.js"; -import type { Settings } from "../../src/core/settings-manager.js"; -import { SettingsManager } from "../../src/core/settings-manager.js"; -import type { ExtensionFactory, ResourceLoader } from "../../src/index.js"; +import { AgentSession, type AgentSessionEvent } from "../../src/core/agent-session.ts"; +import { AuthStorage } from "../../src/core/auth-storage.ts"; +import type { ExtensionRunner } from "../../src/core/extensions/index.ts"; +import { convertToLlm } from "../../src/core/messages.ts"; +import { ModelRegistry } from "../../src/core/model-registry.ts"; +import { SessionManager } from "../../src/core/session-manager.ts"; +import type { Settings } from "../../src/core/settings-manager.ts"; +import { SettingsManager } from "../../src/core/settings-manager.ts"; +import type { ExtensionFactory, ResourceLoader } from "../../src/index.ts"; import { type CreateTestExtensionsResultInput, createTestExtensionsResult, createTestResourceLoader, -} from "../utilities.js"; +} from "../utilities.ts"; type MessageTextPart = { type: "text"; text: string }; diff --git a/packages/coding-agent/test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts b/packages/coding-agent/test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts index bea38c9ee..e8658b1b1 100644 --- a/packages/coding-agent/test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts +++ b/packages/coding-agent/test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts @@ -2,7 +2,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core"; import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, type Harness } from "../harness.js"; +import { createHarness, type Harness } from "../harness.ts"; function createEchoTool(): AgentTool { return { diff --git a/packages/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts b/packages/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts index d4adadfaa..cf3f07522 100644 --- a/packages/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts +++ b/packages/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts @@ -3,7 +3,7 @@ import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai"; import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, getAssistantTexts, getUserTexts, type Harness } from "../harness.js"; +import { createHarness, getAssistantTexts, getUserTexts, type Harness } from "../harness.ts"; describe("issue #2023 queued slash-command follow-up", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts b/packages/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts index a95dc7d07..17d9b302b 100644 --- a/packages/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts +++ b/packages/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts @@ -8,9 +8,9 @@ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, -} from "../../../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../../../src/core/auth-storage.js"; -import { SessionManager } from "../../../src/core/session-manager.js"; +} from "../../../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../../../src/core/auth-storage.ts"; +import { SessionManager } from "../../../src/core/session-manager.ts"; describe("issue #2753 reload stale resource settings", () => { const cleanups: Array<() => void> = []; diff --git a/packages/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts b/packages/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts index e7e17f586..cf36e7710 100644 --- a/packages/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts +++ b/packages/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultResourceLoader } from "../../../src/core/resource-loader.js"; +import { DefaultResourceLoader } from "../../../src/core/resource-loader.ts"; describe("issue #2781 skill collision precedence: user skills should override package skills", () => { let tempDir: string; diff --git a/packages/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts b/packages/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts index 007ba580f..ed450c5a9 100644 --- a/packages/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts +++ b/packages/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts @@ -39,7 +39,7 @@ describe("issue #2791 fs.watch error event crashes process", () => { }); it("process should survive an error event on the theme FSWatcher", () => { - const themeModulePath = join(__dirname, "../../../src/modes/interactive/theme/theme.js").replace(/\\/g, "/"); + const themeModulePath = join(__dirname, "../../../src/modes/interactive/theme/theme.ts").replace(/\\/g, "/"); const agentDir = join(tempRoot, "agent").replace(/\\/g, "/"); // Script that sets up the watcher and emits a synthetic error on it. @@ -87,7 +87,7 @@ process.exit(0); let stderr = ""; let exitCode: number; try { - _stdout = execFileSync("npx", ["tsx", scriptPath], { + _stdout = execFileSync(process.execPath, [scriptPath], { timeout: 10000, encoding: "utf-8", env: { ...process.env, PI_CODING_AGENT_DIR: agentDir }, diff --git a/packages/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts b/packages/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts index 7d69c2442..e0003aa69 100644 --- a/packages/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts +++ b/packages/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts @@ -4,10 +4,10 @@ import { join } from "node:path"; import { getModel } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultResourceLoader } from "../../../src/core/resource-loader.js"; -import { createAgentSession } from "../../../src/core/sdk.js"; -import { SessionManager } from "../../../src/core/session-manager.js"; -import { SettingsManager } from "../../../src/core/settings-manager.js"; +import { DefaultResourceLoader } from "../../../src/core/resource-loader.ts"; +import { createAgentSession } from "../../../src/core/sdk.ts"; +import { SessionManager } from "../../../src/core/session-manager.ts"; +import { SettingsManager } from "../../../src/core/settings-manager.ts"; describe("regression #2835: tool allowlists filter extension tools", () => { let tempDir: string; diff --git a/packages/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts b/packages/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts index 21539919c..0e4c061e0 100644 --- a/packages/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts +++ b/packages/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts @@ -3,16 +3,16 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { fauxAssistantMessage, registerFauxProvider } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import type { AgentSession } from "../../../src/core/agent-session.js"; +import type { AgentSession } from "../../../src/core/agent-session.ts"; import { type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, -} from "../../../src/core/agent-session-runtime.js"; -import { AuthStorage } from "../../../src/core/auth-storage.js"; -import { SessionManager } from "../../../src/core/session-manager.js"; -import type { ExtensionAPI, ExtensionCommandContext, ExtensionFactory } from "../../../src/index.js"; +} from "../../../src/core/agent-session-runtime.ts"; +import { AuthStorage } from "../../../src/core/auth-storage.ts"; +import { SessionManager } from "../../../src/core/session-manager.ts"; +import type { ExtensionAPI, ExtensionCommandContext, ExtensionFactory } from "../../../src/index.ts"; function getText(message: AgentSession["messages"][number]): string { if (!("content" in message)) { diff --git a/packages/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts b/packages/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts index e1b7cadd3..b32535ba6 100644 --- a/packages/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts +++ b/packages/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts @@ -1,11 +1,11 @@ import { setKeybindings, type TUI } from "@earendil-works/pi-tui"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { KeybindingsManager } from "../../../src/core/keybindings.js"; -import { ModelSelectorComponent } from "../../../src/modes/interactive/components/model-selector.js"; -import { ScopedModelsSelectorComponent } from "../../../src/modes/interactive/components/scoped-models-selector.js"; -import { initTheme } from "../../../src/modes/interactive/theme/theme.js"; -import { stripAnsi } from "../../../src/utils/ansi.js"; -import { createHarness, type Harness } from "../harness.js"; +import { KeybindingsManager } from "../../../src/core/keybindings.ts"; +import { ModelSelectorComponent } from "../../../src/modes/interactive/components/model-selector.ts"; +import { ScopedModelsSelectorComponent } from "../../../src/modes/interactive/components/scoped-models-selector.ts"; +import { initTheme } from "../../../src/modes/interactive/theme/theme.ts"; +import { stripAnsi } from "../../../src/utils/ansi.ts"; +import { createHarness, type Harness } from "../harness.ts"; function createFakeTui(): TUI { return { diff --git a/packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts b/packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts index 05cf80086..825b4a05c 100644 --- a/packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts +++ b/packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createFindToolDefinition } from "../../../src/core/tools/find.js"; +import { createFindToolDefinition } from "../../../src/core/tools/find.ts"; /** * Regression test for https://github.com/earendil-works/pi-mono/issues/3302 diff --git a/packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts b/packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts index d22b0c18f..bd986cc93 100644 --- a/packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts +++ b/packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createFindToolDefinition } from "../../../src/core/tools/find.js"; +import { createFindToolDefinition } from "../../../src/core/tools/find.ts"; /** * Regression test for https://github.com/earendil-works/pi-mono/issues/3303 diff --git a/packages/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts b/packages/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts index 74276253b..1be6154e4 100644 --- a/packages/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts +++ b/packages/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts @@ -1,6 +1,6 @@ import { fauxAssistantMessage } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, getAssistantTexts, type Harness } from "../harness.js"; +import { createHarness, getAssistantTexts, type Harness } from "../harness.ts"; describe("issue #3317 network connection lost retry", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/regressions/3592-no-builtin-tools-keeps-extension-tools.test.ts b/packages/coding-agent/test/suite/regressions/3592-no-builtin-tools-keeps-extension-tools.test.ts index 27b186f7b..d7d1376cb 100644 --- a/packages/coding-agent/test/suite/regressions/3592-no-builtin-tools-keeps-extension-tools.test.ts +++ b/packages/coding-agent/test/suite/regressions/3592-no-builtin-tools-keeps-extension-tools.test.ts @@ -7,11 +7,11 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { createAgentSessionFromServices, createAgentSessionServices, -} from "../../../src/core/agent-session-services.js"; -import { DefaultResourceLoader } from "../../../src/core/resource-loader.js"; -import { createAgentSession } from "../../../src/core/sdk.js"; -import { SessionManager } from "../../../src/core/session-manager.js"; -import { SettingsManager } from "../../../src/core/settings-manager.js"; +} from "../../../src/core/agent-session-services.ts"; +import { DefaultResourceLoader } from "../../../src/core/resource-loader.ts"; +import { createAgentSession } from "../../../src/core/sdk.ts"; +import { SessionManager } from "../../../src/core/session-manager.ts"; +import { SettingsManager } from "../../../src/core/settings-manager.ts"; describe("regression #3592: no-builtin-tools keeps extension tools enabled", () => { let tempDir: string; diff --git a/packages/coding-agent/test/suite/regressions/3616-settings-inmemory-reload.test.ts b/packages/coding-agent/test/suite/regressions/3616-settings-inmemory-reload.test.ts index daa2c0307..5f92baeb1 100644 --- a/packages/coding-agent/test/suite/regressions/3616-settings-inmemory-reload.test.ts +++ b/packages/coding-agent/test/suite/regressions/3616-settings-inmemory-reload.test.ts @@ -2,8 +2,8 @@ import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { DefaultResourceLoader } from "../../../src/core/resource-loader.js"; -import { SettingsManager } from "../../../src/core/settings-manager.js"; +import { DefaultResourceLoader } from "../../../src/core/resource-loader.ts"; +import { SettingsManager } from "../../../src/core/settings-manager.ts"; describe("regression #3616: in-memory settings survive reload", () => { let tempDir: string; diff --git a/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts b/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts index 3614c09cc..6265ce966 100644 --- a/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts +++ b/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from "vitest"; -import type { ExtensionAPI } from "../../../src/index.js"; -import { createHarness, type Harness } from "../harness.js"; +import type { ExtensionAPI } from "../../../src/index.ts"; +import { createHarness, type Harness } from "../harness.ts"; describe("regression #3686: session name changes emit an event", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/regressions/3688-tree-cancel-compacting.test.ts b/packages/coding-agent/test/suite/regressions/3688-tree-cancel-compacting.test.ts index 67262e2c5..7d0f172ea 100644 --- a/packages/coding-agent/test/suite/regressions/3688-tree-cancel-compacting.test.ts +++ b/packages/coding-agent/test/suite/regressions/3688-tree-cancel-compacting.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from "vitest"; -import { assistantMsg, userMsg } from "../../utilities.js"; -import { createHarness, type Harness } from "../harness.js"; +import { assistantMsg, userMsg } from "../../utilities.ts"; +import { createHarness, type Harness } from "../harness.ts"; describe("issue #3688 tree cancellation compaction state", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/regressions/3982-message-end-cost-override.test.ts b/packages/coding-agent/test/suite/regressions/3982-message-end-cost-override.test.ts index 99a47b33c..757a08ede 100644 --- a/packages/coding-agent/test/suite/regressions/3982-message-end-cost-override.test.ts +++ b/packages/coding-agent/test/suite/regressions/3982-message-end-cost-override.test.ts @@ -1,6 +1,6 @@ import { fauxAssistantMessage } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, type Harness } from "../harness.js"; +import { createHarness, type Harness } from "../harness.ts"; describe("regression #3982: message_end cost override", () => { const harnesses: Harness[] = []; diff --git a/packages/coding-agent/test/suite/regressions/4167-thinking-toggle-pending-tool-render.test.ts b/packages/coding-agent/test/suite/regressions/4167-thinking-toggle-pending-tool-render.test.ts index 0dcd8a95e..307c71de2 100644 --- a/packages/coding-agent/test/suite/regressions/4167-thinking-toggle-pending-tool-render.test.ts +++ b/packages/coding-agent/test/suite/regressions/4167-thinking-toggle-pending-tool-render.test.ts @@ -2,12 +2,12 @@ import type { AgentMessage } from "@earendil-works/pi-agent-core"; import type { AssistantMessage, ToolResultMessage, Usage } from "@earendil-works/pi-ai"; import { Container, Text, type TUI } from "@earendil-works/pi-tui"; import { beforeAll, describe, expect, test, vi } from "vitest"; -import type { AgentSessionEvent } from "../../../src/core/agent-session.js"; -import type { SessionContext } from "../../../src/core/session-manager.js"; -import type { ToolExecutionComponent } from "../../../src/modes/interactive/components/tool-execution.js"; -import { InteractiveMode } from "../../../src/modes/interactive/interactive-mode.js"; -import { initTheme } from "../../../src/modes/interactive/theme/theme.js"; -import { stripAnsi } from "../../../src/utils/ansi.js"; +import type { AgentSessionEvent } from "../../../src/core/agent-session.ts"; +import type { SessionContext } from "../../../src/core/session-manager.ts"; +import type { ToolExecutionComponent } from "../../../src/modes/interactive/components/tool-execution.ts"; +import { InteractiveMode } from "../../../src/modes/interactive/interactive-mode.ts"; +import { initTheme } from "../../../src/modes/interactive/theme/theme.ts"; +import { stripAnsi } from "../../../src/utils/ansi.ts"; const TOOL_CALL_ID = "tool-4167"; const TOOL_NAME = "slow_tool"; diff --git a/packages/coding-agent/test/syntax-highlight.test.ts b/packages/coding-agent/test/syntax-highlight.test.ts index c5cc7ab1a..92d8aa391 100644 --- a/packages/coding-agent/test/syntax-highlight.test.ts +++ b/packages/coding-agent/test/syntax-highlight.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { highlight, renderHighlightedHtml, supportsLanguage } from "../src/utils/syntax-highlight.js"; +import { highlight, renderHighlightedHtml, supportsLanguage } from "../src/utils/syntax-highlight.ts"; describe("syntax highlight renderer", () => { it("renders highlighted spans with the provided theme", () => { diff --git a/packages/coding-agent/test/system-prompt.test.ts b/packages/coding-agent/test/system-prompt.test.ts index bdc190568..82def2278 100644 --- a/packages/coding-agent/test/system-prompt.test.ts +++ b/packages/coding-agent/test/system-prompt.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "vitest"; -import { buildSystemPrompt } from "../src/core/system-prompt.js"; +import { buildSystemPrompt } from "../src/core/system-prompt.ts"; describe("buildSystemPrompt", () => { describe("empty tools", () => { diff --git a/packages/coding-agent/test/test-harness.test.ts b/packages/coding-agent/test/test-harness.test.ts index f9cafa510..2d6e7866f 100644 --- a/packages/coding-agent/test/test-harness.test.ts +++ b/packages/coding-agent/test/test-harness.test.ts @@ -7,7 +7,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core"; import type { AssistantMessage } from "@earendil-works/pi-ai"; import { Type } from "typebox"; import { afterEach, describe, expect, it } from "vitest"; -import { createHarness, createHarnessWithExtensions, type Harness } from "./test-harness.js"; +import { createHarness, createHarnessWithExtensions, type Harness } from "./test-harness.ts"; describe("test harness", () => { let harness: Harness; diff --git a/packages/coding-agent/test/test-harness.ts b/packages/coding-agent/test/test-harness.ts index 269c51463..0ae601ef6 100644 --- a/packages/coding-agent/test/test-harness.ts +++ b/packages/coding-agent/test/test-harness.ts @@ -26,18 +26,18 @@ import type { Usage, } from "@earendil-works/pi-ai"; import { createAssistantMessageEventStream } from "@earendil-works/pi-ai"; -import { AgentSession, type AgentSessionEvent } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import type { Settings } from "../src/core/settings-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import type { ExtensionFactory, ResourceLoader } from "../src/index.js"; +import { AgentSession, type AgentSessionEvent } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import type { Settings } from "../src/core/settings-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import type { ExtensionFactory, ResourceLoader } from "../src/index.ts"; import { type CreateTestExtensionsResultInput, createTestExtensionsResult, createTestResourceLoader, -} from "./utilities.js"; +} from "./utilities.ts"; // ============================================================================ // Faux model diff --git a/packages/coding-agent/test/test-theme-colors.ts b/packages/coding-agent/test/test-theme-colors.ts index a3317026e..70da7b189 100644 --- a/packages/coding-agent/test/test-theme-colors.ts +++ b/packages/coding-agent/test/test-theme-colors.ts @@ -1,5 +1,5 @@ import fs from "fs"; -import { initTheme, theme } from "../src/modes/interactive/theme/theme.js"; +import { initTheme, theme } from "../src/modes/interactive/theme/theme.ts"; // --- Color utilities --- diff --git a/packages/coding-agent/test/theme-detection.test.ts b/packages/coding-agent/test/theme-detection.test.ts index 582358bbb..7bb280b21 100644 --- a/packages/coding-agent/test/theme-detection.test.ts +++ b/packages/coding-agent/test/theme-detection.test.ts @@ -5,7 +5,7 @@ import { getThemeByName, getThemeForRgbColor, parseOsc11BackgroundColor, -} from "../src/modes/interactive/theme/theme.js"; +} from "../src/modes/interactive/theme/theme.ts"; afterEach(() => { resetCapabilitiesCache(); diff --git a/packages/coding-agent/test/theme-export.test.ts b/packages/coding-agent/test/theme-export.test.ts index 84dd649a4..155a07a48 100644 --- a/packages/coding-agent/test/theme-export.test.ts +++ b/packages/coding-agent/test/theme-export.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs" import { tmpdir } from "os"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { getThemeExportColors } from "../src/modes/interactive/theme/theme.js"; +import { getThemeExportColors } from "../src/modes/interactive/theme/theme.ts"; type ThemeFile = { name: string; diff --git a/packages/coding-agent/test/tool-execution-component.test.ts b/packages/coding-agent/test/tool-execution-component.test.ts index 7013ba2aa..54c75806b 100644 --- a/packages/coding-agent/test/tool-execution-component.test.ts +++ b/packages/coding-agent/test/tool-execution-component.test.ts @@ -2,14 +2,14 @@ import { join, resolve } from "node:path"; import { Text, type TUI } from "@earendil-works/pi-tui"; import { Type } from "typebox"; import { beforeAll, describe, expect, test } from "vitest"; -import { getReadmePath } from "../src/config.js"; -import type { ToolDefinition } from "../src/core/extensions/types.js"; -import { type BashOperations, createBashToolDefinition } from "../src/core/tools/bash.js"; -import { createReadTool, createReadToolDefinition } from "../src/core/tools/read.js"; -import { createWriteToolDefinition } from "../src/core/tools/write.js"; -import { ToolExecutionComponent } from "../src/modes/interactive/components/tool-execution.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; -import { stripAnsi } from "../src/utils/ansi.js"; +import { getReadmePath } from "../src/config.ts"; +import type { ToolDefinition } from "../src/core/extensions/types.ts"; +import { type BashOperations, createBashToolDefinition } from "../src/core/tools/bash.ts"; +import { createReadTool, createReadToolDefinition } from "../src/core/tools/read.ts"; +import { createWriteToolDefinition } from "../src/core/tools/write.ts"; +import { ToolExecutionComponent } from "../src/modes/interactive/components/tool-execution.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; +import { stripAnsi } from "../src/utils/ansi.ts"; function createBaseToolDefinition(name = "custom_tool"): ToolDefinition { return { diff --git a/packages/coding-agent/test/tools.test.ts b/packages/coding-agent/test/tools.test.ts index 70e4e54f4..70d4ec2d5 100644 --- a/packages/coding-agent/test/tools.test.ts +++ b/packages/coding-agent/test/tools.test.ts @@ -2,9 +2,9 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } import { tmpdir } from "os"; import { join } from "path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { executeBashWithOperations } from "../src/core/bash-executor.js"; -import { type BashOperations, createBashTool, createLocalBashOperations } from "../src/core/tools/bash.js"; -import { computeEditsDiff } from "../src/core/tools/edit-diff.js"; +import { executeBashWithOperations } from "../src/core/bash-executor.ts"; +import { type BashOperations, createBashTool, createLocalBashOperations } from "../src/core/tools/bash.ts"; +import { computeEditsDiff } from "../src/core/tools/edit-diff.ts"; import { createEditTool, createFindTool, @@ -12,8 +12,8 @@ import { createLsTool, createReadTool, createWriteTool, -} from "../src/index.js"; -import * as shellModule from "../src/utils/shell.js"; +} from "../src/index.ts"; +import * as shellModule from "../src/utils/shell.ts"; const readTool = createReadTool(process.cwd()); const writeTool = createWriteTool(process.cwd()); diff --git a/packages/coding-agent/test/tree-selector.test.ts b/packages/coding-agent/test/tree-selector.test.ts index 3b29d7e0f..8f423dc54 100644 --- a/packages/coding-agent/test/tree-selector.test.ts +++ b/packages/coding-agent/test/tree-selector.test.ts @@ -1,14 +1,14 @@ import { setKeybindings } from "@earendil-works/pi-tui"; import { beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { KeybindingsManager } from "../src/core/keybindings.js"; +import { KeybindingsManager } from "../src/core/keybindings.ts"; import type { ModelChangeEntry, SessionEntry, SessionMessageEntry, SessionTreeNode, -} from "../src/core/session-manager.js"; -import { TreeSelectorComponent } from "../src/modes/interactive/components/tree-selector.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +} from "../src/core/session-manager.ts"; +import { TreeSelectorComponent } from "../src/modes/interactive/components/tree-selector.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; beforeAll(() => { initTheme("dark"); diff --git a/packages/coding-agent/test/trigger-compact-extension.test.ts b/packages/coding-agent/test/trigger-compact-extension.test.ts index 92d2ce956..a8bdbb2a2 100644 --- a/packages/coding-agent/test/trigger-compact-extension.test.ts +++ b/packages/coding-agent/test/trigger-compact-extension.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test, vi } from "vitest"; -import triggerCompactExtension from "../examples/extensions/trigger-compact.js"; -import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "../src/core/extensions/index.js"; +import triggerCompactExtension from "../examples/extensions/trigger-compact.ts"; +import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "../src/core/extensions/index.ts"; function createContext(tokens: number | null, compact = vi.fn()): ExtensionContext { return { diff --git a/packages/coding-agent/test/user-message.test.ts b/packages/coding-agent/test/user-message.test.ts index 7c7568106..1e62e5a86 100644 --- a/packages/coding-agent/test/user-message.test.ts +++ b/packages/coding-agent/test/user-message.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest"; -import { UserMessageComponent } from "../src/modes/interactive/components/user-message.js"; -import { initTheme } from "../src/modes/interactive/theme/theme.js"; +import { UserMessageComponent } from "../src/modes/interactive/components/user-message.ts"; +import { initTheme } from "../src/modes/interactive/theme/theme.ts"; const OSC133_ZONE_START = "\x1b]133;A\x07"; const OSC133_ZONE_END = "\x1b]133;B\x07"; diff --git a/packages/coding-agent/test/utilities.ts b/packages/coding-agent/test/utilities.ts index 058ce8891..5ebf68135 100644 --- a/packages/coding-agent/test/utilities.ts +++ b/packages/coding-agent/test/utilities.ts @@ -8,16 +8,16 @@ import { dirname, join } from "node:path"; import { Agent } from "@earendil-works/pi-agent-core"; import { getModel, type OAuthCredentials, type OAuthProvider } from "@earendil-works/pi-ai"; import { getOAuthApiKey } from "@earendil-works/pi-ai/oauth"; -import { AgentSession } from "../src/core/agent-session.js"; -import { AuthStorage } from "../src/core/auth-storage.js"; -import { createEventBus } from "../src/core/event-bus.js"; -import type { Extension, ExtensionFactory, LoadExtensionsResult } from "../src/core/extensions/index.js"; -import { createExtensionRuntime, loadExtensionFromFactory } from "../src/core/extensions/loader.js"; -import { ModelRegistry } from "../src/core/model-registry.js"; -import type { ResourceLoader } from "../src/core/resource-loader.js"; -import { SessionManager } from "../src/core/session-manager.js"; -import { SettingsManager } from "../src/core/settings-manager.js"; -import { createCodingTools } from "../src/index.js"; +import { AgentSession } from "../src/core/agent-session.ts"; +import { AuthStorage } from "../src/core/auth-storage.ts"; +import { createEventBus } from "../src/core/event-bus.ts"; +import type { Extension, ExtensionFactory, LoadExtensionsResult } from "../src/core/extensions/index.ts"; +import { createExtensionRuntime, loadExtensionFromFactory } from "../src/core/extensions/loader.ts"; +import { ModelRegistry } from "../src/core/model-registry.ts"; +import type { ResourceLoader } from "../src/core/resource-loader.ts"; +import { SessionManager } from "../src/core/session-manager.ts"; +import { SettingsManager } from "../src/core/settings-manager.ts"; +import { createCodingTools } from "../src/index.ts"; /** * API key for authenticated tests. Tests using this should be wrapped in diff --git a/packages/coding-agent/test/version-check.test.ts b/packages/coding-agent/test/version-check.test.ts index f05bfd2e8..70197fa59 100644 --- a/packages/coding-agent/test/version-check.test.ts +++ b/packages/coding-agent/test/version-check.test.ts @@ -5,7 +5,7 @@ import { getLatestPiRelease, getLatestPiVersion, isNewerPackageVersion, -} from "../src/utils/version-check.js"; +} from "../src/utils/version-check.ts"; const originalSkipVersionCheck = process.env.PI_SKIP_VERSION_CHECK; const originalOffline = process.env.PI_OFFLINE; diff --git a/packages/tui/package.json b/packages/tui/package.json index fd6786127..8248d33f5 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -7,7 +7,7 @@ "scripts": { "clean": "shx rm -rf dist", "build": "tsgo -p tsconfig.build.json", - "test": "node --test --import tsx test/*.test.ts", + "test": "node --test test/*.test.ts", "prepublishOnly": "npm run clean && npm run build" }, "files": [ @@ -35,15 +35,15 @@ }, "types": "./dist/index.d.ts", "dependencies": { - "get-east-asian-width": "^1.3.0", - "marked": "^15.0.12" + "get-east-asian-width": "1.6.0", + "marked": "15.0.12" }, "optionalDependencies": { - "koffi": "^2.9.0" + "koffi": "2.16.2" }, "devDependencies": { - "@xterm/headless": "^5.5.0", - "@xterm/xterm": "^5.5.0", - "chalk": "^5.5.0" + "@xterm/headless": "5.5.0", + "@xterm/xterm": "5.5.0", + "chalk": "5.6.2" } } diff --git a/packages/tui/test/autocomplete.test.ts b/packages/tui/test/autocomplete.test.ts index 3e5c82402..be27d152b 100644 --- a/packages/tui/test/autocomplete.test.ts +++ b/packages/tui/test/autocomplete.test.ts @@ -4,7 +4,7 @@ import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { afterEach, beforeEach, describe, it, test } from "node:test"; -import { CombinedAutocompleteProvider } from "../src/autocomplete.js"; +import { CombinedAutocompleteProvider } from "../src/autocomplete.ts"; const resolveFdPath = (): string | null => { const command = process.platform === "win32" ? "where" : "which"; diff --git a/packages/tui/test/bug-regression-isimageline-startswith-bug.test.ts b/packages/tui/test/bug-regression-isimageline-startswith-bug.test.ts index ff15d18fb..b3d25e835 100644 --- a/packages/tui/test/bug-regression-isimageline-startswith-bug.test.ts +++ b/packages/tui/test/bug-regression-isimageline-startswith-bug.test.ts @@ -56,7 +56,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("new implementation returns true correctly", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); // Line containing image escape sequence with text before it const lineWithImageSequence = @@ -68,7 +68,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("new implementation detects Kitty sequences in any position", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); const scenarios = [ "At start: \x1b_Ga=T,f=100,data...\x1b\\", @@ -85,7 +85,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("new implementation detects iTerm2 sequences in any position", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); const scenarios = [ "At start: \x1b]1337;File=size=100,100:base64...\x07", @@ -121,7 +121,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = */ it("detects image sequences in read tool output", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); // Simulate output when read tool processes an image // The line might have text from the read result plus the image escape sequence @@ -131,7 +131,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("detects Kitty sequences from Image component", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); // Kitty image component creates multi-line output with escape sequences const kittyLine = "\x1b_Ga=T,f=100,t=f,d=base64data...\x1b\\\x1b_Gm=i=1;\x1b\\"; @@ -140,7 +140,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("handles ANSI codes before image sequences", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); // Line might have styling (error, warning, etc.) before image data const lines = [ @@ -161,7 +161,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = describe("Crash scenario simulation", () => { it("does NOT crash on very long lines with image sequences", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); /** * Simulate the exact crash scenario: @@ -190,7 +190,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("handles lines exactly matching crash log dimensions", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); /** * Crash log showed: line 58649 chars wide, terminal width 115 @@ -211,7 +211,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = describe("Negative cases: Don't false positive", () => { it("does not detect images in regular long text", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); // Very long line WITHOUT image sequences const longText = "A".repeat(100000); @@ -220,7 +220,7 @@ describe("Bug regression: isImageLine() crash with image escape sequences", () = }); it("does not detect images in lines with file paths", async () => { - const { isImageLine } = await import("../src/terminal-image.js"); + const { isImageLine } = await import("../src/terminal-image.ts"); const filePaths = [ "/path/to/1337/image.jpg", diff --git a/packages/tui/test/chat-simple.ts b/packages/tui/test/chat-simple.ts index 836d1f53a..b6ccd1a85 100644 --- a/packages/tui/test/chat-simple.ts +++ b/packages/tui/test/chat-simple.ts @@ -3,14 +3,14 @@ */ import chalk from "chalk"; -import { CombinedAutocompleteProvider } from "../src/autocomplete.js"; -import { Editor } from "../src/components/editor.js"; -import { Loader } from "../src/components/loader.js"; -import { Markdown } from "../src/components/markdown.js"; -import { Text } from "../src/components/text.js"; -import { ProcessTerminal } from "../src/terminal.js"; -import { TUI } from "../src/tui.js"; -import { defaultEditorTheme, defaultMarkdownTheme } from "./test-themes.js"; +import { CombinedAutocompleteProvider } from "../src/autocomplete.ts"; +import { Editor } from "../src/components/editor.ts"; +import { Loader } from "../src/components/loader.ts"; +import { Markdown } from "../src/components/markdown.ts"; +import { Text } from "../src/components/text.ts"; +import { ProcessTerminal } from "../src/terminal.ts"; +import { TUI } from "../src/tui.ts"; +import { defaultEditorTheme, defaultMarkdownTheme } from "./test-themes.ts"; // Create terminal const terminal = new ProcessTerminal(); diff --git a/packages/tui/test/editor.test.ts b/packages/tui/test/editor.test.ts index 36f7ee7b2..e7e74ec38 100644 --- a/packages/tui/test/editor.test.ts +++ b/packages/tui/test/editor.test.ts @@ -1,12 +1,12 @@ import assert from "node:assert"; import { describe, it } from "node:test"; import { stripVTControlCharacters } from "node:util"; -import { type AutocompleteProvider, CombinedAutocompleteProvider } from "../src/autocomplete.js"; -import { Editor, wordWrapLine } from "../src/components/editor.js"; -import { TUI } from "../src/tui.js"; -import { visibleWidth } from "../src/utils.js"; -import { defaultEditorTheme } from "./test-themes.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { type AutocompleteProvider, CombinedAutocompleteProvider } from "../src/autocomplete.ts"; +import { Editor, wordWrapLine } from "../src/components/editor.ts"; +import { TUI } from "../src/tui.ts"; +import { visibleWidth } from "../src/utils.ts"; +import { defaultEditorTheme } from "./test-themes.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; /** Create a TUI with a virtual terminal for testing */ function createTestTUI(cols = 80, rows = 24): TUI { diff --git a/packages/tui/test/fuzzy.test.ts b/packages/tui/test/fuzzy.test.ts index e784e49c0..7415e963c 100644 --- a/packages/tui/test/fuzzy.test.ts +++ b/packages/tui/test/fuzzy.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { fuzzyFilter, fuzzyMatch } from "../src/fuzzy.js"; +import { fuzzyFilter, fuzzyMatch } from "../src/fuzzy.ts"; describe("fuzzyMatch", () => { it("empty query matches everything with score 0", () => { diff --git a/packages/tui/test/image-test.ts b/packages/tui/test/image-test.ts index 6a29d16d9..116c97d02 100644 --- a/packages/tui/test/image-test.ts +++ b/packages/tui/test/image-test.ts @@ -1,10 +1,10 @@ import { readFileSync } from "fs"; -import { Image } from "../src/components/image.js"; -import { Spacer } from "../src/components/spacer.js"; -import { Text } from "../src/components/text.js"; -import { ProcessTerminal } from "../src/terminal.js"; -import { getCapabilities, getImageDimensions } from "../src/terminal-image.js"; -import { TUI } from "../src/tui.js"; +import { Image } from "../src/components/image.ts"; +import { Spacer } from "../src/components/spacer.ts"; +import { Text } from "../src/components/text.ts"; +import { ProcessTerminal } from "../src/terminal.ts"; +import { getCapabilities, getImageDimensions } from "../src/terminal-image.ts"; +import { TUI } from "../src/tui.ts"; const testImagePath = process.argv[2] || "/tmp/test-image.png"; diff --git a/packages/tui/test/input.test.ts b/packages/tui/test/input.test.ts index 3edd73ca1..e980fb050 100644 --- a/packages/tui/test/input.test.ts +++ b/packages/tui/test/input.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { Input } from "../src/components/input.js"; -import { visibleWidth } from "../src/utils.js"; +import { Input } from "../src/components/input.ts"; +import { visibleWidth } from "../src/utils.ts"; describe("Input component", () => { it("submits value including backslash on Enter", () => { diff --git a/packages/tui/test/key-tester.ts b/packages/tui/test/key-tester.ts index 443ab3ac1..650b98cb2 100755 --- a/packages/tui/test/key-tester.ts +++ b/packages/tui/test/key-tester.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node -import { matchesKey } from "../src/keys.js"; -import { ProcessTerminal } from "../src/terminal.js"; -import { type Component, TUI } from "../src/tui.js"; +import { matchesKey } from "../src/keys.ts"; +import { ProcessTerminal } from "../src/terminal.ts"; +import { type Component, TUI } from "../src/tui.ts"; /** * Simple key code logger component diff --git a/packages/tui/test/keybindings.test.ts b/packages/tui/test/keybindings.test.ts index 7e255b0a2..37c674422 100644 --- a/packages/tui/test/keybindings.test.ts +++ b/packages/tui/test/keybindings.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { KeybindingsManager, TUI_KEYBINDINGS } from "../src/keybindings.js"; +import { KeybindingsManager, TUI_KEYBINDINGS } from "../src/keybindings.ts"; describe("KeybindingsManager", () => { it("does not evict selector confirm when input submit is rebound", () => { diff --git a/packages/tui/test/keys.test.ts b/packages/tui/test/keys.test.ts index 392214cde..e06844e40 100644 --- a/packages/tui/test/keys.test.ts +++ b/packages/tui/test/keys.test.ts @@ -11,7 +11,7 @@ import { matchesKey, parseKey, setKittyProtocolActive, -} from "../src/keys.js"; +} from "../src/keys.ts"; function withEnv(name: string, value: string | undefined, fn: () => void): void { const previous = process.env[name]; diff --git a/packages/tui/test/markdown.test.ts b/packages/tui/test/markdown.test.ts index 2e1ed022f..584c583c7 100644 --- a/packages/tui/test/markdown.test.ts +++ b/packages/tui/test/markdown.test.ts @@ -2,11 +2,11 @@ import assert from "node:assert"; import { afterEach, describe, it } from "node:test"; import type { Terminal as XtermTerminalType } from "@xterm/headless"; import { Chalk } from "chalk"; -import { Markdown } from "../src/components/markdown.js"; -import { resetCapabilitiesCache, setCapabilities } from "../src/terminal-image.js"; -import { type Component, TUI } from "../src/tui.js"; -import { defaultMarkdownTheme } from "./test-themes.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { Markdown } from "../src/components/markdown.ts"; +import { resetCapabilitiesCache, setCapabilities } from "../src/terminal-image.ts"; +import { type Component, TUI } from "../src/tui.ts"; +import { defaultMarkdownTheme } from "./test-themes.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; // Force full color in CI so ANSI assertions are deterministic const chalk = new Chalk({ level: 3 }); diff --git a/packages/tui/test/overlay-non-capturing.test.ts b/packages/tui/test/overlay-non-capturing.test.ts index a0a7a6767..cb91e5e44 100644 --- a/packages/tui/test/overlay-non-capturing.test.ts +++ b/packages/tui/test/overlay-non-capturing.test.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import type { Component, Focusable } from "../src/tui.js"; -import { TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import type { Component, Focusable } from "../src/tui.ts"; +import { TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class StaticOverlay implements Component { private lines: string[]; diff --git a/packages/tui/test/overlay-options.test.ts b/packages/tui/test/overlay-options.test.ts index 942bddd37..c93f26cbd 100644 --- a/packages/tui/test/overlay-options.test.ts +++ b/packages/tui/test/overlay-options.test.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import type { Component } from "../src/tui.js"; -import { TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import type { Component } from "../src/tui.ts"; +import { TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class StaticOverlay implements Component { private lines: string[]; diff --git a/packages/tui/test/overlay-short-content.test.ts b/packages/tui/test/overlay-short-content.test.ts index 7721ea00c..135d8cb9e 100644 --- a/packages/tui/test/overlay-short-content.test.ts +++ b/packages/tui/test/overlay-short-content.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { type Component, TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { type Component, TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class SimpleContent implements Component { private lines: string[]; diff --git a/packages/tui/test/regression-regional-indicator-width.test.ts b/packages/tui/test/regression-regional-indicator-width.test.ts index 675ce97fa..6803e2b1a 100644 --- a/packages/tui/test/regression-regional-indicator-width.test.ts +++ b/packages/tui/test/regression-regional-indicator-width.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { visibleWidth, wrapTextWithAnsi } from "../src/utils.js"; +import { visibleWidth, wrapTextWithAnsi } from "../src/utils.ts"; describe("regional indicator width regression", () => { it("treats partial flag grapheme as full-width to avoid streaming render drift", () => { diff --git a/packages/tui/test/select-list.test.ts b/packages/tui/test/select-list.test.ts index 053690fe4..b5c24212c 100644 --- a/packages/tui/test/select-list.test.ts +++ b/packages/tui/test/select-list.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { SelectList } from "../src/components/select-list.js"; -import { visibleWidth } from "../src/utils.js"; +import { SelectList } from "../src/components/select-list.ts"; +import { visibleWidth } from "../src/utils.ts"; const testTheme = { selectedPrefix: (text: string) => text, diff --git a/packages/tui/test/stdin-buffer.test.ts b/packages/tui/test/stdin-buffer.test.ts index 4f4a00614..e72c14966 100644 --- a/packages/tui/test/stdin-buffer.test.ts +++ b/packages/tui/test/stdin-buffer.test.ts @@ -7,7 +7,7 @@ import assert from "node:assert"; import { beforeEach, describe, it } from "node:test"; -import { StdinBuffer } from "../src/stdin-buffer.js"; +import { StdinBuffer } from "../src/stdin-buffer.ts"; describe("StdinBuffer", () => { let buffer: StdinBuffer; diff --git a/packages/tui/test/terminal-image.test.ts b/packages/tui/test/terminal-image.test.ts index 4f7c238b3..70fbf9eb3 100644 --- a/packages/tui/test/terminal-image.test.ts +++ b/packages/tui/test/terminal-image.test.ts @@ -4,7 +4,7 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { Image } from "../src/components/image.js"; +import { Image } from "../src/components/image.ts"; import { deleteAllKittyImages, deleteKittyImage, @@ -16,7 +16,7 @@ import { resetCapabilitiesCache, setCapabilities, setCellDimensions, -} from "../src/terminal-image.js"; +} from "../src/terminal-image.ts"; const ENV_KEYS = [ "TERM", diff --git a/packages/tui/test/terminal.test.ts b/packages/tui/test/terminal.test.ts index 7099b3dfa..ab2027dfa 100644 --- a/packages/tui/test/terminal.test.ts +++ b/packages/tui/test/terminal.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { ProcessTerminal } from "../src/terminal.js"; +import { ProcessTerminal } from "../src/terminal.ts"; describe("ProcessTerminal dimensions", () => { it("falls back to COLUMNS and LINES before default dimensions", () => { diff --git a/packages/tui/test/test-themes.ts b/packages/tui/test/test-themes.ts index ff68b2bbe..33e3c39e1 100644 --- a/packages/tui/test/test-themes.ts +++ b/packages/tui/test/test-themes.ts @@ -3,7 +3,7 @@ */ import { Chalk } from "chalk"; -import type { EditorTheme, MarkdownTheme, SelectListTheme } from "../src/index.js"; +import type { EditorTheme, MarkdownTheme, SelectListTheme } from "../src/index.ts"; const chalk = new Chalk({ level: 3 }); diff --git a/packages/tui/test/truncate-to-width.test.ts b/packages/tui/test/truncate-to-width.test.ts index 42d93ffa6..321ba8983 100644 --- a/packages/tui/test/truncate-to-width.test.ts +++ b/packages/tui/test/truncate-to-width.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { normalizeTerminalOutput, truncateToWidth, visibleWidth } from "../src/utils.js"; +import { normalizeTerminalOutput, truncateToWidth, visibleWidth } from "../src/utils.ts"; describe("truncateToWidth", () => { it("keeps output within width for very large unicode input", () => { diff --git a/packages/tui/test/truncated-text.test.ts b/packages/tui/test/truncated-text.test.ts index ac1391793..a25034e27 100644 --- a/packages/tui/test/truncated-text.test.ts +++ b/packages/tui/test/truncated-text.test.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import { describe, it } from "node:test"; import { Chalk } from "chalk"; -import { TruncatedText } from "../src/components/truncated-text.js"; -import { visibleWidth } from "../src/utils.js"; +import { TruncatedText } from "../src/components/truncated-text.ts"; +import { visibleWidth } from "../src/utils.ts"; // Force full color in CI so ANSI assertions are deterministic const chalk = new Chalk({ level: 3 }); diff --git a/packages/tui/test/tui-cell-size-input.test.ts b/packages/tui/test/tui-cell-size-input.test.ts index 0ca515d4b..fab915cac 100644 --- a/packages/tui/test/tui-cell-size-input.test.ts +++ b/packages/tui/test/tui-cell-size-input.test.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { getCellDimensions, resetCapabilitiesCache, setCellDimensions } from "../src/terminal-image.js"; -import { type Component, TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { getCellDimensions, resetCapabilitiesCache, setCellDimensions } from "../src/terminal-image.ts"; +import { type Component, TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class InputRecorder implements Component { readonly inputs: string[] = []; diff --git a/packages/tui/test/tui-overlay-style-leak.test.ts b/packages/tui/test/tui-overlay-style-leak.test.ts index df93deefb..a44b699ee 100644 --- a/packages/tui/test/tui-overlay-style-leak.test.ts +++ b/packages/tui/test/tui-overlay-style-leak.test.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import { describe, it } from "node:test"; import type { Terminal as XtermTerminalType } from "@xterm/headless"; -import { type Component, TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { type Component, TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class StaticLines implements Component { private readonly lines: string[]; diff --git a/packages/tui/test/tui-render.test.ts b/packages/tui/test/tui-render.test.ts index 91cb9695e..230a00050 100644 --- a/packages/tui/test/tui-render.test.ts +++ b/packages/tui/test/tui-render.test.ts @@ -1,9 +1,9 @@ import assert from "node:assert"; import { describe, it } from "node:test"; import type { Terminal as XtermTerminalType } from "@xterm/headless"; -import { deleteKittyImage, encodeKitty } from "../src/terminal-image.js"; -import { type Component, TUI } from "../src/tui.js"; -import { VirtualTerminal } from "./virtual-terminal.js"; +import { deleteKittyImage, encodeKitty } from "../src/terminal-image.ts"; +import { type Component, TUI } from "../src/tui.ts"; +import { VirtualTerminal } from "./virtual-terminal.ts"; class TestComponent implements Component { lines: string[] = []; diff --git a/packages/tui/test/viewport-overwrite-repro.ts b/packages/tui/test/viewport-overwrite-repro.ts index 5a0ac4f9c..1ef432a03 100644 --- a/packages/tui/test/viewport-overwrite-repro.ts +++ b/packages/tui/test/viewport-overwrite-repro.ts @@ -17,8 +17,8 @@ * - When content exceeds the viewport and new lines arrive after a tool-call pause, * some earlier PRE-TOOL lines near the bottom are overwritten by POST-TOOL lines. */ -import { ProcessTerminal } from "../src/terminal.js"; -import { type Component, TUI } from "../src/tui.js"; +import { ProcessTerminal } from "../src/terminal.ts"; +import { type Component, TUI } from "../src/tui.ts"; const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/packages/tui/test/virtual-terminal.ts b/packages/tui/test/virtual-terminal.ts index c7ca45102..4e067f4e5 100644 --- a/packages/tui/test/virtual-terminal.ts +++ b/packages/tui/test/virtual-terminal.ts @@ -1,6 +1,6 @@ import type { Terminal as XtermTerminalType } from "@xterm/headless"; import xterm from "@xterm/headless"; -import type { Terminal } from "../src/terminal.js"; +import type { Terminal } from "../src/terminal.ts"; // Extract Terminal class from the module const XtermTerminal = xterm.Terminal; diff --git a/packages/tui/test/wrap-ansi.test.ts b/packages/tui/test/wrap-ansi.test.ts index bd24e8159..52d591480 100644 --- a/packages/tui/test/wrap-ansi.test.ts +++ b/packages/tui/test/wrap-ansi.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert"; import { describe, it } from "node:test"; -import { visibleWidth, wrapTextWithAnsi } from "../src/utils.js"; +import { visibleWidth, wrapTextWithAnsi } from "../src/utils.ts"; describe("wrapTextWithAnsi", () => { describe("underline styling", () => { diff --git a/scripts/cost.ts b/scripts/cost.ts index 2774b8d87..865fbed79 100755 --- a/scripts/cost.ts +++ b/scripts/cost.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env npx tsx +#!/usr/bin/env node import * as fs from "fs"; import * as path from "path"; diff --git a/scripts/session-transcripts.ts b/scripts/session-transcripts.ts index e10dbff9f..4dca6a1d4 100644 --- a/scripts/session-transcripts.ts +++ b/scripts/session-transcripts.ts @@ -1,9 +1,9 @@ -#!/usr/bin/env npx tsx +#!/usr/bin/env node /** * Extracts session transcripts for a given cwd, splits into context-sized files, * optionally spawns subagents to analyze patterns. * - * Usage: npx tsx scripts/session-transcripts.ts [--analyze] [--output ] [cwd] + * Usage: node scripts/session-transcripts.ts [--analyze] [--output ] [cwd] * --analyze Spawn pi subagents to analyze each transcript file * --output Output directory for transcript files (defaults to ./session-transcripts) * cwd Working directory to extract sessions for (defaults to current) @@ -14,7 +14,7 @@ import { spawn } from "child_process"; import { createInterface } from "node:readline"; import { homedir } from "os"; import { join, resolve } from "path"; -import { parseSessionEntries, type SessionMessageEntry } from "../packages/coding-agent/src/core/session-manager.js"; +import { parseSessionEntries, type SessionMessageEntry } from "../packages/coding-agent/src/core/session-manager.ts"; import chalk from "chalk"; const MAX_CHARS_PER_FILE = 100_000; // ~20k tokens, leaving room for prompt + analysis + output diff --git a/scripts/stats.ts b/scripts/stats.ts index 15c353e38..653f4bfb1 100644 --- a/scripts/stats.ts +++ b/scripts/stats.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env npx tsx +#!/usr/bin/env node import { existsSync, readdirSync, readFileSync } from "node:fs"; import { homedir } from "node:os"; diff --git a/scripts/tool-stats.ts b/scripts/tool-stats.ts index 8d39b8683..78a694187 100755 --- a/scripts/tool-stats.ts +++ b/scripts/tool-stats.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env npx tsx +#!/usr/bin/env node import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; import { homedir, tmpdir } from "node:os"; From ea4eab15cf101995c8bb1a56ba842f2d9b1fbdf7 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 13:06:28 +0200 Subject: [PATCH 04/15] chore: add local release and dependency guards --- package.json | 5 +- scripts/check-pinned-deps.mjs | 63 +++++++++ scripts/check-ts-relative-imports.mjs | 74 ++++++++++ scripts/local-release.mjs | 187 ++++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 scripts/check-pinned-deps.mjs create mode 100644 scripts/check-ts-relative-imports.mjs create mode 100644 scripts/local-release.mjs diff --git a/package.json b/package.json index cd0fed1a6..07a7fd3c9 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,10 @@ "scripts": { "clean": "npm run clean --workspaces", "build": "cd packages/tui && npm run build && cd ../ai && npm run build && cd ../agent && npm run build && cd ../coding-agent && npm run build", - "check": "biome check --write --error-on-warnings . && tsgo --noEmit && npm run check:browser-smoke", + "check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:ts-imports && tsgo --noEmit && npm run check:browser-smoke", "check:browser-smoke": "node scripts/check-browser-smoke.mjs", + "check:pinned-deps": "node scripts/check-pinned-deps.mjs", + "check:ts-imports": "node scripts/check-ts-relative-imports.mjs", "profile:tui": "node scripts/profile-coding-agent-node.mjs --mode tui", "profile:rpc": "node scripts/profile-coding-agent-node.mjs --mode rpc", "test": "npm run test --workspaces --if-present", @@ -24,6 +26,7 @@ "prepublishOnly": "npm run clean && npm run build && npm run check", "publish": "npm run prepublishOnly && npm publish -ws --access public", "publish:dry": "npm run prepublishOnly && npm publish -ws --access public --dry-run", + "release:local": "node scripts/local-release.mjs", "release:patch": "node scripts/release.mjs patch", "release:minor": "node scripts/release.mjs minor", "release:major": "node scripts/release.mjs major", diff --git a/scripts/check-pinned-deps.mjs b/scripts/check-pinned-deps.mjs new file mode 100644 index 000000000..a2b389424 --- /dev/null +++ b/scripts/check-pinned-deps.mjs @@ -0,0 +1,63 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +const dependencySections = ["dependencies", "devDependencies", "optionalDependencies"]; +const exactVersionPattern = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/; +const ignoredDirectories = new Set([".git", "dist", "node_modules"]); +const packageJsonFiles = []; + +function collectPackageJsonFiles(directory) { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + if (entry.isDirectory()) { + if (!ignoredDirectories.has(entry.name)) { + collectPackageJsonFiles(join(directory, entry.name)); + } + continue; + } + + if (entry.isFile() && entry.name === "package.json") { + packageJsonFiles.push(join(directory, entry.name)); + } + } +} + +function isInternalWorkspaceDependency(name) { + return name.startsWith("@earendil-works/pi-"); +} + +function isNonRegistrySpecifier(specifier) { + return /^(?:workspace:|file:|link:|portal:|git\+|github:|git:|https?:|ssh:|git:\/\/)/.test(specifier); +} + +function getVersionSpecifier(specifier) { + if (!specifier.startsWith("npm:")) return specifier; + const aliasTarget = specifier.slice("npm:".length); + const versionSeparator = aliasTarget.lastIndexOf("@"); + if (versionSeparator <= 0) return specifier; + return aliasTarget.slice(versionSeparator + 1); +} + +const failures = []; + +collectPackageJsonFiles("."); + +for (const file of packageJsonFiles.sort()) { + const packageJson = JSON.parse(readFileSync(file, "utf8")); + + for (const section of dependencySections) { + const dependencies = packageJson[section]; + if (!dependencies) continue; + + for (const [name, specifier] of Object.entries(dependencies)) { + if (isInternalWorkspaceDependency(name) || isNonRegistrySpecifier(specifier)) continue; + if (exactVersionPattern.test(getVersionSpecifier(specifier))) continue; + failures.push(`${file}: ${section}.${name} must be pinned, found ${specifier}`); + } + } +} + +if (failures.length > 0) { + console.error("Direct external dependencies must use exact versions:"); + for (const failure of failures) console.error(` ${failure}`); + process.exit(1); +} diff --git a/scripts/check-ts-relative-imports.mjs b/scripts/check-ts-relative-imports.mjs new file mode 100644 index 000000000..bf21a5d0a --- /dev/null +++ b/scripts/check-ts-relative-imports.mjs @@ -0,0 +1,74 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import ts from "typescript"; + +const ignoredDirectories = new Set([".git", "coverage", "dist", "node_modules"]); +const files = []; + +function collectTypescriptFiles(directory) { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + if (entry.isDirectory()) { + if (!ignoredDirectories.has(entry.name)) { + collectTypescriptFiles(join(directory, entry.name)); + } + continue; + } + + if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) { + files.push(join(directory, entry.name)); + } + } +} + +function isRelativeJavaScriptSpecifier(specifier) { + return /^\.\.?\//.test(specifier) && /\.js(?:[?#].*)?$/.test(specifier); +} + +function getImportTypeSpecifier(node) { + if (!ts.isLiteralTypeNode(node.argument)) return undefined; + if (!ts.isStringLiteralLike(node.argument.literal)) return undefined; + return node.argument.literal; +} + +const failures = []; + +collectTypescriptFiles("."); + +for (const file of files.sort()) { + const sourceText = readFileSync(file, "utf8"); + const sourceFile = ts.createSourceFile(file, sourceText, ts.ScriptTarget.Latest, true); + + function checkSpecifier(node) { + if (!isRelativeJavaScriptSpecifier(node.text)) return; + const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)); + failures.push(`${file}:${line + 1}:${character + 1}: ${node.text}`); + } + + function visit(node) { + if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) { + checkSpecifier(node.moduleSpecifier); + } else if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) { + checkSpecifier(node.moduleSpecifier); + } else if ( + ts.isCallExpression(node) && + node.expression.kind === ts.SyntaxKind.ImportKeyword && + node.arguments[0] && + ts.isStringLiteralLike(node.arguments[0]) + ) { + checkSpecifier(node.arguments[0]); + } else if (ts.isImportTypeNode(node)) { + const specifier = getImportTypeSpecifier(node); + if (specifier) checkSpecifier(specifier); + } + + ts.forEachChild(node, visit); + } + + visit(sourceFile); +} + +if (failures.length > 0) { + console.error("Relative .js imports are not allowed in non-declaration .ts files:"); + for (const failure of failures) console.error(` ${failure}`); + process.exit(1); +} diff --git a/scripts/local-release.mjs b/scripts/local-release.mjs new file mode 100644 index 000000000..31e07901c --- /dev/null +++ b/scripts/local-release.mjs @@ -0,0 +1,187 @@ +#!/usr/bin/env node + +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, isAbsolute, join, relative, resolve } from "node:path"; +import { spawnSync } from "node:child_process"; + +const packages = [ + { directory: "packages/ai", name: "@earendil-works/pi-ai" }, + { directory: "packages/tui", name: "@earendil-works/pi-tui" }, + { directory: "packages/agent", name: "@earendil-works/pi-agent-core" }, + { directory: "packages/coding-agent", name: "@earendil-works/pi-coding-agent" }, +]; + +function printUsage() { + console.log(`Usage: node scripts/local-release.mjs [options] + +Builds and packs the publishable packages, then installs the tarballs into an +isolated directory outside the repository for local release testing. + +Options: + --out Output directory. Defaults to a new directory under ${tmpdir()} + --force Remove --out first if it already exists + --skip-check Do not run npm run check before building + --skip-install Only create tarballs; do not create the isolated install + --help Show this help +`); +} + +function parseArgs() { + const options = { force: false, outDir: undefined, skipCheck: false, skipInstall: false }; + const args = process.argv.slice(2); + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (arg === "--help") { + printUsage(); + process.exit(0); + } + if (arg === "--force") { + options.force = true; + continue; + } + if (arg === "--skip-check") { + options.skipCheck = true; + continue; + } + if (arg === "--skip-install") { + options.skipInstall = true; + continue; + } + if (arg === "--out") { + const value = args[++i]; + if (!value) { + throw new Error("--out requires a directory"); + } + options.outDir = value; + continue; + } + throw new Error(`Unknown option: ${arg}`); + } + + return options; +} + +function run(command, args, options = {}) { + console.log(`$ ${[command, ...args].join(" ")}`); + const result = spawnSync(command, args, { + cwd: options.cwd, + encoding: "utf8", + stdio: options.capture ? ["inherit", "pipe", "inherit"] : "inherit", + }); + + if (result.status !== 0) { + throw new Error(`Command failed: ${[command, ...args].join(" ")}`); + } + + return result.stdout ?? ""; +} + +function readPackageJson(directory) { + return JSON.parse(readFileSync(join(directory, "package.json"), "utf8")); +} + +function isInsidePath(child, parent) { + const relativePath = relative(parent, child); + return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath)); +} + +function prepareOutputDirectory(options, repoRoot) { + if (!options.outDir) { + return mkdtempSync(join(tmpdir(), "pi-local-release-")); + } + + const outDir = resolve(options.outDir); + + if (isInsidePath(outDir, repoRoot)) { + throw new Error(`Output directory must be outside the repository: ${outDir}`); + } + + if (existsSync(outDir)) { + if (!options.force) { + throw new Error(`Output directory already exists. Use --force to replace it: ${outDir}`); + } + rmSync(outDir, { force: true, recursive: true }); + } + + mkdirSync(outDir, { recursive: true }); + return outDir; +} + +function fileSpecifier(fromDirectory, file) { + const relativePath = relative(fromDirectory, file).replaceAll("\\", "/"); + return `file:${relativePath.startsWith(".") ? relativePath : `./${relativePath}`}`; +} + +function packPackage(pkg, tarballDirectory) { + const packageJson = readPackageJson(pkg.directory); + if (packageJson.name !== pkg.name) { + throw new Error(`${pkg.directory}/package.json has name ${packageJson.name}, expected ${pkg.name}`); + } + + const output = run("npm", ["pack", "--json", "--pack-destination", tarballDirectory], { + capture: true, + cwd: pkg.directory, + }); + const packed = JSON.parse(output)[0]; + return join(tarballDirectory, packed.filename); +} + +const options = parseArgs(); +const repoRoot = process.cwd(); +const rootPackageJson = readPackageJson(repoRoot); + +if (rootPackageJson.name !== "pi-monorepo") { + throw new Error("Run this script from the repository root"); +} + +const outDir = prepareOutputDirectory(options, repoRoot); +const tarballDirectory = join(outDir, "tarballs"); +const installDirectory = join(outDir, "install"); +const binDirectory = join(outDir, "bin"); +mkdirSync(tarballDirectory, { recursive: true }); + +if (!options.skipCheck) { + run("npm", ["run", "check"], { cwd: repoRoot }); +} + +for (const pkg of packages) { + run("npm", ["run", "clean"], { cwd: pkg.directory }); + run("npm", ["run", "build"], { cwd: pkg.directory }); +} + +const tarballs = new Map(); +for (const pkg of packages) { + const tarball = packPackage(pkg, tarballDirectory); + tarballs.set(pkg.name, tarball); +} + +if (!options.skipInstall) { + mkdirSync(installDirectory, { recursive: true }); + const dependencies = Object.fromEntries( + packages.map((pkg) => [pkg.name, fileSpecifier(installDirectory, tarballs.get(pkg.name))]), + ); + writeFileSync( + join(installDirectory, "package.json"), + `${JSON.stringify({ private: true, dependencies }, undefined, "\t")}\n`, + ); + + run("npm", ["install", "--omit=dev"], { cwd: installDirectory }); + mkdirSync(binDirectory, { recursive: true }); + symlinkSync(join(installDirectory, "node_modules", ".bin", "pi"), join(binDirectory, "pi")); +} + +console.log("\nLocal release artifacts created:"); +console.log(` ${outDir}`); +console.log("\nTarballs:"); +for (const tarball of tarballs.values()) { + console.log(` ${tarball}`); +} + +if (!options.skipInstall) { + console.log("\nIsolated install:"); + console.log(` ${installDirectory}`); + console.log("\nRun the locally packed CLI from outside the repository:"); + console.log(` ${join(binDirectory, "pi")} --help`); +} From fec3871432b45602c38dd2f85a8788951a0f5e80 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 13:38:40 +0200 Subject: [PATCH 05/15] docs: require local release smoke test --- AGENTS.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3e752675f..a05fab617 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -190,13 +190,23 @@ Create provider file exporting: 1. **Update CHANGELOGs**: Ensure all changes since last release are documented in the `[Unreleased]` section of each affected package's CHANGELOG.md -2. **Run release script**: +2. **Soft gate: local release smoke test**: Before running the real release script, build an unpublished local release and manually smoke test it from outside the repository so it cannot accidentally resolve workspace files: + ```bash + npm run release:local -- --out /tmp/pi-local-release --force + cd /tmp + /tmp/pi-local-release/bin/pi --help + /tmp/pi-local-release/bin/pi --version + /tmp/pi-local-release/bin/pi + ``` + In the interactive smoke test, verify startup, model/account listing, and at least one real prompt with the intended default provider. Treat failures as release blockers unless the user explicitly accepts the risk. + +3. **Run release script**: ```bash npm run release:patch # Fixes and additions npm run release:minor # API breaking changes ``` -The script handles: version bump, CHANGELOG finalization, commit, tag, publish, and adding new `[Unreleased]` sections. +The release script handles: version bump, CHANGELOG finalization, commit, tag, publish, and adding new `[Unreleased]` sections. ## **CRITICAL** Git Rules for Parallel Agents **CRITICAL** From dce24ac9ff98d4d4df7a7a6129468932f2c50508 Mon Sep 17 00:00:00 2001 From: Sviatoslav Abakumov Date: Wed, 20 May 2026 15:54:11 +0400 Subject: [PATCH 06/15] fix(coding-agent): keep fork session id aligned --- packages/coding-agent/src/core/agent-session-runtime.ts | 5 ++--- .../coding-agent/test/suite/agent-session-runtime.test.ts | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/coding-agent/src/core/agent-session-runtime.ts b/packages/coding-agent/src/core/agent-session-runtime.ts index a89fef835..b4756d4cf 100644 --- a/packages/coding-agent/src/core/agent-session-runtime.ts +++ b/packages/coding-agent/src/core/agent-session-runtime.ts @@ -292,12 +292,11 @@ export class AgentSessionRuntime { return { cancelled: false, selectedText }; } - const sourceManager = SessionManager.open(currentSessionFile, sessionDir); - const forkedSessionPath = sourceManager.createBranchedSession(targetLeafId); + const sessionManager = SessionManager.open(currentSessionFile, sessionDir); + const forkedSessionPath = sessionManager.createBranchedSession(targetLeafId); if (!forkedSessionPath) { throw new Error("Failed to create forked session"); } - const sessionManager = SessionManager.open(forkedSessionPath, sessionDir); await this.teardownCurrent("fork", sessionManager.getSessionFile()); this.apply( await this.createRuntime({ diff --git a/packages/coding-agent/test/suite/agent-session-runtime.test.ts b/packages/coding-agent/test/suite/agent-session-runtime.test.ts index fb8b21679..a4d6e04de 100644 --- a/packages/coding-agent/test/suite/agent-session-runtime.test.ts +++ b/packages/coding-agent/test/suite/agent-session-runtime.test.ts @@ -1,6 +1,6 @@ import { existsSync, mkdirSync, realpathSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; -import { join } from "node:path"; +import { join, parse } from "node:path"; import { fauxAssistantMessage, registerFauxProvider } from "@earendil-works/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; import { @@ -274,6 +274,8 @@ describe("AgentSessionRuntime characterization", () => { { type: "session_shutdown", reason: "fork", targetSessionFile: runtime.session.sessionFile }, { type: "session_start", reason: "fork", previousSessionFile }, ]); + const sessionFileName = parse(runtime.session.sessionFile!).name; + expect(sessionFileName.endsWith(`_${runtime.session.sessionId}`)).toBe(true); events.length = 0; cancelNextFork = true; From 715c82ce0454b4fa9d6791bca22d6d694a2a0b28 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 14:19:40 +0200 Subject: [PATCH 07/15] chore: shrinkwrap coding agent release deps --- package.json | 10 +- packages/coding-agent/CHANGELOG.md | 1 + packages/coding-agent/npm-shrinkwrap.json | 1803 ++++++++++++++++++ packages/coding-agent/package.json | 6 +- scripts/build-binaries.sh | 2 +- scripts/generate-coding-agent-shrinkwrap.mjs | 340 ++++ scripts/release.mjs | 28 +- 7 files changed, 2171 insertions(+), 19 deletions(-) create mode 100644 packages/coding-agent/npm-shrinkwrap.json create mode 100644 scripts/generate-coding-agent-shrinkwrap.mjs diff --git a/package.json b/package.json index 07a7fd3c9..daa4b4e51 100644 --- a/package.json +++ b/package.json @@ -12,21 +12,23 @@ "scripts": { "clean": "npm run clean --workspaces", "build": "cd packages/tui && npm run build && cd ../ai && npm run build && cd ../agent && npm run build && cd ../coding-agent && npm run build", - "check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:ts-imports && tsgo --noEmit && npm run check:browser-smoke", + "check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:ts-imports && npm run check:shrinkwrap && tsgo --noEmit && npm run check:browser-smoke", "check:browser-smoke": "node scripts/check-browser-smoke.mjs", "check:pinned-deps": "node scripts/check-pinned-deps.mjs", + "check:shrinkwrap": "node scripts/generate-coding-agent-shrinkwrap.mjs --check", "check:ts-imports": "node scripts/check-ts-relative-imports.mjs", "profile:tui": "node scripts/profile-coding-agent-node.mjs --mode tui", "profile:rpc": "node scripts/profile-coding-agent-node.mjs --mode rpc", "test": "npm run test --workspaces --if-present", - "version:patch": "npm version patch -ws --no-git-tag-version && node scripts/sync-versions.js && shx rm -rf node_modules packages/*/node_modules package-lock.json && npm install", - "version:minor": "npm version minor -ws --no-git-tag-version && node scripts/sync-versions.js && shx rm -rf node_modules packages/*/node_modules package-lock.json && npm install", - "version:major": "npm version major -ws --no-git-tag-version && node scripts/sync-versions.js && shx rm -rf node_modules packages/*/node_modules package-lock.json && npm install", + "version:patch": "npm version patch -ws --no-git-tag-version && node scripts/sync-versions.js && npm install --package-lock-only", + "version:minor": "npm version minor -ws --no-git-tag-version && node scripts/sync-versions.js && npm install --package-lock-only", + "version:major": "npm version major -ws --no-git-tag-version && node scripts/sync-versions.js && npm install --package-lock-only", "version:set": "npm version -ws", "prepublishOnly": "npm run clean && npm run build && npm run check", "publish": "npm run prepublishOnly && npm publish -ws --access public", "publish:dry": "npm run prepublishOnly && npm publish -ws --access public --dry-run", "release:local": "node scripts/local-release.mjs", + "shrinkwrap:coding-agent": "node scripts/generate-coding-agent-shrinkwrap.mjs", "release:patch": "node scripts/release.mjs patch", "release:minor": "node scripts/release.mjs minor", "release:major": "node scripts/release.mjs major", diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 582015c0d..f902be1eb 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -6,6 +6,7 @@ - Changed source syntax to avoid TypeScript constructs that require JavaScript emit, keeping core sources compatible with Node.js strip-only TypeScript checks. - Removed web UI workspace references from the CLI package and dropped the package-level development watch script. +- Published npm installs now include an `npm-shrinkwrap.json` to lock transitive dependencies for the CLI package. ### Fixed diff --git a/packages/coding-agent/npm-shrinkwrap.json b/packages/coding-agent/npm-shrinkwrap.json new file mode 100644 index 000000000..174e6d17d --- /dev/null +++ b/packages/coding-agent/npm-shrinkwrap.json @@ -0,0 +1,1803 @@ +{ + "name": "@earendil-works/pi-coding-agent", + "version": "0.75.3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@earendil-works/pi-coding-agent", + "version": "0.75.3", + "license": "MIT", + "dependencies": { + "@earendil-works/pi-agent-core": "^0.75.3", + "@earendil-works/pi-ai": "^0.75.3", + "@earendil-works/pi-tui": "^0.75.3", + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "glob": "13.0.6", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "typebox": "1.1.38", + "undici": "8.3.0", + "yaml": "2.9.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "0.3.6" + }, + "bin": { + "pi": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.974.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.11.tgz", + "integrity": "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.24", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.37.tgz", + "integrity": "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.39.tgz", + "integrity": "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.41.tgz", + "integrity": "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-login": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.41.tgz", + "integrity": "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.42.tgz", + "integrity": "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-ini": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.37.tgz", + "integrity": "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.41.tgz", + "integrity": "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.41.tgz", + "integrity": "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.16.tgz", + "integrity": "sha512-yedpPgKftqjU5SlPFHfqWpOw6xSCRieWRG1euWOlXn4WJxt2VX92VprCa2PpSOXjVCAeK6dTjW9eJRXVig9yGA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.12.tgz", + "integrity": "sha512-tHTHHCHNrq6XklQvlzHBDJG4Iuhh7NVPRdtmvP+nHFA+5sxPlIDzlAHHgfoYHGvT3NXP1yVP/L5c3opUn6T3Qg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.19.tgz", + "integrity": "sha512-mkEhOGYozqKQkbFaVrjwr0faiwwZza1v5/jSY6Tucm3bD+uKTazIUH/4Yo6aMnQD2ua2W9cMP6s8mvwTcjtqHw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.9.tgz", + "integrity": "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/signature-v4-multi-region": "^3.996.27", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.27.tgz", + "integrity": "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.24.tgz", + "integrity": "sha512-V8z5YcDPfsvzrBlj0xR1vhRtocblhYbqdreCJB/voGd4Sr5zjNAeWxexbnqVtskTJe0vFb5KMqbSL++ePl+zRw==", + "license": "Apache-2.0", + "dependencies": { + "@nodable/entities": "2.1.0", + "@smithy/types": "^4.14.1", + "fast-xml-parser": "5.7.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@earendil-works/pi-agent-core": { + "version": "0.75.3", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.75.3.tgz", + "license": "MIT", + "dependencies": { + "@earendil-works/pi-ai": "^0.75.3", + "ignore": "7.0.5", + "typebox": "1.1.38", + "yaml": "2.9.0" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.75.3", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.75.3.tgz", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.1", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.26.0", + "partial-json": "0.1.7", + "typebox": "1.1.38" + }, + "bin": { + "pi-ai": "./dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-tui": { + "version": "0.75.3", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.75.3.tgz", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "15.0.12" + }, + "optionalDependencies": { + "koffi": "2.16.2" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + }, + "engines": { + "node": ">=20.0.0" + }, + "hasInstallScript": true + }, + "node_modules/@mariozechner/clipboard": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.6.tgz", + "integrity": "sha512-MXdtr+6+ntlIVHdrZYuZNQydu6o8yZswFJ2Ln81j2O/Y9B/LDHvEaIm95xWNPkjGTWriSOeLnQJRFs6dYb60bg==", + "license": "MIT", + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.6", + "@mariozechner/clipboard-darwin-universal": "0.3.6", + "@mariozechner/clipboard-darwin-x64": "0.3.6", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.6", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.6", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.6", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.6", + "@mariozechner/clipboard-linux-x64-musl": "0.3.6", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.6", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.6" + }, + "engines": { + "node": ">= 10" + }, + "optional": true + }, + "node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.6.tgz", + "integrity": "sha512-HjaisYCAbHi/1+N1yDAQHc8ZXGffufIUT5NSOSVR3f3AuMDusxTtnbK8tZ7JFDkShua1oNGZoNwQHsc8MPtE0Q==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "darwin" + ], + "cpu": [ + "arm64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.6.tgz", + "integrity": "sha512-8BWtPjOtJOJoykml3w0fx0zRrfWP31mXrJwfoA7xzNprkZw1uolCNfgmjDiVBseoKjp16EGITz7bN+61qn8dWA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "darwin" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.6.tgz", + "integrity": "sha512-p9syiZD1kU4I+1ya7f7g+zD1GiUvR8fdlRlNmgsZNWlyjtc8rlV2EjTLd/35x1LsdBq020GVvtzp0ZmPgBI09Q==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "darwin" + ], + "cpu": [ + "x64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.6.tgz", + "integrity": "sha512-5JFf5rGofrm+V29HNF+wLthXphHdQpMbKDUYJ5tML6/Z5DLlLOV/9Ak4kDPtYyZ+Dzf+kAusE0VsFg4+tfP1IA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.6.tgz", + "integrity": "sha512-JlVjxxw0GbGC0djXYWRIqyteO3J1KZ/QG3udlEFaOD5TLOM1FnmXXAPDQBqr+aBVr720ef9K00dirYnJ0LDCtw==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.6.tgz", + "integrity": "sha512-4t8BUi5zZ+L77otFQVnVSlaTyAX4TVk9EqQm4syMrEQp96trFEHEwwNHcNEBGzYv5+K7mxay50TthYkz47OWzQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "linux" + ], + "cpu": [ + "riscv64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.6.tgz", + "integrity": "sha512-trtPwcNLW37irwQCJLtCxLw757jjJZk3TSnY/MU9bhtWtA3K9b/eLW0e4RGhUXDoFRds9opNWWaUDuFLa8dm0w==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.6.tgz", + "integrity": "sha512-WfnzIvOCCWQiN0MmltCEo6cLceUDbYe+I7xyFZjaps5A+2Op/M2CY7Rey+C4ucQhrvmpoHmTSFgY9ODWk7snoA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.6.tgz", + "integrity": "sha512-+8+1aHYsBPUjmW3otmWlg+Hijt0iJvoBBs5e0mxFeUd4gDaKMB8Bn6x7c6KVtscg7E5j5NFXnwQqNSIAO4p8zQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "win32" + ], + "cpu": [ + "arm64" + ], + "optional": true + }, + "node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.6.tgz", + "integrity": "sha512-S4xfPmERC8ZkiLHe3vekZCjdDwNEETCuvCgQK2kP6/TnvmUkq1y2Pk+DjM4t8uh9KMX9bH4zs5ePcKa8GTXmfg==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "optional": true + }, + "node_modules/@mistralai/mistralai": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", + "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", + "license": "Apache-2.0", + "dependencies": { + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + } + }, + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ] + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause" + }, + "node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "license": "Apache-2.0" + }, + "node_modules/@smithy/core": { + "version": "3.24.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.3.tgz", + "integrity": "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.3.tgz", + "integrity": "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.3.tgz", + "integrity": "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.3.tgz", + "integrity": "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", + "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, + "node_modules/fast-xml-parser": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ] + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/koffi": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.2.tgz", + "integrity": "sha512-owU0MRwv6xkrVqCd+33uw6BaYppkTRXbO/rVdJNI2dvZG0gzyRhYwW25eWtc5pauwK8TGh3AbkFONSezdykfSA==", + "license": "MIT", + "optional": true, + "hasInstallScript": true, + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz", + "integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "license": "MIT", + "engines": { + "node": ">=10.5.0" + }, + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ] + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "license": "Apache-2.0", + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + }, + "bin": { + "openai": "bin/cli" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/protobufjs": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.9.tgz", + "integrity": "sha512-Od4muIm3HW1AouyHF5lONOf1FWo3hY1NbFDoy191X9GzhpgW1clCoaFjfVs2rKJNFYpTNJbje4cbAIDBZJ63ZA==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "hasInstallScript": true + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typebox": { + "version": "1.1.38", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz", + "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.3.0.tgz", + "integrity": "sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index cd83c3807..23a824223 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -25,7 +25,8 @@ "dist", "docs", "examples", - "CHANGELOG.md" + "CHANGELOG.md", + "npm-shrinkwrap.json" ], "scripts": { "clean": "shx rm -rf dist", @@ -34,7 +35,8 @@ "copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/", "copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/", "test": "vitest --run", - "prepublishOnly": "npm run clean && npm run build" + "shrinkwrap": "node ../../scripts/generate-coding-agent-shrinkwrap.mjs", + "prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap" }, "dependencies": { "@earendil-works/pi-agent-core": "^0.75.3", diff --git a/scripts/build-binaries.sh b/scripts/build-binaries.sh index e66e43904..1c1bf0761 100755 --- a/scripts/build-binaries.sh +++ b/scripts/build-binaries.sh @@ -65,7 +65,7 @@ if [[ "$SKIP_DEPS" == "false" ]]; then # We need all platform bindings for bun cross-compilation # Use --force to bypass platform checks (os/cpu restrictions in package.json) # Install all in one command to avoid npm removing packages from previous installs - npm install --no-save --force --ignore-scripts \ + npm install --no-save --package-lock=false --force --ignore-scripts \ @mariozechner/clipboard-darwin-arm64@0.3.2 \ @mariozechner/clipboard-darwin-x64@0.3.2 \ @mariozechner/clipboard-linux-x64-gnu@0.3.2 \ diff --git a/scripts/generate-coding-agent-shrinkwrap.mjs b/scripts/generate-coding-agent-shrinkwrap.mjs new file mode 100644 index 000000000..563b05288 --- /dev/null +++ b/scripts/generate-coding-agent-shrinkwrap.mjs @@ -0,0 +1,340 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, posix, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(scriptDir, ".."); +const codingAgentDir = join(repoRoot, "packages/coding-agent"); +const rootLockfilePath = join(repoRoot, "package-lock.json"); +const shrinkwrapPath = join(codingAgentDir, "npm-shrinkwrap.json"); +const internalPackagePrefix = "@earendil-works/pi-"; + +const args = new Set(process.argv.slice(2)); +const checkOnly = args.has("--check"); + +for (const arg of args) { + if (arg !== "--check") { + console.error(`Unknown argument: ${arg}`); + process.exit(1); + } +} + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function packageDependencies(entry) { + return { + ...(entry.dependencies ?? {}), + ...(entry.optionalDependencies ?? {}), + }; +} + +function sortedObject(object) { + return Object.fromEntries(Object.entries(object).sort(([a], [b]) => a.localeCompare(b))); +} + +function sortedPackageEntry(entry) { + const fieldOrder = [ + "name", + "version", + "resolved", + "integrity", + "license", + "dependencies", + "optionalDependencies", + "peerDependencies", + "peerDependenciesMeta", + "bin", + "engines", + "os", + "cpu", + "libc", + "optional", + "hasInstallScript", + "deprecated", + "funding", + ]; + const sorted = {}; + + for (const field of fieldOrder) { + if (entry[field] !== undefined) { + sorted[field] = entry[field]; + } + } + for (const [field, value] of Object.entries(entry).sort(([a], [b]) => a.localeCompare(b))) { + if (sorted[field] === undefined) { + sorted[field] = value; + } + } + return sorted; +} + +function copyLockEntry(entry) { + const copied = { ...entry }; + delete copied.dev; + delete copied.devOptional; + delete copied.extraneous; + delete copied.link; + return sortedPackageEntry(copied); +} + +function copyPackageJsonEntry(packageJson, options) { + const entry = options.includeName + ? { name: packageJson.name, version: packageJson.version } + : { version: packageJson.version }; + + for (const field of [ + "license", + "dependencies", + "optionalDependencies", + "peerDependencies", + "peerDependenciesMeta", + "bin", + "engines", + "os", + "cpu", + "libc", + ]) { + if (packageJson[field] !== undefined) { + entry[field] = packageJson[field]; + } + } + + return sortedPackageEntry(entry); +} + +function packageNameFromLockPath(lockPath) { + const marker = "node_modules/"; + const index = lockPath.lastIndexOf(marker); + if (index === -1) { + return undefined; + } + + const parts = lockPath.slice(index + marker.length).split("/"); + if (parts[0]?.startsWith("@")) { + return `${parts[0]}/${parts[1]}`; + } + return parts[0]; +} + +function registryTarballUrl(packageName, version) { + const tarballName = packageName.startsWith("@") ? packageName.split("/")[1] : packageName; + return `https://registry.npmjs.org/${packageName}/-/${tarballName}-${version}.tgz`; +} + +function getInternalWorkspaces(lockPackages) { + const workspaces = new Map(); + + for (const [lockPath, entry] of Object.entries(lockPackages)) { + if (!lockPath.startsWith("packages/") || lockPath.includes("/node_modules/") || !entry.name || !entry.version) { + continue; + } + if (!entry.name.startsWith(internalPackagePrefix)) { + continue; + } + + workspaces.set(entry.name, { + lockPath, + packageJson: readJson(join(repoRoot, lockPath, "package.json")), + }); + } + + return workspaces; +} + +function resolveExternalDependency(lockPackages, packageName, fromLockPath) { + const candidateDirs = []; + let current = fromLockPath; + + while (current) { + candidateDirs.push(current); + const parent = posix.dirname(current); + if (parent === "." || parent === current) { + break; + } + current = parent; + } + candidateDirs.push(""); + + const tried = new Set(); + for (const directory of candidateDirs) { + const candidate = directory ? `${directory}/node_modules/${packageName}` : `node_modules/${packageName}`; + if (tried.has(candidate)) { + continue; + } + tried.add(candidate); + + const entry = lockPackages[candidate]; + if (entry && !entry.link) { + return candidate; + } + } + + const suffix = `node_modules/${packageName}`; + const matches = Object.entries(lockPackages) + .filter(([lockPath, entry]) => !entry.link && (lockPath === suffix || lockPath.endsWith(`/${suffix}`))) + .map(([lockPath]) => lockPath); + + if (matches.length === 1) { + return matches[0]; + } + + throw new Error( + `Cannot resolve ${packageName} from ${fromLockPath || "root"}. ` + + (matches.length > 1 ? `Matches: ${matches.join(", ")}` : "No matching lockfile entry found."), + ); +} + +function addInternalWorkspace(shrinkwrapPackages, addedPaths, queue, name, workspace) { + const packageJson = workspace.packageJson; + const outputPath = `node_modules/${name}`; + const entry = copyPackageJsonEntry(packageJson, { includeName: false }); + entry.resolved = registryTarballUrl(name, packageJson.version); + + shrinkwrapPackages[outputPath] = sortedPackageEntry(entry); + addedPaths.add(outputPath); + + for (const dependencyName of Object.keys(packageDependencies(packageJson))) { + queue.push({ name: dependencyName, from: outputPath }); + } +} + +function addExternalPackage(lockPackages, shrinkwrapPackages, addedPaths, queue, name, from) { + const lockPath = resolveExternalDependency(lockPackages, name, from); + if (addedPaths.has(lockPath)) { + return; + } + + const entry = lockPackages[lockPath]; + shrinkwrapPackages[lockPath] = copyLockEntry(entry); + addedPaths.add(lockPath); + + for (const dependencyName of Object.keys(packageDependencies(entry))) { + queue.push({ name: dependencyName, from: lockPath }); + } +} + +function validateShrinkwrap(shrinkwrap, internalNames) { + const errors = []; + const includedPaths = new Set(Object.keys(shrinkwrap.packages)); + const includedPackageNames = new Set(); + + for (const [lockPath, entry] of Object.entries(shrinkwrap.packages)) { + const packageName = packageNameFromLockPath(lockPath); + if (packageName) { + includedPackageNames.add(packageName); + } + if (entry.link) { + errors.push(`${lockPath} is a link entry`); + } + if (typeof entry.resolved === "string" && /^(file:|link:|workspace:|\.\.?\/|\/)/.test(entry.resolved)) { + errors.push(`${lockPath} has a local resolved value: ${entry.resolved}`); + } + } + + for (const name of internalNames) { + if (!includedPackageNames.has(name)) { + errors.push(`internal dependency ${name} is missing`); + } + } + + for (const [lockPath, entry] of Object.entries(shrinkwrap.packages)) { + for (const dependencyName of Object.keys(packageDependencies(entry))) { + const dependencyIncluded = [...includedPaths].some( + (candidate) => candidate === `node_modules/${dependencyName}` || candidate.endsWith(`/node_modules/${dependencyName}`), + ); + if (!dependencyIncluded) { + errors.push(`${lockPath || "root"} dependency ${dependencyName} is missing`); + } + } + } + + const platformPackageCount = Object.values(shrinkwrap.packages).filter((entry) => entry.os || entry.cpu || entry.libc).length; + if (platformPackageCount === 0) { + errors.push("no platform-specific optional dependency entries found"); + } + + if (errors.length > 0) { + throw new Error(`Generated shrinkwrap failed validation:\n${errors.map((error) => ` - ${error}`).join("\n")}`); + } +} + +function generateShrinkwrap() { + const rootLock = readJson(rootLockfilePath); + if (rootLock.lockfileVersion !== 3 || !rootLock.packages) { + throw new Error("package-lock.json must be lockfileVersion 3 and contain a packages map"); + } + + const lockPackages = rootLock.packages; + const codingAgentPackage = readJson(join(codingAgentDir, "package.json")); + const internalWorkspaces = getInternalWorkspaces(lockPackages); + const shrinkwrapPackages = { + "": copyPackageJsonEntry(codingAgentPackage, { includeName: true }), + }; + const addedPaths = new Set([""]); + const internalNames = new Set(); + const queue = Object.keys(packageDependencies(codingAgentPackage)).map((name) => ({ name, from: "" })); + + while (queue.length > 0) { + const item = queue.shift(); + if (!item) { + break; + } + + const workspace = internalWorkspaces.get(item.name); + if (workspace) { + const outputPath = `node_modules/${item.name}`; + internalNames.add(item.name); + if (!addedPaths.has(outputPath)) { + addInternalWorkspace(shrinkwrapPackages, addedPaths, queue, item.name, workspace); + } + continue; + } + + addExternalPackage(lockPackages, shrinkwrapPackages, addedPaths, queue, item.name, item.from); + } + + const shrinkwrap = { + name: codingAgentPackage.name, + version: codingAgentPackage.version, + lockfileVersion: 3, + requires: true, + packages: sortedObject(shrinkwrapPackages), + }; + + validateShrinkwrap(shrinkwrap, internalNames); + return shrinkwrap; +} + +try { + const shrinkwrap = generateShrinkwrap(); + const content = `${JSON.stringify(shrinkwrap, null, "\t")}\n`; + + if (checkOnly) { + if (!existsSync(shrinkwrapPath)) { + console.error("packages/coding-agent/npm-shrinkwrap.json is missing."); + console.error("Run: npm run shrinkwrap:coding-agent"); + process.exit(1); + } + const current = readFileSync(shrinkwrapPath, "utf8"); + if (current !== content) { + console.error("packages/coding-agent/npm-shrinkwrap.json is out of date."); + console.error("Run: npm run shrinkwrap:coding-agent"); + process.exit(1); + } + console.log("packages/coding-agent/npm-shrinkwrap.json is up to date."); + } else { + writeFileSync(shrinkwrapPath, content); + const packageCount = Object.keys(shrinkwrap.packages).length - 1; + const platformPackageCount = Object.values(shrinkwrap.packages).filter((entry) => entry.os || entry.cpu || entry.libc).length; + console.log( + `Wrote packages/coding-agent/npm-shrinkwrap.json (${packageCount} packages, ${platformPackageCount} platform-specific).`, + ); + } +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +} diff --git a/scripts/release.mjs b/scripts/release.mjs index 73ae06f9d..59b515095 100755 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -10,10 +10,11 @@ * 1. Check for uncommitted changes * 2. Bump version via npm run version:xxx or set an explicit version * 3. Update CHANGELOG.md files: [Unreleased] -> [version] - date - * 4. Commit and tag - * 5. Publish to npm - * 6. Add new [Unreleased] section to changelogs - * 7. Commit + * 4. Generate the coding-agent npm-shrinkwrap.json + * 5. Commit and tag + * 6. Publish to npm + * 7. Add new [Unreleased] section to changelogs + * 8. Commit */ import { execSync } from "child_process"; @@ -90,9 +91,7 @@ function bumpOrSetVersion(target) { } console.log(`Setting explicit version (${target})...`); - run( - `npm version ${target} -ws --no-git-tag-version && node scripts/sync-versions.js && npx shx rm -rf node_modules packages/*/node_modules package-lock.json && npm install`, - ); + run(`npm version ${target} -ws --no-git-tag-version && node scripts/sync-versions.js && npm install --package-lock-only`); return getVersion(); } @@ -164,30 +163,35 @@ console.log("Updating CHANGELOG.md files..."); updateChangelogsForRelease(version); console.log(); -// 4. Commit and tag +// 4. Generate publish shrinkwrap +console.log("Generating coding-agent shrinkwrap..."); +run("npm run shrinkwrap:coding-agent"); +console.log(); + +// 5. Commit and tag console.log("Committing and tagging..."); stageChangedFiles(); run(`git commit -m "Release v${version}"`); run(`git tag v${version}`); console.log(); -// 5. Publish +// 6. Publish console.log("Publishing to npm..."); run("npm run publish"); console.log(); -// 6. Add new [Unreleased] sections +// 7. Add new [Unreleased] sections console.log("Adding [Unreleased] sections for next cycle..."); addUnreleasedSection(); console.log(); -// 7. Commit +// 8. Commit console.log("Committing changelog updates..."); stageChangedFiles(); run(`git commit -m "Add [Unreleased] section for next cycle"`); console.log(); -// 8. Push +// 9. Push console.log("Pushing to remote..."); run("git push origin main"); run(`git push origin v${version}`); From a3ebcd2322be07187a69a188b6af21051d2a359a Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 14:42:45 +0200 Subject: [PATCH 08/15] fix(coding-agent): disable scripts during self-update --- packages/coding-agent/src/config.ts | 14 +++-- packages/coding-agent/test/config.test.ts | 65 +++++++++++++---------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/packages/coding-agent/src/config.ts b/packages/coding-agent/src/config.ts index 1a94ea02a..e55fa5f3c 100644 --- a/packages/coding-agent/src/config.ts +++ b/packages/coding-agent/src/config.ts @@ -110,21 +110,21 @@ function getSelfUpdateCommandForMethod( return undefined; case "pnpm": return makeSelfUpdateCommand( - makeSelfUpdateCommandStep("pnpm", ["install", "-g", updatePackageName]), + makeSelfUpdateCommandStep("pnpm", ["install", "-g", "--ignore-scripts", updatePackageName]), updatePackageName === installedPackageName ? undefined : makeSelfUpdateCommandStep("pnpm", ["remove", "-g", installedPackageName]), ); case "yarn": return makeSelfUpdateCommand( - makeSelfUpdateCommandStep("yarn", ["global", "add", updatePackageName]), + makeSelfUpdateCommandStep("yarn", ["global", "add", "--ignore-scripts", updatePackageName]), updatePackageName === installedPackageName ? undefined : makeSelfUpdateCommandStep("yarn", ["global", "remove", installedPackageName]), ); case "bun": return makeSelfUpdateCommand( - makeSelfUpdateCommandStep("bun", ["install", "-g", updatePackageName]), + makeSelfUpdateCommandStep("bun", ["install", "-g", "--ignore-scripts", updatePackageName]), updatePackageName === installedPackageName ? undefined : makeSelfUpdateCommandStep("bun", ["uninstall", "-g", installedPackageName]), @@ -133,7 +133,13 @@ function getSelfUpdateCommandForMethod( const [command = "npm", ...npmArgs] = npmCommand ?? []; const inferred = npmCommand?.length ? undefined : getInferredNpmInstall(); const prefixArgs = [...npmArgs, ...(inferred ? ["--prefix", inferred.prefix] : [])]; - const installStep = makeSelfUpdateCommandStep(command, [...prefixArgs, "install", "-g", updatePackageName]); + const installStep = makeSelfUpdateCommandStep(command, [ + ...prefixArgs, + "install", + "-g", + "--ignore-scripts", + updatePackageName, + ]); const uninstallStep = updatePackageName === installedPackageName ? undefined diff --git a/packages/coding-agent/test/config.test.ts b/packages/coding-agent/test/config.test.ts index c22ff12b4..6b90778ac 100644 --- a/packages/coding-agent/test/config.test.ts +++ b/packages/coding-agent/test/config.test.ts @@ -153,7 +153,7 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("pnpm"); expect(getUpdateInstruction("@earendil-works/pi-coding-agent")).toBe( - "Run: pnpm install -g @earendil-works/pi-coding-agent", + "Run: pnpm install -g --ignore-scripts @earendil-works/pi-coding-agent", ); }); @@ -175,8 +175,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("npm"); expect(command).toEqual({ command: "npm", - args: ["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"], - display: `npm --prefix ${prefix} install -g @earendil-works/pi-coding-agent`, + args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"], + display: `npm --prefix ${prefix} install -g --ignore-scripts @earendil-works/pi-coding-agent`, }); }); @@ -187,8 +187,8 @@ describe("detectInstallMethod", () => { expect(command).toEqual({ command: "npm", - args: ["--prefix", prefix, "install", "-g", "@new-scope/pi"], - display: `npm --prefix ${prefix} uninstall -g @mariozechner/pi-coding-agent && npm --prefix ${prefix} install -g @new-scope/pi`, + args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: `npm --prefix ${prefix} uninstall -g @mariozechner/pi-coding-agent && npm --prefix ${prefix} install -g --ignore-scripts @new-scope/pi`, steps: [ { command: "npm", @@ -197,8 +197,8 @@ describe("detectInstallMethod", () => { }, { command: "npm", - args: ["--prefix", prefix, "install", "-g", "@new-scope/pi"], - display: `npm --prefix ${prefix} install -g @new-scope/pi`, + args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: `npm --prefix ${prefix} install -g --ignore-scripts @new-scope/pi`, }, ], }); @@ -211,8 +211,8 @@ describe("detectInstallMethod", () => { expect(command).toEqual({ command: "npm", - args: ["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"], - display: `npm --prefix ${prefix} install -g @earendil-works/pi-coding-agent`, + args: ["--prefix", prefix, "install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"], + display: `npm --prefix ${prefix} install -g --ignore-scripts @earendil-works/pi-coding-agent`, }); }); @@ -221,7 +221,14 @@ describe("detectInstallMethod", () => { const command = getSelfUpdateCommand("@earendil-works/pi-coding-agent", []); - expect(command?.args).toEqual(["--prefix", prefix, "install", "-g", "@earendil-works/pi-coding-agent"]); + expect(command?.args).toEqual([ + "--prefix", + prefix, + "install", + "-g", + "--ignore-scripts", + "@earendil-works/pi-coding-agent", + ]); }); test("quotes npm self-update display paths", () => { @@ -229,7 +236,9 @@ describe("detectInstallMethod", () => { const command = getSelfUpdateCommand("@earendil-works/pi-coding-agent"); - expect(command?.display).toBe(`npm --prefix "${prefix}" install -g @earendil-works/pi-coding-agent`); + expect(command?.display).toBe( + `npm --prefix "${prefix}" install -g --ignore-scripts @earendil-works/pi-coding-agent`, + ); }); test("does not infer Windows npm custom prefixes from package paths", () => { @@ -239,7 +248,7 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("npm"); expect(getUpdateInstruction("@earendil-works/pi-coding-agent")).toBe( - "Run: npm install -g @earendil-works/pi-coding-agent", + "Run: npm install -g --ignore-scripts @earendil-works/pi-coding-agent", ); }); @@ -251,8 +260,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("bun"); expect(command).toEqual({ command: "bun", - args: ["install", "-g", "@earendil-works/pi-coding-agent"], - display: "bun install -g @earendil-works/pi-coding-agent", + args: ["install", "-g", "--ignore-scripts", "@earendil-works/pi-coding-agent"], + display: "bun install -g --ignore-scripts @earendil-works/pi-coding-agent", }); }); @@ -264,8 +273,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("pnpm"); expect(command).toEqual({ command: "pnpm", - args: ["install", "-g", "@new-scope/pi"], - display: "pnpm remove -g @mariozechner/pi-coding-agent && pnpm install -g @new-scope/pi", + args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: "pnpm remove -g @mariozechner/pi-coding-agent && pnpm install -g --ignore-scripts @new-scope/pi", steps: [ { command: "pnpm", @@ -274,8 +283,8 @@ describe("detectInstallMethod", () => { }, { command: "pnpm", - args: ["install", "-g", "@new-scope/pi"], - display: "pnpm install -g @new-scope/pi", + args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: "pnpm install -g --ignore-scripts @new-scope/pi", }, ], }); @@ -319,8 +328,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("pnpm"); expect(command).toEqual({ command: "pnpm", - args: ["install", "-g", packageName], - display: `pnpm install -g ${packageName}`, + args: ["install", "-g", "--ignore-scripts", packageName], + display: `pnpm install -g --ignore-scripts ${packageName}`, }); }); @@ -332,8 +341,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("yarn"); expect(command).toEqual({ command: "yarn", - args: ["global", "add", "@new-scope/pi"], - display: "yarn global remove @mariozechner/pi-coding-agent && yarn global add @new-scope/pi", + args: ["global", "add", "--ignore-scripts", "@new-scope/pi"], + display: "yarn global remove @mariozechner/pi-coding-agent && yarn global add --ignore-scripts @new-scope/pi", steps: [ { command: "yarn", @@ -342,8 +351,8 @@ describe("detectInstallMethod", () => { }, { command: "yarn", - args: ["global", "add", "@new-scope/pi"], - display: "yarn global add @new-scope/pi", + args: ["global", "add", "--ignore-scripts", "@new-scope/pi"], + display: "yarn global add --ignore-scripts @new-scope/pi", }, ], }); @@ -357,8 +366,8 @@ describe("detectInstallMethod", () => { expect(detectInstallMethod()).toBe("bun"); expect(command).toEqual({ command: "bun", - args: ["install", "-g", "@new-scope/pi"], - display: "bun uninstall -g @mariozechner/pi-coding-agent && bun install -g @new-scope/pi", + args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: "bun uninstall -g @mariozechner/pi-coding-agent && bun install -g --ignore-scripts @new-scope/pi", steps: [ { command: "bun", @@ -367,8 +376,8 @@ describe("detectInstallMethod", () => { }, { command: "bun", - args: ["install", "-g", "@new-scope/pi"], - display: "bun install -g @new-scope/pi", + args: ["install", "-g", "--ignore-scripts", "@new-scope/pi"], + display: "bun install -g --ignore-scripts @new-scope/pi", }, ], }); From 5b7c5d21572e63aed4626b167e5ea9a2c736bb2d Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 14:47:18 +0200 Subject: [PATCH 09/15] docs: recommend scriptless npm installs --- packages/coding-agent/README.md | 8 +++++--- packages/coding-agent/docs/index.md | 16 +++++++++------- packages/coding-agent/docs/quickstart.md | 4 +++- packages/coding-agent/docs/termux.md | 2 +- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index fedc53d26..79f284a07 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -68,13 +68,15 @@ I regularly publish my own `pi-mono` work sessions here: ## Quick Start ```bash -curl -fsSL https://pi.dev/install.sh | sh +npm install -g --ignore-scripts @earendil-works/pi-coding-agent ``` -Or with npm: +`--ignore-scripts` disables dependency lifecycle scripts during install. Pi does not require install scripts for normal npm installs. + +Installer alternative: ```bash -npm install -g @earendil-works/pi-coding-agent +curl -fsSL https://pi.dev/install.sh | sh ``` Authenticate with an API key: diff --git a/packages/coding-agent/docs/index.md b/packages/coding-agent/docs/index.md index ffe978659..75a527d65 100644 --- a/packages/coding-agent/docs/index.md +++ b/packages/coding-agent/docs/index.md @@ -4,18 +4,20 @@ Pi is a minimal terminal coding harness. It is designed to stay small at the cor ## Quick start -On linux or mac you can install Pi with curl: +Install Pi with npm: + +```bash +npm install -g --ignore-scripts @earendil-works/pi-coding-agent +``` + +`--ignore-scripts` disables dependency lifecycle scripts during install. Pi does not require install scripts for normal npm installs. + +On Linux or macOS, you can also use the installer: ```bash curl -fsSL https://pi.dev/install.sh | sh ``` -Or alternatively with npm: - -```bash -npm install -g @earendil-works/pi-coding-agent -``` - To uninstall pi itself, use npm for curl and npm installs: ```bash diff --git a/packages/coding-agent/docs/quickstart.md b/packages/coding-agent/docs/quickstart.md index 29f9896a8..c7266346a 100644 --- a/packages/coding-agent/docs/quickstart.md +++ b/packages/coding-agent/docs/quickstart.md @@ -7,9 +7,11 @@ This page gets you from install to a useful first pi session. Pi is distributed as an npm package: ```bash -npm install -g @earendil-works/pi-coding-agent +npm install -g --ignore-scripts @earendil-works/pi-coding-agent ``` +`--ignore-scripts` disables dependency lifecycle scripts during install. Pi does not require install scripts for normal npm installs. + ### Uninstall Use the package manager that installed pi. The curl installer uses npm globally, so curl and npm installs are removed with npm: diff --git a/packages/coding-agent/docs/termux.md b/packages/coding-agent/docs/termux.md index c9b9973c5..aba6e292d 100644 --- a/packages/coding-agent/docs/termux.md +++ b/packages/coding-agent/docs/termux.md @@ -17,7 +17,7 @@ pkg update && pkg upgrade pkg install nodejs termux-api git # Install pi -npm install -g @earendil-works/pi-coding-agent +npm install -g --ignore-scripts @earendil-works/pi-coding-agent # Create config directory mkdir -p ~/.pi/agent From 29851d01e42a14fa35714e3ccfff2dcd1f63f252 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 14:55:38 +0200 Subject: [PATCH 10/15] chore: enforce npm dependency age gate --- .npmrc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..d9b69800f --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +save-exact=true +min-release-age=14 From aa4adac766d44c94a47a9552c400906cc9d42aae Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 15:51:38 +0200 Subject: [PATCH 11/15] chore: run pi-test through tsx --- package-lock.json | 20 ++++++++++++++++++++ package.json | 1 + pi-test.sh | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 9af10d5bb..4bb2dfe86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "husky": "9.1.7", "jiti": "2.7.0", "shx": "0.4.0", + "tsx": "4.22.1", "typescript": "5.9.3" }, "engines": { @@ -5086,6 +5087,25 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz", + "integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index daa4b4e51..7a62003d7 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "husky": "9.1.7", "jiti": "2.7.0", "shx": "0.4.0", + "tsx": "4.22.1", "typescript": "5.9.3" }, "engines": { diff --git a/pi-test.sh b/pi-test.sh index 37ff01149..b726dd412 100755 --- a/pi-test.sh +++ b/pi-test.sh @@ -54,4 +54,4 @@ if [[ "$NO_ENV" == "true" ]]; then echo "Running without API keys..." fi -node "$SCRIPT_DIR/packages/coding-agent/src/cli.ts" ${ARGS[@]+"${ARGS[@]}"} +"$SCRIPT_DIR/node_modules/.bin/tsx" --tsconfig "$SCRIPT_DIR/tsconfig.json" "$SCRIPT_DIR/packages/coding-agent/src/cli.ts" ${ARGS[@]+"${ARGS[@]}"} From 17cc86a4793bedd13ba17ebec556a0a366816b6d Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 15:53:18 +0200 Subject: [PATCH 12/15] chore: harden dependency workflows --- .github/workflows/ci.yml | 2 +- .github/workflows/npm-audit.yml | 31 +++++++ .husky/pre-commit | 5 ++ .npmrc | 2 +- README.md | 14 +++ scripts/build-binaries.sh | 2 +- scripts/check-lockfile-commit.mjs | 94 ++++++++++++++++++++ scripts/generate-coding-agent-shrinkwrap.mjs | 26 ++++++ scripts/local-release.mjs | 2 +- 9 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/npm-audit.yml create mode 100644 scripts/check-lockfile-commit.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef5b18dac..a40a894cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: sudo ln -s $(which fdfind) /usr/local/bin/fd - name: Install dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Build run: npm run build diff --git a/.github/workflows/npm-audit.yml b/.github/workflows/npm-audit.yml new file mode 100644 index 000000000..021b81ca9 --- /dev/null +++ b/.github/workflows/npm-audit.yml @@ -0,0 +1,31 @@ +name: npm audit + +on: + schedule: + - cron: '37 7 * * *' + workflow_dispatch: + +permissions: + contents: read + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Install dependencies without lifecycle scripts + run: npm ci --ignore-scripts --no-audit --no-fund + + - name: Audit production vulnerabilities + run: npm audit --omit=dev --audit-level=moderate + + - name: Verify registry signatures + run: npm audit signatures --omit=dev diff --git a/.husky/pre-commit b/.husky/pre-commit index 27d18fbc8..2b21ec961 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,6 +3,11 @@ # Get list of staged files before running check STAGED_FILES=$(git diff --cached --name-only) +node scripts/check-lockfile-commit.mjs +if [ $? -ne 0 ]; then + exit 1 +fi + # Run the check script (formatting, linting, and type checking) echo "Running formatting, linting, and type checking..." npm run check diff --git a/.npmrc b/.npmrc index d9b69800f..72acb9ade 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1,2 @@ save-exact=true -min-release-age=14 +min-release-age=2 diff --git a/README.md b/README.md index 6bdda5475..d7e73cf08 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,20 @@ npm run check # Lint, format, and type check ./pi-test.sh # Run pi from sources (can be run from any directory) ``` +## Supply-chain hardening + +We treat npm dependency changes as reviewed code changes. + +- Direct external dependencies are pinned to exact versions. Internal workspace packages remain version-ranged. +- `.npmrc` sets `save-exact=true` and `min-release-age=2` to avoid same-day dependency releases during npm resolution. +- `package-lock.json` is the dependency ground truth. Pre-commit blocks accidental lockfile commits unless `PI_ALLOW_LOCKFILE_CHANGE=1` is set. +- `npm run check` verifies pinned direct deps, native TypeScript import compatibility, and the generated coding-agent shrinkwrap. +- The published CLI package includes `packages/coding-agent/npm-shrinkwrap.json`, generated from the root lockfile, to pin transitive deps for npm users. +- Release smoke tests use `npm run release:local` to build, pack, and install outside the repo before publishing. +- Local release installs, documented npm installs, and `pi update --self` use `--ignore-scripts` where supported. +- CI installs with `npm ci --ignore-scripts`, and a scheduled GitHub workflow runs `npm audit --omit=dev` plus `npm audit signatures --omit=dev`. +- Shrinkwrap generation has an explicit allowlist for dependency lifecycle scripts; new lifecycle-script deps fail checks until reviewed. + ## License MIT diff --git a/scripts/build-binaries.sh b/scripts/build-binaries.sh index 1c1bf0761..4b94de970 100755 --- a/scripts/build-binaries.sh +++ b/scripts/build-binaries.sh @@ -57,7 +57,7 @@ if [[ -n "$PLATFORM" ]]; then fi echo "==> Installing dependencies..." -npm ci +npm ci --ignore-scripts if [[ "$SKIP_DEPS" == "false" ]]; then echo "==> Installing cross-platform native bindings..." diff --git a/scripts/check-lockfile-commit.mjs b/scripts/check-lockfile-commit.mjs new file mode 100644 index 000000000..abf789470 --- /dev/null +++ b/scripts/check-lockfile-commit.mjs @@ -0,0 +1,94 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; + +const allowValue = process.env.PI_ALLOW_LOCKFILE_CHANGE; +const allowed = allowValue === "1" || allowValue === "true" || allowValue === "yes"; + +function git(args) { + return execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); +} + +function readJsonFromGit(ref) { + try { + return JSON.parse(git(["show", ref])); + } catch { + return undefined; + } +} + +function packageNameFromLockPath(lockPath) { + const marker = "node_modules/"; + const index = lockPath.lastIndexOf(marker); + if (index === -1) return lockPath || ""; + const parts = lockPath.slice(index + marker.length).split("/"); + return parts[0]?.startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0]; +} + +function packageLabel(lockPath, entry) { + const name = entry?.name ?? packageNameFromLockPath(lockPath); + return entry?.version ? `${name}@${entry.version}` : name; +} + +function summarizeLockfileChange() { + const before = readJsonFromGit("HEAD:package-lock.json"); + const after = readJsonFromGit(":package-lock.json"); + if (!before?.packages || !after?.packages) return []; + + const changes = []; + const paths = new Set([...Object.keys(before.packages), ...Object.keys(after.packages)]); + for (const lockPath of [...paths].sort()) { + if (!lockPath.includes("node_modules/")) continue; + const oldEntry = before.packages[lockPath]; + const newEntry = after.packages[lockPath]; + if (!oldEntry && newEntry) { + changes.push(`added ${packageLabel(lockPath, newEntry)}`); + } else if (oldEntry && !newEntry) { + changes.push(`removed ${packageLabel(lockPath, oldEntry)}`); + } else if (oldEntry?.version !== newEntry?.version) { + changes.push( + `changed ${packageNameFromLockPath(lockPath)} ${oldEntry?.version ?? ""} -> ${newEntry?.version ?? ""}`, + ); + } + } + return changes; +} + +const stagedFiles = git(["diff", "--cached", "--name-only"]) + .split("\n") + .map((line) => line.trim()) + .filter(Boolean); + +if (!stagedFiles.includes("package-lock.json")) { + process.exit(0); +} + +if (allowed) { + console.error("package-lock.json is staged; PI_ALLOW_LOCKFILE_CHANGE is set, allowing commit."); + process.exit(0); +} + +console.error("package-lock.json is staged."); +console.error(""); +console.error("Review lockfile changes before committing:"); +console.error(" - confirm every new/updated package is intentional"); +console.error(" - confirm npm age gates were active for resolution"); +console.error(" - review any new lifecycle scripts in the dependency tree"); +console.error(" - regenerate/check coding-agent shrinkwrap if release deps changed"); + +const changes = summarizeLockfileChange(); +if (changes.length > 0) { + console.error(""); + console.error("Detected package version changes:"); + for (const change of changes.slice(0, 40)) { + console.error(` - ${change}`); + } + if (changes.length > 40) { + console.error(` ... ${changes.length - 40} more`); + } +} + +console.error(""); +console.error("If this lockfile change is intentional, commit with:"); +console.error(" PI_ALLOW_LOCKFILE_CHANGE=1 git commit ..."); +process.exit(1); diff --git a/scripts/generate-coding-agent-shrinkwrap.mjs b/scripts/generate-coding-agent-shrinkwrap.mjs index 563b05288..a122f1835 100644 --- a/scripts/generate-coding-agent-shrinkwrap.mjs +++ b/scripts/generate-coding-agent-shrinkwrap.mjs @@ -10,6 +10,11 @@ const codingAgentDir = join(repoRoot, "packages/coding-agent"); const rootLockfilePath = join(repoRoot, "package-lock.json"); const shrinkwrapPath = join(codingAgentDir, "npm-shrinkwrap.json"); const internalPackagePrefix = "@earendil-works/pi-"; +const allowedInstallScriptPackages = new Map([ + ["@google/genai@1.52.0", "preinstall is a no-op in the published package"], + ["koffi@2.16.2", "optional native package ships prebuilt modules used without install scripts"], + ["protobufjs@7.5.9", "postinstall only warns about protobufjs version scheme mismatches"], +]); const args = new Set(process.argv.slice(2)); const checkOnly = args.has("--check"); @@ -221,6 +226,7 @@ function validateShrinkwrap(shrinkwrap, internalNames) { const errors = []; const includedPaths = new Set(Object.keys(shrinkwrap.packages)); const includedPackageNames = new Set(); + const seenAllowedInstallScriptPackages = new Set(); for (const [lockPath, entry] of Object.entries(shrinkwrap.packages)) { const packageName = packageNameFromLockPath(lockPath); @@ -233,6 +239,26 @@ function validateShrinkwrap(shrinkwrap, internalNames) { if (typeof entry.resolved === "string" && /^(file:|link:|workspace:|\.\.?\/|\/)/.test(entry.resolved)) { errors.push(`${lockPath} has a local resolved value: ${entry.resolved}`); } + if (entry.hasInstallScript) { + if (!packageName || !entry.version) { + errors.push(`${lockPath || "root"} has install scripts but no package name/version`); + } else { + const packageId = `${packageName}@${entry.version}`; + if (allowedInstallScriptPackages.has(packageId)) { + seenAllowedInstallScriptPackages.add(packageId); + } else { + errors.push( + `${lockPath} has install scripts (${packageId}). Review it and add it to allowedInstallScriptPackages if intentional.`, + ); + } + } + } + } + + for (const packageId of allowedInstallScriptPackages.keys()) { + if (!seenAllowedInstallScriptPackages.has(packageId)) { + errors.push(`allowed install-script package ${packageId} is no longer present; remove it from the allowlist`); + } } for (const name of internalNames) { diff --git a/scripts/local-release.mjs b/scripts/local-release.mjs index 31e07901c..d5b4b4165 100644 --- a/scripts/local-release.mjs +++ b/scripts/local-release.mjs @@ -167,7 +167,7 @@ if (!options.skipInstall) { `${JSON.stringify({ private: true, dependencies }, undefined, "\t")}\n`, ); - run("npm", ["install", "--omit=dev"], { cwd: installDirectory }); + run("npm", ["install", "--omit=dev", "--ignore-scripts"], { cwd: installDirectory }); mkdirSync(binDirectory, { recursive: true }); symlinkSync(join(installDirectory, "node_modules", ".bin", "pi"), join(binDirectory, "pi")); } From beefa6a4fed88422219b125153e82f7404353839 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 16:02:30 +0200 Subject: [PATCH 13/15] chore: add bun local release smoke install --- AGENTS.md | 8 +++-- README.md | 2 +- scripts/local-release.mjs | 68 +++++++++++++++++++++++++++------------ 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a05fab617..4f1d1ccbe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -194,9 +194,11 @@ Create provider file exporting: ```bash npm run release:local -- --out /tmp/pi-local-release --force cd /tmp - /tmp/pi-local-release/bin/pi --help - /tmp/pi-local-release/bin/pi --version - /tmp/pi-local-release/bin/pi + /tmp/pi-local-release/node/pi --help + /tmp/pi-local-release/node/pi --version + /tmp/pi-local-release/node/pi + /tmp/pi-local-release/bun/pi --help + /tmp/pi-local-release/bun/pi --version ``` In the interactive smoke test, verify startup, model/account listing, and at least one real prompt with the intended default provider. Treat failures as release blockers unless the user explicitly accepts the risk. diff --git a/README.md b/README.md index d7e73cf08..750b3a61a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ We treat npm dependency changes as reviewed code changes. - `package-lock.json` is the dependency ground truth. Pre-commit blocks accidental lockfile commits unless `PI_ALLOW_LOCKFILE_CHANGE=1` is set. - `npm run check` verifies pinned direct deps, native TypeScript import compatibility, and the generated coding-agent shrinkwrap. - The published CLI package includes `packages/coding-agent/npm-shrinkwrap.json`, generated from the root lockfile, to pin transitive deps for npm users. -- Release smoke tests use `npm run release:local` to build, pack, and install outside the repo before publishing. +- Release smoke tests use `npm run release:local` to build, pack, and create isolated npm and Bun installs outside the repo before publishing. - Local release installs, documented npm installs, and `pi update --self` use `--ignore-scripts` where supported. - CI installs with `npm ci --ignore-scripts`, and a scheduled GitHub workflow runs `npm audit --omit=dev` plus `npm audit signatures --omit=dev`. - Shrinkwrap generation has an explicit allowlist for dependency lifecycle scripts; new lifecycle-script deps fail checks until reviewed. diff --git a/scripts/local-release.mjs b/scripts/local-release.mjs index d5b4b4165..5cdc67bc1 100644 --- a/scripts/local-release.mjs +++ b/scripts/local-release.mjs @@ -19,16 +19,17 @@ Builds and packs the publishable packages, then installs the tarballs into an isolated directory outside the repository for local release testing. Options: - --out Output directory. Defaults to a new directory under ${tmpdir()} - --force Remove --out first if it already exists - --skip-check Do not run npm run check before building - --skip-install Only create tarballs; do not create the isolated install - --help Show this help + --out Output directory. Defaults to a new directory under ${tmpdir()} + --force Remove --out first if it already exists + --skip-check Do not run npm run check before building + --skip-install Only create tarballs; do not create isolated installs + --skip-bun-install Do not create the isolated Bun install + --help Show this help `); } function parseArgs() { - const options = { force: false, outDir: undefined, skipCheck: false, skipInstall: false }; + const options = { force: false, outDir: undefined, skipBunInstall: false, skipCheck: false, skipInstall: false }; const args = process.argv.slice(2); for (let i = 0; i < args.length; i++) { @@ -49,6 +50,10 @@ function parseArgs() { options.skipInstall = true; continue; } + if (arg === "--skip-bun-install") { + options.skipBunInstall = true; + continue; + } if (arg === "--out") { const value = args[++i]; if (!value) { @@ -82,6 +87,10 @@ function readPackageJson(directory) { return JSON.parse(readFileSync(join(directory, "package.json"), "utf8")); } +function commandExists(command) { + return spawnSync(command, ["--version"], { stdio: "ignore" }).status === 0; +} + function isInsidePath(child, parent) { const relativePath = relative(parent, child); return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath)); @@ -138,8 +147,8 @@ if (rootPackageJson.name !== "pi-monorepo") { const outDir = prepareOutputDirectory(options, repoRoot); const tarballDirectory = join(outDir, "tarballs"); -const installDirectory = join(outDir, "install"); -const binDirectory = join(outDir, "bin"); +const nodeInstallDirectory = join(outDir, "node"); +const bunInstallDirectory = join(outDir, "bun"); mkdirSync(tarballDirectory, { recursive: true }); if (!options.skipCheck) { @@ -158,18 +167,28 @@ for (const pkg of packages) { } if (!options.skipInstall) { - mkdirSync(installDirectory, { recursive: true }); + mkdirSync(nodeInstallDirectory, { recursive: true }); const dependencies = Object.fromEntries( - packages.map((pkg) => [pkg.name, fileSpecifier(installDirectory, tarballs.get(pkg.name))]), - ); - writeFileSync( - join(installDirectory, "package.json"), - `${JSON.stringify({ private: true, dependencies }, undefined, "\t")}\n`, + packages.map((pkg) => [pkg.name, fileSpecifier(nodeInstallDirectory, tarballs.get(pkg.name))]), ); + const installPackageJson = `${JSON.stringify({ private: true, dependencies }, undefined, "\t")}\n`; + writeFileSync(join(nodeInstallDirectory, "package.json"), installPackageJson); - run("npm", ["install", "--omit=dev", "--ignore-scripts"], { cwd: installDirectory }); - mkdirSync(binDirectory, { recursive: true }); - symlinkSync(join(installDirectory, "node_modules", ".bin", "pi"), join(binDirectory, "pi")); + run("npm", ["install", "--omit=dev", "--ignore-scripts"], { cwd: nodeInstallDirectory }); + symlinkSync(join("node_modules", ".bin", "pi"), join(nodeInstallDirectory, "pi")); + + if (!options.skipBunInstall) { + if (!commandExists("bun")) { + throw new Error("Bun is required for the isolated Bun install. Use --skip-bun-install to skip it."); + } + mkdirSync(bunInstallDirectory, { recursive: true }); + const bunDependencies = Object.fromEntries( + packages.map((pkg) => [pkg.name, fileSpecifier(bunInstallDirectory, tarballs.get(pkg.name))]), + ); + writeFileSync(join(bunInstallDirectory, "package.json"), `${JSON.stringify({ private: true, dependencies: bunDependencies }, undefined, "\t")}\n`); + run("bun", ["install", "--production", "--ignore-scripts"], { cwd: bunInstallDirectory }); + symlinkSync(join("node_modules", ".bin", "pi"), join(bunInstallDirectory, "pi")); + } } console.log("\nLocal release artifacts created:"); @@ -180,8 +199,15 @@ for (const tarball of tarballs.values()) { } if (!options.skipInstall) { - console.log("\nIsolated install:"); - console.log(` ${installDirectory}`); - console.log("\nRun the locally packed CLI from outside the repository:"); - console.log(` ${join(binDirectory, "pi")} --help`); + console.log("\nIsolated npm install:"); + console.log(` ${nodeInstallDirectory}`); + console.log("\nRun the locally packed npm CLI from outside the repository:"); + console.log(` ${join(nodeInstallDirectory, "pi")} --help`); + + if (!options.skipBunInstall) { + console.log("\nIsolated Bun install:"); + console.log(` ${bunInstallDirectory}`); + console.log("\nRun the locally packed Bun CLI from outside the repository:"); + console.log(` ${join(bunInstallDirectory, "pi")} --help`); + } } From cd2ae1b5448822b3af2b905316eb53de37715b18 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 16:05:33 +0200 Subject: [PATCH 14/15] docs(coding-agent): document fnm npm shim fix closes #4793 --- packages/coding-agent/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index f902be1eb..9a2fb04ea 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -16,6 +16,7 @@ - Fixed the subagent extension's parallel mode to return useful per-task output and failed-task diagnostics to the parent model instead of 100-character previews ([#4710](https://github.com/earendil-works/pi/issues/4710)). - Fixed Windows local bash execution to hide helper console windows when launched from background SDK processes ([#4699](https://github.com/earendil-works/pi/issues/4699)). - Fixed managed npm extension folders to set cloud-sync ignore metadata where supported ([#4763](https://github.com/earendil-works/pi/issues/4763)). +- Fixed Windows npm-family package commands for fnm-managed Node.js installs that expose both extensionless Unix scripts and `.cmd` shims ([#4793](https://github.com/earendil-works/pi/issues/4793)). ## [0.75.3] - 2026-05-18 From 144b93861f339ce353531f6873d377a1e4b2f5c4 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 20 May 2026 16:10:23 +0200 Subject: [PATCH 15/15] docs: audit unreleased changelog entries --- packages/coding-agent/CHANGELOG.md | 20 ++++++++++++++++++++ packages/tui/CHANGELOG.md | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 9a2fb04ea..5e9053cd4 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,20 +2,40 @@ ## [Unreleased] +### New Features + +- **Hardened npm install and release path** - Pi now ships the CLI with a generated shrinkwrap for transitive dependencies, blocks accidental lockfile changes, verifies dependency pinning and lifecycle-script allowlists in checks, disables lifecycle scripts for self-update and local release installs where supported, and smoke-tests isolated npm and Bun installs before release. See [Supply-chain hardening](../../README.md#supply-chain-hardening). + +### Added + +- Added interactive update notes after `pi update` runs, so users can see the installed version's changelog before continuing ([#4724](https://github.com/earendil-works/pi-mono/pull/4724) by [@mitsuhiko](https://github.com/mitsuhiko)). +- Exported image resize utilities from the package root for SDK consumers ([#4775](https://github.com/earendil-works/pi-mono/pull/4775) by [@xl0](https://github.com/xl0)). + ### Changed - Changed source syntax to avoid TypeScript constructs that require JavaScript emit, keeping core sources compatible with Node.js strip-only TypeScript checks. - Removed web UI workspace references from the CLI package and dropped the package-level development watch script. - Published npm installs now include an `npm-shrinkwrap.json` to lock transitive dependencies for the CLI package. +- Improved terminal theme detection for light/dark and truecolor handling. +- Changed self-update package-manager commands to disable lifecycle scripts during reinstall. ### Fixed - Fixed the system prompt to tell models to resolve pi docs and examples under the absolute package paths before reading topic-specific relative references ([#4752](https://github.com/earendil-works/pi/issues/4752)). - Fixed extension `ctx.abort()` during tool-call preflight to stop later confirmations and restore queued interactive input like Escape ([#4276](https://github.com/earendil-works/pi/issues/4276)). - Fixed AgentSession retry, compaction, and event settlement to use the awaited agent lifecycle instead of a separate event queue, and added `willRetry` to `agent_end` session events. +- Fixed forked session runtime state to keep the active session id aligned with the fork target ([#4799](https://github.com/earendil-works/pi-mono/pull/4799) by [@Perlence](https://github.com/Perlence)). - Fixed the subagent extension's parallel mode to return useful per-task output and failed-task diagnostics to the parent model instead of 100-character previews ([#4710](https://github.com/earendil-works/pi/issues/4710)). - Fixed Windows local bash execution to hide helper console windows when launched from background SDK processes ([#4699](https://github.com/earendil-works/pi/issues/4699)). - Fixed managed npm extension folders to set cloud-sync ignore metadata where supported ([#4763](https://github.com/earendil-works/pi/issues/4763)). +- Fixed HTTP idle timeout configuration so long-running provider streams can avoid premature idle disconnects ([#4759](https://github.com/earendil-works/pi-mono/pull/4759) by [@mitsuhiko](https://github.com/mitsuhiko)). +- Fixed default system prompt boundaries to use explicit XML tags for clearer file separation ([#4709](https://github.com/earendil-works/pi-mono/pull/4709) by [@herrnel](https://github.com/herrnel)). +- Fixed HTML share/export sidebar clicks for shared tool entries to scroll to the rendered tool call ([#4664](https://github.com/earendil-works/pi-mono/pull/4664) by [@yzhg1983](https://github.com/yzhg1983)). +- Fixed theme palettes to set explicit text colors and avoid terminal-default color drift. +- Fixed truecolor detection to align terminal image rendering and interactive theme decisions. +- Fixed loader indicator startup inherited from `@earendil-works/pi-tui` so initialization cannot run before frames are available. +- Fixed OpenAI-compatible default output token requests inherited from `@earendil-works/pi-ai` to avoid reserving impossible context windows on servers such as vLLM ([#4675](https://github.com/earendil-works/pi/issues/4675)). +- Fixed OpenAI prompt cache keys inherited from `@earendil-works/pi-ai` to stay within the 64-character provider limit ([#4720](https://github.com/earendil-works/pi/issues/4720)). - Fixed Windows npm-family package commands for fnm-managed Node.js installs that expose both extensionless Unix scripts and `.cmd` shims ([#4793](https://github.com/earendil-works/pi/issues/4793)). ## [0.75.3] - 2026-05-18 diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 8cae4810e..2a235c747 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -6,6 +6,11 @@ - Removed the package-level development watch script now that the root TypeScript check validates strip-only-compatible sources. +### Fixed + +- Fixed loader initialization so indicator startup cannot run before frames are initialized. +- Fixed truecolor capability detection to align terminal image rendering with the interactive theme detector. + ## [0.75.3] - 2026-05-18 ## [0.75.2] - 2026-05-18