harnery 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +2 -1
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +2 -0
  4. package/dist/commands/work.d.ts +4 -0
  5. package/dist/commands/work.d.ts.map +1 -0
  6. package/dist/commands/work.js +281 -0
  7. package/dist/commands/workflow.d.ts.map +1 -1
  8. package/dist/commands/workflow.js +193 -0
  9. package/dist/core/policy/types.d.ts +1 -1
  10. package/dist/core/policy/types.d.ts.map +1 -1
  11. package/dist/core/work/index.d.ts +3 -0
  12. package/dist/core/work/index.d.ts.map +1 -0
  13. package/dist/core/work/index.js +2 -0
  14. package/dist/core/work/read.d.ts +2 -0
  15. package/dist/core/work/read.d.ts.map +1 -0
  16. package/dist/core/work/read.js +1 -0
  17. package/dist/core/work/runner.d.ts +10 -0
  18. package/dist/core/work/runner.d.ts.map +1 -0
  19. package/dist/core/work/runner.js +63 -0
  20. package/dist/core/work/state.d.ts +109 -0
  21. package/dist/core/work/state.d.ts.map +1 -0
  22. package/dist/core/work/state.js +698 -0
  23. package/dist/core/workflow/approvals.d.ts +71 -0
  24. package/dist/core/workflow/approvals.d.ts.map +1 -0
  25. package/dist/core/workflow/approvals.js +288 -0
  26. package/dist/core/workflow/engine.d.ts +6 -0
  27. package/dist/core/workflow/engine.d.ts.map +1 -1
  28. package/dist/core/workflow/engine.js +243 -43
  29. package/dist/core/workflow/index.d.ts +6 -2
  30. package/dist/core/workflow/index.d.ts.map +1 -1
  31. package/dist/core/workflow/index.js +3 -1
  32. package/dist/core/workflow/proof.d.ts +1 -0
  33. package/dist/core/workflow/proof.d.ts.map +1 -1
  34. package/dist/core/workflow/proof.js +1 -0
  35. package/dist/core/workflow/run-state.d.ts +44 -0
  36. package/dist/core/workflow/run-state.d.ts.map +1 -0
  37. package/dist/core/workflow/run-state.js +233 -0
  38. package/dist/core/workflow/types.d.ts +16 -0
  39. package/dist/core/workflow/types.d.ts.map +1 -1
  40. package/package.json +11 -1
  41. package/src/commander.ts +2 -0
  42. package/src/commands/work.ts +367 -0
  43. package/src/commands/workflow.ts +226 -0
  44. package/src/core/policy/types.ts +1 -1
  45. package/src/core/work/index.ts +24 -0
  46. package/src/core/work/read.ts +15 -0
  47. package/src/core/work/runner.ts +81 -0
  48. package/src/core/work/state.ts +900 -0
  49. package/src/core/workflow/approvals.ts +393 -0
  50. package/src/core/workflow/engine.ts +288 -44
  51. package/src/core/workflow/index.ts +31 -1
  52. package/src/core/workflow/proof.ts +2 -0
  53. package/src/core/workflow/run-state.ts +290 -0
  54. package/src/core/workflow/types.ts +16 -0
@@ -0,0 +1,81 @@
1
+ import { resolve } from "node:path";
2
+ import { runWorkflow } from "../workflow/engine.ts";
3
+ import type { EngineOpts, RunReport } from "../workflow/types.ts";
4
+ import {
5
+ acquireWorkLease,
6
+ appendReconcileIfChanged,
7
+ appendWorkEvent,
8
+ assertWorkflowUnchanged,
9
+ boundedActor,
10
+ newWorkflowRunId,
11
+ readWorkItemIgnoringLease,
12
+ } from "./state.ts";
13
+
14
+ export interface RunWorkItemInput {
15
+ coordRoot: string;
16
+ workId: string;
17
+ engine: Omit<EngineOpts, "coordRoot" | "runId" | "resumeRunId" | "workItemId">;
18
+ retry?: boolean;
19
+ actor?: string;
20
+ }
21
+
22
+ export async function runWorkItem(input: RunWorkItemInput): Promise<RunReport> {
23
+ const coordRoot = resolve(input.coordRoot);
24
+ const release = acquireWorkLease(coordRoot, input.workId);
25
+ try {
26
+ const record = readWorkItemIgnoringLease(coordRoot, input.workId);
27
+ assertWorkflowUnchanged(record.intent);
28
+ const latest = record.projection.attempts.at(-1);
29
+ if (record.projection.state === "awaiting_approval" && latest) {
30
+ if (record.projection.next_action !== "resume") {
31
+ throw new Error(`work item ${input.workId} is waiting for approval ${latest.approval_id}`);
32
+ }
33
+ appendWorkEvent(coordRoot, input.workId, {
34
+ event: "attempt.resumed",
35
+ actor: boundedActor(input.actor),
36
+ reason: "resuming the parked workflow attempt",
37
+ run_id: latest.run_id,
38
+ attempt: latest.number,
39
+ });
40
+ return await runWorkflow(record.intent.workflow.path, {
41
+ ...input.engine,
42
+ coordRoot,
43
+ resumeRunId: latest.run_id,
44
+ workItemId: input.workId,
45
+ });
46
+ }
47
+ if (record.projection.state === "blocked" && !input.retry) {
48
+ throw new Error(`work item ${input.workId} is blocked; use an explicit retry`);
49
+ }
50
+ if (!(record.projection.state === "ready" || record.projection.state === "blocked")) {
51
+ throw new Error(`work item ${input.workId} cannot run from state ${record.projection.state}`);
52
+ }
53
+ if (record.projection.attempts_used >= record.intent.max_attempts) {
54
+ throw new Error(
55
+ `work item ${input.workId} exhausted its ${record.intent.max_attempts} attempts`,
56
+ );
57
+ }
58
+ const attempt = record.projection.attempts_used + 1;
59
+ const runId = newWorkflowRunId();
60
+ appendWorkEvent(coordRoot, input.workId, {
61
+ event: "attempt.started",
62
+ actor: boundedActor(input.actor),
63
+ reason: input.retry ? "explicit retry started" : "workflow attempt started",
64
+ run_id: runId,
65
+ attempt,
66
+ });
67
+ return await runWorkflow(record.intent.workflow.path, {
68
+ ...input.engine,
69
+ coordRoot,
70
+ runId,
71
+ workItemId: input.workId,
72
+ });
73
+ } finally {
74
+ try {
75
+ const current = readWorkItemIgnoringLease(coordRoot, input.workId);
76
+ appendReconcileIfChanged(coordRoot, current, boundedActor(input.actor, "work-runner"));
77
+ } finally {
78
+ release();
79
+ }
80
+ }
81
+ }