@davidorex/pi-workflows 0.2.0 → 0.3.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 (215) hide show
  1. package/CHANGELOG.md +7 -4
  2. package/README.md +12 -2
  3. package/agents/architecture-designer.agent.yaml +58 -0
  4. package/agents/architecture-inferrer.agent.yaml +60 -0
  5. package/agents/gap-identifier.agent.yaml +66 -0
  6. package/agents/handoff-writer.agent.yaml +64 -0
  7. package/agents/plan-creator.agent.yaml +63 -0
  8. package/agents/project-definer.agent.yaml +53 -0
  9. package/agents/project-inferrer.agent.yaml +63 -0
  10. package/agents/requirements-gatherer.agent.yaml +58 -0
  11. package/dist/agent-spec.d.ts +27 -0
  12. package/dist/agent-spec.d.ts.map +1 -0
  13. package/dist/agent-spec.js +112 -0
  14. package/dist/agent-spec.js.map +1 -0
  15. package/dist/checkpoint.d.ts +50 -0
  16. package/dist/checkpoint.d.ts.map +1 -0
  17. package/dist/checkpoint.js +109 -0
  18. package/dist/checkpoint.js.map +1 -0
  19. package/dist/completion.d.ts +18 -0
  20. package/dist/completion.d.ts.map +1 -0
  21. package/dist/completion.js +58 -0
  22. package/dist/completion.js.map +1 -0
  23. package/dist/dag.d.ts +56 -0
  24. package/dist/dag.d.ts.map +1 -0
  25. package/dist/dag.js +172 -0
  26. package/dist/dag.js.map +1 -0
  27. package/dist/dispatch.d.ts +35 -0
  28. package/dist/dispatch.d.ts.map +1 -0
  29. package/dist/dispatch.js +311 -0
  30. package/dist/dispatch.js.map +1 -0
  31. package/dist/expression.d.ts +64 -0
  32. package/dist/expression.d.ts.map +1 -0
  33. package/dist/expression.js +294 -0
  34. package/dist/expression.js.map +1 -0
  35. package/dist/format.d.ts +19 -0
  36. package/dist/format.d.ts.map +1 -0
  37. package/dist/format.js +42 -0
  38. package/dist/format.js.map +1 -0
  39. package/dist/index.d.ts +8 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +675 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/output.d.ts +12 -0
  44. package/dist/output.d.ts.map +1 -0
  45. package/dist/output.js +59 -0
  46. package/dist/output.js.map +1 -0
  47. package/dist/state.d.ts +66 -0
  48. package/dist/state.d.ts.map +1 -0
  49. package/dist/state.js +227 -0
  50. package/dist/state.js.map +1 -0
  51. package/dist/step-agent.d.ts +35 -0
  52. package/dist/step-agent.d.ts.map +1 -0
  53. package/dist/step-agent.js +156 -0
  54. package/dist/step-agent.js.map +1 -0
  55. package/dist/step-command.d.ts +21 -0
  56. package/dist/step-command.d.ts.map +1 -0
  57. package/dist/step-command.js +150 -0
  58. package/dist/step-command.js.map +1 -0
  59. package/dist/step-foreach.d.ts +33 -0
  60. package/dist/step-foreach.d.ts.map +1 -0
  61. package/dist/step-foreach.js +112 -0
  62. package/dist/step-foreach.js.map +1 -0
  63. package/dist/step-gate.d.ts +18 -0
  64. package/dist/step-gate.d.ts.map +1 -0
  65. package/dist/step-gate.js +137 -0
  66. package/dist/step-gate.js.map +1 -0
  67. package/dist/step-loop.d.ts +32 -0
  68. package/dist/step-loop.d.ts.map +1 -0
  69. package/dist/step-loop.js +278 -0
  70. package/dist/step-loop.js.map +1 -0
  71. package/dist/step-monitor.d.ts +56 -0
  72. package/dist/step-monitor.d.ts.map +1 -0
  73. package/dist/step-monitor.js +317 -0
  74. package/dist/step-monitor.js.map +1 -0
  75. package/dist/step-parallel.d.ts +43 -0
  76. package/dist/step-parallel.d.ts.map +1 -0
  77. package/dist/step-parallel.js +122 -0
  78. package/dist/step-parallel.js.map +1 -0
  79. package/{src/step-pause.ts → dist/step-pause.d.ts} +3 -13
  80. package/dist/step-pause.d.ts.map +1 -0
  81. package/dist/step-pause.js +22 -0
  82. package/dist/step-pause.js.map +1 -0
  83. package/dist/step-shared.d.ts +57 -0
  84. package/dist/step-shared.d.ts.map +1 -0
  85. package/dist/step-shared.js +125 -0
  86. package/dist/step-shared.js.map +1 -0
  87. package/dist/step-transform.d.ts +11 -0
  88. package/dist/step-transform.d.ts.map +1 -0
  89. package/dist/step-transform.js +41 -0
  90. package/dist/step-transform.js.map +1 -0
  91. package/dist/template.d.ts +51 -0
  92. package/dist/template.d.ts.map +1 -0
  93. package/{src/template.ts → dist/template.js} +32 -38
  94. package/dist/template.js.map +1 -0
  95. package/dist/test-helpers.d.ts +17 -0
  96. package/dist/test-helpers.d.ts.map +1 -0
  97. package/dist/test-helpers.js +46 -0
  98. package/dist/test-helpers.js.map +1 -0
  99. package/dist/tui.d.ts +47 -0
  100. package/dist/tui.d.ts.map +1 -0
  101. package/dist/tui.js +143 -0
  102. package/dist/tui.js.map +1 -0
  103. package/dist/types.d.ts +164 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +3 -0
  106. package/dist/types.js.map +1 -0
  107. package/dist/workflow-discovery.d.ts +23 -0
  108. package/dist/workflow-discovery.d.ts.map +1 -0
  109. package/dist/workflow-discovery.js +103 -0
  110. package/dist/workflow-discovery.js.map +1 -0
  111. package/dist/workflow-executor.d.ts +50 -0
  112. package/dist/workflow-executor.d.ts.map +1 -0
  113. package/dist/workflow-executor.js +726 -0
  114. package/dist/workflow-executor.js.map +1 -0
  115. package/dist/workflow-sdk.d.ts +44 -0
  116. package/dist/workflow-sdk.d.ts.map +1 -0
  117. package/dist/workflow-sdk.js +438 -0
  118. package/dist/workflow-sdk.js.map +1 -0
  119. package/dist/workflow-spec.d.ts +33 -0
  120. package/dist/workflow-spec.d.ts.map +1 -0
  121. package/dist/workflow-spec.js +464 -0
  122. package/dist/workflow-spec.js.map +1 -0
  123. package/dist/workflows-dir.d.ts +3 -0
  124. package/dist/workflows-dir.d.ts.map +1 -0
  125. package/{src/workflows-dir.ts → dist/workflows-dir.js} +1 -0
  126. package/dist/workflows-dir.js.map +1 -0
  127. package/package.json +53 -38
  128. package/schemas/decomposition-specs.schema.json +48 -48
  129. package/schemas/execution-results.schema.json +48 -48
  130. package/schemas/investigation-findings.schema.json +43 -43
  131. package/schemas/pattern-analysis.schema.json +41 -41
  132. package/schemas/phase.schema.json +48 -0
  133. package/schemas/plan-breakdown.schema.json +20 -20
  134. package/schemas/quality-analysis.schema.json +33 -33
  135. package/schemas/research-findings.schema.json +42 -42
  136. package/schemas/structure-analysis.schema.json +40 -40
  137. package/schemas/synthesis.schema.json +31 -31
  138. package/schemas/verifier-output.schema.json +94 -94
  139. package/skill-narrative.md +84 -0
  140. package/skills/pi-workflows/SKILL.md +247 -0
  141. package/templates/architecture-designer/task.md +117 -0
  142. package/templates/architecture-inferrer/task.md +61 -0
  143. package/templates/gap-identifier/task.md +103 -0
  144. package/templates/handoff-writer/task.md +91 -0
  145. package/templates/plan-creator/task.md +143 -0
  146. package/templates/project-definer/task.md +67 -0
  147. package/templates/project-inferrer/task.md +56 -0
  148. package/templates/requirements-gatherer/task.md +90 -0
  149. package/workflows/analyze-existing-project.workflow.yaml +74 -0
  150. package/workflows/create-handoff.workflow.yaml +58 -0
  151. package/workflows/create-phase.workflow.yaml +1 -1
  152. package/workflows/do-gap.workflow.yaml +4 -4
  153. package/workflows/fix-audit.workflow.yaml +1 -1
  154. package/workflows/gap-to-phase.workflow.yaml +1 -1
  155. package/workflows/init-new-project.workflow.yaml +55 -0
  156. package/workflows/plan-from-requirements.workflow.yaml +51 -0
  157. package/workflows/self-implement.workflow.yaml +3 -3
  158. package/workflows/typed-analysis.workflow.yaml +4 -4
  159. package/src/agent-spec.test.ts +0 -289
  160. package/src/agent-spec.ts +0 -122
  161. package/src/block-validation.test.ts +0 -350
  162. package/src/checkpoint.test.ts +0 -237
  163. package/src/checkpoint.ts +0 -140
  164. package/src/completion.test.ts +0 -143
  165. package/src/completion.ts +0 -68
  166. package/src/dag.test.ts +0 -350
  167. package/src/dag.ts +0 -219
  168. package/src/dispatch.test.ts +0 -475
  169. package/src/dispatch.ts +0 -353
  170. package/src/expression.test.ts +0 -353
  171. package/src/expression.ts +0 -332
  172. package/src/format.test.ts +0 -80
  173. package/src/format.ts +0 -41
  174. package/src/graduated-failure.test.ts +0 -556
  175. package/src/index.test.ts +0 -114
  176. package/src/index.ts +0 -516
  177. package/src/loop.test.ts +0 -551
  178. package/src/output.test.ts +0 -213
  179. package/src/output.ts +0 -70
  180. package/src/parallel-integration.test.ts +0 -175
  181. package/src/resume.test.ts +0 -192
  182. package/src/state.test.ts +0 -192
  183. package/src/state.ts +0 -254
  184. package/src/step-agent.test.ts +0 -327
  185. package/src/step-agent.ts +0 -178
  186. package/src/step-command.test.ts +0 -330
  187. package/src/step-command.ts +0 -132
  188. package/src/step-foreach.test.ts +0 -647
  189. package/src/step-foreach.ts +0 -148
  190. package/src/step-gate.test.ts +0 -185
  191. package/src/step-gate.ts +0 -116
  192. package/src/step-loop.test.ts +0 -626
  193. package/src/step-loop.ts +0 -323
  194. package/src/step-parallel.test.ts +0 -475
  195. package/src/step-parallel.ts +0 -168
  196. package/src/step-pause.test.ts +0 -30
  197. package/src/step-shared.test.ts +0 -355
  198. package/src/step-shared.ts +0 -157
  199. package/src/step-transform.test.ts +0 -155
  200. package/src/step-transform.ts +0 -47
  201. package/src/template-integration.test.ts +0 -72
  202. package/src/template.test.ts +0 -162
  203. package/src/test-helpers.ts +0 -51
  204. package/src/tui.test.ts +0 -355
  205. package/src/tui.ts +0 -182
  206. package/src/types.ts +0 -195
  207. package/src/verifier-schema.test.ts +0 -226
  208. package/src/workflow-discovery.test.ts +0 -105
  209. package/src/workflow-discovery.ts +0 -114
  210. package/src/workflow-executor.test.ts +0 -1532
  211. package/src/workflow-executor.ts +0 -810
  212. package/src/workflow-sdk.test.ts +0 -238
  213. package/src/workflow-sdk.ts +0 -262
  214. package/src/workflow-spec.test.ts +0 -576
  215. package/src/workflow-spec.ts +0 -471
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Agent spec loading — YAML specs are the source of truth.
3
+ *
4
+ * Agent specs are declarative YAML files that define typed functions:
5
+ * InputSchema → OutputSchema, with template references for prompt
6
+ * composition. The .md that pi consumes is compiled at dispatch time
7
+ * from spec + templates + typed input. It exists in memory only.
8
+ *
9
+ * Search order (first match wins):
10
+ * 1. .pi/agents/<name>.agent.yaml (project)
11
+ * 2. ~/.pi/agent/agents/<name>.agent.yaml (user)
12
+ * 3. <package>/agents/<name>.agent.yaml (builtin)
13
+ */
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ /** Check if a prompt.system value looks like a template file path vs inline text. */
17
+ function isTemplatePath(value) {
18
+ if (!value)
19
+ return false;
20
+ return value.endsWith(".md") || value.endsWith(".txt") || (value.includes("/") && !value.includes("\n"));
21
+ }
22
+ import os from "node:os";
23
+ import { parse as parseYaml } from "yaml";
24
+ /**
25
+ * Thrown when an agent spec file is not found in any search path.
26
+ */
27
+ export class AgentNotFoundError extends Error {
28
+ agentName;
29
+ searchPaths;
30
+ constructor(agentName, searchPaths) {
31
+ const pathList = searchPaths.map((p) => ` - ${p}`).join("\n");
32
+ super(`Agent '${agentName}' not found. Searched:\n${pathList}`);
33
+ this.name = "AgentNotFoundError";
34
+ this.agentName = agentName;
35
+ this.searchPaths = searchPaths;
36
+ }
37
+ }
38
+ /**
39
+ * Thrown when an agent spec file exists but cannot be read or parsed.
40
+ */
41
+ export class AgentParseError extends Error {
42
+ agentName;
43
+ filePath;
44
+ cause;
45
+ constructor(agentName, filePath, cause) {
46
+ super(`Agent '${agentName}' at ${filePath}: ${cause.message}`);
47
+ this.name = "AgentParseError";
48
+ this.agentName = agentName;
49
+ this.filePath = filePath;
50
+ this.cause = cause;
51
+ }
52
+ }
53
+ /**
54
+ * Parse a YAML agent spec file into an AgentSpec.
55
+ */
56
+ export function parseAgentYaml(filePath) {
57
+ const name = path.basename(filePath, ".agent.yaml");
58
+ let content;
59
+ try {
60
+ content = fs.readFileSync(filePath, "utf-8");
61
+ }
62
+ catch (err) {
63
+ throw new AgentParseError(name, filePath, err instanceof Error ? err : new Error(String(err)));
64
+ }
65
+ let spec;
66
+ try {
67
+ spec = parseYaml(content);
68
+ }
69
+ catch (err) {
70
+ throw new AgentParseError(name, filePath, err instanceof Error ? err : new Error(String(err)));
71
+ }
72
+ // Handle null/undefined from parsing empty file or non-mapping YAML
73
+ if (!spec || typeof spec !== "object") {
74
+ throw new AgentParseError(name, filePath, new Error("File is empty or does not contain a YAML mapping"));
75
+ }
76
+ return {
77
+ name: spec.name || name,
78
+ description: spec.description,
79
+ role: spec.role,
80
+ model: spec.model,
81
+ thinking: spec.thinking,
82
+ tools: spec.tools,
83
+ extensions: spec.extensions,
84
+ skills: spec.skills,
85
+ output: spec.output?.file,
86
+ promptTemplate: isTemplatePath(spec.prompt?.system) ? spec.prompt?.system : undefined,
87
+ systemPrompt: isTemplatePath(spec.prompt?.system) ? undefined : spec.prompt?.system,
88
+ taskTemplate: spec.prompt?.task,
89
+ inputSchema: spec.input,
90
+ outputFormat: spec.output?.format,
91
+ outputSchema: spec.output?.schema,
92
+ };
93
+ }
94
+ /**
95
+ * Create an agent loader that finds .agent.yaml specs.
96
+ */
97
+ export function createAgentLoader(cwd, builtinDir) {
98
+ const defaultBuiltinDir = builtinDir ?? path.resolve(import.meta.dirname, "..", "agents");
99
+ return (name) => {
100
+ const searchPaths = [
101
+ path.join(cwd, ".pi", "agents", `${name}.agent.yaml`),
102
+ path.join(os.homedir(), ".pi", "agent", "agents", `${name}.agent.yaml`),
103
+ path.join(defaultBuiltinDir, `${name}.agent.yaml`),
104
+ ];
105
+ for (const p of searchPaths) {
106
+ if (fs.existsSync(p))
107
+ return parseAgentYaml(p);
108
+ }
109
+ throw new AgentNotFoundError(name, searchPaths);
110
+ };
111
+ }
112
+ //# sourceMappingURL=agent-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-spec.js","sourceRoot":"","sources":["../src/agent-spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { ExecutionState, WorkflowSpec } from "./types.js";
2
+ export interface IncompleteRun {
3
+ runId: string;
4
+ runDir: string;
5
+ state: ExecutionState;
6
+ completedSteps: string[];
7
+ failedStep?: string;
8
+ updatedAt?: string;
9
+ }
10
+ /**
11
+ * Find the most recent incomplete run for a workflow.
12
+ *
13
+ * Scans .workflows/runs/<name>/runs/ for state.json files
14
+ * with status "running" or "failed". Returns the most recent one
15
+ * (by directory name, which encodes timestamp).
16
+ *
17
+ * Returns null if no incomplete runs exist.
18
+ */
19
+ export declare function findIncompleteRun(cwd: string, workflowName: string): IncompleteRun | null;
20
+ /**
21
+ * Validate that a saved state is compatible with the current workflow spec.
22
+ *
23
+ * Checks:
24
+ * 1. Spec version matches (if both specify one)
25
+ * 2. All completed steps still exist in the spec
26
+ *
27
+ * Returns null if compatible, or a string describing the incompatibility.
28
+ */
29
+ export declare function validateResumeCompatibility(state: ExecutionState, spec: WorkflowSpec): string | null;
30
+ /**
31
+ * Determine which steps need to run when resuming.
32
+ *
33
+ * Given the execution plan (layers of step names) and the set of
34
+ * already-completed steps, returns the layer index to resume from
35
+ * and which steps within that layer still need to run.
36
+ *
37
+ * For a partially-complete parallel layer (some steps done, some not),
38
+ * returns only the incomplete steps from that layer.
39
+ */
40
+ export declare function computeResumePoint(plan: Array<{
41
+ steps: string[];
42
+ }>, completedSteps: Set<string>): {
43
+ resumeLayerIndex: number;
44
+ pendingStepsInLayer: string[];
45
+ } | null;
46
+ /**
47
+ * Format a human-readable summary of an incomplete run for display.
48
+ */
49
+ export declare function formatIncompleteRun(run: IncompleteRun, spec: WorkflowSpec): string;
50
+ //# sourceMappingURL=checkpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../src/checkpoint.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/D,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAqCzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAepG;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,EAChC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GACzB;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAYpE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAQlF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Checkpoint and resume logic for workflow runs.
3
+ *
4
+ * Finds incomplete runs, validates they match the current spec,
5
+ * and provides state needed to resume execution.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { readState } from "./state.js";
10
+ import { WORKFLOWS_DIR } from "./workflows-dir.js";
11
+ /**
12
+ * Find the most recent incomplete run for a workflow.
13
+ *
14
+ * Scans .workflows/runs/<name>/runs/ for state.json files
15
+ * with status "running" or "failed". Returns the most recent one
16
+ * (by directory name, which encodes timestamp).
17
+ *
18
+ * Returns null if no incomplete runs exist.
19
+ */
20
+ export function findIncompleteRun(cwd, workflowName) {
21
+ const runsDir = path.join(cwd, WORKFLOWS_DIR, "runs", workflowName, "runs");
22
+ if (!fs.existsSync(runsDir))
23
+ return null;
24
+ const entries = fs
25
+ .readdirSync(runsDir)
26
+ .filter((e) => {
27
+ const stat = fs.statSync(path.join(runsDir, e));
28
+ return stat.isDirectory();
29
+ })
30
+ .sort() // lexicographic — timestamp-based IDs sort chronologically
31
+ .reverse(); // most recent first
32
+ for (const runId of entries) {
33
+ const runDir = path.join(runsDir, runId);
34
+ const state = readState(runDir);
35
+ if (!state)
36
+ continue;
37
+ if (state.status === "running" || state.status === "failed" || state.status === "paused") {
38
+ const completedSteps = Object.entries(state.steps)
39
+ .filter(([, r]) => r.status === "completed" || r.status === "skipped")
40
+ .map(([name]) => name);
41
+ const failedStep = Object.entries(state.steps).find(([, r]) => r.status === "failed")?.[0];
42
+ return {
43
+ runId,
44
+ runDir,
45
+ state,
46
+ completedSteps,
47
+ failedStep,
48
+ updatedAt: state.updatedAt,
49
+ };
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * Validate that a saved state is compatible with the current workflow spec.
56
+ *
57
+ * Checks:
58
+ * 1. Spec version matches (if both specify one)
59
+ * 2. All completed steps still exist in the spec
60
+ *
61
+ * Returns null if compatible, or a string describing the incompatibility.
62
+ */
63
+ export function validateResumeCompatibility(state, spec) {
64
+ // Check version match
65
+ if (state.specVersion && spec.version && state.specVersion !== spec.version) {
66
+ return `Spec version changed: run has '${state.specVersion}', current is '${spec.version}'`;
67
+ }
68
+ // Check all completed steps still exist in spec
69
+ const specStepNames = new Set(Object.keys(spec.steps));
70
+ for (const stepName of Object.keys(state.steps)) {
71
+ if (!specStepNames.has(stepName)) {
72
+ return `Step '${stepName}' was completed in the saved run but no longer exists in the workflow spec`;
73
+ }
74
+ }
75
+ return null; // compatible
76
+ }
77
+ /**
78
+ * Determine which steps need to run when resuming.
79
+ *
80
+ * Given the execution plan (layers of step names) and the set of
81
+ * already-completed steps, returns the layer index to resume from
82
+ * and which steps within that layer still need to run.
83
+ *
84
+ * For a partially-complete parallel layer (some steps done, some not),
85
+ * returns only the incomplete steps from that layer.
86
+ */
87
+ export function computeResumePoint(plan, completedSteps) {
88
+ for (let i = 0; i < plan.length; i++) {
89
+ const layer = plan[i];
90
+ const pending = layer.steps.filter((s) => !completedSteps.has(s));
91
+ if (pending.length > 0) {
92
+ return { resumeLayerIndex: i, pendingStepsInLayer: pending };
93
+ }
94
+ }
95
+ // All steps completed — nothing to resume
96
+ return null;
97
+ }
98
+ /**
99
+ * Format a human-readable summary of an incomplete run for display.
100
+ */
101
+ export function formatIncompleteRun(run, spec) {
102
+ const totalSteps = Object.keys(spec.steps).length;
103
+ const completed = run.completedSteps.length;
104
+ const status = run.state.status === "paused" ? "paused" : run.state.status === "running" ? "interrupted" : "failed";
105
+ const failedInfo = run.failedStep ? ` at step '${run.failedStep}'` : "";
106
+ const timeInfo = run.updatedAt ? ` (last updated: ${run.updatedAt})` : "";
107
+ return `Found ${status} run${failedInfo}: ${completed}/${totalSteps} steps completed${timeInfo}. Run ID: ${run.runId}`;
108
+ }
109
+ //# sourceMappingURL=checkpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../src/checkpoint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { CompletionSpec, WorkflowResult } from "./types.js";
2
+ /**
3
+ * Resolve a completion spec into the final message string injected into
4
+ * the main LLM conversation after workflow execution.
5
+ *
6
+ * Two forms:
7
+ * - Template: the template string is resolved with ${{ }} expressions
8
+ * and returned as the full content.
9
+ * - Message + include: the message is resolved, then each include path
10
+ * is resolved and appended as structured data.
11
+ *
12
+ * @param spec - the CompletionSpec from the workflow YAML
13
+ * @param result - the completed WorkflowResult
14
+ * @param executionInput - the original workflow input
15
+ * @returns the resolved message string
16
+ */
17
+ export declare function resolveCompletion(spec: CompletionSpec, result: WorkflowResult, executionInput: unknown): string;
18
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CA6C/G"}
@@ -0,0 +1,58 @@
1
+ import { resolveExpression, resolveExpressions } from "./expression.js";
2
+ /**
3
+ * Resolve a completion spec into the final message string injected into
4
+ * the main LLM conversation after workflow execution.
5
+ *
6
+ * Two forms:
7
+ * - Template: the template string is resolved with ${{ }} expressions
8
+ * and returned as the full content.
9
+ * - Message + include: the message is resolved, then each include path
10
+ * is resolved and appended as structured data.
11
+ *
12
+ * @param spec - the CompletionSpec from the workflow YAML
13
+ * @param result - the completed WorkflowResult
14
+ * @param executionInput - the original workflow input
15
+ * @returns the resolved message string
16
+ */
17
+ export function resolveCompletion(spec, result, executionInput) {
18
+ const scope = {
19
+ input: executionInput,
20
+ steps: result.steps,
21
+ totalUsage: result.totalUsage,
22
+ totalDurationMs: result.totalDurationMs,
23
+ runDir: result.runDir,
24
+ runId: result.runId,
25
+ workflow: result.workflow,
26
+ status: result.status,
27
+ output: result.output,
28
+ };
29
+ if (spec.template) {
30
+ const resolved = resolveExpressions(spec.template, scope);
31
+ return String(resolved ?? "");
32
+ }
33
+ // Message form
34
+ const parts = [];
35
+ if (spec.message) {
36
+ const resolvedMessage = resolveExpressions(spec.message, scope);
37
+ parts.push(String(resolvedMessage ?? ""));
38
+ }
39
+ if (spec.include && spec.include.length > 0) {
40
+ const included = {};
41
+ for (const path of spec.include) {
42
+ const value = resolveExpression(path, scope);
43
+ included[path] = value;
44
+ }
45
+ parts.push("");
46
+ parts.push("---");
47
+ for (const [path, value] of Object.entries(included)) {
48
+ if (value !== null && typeof value === "object") {
49
+ parts.push(`\n### ${path}\n\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``);
50
+ }
51
+ else {
52
+ parts.push(`\n### ${path}\n${String(value ?? "")}`);
53
+ }
54
+ }
55
+ }
56
+ return parts.join("\n");
57
+ }
58
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGxE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAoB,EAAE,MAAsB,EAAE,cAAuB;IACtG,MAAM,KAAK,GAAoB;QAC9B,KAAK,EAAE,cAAc;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAgC;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM;KACrB,CAAC;IAEF,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC1D,OAAO,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,eAAe;IACf,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAA4B,EAAE,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7C,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACxB,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACjD,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,iBAAiB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;YACpF,CAAC;iBAAM,CAAC;gBACP,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACrD,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
package/dist/dag.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * DAG dependency analysis and execution planning for workflow steps.
3
+ * Extracts `${{ steps.X }}` references, builds a dependency graph,
4
+ * and produces layered execution plans for parallel dispatch.
5
+ */
6
+ import type { WorkflowSpec } from "./types.js";
7
+ /**
8
+ * A single layer in the execution plan.
9
+ * All steps in a layer are independent and can run concurrently.
10
+ */
11
+ export interface ExecutionLayer {
12
+ steps: string[];
13
+ }
14
+ /**
15
+ * The full execution plan: an ordered list of layers.
16
+ * Steps in the same layer have no mutual dependencies.
17
+ * Steps in layer N depend only on steps in layers 0..N-1.
18
+ */
19
+ export type ExecutionPlan = ExecutionLayer[];
20
+ /**
21
+ * Extract all step dependencies from a workflow spec.
22
+ *
23
+ * Scans all expression-bearing fields in each step:
24
+ * - `input` values (recursive — expressions can be nested in objects/arrays)
25
+ * - `when` condition
26
+ * - `gate.check` (may contain ${{ }})
27
+ * - `transform.mapping` values (recursive)
28
+ * - `loop.attempts` (may be an expression)
29
+ *
30
+ * Does NOT descend into loop sub-steps — a loop step's internal steps
31
+ * are the loop's own concern, not part of the top-level DAG.
32
+ *
33
+ * Returns a map: stepName → Set of step names it depends on.
34
+ */
35
+ export declare function extractDependencies(spec: WorkflowSpec): Map<string, Set<string>>;
36
+ /**
37
+ * Build an execution plan from a pre-computed dependency map.
38
+ * Performs topological sort, grouping independent steps into layers.
39
+ * Throws if the dependency graph contains a cycle.
40
+ */
41
+ export declare function buildPlanFromDeps(allSteps: string[], deps: Map<string, Set<string>>): ExecutionPlan;
42
+ /**
43
+ * Build an execution plan from a workflow spec.
44
+ *
45
+ * Performs topological sort, grouping independent steps into layers.
46
+ * Steps within a layer can execute concurrently.
47
+ *
48
+ * Throws if the dependency graph contains a cycle.
49
+ */
50
+ export declare function buildExecutionPlan(spec: WorkflowSpec): ExecutionPlan;
51
+ /**
52
+ * Check if an execution plan is fully sequential
53
+ * (every layer has exactly one step).
54
+ */
55
+ export declare function isSequential(plan: ExecutionPlan): boolean;
56
+ //# sourceMappingURL=dag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dag.d.ts","sourceRoot":"","sources":["../src/dag.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAY,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAyBhF;AAkGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,aAAa,CA4BnG;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAGpE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAEzD"}
package/dist/dag.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Extract all step dependencies from a workflow spec.
3
+ *
4
+ * Scans all expression-bearing fields in each step:
5
+ * - `input` values (recursive — expressions can be nested in objects/arrays)
6
+ * - `when` condition
7
+ * - `gate.check` (may contain ${{ }})
8
+ * - `transform.mapping` values (recursive)
9
+ * - `loop.attempts` (may be an expression)
10
+ *
11
+ * Does NOT descend into loop sub-steps — a loop step's internal steps
12
+ * are the loop's own concern, not part of the top-level DAG.
13
+ *
14
+ * Returns a map: stepName → Set of step names it depends on.
15
+ */
16
+ export function extractDependencies(spec) {
17
+ const stepNames = new Set(Object.keys(spec.steps));
18
+ const deps = new Map();
19
+ for (const [name, step] of Object.entries(spec.steps)) {
20
+ const stepDeps = new Set();
21
+ // Collect all expression strings from this step
22
+ const expressions = collectExpressions(step);
23
+ // Parse each expression for `steps.<name>` references
24
+ for (const expr of expressions) {
25
+ const referenced = extractStepReferences(expr, stepNames);
26
+ for (const ref of referenced) {
27
+ if (ref !== name) {
28
+ // no self-dependencies
29
+ stepDeps.add(ref);
30
+ }
31
+ }
32
+ }
33
+ deps.set(name, stepDeps);
34
+ }
35
+ return deps;
36
+ }
37
+ /**
38
+ * Collect all raw expression strings from a step spec.
39
+ * Walks `input`, `when`, `gate.check`, `transform.mapping`, `loop.attempts`.
40
+ */
41
+ function collectExpressions(step) {
42
+ const exprs = [];
43
+ // input values (recursive)
44
+ if (step.input) {
45
+ collectExpressionsFromValue(step.input, exprs);
46
+ }
47
+ // when condition
48
+ if (step.when) {
49
+ exprs.push(step.when);
50
+ }
51
+ // gate check
52
+ if (step.gate) {
53
+ collectExpressionsFromValue(step.gate.check, exprs);
54
+ }
55
+ // transform mapping (recursive)
56
+ if (step.transform) {
57
+ collectExpressionsFromValue(step.transform.mapping, exprs);
58
+ }
59
+ // loop attempts expression
60
+ if (step.loop?.attempts) {
61
+ exprs.push(step.loop.attempts);
62
+ }
63
+ // forEach expression
64
+ if (step.forEach) {
65
+ collectExpressionsFromValue(step.forEach, exprs);
66
+ }
67
+ // command expression (may contain ${{ }} references)
68
+ if (step.command) {
69
+ collectExpressionsFromValue(step.command, exprs);
70
+ }
71
+ return exprs;
72
+ }
73
+ /**
74
+ * Recursively collect expression strings from a value.
75
+ * Walks objects, arrays, and strings looking for ${{ }} patterns.
76
+ */
77
+ function collectExpressionsFromValue(value, exprs) {
78
+ if (typeof value === "string") {
79
+ // Extract all ${{ ... }} patterns from the string
80
+ const regex = /\$\{\{([^}]+)\}\}/g;
81
+ let match;
82
+ while ((match = regex.exec(value)) !== null) {
83
+ exprs.push(match[1].trim());
84
+ }
85
+ // Also handle bare expressions (no ${{ }} wrapper, e.g. in `when`)
86
+ if (!value.includes("${{") && value.includes("steps.")) {
87
+ exprs.push(value);
88
+ }
89
+ }
90
+ else if (Array.isArray(value)) {
91
+ for (const item of value) {
92
+ collectExpressionsFromValue(item, exprs);
93
+ }
94
+ }
95
+ else if (value !== null && typeof value === "object") {
96
+ for (const v of Object.values(value)) {
97
+ collectExpressionsFromValue(v, exprs);
98
+ }
99
+ }
100
+ }
101
+ /**
102
+ * Extract step name references from an expression string.
103
+ *
104
+ * Looks for patterns like:
105
+ * - `steps.diagnose.output`
106
+ * - `steps.diagnose.textOutput`
107
+ * - `steps.diagnose.status`
108
+ *
109
+ * Returns the set of step names referenced.
110
+ */
111
+ function extractStepReferences(expr, validStepNames) {
112
+ const refs = new Set();
113
+ // Match `steps.<name>` — name is a word (alphanumeric + underscore + hyphen)
114
+ const regex = /steps\.([a-zA-Z_][\w-]*)/g;
115
+ let match;
116
+ while ((match = regex.exec(expr)) !== null) {
117
+ const name = match[1];
118
+ if (validStepNames.has(name)) {
119
+ refs.add(name);
120
+ }
121
+ }
122
+ return refs;
123
+ }
124
+ /**
125
+ * Build an execution plan from a pre-computed dependency map.
126
+ * Performs topological sort, grouping independent steps into layers.
127
+ * Throws if the dependency graph contains a cycle.
128
+ */
129
+ export function buildPlanFromDeps(allSteps, deps) {
130
+ const plan = [];
131
+ const placed = new Set();
132
+ while (placed.size < allSteps.length) {
133
+ const layer = [];
134
+ for (const step of allSteps) {
135
+ if (placed.has(step))
136
+ continue;
137
+ const stepDeps = deps.get(step) ?? new Set();
138
+ if ([...stepDeps].every((d) => placed.has(d))) {
139
+ layer.push(step);
140
+ }
141
+ }
142
+ if (layer.length === 0) {
143
+ const remaining = allSteps.filter((s) => !placed.has(s));
144
+ throw new Error(`Dependency cycle detected among steps: ${remaining.join(", ")}`);
145
+ }
146
+ plan.push({ steps: layer });
147
+ for (const s of layer) {
148
+ placed.add(s);
149
+ }
150
+ }
151
+ return plan;
152
+ }
153
+ /**
154
+ * Build an execution plan from a workflow spec.
155
+ *
156
+ * Performs topological sort, grouping independent steps into layers.
157
+ * Steps within a layer can execute concurrently.
158
+ *
159
+ * Throws if the dependency graph contains a cycle.
160
+ */
161
+ export function buildExecutionPlan(spec) {
162
+ const deps = extractDependencies(spec);
163
+ return buildPlanFromDeps(Object.keys(spec.steps), deps);
164
+ }
165
+ /**
166
+ * Check if an execution plan is fully sequential
167
+ * (every layer has exactly one step).
168
+ */
169
+ export function isSequential(plan) {
170
+ return plan.every((layer) => layer.steps.length === 1);
171
+ }
172
+ //# sourceMappingURL=dag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dag.js","sourceRoot":"","sources":["../src/dag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { AgentSpec, StepResult, StepSpec, StepUsage } from "./types.js";
2
+ export interface ModelConfig {
3
+ default?: string;
4
+ by_role?: Record<string, string>;
5
+ }
6
+ export interface DispatchOptions {
7
+ cwd: string;
8
+ sessionLogDir: string;
9
+ stepName: string;
10
+ signal?: AbortSignal;
11
+ timeoutMs?: number;
12
+ onEvent?: (event: ProcessEvent) => void;
13
+ modelConfig?: ModelConfig;
14
+ }
15
+ export interface ProcessEvent {
16
+ type: string;
17
+ raw: unknown;
18
+ toolName?: string;
19
+ toolArgs?: string;
20
+ messageText?: string;
21
+ usage?: Partial<StepUsage>;
22
+ }
23
+ export declare function extractText(content: unknown): string;
24
+ export declare function extractToolArgsPreview(args: unknown): string;
25
+ export declare function buildArgs(step: StepSpec, agentSpec: AgentSpec, prompt: string, options: DispatchOptions): string[];
26
+ /**
27
+ * Spawn a pi subprocess for a workflow step and collect the result.
28
+ *
29
+ * Builds CLI args from the step spec and agent spec.
30
+ * Streams stdout as newline-delimited JSON.
31
+ * Collects messages, usage, timing.
32
+ * Returns StepResult when the process exits.
33
+ */
34
+ export declare function dispatch(step: StepSpec, agentSpec: AgentSpec, prompt: string, options: DispatchOptions): Promise<StepResult>;
35
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IAEb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC3B;AAaD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQpD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAU5D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CAqDlH;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC7B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,UAAU,CAAC,CA6NrB"}