codeharness 0.32.1 → 0.32.2
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.
|
@@ -2895,7 +2895,7 @@ function generateDockerfileTemplate(projectDir, stackOrDetections) {
|
|
|
2895
2895
|
}
|
|
2896
2896
|
|
|
2897
2897
|
// src/modules/infra/init-project.ts
|
|
2898
|
-
var HARNESS_VERSION = true ? "0.32.
|
|
2898
|
+
var HARNESS_VERSION = true ? "0.32.2" : "0.0.0-dev";
|
|
2899
2899
|
function failResult(opts, error) {
|
|
2900
2900
|
return {
|
|
2901
2901
|
status: "fail",
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
validateDockerfile,
|
|
41
41
|
warn,
|
|
42
42
|
writeState
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-IICSAAF4.js";
|
|
44
44
|
|
|
45
45
|
// src/index.ts
|
|
46
46
|
import { Command } from "commander";
|
|
@@ -3360,12 +3360,17 @@ async function dispatchTaskWithResult(task, taskName, storyKey, definition, stat
|
|
|
3360
3360
|
let cwd;
|
|
3361
3361
|
let workspace = null;
|
|
3362
3362
|
if (task.source_access === false) {
|
|
3363
|
-
|
|
3364
|
-
|
|
3363
|
+
try {
|
|
3364
|
+
workspace = await createIsolatedWorkspace({ runId: config.runId, storyFiles: [] });
|
|
3365
|
+
cwd = workspace?.toDispatchOptions()?.cwd ?? projectDir;
|
|
3366
|
+
} catch {
|
|
3367
|
+
cwd = projectDir;
|
|
3368
|
+
}
|
|
3365
3369
|
} else {
|
|
3366
3370
|
cwd = projectDir;
|
|
3367
3371
|
}
|
|
3368
|
-
const
|
|
3372
|
+
const isEpicSentinel = storyKey.startsWith("__epic_") || storyKey === PER_RUN_SENTINEL;
|
|
3373
|
+
const basePrompt = customPrompt ?? (isEpicSentinel ? `Execute task "${taskName}" for the current run.` : `Implement story ${storyKey}`);
|
|
3369
3374
|
let prompt = buildPromptWithContractContext(basePrompt, previousOutputContract ?? null);
|
|
3370
3375
|
const coverageDedup = buildCoverageDeduplicationContext(
|
|
3371
3376
|
previousOutputContract ?? null,
|
|
@@ -3912,10 +3917,16 @@ async function executeWorkflow(config) {
|
|
|
3912
3917
|
for (const step of config.workflow.storyFlow) {
|
|
3913
3918
|
if (typeof step === "string") storyFlowTasks.add(step);
|
|
3914
3919
|
}
|
|
3920
|
+
const epicGroups = /* @__PURE__ */ new Map();
|
|
3921
|
+
for (const item of workItems) {
|
|
3922
|
+
const epicId = item.key.match(/^(\d+)-/)?.[1] ?? "unknown";
|
|
3923
|
+
if (!epicGroups.has(epicId)) epicGroups.set(epicId, []);
|
|
3924
|
+
epicGroups.get(epicId).push(item);
|
|
3925
|
+
}
|
|
3915
3926
|
let halted = false;
|
|
3916
3927
|
let lastOutputContract = null;
|
|
3917
3928
|
let accumulatedCostUsd = 0;
|
|
3918
|
-
for (const
|
|
3929
|
+
for (const [epicId, epicItems] of epicGroups) {
|
|
3919
3930
|
if (halted) break;
|
|
3920
3931
|
if (config.abortSignal?.aborted) {
|
|
3921
3932
|
info("Execution interrupted \u2014 saving state");
|
|
@@ -3924,107 +3935,121 @@ async function executeWorkflow(config) {
|
|
|
3924
3935
|
halted = true;
|
|
3925
3936
|
break;
|
|
3926
3937
|
}
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
for (const storyStep of config.workflow.storyFlow) {
|
|
3938
|
+
info(`[epic-${epicId}] Starting epic with ${epicItems.length} stories`);
|
|
3939
|
+
for (const step of config.workflow.epicFlow) {
|
|
3940
|
+
if (halted) break;
|
|
3941
|
+
if (config.abortSignal?.aborted) {
|
|
3942
|
+
state = { ...state, phase: "interrupted" };
|
|
3943
|
+
writeWorkflowState(state, projectDir);
|
|
3944
|
+
halted = true;
|
|
3945
|
+
break;
|
|
3946
|
+
}
|
|
3947
|
+
if (step === "story_flow") {
|
|
3948
|
+
for (const item of epicItems) {
|
|
3939
3949
|
if (halted || config.abortSignal?.aborted) {
|
|
3950
|
+
if (config.abortSignal?.aborted) {
|
|
3951
|
+
state = { ...state, phase: "interrupted" };
|
|
3952
|
+
writeWorkflowState(state, projectDir);
|
|
3953
|
+
}
|
|
3940
3954
|
halted = true;
|
|
3941
3955
|
break;
|
|
3942
3956
|
}
|
|
3943
|
-
|
|
3944
|
-
const
|
|
3945
|
-
|
|
3946
|
-
if (!task2) {
|
|
3947
|
-
warn(`workflow-engine: task "${taskName2}" not found, skipping`);
|
|
3948
|
-
continue;
|
|
3949
|
-
}
|
|
3950
|
-
if (task2.agent === null) continue;
|
|
3951
|
-
const definition2 = config.agents[task2.agent];
|
|
3952
|
-
if (!definition2) {
|
|
3953
|
-
warn(`workflow-engine: agent "${task2.agent}" not found for "${taskName2}"`);
|
|
3954
|
-
continue;
|
|
3955
|
-
}
|
|
3956
|
-
if (isTaskCompleted(state, taskName2, item.key)) continue;
|
|
3957
|
-
try {
|
|
3958
|
-
const dr = await dispatchTaskWithResult(task2, taskName2, item.key, definition2, state, config, void 0, lastOutputContract ?? void 0);
|
|
3959
|
-
state = dr.updatedState;
|
|
3960
|
-
lastOutputContract = dr.contract;
|
|
3961
|
-
propagateVerifyFlags(taskName2, dr.contract, projectDir);
|
|
3962
|
-
accumulatedCostUsd += dr.contract?.cost_usd ?? 0;
|
|
3963
|
-
tasksCompleted++;
|
|
3964
|
-
} catch (err) {
|
|
3965
|
-
const engineError = handleDispatchError(err, taskName2, item.key);
|
|
3966
|
-
errors.push(engineError);
|
|
3967
|
-
if (config.onEvent) {
|
|
3968
|
-
config.onEvent({ type: "dispatch-error", taskName: taskName2, storyKey: item.key, error: { code: engineError.code, message: engineError.message } });
|
|
3969
|
-
} else {
|
|
3970
|
-
warn(`[${taskName2}] ${item.key} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
3971
|
-
}
|
|
3972
|
-
state = recordErrorInState(state, taskName2, item.key, engineError);
|
|
3973
|
-
writeWorkflowState(state, projectDir);
|
|
3974
|
-
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
3957
|
+
processedStories.add(item.key);
|
|
3958
|
+
for (const storyStep of config.workflow.storyFlow) {
|
|
3959
|
+
if (halted || config.abortSignal?.aborted) {
|
|
3975
3960
|
halted = true;
|
|
3961
|
+
break;
|
|
3962
|
+
}
|
|
3963
|
+
if (typeof storyStep !== "string") continue;
|
|
3964
|
+
const taskName2 = storyStep;
|
|
3965
|
+
const task2 = config.workflow.tasks[taskName2];
|
|
3966
|
+
if (!task2) {
|
|
3967
|
+
warn(`workflow-engine: task "${taskName2}" not found, skipping`);
|
|
3968
|
+
continue;
|
|
3969
|
+
}
|
|
3970
|
+
if (task2.agent === null) continue;
|
|
3971
|
+
const definition2 = config.agents[task2.agent];
|
|
3972
|
+
if (!definition2) {
|
|
3973
|
+
warn(`workflow-engine: agent "${task2.agent}" not found for "${taskName2}"`);
|
|
3974
|
+
continue;
|
|
3975
|
+
}
|
|
3976
|
+
if (isTaskCompleted(state, taskName2, item.key)) continue;
|
|
3977
|
+
try {
|
|
3978
|
+
const dr = await dispatchTaskWithResult(task2, taskName2, item.key, definition2, state, config, void 0, lastOutputContract ?? void 0);
|
|
3979
|
+
state = dr.updatedState;
|
|
3980
|
+
lastOutputContract = dr.contract;
|
|
3981
|
+
propagateVerifyFlags(taskName2, dr.contract, projectDir);
|
|
3982
|
+
accumulatedCostUsd += dr.contract?.cost_usd ?? 0;
|
|
3983
|
+
tasksCompleted++;
|
|
3984
|
+
} catch (err) {
|
|
3985
|
+
const engineError = handleDispatchError(err, taskName2, item.key);
|
|
3986
|
+
errors.push(engineError);
|
|
3987
|
+
if (config.onEvent) {
|
|
3988
|
+
config.onEvent({ type: "dispatch-error", taskName: taskName2, storyKey: item.key, error: { code: engineError.code, message: engineError.message } });
|
|
3989
|
+
} else {
|
|
3990
|
+
warn(`[${taskName2}] ${item.key} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
3991
|
+
}
|
|
3992
|
+
state = recordErrorInState(state, taskName2, item.key, engineError);
|
|
3993
|
+
writeWorkflowState(state, projectDir);
|
|
3994
|
+
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
3995
|
+
halted = true;
|
|
3996
|
+
}
|
|
3997
|
+
break;
|
|
3976
3998
|
}
|
|
3977
|
-
break;
|
|
3978
3999
|
}
|
|
3979
4000
|
}
|
|
4001
|
+
continue;
|
|
3980
4002
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
4003
|
+
if (isLoopBlock(step)) {
|
|
4004
|
+
const loopResult = await executeLoopBlock(step, state, config, epicItems, lastOutputContract, storyFlowTasks);
|
|
4005
|
+
state = loopResult.state;
|
|
4006
|
+
errors.push(...loopResult.errors);
|
|
4007
|
+
tasksCompleted += loopResult.tasksCompleted;
|
|
4008
|
+
lastOutputContract = loopResult.lastContract;
|
|
4009
|
+
for (const item of epicItems) processedStories.add(item.key);
|
|
4010
|
+
if (loopResult.halted || state.phase === "max-iterations" || state.phase === "circuit-breaker") {
|
|
4011
|
+
halted = true;
|
|
4012
|
+
}
|
|
4013
|
+
continue;
|
|
3992
4014
|
}
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
warn(`workflow-engine: task "${taskName}" not found, skipping`);
|
|
3999
|
-
continue;
|
|
4000
|
-
}
|
|
4001
|
-
if (task.agent === null) continue;
|
|
4002
|
-
const definition = config.agents[task.agent];
|
|
4003
|
-
if (!definition) {
|
|
4004
|
-
warn(`workflow-engine: agent "${task.agent}" not found for "${taskName}"`);
|
|
4005
|
-
continue;
|
|
4006
|
-
}
|
|
4007
|
-
if (isTaskCompleted(state, taskName, PER_RUN_SENTINEL)) continue;
|
|
4008
|
-
try {
|
|
4009
|
-
const dr = await dispatchTaskWithResult(task, taskName, PER_RUN_SENTINEL, definition, state, config, void 0, lastOutputContract ?? void 0);
|
|
4010
|
-
state = dr.updatedState;
|
|
4011
|
-
lastOutputContract = dr.contract;
|
|
4012
|
-
propagateVerifyFlags(taskName, dr.contract, projectDir);
|
|
4013
|
-
accumulatedCostUsd += dr.contract?.cost_usd ?? 0;
|
|
4014
|
-
tasksCompleted++;
|
|
4015
|
-
} catch (err) {
|
|
4016
|
-
const engineError = handleDispatchError(err, taskName, PER_RUN_SENTINEL);
|
|
4017
|
-
errors.push(engineError);
|
|
4018
|
-
if (config.onEvent) {
|
|
4019
|
-
config.onEvent({ type: "dispatch-error", taskName, storyKey: PER_RUN_SENTINEL, error: { code: engineError.code, message: engineError.message } });
|
|
4020
|
-
} else {
|
|
4021
|
-
warn(`[${taskName}] ${PER_RUN_SENTINEL} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
4015
|
+
const taskName = step;
|
|
4016
|
+
const task = config.workflow.tasks[taskName];
|
|
4017
|
+
if (!task) {
|
|
4018
|
+
warn(`workflow-engine: task "${taskName}" not found, skipping`);
|
|
4019
|
+
continue;
|
|
4022
4020
|
}
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
if (
|
|
4026
|
-
|
|
4021
|
+
if (task.agent === null) continue;
|
|
4022
|
+
const definition = config.agents[task.agent];
|
|
4023
|
+
if (!definition) {
|
|
4024
|
+
warn(`workflow-engine: agent "${task.agent}" not found for "${taskName}"`);
|
|
4025
|
+
continue;
|
|
4027
4026
|
}
|
|
4027
|
+
const epicSentinel = `__epic_${epicId}__`;
|
|
4028
|
+
if (isTaskCompleted(state, taskName, epicSentinel)) continue;
|
|
4029
|
+
try {
|
|
4030
|
+
const dr = await dispatchTaskWithResult(task, taskName, epicSentinel, definition, state, config, void 0, lastOutputContract ?? void 0);
|
|
4031
|
+
state = dr.updatedState;
|
|
4032
|
+
lastOutputContract = dr.contract;
|
|
4033
|
+
propagateVerifyFlags(taskName, dr.contract, projectDir);
|
|
4034
|
+
accumulatedCostUsd += dr.contract?.cost_usd ?? 0;
|
|
4035
|
+
tasksCompleted++;
|
|
4036
|
+
} catch (err) {
|
|
4037
|
+
const engineError = handleDispatchError(err, taskName, epicSentinel);
|
|
4038
|
+
errors.push(engineError);
|
|
4039
|
+
if (config.onEvent) {
|
|
4040
|
+
config.onEvent({ type: "dispatch-error", taskName, storyKey: epicSentinel, error: { code: engineError.code, message: engineError.message } });
|
|
4041
|
+
} else {
|
|
4042
|
+
warn(`[${taskName}] epic-${epicId} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
4043
|
+
}
|
|
4044
|
+
state = recordErrorInState(state, taskName, epicSentinel, engineError);
|
|
4045
|
+
writeWorkflowState(state, projectDir);
|
|
4046
|
+
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
4047
|
+
halted = true;
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
if (!halted) {
|
|
4052
|
+
info(`[epic-${epicId}] Epic completed`);
|
|
4028
4053
|
}
|
|
4029
4054
|
}
|
|
4030
4055
|
if (state.phase === "interrupted") {
|
|
@@ -5468,7 +5493,7 @@ function StoryContext({ entries }) {
|
|
|
5468
5493
|
if (entries.length === 0) return null;
|
|
5469
5494
|
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: entries.map((e, i) => {
|
|
5470
5495
|
if (e.role === "prev") return /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(Text8, { color: "green", children: ` Prev: ${e.key} \u2713` }) }, i);
|
|
5471
|
-
if (e.role === "current") return /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: ` This: ${e.key}
|
|
5496
|
+
if (e.role === "current") return /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: ` This: ${e.key}` }) }, i);
|
|
5472
5497
|
return /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: ` Next: ${e.key}` }) }, i);
|
|
5473
5498
|
}) });
|
|
5474
5499
|
}
|
|
@@ -11135,7 +11160,7 @@ function registerTeardownCommand(program) {
|
|
|
11135
11160
|
} else if (otlpMode === "remote-routed") {
|
|
11136
11161
|
if (!options.keepDocker) {
|
|
11137
11162
|
try {
|
|
11138
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
11163
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-GLX24TXX.js");
|
|
11139
11164
|
stopCollectorOnly2();
|
|
11140
11165
|
result.docker.stopped = true;
|
|
11141
11166
|
if (!isJson) {
|
|
@@ -11167,7 +11192,7 @@ function registerTeardownCommand(program) {
|
|
|
11167
11192
|
info("Shared stack: kept running (other projects may use it)");
|
|
11168
11193
|
}
|
|
11169
11194
|
} else if (isLegacyStack) {
|
|
11170
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
11195
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-GLX24TXX.js");
|
|
11171
11196
|
let stackRunning = false;
|
|
11172
11197
|
try {
|
|
11173
11198
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -14154,7 +14179,7 @@ function registerDriversCommand(program) {
|
|
|
14154
14179
|
}
|
|
14155
14180
|
|
|
14156
14181
|
// src/index.ts
|
|
14157
|
-
var VERSION = true ? "0.32.
|
|
14182
|
+
var VERSION = true ? "0.32.2" : "0.0.0-dev";
|
|
14158
14183
|
function createProgram() {
|
|
14159
14184
|
const program = new Command();
|
|
14160
14185
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|