clawmatrix 0.1.23 → 0.2.0

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/src/types.ts CHANGED
@@ -12,11 +12,33 @@ export interface ClusterFrame {
12
12
  // ── Auth messages ──────────────────────────────────────────────────
13
13
  export interface AuthChallenge extends ClusterFrame {
14
14
  type: "auth_challenge";
15
- payload: { nonce: string };
15
+ payload: { nonce: string; publicKey?: string };
16
16
  }
17
17
 
18
+ /** Legacy plaintext auth (used when E2EE is disabled). */
18
19
  export interface AuthRequest extends ClusterFrame {
19
20
  type: "auth";
21
+ payload: {
22
+ nodeId: string;
23
+ sig: string;
24
+ publicKey?: string;
25
+ agents?: AgentInfo[];
26
+ models?: ModelInfo[];
27
+ tags?: string[];
28
+ deviceInfo?: DeviceInfo;
29
+ toolProxy?: ToolProxyInfo;
30
+ };
31
+ }
32
+
33
+ /** Phase 2 of E2EE handshake: client sends its public key (plaintext). */
34
+ export interface AuthKeyExchange extends ClusterFrame {
35
+ type: "auth_key_exchange";
36
+ payload: { publicKey: string };
37
+ }
38
+
39
+ /** Phase 3 of E2EE handshake: client sends encrypted HMAC + capabilities. */
40
+ export interface AuthVerify extends ClusterFrame {
41
+ type: "auth_verify";
20
42
  payload: {
21
43
  nodeId: string;
22
44
  sig: string;
@@ -115,6 +137,8 @@ export interface ModelResponse extends ClusterFrame {
115
137
  payload: {
116
138
  success: boolean;
117
139
  content?: string;
140
+ /** Reasoning/thinking content from models like DeepSeek. */
141
+ reasoning?: string;
118
142
  /** Full message object from upstream (choices[0].message or responses output).
119
143
  * Carries tool_calls, refusal, etc. that `content` alone cannot represent. */
120
144
  message?: unknown;
@@ -128,6 +152,8 @@ export interface ModelStreamChunk extends ClusterFrame {
128
152
  id: string;
129
153
  payload: {
130
154
  delta: string;
155
+ /** Reasoning/thinking delta from models like DeepSeek (reasoning_content). */
156
+ reasoningDelta?: string;
131
157
  /** Full delta object from upstream (choices[0].delta).
132
158
  * Carries tool_calls chunks that `delta` string cannot represent. */
133
159
  deltaObj?: unknown;
@@ -136,6 +162,14 @@ export interface ModelStreamChunk extends ClusterFrame {
136
162
  };
137
163
  }
138
164
 
165
+ // ── Image content ─────────────────────────────────────────────────
166
+ export interface ImageContent {
167
+ /** Base64-encoded image data (without data URI prefix) */
168
+ data: string;
169
+ /** MIME type, e.g. "image/png", "image/jpeg" */
170
+ mediaType: string;
171
+ }
172
+
139
173
  // ── Handoff ────────────────────────────────────────────────────────
140
174
  export type HandoffStatus = "working" | "input_required" | "completed" | "failed" | "canceled";
141
175
 
@@ -152,6 +186,8 @@ export interface HandoffRequest extends ClusterFrame {
152
186
  target: string;
153
187
  task: string;
154
188
  context?: string;
189
+ sessionId?: string; // Reuse session for multi-turn conversation
190
+ images?: ImageContent[];
155
191
  };
156
192
  }
157
193
 
@@ -177,6 +213,7 @@ export interface HandoffResponse extends ClusterFrame {
177
213
  artifacts?: Artifact[];
178
214
  inputRequired?: boolean;
179
215
  handoffId?: string;
216
+ sessionId?: string; // For multi-turn conversation reuse
180
217
  };
181
218
  }
182
219
 
@@ -216,6 +253,7 @@ export interface HandoffInput extends ClusterFrame {
216
253
  id: string;
217
254
  payload: {
218
255
  message: string;
256
+ images?: ImageContent[];
219
257
  };
220
258
  }
221
259
 
@@ -248,6 +286,36 @@ export interface ToolProxyResponse extends ClusterFrame {
248
286
  };
249
287
  }
250
288
 
289
+ // ── Tool batch proxy ──────────────────────────────────────────────
290
+ export interface ToolBatchItem {
291
+ tool: string;
292
+ params: Record<string, unknown>;
293
+ }
294
+
295
+ export interface ToolBatchResultItem {
296
+ tool: string;
297
+ success: boolean;
298
+ result?: Record<string, unknown>;
299
+ error?: string;
300
+ }
301
+
302
+ export interface ToolBatchRequest extends ClusterFrame {
303
+ type: "tool_batch_req";
304
+ id: string;
305
+ payload: {
306
+ items: ToolBatchItem[];
307
+ stopOnError?: boolean; // default true
308
+ };
309
+ }
310
+
311
+ export interface ToolBatchResponse extends ClusterFrame {
312
+ type: "tool_batch_res";
313
+ id: string;
314
+ payload: {
315
+ results: ToolBatchResultItem[];
316
+ };
317
+ }
318
+
251
319
  // ── Device info ───────────────────────────────────────────────────
252
320
  export interface DeviceInfo {
253
321
  os: string; // e.g. "Darwin 24.6.0", "Linux 6.1.0"
@@ -285,6 +353,7 @@ export interface ModelInfo {
285
353
  id: string;
286
354
  provider: string;
287
355
  description?: string;
356
+ input?: ("text" | "image")[];
288
357
  compat?: ModelCompatInfo;
289
358
  }
290
359
 
@@ -294,6 +363,11 @@ export interface ToolProxyInfo {
294
363
  deny: string[];
295
364
  }
296
365
 
366
+ export interface AcpAgentInfo {
367
+ id: string;
368
+ description: string;
369
+ }
370
+
297
371
  export interface PeerInfo {
298
372
  nodeId: string;
299
373
  agents: AgentInfo[];
@@ -303,6 +377,8 @@ export interface PeerInfo {
303
377
  directPeers?: string[]; // nodeIds this node has direct connections to
304
378
  deviceInfo?: DeviceInfo; // system/hardware info
305
379
  toolProxy?: ToolProxyInfo;
380
+ acpAgents?: AcpAgentInfo[]; // ACP agents available on this node
381
+ latencyMs?: number; // heartbeat RTT (direct) or estimated round-trip (relay)
306
382
  }
307
383
 
308
384
  export interface NodeCapabilities {
@@ -312,6 +388,7 @@ export interface NodeCapabilities {
312
388
  tags: string[];
313
389
  deviceInfo?: DeviceInfo;
314
390
  toolProxy?: ToolProxyInfo;
391
+ acpAgents?: AcpAgentInfo[];
315
392
  }
316
393
 
317
394
  // ── Ingested events (from Shortcuts automations, etc.) ────────────
@@ -328,7 +405,367 @@ export interface IngestedEvent {
328
405
  export interface KnowledgeSyncFrame extends ClusterFrame {
329
406
  type: "knowledge_sync";
330
407
  payload: {
331
- data: string; // base64-encoded Automerge sync message
408
+ docId: string; // "" = registry, otherwise file relPath
409
+ data: string; // base64-encoded Automerge sync message
410
+ };
411
+ }
412
+
413
+ // ── Diagnostic (sentinel) ────────────────────────────────────────
414
+ export interface DiagnosticExec extends ClusterFrame {
415
+ type: "diagnostic_exec";
416
+ id: string;
417
+ payload: {
418
+ command: string;
419
+ timeout?: number; // seconds, default 30
420
+ };
421
+ }
422
+
423
+ export interface DiagnosticExecResponse extends ClusterFrame {
424
+ type: "diagnostic_exec_res";
425
+ id: string;
426
+ payload: {
427
+ success: boolean;
428
+ exitCode?: number;
429
+ stdout?: string;
430
+ stderr?: string;
431
+ error?: string;
432
+ };
433
+ }
434
+
435
+ export interface DiagnosticStatus extends ClusterFrame {
436
+ type: "diagnostic_status";
437
+ id: string;
438
+ }
439
+
440
+ export interface DiagnosticStatusResponse extends ClusterFrame {
441
+ type: "diagnostic_status_res";
442
+ id: string;
443
+ payload: {
444
+ gatewayAlive: boolean;
445
+ uptimeMs: number;
446
+ pid: number;
447
+ gatewayPid?: number;
448
+ };
449
+ }
450
+
451
+ // ── ACP proxy ─────────────────────────────────────────────────────
452
+ export type AcpSessionMode = "oneshot" | "persistent";
453
+
454
+ export interface AcpTaskRequest extends ClusterFrame {
455
+ type: "acp_req";
456
+ id: string;
457
+ payload: {
458
+ agent: string; // ACP harness: "claude", "codex", "gemini", etc.
459
+ task?: string; // prompt to execute (omit to create session without prompting)
460
+ sessionId?: string; // existing session ID for follow-up (persistent mode)
461
+ acpSessionId?: string; // ACP-level session ID for resume when sessionId is stale
462
+ mode?: AcpSessionMode; // default: "oneshot"
463
+ cwd?: string; // working directory on remote node
464
+ images?: ImageContent[];
465
+ };
466
+ }
467
+
468
+ export interface AcpStreamChunk extends ClusterFrame {
469
+ type: "acp_stream";
470
+ id: string;
471
+ payload: {
472
+ delta: string;
473
+ event?: string; // "agent_message_chunk" | "tool_call" | etc.
474
+ done: boolean;
475
+ };
476
+ }
477
+
478
+ export interface AcpTaskResponse extends ClusterFrame {
479
+ type: "acp_res";
480
+ id: string;
481
+ payload: {
482
+ success: boolean;
483
+ nodeId?: string;
484
+ agent?: string;
485
+ result?: string;
486
+ sessionId?: string; // returned for persistent sessions
487
+ acpSessionId?: string; // ACP-level session ID for future resume
488
+ stopReason?: string; // ACP stop reason
489
+ error?: string;
490
+ };
491
+ }
492
+
493
+ export interface AcpCloseRequest extends ClusterFrame {
494
+ type: "acp_close";
495
+ id: string;
496
+ payload: {
497
+ sessionId: string;
498
+ };
499
+ }
500
+
501
+ export interface AcpCloseResponse extends ClusterFrame {
502
+ type: "acp_close_res";
503
+ id: string;
504
+ payload: {
505
+ success: boolean;
506
+ error?: string;
507
+ };
508
+ }
509
+
510
+ // ── ACP session management ──────────────────────────────────────
511
+ export interface AcpSessionInfo {
512
+ sessionId: string;
513
+ cwd: string;
514
+ title?: string;
515
+ description?: string; // first user message (for display in session list)
516
+ updatedAt?: string;
517
+ agent?: string; // which ACP agent (claude, codex, etc.)
518
+ }
519
+
520
+ export interface AcpListRequest extends ClusterFrame {
521
+ type: "acp_list_req";
522
+ id: string;
523
+ payload: {
524
+ agent?: string; // filter by agent type
525
+ cwd?: string; // filter by working directory
526
+ };
527
+ }
528
+
529
+ export interface AcpListResponse extends ClusterFrame {
530
+ type: "acp_list_res";
531
+ id: string;
532
+ payload: {
533
+ success: boolean;
534
+ sessions?: AcpSessionInfo[];
535
+ error?: string;
536
+ };
537
+ }
538
+
539
+ export interface AcpResumeRequest extends ClusterFrame {
540
+ type: "acp_resume_req";
541
+ id: string;
542
+ payload: {
543
+ agent: string;
544
+ acpSessionId: string; // the ACP protocol session ID to resume
545
+ cwd: string;
546
+ };
547
+ }
548
+
549
+ export interface AcpResumeResponse extends ClusterFrame {
550
+ type: "acp_resume_res";
551
+ id: string;
552
+ payload: {
553
+ success: boolean;
554
+ sessionId?: string; // ClawMatrix session ID for follow-up prompts
555
+ error?: string;
556
+ };
557
+ }
558
+
559
+ export interface AcpCancelRequest extends ClusterFrame {
560
+ type: "acp_cancel";
561
+ id: string;
562
+ payload: {
563
+ sessionId: string; // ClawMatrix session ID
564
+ };
565
+ }
566
+
567
+ export interface AcpCancelResponse extends ClusterFrame {
568
+ type: "acp_cancel_res";
569
+ id: string;
570
+ payload: {
571
+ success: boolean;
572
+ error?: string;
573
+ };
574
+ }
575
+
576
+ export interface AcpModeInfo {
577
+ id: string;
578
+ name: string;
579
+ description?: string;
580
+ }
581
+
582
+ export interface AcpSetModeRequest extends ClusterFrame {
583
+ type: "acp_set_mode";
584
+ id: string;
585
+ payload: {
586
+ sessionId: string; // ClawMatrix session ID
587
+ modeId: string; // e.g. "code", "architect", "ask"
588
+ };
589
+ }
590
+
591
+ export interface AcpSetModeResponse extends ClusterFrame {
592
+ type: "acp_set_mode_res";
593
+ id: string;
594
+ payload: {
595
+ success: boolean;
596
+ error?: string;
597
+ };
598
+ }
599
+
600
+ export interface AcpGetModesRequest extends ClusterFrame {
601
+ type: "acp_get_modes";
602
+ id: string;
603
+ payload: {
604
+ sessionId: string;
605
+ };
606
+ }
607
+
608
+ export interface AcpGetModesResponse extends ClusterFrame {
609
+ type: "acp_get_modes_res";
610
+ id: string;
611
+ payload: {
612
+ success: boolean;
613
+ modes?: AcpModeInfo[];
614
+ currentModeId?: string;
615
+ error?: string;
616
+ };
617
+ }
618
+
619
+ // ── Chat history ──────────────────────────────────────────────────
620
+
621
+ export interface ChatHistoryMessage {
622
+ role: "user" | "assistant" | "system" | "tool";
623
+ text: string;
624
+ thinking?: string;
625
+ toolName?: string;
626
+ toolArgs?: string;
627
+ toolResult?: string;
628
+ images?: Array<{ data: string; mediaType: string }>;
629
+ timestamp?: number;
630
+ }
631
+
632
+ export interface ChatHistoryRequest extends ClusterFrame {
633
+ type: "chat_history_req";
634
+ id: string;
635
+ payload: {
636
+ sessionId: string;
637
+ limit?: number;
638
+ };
639
+ }
640
+
641
+ export interface ChatHistoryResponse extends ClusterFrame {
642
+ type: "chat_history_res";
643
+ id: string;
644
+ payload: {
645
+ success: boolean;
646
+ messages?: ChatHistoryMessage[];
647
+ error?: string;
648
+ };
649
+ }
650
+
651
+ // ── Task activity (Live Activity push to mobile nodes) ───────────
652
+
653
+ export type TaskActivityStatus = "started" | "progress" | "completed" | "failed";
654
+
655
+ export interface TaskActivityFrame extends ClusterFrame {
656
+ type: "task_activity";
657
+ payload: {
658
+ taskId: string;
659
+ taskType: "acp" | "handoff";
660
+ status: TaskActivityStatus;
661
+ agent: string;
662
+ nodeId: string; // node where task is running
663
+ title: string;
664
+ detail?: string;
665
+ progress?: number; // 0.0 - 1.0
666
+ startedAt: number;
667
+ elapsedMs?: number;
668
+ tool?: string; // current tool being executed
669
+ toolDone?: boolean;
670
+ };
671
+ }
672
+
673
+ // ── Peer approval ────────────────────────────────────────────────
674
+ export interface PeerApprovalNotify extends ClusterFrame {
675
+ type: "peer_approval_notify";
676
+ payload: {
677
+ approvalId: string;
678
+ nodeId: string;
679
+ deviceInfo?: DeviceInfo;
680
+ mode: "notify" | "required";
681
+ ip?: string;
682
+ /** Present when this is a resolution notification (approved/denied). */
683
+ resolution?: {
684
+ decision: "approve" | "deny";
685
+ resolvedBy: string;
686
+ };
687
+ };
688
+ }
689
+
690
+ export interface PeerApprovalRequest extends ClusterFrame {
691
+ type: "peer_approval_req";
692
+ id: string;
693
+ payload: {
694
+ approvalId: string;
695
+ nodeId: string;
696
+ deviceInfo?: DeviceInfo;
697
+ ip?: string;
698
+ };
699
+ }
700
+
701
+ export interface PeerApprovalResponse extends ClusterFrame {
702
+ type: "peer_approval_res";
703
+ id: string;
704
+ payload: {
705
+ approvalId: string;
706
+ decision: "approve" | "deny";
707
+ };
708
+ }
709
+
710
+ // ── Terminal (interactive PTY over WebSocket) ─────────────────────
711
+
712
+ export interface TerminalOpenRequest extends ClusterFrame {
713
+ type: "terminal_open";
714
+ id: string;
715
+ payload: {
716
+ shell?: string;
717
+ cols?: number;
718
+ rows?: number;
719
+ cwd?: string;
720
+ env?: Record<string, string>;
721
+ };
722
+ }
723
+
724
+ export interface TerminalOpenResponse extends ClusterFrame {
725
+ type: "terminal_open_res";
726
+ id: string;
727
+ payload: {
728
+ success: boolean;
729
+ sessionId?: string;
730
+ error?: string;
731
+ };
732
+ }
733
+
734
+ export interface TerminalData extends ClusterFrame {
735
+ type: "terminal_data";
736
+ id: string;
737
+ payload: {
738
+ sessionId: string;
739
+ data: string; // base64-encoded
740
+ direction: "input" | "output";
741
+ };
742
+ }
743
+
744
+ export interface TerminalResize extends ClusterFrame {
745
+ type: "terminal_resize";
746
+ id: string;
747
+ payload: {
748
+ sessionId: string;
749
+ cols: number;
750
+ rows: number;
751
+ };
752
+ }
753
+
754
+ export interface TerminalCloseRequest extends ClusterFrame {
755
+ type: "terminal_close";
756
+ id: string;
757
+ payload: {
758
+ sessionId: string;
759
+ exitCode?: number;
760
+ };
761
+ }
762
+
763
+ export interface TerminalCloseResponse extends ClusterFrame {
764
+ type: "terminal_close_res";
765
+ id: string;
766
+ payload: {
767
+ success: boolean;
768
+ error?: string;
332
769
  };
333
770
  }
334
771
 
@@ -336,6 +773,8 @@ export interface KnowledgeSyncFrame extends ClusterFrame {
336
773
  export type AnyClusterFrame =
337
774
  | AuthChallenge
338
775
  | AuthRequest
776
+ | AuthKeyExchange
777
+ | AuthVerify
339
778
  | AuthOk
340
779
  | AuthFail
341
780
  | PeerSync
@@ -357,4 +796,37 @@ export type AnyClusterFrame =
357
796
  | HandoffInput
358
797
  | ToolProxyRequest
359
798
  | ToolProxyResponse
360
- | KnowledgeSyncFrame;
799
+ | ToolBatchRequest
800
+ | ToolBatchResponse
801
+ | DiagnosticExec
802
+ | DiagnosticExecResponse
803
+ | DiagnosticStatus
804
+ | DiagnosticStatusResponse
805
+ | KnowledgeSyncFrame
806
+ | AcpTaskRequest
807
+ | AcpStreamChunk
808
+ | AcpTaskResponse
809
+ | AcpCloseRequest
810
+ | AcpCloseResponse
811
+ | AcpListRequest
812
+ | AcpListResponse
813
+ | AcpResumeRequest
814
+ | AcpResumeResponse
815
+ | AcpCancelRequest
816
+ | AcpCancelResponse
817
+ | AcpSetModeRequest
818
+ | AcpSetModeResponse
819
+ | AcpGetModesRequest
820
+ | AcpGetModesResponse
821
+ | ChatHistoryRequest
822
+ | ChatHistoryResponse
823
+ | PeerApprovalNotify
824
+ | PeerApprovalRequest
825
+ | PeerApprovalResponse
826
+ | TaskActivityFrame
827
+ | TerminalOpenRequest
828
+ | TerminalOpenResponse
829
+ | TerminalData
830
+ | TerminalResize
831
+ | TerminalCloseRequest
832
+ | TerminalCloseResponse;
package/src/web.ts CHANGED
@@ -288,14 +288,14 @@ export class WebHandler {
288
288
  } : undefined,
289
289
  clusterTools: [
290
290
  "cluster_handoff", "cluster_send", "cluster_peers",
291
- "cluster_exec", "cluster_read", "cluster_write", "cluster_tool",
291
+ "cluster_exec", "cluster_read", "cluster_write", "cluster_edit",
292
292
  ],
293
293
  };
294
294
 
295
295
  // All mesh peers share these cluster tools (they all run the ClawMatrix plugin)
296
296
  const CLUSTER_TOOLS = [
297
297
  "cluster_handoff", "cluster_send", "cluster_peers",
298
- "cluster_exec", "cluster_read", "cluster_write", "cluster_tool",
298
+ "cluster_exec", "cluster_read", "cluster_write", "cluster_edit",
299
299
  ];
300
300
 
301
301
  const peerNodes: Record<string, unknown>[] = peers.map((p) => ({