@ai-sdk/harness-opencode 0.0.0-cca10482-20260708215408
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.
- package/CHANGELOG.md +182 -0
- package/LICENSE +13 -0
- package/README.md +6 -0
- package/dist/bridge/host-tool-mcp.mjs +101 -0
- package/dist/bridge/host-tool-mcp.mjs.map +1 -0
- package/dist/bridge/index.mjs +2194 -0
- package/dist/bridge/index.mjs.map +1 -0
- package/dist/bridge/package.json +13 -0
- package/dist/bridge/pnpm-lock.yaml +933 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.js +999 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
- package/src/bridge/host-tool-mcp.ts +134 -0
- package/src/bridge/index.ts +1993 -0
- package/src/bridge/opencode-events.ts +88 -0
- package/src/bridge/opencode-path.ts +17 -0
- package/src/bridge/opencode-usage.ts +156 -0
- package/src/bridge/package.json +13 -0
- package/src/bridge/pnpm-lock.yaml +933 -0
- package/src/bridge/tool-relay-auth.ts +151 -0
- package/src/index.ts +12 -0
- package/src/opencode-auth.ts +175 -0
- package/src/opencode-bridge-protocol.ts +29 -0
- package/src/opencode-harness.ts +1020 -0
- package/src/version.ts +6 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# @ai-sdk/harness-opencode
|
|
2
|
+
|
|
3
|
+
## 0.0.0-cca10482-20260708215408
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [90cd96d]
|
|
8
|
+
- @ai-sdk/provider-utils@0.0.0-cca10482-20260708215408
|
|
9
|
+
- @ai-sdk/harness@0.0.0-cca10482-20260708215408
|
|
10
|
+
|
|
11
|
+
## 1.0.21
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [ac306ed]
|
|
16
|
+
- @ai-sdk/provider-utils@5.0.6
|
|
17
|
+
- @ai-sdk/harness@1.0.21
|
|
18
|
+
|
|
19
|
+
## 1.0.20
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- b2d0306: feat(harness): send `User-Agent` and `x-client-app` headers in harness adapters
|
|
24
|
+
- Updated dependencies [b7aa06a]
|
|
25
|
+
- @ai-sdk/harness@1.0.20
|
|
26
|
+
|
|
27
|
+
## 1.0.19
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- @ai-sdk/harness@1.0.19
|
|
32
|
+
|
|
33
|
+
## 1.0.18
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- @ai-sdk/harness@1.0.18
|
|
38
|
+
|
|
39
|
+
## 1.0.17
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [5c5c0f5]
|
|
44
|
+
- @ai-sdk/provider-utils@5.0.5
|
|
45
|
+
- @ai-sdk/harness@1.0.17
|
|
46
|
+
|
|
47
|
+
## 1.0.16
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- @ai-sdk/harness@1.0.16
|
|
52
|
+
|
|
53
|
+
## 1.0.15
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- Updated dependencies [c6f5e62]
|
|
58
|
+
- @ai-sdk/provider-utils@5.0.4
|
|
59
|
+
- @ai-sdk/harness@1.0.15
|
|
60
|
+
|
|
61
|
+
## 1.0.14
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- @ai-sdk/harness@1.0.14
|
|
66
|
+
|
|
67
|
+
## 1.0.13
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- Updated dependencies [8c616f0]
|
|
72
|
+
- @ai-sdk/provider-utils@5.0.3
|
|
73
|
+
- @ai-sdk/harness@1.0.13
|
|
74
|
+
|
|
75
|
+
## 1.0.12
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- 7859cea: feat(harness): add tool filtering via `activeTools` and `inactiveTools`
|
|
80
|
+
- c857346: feat(harness): add utility functions for certain duplicated layers in harnesses
|
|
81
|
+
- Updated dependencies [7859cea]
|
|
82
|
+
- Updated dependencies [c857346]
|
|
83
|
+
- @ai-sdk/harness@1.0.12
|
|
84
|
+
|
|
85
|
+
## 1.0.11
|
|
86
|
+
|
|
87
|
+
### Patch Changes
|
|
88
|
+
|
|
89
|
+
- 2933383: fix(harness): fix harness relay auth
|
|
90
|
+
- @ai-sdk/harness@1.0.11
|
|
91
|
+
|
|
92
|
+
## 1.0.10
|
|
93
|
+
|
|
94
|
+
### Patch Changes
|
|
95
|
+
|
|
96
|
+
- @ai-sdk/harness@1.0.10
|
|
97
|
+
- @ai-sdk/provider-utils@5.0.2
|
|
98
|
+
|
|
99
|
+
## 1.0.9
|
|
100
|
+
|
|
101
|
+
### Patch Changes
|
|
102
|
+
|
|
103
|
+
- @ai-sdk/harness@1.0.9
|
|
104
|
+
|
|
105
|
+
## 1.0.8
|
|
106
|
+
|
|
107
|
+
### Patch Changes
|
|
108
|
+
|
|
109
|
+
- @ai-sdk/harness@1.0.8
|
|
110
|
+
|
|
111
|
+
## 1.0.7
|
|
112
|
+
|
|
113
|
+
### Patch Changes
|
|
114
|
+
|
|
115
|
+
- @ai-sdk/harness@1.0.7
|
|
116
|
+
|
|
117
|
+
## 1.0.6
|
|
118
|
+
|
|
119
|
+
### Patch Changes
|
|
120
|
+
|
|
121
|
+
- Updated dependencies [6a436e3]
|
|
122
|
+
- @ai-sdk/provider-utils@5.0.1
|
|
123
|
+
- @ai-sdk/harness@1.0.6
|
|
124
|
+
|
|
125
|
+
## 1.0.5
|
|
126
|
+
|
|
127
|
+
### Patch Changes
|
|
128
|
+
|
|
129
|
+
- ba6d510: chore: fix deprecated use of zod `.passthrough()`
|
|
130
|
+
- @ai-sdk/harness@1.0.5
|
|
131
|
+
|
|
132
|
+
## 1.0.4
|
|
133
|
+
|
|
134
|
+
### Patch Changes
|
|
135
|
+
|
|
136
|
+
- c493634: fix(harness): fix harness Zod usage to be v3/v4 compatible
|
|
137
|
+
- Updated dependencies [c493634]
|
|
138
|
+
- @ai-sdk/harness@1.0.4
|
|
139
|
+
|
|
140
|
+
## 1.0.3
|
|
141
|
+
|
|
142
|
+
### Patch Changes
|
|
143
|
+
|
|
144
|
+
- Updated dependencies [51d10a0]
|
|
145
|
+
- @ai-sdk/harness@1.0.3
|
|
146
|
+
|
|
147
|
+
## 1.0.2
|
|
148
|
+
|
|
149
|
+
### Patch Changes
|
|
150
|
+
|
|
151
|
+
- @ai-sdk/harness@1.0.2
|
|
152
|
+
|
|
153
|
+
## 1.0.1
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- @ai-sdk/harness@1.0.1
|
|
158
|
+
|
|
159
|
+
## 1.0.0
|
|
160
|
+
|
|
161
|
+
### Major Changes
|
|
162
|
+
|
|
163
|
+
- 34158ac: feat(harness-opencode): implement harness adapter for OpenCode
|
|
164
|
+
|
|
165
|
+
### Patch Changes
|
|
166
|
+
|
|
167
|
+
## 1.0.0-beta.1
|
|
168
|
+
|
|
169
|
+
### Patch Changes
|
|
170
|
+
|
|
171
|
+
- @ai-sdk/harness@1.0.0-beta.27
|
|
172
|
+
|
|
173
|
+
## 1.0.0-beta.0
|
|
174
|
+
|
|
175
|
+
### Major Changes
|
|
176
|
+
|
|
177
|
+
- 34158ac: feat(harness-opencode): implement harness adapter for OpenCode
|
|
178
|
+
|
|
179
|
+
### Patch Changes
|
|
180
|
+
|
|
181
|
+
- Updated dependencies [a83a367]
|
|
182
|
+
- @ai-sdk/harness@1.0.0-beta.26
|
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2023 Vercel, Inc.
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/bridge/host-tool-mcp.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod/v4";
|
|
7
|
+
var schemas = JSON.parse(process.env.TOOL_SCHEMAS || "[]");
|
|
8
|
+
var relayUrl = process.env.TOOL_RELAY_URL || "";
|
|
9
|
+
if (!schemas.length || !relayUrl) {
|
|
10
|
+
process.stderr.write(
|
|
11
|
+
"[host-tool-mcp] Missing TOOL_SCHEMAS or TOOL_RELAY_URL; exiting\n"
|
|
12
|
+
);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
var server = new McpServer({ name: "harness-tools", version: "1.0.0" });
|
|
16
|
+
for (const schema of schemas) {
|
|
17
|
+
const shape = toZodShape(schema.inputSchema);
|
|
18
|
+
server.tool(
|
|
19
|
+
schema.name,
|
|
20
|
+
schema.description ?? "",
|
|
21
|
+
shape,
|
|
22
|
+
async (input) => {
|
|
23
|
+
const requestId = crypto.randomUUID();
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(relayUrl, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "application/json"
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify({ requestId, toolName: schema.name, input })
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.text();
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Tool relay ${schema.name} failed with ${res.status}: ${body.slice(0, 500)}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const data = await res.json();
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: JSON.stringify(data.result ?? null)
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: `Error: ${String(err)}` }],
|
|
50
|
+
isError: true
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function toZodShape(schema) {
|
|
57
|
+
if (!schema?.properties) return {};
|
|
58
|
+
const required = new Set(schema.required ?? []);
|
|
59
|
+
const shape = {};
|
|
60
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
61
|
+
const propType = toZodType(propSchema);
|
|
62
|
+
shape[key] = required.has(key) ? propType : propType.optional();
|
|
63
|
+
}
|
|
64
|
+
return shape;
|
|
65
|
+
}
|
|
66
|
+
function toZodType(schema) {
|
|
67
|
+
if (!schema) return z.any();
|
|
68
|
+
const types = Array.isArray(schema.type) ? schema.type.filter((t) => t !== "null") : [schema.type].filter(Boolean);
|
|
69
|
+
let zType;
|
|
70
|
+
switch (types[0]) {
|
|
71
|
+
case "string":
|
|
72
|
+
zType = z.string();
|
|
73
|
+
break;
|
|
74
|
+
case "number":
|
|
75
|
+
zType = z.number();
|
|
76
|
+
break;
|
|
77
|
+
case "integer":
|
|
78
|
+
zType = z.number().int();
|
|
79
|
+
break;
|
|
80
|
+
case "boolean":
|
|
81
|
+
zType = z.boolean();
|
|
82
|
+
break;
|
|
83
|
+
case "array":
|
|
84
|
+
zType = z.array(toZodType(schema.items));
|
|
85
|
+
break;
|
|
86
|
+
case "object":
|
|
87
|
+
zType = z.object(toZodShape(schema));
|
|
88
|
+
break;
|
|
89
|
+
case "null":
|
|
90
|
+
zType = z.null();
|
|
91
|
+
break;
|
|
92
|
+
default:
|
|
93
|
+
zType = z.any();
|
|
94
|
+
}
|
|
95
|
+
if (schema.description) zType = zType.describe(schema.description);
|
|
96
|
+
if (schema.nullable) zType = zType.nullable();
|
|
97
|
+
return zType;
|
|
98
|
+
}
|
|
99
|
+
var transport = new StdioServerTransport();
|
|
100
|
+
await server.connect(transport);
|
|
101
|
+
//# sourceMappingURL=host-tool-mcp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/host-tool-mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n/*\n * These bridge imports are externalized by tsup and resolved inside the\n * sandbox from src/bridge/package.json and its lockfile. Keep this file,\n * tsup.config.ts, and the bridge package dependency list in sync.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod/v4';\n\ntype ToolSchema = {\n name: string;\n description?: string;\n inputSchema?: JsonSchemaObject;\n};\n\ntype JsonSchemaObject = {\n type?: string | string[];\n description?: string;\n properties?: Record<string, JsonSchemaObject>;\n required?: string[];\n items?: JsonSchemaObject;\n enum?: unknown[];\n const?: unknown;\n oneOf?: JsonSchemaObject[];\n anyOf?: JsonSchemaObject[];\n additionalProperties?: boolean | JsonSchemaObject;\n nullable?: boolean;\n};\n\ntype ZodShape = Record<string, z.ZodTypeAny>;\n\nconst schemas: ToolSchema[] = JSON.parse(process.env.TOOL_SCHEMAS || '[]');\nconst relayUrl = process.env.TOOL_RELAY_URL || '';\n\nif (!schemas.length || !relayUrl) {\n process.stderr.write(\n '[host-tool-mcp] Missing TOOL_SCHEMAS or TOOL_RELAY_URL; exiting\\n',\n );\n process.exit(0);\n}\n\nconst server = new McpServer({ name: 'harness-tools', version: '1.0.0' });\n\nfor (const schema of schemas) {\n const shape = toZodShape(schema.inputSchema);\n server.tool(\n schema.name,\n schema.description ?? '',\n shape,\n async (input: Record<string, unknown>) => {\n const requestId = crypto.randomUUID();\n try {\n const res = await fetch(relayUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ requestId, toolName: schema.name, input }),\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(\n `Tool relay ${schema.name} failed with ${res.status}: ${body.slice(0, 500)}`,\n );\n }\n const data = (await res.json()) as { result?: unknown };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(data.result ?? null),\n },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Error: ${String(err)}` }],\n isError: true,\n };\n }\n },\n );\n}\n\nfunction toZodShape(schema: JsonSchemaObject | undefined): ZodShape {\n if (!schema?.properties) return {};\n const required = new Set(schema.required ?? []);\n const shape: ZodShape = {};\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n const propType = toZodType(propSchema);\n shape[key] = required.has(key) ? propType : propType.optional();\n }\n return shape;\n}\n\nfunction toZodType(schema: JsonSchemaObject | undefined): z.ZodTypeAny {\n if (!schema) return z.any();\n const types = Array.isArray(schema.type)\n ? schema.type.filter((t): t is string => t !== 'null')\n : ([schema.type].filter(Boolean) as string[]);\n let zType: z.ZodTypeAny;\n switch (types[0]) {\n case 'string':\n zType = z.string();\n break;\n case 'number':\n zType = z.number();\n break;\n case 'integer':\n zType = z.number().int();\n break;\n case 'boolean':\n zType = z.boolean();\n break;\n case 'array':\n zType = z.array(toZodType(schema.items));\n break;\n case 'object':\n zType = z.object(toZodShape(schema));\n break;\n case 'null':\n zType = z.null();\n break;\n default:\n zType = z.any();\n }\n if (schema.description) zType = zType.describe(schema.description);\n if (schema.nullable) zType = zType.nullable();\n return zType;\n}\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n"],"mappings":"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","names":[]}
|