@vymalo/opencode-devtools 0.9.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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/catalog.d.ts +18 -0
- package/dist/catalog.js +44 -0
- package/dist/catalog.js.map +1 -0
- package/dist/groups/codec.d.ts +2 -0
- package/dist/groups/codec.js +141 -0
- package/dist/groups/codec.js.map +1 -0
- package/dist/groups/convert.d.ts +2 -0
- package/dist/groups/convert.js +99 -0
- package/dist/groups/convert.js.map +1 -0
- package/dist/groups/crypto.d.ts +2 -0
- package/dist/groups/crypto.js +205 -0
- package/dist/groups/crypto.js.map +1 -0
- package/dist/groups/datetime.d.ts +2 -0
- package/dist/groups/datetime.js +229 -0
- package/dist/groups/datetime.js.map +1 -0
- package/dist/groups/http.d.ts +10 -0
- package/dist/groups/http.js +269 -0
- package/dist/groups/http.js.map +1 -0
- package/dist/groups/math.d.ts +2 -0
- package/dist/groups/math.js +139 -0
- package/dist/groups/math.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +7 -0
- package/dist/lib.js +7 -0
- package/dist/lib.js.map +1 -0
- package/dist/logging.d.ts +16 -0
- package/dist/logging.js +72 -0
- package/dist/logging.js.map +1 -0
- package/dist/opencode.d.ts +14 -0
- package/dist/opencode.js +91 -0
- package/dist/opencode.js.map +1 -0
- package/dist/schema.d.ts +63 -0
- package/dist/schema.js +54 -0
- package/dist/schema.js.map +1 -0
- package/dist/tool-spec.d.ts +44 -0
- package/dist/tool-spec.js +27 -0
- package/dist/tool-spec.js.map +1 -0
- package/dist/tools.d.ts +18 -0
- package/dist/tools.js +91 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { all, create } from "mathjs";
|
|
2
|
+
import { json, reqNumber, reqString } from "../tool-spec.js";
|
|
3
|
+
/**
|
|
4
|
+
* A hardened mathjs instance. We use BigNumber for precise decimal arithmetic
|
|
5
|
+
* and disable every function that can mutate the evaluator or reach outside the
|
|
6
|
+
* expression sandbox. `evaluate` itself parses mathjs's own expression language
|
|
7
|
+
* (not JavaScript), so with `import` / `createUnit` / function-assignment
|
|
8
|
+
* removed there is no path to arbitrary code execution. See plans/devtools.md
|
|
9
|
+
* and the math-sandbox ADR.
|
|
10
|
+
*/
|
|
11
|
+
const math = create(all, { number: "BigNumber", precision: 64 });
|
|
12
|
+
const disabled = () => {
|
|
13
|
+
throw new Error("disabled for security");
|
|
14
|
+
};
|
|
15
|
+
math.import({
|
|
16
|
+
import: disabled,
|
|
17
|
+
createUnit: disabled,
|
|
18
|
+
reviver: disabled,
|
|
19
|
+
splitUnit: disabled
|
|
20
|
+
}, { override: true });
|
|
21
|
+
const RADIX_PREFIX = { 2: "0b", 8: "0o", 16: "0x" };
|
|
22
|
+
function parseInRadix(value, radix) {
|
|
23
|
+
const trimmed = value.trim().replace(/^0[box]/i, "");
|
|
24
|
+
// Number.parseInt stops at the first illegal digit (so "1012" in base 2 would
|
|
25
|
+
// silently parse as 5). Require EVERY digit to be legal for the radix.
|
|
26
|
+
const allLegal = trimmed.length > 0 &&
|
|
27
|
+
[...trimmed.toLowerCase()].every((ch) => {
|
|
28
|
+
const d = Number.parseInt(ch, radix);
|
|
29
|
+
return !Number.isNaN(d) && d < radix;
|
|
30
|
+
});
|
|
31
|
+
if (!allLegal) {
|
|
32
|
+
throw new Error(`"${value}" is not a valid base-${radix} integer`);
|
|
33
|
+
}
|
|
34
|
+
return Number.parseInt(trimmed, radix);
|
|
35
|
+
}
|
|
36
|
+
export const MATH_TOOLS = [
|
|
37
|
+
{
|
|
38
|
+
name: "math_eval",
|
|
39
|
+
group: "math",
|
|
40
|
+
description: 'Evaluate a mathematical expression with arbitrary-precision (64-digit) decimals. Supports arithmetic, functions (sqrt, log, sin, …), constants (pi, e), and inline unit math (e.g. "3 inch to cm"). Sandboxed: no code execution.',
|
|
41
|
+
input: {
|
|
42
|
+
expression: {
|
|
43
|
+
type: "string",
|
|
44
|
+
description: 'Expression to evaluate, e.g. "(2 + 3) * 4" or "sqrt(2)" or "5 km to miles".'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
handler: (args) => {
|
|
48
|
+
const expression = reqString(args, "expression");
|
|
49
|
+
const result = math.evaluate(expression);
|
|
50
|
+
const formatted = math.format(result, { precision: 64 });
|
|
51
|
+
return json({ expression, result: formatted }, formatted);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "math_convert_unit",
|
|
56
|
+
group: "math",
|
|
57
|
+
description: "Convert a physical quantity from one unit to another (length, mass, time, temperature, data, energy, …). Returns the converted value.",
|
|
58
|
+
input: {
|
|
59
|
+
value: { type: "number", description: "Numeric magnitude to convert." },
|
|
60
|
+
from: { type: "string", description: 'Source unit, e.g. "km", "kg", "celsius", "GB".' },
|
|
61
|
+
to: { type: "string", description: 'Target unit, e.g. "miles", "lbs", "fahrenheit", "MB".' }
|
|
62
|
+
},
|
|
63
|
+
handler: (args) => {
|
|
64
|
+
const value = reqNumber(args, "value");
|
|
65
|
+
const from = reqString(args, "from");
|
|
66
|
+
const to = reqString(args, "to");
|
|
67
|
+
const converted = math.evaluate(`${value} ${from} to ${to}`);
|
|
68
|
+
const formatted = math.format(converted, { precision: 14 });
|
|
69
|
+
return json({ value, from, to, result: formatted }, `${value} ${from} = ${formatted}`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "math_stats",
|
|
74
|
+
group: "math",
|
|
75
|
+
description: "Compute descriptive statistics over a list of numbers: count, sum, min, max, mean, median, mode, variance and standard deviation.",
|
|
76
|
+
input: {
|
|
77
|
+
values: { type: "array", items: { type: "number" }, description: "The numbers to summarize." }
|
|
78
|
+
},
|
|
79
|
+
handler: (args) => {
|
|
80
|
+
const raw = args.values;
|
|
81
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
82
|
+
throw new Error('"values" must be a non-empty array of numbers');
|
|
83
|
+
}
|
|
84
|
+
const values = raw.map((v, i) => {
|
|
85
|
+
if (typeof v !== "number" || Number.isNaN(v)) {
|
|
86
|
+
throw new Error(`values[${i}] is not a number`);
|
|
87
|
+
}
|
|
88
|
+
return v;
|
|
89
|
+
});
|
|
90
|
+
const num = (x) => Number(math.format(x, { precision: 14 }));
|
|
91
|
+
const stats = {
|
|
92
|
+
count: values.length,
|
|
93
|
+
sum: num(math.sum(values)),
|
|
94
|
+
min: num(math.min(values)),
|
|
95
|
+
max: num(math.max(values)),
|
|
96
|
+
mean: num(math.mean(values)),
|
|
97
|
+
median: num(math.median(values)),
|
|
98
|
+
mode: math.mode(values).map(num),
|
|
99
|
+
variance: num(math.variance(values)),
|
|
100
|
+
stdev: num(math.std(values))
|
|
101
|
+
};
|
|
102
|
+
return json(stats, `n=${stats.count} mean=${stats.mean} median=${stats.median} stdev=${stats.stdev} min=${stats.min} max=${stats.max}`);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "math_base",
|
|
107
|
+
group: "math",
|
|
108
|
+
description: "Convert an integer between numeric bases (radix 2–36). Common bases (binary, octal, decimal, hex) are returned alongside the requested target.",
|
|
109
|
+
input: {
|
|
110
|
+
value: { type: "string", description: 'Integer to convert, e.g. "255" or "0xff" or "1011".' },
|
|
111
|
+
fromBase: { type: "number", description: "Base of the input value (2–36)." },
|
|
112
|
+
toBase: { type: "number", description: "Base to convert to (2–36)." }
|
|
113
|
+
},
|
|
114
|
+
handler: (args) => {
|
|
115
|
+
const value = reqString(args, "value");
|
|
116
|
+
const fromBase = reqNumber(args, "fromBase");
|
|
117
|
+
const toBase = reqNumber(args, "toBase");
|
|
118
|
+
for (const [label, b] of [
|
|
119
|
+
["fromBase", fromBase],
|
|
120
|
+
["toBase", toBase]
|
|
121
|
+
]) {
|
|
122
|
+
if (!Number.isInteger(b) || b < 2 || b > 36) {
|
|
123
|
+
throw new Error(`"${label}" must be an integer in 2–36`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const n = parseInRadix(value, fromBase);
|
|
127
|
+
const out = n.toString(toBase);
|
|
128
|
+
const prefix = RADIX_PREFIX[toBase] ?? "";
|
|
129
|
+
return json({
|
|
130
|
+
decimal: n,
|
|
131
|
+
result: out,
|
|
132
|
+
binary: n.toString(2),
|
|
133
|
+
octal: n.toString(8),
|
|
134
|
+
hex: n.toString(16)
|
|
135
|
+
}, `${value} (base ${fromBase}) = ${prefix}${out} (base ${toBase})`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
//# sourceMappingURL=math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.js","sourceRoot":"","sources":["../../src/groups/math.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./opencode.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Intentionally tiny. OpenCode iterates every named export of the main entry
|
|
2
|
+
// and rejects anything that isn't a `Plugin` function, so the only thing this
|
|
3
|
+
// module exposes is the default plugin. Library/utility exports live in
|
|
4
|
+
// `./lib` (see lib.ts), which OpenCode never inspects.
|
|
5
|
+
export { default } from "./opencode.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,wEAAwE;AACxE,uDAAuD;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createDevtoolsPlugin, type DevtoolsPluginFactoryOptions, OpencodeDevtoolsPlugin, resolveOptions } from "./opencode.js";
|
|
2
|
+
export { DEFAULT_GROUPS, DEVTOOLS_TOOLS, type NeutralResult, selectTools, TOOL_GROUPS, type ToolContext, type ToolGroup, type ToolSpec } from "./catalog.js";
|
|
3
|
+
export { buildContext, createDevtoolsTools, type ToolDeps } from "./tools.js";
|
|
4
|
+
export { type Field, type JsonInput, type JsonSchema, toJsonSchema } from "./schema.js";
|
|
5
|
+
export { json, optBool, optString, reqNumber, reqString, text } from "./tool-spec.js";
|
|
6
|
+
export { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel, type LogFields, type Logger, type LogLevel } from "./logging.js";
|
|
7
|
+
export type { DevtoolsPluginOptions, HttpOptions, ResolvedDevtoolsOptions } from "./types.js";
|
package/dist/lib.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createDevtoolsPlugin, OpencodeDevtoolsPlugin, resolveOptions } from "./opencode.js";
|
|
2
|
+
export { DEFAULT_GROUPS, DEVTOOLS_TOOLS, selectTools, TOOL_GROUPS } from "./catalog.js";
|
|
3
|
+
export { buildContext, createDevtoolsTools } from "./tools.js";
|
|
4
|
+
export { toJsonSchema } from "./schema.js";
|
|
5
|
+
export { json, optBool, optString, reqNumber, reqString, text } from "./tool-spec.js";
|
|
6
|
+
export { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel } from "./logging.js";
|
|
7
|
+
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAEpB,sBAAsB,EACtB,cAAc,EACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,cAAc,EACd,cAAc,EAEd,WAAW,EACX,WAAW,EAIZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAiB,MAAM,YAAY,CAAC;AAE9E,OAAO,EAA+C,YAAY,EAAE,MAAM,aAAa,CAAC;AAExF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EAIrB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LogLevel } from "./types.js";
|
|
2
|
+
export type { LogLevel } from "./types.js";
|
|
3
|
+
export declare const LOG_LEVEL_PRIORITY: Record<LogLevel, number>;
|
|
4
|
+
export declare const DEFAULT_LOG_LEVEL: LogLevel;
|
|
5
|
+
export interface LogFields {
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface Logger {
|
|
9
|
+
trace(event: string, fields?: LogFields): void;
|
|
10
|
+
debug(event: string, fields?: LogFields): void;
|
|
11
|
+
info(event: string, fields?: LogFields): void;
|
|
12
|
+
warn(event: string, fields?: LogFields): void;
|
|
13
|
+
error(event: string, fields?: LogFields): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createJsonConsoleLogger(minLevel?: LogLevel): Logger;
|
|
16
|
+
export declare function fromOpenCodeLogLevel(value: unknown): LogLevel | undefined;
|
package/dist/logging.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const LOG_LEVEL_PRIORITY = {
|
|
2
|
+
trace: 5,
|
|
3
|
+
debug: 10,
|
|
4
|
+
info: 20,
|
|
5
|
+
warn: 30,
|
|
6
|
+
error: 40
|
|
7
|
+
};
|
|
8
|
+
export const DEFAULT_LOG_LEVEL = "info";
|
|
9
|
+
function redactFields(fields) {
|
|
10
|
+
if (!fields) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const redacted = {};
|
|
14
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
15
|
+
if (/token|secret|password|authorization/i.test(key)) {
|
|
16
|
+
redacted[key] = "[redacted]";
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
redacted[key] = value;
|
|
20
|
+
}
|
|
21
|
+
return redacted;
|
|
22
|
+
}
|
|
23
|
+
export function createJsonConsoleLogger(minLevel = DEFAULT_LOG_LEVEL) {
|
|
24
|
+
const minPriority = LOG_LEVEL_PRIORITY[minLevel];
|
|
25
|
+
const write = (level, event, fields) => {
|
|
26
|
+
if (LOG_LEVEL_PRIORITY[level] < minPriority) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const payload = {
|
|
30
|
+
ts: new Date().toISOString(),
|
|
31
|
+
level,
|
|
32
|
+
event,
|
|
33
|
+
...(redactFields(fields) ?? {})
|
|
34
|
+
};
|
|
35
|
+
const line = JSON.stringify(payload);
|
|
36
|
+
if (level === "error") {
|
|
37
|
+
console.error(line);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (level === "warn") {
|
|
41
|
+
console.warn(line);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
console.log(line);
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
trace: (event, fields) => write("trace", event, fields),
|
|
48
|
+
debug: (event, fields) => write("debug", event, fields),
|
|
49
|
+
info: (event, fields) => write("info", event, fields),
|
|
50
|
+
warn: (event, fields) => write("warn", event, fields),
|
|
51
|
+
error: (event, fields) => write("error", event, fields)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function fromOpenCodeLogLevel(value) {
|
|
55
|
+
if (typeof value !== "string") {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
switch (value.toUpperCase()) {
|
|
59
|
+
case "DEBUG":
|
|
60
|
+
// Host DEBUG unlocks our most-verbose internal tier (trace).
|
|
61
|
+
return "trace";
|
|
62
|
+
case "INFO":
|
|
63
|
+
return "info";
|
|
64
|
+
case "WARN":
|
|
65
|
+
return "warn";
|
|
66
|
+
case "ERROR":
|
|
67
|
+
return "error";
|
|
68
|
+
default:
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Plugin, PluginOptions } from "@opencode-ai/plugin";
|
|
2
|
+
import { type Logger } from "./logging.js";
|
|
3
|
+
import { type ToolDeps } from "./tools.js";
|
|
4
|
+
import type { ResolvedDevtoolsOptions } from "./types.js";
|
|
5
|
+
export interface DevtoolsPluginFactoryOptions {
|
|
6
|
+
/** Inject a logger (defaults to the OpenCode-piped logger). */
|
|
7
|
+
logger?: Logger;
|
|
8
|
+
/** Inject the tool execution context (clock / randomness / fetch) for tests. */
|
|
9
|
+
context?: ToolDeps["context"];
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveOptions(raw: PluginOptions | undefined): ResolvedDevtoolsOptions;
|
|
12
|
+
export declare function createDevtoolsPlugin(factoryOptions?: DevtoolsPluginFactoryOptions): Plugin;
|
|
13
|
+
export declare const OpencodeDevtoolsPlugin: Plugin;
|
|
14
|
+
export default OpencodeDevtoolsPlugin;
|
package/dist/opencode.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { DEFAULT_GROUPS, TOOL_GROUPS } from "./catalog.js";
|
|
2
|
+
import { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel, LOG_LEVEL_PRIORITY } from "./logging.js";
|
|
3
|
+
import { createDevtoolsTools } from "./tools.js";
|
|
4
|
+
const PLUGIN_SERVICE_NAME = "opencode-devtools-plugin";
|
|
5
|
+
const DEFAULTS = {
|
|
6
|
+
httpTimeoutMs: 30_000
|
|
7
|
+
};
|
|
8
|
+
function resolveGroups(raw) {
|
|
9
|
+
if (!Array.isArray(raw)) {
|
|
10
|
+
return [...DEFAULT_GROUPS];
|
|
11
|
+
}
|
|
12
|
+
const valid = raw.filter((g) => TOOL_GROUPS.includes(g));
|
|
13
|
+
// An explicit but empty/invalid list falls back to the defaults rather than
|
|
14
|
+
// registering nothing — matches the browser plugin's behaviour.
|
|
15
|
+
return valid.length > 0 ? Array.from(new Set(valid)) : [...DEFAULT_GROUPS];
|
|
16
|
+
}
|
|
17
|
+
export function resolveOptions(raw) {
|
|
18
|
+
const opts = (raw ?? {});
|
|
19
|
+
return {
|
|
20
|
+
enabled: opts.enabled !== false,
|
|
21
|
+
groups: resolveGroups(opts.groups),
|
|
22
|
+
http: {
|
|
23
|
+
allowPrivateNetwork: opts.http?.allowPrivateNetwork === true,
|
|
24
|
+
timeoutMs: typeof opts.http?.timeoutMs === "number" && opts.http.timeoutMs > 0
|
|
25
|
+
? opts.http.timeoutMs
|
|
26
|
+
: DEFAULTS.httpTimeoutMs
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Pipe plugin logs through OpenCode's `client.app.log` so they show up in the
|
|
32
|
+
* host's structured log stream, with the JSON console as a reliable fallback.
|
|
33
|
+
* Mirrors `@vymalo/opencode-browser`.
|
|
34
|
+
*/
|
|
35
|
+
function createOpenCodeLogger(client, getMinLevel) {
|
|
36
|
+
const fallback = createJsonConsoleLogger("debug");
|
|
37
|
+
const consoleAll = /^(1|true|yes|on)$/i.test(process.env.VYMALO_PLUGIN_CONSOLE_LOG ?? "");
|
|
38
|
+
const write = (level, event, fields) => {
|
|
39
|
+
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[getMinLevel()]) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (consoleAll || level === "warn" || level === "error") {
|
|
43
|
+
fallback[level](event, fields);
|
|
44
|
+
}
|
|
45
|
+
const hostLevel = level === "trace" ? "debug" : level;
|
|
46
|
+
void client.app
|
|
47
|
+
.log({
|
|
48
|
+
body: { service: PLUGIN_SERVICE_NAME, level: hostLevel, message: event, extra: fields }
|
|
49
|
+
})
|
|
50
|
+
.catch(() => {
|
|
51
|
+
/* best-effort */
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
trace: (event, fields) => write("trace", event, fields),
|
|
56
|
+
debug: (event, fields) => write("debug", event, fields),
|
|
57
|
+
info: (event, fields) => write("info", event, fields),
|
|
58
|
+
warn: (event, fields) => write("warn", event, fields),
|
|
59
|
+
error: (event, fields) => write("error", event, fields)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function createDevtoolsPlugin(factoryOptions = {}) {
|
|
63
|
+
return async ({ client }, pluginOptions) => {
|
|
64
|
+
let currentLogLevel = DEFAULT_LOG_LEVEL;
|
|
65
|
+
const logger = factoryOptions.logger ?? createOpenCodeLogger(client, () => currentLogLevel);
|
|
66
|
+
const options = resolveOptions(pluginOptions);
|
|
67
|
+
if (!options.enabled) {
|
|
68
|
+
logger.info("devtools_plugin_disabled", {});
|
|
69
|
+
return {
|
|
70
|
+
config: async (config) => {
|
|
71
|
+
currentLogLevel = fromOpenCodeLogLevel(config.logLevel) ?? DEFAULT_LOG_LEVEL;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
logger.info("devtools_plugin_enabled", { groups: options.groups });
|
|
76
|
+
const tools = createDevtoolsTools({
|
|
77
|
+
options,
|
|
78
|
+
logger,
|
|
79
|
+
context: factoryOptions.context
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
tool: tools,
|
|
83
|
+
config: async (config) => {
|
|
84
|
+
currentLogLevel = fromOpenCodeLogLevel(config.logLevel) ?? DEFAULT_LOG_LEVEL;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export const OpencodeDevtoolsPlugin = createDevtoolsPlugin();
|
|
90
|
+
export default OpencodeDevtoolsPlugin;
|
|
91
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny, neutral schema vocabulary for tool arguments. The tool catalog
|
|
3
|
+
* (`catalog.ts`) is the single source of truth; each adapter turns these specs
|
|
4
|
+
* into its own format:
|
|
5
|
+
* - the OpenCode plugin builds a zod shape (see `buildShape` in tools.ts),
|
|
6
|
+
* - the MCP server emits standard JSON Schema via `toJsonSchema` below.
|
|
7
|
+
*
|
|
8
|
+
* Lifted verbatim from `@vymalo/opencode-browser` so the two tool-registering
|
|
9
|
+
* plugins describe their surface the same way. Keeping the vocabulary small
|
|
10
|
+
* avoids dragging a specific zod version across the package boundary.
|
|
11
|
+
*/
|
|
12
|
+
export type ToolGroup = "math" | "codec" | "crypto" | "datetime" | "convert" | "http";
|
|
13
|
+
export interface StringField {
|
|
14
|
+
type: "string";
|
|
15
|
+
description?: string;
|
|
16
|
+
optional?: boolean;
|
|
17
|
+
enum?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface NumberField {
|
|
20
|
+
type: "number";
|
|
21
|
+
description?: string;
|
|
22
|
+
optional?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface BooleanField {
|
|
25
|
+
type: "boolean";
|
|
26
|
+
description?: string;
|
|
27
|
+
optional?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ArrayField {
|
|
30
|
+
type: "array";
|
|
31
|
+
description?: string;
|
|
32
|
+
optional?: boolean;
|
|
33
|
+
items: Field;
|
|
34
|
+
}
|
|
35
|
+
export interface ObjectField {
|
|
36
|
+
type: "object";
|
|
37
|
+
description?: string;
|
|
38
|
+
optional?: boolean;
|
|
39
|
+
properties: Record<string, Field>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* An open key→value map with arbitrary keys (e.g. HTTP headers, GraphQL
|
|
43
|
+
* variables). Unlike `object`, it does NOT set `additionalProperties: false`,
|
|
44
|
+
* so real keys aren't stripped/rejected by a validating client. `valueType`
|
|
45
|
+
* picks the value schema (`string` for headers, `any` for variables).
|
|
46
|
+
*/
|
|
47
|
+
export interface RecordField {
|
|
48
|
+
type: "record";
|
|
49
|
+
description?: string;
|
|
50
|
+
optional?: boolean;
|
|
51
|
+
valueType?: "string" | "any";
|
|
52
|
+
}
|
|
53
|
+
export type Field = StringField | NumberField | BooleanField | ArrayField | ObjectField | RecordField;
|
|
54
|
+
/** Top-level argument map for a tool. */
|
|
55
|
+
export type JsonInput = Record<string, Field>;
|
|
56
|
+
export interface JsonSchema {
|
|
57
|
+
type: "object";
|
|
58
|
+
properties: Record<string, unknown>;
|
|
59
|
+
required: string[];
|
|
60
|
+
additionalProperties: false;
|
|
61
|
+
}
|
|
62
|
+
/** Convert a tool's input spec to a standard JSON Schema object (for MCP). */
|
|
63
|
+
export declare function toJsonSchema(input: JsonInput): JsonSchema;
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny, neutral schema vocabulary for tool arguments. The tool catalog
|
|
3
|
+
* (`catalog.ts`) is the single source of truth; each adapter turns these specs
|
|
4
|
+
* into its own format:
|
|
5
|
+
* - the OpenCode plugin builds a zod shape (see `buildShape` in tools.ts),
|
|
6
|
+
* - the MCP server emits standard JSON Schema via `toJsonSchema` below.
|
|
7
|
+
*
|
|
8
|
+
* Lifted verbatim from `@vymalo/opencode-browser` so the two tool-registering
|
|
9
|
+
* plugins describe their surface the same way. Keeping the vocabulary small
|
|
10
|
+
* avoids dragging a specific zod version across the package boundary.
|
|
11
|
+
*/
|
|
12
|
+
function fieldToJsonSchema(field) {
|
|
13
|
+
const out = { type: field.type };
|
|
14
|
+
if (field.description) {
|
|
15
|
+
out.description = field.description;
|
|
16
|
+
}
|
|
17
|
+
if (field.type === "string" && field.enum) {
|
|
18
|
+
out.enum = [...field.enum];
|
|
19
|
+
}
|
|
20
|
+
if (field.type === "array") {
|
|
21
|
+
out.items = fieldToJsonSchema(field.items);
|
|
22
|
+
}
|
|
23
|
+
if (field.type === "record") {
|
|
24
|
+
out.type = "object";
|
|
25
|
+
out.additionalProperties = field.valueType === "any" ? true : { type: "string" };
|
|
26
|
+
}
|
|
27
|
+
if (field.type === "object") {
|
|
28
|
+
const properties = {};
|
|
29
|
+
const required = [];
|
|
30
|
+
for (const [key, value] of Object.entries(field.properties)) {
|
|
31
|
+
properties[key] = fieldToJsonSchema(value);
|
|
32
|
+
if (!value.optional) {
|
|
33
|
+
required.push(key);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
out.properties = properties;
|
|
37
|
+
out.required = required;
|
|
38
|
+
out.additionalProperties = false;
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/** Convert a tool's input spec to a standard JSON Schema object (for MCP). */
|
|
43
|
+
export function toJsonSchema(input) {
|
|
44
|
+
const properties = {};
|
|
45
|
+
const required = [];
|
|
46
|
+
for (const [key, field] of Object.entries(input)) {
|
|
47
|
+
properties[key] = fieldToJsonSchema(field);
|
|
48
|
+
if (!field.optional) {
|
|
49
|
+
required.push(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { type: "object", properties, required, additionalProperties: false };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8DH,SAAS,iBAAiB,CAAC,KAAY;IACrC,MAAM,GAAG,GAA4B,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1D,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACtC,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC1C,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,GAAG,CAAC,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;QACpB,GAAG,CAAC,oBAAoB,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACnF,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,UAAU,GAA4B,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5D,UAAU,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QACD,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC;QAC5B,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACxB,GAAG,CAAC,oBAAoB,GAAG,KAAK,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,KAAgB;IAC3C,MAAM,UAAU,GAA4B,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,UAAU,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { JsonInput, ToolGroup } from "./schema.js";
|
|
2
|
+
import type { ResolvedDevtoolsOptions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Execution context handed to every tool handler. The clock, randomness and
|
|
5
|
+
* fetch are injected (not imported) so the deterministic groups stay unit-
|
|
6
|
+
* testable: a test pins `now`/`randomBytes` and asserts exact output, and the
|
|
7
|
+
* `http` group runs against a fake `fetchImpl` with no network.
|
|
8
|
+
*/
|
|
9
|
+
export interface ToolContext {
|
|
10
|
+
options: ResolvedDevtoolsOptions;
|
|
11
|
+
/** Current time. Default `() => new Date()`. */
|
|
12
|
+
now: () => Date;
|
|
13
|
+
/** Cryptographically-strong random bytes. Default `node:crypto.randomBytes`. */
|
|
14
|
+
randomBytes: (size: number) => Buffer;
|
|
15
|
+
/** Fetch implementation for the `http` group. Default the global `fetch`. */
|
|
16
|
+
fetchImpl: typeof fetch;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Adapter-neutral result of a tool call. `text` is always the self-sufficient
|
|
20
|
+
* human/agent-readable output; `data` (json only) carries optional structured
|
|
21
|
+
* metadata the OpenCode adapter surfaces as `metadata`. There is no image
|
|
22
|
+
* variant — unlike the browser plugin, devtools tools return text/json only.
|
|
23
|
+
*/
|
|
24
|
+
export type NeutralResult = {
|
|
25
|
+
kind: "text";
|
|
26
|
+
text: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "json";
|
|
29
|
+
text: string;
|
|
30
|
+
data: unknown;
|
|
31
|
+
};
|
|
32
|
+
export interface ToolSpec {
|
|
33
|
+
name: string;
|
|
34
|
+
group: ToolGroup;
|
|
35
|
+
description: string;
|
|
36
|
+
input: JsonInput;
|
|
37
|
+
handler: (args: Record<string, unknown>, ctx: ToolContext) => NeutralResult | Promise<NeutralResult>;
|
|
38
|
+
}
|
|
39
|
+
export declare const text: (t: string) => NeutralResult;
|
|
40
|
+
export declare const json: (data: unknown, t: string) => NeutralResult;
|
|
41
|
+
export declare function reqString(args: Record<string, unknown>, key: string): string;
|
|
42
|
+
export declare function optString(args: Record<string, unknown>, key: string): string | undefined;
|
|
43
|
+
export declare function reqNumber(args: Record<string, unknown>, key: string): number;
|
|
44
|
+
export declare function optBool(args: Record<string, unknown>, key: string): boolean | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// ─── result builders ─────────────────────────────────────────────────────────
|
|
2
|
+
export const text = (t) => ({ kind: "text", text: t });
|
|
3
|
+
export const json = (data, t) => ({ kind: "json", data, text: t });
|
|
4
|
+
// ─── arg coercion (args are pre-validated by the adapter's schema) ───────────
|
|
5
|
+
export function reqString(args, key) {
|
|
6
|
+
const v = args[key];
|
|
7
|
+
if (typeof v !== "string") {
|
|
8
|
+
throw new Error(`"${key}" must be a string`);
|
|
9
|
+
}
|
|
10
|
+
return v;
|
|
11
|
+
}
|
|
12
|
+
export function optString(args, key) {
|
|
13
|
+
const v = args[key];
|
|
14
|
+
return typeof v === "string" ? v : undefined;
|
|
15
|
+
}
|
|
16
|
+
export function reqNumber(args, key) {
|
|
17
|
+
const v = args[key];
|
|
18
|
+
if (typeof v !== "number" || Number.isNaN(v)) {
|
|
19
|
+
throw new Error(`"${key}" must be a number`);
|
|
20
|
+
}
|
|
21
|
+
return v;
|
|
22
|
+
}
|
|
23
|
+
export function optBool(args, key) {
|
|
24
|
+
const v = args[key];
|
|
25
|
+
return typeof v === "boolean" ? v : undefined;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=tool-spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-spec.js","sourceRoot":"","sources":["../src/tool-spec.ts"],"names":[],"mappings":"AAwCA,gFAAgF;AAChF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAiB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,CAAS,EAAiB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAEnG,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,IAA6B,EAAE,GAAW;IAClE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,IAAI,GAAG,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAA6B,EAAE,GAAW;IAClE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAA6B,EAAE,GAAW;IAClE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,IAAI,GAAG,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAA6B,EAAE,GAAW;IAChE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@opencode-ai/plugin";
|
|
2
|
+
import type { Logger } from "./logging.js";
|
|
3
|
+
import type { ToolContext } from "./tool-spec.js";
|
|
4
|
+
import type { ResolvedDevtoolsOptions } from "./types.js";
|
|
5
|
+
export interface ToolDeps {
|
|
6
|
+
options: ResolvedDevtoolsOptions;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
/** Inject the execution context (clock / randomness / fetch) for tests. */
|
|
9
|
+
context?: Partial<Omit<ToolContext, "options">>;
|
|
10
|
+
}
|
|
11
|
+
/** Build the full execution context, applying DI overrides. */
|
|
12
|
+
export declare function buildContext(options: ResolvedDevtoolsOptions, overrides?: Partial<Omit<ToolContext, "options">>): ToolContext;
|
|
13
|
+
/**
|
|
14
|
+
* Build the devtools tool map registered under `Hooks.tool`, filtered to the
|
|
15
|
+
* enabled groups. Each tool is a thin adapter over the shared catalog: validate
|
|
16
|
+
* args (zod), run the handler with the execution context, render the result.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDevtoolsTools(deps: ToolDeps): Record<string, ToolDefinition>;
|