@gigaai/newton 0.3.0 → 0.4.1

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,157 @@
1
+ import * as vm from "node:vm";
2
+ export function createRealm(consoleLog) {
3
+ const context = vm.createContext({}, { codeGeneration: { strings: false, wasm: false } });
4
+ const hostCallables = new Map();
5
+ let nextCallableId = 1;
6
+ let makeRealmCallable;
7
+ let makeRealmArray;
8
+ let makeRealmObject;
9
+ vm.runInContext(`
10
+ {
11
+ const RealmDate = Date;
12
+ const dateNowUnavailable = () => {
13
+ throw new Error("Date.now() is unavailable in workflows (breaks resume); pass timestamps via --args");
14
+ };
15
+ const mathRandomUnavailable = () => {
16
+ throw new Error("Math.random() is unavailable in workflows (breaks resume); vary prompts by index instead");
17
+ };
18
+
19
+ const GuardedDate = new Proxy(RealmDate, {
20
+ get(target, prop, receiver) {
21
+ if (prop === "now") return dateNowUnavailable;
22
+ return Reflect.get(target, prop, receiver);
23
+ },
24
+ construct(target, argArray) {
25
+ if (argArray.length === 0) {
26
+ throw new Error("new Date() without arguments is unavailable in workflows (breaks resume)");
27
+ }
28
+ return Reflect.construct(target, argArray);
29
+ },
30
+ });
31
+ globalThis.Date = GuardedDate;
32
+ Object.defineProperty(RealmDate.prototype, "constructor", {
33
+ value: GuardedDate,
34
+ writable: true,
35
+ configurable: true,
36
+ });
37
+
38
+ Math.random = mathRandomUnavailable;
39
+ }
40
+ `, context);
41
+ const bridge = (id, args) => {
42
+ const callable = hostCallables.get(id);
43
+ if (!callable)
44
+ throw new Error(`unknown workflow host function ${id}`);
45
+ return callable(...args);
46
+ };
47
+ context.__newtonBridge = bridge;
48
+ const helpers = vm.runInContext(`
49
+ (() => {
50
+ const bridge = globalThis.__newtonBridge;
51
+ delete globalThis.__newtonBridge;
52
+
53
+ const importValue = (value, seen = new WeakMap()) => {
54
+ if (value === null || value === undefined) return value;
55
+ const kind = typeof value;
56
+ if (kind !== "object") return kind === "function" ? undefined : value;
57
+ const existing = seen.get(value);
58
+ if (existing) return existing;
59
+ if (Array.isArray(value)) {
60
+ const copy = [];
61
+ seen.set(value, copy);
62
+ for (let i = 0; i < value.length; i++) copy[i] = importValue(value[i], seen);
63
+ return copy;
64
+ }
65
+ const copy = {};
66
+ seen.set(value, copy);
67
+ for (const key of Object.keys(value)) copy[key] = importValue(value[key], seen);
68
+ return copy;
69
+ };
70
+
71
+ const importError = (error) =>
72
+ new Error(error && typeof error === "object" && typeof error.message === "string" ? error.message : String(error));
73
+
74
+ const makeCallable = (id) => (...args) => {
75
+ try {
76
+ const result = bridge(id, args);
77
+ if (result && typeof result === "object" && typeof result.then === "function") {
78
+ return Promise.resolve(result).then(
79
+ (value) => importValue(value),
80
+ (error) => {
81
+ throw importError(error);
82
+ },
83
+ );
84
+ }
85
+ return importValue(result);
86
+ } catch (error) {
87
+ throw importError(error);
88
+ }
89
+ };
90
+
91
+ return {
92
+ makeCallable,
93
+ makeArray: (items) => Array.from(items),
94
+ makeObject: (entries) => {
95
+ const object = {};
96
+ for (const [key, value] of entries) object[key] = value;
97
+ return object;
98
+ },
99
+ };
100
+ })()
101
+ `, context);
102
+ makeRealmCallable = helpers.makeCallable;
103
+ makeRealmArray = helpers.makeArray;
104
+ makeRealmObject = helpers.makeObject;
105
+ const wrapHostCallable = (callable) => {
106
+ const id = nextCallableId++;
107
+ hostCallables.set(id, callable);
108
+ return makeRealmCallable(id);
109
+ };
110
+ const toRealmValue = (value) => {
111
+ if (value === null || value === undefined)
112
+ return value;
113
+ if (typeof value === "function")
114
+ return wrapHostCallable(value);
115
+ if (typeof value !== "object")
116
+ return value;
117
+ if (Array.isArray(value))
118
+ return makeRealmArray(value.map((item) => toRealmValue(item)));
119
+ return makeRealmObject(Object.entries(value).map(([key, entry]) => [key, toRealmValue(entry)]));
120
+ };
121
+ const writeConsole = (...args) => {
122
+ consoleLog(args.map(formatConsoleArg).join(" "));
123
+ };
124
+ context.__newtonConsole = makeRealmObject([
125
+ ["log", wrapHostCallable(writeConsole)],
126
+ ["info", wrapHostCallable(writeConsole)],
127
+ ["warn", wrapHostCallable(writeConsole)],
128
+ ["error", wrapHostCallable(writeConsole)],
129
+ ["debug", wrapHostCallable(writeConsole)],
130
+ ]);
131
+ vm.runInContext(`
132
+ globalThis.console = globalThis.__newtonConsole;
133
+ delete globalThis.__newtonConsole;
134
+ `, context);
135
+ return {
136
+ compile(params, body, filename) {
137
+ const scriptFn = vm.runInContext(`(async function(${params.join(",")}) {"use strict";\n${body}\n})`, context, {
138
+ filename,
139
+ });
140
+ return (...args) => scriptFn(...args.map((arg) => toRealmValue(arg)));
141
+ },
142
+ };
143
+ }
144
+ export function checkCompile(params, body) {
145
+ new vm.Script('(async function(' + params.join(",") + ') {"use strict";\n' + body + "\n})");
146
+ }
147
+ function formatConsoleArg(arg) {
148
+ if (typeof arg === "string")
149
+ return arg;
150
+ try {
151
+ const json = JSON.stringify(arg);
152
+ return json === undefined ? String(arg) : json;
153
+ }
154
+ catch {
155
+ return String(arg);
156
+ }
157
+ }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.3.0";
1
+ export const VERSION = "0.4.1";
@@ -0,0 +1,51 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdirSync, rmdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { promisify } from "node:util";
5
+ const execFileAsync = promisify(execFile);
6
+ export async function createWorktree(workspace, runId, agentId) {
7
+ const path = join(workspace, ".newton", "worktrees", runId, `agent-${agentId}`);
8
+ mkdirSync(dirname(path), { recursive: true });
9
+ try {
10
+ // Detached HEAD avoids branch-name coordination across parallel agents.
11
+ await git(["-C", workspace, "worktree", "add", "--detach", path, "HEAD"]);
12
+ const baseHead = (await git(["-C", path, "rev-parse", "HEAD"])).trim();
13
+ return { path, baseHead };
14
+ }
15
+ catch (error) {
16
+ throw new Error(`worktree setup failed: ${gitStderr(error)}`);
17
+ }
18
+ }
19
+ export async function finishWorktree(workspace, wt) {
20
+ try {
21
+ const status = await git(["-C", wt.path, "status", "--porcelain"]);
22
+ const head = (await git(["-C", wt.path, "rev-parse", "HEAD"])).trim();
23
+ const dirty = status.trim().length > 0 || head !== wt.baseHead;
24
+ if (dirty)
25
+ return { dirty: true, removed: false };
26
+ // Force is intentional after the clean check: this is disposable isolation.
27
+ await git(["-C", workspace, "worktree", "remove", "--force", wt.path]);
28
+ try {
29
+ rmdirSync(dirname(wt.path));
30
+ }
31
+ catch {
32
+ // Best-effort cleanup of the per-run directory.
33
+ }
34
+ return { dirty: false, removed: true };
35
+ }
36
+ catch {
37
+ return { dirty: true, removed: false };
38
+ }
39
+ }
40
+ async function git(args) {
41
+ const { stdout } = await execFileAsync("git", args);
42
+ return stdout.toString();
43
+ }
44
+ function gitStderr(error) {
45
+ if (typeof error === "object" && error !== null && "stderr" in error) {
46
+ const stderr = String(error.stderr ?? "").trim();
47
+ if (stderr)
48
+ return stderr;
49
+ }
50
+ return error instanceof Error ? error.message : String(error);
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gigaai/newton",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Deterministic multi-agent workflow executor. Write workflows in plain JavaScript; Newton drives coding agents over the Agent Client Protocol.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {