harnery 0.44.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/dist/commander.js +1 -0
- 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/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +11 -17
- 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 +44 -0
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +18 -0
- package/dist/core/agents/state/proc-start.d.ts +5 -6
- package/dist/core/agents/state/proc-start.d.ts.map +1 -1
- package/dist/core/agents/state/proc-start.js +13 -9
- 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/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +2 -1
- package/dist/core/resources/service.d.ts +2 -16
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +1 -78
- 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 +12 -11
- package/dist/core/servers/index.d.ts.map +1 -1
- package/dist/core/servers/index.js +194 -81
- package/dist/core/servers/tunnels.d.ts +5 -3
- package/dist/core/servers/tunnels.d.ts.map +1 -1
- package/dist/core/servers/tunnels.js +45 -2
- package/dist/core/supervisor/service.d.ts +2 -4
- package/dist/core/supervisor/service.d.ts.map +1 -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/workflow/index.d.ts +4 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- 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 +19 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +113 -8
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +70 -14
- package/dist/core/workflow/workspaces/reclaim.d.ts +6 -1
- package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
- 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 +24 -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/package.json +6 -1
- package/src/commander.ts +10 -0
- package/src/commands/files.ts +13 -5
- package/src/commands/servers.ts +12 -23
- package/src/commands/tunnel.ts +533 -166
- package/src/commands/turn-rollback.ts +111 -0
- package/src/commands/workflow.ts +59 -0
- package/src/core/agents/coord-client.ts +20 -0
- package/src/core/agents/state/proc-start.ts +14 -11
- package/src/core/agents/state/process-handle.ts +165 -0
- package/src/core/artifacts/delivery-card.ts +7 -1
- package/src/core/resources/service.ts +3 -88
- package/src/core/semantic/service.ts +2 -8
- package/src/core/servers/index.ts +234 -85
- package/src/core/servers/tunnels.ts +55 -3
- package/src/core/supervisor/service.ts +2 -3
- package/src/core/turn-rollback/content.ts +499 -0
- package/src/core/turn-rollback/index.ts +580 -0
- package/src/core/workflow/index.ts +12 -1
- package/src/core/workflow/recovery-audit.ts +181 -0
- package/src/core/workflow/run-state.ts +137 -8
- package/src/core/workflow/workspaces/local-git.ts +86 -15
- package/src/core/workflow/workspaces/reclaim.ts +4 -0
- package/src/core/workflow/workspaces/recovery.ts +23 -0
- package/src/lib/tunnel/state.ts +70 -15
package/src/lib/tunnel/state.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// <cwd>/.cache/tunnel/; gitignored, so the allowlist is per-machine.
|
|
3
3
|
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
5
6
|
import {
|
|
6
7
|
accessSync,
|
|
7
8
|
chmodSync,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
mkdirSync,
|
|
11
12
|
readdirSync,
|
|
12
13
|
readFileSync,
|
|
14
|
+
renameSync,
|
|
13
15
|
statSync,
|
|
14
16
|
unlinkSync,
|
|
15
17
|
writeFileSync,
|
|
@@ -104,10 +106,12 @@ export interface TunnelState {
|
|
|
104
106
|
provider: TunnelProvider;
|
|
105
107
|
url: string;
|
|
106
108
|
gate_pid: number;
|
|
109
|
+
gate_start_token?: string;
|
|
110
|
+
cloudflared_start_token?: string;
|
|
111
|
+
registration_id?: string;
|
|
112
|
+
provider_state?: "pending" | "ready";
|
|
107
113
|
/** Present for Cloudflare quick tunnels; absent for Tailscale Serve/Funnel. */
|
|
108
114
|
cloudflared_pid?: number;
|
|
109
|
-
/** Optional provider-side process when a provider owns one. */
|
|
110
|
-
provider_pid?: number;
|
|
111
115
|
started_at: string;
|
|
112
116
|
target: string;
|
|
113
117
|
vhost: string;
|
|
@@ -168,7 +172,15 @@ export function readState(
|
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
export function writeState(state: TunnelState, root: string = process.cwd()): void {
|
|
171
|
-
|
|
175
|
+
const path = cachePath(stateFile(state.name), root);
|
|
176
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
177
|
+
try {
|
|
178
|
+
writeFileSync(temporary, JSON.stringify(state, null, 2), { flag: "wx", mode: 0o600 });
|
|
179
|
+
renameSync(temporary, path);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (existsSync(temporary)) unlinkSync(temporary);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
export function clearState(name: string = DEFAULT_INSTANCE, root: string = process.cwd()): void {
|
|
@@ -202,17 +214,60 @@ export function isProcessAlive(pid: number): boolean {
|
|
|
202
214
|
}
|
|
203
215
|
}
|
|
204
216
|
|
|
205
|
-
export type
|
|
217
|
+
export type TunnelReadiness = "ready" | "dead" | "unknown";
|
|
218
|
+
export type TunnelProcessObservation = "same" | "absent" | "different" | "unknown";
|
|
219
|
+
|
|
220
|
+
export interface TunnelReadinessVerifier {
|
|
221
|
+
observeProcess(pid: number, originalToken: string): TunnelProcessObservation;
|
|
222
|
+
withRegistration(state: TunnelState, inspect: () => TunnelReadiness): TunnelReadiness;
|
|
223
|
+
}
|
|
206
224
|
|
|
207
|
-
/**
|
|
208
|
-
export function
|
|
225
|
+
/** Classify saved original witnesses under the verifier's registration custody. */
|
|
226
|
+
export function tunnelReadiness(
|
|
209
227
|
state: TunnelState,
|
|
210
|
-
|
|
211
|
-
):
|
|
212
|
-
if (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
228
|
+
verifier: TunnelReadinessVerifier,
|
|
229
|
+
): TunnelReadiness {
|
|
230
|
+
if (
|
|
231
|
+
!state ||
|
|
232
|
+
typeof state !== "object" ||
|
|
233
|
+
Object.hasOwn(state, "provider_pid") ||
|
|
234
|
+
Object.hasOwn(state, "provider_start_token") ||
|
|
235
|
+
typeof state.registration_id !== "string" ||
|
|
236
|
+
!state.registration_id ||
|
|
237
|
+
!Number.isSafeInteger(state.gate_pid) ||
|
|
238
|
+
state.gate_pid < 1 ||
|
|
239
|
+
typeof state.gate_start_token !== "string" ||
|
|
240
|
+
!state.gate_start_token
|
|
241
|
+
)
|
|
242
|
+
return "unknown";
|
|
243
|
+
const targets = [{ pid: state.gate_pid, token: state.gate_start_token }];
|
|
244
|
+
if (state.provider === "tailscale") {
|
|
245
|
+
if (
|
|
246
|
+
state.provider_state !== "ready" ||
|
|
247
|
+
state.cloudflared_pid !== undefined ||
|
|
248
|
+
state.cloudflared_start_token !== undefined
|
|
249
|
+
)
|
|
250
|
+
return "unknown";
|
|
251
|
+
} else if (state.provider === "cloudflare") {
|
|
252
|
+
if (
|
|
253
|
+
!Number.isSafeInteger(state.cloudflared_pid) ||
|
|
254
|
+
state.cloudflared_pid! < 1 ||
|
|
255
|
+
typeof state.cloudflared_start_token !== "string" ||
|
|
256
|
+
!state.cloudflared_start_token
|
|
257
|
+
)
|
|
258
|
+
return "unknown";
|
|
259
|
+
targets.push({ pid: state.cloudflared_pid!, token: state.cloudflared_start_token });
|
|
260
|
+
} else return "unknown";
|
|
261
|
+
try {
|
|
262
|
+
return verifier.withRegistration(state, () => {
|
|
263
|
+
const observed = targets.map(({ pid, token }) => verifier.observeProcess(pid, token));
|
|
264
|
+
if (observed.every((value) => value === "absent")) return "dead";
|
|
265
|
+
if (observed.every((value) => value === "same")) return "ready";
|
|
266
|
+
return "unknown";
|
|
267
|
+
});
|
|
268
|
+
} catch {
|
|
269
|
+
return "unknown";
|
|
270
|
+
}
|
|
216
271
|
}
|
|
217
272
|
|
|
218
273
|
export function tunnelTargetPort(state: TunnelState): number | null {
|
|
@@ -242,15 +297,15 @@ export function tunnelTargetPort(state: TunnelState): number | null {
|
|
|
242
297
|
export function findLiveTunnelForOrigin(
|
|
243
298
|
port: number,
|
|
244
299
|
vhost: string,
|
|
245
|
-
root: string
|
|
246
|
-
|
|
300
|
+
root: string,
|
|
301
|
+
verifier: TunnelReadinessVerifier,
|
|
247
302
|
): TunnelState | null {
|
|
248
303
|
return (
|
|
249
304
|
listStates(root).find(
|
|
250
305
|
(state) =>
|
|
251
306
|
tunnelTargetPort(state) === port &&
|
|
252
307
|
state.vhost === vhost &&
|
|
253
|
-
|
|
308
|
+
tunnelReadiness(state, verifier) === "ready",
|
|
254
309
|
) ?? null
|
|
255
310
|
);
|
|
256
311
|
}
|