@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.
- package/CHANGELOG.md +162 -3
- package/README.md +170 -104
- package/bin/pifleet-runtime.mjs +1 -1
- package/dist/cli-meta.json +5464 -82
- package/dist/cli.mjs +3481 -253
- package/dist/cli.mjs.map +4 -4
- package/dist/installer-meta.json +87 -13
- package/dist/installer.mjs +555 -95
- package/dist/installer.mjs.map +4 -4
- package/dist/runtime-manifest.json +37 -43
- package/dist/runtime-meta.json +2976 -2868
- package/dist/runtime.mjs +6316 -5247
- package/dist/runtime.mjs.map +4 -4
- package/dist/sqlite-worker-meta.json +6 -6
- package/dist/sqlite-worker.mjs +95 -40
- package/dist/sqlite-worker.mjs.map +2 -2
- package/package.json +11 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"inputs": {
|
|
3
3
|
"src/store/sqlite-store.ts": {
|
|
4
|
-
"bytes":
|
|
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":
|
|
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":
|
|
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":
|
|
75
|
+
"bytesInOutput": 2152
|
|
76
76
|
},
|
|
77
77
|
"src/store/sqlite-store.ts": {
|
|
78
|
-
"bytesInOutput":
|
|
78
|
+
"bytesInOutput": 12211
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
|
-
"bytes":
|
|
81
|
+
"bytes": 14497
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}
|
package/dist/sqlite-worker.mjs
CHANGED
|
@@ -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
|
-
`
|
|
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(
|
|
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": ";AAAA,SAAS,YAAY,kBAAkB;;;ACAvC,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,oBAAoB;
|
|
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.
|
|
4
|
-
"description": "
|
|
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
|
}
|