From fc530582684045aec61a47176521c6f46d0eb7b9 Mon Sep 17 00:00:00 2001 From: auchan Date: Sun, 6 Sep 2026 21:55:52 +0800 Subject: [PATCH 1/2] fix: point Pi install command and requirement bullet at 0.85.1 --- README.md | 2 +- src/extension.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 646e5de..4bf0e48 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ It does not reveal a new chat tab automatically when there are no tabs to restor - VS Code 1.118 or newer. - Node.js 22 or newer. -- Pi coding agent 0.80.8 through 0.82.1 (current verified compatibility +- Pi coding agent 0.80.8 through 0.85.1 (current verified compatibility range). Pi 0.80.8 is the minimum supported release because Pi on Code uses the diff --git a/src/extension.ts b/src/extension.ts index d4b5900..b387422 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2353,7 +2353,7 @@ async function installPi(): Promise { return new Promise((resolve) => { const term = vscode.window.createTerminal("Pi Install"); term.show(); - term.sendText("npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.1"); + term.sendText("npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.85.1"); term.sendText( 'echo "✅ Pi SDK installed! Reload VS Code to use Pi on Code."', ); From 2ff2b438cdd2bf97d08dc967ac8b2e39abc6e570 Mon Sep 17 00:00:00 2001 From: auchan Date: Sun, 6 Sep 2026 21:57:27 +0800 Subject: [PATCH 2/2] test: add reusable pi-coding-agent SDK smoke script --- scripts/smoke-pi-sdk.mjs | 128 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 scripts/smoke-pi-sdk.mjs diff --git a/scripts/smoke-pi-sdk.mjs b/scripts/smoke-pi-sdk.mjs new file mode 100644 index 0000000..d0ca0d4 --- /dev/null +++ b/scripts/smoke-pi-sdk.mjs @@ -0,0 +1,128 @@ +// Compatibility smoke test for the installed @earendil-works/pi-coding-agent SDK. +// +// Verifies the SDK entry points Pi on Code relies on exist and boot offline on +// the installed version (ModelRuntime, SessionManager, agent session services), +// and that a legacy session JSONL written by an older agent can still be read +// (the plugin's session-restore path). +// +// Usage: +// bun run scripts/smoke-pi-sdk.mjs +// # or point at a specific SDK install: +// PI_SDK_PATH=/abs/path/to/pi-coding-agent bun run scripts/smoke-pi-sdk.mjs +import { createRequire } from "node:module"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +const require = createRequire(import.meta.url); + +function resolveSdkRoot() { + if (process.env.PI_SDK_PATH && fs.existsSync(process.env.PI_SDK_PATH)) { + return process.env.PI_SDK_PATH; + } + const suffix = path.join("node_modules", "@earendil-works", "pi-coding-agent"); + const candidates = new Set(); + const home = process.env.HOME || process.env.USERPROFILE || ""; + const appData = process.env.APPDATA || ""; + for (const base of [ + home && path.join(home, ".pi", "npm", suffix), + process.platform === "win32" && appData && path.join(appData, "npm", suffix), + home && path.join(home, ".npm-global", "lib", suffix), + home && path.join(home, ".local", "lib", suffix), + ]) { + if (base) candidates.add(base); + } + for (const candidate of candidates) { + if (fs.existsSync(path.join(candidate, "package.json"))) return candidate; + } + throw new Error( + "pi-coding-agent SDK not found. Install it globally first:\n" + + " npm install -g --ignore-scripts @earendil-works/pi-coding-agent", + ); +} + +function check(ok, label, detail = "") { + console.log(`${ok ? "ok " : "FAIL"} ${label}${detail ? ` (${detail})` : ""}`); + if (!ok) process.exitCode = 1; +} + +const sdkRoot = resolveSdkRoot(); +const SDK = require(sdkRoot); +const pkg = require(path.join(sdkRoot, "package.json")); +console.log(`pi-coding-agent ${pkg.version} at ${sdkRoot}`); + +// ── root entry points used by the extension ──────────────────────────── +const required = [ + "ModelRuntime", + "ModelRegistry", + "SessionManager", + "createAgentSessionServices", + "createAgentSessionFromServices", + "createAgentSession", + "createSyntheticSourceInfo", +]; +const missing = required.filter((key) => typeof SDK[key] === "undefined"); +check(missing.length === 0, "required SDK entry points present", missing.join(", ") || "all"); + +if (missing.length) process.exit(1); + +// ── offline boot + session creation in a temp directory ──────────────── +const cwd = path.join(os.tmpdir(), `pi-sdk-smoke-${Date.now()}`); +const agentDir = path.join(cwd, ".pi", "agent"); +try { + fs.mkdirSync(agentDir, { recursive: true }); + const runtime = await SDK.ModelRuntime.create({ + authPath: path.join(agentDir, "auth.json"), + modelsPath: path.join(agentDir, "models.json"), + }); + check(true, "ModelRuntime.create() boots offline"); + + const sessionManager = SDK.SessionManager.create(cwd, agentDir); + check( + Boolean(sessionManager.getSessionFile?.()?.endsWith(".jsonl")), + "SessionManager.create() returns a session path (file persists on first write)", + ); + + const services = await SDK.createAgentSessionServices({ cwd, agentDir, modelRuntime: runtime }); + check(Array.isArray(services.diagnostics), "createAgentSessionServices() returns diagnostics"); + + const agent = await SDK.createAgentSessionFromServices({ + services, + sessionManager, + model: { provider: "openai", id: "gpt-5.6" }, + }); + const session = agent?.session; + check( + session && typeof session.getAvailableThinkingLevels === "function", + "agent session exposes getAvailableThinkingLevels()", + ); + check(typeof session?.setThinkingLevel === "function", "agent session exposes setThinkingLevel()"); + check(typeof session?.setModel === "function", "agent session exposes setModel()"); + check(typeof SDK.ModelRegistry === "function", "ModelRegistry facade constructs", ""); + + // ── legacy JSONL restore path ────────────────────────────────────────── + const legacyRoot = path.join(os.homedir(), ".pi", "agent", "sessions"); + let opened = null; + let legacyFile = null; + if (fs.existsSync(legacyRoot)) { + outer: for (const project of fs.readdirSync(legacyRoot)) { + const dir = path.join(legacyRoot, project); + if (!fs.statSync(dir).isDirectory()) continue; + for (const file of fs.readdirSync(dir).filter((name) => name.endsWith(".jsonl"))) { + legacyFile = path.join(dir, file); + break outer; + } + } + } + if (legacyFile) { + opened = SDK.SessionManager.open(legacyFile, agentDir); + const entries = opened.getEntries?.() ?? []; + check(entries.length > 0, "legacy session JSONL opens and parses", `${entries.length} entries`); + } else { + console.log("skip no legacy session files under ~/.pi/agent/sessions"); + } + + console.log(process.exitCode ? "SMOKE FAILED" : "SMOKE OK"); +} finally { + fs.rmSync(cwd, { recursive: true, force: true }); +}