@andreroggeri/adapter-pi-local-serialized 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +75 -0
  3. package/dist/cli/format-event.d.ts +2 -0
  4. package/dist/cli/format-event.d.ts.map +1 -0
  5. package/dist/cli/format-event.js +99 -0
  6. package/dist/cli/format-event.js.map +1 -0
  7. package/dist/cli/index.d.ts +2 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +2 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/index.d.ts +11 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +49 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/server/concurrency.d.ts +2 -0
  16. package/dist/server/concurrency.d.ts.map +1 -0
  17. package/dist/server/concurrency.js +25 -0
  18. package/dist/server/concurrency.js.map +1 -0
  19. package/dist/server/execute.d.ts +3 -0
  20. package/dist/server/execute.d.ts.map +1 -0
  21. package/dist/server/execute.js +675 -0
  22. package/dist/server/execute.js.map +1 -0
  23. package/dist/server/execute.remote.test.d.ts +2 -0
  24. package/dist/server/execute.remote.test.d.ts.map +1 -0
  25. package/dist/server/execute.remote.test.js +466 -0
  26. package/dist/server/execute.remote.test.js.map +1 -0
  27. package/dist/server/index.d.ts +8 -0
  28. package/dist/server/index.d.ts.map +1 -0
  29. package/dist/server/index.js +51 -0
  30. package/dist/server/index.js.map +1 -0
  31. package/dist/server/models.d.ts +20 -0
  32. package/dist/server/models.d.ts.map +1 -0
  33. package/dist/server/models.js +163 -0
  34. package/dist/server/models.js.map +1 -0
  35. package/dist/server/models.test.d.ts +2 -0
  36. package/dist/server/models.test.d.ts.map +1 -0
  37. package/dist/server/models.test.js +22 -0
  38. package/dist/server/models.test.js.map +1 -0
  39. package/dist/server/parse.d.ts +23 -0
  40. package/dist/server/parse.d.ts.map +1 -0
  41. package/dist/server/parse.js +195 -0
  42. package/dist/server/parse.js.map +1 -0
  43. package/dist/server/parse.test.d.ts +2 -0
  44. package/dist/server/parse.test.d.ts.map +1 -0
  45. package/dist/server/parse.test.js +249 -0
  46. package/dist/server/parse.test.js.map +1 -0
  47. package/dist/server/skills.d.ts +8 -0
  48. package/dist/server/skills.d.ts.map +1 -0
  49. package/dist/server/skills.js +69 -0
  50. package/dist/server/skills.js.map +1 -0
  51. package/dist/server/test.d.ts +3 -0
  52. package/dist/server/test.d.ts.map +1 -0
  53. package/dist/server/test.js +309 -0
  54. package/dist/server/test.js.map +1 -0
  55. package/dist/ui/build-config.d.ts +3 -0
  56. package/dist/ui/build-config.d.ts.map +1 -0
  57. package/dist/ui/build-config.js +78 -0
  58. package/dist/ui/build-config.js.map +1 -0
  59. package/dist/ui/index.d.ts +3 -0
  60. package/dist/ui/index.d.ts.map +1 -0
  61. package/dist/ui/index.js +3 -0
  62. package/dist/ui/index.js.map +1 -0
  63. package/dist/ui/parse-stdout.d.ts +4 -0
  64. package/dist/ui/parse-stdout.d.ts.map +1 -0
  65. package/dist/ui/parse-stdout.js +271 -0
  66. package/dist/ui/parse-stdout.js.map +1 -0
  67. package/package.json +54 -0
@@ -0,0 +1,249 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parsePiJsonl, isPiUnknownSessionError } from "./parse.js";
3
+ describe("parsePiJsonl", () => {
4
+ it("parses agent lifecycle and messages", () => {
5
+ const stdout = [
6
+ JSON.stringify({ type: "agent_start" }),
7
+ JSON.stringify({
8
+ type: "turn_end",
9
+ message: {
10
+ role: "assistant",
11
+ content: [{ type: "text", text: "Hello from Pi" }],
12
+ },
13
+ }),
14
+ JSON.stringify({ type: "agent_end", messages: [] }),
15
+ ].join("\n");
16
+ const parsed = parsePiJsonl(stdout);
17
+ expect(parsed.messages).toContain("Hello from Pi");
18
+ expect(parsed.finalMessage).toBe("Hello from Pi");
19
+ });
20
+ it("parses streaming text deltas", () => {
21
+ const stdout = [
22
+ JSON.stringify({
23
+ type: "message_update",
24
+ assistantMessageEvent: { type: "text_delta", delta: "Hello " },
25
+ }),
26
+ JSON.stringify({
27
+ type: "message_update",
28
+ assistantMessageEvent: { type: "text_delta", delta: "World" },
29
+ }),
30
+ JSON.stringify({
31
+ type: "turn_end",
32
+ message: {
33
+ role: "assistant",
34
+ content: "Hello World",
35
+ },
36
+ }),
37
+ ].join("\n");
38
+ const parsed = parsePiJsonl(stdout);
39
+ expect(parsed.messages).toContain("Hello World");
40
+ });
41
+ it("parses tool execution", () => {
42
+ const stdout = [
43
+ JSON.stringify({
44
+ type: "tool_execution_start",
45
+ toolCallId: "tool_1",
46
+ toolName: "read",
47
+ args: { path: "/tmp/test.txt" },
48
+ }),
49
+ JSON.stringify({
50
+ type: "tool_execution_end",
51
+ toolCallId: "tool_1",
52
+ toolName: "read",
53
+ result: "file contents",
54
+ isError: false,
55
+ }),
56
+ JSON.stringify({
57
+ type: "turn_end",
58
+ message: { role: "assistant", content: "Done" },
59
+ toolResults: [
60
+ {
61
+ toolCallId: "tool_1",
62
+ content: "file contents",
63
+ isError: false,
64
+ },
65
+ ],
66
+ }),
67
+ ].join("\n");
68
+ const parsed = parsePiJsonl(stdout);
69
+ expect(parsed.toolCalls).toHaveLength(1);
70
+ expect(parsed.toolCalls[0].toolName).toBe("read");
71
+ expect(parsed.toolCalls[0].result).toBe("file contents");
72
+ expect(parsed.toolCalls[0].isError).toBe(false);
73
+ });
74
+ it("handles errors in tool execution", () => {
75
+ const stdout = [
76
+ JSON.stringify({
77
+ type: "tool_execution_start",
78
+ toolCallId: "tool_1",
79
+ toolName: "read",
80
+ args: { path: "/missing.txt" },
81
+ }),
82
+ JSON.stringify({
83
+ type: "tool_execution_end",
84
+ toolCallId: "tool_1",
85
+ toolName: "read",
86
+ result: "File not found",
87
+ isError: true,
88
+ }),
89
+ ].join("\n");
90
+ const parsed = parsePiJsonl(stdout);
91
+ expect(parsed.toolCalls).toHaveLength(1);
92
+ expect(parsed.toolCalls[0].isError).toBe(true);
93
+ expect(parsed.toolCalls[0].result).toBe("File not found");
94
+ });
95
+ it("extracts usage and cost from turn_end events", () => {
96
+ const stdout = [
97
+ JSON.stringify({
98
+ type: "turn_end",
99
+ message: {
100
+ role: "assistant",
101
+ content: "Response with usage",
102
+ usage: {
103
+ input: 100,
104
+ output: 50,
105
+ cacheRead: 20,
106
+ totalTokens: 170,
107
+ cost: {
108
+ input: 0.001,
109
+ output: 0.0015,
110
+ cacheRead: 0.0001,
111
+ cacheWrite: 0,
112
+ total: 0.0026,
113
+ },
114
+ },
115
+ },
116
+ toolResults: [],
117
+ }),
118
+ ].join("\n");
119
+ const parsed = parsePiJsonl(stdout);
120
+ expect(parsed.usage.inputTokens).toBe(100);
121
+ expect(parsed.usage.outputTokens).toBe(50);
122
+ expect(parsed.usage.cachedInputTokens).toBe(20);
123
+ expect(parsed.usage.costUsd).toBeCloseTo(0.0026, 4);
124
+ });
125
+ it("accumulates usage from multiple turns", () => {
126
+ const stdout = [
127
+ JSON.stringify({
128
+ type: "turn_end",
129
+ message: {
130
+ role: "assistant",
131
+ content: "First response",
132
+ usage: {
133
+ input: 50,
134
+ output: 25,
135
+ cacheRead: 0,
136
+ cost: { total: 0.001 },
137
+ },
138
+ },
139
+ }),
140
+ JSON.stringify({
141
+ type: "turn_end",
142
+ message: {
143
+ role: "assistant",
144
+ content: "Second response",
145
+ usage: {
146
+ input: 30,
147
+ output: 20,
148
+ cacheRead: 10,
149
+ cost: { total: 0.0015 },
150
+ },
151
+ },
152
+ }),
153
+ ].join("\n");
154
+ const parsed = parsePiJsonl(stdout);
155
+ expect(parsed.usage.inputTokens).toBe(80);
156
+ expect(parsed.usage.outputTokens).toBe(45);
157
+ expect(parsed.usage.cachedInputTokens).toBe(10);
158
+ expect(parsed.usage.costUsd).toBeCloseTo(0.0025, 4);
159
+ });
160
+ it("handles standalone usage events with Pi format", () => {
161
+ const stdout = [
162
+ JSON.stringify({
163
+ type: "usage",
164
+ usage: {
165
+ input: 200,
166
+ output: 100,
167
+ cacheRead: 50,
168
+ cost: { total: 0.005 },
169
+ },
170
+ }),
171
+ ].join("\n");
172
+ const parsed = parsePiJsonl(stdout);
173
+ expect(parsed.usage.inputTokens).toBe(200);
174
+ expect(parsed.usage.outputTokens).toBe(100);
175
+ expect(parsed.usage.cachedInputTokens).toBe(50);
176
+ expect(parsed.usage.costUsd).toBe(0.005);
177
+ });
178
+ it("handles standalone usage events with generic format", () => {
179
+ const stdout = [
180
+ JSON.stringify({
181
+ type: "usage",
182
+ usage: {
183
+ inputTokens: 150,
184
+ outputTokens: 75,
185
+ cachedInputTokens: 25,
186
+ costUsd: 0.003,
187
+ },
188
+ }),
189
+ ].join("\n");
190
+ const parsed = parsePiJsonl(stdout);
191
+ expect(parsed.usage.inputTokens).toBe(150);
192
+ expect(parsed.usage.outputTokens).toBe(75);
193
+ expect(parsed.usage.cachedInputTokens).toBe(25);
194
+ expect(parsed.usage.costUsd).toBe(0.003);
195
+ });
196
+ it("surfaces failed auto-retry exhaustion as an error", () => {
197
+ const stdout = [
198
+ JSON.stringify({
199
+ type: "auto_retry_end",
200
+ success: false,
201
+ attempt: 3,
202
+ finalError: "Cloud Code Assist API error (429): RESOURCE_EXHAUSTED",
203
+ }),
204
+ ].join("\n");
205
+ const parsed = parsePiJsonl(stdout);
206
+ expect(parsed.errors).toEqual(["Cloud Code Assist API error (429): RESOURCE_EXHAUSTED"]);
207
+ });
208
+ it("does not treat successful auto-retry as an error", () => {
209
+ const stdout = [
210
+ JSON.stringify({
211
+ type: "auto_retry_end",
212
+ success: true,
213
+ attempt: 2,
214
+ }),
215
+ ].join("\n");
216
+ const parsed = parsePiJsonl(stdout);
217
+ expect(parsed.errors).toEqual([]);
218
+ });
219
+ it("surfaces standalone error events", () => {
220
+ const stdout = [
221
+ JSON.stringify({
222
+ type: "error",
223
+ message: "Connection to model provider lost",
224
+ }),
225
+ ].join("\n");
226
+ const parsed = parsePiJsonl(stdout);
227
+ expect(parsed.errors).toEqual(["Connection to model provider lost"]);
228
+ });
229
+ it("ignores error events with empty messages", () => {
230
+ const stdout = [
231
+ JSON.stringify({
232
+ type: "error",
233
+ message: "",
234
+ }),
235
+ ].join("\n");
236
+ const parsed = parsePiJsonl(stdout);
237
+ expect(parsed.errors).toEqual([]);
238
+ });
239
+ });
240
+ describe("isPiUnknownSessionError", () => {
241
+ it("detects unknown session errors", () => {
242
+ expect(isPiUnknownSessionError("session not found: s_123", "")).toBe(true);
243
+ expect(isPiUnknownSessionError("", "unknown session id")).toBe(true);
244
+ expect(isPiUnknownSessionError("", "no session available")).toBe(true);
245
+ expect(isPiUnknownSessionError("all good", "")).toBe(false);
246
+ expect(isPiUnknownSessionError("working fine", "no errors")).toBe(false);
247
+ });
248
+ });
249
+ //# sourceMappingURL=parse.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.js","sourceRoot":"","sources":["../../src/server/parse.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { AdapterSkillContext, AdapterSkillSnapshot } from "@paperclipai/adapter-utils";
2
+ export declare function listPiSkills(ctx: AdapterSkillContext): Promise<AdapterSkillSnapshot>;
3
+ export declare function syncPiSkills(ctx: AdapterSkillContext, desiredSkills: string[]): Promise<AdapterSkillSnapshot>;
4
+ export declare function resolvePiDesiredSkillNames(config: Record<string, unknown>, availableEntries: Array<{
5
+ key: string;
6
+ required?: boolean;
7
+ }>): string[];
8
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AA2CpC,wBAAsB,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAE1F;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,mBAAmB,EACxB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,YAG7D"}
@@ -0,0 +1,69 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { buildPersistentSkillSnapshot, ensurePaperclipSkillSymlink, readPaperclipRuntimeSkillEntries, readInstalledSkillTargets, resolvePaperclipDesiredSkillNames, } from "@paperclipai/adapter-utils/server-utils";
6
+ const __moduleDir = path.dirname(fileURLToPath(import.meta.url));
7
+ function asString(value) {
8
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
9
+ }
10
+ function resolvePiSkillsHome(config) {
11
+ const env = typeof config.env === "object" && config.env !== null && !Array.isArray(config.env)
12
+ ? config.env
13
+ : {};
14
+ const configuredHome = asString(env.HOME);
15
+ const home = configuredHome ? path.resolve(configuredHome) : os.homedir();
16
+ return path.join(home, ".pi", "agent", "skills");
17
+ }
18
+ async function buildPiSkillSnapshot(config) {
19
+ const availableEntries = await readPaperclipRuntimeSkillEntries(config, __moduleDir);
20
+ const desiredSkills = resolvePaperclipDesiredSkillNames(config, availableEntries);
21
+ const skillsHome = resolvePiSkillsHome(config);
22
+ const installed = await readInstalledSkillTargets(skillsHome);
23
+ return buildPersistentSkillSnapshot({
24
+ adapterType: "pi_local",
25
+ availableEntries,
26
+ desiredSkills,
27
+ installed,
28
+ skillsHome,
29
+ locationLabel: "~/.pi/agent/skills",
30
+ missingDetail: "Configured but not currently linked into the Pi skills home.",
31
+ externalConflictDetail: "Skill name is occupied by an external installation.",
32
+ externalDetail: "Installed outside Paperclip management.",
33
+ });
34
+ }
35
+ export async function listPiSkills(ctx) {
36
+ return buildPiSkillSnapshot(ctx.config);
37
+ }
38
+ export async function syncPiSkills(ctx, desiredSkills) {
39
+ const availableEntries = await readPaperclipRuntimeSkillEntries(ctx.config, __moduleDir);
40
+ const desiredSet = new Set([
41
+ ...desiredSkills,
42
+ ...availableEntries.filter((entry) => entry.required).map((entry) => entry.key),
43
+ ]);
44
+ const skillsHome = resolvePiSkillsHome(ctx.config);
45
+ await fs.mkdir(skillsHome, { recursive: true });
46
+ const installed = await readInstalledSkillTargets(skillsHome);
47
+ const availableByRuntimeName = new Map(availableEntries.map((entry) => [entry.runtimeName, entry]));
48
+ for (const available of availableEntries) {
49
+ if (!desiredSet.has(available.key))
50
+ continue;
51
+ const target = path.join(skillsHome, available.runtimeName);
52
+ await ensurePaperclipSkillSymlink(available.source, target);
53
+ }
54
+ for (const [name, installedEntry] of installed.entries()) {
55
+ const available = availableByRuntimeName.get(name);
56
+ if (!available)
57
+ continue;
58
+ if (desiredSet.has(available.key))
59
+ continue;
60
+ if (installedEntry.targetPath !== available.source)
61
+ continue;
62
+ await fs.unlink(path.join(skillsHome, name)).catch(() => { });
63
+ }
64
+ return buildPiSkillSnapshot(ctx.config);
65
+ }
66
+ export function resolvePiDesiredSkillNames(config, availableEntries) {
67
+ return resolvePaperclipDesiredSkillNames(config, availableEntries);
68
+ }
69
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AdapterEnvironmentTestContext, AdapterEnvironmentTestResult } from "@paperclipai/adapter-utils";
2
+ export declare function testEnvironment(ctx: AdapterEnvironmentTestContext): Promise<AdapterEnvironmentTestResult>;
3
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/server/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,6BAA6B,EAC7B,4BAA4B,EAC7B,MAAM,4BAA4B,CAAC;AA4EpC,wBAAsB,eAAe,CACnC,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA+PvC"}
@@ -0,0 +1,309 @@
1
+ import { asString, parseObject, ensurePathInEnv, } from "@paperclipai/adapter-utils/server-utils";
2
+ import { asStringArray, } from "@paperclipai/adapter-utils/server-utils";
3
+ import { ensureAdapterExecutionTargetCommandResolvable, maybeRunSandboxInstallCommand, ensureAdapterExecutionTargetDirectory, runAdapterExecutionTargetProcess, describeAdapterExecutionTarget, resolveAdapterExecutionTargetCwd, } from "@paperclipai/adapter-utils/execution-target";
4
+ import { discoverPiModelsCached } from "./models.js";
5
+ import { parsePiJsonl } from "./parse.js";
6
+ import { SANDBOX_INSTALL_COMMAND } from "../index.js";
7
+ function summarizeStatus(checks) {
8
+ if (checks.some((check) => check.level === "error"))
9
+ return "fail";
10
+ if (checks.some((check) => check.level === "warn"))
11
+ return "warn";
12
+ return "pass";
13
+ }
14
+ function firstNonEmptyLine(text) {
15
+ return (text
16
+ .split(/\r?\n/)
17
+ .map((line) => line.trim())
18
+ .find(Boolean) ?? "");
19
+ }
20
+ function summarizeProbeDetail(stdout, stderr, parsedError) {
21
+ const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout);
22
+ if (!raw)
23
+ return null;
24
+ const clean = raw.replace(/\s+/g, " ").trim();
25
+ const max = 240;
26
+ return clean.length > max ? `${clean.slice(0, max - 1)}...` : clean;
27
+ }
28
+ function normalizeEnv(input) {
29
+ if (typeof input !== "object" || input === null || Array.isArray(input))
30
+ return {};
31
+ const env = {};
32
+ for (const [key, value] of Object.entries(input)) {
33
+ if (typeof value === "string")
34
+ env[key] = value;
35
+ }
36
+ return env;
37
+ }
38
+ const PI_AUTH_REQUIRED_RE = /(?:auth(?:entication)?\s+required|api\s*key|invalid\s*api\s*key|not\s+logged\s+in|free\s+usage\s+exceeded)/i;
39
+ const PI_STALE_PACKAGE_RE = /pi-driver|npm:\s*pi-driver/i;
40
+ function buildPiModelDiscoveryFailureCheck(message) {
41
+ if (PI_STALE_PACKAGE_RE.test(message)) {
42
+ return {
43
+ code: "pi_package_install_failed",
44
+ level: "warn",
45
+ message: "Pi startup failed while installing configured package `npm:pi-driver`.",
46
+ detail: message,
47
+ hint: "Remove `npm:pi-driver` from ~/.pi/agent/settings.json or set adapter env HOME to a clean Pi profile, then retry `pi --list-models`.",
48
+ };
49
+ }
50
+ return {
51
+ code: "pi_models_discovery_failed",
52
+ level: "warn",
53
+ message,
54
+ hint: "Run `pi --list-models` manually to verify provider auth and config.",
55
+ };
56
+ }
57
+ export async function testEnvironment(ctx) {
58
+ const checks = [];
59
+ const config = parseObject(ctx.config);
60
+ const command = asString(config.command, "pi");
61
+ const target = ctx.executionTarget ?? null;
62
+ const targetIsRemote = target?.kind === "remote";
63
+ const cwd = resolveAdapterExecutionTargetCwd(target, asString(config.cwd, ""), process.cwd());
64
+ const targetLabel = targetIsRemote
65
+ ? ctx.environmentName ?? describeAdapterExecutionTarget(target)
66
+ : null;
67
+ const runId = `pi-envtest-${Date.now()}-${Math.random().toString(16).slice(2)}`;
68
+ if (targetLabel) {
69
+ checks.push({
70
+ code: "pi_environment_target",
71
+ level: "info",
72
+ message: `Probing inside environment: ${targetLabel}`,
73
+ });
74
+ }
75
+ try {
76
+ await ensureAdapterExecutionTargetDirectory(runId, target, cwd, {
77
+ cwd,
78
+ env: {},
79
+ createIfMissing: false,
80
+ });
81
+ checks.push({
82
+ code: "pi_cwd_valid",
83
+ level: "info",
84
+ message: `Working directory is valid: ${cwd}`,
85
+ });
86
+ }
87
+ catch (err) {
88
+ checks.push({
89
+ code: "pi_cwd_invalid",
90
+ level: "error",
91
+ message: err instanceof Error ? err.message : "Invalid working directory",
92
+ detail: cwd,
93
+ });
94
+ }
95
+ const envConfig = parseObject(config.env);
96
+ const env = {};
97
+ for (const [key, value] of Object.entries(envConfig)) {
98
+ if (typeof value === "string")
99
+ env[key] = value;
100
+ }
101
+ const runtimeEnv = normalizeEnv(ensurePathInEnv({ ...process.env, ...env }));
102
+ const cwdInvalid = checks.some((check) => check.code === "pi_cwd_invalid");
103
+ if (cwdInvalid) {
104
+ checks.push({
105
+ code: "pi_command_skipped",
106
+ level: "warn",
107
+ message: "Skipped command check because working directory validation failed.",
108
+ detail: command,
109
+ });
110
+ }
111
+ else {
112
+ const installCheck = await maybeRunSandboxInstallCommand({
113
+ runId,
114
+ target,
115
+ adapterKey: "pi",
116
+ installCommand: SANDBOX_INSTALL_COMMAND,
117
+ detectCommand: command,
118
+ env,
119
+ });
120
+ if (installCheck)
121
+ checks.push(installCheck);
122
+ try {
123
+ await ensureAdapterExecutionTargetCommandResolvable(command, target, cwd, runtimeEnv);
124
+ checks.push({
125
+ code: "pi_command_resolvable",
126
+ level: "info",
127
+ message: `Command is executable: ${command}`,
128
+ });
129
+ }
130
+ catch (err) {
131
+ checks.push({
132
+ code: "pi_command_unresolvable",
133
+ level: "error",
134
+ message: err instanceof Error ? err.message : "Command is not executable",
135
+ detail: command,
136
+ });
137
+ }
138
+ }
139
+ const canRunProbe = checks.every((check) => check.code !== "pi_cwd_invalid" && check.code !== "pi_command_unresolvable");
140
+ // Pi model discovery shells out to `pi --list-models` locally; when probing a
141
+ // remote target we skip discovery and let the remote hello probe surface
142
+ // model/auth issues directly.
143
+ if (!targetIsRemote && canRunProbe) {
144
+ try {
145
+ const discovered = await discoverPiModelsCached({ command, cwd, env: runtimeEnv });
146
+ if (discovered.length > 0) {
147
+ checks.push({
148
+ code: "pi_models_discovered",
149
+ level: "info",
150
+ message: `Discovered ${discovered.length} model(s) from Pi.`,
151
+ });
152
+ }
153
+ else {
154
+ checks.push({
155
+ code: "pi_models_empty",
156
+ level: "warn",
157
+ message: "Pi returned no models.",
158
+ hint: "Run `pi --list-models` and verify provider authentication.",
159
+ });
160
+ }
161
+ }
162
+ catch (err) {
163
+ checks.push(buildPiModelDiscoveryFailureCheck(err instanceof Error ? err.message : "Pi model discovery failed."));
164
+ }
165
+ }
166
+ const configuredModel = asString(config.model, "").trim();
167
+ if (!configuredModel) {
168
+ checks.push({
169
+ code: "pi_model_required",
170
+ level: "error",
171
+ message: "Pi requires a configured model in provider/model format.",
172
+ hint: "Set adapterConfig.model using an ID from `pi --list-models`.",
173
+ });
174
+ }
175
+ else if (targetIsRemote) {
176
+ checks.push({
177
+ code: "pi_model_validation_skipped_remote",
178
+ level: "info",
179
+ message: `Skipped local model validation; will be validated by the hello probe inside ${targetLabel}.`,
180
+ });
181
+ }
182
+ else if (canRunProbe) {
183
+ // Verify model is in the list
184
+ try {
185
+ const discovered = await discoverPiModelsCached({ command, cwd, env: runtimeEnv });
186
+ const modelExists = discovered.some((m) => m.id === configuredModel);
187
+ if (modelExists) {
188
+ checks.push({
189
+ code: "pi_model_configured",
190
+ level: "info",
191
+ message: `Configured model: ${configuredModel}`,
192
+ });
193
+ }
194
+ else {
195
+ checks.push({
196
+ code: "pi_model_not_found",
197
+ level: "warn",
198
+ message: `Configured model "${configuredModel}" not found in available models.`,
199
+ hint: "Run `pi --list-models` and choose a currently available provider/model ID.",
200
+ });
201
+ }
202
+ }
203
+ catch {
204
+ // If we can't verify, just note it
205
+ checks.push({
206
+ code: "pi_model_configured",
207
+ level: "info",
208
+ message: `Configured model: ${configuredModel}`,
209
+ });
210
+ }
211
+ }
212
+ if (canRunProbe && configuredModel) {
213
+ // Parse model for probe
214
+ const provider = configuredModel.includes("/")
215
+ ? configuredModel.slice(0, configuredModel.indexOf("/"))
216
+ : "";
217
+ const modelId = configuredModel.includes("/")
218
+ ? configuredModel.slice(configuredModel.indexOf("/") + 1)
219
+ : configuredModel;
220
+ const thinking = asString(config.thinking, "").trim();
221
+ const extraArgs = (() => {
222
+ const fromExtraArgs = asStringArray(config.extraArgs);
223
+ if (fromExtraArgs.length > 0)
224
+ return fromExtraArgs;
225
+ return asStringArray(config.args);
226
+ })();
227
+ const args = ["-p", "Respond with hello.", "--mode", "json"];
228
+ if (provider)
229
+ args.push("--provider", provider);
230
+ if (modelId)
231
+ args.push("--model", modelId);
232
+ if (thinking)
233
+ args.push("--thinking", thinking);
234
+ args.push("--tools", "read");
235
+ if (extraArgs.length > 0)
236
+ args.push(...extraArgs);
237
+ try {
238
+ const probe = await runAdapterExecutionTargetProcess(runId, target, command, args, {
239
+ cwd,
240
+ env: runtimeEnv,
241
+ timeoutSec: 60,
242
+ graceSec: 5,
243
+ onLog: async () => { },
244
+ });
245
+ const parsed = parsePiJsonl(probe.stdout);
246
+ const detail = summarizeProbeDetail(probe.stdout, probe.stderr, parsed.errors[0] ?? null);
247
+ const authEvidence = `${parsed.errors.join("\n")}\n${probe.stdout}\n${probe.stderr}`.trim();
248
+ if (probe.timedOut) {
249
+ checks.push({
250
+ code: "pi_hello_probe_timed_out",
251
+ level: "warn",
252
+ message: "Pi hello probe timed out.",
253
+ hint: "Retry the probe. If this persists, run Pi manually in this working directory.",
254
+ });
255
+ }
256
+ else if ((probe.exitCode ?? 1) === 0 && parsed.errors.length === 0) {
257
+ const summary = (parsed.finalMessage || parsed.messages.join(" ")).trim();
258
+ const hasHello = /\bhello\b/i.test(summary);
259
+ checks.push({
260
+ code: hasHello ? "pi_hello_probe_passed" : "pi_hello_probe_unexpected_output",
261
+ level: hasHello ? "info" : "warn",
262
+ message: hasHello
263
+ ? "Pi hello probe succeeded."
264
+ : "Pi probe ran but did not return `hello` as expected.",
265
+ ...(summary ? { detail: summary.replace(/\s+/g, " ").trim().slice(0, 240) } : {}),
266
+ ...(hasHello
267
+ ? {}
268
+ : {
269
+ hint: "Run `pi --mode json` manually and prompt `Respond with hello` to inspect output.",
270
+ }),
271
+ });
272
+ }
273
+ else if (PI_AUTH_REQUIRED_RE.test(authEvidence)) {
274
+ checks.push({
275
+ code: "pi_hello_probe_auth_required",
276
+ level: "warn",
277
+ message: "Pi is installed, but provider authentication is not ready.",
278
+ ...(detail ? { detail } : {}),
279
+ hint: "Set provider API key environment variable (e.g., ANTHROPIC_API_KEY, XAI_API_KEY) and retry.",
280
+ });
281
+ }
282
+ else {
283
+ checks.push({
284
+ code: "pi_hello_probe_failed",
285
+ level: "error",
286
+ message: "Pi hello probe failed.",
287
+ ...(detail ? { detail } : {}),
288
+ hint: "Run `pi --mode json` manually in this working directory to debug.",
289
+ });
290
+ }
291
+ }
292
+ catch (err) {
293
+ checks.push({
294
+ code: "pi_hello_probe_failed",
295
+ level: "error",
296
+ message: "Pi hello probe failed.",
297
+ detail: err instanceof Error ? err.message : String(err),
298
+ hint: "Run `pi --mode json` manually in this working directory to debug.",
299
+ });
300
+ }
301
+ }
302
+ return {
303
+ adapterType: ctx.adapterType,
304
+ status: summarizeStatus(checks),
305
+ checks,
306
+ testedAt: new Date().toISOString(),
307
+ };
308
+ }
309
+ //# sourceMappingURL=test.js.map