@sentropic/h2a-cli 0.20.2 → 0.22.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/bin.js +4 -1
- package/dist/bin.js.map +1 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli-contract.js +20 -4
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +266 -34
- package/dist/cli.js.map +1 -1
- package/dist/hosts/plugin.d.ts.map +1 -1
- package/dist/hosts/plugin.js +5 -1
- package/dist/hosts/plugin.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime/drive/index.d.ts +72 -0
- package/dist/runtime/drive/index.d.ts.map +1 -0
- package/dist/runtime/drive/index.js +175 -0
- package/dist/runtime/drive/index.js.map +1 -0
- package/dist/runtime/drumbeat/inbox-relance.d.ts +29 -0
- package/dist/runtime/drumbeat/inbox-relance.d.ts.map +1 -0
- package/dist/runtime/drumbeat/inbox-relance.js +101 -0
- package/dist/runtime/drumbeat/inbox-relance.js.map +1 -0
- package/dist/runtime/drumbeat/index.d.ts +2 -1
- package/dist/runtime/drumbeat/index.d.ts.map +1 -1
- package/dist/runtime/drumbeat/index.js +2 -1
- package/dist/runtime/drumbeat/index.js.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts +25 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.js +53 -0
- package/dist/runtime/drumbeat/relaunchers.js.map +1 -1
- package/dist/runtime/drumbeat/scan.d.ts +2 -0
- package/dist/runtime/drumbeat/scan.d.ts.map +1 -1
- package/dist/runtime/drumbeat/scan.js +3 -0
- package/dist/runtime/drumbeat/scan.js.map +1 -1
- package/dist/runtime/drumbeat/watch.d.ts +3 -1
- package/dist/runtime/drumbeat/watch.d.ts.map +1 -1
- package/dist/runtime/drumbeat/watch.js +6 -2
- package/dist/runtime/drumbeat/watch.js.map +1 -1
- package/dist/runtime/identity/bindings.d.ts +60 -0
- package/dist/runtime/identity/bindings.d.ts.map +1 -0
- package/dist/runtime/identity/bindings.js +90 -0
- package/dist/runtime/identity/bindings.js.map +1 -0
- package/dist/runtime/identity/index.d.ts +10 -0
- package/dist/runtime/identity/index.d.ts.map +1 -0
- package/dist/runtime/identity/index.js +6 -0
- package/dist/runtime/identity/index.js.map +1 -0
- package/dist/runtime/identity/live.d.ts +26 -0
- package/dist/runtime/identity/live.d.ts.map +1 -0
- package/dist/runtime/identity/live.js +207 -0
- package/dist/runtime/identity/live.js.map +1 -0
- package/dist/runtime/identity/migration.d.ts +55 -0
- package/dist/runtime/identity/migration.d.ts.map +1 -0
- package/dist/runtime/identity/migration.js +100 -0
- package/dist/runtime/identity/migration.js.map +1 -0
- package/dist/runtime/identity/readers.d.ts +11 -0
- package/dist/runtime/identity/readers.d.ts.map +1 -0
- package/dist/runtime/identity/readers.js +114 -0
- package/dist/runtime/identity/readers.js.map +1 -0
- package/dist/runtime/identity/resolver.d.ts +50 -0
- package/dist/runtime/identity/resolver.d.ts.map +1 -0
- package/dist/runtime/identity/resolver.js +61 -0
- package/dist/runtime/identity/resolver.js.map +1 -0
- package/dist/runtime/local-files/store.d.ts.map +1 -1
- package/dist/runtime/local-files/store.js +19 -9
- package/dist/runtime/local-files/store.js.map +1 -1
- package/dist/runtime/mcp/handlers.d.ts +3 -1
- package/dist/runtime/mcp/handlers.d.ts.map +1 -1
- package/dist/runtime/mcp/handlers.js +2 -0
- package/dist/runtime/mcp/handlers.js.map +1 -1
- package/dist/runtime/mcp/sessions.d.ts +5 -1
- package/dist/runtime/mcp/sessions.d.ts.map +1 -1
- package/dist/runtime/mcp/sessions.js +2 -0
- package/dist/runtime/mcp/sessions.js.map +1 -1
- package/dist/runtime/mcp/stdio.d.ts +3 -0
- package/dist/runtime/mcp/stdio.d.ts.map +1 -1
- package/dist/runtime/mcp/stdio.js +4 -0
- package/dist/runtime/mcp/stdio.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type H2ALaunchContext, type H2AReplayGuard, type H2ASignature } from "@sentropic/h2a";
|
|
2
|
+
import type { LocalStore } from "../local-files/store.js";
|
|
3
|
+
import { type RelauncherRuntime } from "../drumbeat/relaunchers.js";
|
|
4
|
+
export interface H2ADriveInstructionPayload {
|
|
5
|
+
readonly from: string;
|
|
6
|
+
readonly to: string;
|
|
7
|
+
readonly instruction: string;
|
|
8
|
+
readonly nonce: string;
|
|
9
|
+
readonly at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FormatSignedDriveInstructionOptions {
|
|
12
|
+
readonly from: string;
|
|
13
|
+
readonly to: string;
|
|
14
|
+
readonly instruction: string;
|
|
15
|
+
readonly privateKeyPem: string;
|
|
16
|
+
readonly nonce?: string;
|
|
17
|
+
readonly at?: string;
|
|
18
|
+
readonly now?: () => number;
|
|
19
|
+
}
|
|
20
|
+
export interface ParsedSignedDriveInstruction {
|
|
21
|
+
readonly payload: H2ADriveInstructionPayload;
|
|
22
|
+
readonly signature: H2ASignature;
|
|
23
|
+
}
|
|
24
|
+
export type H2ADriveVerifyReason = "malformed" | "no-public-key" | "bad-signature" | "invalid-timestamp" | "expired" | "future" | "replayed";
|
|
25
|
+
export type H2ADriveVerifyResult = {
|
|
26
|
+
readonly ok: true;
|
|
27
|
+
readonly payload: H2ADriveInstructionPayload;
|
|
28
|
+
} | {
|
|
29
|
+
readonly ok: false;
|
|
30
|
+
readonly reason: H2ADriveVerifyReason;
|
|
31
|
+
};
|
|
32
|
+
export interface VerifySignedDriveInstructionOptions {
|
|
33
|
+
readonly resolvePublicKeys: (instance: string) => readonly string[];
|
|
34
|
+
readonly guard: H2AReplayGuard;
|
|
35
|
+
readonly now?: number;
|
|
36
|
+
}
|
|
37
|
+
export type H2ADriveAuthorizeReason = "missing-registration" | "unauthorized";
|
|
38
|
+
export type H2ADriveAuthorizeResult = {
|
|
39
|
+
readonly ok: true;
|
|
40
|
+
} | {
|
|
41
|
+
readonly ok: false;
|
|
42
|
+
readonly reason: H2ADriveAuthorizeReason;
|
|
43
|
+
};
|
|
44
|
+
export interface H2ADriveRequest {
|
|
45
|
+
readonly to: string;
|
|
46
|
+
readonly instructionLine: string;
|
|
47
|
+
readonly launchContext?: H2ALaunchContext;
|
|
48
|
+
}
|
|
49
|
+
export interface H2ADriver {
|
|
50
|
+
drive(request: H2ADriveRequest): boolean | Promise<boolean>;
|
|
51
|
+
}
|
|
52
|
+
export type H2ADriverKind = "logging" | "native" | "local-tmux" | "headless" | "auto";
|
|
53
|
+
export interface NativeBackchannelDriverOptions {
|
|
54
|
+
readonly send?: (request: H2ADriveRequest) => boolean | Promise<boolean>;
|
|
55
|
+
}
|
|
56
|
+
export interface DriverRuntimeOptions {
|
|
57
|
+
readonly runtime?: RelauncherRuntime;
|
|
58
|
+
readonly log?: (line: string) => void;
|
|
59
|
+
}
|
|
60
|
+
export declare function formatSignedDriveInstruction(options: FormatSignedDriveInstructionOptions): string;
|
|
61
|
+
export declare function parseSignedDriveInstruction(line: string): ParsedSignedDriveInstruction | undefined;
|
|
62
|
+
export declare function verifySignedDriveInstruction(line: string, options: VerifySignedDriveInstructionOptions): H2ADriveVerifyResult;
|
|
63
|
+
export declare function authorizeDrive(store: Pick<LocalStore, "findInstance">, request: {
|
|
64
|
+
readonly from: string;
|
|
65
|
+
readonly to: string;
|
|
66
|
+
}): H2ADriveAuthorizeResult;
|
|
67
|
+
export declare function loggingDriver(log?: (line: string) => void): H2ADriver;
|
|
68
|
+
export declare function nativeBackchannelDriver(options?: NativeBackchannelDriverOptions): H2ADriver;
|
|
69
|
+
export declare function localTmuxDriver(options?: DriverRuntimeOptions): H2ADriver;
|
|
70
|
+
export declare function headlessDriver(options?: DriverRuntimeOptions): H2ADriver;
|
|
71
|
+
export declare function chainDriver(...drivers: readonly H2ADriver[]): H2ADriver;
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/drive/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-1 bilateral-discussion driver (signed terminal injection), slice E1a.
|
|
3
|
+
*
|
|
4
|
+
* Provides the SENDER half end-to-end (`h2a drive`): a signed instruction line
|
|
5
|
+
* `[h2a from=… sig=…] <instruction>`, an `H2ADriver` chain
|
|
6
|
+
* (logging/native/local-tmux/headless/auto), and a sender-side authority gate.
|
|
7
|
+
*
|
|
8
|
+
* `verifySignedDriveInstruction` + the receiver `authorizeDrive` below are
|
|
9
|
+
* exported, tested primitives but are **library-only in E1a — not yet wired
|
|
10
|
+
* into any host receive hook**. The receiver-side "verify-before-act" is
|
|
11
|
+
* deferred to E1c (local plugin authority hook) and is mandatory in E1d
|
|
12
|
+
* (remote, which crosses the trust boundary). This is consistent with the
|
|
13
|
+
* ratified single-trusted-user local threat model (DEC-116): a malicious local
|
|
14
|
+
* injector is out of scope; the signature gives provenance + accountability and
|
|
15
|
+
* the sender gate blocks unauthorized h2a drives. Declared boundary, not a gap
|
|
16
|
+
* — see docs/superpowers/specs/2026-05-31-evo1-bilateral-discussion-driver-framing.md.
|
|
17
|
+
*/
|
|
18
|
+
import { randomBytes } from "node:crypto";
|
|
19
|
+
import { H2A_AUTHORITY_MATRIX, canSignArtifactKind, signCanonical, verifyCanonical } from "@sentropic/h2a";
|
|
20
|
+
import { defaultRelauncherRuntime, tmuxTarget } from "../drumbeat/relaunchers.js";
|
|
21
|
+
function randomNonce() {
|
|
22
|
+
return randomBytes(12).toString("hex");
|
|
23
|
+
}
|
|
24
|
+
function driveReplayEnvelope(payload) {
|
|
25
|
+
return {
|
|
26
|
+
protocol: "sentropic.h2a",
|
|
27
|
+
version: "0.1",
|
|
28
|
+
id: `drive:${payload.from}:${payload.to}:${payload.nonce}`,
|
|
29
|
+
type: "event",
|
|
30
|
+
actor: { instance: payload.from, role: "AGENTS", scope: "scope:default" },
|
|
31
|
+
target: { instance: payload.to },
|
|
32
|
+
body: { kind: "drive.instruction" },
|
|
33
|
+
createdAt: payload.at
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function shellQuote(value) {
|
|
37
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
38
|
+
}
|
|
39
|
+
export function formatSignedDriveInstruction(options) {
|
|
40
|
+
const now = options.now?.() ?? Date.now();
|
|
41
|
+
const payload = {
|
|
42
|
+
from: options.from,
|
|
43
|
+
to: options.to,
|
|
44
|
+
instruction: options.instruction,
|
|
45
|
+
nonce: options.nonce ?? randomNonce(),
|
|
46
|
+
at: options.at ?? new Date(now).toISOString()
|
|
47
|
+
};
|
|
48
|
+
const signature = signCanonical(payload, {
|
|
49
|
+
by: options.from,
|
|
50
|
+
privateKeyPem: options.privateKeyPem
|
|
51
|
+
});
|
|
52
|
+
return `[h2a from=${payload.from} to=${payload.to} nonce=${payload.nonce} at=${payload.at} sig=${signature.value}] ${payload.instruction}`;
|
|
53
|
+
}
|
|
54
|
+
export function parseSignedDriveInstruction(line) {
|
|
55
|
+
const match = /^\[h2a ([^\]]+)\] ([\s\S]*)$/.exec(line);
|
|
56
|
+
if (!match)
|
|
57
|
+
return undefined;
|
|
58
|
+
const attrs = new Map();
|
|
59
|
+
for (const part of match[1].split(" ")) {
|
|
60
|
+
const idx = part.indexOf("=");
|
|
61
|
+
if (idx <= 0)
|
|
62
|
+
return undefined;
|
|
63
|
+
attrs.set(part.slice(0, idx), part.slice(idx + 1));
|
|
64
|
+
}
|
|
65
|
+
const from = attrs.get("from");
|
|
66
|
+
const to = attrs.get("to");
|
|
67
|
+
const nonce = attrs.get("nonce");
|
|
68
|
+
const at = attrs.get("at");
|
|
69
|
+
const sig = attrs.get("sig");
|
|
70
|
+
if (!from || !to || !nonce || !at || !sig)
|
|
71
|
+
return undefined;
|
|
72
|
+
return {
|
|
73
|
+
payload: { from, to, instruction: match[2], nonce, at },
|
|
74
|
+
signature: { by: from, alg: "ed25519", value: sig }
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function verifySignedDriveInstruction(line, options) {
|
|
78
|
+
const parsed = parseSignedDriveInstruction(line);
|
|
79
|
+
if (!parsed)
|
|
80
|
+
return { ok: false, reason: "malformed" };
|
|
81
|
+
const publicKeys = options.resolvePublicKeys(parsed.payload.from);
|
|
82
|
+
if (publicKeys.length === 0)
|
|
83
|
+
return { ok: false, reason: "no-public-key" };
|
|
84
|
+
const signatureOk = publicKeys.some((pem) => verifyCanonical(parsed.payload, parsed.signature, pem));
|
|
85
|
+
if (!signatureOk)
|
|
86
|
+
return { ok: false, reason: "bad-signature" };
|
|
87
|
+
const replay = options.guard.accept(driveReplayEnvelope(parsed.payload), options.now);
|
|
88
|
+
if (!replay.ok) {
|
|
89
|
+
return { ok: false, reason: replay.reason ?? "replayed" };
|
|
90
|
+
}
|
|
91
|
+
return { ok: true, payload: parsed.payload };
|
|
92
|
+
}
|
|
93
|
+
function hasSharedScope(a, b) {
|
|
94
|
+
const bScopes = new Set(b.scopes);
|
|
95
|
+
return a.scopes.some((scope) => bScopes.has(scope));
|
|
96
|
+
}
|
|
97
|
+
function canIssueMandate(reg) {
|
|
98
|
+
return reg.roles.some((role) => H2A_AUTHORITY_MATRIX.MANDATE.roles.includes(role) &&
|
|
99
|
+
canSignArtifactKind(role, "MANDATE"));
|
|
100
|
+
}
|
|
101
|
+
export function authorizeDrive(store, request) {
|
|
102
|
+
const from = store.findInstance(request.from);
|
|
103
|
+
const to = store.findInstance(request.to);
|
|
104
|
+
if (!from || !to)
|
|
105
|
+
return { ok: false, reason: "missing-registration" };
|
|
106
|
+
if (request.from === request.to)
|
|
107
|
+
return { ok: true };
|
|
108
|
+
if (to.conductor === request.from || to.principal === request.from)
|
|
109
|
+
return { ok: true };
|
|
110
|
+
if (hasSharedScope(from, to) && canIssueMandate(from)) {
|
|
111
|
+
return { ok: true };
|
|
112
|
+
}
|
|
113
|
+
return { ok: false, reason: "unauthorized" };
|
|
114
|
+
}
|
|
115
|
+
export function loggingDriver(log = () => undefined) {
|
|
116
|
+
return {
|
|
117
|
+
drive(request) {
|
|
118
|
+
log(`drive[logging]: ${request.to} <= ${request.instructionLine}`);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export function nativeBackchannelDriver(options = {}) {
|
|
124
|
+
return {
|
|
125
|
+
drive(request) {
|
|
126
|
+
return options.send?.(request) ?? false;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export function localTmuxDriver(options = {}) {
|
|
131
|
+
const runtime = options.runtime ?? defaultRelauncherRuntime;
|
|
132
|
+
return {
|
|
133
|
+
drive(request) {
|
|
134
|
+
const tmux = request.launchContext?.tmux;
|
|
135
|
+
if (!tmux)
|
|
136
|
+
return false;
|
|
137
|
+
const target = tmuxTarget(tmux);
|
|
138
|
+
const ok = runtime.run("tmux", [
|
|
139
|
+
"send-keys",
|
|
140
|
+
"-t",
|
|
141
|
+
target,
|
|
142
|
+
request.instructionLine,
|
|
143
|
+
"Enter"
|
|
144
|
+
]);
|
|
145
|
+
options.log?.(`drive[local-tmux]: ${request.to} -> ${target} (${ok ? "ok" : "failed"})`);
|
|
146
|
+
return ok;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export function headlessDriver(options = {}) {
|
|
151
|
+
const runtime = options.runtime ?? defaultRelauncherRuntime;
|
|
152
|
+
return {
|
|
153
|
+
drive(request) {
|
|
154
|
+
const base = request.launchContext?.command;
|
|
155
|
+
if (!base)
|
|
156
|
+
return false;
|
|
157
|
+
const command = `${base} ${shellQuote(request.instructionLine)}`;
|
|
158
|
+
const ok = runtime.spawnDetached(command, { cwd: request.launchContext?.cwd });
|
|
159
|
+
options.log?.(`drive[headless]: ${request.to} -> detached (${ok ? "spawned" : "failed"})`);
|
|
160
|
+
return ok;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export function chainDriver(...drivers) {
|
|
165
|
+
return {
|
|
166
|
+
async drive(request) {
|
|
167
|
+
for (const driver of drivers) {
|
|
168
|
+
if (await driver.drive(request))
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/drive/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D4 receive side. A remote relance request is just an inbox envelope; this
|
|
3
|
+
* consumer turns `drumbeat.resume` messages into local relauncher calls.
|
|
4
|
+
*/
|
|
5
|
+
import { type LocalStore } from "../local-files/store.js";
|
|
6
|
+
import type { H2ARelauncher } from "./watch.js";
|
|
7
|
+
export type H2ARelanceInboxSkipReason = "malformed" | "target-mismatch" | "requester-mismatch" | "no-entry" | "done" | "terminal" | "declined" | "failed";
|
|
8
|
+
export interface H2ARelanceInboxSkip {
|
|
9
|
+
readonly envelopeId: string;
|
|
10
|
+
readonly reason: H2ARelanceInboxSkipReason;
|
|
11
|
+
readonly target?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface H2ARelanceInboxResult {
|
|
14
|
+
readonly relanced: readonly string[];
|
|
15
|
+
readonly skipped: readonly H2ARelanceInboxSkip[];
|
|
16
|
+
}
|
|
17
|
+
export interface RelanceFromInboxOptions {
|
|
18
|
+
readonly instances?: readonly string[];
|
|
19
|
+
readonly relauncher: H2ARelauncher;
|
|
20
|
+
readonly store?: LocalStore;
|
|
21
|
+
readonly now?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Drain `drumbeat.resume` envelopes from local inboxes. Non-D4 inbox mail is
|
|
25
|
+
* left untouched; malformed or stale D4 messages are popped so they do not
|
|
26
|
+
* poison every future consume pass.
|
|
27
|
+
*/
|
|
28
|
+
export declare function relanceFromInbox(root: string, options: RelanceFromInboxOptions): Promise<H2ARelanceInboxResult>;
|
|
29
|
+
//# sourceMappingURL=inbox-relance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-relance.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/inbox-relance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,yBAAyB,GACjC,WAAW,GACX,iBAAiB,GACjB,oBAAoB,GACpB,UAAU,GACV,MAAM,GACN,UAAU,GACV,UAAU,GACV,QAAQ,CAAC;AAEb,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CA4EhC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D4 receive side. A remote relance request is just an inbox envelope; this
|
|
3
|
+
* consumer turns `drumbeat.resume` messages into local relauncher calls.
|
|
4
|
+
*/
|
|
5
|
+
import { H2A_DRUMBEAT_RESUME_BODY_KIND, parseDrumbeatResumeBody } from "@sentropic/h2a";
|
|
6
|
+
import { createLocalStore } from "../local-files/store.js";
|
|
7
|
+
import { markRelanced, readDrumbeatEntry } from "./registry.js";
|
|
8
|
+
function hasResumeKind(envelope) {
|
|
9
|
+
const body = envelope.body;
|
|
10
|
+
return (typeof body === "object" &&
|
|
11
|
+
body !== null &&
|
|
12
|
+
body.kind === H2A_DRUMBEAT_RESUME_BODY_KIND);
|
|
13
|
+
}
|
|
14
|
+
function findingFromEntry(entry) {
|
|
15
|
+
return {
|
|
16
|
+
instance: entry.instance,
|
|
17
|
+
reason: entry.workStatus === "out-of-tokens" ? "out-of-tokens" : "stopped",
|
|
18
|
+
workStatus: entry.workStatus,
|
|
19
|
+
...(entry.launchContext ? { launchContext: entry.launchContext } : {}),
|
|
20
|
+
relanceCount: entry.relanceCount
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Drain `drumbeat.resume` envelopes from local inboxes. Non-D4 inbox mail is
|
|
25
|
+
* left untouched; malformed or stale D4 messages are popped so they do not
|
|
26
|
+
* poison every future consume pass.
|
|
27
|
+
*/
|
|
28
|
+
export async function relanceFromInbox(root, options) {
|
|
29
|
+
const store = options.store ?? createLocalStore({ root });
|
|
30
|
+
const instances = options.instances ?? store.listInstances().map((r) => r.instance);
|
|
31
|
+
const relanced = [];
|
|
32
|
+
const skipped = [];
|
|
33
|
+
for (const inboxInstance of instances) {
|
|
34
|
+
for (const envelope of store.readInbox(inboxInstance)) {
|
|
35
|
+
const body = parseDrumbeatResumeBody(envelope.body);
|
|
36
|
+
if (!body) {
|
|
37
|
+
if (hasResumeKind(envelope)) {
|
|
38
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
39
|
+
skipped.push({ envelopeId: envelope.id, reason: "malformed" });
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (body.target !== inboxInstance) {
|
|
44
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
45
|
+
skipped.push({ envelopeId: envelope.id, reason: "target-mismatch", target: body.target });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// Log-integrity / hygiene (DEC-117 authentication-only model): the
|
|
49
|
+
// resume's claimed `requestedBy` must equal the cryptographically
|
|
50
|
+
// verified signer (`acceptRemoteEnvelope` checks the signature against
|
|
51
|
+
// the registry before delivery). A mismatch is a forged/relabelled
|
|
52
|
+
// attribution — drop it so a relance is never recorded under a false
|
|
53
|
+
// requester. Security is already enforced at ingestion; this guards
|
|
54
|
+
// accountability only. (Skipped when no actor is present.)
|
|
55
|
+
const signer = envelope.actor?.instance;
|
|
56
|
+
if (signer && body.requestedBy !== signer) {
|
|
57
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
58
|
+
skipped.push({ envelopeId: envelope.id, reason: "requester-mismatch", target: body.target });
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const entry = readDrumbeatEntry(root, body.target);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
64
|
+
skipped.push({ envelopeId: envelope.id, reason: "no-entry", target: body.target });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (entry.workStatus === "done") {
|
|
68
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
69
|
+
skipped.push({ envelopeId: envelope.id, reason: "done", target: body.target });
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (entry.terminal) {
|
|
73
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
74
|
+
skipped.push({ envelopeId: envelope.id, reason: "terminal", target: body.target });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
let issued = false;
|
|
78
|
+
let failed = false;
|
|
79
|
+
try {
|
|
80
|
+
issued = await options.relauncher.relance(findingFromEntry(entry));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
failed = true;
|
|
84
|
+
}
|
|
85
|
+
store.popInboxMessage(inboxInstance, envelope.id);
|
|
86
|
+
if (issued) {
|
|
87
|
+
markRelanced(root, body.target, options.now);
|
|
88
|
+
relanced.push(body.target);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
skipped.push({
|
|
92
|
+
envelopeId: envelope.id,
|
|
93
|
+
reason: failed ? "failed" : "declined",
|
|
94
|
+
target: body.target
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { relanced, skipped };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=inbox-relance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-relance.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/inbox-relance.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,6 @@ export { loggingDecider, subagentDecider, type ReflexiveDecider, type DeciderRun
|
|
|
3
3
|
export { recordDrumbeatDecision, listDrumbeatDecisions, type H2ADrumbeatDecisionRecord } from "./decisions.js";
|
|
4
4
|
export { scanDrumbeat, H2A_DEFAULT_MAX_RELANCES, type H2ADrumbeatFinding, type H2ADrumbeatReason, type H2ADrumbeatScanResult, type ScanDrumbeatOptions } from "./scan.js";
|
|
5
5
|
export { drumbeatTick, runDrumbeatWatch, loggingRelauncher, type H2ARelauncher, type DrumbeatTickOptions, type DrumbeatTickResult, type DrumbeatWatchOptions } from "./watch.js";
|
|
6
|
-
export { localTmuxRelauncher, headlessRelauncher, chainRelauncher, tmuxTarget, defaultRelauncherRuntime, type RelauncherRuntime, type H2ARelauncherKind } from "./relaunchers.js";
|
|
6
|
+
export { localTmuxRelauncher, headlessRelauncher, remoteRelauncher, chainRelauncher, tmuxTarget, defaultRelauncherRuntime, type RelauncherRuntime, type RemoteEndpointResolver, type RemoteEnvelopeSender, type RemoteRelauncherOptions, type H2ARelauncherKind } from "./relaunchers.js";
|
|
7
|
+
export { relanceFromInbox, type H2ARelanceInboxResult, type H2ARelanceInboxSkip, type H2ARelanceInboxSkipReason, type RelanceFromInboxOptions } from "./inbox-relance.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,yBAAyB,EAC/B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,yBAAyB,EAC/B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC"}
|
|
@@ -3,5 +3,6 @@ export { loggingDecider, subagentDecider } from "./deciders.js";
|
|
|
3
3
|
export { recordDrumbeatDecision, listDrumbeatDecisions } from "./decisions.js";
|
|
4
4
|
export { scanDrumbeat, H2A_DEFAULT_MAX_RELANCES } from "./scan.js";
|
|
5
5
|
export { drumbeatTick, runDrumbeatWatch, loggingRelauncher } from "./watch.js";
|
|
6
|
-
export { localTmuxRelauncher, headlessRelauncher, chainRelauncher, tmuxTarget, defaultRelauncherRuntime } from "./relaunchers.js";
|
|
6
|
+
export { localTmuxRelauncher, headlessRelauncher, remoteRelauncher, chainRelauncher, tmuxTarget, defaultRelauncherRuntime } from "./relaunchers.js";
|
|
7
|
+
export { relanceFromInbox } from "./inbox-relance.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,wBAAwB,EAKzB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,wBAAwB,EAKzB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,wBAAwB,EAMzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAKjB,MAAM,oBAAoB,CAAC"}
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* behind an injectable `RelauncherRuntime` so the adapters are unit-testable
|
|
15
15
|
* with no real tmux or child processes. The remote adapter is D4.
|
|
16
16
|
*/
|
|
17
|
+
import { type H2AActorRef, type H2ADrumbeatResumeBody, type H2AEnvelope } from "@sentropic/h2a";
|
|
18
|
+
import { type SendRemoteOptions, type SendRemoteResult } from "../remote/client.js";
|
|
17
19
|
import type { H2ARelauncher } from "./watch.js";
|
|
18
20
|
/** Process I/O the adapters need — injected so tests supply a fake. */
|
|
19
21
|
export interface RelauncherRuntime {
|
|
@@ -31,6 +33,23 @@ interface RelauncherCommonOptions {
|
|
|
31
33
|
runtime?: RelauncherRuntime;
|
|
32
34
|
log?: (line: string) => void;
|
|
33
35
|
}
|
|
36
|
+
export type RemoteEndpointResolver = (instance: string) => string | undefined | Promise<string | undefined>;
|
|
37
|
+
export type RemoteEnvelopeSender = (url: string, envelope: H2AEnvelope<H2ADrumbeatResumeBody>, options: SendRemoteOptions) => Promise<SendRemoteResult>;
|
|
38
|
+
export interface RemoteRelauncherOptions {
|
|
39
|
+
/** Store root used by the default endpoint resolver. */
|
|
40
|
+
root?: string;
|
|
41
|
+
/** Actor placed on the resume envelope and used as the signature signer. */
|
|
42
|
+
actor: H2AActorRef;
|
|
43
|
+
/** Signer's ed25519 private-key PEM. */
|
|
44
|
+
privateKeyPem: string;
|
|
45
|
+
/** Resolve the target instance to its remote endpoint. Defaults to registry lookup. */
|
|
46
|
+
resolveEndpoint?: RemoteEndpointResolver;
|
|
47
|
+
/** Transport override for tests. Defaults to sendRemoteEnvelope. */
|
|
48
|
+
sendImpl?: RemoteEnvelopeSender;
|
|
49
|
+
/** Clock source for deterministic tests. */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
log?: (line: string) => void;
|
|
52
|
+
}
|
|
34
53
|
/**
|
|
35
54
|
* Build a tmux target-pane spec from a captured `launchContext.tmux`. With a
|
|
36
55
|
* window it is `session:window.pane`; otherwise the pane is assumed to be a
|
|
@@ -48,6 +67,11 @@ export declare function localTmuxRelauncher(options?: RelauncherCommonOptions):
|
|
|
48
67
|
export declare function headlessRelauncher(options?: RelauncherCommonOptions): H2ARelauncher;
|
|
49
68
|
/** Try each adapter in order; the first to issue a relance wins (D3 fallback). */
|
|
50
69
|
export declare function chainRelauncher(...relaunchers: readonly H2ARelauncher[]): H2ARelauncher;
|
|
51
|
-
|
|
70
|
+
/**
|
|
71
|
+
* D4 remote adapter: sign a `drumbeat.resume` envelope and deliver it to the
|
|
72
|
+
* target instance's declared remote endpoint. It never executes remote code.
|
|
73
|
+
*/
|
|
74
|
+
export declare function remoteRelauncher(options: RemoteRelauncherOptions): H2ARelauncher;
|
|
75
|
+
export type H2ARelauncherKind = "logging" | "local-tmux" | "headless" | "remote" | "auto";
|
|
52
76
|
export {};
|
|
53
77
|
//# sourceMappingURL=relaunchers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relaunchers.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/relaunchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IACpD,sEAAsE;IACtE,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;IACnE,4DAA4D;IAC5D,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,wBAAwB,EAAE,iBAmBtC,CAAC;AAEF,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAExF;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,uBAA4B,GAAG,aAAa,CAexF;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,uBAA4B,GAAG,aAAa,CAcvF;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,WAAW,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CASvF;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"relaunchers.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/relaunchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IACpD,sEAAsE;IACtE,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;IACnE,4DAA4D;IAC5D,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,wBAAwB,EAAE,iBAmBtC,CAAC;AAEF,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,sBAAsB,GAAG,CACnC,QAAQ,EAAE,MAAM,KACb,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,WAAW,CAAC,qBAAqB,CAAC,EAC5C,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE/B,MAAM,WAAW,uBAAuB;IACtC,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,KAAK,EAAE,WAAW,CAAC;IACnB,wCAAwC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAExF;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,uBAA4B,GAAG,aAAa,CAexF;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,uBAA4B,GAAG,aAAa,CAcvF;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,WAAW,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CASvF;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,aAAa,CAiDhF;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC"}
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
* with no real tmux or child processes. The remote adapter is D4.
|
|
16
16
|
*/
|
|
17
17
|
import { spawn, spawnSync } from "node:child_process";
|
|
18
|
+
import { randomBytes } from "node:crypto";
|
|
19
|
+
import { H2A_DRUMBEAT_RESUME_BODY_KIND, createEnvelope } from "@sentropic/h2a";
|
|
20
|
+
import { createLocalStore } from "../local-files/store.js";
|
|
21
|
+
import { sendRemoteEnvelope } from "../remote/client.js";
|
|
18
22
|
export const defaultRelauncherRuntime = {
|
|
19
23
|
run(file, args) {
|
|
20
24
|
const res = spawnSync(file, [...args], { stdio: "ignore" });
|
|
@@ -90,4 +94,53 @@ export function chainRelauncher(...relaunchers) {
|
|
|
90
94
|
}
|
|
91
95
|
};
|
|
92
96
|
}
|
|
97
|
+
function envelopeId(now) {
|
|
98
|
+
return `env:${now}:${randomBytes(4).toString("hex")}`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* D4 remote adapter: sign a `drumbeat.resume` envelope and deliver it to the
|
|
102
|
+
* target instance's declared remote endpoint. It never executes remote code.
|
|
103
|
+
*/
|
|
104
|
+
export function remoteRelauncher(options) {
|
|
105
|
+
const store = options.root ? createLocalStore({ root: options.root }) : undefined;
|
|
106
|
+
const resolveEndpoint = options.resolveEndpoint ??
|
|
107
|
+
((instance) => store?.findInstance(instance)?.endpoints.find((e) => e.kind === "remote")?.uri);
|
|
108
|
+
const sendImpl = options.sendImpl ?? sendRemoteEnvelope;
|
|
109
|
+
return {
|
|
110
|
+
async relance(finding) {
|
|
111
|
+
const endpoint = await resolveEndpoint(finding.instance);
|
|
112
|
+
if (!endpoint) {
|
|
113
|
+
options.log?.(`drumbeat[remote]: no remote endpoint for ${finding.instance}`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const now = options.now?.() ?? Date.now();
|
|
117
|
+
const envelope = createEnvelope({
|
|
118
|
+
id: envelopeId(now),
|
|
119
|
+
type: "event",
|
|
120
|
+
actor: options.actor,
|
|
121
|
+
target: { instance: finding.instance },
|
|
122
|
+
body: {
|
|
123
|
+
kind: H2A_DRUMBEAT_RESUME_BODY_KIND,
|
|
124
|
+
target: finding.instance,
|
|
125
|
+
reason: finding.reason,
|
|
126
|
+
requestedBy: options.actor.instance
|
|
127
|
+
},
|
|
128
|
+
createdAt: new Date(now).toISOString()
|
|
129
|
+
});
|
|
130
|
+
try {
|
|
131
|
+
const result = await sendImpl(endpoint, envelope, {
|
|
132
|
+
by: options.actor.instance,
|
|
133
|
+
privateKeyPem: options.privateKeyPem
|
|
134
|
+
});
|
|
135
|
+
const ok = result.status >= 200 && result.status < 300;
|
|
136
|
+
options.log?.(`drumbeat[remote]: relay ${finding.instance} -> ${endpoint} (${result.status}${ok ? " ok" : " failed"})`);
|
|
137
|
+
return ok;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
options.log?.(`drumbeat[remote]: relay ${finding.instance} -> ${endpoint} failed (${error.message})`);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
93
146
|
//# sourceMappingURL=relaunchers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relaunchers.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/relaunchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"relaunchers.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/relaunchers.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,8 @@ export interface H2ADrumbeatScanResult {
|
|
|
23
23
|
}
|
|
24
24
|
export interface ScanDrumbeatOptions {
|
|
25
25
|
readonly maxRelances?: number;
|
|
26
|
+
/** Instances already handled by a pre-scan D4 inbox consume pass. */
|
|
27
|
+
readonly skipInstances?: readonly string[];
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Classify the registry: `done` entries are skipped (a clean finish);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpE,+EAA+E;AAC/E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,eAAe,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACjD,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpE,+EAA+E;AAC/E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,eAAe,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACjD,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,qBAAqB,CAsBvB"}
|
|
@@ -14,9 +14,12 @@ export const H2A_DEFAULT_MAX_RELANCES = 3;
|
|
|
14
14
|
*/
|
|
15
15
|
export function scanDrumbeat(root, options = {}) {
|
|
16
16
|
const maxRelances = options.maxRelances ?? H2A_DEFAULT_MAX_RELANCES;
|
|
17
|
+
const skip = new Set(options.skipInstances ?? []);
|
|
17
18
|
const findings = [];
|
|
18
19
|
const exhausted = [];
|
|
19
20
|
for (const entry of listDrumbeat(root)) {
|
|
21
|
+
if (skip.has(entry.instance))
|
|
22
|
+
continue;
|
|
20
23
|
if (entry.workStatus === "done")
|
|
21
24
|
continue;
|
|
22
25
|
if (entry.terminal)
|