exoagent 0.0.13 → 0.0.14

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Whitelists for exoeval — shared between the evaluator and the eslint rule.
3
+ * Single source of truth: if exoeval adds a node type, the lint rule allows
4
+ * it automatically.
5
+ */
6
+ export declare const allowedExpressions: readonly ["ArrayExpression", "ArrowFunctionExpression", "AwaitExpression", "BinaryExpression", "CallExpression", "ConditionalExpression", "Identifier", "Literal", "LogicalExpression", "MemberExpression", "NewExpression", "ObjectExpression", "TemplateLiteral", "UnaryExpression", "ChainExpression"];
7
+ export declare const allowedStatements: readonly ["BlockStatement", "EmptyStatement", "VariableDeclaration", "ExpressionStatement", "ReturnStatement", "IfStatement"];
8
+ /** Allowed at module top-level (exoImport). */
9
+ export declare const allowedModuleDeclarations: readonly ["ExportDefaultDeclaration"];
@@ -1,6 +1,8 @@
1
1
  import { ExpressionContext } from './expr';
2
- export declare class ExoArray<T = unknown> {
2
+ import { IExoArray, IExoBoolean, IExoDate, IExoNumber, IExoString } from './lib';
3
+ export declare class ExoArray<T = unknown> implements IExoArray<T> {
3
4
  constructor(...args: Parameters<typeof Array>);
5
+ [index: number]: T;
4
6
  get length(): number;
5
7
  get map(): <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[];
6
8
  get filter(): {
@@ -33,6 +35,7 @@ export declare class ExoArray<T = unknown> {
33
35
  (predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean;
34
36
  };
35
37
  get flatMap(): <U, This = undefined>(callback: (this: This, value: any, index: number, array: any[]) => U | readonly U[], thisArg?: This | undefined) => U[];
38
+ get forEach(): (callbackfn: (value: any, index: number, array: any[]) => void, thisArg?: any) => void;
36
39
  get toSorted(): (compareFn?: ((a: any, b: any) => number) | undefined) => any[];
37
40
  get at(): (index: number) => any;
38
41
  get slice(): (start?: number, end?: number) => any[];
@@ -54,10 +57,11 @@ export declare class ExoArray<T = unknown> {
54
57
  (start: number, deleteCount?: number): any[];
55
58
  };
56
59
  get with(): (index: number, value: any) => any[];
60
+ get toString(): () => string;
57
61
  static from(arrayLike: ArrayLike<unknown>): unknown[];
58
62
  static isArray(value: unknown): value is any[];
59
63
  }
60
- export declare class ExoString {
64
+ export declare class ExoString implements IExoString {
61
65
  constructor(...args: Parameters<typeof String>);
62
66
  get length(): number;
63
67
  get at(): (index: number) => string | undefined;
@@ -100,8 +104,9 @@ export declare class ExoString {
100
104
  get trim(): () => string;
101
105
  get trimEnd(): () => string;
102
106
  get trimStart(): () => string;
107
+ get toString(): () => string;
103
108
  }
104
- export declare class ExoDate {
109
+ export declare class ExoDate implements IExoDate {
105
110
  constructor();
106
111
  constructor(value: string | number | Date);
107
112
  constructor(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number);
@@ -130,6 +135,7 @@ export declare class ExoDate {
130
135
  (locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
131
136
  };
132
137
  get valueOf(): () => number;
138
+ get toString(): () => string;
133
139
  static now(): number;
134
140
  static parse(dateString: string): number;
135
141
  }
@@ -141,9 +147,10 @@ export declare class ExoObject {
141
147
  [k: string]: unknown;
142
148
  };
143
149
  }
144
- export declare class ExoBoolean {
150
+ export declare class ExoBoolean implements IExoBoolean {
145
151
  constructor(...args: Parameters<typeof Boolean>);
146
152
  get valueOf(): () => boolean;
153
+ get toString(): () => string;
147
154
  }
148
155
  export declare class ExoJSON {
149
156
  static parse(text: string): any;
@@ -163,8 +170,16 @@ export declare class ExoMath {
163
170
  static sign(x: number): number;
164
171
  static trunc(x: number): number;
165
172
  }
166
- export declare class ExoNumber {
173
+ export declare class ExoPromise {
174
+ static all(values: unknown[]): Promise<unknown[]>;
175
+ static allSettled(values: unknown[]): Promise<PromiseSettledResult<unknown>[]>;
176
+ static race(values: unknown[]): Promise<unknown>;
177
+ static resolve(value: unknown): Promise<unknown>;
178
+ static reject(reason: unknown): Promise<never>;
179
+ }
180
+ export declare class ExoNumber implements IExoNumber {
167
181
  constructor(...args: Parameters<typeof Number>);
182
+ get toString(): (radix?: number) => string;
168
183
  static parseInt(s: string, radix?: number): number;
169
184
  static parseFloat(s: string): number;
170
185
  static isNaN(value: unknown): boolean;
@@ -38,10 +38,17 @@ export declare class Evaluator<Expr> {
38
38
  assertAllowedProperty(key: string | number, node: acorn.Node): void;
39
39
  defineProperty(obj: object, key: string | number, value: unknown, node: acorn.Node): void;
40
40
  getExoProperty(obj: Expr, key: string | number, node: acorn.Node, optional: boolean): EvalResult<Expr>;
41
+ /**
42
+ * Convert a value to string for interpolation/concatenation.
43
+ * Calls .toString() via getExoProperty if available.
44
+ */
45
+ toString(obj: Expr, node: acorn.Node): EvalResult<Expr, string>;
41
46
  getBuiltinPrototype(value: unknown): unknown;
42
47
  ObjectExpression(node: acorn.ObjectExpression): EvalResult<Expr>;
43
48
  AwaitExpression(node: acorn.AwaitExpression): EvalResult<Expr>;
44
- evalStatements(statements: (acorn.Statement | acorn.ModuleDeclaration)[]): EvalResult<Expr>;
49
+ evalStatements(statements: (acorn.Statement | acorn.ModuleDeclaration)[], { module }?: {
50
+ module?: boolean | undefined;
51
+ }): EvalResult<Expr>;
45
52
  evalFunctionCall(node: acorn.Function, args: Expr[]): EvalResult<Expr>;
46
53
  ArrowFunctionExpression(node: acorn.ArrowFunctionExpression): EvalResult<Expr>;
47
54
  UnaryExpression(node: acorn.UnaryExpression): EvalResult<Expr>;
@@ -54,6 +61,8 @@ export declare class Evaluator<Expr> {
54
61
  $(node: acorn.Expression): EvalResult<Expr, unknown>;
55
62
  makeReturn(value: Expr, node: acorn.Node): EvalResult<Expr>;
56
63
  Statement(node: acorn.Statement): EvalResult<Expr>;
57
- Program(node: acorn.Program): Expr | Promise<Expr>;
64
+ Program(node: acorn.Program, { module }?: {
65
+ module?: boolean | undefined;
66
+ }): Expr | Promise<Expr>;
58
67
  }
59
68
  export {};
@@ -3,4 +3,14 @@ export { asToolFn } from './tool';
3
3
  export type { ToolFunction } from './tool';
4
4
  export declare function exoEval(code: string): unknown;
5
5
  export declare function exoEval<T>(code: string, ctx: ExpressionContext<T>): T;
6
+ export declare function exoImport(code: string): {
7
+ [key: string]: unknown;
8
+ } | Promise<{
9
+ [key: string]: unknown;
10
+ }>;
11
+ export declare function exoImport<T>(code: string, ctx: ExpressionContext<T>): {
12
+ [key: string]: unknown;
13
+ } | Promise<{
14
+ [key: string]: unknown;
15
+ }>;
6
16
  export declare function exoFn<T extends (...args: any[]) => unknown>(fn: T): T;
@@ -0,0 +1 @@
1
+ export type { IExoArray, IExoBoolean, IExoDate, IExoJSON, IExoMath, IExoNumber, IExoObject, IExoPromise, IExoString } from './types';
@@ -23,6 +23,11 @@ export declare const registerToolField: (obj: unknown, key: string) => void;
23
23
  * Fields: adds field name to toolFieldsSymbol Set on instance.
24
24
  * If value is a function with schemas, wraps with asTool.
25
25
  * Classes: returns replacement class with constructor validation + toolSymbol.
26
+ *
27
+ * NOTE: @tool() on a class means `new MyClass(...)` is callable by sandboxed code
28
+ * that has a reference to it. This is intended for builtins (e.g. `new Date`, `new Map`)
29
+ * where construction is part of the API. For capability classes where you want to expose
30
+ * only methods (not construction), don't decorate the class — just decorate the methods.
26
31
  */
27
32
  export declare function tool<Schemas extends StandardSchemaV1[]>(...argSchemas: Schemas): {
28
33
  <This, Value extends (this: This, ...args: SchemasToParams<Schemas>) => any>(target: Value, context: ClassMethodDecoratorContext<This, Value>): Value;
package/dist/index.mjs CHANGED
@@ -45,10 +45,10 @@ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use
45
45
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
46
46
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
47
47
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
48
- var _isArray_dec, _from_dec, _with_dec, _toSpliced_dec, _toReversed_dec, _values_dec, _keys_dec, _entries_dec, _flat_dec, _includes_dec, _lastIndexOf_dec, _indexOf_dec, _concat_dec, _join_dec, _slice_dec, _at_dec, _toSorted_dec, _flatMap_dec, _every_dec, _some_dec, _findLastIndex_dec, _findLast_dec, _findIndex_dec, _find_dec, _reduceRight_dec, _reduce_dec, _filter_dec, _map_dec, _length_dec, _ExoArray_decorators, _init, _trimStart_dec, _trimEnd_dec, _trim_dec, _toUpperCase_dec, _toLowerCase_dec, _substring_dec, _startsWith_dec, _split_dec, _slice_dec2, _replaceAll_dec, _replace_dec, _repeat_dec, _padStart_dec, _padEnd_dec, _lastIndexOf_dec2, _indexOf_dec2, _includes_dec2, _endsWith_dec, _concat_dec2, _codePointAt_dec, _charCodeAt_dec, _charAt_dec, _at_dec2, _length_dec2, _ExoString_decorators, _init2, _parse_dec, _now_dec, _valueOf_dec, _toLocaleString_dec, _toLocaleTimeString_dec, _toLocaleDateString_dec, _toISOString_dec, _getMilliseconds_dec, _getSeconds_dec, _getMinutes_dec, _getHours_dec, _getDate_dec, _getMonth_dec, _getFullYear_dec, _getTime_dec, _ExoDate_decorators, _init3, _fromEntries_dec, _entries_dec2, _values_dec2, _keys_dec2, _init4, _valueOf_dec2, _ExoBoolean_decorators, _init5, _stringify_dec, _parse_dec2, _init6, _trunc_dec, _sign_dec, _random_dec, _log_dec, _pow_dec, _sqrt_dec, _abs_dec, _ceil_dec, _floor_dec, _round_dec, _max_dec, _min_dec, _init7, _isInteger_dec, _isFinite_dec, _isNaN_dec, _parseFloat_dec, _parseInt_dec, _ExoNumber_decorators, _init8;
48
+ var _isArray_dec, _from_dec, _toString_dec, _with_dec, _toSpliced_dec, _toReversed_dec, _values_dec, _keys_dec, _entries_dec, _flat_dec, _includes_dec, _lastIndexOf_dec, _indexOf_dec, _concat_dec, _join_dec, _slice_dec, _at_dec, _toSorted_dec, _forEach_dec, _flatMap_dec, _every_dec, _some_dec, _findLastIndex_dec, _findLast_dec, _findIndex_dec, _find_dec, _reduceRight_dec, _reduce_dec, _filter_dec, _map_dec, _length_dec, _ExoArray_decorators, _init, _toString_dec2, _trimStart_dec, _trimEnd_dec, _trim_dec, _toUpperCase_dec, _toLowerCase_dec, _substring_dec, _startsWith_dec, _split_dec, _slice_dec2, _replaceAll_dec, _replace_dec, _repeat_dec, _padStart_dec, _padEnd_dec, _lastIndexOf_dec2, _indexOf_dec2, _includes_dec2, _endsWith_dec, _concat_dec2, _codePointAt_dec, _charCodeAt_dec, _charAt_dec, _at_dec2, _length_dec2, _ExoString_decorators, _init2, _parse_dec, _now_dec, _toString_dec3, _valueOf_dec, _toLocaleString_dec, _toLocaleTimeString_dec, _toLocaleDateString_dec, _toISOString_dec, _getMilliseconds_dec, _getSeconds_dec, _getMinutes_dec, _getHours_dec, _getDate_dec, _getMonth_dec, _getFullYear_dec, _getTime_dec, _ExoDate_decorators, _init3, _fromEntries_dec, _entries_dec2, _values_dec2, _keys_dec2, _init4, _toString_dec4, _valueOf_dec2, _ExoBoolean_decorators, _init5, _stringify_dec, _parse_dec2, _init6, _trunc_dec, _sign_dec, _random_dec, _log_dec, _pow_dec, _sqrt_dec, _abs_dec, _ceil_dec, _floor_dec, _round_dec, _max_dec, _min_dec, _init7, _reject_dec, _resolve_dec, _race_dec, _allSettled_dec, _all_dec, _init8, _isInteger_dec, _isFinite_dec, _isNaN_dec, _parseFloat_dec, _parseInt_dec, _toString_dec5, _ExoNumber_decorators, _init9;
49
49
  import z, { z as z$1 } from "zod";
50
50
  import sjson from "secure-json-parse";
51
- import { t as toolFieldsSymbol, a as tool, e as expr, f as fn, i as isExprFunction, b as isToolableFunction, g as getTool, c as isToolableConstructor, d as asToolFn } from "./tool-DGs9ZxVn.js";
51
+ import { t as toolFieldsSymbol, a as tool, e as expr, f as fn, i as isExprFunction, b as isToolableFunction, g as getTool, c as isToolableConstructor, d as asToolFn } from "./tool-5wSlXWJ2.js";
52
52
  import * as z4 from "zod/v4";
53
53
  import { ZodFirstPartyTypeKind } from "zod/v3";
54
54
  import camelCase from "camelcase";
@@ -5791,7 +5791,7 @@ class Invariant {
5791
5791
  }
5792
5792
  }
5793
5793
  }
5794
- _ExoArray_decorators = [tool()], _length_dec = [tool()], _map_dec = [tool(fn.returns(z.any()))], _filter_dec = [tool(fn.returns(z.any()))], _reduce_dec = [tool(fn.returns(z.any()), z.any().optional())], _reduceRight_dec = [tool(fn.returns(z.any()), z.any().optional())], _find_dec = [tool(fn.returns(z.any()))], _findIndex_dec = [tool(fn.returns(z.any()))], _findLast_dec = [tool(fn.returns(z.any()))], _findLastIndex_dec = [tool(fn.returns(z.any()))], _some_dec = [tool(fn.returns(z.any()))], _every_dec = [tool(fn.returns(z.any()))], _flatMap_dec = [tool(fn.returns(z.any()))], _toSorted_dec = [tool(fn.returns(z.any()).optional())], _at_dec = [tool(z.number())], _slice_dec = [tool(z.number().optional(), z.number().optional())], _join_dec = [tool(z.string().optional())], _concat_dec = [tool(z.array(z.any()))], _indexOf_dec = [tool(z.any(), z.number().optional())], _lastIndexOf_dec = [tool(z.any(), z.number().optional())], _includes_dec = [tool(z.any())], _flat_dec = [tool(z.number().optional())], _entries_dec = [tool()], _keys_dec = [tool()], _values_dec = [tool()], _toReversed_dec = [tool()], _toSpliced_dec = [tool(z.number(), z.number().optional(), z.any().optional())], _with_dec = [tool(z.number(), z.any())], _from_dec = [tool(z.array(z.any()))], _isArray_dec = [tool(z.any())];
5794
+ _ExoArray_decorators = [tool()], _length_dec = [tool()], _map_dec = [tool(fn.returns(z.any()))], _filter_dec = [tool(fn.returns(z.any()))], _reduce_dec = [tool(fn.returns(z.any()), z.any().optional())], _reduceRight_dec = [tool(fn.returns(z.any()), z.any().optional())], _find_dec = [tool(fn.returns(z.any()))], _findIndex_dec = [tool(fn.returns(z.any()))], _findLast_dec = [tool(fn.returns(z.any()))], _findLastIndex_dec = [tool(fn.returns(z.any()))], _some_dec = [tool(fn.returns(z.any()))], _every_dec = [tool(fn.returns(z.any()))], _flatMap_dec = [tool(fn.returns(z.any()))], _forEach_dec = [tool(fn.returns(z.void()))], _toSorted_dec = [tool(fn.returns(z.any()).optional())], _at_dec = [tool(z.number())], _slice_dec = [tool(z.number().optional(), z.number().optional())], _join_dec = [tool(z.string().optional())], _concat_dec = [tool(z.array(z.any()))], _indexOf_dec = [tool(z.any(), z.number().optional())], _lastIndexOf_dec = [tool(z.any(), z.number().optional())], _includes_dec = [tool(z.any())], _flat_dec = [tool(z.number().optional())], _entries_dec = [tool()], _keys_dec = [tool()], _values_dec = [tool()], _toReversed_dec = [tool()], _toSpliced_dec = [tool(z.number(), z.number().optional(), z.any().optional())], _with_dec = [tool(z.number(), z.any())], _toString_dec = [tool()], _from_dec = [tool(z.array(z.any()))], _isArray_dec = [tool(z.any())];
5795
5795
  class ExoArray {
5796
5796
  constructor(...args) {
5797
5797
  __runInitializers(_init, 5, this);
@@ -5836,6 +5836,9 @@ class ExoArray {
5836
5836
  get flatMap() {
5837
5837
  return Array.prototype.flatMap;
5838
5838
  }
5839
+ get forEach() {
5840
+ return Array.prototype.forEach;
5841
+ }
5839
5842
  get toSorted() {
5840
5843
  return Array.prototype.toSorted;
5841
5844
  }
@@ -5881,6 +5884,9 @@ class ExoArray {
5881
5884
  get with() {
5882
5885
  return Array.prototype.with;
5883
5886
  }
5887
+ get toString() {
5888
+ return Array.prototype.toString;
5889
+ }
5884
5890
  static from(arrayLike) {
5885
5891
  return Array.from(arrayLike);
5886
5892
  }
@@ -5903,6 +5909,7 @@ __decorateElement(_init, 2, "findLastIndex", _findLastIndex_dec, ExoArray);
5903
5909
  __decorateElement(_init, 2, "some", _some_dec, ExoArray);
5904
5910
  __decorateElement(_init, 2, "every", _every_dec, ExoArray);
5905
5911
  __decorateElement(_init, 2, "flatMap", _flatMap_dec, ExoArray);
5912
+ __decorateElement(_init, 2, "forEach", _forEach_dec, ExoArray);
5906
5913
  __decorateElement(_init, 2, "toSorted", _toSorted_dec, ExoArray);
5907
5914
  __decorateElement(_init, 2, "at", _at_dec, ExoArray);
5908
5915
  __decorateElement(_init, 2, "slice", _slice_dec, ExoArray);
@@ -5918,10 +5925,11 @@ __decorateElement(_init, 2, "values", _values_dec, ExoArray);
5918
5925
  __decorateElement(_init, 2, "toReversed", _toReversed_dec, ExoArray);
5919
5926
  __decorateElement(_init, 2, "toSpliced", _toSpliced_dec, ExoArray);
5920
5927
  __decorateElement(_init, 2, "with", _with_dec, ExoArray);
5928
+ __decorateElement(_init, 2, "toString", _toString_dec, ExoArray);
5921
5929
  ExoArray = __decorateElement(_init, 0, "ExoArray", _ExoArray_decorators, ExoArray);
5922
5930
  __runInitializers(_init, 3, ExoArray);
5923
5931
  __runInitializers(_init, 1, ExoArray);
5924
- _ExoString_decorators = [tool(z.union([z.string(), z.number(), z.instanceof(Date), z.boolean(), z.null(), z.undefined(), z.bigint()]))], _length_dec2 = [tool()], _at_dec2 = [tool(z.number())], _charAt_dec = [tool(z.number())], _charCodeAt_dec = [tool(z.number())], _codePointAt_dec = [tool(z.number())], _concat_dec2 = [tool(z.string())], _endsWith_dec = [tool(z.string(), z.number().optional())], _includes_dec2 = [tool(z.string(), z.number().optional())], _indexOf_dec2 = [tool(z.string(), z.number().optional())], _lastIndexOf_dec2 = [tool(z.string(), z.number().optional())], _padEnd_dec = [tool(z.number(), z.string().optional())], _padStart_dec = [tool(z.number(), z.string().optional())], _repeat_dec = [tool(z.number())], _replace_dec = [tool(z.string(), z.string())], _replaceAll_dec = [tool(z.string(), z.string())], _slice_dec2 = [tool(z.number().optional(), z.number().optional())], _split_dec = [tool(z.string(), z.number().optional())], _startsWith_dec = [tool(z.string(), z.number().optional())], _substring_dec = [tool(z.number().optional(), z.number().optional())], _toLowerCase_dec = [tool()], _toUpperCase_dec = [tool()], _trim_dec = [tool()], _trimEnd_dec = [tool()], _trimStart_dec = [tool()];
5932
+ _ExoString_decorators = [tool(z.union([z.string(), z.number(), z.instanceof(Date), z.boolean(), z.null(), z.undefined(), z.bigint()]))], _length_dec2 = [tool()], _at_dec2 = [tool(z.number())], _charAt_dec = [tool(z.number())], _charCodeAt_dec = [tool(z.number())], _codePointAt_dec = [tool(z.number())], _concat_dec2 = [tool(z.string())], _endsWith_dec = [tool(z.string(), z.number().optional())], _includes_dec2 = [tool(z.string(), z.number().optional())], _indexOf_dec2 = [tool(z.string(), z.number().optional())], _lastIndexOf_dec2 = [tool(z.string(), z.number().optional())], _padEnd_dec = [tool(z.number(), z.string().optional())], _padStart_dec = [tool(z.number(), z.string().optional())], _repeat_dec = [tool(z.number())], _replace_dec = [tool(z.string(), z.string())], _replaceAll_dec = [tool(z.string(), z.string())], _slice_dec2 = [tool(z.number().optional(), z.number().optional())], _split_dec = [tool(z.string(), z.number().optional())], _startsWith_dec = [tool(z.string(), z.number().optional())], _substring_dec = [tool(z.number().optional(), z.number().optional())], _toLowerCase_dec = [tool()], _toUpperCase_dec = [tool()], _trim_dec = [tool()], _trimEnd_dec = [tool()], _trimStart_dec = [tool()], _toString_dec2 = [tool()];
5925
5933
  class ExoString {
5926
5934
  constructor(...args) {
5927
5935
  __runInitializers(_init2, 5, this);
@@ -6002,6 +6010,9 @@ class ExoString {
6002
6010
  get trimStart() {
6003
6011
  return String.prototype.trimStart;
6004
6012
  }
6013
+ get toString() {
6014
+ return String.prototype.toString;
6015
+ }
6005
6016
  }
6006
6017
  _init2 = __decoratorStart(null);
6007
6018
  __decorateElement(_init2, 2, "length", _length_dec2, ExoString);
@@ -6028,9 +6039,10 @@ __decorateElement(_init2, 2, "toUpperCase", _toUpperCase_dec, ExoString);
6028
6039
  __decorateElement(_init2, 2, "trim", _trim_dec, ExoString);
6029
6040
  __decorateElement(_init2, 2, "trimEnd", _trimEnd_dec, ExoString);
6030
6041
  __decorateElement(_init2, 2, "trimStart", _trimStart_dec, ExoString);
6042
+ __decorateElement(_init2, 2, "toString", _toString_dec2, ExoString);
6031
6043
  ExoString = __decorateElement(_init2, 0, "ExoString", _ExoString_decorators, ExoString);
6032
6044
  __runInitializers(_init2, 1, ExoString);
6033
- _ExoDate_decorators = [tool(z.union([z.string(), z.number(), z.instanceof(Date)]).optional())], _getTime_dec = [tool()], _getFullYear_dec = [tool()], _getMonth_dec = [tool()], _getDate_dec = [tool()], _getHours_dec = [tool()], _getMinutes_dec = [tool()], _getSeconds_dec = [tool()], _getMilliseconds_dec = [tool()], _toISOString_dec = [tool()], _toLocaleDateString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _toLocaleTimeString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _toLocaleString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _valueOf_dec = [tool()], _now_dec = [tool()], _parse_dec = [tool(z.string())];
6045
+ _ExoDate_decorators = [tool(z.union([z.string(), z.number(), z.instanceof(Date)]).optional())], _getTime_dec = [tool()], _getFullYear_dec = [tool()], _getMonth_dec = [tool()], _getDate_dec = [tool()], _getHours_dec = [tool()], _getMinutes_dec = [tool()], _getSeconds_dec = [tool()], _getMilliseconds_dec = [tool()], _toISOString_dec = [tool()], _toLocaleDateString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _toLocaleTimeString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _toLocaleString_dec = [tool(z.string().optional(), z.record(z.string(), z.union([z.string(), z.boolean(), z.undefined()])).optional())], _valueOf_dec = [tool()], _toString_dec3 = [tool()], _now_dec = [tool()], _parse_dec = [tool(z.string())];
6034
6046
  class ExoDate {
6035
6047
  constructor(...args) {
6036
6048
  __runInitializers(_init3, 5, this);
@@ -6075,6 +6087,9 @@ class ExoDate {
6075
6087
  get valueOf() {
6076
6088
  return Date.prototype.valueOf;
6077
6089
  }
6090
+ get toString() {
6091
+ return Date.prototype.toString;
6092
+ }
6078
6093
  static now() {
6079
6094
  return Date.now();
6080
6095
  }
@@ -6098,6 +6113,7 @@ __decorateElement(_init3, 2, "toLocaleDateString", _toLocaleDateString_dec, ExoD
6098
6113
  __decorateElement(_init3, 2, "toLocaleTimeString", _toLocaleTimeString_dec, ExoDate);
6099
6114
  __decorateElement(_init3, 2, "toLocaleString", _toLocaleString_dec, ExoDate);
6100
6115
  __decorateElement(_init3, 2, "valueOf", _valueOf_dec, ExoDate);
6116
+ __decorateElement(_init3, 2, "toString", _toString_dec3, ExoDate);
6101
6117
  ExoDate = __decorateElement(_init3, 0, "ExoDate", _ExoDate_decorators, ExoDate);
6102
6118
  __runInitializers(_init3, 3, ExoDate);
6103
6119
  __runInitializers(_init3, 1, ExoDate);
@@ -6107,20 +6123,23 @@ _keys_dec2 = [expr()], _values_dec2 = [expr()], _entries_dec2 = [expr()], _fromE
6107
6123
  class ExoObject {
6108
6124
  static keys(ctx, obj) {
6109
6125
  const seq = ctx.sequence(obj);
6110
- if (!isPlainObject(seq))
6126
+ if (!isPlainObject(seq)) {
6111
6127
  throw new TypeError("Object.keys requires an object");
6128
+ }
6112
6129
  return ctx.distribute(Object.keys(seq).map((k) => ctx.of(k)));
6113
6130
  }
6114
6131
  static values(ctx, obj) {
6115
6132
  const seq = ctx.sequence(obj);
6116
- if (!isPlainObject(seq))
6133
+ if (!isPlainObject(seq)) {
6117
6134
  throw new TypeError("Object.values requires an object");
6135
+ }
6118
6136
  return ctx.distribute(Object.values(seq));
6119
6137
  }
6120
6138
  static entries(ctx, obj) {
6121
6139
  const seq = ctx.sequence(obj);
6122
- if (!isPlainObject(seq))
6140
+ if (!isPlainObject(seq)) {
6123
6141
  throw new TypeError("Object.entries requires an object");
6142
+ }
6124
6143
  return ctx.distribute(
6125
6144
  Object.entries(seq).map(([k, v]) => ctx.distribute([ctx.of(k), v]))
6126
6145
  );
@@ -6136,7 +6155,7 @@ __decorateElement(_init4, 9, "entries", _entries_dec2, ExoObject);
6136
6155
  __decorateElement(_init4, 9, "fromEntries", _fromEntries_dec, ExoObject);
6137
6156
  __decoratorMetadata(_init4, ExoObject);
6138
6157
  __runInitializers(_init4, 3, ExoObject);
6139
- _ExoBoolean_decorators = [tool(z.any())], _valueOf_dec2 = [tool()];
6158
+ _ExoBoolean_decorators = [tool(z.any())], _valueOf_dec2 = [tool()], _toString_dec4 = [tool()];
6140
6159
  class ExoBoolean {
6141
6160
  constructor(...args) {
6142
6161
  __runInitializers(_init5, 5, this);
@@ -6145,9 +6164,13 @@ class ExoBoolean {
6145
6164
  get valueOf() {
6146
6165
  return Boolean.prototype.valueOf;
6147
6166
  }
6167
+ get toString() {
6168
+ return Boolean.prototype.toString;
6169
+ }
6148
6170
  }
6149
6171
  _init5 = __decoratorStart(null);
6150
6172
  __decorateElement(_init5, 2, "valueOf", _valueOf_dec2, ExoBoolean);
6173
+ __decorateElement(_init5, 2, "toString", _toString_dec4, ExoBoolean);
6151
6174
  ExoBoolean = __decorateElement(_init5, 0, "ExoBoolean", _ExoBoolean_decorators, ExoBoolean);
6152
6175
  __runInitializers(_init5, 1, ExoBoolean);
6153
6176
  _parse_dec2 = [tool(z.string())], _stringify_dec = [tool(z.any(), z.union([z.null(), z.undefined()]), z.number().optional())];
@@ -6218,11 +6241,41 @@ __decorateElement(_init7, 9, "sign", _sign_dec, ExoMath);
6218
6241
  __decorateElement(_init7, 9, "trunc", _trunc_dec, ExoMath);
6219
6242
  __decoratorMetadata(_init7, ExoMath);
6220
6243
  __runInitializers(_init7, 3, ExoMath);
6221
- _ExoNumber_decorators = [tool(z.union([z.string(), z.number(), z.bigint()]))], _parseInt_dec = [tool(z.string(), z.number().optional())], _parseFloat_dec = [tool(z.string())], _isNaN_dec = [tool(z.any())], _isFinite_dec = [tool(z.any())], _isInteger_dec = [tool(z.any())];
6244
+ _all_dec = [tool(z.array(z.any()))], _allSettled_dec = [tool(z.array(z.any()))], _race_dec = [tool(z.array(z.any()))], _resolve_dec = [tool(z.any())], _reject_dec = [tool(z.any())];
6245
+ class ExoPromise {
6246
+ static all(values) {
6247
+ return Promise.all(values);
6248
+ }
6249
+ static allSettled(values) {
6250
+ return Promise.allSettled(values);
6251
+ }
6252
+ static race(values) {
6253
+ return Promise.race(values);
6254
+ }
6255
+ static resolve(value) {
6256
+ return Promise.resolve(value);
6257
+ }
6258
+ static reject(reason) {
6259
+ return Promise.reject(reason);
6260
+ }
6261
+ }
6262
+ _init8 = __decoratorStart(null);
6263
+ __decorateElement(_init8, 9, "all", _all_dec, ExoPromise);
6264
+ __decorateElement(_init8, 9, "allSettled", _allSettled_dec, ExoPromise);
6265
+ __decorateElement(_init8, 9, "race", _race_dec, ExoPromise);
6266
+ __decorateElement(_init8, 9, "resolve", _resolve_dec, ExoPromise);
6267
+ __decorateElement(_init8, 9, "reject", _reject_dec, ExoPromise);
6268
+ __decoratorMetadata(_init8, ExoPromise);
6269
+ __runInitializers(_init8, 3, ExoPromise);
6270
+ _ExoNumber_decorators = [tool(z.union([z.string(), z.number(), z.bigint()]))], _toString_dec5 = [tool(z.number().optional())], _parseInt_dec = [tool(z.string(), z.number().optional())], _parseFloat_dec = [tool(z.string())], _isNaN_dec = [tool(z.any())], _isFinite_dec = [tool(z.any())], _isInteger_dec = [tool(z.any())];
6222
6271
  class ExoNumber {
6223
6272
  constructor(...args) {
6273
+ __runInitializers(_init9, 5, this);
6224
6274
  return new Number(...args);
6225
6275
  }
6276
+ get toString() {
6277
+ return Number.prototype.toString;
6278
+ }
6226
6279
  static parseInt(s, radix) {
6227
6280
  return Number.parseInt(s, radix);
6228
6281
  }
@@ -6239,15 +6292,33 @@ class ExoNumber {
6239
6292
  return Number.isInteger(value);
6240
6293
  }
6241
6294
  }
6242
- _init8 = __decoratorStart(null);
6243
- __decorateElement(_init8, 9, "parseInt", _parseInt_dec, ExoNumber);
6244
- __decorateElement(_init8, 9, "parseFloat", _parseFloat_dec, ExoNumber);
6245
- __decorateElement(_init8, 9, "isNaN", _isNaN_dec, ExoNumber);
6246
- __decorateElement(_init8, 9, "isFinite", _isFinite_dec, ExoNumber);
6247
- __decorateElement(_init8, 9, "isInteger", _isInteger_dec, ExoNumber);
6248
- ExoNumber = __decorateElement(_init8, 0, "ExoNumber", _ExoNumber_decorators, ExoNumber);
6249
- __runInitializers(_init8, 3, ExoNumber);
6250
- __runInitializers(_init8, 1, ExoNumber);
6295
+ _init9 = __decoratorStart(null);
6296
+ __decorateElement(_init9, 9, "parseInt", _parseInt_dec, ExoNumber);
6297
+ __decorateElement(_init9, 9, "parseFloat", _parseFloat_dec, ExoNumber);
6298
+ __decorateElement(_init9, 9, "isNaN", _isNaN_dec, ExoNumber);
6299
+ __decorateElement(_init9, 9, "isFinite", _isFinite_dec, ExoNumber);
6300
+ __decorateElement(_init9, 9, "isInteger", _isInteger_dec, ExoNumber);
6301
+ __decorateElement(_init9, 2, "toString", _toString_dec5, ExoNumber);
6302
+ ExoNumber = __decorateElement(_init9, 0, "ExoNumber", _ExoNumber_decorators, ExoNumber);
6303
+ __runInitializers(_init9, 3, ExoNumber);
6304
+ __runInitializers(_init9, 1, ExoNumber);
6305
+ const allowedExpressions = [
6306
+ "ArrayExpression",
6307
+ "ArrowFunctionExpression",
6308
+ "AwaitExpression",
6309
+ "BinaryExpression",
6310
+ "CallExpression",
6311
+ "ConditionalExpression",
6312
+ "Identifier",
6313
+ "Literal",
6314
+ "LogicalExpression",
6315
+ "MemberExpression",
6316
+ "NewExpression",
6317
+ "ObjectExpression",
6318
+ "TemplateLiteral",
6319
+ "UnaryExpression",
6320
+ "ChainExpression"
6321
+ ];
6251
6322
  class Scope2 {
6252
6323
  constructor(parent) {
6253
6324
  this.parent = parent;
@@ -6441,17 +6512,45 @@ class Evaluator {
6441
6512
  const tool2 = getTool(objRaw, objForLookup, key);
6442
6513
  return this.ctx.of(tool2);
6443
6514
  }
6515
+ /**
6516
+ * Convert a value to string for interpolation/concatenation.
6517
+ * Calls .toString() via getExoProperty if available.
6518
+ */
6519
+ *toString(obj, node) {
6520
+ const raw = yield obj;
6521
+ if (raw === null) {
6522
+ return "null";
6523
+ }
6524
+ if (raw === void 0) {
6525
+ return "undefined";
6526
+ }
6527
+ const toStringFn = yield* this.getExoProperty(obj, "toString", node, true);
6528
+ const toStringRaw = yield toStringFn;
6529
+ if (typeof toStringRaw === "function") {
6530
+ const result = this.ctx.call(this.ctx.of(toStringFn), []);
6531
+ const resultRaw = yield result;
6532
+ if (typeof resultRaw === "string") {
6533
+ return resultRaw;
6534
+ }
6535
+ }
6536
+ return "[object]";
6537
+ }
6444
6538
  getBuiltinPrototype(value) {
6445
- if (typeof value === "string")
6539
+ if (typeof value === "string") {
6446
6540
  return this.builtinPrototypes.String;
6447
- if (typeof value === "number")
6541
+ }
6542
+ if (typeof value === "number") {
6448
6543
  return this.builtinPrototypes.Number;
6449
- if (typeof value === "boolean")
6544
+ }
6545
+ if (typeof value === "boolean") {
6450
6546
  return this.builtinPrototypes.Boolean;
6451
- if (Array.isArray(value))
6547
+ }
6548
+ if (Array.isArray(value)) {
6452
6549
  return this.builtinPrototypes.Array;
6453
- if (value instanceof Date)
6550
+ }
6551
+ if (value instanceof Date) {
6454
6552
  return this.builtinPrototypes.Date;
6553
+ }
6455
6554
  return null;
6456
6555
  }
6457
6556
  *ObjectExpression(node) {
@@ -6477,16 +6576,27 @@ class Evaluator {
6477
6576
  this.inv.eval(this.ctx.isExpr(result), "internal error: result is not an expression", node, result);
6478
6577
  return result;
6479
6578
  }
6480
- *evalStatements(statements) {
6579
+ *evalStatements(statements, { module = false } = {}) {
6481
6580
  let result = this.ctx.of(void 0);
6581
+ const exports$1 = {};
6482
6582
  for (const statement of statements) {
6483
- this.inv.parse(
6484
- statement.type !== "ImportDeclaration" && statement.type !== "ExportAllDeclaration" && statement.type !== "ExportNamedDeclaration" && statement.type !== "ExportDefaultDeclaration",
6485
- "statement is not a statement",
6486
- statement
6487
- );
6583
+ if (statement.type === "ImportDeclaration") {
6584
+ this.inv.parse(false, "imports are not allowed", statement);
6585
+ }
6586
+ if (statement.type === "ExportAllDeclaration" || statement.type === "ExportNamedDeclaration") {
6587
+ this.inv.parse(false, "only export default is allowed", statement);
6588
+ }
6589
+ if (statement.type === "ExportDefaultDeclaration") {
6590
+ this.inv.parse(module, "export is not allowed in script mode", statement);
6591
+ const exported = yield* this.Expression(statement.declaration);
6592
+ this.defineProperty(exports$1, "default", exported, statement);
6593
+ continue;
6594
+ }
6488
6595
  result = yield* this.Statement(statement);
6489
6596
  }
6597
+ if (module) {
6598
+ return this.ctx.distribute(exports$1);
6599
+ }
6490
6600
  return result;
6491
6601
  }
6492
6602
  *evalFunctionCall(node, args) {
@@ -6562,8 +6672,10 @@ class Evaluator {
6562
6672
  }
6563
6673
  *BinaryExpression(node) {
6564
6674
  this.inv.parse(node.left.type !== "PrivateIdentifier", "private identifiers are not allowed", node);
6565
- const left = yield* this.$(node.left);
6566
- const right = yield* this.$(node.right);
6675
+ const leftExpr = yield* this.Expression(node.left);
6676
+ const rightExpr = yield* this.Expression(node.right);
6677
+ const left = yield leftExpr;
6678
+ const right = yield rightExpr;
6567
6679
  switch (node.operator) {
6568
6680
  case "===":
6569
6681
  return this.ctx.of(left === right);
@@ -6574,6 +6686,14 @@ class Evaluator {
6574
6686
  case "!=":
6575
6687
  return this.ctx.of(left != right);
6576
6688
  }
6689
+ if (node.operator === "+") {
6690
+ if (typeof left === "number" && typeof right === "number") {
6691
+ return this.ctx.of(left + right);
6692
+ }
6693
+ const leftStr = yield* this.toString(leftExpr, node.left);
6694
+ const rightStr = yield* this.toString(rightExpr, node.right);
6695
+ return this.ctx.of(leftStr + rightStr);
6696
+ }
6577
6697
  this.inv.eval((typeof left === "number" || typeof left === "string") && (typeof right === "number" || typeof right === "string"), "left and right are not numbers or strings", node, { left, right });
6578
6698
  switch (node.operator) {
6579
6699
  case "<":
@@ -6582,8 +6702,6 @@ class Evaluator {
6582
6702
  return this.ctx.of(left > right);
6583
6703
  case "<=":
6584
6704
  return this.ctx.of(left <= right);
6585
- case "+":
6586
- return this.ctx.of(left + right);
6587
6705
  }
6588
6706
  this.inv.eval(typeof left === "number" && typeof right === "number", "left and right are not numbers", node, { left, right });
6589
6707
  switch (node.operator) {
@@ -6636,9 +6754,9 @@ class Evaluator {
6636
6754
  result.push(quasi.value.cooked);
6637
6755
  const expr2 = node.expressions[i];
6638
6756
  if (expr2) {
6639
- const val = yield* this.$(expr2);
6640
- this.inv.eval(typeof val === "string" || typeof val === "number" || typeof val === "boolean", "template expressions must evaluate to a string, number, or boolean", expr2, val);
6641
- result.push(val);
6757
+ const exprValue = yield* this.Expression(expr2);
6758
+ const str = yield* this.toString(exprValue, expr2);
6759
+ result.push(str);
6642
6760
  }
6643
6761
  }
6644
6762
  return this.ctx.of(result.join(""));
@@ -6660,8 +6778,7 @@ class Evaluator {
6660
6778
  return this.ctx.of(instance);
6661
6779
  }
6662
6780
  *Expression(node) {
6663
- const supportedExpressions = ["ArrayExpression", "ArrowFunctionExpression", "AwaitExpression", "BinaryExpression", "CallExpression", "ConditionalExpression", "Function", "Identifier", "Literal", "LogicalExpression", "MemberExpression", "NewExpression", "ObjectExpression", "TemplateLiteral", "UnaryExpression", "ChainExpression"];
6664
- this.inv.parse(supportedExpressions.includes(node.type), `unsupported expression type: ${node.type}`, node);
6781
+ this.inv.parse(allowedExpressions.includes(node.type), `unsupported expression type: ${node.type}`, node);
6665
6782
  return yield* this[node.type](node);
6666
6783
  }
6667
6784
  *$(node) {
@@ -6705,8 +6822,8 @@ class Evaluator {
6705
6822
  }
6706
6823
  this.inv.parse(false, "unsupported statement type", node);
6707
6824
  }
6708
- Program(node) {
6709
- const iter = this.ctx.doGen(this.evalStatements(node.body));
6825
+ Program(node, { module = false } = {}) {
6826
+ const iter = this.ctx.doGen(this.evalStatements(node.body, { module }));
6710
6827
  let step = iter.next();
6711
6828
  if (step.done) {
6712
6829
  return step.value;
@@ -6731,7 +6848,8 @@ const builtins = {
6731
6848
  Boolean: ExoBoolean,
6732
6849
  JSON: ExoJSON,
6733
6850
  Math: ExoMath,
6734
- Number: ExoNumber
6851
+ Number: ExoNumber,
6852
+ Promise: ExoPromise
6735
6853
  };
6736
6854
  function exoEval(code, ctx = new IdentityContext()) {
6737
6855
  const ast = parse3(code, { ecmaVersion: 2022 });
@@ -6739,7 +6857,9 @@ function exoEval(code, ctx = new IdentityContext()) {
6739
6857
  const evaluator = new Evaluator(ast, code, ctx, rootScope, {
6740
6858
  Array: ExoArray.prototype,
6741
6859
  String: ExoString.prototype,
6742
- Date: ExoDate.prototype
6860
+ Date: ExoDate.prototype,
6861
+ Number: ExoNumber.prototype,
6862
+ Boolean: ExoBoolean.prototype
6743
6863
  });
6744
6864
  for (const [name, value] of Object.entries(builtins)) {
6745
6865
  rootScope.set(
@@ -8141,21 +8261,20 @@ async function* generateToolTypes(tools, name) {
8141
8261
  for (const [toolName, tool2] of toolEntries) {
8142
8262
  const inputSchema = getJsonSchema(tool2.inputSchema);
8143
8263
  const outputSchema = tool2.outputSchema ? getJsonSchema(tool2.outputSchema) : null;
8264
+ const compileOpts = {
8265
+ format: false,
8266
+ bannerComment: " ",
8267
+ cwd: "/"
8268
+ };
8144
8269
  const inputJsonType = await compile(
8145
8270
  inputSchema,
8146
8271
  `${camelCase(toolName, { pascalCase: true })}Input`,
8147
- {
8148
- format: false,
8149
- bannerComment: " "
8150
- }
8272
+ compileOpts
8151
8273
  );
8152
8274
  const outputJsonType = outputSchema ? await compile(
8153
8275
  outputSchema,
8154
8276
  `${camelCase(toolName, { pascalCase: true })}Output`,
8155
- {
8156
- format: false,
8157
- bannerComment: " "
8158
- }
8277
+ compileOpts
8159
8278
  ) : null;
8160
8279
  const inputTypeBody = extractTypeBody(inputJsonType);
8161
8280
  const outputTypeBody = outputJsonType ? extractTypeBody(outputJsonType) : "object";
@@ -0,0 +1,37 @@
1
+ import { Secrets } from './providers/secrets';
2
+ import { StorageCap } from './providers/storage';
3
+ /**
4
+ * exoagentd — runtime daemon.
5
+ *
6
+ * Owns shared infrastructure (storage, secrets) and manages
7
+ * agent processes via dtach (terminal session manager).
8
+ */
9
+ export interface DaemonConfig {
10
+ repoDir: string;
11
+ dataDir?: string;
12
+ }
13
+ export declare class Daemon {
14
+ readonly repoDir: string;
15
+ readonly dataDir: string;
16
+ readonly storage: StorageCap;
17
+ readonly secrets: Secrets;
18
+ private constructor();
19
+ static start(config: DaemonConfig): Promise<Daemon>;
20
+ /** Validate agentId — alphanumeric, hyphens, underscores only */
21
+ private validateAgentId;
22
+ /** Spawn an agent in a dtach session */
23
+ spawn(agentId: string): Promise<string>;
24
+ /** Attach to an agent — replaces current process with dtach */
25
+ attach(agentId: string): void;
26
+ /** List running agents (by socket files) */
27
+ list(): string[];
28
+ /** Kill an agent — terminates the dtach process tree */
29
+ kill(agentId: string): void;
30
+ /** Run an exo with daemon caps */
31
+ runExo(name: string, exoArgs?: string[]): Promise<unknown>;
32
+ /** Eval arbitrary code with daemon caps (like an inline exo) */
33
+ evalCode(code: string): Promise<unknown>;
34
+ /** Get a ReviewCap for the default clone (if exists) */
35
+ private getReviewCap;
36
+ stop(): Promise<void>;
37
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Generate a .d.ts declaration string from a TypeScript source file.
3
+ *
4
+ * Uses the TypeScript compiler API to emit declarations. Resolves imports
5
+ * so the output includes full type information.
6
+ *
7
+ * @param filePath - Absolute path to the .ts source file
8
+ * @returns The generated .d.ts content
9
+ */
10
+ export declare function generateDts(filePath: string): string;
11
+ /**
12
+ * Generate a .d.ts for a class, extracting only its public method signatures.
13
+ *
14
+ * This produces a minimal type declaration suitable for codemode — just the
15
+ * methods the LLM can call, without internal implementation details.
16
+ *
17
+ * @param filePath - Absolute path to the .ts source file
18
+ * @param className - Name of the class to extract
19
+ * @returns A declaration string like `{ method(args): ReturnType; ... }`
20
+ */
21
+ export declare function generateCapDts(filePath: string, className: string): string;
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An Exo is a sandboxed program. It declares its caps by destructuring
3
+ * the first argument of its default export.
4
+ *
5
+ * ```javascript
6
+ * export default async ({ sandbox, review, storage }) => {
7
+ * await sandbox.exec({ command: 'echo hello' })
8
+ * }
9
+ * ```
10
+ *
11
+ * Only the destructured caps are available — exoeval enforces this at
12
+ * the interpreter level. Every exo gets the full cap set; the destructure
13
+ * is the audit trail for what it actually uses.
14
+ */
15
+ /**
16
+ * An exo module's default export signature.
17
+ * Caps are received as a single object, destructured by the exo.
18
+ */
19
+ export type ExoFn = (caps: Record<string, object>) => void | Promise<void>;
20
+ /**
21
+ * Metadata for an exo — loaded from its module.
22
+ */
23
+ export interface ExoDef {
24
+ readonly name: string;
25
+ readonly run: ExoFn;
26
+ }
27
+ /**
28
+ * Loads an exo from source code via exoImport (the sandboxed interpreter).
29
+ * The source must `export default` a function that takes a caps object.
30
+ *
31
+ * Source should already be plain JS (run through esbuild if TypeScript).
32
+ */
33
+ export declare function loadExo(name: string, code: string): Promise<ExoDef>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Args cap — provides CLI arguments to exos.
3
+ */
4
+ export declare class ArgsCap {
5
+ private map;
6
+ constructor(args: string[]);
7
+ get({ key }: {
8
+ key: string;
9
+ }): Promise<string | undefined>;
10
+ has({ key }: {
11
+ key: string;
12
+ }): Promise<boolean>;
13
+ }
@@ -0,0 +1,68 @@
1
+ import { Model } from '@mariozechner/pi-ai';
2
+ import { ExtensionFactory, AgentSession, SessionManager, SettingsManager } from '@mariozechner/pi-coding-agent';
3
+ import { Secrets } from './secrets';
4
+ import { StorageCap } from './storage';
5
+ import { ReviewCap } from './review';
6
+ import { SandboxCap } from './sandbox';
7
+ export interface PiCapConfig {
8
+ sandbox: SandboxCap;
9
+ /** Arbitrary capability objects to expose via codemode */
10
+ caps?: Record<string, object>;
11
+ /** Additional system prompt text */
12
+ systemPrompt?: string;
13
+ /** Pre-generated .d.ts for caps (required when caps are provided) */
14
+ capsDts: string;
15
+ /** @internal */ model?: Model<any>;
16
+ /** @internal */ extensionFactories?: ExtensionFactory[];
17
+ /** @internal */ settingsManager?: SettingsManager;
18
+ /** @internal */ sessionManager?: SessionManager;
19
+ }
20
+ export declare class PiCap {
21
+ private config;
22
+ private session;
23
+ private modelFallbackMessage?;
24
+ constructor(config: PiCapConfig);
25
+ private sandboxBashOps;
26
+ /** Read a file via sandbox exec, returns base64-decoded content */
27
+ private sandboxRead;
28
+ /** Write a file via sandbox exec, content passed via stdin */
29
+ private sandboxWrite;
30
+ /** Check file access via sandbox exec */
31
+ private sandboxAccess;
32
+ private scopedReadOps;
33
+ private scopedWriteOps;
34
+ private scopedEditOps;
35
+ private buildCodemodeTool;
36
+ private ensureSession;
37
+ /** Send a prompt and return the final text response (background mode) */
38
+ prompt(message: string): Promise<string>;
39
+ /** Access the underlying session (for interactive TUI attach) */
40
+ get currentSession(): AgentSession | null;
41
+ /** Initialize session without prompting (for interactive mode) */
42
+ init(): Promise<AgentSession>;
43
+ /** Run pi's interactive TUI (handles /login, /model, etc.) */
44
+ runInteractive(options?: {
45
+ initialMessage?: string;
46
+ }): Promise<void>;
47
+ /** Dispose the session */
48
+ dispose(): void;
49
+ }
50
+ export interface SpawnAgentConfig {
51
+ id: string;
52
+ repoDir: string;
53
+ dataDir: string;
54
+ storage: StorageCap;
55
+ secrets: Secrets;
56
+ }
57
+ export interface Agent {
58
+ readonly id: string;
59
+ readonly pi: PiCap;
60
+ readonly review: ReviewCap | undefined;
61
+ readonly cloneDir: string;
62
+ }
63
+ /**
64
+ * Spawn a coding agent — wires sandbox + review + pi together.
65
+ * Creates a local clone, sets up sandbox and review caps, and returns
66
+ * a fully configured Agent.
67
+ */
68
+ export declare function spawnAgent(config: SpawnAgentConfig): Promise<Agent>;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Review provider — GitHub PR-based code review.
3
+ *
4
+ * Pushes branches to GitHub, opens PRs, fetches reviews.
5
+ * Git push assumes the host has SSH/credentials configured.
6
+ * Only GitHub API operations use the token (from secrets DB).
7
+ */
8
+ /** Review result — uses GitHub API shapes directly (no wrapper types) */
9
+ export interface ReviewResult {
10
+ approved: boolean;
11
+ body: string;
12
+ /** Inline review comments (GitHub PullRequestReviewComment objects) */
13
+ comments: any[];
14
+ /** PR-level issue comments (GitHub IssueComment objects) */
15
+ issueComments: any[];
16
+ pr: number;
17
+ url: string;
18
+ }
19
+ export interface ReviewCapConfig {
20
+ /** Path to the agent's local clone */
21
+ cloneDir: string;
22
+ /** Nix git store path */
23
+ git: string;
24
+ /** GitHub API token (pre-attenuated from secrets) */
25
+ token: string;
26
+ /** GitHub owner/repo (e.g. "user/repo") */
27
+ repo: string;
28
+ /** Base branch for PRs. Default: "main" */
29
+ baseBranch?: string;
30
+ /** Poll interval in ms. Default: 5000 */
31
+ pollInterval?: number;
32
+ /** Agent name for branch prefixing. Default: "default" */
33
+ agentName?: string;
34
+ }
35
+ export declare class ReviewCap {
36
+ private config;
37
+ constructor(config: ReviewCapConfig);
38
+ /** GitHub API token (pre-attenuated, single source of truth) */
39
+ private get token();
40
+ /** Prefix branch name with agent namespace. */
41
+ private qualifyBranch;
42
+ /**
43
+ * Push a branch to GitHub and open/update a PR.
44
+ * Returns immediately with the PR URL.
45
+ * Remote branch will be auto-prefixed with `exoagent-<agent>/`.
46
+ */
47
+ openPR({ branch, title, body }: {
48
+ branch: string;
49
+ title: string;
50
+ body?: string;
51
+ }): Promise<{
52
+ pr: number;
53
+ url: string;
54
+ sha: string;
55
+ }>;
56
+ /**
57
+ * Get the latest review on a PR. Returns immediately (non-blocking).
58
+ * Returns the most recent non-pending review with its comments.
59
+ */
60
+ getReviews({ pr }: {
61
+ pr: number;
62
+ }): Promise<ReviewResult>;
63
+ /**
64
+ * Reply to a specific review comment on a PR.
65
+ */
66
+ replyToComment({ pr, commentId, body }: {
67
+ pr: number;
68
+ commentId: number;
69
+ body: string;
70
+ }): Promise<{
71
+ id: number;
72
+ }>;
73
+ /**
74
+ * Post a general comment on a PR (issue-level comment).
75
+ */
76
+ commentOnPR({ pr, body }: {
77
+ pr: number;
78
+ body: string;
79
+ }): Promise<{
80
+ id: number;
81
+ }>;
82
+ }
@@ -0,0 +1,54 @@
1
+ import { StorageCap } from './storage';
2
+ /**
3
+ * Sandbox provider — bwrap-based execution environment with network
4
+ * isolation (internet yes, LAN/loopback blocked via pasta + nft).
5
+ *
6
+ * - exec: runs commands inside bwrap (PID-isolated, net-filtered, fs-scoped)
7
+ * - read/write/edit: host-side file ops, path-validated to workspace
8
+ */
9
+ /** Nix store paths for essential binaries */
10
+ export interface NixPaths {
11
+ bash: string;
12
+ coreutils: string;
13
+ bwrap: string;
14
+ pasta: string;
15
+ nft: string;
16
+ nix: string;
17
+ cacert: string;
18
+ git: string;
19
+ gnugrep: string;
20
+ dtach: string;
21
+ }
22
+ /** Read nix paths from EXOAGENT_NIX env var (JSON) set by flake.nix devShell */
23
+ export declare function nixPathsFromEnv(): NixPaths;
24
+ interface SandboxConfig {
25
+ nix: NixPaths;
26
+ storage: StorageCap;
27
+ sessionId: string;
28
+ workspace: string;
29
+ }
30
+ export declare class SandboxCap {
31
+ private config;
32
+ private rootDir;
33
+ private scriptWritten;
34
+ constructor(config: SandboxConfig);
35
+ private getRoot;
36
+ /** Compute the transitive closure of nix store paths needed in the sandbox */
37
+ private nixClosure;
38
+ /** Validate a path is safe to interpolate into a shell script (no special chars) */
39
+ private static assertSafePath;
40
+ /** Write the wrapper script once, reuse for every exec */
41
+ private ensureScript;
42
+ exec({ command, timeout, signal, stdin }: {
43
+ command: string;
44
+ timeout?: number;
45
+ signal?: AbortSignal;
46
+ stdin?: string;
47
+ }): Promise<{
48
+ stdout: string;
49
+ stderr: string;
50
+ exitCode: number;
51
+ }>;
52
+ get workspace(): string;
53
+ }
54
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Daemon-only secrets store. Never exposed to exos.
3
+ * Each provider gets its own set of named secrets (e.g. API keys).
4
+ */
5
+ export declare class Secrets {
6
+ private readonly root;
7
+ private readonly db;
8
+ private constructor();
9
+ /**
10
+ * Create a Secrets store backed by a SQLite DB in the given directory.
11
+ * Initializes the directory (mode 0700) and DB schema on first call.
12
+ */
13
+ static create(root: string): Secrets;
14
+ get(provider: string, name: string): string | null;
15
+ set(provider: string, name: string, value: string): void;
16
+ delete(provider: string, name: string): void;
17
+ close(): void;
18
+ }
@@ -0,0 +1,16 @@
1
+ export declare class StorageCap {
2
+ private readonly root;
3
+ private readonly provider;
4
+ private readonly db;
5
+ private constructor();
6
+ /**
7
+ * Create a StorageCap backed by a SQLite DB in the given directory.
8
+ * Initializes the directory and DB schema on first call.
9
+ */
10
+ static create(root: string, provider?: string): StorageCap;
11
+ get(key: string): Promise<unknown>;
12
+ set(key: string, value: unknown): Promise<void>;
13
+ delete(key: string): Promise<void>;
14
+ close(): void;
15
+ dir(name: string): Promise<string>;
16
+ }
@@ -0,0 +1,19 @@
1
+ import { Secrets } from './providers/secrets';
2
+ /**
3
+ * Secret declaration — providers declare what secrets they need.
4
+ */
5
+ export interface SecretDecl {
6
+ name: string;
7
+ required: boolean;
8
+ description: string;
9
+ }
10
+ export interface ProviderSecrets {
11
+ provider: string;
12
+ secrets: SecretDecl[];
13
+ }
14
+ /** Known providers and their secrets */
15
+ export declare const PROVIDER_SECRETS: ProviderSecrets[];
16
+ /**
17
+ * Interactive TUI for managing secrets.
18
+ */
19
+ export declare function runSecretsUI(db: Secrets): Promise<void>;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/sql.mjs CHANGED
@@ -51,7 +51,7 @@ var _desc_dec, _asc_dec, ___dec, ___dec2, ___dec3, ___dec4, ___dec5, _NOT_LIKE_d
51
51
  import { sql as sql$1, Kysely } from "kysely";
52
52
  import invariant from "tiny-invariant";
53
53
  import z from "zod";
54
- import { a as tool, r as registerToolField, f as fn } from "./tool-DGs9ZxVn.js";
54
+ import { a as tool, r as registerToolField, f as fn } from "./tool-5wSlXWJ2.js";
55
55
  const sql = sql$1;
56
56
  const buildSql = (parts, separator = sql$1` `) => {
57
57
  return sql$1.join(parts.filter((x) => x != null), separator);
@@ -70,8 +70,9 @@ const makeFnSchema = (retSchema, allowOptional = false) => {
70
70
  version: 1,
71
71
  vendor: "exoeval",
72
72
  validate: (value) => {
73
- if (value === void 0 && allowOptional)
73
+ if (value === void 0 && allowOptional) {
74
74
  return { value: void 0 };
75
+ }
75
76
  if (typeof value !== "function") {
76
77
  return { issues: [{ message: "Expected a function" }] };
77
78
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "exoagent",
3
3
  "type": "module",
4
- "version": "0.0.13",
4
+ "version": "0.0.14",
5
5
  "description": "The OS kernel to safely unleash your agents",
6
6
  "author": "Ryan Rasti <https://github.com/ryanrasti>",
7
7
  "license": "MIT",
@@ -48,6 +48,7 @@
48
48
  "release": "bumpp",
49
49
  "start": "tsx src/index.ts",
50
50
  "test": "vitest --run",
51
+ "test:ci": "vitest --run --exclude '**/*.local.test.ts'",
51
52
  "typecheck": "tsc",
52
53
  "check:examples": "npm --prefix ./examples run check",
53
54
  "check": "npm ci && npm run lint && npm run typecheck && npm run build && npm run test && npm run check:examples"
@@ -56,6 +57,9 @@
56
57
  "ai": "^6.0.0"
57
58
  },
58
59
  "dependencies": {
60
+ "@mariozechner/pi-coding-agent": "^0.58.4",
61
+ "@sinclair/typebox": "^0.34.48",
62
+ "better-sqlite3": "^12.8.0",
59
63
  "camelcase": "^9.0.0",
60
64
  "json-schema": "^0.4.0",
61
65
  "json-schema-to-typescript": "^15.0.0",
@@ -71,6 +75,7 @@
71
75
  "@antfu/utils": "9.3.0",
72
76
  "@electric-sql/pglite": "^0.3.15",
73
77
  "@standard-schema/spec": "^1.1.0",
78
+ "@types/better-sqlite3": "^7.6.13",
74
79
  "@types/node": "25.0.1",
75
80
  "acorn": "^8.16.0",
76
81
  "bumpp": "10.3.2",