@oisincoveney/pipeline 3.1.1 → 3.3.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.
- package/defaults/pipeline.yaml +2 -2
- package/dist/cli/program.js +3 -10
- package/dist/config/schemas.d.ts +5 -5
- package/dist/model-resolver.js +16 -5
- package/dist/moka-submit.d.ts +1 -1
- package/dist/pipeline-runtime.js +3 -1
- package/dist/run-control/runtime-reporter.js +12 -3
- package/dist/runner-command-contract.d.ts +2 -2
- package/dist/runtime/agent-node/agent-node.js +4 -3
- package/dist/runtime/context/context.js +2 -1
- package/dist/runtime/contracts/contracts.d.ts +1 -0
- package/dist/runtime/events/events.js +2 -1
- package/dist/runtime/opencode-runtime.js +15 -0
- package/dist/schedule/passes/coverage.js +9 -9
- package/package.json +1 -1
package/defaults/pipeline.yaml
CHANGED
|
@@ -86,7 +86,7 @@ scheduler:
|
|
|
86
86
|
green-implementation:
|
|
87
87
|
category: green
|
|
88
88
|
profile: moka-code-writer
|
|
89
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/k2p6
|
|
89
|
+
models: [opencode-go/qwen3.7-max, openai/gpt-5.5-high, kimi-for-coding/k2p6]
|
|
90
90
|
verification:
|
|
91
91
|
category: verification
|
|
92
92
|
profile: moka-verifier
|
|
@@ -109,7 +109,7 @@ scheduler:
|
|
|
109
109
|
green-backend:
|
|
110
110
|
category: green
|
|
111
111
|
profile: moka-code-writer
|
|
112
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/k2p6
|
|
112
|
+
models: [opencode-go/qwen3.7-max, openai/gpt-5.5-high, kimi-for-coding/k2p6]
|
|
113
113
|
green-frontend:
|
|
114
114
|
category: green
|
|
115
115
|
profile: moka-code-writer
|
package/dist/cli/program.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { loadPipelineConfig } from "../config/load.js";
|
|
2
2
|
import "../config.js";
|
|
3
|
+
import { flattenNodes } from "../planning/graph.js";
|
|
3
4
|
import { configureGatewayHosts, localGatewayStatus, reconcileGateway, renderGatewayConfig, runGatewayDoctor, startLocalGateway } from "../mcp/gateway.js";
|
|
4
5
|
import { createOrchestratorLaunchPlan, createRunnerLaunchPlan } from "../runner.js";
|
|
5
6
|
import { compileWorkflowPlan } from "../planning/compile.js";
|
|
6
|
-
import { generateRuntimeRunId } from "../runtime/context/context.js";
|
|
7
|
+
import { generateRuntimeRunId, resolveWorkflowSelection } from "../runtime/context/context.js";
|
|
7
8
|
import "../runtime/context/index.js";
|
|
8
9
|
import { runPipelineFromConfig } from "../pipeline-runtime.js";
|
|
9
10
|
import { compileScheduleArtifact, generateScheduleArtifact, parseScheduleArtifact } from "../planning/generate.js";
|
|
@@ -192,7 +193,7 @@ function resolvedRunControlOptions(input) {
|
|
|
192
193
|
function plannedRunStoreNodeIds(inputs) {
|
|
193
194
|
if (inputs.pipelineRunner) return [];
|
|
194
195
|
const workflowId = resolveWorkflowSelection(inputs.config, inputs.workflow, inputs.entrypoint);
|
|
195
|
-
return compileWorkflowPlan(inputs.config, workflowId).topologicalOrder.map((node) => node.id);
|
|
196
|
+
return flattenNodes(compileWorkflowPlan(inputs.config, workflowId).topologicalOrder, (node) => node.children).map((node) => node.id);
|
|
196
197
|
}
|
|
197
198
|
function formatSupervisedRunFollowUp(runId) {
|
|
198
199
|
return [
|
|
@@ -566,14 +567,6 @@ function formatWorkflowPlanNode(node, config, worktreePath) {
|
|
|
566
567
|
node.artifacts?.length ? `artifacts=${node.artifacts.map((artifact) => artifact.path).join(",")}` : "artifacts=none"
|
|
567
568
|
].filter(Boolean).join(" ");
|
|
568
569
|
}
|
|
569
|
-
function resolveWorkflowSelection(config, workflowId, entrypointId) {
|
|
570
|
-
if (workflowId) return workflowId;
|
|
571
|
-
if (!entrypointId) return;
|
|
572
|
-
const entrypoint = config.entrypoints[entrypointId];
|
|
573
|
-
if (!entrypoint) throw new Error(`Unknown pipeline entrypoint '${entrypointId}'`);
|
|
574
|
-
if ("schedule" in entrypoint) throw new Error(`Pipeline entrypoint '${entrypointId}' generates schedule '${entrypoint.schedule}'; use the entrypoint to create a schedule, then run with --schedule.`);
|
|
575
|
-
return entrypoint.workflow;
|
|
576
|
-
}
|
|
577
570
|
function formatOrchestratorPlan(config, worktreePath) {
|
|
578
571
|
if (!config.orchestrator) return "Orchestrator: not configured";
|
|
579
572
|
const orchestrator = config.profiles[config.orchestrator.profile];
|
package/dist/config/schemas.d.ts
CHANGED
|
@@ -226,8 +226,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
226
226
|
policy: z.ZodOptional<z.ZodObject<{
|
|
227
227
|
commands: z.ZodOptional<z.ZodEnum<{
|
|
228
228
|
allow: "allow";
|
|
229
|
-
"trusted-only": "trusted-only";
|
|
230
229
|
deny: "deny";
|
|
230
|
+
"trusted-only": "trusted-only";
|
|
231
231
|
}>>;
|
|
232
232
|
modules: z.ZodOptional<z.ZodEnum<{
|
|
233
233
|
allow: "allow";
|
|
@@ -255,8 +255,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
255
255
|
global: "global";
|
|
256
256
|
}>>;
|
|
257
257
|
mode: z.ZodEnum<{
|
|
258
|
-
hosted: "hosted";
|
|
259
258
|
local: "local";
|
|
259
|
+
hosted: "hosted";
|
|
260
260
|
}>;
|
|
261
261
|
provider: z.ZodLiteral<"toolhive">;
|
|
262
262
|
authorization_env: z.ZodDefault<z.ZodString>;
|
|
@@ -299,10 +299,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
299
299
|
}, z.core.$strict>>;
|
|
300
300
|
output: z.ZodOptional<z.ZodObject<{
|
|
301
301
|
format: z.ZodEnum<{
|
|
302
|
+
json_schema: "json_schema";
|
|
302
303
|
text: "text";
|
|
303
304
|
json: "json";
|
|
304
305
|
jsonl: "jsonl";
|
|
305
|
-
json_schema: "json_schema";
|
|
306
306
|
}>;
|
|
307
307
|
repair: z.ZodOptional<z.ZodObject<{
|
|
308
308
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -371,10 +371,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
371
371
|
disabled: "disabled";
|
|
372
372
|
}>>>;
|
|
373
373
|
output_formats: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
374
|
+
json_schema: "json_schema";
|
|
374
375
|
text: "text";
|
|
375
376
|
json: "json";
|
|
376
377
|
jsonl: "jsonl";
|
|
377
|
-
json_schema: "json_schema";
|
|
378
378
|
}>>>;
|
|
379
379
|
rules: z.ZodOptional<z.ZodBoolean>;
|
|
380
380
|
skills: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -481,8 +481,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
481
481
|
schedules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
482
482
|
description: z.ZodOptional<z.ZodString>;
|
|
483
483
|
baseline: z.ZodEnum<{
|
|
484
|
-
quick: "quick";
|
|
485
484
|
execute: "execute";
|
|
485
|
+
quick: "quick";
|
|
486
486
|
}>;
|
|
487
487
|
max_parallel_nodes: z.ZodOptional<z.ZodNumber>;
|
|
488
488
|
node_catalog: z.ZodOptional<z.ZodString>;
|
package/dist/model-resolver.js
CHANGED
|
@@ -9,17 +9,28 @@ function fallbackModelSelection(models, options) {
|
|
|
9
9
|
skipped: []
|
|
10
10
|
};
|
|
11
11
|
const disabled = disabledModels();
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
12
|
+
const available = options?.available;
|
|
13
|
+
const enabled = models.filter((candidate) => !disabled.has(candidate) && isAvailable(candidate, available));
|
|
14
|
+
const skipped = models.filter((candidate) => disabled.has(candidate) || !isAvailable(candidate, available));
|
|
15
|
+
const sizing = sizingFromOptions(options);
|
|
16
|
+
if (!sizing) {
|
|
15
17
|
const model = enabled[0];
|
|
16
18
|
return {
|
|
17
19
|
model,
|
|
18
20
|
reason: selectionReason(model),
|
|
19
|
-
skipped
|
|
21
|
+
skipped
|
|
20
22
|
};
|
|
21
23
|
}
|
|
22
|
-
return sizedSelection(enabled,
|
|
24
|
+
return sizedSelection(enabled, skipped, sizing);
|
|
25
|
+
}
|
|
26
|
+
function isAvailable(candidate, available) {
|
|
27
|
+
return available ? available.has(candidate) : true;
|
|
28
|
+
}
|
|
29
|
+
function sizingFromOptions(options) {
|
|
30
|
+
if (options?.budget && typeof options.estimatedTokens === "number") return {
|
|
31
|
+
budget: options.budget,
|
|
32
|
+
estimatedTokens: options.estimatedTokens
|
|
33
|
+
};
|
|
23
34
|
}
|
|
24
35
|
function sizedSelection(enabled, disabledSkipped, options) {
|
|
25
36
|
const { estimatedTokens, budget } = options;
|
package/dist/moka-submit.d.ts
CHANGED
|
@@ -160,8 +160,8 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
160
160
|
}, z.core.$strict>>;
|
|
161
161
|
serviceAccountName: z.ZodOptional<z.ZodString>;
|
|
162
162
|
mode: z.ZodEnum<{
|
|
163
|
-
full: "full";
|
|
164
163
|
quick: "quick";
|
|
164
|
+
full: "full";
|
|
165
165
|
}>;
|
|
166
166
|
schedulePath: z.ZodOptional<z.ZodString>;
|
|
167
167
|
scheduleYaml: z.ZodOptional<z.ZodString>;
|
package/dist/pipeline-runtime.js
CHANGED
|
@@ -77,10 +77,12 @@ function runWithLeasedOpencode(options, config, worktreePath, run) {
|
|
|
77
77
|
...options.signal ? { signal: options.signal } : {},
|
|
78
78
|
worktreePath
|
|
79
79
|
})), (lease) => Effect.promise(() => lease.release()));
|
|
80
|
+
const availableModels = yield* Effect.promise(() => lease.availableModels());
|
|
80
81
|
return yield* run({
|
|
81
82
|
...options,
|
|
82
83
|
config,
|
|
83
|
-
executor: lease.executor
|
|
84
|
+
executor: lease.executor,
|
|
85
|
+
...availableModels ? { availableModels } : {}
|
|
84
86
|
});
|
|
85
87
|
}));
|
|
86
88
|
}
|
|
@@ -20,11 +20,11 @@ function createRunStoreRuntimeReporterRuntime(input) {
|
|
|
20
20
|
const activeHookPreviousStatuses = /* @__PURE__ */ new Map();
|
|
21
21
|
let writeChain = Promise.resolve();
|
|
22
22
|
const enqueue = (event) => {
|
|
23
|
-
const
|
|
23
|
+
const persisted = persistRuntimeEventEffect(input, event, projectRuntimeEvent(event, {
|
|
24
24
|
activeHookPreviousStatuses,
|
|
25
25
|
observedNodeStatuses
|
|
26
|
-
});
|
|
27
|
-
writeChain = writeChain.then(() => withRunStateLock(() => Effect.runPromise(
|
|
26
|
+
}), now).pipe(Effect.catchAll((error) => warnPersistSkipped(input, event, error)));
|
|
27
|
+
writeChain = writeChain.then(() => withRunStateLock(() => Effect.runPromise(persisted)));
|
|
28
28
|
};
|
|
29
29
|
const flushEffect = () => Effect.tryPromise({
|
|
30
30
|
catch: (error) => error,
|
|
@@ -184,5 +184,14 @@ function timestamp(now) {
|
|
|
184
184
|
function assertNever(value) {
|
|
185
185
|
throw new Error(`Unhandled runtime reporter value: ${String(value)}`);
|
|
186
186
|
}
|
|
187
|
+
function warnPersistSkipped(input, event, error) {
|
|
188
|
+
return Effect.sync(() => {
|
|
189
|
+
const nodeId = "nodeId" in event && typeof event.nodeId === "string" ? ` node=${event.nodeId}` : "";
|
|
190
|
+
process.stderr.write(`run-control: skipped persisting ${event.type}${nodeId} for run ${input.runId}: ${errorMessage(error)}\n`);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function errorMessage(error) {
|
|
194
|
+
return error instanceof Error ? error.message : String(error);
|
|
195
|
+
}
|
|
187
196
|
//#endregion
|
|
188
197
|
export { createRunStoreRuntimeReporter };
|
|
@@ -43,8 +43,8 @@ declare const runnerDeliverySchema: z.ZodObject<{
|
|
|
43
43
|
declare const mokaSubmissionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
44
44
|
kind: z.ZodLiteral<"graph">;
|
|
45
45
|
mode: z.ZodEnum<{
|
|
46
|
-
full: "full";
|
|
47
46
|
quick: "quick";
|
|
47
|
+
full: "full";
|
|
48
48
|
}>;
|
|
49
49
|
}, z.core.$strict>, z.ZodObject<{
|
|
50
50
|
argv: z.ZodArray<z.ZodString>;
|
|
@@ -104,8 +104,8 @@ declare const runnerCommandPayloadSchema: z.ZodObject<{
|
|
|
104
104
|
submission: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
105
105
|
kind: z.ZodLiteral<"graph">;
|
|
106
106
|
mode: z.ZodEnum<{
|
|
107
|
-
full: "full";
|
|
108
107
|
quick: "quick";
|
|
108
|
+
full: "full";
|
|
109
109
|
}>;
|
|
110
110
|
}, z.core.$strict>, z.ZodObject<{
|
|
111
111
|
argv: z.ZodArray<z.ZodString>;
|
|
@@ -25,7 +25,7 @@ function executeAgentNodeEffect(node, context, attempt) {
|
|
|
25
25
|
output: ""
|
|
26
26
|
};
|
|
27
27
|
const prompt = yield* renderAgentPromptEffect(node, context);
|
|
28
|
-
const decision = decideNodeModel(prompt, node, context.config.token_budget);
|
|
28
|
+
const decision = decideNodeModel(prompt, node, context.config.token_budget, context.availableModels);
|
|
29
29
|
if (decision.overBudget) return {
|
|
30
30
|
evidence: [
|
|
31
31
|
`agent boundary node=${node.id} profile=${node.profile}`,
|
|
@@ -155,14 +155,15 @@ function createHandoffFinalizerPlan(context, node, runner, rawOutput) {
|
|
|
155
155
|
* with a fallback array but no fitting model is `overBudget` — the caller fails
|
|
156
156
|
* it fast rather than truncating.
|
|
157
157
|
*/
|
|
158
|
-
function decideNodeModel(prompt, node, budget) {
|
|
158
|
+
function decideNodeModel(prompt, node, budget, availableModels) {
|
|
159
159
|
const estimatedTokens = estimateTokens(prompt);
|
|
160
160
|
if (!(budget && node.models?.length)) return {
|
|
161
161
|
estimatedTokens,
|
|
162
162
|
overBudget: false,
|
|
163
|
-
selection: selectNodeModel(node)
|
|
163
|
+
selection: selectNodeModel(node, { available: availableModels })
|
|
164
164
|
};
|
|
165
165
|
const selection = selectNodeModel(node, {
|
|
166
|
+
available: availableModels,
|
|
166
167
|
budget,
|
|
167
168
|
estimatedTokens
|
|
168
169
|
});
|
|
@@ -18,6 +18,7 @@ function createRuntimeContext(options) {
|
|
|
18
18
|
const observability = options.reporter ? createPublicRuntimeObservabilityEmitter(options.reporter, workflowId) : void 0;
|
|
19
19
|
return {
|
|
20
20
|
agentInvocations: [],
|
|
21
|
+
...options.availableModels ? { availableModels: options.availableModels } : {},
|
|
21
22
|
...runId ? { runId } : {},
|
|
22
23
|
config,
|
|
23
24
|
executor: options.executor ?? runLaunchPlan,
|
|
@@ -70,4 +71,4 @@ function generateRuntimeRunId() {
|
|
|
70
71
|
return `run-${randomUUID()}`;
|
|
71
72
|
}
|
|
72
73
|
//#endregion
|
|
73
|
-
export { createRuntimeContext, generateRuntimeRunId,
|
|
74
|
+
export { createRuntimeContext, generateRuntimeRunId, resolveWorkflowSelection };
|
|
@@ -248,6 +248,7 @@ type PipelineRuntimeEvent = {
|
|
|
248
248
|
* single-node, schedule-driven execution path.
|
|
249
249
|
*/
|
|
250
250
|
interface PipelineRuntimeOptions {
|
|
251
|
+
availableModels?: ReadonlySet<string>;
|
|
251
252
|
config?: PipelineConfig;
|
|
252
253
|
entrypoint?: string;
|
|
253
254
|
executor?: (plan: RunnerLaunchPlan, options: RunnerExecutionOptions) => AgentResult | Promise<AgentResult>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flattenNodes } from "../../planning/graph.js";
|
|
1
2
|
import { isRecord } from "../../safe-json.js";
|
|
2
3
|
import { runtimeActorId } from "../actor-ids.js";
|
|
3
4
|
import { parseRuntimeOutput, validateJsonSchemaSource } from "../json-validation/json-validation.js";
|
|
@@ -125,7 +126,7 @@ function emitWorkflowPlanned(context) {
|
|
|
125
126
|
}
|
|
126
127
|
function emitWorkflowStarted(context) {
|
|
127
128
|
emit(context, {
|
|
128
|
-
nodeIds: context.plan.topologicalOrder.map((node) => node.id),
|
|
129
|
+
nodeIds: flattenNodes(context.plan.topologicalOrder, (node) => node.children).map((node) => node.id),
|
|
129
130
|
type: "workflow.start",
|
|
130
131
|
workflowId: context.workflowId
|
|
131
132
|
});
|
|
@@ -27,6 +27,7 @@ function leaseOpencodeRuntimeEffect(input) {
|
|
|
27
27
|
const registry = createOpencodeSessionRegistry();
|
|
28
28
|
let handle;
|
|
29
29
|
let pending;
|
|
30
|
+
let availableModelsPending;
|
|
30
31
|
const ensureExecutor = () => {
|
|
31
32
|
pending ??= Effect.runPromise(Effect.provide(ensureExecutorEffect(input, registry), OpencodeRuntimeServerServiceLive)).then((executor) => {
|
|
32
33
|
handle = executor.handle;
|
|
@@ -34,7 +35,12 @@ function leaseOpencodeRuntimeEffect(input) {
|
|
|
34
35
|
});
|
|
35
36
|
return pending;
|
|
36
37
|
};
|
|
38
|
+
const resolveAvailableModels = () => {
|
|
39
|
+
availableModelsPending ??= ensureExecutor().then(() => handle ? queryAvailableOpencodeModels(handle.client) : void 0).catch(() => void 0);
|
|
40
|
+
return availableModelsPending;
|
|
41
|
+
};
|
|
37
42
|
return Effect.succeed({
|
|
43
|
+
availableModels: resolveAvailableModels,
|
|
38
44
|
executor: async (plan, options) => {
|
|
39
45
|
return await (await ensureExecutor())(plan, options);
|
|
40
46
|
},
|
|
@@ -46,6 +52,15 @@ function leaseOpencodeRuntimeEffect(input) {
|
|
|
46
52
|
}
|
|
47
53
|
});
|
|
48
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Collect every model the leased server can resolve (each authenticated
|
|
57
|
+
* provider's models as `provider/model`) from the opencode `/config/providers`
|
|
58
|
+
* endpoint, for availability-aware model selection.
|
|
59
|
+
*/
|
|
60
|
+
async function queryAvailableOpencodeModels(client) {
|
|
61
|
+
const providers = (await client.config.providers()).data?.providers ?? [];
|
|
62
|
+
return new Set(providers.flatMap((provider) => Object.keys(provider.models ?? {}).map((modelId) => `${provider.id}/${modelId}`)));
|
|
63
|
+
}
|
|
49
64
|
function ensureExecutorEffect(input, registry) {
|
|
50
65
|
return Effect.gen(function* () {
|
|
51
66
|
const handle = yield* (yield* OpencodeRuntimeServerService).open(input);
|
|
@@ -22,15 +22,11 @@ function addWorkflowImplementationCoverage(config, workflow, coverageProfileId)
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
function addNodeScopeImplementationCoverage(config, nodes, coverageProfileId) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const uncovered = scopedNodes.filter((node) => isImplementationNode(config, node)).filter((node) => !hasDownstreamCoverage(config, node.id, index));
|
|
31
|
-
if (uncovered.length === 0) return scopedNodes;
|
|
32
|
-
const coverageNodeId = uniqueGeneratedId("generated-coverage", new Set(scopedNodes.map((node) => node.id)), "generated-coverage");
|
|
33
|
-
return [...scopedNodes, {
|
|
25
|
+
const index = dependentsByNeed(nodes);
|
|
26
|
+
const uncovered = nodes.filter((node) => nodeNeedsImplementationCoverage(config, node)).filter((node) => !hasDownstreamCoverage(config, node.id, index));
|
|
27
|
+
if (uncovered.length === 0) return nodes;
|
|
28
|
+
const coverageNodeId = uniqueGeneratedId("generated-coverage", new Set(nodes.map((node) => node.id)), "generated-coverage");
|
|
29
|
+
return [...nodes, {
|
|
34
30
|
gates: generatedCoverageGates(coverageNodeId),
|
|
35
31
|
id: coverageNodeId,
|
|
36
32
|
kind: "agent",
|
|
@@ -38,6 +34,10 @@ function addNodeScopeImplementationCoverage(config, nodes, coverageProfileId) {
|
|
|
38
34
|
profile: coverageProfileId
|
|
39
35
|
}];
|
|
40
36
|
}
|
|
37
|
+
function nodeNeedsImplementationCoverage(config, node) {
|
|
38
|
+
if (isImplementationNode(config, node)) return true;
|
|
39
|
+
return node.kind === "parallel" && node.nodes.some((child) => nodeNeedsImplementationCoverage(config, child));
|
|
40
|
+
}
|
|
41
41
|
function generatedCoverageProfileId(config) {
|
|
42
42
|
const coverageProfiles = Object.entries(config.profiles).filter(([, profile]) => profile.scheduling_roles?.includes("coverage")).map(([id]) => id);
|
|
43
43
|
if (coverageProfiles.length === 0) return null;
|
package/package.json
CHANGED
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"prepack": "bun run build:cli"
|
|
127
127
|
},
|
|
128
128
|
"type": "module",
|
|
129
|
-
"version": "3.
|
|
129
|
+
"version": "3.3.0",
|
|
130
130
|
"description": "Config-driven multi-agent pipeline runner for repository work",
|
|
131
131
|
"main": "./dist/index.js",
|
|
132
132
|
"types": "./dist/index.d.ts",
|