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

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": 12055,
5
5
  "imports": [
6
6
  {
7
7
  "path": "node:fs",
@@ -43,7 +43,7 @@
43
43
  "imports": [],
44
44
  "exports": [],
45
45
  "inputs": {},
46
- "bytes": 20305
46
+ "bytes": 21104
47
47
  },
48
48
  "dist/sqlite-worker.mjs": {
49
49
  "imports": [
@@ -75,10 +75,10 @@
75
75
  "bytesInOutput": 1928
76
76
  },
77
77
  "src/store/sqlite-store.ts": {
78
- "bytesInOutput": 9965
78
+ "bytesInOutput": 10384
79
79
  }
80
80
  },
81
- "bytes": 12027
81
+ "bytes": 12446
82
82
  }
83
83
  }
84
84
  }
@@ -54,49 +54,50 @@ var SqliteFleetStore = class {
54
54
  );
55
55
  try {
56
56
  this.#migrate();
57
+ const metadata = this.#database.prepare("SELECT clean_shutdown FROM runtime_metadata WHERE singleton_key = 1").get();
58
+ if (metadata?.clean_shutdown === 0) {
59
+ this.#verifyIntegrity();
60
+ this.#database.exec(`
61
+ UPDATE agents
62
+ SET state = 'failed', process_state = 'cleanup_uncertain',
63
+ data_json = json_set(data_json,
64
+ '$.summary.state', 'failed',
65
+ '$.summary.process.state', 'cleanup_uncertain',
66
+ '$.summary.error.code',
67
+ CASE WHEN state IN ('working', 'restoring')
68
+ THEN 'runtime_interrupted'
69
+ ELSE 'incarnation_cleanup_uncertain'
70
+ END)
71
+ WHERE process_state IN ('resident', 'starting');
72
+ UPDATE incarnations
73
+ SET state = 'cleanup_uncertain',
74
+ data_json = json_set(data_json, '$.state', 'cleanup_uncertain')
75
+ WHERE state IN ('starting', 'live', 'stopping');
76
+ `);
77
+ } else if (metadata?.clean_shutdown === 1) {
78
+ this.#database.exec(`
79
+ UPDATE agents
80
+ SET state = CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
81
+ process_state = 'absent',
82
+ data_json = json_set(data_json,
83
+ '$.summary.state', CASE WHEN state = 'idle' THEN 'idle' ELSE 'failed' END,
84
+ '$.summary.process.state', 'absent')
85
+ WHERE process_state IN ('resident', 'starting');
86
+ UPDATE incarnations
87
+ SET state = 'gone', data_json = json_set(data_json, '$.state', 'gone')
88
+ WHERE state IN ('starting', 'live', 'stopping');
89
+ `);
90
+ }
91
+ this.#database.prepare(
92
+ `INSERT INTO runtime_metadata(singleton_key, clean_shutdown)
93
+ VALUES(1, 0)
94
+ ON CONFLICT(singleton_key) DO UPDATE SET clean_shutdown = 0`
95
+ ).run();
57
96
  } catch (error) {
58
97
  this.#database.close();
59
98
  this.#closed = true;
60
99
  throw error;
61
100
  }
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
101
  }
101
102
  async createAgent(agent) {
102
103
  const result = this.#database.prepare(
@@ -211,6 +212,12 @@ var SqliteFleetStore = class {
211
212
  this.#database.close();
212
213
  this.#closed = true;
213
214
  }
215
+ #verifyIntegrity() {
216
+ const rows = this.#database.prepare("PRAGMA quick_check").all();
217
+ if (rows.length !== 1 || Object.values(rows[0] ?? {}).length !== 1 || Object.values(rows[0] ?? {})[0] !== "ok") {
218
+ throw new Error("Fleet database integrity check failed after an unclean shutdown");
219
+ }
220
+ }
214
221
  #migrate() {
215
222
  this.#database.exec("BEGIN IMMEDIATE");
216
223
  try {
@@ -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 { 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 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 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(\"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 `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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",
6
6
  "names": ["path"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elpapi42/pi-fleet",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "A local runtime and machine-first CLI for named Pi agents",
5
5
  "license": "MIT",
6
6
  "author": "elpapi42",
@@ -43,10 +43,13 @@
43
43
  "pretest": "npm run build",
44
44
  "test": "vitest run",
45
45
  "test:integration": "vitest run test/integration --maxWorkers=1",
46
+ "test:faults": "npm run build && vitest run test/faults --maxWorkers=1",
46
47
  "test:process": "vitest run test/process --maxWorkers=1",
47
48
  "test:package": "npm run build && vitest run test/package --maxWorkers=1",
48
49
  "test:platform": "vitest run test/integration/service-installer.test.ts test/process/process-tree.test.ts --maxWorkers=1",
49
50
  "test:compat": "vitest run test/compat --maxWorkers=1",
51
+ "test:version-matrix": "npm run build && VITEST_VERSION_MATRIX=1 vitest run test/package/runtime-version-matrix.test.ts --maxWorkers=1",
52
+ "test:soak": "vitest run --config vitest.soak.config.ts --maxWorkers=1",
50
53
  "probe:pi": "node scripts/pi-compatibility-probe.mts",
51
54
  "benchmark:store": "npm run build && vitest run --config vitest.benchmark.config.ts",
52
55
  "build": "node scripts/build.mjs",