cccc-sdk 0.4.3 → 0.4.40

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.
Files changed (58) hide show
  1. package/README.md +303 -17
  2. package/dist/client.d.ts +88 -95
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +716 -270
  5. package/dist/client.js.map +1 -1
  6. package/dist/client_0430_admin_ops.d.ts +56 -0
  7. package/dist/client_0430_admin_ops.d.ts.map +1 -0
  8. package/dist/client_0430_admin_ops.js +143 -0
  9. package/dist/client_0430_admin_ops.js.map +1 -0
  10. package/dist/client_0430_assistant_ops.d.ts +106 -0
  11. package/dist/client_0430_assistant_ops.d.ts.map +1 -0
  12. package/dist/client_0430_assistant_ops.js +122 -0
  13. package/dist/client_0430_assistant_ops.js.map +1 -0
  14. package/dist/client_0430_memory_ops.d.ts +14 -0
  15. package/dist/client_0430_memory_ops.d.ts.map +1 -0
  16. package/dist/client_0430_memory_ops.js +84 -0
  17. package/dist/client_0430_memory_ops.js.map +1 -0
  18. package/dist/client_0430_ops.d.ts +8 -0
  19. package/dist/client_0430_ops.d.ts.map +1 -0
  20. package/dist/client_0430_ops.js +9 -0
  21. package/dist/client_0430_ops.js.map +1 -0
  22. package/dist/client_0430_shared.d.ts +15 -0
  23. package/dist/client_0430_shared.d.ts.map +1 -0
  24. package/dist/client_0430_shared.js +4 -0
  25. package/dist/client_0430_shared.js.map +1 -0
  26. package/dist/client_0434_ops.d.ts +10 -0
  27. package/dist/client_0434_ops.d.ts.map +1 -0
  28. package/dist/client_0434_ops.js +43 -0
  29. package/dist/client_0434_ops.js.map +1 -0
  30. package/dist/client_chat_ops.d.ts +28 -0
  31. package/dist/client_chat_ops.d.ts.map +1 -0
  32. package/dist/client_chat_ops.js +213 -0
  33. package/dist/client_chat_ops.js.map +1 -0
  34. package/dist/client_connect_ops.d.ts +9 -0
  35. package/dist/client_connect_ops.d.ts.map +1 -0
  36. package/dist/client_connect_ops.js +44 -0
  37. package/dist/client_connect_ops.js.map +1 -0
  38. package/dist/client_group_space_ops.d.ts +24 -0
  39. package/dist/client_group_space_ops.d.ts.map +1 -0
  40. package/dist/client_group_space_ops.js +167 -0
  41. package/dist/client_group_space_ops.js.map +1 -0
  42. package/dist/errors.d.ts +47 -1
  43. package/dist/errors.d.ts.map +1 -1
  44. package/dist/errors.js +56 -1
  45. package/dist/errors.js.map +1 -1
  46. package/dist/index.d.ts +5 -3
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +6 -4
  49. package/dist/index.js.map +1 -1
  50. package/dist/transport.d.ts +4 -3
  51. package/dist/transport.d.ts.map +1 -1
  52. package/dist/transport.js +236 -117
  53. package/dist/transport.js.map +1 -1
  54. package/dist/types.d.ts +1015 -26
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/types.js +20 -1
  57. package/dist/types.js.map +1 -1
  58. package/package.json +3 -3
package/dist/client.js CHANGED
@@ -1,8 +1,16 @@
1
1
  /**
2
2
  * CCCC SDK client
3
3
  */
4
- import { DaemonAPIError, IncompatibleDaemonError, } from './errors.js';
4
+ import { installConnectOps } from './client_connect_ops.js';
5
+ import { DaemonAPIError, DaemonConnectionError, IncompatibleDaemonError, } from './errors.js';
5
6
  import { discoverEndpoint, callDaemon, openEventsStream, readLines, } from './transport.js';
7
+ import { installCCCC0430Ops } from './client_0430_ops.js';
8
+ import { installCCCC0434Ops } from './client_0434_ops.js';
9
+ import { installGroupSpaceOps } from './client_group_space_ops.js';
10
+ import { installChatOps } from './client_chat_ops.js';
11
+ function compactRecord(input) {
12
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
13
+ }
6
14
  /**
7
15
  * Client for communicating with the CCCC daemon over IPC (Unix socket or TCP).
8
16
  *
@@ -13,9 +21,11 @@ import { discoverEndpoint, callDaemon, openEventsStream, readLines, } from './tr
13
21
  * ```
14
22
  */
15
23
  export class CCCCClient {
16
- constructor(endpoint, timeoutMs) {
24
+ constructor(endpoint, timeoutMs, ccccHome, endpointExplicit) {
17
25
  this._endpoint = endpoint;
18
26
  this._timeoutMs = timeoutMs;
27
+ this._ccccHome = ccccHome;
28
+ this._endpointExplicit = endpointExplicit;
19
29
  }
20
30
  /**
21
31
  * Create a new client instance, auto-discovering the daemon endpoint.
@@ -26,7 +36,7 @@ export class CCCCClient {
26
36
  static async create(options = {}) {
27
37
  const endpoint = options.endpoint ?? await discoverEndpoint(options.ccccHome);
28
38
  const timeoutMs = options.timeoutMs ?? 30000;
29
- return new CCCCClient(endpoint, timeoutMs);
39
+ return new CCCCClient(endpoint, timeoutMs, options.ccccHome, options.endpoint !== undefined);
30
40
  }
31
41
  /** The resolved daemon endpoint this client connects to. */
32
42
  get endpoint() {
@@ -49,9 +59,24 @@ export class CCCCClient {
49
59
  op,
50
60
  args: args ?? {},
51
61
  };
52
- const response = await callDaemon(this._endpoint, request, this._timeoutMs);
53
- if (!response.ok && response.error) {
54
- throw new DaemonAPIError(response.error.code ?? 'error', response.error.message ?? 'daemon error', response.error.details ?? {}, response);
62
+ let response;
63
+ try {
64
+ response = await callDaemon(this._endpoint, request, this._timeoutMs);
65
+ }
66
+ catch (error) {
67
+ if (!(error instanceof DaemonConnectionError) || this._endpointExplicit) {
68
+ throw error;
69
+ }
70
+ // Rediscovery is safe only because DaemonConnectionError means that no
71
+ // request bytes were written. Exchange failures are never replayed.
72
+ this._endpoint = await discoverEndpoint(this._ccccHome);
73
+ response = await callDaemon(this._endpoint, request, this._timeoutMs);
74
+ }
75
+ if (response.v !== undefined && response.v !== 1) {
76
+ throw new IncompatibleDaemonError(`Daemon response uses unsupported IPC version: ${response.v}`);
77
+ }
78
+ if (!response.ok) {
79
+ throw new DaemonAPIError(response.error?.code ?? 'error', response.error?.message ?? 'daemon returned ok=false without an error', response.error?.details ?? {}, response);
55
80
  }
56
81
  return response;
57
82
  }
@@ -94,19 +119,83 @@ export class CCCCClient {
94
119
  throw new IncompatibleDaemonError(`Missing capability: ${cap}`);
95
120
  }
96
121
  }
97
- // Check operation support by probing
98
- const reservedOps = new Set(['ping', 'shutdown', 'events_stream', 'term_attach']);
99
- for (const op of options.requireOps ?? []) {
100
- if (reservedOps.has(op))
122
+ // Probe only audited operations with harmless empty arguments.
123
+ const safeEmptyProbes = new Set([
124
+ 'groups',
125
+ 'group_show',
126
+ 'group_preamble_get',
127
+ 'group_preamble_set',
128
+ 'group_preamble_reset',
129
+ 'send',
130
+ 'tracked_send',
131
+ 'send_files',
132
+ 'reply',
133
+ 'inbox_peek',
134
+ 'inbox_read',
135
+ 'context_get',
136
+ 'context_sync',
137
+ 'message_deliver',
138
+ 'message_history',
139
+ 'reply_request_cancel',
140
+ 'send_cross_group',
141
+ 'memory_search',
142
+ 'memory_get',
143
+ 'memory_write',
144
+ 'memory_profile_get',
145
+ 'memory_health',
146
+ 'actor_new_session',
147
+ 'group_reset',
148
+ 'group_copy_export_file',
149
+ 'terminal_history',
150
+ 'terminal_since',
151
+ 'terminal_snapshot',
152
+ 'term_resize',
153
+ 'web_model_delivery_preferences_get',
154
+ 'web_model_delivery_preferences_update',
155
+ 'web_model_runtime_recover_turn',
156
+ 'events_stream',
157
+ 'connect_catalog',
158
+ 'connect_send',
159
+ 'connect_send_files',
160
+ ]);
161
+ for (const requestedOp of options.requireOps ?? []) {
162
+ const op = requestedOp.trim();
163
+ if (op === 'ping')
101
164
  continue;
165
+ if (capabilities[op] === false) {
166
+ throw new IncompatibleDaemonError(`Operation not supported: ${op}`);
167
+ }
168
+ if (!safeEmptyProbes.has(op)) {
169
+ if (capabilities[op] === true)
170
+ continue;
171
+ throw new IncompatibleDaemonError(`Cannot safely verify operation: ${op}; no advertised capability or safe probe`);
172
+ }
102
173
  try {
103
174
  await this.callRaw(op, {});
104
175
  }
105
176
  catch (e) {
106
177
  if (e instanceof DaemonAPIError && e.code === 'unknown_op') {
178
+ if (op === 'term_resize') {
179
+ try {
180
+ await this.callRaw('terminal_resize', {});
181
+ continue;
182
+ }
183
+ catch (aliasError) {
184
+ if (aliasError instanceof DaemonAPIError) {
185
+ if (aliasError.code !== 'unknown_op') {
186
+ continue;
187
+ }
188
+ }
189
+ else {
190
+ throw aliasError;
191
+ }
192
+ }
193
+ }
107
194
  throw new IncompatibleDaemonError(`Operation not supported: ${op}`);
108
195
  }
109
- // Other errors (e.g. missing_group_id) imply the operation exists.
196
+ if (!(e instanceof DaemonAPIError))
197
+ throw e;
198
+ // A structured daemon rejection (e.g. missing_group_id) proves recognition.
110
199
  }
111
200
  }
112
201
  return pingResult;
@@ -163,6 +252,17 @@ export class CCCCClient {
163
252
  async groupDelete(groupId, by = 'user') {
164
253
  return this.call('group_delete', { group_id: groupId, by });
165
254
  }
255
+ /** Replace a group with a clean group while preserving selected configuration. */
256
+ async groupReset(options) {
257
+ if (options.confirmGroupId !== options.groupId) {
258
+ throw new DaemonAPIError('invalid_args', 'groupReset requires confirmGroupId to equal groupId', {});
259
+ }
260
+ return this.call('group_reset', {
261
+ group_id: options.groupId,
262
+ confirm: options.confirmGroupId,
263
+ by: options.by ?? 'user',
264
+ });
265
+ }
166
266
  /**
167
267
  * Use group (set active scope)
168
268
  */
@@ -263,7 +363,7 @@ export class CCCCClient {
263
363
  }
264
364
  /**
265
365
  * Add an actor to a group.
266
- * @param options - Actor configuration (id, runtime, runner, etc.).
366
+ * @param options - Actor configuration (id, runtime, command, etc.).
267
367
  * @returns The daemon result (includes assigned actor id).
268
368
  * @throws {DaemonAPIError} On invalid group or duplicate actor id.
269
369
  */
@@ -272,12 +372,14 @@ export class CCCCClient {
272
372
  actor_id: options.actorId,
273
373
  title: options.title,
274
374
  runtime: options.runtime,
275
- runner: options.runner,
276
375
  command: options.command,
277
376
  env: options.env,
278
377
  env_private: options.envPrivate,
279
378
  capability_autoload: options.capabilityAutoload,
379
+ capability_hidden: options.capabilityHidden,
280
380
  profile_id: options.profileId,
381
+ profile_scope: options.profileScope,
382
+ profile_owner: options.profileOwner,
281
383
  default_scope_key: options.defaultScopeKey,
282
384
  submit: options.submit,
283
385
  };
@@ -331,6 +433,23 @@ export class CCCCClient {
331
433
  async actorRestart(groupId, actorId, by = 'user') {
332
434
  return this.call('actor_restart', { group_id: groupId, actor_id: actorId, by });
333
435
  }
436
+ async runtimeHermesStatus() {
437
+ return this.call('runtime_hermes_status', {});
438
+ }
439
+ async runtimeHermesPrepare(options = {}) {
440
+ return this.call('runtime_hermes_prepare', compactRecord({
441
+ cwd: options.cwd,
442
+ auto_enable_tools: options.autoEnableTools,
443
+ force_mcp: options.forceMcp,
444
+ }));
445
+ }
446
+ async runtimeHermesMcpTest(options = {}) {
447
+ return this.call('runtime_hermes_mcp_test', compactRecord({
448
+ cwd: options.cwd,
449
+ group_id: options.groupId,
450
+ actor_id: options.actorId,
451
+ }));
452
+ }
334
453
  /**
335
454
  * List actor private env keys (without values)
336
455
  */
@@ -639,122 +758,68 @@ export class CCCCClient {
639
758
  args['actor_id'] = options.actorId;
640
759
  return this.call('capability_tool_call', args);
641
760
  }
642
- // ============================================================
643
- // Convenience methods: messaging
644
- // ============================================================
645
- /**
646
- * Send a chat message to a group.
647
- * @param options - Message content, recipients, and priority.
648
- * @returns The daemon result (includes event id).
649
- * @throws {DaemonAPIError} On invalid group, missing permissions, etc.
650
- */
651
- async send(options) {
652
- const args = {
761
+ async capabilityUse(options) {
762
+ const enableResult = await this.capabilityEnable(options);
763
+ if (!options.toolName)
764
+ return enableResult;
765
+ return this.call('capability_tool_call', compactRecord({
653
766
  group_id: options.groupId,
654
- text: options.text,
655
- by: options.by ?? 'user',
656
- priority: options.priority ?? 'normal',
657
- reply_required: options.replyRequired ?? false,
658
- };
659
- if (options.to)
660
- args['to'] = options.to;
661
- if (options.path)
662
- args['path'] = options.path;
663
- return this.call('send', args);
767
+ actor_id: options.actorId,
768
+ by: options.by,
769
+ tool_name: options.toolName,
770
+ arguments: options.toolArguments ?? {},
771
+ }));
664
772
  }
665
- /**
666
- * Send message across groups
667
- */
668
- async sendCrossGroup(options) {
669
- const args = {
773
+ async memorySearch(options) {
774
+ return this.call('memory_search', compactRecord({
670
775
  group_id: options.groupId,
671
- dst_group_id: options.dstGroupId,
672
- text: options.text,
673
- by: options.by ?? 'user',
674
- priority: options.priority ?? 'normal',
675
- reply_required: options.replyRequired ?? false,
676
- };
677
- if (options.to)
678
- args['to'] = options.to;
679
- return this.call('send_cross_group', args);
680
- }
681
- /**
682
- * Reply message
683
- */
684
- async reply(options) {
685
- const args = {
776
+ actor_id: options.actorId,
777
+ query: options.query,
778
+ limit: options.limit,
779
+ max_results: options.maxResults,
780
+ vector_weight: options.vectorWeight,
781
+ candidate_multiplier: options.candidateMultiplier,
782
+ min_score: options.minScore,
783
+ tags: options.tags,
784
+ target: options.target,
785
+ }));
786
+ }
787
+ async memoryGet(options) {
788
+ return this.call('memory_get', compactRecord({
686
789
  group_id: options.groupId,
687
- reply_to: options.replyTo,
688
- text: options.text,
689
- by: options.by ?? 'user',
690
- priority: options.priority ?? 'normal',
691
- reply_required: options.replyRequired ?? false,
692
- };
693
- if (options.to)
694
- args['to'] = options.to;
695
- return this.call('reply', args);
696
- }
697
- /**
698
- * Acknowledge chat message
699
- */
700
- async chatAck(groupId, actorId, eventId, by) {
701
- return this.call('chat_ack', {
702
- group_id: groupId,
703
- actor_id: actorId,
704
- event_id: eventId,
705
- by: by ?? actorId,
706
- });
707
- }
708
- // ============================================================
709
- // Convenience methods: inbox
710
- // ============================================================
711
- /**
712
- * List inbox
713
- */
714
- async inboxList(options) {
715
- return this.call('inbox_list', {
790
+ actor_id: options.actorId,
791
+ path: options.path,
792
+ target: options.target,
793
+ date: options.date,
794
+ offset: options.offset,
795
+ limit: options.limit,
796
+ }));
797
+ }
798
+ async memoryWrite(options) {
799
+ return this.call('memory_write', compactRecord({
716
800
  group_id: options.groupId,
717
801
  actor_id: options.actorId,
718
- by: options.by ?? 'user',
719
- limit: options.limit ?? 50,
720
- kind_filter: options.kindFilter ?? 'all',
721
- });
722
- }
723
- /**
724
- * Mark message as read
725
- */
726
- async inboxMarkRead(groupId, actorId, eventId, by = 'user') {
727
- return this.call('inbox_mark_read', {
728
- group_id: groupId,
729
- actor_id: actorId,
730
- event_id: eventId,
731
- by,
732
- });
733
- }
734
- /**
735
- * Mark all messages as read
736
- */
737
- async inboxMarkAllRead(groupId, actorId, by = 'user', kindFilter = 'all') {
738
- return this.call('inbox_mark_all_read', {
739
- group_id: groupId,
740
- actor_id: actorId,
741
- by,
742
- kind_filter: kindFilter,
743
- });
802
+ target: options.target,
803
+ content: options.content,
804
+ tags: options.tags,
805
+ source_refs: options.sourceRefs,
806
+ idempotency_key: options.idempotencyKey,
807
+ dedup_intent: options.dedupIntent,
808
+ dedup_query: options.dedupQuery,
809
+ }));
810
+ }
811
+ async memoryHealth(options) {
812
+ return this.call('memory_health', compactRecord({
813
+ group_id: options.groupId,
814
+ }));
744
815
  }
745
- // ============================================================
746
- // Convenience methods: notifications
747
- // ============================================================
748
- /**
749
- * Acknowledge notification
750
- */
751
- async notifyAck(groupId, actorId, notifyEventId, by) {
752
- return this.call('notify_ack', {
753
- group_id: groupId,
754
- actor_id: actorId,
755
- notify_event_id: notifyEventId,
756
- by: by ?? actorId,
757
- });
816
+ async memoryProfileGet(options) {
817
+ return this.call('memory_profile_get', compactRecord({
818
+ group_id: options.groupId,
819
+ actor_id: options.actorId,
820
+ user_id: options.userId,
821
+ tags: options.tags,
822
+ }));
758
823
  }
759
824
  // ============================================================
760
825
  // Convenience methods: context
@@ -762,8 +827,8 @@ export class CCCCClient {
762
827
  /**
763
828
  * Get group context
764
829
  */
765
- async contextGet(groupId) {
766
- return this.call('context_get', { group_id: groupId });
830
+ async contextGet(groupId, detail = 'full') {
831
+ return this.call('context_get', { group_id: groupId, detail });
767
832
  }
768
833
  /**
769
834
  * Sync context
@@ -774,209 +839,554 @@ export class CCCCClient {
774
839
  ops: options.ops,
775
840
  by: options.by ?? 'system',
776
841
  dry_run: options.dryRun ?? false,
842
+ ...(options.ifVersion !== undefined ? { if_version: options.ifVersion } : {}),
777
843
  });
778
844
  }
845
+ contextOp(groupId, op, by = 'system', dryRun = false) {
846
+ return this.contextSync({ groupId, by, dryRun, ops: [op] });
847
+ }
848
+ async coordinationBriefUpdate(options) {
849
+ return this.contextOp(options.groupId, compactRecord({
850
+ op: 'coordination.brief.update',
851
+ objective: options.objective,
852
+ current_focus: options.currentFocus,
853
+ constraints: options.constraints,
854
+ project_brief: options.projectBrief,
855
+ project_brief_stale: options.projectBriefStale,
856
+ }), options.by, options.dryRun);
857
+ }
858
+ async coordinationNoteAdd(options) {
859
+ return this.contextOp(options.groupId, compactRecord({
860
+ op: 'coordination.note.add',
861
+ kind: options.kind,
862
+ summary: options.summary,
863
+ task_id: options.taskId,
864
+ }), options.by, options.dryRun);
865
+ }
866
+ async taskCreate(options) {
867
+ return this.contextOp(options.groupId, compactRecord({
868
+ op: 'task.create',
869
+ title: options.title,
870
+ outcome: options.outcome,
871
+ status: options.status,
872
+ parent_id: options.parentId,
873
+ assignee: options.assignee,
874
+ priority: options.priority,
875
+ blocked_by: options.blockedBy,
876
+ waiting_on: options.waitingOn,
877
+ handoff_to: options.handoffTo,
878
+ task_type: options.taskType,
879
+ notes: options.notes,
880
+ checklist: options.checklist,
881
+ }), options.by, options.dryRun);
882
+ }
883
+ async taskUpdate(options) {
884
+ return this.contextOp(options.groupId, compactRecord({
885
+ op: 'task.update',
886
+ task_id: options.taskId,
887
+ title: options.title,
888
+ outcome: options.outcome,
889
+ status: options.status,
890
+ assignee: options.assignee,
891
+ priority: options.priority,
892
+ blocked_by: options.blockedBy,
893
+ waiting_on: options.waitingOn,
894
+ handoff_to: options.handoffTo,
895
+ notes: options.notes,
896
+ checklist: options.checklist,
897
+ }), options.by, options.dryRun);
898
+ }
899
+ async taskMove(options) {
900
+ return this.contextOp(options.groupId, {
901
+ op: 'task.move',
902
+ task_id: options.taskId,
903
+ status: options.status,
904
+ }, options.by, options.dryRun);
905
+ }
906
+ async taskRestore(options) {
907
+ return this.contextOp(options.groupId, {
908
+ op: 'task.restore',
909
+ task_id: options.taskId,
910
+ }, options.by, options.dryRun);
911
+ }
912
+ async taskDelete(options) {
913
+ return this.contextOp(options.groupId, {
914
+ op: 'task.delete',
915
+ task_id: options.taskId,
916
+ }, options.by, options.dryRun);
917
+ }
918
+ async agentStateUpdate(options) {
919
+ return this.contextOp(options.groupId, compactRecord({
920
+ op: 'agent_state.update',
921
+ actor_id: options.actorId,
922
+ active_task_id: options.activeTaskId,
923
+ focus: options.focus,
924
+ next_action: options.nextAction,
925
+ what_changed: options.whatChanged,
926
+ blockers: options.blockers,
927
+ open_loops: options.openLoops,
928
+ commitments: options.commitments,
929
+ environment_summary: options.environmentSummary,
930
+ user_model: options.userModel,
931
+ persona_notes: options.personaNotes,
932
+ }), options.by, options.dryRun);
933
+ }
934
+ async agentStateClear(options) {
935
+ return this.contextOp(options.groupId, {
936
+ op: 'agent_state.clear',
937
+ actor_id: options.actorId,
938
+ }, options.by, options.dryRun);
939
+ }
940
+ async metaMerge(options) {
941
+ return this.contextOp(options.groupId, {
942
+ op: 'meta.merge',
943
+ data: options.data,
944
+ }, options.by, options.dryRun);
945
+ }
779
946
  // ============================================================
780
- // Convenience methods: Group Space
947
+ // Convenience methods: tracked delegation
781
948
  // ============================================================
782
949
  /**
783
- * Read Group Space provider and binding status.
950
+ * Atomically create a tracked task and send the linked chat message. Daemon
951
+ * handles task.create + send in one transaction. Use `idempotencyKey` to make
952
+ * retries safe (the daemon replays the previous result on duplicate keys).
784
953
  */
785
- async groupSpaceStatus(options) {
786
- return this.call('group_space_status', {
954
+ async trackedSend(options) {
955
+ const args = {
787
956
  group_id: options.groupId,
788
- provider: options.provider ?? 'notebooklm',
789
- });
957
+ text: options.text,
958
+ by: options.by ?? 'user',
959
+ };
960
+ if (options.title)
961
+ args['title'] = options.title;
962
+ if (options.insight)
963
+ args['insight'] = options.insight;
964
+ if (options.to)
965
+ args['to'] = options.to;
966
+ if (options.path)
967
+ args['path'] = options.path;
968
+ if (options.taskPriority)
969
+ args['task_priority'] = options.taskPriority;
970
+ if (options.idempotencyKey)
971
+ args['idempotency_key'] = options.idempotencyKey;
972
+ if (options.outcome)
973
+ args['outcome'] = options.outcome;
974
+ if (options.status)
975
+ args['status'] = options.status;
976
+ if (options.waitingOn)
977
+ args['waiting_on'] = options.waitingOn;
978
+ if (options.taskType)
979
+ args['task_type'] = options.taskType;
980
+ if (options.checklist)
981
+ args['checklist'] = options.checklist;
982
+ if (options.notes)
983
+ args['notes'] = options.notes;
984
+ if (options.blockedBy)
985
+ args['blocked_by'] = options.blockedBy;
986
+ if (options.handoffTo)
987
+ args['handoff_to'] = options.handoffTo;
988
+ if (options.assignee)
989
+ args['assignee'] = options.assignee;
990
+ if (options.refs)
991
+ args['refs'] = options.refs;
992
+ if (options.insight)
993
+ args['insight'] = options.insight;
994
+ if (options.requirePeerInsight !== undefined)
995
+ args['require_peer_insight'] = options.requirePeerInsight;
996
+ return this.call('tracked_send', args);
997
+ }
998
+ /**
999
+ * List all tasks in a group, or fetch a single task (with children) by id.
1000
+ */
1001
+ async taskList(options) {
1002
+ if (options.taskId && options.taskIds?.length) {
1003
+ throw new DaemonAPIError('invalid_args', 'taskId and taskIds are mutually exclusive', {});
1004
+ }
1005
+ if (options.status && options.statuses?.length) {
1006
+ throw new DaemonAPIError('invalid_args', 'status and statuses are mutually exclusive', {});
1007
+ }
1008
+ if (options.offset !== undefined && options.limit === undefined) {
1009
+ throw new DaemonAPIError('invalid_args', 'offset requires limit', {});
1010
+ }
1011
+ if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100)) {
1012
+ throw new DaemonAPIError('invalid_args', 'limit must be an integer from 1 through 100', {});
1013
+ }
1014
+ const taskIds = options.taskIds?.map((value) => value.trim()) ?? [];
1015
+ if (taskIds.some((value) => value.length === 0) || taskIds.length > 100) {
1016
+ throw new DaemonAPIError('invalid_args', 'taskIds must contain at most 100 non-empty ids', {});
1017
+ }
1018
+ const args = { group_id: options.groupId };
1019
+ if (options.taskId)
1020
+ args['task_id'] = options.taskId;
1021
+ if (taskIds.length)
1022
+ args['task_ids'] = taskIds.join(',');
1023
+ if (options.status)
1024
+ args['status'] = options.status;
1025
+ if (options.statuses?.length)
1026
+ args['statuses'] = options.statuses.join(',');
1027
+ if (options.query)
1028
+ args['query'] = options.query;
1029
+ if (options.assignee)
1030
+ args['assignee'] = options.assignee;
1031
+ if (options.attention)
1032
+ args['attention'] = options.attention;
1033
+ if (options.offset !== undefined)
1034
+ args['offset'] = options.offset;
1035
+ if (options.limit !== undefined)
1036
+ args['limit'] = options.limit;
1037
+ if (options.includeIndex !== undefined)
1038
+ args['include_index'] = options.includeIndex;
1039
+ return this.call('task_list', args);
790
1040
  }
791
- /**
792
- * List available remote spaces for binding.
793
- */
794
- async groupSpaceSpaces(options) {
795
- return this.call('group_space_spaces', {
1041
+ // ============================================================
1042
+ // Convenience methods: headless runtime control
1043
+ // ============================================================
1044
+ async headlessStatus(options) {
1045
+ return this.call('headless_status', {
796
1046
  group_id: options.groupId,
797
- provider: options.provider ?? 'notebooklm',
1047
+ actor_id: options.actorId,
798
1048
  });
799
1049
  }
800
- /**
801
- * Read the provider capability matrix for a group.
802
- */
803
- async groupSpaceCapabilities(options) {
804
- return this.call('group_space_capabilities', {
1050
+ async headlessSetStatus(options) {
1051
+ const args = {
1052
+ group_id: options.groupId,
1053
+ actor_id: options.actorId,
1054
+ status: options.status,
1055
+ };
1056
+ if (options.taskId)
1057
+ args['task_id'] = options.taskId;
1058
+ return this.call('headless_set_status', args);
1059
+ }
1060
+ // ============================================================
1061
+ // Convenience methods: group copy (export/import)
1062
+ // ============================================================
1063
+ async groupCopyExport(options) {
1064
+ return this.call('group_copy_export', {
805
1065
  group_id: options.groupId,
806
- provider: options.provider ?? 'notebooklm',
1066
+ by: options.by ?? 'user',
807
1067
  });
808
1068
  }
809
- /**
810
- * Bind or unbind one Group Space lane.
811
- */
812
- async groupSpaceBind(options) {
1069
+ async groupCopyPreviewImport(options) {
1070
+ const packageB64 = options.packageB64;
1071
+ const packagePath = options.packagePath;
1072
+ if (Boolean(packageB64) === Boolean(packagePath)) {
1073
+ throw new DaemonAPIError('invalid_args', 'exactly one of packageB64 or packagePath is required', {});
1074
+ }
1075
+ return this.call('group_copy_preview_import', compactRecord({
1076
+ package_b64: packageB64,
1077
+ package_path: packagePath,
1078
+ }));
1079
+ }
1080
+ async groupCopyImport(options) {
1081
+ const packageB64 = options.packageB64;
1082
+ const packagePath = options.packagePath;
1083
+ if (Boolean(packageB64) === Boolean(packagePath)) {
1084
+ throw new DaemonAPIError('invalid_args', 'exactly one of packageB64 or packagePath is required', {});
1085
+ }
1086
+ const args = compactRecord({
1087
+ package_b64: packageB64,
1088
+ package_path: packagePath,
1089
+ });
1090
+ if (options.workspaceRoot)
1091
+ args['workspace_root'] = options.workspaceRoot;
1092
+ if (options.title)
1093
+ args['title'] = options.title;
1094
+ return this.call('group_copy_import', args);
1095
+ }
1096
+ // ============================================================
1097
+ // Convenience methods: capability extensions
1098
+ // ============================================================
1099
+ async capabilityVisibility(options) {
813
1100
  const args = {
814
1101
  group_id: options.groupId,
815
- provider: options.provider ?? 'notebooklm',
816
- lane: options.lane,
817
- action: options.action ?? 'bind',
1102
+ capability_id: options.capabilityId,
1103
+ hidden: options.hidden ?? true,
818
1104
  by: options.by ?? 'user',
819
1105
  };
820
- if (options.remoteSpaceId)
821
- args['remote_space_id'] = options.remoteSpaceId;
822
- return this.call('group_space_bind', args);
1106
+ if (options.actorId)
1107
+ args['actor_id'] = options.actorId;
1108
+ if (options.reason)
1109
+ args['reason'] = options.reason;
1110
+ return this.call('capability_visibility', args);
823
1111
  }
824
- /**
825
- * Enqueue one Group Space ingest action.
826
- */
827
- async groupSpaceIngest(options) {
1112
+ async capabilityInstallTarget(options) {
828
1113
  const args = {
829
1114
  group_id: options.groupId,
830
- provider: options.provider ?? 'notebooklm',
831
- lane: options.lane,
832
- kind: options.kind ?? 'context_sync',
1115
+ target: options.target,
1116
+ scope: options.scope ?? 'actor',
833
1117
  by: options.by ?? 'user',
834
1118
  };
835
- if (options.payload)
836
- args['payload'] = options.payload;
837
- if (options.idempotencyKey)
838
- args['idempotency_key'] = options.idempotencyKey;
839
- return this.call('group_space_ingest', args);
1119
+ if (options.actorId)
1120
+ args['actor_id'] = options.actorId;
1121
+ if (options.ttlSeconds !== undefined)
1122
+ args['ttl_seconds'] = options.ttlSeconds;
1123
+ if (options.reason)
1124
+ args['reason'] = options.reason;
1125
+ return this.call('capability_install_target', args);
840
1126
  }
841
- /**
842
- * Query Group Space knowledge for one lane.
843
- */
844
- async groupSpaceQuery(options) {
1127
+ async capabilitySourceDelete(options) {
845
1128
  const args = {
846
1129
  group_id: options.groupId,
847
- provider: options.provider ?? 'notebooklm',
848
- lane: options.lane,
849
- query: options.query,
1130
+ source_id: options.sourceId,
1131
+ by: options.by ?? 'user',
850
1132
  };
851
- if (options.options)
852
- args['options'] = options.options;
853
- return this.call('group_space_query', args);
1133
+ if (options.reason)
1134
+ args['reason'] = options.reason;
1135
+ if (options.actorId)
1136
+ args['actor_id'] = options.actorId;
1137
+ return this.call('capability_source_delete', args);
854
1138
  }
855
- /**
856
- * Manage remote sources in the bound Group Space lane.
857
- */
858
- async groupSpaceSources(options) {
1139
+ // ============================================================
1140
+ // Convenience methods: presentation workspace
1141
+ // ============================================================
1142
+ async presentationGet(options) {
1143
+ return this.call('presentation_get', { group_id: options.groupId });
1144
+ }
1145
+ async presentationPublish(options) {
859
1146
  const args = {
860
1147
  group_id: options.groupId,
861
- provider: options.provider ?? 'notebooklm',
862
- lane: options.lane,
863
- action: options.action ?? 'list',
864
1148
  by: options.by ?? 'user',
865
1149
  };
866
- if (options.sourceId)
867
- args['source_id'] = options.sourceId;
868
- if (options.newTitle)
869
- args['new_title'] = options.newTitle;
870
- return this.call('group_space_sources', args);
871
- }
872
- /**
873
- * List, generate, or download Group Space artifacts.
874
- */
875
- async groupSpaceArtifact(options) {
1150
+ if (options.slot)
1151
+ args['slot'] = options.slot;
1152
+ if (options.title)
1153
+ args['title'] = options.title;
1154
+ if (options.summary)
1155
+ args['summary'] = options.summary;
1156
+ if (options.sourceLabel)
1157
+ args['source_label'] = options.sourceLabel;
1158
+ if (options.sourceRef)
1159
+ args['source_ref'] = options.sourceRef;
1160
+ if (options.cardType)
1161
+ args['card_type'] = options.cardType;
1162
+ if (options.content)
1163
+ args['content'] = options.content;
1164
+ if (options.path)
1165
+ args['path'] = options.path;
1166
+ if (options.url)
1167
+ args['url'] = options.url;
1168
+ if (options.blobRelPath)
1169
+ args['blob_rel_path'] = options.blobRelPath;
1170
+ if (options.table)
1171
+ args['table'] = options.table;
1172
+ return this.call('presentation_publish', args);
1173
+ }
1174
+ async presentationClear(options) {
876
1175
  const args = {
877
1176
  group_id: options.groupId,
878
- provider: options.provider ?? 'notebooklm',
879
- lane: options.lane,
880
- action: options.action ?? 'list',
881
1177
  by: options.by ?? 'user',
882
1178
  };
883
- if (options.kind)
884
- args['kind'] = options.kind;
885
- if (options.options)
886
- args['options'] = options.options;
887
- if (options.wait !== undefined)
888
- args['wait'] = options.wait;
889
- if (options.saveToSpace !== undefined)
890
- args['save_to_space'] = options.saveToSpace;
891
- if (options.outputPath)
892
- args['output_path'] = options.outputPath;
893
- if (options.outputFormat)
894
- args['output_format'] = options.outputFormat;
895
- if (options.artifactId)
896
- args['artifact_id'] = options.artifactId;
897
- if (options.timeoutSeconds !== undefined)
898
- args['timeout_seconds'] = options.timeoutSeconds;
899
- if (options.initialInterval !== undefined)
900
- args['initial_interval'] = options.initialInterval;
901
- if (options.maxInterval !== undefined)
902
- args['max_interval'] = options.maxInterval;
903
- return this.call('group_space_artifact', args);
1179
+ if (options.slot)
1180
+ args['slot'] = options.slot;
1181
+ return this.call('presentation_clear', args);
904
1182
  }
905
- /**
906
- * List or manage Group Space jobs.
907
- */
908
- async groupSpaceJobs(options) {
909
- const args = {
1183
+ /** @deprecated This browser surface is served by CCCC Web, not daemon IPC. */
1184
+ async presentationBrowserOpen(options) {
1185
+ void options;
1186
+ throw new IncompatibleDaemonError("Presentation browsers are no longer served by daemon IPC; use the CCCC Web Presentation browser surface");
1187
+ }
1188
+ /** @deprecated This browser surface is served by CCCC Web, not daemon IPC. */
1189
+ async presentationBrowserInfo(options) {
1190
+ void options;
1191
+ throw new IncompatibleDaemonError("Presentation browsers are no longer served by daemon IPC; use the CCCC Web Presentation browser surface");
1192
+ }
1193
+ /** @deprecated This browser surface is served by CCCC Web, not daemon IPC. */
1194
+ async presentationBrowserClose(options) {
1195
+ void options;
1196
+ throw new IncompatibleDaemonError("Presentation browsers are no longer served by daemon IPC; use the CCCC Web Presentation browser surface");
1197
+ }
1198
+ // ============================================================
1199
+ // Convenience methods: built-in assistants (PET / Voice Secretary)
1200
+ // ============================================================
1201
+ async assistantState(options) {
1202
+ const args = { group_id: options.groupId };
1203
+ if (options.assistantId)
1204
+ args['assistant_id'] = options.assistantId;
1205
+ if (options.promptRequestId)
1206
+ args['prompt_request_id'] = options.promptRequestId;
1207
+ return this.call('assistant_state', args);
1208
+ }
1209
+ async assistantVoiceRecordingLease(options) {
1210
+ return this.call('assistant_voice_recording_lease', compactRecord({
910
1211
  group_id: options.groupId,
911
- provider: options.provider ?? 'notebooklm',
912
- lane: options.lane,
913
- action: options.action ?? 'list',
1212
+ action: options.action,
914
1213
  by: options.by ?? 'user',
915
- };
916
- if (options.jobId)
917
- args['job_id'] = options.jobId;
918
- if (options.state)
919
- args['state'] = options.state;
920
- if (options.limit !== undefined)
921
- args['limit'] = options.limit;
922
- return this.call('group_space_jobs', args);
1214
+ owner_id: options.ownerId,
1215
+ lease_id: options.leaseId,
1216
+ ttl_seconds: options.ttlSeconds,
1217
+ capture_mode: options.captureMode,
1218
+ recognition_backend: options.recognitionBackend,
1219
+ }));
1220
+ }
1221
+ async assistantSettingsUpdate(options) {
1222
+ return this.call('assistant_settings_update', {
1223
+ group_id: options.groupId,
1224
+ assistant_id: options.assistantId,
1225
+ patch: options.patch,
1226
+ by: options.by ?? 'user',
1227
+ });
923
1228
  }
924
- /**
925
- * Read or run Group Space synchronization for one lane.
926
- */
927
- async groupSpaceSync(options) {
928
- return this.call('group_space_sync', {
1229
+ async assistantStatusUpdate(options) {
1230
+ const args = {
929
1231
  group_id: options.groupId,
930
- provider: options.provider ?? 'notebooklm',
931
- lane: options.lane,
932
- action: options.action ?? 'status',
933
- force: options.force ?? false,
1232
+ assistant_id: options.assistantId,
1233
+ lifecycle: options.lifecycle,
1234
+ };
1235
+ if (options.health)
1236
+ args['health'] = options.health;
1237
+ if (options.by)
1238
+ args['by'] = options.by;
1239
+ return this.call('assistant_status_update', args);
1240
+ }
1241
+ // ============================================================
1242
+ // Convenience methods: daemon core
1243
+ // ============================================================
1244
+ /** Trigger graceful daemon shutdown (no-args). */
1245
+ async shutdown() {
1246
+ return this.call('shutdown', {});
1247
+ }
1248
+ async observabilityGet() {
1249
+ return this.call('observability_get', {});
1250
+ }
1251
+ async observabilityUpdate(options) {
1252
+ return this.call('observability_update', {
1253
+ patch: options.patch,
934
1254
  by: options.by ?? 'user',
935
1255
  });
936
1256
  }
937
- /**
938
- * Read provider credential status.
939
- */
940
- async groupSpaceProviderCredentialStatus(options = {}) {
941
- return this.call('group_space_provider_credential_status', {
942
- provider: options.provider ?? 'notebooklm',
1257
+ async brandingGet() {
1258
+ return this.call('branding_get', {});
1259
+ }
1260
+ async brandingUpdate(options) {
1261
+ return this.call('branding_update', {
1262
+ patch: options.patch,
943
1263
  by: options.by ?? 'user',
944
1264
  });
945
1265
  }
946
- /**
947
- * Update provider credentials.
948
- */
949
- async groupSpaceProviderCredentialUpdate(options = {}) {
1266
+ // ============================================================
1267
+ // Convenience methods: diagnostics
1268
+ // ============================================================
1269
+ async debugSnapshot(options) {
1270
+ return this.call('debug_snapshot', {
1271
+ group_id: options.groupId,
1272
+ by: options.by ?? 'user',
1273
+ });
1274
+ }
1275
+ async debugTailLogs(options) {
950
1276
  const args = {
951
- provider: options.provider ?? 'notebooklm',
1277
+ component: options.component,
952
1278
  by: options.by ?? 'user',
953
- clear: options.clear ?? false,
1279
+ lines: options.lines ?? 200,
954
1280
  };
955
- if (options.authJson)
956
- args['auth_json'] = options.authJson;
957
- return this.call('group_space_provider_credential_update', args);
1281
+ if (options.groupId)
1282
+ args['group_id'] = options.groupId;
1283
+ return this.call('debug_tail_logs', args);
958
1284
  }
959
- /**
960
- * Run provider health check.
961
- */
962
- async groupSpaceProviderHealthCheck(options = {}) {
963
- return this.call('group_space_provider_health_check', {
964
- provider: options.provider ?? 'notebooklm',
1285
+ async debugClearLogs(options) {
1286
+ const args = {
1287
+ component: options.component,
1288
+ by: options.by ?? 'user',
1289
+ };
1290
+ if (options.groupId)
1291
+ args['group_id'] = options.groupId;
1292
+ return this.call('debug_clear_logs', args);
1293
+ }
1294
+ async terminalTail(options) {
1295
+ return this.call('terminal_tail', {
1296
+ group_id: options.groupId,
1297
+ actor_id: options.actorId,
1298
+ max_chars: options.maxChars ?? 8000,
1299
+ strip_ansi: options.stripAnsi ?? true,
1300
+ compact: options.compact ?? true,
1301
+ by: options.by ?? 'user',
1302
+ });
1303
+ }
1304
+ async terminalClear(options) {
1305
+ return this.call('terminal_clear', {
1306
+ group_id: options.groupId,
1307
+ actor_id: options.actorId,
965
1308
  by: options.by ?? 'user',
966
1309
  });
967
1310
  }
1311
+ // ============================================================
1312
+ // Convenience methods: maintenance (ledger)
1313
+ // ============================================================
1314
+ async ledgerSnapshot(options) {
1315
+ return this.call('ledger_snapshot', {
1316
+ group_id: options.groupId,
1317
+ by: options.by ?? 'user',
1318
+ reason: options.reason ?? 'manual',
1319
+ });
1320
+ }
1321
+ async ledgerCompact(options) {
1322
+ return this.call('ledger_compact', {
1323
+ group_id: options.groupId,
1324
+ by: options.by ?? 'user',
1325
+ reason: options.reason ?? 'auto',
1326
+ force: options.force ?? false,
1327
+ });
1328
+ }
1329
+ // ============================================================
1330
+ // Convenience methods: stream / system notify (low-level)
1331
+ // ============================================================
968
1332
  /**
969
- * Control provider auth flow.
1333
+ * Emit a chat.stream event (`op` = 'start' | 'update' | 'end').
1334
+ * For 'start', a new stream_id is generated and returned. For
1335
+ * 'update'/'end', supply the stream_id you got from 'start'.
970
1336
  */
971
- async groupSpaceProviderAuth(options = {}) {
1337
+ async streamEmit(options) {
972
1338
  const args = {
973
- provider: options.provider ?? 'notebooklm',
974
- action: options.action ?? 'status',
975
- by: options.by ?? 'user',
1339
+ group_id: options.groupId,
1340
+ by: options.by,
1341
+ op: options.op,
1342
+ format: options.format ?? 'plain',
1343
+ seq: options.seq ?? 0,
1344
+ };
1345
+ if (options.streamId)
1346
+ args['stream_id'] = options.streamId;
1347
+ if (options.text !== undefined)
1348
+ args['text'] = options.text;
1349
+ if (options.to)
1350
+ args['to'] = options.to;
1351
+ if (options.replyTo)
1352
+ args['reply_to'] = options.replyTo;
1353
+ if (options.clientId)
1354
+ args['client_id'] = options.clientId;
1355
+ return this.call('stream_emit', args);
1356
+ }
1357
+ async systemNotify(options) {
1358
+ const args = {
1359
+ group_id: options.groupId,
1360
+ by: options.by ?? 'system',
1361
+ kind: options.kind ?? 'info',
1362
+ priority: options.priority ?? 'normal',
976
1363
  };
977
- if (options.timeoutSeconds !== undefined)
978
- args['timeout_seconds'] = options.timeoutSeconds;
979
- return this.call('group_space_provider_auth', args);
1364
+ if (options.message)
1365
+ args['message'] = options.message;
1366
+ if (options.title)
1367
+ args['title'] = options.title;
1368
+ if (options.targetActorId)
1369
+ args['target_actor_id'] = options.targetActorId;
1370
+ if (options.imVisibility)
1371
+ args['im_visibility'] = options.imVisibility;
1372
+ if (options.context)
1373
+ args['context'] = options.context;
1374
+ return this.call('system_notify', args);
1375
+ }
1376
+ // ============================================================
1377
+ // Convenience methods: registry / group admin
1378
+ // ============================================================
1379
+ async registryReconcile(options = {}) {
1380
+ return this.call('registry_reconcile', {
1381
+ remove_missing: options.removeMissing ?? false,
1382
+ });
1383
+ }
1384
+ async groupDetachScope(options) {
1385
+ return this.call('group_detach_scope', {
1386
+ group_id: options.groupId,
1387
+ scope_key: options.scopeKey,
1388
+ by: options.by ?? 'user',
1389
+ });
980
1390
  }
981
1391
  // ============================================================
982
1392
  // Event stream
@@ -990,6 +1400,8 @@ export class CCCCClient {
990
1400
  * @throws {DaemonAPIError} If the handshake fails.
991
1401
  */
992
1402
  async *eventsStream(options) {
1403
+ if (options.signal?.aborted)
1404
+ return;
993
1405
  const args = {
994
1406
  group_id: options.groupId,
995
1407
  by: options.by ?? 'user',
@@ -1010,11 +1422,33 @@ export class CCCCClient {
1010
1422
  op: 'events_stream',
1011
1423
  args,
1012
1424
  };
1013
- const { socket, handshake, initialBuffer } = await openEventsStream(this._endpoint, request, options.timeoutMs ?? this._timeoutMs);
1425
+ const streamTimeoutMs = options.timeoutMs ?? this._timeoutMs;
1426
+ let connection;
1427
+ try {
1428
+ connection = await openEventsStream(this._endpoint, request, streamTimeoutMs, options.signal);
1429
+ }
1430
+ catch (error) {
1431
+ if (!(error instanceof DaemonConnectionError) || this._endpointExplicit) {
1432
+ throw error;
1433
+ }
1434
+ this._endpoint = await discoverEndpoint(this._ccccHome);
1435
+ connection = await openEventsStream(this._endpoint, request, streamTimeoutMs, options.signal);
1436
+ }
1437
+ const { socket, handshake, initialBuffer } = connection;
1438
+ if (options.signal?.aborted) {
1439
+ socket.destroy();
1440
+ return;
1441
+ }
1442
+ if (handshake.v !== undefined && handshake.v !== 1) {
1443
+ socket.destroy();
1444
+ throw new IncompatibleDaemonError(`Daemon stream handshake uses unsupported IPC version: ${handshake.v}`);
1445
+ }
1014
1446
  if (!handshake.ok) {
1015
1447
  socket.destroy();
1016
1448
  throw new DaemonAPIError(handshake.error?.code ?? 'unknown', handshake.error?.message ?? 'Handshake failed', handshake.error?.details, handshake);
1017
1449
  }
1450
+ const abortStream = () => socket.destroy();
1451
+ options.signal?.addEventListener('abort', abortStream, { once: true });
1018
1452
  try {
1019
1453
  for await (const line of readLines(socket, initialBuffer)) {
1020
1454
  try {
@@ -1028,9 +1462,21 @@ export class CCCCClient {
1028
1462
  }
1029
1463
  }
1030
1464
  }
1465
+ catch (error) {
1466
+ // Cancelling an established subscription is normal completion. Preserve
1467
+ // unexpected transport/decoding errors when the caller did not cancel.
1468
+ if (!options.signal?.aborted)
1469
+ throw error;
1470
+ }
1031
1471
  finally {
1472
+ options.signal?.removeEventListener('abort', abortStream);
1032
1473
  socket.destroy();
1033
1474
  }
1034
1475
  }
1035
1476
  }
1477
+ installCCCC0430Ops(CCCCClient.prototype);
1478
+ installCCCC0434Ops(CCCCClient.prototype);
1479
+ installGroupSpaceOps(CCCCClient.prototype);
1480
+ installChatOps(CCCCClient.prototype);
1481
+ installConnectOps(CCCCClient.prototype);
1036
1482
  //# sourceMappingURL=client.js.map