@myagentroam/marctl 0.10.8 → 0.10.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 +1 -1
- package/src/i18n/en-US.mjs +38 -6
- package/src/i18n/zh-CN.mjs +34 -6
- package/src/sessions.mjs +70 -12
package/package.json
CHANGED
package/src/i18n/en-US.mjs
CHANGED
|
@@ -48,10 +48,19 @@ Usage:
|
|
|
48
48
|
{program} current [--json]
|
|
49
49
|
{program} list [--query <title>] [--parent <session-id>]
|
|
50
50
|
[--cursor <cursor>] [--limit <1..100>] [--json]
|
|
51
|
-
{program} show <session-id> [--json]
|
|
52
|
-
{program} config <session-id>
|
|
53
|
-
|
|
54
|
-
{program}
|
|
51
|
+
{program} show [<session-id>] [--json]
|
|
52
|
+
{program} config [<session-id>]
|
|
53
|
+
[--model <id>] [--effort <value>] [--json]
|
|
54
|
+
{program} rename [<session-id>] --title <name> [--json]
|
|
55
|
+
{program} schedule list [--cursor <cursor>] [--limit <1..100>] [--json]
|
|
56
|
+
{program} schedule get [<session-id>] [--json]
|
|
57
|
+
{program} schedule create [<session-id>] --cron <cron>
|
|
58
|
+
(-m <text> | --message-file <file|->) [--json]
|
|
59
|
+
{program} schedule update [<session-id>]
|
|
60
|
+
--expected-revision <revision>
|
|
61
|
+
[--cron <cron>] [-m <text> | --message-file <file|->] [--json]
|
|
62
|
+
{program} graph [<session-id>] [--limit <1..100>] [--json]
|
|
63
|
+
{program} history [<session-id>]
|
|
55
64
|
[--cursor <cursor>] [--limit <1..100>] [--json]
|
|
56
65
|
|
|
57
66
|
{program} start --runner <runner>
|
|
@@ -72,6 +81,10 @@ Usage:
|
|
|
72
81
|
--run <run-id> --timeout <30s|5m> [--json]
|
|
73
82
|
|
|
74
83
|
Input:
|
|
84
|
+
show/config/history/graph/rename may omit the ID.
|
|
85
|
+
schedule get/create/update follow the same rule.
|
|
86
|
+
They use the current Session; without one, specify an ID explicitly.
|
|
87
|
+
send/goal/stop/wait always require an explicit Session ID.
|
|
75
88
|
Runners: mar-agent, codex, claude-code, opencode; actual capabilities apply.
|
|
76
89
|
-m / --message supplies text; it is mutually exclusive with --message-file.
|
|
77
90
|
Files use UTF-8; - reads stdin. Repeat --image for PNG/JPEG/GIF/WebP files.
|
|
@@ -80,11 +93,29 @@ Input:
|
|
|
80
93
|
Config requires model or effort; other fields and permissions are unchanged.
|
|
81
94
|
Use --effort "" for the Runner default. Active execution is not restarted.
|
|
82
95
|
|
|
96
|
+
Titles and scheduled tasks:
|
|
97
|
+
rename uses the existing title update; no parent-tree restriction.
|
|
98
|
+
It does not restart execution. schedule list reads local Workspace tasks.
|
|
99
|
+
schedule get/create/update share MCP task data.
|
|
100
|
+
Schedule text is limited to 20,000 characters; update requires cron or text.
|
|
101
|
+
Other-owner edits create PENDING proposals; scheduled callers are read-only.
|
|
102
|
+
Read the current revision before updating; a version conflict is not retried.
|
|
103
|
+
|
|
104
|
+
Reading JSON:
|
|
105
|
+
show: session.activity, session.model, session.effort,
|
|
106
|
+
session.customTitle / session.runnerTitle, runs[] (id/status),
|
|
107
|
+
queue.items[], goal.status (goal may be null).
|
|
108
|
+
history: segments[].items[]; select kind === "assistant_message",
|
|
109
|
+
read payload.text.
|
|
110
|
+
|
|
83
111
|
Delivery and waiting:
|
|
84
112
|
Start/send return a clientMessageId.
|
|
85
113
|
Send requires exactly one of --steer or --queue, even when idle.
|
|
86
|
-
|
|
87
|
-
|
|
114
|
+
--steer prioritizes new context and may switch the current execution.
|
|
115
|
+
Node decides from actual state; reserve it for updates
|
|
116
|
+
affecting current work.
|
|
117
|
+
--queue schedules a subsequent turn; an active Goal can delay it
|
|
118
|
+
until the Goal exits.
|
|
88
119
|
Example:
|
|
89
120
|
marctl sessions send <session-id> --steer \\
|
|
90
121
|
-m "Additional context: focus on the resume path." --json
|
|
@@ -233,6 +264,7 @@ or Server connection is required.`
|
|
|
233
264
|
sessionWaitTimeout: 'Waiting timed out; the target Run was not stopped.',
|
|
234
265
|
|
|
235
266
|
userContextUnavailable: 'This Node session has no valid marctl user authorization.',
|
|
267
|
+
sessionContextRequired: 'No current Session is available; specify a Session ID explicitly.',
|
|
236
268
|
serverUrlInvalid: 'MAR_CTL_SERVER_URL is invalid.',
|
|
237
269
|
serverUrlTransport: 'MAR_CTL_SERVER_URL must use HTTPS or loopback HTTP.',
|
|
238
270
|
serverUrlOrigin: 'MAR_CTL_SERVER_URL must be an origin without credentials or query data.',
|
package/src/i18n/zh-CN.mjs
CHANGED
|
@@ -47,10 +47,19 @@ ${configurationHelp}
|
|
|
47
47
|
{program} current [--json]
|
|
48
48
|
{program} list [--query <title>] [--parent <session-id>]
|
|
49
49
|
[--cursor <cursor>] [--limit <1..100>] [--json]
|
|
50
|
-
{program} show <session-id> [--json]
|
|
51
|
-
{program} config <session-id>
|
|
52
|
-
|
|
53
|
-
{program}
|
|
50
|
+
{program} show [<session-id>] [--json]
|
|
51
|
+
{program} config [<session-id>]
|
|
52
|
+
[--model <id>] [--effort <value>] [--json]
|
|
53
|
+
{program} rename [<session-id>] --title <name> [--json]
|
|
54
|
+
{program} schedule list [--cursor <cursor>] [--limit <1..100>] [--json]
|
|
55
|
+
{program} schedule get [<session-id>] [--json]
|
|
56
|
+
{program} schedule create [<session-id>] --cron <cron>
|
|
57
|
+
(-m <text> | --message-file <file|->) [--json]
|
|
58
|
+
{program} schedule update [<session-id>]
|
|
59
|
+
--expected-revision <revision>
|
|
60
|
+
[--cron <cron>] [-m <text> | --message-file <file|->] [--json]
|
|
61
|
+
{program} graph [<session-id>] [--limit <1..100>] [--json]
|
|
62
|
+
{program} history [<session-id>]
|
|
54
63
|
[--cursor <cursor>] [--limit <1..100>] [--json]
|
|
55
64
|
|
|
56
65
|
{program} start --runner <runner>
|
|
@@ -71,6 +80,9 @@ ${configurationHelp}
|
|
|
71
80
|
--run <run-id> --timeout <30s|5m> [--json]
|
|
72
81
|
|
|
73
82
|
输入:
|
|
83
|
+
show/config/history/graph/rename 和 schedule get/create/update 可省略 ID,
|
|
84
|
+
使用当前会话;没有当前会话时请显式指定 ID。
|
|
85
|
+
send/goal/stop/wait 始终要求显式会话 ID。
|
|
74
86
|
Runner:mar-agent、codex、claude-code、opencode,操作以实际能力为准。
|
|
75
87
|
-m / --message 直接传文本,与 --message-file 互斥;
|
|
76
88
|
文件用 UTF-8,- 从 stdin 读取。
|
|
@@ -79,11 +91,26 @@ ${configurationHelp}
|
|
|
79
91
|
config 至少指定 model 或 effort;未指定字段和权限不变。
|
|
80
92
|
--effort "" 使用 Runner 默认值,不重启当前执行。
|
|
81
93
|
|
|
94
|
+
标题与定时任务:
|
|
95
|
+
rename 复用现有标题更新,不限制 parent 树、不重启执行。
|
|
96
|
+
schedule list 读取本地 Workspace 任务,get/create/update 与 MCP 共用任务数据。
|
|
97
|
+
任务正文最多 20,000 字符;update 至少指定 cron 或正文。
|
|
98
|
+
修改其他用户的任务会生成 PENDING 提议;定时来源只读。
|
|
99
|
+
更新前读取当前 revision;版本冲突不会自动重试。
|
|
100
|
+
|
|
101
|
+
读取 JSON:
|
|
102
|
+
show:session.activity、session.model、session.effort、
|
|
103
|
+
session.customTitle / session.runnerTitle、runs[](id/status)、
|
|
104
|
+
queue.items[]、goal.status(goal 可为空)。
|
|
105
|
+
history:segments[].items[] 中按 kind === "assistant_message"
|
|
106
|
+
筛选,读取 payload.text。
|
|
107
|
+
|
|
82
108
|
投递与等待:
|
|
83
109
|
start/send 返回 clientMessageId。
|
|
84
110
|
send 必须二选一:--steer 或 --queue,空闲时也需指定。
|
|
85
|
-
--steer
|
|
86
|
-
|
|
111
|
+
--steer 优先补充新信息,可能切换当前执行;
|
|
112
|
+
Node 按实际状态裁决,仅用于影响当前工作的必要更新。
|
|
113
|
+
--queue 排入后续轮次;有活动 Goal 时可能等待 Goal 退出才处理。
|
|
87
114
|
示例:
|
|
88
115
|
marctl sessions send <session-id> --steer \\
|
|
89
116
|
-m "Additional context: focus on the resume path." --json
|
|
@@ -222,6 +249,7 @@ ${configurationHelp}`,
|
|
|
222
249
|
sessionWaitTimeout: '等待超时,未停止目标 Run。',
|
|
223
250
|
|
|
224
251
|
userContextUnavailable: '此 Node 会话没有有效的 marctl 用户授权。',
|
|
252
|
+
sessionContextRequired: '当前上下文没有会话,请显式指定会话 ID。',
|
|
225
253
|
serverUrlInvalid: 'MAR_CTL_SERVER_URL 无效。',
|
|
226
254
|
serverUrlTransport: 'MAR_CTL_SERVER_URL 必须使用 HTTPS 或回环 HTTP。',
|
|
227
255
|
serverUrlOrigin: 'MAR_CTL_SERVER_URL 必须是不含凭据或查询参数的 Origin。',
|
package/src/sessions.mjs
CHANGED
|
@@ -5,6 +5,16 @@ import { MarctlError } from './config.mjs';
|
|
|
5
5
|
import { createTranslator } from './i18n/index.mjs';
|
|
6
6
|
|
|
7
7
|
const terminal = new Set(['SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED']);
|
|
8
|
+
const currentSessionActions = new Set([
|
|
9
|
+
'show',
|
|
10
|
+
'config',
|
|
11
|
+
'history',
|
|
12
|
+
'graph',
|
|
13
|
+
'rename',
|
|
14
|
+
'schedule.get',
|
|
15
|
+
'schedule.create',
|
|
16
|
+
'schedule.update'
|
|
17
|
+
]);
|
|
8
18
|
const commands = {
|
|
9
19
|
current: [],
|
|
10
20
|
list: ['cursor', 'limit', 'query', 'parent'],
|
|
@@ -22,6 +32,11 @@ const commands = {
|
|
|
22
32
|
'client-message-id'
|
|
23
33
|
],
|
|
24
34
|
config: ['model', 'effort'],
|
|
35
|
+
rename: ['title'],
|
|
36
|
+
'schedule.list': ['cursor', 'limit'],
|
|
37
|
+
'schedule.get': [],
|
|
38
|
+
'schedule.create': ['cron', 'message', 'message-file'],
|
|
39
|
+
'schedule.update': ['cron', 'message', 'message-file', 'expected-revision'],
|
|
25
40
|
send: ['message', 'message-file', 'image', 'steer', 'queue', 'client-message-id'],
|
|
26
41
|
stop: ['run'],
|
|
27
42
|
'goal.get': [],
|
|
@@ -31,6 +46,7 @@ const commands = {
|
|
|
31
46
|
};
|
|
32
47
|
const fieldNames = {
|
|
33
48
|
parent: 'parentSessionId',
|
|
49
|
+
'expected-revision': 'expectedRevision',
|
|
34
50
|
'message-file': 'messageFile',
|
|
35
51
|
'client-message-id': 'clientMessageId',
|
|
36
52
|
run: 'runId',
|
|
@@ -51,13 +67,17 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
51
67
|
return { command: 'sessions', help: true };
|
|
52
68
|
const input = [...argv];
|
|
53
69
|
let action = input.shift();
|
|
54
|
-
if (action === 'goal') action += '.' + input.shift();
|
|
70
|
+
if (action === 'goal' || action === 'schedule') action += '.' + input.shift();
|
|
55
71
|
if (!Object.hasOwn(commands, action)) throw invalid();
|
|
56
72
|
const args = { command: 'sessions', action };
|
|
57
|
-
if (!['current', 'list', 'start'].includes(action)) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
if (!['current', 'list', 'start', 'schedule.list'].includes(action)) {
|
|
74
|
+
if ((input[0] === undefined || input[0].startsWith('-')) && !currentSessionActions.has(action))
|
|
75
|
+
throw invalid();
|
|
76
|
+
if (input[0] !== undefined && !input[0].startsWith('-')) {
|
|
77
|
+
const sessionId = input.shift();
|
|
78
|
+
if (!sessionId || sessionId.length > 512) throw invalid();
|
|
79
|
+
args.sessionId = sessionId;
|
|
80
|
+
}
|
|
61
81
|
}
|
|
62
82
|
while (input.length > 0) {
|
|
63
83
|
const rawFlag = input.shift();
|
|
@@ -86,8 +106,13 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
86
106
|
if (name === 'image') {
|
|
87
107
|
(args.images ??= []).push(value);
|
|
88
108
|
if (args.images.length > 5) throw invalid();
|
|
89
|
-
} else if (name === 'limit') {
|
|
90
|
-
if (
|
|
109
|
+
} else if (name === 'limit' || name === 'expected-revision') {
|
|
110
|
+
if (
|
|
111
|
+
!/^[1-9][0-9]*$/u.test(value) ||
|
|
112
|
+
!Number.isSafeInteger(Number(value)) ||
|
|
113
|
+
(name === 'limit' && Number(value) > 100)
|
|
114
|
+
)
|
|
115
|
+
throw invalid();
|
|
91
116
|
args[key] = Number(value);
|
|
92
117
|
} else if (name === 'timeout') {
|
|
93
118
|
const match = /^([1-9][0-9]*)(ms|s|m)$/u.exec(value);
|
|
@@ -100,7 +125,7 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
100
125
|
throw invalid('errors.sessionDeliveryRequired');
|
|
101
126
|
if (args.message !== undefined && args.messageFile !== undefined) throw invalid();
|
|
102
127
|
if (
|
|
103
|
-
['start', 'send', 'goal.set'].includes(action) &&
|
|
128
|
+
['start', 'send', 'goal.set', 'schedule.create'].includes(action) &&
|
|
104
129
|
args.messageFile === undefined &&
|
|
105
130
|
args.message === undefined &&
|
|
106
131
|
!args.images?.length
|
|
@@ -113,17 +138,37 @@ export function parseSessionArgs(argv, translate = createTranslator()) {
|
|
|
113
138
|
throw invalid();
|
|
114
139
|
if (action === 'wait' && (args.runId === undefined || args.timeoutMs === undefined))
|
|
115
140
|
throw invalid();
|
|
141
|
+
if (action === 'rename' && args.title !== undefined) args.title = args.title.trim();
|
|
116
142
|
if (args.title !== undefined && args.title.length > 160) throw invalid();
|
|
117
143
|
if (args.model !== undefined && (args.model.trim().length === 0 || args.model.length > 120))
|
|
118
144
|
throw invalid();
|
|
119
145
|
if (args.effort !== undefined && args.effort.length > 120) throw invalid();
|
|
120
146
|
if (action === 'config' && args.model === undefined && args.effort === undefined) throw invalid();
|
|
147
|
+
if (action === 'rename') {
|
|
148
|
+
if (args.title === undefined || args.title.trim().length === 0) throw invalid();
|
|
149
|
+
}
|
|
150
|
+
if (action === 'schedule.create' && args.cron === undefined) throw invalid();
|
|
151
|
+
if (args.cron !== undefined && (args.cron.trim().length === 0 || args.cron.length > 512))
|
|
152
|
+
throw invalid();
|
|
153
|
+
if (
|
|
154
|
+
action === 'schedule.update' &&
|
|
155
|
+
(args.expectedRevision === undefined ||
|
|
156
|
+
(args.cron === undefined && args.message === undefined && args.messageFile === undefined))
|
|
157
|
+
)
|
|
158
|
+
throw invalid();
|
|
121
159
|
if (args.query !== undefined && args.query.length > 160) throw invalid();
|
|
122
160
|
if (args.parentSessionId !== undefined && args.parentSessionId.length > 512) throw invalid();
|
|
123
161
|
return args;
|
|
124
162
|
}
|
|
125
163
|
|
|
126
164
|
export async function runSessionCommand({ args, client, env, stdin, WebSocketClass, translate }) {
|
|
165
|
+
const targeted = !['current', 'list', 'start', 'schedule.list'].includes(args.action);
|
|
166
|
+
const sessionId =
|
|
167
|
+
args.sessionId ?? (currentSessionActions.has(args.action) ? env.MAR_CTL_SESSION_ID : undefined);
|
|
168
|
+
if (targeted && !sessionId)
|
|
169
|
+
throw new MarctlError(translate('errors.sessionContextRequired'), {
|
|
170
|
+
code: 'MARCTL_SESSION_CONTEXT_REQUIRED'
|
|
171
|
+
});
|
|
127
172
|
if (args.action === 'wait') {
|
|
128
173
|
const controller = new AbortController();
|
|
129
174
|
const cancel = () => controller.abort();
|
|
@@ -132,7 +177,7 @@ export async function runSessionCommand({ args, client, env, stdin, WebSocketCla
|
|
|
132
177
|
try {
|
|
133
178
|
return await waitForSessionRun({
|
|
134
179
|
client,
|
|
135
|
-
sessionId
|
|
180
|
+
sessionId,
|
|
136
181
|
runId: args.runId,
|
|
137
182
|
timeoutMs: args.timeoutMs,
|
|
138
183
|
WebSocketClass,
|
|
@@ -155,9 +200,12 @@ export async function runSessionCommand({ args, client, env, stdin, WebSocketCla
|
|
|
155
200
|
'cursor',
|
|
156
201
|
'limit',
|
|
157
202
|
'query',
|
|
158
|
-
'runId'
|
|
203
|
+
'runId',
|
|
204
|
+
'cron',
|
|
205
|
+
'expectedRevision'
|
|
159
206
|
])
|
|
160
207
|
if (args[name] !== undefined) body[name] = args[name];
|
|
208
|
+
if (targeted) body.sessionId = sessionId;
|
|
161
209
|
if (args.action === 'current' && env.MAR_CTL_SESSION_ID) body.sessionId = env.MAR_CTL_SESSION_ID;
|
|
162
210
|
if (args.action === 'start' && env.MAR_CTL_SESSION_ID)
|
|
163
211
|
body.parentSessionId = env.MAR_CTL_SESSION_ID;
|
|
@@ -167,7 +215,7 @@ export async function runSessionCommand({ args, client, env, stdin, WebSocketCla
|
|
|
167
215
|
body.content = await messageContent(
|
|
168
216
|
args,
|
|
169
217
|
stdin,
|
|
170
|
-
args.action === 'goal.set' ? 20000 : 100000,
|
|
218
|
+
args.action === 'goal.set' || args.action.startsWith('schedule.') ? 20000 : 100000,
|
|
171
219
|
translate
|
|
172
220
|
);
|
|
173
221
|
if (args.images !== undefined) {
|
|
@@ -189,7 +237,17 @@ export async function runSessionCommand({ args, client, env, stdin, WebSocketCla
|
|
|
189
237
|
} catch (error) {
|
|
190
238
|
if (body.clientMessageId !== undefined) error.clientMessageId = body.clientMessageId;
|
|
191
239
|
if (
|
|
192
|
-
[
|
|
240
|
+
[
|
|
241
|
+
'start',
|
|
242
|
+
'send',
|
|
243
|
+
'config',
|
|
244
|
+
'rename',
|
|
245
|
+
'schedule.create',
|
|
246
|
+
'schedule.update',
|
|
247
|
+
'stop',
|
|
248
|
+
'goal.set',
|
|
249
|
+
'goal.clear'
|
|
250
|
+
].includes(args.action) &&
|
|
193
251
|
['MARCTL_REQUEST_TIMEOUT', 'MARCTL_SERVER_UNREACHABLE', 'MARCTL_RESPONSE_INVALID'].includes(
|
|
194
252
|
error.code
|
|
195
253
|
)
|