Merge branch 'main' into async-file-tools

This commit is contained in:
Armin Ronacher
2026-05-20 17:14:01 +02:00
295 changed files with 3915 additions and 1034 deletions
@@ -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: {
@@ -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;
@@ -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;
@@ -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<AssistantMessageEvent, AssistantMessage> {
@@ -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;
@@ -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;
@@ -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<AssistantMessageEvent, AssistantMessage> {
constructor() {
@@ -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
@@ -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")!;
@@ -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;
@@ -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)";
+1 -1
View File
@@ -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", () => {
@@ -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";
@@ -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;
@@ -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, `'"'"'`)}'`;
@@ -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 } {
@@ -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 =
@@ -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({
@@ -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();
});
+1 -1
View File
@@ -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 {
@@ -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", () => {
@@ -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;
@@ -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", () => {
@@ -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(),
@@ -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
+38 -29
View File
@@ -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;
@@ -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",
},
],
});
@@ -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[] = [];
@@ -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;
@@ -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", () => {
@@ -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);
@@ -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;
@@ -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;
@@ -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<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
@@ -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;
@@ -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;
@@ -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", () => {
@@ -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)", () => {
@@ -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 {
@@ -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 =
@@ -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==";
@@ -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 {
@@ -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 {
@@ -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 };
@@ -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 () => {
@@ -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";
@@ -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];
@@ -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;
@@ -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[] = [];
@@ -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;
@@ -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">[] = [
@@ -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;
@@ -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;
@@ -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;
@@ -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;");
@@ -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", () => {
+1 -1
View File
@@ -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;
@@ -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", () => {
@@ -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", () => {
@@ -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;
@@ -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
@@ -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;
@@ -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", () => {
@@ -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<unknown>;
+1 -1
View File
@@ -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));
+1 -1
View File
@@ -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", () => {
@@ -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[],
+1 -1
View File
@@ -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));
@@ -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 <n> Number of turns to run. Must be between ${MIN_TURNS} and ${MAX_TURNS}. Default: ${DEFAULT_TURNS}
@@ -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;
@@ -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;
@@ -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;
@@ -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)}`);
@@ -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 = {
@@ -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" };
@@ -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}$/;
@@ -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;
@@ -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", () => {
@@ -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", () => {
@@ -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", () => {
@@ -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", () => {
@@ -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<T> = {
promise: Promise<T>;
@@ -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<void> {
await new Promise<void>((resolve) => {
@@ -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<SessionInfo> & { id: string; modified: Date; allMessagesText: string },
@@ -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.
@@ -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");
+3 -3
View File
@@ -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");
@@ -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,
@@ -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);
@@ -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);
@@ -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<boolean>;
@@ -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[] = [];
@@ -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[] = [];
@@ -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: {
@@ -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[] = [];
@@ -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 {
@@ -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
@@ -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;
+10 -10
View File
@@ -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 };
@@ -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 {
@@ -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[] = [];
@@ -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> = [];
@@ -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;

Some files were not shown because too many files have changed in this diff Show More