@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 +128 -18
- package/dist/mastra/runner.js +3 -3
- package/dist/pipeline-runtime.d.ts +28 -0
- package/package.json +1 -1
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
|
-
"
|
|
36408
|
-
"
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37040
|
+
const result3 = nodeFailure(node.id, attempt, successHook.evidence, last.output);
|
|
37041
|
+
emitNodeFinish(context, result3);
|
|
37042
|
+
return result3;
|
|
37005
37043
|
}
|
|
37006
|
-
|
|
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
|
-
|
|
37063
|
+
const result2 = nodeFailure(node.id, attempt, evidence, last.output);
|
|
37064
|
+
emitNodeFinish(context, result2);
|
|
37065
|
+
return result2;
|
|
37024
37066
|
}
|
|
37025
37067
|
}
|
|
37026
|
-
|
|
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
|
-
|
|
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
|
-
]
|
|
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) {
|
package/dist/mastra/runner.js
CHANGED
|
@@ -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;
|