ticlawk 0.1.16-dev.1 → 0.1.16-dev.3

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.
@@ -200,22 +200,86 @@ export async function handleMessageRead(req, query, ctx) {
200
200
  }
201
201
  }
202
202
 
203
+ export async function handleTaskCreate(req, body, ctx) {
204
+ const actingAgentId = getActingAgentId(req, body);
205
+ const v = validateActingAgent(actingAgentId, ctx);
206
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
207
+
208
+ const text = String(body?.text || '').trim();
209
+ if (!text) return { status: 400, body: { error: 'text is required' } };
210
+
211
+ let conversationId = body?.conversation_id || null;
212
+ if (!conversationId && body?.target) {
213
+ const resolved = await resolveTarget(actingAgentId, String(body.target));
214
+ if (resolved.error) return { status: 404, body: { error: resolved.error } };
215
+ conversationId = resolved.conversationId;
216
+ }
217
+ if (!conversationId) {
218
+ return { status: 400, body: { error: 'target or conversation_id is required' } };
219
+ }
220
+
221
+ try {
222
+ const data = await api.createAgentTask({
223
+ actingAgentId,
224
+ conversationId,
225
+ text,
226
+ title: body?.title ?? null,
227
+ });
228
+ debugLog('agent-cli', 'task.create', {
229
+ actingAgentId,
230
+ conversationId,
231
+ messageId: data?.message?.id,
232
+ taskNumber: data?.task?.number,
233
+ });
234
+ return { status: 200, body: data };
235
+ } catch (err) {
236
+ debugError('agent-cli', 'task.create.failed', {
237
+ actingAgentId,
238
+ conversationId,
239
+ error: err?.message || String(err),
240
+ });
241
+ return { status: err?.status || 500, body: { error: err?.message || 'task create failed' } };
242
+ }
243
+ }
244
+
203
245
  export async function handleTaskClaim(req, body, ctx) {
204
246
  const actingAgentId = getActingAgentId(req, body);
205
247
  const v = validateActingAgent(actingAgentId, ctx);
206
248
  if (!v.ok) return { status: v.status, body: { error: v.error } };
207
- const sourceMessageId = body?.source_message_id || body?.message_id;
208
- if (!sourceMessageId) return { status: 400, body: { error: 'source_message_id (or message_id) is required' } };
249
+ const sourceMessageId = body?.source_message_id || body?.message_id || null;
250
+ const number = body?.number != null ? Number(body.number) : null;
251
+
252
+ // Number-based claim needs the conversation_id to disambiguate. Allow
253
+ // the caller to pass either conversation_id directly or a target.
254
+ let conversationId = body?.conversation_id || null;
255
+ if (number != null && !conversationId && body?.target) {
256
+ const resolved = await resolveTarget(actingAgentId, String(body.target));
257
+ if (resolved.error) return { status: 404, body: { error: resolved.error } };
258
+ conversationId = resolved.conversationId;
259
+ }
260
+
261
+ if (!sourceMessageId && number == null) {
262
+ return { status: 400, body: { error: '--message-id or --number is required' } };
263
+ }
264
+ if (number != null && !conversationId) {
265
+ return { status: 400, body: { error: '--target or --conversation-id is required when claiming by number' } };
266
+ }
267
+
209
268
  try {
210
269
  const data = await api.claimAgentTask({
211
270
  actingAgentId,
212
271
  sourceMessageId,
272
+ conversationId,
273
+ number,
213
274
  leaseSeconds: body?.lease_seconds,
214
275
  });
215
276
  debugLog('agent-cli', 'task.claim', {
216
277
  actingAgentId,
217
- sourceMessageId,
278
+ sourceMessageId: sourceMessageId || null,
279
+ number: number ?? null,
280
+ conversationId: conversationId || null,
218
281
  claimed: data?.claimed,
282
+ taskNumber: data?.task?.number || null,
219
283
  });
220
284
  return { status: data?.claimed === false ? 409 : 200, body: data };
221
285
  } catch (err) {
@@ -223,6 +287,27 @@ export async function handleTaskClaim(req, body, ctx) {
223
287
  }
224
288
  }
225
289
 
290
+ export async function handleTaskUnclaim(req, body, ctx) {
291
+ const actingAgentId = getActingAgentId(req, body);
292
+ const v = validateActingAgent(actingAgentId, ctx);
293
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
294
+ if (!body?.task_id) return { status: 400, body: { error: 'task_id is required' } };
295
+ try {
296
+ const data = await api.unclaimAgentTask({
297
+ actingAgentId,
298
+ taskId: body.task_id,
299
+ });
300
+ debugLog('agent-cli', 'task.unclaim', {
301
+ actingAgentId,
302
+ taskId: body.task_id,
303
+ ok: data?.ok,
304
+ });
305
+ return { status: data?.ok ? 200 : 409, body: data };
306
+ } catch (err) {
307
+ return { status: err?.status || 500, body: { error: err?.message || 'unclaim failed' } };
308
+ }
309
+ }
310
+
226
311
  export async function handleTaskUpdate(req, body, ctx) {
227
312
  const actingAgentId = getActingAgentId(req, body);
228
313
  const v = validateActingAgent(actingAgentId, ctx);
@@ -276,6 +361,334 @@ export async function handleGroupMembers(req, query, ctx) {
276
361
  }
277
362
  }
278
363
 
364
+ export async function handleMessageReact(req, body, ctx) {
365
+ const actingAgentId = getActingAgentId(req, body);
366
+ const v = validateActingAgent(actingAgentId, ctx);
367
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
368
+ const messageId = body?.message_id;
369
+ const emoji = body?.emoji;
370
+ const remove = !!body?.remove;
371
+ if (!messageId) return { status: 400, body: { error: 'message_id is required' } };
372
+ if (!emoji) return { status: 400, body: { error: 'emoji is required' } };
373
+ try {
374
+ const data = await api.reactToMessage({
375
+ actingAgentId, messageId, emoji, remove,
376
+ });
377
+ debugLog('agent-cli', remove ? 'message.unreact' : 'message.react', {
378
+ actingAgentId, messageId, emoji,
379
+ });
380
+ return { status: 200, body: data };
381
+ } catch (err) {
382
+ return { status: err?.status || 500, body: { error: err?.message || 'react failed' } };
383
+ }
384
+ }
385
+
386
+ export async function handleReminderSchedule(req, body, ctx) {
387
+ const actingAgentId = getActingAgentId(req, body);
388
+ const v = validateActingAgent(actingAgentId, ctx);
389
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
390
+ if (!body?.title) return { status: 400, body: { error: 'title is required' } };
391
+ if (!body?.fire_at) return { status: 400, body: { error: 'fire_at (ISO timestamp) is required' } };
392
+
393
+ let anchorConversationId = body?.anchor_conversation_id || null;
394
+ if (!anchorConversationId && body?.target) {
395
+ const resolved = await resolveTarget(actingAgentId, String(body.target));
396
+ if (resolved.error) return { status: 404, body: { error: resolved.error } };
397
+ anchorConversationId = resolved.conversationId;
398
+ }
399
+ if (!anchorConversationId) {
400
+ return { status: 400, body: { error: '--target or --anchor-conversation-id required' } };
401
+ }
402
+
403
+ try {
404
+ const data = await api.scheduleAgentReminder({
405
+ actingAgentId,
406
+ title: body.title,
407
+ fireAt: body.fire_at,
408
+ anchorConversationId,
409
+ anchorMessageId: body?.anchor_message_id || null,
410
+ });
411
+ debugLog('agent-cli', 'reminder.schedule', {
412
+ actingAgentId,
413
+ reminderId: data?.data?.id,
414
+ fireAt: body.fire_at,
415
+ });
416
+ return { status: 200, body: data };
417
+ } catch (err) {
418
+ return { status: err?.status || 500, body: { error: err?.message || 'schedule failed' } };
419
+ }
420
+ }
421
+
422
+ export async function handleReminderList(req, query, ctx) {
423
+ const actingAgentId = getActingAgentId(req, query);
424
+ const v = validateActingAgent(actingAgentId, ctx);
425
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
426
+ try {
427
+ const data = await api.listAgentReminders({
428
+ actingAgentId,
429
+ status: query?.status || null,
430
+ });
431
+ return { status: 200, body: { data } };
432
+ } catch (err) {
433
+ return { status: err?.status || 500, body: { error: err?.message || 'list failed' } };
434
+ }
435
+ }
436
+
437
+ export async function handleReminderSnooze(req, body, ctx) {
438
+ const actingAgentId = getActingAgentId(req, body);
439
+ const v = validateActingAgent(actingAgentId, ctx);
440
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
441
+ if (!body?.reminder_id) return { status: 400, body: { error: 'reminder_id is required' } };
442
+ if (!body?.fire_at) return { status: 400, body: { error: 'fire_at is required' } };
443
+ try {
444
+ const data = await api.snoozeAgentReminder({
445
+ actingAgentId,
446
+ reminderId: body.reminder_id,
447
+ fireAt: body.fire_at,
448
+ });
449
+ return { status: 200, body: data };
450
+ } catch (err) {
451
+ return { status: err?.status || 500, body: { error: err?.message || 'snooze failed' } };
452
+ }
453
+ }
454
+
455
+ export async function handleReminderUpdate(req, body, ctx) {
456
+ const actingAgentId = getActingAgentId(req, body);
457
+ const v = validateActingAgent(actingAgentId, ctx);
458
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
459
+ if (!body?.reminder_id) return { status: 400, body: { error: 'reminder_id is required' } };
460
+ try {
461
+ const data = await api.updateAgentReminder({
462
+ actingAgentId,
463
+ reminderId: body.reminder_id,
464
+ title: body?.title || null,
465
+ fireAt: body?.fire_at || null,
466
+ });
467
+ return { status: 200, body: data };
468
+ } catch (err) {
469
+ return { status: err?.status || 500, body: { error: err?.message || 'update failed' } };
470
+ }
471
+ }
472
+
473
+ export async function handleReminderCancel(req, body, ctx) {
474
+ const actingAgentId = getActingAgentId(req, body);
475
+ const v = validateActingAgent(actingAgentId, ctx);
476
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
477
+ if (!body?.reminder_id) return { status: 400, body: { error: 'reminder_id is required' } };
478
+ try {
479
+ const data = await api.cancelAgentReminder({
480
+ actingAgentId,
481
+ reminderId: body.reminder_id,
482
+ });
483
+ return { status: 200, body: data };
484
+ } catch (err) {
485
+ return { status: err?.status || 500, body: { error: err?.message || 'cancel failed' } };
486
+ }
487
+ }
488
+
489
+ export async function handleReminderLog(req, query, ctx) {
490
+ const actingAgentId = getActingAgentId(req, query);
491
+ const v = validateActingAgent(actingAgentId, ctx);
492
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
493
+ if (!query?.reminder_id) return { status: 400, body: { error: 'reminder_id is required' } };
494
+ try {
495
+ const data = await api.getAgentReminderLog({
496
+ actingAgentId,
497
+ reminderId: query.reminder_id,
498
+ });
499
+ return { status: 200, body: { data } };
500
+ } catch (err) {
501
+ return { status: err?.status || 500, body: { error: err?.message || 'log failed' } };
502
+ }
503
+ }
504
+
505
+ export async function handleMessageCheck(req, query, ctx) {
506
+ const actingAgentId = getActingAgentId(req, query);
507
+ const v = validateActingAgent(actingAgentId, ctx);
508
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
509
+ let conversationId = query?.conversation_id || null;
510
+ if (!conversationId && query?.target) {
511
+ const resolved = await resolveTarget(actingAgentId, String(query.target));
512
+ if (!resolved.error) conversationId = resolved.conversationId;
513
+ }
514
+ try {
515
+ const data = await api.checkAgentMessages({ actingAgentId, conversationId });
516
+ return { status: 200, body: data };
517
+ } catch (err) {
518
+ return { status: err?.status || 500, body: { error: err?.message || 'check failed' } };
519
+ }
520
+ }
521
+
522
+ export async function handleMessageSearch(req, query, ctx) {
523
+ const actingAgentId = getActingAgentId(req, query);
524
+ const v = validateActingAgent(actingAgentId, ctx);
525
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
526
+ if (!query?.q) return { status: 400, body: { error: 'q is required' } };
527
+ let conversationId = query?.conversation_id || null;
528
+ if (!conversationId && query?.target) {
529
+ const resolved = await resolveTarget(actingAgentId, String(query.target));
530
+ if (!resolved.error) conversationId = resolved.conversationId;
531
+ }
532
+ try {
533
+ const data = await api.searchAgentMessages({
534
+ actingAgentId,
535
+ query: query.q,
536
+ conversationId,
537
+ limit: query?.limit != null ? Number(query.limit) : null,
538
+ });
539
+ return { status: 200, body: { data } };
540
+ } catch (err) {
541
+ return { status: err?.status || 500, body: { error: err?.message || 'search failed' } };
542
+ }
543
+ }
544
+
545
+ export async function handleProfileShow(req, query, ctx) {
546
+ const actingAgentId = getActingAgentId(req, query);
547
+ const v = validateActingAgent(actingAgentId, ctx);
548
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
549
+ const idOrHandle = query?.id || query?.handle || actingAgentId;
550
+ try {
551
+ const data = await api.getAgentProfile({ actingAgentId, idOrHandle });
552
+ return { status: 200, body: data };
553
+ } catch (err) {
554
+ return { status: err?.status || 500, body: { error: err?.message || 'profile show failed' } };
555
+ }
556
+ }
557
+
558
+ export async function handleProfileUpdate(req, body, ctx) {
559
+ const actingAgentId = getActingAgentId(req, body);
560
+ const v = validateActingAgent(actingAgentId, ctx);
561
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
562
+ try {
563
+ const data = await api.patchAgentProfile({
564
+ actingAgentId,
565
+ displayName: body?.display_name ?? null,
566
+ description: body?.description ?? null,
567
+ avatarUrl: body?.avatar_url ?? null,
568
+ });
569
+ debugLog('agent-cli', 'profile.update', { actingAgentId, keys: Object.keys(body || {}) });
570
+ return { status: 200, body: data };
571
+ } catch (err) {
572
+ return { status: err?.status || 500, body: { error: err?.message || 'profile update failed' } };
573
+ }
574
+ }
575
+
576
+ export async function handleAttachmentUpload(req, body, ctx) {
577
+ const actingAgentId = getActingAgentId(req, body);
578
+ const v = validateActingAgent(actingAgentId, ctx);
579
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
580
+ if (!body?.data_base64) return { status: 400, body: { error: 'data_base64 is required' } };
581
+ try {
582
+ const data = await api.uploadAgentAttachment({
583
+ actingAgentId,
584
+ filename: body?.filename || 'attachment.bin',
585
+ contentType: body?.content_type || 'application/octet-stream',
586
+ dataBase64: body.data_base64,
587
+ });
588
+ debugLog('agent-cli', 'attachment.upload', {
589
+ actingAgentId,
590
+ asset_id: data?.asset?.asset_id,
591
+ bytes: data?.asset?.size_bytes,
592
+ });
593
+ return { status: 200, body: data };
594
+ } catch (err) {
595
+ return { status: err?.status || 500, body: { error: err?.message || 'attachment upload failed' } };
596
+ }
597
+ }
598
+
599
+ export async function handleAttachmentView(req, query, ctx) {
600
+ const actingAgentId = getActingAgentId(req, query);
601
+ const v = validateActingAgent(actingAgentId, ctx);
602
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
603
+ const assetId = query?.asset_id;
604
+ if (!assetId) return { status: 400, body: { error: 'asset_id is required' } };
605
+ try {
606
+ const data = await api.viewAgentAttachment({ actingAgentId, assetId });
607
+ return { status: 200, body: data };
608
+ } catch (err) {
609
+ return { status: err?.status || 500, body: { error: err?.message || 'attachment view failed' } };
610
+ }
611
+ }
612
+
613
+ export async function handleGroupCreate(req, body, ctx) {
614
+ const actingAgentId = getActingAgentId(req, body);
615
+ const v = validateActingAgent(actingAgentId, ctx);
616
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
617
+ const name = String(body?.name || '').trim();
618
+ if (!name) return { status: 400, body: { error: 'name is required' } };
619
+ try {
620
+ const data = await api.createAgentGroup({
621
+ actingAgentId,
622
+ name,
623
+ description: body?.description || null,
624
+ memberAgentIds: Array.isArray(body?.member_agent_ids) ? body.member_agent_ids : [],
625
+ });
626
+ invalidateServerInfoCache(actingAgentId);
627
+ debugLog('agent-cli', 'group.create', {
628
+ actingAgentId,
629
+ conversationId: data?.conversation?.id,
630
+ members: data?.member_agent_ids,
631
+ });
632
+ return { status: 200, body: data };
633
+ } catch (err) {
634
+ return { status: err?.status || 500, body: { error: err?.message || 'group create failed' } };
635
+ }
636
+ }
637
+
638
+ export async function handleGroupMembersAdd(req, body, ctx) {
639
+ const actingAgentId = getActingAgentId(req, body);
640
+ const v = validateActingAgent(actingAgentId, ctx);
641
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
642
+ let conversationId = body?.conversation_id || null;
643
+ if (!conversationId && body?.target) {
644
+ const resolved = await resolveTarget(actingAgentId, String(body.target));
645
+ if (resolved.error) return { status: 404, body: { error: resolved.error } };
646
+ conversationId = resolved.conversationId;
647
+ }
648
+ if (!conversationId) return { status: 400, body: { error: 'target or conversation_id is required' } };
649
+ const agentIds = Array.isArray(body?.agent_ids) ? body.agent_ids : [];
650
+ if (agentIds.length === 0) return { status: 400, body: { error: 'agent_ids must be non-empty' } };
651
+ try {
652
+ const data = await api.addAgentGroupMembers({
653
+ actingAgentId, conversationId, agentIds,
654
+ });
655
+ invalidateServerInfoCache(actingAgentId);
656
+ debugLog('agent-cli', 'group.members.add', {
657
+ actingAgentId, conversationId, agentIds,
658
+ });
659
+ return { status: 200, body: data };
660
+ } catch (err) {
661
+ return { status: err?.status || 500, body: { error: err?.message || 'add failed' } };
662
+ }
663
+ }
664
+
665
+ export async function handleGroupMembersRemove(req, body, ctx) {
666
+ const actingAgentId = getActingAgentId(req, body);
667
+ const v = validateActingAgent(actingAgentId, ctx);
668
+ if (!v.ok) return { status: v.status, body: { error: v.error } };
669
+ let conversationId = body?.conversation_id || null;
670
+ if (!conversationId && body?.target) {
671
+ const resolved = await resolveTarget(actingAgentId, String(body.target));
672
+ if (resolved.error) return { status: 404, body: { error: resolved.error } };
673
+ conversationId = resolved.conversationId;
674
+ }
675
+ if (!conversationId) return { status: 400, body: { error: 'target or conversation_id is required' } };
676
+ const agentId = body?.agent_id;
677
+ if (!agentId) return { status: 400, body: { error: 'agent_id is required' } };
678
+ try {
679
+ const data = await api.removeAgentGroupMember({
680
+ actingAgentId, conversationId, agentId,
681
+ });
682
+ invalidateServerInfoCache(actingAgentId);
683
+ debugLog('agent-cli', 'group.members.remove', {
684
+ actingAgentId, conversationId, agentId,
685
+ });
686
+ return { status: 200, body: data };
687
+ } catch (err) {
688
+ return { status: err?.status || 500, body: { error: err?.message || 'remove failed' } };
689
+ }
690
+ }
691
+
279
692
  export async function handleServerInfo(req, query, ctx) {
280
693
  const actingAgentId = getActingAgentId(req, query);
281
694
  const v = validateActingAgent(actingAgentId, ctx);
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Per-agent slock-style home directory: ~/.ticlawk/agents/<agent_id>/
3
+ *
4
+ * This is the agent's authoritative workspace. The daemon spawns every
5
+ * runtime with this as cwd; the agent's MEMORY.md, notes/, and any
6
+ * artifacts it produces live here. No project binding.
7
+ *
8
+ * Following slock's daemon model (dist/chunk-M4A5QPUN.js:5079) —
9
+ * dataDir = ~/.slock/agents, agentDataDir = <dataDir>/<id>, and every
10
+ * driver.spawn() receives `workingDirectory: agentDataDir`. One MEMORY.md
11
+ * per agent, lives in cwd, agent reads it via `cat MEMORY.md`.
12
+ */
13
+
14
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+ import { AF_HOME } from './config.mjs';
17
+
18
+ export const AF_AGENTS_DIR = join(AF_HOME, 'agents');
19
+
20
+ export function getAgentHome(agentId) {
21
+ if (!agentId) throw new Error('getAgentHome: agentId is required');
22
+ return join(AF_AGENTS_DIR, String(agentId));
23
+ }
24
+
25
+ export function getAgentMemoryPath(agentId) {
26
+ return join(getAgentHome(agentId), 'MEMORY.md');
27
+ }
28
+
29
+ /**
30
+ * Make sure the agent home dir exists + has a starter MEMORY.md. Idempotent;
31
+ * safe to call on every spawn. The daemon does this before driver.spawn()
32
+ * so cwd is always a real, writable directory.
33
+ *
34
+ * Pass `displayName` only when seeding for the first time — existing
35
+ * MEMORY.md is never overwritten (the agent owns it).
36
+ */
37
+ export function ensureAgentHome(agentId, { displayName } = {}) {
38
+ const home = getAgentHome(agentId);
39
+ mkdirSync(home, { recursive: true });
40
+ const memoryPath = getAgentMemoryPath(agentId);
41
+ if (!existsSync(memoryPath)) {
42
+ writeFileSync(memoryPath, buildInitialMemoryMd({ displayName, home }), 'utf8');
43
+ }
44
+ return home;
45
+ }
46
+
47
+ function buildInitialMemoryMd({ displayName, home }) {
48
+ const lines = [
49
+ `# ${displayName || 'Agent'}`,
50
+ '',
51
+ '## Role',
52
+ '<your role definition, evolved over time>',
53
+ '',
54
+ '## Workspace',
55
+ home,
56
+ '',
57
+ ];
58
+ lines.push(
59
+ '## Key Knowledge',
60
+ '- (none yet — populate as you learn the user, project, and domain)',
61
+ '',
62
+ '## Active Context',
63
+ '- (none)',
64
+ '',
65
+ '## How to update this file',
66
+ 'MEMORY.md is your entry point. Read it at the top of every turn. Add a',
67
+ '`notes/<topic>.md` for each long-lived knowledge area and link it here.',
68
+ '',
69
+ );
70
+ return lines.join('\n');
71
+ }
72
+
73
+ /**
74
+ * Best-effort read of the "## Workspace" line from a MEMORY.md. Useful
75
+ * if some code wants to know where the agent currently believes it
76
+ * works (e.g. for UI display). The daemon does NOT use this for spawn
77
+ * cwd — spawn cwd is always getAgentHome(id).
78
+ */
79
+ export function readWorkspaceFromMemory(agentId) {
80
+ const memoryPath = getAgentMemoryPath(agentId);
81
+ if (!existsSync(memoryPath)) return null;
82
+ try {
83
+ const text = readFileSync(memoryPath, 'utf8');
84
+ const m = text.match(/^##\s+Workspace\s*\n([^\n]+)/m);
85
+ return m ? m[1].trim() : null;
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
package/src/core/http.mjs CHANGED
@@ -1,11 +1,29 @@
1
1
  import { createServer } from 'node:http';
2
2
  import {
3
+ handleAttachmentUpload,
4
+ handleAttachmentView,
5
+ handleGroupCreate,
3
6
  handleGroupMembers,
7
+ handleGroupMembersAdd,
8
+ handleGroupMembersRemove,
9
+ handleMessageCheck,
10
+ handleMessageReact,
4
11
  handleMessageRead,
12
+ handleMessageSearch,
5
13
  handleMessageSend,
14
+ handleProfileShow,
15
+ handleProfileUpdate,
16
+ handleReminderCancel,
17
+ handleReminderList,
18
+ handleReminderLog,
19
+ handleReminderSchedule,
20
+ handleReminderSnooze,
21
+ handleReminderUpdate,
6
22
  handleServerInfo,
7
23
  handleTaskClaim,
24
+ handleTaskCreate,
8
25
  handleTaskList,
26
+ handleTaskUnclaim,
9
27
  handleTaskUpdate,
10
28
  } from './agent-cli-handlers.mjs';
11
29
 
@@ -78,12 +96,24 @@ export function startLocalHttpServer({ port, adapter, ctx }) {
78
96
  const r = await handleMessageRead(req, parseQuery(req.url || ''), cliCtx);
79
97
  return writeJson(res, r.status, r.body);
80
98
  }
99
+ if (urlNoQuery === '/agent/task/create' && method === 'POST') {
100
+ const body = await readJsonBody(req);
101
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
102
+ const r = await handleTaskCreate(req, body, cliCtx);
103
+ return writeJson(res, r.status, r.body);
104
+ }
81
105
  if (urlNoQuery === '/agent/task/claim' && method === 'POST') {
82
106
  const body = await readJsonBody(req);
83
107
  if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
84
108
  const r = await handleTaskClaim(req, body, cliCtx);
85
109
  return writeJson(res, r.status, r.body);
86
110
  }
111
+ if (urlNoQuery === '/agent/task/unclaim' && method === 'POST') {
112
+ const body = await readJsonBody(req);
113
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
114
+ const r = await handleTaskUnclaim(req, body, cliCtx);
115
+ return writeJson(res, r.status, r.body);
116
+ }
87
117
  if (urlNoQuery === '/agent/task/update' && method === 'POST') {
88
118
  const body = await readJsonBody(req);
89
119
  if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
@@ -94,10 +124,94 @@ export function startLocalHttpServer({ port, adapter, ctx }) {
94
124
  const r = await handleTaskList(req, parseQuery(req.url || ''), cliCtx);
95
125
  return writeJson(res, r.status, r.body);
96
126
  }
127
+ if (urlNoQuery === '/agent/message/react' && method === 'POST') {
128
+ const body = await readJsonBody(req);
129
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
130
+ const r = await handleMessageReact(req, body, cliCtx);
131
+ return writeJson(res, r.status, r.body);
132
+ }
133
+ if (urlNoQuery === '/agent/message/check' && method === 'GET') {
134
+ const r = await handleMessageCheck(req, parseQuery(req.url || ''), cliCtx);
135
+ return writeJson(res, r.status, r.body);
136
+ }
137
+ if (urlNoQuery === '/agent/message/search' && method === 'GET') {
138
+ const r = await handleMessageSearch(req, parseQuery(req.url || ''), cliCtx);
139
+ return writeJson(res, r.status, r.body);
140
+ }
141
+ if (urlNoQuery === '/agent/profile/show' && method === 'GET') {
142
+ const r = await handleProfileShow(req, parseQuery(req.url || ''), cliCtx);
143
+ return writeJson(res, r.status, r.body);
144
+ }
145
+ if (urlNoQuery === '/agent/profile/update' && method === 'POST') {
146
+ const body = await readJsonBody(req);
147
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
148
+ const r = await handleProfileUpdate(req, body, cliCtx);
149
+ return writeJson(res, r.status, r.body);
150
+ }
151
+ if (urlNoQuery === '/agent/attachment/upload' && method === 'POST') {
152
+ const body = await readJsonBody(req);
153
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
154
+ const r = await handleAttachmentUpload(req, body, cliCtx);
155
+ return writeJson(res, r.status, r.body);
156
+ }
157
+ if (urlNoQuery === '/agent/attachment/view' && method === 'GET') {
158
+ const r = await handleAttachmentView(req, parseQuery(req.url || ''), cliCtx);
159
+ return writeJson(res, r.status, r.body);
160
+ }
161
+ if (urlNoQuery === '/agent/reminder/schedule' && method === 'POST') {
162
+ const body = await readJsonBody(req);
163
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
164
+ const r = await handleReminderSchedule(req, body, cliCtx);
165
+ return writeJson(res, r.status, r.body);
166
+ }
167
+ if (urlNoQuery === '/agent/reminder/list' && method === 'GET') {
168
+ const r = await handleReminderList(req, parseQuery(req.url || ''), cliCtx);
169
+ return writeJson(res, r.status, r.body);
170
+ }
171
+ if (urlNoQuery === '/agent/reminder/snooze' && method === 'POST') {
172
+ const body = await readJsonBody(req);
173
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
174
+ const r = await handleReminderSnooze(req, body, cliCtx);
175
+ return writeJson(res, r.status, r.body);
176
+ }
177
+ if (urlNoQuery === '/agent/reminder/update' && method === 'POST') {
178
+ const body = await readJsonBody(req);
179
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
180
+ const r = await handleReminderUpdate(req, body, cliCtx);
181
+ return writeJson(res, r.status, r.body);
182
+ }
183
+ if (urlNoQuery === '/agent/reminder/cancel' && method === 'POST') {
184
+ const body = await readJsonBody(req);
185
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
186
+ const r = await handleReminderCancel(req, body, cliCtx);
187
+ return writeJson(res, r.status, r.body);
188
+ }
189
+ if (urlNoQuery === '/agent/reminder/log' && method === 'GET') {
190
+ const r = await handleReminderLog(req, parseQuery(req.url || ''), cliCtx);
191
+ return writeJson(res, r.status, r.body);
192
+ }
97
193
  if (urlNoQuery === '/agent/group/members' && method === 'GET') {
98
194
  const r = await handleGroupMembers(req, parseQuery(req.url || ''), cliCtx);
99
195
  return writeJson(res, r.status, r.body);
100
196
  }
197
+ if (urlNoQuery === '/agent/group/create' && method === 'POST') {
198
+ const body = await readJsonBody(req);
199
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
200
+ const r = await handleGroupCreate(req, body, cliCtx);
201
+ return writeJson(res, r.status, r.body);
202
+ }
203
+ if (urlNoQuery === '/agent/group/members/add' && method === 'POST') {
204
+ const body = await readJsonBody(req);
205
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
206
+ const r = await handleGroupMembersAdd(req, body, cliCtx);
207
+ return writeJson(res, r.status, r.body);
208
+ }
209
+ if (urlNoQuery === '/agent/group/members/remove' && method === 'POST') {
210
+ const body = await readJsonBody(req);
211
+ if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
212
+ const r = await handleGroupMembersRemove(req, body, cliCtx);
213
+ return writeJson(res, r.status, r.body);
214
+ }
101
215
  if (urlNoQuery === '/agent/server/info' && method === 'GET') {
102
216
  const r = await handleServerInfo(req, parseQuery(req.url || ''), cliCtx);
103
217
  return writeJson(res, r.status, r.body);