codeharness 0.36.4 → 0.36.6
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.
|
@@ -1774,7 +1774,7 @@ function checkDocker(opts) {
|
|
|
1774
1774
|
}
|
|
1775
1775
|
function setupDocker(opts) {
|
|
1776
1776
|
try {
|
|
1777
|
-
|
|
1777
|
+
const state = { ...opts.state };
|
|
1778
1778
|
if (!opts.observability) {
|
|
1779
1779
|
writeState(state, opts.projectDir);
|
|
1780
1780
|
if (!opts.isJson) {
|
|
@@ -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.36.
|
|
2898
|
+
var HARNESS_VERSION = true ? "0.36.6" : "0.0.0-dev";
|
|
2899
2899
|
function failResult(opts, error) {
|
|
2900
2900
|
return {
|
|
2901
2901
|
status: "fail",
|
|
@@ -3013,7 +3013,7 @@ async function initProjectInner(opts) {
|
|
|
3013
3013
|
result.beads = { status: "skipped", message: "beads removed" };
|
|
3014
3014
|
const bmadResult = setupBmad({ projectDir, isJson });
|
|
3015
3015
|
if (isOk(bmadResult)) result.bmad = bmadResult.data;
|
|
3016
|
-
|
|
3016
|
+
const state = getDefaultState(stack);
|
|
3017
3017
|
state.harness_version = HARNESS_VERSION;
|
|
3018
3018
|
state.initialized = true;
|
|
3019
3019
|
state.app_type = appType;
|
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-VB6M7AES.js";
|
|
44
44
|
|
|
45
45
|
// src/index.ts
|
|
46
46
|
import { Command } from "commander";
|
|
@@ -3171,7 +3171,7 @@ function formatCoverageContextMessage(coverage, target) {
|
|
|
3171
3171
|
return `Coverage already verified by engine: ${coverage}% (target: ${target}%). No re-run needed.`;
|
|
3172
3172
|
}
|
|
3173
3173
|
|
|
3174
|
-
// src/lib/workflow-
|
|
3174
|
+
// src/lib/workflow-constants.ts
|
|
3175
3175
|
var TASK_PROMPTS = {
|
|
3176
3176
|
"create-story": (key) => `Create the story spec for ${key}. Read the epic definitions and architecture docs. Write a complete story file with acceptance criteria, tasks, and dev notes. CRITICAL: Every AC must be testable by a blind QA agent using ONLY a user guide + browser/API/CLI access. No AC should reference source code, internal data structures, or implementation details like O(1) complexity. Each AC must describe observable behavior that can be verified through UI interaction (agent-browser), API calls (curl), CLI commands (docker exec), or log inspection (docker logs). Wrap output in <story-spec>...</story-spec> tags.`,
|
|
3177
3177
|
"implement": (key) => `Implement story ${key}`,
|
|
@@ -3192,6 +3192,8 @@ var FILE_WRITE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
3192
3192
|
"WriteFile",
|
|
3193
3193
|
"EditFile"
|
|
3194
3194
|
]);
|
|
3195
|
+
|
|
3196
|
+
// src/lib/workflow-actors.ts
|
|
3195
3197
|
function buildCoverageDeduplicationContext(contract, projectDir) {
|
|
3196
3198
|
if (!contract?.testResults) return null;
|
|
3197
3199
|
const { coverage } = contract.testResults;
|
|
@@ -3199,8 +3201,7 @@ function buildCoverageDeduplicationContext(contract, projectDir) {
|
|
|
3199
3201
|
try {
|
|
3200
3202
|
const { state } = readStateWithBody(projectDir);
|
|
3201
3203
|
if (!state.session_flags.coverage_met) return null;
|
|
3202
|
-
|
|
3203
|
-
return formatCoverageContextMessage(coverage, target);
|
|
3204
|
+
return formatCoverageContextMessage(coverage, state.coverage.target ?? 90);
|
|
3204
3205
|
} catch {
|
|
3205
3206
|
return null;
|
|
3206
3207
|
}
|
|
@@ -3215,14 +3216,7 @@ async function nullTaskCore(input) {
|
|
|
3215
3216
|
}
|
|
3216
3217
|
const startMs = Date.now();
|
|
3217
3218
|
const workflowStartMs = workflowState.started ? new Date(workflowState.started).getTime() : startMs;
|
|
3218
|
-
const ctx = {
|
|
3219
|
-
storyKey,
|
|
3220
|
-
taskName,
|
|
3221
|
-
cost: accumulatedCostUsd,
|
|
3222
|
-
durationMs: startMs - workflowStartMs,
|
|
3223
|
-
outputContract: previousContract,
|
|
3224
|
-
projectDir
|
|
3225
|
-
};
|
|
3219
|
+
const ctx = { storyKey, taskName, cost: accumulatedCostUsd, durationMs: startMs - workflowStartMs, outputContract: previousContract, projectDir };
|
|
3226
3220
|
let result;
|
|
3227
3221
|
try {
|
|
3228
3222
|
result = await handler(ctx);
|
|
@@ -3253,8 +3247,7 @@ async function nullTaskCore(input) {
|
|
|
3253
3247
|
return { output: result.output ?? "", cost: 0, changedFiles: [], sessionId: "", contract, updatedState };
|
|
3254
3248
|
}
|
|
3255
3249
|
function propagateVerifyFlags(taskName, contract, projectDir) {
|
|
3256
|
-
if (taskName !== "implement") return;
|
|
3257
|
-
if (!contract?.testResults) return;
|
|
3250
|
+
if (taskName !== "implement" || !contract?.testResults) return;
|
|
3258
3251
|
const { failed, coverage } = contract.testResults;
|
|
3259
3252
|
try {
|
|
3260
3253
|
const { state, body } = readStateWithBody(projectDir);
|
|
@@ -3264,8 +3257,7 @@ function propagateVerifyFlags(taskName, contract, projectDir) {
|
|
|
3264
3257
|
}
|
|
3265
3258
|
writeState(state, projectDir, body);
|
|
3266
3259
|
} catch (err) {
|
|
3267
|
-
|
|
3268
|
-
warn(`workflow-actors: flag propagation failed for ${taskName}: ${msg}`);
|
|
3260
|
+
warn(`workflow-actors: flag propagation failed for ${taskName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3269
3261
|
}
|
|
3270
3262
|
}
|
|
3271
3263
|
async function dispatchTaskCore(input) {
|
|
@@ -3290,14 +3282,7 @@ async function dispatchTaskCore(input) {
|
|
|
3290
3282
|
} else {
|
|
3291
3283
|
cwd = projectDir;
|
|
3292
3284
|
}
|
|
3293
|
-
|
|
3294
|
-
if (customPrompt) {
|
|
3295
|
-
basePrompt = customPrompt;
|
|
3296
|
-
} else if (TASK_PROMPTS[taskName]) {
|
|
3297
|
-
basePrompt = TASK_PROMPTS[taskName](storyKey);
|
|
3298
|
-
} else {
|
|
3299
|
-
basePrompt = `Execute task "${taskName}" for story ${storyKey}`;
|
|
3300
|
-
}
|
|
3285
|
+
const basePrompt = customPrompt ?? (TASK_PROMPTS[taskName]?.(storyKey) ?? `Execute task "${taskName}" for story ${storyKey}`);
|
|
3301
3286
|
let prompt = buildPromptWithContractContext(basePrompt, previousContract);
|
|
3302
3287
|
const coverageDedup = buildCoverageDeduplicationContext(previousContract, projectDir);
|
|
3303
3288
|
if (coverageDedup) prompt = `${prompt}
|
|
@@ -3396,8 +3381,7 @@ ${coverageDedup}`;
|
|
|
3396
3381
|
};
|
|
3397
3382
|
writeOutputContract(contract, join12(projectDir, ".codeharness", "contracts"));
|
|
3398
3383
|
} catch (err) {
|
|
3399
|
-
|
|
3400
|
-
warn(`workflow-actors: failed to write output contract for ${taskName}/${storyKey}: ${msg}`);
|
|
3384
|
+
warn(`workflow-actors: failed to write output contract for ${taskName}/${storyKey}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3401
3385
|
contract = null;
|
|
3402
3386
|
}
|
|
3403
3387
|
writeWorkflowState(updatedState, projectDir);
|
|
@@ -3405,9 +3389,7 @@ ${coverageDedup}`;
|
|
|
3405
3389
|
return { output, cost, changedFiles, sessionId: resultSessionId, contract, updatedState };
|
|
3406
3390
|
}
|
|
3407
3391
|
var dispatchActor = fromPromise(async ({ input }) => dispatchTaskCore(input));
|
|
3408
|
-
var nullTaskDispatchActor = fromPromise(async ({ input }) =>
|
|
3409
|
-
return nullTaskCore(input);
|
|
3410
|
-
});
|
|
3392
|
+
var nullTaskDispatchActor = fromPromise(async ({ input }) => nullTaskCore(input));
|
|
3411
3393
|
|
|
3412
3394
|
// src/lib/workflow-machine.ts
|
|
3413
3395
|
var HALT_ERROR_CODES = /* @__PURE__ */ new Set(["RATE_LIMIT", "NETWORK", "SDK_INIT"]);
|
|
@@ -3520,8 +3502,9 @@ function isLoopBlock(step) {
|
|
|
3520
3502
|
return typeof step === "object" && step !== null && "loop" in step;
|
|
3521
3503
|
}
|
|
3522
3504
|
var loopIterationActor = fromPromise2(async ({ input }) => {
|
|
3523
|
-
const { loopBlock, config, workItems, storyFlowTasks, onStreamEvent, maxIterations } = input;
|
|
3524
|
-
|
|
3505
|
+
const { loopBlock, config, workItems, storyFlowTasks, onStreamEvent, maxIterations: _maxIterations } = input;
|
|
3506
|
+
const { errors } = input;
|
|
3507
|
+
let { currentState, tasksCompleted, lastContract, lastVerdict, accumulatedCostUsd } = input;
|
|
3525
3508
|
const projectDir = config.projectDir ?? process.cwd();
|
|
3526
3509
|
const RUN_SENTINEL = "__run__";
|
|
3527
3510
|
const lastAgentTaskInLoop = (() => {
|
|
@@ -3635,6 +3618,10 @@ var loopIterationActor = fromPromise2(async ({ input }) => {
|
|
|
3635
3618
|
}
|
|
3636
3619
|
if (haltedInLoop) break;
|
|
3637
3620
|
}
|
|
3621
|
+
if (tasksCompleted === 0 && !haltedInLoop && errors.length > 0) {
|
|
3622
|
+
warn(`workflow-machine: loop iteration produced zero completions with ${errors.length} error(s) \u2014 halting to prevent infinite loop`);
|
|
3623
|
+
haltedInLoop = true;
|
|
3624
|
+
}
|
|
3638
3625
|
return { ...input, currentState, errors, tasksCompleted, halted: haltedInLoop, lastContract, lastVerdict, accumulatedCostUsd };
|
|
3639
3626
|
});
|
|
3640
3627
|
var loopMachine = setup({
|
|
@@ -3880,7 +3867,8 @@ var storyFlowActor = fromPromise2(async ({ input }) => {
|
|
|
3880
3867
|
});
|
|
3881
3868
|
var epicStepActor = fromPromise2(async ({ input }) => {
|
|
3882
3869
|
const { epicId, epicItems, config, storyFlowTasks } = input;
|
|
3883
|
-
|
|
3870
|
+
const { errors, storiesProcessed, currentStepIndex } = input;
|
|
3871
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
3884
3872
|
const projectDir = config.projectDir ?? process.cwd();
|
|
3885
3873
|
const step = config.workflow.epicFlow[currentStepIndex];
|
|
3886
3874
|
if (!step || halted || config.abortSignal?.aborted) {
|
|
@@ -4014,7 +4002,8 @@ var epicMachine = setup({
|
|
|
4014
4002
|
});
|
|
4015
4003
|
var runEpicActor = fromPromise2(async ({ input }) => {
|
|
4016
4004
|
const { config, storyFlowTasks, epicEntries, currentEpicIndex } = input;
|
|
4017
|
-
|
|
4005
|
+
const { errors, storiesProcessed } = input;
|
|
4006
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
4018
4007
|
if (currentEpicIndex >= epicEntries.length || halted || config.abortSignal?.aborted) {
|
|
4019
4008
|
if (config.abortSignal?.aborted) {
|
|
4020
4009
|
const projectDir = config.projectDir ?? process.cwd();
|
|
@@ -5058,12 +5047,12 @@ function LastThought({ text }) {
|
|
|
5058
5047
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: text })
|
|
5059
5048
|
] });
|
|
5060
5049
|
}
|
|
5061
|
-
function RetryNotice({ info:
|
|
5050
|
+
function RetryNotice({ info: info2 }) {
|
|
5062
5051
|
return /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
5063
5052
|
"\u23F3 API retry ",
|
|
5064
|
-
|
|
5053
|
+
info2.attempt,
|
|
5065
5054
|
" (waiting ",
|
|
5066
|
-
|
|
5055
|
+
info2.delay,
|
|
5067
5056
|
"ms)"
|
|
5068
5057
|
] });
|
|
5069
5058
|
}
|
|
@@ -5128,7 +5117,7 @@ function loopIteration(tasks, taskStates) {
|
|
|
5128
5117
|
});
|
|
5129
5118
|
return anyStarted ? 1 : 0;
|
|
5130
5119
|
}
|
|
5131
|
-
function WorkflowGraph({ flow, currentTask, taskStates, taskMeta }) {
|
|
5120
|
+
function WorkflowGraph({ flow, currentTask: _currentTask, taskStates, taskMeta }) {
|
|
5132
5121
|
if (flow.length === 0 || Object.keys(taskStates).length === 0) {
|
|
5133
5122
|
return null;
|
|
5134
5123
|
}
|
|
@@ -5536,12 +5525,12 @@ function Separator() {
|
|
|
5536
5525
|
function formatCost2(cost) {
|
|
5537
5526
|
return `$${cost.toFixed(2)}`;
|
|
5538
5527
|
}
|
|
5539
|
-
function Header({ info:
|
|
5540
|
-
if (!
|
|
5528
|
+
function Header({ info: info2, laneCount }) {
|
|
5529
|
+
if (!info2) return null;
|
|
5541
5530
|
const parts = ["codeharness run"];
|
|
5542
5531
|
if (laneCount != null && laneCount > 1) parts.push(`${laneCount} lanes`);
|
|
5543
|
-
if (
|
|
5544
|
-
const displayCost = laneCount != null && laneCount > 1 &&
|
|
5532
|
+
if (info2.elapsed) parts.push(`${info2.elapsed} elapsed`);
|
|
5533
|
+
const displayCost = laneCount != null && laneCount > 1 && info2.laneTotalCost != null ? info2.laneTotalCost : info2.totalCost;
|
|
5545
5534
|
if (displayCost != null) parts.push(`${formatCost2(displayCost)} spent`);
|
|
5546
5535
|
const left = parts.join(" | ");
|
|
5547
5536
|
const right = "[q to quit]";
|
|
@@ -5570,20 +5559,20 @@ function ProgressBar({ done, total, inProgress }) {
|
|
|
5570
5559
|
` ${label}`
|
|
5571
5560
|
] });
|
|
5572
5561
|
}
|
|
5573
|
-
function EpicInfo({ info:
|
|
5574
|
-
if (!
|
|
5575
|
-
const title =
|
|
5576
|
-
const epicPrefix2 = `${
|
|
5562
|
+
function EpicInfo({ info: info2, stories }) {
|
|
5563
|
+
if (!info2?.epicId) return null;
|
|
5564
|
+
const title = info2.epicTitle ?? `Epic ${info2.epicId}`;
|
|
5565
|
+
const epicPrefix2 = `${info2.epicId}-`;
|
|
5577
5566
|
const epicStories = stories?.filter((s) => s.key.startsWith(epicPrefix2)) ?? [];
|
|
5578
5567
|
const ipCount = epicStories.filter((s) => s.status === "in-progress").length;
|
|
5579
|
-
const doneCount =
|
|
5580
|
-
const totalCount =
|
|
5568
|
+
const doneCount = info2.epicStoriesDone ?? 0;
|
|
5569
|
+
const totalCount = info2.epicStoriesTotal ?? epicStories.length;
|
|
5581
5570
|
const progressParts = [];
|
|
5582
5571
|
if (doneCount > 0) progressParts.push(`${doneCount} verified`);
|
|
5583
5572
|
if (ipCount > 0) progressParts.push(`${ipCount} implemented`);
|
|
5584
5573
|
const progress = totalCount > 0 ? ` \u2014 ${progressParts.join(", ")} / ${totalCount} stories` : "";
|
|
5585
5574
|
return /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
5586
|
-
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${
|
|
5575
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${info2.epicId}: ${title}` }),
|
|
5587
5576
|
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: progress })
|
|
5588
5577
|
] });
|
|
5589
5578
|
}
|
|
@@ -6352,7 +6341,6 @@ function registerRunCommand(program) {
|
|
|
6352
6341
|
}
|
|
6353
6342
|
}
|
|
6354
6343
|
if (isEpicTask) {
|
|
6355
|
-
const epicStories = storyEntries.filter((s) => s.key.startsWith(`${epicId}-`));
|
|
6356
6344
|
renderer.updateStories([...storyEntries]);
|
|
6357
6345
|
}
|
|
6358
6346
|
}
|
|
@@ -6530,7 +6518,7 @@ function registerRunCommand(program) {
|
|
|
6530
6518
|
}
|
|
6531
6519
|
|
|
6532
6520
|
// src/commands/verify.ts
|
|
6533
|
-
import { existsSync as
|
|
6521
|
+
import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
|
|
6534
6522
|
import { join as join29 } from "path";
|
|
6535
6523
|
|
|
6536
6524
|
// src/modules/verify/index.ts
|
|
@@ -7349,7 +7337,7 @@ function closeBeadsIssue(_storyId, _dir) {
|
|
|
7349
7337
|
}
|
|
7350
7338
|
|
|
7351
7339
|
// src/modules/verify/parser.ts
|
|
7352
|
-
import { existsSync as
|
|
7340
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
7353
7341
|
|
|
7354
7342
|
// src/modules/verify/parser-keywords.ts
|
|
7355
7343
|
var UI_KEYWORDS = [
|
|
@@ -7393,7 +7381,7 @@ function classifyAC(description) {
|
|
|
7393
7381
|
return "general";
|
|
7394
7382
|
}
|
|
7395
7383
|
function parseStoryACs(storyFilePath) {
|
|
7396
|
-
if (!
|
|
7384
|
+
if (!existsSync22(storyFilePath)) {
|
|
7397
7385
|
throw new Error(
|
|
7398
7386
|
`Story file not found: ${storyFilePath}. Ensure the story file exists at the expected path.`
|
|
7399
7387
|
);
|
|
@@ -7609,7 +7597,7 @@ function normalizeSeverity(severity) {
|
|
|
7609
7597
|
}
|
|
7610
7598
|
|
|
7611
7599
|
// src/modules/observability/coverage.ts
|
|
7612
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync11, renameSync as renameSync3, existsSync as
|
|
7600
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync11, renameSync as renameSync3, existsSync as existsSync23 } from "fs";
|
|
7613
7601
|
import { join as join23 } from "path";
|
|
7614
7602
|
var STATE_FILE2 = "sprint-state.json";
|
|
7615
7603
|
var DEFAULT_STATIC_TARGET = 80;
|
|
@@ -7627,7 +7615,7 @@ function defaultCoverageState() {
|
|
|
7627
7615
|
}
|
|
7628
7616
|
function readStateFile(projectDir) {
|
|
7629
7617
|
const fp = join23(projectDir, STATE_FILE2);
|
|
7630
|
-
if (!
|
|
7618
|
+
if (!existsSync23(fp)) {
|
|
7631
7619
|
return ok2({});
|
|
7632
7620
|
}
|
|
7633
7621
|
try {
|
|
@@ -7698,7 +7686,7 @@ function parseGapArray(raw) {
|
|
|
7698
7686
|
}
|
|
7699
7687
|
|
|
7700
7688
|
// src/modules/observability/runtime-coverage.ts
|
|
7701
|
-
import { readFileSync as readFileSync21, writeFileSync as writeFileSync12, renameSync as renameSync4, existsSync as
|
|
7689
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync12, renameSync as renameSync4, existsSync as existsSync24 } from "fs";
|
|
7702
7690
|
import { join as join24 } from "path";
|
|
7703
7691
|
|
|
7704
7692
|
// src/modules/observability/coverage-gate.ts
|
|
@@ -7902,7 +7890,7 @@ function parseLogEvents(text) {
|
|
|
7902
7890
|
|
|
7903
7891
|
// src/modules/verify/browser.ts
|
|
7904
7892
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7905
|
-
import { existsSync as
|
|
7893
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
|
|
7906
7894
|
|
|
7907
7895
|
// src/modules/verify/validation-ac-fr.ts
|
|
7908
7896
|
var FR_ACS = [
|
|
@@ -8541,7 +8529,7 @@ function getACById(id) {
|
|
|
8541
8529
|
// src/modules/verify/validation-runner.ts
|
|
8542
8530
|
import { execSync as execSync5 } from "child_process";
|
|
8543
8531
|
import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync10 } from "fs";
|
|
8544
|
-
import { join as join26, dirname as
|
|
8532
|
+
import { join as join26, dirname as dirname2 } from "path";
|
|
8545
8533
|
var MAX_VALIDATION_ATTEMPTS = 10;
|
|
8546
8534
|
var AC_COMMAND_TIMEOUT_MS = 3e4;
|
|
8547
8535
|
var VAL_KEY_PREFIX = "val-";
|
|
@@ -8693,7 +8681,7 @@ function createFixStory(ac, error) {
|
|
|
8693
8681
|
"Fix the root cause so the validation command passes.",
|
|
8694
8682
|
""
|
|
8695
8683
|
].join("\n");
|
|
8696
|
-
mkdirSync10(
|
|
8684
|
+
mkdirSync10(dirname2(storyPath), { recursive: true });
|
|
8697
8685
|
writeFileSync13(storyPath, markdown, "utf-8");
|
|
8698
8686
|
return ok2(storyKey);
|
|
8699
8687
|
} catch (err) {
|
|
@@ -9020,7 +9008,7 @@ function runValidationCycle() {
|
|
|
9020
9008
|
|
|
9021
9009
|
// src/modules/verify/env.ts
|
|
9022
9010
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
9023
|
-
import { existsSync as
|
|
9011
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync14, cpSync, rmSync as rmSync3, statSync as statSync6 } from "fs";
|
|
9024
9012
|
import { join as join28, basename as basename2 } from "path";
|
|
9025
9013
|
import { createHash } from "crypto";
|
|
9026
9014
|
|
|
@@ -9075,7 +9063,7 @@ function isValidStoryKey(storyKey) {
|
|
|
9075
9063
|
}
|
|
9076
9064
|
function computeDistHash(projectDir) {
|
|
9077
9065
|
const distDir = join28(projectDir, "dist");
|
|
9078
|
-
if (!
|
|
9066
|
+
if (!existsSync26(distDir)) return null;
|
|
9079
9067
|
const hash = createHash("sha256");
|
|
9080
9068
|
const files = collectFiles(distDir).sort();
|
|
9081
9069
|
for (const file of files) {
|
|
@@ -9123,7 +9111,7 @@ function detectProjectType(projectDir) {
|
|
|
9123
9111
|
const rootDetection = allStacks.find((s) => s.dir === ".");
|
|
9124
9112
|
const stack = rootDetection ? rootDetection.stack : null;
|
|
9125
9113
|
if (stack && STACK_TO_PROJECT_TYPE[stack]) return STACK_TO_PROJECT_TYPE[stack];
|
|
9126
|
-
if (
|
|
9114
|
+
if (existsSync26(join28(projectDir, ".claude-plugin", "plugin.json"))) return "plugin";
|
|
9127
9115
|
return "generic";
|
|
9128
9116
|
}
|
|
9129
9117
|
function buildVerifyImage(options = {}) {
|
|
@@ -9221,15 +9209,15 @@ function prepareVerifyWorkspace(storyKey, projectDir) {
|
|
|
9221
9209
|
throw new Error(`Invalid story key: ${storyKey}. Keys must contain only alphanumeric characters, hyphens, and underscores.`);
|
|
9222
9210
|
}
|
|
9223
9211
|
const storyFile = join28(root, STORY_DIR, `${storyKey}.md`);
|
|
9224
|
-
if (!
|
|
9212
|
+
if (!existsSync26(storyFile)) throw new Error(`Story file not found: ${storyFile}`);
|
|
9225
9213
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9226
|
-
if (
|
|
9214
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9227
9215
|
mkdirSync11(workspace, { recursive: true });
|
|
9228
9216
|
cpSync(storyFile, join28(workspace, "story.md"));
|
|
9229
9217
|
const readmePath = join28(root, "README.md");
|
|
9230
|
-
if (
|
|
9218
|
+
if (existsSync26(readmePath)) cpSync(readmePath, join28(workspace, "README.md"));
|
|
9231
9219
|
const docsDir = join28(root, "docs");
|
|
9232
|
-
if (
|
|
9220
|
+
if (existsSync26(docsDir) && statSync6(docsDir).isDirectory()) {
|
|
9233
9221
|
cpSync(docsDir, join28(workspace, "docs"), { recursive: true });
|
|
9234
9222
|
}
|
|
9235
9223
|
mkdirSync11(join28(workspace, "verification"), { recursive: true });
|
|
@@ -9274,7 +9262,7 @@ function cleanupVerifyEnv(storyKey) {
|
|
|
9274
9262
|
}
|
|
9275
9263
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9276
9264
|
const containerName = `codeharness-verify-${storyKey}`;
|
|
9277
|
-
if (
|
|
9265
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9278
9266
|
try {
|
|
9279
9267
|
execFileSync5("docker", ["stop", containerName], { stdio: "pipe", timeout: 15e3 });
|
|
9280
9268
|
} catch {
|
|
@@ -9292,7 +9280,7 @@ function buildPluginImage(projectDir) {
|
|
|
9292
9280
|
cpSync(pluginDir, join28(buildContext, ".claude-plugin"), { recursive: true });
|
|
9293
9281
|
for (const dir of ["commands", "hooks", "knowledge", "skills"]) {
|
|
9294
9282
|
const src = join28(projectDir, dir);
|
|
9295
|
-
if (
|
|
9283
|
+
if (existsSync26(src) && statSync6(src).isDirectory()) {
|
|
9296
9284
|
cpSync(src, join28(buildContext, dir), { recursive: true });
|
|
9297
9285
|
}
|
|
9298
9286
|
}
|
|
@@ -9393,7 +9381,7 @@ function verifyRetro(opts, isJson, root) {
|
|
|
9393
9381
|
}
|
|
9394
9382
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
9395
9383
|
const retroPath = join29(root, STORY_DIR2, retroFile);
|
|
9396
|
-
if (!
|
|
9384
|
+
if (!existsSync27(retroPath)) {
|
|
9397
9385
|
if (isJson) {
|
|
9398
9386
|
jsonOutput({ status: "fail", epic: epicNum, retroFile, message: `${retroFile} not found` });
|
|
9399
9387
|
} else {
|
|
@@ -9422,7 +9410,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9422
9410
|
return;
|
|
9423
9411
|
}
|
|
9424
9412
|
const readmePath = join29(root, "README.md");
|
|
9425
|
-
if (!
|
|
9413
|
+
if (!existsSync27(readmePath)) {
|
|
9426
9414
|
if (isJson) {
|
|
9427
9415
|
jsonOutput({ status: "fail", message: "No README.md found \u2014 verification requires user documentation" });
|
|
9428
9416
|
} else {
|
|
@@ -9432,7 +9420,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9432
9420
|
return;
|
|
9433
9421
|
}
|
|
9434
9422
|
const storyFilePath = join29(root, STORY_DIR2, `${storyId}.md`);
|
|
9435
|
-
if (!
|
|
9423
|
+
if (!existsSync27(storyFilePath)) {
|
|
9436
9424
|
fail(`Story file not found: ${storyFilePath}`, { json: isJson });
|
|
9437
9425
|
process.exitCode = 1;
|
|
9438
9426
|
return;
|
|
@@ -9473,7 +9461,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9473
9461
|
}
|
|
9474
9462
|
const storyTitle = extractStoryTitle(storyFilePath);
|
|
9475
9463
|
const expectedProofPath = join29(root, "verification", `${storyId}-proof.md`);
|
|
9476
|
-
const proofPath =
|
|
9464
|
+
const proofPath = existsSync27(expectedProofPath) ? expectedProofPath : createProofDocument(storyId, storyTitle, acs, root);
|
|
9477
9465
|
const proofQuality = validateProofQuality(proofPath);
|
|
9478
9466
|
if (!proofQuality.passed) {
|
|
9479
9467
|
if (isJson) {
|
|
@@ -9643,11 +9631,11 @@ function resolveEndpoints(state) {
|
|
|
9643
9631
|
}
|
|
9644
9632
|
|
|
9645
9633
|
// src/lib/onboard-checks.ts
|
|
9646
|
-
import { existsSync as
|
|
9634
|
+
import { existsSync as existsSync30 } from "fs";
|
|
9647
9635
|
import { join as join32 } from "path";
|
|
9648
9636
|
|
|
9649
9637
|
// src/lib/coverage/parser.ts
|
|
9650
|
-
import { existsSync as
|
|
9638
|
+
import { existsSync as existsSync28, readFileSync as readFileSync26 } from "fs";
|
|
9651
9639
|
import { join as join30 } from "path";
|
|
9652
9640
|
function parseTestCounts(output) {
|
|
9653
9641
|
const vitestMatch = /Tests\s+(\d+)\s+passed(?:\s*\|\s*(\d+)\s+failed)?/i.exec(output);
|
|
@@ -9713,7 +9701,7 @@ function parseVitestCoverage(dir) {
|
|
|
9713
9701
|
}
|
|
9714
9702
|
function parsePythonCoverage(dir) {
|
|
9715
9703
|
const reportPath = join30(dir, "coverage.json");
|
|
9716
|
-
if (!
|
|
9704
|
+
if (!existsSync28(reportPath)) {
|
|
9717
9705
|
warn("Coverage report not found at coverage.json");
|
|
9718
9706
|
return 0;
|
|
9719
9707
|
}
|
|
@@ -9727,7 +9715,7 @@ function parsePythonCoverage(dir) {
|
|
|
9727
9715
|
}
|
|
9728
9716
|
function parseTarpaulinCoverage(dir) {
|
|
9729
9717
|
const reportPath = join30(dir, "coverage", "tarpaulin-report.json");
|
|
9730
|
-
if (!
|
|
9718
|
+
if (!existsSync28(reportPath)) {
|
|
9731
9719
|
warn("Tarpaulin report not found at coverage/tarpaulin-report.json");
|
|
9732
9720
|
return 0;
|
|
9733
9721
|
}
|
|
@@ -9745,14 +9733,14 @@ function findCoverageSummary(dir) {
|
|
|
9745
9733
|
join30(dir, "src", "coverage", "coverage-summary.json")
|
|
9746
9734
|
];
|
|
9747
9735
|
for (const p of candidates) {
|
|
9748
|
-
if (
|
|
9736
|
+
if (existsSync28(p)) return p;
|
|
9749
9737
|
}
|
|
9750
9738
|
return null;
|
|
9751
9739
|
}
|
|
9752
9740
|
|
|
9753
9741
|
// src/lib/coverage/runner.ts
|
|
9754
9742
|
import { execSync as execSync7 } from "child_process";
|
|
9755
|
-
import { existsSync as
|
|
9743
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27 } from "fs";
|
|
9756
9744
|
import { join as join31 } from "path";
|
|
9757
9745
|
function detectCoverageTool(dir) {
|
|
9758
9746
|
const baseDir = dir ?? process.cwd();
|
|
@@ -9809,14 +9797,14 @@ function getStateToolHint(dir) {
|
|
|
9809
9797
|
}
|
|
9810
9798
|
}
|
|
9811
9799
|
function detectNodeCoverageTool(dir, stateHint) {
|
|
9812
|
-
const hasVitestConfig =
|
|
9800
|
+
const hasVitestConfig = existsSync29(join31(dir, "vitest.config.ts")) || existsSync29(join31(dir, "vitest.config.js"));
|
|
9813
9801
|
const pkgPath = join31(dir, "package.json");
|
|
9814
9802
|
let hasVitestCoverageV8 = false;
|
|
9815
9803
|
let hasVitestCoverageIstanbul = false;
|
|
9816
9804
|
let hasC8 = false;
|
|
9817
9805
|
let hasJest = false;
|
|
9818
9806
|
let pkgScripts = {};
|
|
9819
|
-
if (
|
|
9807
|
+
if (existsSync29(pkgPath)) {
|
|
9820
9808
|
try {
|
|
9821
9809
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
9822
9810
|
const allDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
@@ -9872,7 +9860,7 @@ function getNodeTestCommand(scripts, runner) {
|
|
|
9872
9860
|
}
|
|
9873
9861
|
function detectPythonCoverageTool(dir) {
|
|
9874
9862
|
const reqPath = join31(dir, "requirements.txt");
|
|
9875
|
-
if (
|
|
9863
|
+
if (existsSync29(reqPath)) {
|
|
9876
9864
|
try {
|
|
9877
9865
|
const content = readFileSync27(reqPath, "utf-8");
|
|
9878
9866
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -9886,7 +9874,7 @@ function detectPythonCoverageTool(dir) {
|
|
|
9886
9874
|
}
|
|
9887
9875
|
}
|
|
9888
9876
|
const pyprojectPath = join31(dir, "pyproject.toml");
|
|
9889
|
-
if (
|
|
9877
|
+
if (existsSync29(pyprojectPath)) {
|
|
9890
9878
|
try {
|
|
9891
9879
|
const content = readFileSync27(pyprojectPath, "utf-8");
|
|
9892
9880
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -10098,7 +10086,7 @@ function printCoverageOutput(result, evaluation) {
|
|
|
10098
10086
|
// src/lib/onboard-checks.ts
|
|
10099
10087
|
function checkHarnessInitialized(dir) {
|
|
10100
10088
|
const statePath2 = getStatePath(dir ?? process.cwd());
|
|
10101
|
-
return { ok:
|
|
10089
|
+
return { ok: existsSync30(statePath2) };
|
|
10102
10090
|
}
|
|
10103
10091
|
function checkBmadInstalled(dir) {
|
|
10104
10092
|
return { ok: isBmadInstalled(dir) };
|
|
@@ -10717,7 +10705,7 @@ function registerStatusCommand(program) {
|
|
|
10717
10705
|
}
|
|
10718
10706
|
|
|
10719
10707
|
// src/modules/audit/dimensions.ts
|
|
10720
|
-
import { existsSync as
|
|
10708
|
+
import { existsSync as existsSync31, readdirSync as readdirSync8 } from "fs";
|
|
10721
10709
|
import { join as join33 } from "path";
|
|
10722
10710
|
function gap(dimension, description, suggestedFix) {
|
|
10723
10711
|
return { dimension, description, suggestedFix };
|
|
@@ -10831,10 +10819,10 @@ function checkVerification(projectDir) {
|
|
|
10831
10819
|
try {
|
|
10832
10820
|
const gaps = [];
|
|
10833
10821
|
const sprintPath = join33(projectDir, "_bmad-output", "implementation-artifacts", "sprint-status.yaml");
|
|
10834
|
-
if (!
|
|
10822
|
+
if (!existsSync31(sprintPath)) return dimOk("verification", "warn", "no sprint data", [gap("verification", "No sprint-status.yaml found", "Run sprint planning to create sprint status")]);
|
|
10835
10823
|
const vDir = join33(projectDir, "verification");
|
|
10836
10824
|
let proofCount = 0, totalChecked = 0;
|
|
10837
|
-
if (
|
|
10825
|
+
if (existsSync31(vDir)) {
|
|
10838
10826
|
for (const file of readdirSafe(vDir)) {
|
|
10839
10827
|
if (!file.endsWith("-proof.md")) continue;
|
|
10840
10828
|
totalChecked++;
|
|
@@ -10915,13 +10903,13 @@ function formatAuditJson(result) {
|
|
|
10915
10903
|
}
|
|
10916
10904
|
|
|
10917
10905
|
// src/modules/audit/fix-generator.ts
|
|
10918
|
-
import { existsSync as
|
|
10919
|
-
import { join as join34, dirname as
|
|
10906
|
+
import { existsSync as existsSync32, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12 } from "fs";
|
|
10907
|
+
import { join as join34, dirname as dirname3 } from "path";
|
|
10920
10908
|
function buildStoryKey(gap2, index) {
|
|
10921
10909
|
const safeDimension = gap2.dimension.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
10922
10910
|
return `audit-fix-${safeDimension}-${index}`;
|
|
10923
10911
|
}
|
|
10924
|
-
function buildStoryMarkdown(gap2,
|
|
10912
|
+
function buildStoryMarkdown(gap2, _key) {
|
|
10925
10913
|
return [
|
|
10926
10914
|
`# Fix: ${gap2.dimension} \u2014 ${gap2.description}`,
|
|
10927
10915
|
"",
|
|
@@ -10958,7 +10946,7 @@ function generateFixStories(auditResult) {
|
|
|
10958
10946
|
const gap2 = dimension.gaps[i];
|
|
10959
10947
|
const key = buildStoryKey(gap2, i + 1);
|
|
10960
10948
|
const filePath = join34(artifactsDir, `${key}.md`);
|
|
10961
|
-
if (
|
|
10949
|
+
if (existsSync32(filePath)) {
|
|
10962
10950
|
stories.push({
|
|
10963
10951
|
key,
|
|
10964
10952
|
filePath,
|
|
@@ -10970,7 +10958,7 @@ function generateFixStories(auditResult) {
|
|
|
10970
10958
|
continue;
|
|
10971
10959
|
}
|
|
10972
10960
|
const markdown = buildStoryMarkdown(gap2, key);
|
|
10973
|
-
mkdirSync12(
|
|
10961
|
+
mkdirSync12(dirname3(filePath), { recursive: true });
|
|
10974
10962
|
writeFileSync15(filePath, markdown, "utf-8");
|
|
10975
10963
|
stories.push({ key, filePath, gap: gap2, skipped: false });
|
|
10976
10964
|
created++;
|
|
@@ -11147,7 +11135,7 @@ function registerOnboardCommand(program) {
|
|
|
11147
11135
|
}
|
|
11148
11136
|
|
|
11149
11137
|
// src/commands/teardown.ts
|
|
11150
|
-
import { existsSync as
|
|
11138
|
+
import { existsSync as existsSync33, unlinkSync as unlinkSync3, readFileSync as readFileSync29, writeFileSync as writeFileSync16, rmSync as rmSync4 } from "fs";
|
|
11151
11139
|
import { join as join35 } from "path";
|
|
11152
11140
|
function buildDefaultResult() {
|
|
11153
11141
|
return {
|
|
@@ -11194,7 +11182,7 @@ function registerTeardownCommand(program) {
|
|
|
11194
11182
|
} else if (otlpMode === "remote-routed") {
|
|
11195
11183
|
if (!options.keepDocker) {
|
|
11196
11184
|
try {
|
|
11197
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
11185
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-W7JLB33I.js");
|
|
11198
11186
|
stopCollectorOnly2();
|
|
11199
11187
|
result.docker.stopped = true;
|
|
11200
11188
|
if (!isJson) {
|
|
@@ -11226,7 +11214,7 @@ function registerTeardownCommand(program) {
|
|
|
11226
11214
|
info("Shared stack: kept running (other projects may use it)");
|
|
11227
11215
|
}
|
|
11228
11216
|
} else if (isLegacyStack) {
|
|
11229
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
11217
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-W7JLB33I.js");
|
|
11230
11218
|
let stackRunning = false;
|
|
11231
11219
|
try {
|
|
11232
11220
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -11252,7 +11240,7 @@ function registerTeardownCommand(program) {
|
|
|
11252
11240
|
}
|
|
11253
11241
|
}
|
|
11254
11242
|
const composeFilePath = join35(projectDir, composeFile);
|
|
11255
|
-
if (
|
|
11243
|
+
if (existsSync33(composeFilePath)) {
|
|
11256
11244
|
unlinkSync3(composeFilePath);
|
|
11257
11245
|
result.removed.push(composeFile);
|
|
11258
11246
|
if (!isJson) {
|
|
@@ -11260,7 +11248,7 @@ function registerTeardownCommand(program) {
|
|
|
11260
11248
|
}
|
|
11261
11249
|
}
|
|
11262
11250
|
const otelConfigPath = join35(projectDir, "otel-collector-config.yaml");
|
|
11263
|
-
if (
|
|
11251
|
+
if (existsSync33(otelConfigPath)) {
|
|
11264
11252
|
unlinkSync3(otelConfigPath);
|
|
11265
11253
|
result.removed.push("otel-collector-config.yaml");
|
|
11266
11254
|
if (!isJson) {
|
|
@@ -11280,7 +11268,7 @@ function registerTeardownCommand(program) {
|
|
|
11280
11268
|
const stacks = state.stacks ?? (state.stack ? [state.stack] : []);
|
|
11281
11269
|
if (state.otlp?.enabled && stacks.includes("nodejs")) {
|
|
11282
11270
|
const pkgPath = join35(projectDir, "package.json");
|
|
11283
|
-
if (
|
|
11271
|
+
if (existsSync33(pkgPath)) {
|
|
11284
11272
|
try {
|
|
11285
11273
|
const raw = readFileSync29(pkgPath, "utf-8");
|
|
11286
11274
|
const pkg = JSON.parse(raw);
|
|
@@ -11323,7 +11311,7 @@ function registerTeardownCommand(program) {
|
|
|
11323
11311
|
}
|
|
11324
11312
|
}
|
|
11325
11313
|
const harnessDir = join35(projectDir, ".harness");
|
|
11326
|
-
if (
|
|
11314
|
+
if (existsSync33(harnessDir)) {
|
|
11327
11315
|
rmSync4(harnessDir, { recursive: true, force: true });
|
|
11328
11316
|
result.removed.push(".harness/");
|
|
11329
11317
|
if (!isJson) {
|
|
@@ -11331,7 +11319,7 @@ function registerTeardownCommand(program) {
|
|
|
11331
11319
|
}
|
|
11332
11320
|
}
|
|
11333
11321
|
const statePath2 = getStatePath(projectDir);
|
|
11334
|
-
if (
|
|
11322
|
+
if (existsSync33(statePath2)) {
|
|
11335
11323
|
unlinkSync3(statePath2);
|
|
11336
11324
|
result.removed.push(".claude/codeharness.local.md");
|
|
11337
11325
|
if (!isJson) {
|
|
@@ -12012,7 +12000,7 @@ function registerQueryCommand(program) {
|
|
|
12012
12000
|
}
|
|
12013
12001
|
|
|
12014
12002
|
// src/commands/retro-import.ts
|
|
12015
|
-
import { existsSync as
|
|
12003
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31 } from "fs";
|
|
12016
12004
|
import { join as join37 } from "path";
|
|
12017
12005
|
|
|
12018
12006
|
// src/lib/retro-parser.ts
|
|
@@ -12130,7 +12118,7 @@ function isDuplicate(newItem, existingTitles, threshold = 0.8) {
|
|
|
12130
12118
|
}
|
|
12131
12119
|
|
|
12132
12120
|
// src/lib/issue-tracker.ts
|
|
12133
|
-
import { existsSync as
|
|
12121
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, writeFileSync as writeFileSync17, mkdirSync as mkdirSync13 } from "fs";
|
|
12134
12122
|
import { join as join36 } from "path";
|
|
12135
12123
|
import { parse as parse6, stringify as stringify3 } from "yaml";
|
|
12136
12124
|
var VALID_PRIORITIES = /* @__PURE__ */ new Set([
|
|
@@ -12145,7 +12133,7 @@ function issuesPath(dir) {
|
|
|
12145
12133
|
}
|
|
12146
12134
|
function readIssues(dir = process.cwd()) {
|
|
12147
12135
|
const filePath = issuesPath(dir);
|
|
12148
|
-
if (!
|
|
12136
|
+
if (!existsSync34(filePath)) {
|
|
12149
12137
|
return { issues: [] };
|
|
12150
12138
|
}
|
|
12151
12139
|
const raw = readFileSync30(filePath, "utf-8");
|
|
@@ -12158,7 +12146,7 @@ function readIssues(dir = process.cwd()) {
|
|
|
12158
12146
|
function writeIssues(data, dir = process.cwd()) {
|
|
12159
12147
|
const filePath = issuesPath(dir);
|
|
12160
12148
|
const dirPath = join36(dir, ".codeharness");
|
|
12161
|
-
if (!
|
|
12149
|
+
if (!existsSync34(dirPath)) {
|
|
12162
12150
|
mkdirSync13(dirPath, { recursive: true });
|
|
12163
12151
|
}
|
|
12164
12152
|
writeFileSync17(filePath, stringify3(data, { nullStr: "" }), "utf-8");
|
|
@@ -12319,7 +12307,7 @@ function registerRetroImportCommand(program) {
|
|
|
12319
12307
|
}
|
|
12320
12308
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
12321
12309
|
const retroPath = join37(root, STORY_DIR3, retroFile);
|
|
12322
|
-
if (!
|
|
12310
|
+
if (!existsSync35(retroPath)) {
|
|
12323
12311
|
fail(`Retro file not found: ${retroFile}`, { json: isJson });
|
|
12324
12312
|
process.exitCode = 1;
|
|
12325
12313
|
return;
|
|
@@ -12818,7 +12806,7 @@ function registerValidateStateCommand(program) {
|
|
|
12818
12806
|
}
|
|
12819
12807
|
|
|
12820
12808
|
// src/commands/validate-schema.ts
|
|
12821
|
-
import { readdirSync as readdirSync9, existsSync as
|
|
12809
|
+
import { readdirSync as readdirSync9, existsSync as existsSync36 } from "fs";
|
|
12822
12810
|
import { join as join38, resolve as resolve6 } from "path";
|
|
12823
12811
|
function renderSchemaResult(result, isJson) {
|
|
12824
12812
|
if (isJson) {
|
|
@@ -12840,7 +12828,7 @@ function renderSchemaResult(result, isJson) {
|
|
|
12840
12828
|
}
|
|
12841
12829
|
function runSchemaValidation(projectDir) {
|
|
12842
12830
|
const workflowsDir = join38(projectDir, ".codeharness", "workflows");
|
|
12843
|
-
if (!
|
|
12831
|
+
if (!existsSync36(workflowsDir)) {
|
|
12844
12832
|
return {
|
|
12845
12833
|
status: "fail",
|
|
12846
12834
|
files: [{
|
|
@@ -13147,7 +13135,7 @@ function registerAuditCommand(program) {
|
|
|
13147
13135
|
}
|
|
13148
13136
|
|
|
13149
13137
|
// src/commands/stats.ts
|
|
13150
|
-
import { existsSync as
|
|
13138
|
+
import { existsSync as existsSync37, readdirSync as readdirSync10, readFileSync as readFileSync32, writeFileSync as writeFileSync18 } from "fs";
|
|
13151
13139
|
import { join as join39 } from "path";
|
|
13152
13140
|
var RATES = {
|
|
13153
13141
|
input: 15,
|
|
@@ -13171,7 +13159,7 @@ function addToBucket(target, input, output, cacheRead, cacheWrite) {
|
|
|
13171
13159
|
function parseLogFile(filePath, report) {
|
|
13172
13160
|
const basename3 = filePath.split("/").pop() ?? "";
|
|
13173
13161
|
const dateMatch = basename3.match(/(\d{4}-\d{2}-\d{2})/);
|
|
13174
|
-
const
|
|
13162
|
+
const _date = dateMatch ? dateMatch[1] : "unknown";
|
|
13175
13163
|
let currentPhase = "orchestrator";
|
|
13176
13164
|
let currentStory = "unknown";
|
|
13177
13165
|
let currentTool = "";
|
|
@@ -13235,7 +13223,7 @@ function parseLogFile(filePath, report) {
|
|
|
13235
13223
|
function generateReport3(projectDir, logsDir) {
|
|
13236
13224
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13237
13225
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13238
|
-
const resolvedLogsDir = logsDir ?? (
|
|
13226
|
+
const resolvedLogsDir = logsDir ?? (existsSync37(ralphLogs) ? ralphLogs : sessionLogs);
|
|
13239
13227
|
const logFiles = readdirSync10(resolvedLogsDir).filter((f) => f.endsWith(".log")).sort().map((f) => join39(resolvedLogsDir, f));
|
|
13240
13228
|
const report = {
|
|
13241
13229
|
byPhase: /* @__PURE__ */ new Map(),
|
|
@@ -13341,9 +13329,9 @@ function registerStatsCommand(program) {
|
|
|
13341
13329
|
} else {
|
|
13342
13330
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13343
13331
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13344
|
-
logsDir =
|
|
13332
|
+
logsDir = existsSync37(ralphLogs) ? ralphLogs : sessionLogs;
|
|
13345
13333
|
}
|
|
13346
|
-
if (!
|
|
13334
|
+
if (!existsSync37(logsDir)) {
|
|
13347
13335
|
fail("No logs directory found \u2014 checked ralph/logs/ and session-logs/. Run codeharness run first or use --logs-dir <path>");
|
|
13348
13336
|
process.exitCode = 1;
|
|
13349
13337
|
return;
|
|
@@ -13745,7 +13733,6 @@ function parseLine(line) {
|
|
|
13745
13733
|
if (type === "item.started" && item) {
|
|
13746
13734
|
const itemType = item.type;
|
|
13747
13735
|
if (itemType === "command_execution") {
|
|
13748
|
-
const cmd = item.command;
|
|
13749
13736
|
return { type: "tool-start", name: "Bash", id: item.id ?? "" };
|
|
13750
13737
|
}
|
|
13751
13738
|
if (itemType === "file_edit") {
|
|
@@ -13759,7 +13746,6 @@ function parseLine(line) {
|
|
|
13759
13746
|
if (type === "item.completed" && item) {
|
|
13760
13747
|
const itemType = item.type;
|
|
13761
13748
|
if (itemType === "command_execution") {
|
|
13762
|
-
const cmd = item.command;
|
|
13763
13749
|
return { type: "tool-complete" };
|
|
13764
13750
|
}
|
|
13765
13751
|
if (itemType === "agent_message") {
|
|
@@ -13859,7 +13845,7 @@ var CodexDriver = class {
|
|
|
13859
13845
|
opts.plugins
|
|
13860
13846
|
);
|
|
13861
13847
|
}
|
|
13862
|
-
const args = opts.sourceAccess ? ["exec", "--json", "-
|
|
13848
|
+
const args = opts.sourceAccess ? ["exec", "--json", "--dangerously-bypass-approvals-and-sandbox", "--skip-git-repo-check"] : ["exec", "--json", "--full-auto", "--skip-git-repo-check"];
|
|
13863
13849
|
const model = opts.model && !opts.model.startsWith("claude-") ? opts.model : void 0;
|
|
13864
13850
|
if (model) {
|
|
13865
13851
|
args.push("--model", model);
|
|
@@ -14213,7 +14199,7 @@ function registerDriversCommand(program) {
|
|
|
14213
14199
|
}
|
|
14214
14200
|
|
|
14215
14201
|
// src/index.ts
|
|
14216
|
-
var VERSION = true ? "0.36.
|
|
14202
|
+
var VERSION = true ? "0.36.6" : "0.0.0-dev";
|
|
14217
14203
|
function createProgram() {
|
|
14218
14204
|
const program = new Command();
|
|
14219
14205
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|