import assert from "node:assert/strict"; import { chmodSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent"; import codexFastModeExtension, { FAST_MODE_SERVICE_TIER, FAST_MODE_STATE_ENTRY_TYPE, FAST_MODE_STATUS_KEY, fastModeArgumentCompletions, getFastModeConfigPath, isFastModeEligibleModel, isPlainObject, loadGlobalFastModeState, parseFastModeCommand, reconstructFastModeState, saveGlobalFastModeState, transformFastModeRequest, type FastModeState, } from "../index.ts"; type StatusUpdate = { key: string; value: string | undefined }; type Notification = { message: string; level: string }; type Handler = (event: any, ctx: any) => unknown; function createHarness(options: { entries?: unknown[]; busy?: boolean; pending?: boolean; globalEnabled?: boolean; saveError?: string; } = {}) { const handlers = new Map(); const commands = new Map(); const entries = options.entries ?? []; const statusUpdates: StatusUpdate[] = []; const notifications: Notification[] = []; const appendCalls: Array<{ customType: string; data: unknown }> = []; const loadCalls: string[] = []; const saveCalls: Array<{ path: string; state: FastModeState }> = []; let busy = options.busy ?? false; let pending = options.pending ?? false; let globalEnabled = options.globalEnabled ?? false; const context = { model: { provider: "openai-codex", api: "openai-codex-responses" }, sessionManager: { getBranch: () => entries }, isIdle: () => !busy, hasPendingMessages: () => pending, ui: { setStatus(key: string, value: string | undefined) { statusUpdates.push({ key, value }); }, notify(message: string, level: string) { notifications.push({ message, level }); }, }, } as unknown as ExtensionCommandContext; codexFastModeExtension({ on(event: string, handler: Handler) { handlers.set(event, handler); }, registerCommand(name: string, command: unknown) { commands.set(name, command); }, appendEntry(customType: string, data: unknown) { appendCalls.push({ customType, data }); entries.push({ type: "custom", customType, data }); }, } as unknown as ExtensionAPI, { configPath: "/test-agent/extensions/pi-extension-codex-fast-mode/config.json", loadGlobalState(path) { loadCalls.push(path); return { state: { enabled: globalEnabled } }; }, saveGlobalState(path, state) { saveCalls.push({ path, state }); if (options.saveError) return { success: false, error: options.saveError }; globalEnabled = state.enabled; return { success: true }; }, }); return { appendCalls, commands, context, entries, handlers, loadCalls, notifications, saveCalls, setBusy(value: boolean) { busy = value; }, setPending(value: boolean) { pending = value; }, statusUpdates, }; } test("plain-object guard excludes malformed payloads", () => { assert.equal(isPlainObject({}), true); assert.equal(isPlainObject(Object.create(null)), true); assert.equal(isPlainObject([]), false); assert.equal(isPlainObject(new Date()), false); assert.equal(isPlainObject(null), false); assert.equal(isPlainObject("payload"), false); }); test("provider eligibility is exact", () => { assert.equal(isFastModeEligibleModel({ provider: "openai-codex", api: "openai-codex-responses" }), true); assert.equal(isFastModeEligibleModel({ provider: "openai", api: "openai-codex-responses" }), false); assert.equal(isFastModeEligibleModel({ provider: "openai-codex", api: "openai-responses" }), false); assert.equal(isFastModeEligibleModel(undefined), false); }); test("request transformer is isolated, non-mutating, and overwrites only service_tier", () => { const payload = { model: "gpt-5.6-codex", service_tier: "default", nested: { preserved: true } }; const transformed = transformFastModeRequest(true, { provider: "openai-codex", api: "openai-codex-responses" }, payload); assert.deepEqual(transformed, { model: "gpt-5.6-codex", service_tier: FAST_MODE_SERVICE_TIER, nested: { preserved: true }, }); assert.notStrictEqual(transformed, payload); assert.strictEqual(transformed?.nested, payload.nested); assert.equal(payload.service_tier, "default"); assert.equal(transformFastModeRequest(false, { provider: "openai-codex", api: "openai-codex-responses" }, payload), undefined); assert.equal(transformFastModeRequest(true, { provider: "openai", api: "openai-codex-responses" }, payload), undefined); assert.equal(transformFastModeRequest(true, { provider: "openai-codex", api: "openai-codex-responses" }, []), undefined); }); test("branch reconstruction prefers the latest valid snapshot over the global default", () => { assert.deepEqual(reconstructFastModeState([], true), { enabled: true }); assert.deepEqual(reconstructFastModeState([ { type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: true } }, { type: "custom", customType: "other", data: { enabled: false } }, { type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: "invalid" } }, { type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: false } }, ], true), { enabled: false }); }); test("global config round-trips atomically with owner-only permissions", () => { const agentDir = mkdtempSync(join(tmpdir(), "fast-mode-test-")); const configPath = getFastModeConfigPath(agentDir); try { assert.deepEqual(loadGlobalFastModeState(configPath), { state: { enabled: false } }); assert.deepEqual(saveGlobalFastModeState(configPath, { enabled: true }), { success: true }); assert.deepEqual(loadGlobalFastModeState(configPath), { state: { enabled: true } }); assert.deepEqual(JSON.parse(readFileSync(configPath, "utf8")), { enabled: true }); assert.equal(statSync(configPath).mode & 0o777, 0o600); assert.equal(statSync(join(agentDir, "extensions", "pi-extension-codex-fast-mode")).mode & 0o777, 0o700); } finally { rmSync(agentDir, { recursive: true, force: true }); } }); test("invalid or unreadable global config fails safely to off", () => { const directory = mkdtempSync(join(tmpdir(), "fast-mode-invalid-")); const configPath = join(directory, "config.json"); try { writeFileSync(configPath, "{ not-json", "utf8"); const invalid = loadGlobalFastModeState(configPath); assert.deepEqual(invalid.state, { enabled: false }); assert.match(invalid.warning ?? "", /Could not read/u); writeFileSync(configPath, JSON.stringify({ enabled: "yes" }), "utf8"); const wrongType = loadGlobalFastModeState(configPath); assert.deepEqual(wrongType.state, { enabled: false }); assert.match(wrongType.warning ?? "", /expected/u); chmodSync(configPath, 0o600); } finally { rmSync(directory, { recursive: true, force: true }); } }); test("command grammar and completions are deterministic", () => { assert.equal(parseFastModeCommand(""), "toggle"); assert.equal(parseFastModeCommand(" ON "), "on"); assert.equal(parseFastModeCommand("off"), "off"); assert.equal(parseFastModeCommand("status"), "status"); assert.equal(parseFastModeCommand("on now"), "invalid"); assert.deepEqual(fastModeArgumentCompletions("o"), [ { value: "on", label: "on" }, { value: "off", label: "off" }, ]); assert.deepEqual(fastModeArgumentCompletions("status"), [{ value: "status", label: "status" }]); }); test("a new session inherits the global default while a branch snapshot takes precedence", () => { const inherited = createHarness({ globalEnabled: true }); const inheritedStart = inherited.handlers.get("session_start"); assert.ok(inheritedStart); inheritedStart!({}, inherited.context as unknown as ExtensionContext); assert.deepEqual(inherited.statusUpdates.at(-1), { key: FAST_MODE_STATUS_KEY, value: "on" }); const overridden = createHarness({ globalEnabled: true, entries: [{ type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: false } }], }); const overriddenStart = overridden.handlers.get("session_start"); assert.ok(overriddenStart); overriddenStart!({}, overridden.context as unknown as ExtensionContext); assert.deepEqual(overridden.statusUpdates.at(-1), { key: FAST_MODE_STATUS_KEY, value: "off" }); }); test("extension restores state, publishes status, and persists session and global mutations", async () => { const harness = createHarness({ entries: [{ type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: true } }], }); const sessionStart = harness.handlers.get("session_start"); const request = harness.handlers.get("before_provider_request"); const command = harness.commands.get("fast-mode"); assert.ok(sessionStart && request && command); sessionStart!({}, harness.context as unknown as ExtensionContext); assert.deepEqual(harness.statusUpdates.at(-1), { key: FAST_MODE_STATUS_KEY, value: "on" }); assert.deepEqual(request!({ payload: { service_tier: "standard", keep: true } }, harness.context), { service_tier: FAST_MODE_SERVICE_TIER, keep: true, }); await command.handler("off", harness.context); assert.deepEqual(harness.appendCalls, [{ customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: false } }]); assert.deepEqual(harness.saveCalls.map((call) => call.state), [{ enabled: false }]); assert.deepEqual(harness.statusUpdates.at(-1), { key: FAST_MODE_STATUS_KEY, value: "off" }); assert.equal(request!({ payload: { keep: true } }, harness.context), undefined); await command.handler("status", harness.context); assert.match(harness.notifications.at(-1)?.message ?? "", /Fast mode: off.*New sessions default to off/u); assert.equal(harness.notifications.at(-1)?.level, "info"); }); test("an explicit no-op mode command still refreshes the global default", async () => { const harness = createHarness({ globalEnabled: true }); const sessionStart = harness.handlers.get("session_start"); const command = harness.commands.get("fast-mode"); assert.ok(sessionStart && command); sessionStart!({}, harness.context as unknown as ExtensionContext); await command.handler("on", harness.context); assert.equal(harness.appendCalls.length, 0); assert.deepEqual(harness.saveCalls.map((call) => call.state), [{ enabled: true }]); }); test("a global save failure leaves the session usable and reports the persistence failure", async () => { const harness = createHarness({ saveError: "read-only filesystem" }); const sessionStart = harness.handlers.get("session_start"); const command = harness.commands.get("fast-mode"); assert.ok(sessionStart && command); sessionStart!({}, harness.context as unknown as ExtensionContext); await command.handler("on", harness.context); assert.deepEqual(harness.appendCalls, [{ customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: true } }]); assert.equal(harness.notifications.at(-1)?.level, "warning"); assert.match(harness.notifications.at(-1)?.message ?? "", /could not be saved.*read-only filesystem/u); }); test("extension rejects every mutation while busy but leaves status readable", async () => { const harness = createHarness({ busy: true }); const sessionStart = harness.handlers.get("session_start"); const command = harness.commands.get("fast-mode"); assert.ok(sessionStart && command); sessionStart!({}, harness.context as unknown as ExtensionContext); await command.handler("on", harness.context); await command.handler("", harness.context); await command.handler("off", harness.context); assert.equal(harness.appendCalls.length, 0); assert.equal(harness.saveCalls.length, 0); assert.equal(harness.notifications.filter((item) => item.level === "warning").length, 3); await command.handler("status", harness.context); assert.match(harness.notifications.at(-1)?.message ?? "", /Fast mode: off/u); assert.equal(harness.notifications.at(-1)?.level, "info"); harness.setBusy(false); harness.setPending(true); await command.handler("on", harness.context); assert.equal(harness.appendCalls.length, 0); assert.equal(harness.saveCalls.length, 0); }); test("tree navigation reconstructs the active branch state", () => { const harness = createHarness({ globalEnabled: true, entries: [{ type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: true } }], }); const sessionStart = harness.handlers.get("session_start"); const sessionTree = harness.handlers.get("session_tree"); assert.ok(sessionStart && sessionTree); sessionStart!({}, harness.context as unknown as ExtensionContext); harness.entries.push({ type: "custom", customType: FAST_MODE_STATE_ENTRY_TYPE, data: { enabled: false } }); sessionTree!({}, harness.context as unknown as ExtensionContext); assert.deepEqual(harness.statusUpdates.at(-1), { key: FAST_MODE_STATUS_KEY, value: "off" }); });