@myagentroam/marctl 0.11.8 → 0.11.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/marctl",
3
- "version": "0.11.8",
3
+ "version": "0.11.10",
4
4
  "description": "MyAgentRoam command-line interface for authorized Node access.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -45,22 +45,19 @@ Notes:
45
45
  agents: `{program} — Coordinate Agents in the current MAR Workspace
46
46
 
47
47
  Usage:
48
- {program} start [-m <text> | --message-file <file|->] [--image <path> ...]
48
+ {program} start [-m <text> | --message-file <file|->]
49
49
  [--runner <runner>] [--parent <id>] [--model-id <id>] [--effort <value>]
50
50
  [--title <name>] [--goal <objective> | --clear-goal]
51
51
  [--client-message-id <id>] [--json]
52
52
  {program} send <id> [-m <text> | --message-file <file|->]
53
- [--image <path> ...]
54
53
  [--steer | --queue] [--goal <objective> | --clear-goal]
55
54
  [--approval <id> --decision <approve|reject>]
56
55
  [--client-message-id <id>] [--json]
57
56
  {program} wait [<id>] [--agent <id> ...] [--mode any|all]
58
57
  [--wait-for message|completion] [--timeout <duration>] [--json]
59
58
  {program} stop <id> --execution <execution-id> [--json]
60
- {program} list [--scope children|descendants|workspace|profile]
61
- [--agent <id>]
62
- [--runner <runner>] [--query <title>] [--parent <id>]
63
- [--cursor <cursor>] [--limit <1..100>] [--json]
59
+ {program} list [--scope tree|active] [--query <title>]
60
+ [--limit <1..100>] [--json]
64
61
  {program} view [<id>] [--history] [--cursor <cursor>]
65
62
  [--limit <1..100>] [--json]
66
63
 
@@ -84,26 +81,33 @@ Management:
84
81
 
85
82
  Input and results:
86
83
  Start defaults to the current Session Runner; a terminal without a current
87
- Session must specify --runner or --parent. Profile lists configured models,
88
- not guaranteed account availability. Start returns without waiting.
84
+ Session must specify --runner or --parent. Start returns without waiting.
89
85
  Send appends by default; --steer provides timely input and --queue defers.
90
86
  --goal sets or replaces a Goal; --clear-goal clears it. Send can update a Goal
91
87
  without text; omitted Goal is unchanged. Stop clears the target Session Goal.
92
88
  Wait defaults to direct-child completion and 30s; 0ms is a snapshot.
93
89
  Positive timeouts below 10s become 10s; maximum is 5m. Waiting does not stop.
94
- Images may be supplied without text: at most 5, 5 MiB each, 10 MiB total.
95
90
  -m and --message-file are exclusive; files use UTF-8 and - reads stdin.
96
- List exposes current identity and bounded pages; nextCursor marks more.
91
+ List defaults to the containing tree, including idle Sessions. Without a
92
+ current Session it defaults to active; explicit tree requires a Session.
93
+ Active includes running and sleeping Sessions in the current Workspace.
94
+ List returns currentAgentId (null without a Session), flat sessions and
95
+ truncated. Limit defaults to 100, maximum 100; no cursor or pagination.
97
96
  Configuration and prompt changes apply to future executions.
98
97
  Prefer --steer for timely communication or course correction.
99
- Use --queue only for deliberately deferred input: it is consumed after
98
+ Reserve --queue for explicitly requested deferred input: it is consumed after
100
99
  current work and earlier queued inputs finish. With an active Goal it is
101
100
  not consumed until that Goal exits.
102
101
  Acceptance does not guarantee immediate processing.
102
+ An accepted message normally needs no separate acknowledgment or receipt
103
+ check.
104
+ While children run, prefer meaningful, non-overlapping work; wait when needed
105
+ to unblock or finish and no other meaningful local task work remains.
103
106
 
104
107
  show --json includes session.status, session.modelId, session.effort,
105
108
  session.title, session.runId, session.recentTools, session.queuedCount and
106
- session.latestMessage. list reports latestActivity; wait may include progress.
109
+ session.latestMessage. List entries have id, parentSessionId, title, runner
110
+ and status; wait may include progress.
107
111
  Status is RUNNING/IDLE/SLEEPING. In history, segments[].items[] with
108
112
  kind === "assistant_message" expose payload.text.
109
113
 
@@ -220,8 +224,6 @@ or Server connection is required.`
220
224
  'The delivery outcome is unknown. Inspect Session state/history before retrying.',
221
225
  sessionMessageInvalid:
222
226
  'The message must be non-empty and within the length limit; input files must be readable UTF-8.',
223
- sessionImageInvalid:
224
- 'Images must be readable PNG, JPEG, GIF or WebP files: at most 5 images, 5 MiB each and 10 MiB total.',
225
227
  sessionWaitUnknown: 'The specified Run could not be confirmed. Inspect Session state/history.',
226
228
  sessionWaitCancelled: 'Waiting was cancelled; the target Run was not stopped.',
227
229
  sessionWaitTimeout: 'Waiting timed out; the target Run was not stopped.',
@@ -44,22 +44,19 @@ ${configurationHelp}
44
44
  agents: `{program} — 协调当前 MAR 工作区中的 Agent
45
45
 
46
46
  用法:
47
- {program} start [-m <text> | --message-file <file|->] [--image <path> ...]
47
+ {program} start [-m <text> | --message-file <file|->]
48
48
  [--runner <runner>] [--parent <id>] [--model-id <id>] [--effort <value>]
49
49
  [--title <name>] [--goal <objective> | --clear-goal]
50
50
  [--client-message-id <id>] [--json]
51
51
  {program} send <id> [-m <text> | --message-file <file|->]
52
- [--image <path> ...]
53
52
  [--steer | --queue] [--goal <objective> | --clear-goal]
54
53
  [--approval <id> --decision <approve|reject>]
55
54
  [--client-message-id <id>] [--json]
56
55
  {program} wait [<id>] [--agent <id> ...] [--mode any|all]
57
56
  [--wait-for message|completion] [--timeout <duration>] [--json]
58
57
  {program} stop <id> --execution <execution-id> [--json]
59
- {program} list [--scope children|descendants|workspace|profile]
60
- [--agent <id>]
61
- [--runner <runner>] [--query <title>] [--parent <id>]
62
- [--cursor <cursor>] [--limit <1..100>] [--json]
58
+ {program} list [--scope tree|active] [--query <title>]
59
+ [--limit <1..100>] [--json]
63
60
  {program} view [<id>] [--history] [--cursor <cursor>]
64
61
  [--limit <1..100>] [--json]
65
62
 
@@ -83,21 +80,28 @@ ${configurationHelp}
83
80
 
84
81
  输入与结果:
85
82
  start 默认当前会话的 Runner;没有当前会话的终端须指定 --runner 或
86
- --parent。profile 显示已配置模型,不代表账号实时可用。start 不等待。
83
+ --parent。start 不等待。
87
84
  send 默认追加;--steer 优先补充,--queue 排队。--goal 设置或替换目标,
88
85
  --clear-goal 清除目标;send 可仅更新目标,省略则不修改。
89
86
  stop 清除目标会话的 Goal。wait 默认等待直接子会话终态 30 秒,
90
87
  0ms 为快照;正数小于 10 秒按 10 秒等待,最多 5 分钟。等待不会停止任务。
91
- 可只传图片:最多 5 张,单张 5 MiB、总计 10 MiB。-m 与 --message-file
92
- 互斥;文件使用 UTF-8,- 从 stdin 读取。list 返回当前身份和分页结果,
93
- nextCursor 表示还有后续页面。配置和持久提示从后续执行生效。
88
+ -m 与 --message-file 互斥;文件使用 UTF-8,- 从 stdin 读取。
89
+ list 默认查询所在会话树,包含空闲会话;
90
+ 没有当前会话时默认 active,显式 tree 须有会话上下文。active 包含当前
91
+ Workspace 中运行及睡眠的会话。返回 currentAgentId(无会话时为 null)、
92
+ 扁平 sessions 和 truncated。limit 默认及上限均为 100,无 cursor 或分页。
93
+ 配置和持久提示从后续执行生效。
94
94
  即时沟通或纠偏优先使用 --steer。
95
- 仅明确要延后处理的输入使用 --queue:当前工作及前面的队列项结束后才消费,
95
+ 建议仅将 --queue 用于明确要求延后的输入:当前工作及前面的队列项结束后才消费,
96
96
  有活动 Goal 时,必须等到该 Goal 退出才消费。已接收不保证立即处理。
97
+ 消息被接受后,通常无需另行确认收悉或立即查看是否收到。
98
+ 子会话运行时建议并行推进有意义且不重叠的工作;无其他本地工作可做,且需
99
+ 结果解除阻塞或收尾时,再考虑等待。
97
100
 
98
101
  show --json 包含 session.status、session.modelId、session.effort、
99
102
  session.title、session.runId、session.recentTools、session.queuedCount 和
100
- session.latestMessage。list 返回 latestActivity;wait 可能包含 progress;
103
+ session.latestMessage。list 每项仅含 id、parentSessionId、title、runner 和
104
+ status;wait 可能包含 progress;
101
105
  状态为 RUNNING/IDLE/SLEEPING。历史中 segments[].items[] 的
102
106
  kind === "assistant_message" 包含 payload.text。
103
107
 
@@ -207,8 +211,6 @@ ${configurationHelp}`,
207
211
  errors: Object.freeze({
208
212
  sessionOutcomeUnknown: '投递结果未知,请先查看会话状态和历史,不要盲目重试。',
209
213
  sessionMessageInvalid: '消息不能为空或超过长度限制;输入文件必须是可读取的 UTF-8 文本。',
210
- sessionImageInvalid:
211
- '图片必须是可读取的 PNG、JPEG、GIF 或 WebP 文件:最多 5 张,单张 5 MiB,合计 10 MiB。',
212
214
  sessionWaitUnknown: '无法确认指定 Run,请查看会话状态和历史。',
213
215
  sessionWaitCancelled: '已取消等待,未停止目标 Run。',
214
216
  sessionWaitTimeout: '等待超时,未停止目标 Run。',
@@ -4,7 +4,7 @@ import { sessionTarget } from './session-target.mjs';
4
4
 
5
5
  const commands = {
6
6
  current: [],
7
- list: ['cursor', 'limit', 'query', 'parent', 'scope', 'agent', 'runner'],
7
+ list: ['scope', 'query', 'limit'],
8
8
  graph: ['limit'],
9
9
  show: [],
10
10
  view: ['cursor', 'limit', 'history'],
@@ -16,7 +16,6 @@ const commands = {
16
16
  'title',
17
17
  'message',
18
18
  'message-file',
19
- 'image',
20
19
  'client-message-id',
21
20
  'parent',
22
21
  'goal',
@@ -35,7 +34,6 @@ const commands = {
35
34
  send: [
36
35
  'message',
37
36
  'message-file',
38
- 'image',
39
37
  'steer',
40
38
  'queue',
41
39
  'client-message-id',
@@ -61,8 +59,7 @@ const fieldNames = {
61
59
  timeout: 'timeoutMs',
62
60
  execution: 'executionId',
63
61
  'wait-for': 'waitFor',
64
- 'clear-goal': 'clearGoal',
65
- image: 'images'
62
+ 'clear-goal': 'clearGoal'
66
63
  };
67
64
 
68
65
  export function parseSessionArgs(argv, translate = createTranslator()) {
@@ -128,7 +125,7 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
128
125
  const key = fieldNames[name] ?? name;
129
126
  if (
130
127
  !commands[action].includes(name) ||
131
- (name !== 'image' && !(name === 'agent' && action === 'wait') && Object.hasOwn(args, key))
128
+ (!(name === 'agent' && action === 'wait') && Object.hasOwn(args, key))
132
129
  )
133
130
  throw invalid();
134
131
  const value = input.shift();
@@ -141,9 +138,6 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
141
138
  if (name === 'agent' && action === 'wait') {
142
139
  (args.agentIds ??= []).push(value);
143
140
  if (args.agentIds.length > 8) throw invalid();
144
- } else if (name === 'image') {
145
- (args.images ??= []).push(value);
146
- if (args.images.length > 5) throw invalid();
147
141
  } else if (name === 'limit' || name === 'expected-revision') {
148
142
  if (
149
143
  !/^[1-9][0-9]*$/u.test(value) ||
@@ -174,7 +168,6 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
174
168
  ['start', 'send', 'goal.set', 'schedule.create', 'prompt.set'].includes(action) &&
175
169
  args.messageFile === undefined &&
176
170
  args.message === undefined &&
177
- !args.images?.length &&
178
171
  !(
179
172
  action === 'send' &&
180
173
  (args.goal !== undefined || args.clearGoal || args.approvalId !== undefined)
@@ -211,11 +204,7 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
211
204
  if (args.waitFor !== undefined && !['message', 'completion'].includes(args.waitFor))
212
205
  throw invalid();
213
206
  if (args.mode !== undefined && !['any', 'all'].includes(args.mode)) throw invalid();
214
- if (
215
- args.scope !== undefined &&
216
- !['children', 'descendants', 'workspace', 'profile'].includes(args.scope)
217
- )
218
- throw invalid();
207
+ if (args.scope !== undefined && !['tree', 'active'].includes(args.scope)) throw invalid();
219
208
  if (
220
209
  action === 'approval.decide' &&
221
210
  (!args.runId || !args.approvalId || !['approve', 'reject'].includes(args.decision))
@@ -1,5 +1,4 @@
1
1
  import { open } from 'node:fs/promises';
2
- import { basename } from 'node:path';
3
2
  import { MarctlError } from './errors.mjs';
4
3
 
5
4
  export async function messageContent(
@@ -42,47 +41,3 @@ export async function messageContent(
42
41
  await file?.close();
43
42
  }
44
43
  }
45
-
46
- export async function imageAttachments(paths, translate) {
47
- const attachments = [];
48
- let total = 0;
49
- for (const path of paths) {
50
- let file;
51
- try {
52
- file = await open(path, 'r');
53
- const info = await file.stat();
54
- if (!info.isFile() || info.size === 0 || info.size > 5 * 1024 * 1024)
55
- throw new Error('IMAGE_INVALID');
56
- const parts = [];
57
- let size = 0;
58
- for await (const part of file.createReadStream({ autoClose: false })) {
59
- size += part.length;
60
- total += part.length;
61
- if (size > 5 * 1024 * 1024 || total > 10 * 1024 * 1024) throw new Error('IMAGE_TOO_LARGE');
62
- parts.push(part);
63
- }
64
- const data = Buffer.concat(parts);
65
- const mime = imageMime(data);
66
- if (mime === undefined) throw new Error('IMAGE_INVALID');
67
- attachments.push({ name: basename(path), mime, dataBase64: data.toString('base64') });
68
- } catch {
69
- throw new MarctlError(translate('errors.sessionImageInvalid'), {
70
- code: 'MARCTL_SESSION_INPUT_INVALID'
71
- });
72
- } finally {
73
- await file?.close();
74
- }
75
- }
76
- return attachments;
77
- }
78
-
79
- function imageMime(data) {
80
- if (data.subarray(0, 8).equals(Buffer.from('89504e470d0a1a0a', 'hex'))) return 'image/png';
81
- if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return 'image/jpeg';
82
- if (['GIF87a', 'GIF89a'].includes(data.subarray(0, 6).toString('ascii'))) return 'image/gif';
83
- if (
84
- data.subarray(0, 4).toString('ascii') === 'RIFF' &&
85
- data.subarray(8, 12).toString('ascii') === 'WEBP'
86
- )
87
- return 'image/webp';
88
- }
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { messageContent, imageAttachments } from './session-input.mjs';
2
+ import { messageContent } from './session-input.mjs';
3
3
 
4
4
  const networkActions = new Set(['start', 'send', 'wait', 'stop', 'list', 'view']);
5
5
 
@@ -21,11 +21,6 @@ export async function prepareAgentNetworkRequest({ args, stdin, translate, sessi
21
21
  'executionId'
22
22
  ])
23
23
  if (args[name] !== undefined) input[name] = args[name];
24
- if (args.action === 'list' && input.parentSessionId !== undefined) {
25
- input.parent = input.parentSessionId;
26
- delete input.parentSessionId;
27
- }
28
- if (args.action === 'list' && args.agent !== undefined) input.agentId = args.agent;
29
24
  if (['send', 'stop', 'view', 'wait'].includes(args.action) && sessionId)
30
25
  input.agentId = sessionId;
31
26
  if (args.action === 'wait' && args.agentIds?.length) input.agentIds = args.agentIds;
@@ -33,7 +28,6 @@ export async function prepareAgentNetworkRequest({ args, stdin, translate, sessi
33
28
  if (args.action === 'view' && args.history) input.includeHistory = true;
34
29
  if (args.message !== undefined || args.messageFile !== undefined)
35
30
  input.content = await messageContent(args, stdin, 100000, translate);
36
- if (args.images?.length) input.attachments = await imageAttachments(args.images, translate);
37
31
  if (args.goal !== undefined) input.goal = { objective: args.goal.trim() };
38
32
  if (args.clearGoal) input.goal = { clear: true };
39
33
  if (args.action === 'send' && args.approvalId !== undefined)
@@ -87,10 +81,6 @@ export async function prepareSessionRequest({ args, env, stdin, translate, sessi
87
81
  );
88
82
  if (args.action === 'approval.decide')
89
83
  body.decision = args.decision === 'approve' ? 'APPROVED' : 'REJECTED';
90
- if (args.images !== undefined) {
91
- body.attachments = await imageAttachments(args.images, translate);
92
- body.content ??= '';
93
- }
94
84
  if (args.action === 'start' || args.action === 'send')
95
85
  body.clientMessageId = args.clientMessageId ?? randomUUID();
96
86
  if (args.action === 'send')