@osolmaz/pi-workflows 0.16.1 → 0.16.3

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 (327) hide show
  1. package/README.md +41 -41
  2. package/dist/builtins/monitor.workflow.d.ts +1 -1
  3. package/dist/builtins/monitor.workflow.js +8 -8
  4. package/dist/builtins/pi-agent-group.js +3 -3
  5. package/dist/builtins/pi-agent-group.js.map +1 -1
  6. package/dist/channels/adapter-entry.js +14 -14
  7. package/dist/channels/adapter-entry.js.map +1 -1
  8. package/dist/client/client.d.ts +6 -6
  9. package/dist/client/client.js +27 -27
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/protocol.d.ts +4 -1
  12. package/dist/client/protocol.js +17 -11
  13. package/dist/client/protocol.js.map +1 -1
  14. package/dist/client/resolver.d.ts +4 -4
  15. package/dist/client/view.d.ts +7 -1
  16. package/dist/client/view.js +1 -0
  17. package/dist/client/view.js.map +1 -1
  18. package/dist/extension/index.d.ts +1 -1
  19. package/dist/extension/index.js +66 -47
  20. package/dist/extension/index.js.map +1 -1
  21. package/dist/extension/recorder.d.ts +1 -1
  22. package/dist/extension/recorder.js +1 -1
  23. package/dist/extension/recorder.js.map +1 -1
  24. package/dist/extension/remote-recorder-store.d.ts +1 -1
  25. package/dist/extension/remote-recorder-store.js +2 -2
  26. package/dist/extension/remote-recorder-store.js.map +1 -1
  27. package/dist/extension/{controller-command.d.ts → resource-manager-command.d.ts} +6 -6
  28. package/dist/extension/{controller-command.js → resource-manager-command.js} +7 -7
  29. package/dist/extension/resource-manager-command.js.map +1 -0
  30. package/dist/extension/session-delivery.d.ts +1 -1
  31. package/dist/extension/session-delivery.js +2 -2
  32. package/dist/extension/session-delivery.js.map +1 -1
  33. package/dist/extension/session-view.d.ts +1 -1
  34. package/dist/extension/session-view.js +1 -1
  35. package/dist/extension/session-view.js.map +1 -1
  36. package/dist/extension/workflow-message-coordinator.d.ts +4 -3
  37. package/dist/extension/workflow-message-coordinator.js +81 -29
  38. package/dist/extension/workflow-message-coordinator.js.map +1 -1
  39. package/dist/resource-managers/conditions.d.ts +6 -0
  40. package/dist/{controllers → resource-managers}/conditions.js +3 -3
  41. package/dist/resource-managers/conditions.js.map +1 -0
  42. package/dist/resource-managers/definition.d.ts +6 -0
  43. package/dist/resource-managers/definition.js +45 -0
  44. package/dist/resource-managers/definition.js.map +1 -0
  45. package/dist/resource-managers/effects.d.ts +15 -0
  46. package/dist/{controllers → resource-managers}/effects.js +2 -2
  47. package/dist/resource-managers/effects.js.map +1 -0
  48. package/dist/resource-managers/errors.d.ts +12 -0
  49. package/dist/resource-managers/errors.js +25 -0
  50. package/dist/resource-managers/errors.js.map +1 -0
  51. package/dist/resource-managers/index.d.ts +12 -0
  52. package/dist/resource-managers/index.js +12 -0
  53. package/dist/resource-managers/index.js.map +1 -0
  54. package/dist/resource-managers/json.js.map +1 -0
  55. package/dist/resource-managers/loader.d.ts +23 -0
  56. package/dist/resource-managers/loader.js +75 -0
  57. package/dist/resource-managers/loader.js.map +1 -0
  58. package/dist/resource-managers/results.d.ts +5 -0
  59. package/dist/resource-managers/results.js.map +1 -0
  60. package/dist/resource-managers/runtime.d.ts +59 -0
  61. package/dist/{controllers/manager.js → resource-managers/runtime.js} +57 -57
  62. package/dist/resource-managers/runtime.js.map +1 -0
  63. package/dist/{controllers → resource-managers}/sqlite.d.ts +51 -43
  64. package/dist/{controllers → resource-managers}/sqlite.js +187 -125
  65. package/dist/resource-managers/sqlite.js.map +1 -0
  66. package/dist/{controllers → resource-managers}/store.d.ts +33 -33
  67. package/dist/{controllers → resource-managers}/store.js.map +1 -1
  68. package/dist/{controllers → resource-managers}/types.d.ts +41 -41
  69. package/dist/{controllers → resource-managers}/types.js.map +1 -1
  70. package/dist/resource-managers/workflows.d.ts +34 -0
  71. package/dist/{controllers → resource-managers}/workflows.js +15 -15
  72. package/dist/resource-managers/workflows.js.map +1 -0
  73. package/dist/server/channel-effects.js.map +1 -0
  74. package/dist/{host → server}/channel-supervisor.d.ts +6 -6
  75. package/dist/{host → server}/channel-supervisor.js +3 -3
  76. package/dist/server/channel-supervisor.js.map +1 -0
  77. package/dist/{host/child-worker-supervisor.d.ts → server/child-runner-supervisor.d.ts} +15 -13
  78. package/dist/{host/child-worker-supervisor.js → server/child-runner-supervisor.js} +6 -5
  79. package/dist/server/child-runner-supervisor.js.map +1 -0
  80. package/dist/{host → server}/processes.d.ts +3 -3
  81. package/dist/{host → server}/processes.js +3 -3
  82. package/dist/server/processes.js.map +1 -0
  83. package/dist/{host → server}/resolver-entry.d.ts +6 -6
  84. package/dist/{host → server}/resolver-entry.js +14 -14
  85. package/dist/server/resolver-entry.js.map +1 -0
  86. package/dist/server/resource-runner-entry.d.ts +2 -0
  87. package/dist/{host/controller-worker-entry.js → server/resource-runner-entry.js} +33 -33
  88. package/dist/server/resource-runner-entry.js.map +1 -0
  89. package/dist/server/resource-runner-protocol.d.ts +36 -0
  90. package/dist/server/resource-runner-protocol.js +49 -0
  91. package/dist/server/resource-runner-protocol.js.map +1 -0
  92. package/dist/server/resource-runner-supervisor.d.ts +21 -0
  93. package/dist/{host/worker-supervisor.js → server/resource-runner-supervisor.js} +17 -17
  94. package/dist/server/resource-runner-supervisor.js.map +1 -0
  95. package/dist/{host → server}/rpc-bridge.d.ts +3 -3
  96. package/dist/{host → server}/rpc-bridge.js +3 -3
  97. package/dist/server/rpc-bridge.js.map +1 -0
  98. package/dist/{host → server}/rpc-executor.d.ts +1 -1
  99. package/dist/{host → server}/rpc-executor.js +3 -3
  100. package/dist/server/rpc-executor.js.map +1 -0
  101. package/dist/{host/host-entry.js → server/server-entry.js} +6 -6
  102. package/dist/server/server-entry.js.map +1 -0
  103. package/dist/{host/runner.d.ts → server/server.d.ts} +47 -39
  104. package/dist/{host/runner.js → server/server.js} +624 -535
  105. package/dist/server/server.js.map +1 -0
  106. package/dist/{host → server}/state.d.ts +25 -25
  107. package/dist/{host → server}/state.js +49 -49
  108. package/dist/server/state.js.map +1 -0
  109. package/dist/{host → server}/view.d.ts +7 -7
  110. package/dist/{host → server}/view.js +19 -15
  111. package/dist/server/view.js.map +1 -0
  112. package/dist/server/workflow-runner-content.d.ts +6 -0
  113. package/dist/server/workflow-runner-content.js +96 -0
  114. package/dist/server/workflow-runner-content.js.map +1 -0
  115. package/dist/server/workflow-runner-entry.d.ts +13 -0
  116. package/dist/{host/worker-entry.js → server/workflow-runner-entry.js} +89 -57
  117. package/dist/server/workflow-runner-entry.js.map +1 -0
  118. package/dist/server/workflow-runner-protocol.d.ts +69 -0
  119. package/dist/server/workflow-runner-protocol.js +176 -0
  120. package/dist/server/workflow-runner-protocol.js.map +1 -0
  121. package/dist/{host/worker-store.d.ts → server/workflow-runner-store.d.ts} +11 -11
  122. package/dist/{host/worker-store.js → server/workflow-runner-store.js} +8 -8
  123. package/dist/server/workflow-runner-store.js.map +1 -0
  124. package/dist/server/workflow-runner-supervisor.d.ts +22 -0
  125. package/dist/server/workflow-runner-supervisor.js +56 -0
  126. package/dist/server/workflow-runner-supervisor.js.map +1 -0
  127. package/dist/state/prune.d.ts +1 -1
  128. package/dist/state/prune.js +17 -10
  129. package/dist/state/prune.js.map +1 -1
  130. package/dist/state/schema.js +2 -2
  131. package/dist/state/workflow-messages.d.ts +3 -1
  132. package/dist/state/workflow-messages.js +32 -1
  133. package/dist/state/workflow-messages.js.map +1 -1
  134. package/dist/viewer/backup.js +1 -1
  135. package/dist/viewer/backup.js.map +1 -1
  136. package/dist/viewer/cli.d.ts +2 -2
  137. package/dist/viewer/cli.js +46 -32
  138. package/dist/viewer/cli.js.map +1 -1
  139. package/dist/viewer/tui.d.ts +1 -1
  140. package/dist/viewer/tui.js +1 -1
  141. package/dist/viewer/tui.js.map +1 -1
  142. package/dist/workflows/command-batch.js +2 -2
  143. package/dist/workflows/composition.js +0 -4
  144. package/dist/workflows/composition.js.map +1 -1
  145. package/dist/workflows/definition.js +0 -8
  146. package/dist/workflows/definition.js.map +1 -1
  147. package/dist/workflows/engine.js +18 -20
  148. package/dist/workflows/engine.js.map +1 -1
  149. package/dist/workflows/schema.js +0 -4
  150. package/dist/workflows/schema.js.map +1 -1
  151. package/dist/workflows/store.d.ts +27 -11
  152. package/dist/workflows/store.js +66 -18
  153. package/dist/workflows/store.js.map +1 -1
  154. package/dist/workflows/types.d.ts +3 -5
  155. package/docs/2026-08-20-durable-workflow-launch-plan.md +12 -12
  156. package/docs/2026-08-25-workflow-follow-ups.md +7 -7
  157. package/docs/2026-08-25-workflow-settings.md +3 -3
  158. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
  159. package/docs/2026-09-01-restore-session-delivery-controls-plan.md +5 -5
  160. package/docs/2026-09-01-unified-workflow-client-plan.md +6 -6
  161. package/docs/2026-09-02-installed-live-e2e-plan.md +3 -3
  162. package/docs/2026-09-02-unify-workflow-messages-plan.md +8 -8
  163. package/docs/2026-09-04-workflow-run-state-plan.md +363 -0
  164. package/docs/DEFERRED_TURNS.md +7 -7
  165. package/docs/DESIGN_PHILOSOPHY.md +1 -1
  166. package/docs/HUMAN_DECISIONS.md +11 -11
  167. package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -4
  168. package/docs/MONITOR.md +1 -1
  169. package/docs/RESOURCE_MANAGERS.md +221 -0
  170. package/docs/SQLITE_STATE.md +40 -34
  171. package/docs/WORKFLOW_COMPOSITION.md +1 -1
  172. package/docs/{WORKFLOW_HOST.md → WORKFLOW_SERVER.md} +131 -116
  173. package/docs/WORKFLOW_STEP_MESSAGES.md +18 -18
  174. package/docs/WORKFLOW_UPDATES.md +16 -16
  175. package/docs/development.md +15 -14
  176. package/docs/live-replay-protocol.md +20 -20
  177. package/docs/plans/2026-08-04-controller-runtime-plan.md +25 -25
  178. package/docs/plans/2026-08-05-always-on-workflows-plan.md +8 -8
  179. package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +2 -2
  180. package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +1 -1
  181. package/docs/plans/2026-08-16-workflow-updates-plan.md +5 -5
  182. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  183. package/docs/plans/2026-08-20-bounded-command-batches-plan.md +1 -1
  184. package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +3 -3
  185. package/docs/plans/2026-08-21-sanity-check-plan.md +2 -2
  186. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +5 -5
  187. package/docs/plans/2026-08-23-sqlite-state-plan.md +25 -25
  188. package/docs/plans/2026-08-25-live-workflow-settings-plan.md +4 -4
  189. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +3 -3
  190. package/docs/plans/2026-09-04-workflow-runner-resume-state-plan.md +318 -0
  191. package/docs/plans/piw-viewer-experience-implementation-plan.md +1 -1
  192. package/docs/tui-viewer.md +9 -9
  193. package/docs/workflows.md +78 -63
  194. package/examples/{controllers/pull-request.controller.ts → resource-managers/pull-request.resource-manager.ts} +12 -12
  195. package/herdr-plugin.toml +1 -1
  196. package/package.json +5 -5
  197. package/protocol/client.v1.schema.json +7 -7
  198. package/protocol/fixtures/client-v1.json +1 -1
  199. package/src/builtins/monitor.workflow.ts +9 -9
  200. package/src/builtins/pi-agent-group.ts +3 -3
  201. package/src/channels/adapter-entry.ts +14 -14
  202. package/src/client/client.ts +33 -32
  203. package/src/client/protocol.ts +16 -11
  204. package/src/client/resolver.ts +4 -4
  205. package/src/client/view.ts +9 -1
  206. package/src/extension/index.ts +81 -53
  207. package/src/extension/recorder.ts +1 -1
  208. package/src/extension/remote-recorder-store.ts +2 -2
  209. package/src/extension/resource-manager-command.ts +45 -0
  210. package/src/extension/session-delivery.ts +2 -2
  211. package/src/extension/session-view.ts +1 -1
  212. package/src/extension/workflow-message-coordinator.ts +94 -30
  213. package/src/{controllers → resource-managers}/conditions.ts +23 -23
  214. package/src/resource-managers/definition.ts +71 -0
  215. package/src/{controllers → resource-managers}/effects.ts +9 -9
  216. package/src/resource-managers/errors.ts +27 -0
  217. package/src/resource-managers/index.ts +88 -0
  218. package/src/resource-managers/loader.ts +111 -0
  219. package/src/{controllers → resource-managers}/results.ts +4 -4
  220. package/src/{controllers/manager.ts → resource-managers/runtime.ts} +95 -92
  221. package/src/{controllers → resource-managers}/sqlite.ts +275 -181
  222. package/src/{controllers → resource-managers}/store.ts +46 -38
  223. package/src/{controllers → resource-managers}/types.ts +50 -41
  224. package/src/{controllers → resource-managers}/workflows.ts +43 -41
  225. package/src/{host → server}/channel-supervisor.ts +8 -8
  226. package/src/{host/child-worker-supervisor.ts → server/child-runner-supervisor.ts} +22 -18
  227. package/src/{host → server}/processes.ts +3 -3
  228. package/src/{host → server}/resolver-entry.ts +28 -25
  229. package/src/{host/controller-worker-entry.ts → server/resource-runner-entry.ts} +67 -65
  230. package/src/server/resource-runner-protocol.ts +103 -0
  231. package/src/server/resource-runner-supervisor.ts +76 -0
  232. package/src/{host → server}/rpc-bridge.ts +3 -3
  233. package/src/{host → server}/rpc-executor.ts +4 -4
  234. package/src/{host/host-entry.ts → server/server-entry.ts} +5 -5
  235. package/src/{host/runner.ts → server/server.ts} +786 -672
  236. package/src/{host → server}/state.ts +78 -67
  237. package/src/{host → server}/view.ts +21 -17
  238. package/src/server/workflow-runner-content.ts +119 -0
  239. package/src/{host/worker-entry.ts → server/workflow-runner-entry.ts} +131 -82
  240. package/src/server/workflow-runner-protocol.ts +241 -0
  241. package/src/{host/worker-store.ts → server/workflow-runner-store.ts} +18 -20
  242. package/src/server/workflow-runner-supervisor.ts +79 -0
  243. package/src/state/prune.ts +27 -9
  244. package/src/state/schema.ts +2 -2
  245. package/src/state/workflow-messages.ts +52 -1
  246. package/src/viewer/backup.ts +1 -1
  247. package/src/viewer/cli.ts +50 -36
  248. package/src/viewer/tui.ts +1 -1
  249. package/src/workflows/command-batch.ts +2 -2
  250. package/src/workflows/composition.ts +0 -5
  251. package/src/workflows/definition.ts +0 -8
  252. package/src/workflows/engine.ts +18 -21
  253. package/src/workflows/schema.ts +0 -6
  254. package/src/workflows/store.ts +95 -28
  255. package/src/workflows/types.ts +3 -5
  256. package/dist/controllers/conditions.d.ts +0 -6
  257. package/dist/controllers/conditions.js.map +0 -1
  258. package/dist/controllers/definition.d.ts +0 -6
  259. package/dist/controllers/definition.js +0 -45
  260. package/dist/controllers/definition.js.map +0 -1
  261. package/dist/controllers/effects.d.ts +0 -15
  262. package/dist/controllers/effects.js.map +0 -1
  263. package/dist/controllers/errors.d.ts +0 -12
  264. package/dist/controllers/errors.js +0 -25
  265. package/dist/controllers/errors.js.map +0 -1
  266. package/dist/controllers/index.d.ts +0 -12
  267. package/dist/controllers/index.js +0 -12
  268. package/dist/controllers/index.js.map +0 -1
  269. package/dist/controllers/json.js.map +0 -1
  270. package/dist/controllers/loader.d.ts +0 -23
  271. package/dist/controllers/loader.js +0 -74
  272. package/dist/controllers/loader.js.map +0 -1
  273. package/dist/controllers/manager.d.ts +0 -59
  274. package/dist/controllers/manager.js.map +0 -1
  275. package/dist/controllers/results.d.ts +0 -5
  276. package/dist/controllers/results.js.map +0 -1
  277. package/dist/controllers/sqlite.js.map +0 -1
  278. package/dist/controllers/workflows.d.ts +0 -34
  279. package/dist/controllers/workflows.js.map +0 -1
  280. package/dist/extension/controller-command.js.map +0 -1
  281. package/dist/host/channel-effects.js.map +0 -1
  282. package/dist/host/channel-supervisor.js.map +0 -1
  283. package/dist/host/child-worker-supervisor.js.map +0 -1
  284. package/dist/host/controller-worker-entry.d.ts +0 -2
  285. package/dist/host/controller-worker-entry.js.map +0 -1
  286. package/dist/host/controller-worker-protocol.d.ts +0 -36
  287. package/dist/host/controller-worker-protocol.js +0 -49
  288. package/dist/host/controller-worker-protocol.js.map +0 -1
  289. package/dist/host/controller-worker-supervisor.d.ts +0 -21
  290. package/dist/host/controller-worker-supervisor.js +0 -54
  291. package/dist/host/controller-worker-supervisor.js.map +0 -1
  292. package/dist/host/host-entry.js.map +0 -1
  293. package/dist/host/processes.js.map +0 -1
  294. package/dist/host/resolver-entry.js.map +0 -1
  295. package/dist/host/rpc-bridge.js.map +0 -1
  296. package/dist/host/rpc-executor.js.map +0 -1
  297. package/dist/host/runner.js.map +0 -1
  298. package/dist/host/state.js.map +0 -1
  299. package/dist/host/view.js.map +0 -1
  300. package/dist/host/worker-entry.d.ts +0 -10
  301. package/dist/host/worker-entry.js.map +0 -1
  302. package/dist/host/worker-protocol.d.ts +0 -31
  303. package/dist/host/worker-protocol.js +0 -122
  304. package/dist/host/worker-protocol.js.map +0 -1
  305. package/dist/host/worker-store.js.map +0 -1
  306. package/dist/host/worker-supervisor.d.ts +0 -22
  307. package/dist/host/worker-supervisor.js.map +0 -1
  308. package/docs/CONTROLLERS.md +0 -217
  309. package/src/controllers/definition.ts +0 -65
  310. package/src/controllers/errors.ts +0 -27
  311. package/src/controllers/index.ts +0 -88
  312. package/src/controllers/loader.ts +0 -104
  313. package/src/extension/controller-command.ts +0 -45
  314. package/src/host/controller-worker-protocol.ts +0 -104
  315. package/src/host/controller-worker-supervisor.ts +0 -79
  316. package/src/host/worker-protocol.ts +0 -165
  317. package/src/host/worker-supervisor.ts +0 -74
  318. /package/dist/{controllers → resource-managers}/json.d.ts +0 -0
  319. /package/dist/{controllers → resource-managers}/json.js +0 -0
  320. /package/dist/{controllers → resource-managers}/results.js +0 -0
  321. /package/dist/{controllers → resource-managers}/store.js +0 -0
  322. /package/dist/{controllers → resource-managers}/types.js +0 -0
  323. /package/dist/{host → server}/channel-effects.d.ts +0 -0
  324. /package/dist/{host → server}/channel-effects.js +0 -0
  325. /package/dist/{host/host-entry.d.ts → server/server-entry.d.ts} +0 -0
  326. /package/src/{controllers → resource-managers}/json.ts +0 -0
  327. /package/src/{host → server}/channel-effects.ts +0 -0
@@ -1,21 +1,24 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { applyStatusPatch } from "./conditions.js";
3
- import { asAnyControllerDefinition, asTypedResource } from "./definition.js";
4
- import { ControllerEffectService } from "./effects.js";
5
- import { ResourceConflictError } from "./errors.js";
3
+ import { asAnyResourceManagerDefinition, asTypedResource } from "./definition.js";
4
+ import { ResourceManagerEffectService } from "./effects.js";
5
+ import { ManagedResourceConflictError } from "./errors.js";
6
6
  import { createResultHelpers } from "./results.js";
7
- import type { ControllerStore } from "./store.js";
7
+ import type { ResourceManagerStore } from "./store.js";
8
8
  import type {
9
- AnyControllerDefinition,
10
- ControllerDefinition,
11
- ControllerQueueClaim,
12
- ControllerResource,
13
- ControllerResourceRef,
9
+ AnyResourceManagerDefinition,
10
+ ResourceManagerDefinition,
11
+ ResourceManagerQueueClaim,
12
+ ManagedResource,
13
+ ManagedResourceRef,
14
14
  JsonObject,
15
15
  ReconcileContext,
16
16
  ReconcileResult,
17
17
  } from "./types.js";
18
- import { ControllerWorkflowCoordinator, type ControllerWorkflowScheduler } from "./workflows.js";
18
+ import {
19
+ ResourceManagerWorkflowCoordinator,
20
+ type ResourceManagerWorkflowScheduler,
21
+ } from "./workflows.js";
19
22
 
20
23
  const DEFAULT_MAX_CONCURRENT = 4;
21
24
  const DEFAULT_TIMEOUT_MS = 60_000;
@@ -26,12 +29,12 @@ const DEFAULT_MAX_BACKOFF_MS = 60_000;
26
29
  const DEFAULT_JITTER_RATIO = 0.2;
27
30
  const MIN_LEASE_MS = 300;
28
31
 
29
- export type ControllerManagerOptions = {
30
- store: ControllerStore;
31
- controllers: AnyControllerDefinition[];
32
- workflowScheduler?: ControllerWorkflowScheduler;
32
+ export type ResourceManagerRuntimeOptions = {
33
+ store: ResourceManagerStore;
34
+ resourceManagers: AnyResourceManagerDefinition[];
35
+ workflowScheduler?: ResourceManagerWorkflowScheduler;
33
36
  maxConcurrent?: number;
34
- controllerConcurrency?: Record<string, number>;
37
+ resourceManagerConcurrency?: Record<string, number>;
35
38
  defaultTimeoutMs?: number;
36
39
  leaseMs?: number;
37
40
  pollIntervalMs?: number;
@@ -42,13 +45,13 @@ export type ControllerManagerOptions = {
42
45
  random?: () => number;
43
46
  };
44
47
 
45
- export class ControllerManager {
46
- readonly store: ControllerStore;
47
- private readonly ownerId = `controller-manager-${randomUUID()}`;
48
- private readonly definitions = new Map<string, AnyControllerDefinition>();
49
- private readonly workflowCoordinator: ControllerWorkflowCoordinator;
48
+ export class ResourceManagerRuntime {
49
+ readonly store: ResourceManagerStore;
50
+ private readonly ownerId = `resource-manager-runtime-${randomUUID()}`;
51
+ private readonly definitions = new Map<string, AnyResourceManagerDefinition>();
52
+ private readonly workflowCoordinator: ResourceManagerWorkflowCoordinator;
50
53
  private readonly maxConcurrent: number;
51
- private readonly controllerConcurrency: Record<string, number>;
54
+ private readonly resourceManagerConcurrency: Record<string, number>;
52
55
  private readonly defaultTimeoutMs: number;
53
56
  private readonly leaseMs: number;
54
57
  private readonly pollIntervalMs: number;
@@ -57,20 +60,20 @@ export class ControllerManager {
57
60
  private readonly jitterRatio: number;
58
61
  private readonly now: () => Date;
59
62
  private readonly random: () => number;
60
- private readonly activeByController = new Map<string, number>();
63
+ private readonly activeByResourceManager = new Map<string, number>();
61
64
  private readonly activeReconciles = new Map<string, AbortController>();
62
65
  private runAbort: AbortController | null = null;
63
- private workerTasks: Promise<void>[] = [];
66
+ private runnerTasks: Promise<void>[] = [];
64
67
 
65
- constructor(options: ControllerManagerOptions) {
68
+ constructor(options: ResourceManagerRuntimeOptions) {
66
69
  this.store = options.store;
67
- for (const definition of options.controllers) {
70
+ for (const definition of options.resourceManagers) {
68
71
  if (this.definitions.has(definition.name)) {
69
- throw new Error(`Duplicate controller definition: ${definition.name}`);
72
+ throw new Error(`Duplicate resource manager definition: ${definition.name}`);
70
73
  }
71
74
  this.definitions.set(definition.name, definition);
72
75
  }
73
- this.workflowCoordinator = new ControllerWorkflowCoordinator(
76
+ this.workflowCoordinator = new ResourceManagerWorkflowCoordinator(
74
77
  options.store,
75
78
  options.workflowScheduler,
76
79
  );
@@ -78,12 +81,12 @@ export class ControllerManager {
78
81
  options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT,
79
82
  "maxConcurrent",
80
83
  );
81
- this.controllerConcurrency = options.controllerConcurrency ?? {};
82
- for (const [name, value] of Object.entries(this.controllerConcurrency)) {
84
+ this.resourceManagerConcurrency = options.resourceManagerConcurrency ?? {};
85
+ for (const [name, value] of Object.entries(this.resourceManagerConcurrency)) {
83
86
  if (!this.definitions.has(name)) {
84
- throw new Error(`Concurrency limit names an unknown controller: ${name}`);
87
+ throw new Error(`Concurrency limit names an unknown resource manager: ${name}`);
85
88
  }
86
- positiveInteger(value, `controllerConcurrency.${name}`);
89
+ positiveInteger(value, `resourceManagerConcurrency.${name}`);
87
90
  }
88
91
  this.defaultTimeoutMs = positiveInteger(
89
92
  options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,
@@ -117,67 +120,67 @@ export class ControllerManager {
117
120
  }
118
121
 
119
122
  putResource<TSpec, TStatus>(
120
- definition: ControllerDefinition<TSpec, TStatus>,
123
+ definition: ResourceManagerDefinition<TSpec, TStatus>,
121
124
  key: string,
122
125
  spec: TSpec,
123
- ): ControllerResource<TSpec, TStatus> {
126
+ ): ManagedResource<TSpec, TStatus> {
124
127
  const registered = this.definitions.get(definition.name);
125
- if (registered !== asAnyControllerDefinition(definition)) {
126
- throw new Error(`Controller definition is not registered: ${definition.name}`);
128
+ if (registered !== asAnyResourceManagerDefinition(definition)) {
129
+ throw new Error(`ResourceManager definition is not registered: ${definition.name}`);
127
130
  }
128
131
  const initialStatus = definition.initialStatus(spec);
129
132
  const resource = this.store.putResource({
130
- controller: definition.name,
133
+ resourceManager: definition.name,
131
134
  key,
132
135
  spec,
133
136
  initialStatus,
134
137
  now: this.now().toISOString(),
135
138
  });
136
139
  this.recordEvent(
137
- { controller: definition.name, key },
140
+ { resourceManager: definition.name, key },
138
141
  resource.metadata.generation === 1 ? "resource_applied" : "resource_updated",
139
142
  { generation: resource.metadata.generation },
140
143
  );
141
144
  const current = this.store.getResource<TSpec, TStatus>({
142
- controller: definition.name,
145
+ resourceManager: definition.name,
143
146
  key,
144
147
  });
145
- if (current === undefined) throw new Error("Controller resource disappeared after its event");
148
+ if (current === undefined) throw new Error("Managed resource disappeared after its event");
146
149
  return current;
147
150
  }
148
151
 
149
- putResourceByName(controller: string, key: string, spec: unknown): ControllerResource {
150
- const definition = this.definitions.get(controller);
152
+ putResourceByName(resourceManager: string, key: string, spec: unknown): ManagedResource {
153
+ const definition = this.definitions.get(resourceManager);
151
154
  if (definition === undefined) {
152
- throw new Error(`Unknown controller: ${controller}`);
155
+ throw new Error(`Unknown resource manager: ${resourceManager}`);
153
156
  }
154
157
  const initialStatus = definition.initialStatus(spec);
155
158
  const resource = this.store.putResource({
156
- controller,
159
+ resourceManager,
157
160
  key,
158
161
  spec,
159
162
  initialStatus,
160
163
  now: this.now().toISOString(),
161
164
  });
162
165
  this.recordEvent(
163
- { controller, key },
166
+ { resourceManager, key },
164
167
  resource.metadata.generation === 1 ? "resource_applied" : "resource_updated",
165
168
  { generation: resource.metadata.generation },
166
169
  );
167
- const current = this.store.getResource({ controller, key });
168
- if (current === undefined) throw new Error("Controller resource disappeared after its event");
170
+ const current = this.store.getResource({ resourceManager, key });
171
+ if (current === undefined) throw new Error("Managed resource disappeared after its event");
169
172
  return current;
170
173
  }
171
174
 
172
- requestDeletion(ref: ControllerResourceRef): ControllerResource {
175
+ requestDeletion(ref: ManagedResourceRef): ManagedResource {
173
176
  this.store.requestDeletion(ref, this.now().toISOString());
174
177
  this.recordEvent(ref, "deletion_requested");
175
178
  const current = this.store.getResource(ref);
176
- if (current === undefined) throw new Error("Controller resource disappeared after its event");
179
+ if (current === undefined) throw new Error("Managed resource disappeared after its event");
177
180
  return current;
178
181
  }
179
182
 
180
- enqueue(ref: ControllerResourceRef, afterMs = 0): void {
183
+ enqueue(ref: ManagedResourceRef, afterMs = 0): void {
181
184
  if (!Number.isSafeInteger(afterMs) || afterMs < 0) {
182
185
  throw new Error("afterMs must be a non-negative safe integer");
183
186
  }
@@ -189,8 +192,8 @@ export class ControllerManager {
189
192
  return;
190
193
  }
191
194
  this.runAbort = new AbortController();
192
- this.workerTasks = Array.from({ length: this.maxConcurrent }, () =>
193
- this.workerLoop(this.runAbort?.signal as AbortSignal),
195
+ this.runnerTasks = Array.from({ length: this.maxConcurrent }, () =>
196
+ this.runnerLoop(this.runAbort?.signal as AbortSignal),
194
197
  );
195
198
  }
196
199
 
@@ -200,12 +203,12 @@ export class ControllerManager {
200
203
  return;
201
204
  }
202
205
  this.runAbort = null;
203
- abort.abort(new Error("Controller manager stopped"));
204
- for (const controller of this.activeReconciles.values()) {
205
- controller.abort(new Error("Controller manager stopped"));
206
+ abort.abort(new Error("Resource manager stopped"));
207
+ for (const abortController of this.activeReconciles.values()) {
208
+ abortController.abort(new Error("Resource manager stopped"));
206
209
  }
207
- await Promise.allSettled(this.workerTasks);
208
- this.workerTasks = [];
210
+ await Promise.allSettled(this.runnerTasks);
211
+ this.runnerTasks = [];
209
212
  }
210
213
 
211
214
  async runOne(): Promise<boolean> {
@@ -224,16 +227,16 @@ export class ControllerManager {
224
227
  count += 1;
225
228
  }
226
229
  if (count === maxReconciles && this.readyQueueExists()) {
227
- throw new Error(`Controller manager exceeded ${maxReconciles} reconciliations`);
230
+ throw new Error(`Resource manager exceeded ${maxReconciles} reconciliations`);
228
231
  }
229
232
  return count;
230
233
  }
231
234
 
232
- get workflowRequests(): ControllerWorkflowCoordinator {
235
+ get workflowRequests(): ResourceManagerWorkflowCoordinator {
233
236
  return this.workflowCoordinator;
234
237
  }
235
238
 
236
- private async workerLoop(signal: AbortSignal): Promise<void> {
239
+ private async runnerLoop(signal: AbortSignal): Promise<void> {
237
240
  while (!signal.aborted) {
238
241
  const claim = this.claimNext();
239
242
  if (claim === undefined) {
@@ -245,54 +248,54 @@ export class ControllerManager {
245
248
  } catch {
246
249
  if (signal.aborted) return;
247
250
  // A stale claim means another owner now controls that resource. Keep
248
- // this worker alive so it can reconcile other queued resources.
251
+ // this runner alive so it can reconcile other queued resources.
249
252
  }
250
253
  }
251
254
  }
252
255
 
253
- private claimNext(): ControllerQueueClaim | undefined {
256
+ private claimNext(): ResourceManagerQueueClaim | undefined {
254
257
  return this.store.claimNext({
255
- controllers: this.eligibleControllers(),
258
+ resourceManagers: this.eligibleResourceManagers(),
256
259
  ownerId: this.ownerId,
257
260
  leaseMs: this.leaseMs,
258
261
  now: this.now().toISOString(),
259
262
  });
260
263
  }
261
264
 
262
- private eligibleControllers(): string[] {
265
+ private eligibleResourceManagers(): string[] {
263
266
  return [...this.definitions.keys()].filter((name) => {
264
- const active = this.activeByController.get(name) ?? 0;
265
- const limit = this.controllerConcurrency[name] ?? this.maxConcurrent;
267
+ const active = this.activeByResourceManager.get(name) ?? 0;
268
+ const limit = this.resourceManagerConcurrency[name] ?? this.maxConcurrent;
266
269
  return active < limit;
267
270
  });
268
271
  }
269
272
 
270
- private async processClaim(claim: ControllerQueueClaim): Promise<void> {
271
- const definition = this.definitions.get(claim.controller);
273
+ private async processClaim(claim: ResourceManagerQueueClaim): Promise<void> {
274
+ const definition = this.definitions.get(claim.resourceManager);
272
275
  if (definition === undefined) {
273
276
  return;
274
277
  }
275
- this.activeByController.set(
276
- claim.controller,
277
- (this.activeByController.get(claim.controller) ?? 0) + 1,
278
+ this.activeByResourceManager.set(
279
+ claim.resourceManager,
280
+ (this.activeByResourceManager.get(claim.resourceManager) ?? 0) + 1,
278
281
  );
279
282
  try {
280
283
  await this.reconcileClaim(definition, claim);
281
284
  } finally {
282
- const active = (this.activeByController.get(claim.controller) ?? 1) - 1;
285
+ const active = (this.activeByResourceManager.get(claim.resourceManager) ?? 1) - 1;
283
286
  if (active === 0) {
284
- this.activeByController.delete(claim.controller);
287
+ this.activeByResourceManager.delete(claim.resourceManager);
285
288
  } else {
286
- this.activeByController.set(claim.controller, active);
289
+ this.activeByResourceManager.set(claim.resourceManager, active);
287
290
  }
288
291
  }
289
292
  }
290
293
 
291
294
  private async reconcileClaim(
292
- definition: AnyControllerDefinition,
293
- claim: ControllerQueueClaim,
295
+ definition: AnyResourceManagerDefinition,
296
+ claim: ResourceManagerQueueClaim,
294
297
  ): Promise<void> {
295
- const ref = { controller: claim.controller, key: claim.key };
298
+ const ref = { resourceManager: claim.resourceManager, key: claim.key };
296
299
  const resource = this.store.getResource(ref);
297
300
  if (resource === undefined) {
298
301
  this.store.settleClaim(claim, this.now().toISOString());
@@ -314,7 +317,7 @@ export class ControllerManager {
314
317
  () => {
315
318
  const renewed = this.store.renewClaim(claim, this.leaseMs, this.now().toISOString());
316
319
  if (!renewed) {
317
- abort.abort(new Error("Controller queue claim was lost"));
320
+ abort.abort(new Error("ResourceManager queue claim was lost"));
318
321
  }
319
322
  },
320
323
  Math.max(100, Math.floor(this.leaseMs / 3)),
@@ -350,14 +353,14 @@ export class ControllerManager {
350
353
  }
351
354
 
352
355
  private async callReconciler(
353
- definition: AnyControllerDefinition,
354
- resource: ControllerResource,
355
- claim: ControllerQueueClaim,
356
+ definition: AnyResourceManagerDefinition,
357
+ resource: ManagedResource,
358
+ claim: ResourceManagerQueueClaim,
356
359
  signal: AbortSignal,
357
360
  ): Promise<ReconcileResult<unknown>> {
358
361
  const context: ReconcileContext<unknown> = {
359
362
  signal,
360
- effects: new ControllerEffectService(this.store, resource, claim, signal),
363
+ effects: new ResourceManagerEffectService(this.store, resource, claim, signal),
361
364
  workflows: this.workflowCoordinator.forResource(resource, claim, signal),
362
365
  ...createResultHelpers<unknown>(),
363
366
  };
@@ -367,13 +370,13 @@ export class ControllerManager {
367
370
  }
368
371
 
369
372
  private async finishSuccessfulClaim(
370
- claim: ControllerQueueClaim,
371
- resource: ControllerResource,
373
+ claim: ResourceManagerQueueClaim,
374
+ resource: ManagedResource,
372
375
  result: ReconcileResult<unknown>,
373
376
  reconcileId: string,
374
377
  startedAtMs: number,
375
378
  ): Promise<void> {
376
- const ref = { controller: claim.controller, key: claim.key };
379
+ const ref = { resourceManager: claim.resourceManager, key: claim.key };
377
380
  const now = this.now();
378
381
  const status = applyStatusPatch(
379
382
  resource.status,
@@ -416,7 +419,7 @@ export class ControllerManager {
416
419
  return;
417
420
  }
418
421
  } catch (error) {
419
- if (error instanceof ResourceConflictError) {
422
+ if (error instanceof ManagedResourceConflictError) {
420
423
  this.recordEvent(ref, "reconcile_conflict", { reconcileId }, claim);
421
424
  this.store.requeueClaim(claim, { availableAt: now.toISOString() }, now.toISOString());
422
425
  return;
@@ -436,8 +439,8 @@ export class ControllerManager {
436
439
  }
437
440
 
438
441
  private async finishFailedClaim(
439
- claim: ControllerQueueClaim,
440
- ref: ControllerResourceRef,
442
+ claim: ResourceManagerQueueClaim,
443
+ ref: ManagedResourceRef,
441
444
  reconcileId: string,
442
445
  error: unknown,
443
446
  startedAtMs: number,
@@ -479,13 +482,13 @@ export class ControllerManager {
479
482
  }
480
483
 
481
484
  private recordEvent(
482
- ref: ControllerResourceRef,
485
+ ref: ManagedResourceRef,
483
486
  type: string,
484
487
  payload: JsonObject = {},
485
- claim?: ControllerQueueClaim,
488
+ claim?: ResourceManagerQueueClaim,
486
489
  ): void {
487
490
  this.store.recordEvent({
488
- controller: ref.controller,
491
+ resourceManager: ref.resourceManager,
489
492
  key: ref.key,
490
493
  ...(claim === undefined ? {} : { claim }),
491
494
  type,
@@ -521,10 +524,10 @@ function raceWithAbort<T>(operation: Promise<T>, signal: AbortSignal): Promise<T
521
524
 
522
525
  function validateResult(result: ReconcileResult<unknown>): void {
523
526
  if (result === null || typeof result !== "object") {
524
- throw new Error("Controller reconcile must return a result object");
527
+ throw new Error("ResourceManager reconcile must return a result object");
525
528
  }
526
529
  if (result.kind !== "settled" && result.kind !== "requeue") {
527
- throw new Error("Controller reconcile returned an unknown result kind");
530
+ throw new Error("ResourceManager reconcile returned an unknown result kind");
528
531
  }
529
532
  if (result.kind === "settled" && "afterMs" in result) {
530
533
  throw new Error("A settled reconcile result cannot specify afterMs");