@opencode-ai/codemode 0.0.0-beta-17492

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 (72) hide show
  1. package/README.md +168 -0
  2. package/dist/codemode.d.ts +148 -0
  3. package/dist/codemode.js +70 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +5 -0
  6. package/dist/interpreter/errors.d.ts +9 -0
  7. package/dist/interpreter/errors.js +91 -0
  8. package/dist/interpreter/execute.d.ts +4 -0
  9. package/dist/interpreter/execute.js +178 -0
  10. package/dist/interpreter/iterator.d.ts +13 -0
  11. package/dist/interpreter/iterator.js +4 -0
  12. package/dist/interpreter/methods.d.ts +17 -0
  13. package/dist/interpreter/methods.js +1026 -0
  14. package/dist/interpreter/model.d.ts +151 -0
  15. package/dist/interpreter/model.js +186 -0
  16. package/dist/interpreter/promises.d.ts +29 -0
  17. package/dist/interpreter/promises.js +253 -0
  18. package/dist/interpreter/references.d.ts +6 -0
  19. package/dist/interpreter/references.js +114 -0
  20. package/dist/interpreter/runtime.d.ts +98 -0
  21. package/dist/interpreter/runtime.js +2351 -0
  22. package/dist/interpreter/scope.d.ts +15 -0
  23. package/dist/interpreter/scope.js +79 -0
  24. package/dist/interpreter/transpile.node.d.ts +5 -0
  25. package/dist/interpreter/transpile.node.js +19 -0
  26. package/dist/interpreter/transpile.workerd.d.ts +5 -0
  27. package/dist/interpreter/transpile.workerd.js +6 -0
  28. package/dist/openapi/index.d.ts +7 -0
  29. package/dist/openapi/index.js +101 -0
  30. package/dist/openapi/runtime.d.ts +4 -0
  31. package/dist/openapi/runtime.js +283 -0
  32. package/dist/openapi/spec.d.ts +20 -0
  33. package/dist/openapi/spec.js +588 -0
  34. package/dist/openapi/types.d.ts +122 -0
  35. package/dist/openapi/types.js +2 -0
  36. package/dist/stdlib/collections.d.ts +4 -0
  37. package/dist/stdlib/collections.js +57 -0
  38. package/dist/stdlib/console.d.ts +2 -0
  39. package/dist/stdlib/console.js +126 -0
  40. package/dist/stdlib/date.d.ts +7 -0
  41. package/dist/stdlib/date.js +186 -0
  42. package/dist/stdlib/json.d.ts +6 -0
  43. package/dist/stdlib/json.js +124 -0
  44. package/dist/stdlib/math.d.ts +12 -0
  45. package/dist/stdlib/math.js +157 -0
  46. package/dist/stdlib/number.d.ts +6 -0
  47. package/dist/stdlib/number.js +76 -0
  48. package/dist/stdlib/object.d.ts +7 -0
  49. package/dist/stdlib/object.js +100 -0
  50. package/dist/stdlib/promise.d.ts +2 -0
  51. package/dist/stdlib/promise.js +1 -0
  52. package/dist/stdlib/regexp.d.ts +11 -0
  53. package/dist/stdlib/regexp.js +106 -0
  54. package/dist/stdlib/string.d.ts +4 -0
  55. package/dist/stdlib/string.js +48 -0
  56. package/dist/stdlib/url.d.ts +12 -0
  57. package/dist/stdlib/url.js +84 -0
  58. package/dist/stdlib/value.d.ts +12 -0
  59. package/dist/stdlib/value.js +120 -0
  60. package/dist/tool-error.d.ts +11 -0
  61. package/dist/tool-error.js +9 -0
  62. package/dist/tool-runtime.d.ts +68 -0
  63. package/dist/tool-runtime.js +390 -0
  64. package/dist/tool-schema.d.ts +15 -0
  65. package/dist/tool-schema.js +213 -0
  66. package/dist/tool.d.ts +55 -0
  67. package/dist/tool.js +21 -0
  68. package/dist/tools.d.ts +4 -0
  69. package/dist/tools.js +1 -0
  70. package/dist/values.d.ts +31 -0
  71. package/dist/values.js +50 -0
  72. package/package.json +46 -0
@@ -0,0 +1,213 @@
1
+ import { JsonPointer, Schema } from "effect";
2
+ const isEffectSchema = (schema) => Schema.isSchema(schema);
3
+ const renderLiteral = (value) => JSON.stringify(value) ?? "unknown";
4
+ export const identifierSegment = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
5
+ const renderKey = (name) => (identifierSegment.test(name) ? name : JSON.stringify(name));
6
+ const effectNumberSentinel = (schema) => schema.type === "string" &&
7
+ Array.isArray(schema.enum) &&
8
+ schema.enum.length === 1 &&
9
+ (schema.enum[0] === "NaN" || schema.enum[0] === "Infinity" || schema.enum[0] === "-Infinity");
10
+ const intersection = (members) => {
11
+ const concrete = members.filter((member) => member !== "unknown");
12
+ if (concrete.length === 0)
13
+ return "unknown";
14
+ if (concrete.length === 1)
15
+ return concrete[0];
16
+ return concrete.map((member) => (member.includes(" | ") ? `(${member})` : member)).join(" & ");
17
+ };
18
+ const MAX_RENDER_DEPTH = 8;
19
+ const hasUnresolvedRef = (schema, definitions, seen = new Set(), visited = new Set()) => {
20
+ if (visited.has(schema))
21
+ return false;
22
+ const nextVisited = new Set([...visited, schema]);
23
+ if (schema.$ref !== undefined) {
24
+ const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1];
25
+ const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment);
26
+ if (name === undefined || definitions[name] === undefined || seen.has(name))
27
+ return true;
28
+ if (hasUnresolvedRef(definitions[name], definitions, new Set([...seen, name]), nextVisited))
29
+ return true;
30
+ }
31
+ return [
32
+ ...(schema.anyOf ?? []),
33
+ ...(schema.oneOf ?? []),
34
+ ...(schema.allOf ?? []),
35
+ ...Object.values(schema.properties ?? {}),
36
+ ...(schema.items === undefined ? [] : [schema.items]),
37
+ ...(typeof schema.additionalProperties === "object" ? [schema.additionalProperties] : []),
38
+ ].some((item) => hasUnresolvedRef(item, definitions, seen, nextVisited));
39
+ };
40
+ const docTags = (schema) => {
41
+ const tags = [];
42
+ if (schema.deprecated === true)
43
+ tags.push("@deprecated");
44
+ if (schema.default !== undefined) {
45
+ try {
46
+ const rendered = JSON.stringify(schema.default);
47
+ if (rendered !== undefined)
48
+ tags.push(`@default ${rendered}`);
49
+ }
50
+ catch { }
51
+ }
52
+ if (typeof schema.format === "string")
53
+ tags.push(`@format ${schema.format}`);
54
+ if (typeof schema.minItems === "number")
55
+ tags.push(`@minItems ${schema.minItems}`);
56
+ if (typeof schema.maxItems === "number")
57
+ tags.push(`@maxItems ${schema.maxItems}`);
58
+ return tags;
59
+ };
60
+ // Neutralize `*\/` so model-provided schema text cannot terminate generated documentation.
61
+ const jsdoc = (description, tags, pad) => {
62
+ const lines = [...(description === undefined ? [] : description.split("\n")), ...tags].map((line) => line.replaceAll("*/", "* /").replace(/\s+$/, ""));
63
+ while (lines.length > 0 && lines[0].trim() === "")
64
+ lines.shift();
65
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "")
66
+ lines.pop();
67
+ if (lines.length === 0)
68
+ return "";
69
+ if (lines.length === 1)
70
+ return `${pad}/** ${lines[0]} */\n`;
71
+ const body = lines.map((line) => `${pad} *${line === "" ? "" : ` ${line}`}`).join("\n");
72
+ return `${pad}/**\n${body}\n${pad} */\n`;
73
+ };
74
+ const renderSchema = (schema, ctx, depth = 0, seen = new Set()) => {
75
+ if (depth > MAX_RENDER_DEPTH)
76
+ return "unknown";
77
+ const nested = schema.definitions === undefined && schema.$defs === undefined
78
+ ? ctx
79
+ : { ...ctx, definitions: { ...ctx.definitions, ...(schema.definitions ?? {}), ...(schema.$defs ?? {}) } };
80
+ if (schema.$ref) {
81
+ const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1];
82
+ const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment);
83
+ if (!name || !nested.definitions[name] || seen.has(name))
84
+ return "unknown";
85
+ return intersection([
86
+ renderSchema(nested.definitions[name], nested, depth, new Set([...seen, name])),
87
+ renderSchema({ ...schema, $ref: undefined }, nested, depth + 1, seen),
88
+ ]);
89
+ }
90
+ if (schema.const !== undefined)
91
+ return renderLiteral(schema.const);
92
+ if (schema.enum)
93
+ return schema.enum.map(renderLiteral).join(" | ");
94
+ const alternatives = schema.anyOf ?? schema.oneOf;
95
+ if (alternatives) {
96
+ if (alternatives.some((item) => item.type === "number") &&
97
+ alternatives.every((item) => item.type === "number" || effectNumberSentinel(item)))
98
+ return "number";
99
+ if (alternatives.length === 2 &&
100
+ alternatives[0]?.type === "object" &&
101
+ alternatives[0].properties === undefined &&
102
+ alternatives[1]?.type === "array" &&
103
+ alternatives[1].items === undefined) {
104
+ return "{}";
105
+ }
106
+ const members = alternatives.map((item) => renderSchema(item, nested, depth + 1, seen));
107
+ if (members.some((member) => member === "unknown"))
108
+ return "unknown";
109
+ return intersection([
110
+ members.join(" | "),
111
+ renderSchema({ ...schema, anyOf: undefined, oneOf: undefined }, nested, depth + 1, seen),
112
+ ]);
113
+ }
114
+ if (schema.allOf) {
115
+ const members = schema.allOf.map((item) => renderSchema(item, nested, depth + 1, seen));
116
+ if (schema.allOf.some((item) => hasUnresolvedRef(item, nested.definitions)))
117
+ return "unknown";
118
+ return intersection([renderSchema({ ...schema, allOf: undefined }, nested, depth + 1, seen), ...members]);
119
+ }
120
+ if (Array.isArray(schema.type)) {
121
+ return schema.type.map((item) => renderSchema({ ...schema, type: item }, nested, depth + 1, seen)).join(" | ");
122
+ }
123
+ if (schema.type === "string")
124
+ return "string";
125
+ if (schema.type === "number" || schema.type === "integer")
126
+ return "number";
127
+ if (schema.type === "boolean")
128
+ return "boolean";
129
+ if (schema.type === "null")
130
+ return "null";
131
+ if (schema.type === "array")
132
+ return `Array<${renderSchema(schema.items ?? {}, nested, depth + 1, seen)}>`;
133
+ if (schema.type === "object" || schema.properties) {
134
+ const required = new Set(schema.required ?? []);
135
+ const properties = Object.entries(schema.properties ?? {});
136
+ const additional = schema.additionalProperties;
137
+ const indexType = additional && typeof additional === "object" ? renderSchema(additional, nested, depth + 1, seen) : undefined;
138
+ const field = ([name, value]) => `${renderKey(name)}${required.has(name) ? "" : "?"}: ${renderSchema(value, nested, depth + 1, seen)}`;
139
+ if (!ctx.pretty) {
140
+ const fields = properties.map(field);
141
+ if (indexType !== undefined)
142
+ fields.push(`[key: string]: ${indexType}`);
143
+ return fields.length === 0 ? "{}" : `{ ${fields.join("; ")} }`;
144
+ }
145
+ if (properties.length === 0 && indexType === undefined)
146
+ return "{}";
147
+ const pad = " ".repeat(depth + 1);
148
+ const lines = properties.map((entry) => `${jsdoc(entry[1].description, docTags(entry[1]), pad)}${pad}${field(entry)},`);
149
+ if (indexType !== undefined)
150
+ lines.push(`${pad}[key: string]: ${indexType},`);
151
+ return `{\n${lines.join("\n")}\n${" ".repeat(depth)}}`;
152
+ }
153
+ return "unknown";
154
+ };
155
+ export const toTypeScript = (schema, decoded = false, pretty = false) => {
156
+ try {
157
+ const visible = decoded ? Schema.toType(schema) : schema;
158
+ const document = Schema.toJsonSchemaDocument(visible);
159
+ return renderSchema(document.schema, { definitions: document.definitions ?? {}, pretty });
160
+ }
161
+ catch {
162
+ return "unknown";
163
+ }
164
+ };
165
+ export const jsonSchemaToTypeScript = (schema, pretty = false) => {
166
+ try {
167
+ return renderSchema(schema, { definitions: { ...(schema.definitions ?? {}), ...(schema.$defs ?? {}) }, pretty });
168
+ }
169
+ catch {
170
+ return "unknown";
171
+ }
172
+ };
173
+ export const inputProperties = (tool) => {
174
+ try {
175
+ const document = isEffectSchema(tool.input)
176
+ ? Schema.toJsonSchemaDocument(tool.input)
177
+ : {
178
+ schema: tool.input,
179
+ definitions: { ...(tool.input.definitions ?? {}), ...(tool.input.$defs ?? {}) },
180
+ };
181
+ const definitions = document.definitions ?? {};
182
+ let schema = document.schema;
183
+ if (schema.$ref !== undefined) {
184
+ const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1];
185
+ const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment);
186
+ const resolved = name === undefined ? undefined : definitions[name];
187
+ if (resolved === undefined)
188
+ return [];
189
+ schema = resolved;
190
+ }
191
+ const required = new Set(schema.required ?? []);
192
+ return Object.entries(schema.properties ?? {}).map(([name, value]) => ({
193
+ name,
194
+ description: typeof value.description === "string" ? value.description : undefined,
195
+ required: required.has(name),
196
+ }));
197
+ }
198
+ catch {
199
+ return [];
200
+ }
201
+ };
202
+ export const inputTypeScript = (tool, pretty = false) => isEffectSchema(tool.input) ? toTypeScript(tool.input, false, pretty) : jsonSchemaToTypeScript(tool.input, pretty);
203
+ export const outputTypeScript = (tool, pretty = false) => tool.output === undefined
204
+ ? "void"
205
+ : isEffectSchema(tool.output)
206
+ ? toTypeScript(tool.output, true, pretty)
207
+ : jsonSchemaToTypeScript(tool.output, pretty);
208
+ export const decodeInput = (tool, value) => isEffectSchema(tool.input) ? Schema.decodeUnknownSync(tool.input)(value) : value;
209
+ export const decodeOutput = (tool, value) => tool.output === undefined
210
+ ? undefined
211
+ : isEffectSchema(tool.output)
212
+ ? Schema.decodeUnknownSync(tool.output)(value)
213
+ : value;
package/dist/tool.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { Effect, Schema } from "effect";
2
+ /**
3
+ * JSON Schema subset for model-visible signatures. CodeMode does not validate values against
4
+ * these schemas.
5
+ */
6
+ export type JsonSchema = {
7
+ readonly type?: string | ReadonlyArray<string>;
8
+ readonly enum?: ReadonlyArray<unknown>;
9
+ readonly const?: unknown;
10
+ readonly anyOf?: ReadonlyArray<JsonSchema>;
11
+ readonly oneOf?: ReadonlyArray<JsonSchema>;
12
+ readonly allOf?: ReadonlyArray<JsonSchema>;
13
+ readonly properties?: Readonly<Record<string, JsonSchema>>;
14
+ readonly required?: ReadonlyArray<string>;
15
+ readonly items?: JsonSchema;
16
+ readonly additionalProperties?: boolean | JsonSchema;
17
+ readonly description?: string;
18
+ readonly default?: unknown;
19
+ readonly format?: string;
20
+ readonly deprecated?: boolean;
21
+ readonly minItems?: number;
22
+ readonly maxItems?: number;
23
+ readonly $ref?: string;
24
+ readonly $defs?: Readonly<Record<string, JsonSchema>>;
25
+ readonly definitions?: Readonly<Record<string, JsonSchema>>;
26
+ };
27
+ /** Either a validating Effect Schema or a render-only JSON Schema document. */
28
+ export type SchemaType = Schema.Decoder<unknown> | JsonSchema;
29
+ /** Executable tool exposed through CodeMode's `tools` object. */
30
+ export type Tool<R = never> = {
31
+ readonly _tag: "CodeModeTool";
32
+ readonly description: string;
33
+ readonly input: SchemaType;
34
+ readonly output: SchemaType | undefined;
35
+ readonly execute: (input: unknown) => Effect.Effect<unknown, unknown, R>;
36
+ };
37
+ type InputType<S> = S extends Schema.Decoder<unknown> ? S["Type"] : unknown;
38
+ type ResultType<S> = S extends undefined ? void : S extends Schema.Decoder<unknown> ? S["Encoded"] : unknown;
39
+ /** Options for declaring one CodeMode tool. */
40
+ export type Options<I extends SchemaType, O extends SchemaType | undefined, R = never> = {
41
+ readonly description: string;
42
+ readonly input: I;
43
+ readonly output?: O;
44
+ readonly execute: (input: InputType<I>) => Effect.Effect<ResultType<O>, unknown, R>;
45
+ };
46
+ export declare const isTool: <R = never>(value: unknown) => value is Tool<R>;
47
+ /**
48
+ * Declares one schema-described tool available to a CodeMode program through `tools.*`.
49
+ *
50
+ * Effect Schemas validate values; JSON Schemas only shape the model-visible signature.
51
+ * Without `output`, results are exposed as `void`. Hosts remain responsible for authorization
52
+ * and durable side effects.
53
+ */
54
+ export declare const make: <I extends SchemaType, const O extends SchemaType | undefined = undefined, R = never>(options: Options<I, O, R>) => Tool<R>;
55
+ export {};
package/dist/tool.js ADDED
@@ -0,0 +1,21 @@
1
+ import { Effect, Schema } from "effect";
2
+ // Object.hasOwn: an inherited _tag must not classify a namespace as a Tool.
3
+ export const isTool = (value) => typeof value === "object" &&
4
+ value !== null &&
5
+ "_tag" in value &&
6
+ Object.hasOwn(value, "_tag") &&
7
+ value._tag === "CodeModeTool";
8
+ /**
9
+ * Declares one schema-described tool available to a CodeMode program through `tools.*`.
10
+ *
11
+ * Effect Schemas validate values; JSON Schemas only shape the model-visible signature.
12
+ * Without `output`, results are exposed as `void`. Hosts remain responsible for authorization
13
+ * and durable side effects.
14
+ */
15
+ export const make = (options) => ({
16
+ _tag: "CodeModeTool",
17
+ description: options.description,
18
+ input: options.input,
19
+ output: options.output,
20
+ execute: (input) => options.execute(input),
21
+ });
@@ -0,0 +1,4 @@
1
+ import type { Tool } from "./tool.js";
2
+ export type Tools<R = never> = {
3
+ readonly [name: string]: Tool<R> | Tools<R>;
4
+ };
package/dist/tools.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import type { Fiber } from "effect";
2
+ export declare class CodeModePromise {
3
+ readonly fiber: Fiber.Fiber<unknown, unknown>;
4
+ constructor(fiber: Fiber.Fiber<unknown, unknown>);
5
+ }
6
+ export declare class CodeModeDate {
7
+ time: number;
8
+ constructor(time: number);
9
+ }
10
+ export declare class CodeModeRegExp {
11
+ readonly regex: RegExp;
12
+ constructor(pattern: string, flags: string);
13
+ get lastIndex(): unknown;
14
+ set lastIndex(value: unknown);
15
+ }
16
+ export declare class CodeModeMap {
17
+ readonly map: Map<unknown, unknown>;
18
+ }
19
+ export declare class CodeModeSet {
20
+ readonly set: Set<unknown>;
21
+ }
22
+ export declare class CodeModeURLSearchParams {
23
+ readonly params: URLSearchParams;
24
+ constructor(params: URLSearchParams);
25
+ }
26
+ export declare class CodeModeURL {
27
+ readonly url: URL;
28
+ readonly searchParams: CodeModeURLSearchParams;
29
+ constructor(url: URL);
30
+ }
31
+ export declare const isCodeModeValue: (value: unknown) => value is CodeModeDate | CodeModeRegExp | CodeModeMap | CodeModeSet | CodeModeURL | CodeModeURLSearchParams;
package/dist/values.js ADDED
@@ -0,0 +1,50 @@
1
+ export class CodeModePromise {
2
+ fiber;
3
+ constructor(fiber) {
4
+ this.fiber = fiber;
5
+ }
6
+ }
7
+ export class CodeModeDate {
8
+ time;
9
+ constructor(time) {
10
+ this.time = time;
11
+ }
12
+ }
13
+ export class CodeModeRegExp {
14
+ regex;
15
+ constructor(pattern, flags) {
16
+ this.regex = new RegExp(pattern, flags);
17
+ }
18
+ get lastIndex() {
19
+ return Reflect.get(this.regex, "lastIndex");
20
+ }
21
+ set lastIndex(value) {
22
+ Reflect.set(this.regex, "lastIndex", value);
23
+ }
24
+ }
25
+ export class CodeModeMap {
26
+ map = new Map();
27
+ }
28
+ export class CodeModeSet {
29
+ set = new Set();
30
+ }
31
+ export class CodeModeURLSearchParams {
32
+ params;
33
+ constructor(params) {
34
+ this.params = params;
35
+ }
36
+ }
37
+ export class CodeModeURL {
38
+ url;
39
+ searchParams;
40
+ constructor(url) {
41
+ this.url = url;
42
+ this.searchParams = new CodeModeURLSearchParams(url.searchParams);
43
+ }
44
+ }
45
+ export const isCodeModeValue = (value) => value instanceof CodeModeDate ||
46
+ value instanceof CodeModeRegExp ||
47
+ value instanceof CodeModeMap ||
48
+ value instanceof CodeModeSet ||
49
+ value instanceof CodeModeURL ||
50
+ value instanceof CodeModeURLSearchParams;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package.json",
3
+ "name": "@opencode-ai/codemode",
4
+ "version": "0.0.0-beta-17492",
5
+ "description": "Effect-native confined code execution over schema-described tools",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/anomalyco/opencode.git",
11
+ "directory": "packages/codemode"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "import": "./dist/index.js",
22
+ "types": "./dist/index.d.ts"
23
+ }
24
+ },
25
+ "imports": {
26
+ "#transpile": {
27
+ "workerd": "./src/interpreter/transpile.workerd.ts",
28
+ "default": "./src/interpreter/transpile.node.ts"
29
+ }
30
+ },
31
+ "scripts": {
32
+ "build": "bun run script/build.ts",
33
+ "typecheck": "tsgo --noEmit",
34
+ "test": "bun test"
35
+ },
36
+ "dependencies": {
37
+ "acorn": "8.15.0",
38
+ "effect": "4.0.0-beta.101",
39
+ "typescript": "5.8.2"
40
+ },
41
+ "devDependencies": {
42
+ "@tsconfig/bun": "1.0.9",
43
+ "@types/bun": "1.3.13",
44
+ "@typescript/native-preview": "7.0.0-dev.20251207.1"
45
+ }
46
+ }