@evermore.work/adapter-opencode-local 2026.509.0-canary.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 (69) hide show
  1. package/dist/cli/format-event.d.ts +2 -0
  2. package/dist/cli/format-event.d.ts.map +1 -0
  3. package/dist/cli/format-event.js +115 -0
  4. package/dist/cli/format-event.js.map +1 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +2 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/index.d.ts +13 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +73 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/server/execute.d.ts +3 -0
  14. package/dist/server/execute.d.ts.map +1 -0
  15. package/dist/server/execute.js +520 -0
  16. package/dist/server/execute.js.map +1 -0
  17. package/dist/server/execute.remote.test.d.ts +2 -0
  18. package/dist/server/execute.remote.test.d.ts.map +1 -0
  19. package/dist/server/execute.remote.test.js +317 -0
  20. package/dist/server/execute.remote.test.js.map +1 -0
  21. package/dist/server/index.d.ts +8 -0
  22. package/dist/server/index.d.ts.map +1 -0
  23. package/dist/server/index.js +63 -0
  24. package/dist/server/index.js.map +1 -0
  25. package/dist/server/models.d.ts +22 -0
  26. package/dist/server/models.d.ts.map +1 -0
  27. package/dist/server/models.js +171 -0
  28. package/dist/server/models.js.map +1 -0
  29. package/dist/server/models.test.d.ts +2 -0
  30. package/dist/server/models.test.d.ts.map +1 -0
  31. package/dist/server/models.test.js +29 -0
  32. package/dist/server/models.test.js.map +1 -0
  33. package/dist/server/parse.d.ts +14 -0
  34. package/dist/server/parse.d.ts.map +1 -0
  35. package/dist/server/parse.js +99 -0
  36. package/dist/server/parse.js.map +1 -0
  37. package/dist/server/parse.test.d.ts +2 -0
  38. package/dist/server/parse.test.d.ts.map +1 -0
  39. package/dist/server/parse.test.js +73 -0
  40. package/dist/server/parse.test.js.map +1 -0
  41. package/dist/server/runtime-config.d.ts +12 -0
  42. package/dist/server/runtime-config.d.ts.map +1 -0
  43. package/dist/server/runtime-config.js +87 -0
  44. package/dist/server/runtime-config.js.map +1 -0
  45. package/dist/server/runtime-config.test.d.ts +2 -0
  46. package/dist/server/runtime-config.test.d.ts.map +1 -0
  47. package/dist/server/runtime-config.test.js +60 -0
  48. package/dist/server/runtime-config.test.js.map +1 -0
  49. package/dist/server/skills.d.ts +8 -0
  50. package/dist/server/skills.d.ts.map +1 -0
  51. package/dist/server/skills.js +73 -0
  52. package/dist/server/skills.js.map +1 -0
  53. package/dist/server/test.d.ts +3 -0
  54. package/dist/server/test.d.ts.map +1 -0
  55. package/dist/server/test.js +358 -0
  56. package/dist/server/test.js.map +1 -0
  57. package/dist/ui/build-config.d.ts +3 -0
  58. package/dist/ui/build-config.d.ts.map +1 -0
  59. package/dist/ui/build-config.js +84 -0
  60. package/dist/ui/build-config.js.map +1 -0
  61. package/dist/ui/index.d.ts +3 -0
  62. package/dist/ui/index.d.ts.map +1 -0
  63. package/dist/ui/index.js +3 -0
  64. package/dist/ui/index.js.map +1 -0
  65. package/dist/ui/parse-stdout.d.ts +3 -0
  66. package/dist/ui/parse-stdout.d.ts.map +1 -0
  67. package/dist/ui/parse-stdout.js +141 -0
  68. package/dist/ui/parse-stdout.js.map +1 -0
  69. package/package.json +54 -0
@@ -0,0 +1,29 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { ensureOpenCodeModelConfiguredAndAvailable, listOpenCodeModels, requireOpenCodeModelId, resetOpenCodeModelsCacheForTests, } from "./models.js";
3
+ describe("openCode models", () => {
4
+ afterEach(() => {
5
+ delete process.env.EVERMORE_OPENCODE_COMMAND;
6
+ resetOpenCodeModelsCacheForTests();
7
+ });
8
+ it("returns an empty list when discovery command is unavailable", async () => {
9
+ process.env.EVERMORE_OPENCODE_COMMAND = "__evermore_missing_opencode_command__";
10
+ await expect(listOpenCodeModels()).resolves.toEqual([]);
11
+ });
12
+ it("rejects when model is missing", async () => {
13
+ await expect(ensureOpenCodeModelConfiguredAndAvailable({ model: "" })).rejects.toThrow("OpenCode requires `adapterConfig.model`");
14
+ });
15
+ it("accepts a provider/model id without running discovery", () => {
16
+ expect(requireOpenCodeModelId("openai/gpt-5.2-codex")).toBe("openai/gpt-5.2-codex");
17
+ });
18
+ it("rejects malformed provider/model ids before discovery", () => {
19
+ expect(() => requireOpenCodeModelId("gpt-5.2-codex")).toThrow("OpenCode requires `adapterConfig.model`");
20
+ expect(() => requireOpenCodeModelId("openai/")).toThrow("OpenCode requires `adapterConfig.model`");
21
+ });
22
+ it("rejects when discovery cannot run for configured model", async () => {
23
+ process.env.EVERMORE_OPENCODE_COMMAND = "__evermore_missing_opencode_command__";
24
+ await expect(ensureOpenCodeModelConfiguredAndAvailable({
25
+ model: "openai/gpt-5",
26
+ })).rejects.toThrow("Failed to start command");
27
+ });
28
+ });
29
+ //# sourceMappingURL=models.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.test.js","sourceRoot":"","sources":["../../src/server/models.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EACL,yCAAyC,EACzC,kBAAkB,EAClB,sBAAsB,EACtB,gCAAgC,GACjC,MAAM,aAAa,CAAC;AAErB,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;QAC7C,gCAAgC,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,uCAAuC,CAAC;QAChF,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,MAAM,CACV,yCAAyC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CACzD,CAAC,OAAO,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAC3D,yCAAyC,CAC1C,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CACrD,yCAAyC,CAC1C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,uCAAuC,CAAC;QAChF,MAAM,MAAM,CACV,yCAAyC,CAAC;YACxC,KAAK,EAAE,cAAc;SACtB,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export declare function parseOpenCodeJsonl(stdout: string): {
2
+ sessionId: string | null;
3
+ summary: string;
4
+ usage: {
5
+ inputTokens: number;
6
+ cachedInputTokens: number;
7
+ outputTokens: number;
8
+ };
9
+ costUsd: number;
10
+ errorMessage: string | null;
11
+ toolErrors: string[];
12
+ };
13
+ export declare function isOpenCodeUnknownSessionError(stdout: string, stderr: string): boolean;
14
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/server/parse.ts"],"names":[],"mappings":"AAqBA,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;EAmEhD;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAUrF"}
@@ -0,0 +1,99 @@
1
+ import { asNumber, asString, parseJson, parseObject } from "@evermore.work/adapter-utils/server-utils";
2
+ function errorText(value) {
3
+ if (typeof value === "string")
4
+ return value;
5
+ const rec = parseObject(value);
6
+ const message = asString(rec.message, "").trim();
7
+ if (message)
8
+ return message;
9
+ const data = parseObject(rec.data);
10
+ const nestedMessage = asString(data.message, "").trim();
11
+ if (nestedMessage)
12
+ return nestedMessage;
13
+ const name = asString(rec.name, "").trim();
14
+ if (name)
15
+ return name;
16
+ const code = asString(rec.code, "").trim();
17
+ if (code)
18
+ return code;
19
+ try {
20
+ return JSON.stringify(rec);
21
+ }
22
+ catch {
23
+ return "";
24
+ }
25
+ }
26
+ export function parseOpenCodeJsonl(stdout) {
27
+ let sessionId = null;
28
+ const messages = [];
29
+ const errors = [];
30
+ const toolErrors = [];
31
+ const usage = {
32
+ inputTokens: 0,
33
+ cachedInputTokens: 0,
34
+ outputTokens: 0,
35
+ };
36
+ let costUsd = 0;
37
+ for (const rawLine of stdout.split(/\r?\n/)) {
38
+ const line = rawLine.trim();
39
+ if (!line)
40
+ continue;
41
+ const event = parseJson(line);
42
+ if (!event)
43
+ continue;
44
+ const currentSessionId = asString(event.sessionID, "").trim();
45
+ if (currentSessionId)
46
+ sessionId = currentSessionId;
47
+ const type = asString(event.type, "");
48
+ if (type === "text") {
49
+ const part = parseObject(event.part);
50
+ const text = asString(part.text, "").trim();
51
+ if (text)
52
+ messages.push(text);
53
+ continue;
54
+ }
55
+ if (type === "step_finish") {
56
+ const part = parseObject(event.part);
57
+ const tokens = parseObject(part.tokens);
58
+ const cache = parseObject(tokens.cache);
59
+ usage.inputTokens += asNumber(tokens.input, 0);
60
+ usage.cachedInputTokens += asNumber(cache.read, 0);
61
+ usage.outputTokens += asNumber(tokens.output, 0) + asNumber(tokens.reasoning, 0);
62
+ costUsd += asNumber(part.cost, 0);
63
+ continue;
64
+ }
65
+ if (type === "tool_use") {
66
+ const part = parseObject(event.part);
67
+ const state = parseObject(part.state);
68
+ if (asString(state.status, "") === "error") {
69
+ const text = asString(state.error, "").trim();
70
+ if (text)
71
+ toolErrors.push(text);
72
+ }
73
+ continue;
74
+ }
75
+ if (type === "error") {
76
+ const text = errorText(event.error ?? event.message).trim();
77
+ if (text)
78
+ errors.push(text);
79
+ continue;
80
+ }
81
+ }
82
+ return {
83
+ sessionId,
84
+ summary: messages.join("\n\n").trim(),
85
+ usage,
86
+ costUsd,
87
+ errorMessage: errors.length > 0 ? errors.join("\n") : null,
88
+ toolErrors,
89
+ };
90
+ }
91
+ export function isOpenCodeUnknownSessionError(stdout, stderr) {
92
+ const haystack = `${stdout}\n${stderr}`
93
+ .split(/\r?\n/)
94
+ .map((line) => line.trim())
95
+ .filter(Boolean)
96
+ .join("\n");
97
+ return /unknown\s+session|session\b.*\bnot\s+found|resource\s+not\s+found:.*[\\/]session[\\/].*\.json|notfounderror|no session/i.test(haystack);
98
+ }
99
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/server/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAEvG,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG;QACZ,WAAW,EAAE,CAAC;QACd,iBAAiB,EAAE,CAAC;QACpB,YAAY,EAAE,CAAC;KAChB,CAAC;IACF,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK;YAAE,SAAS;QAErB,MAAM,gBAAgB,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9D,IAAI,gBAAgB;YAAE,SAAS,GAAG,gBAAgB,CAAC;QAEnD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAEtC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxC,KAAK,CAAC,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC/C,KAAK,CAAC,iBAAiB,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACnD,KAAK,CAAC,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACjF,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC;gBAC3C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC9C,IAAI,IAAI;oBAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5D,IAAI,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS;QACT,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;QACrC,KAAK;QACL,OAAO;QACP,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;QAC1D,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,MAAc,EAAE,MAAc;IAC1E,MAAM,QAAQ,GAAG,GAAG,MAAM,KAAK,MAAM,EAAE;SACpC,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,yHAAyH,CAAC,IAAI,CACnI,QAAQ,CACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parse.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.d.ts","sourceRoot":"","sources":["../../src/server/parse.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parseOpenCodeJsonl, isOpenCodeUnknownSessionError } from "./parse.js";
3
+ describe("parseOpenCodeJsonl", () => {
4
+ it("parses assistant text, usage, cost, and errors", () => {
5
+ const stdout = [
6
+ JSON.stringify({
7
+ type: "text",
8
+ sessionID: "session_123",
9
+ part: { text: "Hello from OpenCode" },
10
+ }),
11
+ JSON.stringify({
12
+ type: "step_finish",
13
+ sessionID: "session_123",
14
+ part: {
15
+ reason: "done",
16
+ cost: 0.0025,
17
+ tokens: {
18
+ input: 120,
19
+ output: 40,
20
+ reasoning: 10,
21
+ cache: { read: 20, write: 0 },
22
+ },
23
+ },
24
+ }),
25
+ JSON.stringify({
26
+ type: "error",
27
+ sessionID: "session_123",
28
+ error: { message: "model unavailable" },
29
+ }),
30
+ ].join("\n");
31
+ const parsed = parseOpenCodeJsonl(stdout);
32
+ expect(parsed.sessionId).toBe("session_123");
33
+ expect(parsed.summary).toBe("Hello from OpenCode");
34
+ expect(parsed.usage).toEqual({
35
+ inputTokens: 120,
36
+ cachedInputTokens: 20,
37
+ outputTokens: 50,
38
+ });
39
+ expect(parsed.costUsd).toBeCloseTo(0.0025, 6);
40
+ expect(parsed.errorMessage).toContain("model unavailable");
41
+ expect(parsed.toolErrors).toEqual([]);
42
+ });
43
+ it("keeps failed tool calls separate from fatal run errors", () => {
44
+ const stdout = [
45
+ JSON.stringify({
46
+ type: "tool_use",
47
+ sessionID: "session_123",
48
+ part: {
49
+ state: {
50
+ status: "error",
51
+ error: "File not found: e2b-adapter-result.txt",
52
+ },
53
+ },
54
+ }),
55
+ JSON.stringify({
56
+ type: "text",
57
+ sessionID: "session_123",
58
+ part: { text: "Recovered and completed the task" },
59
+ }),
60
+ ].join("\n");
61
+ const parsed = parseOpenCodeJsonl(stdout);
62
+ expect(parsed.sessionId).toBe("session_123");
63
+ expect(parsed.summary).toBe("Recovered and completed the task");
64
+ expect(parsed.errorMessage).toBeNull();
65
+ expect(parsed.toolErrors).toEqual(["File not found: e2b-adapter-result.txt"]);
66
+ });
67
+ it("detects unknown session errors", () => {
68
+ expect(isOpenCodeUnknownSessionError("Session not found: s_123", "")).toBe(true);
69
+ expect(isOpenCodeUnknownSessionError("", "unknown session id")).toBe(true);
70
+ expect(isOpenCodeUnknownSessionError("all good", "")).toBe(false);
71
+ });
72
+ });
73
+ //# 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,12 @@
1
+ type PreparedOpenCodeRuntimeConfig = {
2
+ env: Record<string, string>;
3
+ notes: string[];
4
+ cleanup: () => Promise<void>;
5
+ };
6
+ export declare function prepareOpenCodeRuntimeConfig(input: {
7
+ env: Record<string, string>;
8
+ config: Record<string, unknown>;
9
+ targetIsRemote?: boolean;
10
+ }): Promise<PreparedOpenCodeRuntimeConfig>;
11
+ export {};
12
+ //# sourceMappingURL=runtime-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-config.d.ts","sourceRoot":"","sources":["../../src/server/runtime-config.ts"],"names":[],"mappings":"AAKA,KAAK,6BAA6B,GAAG;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAwBF,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAmEzC"}
@@ -0,0 +1,87 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { asBoolean } from "@evermore.work/adapter-utils/server-utils";
5
+ function resolveXdgConfigHome(env) {
6
+ return ((typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim()) ||
7
+ (typeof process.env.XDG_CONFIG_HOME === "string" && process.env.XDG_CONFIG_HOME.trim()) ||
8
+ path.join(os.homedir(), ".config"));
9
+ }
10
+ function isPlainObject(value) {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+ async function readJsonObject(filepath) {
14
+ try {
15
+ const raw = await fs.readFile(filepath, "utf8");
16
+ const parsed = JSON.parse(raw);
17
+ return isPlainObject(parsed) ? parsed : {};
18
+ }
19
+ catch {
20
+ return {};
21
+ }
22
+ }
23
+ export async function prepareOpenCodeRuntimeConfig(input) {
24
+ const skipPermissions = asBoolean(input.config.dangerouslySkipPermissions, true);
25
+ if (!skipPermissions) {
26
+ return {
27
+ env: input.env,
28
+ notes: [],
29
+ cleanup: async () => { },
30
+ };
31
+ }
32
+ // For remote execution targets the host XDG_CONFIG_HOME path is meaningless
33
+ // (and actively harmful — it leaks a macOS-only path into the remote Linux
34
+ // env). Callers that need to ship a runtime opencode config to the remote
35
+ // box do that via prepareAdapterExecutionTargetRuntime in execute.ts; this
36
+ // host-fs helper is local-only.
37
+ if (input.targetIsRemote) {
38
+ return {
39
+ env: input.env,
40
+ notes: [],
41
+ cleanup: async () => { },
42
+ };
43
+ }
44
+ const sourceConfigDir = path.join(resolveXdgConfigHome(input.env), "opencode");
45
+ const runtimeConfigHome = await fs.mkdtemp(path.join(os.tmpdir(), "evermore-opencode-config-"));
46
+ const runtimeConfigDir = path.join(runtimeConfigHome, "opencode");
47
+ const runtimeConfigPath = path.join(runtimeConfigDir, "opencode.json");
48
+ await fs.mkdir(runtimeConfigDir, { recursive: true });
49
+ try {
50
+ await fs.cp(sourceConfigDir, runtimeConfigDir, {
51
+ recursive: true,
52
+ force: true,
53
+ errorOnExist: false,
54
+ dereference: false,
55
+ });
56
+ }
57
+ catch (err) {
58
+ if (err?.code !== "ENOENT") {
59
+ throw err;
60
+ }
61
+ }
62
+ const existingConfig = await readJsonObject(runtimeConfigPath);
63
+ const existingPermission = isPlainObject(existingConfig.permission)
64
+ ? existingConfig.permission
65
+ : {};
66
+ const nextConfig = {
67
+ ...existingConfig,
68
+ permission: {
69
+ ...existingPermission,
70
+ external_directory: "allow",
71
+ },
72
+ };
73
+ await fs.writeFile(runtimeConfigPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
74
+ return {
75
+ env: {
76
+ ...input.env,
77
+ XDG_CONFIG_HOME: runtimeConfigHome,
78
+ },
79
+ notes: [
80
+ "Injected runtime OpenCode config with permission.external_directory=allow to avoid headless approval prompts.",
81
+ ],
82
+ cleanup: async () => {
83
+ await fs.rm(runtimeConfigHome, { recursive: true, force: true });
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=runtime-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-config.js","sourceRoot":"","sources":["../../src/server/runtime-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-config.test.d.ts","sourceRoot":"","sources":["../../src/server/runtime-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { prepareOpenCodeRuntimeConfig } from "./runtime-config.js";
6
+ const cleanupPaths = new Set();
7
+ afterEach(async () => {
8
+ await Promise.all([...cleanupPaths].map(async (filepath) => {
9
+ await fs.rm(filepath, { recursive: true, force: true });
10
+ cleanupPaths.delete(filepath);
11
+ }));
12
+ });
13
+ async function makeConfigHome(initialConfig) {
14
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "evermore-opencode-test-"));
15
+ cleanupPaths.add(root);
16
+ const configDir = path.join(root, "opencode");
17
+ await fs.mkdir(configDir, { recursive: true });
18
+ if (initialConfig) {
19
+ await fs.writeFile(path.join(configDir, "opencode.json"), `${JSON.stringify(initialConfig, null, 2)}\n`, "utf8");
20
+ }
21
+ return root;
22
+ }
23
+ describe("prepareOpenCodeRuntimeConfig", () => {
24
+ it("injects an external_directory allow rule by default", async () => {
25
+ const configHome = await makeConfigHome({
26
+ permission: {
27
+ read: "allow",
28
+ },
29
+ theme: "system",
30
+ });
31
+ const prepared = await prepareOpenCodeRuntimeConfig({
32
+ env: { XDG_CONFIG_HOME: configHome },
33
+ config: {},
34
+ });
35
+ cleanupPaths.add(prepared.env.XDG_CONFIG_HOME);
36
+ expect(prepared.env.XDG_CONFIG_HOME).not.toBe(configHome);
37
+ const runtimeConfig = JSON.parse(await fs.readFile(path.join(prepared.env.XDG_CONFIG_HOME, "opencode", "opencode.json"), "utf8"));
38
+ expect(runtimeConfig).toMatchObject({
39
+ theme: "system",
40
+ permission: {
41
+ read: "allow",
42
+ external_directory: "allow",
43
+ },
44
+ });
45
+ await prepared.cleanup();
46
+ cleanupPaths.delete(prepared.env.XDG_CONFIG_HOME);
47
+ await expect(fs.access(prepared.env.XDG_CONFIG_HOME)).rejects.toThrow();
48
+ });
49
+ it("respects explicit opt-out", async () => {
50
+ const configHome = await makeConfigHome();
51
+ const prepared = await prepareOpenCodeRuntimeConfig({
52
+ env: { XDG_CONFIG_HOME: configHome },
53
+ config: { dangerouslySkipPermissions: false },
54
+ });
55
+ expect(prepared.env).toEqual({ XDG_CONFIG_HOME: configHome });
56
+ expect(prepared.notes).toEqual([]);
57
+ await prepared.cleanup();
58
+ });
59
+ });
60
+ //# sourceMappingURL=runtime-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-config.test.js","sourceRoot":"","sources":["../../src/server/runtime-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { AdapterSkillContext, AdapterSkillSnapshot } from "@evermore.work/adapter-utils";
2
+ export declare function listOpenCodeSkills(ctx: AdapterSkillContext): Promise<AdapterSkillSnapshot>;
3
+ export declare function syncOpenCodeSkills(ctx: AdapterSkillContext, desiredSkills: string[]): Promise<AdapterSkillSnapshot>;
4
+ export declare function resolveOpenCodeDesiredSkillNames(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,8BAA8B,CAAC;AA+CtC,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAEhG;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,mBAAmB,EACxB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAED,wBAAgB,gCAAgC,CAC9C,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,73 @@
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, ensureEvermoreSkillSymlink, readEvermoreRuntimeSkillEntries, readInstalledSkillTargets, resolveEvermoreDesiredSkillNames, } from "@evermore.work/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 resolveOpenCodeSkillsHome(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, ".claude", "skills");
17
+ }
18
+ async function buildOpenCodeSkillSnapshot(config) {
19
+ const availableEntries = await readEvermoreRuntimeSkillEntries(config, __moduleDir);
20
+ const desiredSkills = resolveEvermoreDesiredSkillNames(config, availableEntries);
21
+ const skillsHome = resolveOpenCodeSkillsHome(config);
22
+ const installed = await readInstalledSkillTargets(skillsHome);
23
+ return buildPersistentSkillSnapshot({
24
+ adapterType: "opencode_local",
25
+ availableEntries,
26
+ desiredSkills,
27
+ installed,
28
+ skillsHome,
29
+ locationLabel: "~/.claude/skills",
30
+ installedDetail: "Installed in the shared Claude/OpenCode skills home.",
31
+ missingDetail: "Configured but not currently linked into the shared Claude/OpenCode skills home.",
32
+ externalConflictDetail: "Skill name is occupied by an external installation in the shared skills home.",
33
+ externalDetail: "Installed outside Evermore management in the shared skills home.",
34
+ warnings: [
35
+ "OpenCode currently uses the shared Claude skills home (~/.claude/skills).",
36
+ ],
37
+ });
38
+ }
39
+ export async function listOpenCodeSkills(ctx) {
40
+ return buildOpenCodeSkillSnapshot(ctx.config);
41
+ }
42
+ export async function syncOpenCodeSkills(ctx, desiredSkills) {
43
+ const availableEntries = await readEvermoreRuntimeSkillEntries(ctx.config, __moduleDir);
44
+ const desiredSet = new Set([
45
+ ...desiredSkills,
46
+ ...availableEntries.filter((entry) => entry.required).map((entry) => entry.key),
47
+ ]);
48
+ const skillsHome = resolveOpenCodeSkillsHome(ctx.config);
49
+ await fs.mkdir(skillsHome, { recursive: true });
50
+ const installed = await readInstalledSkillTargets(skillsHome);
51
+ const availableByRuntimeName = new Map(availableEntries.map((entry) => [entry.runtimeName, entry]));
52
+ for (const available of availableEntries) {
53
+ if (!desiredSet.has(available.key))
54
+ continue;
55
+ const target = path.join(skillsHome, available.runtimeName);
56
+ await ensureEvermoreSkillSymlink(available.source, target);
57
+ }
58
+ for (const [name, installedEntry] of installed.entries()) {
59
+ const available = availableByRuntimeName.get(name);
60
+ if (!available)
61
+ continue;
62
+ if (desiredSet.has(available.key))
63
+ continue;
64
+ if (installedEntry.targetPath !== available.source)
65
+ continue;
66
+ await fs.unlink(path.join(skillsHome, name)).catch(() => { });
67
+ }
68
+ return buildOpenCodeSkillSnapshot(ctx.config);
69
+ }
70
+ export function resolveOpenCodeDesiredSkillNames(config, availableEntries) {
71
+ return resolveEvermoreDesiredSkillNames(config, availableEntries);
72
+ }
73
+ //# 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 "@evermore.work/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,8BAA8B,CAAC;AAwDtC,wBAAsB,eAAe,CACnC,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA8TvC"}