ticlawk 0.1.16-dev.9 → 0.1.17-dev.1
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/README.md +17 -3
- package/bin/ticlawk.mjs +255 -21
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +350 -50
- package/src/adapters/ticlawk/credentials.mjs +41 -1
- package/src/adapters/ticlawk/index.mjs +248 -130
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +715 -18
- package/src/core/agent-cli-handlers.mjs +556 -18
- package/src/core/agent-home.mjs +81 -1
- package/src/core/argv.mjs +11 -1
- package/src/core/events/worker-events.mjs +32 -36
- package/src/core/http.mjs +152 -0
- package/src/core/runtime-contract.mjs +0 -1
- package/src/core/runtime-env.mjs +7 -0
- package/src/core/runtime-support.mjs +130 -78
- package/src/runtimes/_shared/agent-handbook.mjs +45 -0
- package/src/runtimes/_shared/brand.mjs +2 -0
- package/src/runtimes/_shared/goal-step-prompt.mjs +98 -0
- package/src/runtimes/_shared/goal-task-protocol.mjs +50 -0
- package/src/runtimes/_shared/handbook/BASICS.md +27 -0
- package/src/runtimes/_shared/handbook/COLLABORATION.md +37 -0
- package/src/runtimes/_shared/handbook/COMMUNICATION.md +55 -0
- package/src/runtimes/_shared/handbook/DM_SCOPE.md +13 -0
- package/src/runtimes/_shared/handbook/GOAL_AUTHORITY.md +47 -0
- package/src/runtimes/_shared/handbook/GOAL_TASK_CORE.md +43 -0
- package/src/runtimes/_shared/handbook/GROUP_ADMIN_SCOPE.md +21 -0
- package/src/runtimes/_shared/handbook/GROUP_MEMBER_SCOPE.md +15 -0
- package/src/runtimes/_shared/handbook/SURFACES.md +41 -0
- package/src/runtimes/_shared/handbook/TASK_WORKER.md +14 -0
- package/src/runtimes/_shared/standing-prompt.mjs +124 -279
- package/src/runtimes/_shared/wake-prompt.mjs +268 -0
- package/src/runtimes/claude-code/index.mjs +19 -46
- package/src/runtimes/claude-code/session.mjs +2 -7
- package/src/runtimes/codex/index.mjs +115 -63
- package/src/runtimes/codex/session.mjs +2 -12
- package/src/runtimes/openclaw/index.mjs +11 -24
- package/src/runtimes/opencode/index.mjs +38 -60
- package/src/runtimes/opencode/session.mjs +12 -12
- package/src/runtimes/pi/index.mjs +38 -60
- package/src/runtimes/pi/session.mjs +9 -6
- package/ticlawk.mjs +0 -30
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
* the ticlawk backend.
|
|
9
9
|
*
|
|
10
10
|
* Commands:
|
|
11
|
-
* ticlawk message send --target <t> [--seen-up-to-seq N] [--reply-to <msg>]
|
|
11
|
+
* ticlawk message send --target <t> [--phase progress|final] [--seen-up-to-seq N] [--reply-to <msg>]
|
|
12
12
|
* ticlawk message read --target <t> [--around <msg>] [--limit N]
|
|
13
|
+
* ticlawk task create --target <t> [--title <t>] [--assign-agent <id>]
|
|
13
14
|
* ticlawk task claim --message-id <id> [--lease-seconds N]
|
|
14
15
|
* ticlawk task update --task-id <id> --status <s>
|
|
15
|
-
* ticlawk task list [--target <t>]
|
|
16
|
+
* ticlawk task list [--target <t>] # group admins see the full task board
|
|
17
|
+
* ticlawk charter get/set --target <t>
|
|
16
18
|
* ticlawk group members --target <t>
|
|
17
19
|
* ticlawk server info [--refresh]
|
|
18
20
|
*
|
|
@@ -41,6 +43,9 @@ function requireAgentEnv() {
|
|
|
41
43
|
agentId,
|
|
42
44
|
hostId: String(process.env.TICLAWK_RUNTIME_HOST_ID || '').trim() || null,
|
|
43
45
|
sessionId: String(process.env.TICLAWK_RUNTIME_SESSION_ID || '').trim() || null,
|
|
46
|
+
currentConversationId: String(process.env.TICLAWK_RUNTIME_CONVERSATION_ID || '').trim() || null,
|
|
47
|
+
currentMessageId: String(process.env.TICLAWK_RUNTIME_MESSAGE_ID || '').trim() || null,
|
|
48
|
+
currentTarget: String(process.env.TICLAWK_RUNTIME_TARGET || '').trim() || null,
|
|
44
49
|
};
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -51,6 +56,11 @@ function commonHeaders(env) {
|
|
|
51
56
|
};
|
|
52
57
|
if (env.hostId) headers['X-Ticlawk-Runtime-Host-Id'] = env.hostId;
|
|
53
58
|
if (env.sessionId) headers['X-Ticlawk-Runtime-Session-Id'] = env.sessionId;
|
|
59
|
+
if (env.currentConversationId) headers['X-Ticlawk-Current-Conversation-Id'] = env.currentConversationId;
|
|
60
|
+
if (env.currentMessageId) headers['X-Ticlawk-Current-Message-Id'] = env.currentMessageId;
|
|
61
|
+
if (env.currentTarget && /^[\x00-\x7F]*$/.test(env.currentTarget)) {
|
|
62
|
+
headers['X-Ticlawk-Current-Target'] = env.currentTarget;
|
|
63
|
+
}
|
|
54
64
|
return headers;
|
|
55
65
|
}
|
|
56
66
|
|
|
@@ -104,6 +114,14 @@ function getNumberArg(args, name) {
|
|
|
104
114
|
return Number.isFinite(n) ? n : null;
|
|
105
115
|
}
|
|
106
116
|
|
|
117
|
+
function getMessagePhaseArg(args) {
|
|
118
|
+
const raw = getArg(args, 'phase');
|
|
119
|
+
if (raw == null) return null;
|
|
120
|
+
const phase = raw.trim().toLowerCase();
|
|
121
|
+
if (phase === 'progress' || phase === 'final') return phase;
|
|
122
|
+
return { error: '--phase must be progress or final' };
|
|
123
|
+
}
|
|
124
|
+
|
|
107
125
|
function printJson(value) {
|
|
108
126
|
console.log(JSON.stringify(value, null, 2));
|
|
109
127
|
}
|
|
@@ -160,13 +178,28 @@ export async function runMessageSendCommand(args) {
|
|
|
160
178
|
mediaAssetIds.push(upload.assetId);
|
|
161
179
|
}
|
|
162
180
|
|
|
181
|
+
// Optional metadata flags. --kind classifies the message; --phase
|
|
182
|
+
// marks whether this is an intermediate progress update or the final
|
|
183
|
+
// visible response for the current turn.
|
|
184
|
+
const kind = getArg(args, 'kind');
|
|
185
|
+
const phase = getMessagePhaseArg(args);
|
|
186
|
+
if (phase && typeof phase === 'object') {
|
|
187
|
+
console.error(phase.error);
|
|
188
|
+
return 2;
|
|
189
|
+
}
|
|
190
|
+
const metadata = {};
|
|
191
|
+
if (kind) metadata.kind = kind;
|
|
192
|
+
if (phase) metadata.agent_response_phase = phase;
|
|
193
|
+
|
|
163
194
|
const body = {
|
|
164
195
|
target,
|
|
165
196
|
conversation_id: conversationId,
|
|
166
197
|
text: text.replace(/\n+$/, ''),
|
|
167
198
|
seen_up_to_seq: getNumberArg(args, 'seen-up-to-seq'),
|
|
168
199
|
reply_to_message_id: getArg(args, 'reply-to'),
|
|
200
|
+
allow_cross_target: Boolean(args['allow-cross-target']),
|
|
169
201
|
media_asset_ids: mediaAssetIds.length > 0 ? mediaAssetIds : undefined,
|
|
202
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
170
203
|
};
|
|
171
204
|
const res = await daemonRequest({
|
|
172
205
|
method: 'POST',
|
|
@@ -217,7 +250,7 @@ export async function runTaskCreateCommand(args) {
|
|
|
217
250
|
if (!text || !text.trim()) {
|
|
218
251
|
console.error('task body is required on stdin');
|
|
219
252
|
console.error('Example:');
|
|
220
|
-
console.error(" ticlawk task create --target \"#frontend\" --title \"fix login\" <<'EOF'");
|
|
253
|
+
console.error(" ticlawk task create --target \"#frontend\" --title \"fix login\" --assign-agent <agent-id> <<'EOF'");
|
|
221
254
|
console.error(' Detailed description goes here.');
|
|
222
255
|
console.error(' EOF');
|
|
223
256
|
return 2;
|
|
@@ -231,6 +264,7 @@ export async function runTaskCreateCommand(args) {
|
|
|
231
264
|
conversation_id: conversationId,
|
|
232
265
|
text: text.replace(/\n+$/, ''),
|
|
233
266
|
title: getArg(args, 'title'),
|
|
267
|
+
assign_agent_id: getArg(args, 'assign-agent') || getArg(args, 'assignee-agent'),
|
|
234
268
|
},
|
|
235
269
|
});
|
|
236
270
|
printJson(res.body);
|
|
@@ -310,6 +344,137 @@ export async function runTaskUpdateCommand(args) {
|
|
|
310
344
|
return exitFromStatus(res.statusCode);
|
|
311
345
|
}
|
|
312
346
|
|
|
347
|
+
const GOAL_OUTCOMES = [
|
|
348
|
+
'gap', 'no_gap', 'wait',
|
|
349
|
+
'task_completed', 'needs_approval', 'blocked',
|
|
350
|
+
'accepted', 'rejected',
|
|
351
|
+
];
|
|
352
|
+
|
|
353
|
+
export async function runGoalReportCommand(args) {
|
|
354
|
+
const env = requireAgentEnv();
|
|
355
|
+
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
356
|
+
const transitionId = getArg(args, 'transition') || getArg(args, 'transition-id');
|
|
357
|
+
const outcome = getArg(args, 'outcome');
|
|
358
|
+
if (!conversationId) {
|
|
359
|
+
console.error('--conversation is required');
|
|
360
|
+
return 2;
|
|
361
|
+
}
|
|
362
|
+
if (!transitionId) {
|
|
363
|
+
console.error('--transition is required');
|
|
364
|
+
return 2;
|
|
365
|
+
}
|
|
366
|
+
if (!outcome || !GOAL_OUTCOMES.includes(outcome)) {
|
|
367
|
+
console.error(`--outcome must be one of: ${GOAL_OUTCOMES.join(', ')}`);
|
|
368
|
+
return 2;
|
|
369
|
+
}
|
|
370
|
+
const res = await daemonRequest({
|
|
371
|
+
method: 'POST',
|
|
372
|
+
path: '/agent/goal/report',
|
|
373
|
+
headers: commonHeaders(env),
|
|
374
|
+
body: {
|
|
375
|
+
conversation_id: conversationId,
|
|
376
|
+
transition_id: transitionId,
|
|
377
|
+
outcome,
|
|
378
|
+
detail: getArg(args, 'detail'),
|
|
379
|
+
current_task_id: getArg(args, 'current-task') || getArg(args, 'task-id'),
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
printJson(res.body);
|
|
383
|
+
return exitFromStatus(res.statusCode);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export async function runGoalChangedCommand(args) {
|
|
387
|
+
const env = requireAgentEnv();
|
|
388
|
+
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
389
|
+
if (!conversationId) {
|
|
390
|
+
console.error('--conversation is required');
|
|
391
|
+
return 2;
|
|
392
|
+
}
|
|
393
|
+
const res = await daemonRequest({
|
|
394
|
+
method: 'POST',
|
|
395
|
+
path: '/agent/goal/changed',
|
|
396
|
+
headers: commonHeaders(env),
|
|
397
|
+
body: { conversation_id: conversationId },
|
|
398
|
+
});
|
|
399
|
+
printJson(res.body);
|
|
400
|
+
return exitFromStatus(res.statusCode);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export async function runApprovalRequestCommand(args) {
|
|
404
|
+
const env = requireAgentEnv();
|
|
405
|
+
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
406
|
+
const title = getArg(args, 'title');
|
|
407
|
+
if (!conversationId) {
|
|
408
|
+
console.error('--conversation is required');
|
|
409
|
+
return 2;
|
|
410
|
+
}
|
|
411
|
+
if (!title) {
|
|
412
|
+
console.error('--title is required');
|
|
413
|
+
return 2;
|
|
414
|
+
}
|
|
415
|
+
const ttlRaw = getArg(args, 'ttl-seconds');
|
|
416
|
+
const res = await daemonRequest({
|
|
417
|
+
method: 'POST',
|
|
418
|
+
path: '/agent/approval/request',
|
|
419
|
+
headers: commonHeaders(env),
|
|
420
|
+
body: {
|
|
421
|
+
conversation_id: conversationId,
|
|
422
|
+
title,
|
|
423
|
+
detail: getArg(args, 'detail'),
|
|
424
|
+
ttl_seconds: ttlRaw != null ? Number(ttlRaw) : undefined,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
printJson(res.body);
|
|
428
|
+
return exitFromStatus(res.statusCode);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export async function runApprovalResolveCommand(args) {
|
|
432
|
+
const env = requireAgentEnv();
|
|
433
|
+
const requestId = getArg(args, 'request') || getArg(args, 'request-id');
|
|
434
|
+
let decision = getArg(args, 'decision');
|
|
435
|
+
if (args.grant) decision = 'granted';
|
|
436
|
+
if (args.reject) decision = 'rejected';
|
|
437
|
+
if (!requestId) {
|
|
438
|
+
console.error('--request is required');
|
|
439
|
+
return 2;
|
|
440
|
+
}
|
|
441
|
+
if (decision !== 'granted' && decision !== 'rejected') {
|
|
442
|
+
console.error('--decision must be granted or rejected (or use --grant / --reject)');
|
|
443
|
+
return 2;
|
|
444
|
+
}
|
|
445
|
+
const confidenceRaw = getArg(args, 'confidence');
|
|
446
|
+
const res = await daemonRequest({
|
|
447
|
+
method: 'POST',
|
|
448
|
+
path: '/agent/approval/resolve',
|
|
449
|
+
headers: commonHeaders(env),
|
|
450
|
+
body: {
|
|
451
|
+
request_id: requestId,
|
|
452
|
+
decision,
|
|
453
|
+
original_text: getArg(args, 'original-text'),
|
|
454
|
+
confidence: confidenceRaw != null ? Number(confidenceRaw) : undefined,
|
|
455
|
+
source_message_id: getArg(args, 'source-message-id'),
|
|
456
|
+
},
|
|
457
|
+
});
|
|
458
|
+
printJson(res.body);
|
|
459
|
+
return exitFromStatus(res.statusCode);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export async function runApprovalListCommand(args) {
|
|
463
|
+
const env = requireAgentEnv();
|
|
464
|
+
const params = new URLSearchParams();
|
|
465
|
+
const target = getArg(args, 'target');
|
|
466
|
+
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
467
|
+
if (target) params.set('target', target);
|
|
468
|
+
if (conversationId) params.set('conversation_id', conversationId);
|
|
469
|
+
const res = await daemonRequest({
|
|
470
|
+
method: 'GET',
|
|
471
|
+
path: `/agent/approval/list?${params}`,
|
|
472
|
+
headers: commonHeaders(env),
|
|
473
|
+
});
|
|
474
|
+
printJson(res.body);
|
|
475
|
+
return exitFromStatus(res.statusCode);
|
|
476
|
+
}
|
|
477
|
+
|
|
313
478
|
export async function runMessageReactCommand(args) {
|
|
314
479
|
const env = requireAgentEnv();
|
|
315
480
|
const messageId = getArg(args, 'message-id');
|
|
@@ -654,6 +819,11 @@ function inferContentType(filePath) {
|
|
|
654
819
|
case '.jpg': case '.jpeg': return 'image/jpeg';
|
|
655
820
|
case '.gif': return 'image/gif';
|
|
656
821
|
case '.webp': return 'image/webp';
|
|
822
|
+
case '.mp4': return 'video/mp4';
|
|
823
|
+
case '.mov': return 'video/quicktime';
|
|
824
|
+
case '.m4v': return 'video/x-m4v';
|
|
825
|
+
case '.webm': return 'video/webm';
|
|
826
|
+
case '.html': case '.htm': return 'text/html';
|
|
657
827
|
case '.pdf': return 'application/pdf';
|
|
658
828
|
case '.txt': return 'text/plain';
|
|
659
829
|
case '.md': return 'text/markdown';
|
|
@@ -800,6 +970,410 @@ export async function runGroupMembersCommand(args) {
|
|
|
800
970
|
return exitFromStatus(res.statusCode);
|
|
801
971
|
}
|
|
802
972
|
|
|
973
|
+
export async function runWorkstreamCreateCommand(args) {
|
|
974
|
+
const env = requireAgentEnv();
|
|
975
|
+
const name = getArg(args, 'name');
|
|
976
|
+
if (!name) { console.error('--name is required'); return 2; }
|
|
977
|
+
const description = getArg(args, 'description');
|
|
978
|
+
const memberArgs = args.member;
|
|
979
|
+
const memberAgentIds = Array.isArray(memberArgs)
|
|
980
|
+
? memberArgs
|
|
981
|
+
: memberArgs ? [memberArgs] : [];
|
|
982
|
+
// Optional charter from stdin when --charter is supplied with no value
|
|
983
|
+
let charter = null;
|
|
984
|
+
if (args.charter === true) {
|
|
985
|
+
charter = await readStdin();
|
|
986
|
+
} else if (typeof args.charter === 'string') {
|
|
987
|
+
charter = args.charter;
|
|
988
|
+
}
|
|
989
|
+
const res = await daemonRequest({
|
|
990
|
+
method: 'POST',
|
|
991
|
+
path: '/agent/workstream/create',
|
|
992
|
+
headers: commonHeaders(env),
|
|
993
|
+
body: {
|
|
994
|
+
name,
|
|
995
|
+
description,
|
|
996
|
+
charter,
|
|
997
|
+
member_agent_ids: memberAgentIds.map((s) => String(s).trim()).filter(Boolean),
|
|
998
|
+
},
|
|
999
|
+
});
|
|
1000
|
+
printJson(res.body);
|
|
1001
|
+
return exitFromStatus(res.statusCode);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
export async function runWorkstreamDeleteCommand(args) {
|
|
1005
|
+
const env = requireAgentEnv();
|
|
1006
|
+
const target = getArg(args, 'target');
|
|
1007
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
1008
|
+
if (!target && !conversationId) {
|
|
1009
|
+
console.error('--target or --conversation-id is required');
|
|
1010
|
+
return 2;
|
|
1011
|
+
}
|
|
1012
|
+
const res = await daemonRequest({
|
|
1013
|
+
method: 'POST',
|
|
1014
|
+
path: '/agent/workstream/delete',
|
|
1015
|
+
headers: commonHeaders(env),
|
|
1016
|
+
body: { target, conversation_id: conversationId },
|
|
1017
|
+
});
|
|
1018
|
+
printJson(res.body);
|
|
1019
|
+
return exitFromStatus(res.statusCode);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
export async function runWorkstreamListCommand(args) {
|
|
1023
|
+
const env = requireAgentEnv();
|
|
1024
|
+
const res = await daemonRequest({
|
|
1025
|
+
method: 'GET',
|
|
1026
|
+
path: '/agent/workstream/list',
|
|
1027
|
+
headers: commonHeaders(env),
|
|
1028
|
+
});
|
|
1029
|
+
printJson(res.body);
|
|
1030
|
+
return exitFromStatus(res.statusCode);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
export async function runAgentListCommand(args) {
|
|
1034
|
+
const env = requireAgentEnv();
|
|
1035
|
+
const res = await daemonRequest({
|
|
1036
|
+
method: 'GET',
|
|
1037
|
+
path: '/agent/agent/list',
|
|
1038
|
+
headers: commonHeaders(env),
|
|
1039
|
+
});
|
|
1040
|
+
printJson(res.body);
|
|
1041
|
+
return exitFromStatus(res.statusCode);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
export async function runAgentCreateCommand(args) {
|
|
1045
|
+
const env = requireAgentEnv();
|
|
1046
|
+
const name = getArg(args, 'name');
|
|
1047
|
+
const runtime = getArg(args, 'runtime');
|
|
1048
|
+
if (!name) { console.error('--name is required'); return 2; }
|
|
1049
|
+
if (!runtime) { console.error('--runtime is required'); return 2; }
|
|
1050
|
+
const res = await daemonRequest({
|
|
1051
|
+
method: 'POST',
|
|
1052
|
+
path: '/agent/agent/create',
|
|
1053
|
+
headers: commonHeaders(env),
|
|
1054
|
+
body: {
|
|
1055
|
+
name,
|
|
1056
|
+
runtime,
|
|
1057
|
+
description: getArg(args, 'description'),
|
|
1058
|
+
display_name: getArg(args, 'display-name'),
|
|
1059
|
+
model: getArg(args, 'model'),
|
|
1060
|
+
},
|
|
1061
|
+
});
|
|
1062
|
+
printJson(res.body);
|
|
1063
|
+
return exitFromStatus(res.statusCode);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
export async function runAgentDeleteCommand(args) {
|
|
1067
|
+
const env = requireAgentEnv();
|
|
1068
|
+
const agentId = getArg(args, 'agent-id');
|
|
1069
|
+
if (!agentId) { console.error('--agent-id is required'); return 2; }
|
|
1070
|
+
const res = await daemonRequest({
|
|
1071
|
+
method: 'POST',
|
|
1072
|
+
path: '/agent/agent/delete',
|
|
1073
|
+
headers: commonHeaders(env),
|
|
1074
|
+
body: { agent_id: agentId },
|
|
1075
|
+
});
|
|
1076
|
+
printJson(res.body);
|
|
1077
|
+
return exitFromStatus(res.statusCode);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function readJsonFromFileOrInline(value) {
|
|
1081
|
+
if (!value) return null;
|
|
1082
|
+
// Accept either a path to a .json file or a raw JSON string.
|
|
1083
|
+
try {
|
|
1084
|
+
return JSON.parse(value);
|
|
1085
|
+
} catch {}
|
|
1086
|
+
try {
|
|
1087
|
+
const fs = require('node:fs');
|
|
1088
|
+
const txt = fs.readFileSync(value, 'utf8');
|
|
1089
|
+
return JSON.parse(txt);
|
|
1090
|
+
} catch (err) {
|
|
1091
|
+
throw new Error(`could not parse JSON from ${value}: ${err?.message || err}`);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
export async function runServiceCreateCommand(args) {
|
|
1096
|
+
const env = requireAgentEnv();
|
|
1097
|
+
const name = getArg(args, 'name');
|
|
1098
|
+
if (!name) { console.error('--name is required'); return 2; }
|
|
1099
|
+
const description = getArg(args, 'description');
|
|
1100
|
+
let contractSchema = null;
|
|
1101
|
+
let endpointConfig = null;
|
|
1102
|
+
try {
|
|
1103
|
+
const contractRaw = getArg(args, 'contract');
|
|
1104
|
+
if (contractRaw) contractSchema = readJsonFromFileOrInline(contractRaw);
|
|
1105
|
+
const endpointRaw = getArg(args, 'endpoint');
|
|
1106
|
+
if (endpointRaw) endpointConfig = readJsonFromFileOrInline(endpointRaw);
|
|
1107
|
+
} catch (err) {
|
|
1108
|
+
console.error(err.message);
|
|
1109
|
+
return 2;
|
|
1110
|
+
}
|
|
1111
|
+
if (!endpointConfig) { console.error('--endpoint <path-or-json> is required'); return 2; }
|
|
1112
|
+
const res = await daemonRequest({
|
|
1113
|
+
method: 'POST', path: '/agent/service/create',
|
|
1114
|
+
headers: commonHeaders(env),
|
|
1115
|
+
body: { name, description, contract_schema: contractSchema, endpoint_config: endpointConfig },
|
|
1116
|
+
});
|
|
1117
|
+
printJson(res.body);
|
|
1118
|
+
return exitFromStatus(res.statusCode);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
export async function runServiceUpdateCommand(args) {
|
|
1122
|
+
const env = requireAgentEnv();
|
|
1123
|
+
const serviceId = getArg(args, 'service-id');
|
|
1124
|
+
if (!serviceId) { console.error('--service-id is required'); return 2; }
|
|
1125
|
+
const body = { service_id: serviceId };
|
|
1126
|
+
if (getArg(args, 'description')) body.description = getArg(args, 'description');
|
|
1127
|
+
if (getArg(args, 'contract')) body.contract_schema = readJsonFromFileOrInline(getArg(args, 'contract'));
|
|
1128
|
+
if (getArg(args, 'endpoint')) body.endpoint_config = readJsonFromFileOrInline(getArg(args, 'endpoint'));
|
|
1129
|
+
if (getArg(args, 'status')) body.status = getArg(args, 'status');
|
|
1130
|
+
const res = await daemonRequest({
|
|
1131
|
+
method: 'POST', path: '/agent/service/update',
|
|
1132
|
+
headers: commonHeaders(env), body,
|
|
1133
|
+
});
|
|
1134
|
+
printJson(res.body);
|
|
1135
|
+
return exitFromStatus(res.statusCode);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
export async function runServiceDeleteCommand(args) {
|
|
1139
|
+
const env = requireAgentEnv();
|
|
1140
|
+
const serviceId = getArg(args, 'service-id');
|
|
1141
|
+
if (!serviceId) { console.error('--service-id is required'); return 2; }
|
|
1142
|
+
const res = await daemonRequest({
|
|
1143
|
+
method: 'POST', path: '/agent/service/delete',
|
|
1144
|
+
headers: commonHeaders(env),
|
|
1145
|
+
body: { service_id: serviceId },
|
|
1146
|
+
});
|
|
1147
|
+
printJson(res.body);
|
|
1148
|
+
return exitFromStatus(res.statusCode);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
export async function runServiceListCommand(args) {
|
|
1152
|
+
const env = requireAgentEnv();
|
|
1153
|
+
const res = await daemonRequest({
|
|
1154
|
+
method: 'GET', path: '/agent/service/list',
|
|
1155
|
+
headers: commonHeaders(env),
|
|
1156
|
+
});
|
|
1157
|
+
printJson(res.body);
|
|
1158
|
+
return exitFromStatus(res.statusCode);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
export async function runServiceInfoCommand(args) {
|
|
1162
|
+
const env = requireAgentEnv();
|
|
1163
|
+
const name = getArg(args, 'name');
|
|
1164
|
+
if (!name) { console.error('--name is required'); return 2; }
|
|
1165
|
+
const params = new URLSearchParams();
|
|
1166
|
+
params.set('name', name);
|
|
1167
|
+
const res = await daemonRequest({
|
|
1168
|
+
method: 'GET', path: `/agent/service/info?${params}`,
|
|
1169
|
+
headers: commonHeaders(env),
|
|
1170
|
+
});
|
|
1171
|
+
printJson(res.body);
|
|
1172
|
+
return exitFromStatus(res.statusCode);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
export async function runServiceCallCommand(args) {
|
|
1176
|
+
const env = requireAgentEnv();
|
|
1177
|
+
const name = getArg(args, 'name');
|
|
1178
|
+
if (!name) { console.error('--name is required'); return 2; }
|
|
1179
|
+
const inputText = await readStdin();
|
|
1180
|
+
let input = null;
|
|
1181
|
+
if (inputText && inputText.trim().length > 0) {
|
|
1182
|
+
try {
|
|
1183
|
+
input = JSON.parse(inputText);
|
|
1184
|
+
} catch (err) {
|
|
1185
|
+
console.error('stdin must be JSON for service call input');
|
|
1186
|
+
return 2;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
const res = await daemonRequest({
|
|
1190
|
+
method: 'POST', path: '/agent/service/call',
|
|
1191
|
+
headers: commonHeaders(env),
|
|
1192
|
+
body: { name, input },
|
|
1193
|
+
});
|
|
1194
|
+
printJson(res.body);
|
|
1195
|
+
return exitFromStatus(res.statusCode);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
export async function runBriefingGetCommand(args) {
|
|
1199
|
+
const env = requireAgentEnv();
|
|
1200
|
+
const id = args._[2] || getArg(args, 'id');
|
|
1201
|
+
if (!id) { console.error('briefing id required (positional or --id)'); return 2; }
|
|
1202
|
+
const params = new URLSearchParams();
|
|
1203
|
+
params.set('id', id);
|
|
1204
|
+
const res = await daemonRequest({
|
|
1205
|
+
method: 'GET',
|
|
1206
|
+
path: `/agent/briefing/get?${params}`,
|
|
1207
|
+
headers: commonHeaders(env),
|
|
1208
|
+
});
|
|
1209
|
+
printJson(res.body);
|
|
1210
|
+
return exitFromStatus(res.statusCode);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
export async function runBriefingPublishCommand(args) {
|
|
1214
|
+
const env = requireAgentEnv();
|
|
1215
|
+
const textArg = getArg(args, 'text');
|
|
1216
|
+
const attachPath = getArg(args, 'attach');
|
|
1217
|
+
const mode = String(getArg(args, 'mode') || 'info').trim().toLowerCase();
|
|
1218
|
+
if (!textArg) {
|
|
1219
|
+
console.error('--text "<short>" is required');
|
|
1220
|
+
return 2;
|
|
1221
|
+
}
|
|
1222
|
+
if (textArg.length > 140) {
|
|
1223
|
+
console.error('--text must be ≤140 chars');
|
|
1224
|
+
return 2;
|
|
1225
|
+
}
|
|
1226
|
+
if (!['info', 'approval'].includes(mode)) {
|
|
1227
|
+
console.error('--mode must be info or approval');
|
|
1228
|
+
return 2;
|
|
1229
|
+
}
|
|
1230
|
+
let attachmentAssetId = null;
|
|
1231
|
+
if (attachPath) {
|
|
1232
|
+
const contentType = inferContentType(String(attachPath));
|
|
1233
|
+
if (!contentType.startsWith('image/') && !contentType.startsWith('video/') && contentType !== 'text/html') {
|
|
1234
|
+
console.error('--attach must be an image, video, or HTML file');
|
|
1235
|
+
return 2;
|
|
1236
|
+
}
|
|
1237
|
+
const upload = await uploadFileViaDaemon(env, String(attachPath));
|
|
1238
|
+
if (!upload.ok) {
|
|
1239
|
+
console.error(`attachment upload failed for ${attachPath}: ${upload.error}`);
|
|
1240
|
+
return 1;
|
|
1241
|
+
}
|
|
1242
|
+
attachmentAssetId = upload.assetId;
|
|
1243
|
+
}
|
|
1244
|
+
const res = await daemonRequest({
|
|
1245
|
+
method: 'POST',
|
|
1246
|
+
path: '/agent/briefing/publish',
|
|
1247
|
+
headers: commonHeaders(env),
|
|
1248
|
+
body: {
|
|
1249
|
+
body_text: textArg,
|
|
1250
|
+
attachment_asset_id: attachmentAssetId,
|
|
1251
|
+
current_conversation_id: env.currentConversationId,
|
|
1252
|
+
response_mode: mode,
|
|
1253
|
+
},
|
|
1254
|
+
});
|
|
1255
|
+
printJson(res.body);
|
|
1256
|
+
return exitFromStatus(res.statusCode);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
export async function runCredentialRequestCommand(args) {
|
|
1260
|
+
const env = requireAgentEnv();
|
|
1261
|
+
const name = getArg(args, 'name');
|
|
1262
|
+
if (!name) { console.error('--name is required (e.g. GEMINI_API_KEY)'); return 2; }
|
|
1263
|
+
const description = getArg(args, 'description');
|
|
1264
|
+
const groupTarget = getArg(args, 'group') || getArg(args, 'workstream');
|
|
1265
|
+
const res = await daemonRequest({
|
|
1266
|
+
method: 'POST',
|
|
1267
|
+
path: '/agent/credential/request',
|
|
1268
|
+
headers: commonHeaders(env),
|
|
1269
|
+
body: {
|
|
1270
|
+
name,
|
|
1271
|
+
description,
|
|
1272
|
+
target: groupTarget,
|
|
1273
|
+
},
|
|
1274
|
+
});
|
|
1275
|
+
printJson(res.body);
|
|
1276
|
+
return exitFromStatus(res.statusCode);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
export async function runDashboardSetCommand(args) {
|
|
1280
|
+
const env = requireAgentEnv();
|
|
1281
|
+
const target = getArg(args, 'target');
|
|
1282
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
1283
|
+
if (!target && !conversationId) {
|
|
1284
|
+
console.error('--target or --conversation-id is required');
|
|
1285
|
+
return 2;
|
|
1286
|
+
}
|
|
1287
|
+
// Body is read from stdin as JSON: { data_json?, html_template? }
|
|
1288
|
+
const stdinText = await readStdin();
|
|
1289
|
+
let payload = {};
|
|
1290
|
+
if (stdinText && stdinText.trim().length > 0) {
|
|
1291
|
+
try {
|
|
1292
|
+
payload = JSON.parse(stdinText);
|
|
1293
|
+
} catch (err) {
|
|
1294
|
+
console.error('stdin must be JSON: { data_json?, html_template? }');
|
|
1295
|
+
return 2;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
const res = await daemonRequest({
|
|
1299
|
+
method: 'POST',
|
|
1300
|
+
path: '/agent/dashboard/set',
|
|
1301
|
+
headers: commonHeaders(env),
|
|
1302
|
+
body: {
|
|
1303
|
+
target,
|
|
1304
|
+
conversation_id: conversationId,
|
|
1305
|
+
...(('data_json' in payload) ? { data_json: payload.data_json } : {}),
|
|
1306
|
+
...(('html_template' in payload) ? { html_template: payload.html_template } : {}),
|
|
1307
|
+
},
|
|
1308
|
+
});
|
|
1309
|
+
printJson(res.body);
|
|
1310
|
+
return exitFromStatus(res.statusCode);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
export async function runDashboardGetCommand(args) {
|
|
1314
|
+
const env = requireAgentEnv();
|
|
1315
|
+
const target = getArg(args, 'target');
|
|
1316
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
1317
|
+
if (!target && !conversationId) {
|
|
1318
|
+
console.error('--target or --conversation-id is required');
|
|
1319
|
+
return 2;
|
|
1320
|
+
}
|
|
1321
|
+
const params = new URLSearchParams();
|
|
1322
|
+
if (target) params.set('target', target);
|
|
1323
|
+
if (conversationId) params.set('conversation_id', conversationId);
|
|
1324
|
+
const res = await daemonRequest({
|
|
1325
|
+
method: 'GET',
|
|
1326
|
+
path: `/agent/dashboard/get?${params}`,
|
|
1327
|
+
headers: commonHeaders(env),
|
|
1328
|
+
});
|
|
1329
|
+
printJson(res.body);
|
|
1330
|
+
return exitFromStatus(res.statusCode);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
export async function runWorkstreamCharterGetCommand(args) {
|
|
1334
|
+
const env = requireAgentEnv();
|
|
1335
|
+
const target = getArg(args, 'target');
|
|
1336
|
+
const conversationId = getArg(args, 'conversation-id') || env.currentConversationId;
|
|
1337
|
+
if (!target && !conversationId) {
|
|
1338
|
+
console.error('--target or --conversation-id is required outside a delivered conversation');
|
|
1339
|
+
return 2;
|
|
1340
|
+
}
|
|
1341
|
+
const params = new URLSearchParams();
|
|
1342
|
+
if (target) params.set('target', target);
|
|
1343
|
+
if (conversationId) params.set('conversation_id', conversationId);
|
|
1344
|
+
const res = await daemonRequest({
|
|
1345
|
+
method: 'GET',
|
|
1346
|
+
path: `/agent/workstream/charter/get?${params}`,
|
|
1347
|
+
headers: commonHeaders(env),
|
|
1348
|
+
});
|
|
1349
|
+
printJson(res.body);
|
|
1350
|
+
return exitFromStatus(res.statusCode);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
export async function runWorkstreamCharterSetCommand(args) {
|
|
1354
|
+
const env = requireAgentEnv();
|
|
1355
|
+
const target = getArg(args, 'target');
|
|
1356
|
+
const conversationId = getArg(args, 'conversation-id') || env.currentConversationId;
|
|
1357
|
+
if (!target && !conversationId) {
|
|
1358
|
+
console.error('--target or --conversation-id is required outside a delivered conversation');
|
|
1359
|
+
return 2;
|
|
1360
|
+
}
|
|
1361
|
+
// Body from stdin (heredoc / pipe). Empty input clears the charter.
|
|
1362
|
+
const charter = await readStdin();
|
|
1363
|
+
const res = await daemonRequest({
|
|
1364
|
+
method: 'POST',
|
|
1365
|
+
path: '/agent/workstream/charter/set',
|
|
1366
|
+
headers: commonHeaders(env),
|
|
1367
|
+
body: {
|
|
1368
|
+
target,
|
|
1369
|
+
conversation_id: conversationId,
|
|
1370
|
+
charter: charter ?? '',
|
|
1371
|
+
},
|
|
1372
|
+
});
|
|
1373
|
+
printJson(res.body);
|
|
1374
|
+
return exitFromStatus(res.statusCode);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
803
1377
|
export async function runServerInfoCommand(args) {
|
|
804
1378
|
const env = requireAgentEnv();
|
|
805
1379
|
const params = new URLSearchParams();
|
|
@@ -815,12 +1389,18 @@ export async function runServerInfoCommand(args) {
|
|
|
815
1389
|
|
|
816
1390
|
export const AGENT_COMMAND_HELP = {
|
|
817
1391
|
message: `ticlawk message <send|read|check|search|react>
|
|
818
|
-
ticlawk message send --target "<target>" [--seen-up-to-seq N] [--reply-to <msg-id>] [--attach <file> ...]
|
|
1392
|
+
ticlawk message send --target "<target>" [--phase progress|final] [--seen-up-to-seq N] [--reply-to <msg-id>] [--allow-cross-target] [--attach <file> ...] [--kind <kind>]
|
|
819
1393
|
Body is read from stdin (use <<'EOF' ... EOF for multiline).
|
|
1394
|
+
During a delivered turn, sending to a different conversation is blocked
|
|
1395
|
+
unless --allow-cross-target is passed deliberately.
|
|
1396
|
+
--phase progress|final tags whether this is an intermediate update or
|
|
1397
|
+
the final visible response after the current work/goal check is done.
|
|
1398
|
+
--kind <kind> tags this message via metadata.kind.
|
|
820
1399
|
Targets:
|
|
821
|
-
dm
|
|
822
|
-
|
|
823
|
-
#<group
|
|
1400
|
+
dm:<conversation-id> private message by conversation id
|
|
1401
|
+
dm:@<user> private message by user/agent handle
|
|
1402
|
+
#<group> group conversation by name or id
|
|
1403
|
+
#<group>:<msgid> replies under a top-level message in that group
|
|
824
1404
|
--attach <file> uploads a local file and attaches it to the message
|
|
825
1405
|
(repeatable; max 10 attachments per message).
|
|
826
1406
|
ticlawk message read --target "<target>" [--around <msg-id>] [--before-seq N] [--limit N]
|
|
@@ -832,7 +1412,11 @@ export const AGENT_COMMAND_HELP = {
|
|
|
832
1412
|
Use sparingly: prefer acknowledgement/follow-up signals like 👀. Do not
|
|
833
1413
|
auto-react to every merge, deploy, or task completion with celebratory emoji.
|
|
834
1414
|
`,
|
|
835
|
-
profile: `ticlawk profile <show|update>
|
|
1415
|
+
profile: `ticlawk profile <list|current|use|show|update>
|
|
1416
|
+
ticlawk profile list
|
|
1417
|
+
ticlawk profile current
|
|
1418
|
+
ticlawk profile use ticlawk:<user-id>
|
|
1419
|
+
|
|
836
1420
|
ticlawk profile show [@handle | --id <agent-id>]
|
|
837
1421
|
ticlawk profile update [--display-name X] [--description Y] [--avatar-file path]
|
|
838
1422
|
`,
|
|
@@ -853,23 +1437,136 @@ export const AGENT_COMMAND_HELP = {
|
|
|
853
1437
|
conversation and waking the owner agent via an explicit delivery.
|
|
854
1438
|
`,
|
|
855
1439
|
task: `ticlawk task <create|claim|unclaim|update|list>
|
|
856
|
-
ticlawk task create --target "<target>" [--title <t>]
|
|
857
|
-
Body is read from stdin. Creates a brand-new
|
|
858
|
-
|
|
1440
|
+
ticlawk task create --target "<target>" [--title <t>] [--assign-agent <agent-id>]
|
|
1441
|
+
Body is read from stdin. Creates a brand-new group task. Group admins
|
|
1442
|
+
may assign it immediately to an agent member with --assign-agent.
|
|
859
1443
|
ticlawk task claim --message-id <id> [--lease-seconds N]
|
|
860
1444
|
ticlawk task claim --number <N> --target "<target>" [--lease-seconds N]
|
|
861
1445
|
ticlawk task unclaim --task-id <id>
|
|
862
1446
|
ticlawk task update --task-id <id> --status <todo|in_progress|in_review|done|canceled>
|
|
863
|
-
|
|
1447
|
+
Only a group admin can set status=done. Other agents should set
|
|
1448
|
+
in_review and let the group's admin finalize. A group admin can also
|
|
1449
|
+
reopen another agent's in_review task to in_progress for redo.
|
|
1450
|
+
ticlawk task list [--target <target>|--conversation-id <id>]
|
|
1451
|
+
Default view is open tasks plus tasks owned by the caller. When the
|
|
1452
|
+
caller is a group admin and --target/--conversation-id scopes the
|
|
1453
|
+
request to that group, the list shows the full task board, including
|
|
1454
|
+
other agents' in_progress, in_review, and done tasks.
|
|
1455
|
+
`,
|
|
1456
|
+
workstream: `ticlawk workstream <create|delete|list|charter>
|
|
1457
|
+
Compatibility alias for group admin commands. Prefer \`ticlawk group ...\`
|
|
1458
|
+
for groups and \`ticlawk charter ...\` for conversation charters.
|
|
1459
|
+
`,
|
|
1460
|
+
goal: `ticlawk goal <report|changed>
|
|
1461
|
+
Goal-lane (FSM) control. Normally invoked from a goal-step turn, not by hand.
|
|
1462
|
+
ticlawk goal report --transition <id> --outcome <outcome> [--conversation <id>] [--detail <text>] [--current-task <task-id>]
|
|
1463
|
+
Report the outcome of the current FSM step and advance the state machine.
|
|
1464
|
+
--conversation defaults to the current goal-turn conversation.
|
|
1465
|
+
Outcomes by step:
|
|
1466
|
+
gap_analysis: gap | no_gap | wait
|
|
1467
|
+
execute: task_completed | needs_approval | blocked
|
|
1468
|
+
review: accepted | rejected
|
|
1469
|
+
ticlawk goal changed [--conversation <id>]
|
|
1470
|
+
Signal that the conversation's goal changed; wakes the FSM into gap analysis.
|
|
1471
|
+
`,
|
|
1472
|
+
approval: `ticlawk approval <request|resolve|list>
|
|
1473
|
+
Canonical goal-loop approval flow. The goal lane parks on an approval and is
|
|
1474
|
+
resumed by exactly one idempotent decision (button token OR chat resolver).
|
|
1475
|
+
ticlawk approval request --title "<text>" [--conversation <id>] [--detail <text>] [--ttl-seconds <n>]
|
|
1476
|
+
Park a pending owner approval on the goal_session (after EXECUTE reports
|
|
1477
|
+
needs_approval). Returns request_id plus a one-time button action token.
|
|
1478
|
+
--conversation defaults to the current goal-turn conversation.
|
|
1479
|
+
ticlawk approval list [--conversation <id> | --target "<target>"]
|
|
1480
|
+
List pending approval requests in the conversation. Use this from the chat
|
|
1481
|
+
lane to find which request an owner's natural-language approval refers to.
|
|
1482
|
+
--conversation defaults to the current conversation.
|
|
1483
|
+
ticlawk approval resolve --request <id> (--grant | --reject | --decision granted|rejected) [--original-text <text>] [--confidence <0-1>] [--source-message-id <id>]
|
|
1484
|
+
Resolve a pending approval from a natural-language chat decision (source=chat).
|
|
1485
|
+
Idempotent: a second resolve (or a button tap) on the same request is a no-op.
|
|
1486
|
+
`,
|
|
1487
|
+
charter: `ticlawk charter <get|set> [--target "<target>" | --conversation-id <id>]
|
|
1488
|
+
ticlawk charter get [--target "<target>" | --conversation-id <id>]
|
|
1489
|
+
Print the conversation charter. DM/group members can read.
|
|
1490
|
+
ticlawk charter set [--target "<target>" | --conversation-id <id>] # body via stdin
|
|
1491
|
+
Replace the conversation charter. DM member agents can write their DM
|
|
1492
|
+
charter; group writes require group admin/owner. Empty stdin clears it.
|
|
1493
|
+
During a delivered turn, omitting target/conversation-id uses the
|
|
1494
|
+
current conversation.
|
|
1495
|
+
`,
|
|
1496
|
+
service: `ticlawk service <create|update|delete|list|info|call>
|
|
1497
|
+
service create --name X --endpoint <path-or-json> [--description Y] [--contract <path-or-json>]
|
|
1498
|
+
Any agent. Register a callable service. --endpoint takes either a
|
|
1499
|
+
.json file path or a JSON string; same for --contract.
|
|
1500
|
+
endpoint_config shape: { url, method?, headers? }.
|
|
1501
|
+
service update --service-id <id> [--description Y] [--contract <json>] [--endpoint <json>] [--status <active|down|archived>]
|
|
1502
|
+
Any agent.
|
|
1503
|
+
service delete --service-id <id>
|
|
1504
|
+
Any agent. Soft-archives.
|
|
1505
|
+
service list
|
|
1506
|
+
Any agent. Returns active services (no endpoint_config).
|
|
1507
|
+
service info --name X
|
|
1508
|
+
Any agent. Returns contract_schema + description.
|
|
1509
|
+
service call --name X # input from stdin (JSON)
|
|
1510
|
+
Any agent. Backend proxies to endpoint_config.url. No retry.
|
|
1511
|
+
`,
|
|
1512
|
+
briefing: `ticlawk briefing <publish|get>
|
|
1513
|
+
briefing publish --text "..." [--mode info|approval] [--attach <image|video|html path>]
|
|
1514
|
+
Publish a briefing to the owner's Briefings. Allowed from DMs, or
|
|
1515
|
+
from groups where this agent is admin/owner.
|
|
1516
|
+
--text short plain text (≤140 chars)
|
|
1517
|
+
--mode owner response mode: info shows ack; approval shows approve
|
|
1518
|
+
--attach optional image, video, or HTML file when visual context matters
|
|
1519
|
+
Briefings are independent of chat — they do NOT appear in any DM
|
|
1520
|
+
message stream. Use this verb (not \`message send\`) for any status
|
|
1521
|
+
surface the owner consumes in Briefings.
|
|
1522
|
+
briefing get <id>
|
|
1523
|
+
Fetch a briefing including text and attachment metadata. Use this when a
|
|
1524
|
+
quote (metadata.quote.kind=briefing) points at a briefing whose
|
|
1525
|
+
full body you want to read.
|
|
1526
|
+
`,
|
|
1527
|
+
credential: `ticlawk credential request --name <ENV_VAR> [--description Y] [--group "#<group>"]
|
|
1528
|
+
Any agent. Pre-allocate a credential slot. Response includes a deep
|
|
1529
|
+
link the user opens in the mobile app (Settings → Credentials)
|
|
1530
|
+
to fill the value. Once filled, the daemon syncs it locally and
|
|
1531
|
+
injects it as an env var when spawning agents.
|
|
1532
|
+
`,
|
|
1533
|
+
dashboard: `ticlawk dashboard <set|get> (--target "<target>" | --conversation-id <id>)
|
|
1534
|
+
dashboard set (--target "<target>" | --conversation-id <id>) # body via stdin (JSON)
|
|
1535
|
+
Allowed from DMs, or from groups where this agent is admin/owner.
|
|
1536
|
+
stdin = { "data_json": ..., "html_template": "..." }.
|
|
1537
|
+
Either field may be omitted (leaves unchanged) or null (clears).
|
|
1538
|
+
dashboard get (--target "<target>" | --conversation-id <id>)
|
|
1539
|
+
Conversation members can read.
|
|
1540
|
+
`,
|
|
1541
|
+
agent: `ticlawk agent <list|create|delete>
|
|
1542
|
+
agent list
|
|
1543
|
+
Any agent. List all non-archived agents owned by the user, including
|
|
1544
|
+
descriptions, runtime/status, and group memberships.
|
|
1545
|
+
agent create --name X --runtime <claude_code|codex|opencode|openclaw|pi> [--description Y] [--display-name N] [--model M]
|
|
1546
|
+
Any agent. Pre-allocate an agent slot (status='unpaired'). User
|
|
1547
|
+
later pairs a runtime to fill it.
|
|
1548
|
+
agent delete --agent-id <id>
|
|
1549
|
+
Owner-only. Agent-facing deletion is disabled.
|
|
864
1550
|
`,
|
|
865
|
-
group: `ticlawk group <create|members>
|
|
1551
|
+
group: `ticlawk group <create|list|delete|charter|members>
|
|
866
1552
|
ticlawk group create --name <n> [--description <d>] [--member <agent-id> ...]
|
|
867
|
-
Agent self-creates a new group. The agent is added as
|
|
1553
|
+
Agent self-creates a new group. The agent is added as admin; the
|
|
868
1554
|
conversation owner is set to the user that owns this agent. Other
|
|
869
|
-
member agents must belong to the same user
|
|
870
|
-
|
|
871
|
-
ticlawk group
|
|
872
|
-
|
|
1555
|
+
member agents join as regular members and must belong to the same user
|
|
1556
|
+
(RLS enforces).
|
|
1557
|
+
ticlawk group list
|
|
1558
|
+
List group conversations the caller belongs to, including agent members,
|
|
1559
|
+
descriptions, charters, and dashboard presence.
|
|
1560
|
+
ticlawk group delete --target "#<group>"
|
|
1561
|
+
Group-admin only. Hard-delete the group (messages, members, deliveries).
|
|
1562
|
+
ticlawk group charter get (--target "#<group>" | --conversation-id <id>)
|
|
1563
|
+
Compatibility alias for \`ticlawk charter get\` on groups.
|
|
1564
|
+
ticlawk group charter set (--target "#<group>" | --conversation-id <id>) # body via stdin
|
|
1565
|
+
Compatibility alias for \`ticlawk charter set\` on groups. Group-admin only.
|
|
1566
|
+
ticlawk group members (--target "<target>" | --conversation-id <id>)
|
|
1567
|
+
ticlawk group members (--target "<target>" | --conversation-id <id>) --add <agent-id> [--add <agent-id> ...]
|
|
1568
|
+
ticlawk group members (--target "<target>" | --conversation-id <id>) --remove <agent-id>
|
|
1569
|
+
Listing requires membership; add/remove requires group admin.
|
|
873
1570
|
`,
|
|
874
1571
|
server: `ticlawk server info [--refresh]
|
|
875
1572
|
`,
|