@myagentroam/node 0.9.179 → 0.10.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.
package/NOTICE CHANGED
@@ -2,3 +2,10 @@ MyAgentRoam
2
2
  Copyright 2026 MyAgentRoam contributors
3
3
 
4
4
  This product includes software developed by the MyAgentRoam project.
5
+
6
+ Enterprise implementation and product composition:
7
+ Copyright 2026 aCHAOS
8
+ Author and licensing contact: aCHAOS (achaosxyz@gmail.com)
9
+ Licensed under MyAgentRoam Enterprise Source-Available License 1.0; see
10
+ ee/LICENSE and LICENSING.md. Independent core and third-party notices remain
11
+ applicable; this attribution does not transfer any contributor's copyright.
@@ -1 +1 @@
1
- export const computerUseRuntimeVersion = '0.9.96';
1
+ export const computerUseRuntimeVersion = '0.10.1';
@@ -294,9 +294,6 @@ function safeRuntimePath(root, path) {
294
294
  throw new ComputerUseRuntimeError('COMPUTER_RUNTIME_MANIFEST_INVALID');
295
295
  return target;
296
296
  }
297
- function isMissing(error) {
298
- return (error instanceof Error && 'code' in error && error.code === 'ENOENT');
299
- }
300
297
  function isAlreadyExists(error) {
301
298
  return (error instanceof Error && 'code' in error && error.code === 'EEXIST');
302
299
  }
package/dist/connector.js CHANGED
@@ -1674,13 +1674,13 @@ export class NodeConnector {
1674
1674
  this.scheduledSessions.start();
1675
1675
  await this.initializeConversationHosting();
1676
1676
  this.computerUseEnablement.initialize();
1677
- this.directTransferService ??= this.createDirectTransferService();
1677
+ this.directTransferService ??= await this.createDirectTransferService();
1678
1678
  this.connectionLifecycle.start();
1679
1679
  this.controlChannel.connect();
1680
1680
  }
1681
- createDirectTransferService() {
1681
+ async createDirectTransferService() {
1682
1682
  try {
1683
- return new DirectTransferService({
1683
+ return await DirectTransferService.create({
1684
1684
  nodeGeneration: () => this.nodeGeneration,
1685
1685
  send: (type, payload) => this.send(type, payload),
1686
1686
  terminalManager: this.terminalManager,
@@ -49,7 +49,7 @@ export class CodexRunner extends AbstractRunner {
49
49
  }).find((profile) => profile.runner === this.name);
50
50
  return { ...base, models: this.profileCache?.profile.models ?? [] };
51
51
  }
52
- cachedProfile(capabilities, environment = {}) {
52
+ cachedProfile(capabilities, _environment = {}) {
53
53
  const base = this.profile(capabilities);
54
54
  return this.profileCache === undefined ||
55
55
  this.profileCacheVersion !== capabilities.codex.version
@@ -20,6 +20,7 @@ const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0
20
20
  const MAX_EDIT_IMAGES = 5;
21
21
  const SUPPORTED_EDIT_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp']);
22
22
  const IMAGE_GENERATION_RESPONSE_TIMEOUT_MS = 5 * 60 * 1000;
23
+ const IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
23
24
  export const codexImageGenToolDefinition = {
24
25
  name: 'codex_image_gen',
25
26
  agentScope: 'ROOT_ONLY',
@@ -230,19 +231,34 @@ async function readJsonResponse(response, signal) {
230
231
  if (response.body === null)
231
232
  return {};
232
233
  const reader = response.body.getReader();
234
+ const readController = new AbortController();
235
+ const readSignal = AbortSignal.any([signal, readController.signal]);
233
236
  const abort = () => {
234
- void reader.cancel(signal.reason).catch(() => undefined);
237
+ void reader.cancel(readSignal.reason).catch(() => undefined);
235
238
  };
236
- signal.addEventListener('abort', abort, { once: true });
239
+ readSignal.addEventListener('abort', abort, { once: true });
240
+ const onIdle = () => {
241
+ readController.abort(new MarAgentError('MAR_AGENT_IMAGE_GENERATION_READ_TIMEOUT', 'Image response body read timed out waiting for data.', {
242
+ details: {
243
+ reason: 'IMAGE_RESPONSE_READ_TIMEOUT',
244
+ idleTimeoutMs: IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS
245
+ }
246
+ }));
247
+ };
248
+ let readTimeout = setTimeout(onIdle, IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS);
237
249
  const chunks = [];
238
250
  let bytes = 0;
239
251
  try {
240
- signal.throwIfAborted();
252
+ readSignal.throwIfAborted();
241
253
  for (;;) {
242
- const chunk = await reader.read();
243
- signal.throwIfAborted();
254
+ const chunk = await waitForImageStep(reader.read(), readSignal);
255
+ readSignal.throwIfAborted();
244
256
  if (chunk.done)
245
257
  break;
258
+ if (chunk.value.byteLength === 0)
259
+ continue;
260
+ clearTimeout(readTimeout);
261
+ readTimeout = setTimeout(onIdle, IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS);
246
262
  bytes += chunk.value.byteLength;
247
263
  if (bytes > RESPONSE_MAX_BYTES)
248
264
  throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Image response exceeded the size limit.');
@@ -254,7 +270,8 @@ async function readJsonResponse(response, signal) {
254
270
  throw error;
255
271
  }
256
272
  finally {
257
- signal.removeEventListener('abort', abort);
273
+ clearTimeout(readTimeout);
274
+ readSignal.removeEventListener('abort', abort);
258
275
  reader.releaseLock();
259
276
  }
260
277
  try {
@@ -43,7 +43,7 @@ export class OpenCodeRunner extends AbstractRunner {
43
43
  }).find((profile) => profile.runner === this.name);
44
44
  return { ...base, models: [] };
45
45
  }
46
- cachedProfile(capabilities, environment = {}) {
46
+ cachedProfile(capabilities, _environment = {}) {
47
47
  const cached = this.profileCache;
48
48
  return cached === undefined
49
49
  ? this.profile(capabilities)
@@ -70,10 +70,6 @@ function candidates(path) {
70
70
  ? [path]
71
71
  : [path, ...extensionlessSourceExtensions.map((extension) => `${path}${extension}`)];
72
72
  }
73
- function sourceFileStem(path) {
74
- const name = path.slice(path.lastIndexOf('/') + 1);
75
- return name.replace(/(?:\.d)?\.[^.]+$/u, '');
76
- }
77
73
  function unresolvedSpecifierScore(path, specifier) {
78
74
  const normalizedSpecifier = specifier.startsWith('@/') ? specifier.slice(2) : specifier;
79
75
  return trailingPathCandidateScore(path, unresolvedCandidates(normalizedSpecifier));
@@ -1,3 +1,4 @@
1
+ import { createSocket } from 'node:dgram';
1
2
  import { directDataControlFrameSchema, directNodeCommandSchema } from '@myagentroam/protocol';
2
3
  import { TerminalDirectService } from './terminal-direct-service.js';
3
4
  import { IceUdpMuxListener as NativeIceUdpMuxListener } from 'node-datachannel';
@@ -21,12 +22,18 @@ export class DirectTransferService {
21
22
  leaseCheckMs;
22
23
  terminalDirect;
23
24
  disposed = false;
24
- constructor(options) {
25
- this.options = options;
26
- this.now = options.now ?? Date.now;
25
+ static async create(options) {
27
26
  const range = options.udpPortRange?.() ?? { begin: 49_152, end: 49_215 };
28
27
  const createIceUdpMuxListener = options.createIceUdpMuxListener ?? ((port) => new NativeIceUdpMuxListener(port));
29
- this.iceUdpMuxListener = bindIceUdpMuxListener(range, createIceUdpMuxListener);
28
+ // Windows can accept an IPv6 mux bind while another IPv4 endpoint owns the port.
29
+ const probe = options.probeUdp4Port ?? (process.platform === 'win32' ? probeUdp4Port : undefined);
30
+ const listener = await bindIceUdpMuxListener(range, createIceUdpMuxListener, probe);
31
+ return new DirectTransferService(options, listener);
32
+ }
33
+ constructor(options, iceUdpMuxListener) {
34
+ this.options = options;
35
+ this.now = options.now ?? Date.now;
36
+ this.iceUdpMuxListener = iceUdpMuxListener;
30
37
  const udpPort = this.iceUdpMuxListener.port();
31
38
  this.peerConfiguration = {
32
39
  iceServers: [],
@@ -382,7 +389,10 @@ export class DirectTransferService {
382
389
  const complete = (error) => {
383
390
  channel.removeEventListener('bufferedamountlow', available);
384
391
  channel.removeEventListener('close', closed);
385
- error === undefined ? resolve() : reject(error);
392
+ if (error === undefined)
393
+ resolve();
394
+ else
395
+ reject(error);
386
396
  };
387
397
  const available = () => complete();
388
398
  const closed = () => complete(new Error('DIRECT_CHANNEL_CLOSED'));
@@ -465,10 +475,12 @@ function openFrameSessionId(data) {
465
475
  return undefined;
466
476
  }
467
477
  }
468
- function bindIceUdpMuxListener(range, create) {
478
+ async function bindIceUdpMuxListener(range, create, probe) {
469
479
  let lastError;
470
480
  for (let port = range.begin; port <= range.end; port += 1) {
471
481
  try {
482
+ if (probe !== undefined)
483
+ await probe(port);
472
484
  return create(port);
473
485
  }
474
486
  catch (error) {
@@ -477,6 +489,13 @@ function bindIceUdpMuxListener(range, create) {
477
489
  }
478
490
  throw new Error('DIRECT_UDP_PORT_UNAVAILABLE', { cause: lastError });
479
491
  }
492
+ export function probeUdp4Port(port) {
493
+ const socket = createSocket({ type: 'udp4', reuseAddr: false });
494
+ return new Promise((resolve, reject) => {
495
+ socket.once('error', (error) => socket.close(() => reject(error)));
496
+ socket.bind({ port, address: '0.0.0.0', exclusive: true }, () => socket.close(() => resolve()));
497
+ });
498
+ }
480
499
  export function fingerprint(sdp) {
481
500
  const match = sdp?.match(/^a=fingerprint:(sha-256 [A-F0-9:]+)\r?$/imu);
482
501
  return match?.[1];
@@ -1798,18 +1798,6 @@ function publishedTemplateEntry(value) {
1798
1798
  resolvedTarget
1799
1799
  };
1800
1800
  }
1801
- function publishedTemplateFiles(value) {
1802
- if (!Array.isArray(value))
1803
- throw new Error('CONVERSATION_TEMPLATE_VERSION_CORRUPTED');
1804
- const paths = new Set();
1805
- return value.map((candidate) => {
1806
- const file = publishedTemplateFile(candidate);
1807
- if (paths.has(file.relativePath))
1808
- throw new Error('CONVERSATION_TEMPLATE_VERSION_CORRUPTED');
1809
- paths.add(file.relativePath);
1810
- return file;
1811
- });
1812
- }
1813
1801
  function publishedTemplateFile(value, requireKind = false) {
1814
1802
  if (!record(value) ||
1815
1803
  (requireKind && value.kind !== 'FILE') ||
@@ -22,10 +22,6 @@ const MAX_TAGS_BYTES = 512 * 1024 * 1024;
22
22
  const MAX_CANDIDATES = 100;
23
23
  const MAX_RESULTS = 20;
24
24
  const MAX_REFERENCES = 100;
25
- const MAX_TAG_LINE_BYTES = 16 * 1024;
26
- const READ_BLOCK_BYTES = 4096;
27
- const MAX_TARGET_LINE_SCAN_BYTES = MAX_SOURCE_BYTES;
28
- const MAX_TARGET_PREVIEW_CHARACTERS = 512;
29
25
  /**
30
26
  * Builds a demand-driven, standard u-ctags declaration index. It never keeps
31
27
  * a complete symbol table, watcher, or idle child process in memory.
@@ -77,15 +77,15 @@ export class WorkspaceFileService {
77
77
  : readWorkspaceFileContentRange(workspacePath, path, offset, limit);
78
78
  }
79
79
  readDirect(workspace, input, workspacePath = workspace.path) {
80
- const service = this;
80
+ const readContent = this.readContent.bind(this);
81
81
  return (async function* () {
82
- const initial = (await service.readContent(workspace, { path: input.path, offset: input.range?.offset ?? 0, limit: 1 }, workspacePath));
82
+ const initial = (await readContent(workspace, { path: input.path, offset: input.range?.offset ?? 0, limit: 1 }, workspacePath));
83
83
  if (initial.size !== input.size || initial.sourceRevision !== input.revision)
84
84
  throw new Error('DIRECT_FILE_REVISION_CHANGED');
85
85
  let offset = input.range?.offset ?? 0;
86
86
  const endOffset = input.range === undefined ? input.size : input.range.offset + input.range.length;
87
87
  while (offset < endOffset) {
88
- const range = (await service.readContent(workspace, {
88
+ const range = (await readContent(workspace, {
89
89
  path: input.path,
90
90
  offset,
91
91
  limit: Math.min(512 * 1024, endOffset - offset)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.9.179",
3
+ "version": "0.10.1",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -36,10 +36,10 @@
36
36
  "playwright": "1.62.1",
37
37
  "ws": "^8.21.3",
38
38
  "zod": "4.4.3",
39
- "@myagentroam/agent": "0.9.179",
40
- "@myagentroam/code-navigation": "0.9.129",
41
- "@myagentroam/marctl": "0.9.123",
42
- "@myagentroam/protocol": "0.9.179"
39
+ "@myagentroam/agent": "0.10.1",
40
+ "@myagentroam/protocol": "0.10.1",
41
+ "@myagentroam/marctl": "0.10.1",
42
+ "@myagentroam/code-navigation": "0.10.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/ws": "^8.18.1"
@@ -51,7 +51,7 @@
51
51
  "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
52
52
  "dev": "tsx watch src/main.ts",
53
53
  "start": "node dist/main.js",
54
- "test:unit": "vitest run --config vitest.config.mts",
54
+ "test:unit": "vitest run --config vitest.config.mts && node --test test/unit/*.test.mjs",
55
55
  "test:e2e:real": "vitest run --config vitest.e2e.config.mts"
56
56
  }
57
57
  }