@sentropic/h2a-cli 0.20.2 → 0.21.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.
Files changed (54) hide show
  1. package/dist/bin.js +4 -1
  2. package/dist/bin.js.map +1 -1
  3. package/dist/cli-contract.d.ts.map +1 -1
  4. package/dist/cli-contract.js +10 -2
  5. package/dist/cli-contract.js.map +1 -1
  6. package/dist/cli.d.ts +5 -0
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +108 -6
  9. package/dist/cli.js.map +1 -1
  10. package/dist/index.d.ts +4 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/runtime/drumbeat/inbox-relance.d.ts +29 -0
  15. package/dist/runtime/drumbeat/inbox-relance.d.ts.map +1 -0
  16. package/dist/runtime/drumbeat/inbox-relance.js +101 -0
  17. package/dist/runtime/drumbeat/inbox-relance.js.map +1 -0
  18. package/dist/runtime/drumbeat/index.d.ts +2 -1
  19. package/dist/runtime/drumbeat/index.d.ts.map +1 -1
  20. package/dist/runtime/drumbeat/index.js +2 -1
  21. package/dist/runtime/drumbeat/index.js.map +1 -1
  22. package/dist/runtime/drumbeat/relaunchers.d.ts +25 -1
  23. package/dist/runtime/drumbeat/relaunchers.d.ts.map +1 -1
  24. package/dist/runtime/drumbeat/relaunchers.js +53 -0
  25. package/dist/runtime/drumbeat/relaunchers.js.map +1 -1
  26. package/dist/runtime/drumbeat/scan.d.ts +2 -0
  27. package/dist/runtime/drumbeat/scan.d.ts.map +1 -1
  28. package/dist/runtime/drumbeat/scan.js +3 -0
  29. package/dist/runtime/drumbeat/scan.js.map +1 -1
  30. package/dist/runtime/drumbeat/watch.d.ts +3 -1
  31. package/dist/runtime/drumbeat/watch.d.ts.map +1 -1
  32. package/dist/runtime/drumbeat/watch.js +6 -2
  33. package/dist/runtime/drumbeat/watch.js.map +1 -1
  34. package/dist/runtime/identity/bindings.d.ts +60 -0
  35. package/dist/runtime/identity/bindings.d.ts.map +1 -0
  36. package/dist/runtime/identity/bindings.js +90 -0
  37. package/dist/runtime/identity/bindings.js.map +1 -0
  38. package/dist/runtime/identity/index.d.ts +8 -0
  39. package/dist/runtime/identity/index.d.ts.map +1 -0
  40. package/dist/runtime/identity/index.js +5 -0
  41. package/dist/runtime/identity/index.js.map +1 -0
  42. package/dist/runtime/identity/migration.d.ts +46 -0
  43. package/dist/runtime/identity/migration.d.ts.map +1 -0
  44. package/dist/runtime/identity/migration.js +63 -0
  45. package/dist/runtime/identity/migration.js.map +1 -0
  46. package/dist/runtime/identity/readers.d.ts +11 -0
  47. package/dist/runtime/identity/readers.d.ts.map +1 -0
  48. package/dist/runtime/identity/readers.js +114 -0
  49. package/dist/runtime/identity/readers.js.map +1 -0
  50. package/dist/runtime/identity/resolver.d.ts +50 -0
  51. package/dist/runtime/identity/resolver.d.ts.map +1 -0
  52. package/dist/runtime/identity/resolver.js +61 -0
  53. package/dist/runtime/identity/resolver.js.map +1 -0
  54. package/package.json +2 -2
@@ -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,EAGzB,MAAM,kBAAkB,CAAC"}
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
- export type H2ARelauncherKind = "logging" | "local-tmux" | "headless" | "auto";
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":"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"}
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;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,qBAAqB,CAoBvB"}
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)
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,YAAY,EAAyB,MAAM,eAAe,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAuB1C;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,UAA+B,EAAE;IAEjC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,wBAAwB,CAAC;IACpE,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM;YAAE,SAAS;QAC1C,IAAI,KAAK,CAAC,QAAQ;YAAE,SAAS,CAAC,uDAAuD;QACrF,IAAI,KAAK,CAAC,YAAY,IAAI,WAAW,EAAE,CAAC;YACtC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,KAAK,CAAC,UAAU,KAAK,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;YAC1E,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,YAAY,EAAyB,MAAM,eAAe,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAyB1C;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,UAA+B,EAAE;IAEjC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,wBAAwB,CAAC;IACpE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,SAAS;QACvC,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM;YAAE,SAAS;QAC1C,IAAI,KAAK,CAAC,QAAQ;YAAE,SAAS,CAAC,uDAAuD;QACrF,IAAI,KAAK,CAAC,YAAY,IAAI,WAAW,EAAE,CAAC;YACtC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,KAAK,CAAC,UAAU,KAAK,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;YAC1E,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC"}
@@ -17,6 +17,8 @@ export interface H2ARelauncher {
17
17
  /** A relauncher that only logs — the D2 default until real adapters land. */
18
18
  export declare function loggingRelauncher(write: (line: string) => void): H2ARelauncher;
19
19
  export interface DrumbeatTickOptions extends ScanDrumbeatOptions {
20
+ /** D4: optional pre-scan hook, used by watch to consume remote resume inboxes. */
21
+ beforeScan?: () => readonly string[] | Promise<readonly string[]>;
20
22
  /** Hook for entries that hit the relance cap → escalate to PRINCIPAL (D7). */
21
23
  onExhausted?: (entry: H2ADrumbeatEntry) => void | Promise<void>;
22
24
  now?: number;
@@ -43,7 +45,7 @@ export interface DrumbeatWatchOptions extends DrumbeatTickOptions {
43
45
  intervalMs?: number;
44
46
  /** Stop the loop. */
45
47
  signal?: AbortSignal;
46
- onTick?: (result: DrumbeatTickResult) => void;
48
+ onTick?: (result: DrumbeatTickResult) => void | Promise<void>;
47
49
  }
48
50
  /**
49
51
  * Run the drumbeat loop until `signal` aborts. Each beat: scan → relance via
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/watch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAsB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAgB,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5F,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,aAAa,CAS9E;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnG,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnG;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,0EAA0E;AAC1E,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CA0D7B;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C;AAiBD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAQf"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/runtime/drumbeat/watch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAsB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAgB,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5F,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,aAAa,CAS9E;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAClE,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnG,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnG;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,0EAA0E;AAC1E,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CA8D7B;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAiBD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -19,7 +19,11 @@ export function loggingRelauncher(write) {
19
19
  }
20
20
  /** One scan→dispatch pass (no timers) — the testable unit of the loop. */
21
21
  export async function drumbeatTick(root, relauncher, options = {}) {
22
- const { findings, exhausted } = scanDrumbeat(root, { maxRelances: options.maxRelances });
22
+ const preRelanced = await options.beforeScan?.();
23
+ const { findings, exhausted } = scanDrumbeat(root, {
24
+ maxRelances: options.maxRelances,
25
+ skipInstances: [...(options.skipInstances ?? []), ...(preRelanced ?? [])]
26
+ });
23
27
  const relanced = [];
24
28
  const k = options.deciderAfter ?? 1;
25
29
  for (const finding of findings) {
@@ -98,7 +102,7 @@ export async function runDrumbeatWatch(root, relauncher, options = {}) {
98
102
  const intervalMs = options.intervalMs ?? 30_000;
99
103
  while (!options.signal?.aborted) {
100
104
  const result = await drumbeatTick(root, relauncher, options);
101
- options.onTick?.(result);
105
+ await options.onTick?.(result);
102
106
  if (options.signal?.aborted)
103
107
  break;
104
108
  await delay(intervalMs, options.signal);
@@ -1 +1 @@
1
- {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/watch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/runtime/drumbeat/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Identity binding registry + proof-of-possession (DEC-116, F1 — the
3
+ * load-bearing security fix).
4
+ *
5
+ * Reconnect de-collision binds `(host, providerSessionId, workspaceId)` → the
6
+ * agent's perennial identity. **RECLAIM requires proof-of-possession**: the
7
+ * connector must sign a fresh nonce with the ed25519 key already bound to that
8
+ * identity (verified against the instance's active keys). The provider session
9
+ * id is a spoofable *routing hint* — never the authenticator. No valid
10
+ * signature → **MINT** a fresh identity (so a process presenting a victim's
11
+ * id/workspace, without the key, gets a new identity, not the victim's inbox).
12
+ * The read → decide → append runs in ONE lock (no reclaim/mint race, F3).
13
+ */
14
+ import { type H2ASignature } from "@sentropic/h2a";
15
+ export interface H2AIdentityBinding {
16
+ readonly host: string;
17
+ readonly providerSessionId: string;
18
+ readonly workspaceId: string;
19
+ /** The addressable handle `host:label:uuid12` — what the keyring + addressing key on. */
20
+ readonly instance: string;
21
+ /** The perennial agent UUID (its first 12 hex form `uuid12` in the instance). */
22
+ readonly agentUuid: string;
23
+ readonly at: string;
24
+ }
25
+ export interface IdentityBindingKey {
26
+ readonly host: string;
27
+ readonly providerSessionId: string;
28
+ readonly workspaceId: string;
29
+ }
30
+ export declare function listBindings(root: string): H2AIdentityBinding[];
31
+ /** The latest binding matching the key (append-only → last wins), or undefined. */
32
+ export declare function findBinding(root: string, key: IdentityBindingKey): H2AIdentityBinding | undefined;
33
+ /**
34
+ * Verify a reclaim proof: `signature` over `nonce` must verify against ANY of
35
+ * the agent's active public keys. Total — never throws.
36
+ */
37
+ export declare function verifyReclaimProof(nonce: string, signature: H2ASignature, publicKeys: readonly string[]): boolean;
38
+ export interface ReclaimOrMintDeps {
39
+ /** PoP: true iff the connector proved possession of the bound instance's key. */
40
+ verifyProof(binding: H2AIdentityBinding): boolean;
41
+ /** Mint a fresh identity (new uuid + derived instance) when no reclaim. */
42
+ mint(): {
43
+ instance: string;
44
+ agentUuid: string;
45
+ };
46
+ now(): number;
47
+ }
48
+ export interface ReclaimOrMintResult {
49
+ readonly action: "reclaim" | "mint";
50
+ readonly instance: string;
51
+ readonly agentUuid: string;
52
+ }
53
+ /**
54
+ * Atomically (one lock) reclaim the existing binding iff it exists AND
55
+ * proof-of-possession passes; otherwise mint a fresh identity and record the new
56
+ * binding. Spoofing the id without the key → mint (a new identity), never a
57
+ * reclaim of someone else's.
58
+ */
59
+ export declare function reclaimOrMint(root: string, key: IdentityBindingKey, deps: ReclaimOrMintDeps): ReclaimOrMintResult;
60
+ //# sourceMappingURL=bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../../src/runtime/identity/bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIpE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAYD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAa/D;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,CAYjG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,YAAY,EACvB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAST;AAED,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;IAClD,2EAA2E;IAC3E,IAAI,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,GAAG,IAAI,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,iBAAiB,GACtB,mBAAmB,CAerB"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Identity binding registry + proof-of-possession (DEC-116, F1 — the
3
+ * load-bearing security fix).
4
+ *
5
+ * Reconnect de-collision binds `(host, providerSessionId, workspaceId)` → the
6
+ * agent's perennial identity. **RECLAIM requires proof-of-possession**: the
7
+ * connector must sign a fresh nonce with the ed25519 key already bound to that
8
+ * identity (verified against the instance's active keys). The provider session
9
+ * id is a spoofable *routing hint* — never the authenticator. No valid
10
+ * signature → **MINT** a fresh identity (so a process presenting a victim's
11
+ * id/workspace, without the key, gets a new identity, not the victim's inbox).
12
+ * The read → decide → append runs in ONE lock (no reclaim/mint race, F3).
13
+ */
14
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { verifyCanonical } from "@sentropic/h2a";
17
+ import { localStorePaths, withLockSync } from "../local-files/index.js";
18
+ function identityDir(root) {
19
+ return join(localStorePaths(root).root, "identity");
20
+ }
21
+ function bindingsFile(root) {
22
+ return join(identityDir(root), "bindings.jsonl");
23
+ }
24
+ function bindingsLock(root) {
25
+ return join(identityDir(root), ".lock");
26
+ }
27
+ export function listBindings(root) {
28
+ const f = bindingsFile(root);
29
+ if (!existsSync(f))
30
+ return [];
31
+ const out = [];
32
+ for (const line of readFileSync(f, "utf8").split("\n")) {
33
+ if (!line.trim())
34
+ continue;
35
+ try {
36
+ out.push(JSON.parse(line));
37
+ }
38
+ catch {
39
+ // skip malformed
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+ /** The latest binding matching the key (append-only → last wins), or undefined. */
45
+ export function findBinding(root, key) {
46
+ let found;
47
+ for (const b of listBindings(root)) {
48
+ if (b.host === key.host &&
49
+ b.providerSessionId === key.providerSessionId &&
50
+ b.workspaceId === key.workspaceId) {
51
+ found = b;
52
+ }
53
+ }
54
+ return found;
55
+ }
56
+ /**
57
+ * Verify a reclaim proof: `signature` over `nonce` must verify against ANY of
58
+ * the agent's active public keys. Total — never throws.
59
+ */
60
+ export function verifyReclaimProof(nonce, signature, publicKeys) {
61
+ for (const pem of publicKeys) {
62
+ try {
63
+ if (verifyCanonical(nonce, signature, pem))
64
+ return true;
65
+ }
66
+ catch {
67
+ // try the next active key
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ /**
73
+ * Atomically (one lock) reclaim the existing binding iff it exists AND
74
+ * proof-of-possession passes; otherwise mint a fresh identity and record the new
75
+ * binding. Spoofing the id without the key → mint (a new identity), never a
76
+ * reclaim of someone else's.
77
+ */
78
+ export function reclaimOrMint(root, key, deps) {
79
+ mkdirSync(identityDir(root), { recursive: true });
80
+ return withLockSync(bindingsLock(root), () => {
81
+ const existing = findBinding(root, key);
82
+ if (existing && deps.verifyProof(existing)) {
83
+ return { action: "reclaim", instance: existing.instance, agentUuid: existing.agentUuid };
84
+ }
85
+ const minted = deps.mint();
86
+ appendFileSync(bindingsFile(root), `${JSON.stringify({ ...key, instance: minted.instance, agentUuid: minted.agentUuid, at: new Date(deps.now()).toISOString() })}\n`, "utf8");
87
+ return { action: "mint", instance: minted.instance, agentUuid: minted.agentUuid };
88
+ });
89
+ }
90
+ //# sourceMappingURL=bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.js","sourceRoot":"","sources":["../../../src/runtime/identity/bindings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { resolveProviderSession } from "./resolver.js";
2
+ export type { ProviderSession, ProviderSessionReaders, ProviderSessionSource, ResolveProviderSessionInput } from "./resolver.js";
3
+ export { defaultProviderSessionReaders } from "./readers.js";
4
+ export { listBindings, findBinding, verifyReclaimProof, reclaimOrMint } from "./bindings.js";
5
+ export type { H2AIdentityBinding, IdentityBindingKey, ReclaimOrMintDeps, ReclaimOrMintResult } from "./bindings.js";
6
+ export { mergeInboxDedup, decideLegacyAdoption } from "./migration.js";
7
+ export type { LegacyAdoptionInput, LegacyAdoptionDecision } from "./migration.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/identity/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { resolveProviderSession } from "./resolver.js";
2
+ export { defaultProviderSessionReaders } from "./readers.js";
3
+ export { listBindings, findBinding, verifyReclaimProof, reclaimOrMint } from "./bindings.js";
4
+ export { mergeInboxDedup, decideLegacyAdoption } from "./migration.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/identity/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAOvD,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,eAAe,CAAC;AAOvB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}