harnery 0.45.1 → 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/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/state/pidmap.js +2 -2
- 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/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/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/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 +0 -2
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +3 -18
- 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/workflow/engine.js +2 -1
- 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/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +30 -74
- 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/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/package.json +1 -1
- package/src/commands/workflow.ts +8 -58
- package/src/core/agents/coord-client.ts +0 -20
- package/src/core/agents/state/pidmap.ts +2 -2
- package/src/core/agents/state/proc-start.ts +41 -69
- package/src/core/agents/state/service-process.ts +217 -0
- package/src/core/context/index.ts +207 -272
- package/src/core/context/observation.ts +40 -9
- 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/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 +3 -23
- 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/workflow/engine.ts +1 -1
- package/src/core/workflow/index.ts +2 -13
- package/src/core/workflow/proof.ts +35 -83
- package/src/core/workflow/resume-lock.ts +179 -0
- package/src/core/workflow/run-state.ts +3 -207
- 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/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/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/core/agents/state/process-handle.ts +0 -165
- package/src/core/workflow/recovery-audit.ts +0 -181
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, readdirSync } from "node:fs";
|
|
3
|
-
import { hostname } from "node:os";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
import { stateDirMode } from "../storage/modes.ts";
|
|
6
|
-
import { assertWorkflowRunId } from "./approvals.ts";
|
|
7
|
-
import {
|
|
8
|
-
fsyncParentDirectory,
|
|
9
|
-
readJsonRecord,
|
|
10
|
-
stableDigest,
|
|
11
|
-
writeImmutableJson,
|
|
12
|
-
} from "./durable-record.ts";
|
|
13
|
-
|
|
14
|
-
export interface WorkflowRecoveryAuthorization {
|
|
15
|
-
actor: string;
|
|
16
|
-
reason: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface WorkflowRecoveryIntent extends WorkflowRecoveryAuthorization {
|
|
20
|
-
schema_version: 1;
|
|
21
|
-
operation_id: string;
|
|
22
|
-
run_id: string;
|
|
23
|
-
action: "reclaim_unknown_liveness" | "unlock_resume";
|
|
24
|
-
target_sha256: string;
|
|
25
|
-
target: Record<string, unknown>;
|
|
26
|
-
recorded_at: string;
|
|
27
|
-
pid: number;
|
|
28
|
-
host: string;
|
|
29
|
-
outcome: "unknown";
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface WorkflowRecoveryRecord {
|
|
33
|
-
intent: WorkflowRecoveryIntent;
|
|
34
|
-
outcome: "unknown" | "completed";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function validateWorkflowRecoveryAuthorization(
|
|
38
|
-
authorization: WorkflowRecoveryAuthorization,
|
|
39
|
-
): void {
|
|
40
|
-
for (const [field, limit] of [
|
|
41
|
-
["actor", 200],
|
|
42
|
-
["reason", 2_000],
|
|
43
|
-
] as const) {
|
|
44
|
-
const value = authorization[field];
|
|
45
|
-
if (
|
|
46
|
-
typeof value !== "string" ||
|
|
47
|
-
!value.trim() ||
|
|
48
|
-
value.length > limit ||
|
|
49
|
-
Array.from(value).some(
|
|
50
|
-
(character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127,
|
|
51
|
-
)
|
|
52
|
-
) {
|
|
53
|
-
throw new Error(
|
|
54
|
-
`workflow recovery requires a nonempty ${field} of at most ${limit} characters without control characters`,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Canonical recovery ledger: immutable intent is durable before effects.
|
|
61
|
-
* Completion cites that exact intent; absence always means unknown. */
|
|
62
|
-
export function beginWorkflowRecovery(
|
|
63
|
-
coordRoot: string,
|
|
64
|
-
input: Omit<
|
|
65
|
-
WorkflowRecoveryIntent,
|
|
66
|
-
"schema_version" | "operation_id" | "recorded_at" | "pid" | "host" | "outcome"
|
|
67
|
-
>,
|
|
68
|
-
): { intent: WorkflowRecoveryIntent; assertCurrent(): void; complete(): void } {
|
|
69
|
-
assertWorkflowRunId(input.run_id);
|
|
70
|
-
validateWorkflowRecoveryAuthorization(input);
|
|
71
|
-
if (!/^[a-f0-9]{64}$/.test(input.target_sha256))
|
|
72
|
-
throw new Error("workflow recovery requires an exact preview digest");
|
|
73
|
-
const intent: WorkflowRecoveryIntent = {
|
|
74
|
-
...input,
|
|
75
|
-
schema_version: 1,
|
|
76
|
-
operation_id: `recovery-${randomUUID()}`,
|
|
77
|
-
recorded_at: new Date().toISOString(),
|
|
78
|
-
pid: process.pid,
|
|
79
|
-
host: hostname(),
|
|
80
|
-
outcome: "unknown",
|
|
81
|
-
};
|
|
82
|
-
const directory = join(
|
|
83
|
-
coordRoot,
|
|
84
|
-
".harnery",
|
|
85
|
-
"workflows",
|
|
86
|
-
input.run_id,
|
|
87
|
-
"recovery",
|
|
88
|
-
intent.operation_id,
|
|
89
|
-
);
|
|
90
|
-
// Sync each newly published directory name too. Syncing only the intent's
|
|
91
|
-
// immediate parent cannot make a newly created ancestor durable.
|
|
92
|
-
const runDirectory = join(coordRoot, ".harnery", "workflows", input.run_id);
|
|
93
|
-
ensureDurableDirectory(runDirectory);
|
|
94
|
-
const ledgerDirectory = join(runDirectory, "recovery");
|
|
95
|
-
ensureDurableDirectory(ledgerDirectory);
|
|
96
|
-
fsyncParentDirectory(ledgerDirectory);
|
|
97
|
-
mkdirSync(directory, { mode: stateDirMode() });
|
|
98
|
-
fsyncParentDirectory(directory);
|
|
99
|
-
const intentPath = join(directory, "intent.json");
|
|
100
|
-
writeImmutableJson(intentPath, intent);
|
|
101
|
-
const assertCurrent = () => {
|
|
102
|
-
if (stableDigest(readJsonRecord(intentPath, "recovery intent")) !== stableDigest(intent))
|
|
103
|
-
throw new Error("workflow recovery audit authority changed");
|
|
104
|
-
};
|
|
105
|
-
return {
|
|
106
|
-
intent,
|
|
107
|
-
assertCurrent,
|
|
108
|
-
complete: () => {
|
|
109
|
-
assertCurrent();
|
|
110
|
-
writeImmutableJson(join(directory, "completion.json"), {
|
|
111
|
-
schema_version: 1,
|
|
112
|
-
operation_id: intent.operation_id,
|
|
113
|
-
intent_sha256: stableDigest(intent),
|
|
114
|
-
outcome: "completed",
|
|
115
|
-
recorded_at: new Date().toISOString(),
|
|
116
|
-
});
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function ensureDurableDirectory(path: string): void {
|
|
122
|
-
if (existsSync(path)) {
|
|
123
|
-
if (!lstatSync(path).isDirectory())
|
|
124
|
-
throw new Error("workflow recovery ledger is not a directory");
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
ensureDurableDirectory(dirname(path));
|
|
128
|
-
try {
|
|
129
|
-
mkdirSync(path, { mode: stateDirMode() });
|
|
130
|
-
} catch (error) {
|
|
131
|
-
if ((error as NodeJS.ErrnoException).code !== "EEXIST" || !lstatSync(path).isDirectory())
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
fsyncParentDirectory(path);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function readWorkflowRecoveryLedger(
|
|
138
|
-
coordRoot: string,
|
|
139
|
-
runId: string,
|
|
140
|
-
): WorkflowRecoveryRecord[] {
|
|
141
|
-
assertWorkflowRunId(runId);
|
|
142
|
-
const directory = join(coordRoot, ".harnery", "workflows", runId, "recovery");
|
|
143
|
-
if (!existsSync(directory)) return [];
|
|
144
|
-
return readdirSync(directory)
|
|
145
|
-
.sort()
|
|
146
|
-
.map((entry) => {
|
|
147
|
-
if (!/^recovery-[a-f0-9-]{36}$/.test(entry))
|
|
148
|
-
throw new Error("invalid workflow recovery ledger entry");
|
|
149
|
-
const intent = readJsonRecord<WorkflowRecoveryIntent>(
|
|
150
|
-
join(directory, entry, "intent.json"),
|
|
151
|
-
"recovery intent",
|
|
152
|
-
);
|
|
153
|
-
if (
|
|
154
|
-
intent.schema_version !== 1 ||
|
|
155
|
-
intent.operation_id !== entry ||
|
|
156
|
-
intent.run_id !== runId ||
|
|
157
|
-
intent.outcome !== "unknown" ||
|
|
158
|
-
!["reclaim_unknown_liveness", "unlock_resume"].includes(intent.action) ||
|
|
159
|
-
!/^[a-f0-9]{64}$/.test(intent.target_sha256)
|
|
160
|
-
) {
|
|
161
|
-
throw new Error("invalid workflow recovery intent authority");
|
|
162
|
-
}
|
|
163
|
-
validateWorkflowRecoveryAuthorization(intent);
|
|
164
|
-
const completionPath = join(directory, entry, "completion.json");
|
|
165
|
-
if (!existsSync(completionPath)) return { intent, outcome: "unknown" };
|
|
166
|
-
const completion = readJsonRecord<{
|
|
167
|
-
schema_version: number;
|
|
168
|
-
operation_id: string;
|
|
169
|
-
intent_sha256: string;
|
|
170
|
-
outcome: string;
|
|
171
|
-
}>(completionPath, "recovery completion");
|
|
172
|
-
if (
|
|
173
|
-
completion.schema_version !== 1 ||
|
|
174
|
-
completion.operation_id !== entry ||
|
|
175
|
-
completion.intent_sha256 !== stableDigest(intent) ||
|
|
176
|
-
completion.outcome !== "completed"
|
|
177
|
-
)
|
|
178
|
-
throw new Error("invalid workflow recovery completion authority");
|
|
179
|
-
return { intent, outcome: "completed" };
|
|
180
|
-
});
|
|
181
|
-
}
|