ticlawk 0.1.16-dev.1 → 0.1.16-dev.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -211,10 +211,23 @@ Usage:
211
211
  ticlawk uninstall [-y]
212
212
  ticlawk version
213
213
 
214
+ Agent CLI (run inside an agent runtime; requires TICLAWK_RUNTIME_AGENT_ID):
215
+ ticlawk message send --target <t> # body on stdin
216
+ ticlawk message read --target <t> [opts]
217
+ ticlawk task claim --message-id <id>
218
+ ticlawk task update --task-id <id> --status <s>
219
+ ticlawk task list [--target <t>]
220
+ ticlawk group members --target <t>
221
+ ticlawk server info [--refresh]
222
+
214
223
  Commands:
215
224
  auth store the ticlawk app pairing code locally
216
225
  connect connect ticlawk to a local runtime
217
226
  profile list or switch saved local identities
227
+ message send/read chat messages (agent CLI surface)
228
+ task claim/update/list tasks (agent CLI surface)
229
+ group list members of a group conversation (agent CLI surface)
230
+ server server-info introspection (agent CLI surface)
218
231
  install-daemon install or refresh the background daemon
219
232
  update update the npm package and refresh the daemon
220
233
  uninstall remove service and managed install files, preserving ~/.ticlawk
package/bin/ticlawk.mjs CHANGED
@@ -30,12 +30,29 @@ import { getInstallDaemonHelp, runInstallDaemon } from '../src/core/daemon-insta
30
30
  import { runSetupReadiness } from '../src/core/setup-readiness.mjs';
31
31
  import {
32
32
  AGENT_COMMAND_HELP,
33
+ runAttachmentViewCommand,
34
+ runGroupCreateCommand,
35
+ runGroupMembersAddCommand,
33
36
  runGroupMembersCommand,
37
+ runGroupMembersRemoveCommand,
38
+ runMessageCheckCommand,
39
+ runMessageReactCommand,
34
40
  runMessageReadCommand,
41
+ runMessageSearchCommand,
35
42
  runMessageSendCommand,
43
+ runProfileShowCommand,
44
+ runProfileUpdateCommand,
45
+ runReminderCancelCommand,
46
+ runReminderListCommand,
47
+ runReminderLogCommand,
48
+ runReminderScheduleCommand,
49
+ runReminderSnoozeCommand,
50
+ runReminderUpdateCommand,
36
51
  runServerInfoCommand,
37
52
  runTaskClaimCommand,
53
+ runTaskCreateCommand,
38
54
  runTaskListCommand,
55
+ runTaskUnclaimCommand,
39
56
  runTaskUpdateCommand,
40
57
  } from '../src/cli/agent-commands.mjs';
41
58
 
@@ -324,20 +341,106 @@ async function main() {
324
341
  process.exitCode = await runMessageReadCommand(args);
325
342
  return;
326
343
  }
344
+ if (sub === 'react') {
345
+ process.exitCode = await runMessageReactCommand(args);
346
+ return;
347
+ }
348
+ if (sub === 'check') {
349
+ process.exitCode = await runMessageCheckCommand(args);
350
+ return;
351
+ }
352
+ if (sub === 'search') {
353
+ process.exitCode = await runMessageSearchCommand(args);
354
+ return;
355
+ }
327
356
  console.error(`unknown message subcommand: ${sub}`);
328
357
  process.exit(1);
329
358
  }
330
359
 
360
+ if (command === 'profile') {
361
+ const sub = args._[1];
362
+ if (args.help || args.h || !sub) {
363
+ console.log(AGENT_COMMAND_HELP.profile);
364
+ return;
365
+ }
366
+ if (sub === 'show') {
367
+ process.exitCode = await runProfileShowCommand(args);
368
+ return;
369
+ }
370
+ if (sub === 'update') {
371
+ process.exitCode = await runProfileUpdateCommand(args);
372
+ return;
373
+ }
374
+ console.error(`unknown profile subcommand: ${sub}`);
375
+ process.exit(1);
376
+ }
377
+
378
+ if (command === 'reminder') {
379
+ const sub = args._[1];
380
+ if (args.help || args.h || !sub) {
381
+ console.log(AGENT_COMMAND_HELP.reminder);
382
+ return;
383
+ }
384
+ if (sub === 'schedule') {
385
+ process.exitCode = await runReminderScheduleCommand(args);
386
+ return;
387
+ }
388
+ if (sub === 'list') {
389
+ process.exitCode = await runReminderListCommand(args);
390
+ return;
391
+ }
392
+ if (sub === 'snooze') {
393
+ process.exitCode = await runReminderSnoozeCommand(args);
394
+ return;
395
+ }
396
+ if (sub === 'update') {
397
+ process.exitCode = await runReminderUpdateCommand(args);
398
+ return;
399
+ }
400
+ if (sub === 'cancel') {
401
+ process.exitCode = await runReminderCancelCommand(args);
402
+ return;
403
+ }
404
+ if (sub === 'log') {
405
+ process.exitCode = await runReminderLogCommand(args);
406
+ return;
407
+ }
408
+ console.error(`unknown reminder subcommand: ${sub}`);
409
+ process.exit(1);
410
+ }
411
+
412
+ if (command === 'attachment') {
413
+ const sub = args._[1];
414
+ if (args.help || args.h || !sub) {
415
+ console.log(AGENT_COMMAND_HELP.attachment);
416
+ return;
417
+ }
418
+ if (sub === 'view') {
419
+ process.exitCode = await runAttachmentViewCommand(args);
420
+ return;
421
+ }
422
+ console.error(`unknown attachment subcommand: ${sub}`);
423
+ process.exit(1);
424
+ }
425
+
331
426
  if (command === 'task') {
332
427
  const sub = args._[1];
333
428
  if (args.help || args.h || !sub) {
334
429
  console.log(AGENT_COMMAND_HELP.task);
335
430
  return;
336
431
  }
432
+ if (sub === 'create') {
433
+ process.exitCode = await runTaskCreateCommand(args);
434
+ return;
435
+ }
337
436
  if (sub === 'claim') {
338
437
  process.exitCode = await runTaskClaimCommand(args);
339
438
  return;
340
439
  }
440
+ if (sub === 'unclaim') {
441
+ process.exitCode = await runTaskUnclaimCommand(args);
442
+ return;
443
+ }
341
444
  if (sub === 'update') {
342
445
  process.exitCode = await runTaskUpdateCommand(args);
343
446
  return;
@@ -356,7 +459,20 @@ async function main() {
356
459
  console.log(AGENT_COMMAND_HELP.group);
357
460
  return;
358
461
  }
462
+ if (sub === 'create') {
463
+ process.exitCode = await runGroupCreateCommand(args);
464
+ return;
465
+ }
359
466
  if (sub === 'members') {
467
+ // Same subcommand handles list / add / remove based on flags.
468
+ if (args.add) {
469
+ process.exitCode = await runGroupMembersAddCommand(args);
470
+ return;
471
+ }
472
+ if (args.remove) {
473
+ process.exitCode = await runGroupMembersRemoveCommand(args);
474
+ return;
475
+ }
360
476
  process.exitCode = await runGroupMembersCommand(args);
361
477
  return;
362
478
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticlawk",
3
- "version": "0.1.16-dev.1",
3
+ "version": "0.1.16-dev.11",
4
4
  "description": "Local connector that links agent harnesses (Claude Code, Codex, OpenClaw, opencode, Pi) to the Ticlawk mobile app.",
5
5
  "type": "module",
6
6
  "main": "ticlawk.mjs",
@@ -149,18 +149,6 @@ export async function updateChannel(id, updates) {
149
149
  return updateAgent(id, updates);
150
150
  }
151
151
 
152
- export async function postRuntimeResult(body) {
153
- // Activity-only: backend records the agent_event for UI trajectory
154
- // display but does NOT project it into a chat message. The agent CLI's
155
- // `ticlawk message send` is the only path that produces chat rows.
156
- const result = await apiFetch('/api/runtime-results', {
157
- method: 'POST',
158
- body: JSON.stringify(body),
159
- timeout: 30000,
160
- });
161
- return result;
162
- }
163
-
164
152
  // ── Deliveries (replaces legacy message_jobs poll/ack) ──
165
153
 
166
154
  export async function claimPendingDeliveries(hostId, limit = 5, excludedAgentIds = []) {
@@ -198,6 +186,8 @@ export async function sendAgentMessage({
198
186
  seenUpToSeq,
199
187
  replyToMessageId,
200
188
  runtimeHostId,
189
+ visibility,
190
+ mediaAssetIds,
201
191
  }) {
202
192
  const { data } = await apiFetch('/api/agent/messages/send', {
203
193
  method: 'POST',
@@ -208,6 +198,8 @@ export async function sendAgentMessage({
208
198
  seen_up_to_seq: seenUpToSeq ?? null,
209
199
  reply_to_message_id: replyToMessageId ?? null,
210
200
  runtime_host_id: runtimeHostId ?? null,
201
+ visibility: visibility || null,
202
+ media_asset_ids: Array.isArray(mediaAssetIds) && mediaAssetIds.length > 0 ? mediaAssetIds : undefined,
211
203
  }),
212
204
  });
213
205
  return data || null;
@@ -230,17 +222,55 @@ export async function readAgentMessages({
230
222
  return data || [];
231
223
  }
232
224
 
233
- export async function claimAgentTask({ actingAgentId, sourceMessageId, leaseSeconds }) {
225
+ export async function createAgentTask({ actingAgentId, conversationId, text, title }) {
226
+ return apiFetch('/api/agent/tasks/create', {
227
+ method: 'POST',
228
+ body: JSON.stringify({
229
+ acting_as_agent_id: actingAgentId,
230
+ conversation_id: conversationId,
231
+ text,
232
+ title: title ?? null,
233
+ }),
234
+ });
235
+ }
236
+
237
+ export async function claimAgentTask({
238
+ actingAgentId, sourceMessageId, conversationId, number, leaseSeconds,
239
+ }) {
234
240
  return apiFetch('/api/agent/tasks/claim', {
235
241
  method: 'POST',
236
242
  body: JSON.stringify({
237
243
  acting_as_agent_id: actingAgentId,
238
- source_message_id: sourceMessageId,
244
+ source_message_id: sourceMessageId ?? null,
245
+ conversation_id: conversationId ?? null,
246
+ number: number ?? null,
239
247
  lease_seconds: leaseSeconds ?? null,
240
248
  }),
241
249
  });
242
250
  }
243
251
 
252
+ export async function unclaimAgentTask({ actingAgentId, taskId }) {
253
+ return apiFetch('/api/agent/tasks/unclaim', {
254
+ method: 'POST',
255
+ body: JSON.stringify({
256
+ acting_as_agent_id: actingAgentId,
257
+ task_id: taskId,
258
+ }),
259
+ });
260
+ }
261
+
262
+ export async function reactToMessage({
263
+ actingAgentId, messageId, emoji, remove,
264
+ }) {
265
+ return apiFetch(`/api/agent/messages/${encodeURIComponent(messageId)}/reactions`, {
266
+ method: remove ? 'DELETE' : 'POST',
267
+ body: JSON.stringify({
268
+ acting_as_agent_id: actingAgentId,
269
+ emoji,
270
+ }),
271
+ });
272
+ }
273
+
244
274
  export async function updateAgentTask({ actingAgentId, taskId, status }) {
245
275
  return apiFetch('/api/agent/tasks/update', {
246
276
  method: 'POST',
@@ -273,29 +303,185 @@ export async function getAgentServerInfo({ actingAgentId }) {
273
303
  return apiFetch(`/api/agent/server-info?${params}`);
274
304
  }
275
305
 
276
- // ── Transcript history ──
306
+ // ── Reminders ──
277
307
 
278
- export async function syncMessages(rows) {
279
- return apiFetch('/api/messages/sync', {
308
+ export async function scheduleAgentReminder({
309
+ actingAgentId, title, fireAt, anchorConversationId, anchorMessageId,
310
+ }) {
311
+ return apiFetch('/api/agent/reminders', {
280
312
  method: 'POST',
281
- body: JSON.stringify({ rows }),
313
+ body: JSON.stringify({
314
+ acting_as_agent_id: actingAgentId,
315
+ title,
316
+ fire_at: fireAt,
317
+ anchor_conversation_id: anchorConversationId,
318
+ anchor_message_id: anchorMessageId ?? null,
319
+ }),
282
320
  });
283
321
  }
284
322
 
285
- // ── Upload ──
323
+ export async function listAgentReminders({ actingAgentId, status }) {
324
+ const params = new URLSearchParams();
325
+ params.set('acting_as_agent_id', actingAgentId);
326
+ if (status) params.set('status', status);
327
+ const { data } = await apiFetch(`/api/agent/reminders?${params}`);
328
+ return data || [];
329
+ }
286
330
 
287
- export async function uploadAsset(fileName, fileData, contentType, kind = 'chat_media') {
288
- const formData = new FormData();
289
- formData.append('file', new Blob([fileData], { type: contentType }), fileName);
290
- formData.append('kind', kind);
291
- if (contentType) formData.append('content_type', contentType);
331
+ export async function snoozeAgentReminder({ actingAgentId, reminderId, fireAt }) {
332
+ return apiFetch(`/api/agent/reminders/${encodeURIComponent(reminderId)}/snooze`, {
333
+ method: 'POST',
334
+ body: JSON.stringify({
335
+ acting_as_agent_id: actingAgentId,
336
+ fire_at: fireAt,
337
+ }),
338
+ });
339
+ }
340
+
341
+ export async function updateAgentReminder({
342
+ actingAgentId, reminderId, title, fireAt,
343
+ }) {
344
+ return apiFetch(`/api/agent/reminders/${encodeURIComponent(reminderId)}`, {
345
+ method: 'PATCH',
346
+ body: JSON.stringify({
347
+ acting_as_agent_id: actingAgentId,
348
+ title: title ?? null,
349
+ fire_at: fireAt ?? null,
350
+ }),
351
+ });
352
+ }
292
353
 
293
- const { data } = await apiFetch('/api/assets/upload', {
354
+ export async function cancelAgentReminder({ actingAgentId, reminderId }) {
355
+ return apiFetch(`/api/agent/reminders/${encodeURIComponent(reminderId)}/cancel`, {
294
356
  method: 'POST',
295
- body: formData,
296
- timeout: 30000,
357
+ body: JSON.stringify({ acting_as_agent_id: actingAgentId }),
297
358
  });
298
- return data;
359
+ }
360
+
361
+ export async function getAgentReminderLog({ actingAgentId, reminderId }) {
362
+ const params = new URLSearchParams();
363
+ params.set('acting_as_agent_id', actingAgentId);
364
+ const { data } = await apiFetch(`/api/agent/reminders/${encodeURIComponent(reminderId)}/log?${params}`);
365
+ return data || [];
366
+ }
367
+
368
+ export async function fireDueReminders() {
369
+ // System call: no acting agent. Used by the daemon's tick.
370
+ return apiFetch('/api/agent/reminders/fire-due', {
371
+ method: 'POST',
372
+ body: '{}',
373
+ });
374
+ }
375
+
376
+ export async function checkAgentMessages({ actingAgentId, conversationId }) {
377
+ const params = new URLSearchParams();
378
+ params.set('acting_as_agent_id', actingAgentId);
379
+ if (conversationId) params.set('conversation_id', conversationId);
380
+ return apiFetch(`/api/agent/messages/check?${params}`);
381
+ }
382
+
383
+ export async function searchAgentMessages({
384
+ actingAgentId, query, conversationId, limit,
385
+ }) {
386
+ const params = new URLSearchParams();
387
+ params.set('acting_as_agent_id', actingAgentId);
388
+ params.set('q', query);
389
+ if (conversationId) params.set('conversation_id', conversationId);
390
+ if (limit != null) params.set('limit', String(limit));
391
+ const { data } = await apiFetch(`/api/agent/messages/search?${params}`);
392
+ return data || [];
393
+ }
394
+
395
+ export async function getAgentProfile({ actingAgentId, idOrHandle }) {
396
+ const params = new URLSearchParams();
397
+ params.set('acting_as_agent_id', actingAgentId);
398
+ return apiFetch(`/api/agent/profile/${encodeURIComponent(idOrHandle)}?${params}`);
399
+ }
400
+
401
+ export async function patchAgentProfile({
402
+ actingAgentId, displayName, description, avatarUrl,
403
+ }) {
404
+ return apiFetch('/api/agent/profile', {
405
+ method: 'PATCH',
406
+ body: JSON.stringify({
407
+ acting_as_agent_id: actingAgentId,
408
+ display_name: displayName ?? null,
409
+ description: description ?? null,
410
+ avatar_url: avatarUrl ?? null,
411
+ }),
412
+ });
413
+ }
414
+
415
+ export async function uploadAgentAttachment({
416
+ actingAgentId, filename, contentType, dataBase64,
417
+ }) {
418
+ return apiFetch('/api/agent/attachments', {
419
+ method: 'POST',
420
+ body: JSON.stringify({
421
+ acting_as_agent_id: actingAgentId,
422
+ filename,
423
+ content_type: contentType,
424
+ data_base64: dataBase64,
425
+ }),
426
+ });
427
+ }
428
+
429
+ export async function uploadAgentAvatar({
430
+ actingAgentId, filename, contentType, dataBase64,
431
+ }) {
432
+ return apiFetch('/api/agent/profile/avatar', {
433
+ method: 'POST',
434
+ body: JSON.stringify({
435
+ acting_as_agent_id: actingAgentId,
436
+ filename,
437
+ content_type: contentType,
438
+ data_base64: dataBase64,
439
+ }),
440
+ });
441
+ }
442
+
443
+ export async function viewAgentAttachment({ actingAgentId, assetId }) {
444
+ const params = new URLSearchParams();
445
+ params.set('acting_as_agent_id', actingAgentId);
446
+ return apiFetch(`/api/agent/attachments/${encodeURIComponent(assetId)}?${params}`);
447
+ }
448
+
449
+ export async function createAgentGroup({
450
+ actingAgentId, name, description, memberAgentIds,
451
+ }) {
452
+ return apiFetch('/api/agent/groups', {
453
+ method: 'POST',
454
+ body: JSON.stringify({
455
+ acting_as_agent_id: actingAgentId,
456
+ name,
457
+ description: description ?? null,
458
+ member_agent_ids: memberAgentIds || [],
459
+ }),
460
+ });
461
+ }
462
+
463
+ export async function addAgentGroupMembers({
464
+ actingAgentId, conversationId, agentIds,
465
+ }) {
466
+ return apiFetch(`/api/agent/groups/${encodeURIComponent(conversationId)}/members`, {
467
+ method: 'POST',
468
+ body: JSON.stringify({
469
+ acting_as_agent_id: actingAgentId,
470
+ agent_ids: agentIds,
471
+ }),
472
+ });
473
+ }
474
+
475
+ export async function removeAgentGroupMember({
476
+ actingAgentId, conversationId, agentId,
477
+ }) {
478
+ return apiFetch(
479
+ `/api/agent/groups/${encodeURIComponent(conversationId)}/members/${encodeURIComponent(agentId)}`,
480
+ {
481
+ method: 'DELETE',
482
+ body: JSON.stringify({ acting_as_agent_id: actingAgentId }),
483
+ },
484
+ );
299
485
  }
300
486
 
301
487
  // ── Channel event pipe ──
@@ -425,3 +611,15 @@ export async function getMe() {
425
611
  const { data } = await apiFetch('/api/me');
426
612
  return data || null;
427
613
  }
614
+
615
+ export async function reportHostCapabilities({ hostId, hostLabel, runtimesHealth, daemonVersion }) {
616
+ return apiFetch('/api/hosts/capabilities', {
617
+ method: 'POST',
618
+ body: JSON.stringify({
619
+ host_id: hostId,
620
+ host_label: hostLabel || null,
621
+ runtimes_health: runtimesHealth || {},
622
+ daemon_version: daemonVersion || null,
623
+ }),
624
+ });
625
+ }