@clinebot/core 0.0.11 → 0.0.13
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 +1 -1
- package/dist/agents/agent-config-loader.d.ts +1 -1
- package/dist/agents/agent-config-parser.d.ts +5 -2
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/plugin-config-loader.d.ts +4 -0
- package/dist/agents/plugin-loader.d.ts +1 -0
- package/dist/agents/plugin-sandbox-bootstrap.js +446 -0
- package/dist/agents/plugin-sandbox.d.ts +4 -0
- package/dist/index.node.d.ts +5 -0
- package/dist/index.node.js +685 -413
- package/dist/runtime/commands.d.ts +11 -0
- package/dist/runtime/sandbox/subprocess-sandbox.d.ts +8 -1
- package/dist/runtime/skills.d.ts +13 -0
- package/dist/session/default-session-manager.d.ts +5 -0
- package/dist/session/session-config-builder.d.ts +4 -1
- package/dist/session/session-manager.d.ts +1 -0
- package/dist/session/session-service.d.ts +22 -22
- package/dist/session/unified-session-persistence-service.d.ts +12 -6
- package/dist/session/utils/helpers.d.ts +2 -2
- package/dist/session/utils/types.d.ts +9 -0
- package/dist/tools/definitions.d.ts +2 -2
- package/dist/tools/presets.d.ts +3 -3
- package/dist/tools/schemas.d.ts +15 -14
- package/dist/types/config.d.ts +5 -0
- package/dist/types/events.d.ts +22 -0
- package/package.json +5 -4
- package/src/agents/agent-config-loader.test.ts +2 -0
- package/src/agents/agent-config-loader.ts +1 -0
- package/src/agents/agent-config-parser.ts +12 -5
- package/src/agents/index.ts +1 -0
- package/src/agents/plugin-config-loader.test.ts +49 -0
- package/src/agents/plugin-config-loader.ts +10 -73
- package/src/agents/plugin-loader.test.ts +127 -1
- package/src/agents/plugin-loader.ts +72 -5
- package/src/agents/plugin-sandbox-bootstrap.ts +445 -0
- package/src/agents/plugin-sandbox.test.ts +198 -1
- package/src/agents/plugin-sandbox.ts +223 -353
- package/src/index.node.ts +14 -0
- package/src/runtime/commands.test.ts +98 -0
- package/src/runtime/commands.ts +83 -0
- package/src/runtime/hook-file-hooks.test.ts +1 -1
- package/src/runtime/hook-file-hooks.ts +16 -6
- package/src/runtime/index.ts +10 -0
- package/src/runtime/runtime-builder.test.ts +67 -0
- package/src/runtime/runtime-builder.ts +70 -16
- package/src/runtime/sandbox/subprocess-sandbox.ts +35 -11
- package/src/runtime/skills.ts +44 -0
- package/src/runtime/workflows.ts +20 -29
- package/src/session/default-session-manager.e2e.test.ts +52 -33
- package/src/session/default-session-manager.test.ts +453 -1
- package/src/session/default-session-manager.ts +210 -12
- package/src/session/rpc-session-service.ts +14 -96
- package/src/session/session-config-builder.ts +2 -0
- package/src/session/session-manager.ts +1 -0
- package/src/session/session-service.ts +127 -64
- package/src/session/session-team-coordination.ts +30 -0
- package/src/session/unified-session-persistence-service.test.ts +3 -3
- package/src/session/unified-session-persistence-service.ts +159 -141
- package/src/session/utils/helpers.ts +22 -41
- package/src/session/utils/types.ts +10 -0
- package/src/storage/sqlite-team-store.ts +16 -5
- package/src/tools/definitions.test.ts +137 -8
- package/src/tools/definitions.ts +115 -70
- package/src/tools/presets.test.ts +2 -3
- package/src/tools/presets.ts +3 -3
- package/src/tools/schemas.ts +28 -28
- package/src/types/config.ts +5 -0
- package/src/types/events.ts +23 -0
|
@@ -24,35 +24,35 @@ import type {
|
|
|
24
24
|
} from "./unified-session-persistence-service";
|
|
25
25
|
import { UnifiedSessionPersistenceService } from "./unified-session-persistence-service";
|
|
26
26
|
|
|
27
|
-
export interface
|
|
28
|
-
|
|
27
|
+
export interface SessionRow {
|
|
28
|
+
sessionId: string;
|
|
29
29
|
source: string;
|
|
30
30
|
pid: number;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
startedAt: string;
|
|
32
|
+
endedAt?: string | null;
|
|
33
|
+
exitCode?: number | null;
|
|
34
34
|
status: SessionStatus;
|
|
35
|
-
|
|
36
|
-
interactive:
|
|
35
|
+
statusLock: number;
|
|
36
|
+
interactive: boolean;
|
|
37
37
|
provider: string;
|
|
38
38
|
model: string;
|
|
39
39
|
cwd: string;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
workspaceRoot: string;
|
|
41
|
+
teamName?: string | null;
|
|
42
|
+
enableTools: boolean;
|
|
43
|
+
enableSpawn: boolean;
|
|
44
|
+
enableTeams: boolean;
|
|
45
|
+
parentSessionId?: string | null;
|
|
46
|
+
parentAgentId?: string | null;
|
|
47
|
+
agentId?: string | null;
|
|
48
|
+
conversationId?: string | null;
|
|
49
|
+
isSubagent: boolean;
|
|
50
50
|
prompt?: string | null;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
metadata?: Record<string, unknown> | null;
|
|
52
|
+
transcriptPath: string;
|
|
53
|
+
hookPath: string;
|
|
54
|
+
messagesPath?: string | null;
|
|
55
|
+
updatedAt: string;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export interface CreateRootSessionInput {
|
|
@@ -110,6 +110,74 @@ export interface UpsertSubagentInput {
|
|
|
110
110
|
rootSessionId?: string;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// ── SQLite helpers ───────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
/** SELECT clause that aliases snake_case columns to camelCase SessionRow keys. */
|
|
116
|
+
const SESSION_SELECT_COLUMNS = `
|
|
117
|
+
session_id AS sessionId,
|
|
118
|
+
source,
|
|
119
|
+
pid,
|
|
120
|
+
started_at AS startedAt,
|
|
121
|
+
ended_at AS endedAt,
|
|
122
|
+
exit_code AS exitCode,
|
|
123
|
+
status,
|
|
124
|
+
status_lock AS statusLock,
|
|
125
|
+
interactive,
|
|
126
|
+
provider,
|
|
127
|
+
model,
|
|
128
|
+
cwd,
|
|
129
|
+
workspace_root AS workspaceRoot,
|
|
130
|
+
team_name AS teamName,
|
|
131
|
+
enable_tools AS enableTools,
|
|
132
|
+
enable_spawn AS enableSpawn,
|
|
133
|
+
enable_teams AS enableTeams,
|
|
134
|
+
parent_session_id AS parentSessionId,
|
|
135
|
+
parent_agent_id AS parentAgentId,
|
|
136
|
+
agent_id AS agentId,
|
|
137
|
+
conversation_id AS conversationId,
|
|
138
|
+
is_subagent AS isSubagent,
|
|
139
|
+
prompt,
|
|
140
|
+
metadata_json AS metadata,
|
|
141
|
+
transcript_path AS transcriptPath,
|
|
142
|
+
hook_path AS hookPath,
|
|
143
|
+
messages_path AS messagesPath,
|
|
144
|
+
updated_at AS updatedAt`;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Patch a raw SQLite result into a proper SessionRow.
|
|
148
|
+
* SQLite returns 0/1 for booleans and a JSON string for metadata —
|
|
149
|
+
* this converts them in-place to avoid allocating a second object.
|
|
150
|
+
*/
|
|
151
|
+
function patchSqliteRow(raw: Record<string, unknown>): SessionRow {
|
|
152
|
+
raw.interactive = raw.interactive === 1;
|
|
153
|
+
raw.enableTools = raw.enableTools === 1;
|
|
154
|
+
raw.enableSpawn = raw.enableSpawn === 1;
|
|
155
|
+
raw.enableTeams = raw.enableTeams === 1;
|
|
156
|
+
raw.isSubagent = raw.isSubagent === 1;
|
|
157
|
+
const meta = raw.metadata;
|
|
158
|
+
if (typeof meta === "string" && meta.trim()) {
|
|
159
|
+
try {
|
|
160
|
+
const parsed = JSON.parse(meta) as unknown;
|
|
161
|
+
raw.metadata =
|
|
162
|
+
parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
163
|
+
? parsed
|
|
164
|
+
: null;
|
|
165
|
+
} catch {
|
|
166
|
+
raw.metadata = null;
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
raw.metadata = null;
|
|
170
|
+
}
|
|
171
|
+
return raw as unknown as SessionRow;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function stringifyMetadata(
|
|
175
|
+
metadata: Record<string, unknown> | null | undefined,
|
|
176
|
+
): string | null {
|
|
177
|
+
if (!metadata || Object.keys(metadata).length === 0) return null;
|
|
178
|
+
return JSON.stringify(metadata);
|
|
179
|
+
}
|
|
180
|
+
|
|
113
181
|
function reviveTeamStateDates(state: TeamRuntimeState): TeamRuntimeState {
|
|
114
182
|
return {
|
|
115
183
|
...state,
|
|
@@ -327,7 +395,7 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
327
395
|
return this.store.ensureSessionsDir();
|
|
328
396
|
}
|
|
329
397
|
|
|
330
|
-
async upsertSession(row:
|
|
398
|
+
async upsertSession(row: SessionRow): Promise<void> {
|
|
331
399
|
this.store.run(
|
|
332
400
|
`INSERT OR REPLACE INTO sessions (
|
|
333
401
|
session_id, source, pid, started_at, ended_at, exit_code, status, status_lock, interactive,
|
|
@@ -336,55 +404,51 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
336
404
|
metadata_json, transcript_path, hook_path, messages_path, updated_at
|
|
337
405
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
338
406
|
[
|
|
339
|
-
row.
|
|
407
|
+
row.sessionId,
|
|
340
408
|
row.source,
|
|
341
409
|
row.pid,
|
|
342
|
-
row.
|
|
343
|
-
row.
|
|
344
|
-
row.
|
|
410
|
+
row.startedAt,
|
|
411
|
+
row.endedAt ?? null,
|
|
412
|
+
row.exitCode ?? null,
|
|
345
413
|
row.status,
|
|
346
|
-
|
|
347
|
-
row.interactive,
|
|
414
|
+
row.statusLock,
|
|
415
|
+
row.interactive ? 1 : 0,
|
|
348
416
|
row.provider,
|
|
349
417
|
row.model,
|
|
350
418
|
row.cwd,
|
|
351
|
-
row.
|
|
352
|
-
row.
|
|
353
|
-
row.
|
|
354
|
-
row.
|
|
355
|
-
row.
|
|
356
|
-
row.
|
|
357
|
-
row.
|
|
358
|
-
row.
|
|
359
|
-
row.
|
|
360
|
-
row.
|
|
419
|
+
row.workspaceRoot,
|
|
420
|
+
row.teamName ?? null,
|
|
421
|
+
row.enableTools ? 1 : 0,
|
|
422
|
+
row.enableSpawn ? 1 : 0,
|
|
423
|
+
row.enableTeams ? 1 : 0,
|
|
424
|
+
row.parentSessionId ?? null,
|
|
425
|
+
row.parentAgentId ?? null,
|
|
426
|
+
row.agentId ?? null,
|
|
427
|
+
row.conversationId ?? null,
|
|
428
|
+
row.isSubagent ? 1 : 0,
|
|
361
429
|
row.prompt ?? null,
|
|
362
|
-
row.
|
|
363
|
-
row.
|
|
364
|
-
row.
|
|
365
|
-
row.
|
|
366
|
-
row.
|
|
430
|
+
stringifyMetadata(row.metadata),
|
|
431
|
+
row.transcriptPath,
|
|
432
|
+
row.hookPath,
|
|
433
|
+
row.messagesPath ?? null,
|
|
434
|
+
row.updatedAt,
|
|
367
435
|
],
|
|
368
436
|
);
|
|
369
437
|
}
|
|
370
438
|
|
|
371
|
-
async getSession(sessionId: string): Promise<
|
|
372
|
-
const row = this.store.queryOne<
|
|
373
|
-
`SELECT
|
|
374
|
-
provider, model, cwd, workspace_root, team_name, enable_tools, enable_spawn, enable_teams,
|
|
375
|
-
parent_session_id, parent_agent_id, agent_id, conversation_id, is_subagent, prompt,
|
|
376
|
-
metadata_json, transcript_path, hook_path, messages_path, updated_at
|
|
377
|
-
FROM sessions WHERE session_id = ?`,
|
|
439
|
+
async getSession(sessionId: string): Promise<SessionRow | undefined> {
|
|
440
|
+
const row = this.store.queryOne<Record<string, unknown>>(
|
|
441
|
+
`SELECT ${SESSION_SELECT_COLUMNS} FROM sessions WHERE session_id = ?`,
|
|
378
442
|
[sessionId],
|
|
379
443
|
);
|
|
380
|
-
return row
|
|
444
|
+
return row ? patchSqliteRow(row) : undefined;
|
|
381
445
|
}
|
|
382
446
|
|
|
383
447
|
async listSessions(options: {
|
|
384
448
|
limit: number;
|
|
385
449
|
parentSessionId?: string;
|
|
386
450
|
status?: string;
|
|
387
|
-
}): Promise<
|
|
451
|
+
}): Promise<SessionRow[]> {
|
|
388
452
|
const whereClauses: string[] = [];
|
|
389
453
|
const params: unknown[] = [];
|
|
390
454
|
if (options.parentSessionId) {
|
|
@@ -397,17 +461,16 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
397
461
|
}
|
|
398
462
|
const where =
|
|
399
463
|
whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
400
|
-
return this.store
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
parent_session_id, parent_agent_id, agent_id, conversation_id, is_subagent, prompt,
|
|
404
|
-
metadata_json, transcript_path, hook_path, messages_path, updated_at
|
|
464
|
+
return this.store
|
|
465
|
+
.queryAll<Record<string, unknown>>(
|
|
466
|
+
`SELECT ${SESSION_SELECT_COLUMNS}
|
|
405
467
|
FROM sessions
|
|
406
468
|
${where}
|
|
407
469
|
ORDER BY started_at DESC
|
|
408
470
|
LIMIT ?`,
|
|
409
|
-
|
|
410
|
-
|
|
471
|
+
[...params, options.limit],
|
|
472
|
+
)
|
|
473
|
+
.map(patchSqliteRow);
|
|
411
474
|
}
|
|
412
475
|
|
|
413
476
|
async updateSession(
|
|
@@ -459,9 +522,9 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
459
522
|
fields.push("prompt = ?");
|
|
460
523
|
params.push(input.prompt ?? null);
|
|
461
524
|
}
|
|
462
|
-
if (input.
|
|
525
|
+
if (input.metadata !== undefined) {
|
|
463
526
|
fields.push("metadata_json = ?");
|
|
464
|
-
params.push(input.
|
|
527
|
+
params.push(stringifyMetadata(input.metadata));
|
|
465
528
|
}
|
|
466
529
|
if (input.parentSessionId !== undefined) {
|
|
467
530
|
fields.push("parent_session_id = ?");
|
|
@@ -481,7 +544,7 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
481
544
|
}
|
|
482
545
|
if (fields.length === 0) {
|
|
483
546
|
const row = await this.getSession(input.sessionId);
|
|
484
|
-
return { updated: !!row, statusLock: row?.
|
|
547
|
+
return { updated: !!row, statusLock: row?.statusLock ?? 0 };
|
|
485
548
|
}
|
|
486
549
|
|
|
487
550
|
let statusLock = 0;
|
|
@@ -505,7 +568,7 @@ class LocalSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
505
568
|
}
|
|
506
569
|
if (input.expectedStatusLock === undefined) {
|
|
507
570
|
const row = await this.getSession(input.sessionId);
|
|
508
|
-
statusLock = row?.
|
|
571
|
+
statusLock = row?.statusLock ?? 0;
|
|
509
572
|
}
|
|
510
573
|
return { updated: true, statusLock };
|
|
511
574
|
}
|
|
@@ -52,6 +52,36 @@ export async function dispatchTeamEventToBackend(
|
|
|
52
52
|
invokeOptional: (method: string, ...args: unknown[]) => Promise<void>,
|
|
53
53
|
): Promise<void> {
|
|
54
54
|
switch (event.type) {
|
|
55
|
+
case "run_progress":
|
|
56
|
+
await invokeOptional(
|
|
57
|
+
"onTeamTaskProgress",
|
|
58
|
+
rootSessionId,
|
|
59
|
+
event.run.agentId,
|
|
60
|
+
event.message,
|
|
61
|
+
{ kind: event.message === "heartbeat" ? "heartbeat" : "progress" },
|
|
62
|
+
);
|
|
63
|
+
break;
|
|
64
|
+
case "agent_event":
|
|
65
|
+
if (
|
|
66
|
+
event.event.type === "content_start" &&
|
|
67
|
+
event.event.contentType === "text" &&
|
|
68
|
+
typeof event.event.text === "string"
|
|
69
|
+
) {
|
|
70
|
+
const snippet = event.event.text
|
|
71
|
+
.replace(/\s+/g, " ")
|
|
72
|
+
.trim()
|
|
73
|
+
.slice(0, 120);
|
|
74
|
+
if (snippet) {
|
|
75
|
+
await invokeOptional(
|
|
76
|
+
"onTeamTaskProgress",
|
|
77
|
+
rootSessionId,
|
|
78
|
+
event.agentId,
|
|
79
|
+
snippet,
|
|
80
|
+
{ kind: "text" },
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
55
85
|
case "task_start":
|
|
56
86
|
await invokeOptional(
|
|
57
87
|
"onTeamTaskStart",
|
|
@@ -45,11 +45,11 @@ describe("UnifiedSessionPersistenceService", () => {
|
|
|
45
45
|
const rows = await service.listSessions(10);
|
|
46
46
|
expect(rows).toHaveLength(1);
|
|
47
47
|
expect(rows[0]).toMatchObject({
|
|
48
|
-
|
|
48
|
+
sessionId,
|
|
49
49
|
status: "failed",
|
|
50
|
-
|
|
50
|
+
exitCode: 1,
|
|
51
51
|
});
|
|
52
|
-
expect(rows[0]?.
|
|
52
|
+
expect(rows[0]?.endedAt).toBeTruthy();
|
|
53
53
|
|
|
54
54
|
const manifest = JSON.parse(
|
|
55
55
|
readFileSync(artifacts.manifestPath, "utf8"),
|