harnery 0.43.0 → 0.45.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/README.md +3 -3
- package/dist/commander.js +1 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +41 -48
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +38 -11
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +10 -0
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +22 -7
- package/dist/commands/files.d.ts +2 -2
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +7 -4
- package/dist/commands/governor.js +22 -10
- package/dist/commands/inbox.d.ts +1 -1
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +55 -2
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +28 -4
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +26 -17
- package/dist/commands/supervisor.d.ts.map +1 -1
- package/dist/commands/supervisor.js +7 -2
- package/dist/commands/toc.d.ts +14 -0
- package/dist/commands/toc.d.ts.map +1 -1
- package/dist/commands/toc.js +7 -4
- package/dist/commands/tunnel.d.ts +15 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +453 -153
- package/dist/commands/turn-rollback.d.ts +5 -0
- package/dist/commands/turn-rollback.d.ts.map +1 -0
- package/dist/commands/turn-rollback.js +76 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +68 -30
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +18 -0
- package/dist/core/agents/live-authority-v3.d.ts +1 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +11 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts +4 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/live-lifecycle-v3.js +28 -7
- package/dist/core/agents/mailbox.d.ts +9 -8
- package/dist/core/agents/mailbox.d.ts.map +1 -1
- package/dist/core/agents/mailbox.js +24 -17
- package/dist/core/agents/render/prompt-context.d.ts +2 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +8 -12
- package/dist/core/agents/render/session-context.d.ts +2 -8
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +7 -30
- package/dist/core/agents/rules/stop-hook.js +3 -3
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +25 -14
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +5 -0
- package/dist/core/agents/state/proc-start.d.ts +19 -1
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +46 -1
- package/dist/core/agents/state/process-handle.d.ts +26 -0
- package/dist/core/agents/state/process-handle.d.ts.map +1 -0
- package/dist/core/agents/state/process-handle.js +121 -0
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +180 -70
- package/dist/core/agents/state/unchanged-file.d.ts +44 -0
- package/dist/core/agents/state/unchanged-file.d.ts.map +1 -0
- package/dist/core/agents/state/unchanged-file.js +390 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +2 -1
- package/dist/core/context/index.d.ts +22 -10
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +381 -119
- package/dist/core/context/observation.d.ts +26 -0
- package/dist/core/context/observation.d.ts.map +1 -0
- package/dist/core/context/observation.js +11 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +25 -14
- package/dist/core/diagnostics/path-identity.d.ts +3 -0
- package/dist/core/diagnostics/path-identity.d.ts.map +1 -0
- package/dist/core/diagnostics/path-identity.js +12 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -1
- package/dist/core/diagnostics/sanitize.js +4 -3
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +29 -0
- package/dist/core/events/v3/generation-custody.d.ts +5 -0
- package/dist/core/events/v3/generation-custody.d.ts.map +1 -0
- package/dist/core/events/v3/generation-custody.js +50 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +1 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +7 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +77 -64
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +14 -1
- package/dist/core/governor/service-read.d.ts +10 -2
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +105 -22
- package/dist/core/governor/service.d.ts +20 -2
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +72 -47
- package/dist/core/hooks/cli.js +33 -5
- package/dist/core/inbox/contract.d.ts +2 -1
- package/dist/core/inbox/contract.d.ts.map +1 -1
- package/dist/core/inbox/index.d.ts +2 -0
- package/dist/core/inbox/index.d.ts.map +1 -1
- package/dist/core/inbox/index.js +2 -0
- package/dist/core/inbox/peer-messages.d.ts +37 -0
- package/dist/core/inbox/peer-messages.d.ts.map +1 -0
- package/dist/core/inbox/peer-messages.js +72 -0
- package/dist/core/inbox/service.d.ts +8 -1
- package/dist/core/inbox/service.d.ts.map +1 -1
- package/dist/core/inbox/service.js +67 -21
- package/dist/core/inbox/targets.d.ts +22 -0
- package/dist/core/inbox/targets.d.ts.map +1 -0
- package/dist/core/inbox/targets.js +108 -0
- package/dist/core/inbox/watcher.js +7 -3
- package/dist/core/journal/index.d.ts.map +1 -1
- package/dist/core/journal/index.js +17 -2
- package/dist/core/resources/contract.d.ts +3 -0
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/service-status.d.ts +14 -1
- package/dist/core/resources/service-status.d.ts.map +1 -1
- package/dist/core/resources/service-status.js +23 -13
- package/dist/core/resources/service.d.ts +7 -13
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +34 -91
- package/dist/core/resources/status.d.ts +2 -5
- package/dist/core/resources/status.d.ts.map +1 -1
- package/dist/core/resources/status.js +36 -7
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +2 -9
- package/dist/core/servers/index.d.ts +34 -22
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +297 -144
- package/dist/core/servers/tunnels.d.ts +7 -7
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +47 -10
- package/dist/core/supervisor/contract.d.ts +12 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.d.ts.map +1 -1
- package/dist/core/supervisor/explanations.js +2 -1
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +54 -9
- package/dist/core/supervisor/service.d.ts +7 -1
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +59 -29
- package/dist/core/supervisor/services.d.ts.map +1 -1
- package/dist/core/supervisor/services.js +22 -1
- package/dist/core/supervisor/status.d.ts +17 -2
- package/dist/core/supervisor/status.d.ts.map +1 -1
- package/dist/core/supervisor/status.js +70 -12
- package/dist/core/supervisor/timeline.d.ts.map +1 -1
- package/dist/core/supervisor/timeline.js +2 -1
- package/dist/core/turn-rollback/content.d.ts +53 -0
- package/dist/core/turn-rollback/content.d.ts.map +1 -0
- package/dist/core/turn-rollback/content.js +396 -0
- package/dist/core/turn-rollback/index.d.ts +72 -0
- package/dist/core/turn-rollback/index.d.ts.map +1 -0
- package/dist/core/turn-rollback/index.js +443 -0
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +105 -32
- package/dist/core/workflow/failure-evidence.d.ts +16 -0
- package/dist/core/workflow/failure-evidence.d.ts.map +1 -0
- package/dist/core/workflow/failure-evidence.js +114 -0
- package/dist/core/workflow/index.d.ts +5 -3
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +3 -2
- package/dist/core/workflow/live-session-v3.d.ts +6 -0
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +126 -5
- package/dist/core/workflow/proof.d.ts +5 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +115 -20
- package/dist/core/workflow/recovery-audit.d.ts +30 -0
- package/dist/core/workflow/recovery-audit.d.ts.map +1 -0
- package/dist/core/workflow/recovery-audit.js +116 -0
- package/dist/core/workflow/run-state.d.ts +20 -1
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +141 -32
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +19 -0
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +13 -0
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +19 -0
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +14 -0
- package/dist/core/workflow/types.d.ts +64 -17
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.d.ts +0 -1
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/index.js +0 -1
- package/dist/core/workflow/workspaces/leases.d.ts +3 -1
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +30 -16
- package/dist/core/workflow/workspaces/local-git.d.ts +6 -2
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +328 -8
- package/dist/core/workflow/workspaces/ownership.d.ts +11 -0
- package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/ownership.js +194 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts +40 -0
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/reclaim.js +14 -0
- package/dist/core/workflow/workspaces/recovery.d.ts +2 -0
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +42 -10
- package/dist/core/workflow/workspaces/state.d.ts +1 -0
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +21 -1
- package/dist/lib/browser/windows-chrome.d.ts +100 -12
- package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
- package/dist/lib/browser/windows-chrome.js +262 -73
- package/dist/lib/docs-links.d.ts.map +1 -1
- package/dist/lib/docs-links.js +45 -2
- package/dist/lib/guarded-remove.d.ts +7 -0
- package/dist/lib/guarded-remove.d.ts.map +1 -1
- package/dist/lib/guarded-remove.js +106 -12
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +4 -0
- package/dist/lib/tunnel/state.d.ts +13 -6
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +58 -12
- package/dist/lib/zip/index.d.ts +41 -0
- package/dist/lib/zip/index.d.ts.map +1 -0
- package/dist/lib/zip/index.js +398 -0
- package/package.json +12 -1
- package/src/commander.ts +10 -0
- package/src/commands/agents.ts +54 -63
- package/src/commands/browse.ts +50 -14
- package/src/commands/diagnostics.ts +10 -0
- package/src/commands/doctor.ts +26 -7
- package/src/commands/files.ts +13 -5
- package/src/commands/governor.ts +23 -10
- package/src/commands/inbox.ts +52 -2
- package/src/commands/rm.ts +43 -4
- package/src/commands/servers.ts +27 -26
- package/src/commands/supervisor.ts +7 -2
- package/src/commands/toc.ts +14 -6
- package/src/commands/tunnel.ts +533 -166
- package/src/commands/turn-rollback.ts +111 -0
- package/src/commands/workflow.ts +89 -30
- package/src/core/agents/coord-client.ts +20 -0
- package/src/core/agents/live-authority-v3.ts +17 -0
- package/src/core/agents/live-lifecycle-v3.ts +52 -14
- package/src/core/agents/mailbox.ts +26 -17
- package/src/core/agents/render/prompt-context.ts +10 -12
- package/src/core/agents/render/session-context.ts +9 -32
- package/src/core/agents/rules/stop-hook.ts +3 -3
- package/src/core/agents/state/heartbeat-writer.ts +29 -12
- package/src/core/agents/state/live-coordination-writer.ts +29 -0
- package/src/core/agents/state/pidmap.ts +13 -0
- package/src/core/agents/state/proc-start.ts +62 -2
- package/src/core/agents/state/process-handle.ts +165 -0
- package/src/core/agents/state/stale-sweep.ts +247 -82
- package/src/core/agents/state/unchanged-file.ts +456 -0
- package/src/core/artifacts/delivery-card.ts +7 -1
- package/src/core/context/index.ts +446 -136
- package/src/core/context/observation.ts +29 -0
- package/src/core/diagnostics/bundle.ts +23 -18
- package/src/core/diagnostics/path-identity.ts +15 -0
- package/src/core/diagnostics/sanitize.ts +4 -3
- package/src/core/events/v3/authority-outbox.ts +56 -0
- package/src/core/events/v3/generation-custody.ts +59 -0
- package/src/core/events/v3/producers/coordination-recorder.ts +15 -0
- package/src/core/events/v3/producers/recorder.ts +94 -68
- package/src/core/governor/planning.ts +20 -8
- package/src/core/governor/service-read.ts +128 -20
- package/src/core/governor/service.ts +119 -42
- package/src/core/hooks/cli.ts +33 -5
- package/src/core/inbox/contract.ts +2 -1
- package/src/core/inbox/index.ts +2 -0
- package/src/core/inbox/peer-messages.ts +94 -0
- package/src/core/inbox/service.ts +88 -22
- package/src/core/inbox/targets.ts +148 -0
- package/src/core/inbox/watcher.ts +8 -9
- package/src/core/journal/index.ts +19 -2
- package/src/core/resources/contract.ts +4 -0
- package/src/core/resources/service-status.ts +35 -12
- package/src/core/resources/service.ts +57 -95
- package/src/core/resources/status.ts +57 -8
- package/src/core/semantic/service.ts +2 -8
- package/src/core/servers/index.ts +376 -141
- package/src/core/servers/tunnels.ts +57 -13
- package/src/core/supervisor/contract.ts +13 -0
- package/src/core/supervisor/explanations.ts +4 -1
- package/src/core/supervisor/findings.ts +68 -10
- package/src/core/supervisor/service.ts +87 -26
- package/src/core/supervisor/services.ts +26 -8
- package/src/core/supervisor/status.ts +89 -12
- package/src/core/supervisor/timeline.ts +2 -1
- package/src/core/turn-rollback/content.ts +499 -0
- package/src/core/turn-rollback/index.ts +580 -0
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +131 -49
- package/src/core/workflow/failure-evidence.ts +141 -0
- package/src/core/workflow/index.ts +12 -2
- package/src/core/workflow/live-session-v3.ts +146 -5
- package/src/core/workflow/proof.ts +134 -26
- package/src/core/workflow/recovery-audit.ts +181 -0
- package/src/core/workflow/run-state.ts +165 -34
- package/src/core/workflow/spawn-claude.ts +18 -0
- package/src/core/workflow/spawn-codex.ts +13 -0
- package/src/core/workflow/spawn-cursor.ts +18 -0
- package/src/core/workflow/spawn-opencode.ts +14 -0
- package/src/core/workflow/types.ts +51 -17
- package/src/core/workflow/workspaces/index.ts +0 -1
- package/src/core/workflow/workspaces/leases.ts +48 -17
- package/src/core/workflow/workspaces/local-git.ts +388 -7
- package/src/core/workflow/workspaces/ownership.ts +232 -0
- package/src/core/workflow/workspaces/reclaim.ts +62 -0
- package/src/core/workflow/workspaces/recovery.ts +45 -10
- package/src/core/workflow/workspaces/state.ts +20 -0
- package/src/lib/browser/windows-chrome.ts +346 -86
- package/src/lib/docs-links.ts +49 -2
- package/src/lib/guarded-remove.ts +132 -14
- package/src/lib/identities/assume.ts +4 -0
- package/src/lib/tunnel/state.ts +70 -15
- package/src/lib/zip/index.ts +483 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { lstatSync, readdirSync, readFileSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { readJsonRecord, stableDigest } from "../durable-record.js";
|
|
4
|
+
import { acquireNoClobberLease } from "./leases.js";
|
|
5
|
+
import { containsPath } from "./paths.js";
|
|
6
|
+
import { isWorkspaceAllocationRequest } from "./validate.js";
|
|
7
|
+
const STALE_MS = 5 * 60 * 1_000;
|
|
8
|
+
const RESERVATION_SCOPE = "workspace-reclaim";
|
|
9
|
+
function leaseRoot(coordRoot, providerId) {
|
|
10
|
+
return join(resolve(coordRoot), ".harnery", "workspaces", providerId, ".leases");
|
|
11
|
+
}
|
|
12
|
+
/** Serialize only publication and reservation registration, never Git work. */
|
|
13
|
+
function withPublicationGate(coordRoot, providerId, operation) {
|
|
14
|
+
const authority = stableDigest({ provider_id: providerId, scope: "workspace-publication" });
|
|
15
|
+
const gate = acquireNoClobberLease({
|
|
16
|
+
path: join(leaseRoot(coordRoot, providerId), "publication.lock"),
|
|
17
|
+
scope: "workspace-publication",
|
|
18
|
+
authoritySha256: authority,
|
|
19
|
+
staleAfterMs: STALE_MS,
|
|
20
|
+
validateStaleOwner: (owner) => owner.authority_sha256 === authority,
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
return operation();
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
gate.release();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function reservationPath(coordRoot, claim) {
|
|
30
|
+
return join(leaseRoot(coordRoot, claim.provider_id), `reclaim-${claim.binding_id}.lock`);
|
|
31
|
+
}
|
|
32
|
+
function acquireReservation(coordRoot, claim) {
|
|
33
|
+
const authority = stableDigest(claim);
|
|
34
|
+
return acquireNoClobberLease({
|
|
35
|
+
path: reservationPath(coordRoot, claim),
|
|
36
|
+
scope: RESERVATION_SCOPE,
|
|
37
|
+
authoritySha256: authority,
|
|
38
|
+
staleAfterMs: STALE_MS,
|
|
39
|
+
metadata: { binding_id: claim.binding_id, request_sha256: claim.request_sha256 },
|
|
40
|
+
validateStaleOwner: (owner) => owner.authority_sha256 === authority &&
|
|
41
|
+
owner.metadata?.binding_id === claim.binding_id &&
|
|
42
|
+
owner.metadata?.request_sha256 === claim.request_sha256,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** The immutable claim is the authority; the lease reserves its destructive path. */
|
|
46
|
+
export function reserveWorkspaceReclaim(coordRoot, claim) {
|
|
47
|
+
assertClaimAuthority(claim, claim.provider_id, claim.binding_id);
|
|
48
|
+
const lease = withPublicationGate(coordRoot, claim.provider_id, () => acquireReservation(coordRoot, claim));
|
|
49
|
+
return {
|
|
50
|
+
assertCurrent() {
|
|
51
|
+
const path = reservationPath(coordRoot, claim);
|
|
52
|
+
const current = join(path, "current");
|
|
53
|
+
const pin = join(path, lease.owner.owner_file);
|
|
54
|
+
const a = lstatSync(current, { bigint: true });
|
|
55
|
+
const b = lstatSync(pin, { bigint: true });
|
|
56
|
+
if (!a.isFile() ||
|
|
57
|
+
!b.isFile() ||
|
|
58
|
+
a.dev !== b.dev ||
|
|
59
|
+
a.ino !== b.ino ||
|
|
60
|
+
readFileSync(current, "utf8") !== readFileSync(pin, "utf8") ||
|
|
61
|
+
stableDigest(readJsonRecord(current, "reclaim reservation")) !== stableDigest(lease.owner)) {
|
|
62
|
+
throw new Error("workspace reclaim reservation owner changed");
|
|
63
|
+
}
|
|
64
|
+
const persisted = readJsonRecord(join(dirname(dirname(path)), claim.binding_id, "claim.json"), "reserved workspace claim");
|
|
65
|
+
if (stableDigest(persisted) !== stableDigest(claim)) {
|
|
66
|
+
throw new Error("workspace reclaim reservation claim changed");
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
release: () => lease.release(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function publishWorkspaceClaim(coordRoot, claim, publish) {
|
|
73
|
+
assertClaimAuthority(claim, claim.provider_id, claim.binding_id);
|
|
74
|
+
return withPublicationGate(coordRoot, claim.provider_id, () => {
|
|
75
|
+
for (const entry of readdirSync(leaseRoot(coordRoot, claim.provider_id), {
|
|
76
|
+
withFileTypes: true,
|
|
77
|
+
})) {
|
|
78
|
+
if (!entry.name.startsWith("reclaim-") || !entry.name.endsWith(".lock"))
|
|
79
|
+
continue;
|
|
80
|
+
if (!entry.isDirectory())
|
|
81
|
+
throw new Error("workspace reclaim reservation is not a directory");
|
|
82
|
+
const path = join(leaseRoot(coordRoot, claim.provider_id), entry.name);
|
|
83
|
+
const current = join(path, "current");
|
|
84
|
+
try {
|
|
85
|
+
lstatSync(current);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === "ENOENT")
|
|
89
|
+
continue;
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
const id = entry.name.slice("reclaim-".length, -".lock".length);
|
|
93
|
+
const reserved = readJsonRecord(join(dirname(leaseRoot(coordRoot, claim.provider_id)), id, "claim.json"), "reserved workspace claim");
|
|
94
|
+
assertClaimAuthority(reserved, claim.provider_id, id);
|
|
95
|
+
// Unknown reservation authority is never interpreted as an unrelated owner.
|
|
96
|
+
const owner = readJsonRecord(current, "reclaim reservation");
|
|
97
|
+
if (owner.schema_version !== 1 ||
|
|
98
|
+
typeof owner.owner_id !== "string" ||
|
|
99
|
+
!/^[a-f0-9-]{36}$/.test(owner.owner_id) ||
|
|
100
|
+
owner.owner_file !== `owner-${owner.owner_id}.json` ||
|
|
101
|
+
!Number.isSafeInteger(owner.pid) ||
|
|
102
|
+
owner.pid <= 0 ||
|
|
103
|
+
typeof owner.host !== "string" ||
|
|
104
|
+
owner.host.length === 0 ||
|
|
105
|
+
!Number.isFinite(Date.parse(owner.created_at)) ||
|
|
106
|
+
!Number.isFinite(Date.parse(owner.expires_at)) ||
|
|
107
|
+
Date.parse(owner.expires_at) < Date.parse(owner.created_at) ||
|
|
108
|
+
owner.scope !== RESERVATION_SCOPE ||
|
|
109
|
+
owner.authority_sha256 !== stableDigest(reserved) ||
|
|
110
|
+
owner.metadata?.binding_id !== id ||
|
|
111
|
+
owner.metadata?.request_sha256 !== reserved.request_sha256) {
|
|
112
|
+
throw new Error("workspace reclaim reservation authority is unproven");
|
|
113
|
+
}
|
|
114
|
+
const a = lstatSync(current, { bigint: true });
|
|
115
|
+
const pin = join(path, owner.owner_file);
|
|
116
|
+
const b = lstatSync(pin, { bigint: true });
|
|
117
|
+
if (!a.isFile() ||
|
|
118
|
+
!b.isFile() ||
|
|
119
|
+
a.dev !== b.dev ||
|
|
120
|
+
a.ino !== b.ino ||
|
|
121
|
+
readFileSync(current, "utf8") !== readFileSync(pin, "utf8"))
|
|
122
|
+
throw new Error("workspace reclaim reservation owner is unproven");
|
|
123
|
+
if (!claimOverlapsWorkspace(claim, reserved.workspace_root))
|
|
124
|
+
continue;
|
|
125
|
+
// This succeeds only for an expired, provably dead, exact prior owner.
|
|
126
|
+
// It retires the reservation, never the immutable claim or resource.
|
|
127
|
+
const recovered = acquireReservation(coordRoot, reserved);
|
|
128
|
+
recovered.release();
|
|
129
|
+
}
|
|
130
|
+
return publish();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
export function assertClaimAuthority(claim, providerId, id) {
|
|
134
|
+
if (claim?.schema_version !== 1 ||
|
|
135
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(providerId) ||
|
|
136
|
+
claim.provider_id !== providerId ||
|
|
137
|
+
claim.provider_version !== "1" ||
|
|
138
|
+
claim.binding_id !== id ||
|
|
139
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(id) ||
|
|
140
|
+
!isWorkspaceAllocationRequest(claim.request) ||
|
|
141
|
+
claim.request.provider_id !== providerId ||
|
|
142
|
+
stableDigest(claim.request) !== claim.request_sha256 ||
|
|
143
|
+
!/^[a-f0-9]{64}$/.test(claim.recovery_token) ||
|
|
144
|
+
stableDigest(claim.writable_root) !== stableDigest(claim.request.selected_writable_root)) {
|
|
145
|
+
throw new Error("retained workspace claim authority is unproven");
|
|
146
|
+
}
|
|
147
|
+
for (const path of claimPaths(claim)) {
|
|
148
|
+
if (typeof path !== "string" || !isAbsolute(path) || resolve(path) !== path) {
|
|
149
|
+
throw new Error("retained workspace claim path is unproven");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!containsPath(claim.workspace_root, claim.active_root)) {
|
|
153
|
+
throw new Error("retained workspace active root escapes its claim");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function claimPaths(claim) {
|
|
157
|
+
return [
|
|
158
|
+
claim.workspace_root,
|
|
159
|
+
claim.active_root,
|
|
160
|
+
claim.repository?.source_root?.realpath,
|
|
161
|
+
claim.repository?.common_dir?.realpath,
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
/** Include absent descendants without losing aliases in an existing ancestor. */
|
|
165
|
+
function physicalPath(path) {
|
|
166
|
+
const tail = [];
|
|
167
|
+
let cursor = path;
|
|
168
|
+
for (;;) {
|
|
169
|
+
try {
|
|
170
|
+
lstatSync(cursor);
|
|
171
|
+
return resolve(realpathSync(cursor), ...tail);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (error.code !== "ENOENT" || dirname(cursor) === cursor) {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
// A dangling symlink must fail, rather than be treated as an absent directory.
|
|
178
|
+
try {
|
|
179
|
+
if (lstatSync(cursor).isSymbolicLink())
|
|
180
|
+
throw new Error("unresolved workspace alias");
|
|
181
|
+
}
|
|
182
|
+
catch (missing) {
|
|
183
|
+
if (missing.code !== "ENOENT")
|
|
184
|
+
throw missing;
|
|
185
|
+
}
|
|
186
|
+
tail.unshift(basename(cursor));
|
|
187
|
+
cursor = dirname(cursor);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export function claimOverlapsWorkspace(claim, workspaceRoot) {
|
|
192
|
+
const targets = [workspaceRoot, physicalPath(workspaceRoot)];
|
|
193
|
+
return claimPaths(claim).some((path, index) => [path, physicalPath(path)].some((candidate) => targets.some((target) => containsPath(target, candidate) || (index < 2 && containsPath(candidate, target)))));
|
|
194
|
+
}
|
|
@@ -14,7 +14,45 @@
|
|
|
14
14
|
* always has. So reclaim adds no second removal path that could diverge from the
|
|
15
15
|
* audited one, and a force-delete of live work exists nowhere in the codebase.
|
|
16
16
|
*/
|
|
17
|
+
import type { WorkflowRecoveryAuthorization } from "../recovery-audit.js";
|
|
18
|
+
import type { WorkflowLiveness } from "./recovery.js";
|
|
19
|
+
import type { WorkspaceCleanupAttempt, WorkspaceCleanupReceipt } from "./types.js";
|
|
17
20
|
export type ReclaimMode = "salvage" | "discard";
|
|
21
|
+
export type WorkflowReclaimRefusalCode = "workflow_reclaim_run_live" | "workflow_reclaim_liveness_unknown" | "workflow_reclaim_recovery_mismatch" | "workflow_reclaim_ownership_unproven" | "workflow_reclaim_lease_held";
|
|
22
|
+
export declare class WorkflowReclaimError extends Error {
|
|
23
|
+
readonly code: WorkflowReclaimRefusalCode;
|
|
24
|
+
constructor(code: WorkflowReclaimRefusalCode, message: string);
|
|
25
|
+
}
|
|
26
|
+
export interface WorkspaceReclaimOptions {
|
|
27
|
+
mode: ReclaimMode;
|
|
28
|
+
yes?: boolean;
|
|
29
|
+
unknownLiveness?: WorkflowRecoveryAuthorization & {
|
|
30
|
+
evidenceSha256: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface ReclaimLeaseHolder {
|
|
34
|
+
scope: "binding" | "repository" | "resume";
|
|
35
|
+
owner_id?: string;
|
|
36
|
+
pid?: number;
|
|
37
|
+
host?: string;
|
|
38
|
+
detail?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface WorkspaceReclaimPreview {
|
|
41
|
+
action: "preview";
|
|
42
|
+
run_id: string;
|
|
43
|
+
mode: ReclaimMode;
|
|
44
|
+
liveness: WorkflowLiveness;
|
|
45
|
+
evidence_sha256: string;
|
|
46
|
+
ownership: "ok" | "unproven";
|
|
47
|
+
ownership_detail?: string;
|
|
48
|
+
dirty_paths: string[] | null;
|
|
49
|
+
lease_holder: ReclaimLeaseHolder[];
|
|
50
|
+
}
|
|
51
|
+
export type WorkspaceReclaimResult = WorkspaceReclaimPreview | (Omit<WorkspaceReclaimPreview, "action"> & {
|
|
52
|
+
action: "reclaimed";
|
|
53
|
+
preparation: ReclaimPreparation;
|
|
54
|
+
cleanup: WorkspaceCleanupAttempt | WorkspaceCleanupReceipt;
|
|
55
|
+
});
|
|
18
56
|
export type ReclaimPreparation = {
|
|
19
57
|
action: "salvaged";
|
|
20
58
|
branch: string;
|
|
@@ -34,6 +72,8 @@ export interface PrepareReclaimInput {
|
|
|
34
72
|
worktreePath: string;
|
|
35
73
|
mode: ReclaimMode;
|
|
36
74
|
runId: string;
|
|
75
|
+
/** Revalidate the held reservation and peer authority immediately before effects. */
|
|
76
|
+
beforeEffect?: () => void;
|
|
37
77
|
}
|
|
38
78
|
/**
|
|
39
79
|
* Bring the worktree to a clean state so ordinary cleanup can release it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reclaim.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/reclaim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"reclaim.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/reclaim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhD,MAAM,MAAM,0BAA0B,GAClC,2BAA2B,GAC3B,mCAAmC,GACnC,oCAAoC,GACpC,qCAAqC,GACrC,6BAA6B,CAAC;AAElC,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,0BAA0B;gBAAhC,IAAI,EAAE,0BAA0B,EACzC,OAAO,EAAE,MAAM;CAKlB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,GAAG;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9E;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,IAAI,GAAG,UAAU,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,kBAAkB,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,CAAC,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,GAAG;IACzC,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,kBAAkB,CAAC;IAChC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAAC;CAC5D,CAAC,CAAC;AAEP,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,kBAAkB,CAwD7E;AAYD;qEACqE;AACrE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -16,6 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { existsSync } from "node:fs";
|
|
18
18
|
import { git, gitMaybe } from "./git.js";
|
|
19
|
+
export class WorkflowReclaimError extends Error {
|
|
20
|
+
code;
|
|
21
|
+
constructor(code, message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.name = "WorkflowReclaimError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
19
27
|
/**
|
|
20
28
|
* Bring the worktree to a clean state so ordinary cleanup can release it.
|
|
21
29
|
*
|
|
@@ -41,7 +49,9 @@ export function prepareReclaim(input) {
|
|
|
41
49
|
if (input.mode === "discard") {
|
|
42
50
|
// Ordered: reset drops tracked modifications, clean removes what reset
|
|
43
51
|
// cannot see. Running clean first would leave staged deletions behind.
|
|
52
|
+
input.beforeEffect?.();
|
|
44
53
|
git(input.worktreePath, ["reset", "--hard"]);
|
|
54
|
+
input.beforeEffect?.();
|
|
45
55
|
git(input.worktreePath, ["clean", "-fd"]);
|
|
46
56
|
return { action: "discarded", detail: "uncommitted changes were discarded on request" };
|
|
47
57
|
}
|
|
@@ -59,11 +69,15 @@ export function prepareReclaim(input) {
|
|
|
59
69
|
// ref ends untouched, and the work lives on a ref cleanup has no reason to
|
|
60
70
|
// touch.
|
|
61
71
|
const before = git(input.worktreePath, ["rev-parse", "HEAD"]).trim();
|
|
72
|
+
input.beforeEffect?.();
|
|
62
73
|
git(input.worktreePath, ["add", "-A"]);
|
|
74
|
+
input.beforeEffect?.();
|
|
63
75
|
git(input.worktreePath, ["commit", "--no-verify", "-m", salvageMessage(input.runId)]);
|
|
64
76
|
const commit = git(input.worktreePath, ["rev-parse", "HEAD"]).trim();
|
|
65
77
|
const branch = salvageBranch(input.runId);
|
|
78
|
+
input.beforeEffect?.();
|
|
66
79
|
git(input.worktreePath, ["branch", "--force", branch, commit]);
|
|
80
|
+
input.beforeEffect?.();
|
|
67
81
|
git(input.worktreePath, ["reset", "--hard", before]);
|
|
68
82
|
return {
|
|
69
83
|
action: "salvaged",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type WorkflowLiveness = "active" | "inactive" | "unknown";
|
|
2
|
+
/** Corruption must not hide a readable active marker from an audited override. */
|
|
3
|
+
export declare function hasActiveWorkflowEvidence(coordRoot: string, runId: string): boolean;
|
|
2
4
|
export declare function readWorkflowLiveness(coordRoot: string, runId: string): WorkflowLiveness;
|
|
3
5
|
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/recovery.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/recovery.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjE,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBnF;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CA6DvF"}
|
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { readWorkflowProof } from "../proof.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
if (existsSync(
|
|
4
|
+
/** Corruption must not hide a readable active marker from an audited override. */
|
|
5
|
+
export function hasActiveWorkflowEvidence(coordRoot, runId) {
|
|
6
|
+
const path = join(resolve(coordRoot), ".harnery", "workflows", runId, "transcript.jsonl");
|
|
7
|
+
if (!existsSync(path))
|
|
8
|
+
return false;
|
|
9
|
+
let active = false;
|
|
10
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
8
11
|
try {
|
|
9
|
-
const
|
|
10
|
-
|
|
12
|
+
const event = JSON.parse(line);
|
|
13
|
+
if (event?.run_id !== runId)
|
|
14
|
+
continue;
|
|
15
|
+
if (["run.start", "run.resume", "agent.start"].includes(event.event))
|
|
16
|
+
active = true;
|
|
17
|
+
if (event.event === "run.parked" ||
|
|
18
|
+
(event.event === "run.end" && typeof event.ok === "boolean") ||
|
|
19
|
+
(event.event === "workspace.reattach.failed" && ["blocked", "lost"].includes(event.status)))
|
|
20
|
+
active = false;
|
|
11
21
|
}
|
|
12
22
|
catch {
|
|
13
|
-
|
|
23
|
+
/* Unreadable evidence cannot establish inactivity. */
|
|
14
24
|
}
|
|
15
25
|
}
|
|
26
|
+
return active;
|
|
27
|
+
}
|
|
28
|
+
export function readWorkflowLiveness(coordRoot, runId) {
|
|
29
|
+
const root = resolve(coordRoot);
|
|
16
30
|
const transcriptPath = join(root, ".harnery", "workflows", runId, "transcript.jsonl");
|
|
17
31
|
if (!existsSync(transcriptPath))
|
|
18
32
|
return "unknown";
|
|
@@ -26,12 +40,16 @@ export function readWorkflowLiveness(coordRoot, runId) {
|
|
|
26
40
|
catch {
|
|
27
41
|
return "unknown";
|
|
28
42
|
}
|
|
29
|
-
if (events.some((item) => item
|
|
43
|
+
if (events.some((item) => !item ||
|
|
44
|
+
typeof item !== "object" ||
|
|
45
|
+
Array.isArray(item) ||
|
|
46
|
+
item.run_id !== runId ||
|
|
47
|
+
typeof item.event !== "string")) {
|
|
30
48
|
return "unknown";
|
|
31
49
|
}
|
|
32
50
|
let liveness;
|
|
33
51
|
for (const item of events) {
|
|
34
|
-
if (item.event === "run.start" || item.event === "run.resume")
|
|
52
|
+
if (item.event === "run.start" || item.event === "run.resume" || item.event === "agent.start")
|
|
35
53
|
liveness = "active";
|
|
36
54
|
if (item.event === "run.parked")
|
|
37
55
|
liveness = "inactive";
|
|
@@ -46,5 +64,19 @@ export function readWorkflowLiveness(coordRoot, runId) {
|
|
|
46
64
|
liveness = "inactive";
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
|
-
|
|
67
|
+
// A terminal proof can predate a resumed run. Only the current transcript
|
|
68
|
+
// can establish that no later activity invalidated that terminal observation.
|
|
69
|
+
if (liveness !== "inactive")
|
|
70
|
+
return liveness ?? "unknown";
|
|
71
|
+
const proofPath = join(root, ".harnery", "workflows", runId, "proof.json");
|
|
72
|
+
if (existsSync(proofPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const proof = readWorkflowProof(root, runId);
|
|
75
|
+
return ["succeeded", "failed"].includes(proof.run.status) ? "inactive" : "unknown";
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "unknown";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return "inactive";
|
|
50
82
|
}
|
|
@@ -44,6 +44,7 @@ export declare function workspaceLockPath(coordRoot: string, providerId: string,
|
|
|
44
44
|
export declare function writeWorkspaceRequest(coordRoot: string, request: WorkspaceAllocationRequest): string;
|
|
45
45
|
export declare function readWorkspaceRequest(coordRoot: string, runId: string): WorkspaceAllocationRequest | undefined;
|
|
46
46
|
export declare function writeWorkspaceClaim(coordRoot: string, claim: WorkspaceClaim): boolean;
|
|
47
|
+
export declare function readWorkspaceClaims(coordRoot: string, providerId: string): WorkspaceClaim[];
|
|
47
48
|
export declare function readWorkspaceClaim(coordRoot: string, providerId: string, bindingId: string): WorkspaceClaim | undefined;
|
|
48
49
|
export declare function writeWorkspaceBinding(coordRoot: string, binding: WorkspaceBinding): boolean;
|
|
49
50
|
export declare function readWorkspaceBinding(coordRoot: string, providerId: string, bindingId: string): WorkspaceBinding | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
1
|
+
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { stateDirMode, stateFileMode } from "../../storage/modes.js";
|
|
4
4
|
import { canonicalJson, fsyncParentDirectory, readJsonRecord, stableDigest, writeImmutableJson, } from "../durable-record.js";
|
|
5
|
+
import { assertClaimAuthority, publishWorkspaceClaim } from "./ownership.js";
|
|
5
6
|
export { appendWorkflowTranscriptEvent } from "../transcript.js";
|
|
6
7
|
const JSON_LIMIT = 512 * 1024;
|
|
7
8
|
const WORKSPACE_EVENT_BYTES = 32 * 1024;
|
|
@@ -39,6 +40,9 @@ export function readWorkspaceRequest(coordRoot, runId) {
|
|
|
39
40
|
: undefined;
|
|
40
41
|
}
|
|
41
42
|
export function writeWorkspaceClaim(coordRoot, claim) {
|
|
43
|
+
return publishWorkspaceClaim(coordRoot, claim, () => writeClaim(coordRoot, claim));
|
|
44
|
+
}
|
|
45
|
+
function writeClaim(coordRoot, claim) {
|
|
42
46
|
const path = workspaceClaimPath(coordRoot, claim.provider_id, claim.binding_id);
|
|
43
47
|
try {
|
|
44
48
|
return writeImmutableJson(path, claim);
|
|
@@ -52,6 +56,22 @@ export function writeWorkspaceClaim(coordRoot, claim) {
|
|
|
52
56
|
throw error;
|
|
53
57
|
}
|
|
54
58
|
}
|
|
59
|
+
export function readWorkspaceClaims(coordRoot, providerId) {
|
|
60
|
+
const root = join(resolve(coordRoot), ".harnery", "workspaces", providerId);
|
|
61
|
+
if (!existsSync(root))
|
|
62
|
+
return [];
|
|
63
|
+
return readdirSync(root, { withFileTypes: true })
|
|
64
|
+
.filter((entry) => entry.name !== ".leases")
|
|
65
|
+
.map((entry) => {
|
|
66
|
+
if (!entry.isDirectory())
|
|
67
|
+
throw new Error("retained workspace inventory is unproven");
|
|
68
|
+
const claim = readWorkspaceClaim(coordRoot, providerId, entry.name);
|
|
69
|
+
if (!claim)
|
|
70
|
+
throw new Error("retained workspace ownership claim is missing");
|
|
71
|
+
assertClaimAuthority(claim, providerId, entry.name);
|
|
72
|
+
return claim;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
55
75
|
export function readWorkspaceClaim(coordRoot, providerId, bindingId) {
|
|
56
76
|
const path = workspaceClaimPath(coordRoot, providerId, bindingId);
|
|
57
77
|
return existsSync(path) ? readJsonRecord(path, "workspace claim") : undefined;
|
|
@@ -28,31 +28,119 @@ interface CdpCookie {
|
|
|
28
28
|
}
|
|
29
29
|
/** Keep the sign-in site's cookies and normalize them to the store's shape. */
|
|
30
30
|
export declare function cookiesForDomain(cdpCookies: CdpCookie[], domain: string): Cookie[];
|
|
31
|
+
/**
|
|
32
|
+
* Regular expression, valid in both JavaScript and .NET, that matches a Chrome
|
|
33
|
+
* command line running on `profileWindows`. It matches the `--user-data-dir`
|
|
34
|
+
* argument exactly, with or without quotes around the path, so `...\profile`
|
|
35
|
+
* never matches `...\profile-2`. Quotes are written as `\x22` so the pattern
|
|
36
|
+
* survives being passed to PowerShell as an argument. Case-insensitive use is
|
|
37
|
+
* intended, as Windows paths are.
|
|
38
|
+
*/
|
|
39
|
+
export declare function profileCommandLinePattern(profileWindows: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* PowerShell that sets the profile's startup preference to "continue where
|
|
42
|
+
* you left off". Chrome deletes browser-session cookies (cookies with no
|
|
43
|
+
* expiry) when it exits normally unless that preference is set, and many
|
|
44
|
+
* sign-ins keep the signed-in state only in such cookies. With it set, the
|
|
45
|
+
* person can simply close the window and the sign-in survives for the
|
|
46
|
+
* harvest, and the next sign-in window reopens where they left off.
|
|
47
|
+
*
|
|
48
|
+
* The preference is protected against edits to the profile's files, so the
|
|
49
|
+
* script sets it the way the settings page does: it opens the profile
|
|
50
|
+
* headless, loads the settings page, and calls the settings API there. When
|
|
51
|
+
* the profile's preference files already show the value, Chrome is not
|
|
52
|
+
* started. The script prints `{"changed":bool,"value":n}`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function keepSessionScript(): string;
|
|
31
55
|
/**
|
|
32
56
|
* PowerShell that does the whole read on the Windows side: start Chrome
|
|
33
|
-
* headless on the profile
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* it may not be able to
|
|
57
|
+
* headless on the profile with its last session restored, read every cookie
|
|
58
|
+
* with `Storage.getCookies`, list the open pages with `Target.getTargets`,
|
|
59
|
+
* write both raw responses to stdout as one JSON object, and close the
|
|
60
|
+
* browser. WSL never touches the profile folder, which it may not be able to
|
|
61
|
+
* list. Every wait carries a deadline.
|
|
62
|
+
*
|
|
63
|
+
* Restoring the session keeps browser-session cookies that a forced stop left
|
|
64
|
+
* on disk, and it reopens the tabs the person had open, so the harvest can
|
|
65
|
+
* report the last page they reached on the sign-in site. That page's URL may
|
|
66
|
+
* carry a per-session token that cookies alone do not replace. The page list
|
|
67
|
+
* is polled for up to `$PageSeconds` until a page on `$Domain` appears.
|
|
37
68
|
*/
|
|
38
69
|
export declare function harvestScript(): string;
|
|
70
|
+
/** Shape `Target.getTargets` returns; extra fields are ignored. */
|
|
71
|
+
interface CdpTargetInfo {
|
|
72
|
+
type: string;
|
|
73
|
+
url: string;
|
|
74
|
+
}
|
|
39
75
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
76
|
+
* URLs of the open pages on the sign-in site, in the order Chrome lists them,
|
|
77
|
+
* without duplicates.
|
|
78
|
+
*/
|
|
79
|
+
export declare function sitePages(targets: CdpTargetInfo[], domain: string): string[];
|
|
80
|
+
export interface WindowsChromeHarvest {
|
|
81
|
+
/** The sign-in site's cookies, browser-session cookies included. */
|
|
82
|
+
cookies: Cookie[];
|
|
83
|
+
/** Open pages on the sign-in site; the first is the one to resume from. */
|
|
84
|
+
pages: string[];
|
|
85
|
+
}
|
|
86
|
+
/** Parse the harvest script's stdout. */
|
|
87
|
+
export declare function parseHarvestOutput(stdout: string, domain: string): WindowsChromeHarvest;
|
|
88
|
+
/**
|
|
89
|
+
* Reopen the Windows profile headless with its last session restored, read
|
|
90
|
+
* its cookies for `domain` and its open pages on that site, and close it.
|
|
91
|
+
* The profile must already be closed; see `stopWindowsChromeProfile`.
|
|
42
92
|
*/
|
|
43
93
|
export declare function harvestWindowsChromeCookies(input: {
|
|
44
94
|
chromeWindows: string;
|
|
45
95
|
profileWindows: string;
|
|
46
96
|
domain: string;
|
|
47
97
|
startupTimeoutSeconds?: number;
|
|
48
|
-
|
|
98
|
+
pageTimeoutSeconds?: number;
|
|
99
|
+
}): WindowsChromeHarvest;
|
|
100
|
+
export interface WindowsChromeKeepSession {
|
|
101
|
+
/** True when the preference was already set or is now set. */
|
|
102
|
+
kept: boolean;
|
|
103
|
+
/** True when this call changed the preference. */
|
|
104
|
+
changed: boolean;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Set the profile to keep browser-session cookies across a normal exit; see
|
|
108
|
+
* `keepSessionScript`. Throws when Chrome is already open on the profile,
|
|
109
|
+
* since a second sign-in window would hand off to it. Any other failure
|
|
110
|
+
* returns `kept: false` so the caller can warn and continue.
|
|
111
|
+
*/
|
|
112
|
+
export declare function keepWindowsChromeSession(input: {
|
|
113
|
+
chromeWindows: string;
|
|
114
|
+
profileWindows: string;
|
|
115
|
+
startupTimeoutSeconds?: number;
|
|
116
|
+
}): WindowsChromeKeepSession;
|
|
117
|
+
/**
|
|
118
|
+
* PowerShell that closes every Chrome whose command line matches `$Pattern`. It asks each window to
|
|
119
|
+
* close, repeating so a profile with several windows closes them all, which
|
|
120
|
+
* lets Chrome write its cookies and session to disk. Whatever is still
|
|
121
|
+
* running after `$CloseSeconds` is stopped by force. The script prints
|
|
122
|
+
* `{found, forced, remaining}` as JSON; `remaining` lists process ids that
|
|
123
|
+
* survived even the forced stop.
|
|
124
|
+
*/
|
|
125
|
+
export declare function stopScript(): string;
|
|
126
|
+
export interface WindowsChromeStop {
|
|
127
|
+
/** Chrome processes running on the profile when the stop began. */
|
|
128
|
+
found: number;
|
|
129
|
+
/** Processes that ignored the close request and were stopped by force. */
|
|
130
|
+
forced: number;
|
|
131
|
+
}
|
|
132
|
+
/** Parse the stop script's stdout; throws when a process survived. */
|
|
133
|
+
export declare function parseStopOutput(stdout: string, profileWindows: string): WindowsChromeStop;
|
|
49
134
|
/**
|
|
50
|
-
* Close
|
|
51
|
-
* the sign-in from the terminal while the window is open. The profile
|
|
52
|
-
* closed before its cookies can be read. Closing the
|
|
53
|
-
* write recent cookies to disk; a forced stop is the fallback after
|
|
135
|
+
* Close every Chrome still running on `profileWindows`, for when the person
|
|
136
|
+
* ends the sign-in from the terminal while the window is open. The profile
|
|
137
|
+
* must be closed before its cookies can be read. Closing the windows lets
|
|
138
|
+
* Chrome write recent cookies to disk; a forced stop is the fallback after
|
|
139
|
+
* `closeSeconds`, and it can lose cookies Chrome had not yet written. Throws
|
|
140
|
+
* when the stop cannot be confirmed, so the harvest never runs against a
|
|
141
|
+
* profile that is still open.
|
|
54
142
|
*/
|
|
55
|
-
export declare function stopWindowsChromeProfile(profileWindows: string):
|
|
143
|
+
export declare function stopWindowsChromeProfile(profileWindows: string, closeSeconds?: number): WindowsChromeStop;
|
|
56
144
|
/** Windows form of a `/mnt/<drive>/...` path. */
|
|
57
145
|
export declare function wslPathToWindows(linuxPath: string): string;
|
|
58
146
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-chrome.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/windows-chrome.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"windows-chrome.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/windows-chrome.ts"],"names":[],"mappings":"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"}
|