@quintinshaw/pi-dynamic-workflows 1.0.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 (51) hide show
  1. package/README.md +159 -0
  2. package/dist/adversarial-review.d.ts +20 -0
  3. package/dist/adversarial-review.js +87 -0
  4. package/dist/agent.d.ts +29 -0
  5. package/dist/agent.js +90 -0
  6. package/dist/auto-workflow.d.ts +26 -0
  7. package/dist/auto-workflow.js +121 -0
  8. package/dist/config.d.ts +17 -0
  9. package/dist/config.js +17 -0
  10. package/dist/deep-research.d.ts +22 -0
  11. package/dist/deep-research.js +110 -0
  12. package/dist/display.d.ts +62 -0
  13. package/dist/display.js +163 -0
  14. package/dist/errors.d.ts +41 -0
  15. package/dist/errors.js +63 -0
  16. package/dist/index.d.ts +28 -0
  17. package/dist/index.js +15 -0
  18. package/dist/logger.d.ts +21 -0
  19. package/dist/logger.js +67 -0
  20. package/dist/model-routing.d.ts +33 -0
  21. package/dist/model-routing.js +57 -0
  22. package/dist/run-persistence.d.ts +53 -0
  23. package/dist/run-persistence.js +78 -0
  24. package/dist/structured-output.d.ts +19 -0
  25. package/dist/structured-output.js +30 -0
  26. package/dist/workflow-manager.d.ts +74 -0
  27. package/dist/workflow-manager.js +241 -0
  28. package/dist/workflow-saved.d.ts +35 -0
  29. package/dist/workflow-saved.js +91 -0
  30. package/dist/workflow-tool.d.ts +22 -0
  31. package/dist/workflow-tool.js +216 -0
  32. package/dist/workflow.d.ts +75 -0
  33. package/dist/workflow.js +364 -0
  34. package/extensions/workflow.ts +14 -0
  35. package/package.json +70 -0
  36. package/src/adversarial-review.ts +107 -0
  37. package/src/agent.ts +135 -0
  38. package/src/auto-workflow.ts +146 -0
  39. package/src/config.ts +24 -0
  40. package/src/deep-research.ts +128 -0
  41. package/src/display.ts +236 -0
  42. package/src/errors.ts +85 -0
  43. package/src/index.ts +55 -0
  44. package/src/logger.ts +89 -0
  45. package/src/model-routing.ts +80 -0
  46. package/src/run-persistence.ts +132 -0
  47. package/src/structured-output.ts +47 -0
  48. package/src/workflow-manager.ts +294 -0
  49. package/src/workflow-saved.ts +131 -0
  50. package/src/workflow-tool.ts +254 -0
  51. package/src/workflow.ts +492 -0
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # pi-dynamic-workflows
2
+
3
+ > Claude-Code-style dynamic workflows for [Pi](https://github.com/earendil-works/pi).
4
+
5
+ A Pi extension that adds a `workflow` tool. Instead of one assistant doing everything sequentially, the model writes a small JavaScript script that fans out the work across many isolated subagents, then synthesizes the results.
6
+
7
+ Great for codebase audits, multi-perspective review, large refactors, and fan-out research. Inspired by Anthropic's [dynamic workflows in Claude Code](https://claude.com/blog/introducing-dynamic-workflows-in-claude-code).
8
+
9
+ Fork of [Michaelliv/pi-dynamic-workflows](https://github.com/Michaelliv/pi-dynamic-workflows), updated for `@earendil-works/*` packages with a subagent settings-inheritance fix.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pi install @quintinshaw/pi-dynamic-workflows
15
+ ```
16
+
17
+ Then `/reload` in Pi. The extension registers a `workflow` tool and activates it on session start.
18
+
19
+ <details>
20
+ <summary>From source (for development)</summary>
21
+
22
+ ```bash
23
+ git clone git@github.com:QuintinShaw/pi-dynamic-workflows.git
24
+ pi install /path/to/pi-dynamic-workflows
25
+ ```
26
+ </details>
27
+
28
+ ## Usage
29
+
30
+ Ask Pi for a workflow in plain language:
31
+
32
+ ```text
33
+ Run a workflow to inspect this repository and summarize the main modules.
34
+ ```
35
+
36
+ The model writes a workflow script and calls the `workflow` tool. Live progress streams inline:
37
+
38
+ ```text
39
+ ◆ Workflow: inspect_project (3/3 done · 12,480 tokens)
40
+ ✓ Scan 1/1
41
+ #1 ✓ repo inventory
42
+ ✓ Analyze 2/2
43
+ #2 ✓ source modules
44
+ #3 ✓ final summary
45
+ ```
46
+
47
+ Press `Esc` to cancel a running run; active subagents are aborted and surfaced as skipped.
48
+
49
+ ## Workflow script shape
50
+
51
+ A workflow is plain JavaScript. The first statement must export literal metadata:
52
+
53
+ ```js
54
+ export const meta = {
55
+ name: 'inspect_project',
56
+ description: 'Inspect a repository and summarize the main modules',
57
+ phases: [{ title: 'Scan' }, { title: 'Analyze' }],
58
+ }
59
+
60
+ phase('Scan')
61
+ const inventory = await agent('Inspect the repository structure.', { label: 'repo inventory' })
62
+
63
+ phase('Analyze')
64
+ const summary = await agent('Summarize the main modules:\n' + inventory, { label: 'module summary' })
65
+
66
+ return { inventory, summary }
67
+ ```
68
+
69
+ ### Globals
70
+
71
+ | Global | Description |
72
+ | --- | --- |
73
+ | `agent(prompt, opts)` | Spawn an isolated subagent. Returns its final text, or a validated object with `opts.schema`. |
74
+ | `parallel(thunks)` | Run an array of `() => agent(...)` thunks concurrently. Results returned in input order. |
75
+ | `pipeline(items, ...stages)` | Fan items out through sequential stages. Each stage receives `(prev, original, index)`. |
76
+ | `phase(title)` | Mark the current phase for the live progress view. |
77
+ | `log(message)` | Append a workflow-level log line. |
78
+ | `args` | Optional JSON value passed via the tool's `args` parameter. |
79
+ | `budget` | `{ total, spent(), remaining() }` token-budget tracker. |
80
+ | `cwd`, `process.cwd()` | Working directory for subagents. |
81
+
82
+ ### Agent options
83
+
84
+ | Option | Type | Description |
85
+ | --- | --- | --- |
86
+ | `label` | string | Human-readable label for progress display |
87
+ | `phase` | string | Override the current phase for this agent |
88
+ | `schema` | object | JSON Schema for structured output |
89
+ | `timeoutMs` | number | Override the default 5-minute agent timeout |
90
+
91
+ ### Structured output
92
+
93
+ Pass a JSON Schema via `opts.schema` and the subagent returns a validated object:
94
+
95
+ ```js
96
+ const finding = await agent('Find security-sensitive files.', {
97
+ label: 'security scan',
98
+ schema: {
99
+ type: 'object',
100
+ properties: {
101
+ paths: { type: 'array', items: { type: 'string' } },
102
+ reason: { type: 'string' },
103
+ },
104
+ required: ['paths', 'reason'],
105
+ },
106
+ })
107
+ ```
108
+
109
+ Backed by a Pi `structured_output` tool with `terminate: true`, so the subagent ends on that call.
110
+
111
+ ### Determinism rules
112
+
113
+ Scripts run inside a Node `vm` sandbox. Intentionally unavailable: `Date.now()`, `new Date()`, `Math.random()`, `require`/`import`/`fs`/network, and (inside `meta`) spreads, computed keys, template interpolation, and function calls. This keeps `meta` parseable and runs reproducible.
114
+
115
+ ## What works today
116
+
117
+ - **Core runtime** — `agent` / `parallel` / `pipeline` / `phase` / `log` / `budget` in a sandboxed script
118
+ - **Structured output** — JSON-Schema-validated subagent results
119
+ - **Safety limits** — 1000-agent cap (`maxAgents`), per-agent timeout (`agentTimeoutMs`), recoverable-vs-fatal error classification
120
+ - **Live progress + token display**, `Esc` to abort
121
+ - **Log persistence** to `.pi/workflows/runs/`
122
+
123
+ ## Roadmap
124
+
125
+ Tracked toward closer parity with Claude Code dynamic workflows:
126
+
127
+ - **Real per-agent / per-phase model routing** (`opts.model`, `meta.phases[].model`)
128
+ - **Real token accounting** via the SDK's session stats (today's display uses an estimate)
129
+ - **Command surface** — `/workflows` (list / status / stop) and reachable background runs
130
+ - **Resume** — journaled results, replay the unchanged prefix, run the rest live
131
+ - **Worktree isolation** for parallel edits, and **bundled `/deep-research`**
132
+ - **Saved workflows** as `/<name>` slash commands
133
+
134
+ ## How it works
135
+
136
+ ```text
137
+ user prompt
138
+ → Pi model writes a workflow script
139
+ → workflow tool parses + runs it in a vm sandbox
140
+ → script calls agent() / parallel() / pipeline()
141
+ → each agent() spawns a fresh in-memory Pi subagent session
142
+ → snapshots stream back as compact progress
143
+ → final structured result returns to the parent assistant
144
+ ```
145
+
146
+ Subagents run in fresh in-memory Pi sessions with the standard coding tools (read, bash, edit, write, grep, find, ls), so they work exactly like a normal Pi turn.
147
+
148
+ ## Development
149
+
150
+ ```bash
151
+ npm install
152
+ npm test # biome check + tsc + unit tests
153
+ ```
154
+
155
+ Parser unit tests live in `tests/workflow-parser.test.ts`.
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Adversarial review mode for workflows.
3
+ * Agents cross-check each other's findings for higher quality results.
4
+ */
5
+ export interface AdversarialReviewConfig {
6
+ /** Number of independent reviewers per finding. */
7
+ reviewerCount: number;
8
+ /** Whether to filter out findings that don't survive cross-checking. */
9
+ filterContested: boolean;
10
+ /** Minimum agreement threshold (0-1). */
11
+ agreementThreshold: number;
12
+ }
13
+ /**
14
+ * Generate an adversarial review workflow script.
15
+ */
16
+ export declare function generateAdversarialReviewWorkflow(taskDescription: string, config?: Partial<AdversarialReviewConfig>): string;
17
+ /**
18
+ * Generate a multi-perspective analysis workflow.
19
+ */
20
+ export declare function generateMultiPerspectiveWorkflow(topic: string, perspectives: string[]): string;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Adversarial review mode for workflows.
3
+ * Agents cross-check each other's findings for higher quality results.
4
+ */
5
+ const DEFAULT_CONFIG = {
6
+ reviewerCount: 2,
7
+ filterContested: true,
8
+ agreementThreshold: 0.5,
9
+ };
10
+ /**
11
+ * Generate an adversarial review workflow script.
12
+ */
13
+ export function generateAdversarialReviewWorkflow(taskDescription, config = {}) {
14
+ const cfg = { ...DEFAULT_CONFIG, ...config };
15
+ return `export const meta = {
16
+ name: 'adversarial_review',
17
+ description: 'Adversarial review with ${cfg.reviewerCount} independent reviewers',
18
+ phases: [
19
+ { title: 'Initial Investigation' },
20
+ { title: 'Independent Review' },
21
+ { title: 'Cross-Check' },
22
+ { title: 'Consensus' },
23
+ ],
24
+ };
25
+
26
+ phase('Initial Investigation');
27
+ const findings = await agent(
28
+ 'Investigate and document findings for: ${taskDescription.replace(/'/g, "\\'").slice(0, 80)}',
29
+ { label: 'investigator' }
30
+ );
31
+
32
+ phase('Independent Review');
33
+ const reviews = await parallel(Array.from({ length: ${cfg.reviewerCount} }, (_, i) => () =>
34
+ agent(
35
+ 'Independently review these findings. Agree or disagree with each point, and explain why:\\n\\n' + findings,
36
+ { label: 'reviewer-' + (i + 1) }
37
+ )
38
+ ));
39
+
40
+ phase('Cross-Check');
41
+ const crossCheck = await agent(
42
+ 'Compare these independent reviews and identify points of agreement and disagreement:\\n' +
43
+ 'Reviews: ' + JSON.stringify(reviews) + '\\n' +
44
+ 'Original findings: ' + findings,
45
+ { label: 'cross-checker' }
46
+ );
47
+
48
+ phase('Consensus');
49
+ const consensus = await agent(
50
+ 'Based on the cross-check, produce a final verified report. Only include findings that survived independent review:\\n' + crossCheck,
51
+ { label: 'consensus-builder' }
52
+ );
53
+
54
+ return { findings, reviews, crossCheck, consensus };`;
55
+ }
56
+ /**
57
+ * Generate a multi-perspective analysis workflow.
58
+ */
59
+ export function generateMultiPerspectiveWorkflow(topic, perspectives) {
60
+ const perspectiveAgents = perspectives
61
+ .map((p, _i) => ` () => agent('Analyze from ${p} perspective: ' + topic, { label: '${p.toLowerCase().replace(/\\s+/g, "-")}' }),`)
62
+ .join("\n");
63
+ return `export const meta = {
64
+ name: 'multi_perspective_analysis',
65
+ description: 'Analyze from ${perspectives.length} different perspectives',
66
+ phases: [
67
+ { title: 'Perspective Analysis' },
68
+ { title: 'Synthesis' },
69
+ ],
70
+ };
71
+
72
+ phase('Perspective Analysis');
73
+ const topic = '${topic.replace(/'/g, "\\'")}';
74
+ const analyses = await parallel([
75
+ ${perspectiveAgents}
76
+ ]);
77
+
78
+ phase('Synthesis');
79
+ const synthesis = await agent(
80
+ 'Synthesize these different perspectives into a balanced analysis:\\n' +
81
+ 'Analyses: ' + JSON.stringify(analyses) + '\\n' +
82
+ 'Topic: ' + topic,
83
+ { label: 'synthesizer' }
84
+ );
85
+
86
+ return { analyses, synthesis };`;
87
+ }
@@ -0,0 +1,29 @@
1
+ import { type CreateAgentSessionOptions, type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import type { Static, TSchema } from "typebox";
3
+ export interface WorkflowAgentOptions {
4
+ cwd?: string;
5
+ /** Extra tools available to the subagent in addition to the structured output tool. */
6
+ tools?: ToolDefinition[];
7
+ /** Override any createAgentSession option (model, authStorage, resourceLoader, etc.). */
8
+ session?: Partial<CreateAgentSessionOptions>;
9
+ /** Extra system guidance prepended to every subagent task. */
10
+ instructions?: string;
11
+ }
12
+ export interface AgentRunOptions<TSchemaDef extends TSchema | undefined = undefined> {
13
+ label?: string;
14
+ schema?: TSchemaDef;
15
+ tools?: ToolDefinition[];
16
+ instructions?: string;
17
+ signal?: AbortSignal;
18
+ }
19
+ export type AgentRunResult<TSchemaDef extends TSchema | undefined> = TSchemaDef extends TSchema ? Static<TSchemaDef> : string;
20
+ export declare class WorkflowAgent {
21
+ private readonly cwd;
22
+ private readonly baseTools;
23
+ private readonly sessionOptions;
24
+ private readonly instructions?;
25
+ constructor(options?: WorkflowAgentOptions);
26
+ run<TSchemaDef extends TSchema | undefined = undefined>(prompt: string, options?: AgentRunOptions<TSchemaDef>): Promise<AgentRunResult<TSchemaDef>>;
27
+ private buildPrompt;
28
+ private lastAssistantText;
29
+ }
package/dist/agent.js ADDED
@@ -0,0 +1,90 @@
1
+ import { createAgentSession, createCodingTools, getAgentDir, SessionManager, SettingsManager, } from "@earendil-works/pi-coding-agent";
2
+ import { createStructuredOutputTool } from "./structured-output.js";
3
+ export class WorkflowAgent {
4
+ cwd;
5
+ baseTools;
6
+ sessionOptions;
7
+ instructions;
8
+ constructor(options = {}) {
9
+ this.cwd = options.cwd ?? process.cwd();
10
+ this.baseTools = options.tools ?? createCodingTools(this.cwd);
11
+ this.sessionOptions = options.session ?? {};
12
+ this.instructions = options.instructions;
13
+ }
14
+ async run(prompt, options = {}) {
15
+ const capture = { called: false, value: undefined };
16
+ const customTools = [...this.baseTools, ...(options.tools ?? [])];
17
+ if (options.schema) {
18
+ customTools.push(createStructuredOutputTool({ schema: options.schema, capture }));
19
+ }
20
+ const agentDir = getAgentDir();
21
+ const { session } = await createAgentSession({
22
+ cwd: this.cwd,
23
+ agentDir,
24
+ sessionManager: SessionManager.inMemory(),
25
+ // Use real SettingsManager to inherit user's default provider/model settings.
26
+ // SettingsManager.inMemory() doesn't load ~/.pi/settings.json, so subagents
27
+ // would fall back to the first available model (e.g. openai-codex) which may
28
+ // not have valid auth, causing silent empty responses.
29
+ settingsManager: SettingsManager.create(this.cwd, agentDir),
30
+ customTools,
31
+ ...this.sessionOptions,
32
+ });
33
+ let removeAbortListener;
34
+ try {
35
+ if (options.signal?.aborted)
36
+ throw new Error("Subagent was aborted");
37
+ if (options.signal) {
38
+ const onAbort = () => void session.abort();
39
+ options.signal.addEventListener("abort", onAbort, { once: true });
40
+ removeAbortListener = () => options.signal?.removeEventListener("abort", onAbort);
41
+ }
42
+ await session.prompt(this.buildPrompt(prompt, options, Boolean(options.schema)));
43
+ if (options.signal?.aborted)
44
+ throw new Error("Subagent was aborted");
45
+ if (options.schema) {
46
+ if (!capture.called) {
47
+ throw new Error("Subagent finished without calling structured_output");
48
+ }
49
+ return capture.value;
50
+ }
51
+ return this.lastAssistantText(session.messages);
52
+ }
53
+ finally {
54
+ removeAbortListener?.();
55
+ session.dispose();
56
+ }
57
+ }
58
+ buildPrompt(prompt, options, structured) {
59
+ const parts = [
60
+ this.instructions,
61
+ options.instructions,
62
+ options.label ? `Task label: ${options.label}` : undefined,
63
+ prompt,
64
+ ].filter(Boolean);
65
+ if (structured) {
66
+ parts.push([
67
+ "Final output contract:",
68
+ "- Your final action MUST be a structured_output tool call.",
69
+ "- The structured_output arguments are the return value of this subagent.",
70
+ "- Do not emit a prose final answer instead of structured_output.",
71
+ "- If you need to inspect files or run commands first, do so, then call structured_output exactly once.",
72
+ ].join("\n"));
73
+ }
74
+ return parts.join("\n\n");
75
+ }
76
+ lastAssistantText(messages) {
77
+ for (let i = messages.length - 1; i >= 0; i--) {
78
+ const message = messages[i];
79
+ if (message?.role !== "assistant" || !Array.isArray(message.content))
80
+ continue;
81
+ const text = message.content
82
+ .filter((part) => part.type === "text")
83
+ .map((part) => part.text)
84
+ .join("");
85
+ if (text.trim())
86
+ return text;
87
+ }
88
+ return "";
89
+ }
90
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Auto-workflow mode (ultracode equivalent).
3
+ * Automatically decides when to use workflows based on task complexity.
4
+ */
5
+ export interface AutoWorkflowConfig {
6
+ /** Enable auto-workflow mode. */
7
+ enabled: boolean;
8
+ /** Minimum number of subtasks to trigger a workflow. */
9
+ minSubtasks: number;
10
+ /** Keywords that suggest workflow usage. */
11
+ triggerKeywords: string[];
12
+ /** Maximum complexity score before auto-triggering. */
13
+ complexityThreshold: number;
14
+ }
15
+ /**
16
+ * Analyze a task description and determine if it should use a workflow.
17
+ */
18
+ export declare function shouldUseWorkflow(taskDescription: string, config?: Partial<AutoWorkflowConfig>): {
19
+ useWorkflow: boolean;
20
+ confidence: number;
21
+ reason: string;
22
+ };
23
+ /**
24
+ * Generate a workflow script suggestion from a task description.
25
+ */
26
+ export declare function suggestWorkflowScript(taskDescription: string): string;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Auto-workflow mode (ultracode equivalent).
3
+ * Automatically decides when to use workflows based on task complexity.
4
+ */
5
+ const DEFAULT_CONFIG = {
6
+ enabled: false,
7
+ minSubtasks: 3,
8
+ triggerKeywords: [
9
+ "workflow",
10
+ "parallel",
11
+ "fan-out",
12
+ "audit",
13
+ "migrate",
14
+ "review",
15
+ "research",
16
+ "analyze all",
17
+ "check every",
18
+ "sweep",
19
+ "batch",
20
+ "bulk",
21
+ ],
22
+ complexityThreshold: 7,
23
+ };
24
+ /**
25
+ * Analyze a task description and determine if it should use a workflow.
26
+ */
27
+ export function shouldUseWorkflow(taskDescription, config = { enabled: true }) {
28
+ const cfg = { ...DEFAULT_CONFIG, ...config };
29
+ if (!cfg.enabled) {
30
+ return { useWorkflow: false, confidence: 0, reason: "Auto-workflow disabled" };
31
+ }
32
+ const lower = taskDescription.toLowerCase();
33
+ // Check for explicit workflow keywords
34
+ const keywordMatches = cfg.triggerKeywords.filter((kw) => lower.includes(kw));
35
+ if (keywordMatches.length > 0) {
36
+ return {
37
+ useWorkflow: true,
38
+ confidence: Math.min(0.5 + keywordMatches.length * 0.15, 1),
39
+ reason: `Matched keywords: ${keywordMatches.join(", ")}`,
40
+ };
41
+ }
42
+ // Analyze complexity indicators
43
+ const complexityIndicators = [
44
+ { pattern: /\b(all|every|each|entire|whole)\b/i, weight: 2 },
45
+ { pattern: /\b(files?|directories|folders?|modules?|components?|endpoints?)\b/i, weight: 1.5 },
46
+ { pattern: /\b(parallel|concurrent|simultaneously)\b/i, weight: 2 },
47
+ { pattern: /\b(review|audit|check|verify|validate)\b/i, weight: 1 },
48
+ { pattern: /\b(migrate|refactor|update|modify|change)\b/i, weight: 1.5 },
49
+ { pattern: /\b(research|investigate|analyze|compare)\b/i, weight: 1 },
50
+ { pattern: /\d+\s*(files?|items?|tasks?|components?)/i, weight: 2 },
51
+ { pattern: /\b(across|throughout|cross-cutting)\b/i, weight: 1.5 },
52
+ ];
53
+ let complexityScore = 0;
54
+ for (const indicator of complexityIndicators) {
55
+ if (indicator.pattern.test(taskDescription)) {
56
+ complexityScore += indicator.weight;
57
+ }
58
+ }
59
+ // Estimate subtask count
60
+ const subtaskIndicators = [
61
+ /\bfirst\b/gi,
62
+ /\bthen\b/gi,
63
+ /\bfinally\b/gi,
64
+ /\bafter\b/gi,
65
+ /\bnext\b/gi,
66
+ /\balso\b/gi,
67
+ /\bstep \d/gi,
68
+ ];
69
+ let estimatedSubtasks = 1;
70
+ for (const pattern of subtaskIndicators) {
71
+ const matches = taskDescription.match(pattern);
72
+ if (matches)
73
+ estimatedSubtasks += matches.length;
74
+ }
75
+ if (complexityScore >= cfg.complexityThreshold || estimatedSubtasks >= cfg.minSubtasks) {
76
+ return {
77
+ useWorkflow: true,
78
+ confidence: Math.min(complexityScore / 10, 1),
79
+ reason: `Complexity score: ${complexityScore}, estimated subtasks: ${estimatedSubtasks}`,
80
+ };
81
+ }
82
+ return {
83
+ useWorkflow: false,
84
+ confidence: 0.3,
85
+ reason: `Below threshold (complexity: ${complexityScore}, subtasks: ${estimatedSubtasks})`,
86
+ };
87
+ }
88
+ /**
89
+ * Generate a workflow script suggestion from a task description.
90
+ */
91
+ export function suggestWorkflowScript(taskDescription) {
92
+ return `export const meta = {
93
+ name: 'auto_generated',
94
+ description: '${taskDescription.replace(/'/g, "\\'").slice(0, 100)}',
95
+ phases: [
96
+ { title: 'Analyze' },
97
+ { title: 'Execute' },
98
+ { title: 'Verify' },
99
+ ],
100
+ };
101
+
102
+ phase('Analyze');
103
+ const analysis = await agent(
104
+ 'Analyze this task and break it into subtasks: ${taskDescription.replace(/'/g, "\\'").slice(0, 80)}',
105
+ { label: 'task analysis' }
106
+ );
107
+
108
+ phase('Execute');
109
+ const results = await parallel([
110
+ () => agent('Execute subtask 1 based on: ' + analysis, { label: 'subtask-1' }),
111
+ // Add more subtasks as needed
112
+ ]);
113
+
114
+ phase('Verify');
115
+ const verification = await agent(
116
+ 'Verify these results are correct: ' + JSON.stringify(results),
117
+ { label: 'verification' }
118
+ );
119
+
120
+ return { analysis, results, verification };`;
121
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Configuration constants for pi-dynamic-workflows.
3
+ */
4
+ /** Maximum number of agents allowed per workflow run. */
5
+ export declare const MAX_AGENTS_PER_RUN = 1000;
6
+ /** Default timeout for a single agent in milliseconds (5 minutes). */
7
+ export declare const DEFAULT_AGENT_TIMEOUT_MS: number;
8
+ /** Maximum concurrent agents (matches Claude Code limit). */
9
+ export declare const MAX_CONCURRENCY = 16;
10
+ /** Default token budget if none specified. */
11
+ export declare const DEFAULT_TOKEN_BUDGET: null;
12
+ /** Directory for persisting workflow run state. */
13
+ export declare const WORKFLOW_RUNS_DIR = ".pi/workflows/runs";
14
+ /** Directory for saved workflow commands. */
15
+ export declare const WORKFLOW_SAVED_DIR = ".pi/workflows/saved";
16
+ /** User-level saved workflows directory. */
17
+ export declare const USER_WORKFLOW_SAVED_DIR = "~/.pi/workflows/saved";
package/dist/config.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Configuration constants for pi-dynamic-workflows.
3
+ */
4
+ /** Maximum number of agents allowed per workflow run. */
5
+ export const MAX_AGENTS_PER_RUN = 1000;
6
+ /** Default timeout for a single agent in milliseconds (5 minutes). */
7
+ export const DEFAULT_AGENT_TIMEOUT_MS = 5 * 60 * 1000;
8
+ /** Maximum concurrent agents (matches Claude Code limit). */
9
+ export const MAX_CONCURRENCY = 16;
10
+ /** Default token budget if none specified. */
11
+ export const DEFAULT_TOKEN_BUDGET = null;
12
+ /** Directory for persisting workflow run state. */
13
+ export const WORKFLOW_RUNS_DIR = ".pi/workflows/runs";
14
+ /** Directory for saved workflow commands. */
15
+ export const WORKFLOW_SAVED_DIR = ".pi/workflows/saved";
16
+ /** User-level saved workflows directory. */
17
+ export const USER_WORKFLOW_SAVED_DIR = "~/.pi/workflows/saved";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Deep research workflow.
3
+ * Built-in workflow for comprehensive research across multiple sources.
4
+ */
5
+ export interface DeepResearchConfig {
6
+ /** Number of search angles to explore. */
7
+ searchAngles: number;
8
+ /** Number of sources to fetch per angle. */
9
+ sourcesPerAngle: number;
10
+ /** Whether to cross-check claims across sources. */
11
+ crossCheck: boolean;
12
+ /** Maximum number of agents to use. */
13
+ maxAgents: number;
14
+ }
15
+ /**
16
+ * Generate a deep research workflow script.
17
+ */
18
+ export declare function generateDeepResearchWorkflow(question: string, config?: Partial<DeepResearchConfig>): string;
19
+ /**
20
+ * Generate a codebase audit workflow.
21
+ */
22
+ export declare function generateCodebaseAuditWorkflow(scope: string, checks: string[]): string;