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.
Files changed (119) hide show
  1. package/dist/commands/workflow.d.ts.map +1 -1
  2. package/dist/commands/workflow.js +6 -45
  3. package/dist/core/agents/coord-client.d.ts.map +1 -1
  4. package/dist/core/agents/coord-client.js +0 -18
  5. package/dist/core/agents/state/pidmap.js +2 -2
  6. package/dist/core/agents/state/proc-start.d.ts +20 -31
  7. package/dist/core/agents/state/proc-start.d.ts.map +1 -1
  8. package/dist/core/agents/state/proc-start.js +37 -70
  9. package/dist/core/agents/state/service-process.d.ts +61 -0
  10. package/dist/core/agents/state/service-process.d.ts.map +1 -0
  11. package/dist/core/agents/state/service-process.js +143 -0
  12. package/dist/core/context/index.d.ts +6 -4
  13. package/dist/core/context/index.d.ts.map +1 -1
  14. package/dist/core/context/index.js +194 -256
  15. package/dist/core/context/observation.d.ts +9 -9
  16. package/dist/core/context/observation.d.ts.map +1 -1
  17. package/dist/core/context/observation.js +37 -6
  18. package/dist/core/events/v3/runtime-build.d.ts +14 -0
  19. package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
  20. package/dist/core/events/v3/runtime-build.js +44 -0
  21. package/dist/core/governor/index.d.ts +2 -1
  22. package/dist/core/governor/index.d.ts.map +1 -1
  23. package/dist/core/governor/index.js +2 -1
  24. package/dist/core/governor/service-read.d.ts +3 -10
  25. package/dist/core/governor/service-read.d.ts.map +1 -1
  26. package/dist/core/governor/service-read.js +10 -94
  27. package/dist/core/governor/service.d.ts +3 -7
  28. package/dist/core/governor/service.d.ts.map +1 -1
  29. package/dist/core/governor/service.js +17 -182
  30. package/dist/core/hooks/resolve/owner.js +2 -2
  31. package/dist/core/resources/sampler.js +2 -2
  32. package/dist/core/resources/service-status.d.ts +2 -14
  33. package/dist/core/resources/service-status.d.ts.map +1 -1
  34. package/dist/core/resources/service-status.js +3 -23
  35. package/dist/core/resources/service.d.ts +3 -7
  36. package/dist/core/resources/service.d.ts.map +1 -1
  37. package/dist/core/resources/service.js +12 -101
  38. package/dist/core/resources/status.d.ts.map +1 -1
  39. package/dist/core/resources/status.js +3 -2
  40. package/dist/core/semantic/service.d.ts.map +1 -1
  41. package/dist/core/semantic/service.js +9 -2
  42. package/dist/core/servers/index.d.ts +0 -2
  43. package/dist/core/servers/index.d.ts.map +1 -1
  44. package/dist/core/servers/index.js +3 -18
  45. package/dist/core/supervisor/service.d.ts +4 -7
  46. package/dist/core/supervisor/service.d.ts.map +1 -1
  47. package/dist/core/supervisor/service.js +23 -122
  48. package/dist/core/supervisor/services.js +2 -2
  49. package/dist/core/supervisor/status.d.ts +3 -17
  50. package/dist/core/supervisor/status.d.ts.map +1 -1
  51. package/dist/core/supervisor/status.js +7 -70
  52. package/dist/core/workflow/engine.js +2 -1
  53. package/dist/core/workflow/index.d.ts +3 -4
  54. package/dist/core/workflow/index.d.ts.map +1 -1
  55. package/dist/core/workflow/index.js +2 -2
  56. package/dist/core/workflow/proof.d.ts.map +1 -1
  57. package/dist/core/workflow/proof.js +30 -74
  58. package/dist/core/workflow/resume-lock.d.ts +17 -0
  59. package/dist/core/workflow/resume-lock.d.ts.map +1 -0
  60. package/dist/core/workflow/resume-lock.js +158 -0
  61. package/dist/core/workflow/run-state.d.ts +0 -21
  62. package/dist/core/workflow/run-state.d.ts.map +1 -1
  63. package/dist/core/workflow/run-state.js +3 -174
  64. package/dist/core/workflow/workspaces/leases.d.ts +4 -0
  65. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  66. package/dist/core/workflow/workspaces/leases.js +1 -1
  67. package/dist/core/workflow/workspaces/local-git.js +91 -210
  68. package/dist/core/workflow/workspaces/ownership.d.ts +0 -7
  69. package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -1
  70. package/dist/core/workflow/workspaces/ownership.js +3 -130
  71. package/dist/core/workflow/workspaces/reclaim.d.ts +4 -7
  72. package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
  73. package/dist/core/workflow/workspaces/reclaim.js +0 -4
  74. package/dist/core/workflow/workspaces/recovery.d.ts +1 -1
  75. package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
  76. package/dist/core/workflow/workspaces/recovery.js +1 -1
  77. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  78. package/dist/core/workflow/workspaces/state.js +1 -4
  79. package/package.json +1 -1
  80. package/src/commands/workflow.ts +8 -58
  81. package/src/core/agents/coord-client.ts +0 -20
  82. package/src/core/agents/state/pidmap.ts +2 -2
  83. package/src/core/agents/state/proc-start.ts +41 -69
  84. package/src/core/agents/state/service-process.ts +217 -0
  85. package/src/core/context/index.ts +207 -272
  86. package/src/core/context/observation.ts +40 -9
  87. package/src/core/events/v3/runtime-build.ts +62 -0
  88. package/src/core/governor/index.ts +1 -2
  89. package/src/core/governor/service-read.ts +15 -114
  90. package/src/core/governor/service.ts +36 -220
  91. package/src/core/hooks/resolve/owner.ts +2 -2
  92. package/src/core/resources/sampler.ts +3 -2
  93. package/src/core/resources/service-status.ts +6 -35
  94. package/src/core/resources/service.ts +23 -133
  95. package/src/core/resources/status.ts +3 -2
  96. package/src/core/semantic/service.ts +8 -2
  97. package/src/core/servers/index.ts +3 -23
  98. package/src/core/supervisor/service.ts +33 -155
  99. package/src/core/supervisor/services.ts +2 -2
  100. package/src/core/supervisor/status.ts +10 -85
  101. package/src/core/workflow/engine.ts +1 -1
  102. package/src/core/workflow/index.ts +2 -13
  103. package/src/core/workflow/proof.ts +35 -83
  104. package/src/core/workflow/resume-lock.ts +179 -0
  105. package/src/core/workflow/run-state.ts +3 -207
  106. package/src/core/workflow/workspaces/leases.ts +1 -1
  107. package/src/core/workflow/workspaces/local-git.ts +120 -239
  108. package/src/core/workflow/workspaces/ownership.ts +3 -158
  109. package/src/core/workflow/workspaces/reclaim.ts +3 -9
  110. package/src/core/workflow/workspaces/recovery.ts +1 -1
  111. package/src/core/workflow/workspaces/state.ts +1 -5
  112. package/dist/core/agents/state/process-handle.d.ts +0 -26
  113. package/dist/core/agents/state/process-handle.d.ts.map +0 -1
  114. package/dist/core/agents/state/process-handle.js +0 -121
  115. package/dist/core/workflow/recovery-audit.d.ts +0 -30
  116. package/dist/core/workflow/recovery-audit.d.ts.map +0 -1
  117. package/dist/core/workflow/recovery-audit.js +0 -116
  118. package/src/core/agents/state/process-handle.ts +0 -165
  119. 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
- }