@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
|
@@ -64,7 +64,7 @@ import { SessionManifestSchema } from "./session-manifest";
|
|
|
64
64
|
import type {
|
|
65
65
|
CoreSessionService,
|
|
66
66
|
RootSessionArtifacts,
|
|
67
|
-
|
|
67
|
+
SessionRow,
|
|
68
68
|
} from "./session-service";
|
|
69
69
|
import {
|
|
70
70
|
buildTeamRunContinuationPrompt,
|
|
@@ -223,6 +223,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
223
223
|
hookPath,
|
|
224
224
|
sessionId,
|
|
225
225
|
this.defaultTelemetry,
|
|
226
|
+
(e) => void this.handlePluginEvent(sessionId, e),
|
|
226
227
|
);
|
|
227
228
|
const providerConfig = buildResolvedProviderConfig(
|
|
228
229
|
effectiveConfig,
|
|
@@ -307,6 +308,8 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
307
308
|
activeTeamRunIds: new Set<string>(),
|
|
308
309
|
pendingTeamRunUpdates: [],
|
|
309
310
|
teamRunWaiters: [],
|
|
311
|
+
pendingPrompts: [],
|
|
312
|
+
drainingPendingPrompts: false,
|
|
310
313
|
pluginSandboxShutdown,
|
|
311
314
|
};
|
|
312
315
|
this.sessions.set(sessionId, active);
|
|
@@ -349,8 +352,18 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
349
352
|
promptLength: input.prompt.length,
|
|
350
353
|
userImageCount: input.userImages?.length ?? 0,
|
|
351
354
|
userFileCount: input.userFiles?.length ?? 0,
|
|
355
|
+
delivery: input.delivery ?? "immediate",
|
|
352
356
|
},
|
|
353
357
|
});
|
|
358
|
+
if (input.delivery === "queue" || input.delivery === "steer") {
|
|
359
|
+
this.enqueuePendingPrompt(input.sessionId, {
|
|
360
|
+
prompt: input.prompt,
|
|
361
|
+
delivery: input.delivery,
|
|
362
|
+
userImages: input.userImages,
|
|
363
|
+
userFiles: input.userFiles,
|
|
364
|
+
});
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
354
367
|
try {
|
|
355
368
|
const result = await this.runTurn(session, {
|
|
356
369
|
prompt: input.prompt,
|
|
@@ -360,6 +373,9 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
360
373
|
if (!session.interactive) {
|
|
361
374
|
await this.finalizeSingleRun(session, result.finishReason);
|
|
362
375
|
}
|
|
376
|
+
queueMicrotask(() => {
|
|
377
|
+
void this.drainPendingPrompts(input.sessionId);
|
|
378
|
+
});
|
|
363
379
|
return result;
|
|
364
380
|
} catch (error) {
|
|
365
381
|
await this.failSession(session);
|
|
@@ -446,8 +462,8 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
446
462
|
|
|
447
463
|
async readTranscript(sessionId: string, maxChars?: number): Promise<string> {
|
|
448
464
|
const row = await this.getRow(sessionId);
|
|
449
|
-
if (!row?.
|
|
450
|
-
const raw = readFileSync(row.
|
|
465
|
+
if (!row?.transcriptPath || !existsSync(row.transcriptPath)) return "";
|
|
466
|
+
const raw = readFileSync(row.transcriptPath, "utf8");
|
|
451
467
|
if (typeof maxChars === "number" && Number.isFinite(maxChars)) {
|
|
452
468
|
return raw.slice(-Math.max(0, Math.floor(maxChars)));
|
|
453
469
|
}
|
|
@@ -456,7 +472,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
456
472
|
|
|
457
473
|
async readMessages(sessionId: string): Promise<LlmsProviders.Message[]> {
|
|
458
474
|
const row = await this.getRow(sessionId);
|
|
459
|
-
const messagesPath = row?.
|
|
475
|
+
const messagesPath = row?.messagesPath?.trim();
|
|
460
476
|
if (!messagesPath || !existsSync(messagesPath)) return [];
|
|
461
477
|
try {
|
|
462
478
|
const raw = readFileSync(messagesPath, "utf8").trim();
|
|
@@ -475,8 +491,8 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
475
491
|
|
|
476
492
|
async readHooks(sessionId: string, limit = 200): Promise<unknown[]> {
|
|
477
493
|
const row = await this.getRow(sessionId);
|
|
478
|
-
if (!row?.
|
|
479
|
-
const lines = readFileSync(row.
|
|
494
|
+
if (!row?.hookPath || !existsSync(row.hookPath)) return [];
|
|
495
|
+
const lines = readFileSync(row.hookPath, "utf8")
|
|
480
496
|
.split("\n")
|
|
481
497
|
.filter((line) => line.trim().length > 0);
|
|
482
498
|
return lines.slice(-Math.max(1, Math.floor(limit))).map((line) => {
|
|
@@ -766,6 +782,151 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
766
782
|
this.emitStatus(session.sessionId, status);
|
|
767
783
|
}
|
|
768
784
|
|
|
785
|
+
private async handlePluginEvent(
|
|
786
|
+
rootSessionId: string,
|
|
787
|
+
event: { name: string; payload?: unknown },
|
|
788
|
+
): Promise<void> {
|
|
789
|
+
if (
|
|
790
|
+
event.name !== "steer_message" &&
|
|
791
|
+
event.name !== "queue_message" &&
|
|
792
|
+
event.name !== "pending_prompt"
|
|
793
|
+
) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const payload =
|
|
797
|
+
event.payload && typeof event.payload === "object"
|
|
798
|
+
? (event.payload as Record<string, unknown>)
|
|
799
|
+
: undefined;
|
|
800
|
+
const targetSessionId =
|
|
801
|
+
typeof payload?.sessionId === "string" &&
|
|
802
|
+
payload.sessionId.trim().length > 0
|
|
803
|
+
? payload.sessionId.trim()
|
|
804
|
+
: rootSessionId;
|
|
805
|
+
const prompt =
|
|
806
|
+
typeof payload?.prompt === "string" ? payload.prompt.trim() : "";
|
|
807
|
+
if (!prompt) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const delivery =
|
|
811
|
+
event.name === "steer_message"
|
|
812
|
+
? "steer"
|
|
813
|
+
: event.name === "queue_message"
|
|
814
|
+
? "queue"
|
|
815
|
+
: payload?.delivery === "steer"
|
|
816
|
+
? "steer"
|
|
817
|
+
: "queue";
|
|
818
|
+
this.enqueuePendingPrompt(targetSessionId, {
|
|
819
|
+
prompt,
|
|
820
|
+
delivery,
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
private enqueuePendingPrompt(
|
|
825
|
+
sessionId: string,
|
|
826
|
+
entry: {
|
|
827
|
+
prompt: string;
|
|
828
|
+
delivery: "queue" | "steer";
|
|
829
|
+
userImages?: string[];
|
|
830
|
+
userFiles?: string[];
|
|
831
|
+
},
|
|
832
|
+
): void {
|
|
833
|
+
const session = this.sessions.get(sessionId);
|
|
834
|
+
if (!session) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const { prompt, delivery, userImages, userFiles } = entry;
|
|
838
|
+
const existingIndex = session.pendingPrompts.findIndex(
|
|
839
|
+
(queued) => queued.prompt === prompt,
|
|
840
|
+
);
|
|
841
|
+
if (existingIndex >= 0) {
|
|
842
|
+
const [existing] = session.pendingPrompts.splice(existingIndex, 1);
|
|
843
|
+
if (delivery === "steer" || existing.delivery === "steer") {
|
|
844
|
+
session.pendingPrompts.unshift({
|
|
845
|
+
id: existing.id,
|
|
846
|
+
prompt,
|
|
847
|
+
delivery: "steer",
|
|
848
|
+
userImages: userImages ?? existing.userImages,
|
|
849
|
+
userFiles: userFiles ?? existing.userFiles,
|
|
850
|
+
});
|
|
851
|
+
} else {
|
|
852
|
+
session.pendingPrompts.push({
|
|
853
|
+
...existing,
|
|
854
|
+
userImages: userImages ?? existing.userImages,
|
|
855
|
+
userFiles: userFiles ?? existing.userFiles,
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
} else if (delivery === "steer") {
|
|
859
|
+
session.pendingPrompts.unshift({
|
|
860
|
+
id: `pending_${Date.now()}_${nanoid(5)}`,
|
|
861
|
+
prompt,
|
|
862
|
+
delivery,
|
|
863
|
+
userImages,
|
|
864
|
+
userFiles,
|
|
865
|
+
});
|
|
866
|
+
} else {
|
|
867
|
+
session.pendingPrompts.push({
|
|
868
|
+
id: `pending_${Date.now()}_${nanoid(5)}`,
|
|
869
|
+
prompt,
|
|
870
|
+
delivery,
|
|
871
|
+
userImages,
|
|
872
|
+
userFiles,
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
this.emitPendingPrompts(session);
|
|
876
|
+
queueMicrotask(() => {
|
|
877
|
+
void this.drainPendingPrompts(sessionId);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
private async drainPendingPrompts(sessionId: string): Promise<void> {
|
|
882
|
+
const session = this.sessions.get(sessionId);
|
|
883
|
+
if (!session || session.drainingPendingPrompts) {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
const canStartRun =
|
|
887
|
+
typeof (session.agent as Agent & { canStartRun?: () => boolean })
|
|
888
|
+
.canStartRun === "function"
|
|
889
|
+
? (
|
|
890
|
+
session.agent as Agent & {
|
|
891
|
+
canStartRun: () => boolean;
|
|
892
|
+
}
|
|
893
|
+
).canStartRun()
|
|
894
|
+
: true;
|
|
895
|
+
if (!canStartRun) {
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const next = session.pendingPrompts.shift();
|
|
899
|
+
if (!next) {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
this.emitPendingPrompts(session);
|
|
903
|
+
this.emitPendingPromptSubmitted(session, next);
|
|
904
|
+
session.drainingPendingPrompts = true;
|
|
905
|
+
try {
|
|
906
|
+
await this.send({
|
|
907
|
+
sessionId,
|
|
908
|
+
prompt: next.prompt,
|
|
909
|
+
userImages: next.userImages,
|
|
910
|
+
userFiles: next.userFiles,
|
|
911
|
+
});
|
|
912
|
+
} catch (error) {
|
|
913
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
914
|
+
if (message.includes("already in progress")) {
|
|
915
|
+
session.pendingPrompts.unshift(next);
|
|
916
|
+
this.emitPendingPrompts(session);
|
|
917
|
+
} else {
|
|
918
|
+
throw error;
|
|
919
|
+
}
|
|
920
|
+
} finally {
|
|
921
|
+
session.drainingPendingPrompts = false;
|
|
922
|
+
if (session.pendingPrompts.length > 0) {
|
|
923
|
+
queueMicrotask(() => {
|
|
924
|
+
void this.drainPendingPrompts(sessionId);
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
769
930
|
// ── Agent event handling ────────────────────────────────────────────
|
|
770
931
|
|
|
771
932
|
private onAgentEvent(
|
|
@@ -791,6 +952,45 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
791
952
|
handleAgentEvent(ctx, event);
|
|
792
953
|
}
|
|
793
954
|
|
|
955
|
+
private emitPendingPrompts(session: ActiveSession): void {
|
|
956
|
+
this.emit({
|
|
957
|
+
type: "pending_prompts",
|
|
958
|
+
payload: {
|
|
959
|
+
sessionId: session.sessionId,
|
|
960
|
+
prompts: session.pendingPrompts.map((entry) => ({
|
|
961
|
+
id: entry.id,
|
|
962
|
+
prompt: entry.prompt,
|
|
963
|
+
delivery: entry.delivery,
|
|
964
|
+
attachmentCount:
|
|
965
|
+
(entry.userImages?.length ?? 0) + (entry.userFiles?.length ?? 0),
|
|
966
|
+
})),
|
|
967
|
+
},
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
private emitPendingPromptSubmitted(
|
|
972
|
+
session: ActiveSession,
|
|
973
|
+
entry: {
|
|
974
|
+
id: string;
|
|
975
|
+
prompt: string;
|
|
976
|
+
delivery: "queue" | "steer";
|
|
977
|
+
userImages?: string[];
|
|
978
|
+
userFiles?: string[];
|
|
979
|
+
},
|
|
980
|
+
): void {
|
|
981
|
+
this.emit({
|
|
982
|
+
type: "pending_prompt_submitted",
|
|
983
|
+
payload: {
|
|
984
|
+
sessionId: session.sessionId,
|
|
985
|
+
id: entry.id,
|
|
986
|
+
prompt: entry.prompt,
|
|
987
|
+
delivery: entry.delivery,
|
|
988
|
+
attachmentCount:
|
|
989
|
+
(entry.userImages?.length ?? 0) + (entry.userFiles?.length ?? 0),
|
|
990
|
+
},
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
794
994
|
// ── Spawn / sub-agents ──────────────────────────────────────────────
|
|
795
995
|
|
|
796
996
|
private createSpawnTool(
|
|
@@ -964,20 +1164,18 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
964
1164
|
for (const listener of this.listeners) listener(event);
|
|
965
1165
|
}
|
|
966
1166
|
|
|
967
|
-
private async listRows(limit: number): Promise<
|
|
968
|
-
return this.invoke<
|
|
1167
|
+
private async listRows(limit: number): Promise<SessionRow[]> {
|
|
1168
|
+
return this.invoke<SessionRow[]>(
|
|
969
1169
|
"listSessions",
|
|
970
1170
|
Math.min(Math.max(1, Math.floor(limit)), MAX_SCAN_LIMIT),
|
|
971
1171
|
);
|
|
972
1172
|
}
|
|
973
1173
|
|
|
974
|
-
private async getRow(
|
|
975
|
-
sessionId: string,
|
|
976
|
-
): Promise<SessionRowShape | undefined> {
|
|
1174
|
+
private async getRow(sessionId: string): Promise<SessionRow | undefined> {
|
|
977
1175
|
const target = sessionId.trim();
|
|
978
1176
|
if (!target) return undefined;
|
|
979
1177
|
const rows = await this.listRows(MAX_SCAN_LIMIT);
|
|
980
|
-
return rows.find((row) => row.
|
|
1178
|
+
return rows.find((row) => row.sessionId === target);
|
|
981
1179
|
}
|
|
982
1180
|
|
|
983
1181
|
// ── Session service invocation ──────────────────────────────────────
|
|
@@ -1,91 +1,13 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { RpcSessionClient, type RpcSessionRow } from "@clinebot/rpc";
|
|
3
|
-
import {
|
|
4
|
-
import type { SessionRowShape } from "./session-service";
|
|
3
|
+
import type { SessionRow } from "./session-service";
|
|
5
4
|
import type {
|
|
6
5
|
PersistedSessionUpdateInput,
|
|
7
6
|
SessionPersistenceAdapter,
|
|
8
7
|
} from "./unified-session-persistence-service";
|
|
9
8
|
import { UnifiedSessionPersistenceService } from "./unified-session-persistence-service";
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
session_id: row.sessionId,
|
|
14
|
-
source: row.source,
|
|
15
|
-
pid: row.pid,
|
|
16
|
-
started_at: row.startedAt,
|
|
17
|
-
ended_at: row.endedAt ?? null,
|
|
18
|
-
exit_code: row.exitCode ?? null,
|
|
19
|
-
status: row.status,
|
|
20
|
-
status_lock: row.statusLock,
|
|
21
|
-
interactive: row.interactive ? 1 : 0,
|
|
22
|
-
provider: row.provider,
|
|
23
|
-
model: row.model,
|
|
24
|
-
cwd: row.cwd,
|
|
25
|
-
workspace_root: row.workspaceRoot,
|
|
26
|
-
team_name: row.teamName ?? null,
|
|
27
|
-
enable_tools: row.enableTools ? 1 : 0,
|
|
28
|
-
enable_spawn: row.enableSpawn ? 1 : 0,
|
|
29
|
-
enable_teams: row.enableTeams ? 1 : 0,
|
|
30
|
-
parent_session_id: row.parentSessionId ?? null,
|
|
31
|
-
parent_agent_id: row.parentAgentId ?? null,
|
|
32
|
-
agent_id: row.agentId ?? null,
|
|
33
|
-
conversation_id: row.conversationId ?? null,
|
|
34
|
-
is_subagent: row.isSubagent ? 1 : 0,
|
|
35
|
-
prompt: row.prompt ?? null,
|
|
36
|
-
metadata_json: row.metadata ? JSON.stringify(row.metadata) : null,
|
|
37
|
-
transcript_path: row.transcriptPath,
|
|
38
|
-
hook_path: row.hookPath,
|
|
39
|
-
messages_path: row.messagesPath ?? null,
|
|
40
|
-
updated_at: row.updatedAt,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function fromShape(row: SessionRowShape): RpcSessionRow {
|
|
45
|
-
return {
|
|
46
|
-
sessionId: row.session_id,
|
|
47
|
-
source: row.source,
|
|
48
|
-
pid: row.pid,
|
|
49
|
-
startedAt: row.started_at,
|
|
50
|
-
endedAt: row.ended_at ?? null,
|
|
51
|
-
exitCode: row.exit_code ?? null,
|
|
52
|
-
status: row.status,
|
|
53
|
-
statusLock: row.status_lock ?? 0,
|
|
54
|
-
interactive: row.interactive === 1,
|
|
55
|
-
provider: row.provider,
|
|
56
|
-
model: row.model,
|
|
57
|
-
cwd: row.cwd,
|
|
58
|
-
workspaceRoot: row.workspace_root,
|
|
59
|
-
teamName: row.team_name ?? undefined,
|
|
60
|
-
enableTools: row.enable_tools === 1,
|
|
61
|
-
enableSpawn: row.enable_spawn === 1,
|
|
62
|
-
enableTeams: row.enable_teams === 1,
|
|
63
|
-
parentSessionId: row.parent_session_id ?? undefined,
|
|
64
|
-
parentAgentId: row.parent_agent_id ?? undefined,
|
|
65
|
-
agentId: row.agent_id ?? undefined,
|
|
66
|
-
conversationId: row.conversation_id ?? undefined,
|
|
67
|
-
isSubagent: row.is_subagent === 1,
|
|
68
|
-
prompt: row.prompt ?? undefined,
|
|
69
|
-
metadata: (() => {
|
|
70
|
-
if (!row.metadata_json) {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
const parsed = JSON.parse(row.metadata_json) as unknown;
|
|
75
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
76
|
-
return parsed as Record<string, unknown>;
|
|
77
|
-
}
|
|
78
|
-
} catch {
|
|
79
|
-
// Ignore malformed metadata payloads.
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
82
|
-
})(),
|
|
83
|
-
transcriptPath: row.transcript_path,
|
|
84
|
-
hookPath: row.hook_path,
|
|
85
|
-
messagesPath: row.messages_path ?? undefined,
|
|
86
|
-
updatedAt: row.updated_at ?? nowIso(),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
10
|
+
// ── Adapter ──────────────────────────────────────────────────────────
|
|
89
11
|
|
|
90
12
|
class RpcSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
91
13
|
constructor(private readonly client: RpcSessionClient) {}
|
|
@@ -94,39 +16,34 @@ class RpcSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
94
16
|
return "";
|
|
95
17
|
}
|
|
96
18
|
|
|
97
|
-
async upsertSession(row:
|
|
98
|
-
await this.client.upsertSession(
|
|
19
|
+
async upsertSession(row: SessionRow): Promise<void> {
|
|
20
|
+
await this.client.upsertSession(row as RpcSessionRow);
|
|
99
21
|
}
|
|
100
22
|
|
|
101
|
-
async getSession(sessionId: string): Promise<
|
|
23
|
+
async getSession(sessionId: string): Promise<SessionRow | undefined> {
|
|
102
24
|
const row = await this.client.getSession(sessionId);
|
|
103
|
-
return row
|
|
25
|
+
return (row as SessionRow | undefined) ?? undefined;
|
|
104
26
|
}
|
|
105
27
|
|
|
106
28
|
async listSessions(options: {
|
|
107
29
|
limit: number;
|
|
108
30
|
parentSessionId?: string;
|
|
109
31
|
status?: string;
|
|
110
|
-
}): Promise<
|
|
32
|
+
}): Promise<SessionRow[]> {
|
|
111
33
|
const rows = await this.client.listSessions(options);
|
|
112
|
-
return rows
|
|
34
|
+
return rows as SessionRow[];
|
|
113
35
|
}
|
|
114
36
|
|
|
115
37
|
async updateSession(
|
|
116
38
|
input: PersistedSessionUpdateInput,
|
|
117
39
|
): Promise<{ updated: boolean; statusLock: number }> {
|
|
118
|
-
|
|
40
|
+
return this.client.updateSession({
|
|
119
41
|
sessionId: input.sessionId,
|
|
120
42
|
status: input.status,
|
|
121
43
|
endedAt: input.endedAt,
|
|
122
44
|
exitCode: input.exitCode,
|
|
123
45
|
prompt: input.prompt,
|
|
124
|
-
metadata:
|
|
125
|
-
input.metadataJson === undefined
|
|
126
|
-
? undefined
|
|
127
|
-
: input.metadataJson
|
|
128
|
-
? (JSON.parse(input.metadataJson) as Record<string, unknown>)
|
|
129
|
-
: null,
|
|
46
|
+
metadata: input.metadata,
|
|
130
47
|
parentSessionId: input.parentSessionId,
|
|
131
48
|
parentAgentId: input.parentAgentId,
|
|
132
49
|
agentId: input.agentId,
|
|
@@ -134,11 +51,10 @@ class RpcSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
134
51
|
expectedStatusLock: input.expectedStatusLock,
|
|
135
52
|
setRunning: input.setRunning,
|
|
136
53
|
});
|
|
137
|
-
return changed;
|
|
138
54
|
}
|
|
139
55
|
|
|
140
56
|
async deleteSession(sessionId: string, cascade: boolean): Promise<boolean> {
|
|
141
|
-
return
|
|
57
|
+
return this.client.deleteSession(sessionId, cascade);
|
|
142
58
|
}
|
|
143
59
|
|
|
144
60
|
async enqueueSpawnRequest(input: {
|
|
@@ -154,10 +70,12 @@ class RpcSessionPersistenceAdapter implements SessionPersistenceAdapter {
|
|
|
154
70
|
rootSessionId: string,
|
|
155
71
|
parentAgentId: string,
|
|
156
72
|
): Promise<string | undefined> {
|
|
157
|
-
return
|
|
73
|
+
return this.client.claimSpawnRequest(rootSessionId, parentAgentId);
|
|
158
74
|
}
|
|
159
75
|
}
|
|
160
76
|
|
|
77
|
+
// ── Service ──────────────────────────────────────────────────────────
|
|
78
|
+
|
|
161
79
|
export interface RpcCoreSessionServiceOptions {
|
|
162
80
|
address?: string;
|
|
163
81
|
sessionsDir: string;
|
|
@@ -24,6 +24,7 @@ export async function buildEffectiveConfig(
|
|
|
24
24
|
hookPath: string,
|
|
25
25
|
sessionId: string,
|
|
26
26
|
defaultTelemetry: ITelemetryService | undefined,
|
|
27
|
+
onPluginEvent?: (event: { name: string; payload?: unknown }) => void,
|
|
27
28
|
): Promise<{
|
|
28
29
|
config: CoreSessionConfig;
|
|
29
30
|
pluginSandboxShutdown?: () => Promise<void>;
|
|
@@ -54,6 +55,7 @@ export async function buildEffectiveConfig(
|
|
|
54
55
|
pluginPaths: input.config.pluginPaths,
|
|
55
56
|
workspacePath,
|
|
56
57
|
cwd: input.config.cwd,
|
|
58
|
+
onEvent: onPluginEvent,
|
|
57
59
|
});
|
|
58
60
|
const effectiveExtensions = mergeAgentExtensions(
|
|
59
61
|
input.config.extensions,
|