patchwork-os 1.2.0-beta.2.canary.633 → 1.2.0-beta.2.canary.635

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.
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Butler errand outcome grader — "did the operator keep it?"
3
+ *
4
+ * A Butler errand's artifact is usually a task in a tracker, not a GitHub
5
+ * issue, so `classifyIssueDisposition` (outcomeStore.ts) does not apply. This
6
+ * is its sibling for artifacts whose only honest signal is what the operator
7
+ * subsequently did with the thing.
8
+ *
9
+ * ## The model
10
+ *
11
+ * completed → confirmed the operator acted on it. Real positive.
12
+ * deleted → junk the operator threw it away. Real negative.
13
+ * open + stale → junk left untouched past the staleness horizon.
14
+ * open + recent → WITHHELD no signal yet. Not evidence in EITHER
15
+ * direction.
16
+ *
17
+ * ## Why "open + recent" must withhold rather than pass
18
+ *
19
+ * This is the single load-bearing rule, and it is the one a reasonable person
20
+ * gets wrong. An errand that nobody has deleted looks like a success and is
21
+ * not one: the operator may simply not have looked. Folding it as good is
22
+ * trust-by-neglect, the exact defect closed three times already in this
23
+ * subsystem (#1064, #1318/#1319, #1320, #1322) — each time by making absence
24
+ * of a negative stop counting as a positive.
25
+ *
26
+ * So the grader has no "default to good" branch at all. Every path that is not
27
+ * a POSITIVE ACT by the operator returns `unknown`, which the fold withholds.
28
+ *
29
+ * ## Why stale → junk rather than unknown
30
+ *
31
+ * Asymmetric on purpose. `unknown` is the right answer while the operator
32
+ * might still act; it is the wrong answer once enough time has passed that
33
+ * not-acting IS the answer. Leaving it `unknown` forever would let a worker
34
+ * that files things nobody ever touches sit permanently un-judged instead of
35
+ * accumulating the negative it has earned. The horizon is explicit and long
36
+ * (default 14 days) precisely because it converts silence into a negative.
37
+ *
38
+ * ## No model in the loop
39
+ *
40
+ * Pure function of observed state and two timestamps. A prior LLM judge in
41
+ * this repo flipped verdicts between runs on identical inputs, which makes the
42
+ * trust ledger unreproducible — and a trust ledger you cannot replay is not
43
+ * evidence, it is an opinion with a timestamp.
44
+ */
45
+ import type { OutcomeDisposition } from "../workers/outcomeStore.js";
46
+ /** Default staleness horizon: 14 days. */
47
+ export declare const DEFAULT_STALE_AFTER_MS: number;
48
+ /**
49
+ * What we observed about the errand's artifact.
50
+ *
51
+ * Every field is optional because observation is best-effort — a connector may
52
+ * not report deletion at all. Absent fields must never be read as a positive:
53
+ * see `gradeErrandOutcome`'s ordering.
54
+ */
55
+ export interface ObservedErrandArtifact {
56
+ /** The operator marked it done. A positive act. */
57
+ completed?: boolean;
58
+ /**
59
+ * The artifact is gone. A positive act in the other direction.
60
+ *
61
+ * Distinct from "we could not find it": a lookup failure must be reported as
62
+ * `undefined`, never as `deleted: true`. A transient API error that reads as
63
+ * deletion would manufacture a negative against a worker that did nothing
64
+ * wrong.
65
+ */
66
+ deleted?: boolean;
67
+ /** When the errand created the artifact. */
68
+ createdAt?: number;
69
+ }
70
+ export interface GradeOptions {
71
+ /** Clock. Injected so grading is reproducible in replay. */
72
+ now: number;
73
+ /** How long "open" stays `unknown` before becoming `junk`. */
74
+ staleAfterMs?: number;
75
+ }
76
+ export interface GradedOutcome {
77
+ disposition: OutcomeDisposition;
78
+ /**
79
+ * Why, in a form a human can check against the row. Stored alongside the
80
+ * disposition — a verdict whose reasoning is not recorded cannot be audited,
81
+ * only believed.
82
+ */
83
+ reason: "completed" | "deleted" | "stale-unactioned" | "open-recent" | "not-observed";
84
+ }
85
+ /**
86
+ * Grade one observed artifact.
87
+ *
88
+ * Ordering is deliberate: the two POSITIVE ACTS are tested first, then
89
+ * staleness, and everything remaining falls to `unknown`. There is no branch
90
+ * that reaches `confirmed` without `completed === true`.
91
+ */
92
+ export declare function gradeErrandOutcome(observed: ObservedErrandArtifact, opts: GradeOptions): GradedOutcome;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Butler errand outcome grader — "did the operator keep it?"
3
+ *
4
+ * A Butler errand's artifact is usually a task in a tracker, not a GitHub
5
+ * issue, so `classifyIssueDisposition` (outcomeStore.ts) does not apply. This
6
+ * is its sibling for artifacts whose only honest signal is what the operator
7
+ * subsequently did with the thing.
8
+ *
9
+ * ## The model
10
+ *
11
+ * completed → confirmed the operator acted on it. Real positive.
12
+ * deleted → junk the operator threw it away. Real negative.
13
+ * open + stale → junk left untouched past the staleness horizon.
14
+ * open + recent → WITHHELD no signal yet. Not evidence in EITHER
15
+ * direction.
16
+ *
17
+ * ## Why "open + recent" must withhold rather than pass
18
+ *
19
+ * This is the single load-bearing rule, and it is the one a reasonable person
20
+ * gets wrong. An errand that nobody has deleted looks like a success and is
21
+ * not one: the operator may simply not have looked. Folding it as good is
22
+ * trust-by-neglect, the exact defect closed three times already in this
23
+ * subsystem (#1064, #1318/#1319, #1320, #1322) — each time by making absence
24
+ * of a negative stop counting as a positive.
25
+ *
26
+ * So the grader has no "default to good" branch at all. Every path that is not
27
+ * a POSITIVE ACT by the operator returns `unknown`, which the fold withholds.
28
+ *
29
+ * ## Why stale → junk rather than unknown
30
+ *
31
+ * Asymmetric on purpose. `unknown` is the right answer while the operator
32
+ * might still act; it is the wrong answer once enough time has passed that
33
+ * not-acting IS the answer. Leaving it `unknown` forever would let a worker
34
+ * that files things nobody ever touches sit permanently un-judged instead of
35
+ * accumulating the negative it has earned. The horizon is explicit and long
36
+ * (default 14 days) precisely because it converts silence into a negative.
37
+ *
38
+ * ## No model in the loop
39
+ *
40
+ * Pure function of observed state and two timestamps. A prior LLM judge in
41
+ * this repo flipped verdicts between runs on identical inputs, which makes the
42
+ * trust ledger unreproducible — and a trust ledger you cannot replay is not
43
+ * evidence, it is an opinion with a timestamp.
44
+ */
45
+ /** Default staleness horizon: 14 days. */
46
+ export const DEFAULT_STALE_AFTER_MS = 14 * 24 * 60 * 60 * 1000;
47
+ /**
48
+ * Grade one observed artifact.
49
+ *
50
+ * Ordering is deliberate: the two POSITIVE ACTS are tested first, then
51
+ * staleness, and everything remaining falls to `unknown`. There is no branch
52
+ * that reaches `confirmed` without `completed === true`.
53
+ */
54
+ export function gradeErrandOutcome(observed, opts) {
55
+ // Deleted is checked BEFORE completed. A tracker can report both when an
56
+ // operator completes and then clears a task, and "they threw it away" is the
57
+ // more conservative reading of a contradictory pair — it lowers trust rather
58
+ // than raising it on ambiguous evidence.
59
+ if (observed.deleted === true) {
60
+ return { disposition: "junk", reason: "deleted" };
61
+ }
62
+ if (observed.completed === true) {
63
+ return { disposition: "confirmed", reason: "completed" };
64
+ }
65
+ // Not completed, not deleted. Everything from here is an ABSENCE, and no
66
+ // absence may produce `confirmed`.
67
+ if (observed.createdAt === undefined) {
68
+ // We cannot even tell how long it has been open, so we cannot tell whether
69
+ // silence has become meaningful. Withhold.
70
+ return { disposition: "unknown", reason: "not-observed" };
71
+ }
72
+ const staleAfter = opts.staleAfterMs ?? DEFAULT_STALE_AFTER_MS;
73
+ const age = opts.now - observed.createdAt;
74
+ if (age >= staleAfter) {
75
+ return { disposition: "junk", reason: "stale-unactioned" };
76
+ }
77
+ return { disposition: "unknown", reason: "open-recent" };
78
+ }
79
+ //# sourceMappingURL=errandOutcomeGrader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errandOutcomeGrader.js","sourceRoot":"","sources":["../../src/butler/errandOutcomeGrader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AA+C/D;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgC,EAChC,IAAkB;IAElB,yEAAyE;IACzE,6EAA6E;IAC7E,6EAA6E;IAC7E,yCAAyC;IACzC,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;IACD,IAAI,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAChC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC3D,CAAC;IAED,yEAAyE;IACzE,mCAAmC;IACnC,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACrC,2EAA2E;QAC3E,2CAA2C;QAC3C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,IAAI,sBAAsB,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC;IAC1C,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;QACtB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Shadow ledger for graded Butler errand outcomes.
3
+ *
4
+ * A SEPARATE file from `outcome-log.jsonl`, and that separation is the entire
5
+ * safety property of this phase. The trust fold reads `outcome-log.jsonl`; it
6
+ * does not read this file and must not be taught to. Rows here are a
7
+ * measurement of what the grader WOULD have said, recorded so the labelling
8
+ * can be checked against reality before anything moves a worker's dial.
9
+ *
10
+ * This mirrors how the autonomy gate itself was landed — `workers shadow` and
11
+ * `workers backtest` measured divergence for a whole campaign before the gate
12
+ * was allowed to decide anything — and how #1319 was flipped, against a
13
+ * measured delta rather than an argument. The pattern exists because the
14
+ * alternative has failed here repeatedly: a labelling change that looks
15
+ * obviously correct turns out to move real workers in ways nobody predicted,
16
+ * and by then it is already in the ledger the gate rests on.
17
+ *
18
+ * ## What "shadow" costs
19
+ *
20
+ * Nothing observable. No gate decision consults it, no dial reads it, and
21
+ * deleting the file loses only the measurement. That is the point: until
22
+ * someone has read these rows against the real errands they describe, the
23
+ * grader has not earned the right to be evidence.
24
+ *
25
+ * ## Promotion
26
+ *
27
+ * Promoting it means writing graded rows into `outcome-log.jsonl` through
28
+ * `OutcomeStore.upsert` — deliberately NOT implemented here. That step needs
29
+ * the join key to be right (`ref` = `"<tool>:<id>"`, see `actionRef.ts`) and a
30
+ * measured before/after on the real log, exactly as #1319 required.
31
+ */
32
+ import type { OutcomeDisposition } from "../workers/outcomeStore.js";
33
+ import type { GradedOutcome } from "./errandOutcomeGrader.js";
34
+ /**
35
+ * Filename. Deliberately NOT `outcome-log.jsonl` and deliberately not in a
36
+ * subdirectory of it — a reader that globs the outcome log must not pick this
37
+ * up by accident.
38
+ */
39
+ export declare const SHADOW_LOG_BASENAME = "butler_outcome_shadow.jsonl";
40
+ export declare function shadowLogPath(override?: string): string;
41
+ export interface ShadowOutcomeRow {
42
+ /**
43
+ * The action this grades, in `canonicalActionRef` form (`"<tool>:<id>"`).
44
+ * Stored so a promoted row can join to the same action the fold would —
45
+ * recording a grade under a key the fold cannot resolve would produce a
46
+ * measurement of nothing.
47
+ */
48
+ ref: string;
49
+ disposition: OutcomeDisposition;
50
+ reason: GradedOutcome["reason"];
51
+ /** When the grade was computed. */
52
+ gradedAt: number;
53
+ /** The recipe that filed the action, for attribution during review. */
54
+ recipe?: string;
55
+ /**
56
+ * Whether the fold WOULD have counted this as evidence. Derived once at
57
+ * write time so a reviewer reading the file does not have to re-derive the
58
+ * withholding rule and risk deriving it differently.
59
+ */
60
+ wouldCountAsEvidence: boolean;
61
+ }
62
+ /** `unknown` is withheld by the fold; the other two are evidence. */
63
+ export declare function wouldCountAsEvidence(d: OutcomeDisposition): boolean;
64
+ /**
65
+ * Append one graded row. Append-only and best-effort: this is a measurement,
66
+ * and a measurement must never be able to fail an errand it is observing.
67
+ */
68
+ export declare function appendShadowOutcome(row: Omit<ShadowOutcomeRow, "wouldCountAsEvidence">, opts?: {
69
+ dir?: string;
70
+ }): void;
71
+ export interface ShadowSummary {
72
+ total: number;
73
+ confirmed: number;
74
+ junk: number;
75
+ unknown: number;
76
+ /** Rows that would have become evidence had the grader been live. */
77
+ wouldCount: number;
78
+ }
79
+ /**
80
+ * Summarise the shadow ledger — the number this phase exists to produce.
81
+ *
82
+ * Malformed lines are SKIPPED but counted in nothing; a half-written row from
83
+ * an interrupted append is not evidence of anything and must not inflate a
84
+ * count someone is about to make a decision on.
85
+ */
86
+ export declare function summariseShadowLog(opts?: {
87
+ dir?: string;
88
+ }): ShadowSummary;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Shadow ledger for graded Butler errand outcomes.
3
+ *
4
+ * A SEPARATE file from `outcome-log.jsonl`, and that separation is the entire
5
+ * safety property of this phase. The trust fold reads `outcome-log.jsonl`; it
6
+ * does not read this file and must not be taught to. Rows here are a
7
+ * measurement of what the grader WOULD have said, recorded so the labelling
8
+ * can be checked against reality before anything moves a worker's dial.
9
+ *
10
+ * This mirrors how the autonomy gate itself was landed — `workers shadow` and
11
+ * `workers backtest` measured divergence for a whole campaign before the gate
12
+ * was allowed to decide anything — and how #1319 was flipped, against a
13
+ * measured delta rather than an argument. The pattern exists because the
14
+ * alternative has failed here repeatedly: a labelling change that looks
15
+ * obviously correct turns out to move real workers in ways nobody predicted,
16
+ * and by then it is already in the ledger the gate rests on.
17
+ *
18
+ * ## What "shadow" costs
19
+ *
20
+ * Nothing observable. No gate decision consults it, no dial reads it, and
21
+ * deleting the file loses only the measurement. That is the point: until
22
+ * someone has read these rows against the real errands they describe, the
23
+ * grader has not earned the right to be evidence.
24
+ *
25
+ * ## Promotion
26
+ *
27
+ * Promoting it means writing graded rows into `outcome-log.jsonl` through
28
+ * `OutcomeStore.upsert` — deliberately NOT implemented here. That step needs
29
+ * the join key to be right (`ref` = `"<tool>:<id>"`, see `actionRef.ts`) and a
30
+ * measured before/after on the real log, exactly as #1319 required.
31
+ */
32
+ import { appendFileSync, existsSync, readFileSync } from "node:fs";
33
+ import path from "node:path";
34
+ import { patchworkHome } from "../patchworkHome.js";
35
+ /**
36
+ * Filename. Deliberately NOT `outcome-log.jsonl` and deliberately not in a
37
+ * subdirectory of it — a reader that globs the outcome log must not pick this
38
+ * up by accident.
39
+ */
40
+ export const SHADOW_LOG_BASENAME = "butler_outcome_shadow.jsonl";
41
+ export function shadowLogPath(override) {
42
+ return path.join(override ?? patchworkHome(), SHADOW_LOG_BASENAME);
43
+ }
44
+ /** `unknown` is withheld by the fold; the other two are evidence. */
45
+ export function wouldCountAsEvidence(d) {
46
+ return d !== "unknown";
47
+ }
48
+ /**
49
+ * Append one graded row. Append-only and best-effort: this is a measurement,
50
+ * and a measurement must never be able to fail an errand it is observing.
51
+ */
52
+ export function appendShadowOutcome(row, opts = {}) {
53
+ const full = {
54
+ ...row,
55
+ wouldCountAsEvidence: wouldCountAsEvidence(row.disposition),
56
+ };
57
+ try {
58
+ appendFileSync(shadowLogPath(opts.dir), `${JSON.stringify(full)}\n`);
59
+ }
60
+ catch {
61
+ // Swallowed on purpose. See above: an unwritable shadow ledger must not
62
+ // turn into an errand failure.
63
+ }
64
+ }
65
+ /**
66
+ * Summarise the shadow ledger — the number this phase exists to produce.
67
+ *
68
+ * Malformed lines are SKIPPED but counted in nothing; a half-written row from
69
+ * an interrupted append is not evidence of anything and must not inflate a
70
+ * count someone is about to make a decision on.
71
+ */
72
+ export function summariseShadowLog(opts = {}) {
73
+ const empty = {
74
+ total: 0,
75
+ confirmed: 0,
76
+ junk: 0,
77
+ unknown: 0,
78
+ wouldCount: 0,
79
+ };
80
+ const p = shadowLogPath(opts.dir);
81
+ if (!existsSync(p))
82
+ return empty;
83
+ let text;
84
+ try {
85
+ text = readFileSync(p, "utf-8");
86
+ }
87
+ catch {
88
+ return empty;
89
+ }
90
+ const out = { ...empty };
91
+ for (const line of text.split("\n")) {
92
+ if (!line.trim())
93
+ continue;
94
+ let row;
95
+ try {
96
+ row = JSON.parse(line);
97
+ }
98
+ catch {
99
+ continue;
100
+ }
101
+ if (row.disposition !== "confirmed" &&
102
+ row.disposition !== "junk" &&
103
+ row.disposition !== "unknown") {
104
+ continue;
105
+ }
106
+ out.total++;
107
+ out[row.disposition]++;
108
+ if (row.wouldCountAsEvidence)
109
+ out.wouldCount++;
110
+ }
111
+ return out;
112
+ }
113
+ //# sourceMappingURL=outcomeShadowLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcomeShadowLog.js","sourceRoot":"","sources":["../../src/butler/outcomeShadowLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;AAEjE,MAAM,UAAU,aAAa,CAAC,QAAiB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,aAAa,EAAE,EAAE,mBAAmB,CAAC,CAAC;AACrE,CAAC;AAwBD,qEAAqE;AACrE,MAAM,UAAU,oBAAoB,CAAC,CAAqB;IACxD,OAAO,CAAC,KAAK,SAAS,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAmD,EACnD,OAAyB,EAAE;IAE3B,MAAM,IAAI,GAAqB;QAC7B,GAAG,GAAG;QACN,oBAAoB,EAAE,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC;KAC5D,CAAC;IACF,IAAI,CAAC;QACH,cAAc,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,+BAA+B;IACjC,CAAC;AACH,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAyB,EAAE;IAC5D,MAAM,KAAK,GAAkB;QAC3B,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,CAAC;KACd,CAAC;IACF,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,GAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqB,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IACE,GAAG,CAAC,WAAW,KAAK,WAAW;YAC/B,GAAG,CAAC,WAAW,KAAK,MAAM;YAC1B,GAAG,CAAC,WAAW,KAAK,SAAS,EAC7B,CAAC;YACD,SAAS;QACX,CAAC;QACD,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,oBAAoB;YAAE,GAAG,CAAC,UAAU,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchwork-os",
3
- "version": "1.2.0-beta.2.canary.633",
3
+ "version": "1.2.0-beta.2.canary.635",
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",