pi-daddy 0.17.0 → 0.18.0
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 +154 -80
- package/README.md +54 -25
- package/dist/approval-prompt.d.ts +3 -1
- package/dist/approval-prompt.d.ts.map +1 -1
- package/dist/approval-prompt.js +1 -1
- package/dist/approval-prompt.js.map +1 -1
- package/dist/approval-store.d.ts.map +1 -1
- package/dist/approval-store.js +4 -1
- package/dist/approval-store.js.map +1 -1
- package/dist/approval.d.ts +20 -2
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +26 -6
- package/dist/approval.js.map +1 -1
- package/dist/chain.d.ts +6 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +1 -1
- package/dist/chain.js.map +1 -1
- package/dist/check-runner.d.ts +61 -0
- package/dist/check-runner.d.ts.map +1 -0
- package/dist/check-runner.js +237 -0
- package/dist/check-runner.js.map +1 -0
- package/dist/correlation.d.ts +90 -0
- package/dist/correlation.d.ts.map +1 -0
- package/dist/correlation.js +183 -0
- package/dist/correlation.js.map +1 -0
- package/dist/delegate-types.d.ts +140 -0
- package/dist/delegate-types.d.ts.map +1 -0
- package/dist/delegate-types.js +8 -0
- package/dist/delegate-types.js.map +1 -0
- package/dist/delegate.d.ts +4 -128
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +68 -72
- package/dist/delegate.js.map +1 -1
- package/dist/delegation-approval.d.ts +36 -0
- package/dist/delegation-approval.d.ts.map +1 -0
- package/dist/delegation-approval.js +67 -0
- package/dist/delegation-approval.js.map +1 -0
- package/dist/git-identity.d.ts +13 -0
- package/dist/git-identity.d.ts.map +1 -0
- package/dist/git-identity.js +44 -0
- package/dist/git-identity.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lease-record.d.ts +78 -0
- package/dist/lease-record.d.ts.map +1 -0
- package/dist/lease-record.js +52 -0
- package/dist/lease-record.js.map +1 -0
- package/dist/ledger-events.d.ts +87 -0
- package/dist/ledger-events.d.ts.map +1 -0
- package/dist/ledger-events.js +45 -0
- package/dist/ledger-events.js.map +1 -0
- package/dist/ledger-report.d.ts +19 -12
- package/dist/ledger-report.d.ts.map +1 -1
- package/dist/ledger-report.js +81 -1
- package/dist/ledger-report.js.map +1 -1
- package/dist/ledger.d.ts +44 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +20 -2
- package/dist/ledger.js.map +1 -1
- package/dist/refusals.d.ts +16 -0
- package/dist/refusals.d.ts.map +1 -0
- package/dist/refusals.js +51 -0
- package/dist/refusals.js.map +1 -0
- package/dist/run-child.d.ts +4 -0
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +21 -1
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +7 -0
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +41 -12
- package/dist/run-herdr.js.map +1 -1
- package/dist/workspace-lease.d.ts +28 -0
- package/dist/workspace-lease.d.ts.map +1 -0
- package/dist/workspace-lease.js +276 -0
- package/dist/workspace-lease.js.map +1 -0
- package/dist/workspace.d.ts +32 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +79 -0
- package/dist/workspace.js.map +1 -0
- package/extensions/approval-banking.ts +66 -0
- package/extensions/approvals.ts +95 -7
- package/extensions/chain-approval-facts.ts +51 -0
- package/extensions/chain-ledger.ts +48 -0
- package/extensions/delegate-chain.ts +115 -81
- package/extensions/delegation.ts +81 -23
- package/extensions/execute-child.ts +289 -0
- package/extensions/fanout-outcome.ts +97 -0
- package/extensions/run-delegation.ts +130 -120
- package/extensions/session.ts +4 -0
- package/extensions/workspace-runtime.ts +165 -0
- package/package.json +17 -1
- package/src/approval-prompt.ts +4 -2
- package/src/approval-store.ts +4 -1
- package/src/approval.ts +47 -14
- package/src/chain.ts +3 -1
- package/src/check-runner.ts +341 -0
- package/src/correlation.ts +260 -0
- package/src/delegate-types.ts +144 -0
- package/src/delegate.ts +80 -179
- package/src/delegation-approval.ts +99 -0
- package/src/git-identity.ts +52 -0
- package/src/index.ts +50 -0
- package/src/lease-record.ts +119 -0
- package/src/ledger-events.ts +138 -0
- package/src/ledger-report.ts +90 -2
- package/src/ledger.ts +68 -3
- package/src/refusals.ts +66 -0
- package/src/run-child.ts +23 -1
- package/src/run-herdr.ts +41 -11
- package/src/workspace-lease.ts +303 -0
- package/src/workspace.ts +135 -0
package/dist/refusals.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const REFUSAL_CODES = [
|
|
2
|
+
"CAPABILITY_ESCALATION",
|
|
3
|
+
"DEFINITION_NOT_AUTHORIZED",
|
|
4
|
+
"UNDECLARED_TOOLS",
|
|
5
|
+
"UNKNOWN_TOOL",
|
|
6
|
+
"GATED_UNAPPROVED",
|
|
7
|
+
"APPROVAL_EXPIRED",
|
|
8
|
+
"APPROVAL_SCOPE_MISMATCH",
|
|
9
|
+
"APPROVAL_FLOW_FAILED",
|
|
10
|
+
"DEPTH_EXCEEDED",
|
|
11
|
+
"FANOUT_EXCEEDED",
|
|
12
|
+
"EXECUTOR_UNAVAILABLE",
|
|
13
|
+
// Execution-phase outcomes. Without these, an external controller could distinguish a policy refusal
|
|
14
|
+
// from an internal error but not a lost writer lease from a user pressing stop (R-103).
|
|
15
|
+
"CHILD_TIMED_OUT",
|
|
16
|
+
"CHILD_CANCELLED",
|
|
17
|
+
"CHILD_EXIT_NONZERO",
|
|
18
|
+
// Planner refusals that previously carried a message and no code at all — including the narrowing
|
|
19
|
+
// violation, which is the hardest rule this package enforces (R-109).
|
|
20
|
+
"TASK_MISSING",
|
|
21
|
+
"UNKNOWN_DEFINITION",
|
|
22
|
+
"CEILING_PATTERNS_UNRESOLVED",
|
|
23
|
+
"NARROWING_VIOLATED",
|
|
24
|
+
"DEFINITION_UNREADABLE",
|
|
25
|
+
"CORRELATION_TOO_LARGE",
|
|
26
|
+
"CORRELATION_INVALID",
|
|
27
|
+
"LEDGER_WRITE_FAILED",
|
|
28
|
+
"FANOUT_FAILED",
|
|
29
|
+
"WORKSPACE_NOT_REGISTERED",
|
|
30
|
+
"WORKSPACE_WRITE_CONFLICT",
|
|
31
|
+
"WORKSPACE_LEASE_STALE",
|
|
32
|
+
"CHECK_NOT_CONFIGURED",
|
|
33
|
+
"CHECK_CONFIGURATION_INVALID",
|
|
34
|
+
"CHECK_IDENTITY_UNAVAILABLE",
|
|
35
|
+
"CHECK_IDENTITY_MISMATCH",
|
|
36
|
+
];
|
|
37
|
+
export function refusal(code, message, details) {
|
|
38
|
+
return { code, message, ...(details && Object.keys(details).length > 0 ? { details: { ...details } } : {}) };
|
|
39
|
+
}
|
|
40
|
+
/** Error shape for API callers. pi-facing tools still throw, as pi requires, while retaining a stable code. */
|
|
41
|
+
export class GovernanceRefusal extends Error {
|
|
42
|
+
code;
|
|
43
|
+
details;
|
|
44
|
+
constructor(value) {
|
|
45
|
+
super(value.message);
|
|
46
|
+
this.name = "GovernanceRefusal";
|
|
47
|
+
this.code = value.code;
|
|
48
|
+
this.details = value.details;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=refusals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../src/refusals.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uBAAuB;IACvB,2BAA2B;IAC3B,kBAAkB;IAClB,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,yBAAyB;IACzB,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,sBAAsB;IACtB,qGAAqG;IACrG,wFAAwF;IACxF,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,kGAAkG;IAClG,sEAAsE;IACtE,cAAc;IACd,oBAAoB;IACpB,6BAA6B;IAC7B,oBAAoB;IACpB,uBAAuB;IACvB,uBAAuB;IACvB,qBAAqB;IACrB,qBAAqB;IACrB,eAAe;IACf,0BAA0B;IAC1B,0BAA0B;IAC1B,uBAAuB;IACvB,sBAAsB;IACtB,6BAA6B;IAC7B,4BAA4B;IAC5B,yBAAyB;CACjB,CAAC;AAWX,MAAM,UAAU,OAAO,CACrB,IAAiB,EACjB,OAAe,EACf,OAAsC;IAEtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED,+GAA+G;AAC/G,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAc;IAClB,OAAO,CAAgC;IAEhD,YAAY,KAAwB;QAClC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,CAAC;CACF"}
|
package/dist/run-child.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ export interface ChildRunRequest {
|
|
|
56
56
|
* governed child mid-task.
|
|
57
57
|
*/
|
|
58
58
|
onOutput?: (chunk: string) => void;
|
|
59
|
+
/** Security hook called immediately after spawn, before output handling (for lease attachment). */
|
|
60
|
+
onSpawn?: (pid: number) => void;
|
|
59
61
|
}
|
|
60
62
|
export interface ChildRunResult {
|
|
61
63
|
/** Exit code, or `null` when nothing was spawned or the child was killed by a signal. */
|
|
@@ -64,6 +66,8 @@ export interface ChildRunResult {
|
|
|
64
66
|
truncated: boolean;
|
|
65
67
|
timedOut: boolean;
|
|
66
68
|
aborted: boolean;
|
|
69
|
+
/** Signal that ended the process, separate from the nullable numeric exit code. */
|
|
70
|
+
signal?: NodeJS.Signals | null;
|
|
67
71
|
/** Set when the process could not be started at all. */
|
|
68
72
|
spawnError?: string;
|
|
69
73
|
}
|
package/dist/run-child.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-child.d.ts","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAY9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"run-child.d.ts","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAY9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAE3D,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK9D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,mGAAmG;IACnG,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,yFAAyF;IACzF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC/B,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0FAA0F;AAC1F,eAAO,MAAM,wBAAwB,QAAc,CAAC;AACpD,kGAAkG;AAClG,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AACjD,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAwJ1E"}
|
package/dist/run-child.js
CHANGED
|
@@ -83,6 +83,19 @@ export function runChild(request) {
|
|
|
83
83
|
settle({ code: null, text: "", truncated: false, timedOut: false, aborted: false, spawnError: String(error) });
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
|
+
try {
|
|
87
|
+
if (child.pid !== undefined)
|
|
88
|
+
request.onSpawn?.(child.pid);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const failed = { code: null, text: "", truncated: false, timedOut: false, aborted: false, spawnError: String(error) };
|
|
92
|
+
child.stdout?.destroy();
|
|
93
|
+
child.stderr?.destroy();
|
|
94
|
+
child.once("error", () => settle(failed));
|
|
95
|
+
child.once("close", () => settle(failed));
|
|
96
|
+
child.kill("SIGKILL");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
86
99
|
// One decoder for BOTH streams is deliberate: they are already interleaved into one `text`, and two
|
|
87
100
|
// decoders would each hold their own partial character, so a split byte could surface out of order.
|
|
88
101
|
const decoder = new StringDecoder("utf8");
|
|
@@ -177,10 +190,17 @@ export function runChild(request) {
|
|
|
177
190
|
done = true;
|
|
178
191
|
clearTimers();
|
|
179
192
|
request.signal?.removeEventListener("abort", onAbort);
|
|
193
|
+
child.stdout?.destroy();
|
|
194
|
+
child.stderr?.destroy();
|
|
180
195
|
settle(result);
|
|
181
196
|
};
|
|
182
197
|
child.on("error", (error) => finish({ code: null, text, truncated, timedOut, aborted, spawnError: String(error) }));
|
|
183
|
-
|
|
198
|
+
// `close` waits for every inherited pipe, including one retained by a detached grandchild. Once the
|
|
199
|
+
// governed PID exits, allow a short drain and settle anyway so timeout/output bounds remain bounds.
|
|
200
|
+
child.on("exit", (code, signal) => {
|
|
201
|
+
timers.push(setTimeout(() => finish({ code, signal, text, truncated, timedOut, aborted }), 100));
|
|
202
|
+
});
|
|
203
|
+
child.on("close", (code, signal) => finish({ code, signal, text, truncated, timedOut, aborted }));
|
|
184
204
|
});
|
|
185
205
|
}
|
|
186
206
|
//# sourceMappingURL=run-child.js.map
|
package/dist/run-child.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-child.js","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACpD,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,IAAI,GAAG,MAAM;YAAE,MAAM;QAChC,GAAG,IAAI,SAAS,CAAC;QACjB,IAAI,IAAI,IAAI,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAE3D,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,GAAuB;IACpD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,mGAAmG;IACnG,uEAAuE;IACvE,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC;AAC1G,CAAC;
|
|
1
|
+
{"version":3,"file":"run-child.js","sourceRoot":"","sources":["../src/run-child.ts"],"names":[],"mappings":"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"}
|
package/dist/run-herdr.d.ts
CHANGED
|
@@ -89,9 +89,16 @@ export interface HerdrRunRequest {
|
|
|
89
89
|
* name a human can switch to **while the child is alive**, which is the whole point of the pane surviving.
|
|
90
90
|
*/
|
|
91
91
|
onPane?: (paneId: string, agentName: string) => void;
|
|
92
|
+
/** Security hook for attaching a writer lease to the tab. Unlike display callbacks, errors fail the run. */
|
|
93
|
+
onTab?: (tabId: string) => void;
|
|
94
|
+
/** Close even a settled pane before releasing a writer lease; no post-lease prompt may remain live. */
|
|
95
|
+
closeOnSettle?: boolean;
|
|
92
96
|
/** Poll cadence override. Exists so tests do not wait `POLL_INTERVAL_MS` per state transition. */
|
|
93
97
|
pollIntervalMs?: number;
|
|
94
98
|
}
|
|
99
|
+
export declare class HerdrWriterCloseError extends Error {
|
|
100
|
+
constructor(tabId: string);
|
|
101
|
+
}
|
|
95
102
|
/** How often to retry `agent start` while a freshly created pane is still reaching its shell prompt. */
|
|
96
103
|
export declare const PANE_READY_POLL_MS = 300;
|
|
97
104
|
/**
|
package/dist/run-herdr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-herdr.d.ts","sourceRoot":"","sources":["../src/run-herdr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKzE;;;;;GAKG;AACH,OAAO,EAAE,KAAK,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5D,gHAAgH;AAChH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,wGAAwG;AACxG,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD;;;;;GAKG;AACH,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEjI,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAGD,wGAAwG;AACxG,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAGtC;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"run-herdr.d.ts","sourceRoot":"","sources":["../src/run-herdr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKzE;;;;;GAKG;AACH,OAAO,EAAE,KAAK,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5D,gHAAgH;AAChH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,wGAAwG;AACxG,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD;;;;;GAKG;AACH,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEjI,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,4GAA4G;IAC5G,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,uGAAuG;IACvG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAGD,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,KAAK,EAAE,MAAM;CAI1B;AAED,wGAAwG;AACxG,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAGtC;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA8NpF"}
|
package/dist/run-herdr.js
CHANGED
|
@@ -45,6 +45,12 @@ export { uniqueAgentName } from "./herdr-name.js";
|
|
|
45
45
|
* of this module's surface and moving a file should not move an export.
|
|
46
46
|
*/
|
|
47
47
|
export { DEFAULT_SNAPSHOT_LINES, POLL_INTERVAL_MS, readPane, tailLines, waitForSettled } from "./herdr-poll.js";
|
|
48
|
+
export class HerdrWriterCloseError extends Error {
|
|
49
|
+
constructor(tabId) {
|
|
50
|
+
super(`herdr writer tab ${tabId} could not be closed; retaining its workspace lease`);
|
|
51
|
+
this.name = "HerdrWriterCloseError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
48
54
|
/** How often to retry `agent start` while a freshly created pane is still reaching its shell prompt. */
|
|
49
55
|
export const PANE_READY_POLL_MS = 300;
|
|
50
56
|
/**
|
|
@@ -114,14 +120,29 @@ export async function runHerdrPane(request) {
|
|
|
114
120
|
// path leaked a `/tmp/grants-herdr-*` that neither sweep could reach.
|
|
115
121
|
trackPane({ tab: tabId, name: agentName, promptDir, settled: true, keepTab: true });
|
|
116
122
|
}
|
|
117
|
-
if (tabId && !request.keepPane)
|
|
123
|
+
if (tabId && !request.keepPane)
|
|
118
124
|
trackPane({ tab: tabId, name: agentName, promptDir });
|
|
125
|
+
// Attach before the first post-create await. If the parent dies after this point, the independent lock
|
|
126
|
+
// helper closes the tab before releasing the writer lease.
|
|
127
|
+
if (request.onTab) {
|
|
128
|
+
try {
|
|
129
|
+
if (!tabId)
|
|
130
|
+
throw new Error("herdr returned no tab id for writer-lease attachment");
|
|
131
|
+
request.onTab(tabId);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (tabId && !request.keepPane) {
|
|
135
|
+
const closed = await exec(["tab", "close", tabId]).catch(() => undefined);
|
|
136
|
+
if (closed === undefined || parseReply(closed).error)
|
|
137
|
+
throw new HerdrWriterCloseError(tabId);
|
|
138
|
+
}
|
|
139
|
+
return { ...empty, spawnError: `workspace writer lease could not attach to herdr tab (${String(error)})` };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (tabId && !request.keepPane) {
|
|
119
143
|
// ADR-0032: panes now live until `agent_settled`, so they accumulate across one agent run — and a plain
|
|
120
144
|
// blocking `delegate` spends nothing from the fan-out budget, so the count is otherwise unbounded. Trimmed
|
|
121
145
|
// here rather than at settle time so the bound holds DURING a long run, not only after it.
|
|
122
|
-
//
|
|
123
|
-
// Whatever is closed is reported through `onOutput` rather than dropped: an operator whose pane vanished
|
|
124
|
-
// while they were reading it deserves to know why (R-48's rule, applied to a display).
|
|
125
146
|
const dropped = await trimOpenPanes(exec);
|
|
126
147
|
if (dropped.length > 0 && request.onSnapshot) {
|
|
127
148
|
try {
|
|
@@ -142,8 +163,13 @@ export async function runHerdrPane(request) {
|
|
|
142
163
|
const reply = await exec(["tab", "close", tabId]).catch(() => undefined);
|
|
143
164
|
// Same rule as `cleanup`: untrack only what is provably gone, so a close herdr refused stays the
|
|
144
165
|
// reaper's problem rather than being dropped on the assumption that it worked.
|
|
145
|
-
if (reply
|
|
166
|
+
if (reply === undefined || parseReply(reply).error) {
|
|
167
|
+
if (request.closeOnSettle)
|
|
168
|
+
throw new HerdrWriterCloseError(tabId);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
146
171
|
untrackPane(tabId);
|
|
172
|
+
}
|
|
147
173
|
}
|
|
148
174
|
// There is no agent in this pane to ask, so the staged prompt has no reader — remove it. Kept only under
|
|
149
175
|
// `keepPane`, where the operator asked to inspect whatever exists.
|
|
@@ -175,18 +201,21 @@ export async function runHerdrPane(request) {
|
|
|
175
201
|
const cleanup = async (settledCleanly) => {
|
|
176
202
|
if (request.keepPane)
|
|
177
203
|
return;
|
|
178
|
-
if (settledCleanly)
|
|
204
|
+
if (settledCleanly && !request.closeOnSettle)
|
|
179
205
|
return;
|
|
180
206
|
if (!tabId)
|
|
181
207
|
return;
|
|
182
208
|
const reply = await exec(["tab", "close", tabId]).catch(() => undefined);
|
|
183
|
-
// Untracked only if provably closed — R-62's rule. A close
|
|
184
|
-
//
|
|
185
|
-
if (reply
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
209
|
+
// Untracked only if provably closed — R-62's rule. A writer close failure must retain the lease;
|
|
210
|
+
// otherwise a still-promptable pane can overlap the successor admitted by a clean release.
|
|
211
|
+
if (reply === undefined || parseReply(reply).error) {
|
|
212
|
+
if (request.closeOnSettle)
|
|
213
|
+
throw new HerdrWriterCloseError(tabId);
|
|
214
|
+
return;
|
|
189
215
|
}
|
|
216
|
+
untrackPane(tabId);
|
|
217
|
+
if (promptDir)
|
|
218
|
+
await rm(promptDir, { recursive: true, force: true }).catch(() => undefined);
|
|
190
219
|
};
|
|
191
220
|
// ADR-0032: the pane exists and has a name, so tell the caller NOW. A pane id that arrives with the result is
|
|
192
221
|
// useless — the point is switching to a child while it is still working. Guarded because a renderer must not
|
package/dist/run-herdr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-herdr.js","sourceRoot":"","sources":["../src/run-herdr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAEtC,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EAAE,WAAW,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;GAKG;AACH,OAAO,EAAkB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5D,gHAAgH;AAChH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,wGAAwG;AACxG,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD;;;;;GAKG;AACH,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAmB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"run-herdr.js","sourceRoot":"","sources":["../src/run-herdr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type LeaseReleaseOutcome, type WorkspaceLease } from "./lease-record.ts";
|
|
2
|
+
export type { LeaseReleaseOutcome, WorkspaceLease } from "./lease-record.ts";
|
|
3
|
+
import type { ValidatedWorkspace, WorkspaceAccess } from "./workspace.ts";
|
|
4
|
+
export declare const ENV_WORKSPACE_LEASE_DIR = "PI_GRANTS_WORKSPACE_LEASE_DIR";
|
|
5
|
+
export declare function defaultWorkspaceLeaseDir(env?: NodeJS.ProcessEnv): string;
|
|
6
|
+
/**
|
|
7
|
+
* The ledger outcome for a release. ONE definition, exported, because two call sites had their own copies
|
|
8
|
+
* and the check runner's copy asserted `released` unconditionally — reproducing in the evidence path the
|
|
9
|
+
* exact defect this union was added to expose (R-100/R-103).
|
|
10
|
+
*/
|
|
11
|
+
export declare function leaseReleaseLedgerOutcome(outcome: LeaseReleaseOutcome | "retained", reason: string): "timeout" | "released" | "released-unrecorded" | "lost" | "retained" | "uncontended";
|
|
12
|
+
/**
|
|
13
|
+
* `acquired` must mean the kernel actually excluded somebody. A read lease takes no lock (R-105), and an
|
|
14
|
+
* unreadable predecessor record is not proof of a crash (R-100) — so neither may be reported as one.
|
|
15
|
+
*/
|
|
16
|
+
export declare function leaseAcquisitionOutcome(access: "read" | "write", recovered: boolean | "unknown"): "acquired" | "uncontended" | "recovered";
|
|
17
|
+
export declare function acquireWorkspaceLease(input: {
|
|
18
|
+
workspace: ValidatedWorkspace;
|
|
19
|
+
access: WorkspaceAccess;
|
|
20
|
+
leaseDir: string;
|
|
21
|
+
ownerId: string;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
flockCommand?: string;
|
|
24
|
+
acquisitionTimeoutMs?: number;
|
|
25
|
+
/** Bound on the helper's `herdr tab close` retries before it releases the lock anyway (R-102). */
|
|
26
|
+
herdrCloseAttempts?: number;
|
|
27
|
+
}): Promise<WorkspaceLease>;
|
|
28
|
+
//# sourceMappingURL=workspace-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-lease.d.ts","sourceRoot":"","sources":["../src/workspace-lease.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAM7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE1E,eAAO,MAAM,uBAAuB,kCAAkC,CAAC;AAEvE,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAGrF;AAoBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,mBAAmB,GAAG,UAAU,EACzC,MAAM,EAAE,MAAM,GACb,SAAS,GAAG,UAAU,GAAG,qBAAqB,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,CAQtF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GAAG,OAAO,EACxB,SAAS,EAAE,OAAO,GAAG,SAAS,GAC7B,UAAU,GAAG,aAAa,GAAG,WAAW,CAG1C;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,SAAS,EAAE,kBAAkB,CAAC;IAC9B,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kGAAkG;IAClG,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GAAG,OAAO,CAAC,cAAc,CAAC,CA4N1B"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { atomicMetadata, leasePaths, readMetadata, } from "./lease-record.js";
|
|
3
|
+
import { once } from "node:events";
|
|
4
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { GovernanceRefusal, refusal } from "./refusals.js";
|
|
8
|
+
export const ENV_WORKSPACE_LEASE_DIR = "PI_GRANTS_WORKSPACE_LEASE_DIR";
|
|
9
|
+
export function defaultWorkspaceLeaseDir(env = process.env) {
|
|
10
|
+
const agentDir = env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
|
|
11
|
+
return env[ENV_WORKSPACE_LEASE_DIR] ?? join(agentDir, "pi-daddy", "workspace-leases");
|
|
12
|
+
}
|
|
13
|
+
const LEASE_READY = "PI_DADDY_LEASE_READY";
|
|
14
|
+
// The lock holder also owns crash cleanup for the governed child. If the parent dies, stdin closes;
|
|
15
|
+
// the helper signals the attached process, or closes the herdr tab, before releasing flock. A raw
|
|
16
|
+
// descendant deliberately detached by bash remains ADR-0012's OS-containment boundary, not a lease
|
|
17
|
+
// guarantee. The process branch SIGTERMs, escalates to SIGKILL at +500ms, and releases at +750ms
|
|
18
|
+
// WITHOUT confirming death (R-101). The herdr branch retries `tab close` a BOUNDED number of times
|
|
19
|
+
// and then releases anyway, leaving a marker file: an unreleasable lock strands a worktree forever
|
|
20
|
+
// with no in-product recovery, which is strictly worse than a recorded failure to close (R-102).
|
|
21
|
+
const HELPER_SOURCE = `
|
|
22
|
+
import { execFile } from "node:child_process";
|
|
23
|
+
import { writeFileSync } from "node:fs";
|
|
24
|
+
let clean=false, target=null, buffered="";
|
|
25
|
+
process.stdout.write(${JSON.stringify(`${LEASE_READY}:`)}+process.pid+"\\n");
|
|
26
|
+
process.stdin.setEncoding("utf8");
|
|
27
|
+
process.stdin.on("data",chunk=>{buffered+=chunk;for(;;){const i=buffered.indexOf("\\n");if(i<0)break;const line=buffered.slice(0,i);buffered=buffered.slice(i+1);try{const value=JSON.parse(line);if(value.release)clean=true;else if(value.process_pid)target={process_pid:value.process_pid};else if(value.herdr_tab)target={herdr_tab:value.herdr_tab};}catch{}}});
|
|
28
|
+
process.stdin.on("end",()=>{if(clean||!target)return process.exit(0);if(target.process_pid){try{process.kill(target.process_pid,"SIGTERM")}catch{return process.exit(0)}setTimeout(()=>{try{process.kill(target.process_pid,"SIGKILL")}catch{}},500);return setTimeout(()=>process.exit(0),750);}let left=Number(process.env.PI_DADDY_LEASE_CLOSE_ATTEMPTS||10);const giveUp=()=>{try{if(process.env.PI_DADDY_LEASE_MARKER)writeFileSync(process.env.PI_DADDY_LEASE_MARKER,JSON.stringify({reason:"herdr-close-failed",herdr_tab:target.herdr_tab})+"\\n")}catch{}process.exit(0)};const close=()=>execFile("herdr",["tab","close",target.herdr_tab],error=>{if(!error)return process.exit(0);if(--left<=0)return giveUp();setTimeout(close,1000)});close();});
|
|
29
|
+
process.stdin.resume();`;
|
|
30
|
+
/**
|
|
31
|
+
* The ledger outcome for a release. ONE definition, exported, because two call sites had their own copies
|
|
32
|
+
* and the check runner's copy asserted `released` unconditionally — reproducing in the evidence path the
|
|
33
|
+
* exact defect this union was added to expose (R-100/R-103).
|
|
34
|
+
*/
|
|
35
|
+
export function leaseReleaseLedgerOutcome(outcome, reason) {
|
|
36
|
+
if (outcome === "retained")
|
|
37
|
+
return "retained";
|
|
38
|
+
if (outcome === "lost")
|
|
39
|
+
return "lost";
|
|
40
|
+
if (outcome === "released-unrecorded")
|
|
41
|
+
return "released-unrecorded";
|
|
42
|
+
if (outcome === "not-held")
|
|
43
|
+
return "uncontended";
|
|
44
|
+
// `released-superseded` is a clean handover as far as the ledger is concerned: the lock went back and the
|
|
45
|
+
// record is correct — it just belongs to somebody else now.
|
|
46
|
+
return reason === "timeout" ? "timeout" : "released";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `acquired` must mean the kernel actually excluded somebody. A read lease takes no lock (R-105), and an
|
|
50
|
+
* unreadable predecessor record is not proof of a crash (R-100) — so neither may be reported as one.
|
|
51
|
+
*/
|
|
52
|
+
export function leaseAcquisitionOutcome(access, recovered) {
|
|
53
|
+
if (access === "read")
|
|
54
|
+
return "uncontended";
|
|
55
|
+
return recovered === true ? "recovered" : "acquired";
|
|
56
|
+
}
|
|
57
|
+
export async function acquireWorkspaceLease(input) {
|
|
58
|
+
if (input.access === "read") {
|
|
59
|
+
return {
|
|
60
|
+
workspace: input.workspace,
|
|
61
|
+
access: "read",
|
|
62
|
+
ownerId: input.ownerId,
|
|
63
|
+
recovered: false,
|
|
64
|
+
attachProcess: () => { },
|
|
65
|
+
attachHerdrTab: () => { },
|
|
66
|
+
markRetained: async () => { },
|
|
67
|
+
readCloseFailure: async () => null,
|
|
68
|
+
lost: new Promise(() => { }),
|
|
69
|
+
// No kernel lock was ever taken, so there is no handover to claim (R-105, release side).
|
|
70
|
+
release: async () => "not-held",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (input.signal?.aborted) {
|
|
74
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_WRITE_CONFLICT", `writer lease for ${input.workspace.workspaceId} was cancelled before acquisition`));
|
|
75
|
+
}
|
|
76
|
+
await mkdir(input.leaseDir, { recursive: true, mode: 0o700 });
|
|
77
|
+
const paths = leasePaths(input.leaseDir, input.workspace.root);
|
|
78
|
+
const { spawn } = await import("node:child_process");
|
|
79
|
+
const holder = spawn(input.flockCommand ?? "flock", [
|
|
80
|
+
"--exclusive", "--nonblock", "--conflict-exit-code", "73", paths.lock,
|
|
81
|
+
process.execPath, "--input-type=module", "-e", HELPER_SOURCE,
|
|
82
|
+
], {
|
|
83
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
84
|
+
env: { ...process.env, PI_DADDY_LEASE_MARKER: paths.marker, PI_DADDY_LEASE_CLOSE_ATTEMPTS: String(input.herdrCloseAttempts ?? 10) },
|
|
85
|
+
// Own process group, for two reasons. It lets teardown kill `flock` AND the helper holding the lock
|
|
86
|
+
// file descriptor as one unit even before the helper has reported its pid (R-99), and it stops a
|
|
87
|
+
// stray group signal — a terminal Ctrl-C, a closed window — from releasing a live writer's lock as
|
|
88
|
+
// a side effect.
|
|
89
|
+
detached: true,
|
|
90
|
+
});
|
|
91
|
+
const timeoutMs = input.acquisitionTimeoutMs ?? 2000;
|
|
92
|
+
let ready = false;
|
|
93
|
+
let helperPid;
|
|
94
|
+
let stderr = "";
|
|
95
|
+
/**
|
|
96
|
+
* Kill the whole holder GROUP — one signal, no ordering. (The pid-by-pid fallback below is the
|
|
97
|
+
* only path that kills in sequence, and only when the group is already reaped.) `flock` does not pass `--close`, so the helper inherits
|
|
98
|
+
* the lock file descriptor and holds the lock in its own right — killing only `flock` leaves the
|
|
99
|
+
* lock HELD by an orphan, and every later acquisition then reports WORKSPACE_WRITE_CONFLICT, which
|
|
100
|
+
* is the one message an operator would use to conclude another agent is writing. Measured in
|
|
101
|
+
* `docs/probes/g35-flock-fd-inheritance` (R-99).
|
|
102
|
+
*/
|
|
103
|
+
const hardKill = () => {
|
|
104
|
+
// The GROUP, so this works on the readiness-timeout path too — there `helperPid` is usually still
|
|
105
|
+
// unknown, and killing only the wrapper leaves a half-booted helper free to inherit the lock file
|
|
106
|
+
// descriptor and hold it forever. Fall back to individual pids if the group is already reaped.
|
|
107
|
+
if (holder.pid !== undefined) {
|
|
108
|
+
try {
|
|
109
|
+
process.kill(-holder.pid, "SIGKILL");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
catch { /* group gone */ }
|
|
113
|
+
}
|
|
114
|
+
if (Number.isInteger(helperPid)) {
|
|
115
|
+
try {
|
|
116
|
+
process.kill(helperPid, "SIGKILL");
|
|
117
|
+
}
|
|
118
|
+
catch { /* already gone */ }
|
|
119
|
+
}
|
|
120
|
+
holder.kill("SIGKILL");
|
|
121
|
+
};
|
|
122
|
+
holder.stderr?.on("data", (chunk) => { stderr += String(chunk); });
|
|
123
|
+
try {
|
|
124
|
+
await new Promise((resolveReady, rejectReady) => {
|
|
125
|
+
const timer = setTimeout(() => rejectReady(new GovernanceRefusal(refusal("WORKSPACE_LEASE_STALE", `writer lease helper did not become ready within ${timeoutMs}ms`))), timeoutMs);
|
|
126
|
+
const cleanup = () => {
|
|
127
|
+
clearTimeout(timer);
|
|
128
|
+
input.signal?.removeEventListener("abort", onAbort);
|
|
129
|
+
};
|
|
130
|
+
const onAbort = () => rejectReady(new GovernanceRefusal(refusal("WORKSPACE_WRITE_CONFLICT", `writer lease for ${input.workspace.workspaceId} was cancelled before acquisition`)));
|
|
131
|
+
input.signal?.addEventListener("abort", onAbort, { once: true });
|
|
132
|
+
holder.once("error", (error) => {
|
|
133
|
+
cleanup();
|
|
134
|
+
rejectReady(new GovernanceRefusal(refusal("WORKSPACE_LEASE_STALE", `workspace writer leases require a working flock command (${String(error)})`)));
|
|
135
|
+
});
|
|
136
|
+
holder.once("close", (code) => {
|
|
137
|
+
if (ready)
|
|
138
|
+
return;
|
|
139
|
+
cleanup();
|
|
140
|
+
const codeName = code === 73 ? "WORKSPACE_WRITE_CONFLICT" : "WORKSPACE_LEASE_STALE";
|
|
141
|
+
rejectReady(new GovernanceRefusal(refusal(codeName, code === 73
|
|
142
|
+
? `workspace ${input.workspace.workspaceId} already has an active pi-daddy-governed writer`
|
|
143
|
+
: `workspace lease helper exited before acquisition${stderr ? ` (${stderr.trim()})` : ""}`, { workspace_id: input.workspace.workspaceId, root: input.workspace.root })));
|
|
144
|
+
});
|
|
145
|
+
holder.stdout?.on("data", (chunk) => {
|
|
146
|
+
const output = String(chunk);
|
|
147
|
+
if (!output.includes(LEASE_READY) || ready)
|
|
148
|
+
return;
|
|
149
|
+
helperPid = Number(output.match(new RegExp(`${LEASE_READY}:(\\d+)`))?.[1]);
|
|
150
|
+
ready = true;
|
|
151
|
+
cleanup();
|
|
152
|
+
resolveReady();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
hardKill();
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
const previous = await readMetadata(paths.metadata);
|
|
161
|
+
// "malformed" is not "no prior owner": an unreadable record cannot prove a clean handover (R-100).
|
|
162
|
+
const recovered = previous === "malformed" ? "unknown" : previous?.state === "active";
|
|
163
|
+
const token = randomUUID();
|
|
164
|
+
const metadata = {
|
|
165
|
+
version: 1,
|
|
166
|
+
state: "active",
|
|
167
|
+
token,
|
|
168
|
+
owner_id: input.ownerId,
|
|
169
|
+
workspace_id: input.workspace.workspaceId,
|
|
170
|
+
root: input.workspace.root,
|
|
171
|
+
pid: Number.isInteger(helperPid) ? helperPid : (holder.pid ?? process.pid),
|
|
172
|
+
acquired_at: new Date().toISOString(),
|
|
173
|
+
};
|
|
174
|
+
try {
|
|
175
|
+
await atomicMetadata(paths.metadata, metadata);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
holder.stdin?.end();
|
|
179
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_LEASE_STALE", `acquired the kernel writer lock but could not record its owner (${String(error)})`, { workspace_id: input.workspace.workspaceId, root: input.workspace.root }));
|
|
180
|
+
}
|
|
181
|
+
// TWO variables, deliberately. `releasing` goes up the instant release begins, because the handshake
|
|
182
|
+
// below closes the helper on purpose — and if `lost` could still fire during it, an intentional release
|
|
183
|
+
// would report itself as a lost lease. `settled` memoizes the ANSWER, so a second call cannot invent a
|
|
184
|
+
// clean handover. Collapsing these into one flag set at the end broke every check-runner test.
|
|
185
|
+
let releasing = false;
|
|
186
|
+
let settled;
|
|
187
|
+
let lose;
|
|
188
|
+
const lost = new Promise((resolveLost) => { lose = resolveLost; });
|
|
189
|
+
const lostError = () => new Error(`workspace writer lease helper exited for ${input.workspace.workspaceId}`);
|
|
190
|
+
holder.once("close", () => { if (!releasing)
|
|
191
|
+
lose(lostError()); });
|
|
192
|
+
if (holder.exitCode !== null || holder.signalCode !== null)
|
|
193
|
+
queueMicrotask(() => lose(lostError()));
|
|
194
|
+
const attach = (value) => {
|
|
195
|
+
if (releasing || holder.exitCode !== null || holder.signalCode !== null || !holder.stdin?.writable) {
|
|
196
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_LEASE_STALE", `writer lease for ${input.workspace.workspaceId} was lost before child attachment`));
|
|
197
|
+
}
|
|
198
|
+
holder.stdin.write(`${JSON.stringify(value)}\n`);
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
workspace: input.workspace,
|
|
202
|
+
access: "write",
|
|
203
|
+
ownerId: input.ownerId,
|
|
204
|
+
recovered,
|
|
205
|
+
attachProcess(pid) { attach({ process_pid: pid }); },
|
|
206
|
+
attachHerdrTab(tabId) { attach({ herdr_tab: tabId }); },
|
|
207
|
+
lost,
|
|
208
|
+
async markRetained(reason = "retained") {
|
|
209
|
+
// Deliberately does NOT touch the kernel lock or the helper: the pane may still be live. It only
|
|
210
|
+
// stops the record from looking like a crash.
|
|
211
|
+
const current = await readMetadata(paths.metadata);
|
|
212
|
+
if (current !== "malformed" && current?.token === token) {
|
|
213
|
+
await atomicMetadata(paths.metadata, {
|
|
214
|
+
...metadata, state: "released", released_at: new Date().toISOString(), release_reason: `retained:${reason}`,
|
|
215
|
+
}).catch(() => undefined);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
async readCloseFailure() {
|
|
219
|
+
try {
|
|
220
|
+
return JSON.parse(await readFile(paths.marker, "utf8"));
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
async release(reason = "completed") {
|
|
227
|
+
// Memoized, not a boolean. A second call used to answer "released" whatever the first returned, so a
|
|
228
|
+
// retry — or a `finally` after an explicit release — read a clean handover that never happened.
|
|
229
|
+
if (settled)
|
|
230
|
+
return settled;
|
|
231
|
+
releasing = true;
|
|
232
|
+
// Already gone: this owner never released anything, and saying so is the caller's business to
|
|
233
|
+
// record. Throwing here discarded completed work and masked the real error (R-99).
|
|
234
|
+
if (holder.exitCode !== null || holder.signalCode !== null)
|
|
235
|
+
return (settled = "lost");
|
|
236
|
+
// Default FALSE: "recorded" must mean this owner actually wrote its own handover. Anything else —
|
|
237
|
+
// an unreadable record, or a successor's token in place of ours — means the lock goes back but the
|
|
238
|
+
// record does not say so, and the NEXT owner will report a recovery that never happened unless the
|
|
239
|
+
// caller ledgers it (R-100). Only the current token may mark the handover, so a stale lease object
|
|
240
|
+
// can never overwrite a live successor.
|
|
241
|
+
// Three outcomes, because they call for three different responses: we wrote our handover; a
|
|
242
|
+
// successor already owns the record and we correctly left it alone; or the record is unreadable or
|
|
243
|
+
// unwritable and somebody has to be told.
|
|
244
|
+
let how = "released-unrecorded";
|
|
245
|
+
const current = await readMetadata(paths.metadata);
|
|
246
|
+
if (current !== "malformed" && current?.token === token) {
|
|
247
|
+
try {
|
|
248
|
+
await atomicMetadata(paths.metadata, {
|
|
249
|
+
...metadata,
|
|
250
|
+
state: "released",
|
|
251
|
+
released_at: new Date().toISOString(),
|
|
252
|
+
release_reason: reason,
|
|
253
|
+
});
|
|
254
|
+
how = "released";
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
how = "released-unrecorded";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if (current !== "malformed" && current !== null) {
|
|
261
|
+
// A live successor's record. Declining to overwrite it is the token guard working, not a fault.
|
|
262
|
+
how = "released-superseded";
|
|
263
|
+
}
|
|
264
|
+
holder.stdin?.write(`${JSON.stringify({ release: true })}\n`);
|
|
265
|
+
holder.stdin?.end();
|
|
266
|
+
if (holder.exitCode === null && holder.signalCode === null) {
|
|
267
|
+
await Promise.race([once(holder, "close"), new Promise((resolveWait) => setTimeout(resolveWait, 1000))]);
|
|
268
|
+
}
|
|
269
|
+
// The helper holds the lock fd in its own right, so the wrapper alone is not enough (R-99).
|
|
270
|
+
if (holder.exitCode === null && holder.signalCode === null)
|
|
271
|
+
hardKill();
|
|
272
|
+
return (settled = how);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=workspace-lease.js.map
|