@clinebot/core 0.0.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/README.md +88 -0
- package/dist/account/cline-account-service.d.ts +34 -0
- package/dist/account/index.d.ts +3 -0
- package/dist/account/rpc.d.ts +38 -0
- package/dist/account/types.d.ts +74 -0
- package/dist/agents/agent-config-loader.d.ts +18 -0
- package/dist/agents/agent-config-parser.d.ts +25 -0
- package/dist/agents/hooks-config-loader.d.ts +23 -0
- package/dist/agents/index.d.ts +11 -0
- package/dist/agents/plugin-config-loader.d.ts +22 -0
- package/dist/agents/plugin-loader.d.ts +9 -0
- package/dist/agents/plugin-sandbox.d.ts +12 -0
- package/dist/agents/unified-config-file-watcher.d.ts +77 -0
- package/dist/agents/user-instruction-config-loader.d.ts +63 -0
- package/dist/auth/client.d.ts +11 -0
- package/dist/auth/cline.d.ts +41 -0
- package/dist/auth/codex.d.ts +39 -0
- package/dist/auth/oca.d.ts +22 -0
- package/dist/auth/server.d.ts +22 -0
- package/dist/auth/types.d.ts +72 -0
- package/dist/auth/utils.d.ts +32 -0
- package/dist/chat/chat-schema.d.ts +145 -0
- package/dist/default-tools/constants.d.ts +23 -0
- package/dist/default-tools/definitions.d.ts +96 -0
- package/dist/default-tools/executors/apply-patch-parser.d.ts +68 -0
- package/dist/default-tools/executors/apply-patch.d.ts +26 -0
- package/dist/default-tools/executors/bash.d.ts +49 -0
- package/dist/default-tools/executors/editor.d.ts +31 -0
- package/dist/default-tools/executors/file-read.d.ts +40 -0
- package/dist/default-tools/executors/index.d.ts +44 -0
- package/dist/default-tools/executors/search.d.ts +50 -0
- package/dist/default-tools/executors/web-fetch.d.ts +58 -0
- package/dist/default-tools/index.d.ts +57 -0
- package/dist/default-tools/presets.d.ts +124 -0
- package/dist/default-tools/schemas.d.ts +121 -0
- package/dist/default-tools/types.d.ts +237 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +220 -0
- package/dist/input/file-indexer.d.ts +5 -0
- package/dist/input/index.d.ts +4 -0
- package/dist/input/mention-enricher.d.ts +12 -0
- package/dist/mcp/config-loader.d.ts +15 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/manager.d.ts +24 -0
- package/dist/mcp/types.d.ts +66 -0
- package/dist/runtime/hook-file-hooks.d.ts +18 -0
- package/dist/runtime/rules.d.ts +5 -0
- package/dist/runtime/runtime-builder.d.ts +5 -0
- package/dist/runtime/sandbox/subprocess-sandbox.d.ts +19 -0
- package/dist/runtime/session-runtime.d.ts +36 -0
- package/dist/runtime/tool-approval.d.ts +9 -0
- package/dist/runtime/workflows.d.ts +13 -0
- package/dist/server/index.d.ts +47 -0
- package/dist/server/index.js +641 -0
- package/dist/session/default-session-manager.d.ts +77 -0
- package/dist/session/rpc-session-service.d.ts +12 -0
- package/dist/session/runtime-oauth-token-manager.d.ts +28 -0
- package/dist/session/session-artifacts.d.ts +19 -0
- package/dist/session/session-graph.d.ts +15 -0
- package/dist/session/session-host.d.ts +21 -0
- package/dist/session/session-manager.d.ts +50 -0
- package/dist/session/session-manifest.d.ts +30 -0
- package/dist/session/session-service.d.ts +113 -0
- package/dist/session/sqlite-rpc-session-backend.d.ts +30 -0
- package/dist/session/unified-session-persistence-service.d.ts +93 -0
- package/dist/session/workspace-manager.d.ts +28 -0
- package/dist/session/workspace-manifest.d.ts +25 -0
- package/dist/storage/provider-settings-legacy-migration.d.ts +13 -0
- package/dist/storage/provider-settings-manager.d.ts +20 -0
- package/dist/storage/sqlite-session-store.d.ts +29 -0
- package/dist/storage/sqlite-team-store.d.ts +31 -0
- package/dist/storage/team-store.d.ts +2 -0
- package/dist/team/index.d.ts +1 -0
- package/dist/team/projections.d.ts +8 -0
- package/dist/types/common.d.ts +10 -0
- package/dist/types/config.d.ts +37 -0
- package/dist/types/events.d.ts +54 -0
- package/dist/types/provider-settings.d.ts +20 -0
- package/dist/types/sessions.d.ts +9 -0
- package/dist/types/storage.d.ts +37 -0
- package/dist/types/workspace.d.ts +7 -0
- package/dist/types.d.ts +26 -0
- package/package.json +63 -0
- package/src/account/cline-account-service.test.ts +101 -0
- package/src/account/cline-account-service.ts +267 -0
- package/src/account/index.ts +20 -0
- package/src/account/rpc.test.ts +62 -0
- package/src/account/rpc.ts +172 -0
- package/src/account/types.ts +80 -0
- package/src/agents/agent-config-loader.test.ts +234 -0
- package/src/agents/agent-config-loader.ts +107 -0
- package/src/agents/agent-config-parser.ts +191 -0
- package/src/agents/hooks-config-loader.ts +97 -0
- package/src/agents/index.ts +84 -0
- package/src/agents/plugin-config-loader.test.ts +91 -0
- package/src/agents/plugin-config-loader.ts +160 -0
- package/src/agents/plugin-loader.test.ts +102 -0
- package/src/agents/plugin-loader.ts +105 -0
- package/src/agents/plugin-sandbox.test.ts +120 -0
- package/src/agents/plugin-sandbox.ts +471 -0
- package/src/agents/unified-config-file-watcher.test.ts +196 -0
- package/src/agents/unified-config-file-watcher.ts +483 -0
- package/src/agents/user-instruction-config-loader.test.ts +158 -0
- package/src/agents/user-instruction-config-loader.ts +438 -0
- package/src/auth/client.test.ts +40 -0
- package/src/auth/client.ts +25 -0
- package/src/auth/cline.test.ts +130 -0
- package/src/auth/cline.ts +414 -0
- package/src/auth/codex.test.ts +170 -0
- package/src/auth/codex.ts +466 -0
- package/src/auth/oca.test.ts +215 -0
- package/src/auth/oca.ts +546 -0
- package/src/auth/server.ts +216 -0
- package/src/auth/types.ts +78 -0
- package/src/auth/utils.test.ts +128 -0
- package/src/auth/utils.ts +247 -0
- package/src/chat/chat-schema.ts +82 -0
- package/src/default-tools/constants.ts +35 -0
- package/src/default-tools/definitions.test.ts +233 -0
- package/src/default-tools/definitions.ts +632 -0
- package/src/default-tools/executors/apply-patch-parser.ts +520 -0
- package/src/default-tools/executors/apply-patch.ts +359 -0
- package/src/default-tools/executors/bash.ts +205 -0
- package/src/default-tools/executors/editor.ts +231 -0
- package/src/default-tools/executors/file-read.test.ts +25 -0
- package/src/default-tools/executors/file-read.ts +94 -0
- package/src/default-tools/executors/index.ts +75 -0
- package/src/default-tools/executors/search.ts +278 -0
- package/src/default-tools/executors/web-fetch.ts +259 -0
- package/src/default-tools/index.ts +161 -0
- package/src/default-tools/presets.test.ts +63 -0
- package/src/default-tools/presets.ts +168 -0
- package/src/default-tools/schemas.ts +228 -0
- package/src/default-tools/types.ts +324 -0
- package/src/index.ts +119 -0
- package/src/input/file-indexer.d.ts +11 -0
- package/src/input/file-indexer.test.ts +87 -0
- package/src/input/file-indexer.ts +280 -0
- package/src/input/index.ts +7 -0
- package/src/input/mention-enricher.test.ts +82 -0
- package/src/input/mention-enricher.ts +119 -0
- package/src/mcp/config-loader.test.ts +238 -0
- package/src/mcp/config-loader.ts +219 -0
- package/src/mcp/index.ts +26 -0
- package/src/mcp/manager.test.ts +106 -0
- package/src/mcp/manager.ts +262 -0
- package/src/mcp/types.ts +88 -0
- package/src/runtime/hook-file-hooks.test.ts +106 -0
- package/src/runtime/hook-file-hooks.ts +736 -0
- package/src/runtime/index.ts +27 -0
- package/src/runtime/rules.ts +34 -0
- package/src/runtime/runtime-builder.team-persistence.test.ts +203 -0
- package/src/runtime/runtime-builder.test.ts +215 -0
- package/src/runtime/runtime-builder.ts +515 -0
- package/src/runtime/runtime-parity.test.ts +132 -0
- package/src/runtime/sandbox/subprocess-sandbox.ts +207 -0
- package/src/runtime/session-runtime.ts +44 -0
- package/src/runtime/tool-approval.ts +104 -0
- package/src/runtime/workflows.test.ts +119 -0
- package/src/runtime/workflows.ts +54 -0
- package/src/server/index.ts +282 -0
- package/src/session/default-session-manager.e2e.test.ts +354 -0
- package/src/session/default-session-manager.test.ts +816 -0
- package/src/session/default-session-manager.ts +1286 -0
- package/src/session/index.ts +37 -0
- package/src/session/rpc-session-service.ts +189 -0
- package/src/session/runtime-oauth-token-manager.test.ts +137 -0
- package/src/session/runtime-oauth-token-manager.ts +265 -0
- package/src/session/session-artifacts.ts +106 -0
- package/src/session/session-graph.ts +90 -0
- package/src/session/session-host.ts +190 -0
- package/src/session/session-manager.ts +56 -0
- package/src/session/session-manifest.ts +29 -0
- package/src/session/session-service.team-persistence.test.ts +48 -0
- package/src/session/session-service.ts +610 -0
- package/src/session/sqlite-rpc-session-backend.ts +303 -0
- package/src/session/unified-session-persistence-service.ts +781 -0
- package/src/session/workspace-manager.ts +98 -0
- package/src/session/workspace-manifest.ts +100 -0
- package/src/storage/artifact-store.ts +1 -0
- package/src/storage/index.ts +11 -0
- package/src/storage/provider-settings-legacy-migration.test.ts +175 -0
- package/src/storage/provider-settings-legacy-migration.ts +637 -0
- package/src/storage/provider-settings-manager.test.ts +111 -0
- package/src/storage/provider-settings-manager.ts +129 -0
- package/src/storage/session-store.ts +1 -0
- package/src/storage/sqlite-session-store.ts +270 -0
- package/src/storage/sqlite-team-store.ts +443 -0
- package/src/storage/team-store.ts +5 -0
- package/src/team/index.ts +4 -0
- package/src/team/projections.ts +285 -0
- package/src/types/common.ts +14 -0
- package/src/types/config.ts +64 -0
- package/src/types/events.ts +46 -0
- package/src/types/index.ts +24 -0
- package/src/types/provider-settings.ts +43 -0
- package/src/types/sessions.ts +16 -0
- package/src/types/storage.ts +64 -0
- package/src/types/workspace.ts +7 -0
- package/src/types.ts +127 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type {
|
|
4
|
+
TeamEvent,
|
|
5
|
+
TeamRuntimeState,
|
|
6
|
+
TeamTeammateSpec,
|
|
7
|
+
} from "@clinebot/agents";
|
|
8
|
+
import { loadSqliteDb, nowIso, type SqliteDb } from "@clinebot/shared/db";
|
|
9
|
+
import { resolveTeamDataDir } from "@clinebot/shared/storage";
|
|
10
|
+
import type { TeamStore } from "../types/storage";
|
|
11
|
+
|
|
12
|
+
function defaultTeamDir(): string {
|
|
13
|
+
return resolveTeamDataDir();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sanitizeTeamName(name: string): string {
|
|
17
|
+
return name
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9._-]+/g, "-")
|
|
20
|
+
.replace(/^-+|-+$/g, "");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SqliteTeamStoreOptions {
|
|
24
|
+
teamDir?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface TeamRuntimeLoadResult {
|
|
28
|
+
state?: TeamRuntimeState;
|
|
29
|
+
teammates: TeamTeammateSpec[];
|
|
30
|
+
interruptedRunIds: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface TeamSnapshotRow {
|
|
34
|
+
team_name: string;
|
|
35
|
+
state_json: string;
|
|
36
|
+
teammates_json: string;
|
|
37
|
+
updated_at: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface TeamRunRow {
|
|
41
|
+
run_id: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function reviveTeamRuntimeStateDates(
|
|
45
|
+
state: TeamRuntimeState,
|
|
46
|
+
): TeamRuntimeState {
|
|
47
|
+
return {
|
|
48
|
+
...state,
|
|
49
|
+
tasks: state.tasks.map((task) => ({
|
|
50
|
+
...task,
|
|
51
|
+
createdAt: new Date(task.createdAt),
|
|
52
|
+
updatedAt: new Date(task.updatedAt),
|
|
53
|
+
})),
|
|
54
|
+
mailbox: state.mailbox.map((message) => ({
|
|
55
|
+
...message,
|
|
56
|
+
sentAt: new Date(message.sentAt),
|
|
57
|
+
readAt: message.readAt ? new Date(message.readAt) : undefined,
|
|
58
|
+
})),
|
|
59
|
+
missionLog: state.missionLog.map((entry) => ({
|
|
60
|
+
...entry,
|
|
61
|
+
ts: new Date(entry.ts),
|
|
62
|
+
})),
|
|
63
|
+
runs: (state.runs ?? []).map((run) => ({
|
|
64
|
+
...run,
|
|
65
|
+
startedAt: new Date(run.startedAt),
|
|
66
|
+
endedAt: run.endedAt ? new Date(run.endedAt) : undefined,
|
|
67
|
+
nextAttemptAt: run.nextAttemptAt
|
|
68
|
+
? new Date(run.nextAttemptAt)
|
|
69
|
+
: undefined,
|
|
70
|
+
heartbeatAt: run.heartbeatAt ? new Date(run.heartbeatAt) : undefined,
|
|
71
|
+
})),
|
|
72
|
+
outcomes: (state.outcomes ?? []).map((outcome) => ({
|
|
73
|
+
...outcome,
|
|
74
|
+
createdAt: new Date(outcome.createdAt),
|
|
75
|
+
finalizedAt: outcome.finalizedAt
|
|
76
|
+
? new Date(outcome.finalizedAt)
|
|
77
|
+
: undefined,
|
|
78
|
+
})),
|
|
79
|
+
outcomeFragments: (state.outcomeFragments ?? []).map((fragment) => ({
|
|
80
|
+
...fragment,
|
|
81
|
+
createdAt: new Date(fragment.createdAt),
|
|
82
|
+
reviewedAt: fragment.reviewedAt
|
|
83
|
+
? new Date(fragment.reviewedAt)
|
|
84
|
+
: undefined,
|
|
85
|
+
})),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class SqliteTeamStore implements TeamStore {
|
|
90
|
+
private readonly teamDirPath: string;
|
|
91
|
+
private db: SqliteDb | undefined;
|
|
92
|
+
|
|
93
|
+
constructor(options: SqliteTeamStoreOptions = {}) {
|
|
94
|
+
this.teamDirPath = options.teamDir ?? defaultTeamDir();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
init(): void {
|
|
98
|
+
this.getRawDb();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private ensureTeamDir(): string {
|
|
102
|
+
if (!existsSync(this.teamDirPath)) {
|
|
103
|
+
mkdirSync(this.teamDirPath, { recursive: true });
|
|
104
|
+
}
|
|
105
|
+
return this.teamDirPath;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private dbPath(): string {
|
|
109
|
+
return join(this.ensureTeamDir(), "teams.db");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private getRawDb(): SqliteDb {
|
|
113
|
+
if (this.db) {
|
|
114
|
+
return this.db;
|
|
115
|
+
}
|
|
116
|
+
const db = loadSqliteDb(this.dbPath());
|
|
117
|
+
this.ensureSchema(db);
|
|
118
|
+
this.db = db;
|
|
119
|
+
return db;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private ensureSchema(db: SqliteDb): void {
|
|
123
|
+
db.exec(`
|
|
124
|
+
CREATE TABLE IF NOT EXISTS team_events (
|
|
125
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
126
|
+
team_name TEXT NOT NULL,
|
|
127
|
+
ts TEXT NOT NULL,
|
|
128
|
+
event_type TEXT NOT NULL,
|
|
129
|
+
payload_json TEXT NOT NULL,
|
|
130
|
+
causation_id TEXT,
|
|
131
|
+
correlation_id TEXT
|
|
132
|
+
);
|
|
133
|
+
CREATE INDEX IF NOT EXISTS idx_team_events_name_ts
|
|
134
|
+
ON team_events(team_name, ts DESC);
|
|
135
|
+
|
|
136
|
+
CREATE TABLE IF NOT EXISTS team_runtime_snapshot (
|
|
137
|
+
team_name TEXT PRIMARY KEY,
|
|
138
|
+
state_json TEXT NOT NULL,
|
|
139
|
+
teammates_json TEXT NOT NULL,
|
|
140
|
+
updated_at TEXT NOT NULL
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
CREATE TABLE IF NOT EXISTS team_tasks (
|
|
144
|
+
team_name TEXT NOT NULL,
|
|
145
|
+
task_id TEXT NOT NULL,
|
|
146
|
+
title TEXT NOT NULL,
|
|
147
|
+
description TEXT NOT NULL,
|
|
148
|
+
status TEXT NOT NULL,
|
|
149
|
+
assignee TEXT,
|
|
150
|
+
depends_on_json TEXT NOT NULL,
|
|
151
|
+
summary TEXT,
|
|
152
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
153
|
+
updated_at TEXT NOT NULL,
|
|
154
|
+
PRIMARY KEY(team_name, task_id)
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
CREATE TABLE IF NOT EXISTS team_runs (
|
|
158
|
+
team_name TEXT NOT NULL,
|
|
159
|
+
run_id TEXT NOT NULL,
|
|
160
|
+
agent_id TEXT NOT NULL,
|
|
161
|
+
task_id TEXT,
|
|
162
|
+
status TEXT NOT NULL,
|
|
163
|
+
message TEXT NOT NULL,
|
|
164
|
+
started_at TEXT,
|
|
165
|
+
ended_at TEXT,
|
|
166
|
+
error TEXT,
|
|
167
|
+
lease_owner TEXT,
|
|
168
|
+
heartbeat_at TEXT,
|
|
169
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
170
|
+
PRIMARY KEY(team_name, run_id)
|
|
171
|
+
);
|
|
172
|
+
CREATE INDEX IF NOT EXISTS idx_team_runs_status
|
|
173
|
+
ON team_runs(team_name, status);
|
|
174
|
+
|
|
175
|
+
CREATE TABLE IF NOT EXISTS team_outcomes (
|
|
176
|
+
team_name TEXT NOT NULL,
|
|
177
|
+
outcome_id TEXT NOT NULL,
|
|
178
|
+
title TEXT NOT NULL,
|
|
179
|
+
status TEXT NOT NULL,
|
|
180
|
+
schema_json TEXT NOT NULL,
|
|
181
|
+
finalized_at TEXT,
|
|
182
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
183
|
+
PRIMARY KEY(team_name, outcome_id)
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
CREATE TABLE IF NOT EXISTS team_outcome_fragments (
|
|
187
|
+
team_name TEXT NOT NULL,
|
|
188
|
+
outcome_id TEXT NOT NULL,
|
|
189
|
+
fragment_id TEXT NOT NULL,
|
|
190
|
+
section TEXT NOT NULL,
|
|
191
|
+
source_agent_id TEXT NOT NULL,
|
|
192
|
+
source_run_id TEXT,
|
|
193
|
+
content TEXT NOT NULL,
|
|
194
|
+
status TEXT NOT NULL,
|
|
195
|
+
reviewed_by TEXT,
|
|
196
|
+
reviewed_at TEXT,
|
|
197
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
198
|
+
PRIMARY KEY(team_name, fragment_id)
|
|
199
|
+
);
|
|
200
|
+
`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private run(sql: string, params: unknown[] = []): { changes?: number } {
|
|
204
|
+
return this.getRawDb()
|
|
205
|
+
.prepare(sql)
|
|
206
|
+
.run(...params);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private queryOne<T>(sql: string, params: unknown[] = []): T | undefined {
|
|
210
|
+
const row = this.getRawDb()
|
|
211
|
+
.prepare(sql)
|
|
212
|
+
.get(...params);
|
|
213
|
+
return (row as T | null) ?? undefined;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private queryAll<T>(sql: string, params: unknown[] = []): T[] {
|
|
217
|
+
return this.getRawDb()
|
|
218
|
+
.prepare(sql)
|
|
219
|
+
.all(...params) as T[];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
listTeamNames(): string[] {
|
|
223
|
+
return this.queryAll<{ team_name: string }>(
|
|
224
|
+
`SELECT team_name FROM team_runtime_snapshot ORDER BY team_name ASC`,
|
|
225
|
+
).map((row) => row.team_name);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
readState(teamName: string): TeamRuntimeState | undefined {
|
|
229
|
+
const row = this.queryOne<TeamSnapshotRow>(
|
|
230
|
+
`SELECT team_name, state_json, teammates_json, updated_at FROM team_runtime_snapshot WHERE team_name = ?`,
|
|
231
|
+
[sanitizeTeamName(teamName)],
|
|
232
|
+
);
|
|
233
|
+
if (!row) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
return reviveTeamRuntimeStateDates(
|
|
237
|
+
JSON.parse(row.state_json) as TeamRuntimeState,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
readHistory(teamName: string, limit = 200): unknown[] {
|
|
242
|
+
return this.queryAll<{
|
|
243
|
+
event_type: string;
|
|
244
|
+
payload_json: string;
|
|
245
|
+
ts: string;
|
|
246
|
+
}>(
|
|
247
|
+
`SELECT event_type, payload_json, ts FROM team_events WHERE team_name = ? ORDER BY id DESC LIMIT ?`,
|
|
248
|
+
[sanitizeTeamName(teamName), limit],
|
|
249
|
+
).map((row) => ({
|
|
250
|
+
eventType: row.event_type,
|
|
251
|
+
payload: JSON.parse(row.payload_json),
|
|
252
|
+
ts: row.ts,
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
loadRuntime(teamName: string): TeamRuntimeLoadResult {
|
|
257
|
+
const safeTeamName = sanitizeTeamName(teamName);
|
|
258
|
+
const state = this.readState(safeTeamName);
|
|
259
|
+
const snapshotRow = this.queryOne<TeamSnapshotRow>(
|
|
260
|
+
`SELECT team_name, state_json, teammates_json, updated_at FROM team_runtime_snapshot WHERE team_name = ?`,
|
|
261
|
+
[safeTeamName],
|
|
262
|
+
);
|
|
263
|
+
const teammates = snapshotRow
|
|
264
|
+
? (JSON.parse(snapshotRow.teammates_json) as TeamTeammateSpec[])
|
|
265
|
+
: [];
|
|
266
|
+
const interruptedRunIds = this.markInProgressRunsInterrupted(
|
|
267
|
+
safeTeamName,
|
|
268
|
+
"runtime_recovered",
|
|
269
|
+
);
|
|
270
|
+
return {
|
|
271
|
+
state,
|
|
272
|
+
teammates,
|
|
273
|
+
interruptedRunIds,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
appendTeamEvent(
|
|
278
|
+
teamName: string,
|
|
279
|
+
eventType: string,
|
|
280
|
+
payload: unknown,
|
|
281
|
+
correlationId?: string,
|
|
282
|
+
): void {
|
|
283
|
+
this.run(
|
|
284
|
+
`INSERT INTO team_events (team_name, ts, event_type, payload_json, causation_id, correlation_id)
|
|
285
|
+
VALUES (?, ?, ?, ?, NULL, ?)`,
|
|
286
|
+
[
|
|
287
|
+
sanitizeTeamName(teamName),
|
|
288
|
+
nowIso(),
|
|
289
|
+
eventType,
|
|
290
|
+
JSON.stringify(payload),
|
|
291
|
+
correlationId ?? null,
|
|
292
|
+
],
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
persistRuntime(
|
|
297
|
+
teamName: string,
|
|
298
|
+
state: TeamRuntimeState,
|
|
299
|
+
teammates: TeamTeammateSpec[],
|
|
300
|
+
): void {
|
|
301
|
+
const safeTeamName = sanitizeTeamName(teamName);
|
|
302
|
+
const now = nowIso();
|
|
303
|
+
this.run(
|
|
304
|
+
`INSERT INTO team_runtime_snapshot (team_name, state_json, teammates_json, updated_at)
|
|
305
|
+
VALUES (?, ?, ?, ?)
|
|
306
|
+
ON CONFLICT(team_name) DO UPDATE SET
|
|
307
|
+
state_json = excluded.state_json,
|
|
308
|
+
teammates_json = excluded.teammates_json,
|
|
309
|
+
updated_at = excluded.updated_at`,
|
|
310
|
+
[safeTeamName, JSON.stringify(state), JSON.stringify(teammates), now],
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
for (const task of state.tasks) {
|
|
314
|
+
this.run(
|
|
315
|
+
`INSERT INTO team_tasks (team_name, task_id, title, description, status, assignee, depends_on_json, summary, version, updated_at)
|
|
316
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
|
|
317
|
+
ON CONFLICT(team_name, task_id) DO UPDATE SET
|
|
318
|
+
title = excluded.title,
|
|
319
|
+
description = excluded.description,
|
|
320
|
+
status = excluded.status,
|
|
321
|
+
assignee = excluded.assignee,
|
|
322
|
+
depends_on_json = excluded.depends_on_json,
|
|
323
|
+
summary = excluded.summary,
|
|
324
|
+
version = team_tasks.version + 1,
|
|
325
|
+
updated_at = excluded.updated_at`,
|
|
326
|
+
[
|
|
327
|
+
safeTeamName,
|
|
328
|
+
task.id,
|
|
329
|
+
task.title,
|
|
330
|
+
task.description,
|
|
331
|
+
task.status,
|
|
332
|
+
task.assignee ?? null,
|
|
333
|
+
JSON.stringify(task.dependsOn ?? []),
|
|
334
|
+
task.summary ?? null,
|
|
335
|
+
task.updatedAt.toISOString(),
|
|
336
|
+
],
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for (const run of state.runs ?? []) {
|
|
341
|
+
this.run(
|
|
342
|
+
`INSERT INTO team_runs (team_name, run_id, agent_id, task_id, status, message, started_at, ended_at, error, lease_owner, heartbeat_at, version)
|
|
343
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
|
|
344
|
+
ON CONFLICT(team_name, run_id) DO UPDATE SET
|
|
345
|
+
agent_id = excluded.agent_id,
|
|
346
|
+
task_id = excluded.task_id,
|
|
347
|
+
status = excluded.status,
|
|
348
|
+
message = excluded.message,
|
|
349
|
+
started_at = excluded.started_at,
|
|
350
|
+
ended_at = excluded.ended_at,
|
|
351
|
+
error = excluded.error,
|
|
352
|
+
lease_owner = excluded.lease_owner,
|
|
353
|
+
heartbeat_at = excluded.heartbeat_at,
|
|
354
|
+
version = team_runs.version + 1`,
|
|
355
|
+
[
|
|
356
|
+
safeTeamName,
|
|
357
|
+
run.id,
|
|
358
|
+
run.agentId,
|
|
359
|
+
run.taskId ?? null,
|
|
360
|
+
run.status,
|
|
361
|
+
run.message,
|
|
362
|
+
run.startedAt ? run.startedAt.toISOString() : null,
|
|
363
|
+
run.endedAt ? run.endedAt.toISOString() : null,
|
|
364
|
+
run.error ?? null,
|
|
365
|
+
run.leaseOwner ?? null,
|
|
366
|
+
run.heartbeatAt ? run.heartbeatAt.toISOString() : null,
|
|
367
|
+
],
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
for (const outcome of state.outcomes ?? []) {
|
|
372
|
+
this.run(
|
|
373
|
+
`INSERT INTO team_outcomes (team_name, outcome_id, title, status, schema_json, finalized_at, version)
|
|
374
|
+
VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
375
|
+
ON CONFLICT(team_name, outcome_id) DO UPDATE SET
|
|
376
|
+
title = excluded.title,
|
|
377
|
+
status = excluded.status,
|
|
378
|
+
schema_json = excluded.schema_json,
|
|
379
|
+
finalized_at = excluded.finalized_at,
|
|
380
|
+
version = team_outcomes.version + 1`,
|
|
381
|
+
[
|
|
382
|
+
safeTeamName,
|
|
383
|
+
outcome.id,
|
|
384
|
+
outcome.title,
|
|
385
|
+
outcome.status,
|
|
386
|
+
JSON.stringify({ requiredSections: outcome.requiredSections }),
|
|
387
|
+
outcome.finalizedAt ? outcome.finalizedAt.toISOString() : null,
|
|
388
|
+
],
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
for (const fragment of state.outcomeFragments ?? []) {
|
|
393
|
+
this.run(
|
|
394
|
+
`INSERT INTO team_outcome_fragments (team_name, outcome_id, fragment_id, section, source_agent_id, source_run_id, content, status, reviewed_by, reviewed_at, version)
|
|
395
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
|
|
396
|
+
ON CONFLICT(team_name, fragment_id) DO UPDATE SET
|
|
397
|
+
outcome_id = excluded.outcome_id,
|
|
398
|
+
section = excluded.section,
|
|
399
|
+
source_agent_id = excluded.source_agent_id,
|
|
400
|
+
source_run_id = excluded.source_run_id,
|
|
401
|
+
content = excluded.content,
|
|
402
|
+
status = excluded.status,
|
|
403
|
+
reviewed_by = excluded.reviewed_by,
|
|
404
|
+
reviewed_at = excluded.reviewed_at,
|
|
405
|
+
version = team_outcome_fragments.version + 1`,
|
|
406
|
+
[
|
|
407
|
+
safeTeamName,
|
|
408
|
+
fragment.outcomeId,
|
|
409
|
+
fragment.id,
|
|
410
|
+
fragment.section,
|
|
411
|
+
fragment.sourceAgentId,
|
|
412
|
+
fragment.sourceRunId ?? null,
|
|
413
|
+
fragment.content,
|
|
414
|
+
fragment.status,
|
|
415
|
+
fragment.reviewedBy ?? null,
|
|
416
|
+
fragment.reviewedAt ? fragment.reviewedAt.toISOString() : null,
|
|
417
|
+
],
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
markInProgressRunsInterrupted(teamName: string, reason: string): string[] {
|
|
423
|
+
const safeTeamName = sanitizeTeamName(teamName);
|
|
424
|
+
const rows = this.queryAll<TeamRunRow>(
|
|
425
|
+
`SELECT run_id FROM team_runs WHERE team_name = ? AND status IN ('queued', 'running')`,
|
|
426
|
+
[safeTeamName],
|
|
427
|
+
);
|
|
428
|
+
if (rows.length === 0) {
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
const now = nowIso();
|
|
432
|
+
this.run(
|
|
433
|
+
`UPDATE team_runs SET status = 'interrupted', error = ?, ended_at = ?, version = version + 1
|
|
434
|
+
WHERE team_name = ? AND status IN ('queued', 'running')`,
|
|
435
|
+
[reason, now, safeTeamName],
|
|
436
|
+
);
|
|
437
|
+
return rows.map((row) => row.run_id);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
handleTeamEvent(teamName: string, event: TeamEvent): void {
|
|
441
|
+
this.appendTeamEvent(teamName, event.type, event);
|
|
442
|
+
}
|
|
443
|
+
}
|