@agwab/pi-workflow 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 (79) hide show
  1. package/README.md +2 -0
  2. package/dist/compiler.d.ts +4 -6
  3. package/dist/compiler.js +70 -39
  4. package/dist/dynamic-decision.d.ts +0 -1
  5. package/dist/dynamic-decision.js +0 -7
  6. package/dist/dynamic-generated-task-runtime.d.ts +2 -0
  7. package/dist/dynamic-generated-task-runtime.js +21 -8
  8. package/dist/dynamic-profiles.d.ts +0 -1
  9. package/dist/dynamic-profiles.js +0 -3
  10. package/dist/engine-run-graph.d.ts +1 -0
  11. package/dist/engine-run-graph.js +142 -2
  12. package/dist/engine.d.ts +10 -6
  13. package/dist/engine.js +146 -77
  14. package/dist/extension.d.ts +2 -1
  15. package/dist/extension.js +38 -15
  16. package/dist/index.d.ts +3 -3
  17. package/dist/index.js +2 -1
  18. package/dist/store.d.ts +3 -1
  19. package/dist/store.js +189 -49
  20. package/dist/subagent-backend.d.ts +4 -0
  21. package/dist/subagent-backend.js +281 -31
  22. package/dist/types.d.ts +9 -1
  23. package/dist/workflow-runtime.d.ts +2 -0
  24. package/dist/workflow-runtime.js +40 -1
  25. package/dist/workflow-view.js +3 -1
  26. package/dist/workflow-web-source-extension.js +167 -48
  27. package/dist/workflow-web-source.d.ts +2 -1
  28. package/dist/workflow-web-source.js +84 -19
  29. package/docs/usage.md +11 -0
  30. package/node_modules/@agwab/pi-subagent/README.md +3 -3
  31. package/node_modules/@agwab/pi-subagent/api.mjs +1 -0
  32. package/node_modules/@agwab/pi-subagent/docs/usage.md +63 -12
  33. package/node_modules/@agwab/pi-subagent/package.json +2 -2
  34. package/node_modules/@agwab/pi-subagent/src/api.ts +54 -1
  35. package/node_modules/@agwab/pi-subagent/src/artifacts/registry.ts +9 -4
  36. package/node_modules/@agwab/pi-subagent/src/artifacts/result.ts +8 -0
  37. package/node_modules/@agwab/pi-subagent/src/core/constants.ts +9 -0
  38. package/node_modules/@agwab/pi-subagent/src/core/validation.ts +21 -0
  39. package/node_modules/@agwab/pi-subagent/src/index.ts +995 -573
  40. package/node_modules/@agwab/pi-subagent/src/orchestrate/async.ts +279 -156
  41. package/node_modules/@agwab/pi-subagent/src/orchestrate/interrupt.ts +165 -89
  42. package/node_modules/@agwab/pi-subagent/src/orchestrate/reconcile.ts +111 -65
  43. package/node_modules/@agwab/pi-subagent/src/orchestrate/run-ref.ts +219 -0
  44. package/node_modules/@agwab/pi-subagent/src/orchestrate/run.ts +88 -8
  45. package/node_modules/@agwab/pi-subagent/src/orchestrate/status.ts +614 -298
  46. package/node_modules/@agwab/pi-subagent/src/panel.ts +1352 -560
  47. package/node_modules/@agwab/pi-subagent/src/runners/headless-model.ts +53 -5
  48. package/node_modules/@agwab/pi-subagent/src/runners/tmux.ts +13 -6
  49. package/package.json +2 -2
  50. package/src/compiler.ts +127 -66
  51. package/src/dynamic-decision.ts +0 -11
  52. package/src/dynamic-generated-task-runtime.ts +47 -12
  53. package/src/dynamic-profiles.ts +0 -4
  54. package/src/engine-run-graph.ts +185 -2
  55. package/src/engine.ts +192 -107
  56. package/src/extension.ts +50 -17
  57. package/src/index.ts +3 -1
  58. package/src/store.ts +253 -55
  59. package/src/subagent-backend.ts +369 -32
  60. package/src/types.ts +13 -1
  61. package/src/workflow-runtime.ts +53 -2
  62. package/src/workflow-view.ts +2 -1
  63. package/src/workflow-web-source-extension.ts +621 -228
  64. package/src/workflow-web-source.ts +118 -28
  65. package/workflows/deep-research/helpers/claim-evidence-gate.mjs +56 -16
  66. package/workflows/deep-research/helpers/final-audit-packet.mjs +1 -4
  67. package/workflows/deep-research/helpers/normalize-input-packet.mjs +1 -1
  68. package/workflows/deep-research/helpers/render-executive.mjs +8 -21
  69. package/workflows/deep-research/helpers/sanitize-verification-candidates.mjs +89 -15
  70. package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +0 -1
  71. package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +4 -1
  72. package/workflows/impact-review/spec.json +3 -3
  73. package/workflows/spec-review/helpers/spec-review-pipeline.mjs +1 -8
  74. package/dist/dynamic-loader.d.ts +0 -25
  75. package/dist/dynamic-loader.js +0 -13
  76. package/src/dynamic-loader.ts +0 -49
  77. package/workflows/impact-review/schemas/docs-release-impact-control.schema.json +0 -42
  78. package/workflows/impact-review/schemas/security-performance-impact-control.schema.json +0 -42
  79. package/workflows/impact-review/schemas/state-data-impact-control.schema.json +0 -42
@@ -127,6 +127,135 @@ export function reconcileDynamicGeneratedRunRecords(
127
127
  return changed;
128
128
  }
129
129
 
130
+ export function reconcileForeachGeneratedRunRecords(
131
+ cwd: string,
132
+ run: WorkflowRunRecord,
133
+ compiledFlow: CompiledWorkflow,
134
+ ): boolean {
135
+ let changed = false;
136
+ const compiledSpecIds = new Set(
137
+ compiledFlow.tasks.map((task) => compiledTaskSpecId(task)),
138
+ );
139
+ const placeholderToGeneratedSpecIds = new Map<string, string[]>();
140
+
141
+ for (const compiledTask of compiledFlow.tasks) {
142
+ const specId = compiledTaskSpecId(compiledTask);
143
+ const placeholderSpecId = foreachGeneratedPlaceholderSpecId(
144
+ compiledTask,
145
+ compiledFlow,
146
+ specId,
147
+ );
148
+ if (!placeholderSpecId) continue;
149
+ if (
150
+ compiledTask.foreachGenerated?.placeholderSpecId !== placeholderSpecId
151
+ ) {
152
+ compiledTask.foreachGenerated = { placeholderSpecId };
153
+ changed = true;
154
+ }
155
+ const generated =
156
+ placeholderToGeneratedSpecIds.get(placeholderSpecId) ?? [];
157
+ generated.push(specId);
158
+ placeholderToGeneratedSpecIds.set(placeholderSpecId, generated);
159
+ }
160
+
161
+ if (placeholderToGeneratedSpecIds.size === 0) return changed;
162
+
163
+ const filteredRunTasks: WorkflowTaskRunRecord[] = [];
164
+ const seenGeneratedSpecIds = new Set<string>();
165
+ for (const task of run.tasks) {
166
+ const generatedSpecIds = placeholderToGeneratedSpecIds.get(task.specId);
167
+ let placeholderSpecId = foreachGeneratedPlaceholderSpecId(
168
+ task,
169
+ compiledFlow,
170
+ task.specId,
171
+ );
172
+ if (generatedSpecIds && !placeholderSpecId) {
173
+ if (generatedSpecIds.includes(task.specId)) {
174
+ placeholderSpecId = task.specId;
175
+ task.foreachGenerated = { placeholderSpecId };
176
+ changed = true;
177
+ } else {
178
+ changed = true;
179
+ continue;
180
+ }
181
+ }
182
+ if (placeholderSpecId && !compiledSpecIds.has(task.specId)) {
183
+ changed = true;
184
+ continue;
185
+ }
186
+ if (placeholderSpecId && seenGeneratedSpecIds.has(task.specId)) {
187
+ changed = true;
188
+ continue;
189
+ }
190
+ if (placeholderSpecId) {
191
+ seenGeneratedSpecIds.add(task.specId);
192
+ if (task.foreachGenerated?.placeholderSpecId !== placeholderSpecId) {
193
+ task.foreachGenerated = { placeholderSpecId };
194
+ changed = true;
195
+ }
196
+ }
197
+ filteredRunTasks.push(task);
198
+ }
199
+
200
+ const runTaskBySpecId = new Map<string, WorkflowTaskRunRecord>();
201
+ for (const task of filteredRunTasks) {
202
+ if (!runTaskBySpecId.has(task.specId))
203
+ runTaskBySpecId.set(task.specId, task);
204
+ }
205
+
206
+ const reordered: WorkflowTaskRunRecord[] = [];
207
+ const usedSpecIds = new Set<string>();
208
+ let nextIndex = nextTaskRecordIndex({ ...run, tasks: filteredRunTasks });
209
+ for (const compiledTask of compiledFlow.tasks) {
210
+ const specId = compiledTaskSpecId(compiledTask);
211
+ const existing = runTaskBySpecId.get(specId);
212
+ if (existing) {
213
+ const placeholderSpecId =
214
+ compiledTask.foreachGenerated?.placeholderSpecId;
215
+ if (
216
+ placeholderSpecId &&
217
+ existing.foreachGenerated?.placeholderSpecId !== placeholderSpecId
218
+ ) {
219
+ existing.foreachGenerated = { placeholderSpecId };
220
+ changed = true;
221
+ }
222
+ reordered.push(existing);
223
+ usedSpecIds.add(specId);
224
+ continue;
225
+ }
226
+ if (!compiledTask.foreachGenerated) continue;
227
+ const created = createTaskRunRecord(
228
+ cwd,
229
+ run.runId,
230
+ compiledTask,
231
+ nextIndex,
232
+ );
233
+ nextIndex += 1;
234
+ reordered.push(created);
235
+ usedSpecIds.add(specId);
236
+ changed = true;
237
+ }
238
+
239
+ for (const task of filteredRunTasks) {
240
+ if (!usedSpecIds.has(task.specId)) reordered.push(task);
241
+ }
242
+
243
+ if (!sameTaskRecordOrder(run.tasks, reordered)) changed = true;
244
+ for (const task of reordered) {
245
+ if (!task.dependsOn) continue;
246
+ const replaced = replaceForeachGeneratedDependencies(
247
+ task.dependsOn,
248
+ placeholderToGeneratedSpecIds,
249
+ );
250
+ if (!sameStringList(task.dependsOn, replaced)) {
251
+ task.dependsOn = replaced;
252
+ changed = true;
253
+ }
254
+ }
255
+ if (changed) run.tasks = reordered;
256
+ return changed;
257
+ }
258
+
130
259
  export function assertRunTaskPositionalAlignment(
131
260
  run: WorkflowRunRecord,
132
261
  compiledFlow: CompiledWorkflow,
@@ -209,6 +338,54 @@ export function compiledTaskSpecId(task: CompiledTask): string {
209
338
  return typeof specId === "string" && specId.trim() !== "" ? specId : task.id;
210
339
  }
211
340
 
341
+ function foreachGeneratedPlaceholderSpecId(
342
+ task: CompiledTask | WorkflowTaskRunRecord,
343
+ compiledFlow: CompiledWorkflow,
344
+ specId: string,
345
+ ): string | undefined {
346
+ const explicit = task.foreachGenerated?.placeholderSpecId;
347
+ if (typeof explicit === "string" && explicit.trim() !== "") return explicit;
348
+ if ((task as CompiledTask).foreach) return undefined;
349
+ if (task.kind !== "foreach" || !task.stageId) return undefined;
350
+ const placeholderSpecId = foreachPlaceholderSpecId(
351
+ compiledFlow,
352
+ task.stageId,
353
+ );
354
+ if (!placeholderSpecId || specId === placeholderSpecId) return undefined;
355
+ return placeholderSpecId;
356
+ }
357
+
358
+ function foreachPlaceholderSpecId(
359
+ compiledFlow: CompiledWorkflow,
360
+ stageId: string,
361
+ ): string | undefined {
362
+ const stage = ((compiledFlow as any).stages ?? []).find(
363
+ (candidate: any) => candidate?.id === stageId,
364
+ );
365
+ if (stage?.type !== "foreach") return undefined;
366
+ return `${stageId}.item`;
367
+ }
368
+
369
+ function replaceForeachGeneratedDependencies(
370
+ dependsOn: string[],
371
+ placeholderToGeneratedSpecIds: Map<string, string[]>,
372
+ ): string[] {
373
+ const replaced: string[] = [];
374
+ for (const dep of dependsOn) {
375
+ const generatedSpecIds = placeholderToGeneratedSpecIds.get(dep);
376
+ if (generatedSpecIds) replaced.push(...generatedSpecIds);
377
+ else replaced.push(dep);
378
+ }
379
+ return [...new Set(replaced)];
380
+ }
381
+
382
+ function sameStringList(left: string[], right: string[]): boolean {
383
+ return (
384
+ left.length === right.length &&
385
+ left.every((value, index) => value === right[index])
386
+ );
387
+ }
388
+
212
389
  function isLoopGeneratedCompiledTask(
213
390
  task: CompiledTask,
214
391
  loopIds: Set<string>,
@@ -330,7 +507,7 @@ export function buildForeachGeneratedTasks(
330
507
  const itemText = formatForeachItem(item);
331
508
  const instructions = template.foreach!.prompt.replace(
332
509
  /\$\{item\}/g,
333
- itemText,
510
+ escapeReplacementText(itemText),
334
511
  );
335
512
  const compiledPrompt = [
336
513
  template.foreach!.injectRuntimeTask && runtimeTask
@@ -352,6 +529,7 @@ export function buildForeachGeneratedTasks(
352
529
  compiledPrompt,
353
530
  dependsOn: [...(template.dependsOn ?? [])],
354
531
  foreach: undefined,
532
+ foreachGenerated: { placeholderSpecId: template.id },
355
533
  } as CompiledTask);
356
534
  }
357
535
  return { tasks };
@@ -382,6 +560,10 @@ function formatForeachItem(item: unknown): string {
382
560
  return typeof item === "string" ? item : JSON.stringify(item);
383
561
  }
384
562
 
563
+ function escapeReplacementText(value: string): string {
564
+ return value.replace(/\$/g, "$$$$");
565
+ }
566
+
385
567
  export function sourceStageIdsForFrom(from: unknown): string[] {
386
568
  if (Array.isArray(from))
387
569
  return from.filter((item): item is string => typeof item === "string");
@@ -453,7 +635,8 @@ export function markDagDependentsSkipped(
453
635
  return (
454
636
  status === "failed" ||
455
637
  status === "interrupted" ||
456
- status === "skipped"
638
+ status === "skipped" ||
639
+ status === "blocked"
457
640
  );
458
641
  });
459
642
  if (!failedDep) continue;