@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
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Workflow run state persistence for pause/resume support.
3
+ */
4
+ export type RunStatus = "pending" | "running" | "paused" | "completed" | "failed" | "aborted";
5
+ export interface PersistedAgentState {
6
+ id: number;
7
+ label: string;
8
+ phase?: string;
9
+ prompt: string;
10
+ status: "queued" | "running" | "done" | "error" | "skipped";
11
+ result?: unknown;
12
+ error?: string;
13
+ startedAt?: string;
14
+ endedAt?: string;
15
+ }
16
+ export interface PersistedRunState {
17
+ runId: string;
18
+ workflowName: string;
19
+ script: string;
20
+ args?: unknown;
21
+ status: RunStatus;
22
+ phases: string[];
23
+ currentPhase?: string;
24
+ agents: PersistedAgentState[];
25
+ logs: string[];
26
+ result?: unknown;
27
+ startedAt: string;
28
+ updatedAt: string;
29
+ completedAt?: string;
30
+ durationMs?: number;
31
+ tokenUsage?: {
32
+ input: number;
33
+ output: number;
34
+ total: number;
35
+ };
36
+ }
37
+ export interface RunPersistence {
38
+ /** Save current run state. */
39
+ save(state: PersistedRunState): void;
40
+ /** Load a persisted run by ID. */
41
+ load(runId: string): PersistedRunState | null;
42
+ /** List all persisted runs. */
43
+ list(): PersistedRunState[];
44
+ /** Delete a persisted run. */
45
+ delete(runId: string): boolean;
46
+ /** Get runs directory path. */
47
+ getRunsDir(): string;
48
+ }
49
+ export declare function createRunPersistence(cwd: string): RunPersistence;
50
+ /**
51
+ * Generate a unique run ID.
52
+ */
53
+ export declare function generateRunId(): string;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Workflow run state persistence for pause/resume support.
3
+ */
4
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { WORKFLOW_RUNS_DIR } from "./config.js";
7
+ export function createRunPersistence(cwd) {
8
+ const runsDir = join(cwd, WORKFLOW_RUNS_DIR);
9
+ const ensureDir = () => {
10
+ if (!existsSync(runsDir)) {
11
+ mkdirSync(runsDir, { recursive: true });
12
+ }
13
+ };
14
+ const runPath = (runId) => join(runsDir, `${runId}.json`);
15
+ return {
16
+ save(state) {
17
+ ensureDir();
18
+ state.updatedAt = new Date().toISOString();
19
+ writeFileSync(runPath(state.runId), JSON.stringify(state, null, 2));
20
+ },
21
+ load(runId) {
22
+ try {
23
+ const path = runPath(runId);
24
+ if (!existsSync(path))
25
+ return null;
26
+ return JSON.parse(readFileSync(path, "utf-8"));
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ },
32
+ list() {
33
+ ensureDir();
34
+ try {
35
+ const files = readdirSync(runsDir).filter((f) => f.endsWith(".json"));
36
+ const runs = [];
37
+ for (const file of files) {
38
+ try {
39
+ const state = JSON.parse(readFileSync(join(runsDir, file), "utf-8"));
40
+ runs.push(state);
41
+ }
42
+ catch {
43
+ // Skip corrupted files
44
+ }
45
+ }
46
+ return runs.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
47
+ }
48
+ catch {
49
+ return [];
50
+ }
51
+ },
52
+ delete(runId) {
53
+ try {
54
+ const path = runPath(runId);
55
+ if (existsSync(path)) {
56
+ const { unlinkSync } = require("node:fs");
57
+ unlinkSync(path);
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ },
66
+ getRunsDir() {
67
+ return runsDir;
68
+ },
69
+ };
70
+ }
71
+ /**
72
+ * Generate a unique run ID.
73
+ */
74
+ export function generateRunId() {
75
+ const timestamp = Date.now().toString(36);
76
+ const random = Math.random().toString(36).slice(2, 8);
77
+ return `${timestamp}-${random}`;
78
+ }
@@ -0,0 +1,19 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import type { Static, TSchema } from "typebox";
3
+ export interface StructuredOutputCapture<T = unknown> {
4
+ value: T | undefined;
5
+ called: boolean;
6
+ }
7
+ export interface StructuredOutputToolOptions<TSchemaDef extends TSchema> {
8
+ schema: TSchemaDef;
9
+ capture: StructuredOutputCapture<Static<TSchemaDef>>;
10
+ name?: string;
11
+ }
12
+ /**
13
+ * Create a terminating tool that captures validated params as the subagent result.
14
+ *
15
+ * Pi validates `params` against `schema` before execute() is called. Returning
16
+ * `terminate: true` lets the subagent finish on this tool call without paying for
17
+ * an extra assistant follow-up turn.
18
+ */
19
+ export declare function createStructuredOutputTool<TSchemaDef extends TSchema>({ schema, capture, name, }: StructuredOutputToolOptions<TSchemaDef>): ToolDefinition<TSchemaDef, Static<TSchemaDef>>;
@@ -0,0 +1,30 @@
1
+ import { defineTool } from "@earendil-works/pi-coding-agent";
2
+ /**
3
+ * Create a terminating tool that captures validated params as the subagent result.
4
+ *
5
+ * Pi validates `params` against `schema` before execute() is called. Returning
6
+ * `terminate: true` lets the subagent finish on this tool call without paying for
7
+ * an extra assistant follow-up turn.
8
+ */
9
+ export function createStructuredOutputTool({ schema, capture, name = "structured_output", }) {
10
+ return defineTool({
11
+ name,
12
+ label: "Structured Output",
13
+ description: "Return the final machine-readable result for this subagent task.",
14
+ promptSnippet: "Return final machine-readable output",
15
+ promptGuidelines: [
16
+ `${name} is the final answer channel for this task; call ${name} exactly once when done.`,
17
+ `Do not write a prose final answer after calling ${name}.`,
18
+ ],
19
+ parameters: schema,
20
+ async execute(_toolCallId, params) {
21
+ capture.value = params;
22
+ capture.called = true;
23
+ return {
24
+ content: [{ type: "text", text: "Structured output received." }],
25
+ details: params,
26
+ terminate: true,
27
+ };
28
+ },
29
+ });
30
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Workflow manager for background execution, pause/resume, and run management.
3
+ */
4
+ import { EventEmitter } from "node:events";
5
+ import type { WorkflowSnapshot } from "./display.js";
6
+ import { WorkflowError } from "./errors.js";
7
+ import { type PersistedRunState, type RunPersistence, type RunStatus } from "./run-persistence.js";
8
+ import { type WorkflowRunResult } from "./workflow.js";
9
+ export interface ManagedRun {
10
+ runId: string;
11
+ status: RunStatus;
12
+ snapshot: WorkflowSnapshot;
13
+ result?: WorkflowRunResult;
14
+ error?: WorkflowError;
15
+ controller: AbortController;
16
+ startedAt: Date;
17
+ }
18
+ export interface WorkflowManagerOptions {
19
+ cwd?: string;
20
+ concurrency?: number;
21
+ }
22
+ export declare class WorkflowManager extends EventEmitter {
23
+ private runs;
24
+ private persistence;
25
+ private cwd;
26
+ private concurrency;
27
+ constructor(options?: WorkflowManagerOptions);
28
+ /**
29
+ * Start a workflow in the background.
30
+ * Returns immediately with a run ID; the workflow executes asynchronously.
31
+ */
32
+ startInBackground(script: string, args?: unknown): {
33
+ runId: string;
34
+ promise: Promise<WorkflowRunResult>;
35
+ };
36
+ /**
37
+ * Execute a workflow synchronously (blocking).
38
+ */
39
+ runSync(script: string, args?: unknown): Promise<WorkflowRunResult>;
40
+ private executeRun;
41
+ private persistRun;
42
+ /**
43
+ * Pause a running workflow.
44
+ */
45
+ pause(runId: string): boolean;
46
+ /**
47
+ * Resume a paused workflow.
48
+ */
49
+ resume(runId: string): Promise<boolean>;
50
+ /**
51
+ * Stop a running workflow.
52
+ */
53
+ stop(runId: string): boolean;
54
+ /**
55
+ * Get status of a specific run.
56
+ */
57
+ getRun(runId: string): ManagedRun | undefined;
58
+ /**
59
+ * List all runs (active + persisted).
60
+ */
61
+ listRuns(): PersistedRunState[];
62
+ /**
63
+ * Get snapshot of a run.
64
+ */
65
+ getSnapshot(runId: string): WorkflowSnapshot | null;
66
+ /**
67
+ * Delete a persisted run.
68
+ */
69
+ deleteRun(runId: string): boolean;
70
+ /**
71
+ * Get the persistence layer (for saving workflows).
72
+ */
73
+ getPersistence(): RunPersistence;
74
+ }
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Workflow manager for background execution, pause/resume, and run management.
3
+ */
4
+ import { EventEmitter } from "node:events";
5
+ import { WorkflowError, WorkflowErrorCode } from "./errors.js";
6
+ import { createRunPersistence, generateRunId, } from "./run-persistence.js";
7
+ import { parseWorkflowScript, runWorkflow } from "./workflow.js";
8
+ export class WorkflowManager extends EventEmitter {
9
+ runs = new Map();
10
+ persistence;
11
+ cwd;
12
+ concurrency;
13
+ constructor(options = {}) {
14
+ super();
15
+ this.cwd = options.cwd ?? process.cwd();
16
+ this.concurrency = options.concurrency ?? 8;
17
+ this.persistence = createRunPersistence(this.cwd);
18
+ }
19
+ /**
20
+ * Start a workflow in the background.
21
+ * Returns immediately with a run ID; the workflow executes asynchronously.
22
+ */
23
+ startInBackground(script, args) {
24
+ const runId = generateRunId();
25
+ const controller = new AbortController();
26
+ const parsed = parseWorkflowScript(script);
27
+ const managed = {
28
+ runId,
29
+ status: "running",
30
+ snapshot: {
31
+ name: parsed.meta.name,
32
+ description: parsed.meta.description,
33
+ phases: parsed.meta.phases?.map((p) => p.title) ?? [],
34
+ logs: [],
35
+ agents: [],
36
+ agentCount: 0,
37
+ runningCount: 0,
38
+ doneCount: 0,
39
+ errorCount: 0,
40
+ },
41
+ controller,
42
+ startedAt: new Date(),
43
+ };
44
+ this.runs.set(runId, managed);
45
+ // Persist initial state
46
+ this.persistence.save({
47
+ runId,
48
+ workflowName: parsed.meta.name,
49
+ script,
50
+ args,
51
+ status: "running",
52
+ phases: managed.snapshot.phases,
53
+ agents: [],
54
+ logs: [],
55
+ startedAt: managed.startedAt.toISOString(),
56
+ updatedAt: managed.startedAt.toISOString(),
57
+ });
58
+ // Run workflow asynchronously
59
+ const promise = this.executeRun(managed, script, args);
60
+ return { runId, promise };
61
+ }
62
+ /**
63
+ * Execute a workflow synchronously (blocking).
64
+ */
65
+ async runSync(script, args) {
66
+ const runId = generateRunId();
67
+ const controller = new AbortController();
68
+ const parsed = parseWorkflowScript(script);
69
+ const managed = {
70
+ runId,
71
+ status: "running",
72
+ snapshot: {
73
+ name: parsed.meta.name,
74
+ description: parsed.meta.description,
75
+ phases: parsed.meta.phases?.map((p) => p.title) ?? [],
76
+ logs: [],
77
+ agents: [],
78
+ agentCount: 0,
79
+ runningCount: 0,
80
+ doneCount: 0,
81
+ errorCount: 0,
82
+ },
83
+ controller,
84
+ startedAt: new Date(),
85
+ };
86
+ this.runs.set(runId, managed);
87
+ return this.executeRun(managed, script, args);
88
+ }
89
+ async executeRun(managed, script, args) {
90
+ try {
91
+ const result = await runWorkflow(script, {
92
+ cwd: this.cwd,
93
+ args,
94
+ signal: managed.controller.signal,
95
+ concurrency: this.concurrency,
96
+ onLog: (message) => {
97
+ managed.snapshot.logs.push(message);
98
+ this.emit("log", { runId: managed.runId, message });
99
+ },
100
+ onPhase: (title) => {
101
+ managed.snapshot.currentPhase = title;
102
+ if (!managed.snapshot.phases.includes(title)) {
103
+ managed.snapshot.phases.push(title);
104
+ }
105
+ this.emit("phase", { runId: managed.runId, title });
106
+ },
107
+ onAgentStart: (event) => {
108
+ managed.snapshot.agents.push({
109
+ id: managed.snapshot.agents.length + 1,
110
+ label: event.label,
111
+ phase: event.phase,
112
+ prompt: event.prompt,
113
+ status: "running",
114
+ });
115
+ this.emit("agentStart", { runId: managed.runId, ...event });
116
+ },
117
+ onAgentEnd: (event) => {
118
+ const agent = [...managed.snapshot.agents]
119
+ .reverse()
120
+ .find((a) => a.label === event.label && a.status === "running");
121
+ if (agent) {
122
+ agent.status = event.result === null ? "error" : "done";
123
+ }
124
+ this.emit("agentEnd", { runId: managed.runId, ...event });
125
+ },
126
+ });
127
+ managed.status = "completed";
128
+ managed.result = result;
129
+ this.emit("complete", { runId: managed.runId, result });
130
+ // Persist final state
131
+ this.persistRun(managed);
132
+ return result;
133
+ }
134
+ catch (error) {
135
+ const workflowError = error instanceof WorkflowError
136
+ ? error
137
+ : new WorkflowError(error instanceof Error ? error.message : String(error), WorkflowErrorCode.WORKFLOW_ABORTED, { recoverable: true });
138
+ if (managed.controller.signal.aborted) {
139
+ managed.status = "aborted";
140
+ }
141
+ else {
142
+ managed.status = "failed";
143
+ }
144
+ managed.error = workflowError;
145
+ this.emit("error", { runId: managed.runId, error: workflowError });
146
+ // Persist final state
147
+ this.persistRun(managed);
148
+ throw workflowError;
149
+ }
150
+ }
151
+ persistRun(managed) {
152
+ this.persistence.save({
153
+ runId: managed.runId,
154
+ workflowName: managed.snapshot.name,
155
+ script: "", // Don't persist script for security
156
+ status: managed.status,
157
+ phases: managed.snapshot.phases,
158
+ currentPhase: managed.snapshot.currentPhase,
159
+ agents: managed.snapshot.agents.map((a) => ({
160
+ ...a,
161
+ startedAt: managed.startedAt.toISOString(),
162
+ endedAt: new Date().toISOString(),
163
+ })),
164
+ logs: managed.snapshot.logs,
165
+ result: managed.result?.result,
166
+ startedAt: managed.startedAt.toISOString(),
167
+ updatedAt: new Date().toISOString(),
168
+ completedAt: managed.status === "completed" ? new Date().toISOString() : undefined,
169
+ durationMs: managed.result?.durationMs,
170
+ });
171
+ }
172
+ /**
173
+ * Pause a running workflow.
174
+ */
175
+ pause(runId) {
176
+ const managed = this.runs.get(runId);
177
+ if (managed?.status !== "running")
178
+ return false;
179
+ managed.controller.abort();
180
+ managed.status = "paused";
181
+ this.emit("paused", { runId });
182
+ this.persistRun(managed);
183
+ return true;
184
+ }
185
+ /**
186
+ * Resume a paused workflow.
187
+ */
188
+ async resume(runId) {
189
+ const persisted = this.persistence.load(runId);
190
+ if (persisted?.status !== "paused")
191
+ return false;
192
+ // For now, resume creates a fresh run with completed agents' results cached
193
+ // Full resume would require re-executing the script with cached results
194
+ this.emit("resumed", { runId });
195
+ return true;
196
+ }
197
+ /**
198
+ * Stop a running workflow.
199
+ */
200
+ stop(runId) {
201
+ const managed = this.runs.get(runId);
202
+ if (!managed || (managed.status !== "running" && managed.status !== "paused"))
203
+ return false;
204
+ managed.controller.abort();
205
+ managed.status = "aborted";
206
+ this.emit("stopped", { runId });
207
+ this.persistRun(managed);
208
+ return true;
209
+ }
210
+ /**
211
+ * Get status of a specific run.
212
+ */
213
+ getRun(runId) {
214
+ return this.runs.get(runId);
215
+ }
216
+ /**
217
+ * List all runs (active + persisted).
218
+ */
219
+ listRuns() {
220
+ return this.persistence.list();
221
+ }
222
+ /**
223
+ * Get snapshot of a run.
224
+ */
225
+ getSnapshot(runId) {
226
+ return this.runs.get(runId)?.snapshot ?? null;
227
+ }
228
+ /**
229
+ * Delete a persisted run.
230
+ */
231
+ deleteRun(runId) {
232
+ this.runs.delete(runId);
233
+ return this.persistence.delete(runId);
234
+ }
235
+ /**
236
+ * Get the persistence layer (for saving workflows).
237
+ */
238
+ getPersistence() {
239
+ return this.persistence;
240
+ }
241
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Save and load reusable workflow commands.
3
+ */
4
+ export interface SavedWorkflow {
5
+ /** Command name (filename without extension). */
6
+ name: string;
7
+ /** Human-readable description. */
8
+ description: string;
9
+ /** The workflow script. */
10
+ script: string;
11
+ /** Optional parameter schema for parameterized workflows. */
12
+ parameters?: Record<string, {
13
+ type: string;
14
+ description?: string;
15
+ required?: boolean;
16
+ default?: unknown;
17
+ }>;
18
+ /** Where this workflow is saved. */
19
+ location: "project" | "user";
20
+ /** Full file path. */
21
+ path: string;
22
+ /** When it was saved. */
23
+ savedAt: string;
24
+ }
25
+ export interface WorkflowStorage {
26
+ /** Save a workflow. */
27
+ save(workflow: Omit<SavedWorkflow, "path" | "savedAt">, location?: "project" | "user"): SavedWorkflow;
28
+ /** Load a workflow by name. */
29
+ load(name: string): SavedWorkflow | null;
30
+ /** List all saved workflows. */
31
+ list(): SavedWorkflow[];
32
+ /** Delete a saved workflow. */
33
+ delete(name: string, location?: "project" | "user"): boolean;
34
+ }
35
+ export declare function createWorkflowStorage(cwd: string): WorkflowStorage;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Save and load reusable workflow commands.
3
+ */
4
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { USER_WORKFLOW_SAVED_DIR, WORKFLOW_SAVED_DIR } from "./config.js";
7
+ export function createWorkflowStorage(cwd) {
8
+ const projectDir = join(cwd, WORKFLOW_SAVED_DIR);
9
+ const userDir = USER_WORKFLOW_SAVED_DIR.replace("~", process.env.HOME ?? "");
10
+ const ensureDir = (dir) => {
11
+ if (!existsSync(dir)) {
12
+ mkdirSync(dir, { recursive: true });
13
+ }
14
+ };
15
+ const workflowPath = (name, location) => {
16
+ const dir = location === "project" ? projectDir : userDir;
17
+ return join(dir, `${name}.json`);
18
+ };
19
+ const loadFromFile = (path, location) => {
20
+ try {
21
+ if (!existsSync(path))
22
+ return null;
23
+ const data = JSON.parse(readFileSync(path, "utf-8"));
24
+ return {
25
+ ...data,
26
+ location,
27
+ path,
28
+ };
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ };
34
+ return {
35
+ save(workflow, location = "project") {
36
+ const dir = location === "project" ? projectDir : userDir;
37
+ ensureDir(dir);
38
+ const path = workflowPath(workflow.name, location);
39
+ const saved = {
40
+ ...workflow,
41
+ location,
42
+ path,
43
+ savedAt: new Date().toISOString(),
44
+ };
45
+ writeFileSync(path, JSON.stringify(saved, null, 2));
46
+ return saved;
47
+ },
48
+ load(name) {
49
+ // Project takes precedence over user
50
+ const projectPath = workflowPath(name, "project");
51
+ const project = loadFromFile(projectPath, "project");
52
+ if (project)
53
+ return project;
54
+ const userPath = workflowPath(name, "user");
55
+ return loadFromFile(userPath, "user");
56
+ },
57
+ list() {
58
+ const workflows = [];
59
+ // Load project workflows
60
+ if (existsSync(projectDir)) {
61
+ for (const file of readdirSync(projectDir).filter((f) => f.endsWith(".json"))) {
62
+ const wf = loadFromFile(join(projectDir, file), "project");
63
+ if (wf)
64
+ workflows.push(wf);
65
+ }
66
+ }
67
+ // Load user workflows
68
+ if (existsSync(userDir)) {
69
+ for (const file of readdirSync(userDir).filter((f) => f.endsWith(".json"))) {
70
+ const wf = loadFromFile(join(userDir, file), "user");
71
+ if (wf)
72
+ workflows.push(wf);
73
+ }
74
+ }
75
+ return workflows.sort((a, b) => a.name.localeCompare(b.name));
76
+ },
77
+ delete(name, location) {
78
+ const locations = location ? [location] : ["project", "user"];
79
+ let deleted = false;
80
+ for (const loc of locations) {
81
+ const path = workflowPath(name, loc);
82
+ if (existsSync(path)) {
83
+ const { unlinkSync } = require("node:fs");
84
+ unlinkSync(path);
85
+ deleted = true;
86
+ }
87
+ }
88
+ return deleted;
89
+ },
90
+ };
91
+ }
@@ -0,0 +1,22 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+ declare const workflowToolSchema: Type.TObject<{
4
+ script: Type.TString;
5
+ args: Type.TOptional<Type.TAny>;
6
+ background: Type.TOptional<Type.TBoolean>;
7
+ maxAgents: Type.TOptional<Type.TNumber>;
8
+ agentTimeoutMs: Type.TOptional<Type.TNumber>;
9
+ }>;
10
+ export type WorkflowToolInput = {
11
+ script: string;
12
+ args?: unknown;
13
+ background?: boolean;
14
+ maxAgents?: number;
15
+ agentTimeoutMs?: number;
16
+ };
17
+ export interface WorkflowToolOptions {
18
+ cwd?: string;
19
+ concurrency?: number;
20
+ }
21
+ export declare function createWorkflowTool(options?: WorkflowToolOptions): ToolDefinition<typeof workflowToolSchema, any>;
22
+ export {};