@elpapi42/pi-fleet 0.1.0-beta.0 → 0.1.0-beta.10

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "inputs": {
3
3
  "src/store/sqlite-store.ts": {
4
- "bytes": 11540,
4
+ "bytes": 14146,
5
5
  "imports": [
6
6
  {
7
7
  "path": "node:fs",
@@ -22,7 +22,7 @@
22
22
  "format": "esm"
23
23
  },
24
24
  "src/store/sqlite-worker.ts": {
25
- "bytes": 2480,
25
+ "bytes": 2757,
26
26
  "imports": [
27
27
  {
28
28
  "path": "node:worker_threads",
@@ -43,7 +43,7 @@
43
43
  "imports": [],
44
44
  "exports": [],
45
45
  "inputs": {},
46
- "bytes": 20305
46
+ "bytes": 24288
47
47
  },
48
48
  "dist/sqlite-worker.mjs": {
49
49
  "imports": [
@@ -72,13 +72,13 @@
72
72
  "entryPoint": "src/store/sqlite-worker.ts",
73
73
  "inputs": {
74
74
  "src/store/sqlite-worker.ts": {
75
- "bytesInOutput": 1928
75
+ "bytesInOutput": 2152
76
76
  },
77
77
  "src/store/sqlite-store.ts": {
78
- "bytesInOutput": 9965
78
+ "bytesInOutput": 12211
79
79
  }
80
80
  },
81
- "bytes": 12027
81
+ "bytes": 14497
82
82
  }
83
83
  }
84
84
  }
@@ -41,6 +41,29 @@ var MIGRATIONS = [
41
41
  data_json TEXT NOT NULL CHECK(json_valid(data_json))
42
42
  );
43
43
  `
44
+ },
45
+ {
46
+ version: 2,
47
+ checksum: "002_compact_v1",
48
+ statements: `
49
+ ALTER TABLE operations RENAME TO operations_v1;
50
+ CREATE TABLE operations(
51
+ operation_id TEXT PRIMARY KEY,
52
+ method TEXT NOT NULL CHECK(method IN ('create','send','destroy','compact')),
53
+ state TEXT NOT NULL CHECK(state IN ('pending','completed')),
54
+ data_json TEXT NOT NULL CHECK(json_valid(data_json))
55
+ );
56
+ INSERT INTO operations(operation_id, method, state, data_json)
57
+ SELECT operation_id, method, state, data_json FROM operations_v1;
58
+ DROP TABLE operations_v1;
59
+ CREATE TABLE compact_records(
60
+ compact_id TEXT PRIMARY KEY,
61
+ agent_name TEXT NOT NULL,
62
+ state TEXT NOT NULL CHECK(state IN ('pending','dispatching','completed','failed','uncertain')),
63
+ data_json TEXT NOT NULL CHECK(json_valid(data_json))
64
+ );
65
+ CREATE INDEX compact_records_nonterminal ON compact_records(state, agent_name);
66
+ `
44
67
  }
45
68
  ];
46
69
  var SqliteFleetStore = class {
@@ -54,49 +77,50 @@ var SqliteFleetStore = class {
54
77
  );
55
78
  try {
56
79
  this.#migrate();
80
+ const metadata = this.#database.prepare("SELECT clean_shutdown FROM runtime_metadata WHERE singleton_key = 1").get();
81
+ if (metadata?.clean_shutdown === 0) {
82
+ this.#verifyIntegrity();
83
+ this.#database.exec(`
84
+ UPDATE agents
85
+ SET state = 'failed', process_state = 'cleanup_uncertain',
86
+ data_json = json_set(data_json,
87
+ '$.summary.state', 'failed',
88
+ '$.summary.process.state', 'cleanup_uncertain',
89
+ '$.summary.error.code',
90
+ CASE WHEN state IN ('working', 'restoring')
91
+ THEN 'runtime_interrupted'
92
+ ELSE 'incarnation_cleanup_uncertain'
93
+ END)
94
+ WHERE process_state IN ('resident', 'starting');
95
+ UPDATE incarnations
96
+ SET state = 'cleanup_uncertain',
97
+ data_json = json_set(data_json, '$.state', 'cleanup_uncertain')
98
+ WHERE state IN ('starting', 'live', 'stopping');
99
+ `);
100
+ } else if (metadata?.clean_shutdown === 1) {
101
+ this.#database.exec(`
102
+ UPDATE agents
103
+ SET state = CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
104
+ process_state = 'absent',
105
+ data_json = json_set(data_json,
106
+ '$.summary.state', CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
107
+ '$.summary.process.state', 'absent')
108
+ WHERE process_state IN ('resident', 'starting');
109
+ UPDATE incarnations
110
+ SET state = 'gone', data_json = json_set(data_json, '$.state', 'gone')
111
+ WHERE state IN ('starting', 'live', 'stopping');
112
+ `);
113
+ }
114
+ this.#database.prepare(
115
+ `INSERT INTO runtime_metadata(singleton_key, clean_shutdown)
116
+ VALUES(1, 0)
117
+ ON CONFLICT(singleton_key) DO UPDATE SET clean_shutdown = 0`
118
+ ).run();
57
119
  } catch (error) {
58
120
  this.#database.close();
59
121
  this.#closed = true;
60
122
  throw error;
61
123
  }
62
- const metadata = this.#database.prepare("SELECT clean_shutdown FROM runtime_metadata WHERE singleton_key = 1").get();
63
- if (metadata?.clean_shutdown === 0) {
64
- this.#database.exec(`
65
- UPDATE agents
66
- SET state = 'failed', process_state = 'cleanup_uncertain',
67
- data_json = json_set(data_json,
68
- '$.summary.state', 'failed',
69
- '$.summary.process.state', 'cleanup_uncertain',
70
- '$.summary.error.code',
71
- CASE WHEN state IN ('working', 'restoring')
72
- THEN 'runtime_interrupted'
73
- ELSE 'incarnation_cleanup_uncertain'
74
- END)
75
- WHERE process_state IN ('resident', 'starting');
76
- UPDATE incarnations
77
- SET state = 'cleanup_uncertain',
78
- data_json = json_set(data_json, '$.state', 'cleanup_uncertain')
79
- WHERE state IN ('starting', 'live', 'stopping');
80
- `);
81
- } else if (metadata?.clean_shutdown === 1) {
82
- this.#database.exec(`
83
- UPDATE agents
84
- SET state = CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
85
- process_state = 'absent',
86
- data_json = json_set(data_json,
87
- '$.summary.state', CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
88
- '$.summary.process.state', 'absent')
89
- WHERE process_state IN ('resident', 'starting');
90
- UPDATE incarnations
91
- SET state = 'gone', data_json = json_set(data_json, '$.state', 'gone')
92
- WHERE state IN ('starting', 'live', 'stopping');
93
- `);
94
- }
95
- this.#database.prepare(
96
- `INSERT INTO runtime_metadata(singleton_key, clean_shutdown)
97
- VALUES(1, 0)
98
- ON CONFLICT(singleton_key) DO UPDATE SET clean_shutdown = 0`
99
- ).run();
100
124
  }
101
125
  async createAgent(agent) {
102
126
  const result = this.#database.prepare(
@@ -185,6 +209,23 @@ var SqliteFleetStore = class {
185
209
  ).all();
186
210
  return rows.map((row) => JSON.parse(row.data_json));
187
211
  }
212
+ async getCompact(compactId) {
213
+ const row = this.#database.prepare("SELECT data_json FROM compact_records WHERE compact_id = ?").get(compactId);
214
+ return row === void 0 ? null : JSON.parse(row.data_json);
215
+ }
216
+ async putCompact(compact) {
217
+ this.#database.prepare(
218
+ `INSERT INTO compact_records(compact_id, agent_name, state, data_json)
219
+ VALUES(?, ?, ?, ?)
220
+ ON CONFLICT(compact_id) DO UPDATE SET state=excluded.state, data_json=excluded.data_json`
221
+ ).run(compact.compactId, compact.agentName, compact.state, JSON.stringify(compact));
222
+ }
223
+ async listNonterminalCompacts() {
224
+ const rows = this.#database.prepare(
225
+ "SELECT data_json FROM compact_records WHERE state IN ('pending','dispatching') ORDER BY rowid"
226
+ ).all();
227
+ return rows.map((row) => JSON.parse(row.data_json));
228
+ }
188
229
  async putIncarnation(incarnation) {
189
230
  this.#database.prepare(
190
231
  `INSERT INTO incarnations(incarnation_id, agent_name, pid, state, data_json)
@@ -211,6 +252,12 @@ var SqliteFleetStore = class {
211
252
  this.#database.close();
212
253
  this.#closed = true;
213
254
  }
255
+ #verifyIntegrity() {
256
+ const rows = this.#database.prepare("PRAGMA quick_check").all();
257
+ if (rows.length !== 1 || Object.values(rows[0] ?? {}).length !== 1 || Object.values(rows[0] ?? {})[0] !== "ok") {
258
+ throw new Error("pi-fleet database integrity check failed after an unclean shutdown");
259
+ }
260
+ }
214
261
  #migrate() {
215
262
  this.#database.exec("BEGIN IMMEDIATE");
216
263
  try {
@@ -226,13 +273,15 @@ var SqliteFleetStore = class {
226
273
  const newer = applied.find((migration) => migration.version > latestSupported);
227
274
  if (newer !== void 0) {
228
275
  throw new Error(
229
- `Fleet database schema ${String(newer.version)} is newer than this runtime`
276
+ `pi-fleet database schema ${String(newer.version)} is newer than this runtime`
230
277
  );
231
278
  }
232
279
  for (const existing of applied) {
233
280
  const expected = MIGRATIONS.find((migration) => migration.version === existing.version);
234
281
  if (expected === void 0 || expected.checksum !== existing.checksum) {
235
- throw new Error(`Fleet database migration ${String(existing.version)} checksum mismatch`);
282
+ throw new Error(
283
+ `pi-fleet database migration ${String(existing.version)} checksum mismatch`
284
+ );
236
285
  }
237
286
  }
238
287
  for (const migration of MIGRATIONS) {
@@ -291,6 +340,12 @@ async function dispatch(request) {
291
340
  return store.putSend(request.args[0]);
292
341
  case "listNonterminalSends":
293
342
  return store.listNonterminalSends();
343
+ case "getCompact":
344
+ return store.getCompact(request.args[0]);
345
+ case "putCompact":
346
+ return store.putCompact(request.args[0]);
347
+ case "listNonterminalCompacts":
348
+ return store.listNonterminalCompacts();
294
349
  case "putIncarnation":
295
350
  return store.putIncarnation(request.args[0]);
296
351
  case "listActiveIncarnations":
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/store/sqlite-worker.ts", "../src/store/sqlite-store.ts"],
4
- "sourcesContent": ["import { parentPort, workerData } from \"node:worker_threads\";\n\nimport type { StoredAgent, StoredIncarnation, StoredOperation, StoredSend } from \"./fleet-store.js\";\nimport { SqliteFleetStore } from \"./sqlite-store.js\";\n\ninterface WorkerRequest {\n readonly id: string;\n readonly method: string;\n readonly args: readonly unknown[];\n}\n\nconst port = parentPort;\nif (port === null) throw new Error(\"SQLite worker requires a parent port\");\nconst path = (workerData as { path?: unknown }).path;\nif (typeof path !== \"string\") throw new Error(\"SQLite worker requires a database path\");\nconst store = new SqliteFleetStore(path);\n\nport.on(\"message\", (request: WorkerRequest) => {\n void dispatch(request)\n .then((value) => port.postMessage({ id: request.id, ok: true, value }))\n .catch((error: unknown) =>\n port.postMessage({\n id: request.id,\n ok: false,\n error: error instanceof Error ? error.message : \"SQLite worker failed\",\n }),\n );\n});\n\nasync function dispatch(request: WorkerRequest): Promise<unknown> {\n switch (request.method) {\n case \"createAgent\":\n return store.createAgent(request.args[0] as StoredAgent);\n case \"getAgent\":\n return store.getAgent(request.args[0] as string);\n case \"listAgents\":\n return store.listAgents();\n case \"putAgent\":\n return store.putAgent(request.args[0] as StoredAgent);\n case \"deleteAgent\":\n return store.deleteAgent(request.args[0] as string);\n case \"getOperation\":\n return store.getOperation(request.args[0] as string);\n case \"putOperation\":\n return store.putOperation(request.args[0] as StoredOperation);\n case \"listPendingOperations\":\n return store.listPendingOperations();\n case \"deleteOperation\":\n return store.deleteOperation(request.args[0] as string);\n case \"getSend\":\n return store.getSend(request.args[0] as string);\n case \"nextSendOrdinal\":\n return store.nextSendOrdinal(request.args[0] as string);\n case \"putSend\":\n return store.putSend(request.args[0] as StoredSend);\n case \"listNonterminalSends\":\n return store.listNonterminalSends();\n case \"putIncarnation\":\n return store.putIncarnation(request.args[0] as StoredIncarnation);\n case \"listActiveIncarnations\":\n return store.listActiveIncarnations();\n case \"close\":\n return store.close(request.args[0] as boolean | undefined);\n default:\n throw new Error(`Unknown SQLite worker method ${request.method}`);\n }\n}\n", "import { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nimport type {\n FleetStore,\n StoredAgent,\n StoredIncarnation,\n StoredOperation,\n StoredSend,\n} from \"./fleet-store.js\";\n\ninterface JsonRow {\n readonly data_json: string;\n}\n\nconst MIGRATIONS = [\n {\n version: 1,\n checksum: \"001_initial_v1\",\n statements: `\n CREATE TABLE runtime_metadata(\n singleton_key INTEGER PRIMARY KEY CHECK(singleton_key = 1),\n clean_shutdown INTEGER NOT NULL CHECK(clean_shutdown IN (0, 1))\n );\n CREATE TABLE agents(\n agent_id TEXT NOT NULL,\n name TEXT PRIMARY KEY,\n state TEXT NOT NULL CHECK(state IN ('restoring','working','idle','failed','destroying')),\n process_state TEXT NOT NULL CHECK(process_state IN ('resident','starting','absent','cleanup_uncertain')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE operations(\n operation_id TEXT PRIMARY KEY,\n method TEXT NOT NULL CHECK(method IN ('create','send','destroy')),\n state TEXT NOT NULL CHECK(state IN ('pending','completed')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE send_records(\n send_id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n state TEXT NOT NULL CHECK(state IN ('pending','dispatching','acknowledged','failed','uncertain')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE incarnations(\n incarnation_id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n pid INTEGER,\n state TEXT NOT NULL CHECK(state IN ('starting','live','stopping','cleanup_uncertain','gone')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n `,\n },\n] as const;\n\nexport class SqliteFleetStore implements FleetStore {\n readonly #database: DatabaseSync;\n #closed = false;\n\n constructor(path: string) {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n this.#database = new DatabaseSync(path);\n this.#database.exec(\n \"PRAGMA foreign_keys=ON; PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL;\",\n );\n try {\n this.#migrate();\n } catch (error: unknown) {\n this.#database.close();\n this.#closed = true;\n throw error;\n }\n const metadata = this.#database\n .prepare(\"SELECT clean_shutdown FROM runtime_metadata WHERE singleton_key = 1\")\n .get() as { clean_shutdown: number } | undefined;\n if (metadata?.clean_shutdown === 0) {\n this.#database.exec(`\n UPDATE agents\n SET state = 'failed', process_state = 'cleanup_uncertain',\n data_json = json_set(data_json,\n '$.summary.state', 'failed',\n '$.summary.process.state', 'cleanup_uncertain',\n '$.summary.error.code',\n CASE WHEN state IN ('working', 'restoring')\n THEN 'runtime_interrupted'\n ELSE 'incarnation_cleanup_uncertain'\n END)\n WHERE process_state IN ('resident', 'starting');\n UPDATE incarnations\n SET state = 'cleanup_uncertain',\n data_json = json_set(data_json, '$.state', 'cleanup_uncertain')\n WHERE state IN ('starting', 'live', 'stopping');\n `);\n } else if (metadata?.clean_shutdown === 1) {\n this.#database.exec(`\n UPDATE agents\n SET state = CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,\n process_state = 'absent',\n data_json = json_set(data_json,\n '$.summary.state', CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,\n '$.summary.process.state', 'absent')\n WHERE process_state IN ('resident', 'starting');\n UPDATE incarnations\n SET state = 'gone', data_json = json_set(data_json, '$.state', 'gone')\n WHERE state IN ('starting', 'live', 'stopping');\n `);\n }\n this.#database\n .prepare(\n `INSERT INTO runtime_metadata(singleton_key, clean_shutdown)\n VALUES(1, 0)\n ON CONFLICT(singleton_key) DO UPDATE SET clean_shutdown = 0`,\n )\n .run();\n }\n\n async createAgent(agent: StoredAgent): Promise<boolean> {\n const result = this.#database\n .prepare(\n `INSERT OR IGNORE INTO agents(agent_id, name, state, process_state, data_json)\n VALUES(?, ?, ?, ?, ?)`,\n )\n .run(\n agent.summary.id,\n agent.summary.name,\n agent.summary.state,\n agent.summary.process.state,\n JSON.stringify(agent),\n );\n return result.changes === 1;\n }\n\n async getAgent(name: string): Promise<StoredAgent | null> {\n const row = this.#database.prepare(\"SELECT data_json FROM agents WHERE name = ?\").get(name) as\n | JsonRow\n | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredAgent);\n }\n\n async listAgents(): Promise<readonly StoredAgent[]> {\n const rows = this.#database\n .prepare(\"SELECT data_json FROM agents ORDER BY name\")\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredAgent);\n }\n\n async putAgent(agent: StoredAgent): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO agents(agent_id, name, state, process_state, data_json)\n VALUES(?, ?, ?, ?, ?)\n ON CONFLICT(name) DO UPDATE SET\n agent_id=excluded.agent_id,\n state=excluded.state,\n process_state=excluded.process_state,\n data_json=excluded.data_json`,\n )\n .run(\n agent.summary.id,\n agent.summary.name,\n agent.summary.state,\n agent.summary.process.state,\n JSON.stringify(agent),\n );\n }\n\n async deleteAgent(name: string): Promise<StoredAgent | null> {\n const existing = await this.getAgent(name);\n if (existing !== null) this.#database.prepare(\"DELETE FROM agents WHERE name = ?\").run(name);\n return existing;\n }\n\n async getOperation(operationId: string): Promise<StoredOperation | null> {\n const row = this.#database\n .prepare(\"SELECT data_json FROM operations WHERE operation_id = ?\")\n .get(operationId) as JsonRow | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredOperation);\n }\n\n async putOperation(operation: StoredOperation): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO operations(operation_id, method, state, data_json)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(operation_id) DO UPDATE SET\n method=excluded.method, state=excluded.state, data_json=excluded.data_json`,\n )\n .run(operation.operationId, operation.method, operation.state, JSON.stringify(operation));\n }\n\n async listPendingOperations(): Promise<readonly StoredOperation[]> {\n const rows = this.#database\n .prepare(\"SELECT data_json FROM operations WHERE state = 'pending'\")\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredOperation);\n }\n\n async deleteOperation(operationId: string): Promise<void> {\n this.#database.prepare(\"DELETE FROM operations WHERE operation_id = ?\").run(operationId);\n }\n\n async getSend(sendId: string): Promise<StoredSend | null> {\n const row = this.#database\n .prepare(\"SELECT data_json FROM send_records WHERE send_id = ?\")\n .get(sendId) as JsonRow | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredSend);\n }\n\n async nextSendOrdinal(agentName: string): Promise<number> {\n const row = this.#database\n .prepare(\n `SELECT COALESCE(MAX(CAST(json_extract(data_json, '$.ordinal') AS INTEGER)), 0) + 1 AS ordinal\n FROM send_records WHERE agent_name = ?`,\n )\n .get(agentName) as { readonly ordinal: number };\n return row.ordinal;\n }\n\n async putSend(send: StoredSend): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO send_records(send_id, agent_name, state, data_json)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(send_id) DO UPDATE SET state=excluded.state, data_json=excluded.data_json`,\n )\n .run(send.sendId, send.agentName, send.state, JSON.stringify(send));\n }\n\n async listNonterminalSends(): Promise<readonly StoredSend[]> {\n const rows = this.#database\n .prepare(\n `SELECT data_json FROM send_records WHERE state IN ('pending', 'dispatching')\n ORDER BY agent_name, COALESCE(CAST(json_extract(data_json, '$.ordinal') AS INTEGER), 0), rowid`,\n )\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredSend);\n }\n\n async putIncarnation(incarnation: StoredIncarnation): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO incarnations(incarnation_id, agent_name, pid, state, data_json)\n VALUES(?, ?, ?, ?, ?)\n ON CONFLICT(incarnation_id) DO UPDATE SET\n pid=excluded.pid, state=excluded.state, data_json=excluded.data_json`,\n )\n .run(\n incarnation.incarnationId,\n incarnation.agentName,\n incarnation.pid,\n incarnation.state,\n JSON.stringify(incarnation),\n );\n }\n\n async listActiveIncarnations(): Promise<readonly StoredIncarnation[]> {\n const rows = this.#database\n .prepare(\n \"SELECT data_json FROM incarnations WHERE state IN ('starting','live','stopping','cleanup_uncertain')\",\n )\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredIncarnation);\n }\n\n async close(cleanShutdown = true): Promise<void> {\n if (this.#closed) return;\n this.#database\n .prepare(\"UPDATE runtime_metadata SET clean_shutdown = ? WHERE singleton_key = 1\")\n .run(cleanShutdown ? 1 : 0);\n this.#database.close();\n this.#closed = true;\n }\n\n #migrate(): void {\n this.#database.exec(\"BEGIN IMMEDIATE\");\n try {\n this.#database.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations(\n version INTEGER PRIMARY KEY,\n checksum TEXT NOT NULL,\n applied_at TEXT NOT NULL\n );\n `);\n const applied = this.#database\n .prepare(\"SELECT version, checksum FROM schema_migrations ORDER BY version\")\n .all() as unknown as { readonly version: number; readonly checksum: string }[];\n const latestSupported = MIGRATIONS.at(-1)?.version ?? 0;\n const newer = applied.find((migration) => migration.version > latestSupported);\n if (newer !== undefined) {\n throw new Error(\n `Fleet database schema ${String(newer.version)} is newer than this runtime`,\n );\n }\n for (const existing of applied) {\n const expected = MIGRATIONS.find((migration) => migration.version === existing.version);\n if (expected === undefined || expected.checksum !== existing.checksum) {\n throw new Error(`Fleet database migration ${String(existing.version)} checksum mismatch`);\n }\n }\n for (const migration of MIGRATIONS) {\n if (applied.some((existing) => existing.version === migration.version)) continue;\n this.#database.exec(migration.statements);\n this.#database\n .prepare(\"INSERT INTO schema_migrations(version, checksum, applied_at) VALUES(?, ?, ?)\")\n .run(migration.version, migration.checksum, new Date().toISOString());\n }\n this.#database.exec(\"COMMIT\");\n } catch (error: unknown) {\n this.#database.exec(\"ROLLBACK\");\n throw error;\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { parentPort, workerData } from \"node:worker_threads\";\n\nimport type {\n StoredAgent,\n StoredCompact,\n StoredIncarnation,\n StoredOperation,\n StoredSend,\n} from \"./fleet-store.js\";\nimport { SqliteFleetStore } from \"./sqlite-store.js\";\n\ninterface WorkerRequest {\n readonly id: string;\n readonly method: string;\n readonly args: readonly unknown[];\n}\n\nconst port = parentPort;\nif (port === null) throw new Error(\"SQLite worker requires a parent port\");\nconst path = (workerData as { path?: unknown }).path;\nif (typeof path !== \"string\") throw new Error(\"SQLite worker requires a database path\");\nconst store = new SqliteFleetStore(path);\n\nport.on(\"message\", (request: WorkerRequest) => {\n void dispatch(request)\n .then((value) => port.postMessage({ id: request.id, ok: true, value }))\n .catch((error: unknown) =>\n port.postMessage({\n id: request.id,\n ok: false,\n error: error instanceof Error ? error.message : \"SQLite worker failed\",\n }),\n );\n});\n\nasync function dispatch(request: WorkerRequest): Promise<unknown> {\n switch (request.method) {\n case \"createAgent\":\n return store.createAgent(request.args[0] as StoredAgent);\n case \"getAgent\":\n return store.getAgent(request.args[0] as string);\n case \"listAgents\":\n return store.listAgents();\n case \"putAgent\":\n return store.putAgent(request.args[0] as StoredAgent);\n case \"deleteAgent\":\n return store.deleteAgent(request.args[0] as string);\n case \"getOperation\":\n return store.getOperation(request.args[0] as string);\n case \"putOperation\":\n return store.putOperation(request.args[0] as StoredOperation);\n case \"listPendingOperations\":\n return store.listPendingOperations();\n case \"deleteOperation\":\n return store.deleteOperation(request.args[0] as string);\n case \"getSend\":\n return store.getSend(request.args[0] as string);\n case \"nextSendOrdinal\":\n return store.nextSendOrdinal(request.args[0] as string);\n case \"putSend\":\n return store.putSend(request.args[0] as StoredSend);\n case \"listNonterminalSends\":\n return store.listNonterminalSends();\n case \"getCompact\":\n return store.getCompact(request.args[0] as string);\n case \"putCompact\":\n return store.putCompact(request.args[0] as StoredCompact);\n case \"listNonterminalCompacts\":\n return store.listNonterminalCompacts();\n case \"putIncarnation\":\n return store.putIncarnation(request.args[0] as StoredIncarnation);\n case \"listActiveIncarnations\":\n return store.listActiveIncarnations();\n case \"close\":\n return store.close(request.args[0] as boolean | undefined);\n default:\n throw new Error(`Unknown SQLite worker method ${request.method}`);\n }\n}\n", "import { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nimport type {\n FleetStore,\n StoredAgent,\n StoredCompact,\n StoredIncarnation,\n StoredOperation,\n StoredSend,\n} from \"./fleet-store.js\";\n\ninterface JsonRow {\n readonly data_json: string;\n}\n\nconst MIGRATIONS = [\n {\n version: 1,\n checksum: \"001_initial_v1\",\n statements: `\n CREATE TABLE runtime_metadata(\n singleton_key INTEGER PRIMARY KEY CHECK(singleton_key = 1),\n clean_shutdown INTEGER NOT NULL CHECK(clean_shutdown IN (0, 1))\n );\n CREATE TABLE agents(\n agent_id TEXT NOT NULL,\n name TEXT PRIMARY KEY,\n state TEXT NOT NULL CHECK(state IN ('restoring','working','idle','failed','destroying')),\n process_state TEXT NOT NULL CHECK(process_state IN ('resident','starting','absent','cleanup_uncertain')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE operations(\n operation_id TEXT PRIMARY KEY,\n method TEXT NOT NULL CHECK(method IN ('create','send','destroy')),\n state TEXT NOT NULL CHECK(state IN ('pending','completed')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE send_records(\n send_id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n state TEXT NOT NULL CHECK(state IN ('pending','dispatching','acknowledged','failed','uncertain')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE TABLE incarnations(\n incarnation_id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n pid INTEGER,\n state TEXT NOT NULL CHECK(state IN ('starting','live','stopping','cleanup_uncertain','gone')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n `,\n },\n {\n version: 2,\n checksum: \"002_compact_v1\",\n statements: `\n ALTER TABLE operations RENAME TO operations_v1;\n CREATE TABLE operations(\n operation_id TEXT PRIMARY KEY,\n method TEXT NOT NULL CHECK(method IN ('create','send','destroy','compact')),\n state TEXT NOT NULL CHECK(state IN ('pending','completed')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n INSERT INTO operations(operation_id, method, state, data_json)\n SELECT operation_id, method, state, data_json FROM operations_v1;\n DROP TABLE operations_v1;\n CREATE TABLE compact_records(\n compact_id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n state TEXT NOT NULL CHECK(state IN ('pending','dispatching','completed','failed','uncertain')),\n data_json TEXT NOT NULL CHECK(json_valid(data_json))\n );\n CREATE INDEX compact_records_nonterminal ON compact_records(state, agent_name);\n `,\n },\n] as const;\n\nexport class SqliteFleetStore implements FleetStore {\n readonly #database: DatabaseSync;\n #closed = false;\n\n constructor(path: string) {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n this.#database = new DatabaseSync(path);\n this.#database.exec(\n \"PRAGMA foreign_keys=ON; PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL;\",\n );\n try {\n this.#migrate();\n const metadata = this.#database\n .prepare(\"SELECT clean_shutdown FROM runtime_metadata WHERE singleton_key = 1\")\n .get() as { clean_shutdown: number } | undefined;\n if (metadata?.clean_shutdown === 0) {\n this.#verifyIntegrity();\n this.#database.exec(`\n UPDATE agents\n SET state = 'failed', process_state = 'cleanup_uncertain',\n data_json = json_set(data_json,\n '$.summary.state', 'failed',\n '$.summary.process.state', 'cleanup_uncertain',\n '$.summary.error.code',\n CASE WHEN state IN ('working', 'restoring')\n THEN 'runtime_interrupted'\n ELSE 'incarnation_cleanup_uncertain'\n END)\n WHERE process_state IN ('resident', 'starting');\n UPDATE incarnations\n SET state = 'cleanup_uncertain',\n data_json = json_set(data_json, '$.state', 'cleanup_uncertain')\n WHERE state IN ('starting', 'live', 'stopping');\n `);\n } else if (metadata?.clean_shutdown === 1) {\n this.#database.exec(`\n UPDATE agents\n SET state = CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,\n process_state = 'absent',\n data_json = json_set(data_json,\n '$.summary.state', CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,\n '$.summary.process.state', 'absent')\n WHERE process_state IN ('resident', 'starting');\n UPDATE incarnations\n SET state = 'gone', data_json = json_set(data_json, '$.state', 'gone')\n WHERE state IN ('starting', 'live', 'stopping');\n `);\n }\n this.#database\n .prepare(\n `INSERT INTO runtime_metadata(singleton_key, clean_shutdown)\n VALUES(1, 0)\n ON CONFLICT(singleton_key) DO UPDATE SET clean_shutdown = 0`,\n )\n .run();\n } catch (error: unknown) {\n this.#database.close();\n this.#closed = true;\n throw error;\n }\n }\n\n async createAgent(agent: StoredAgent): Promise<boolean> {\n const result = this.#database\n .prepare(\n `INSERT OR IGNORE INTO agents(agent_id, name, state, process_state, data_json)\n VALUES(?, ?, ?, ?, ?)`,\n )\n .run(\n agent.summary.id,\n agent.summary.name,\n agent.summary.state,\n agent.summary.process.state,\n JSON.stringify(agent),\n );\n return result.changes === 1;\n }\n\n async getAgent(name: string): Promise<StoredAgent | null> {\n const row = this.#database.prepare(\"SELECT data_json FROM agents WHERE name = ?\").get(name) as\n | JsonRow\n | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredAgent);\n }\n\n async listAgents(): Promise<readonly StoredAgent[]> {\n const rows = this.#database\n .prepare(\"SELECT data_json FROM agents ORDER BY name\")\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredAgent);\n }\n\n async putAgent(agent: StoredAgent): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO agents(agent_id, name, state, process_state, data_json)\n VALUES(?, ?, ?, ?, ?)\n ON CONFLICT(name) DO UPDATE SET\n agent_id=excluded.agent_id,\n state=excluded.state,\n process_state=excluded.process_state,\n data_json=excluded.data_json`,\n )\n .run(\n agent.summary.id,\n agent.summary.name,\n agent.summary.state,\n agent.summary.process.state,\n JSON.stringify(agent),\n );\n }\n\n async deleteAgent(name: string): Promise<StoredAgent | null> {\n const existing = await this.getAgent(name);\n if (existing !== null) this.#database.prepare(\"DELETE FROM agents WHERE name = ?\").run(name);\n return existing;\n }\n\n async getOperation(operationId: string): Promise<StoredOperation | null> {\n const row = this.#database\n .prepare(\"SELECT data_json FROM operations WHERE operation_id = ?\")\n .get(operationId) as JsonRow | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredOperation);\n }\n\n async putOperation(operation: StoredOperation): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO operations(operation_id, method, state, data_json)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(operation_id) DO UPDATE SET\n method=excluded.method, state=excluded.state, data_json=excluded.data_json`,\n )\n .run(operation.operationId, operation.method, operation.state, JSON.stringify(operation));\n }\n\n async listPendingOperations(): Promise<readonly StoredOperation[]> {\n const rows = this.#database\n .prepare(\"SELECT data_json FROM operations WHERE state = 'pending'\")\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredOperation);\n }\n\n async deleteOperation(operationId: string): Promise<void> {\n this.#database.prepare(\"DELETE FROM operations WHERE operation_id = ?\").run(operationId);\n }\n\n async getSend(sendId: string): Promise<StoredSend | null> {\n const row = this.#database\n .prepare(\"SELECT data_json FROM send_records WHERE send_id = ?\")\n .get(sendId) as JsonRow | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredSend);\n }\n\n async nextSendOrdinal(agentName: string): Promise<number> {\n const row = this.#database\n .prepare(\n `SELECT COALESCE(MAX(CAST(json_extract(data_json, '$.ordinal') AS INTEGER)), 0) + 1 AS ordinal\n FROM send_records WHERE agent_name = ?`,\n )\n .get(agentName) as { readonly ordinal: number };\n return row.ordinal;\n }\n\n async putSend(send: StoredSend): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO send_records(send_id, agent_name, state, data_json)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(send_id) DO UPDATE SET state=excluded.state, data_json=excluded.data_json`,\n )\n .run(send.sendId, send.agentName, send.state, JSON.stringify(send));\n }\n\n async listNonterminalSends(): Promise<readonly StoredSend[]> {\n const rows = this.#database\n .prepare(\n `SELECT data_json FROM send_records WHERE state IN ('pending', 'dispatching')\n ORDER BY agent_name, COALESCE(CAST(json_extract(data_json, '$.ordinal') AS INTEGER), 0), rowid`,\n )\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredSend);\n }\n\n async getCompact(compactId: string): Promise<StoredCompact | null> {\n const row = this.#database\n .prepare(\"SELECT data_json FROM compact_records WHERE compact_id = ?\")\n .get(compactId) as JsonRow | undefined;\n return row === undefined ? null : (JSON.parse(row.data_json) as StoredCompact);\n }\n\n async putCompact(compact: StoredCompact): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO compact_records(compact_id, agent_name, state, data_json)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(compact_id) DO UPDATE SET state=excluded.state, data_json=excluded.data_json`,\n )\n .run(compact.compactId, compact.agentName, compact.state, JSON.stringify(compact));\n }\n\n async listNonterminalCompacts(): Promise<readonly StoredCompact[]> {\n const rows = this.#database\n .prepare(\n \"SELECT data_json FROM compact_records WHERE state IN ('pending','dispatching') ORDER BY rowid\",\n )\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredCompact);\n }\n\n async putIncarnation(incarnation: StoredIncarnation): Promise<void> {\n this.#database\n .prepare(\n `INSERT INTO incarnations(incarnation_id, agent_name, pid, state, data_json)\n VALUES(?, ?, ?, ?, ?)\n ON CONFLICT(incarnation_id) DO UPDATE SET\n pid=excluded.pid, state=excluded.state, data_json=excluded.data_json`,\n )\n .run(\n incarnation.incarnationId,\n incarnation.agentName,\n incarnation.pid,\n incarnation.state,\n JSON.stringify(incarnation),\n );\n }\n\n async listActiveIncarnations(): Promise<readonly StoredIncarnation[]> {\n const rows = this.#database\n .prepare(\n \"SELECT data_json FROM incarnations WHERE state IN ('starting','live','stopping','cleanup_uncertain')\",\n )\n .all() as unknown as JsonRow[];\n return rows.map((row) => JSON.parse(row.data_json) as StoredIncarnation);\n }\n\n async close(cleanShutdown = true): Promise<void> {\n if (this.#closed) return;\n this.#database\n .prepare(\"UPDATE runtime_metadata SET clean_shutdown = ? WHERE singleton_key = 1\")\n .run(cleanShutdown ? 1 : 0);\n this.#database.close();\n this.#closed = true;\n }\n\n #verifyIntegrity(): void {\n const rows = this.#database.prepare(\"PRAGMA quick_check\").all() as unknown as Array<\n Record<string, unknown>\n >;\n if (\n rows.length !== 1 ||\n Object.values(rows[0] ?? {}).length !== 1 ||\n Object.values(rows[0] ?? {})[0] !== \"ok\"\n ) {\n throw new Error(\"pi-fleet database integrity check failed after an unclean shutdown\");\n }\n }\n\n #migrate(): void {\n this.#database.exec(\"BEGIN IMMEDIATE\");\n try {\n this.#database.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations(\n version INTEGER PRIMARY KEY,\n checksum TEXT NOT NULL,\n applied_at TEXT NOT NULL\n );\n `);\n const applied = this.#database\n .prepare(\"SELECT version, checksum FROM schema_migrations ORDER BY version\")\n .all() as unknown as { readonly version: number; readonly checksum: string }[];\n const latestSupported = MIGRATIONS.at(-1)?.version ?? 0;\n const newer = applied.find((migration) => migration.version > latestSupported);\n if (newer !== undefined) {\n throw new Error(\n `pi-fleet database schema ${String(newer.version)} is newer than this runtime`,\n );\n }\n for (const existing of applied) {\n const expected = MIGRATIONS.find((migration) => migration.version === existing.version);\n if (expected === undefined || expected.checksum !== existing.checksum) {\n throw new Error(\n `pi-fleet database migration ${String(existing.version)} checksum mismatch`,\n );\n }\n }\n for (const migration of MIGRATIONS) {\n if (applied.some((existing) => existing.version === migration.version)) continue;\n this.#database.exec(migration.statements);\n this.#database\n .prepare(\"INSERT INTO schema_migrations(version, checksum, applied_at) VALUES(?, ?, ?)\")\n .run(migration.version, migration.checksum, new Date().toISOString());\n }\n this.#database.exec(\"COMMIT\");\n } catch (error: unknown) {\n this.#database.exec(\"ROLLBACK\");\n throw error;\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path"]
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elpapi42/pi-fleet",
3
- "version": "0.1.0-beta.0",
4
- "description": "A local runtime and machine-first CLI for named Pi agents",
3
+ "version": "0.1.0-beta.10",
4
+ "description": "Pi-native execution infrastructure for programmatic agent orchestration",
5
5
  "license": "MIT",
6
6
  "author": "elpapi42",
7
7
  "keywords": [
@@ -9,7 +9,10 @@
9
9
  "agents",
10
10
  "cli",
11
11
  "runtime",
12
- "automation"
12
+ "automation",
13
+ "orchestration",
14
+ "infrastructure",
15
+ "jsonl"
13
16
  ],
14
17
  "repository": {
15
18
  "type": "git",
@@ -43,14 +46,18 @@
43
46
  "pretest": "npm run build",
44
47
  "test": "vitest run",
45
48
  "test:integration": "vitest run test/integration --maxWorkers=1",
49
+ "test:faults": "npm run build && vitest run test/faults --maxWorkers=1",
46
50
  "test:process": "vitest run test/process --maxWorkers=1",
47
51
  "test:package": "npm run build && vitest run test/package --maxWorkers=1",
48
52
  "test:platform": "vitest run test/integration/service-installer.test.ts test/process/process-tree.test.ts --maxWorkers=1",
49
53
  "test:compat": "vitest run test/compat --maxWorkers=1",
54
+ "test:version-matrix": "npm run build && VITEST_VERSION_MATRIX=1 vitest run test/package/runtime-version-matrix.test.ts --maxWorkers=1",
55
+ "test:soak": "vitest run --config vitest.soak.config.ts --maxWorkers=1",
50
56
  "probe:pi": "node scripts/pi-compatibility-probe.mts",
51
57
  "benchmark:store": "npm run build && vitest run --config vitest.benchmark.config.ts",
52
58
  "build": "node scripts/build.mjs",
53
- "release:check": "node scripts/check-release.mjs"
59
+ "release:check": "node scripts/check-release.mjs",
60
+ "audit:production": "node scripts/check-production-audit.mjs"
54
61
  },
55
62
  "files": [
56
63
  "bin/",
@@ -70,7 +77,6 @@
70
77
  "vitest": "4.1.10"
71
78
  },
72
79
  "dependencies": {
73
- "@earendil-works/pi-coding-agent": "0.80.10",
74
80
  "@sinclair/typebox": "0.34.52",
75
81
  "commander": "15.0.0"
76
82
  }