subharness 0.0.4 → 0.0.5

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 (188) hide show
  1. package/README.md +36 -6
  2. package/dist/adapters/claude-process.d.ts +3 -0
  3. package/dist/adapters/claude-process.js +11 -1
  4. package/dist/adapters/claude-process.js.map +1 -1
  5. package/dist/adapters/claude-result.d.ts +2 -0
  6. package/dist/adapters/claude-result.js +22 -0
  7. package/dist/adapters/claude-result.js.map +1 -0
  8. package/dist/adapters/claude.js +30 -11
  9. package/dist/adapters/claude.js.map +1 -1
  10. package/dist/adapters/codex.js +4 -1
  11. package/dist/adapters/codex.js.map +1 -1
  12. package/dist/adapters/copilot-permissions.d.ts +26 -0
  13. package/dist/adapters/copilot-permissions.js +121 -0
  14. package/dist/adapters/copilot-permissions.js.map +1 -0
  15. package/dist/adapters/copilot-tools.d.ts +12 -0
  16. package/dist/adapters/copilot-tools.js +61 -0
  17. package/dist/adapters/copilot-tools.js.map +1 -0
  18. package/dist/adapters/copilot.d.ts +108 -0
  19. package/dist/adapters/copilot.js +819 -0
  20. package/dist/adapters/copilot.js.map +1 -0
  21. package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
  22. package/dist/adapters/cursor-cli-approvals.js +83 -0
  23. package/dist/adapters/cursor-cli-approvals.js.map +1 -0
  24. package/dist/adapters/cursor-cli-model.d.ts +4 -0
  25. package/dist/adapters/cursor-cli-model.js +64 -0
  26. package/dist/adapters/cursor-cli-model.js.map +1 -0
  27. package/dist/adapters/cursor-cli-session.d.ts +32 -0
  28. package/dist/adapters/cursor-cli-session.js +316 -0
  29. package/dist/adapters/cursor-cli-session.js.map +1 -0
  30. package/dist/adapters/cursor-cli-tools.d.ts +20 -0
  31. package/dist/adapters/cursor-cli-tools.js +181 -0
  32. package/dist/adapters/cursor-cli-tools.js.map +1 -0
  33. package/dist/adapters/cursor-cli.d.ts +2 -0
  34. package/dist/adapters/cursor-cli.js +306 -0
  35. package/dist/adapters/cursor-cli.js.map +1 -0
  36. package/dist/adapters/cursor-model.d.ts +7 -0
  37. package/dist/adapters/cursor-model.js +67 -0
  38. package/dist/adapters/cursor-model.js.map +1 -0
  39. package/dist/adapters/cursor-rpc.d.ts +42 -0
  40. package/dist/adapters/cursor-rpc.js +271 -0
  41. package/dist/adapters/cursor-rpc.js.map +1 -0
  42. package/dist/adapters/cursor-session.d.ts +4 -0
  43. package/dist/adapters/cursor-session.js +327 -0
  44. package/dist/adapters/cursor-session.js.map +1 -0
  45. package/dist/adapters/cursor-startup.d.ts +16 -0
  46. package/dist/adapters/cursor-startup.js +74 -0
  47. package/dist/adapters/cursor-startup.js.map +1 -0
  48. package/dist/adapters/cursor-tools.d.ts +11 -0
  49. package/dist/adapters/cursor-tools.js +49 -0
  50. package/dist/adapters/cursor-tools.js.map +1 -0
  51. package/dist/adapters/cursor.d.ts +6 -0
  52. package/dist/adapters/cursor.js +17 -0
  53. package/dist/adapters/cursor.js.map +1 -0
  54. package/dist/adapters/fx-auth.d.ts +12 -2
  55. package/dist/adapters/fx-auth.js +51 -61
  56. package/dist/adapters/fx-auth.js.map +1 -1
  57. package/dist/adapters/fx-profile.d.ts +8 -0
  58. package/dist/adapters/fx-profile.js +101 -0
  59. package/dist/adapters/fx-profile.js.map +1 -0
  60. package/dist/adapters/fx-rpc.d.ts +2 -0
  61. package/dist/adapters/fx-rpc.js +30 -4
  62. package/dist/adapters/fx-rpc.js.map +1 -1
  63. package/dist/adapters/fx-status.d.ts +2 -0
  64. package/dist/adapters/fx-status.js +96 -0
  65. package/dist/adapters/fx-status.js.map +1 -0
  66. package/dist/adapters/fx.js +28 -12
  67. package/dist/adapters/fx.js.map +1 -1
  68. package/dist/adapters/opencode-access.d.ts +13 -0
  69. package/dist/adapters/opencode-access.js +76 -0
  70. package/dist/adapters/opencode-access.js.map +1 -0
  71. package/dist/adapters/opencode-config.d.ts +11 -0
  72. package/dist/adapters/opencode-config.js +238 -0
  73. package/dist/adapters/opencode-config.js.map +1 -0
  74. package/dist/adapters/opencode-http.d.ts +28 -0
  75. package/dist/adapters/opencode-http.js +297 -0
  76. package/dist/adapters/opencode-http.js.map +1 -0
  77. package/dist/adapters/opencode-tools.d.ts +19 -0
  78. package/dist/adapters/opencode-tools.js +127 -0
  79. package/dist/adapters/opencode-tools.js.map +1 -0
  80. package/dist/adapters/opencode.d.ts +2 -0
  81. package/dist/adapters/opencode.js +569 -0
  82. package/dist/adapters/opencode.js.map +1 -0
  83. package/dist/adapters/rpc.d.ts +3 -0
  84. package/dist/adapters/rpc.js +45 -4
  85. package/dist/adapters/rpc.js.map +1 -1
  86. package/dist/adapters/types.d.ts +5 -0
  87. package/dist/adapters/types.js.map +1 -1
  88. package/dist/approvals/types.d.ts +1 -1
  89. package/dist/approvals/types.js.map +1 -1
  90. package/dist/cli/args.d.ts +1 -1
  91. package/dist/cli/args.js +4 -1
  92. package/dist/cli/args.js.map +1 -1
  93. package/dist/cli/dashboard-client.js +1 -1
  94. package/dist/cli/dashboard-client.js.map +1 -1
  95. package/dist/cli/dashboard-controller.d.ts +7 -0
  96. package/dist/cli/dashboard-controller.js +27 -0
  97. package/dist/cli/dashboard-controller.js.map +1 -0
  98. package/dist/cli/dashboard-detail-view.d.ts +1 -1
  99. package/dist/cli/dashboard-detail-view.js +3 -4
  100. package/dist/cli/dashboard-detail-view.js.map +1 -1
  101. package/dist/cli/dashboard-history-view.js.map +1 -1
  102. package/dist/cli/dashboard-input.d.ts +1 -1
  103. package/dist/cli/dashboard-input.js +11 -1
  104. package/dist/cli/dashboard-input.js.map +1 -1
  105. package/dist/cli/dashboard-layout.js +3 -3
  106. package/dist/cli/dashboard-layout.js.map +1 -1
  107. package/dist/cli/dashboard-renderer.js.map +1 -1
  108. package/dist/cli/dashboard-style.js +2 -2
  109. package/dist/cli/dashboard-style.js.map +1 -1
  110. package/dist/cli/dashboard.d.ts +2 -2
  111. package/dist/cli/dashboard.js +7 -32
  112. package/dist/cli/dashboard.js.map +1 -1
  113. package/dist/cli/help.d.ts +1 -1
  114. package/dist/cli/help.js +30 -12
  115. package/dist/cli/help.js.map +1 -1
  116. package/dist/cli/main.js +5 -1
  117. package/dist/cli/main.js.map +1 -1
  118. package/dist/config/access-provenance.d.ts +10 -0
  119. package/dist/config/access-provenance.js +31 -0
  120. package/dist/config/access-provenance.js.map +1 -0
  121. package/dist/config/access.d.ts +12 -2
  122. package/dist/config/access.js +125 -27
  123. package/dist/config/access.js.map +1 -1
  124. package/dist/config/loader.js +1 -0
  125. package/dist/config/loader.js.map +1 -1
  126. package/dist/config/oidc.js +4 -2
  127. package/dist/config/oidc.js.map +1 -1
  128. package/dist/config/project.js +2 -1
  129. package/dist/config/project.js.map +1 -1
  130. package/dist/config/resolve-access.js +24 -10
  131. package/dist/config/resolve-access.js.map +1 -1
  132. package/dist/index.d.ts +2 -2
  133. package/dist/index.js +1 -1
  134. package/dist/index.js.map +1 -1
  135. package/dist/process-diagnostics.d.ts +2 -0
  136. package/dist/process-diagnostics.js +11 -0
  137. package/dist/process-diagnostics.js.map +1 -0
  138. package/dist/runtime/access-errors.d.ts +4 -0
  139. package/dist/runtime/access-errors.js +25 -0
  140. package/dist/runtime/access-errors.js.map +1 -0
  141. package/dist/runtime/approval-registry.js +1 -1
  142. package/dist/runtime/approval-registry.js.map +1 -1
  143. package/dist/runtime/client.js +54 -14
  144. package/dist/runtime/client.js.map +1 -1
  145. package/dist/runtime/dashboard-sanitize.d.ts +2 -0
  146. package/dist/runtime/dashboard-sanitize.js +7 -0
  147. package/dist/runtime/dashboard-sanitize.js.map +1 -0
  148. package/dist/runtime/dashboard.d.ts +1 -1
  149. package/dist/runtime/dashboard.js +2 -3
  150. package/dist/runtime/dashboard.js.map +1 -1
  151. package/dist/runtime/definition.js +11 -1
  152. package/dist/runtime/definition.js.map +1 -1
  153. package/dist/runtime/select-native.js +26 -8
  154. package/dist/runtime/select-native.js.map +1 -1
  155. package/dist/runtime/worker-client.js +38 -13
  156. package/dist/runtime/worker-client.js.map +1 -1
  157. package/dist/sdk/definitions.d.ts +4 -1
  158. package/dist/sdk/definitions.js +16 -2
  159. package/dist/sdk/definitions.js.map +1 -1
  160. package/dist/sdk/permission-validation.js +10 -1
  161. package/dist/sdk/permission-validation.js.map +1 -1
  162. package/dist/sdk/types.d.ts +29 -1
  163. package/dist/sdk/types.js.map +1 -1
  164. package/package.json +4 -1
  165. package/sdk/access-config.md +58 -4
  166. package/sdk/adapter-contract.md +5 -3
  167. package/sdk/additional-harnesses.md +43 -0
  168. package/sdk/agent-skill.md +2 -2
  169. package/sdk/agent.md +5 -3
  170. package/sdk/approvals.md +3 -1
  171. package/sdk/authentication.md +1 -1
  172. package/sdk/cli/dashboard-design.md +6 -0
  173. package/sdk/cli/index.md +9 -6
  174. package/sdk/cli/output.md +3 -1
  175. package/sdk/config.md +1 -1
  176. package/sdk/copilot.md +53 -0
  177. package/sdk/cursor.md +68 -0
  178. package/sdk/diagnostics.md +29 -0
  179. package/sdk/distribution.md +1 -1
  180. package/sdk/evals.md +1 -1
  181. package/sdk/fx.md +50 -5
  182. package/sdk/harnesses.md +13 -13
  183. package/sdk/index.md +3 -2
  184. package/sdk/opencode.md +57 -0
  185. package/sdk/permissions.md +4 -2
  186. package/sdk/project-team.md +2 -0
  187. package/sdk/tools.md +1 -1
  188. package/sdk/v1-runtime.md +3 -3
@@ -0,0 +1,76 @@
1
+ import { AgentError } from "../errors.js";
2
+ const directPackages = {
3
+ anthropic: ["@ai-sdk/anthropic"],
4
+ openai: ["@ai-sdk/openai"],
5
+ google: ["@ai-sdk/google"],
6
+ groq: ["@ai-sdk/groq"],
7
+ openrouter: ["@openrouter/ai-sdk-provider"],
8
+ xai: ["@ai-sdk/xai"],
9
+ mistral: ["@ai-sdk/mistral"],
10
+ cohere: ["@ai-sdk/cohere", "@ai-sdk/openai-compatible"],
11
+ opencode: ["@ai-sdk/openai-compatible", "@ai-sdk/openai", "@ai-sdk/anthropic", "@ai-sdk/google"],
12
+ "opencode-go": ["@ai-sdk/openai-compatible", "@ai-sdk/openai", "@ai-sdk/anthropic"],
13
+ };
14
+ const subscriptionPackages = {
15
+ openai: ["@ai-sdk/openai"],
16
+ "github-copilot": ["@ai-sdk/github-copilot"],
17
+ xai: ["@ai-sdk/xai"],
18
+ };
19
+ export function resolveOpencodeRoute(model, access) {
20
+ if (typeof model !== "string" || !model.trim()) {
21
+ throw new AgentError("INVALID_CONFIG", "OpenCode model must be nonempty.");
22
+ }
23
+ if (access.type === "vercel-api-key" || access.type === "vercel-oidc") {
24
+ if (!access.token?.trim())
25
+ throw new AgentError("ACCESS_UNAVAILABLE", "The selected OpenCode Gateway credential is unavailable.");
26
+ return {
27
+ kind: "gateway",
28
+ providerID: "vercel",
29
+ modelID: model,
30
+ nativeModel: `vercel/${model}`,
31
+ packages: ["@ai-sdk/gateway"],
32
+ configPackage: "@ai-sdk/gateway",
33
+ };
34
+ }
35
+ const providerID = access.provider;
36
+ const separator = model.indexOf("/");
37
+ const modelProvider = separator > 0 ? model.slice(0, separator) : "";
38
+ const modelID = separator > 0 ? model.slice(separator + 1) : "";
39
+ if (!providerID || !modelID || modelProvider !== providerID) {
40
+ throw new AgentError("INVALID_CONFIG", "OpenCode model must be an exact provider/model ID matching the selected provider.");
41
+ }
42
+ if (access.type === "api-key") {
43
+ if (!(providerID in directPackages))
44
+ throw new AgentError("UNSUPPORTED_OPTION", "OpenCode does not support the selected direct API-key provider.");
45
+ if (!access.token?.trim())
46
+ throw new AgentError("ACCESS_UNAVAILABLE", "The selected OpenCode provider credential is unavailable.");
47
+ if (access.baseUrl !== undefined && !access.baseUrl.trim())
48
+ throw new AgentError("INVALID_CONFIG", "OpenCode baseUrl must be nonempty when supplied.");
49
+ const packages = directPackages[providerID];
50
+ return {
51
+ kind: "direct",
52
+ providerID,
53
+ modelID,
54
+ nativeModel: model,
55
+ packages,
56
+ ...(access.baseUrl === undefined ? {} : { baseUrl: access.baseUrl }),
57
+ };
58
+ }
59
+ if (access.type === "subscription") {
60
+ if (!(providerID in subscriptionPackages))
61
+ throw new AgentError("UNSUPPORTED_OPTION", "OpenCode does not support the selected native subscription provider.");
62
+ if (access.baseUrl !== undefined)
63
+ throw new AgentError("UNSUPPORTED_OPTION", "OpenCode subscription access does not support baseUrl.");
64
+ return {
65
+ kind: "subscription",
66
+ providerID,
67
+ modelID,
68
+ nativeModel: model,
69
+ packages: subscriptionPackages[providerID],
70
+ unavailablePackages: providerID === "github-copilot" ? ["@ai-sdk/openai-compatible"] : subscriptionPackages[providerID],
71
+ oauthMarker: providerID === "github-copilot" ? "" : "opencode-oauth-dummy-key",
72
+ };
73
+ }
74
+ throw new AgentError("UNSUPPORTED_OPTION", "OpenCode requires explicit Gateway, direct API-key, or supported native subscription access.");
75
+ }
76
+ //# sourceMappingURL=opencode-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-access.js","sourceRoot":"","sources":["../../src/adapters/opencode-access.ts"],"names":[],"mappings":"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","sourcesContent":["import { AgentError } from \"../errors.js\";\nimport type { ResolvedAccess } from \"./types.js\";\n\nconst directPackages = {\n anthropic: [\"@ai-sdk/anthropic\"],\n openai: [\"@ai-sdk/openai\"],\n google: [\"@ai-sdk/google\"],\n groq: [\"@ai-sdk/groq\"],\n openrouter: [\"@openrouter/ai-sdk-provider\"],\n xai: [\"@ai-sdk/xai\"],\n mistral: [\"@ai-sdk/mistral\"],\n cohere: [\"@ai-sdk/cohere\", \"@ai-sdk/openai-compatible\"],\n opencode: [\"@ai-sdk/openai-compatible\", \"@ai-sdk/openai\", \"@ai-sdk/anthropic\", \"@ai-sdk/google\"],\n \"opencode-go\": [\"@ai-sdk/openai-compatible\", \"@ai-sdk/openai\", \"@ai-sdk/anthropic\"],\n} as const;\n\nconst subscriptionPackages = {\n openai: [\"@ai-sdk/openai\"],\n \"github-copilot\": [\"@ai-sdk/github-copilot\"],\n xai: [\"@ai-sdk/xai\"],\n} as const;\n\nexport type OpencodeRoute = {\n readonly kind: \"gateway\" | \"direct\" | \"subscription\";\n readonly providerID: string;\n readonly modelID: string;\n readonly nativeModel: string;\n readonly packages: readonly string[];\n readonly unavailablePackages?: readonly string[];\n readonly configPackage?: string;\n readonly baseUrl?: string;\n readonly oauthMarker?: string;\n};\n\nexport function resolveOpencodeRoute(model: string, access: ResolvedAccess): OpencodeRoute {\n if (typeof model !== \"string\" || !model.trim()) {\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode model must be nonempty.\");\n }\n if (access.type === \"vercel-api-key\" || access.type === \"vercel-oidc\") {\n if (!access.token?.trim()) throw new AgentError(\"ACCESS_UNAVAILABLE\", \"The selected OpenCode Gateway credential is unavailable.\");\n return {\n kind: \"gateway\",\n providerID: \"vercel\",\n modelID: model,\n nativeModel: `vercel/${model}`,\n packages: [\"@ai-sdk/gateway\"],\n configPackage: \"@ai-sdk/gateway\",\n };\n }\n\n const providerID = access.provider;\n const separator = model.indexOf(\"/\");\n const modelProvider = separator > 0 ? model.slice(0, separator) : \"\";\n const modelID = separator > 0 ? model.slice(separator + 1) : \"\";\n if (!providerID || !modelID || modelProvider !== providerID) {\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode model must be an exact provider/model ID matching the selected provider.\");\n }\n\n if (access.type === \"api-key\") {\n if (!(providerID in directPackages)) throw new AgentError(\"UNSUPPORTED_OPTION\", \"OpenCode does not support the selected direct API-key provider.\");\n if (!access.token?.trim()) throw new AgentError(\"ACCESS_UNAVAILABLE\", \"The selected OpenCode provider credential is unavailable.\");\n if (access.baseUrl !== undefined && !access.baseUrl.trim()) throw new AgentError(\"INVALID_CONFIG\", \"OpenCode baseUrl must be nonempty when supplied.\");\n const packages = directPackages[providerID as keyof typeof directPackages];\n return {\n kind: \"direct\",\n providerID,\n modelID,\n nativeModel: model,\n packages,\n ...(access.baseUrl === undefined ? {} : { baseUrl: access.baseUrl }),\n };\n }\n\n if (access.type === \"subscription\") {\n if (!(providerID in subscriptionPackages)) throw new AgentError(\"UNSUPPORTED_OPTION\", \"OpenCode does not support the selected native subscription provider.\");\n if (access.baseUrl !== undefined) throw new AgentError(\"UNSUPPORTED_OPTION\", \"OpenCode subscription access does not support baseUrl.\");\n return {\n kind: \"subscription\",\n providerID,\n modelID,\n nativeModel: model,\n packages: subscriptionPackages[providerID as keyof typeof subscriptionPackages],\n unavailablePackages: providerID === \"github-copilot\" ? [\"@ai-sdk/openai-compatible\"] : subscriptionPackages[providerID as keyof typeof subscriptionPackages],\n oauthMarker: providerID === \"github-copilot\" ? \"\" : \"opencode-oauth-dummy-key\",\n };\n }\n\n throw new AgentError(\"UNSUPPORTED_OPTION\", \"OpenCode requires explicit Gateway, direct API-key, or supported native subscription access.\");\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import type { OpencodeRoute } from "./opencode-access.js";
2
+ import type { AdapterOptions } from "./types.js";
3
+ export declare const gatewayBaseUrl = "https://ai-gateway.vercel.sh/v3/ai";
4
+ export interface OpencodeRuntime {
5
+ readonly directory: string;
6
+ readonly configFile: string;
7
+ readonly config: Record<string, unknown>;
8
+ readonly env: NodeJS.ProcessEnv;
9
+ close(): Promise<void>;
10
+ }
11
+ export declare function createOpencodeRuntime(options: AdapterOptions, route: OpencodeRoute): Promise<OpencodeRuntime>;
@@ -0,0 +1,238 @@
1
+ import { mkdir, mkdtemp, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
2
+ import { homedir, tmpdir, userInfo } from "node:os";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { AgentError } from "../errors.js";
5
+ export const gatewayBaseUrl = "https://ai-gateway.vercel.sh/v3/ai";
6
+ export async function createOpencodeRuntime(options, route) {
7
+ await assertNoResidualConfiguration(options.env);
8
+ const instructions = await repositoryInstructions(options.cwd);
9
+ const directory = await mkdtemp(join(tmpdir(), "subharness-opencode-"));
10
+ const privateDirectories = [
11
+ mkdir(join(directory, "config"), { recursive: true, mode: 0o700 }),
12
+ mkdir(join(directory, "state"), { recursive: true, mode: 0o700 }),
13
+ mkdir(join(directory, "cache"), { recursive: true, mode: 0o700 }),
14
+ ];
15
+ if (route.kind !== "subscription")
16
+ privateDirectories.push(mkdir(join(directory, "data"), { recursive: true, mode: 0o700 }));
17
+ await Promise.all(privateDirectories);
18
+ const configFile = join(directory, "opencode.json");
19
+ const provider = providerConfiguration(options, route);
20
+ const config = {
21
+ $schema: "https://opencode.ai/config.json",
22
+ enabled_providers: [route.providerID],
23
+ model: route.nativeModel,
24
+ small_model: route.nativeModel,
25
+ ...(provider === undefined ? {} : { provider: { [route.providerID]: provider } }),
26
+ permission: { "*": "ask" },
27
+ plugin: [],
28
+ share: "disabled",
29
+ autoupdate: false,
30
+ lsp: false,
31
+ formatter: false,
32
+ ...(instructions.length === 0 ? {} : { instructions }),
33
+ };
34
+ await writeFile(configFile, JSON.stringify(config), { mode: 0o600, flag: "wx" });
35
+ const env = isolatedEnvironment(options.env);
36
+ env.XDG_CONFIG_HOME = join(directory, "config");
37
+ if (route.kind !== "subscription")
38
+ env.XDG_DATA_HOME = join(directory, "data");
39
+ env.XDG_STATE_HOME = join(directory, "state");
40
+ env.XDG_CACHE_HOME = join(directory, "cache");
41
+ env.OPENCODE_CONFIG = configFile;
42
+ if (route.kind !== "subscription")
43
+ env.OPENCODE_AUTH_CONTENT = "{}";
44
+ env.OPENCODE_SERVER_USERNAME = "opencode";
45
+ env.OPENCODE_DISABLE_AUTOUPDATE = "1";
46
+ env.OPENCODE_DISABLE_MODELS_FETCH = "1";
47
+ env.OPENCODE_DISABLE_PROJECT_CONFIG = "1";
48
+ if (route.kind !== "subscription")
49
+ env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1";
50
+ env.OPENCODE_DISABLE_LSP_DOWNLOAD = "1";
51
+ env.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT = "1";
52
+ env.OPENCODE_PURE = "1";
53
+ if (options.access.type === "vercel-oidc")
54
+ env.VERCEL_OIDC_TOKEN = options.access.token;
55
+ for (const name of providerCredentialEnvironment(route.providerID))
56
+ delete env[name];
57
+ let closed = false;
58
+ return {
59
+ directory,
60
+ configFile,
61
+ config,
62
+ env,
63
+ async close() {
64
+ if (closed)
65
+ return;
66
+ closed = true;
67
+ await rm(directory, { recursive: true, force: true });
68
+ },
69
+ };
70
+ }
71
+ function providerConfiguration(options, route) {
72
+ if (route.kind === "subscription")
73
+ return undefined;
74
+ const providerOptions = {};
75
+ if (route.kind === "gateway") {
76
+ providerOptions.baseURL = gatewayBaseUrl;
77
+ if (options.access.type === "vercel-api-key")
78
+ providerOptions.apiKey = options.access.token;
79
+ }
80
+ else {
81
+ providerOptions.apiKey = options.access.token;
82
+ if (route.baseUrl !== undefined)
83
+ providerOptions.baseURL = route.baseUrl;
84
+ }
85
+ return {
86
+ ...(route.configPackage === undefined ? {} : { npm: route.configPackage }),
87
+ env: [],
88
+ options: providerOptions,
89
+ };
90
+ }
91
+ function providerCredentialEnvironment(provider) {
92
+ switch (provider) {
93
+ case "anthropic": return ["ANTHROPIC_API_KEY"];
94
+ case "openai": return ["OPENAI_API_KEY"];
95
+ case "google": return ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"];
96
+ case "groq": return ["GROQ_API_KEY"];
97
+ case "openrouter": return ["OPENROUTER_API_KEY"];
98
+ case "xai": return ["XAI_API_KEY"];
99
+ case "mistral": return ["MISTRAL_API_KEY"];
100
+ case "cohere": return ["COHERE_API_KEY"];
101
+ case "opencode":
102
+ case "opencode-go": return ["OPENCODE_API_KEY"];
103
+ case "github-copilot": return ["GITHUB_TOKEN"];
104
+ default: return [];
105
+ }
106
+ }
107
+ function isolatedEnvironment(source) {
108
+ const env = { ...source };
109
+ for (const key of Object.keys(env)) {
110
+ if (key.startsWith("OPENCODE_") || key === "AI_GATEWAY_API_KEY" || key === "VERCEL_OIDC_TOKEN")
111
+ delete env[key];
112
+ }
113
+ return env;
114
+ }
115
+ async function assertNoResidualConfiguration(env) {
116
+ const home = env.HOME || homedir();
117
+ if (await hasHomeConfiguration(join(home, ".opencode")))
118
+ incompatible();
119
+ const managed = process.platform === "darwin"
120
+ ? "/Library/Application Support/opencode"
121
+ : process.platform === "win32"
122
+ ? join(env.ProgramData || "C:\\ProgramData", "opencode")
123
+ : "/etc/opencode";
124
+ for (const name of ["opencode.json", "opencode.jsonc"]) {
125
+ if (await exists(join(managed, name)))
126
+ incompatible();
127
+ }
128
+ if (process.platform === "darwin") {
129
+ let user = "user";
130
+ try {
131
+ user = userInfo().username || user;
132
+ }
133
+ catch { /* OpenCode uses the same fallback. */ }
134
+ for (const file of [
135
+ join("/Library/Managed Preferences", user, "ai.opencode.managed.plist"),
136
+ "/Library/Managed Preferences/ai.opencode.managed.plist",
137
+ ])
138
+ if (await exists(file))
139
+ incompatible();
140
+ }
141
+ }
142
+ async function hasHomeConfiguration(path) {
143
+ for (const name of ["opencode.json", "opencode.jsonc"])
144
+ if (await exists(join(path, name)))
145
+ return true;
146
+ for (const name of ["command", "commands", "agent", "agents"]) {
147
+ if (await containsMatchingFile(join(path, name), filename => filename.endsWith(".md"), true))
148
+ return true;
149
+ }
150
+ for (const name of ["mode", "modes"]) {
151
+ if (await containsMatchingFile(join(path, name), filename => filename.endsWith(".md"), false))
152
+ return true;
153
+ }
154
+ for (const name of ["plugin", "plugins"]) {
155
+ if (await containsMatchingFile(join(path, name), filename => filename.endsWith(".ts") || filename.endsWith(".js"), false))
156
+ return true;
157
+ }
158
+ return false;
159
+ }
160
+ async function containsMatchingFile(path, matches, recursive, visited = new Set()) {
161
+ let entries;
162
+ try {
163
+ entries = await readdir(path, { withFileTypes: true });
164
+ }
165
+ catch (error) {
166
+ if (error.code === "ENOENT")
167
+ return false;
168
+ throw new AgentError("INVALID_CONFIG", "OpenCode residual home configuration could not be verified before startup.");
169
+ }
170
+ const canonical = await realpath(path).catch(() => resolve(path));
171
+ if (visited.has(canonical))
172
+ return false;
173
+ visited.add(canonical);
174
+ for (const entry of entries) {
175
+ const item = join(path, entry.name);
176
+ let kind = entry;
177
+ if (entry.isSymbolicLink()) {
178
+ try {
179
+ kind = await stat(item);
180
+ }
181
+ catch (error) {
182
+ if (error.code === "ENOENT")
183
+ continue;
184
+ throw new AgentError("INVALID_CONFIG", "OpenCode residual home configuration could not be verified before startup.");
185
+ }
186
+ }
187
+ if (kind.isFile() && matches(entry.name))
188
+ return true;
189
+ if (recursive && kind.isDirectory() && await containsMatchingFile(item, matches, true, visited))
190
+ return true;
191
+ }
192
+ return false;
193
+ }
194
+ async function exists(path) {
195
+ try {
196
+ await stat(path);
197
+ return true;
198
+ }
199
+ catch (error) {
200
+ if (error.code === "ENOENT")
201
+ return false;
202
+ throw new AgentError("INVALID_CONFIG", "OpenCode machine-managed configuration could not be verified before startup.");
203
+ }
204
+ }
205
+ function incompatible() {
206
+ throw new AgentError("INVALID_CONFIG", "OpenCode residual home or machine-managed configuration is incompatible with the isolated native profile.");
207
+ }
208
+ async function repositoryInstructions(cwd) {
209
+ const start = await realpath(cwd).catch(() => resolve(cwd));
210
+ const root = await nearestWorktree(start);
211
+ const directories = [];
212
+ for (let current = start;; current = dirname(current)) {
213
+ directories.push(current);
214
+ if (current === (root ?? start))
215
+ break;
216
+ }
217
+ for (const filename of ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"]) {
218
+ const matches = [];
219
+ for (const directory of directories) {
220
+ const file = join(directory, filename);
221
+ if (await exists(file))
222
+ matches.push(file);
223
+ }
224
+ if (matches.length > 0)
225
+ return matches;
226
+ }
227
+ return [];
228
+ }
229
+ async function nearestWorktree(start) {
230
+ for (let current = start;; current = dirname(current)) {
231
+ if (await exists(join(current, ".git")))
232
+ return current;
233
+ const parent = dirname(current);
234
+ if (parent === current)
235
+ return undefined;
236
+ }
237
+ }
238
+ //# sourceMappingURL=opencode-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-config.js","sourceRoot":"","sources":["../../src/adapters/opencode-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, mkdtemp, readdir, realpath, rm, stat, writeFile } from \"node:fs/promises\";\nimport { homedir, tmpdir, userInfo } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\nimport type { OpencodeRoute } from \"./opencode-access.js\";\nimport type { AdapterOptions } from \"./types.js\";\n\nexport const gatewayBaseUrl = \"https://ai-gateway.vercel.sh/v3/ai\";\n\nexport interface OpencodeRuntime {\n readonly directory: string;\n readonly configFile: string;\n readonly config: Record<string, unknown>;\n readonly env: NodeJS.ProcessEnv;\n close(): Promise<void>;\n}\n\nexport async function createOpencodeRuntime(options: AdapterOptions, route: OpencodeRoute): Promise<OpencodeRuntime> {\n await assertNoResidualConfiguration(options.env);\n const instructions = await repositoryInstructions(options.cwd);\n const directory = await mkdtemp(join(tmpdir(), \"subharness-opencode-\"));\n const privateDirectories = [\n mkdir(join(directory, \"config\"), { recursive: true, mode: 0o700 }),\n mkdir(join(directory, \"state\"), { recursive: true, mode: 0o700 }),\n mkdir(join(directory, \"cache\"), { recursive: true, mode: 0o700 }),\n ];\n if (route.kind !== \"subscription\") privateDirectories.push(mkdir(join(directory, \"data\"), { recursive: true, mode: 0o700 }));\n await Promise.all(privateDirectories);\n const configFile = join(directory, \"opencode.json\");\n const provider = providerConfiguration(options, route);\n const config = {\n $schema: \"https://opencode.ai/config.json\",\n enabled_providers: [route.providerID],\n model: route.nativeModel,\n small_model: route.nativeModel,\n ...(provider === undefined ? {} : { provider: { [route.providerID]: provider } }),\n permission: { \"*\": \"ask\" },\n plugin: [],\n share: \"disabled\",\n autoupdate: false,\n lsp: false,\n formatter: false,\n ...(instructions.length === 0 ? {} : { instructions }),\n };\n await writeFile(configFile, JSON.stringify(config), { mode: 0o600, flag: \"wx\" });\n\n const env = isolatedEnvironment(options.env);\n env.XDG_CONFIG_HOME = join(directory, \"config\");\n if (route.kind !== \"subscription\") env.XDG_DATA_HOME = join(directory, \"data\");\n env.XDG_STATE_HOME = join(directory, \"state\");\n env.XDG_CACHE_HOME = join(directory, \"cache\");\n env.OPENCODE_CONFIG = configFile;\n if (route.kind !== \"subscription\") env.OPENCODE_AUTH_CONTENT = \"{}\";\n env.OPENCODE_SERVER_USERNAME = \"opencode\";\n env.OPENCODE_DISABLE_AUTOUPDATE = \"1\";\n env.OPENCODE_DISABLE_MODELS_FETCH = \"1\";\n env.OPENCODE_DISABLE_PROJECT_CONFIG = \"1\";\n if (route.kind !== \"subscription\") env.OPENCODE_DISABLE_DEFAULT_PLUGINS = \"1\";\n env.OPENCODE_DISABLE_LSP_DOWNLOAD = \"1\";\n env.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT = \"1\";\n env.OPENCODE_PURE = \"1\";\n if (options.access.type === \"vercel-oidc\") env.VERCEL_OIDC_TOKEN = options.access.token;\n for (const name of providerCredentialEnvironment(route.providerID)) delete env[name];\n\n let closed = false;\n return {\n directory,\n configFile,\n config,\n env,\n async close() {\n if (closed) return;\n closed = true;\n await rm(directory, { recursive: true, force: true });\n },\n };\n}\n\nfunction providerConfiguration(options: AdapterOptions, route: OpencodeRoute): Record<string, unknown> | undefined {\n if (route.kind === \"subscription\") return undefined;\n const providerOptions: Record<string, string> = {};\n if (route.kind === \"gateway\") {\n providerOptions.baseURL = gatewayBaseUrl;\n if (options.access.type === \"vercel-api-key\") providerOptions.apiKey = options.access.token!;\n } else {\n providerOptions.apiKey = options.access.token!;\n if (route.baseUrl !== undefined) providerOptions.baseURL = route.baseUrl;\n }\n return {\n ...(route.configPackage === undefined ? {} : { npm: route.configPackage }),\n env: [],\n options: providerOptions,\n };\n}\n\nfunction providerCredentialEnvironment(provider: string): string[] {\n switch (provider) {\n case \"anthropic\": return [\"ANTHROPIC_API_KEY\"];\n case \"openai\": return [\"OPENAI_API_KEY\"];\n case \"google\": return [\"GOOGLE_API_KEY\", \"GOOGLE_GENERATIVE_AI_API_KEY\", \"GEMINI_API_KEY\"];\n case \"groq\": return [\"GROQ_API_KEY\"];\n case \"openrouter\": return [\"OPENROUTER_API_KEY\"];\n case \"xai\": return [\"XAI_API_KEY\"];\n case \"mistral\": return [\"MISTRAL_API_KEY\"];\n case \"cohere\": return [\"COHERE_API_KEY\"];\n case \"opencode\":\n case \"opencode-go\": return [\"OPENCODE_API_KEY\"];\n case \"github-copilot\": return [\"GITHUB_TOKEN\"];\n default: return [];\n }\n}\n\nfunction isolatedEnvironment(source: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const env = { ...source };\n for (const key of Object.keys(env)) {\n if (key.startsWith(\"OPENCODE_\") || key === \"AI_GATEWAY_API_KEY\" || key === \"VERCEL_OIDC_TOKEN\") delete env[key];\n }\n return env;\n}\n\nasync function assertNoResidualConfiguration(env: NodeJS.ProcessEnv): Promise<void> {\n const home = env.HOME || homedir();\n if (await hasHomeConfiguration(join(home, \".opencode\"))) incompatible();\n\n const managed = process.platform === \"darwin\"\n ? \"/Library/Application Support/opencode\"\n : process.platform === \"win32\"\n ? join(env.ProgramData || \"C:\\\\ProgramData\", \"opencode\")\n : \"/etc/opencode\";\n for (const name of [\"opencode.json\", \"opencode.jsonc\"]) {\n if (await exists(join(managed, name))) incompatible();\n }\n if (process.platform === \"darwin\") {\n let user = \"user\";\n try { user = userInfo().username || user; } catch { /* OpenCode uses the same fallback. */ }\n for (const file of [\n join(\"/Library/Managed Preferences\", user, \"ai.opencode.managed.plist\"),\n \"/Library/Managed Preferences/ai.opencode.managed.plist\",\n ]) if (await exists(file)) incompatible();\n }\n}\n\nasync function hasHomeConfiguration(path: string): Promise<boolean> {\n for (const name of [\"opencode.json\", \"opencode.jsonc\"]) if (await exists(join(path, name))) return true;\n for (const name of [\"command\", \"commands\", \"agent\", \"agents\"]) {\n if (await containsMatchingFile(join(path, name), filename => filename.endsWith(\".md\"), true)) return true;\n }\n for (const name of [\"mode\", \"modes\"]) {\n if (await containsMatchingFile(join(path, name), filename => filename.endsWith(\".md\"), false)) return true;\n }\n for (const name of [\"plugin\", \"plugins\"]) {\n if (await containsMatchingFile(join(path, name), filename => filename.endsWith(\".ts\") || filename.endsWith(\".js\"), false)) return true;\n }\n return false;\n}\n\nasync function containsMatchingFile(\n path: string,\n matches: (filename: string) => boolean,\n recursive: boolean,\n visited = new Set<string>(),\n): Promise<boolean> {\n let entries;\n try { entries = await readdir(path, { withFileTypes: true }); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode residual home configuration could not be verified before startup.\");\n }\n const canonical = await realpath(path).catch(() => resolve(path));\n if (visited.has(canonical)) return false;\n visited.add(canonical);\n for (const entry of entries) {\n const item = join(path, entry.name);\n let kind = entry;\n if (entry.isSymbolicLink()) {\n try { kind = await stat(item) as unknown as typeof entry; }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode residual home configuration could not be verified before startup.\");\n }\n }\n if (kind.isFile() && matches(entry.name)) return true;\n if (recursive && kind.isDirectory() && await containsMatchingFile(item, matches, true, visited)) return true;\n }\n return false;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try { await stat(path); return true; }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode machine-managed configuration could not be verified before startup.\");\n }\n}\n\nfunction incompatible(): never {\n throw new AgentError(\"INVALID_CONFIG\", \"OpenCode residual home or machine-managed configuration is incompatible with the isolated native profile.\");\n}\n\nasync function repositoryInstructions(cwd: string): Promise<string[]> {\n const start = await realpath(cwd).catch(() => resolve(cwd));\n const root = await nearestWorktree(start);\n const directories: string[] = [];\n for (let current = start;; current = dirname(current)) {\n directories.push(current);\n if (current === (root ?? start)) break;\n }\n for (const filename of [\"AGENTS.md\", \"CLAUDE.md\", \"CONTEXT.md\"]) {\n const matches: string[] = [];\n for (const directory of directories) {\n const file = join(directory, filename);\n if (await exists(file)) matches.push(file);\n }\n if (matches.length > 0) return matches;\n }\n return [];\n}\n\nasync function nearestWorktree(start: string): Promise<string | undefined> {\n for (let current = start;; current = dirname(current)) {\n if (await exists(join(current, \".git\"))) return current;\n const parent = dirname(current);\n if (parent === current) return undefined;\n }\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { type ChildProcessByStdio } from "node:child_process";
2
+ import type { Readable } from "node:stream";
3
+ export declare const supportedOpencodeVersion = "1.18.32";
4
+ type OpencodeChild = ChildProcessByStdio<null, Readable, Readable>;
5
+ export interface OpencodeProcess {
6
+ readonly url: string;
7
+ readonly child: OpencodeChild;
8
+ readonly exited: Promise<{
9
+ code: number | null;
10
+ signal: NodeJS.Signals | null;
11
+ }>;
12
+ close(): Promise<void>;
13
+ }
14
+ export declare function startOpencodeProcess(cwd: string, env: NodeJS.ProcessEnv): Promise<OpencodeProcess>;
15
+ export declare class OpencodeHttp {
16
+ #private;
17
+ readonly baseUrl: string;
18
+ readonly directory: string;
19
+ constructor(baseUrl: string, directory: string, password: string);
20
+ json(path: string, init?: {
21
+ method?: string;
22
+ body?: unknown;
23
+ signal?: AbortSignal;
24
+ timeout?: number | false;
25
+ }): Promise<unknown>;
26
+ events(signal: AbortSignal, consume: (event: unknown) => void, ready?: () => void): Promise<void>;
27
+ }
28
+ export {};