patchwork-os 1.2.0-beta.2.canary.603 → 1.2.0-beta.2.canary.604
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ patchwork-os init
|
|
|
62
62
|
|
|
63
63
|
`init` scaffolds `~/.patchwork`, seeds local-only recipes, and registers Patchwork's PreToolUse hook in `~/.claude/settings.json`. Restart Claude Code afterwards — it reads hooks at session start.
|
|
64
64
|
|
|
65
|
-
**Prereqs:** Node 22+. macOS, Linux, and native Windows (no WSL).
|
|
65
|
+
**Prereqs:** Node 22.5+. macOS, Linux, and native Windows (no WSL).
|
|
66
66
|
|
|
67
67
|
Two things worth knowing before you start:
|
|
68
68
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SQLite run store — ADR-0022.
|
|
3
|
+
*
|
|
4
|
+
* Held to the SAME contract as the JSONL incumbent
|
|
5
|
+
* (`describeRunRepositoryContract`), which is the entire point: the migration's
|
|
6
|
+
* safety argument is "this behaves like the store we already trust", and that
|
|
7
|
+
* is only checkable if one set of assertions covers both.
|
|
8
|
+
*
|
|
9
|
+
* ## Why SQLite at all
|
|
10
|
+
*
|
|
11
|
+
* `runs.jsonl` is the autonomy gate's trust evidence and an append-only text
|
|
12
|
+
* file with no integrity properties. It failed three ways in eight weeks, each
|
|
13
|
+
* silently — #1324 (`seq` collides across processes), #1340 (in-flight steps
|
|
14
|
+
* never written), #1341 (a concurrent reader made `completeRun` a no-op). The
|
|
15
|
+
* fixes grew a file lock, byte AND line caps, an archive tier and an upsert
|
|
16
|
+
* reconciliation path into `runLog.ts`: a database, reimplemented, losing.
|
|
17
|
+
* `runLog.ts:753` documents a lost write we chose to live with.
|
|
18
|
+
*
|
|
19
|
+
* ## Identity
|
|
20
|
+
*
|
|
21
|
+
* `task_id` is the PRIMARY KEY, not `seq`. That is the #1324 fix landing as a
|
|
22
|
+
* schema constraint rather than a convention: `seq` is a PER-INSTANCE counter
|
|
23
|
+
* handed out by eight construction sites, so 142 of 145 seqs in the live log
|
|
24
|
+
* were shared by unrelated runs. Here the database refuses to store two runs
|
|
25
|
+
* under one identity, instead of a reader silently discarding one.
|
|
26
|
+
*
|
|
27
|
+
* `seq` is still carried, still per-instance, and `getBySeq` is still
|
|
28
|
+
* ambiguous — preserved deliberately, because a migration that also changes the
|
|
29
|
+
* domain model cannot be verified by comparing old against new. #1360 fixes
|
|
30
|
+
* that separately, once the stores agree.
|
|
31
|
+
*
|
|
32
|
+
* ## What is NOT here
|
|
33
|
+
*
|
|
34
|
+
* No byte cap, no line cap, no rotation, no archive tier. Retention becomes a
|
|
35
|
+
* policy decision against a queryable store rather than a byte budget fighting
|
|
36
|
+
* a 24-hour durability window — which is the collision that starved the trust
|
|
37
|
+
* ledger. Nothing calls this yet; dual-write and shadow-read come next.
|
|
38
|
+
*/
|
|
39
|
+
import type { Logger } from "../logger.js";
|
|
40
|
+
import type { RecipeRun, RunQuery, RunStepResult } from "../runLog.js";
|
|
41
|
+
import type { CompleteRunInput, RunRepository, StartRunInput } from "./runRepository.js";
|
|
42
|
+
export interface SqliteRunStoreOptions {
|
|
43
|
+
/** Directory holding runs.db. Created if missing. */
|
|
44
|
+
dir: string;
|
|
45
|
+
logger?: Logger;
|
|
46
|
+
/** Test hook — default Date.now. */
|
|
47
|
+
now?: () => number;
|
|
48
|
+
/** Test seam for liveness. Default: real process check. */
|
|
49
|
+
isAlive?: (pid: number | undefined) => boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare class SqliteRunRepository implements RunRepository {
|
|
52
|
+
private readonly opts;
|
|
53
|
+
private readonly db;
|
|
54
|
+
private readonly now;
|
|
55
|
+
private readonly isAlive;
|
|
56
|
+
private seq;
|
|
57
|
+
private closed;
|
|
58
|
+
constructor(opts: SqliteRunStoreOptions);
|
|
59
|
+
/**
|
|
60
|
+
* Release the database handle. Idempotent, and never throws.
|
|
61
|
+
*
|
|
62
|
+
* Callers close defensively (teardown paths, error paths, a shutdown that
|
|
63
|
+
* may already have run), and a store whose cleanup can itself fail turns
|
|
64
|
+
* "we tidied up" into a new failure mode. On Windows this is not cosmetic:
|
|
65
|
+
* an open handle prevents the file being unlinked at all.
|
|
66
|
+
*/
|
|
67
|
+
close(): void;
|
|
68
|
+
private maxSeq;
|
|
69
|
+
/**
|
|
70
|
+
* Flip runs whose owning process is provably gone to `interrupted`, folding
|
|
71
|
+
* in the evidence they managed to persist.
|
|
72
|
+
*
|
|
73
|
+
* ONLY when the owner is gone. Running this unconditionally is exactly
|
|
74
|
+
* #1341: a concurrent reader declared a live sibling's runs dead, and because
|
|
75
|
+
* `completeRun` no-ops on a non-running row, the real completion was never
|
|
76
|
+
* written — a successful run recorded `interrupted, steps: 0`.
|
|
77
|
+
*/
|
|
78
|
+
private sweepInterrupted;
|
|
79
|
+
private stepsFor;
|
|
80
|
+
private rowToRun;
|
|
81
|
+
startRun(input: StartRunInput): number;
|
|
82
|
+
/** Resolve a per-instance `seq` to a task id. Ambiguous by construction — see
|
|
83
|
+
* the class docs and #1360. Newest wins, which is the least surprising of
|
|
84
|
+
* several wrong answers. */
|
|
85
|
+
private taskIdForSeq;
|
|
86
|
+
updateRunSteps(seq: number, stepResults: RunStepResult[]): void;
|
|
87
|
+
completeRun(seq: number, input: CompleteRunInput): void;
|
|
88
|
+
query(q?: RunQuery): RecipeRun[];
|
|
89
|
+
getBySeq(seq: number): RecipeRun | null;
|
|
90
|
+
getChildSeqs(parentSeq: number): number[];
|
|
91
|
+
size(): number;
|
|
92
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SQLite run store — ADR-0022.
|
|
3
|
+
*
|
|
4
|
+
* Held to the SAME contract as the JSONL incumbent
|
|
5
|
+
* (`describeRunRepositoryContract`), which is the entire point: the migration's
|
|
6
|
+
* safety argument is "this behaves like the store we already trust", and that
|
|
7
|
+
* is only checkable if one set of assertions covers both.
|
|
8
|
+
*
|
|
9
|
+
* ## Why SQLite at all
|
|
10
|
+
*
|
|
11
|
+
* `runs.jsonl` is the autonomy gate's trust evidence and an append-only text
|
|
12
|
+
* file with no integrity properties. It failed three ways in eight weeks, each
|
|
13
|
+
* silently — #1324 (`seq` collides across processes), #1340 (in-flight steps
|
|
14
|
+
* never written), #1341 (a concurrent reader made `completeRun` a no-op). The
|
|
15
|
+
* fixes grew a file lock, byte AND line caps, an archive tier and an upsert
|
|
16
|
+
* reconciliation path into `runLog.ts`: a database, reimplemented, losing.
|
|
17
|
+
* `runLog.ts:753` documents a lost write we chose to live with.
|
|
18
|
+
*
|
|
19
|
+
* ## Identity
|
|
20
|
+
*
|
|
21
|
+
* `task_id` is the PRIMARY KEY, not `seq`. That is the #1324 fix landing as a
|
|
22
|
+
* schema constraint rather than a convention: `seq` is a PER-INSTANCE counter
|
|
23
|
+
* handed out by eight construction sites, so 142 of 145 seqs in the live log
|
|
24
|
+
* were shared by unrelated runs. Here the database refuses to store two runs
|
|
25
|
+
* under one identity, instead of a reader silently discarding one.
|
|
26
|
+
*
|
|
27
|
+
* `seq` is still carried, still per-instance, and `getBySeq` is still
|
|
28
|
+
* ambiguous — preserved deliberately, because a migration that also changes the
|
|
29
|
+
* domain model cannot be verified by comparing old against new. #1360 fixes
|
|
30
|
+
* that separately, once the stores agree.
|
|
31
|
+
*
|
|
32
|
+
* ## What is NOT here
|
|
33
|
+
*
|
|
34
|
+
* No byte cap, no line cap, no rotation, no archive tier. Retention becomes a
|
|
35
|
+
* policy decision against a queryable store rather than a byte budget fighting
|
|
36
|
+
* a 24-hour durability window — which is the collision that starved the trust
|
|
37
|
+
* ledger. Nothing calls this yet; dual-write and shadow-read come next.
|
|
38
|
+
*/
|
|
39
|
+
import { mkdirSync } from "node:fs";
|
|
40
|
+
import path from "node:path";
|
|
41
|
+
import { DatabaseSync } from "node:sqlite";
|
|
42
|
+
import { isEvidenceBearing } from "../runStepLedger.js";
|
|
43
|
+
/**
|
|
44
|
+
* Is the process that owns a running row still alive?
|
|
45
|
+
*
|
|
46
|
+
* Byte-for-byte the same rule as `runLog.ts`, including its judgement calls:
|
|
47
|
+
* `EPERM` counts as alive (the process exists, it just belongs to someone
|
|
48
|
+
* else), and an ABSENT pid returns false so rows predating `ownerPid` keep
|
|
49
|
+
* being recovered. "We don't know" is not evidence of a live owner.
|
|
50
|
+
*
|
|
51
|
+
* Divergence here would be invisible and would desynchronise the two stores
|
|
52
|
+
* during dual-write in the one area — sweeping live runs — that #1341 proves
|
|
53
|
+
* is dangerous.
|
|
54
|
+
*/
|
|
55
|
+
function defaultIsAlive(pid) {
|
|
56
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
process.kill(pid, 0);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return err?.code === "EPERM";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const SCHEMA = `
|
|
68
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
69
|
+
task_id TEXT PRIMARY KEY,
|
|
70
|
+
seq INTEGER NOT NULL,
|
|
71
|
+
recipe_name TEXT NOT NULL,
|
|
72
|
+
trigger TEXT NOT NULL,
|
|
73
|
+
status TEXT NOT NULL,
|
|
74
|
+
created_at INTEGER NOT NULL,
|
|
75
|
+
started_at INTEGER,
|
|
76
|
+
done_at INTEGER,
|
|
77
|
+
duration_ms INTEGER,
|
|
78
|
+
model TEXT,
|
|
79
|
+
output_tail TEXT,
|
|
80
|
+
error_message TEXT,
|
|
81
|
+
parent_seq INTEGER,
|
|
82
|
+
manual_run_id TEXT,
|
|
83
|
+
owner_pid INTEGER,
|
|
84
|
+
had_step_errors INTEGER,
|
|
85
|
+
step_results TEXT,
|
|
86
|
+
extra TEXT
|
|
87
|
+
);
|
|
88
|
+
CREATE INDEX IF NOT EXISTS runs_created_at ON runs(created_at DESC);
|
|
89
|
+
CREATE INDEX IF NOT EXISTS runs_seq ON runs(seq);
|
|
90
|
+
CREATE INDEX IF NOT EXISTS runs_parent ON runs(parent_seq);
|
|
91
|
+
CREATE INDEX IF NOT EXISTS runs_recipe ON runs(recipe_name);
|
|
92
|
+
|
|
93
|
+
-- In-flight evidence. Separate table for the same reason #1340 used a separate
|
|
94
|
+
-- FILE: these rows arrive per step, and mixing them into the run record made
|
|
95
|
+
-- durability compete with retention.
|
|
96
|
+
CREATE TABLE IF NOT EXISTS run_steps (
|
|
97
|
+
task_id TEXT NOT NULL,
|
|
98
|
+
step_id TEXT NOT NULL,
|
|
99
|
+
at INTEGER NOT NULL,
|
|
100
|
+
step TEXT NOT NULL,
|
|
101
|
+
PRIMARY KEY (task_id, step_id)
|
|
102
|
+
);
|
|
103
|
+
`;
|
|
104
|
+
/** Columns carried verbatim as JSON rather than promoted to columns. Nothing
|
|
105
|
+
* queries them; giving each a column would be schema churn for no reader. */
|
|
106
|
+
const EXTRA_KEYS = [
|
|
107
|
+
"assertionFailures",
|
|
108
|
+
"inboxOutputs",
|
|
109
|
+
"budgetWarnings",
|
|
110
|
+
"tokenTotals",
|
|
111
|
+
"budgetTotals",
|
|
112
|
+
];
|
|
113
|
+
export class SqliteRunRepository {
|
|
114
|
+
opts;
|
|
115
|
+
db;
|
|
116
|
+
now;
|
|
117
|
+
isAlive;
|
|
118
|
+
seq = 0;
|
|
119
|
+
closed = false;
|
|
120
|
+
constructor(opts) {
|
|
121
|
+
this.opts = opts;
|
|
122
|
+
this.now = opts.now ?? Date.now;
|
|
123
|
+
this.isAlive = opts.isAlive ?? defaultIsAlive;
|
|
124
|
+
mkdirSync(opts.dir, { recursive: true, mode: 0o700 });
|
|
125
|
+
this.db = new DatabaseSync(path.join(opts.dir, "runs.db"));
|
|
126
|
+
// WAL: a reader must not block the writer, and vice versa. The whole
|
|
127
|
+
// reason this store exists is that eight construction sites touch one
|
|
128
|
+
// ledger concurrently.
|
|
129
|
+
this.db.exec("PRAGMA journal_mode=WAL");
|
|
130
|
+
this.db.exec("PRAGMA foreign_keys=ON");
|
|
131
|
+
this.db.exec(SCHEMA);
|
|
132
|
+
this.seq = this.maxSeq();
|
|
133
|
+
this.sweepInterrupted();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Release the database handle. Idempotent, and never throws.
|
|
137
|
+
*
|
|
138
|
+
* Callers close defensively (teardown paths, error paths, a shutdown that
|
|
139
|
+
* may already have run), and a store whose cleanup can itself fail turns
|
|
140
|
+
* "we tidied up" into a new failure mode. On Windows this is not cosmetic:
|
|
141
|
+
* an open handle prevents the file being unlinked at all.
|
|
142
|
+
*/
|
|
143
|
+
close() {
|
|
144
|
+
if (this.closed)
|
|
145
|
+
return;
|
|
146
|
+
this.closed = true;
|
|
147
|
+
try {
|
|
148
|
+
this.db.close();
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
this.opts.logger?.warn?.(`[sqlite-runstore] close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
maxSeq() {
|
|
155
|
+
const r = this.db.prepare("SELECT MAX(seq) AS m FROM runs").get();
|
|
156
|
+
return typeof r?.m === "number" ? r.m : 0;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Flip runs whose owning process is provably gone to `interrupted`, folding
|
|
160
|
+
* in the evidence they managed to persist.
|
|
161
|
+
*
|
|
162
|
+
* ONLY when the owner is gone. Running this unconditionally is exactly
|
|
163
|
+
* #1341: a concurrent reader declared a live sibling's runs dead, and because
|
|
164
|
+
* `completeRun` no-ops on a non-running row, the real completion was never
|
|
165
|
+
* written — a successful run recorded `interrupted, steps: 0`.
|
|
166
|
+
*/
|
|
167
|
+
sweepInterrupted() {
|
|
168
|
+
const rows = this.db
|
|
169
|
+
.prepare("SELECT task_id, owner_pid, created_at FROM runs WHERE status='running'")
|
|
170
|
+
.all();
|
|
171
|
+
const now = this.now();
|
|
172
|
+
const flip = this.db.prepare("UPDATE runs SET status='interrupted', done_at=?, duration_ms=?, step_results=? WHERE task_id=?");
|
|
173
|
+
for (const r of rows) {
|
|
174
|
+
const pid = typeof r.owner_pid === "number" ? r.owner_pid : undefined;
|
|
175
|
+
if (this.isAlive(pid))
|
|
176
|
+
continue;
|
|
177
|
+
const taskId = String(r.task_id);
|
|
178
|
+
const createdAt = Number(r.created_at);
|
|
179
|
+
const recovered = this.stepsFor(taskId);
|
|
180
|
+
flip.run(now, now - createdAt, recovered.length > 0 ? JSON.stringify(recovered) : null, taskId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
stepsFor(taskId) {
|
|
184
|
+
const rows = this.db
|
|
185
|
+
.prepare("SELECT step FROM run_steps WHERE task_id=? ORDER BY at ASC, rowid ASC")
|
|
186
|
+
.all(taskId);
|
|
187
|
+
const out = [];
|
|
188
|
+
for (const r of rows) {
|
|
189
|
+
try {
|
|
190
|
+
out.push(JSON.parse(String(r.step)));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// A single unparseable row must not destroy the rest of a run's
|
|
194
|
+
// evidence — the failure mode this whole subsystem exists to prevent.
|
|
195
|
+
this.opts.logger?.warn?.(`[sqlite-runstore] skipping unparseable step row for ${taskId}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
rowToRun(r) {
|
|
201
|
+
const extra = r.extra ? JSON.parse(String(r.extra)) : {};
|
|
202
|
+
const steps = r.step_results
|
|
203
|
+
? JSON.parse(String(r.step_results))
|
|
204
|
+
: undefined;
|
|
205
|
+
const run = {
|
|
206
|
+
seq: Number(r.seq),
|
|
207
|
+
taskId: String(r.task_id),
|
|
208
|
+
recipeName: String(r.recipe_name),
|
|
209
|
+
trigger: String(r.trigger),
|
|
210
|
+
status: String(r.status),
|
|
211
|
+
createdAt: Number(r.created_at),
|
|
212
|
+
doneAt: Number(r.done_at ?? 0),
|
|
213
|
+
durationMs: Number(r.duration_ms ?? 0),
|
|
214
|
+
...(r.started_at != null && { startedAt: Number(r.started_at) }),
|
|
215
|
+
...(r.model != null && { model: String(r.model) }),
|
|
216
|
+
...(r.output_tail != null && { outputTail: String(r.output_tail) }),
|
|
217
|
+
...(r.error_message != null && { errorMessage: String(r.error_message) }),
|
|
218
|
+
...(r.parent_seq != null && { parentSeq: Number(r.parent_seq) }),
|
|
219
|
+
...(r.manual_run_id != null && { manualRunId: String(r.manual_run_id) }),
|
|
220
|
+
...(r.owner_pid != null && { ownerPid: Number(r.owner_pid) }),
|
|
221
|
+
...(r.had_step_errors != null && {
|
|
222
|
+
hadStepErrors: Boolean(r.had_step_errors),
|
|
223
|
+
}),
|
|
224
|
+
...(steps ? { stepResults: steps } : {}),
|
|
225
|
+
...extra,
|
|
226
|
+
};
|
|
227
|
+
return run;
|
|
228
|
+
}
|
|
229
|
+
startRun(input) {
|
|
230
|
+
const seq = ++this.seq;
|
|
231
|
+
this.db
|
|
232
|
+
.prepare(`INSERT INTO runs (task_id, seq, recipe_name, trigger, status, created_at,
|
|
233
|
+
started_at, model, parent_seq, manual_run_id, owner_pid)
|
|
234
|
+
VALUES (?,?,?,?,'running',?,?,?,?,?,?)
|
|
235
|
+
ON CONFLICT(task_id) DO UPDATE SET
|
|
236
|
+
seq=excluded.seq, status='running', created_at=excluded.created_at,
|
|
237
|
+
started_at=excluded.started_at, owner_pid=excluded.owner_pid`)
|
|
238
|
+
.run(input.taskId, seq, input.recipeName, input.trigger, input.createdAt, input.startedAt ?? null, input.model ?? null, input.parentSeq ?? null, input.manualRunId ?? null, input.ownerPid ?? process.pid);
|
|
239
|
+
return seq;
|
|
240
|
+
}
|
|
241
|
+
/** Resolve a per-instance `seq` to a task id. Ambiguous by construction — see
|
|
242
|
+
* the class docs and #1360. Newest wins, which is the least surprising of
|
|
243
|
+
* several wrong answers. */
|
|
244
|
+
taskIdForSeq(seq) {
|
|
245
|
+
const r = this.db
|
|
246
|
+
.prepare("SELECT task_id FROM runs WHERE seq=? ORDER BY created_at DESC LIMIT 1")
|
|
247
|
+
.get(seq);
|
|
248
|
+
return r ? String(r.task_id) : null;
|
|
249
|
+
}
|
|
250
|
+
updateRunSteps(seq, stepResults) {
|
|
251
|
+
const taskId = this.taskIdForSeq(seq);
|
|
252
|
+
if (!taskId)
|
|
253
|
+
return;
|
|
254
|
+
const cur = this.db
|
|
255
|
+
.prepare("SELECT status FROM runs WHERE task_id=?")
|
|
256
|
+
.get(taskId);
|
|
257
|
+
if (!cur || cur.status !== "running")
|
|
258
|
+
return;
|
|
259
|
+
const now = this.now();
|
|
260
|
+
const ins = this.db.prepare("INSERT INTO run_steps (task_id, step_id, at, step) VALUES (?,?,?,?) ON CONFLICT(task_id, step_id) DO NOTHING");
|
|
261
|
+
for (const step of stepResults) {
|
|
262
|
+
if (!step?.id)
|
|
263
|
+
continue;
|
|
264
|
+
// Same scope as the JSONL ledger: non-reversible, or any error. A
|
|
265
|
+
// reversible step carries no trust evidence, and persisting everything
|
|
266
|
+
// would buy durability with retention — the trade that starved the
|
|
267
|
+
// ledger in the first place.
|
|
268
|
+
if (!isEvidenceBearing(step))
|
|
269
|
+
continue;
|
|
270
|
+
ins.run(taskId, step.id, now, JSON.stringify(step));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
completeRun(seq, input) {
|
|
274
|
+
const taskId = this.taskIdForSeq(seq);
|
|
275
|
+
if (!taskId)
|
|
276
|
+
return;
|
|
277
|
+
const cur = this.db
|
|
278
|
+
.prepare("SELECT status FROM runs WHERE task_id=?")
|
|
279
|
+
.get(taskId);
|
|
280
|
+
// No-op on an already-terminal row, matching the incumbent.
|
|
281
|
+
if (!cur || cur.status !== "running")
|
|
282
|
+
return;
|
|
283
|
+
const extra = {};
|
|
284
|
+
for (const k of EXTRA_KEYS) {
|
|
285
|
+
const v = input[k];
|
|
286
|
+
if (v !== undefined)
|
|
287
|
+
extra[k] = v;
|
|
288
|
+
}
|
|
289
|
+
const hadStepErrors = input.stepResults.some((s) => s?.status === "error");
|
|
290
|
+
this.db
|
|
291
|
+
.prepare(`UPDATE runs SET status=?, done_at=?, duration_ms=?, step_results=?,
|
|
292
|
+
output_tail=?, error_message=?, had_step_errors=?, extra=?
|
|
293
|
+
WHERE task_id=?`)
|
|
294
|
+
.run(input.status, input.doneAt, input.durationMs, JSON.stringify(input.stepResults), input.outputTail ?? null, input.errorMessage ?? null, hadStepErrors ? 1 : 0, Object.keys(extra).length > 0 ? JSON.stringify(extra) : null, taskId);
|
|
295
|
+
}
|
|
296
|
+
query(q = {}) {
|
|
297
|
+
const where = [];
|
|
298
|
+
const args = [];
|
|
299
|
+
if (q.recipe !== undefined) {
|
|
300
|
+
where.push("recipe_name = ?");
|
|
301
|
+
args.push(q.recipe);
|
|
302
|
+
}
|
|
303
|
+
if (q.status !== undefined) {
|
|
304
|
+
where.push("status = ?");
|
|
305
|
+
args.push(q.status);
|
|
306
|
+
}
|
|
307
|
+
if (q.trigger !== undefined) {
|
|
308
|
+
where.push("trigger = ?");
|
|
309
|
+
args.push(q.trigger);
|
|
310
|
+
}
|
|
311
|
+
if (q.since !== undefined) {
|
|
312
|
+
where.push("created_at >= ?");
|
|
313
|
+
args.push(q.since);
|
|
314
|
+
}
|
|
315
|
+
if (q.after !== undefined) {
|
|
316
|
+
where.push("seq > ?");
|
|
317
|
+
args.push(q.after);
|
|
318
|
+
}
|
|
319
|
+
if (q.manualRunId !== undefined) {
|
|
320
|
+
where.push("manual_run_id = ?");
|
|
321
|
+
args.push(q.manualRunId);
|
|
322
|
+
}
|
|
323
|
+
const sql = `SELECT * FROM runs${where.length ? ` WHERE ${where.join(" AND ")}` : ""}` +
|
|
324
|
+
// seq as tiebreak so equal createdAt still yields a deterministic order —
|
|
325
|
+
// several contract cases share a timestamp.
|
|
326
|
+
" ORDER BY created_at DESC, seq DESC" +
|
|
327
|
+
(q.limit !== undefined ? " LIMIT ?" : "");
|
|
328
|
+
if (q.limit !== undefined)
|
|
329
|
+
args.push(q.limit);
|
|
330
|
+
const rows = this.db.prepare(sql).all(...args);
|
|
331
|
+
return rows.map((r) => this.rowToRun(r));
|
|
332
|
+
}
|
|
333
|
+
getBySeq(seq) {
|
|
334
|
+
const r = this.db
|
|
335
|
+
.prepare("SELECT * FROM runs WHERE seq=? ORDER BY created_at DESC LIMIT 1")
|
|
336
|
+
.get(seq);
|
|
337
|
+
return r ? this.rowToRun(r) : null;
|
|
338
|
+
}
|
|
339
|
+
getChildSeqs(parentSeq) {
|
|
340
|
+
const rows = this.db
|
|
341
|
+
.prepare("SELECT seq FROM runs WHERE parent_seq=? ORDER BY seq ASC")
|
|
342
|
+
.all(parentSeq);
|
|
343
|
+
return rows.map((r) => Number(r.seq));
|
|
344
|
+
}
|
|
345
|
+
size() {
|
|
346
|
+
const r = this.db.prepare("SELECT COUNT(*) AS n FROM runs").get();
|
|
347
|
+
return Number(r?.n ?? 0);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=sqliteRunRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqliteRunRepository.js","sourceRoot":"","sources":["../../src/runStore/sqliteRunRepository.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "1.2.0-beta.2.canary.
|
|
3
|
+
"version": "1.2.0-beta.2.canary.604",
|
|
4
4
|
"description": "Your personal AI runtime, local-first. Patchwork OS gives any AI model a consistent set of tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all on your machine, all under your policy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"README.md"
|
|
90
90
|
],
|
|
91
91
|
"engines": {
|
|
92
|
-
"node": ">=22.
|
|
92
|
+
"node": ">=22.5.0"
|
|
93
93
|
},
|
|
94
94
|
"scripts": {
|
|
95
95
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc && (node scripts/postinstall.mjs || true)",
|