@myagentroam/node 0.10.1 → 0.10.3

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,43 @@
1
+ export interface ConversationHostingConfig {
2
+ readonly enabled: boolean;
3
+ /** Relative directory inside dataDirectory. */
4
+ readonly storeDirectory?: string;
5
+ readonly inactiveRetentionDays?: number;
6
+ }
7
+ export interface DirectTransferConfig {
8
+ readonly udpPortRangeBegin: number;
9
+ readonly udpPortRangeEnd: number;
10
+ }
11
+ export interface DirectTransferUdpPortRange {
12
+ readonly begin: number;
13
+ readonly end: number;
14
+ }
15
+ export interface ComputerUseConfig {
16
+ readonly enabled: boolean;
17
+ /** Development/validation override; production distributions use the managed runtime path. */
18
+ readonly runtimeExecutable?: string;
19
+ }
20
+ export interface NodeConfig {
21
+ readonly serverUrl: string;
22
+ /** Explicit roots or the platform default resolved while loading the config. */
23
+ readonly allowedRoots: readonly string[];
24
+ /** Absolute or config-relative root for SQLite, upgrades and other private Node data. */
25
+ readonly dataDirectory?: string;
26
+ readonly conversationHosting?: ConversationHostingConfig;
27
+ readonly directTransfer?: DirectTransferConfig;
28
+ readonly computerUse?: ComputerUseConfig;
29
+ readonly nodeId?: string;
30
+ readonly credential?: string;
31
+ readonly registrationToken?: string;
32
+ }
33
+ export declare function nodeConfigPath(): string;
34
+ export declare function loadNodeConfig(path?: string): Promise<NodeConfig>;
35
+ export declare function directTransferUdpPortRange(config: Pick<NodeConfig, 'directTransfer'> | undefined): DirectTransferUdpPortRange;
36
+ /** Uses the Node service account's scope when no Workspace roots are configured. */
37
+ export declare function defaultAllowedRoots(platform?: NodeJS.Platform, homePath?: string, currentDirectory?: string): readonly string[];
38
+ export declare function nodeDatabasePath(config: NodeConfig, configPath?: string): string;
39
+ export declare function nodeDataDirectory(config: NodeConfig, configPath?: string): string;
40
+ export declare function computerUseRuntimeExecutable(config: NodeConfig, configPath?: string, platform?: NodeJS.Platform, architecture?: string): string | undefined;
41
+ export declare function hostedConversationStorePath(config: NodeConfig, configPath?: string): string | undefined;
42
+ /** Credentials are always written with owner-only POSIX permissions where supported. */
43
+ export declare function saveNodeConfig(config: NodeConfig, path?: string): Promise<void>;
package/dist/config.js CHANGED
@@ -1,4 +1,5 @@
1
- import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
1
+ import { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
2
+ import { randomUUID } from 'node:crypto';
2
3
  import { homedir } from 'node:os';
3
4
  import { dirname, isAbsolute, relative, resolve, sep, win32 } from 'node:path';
4
5
  import { computerUseRuntimeVersion } from './computer-use-runtime-version.js';
@@ -87,9 +88,18 @@ export function hostedConversationStorePath(config, configPath = nodeConfigPath(
87
88
  /** Credentials are always written with owner-only POSIX permissions where supported. */
88
89
  export async function saveNodeConfig(config, path = nodeConfigPath()) {
89
90
  await mkdir(dirname(path), { recursive: true, mode: 0o700 });
90
- await writeFile(path, `${JSON.stringify(config, undefined, 2)}\n`, { mode: 0o600 });
91
- if (process.platform !== 'win32') {
92
- await chmod(path, 0o600);
91
+ const temporary = `${path}.${randomUUID()}.tmp`;
92
+ try {
93
+ await writeFile(temporary, `${JSON.stringify(config, undefined, 2)}\n`, {
94
+ mode: 0o600,
95
+ flag: 'wx'
96
+ });
97
+ if (process.platform !== 'win32')
98
+ await chmod(temporary, 0o600);
99
+ await rename(temporary, path);
100
+ }
101
+ finally {
102
+ await rm(temporary, { force: true });
93
103
  }
94
104
  }
95
105
  function parseConversationHosting(value) {
package/dist/connector.js CHANGED
@@ -1684,7 +1684,7 @@ export class NodeConnector {
1684
1684
  nodeGeneration: () => this.nodeGeneration,
1685
1685
  send: (type, payload) => this.send(type, payload),
1686
1686
  terminalManager: this.terminalManager,
1687
- sendTerminalReady: (directSessionId) => this.send('terminal.direct.ready', { directSessionId }),
1687
+ sendTerminalReady: (directSessionId, phase) => this.send('terminal.direct.ready', { directSessionId, ...(phase ? { phase } : {}) }),
1688
1688
  udpPortRange: () => directTransferUdpPortRange(this.config),
1689
1689
  openUpload: async (descriptor) => {
1690
1690
  if (descriptor.direction !== 'UPLOAD' || descriptor.resource.kind !== 'WORKSPACE_FILE')
package/dist/main.js CHANGED
@@ -17,10 +17,13 @@ if (command === 'run') {
17
17
  const { NodeConnector } = await import('./connector.js');
18
18
  configureNodeLog(nodeDataDirectory(await loadNodeConfig(config), config));
19
19
  const connector = new NodeConnector({ configPath: config });
20
- await connector.start();
20
+ const shutdown = () => {
21
+ void connector.stop().finally(() => process.exit(0));
22
+ };
21
23
  for (const signal of ['SIGINT', 'SIGTERM']) {
22
- process.once(signal, () => connector.stop());
24
+ process.once(signal, shutdown);
23
25
  }
26
+ await connector.start();
24
27
  }
25
28
  else if (command === 'supervise') {
26
29
  if (process.argv[1] === undefined)
@@ -47,7 +47,7 @@ export class DirectTransferService {
47
47
  this.leaseGraceMs = options.leaseGraceMs ?? LEASE_GRACE_MS;
48
48
  this.leaseCheckMs = options.leaseCheckMs ?? LEASE_CHECK_MS;
49
49
  if (options.terminalManager !== undefined)
50
- this.terminalDirect = new TerminalDirectService(options.terminalManager, (id) => options.sendTerminalReady?.(id), (command, peer) => {
50
+ this.terminalDirect = new TerminalDirectService(options.terminalManager, (id, phase) => options.sendTerminalReady?.(id, phase), (command, peer) => {
51
51
  const transport = this.transports.get(command.transportSessionId);
52
52
  return (transport?.peer === peer &&
53
53
  transport.command.workbenchConnectionId === command.workbenchConnectionId &&
@@ -114,6 +114,9 @@ export class TerminalDirectService {
114
114
  this.sendFrame(session, frame);
115
115
  channel.onmessage = (event) => this.accept(session, event.data);
116
116
  this.manager.startCommand(session.command.terminalId);
117
+ void Promise.resolve()
118
+ .then(() => this.sendReady(session.command.directSessionId, 'ATTACHED'))
119
+ .catch(() => console.warn('AUDIT_RECEIPT_UNAVAILABLE'));
117
120
  }
118
121
  catch (error) {
119
122
  this.remove(session, error instanceof Error && error.message === 'TERMINAL_ATTACH_CONFLICT'
@@ -44,8 +44,8 @@ export class WorkspaceQueueWorkbenchService {
44
44
  version: queue.version,
45
45
  paused: queue.paused,
46
46
  items: queue.itemIds.flatMap((itemId) => {
47
- const item = this.options.runtime.getQueueItem(itemId);
48
- if (item === undefined || item.clientMessageId.startsWith('goal:'))
47
+ const item = this.publicQueueItem(itemId);
48
+ if (item === undefined)
49
49
  return [];
50
50
  const session = this.options.runtime.getAgentSession(item.sessionId);
51
51
  return [
@@ -89,7 +89,16 @@ export class WorkspaceQueueWorkbenchService {
89
89
  throw new Error('QUEUE_INVALID');
90
90
  const session = this.requireSession(input);
91
91
  assertSessionControlOwner(this.options.runtime, session.id, input.__requestUserId);
92
- this.options.runtime.reorderSessionQueue(session.id, input.expectedVersion, input.queueItemIds);
92
+ const current = this.options.runtime.sessionQueue(session.id);
93
+ const publicItemIds = new Set(current.itemIds.filter((itemId) => this.publicQueueItem(itemId) !== undefined));
94
+ const reorderedIds = input.queueItemIds;
95
+ if (reorderedIds.length !== publicItemIds.size ||
96
+ new Set(reorderedIds).size !== reorderedIds.length ||
97
+ reorderedIds.some((itemId) => !publicItemIds.has(itemId)))
98
+ throw new Error('QUEUE_VERSION_CONFLICT');
99
+ let index = 0;
100
+ // Reorder only public slots, leaving internal continuations in place.
101
+ this.options.runtime.reorderSessionQueue(session.id, input.expectedVersion, current.itemIds.map((itemId) => (publicItemIds.has(itemId) ? reorderedIds[index++] : itemId)));
93
102
  this.options.emit(session.workspaceId, session.id);
94
103
  return {
95
104
  queue: this.present(session.workspaceId, session.id),
@@ -151,6 +160,10 @@ export class WorkspaceQueueWorkbenchService {
151
160
  throw new Error('SESSION_NOT_FOUND');
152
161
  return session;
153
162
  }
163
+ publicQueueItem(itemId) {
164
+ const item = this.options.runtime.getQueueItem(itemId);
165
+ return item?.clientMessageId.startsWith('goal:') ? undefined : item;
166
+ }
154
167
  requireItem(itemId, workspaceId) {
155
168
  const item = this.options.runtime.getQueueItem(itemId);
156
169
  if (item === undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -9,6 +9,7 @@
9
9
  "scripts/install-web-browser.mjs",
10
10
  "vendor/ripgrep/**/*",
11
11
  "vendor/ctags/**/*",
12
+ "dist/config.d.ts",
12
13
  "LICENSE",
13
14
  "NOTICE"
14
15
  ],
@@ -36,14 +37,22 @@
36
37
  "playwright": "1.62.1",
37
38
  "ws": "^8.21.3",
38
39
  "zod": "4.4.3",
39
- "@myagentroam/agent": "0.10.1",
40
- "@myagentroam/protocol": "0.10.1",
40
+ "@myagentroam/agent": "0.10.3",
41
+ "@myagentroam/code-navigation": "0.10.1",
41
42
  "@myagentroam/marctl": "0.10.1",
42
- "@myagentroam/code-navigation": "0.10.1"
43
+ "@myagentroam/protocol": "0.10.3"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@types/ws": "^8.18.1"
46
47
  },
48
+ "exports": {
49
+ "./config": {
50
+ "types": "./dist/config.d.ts",
51
+ "import": "./dist/config.js"
52
+ },
53
+ "./cli": "./dist/main.js",
54
+ "./package.json": "./package.json"
55
+ },
47
56
  "scripts": {
48
57
  "postinstall": "node scripts/install-web-browser.mjs",
49
58
  "build": "node ../scripts/clean-build-output.mjs dist && tsc -p tsconfig.json",