@addai/node 0.30.13 → 0.30.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.
Files changed (143) hide show
  1. package/dist/auto-update.d.ts +3 -0
  2. package/dist/auto-update.js +15 -0
  3. package/dist/capabilities.d.ts +17 -3
  4. package/dist/capabilities.js +18 -8
  5. package/dist/claude-models.d.ts +4 -12
  6. package/dist/claude-models.js +12 -88
  7. package/dist/claude-print.d.ts +15 -0
  8. package/dist/claude-print.js +16 -0
  9. package/dist/codex-models.d.ts +81 -0
  10. package/dist/codex-models.js +385 -0
  11. package/dist/codex-spawn.d.ts +14 -8
  12. package/dist/codex-spawn.js +30 -10
  13. package/dist/command-runner.js +31 -9
  14. package/dist/desktop/docker.js +2 -0
  15. package/dist/desktop/manager.d.ts +2 -1
  16. package/dist/desktop/manager.js +51 -1
  17. package/dist/desktop/provider.d.ts +1 -1
  18. package/dist/desktop/provider.js +2 -0
  19. package/dist/desktop/relay-client.js +7 -0
  20. package/dist/desktop/spec.d.ts +2 -0
  21. package/dist/direct/aios-bridge.d.ts +13 -0
  22. package/dist/direct/aios-bridge.js +177 -0
  23. package/dist/direct/aios-mcp.d.ts +2 -0
  24. package/dist/direct/aios-mcp.js +132 -0
  25. package/dist/direct/aios-tools.d.ts +351 -0
  26. package/dist/direct/aios-tools.js +120 -0
  27. package/dist/direct/board-chat-provider.d.ts +64 -0
  28. package/dist/direct/board-chat-provider.js +151 -0
  29. package/dist/direct/board-chat.d.ts +40 -0
  30. package/dist/direct/board-chat.js +414 -0
  31. package/dist/direct/config.d.ts +2 -0
  32. package/dist/direct/config.js +60 -0
  33. package/dist/direct/launch.d.ts +14 -0
  34. package/dist/direct/launch.js +121 -0
  35. package/dist/direct/protocol.d.ts +46 -0
  36. package/dist/direct/protocol.js +84 -0
  37. package/dist/direct/relay-main.d.ts +1 -0
  38. package/dist/direct/relay-main.js +21 -0
  39. package/dist/direct/relay.d.ts +26 -0
  40. package/dist/direct/relay.js +334 -0
  41. package/dist/direct/sessions.d.ts +61 -0
  42. package/dist/direct/sessions.js +368 -0
  43. package/dist/direct/supervisor.d.ts +9 -0
  44. package/dist/direct/supervisor.js +137 -0
  45. package/dist/direct/terminal.d.ts +1 -0
  46. package/dist/direct/terminal.js +106 -0
  47. package/dist/direct/worker.d.ts +1 -0
  48. package/dist/direct/worker.js +278 -0
  49. package/dist/entitybox/container-action.cjs +85 -0
  50. package/dist/entitybox/container-watchdog.cjs +70 -0
  51. package/dist/entitybox/model-entry.d.ts +3 -0
  52. package/dist/entitybox/model-entry.js +233 -0
  53. package/dist/entitybox/model-mcp-proxy.d.ts +3 -0
  54. package/dist/entitybox/model-mcp-proxy.js +85 -0
  55. package/dist/entitybox-application-boundary.d.ts +59 -0
  56. package/dist/entitybox-application-boundary.js +161 -0
  57. package/dist/entitybox-application-guard-core.d.ts +44 -0
  58. package/dist/entitybox-application-guard-core.js +164 -0
  59. package/dist/entitybox-application-guard-process.d.ts +1 -0
  60. package/dist/entitybox-application-guard-process.js +83 -0
  61. package/dist/entitybox-application-guard.d.ts +46 -0
  62. package/dist/entitybox-application-guard.js +239 -0
  63. package/dist/entitybox-capacity-health-host.d.ts +12 -0
  64. package/dist/entitybox-capacity-health-host.js +80 -0
  65. package/dist/entitybox-capacity-health-worker.d.ts +22 -0
  66. package/dist/entitybox-capacity-health-worker.js +168 -0
  67. package/dist/entitybox-capacity-host.d.ts +17 -0
  68. package/dist/entitybox-capacity-host.js +155 -0
  69. package/dist/entitybox-capacity-owner-process.d.ts +1 -0
  70. package/dist/entitybox-capacity-owner-process.js +32 -0
  71. package/dist/entitybox-capacity-owner.d.ts +16 -0
  72. package/dist/entitybox-capacity-owner.js +90 -0
  73. package/dist/entitybox-capacity-programs.d.ts +7 -0
  74. package/dist/entitybox-capacity-programs.js +49 -0
  75. package/dist/entitybox-capacity-provisioner.d.ts +82 -0
  76. package/dist/entitybox-capacity-provisioner.js +404 -0
  77. package/dist/entitybox-capacity-publication.d.ts +29 -0
  78. package/dist/entitybox-capacity-publication.js +199 -0
  79. package/dist/entitybox-capacity-registration.d.ts +36 -0
  80. package/dist/entitybox-capacity-registration.js +75 -0
  81. package/dist/entitybox-capacity-worker.d.ts +29 -0
  82. package/dist/entitybox-capacity-worker.js +113 -0
  83. package/dist/entitybox-computer-task.d.ts +69 -0
  84. package/dist/entitybox-computer-task.js +176 -0
  85. package/dist/entitybox-controller-recovery.d.ts +40 -0
  86. package/dist/entitybox-controller-recovery.js +156 -0
  87. package/dist/entitybox-desktop-action-server.d.ts +34 -0
  88. package/dist/entitybox-desktop-action-server.js +176 -0
  89. package/dist/entitybox-desktop-admission.d.ts +32 -0
  90. package/dist/entitybox-desktop-admission.js +79 -0
  91. package/dist/entitybox-display-binding.d.ts +13 -0
  92. package/dist/entitybox-display-binding.js +31 -0
  93. package/dist/entitybox-execution-container.d.ts +82 -0
  94. package/dist/entitybox-execution-container.js +450 -0
  95. package/dist/entitybox-execution-host.d.ts +40 -0
  96. package/dist/entitybox-execution-host.js +168 -0
  97. package/dist/entitybox-execution-lease.d.ts +81 -0
  98. package/dist/entitybox-execution-lease.js +332 -0
  99. package/dist/entitybox-file-inputs.d.ts +51 -0
  100. package/dist/entitybox-file-inputs.js +182 -0
  101. package/dist/entitybox-file-session.d.ts +38 -0
  102. package/dist/entitybox-file-session.js +82 -0
  103. package/dist/entitybox-host-process.d.ts +12 -0
  104. package/dist/entitybox-host-process.js +120 -0
  105. package/dist/entitybox-install.d.ts +10 -0
  106. package/dist/entitybox-install.js +40 -0
  107. package/dist/entitybox-mcp-broker.d.ts +77 -0
  108. package/dist/entitybox-mcp-broker.js +420 -0
  109. package/dist/entitybox-mcp-contract.d.ts +10 -0
  110. package/dist/entitybox-mcp-contract.js +24 -0
  111. package/dist/entitybox-mcp-guard.d.ts +3 -0
  112. package/dist/entitybox-mcp-guard.js +167 -0
  113. package/dist/entitybox-model-artifact.d.ts +9 -0
  114. package/dist/entitybox-model-artifact.js +83 -0
  115. package/dist/entitybox-native-services.d.ts +33 -0
  116. package/dist/entitybox-native-services.js +172 -0
  117. package/dist/entitybox-operation.d.ts +4 -0
  118. package/dist/entitybox-operation.js +34 -0
  119. package/dist/entitybox-provider-broker.d.ts +41 -0
  120. package/dist/entitybox-provider-broker.js +149 -0
  121. package/dist/entitybox-queue-request.d.ts +32 -0
  122. package/dist/entitybox-queue-request.js +141 -0
  123. package/dist/entitybox-recovery-host.d.ts +12 -0
  124. package/dist/entitybox-recovery-host.js +80 -0
  125. package/dist/entitybox-recovery-store.d.ts +33 -0
  126. package/dist/entitybox-recovery-store.js +150 -0
  127. package/dist/entitybox-recovery-worker.d.ts +30 -0
  128. package/dist/entitybox-recovery-worker.js +134 -0
  129. package/dist/entitybox-vault-provider.d.ts +27 -0
  130. package/dist/entitybox-vault-provider.js +127 -0
  131. package/dist/harness-registry.js +3 -1
  132. package/dist/index.js +72 -38
  133. package/dist/install.d.ts +14 -2
  134. package/dist/install.js +115 -10
  135. package/dist/model-cache.d.ts +38 -0
  136. package/dist/model-cache.js +137 -0
  137. package/dist/request-pump.d.ts +3 -0
  138. package/dist/request-pump.js +21 -7
  139. package/dist/session-runner.d.ts +8 -1
  140. package/dist/session-runner.js +48 -3
  141. package/dist/supabase-client.js +4 -1
  142. package/package.json +5 -1
  143. package/scripts/copy-assets.js +4 -2
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ // What every model probe sits behind: one answer per (binary, version), kept
3
+ // for the heartbeat, which must never wait for a CLI to start. claude-models.ts
4
+ // explains why it is shaped this way; codex-models.ts uses it the same way.
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createModelCache = createModelCache;
40
+ exports.makeProbeDir = makeProbeDir;
41
+ const fs = __importStar(require("fs"));
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const paths_1 = require("./paths");
45
+ /** Re-ask now and then even when nothing changed: the CLI's list can move
46
+ * without a CLI update. */
47
+ const REFRESH_MS = 6 * 60 * 60 * 1000;
48
+ const RETRY_AFTER_FAIL_MS = 30 * 60 * 1000;
49
+ function createModelCache(opts) {
50
+ let good = null;
51
+ let failed = null;
52
+ let inflight = null;
53
+ const start = (bin, key) => {
54
+ if (inflight)
55
+ return;
56
+ inflight = opts.probe(bin).then(result => {
57
+ if (result.ok) {
58
+ if (good?.key === key && opts.keep?.(good.report, result.report)) {
59
+ good = { ...good, at: opts.now() };
60
+ if (failed?.key === key)
61
+ failed = null;
62
+ return;
63
+ }
64
+ const changed = !good || good.report.models.join() !== result.report.models.join();
65
+ good = { key, report: result.report, at: opts.now() };
66
+ if (failed?.key === key)
67
+ failed = null;
68
+ if (changed) {
69
+ const detail = opts.describe?.(result.report);
70
+ opts.log(`[models] ${opts.agent}: ${result.report.models.length} models from the CLI${detail ? ` (${detail})` : ''}`);
71
+ }
72
+ }
73
+ else {
74
+ // An answer this exact binary already gave stays good: a refresh
75
+ // that fails is a reason to retry, not to forget it.
76
+ failed = { key, at: opts.now() };
77
+ const kept = good?.key === key;
78
+ opts.log(`[models] could not read ${opts.agent}'s model list (${result.reason}) — ${kept ? 'keeping the last answer' : 'offering the built-in list'}; next try in ${RETRY_AFTER_FAIL_MS / 60000} min`);
79
+ }
80
+ }).catch(() => { failed = { key, at: opts.now() }; })
81
+ .finally(() => { inflight = null; });
82
+ };
83
+ return {
84
+ /**
85
+ * The models for this binary state, or null to mean "use the built-in
86
+ * list". Never waits: a missing or stale answer is fetched in the
87
+ * background and arrives on a later call.
88
+ */
89
+ get(bin, key) {
90
+ const now = opts.now();
91
+ const recentlyFailed = failed?.key === key && now - failed.at < RETRY_AFTER_FAIL_MS;
92
+ if (good?.key === key) {
93
+ if (now - good.at > REFRESH_MS && !recentlyFailed)
94
+ start(bin, key);
95
+ return good.report;
96
+ }
97
+ if (!recentlyFailed)
98
+ start(bin, key);
99
+ // A new CLI version that has not answered yet: keep showing the last
100
+ // real list — closer to the truth than the constant, and it stops the
101
+ // pickers flickering to the built-in list across an upgrade. Once the
102
+ // new version has actually failed, the built-in list it is.
103
+ return failed?.key === key ? null : (good?.report ?? null);
104
+ },
105
+ /** The last real answer, whichever binary gave it. */
106
+ last() {
107
+ return good?.report ?? null;
108
+ },
109
+ };
110
+ }
111
+ /** A throwaway folder for one probe, under RUNTIME_HOME/model-probe. Folders
112
+ * older than a day are swept — a probe's own cleanup can lose a race with
113
+ * Windows releasing its files. */
114
+ function makeProbeDir(prefix = 'p-') {
115
+ const root = path.join(paths_1.RUNTIME_HOME, 'model-probe');
116
+ try {
117
+ fs.mkdirSync(root, { recursive: true });
118
+ const cutoff = Date.now() - 24 * 60 * 60 * 1000;
119
+ for (const name of fs.readdirSync(root)) {
120
+ const p = path.join(root, name);
121
+ try {
122
+ if (fs.lstatSync(p).mtimeMs < cutoff)
123
+ fs.rmSync(p, { recursive: true, force: true });
124
+ }
125
+ catch { /* next time */ }
126
+ }
127
+ return fs.mkdtempSync(path.join(root, prefix));
128
+ }
129
+ catch {
130
+ try {
131
+ return fs.mkdtempSync(path.join(os.tmpdir(), `ainode-model-probe-${prefix}`));
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
137
+ }
@@ -1,3 +1,4 @@
1
+ import type { EntityboxQueueServices } from './entitybox-queue-request';
1
2
  export declare const DEFAULT_MAX_CONCURRENT = 4;
2
3
  /** Clamp whatever the server sent into something the pump can act on. A null,
3
4
  * a string, a 0 or a 10_000 must not be able to wedge the pump shut or uncap
@@ -9,6 +10,8 @@ export declare function clampMaxConcurrent(value: unknown): number;
9
10
  export declare function setMaxConcurrent(value: unknown): void;
10
11
  /** The node's current ceiling. Exported for /stats and the TUI. */
11
12
  export declare function maxConcurrentRuns(): number;
13
+ /** Register once before heartbeat/relay pickup can begin. No ordinary host route changes. */
14
+ export declare function configureEntityboxQueueServices(services?: EntityboxQueueServices): void;
12
15
  export declare function inflightCount(): number;
13
16
  export declare function activeRequestIdList(): string[];
14
17
  export declare function start(): void;
@@ -1,19 +1,20 @@
1
1
  "use strict";
2
- // Polls Supabase for pending requests targeted at this runtime and runs
3
- // them via session-runner. Bounded concurrency keeps a single runtime
4
- // from spawning unlimited Claude processes when a burst of requests
5
- // arrives.
6
2
  Object.defineProperty(exports, "__esModule", { value: true });
7
3
  exports.DEFAULT_MAX_CONCURRENT = void 0;
8
4
  exports.clampMaxConcurrent = clampMaxConcurrent;
9
5
  exports.setMaxConcurrent = setMaxConcurrent;
10
6
  exports.maxConcurrentRuns = maxConcurrentRuns;
7
+ exports.configureEntityboxQueueServices = configureEntityboxQueueServices;
11
8
  exports.inflightCount = inflightCount;
12
9
  exports.activeRequestIdList = activeRequestIdList;
13
10
  exports.start = start;
14
11
  exports.stop = stop;
15
12
  exports.pumpNow = pumpNow;
16
13
  exports.drain = drain;
14
+ // Polls Supabase for pending requests targeted at this runtime and runs
15
+ // them via session-runner. Bounded concurrency keeps a single runtime
16
+ // from spawning unlimited Claude processes when a burst of requests
17
+ // arrives.
17
18
  const supabase_client_1 = require("./supabase-client");
18
19
  const store_1 = require("./store");
19
20
  const session_runner_1 = require("./session-runner");
@@ -86,7 +87,17 @@ const SLOT_LEAK_BACKSTOP_MS = 12 * 60 * 60 * 1000; // 12 hours
86
87
  const SLOT_TIMEOUT_GRACE_MS = 5 * 60 * 1000; // pad over a node timeout
87
88
  let timer = null;
88
89
  let stopped = false;
90
+ let picking = false;
89
91
  let inflight = 0;
92
+ let entityboxServices;
93
+ let entityboxConfigured = false;
94
+ /** Register once before heartbeat/relay pickup can begin. No ordinary host route changes. */
95
+ function configureEntityboxQueueServices(services) {
96
+ if (entityboxConfigured || timer || inflight || picking || stopped)
97
+ throw new Error('Computer task services must be configured before request pickup');
98
+ entityboxConfigured = true;
99
+ entityboxServices = services;
100
+ }
90
101
  // Request ids with a runRequest currently in-flight on THIS daemon.
91
102
  // Guards against launching a second run for the same request — e.g. if a
92
103
  // reclaim ever requeues one whose spawn is still alive — which is exactly
@@ -120,7 +131,7 @@ function activeRequestIdList() { return [...activeRequestIds]; }
120
131
  async function tick() {
121
132
  if (stopped)
122
133
  return;
123
- if (inflight >= maxConcurrent)
134
+ if (picking || inflight >= maxConcurrent)
124
135
  return;
125
136
  // Honour the backoff window — skip this tick if we recently failed.
126
137
  if (Date.now() < nextPickAllowedAt)
@@ -150,6 +161,7 @@ async function tick() {
150
161
  return;
151
162
  }
152
163
  let row = null;
164
+ picking = true;
153
165
  try {
154
166
  // runtime_pick_next_request returns a row record. PostgREST wraps
155
167
  // it as an object or null depending on the function shape.
@@ -165,6 +177,7 @@ async function tick() {
165
177
  }
166
178
  }
167
179
  catch (err) {
180
+ picking = false;
168
181
  if (err instanceof supabase_client_1.RpcError && err.status === 401) {
169
182
  console.error('[request-pump] unauthorized; will retry on next heartbeat.');
170
183
  return;
@@ -185,7 +198,8 @@ async function tick() {
185
198
  }
186
199
  return;
187
200
  }
188
- if (!row)
201
+ picking = false;
202
+ if (stopped || !row)
189
203
  return;
190
204
  // Defense-in-depth: never run the same request twice concurrently. The
191
205
  // server-side reclaim now keys off real activity so it shouldn't requeue
@@ -232,7 +246,7 @@ async function tick() {
232
246
  }, slotBackstopMs);
233
247
  t.unref?.();
234
248
  });
235
- const runPromise = (0, session_runner_1.runRequest)(row).catch(err => console.error(`[request-pump] runRequest threw [reqId=${reqId}]: ${err.message}`));
249
+ const runPromise = (0, session_runner_1.runRequest)(row, entityboxServices).catch(err => console.error(`[request-pump] runRequest threw [reqId=${reqId}]: ${err.message}`));
236
250
  // Heartbeat + in-flight registration live for the REAL lifetime of the
237
251
  // run (until the spawn exits), NOT just until the slot's hard timeout.
238
252
  // A task that runs longer than REQUEST_HARD_TIMEOUT_MS must keep
@@ -1,8 +1,15 @@
1
+ import { type EntityboxQueueServices } from './entitybox-queue-request';
1
2
  import type { RuntimePermissionMode, RuntimeEffortLevel } from './types';
2
3
  /** Shape of a row returned by runtime_pick_next_request. */
3
4
  export interface RuntimeRequestRow {
4
5
  id: string;
5
6
  runtime_id: string;
7
+ /** Native queue destination; EntityBox computer bindings require an exact match. */
8
+ desktop_id?: string | null;
9
+ /** Server-stamped routing marker, independent of MCP configuration. Not authorization. */
10
+ entitybox_computer_request?: boolean;
11
+ /** Server-stamped requirement; file failures must never become text-only runs. */
12
+ entitybox_file_request?: boolean;
6
13
  project_id: string | null;
7
14
  agent: 'claude' | 'claude-tui' | 'claude-bypass' | 'codex' | 'kimi' | 'gemini' | 'grok';
8
15
  mode: 'tui' | 'print';
@@ -129,4 +136,4 @@ export declare function notifySelfImproveIfEnabled(requestId: string): Promise<v
129
136
  *
130
137
  * Exported for tests. */
131
138
  export declare function resumeSessionIsVoid(workingDirectory: string | null | undefined, resumeSessionId: string | null | undefined, cwdSubstituted: boolean): boolean;
132
- export declare function runRequest(req: RuntimeRequestRow): Promise<void>;
139
+ export declare function runRequest(req: RuntimeRequestRow, entitybox?: EntityboxQueueServices): Promise<void>;
@@ -61,13 +61,17 @@ const projects_1 = require("./projects");
61
61
  const claude_print_1 = require("./claude-print");
62
62
  const subagent_usage_1 = require("./subagent-usage");
63
63
  const attachments_1 = require("./attachments");
64
+ const entitybox_file_session_1 = require("./entitybox-file-session");
65
+ const entitybox_file_inputs_1 = require("./entitybox-file-inputs");
64
66
  const codex_spawn_1 = require("./codex-spawn");
67
+ const codex_models_1 = require("./codex-models");
65
68
  const diskguard_1 = require("./diskguard");
66
69
  const kimi_spawn_1 = require("./kimi-spawn");
67
70
  const gemini_spawn_1 = require("./gemini-spawn");
68
71
  const grok_spawn_1 = require("./grok-spawn");
69
72
  const model_filter_1 = require("./model-filter");
70
73
  const agent_auth_1 = require("./agent-auth");
74
+ const entitybox_queue_request_1 = require("./entitybox-queue-request");
71
75
  const prompt_keystrokes_1 = require("./prompt-keystrokes");
72
76
  const projects_2 = require("./projects");
73
77
  const run_retry_1 = require("./run-retry");
@@ -1577,11 +1581,32 @@ async function runClaudePrint(req, cwd, installed) {
1577
1581
  // subagent-usage.ts. Taken before the spawn so nothing this run writes
1578
1582
  // can fall outside the window.
1579
1583
  const startedAtMs = Date.now();
1584
+ let inputBlocks;
1585
+ if (req.entitybox_file_request === true) {
1586
+ const abort = new AbortController(), watcher = startCancelWatcher(req.id, () => abort.abort());
1587
+ try {
1588
+ inputBlocks = await (0, entitybox_file_session_1.prepareEntityboxSessionFiles)(req, { rpc: supabase_client_1.rpc, pairing: store_1.readPairing }, abort.signal);
1589
+ }
1590
+ catch {
1591
+ const status = await (0, supabase_client_1.rpc)('runtime_get_request_status', { p_token: token(), p_request_id: req.id }).catch(() => null);
1592
+ if (!abort.signal.aborted && ['starting', 'running'].includes(status ?? '')) {
1593
+ const message = new entitybox_file_inputs_1.EntityboxFileInputError().message;
1594
+ await setStatus(req.id, { status: 'failed', errorCode: 'entitybox_file_input_failed', errorMessage: message });
1595
+ await emit(req.id, 'error', { code: 'entitybox_file_input_failed', message });
1596
+ }
1597
+ return;
1598
+ }
1599
+ finally {
1600
+ watcher.stop();
1601
+ abort.abort();
1602
+ }
1603
+ }
1580
1604
  let handle;
1581
1605
  try {
1582
1606
  handle = (0, claude_print_1.spawnClaudePrint)({
1583
1607
  workingDirectory: cwd,
1584
1608
  prompt: req.prompt,
1609
+ ...(inputBlocks ? { inputBlocks } : {}),
1585
1610
  permissionMode,
1586
1611
  effortLevel: req.effort ?? undefined,
1587
1612
  model: (0, model_filter_1.modelForAgent)('claude', req.model),
@@ -1692,11 +1717,13 @@ async function runCodex(req, cwd, installed) {
1692
1717
  await (0, diskguard_1.getDiskGuard)().sweep('pre-spawn').catch(() => { });
1693
1718
  let handle;
1694
1719
  try {
1720
+ const codexModel = (0, model_filter_1.modelForAgent)('codex', req.model);
1695
1721
  handle = (0, codex_spawn_1.spawnCodex)({
1696
1722
  workingDirectory: cwd,
1697
1723
  prompt: finalPrompt,
1698
- model: (0, model_filter_1.modelForAgent)('codex', req.model),
1724
+ model: codexModel,
1699
1725
  effortLevel: req.effort ?? undefined,
1726
+ supportedEfforts: (0, codex_models_1.codexModelEfforts)(codexModel),
1700
1727
  bypassPermissions: req.permission_mode === 'bypassPermissions',
1701
1728
  skipGitRepoCheck: true,
1702
1729
  resumeThreadId: req.resume_session_id ?? undefined,
@@ -2153,7 +2180,20 @@ async function buildMemoryManifest(installed) {
2153
2180
  }
2154
2181
  }
2155
2182
  // ── Dispatcher ─────────────────────────────────────────────────────────────
2156
- async function runRequest(req) {
2183
+ async function runRequest(req, entitybox) {
2184
+ if (await (0, entitybox_queue_request_1.runEntityboxQueueRequest)(req, { rpc: supabase_client_1.rpc, pairing: store_1.readPairing }, entitybox))
2185
+ return;
2186
+ if (req.entitybox_file_request === true) {
2187
+ try {
2188
+ (0, entitybox_file_session_1.entityboxFileSessionConfiguration)(req);
2189
+ }
2190
+ catch {
2191
+ const message = "This runtime cannot read the attached images or PDFs. Choose a compatible runtime.";
2192
+ await setStatus(req.id, { status: "failed", errorCode: "entitybox_file_runtime_unavailable", errorMessage: message });
2193
+ await emit(req.id, "error", { code: "entitybox_file_runtime_unavailable", message });
2194
+ return;
2195
+ }
2196
+ }
2157
2197
  // Auth pre-flight: cheap file/env check before we spawn so the user
2158
2198
  // gets a clean `auth_required` event instead of cryptic stderr from
2159
2199
  // the child (e.g. "Invalid API key", "401 unauthorized"). This also
@@ -2220,7 +2260,12 @@ async function runRequest(req) {
2220
2260
  req.mcp_env_overrides ?? undefined,
2221
2261
  // Per-skill variable values keyed by skill id — substituted into each
2222
2262
  // skill's {{var.<name>}} tokens before SKILL.md is written.
2223
- req.skill_var_values ?? {}, req.id);
2263
+ req.skill_var_values ?? {}, req.id, async (message) => {
2264
+ // A missing required computer connection must not start an unrestricted
2265
+ // harness or leave the row waiting for reclaim. Other installs are unchanged.
2266
+ await setStatus(req.id, { status: 'failed', errorCode: 'entitybox_computer_setup_failed', errorMessage: message });
2267
+ await emit(req.id, 'error', { code: 'entitybox_computer_setup_failed', message });
2268
+ });
2224
2269
  if (installed.mcpConfigPath || installed.skillSlugs.length > 0) {
2225
2270
  void emit(req.id, 'claude:install_complete', {
2226
2271
  mcps_installed: installed.mcpConfigPath ? true : false,
@@ -62,6 +62,7 @@ async function rpc(name, args = {}) {
62
62
  const ac = new AbortController();
63
63
  const timer = setTimeout(() => ac.abort(), DEFAULT_RPC_TIMEOUT_MS);
64
64
  let res;
65
+ let text;
65
66
  try {
66
67
  res = await fetch(url, {
67
68
  method: 'POST',
@@ -74,6 +75,9 @@ async function rpc(name, args = {}) {
74
75
  body: JSON.stringify(args),
75
76
  signal: ac.signal,
76
77
  });
78
+ // The deadline covers the full body too. A server may send headers and
79
+ // then stall; clearing the timer at headers stranded runtime pollers.
80
+ text = await res.text();
77
81
  }
78
82
  catch (err) {
79
83
  clearTimeout(timer);
@@ -89,7 +93,6 @@ async function rpc(name, args = {}) {
89
93
  throw err;
90
94
  }
91
95
  clearTimeout(timer);
92
- const text = await res.text();
93
96
  let parsed = undefined;
94
97
  if (text) {
95
98
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@addai/node",
3
- "version": "0.30.13",
3
+ "version": "0.30.14",
4
4
  "description": "Daemon that pairs a machine with your +Ai account and runs Claude / Codex / Kimi / Gemini agents on its behalf. Reachable via Supabase from Vault, Entity Studio, or any other +Ai surface.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -40,6 +40,8 @@
40
40
  "scripts": {
41
41
  "build": "tsc -p tsconfig.json && node scripts/copy-assets.js",
42
42
  "start": "node dist/cli.js",
43
+ "direct:relay": "node dist/direct/relay-main.js",
44
+ "test:direct": "npm run build && node --test test/direct-*.test.mjs",
43
45
  "dev": "tsc -p tsconfig.json && node dist/cli.js",
44
46
  "test": "npm run build && node --test test/*.test.mjs",
45
47
  "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
@@ -51,6 +53,8 @@
51
53
  },
52
54
  "dependencies": {
53
55
  "@addai/node-flows": "^1.0.0",
56
+ "@xterm/addon-serialize": "^0.14.0",
57
+ "@xterm/headless": "^6.0.0",
54
58
  "node-pty": "^1.1.0",
55
59
  "ws": "^8.21.3"
56
60
  },
@@ -1,11 +1,13 @@
1
- // tsc compiles .ts and ignores everything else, but two files in this package
2
- // are deliberately plain .mjs: they run inside a desktop container (node 22,
1
+ // tsc compiles .ts and ignores everything else, but some files in this package
2
+ // are deliberately plain JavaScript: they run inside a desktop container (node 22,
3
3
  // no build step, no node_modules) rather than in the daemon. Ship them next to
4
4
  // the compiled output so dist/ is self-contained.
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
8
  const ASSETS = [
9
+ ['src/entitybox/container-action.cjs', 'dist/entitybox/container-action.cjs'],
10
+ ['src/entitybox/container-watchdog.cjs', 'dist/entitybox/container-watchdog.cjs'],
9
11
  ['src/desktop/learn/recorder.mjs', 'dist/desktop/learn/recorder.mjs'],
10
12
  ['src/desktop/learn/injected.mjs', 'dist/desktop/learn/injected.mjs'],
11
13
  ['src/desktop/vault-seed.mjs', 'dist/desktop/vault-seed.mjs'],