@myagentroam/node 0.12.0 → 0.12.2

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 (142) hide show
  1. package/dist/code-navigation/index.js +2 -0
  2. package/dist/code-navigation/languages/c-family.js +9 -0
  3. package/dist/code-navigation/languages/c-preprocessor.js +30 -0
  4. package/dist/code-navigation/languages/c.js +8 -0
  5. package/dist/code-navigation/languages/cpp.js +10 -0
  6. package/dist/code-navigation/languages/csharp.js +18 -0
  7. package/dist/code-navigation/languages/css.js +7 -0
  8. package/dist/code-navigation/languages/ecmascript.js +44 -0
  9. package/dist/code-navigation/languages/file-target.js +9 -0
  10. package/dist/code-navigation/languages/go.js +32 -0
  11. package/dist/code-navigation/languages/html.js +7 -0
  12. package/dist/code-navigation/languages/jvm.js +17 -0
  13. package/dist/code-navigation/languages/less.js +7 -0
  14. package/dist/code-navigation/languages/markdown.js +113 -0
  15. package/dist/code-navigation/languages/markup-reference.js +27 -0
  16. package/dist/code-navigation/languages/objective-c.js +11 -0
  17. package/dist/code-navigation/languages/objective-cpp.js +10 -0
  18. package/dist/code-navigation/languages/python.js +17 -0
  19. package/dist/code-navigation/languages/rust.js +18 -0
  20. package/dist/code-navigation/languages/sass.js +7 -0
  21. package/dist/code-navigation/languages/scss.js +7 -0
  22. package/dist/code-navigation/languages/stylesheet-reference.js +37 -0
  23. package/dist/code-navigation/languages/vue.js +75 -0
  24. package/dist/code-navigation/registry.js +72 -0
  25. package/dist/code-navigation/source-ranges.js +17 -0
  26. package/dist/code-navigation/symbol-maps.js +257 -0
  27. package/dist/code-navigation/symbol-matcher.js +48 -0
  28. package/dist/code-navigation/symbol-navigation.js +1 -0
  29. package/dist/code-navigation/types.js +1 -0
  30. package/dist/ctags-binary.js +3 -3
  31. package/dist/hosting/hosted-conversation-node-service.js +1 -1
  32. package/dist/marctl/bin/marctl.mjs +6 -0
  33. package/dist/marctl/bin/marnodes.mjs +6 -0
  34. package/dist/marctl/bin/marscp.mjs +6 -0
  35. package/dist/marctl/bin/marssh.mjs +6 -0
  36. package/dist/marctl/package.json +1 -0
  37. package/dist/marctl/src/cli.mjs +271 -0
  38. package/dist/marctl/src/client.mjs +291 -0
  39. package/dist/marctl/src/config.mjs +46 -0
  40. package/dist/marctl/src/direct-control.mjs +225 -0
  41. package/dist/marctl/src/direct-errors.mjs +48 -0
  42. package/dist/marctl/src/direct-process.mjs +374 -0
  43. package/dist/marctl/src/direct-transport.mjs +235 -0
  44. package/dist/marctl/src/direct.mjs +421 -0
  45. package/dist/marctl/src/errors.mjs +11 -0
  46. package/dist/marctl/src/i18n/en-US.mjs +285 -0
  47. package/dist/marctl/src/i18n/index.mjs +20 -0
  48. package/dist/marctl/src/i18n/zh-CN.mjs +269 -0
  49. package/dist/marctl/src/scp-channel.mjs +99 -0
  50. package/dist/marctl/src/scp-copy.mjs +46 -0
  51. package/dist/marctl/src/scp-endpoint.mjs +29 -0
  52. package/dist/marctl/src/scp-protocol.mjs +2 -0
  53. package/dist/marctl/src/scp-worker.cjs +266 -0
  54. package/dist/marctl/src/scp-workers.mjs +179 -0
  55. package/dist/marctl/src/scp.mjs +64 -0
  56. package/dist/marctl/src/session-args.mjs +233 -0
  57. package/dist/marctl/src/session-input.mjs +43 -0
  58. package/dist/marctl/src/session-prepare.mjs +87 -0
  59. package/dist/marctl/src/session-target.mjs +26 -0
  60. package/dist/marctl/src/session-wait.mjs +232 -0
  61. package/dist/marctl/src/sessions.mjs +93 -0
  62. package/dist/marctl/src/terminal-frame.mjs +48 -0
  63. package/dist/marctl/src/terminal-interaction.mjs +177 -0
  64. package/dist/marctl/src/terminal-race.mjs +117 -0
  65. package/dist/marctl/src/terminal-relay-sender.mjs +129 -0
  66. package/dist/marctl/src/terminal-relay.mjs +305 -0
  67. package/dist/marctl/src/terminal.mjs +152 -0
  68. package/dist/marctl-guidance.js +1 -1
  69. package/dist/marctl.js +1 -1
  70. package/dist/marnodes.js +1 -1
  71. package/dist/marscp.js +1 -1
  72. package/dist/marssh.js +1 -1
  73. package/dist/native-session-history.js +1 -1
  74. package/dist/ripgrep-binary.js +3 -3
  75. package/dist/runner/codex-runner.js +2 -2
  76. package/dist/runner/mar-agent/agent-operation-presentation.js +22 -10
  77. package/dist/runner/mar-agent/codex-imagegen-skill.js +15 -23
  78. package/dist/runner/mar-agent/conversation-normalizer.js +4 -18
  79. package/dist/runner/mar-agent/image-generation-extensions.js +1 -1
  80. package/dist/runner/mar-agent/image-generation.js +73 -20
  81. package/dist/runner/mar-agent/session-runtime-registry.js +5 -3
  82. package/dist/service/code-navigation/file-reference-parser.js +1 -1
  83. package/dist/service/node-terminal-channel.js +1 -1
  84. package/dist/session/session-catalog-service.js +4 -1
  85. package/dist/workspace/workspace-code-navigation-service.js +2 -2
  86. package/dist/workspace/workspace-git-exclude-service.js +1 -1
  87. package/package.json +11 -9
  88. package/vendor/ctags/NOTICE +0 -22
  89. package/vendor/ctags/darwin-arm64/ctags +0 -0
  90. package/vendor/ctags/darwin-x64/ctags +0 -0
  91. package/vendor/ctags/licenses/COPYING +0 -340
  92. package/vendor/ctags/licenses/COPYING.MinGW-w64-runtime.txt +0 -240
  93. package/vendor/ctags/licenses/LICENSE.janssen +0 -19
  94. package/vendor/ctags/licenses/LICENSE.libyaml +0 -19
  95. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/COPYING +0 -340
  96. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/RECEIPT.yml +0 -27
  97. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/dependencies/libiconv.yml +0 -24
  98. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/dependencies/libjansson.yml +0 -19
  99. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/dependencies/libxml2.yml +0 -20
  100. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/dependencies/libyaml.yml +0 -7
  101. package/vendor/ctags/licenses/official-snapshot/darwin-arm64/dependencies/libz.yml +0 -13
  102. package/vendor/ctags/licenses/official-snapshot/darwin-x64/COPYING +0 -340
  103. package/vendor/ctags/licenses/official-snapshot/darwin-x64/RECEIPT.yml +0 -27
  104. package/vendor/ctags/licenses/official-snapshot/darwin-x64/dependencies/libiconv.yml +0 -24
  105. package/vendor/ctags/licenses/official-snapshot/darwin-x64/dependencies/libjansson.yml +0 -19
  106. package/vendor/ctags/licenses/official-snapshot/darwin-x64/dependencies/libxml2.yml +0 -20
  107. package/vendor/ctags/licenses/official-snapshot/darwin-x64/dependencies/libyaml.yml +0 -7
  108. package/vendor/ctags/licenses/official-snapshot/darwin-x64/dependencies/libz.yml +0 -13
  109. package/vendor/ctags/licenses/official-snapshot/linux-arm64/COPYING +0 -340
  110. package/vendor/ctags/licenses/official-snapshot/linux-arm64/RECEIPT.yml +0 -27
  111. package/vendor/ctags/licenses/official-snapshot/linux-arm64/dependencies/libiconv.yml +0 -24
  112. package/vendor/ctags/licenses/official-snapshot/linux-arm64/dependencies/libjansson.yml +0 -19
  113. package/vendor/ctags/licenses/official-snapshot/linux-arm64/dependencies/libxml2.yml +0 -20
  114. package/vendor/ctags/licenses/official-snapshot/linux-arm64/dependencies/libyaml.yml +0 -7
  115. package/vendor/ctags/licenses/official-snapshot/linux-arm64/dependencies/libz.yml +0 -13
  116. package/vendor/ctags/licenses/official-snapshot/linux-x64/COPYING +0 -340
  117. package/vendor/ctags/licenses/official-snapshot/linux-x64/RECEIPT.yml +0 -27
  118. package/vendor/ctags/licenses/official-snapshot/linux-x64/dependencies/libiconv.yml +0 -24
  119. package/vendor/ctags/licenses/official-snapshot/linux-x64/dependencies/libjansson.yml +0 -19
  120. package/vendor/ctags/licenses/official-snapshot/linux-x64/dependencies/libxml2.yml +0 -20
  121. package/vendor/ctags/licenses/official-snapshot/linux-x64/dependencies/libyaml.yml +0 -7
  122. package/vendor/ctags/licenses/official-snapshot/linux-x64/dependencies/libz.yml +0 -13
  123. package/vendor/ctags/licenses/win32-x64/COPYING +0 -340
  124. package/vendor/ctags/licenses/win32-x64/COPYING.MinGW-w64-runtime.txt +0 -240
  125. package/vendor/ctags/licenses/win32-x64/Copyright.libxml2 +0 -23
  126. package/vendor/ctags/licenses/win32-x64/LICENCE.pcre2 +0 -94
  127. package/vendor/ctags/licenses/win32-x64/LICENSE.janssen +0 -19
  128. package/vendor/ctags/licenses/win32-x64/LICENSE.libyaml +0 -19
  129. package/vendor/ctags/linux-arm64/ctags +0 -0
  130. package/vendor/ctags/linux-x64/ctags +0 -0
  131. package/vendor/ctags/manifest.json +0 -42
  132. package/vendor/ctags/source/universal-ctags-ab95af198f8eaeb6d50dc96e3adf52e769d3e5f0.tar.gz +0 -0
  133. package/vendor/ctags/win32-x64/ctags.exe +0 -0
  134. package/vendor/ripgrep/LICENSE-MIT +0 -21
  135. package/vendor/ripgrep/UNLICENSE +0 -24
  136. package/vendor/ripgrep/darwin-arm64/rg +0 -0
  137. package/vendor/ripgrep/darwin-x64/rg +0 -0
  138. package/vendor/ripgrep/linux-arm64/rg +0 -0
  139. package/vendor/ripgrep/linux-x64/rg +0 -0
  140. package/vendor/ripgrep/manifest.json +0 -42
  141. package/vendor/ripgrep/win32-arm64/rg.exe +0 -0
  142. package/vendor/ripgrep/win32-x64/rg.exe +0 -0
@@ -0,0 +1,305 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { MarctlError } from './errors.mjs';
3
+ import { TerminalRelaySender } from './terminal-relay-sender.mjs';
4
+ import { parseFrame } from './terminal-frame.mjs';
5
+ import { DirectFallbackError } from './direct-errors.mjs';
6
+
7
+ export async function openRelayTransport({
8
+ client,
9
+ WebSocketClass,
10
+ nodeId,
11
+ terminalId,
12
+ translate,
13
+ connectionTimeoutMs,
14
+ signal
15
+ }) {
16
+ const ticket = await client.createAttachTicket({ nodeId, terminalId });
17
+ if (signal?.aborted) throw new DirectFallbackError('DIRECT_RACE_CANCELLED');
18
+ const socket = client.openTerminalWebSocket(WebSocketClass, { terminalId, ticket });
19
+ const transport = new BufferedRelayTransport({
20
+ socket,
21
+ terminalId,
22
+ translate,
23
+ connectionTimeoutMs
24
+ });
25
+ try {
26
+ await waitForAttachment(transport, signal);
27
+ return transport;
28
+ } catch (error) {
29
+ transport.close();
30
+ throw error;
31
+ }
32
+ }
33
+
34
+ export async function prepareRelayTransport({
35
+ client,
36
+ WebSocketClass,
37
+ nodeId,
38
+ terminalId,
39
+ translate,
40
+ connectionTimeoutMs,
41
+ signal,
42
+ onPrepared
43
+ }) {
44
+ const ticket = await client.createAttachTicket({ nodeId, terminalId });
45
+ if (onPrepared) await onPrepared();
46
+ if (signal?.aborted) throw new MarctlError(translate('errors.terminalAttachConnection'));
47
+ const socket = client.openTerminalWebSocket(WebSocketClass, {
48
+ terminalId,
49
+ ticket,
50
+ deferred: true
51
+ });
52
+ // Keep an error listener after readiness until the socket is discarded.
53
+ socket.on('error', () => {});
54
+ let activated = false;
55
+ const ready = new Promise((resolve, reject) => {
56
+ const timer = setTimeout(() => fail(), connectionTimeoutMs);
57
+ const cleanup = () => {
58
+ clearTimeout(timer);
59
+ socket.removeListener?.('message', onMessage);
60
+ socket.removeListener?.('error', fail);
61
+ socket.removeListener?.('close', fail);
62
+ signal?.removeEventListener('abort', fail);
63
+ };
64
+ const fail = () => {
65
+ cleanup();
66
+ try {
67
+ socket.close();
68
+ } catch {
69
+ /* Connection not yet established. */
70
+ }
71
+ reject(new MarctlError(translate('errors.terminalAttachConnection')));
72
+ };
73
+ const onMessage = (raw) => {
74
+ let frame;
75
+ try {
76
+ frame = JSON.parse(String(raw));
77
+ } catch {
78
+ return fail();
79
+ }
80
+ if (frame?.type !== 'ready' || frame.terminalId !== terminalId) return fail();
81
+ cleanup();
82
+ resolve();
83
+ };
84
+ socket.on('message', onMessage);
85
+ socket.on('error', fail);
86
+ socket.on('close', fail);
87
+ signal?.addEventListener('abort', fail, { once: true });
88
+ if (signal?.aborted) fail();
89
+ });
90
+ await ready;
91
+ return {
92
+ async activate(signal) {
93
+ if (signal?.aborted) {
94
+ socket.close();
95
+ throw new DirectFallbackError('DIRECT_RACE_CANCELLED');
96
+ }
97
+ if (activated || socket.readyState !== 1)
98
+ throw new MarctlError(translate('errors.terminalAttachConnection'));
99
+ activated = true;
100
+ const transport = new BufferedRelayTransport({
101
+ socket,
102
+ terminalId,
103
+ translate,
104
+ connectionTimeoutMs
105
+ });
106
+ try {
107
+ socket.send(JSON.stringify({ type: 'activate', terminalId }));
108
+ await waitForAttachment(transport, signal);
109
+ return transport;
110
+ } catch (error) {
111
+ transport.close();
112
+ throw error;
113
+ }
114
+ },
115
+ close() {
116
+ socket.close();
117
+ }
118
+ };
119
+ }
120
+
121
+ async function waitForAttachment(transport, signal) {
122
+ if (!signal) return transport.waitForAttachment();
123
+ if (signal.aborted) throw new DirectFallbackError('DIRECT_RACE_CANCELLED');
124
+ let cancel;
125
+ const cancelled = new Promise((_, reject) => {
126
+ cancel = () => {
127
+ transport.close();
128
+ reject(new DirectFallbackError('DIRECT_RACE_CANCELLED'));
129
+ };
130
+ signal.addEventListener('abort', cancel, { once: true });
131
+ });
132
+ try {
133
+ return await Promise.race([transport.waitForAttachment(), cancelled]);
134
+ } finally {
135
+ signal.removeEventListener('abort', cancel);
136
+ }
137
+ }
138
+
139
+ class BufferedRelayTransport extends EventEmitter {
140
+ #socket;
141
+ #sender;
142
+ #terminalId;
143
+ #translate;
144
+ #attached = false;
145
+ #active = false;
146
+ #pendingEvents = [];
147
+ #attachmentResolve;
148
+ #attachmentReject;
149
+ #openTimer;
150
+ #attachTimer;
151
+ #closed = false;
152
+ #onOpen;
153
+ #onMessage;
154
+ #onError;
155
+ #onClose;
156
+
157
+ constructor({ socket, terminalId, translate, connectionTimeoutMs }) {
158
+ super();
159
+ this.#socket = socket;
160
+ this.#sender = new TerminalRelaySender(socket);
161
+ this.#terminalId = terminalId;
162
+ this.#translate = translate;
163
+ this.#onOpen = () => {
164
+ clearTimeout(this.#openTimer);
165
+ this.#armAttachTimer(connectionTimeoutMs);
166
+ };
167
+ this.#onMessage = (raw, isBinary) => {
168
+ try {
169
+ const frame = parseFrame(raw, isBinary, this.#terminalId, this.#translate);
170
+ if (!this.#attached) {
171
+ if (frame.type === 'attach') {
172
+ this.#attached = true;
173
+ clearTimeout(this.#attachTimer);
174
+ this.#attachmentResolve?.();
175
+ this.#attachmentResolve = undefined;
176
+ this.#attachmentReject = undefined;
177
+ return;
178
+ }
179
+ if (frame.type === 'error')
180
+ throw new MarctlError(this.#translate('errors.terminalRemoteError'));
181
+ this.#queueOrEmit('message', raw, isBinary);
182
+ return;
183
+ }
184
+ this.#queueOrEmit('message', raw, isBinary);
185
+ } catch (error) {
186
+ this.#fail(
187
+ error instanceof MarctlError
188
+ ? error
189
+ : new MarctlError(this.#translate('errors.terminalFrameInvalid'))
190
+ );
191
+ }
192
+ };
193
+ this.#onError = () => {
194
+ const error = new MarctlError(
195
+ this.#translate(
196
+ this.#attached ? 'errors.terminalConnectionFailed' : 'errors.terminalAttachConnection'
197
+ )
198
+ );
199
+ if (this.#attached) this.#queueOrEmit('error', error);
200
+ else this.#fail(error);
201
+ };
202
+ this.#onClose = () => {
203
+ this.#sender.close();
204
+ const error = new MarctlError(
205
+ this.#translate(
206
+ this.#attached ? 'errors.terminalConnectionLost' : 'errors.terminalAttachLost'
207
+ )
208
+ );
209
+ if (this.#attached) this.#queueOrEmit('close');
210
+ else this.#fail(error);
211
+ };
212
+
213
+ socket.on?.('open', this.#onOpen);
214
+ socket.on?.('message', this.#onMessage);
215
+ socket.on?.('error', this.#onError);
216
+ socket.on?.('close', this.#onClose);
217
+ if (socket.readyState === 1) this.#onOpen();
218
+ else
219
+ this.#openTimer = setTimeout(
220
+ () => this.#fail(new MarctlError(this.#translate('errors.terminalConnectionOpen'))),
221
+ connectionTimeoutMs
222
+ );
223
+ }
224
+
225
+ waitForAttachment() {
226
+ return new Promise((resolve, reject) => {
227
+ if (this.#closed) {
228
+ reject(new MarctlError(this.#translate('errors.terminalAttachLost')));
229
+ return;
230
+ }
231
+ this.#attachmentResolve = resolve;
232
+ this.#attachmentReject = reject;
233
+ if (this.#attached) {
234
+ this.#attachmentResolve = undefined;
235
+ this.#attachmentReject = undefined;
236
+ resolve();
237
+ }
238
+ });
239
+ }
240
+
241
+ activate() {
242
+ if (this.#active) return;
243
+ this.#active = true;
244
+ const pendingEvents = this.#pendingEvents;
245
+ this.#pendingEvents = [];
246
+ for (const { type, args } of pendingEvents) this.emit(type, ...args);
247
+ }
248
+
249
+ get readyState() {
250
+ return this.#socket.readyState;
251
+ }
252
+
253
+ send(value) {
254
+ if (this.#closed) throw new Error('TERMINAL_CONNECTION_LOST');
255
+ if (JSON.parse(value).type === 'input') return this.#sender.send(value);
256
+ this.#socket.send(value);
257
+ }
258
+
259
+ close() {
260
+ if (this.#closed) return;
261
+ this.#closed = true;
262
+ this.#attachmentReject?.(new MarctlError(this.#translate('errors.terminalAttachLost')));
263
+ this.#attachmentReject = undefined;
264
+ this.#attachmentResolve = undefined;
265
+ this.#sender.close();
266
+ clearTimeout(this.#openTimer);
267
+ clearTimeout(this.#attachTimer);
268
+ this.#socket.removeListener?.('open', this.#onOpen);
269
+ this.#socket.removeListener?.('message', this.#onMessage);
270
+ this.#socket.removeListener?.('error', this.#onError);
271
+ this.#socket.removeListener?.('close', this.#onClose);
272
+ try {
273
+ this.#socket.close();
274
+ } catch {
275
+ // The connection is already unavailable.
276
+ }
277
+ }
278
+
279
+ #armAttachTimer(connectionTimeoutMs) {
280
+ if (this.#attached) return;
281
+ this.#attachTimer = setTimeout(
282
+ () => this.#fail(new MarctlError(this.#translate('errors.terminalAttachTimeout'))),
283
+ connectionTimeoutMs
284
+ );
285
+ }
286
+
287
+ #fail(error) {
288
+ if (this.#closed) return;
289
+ clearTimeout(this.#openTimer);
290
+ clearTimeout(this.#attachTimer);
291
+ this.#attachmentResolve = undefined;
292
+ const reject = this.#attachmentReject;
293
+ this.#attachmentReject = undefined;
294
+ if (!this.#attached) reject?.(error);
295
+ else this.#queueOrEmit('error', error);
296
+ }
297
+
298
+ #queueOrEmit(type, ...args) {
299
+ if (this.#active) {
300
+ if (type !== 'error' || this.listenerCount('error') > 0) this.emit(type, ...args);
301
+ return;
302
+ }
303
+ this.#pendingEvents.push({ type, args });
304
+ }
305
+ }
@@ -0,0 +1,152 @@
1
+ import { MarctlError } from './errors.mjs';
2
+ import { DirectRejectedError } from './direct-errors.mjs';
3
+ import { createTranslator } from './i18n/index.mjs';
4
+ import { raceTerminalConnections } from './terminal-race.mjs';
5
+ import { openRelayTransport } from './terminal-relay.mjs';
6
+ import { getDimensions, runAttachedTerminal } from './terminal-interaction.mjs';
7
+
8
+ const DEFAULT_CONNECTION_TIMEOUT_MS = 15000;
9
+
10
+ export async function runTerminalSession({
11
+ client,
12
+ WebSocketClass,
13
+ nodeId,
14
+ command,
15
+ binary = false,
16
+ attached,
17
+ stdin = process.stdin,
18
+ stdout = process.stdout,
19
+ signal,
20
+ translate = createTranslator(),
21
+ connectionTimeoutMs = DEFAULT_CONNECTION_TIMEOUT_MS,
22
+ openDirectTerminal: openDirectTerminalImpl,
23
+ raceConnections = false
24
+ }) {
25
+ const dimensions = getDimensions(stdout);
26
+ let terminalId;
27
+ let transport;
28
+ let result;
29
+ let primaryError;
30
+ let manifest;
31
+
32
+ try {
33
+ if (signal?.aborted) return signal.reason === 'SIGTERM' ? 143 : 130;
34
+ if (binary) {
35
+ if (command === undefined)
36
+ throw new MarctlError(translate('errors.terminalBinaryUnavailable'));
37
+ manifest = await client.getTerminalManifest(nodeId);
38
+ if (signal?.aborted) return signal.reason === 'SIGTERM' ? 143 : 130;
39
+ if (manifest?.binaryTerminal !== true)
40
+ throw new MarctlError(translate('errors.terminalBinaryUnavailable'));
41
+ }
42
+ const created = await client.createTerminal({
43
+ nodeId,
44
+ ...dimensions,
45
+ ...(command === undefined ? {} : { command }),
46
+ ...(binary ? { binary: true } : {})
47
+ });
48
+ terminalId = binary ? created?.terminalId : created;
49
+ if (binary && created?.binary !== true)
50
+ throw new MarctlError(translate('errors.terminalBinaryUnavailable'));
51
+ if (signal?.aborted) return signal.reason === 'SIGTERM' ? 143 : 130;
52
+ try {
53
+ const openDirectTerminal =
54
+ openDirectTerminalImpl ?? (await import('./direct.mjs')).openDirectTerminal;
55
+ if (raceConnections && manifest === undefined)
56
+ manifest = await client.getTerminalManifest(nodeId).catch(() => undefined);
57
+ const directOptions = {
58
+ client,
59
+ WebSocketClass,
60
+ nodeId,
61
+ terminalId,
62
+ manifest,
63
+ afterSequence: 0,
64
+ timeoutMs: connectionTimeoutMs,
65
+ signal
66
+ };
67
+ const canRace = raceConnections && manifest?.deferredRelay === true;
68
+ transport = canRace
69
+ ? await raceTerminalConnections({
70
+ openDirectTerminal,
71
+ directOptions,
72
+ client,
73
+ WebSocketClass,
74
+ nodeId,
75
+ terminalId,
76
+ translate,
77
+ connectionTimeoutMs,
78
+ signal
79
+ })
80
+ : await openDirectTerminal(directOptions);
81
+ if (signal?.aborted) return signal.reason === 'SIGTERM' ? 143 : 130;
82
+ result =
83
+ attached === undefined
84
+ ? await runAttachedTerminal({
85
+ transport,
86
+ terminalId,
87
+ commandMode: command !== undefined,
88
+ stdin,
89
+ stdout,
90
+ signal,
91
+ translate
92
+ })
93
+ : await attached({ transport, terminalId, translate });
94
+ } catch (error) {
95
+ if (signal?.aborted) {
96
+ result = signal.reason === 'SIGTERM' ? 143 : 130;
97
+ } else {
98
+ if (error?.name === 'DirectUnsafeError')
99
+ throw new MarctlError(translate('errors.terminalDirectUnsafeFallback'));
100
+ if (error?.name !== 'DirectFallbackError') throw error;
101
+ transport = await openRelayTransport({
102
+ client,
103
+ WebSocketClass,
104
+ nodeId,
105
+ terminalId,
106
+ translate,
107
+ connectionTimeoutMs,
108
+ signal
109
+ });
110
+ if (signal?.aborted) return signal.reason === 'SIGTERM' ? 143 : 130;
111
+ result =
112
+ attached === undefined
113
+ ? await runAttachedTerminal({
114
+ transport,
115
+ terminalId,
116
+ commandMode: command !== undefined,
117
+ stdin,
118
+ stdout,
119
+ signal,
120
+ translate
121
+ })
122
+ : await attached({ transport, terminalId, translate });
123
+ }
124
+ }
125
+ } catch (error) {
126
+ if (signal?.aborted) result = signal.reason === 'SIGTERM' ? 143 : 130;
127
+ else primaryError = toMarctlError(error, translate);
128
+ } finally {
129
+ transport?.close?.();
130
+ if (terminalId !== undefined) {
131
+ try {
132
+ await client.deleteTerminal({ nodeId, terminalId });
133
+ } catch {
134
+ if (primaryError === undefined && result === undefined)
135
+ primaryError = new MarctlError(translate('errors.terminalCloseFailed'));
136
+ }
137
+ }
138
+ }
139
+
140
+ if (primaryError !== undefined) throw primaryError;
141
+ return result;
142
+ }
143
+
144
+ function toMarctlError(error, translate) {
145
+ if (error instanceof DirectRejectedError)
146
+ return new MarctlError(`${translate('errors.terminalSessionFailed')} [${error.code}]`, {
147
+ code: error.code
148
+ });
149
+ return error instanceof MarctlError
150
+ ? error
151
+ : new MarctlError(translate('errors.terminalSessionFailed'));
152
+ }
@@ -28,7 +28,7 @@ export const marctlInstructions = [
28
28
  'Prefer agents send <id> --steer -m <text> for timely communication or course correction. --queue is best reserved for deferred input explicitly requested by the user or recipient: it is consumed after current work and earlier queued inputs finish, and with an active Goal it is not consumed until that Goal exits. Acceptance is not a guarantee of immediate processing.',
29
29
  'An accepted message normally needs no separate acknowledgment. Requests for receipt-only replies and immediate agents view checks solely to confirm receipt are usually unnecessary.',
30
30
  'Send can update a Goal alone with --goal <objective> or --clear-goal; omitted Goal leaves it unchanged. Decide an authorized Agent approval with send <id> --approval <approval-id> --decision approve|reject.',
31
- 'List accepts only --scope tree|active, optional --query <title-fragment> and --limit <1..100> (default 10). With a current Session it defaults to the containing collaboration tree, including idle Sessions; without one it defaults to active Workspace Sessions (running or sleeping), and explicit tree is rejected. Active Sessions come first, then recent activity descending. Returns currentAgentId (null without a Session), flat sessions with id, parentSessionId, title and status, and truncated; no cursor or pagination. Reuse known IDs directly.',
31
+ 'List accepts only --scope tree|active, optional --query <title-fragment> and --limit <1..100> (default 10). With a current Session it defaults to the containing collaboration tree, including idle Sessions; without one it defaults to active Workspace Sessions (running or sleeping), and explicit tree is rejected. Active Sessions come first, then recent activity descending. Returns scope, currentAgentId (null without a Session), flat sessions with id, parentSessionId, title and status, and truncated; no cursor or pagination. Reuse known IDs directly.',
32
32
  'Only direct-child updates are collected automatically. Sending to a non-child never subscribes; an explicit wait observes it only for that call.',
33
33
  'Use agents config, rename, prompt and schedule for management. marctl nodes, ssh and scp use authorized Nodes.',
34
34
  marctlSafety
package/dist/marctl.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  // Keep the CLI implementation in its own package; the Node install exposes the same entrypoint.
3
- const entrypoint = '@myagentroam/marctl/bin/marctl.mjs';
3
+ const entrypoint = './marctl/bin/marctl.mjs';
4
4
  await import(entrypoint);
5
5
  export {};
package/dist/marnodes.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- const entrypoint = '@myagentroam/marctl/bin/marnodes.mjs';
2
+ const entrypoint = './marctl/bin/marnodes.mjs';
3
3
  await import(entrypoint);
4
4
  export {};
package/dist/marscp.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- const entrypoint = '@myagentroam/marctl/bin/marscp.mjs';
2
+ const entrypoint = './marctl/bin/marscp.mjs';
3
3
  await import(entrypoint);
4
4
  export {};
package/dist/marssh.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- const entrypoint = '@myagentroam/marctl/bin/marssh.mjs';
2
+ const entrypoint = './marctl/bin/marssh.mjs';
3
3
  await import(entrypoint);
4
4
  export {};
@@ -365,7 +365,7 @@ function deleteTranscriptIndex(key) {
365
365
  export async function locateNativeSessionPath(runner, workspacePath, externalSessionId) {
366
366
  const wanted = canonical(workspacePath);
367
367
  const key = indexKey(runner, wanted, externalSessionId);
368
- let path = getTranscriptIndex(key);
368
+ const path = getTranscriptIndex(key);
369
369
  if (path !== undefined)
370
370
  return path;
371
371
  const candidates = await nativeTranscriptAdapter(runner)?.locateCandidates?.(externalSessionId);
@@ -1,5 +1,5 @@
1
1
  import { dirname, resolve } from 'node:path';
2
- import { fileURLToPath } from 'node:url';
2
+ import { createRequire } from 'node:module';
3
3
  export const BUNDLED_RIPGREP_VERSION = '15.1.0';
4
4
  const TARGETS = {
5
5
  'linux-x64': ['linux-x64', 'rg'],
@@ -11,8 +11,8 @@ const TARGETS = {
11
11
  };
12
12
  export function bundledRipgrepDirectory(packageRoot) {
13
13
  return packageRoot === undefined
14
- ? resolve(dirname(fileURLToPath(import.meta.url)), '..', 'vendor/ripgrep')
15
- : resolve(packageRoot, 'mar-node/vendor/ripgrep');
14
+ ? resolve(dirname(createRequire(import.meta.url).resolve('@myagentroam/binaries/package.json')), 'vendor/ripgrep')
15
+ : resolve(packageRoot, 'packages/binaries/vendor/ripgrep');
16
16
  }
17
17
  export function bundledRipgrepPath(platform = process.platform, architecture = process.arch, packageRoot) {
18
18
  const target = TARGETS[`${platform}-${architecture}`];
@@ -394,7 +394,7 @@ export class CodexRunner extends AbstractRunner {
394
394
  const threads = [];
395
395
  const cursors = new Set();
396
396
  let cursor;
397
- do {
397
+ for (;;) {
398
398
  const result = await this.client.listThreads({
399
399
  limit: 200,
400
400
  ...(cursor === undefined ? {} : { cursor })
@@ -415,7 +415,7 @@ export class CodexRunner extends AbstractRunner {
415
415
  throw new Error('CODEX_THREAD_LIST_INVALID');
416
416
  cursors.add(next);
417
417
  cursor = next;
418
- } while (true);
418
+ }
419
419
  }
420
420
  async discoverSessions(context, workspace) {
421
421
  const [threads, nativeSessions] = context.cleanup
@@ -39,22 +39,34 @@ export function agentOperationPresentation(toolName, input, data) {
39
39
  if (!action)
40
40
  return undefined;
41
41
  const parsed = agentOperationPresentationSchema.safeParse(isPlainRecord(data) ? data.agentOperation : undefined);
42
- if (parsed.success && parsed.data.action === action)
43
- return parsed.data;
44
42
  const value = isPlainRecord(input) ? input : {};
45
43
  const ids = typeof value.agentId === 'string'
46
44
  ? [value.agentId]
47
45
  : Array.isArray(value.agentIds)
48
46
  ? value.agentIds
49
47
  : [];
50
- return {
51
- action,
52
- targets: ids
53
- .filter((id) => typeof id === 'string' && id.length > 0 && id.length <= 128)
54
- .slice(0, 8)
55
- .map((agentId) => ({ agentId })),
56
- ...(text(value.scope, 32) ? { scope: text(value.scope, 32) } : {})
57
- };
48
+ const operation = parsed.success && parsed.data.action === action
49
+ ? parsed.data
50
+ : {
51
+ action,
52
+ targets: ids
53
+ .filter((id) => typeof id === 'string' && id.length > 0 && id.length <= 128)
54
+ .slice(0, 8)
55
+ .map((agentId) => ({ agentId })),
56
+ ...(text(value.scope, 32) ? { scope: text(value.scope, 32) } : {})
57
+ };
58
+ const goal = isPlainRecord(value.goal) ? value.goal : undefined;
59
+ const objective = action === 'SEND' && !operation.detail?.message && !text(value.content) && goal?.clear !== true
60
+ ? text(goal?.objective, 2000)
61
+ : undefined;
62
+ if (objective)
63
+ operation.detail = {
64
+ ...operation.detail,
65
+ message: objective,
66
+ messageIsGoal: true,
67
+ ...(objective !== goal?.objective ? { messageTruncated: true } : {})
68
+ };
69
+ return operation;
58
70
  }
59
71
  /** Whitelist public receipts; never serialize configuration, credentials or full history. */
60
72
  export function agentOperationEvent(action, input, result) {
@@ -1,36 +1,28 @@
1
1
  export function codexImagegenSkill() {
2
2
  return `## Working with images
3
3
 
4
- Use codex_image_gen only when the user requests image generation or editing, or explicitly authorizes that work as part of the task. An opportunity to add a visual is not authorization. Loading this skill does not itself generate anything.
4
+ Use codex_image_gen only for image generation or editing the user requests or explicitly authorizes. Loading this skill is not authorization to add visuals.
5
5
 
6
6
  ### Choose the operation
7
- - Use AI image generation for requested raster artwork, photographs, textures, or visual variants. Prefer existing editable vector/code-native sources for deterministic changes to those assets; do not replace them with generated bitmaps merely because this tool exists.
8
- - Distinguish a new composition, an edit target, and a reference for style or subject. Label each supplied image by index and role in the prompt. A reference-guided new composition still needs the reference pixels: pass an image selector rather than silently omitting them.
9
- - Inspect an unseen local input with view_image when that tool is available. With a TEXT-only model, use the user-supplied reference path and instructions without claiming to have inspected pixels. Prefer referenced_image_paths when all necessary images have valid absolute paths. The Host's file boundaries still apply.
10
- - Use num_last_images_to_include only when a necessary image has no usable path, and choose the smallest suffix containing all inputs. This is the current Execution's available in-memory images, not a permanent conversation gallery. After a new Execution or Compact, use valid saved paths or ask for missing inputs again.
11
- - The selectors are mutually exclusive and include at most five images. Omit both only for generation without input images. Do not pretend an unavailable reference was used.
7
+ - Use generated raster artwork for photos, illustrations, textures, and visual variants. Prefer direct source edits for existing SVG, icons, and other code-native assets.
8
+ - Omit both selectors for generation without references. Otherwise use up to five absolute referenced_image_paths, or the smallest num_last_images_to_include containing all needed images, never both. Prefer paths when all inputs have them. Recent images belong to this Execution, not a permanent gallery; after recovery or Compact, use saved paths or ask for missing inputs.
9
+ - Identify each reference's role. Inspect unseen PNG/JPEG/WebP inputs with view_image when available; TEXT-only models must not claim visual inspection. Do not silently omit required references.
12
10
 
13
11
  ### Shape the prompt
14
- - Preserve the user's specifics and exact requested text. Organize them into subject, intended use, composition, style, input-image roles, and constraints as useful; a fixed template is not required.
15
- - For a vague request, supply only details that support its stated goal. Do not invent brands, slogans, additional subjects, or unrelated requirements.
16
- - For edits, identify the target and state what changes and what must remain unchanged, including identity, layout, text, or other important details. Carry these invariants into follow-up edits.
17
- - For lettering, quote the literal text and specify placement and typography when relevant. For multiple images, explain which image supplies each element.
18
- - Ask for a missing decision only if it materially blocks the requested result; do not request a second approval for an already authorized operation.
12
+ - State the subject, composition, style, and essential constraints; preserve exact requested lettering. For edits, specify what changes and what stays unchanged. Add only details that support the user's goal; clarify only when a missing decision blocks the result.
13
+ - Set transparent_background: true for cutouts, background removal, or transparency; preserve existing transparency during edits unless the user asks to change it. Preserve real alpha, not a drawn checkerboard.
14
+ - For a simple looping animation, set gif: {} or specify frame_count (2–16) and frame_duration_ms (20–2000). Defaults are 9 frames and 200 ms. Describe the motion and loop seam; keep subjects and camera stable unless asked otherwise.
15
+ - To edit a GIF, first inspect its frames and use available tools to make a PNG spritesheet with equal-sized cells in a regular grid. Pass that spritesheet through referenced_image_paths and set gif. Do not pass the GIF itself as an edit input; if preparation is unavailable, explain the limitation.
16
+ - For complex animation or more than 16 frames, use suitable available tools or explain the limit rather than stretching this tool's bounds.
19
17
 
20
18
  ### Generate and check
21
- - Call codex_image_gen with its actual schema. It produces one PNG per call; use separate calls for separately requested assets. Do not add unsupported parameters for model, dimensions, quality, masks, output format, or destination.
22
- - In Code Mode, call tools.codex_image_gen. Independent calls can run with Promise.all; await earlier results when later images depend on them.
23
- - The service configuration controls model and automatic size/quality/background. A prompt can request an aspect ratio or transparency, but these are not guaranteed API settings. Check the actual result before claiming compliance.
24
- - Generation may take minutes. Await the tool result; do not blindly repeat a timed-out or interrupted request because the upstream operation may already have run. Report failures rather than claiming an artifact exists.
25
- - A successful result returns the saved path, not inspected pixels. When view_image is available, use it for visual acceptance: subject, exact text, composition, edit invariants, and unwanted elements. Otherwise explicitly state that visual acceptance was not performed. Make targeted corrections only within the requested scope.
26
- - For transparent deliverables, verify actual transparency rather than treating a drawn checkerboard as alpha. Preserve the alpha channel when copying or processing the result.
19
+ - One PNG or GIF is saved per call. Model, quality, and size remain service-controlled; do not invent API parameters, output paths, SVG support, or fallback tools.
20
+ - In Code Mode, call tools.codex_image_gen. Independent calls may use Promise.all; dependent edits must await their inputs. Generation can take minutes: await the result and do not blindly replay an interrupted or timed-out request. Report failures rather than claiming an artifact exists.
21
+ - Verify the actual format and requested transparency, then check PNG content (subject, lettering, and edit invariants) with view_image when available. For GIFs, check frames, timing, and the loop with available animation-aware tools; a first-frame preview does not verify animation. If inspection is unavailable, say so. Correct only issues within the requested scope.
27
22
 
28
23
  ### Keep and deliver
29
- - Treat the tool-returned path as authoritative; do not guess a product HOME or generated-image directory.
30
- - Keep the managed original. Copy selected assets into the user-requested, Host-permitted destination when needed by the project. Do not leave a project dependency pointing only at private Session storage.
31
- - Avoid overwriting existing assets unless replacement was requested. For preview-only work the managed file can remain in place.
32
- - If the user asks to reuse an existing image, inspect or copy it rather than generating a replacement. If it is missing, state that fact; generate again only when authorized.
33
- - Report the actual final path and any material unmet constraints. Do not dump a long generation prompt unless the user requests it.
24
+ - Trust the returned path and keep the managed original. Copy assets into the authorized project destination when needed; do not leave project dependencies in private Session storage. Do not overwrite existing assets unless replacement was requested.
25
+ - Reuse existing images when requested rather than regenerating them. Report the final path and material unmet constraints, not a long prompt dump.
34
26
 
35
- This Host-provided skill has no bundled command-line fallback, install step, or separate API-key requirement. Do not invent scripts or switch credentials, endpoints, or models. If the tool or a required capability is unavailable, explain the limitation. Workspace instructions can supply additional authorized workflows without changing the tool schema or Host boundaries.`;
27
+ This Host-provided skill has no bundled CLI fallback or separate API-key setup. Do not switch credentials, endpoints, or models. Follow the tool schema and Host file boundaries.`;
36
28
  }