@osolmaz/pi-workflows 0.12.0 → 0.13.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 (257) hide show
  1. package/README.md +56 -31
  2. package/dist/builtins/autodoc.workflow.d.ts +4 -4
  3. package/dist/builtins/autoimplement.workflow.d.ts +797 -142
  4. package/dist/builtins/autoimplement.workflow.js +17 -105
  5. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  6. package/dist/builtins/autoplan.workflow.d.ts +126 -13
  7. package/dist/builtins/autoplan.workflow.js +200 -29
  8. package/dist/builtins/autoplan.workflow.js.map +1 -1
  9. package/dist/builtins/catalog.js +7 -5
  10. package/dist/builtins/catalog.js.map +1 -1
  11. package/dist/builtins/index.d.ts +4 -2
  12. package/dist/builtins/index.js +3 -1
  13. package/dist/builtins/index.js.map +1 -1
  14. package/dist/builtins/monitor.workflow.d.ts +56 -23
  15. package/dist/builtins/monitor.workflow.js +508 -329
  16. package/dist/builtins/monitor.workflow.js.map +1 -1
  17. package/dist/builtins/pi-agent-group.d.ts +72 -0
  18. package/dist/builtins/pi-agent-group.js +1087 -0
  19. package/dist/builtins/pi-agent-group.js.map +1 -0
  20. package/dist/builtins/plain-summary.workflow.d.ts +32 -0
  21. package/dist/builtins/plain-summary.workflow.js +134 -0
  22. package/dist/builtins/plain-summary.workflow.js.map +1 -0
  23. package/dist/builtins/plan-approval.workflow.d.ts +39 -5
  24. package/dist/builtins/plan-approval.workflow.js +92 -14
  25. package/dist/builtins/plan-approval.workflow.js.map +1 -1
  26. package/dist/builtins/plan-change.workflow.d.ts +449 -0
  27. package/dist/builtins/plan-change.workflow.js +256 -0
  28. package/dist/builtins/plan-change.workflow.js.map +1 -0
  29. package/dist/builtins/plan-presentation.js +2 -2
  30. package/dist/builtins/plan-presentation.js.map +1 -1
  31. package/dist/builtins/sanity-check.workflow.d.ts +50 -6
  32. package/dist/builtins/sanity-check.workflow.js +150 -28
  33. package/dist/builtins/sanity-check.workflow.js.map +1 -1
  34. package/dist/controllers/effects.d.ts +3 -2
  35. package/dist/controllers/effects.js +8 -1
  36. package/dist/controllers/effects.js.map +1 -1
  37. package/dist/controllers/index.d.ts +1 -1
  38. package/dist/controllers/index.js +1 -1
  39. package/dist/controllers/index.js.map +1 -1
  40. package/dist/controllers/manager.d.ts +1 -0
  41. package/dist/controllers/manager.js +41 -17
  42. package/dist/controllers/manager.js.map +1 -1
  43. package/dist/controllers/sqlite.d.ts +107 -85
  44. package/dist/controllers/sqlite.js +1611 -1486
  45. package/dist/controllers/sqlite.js.map +1 -1
  46. package/dist/controllers/store.d.ts +9 -8
  47. package/dist/controllers/store.js +1 -31
  48. package/dist/controllers/store.js.map +1 -1
  49. package/dist/controllers/types.d.ts +3 -0
  50. package/dist/controllers/workflow-engine-scheduler.d.ts +1 -1
  51. package/dist/controllers/workflow-engine-scheduler.js +3 -5
  52. package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
  53. package/dist/controllers/workflows.d.ts +2 -2
  54. package/dist/controllers/workflows.js +11 -10
  55. package/dist/controllers/workflows.js.map +1 -1
  56. package/dist/extension/controller-host.js +2 -2
  57. package/dist/extension/controller-host.js.map +1 -1
  58. package/dist/extension/decision-channels.d.ts +4 -2
  59. package/dist/extension/decision-channels.js +333 -146
  60. package/dist/extension/decision-channels.js.map +1 -1
  61. package/dist/extension/executor.d.ts +9 -2
  62. package/dist/extension/executor.js +89 -2
  63. package/dist/extension/executor.js.map +1 -1
  64. package/dist/extension/herdr-viewer.d.ts +0 -1
  65. package/dist/extension/herdr-viewer.js +0 -4
  66. package/dist/extension/herdr-viewer.js.map +1 -1
  67. package/dist/extension/index.js +209 -127
  68. package/dist/extension/index.js.map +1 -1
  69. package/dist/extension/recorder.d.ts +3 -10
  70. package/dist/extension/recorder.js +13 -22
  71. package/dist/extension/recorder.js.map +1 -1
  72. package/dist/extension/session-events.d.ts +2 -2
  73. package/dist/extension/step-message.d.ts +7 -2
  74. package/dist/extension/step-message.js +94 -2
  75. package/dist/extension/step-message.js.map +1 -1
  76. package/dist/extension/widget.js +29 -3
  77. package/dist/extension/widget.js.map +1 -1
  78. package/dist/host/rpc-executor.d.ts +3 -0
  79. package/dist/host/rpc-executor.js +2 -0
  80. package/dist/host/rpc-executor.js.map +1 -1
  81. package/dist/host/runner.d.ts +3 -6
  82. package/dist/host/runner.js +83 -32
  83. package/dist/host/runner.js.map +1 -1
  84. package/dist/render/graph-render.js +15 -10
  85. package/dist/render/graph-render.js.map +1 -1
  86. package/dist/state/database.d.ts +35 -0
  87. package/dist/state/database.js +287 -0
  88. package/dist/state/database.js.map +1 -0
  89. package/dist/state/index.d.ts +4 -0
  90. package/dist/state/index.js +5 -0
  91. package/dist/state/index.js.map +1 -0
  92. package/dist/state/json.d.ts +6 -0
  93. package/dist/state/json.js +38 -0
  94. package/dist/state/json.js.map +1 -0
  95. package/dist/state/mutation.d.ts +57 -0
  96. package/dist/state/mutation.js +255 -0
  97. package/dist/state/mutation.js.map +1 -0
  98. package/dist/state/schema.d.ts +6 -0
  99. package/dist/state/schema.js +473 -0
  100. package/dist/state/schema.js.map +1 -0
  101. package/dist/viewer/cli.d.ts +2 -2
  102. package/dist/viewer/cli.js +142 -122
  103. package/dist/viewer/cli.js.map +1 -1
  104. package/dist/viewer/render.d.ts +4 -4
  105. package/dist/viewer/render.js +9 -23
  106. package/dist/viewer/render.js.map +1 -1
  107. package/dist/viewer/session-reducer.d.ts +1 -1
  108. package/dist/viewer/session-reducer.js +1 -1
  109. package/dist/viewer/tui.d.ts +3 -3
  110. package/dist/viewer/tui.js +15 -13
  111. package/dist/viewer/tui.js.map +1 -1
  112. package/dist/viewer/watch.d.ts +2 -5
  113. package/dist/viewer/watch.js +13 -13
  114. package/dist/viewer/watch.js.map +1 -1
  115. package/dist/workflows/catalog.js +7 -2
  116. package/dist/workflows/catalog.js.map +1 -1
  117. package/dist/workflows/composition.js +20 -2
  118. package/dist/workflows/composition.js.map +1 -1
  119. package/dist/workflows/decision-presentation.d.ts +1 -1
  120. package/dist/workflows/decision-presentation.js +51 -38
  121. package/dist/workflows/decision-presentation.js.map +1 -1
  122. package/dist/workflows/definition.d.ts +6 -2
  123. package/dist/workflows/definition.js +17 -0
  124. package/dist/workflows/definition.js.map +1 -1
  125. package/dist/workflows/engine.d.ts +7 -7
  126. package/dist/workflows/engine.js +196 -115
  127. package/dist/workflows/engine.js.map +1 -1
  128. package/dist/workflows/errors.d.ts +16 -3
  129. package/dist/workflows/errors.js +18 -3
  130. package/dist/workflows/errors.js.map +1 -1
  131. package/dist/workflows/human-decision.d.ts +45 -8
  132. package/dist/workflows/human-decision.js +641 -274
  133. package/dist/workflows/human-decision.js.map +1 -1
  134. package/dist/workflows/index.d.ts +5 -6
  135. package/dist/workflows/index.js +4 -5
  136. package/dist/workflows/index.js.map +1 -1
  137. package/dist/workflows/progress.d.ts +1 -0
  138. package/dist/workflows/progress.js +15 -3
  139. package/dist/workflows/progress.js.map +1 -1
  140. package/dist/workflows/schema.js +27 -1
  141. package/dist/workflows/schema.js.map +1 -1
  142. package/dist/workflows/store.d.ts +83 -103
  143. package/dist/workflows/store.js +907 -951
  144. package/dist/workflows/store.js.map +1 -1
  145. package/dist/workflows/types.d.ts +88 -126
  146. package/docs/CONTROLLERS.md +10 -8
  147. package/docs/DEFERRED_TURNS.md +2 -2
  148. package/docs/DESIGN_PHILOSOPHY.md +4 -2
  149. package/docs/HUMAN_DECISIONS.md +36 -47
  150. package/docs/HUMAN_DECISION_PRESENTATIONS.md +14 -24
  151. package/docs/MONITOR.md +179 -237
  152. package/docs/SQLITE_STATE.md +219 -0
  153. package/docs/WORKFLOW_COMPOSITION.md +27 -26
  154. package/docs/WORKFLOW_STEP_MESSAGES.md +20 -18
  155. package/docs/WORKFLOW_UPDATES.md +10 -9
  156. package/docs/development.md +9 -9
  157. package/docs/live-replay-protocol.md +28 -37
  158. package/docs/plans/2026-08-16-workflow-updates-plan.md +1 -1
  159. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  160. package/docs/plans/2026-08-21-autoimplement-timeout-fallback-plan.md +1 -1
  161. package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +322 -0
  162. package/docs/plans/2026-08-21-sanity-check-plan.md +217 -95
  163. package/docs/plans/2026-08-22-goal-finishing-monitor-plan.md +200 -0
  164. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +701 -0
  165. package/docs/plans/2026-08-23-sqlite-state-plan.md +970 -0
  166. package/docs/plans/replayable-run-bundles-implementation-plan.md +2 -2
  167. package/docs/plans/session-event-replay-implementation-plan.md +1 -1
  168. package/docs/plans/tui-viewer-implementation-plan.md +1 -1
  169. package/docs/session-event-journal.md +63 -434
  170. package/docs/tui-viewer.md +13 -15
  171. package/docs/workflows.md +127 -53
  172. package/examples/workflows/approved-plan.workflow.ts +19 -46
  173. package/examples/workflows/plain-summary.workflow.ts +1 -0
  174. package/herdr-plugin.toml +1 -1
  175. package/package.json +7 -7
  176. package/plugins/herdr/viewer.mjs +1 -11
  177. package/schemas/human-decision-accepted-v1.schema.json +15 -3
  178. package/schemas/human-decision-continuation-v1.schema.json +10 -1
  179. package/schemas/human-decision-delivery-v1.schema.json +8 -0
  180. package/schemas/human-decision-receipt-v1.schema.json +8 -0
  181. package/schemas/human-decision-request-v1.schema.json +24 -4
  182. package/skills/autoimplement/SKILL.md +27 -0
  183. package/skills/autoplan/SKILL.md +5 -4
  184. package/skills/monitor/SKILL.md +91 -135
  185. package/skills/pi-workflows/SKILL.md +9 -8
  186. package/skills/sanity-check/SKILL.md +44 -0
  187. package/src/builtins/autoimplement.workflow.ts +19 -118
  188. package/src/builtins/autoplan.workflow.ts +290 -40
  189. package/src/builtins/catalog.ts +7 -5
  190. package/src/builtins/index.ts +18 -1
  191. package/src/builtins/monitor.workflow.ts +673 -382
  192. package/src/builtins/pi-agent-group.ts +1407 -0
  193. package/src/builtins/plain-summary.workflow.ts +185 -0
  194. package/src/builtins/plan-approval.workflow.ts +157 -24
  195. package/src/builtins/plan-change.workflow.ts +321 -0
  196. package/src/builtins/plan-presentation.ts +2 -2
  197. package/src/builtins/sanity-check.workflow.ts +248 -48
  198. package/src/controllers/effects.ts +7 -0
  199. package/src/controllers/index.ts +0 -6
  200. package/src/controllers/manager.ts +72 -32
  201. package/src/controllers/sqlite.ts +2420 -1948
  202. package/src/controllers/store.ts +17 -38
  203. package/src/controllers/types.ts +3 -0
  204. package/src/controllers/workflow-engine-scheduler.ts +4 -8
  205. package/src/controllers/workflows.ts +45 -21
  206. package/src/extension/controller-host.ts +1 -2
  207. package/src/extension/decision-channels.ts +456 -203
  208. package/src/extension/executor.ts +105 -2
  209. package/src/extension/herdr-viewer.ts +0 -5
  210. package/src/extension/index.ts +251 -151
  211. package/src/extension/recorder.ts +13 -22
  212. package/src/extension/session-events.ts +2 -2
  213. package/src/extension/step-message.ts +106 -4
  214. package/src/extension/widget.ts +32 -5
  215. package/src/host/rpc-executor.ts +4 -0
  216. package/src/host/runner.ts +93 -41
  217. package/src/render/graph-render.ts +12 -6
  218. package/src/state/database.ts +375 -0
  219. package/src/state/index.ts +29 -0
  220. package/src/state/json.ts +42 -0
  221. package/src/state/mutation.ts +435 -0
  222. package/src/state/schema.ts +475 -0
  223. package/src/viewer/cli.ts +151 -144
  224. package/src/viewer/render.ts +19 -30
  225. package/src/viewer/session-reducer.ts +1 -1
  226. package/src/viewer/tui.ts +18 -17
  227. package/src/viewer/watch.ts +13 -17
  228. package/src/workflows/catalog.ts +7 -2
  229. package/src/workflows/composition.ts +21 -3
  230. package/src/workflows/decision-presentation.ts +56 -43
  231. package/src/workflows/definition.ts +36 -3
  232. package/src/workflows/engine.ts +228 -130
  233. package/src/workflows/errors.ts +27 -3
  234. package/src/workflows/human-decision.ts +921 -349
  235. package/src/workflows/index.ts +20 -30
  236. package/src/workflows/progress.ts +18 -3
  237. package/src/workflows/schema.ts +36 -1
  238. package/src/workflows/store.ts +1300 -1163
  239. package/src/workflows/types.ts +100 -137
  240. package/dist/builtins/sanity-check-session.d.ts +0 -17
  241. package/dist/builtins/sanity-check-session.js +0 -168
  242. package/dist/builtins/sanity-check-session.js.map +0 -1
  243. package/dist/workflows/artifacts.d.ts +0 -40
  244. package/dist/workflows/artifacts.js +0 -155
  245. package/dist/workflows/artifacts.js.map +0 -1
  246. package/dist/workflows/migrate-sources.d.ts +0 -42
  247. package/dist/workflows/migrate-sources.js +0 -133
  248. package/dist/workflows/migrate-sources.js.map +0 -1
  249. package/docs/run-bundles.md +0 -481
  250. package/schemas/human-decision-accepted-v2.schema.json +0 -50
  251. package/schemas/human-decision-delivery-v2.schema.json +0 -36
  252. package/schemas/human-decision-receipt-v2.schema.json +0 -39
  253. package/schemas/human-decision-request-v2.schema.json +0 -69
  254. package/schemas/human-decision-resolution-v2.schema.json +0 -27
  255. package/src/builtins/sanity-check-session.ts +0 -205
  256. package/src/workflows/artifacts.ts +0 -188
  257. package/src/workflows/migrate-sources.ts +0 -178
@@ -1,7 +1,3 @@
1
- import { createHash } from "node:crypto";
2
- import fs from "node:fs";
3
- import os from "node:os";
4
- import path from "node:path";
5
1
  import type {
6
2
  ChildWorkflowRecord,
7
3
  ControllerEvent,
@@ -13,8 +9,6 @@ import type {
13
9
  JsonObject,
14
10
  } from "./types.js";
15
11
 
16
- export const CONTROLLER_STORE_SCHEMA = "pi-workflows.controller-store.v1" as const;
17
-
18
12
  export type QueueRequeueOptions = {
19
13
  availableAt: string;
20
14
  error?: string;
@@ -65,6 +59,7 @@ export interface ControllerStore {
65
59
  updateStatus<TStatus>(options: {
66
60
  ref: ControllerResourceRef;
67
61
  expectedResourceVersion: number;
62
+ claim: ControllerQueueClaim;
68
63
  status: ControllerResourceStatus<TStatus>;
69
64
  finalizers?: string[];
70
65
  now?: string;
@@ -76,11 +71,16 @@ export interface ControllerStore {
76
71
  finalizers: string[];
77
72
  now?: string;
78
73
  }): ControllerResource;
79
- deleteResource(ref: ControllerResourceRef, expectedResourceVersion: number): boolean;
74
+ deleteResource(
75
+ ref: ControllerResourceRef,
76
+ expectedResourceVersion: number,
77
+ claim: ControllerQueueClaim,
78
+ ): boolean;
80
79
 
81
80
  enqueue(ref: ControllerResourceRef, availableAt?: string): void;
82
81
  claimNext(options: {
83
82
  controllers: string[];
83
+ ownerId: string;
84
84
  leaseMs: number;
85
85
  now?: string;
86
86
  }): ControllerQueueClaim | undefined;
@@ -92,6 +92,7 @@ export interface ControllerStore {
92
92
  reserveEffect(options: {
93
93
  key: string;
94
94
  resourceUid: string;
95
+ claim: ControllerQueueClaim;
95
96
  generation: number;
96
97
  kind: string;
97
98
  requestFingerprint: string;
@@ -101,6 +102,7 @@ export interface ControllerStore {
101
102
  updateEffect(options: {
102
103
  resourceUid: string;
103
104
  key: string;
105
+ claim: ControllerQueueClaim;
104
106
  state: EffectRecord["state"];
105
107
  externalRef?: string;
106
108
  error?: string;
@@ -110,51 +112,28 @@ export interface ControllerStore {
110
112
 
111
113
  reserveWorkflow(options: {
112
114
  resourceUid: string;
115
+ claim: ControllerQueueClaim;
113
116
  requestKey: string;
114
117
  workflow: string;
115
118
  inputFingerprint: string;
116
119
  }): WorkflowReservation;
117
120
  getWorkflow(resourceUid: string, requestKey: string): ChildWorkflowRecord | undefined;
118
121
  getWorkflowByRequestId(requestId: string): ChildWorkflowRecord | undefined;
119
- updateWorkflow(requestId: string, update: WorkflowRecordUpdate): ChildWorkflowRecord;
122
+ updateWorkflow(
123
+ requestId: string,
124
+ update: WorkflowRecordUpdate,
125
+ claim: ControllerQueueClaim,
126
+ ): ChildWorkflowRecord;
127
+ completeWorkflow(requestId: string, update: WorkflowRecordUpdate): ChildWorkflowRecord;
120
128
  listWorkflows(resourceUid: string): ChildWorkflowRecord[];
121
129
 
122
130
  recordEvent(options: {
123
131
  controller: string;
124
132
  key: string;
133
+ claim?: ControllerQueueClaim;
125
134
  type: string;
126
135
  payload?: JsonObject;
127
136
  now?: string;
128
137
  }): ControllerEvent;
129
138
  listEvents(options?: { controller?: string; key?: string; limit?: number }): ControllerEvent[];
130
139
  }
131
-
132
- export function controllerStoreBaseDir(homeDir: string = os.homedir()): string {
133
- const override = process.env.PI_WORKFLOWS_CONTROLLER_DIR;
134
- if (override !== undefined && override.length > 0) {
135
- return override;
136
- }
137
- return path.join(homeDir, ".pi", "agent", "workflows", "controllers");
138
- }
139
-
140
- export function controllerStorePath(homeDir: string = os.homedir()): string {
141
- return path.join(controllerStoreBaseDir(homeDir), "controller.sqlite");
142
- }
143
-
144
- export function controllerProjectScope(cwd: string): string {
145
- let canonicalCwd: string;
146
- try {
147
- canonicalCwd = fs.realpathSync.native(cwd);
148
- } catch {
149
- canonicalCwd = path.resolve(cwd);
150
- }
151
- return createHash("sha256").update(canonicalCwd).digest("hex").slice(0, 24);
152
- }
153
-
154
- export function projectControllerStoreBaseDir(cwd: string, homeDir: string = os.homedir()): string {
155
- return path.join(controllerStoreBaseDir(homeDir), "projects", controllerProjectScope(cwd));
156
- }
157
-
158
- export function projectControllerStorePath(cwd: string, homeDir: string = os.homedir()): string {
159
- return path.join(projectControllerStoreBaseDir(cwd, homeDir), "controller.sqlite");
160
- }
@@ -167,8 +167,11 @@ export type AnyControllerDefinition = {
167
167
  export type ControllerQueueClaim = {
168
168
  controller: string;
169
169
  key: string;
170
+ ownerId: string;
170
171
  token: string;
172
+ generation: number;
171
173
  queueVersion: number;
174
+ resourceVersion: number;
172
175
  consecutiveErrors: number;
173
176
  expiresAt: string;
174
177
  };
@@ -1,5 +1,5 @@
1
1
  import { WorkflowEngine } from "../workflows/engine.js";
2
- import { readLastTraceEvent, readRunBundle, type WorkflowRunStore } from "../workflows/store.js";
2
+ import type { WorkflowRunStore } from "../workflows/store.js";
3
3
  import type {
4
4
  WorkflowDefinition,
5
5
  WorkflowRunResult,
@@ -47,17 +47,14 @@ export class WorkflowEngineScheduler implements ControllerWorkflowScheduler {
47
47
  return { state: "running", runId: active.runId };
48
48
  }
49
49
 
50
- const bundle = await readRunBundle(this.options.store.runDirFor(request.runId));
50
+ const bundle = this.options.store.readRun(request.runId, { includeTrace: true });
51
51
  if (bundle !== null) {
52
52
  const recovered =
53
53
  bundle.state.status === "running"
54
54
  ? await this.options.store.markRunInterrupted(request.runId)
55
55
  : bundle;
56
56
  if (recovered !== null) {
57
- const lastTraceEvent = await readLastTraceEvent(
58
- recovered.runDir,
59
- recovered.manifest.paths.trace,
60
- );
57
+ const lastTraceEvent = recovered.traceEvents?.at(-1) ?? null;
61
58
  return resultFromStatus(
62
59
  recovered.state.status,
63
60
  request.runId,
@@ -68,7 +65,6 @@ export class WorkflowEngineScheduler implements ControllerWorkflowScheduler {
68
65
  return { state: "pending" };
69
66
  }
70
67
 
71
- await this.options.store.quarantineIncompleteRun(request.runId);
72
68
  const resolved = await this.options.resolveWorkflow(request.workflow);
73
69
  if (signal.aborted) {
74
70
  throw signal.reason ?? new Error("Workflow scheduling aborted");
@@ -112,7 +108,7 @@ function callCompletion(
112
108
  try {
113
109
  callback(result);
114
110
  } catch {
115
- // A later reconciliation recovers completion from the immutable run bundle.
111
+ // A later reconciliation recovers completion from the immutable run event.
116
112
  }
117
113
  }
118
114
 
@@ -5,6 +5,7 @@ import type {
5
5
  ChildWorkflowRecord,
6
6
  ChildWorkflowRequest,
7
7
  ChildWorkflowState,
8
+ ControllerQueueClaim,
8
9
  ControllerResource,
9
10
  ControllerWorkflows,
10
11
  } from "./types.js";
@@ -37,9 +38,13 @@ export class ControllerWorkflowCoordinator {
37
38
  private readonly scheduler?: ControllerWorkflowScheduler,
38
39
  ) {}
39
40
 
40
- forResource(resource: ControllerResource, signal: AbortSignal): ControllerWorkflows {
41
+ forResource(
42
+ resource: ControllerResource,
43
+ claim: ControllerQueueClaim,
44
+ signal: AbortSignal,
45
+ ): ControllerWorkflows {
41
46
  return {
42
- ensure: async (request) => await this.ensure(resource, request, signal),
47
+ ensure: async (request) => await this.ensure(resource, claim, request, signal),
43
48
  };
44
49
  }
45
50
 
@@ -48,24 +53,25 @@ export class ControllerWorkflowCoordinator {
48
53
  if (previous === undefined) {
49
54
  throw new Error(`Workflow request not found: ${requestId}`);
50
55
  }
51
- const record = this.store.updateWorkflow(requestId, {
56
+ const record = this.store.completeWorkflow(requestId, {
52
57
  state: result.state,
53
58
  ...(result.runId !== undefined ? { runId: result.runId } : {}),
54
59
  ...(result.error !== undefined ? { error: result.error } : { error: null }),
55
60
  });
56
61
  this.enqueueParent(record.resourceUid);
57
- this.recordEvent(record, "workflow_state_changed");
58
62
  return record;
59
63
  }
60
64
 
61
65
  private async ensure(
62
66
  resource: ControllerResource,
67
+ claim: ControllerQueueClaim,
63
68
  request: ChildWorkflowRequest,
64
69
  signal: AbortSignal,
65
70
  ): Promise<ChildWorkflowRecord> {
66
71
  const inputFingerprint = jsonFingerprint(request.input);
67
72
  const reservation = this.store.reserveWorkflow({
68
73
  resourceUid: resource.metadata.uid,
74
+ claim,
69
75
  requestKey: request.requestKey,
70
76
  workflow: request.workflow,
71
77
  inputFingerprint,
@@ -78,18 +84,26 @@ export class ControllerWorkflowCoordinator {
78
84
  return record;
79
85
  }
80
86
  if (record.state === "interrupted" || record.attempt === 0) {
81
- record = this.store.updateWorkflow(record.requestId, {
82
- state: "pending",
83
- attempt: record.attempt + 1,
84
- runId: createRunId(record.workflow),
85
- error: null,
86
- });
87
+ record = this.store.updateWorkflow(
88
+ record.requestId,
89
+ {
90
+ state: "pending",
91
+ attempt: record.attempt + 1,
92
+ runId: createRunId(record.workflow),
93
+ error: null,
94
+ },
95
+ claim,
96
+ );
87
97
  } else if (record.runId === undefined) {
88
- record = this.store.updateWorkflow(record.requestId, {
89
- state: "pending",
90
- runId: createRunId(record.workflow),
91
- error: null,
92
- });
98
+ record = this.store.updateWorkflow(
99
+ record.requestId,
100
+ {
101
+ state: "pending",
102
+ runId: createRunId(record.workflow),
103
+ error: null,
104
+ },
105
+ claim,
106
+ );
93
107
  }
94
108
  if (record.runId === undefined) {
95
109
  throw new Error(`Workflow request has no reserved run ID: ${record.requestId}`);
@@ -107,15 +121,20 @@ export class ControllerWorkflowCoordinator {
107
121
  this.complete(record.requestId, completed);
108
122
  },
109
123
  );
110
- record = this.store.updateWorkflow(record.requestId, {
111
- state: result.state,
112
- ...(result.runId !== undefined ? { runId: result.runId } : {}),
113
- ...(result.error !== undefined ? { error: result.error } : { error: null }),
114
- });
124
+ record = this.store.updateWorkflow(
125
+ record.requestId,
126
+ {
127
+ state: result.state,
128
+ ...(result.runId !== undefined ? { runId: result.runId } : {}),
129
+ ...(result.error !== undefined ? { error: result.error } : { error: null }),
130
+ },
131
+ claim,
132
+ );
115
133
  if (reservation.created || result.state !== "running") {
116
134
  this.recordEvent(
117
135
  record,
118
136
  reservation.created ? "workflow_requested" : "workflow_state_changed",
137
+ claim,
119
138
  );
120
139
  }
121
140
  return record;
@@ -131,7 +150,11 @@ export class ControllerWorkflowCoordinator {
131
150
  }
132
151
  }
133
152
 
134
- private recordEvent(record: ChildWorkflowRecord, type: string): void {
153
+ private recordEvent(
154
+ record: ChildWorkflowRecord,
155
+ type: string,
156
+ claim: ControllerQueueClaim,
157
+ ): void {
135
158
  const resource = this.store.getResourceByUid(record.resourceUid);
136
159
  if (resource === undefined) {
137
160
  return;
@@ -139,6 +162,7 @@ export class ControllerWorkflowCoordinator {
139
162
  this.store.recordEvent({
140
163
  controller: resource.metadata.controller,
141
164
  key: resource.metadata.key,
165
+ claim,
142
166
  type,
143
167
  payload: {
144
168
  requestId: record.requestId,
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  ControllerManager,
3
3
  SqliteControllerStore,
4
- projectControllerStorePath,
5
4
  loadDiscoveredControllers,
6
5
  type AnyControllerDefinition,
7
6
  type ControllerResource,
@@ -86,7 +85,7 @@ export class PiControllerHost {
86
85
  if (definitions.length === 0) {
87
86
  return undefined;
88
87
  }
89
- const store = new SqliteControllerStore(projectControllerStorePath(options.cwd));
88
+ const store = new SqliteControllerStore(undefined, { projectPath: options.cwd });
90
89
  const manager = new ControllerManager({
91
90
  store,
92
91
  controllers: definitions,