ticlawk 0.1.17-dev.17 → 0.1.17-dev.19
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 +3 -17
- package/bin/ticlawk.mjs +21 -245
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +51 -327
- package/src/adapters/ticlawk/credentials.mjs +1 -41
- package/src/adapters/ticlawk/index.mjs +27 -249
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +22 -703
- package/src/core/agent-cli-handlers.mjs +18 -519
- package/src/core/agent-home.mjs +1 -64
- package/src/core/events/worker-events.mjs +36 -32
- package/src/core/http.mjs +0 -138
- package/src/core/runtime-contract.mjs +1 -0
- package/src/core/runtime-env.mjs +0 -7
- package/src/core/runtime-support.mjs +78 -130
- package/src/runtimes/_shared/incoming-message-prompt.mjs +232 -0
- package/src/runtimes/_shared/runtime-base-instructions.mjs +34 -0
- package/src/runtimes/claude-code/index.mjs +48 -21
- package/src/runtimes/claude-code/session.mjs +7 -2
- package/src/runtimes/codex/index.mjs +64 -116
- package/src/runtimes/codex/session.mjs +12 -2
- package/src/runtimes/openclaw/index.mjs +30 -17
- package/src/runtimes/opencode/index.mjs +64 -42
- package/src/runtimes/opencode/session.mjs +14 -14
- package/src/runtimes/pi/index.mjs +64 -42
- package/src/runtimes/pi/session.mjs +8 -11
- package/ticlawk.mjs +30 -0
- package/src/runtimes/_shared/agent-handbook.mjs +0 -38
- package/src/runtimes/_shared/brand.mjs +0 -2
- package/src/runtimes/_shared/goal-step-prompt.mjs +0 -133
- package/src/runtimes/_shared/goal-task-protocol.mjs +0 -50
- package/src/runtimes/_shared/standing-prompt.mjs +0 -331
- package/src/runtimes/_shared/wake-prompt.mjs +0 -296
|
@@ -8,13 +8,11 @@
|
|
|
8
8
|
* the ticlawk backend.
|
|
9
9
|
*
|
|
10
10
|
* Commands:
|
|
11
|
-
* ticlawk message send --target <t> [--
|
|
11
|
+
* ticlawk message send --target <t> [--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>]
|
|
14
13
|
* ticlawk task claim --message-id <id> [--lease-seconds N]
|
|
15
14
|
* ticlawk task update --task-id <id> --status <s>
|
|
16
|
-
* ticlawk task list [--target <t>]
|
|
17
|
-
* ticlawk charter get/set --target <t>
|
|
15
|
+
* ticlawk task list [--target <t>]
|
|
18
16
|
* ticlawk group members --target <t>
|
|
19
17
|
* ticlawk server info [--refresh]
|
|
20
18
|
*
|
|
@@ -43,9 +41,6 @@ function requireAgentEnv() {
|
|
|
43
41
|
agentId,
|
|
44
42
|
hostId: String(process.env.TICLAWK_RUNTIME_HOST_ID || '').trim() || null,
|
|
45
43
|
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,
|
|
49
44
|
};
|
|
50
45
|
}
|
|
51
46
|
|
|
@@ -56,11 +51,6 @@ function commonHeaders(env) {
|
|
|
56
51
|
};
|
|
57
52
|
if (env.hostId) headers['X-Ticlawk-Runtime-Host-Id'] = env.hostId;
|
|
58
53
|
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
|
-
}
|
|
64
54
|
return headers;
|
|
65
55
|
}
|
|
66
56
|
|
|
@@ -114,14 +104,6 @@ function getNumberArg(args, name) {
|
|
|
114
104
|
return Number.isFinite(n) ? n : null;
|
|
115
105
|
}
|
|
116
106
|
|
|
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
|
-
|
|
125
107
|
function printJson(value) {
|
|
126
108
|
console.log(JSON.stringify(value, null, 2));
|
|
127
109
|
}
|
|
@@ -178,28 +160,13 @@ export async function runMessageSendCommand(args) {
|
|
|
178
160
|
mediaAssetIds.push(upload.assetId);
|
|
179
161
|
}
|
|
180
162
|
|
|
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
|
-
|
|
194
163
|
const body = {
|
|
195
164
|
target,
|
|
196
165
|
conversation_id: conversationId,
|
|
197
166
|
text: text.replace(/\n+$/, ''),
|
|
198
167
|
seen_up_to_seq: getNumberArg(args, 'seen-up-to-seq'),
|
|
199
168
|
reply_to_message_id: getArg(args, 'reply-to'),
|
|
200
|
-
allow_cross_target: Boolean(args['allow-cross-target']),
|
|
201
169
|
media_asset_ids: mediaAssetIds.length > 0 ? mediaAssetIds : undefined,
|
|
202
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
203
170
|
};
|
|
204
171
|
const res = await daemonRequest({
|
|
205
172
|
method: 'POST',
|
|
@@ -241,9 +208,7 @@ export async function runMessageReadCommand(args) {
|
|
|
241
208
|
export async function runTaskCreateCommand(args) {
|
|
242
209
|
const env = requireAgentEnv();
|
|
243
210
|
const target = getArg(args, 'target');
|
|
244
|
-
|
|
245
|
-
// Lets a goal-lane step just `task create --title ...` without addressing.
|
|
246
|
-
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
211
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
247
212
|
if (!target && !conversationId) {
|
|
248
213
|
console.error('--target or --conversation-id is required');
|
|
249
214
|
return 2;
|
|
@@ -252,7 +217,7 @@ export async function runTaskCreateCommand(args) {
|
|
|
252
217
|
if (!text || !text.trim()) {
|
|
253
218
|
console.error('task body is required on stdin');
|
|
254
219
|
console.error('Example:');
|
|
255
|
-
console.error(" ticlawk task create --target \"#frontend\" --title \"fix login\"
|
|
220
|
+
console.error(" ticlawk task create --target \"#frontend\" --title \"fix login\" <<'EOF'");
|
|
256
221
|
console.error(' Detailed description goes here.');
|
|
257
222
|
console.error(' EOF');
|
|
258
223
|
return 2;
|
|
@@ -266,7 +231,6 @@ export async function runTaskCreateCommand(args) {
|
|
|
266
231
|
conversation_id: conversationId,
|
|
267
232
|
text: text.replace(/\n+$/, ''),
|
|
268
233
|
title: getArg(args, 'title'),
|
|
269
|
-
assign_agent_id: getArg(args, 'assign-agent') || getArg(args, 'assignee-agent'),
|
|
270
234
|
},
|
|
271
235
|
});
|
|
272
236
|
printJson(res.body);
|
|
@@ -278,7 +242,7 @@ export async function runTaskClaimCommand(args) {
|
|
|
278
242
|
const messageId = getArg(args, 'message-id');
|
|
279
243
|
const number = getNumberArg(args, 'number');
|
|
280
244
|
const target = getArg(args, 'target');
|
|
281
|
-
const conversationId = getArg(args, 'conversation
|
|
245
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
282
246
|
if (!messageId && number == null) {
|
|
283
247
|
console.error('--message-id or --number is required');
|
|
284
248
|
return 2;
|
|
@@ -346,92 +310,6 @@ export async function runTaskUpdateCommand(args) {
|
|
|
346
310
|
return exitFromStatus(res.statusCode);
|
|
347
311
|
}
|
|
348
312
|
|
|
349
|
-
const GOAL_OUTCOMES = [
|
|
350
|
-
'gap', 'no_gap', 'wait',
|
|
351
|
-
'task_completed', 'needs_approval', 'blocked',
|
|
352
|
-
'accepted', 'rejected',
|
|
353
|
-
];
|
|
354
|
-
|
|
355
|
-
export async function runGoalReportCommand(args) {
|
|
356
|
-
const env = requireAgentEnv();
|
|
357
|
-
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
358
|
-
const transitionId = getArg(args, 'transition') || getArg(args, 'transition-id');
|
|
359
|
-
const outcome = getArg(args, 'outcome');
|
|
360
|
-
if (!conversationId) {
|
|
361
|
-
console.error('--conversation is required');
|
|
362
|
-
return 2;
|
|
363
|
-
}
|
|
364
|
-
if (!transitionId) {
|
|
365
|
-
console.error('--transition is required');
|
|
366
|
-
return 2;
|
|
367
|
-
}
|
|
368
|
-
if (!outcome || !GOAL_OUTCOMES.includes(outcome)) {
|
|
369
|
-
console.error(`--outcome must be one of: ${GOAL_OUTCOMES.join(', ')}`);
|
|
370
|
-
return 2;
|
|
371
|
-
}
|
|
372
|
-
const res = await daemonRequest({
|
|
373
|
-
method: 'POST',
|
|
374
|
-
path: '/agent/goal/report',
|
|
375
|
-
headers: commonHeaders(env),
|
|
376
|
-
body: {
|
|
377
|
-
conversation_id: conversationId,
|
|
378
|
-
transition_id: transitionId,
|
|
379
|
-
outcome,
|
|
380
|
-
detail: getArg(args, 'detail'),
|
|
381
|
-
current_task_id: getArg(args, 'current-task') || getArg(args, 'task-id'),
|
|
382
|
-
},
|
|
383
|
-
});
|
|
384
|
-
printJson(res.body);
|
|
385
|
-
return exitFromStatus(res.statusCode);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export async function runApprovalResolveCommand(args) {
|
|
389
|
-
const env = requireAgentEnv();
|
|
390
|
-
const requestId = getArg(args, 'request') || getArg(args, 'request-id');
|
|
391
|
-
let decision = getArg(args, 'decision');
|
|
392
|
-
if (args.grant) decision = 'granted';
|
|
393
|
-
if (args.reject) decision = 'rejected';
|
|
394
|
-
if (!requestId) {
|
|
395
|
-
console.error('--request is required');
|
|
396
|
-
return 2;
|
|
397
|
-
}
|
|
398
|
-
if (decision !== 'granted' && decision !== 'rejected') {
|
|
399
|
-
console.error('--decision must be granted or rejected (or use --grant / --reject)');
|
|
400
|
-
return 2;
|
|
401
|
-
}
|
|
402
|
-
const confidenceRaw = getArg(args, 'confidence');
|
|
403
|
-
const res = await daemonRequest({
|
|
404
|
-
method: 'POST',
|
|
405
|
-
path: '/agent/approval/resolve',
|
|
406
|
-
headers: commonHeaders(env),
|
|
407
|
-
body: {
|
|
408
|
-
request_id: requestId,
|
|
409
|
-
decision,
|
|
410
|
-
original_text: getArg(args, 'original-text'),
|
|
411
|
-
confidence: confidenceRaw != null ? Number(confidenceRaw) : undefined,
|
|
412
|
-
source_message_id: getArg(args, 'source-message-id'),
|
|
413
|
-
},
|
|
414
|
-
});
|
|
415
|
-
printJson(res.body);
|
|
416
|
-
return exitFromStatus(res.statusCode);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export async function runApprovalListCommand(args) {
|
|
420
|
-
const env = requireAgentEnv();
|
|
421
|
-
const params = new URLSearchParams();
|
|
422
|
-
const target = getArg(args, 'target');
|
|
423
|
-
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id') || env.currentConversationId;
|
|
424
|
-
if (target) params.set('target', target);
|
|
425
|
-
if (conversationId) params.set('conversation_id', conversationId);
|
|
426
|
-
const res = await daemonRequest({
|
|
427
|
-
method: 'GET',
|
|
428
|
-
path: `/agent/approval/list?${params}`,
|
|
429
|
-
headers: commonHeaders(env),
|
|
430
|
-
});
|
|
431
|
-
printJson(res.body);
|
|
432
|
-
return exitFromStatus(res.statusCode);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
313
|
export async function runMessageReactCommand(args) {
|
|
436
314
|
const env = requireAgentEnv();
|
|
437
315
|
const messageId = getArg(args, 'message-id');
|
|
@@ -467,10 +345,7 @@ export async function runTaskListCommand(args) {
|
|
|
467
345
|
const env = requireAgentEnv();
|
|
468
346
|
const params = new URLSearchParams();
|
|
469
347
|
const target = getArg(args, 'target');
|
|
470
|
-
|
|
471
|
-
// of dumping tasks from every conversation the owner can see.
|
|
472
|
-
const conversationId = getArg(args, 'conversation') || getArg(args, 'conversation-id')
|
|
473
|
-
|| (target ? null : env.currentConversationId);
|
|
348
|
+
const conversationId = getArg(args, 'conversation-id');
|
|
474
349
|
if (target) params.set('target', target);
|
|
475
350
|
if (conversationId) params.set('conversation_id', conversationId);
|
|
476
351
|
const res = await daemonRequest({
|
|
@@ -517,18 +392,6 @@ export async function runReminderScheduleCommand(args) {
|
|
|
517
392
|
console.error('--target or --anchor-conversation-id is required');
|
|
518
393
|
return 2;
|
|
519
394
|
}
|
|
520
|
-
// Optional recurrence: --recur-at HH:MM (owner-local) [--recur-weekday 1,2,3].
|
|
521
|
-
// The timezone is system-owned (the owner's), filled in by the backend — the
|
|
522
|
-
// agent never passes it. The backend also computes the first fire_at in it.
|
|
523
|
-
let recurrence = null;
|
|
524
|
-
const recurAt = getArg(args, 'recur-at');
|
|
525
|
-
if (recurAt) {
|
|
526
|
-
const wdRaw = getArg(args, 'recur-weekday');
|
|
527
|
-
const byWeekday = wdRaw
|
|
528
|
-
? String(wdRaw).split(',').map((s) => parseInt(s.trim(), 10)).filter((n) => n >= 1 && n <= 7)
|
|
529
|
-
: [];
|
|
530
|
-
recurrence = { at: recurAt, ...(byWeekday.length ? { by_weekday: byWeekday } : {}) };
|
|
531
|
-
}
|
|
532
395
|
const res = await daemonRequest({
|
|
533
396
|
method: 'POST',
|
|
534
397
|
path: '/agent/reminder/schedule',
|
|
@@ -539,7 +402,6 @@ export async function runReminderScheduleCommand(args) {
|
|
|
539
402
|
target,
|
|
540
403
|
anchor_conversation_id: anchorConversationId,
|
|
541
404
|
anchor_message_id: anchorMessageId,
|
|
542
|
-
recurrence,
|
|
543
405
|
},
|
|
544
406
|
});
|
|
545
407
|
printJson(res.body);
|
|
@@ -792,11 +654,6 @@ function inferContentType(filePath) {
|
|
|
792
654
|
case '.jpg': case '.jpeg': return 'image/jpeg';
|
|
793
655
|
case '.gif': return 'image/gif';
|
|
794
656
|
case '.webp': return 'image/webp';
|
|
795
|
-
case '.mp4': return 'video/mp4';
|
|
796
|
-
case '.mov': return 'video/quicktime';
|
|
797
|
-
case '.m4v': return 'video/x-m4v';
|
|
798
|
-
case '.webm': return 'video/webm';
|
|
799
|
-
case '.html': case '.htm': return 'text/html';
|
|
800
657
|
case '.pdf': return 'application/pdf';
|
|
801
658
|
case '.txt': return 'text/plain';
|
|
802
659
|
case '.md': return 'text/markdown';
|
|
@@ -943,410 +800,6 @@ export async function runGroupMembersCommand(args) {
|
|
|
943
800
|
return exitFromStatus(res.statusCode);
|
|
944
801
|
}
|
|
945
802
|
|
|
946
|
-
export async function runWorkstreamCreateCommand(args) {
|
|
947
|
-
const env = requireAgentEnv();
|
|
948
|
-
const name = getArg(args, 'name');
|
|
949
|
-
if (!name) { console.error('--name is required'); return 2; }
|
|
950
|
-
const description = getArg(args, 'description');
|
|
951
|
-
const memberArgs = args.member;
|
|
952
|
-
const memberAgentIds = Array.isArray(memberArgs)
|
|
953
|
-
? memberArgs
|
|
954
|
-
: memberArgs ? [memberArgs] : [];
|
|
955
|
-
// Optional charter from stdin when --charter is supplied with no value
|
|
956
|
-
let charter = null;
|
|
957
|
-
if (args.charter === true) {
|
|
958
|
-
charter = await readStdin();
|
|
959
|
-
} else if (typeof args.charter === 'string') {
|
|
960
|
-
charter = args.charter;
|
|
961
|
-
}
|
|
962
|
-
const res = await daemonRequest({
|
|
963
|
-
method: 'POST',
|
|
964
|
-
path: '/agent/workstream/create',
|
|
965
|
-
headers: commonHeaders(env),
|
|
966
|
-
body: {
|
|
967
|
-
name,
|
|
968
|
-
description,
|
|
969
|
-
charter,
|
|
970
|
-
member_agent_ids: memberAgentIds.map((s) => String(s).trim()).filter(Boolean),
|
|
971
|
-
},
|
|
972
|
-
});
|
|
973
|
-
printJson(res.body);
|
|
974
|
-
return exitFromStatus(res.statusCode);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
export async function runWorkstreamDeleteCommand(args) {
|
|
978
|
-
const env = requireAgentEnv();
|
|
979
|
-
const target = getArg(args, 'target');
|
|
980
|
-
const conversationId = getArg(args, 'conversation-id');
|
|
981
|
-
if (!target && !conversationId) {
|
|
982
|
-
console.error('--target or --conversation-id is required');
|
|
983
|
-
return 2;
|
|
984
|
-
}
|
|
985
|
-
const res = await daemonRequest({
|
|
986
|
-
method: 'POST',
|
|
987
|
-
path: '/agent/workstream/delete',
|
|
988
|
-
headers: commonHeaders(env),
|
|
989
|
-
body: { target, conversation_id: conversationId },
|
|
990
|
-
});
|
|
991
|
-
printJson(res.body);
|
|
992
|
-
return exitFromStatus(res.statusCode);
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
export async function runWorkstreamListCommand(args) {
|
|
996
|
-
const env = requireAgentEnv();
|
|
997
|
-
const res = await daemonRequest({
|
|
998
|
-
method: 'GET',
|
|
999
|
-
path: '/agent/workstream/list',
|
|
1000
|
-
headers: commonHeaders(env),
|
|
1001
|
-
});
|
|
1002
|
-
printJson(res.body);
|
|
1003
|
-
return exitFromStatus(res.statusCode);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
export async function runAgentListCommand(args) {
|
|
1007
|
-
const env = requireAgentEnv();
|
|
1008
|
-
const res = await daemonRequest({
|
|
1009
|
-
method: 'GET',
|
|
1010
|
-
path: '/agent/agent/list',
|
|
1011
|
-
headers: commonHeaders(env),
|
|
1012
|
-
});
|
|
1013
|
-
printJson(res.body);
|
|
1014
|
-
return exitFromStatus(res.statusCode);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
export async function runAgentCreateCommand(args) {
|
|
1018
|
-
const env = requireAgentEnv();
|
|
1019
|
-
const name = getArg(args, 'name');
|
|
1020
|
-
const runtime = getArg(args, 'runtime');
|
|
1021
|
-
if (!name) { console.error('--name is required'); return 2; }
|
|
1022
|
-
if (!runtime) { console.error('--runtime is required'); return 2; }
|
|
1023
|
-
const res = await daemonRequest({
|
|
1024
|
-
method: 'POST',
|
|
1025
|
-
path: '/agent/agent/create',
|
|
1026
|
-
headers: commonHeaders(env),
|
|
1027
|
-
body: {
|
|
1028
|
-
name,
|
|
1029
|
-
runtime,
|
|
1030
|
-
description: getArg(args, 'description'),
|
|
1031
|
-
display_name: getArg(args, 'display-name'),
|
|
1032
|
-
model: getArg(args, 'model'),
|
|
1033
|
-
},
|
|
1034
|
-
});
|
|
1035
|
-
printJson(res.body);
|
|
1036
|
-
return exitFromStatus(res.statusCode);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
export async function runAgentDeleteCommand(args) {
|
|
1040
|
-
const env = requireAgentEnv();
|
|
1041
|
-
const agentId = getArg(args, 'agent-id');
|
|
1042
|
-
if (!agentId) { console.error('--agent-id is required'); return 2; }
|
|
1043
|
-
const res = await daemonRequest({
|
|
1044
|
-
method: 'POST',
|
|
1045
|
-
path: '/agent/agent/delete',
|
|
1046
|
-
headers: commonHeaders(env),
|
|
1047
|
-
body: { agent_id: agentId },
|
|
1048
|
-
});
|
|
1049
|
-
printJson(res.body);
|
|
1050
|
-
return exitFromStatus(res.statusCode);
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
function readJsonFromFileOrInline(value) {
|
|
1054
|
-
if (!value) return null;
|
|
1055
|
-
// Accept either a path to a .json file or a raw JSON string.
|
|
1056
|
-
try {
|
|
1057
|
-
return JSON.parse(value);
|
|
1058
|
-
} catch {}
|
|
1059
|
-
try {
|
|
1060
|
-
const fs = require('node:fs');
|
|
1061
|
-
const txt = fs.readFileSync(value, 'utf8');
|
|
1062
|
-
return JSON.parse(txt);
|
|
1063
|
-
} catch (err) {
|
|
1064
|
-
throw new Error(`could not parse JSON from ${value}: ${err?.message || err}`);
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
export async function runServiceCreateCommand(args) {
|
|
1069
|
-
const env = requireAgentEnv();
|
|
1070
|
-
const name = getArg(args, 'name');
|
|
1071
|
-
if (!name) { console.error('--name is required'); return 2; }
|
|
1072
|
-
const description = getArg(args, 'description');
|
|
1073
|
-
let contractSchema = null;
|
|
1074
|
-
let endpointConfig = null;
|
|
1075
|
-
try {
|
|
1076
|
-
const contractRaw = getArg(args, 'contract');
|
|
1077
|
-
if (contractRaw) contractSchema = readJsonFromFileOrInline(contractRaw);
|
|
1078
|
-
const endpointRaw = getArg(args, 'endpoint');
|
|
1079
|
-
if (endpointRaw) endpointConfig = readJsonFromFileOrInline(endpointRaw);
|
|
1080
|
-
} catch (err) {
|
|
1081
|
-
console.error(err.message);
|
|
1082
|
-
return 2;
|
|
1083
|
-
}
|
|
1084
|
-
if (!endpointConfig) { console.error('--endpoint <path-or-json> is required'); return 2; }
|
|
1085
|
-
const res = await daemonRequest({
|
|
1086
|
-
method: 'POST', path: '/agent/service/create',
|
|
1087
|
-
headers: commonHeaders(env),
|
|
1088
|
-
body: { name, description, contract_schema: contractSchema, endpoint_config: endpointConfig },
|
|
1089
|
-
});
|
|
1090
|
-
printJson(res.body);
|
|
1091
|
-
return exitFromStatus(res.statusCode);
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
export async function runServiceUpdateCommand(args) {
|
|
1095
|
-
const env = requireAgentEnv();
|
|
1096
|
-
const serviceId = getArg(args, 'service-id');
|
|
1097
|
-
if (!serviceId) { console.error('--service-id is required'); return 2; }
|
|
1098
|
-
const body = { service_id: serviceId };
|
|
1099
|
-
if (getArg(args, 'description')) body.description = getArg(args, 'description');
|
|
1100
|
-
if (getArg(args, 'contract')) body.contract_schema = readJsonFromFileOrInline(getArg(args, 'contract'));
|
|
1101
|
-
if (getArg(args, 'endpoint')) body.endpoint_config = readJsonFromFileOrInline(getArg(args, 'endpoint'));
|
|
1102
|
-
if (getArg(args, 'status')) body.status = getArg(args, 'status');
|
|
1103
|
-
const res = await daemonRequest({
|
|
1104
|
-
method: 'POST', path: '/agent/service/update',
|
|
1105
|
-
headers: commonHeaders(env), body,
|
|
1106
|
-
});
|
|
1107
|
-
printJson(res.body);
|
|
1108
|
-
return exitFromStatus(res.statusCode);
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
export async function runServiceDeleteCommand(args) {
|
|
1112
|
-
const env = requireAgentEnv();
|
|
1113
|
-
const serviceId = getArg(args, 'service-id');
|
|
1114
|
-
if (!serviceId) { console.error('--service-id is required'); return 2; }
|
|
1115
|
-
const res = await daemonRequest({
|
|
1116
|
-
method: 'POST', path: '/agent/service/delete',
|
|
1117
|
-
headers: commonHeaders(env),
|
|
1118
|
-
body: { service_id: serviceId },
|
|
1119
|
-
});
|
|
1120
|
-
printJson(res.body);
|
|
1121
|
-
return exitFromStatus(res.statusCode);
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
export async function runServiceListCommand(args) {
|
|
1125
|
-
const env = requireAgentEnv();
|
|
1126
|
-
const res = await daemonRequest({
|
|
1127
|
-
method: 'GET', path: '/agent/service/list',
|
|
1128
|
-
headers: commonHeaders(env),
|
|
1129
|
-
});
|
|
1130
|
-
printJson(res.body);
|
|
1131
|
-
return exitFromStatus(res.statusCode);
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
export async function runServiceInfoCommand(args) {
|
|
1135
|
-
const env = requireAgentEnv();
|
|
1136
|
-
const name = getArg(args, 'name');
|
|
1137
|
-
if (!name) { console.error('--name is required'); return 2; }
|
|
1138
|
-
const params = new URLSearchParams();
|
|
1139
|
-
params.set('name', name);
|
|
1140
|
-
const res = await daemonRequest({
|
|
1141
|
-
method: 'GET', path: `/agent/service/info?${params}`,
|
|
1142
|
-
headers: commonHeaders(env),
|
|
1143
|
-
});
|
|
1144
|
-
printJson(res.body);
|
|
1145
|
-
return exitFromStatus(res.statusCode);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
export async function runServiceCallCommand(args) {
|
|
1149
|
-
const env = requireAgentEnv();
|
|
1150
|
-
const name = getArg(args, 'name');
|
|
1151
|
-
if (!name) { console.error('--name is required'); return 2; }
|
|
1152
|
-
const inputText = await readStdin();
|
|
1153
|
-
let input = null;
|
|
1154
|
-
if (inputText && inputText.trim().length > 0) {
|
|
1155
|
-
try {
|
|
1156
|
-
input = JSON.parse(inputText);
|
|
1157
|
-
} catch (err) {
|
|
1158
|
-
console.error('stdin must be JSON for service call input');
|
|
1159
|
-
return 2;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
const res = await daemonRequest({
|
|
1163
|
-
method: 'POST', path: '/agent/service/call',
|
|
1164
|
-
headers: commonHeaders(env),
|
|
1165
|
-
body: { name, input },
|
|
1166
|
-
});
|
|
1167
|
-
printJson(res.body);
|
|
1168
|
-
return exitFromStatus(res.statusCode);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
export async function runBriefingGetCommand(args) {
|
|
1172
|
-
const env = requireAgentEnv();
|
|
1173
|
-
const id = args._[2] || getArg(args, 'id');
|
|
1174
|
-
if (!id) { console.error('briefing id required (positional or --id)'); return 2; }
|
|
1175
|
-
const params = new URLSearchParams();
|
|
1176
|
-
params.set('id', id);
|
|
1177
|
-
const res = await daemonRequest({
|
|
1178
|
-
method: 'GET',
|
|
1179
|
-
path: `/agent/briefing/get?${params}`,
|
|
1180
|
-
headers: commonHeaders(env),
|
|
1181
|
-
});
|
|
1182
|
-
printJson(res.body);
|
|
1183
|
-
return exitFromStatus(res.statusCode);
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
export async function runBriefingPublishCommand(args) {
|
|
1187
|
-
const env = requireAgentEnv();
|
|
1188
|
-
const textArg = getArg(args, 'text');
|
|
1189
|
-
const attachPath = getArg(args, 'attach');
|
|
1190
|
-
const mode = String(getArg(args, 'mode') || 'info').trim().toLowerCase();
|
|
1191
|
-
if (!textArg) {
|
|
1192
|
-
console.error('--text "<short>" is required');
|
|
1193
|
-
return 2;
|
|
1194
|
-
}
|
|
1195
|
-
if (textArg.length > 140) {
|
|
1196
|
-
console.error('--text must be ≤140 chars');
|
|
1197
|
-
return 2;
|
|
1198
|
-
}
|
|
1199
|
-
if (!['info', 'approval'].includes(mode)) {
|
|
1200
|
-
console.error('--mode must be info or approval');
|
|
1201
|
-
return 2;
|
|
1202
|
-
}
|
|
1203
|
-
let attachmentAssetId = null;
|
|
1204
|
-
if (attachPath) {
|
|
1205
|
-
const contentType = inferContentType(String(attachPath));
|
|
1206
|
-
if (!contentType.startsWith('image/') && !contentType.startsWith('video/') && contentType !== 'text/html') {
|
|
1207
|
-
console.error('--attach must be an image, video, or HTML file');
|
|
1208
|
-
return 2;
|
|
1209
|
-
}
|
|
1210
|
-
const upload = await uploadFileViaDaemon(env, String(attachPath));
|
|
1211
|
-
if (!upload.ok) {
|
|
1212
|
-
console.error(`attachment upload failed for ${attachPath}: ${upload.error}`);
|
|
1213
|
-
return 1;
|
|
1214
|
-
}
|
|
1215
|
-
attachmentAssetId = upload.assetId;
|
|
1216
|
-
}
|
|
1217
|
-
const res = await daemonRequest({
|
|
1218
|
-
method: 'POST',
|
|
1219
|
-
path: '/agent/briefing/publish',
|
|
1220
|
-
headers: commonHeaders(env),
|
|
1221
|
-
body: {
|
|
1222
|
-
body_text: textArg,
|
|
1223
|
-
attachment_asset_id: attachmentAssetId,
|
|
1224
|
-
current_conversation_id: env.currentConversationId,
|
|
1225
|
-
response_mode: mode,
|
|
1226
|
-
},
|
|
1227
|
-
});
|
|
1228
|
-
printJson(res.body);
|
|
1229
|
-
return exitFromStatus(res.statusCode);
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
export async function runCredentialRequestCommand(args) {
|
|
1233
|
-
const env = requireAgentEnv();
|
|
1234
|
-
const name = getArg(args, 'name');
|
|
1235
|
-
if (!name) { console.error('--name is required (e.g. GEMINI_API_KEY)'); return 2; }
|
|
1236
|
-
const description = getArg(args, 'description');
|
|
1237
|
-
const groupTarget = getArg(args, 'group') || getArg(args, 'workstream');
|
|
1238
|
-
const res = await daemonRequest({
|
|
1239
|
-
method: 'POST',
|
|
1240
|
-
path: '/agent/credential/request',
|
|
1241
|
-
headers: commonHeaders(env),
|
|
1242
|
-
body: {
|
|
1243
|
-
name,
|
|
1244
|
-
description,
|
|
1245
|
-
target: groupTarget,
|
|
1246
|
-
},
|
|
1247
|
-
});
|
|
1248
|
-
printJson(res.body);
|
|
1249
|
-
return exitFromStatus(res.statusCode);
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
export async function runDashboardSetCommand(args) {
|
|
1253
|
-
const env = requireAgentEnv();
|
|
1254
|
-
const target = getArg(args, 'target');
|
|
1255
|
-
const conversationId = getArg(args, 'conversation-id');
|
|
1256
|
-
if (!target && !conversationId) {
|
|
1257
|
-
console.error('--target or --conversation-id is required');
|
|
1258
|
-
return 2;
|
|
1259
|
-
}
|
|
1260
|
-
// Body is read from stdin as JSON: { data_json?, html_template? }
|
|
1261
|
-
const stdinText = await readStdin();
|
|
1262
|
-
let payload = {};
|
|
1263
|
-
if (stdinText && stdinText.trim().length > 0) {
|
|
1264
|
-
try {
|
|
1265
|
-
payload = JSON.parse(stdinText);
|
|
1266
|
-
} catch (err) {
|
|
1267
|
-
console.error('stdin must be JSON: { data_json?, html_template? }');
|
|
1268
|
-
return 2;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
const res = await daemonRequest({
|
|
1272
|
-
method: 'POST',
|
|
1273
|
-
path: '/agent/dashboard/set',
|
|
1274
|
-
headers: commonHeaders(env),
|
|
1275
|
-
body: {
|
|
1276
|
-
target,
|
|
1277
|
-
conversation_id: conversationId,
|
|
1278
|
-
...(('data_json' in payload) ? { data_json: payload.data_json } : {}),
|
|
1279
|
-
...(('html_template' in payload) ? { html_template: payload.html_template } : {}),
|
|
1280
|
-
},
|
|
1281
|
-
});
|
|
1282
|
-
printJson(res.body);
|
|
1283
|
-
return exitFromStatus(res.statusCode);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
export async function runDashboardGetCommand(args) {
|
|
1287
|
-
const env = requireAgentEnv();
|
|
1288
|
-
const target = getArg(args, 'target');
|
|
1289
|
-
const conversationId = getArg(args, 'conversation-id');
|
|
1290
|
-
if (!target && !conversationId) {
|
|
1291
|
-
console.error('--target or --conversation-id is required');
|
|
1292
|
-
return 2;
|
|
1293
|
-
}
|
|
1294
|
-
const params = new URLSearchParams();
|
|
1295
|
-
if (target) params.set('target', target);
|
|
1296
|
-
if (conversationId) params.set('conversation_id', conversationId);
|
|
1297
|
-
const res = await daemonRequest({
|
|
1298
|
-
method: 'GET',
|
|
1299
|
-
path: `/agent/dashboard/get?${params}`,
|
|
1300
|
-
headers: commonHeaders(env),
|
|
1301
|
-
});
|
|
1302
|
-
printJson(res.body);
|
|
1303
|
-
return exitFromStatus(res.statusCode);
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
export async function runWorkstreamCharterGetCommand(args) {
|
|
1307
|
-
const env = requireAgentEnv();
|
|
1308
|
-
const target = getArg(args, 'target');
|
|
1309
|
-
const conversationId = getArg(args, 'conversation-id') || env.currentConversationId;
|
|
1310
|
-
if (!target && !conversationId) {
|
|
1311
|
-
console.error('--target or --conversation-id is required outside a delivered conversation');
|
|
1312
|
-
return 2;
|
|
1313
|
-
}
|
|
1314
|
-
const params = new URLSearchParams();
|
|
1315
|
-
if (target) params.set('target', target);
|
|
1316
|
-
if (conversationId) params.set('conversation_id', conversationId);
|
|
1317
|
-
const res = await daemonRequest({
|
|
1318
|
-
method: 'GET',
|
|
1319
|
-
path: `/agent/workstream/charter/get?${params}`,
|
|
1320
|
-
headers: commonHeaders(env),
|
|
1321
|
-
});
|
|
1322
|
-
printJson(res.body);
|
|
1323
|
-
return exitFromStatus(res.statusCode);
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
export async function runWorkstreamCharterSetCommand(args) {
|
|
1327
|
-
const env = requireAgentEnv();
|
|
1328
|
-
const target = getArg(args, 'target');
|
|
1329
|
-
const conversationId = getArg(args, 'conversation-id') || env.currentConversationId;
|
|
1330
|
-
if (!target && !conversationId) {
|
|
1331
|
-
console.error('--target or --conversation-id is required outside a delivered conversation');
|
|
1332
|
-
return 2;
|
|
1333
|
-
}
|
|
1334
|
-
// Body from stdin (heredoc / pipe). Empty input clears the charter.
|
|
1335
|
-
const charter = await readStdin();
|
|
1336
|
-
const res = await daemonRequest({
|
|
1337
|
-
method: 'POST',
|
|
1338
|
-
path: '/agent/workstream/charter/set',
|
|
1339
|
-
headers: commonHeaders(env),
|
|
1340
|
-
body: {
|
|
1341
|
-
target,
|
|
1342
|
-
conversation_id: conversationId,
|
|
1343
|
-
charter: charter ?? '',
|
|
1344
|
-
},
|
|
1345
|
-
});
|
|
1346
|
-
printJson(res.body);
|
|
1347
|
-
return exitFromStatus(res.statusCode);
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
803
|
export async function runServerInfoCommand(args) {
|
|
1351
804
|
const env = requireAgentEnv();
|
|
1352
805
|
const params = new URLSearchParams();
|
|
@@ -1362,18 +815,12 @@ export async function runServerInfoCommand(args) {
|
|
|
1362
815
|
|
|
1363
816
|
export const AGENT_COMMAND_HELP = {
|
|
1364
817
|
message: `ticlawk message <send|read|check|search|react>
|
|
1365
|
-
ticlawk message send --target "<target>" [--
|
|
818
|
+
ticlawk message send --target "<target>" [--seen-up-to-seq N] [--reply-to <msg-id>] [--attach <file> ...]
|
|
1366
819
|
Body is read from stdin (use <<'EOF' ... EOF for multiline).
|
|
1367
|
-
During a delivered turn, sending to a different conversation is blocked
|
|
1368
|
-
unless --allow-cross-target is passed deliberately.
|
|
1369
|
-
--phase progress|final tags whether this is an intermediate update or
|
|
1370
|
-
the final visible response after the current work/goal check is done.
|
|
1371
|
-
--kind <kind> tags this message via metadata.kind.
|
|
1372
820
|
Targets:
|
|
1373
|
-
dm
|
|
1374
|
-
|
|
1375
|
-
#<group>
|
|
1376
|
-
#<group>:<msgid> replies under a top-level message in that group
|
|
821
|
+
dm:@<user> private message
|
|
822
|
+
#<group> group conversation
|
|
823
|
+
#<group>:<msgid> thread under a top-level message in that group
|
|
1377
824
|
--attach <file> uploads a local file and attaches it to the message
|
|
1378
825
|
(repeatable; max 10 attachments per message).
|
|
1379
826
|
ticlawk message read --target "<target>" [--around <msg-id>] [--before-seq N] [--limit N]
|
|
@@ -1385,11 +832,7 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1385
832
|
Use sparingly: prefer acknowledgement/follow-up signals like 👀. Do not
|
|
1386
833
|
auto-react to every merge, deploy, or task completion with celebratory emoji.
|
|
1387
834
|
`,
|
|
1388
|
-
profile: `ticlawk profile <
|
|
1389
|
-
ticlawk profile list
|
|
1390
|
-
ticlawk profile current
|
|
1391
|
-
ticlawk profile use ticlawk:<user-id>
|
|
1392
|
-
|
|
835
|
+
profile: `ticlawk profile <show|update>
|
|
1393
836
|
ticlawk profile show [@handle | --id <agent-id>]
|
|
1394
837
|
ticlawk profile update [--display-name X] [--description Y] [--avatar-file path]
|
|
1395
838
|
`,
|
|
@@ -1398,7 +841,7 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1398
841
|
to a user, use \`ticlawk message send --attach <file>\` instead.
|
|
1399
842
|
`,
|
|
1400
843
|
reminder: `ticlawk reminder <schedule|list|snooze|update|cancel|log>
|
|
1401
|
-
ticlawk reminder schedule --title <t> (--fire-at <iso> | --in-seconds N | --in-minutes N) (--target "<target>" | --anchor-conversation-id <id>) [--anchor-message-id <id>]
|
|
844
|
+
ticlawk reminder schedule --title <t> (--fire-at <iso> | --in-seconds N | --in-minutes N) (--target "<target>" | --anchor-conversation-id <id>) [--anchor-message-id <id>]
|
|
1402
845
|
ticlawk reminder list [--status active|fired|canceled]
|
|
1403
846
|
ticlawk reminder snooze <reminder-id> (--fire-at <iso> | --in-seconds N | --in-minutes N)
|
|
1404
847
|
ticlawk reminder update <reminder-id> [--title <t>] [--fire-at <iso>]
|
|
@@ -1408,149 +851,25 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1408
851
|
Use reminders for follow-up that depends on future state you cannot resolve
|
|
1409
852
|
now. A reminder fires by posting a system message into the anchor
|
|
1410
853
|
conversation and waking the owner agent via an explicit delivery.
|
|
1411
|
-
|
|
1412
|
-
RECURRING: for a fixed cadence (e.g. a daily/weekly meal-time check-in), use
|
|
1413
|
-
ONE recurring reminder instead of enumerating many one-shots. Pass --recur-at
|
|
1414
|
-
(the owner's local HH:MM) and optionally --recur-weekday (ISO 1=Mon..7=Sun,
|
|
1415
|
-
comma-separated; omit for every day). You do NOT set a timezone — the backend
|
|
1416
|
-
fills the owner's timezone and computes the fire time in it. On each fire the
|
|
1417
|
-
reminder auto-advances to the next occurrence and stays active. Example —
|
|
1418
|
-
weekday 18:30 dinner check-in (--fire-at is ignored for recurring, the backend
|
|
1419
|
-
computes it):
|
|
1420
|
-
ticlawk reminder schedule --title "晚餐" --anchor-conversation-id <id> \\
|
|
1421
|
-
--in-minutes 1 --recur-at 18:30 --recur-weekday 1,2,3,4,5
|
|
1422
854
|
`,
|
|
1423
855
|
task: `ticlawk task <create|claim|unclaim|update|list>
|
|
1424
|
-
ticlawk task create
|
|
1425
|
-
Body is read from stdin. Creates a brand-new
|
|
1426
|
-
|
|
1427
|
-
Conversation defaults to the one this turn is running for; pass
|
|
1428
|
-
--conversation <id> (or --target) only to address a different one.
|
|
856
|
+
ticlawk task create --target "<target>" [--title <t>]
|
|
857
|
+
Body is read from stdin. Creates a brand-new message published as a todo
|
|
858
|
+
task. To own it, follow up with \`ticlawk task claim --message-id <id>\`.
|
|
1429
859
|
ticlawk task claim --message-id <id> [--lease-seconds N]
|
|
1430
860
|
ticlawk task claim --number <N> --target "<target>" [--lease-seconds N]
|
|
1431
861
|
ticlawk task unclaim --task-id <id>
|
|
1432
862
|
ticlawk task update --task-id <id> --status <todo|in_progress|in_review|done|canceled>
|
|
1433
|
-
|
|
1434
|
-
in_review and let the group's admin finalize. A group admin can also
|
|
1435
|
-
reopen another agent's in_review task to in_progress for redo.
|
|
1436
|
-
ticlawk task list [--conversation <id>|--target <target>]
|
|
1437
|
-
Scopes to the conversation this turn runs for by default; pass
|
|
1438
|
-
--conversation <id> (or --target) to look at a different one. When the
|
|
1439
|
-
caller is a group admin and the scope is that group, the list shows the
|
|
1440
|
-
full task board, including other agents' in_progress/in_review/done tasks.
|
|
1441
|
-
`,
|
|
1442
|
-
workstream: `ticlawk workstream <create|delete|list|charter>
|
|
1443
|
-
Compatibility alias for group admin commands. Prefer \`ticlawk group ...\`
|
|
1444
|
-
for groups and \`ticlawk charter ...\` for conversation charters.
|
|
1445
|
-
`,
|
|
1446
|
-
goal: `ticlawk goal <report>
|
|
1447
|
-
Goal-lane (FSM) control. Normally invoked from a goal-step turn, not by hand.
|
|
1448
|
-
ticlawk goal report --transition <id> --outcome <outcome> [--conversation <id>] [--detail <text>] [--current-task <task-id>]
|
|
1449
|
-
Report the outcome of the current FSM step and advance the state machine.
|
|
1450
|
-
--conversation defaults to the current goal-turn conversation.
|
|
1451
|
-
Outcomes by step:
|
|
1452
|
-
gap_analysis: gap | no_gap | wait
|
|
1453
|
-
execute: task_completed | needs_approval | blocked
|
|
1454
|
-
review: accepted | rejected
|
|
1455
|
-
(To change a goal, write the charter with \`ticlawk charter set\` — that re-aims the goal lane.)
|
|
1456
|
-
`,
|
|
1457
|
-
approval: `ticlawk approval <resolve|list>
|
|
1458
|
-
Goal-loop approval resolution (chat lane). The goal lane PARKS an approval by
|
|
1459
|
-
publishing an approval briefing (\`ticlawk briefing publish --mode approval\`),
|
|
1460
|
-
which both asks the owner and suspends the loop on it. The owner answers by
|
|
1461
|
-
tapping approve (which posts an "approved" message) or replying in plain
|
|
1462
|
-
language — either way the chat lane resolves it here, idempotently.
|
|
1463
|
-
ticlawk approval list [--conversation <id> | --target "<target>"]
|
|
1464
|
-
List pending approval requests in the conversation. Use this from the chat
|
|
1465
|
-
lane to find which request an owner's natural-language approval refers to.
|
|
1466
|
-
--conversation defaults to the current conversation.
|
|
1467
|
-
ticlawk approval resolve --request <id> (--grant | --reject | --decision granted|rejected) [--original-text <text>] [--confidence <0-1>] [--source-message-id <id>]
|
|
1468
|
-
Resolve a pending approval from a natural-language chat decision (source=chat).
|
|
1469
|
-
Idempotent: a second resolve (or a button tap) on the same request is a no-op.
|
|
1470
|
-
`,
|
|
1471
|
-
charter: `ticlawk charter <get|set> [--target "<target>" | --conversation-id <id>]
|
|
1472
|
-
ticlawk charter get [--target "<target>" | --conversation-id <id>]
|
|
1473
|
-
Print the conversation charter. DM/group members can read.
|
|
1474
|
-
ticlawk charter set [--target "<target>" | --conversation-id <id>] # body via stdin
|
|
1475
|
-
Replace the conversation charter. DM member agents can write their DM
|
|
1476
|
-
charter; group writes require group admin/owner. Empty stdin clears it.
|
|
1477
|
-
During a delivered turn, omitting target/conversation-id uses the
|
|
1478
|
-
current conversation.
|
|
1479
|
-
`,
|
|
1480
|
-
service: `ticlawk service <create|update|delete|list|info|call>
|
|
1481
|
-
service create --name X --endpoint <path-or-json> [--description Y] [--contract <path-or-json>]
|
|
1482
|
-
Any agent. Register a callable service. --endpoint takes either a
|
|
1483
|
-
.json file path or a JSON string; same for --contract.
|
|
1484
|
-
endpoint_config shape: { url, method?, headers? }.
|
|
1485
|
-
service update --service-id <id> [--description Y] [--contract <json>] [--endpoint <json>] [--status <active|down|archived>]
|
|
1486
|
-
Any agent.
|
|
1487
|
-
service delete --service-id <id>
|
|
1488
|
-
Any agent. Soft-archives.
|
|
1489
|
-
service list
|
|
1490
|
-
Any agent. Returns active services (no endpoint_config).
|
|
1491
|
-
service info --name X
|
|
1492
|
-
Any agent. Returns contract_schema + description.
|
|
1493
|
-
service call --name X # input from stdin (JSON)
|
|
1494
|
-
Any agent. Backend proxies to endpoint_config.url. No retry.
|
|
1495
|
-
`,
|
|
1496
|
-
briefing: `ticlawk briefing <publish|get>
|
|
1497
|
-
briefing publish --text "..." [--mode info|approval] [--attach <image|video|html path>]
|
|
1498
|
-
Publish a briefing to the owner's Briefings. Allowed from DMs, or
|
|
1499
|
-
from groups where this agent is admin/owner.
|
|
1500
|
-
--text short plain text (≤140 chars)
|
|
1501
|
-
--mode owner response mode: info shows ack; approval shows approve
|
|
1502
|
-
--attach optional image, video, or HTML file when visual context matters
|
|
1503
|
-
Briefings are independent of chat — they do NOT appear in any DM
|
|
1504
|
-
message stream. Use this verb (not \`message send\`) for any status
|
|
1505
|
-
surface the owner consumes in Briefings.
|
|
1506
|
-
briefing get <id>
|
|
1507
|
-
Fetch a briefing including text and attachment metadata. Use this when a
|
|
1508
|
-
quote (metadata.quote.kind=briefing) points at a briefing whose
|
|
1509
|
-
full body you want to read.
|
|
1510
|
-
`,
|
|
1511
|
-
credential: `ticlawk credential request --name <ENV_VAR> [--description Y] [--group "#<group>"]
|
|
1512
|
-
Any agent. Pre-allocate a credential slot. Response includes a deep
|
|
1513
|
-
link the user opens in the mobile app (Settings → Credentials)
|
|
1514
|
-
to fill the value. Once filled, the daemon syncs it locally and
|
|
1515
|
-
injects it as an env var when spawning agents.
|
|
1516
|
-
`,
|
|
1517
|
-
dashboard: `ticlawk dashboard <set|get> (--target "<target>" | --conversation-id <id>)
|
|
1518
|
-
dashboard set (--target "<target>" | --conversation-id <id>) # body via stdin (JSON)
|
|
1519
|
-
Allowed from DMs, or from groups where this agent is admin/owner.
|
|
1520
|
-
stdin = { "data_json": ..., "html_template": "..." }.
|
|
1521
|
-
Either field may be omitted (leaves unchanged) or null (clears).
|
|
1522
|
-
dashboard get (--target "<target>" | --conversation-id <id>)
|
|
1523
|
-
Conversation members can read.
|
|
1524
|
-
`,
|
|
1525
|
-
agent: `ticlawk agent <list|create|delete>
|
|
1526
|
-
agent list
|
|
1527
|
-
Any agent. List all non-archived agents owned by the user, including
|
|
1528
|
-
descriptions, runtime/status, and group memberships.
|
|
1529
|
-
agent create --name X --runtime <claude_code|codex|opencode|openclaw|pi> [--description Y] [--display-name N] [--model M]
|
|
1530
|
-
Any agent. Pre-allocate an agent slot (status='unpaired'). User
|
|
1531
|
-
later pairs a runtime to fill it.
|
|
1532
|
-
agent delete --agent-id <id>
|
|
1533
|
-
Owner-only. Agent-facing deletion is disabled.
|
|
863
|
+
ticlawk task list [--target <target>]
|
|
1534
864
|
`,
|
|
1535
|
-
group: `ticlawk group <create|
|
|
865
|
+
group: `ticlawk group <create|members>
|
|
1536
866
|
ticlawk group create --name <n> [--description <d>] [--member <agent-id> ...]
|
|
1537
|
-
Agent self-creates a new group. The agent is added as
|
|
867
|
+
Agent self-creates a new group. The agent is added as a member; the
|
|
1538
868
|
conversation owner is set to the user that owns this agent. Other
|
|
1539
|
-
member agents
|
|
1540
|
-
|
|
1541
|
-
ticlawk group
|
|
1542
|
-
|
|
1543
|
-
descriptions, charters, and dashboard presence.
|
|
1544
|
-
ticlawk group delete --target "#<group>"
|
|
1545
|
-
Group-admin only. Hard-delete the group (messages, members, deliveries).
|
|
1546
|
-
ticlawk group charter get (--target "#<group>" | --conversation-id <id>)
|
|
1547
|
-
Compatibility alias for \`ticlawk charter get\` on groups.
|
|
1548
|
-
ticlawk group charter set (--target "#<group>" | --conversation-id <id>) # body via stdin
|
|
1549
|
-
Compatibility alias for \`ticlawk charter set\` on groups. Group-admin only.
|
|
1550
|
-
ticlawk group members (--target "<target>" | --conversation-id <id>)
|
|
1551
|
-
ticlawk group members (--target "<target>" | --conversation-id <id>) --add <agent-id> [--add <agent-id> ...]
|
|
1552
|
-
ticlawk group members (--target "<target>" | --conversation-id <id>) --remove <agent-id>
|
|
1553
|
-
Listing requires membership; add/remove requires group admin.
|
|
869
|
+
member agents must belong to the same user (RLS enforces).
|
|
870
|
+
ticlawk group members --target "<target>"
|
|
871
|
+
ticlawk group members --target "<target>" --add <agent-id> [--add <agent-id> ...]
|
|
872
|
+
ticlawk group members --target "<target>" --remove <agent-id>
|
|
1554
873
|
`,
|
|
1555
874
|
server: `ticlawk server info [--refresh]
|
|
1556
875
|
`,
|