@oisincoveney/pipeline 1.3.0 → 1.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.
package/dist/index.js CHANGED
@@ -35809,6 +35809,8 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
35809
35809
  return [
35810
35810
  "exec",
35811
35811
  "--json",
35812
+ "-C",
35813
+ worktreePath,
35812
35814
  ...optionalModelArgs(harness, options2.runner, options2.actor),
35813
35815
  ...mcpArgs,
35814
35816
  ...skillArgs,
@@ -35817,9 +35819,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
35817
35819
  "--config",
35818
35820
  'approval_policy="never"',
35819
35821
  "--skip-git-repo-check",
35820
- prompt,
35821
- "-C",
35822
- worktreePath
35822
+ prompt
35823
35823
  ];
35824
35824
  case "opencode":
35825
35825
  return contextFile ? [
@@ -36404,8 +36404,11 @@ var SCAFFOLD_FILES = {
36404
36404
  `),
36405
36405
  ".pipeline/prompts/inspector.md": [
36406
36406
  "You are the read-only inspection phase for the pipeline.",
36407
- "Inspect first-party source, tests, docs, and task context.",
36408
- "Report the repository structure, available checks, important files, and notable risks.",
36407
+ "Use a bounded inspection: run at most 8 discovery commands and read at most 12 small, high-signal files.",
36408
+ "Prefer `pwd`, `rg --files -g '!*node_modules*' -g '!dist/**' -g '!build/**' | head -200`, package/workspace manifests, mise/turbo config, and test config files.",
36409
+ "When reading paths with shell metacharacters such as brackets, quote the whole path.",
36410
+ "Do not recursively inspect route trees or generated output.",
36411
+ "Report the app structure, available checks, important files, and notable risks from the sampled evidence.",
36409
36412
  "Do not modify files.",
36410
36413
  ""
36411
36414
  ].join(`
@@ -36932,17 +36935,29 @@ async function runPipelineFromConfig(options2) {
36932
36935
  plan,
36933
36936
  task: options2.task,
36934
36937
  workflowId,
36935
- worktreePath
36938
+ worktreePath,
36939
+ ...options2.reporter ? { reporter: options2.reporter } : {}
36936
36940
  };
36937
36941
  const nodes = [];
36942
+ emit(context, {
36943
+ nodeIds: plan.topologicalOrder.map((node) => node.id),
36944
+ type: "workflow.start",
36945
+ workflowId
36946
+ });
36938
36947
  const startHook = await dispatchHooks(context, "workflow.start");
36939
36948
  if (startHook) {
36940
- return failedRuntimeResult(context, nodes, startHook);
36949
+ const result2 = failedRuntimeResult(context, nodes, startHook);
36950
+ emit(context, {
36951
+ outcome: result2.outcome,
36952
+ type: "workflow.finish",
36953
+ workflowId
36954
+ });
36955
+ return result2;
36941
36956
  }
36942
36957
  for (const batch of plan.parallelBatches) {
36943
36958
  const results = await Promise.all(batch.map((node) => executeNode(node, context)));
36944
36959
  nodes.push(...results);
36945
- const failed = results.find((result) => result.status === "failed");
36960
+ const failed = results.find((result2) => result2.status === "failed");
36946
36961
  if (failed) {
36947
36962
  const failure = {
36948
36963
  evidence: failed.evidence,
@@ -36952,16 +36967,28 @@ async function runPipelineFromConfig(options2) {
36952
36967
  };
36953
36968
  await dispatchHooks(context, "workflow.failure", failure);
36954
36969
  await dispatchHooks(context, "workflow.complete", failure);
36955
- return failedRuntimeResult(context, nodes, failure);
36970
+ const result2 = failedRuntimeResult(context, nodes, failure);
36971
+ emit(context, {
36972
+ outcome: result2.outcome,
36973
+ type: "workflow.finish",
36974
+ workflowId
36975
+ });
36976
+ return result2;
36956
36977
  }
36957
36978
  }
36958
36979
  const successHook = await dispatchHooks(context, "workflow.success");
36959
36980
  const completeHook = await dispatchHooks(context, "workflow.complete");
36960
36981
  const hookFailure = successHook ?? completeHook;
36961
36982
  if (hookFailure) {
36962
- return failedRuntimeResult(context, nodes, hookFailure);
36983
+ const result2 = failedRuntimeResult(context, nodes, hookFailure);
36984
+ emit(context, {
36985
+ outcome: result2.outcome,
36986
+ type: "workflow.finish",
36987
+ workflowId
36988
+ });
36989
+ return result2;
36963
36990
  }
36964
- return {
36991
+ const result = {
36965
36992
  agentInvocations: context.agentInvocations,
36966
36993
  failureDetails: [],
36967
36994
  gates: context.gates,
@@ -36970,6 +36997,12 @@ async function runPipelineFromConfig(options2) {
36970
36997
  outcome: "PASS",
36971
36998
  plan
36972
36999
  };
37000
+ emit(context, {
37001
+ outcome: result.outcome,
37002
+ type: "workflow.finish",
37003
+ workflowId
37004
+ });
37005
+ return result;
36973
37006
  }
36974
37007
  function failedRuntimeResult(context, nodes, failure) {
36975
37008
  return {
@@ -36990,9 +37023,12 @@ async function executeNode(node, context) {
36990
37023
  output: ""
36991
37024
  };
36992
37025
  for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
37026
+ emitNodeStart(context, node, attempt);
36993
37027
  const startHook = await dispatchHooks(context, "node.start", undefined, node);
36994
37028
  if (startHook) {
36995
- return nodeFailure(node.id, attempt, startHook.evidence, last.output);
37029
+ const result2 = nodeFailure(node.id, attempt, startHook.evidence, last.output);
37030
+ emitNodeFinish(context, result2);
37031
+ return result2;
36996
37032
  }
36997
37033
  last = await executeNodeAttempt(node, context);
36998
37034
  context.lastOutputByNode.set(node.id, last.output);
@@ -37001,9 +37037,11 @@ async function executeNode(node, context) {
37001
37037
  if (!failedGate && last.exitCode === 0) {
37002
37038
  const successHook = await dispatchHooks(context, "node.success", undefined, node);
37003
37039
  if (successHook) {
37004
- return nodeFailure(node.id, attempt, successHook.evidence, last.output);
37040
+ const result3 = nodeFailure(node.id, attempt, successHook.evidence, last.output);
37041
+ emitNodeFinish(context, result3);
37042
+ return result3;
37005
37043
  }
37006
- return {
37044
+ const result2 = {
37007
37045
  attempts: attempt,
37008
37046
  evidence: last.evidence,
37009
37047
  exitCode: 0,
@@ -37011,6 +37049,8 @@ async function executeNode(node, context) {
37011
37049
  output: last.output,
37012
37050
  status: "passed"
37013
37051
  };
37052
+ emitNodeFinish(context, result2);
37053
+ return result2;
37014
37054
  }
37015
37055
  const evidence = failedGate?.evidence ?? last.evidence.concat(`node exited with code ${last.exitCode}`);
37016
37056
  if (attempt === maxAttempts) {
@@ -37020,10 +37060,14 @@ async function executeNode(node, context) {
37020
37060
  nodeId: node.id,
37021
37061
  reason: failedGate?.reason ?? `node exited with code ${last.exitCode}`
37022
37062
  }, node);
37023
- return nodeFailure(node.id, attempt, evidence, last.output);
37063
+ const result2 = nodeFailure(node.id, attempt, evidence, last.output);
37064
+ emitNodeFinish(context, result2);
37065
+ return result2;
37024
37066
  }
37025
37067
  }
37026
- return nodeFailure(node.id, maxAttempts, last.evidence, last.output);
37068
+ const result = nodeFailure(node.id, maxAttempts, last.evidence, last.output);
37069
+ emitNodeFinish(context, result);
37070
+ return result;
37027
37071
  }
37028
37072
  function nodeFailure(nodeId, attempts, evidence, output) {
37029
37073
  return {
@@ -37301,6 +37345,13 @@ async function evaluateNodeGates(node, context, attempt) {
37301
37345
  const result = await evaluateGate(gate, node.id, context, attempt);
37302
37346
  context.gates.push(result);
37303
37347
  results.push(result);
37348
+ emit(context, {
37349
+ gateId: result.gateId,
37350
+ nodeId: result.nodeId,
37351
+ passed: result.passed,
37352
+ type: "gate.finish",
37353
+ ...result.reason ? { reason: result.reason } : {}
37354
+ });
37304
37355
  if (!result.passed) {
37305
37356
  await dispatchHooks(context, "gate.failure", {
37306
37357
  evidence: result.evidence,
@@ -37315,6 +37366,28 @@ async function evaluateNodeGates(node, context, attempt) {
37315
37366
  }
37316
37367
  return results;
37317
37368
  }
37369
+ function emit(context, event) {
37370
+ context.reporter?.(event);
37371
+ }
37372
+ function emitNodeStart(context, node, attempt) {
37373
+ const profile = node.profile ? context.config.profiles[node.profile] : undefined;
37374
+ emit(context, {
37375
+ attempt,
37376
+ nodeId: node.id,
37377
+ type: "node.start",
37378
+ ...node.profile ? { profile: node.profile } : {},
37379
+ ...profile?.runner ? { runnerId: profile.runner } : {}
37380
+ });
37381
+ }
37382
+ function emitNodeFinish(context, result) {
37383
+ emit(context, {
37384
+ attempt: result.attempts,
37385
+ exitCode: result.exitCode,
37386
+ nodeId: result.nodeId,
37387
+ status: result.status,
37388
+ type: "node.finish"
37389
+ });
37390
+ }
37318
37391
  async function evaluateGate(gate, nodeId, context, attempt) {
37319
37392
  const gateId = gate.id ?? `${gate.kind}:${nodeId}`;
37320
37393
  if (gate.kind === "command") {
@@ -37554,6 +37627,7 @@ function pipe2(description, options2 = {}) {
37554
37627
  async function runConfiguredPipeline(inputs) {
37555
37628
  const runner = inputs.pipelineRunner ?? runPipelineFromConfig;
37556
37629
  const result = await runner({
37630
+ reporter: formatRuntimeProgress,
37557
37631
  task: inputs.task,
37558
37632
  workflowId: inputs.workflow,
37559
37633
  worktreePath: inputs.worktreePath
@@ -37563,13 +37637,49 @@ async function runConfiguredPipeline(inputs) {
37563
37637
  throw new Error(formatRuntimeFailure(result));
37564
37638
  }
37565
37639
  }
37640
+ function formatRuntimeProgress(event) {
37641
+ switch (event.type) {
37642
+ case "workflow.start":
37643
+ console.error(`Pipeline starting: ${event.workflowId} (${event.nodeIds.join(" -> ")})`);
37644
+ return;
37645
+ case "node.start":
37646
+ console.error([
37647
+ `Node starting: ${event.nodeId}`,
37648
+ event.runnerId ? `runner=${event.runnerId}` : "",
37649
+ event.profile ? `profile=${event.profile}` : "",
37650
+ `attempt=${event.attempt}`
37651
+ ].filter(Boolean).join(" "));
37652
+ return;
37653
+ case "gate.finish":
37654
+ console.error(`Gate ${event.passed ? "passed" : "failed"}: ${event.nodeId}/${event.gateId}${event.reason ? ` (${event.reason})` : ""}`);
37655
+ return;
37656
+ case "node.finish":
37657
+ console.error(`Node finished: ${event.nodeId} ${event.status} exit=${event.exitCode}`);
37658
+ return;
37659
+ case "workflow.finish":
37660
+ console.error(`Pipeline finished: ${event.workflowId} ${event.outcome}`);
37661
+ return;
37662
+ default: {
37663
+ const _exhaustive = event;
37664
+ throw new Error(`Unhandled runtime event: ${String(_exhaustive)}`);
37665
+ }
37666
+ }
37667
+ }
37566
37668
  function formatRuntimeResult(result) {
37567
- return [
37669
+ const lines = [
37568
37670
  `Pipeline complete: ${result.outcome}`,
37569
37671
  `Workflow: ${result.plan.workflowId}`,
37570
37672
  `Nodes: ${result.nodes.map((node) => `${node.nodeId}:${node.status}`).join(", ")}`,
37571
37673
  `Agent boundaries: ${result.agentInvocations.length}`
37572
- ].join(`
37674
+ ];
37675
+ const outputs = result.nodes.filter((node) => node.output.trim());
37676
+ if (outputs.length > 0) {
37677
+ lines.push("Node outputs:");
37678
+ for (const node of outputs) {
37679
+ appendIndentedSection(lines, node.nodeId, [node.output]);
37680
+ }
37681
+ }
37682
+ return lines.join(`
37573
37683
  `);
37574
37684
  }
37575
37685
  function formatRuntimeFailure(result) {
@@ -7277,6 +7277,8 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
7277
7277
  return [
7278
7278
  "exec",
7279
7279
  "--json",
7280
+ "-C",
7281
+ worktreePath,
7280
7282
  ...optionalModelArgs(harness, options.runner, options.actor),
7281
7283
  ...mcpArgs,
7282
7284
  ...skillArgs,
@@ -7285,9 +7287,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
7285
7287
  "--config",
7286
7288
  'approval_policy="never"',
7287
7289
  "--skip-git-repo-check",
7288
- prompt,
7289
- "-C",
7290
- worktreePath
7290
+ prompt
7291
7291
  ];
7292
7292
  case "opencode":
7293
7293
  return contextFile ? [
@@ -32,9 +32,37 @@ export interface PipelineRuntimeResult {
32
32
  outcome: "FAIL" | "PASS";
33
33
  plan: WorkflowExecutionPlan;
34
34
  }
35
+ export type PipelineRuntimeEvent = {
36
+ nodeIds: string[];
37
+ type: "workflow.start";
38
+ workflowId: string;
39
+ } | {
40
+ attempt: number;
41
+ nodeId: string;
42
+ profile?: string;
43
+ runnerId?: string;
44
+ type: "node.start";
45
+ } | {
46
+ attempt: number;
47
+ exitCode: number;
48
+ nodeId: string;
49
+ status: RuntimeNodeResult["status"];
50
+ type: "node.finish";
51
+ } | {
52
+ gateId: string;
53
+ nodeId: string;
54
+ passed: boolean;
55
+ reason?: string;
56
+ type: "gate.finish";
57
+ } | {
58
+ outcome: PipelineRuntimeResult["outcome"];
59
+ type: "workflow.finish";
60
+ workflowId: string;
61
+ };
35
62
  export interface PipelineRuntimeOptions {
36
63
  config?: PipelineConfig;
37
64
  executor?: (plan: RunnerLaunchPlan) => AgentResult | Promise<AgentResult>;
65
+ reporter?: (event: PipelineRuntimeEvent) => void;
38
66
  task: string;
39
67
  workflowId?: string;
40
68
  worktreePath?: string;
package/package.json CHANGED
@@ -69,7 +69,7 @@
69
69
  "prepack": "bun run build:cli"
70
70
  },
71
71
  "type": "module",
72
- "version": "1.3.0",
72
+ "version": "1.3.1",
73
73
  "description": "",
74
74
  "main": "index.js",
75
75
  "keywords": [],