pi-amq 0.1.1

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 (264) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +21 -0
  3. package/README.md +92 -0
  4. package/THIRD_PARTY_NOTICES.md +33 -0
  5. package/dist/extension/guidance.d.ts +25 -0
  6. package/dist/extension/guidance.d.ts.map +1 -0
  7. package/dist/extension/guidance.js +121 -0
  8. package/dist/extension/guidance.js.map +1 -0
  9. package/dist/extension/guide.d.ts +30 -0
  10. package/dist/extension/guide.d.ts.map +1 -0
  11. package/dist/extension/guide.js +128 -0
  12. package/dist/extension/guide.js.map +1 -0
  13. package/dist/extension/index.d.ts +4 -0
  14. package/dist/extension/index.d.ts.map +1 -0
  15. package/dist/extension/index.js +6 -0
  16. package/dist/extension/index.js.map +1 -0
  17. package/dist/extension/runtime.d.ts +48 -0
  18. package/dist/extension/runtime.d.ts.map +1 -0
  19. package/dist/extension/runtime.js +1095 -0
  20. package/dist/extension/runtime.js.map +1 -0
  21. package/dist/extension/tools.d.ts +12 -0
  22. package/dist/extension/tools.d.ts.map +1 -0
  23. package/dist/extension/tools.js +198 -0
  24. package/dist/extension/tools.js.map +1 -0
  25. package/dist/extension/worker-runtime.d.ts +34 -0
  26. package/dist/extension/worker-runtime.d.ts.map +1 -0
  27. package/dist/extension/worker-runtime.js +974 -0
  28. package/dist/extension/worker-runtime.js.map +1 -0
  29. package/dist/extension/worker-tools.d.ts +140 -0
  30. package/dist/extension/worker-tools.d.ts.map +1 -0
  31. package/dist/extension/worker-tools.js +217 -0
  32. package/dist/extension/worker-tools.js.map +1 -0
  33. package/dist/integration/confirmed-bind-onboarding.d.ts +44 -0
  34. package/dist/integration/confirmed-bind-onboarding.d.ts.map +1 -0
  35. package/dist/integration/confirmed-bind-onboarding.js +199 -0
  36. package/dist/integration/confirmed-bind-onboarding.js.map +1 -0
  37. package/dist/integration/fleet-view.d.ts +66 -0
  38. package/dist/integration/fleet-view.d.ts.map +1 -0
  39. package/dist/integration/fleet-view.js +238 -0
  40. package/dist/integration/fleet-view.js.map +1 -0
  41. package/dist/integration/fresh-session-dispatcher.d.ts +66 -0
  42. package/dist/integration/fresh-session-dispatcher.d.ts.map +1 -0
  43. package/dist/integration/fresh-session-dispatcher.js +103 -0
  44. package/dist/integration/fresh-session-dispatcher.js.map +1 -0
  45. package/dist/integration/launch-preview.d.ts +31 -0
  46. package/dist/integration/launch-preview.d.ts.map +1 -0
  47. package/dist/integration/launch-preview.js +325 -0
  48. package/dist/integration/launch-preview.js.map +1 -0
  49. package/dist/integration/transport-port.d.ts +39 -0
  50. package/dist/integration/transport-port.d.ts.map +1 -0
  51. package/dist/integration/transport-port.js +2 -0
  52. package/dist/integration/transport-port.js.map +1 -0
  53. package/dist/integration/worker-completion-notifier.d.ts +22 -0
  54. package/dist/integration/worker-completion-notifier.d.ts.map +1 -0
  55. package/dist/integration/worker-completion-notifier.js +81 -0
  56. package/dist/integration/worker-completion-notifier.js.map +1 -0
  57. package/dist/transport/amq-cli-adapter.d.ts +41 -0
  58. package/dist/transport/amq-cli-adapter.d.ts.map +1 -0
  59. package/dist/transport/amq-cli-adapter.js +291 -0
  60. package/dist/transport/amq-cli-adapter.js.map +1 -0
  61. package/dist/transport/amq-message.d.ts +47 -0
  62. package/dist/transport/amq-message.d.ts.map +1 -0
  63. package/dist/transport/amq-message.js +173 -0
  64. package/dist/transport/amq-message.js.map +1 -0
  65. package/dist/transport/amq-operations.d.ts +105 -0
  66. package/dist/transport/amq-operations.d.ts.map +1 -0
  67. package/dist/transport/amq-operations.js +320 -0
  68. package/dist/transport/amq-operations.js.map +1 -0
  69. package/dist/transport/atomic-json.d.ts +18 -0
  70. package/dist/transport/atomic-json.d.ts.map +1 -0
  71. package/dist/transport/atomic-json.js +90 -0
  72. package/dist/transport/atomic-json.js.map +1 -0
  73. package/dist/transport/binding-resolver.d.ts +46 -0
  74. package/dist/transport/binding-resolver.d.ts.map +1 -0
  75. package/dist/transport/binding-resolver.js +389 -0
  76. package/dist/transport/binding-resolver.js.map +1 -0
  77. package/dist/transport/bridge-journal.d.ts +100 -0
  78. package/dist/transport/bridge-journal.d.ts.map +1 -0
  79. package/dist/transport/bridge-journal.js +459 -0
  80. package/dist/transport/bridge-journal.js.map +1 -0
  81. package/dist/transport/dlq-retry-audit.d.ts +28 -0
  82. package/dist/transport/dlq-retry-audit.d.ts.map +1 -0
  83. package/dist/transport/dlq-retry-audit.js +66 -0
  84. package/dist/transport/dlq-retry-audit.js.map +1 -0
  85. package/dist/transport/inbox-pump.d.ts +81 -0
  86. package/dist/transport/inbox-pump.d.ts.map +1 -0
  87. package/dist/transport/inbox-pump.js +558 -0
  88. package/dist/transport/inbox-pump.js.map +1 -0
  89. package/dist/transport/index.d.ts +12 -0
  90. package/dist/transport/index.d.ts.map +1 -0
  91. package/dist/transport/index.js +12 -0
  92. package/dist/transport/index.js.map +1 -0
  93. package/dist/transport/presence-projector.d.ts +29 -0
  94. package/dist/transport/presence-projector.d.ts.map +1 -0
  95. package/dist/transport/presence-projector.js +73 -0
  96. package/dist/transport/presence-projector.js.map +1 -0
  97. package/dist/transport/priority-delivery-scheduler.d.ts +85 -0
  98. package/dist/transport/priority-delivery-scheduler.d.ts.map +1 -0
  99. package/dist/transport/priority-delivery-scheduler.js +210 -0
  100. package/dist/transport/priority-delivery-scheduler.js.map +1 -0
  101. package/dist/transport/receiver-lease.d.ts +102 -0
  102. package/dist/transport/receiver-lease.d.ts.map +1 -0
  103. package/dist/transport/receiver-lease.js +778 -0
  104. package/dist/transport/receiver-lease.js.map +1 -0
  105. package/dist/transport/runtime-status.d.ts +48 -0
  106. package/dist/transport/runtime-status.d.ts.map +1 -0
  107. package/dist/transport/runtime-status.js +71 -0
  108. package/dist/transport/runtime-status.js.map +1 -0
  109. package/dist/workflow/atomic-storage.d.ts +12 -0
  110. package/dist/workflow/atomic-storage.d.ts.map +1 -0
  111. package/dist/workflow/atomic-storage.js +104 -0
  112. package/dist/workflow/atomic-storage.js.map +1 -0
  113. package/dist/workflow/budget.d.ts +18 -0
  114. package/dist/workflow/budget.d.ts.map +1 -0
  115. package/dist/workflow/budget.js +74 -0
  116. package/dist/workflow/budget.js.map +1 -0
  117. package/dist/workflow/index.d.ts +17 -0
  118. package/dist/workflow/index.d.ts.map +1 -0
  119. package/dist/workflow/index.js +17 -0
  120. package/dist/workflow/index.js.map +1 -0
  121. package/dist/workflow/lifecycle-projection.d.ts +18 -0
  122. package/dist/workflow/lifecycle-projection.d.ts.map +1 -0
  123. package/dist/workflow/lifecycle-projection.js +22 -0
  124. package/dist/workflow/lifecycle-projection.js.map +1 -0
  125. package/dist/workflow/model-fallback.d.ts +2 -0
  126. package/dist/workflow/model-fallback.d.ts.map +1 -0
  127. package/dist/workflow/model-fallback.js +17 -0
  128. package/dist/workflow/model-fallback.js.map +1 -0
  129. package/dist/workflow/pi-session-fork.d.ts +18 -0
  130. package/dist/workflow/pi-session-fork.d.ts.map +1 -0
  131. package/dist/workflow/pi-session-fork.js +80 -0
  132. package/dist/workflow/pi-session-fork.js.map +1 -0
  133. package/dist/workflow/run-artifacts.d.ts +5 -0
  134. package/dist/workflow/run-artifacts.d.ts.map +1 -0
  135. package/dist/workflow/run-artifacts.js +25 -0
  136. package/dist/workflow/run-artifacts.js.map +1 -0
  137. package/dist/workflow/run-cleanup.d.ts +70 -0
  138. package/dist/workflow/run-cleanup.d.ts.map +1 -0
  139. package/dist/workflow/run-cleanup.js +222 -0
  140. package/dist/workflow/run-cleanup.js.map +1 -0
  141. package/dist/workflow/run-gate.d.ts +43 -0
  142. package/dist/workflow/run-gate.d.ts.map +1 -0
  143. package/dist/workflow/run-gate.js +70 -0
  144. package/dist/workflow/run-gate.js.map +1 -0
  145. package/dist/workflow/run-store.d.ts +208 -0
  146. package/dist/workflow/run-store.d.ts.map +1 -0
  147. package/dist/workflow/run-store.js +2965 -0
  148. package/dist/workflow/run-store.js.map +1 -0
  149. package/dist/workflow/spawn-confirmation.d.ts +44 -0
  150. package/dist/workflow/spawn-confirmation.d.ts.map +1 -0
  151. package/dist/workflow/spawn-confirmation.js +228 -0
  152. package/dist/workflow/spawn-confirmation.js.map +1 -0
  153. package/dist/workflow/system-process-inspector.d.ts +9 -0
  154. package/dist/workflow/system-process-inspector.d.ts.map +1 -0
  155. package/dist/workflow/system-process-inspector.js +129 -0
  156. package/dist/workflow/system-process-inspector.js.map +1 -0
  157. package/dist/workflow/worker-child-extension.d.ts +3 -0
  158. package/dist/workflow/worker-child-extension.d.ts.map +1 -0
  159. package/dist/workflow/worker-child-extension.js +182 -0
  160. package/dist/workflow/worker-child-extension.js.map +1 -0
  161. package/dist/workflow/worker-gate.d.ts +74 -0
  162. package/dist/workflow/worker-gate.d.ts.map +1 -0
  163. package/dist/workflow/worker-gate.js +165 -0
  164. package/dist/workflow/worker-gate.js.map +1 -0
  165. package/dist/workflow/worker-launch.d.ts +65 -0
  166. package/dist/workflow/worker-launch.d.ts.map +1 -0
  167. package/dist/workflow/worker-launch.js +338 -0
  168. package/dist/workflow/worker-launch.js.map +1 -0
  169. package/dist/workflow/worker-model-catalog.d.ts +36 -0
  170. package/dist/workflow/worker-model-catalog.d.ts.map +1 -0
  171. package/dist/workflow/worker-model-catalog.js +105 -0
  172. package/dist/workflow/worker-model-catalog.js.map +1 -0
  173. package/dist/workflow/worker-process-supervisor.d.ts +110 -0
  174. package/dist/workflow/worker-process-supervisor.d.ts.map +1 -0
  175. package/dist/workflow/worker-process-supervisor.js +1188 -0
  176. package/dist/workflow/worker-process-supervisor.js.map +1 -0
  177. package/dist/workflow/worker-prompt-capsule.d.ts +32 -0
  178. package/dist/workflow/worker-prompt-capsule.d.ts.map +1 -0
  179. package/dist/workflow/worker-prompt-capsule.js +52 -0
  180. package/dist/workflow/worker-prompt-capsule.js.map +1 -0
  181. package/dist/workflow/worker-role-presets.d.ts +38 -0
  182. package/dist/workflow/worker-role-presets.d.ts.map +1 -0
  183. package/dist/workflow/worker-role-presets.js +201 -0
  184. package/dist/workflow/worker-role-presets.js.map +1 -0
  185. package/dist/workflow/workflow-doctor.d.ts +57 -0
  186. package/dist/workflow/workflow-doctor.d.ts.map +1 -0
  187. package/dist/workflow/workflow-doctor.js +289 -0
  188. package/dist/workflow/workflow-doctor.js.map +1 -0
  189. package/dist/workflow/workflow-lease.d.ts +125 -0
  190. package/dist/workflow/workflow-lease.d.ts.map +1 -0
  191. package/dist/workflow/workflow-lease.js +689 -0
  192. package/dist/workflow/workflow-lease.js.map +1 -0
  193. package/dist/workflow/workflow-types.d.ts +335 -0
  194. package/dist/workflow/workflow-types.d.ts.map +1 -0
  195. package/dist/workflow/workflow-types.js +11 -0
  196. package/dist/workflow/workflow-types.js.map +1 -0
  197. package/dist/workflow/workspace-paths.d.ts +4 -0
  198. package/dist/workflow/workspace-paths.d.ts.map +1 -0
  199. package/dist/workflow/workspace-paths.js +22 -0
  200. package/dist/workflow/workspace-paths.js.map +1 -0
  201. package/docs/conformance.md +116 -0
  202. package/docs/demo-transcript.md +34 -0
  203. package/docs/design.md +1481 -0
  204. package/docs/operator-guide.md +100 -0
  205. package/extension/guidance.ts +162 -0
  206. package/extension/guide.ts +155 -0
  207. package/extension/index.ts +8 -0
  208. package/extension/runtime.ts +1224 -0
  209. package/extension/tools.ts +221 -0
  210. package/extension/worker-runtime.ts +1150 -0
  211. package/extension/worker-tools.ts +276 -0
  212. package/integration/confirmed-bind-onboarding.ts +296 -0
  213. package/integration/fleet-view.ts +286 -0
  214. package/integration/fresh-session-dispatcher.ts +166 -0
  215. package/integration/launch-preview.ts +396 -0
  216. package/integration/transport-port.ts +29 -0
  217. package/integration/worker-completion-notifier.ts +98 -0
  218. package/package.json +55 -0
  219. package/roles/oracle.md +9 -0
  220. package/roles/researcher.md +8 -0
  221. package/roles/reviewer.md +9 -0
  222. package/roles/scout.md +8 -0
  223. package/roles/worker.md +10 -0
  224. package/scripts/demo-two-terminal.sh +59 -0
  225. package/skills/coordination-patterns/SKILL.md +41 -0
  226. package/skills/coordination-patterns/references/supervised-worker-fan-out.md +12 -0
  227. package/skills/coordination-patterns/references/today-mail-team.md +36 -0
  228. package/transport/amq-cli-adapter.ts +381 -0
  229. package/transport/amq-message.ts +218 -0
  230. package/transport/amq-operations.ts +482 -0
  231. package/transport/atomic-json.ts +115 -0
  232. package/transport/binding-resolver.ts +565 -0
  233. package/transport/bridge-journal.ts +588 -0
  234. package/transport/dlq-retry-audit.ts +97 -0
  235. package/transport/inbox-pump.ts +729 -0
  236. package/transport/index.ts +11 -0
  237. package/transport/presence-projector.ts +104 -0
  238. package/transport/priority-delivery-scheduler.ts +328 -0
  239. package/transport/receiver-lease.ts +945 -0
  240. package/transport/runtime-status.ts +112 -0
  241. package/workflow/.gitkeep +1 -0
  242. package/workflow/atomic-storage.ts +120 -0
  243. package/workflow/budget.ts +90 -0
  244. package/workflow/index.ts +16 -0
  245. package/workflow/lifecycle-projection.ts +37 -0
  246. package/workflow/model-fallback.ts +17 -0
  247. package/workflow/pi-session-fork.ts +96 -0
  248. package/workflow/run-artifacts.ts +36 -0
  249. package/workflow/run-cleanup.ts +315 -0
  250. package/workflow/run-gate.ts +122 -0
  251. package/workflow/run-store.ts +3890 -0
  252. package/workflow/spawn-confirmation.ts +305 -0
  253. package/workflow/system-process-inspector.ts +142 -0
  254. package/workflow/worker-child-extension.ts +193 -0
  255. package/workflow/worker-gate.ts +238 -0
  256. package/workflow/worker-launch.ts +485 -0
  257. package/workflow/worker-model-catalog.ts +165 -0
  258. package/workflow/worker-process-supervisor.ts +1504 -0
  259. package/workflow/worker-prompt-capsule.ts +81 -0
  260. package/workflow/worker-role-presets.ts +241 -0
  261. package/workflow/workflow-doctor.ts +400 -0
  262. package/workflow/workflow-lease.ts +905 -0
  263. package/workflow/workflow-types.ts +367 -0
  264. package/workflow/workspace-paths.ts +32 -0
@@ -0,0 +1,81 @@
1
+ import type { AmqCliAdapter } from "./amq-cli-adapter.js";
2
+ import { type AmqMessage } from "./amq-message.js";
3
+ import { BridgeJournal, type DiskProjectionEvidence } from "./bridge-journal.js";
4
+ import { type DlqRetryAuditVerifier } from "./dlq-retry-audit.js";
5
+ import { PriorityDeliveryScheduler } from "./priority-delivery-scheduler.js";
6
+ import { ReceiverLeaseManager } from "./receiver-lease.js";
7
+ import { InboxStatusStore } from "./runtime-status.js";
8
+ export interface InboxBinding {
9
+ readonly root: string;
10
+ readonly rootId: string;
11
+ readonly handle: string;
12
+ }
13
+ export type InboxAuthorityResult = {
14
+ readonly kind: "valid";
15
+ } | {
16
+ readonly kind: "invalid";
17
+ readonly diagnostic: string;
18
+ };
19
+ export interface InboxAuthority {
20
+ revalidate(signal?: AbortSignal): Promise<InboxAuthorityResult>;
21
+ }
22
+ export interface SessionProjectionLookup {
23
+ find(messageId: string, targetSessionId: string, signal?: AbortSignal): Promise<DiskProjectionEvidence | undefined>;
24
+ }
25
+ export interface IncomingFreshSessionDispatcher {
26
+ dispatch(message: AmqMessage, signal?: AbortSignal): Promise<{
27
+ readonly kind: "ordinary";
28
+ } | {
29
+ readonly kind: "refused";
30
+ readonly reason: string;
31
+ } | {
32
+ readonly kind: "pending";
33
+ readonly reason: string;
34
+ readonly action: "/amq ingest";
35
+ } | {
36
+ readonly kind: "dispatched";
37
+ readonly projection: DiskProjectionEvidence;
38
+ }>;
39
+ }
40
+ type JsonCommandRunner = Pick<AmqCliAdapter, "runJson">;
41
+ export interface InboxPumpOptions {
42
+ readonly adapter: JsonCommandRunner;
43
+ readonly binding: InboxBinding;
44
+ readonly receiverGeneration: string;
45
+ readonly targetSessionId: string;
46
+ readonly authority: InboxAuthority;
47
+ readonly journal: BridgeJournal;
48
+ readonly scheduler: PriorityDeliveryScheduler;
49
+ readonly status?: InboxStatusStore;
50
+ readonly projectionLookup?: SessionProjectionLookup;
51
+ readonly freshSessionDispatcher?: IncomingFreshSessionDispatcher;
52
+ readonly retryAuditVerifier?: DlqRetryAuditVerifier;
53
+ readonly now?: () => Date;
54
+ readonly random?: () => number;
55
+ readonly sleep?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
56
+ readonly backoff?: {
57
+ readonly initialMs?: number;
58
+ readonly maximumMs?: number;
59
+ readonly multiplier?: number;
60
+ readonly jitterRatio?: number;
61
+ };
62
+ }
63
+ /** Supervises one non-consuming watch child and the exact-ID claim pipeline. */
64
+ export declare class InboxPump {
65
+ #private;
66
+ constructor(options: InboxPumpOptions);
67
+ run(signal?: AbortSignal): Promise<void>;
68
+ claimExact(id: string, signal?: AbortSignal): Promise<AmqMessage>;
69
+ ingestStaged(signal?: AbortSignal): Promise<number>;
70
+ }
71
+ export declare class LeaseBackedInboxAuthority implements InboxAuthority {
72
+ #private;
73
+ constructor(options: {
74
+ readonly lease: ReceiverLeaseManager;
75
+ readonly generation: string;
76
+ readonly verifyBinding: (signal?: AbortSignal) => Promise<InboxAuthorityResult>;
77
+ });
78
+ revalidate(signal?: AbortSignal): Promise<InboxAuthorityResult>;
79
+ }
80
+ export {};
81
+ //# sourceMappingURL=inbox-pump.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-pump.d.ts","sourceRoot":"","sources":["../../transport/inbox-pump.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,558 @@
1
+ import { setTimeout as delay } from "node:timers/promises";
2
+ import { parseAmqReadOutcome, parseMessageList, parseWatchCohort, sortAndDeduplicateCandidates, } from "./amq-message.js";
3
+ import { BridgeJournal, } from "./bridge-journal.js";
4
+ import { AmqDlqRetryAuditVerifier, } from "./dlq-retry-audit.js";
5
+ import { PriorityDeliveryScheduler, } from "./priority-delivery-scheduler.js";
6
+ import { ReceiverLeaseManager } from "./receiver-lease.js";
7
+ import { InboxStatusStore } from "./runtime-status.js";
8
+ class TerminalPumpError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "TerminalPumpError";
12
+ }
13
+ }
14
+ class RecoverablePumpError extends Error {
15
+ needsRecovery;
16
+ constructor(message, options) {
17
+ super(message, options.cause === undefined ? undefined : { cause: options.cause });
18
+ this.name = "RecoverablePumpError";
19
+ this.needsRecovery = options.needsRecovery;
20
+ }
21
+ }
22
+ /** Supervises one non-consuming watch child and the exact-ID claim pipeline. */
23
+ export class InboxPump {
24
+ #adapter;
25
+ #binding;
26
+ #receiverGeneration;
27
+ #targetSessionId;
28
+ #authority;
29
+ #journal;
30
+ #scheduler;
31
+ #status;
32
+ #projectionLookup;
33
+ #freshSessionDispatcher;
34
+ #retryAuditVerifier;
35
+ #now;
36
+ #random;
37
+ #sleep;
38
+ #initialBackoffMs;
39
+ #maximumBackoffMs;
40
+ #backoffMultiplier;
41
+ #jitterRatio;
42
+ #serial = Promise.resolve();
43
+ constructor(options) {
44
+ requireNonEmpty(options.binding.root, "binding root");
45
+ requireNonEmpty(options.binding.rootId, "binding root ID");
46
+ requireNonEmpty(options.binding.handle, "binding handle");
47
+ requireNonEmpty(options.receiverGeneration, "receiver generation");
48
+ requireNonEmpty(options.targetSessionId, "target session ID");
49
+ this.#adapter = options.adapter;
50
+ this.#binding = options.binding;
51
+ this.#receiverGeneration = options.receiverGeneration;
52
+ this.#targetSessionId = options.targetSessionId;
53
+ this.#authority = options.authority;
54
+ this.#journal = options.journal;
55
+ this.#scheduler = options.scheduler;
56
+ this.#status = options.status ?? new InboxStatusStore();
57
+ this.#projectionLookup = options.projectionLookup ?? NO_PROJECTIONS;
58
+ this.#freshSessionDispatcher = options.freshSessionDispatcher;
59
+ this.#retryAuditVerifier = options.retryAuditVerifier ?? new AmqDlqRetryAuditVerifier({
60
+ runner: options.adapter,
61
+ root: options.binding.root,
62
+ handle: options.binding.handle,
63
+ });
64
+ this.#now = options.now ?? (() => new Date());
65
+ this.#random = options.random ?? Math.random;
66
+ this.#sleep = options.sleep ?? defaultSleep;
67
+ this.#initialBackoffMs = positiveNumber(options.backoff?.initialMs ?? 100, "initial backoff");
68
+ this.#maximumBackoffMs = positiveNumber(options.backoff?.maximumMs ?? 5_000, "maximum backoff");
69
+ this.#backoffMultiplier = positiveNumber(options.backoff?.multiplier ?? 2, "backoff multiplier");
70
+ this.#jitterRatio = ratio(options.backoff?.jitterRatio ?? 0.2, "backoff jitter ratio");
71
+ if (this.#maximumBackoffMs < this.#initialBackoffMs) {
72
+ throw new TypeError("maximum backoff must be at least the initial backoff");
73
+ }
74
+ }
75
+ async run(signal) {
76
+ this.#status.update({
77
+ receiver: "receiving",
78
+ watch: "recovering",
79
+ receiverGeneration: this.#receiverGeneration,
80
+ lastError: null,
81
+ });
82
+ let recover = true;
83
+ let backoffAttempt = 0;
84
+ while (!signal?.aborted) {
85
+ try {
86
+ if (recover) {
87
+ this.#status.update({ watch: "recovering", nextBackoffMs: null });
88
+ await this.#reconcileStartup(signal);
89
+ recover = false;
90
+ }
91
+ await this.#assertAuthority(signal);
92
+ this.#status.update({
93
+ watch: "watching",
94
+ backoffAttempt: 0,
95
+ nextBackoffMs: null,
96
+ });
97
+ const result = await this.#adapter.runJson([
98
+ "watch",
99
+ "--root",
100
+ this.#binding.root,
101
+ "--me",
102
+ this.#binding.handle,
103
+ "--timeout",
104
+ "0",
105
+ ], { ...(signal ? { signal } : {}), parse: parseWatchCohort });
106
+ if (result.category === "cancelled")
107
+ break;
108
+ if (result.category === "context-mismatch") {
109
+ throw new TerminalPumpError(literalFailure(result, "AMQ watch context mismatch"));
110
+ }
111
+ if (result.json?.event === "timeout" && result.category === "timeout") {
112
+ backoffAttempt = 0;
113
+ continue;
114
+ }
115
+ if (!result.ok || !result.json) {
116
+ throw new RecoverablePumpError(literalFailure(result, "AMQ watch failed"), {
117
+ needsRecovery: false,
118
+ });
119
+ }
120
+ await this.#serialized(() => this.#processCandidates(result.json.messages, signal));
121
+ await this.#refreshStagedCounts();
122
+ backoffAttempt = 0;
123
+ }
124
+ catch (error) {
125
+ if (signal?.aborted)
126
+ break;
127
+ if (error instanceof TerminalPumpError) {
128
+ this.#status.update({
129
+ watch: "disabled",
130
+ nextBackoffMs: null,
131
+ lastError: error.message,
132
+ });
133
+ return;
134
+ }
135
+ const recoverable = error instanceof RecoverablePumpError
136
+ ? error
137
+ : new RecoverablePumpError(toError(error).message, { needsRecovery: true, cause: error });
138
+ recover ||= recoverable.needsRecovery;
139
+ backoffAttempt += 1;
140
+ const waitMs = this.#backoffDelay(backoffAttempt);
141
+ this.#status.update({
142
+ watch: "backoff",
143
+ backoffAttempt,
144
+ nextBackoffMs: waitMs,
145
+ lastError: recoverable.message,
146
+ });
147
+ try {
148
+ await this.#sleep(waitMs, signal);
149
+ }
150
+ catch (sleepError) {
151
+ if (!signal?.aborted)
152
+ throw sleepError;
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ this.#status.update({ watch: "stopped", nextBackoffMs: null });
158
+ }
159
+ async claimExact(id, signal) {
160
+ let claimed;
161
+ await this.#serialized(async () => {
162
+ const messages = await this.#processCandidates([{
163
+ id,
164
+ priority: "normal",
165
+ created: this.#now().toISOString(),
166
+ }], signal);
167
+ claimed = messages.find((message) => message.header.id === id);
168
+ if (!claimed)
169
+ claimed = await this.#readCurrentMessage(id, signal);
170
+ });
171
+ if (!claimed)
172
+ throw new Error(`AMQ message ${id} was not available after receiver claim`);
173
+ return claimed;
174
+ }
175
+ async ingestStaged(signal) {
176
+ let count = 0;
177
+ await this.#serialized(async () => {
178
+ const staged = (await this.#journal.list()).filter((record) => record.phase === "pending"
179
+ && (record.delivery === "nextTurn" || record.delivery === "fresh-session"));
180
+ const messages = [];
181
+ for (const record of staged) {
182
+ const message = await this.#readCurrentMessage(record.id, signal);
183
+ if (!message)
184
+ continue;
185
+ await this.#journal.setTarget(record.id, this.#receiverGeneration, {
186
+ targetSessionId: this.#targetSessionId,
187
+ delivery: "followUp",
188
+ });
189
+ messages.push(record.delivery === "fresh-session"
190
+ ? withFreshSessionOutcome(message, "pending-capability", "Fresh-session automation was unavailable; delivered by explicit /amq ingest")
191
+ : message);
192
+ }
193
+ if (messages.length === 0)
194
+ return;
195
+ const outcomes = await this.#scheduler.scheduleAs(messages, this.#targetSessionId, { deliverAs: "followUp", triggerTurn: true }, signal);
196
+ await this.#applyDeliveryOutcomes(outcomes);
197
+ count = outcomes.flatMap((outcome) => outcome.request.message.details.messageIds).length;
198
+ await this.#refreshStagedCounts();
199
+ });
200
+ return count;
201
+ }
202
+ async #reconcileStartup(signal) {
203
+ await this.#assertAuthority(signal);
204
+ const binding = {
205
+ rootId: this.#binding.rootId,
206
+ handle: this.#binding.handle,
207
+ };
208
+ const records = await this.#journal.list();
209
+ const unresolved = [];
210
+ let diagnostic = null;
211
+ for (const original of records) {
212
+ throwIfAborted(signal);
213
+ if (original.phase === "dlq")
214
+ continue;
215
+ if (original.phase === "injected") {
216
+ if (original.targetSessionId) {
217
+ const projection = await this.#projectionLookup.find(original.id, original.targetSessionId, signal);
218
+ if (!projection?.diskVisible) {
219
+ diagnostic = `Injected AMQ projection is missing for ${original.id}; it was not resurrected`;
220
+ }
221
+ }
222
+ continue;
223
+ }
224
+ const record = await this.#journal.adoptPending(original.id, this.#receiverGeneration, binding);
225
+ if (record.targetSessionId) {
226
+ const projection = await this.#projectionLookup.find(record.id, record.targetSessionId, signal);
227
+ if (projection?.diskVisible) {
228
+ await this.#journal.markInjected(record.id, this.#receiverGeneration, projection);
229
+ continue;
230
+ }
231
+ }
232
+ unresolved.push(record.id);
233
+ }
234
+ if (diagnostic)
235
+ this.#status.update({ lastError: diagnostic });
236
+ if (unresolved.length === 0) {
237
+ await this.#refreshStagedCounts();
238
+ return;
239
+ }
240
+ const listed = await this.#listRecoveryCandidates(signal);
241
+ const byId = new Map(listed.map((candidate) => [candidate.id, candidate]));
242
+ const candidates = unresolved.map((id) => byId.get(id) ?? {
243
+ id,
244
+ priority: "normal",
245
+ created: "",
246
+ parseError: "pending journal ID is not listed in AMQ new/cur",
247
+ });
248
+ await this.#serialized(() => this.#processCandidates(candidates, signal));
249
+ await this.#refreshStagedCounts();
250
+ }
251
+ async #listRecoveryCandidates(signal) {
252
+ const candidates = [];
253
+ for (const box of ["--new", "--cur"]) {
254
+ await this.#assertAuthority(signal);
255
+ const result = await this.#adapter.runJson([
256
+ "list",
257
+ "--root",
258
+ this.#binding.root,
259
+ "--me",
260
+ this.#binding.handle,
261
+ box,
262
+ ], { ...(signal ? { signal } : {}), parse: parseMessageList });
263
+ if (result.category === "context-mismatch") {
264
+ throw new TerminalPumpError(literalFailure(result, "AMQ recovery list context mismatch"));
265
+ }
266
+ if (!result.ok || !result.json) {
267
+ throw new RecoverablePumpError(literalFailure(result, "AMQ recovery list failed"), {
268
+ needsRecovery: true,
269
+ });
270
+ }
271
+ candidates.push(...result.json);
272
+ }
273
+ return sortAndDeduplicateCandidates(candidates);
274
+ }
275
+ async #processCandidates(candidates, signal) {
276
+ const messages = [];
277
+ const missingIds = [];
278
+ for (const candidate of sortAndDeduplicateCandidates(candidates)) {
279
+ throwIfAborted(signal);
280
+ let record = await this.#journal.read(candidate.id);
281
+ if (record?.phase === "injected")
282
+ continue;
283
+ if (record?.phase === "dlq") {
284
+ const audits = await this.#retryAuditVerifier.verify(candidate.id, signal);
285
+ let promoted = false;
286
+ for (const audit of audits) {
287
+ try {
288
+ record = await this.#journal.promoteVerifiedRetry(candidate.id, this.#receiverGeneration, audit);
289
+ promoted = true;
290
+ break;
291
+ }
292
+ catch (error) {
293
+ this.#status.update({
294
+ lastError: `DLQ retry audit ${audit.auditId} refused for ${candidate.id}: ${toError(error).message}`,
295
+ });
296
+ }
297
+ }
298
+ if (!promoted) {
299
+ this.#status.update({
300
+ lastError: `DLQ tombstone for ${candidate.id} remains terminal: visible same-ID mail has no unused delivered AMQ retry audit`,
301
+ });
302
+ continue;
303
+ }
304
+ }
305
+ if (!record) {
306
+ await this.#assertAuthority(signal);
307
+ record = await this.#journal.createPending({
308
+ id: candidate.id,
309
+ attempt: 1,
310
+ binding: { rootId: this.#binding.rootId, handle: this.#binding.handle },
311
+ leaseGeneration: this.#receiverGeneration,
312
+ });
313
+ }
314
+ else if (record.leaseGeneration !== this.#receiverGeneration) {
315
+ record = await this.#journal.adoptPending(record.id, this.#receiverGeneration, { rootId: this.#binding.rootId, handle: this.#binding.handle });
316
+ }
317
+ await this.#assertAuthority(signal);
318
+ const result = await this.#adapter.runJson([
319
+ "read",
320
+ "--root",
321
+ this.#binding.root,
322
+ "--me",
323
+ this.#binding.handle,
324
+ "--id",
325
+ candidate.id,
326
+ ], { ...(signal ? { signal } : {}), parse: parseAmqReadOutcome });
327
+ if (result.category === "cancelled")
328
+ throwIfAborted(signal);
329
+ if (result.category === "context-mismatch") {
330
+ throw new TerminalPumpError(literalFailure(result, "AMQ read context mismatch"));
331
+ }
332
+ if (result.json?.kind === "dlq") {
333
+ await this.#journal.markDlq(candidate.id, this.#receiverGeneration, {
334
+ messageId: result.json.id,
335
+ diagnostic: result.json.diagnostic,
336
+ });
337
+ continue;
338
+ }
339
+ if (result.json?.kind === "message"
340
+ && (result.category === "success" || result.category === "error")) {
341
+ if (result.json.message.header.id !== candidate.id) {
342
+ throw new RecoverablePumpError(`AMQ read returned ${result.json.message.header.id} for requested ${candidate.id}`, { needsRecovery: true });
343
+ }
344
+ await this.#journal.recordClaim(candidate.id, this.#receiverGeneration, {
345
+ claimedAt: this.#now().toISOString(),
346
+ receiptWarning: result.ok ? null : literalFailure(result, "AMQ claim committed with warning"),
347
+ });
348
+ if (!result.ok) {
349
+ this.#status.update({
350
+ lastError: `Claim committed; drained receipt audit failed for ${candidate.id}: ${literalFailure(result, "AMQ receipt audit failed")}`,
351
+ });
352
+ }
353
+ const fresh = await this.#freshSessionDispatcher?.dispatch(result.json.message, signal);
354
+ if (fresh?.kind === "pending") {
355
+ await this.#journal.setTarget(candidate.id, this.#receiverGeneration, {
356
+ targetSessionId: this.#targetSessionId,
357
+ delivery: "fresh-session",
358
+ });
359
+ continue;
360
+ }
361
+ if (fresh?.kind === "dispatched") {
362
+ await this.#journal.setTarget(candidate.id, this.#receiverGeneration, {
363
+ targetSessionId: fresh.projection.sessionId,
364
+ delivery: "fresh-session",
365
+ });
366
+ if (fresh.projection.diskVisible) {
367
+ await this.#journal.markInjected(candidate.id, this.#receiverGeneration, fresh.projection);
368
+ }
369
+ continue;
370
+ }
371
+ messages.push(fresh?.kind === "refused"
372
+ ? withFreshSessionOutcome(result.json.message, "refused", fresh.reason)
373
+ : result.json.message);
374
+ continue;
375
+ }
376
+ if (result.category === "not-found") {
377
+ missingIds.push(candidate.id);
378
+ continue;
379
+ }
380
+ throw new RecoverablePumpError(literalFailure(result, `AMQ read failed for ${candidate.id}`), {
381
+ needsRecovery: true,
382
+ });
383
+ }
384
+ if (messages.length > 0) {
385
+ for (const message of messages) {
386
+ await this.#journal.setTarget(message.header.id, this.#receiverGeneration, {
387
+ targetSessionId: this.#targetSessionId,
388
+ delivery: bridgeDelivery(message.header.priority),
389
+ });
390
+ }
391
+ const outcomes = await this.#scheduler.schedule(messages, this.#targetSessionId, signal);
392
+ await this.#applyDeliveryOutcomes(outcomes);
393
+ }
394
+ if (missingIds.length > 0) {
395
+ throw new RecoverablePumpError(`Pending AMQ messages were not found by exact ID: ${missingIds.join(", ")}`, { needsRecovery: true });
396
+ }
397
+ return messages;
398
+ }
399
+ async #readCurrentMessage(id, signal) {
400
+ await this.#assertAuthority(signal);
401
+ const result = await this.#adapter.runJson(["read", "--root", this.#binding.root, "--me", this.#binding.handle, "--id", id], { ...(signal ? { signal } : {}), parse: parseAmqReadOutcome });
402
+ if (result.json?.kind === "message"
403
+ && (result.category === "success" || result.category === "error")) {
404
+ return result.json.message;
405
+ }
406
+ if (result.category === "not-found")
407
+ return undefined;
408
+ throw new RecoverablePumpError(literalFailure(result, `AMQ read failed for ${id}`), {
409
+ needsRecovery: true,
410
+ });
411
+ }
412
+ async #serialized(operation) {
413
+ const task = this.#serial.then(operation);
414
+ this.#serial = task.then(() => undefined, () => undefined);
415
+ return task;
416
+ }
417
+ async #applyDeliveryOutcomes(outcomes) {
418
+ for (const outcome of outcomes) {
419
+ if (outcome.result.kind !== "accepted") {
420
+ throw new RecoverablePumpError(`Pi delivery ${outcome.result.kind}: ${outcome.result.error.message}`, { needsRecovery: true, cause: outcome.result.error });
421
+ }
422
+ const ids = new Set(outcome.request.message.details.messageIds);
423
+ for (const projection of outcome.result.projections) {
424
+ if (!ids.has(projection.messageId)) {
425
+ throw new RecoverablePumpError(`Pi delivery returned projection for unrelated AMQ ID ${projection.messageId}`, { needsRecovery: true });
426
+ }
427
+ if (!projection.diskVisible)
428
+ continue;
429
+ await this.#journal.markInjected(projection.messageId, this.#receiverGeneration, projection);
430
+ }
431
+ }
432
+ }
433
+ async #refreshStagedCounts() {
434
+ const counts = { urgent: 0, normal: 0, low: 0 };
435
+ for (const record of await this.#journal.list()) {
436
+ if (record.phase !== "pending" || record.delivery === null)
437
+ continue;
438
+ switch (record.delivery) {
439
+ case "steer":
440
+ counts.urgent += 1;
441
+ break;
442
+ case "followUp":
443
+ case "fresh-session":
444
+ counts.normal += 1;
445
+ break;
446
+ case "nextTurn":
447
+ counts.low += 1;
448
+ break;
449
+ }
450
+ }
451
+ this.#status.update({ staged: counts });
452
+ }
453
+ async #assertAuthority(signal) {
454
+ throwIfAborted(signal);
455
+ const authority = await this.#authority.revalidate(signal);
456
+ if (authority.kind === "invalid")
457
+ throw new TerminalPumpError(authority.diagnostic);
458
+ }
459
+ #backoffDelay(attempt) {
460
+ const base = Math.min(this.#maximumBackoffMs, this.#initialBackoffMs * this.#backoffMultiplier ** (attempt - 1));
461
+ const jitter = 1 + ((this.#random() * 2) - 1) * this.#jitterRatio;
462
+ return Math.max(1, Math.min(this.#maximumBackoffMs, Math.round(base * jitter)));
463
+ }
464
+ }
465
+ export class LeaseBackedInboxAuthority {
466
+ #lease;
467
+ #generation;
468
+ #verifyBinding;
469
+ constructor(options) {
470
+ this.#lease = options.lease;
471
+ this.#generation = requireNonEmpty(options.generation, "receiver generation");
472
+ this.#verifyBinding = options.verifyBinding;
473
+ }
474
+ async revalidate(signal) {
475
+ throwIfAborted(signal);
476
+ const binding = await this.#verifyBinding(signal);
477
+ if (binding.kind === "invalid")
478
+ return binding;
479
+ try {
480
+ await this.#lease.withCurrentLease(this.#generation, async () => undefined);
481
+ return { kind: "valid" };
482
+ }
483
+ catch (error) {
484
+ return { kind: "invalid", diagnostic: `Receiver lease revalidation failed: ${toError(error).message}` };
485
+ }
486
+ }
487
+ }
488
+ const NO_PROJECTIONS = {
489
+ async find() {
490
+ return undefined;
491
+ },
492
+ };
493
+ function bridgeDelivery(priority) {
494
+ switch (priority) {
495
+ case "urgent":
496
+ return "steer";
497
+ case "normal":
498
+ return "followUp";
499
+ case "low":
500
+ return "nextTurn";
501
+ }
502
+ }
503
+ function withFreshSessionOutcome(message, outcome, reason) {
504
+ const previous = message.header.context.pi_amq;
505
+ const piAmq = previous && typeof previous === "object" && !Array.isArray(previous)
506
+ ? previous
507
+ : {};
508
+ return {
509
+ ...message,
510
+ header: {
511
+ ...message.header,
512
+ context: {
513
+ ...message.header.context,
514
+ pi_amq: {
515
+ ...piAmq,
516
+ fresh_session_outcome: outcome,
517
+ fresh_session_reason: reason,
518
+ },
519
+ },
520
+ },
521
+ };
522
+ }
523
+ function literalFailure(result, fallback) {
524
+ const literal = result.stderr.trim() || result.jsonError?.message || result.processError?.message;
525
+ return literal ? `${fallback}: ${literal}` : `${fallback} (${result.category})`;
526
+ }
527
+ async function defaultSleep(milliseconds, signal) {
528
+ if (signal) {
529
+ await delay(milliseconds, undefined, { signal });
530
+ return;
531
+ }
532
+ await delay(milliseconds);
533
+ }
534
+ function throwIfAborted(signal) {
535
+ if (!signal?.aborted)
536
+ return;
537
+ throw signal.reason instanceof Error ? signal.reason : new Error("Inbox pump was cancelled");
538
+ }
539
+ function positiveNumber(value, name) {
540
+ if (!Number.isFinite(value) || value <= 0)
541
+ throw new TypeError(`${name} must be positive`);
542
+ return value;
543
+ }
544
+ function ratio(value, name) {
545
+ if (!Number.isFinite(value) || value < 0 || value > 1) {
546
+ throw new TypeError(`${name} must be between 0 and 1`);
547
+ }
548
+ return value;
549
+ }
550
+ function requireNonEmpty(value, name) {
551
+ if (value.length === 0)
552
+ throw new TypeError(`${name} is required`);
553
+ return value;
554
+ }
555
+ function toError(error) {
556
+ return error instanceof Error ? error : new Error(String(error));
557
+ }
558
+ //# sourceMappingURL=inbox-pump.js.map