feat(tests): add isolated pi launchers
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Add repository commands for testing the current checkout either in a logged-out, automatically cleaned-up pi environment or with existing credentials and only Command Code models enabled.
|
||||||
- Use the host-provided `pi-ai` and `pi-coding-agent` core packages instead of installing private runtime copies, including for local and out-of-store development checkouts.
|
- Use the host-provided `pi-ai` and `pi-coding-agent` core packages instead of installing private runtime copies, including for local and out-of-store development checkouts.
|
||||||
|
|
||||||
## 0.4.4 - 2026-08-03
|
## 0.4.4 - 2026-08-03
|
||||||
|
|||||||
@@ -21,9 +21,31 @@ npm run test:models
|
|||||||
npm run test:oauth
|
npm run test:oauth
|
||||||
npm run test:abort
|
npm run test:abort
|
||||||
npm run test:stream
|
npm run test:stream
|
||||||
|
npm run test:pi-isolated
|
||||||
|
npm run test:pi-authenticated
|
||||||
npm run test:pi-local
|
npm run test:pi-local
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Start pi with only the current checkout installed in temporary config and session directories, without inheriting Command Code credentials:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run pi:isolated
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `/login` inside pi. The temporary credential and sessions are deleted when pi exits.
|
||||||
|
|
||||||
|
To use the current checkout with your existing pi credentials and expose only Command Code models in the model picker:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run pi:authenticated
|
||||||
|
```
|
||||||
|
|
||||||
|
Both launchers default to `commandcode/gpt-5.6-luna`. Pass additional pi arguments after `--` to override defaults or change startup behavior:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run pi:authenticated -- --model claude-sonnet-4-6
|
||||||
|
```
|
||||||
|
|
||||||
Before opening a PR, run:
|
Before opening a PR, run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -147,6 +147,22 @@ omp plugin uninstall pi-commandcode-provider
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
Start an isolated pi instance with only the current checkout installed and no existing Command Code credentials:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run pi:isolated
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `/login` inside pi. Temporary credentials, configuration, and sessions are deleted when pi exits.
|
||||||
|
|
||||||
|
Start the current checkout with your existing pi credentials and only Command Code models in the model picker:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run pi:authenticated
|
||||||
|
```
|
||||||
|
|
||||||
|
Both commands accept additional pi arguments after `--`, for example `npm run pi:authenticated -- --model claude-sonnet-4-6`.
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and tests. See [RELEASE.md](RELEASE.md) for the release process.
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and tests. See [RELEASE.md](RELEASE.md) for the release process.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ import { AssistantMessageEventStream } from "@earendil-works/pi-ai"
|
|||||||
import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent"
|
import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
|
|
||||||
|
import { getApiKey as getStoredApiKey } from "./src/converters.ts"
|
||||||
import { COMMAND_CODE_CLI_VERSION, createStreamCommandCode, DEFAULT_API_BASE } from "./src/core.ts"
|
import { COMMAND_CODE_CLI_VERSION, createStreamCommandCode, DEFAULT_API_BASE } from "./src/core.ts"
|
||||||
import { calculateCommandCodeCost } from "./src/cost.ts"
|
import { calculateCommandCodeCost } from "./src/cost.ts"
|
||||||
import { DEFAULT_MODELS_URL, loadCommandCodeModels } from "./src/models.ts"
|
import { DEFAULT_MODELS_URL, loadCommandCodeModels } from "./src/models.ts"
|
||||||
import { getApiKey, login, refreshToken } from "./src/oauth.ts"
|
import { getApiKey as getOAuthApiKey, login, refreshToken } from "./src/oauth.ts"
|
||||||
|
|
||||||
const API_BASE = process.env.COMMANDCODE_API_BASE ?? DEFAULT_API_BASE
|
const API_BASE = process.env.COMMANDCODE_API_BASE ?? DEFAULT_API_BASE
|
||||||
const MODELS_URL = process.env.COMMANDCODE_MODELS_URL ?? DEFAULT_MODELS_URL
|
const MODELS_URL = process.env.COMMANDCODE_MODELS_URL ?? DEFAULT_MODELS_URL
|
||||||
@@ -82,6 +83,7 @@ const streamCommandCode = createStreamCommandCode({
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export default async function (pi: ExtensionAPI) {
|
export default async function (pi: ExtensionAPI) {
|
||||||
|
const storedApiKey = getStoredApiKey()
|
||||||
const { models, warning } = await loadCommandCodeModels({
|
const { models, warning } = await loadCommandCodeModels({
|
||||||
url: MODELS_URL,
|
url: MODELS_URL,
|
||||||
cachePath: MODELS_CACHE_PATH,
|
cachePath: MODELS_CACHE_PATH,
|
||||||
@@ -92,7 +94,7 @@ export default async function (pi: ExtensionAPI) {
|
|||||||
pi.registerProvider("commandcode", {
|
pi.registerProvider("commandcode", {
|
||||||
name: "Command Code",
|
name: "Command Code",
|
||||||
baseUrl: API_BASE,
|
baseUrl: API_BASE,
|
||||||
apiKey: "$COMMANDCODE_API_KEY",
|
apiKey: storedApiKey,
|
||||||
authHeader: true,
|
authHeader: true,
|
||||||
api: "commandcode-custom",
|
api: "commandcode-custom",
|
||||||
streamSimple: streamCommandCode,
|
streamSimple: streamCommandCode,
|
||||||
@@ -104,7 +106,7 @@ export default async function (pi: ExtensionAPI) {
|
|||||||
name: "Command Code",
|
name: "Command Code",
|
||||||
login,
|
login,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
getApiKey,
|
getApiKey: getOAuthApiKey,
|
||||||
},
|
},
|
||||||
models: models.map((model) => ({
|
models: models.map((model) => ({
|
||||||
id: model.id,
|
id: model.id,
|
||||||
|
|||||||
+6
-1
@@ -21,6 +21,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"index.ts",
|
"index.ts",
|
||||||
"src/",
|
"src/",
|
||||||
|
"scripts/",
|
||||||
"README.md",
|
"README.md",
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"CONTRIBUTING.md",
|
"CONTRIBUTING.md",
|
||||||
@@ -28,10 +29,12 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run typecheck && tsx tests/test-package-manifest.ts && tsx tests/test-pure-functions.ts && tsx tests/test-models.ts && tsx tests/test-pricing.ts && tsx tests/test-cost.ts && tsx tests/test-oauth.ts && tsx tests/test-abort.ts && tsx tests/test-stream.ts && tsx tests/test-retry.ts && node tests/test-pi-local.mjs && node tests/test-omp-compat.mjs",
|
"test": "npm run typecheck && tsx tests/test-package-manifest.ts && tsx tests/test-pure-functions.ts && tsx tests/test-models.ts && tsx tests/test-pricing.ts && tsx tests/test-cost.ts && tsx tests/test-oauth.ts && tsx tests/test-abort.ts && tsx tests/test-stream.ts && tsx tests/test-retry.ts && node tests/test-pi-isolated.mjs && node tests/test-pi-authenticated.mjs && node tests/test-pi-local.mjs && node tests/test-omp-compat.mjs",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"format:check": "prettier --check '**/*.{ts,mjs,json,md}'",
|
"format:check": "prettier --check '**/*.{ts,mjs,json,md}'",
|
||||||
"format": "prettier --write '**/*.{ts,mjs,json,md}'",
|
"format": "prettier --write '**/*.{ts,mjs,json,md}'",
|
||||||
|
"pi:isolated": "node scripts/pi-isolated.mjs",
|
||||||
|
"pi:authenticated": "node scripts/pi-authenticated.mjs",
|
||||||
"test:unit": "tsx tests/test-pure-functions.ts",
|
"test:unit": "tsx tests/test-pure-functions.ts",
|
||||||
"test:models": "tsx tests/test-models.ts",
|
"test:models": "tsx tests/test-models.ts",
|
||||||
"test:pricing": "tsx tests/test-pricing.ts",
|
"test:pricing": "tsx tests/test-pricing.ts",
|
||||||
@@ -39,6 +42,8 @@
|
|||||||
"test:abort": "tsx tests/test-abort.ts",
|
"test:abort": "tsx tests/test-abort.ts",
|
||||||
"test:stream": "tsx tests/test-stream.ts",
|
"test:stream": "tsx tests/test-stream.ts",
|
||||||
"test:retry": "tsx tests/test-retry.ts",
|
"test:retry": "tsx tests/test-retry.ts",
|
||||||
|
"test:pi-isolated": "node tests/test-pi-isolated.mjs",
|
||||||
|
"test:pi-authenticated": "node tests/test-pi-authenticated.mjs",
|
||||||
"test:pi-local": "node tests/test-pi-local.mjs",
|
"test:pi-local": "node tests/test-pi-local.mjs",
|
||||||
"test:smoke": "node tests/test-smoke.mjs",
|
"test:smoke": "node tests/test-smoke.mjs",
|
||||||
"test:cost": "tsx tests/test-cost.ts"
|
"test:cost": "tsx tests/test-cost.ts"
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { spawn } from "node:child_process"
|
||||||
|
import { dirname, resolve } from "node:path"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
|
||||||
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
||||||
|
const extensionPath = resolve(repoRoot, "index.ts")
|
||||||
|
|
||||||
|
const env = {
|
||||||
|
...process.env,
|
||||||
|
PI_SKIP_VERSION_CHECK: "1",
|
||||||
|
}
|
||||||
|
delete env.COMMANDCODE_API_KEY
|
||||||
|
|
||||||
|
const child = spawn(
|
||||||
|
"pi",
|
||||||
|
[
|
||||||
|
"--no-extensions",
|
||||||
|
"--extension",
|
||||||
|
extensionPath,
|
||||||
|
"--provider",
|
||||||
|
"commandcode",
|
||||||
|
"--model",
|
||||||
|
"gpt-5.6-luna",
|
||||||
|
"--models",
|
||||||
|
"commandcode/*",
|
||||||
|
...process.argv.slice(2),
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cwd: repoRoot,
|
||||||
|
env,
|
||||||
|
stdio: "inherit",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
||||||
|
process.on(signal, () => child.kill(signal))
|
||||||
|
}
|
||||||
|
|
||||||
|
child.once("error", (error) => {
|
||||||
|
console.error(`Could not start pi: ${error.message}`)
|
||||||
|
process.exitCode = 1
|
||||||
|
})
|
||||||
|
|
||||||
|
child.once("exit", (status, signal) => {
|
||||||
|
if (signal) process.kill(process.pid, signal)
|
||||||
|
process.exitCode = status ?? 1
|
||||||
|
})
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { spawn } from "node:child_process"
|
||||||
|
import { mkdir, mkdtemp, rm } from "node:fs/promises"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { dirname, join, resolve } from "node:path"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
|
||||||
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
||||||
|
const testRoot = await mkdtemp(join(tmpdir(), "pi-commandcode-isolated-"))
|
||||||
|
const agentDir = join(testRoot, "agent")
|
||||||
|
const sessionDir = join(testRoot, "sessions")
|
||||||
|
|
||||||
|
await mkdir(agentDir, { mode: 0o700 })
|
||||||
|
await mkdir(sessionDir, { mode: 0o700 })
|
||||||
|
|
||||||
|
const env = {
|
||||||
|
...process.env,
|
||||||
|
HOME: testRoot,
|
||||||
|
USERPROFILE: testRoot,
|
||||||
|
PI_CODING_AGENT_DIR: agentDir,
|
||||||
|
PI_CODING_AGENT_SESSION_DIR: sessionDir,
|
||||||
|
PI_SKIP_VERSION_CHECK: "1",
|
||||||
|
}
|
||||||
|
delete env.COMMANDCODE_API_KEY
|
||||||
|
|
||||||
|
let activeChild
|
||||||
|
let receivedSignal
|
||||||
|
|
||||||
|
function forwardSignal(signal) {
|
||||||
|
receivedSignal = signal
|
||||||
|
activeChild?.kill(signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const forwardSigint = () => forwardSignal("SIGINT")
|
||||||
|
const forwardSigterm = () => forwardSignal("SIGTERM")
|
||||||
|
process.on("SIGINT", forwardSigint)
|
||||||
|
process.on("SIGTERM", forwardSigterm)
|
||||||
|
|
||||||
|
function runPi(args) {
|
||||||
|
return new Promise((resolveRun, rejectRun) => {
|
||||||
|
const child = spawn("pi", args, { cwd: repoRoot, env, stdio: "inherit" })
|
||||||
|
activeChild = child
|
||||||
|
child.once("error", rejectRun)
|
||||||
|
child.once("exit", (status, signal) => {
|
||||||
|
activeChild = undefined
|
||||||
|
resolveRun({ status, signal })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let result
|
||||||
|
try {
|
||||||
|
console.error("Installing the current checkout into an isolated pi environment...")
|
||||||
|
const install = await runPi(["install", repoRoot, "--no-approve"])
|
||||||
|
if (install.status !== 0 || install.signal) {
|
||||||
|
result = install
|
||||||
|
} else {
|
||||||
|
console.error("Starting pi. Temporary auth and sessions will be removed on exit.")
|
||||||
|
result = await runPi([
|
||||||
|
"--no-approve",
|
||||||
|
"--provider",
|
||||||
|
"commandcode",
|
||||||
|
"--model",
|
||||||
|
"gpt-5.6-luna",
|
||||||
|
...process.argv.slice(2),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
process.removeListener("SIGINT", forwardSigint)
|
||||||
|
process.removeListener("SIGTERM", forwardSigterm)
|
||||||
|
await rm(testRoot, { recursive: true, force: true })
|
||||||
|
console.error("Removed the isolated pi environment.")
|
||||||
|
}
|
||||||
|
|
||||||
|
const signal = receivedSignal ?? result?.signal
|
||||||
|
if (signal) process.kill(process.pid, signal)
|
||||||
|
process.exitCode = result?.status ?? 1
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import assert from "node:assert/strict"
|
||||||
|
import { spawnSync } from "node:child_process"
|
||||||
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { delimiter, dirname, join, resolve } from "node:path"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
import { describe, it } from "node:test"
|
||||||
|
|
||||||
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
||||||
|
const launcher = join(repoRoot, "scripts", "pi-authenticated.mjs")
|
||||||
|
|
||||||
|
function runLauncher() {
|
||||||
|
const fakeBin = mkdtempSync(join(tmpdir(), "pi-commandcode-fake-bin-"))
|
||||||
|
const logPath = join(fakeBin, "call.json")
|
||||||
|
const fakePi = join(fakeBin, "pi")
|
||||||
|
|
||||||
|
writeFileSync(
|
||||||
|
fakePi,
|
||||||
|
`#!/bin/sh
|
||||||
|
node - "$@" <<'NODE'
|
||||||
|
const { writeFileSync } = require("node:fs")
|
||||||
|
writeFileSync(process.env.FAKE_PI_LOG, JSON.stringify({
|
||||||
|
args: process.argv.slice(2),
|
||||||
|
agentDir: process.env.PI_CODING_AGENT_DIR ?? null,
|
||||||
|
apiKey: process.env.COMMANDCODE_API_KEY ?? null,
|
||||||
|
skipVersionCheck: process.env.PI_SKIP_VERSION_CHECK,
|
||||||
|
}))
|
||||||
|
NODE
|
||||||
|
`,
|
||||||
|
{ mode: 0o700 },
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = spawnSync(process.execPath, [launcher, "--thinking", "high"], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PATH: `${fakeBin}${delimiter}${process.env.PATH ?? ""}`,
|
||||||
|
FAKE_PI_LOG: logPath,
|
||||||
|
PI_CODING_AGENT_DIR: "/existing/pi-agent",
|
||||||
|
COMMANDCODE_API_KEY: "existing-key",
|
||||||
|
},
|
||||||
|
encoding: "utf8",
|
||||||
|
})
|
||||||
|
return { result, call: JSON.parse(readFileSync(logPath, "utf8")) }
|
||||||
|
} finally {
|
||||||
|
rmSync(fakeBin, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("authenticated pi launcher", () => {
|
||||||
|
it("loads only the checkout extension and leaves auth resolution to existing files", () => {
|
||||||
|
const { result, call } = runLauncher()
|
||||||
|
|
||||||
|
assert.equal(result.status, 0)
|
||||||
|
assert.deepEqual(call.args, [
|
||||||
|
"--no-extensions",
|
||||||
|
"--extension",
|
||||||
|
join(repoRoot, "index.ts"),
|
||||||
|
"--provider",
|
||||||
|
"commandcode",
|
||||||
|
"--model",
|
||||||
|
"gpt-5.6-luna",
|
||||||
|
"--models",
|
||||||
|
"commandcode/*",
|
||||||
|
"--thinking",
|
||||||
|
"high",
|
||||||
|
])
|
||||||
|
assert.equal(call.agentDir, "/existing/pi-agent")
|
||||||
|
assert.equal(call.apiKey, null)
|
||||||
|
assert.equal(call.skipVersionCheck, "1")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import assert from "node:assert/strict"
|
||||||
|
import { spawnSync } from "node:child_process"
|
||||||
|
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { delimiter, dirname, join, resolve } from "node:path"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
import { describe, it } from "node:test"
|
||||||
|
|
||||||
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
||||||
|
const launcher = join(repoRoot, "scripts", "pi-isolated.mjs")
|
||||||
|
|
||||||
|
function runLauncher({ exitStatus = 0 } = {}) {
|
||||||
|
const fakeBin = mkdtempSync(join(tmpdir(), "pi-commandcode-fake-bin-"))
|
||||||
|
const logPath = join(fakeBin, "calls.jsonl")
|
||||||
|
const fakePi = join(fakeBin, "pi")
|
||||||
|
|
||||||
|
writeFileSync(
|
||||||
|
fakePi,
|
||||||
|
`#!/bin/sh
|
||||||
|
node - "$@" <<'NODE'
|
||||||
|
const { appendFileSync } = require("node:fs")
|
||||||
|
appendFileSync(process.env.FAKE_PI_LOG, JSON.stringify({
|
||||||
|
args: process.argv.slice(2),
|
||||||
|
agentDir: process.env.PI_CODING_AGENT_DIR,
|
||||||
|
sessionDir: process.env.PI_CODING_AGENT_SESSION_DIR,
|
||||||
|
skipVersionCheck: process.env.PI_SKIP_VERSION_CHECK,
|
||||||
|
home: process.env.HOME,
|
||||||
|
userProfile: process.env.USERPROFILE,
|
||||||
|
inheritedApiKey: process.env.COMMANDCODE_API_KEY ?? null,
|
||||||
|
}) + "\\n")
|
||||||
|
NODE
|
||||||
|
if [ "$1" = "install" ]; then exit 0; fi
|
||||||
|
exit ${exitStatus}
|
||||||
|
`,
|
||||||
|
{ mode: 0o700 },
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = spawnSync(process.execPath, [launcher, "--model", "claude-sonnet-5"], {
|
||||||
|
cwd: repoRoot,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PATH: `${fakeBin}${delimiter}${process.env.PATH ?? ""}`,
|
||||||
|
FAKE_PI_LOG: logPath,
|
||||||
|
COMMANDCODE_API_KEY: "must-not-leak",
|
||||||
|
},
|
||||||
|
encoding: "utf8",
|
||||||
|
})
|
||||||
|
const calls = readFileSync(logPath, "utf8")
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => JSON.parse(line))
|
||||||
|
return { result, calls }
|
||||||
|
} finally {
|
||||||
|
rmSync(fakeBin, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("isolated pi launcher", () => {
|
||||||
|
it("installs the current checkout, forwards arguments, and removes its environment", () => {
|
||||||
|
const { result, calls } = runLauncher()
|
||||||
|
|
||||||
|
assert.equal(result.status, 0)
|
||||||
|
assert.equal(calls.length, 2)
|
||||||
|
assert.deepEqual(calls[0].args, ["install", repoRoot, "--no-approve"])
|
||||||
|
assert.deepEqual(calls[1].args, [
|
||||||
|
"--no-approve",
|
||||||
|
"--provider",
|
||||||
|
"commandcode",
|
||||||
|
"--model",
|
||||||
|
"gpt-5.6-luna",
|
||||||
|
"--model",
|
||||||
|
"claude-sonnet-5",
|
||||||
|
])
|
||||||
|
|
||||||
|
const [install, launch] = calls
|
||||||
|
assert.equal(install.agentDir, launch.agentDir)
|
||||||
|
assert.equal(install.sessionDir, launch.sessionDir)
|
||||||
|
assert.equal(launch.skipVersionCheck, "1")
|
||||||
|
assert.equal(launch.inheritedApiKey, null)
|
||||||
|
assert.ok(launch.agentDir.includes("pi-commandcode-isolated-"))
|
||||||
|
assert.equal(launch.home, dirname(launch.agentDir))
|
||||||
|
assert.equal(launch.userProfile, dirname(launch.agentDir))
|
||||||
|
assert.equal(dirname(launch.agentDir), dirname(launch.sessionDir))
|
||||||
|
assert.equal(existsSync(dirname(launch.agentDir)), false)
|
||||||
|
assert.match(result.stderr, /Removed the isolated pi environment/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns the pi exit status and still removes its environment", () => {
|
||||||
|
const { result, calls } = runLauncher({ exitStatus: 7 })
|
||||||
|
|
||||||
|
assert.equal(result.status, 7)
|
||||||
|
assert.equal(calls.length, 2)
|
||||||
|
assert.equal(existsSync(dirname(calls[1].agentDir)), false)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user