cccc-sdk 0.1.0 → 0.1.1
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 +68 -186
- package/dist/client.d.ts +101 -186
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +373 -410
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +28 -10
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +42 -16
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -0
- package/dist/transport.d.ts +19 -24
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +202 -92
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +273 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +24 -25
- package/dist/types/actor.d.ts +0 -42
- package/dist/types/actor.d.ts.map +0 -1
- package/dist/types/actor.js +0 -5
- package/dist/types/actor.js.map +0 -1
- package/dist/types/context.d.ts +0 -89
- package/dist/types/context.d.ts.map +0 -1
- package/dist/types/context.js +0 -5
- package/dist/types/context.js.map +0 -1
- package/dist/types/event.d.ts +0 -15
- package/dist/types/event.d.ts.map +0 -1
- package/dist/types/event.js +0 -5
- package/dist/types/event.js.map +0 -1
- package/dist/types/group.d.ts +0 -33
- package/dist/types/group.d.ts.map +0 -1
- package/dist/types/group.js +0 -5
- package/dist/types/group.js.map +0 -1
- package/dist/types/index.d.ts +0 -10
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -10
- package/dist/types/index.js.map +0 -1
- package/dist/types/ipc.d.ts +0 -24
- package/dist/types/ipc.d.ts.map +0 -1
- package/dist/types/ipc.js +0 -10
- package/dist/types/ipc.js.map +0 -1
- package/dist/types/message.d.ts +0 -53
- package/dist/types/message.d.ts.map +0 -1
- package/dist/types/message.js +0 -5
- package/dist/types/message.js.map +0 -1
package/dist/client.js
CHANGED
|
@@ -1,536 +1,499 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CCCC
|
|
3
|
-
*
|
|
4
|
-
* High-level API for interacting with CCCC daemon
|
|
2
|
+
* CCCC SDK client
|
|
5
3
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { CCCCError } from './errors.js';
|
|
4
|
+
import { DaemonAPIError, IncompatibleDaemonError, } from './errors.js';
|
|
5
|
+
import { discoverEndpoint, callDaemon, openEventsStream, readLines, } from './transport.js';
|
|
9
6
|
/**
|
|
10
|
-
*
|
|
7
|
+
* CCCC client
|
|
11
8
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
throw new CCCCError('DAEMON_ERROR', 'Unknown daemon error');
|
|
18
|
-
}
|
|
19
|
-
return response.result;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Groups API
|
|
23
|
-
*/
|
|
24
|
-
class GroupsAPI {
|
|
25
|
-
client;
|
|
26
|
-
constructor(client) {
|
|
27
|
-
this.client = client;
|
|
9
|
+
export class CCCCClient {
|
|
10
|
+
constructor(endpoint, timeoutMs) {
|
|
11
|
+
this._endpoint = endpoint;
|
|
12
|
+
this._timeoutMs = timeoutMs;
|
|
28
13
|
}
|
|
29
14
|
/**
|
|
30
|
-
*
|
|
15
|
+
* Async factory method: create a client instance
|
|
31
16
|
*/
|
|
32
|
-
async
|
|
33
|
-
const
|
|
34
|
-
|
|
17
|
+
static async create(options = {}) {
|
|
18
|
+
const endpoint = options.endpoint ?? await discoverEndpoint(options.ccccHome);
|
|
19
|
+
const timeoutMs = options.timeoutMs ?? 30000;
|
|
20
|
+
return new CCCCClient(endpoint, timeoutMs);
|
|
35
21
|
}
|
|
36
22
|
/**
|
|
37
|
-
* Get
|
|
23
|
+
* Get the current endpoint
|
|
38
24
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return handleResponse(response);
|
|
25
|
+
get endpoint() {
|
|
26
|
+
return this._endpoint;
|
|
42
27
|
}
|
|
28
|
+
// ============================================================
|
|
29
|
+
// Low-level API
|
|
30
|
+
// ============================================================
|
|
43
31
|
/**
|
|
44
|
-
*
|
|
32
|
+
* Send raw IPC request and return the full response
|
|
45
33
|
*/
|
|
46
|
-
async
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
async setState(groupId, state, by) {
|
|
58
|
-
const response = await this.client.call('group_set_state', {
|
|
59
|
-
group_id: groupId,
|
|
60
|
-
state,
|
|
61
|
-
by,
|
|
62
|
-
});
|
|
63
|
-
handleResponse(response);
|
|
34
|
+
async callRaw(op, args) {
|
|
35
|
+
const request = {
|
|
36
|
+
v: 1,
|
|
37
|
+
op,
|
|
38
|
+
args: args ?? {},
|
|
39
|
+
};
|
|
40
|
+
const response = await callDaemon(this._endpoint, request, this._timeoutMs);
|
|
41
|
+
if (!response.ok && response.error) {
|
|
42
|
+
throw new DaemonAPIError(response.error.code, response.error.message, response.error.details, response);
|
|
43
|
+
}
|
|
44
|
+
return response;
|
|
64
45
|
}
|
|
65
46
|
/**
|
|
66
|
-
*
|
|
47
|
+
* Send IPC request and return only result payload
|
|
67
48
|
*/
|
|
68
|
-
async
|
|
69
|
-
const response = await this.
|
|
70
|
-
|
|
49
|
+
async call(op, args) {
|
|
50
|
+
const response = await this.callRaw(op, args);
|
|
51
|
+
return response.result ?? {};
|
|
71
52
|
}
|
|
72
53
|
/**
|
|
73
|
-
*
|
|
54
|
+
* Compatibility check
|
|
74
55
|
*/
|
|
75
|
-
async
|
|
76
|
-
const
|
|
77
|
-
|
|
56
|
+
async assertCompatible(options = {}) {
|
|
57
|
+
const pingResult = await this.ping();
|
|
58
|
+
const ipcV = pingResult['ipc_v'] ?? 0;
|
|
59
|
+
const capabilities = pingResult['capabilities'] ?? {};
|
|
60
|
+
// Check IPC version
|
|
61
|
+
const requiredV = options.requireIpcV ?? 1;
|
|
62
|
+
if (ipcV < requiredV) {
|
|
63
|
+
throw new IncompatibleDaemonError(`IPC version ${ipcV} < required ${requiredV}`);
|
|
64
|
+
}
|
|
65
|
+
// Check capabilities
|
|
66
|
+
for (const [cap, required] of Object.entries(options.requireCapabilities ?? {})) {
|
|
67
|
+
if (required && !capabilities[cap]) {
|
|
68
|
+
throw new IncompatibleDaemonError(`Missing capability: ${cap}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Check operation support by probing
|
|
72
|
+
const reservedOps = new Set(['ping', 'shutdown', 'events_stream', 'term_attach']);
|
|
73
|
+
for (const op of options.requireOps ?? []) {
|
|
74
|
+
if (reservedOps.has(op))
|
|
75
|
+
continue;
|
|
76
|
+
try {
|
|
77
|
+
await this.callRaw(op, {});
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (e instanceof DaemonAPIError && e.code === 'unknown_op') {
|
|
81
|
+
throw new IncompatibleDaemonError(`Operation not supported: ${op}`);
|
|
82
|
+
}
|
|
83
|
+
// Other errors (e.g. missing_group_id) imply the operation exists.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return pingResult;
|
|
78
87
|
}
|
|
88
|
+
// ============================================================
|
|
89
|
+
// Convenience methods: diagnostics
|
|
90
|
+
// ============================================================
|
|
79
91
|
/**
|
|
80
|
-
*
|
|
92
|
+
* Ping daemon
|
|
81
93
|
*/
|
|
82
|
-
async
|
|
83
|
-
|
|
84
|
-
group_id: groupId,
|
|
85
|
-
patch,
|
|
86
|
-
});
|
|
87
|
-
handleResponse(response);
|
|
94
|
+
async ping() {
|
|
95
|
+
return this.call('ping');
|
|
88
96
|
}
|
|
97
|
+
// ============================================================
|
|
98
|
+
// Convenience methods: group operations
|
|
99
|
+
// ============================================================
|
|
89
100
|
/**
|
|
90
|
-
*
|
|
101
|
+
* List all groups
|
|
91
102
|
*/
|
|
92
|
-
async
|
|
93
|
-
|
|
94
|
-
handleResponse(response);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Actors API
|
|
99
|
-
*/
|
|
100
|
-
class ActorsAPI {
|
|
101
|
-
client;
|
|
102
|
-
constructor(client) {
|
|
103
|
-
this.client = client;
|
|
103
|
+
async groups() {
|
|
104
|
+
return this.call('groups');
|
|
104
105
|
}
|
|
105
106
|
/**
|
|
106
|
-
*
|
|
107
|
+
* Show group details
|
|
107
108
|
*/
|
|
108
|
-
async
|
|
109
|
-
|
|
110
|
-
return (handleResponse(response)).actors;
|
|
109
|
+
async groupShow(groupId) {
|
|
110
|
+
return this.call('group_show', { group_id: groupId });
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
113
|
+
* Create group
|
|
114
114
|
*/
|
|
115
|
-
async
|
|
116
|
-
|
|
117
|
-
group_id: groupId,
|
|
118
|
-
by,
|
|
119
|
-
actor_id: options.actor_id,
|
|
120
|
-
runtime: options.runtime ?? 'claude',
|
|
121
|
-
runner: options.runner ?? 'pty',
|
|
115
|
+
async groupCreate(options = {}) {
|
|
116
|
+
return this.call('group_create', {
|
|
122
117
|
title: options.title ?? '',
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
topic: options.topic ?? '',
|
|
119
|
+
by: options.by ?? 'user',
|
|
125
120
|
});
|
|
126
|
-
return handleResponse(response).actor;
|
|
127
121
|
}
|
|
128
122
|
/**
|
|
129
|
-
*
|
|
123
|
+
* Update group
|
|
130
124
|
*/
|
|
131
|
-
async
|
|
132
|
-
|
|
133
|
-
group_id: groupId,
|
|
134
|
-
|
|
135
|
-
by,
|
|
125
|
+
async groupUpdate(options) {
|
|
126
|
+
return this.call('group_update', {
|
|
127
|
+
group_id: options.groupId,
|
|
128
|
+
patch: options.patch,
|
|
129
|
+
by: options.by ?? 'user',
|
|
136
130
|
});
|
|
137
|
-
handleResponse(response);
|
|
138
131
|
}
|
|
139
132
|
/**
|
|
140
|
-
*
|
|
133
|
+
* Delete group
|
|
141
134
|
*/
|
|
142
|
-
async
|
|
143
|
-
|
|
144
|
-
group_id: groupId,
|
|
145
|
-
actor_id: actorId,
|
|
146
|
-
by,
|
|
147
|
-
});
|
|
148
|
-
handleResponse(response);
|
|
135
|
+
async groupDelete(groupId, by = 'user') {
|
|
136
|
+
return this.call('group_delete', { group_id: groupId, by });
|
|
149
137
|
}
|
|
150
138
|
/**
|
|
151
|
-
*
|
|
139
|
+
* Use group (set active scope)
|
|
152
140
|
*/
|
|
153
|
-
async
|
|
154
|
-
|
|
155
|
-
group_id: groupId,
|
|
156
|
-
actor_id: actorId,
|
|
157
|
-
by,
|
|
158
|
-
});
|
|
159
|
-
handleResponse(response);
|
|
141
|
+
async groupUse(groupId, path, by = 'user') {
|
|
142
|
+
return this.call('group_use', { group_id: groupId, path, by });
|
|
160
143
|
}
|
|
161
144
|
/**
|
|
162
|
-
*
|
|
145
|
+
* Set group state
|
|
163
146
|
*/
|
|
164
|
-
async
|
|
165
|
-
|
|
166
|
-
group_id: groupId,
|
|
167
|
-
actor_id: actorId,
|
|
168
|
-
by,
|
|
169
|
-
});
|
|
170
|
-
handleResponse(response);
|
|
147
|
+
async groupSetState(groupId, state, by = 'user') {
|
|
148
|
+
return this.call('group_set_state', { group_id: groupId, state, by });
|
|
171
149
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
client;
|
|
178
|
-
constructor(client) {
|
|
179
|
-
this.client = client;
|
|
150
|
+
/**
|
|
151
|
+
* Update group settings
|
|
152
|
+
*/
|
|
153
|
+
async groupSettingsUpdate(groupId, patch, by = 'user') {
|
|
154
|
+
return this.call('group_settings_update', { group_id: groupId, patch, by });
|
|
180
155
|
}
|
|
181
156
|
/**
|
|
182
|
-
*
|
|
157
|
+
* Read group-level automation state (rules, snippets, next run, ...)
|
|
183
158
|
*/
|
|
184
|
-
async
|
|
185
|
-
|
|
186
|
-
group_id: groupId,
|
|
187
|
-
by,
|
|
188
|
-
text: options.text,
|
|
189
|
-
to: options.to ?? [],
|
|
190
|
-
format: options.format ?? 'plain',
|
|
191
|
-
});
|
|
192
|
-
return handleResponse(response).event;
|
|
159
|
+
async groupAutomationState(groupId, by = 'user') {
|
|
160
|
+
return this.call('group_automation_state', { group_id: groupId, by });
|
|
193
161
|
}
|
|
194
162
|
/**
|
|
195
|
-
*
|
|
163
|
+
* Replace group-level automation (rules + snippets)
|
|
196
164
|
*/
|
|
197
|
-
async
|
|
198
|
-
const
|
|
199
|
-
group_id: groupId,
|
|
200
|
-
by,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
165
|
+
async groupAutomationUpdate(options) {
|
|
166
|
+
const args = {
|
|
167
|
+
group_id: options.groupId,
|
|
168
|
+
by: options.by ?? 'user',
|
|
169
|
+
ruleset: options.ruleset,
|
|
170
|
+
};
|
|
171
|
+
if (options.expectedVersion !== undefined) {
|
|
172
|
+
args['expected_version'] = options.expectedVersion;
|
|
173
|
+
}
|
|
174
|
+
return this.call('group_automation_update', args);
|
|
206
175
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Incrementally manage group-level automation (actions[])
|
|
178
|
+
*/
|
|
179
|
+
async groupAutomationManage(options) {
|
|
180
|
+
const actions = options.actions;
|
|
181
|
+
if (actions.length === 0) {
|
|
182
|
+
throw new Error('groupAutomationManage requires a non-empty actions array');
|
|
183
|
+
}
|
|
184
|
+
const args = {
|
|
185
|
+
group_id: options.groupId,
|
|
186
|
+
by: options.by ?? 'user',
|
|
187
|
+
actions,
|
|
188
|
+
};
|
|
189
|
+
if (options.expectedVersion !== undefined)
|
|
190
|
+
args['expected_version'] = options.expectedVersion;
|
|
191
|
+
return this.call('group_automation_manage', args);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Reset group-level automation to baseline
|
|
195
|
+
*/
|
|
196
|
+
async groupAutomationResetBaseline(options) {
|
|
197
|
+
const args = {
|
|
198
|
+
group_id: options.groupId,
|
|
199
|
+
by: options.by ?? 'user',
|
|
200
|
+
};
|
|
201
|
+
if (options.expectedVersion !== undefined) {
|
|
202
|
+
args['expected_version'] = options.expectedVersion;
|
|
203
|
+
}
|
|
204
|
+
return this.call('group_automation_reset_baseline', args);
|
|
215
205
|
}
|
|
216
206
|
/**
|
|
217
|
-
*
|
|
207
|
+
* Start group
|
|
218
208
|
*/
|
|
219
|
-
async
|
|
220
|
-
|
|
221
|
-
group_id: groupId,
|
|
222
|
-
actor_id: actorId,
|
|
223
|
-
kind_filter: options.kind_filter ?? 'all',
|
|
224
|
-
limit: options.limit ?? 50,
|
|
225
|
-
});
|
|
226
|
-
return (handleResponse(response)).messages;
|
|
209
|
+
async groupStart(groupId, by = 'user') {
|
|
210
|
+
return this.call('group_start', { group_id: groupId, by });
|
|
227
211
|
}
|
|
228
212
|
/**
|
|
229
|
-
*
|
|
213
|
+
* Stop group
|
|
230
214
|
*/
|
|
231
|
-
async
|
|
232
|
-
|
|
233
|
-
group_id: groupId,
|
|
234
|
-
actor_id: actorId,
|
|
235
|
-
event_id: eventId,
|
|
236
|
-
});
|
|
237
|
-
handleResponse(response);
|
|
215
|
+
async groupStop(groupId, by = 'user') {
|
|
216
|
+
return this.call('group_stop', { group_id: groupId, by });
|
|
238
217
|
}
|
|
239
218
|
/**
|
|
240
|
-
*
|
|
219
|
+
* Attach path to group
|
|
241
220
|
*/
|
|
242
|
-
async
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
handleResponse(response);
|
|
221
|
+
async attach(path, groupId = '', by = 'user') {
|
|
222
|
+
const args = { path, by };
|
|
223
|
+
if (groupId)
|
|
224
|
+
args['group_id'] = groupId;
|
|
225
|
+
return this.call('attach', args);
|
|
248
226
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
this.
|
|
227
|
+
// ============================================================
|
|
228
|
+
// Convenience methods: actor operations
|
|
229
|
+
// ============================================================
|
|
230
|
+
/**
|
|
231
|
+
* List actors in group
|
|
232
|
+
*/
|
|
233
|
+
async actorList(groupId) {
|
|
234
|
+
return this.call('actor_list', { group_id: groupId });
|
|
257
235
|
}
|
|
258
236
|
/**
|
|
259
|
-
*
|
|
237
|
+
* Add actor
|
|
260
238
|
*/
|
|
261
|
-
async
|
|
262
|
-
const
|
|
263
|
-
|
|
239
|
+
async actorAdd(options) {
|
|
240
|
+
const args = {
|
|
241
|
+
group_id: options.groupId,
|
|
242
|
+
by: options.by ?? 'user',
|
|
243
|
+
};
|
|
244
|
+
if (options.actorId)
|
|
245
|
+
args['actor_id'] = options.actorId;
|
|
246
|
+
if (options.title)
|
|
247
|
+
args['title'] = options.title;
|
|
248
|
+
if (options.runtime)
|
|
249
|
+
args['runtime'] = options.runtime;
|
|
250
|
+
if (options.runner)
|
|
251
|
+
args['runner'] = options.runner;
|
|
252
|
+
if (options.command)
|
|
253
|
+
args['command'] = options.command;
|
|
254
|
+
if (options.env)
|
|
255
|
+
args['env'] = options.env;
|
|
256
|
+
if (options.envPrivate)
|
|
257
|
+
args['env_private'] = options.envPrivate;
|
|
258
|
+
if (options.defaultScopeKey)
|
|
259
|
+
args['default_scope_key'] = options.defaultScopeKey;
|
|
260
|
+
if (options.submit)
|
|
261
|
+
args['submit'] = options.submit;
|
|
262
|
+
return this.call('actor_add', args);
|
|
264
263
|
}
|
|
265
264
|
/**
|
|
266
|
-
*
|
|
265
|
+
* Update actor
|
|
267
266
|
*/
|
|
268
|
-
async
|
|
269
|
-
|
|
270
|
-
group_id: groupId,
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
async actorUpdate(options) {
|
|
268
|
+
return this.call('actor_update', {
|
|
269
|
+
group_id: options.groupId,
|
|
270
|
+
actor_id: options.actorId,
|
|
271
|
+
patch: options.patch,
|
|
272
|
+
by: options.by ?? 'user',
|
|
273
273
|
});
|
|
274
|
-
return handleResponse(response);
|
|
275
274
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
client;
|
|
282
|
-
constructor(client) {
|
|
283
|
-
this.client = client;
|
|
275
|
+
/**
|
|
276
|
+
* Remove actor
|
|
277
|
+
*/
|
|
278
|
+
async actorRemove(groupId, actorId, by = 'user') {
|
|
279
|
+
return this.call('actor_remove', { group_id: groupId, actor_id: actorId, by });
|
|
284
280
|
}
|
|
285
281
|
/**
|
|
286
|
-
*
|
|
282
|
+
* Start actor
|
|
287
283
|
*/
|
|
288
|
-
async
|
|
289
|
-
|
|
290
|
-
group_id: groupId,
|
|
291
|
-
include_archived: includeArchived,
|
|
292
|
-
});
|
|
293
|
-
return (handleResponse(response)).tasks;
|
|
284
|
+
async actorStart(groupId, actorId, by = 'user') {
|
|
285
|
+
return this.call('actor_start', { group_id: groupId, actor_id: actorId, by });
|
|
294
286
|
}
|
|
295
287
|
/**
|
|
296
|
-
*
|
|
288
|
+
* Stop actor
|
|
297
289
|
*/
|
|
298
|
-
async
|
|
299
|
-
|
|
300
|
-
group_id: groupId,
|
|
301
|
-
ops: [
|
|
302
|
-
{
|
|
303
|
-
op: 'task.create',
|
|
304
|
-
name: options.name,
|
|
305
|
-
goal: options.goal,
|
|
306
|
-
steps: options.steps,
|
|
307
|
-
milestone_id: options.milestone_id,
|
|
308
|
-
assignee: options.assignee,
|
|
309
|
-
},
|
|
310
|
-
],
|
|
311
|
-
});
|
|
312
|
-
const result = handleResponse(response);
|
|
313
|
-
return result.results[0].task;
|
|
290
|
+
async actorStop(groupId, actorId, by = 'user') {
|
|
291
|
+
return this.call('actor_stop', { group_id: groupId, actor_id: actorId, by });
|
|
314
292
|
}
|
|
315
293
|
/**
|
|
316
|
-
*
|
|
294
|
+
* Restart actor
|
|
317
295
|
*/
|
|
318
|
-
async
|
|
319
|
-
|
|
320
|
-
group_id: groupId,
|
|
321
|
-
ops: [
|
|
322
|
-
{
|
|
323
|
-
op: 'task.update',
|
|
324
|
-
task_id: options.task_id,
|
|
325
|
-
name: options.name,
|
|
326
|
-
goal: options.goal,
|
|
327
|
-
status: options.status,
|
|
328
|
-
assignee: options.assignee,
|
|
329
|
-
milestone_id: options.milestone_id,
|
|
330
|
-
step_id: options.step_id,
|
|
331
|
-
step_status: options.step_status,
|
|
332
|
-
},
|
|
333
|
-
],
|
|
334
|
-
});
|
|
335
|
-
const result = handleResponse(response);
|
|
336
|
-
return result.results[0].task;
|
|
296
|
+
async actorRestart(groupId, actorId, by = 'user') {
|
|
297
|
+
return this.call('actor_restart', { group_id: groupId, actor_id: actorId, by });
|
|
337
298
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
client;
|
|
344
|
-
constructor(client) {
|
|
345
|
-
this.client = client;
|
|
299
|
+
/**
|
|
300
|
+
* List actor private env keys (without values)
|
|
301
|
+
*/
|
|
302
|
+
async actorEnvPrivateKeys(groupId, actorId, by = 'user') {
|
|
303
|
+
return this.call('actor_env_private_keys', { group_id: groupId, actor_id: actorId, by });
|
|
346
304
|
}
|
|
347
305
|
/**
|
|
348
|
-
*
|
|
306
|
+
* Update actor private env vars (runtime-only; values are never echoed)
|
|
349
307
|
*/
|
|
350
|
-
async
|
|
351
|
-
|
|
352
|
-
group_id: groupId,
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
status: options.status ?? 'planned',
|
|
359
|
-
},
|
|
360
|
-
],
|
|
308
|
+
async actorEnvPrivateUpdate(options) {
|
|
309
|
+
return this.call('actor_env_private_update', {
|
|
310
|
+
group_id: options.groupId,
|
|
311
|
+
actor_id: options.actorId,
|
|
312
|
+
by: options.by ?? 'user',
|
|
313
|
+
set: options.set ?? undefined,
|
|
314
|
+
unset: options.unset ?? undefined,
|
|
315
|
+
clear: options.clear ?? false,
|
|
361
316
|
});
|
|
362
|
-
const result = handleResponse(response);
|
|
363
|
-
return result.results[0].milestone;
|
|
364
317
|
}
|
|
318
|
+
// ============================================================
|
|
319
|
+
// Convenience methods: messaging
|
|
320
|
+
// ============================================================
|
|
365
321
|
/**
|
|
366
|
-
*
|
|
322
|
+
* Send message
|
|
367
323
|
*/
|
|
368
|
-
async
|
|
369
|
-
const
|
|
370
|
-
group_id: groupId,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
]
|
|
378
|
-
|
|
379
|
-
|
|
324
|
+
async send(options) {
|
|
325
|
+
const args = {
|
|
326
|
+
group_id: options.groupId,
|
|
327
|
+
text: options.text,
|
|
328
|
+
by: options.by ?? 'user',
|
|
329
|
+
priority: options.priority ?? 'normal',
|
|
330
|
+
reply_required: options.replyRequired ?? false,
|
|
331
|
+
};
|
|
332
|
+
if (options.to)
|
|
333
|
+
args['to'] = options.to;
|
|
334
|
+
if (options.path)
|
|
335
|
+
args['path'] = options.path;
|
|
336
|
+
return this.call('send', args);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Send message across groups
|
|
340
|
+
*/
|
|
341
|
+
async sendCrossGroup(options) {
|
|
342
|
+
const args = {
|
|
343
|
+
group_id: options.groupId,
|
|
344
|
+
dst_group_id: options.dstGroupId,
|
|
345
|
+
text: options.text,
|
|
346
|
+
by: options.by ?? 'user',
|
|
347
|
+
priority: options.priority ?? 'normal',
|
|
348
|
+
reply_required: options.replyRequired ?? false,
|
|
349
|
+
};
|
|
350
|
+
if (options.to)
|
|
351
|
+
args['to'] = options.to;
|
|
352
|
+
return this.call('send_cross_group', args);
|
|
380
353
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Reply message
|
|
356
|
+
*/
|
|
357
|
+
async reply(options) {
|
|
358
|
+
const args = {
|
|
359
|
+
group_id: options.groupId,
|
|
360
|
+
reply_to: options.replyTo,
|
|
361
|
+
text: options.text,
|
|
362
|
+
by: options.by ?? 'user',
|
|
363
|
+
priority: options.priority ?? 'normal',
|
|
364
|
+
reply_required: options.replyRequired ?? false,
|
|
365
|
+
};
|
|
366
|
+
if (options.to)
|
|
367
|
+
args['to'] = options.to;
|
|
368
|
+
return this.call('reply', args);
|
|
389
369
|
}
|
|
390
370
|
/**
|
|
391
|
-
*
|
|
371
|
+
* Acknowledge chat message
|
|
392
372
|
*/
|
|
393
|
-
async
|
|
394
|
-
|
|
373
|
+
async chatAck(groupId, actorId, eventId, by) {
|
|
374
|
+
return this.call('chat_ack', {
|
|
395
375
|
group_id: groupId,
|
|
396
|
-
|
|
376
|
+
actor_id: actorId,
|
|
377
|
+
event_id: eventId,
|
|
378
|
+
by: by ?? actorId,
|
|
397
379
|
});
|
|
398
|
-
handleResponse(response);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Sketch API
|
|
403
|
-
*/
|
|
404
|
-
class SketchAPI {
|
|
405
|
-
client;
|
|
406
|
-
constructor(client) {
|
|
407
|
-
this.client = client;
|
|
408
380
|
}
|
|
381
|
+
// ============================================================
|
|
382
|
+
// Convenience methods: inbox
|
|
383
|
+
// ============================================================
|
|
409
384
|
/**
|
|
410
|
-
*
|
|
385
|
+
* List inbox
|
|
411
386
|
*/
|
|
412
|
-
async
|
|
413
|
-
|
|
414
|
-
group_id: groupId,
|
|
415
|
-
|
|
387
|
+
async inboxList(options) {
|
|
388
|
+
return this.call('inbox_list', {
|
|
389
|
+
group_id: options.groupId,
|
|
390
|
+
actor_id: options.actorId,
|
|
391
|
+
by: options.by ?? 'user',
|
|
392
|
+
limit: options.limit ?? 50,
|
|
393
|
+
kind_filter: options.kindFilter ?? 'all',
|
|
416
394
|
});
|
|
417
|
-
handleResponse(response);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Headless API for MCP-driven actors
|
|
422
|
-
*/
|
|
423
|
-
class HeadlessAPI {
|
|
424
|
-
client;
|
|
425
|
-
constructor(client) {
|
|
426
|
-
this.client = client;
|
|
427
395
|
}
|
|
428
396
|
/**
|
|
429
|
-
*
|
|
397
|
+
* Mark message as read
|
|
430
398
|
*/
|
|
431
|
-
async
|
|
432
|
-
|
|
399
|
+
async inboxMarkRead(groupId, actorId, eventId, by = 'user') {
|
|
400
|
+
return this.call('inbox_mark_read', {
|
|
433
401
|
group_id: groupId,
|
|
434
402
|
actor_id: actorId,
|
|
403
|
+
event_id: eventId,
|
|
404
|
+
by,
|
|
435
405
|
});
|
|
436
|
-
return handleResponse(response);
|
|
437
406
|
}
|
|
438
407
|
/**
|
|
439
|
-
*
|
|
408
|
+
* Mark all messages as read
|
|
440
409
|
*/
|
|
441
|
-
async
|
|
442
|
-
|
|
410
|
+
async inboxMarkAllRead(groupId, actorId, by = 'user', kindFilter = 'all') {
|
|
411
|
+
return this.call('inbox_mark_all_read', {
|
|
443
412
|
group_id: groupId,
|
|
444
413
|
actor_id: actorId,
|
|
445
|
-
|
|
446
|
-
|
|
414
|
+
by,
|
|
415
|
+
kind_filter: kindFilter,
|
|
447
416
|
});
|
|
448
|
-
handleResponse(response);
|
|
449
417
|
}
|
|
418
|
+
// ============================================================
|
|
419
|
+
// Convenience methods: notifications
|
|
420
|
+
// ============================================================
|
|
450
421
|
/**
|
|
451
|
-
* Acknowledge
|
|
422
|
+
* Acknowledge notification
|
|
452
423
|
*/
|
|
453
|
-
async
|
|
454
|
-
|
|
424
|
+
async notifyAck(groupId, actorId, notifyEventId, by) {
|
|
425
|
+
return this.call('notify_ack', {
|
|
455
426
|
group_id: groupId,
|
|
456
427
|
actor_id: actorId,
|
|
457
|
-
|
|
428
|
+
notify_event_id: notifyEventId,
|
|
429
|
+
by: by ?? actorId,
|
|
458
430
|
});
|
|
459
|
-
handleResponse(response);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* CCCC Client
|
|
464
|
-
*
|
|
465
|
-
* Main entry point for SDK
|
|
466
|
-
*
|
|
467
|
-
* @example
|
|
468
|
-
* ```typescript
|
|
469
|
-
* const client = new CCCCClient();
|
|
470
|
-
*
|
|
471
|
-
* // List all groups
|
|
472
|
-
* const groups = await client.groups.list();
|
|
473
|
-
*
|
|
474
|
-
* // Add an actor
|
|
475
|
-
* await client.actors.add(groupId, 'user', {
|
|
476
|
-
* actor_id: 'agent-1',
|
|
477
|
-
* runtime: 'claude',
|
|
478
|
-
* runner: 'pty'
|
|
479
|
-
* });
|
|
480
|
-
*
|
|
481
|
-
* // Send a message
|
|
482
|
-
* await client.messages.send(groupId, 'user', {
|
|
483
|
-
* text: 'Hello agents!',
|
|
484
|
-
* to: ['agent-1']
|
|
485
|
-
* });
|
|
486
|
-
* ```
|
|
487
|
-
*/
|
|
488
|
-
export class CCCCClient {
|
|
489
|
-
options;
|
|
490
|
-
// API namespaces
|
|
491
|
-
groups;
|
|
492
|
-
actors;
|
|
493
|
-
messages;
|
|
494
|
-
inbox;
|
|
495
|
-
context;
|
|
496
|
-
tasks;
|
|
497
|
-
milestones;
|
|
498
|
-
vision;
|
|
499
|
-
sketch;
|
|
500
|
-
headless;
|
|
501
|
-
constructor(options = {}) {
|
|
502
|
-
this.options = options;
|
|
503
|
-
// Initialize API namespaces
|
|
504
|
-
this.groups = new GroupsAPI(this);
|
|
505
|
-
this.actors = new ActorsAPI(this);
|
|
506
|
-
this.messages = new MessagesAPI(this);
|
|
507
|
-
this.inbox = new InboxAPI(this);
|
|
508
|
-
this.context = new ContextAPI(this);
|
|
509
|
-
this.tasks = new TasksAPI(this);
|
|
510
|
-
this.milestones = new MilestonesAPI(this);
|
|
511
|
-
this.vision = new VisionAPI(this);
|
|
512
|
-
this.sketch = new SketchAPI(this);
|
|
513
|
-
this.headless = new HeadlessAPI(this);
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Ping daemon to check if it's running
|
|
517
|
-
*/
|
|
518
|
-
async ping() {
|
|
519
|
-
return pingDaemon(this.options);
|
|
520
431
|
}
|
|
432
|
+
// ============================================================
|
|
433
|
+
// Convenience methods: context
|
|
434
|
+
// ============================================================
|
|
521
435
|
/**
|
|
522
|
-
*
|
|
436
|
+
* Get group context
|
|
523
437
|
*/
|
|
524
|
-
async
|
|
525
|
-
|
|
526
|
-
return callDaemon(request, this.options);
|
|
438
|
+
async contextGet(groupId) {
|
|
439
|
+
return this.call('context_get', { group_id: groupId });
|
|
527
440
|
}
|
|
528
441
|
/**
|
|
529
|
-
*
|
|
442
|
+
* Sync context
|
|
530
443
|
*/
|
|
531
|
-
async
|
|
532
|
-
|
|
533
|
-
|
|
444
|
+
async contextSync(options) {
|
|
445
|
+
return this.call('context_sync', {
|
|
446
|
+
group_id: options.groupId,
|
|
447
|
+
ops: options.ops,
|
|
448
|
+
by: options.by ?? 'system',
|
|
449
|
+
dry_run: options.dryRun ?? false,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
// ============================================================
|
|
453
|
+
// Event stream
|
|
454
|
+
// ============================================================
|
|
455
|
+
/**
|
|
456
|
+
* Subscribe to event stream
|
|
457
|
+
*/
|
|
458
|
+
async *eventsStream(options) {
|
|
459
|
+
const args = {
|
|
460
|
+
group_id: options.groupId,
|
|
461
|
+
by: options.by ?? 'user',
|
|
462
|
+
};
|
|
463
|
+
if (options.kinds) {
|
|
464
|
+
args['kinds'] = options.kinds instanceof Set
|
|
465
|
+
? Array.from(options.kinds)
|
|
466
|
+
: options.kinds;
|
|
467
|
+
}
|
|
468
|
+
if (options.sinceEventId) {
|
|
469
|
+
args['since_event_id'] = options.sinceEventId;
|
|
470
|
+
}
|
|
471
|
+
if (options.sinceTs) {
|
|
472
|
+
args['since_ts'] = options.sinceTs;
|
|
473
|
+
}
|
|
474
|
+
const request = {
|
|
475
|
+
v: 1,
|
|
476
|
+
op: 'events_stream',
|
|
477
|
+
args,
|
|
478
|
+
};
|
|
479
|
+
const { socket, handshake, initialBuffer } = await openEventsStream(this._endpoint, request, options.timeoutMs ?? this._timeoutMs);
|
|
480
|
+
if (!handshake.ok) {
|
|
481
|
+
socket.destroy();
|
|
482
|
+
throw new DaemonAPIError(handshake.error?.code ?? 'unknown', handshake.error?.message ?? 'Handshake failed', handshake.error?.details, handshake);
|
|
483
|
+
}
|
|
484
|
+
try {
|
|
485
|
+
for await (const line of readLines(socket, initialBuffer)) {
|
|
486
|
+
try {
|
|
487
|
+
yield JSON.parse(line);
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
// Skip invalid JSON lines.
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
finally {
|
|
495
|
+
socket.destroy();
|
|
496
|
+
}
|
|
534
497
|
}
|
|
535
498
|
}
|
|
536
499
|
//# sourceMappingURL=client.js.map
|