@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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/catalog.d.ts +18 -0
  4. package/dist/catalog.js +44 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/groups/codec.d.ts +2 -0
  7. package/dist/groups/codec.js +141 -0
  8. package/dist/groups/codec.js.map +1 -0
  9. package/dist/groups/convert.d.ts +2 -0
  10. package/dist/groups/convert.js +99 -0
  11. package/dist/groups/convert.js.map +1 -0
  12. package/dist/groups/crypto.d.ts +2 -0
  13. package/dist/groups/crypto.js +205 -0
  14. package/dist/groups/crypto.js.map +1 -0
  15. package/dist/groups/datetime.d.ts +2 -0
  16. package/dist/groups/datetime.js +229 -0
  17. package/dist/groups/datetime.js.map +1 -0
  18. package/dist/groups/http.d.ts +10 -0
  19. package/dist/groups/http.js +269 -0
  20. package/dist/groups/http.js.map +1 -0
  21. package/dist/groups/math.d.ts +2 -0
  22. package/dist/groups/math.js +139 -0
  23. package/dist/groups/math.js.map +1 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +6 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib.d.ts +7 -0
  28. package/dist/lib.js +7 -0
  29. package/dist/lib.js.map +1 -0
  30. package/dist/logging.d.ts +16 -0
  31. package/dist/logging.js +72 -0
  32. package/dist/logging.js.map +1 -0
  33. package/dist/opencode.d.ts +14 -0
  34. package/dist/opencode.js +91 -0
  35. package/dist/opencode.js.map +1 -0
  36. package/dist/schema.d.ts +63 -0
  37. package/dist/schema.js +54 -0
  38. package/dist/schema.js.map +1 -0
  39. package/dist/tool-spec.d.ts +44 -0
  40. package/dist/tool-spec.js +27 -0
  41. package/dist/tool-spec.js.map +1 -0
  42. package/dist/tools.d.ts +18 -0
  43. package/dist/tools.js +91 -0
  44. package/dist/tools.js.map +1 -0
  45. package/dist/types.d.ts +38 -0
  46. package/dist/types.js +2 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +81 -0
package/dist/tools.js ADDED
@@ -0,0 +1,91 @@
1
+ import { randomBytes as nodeRandomBytes } from "node:crypto";
2
+ import { tool } from "@opencode-ai/plugin";
3
+ import { selectTools } from "./catalog.js";
4
+ const z = tool.schema;
5
+ /** Build the full execution context, applying DI overrides. */
6
+ export function buildContext(options, overrides) {
7
+ return {
8
+ options,
9
+ now: overrides?.now ?? (() => new Date()),
10
+ randomBytes: overrides?.randomBytes ?? ((size) => nodeRandomBytes(size)),
11
+ fetchImpl: overrides?.fetchImpl ?? ((...a) => fetch(...a))
12
+ };
13
+ }
14
+ function fieldToZod(field) {
15
+ let schema;
16
+ switch (field.type) {
17
+ case "string":
18
+ schema = (field.enum
19
+ ? z.enum(field.enum)
20
+ : z.string());
21
+ break;
22
+ case "number":
23
+ schema = z.number();
24
+ break;
25
+ case "boolean":
26
+ schema = z.boolean();
27
+ break;
28
+ case "array":
29
+ schema = z.array(fieldToZod(field.items));
30
+ break;
31
+ case "object":
32
+ schema = z.object(buildShape(field.properties));
33
+ break;
34
+ case "record":
35
+ schema = z.record(z.string(), field.valueType === "any" ? z.any() : z.string());
36
+ break;
37
+ }
38
+ if (field.description) {
39
+ schema = schema.describe(field.description);
40
+ }
41
+ if (field.optional) {
42
+ schema = schema.optional();
43
+ }
44
+ return schema;
45
+ }
46
+ function buildShape(input) {
47
+ const shape = {};
48
+ for (const [key, field] of Object.entries(input)) {
49
+ shape[key] = fieldToZod(field);
50
+ }
51
+ return shape;
52
+ }
53
+ /** Render an adapter-neutral result into OpenCode's text-only ToolResult. */
54
+ function renderOpenCode(result) {
55
+ if (result.kind === "text") {
56
+ return result.text;
57
+ }
58
+ const metadata = typeof result.data === "object" && result.data !== null ? result.data : { value: result.data };
59
+ return { output: result.text, metadata };
60
+ }
61
+ /**
62
+ * Build the devtools tool map registered under `Hooks.tool`, filtered to the
63
+ * enabled groups. Each tool is a thin adapter over the shared catalog: validate
64
+ * args (zod), run the handler with the execution context, render the result.
65
+ */
66
+ export function createDevtoolsTools(deps) {
67
+ const ctx = buildContext(deps.options, deps.context);
68
+ const tools = {};
69
+ for (const spec of selectTools(deps.options.groups)) {
70
+ const definition = {
71
+ description: spec.description,
72
+ args: buildShape(spec.input),
73
+ async execute(args) {
74
+ deps.logger.trace("devtools_tool_invoked", { tool: spec.name, group: spec.group });
75
+ try {
76
+ const result = await spec.handler(args, ctx);
77
+ deps.logger.trace("devtools_tool_completed", { tool: spec.name });
78
+ return renderOpenCode(result);
79
+ }
80
+ catch (err) {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ deps.logger.warn("devtools_tool_failed", { tool: spec.name, error: message });
83
+ throw err;
84
+ }
85
+ }
86
+ };
87
+ tools[spec.name] = definition;
88
+ }
89
+ return tools;
90
+ }
91
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ToolGroup } from "./schema.js";
2
+ export type LogLevel = "trace" | "debug" | "info" | "warn" | "error";
3
+ export type { ToolGroup } from "./schema.js";
4
+ /**
5
+ * Per-plugin configuration, supplied as the second argument to the plugin
6
+ * factory by OpenCode (the `[name, options]` tuple form in `plugin`). All
7
+ * fields are optional; see DEFAULTS in opencode.ts for the resolved values.
8
+ */
9
+ export interface DevtoolsPluginOptions {
10
+ /** Master switch. When false no tools are registered. */
11
+ enabled?: boolean;
12
+ /**
13
+ * Which tool groups to register. The five deterministic, offline groups
14
+ * (`math`, `codec`, `crypto`, `datetime`, `convert`) are on by default;
15
+ * `http` performs network egress and is **opt-in** — add it explicitly to
16
+ * enable it. Per-agent control is also possible via OpenCode's tool
17
+ * allow/deny on the `math_* / codec_* / …` names.
18
+ */
19
+ groups?: ToolGroup[];
20
+ /** Options for the opt-in `http` group. */
21
+ http?: HttpOptions;
22
+ }
23
+ export interface HttpOptions {
24
+ /**
25
+ * Allow requests to loopback / private / link-local hosts (incl. the cloud
26
+ * metadata IP `169.254.169.254`). Default `false` — the SSRF guard rejects
27
+ * them. Turn on only when you intend the model to reach internal services.
28
+ */
29
+ allowPrivateNetwork?: boolean;
30
+ /** Per-request timeout in ms before the call aborts. Default 30000. */
31
+ timeoutMs?: number;
32
+ }
33
+ /** Fully-resolved options with defaults applied. */
34
+ export interface ResolvedDevtoolsOptions {
35
+ enabled: boolean;
36
+ groups: ToolGroup[];
37
+ http: Required<HttpOptions>;
38
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@vymalo/opencode-devtools",
3
+ "version": "0.9.0",
4
+ "description": "OpenCode plugin of everyday developer utilities the model can call locally: math (precise arithmetic, unit & base conversion, stats), codec (base64/hex/url, JWT decode, gzip), crypto (hash/hmac, uuid/ulid, random, keypairs), datetime (parse/format/diff, timezones, cron explain), convert (JSON/YAML/TOML/CSV + JSONPath), and an opt-in http client. Deterministic, zero-auth, no server — tools gated into named groups.",
5
+ "license": "MIT",
6
+ "author": "vymalo contributors",
7
+ "homepage": "https://github.com/vymalo/opencode-oauth2#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vymalo/opencode-oauth2.git",
11
+ "directory": "packages/opencode-devtools"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/vymalo/opencode-oauth2/issues"
15
+ },
16
+ "keywords": [
17
+ "opencode",
18
+ "opencode-plugin",
19
+ "utilities",
20
+ "math",
21
+ "crypto",
22
+ "base64",
23
+ "jwt",
24
+ "datetime",
25
+ "cron",
26
+ "yaml",
27
+ "csv",
28
+ "http",
29
+ "ai-sdk"
30
+ ],
31
+ "type": "module",
32
+ "main": "dist/index.js",
33
+ "types": "dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.js"
38
+ },
39
+ "./lib": {
40
+ "types": "./dist/lib.d.ts",
41
+ "import": "./dist/lib.js"
42
+ },
43
+ "./package.json": "./package.json"
44
+ },
45
+ "sideEffects": false,
46
+ "files": [
47
+ "dist"
48
+ ],
49
+ "engines": {
50
+ "node": ">=22"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "dependencies": {
56
+ "@iarna/toml": "^2.2.5",
57
+ "@opencode-ai/plugin": "1.15.10",
58
+ "cron-parser": "^5.5.0",
59
+ "cronstrue": "^3.20.0",
60
+ "jsonpath-plus": "^10.4.0",
61
+ "luxon": "^3.7.2",
62
+ "mathjs": "^15.2.0",
63
+ "papaparse": "^5.5.3",
64
+ "yaml": "^2.9.0"
65
+ },
66
+ "devDependencies": {
67
+ "@types/luxon": "^3.7.1",
68
+ "@types/papaparse": "^5.5.2",
69
+ "vite": "^8.0.14",
70
+ "vitest": "^4.1.7"
71
+ },
72
+ "scripts": {
73
+ "build": "tsc -p tsconfig.json",
74
+ "lint": "biome lint .",
75
+ "typecheck": "tsc -p tsconfig.json --noEmit",
76
+ "test": "vitest run",
77
+ "coverage": "vitest run --coverage",
78
+ "format": "biome format --write .",
79
+ "format:check": "biome format ."
80
+ }
81
+ }