@myagentroam/marctl 0.11.9 → 0.11.11
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 +1 -1
- package/src/i18n/en-US.mjs +18 -15
- package/src/i18n/zh-CN.mjs +17 -16
- package/src/session-args.mjs +6 -18
- package/src/session-input.mjs +0 -45
- package/src/session-prepare.mjs +2 -9
package/package.json
CHANGED
package/src/i18n/en-US.mjs
CHANGED
|
@@ -45,22 +45,20 @@ 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|->]
|
|
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
|
-
{program} stop <id>
|
|
58
|
+
{program} stop <id> [--json]
|
|
60
59
|
{program} list [--scope tree|active] [--query <title>]
|
|
61
60
|
[--limit <1..100>] [--json]
|
|
62
|
-
{program} view [<id>] [--
|
|
63
|
-
[--limit <1..100>] [--json]
|
|
61
|
+
{program} view [<id>] [--json]
|
|
64
62
|
|
|
65
63
|
Management:
|
|
66
64
|
{program} config [<id>] [--model-id <id>] [--effort <value>] [--json]
|
|
@@ -78,34 +76,41 @@ Management:
|
|
|
78
76
|
{program} wait <id> --run <run-id> [--until approval] --timeout <duration>
|
|
79
77
|
{program} goal get|clear <id> [--json]
|
|
80
78
|
{program} goal set <id> (-m <text> | --message-file <file|->) [--json]
|
|
81
|
-
{program} current | show [<id>] | graph [<id>]
|
|
79
|
+
{program} current | show [<id>] | graph [<id>]
|
|
80
|
+
{program} history [<id>] [--cursor <cursor>] [--limit <1..100>] [--json]
|
|
82
81
|
|
|
83
82
|
Input and results:
|
|
84
83
|
Start defaults to the current Session Runner; a terminal without a current
|
|
85
84
|
Session must specify --runner or --parent. Start returns without waiting.
|
|
86
85
|
Send appends by default; --steer provides timely input and --queue defers.
|
|
87
86
|
--goal sets or replaces a Goal; --clear-goal clears it. Send can update a Goal
|
|
88
|
-
without text; omitted Goal is unchanged. Stop
|
|
87
|
+
without text; omitted Goal is unchanged. Stop targets the current execution
|
|
88
|
+
and clears the target Session Goal.
|
|
89
89
|
Wait defaults to direct-child completion and 30s; 0ms is a snapshot.
|
|
90
|
-
Positive timeouts
|
|
91
|
-
|
|
90
|
+
Positive timeouts use the requested duration; maximum is 5m.
|
|
91
|
+
Waiting does not stop the task.
|
|
92
92
|
-m and --message-file are exclusive; files use UTF-8 and - reads stdin.
|
|
93
93
|
List defaults to the containing tree, including idle Sessions. Without a
|
|
94
94
|
current Session it defaults to active; explicit tree requires a Session.
|
|
95
95
|
Active includes running and sleeping Sessions in the current Workspace.
|
|
96
96
|
List returns currentAgentId (null without a Session), flat sessions and
|
|
97
|
-
truncated. Limit defaults to
|
|
97
|
+
truncated. Limit defaults to 10, maximum 100; no cursor or pagination.
|
|
98
|
+
Active Sessions come first, then recent activity descending.
|
|
98
99
|
Configuration and prompt changes apply to future executions.
|
|
99
100
|
Prefer --steer for timely communication or course correction.
|
|
100
|
-
|
|
101
|
+
Reserve --queue for explicitly requested deferred input: it is consumed after
|
|
101
102
|
current work and earlier queued inputs finish. With an active Goal it is
|
|
102
103
|
not consumed until that Goal exits.
|
|
103
104
|
Acceptance does not guarantee immediate processing.
|
|
105
|
+
An accepted message normally needs no separate acknowledgment or receipt
|
|
106
|
+
check.
|
|
107
|
+
While children run, prefer meaningful, non-overlapping work; wait when needed
|
|
108
|
+
to unblock or finish and no other meaningful local task work remains.
|
|
104
109
|
|
|
105
110
|
show --json includes session.status, session.modelId, session.effort,
|
|
106
111
|
session.title, session.runId, session.recentTools, session.queuedCount and
|
|
107
|
-
session.latestMessage. List entries have id, parentSessionId, title
|
|
108
|
-
|
|
112
|
+
session.latestMessage. List entries have id, parentSessionId, title and
|
|
113
|
+
status; wait may include progress. View omits Run and Execution IDs.
|
|
109
114
|
Status is RUNNING/IDLE/SLEEPING. In history, segments[].items[] with
|
|
110
115
|
kind === "assistant_message" expose payload.text.
|
|
111
116
|
|
|
@@ -222,8 +227,6 @@ or Server connection is required.`
|
|
|
222
227
|
'The delivery outcome is unknown. Inspect Session state/history before retrying.',
|
|
223
228
|
sessionMessageInvalid:
|
|
224
229
|
'The message must be non-empty and within the length limit; input files must be readable UTF-8.',
|
|
225
|
-
sessionImageInvalid:
|
|
226
|
-
'Images must be readable PNG, JPEG, GIF or WebP files: at most 5 images, 5 MiB each and 10 MiB total.',
|
|
227
230
|
sessionWaitUnknown: 'The specified Run could not be confirmed. Inspect Session state/history.',
|
|
228
231
|
sessionWaitCancelled: 'Waiting was cancelled; the target Run was not stopped.',
|
|
229
232
|
sessionWaitTimeout: 'Waiting timed out; the target Run was not stopped.',
|
package/src/i18n/zh-CN.mjs
CHANGED
|
@@ -44,22 +44,20 @@ ${configurationHelp}
|
|
|
44
44
|
agents: `{program} — 协调当前 MAR 工作区中的 Agent
|
|
45
45
|
|
|
46
46
|
用法:
|
|
47
|
-
{program} start [-m <text> | --message-file <file|->]
|
|
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
|
-
{program} stop <id>
|
|
57
|
+
{program} stop <id> [--json]
|
|
59
58
|
{program} list [--scope tree|active] [--query <title>]
|
|
60
59
|
[--limit <1..100>] [--json]
|
|
61
|
-
{program} view [<id>] [--
|
|
62
|
-
[--limit <1..100>] [--json]
|
|
60
|
+
{program} view [<id>] [--json]
|
|
63
61
|
|
|
64
62
|
管理:
|
|
65
63
|
{program} config [<id>] [--model-id <id>] [--effort <value>] [--json]
|
|
@@ -77,29 +75,34 @@ ${configurationHelp}
|
|
|
77
75
|
{program} wait <id> --run <run-id> [--until approval] --timeout <duration>
|
|
78
76
|
{program} goal get|clear <id> [--json]
|
|
79
77
|
{program} goal set <id> (-m <text> | --message-file <file|->) [--json]
|
|
80
|
-
{program} current | show [<id>] | graph [<id>]
|
|
78
|
+
{program} current | show [<id>] | graph [<id>]
|
|
79
|
+
{program} history [<id>] [--cursor <cursor>] [--limit <1..100>] [--json]
|
|
81
80
|
|
|
82
81
|
输入与结果:
|
|
83
82
|
start 默认当前会话的 Runner;没有当前会话的终端须指定 --runner 或
|
|
84
83
|
--parent。start 不等待。
|
|
85
84
|
send 默认追加;--steer 优先补充,--queue 排队。--goal 设置或替换目标,
|
|
86
85
|
--clear-goal 清除目标;send 可仅更新目标,省略则不修改。
|
|
87
|
-
stop
|
|
88
|
-
0ms
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
stop 停止目标当前执行并清除 Goal。wait 默认等待直接子会话终态 30 秒,
|
|
87
|
+
0ms 为快照;正数按传入时长等待,最多 5 分钟。等待不会停止任务。
|
|
88
|
+
-m 与 --message-file 互斥;文件使用 UTF-8,- 从 stdin 读取。
|
|
89
|
+
list 默认查询所在会话树,包含空闲会话;
|
|
91
90
|
没有当前会话时默认 active,显式 tree 须有会话上下文。active 包含当前
|
|
92
91
|
Workspace 中运行及睡眠的会话。返回 currentAgentId(无会话时为 null)、
|
|
93
|
-
扁平 sessions 和 truncated。limit
|
|
92
|
+
扁平 sessions 和 truncated。limit 默认 10、上限 100,无 cursor 或分页。
|
|
93
|
+
活跃会话优先,其后按最近活动时间倒序。
|
|
94
94
|
配置和持久提示从后续执行生效。
|
|
95
95
|
即时沟通或纠偏优先使用 --steer。
|
|
96
|
-
|
|
96
|
+
建议仅将 --queue 用于明确要求延后的输入:当前工作及前面的队列项结束后才消费,
|
|
97
97
|
有活动 Goal 时,必须等到该 Goal 退出才消费。已接收不保证立即处理。
|
|
98
|
+
消息被接受后,通常无需另行确认收悉或立即查看是否收到。
|
|
99
|
+
子会话运行时建议并行推进有意义且不重叠的工作;无其他本地工作可做,且需
|
|
100
|
+
结果解除阻塞或收尾时,再考虑等待。
|
|
98
101
|
|
|
99
102
|
show --json 包含 session.status、session.modelId、session.effort、
|
|
100
103
|
session.title、session.runId、session.recentTools、session.queuedCount 和
|
|
101
|
-
session.latestMessage。list 每项仅含 id、parentSessionId、title
|
|
102
|
-
|
|
104
|
+
session.latestMessage。list 每项仅含 id、parentSessionId、title 和 status;
|
|
105
|
+
wait 可能包含 progress;view 不公开 Run 或 Execution ID。
|
|
103
106
|
状态为 RUNNING/IDLE/SLEEPING。历史中 segments[].items[] 的
|
|
104
107
|
kind === "assistant_message" 包含 payload.text。
|
|
105
108
|
|
|
@@ -209,8 +212,6 @@ ${configurationHelp}`,
|
|
|
209
212
|
errors: Object.freeze({
|
|
210
213
|
sessionOutcomeUnknown: '投递结果未知,请先查看会话状态和历史,不要盲目重试。',
|
|
211
214
|
sessionMessageInvalid: '消息不能为空或超过长度限制;输入文件必须是可读取的 UTF-8 文本。',
|
|
212
|
-
sessionImageInvalid:
|
|
213
|
-
'图片必须是可读取的 PNG、JPEG、GIF 或 WebP 文件:最多 5 张,单张 5 MiB,合计 10 MiB。',
|
|
214
215
|
sessionWaitUnknown: '无法确认指定 Run,请查看会话状态和历史。',
|
|
215
216
|
sessionWaitCancelled: '已取消等待,未停止目标 Run。',
|
|
216
217
|
sessionWaitTimeout: '等待超时,未停止目标 Run。',
|
package/src/session-args.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const commands = {
|
|
|
7
7
|
list: ['scope', 'query', 'limit'],
|
|
8
8
|
graph: ['limit'],
|
|
9
9
|
show: [],
|
|
10
|
-
view: [
|
|
10
|
+
view: [],
|
|
11
11
|
history: ['cursor', 'limit'],
|
|
12
12
|
start: [
|
|
13
13
|
'runner',
|
|
@@ -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',
|
|
@@ -44,7 +42,7 @@ const commands = {
|
|
|
44
42
|
'approval',
|
|
45
43
|
'decision'
|
|
46
44
|
],
|
|
47
|
-
stop: [
|
|
45
|
+
stop: [],
|
|
48
46
|
'goal.get': [],
|
|
49
47
|
'goal.set': ['message', 'message-file'],
|
|
50
48
|
'goal.clear': [],
|
|
@@ -59,10 +57,8 @@ const fieldNames = {
|
|
|
59
57
|
run: 'runId',
|
|
60
58
|
approval: 'approvalId',
|
|
61
59
|
timeout: 'timeoutMs',
|
|
62
|
-
execution: 'executionId',
|
|
63
60
|
'wait-for': 'waitFor',
|
|
64
|
-
'clear-goal': 'clearGoal'
|
|
65
|
-
image: 'images'
|
|
61
|
+
'clear-goal': 'clearGoal'
|
|
66
62
|
};
|
|
67
63
|
|
|
68
64
|
export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
@@ -115,11 +111,8 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
115
111
|
args[key] = true;
|
|
116
112
|
continue;
|
|
117
113
|
}
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
(flag === '--history' && action === 'view')
|
|
121
|
-
) {
|
|
122
|
-
const key = flag === '--history' ? 'history' : 'clearGoal';
|
|
114
|
+
if (flag === '--clear-goal' && ['start', 'send'].includes(action)) {
|
|
115
|
+
const key = 'clearGoal';
|
|
123
116
|
if (Object.hasOwn(args, key)) throw invalid();
|
|
124
117
|
args[key] = true;
|
|
125
118
|
continue;
|
|
@@ -128,7 +121,7 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
128
121
|
const key = fieldNames[name] ?? name;
|
|
129
122
|
if (
|
|
130
123
|
!commands[action].includes(name) ||
|
|
131
|
-
(
|
|
124
|
+
(!(name === 'agent' && action === 'wait') && Object.hasOwn(args, key))
|
|
132
125
|
)
|
|
133
126
|
throw invalid();
|
|
134
127
|
const value = input.shift();
|
|
@@ -141,9 +134,6 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
141
134
|
if (name === 'agent' && action === 'wait') {
|
|
142
135
|
(args.agentIds ??= []).push(value);
|
|
143
136
|
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
137
|
} else if (name === 'limit' || name === 'expected-revision') {
|
|
148
138
|
if (
|
|
149
139
|
!/^[1-9][0-9]*$/u.test(value) ||
|
|
@@ -174,7 +164,6 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
174
164
|
['start', 'send', 'goal.set', 'schedule.create', 'prompt.set'].includes(action) &&
|
|
175
165
|
args.messageFile === undefined &&
|
|
176
166
|
args.message === undefined &&
|
|
177
|
-
!args.images?.length &&
|
|
178
167
|
!(
|
|
179
168
|
action === 'send' &&
|
|
180
169
|
(args.goal !== undefined || args.clearGoal || args.approvalId !== undefined)
|
|
@@ -187,7 +176,6 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
187
176
|
!['mar-agent', 'codex', 'claude-code', 'opencode'].includes(args.runner)
|
|
188
177
|
)
|
|
189
178
|
throw invalid();
|
|
190
|
-
if (action === 'stop' && !args.executionId) throw invalid();
|
|
191
179
|
if (action === 'wait' && args.sessionId && args.agentIds?.length) throw invalid();
|
|
192
180
|
if (
|
|
193
181
|
args.until !== undefined &&
|
package/src/session-input.mjs
CHANGED
|
@@ -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
|
-
}
|
package/src/session-prepare.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { messageContent
|
|
2
|
+
import { messageContent } from './session-input.mjs';
|
|
3
3
|
|
|
4
4
|
const networkActions = new Set(['start', 'send', 'wait', 'stop', 'list', 'view']);
|
|
5
5
|
|
|
@@ -17,18 +17,15 @@ export async function prepareAgentNetworkRequest({ args, stdin, translate, sessi
|
|
|
17
17
|
'parentSessionId',
|
|
18
18
|
'scope',
|
|
19
19
|
'waitFor',
|
|
20
|
-
'mode'
|
|
21
|
-
'executionId'
|
|
20
|
+
'mode'
|
|
22
21
|
])
|
|
23
22
|
if (args[name] !== undefined) input[name] = args[name];
|
|
24
23
|
if (['send', 'stop', 'view', 'wait'].includes(args.action) && sessionId)
|
|
25
24
|
input.agentId = sessionId;
|
|
26
25
|
if (args.action === 'wait' && args.agentIds?.length) input.agentIds = args.agentIds;
|
|
27
26
|
if (args.action === 'wait' && args.timeoutMs !== undefined) input.waitMs = args.timeoutMs;
|
|
28
|
-
if (args.action === 'view' && args.history) input.includeHistory = true;
|
|
29
27
|
if (args.message !== undefined || args.messageFile !== undefined)
|
|
30
28
|
input.content = await messageContent(args, stdin, 100000, translate);
|
|
31
|
-
if (args.images?.length) input.attachments = await imageAttachments(args.images, translate);
|
|
32
29
|
if (args.goal !== undefined) input.goal = { objective: args.goal.trim() };
|
|
33
30
|
if (args.clearGoal) input.goal = { clear: true };
|
|
34
31
|
if (args.action === 'send' && args.approvalId !== undefined)
|
|
@@ -82,10 +79,6 @@ export async function prepareSessionRequest({ args, env, stdin, translate, sessi
|
|
|
82
79
|
);
|
|
83
80
|
if (args.action === 'approval.decide')
|
|
84
81
|
body.decision = args.decision === 'approve' ? 'APPROVED' : 'REJECTED';
|
|
85
|
-
if (args.images !== undefined) {
|
|
86
|
-
body.attachments = await imageAttachments(args.images, translate);
|
|
87
|
-
body.content ??= '';
|
|
88
|
-
}
|
|
89
82
|
if (args.action === 'start' || args.action === 'send')
|
|
90
83
|
body.clientMessageId = args.clientMessageId ?? randomUUID();
|
|
91
84
|
if (args.action === 'send')
|