@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.
Files changed (200) hide show
  1. package/README.md +88 -0
  2. package/dist/account/cline-account-service.d.ts +34 -0
  3. package/dist/account/index.d.ts +3 -0
  4. package/dist/account/rpc.d.ts +38 -0
  5. package/dist/account/types.d.ts +74 -0
  6. package/dist/agents/agent-config-loader.d.ts +18 -0
  7. package/dist/agents/agent-config-parser.d.ts +25 -0
  8. package/dist/agents/hooks-config-loader.d.ts +23 -0
  9. package/dist/agents/index.d.ts +11 -0
  10. package/dist/agents/plugin-config-loader.d.ts +22 -0
  11. package/dist/agents/plugin-loader.d.ts +9 -0
  12. package/dist/agents/plugin-sandbox.d.ts +12 -0
  13. package/dist/agents/unified-config-file-watcher.d.ts +77 -0
  14. package/dist/agents/user-instruction-config-loader.d.ts +63 -0
  15. package/dist/auth/client.d.ts +11 -0
  16. package/dist/auth/cline.d.ts +41 -0
  17. package/dist/auth/codex.d.ts +39 -0
  18. package/dist/auth/oca.d.ts +22 -0
  19. package/dist/auth/server.d.ts +22 -0
  20. package/dist/auth/types.d.ts +72 -0
  21. package/dist/auth/utils.d.ts +32 -0
  22. package/dist/chat/chat-schema.d.ts +145 -0
  23. package/dist/default-tools/constants.d.ts +23 -0
  24. package/dist/default-tools/definitions.d.ts +96 -0
  25. package/dist/default-tools/executors/apply-patch-parser.d.ts +68 -0
  26. package/dist/default-tools/executors/apply-patch.d.ts +26 -0
  27. package/dist/default-tools/executors/bash.d.ts +49 -0
  28. package/dist/default-tools/executors/editor.d.ts +31 -0
  29. package/dist/default-tools/executors/file-read.d.ts +40 -0
  30. package/dist/default-tools/executors/index.d.ts +44 -0
  31. package/dist/default-tools/executors/search.d.ts +50 -0
  32. package/dist/default-tools/executors/web-fetch.d.ts +58 -0
  33. package/dist/default-tools/index.d.ts +57 -0
  34. package/dist/default-tools/presets.d.ts +124 -0
  35. package/dist/default-tools/schemas.d.ts +121 -0
  36. package/dist/default-tools/types.d.ts +237 -0
  37. package/dist/index.d.ts +23 -0
  38. package/dist/index.js +220 -0
  39. package/dist/input/file-indexer.d.ts +5 -0
  40. package/dist/input/index.d.ts +4 -0
  41. package/dist/input/mention-enricher.d.ts +12 -0
  42. package/dist/mcp/config-loader.d.ts +15 -0
  43. package/dist/mcp/index.d.ts +4 -0
  44. package/dist/mcp/manager.d.ts +24 -0
  45. package/dist/mcp/types.d.ts +66 -0
  46. package/dist/runtime/hook-file-hooks.d.ts +18 -0
  47. package/dist/runtime/rules.d.ts +5 -0
  48. package/dist/runtime/runtime-builder.d.ts +5 -0
  49. package/dist/runtime/sandbox/subprocess-sandbox.d.ts +19 -0
  50. package/dist/runtime/session-runtime.d.ts +36 -0
  51. package/dist/runtime/tool-approval.d.ts +9 -0
  52. package/dist/runtime/workflows.d.ts +13 -0
  53. package/dist/server/index.d.ts +47 -0
  54. package/dist/server/index.js +641 -0
  55. package/dist/session/default-session-manager.d.ts +77 -0
  56. package/dist/session/rpc-session-service.d.ts +12 -0
  57. package/dist/session/runtime-oauth-token-manager.d.ts +28 -0
  58. package/dist/session/session-artifacts.d.ts +19 -0
  59. package/dist/session/session-graph.d.ts +15 -0
  60. package/dist/session/session-host.d.ts +21 -0
  61. package/dist/session/session-manager.d.ts +50 -0
  62. package/dist/session/session-manifest.d.ts +30 -0
  63. package/dist/session/session-service.d.ts +113 -0
  64. package/dist/session/sqlite-rpc-session-backend.d.ts +30 -0
  65. package/dist/session/unified-session-persistence-service.d.ts +93 -0
  66. package/dist/session/workspace-manager.d.ts +28 -0
  67. package/dist/session/workspace-manifest.d.ts +25 -0
  68. package/dist/storage/provider-settings-legacy-migration.d.ts +13 -0
  69. package/dist/storage/provider-settings-manager.d.ts +20 -0
  70. package/dist/storage/sqlite-session-store.d.ts +29 -0
  71. package/dist/storage/sqlite-team-store.d.ts +31 -0
  72. package/dist/storage/team-store.d.ts +2 -0
  73. package/dist/team/index.d.ts +1 -0
  74. package/dist/team/projections.d.ts +8 -0
  75. package/dist/types/common.d.ts +10 -0
  76. package/dist/types/config.d.ts +37 -0
  77. package/dist/types/events.d.ts +54 -0
  78. package/dist/types/provider-settings.d.ts +20 -0
  79. package/dist/types/sessions.d.ts +9 -0
  80. package/dist/types/storage.d.ts +37 -0
  81. package/dist/types/workspace.d.ts +7 -0
  82. package/dist/types.d.ts +26 -0
  83. package/package.json +63 -0
  84. package/src/account/cline-account-service.test.ts +101 -0
  85. package/src/account/cline-account-service.ts +267 -0
  86. package/src/account/index.ts +20 -0
  87. package/src/account/rpc.test.ts +62 -0
  88. package/src/account/rpc.ts +172 -0
  89. package/src/account/types.ts +80 -0
  90. package/src/agents/agent-config-loader.test.ts +234 -0
  91. package/src/agents/agent-config-loader.ts +107 -0
  92. package/src/agents/agent-config-parser.ts +191 -0
  93. package/src/agents/hooks-config-loader.ts +97 -0
  94. package/src/agents/index.ts +84 -0
  95. package/src/agents/plugin-config-loader.test.ts +91 -0
  96. package/src/agents/plugin-config-loader.ts +160 -0
  97. package/src/agents/plugin-loader.test.ts +102 -0
  98. package/src/agents/plugin-loader.ts +105 -0
  99. package/src/agents/plugin-sandbox.test.ts +120 -0
  100. package/src/agents/plugin-sandbox.ts +471 -0
  101. package/src/agents/unified-config-file-watcher.test.ts +196 -0
  102. package/src/agents/unified-config-file-watcher.ts +483 -0
  103. package/src/agents/user-instruction-config-loader.test.ts +158 -0
  104. package/src/agents/user-instruction-config-loader.ts +438 -0
  105. package/src/auth/client.test.ts +40 -0
  106. package/src/auth/client.ts +25 -0
  107. package/src/auth/cline.test.ts +130 -0
  108. package/src/auth/cline.ts +414 -0
  109. package/src/auth/codex.test.ts +170 -0
  110. package/src/auth/codex.ts +466 -0
  111. package/src/auth/oca.test.ts +215 -0
  112. package/src/auth/oca.ts +546 -0
  113. package/src/auth/server.ts +216 -0
  114. package/src/auth/types.ts +78 -0
  115. package/src/auth/utils.test.ts +128 -0
  116. package/src/auth/utils.ts +247 -0
  117. package/src/chat/chat-schema.ts +82 -0
  118. package/src/default-tools/constants.ts +35 -0
  119. package/src/default-tools/definitions.test.ts +233 -0
  120. package/src/default-tools/definitions.ts +632 -0
  121. package/src/default-tools/executors/apply-patch-parser.ts +520 -0
  122. package/src/default-tools/executors/apply-patch.ts +359 -0
  123. package/src/default-tools/executors/bash.ts +205 -0
  124. package/src/default-tools/executors/editor.ts +231 -0
  125. package/src/default-tools/executors/file-read.test.ts +25 -0
  126. package/src/default-tools/executors/file-read.ts +94 -0
  127. package/src/default-tools/executors/index.ts +75 -0
  128. package/src/default-tools/executors/search.ts +278 -0
  129. package/src/default-tools/executors/web-fetch.ts +259 -0
  130. package/src/default-tools/index.ts +161 -0
  131. package/src/default-tools/presets.test.ts +63 -0
  132. package/src/default-tools/presets.ts +168 -0
  133. package/src/default-tools/schemas.ts +228 -0
  134. package/src/default-tools/types.ts +324 -0
  135. package/src/index.ts +119 -0
  136. package/src/input/file-indexer.d.ts +11 -0
  137. package/src/input/file-indexer.test.ts +87 -0
  138. package/src/input/file-indexer.ts +280 -0
  139. package/src/input/index.ts +7 -0
  140. package/src/input/mention-enricher.test.ts +82 -0
  141. package/src/input/mention-enricher.ts +119 -0
  142. package/src/mcp/config-loader.test.ts +238 -0
  143. package/src/mcp/config-loader.ts +219 -0
  144. package/src/mcp/index.ts +26 -0
  145. package/src/mcp/manager.test.ts +106 -0
  146. package/src/mcp/manager.ts +262 -0
  147. package/src/mcp/types.ts +88 -0
  148. package/src/runtime/hook-file-hooks.test.ts +106 -0
  149. package/src/runtime/hook-file-hooks.ts +736 -0
  150. package/src/runtime/index.ts +27 -0
  151. package/src/runtime/rules.ts +34 -0
  152. package/src/runtime/runtime-builder.team-persistence.test.ts +203 -0
  153. package/src/runtime/runtime-builder.test.ts +215 -0
  154. package/src/runtime/runtime-builder.ts +515 -0
  155. package/src/runtime/runtime-parity.test.ts +132 -0
  156. package/src/runtime/sandbox/subprocess-sandbox.ts +207 -0
  157. package/src/runtime/session-runtime.ts +44 -0
  158. package/src/runtime/tool-approval.ts +104 -0
  159. package/src/runtime/workflows.test.ts +119 -0
  160. package/src/runtime/workflows.ts +54 -0
  161. package/src/server/index.ts +282 -0
  162. package/src/session/default-session-manager.e2e.test.ts +354 -0
  163. package/src/session/default-session-manager.test.ts +816 -0
  164. package/src/session/default-session-manager.ts +1286 -0
  165. package/src/session/index.ts +37 -0
  166. package/src/session/rpc-session-service.ts +189 -0
  167. package/src/session/runtime-oauth-token-manager.test.ts +137 -0
  168. package/src/session/runtime-oauth-token-manager.ts +265 -0
  169. package/src/session/session-artifacts.ts +106 -0
  170. package/src/session/session-graph.ts +90 -0
  171. package/src/session/session-host.ts +190 -0
  172. package/src/session/session-manager.ts +56 -0
  173. package/src/session/session-manifest.ts +29 -0
  174. package/src/session/session-service.team-persistence.test.ts +48 -0
  175. package/src/session/session-service.ts +610 -0
  176. package/src/session/sqlite-rpc-session-backend.ts +303 -0
  177. package/src/session/unified-session-persistence-service.ts +781 -0
  178. package/src/session/workspace-manager.ts +98 -0
  179. package/src/session/workspace-manifest.ts +100 -0
  180. package/src/storage/artifact-store.ts +1 -0
  181. package/src/storage/index.ts +11 -0
  182. package/src/storage/provider-settings-legacy-migration.test.ts +175 -0
  183. package/src/storage/provider-settings-legacy-migration.ts +637 -0
  184. package/src/storage/provider-settings-manager.test.ts +111 -0
  185. package/src/storage/provider-settings-manager.ts +129 -0
  186. package/src/storage/session-store.ts +1 -0
  187. package/src/storage/sqlite-session-store.ts +270 -0
  188. package/src/storage/sqlite-team-store.ts +443 -0
  189. package/src/storage/team-store.ts +5 -0
  190. package/src/team/index.ts +4 -0
  191. package/src/team/projections.ts +285 -0
  192. package/src/types/common.ts +14 -0
  193. package/src/types/config.ts +64 -0
  194. package/src/types/events.ts +46 -0
  195. package/src/types/index.ts +24 -0
  196. package/src/types/provider-settings.ts +43 -0
  197. package/src/types/sessions.ts +16 -0
  198. package/src/types/storage.ts +64 -0
  199. package/src/types/workspace.ts +7 -0
  200. 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
+ }
@@ -0,0 +1,5 @@
1
+ export type { TeamStore } from "../types/storage";
2
+ export {
3
+ SqliteTeamStore,
4
+ type SqliteTeamStoreOptions,
5
+ } from "./sqlite-team-store";
@@ -0,0 +1,4 @@
1
+ export {
2
+ buildTeamProgressSummary,
3
+ toTeamProgressLifecycleEvent,
4
+ } from "./projections";