@davidorex/pi-workflows 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) 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 +178 -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 +724 -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 +171 -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 +63 -0
  84. package/dist/step-shared.d.ts.map +1 -0
  85. package/dist/step-shared.js +136 -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 +165 -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 +738 -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 +457 -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 +476 -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 +107 -0
  140. package/skills/pi-workflows/SKILL.md +185 -0
  141. package/skills/pi-workflows/references/bundled-resources.md +87 -0
  142. package/templates/architecture-designer/task.md +117 -0
  143. package/templates/architecture-inferrer/task.md +61 -0
  144. package/templates/gap-identifier/task.md +103 -0
  145. package/templates/handoff-writer/task.md +91 -0
  146. package/templates/plan-creator/task.md +143 -0
  147. package/templates/project-definer/task.md +67 -0
  148. package/templates/project-inferrer/task.md +56 -0
  149. package/templates/requirements-gatherer/task.md +90 -0
  150. package/workflows/analyze-existing-project.workflow.yaml +94 -0
  151. package/workflows/create-handoff.workflow.yaml +66 -0
  152. package/workflows/create-phase.workflow.yaml +1 -1
  153. package/workflows/do-gap.workflow.yaml +4 -4
  154. package/workflows/fix-audit.workflow.yaml +1 -1
  155. package/workflows/gap-to-phase.workflow.yaml +1 -1
  156. package/workflows/init-new-project.workflow.yaml +81 -0
  157. package/workflows/plan-from-requirements.workflow.yaml +59 -0
  158. package/workflows/self-implement.workflow.yaml +3 -3
  159. package/workflows/typed-analysis.workflow.yaml +4 -4
  160. package/src/agent-spec.test.ts +0 -289
  161. package/src/agent-spec.ts +0 -122
  162. package/src/block-validation.test.ts +0 -350
  163. package/src/checkpoint.test.ts +0 -237
  164. package/src/checkpoint.ts +0 -140
  165. package/src/completion.test.ts +0 -143
  166. package/src/completion.ts +0 -68
  167. package/src/dag.test.ts +0 -350
  168. package/src/dag.ts +0 -219
  169. package/src/dispatch.test.ts +0 -475
  170. package/src/dispatch.ts +0 -353
  171. package/src/expression.test.ts +0 -353
  172. package/src/expression.ts +0 -332
  173. package/src/format.test.ts +0 -80
  174. package/src/format.ts +0 -41
  175. package/src/graduated-failure.test.ts +0 -556
  176. package/src/index.test.ts +0 -114
  177. package/src/index.ts +0 -516
  178. package/src/loop.test.ts +0 -551
  179. package/src/output.test.ts +0 -213
  180. package/src/output.ts +0 -70
  181. package/src/parallel-integration.test.ts +0 -175
  182. package/src/resume.test.ts +0 -192
  183. package/src/state.test.ts +0 -192
  184. package/src/state.ts +0 -254
  185. package/src/step-agent.test.ts +0 -327
  186. package/src/step-agent.ts +0 -178
  187. package/src/step-command.test.ts +0 -330
  188. package/src/step-command.ts +0 -132
  189. package/src/step-foreach.test.ts +0 -647
  190. package/src/step-foreach.ts +0 -148
  191. package/src/step-gate.test.ts +0 -185
  192. package/src/step-gate.ts +0 -116
  193. package/src/step-loop.test.ts +0 -626
  194. package/src/step-loop.ts +0 -323
  195. package/src/step-parallel.test.ts +0 -475
  196. package/src/step-parallel.ts +0 -168
  197. package/src/step-pause.test.ts +0 -30
  198. package/src/step-shared.test.ts +0 -355
  199. package/src/step-shared.ts +0 -157
  200. package/src/step-transform.test.ts +0 -155
  201. package/src/step-transform.ts +0 -47
  202. package/src/template-integration.test.ts +0 -72
  203. package/src/template.test.ts +0 -162
  204. package/src/test-helpers.ts +0 -51
  205. package/src/tui.test.ts +0 -355
  206. package/src/tui.ts +0 -182
  207. package/src/types.ts +0 -195
  208. package/src/verifier-schema.test.ts +0 -226
  209. package/src/workflow-discovery.test.ts +0 -105
  210. package/src/workflow-discovery.ts +0 -114
  211. package/src/workflow-executor.test.ts +0 -1532
  212. package/src/workflow-executor.ts +0 -810
  213. package/src/workflow-sdk.test.ts +0 -238
  214. package/src/workflow-sdk.ts +0 -262
  215. package/src/workflow-spec.test.ts +0 -576
  216. package/src/workflow-spec.ts +0 -471
package/src/step-loop.ts DELETED
@@ -1,323 +0,0 @@
1
- /**
2
- * Loop step executor — runs sub-steps repeatedly until a gate breaks,
3
- * max attempts is reached, or a step fails.
4
- */
5
- import path from "node:path";
6
- import type { LoopSpec, StepResult, StepUsage, ExecutionState, AgentSpec, StepSpec, WorkflowSpec, LoopAttempt } from "./types.ts";
7
- import { resolveExpressions, evaluateCondition } from "./expression.ts";
8
- import { executeGate } from "./step-gate.ts";
9
- import { executeTransform } from "./step-transform.ts";
10
- import { zeroUsage, addUsage, buildPrompt, DEFAULT_MAX_ATTEMPTS, compileAgentSpec } from "./step-shared.ts";
11
- import { persistStepOutput } from "./output.ts";
12
- import type nunjucks from "nunjucks";
13
-
14
- /** Options for executeLoop, including callback-injected dispatch to avoid circular imports. */
15
- export interface LoopExecuteOptions {
16
- ctx: any;
17
- pi: any;
18
- signal?: AbortSignal;
19
- loadAgent: (name: string) => AgentSpec;
20
- dispatchAgent: (
21
- stepSpec: StepSpec,
22
- agentSpec: AgentSpec,
23
- prompt: string,
24
- opts: { cwd: string; sessionLogDir: string; stepName: string; signal?: AbortSignal },
25
- ) => Promise<StepResult>;
26
- runDir: string;
27
- spec: WorkflowSpec;
28
- templateEnv?: nunjucks.Environment;
29
- outputPath?: string; // author-declared output path (resolved ${{ }} expressions)
30
- }
31
-
32
- /**
33
- * Execute a loop step: runs sub-steps repeatedly until a gate breaks,
34
- * max attempts is reached, or a step fails.
35
- *
36
- * Loop sub-steps can be agent, gate, or transform steps.
37
- * Gates inside loops support onPass: "break" (stop looping on success)
38
- * and onFail: "continue" (retry on failure, the default inside loops).
39
- *
40
- * The loop scope provides ${{ loop.iteration }}, ${{ loop.maxAttempts }},
41
- * and ${{ loop.priorAttempts }} for expression resolution inside sub-steps.
42
- */
43
- export async function executeLoop(
44
- loopSpec: LoopSpec,
45
- stepName: string,
46
- state: ExecutionState,
47
- options: LoopExecuteOptions,
48
- ): Promise<StepResult> {
49
- const { ctx, signal, loadAgent, dispatchAgent, runDir } = options;
50
- const startTime = Date.now();
51
-
52
- // Resolve maxAttempts (may be a ${{ }} expression)
53
- const scope = { input: state.input, steps: state.steps };
54
- let maxAttempts: number;
55
- if (loopSpec.attempts) {
56
- const resolved = resolveExpressions(loopSpec.attempts, scope);
57
- maxAttempts = Number(resolved);
58
- if (isNaN(maxAttempts) || maxAttempts < 1) maxAttempts = loopSpec.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
59
- } else {
60
- maxAttempts = loopSpec.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
61
- }
62
-
63
- const allAttempts: LoopAttempt[] = [];
64
- let loopStatus: "completed" | "failed" = "failed"; // assume failure until break
65
- let lastIterationSteps: Record<string, StepResult> = {};
66
-
67
- for (let iteration = 0; iteration < maxAttempts; iteration++) {
68
- // Check cancellation
69
- if (signal?.aborted) break;
70
-
71
- const iterationSteps: Record<string, StepResult> = {};
72
- let shouldBreak = false;
73
- let iterationFailed = false;
74
-
75
- // Execute sub-steps sequentially
76
- const subStepEntries = Object.entries(loopSpec.steps);
77
- for (const [subName, subSpec] of subStepEntries) {
78
- if (signal?.aborted) break;
79
-
80
- // Build scope with loop context
81
- const subScope: Record<string, unknown> = {
82
- input: state.input,
83
- steps: { ...state.steps, ...iterationSteps }, // see prior sub-steps in this iteration
84
- loop: {
85
- iteration,
86
- maxAttempts,
87
- priorAttempts: allAttempts,
88
- },
89
- };
90
-
91
- // Handle `when` conditional
92
- if (subSpec.when) {
93
- const condExpr = subSpec.when.replace(/^\$\{\{\s*/, "").replace(/\s*\}\}$/, "");
94
- if (!evaluateCondition(condExpr, subScope)) {
95
- iterationSteps[subName] = {
96
- step: subName,
97
- agent: subSpec.agent ?? "skipped",
98
- status: "skipped",
99
- usage: zeroUsage(),
100
- durationMs: 0,
101
- };
102
- continue;
103
- }
104
- }
105
-
106
- // Execute sub-step based on type
107
- let result: StepResult;
108
-
109
- if (subSpec.gate) {
110
- const resolvedCheck = String(resolveExpressions(subSpec.gate.check, subScope));
111
- result = await executeGate({ ...subSpec.gate, check: resolvedCheck }, subName, { cwd: ctx.cwd, signal });
112
-
113
- // Handle gate pass/fail with break/continue
114
- const passed = result.output?.passed;
115
- if (passed && subSpec.gate.onPass === "break") {
116
- iterationSteps[subName] = result;
117
- shouldBreak = true;
118
- loopStatus = "completed";
119
- break;
120
- }
121
- if (!passed) {
122
- if (subSpec.gate.onFail === "break") {
123
- iterationSteps[subName] = result;
124
- shouldBreak = true;
125
- break;
126
- }
127
- if (subSpec.gate.onFail === "fail") {
128
- // Explicitly set to "fail" — stop the loop
129
- result.status = "failed";
130
- iterationSteps[subName] = result;
131
- iterationFailed = true;
132
- break;
133
- }
134
- // Default inside loops is "continue" — proceed to next sub-step
135
- // (or end iteration, triggering retry)
136
- }
137
- } else if (subSpec.transform) {
138
- result = executeTransform(subSpec.transform, subName, subScope);
139
- if (result.status === "failed") {
140
- iterationSteps[subName] = result;
141
- iterationFailed = true;
142
- break;
143
- }
144
- } else if (subSpec.agent) {
145
- // Resolve input, load agent, dispatch
146
- let resolvedInput: unknown;
147
- try {
148
- resolvedInput = resolveExpressions(subSpec.input ?? {}, subScope);
149
- } catch (err) {
150
- iterationSteps[subName] = {
151
- step: subName,
152
- agent: subSpec.agent,
153
- status: "failed",
154
- usage: zeroUsage(),
155
- durationMs: 0,
156
- error: err instanceof Error ? err.message : String(err),
157
- };
158
- iterationFailed = true;
159
- break;
160
- }
161
-
162
- let agentSpec: AgentSpec;
163
- try {
164
- agentSpec = loadAgent(subSpec.agent);
165
- } catch (err) {
166
- iterationSteps[subName] = {
167
- step: subName,
168
- agent: subSpec.agent,
169
- status: "failed",
170
- usage: zeroUsage(),
171
- durationMs: 0,
172
- error: err instanceof Error ? err.message : String(err),
173
- };
174
- iterationFailed = true;
175
- break;
176
- }
177
- agentSpec = compileAgentSpec(agentSpec, resolvedInput, options.templateEnv);
178
-
179
- const prompt = buildPrompt(subSpec, agentSpec, resolvedInput, runDir, `${stepName}-${iteration}-${subName}`);
180
-
181
- result = await dispatchAgent(subSpec, agentSpec, prompt, {
182
- cwd: ctx.cwd,
183
- sessionLogDir: path.join(runDir, "sessions"),
184
- stepName: `${stepName}-${iteration}-${subName}`,
185
- signal,
186
- });
187
-
188
- if (result.status === "failed") {
189
- iterationSteps[subName] = result;
190
- iterationFailed = true;
191
- break;
192
- }
193
- } else {
194
- continue; // unknown step type, skip
195
- }
196
-
197
- iterationSteps[subName] = result!;
198
- }
199
-
200
- // Record this iteration
201
- lastIterationSteps = iterationSteps;
202
- allAttempts.push({ iteration, steps: iterationSteps });
203
-
204
- if (shouldBreak) break;
205
- if (iterationFailed) {
206
- // Agent step failed within loop — stop the loop (not just the iteration)
207
- loopStatus = "failed";
208
- break;
209
- }
210
-
211
- // End of iteration without break — loop continues to next iteration
212
- }
213
-
214
- // If loop exhausted without break or failure, run onExhausted
215
- if (loopStatus !== "completed" && loopSpec.onExhausted) {
216
- const exhaustedScope: Record<string, unknown> = {
217
- input: state.input,
218
- steps: state.steps,
219
- loop: {
220
- iteration: allAttempts.length,
221
- maxAttempts,
222
- priorAttempts: allAttempts,
223
- allAttempts,
224
- },
225
- };
226
-
227
- let resolvedInput: unknown;
228
- let exhaustedError: string | undefined;
229
- try {
230
- resolvedInput = resolveExpressions(loopSpec.onExhausted.input ?? {}, exhaustedScope);
231
- } catch (err) {
232
- exhaustedError = err instanceof Error ? err.message : String(err);
233
- // Still proceed with onExhausted — let the agent run with empty input
234
- // but record the expression error so it's visible in the result
235
- }
236
-
237
- if (loopSpec.onExhausted.agent) {
238
- let agentSpec: AgentSpec;
239
- try {
240
- agentSpec = loadAgent(loopSpec.onExhausted.agent);
241
- } catch (err) {
242
- lastIterationSteps["_exhausted"] = {
243
- step: `${stepName}-exhausted`,
244
- agent: loopSpec.onExhausted.agent,
245
- status: "failed",
246
- usage: zeroUsage(),
247
- durationMs: 0,
248
- error: err instanceof Error ? err.message : String(err),
249
- };
250
- agentSpec = null as any;
251
- }
252
-
253
- if (agentSpec) {
254
- const prompt = buildPrompt(loopSpec.onExhausted, agentSpec, resolvedInput, runDir, `${stepName}-exhausted`);
255
-
256
- const exhaustedResult = await dispatchAgent(loopSpec.onExhausted, agentSpec, prompt, {
257
- cwd: ctx.cwd,
258
- sessionLogDir: path.join(runDir, "sessions"),
259
- stepName: `${stepName}-exhausted`,
260
- signal,
261
- });
262
-
263
- if (exhaustedResult && exhaustedError) {
264
- exhaustedResult.error = `Expression error in onExhausted input: ${exhaustedError}. Agent ran with empty input.`;
265
- }
266
- // Include exhausted result in the loop's output
267
- lastIterationSteps["_exhausted"] = exhaustedResult;
268
- }
269
- }
270
-
271
- if (!loopSpec.onExhausted.agent && exhaustedError) {
272
- lastIterationSteps["_exhausted"] = {
273
- step: `${stepName}-exhausted`,
274
- agent: "exhausted",
275
- status: "failed",
276
- usage: zeroUsage(),
277
- durationMs: 0,
278
- error: `Expression error in onExhausted input: ${exhaustedError}`,
279
- };
280
- }
281
- }
282
-
283
- // Aggregate usage across all iterations
284
- const totalUsage = zeroUsage();
285
- for (const attempt of allAttempts) {
286
- for (const result of Object.values(attempt.steps)) {
287
- addUsage(totalUsage, result.usage);
288
- }
289
- }
290
-
291
- const loopOutput = {
292
- iterations: allAttempts.length,
293
- maxAttempts,
294
- attempts: allAttempts,
295
- lastIteration: lastIterationSteps,
296
- };
297
- const loopTextOutput = `Loop '${stepName}': ${allAttempts.length}/${maxAttempts} iterations, status: ${loopStatus}`;
298
-
299
- const result: StepResult = {
300
- step: stepName,
301
- agent: "loop",
302
- status: loopStatus,
303
- output: loopOutput,
304
- textOutput: loopTextOutput,
305
- usage: totalUsage,
306
- durationMs: Date.now() - startTime,
307
- };
308
-
309
- // Propagate truncation from any sub-step
310
- const anyTruncated = allAttempts.some(a =>
311
- Object.values(a.steps).some(s => s.truncated)
312
- );
313
- if (anyTruncated) {
314
- result.truncated = true;
315
- result.warnings = [
316
- ...(result.warnings ?? []),
317
- "One or more loop sub-steps had truncated stdout — usage totals may undercount.",
318
- ];
319
- }
320
-
321
- result.outputPath = persistStepOutput(runDir, stepName, loopOutput, loopTextOutput, options.outputPath);
322
- return result;
323
- }