pi-extensible-workflows 1.0.1 → 2.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.
@@ -0,0 +1,74 @@
1
+ import { execFile } from "node:child_process";
2
+ import { fileURLToPath } from "node:url";
3
+ const runHerdr = (args) => new Promise((resolve, reject) => {
4
+ execFile("herdr", [...args], { encoding: "utf8", maxBuffer: 1024 * 1024 }, (error, stdout) => {
5
+ if (error) {
6
+ reject(new Error(error.message));
7
+ return;
8
+ }
9
+ resolve(stdout);
10
+ });
11
+ });
12
+ export function herdrPaneId(env = process.env) {
13
+ if (env.HERDR_ENV !== "1")
14
+ return undefined;
15
+ const paneId = env.HERDR_PANE_ID?.trim();
16
+ return paneId || undefined;
17
+ }
18
+ function shellQuote(value) { return `'${value.replace(/'/g, `'\\''`)}'`; }
19
+ function json(value) { return JSON.parse(value); }
20
+ function record(value) { return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined; }
21
+ function paneLayout(value, targetPane) {
22
+ const root = record(value);
23
+ const result = record(root?.result);
24
+ const layout = record(result?.layout);
25
+ const rawPanes = layout?.panes;
26
+ if (!Array.isArray(rawPanes))
27
+ throw new Error("Herdr returned an invalid pane layout.");
28
+ const panes = rawPanes;
29
+ const pane = panes.find((candidate) => record(candidate)?.pane_id === targetPane);
30
+ const rect = record(record(pane)?.rect);
31
+ const width = rect?.width;
32
+ const height = rect?.height;
33
+ if (width === undefined || height === undefined || typeof width !== "number" || typeof height !== "number")
34
+ throw new Error("Herdr returned an invalid target pane geometry.");
35
+ return { width, height };
36
+ }
37
+ function splitPaneId(value) {
38
+ const pane = record(record(record(value)?.result)?.pane);
39
+ const paneId = pane?.pane_id;
40
+ if (typeof paneId !== "string" || !paneId)
41
+ throw new Error("Herdr returned an invalid created pane ID.");
42
+ return paneId;
43
+ }
44
+ function commandFor(request) {
45
+ const cliPath = fileURLToPath(new URL("./cli.js", import.meta.resolve("pi-extensible-workflows")));
46
+ const environment = ["PI_CODING_AGENT_DIR", "PI_CODING_AGENT_SESSION_DIR"].flatMap((name) => process.env[name] === undefined ? [] : [`${name}=${shellQuote(process.env[name] ?? "")}`]);
47
+ const command = request.action === "inspect"
48
+ ? [shellQuote(process.execPath), shellQuote(cliPath), "inspect", shellQuote(request.sessionId ?? "")]
49
+ : request.action === "transcript"
50
+ ? [shellQuote(process.execPath), shellQuote(cliPath), "transcript", shellQuote(request.original ?? "")]
51
+ : ["pi", "--fork", shellQuote(request.original ?? ""), ...(request.readOnly ? ["--tools", shellQuote("read,grep,find,ls")] : [])];
52
+ return `cd ${shellQuote(request.cwd)} && ${environment.length ? `${environment.join(" ")} ` : ""}${command.join(" ")}`;
53
+ }
54
+ export function herdrPaneCommand(request) { return commandFor(request); }
55
+ export async function openHerdrPane(request, runner = runHerdr) {
56
+ const targetPane = herdrPaneId();
57
+ if (!targetPane)
58
+ throw new Error("Pane actions require a Herdr-managed session with HERDR_PANE_ID.");
59
+ if (!request.cwd)
60
+ throw new Error("Pane actions require a working directory.");
61
+ if ((request.action === "inspect" && !request.sessionId) || (request.action !== "inspect" && !request.original))
62
+ throw new Error("Pane action is missing its session source.");
63
+ const layout = paneLayout(json(await runner(["pane", "layout", "--pane", targetPane])), targetPane);
64
+ const direction = layout.width > layout.height ? "right" : "down";
65
+ const paneId = splitPaneId(json(await runner(["pane", "split", targetPane, "--direction", direction, "--no-focus"])));
66
+ try {
67
+ await runner(["pane", "run", paneId, commandFor(request)]);
68
+ return paneId;
69
+ }
70
+ catch (error) {
71
+ await runner(["pane", "close", paneId]).catch(() => undefined);
72
+ throw error;
73
+ }
74
+ }
@@ -5,7 +5,7 @@ import { RunStore } from "./persistence.js";
5
5
  import type { AwaitingCheckpoint, PersistedRun, WorktreeReference } from "./persistence.js";
6
6
  export declare const RUN_STATES: readonly ["queued", "running", "pausing", "paused", "awaiting_input", "completed", "failed", "stopped", "interrupted", "budget_exhausted"];
7
7
  export declare const AGENT_STATES: readonly ["queued", "running", "waiting_for_child", "paused", "retrying", "completed", "failed", "cancelled"];
8
- export declare const WORKFLOW_CALL_KINDS: readonly ["agent", "conversation", "parallel", "pipeline", "checkpoint", "phase", "withWorktree"];
8
+ export declare const WORKFLOW_CALL_KINDS: readonly ["agent", "conversation", "parallel", "pipeline", "checkpoint", "phase", "withWorktree", "shell"];
9
9
  export type WorkflowCallKind = (typeof WORKFLOW_CALL_KINDS)[number];
10
10
  export declare const WORKFLOW_RUN_STARTED_EVENT = "workflow:run-started";
11
11
  export declare const WORKFLOW_RUN_RESUMED_EVENT = "workflow:run-resumed";
@@ -17,7 +17,7 @@ export declare const WORKFLOW_PHASE_CHANGED_EVENT = "workflow:phase-changed";
17
17
  export declare const WORKFLOW_CHECKPOINT_STATE_CHANGED_EVENT = "workflow:checkpoint-state-changed";
18
18
  export declare const WORKFLOW_BUDGET_EVENT = "workflow:budget-event";
19
19
  export declare const WORKFLOW_WORKTREE_CREATED_EVENT = "workflow:worktree-created";
20
- export declare const ERROR_CODES: readonly ["CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT_TYPE", "RUN_OWNED", "REGISTRY_FROZEN", "GLOBAL_COLLISION", "MISSING_WORKFLOW", "RPC_LIMIT_EXCEEDED", "AGENT_TIMEOUT", "AGENT_FAILED", "RESULT_INVALID", "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR"];
20
+ export declare const ERROR_CODES: readonly ["CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT_TYPE", "RUN_OWNED", "REGISTRY_FROZEN", "GLOBAL_COLLISION", "MISSING_WORKFLOW", "RPC_LIMIT_EXCEEDED", "SHELL_FAILED", "AGENT_TIMEOUT", "AGENT_FAILED", "RESULT_INVALID", "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR"];
21
21
  export type RunState = (typeof RUN_STATES)[number];
22
22
  export type AgentState = (typeof AGENT_STATES)[number];
23
23
  export type WorkflowErrorCode = (typeof ERROR_CODES)[number];
@@ -27,6 +27,15 @@ export type JsonValue = null | boolean | number | string | JsonValue[] | {
27
27
  export type JsonSchema = {
28
28
  [key: string]: JsonValue;
29
29
  };
30
+ export interface ShellOptions {
31
+ timeoutMs?: number;
32
+ env?: Record<string, string>;
33
+ }
34
+ export interface ShellResult {
35
+ exitCode: number | null;
36
+ stdout: string;
37
+ stderr: string;
38
+ }
30
39
  export type BudgetDimension = "tokens" | "costUsd" | "durationMs" | "agentLaunches";
31
40
  export interface BudgetLimits {
32
41
  soft?: number;
@@ -184,6 +193,10 @@ export interface WorkflowWorktreeCreatedEvent extends WorkflowEventBase {
184
193
  path: string;
185
194
  base: string;
186
195
  }
196
+ export interface WorkflowWorktreeReference {
197
+ readonly path: string;
198
+ readonly branch: string;
199
+ }
187
200
  export interface AgentRecord {
188
201
  id: string;
189
202
  name: string;
@@ -224,6 +237,7 @@ export interface RunRecord {
224
237
  cwd: string;
225
238
  sessionId: string;
226
239
  state: RunState;
240
+ parentRunId?: string;
227
241
  phase?: string;
228
242
  agents: readonly AgentRecord[];
229
243
  error?: WorkflowErrorShape;
@@ -233,9 +247,11 @@ export interface RunRecord {
233
247
  budgetEvents?: readonly BudgetEvent[];
234
248
  events?: readonly WorkflowRunEvent[];
235
249
  }
236
- export declare const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 3;
250
+ export declare const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 4;
237
251
  export interface LaunchSnapshot {
238
252
  identityVersion?: number;
253
+ launchKind?: "inline" | "function";
254
+ functionName?: string;
239
255
  script: string;
240
256
  args: JsonValue;
241
257
  metadata: WorkflowMetadata;
@@ -272,10 +288,14 @@ export interface PreflightResult {
272
288
  }
273
289
  export interface WorkflowOrchestrationContext {
274
290
  agent: (...args: readonly unknown[]) => Promise<JsonValue>;
291
+ shell: (command: string, options?: ShellOptions) => Promise<ShellResult>;
275
292
  prompt: (template: string, values: Readonly<Record<string, JsonValue>>) => string;
276
293
  parallel: (...args: readonly unknown[]) => Promise<JsonValue>;
277
294
  pipeline: (...args: readonly unknown[]) => Promise<JsonValue>;
278
- withWorktree: (...args: readonly unknown[]) => Promise<JsonValue>;
295
+ withWorktree: {
296
+ (callback: WorkflowWorktreeCallback): Promise<JsonValue>;
297
+ (name: string, callback: WorkflowWorktreeCallback): Promise<JsonValue>;
298
+ };
279
299
  checkpoint: (...args: readonly unknown[]) => Promise<boolean>;
280
300
  phase: (name: string) => void;
281
301
  log: (message: string) => void;
@@ -292,6 +312,7 @@ export interface WorkflowFunctionContext extends WorkflowOrchestrationContext {
292
312
  run: Readonly<WorkflowRunContext>;
293
313
  invoke: (name: string, input: Readonly<Record<string, JsonValue>>) => Promise<JsonValue>;
294
314
  }
315
+ export type WorkflowWorktreeCallback = (reference: Readonly<WorkflowWorktreeReference>) => JsonValue | Promise<JsonValue>;
295
316
  export interface WorkflowFunction {
296
317
  description: string;
297
318
  input: JsonSchema;
@@ -303,17 +324,12 @@ export interface WorkflowVariable {
303
324
  schema: JsonSchema;
304
325
  resolve: (run: Readonly<WorkflowRunContext>) => Promise<JsonValue> | JsonValue;
305
326
  }
306
- export interface WorkflowScriptDefinition {
307
- description: string;
308
- script: string;
309
- }
310
327
  export interface WorkflowExtension {
311
328
  version: string;
312
329
  headline: string;
313
330
  description: string;
314
331
  functions?: Readonly<Record<string, WorkflowFunction>>;
315
332
  variables?: Readonly<Record<string, WorkflowVariable>>;
316
- workflows?: Readonly<Record<string, WorkflowScriptDefinition>>;
317
333
  agentSetupHooks?: Readonly<Record<string, AgentSetupHook>>;
318
334
  }
319
335
  export interface WorkflowJournal {
@@ -324,6 +340,36 @@ export declare class WorkflowError extends Error {
324
340
  readonly code: WorkflowErrorCode;
325
341
  constructor(code: WorkflowErrorCode, message: string);
326
342
  }
343
+ export interface WorkflowFailureAgent {
344
+ id: string;
345
+ label?: string;
346
+ role?: string;
347
+ structuralPath: readonly string[];
348
+ attempt: number;
349
+ sessionId?: string;
350
+ sessionFile?: string;
351
+ }
352
+ export interface WorkflowSiblingAgent {
353
+ id: string;
354
+ label?: string;
355
+ role?: string;
356
+ structuralPath: readonly string[];
357
+ }
358
+ export interface WorkflowFailureDiagnostics {
359
+ runId: string;
360
+ workflowName: string;
361
+ state: RunState;
362
+ failedAt: string | null;
363
+ error: WorkflowErrorShape;
364
+ failedAgent?: WorkflowFailureAgent;
365
+ completedSiblingAgents?: readonly WorkflowSiblingAgent[];
366
+ completedSiblingPaths: readonly (readonly string[])[];
367
+ artifacts: {
368
+ runDirectory: string;
369
+ statePath: string;
370
+ journalPath: string;
371
+ };
372
+ }
327
373
  export declare function formatWorkflowFailure(error: unknown): string;
328
374
  export declare class RunLifecycle {
329
375
  #private;
@@ -431,27 +477,43 @@ export interface WorkflowCatalogVariable {
431
477
  description: string;
432
478
  schema: JsonSchema;
433
479
  }
434
- export interface WorkflowCatalogWorkflow {
435
- name: string;
436
- version: string;
437
- headline: string;
438
- extensionDescription: string;
439
- description: string;
440
- }
441
480
  export interface WorkflowCatalog {
442
481
  functions: readonly WorkflowCatalogFunction[];
443
482
  variables: readonly WorkflowCatalogVariable[];
444
- workflows: readonly WorkflowCatalogWorkflow[];
445
483
  modelAliases?: Readonly<Record<string, string>>;
446
484
  }
485
+ export interface WorkflowCatalogIndexFunction {
486
+ name: string;
487
+ description: string;
488
+ input: JsonSchema;
489
+ }
490
+ export interface WorkflowCatalogIndexVariable {
491
+ name: string;
492
+ description: string;
493
+ schema: JsonSchema;
494
+ }
495
+ export interface WorkflowCatalogIndex {
496
+ functions: readonly WorkflowCatalogIndexFunction[];
497
+ variables: readonly WorkflowCatalogIndexVariable[];
498
+ modelAliases?: Readonly<Record<string, string>>;
499
+ }
500
+ export interface WorkflowCatalogError {
501
+ error: {
502
+ code: "NOT_FOUND";
503
+ name: string;
504
+ message: string;
505
+ };
506
+ }
447
507
  export declare class WorkflowRegistry {
448
508
  #private;
449
509
  get frozen(): boolean;
450
510
  freeze(): void;
451
511
  register(extension: WorkflowExtension): void;
452
- workflow(name: string): WorkflowScriptDefinition;
453
- workflows(): Readonly<Record<string, WorkflowScriptDefinition>>;
512
+ function(name: string): WorkflowFunction;
513
+ functions(): Readonly<Record<string, WorkflowFunction>>;
454
514
  catalog(): WorkflowCatalog;
515
+ catalogIndex(): WorkflowCatalogIndex;
516
+ catalogDetail(name: string): WorkflowCatalogFunction | WorkflowCatalogVariable | WorkflowCatalogError;
455
517
  globals(): Readonly<Record<string, {
456
518
  name: string;
457
519
  }>>;
@@ -464,7 +526,9 @@ export declare class WorkflowRegistry {
464
526
  }
465
527
  export declare function registerWorkflowExtension(extension: WorkflowExtension): void;
466
528
  export declare function workflowCatalog(): WorkflowCatalog;
467
- export declare function registeredWorkflowDefinitions(): Readonly<Record<string, WorkflowScriptDefinition>>;
529
+ export declare function workflowCatalogIndex(): WorkflowCatalogIndex;
530
+ export declare function workflowCatalogDetail(name: string): WorkflowCatalogFunction | WorkflowCatalogVariable | WorkflowCatalogError;
531
+ export declare function registeredWorkflowFunctions(): Readonly<Record<string, WorkflowFunction>>;
468
532
  export declare function formatWorkflowPreview(args: {
469
533
  script?: unknown;
470
534
  workflow?: unknown;
@@ -473,7 +537,7 @@ export declare function formatWorkflowPreview(args: {
473
537
  }): string;
474
538
  export declare const WORKFLOW_TOOL_LABEL = "Workflow";
475
539
  export declare const WORKFLOW_TOOL_DESCRIPTION = "Run a deterministic JavaScript workflow";
476
- export declare const WORKFLOW_TOOL_PROMPT_SNIPPET = "Run a deterministic, resumable JavaScript workflow that orchestrates subagents. Inline scripts require a name; registered workflows use their workflow name. Runs in the background by default; completion arrives as a follow-up message.";
540
+ export declare const WORKFLOW_TOOL_PROMPT_SNIPPET = "Run a deterministic, resumable JavaScript workflow that orchestrates subagents. Inline scripts require a name; registered functions use their function name. Runs in the background by default; completion arrives as a follow-up message. Foreground results include the completed run ID, and parentRunId reuses matching named worktrees from a terminal run.";
477
541
  export declare const WORKFLOW_TOOL_PARAMETERS: Type.TObject<{
478
542
  name: Type.TOptional<Type.TString>;
479
543
  description: Type.TOptional<Type.TString>;
@@ -483,6 +547,7 @@ export declare const WORKFLOW_TOOL_PARAMETERS: Type.TObject<{
483
547
  foreground: Type.TOptional<Type.TBoolean>;
484
548
  concurrency: Type.TOptional<Type.TInteger>;
485
549
  budget: Type.TOptional<Type.TUnknown>;
550
+ parentRunId: Type.TOptional<Type.TString>;
486
551
  }>;
487
552
  export declare function preflight(script: string, capabilities: PreflightCapabilities, schemas?: readonly unknown[], metadata?: WorkflowMetadata): PreflightResult;
488
553
  export interface WorkflowValidationParameters {
@@ -490,6 +555,7 @@ export interface WorkflowValidationParameters {
490
555
  description?: string;
491
556
  script?: string;
492
557
  workflow?: string;
558
+ args?: unknown;
493
559
  }
494
560
  export interface WorkflowValidationContext {
495
561
  cwd: string;
@@ -499,6 +565,7 @@ export interface WorkflowValidationContext {
499
565
  modelAliases?: Readonly<Record<string, string>>;
500
566
  knownModels?: ReadonlySet<string>;
501
567
  settingsPath?: string;
568
+ agentDir?: string;
502
569
  }
503
570
  export interface ValidatedWorkflowLaunch {
504
571
  script: string;
@@ -506,6 +573,7 @@ export interface ValidatedWorkflowLaunch {
506
573
  agentDefinitions: Readonly<Record<string, AgentDefinition>>;
507
574
  projectAgentDefinitions: Readonly<Record<string, AgentDefinition>>;
508
575
  roleNames: readonly string[];
576
+ functionName?: string;
509
577
  }
510
578
  export declare function validateWorkflowLaunch(params: WorkflowValidationParameters, context: WorkflowValidationContext): ValidatedWorkflowLaunch;
511
579
  type LaunchSnapshotInput = Omit<LaunchSnapshot, "identityVersion"> & {
@@ -526,10 +594,18 @@ export interface AgentIdentity {
526
594
  turn: number;
527
595
  };
528
596
  }
597
+ export interface ShellIdentity {
598
+ structuralPath: readonly string[];
599
+ callSite: string;
600
+ occurrence: number;
601
+ worktreeOwner?: string;
602
+ }
529
603
  export interface WorkflowBridge {
530
604
  agent?: (prompt: string, options: Readonly<Record<string, JsonValue>>, signal: AbortSignal, identity: AgentIdentity) => Promise<JsonValue>;
605
+ shell?: (command: string, options: ShellOptions, signal: AbortSignal, identity: ShellIdentity) => Promise<ShellResult>;
531
606
  checkpoint?: (input: Readonly<Record<string, JsonValue>>, signal: AbortSignal) => boolean | Promise<boolean>;
532
607
  function?: (name: string, input: Readonly<Record<string, JsonValue>>, path: string, signal: AbortSignal, worktreeOwner?: string, structuralPath?: readonly string[]) => Promise<JsonValue>;
608
+ worktree?: (owner: string, signal: AbortSignal) => Promise<Readonly<WorkflowWorktreeReference>>;
533
609
  functions?: Readonly<Record<string, {
534
610
  name: string;
535
611
  }>>;
@@ -551,10 +627,11 @@ export declare function formatNavigatorRun(loaded: {
551
627
  run: PersistedRun;
552
628
  snapshot: Readonly<LaunchSnapshot>;
553
629
  }, checkpoints: readonly AwaitingCheckpoint[], _worktrees: readonly WorktreeReference[]): string;
554
- export default function workflowExtension(pi: ExtensionAPI, home?: string, clipboard?: typeof copyToClipboard, createSession?: SessionFactory): void;
630
+ export declare function formatWorkflowFailureDiagnostics(diagnostic: WorkflowFailureDiagnostics): string;
631
+ export default function workflowExtension(pi: ExtensionAPI, home?: string, clipboard?: typeof copyToClipboard, createSession?: SessionFactory, agentDir?: string): void;
555
632
  export { acquireSessionLease, projectStorageKey, RunStore, runsDirectory, SessionLease, structuralPath } from "./persistence.js";
556
633
  export type { AwaitingCheckpoint, CompletedOperation, ConversationHead, NativeSessionReference, PendingWorkflowDecision, PersistedConversation, PersistedOwnershipNode, PersistedRun, WorktreeReference } from "./persistence.js";
557
634
  export { FairAgentScheduler, WorkflowAgentExecutor } from "./agent-execution.js";
558
- export type { AgentAccounting, AgentAttempt, AgentBudgetHooks, AgentDefinition, AgentExecutionOptions, AgentExecutionResult, AgentExecutionRoot, AgentProgress, AgentSetup, AgentSetupContext, AgentSetupHook, AgentToolCallProgress, RegisteredAgentSetupHook, SessionInput } from "./agent-execution.js";
635
+ export type { AgentAccounting, AgentAttempt, AgentBudgetHooks, AgentDefinition, AgentExecutionOptions, AgentExecutionResult, AgentExecutionRoot, AgentProgress, AgentProviderFailure, AgentProviderRecovery, AgentSetup, AgentSetupContext, AgentSetupHook, AgentToolCallProgress, RegisteredAgentSetupHook, SessionInput } from "./agent-execution.js";
559
636
  export { doctor, doctorExitCode, formatDoctorReport } from "./doctor.js";
560
- export type { DoctorDiagnostic, DoctorOptions, DoctorPiState, DoctorReport, DoctorRole, DoctorSeverity, DoctorTrust, DoctorWorkflow } from "./doctor.js";
637
+ export type { DoctorDiagnostic, DoctorFunction, DoctorOptions, DoctorPiState, DoctorReport, DoctorRole, DoctorSeverity, DoctorTrust } from "./doctor.js";