cccc-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js ADDED
@@ -0,0 +1,536 @@
1
+ /**
2
+ * CCCC Client SDK
3
+ *
4
+ * High-level API for interacting with CCCC daemon
5
+ */
6
+ import { callDaemon, pingDaemon } from './transport.js';
7
+ import { createRequest } from './types/ipc.js';
8
+ import { CCCCError } from './errors.js';
9
+ /**
10
+ * Handle daemon response, throwing on error
11
+ */
12
+ function handleResponse(response) {
13
+ if (!response.ok) {
14
+ if (response.error) {
15
+ throw CCCCError.fromDaemonError(response.error);
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;
28
+ }
29
+ /**
30
+ * List all groups
31
+ */
32
+ async list() {
33
+ const response = await this.client.call('groups', {});
34
+ return (handleResponse(response)).groups;
35
+ }
36
+ /**
37
+ * Get group info
38
+ */
39
+ async get(groupId) {
40
+ const response = await this.client.call('group_show', { group_id: groupId });
41
+ return handleResponse(response);
42
+ }
43
+ /**
44
+ * Create a new group
45
+ */
46
+ async create(options) {
47
+ const response = await this.client.call('group_create', {
48
+ title: options.title,
49
+ topic: options.topic ?? '',
50
+ url: options.url ?? '',
51
+ });
52
+ return handleResponse(response);
53
+ }
54
+ /**
55
+ * Set group state
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);
64
+ }
65
+ /**
66
+ * Start group (activate all enabled actors)
67
+ */
68
+ async start(groupId) {
69
+ const response = await this.client.call('group_start', { group_id: groupId });
70
+ handleResponse(response);
71
+ }
72
+ /**
73
+ * Stop group (stop all actors)
74
+ */
75
+ async stop(groupId) {
76
+ const response = await this.client.call('group_stop', { group_id: groupId });
77
+ handleResponse(response);
78
+ }
79
+ /**
80
+ * Update group
81
+ */
82
+ async update(groupId, patch) {
83
+ const response = await this.client.call('group_update', {
84
+ group_id: groupId,
85
+ patch,
86
+ });
87
+ handleResponse(response);
88
+ }
89
+ /**
90
+ * Delete group
91
+ */
92
+ async delete(groupId) {
93
+ const response = await this.client.call('group_delete', { group_id: groupId });
94
+ handleResponse(response);
95
+ }
96
+ }
97
+ /**
98
+ * Actors API
99
+ */
100
+ class ActorsAPI {
101
+ client;
102
+ constructor(client) {
103
+ this.client = client;
104
+ }
105
+ /**
106
+ * List actors in a group
107
+ */
108
+ async list(groupId) {
109
+ const response = await this.client.call('actor_list', { group_id: groupId });
110
+ return (handleResponse(response)).actors;
111
+ }
112
+ /**
113
+ * Add an actor to a group
114
+ */
115
+ async add(groupId, by, options) {
116
+ const response = await this.client.call('actor_add', {
117
+ group_id: groupId,
118
+ by,
119
+ actor_id: options.actor_id,
120
+ runtime: options.runtime ?? 'claude',
121
+ runner: options.runner ?? 'pty',
122
+ title: options.title ?? '',
123
+ command: options.command ?? [],
124
+ env: options.env ?? {},
125
+ });
126
+ return handleResponse(response).actor;
127
+ }
128
+ /**
129
+ * Start an actor
130
+ */
131
+ async start(groupId, actorId, by) {
132
+ const response = await this.client.call('actor_start', {
133
+ group_id: groupId,
134
+ actor_id: actorId,
135
+ by,
136
+ });
137
+ handleResponse(response);
138
+ }
139
+ /**
140
+ * Stop an actor
141
+ */
142
+ async stop(groupId, actorId, by) {
143
+ const response = await this.client.call('actor_stop', {
144
+ group_id: groupId,
145
+ actor_id: actorId,
146
+ by,
147
+ });
148
+ handleResponse(response);
149
+ }
150
+ /**
151
+ * Restart an actor
152
+ */
153
+ async restart(groupId, actorId, by) {
154
+ const response = await this.client.call('actor_restart', {
155
+ group_id: groupId,
156
+ actor_id: actorId,
157
+ by,
158
+ });
159
+ handleResponse(response);
160
+ }
161
+ /**
162
+ * Remove an actor
163
+ */
164
+ async remove(groupId, actorId, by) {
165
+ const response = await this.client.call('actor_remove', {
166
+ group_id: groupId,
167
+ actor_id: actorId,
168
+ by,
169
+ });
170
+ handleResponse(response);
171
+ }
172
+ }
173
+ /**
174
+ * Messages API
175
+ */
176
+ class MessagesAPI {
177
+ client;
178
+ constructor(client) {
179
+ this.client = client;
180
+ }
181
+ /**
182
+ * Send a message
183
+ */
184
+ async send(groupId, by, options) {
185
+ const response = await this.client.call('send', {
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;
193
+ }
194
+ /**
195
+ * Reply to a message
196
+ */
197
+ async reply(groupId, by, options) {
198
+ const response = await this.client.call('reply', {
199
+ group_id: groupId,
200
+ by,
201
+ event_id: options.event_id,
202
+ text: options.text,
203
+ to: options.to ?? [],
204
+ });
205
+ return handleResponse(response).event;
206
+ }
207
+ }
208
+ /**
209
+ * Inbox API
210
+ */
211
+ class InboxAPI {
212
+ client;
213
+ constructor(client) {
214
+ this.client = client;
215
+ }
216
+ /**
217
+ * List inbox messages
218
+ */
219
+ async list(groupId, actorId, options = {}) {
220
+ const response = await this.client.call('inbox_list', {
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;
227
+ }
228
+ /**
229
+ * Mark messages as read up to event_id
230
+ */
231
+ async markRead(groupId, actorId, eventId) {
232
+ const response = await this.client.call('inbox_mark_read', {
233
+ group_id: groupId,
234
+ actor_id: actorId,
235
+ event_id: eventId,
236
+ });
237
+ handleResponse(response);
238
+ }
239
+ /**
240
+ * Mark all messages as read
241
+ */
242
+ async markAllRead(groupId, actorId) {
243
+ const response = await this.client.call('inbox_mark_all_read', {
244
+ group_id: groupId,
245
+ actor_id: actorId,
246
+ });
247
+ handleResponse(response);
248
+ }
249
+ }
250
+ /**
251
+ * Context API
252
+ */
253
+ class ContextAPI {
254
+ client;
255
+ constructor(client) {
256
+ this.client = client;
257
+ }
258
+ /**
259
+ * Get project context
260
+ */
261
+ async get(groupId) {
262
+ const response = await this.client.call('context_get', { group_id: groupId });
263
+ return handleResponse(response);
264
+ }
265
+ /**
266
+ * Sync context with batch operations
267
+ */
268
+ async sync(groupId, ops, dryRun = false) {
269
+ const response = await this.client.call('context_sync', {
270
+ group_id: groupId,
271
+ ops,
272
+ dry_run: dryRun,
273
+ });
274
+ return handleResponse(response);
275
+ }
276
+ }
277
+ /**
278
+ * Tasks API
279
+ */
280
+ class TasksAPI {
281
+ client;
282
+ constructor(client) {
283
+ this.client = client;
284
+ }
285
+ /**
286
+ * List tasks
287
+ */
288
+ async list(groupId, includeArchived = false) {
289
+ const response = await this.client.call('task_list', {
290
+ group_id: groupId,
291
+ include_archived: includeArchived,
292
+ });
293
+ return (handleResponse(response)).tasks;
294
+ }
295
+ /**
296
+ * Create a task
297
+ */
298
+ async create(groupId, options) {
299
+ const response = await this.client.call('context_sync', {
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;
314
+ }
315
+ /**
316
+ * Update a task
317
+ */
318
+ async update(groupId, options) {
319
+ const response = await this.client.call('context_sync', {
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;
337
+ }
338
+ }
339
+ /**
340
+ * Milestones API
341
+ */
342
+ class MilestonesAPI {
343
+ client;
344
+ constructor(client) {
345
+ this.client = client;
346
+ }
347
+ /**
348
+ * Create a milestone
349
+ */
350
+ async create(groupId, options) {
351
+ const response = await this.client.call('context_sync', {
352
+ group_id: groupId,
353
+ ops: [
354
+ {
355
+ op: 'milestone.create',
356
+ name: options.name,
357
+ description: options.description,
358
+ status: options.status ?? 'planned',
359
+ },
360
+ ],
361
+ });
362
+ const result = handleResponse(response);
363
+ return result.results[0].milestone;
364
+ }
365
+ /**
366
+ * Complete a milestone
367
+ */
368
+ async complete(groupId, milestoneId, outcomes) {
369
+ const response = await this.client.call('context_sync', {
370
+ group_id: groupId,
371
+ ops: [
372
+ {
373
+ op: 'milestone.complete',
374
+ milestone_id: milestoneId,
375
+ outcomes,
376
+ },
377
+ ],
378
+ });
379
+ handleResponse(response);
380
+ }
381
+ }
382
+ /**
383
+ * Vision API
384
+ */
385
+ class VisionAPI {
386
+ client;
387
+ constructor(client) {
388
+ this.client = client;
389
+ }
390
+ /**
391
+ * Update project vision
392
+ */
393
+ async update(groupId, vision) {
394
+ const response = await this.client.call('context_sync', {
395
+ group_id: groupId,
396
+ ops: [{ op: 'vision.update', vision }],
397
+ });
398
+ handleResponse(response);
399
+ }
400
+ }
401
+ /**
402
+ * Sketch API
403
+ */
404
+ class SketchAPI {
405
+ client;
406
+ constructor(client) {
407
+ this.client = client;
408
+ }
409
+ /**
410
+ * Update execution sketch
411
+ */
412
+ async update(groupId, sketch) {
413
+ const response = await this.client.call('context_sync', {
414
+ group_id: groupId,
415
+ ops: [{ op: 'sketch.update', sketch }],
416
+ });
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
+ }
428
+ /**
429
+ * Get headless session status
430
+ */
431
+ async status(groupId, actorId) {
432
+ const response = await this.client.call('headless_status', {
433
+ group_id: groupId,
434
+ actor_id: actorId,
435
+ });
436
+ return handleResponse(response);
437
+ }
438
+ /**
439
+ * Set headless session status
440
+ */
441
+ async setStatus(groupId, actorId, status, taskId) {
442
+ const response = await this.client.call('headless_set_status', {
443
+ group_id: groupId,
444
+ actor_id: actorId,
445
+ status,
446
+ task_id: taskId,
447
+ });
448
+ handleResponse(response);
449
+ }
450
+ /**
451
+ * Acknowledge processed message
452
+ */
453
+ async ackMessage(groupId, actorId, messageId) {
454
+ const response = await this.client.call('headless_ack_message', {
455
+ group_id: groupId,
456
+ actor_id: actorId,
457
+ message_id: messageId,
458
+ });
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
+ }
521
+ /**
522
+ * Low-level daemon call
523
+ */
524
+ async call(op, args) {
525
+ const request = createRequest(op, args);
526
+ return callDaemon(request, this.options);
527
+ }
528
+ /**
529
+ * Shutdown the daemon
530
+ */
531
+ async shutdown() {
532
+ const response = await this.call('shutdown', {});
533
+ handleResponse(response);
534
+ }
535
+ }
536
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CCCC SDK Error Types
3
+ */
4
+ export type CCCCErrorCode = 'DAEMON_NOT_RUNNING' | 'SOCKET_NOT_FOUND' | 'TIMEOUT' | 'INVALID_REQUEST' | 'PERMISSION_DENIED' | 'GROUP_NOT_FOUND' | 'ACTOR_NOT_FOUND' | 'INTERNAL' | 'DAEMON_ERROR';
5
+ export declare class CCCCError extends Error {
6
+ readonly code: CCCCErrorCode;
7
+ readonly details: Record<string, unknown>;
8
+ constructor(code: CCCCErrorCode, message: string, details?: Record<string, unknown>);
9
+ static fromDaemonError(error: {
10
+ code: string;
11
+ message: string;
12
+ details?: Record<string, unknown>;
13
+ }): CCCCError;
14
+ }
15
+ //# sourceMappingURL=errors.d.ts.map
package/dist/errors.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * CCCC SDK Error Types
3
+ */
4
+ export class CCCCError extends Error {
5
+ code;
6
+ details;
7
+ constructor(code, message, details = {}) {
8
+ super(message);
9
+ this.name = 'CCCCError';
10
+ this.code = code;
11
+ this.details = details;
12
+ }
13
+ static fromDaemonError(error) {
14
+ const codeMap = {
15
+ daemon_unavailable: 'DAEMON_NOT_RUNNING',
16
+ invalid_request: 'INVALID_REQUEST',
17
+ permission_denied: 'PERMISSION_DENIED',
18
+ group_not_found: 'GROUP_NOT_FOUND',
19
+ actor_not_found: 'ACTOR_NOT_FOUND',
20
+ };
21
+ const code = codeMap[error.code] ?? 'DAEMON_ERROR';
22
+ return new CCCCError(code, error.message, error.details ?? {});
23
+ }
24
+ }
25
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CCCC Client SDK for Node.js
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { CCCCClient, type CCCCClientOptions } from './client.js';
7
+ export { callDaemon, pingDaemon, getSocketPath, getDefaultCcccHome, socketExists, type TransportOptions, } from './transport.js';
8
+ export { CCCCError, type CCCCErrorCode } from './errors.js';
9
+ export * from './types/index.js';
10
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * CCCC Client SDK for Node.js
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ // Main client
7
+ export { CCCCClient } from './client.js';
8
+ // Transport
9
+ export { callDaemon, pingDaemon, getSocketPath, getDefaultCcccHome, socketExists, } from './transport.js';
10
+ // Errors
11
+ export { CCCCError } from './errors.js';
12
+ // Types
13
+ export * from './types/index.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Unix Socket Transport Layer for CCCC daemon IPC
3
+ *
4
+ * Protocol:
5
+ * - Uses Unix Domain Socket at $CCCC_HOME/daemon/ccccd.sock
6
+ * - Messages are newline-delimited JSON
7
+ * - Request: {"v": 1, "op": "xxx", "args": {...}}
8
+ * - Response: {"v": 1, "ok": true/false, "result": {...}, "error": {...}}
9
+ */
10
+ import type { DaemonRequest, DaemonResponse } from './types/ipc.js';
11
+ export interface TransportOptions {
12
+ /** CCCC home directory, defaults to ~/.cccc */
13
+ ccccHome?: string;
14
+ /** Request timeout in milliseconds, defaults to 60000 */
15
+ timeoutMs?: number;
16
+ }
17
+ /**
18
+ * Get default CCCC home directory
19
+ */
20
+ export declare function getDefaultCcccHome(): string;
21
+ /**
22
+ * Get socket path for CCCC daemon
23
+ */
24
+ export declare function getSocketPath(ccccHome?: string): string;
25
+ /**
26
+ * Check if daemon socket exists
27
+ */
28
+ export declare function socketExists(ccccHome?: string): boolean;
29
+ /**
30
+ * Send a request to the CCCC daemon and receive a response
31
+ */
32
+ export declare function callDaemon(request: DaemonRequest, options?: TransportOptions): Promise<DaemonResponse>;
33
+ /**
34
+ * Ping the daemon to check if it's running
35
+ */
36
+ export declare function pingDaemon(options?: TransportOptions): Promise<boolean>;
37
+ //# sourceMappingURL=transport.d.ts.map