cccc-sdk 0.4.4 → 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.
- package/README.md +252 -16
- package/dist/client.d.ts +87 -163
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +663 -536
- package/dist/client.js.map +1 -1
- package/dist/client_0430_admin_ops.d.ts +56 -0
- package/dist/client_0430_admin_ops.d.ts.map +1 -0
- package/dist/client_0430_admin_ops.js +143 -0
- package/dist/client_0430_admin_ops.js.map +1 -0
- package/dist/client_0430_assistant_ops.d.ts +106 -0
- package/dist/client_0430_assistant_ops.d.ts.map +1 -0
- package/dist/client_0430_assistant_ops.js +122 -0
- package/dist/client_0430_assistant_ops.js.map +1 -0
- package/dist/client_0430_memory_ops.d.ts +14 -0
- package/dist/client_0430_memory_ops.d.ts.map +1 -0
- package/dist/client_0430_memory_ops.js +84 -0
- package/dist/client_0430_memory_ops.js.map +1 -0
- package/dist/client_0430_ops.d.ts +8 -0
- package/dist/client_0430_ops.d.ts.map +1 -0
- package/dist/client_0430_ops.js +9 -0
- package/dist/client_0430_ops.js.map +1 -0
- package/dist/client_0430_shared.d.ts +15 -0
- package/dist/client_0430_shared.d.ts.map +1 -0
- package/dist/client_0430_shared.js +4 -0
- package/dist/client_0430_shared.js.map +1 -0
- package/dist/client_0434_ops.d.ts +10 -0
- package/dist/client_0434_ops.d.ts.map +1 -0
- package/dist/client_0434_ops.js +43 -0
- package/dist/client_0434_ops.js.map +1 -0
- package/dist/client_chat_ops.d.ts +28 -0
- package/dist/client_chat_ops.d.ts.map +1 -0
- package/dist/client_chat_ops.js +213 -0
- package/dist/client_chat_ops.js.map +1 -0
- package/dist/client_connect_ops.d.ts +9 -0
- package/dist/client_connect_ops.d.ts.map +1 -0
- package/dist/client_connect_ops.js +44 -0
- package/dist/client_connect_ops.js.map +1 -0
- package/dist/client_group_space_ops.d.ts +24 -0
- package/dist/client_group_space_ops.d.ts.map +1 -0
- package/dist/client_group_space_ops.js +167 -0
- package/dist/client_group_space_ops.js.map +1 -0
- package/dist/errors.d.ts +17 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +26 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/transport.d.ts +4 -3
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +236 -120
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +752 -89
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CCCC SDK client
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { installConnectOps } from './client_connect_ops.js';
|
|
5
|
+
import { DaemonAPIError, DaemonConnectionError, IncompatibleDaemonError, } from './errors.js';
|
|
6
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';
|
|
7
11
|
function compactRecord(input) {
|
|
8
12
|
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
|
|
9
13
|
}
|
|
@@ -17,9 +21,11 @@ function compactRecord(input) {
|
|
|
17
21
|
* ```
|
|
18
22
|
*/
|
|
19
23
|
export class CCCCClient {
|
|
20
|
-
constructor(endpoint, timeoutMs) {
|
|
24
|
+
constructor(endpoint, timeoutMs, ccccHome, endpointExplicit) {
|
|
21
25
|
this._endpoint = endpoint;
|
|
22
26
|
this._timeoutMs = timeoutMs;
|
|
27
|
+
this._ccccHome = ccccHome;
|
|
28
|
+
this._endpointExplicit = endpointExplicit;
|
|
23
29
|
}
|
|
24
30
|
/**
|
|
25
31
|
* Create a new client instance, auto-discovering the daemon endpoint.
|
|
@@ -30,7 +36,7 @@ export class CCCCClient {
|
|
|
30
36
|
static async create(options = {}) {
|
|
31
37
|
const endpoint = options.endpoint ?? await discoverEndpoint(options.ccccHome);
|
|
32
38
|
const timeoutMs = options.timeoutMs ?? 30000;
|
|
33
|
-
return new CCCCClient(endpoint, timeoutMs);
|
|
39
|
+
return new CCCCClient(endpoint, timeoutMs, options.ccccHome, options.endpoint !== undefined);
|
|
34
40
|
}
|
|
35
41
|
/** The resolved daemon endpoint this client connects to. */
|
|
36
42
|
get endpoint() {
|
|
@@ -53,24 +59,38 @@ export class CCCCClient {
|
|
|
53
59
|
op,
|
|
54
60
|
args: args ?? {},
|
|
55
61
|
};
|
|
56
|
-
|
|
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
|
+
}
|
|
57
78
|
if (!response.ok) {
|
|
58
|
-
throw new DaemonAPIError(response.error?.code ?? 'error', response.error?.message ?? 'daemon error', response.error?.details ?? {}, response);
|
|
79
|
+
throw new DaemonAPIError(response.error?.code ?? 'error', response.error?.message ?? 'daemon returned ok=false without an error', response.error?.details ?? {}, response);
|
|
59
80
|
}
|
|
60
81
|
return response;
|
|
61
82
|
}
|
|
62
83
|
/**
|
|
63
84
|
* Send an IPC request and return only the result payload.
|
|
64
|
-
* @typeParam T - Expected result type (defaults to `Record<string, unknown>`).
|
|
65
85
|
* @param op - The IPC operation name.
|
|
66
86
|
* @param args - Operation arguments.
|
|
67
|
-
* @returns The `result` field from the daemon response
|
|
87
|
+
* @returns The `result` field from the daemon response (empty object if absent).
|
|
68
88
|
* @throws {DaemonAPIError} If the daemon returns an error.
|
|
69
89
|
* @throws {DaemonUnavailableError} If the connection fails.
|
|
70
90
|
*/
|
|
71
91
|
async call(op, args) {
|
|
72
92
|
const response = await this.callRaw(op, args);
|
|
73
|
-
return
|
|
93
|
+
return response.result ?? {};
|
|
74
94
|
}
|
|
75
95
|
/**
|
|
76
96
|
* Assert that the connected daemon meets the caller's compatibility requirements.
|
|
@@ -82,8 +102,12 @@ export class CCCCClient {
|
|
|
82
102
|
*/
|
|
83
103
|
async assertCompatible(options = {}) {
|
|
84
104
|
const pingResult = await this.ping();
|
|
85
|
-
const
|
|
86
|
-
const
|
|
105
|
+
const rawIpcV = pingResult['ipc_v'];
|
|
106
|
+
const ipcV = typeof rawIpcV === 'number' ? rawIpcV : 0;
|
|
107
|
+
const rawCaps = pingResult['capabilities'];
|
|
108
|
+
const capabilities = (rawCaps !== null && typeof rawCaps === 'object' && !Array.isArray(rawCaps))
|
|
109
|
+
? rawCaps
|
|
110
|
+
: {};
|
|
87
111
|
// Check IPC version
|
|
88
112
|
const requiredV = options.requireIpcV ?? 1;
|
|
89
113
|
if (ipcV < requiredV) {
|
|
@@ -95,19 +119,83 @@ export class CCCCClient {
|
|
|
95
119
|
throw new IncompatibleDaemonError(`Missing capability: ${cap}`);
|
|
96
120
|
}
|
|
97
121
|
}
|
|
98
|
-
//
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
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')
|
|
102
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
|
+
}
|
|
103
173
|
try {
|
|
104
174
|
await this.callRaw(op, {});
|
|
105
175
|
}
|
|
106
176
|
catch (e) {
|
|
107
|
-
if (e instanceof DaemonAPIError && e.code ===
|
|
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
|
+
}
|
|
108
194
|
throw new IncompatibleDaemonError(`Operation not supported: ${op}`);
|
|
109
195
|
}
|
|
110
|
-
|
|
196
|
+
if (!(e instanceof DaemonAPIError))
|
|
197
|
+
throw e;
|
|
198
|
+
// A structured daemon rejection (e.g. missing_group_id) proves recognition.
|
|
111
199
|
}
|
|
112
200
|
}
|
|
113
201
|
return pingResult;
|
|
@@ -164,6 +252,17 @@ export class CCCCClient {
|
|
|
164
252
|
async groupDelete(groupId, by = 'user') {
|
|
165
253
|
return this.call('group_delete', { group_id: groupId, by });
|
|
166
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
|
+
}
|
|
167
266
|
/**
|
|
168
267
|
* Use group (set active scope)
|
|
169
268
|
*/
|
|
@@ -208,7 +307,7 @@ export class CCCCClient {
|
|
|
208
307
|
async groupAutomationManage(options) {
|
|
209
308
|
const actions = options.actions;
|
|
210
309
|
if (actions.length === 0) {
|
|
211
|
-
throw new DaemonAPIError(
|
|
310
|
+
throw new DaemonAPIError('invalid_args', 'groupAutomationManage requires a non-empty actions array', {});
|
|
212
311
|
}
|
|
213
312
|
const args = {
|
|
214
313
|
group_id: options.groupId,
|
|
@@ -264,7 +363,7 @@ export class CCCCClient {
|
|
|
264
363
|
}
|
|
265
364
|
/**
|
|
266
365
|
* Add an actor to a group.
|
|
267
|
-
* @param options - Actor configuration (id, runtime,
|
|
366
|
+
* @param options - Actor configuration (id, runtime, command, etc.).
|
|
268
367
|
* @returns The daemon result (includes assigned actor id).
|
|
269
368
|
* @throws {DaemonAPIError} On invalid group or duplicate actor id.
|
|
270
369
|
*/
|
|
@@ -273,12 +372,14 @@ export class CCCCClient {
|
|
|
273
372
|
actor_id: options.actorId,
|
|
274
373
|
title: options.title,
|
|
275
374
|
runtime: options.runtime,
|
|
276
|
-
runner: options.runner,
|
|
277
375
|
command: options.command,
|
|
278
376
|
env: options.env,
|
|
279
377
|
env_private: options.envPrivate,
|
|
280
378
|
capability_autoload: options.capabilityAutoload,
|
|
379
|
+
capability_hidden: options.capabilityHidden,
|
|
281
380
|
profile_id: options.profileId,
|
|
381
|
+
profile_scope: options.profileScope,
|
|
382
|
+
profile_owner: options.profileOwner,
|
|
282
383
|
default_scope_key: options.defaultScopeKey,
|
|
283
384
|
submit: options.submit,
|
|
284
385
|
};
|
|
@@ -315,25 +416,10 @@ export class CCCCClient {
|
|
|
315
416
|
return this.call('actor_remove', { group_id: groupId, actor_id: actorId, by });
|
|
316
417
|
}
|
|
317
418
|
/**
|
|
318
|
-
* Start actor
|
|
319
|
-
* @param groupId - Group ID.
|
|
320
|
-
* @param actorId - Actor ID.
|
|
321
|
-
* @param options - Optional settings. Pass `{ idempotent: true }` to suppress errors when the actor is already running.
|
|
322
|
-
* @returns The daemon result.
|
|
323
|
-
* @throws {DaemonAPIError} On error (unless idempotent and actor already running).
|
|
419
|
+
* Start actor
|
|
324
420
|
*/
|
|
325
|
-
async actorStart(groupId, actorId,
|
|
326
|
-
|
|
327
|
-
const idempotent = typeof options === 'object' && options?.idempotent === true;
|
|
328
|
-
try {
|
|
329
|
-
return await this.call('actor_start', { group_id: groupId, actor_id: actorId, by });
|
|
330
|
-
}
|
|
331
|
-
catch (e) {
|
|
332
|
-
if (idempotent && e instanceof DaemonAPIError && e.code === ErrorCodes.CONFLICT) {
|
|
333
|
-
return {};
|
|
334
|
-
}
|
|
335
|
-
throw e;
|
|
336
|
-
}
|
|
421
|
+
async actorStart(groupId, actorId, by = 'user') {
|
|
422
|
+
return this.call('actor_start', { group_id: groupId, actor_id: actorId, by });
|
|
337
423
|
}
|
|
338
424
|
/**
|
|
339
425
|
* Stop actor
|
|
@@ -347,6 +433,23 @@ export class CCCCClient {
|
|
|
347
433
|
async actorRestart(groupId, actorId, by = 'user') {
|
|
348
434
|
return this.call('actor_restart', { group_id: groupId, actor_id: actorId, by });
|
|
349
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
|
+
}
|
|
350
453
|
/**
|
|
351
454
|
* List actor private env keys (without values)
|
|
352
455
|
*/
|
|
@@ -482,35 +585,48 @@ export class CCCCClient {
|
|
|
482
585
|
/**
|
|
483
586
|
* Search the capability registry for one group/caller scope.
|
|
484
587
|
*/
|
|
485
|
-
async capabilitySearch(options
|
|
486
|
-
|
|
588
|
+
async capabilitySearch(options) {
|
|
589
|
+
const args = {
|
|
487
590
|
group_id: options.groupId,
|
|
488
|
-
by: options.by,
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
591
|
+
by: options.by ?? 'user',
|
|
592
|
+
};
|
|
593
|
+
if (options.actorId)
|
|
594
|
+
args['actor_id'] = options.actorId;
|
|
595
|
+
if (options.query)
|
|
596
|
+
args['query'] = options.query;
|
|
597
|
+
if (options.kind !== undefined)
|
|
598
|
+
args['kind'] = options.kind;
|
|
599
|
+
if (options.sourceId)
|
|
600
|
+
args['source_id'] = options.sourceId;
|
|
601
|
+
if (options.trustTier)
|
|
602
|
+
args['trust_tier'] = options.trustTier;
|
|
603
|
+
if (options.qualificationStatus !== undefined)
|
|
604
|
+
args['qualification_status'] = options.qualificationStatus;
|
|
605
|
+
if (options.includeExternal !== undefined)
|
|
606
|
+
args['include_external'] = options.includeExternal;
|
|
607
|
+
if (options.limit !== undefined)
|
|
608
|
+
args['limit'] = options.limit;
|
|
609
|
+
return this.call('capability_search', args);
|
|
498
610
|
}
|
|
499
611
|
/**
|
|
500
612
|
* Enable or disable a capability.
|
|
501
613
|
*/
|
|
502
614
|
async capabilityEnable(options) {
|
|
503
|
-
|
|
615
|
+
const args = {
|
|
504
616
|
group_id: options.groupId,
|
|
505
617
|
capability_id: options.capabilityId,
|
|
506
|
-
scope: options.scope,
|
|
507
|
-
enabled: options.enabled,
|
|
508
|
-
cleanup: options.cleanup,
|
|
509
|
-
by: options.by,
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
618
|
+
scope: options.scope ?? 'session',
|
|
619
|
+
enabled: options.enabled ?? true,
|
|
620
|
+
cleanup: options.cleanup ?? false,
|
|
621
|
+
by: options.by ?? 'user',
|
|
622
|
+
};
|
|
623
|
+
if (options.reason)
|
|
624
|
+
args['reason'] = options.reason;
|
|
625
|
+
if (options.ttlSeconds !== undefined)
|
|
626
|
+
args['ttl_seconds'] = options.ttlSeconds;
|
|
627
|
+
if (options.actorId)
|
|
628
|
+
args['actor_id'] = options.actorId;
|
|
629
|
+
return this.call('capability_enable', args);
|
|
514
630
|
}
|
|
515
631
|
/**
|
|
516
632
|
* Block or unblock a capability.
|
|
@@ -534,15 +650,14 @@ export class CCCCClient {
|
|
|
534
650
|
/**
|
|
535
651
|
* Read effective capability exposure for one caller scope.
|
|
536
652
|
*/
|
|
537
|
-
async capabilityState(options
|
|
538
|
-
const args =
|
|
539
|
-
|
|
540
|
-
:
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return this.call('capability_state', compactRecord(args));
|
|
653
|
+
async capabilityState(options) {
|
|
654
|
+
const args = {
|
|
655
|
+
group_id: options.groupId,
|
|
656
|
+
by: options.by ?? 'user',
|
|
657
|
+
};
|
|
658
|
+
if (options.actorId)
|
|
659
|
+
args['actor_id'] = options.actorId;
|
|
660
|
+
return this.call('capability_state', args);
|
|
546
661
|
}
|
|
547
662
|
/**
|
|
548
663
|
* Read capability allowlist default, overlay, and effective snapshots.
|
|
@@ -643,250 +758,68 @@ export class CCCCClient {
|
|
|
643
758
|
args['actor_id'] = options.actorId;
|
|
644
759
|
return this.call('capability_tool_call', args);
|
|
645
760
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
* @param options - Message content, recipients, and priority.
|
|
652
|
-
* @returns The created event and optional ack event.
|
|
653
|
-
* @throws {DaemonAPIError} On invalid group, missing permissions, etc.
|
|
654
|
-
*/
|
|
655
|
-
async send(options) {
|
|
656
|
-
const args = {
|
|
657
|
-
group_id: options.groupId,
|
|
658
|
-
text: options.text,
|
|
659
|
-
by: options.by ?? 'user',
|
|
660
|
-
priority: options.priority ?? 'normal',
|
|
661
|
-
reply_required: options.replyRequired ?? false,
|
|
662
|
-
};
|
|
663
|
-
if (options.to)
|
|
664
|
-
args['to'] = options.to;
|
|
665
|
-
if (options.path)
|
|
666
|
-
args['path'] = options.path;
|
|
667
|
-
return this.call('send', args);
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Send message across groups.
|
|
671
|
-
* @returns The created event and optional ack event.
|
|
672
|
-
*/
|
|
673
|
-
async sendCrossGroup(options) {
|
|
674
|
-
const args = {
|
|
675
|
-
group_id: options.groupId,
|
|
676
|
-
dst_group_id: options.dstGroupId,
|
|
677
|
-
text: options.text,
|
|
678
|
-
by: options.by ?? 'user',
|
|
679
|
-
priority: options.priority ?? 'normal',
|
|
680
|
-
reply_required: options.replyRequired ?? false,
|
|
681
|
-
};
|
|
682
|
-
if (options.to)
|
|
683
|
-
args['to'] = options.to;
|
|
684
|
-
return this.call('send_cross_group', args);
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Create a durable task and send one linked visible message.
|
|
688
|
-
*/
|
|
689
|
-
async trackedSend(options) {
|
|
690
|
-
const args = compactRecord({
|
|
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({
|
|
691
766
|
group_id: options.groupId,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
waiting_on: options.waitingOn,
|
|
698
|
-
checklist: options.checklist,
|
|
699
|
-
notes: options.notes,
|
|
700
|
-
by: options.by ?? 'user',
|
|
701
|
-
to: options.to,
|
|
702
|
-
priority: options.priority ?? 'normal',
|
|
703
|
-
reply_required: options.replyRequired ?? true,
|
|
704
|
-
path: options.path,
|
|
705
|
-
});
|
|
706
|
-
return this.call('tracked_send', args);
|
|
767
|
+
actor_id: options.actorId,
|
|
768
|
+
by: options.by,
|
|
769
|
+
tool_name: options.toolName,
|
|
770
|
+
arguments: options.toolArguments ?? {},
|
|
771
|
+
}));
|
|
707
772
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
* @returns The created event and optional ack event.
|
|
711
|
-
*/
|
|
712
|
-
async reply(options) {
|
|
713
|
-
const args = {
|
|
773
|
+
async memorySearch(options) {
|
|
774
|
+
return this.call('memory_search', compactRecord({
|
|
714
775
|
group_id: options.groupId,
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Send a message and wait for a reply to it.
|
|
727
|
-
* Opens the event stream **before** sending to avoid race conditions,
|
|
728
|
-
* then yields control to the stream until a matching reply arrives.
|
|
729
|
-
*
|
|
730
|
-
* @param options - Send options plus `listenAs` (the actor to listen as) and optional `waitTimeoutMs`.
|
|
731
|
-
* @returns The reply event (a `chat.message` whose `reply_to` matches the sent event ID).
|
|
732
|
-
* @throws {DaemonAPIError} On send/stream errors.
|
|
733
|
-
* @throws {Error} If the timeout elapses or the signal is aborted before a reply arrives.
|
|
734
|
-
*/
|
|
735
|
-
async sendAndWaitForReply(options) {
|
|
736
|
-
const waitTimeout = options.waitTimeoutMs ?? 60000;
|
|
737
|
-
const deadline = Date.now() + waitTimeout;
|
|
738
|
-
// Open stream FIRST (with sinceTs = now) to avoid missing replies
|
|
739
|
-
// that arrive between send() returning and stream connecting.
|
|
740
|
-
const stream = this.eventsStream({
|
|
741
|
-
groupId: options.groupId,
|
|
742
|
-
by: options.listenAs,
|
|
743
|
-
kinds: ['chat.message'],
|
|
744
|
-
sinceTs: new Date().toISOString(),
|
|
745
|
-
signal: options.signal,
|
|
746
|
-
});
|
|
747
|
-
let nextItem = stream.next();
|
|
748
|
-
// Now send the message
|
|
749
|
-
const sendResult = await this.send(options);
|
|
750
|
-
const sentEventId = sendResult.event.id;
|
|
751
|
-
try {
|
|
752
|
-
while (true) {
|
|
753
|
-
if (options.signal?.aborted) {
|
|
754
|
-
throw new Error('sendAndWaitForReply aborted');
|
|
755
|
-
}
|
|
756
|
-
if (Date.now() > deadline) {
|
|
757
|
-
throw new Error(`sendAndWaitForReply timed out after ${waitTimeout}ms`);
|
|
758
|
-
}
|
|
759
|
-
const { value: item, done } = await nextItem;
|
|
760
|
-
if (done)
|
|
761
|
-
break;
|
|
762
|
-
nextItem = stream.next();
|
|
763
|
-
if (isStreamEvent(item)) {
|
|
764
|
-
const evt = item.event;
|
|
765
|
-
if (evt.kind === 'chat.message') {
|
|
766
|
-
const data = evt.data;
|
|
767
|
-
if (data['reply_to'] === sentEventId) {
|
|
768
|
-
return evt;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
finally {
|
|
775
|
-
await stream.return(undefined);
|
|
776
|
-
}
|
|
777
|
-
throw new Error('sendAndWaitForReply: stream ended without reply');
|
|
778
|
-
}
|
|
779
|
-
/**
|
|
780
|
-
* Acknowledge chat message
|
|
781
|
-
*/
|
|
782
|
-
async chatAck(groupId, actorId, eventId, by) {
|
|
783
|
-
return this.call('chat_ack', {
|
|
784
|
-
group_id: groupId,
|
|
785
|
-
actor_id: actorId,
|
|
786
|
-
event_id: eventId,
|
|
787
|
-
by: by ?? actorId,
|
|
788
|
-
});
|
|
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
|
+
}));
|
|
789
786
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
* @param options - File path (relative to scope root), optional caption and recipients.
|
|
793
|
-
* @returns The created event and optional ack event.
|
|
794
|
-
*/
|
|
795
|
-
async fileSend(options) {
|
|
796
|
-
const args = {
|
|
787
|
+
async memoryGet(options) {
|
|
788
|
+
return this.call('memory_get', compactRecord({
|
|
797
789
|
group_id: options.groupId,
|
|
790
|
+
actor_id: options.actorId,
|
|
798
791
|
path: options.path,
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
args['text'] = options.text;
|
|
805
|
-
if (options.to)
|
|
806
|
-
args['to'] = options.to;
|
|
807
|
-
return this.call('file_send', args);
|
|
792
|
+
target: options.target,
|
|
793
|
+
date: options.date,
|
|
794
|
+
offset: options.offset,
|
|
795
|
+
limit: options.limit,
|
|
796
|
+
}));
|
|
808
797
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
* @param options - Group ID, limit, and max chars.
|
|
812
|
-
* @returns The ledger tail result.
|
|
813
|
-
*/
|
|
814
|
-
async ledgerTail(options) {
|
|
815
|
-
const args = {
|
|
798
|
+
async memoryWrite(options) {
|
|
799
|
+
return this.call('memory_write', compactRecord({
|
|
816
800
|
group_id: options.groupId,
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
801
|
+
actor_id: options.actorId,
|
|
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
|
+
}));
|
|
824
810
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
* @param options - Group ID, actor ID, and line count.
|
|
828
|
-
* @returns The terminal tail result.
|
|
829
|
-
*/
|
|
830
|
-
async terminalTail(options) {
|
|
831
|
-
const args = {
|
|
811
|
+
async memoryHealth(options) {
|
|
812
|
+
return this.call('memory_health', compactRecord({
|
|
832
813
|
group_id: options.groupId,
|
|
833
|
-
|
|
834
|
-
by: options.by ?? 'user',
|
|
835
|
-
};
|
|
836
|
-
if (options.lines !== undefined)
|
|
837
|
-
args['lines'] = options.lines;
|
|
838
|
-
return this.call('terminal_tail', args);
|
|
814
|
+
}));
|
|
839
815
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
// ============================================================
|
|
843
|
-
/**
|
|
844
|
-
* List inbox
|
|
845
|
-
*/
|
|
846
|
-
async inboxList(options) {
|
|
847
|
-
return this.call('inbox_list', {
|
|
816
|
+
async memoryProfileGet(options) {
|
|
817
|
+
return this.call('memory_profile_get', compactRecord({
|
|
848
818
|
group_id: options.groupId,
|
|
849
819
|
actor_id: options.actorId,
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
/**
|
|
856
|
-
* Mark message as read
|
|
857
|
-
*/
|
|
858
|
-
async inboxMarkRead(groupId, actorId, eventId, by = 'user') {
|
|
859
|
-
return this.call('inbox_mark_read', {
|
|
860
|
-
group_id: groupId,
|
|
861
|
-
actor_id: actorId,
|
|
862
|
-
event_id: eventId,
|
|
863
|
-
by,
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
/**
|
|
867
|
-
* Mark all messages as read
|
|
868
|
-
*/
|
|
869
|
-
async inboxMarkAllRead(groupId, actorId, by = 'user', kindFilter = 'all') {
|
|
870
|
-
return this.call('inbox_mark_all_read', {
|
|
871
|
-
group_id: groupId,
|
|
872
|
-
actor_id: actorId,
|
|
873
|
-
by,
|
|
874
|
-
kind_filter: kindFilter,
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
|
-
// ============================================================
|
|
878
|
-
// Convenience methods: notifications
|
|
879
|
-
// ============================================================
|
|
880
|
-
/**
|
|
881
|
-
* Acknowledge notification
|
|
882
|
-
*/
|
|
883
|
-
async notifyAck(groupId, actorId, notifyEventId, by) {
|
|
884
|
-
return this.call('notify_ack', {
|
|
885
|
-
group_id: groupId,
|
|
886
|
-
actor_id: actorId,
|
|
887
|
-
notify_event_id: notifyEventId,
|
|
888
|
-
by: by ?? actorId,
|
|
889
|
-
});
|
|
820
|
+
user_id: options.userId,
|
|
821
|
+
tags: options.tags,
|
|
822
|
+
}));
|
|
890
823
|
}
|
|
891
824
|
// ============================================================
|
|
892
825
|
// Convenience methods: context
|
|
@@ -894,8 +827,8 @@ export class CCCCClient {
|
|
|
894
827
|
/**
|
|
895
828
|
* Get group context
|
|
896
829
|
*/
|
|
897
|
-
async contextGet(groupId) {
|
|
898
|
-
return this.call('context_get', { group_id: groupId });
|
|
830
|
+
async contextGet(groupId, detail = 'full') {
|
|
831
|
+
return this.call('context_get', { group_id: groupId, detail });
|
|
899
832
|
}
|
|
900
833
|
/**
|
|
901
834
|
* Sync context
|
|
@@ -906,12 +839,12 @@ export class CCCCClient {
|
|
|
906
839
|
ops: options.ops,
|
|
907
840
|
by: options.by ?? 'system',
|
|
908
841
|
dry_run: options.dryRun ?? false,
|
|
842
|
+
...(options.ifVersion !== undefined ? { if_version: options.ifVersion } : {}),
|
|
909
843
|
});
|
|
910
844
|
}
|
|
911
845
|
contextOp(groupId, op, by = 'system', dryRun = false) {
|
|
912
846
|
return this.contextSync({ groupId, by, dryRun, ops: [op] });
|
|
913
847
|
}
|
|
914
|
-
/** Update the shared coordination brief (Context Ops v3). */
|
|
915
848
|
async coordinationBriefUpdate(options) {
|
|
916
849
|
return this.contextOp(options.groupId, compactRecord({
|
|
917
850
|
op: 'coordination.brief.update',
|
|
@@ -922,7 +855,6 @@ export class CCCCClient {
|
|
|
922
855
|
project_brief_stale: options.projectBriefStale,
|
|
923
856
|
}), options.by, options.dryRun);
|
|
924
857
|
}
|
|
925
|
-
/** Add a compact coordination decision or handoff note. */
|
|
926
858
|
async coordinationNoteAdd(options) {
|
|
927
859
|
return this.contextOp(options.groupId, compactRecord({
|
|
928
860
|
op: 'coordination.note.add',
|
|
@@ -931,7 +863,6 @@ export class CCCCClient {
|
|
|
931
863
|
task_id: options.taskId,
|
|
932
864
|
}), options.by, options.dryRun);
|
|
933
865
|
}
|
|
934
|
-
/** Create a Context Ops v3 task. */
|
|
935
866
|
async taskCreate(options) {
|
|
936
867
|
return this.contextOp(options.groupId, compactRecord({
|
|
937
868
|
op: 'task.create',
|
|
@@ -949,7 +880,6 @@ export class CCCCClient {
|
|
|
949
880
|
checklist: options.checklist,
|
|
950
881
|
}), options.by, options.dryRun);
|
|
951
882
|
}
|
|
952
|
-
/** Update a Context Ops v3 task. */
|
|
953
883
|
async taskUpdate(options) {
|
|
954
884
|
return this.contextOp(options.groupId, compactRecord({
|
|
955
885
|
op: 'task.update',
|
|
@@ -966,7 +896,6 @@ export class CCCCClient {
|
|
|
966
896
|
checklist: options.checklist,
|
|
967
897
|
}), options.by, options.dryRun);
|
|
968
898
|
}
|
|
969
|
-
/** Move a task through the canonical lifecycle operation. */
|
|
970
899
|
async taskMove(options) {
|
|
971
900
|
return this.contextOp(options.groupId, {
|
|
972
901
|
op: 'task.move',
|
|
@@ -974,14 +903,18 @@ export class CCCCClient {
|
|
|
974
903
|
status: options.status,
|
|
975
904
|
}, options.by, options.dryRun);
|
|
976
905
|
}
|
|
977
|
-
/** Restore an archived task. */
|
|
978
906
|
async taskRestore(options) {
|
|
979
907
|
return this.contextOp(options.groupId, {
|
|
980
908
|
op: 'task.restore',
|
|
981
909
|
task_id: options.taskId,
|
|
982
910
|
}, options.by, options.dryRun);
|
|
983
911
|
}
|
|
984
|
-
|
|
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
|
+
}
|
|
985
918
|
async agentStateUpdate(options) {
|
|
986
919
|
return this.contextOp(options.groupId, compactRecord({
|
|
987
920
|
op: 'agent_state.update',
|
|
@@ -996,17 +929,14 @@ export class CCCCClient {
|
|
|
996
929
|
environment_summary: options.environmentSummary,
|
|
997
930
|
user_model: options.userModel,
|
|
998
931
|
persona_notes: options.personaNotes,
|
|
999
|
-
resume_hint: options.resumeHint,
|
|
1000
932
|
}), options.by, options.dryRun);
|
|
1001
933
|
}
|
|
1002
|
-
/** Clear per-actor working memory. */
|
|
1003
934
|
async agentStateClear(options) {
|
|
1004
935
|
return this.contextOp(options.groupId, {
|
|
1005
936
|
op: 'agent_state.clear',
|
|
1006
937
|
actor_id: options.actorId,
|
|
1007
938
|
}, options.by, options.dryRun);
|
|
1008
939
|
}
|
|
1009
|
-
/** Merge restricted projection metadata. */
|
|
1010
940
|
async metaMerge(options) {
|
|
1011
941
|
return this.contextOp(options.groupId, {
|
|
1012
942
|
op: 'meta.merge',
|
|
@@ -1014,268 +944,449 @@ export class CCCCClient {
|
|
|
1014
944
|
}, options.by, options.dryRun);
|
|
1015
945
|
}
|
|
1016
946
|
// ============================================================
|
|
1017
|
-
// Convenience methods:
|
|
947
|
+
// Convenience methods: tracked delegation
|
|
1018
948
|
// ============================================================
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
by: options.by,
|
|
1027
|
-
tool_name: options.toolName,
|
|
1028
|
-
arguments: options.toolArguments ?? {},
|
|
1029
|
-
}));
|
|
1030
|
-
}
|
|
1031
|
-
async memorySearch(options) {
|
|
1032
|
-
return this.call('memory_search', compactRecord({
|
|
949
|
+
/**
|
|
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).
|
|
953
|
+
*/
|
|
954
|
+
async trackedSend(options) {
|
|
955
|
+
const args = {
|
|
1033
956
|
group_id: options.groupId,
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
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);
|
|
1040
997
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
}
|
|
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);
|
|
1051
1040
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1041
|
+
// ============================================================
|
|
1042
|
+
// Convenience methods: headless runtime control
|
|
1043
|
+
// ============================================================
|
|
1044
|
+
async headlessStatus(options) {
|
|
1045
|
+
return this.call('headless_status', {
|
|
1054
1046
|
group_id: options.groupId,
|
|
1055
1047
|
actor_id: options.actorId,
|
|
1056
|
-
|
|
1057
|
-
content: options.content,
|
|
1058
|
-
tags: options.tags,
|
|
1059
|
-
source_refs: options.sourceRefs,
|
|
1060
|
-
idempotency_key: options.idempotencyKey,
|
|
1061
|
-
dedup_intent: options.dedupIntent,
|
|
1062
|
-
dedup_query: options.dedupQuery,
|
|
1063
|
-
}));
|
|
1064
|
-
}
|
|
1065
|
-
async memoryHealth(options = {}) {
|
|
1066
|
-
return this.call('memory_health', compactRecord({
|
|
1067
|
-
group_id: options.groupId,
|
|
1068
|
-
}));
|
|
1048
|
+
});
|
|
1069
1049
|
}
|
|
1070
|
-
async
|
|
1071
|
-
|
|
1050
|
+
async headlessSetStatus(options) {
|
|
1051
|
+
const args = {
|
|
1072
1052
|
group_id: options.groupId,
|
|
1073
1053
|
actor_id: options.actorId,
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1054
|
+
status: options.status,
|
|
1055
|
+
};
|
|
1056
|
+
if (options.taskId)
|
|
1057
|
+
args['task_id'] = options.taskId;
|
|
1058
|
+
return this.call('headless_set_status', args);
|
|
1077
1059
|
}
|
|
1078
1060
|
// ============================================================
|
|
1079
|
-
// Convenience methods:
|
|
1061
|
+
// Convenience methods: group copy (export/import)
|
|
1080
1062
|
// ============================================================
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
*/
|
|
1084
|
-
async groupSpaceStatus(options) {
|
|
1085
|
-
return this.call('group_space_status', {
|
|
1063
|
+
async groupCopyExport(options) {
|
|
1064
|
+
return this.call('group_copy_export', {
|
|
1086
1065
|
group_id: options.groupId,
|
|
1087
|
-
|
|
1066
|
+
by: options.by ?? 'user',
|
|
1088
1067
|
});
|
|
1089
1068
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
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
|
+
}));
|
|
1098
1079
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
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,
|
|
1106
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);
|
|
1107
1095
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
async
|
|
1096
|
+
// ============================================================
|
|
1097
|
+
// Convenience methods: capability extensions
|
|
1098
|
+
// ============================================================
|
|
1099
|
+
async capabilityVisibility(options) {
|
|
1112
1100
|
const args = {
|
|
1113
1101
|
group_id: options.groupId,
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
action: options.action ?? 'bind',
|
|
1102
|
+
capability_id: options.capabilityId,
|
|
1103
|
+
hidden: options.hidden ?? true,
|
|
1117
1104
|
by: options.by ?? 'user',
|
|
1118
1105
|
};
|
|
1119
|
-
if (options.
|
|
1120
|
-
args['
|
|
1121
|
-
|
|
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);
|
|
1122
1111
|
}
|
|
1123
|
-
|
|
1124
|
-
* Enqueue one Group Space ingest action.
|
|
1125
|
-
*/
|
|
1126
|
-
async groupSpaceIngest(options) {
|
|
1112
|
+
async capabilityInstallTarget(options) {
|
|
1127
1113
|
const args = {
|
|
1128
1114
|
group_id: options.groupId,
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
kind: options.kind ?? 'context_sync',
|
|
1115
|
+
target: options.target,
|
|
1116
|
+
scope: options.scope ?? 'actor',
|
|
1132
1117
|
by: options.by ?? 'user',
|
|
1133
1118
|
};
|
|
1134
|
-
if (options.
|
|
1135
|
-
args['
|
|
1136
|
-
if (options.
|
|
1137
|
-
args['
|
|
1138
|
-
|
|
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);
|
|
1139
1126
|
}
|
|
1140
|
-
|
|
1141
|
-
* Query Group Space knowledge for one lane.
|
|
1142
|
-
*/
|
|
1143
|
-
async groupSpaceQuery(options) {
|
|
1127
|
+
async capabilitySourceDelete(options) {
|
|
1144
1128
|
const args = {
|
|
1145
1129
|
group_id: options.groupId,
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
query: options.query,
|
|
1130
|
+
source_id: options.sourceId,
|
|
1131
|
+
by: options.by ?? 'user',
|
|
1149
1132
|
};
|
|
1150
|
-
if (options.
|
|
1151
|
-
args['
|
|
1152
|
-
|
|
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);
|
|
1153
1138
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
async
|
|
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) {
|
|
1158
1146
|
const args = {
|
|
1159
1147
|
group_id: options.groupId,
|
|
1160
|
-
provider: options.provider ?? 'notebooklm',
|
|
1161
|
-
lane: options.lane,
|
|
1162
|
-
action: options.action ?? 'list',
|
|
1163
1148
|
by: options.by ?? 'user',
|
|
1164
1149
|
};
|
|
1165
|
-
if (options.
|
|
1166
|
-
args['
|
|
1167
|
-
if (options.
|
|
1168
|
-
args['
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
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) {
|
|
1175
1175
|
const args = {
|
|
1176
1176
|
group_id: options.groupId,
|
|
1177
|
-
provider: options.provider ?? 'notebooklm',
|
|
1178
|
-
lane: options.lane,
|
|
1179
|
-
action: options.action ?? 'list',
|
|
1180
1177
|
by: options.by ?? 'user',
|
|
1181
1178
|
};
|
|
1182
|
-
if (options.
|
|
1183
|
-
args['
|
|
1184
|
-
|
|
1185
|
-
args['options'] = options.options;
|
|
1186
|
-
if (options.wait !== undefined)
|
|
1187
|
-
args['wait'] = options.wait;
|
|
1188
|
-
if (options.saveToSpace !== undefined)
|
|
1189
|
-
args['save_to_space'] = options.saveToSpace;
|
|
1190
|
-
if (options.outputPath)
|
|
1191
|
-
args['output_path'] = options.outputPath;
|
|
1192
|
-
if (options.outputFormat)
|
|
1193
|
-
args['output_format'] = options.outputFormat;
|
|
1194
|
-
if (options.artifactId)
|
|
1195
|
-
args['artifact_id'] = options.artifactId;
|
|
1196
|
-
if (options.timeoutSeconds !== undefined)
|
|
1197
|
-
args['timeout_seconds'] = options.timeoutSeconds;
|
|
1198
|
-
if (options.initialInterval !== undefined)
|
|
1199
|
-
args['initial_interval'] = options.initialInterval;
|
|
1200
|
-
if (options.maxInterval !== undefined)
|
|
1201
|
-
args['max_interval'] = options.maxInterval;
|
|
1202
|
-
return this.call('group_space_artifact', args);
|
|
1179
|
+
if (options.slot)
|
|
1180
|
+
args['slot'] = options.slot;
|
|
1181
|
+
return this.call('presentation_clear', args);
|
|
1203
1182
|
}
|
|
1204
|
-
/**
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
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({
|
|
1209
1211
|
group_id: options.groupId,
|
|
1210
|
-
|
|
1211
|
-
lane: options.lane,
|
|
1212
|
-
action: options.action ?? 'list',
|
|
1212
|
+
action: options.action,
|
|
1213
1213
|
by: options.by ?? 'user',
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
args['limit'] = options.limit;
|
|
1221
|
-
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
|
+
}));
|
|
1222
1220
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
*/
|
|
1226
|
-
async groupSpaceSync(options) {
|
|
1227
|
-
return this.call('group_space_sync', {
|
|
1221
|
+
async assistantSettingsUpdate(options) {
|
|
1222
|
+
return this.call('assistant_settings_update', {
|
|
1228
1223
|
group_id: options.groupId,
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
action: options.action ?? 'status',
|
|
1232
|
-
force: options.force ?? false,
|
|
1224
|
+
assistant_id: options.assistantId,
|
|
1225
|
+
patch: options.patch,
|
|
1233
1226
|
by: options.by ?? 'user',
|
|
1234
1227
|
});
|
|
1235
1228
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1229
|
+
async assistantStatusUpdate(options) {
|
|
1230
|
+
const args = {
|
|
1231
|
+
group_id: options.groupId,
|
|
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,
|
|
1242
1254
|
by: options.by ?? 'user',
|
|
1243
1255
|
});
|
|
1244
1256
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
async
|
|
1257
|
+
async brandingGet() {
|
|
1258
|
+
return this.call('branding_get', {});
|
|
1259
|
+
}
|
|
1260
|
+
async brandingUpdate(options) {
|
|
1261
|
+
return this.call('branding_update', {
|
|
1262
|
+
patch: options.patch,
|
|
1263
|
+
by: options.by ?? 'user',
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
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) {
|
|
1249
1276
|
const args = {
|
|
1250
|
-
|
|
1277
|
+
component: options.component,
|
|
1251
1278
|
by: options.by ?? 'user',
|
|
1252
|
-
|
|
1279
|
+
lines: options.lines ?? 200,
|
|
1253
1280
|
};
|
|
1254
|
-
if (options.
|
|
1255
|
-
args['
|
|
1256
|
-
return this.call('
|
|
1281
|
+
if (options.groupId)
|
|
1282
|
+
args['group_id'] = options.groupId;
|
|
1283
|
+
return this.call('debug_tail_logs', args);
|
|
1257
1284
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
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,
|
|
1308
|
+
by: options.by ?? 'user',
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
// ============================================================
|
|
1312
|
+
// Convenience methods: maintenance (ledger)
|
|
1313
|
+
// ============================================================
|
|
1314
|
+
async ledgerSnapshot(options) {
|
|
1315
|
+
return this.call('ledger_snapshot', {
|
|
1316
|
+
group_id: options.groupId,
|
|
1264
1317
|
by: options.by ?? 'user',
|
|
1318
|
+
reason: options.reason ?? 'manual',
|
|
1265
1319
|
});
|
|
1266
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
|
+
// ============================================================
|
|
1267
1332
|
/**
|
|
1268
|
-
*
|
|
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'.
|
|
1269
1336
|
*/
|
|
1270
|
-
async
|
|
1337
|
+
async streamEmit(options) {
|
|
1271
1338
|
const args = {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
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',
|
|
1275
1363
|
};
|
|
1276
|
-
if (options.
|
|
1277
|
-
args['
|
|
1278
|
-
|
|
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
|
+
});
|
|
1279
1390
|
}
|
|
1280
1391
|
// ============================================================
|
|
1281
1392
|
// Event stream
|
|
@@ -1284,12 +1395,11 @@ export class CCCCClient {
|
|
|
1284
1395
|
* Subscribe to the group event stream (Server-Sent Events style, long-lived connection).
|
|
1285
1396
|
* Yields {@link EventStreamItem} objects as they arrive. The socket is destroyed
|
|
1286
1397
|
* when the generator is returned or thrown.
|
|
1287
|
-
* @param options - Group ID, event filters, optional since cursor
|
|
1398
|
+
* @param options - Group ID, event filters, and optional since cursor.
|
|
1288
1399
|
* @yields {EventStreamItem} Each event or heartbeat from the stream.
|
|
1289
1400
|
* @throws {DaemonAPIError} If the handshake fails.
|
|
1290
1401
|
*/
|
|
1291
1402
|
async *eventsStream(options) {
|
|
1292
|
-
// Check abort before connecting
|
|
1293
1403
|
if (options.signal?.aborted)
|
|
1294
1404
|
return;
|
|
1295
1405
|
const args = {
|
|
@@ -1312,44 +1422,61 @@ export class CCCCClient {
|
|
|
1312
1422
|
op: 'events_stream',
|
|
1313
1423
|
args,
|
|
1314
1424
|
};
|
|
1315
|
-
const
|
|
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
|
+
}
|
|
1316
1446
|
if (!handshake.ok) {
|
|
1317
1447
|
socket.destroy();
|
|
1318
1448
|
throw new DaemonAPIError(handshake.error?.code ?? 'unknown', handshake.error?.message ?? 'Handshake failed', handshake.error?.details, handshake);
|
|
1319
1449
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
1450
|
+
const abortStream = () => socket.destroy();
|
|
1451
|
+
options.signal?.addEventListener('abort', abortStream, { once: true });
|
|
1323
1452
|
try {
|
|
1324
1453
|
for await (const line of readLines(socket, initialBuffer)) {
|
|
1325
|
-
if (options.signal?.aborted)
|
|
1326
|
-
return;
|
|
1327
|
-
let parsed;
|
|
1328
1454
|
try {
|
|
1329
|
-
parsed = JSON.parse(line);
|
|
1330
|
-
|
|
1331
|
-
catch {
|
|
1332
|
-
// Non-JSON line from daemon; surface as an error so callers know
|
|
1333
|
-
// something unexpected happened instead of silently losing data.
|
|
1334
|
-
throw new DaemonAPIError('invalid_stream_data', `Unparseable event stream line: ${line.slice(0, 200)}`, {});
|
|
1335
|
-
}
|
|
1336
|
-
if (parsed !== null && typeof parsed === 'object') {
|
|
1337
|
-
const obj = parsed;
|
|
1338
|
-
// Daemon may send error objects in the stream (ok: false).
|
|
1339
|
-
if ('ok' in obj && obj['ok'] === false) {
|
|
1340
|
-
const err = obj['error'];
|
|
1341
|
-
throw new DaemonAPIError(err?.['code'] ?? 'stream_error', err?.['message'] ?? 'Daemon sent error in event stream', err?.['details'] ?? {}, obj);
|
|
1342
|
-
}
|
|
1343
|
-
if ('t' in obj) {
|
|
1455
|
+
const parsed = JSON.parse(line);
|
|
1456
|
+
if (parsed !== null && typeof parsed === 'object' && 't' in parsed) {
|
|
1344
1457
|
yield parsed;
|
|
1345
1458
|
}
|
|
1346
1459
|
}
|
|
1460
|
+
catch {
|
|
1461
|
+
// Skip invalid JSON lines.
|
|
1462
|
+
}
|
|
1347
1463
|
}
|
|
1348
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
|
+
}
|
|
1349
1471
|
finally {
|
|
1350
|
-
options.signal?.removeEventListener('abort',
|
|
1472
|
+
options.signal?.removeEventListener('abort', abortStream);
|
|
1351
1473
|
socket.destroy();
|
|
1352
1474
|
}
|
|
1353
1475
|
}
|
|
1354
1476
|
}
|
|
1477
|
+
installCCCC0430Ops(CCCCClient.prototype);
|
|
1478
|
+
installCCCC0434Ops(CCCCClient.prototype);
|
|
1479
|
+
installGroupSpaceOps(CCCCClient.prototype);
|
|
1480
|
+
installChatOps(CCCCClient.prototype);
|
|
1481
|
+
installConnectOps(CCCCClient.prototype);
|
|
1355
1482
|
//# sourceMappingURL=client.js.map
|