harnery 0.45.0 → 0.45.2
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/dist/commander.js +0 -1
- package/dist/commands/files.d.ts +2 -2
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +4 -7
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +17 -11
- package/dist/commands/tunnel.d.ts +0 -15
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +153 -453
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +6 -45
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +0 -18
- package/dist/core/agents/live-authority-v3.d.ts +0 -1
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +0 -11
- package/dist/core/agents/live-lifecycle-v3.d.ts +2 -4
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/live-lifecycle-v3.js +7 -28
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +14 -25
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-writer.js +0 -5
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +2 -7
- package/dist/core/agents/state/proc-start.d.ts +20 -31
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +37 -70
- package/dist/core/agents/state/service-process.d.ts +61 -0
- package/dist/core/agents/state/service-process.d.ts.map +1 -0
- package/dist/core/agents/state/service-process.js +143 -0
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +70 -180
- package/dist/core/artifacts/activity.d.ts +4 -1
- package/dist/core/artifacts/activity.d.ts.map +1 -1
- package/dist/core/artifacts/activity.js +8 -2
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +1 -2
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +38 -12
- package/dist/core/context/index.d.ts +6 -4
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +194 -256
- package/dist/core/context/observation.d.ts +9 -9
- package/dist/core/context/observation.d.ts.map +1 -1
- package/dist/core/context/observation.js +37 -6
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +0 -29
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +0 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +0 -7
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +64 -77
- package/dist/core/events/v3/runtime-build.d.ts +14 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +44 -0
- package/dist/core/governor/index.d.ts +2 -1
- package/dist/core/governor/index.d.ts.map +1 -1
- package/dist/core/governor/index.js +2 -1
- package/dist/core/governor/service-read.d.ts +3 -10
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +10 -94
- package/dist/core/governor/service.d.ts +3 -7
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +17 -182
- package/dist/core/hooks/cli.js +78 -48
- package/dist/core/hooks/resolve/owner.js +2 -2
- package/dist/core/resources/sampler.js +2 -2
- package/dist/core/resources/service-status.d.ts +2 -14
- package/dist/core/resources/service-status.d.ts.map +1 -1
- package/dist/core/resources/service-status.js +3 -23
- package/dist/core/resources/service.d.ts +3 -7
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +12 -101
- package/dist/core/resources/status.d.ts.map +1 -1
- package/dist/core/resources/status.js +3 -2
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +9 -2
- package/dist/core/servers/index.d.ts +11 -10
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +82 -192
- package/dist/core/servers/tunnels.d.ts +3 -5
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +2 -45
- package/dist/core/storage/durable-history.js +56 -22
- package/dist/core/storage/segments.d.ts.map +1 -1
- package/dist/core/storage/segments.js +73 -17
- package/dist/core/supervisor/service.d.ts +4 -7
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +23 -122
- package/dist/core/supervisor/services.js +2 -2
- package/dist/core/supervisor/status.d.ts +3 -17
- package/dist/core/supervisor/status.d.ts.map +1 -1
- package/dist/core/supervisor/status.js +7 -70
- package/dist/core/work/state.js +7 -7
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +23 -66
- package/dist/core/workflow/index.d.ts +3 -4
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -2
- package/dist/core/workflow/live-session-v3.d.ts +0 -6
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +5 -126
- package/dist/core/workflow/proof.d.ts +4 -4
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +34 -86
- package/dist/core/workflow/resume-lock.d.ts +17 -0
- package/dist/core/workflow/resume-lock.d.ts.map +1 -0
- package/dist/core/workflow/resume-lock.js +158 -0
- package/dist/core/workflow/run-state.d.ts +0 -21
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +3 -174
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +0 -19
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +0 -13
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +0 -19
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
- package/dist/core/workflow/spawn-opencode.js +0 -14
- package/dist/core/workflow/types.d.ts +11 -54
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.d.ts +4 -0
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +1 -1
- package/dist/core/workflow/workspaces/local-git.js +91 -210
- package/dist/core/workflow/workspaces/ownership.d.ts +0 -7
- package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/ownership.js +3 -130
- package/dist/core/workflow/workspaces/reclaim.d.ts +4 -7
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/reclaim.js +0 -4
- package/dist/core/workflow/workspaces/recovery.d.ts +1 -1
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/recovery.js +1 -1
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +1 -4
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +0 -4
- package/dist/lib/tunnel/state.d.ts +6 -13
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +12 -58
- package/package.json +1 -6
- package/src/commander.ts +0 -10
- package/src/commands/files.ts +5 -13
- package/src/commands/servers.ts +23 -12
- package/src/commands/tunnel.ts +166 -533
- package/src/commands/workflow.ts +8 -58
- package/src/core/agents/coord-client.ts +0 -20
- package/src/core/agents/live-authority-v3.ts +0 -17
- package/src/core/agents/live-lifecycle-v3.ts +14 -52
- package/src/core/agents/state/heartbeat-writer.ts +12 -29
- package/src/core/agents/state/live-coordination-writer.ts +0 -29
- package/src/core/agents/state/pidmap.ts +2 -15
- package/src/core/agents/state/proc-start.ts +41 -69
- package/src/core/agents/state/service-process.ts +217 -0
- package/src/core/agents/state/stale-sweep.ts +82 -247
- package/src/core/artifacts/activity.ts +9 -2
- package/src/core/artifacts/delivery-card.ts +1 -7
- package/src/core/artifacts/index.ts +45 -12
- package/src/core/context/index.ts +207 -272
- package/src/core/context/observation.ts +40 -9
- package/src/core/events/v3/authority-outbox.ts +0 -56
- package/src/core/events/v3/producers/coordination-recorder.ts +0 -15
- package/src/core/events/v3/producers/recorder.ts +68 -94
- package/src/core/events/v3/runtime-build.ts +62 -0
- package/src/core/governor/index.ts +1 -2
- package/src/core/governor/service-read.ts +15 -114
- package/src/core/governor/service.ts +36 -220
- package/src/core/hooks/cli.ts +85 -47
- package/src/core/hooks/resolve/owner.ts +2 -2
- package/src/core/resources/sampler.ts +3 -2
- package/src/core/resources/service-status.ts +6 -35
- package/src/core/resources/service.ts +23 -133
- package/src/core/resources/status.ts +3 -2
- package/src/core/semantic/service.ts +8 -2
- package/src/core/servers/index.ts +86 -228
- package/src/core/servers/tunnels.ts +3 -55
- package/src/core/storage/durable-history.ts +52 -20
- package/src/core/storage/segments.ts +79 -17
- package/src/core/supervisor/service.ts +33 -155
- package/src/core/supervisor/services.ts +2 -2
- package/src/core/supervisor/status.ts +10 -85
- package/src/core/work/state.ts +7 -7
- package/src/core/workflow/engine.ts +22 -74
- package/src/core/workflow/index.ts +2 -13
- package/src/core/workflow/live-session-v3.ts +5 -146
- package/src/core/workflow/proof.ts +40 -104
- package/src/core/workflow/resume-lock.ts +179 -0
- package/src/core/workflow/run-state.ts +3 -207
- package/src/core/workflow/spawn-claude.ts +0 -18
- package/src/core/workflow/spawn-codex.ts +0 -13
- package/src/core/workflow/spawn-cursor.ts +0 -18
- package/src/core/workflow/spawn-opencode.ts +0 -14
- package/src/core/workflow/types.ts +11 -41
- package/src/core/workflow/workspaces/leases.ts +1 -1
- package/src/core/workflow/workspaces/local-git.ts +120 -239
- package/src/core/workflow/workspaces/ownership.ts +3 -158
- package/src/core/workflow/workspaces/reclaim.ts +3 -9
- package/src/core/workflow/workspaces/recovery.ts +1 -1
- package/src/core/workflow/workspaces/state.ts +1 -5
- package/src/lib/identities/assume.ts +0 -4
- package/src/lib/tunnel/state.ts +15 -70
- package/dist/commands/turn-rollback.d.ts +0 -5
- package/dist/commands/turn-rollback.d.ts.map +0 -1
- package/dist/commands/turn-rollback.js +0 -76
- package/dist/core/agents/state/process-handle.d.ts +0 -26
- package/dist/core/agents/state/process-handle.d.ts.map +0 -1
- package/dist/core/agents/state/process-handle.js +0 -121
- package/dist/core/agents/state/unchanged-file.d.ts +0 -44
- package/dist/core/agents/state/unchanged-file.d.ts.map +0 -1
- package/dist/core/agents/state/unchanged-file.js +0 -390
- package/dist/core/events/v3/generation-custody.d.ts +0 -5
- package/dist/core/events/v3/generation-custody.d.ts.map +0 -1
- package/dist/core/events/v3/generation-custody.js +0 -50
- package/dist/core/turn-rollback/content.d.ts +0 -53
- package/dist/core/turn-rollback/content.d.ts.map +0 -1
- package/dist/core/turn-rollback/content.js +0 -396
- package/dist/core/turn-rollback/index.d.ts +0 -72
- package/dist/core/turn-rollback/index.d.ts.map +0 -1
- package/dist/core/turn-rollback/index.js +0 -443
- package/dist/core/workflow/failure-evidence.d.ts +0 -16
- package/dist/core/workflow/failure-evidence.d.ts.map +0 -1
- package/dist/core/workflow/failure-evidence.js +0 -114
- package/dist/core/workflow/recovery-audit.d.ts +0 -30
- package/dist/core/workflow/recovery-audit.d.ts.map +0 -1
- package/dist/core/workflow/recovery-audit.js +0 -116
- package/src/commands/turn-rollback.ts +0 -111
- package/src/core/agents/state/process-handle.ts +0 -165
- package/src/core/agents/state/unchanged-file.ts +0 -456
- package/src/core/events/v3/generation-custody.ts +0 -59
- package/src/core/turn-rollback/content.ts +0 -499
- package/src/core/turn-rollback/index.ts +0 -580
- package/src/core/workflow/failure-evidence.ts +0 -141
- package/src/core/workflow/recovery-audit.ts +0 -181
|
@@ -1,135 +1,8 @@
|
|
|
1
|
-
import { lstatSync,
|
|
2
|
-
import { basename, dirname, isAbsolute,
|
|
3
|
-
import {
|
|
4
|
-
import { acquireNoClobberLease } from "./leases.js";
|
|
1
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { stableDigest } from "../durable-record.js";
|
|
5
4
|
import { containsPath } from "./paths.js";
|
|
6
5
|
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
6
|
export function assertClaimAuthority(claim, providerId, id) {
|
|
134
7
|
if (claim?.schema_version !== 1 ||
|
|
135
8
|
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(providerId) ||
|
|
@@ -14,11 +14,10 @@
|
|
|
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
17
|
import type { WorkflowLiveness } from "./recovery.js";
|
|
19
18
|
import type { WorkspaceCleanupAttempt, WorkspaceCleanupReceipt } from "./types.js";
|
|
20
19
|
export type ReclaimMode = "salvage" | "discard";
|
|
21
|
-
export type WorkflowReclaimRefusalCode = "workflow_reclaim_run_live" | "workflow_reclaim_liveness_unknown" | "
|
|
20
|
+
export type WorkflowReclaimRefusalCode = "workflow_reclaim_run_live" | "workflow_reclaim_liveness_unknown" | "workflow_reclaim_ownership_unproven" | "workflow_reclaim_lease_held";
|
|
22
21
|
export declare class WorkflowReclaimError extends Error {
|
|
23
22
|
readonly code: WorkflowReclaimRefusalCode;
|
|
24
23
|
constructor(code: WorkflowReclaimRefusalCode, message: string);
|
|
@@ -26,9 +25,8 @@ export declare class WorkflowReclaimError extends Error {
|
|
|
26
25
|
export interface WorkspaceReclaimOptions {
|
|
27
26
|
mode: ReclaimMode;
|
|
28
27
|
yes?: boolean;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
28
|
+
/** Admit missing or corrupt liveness evidence; active evidence still refuses. */
|
|
29
|
+
force?: boolean;
|
|
32
30
|
}
|
|
33
31
|
export interface ReclaimLeaseHolder {
|
|
34
32
|
scope: "binding" | "repository" | "resume";
|
|
@@ -42,7 +40,6 @@ export interface WorkspaceReclaimPreview {
|
|
|
42
40
|
run_id: string;
|
|
43
41
|
mode: ReclaimMode;
|
|
44
42
|
liveness: WorkflowLiveness;
|
|
45
|
-
evidence_sha256: string;
|
|
46
43
|
ownership: "ok" | "unproven";
|
|
47
44
|
ownership_detail?: string;
|
|
48
45
|
dirty_paths: string[] | null;
|
|
@@ -72,7 +69,7 @@ export interface PrepareReclaimInput {
|
|
|
72
69
|
worktreePath: string;
|
|
73
70
|
mode: ReclaimMode;
|
|
74
71
|
runId: string;
|
|
75
|
-
/**
|
|
72
|
+
/** Recheck peer authority once, immediately before the first destructive step. */
|
|
76
73
|
beforeEffect?: () => void;
|
|
77
74
|
}
|
|
78
75
|
/**
|
|
@@ -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;AAIH,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,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,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;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,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,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,kBAAkB,CAoD7E;AAYD;qEACqE;AACrE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -51,7 +51,6 @@ export function prepareReclaim(input) {
|
|
|
51
51
|
// cannot see. Running clean first would leave staged deletions behind.
|
|
52
52
|
input.beforeEffect?.();
|
|
53
53
|
git(input.worktreePath, ["reset", "--hard"]);
|
|
54
|
-
input.beforeEffect?.();
|
|
55
54
|
git(input.worktreePath, ["clean", "-fd"]);
|
|
56
55
|
return { action: "discarded", detail: "uncommitted changes were discarded on request" };
|
|
57
56
|
}
|
|
@@ -71,13 +70,10 @@ export function prepareReclaim(input) {
|
|
|
71
70
|
const before = git(input.worktreePath, ["rev-parse", "HEAD"]).trim();
|
|
72
71
|
input.beforeEffect?.();
|
|
73
72
|
git(input.worktreePath, ["add", "-A"]);
|
|
74
|
-
input.beforeEffect?.();
|
|
75
73
|
git(input.worktreePath, ["commit", "--no-verify", "-m", salvageMessage(input.runId)]);
|
|
76
74
|
const commit = git(input.worktreePath, ["rev-parse", "HEAD"]).trim();
|
|
77
75
|
const branch = salvageBranch(input.runId);
|
|
78
|
-
input.beforeEffect?.();
|
|
79
76
|
git(input.worktreePath, ["branch", "--force", branch, commit]);
|
|
80
|
-
input.beforeEffect?.();
|
|
81
77
|
git(input.worktreePath, ["reset", "--hard", before]);
|
|
82
78
|
return {
|
|
83
79
|
action: "salvaged",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type WorkflowLiveness = "active" | "inactive" | "unknown";
|
|
2
|
-
/** Corruption must not hide a readable active marker from
|
|
2
|
+
/** Corruption must not hide a readable active marker from a forced reclaim. */
|
|
3
3
|
export declare function hasActiveWorkflowEvidence(coordRoot: string, runId: string): boolean;
|
|
4
4
|
export declare function readWorkflowLiveness(coordRoot: string, runId: string): WorkflowLiveness;
|
|
5
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
|
|
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,+EAA+E;AAC/E,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,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { readWorkflowProof } from "../proof.js";
|
|
4
|
-
/** Corruption must not hide a readable active marker from
|
|
4
|
+
/** Corruption must not hide a readable active marker from a forced reclaim. */
|
|
5
5
|
export function hasActiveWorkflowEvidence(coordRoot, runId) {
|
|
6
6
|
const path = join(resolve(coordRoot), ".harnery", "workflows", runId, "transcript.jsonl");
|
|
7
7
|
if (!existsSync(path))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/state.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,KAAK,EACV,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,EACf,uBAAuB,EACvB,0BAA0B,EAC1B,gBAAgB,EAChB,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,CAAC,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjD,UAAU,EAAE;QACV,WAAW,EAAE,oBAAoB,CAAC,aAAa,CAAC,CAAC;QACjD,UAAU,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;QAC/C,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,CAAC,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGvE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAIR;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,0BAA0B,GAClC,MAAM,CAIR;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,0BAA0B,GAAG,SAAS,CAKxC;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/core/workflow/workspaces/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readd
|
|
|
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
|
|
5
|
+
import { assertClaimAuthority } from "./ownership.js";
|
|
6
6
|
export { appendWorkflowTranscriptEvent } from "../transcript.js";
|
|
7
7
|
const JSON_LIMIT = 512 * 1024;
|
|
8
8
|
const WORKSPACE_EVENT_BYTES = 32 * 1024;
|
|
@@ -40,9 +40,6 @@ export function readWorkspaceRequest(coordRoot, runId) {
|
|
|
40
40
|
: undefined;
|
|
41
41
|
}
|
|
42
42
|
export function writeWorkspaceClaim(coordRoot, claim) {
|
|
43
|
-
return publishWorkspaceClaim(coordRoot, claim, () => writeClaim(coordRoot, claim));
|
|
44
|
-
}
|
|
45
|
-
function writeClaim(coordRoot, claim) {
|
|
46
43
|
const path = workspaceClaimPath(coordRoot, claim.provider_id, claim.binding_id);
|
|
47
44
|
try {
|
|
48
45
|
return writeImmutableJson(path, claim);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assume.d.ts","sourceRoot":"","sources":["../../../src/lib/identities/assume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA0BH,MAAM,MAAM,uBAAuB,GAC/B,eAAe,GACf,iBAAiB,GACjB,sBAAsB,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,GACpB,aAAa,GACb,mBAAmB,CAAC;AAExB,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,IAAI,EAAE,uBAAuB;gBAA7B,IAAI,EAAE,uBAAuB,EAC7C,OAAO,EAAE,MAAM;CAKlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,+DAA+D;IAC/D,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAOD;+EAC+E;AAC/E,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAa,EAClB,mBAAmB,GAAE,WAAW,CAAC,MAAM,CAAa,GACnD,gBAAgB,GAAG,IAAI,CA6BzB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,
|
|
1
|
+
{"version":3,"file":"assume.d.ts","sourceRoot":"","sources":["../../../src/lib/identities/assume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA0BH,MAAM,MAAM,uBAAuB,GAC/B,eAAe,GACf,iBAAiB,GACjB,sBAAsB,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,GACpB,aAAa,GACb,mBAAmB,CAAC;AAExB,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,IAAI,EAAE,uBAAuB;gBAA7B,IAAI,EAAE,uBAAuB,EAC7C,OAAO,EAAE,MAAM;CAKlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,+DAA+D;IAC/D,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAOD;+EAC+E;AAC/E,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAa,EAClB,mBAAmB,GAAE,WAAW,CAAC,MAAM,CAAa,GACnD,gBAAgB,GAAG,IAAI,CA6BzB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAyCT;AAuED,gEAAgE;AAChE,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,oBAAoB,CAyHtB"}
|
|
@@ -85,7 +85,6 @@ export function reclaimAbandonedLocalConflict(coordRoot, conflict) {
|
|
|
85
85
|
let sessionId = conflict.instance_id;
|
|
86
86
|
let ageSecs;
|
|
87
87
|
const liveRow = readLiveCoordinationRow(coordRoot, conflict.instance_id);
|
|
88
|
-
let expectedGenerationId = liveRow?.v3_generation_id ?? null;
|
|
89
88
|
if (liveRow) {
|
|
90
89
|
adapter = adapterOf(liveRow.platform);
|
|
91
90
|
sessionId = liveRow.session_id || conflict.instance_id;
|
|
@@ -100,10 +99,8 @@ export function reclaimAbandonedLocalConflict(coordRoot, conflict) {
|
|
|
100
99
|
// It is required to join the exact producer state when recording the sweep.
|
|
101
100
|
adapter = adapterOf(hb.platform);
|
|
102
101
|
sessionId = hb.session_id || conflict.instance_id;
|
|
103
|
-
expectedGenerationId = hb.v3_generation_id ?? null;
|
|
104
102
|
}
|
|
105
103
|
catch {
|
|
106
|
-
expectedGenerationId = null;
|
|
107
104
|
/* content unreadable — still reclaim the file */
|
|
108
105
|
}
|
|
109
106
|
try {
|
|
@@ -119,7 +116,6 @@ export function reclaimAbandonedLocalConflict(coordRoot, conflict) {
|
|
|
119
116
|
owner: conflict.instance_id,
|
|
120
117
|
nativeSessionId: sessionId,
|
|
121
118
|
adapter,
|
|
122
|
-
expectedGenerationId,
|
|
123
119
|
observation: "stale_heartbeat",
|
|
124
120
|
ageMs: Math.max(0, (ageSecs ?? 0) * 1_000),
|
|
125
121
|
});
|
|
@@ -32,12 +32,10 @@ export interface TunnelState {
|
|
|
32
32
|
provider: TunnelProvider;
|
|
33
33
|
url: string;
|
|
34
34
|
gate_pid: number;
|
|
35
|
-
gate_start_token?: string;
|
|
36
|
-
cloudflared_start_token?: string;
|
|
37
|
-
registration_id?: string;
|
|
38
|
-
provider_state?: "pending" | "ready";
|
|
39
35
|
/** Present for Cloudflare quick tunnels; absent for Tailscale Serve/Funnel. */
|
|
40
36
|
cloudflared_pid?: number;
|
|
37
|
+
/** Optional provider-side process when a provider owns one. */
|
|
38
|
+
provider_pid?: number;
|
|
41
39
|
started_at: string;
|
|
42
40
|
target: string;
|
|
43
41
|
vhost: string;
|
|
@@ -59,14 +57,9 @@ export declare function clearState(name?: string, root?: string): void;
|
|
|
59
57
|
*/
|
|
60
58
|
export declare function listStates(root?: string): TunnelState[];
|
|
61
59
|
export declare function isProcessAlive(pid: number): boolean;
|
|
62
|
-
export type
|
|
63
|
-
|
|
64
|
-
export
|
|
65
|
-
observeProcess(pid: number, originalToken: string): TunnelProcessObservation;
|
|
66
|
-
withRegistration(state: TunnelState, inspect: () => TunnelReadiness): TunnelReadiness;
|
|
67
|
-
}
|
|
68
|
-
/** Classify saved original witnesses under the verifier's registration custody. */
|
|
69
|
-
export declare function tunnelReadiness(state: TunnelState, verifier: TunnelReadinessVerifier): TunnelReadiness;
|
|
60
|
+
export type ProcessAliveCheck = (pid: number) => boolean;
|
|
61
|
+
/** True when both the local gate and its provider-side process are live. */
|
|
62
|
+
export declare function isTunnelStateLive(state: TunnelState, processAlive?: ProcessAliveCheck): boolean;
|
|
70
63
|
export declare function tunnelTargetPort(state: TunnelState): number | null;
|
|
71
64
|
/**
|
|
72
65
|
* Newest live tunnel that serves `vhost` on the requested local web port.
|
|
@@ -79,7 +72,7 @@ export declare function tunnelTargetPort(state: TunnelState): number | null;
|
|
|
79
72
|
* link 400s. Matching the vhost too keeps the returned tunnel the one that
|
|
80
73
|
* actually serves the caller's origin.
|
|
81
74
|
*/
|
|
82
|
-
export declare function findLiveTunnelForOrigin(port: number, vhost: string, root
|
|
75
|
+
export declare function findLiveTunnelForOrigin(port: number, vhost: string, root?: string, processAlive?: ProcessAliveCheck): TunnelState | null;
|
|
83
76
|
/** True when the tunnel's path scope forwards every one of `paths`. */
|
|
84
77
|
export declare function tunnelServesPaths(state: TunnelState, paths: readonly string[]): boolean;
|
|
85
78
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/lib/tunnel/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/lib/tunnel/state.ts"],"names":[],"mappings":"AAoBA,qGAAqG;AACrG,eAAO,MAAM,cAAc,uBAAuB,CAAC;AACnD,yEAAyE;AACzE,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,GAAE,MAAsB,EAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAUD,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAW1C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAG9E;AAgBD,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAgBD,wBAAgB,UAAU,IAAI,YAAY,CAezC;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAEnD;AAED,wBAAgB,SAAS,CACvB,IAAI,GAAE,MAAyB,EAC/B,IAAI,GAAE,MAAsB,GAC3B,WAAW,GAAG,IAAI,CAQpB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,GAAE,MAAsB,GAAG,IAAI,CAEjF;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAyB,EAAE,IAAI,GAAE,MAAsB,GAAG,IAAI,CAG9F;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAsB,GAAG,WAAW,EAAE,CAWtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAEzD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,YAAY,GAAE,iBAAkC,GAC/C,OAAO,CAKT;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAWlE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,MAAsB,EAC5B,YAAY,GAAE,iBAAkC,GAC/C,WAAW,GAAG,IAAI,CASpB;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEvF;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,cAAc,GAAE,MAAM,GAAG,SAAyC,GACjE,MAAM,CAoDR"}
|
package/dist/lib/tunnel/state.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// Tunnel config + state persistence + provider helpers. Commands default to
|
|
2
2
|
// <cwd>/.cache/tunnel/; gitignored, so the allowlist is per-machine.
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
-
import {
|
|
5
|
-
import { accessSync, chmodSync, constants, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { accessSync, chmodSync, constants, existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
6
5
|
import { homedir } from "node:os";
|
|
7
6
|
import { delimiter, join, resolve } from "node:path";
|
|
8
7
|
import { isPathAllowed } from "./path-scope.js";
|
|
@@ -105,17 +104,7 @@ export function readState(name = DEFAULT_INSTANCE, root = process.cwd()) {
|
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
export function writeState(state, root = process.cwd()) {
|
|
108
|
-
|
|
109
|
-
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
110
|
-
try {
|
|
111
|
-
writeFileSync(temporary, JSON.stringify(state, null, 2), { flag: "wx", mode: 0o600 });
|
|
112
|
-
renameSync(temporary, path);
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
if (existsSync(temporary))
|
|
116
|
-
unlinkSync(temporary);
|
|
117
|
-
throw error;
|
|
118
|
-
}
|
|
107
|
+
writeFileSync(cachePath(stateFile(state.name), root), JSON.stringify(state, null, 2));
|
|
119
108
|
}
|
|
120
109
|
export function clearState(name = DEFAULT_INSTANCE, root = process.cwd()) {
|
|
121
110
|
const p = cachePath(stateFile(name), root);
|
|
@@ -150,49 +139,14 @@ export function isProcessAlive(pid) {
|
|
|
150
139
|
return false;
|
|
151
140
|
}
|
|
152
141
|
}
|
|
153
|
-
/**
|
|
154
|
-
export function
|
|
155
|
-
if (!state
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
!Number.isSafeInteger(state.gate_pid) ||
|
|
162
|
-
state.gate_pid < 1 ||
|
|
163
|
-
typeof state.gate_start_token !== "string" ||
|
|
164
|
-
!state.gate_start_token)
|
|
165
|
-
return "unknown";
|
|
166
|
-
const targets = [{ pid: state.gate_pid, token: state.gate_start_token }];
|
|
167
|
-
if (state.provider === "tailscale") {
|
|
168
|
-
if (state.provider_state !== "ready" ||
|
|
169
|
-
state.cloudflared_pid !== undefined ||
|
|
170
|
-
state.cloudflared_start_token !== undefined)
|
|
171
|
-
return "unknown";
|
|
172
|
-
}
|
|
173
|
-
else if (state.provider === "cloudflare") {
|
|
174
|
-
if (!Number.isSafeInteger(state.cloudflared_pid) ||
|
|
175
|
-
state.cloudflared_pid < 1 ||
|
|
176
|
-
typeof state.cloudflared_start_token !== "string" ||
|
|
177
|
-
!state.cloudflared_start_token)
|
|
178
|
-
return "unknown";
|
|
179
|
-
targets.push({ pid: state.cloudflared_pid, token: state.cloudflared_start_token });
|
|
180
|
-
}
|
|
181
|
-
else
|
|
182
|
-
return "unknown";
|
|
183
|
-
try {
|
|
184
|
-
return verifier.withRegistration(state, () => {
|
|
185
|
-
const observed = targets.map(({ pid, token }) => verifier.observeProcess(pid, token));
|
|
186
|
-
if (observed.every((value) => value === "absent"))
|
|
187
|
-
return "dead";
|
|
188
|
-
if (observed.every((value) => value === "same"))
|
|
189
|
-
return "ready";
|
|
190
|
-
return "unknown";
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
return "unknown";
|
|
195
|
-
}
|
|
142
|
+
/** True when both the local gate and its provider-side process are live. */
|
|
143
|
+
export function isTunnelStateLive(state, processAlive = isProcessAlive) {
|
|
144
|
+
if (!processAlive(state.gate_pid))
|
|
145
|
+
return false;
|
|
146
|
+
if (state.provider === "tailscale")
|
|
147
|
+
return true;
|
|
148
|
+
const providerPid = state.cloudflared_pid ?? state.provider_pid;
|
|
149
|
+
return typeof providerPid === "number" && processAlive(providerPid);
|
|
196
150
|
}
|
|
197
151
|
export function tunnelTargetPort(state) {
|
|
198
152
|
const value = /^[a-z][a-z\d+.-]*:\/\//i.test(state.target)
|
|
@@ -219,10 +173,10 @@ export function tunnelTargetPort(state) {
|
|
|
219
173
|
* link 400s. Matching the vhost too keeps the returned tunnel the one that
|
|
220
174
|
* actually serves the caller's origin.
|
|
221
175
|
*/
|
|
222
|
-
export function findLiveTunnelForOrigin(port, vhost, root,
|
|
176
|
+
export function findLiveTunnelForOrigin(port, vhost, root = process.cwd(), processAlive = isProcessAlive) {
|
|
223
177
|
return (listStates(root).find((state) => tunnelTargetPort(state) === port &&
|
|
224
178
|
state.vhost === vhost &&
|
|
225
|
-
|
|
179
|
+
isTunnelStateLive(state, processAlive)) ?? null);
|
|
226
180
|
}
|
|
227
181
|
/** True when the tunnel's path scope forwards every one of `paths`. */
|
|
228
182
|
export function tunnelServesPaths(state, paths) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harnery",
|
|
3
|
-
"version": "0.45.
|
|
3
|
+
"version": "0.45.2",
|
|
4
4
|
"description": "Multi-agent coordination for AI coding agents - Claude Code, Cursor, and Codex.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ryan Kelly",
|
|
@@ -67,11 +67,6 @@
|
|
|
67
67
|
"types": "./dist/core/context/index.d.ts",
|
|
68
68
|
"import": "./dist/core/context/index.js"
|
|
69
69
|
},
|
|
70
|
-
"./core/turn-rollback": {
|
|
71
|
-
"bun": "./src/core/turn-rollback/index.ts",
|
|
72
|
-
"types": "./dist/core/turn-rollback/index.d.ts",
|
|
73
|
-
"import": "./dist/core/turn-rollback/index.js"
|
|
74
|
-
},
|
|
75
70
|
"./core/workflow": {
|
|
76
71
|
"bun": "./src/core/workflow/index.ts",
|
|
77
72
|
"types": "./dist/core/workflow/index.d.ts",
|
package/src/commander.ts
CHANGED
|
@@ -795,16 +795,6 @@ function harneryCommandBundles({
|
|
|
795
795
|
load: async (program) =>
|
|
796
796
|
(await import("./commands/workflow.ts")).registerWorkflowCommand(program, emit),
|
|
797
797
|
},
|
|
798
|
-
lazy(
|
|
799
|
-
"turn-rollback",
|
|
800
|
-
"Capture and review exact turn paths before restoring owned content.",
|
|
801
|
-
async (program) =>
|
|
802
|
-
(await import("./commands/turn-rollback.ts")).registerTurnRollbackCommand(
|
|
803
|
-
program,
|
|
804
|
-
emit,
|
|
805
|
-
context,
|
|
806
|
-
),
|
|
807
|
-
),
|
|
808
798
|
lazy("work", "Track durable objectives across bounded workflow attempts.", async (program) =>
|
|
809
799
|
(await import("./commands/work.ts")).registerWorkCommand(program, emit),
|
|
810
800
|
),
|
package/src/commands/files.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type { Command } from "commander";
|
|
|
4
4
|
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
5
5
|
import { resolveCoordRoot } from "../core/agents/coord-client.ts";
|
|
6
6
|
import { DEFAULT_WEB_PORT, resolveWebPort } from "../core/config.ts";
|
|
7
|
-
import { createTunnelReadinessVerifier } from "../core/servers/index.ts";
|
|
8
7
|
import { coordRootId, localCoordRootIdUrl } from "../lib/coord-root-id.ts";
|
|
9
8
|
import {
|
|
10
9
|
encodedRepoPath,
|
|
@@ -15,10 +14,10 @@ import {
|
|
|
15
14
|
} from "../lib/local-file-url.ts";
|
|
16
15
|
import { isPathAllowed } from "../lib/tunnel/path-scope.ts";
|
|
17
16
|
import {
|
|
17
|
+
isTunnelStateLive,
|
|
18
18
|
listStates,
|
|
19
|
-
type
|
|
19
|
+
type ProcessAliveCheck,
|
|
20
20
|
type TunnelState,
|
|
21
|
-
tunnelReadiness,
|
|
22
21
|
tunnelTargetPort,
|
|
23
22
|
} from "../lib/tunnel/state.ts";
|
|
24
23
|
|
|
@@ -209,10 +208,10 @@ export function tunnelFileUrl(
|
|
|
209
208
|
local: LocalFileUrl,
|
|
210
209
|
port: number,
|
|
211
210
|
states: TunnelState[],
|
|
212
|
-
|
|
211
|
+
processAlive?: ProcessAliveCheck,
|
|
213
212
|
): string {
|
|
214
213
|
const live = states.filter(
|
|
215
|
-
(state) => tunnelTargetPort(state) === port &&
|
|
214
|
+
(state) => tunnelTargetPort(state) === port && isTunnelStateLive(state, processAlive),
|
|
216
215
|
);
|
|
217
216
|
if (local.mode === "raw") {
|
|
218
217
|
const path = `/${encodedRepoPath(local.relPath)}`;
|
|
@@ -310,14 +309,7 @@ export function registerFilesCommand(
|
|
|
310
309
|
mode: opts.raw ? "raw" : opts.viewer ? "viewer" : "auto",
|
|
311
310
|
});
|
|
312
311
|
if (opts.verify !== false) await verifyDashboardRoot(coordRoot, port);
|
|
313
|
-
const url = opts.tunnel
|
|
314
|
-
? tunnelFileUrl(
|
|
315
|
-
result,
|
|
316
|
-
port,
|
|
317
|
-
listStates(coordRoot),
|
|
318
|
-
createTunnelReadinessVerifier({ coordRoot }),
|
|
319
|
-
)
|
|
320
|
-
: result.url;
|
|
312
|
+
const url = opts.tunnel ? tunnelFileUrl(result, port, listStates(coordRoot)) : result.url;
|
|
321
313
|
emit.text(`${url}\n`);
|
|
322
314
|
} catch (error) {
|
|
323
315
|
if (error instanceof TunnelLinkError) {
|
package/src/commands/servers.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { hostname } from "node:os";
|
|
2
3
|
import type { Command } from "commander";
|
|
3
4
|
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
4
5
|
import { resolveCoordRoot } from "../core/agents/coord-client.ts";
|
|
@@ -110,13 +111,23 @@ export function registerServersCommand(
|
|
|
110
111
|
const preview = Boolean(options.type) && !options.yes;
|
|
111
112
|
const results: Array<StopResult | { id: string; would_stop: true }> = [];
|
|
112
113
|
for (const stray of strays) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
results.push(
|
|
115
|
+
await stopServer(
|
|
116
|
+
{
|
|
117
|
+
schema_version: 1,
|
|
118
|
+
id: `pid-${stray.pid}`,
|
|
119
|
+
kind: "session",
|
|
120
|
+
type: "unregistered",
|
|
121
|
+
label: stray.command,
|
|
122
|
+
pid: stray.pid,
|
|
123
|
+
...(stray.start_token ? { start_token: stray.start_token } : {}),
|
|
124
|
+
host: hostname(),
|
|
125
|
+
started_at: new Date().toISOString(),
|
|
126
|
+
registered_at: new Date().toISOString(),
|
|
127
|
+
},
|
|
128
|
+
{ coordRoot },
|
|
129
|
+
),
|
|
130
|
+
);
|
|
120
131
|
}
|
|
121
132
|
for (const view of selected) {
|
|
122
133
|
if (preview && !ids.includes(view.record.id))
|
|
@@ -397,14 +408,14 @@ export function registerServersCommand(
|
|
|
397
408
|
|
|
398
409
|
cmd
|
|
399
410
|
.command("unregister <id>")
|
|
400
|
-
.description("Remove
|
|
411
|
+
.description("Remove a server's record (with --pid, only if the record still names that pid)")
|
|
401
412
|
.option("--pid <pid>", "Only remove when the record names this pid")
|
|
402
413
|
.action((id: string, options: { pid?: string }) => {
|
|
403
414
|
try {
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
415
|
+
const removed = unregisterServer(id, {
|
|
416
|
+
coordRoot: root(),
|
|
417
|
+
...(options.pid ? { pid: integer(options.pid, "--pid") } : {}),
|
|
418
|
+
});
|
|
408
419
|
emit.config({ format: "json" });
|
|
409
420
|
emit.data({ id, removed });
|
|
410
421
|
} catch (error) {
|