codeharness 0.29.4 → 0.30.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.
|
@@ -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.
|
|
2898
|
+
var HARNESS_VERSION = true ? "0.30.0" : "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-S3RKDJMC.js";
|
|
44
44
|
|
|
45
45
|
// src/index.ts
|
|
46
46
|
import { Command } from "commander";
|
|
@@ -3882,75 +3882,165 @@ async function executeWorkflow(config) {
|
|
|
3882
3882
|
let halted = false;
|
|
3883
3883
|
let lastOutputContract = null;
|
|
3884
3884
|
let accumulatedCostUsd = 0;
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
}
|
|
3894
|
-
if (isLoopBlock(step)) {
|
|
3895
|
-
const loopResult = await executeLoopBlock(step, state, config, workItems, lastOutputContract);
|
|
3896
|
-
state = loopResult.state;
|
|
3897
|
-
errors.push(...loopResult.errors);
|
|
3898
|
-
tasksCompleted += loopResult.tasksCompleted;
|
|
3899
|
-
lastOutputContract = loopResult.lastContract;
|
|
3900
|
-
for (const item of workItems) {
|
|
3901
|
-
processedStories.add(item.key);
|
|
3885
|
+
if (config.storyPipeline) {
|
|
3886
|
+
const preTasks = [];
|
|
3887
|
+
let loopIdx = -1;
|
|
3888
|
+
for (let i = 0; i < config.workflow.storyFlow.length; i++) {
|
|
3889
|
+
const s = config.workflow.storyFlow[i];
|
|
3890
|
+
if (isLoopBlock(s)) {
|
|
3891
|
+
loopIdx = i;
|
|
3892
|
+
break;
|
|
3902
3893
|
}
|
|
3903
|
-
if (
|
|
3894
|
+
if (typeof s === "string") preTasks.push(s);
|
|
3895
|
+
}
|
|
3896
|
+
for (const item of workItems) {
|
|
3897
|
+
if (halted || config.abortSignal?.aborted) {
|
|
3898
|
+
if (config.abortSignal?.aborted) {
|
|
3899
|
+
info("Execution interrupted \u2014 saving state");
|
|
3900
|
+
state = { ...state, phase: "interrupted" };
|
|
3901
|
+
writeWorkflowState(state, projectDir);
|
|
3902
|
+
}
|
|
3904
3903
|
halted = true;
|
|
3904
|
+
break;
|
|
3905
3905
|
}
|
|
3906
|
-
|
|
3907
|
-
|
|
3906
|
+
processedStories.add(item.key);
|
|
3907
|
+
for (const taskName of preTasks) {
|
|
3908
|
+
if (halted || config.abortSignal?.aborted) {
|
|
3909
|
+
halted = true;
|
|
3910
|
+
break;
|
|
3911
|
+
}
|
|
3912
|
+
const task = config.workflow.tasks[taskName];
|
|
3913
|
+
if (!task || task.agent === null) continue;
|
|
3914
|
+
const definition = config.agents[task.agent];
|
|
3915
|
+
if (!definition) {
|
|
3916
|
+
warn(`workflow-engine: agent "${task.agent}" not found for "${taskName}"`);
|
|
3917
|
+
continue;
|
|
3918
|
+
}
|
|
3919
|
+
if (isTaskCompleted(state, taskName, item.key)) continue;
|
|
3920
|
+
try {
|
|
3921
|
+
const dr = await dispatchTaskWithResult(task, taskName, item.key, definition, state, config, void 0, lastOutputContract ?? void 0);
|
|
3922
|
+
state = dr.updatedState;
|
|
3923
|
+
lastOutputContract = dr.contract;
|
|
3924
|
+
propagateVerifyFlags(taskName, dr.contract, projectDir);
|
|
3925
|
+
accumulatedCostUsd += dr.contract?.cost_usd ?? 0;
|
|
3926
|
+
tasksCompleted++;
|
|
3927
|
+
} catch (err) {
|
|
3928
|
+
const engineError = handleDispatchError(err, taskName, item.key);
|
|
3929
|
+
errors.push(engineError);
|
|
3930
|
+
if (config.onEvent) {
|
|
3931
|
+
config.onEvent({ type: "dispatch-error", taskName, storyKey: item.key, error: { code: engineError.code, message: engineError.message } });
|
|
3932
|
+
} else {
|
|
3933
|
+
warn(`[${taskName}] ${item.key} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
3934
|
+
}
|
|
3935
|
+
state = recordErrorInState(state, taskName, item.key, engineError);
|
|
3936
|
+
writeWorkflowState(state, projectDir);
|
|
3937
|
+
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
3938
|
+
halted = true;
|
|
3939
|
+
}
|
|
3940
|
+
break;
|
|
3941
|
+
}
|
|
3908
3942
|
}
|
|
3909
|
-
continue;
|
|
3910
3943
|
}
|
|
3911
|
-
const
|
|
3912
|
-
const
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3944
|
+
const remaining = loopIdx >= 0 ? config.workflow.storyFlow.slice(loopIdx) : [];
|
|
3945
|
+
for (const step of remaining) {
|
|
3946
|
+
if (halted || config.abortSignal?.aborted) {
|
|
3947
|
+
halted = true;
|
|
3948
|
+
break;
|
|
3949
|
+
}
|
|
3950
|
+
if (isLoopBlock(step)) {
|
|
3951
|
+
const loopResult = await executeLoopBlock(step, state, config, workItems, lastOutputContract);
|
|
3952
|
+
state = loopResult.state;
|
|
3953
|
+
errors.push(...loopResult.errors);
|
|
3954
|
+
tasksCompleted += loopResult.tasksCompleted;
|
|
3955
|
+
lastOutputContract = loopResult.lastContract;
|
|
3956
|
+
for (const item of workItems) processedStories.add(item.key);
|
|
3957
|
+
if (loopResult.halted || state.phase === "max-iterations" || state.phase === "circuit-breaker") {
|
|
3958
|
+
halted = true;
|
|
3922
3959
|
}
|
|
3960
|
+
continue;
|
|
3961
|
+
}
|
|
3962
|
+
const taskName = step;
|
|
3963
|
+
const task = config.workflow.tasks[taskName];
|
|
3964
|
+
if (!task) continue;
|
|
3965
|
+
if (task.agent === null) continue;
|
|
3966
|
+
const definition = config.agents[task.agent];
|
|
3967
|
+
if (!definition) continue;
|
|
3968
|
+
if (task.scope === "per-run" || task.scope === "per-epic") {
|
|
3969
|
+
if (isTaskCompleted(state, taskName, PER_RUN_SENTINEL)) continue;
|
|
3923
3970
|
try {
|
|
3924
|
-
const
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
PER_RUN_SENTINEL,
|
|
3928
|
-
state,
|
|
3929
|
-
config,
|
|
3930
|
-
lastOutputContract ?? void 0,
|
|
3931
|
-
accumulatedCostUsd
|
|
3932
|
-
);
|
|
3933
|
-
state = nullResult.updatedState;
|
|
3934
|
-
lastOutputContract = nullResult.contract;
|
|
3971
|
+
const dr = await dispatchTaskWithResult(task, taskName, PER_RUN_SENTINEL, definition, state, config, void 0, lastOutputContract ?? void 0);
|
|
3972
|
+
state = dr.updatedState;
|
|
3973
|
+
lastOutputContract = dr.contract;
|
|
3935
3974
|
tasksCompleted++;
|
|
3936
3975
|
} catch (err) {
|
|
3937
|
-
const engineError =
|
|
3976
|
+
const engineError = handleDispatchError(err, taskName, PER_RUN_SENTINEL);
|
|
3938
3977
|
errors.push(engineError);
|
|
3939
3978
|
state = recordErrorInState(state, taskName, PER_RUN_SENTINEL, engineError);
|
|
3940
3979
|
writeWorkflowState(state, projectDir);
|
|
3941
3980
|
}
|
|
3942
3981
|
} else {
|
|
3982
|
+
for (const item of workItems) {
|
|
3983
|
+
if (halted || config.abortSignal?.aborted) break;
|
|
3984
|
+
if (isTaskCompleted(state, taskName, item.key)) continue;
|
|
3985
|
+
try {
|
|
3986
|
+
const dr = await dispatchTaskWithResult(task, taskName, item.key, definition, state, config, void 0, lastOutputContract ?? void 0);
|
|
3987
|
+
state = dr.updatedState;
|
|
3988
|
+
lastOutputContract = dr.contract;
|
|
3989
|
+
tasksCompleted++;
|
|
3990
|
+
} catch (err) {
|
|
3991
|
+
const engineError = handleDispatchError(err, taskName, item.key);
|
|
3992
|
+
errors.push(engineError);
|
|
3993
|
+
state = recordErrorInState(state, taskName, item.key, engineError);
|
|
3994
|
+
writeWorkflowState(state, projectDir);
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
if (!config.storyPipeline)
|
|
4001
|
+
for (const step of config.workflow.storyFlow) {
|
|
4002
|
+
if (halted) break;
|
|
4003
|
+
if (config.abortSignal?.aborted) {
|
|
4004
|
+
info("Execution interrupted \u2014 saving state");
|
|
4005
|
+
state = { ...state, phase: "interrupted" };
|
|
4006
|
+
writeWorkflowState(state, projectDir);
|
|
4007
|
+
halted = true;
|
|
4008
|
+
break;
|
|
4009
|
+
}
|
|
4010
|
+
if (isLoopBlock(step)) {
|
|
4011
|
+
const loopResult = await executeLoopBlock(step, state, config, workItems, lastOutputContract);
|
|
4012
|
+
state = loopResult.state;
|
|
4013
|
+
errors.push(...loopResult.errors);
|
|
4014
|
+
tasksCompleted += loopResult.tasksCompleted;
|
|
4015
|
+
lastOutputContract = loopResult.lastContract;
|
|
3943
4016
|
for (const item of workItems) {
|
|
3944
4017
|
processedStories.add(item.key);
|
|
3945
|
-
|
|
3946
|
-
|
|
4018
|
+
}
|
|
4019
|
+
if (loopResult.halted) {
|
|
4020
|
+
halted = true;
|
|
4021
|
+
}
|
|
4022
|
+
if (state.phase === "max-iterations" || state.phase === "circuit-breaker") {
|
|
4023
|
+
halted = true;
|
|
4024
|
+
}
|
|
4025
|
+
continue;
|
|
4026
|
+
}
|
|
4027
|
+
const taskName = step;
|
|
4028
|
+
const task = config.workflow.tasks[taskName];
|
|
4029
|
+
if (!task) {
|
|
4030
|
+
warn(`workflow-engine: task "${taskName}" not found in workflow tasks, skipping`);
|
|
4031
|
+
continue;
|
|
4032
|
+
}
|
|
4033
|
+
if (task.agent === null) {
|
|
4034
|
+
if (task.scope === "per-run") {
|
|
4035
|
+
if (isTaskCompleted(state, taskName, PER_RUN_SENTINEL)) {
|
|
4036
|
+
warn(`workflow-engine: skipping completed task ${taskName} for ${PER_RUN_SENTINEL}`);
|
|
3947
4037
|
continue;
|
|
3948
4038
|
}
|
|
3949
4039
|
try {
|
|
3950
4040
|
const nullResult = await executeNullTask(
|
|
3951
4041
|
task,
|
|
3952
4042
|
taskName,
|
|
3953
|
-
|
|
4043
|
+
PER_RUN_SENTINEL,
|
|
3954
4044
|
state,
|
|
3955
4045
|
config,
|
|
3956
4046
|
lastOutputContract ?? void 0,
|
|
@@ -3960,71 +4050,56 @@ async function executeWorkflow(config) {
|
|
|
3960
4050
|
lastOutputContract = nullResult.contract;
|
|
3961
4051
|
tasksCompleted++;
|
|
3962
4052
|
} catch (err) {
|
|
3963
|
-
const engineError = isEngineError(err) ? err : handleDispatchError(err, taskName,
|
|
4053
|
+
const engineError = isEngineError(err) ? err : handleDispatchError(err, taskName, PER_RUN_SENTINEL);
|
|
3964
4054
|
errors.push(engineError);
|
|
3965
|
-
state = recordErrorInState(state, taskName,
|
|
4055
|
+
state = recordErrorInState(state, taskName, PER_RUN_SENTINEL, engineError);
|
|
3966
4056
|
writeWorkflowState(state, projectDir);
|
|
3967
4057
|
}
|
|
4058
|
+
} else {
|
|
4059
|
+
for (const item of workItems) {
|
|
4060
|
+
processedStories.add(item.key);
|
|
4061
|
+
if (isTaskCompleted(state, taskName, item.key)) {
|
|
4062
|
+
warn(`workflow-engine: skipping completed task ${taskName} for ${item.key}`);
|
|
4063
|
+
continue;
|
|
4064
|
+
}
|
|
4065
|
+
try {
|
|
4066
|
+
const nullResult = await executeNullTask(
|
|
4067
|
+
task,
|
|
4068
|
+
taskName,
|
|
4069
|
+
item.key,
|
|
4070
|
+
state,
|
|
4071
|
+
config,
|
|
4072
|
+
lastOutputContract ?? void 0,
|
|
4073
|
+
accumulatedCostUsd
|
|
4074
|
+
);
|
|
4075
|
+
state = nullResult.updatedState;
|
|
4076
|
+
lastOutputContract = nullResult.contract;
|
|
4077
|
+
tasksCompleted++;
|
|
4078
|
+
} catch (err) {
|
|
4079
|
+
const engineError = isEngineError(err) ? err : handleDispatchError(err, taskName, item.key);
|
|
4080
|
+
errors.push(engineError);
|
|
4081
|
+
state = recordErrorInState(state, taskName, item.key, engineError);
|
|
4082
|
+
writeWorkflowState(state, projectDir);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
3968
4085
|
}
|
|
3969
|
-
}
|
|
3970
|
-
continue;
|
|
3971
|
-
}
|
|
3972
|
-
const definition = config.agents[task.agent];
|
|
3973
|
-
if (!definition) {
|
|
3974
|
-
warn(`workflow-engine: agent "${task.agent}" not found for task "${taskName}", skipping`);
|
|
3975
|
-
continue;
|
|
3976
|
-
}
|
|
3977
|
-
if (task.scope === "per-run") {
|
|
3978
|
-
if (isTaskCompleted(state, taskName, PER_RUN_SENTINEL)) {
|
|
3979
|
-
warn(`workflow-engine: skipping completed task ${taskName} for ${PER_RUN_SENTINEL}`);
|
|
3980
4086
|
continue;
|
|
3981
4087
|
}
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
PER_RUN_SENTINEL,
|
|
3987
|
-
definition,
|
|
3988
|
-
state,
|
|
3989
|
-
config,
|
|
3990
|
-
void 0,
|
|
3991
|
-
lastOutputContract ?? void 0
|
|
3992
|
-
);
|
|
3993
|
-
state = dispatchResult.updatedState;
|
|
3994
|
-
lastOutputContract = dispatchResult.contract;
|
|
3995
|
-
propagateVerifyFlags(taskName, dispatchResult.contract, projectDir);
|
|
3996
|
-
accumulatedCostUsd += dispatchResult.contract?.cost_usd ?? 0;
|
|
3997
|
-
tasksCompleted++;
|
|
3998
|
-
} catch (err) {
|
|
3999
|
-
const engineError = handleDispatchError(err, taskName, PER_RUN_SENTINEL);
|
|
4000
|
-
errors.push(engineError);
|
|
4001
|
-
if (config.onEvent) {
|
|
4002
|
-
config.onEvent({ type: "dispatch-error", taskName, storyKey: PER_RUN_SENTINEL, error: { code: engineError.code, message: engineError.message } });
|
|
4003
|
-
} else {
|
|
4004
|
-
warn(`[${taskName}] ${PER_RUN_SENTINEL} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
4005
|
-
}
|
|
4006
|
-
state = recordErrorInState(state, taskName, PER_RUN_SENTINEL, engineError);
|
|
4007
|
-
writeWorkflowState(state, projectDir);
|
|
4008
|
-
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
4009
|
-
halted = true;
|
|
4010
|
-
}
|
|
4088
|
+
const definition = config.agents[task.agent];
|
|
4089
|
+
if (!definition) {
|
|
4090
|
+
warn(`workflow-engine: agent "${task.agent}" not found for task "${taskName}", skipping`);
|
|
4091
|
+
continue;
|
|
4011
4092
|
}
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
halted = true;
|
|
4016
|
-
break;
|
|
4017
|
-
}
|
|
4018
|
-
processedStories.add(item.key);
|
|
4019
|
-
if (isTaskCompleted(state, taskName, item.key)) {
|
|
4020
|
-
warn(`workflow-engine: skipping completed task ${taskName} for ${item.key}`);
|
|
4093
|
+
if (task.scope === "per-run") {
|
|
4094
|
+
if (isTaskCompleted(state, taskName, PER_RUN_SENTINEL)) {
|
|
4095
|
+
warn(`workflow-engine: skipping completed task ${taskName} for ${PER_RUN_SENTINEL}`);
|
|
4021
4096
|
continue;
|
|
4022
4097
|
}
|
|
4023
4098
|
try {
|
|
4024
4099
|
const dispatchResult = await dispatchTaskWithResult(
|
|
4025
4100
|
task,
|
|
4026
4101
|
taskName,
|
|
4027
|
-
|
|
4102
|
+
PER_RUN_SENTINEL,
|
|
4028
4103
|
definition,
|
|
4029
4104
|
state,
|
|
4030
4105
|
config,
|
|
@@ -4037,24 +4112,65 @@ async function executeWorkflow(config) {
|
|
|
4037
4112
|
accumulatedCostUsd += dispatchResult.contract?.cost_usd ?? 0;
|
|
4038
4113
|
tasksCompleted++;
|
|
4039
4114
|
} catch (err) {
|
|
4040
|
-
const engineError = handleDispatchError(err, taskName,
|
|
4115
|
+
const engineError = handleDispatchError(err, taskName, PER_RUN_SENTINEL);
|
|
4041
4116
|
errors.push(engineError);
|
|
4042
4117
|
if (config.onEvent) {
|
|
4043
|
-
config.onEvent({ type: "dispatch-error", taskName, storyKey:
|
|
4118
|
+
config.onEvent({ type: "dispatch-error", taskName, storyKey: PER_RUN_SENTINEL, error: { code: engineError.code, message: engineError.message } });
|
|
4044
4119
|
} else {
|
|
4045
|
-
warn(`[${taskName}] ${
|
|
4120
|
+
warn(`[${taskName}] ${PER_RUN_SENTINEL} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
4046
4121
|
}
|
|
4047
|
-
state = recordErrorInState(state, taskName,
|
|
4122
|
+
state = recordErrorInState(state, taskName, PER_RUN_SENTINEL, engineError);
|
|
4048
4123
|
writeWorkflowState(state, projectDir);
|
|
4049
4124
|
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
4050
4125
|
halted = true;
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
} else {
|
|
4129
|
+
for (const item of workItems) {
|
|
4130
|
+
if (config.abortSignal?.aborted) {
|
|
4131
|
+
halted = true;
|
|
4051
4132
|
break;
|
|
4052
4133
|
}
|
|
4053
|
-
|
|
4134
|
+
processedStories.add(item.key);
|
|
4135
|
+
if (isTaskCompleted(state, taskName, item.key)) {
|
|
4136
|
+
warn(`workflow-engine: skipping completed task ${taskName} for ${item.key}`);
|
|
4137
|
+
continue;
|
|
4138
|
+
}
|
|
4139
|
+
try {
|
|
4140
|
+
const dispatchResult = await dispatchTaskWithResult(
|
|
4141
|
+
task,
|
|
4142
|
+
taskName,
|
|
4143
|
+
item.key,
|
|
4144
|
+
definition,
|
|
4145
|
+
state,
|
|
4146
|
+
config,
|
|
4147
|
+
void 0,
|
|
4148
|
+
lastOutputContract ?? void 0
|
|
4149
|
+
);
|
|
4150
|
+
state = dispatchResult.updatedState;
|
|
4151
|
+
lastOutputContract = dispatchResult.contract;
|
|
4152
|
+
propagateVerifyFlags(taskName, dispatchResult.contract, projectDir);
|
|
4153
|
+
accumulatedCostUsd += dispatchResult.contract?.cost_usd ?? 0;
|
|
4154
|
+
tasksCompleted++;
|
|
4155
|
+
} catch (err) {
|
|
4156
|
+
const engineError = handleDispatchError(err, taskName, item.key);
|
|
4157
|
+
errors.push(engineError);
|
|
4158
|
+
if (config.onEvent) {
|
|
4159
|
+
config.onEvent({ type: "dispatch-error", taskName, storyKey: item.key, error: { code: engineError.code, message: engineError.message } });
|
|
4160
|
+
} else {
|
|
4161
|
+
warn(`[${taskName}] ${item.key} \u2014 ERROR: [${engineError.code}] ${engineError.message}`);
|
|
4162
|
+
}
|
|
4163
|
+
state = recordErrorInState(state, taskName, item.key, engineError);
|
|
4164
|
+
writeWorkflowState(state, projectDir);
|
|
4165
|
+
if (err instanceof DispatchError && HALT_ERROR_CODES.has(err.code)) {
|
|
4166
|
+
halted = true;
|
|
4167
|
+
break;
|
|
4168
|
+
}
|
|
4169
|
+
continue;
|
|
4170
|
+
}
|
|
4054
4171
|
}
|
|
4055
4172
|
}
|
|
4056
4173
|
}
|
|
4057
|
-
}
|
|
4058
4174
|
if (state.phase === "interrupted") {
|
|
4059
4175
|
} else if (errors.length === 0 && state.phase !== "max-iterations" && state.phase !== "circuit-breaker") {
|
|
4060
4176
|
state = { ...state, phase: "completed" };
|
|
@@ -5430,14 +5546,17 @@ function LaneActivityHeader({ activeLaneId, laneCount }) {
|
|
|
5430
5546
|
if (laneCount <= 1 || !activeLaneId) return null;
|
|
5431
5547
|
return /* @__PURE__ */ jsx7(Text7, { children: /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: `[Lane ${activeLaneId} \u25B8]` }) });
|
|
5432
5548
|
}
|
|
5433
|
-
function App({ state, onCycleLane }) {
|
|
5549
|
+
function App({ state, onCycleLane, onQuit }) {
|
|
5434
5550
|
const lanes = state.lanes;
|
|
5435
5551
|
const laneCount = lanes?.length ?? 0;
|
|
5436
5552
|
const terminalWidth = process.stdout.columns || 80;
|
|
5437
|
-
useInput((
|
|
5438
|
-
if (key.ctrl &&
|
|
5553
|
+
useInput((input, key) => {
|
|
5554
|
+
if (key.ctrl && input === "l" && onCycleLane && laneCount > 1) {
|
|
5439
5555
|
onCycleLane();
|
|
5440
5556
|
}
|
|
5557
|
+
if (input === "q" && onQuit) {
|
|
5558
|
+
onQuit();
|
|
5559
|
+
}
|
|
5441
5560
|
}, { isActive: typeof process.stdin.setRawMode === "function" });
|
|
5442
5561
|
const activeLaneCount = state.laneCount ?? 0;
|
|
5443
5562
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
@@ -5661,7 +5780,8 @@ function startRenderer(options) {
|
|
|
5661
5780
|
let lastStoryKey = state.sprintInfo?.storyKey ?? null;
|
|
5662
5781
|
const pendingStoryCosts = /* @__PURE__ */ new Map();
|
|
5663
5782
|
let cleaned = false;
|
|
5664
|
-
const
|
|
5783
|
+
const onQuit = options?.onQuit;
|
|
5784
|
+
const inkInstance = inkRender(/* @__PURE__ */ jsx9(App, { state, onCycleLane: () => cycleLane(), onQuit: onQuit ? () => onQuit() : void 0 }), {
|
|
5665
5785
|
exitOnCtrlC: false,
|
|
5666
5786
|
patchConsole: !options?._forceTTY,
|
|
5667
5787
|
maxFps: 15
|
|
@@ -5669,7 +5789,7 @@ function startRenderer(options) {
|
|
|
5669
5789
|
function rerender() {
|
|
5670
5790
|
if (!cleaned) {
|
|
5671
5791
|
state = { ...state };
|
|
5672
|
-
inkInstance.rerender(/* @__PURE__ */ jsx9(App, { state, onCycleLane: () => cycleLane() }));
|
|
5792
|
+
inkInstance.rerender(/* @__PURE__ */ jsx9(App, { state, onCycleLane: () => cycleLane(), onQuit: onQuit ? () => onQuit() : void 0 }));
|
|
5673
5793
|
}
|
|
5674
5794
|
}
|
|
5675
5795
|
const heartbeat = setInterval(() => {
|
|
@@ -6175,17 +6295,8 @@ function registerRunCommand(program) {
|
|
|
6175
6295
|
}
|
|
6176
6296
|
}
|
|
6177
6297
|
const abortController = new AbortController();
|
|
6178
|
-
const renderer = startRenderer({
|
|
6179
|
-
quiet: !!options.quiet || isJson,
|
|
6180
|
-
sprintState: {
|
|
6181
|
-
storyKey: "",
|
|
6182
|
-
phase: "executing",
|
|
6183
|
-
done: counts.done,
|
|
6184
|
-
total: counts.total,
|
|
6185
|
-
totalCost: 0
|
|
6186
|
-
}
|
|
6187
|
-
});
|
|
6188
6298
|
let interrupted = false;
|
|
6299
|
+
let renderer;
|
|
6189
6300
|
const onInterrupt = () => {
|
|
6190
6301
|
if (interrupted) {
|
|
6191
6302
|
process.exit(1);
|
|
@@ -6195,6 +6306,17 @@ function registerRunCommand(program) {
|
|
|
6195
6306
|
abortController.abort();
|
|
6196
6307
|
info("Interrupted \u2014 waiting for current task to finish...", outputOpts);
|
|
6197
6308
|
};
|
|
6309
|
+
renderer = startRenderer({
|
|
6310
|
+
quiet: !!options.quiet || isJson,
|
|
6311
|
+
sprintState: {
|
|
6312
|
+
storyKey: "",
|
|
6313
|
+
phase: "executing",
|
|
6314
|
+
done: counts.done,
|
|
6315
|
+
total: counts.total,
|
|
6316
|
+
totalCost: 0
|
|
6317
|
+
},
|
|
6318
|
+
onQuit: () => onInterrupt()
|
|
6319
|
+
});
|
|
6198
6320
|
process.on("SIGINT", onInterrupt);
|
|
6199
6321
|
process.on("SIGTERM", onInterrupt);
|
|
6200
6322
|
const sessionStartMs = Date.now();
|
|
@@ -6286,6 +6408,7 @@ function registerRunCommand(program) {
|
|
|
6286
6408
|
runId: `run-${Date.now()}`,
|
|
6287
6409
|
projectDir,
|
|
6288
6410
|
abortSignal: abortController.signal,
|
|
6411
|
+
storyPipeline: true,
|
|
6289
6412
|
maxIterations,
|
|
6290
6413
|
onEvent
|
|
6291
6414
|
};
|
|
@@ -11167,7 +11290,7 @@ function registerTeardownCommand(program) {
|
|
|
11167
11290
|
} else if (otlpMode === "remote-routed") {
|
|
11168
11291
|
if (!options.keepDocker) {
|
|
11169
11292
|
try {
|
|
11170
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
11293
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-7QONH2B5.js");
|
|
11171
11294
|
stopCollectorOnly2();
|
|
11172
11295
|
result.docker.stopped = true;
|
|
11173
11296
|
if (!isJson) {
|
|
@@ -11199,7 +11322,7 @@ function registerTeardownCommand(program) {
|
|
|
11199
11322
|
info("Shared stack: kept running (other projects may use it)");
|
|
11200
11323
|
}
|
|
11201
11324
|
} else if (isLegacyStack) {
|
|
11202
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
11325
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-7QONH2B5.js");
|
|
11203
11326
|
let stackRunning = false;
|
|
11204
11327
|
try {
|
|
11205
11328
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -14095,7 +14218,7 @@ function registerDriversCommand(program) {
|
|
|
14095
14218
|
}
|
|
14096
14219
|
|
|
14097
14220
|
// src/index.ts
|
|
14098
|
-
var VERSION = true ? "0.
|
|
14221
|
+
var VERSION = true ? "0.30.0" : "0.0.0-dev";
|
|
14099
14222
|
function createProgram() {
|
|
14100
14223
|
const program = new Command();
|
|
14101
14224
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|