codeharness 0.36.5 → 0.36.7
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.7" : "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-2IFLGCTS.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 = (() => {
|
|
@@ -3826,10 +3809,14 @@ var storyFlowActor = fromPromise2(async ({ input }) => {
|
|
|
3826
3809
|
errors.push(...loopResult.errors);
|
|
3827
3810
|
tasksCompleted += loopResult.tasksCompleted;
|
|
3828
3811
|
lastContract = loopResult.lastContract;
|
|
3829
|
-
if (loopResult.halted
|
|
3812
|
+
if (loopResult.halted) {
|
|
3830
3813
|
halted = true;
|
|
3831
3814
|
break;
|
|
3832
3815
|
}
|
|
3816
|
+
if (state.phase === "max-iterations" || state.phase === "circuit-breaker") {
|
|
3817
|
+
state = { ...state, phase: "executing" };
|
|
3818
|
+
break;
|
|
3819
|
+
}
|
|
3833
3820
|
continue;
|
|
3834
3821
|
}
|
|
3835
3822
|
if (typeof storyStep !== "string") continue;
|
|
@@ -3884,7 +3871,8 @@ var storyFlowActor = fromPromise2(async ({ input }) => {
|
|
|
3884
3871
|
});
|
|
3885
3872
|
var epicStepActor = fromPromise2(async ({ input }) => {
|
|
3886
3873
|
const { epicId, epicItems, config, storyFlowTasks } = input;
|
|
3887
|
-
|
|
3874
|
+
const { errors, storiesProcessed, currentStepIndex } = input;
|
|
3875
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
3888
3876
|
const projectDir = config.projectDir ?? process.cwd();
|
|
3889
3877
|
const step = config.workflow.epicFlow[currentStepIndex];
|
|
3890
3878
|
if (!step || halted || config.abortSignal?.aborted) {
|
|
@@ -4018,7 +4006,8 @@ var epicMachine = setup({
|
|
|
4018
4006
|
});
|
|
4019
4007
|
var runEpicActor = fromPromise2(async ({ input }) => {
|
|
4020
4008
|
const { config, storyFlowTasks, epicEntries, currentEpicIndex } = input;
|
|
4021
|
-
|
|
4009
|
+
const { errors, storiesProcessed } = input;
|
|
4010
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
4022
4011
|
if (currentEpicIndex >= epicEntries.length || halted || config.abortSignal?.aborted) {
|
|
4023
4012
|
if (config.abortSignal?.aborted) {
|
|
4024
4013
|
const projectDir = config.projectDir ?? process.cwd();
|
|
@@ -5062,12 +5051,12 @@ function LastThought({ text }) {
|
|
|
5062
5051
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: text })
|
|
5063
5052
|
] });
|
|
5064
5053
|
}
|
|
5065
|
-
function RetryNotice({ info:
|
|
5054
|
+
function RetryNotice({ info: info2 }) {
|
|
5066
5055
|
return /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
5067
5056
|
"\u23F3 API retry ",
|
|
5068
|
-
|
|
5057
|
+
info2.attempt,
|
|
5069
5058
|
" (waiting ",
|
|
5070
|
-
|
|
5059
|
+
info2.delay,
|
|
5071
5060
|
"ms)"
|
|
5072
5061
|
] });
|
|
5073
5062
|
}
|
|
@@ -5132,7 +5121,7 @@ function loopIteration(tasks, taskStates) {
|
|
|
5132
5121
|
});
|
|
5133
5122
|
return anyStarted ? 1 : 0;
|
|
5134
5123
|
}
|
|
5135
|
-
function WorkflowGraph({ flow, currentTask, taskStates, taskMeta }) {
|
|
5124
|
+
function WorkflowGraph({ flow, currentTask: _currentTask, taskStates, taskMeta }) {
|
|
5136
5125
|
if (flow.length === 0 || Object.keys(taskStates).length === 0) {
|
|
5137
5126
|
return null;
|
|
5138
5127
|
}
|
|
@@ -5540,12 +5529,12 @@ function Separator() {
|
|
|
5540
5529
|
function formatCost2(cost) {
|
|
5541
5530
|
return `$${cost.toFixed(2)}`;
|
|
5542
5531
|
}
|
|
5543
|
-
function Header({ info:
|
|
5544
|
-
if (!
|
|
5532
|
+
function Header({ info: info2, laneCount }) {
|
|
5533
|
+
if (!info2) return null;
|
|
5545
5534
|
const parts = ["codeharness run"];
|
|
5546
5535
|
if (laneCount != null && laneCount > 1) parts.push(`${laneCount} lanes`);
|
|
5547
|
-
if (
|
|
5548
|
-
const displayCost = laneCount != null && laneCount > 1 &&
|
|
5536
|
+
if (info2.elapsed) parts.push(`${info2.elapsed} elapsed`);
|
|
5537
|
+
const displayCost = laneCount != null && laneCount > 1 && info2.laneTotalCost != null ? info2.laneTotalCost : info2.totalCost;
|
|
5549
5538
|
if (displayCost != null) parts.push(`${formatCost2(displayCost)} spent`);
|
|
5550
5539
|
const left = parts.join(" | ");
|
|
5551
5540
|
const right = "[q to quit]";
|
|
@@ -5574,20 +5563,20 @@ function ProgressBar({ done, total, inProgress }) {
|
|
|
5574
5563
|
` ${label}`
|
|
5575
5564
|
] });
|
|
5576
5565
|
}
|
|
5577
|
-
function EpicInfo({ info:
|
|
5578
|
-
if (!
|
|
5579
|
-
const title =
|
|
5580
|
-
const epicPrefix2 = `${
|
|
5566
|
+
function EpicInfo({ info: info2, stories }) {
|
|
5567
|
+
if (!info2?.epicId) return null;
|
|
5568
|
+
const title = info2.epicTitle ?? `Epic ${info2.epicId}`;
|
|
5569
|
+
const epicPrefix2 = `${info2.epicId}-`;
|
|
5581
5570
|
const epicStories = stories?.filter((s) => s.key.startsWith(epicPrefix2)) ?? [];
|
|
5582
5571
|
const ipCount = epicStories.filter((s) => s.status === "in-progress").length;
|
|
5583
|
-
const doneCount =
|
|
5584
|
-
const totalCount =
|
|
5572
|
+
const doneCount = info2.epicStoriesDone ?? 0;
|
|
5573
|
+
const totalCount = info2.epicStoriesTotal ?? epicStories.length;
|
|
5585
5574
|
const progressParts = [];
|
|
5586
5575
|
if (doneCount > 0) progressParts.push(`${doneCount} verified`);
|
|
5587
5576
|
if (ipCount > 0) progressParts.push(`${ipCount} implemented`);
|
|
5588
5577
|
const progress = totalCount > 0 ? ` \u2014 ${progressParts.join(", ")} / ${totalCount} stories` : "";
|
|
5589
5578
|
return /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
5590
|
-
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${
|
|
5579
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${info2.epicId}: ${title}` }),
|
|
5591
5580
|
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: progress })
|
|
5592
5581
|
] });
|
|
5593
5582
|
}
|
|
@@ -6356,7 +6345,6 @@ function registerRunCommand(program) {
|
|
|
6356
6345
|
}
|
|
6357
6346
|
}
|
|
6358
6347
|
if (isEpicTask) {
|
|
6359
|
-
const epicStories = storyEntries.filter((s) => s.key.startsWith(`${epicId}-`));
|
|
6360
6348
|
renderer.updateStories([...storyEntries]);
|
|
6361
6349
|
}
|
|
6362
6350
|
}
|
|
@@ -6534,7 +6522,7 @@ function registerRunCommand(program) {
|
|
|
6534
6522
|
}
|
|
6535
6523
|
|
|
6536
6524
|
// src/commands/verify.ts
|
|
6537
|
-
import { existsSync as
|
|
6525
|
+
import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
|
|
6538
6526
|
import { join as join29 } from "path";
|
|
6539
6527
|
|
|
6540
6528
|
// src/modules/verify/index.ts
|
|
@@ -7353,7 +7341,7 @@ function closeBeadsIssue(_storyId, _dir) {
|
|
|
7353
7341
|
}
|
|
7354
7342
|
|
|
7355
7343
|
// src/modules/verify/parser.ts
|
|
7356
|
-
import { existsSync as
|
|
7344
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
7357
7345
|
|
|
7358
7346
|
// src/modules/verify/parser-keywords.ts
|
|
7359
7347
|
var UI_KEYWORDS = [
|
|
@@ -7397,7 +7385,7 @@ function classifyAC(description) {
|
|
|
7397
7385
|
return "general";
|
|
7398
7386
|
}
|
|
7399
7387
|
function parseStoryACs(storyFilePath) {
|
|
7400
|
-
if (!
|
|
7388
|
+
if (!existsSync22(storyFilePath)) {
|
|
7401
7389
|
throw new Error(
|
|
7402
7390
|
`Story file not found: ${storyFilePath}. Ensure the story file exists at the expected path.`
|
|
7403
7391
|
);
|
|
@@ -7613,7 +7601,7 @@ function normalizeSeverity(severity) {
|
|
|
7613
7601
|
}
|
|
7614
7602
|
|
|
7615
7603
|
// src/modules/observability/coverage.ts
|
|
7616
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync11, renameSync as renameSync3, existsSync as
|
|
7604
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync11, renameSync as renameSync3, existsSync as existsSync23 } from "fs";
|
|
7617
7605
|
import { join as join23 } from "path";
|
|
7618
7606
|
var STATE_FILE2 = "sprint-state.json";
|
|
7619
7607
|
var DEFAULT_STATIC_TARGET = 80;
|
|
@@ -7631,7 +7619,7 @@ function defaultCoverageState() {
|
|
|
7631
7619
|
}
|
|
7632
7620
|
function readStateFile(projectDir) {
|
|
7633
7621
|
const fp = join23(projectDir, STATE_FILE2);
|
|
7634
|
-
if (!
|
|
7622
|
+
if (!existsSync23(fp)) {
|
|
7635
7623
|
return ok2({});
|
|
7636
7624
|
}
|
|
7637
7625
|
try {
|
|
@@ -7702,7 +7690,7 @@ function parseGapArray(raw) {
|
|
|
7702
7690
|
}
|
|
7703
7691
|
|
|
7704
7692
|
// src/modules/observability/runtime-coverage.ts
|
|
7705
|
-
import { readFileSync as readFileSync21, writeFileSync as writeFileSync12, renameSync as renameSync4, existsSync as
|
|
7693
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync12, renameSync as renameSync4, existsSync as existsSync24 } from "fs";
|
|
7706
7694
|
import { join as join24 } from "path";
|
|
7707
7695
|
|
|
7708
7696
|
// src/modules/observability/coverage-gate.ts
|
|
@@ -7906,7 +7894,7 @@ function parseLogEvents(text) {
|
|
|
7906
7894
|
|
|
7907
7895
|
// src/modules/verify/browser.ts
|
|
7908
7896
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7909
|
-
import { existsSync as
|
|
7897
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
|
|
7910
7898
|
|
|
7911
7899
|
// src/modules/verify/validation-ac-fr.ts
|
|
7912
7900
|
var FR_ACS = [
|
|
@@ -8545,7 +8533,7 @@ function getACById(id) {
|
|
|
8545
8533
|
// src/modules/verify/validation-runner.ts
|
|
8546
8534
|
import { execSync as execSync5 } from "child_process";
|
|
8547
8535
|
import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync10 } from "fs";
|
|
8548
|
-
import { join as join26, dirname as
|
|
8536
|
+
import { join as join26, dirname as dirname2 } from "path";
|
|
8549
8537
|
var MAX_VALIDATION_ATTEMPTS = 10;
|
|
8550
8538
|
var AC_COMMAND_TIMEOUT_MS = 3e4;
|
|
8551
8539
|
var VAL_KEY_PREFIX = "val-";
|
|
@@ -8697,7 +8685,7 @@ function createFixStory(ac, error) {
|
|
|
8697
8685
|
"Fix the root cause so the validation command passes.",
|
|
8698
8686
|
""
|
|
8699
8687
|
].join("\n");
|
|
8700
|
-
mkdirSync10(
|
|
8688
|
+
mkdirSync10(dirname2(storyPath), { recursive: true });
|
|
8701
8689
|
writeFileSync13(storyPath, markdown, "utf-8");
|
|
8702
8690
|
return ok2(storyKey);
|
|
8703
8691
|
} catch (err) {
|
|
@@ -9024,7 +9012,7 @@ function runValidationCycle() {
|
|
|
9024
9012
|
|
|
9025
9013
|
// src/modules/verify/env.ts
|
|
9026
9014
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
9027
|
-
import { existsSync as
|
|
9015
|
+
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";
|
|
9028
9016
|
import { join as join28, basename as basename2 } from "path";
|
|
9029
9017
|
import { createHash } from "crypto";
|
|
9030
9018
|
|
|
@@ -9079,7 +9067,7 @@ function isValidStoryKey(storyKey) {
|
|
|
9079
9067
|
}
|
|
9080
9068
|
function computeDistHash(projectDir) {
|
|
9081
9069
|
const distDir = join28(projectDir, "dist");
|
|
9082
|
-
if (!
|
|
9070
|
+
if (!existsSync26(distDir)) return null;
|
|
9083
9071
|
const hash = createHash("sha256");
|
|
9084
9072
|
const files = collectFiles(distDir).sort();
|
|
9085
9073
|
for (const file of files) {
|
|
@@ -9127,7 +9115,7 @@ function detectProjectType(projectDir) {
|
|
|
9127
9115
|
const rootDetection = allStacks.find((s) => s.dir === ".");
|
|
9128
9116
|
const stack = rootDetection ? rootDetection.stack : null;
|
|
9129
9117
|
if (stack && STACK_TO_PROJECT_TYPE[stack]) return STACK_TO_PROJECT_TYPE[stack];
|
|
9130
|
-
if (
|
|
9118
|
+
if (existsSync26(join28(projectDir, ".claude-plugin", "plugin.json"))) return "plugin";
|
|
9131
9119
|
return "generic";
|
|
9132
9120
|
}
|
|
9133
9121
|
function buildVerifyImage(options = {}) {
|
|
@@ -9225,15 +9213,15 @@ function prepareVerifyWorkspace(storyKey, projectDir) {
|
|
|
9225
9213
|
throw new Error(`Invalid story key: ${storyKey}. Keys must contain only alphanumeric characters, hyphens, and underscores.`);
|
|
9226
9214
|
}
|
|
9227
9215
|
const storyFile = join28(root, STORY_DIR, `${storyKey}.md`);
|
|
9228
|
-
if (!
|
|
9216
|
+
if (!existsSync26(storyFile)) throw new Error(`Story file not found: ${storyFile}`);
|
|
9229
9217
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9230
|
-
if (
|
|
9218
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9231
9219
|
mkdirSync11(workspace, { recursive: true });
|
|
9232
9220
|
cpSync(storyFile, join28(workspace, "story.md"));
|
|
9233
9221
|
const readmePath = join28(root, "README.md");
|
|
9234
|
-
if (
|
|
9222
|
+
if (existsSync26(readmePath)) cpSync(readmePath, join28(workspace, "README.md"));
|
|
9235
9223
|
const docsDir = join28(root, "docs");
|
|
9236
|
-
if (
|
|
9224
|
+
if (existsSync26(docsDir) && statSync6(docsDir).isDirectory()) {
|
|
9237
9225
|
cpSync(docsDir, join28(workspace, "docs"), { recursive: true });
|
|
9238
9226
|
}
|
|
9239
9227
|
mkdirSync11(join28(workspace, "verification"), { recursive: true });
|
|
@@ -9278,7 +9266,7 @@ function cleanupVerifyEnv(storyKey) {
|
|
|
9278
9266
|
}
|
|
9279
9267
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9280
9268
|
const containerName = `codeharness-verify-${storyKey}`;
|
|
9281
|
-
if (
|
|
9269
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9282
9270
|
try {
|
|
9283
9271
|
execFileSync5("docker", ["stop", containerName], { stdio: "pipe", timeout: 15e3 });
|
|
9284
9272
|
} catch {
|
|
@@ -9296,7 +9284,7 @@ function buildPluginImage(projectDir) {
|
|
|
9296
9284
|
cpSync(pluginDir, join28(buildContext, ".claude-plugin"), { recursive: true });
|
|
9297
9285
|
for (const dir of ["commands", "hooks", "knowledge", "skills"]) {
|
|
9298
9286
|
const src = join28(projectDir, dir);
|
|
9299
|
-
if (
|
|
9287
|
+
if (existsSync26(src) && statSync6(src).isDirectory()) {
|
|
9300
9288
|
cpSync(src, join28(buildContext, dir), { recursive: true });
|
|
9301
9289
|
}
|
|
9302
9290
|
}
|
|
@@ -9397,7 +9385,7 @@ function verifyRetro(opts, isJson, root) {
|
|
|
9397
9385
|
}
|
|
9398
9386
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
9399
9387
|
const retroPath = join29(root, STORY_DIR2, retroFile);
|
|
9400
|
-
if (!
|
|
9388
|
+
if (!existsSync27(retroPath)) {
|
|
9401
9389
|
if (isJson) {
|
|
9402
9390
|
jsonOutput({ status: "fail", epic: epicNum, retroFile, message: `${retroFile} not found` });
|
|
9403
9391
|
} else {
|
|
@@ -9426,7 +9414,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9426
9414
|
return;
|
|
9427
9415
|
}
|
|
9428
9416
|
const readmePath = join29(root, "README.md");
|
|
9429
|
-
if (!
|
|
9417
|
+
if (!existsSync27(readmePath)) {
|
|
9430
9418
|
if (isJson) {
|
|
9431
9419
|
jsonOutput({ status: "fail", message: "No README.md found \u2014 verification requires user documentation" });
|
|
9432
9420
|
} else {
|
|
@@ -9436,7 +9424,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9436
9424
|
return;
|
|
9437
9425
|
}
|
|
9438
9426
|
const storyFilePath = join29(root, STORY_DIR2, `${storyId}.md`);
|
|
9439
|
-
if (!
|
|
9427
|
+
if (!existsSync27(storyFilePath)) {
|
|
9440
9428
|
fail(`Story file not found: ${storyFilePath}`, { json: isJson });
|
|
9441
9429
|
process.exitCode = 1;
|
|
9442
9430
|
return;
|
|
@@ -9477,7 +9465,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9477
9465
|
}
|
|
9478
9466
|
const storyTitle = extractStoryTitle(storyFilePath);
|
|
9479
9467
|
const expectedProofPath = join29(root, "verification", `${storyId}-proof.md`);
|
|
9480
|
-
const proofPath =
|
|
9468
|
+
const proofPath = existsSync27(expectedProofPath) ? expectedProofPath : createProofDocument(storyId, storyTitle, acs, root);
|
|
9481
9469
|
const proofQuality = validateProofQuality(proofPath);
|
|
9482
9470
|
if (!proofQuality.passed) {
|
|
9483
9471
|
if (isJson) {
|
|
@@ -9647,11 +9635,11 @@ function resolveEndpoints(state) {
|
|
|
9647
9635
|
}
|
|
9648
9636
|
|
|
9649
9637
|
// src/lib/onboard-checks.ts
|
|
9650
|
-
import { existsSync as
|
|
9638
|
+
import { existsSync as existsSync30 } from "fs";
|
|
9651
9639
|
import { join as join32 } from "path";
|
|
9652
9640
|
|
|
9653
9641
|
// src/lib/coverage/parser.ts
|
|
9654
|
-
import { existsSync as
|
|
9642
|
+
import { existsSync as existsSync28, readFileSync as readFileSync26 } from "fs";
|
|
9655
9643
|
import { join as join30 } from "path";
|
|
9656
9644
|
function parseTestCounts(output) {
|
|
9657
9645
|
const vitestMatch = /Tests\s+(\d+)\s+passed(?:\s*\|\s*(\d+)\s+failed)?/i.exec(output);
|
|
@@ -9717,7 +9705,7 @@ function parseVitestCoverage(dir) {
|
|
|
9717
9705
|
}
|
|
9718
9706
|
function parsePythonCoverage(dir) {
|
|
9719
9707
|
const reportPath = join30(dir, "coverage.json");
|
|
9720
|
-
if (!
|
|
9708
|
+
if (!existsSync28(reportPath)) {
|
|
9721
9709
|
warn("Coverage report not found at coverage.json");
|
|
9722
9710
|
return 0;
|
|
9723
9711
|
}
|
|
@@ -9731,7 +9719,7 @@ function parsePythonCoverage(dir) {
|
|
|
9731
9719
|
}
|
|
9732
9720
|
function parseTarpaulinCoverage(dir) {
|
|
9733
9721
|
const reportPath = join30(dir, "coverage", "tarpaulin-report.json");
|
|
9734
|
-
if (!
|
|
9722
|
+
if (!existsSync28(reportPath)) {
|
|
9735
9723
|
warn("Tarpaulin report not found at coverage/tarpaulin-report.json");
|
|
9736
9724
|
return 0;
|
|
9737
9725
|
}
|
|
@@ -9749,14 +9737,14 @@ function findCoverageSummary(dir) {
|
|
|
9749
9737
|
join30(dir, "src", "coverage", "coverage-summary.json")
|
|
9750
9738
|
];
|
|
9751
9739
|
for (const p of candidates) {
|
|
9752
|
-
if (
|
|
9740
|
+
if (existsSync28(p)) return p;
|
|
9753
9741
|
}
|
|
9754
9742
|
return null;
|
|
9755
9743
|
}
|
|
9756
9744
|
|
|
9757
9745
|
// src/lib/coverage/runner.ts
|
|
9758
9746
|
import { execSync as execSync7 } from "child_process";
|
|
9759
|
-
import { existsSync as
|
|
9747
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27 } from "fs";
|
|
9760
9748
|
import { join as join31 } from "path";
|
|
9761
9749
|
function detectCoverageTool(dir) {
|
|
9762
9750
|
const baseDir = dir ?? process.cwd();
|
|
@@ -9813,14 +9801,14 @@ function getStateToolHint(dir) {
|
|
|
9813
9801
|
}
|
|
9814
9802
|
}
|
|
9815
9803
|
function detectNodeCoverageTool(dir, stateHint) {
|
|
9816
|
-
const hasVitestConfig =
|
|
9804
|
+
const hasVitestConfig = existsSync29(join31(dir, "vitest.config.ts")) || existsSync29(join31(dir, "vitest.config.js"));
|
|
9817
9805
|
const pkgPath = join31(dir, "package.json");
|
|
9818
9806
|
let hasVitestCoverageV8 = false;
|
|
9819
9807
|
let hasVitestCoverageIstanbul = false;
|
|
9820
9808
|
let hasC8 = false;
|
|
9821
9809
|
let hasJest = false;
|
|
9822
9810
|
let pkgScripts = {};
|
|
9823
|
-
if (
|
|
9811
|
+
if (existsSync29(pkgPath)) {
|
|
9824
9812
|
try {
|
|
9825
9813
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
9826
9814
|
const allDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
@@ -9876,7 +9864,7 @@ function getNodeTestCommand(scripts, runner) {
|
|
|
9876
9864
|
}
|
|
9877
9865
|
function detectPythonCoverageTool(dir) {
|
|
9878
9866
|
const reqPath = join31(dir, "requirements.txt");
|
|
9879
|
-
if (
|
|
9867
|
+
if (existsSync29(reqPath)) {
|
|
9880
9868
|
try {
|
|
9881
9869
|
const content = readFileSync27(reqPath, "utf-8");
|
|
9882
9870
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -9890,7 +9878,7 @@ function detectPythonCoverageTool(dir) {
|
|
|
9890
9878
|
}
|
|
9891
9879
|
}
|
|
9892
9880
|
const pyprojectPath = join31(dir, "pyproject.toml");
|
|
9893
|
-
if (
|
|
9881
|
+
if (existsSync29(pyprojectPath)) {
|
|
9894
9882
|
try {
|
|
9895
9883
|
const content = readFileSync27(pyprojectPath, "utf-8");
|
|
9896
9884
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -10102,7 +10090,7 @@ function printCoverageOutput(result, evaluation) {
|
|
|
10102
10090
|
// src/lib/onboard-checks.ts
|
|
10103
10091
|
function checkHarnessInitialized(dir) {
|
|
10104
10092
|
const statePath2 = getStatePath(dir ?? process.cwd());
|
|
10105
|
-
return { ok:
|
|
10093
|
+
return { ok: existsSync30(statePath2) };
|
|
10106
10094
|
}
|
|
10107
10095
|
function checkBmadInstalled(dir) {
|
|
10108
10096
|
return { ok: isBmadInstalled(dir) };
|
|
@@ -10721,7 +10709,7 @@ function registerStatusCommand(program) {
|
|
|
10721
10709
|
}
|
|
10722
10710
|
|
|
10723
10711
|
// src/modules/audit/dimensions.ts
|
|
10724
|
-
import { existsSync as
|
|
10712
|
+
import { existsSync as existsSync31, readdirSync as readdirSync8 } from "fs";
|
|
10725
10713
|
import { join as join33 } from "path";
|
|
10726
10714
|
function gap(dimension, description, suggestedFix) {
|
|
10727
10715
|
return { dimension, description, suggestedFix };
|
|
@@ -10835,10 +10823,10 @@ function checkVerification(projectDir) {
|
|
|
10835
10823
|
try {
|
|
10836
10824
|
const gaps = [];
|
|
10837
10825
|
const sprintPath = join33(projectDir, "_bmad-output", "implementation-artifacts", "sprint-status.yaml");
|
|
10838
|
-
if (!
|
|
10826
|
+
if (!existsSync31(sprintPath)) return dimOk("verification", "warn", "no sprint data", [gap("verification", "No sprint-status.yaml found", "Run sprint planning to create sprint status")]);
|
|
10839
10827
|
const vDir = join33(projectDir, "verification");
|
|
10840
10828
|
let proofCount = 0, totalChecked = 0;
|
|
10841
|
-
if (
|
|
10829
|
+
if (existsSync31(vDir)) {
|
|
10842
10830
|
for (const file of readdirSafe(vDir)) {
|
|
10843
10831
|
if (!file.endsWith("-proof.md")) continue;
|
|
10844
10832
|
totalChecked++;
|
|
@@ -10919,13 +10907,13 @@ function formatAuditJson(result) {
|
|
|
10919
10907
|
}
|
|
10920
10908
|
|
|
10921
10909
|
// src/modules/audit/fix-generator.ts
|
|
10922
|
-
import { existsSync as
|
|
10923
|
-
import { join as join34, dirname as
|
|
10910
|
+
import { existsSync as existsSync32, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12 } from "fs";
|
|
10911
|
+
import { join as join34, dirname as dirname3 } from "path";
|
|
10924
10912
|
function buildStoryKey(gap2, index) {
|
|
10925
10913
|
const safeDimension = gap2.dimension.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
10926
10914
|
return `audit-fix-${safeDimension}-${index}`;
|
|
10927
10915
|
}
|
|
10928
|
-
function buildStoryMarkdown(gap2,
|
|
10916
|
+
function buildStoryMarkdown(gap2, _key) {
|
|
10929
10917
|
return [
|
|
10930
10918
|
`# Fix: ${gap2.dimension} \u2014 ${gap2.description}`,
|
|
10931
10919
|
"",
|
|
@@ -10962,7 +10950,7 @@ function generateFixStories(auditResult) {
|
|
|
10962
10950
|
const gap2 = dimension.gaps[i];
|
|
10963
10951
|
const key = buildStoryKey(gap2, i + 1);
|
|
10964
10952
|
const filePath = join34(artifactsDir, `${key}.md`);
|
|
10965
|
-
if (
|
|
10953
|
+
if (existsSync32(filePath)) {
|
|
10966
10954
|
stories.push({
|
|
10967
10955
|
key,
|
|
10968
10956
|
filePath,
|
|
@@ -10974,7 +10962,7 @@ function generateFixStories(auditResult) {
|
|
|
10974
10962
|
continue;
|
|
10975
10963
|
}
|
|
10976
10964
|
const markdown = buildStoryMarkdown(gap2, key);
|
|
10977
|
-
mkdirSync12(
|
|
10965
|
+
mkdirSync12(dirname3(filePath), { recursive: true });
|
|
10978
10966
|
writeFileSync15(filePath, markdown, "utf-8");
|
|
10979
10967
|
stories.push({ key, filePath, gap: gap2, skipped: false });
|
|
10980
10968
|
created++;
|
|
@@ -11151,7 +11139,7 @@ function registerOnboardCommand(program) {
|
|
|
11151
11139
|
}
|
|
11152
11140
|
|
|
11153
11141
|
// src/commands/teardown.ts
|
|
11154
|
-
import { existsSync as
|
|
11142
|
+
import { existsSync as existsSync33, unlinkSync as unlinkSync3, readFileSync as readFileSync29, writeFileSync as writeFileSync16, rmSync as rmSync4 } from "fs";
|
|
11155
11143
|
import { join as join35 } from "path";
|
|
11156
11144
|
function buildDefaultResult() {
|
|
11157
11145
|
return {
|
|
@@ -11198,7 +11186,7 @@ function registerTeardownCommand(program) {
|
|
|
11198
11186
|
} else if (otlpMode === "remote-routed") {
|
|
11199
11187
|
if (!options.keepDocker) {
|
|
11200
11188
|
try {
|
|
11201
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
11189
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-IINEL23U.js");
|
|
11202
11190
|
stopCollectorOnly2();
|
|
11203
11191
|
result.docker.stopped = true;
|
|
11204
11192
|
if (!isJson) {
|
|
@@ -11230,7 +11218,7 @@ function registerTeardownCommand(program) {
|
|
|
11230
11218
|
info("Shared stack: kept running (other projects may use it)");
|
|
11231
11219
|
}
|
|
11232
11220
|
} else if (isLegacyStack) {
|
|
11233
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
11221
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-IINEL23U.js");
|
|
11234
11222
|
let stackRunning = false;
|
|
11235
11223
|
try {
|
|
11236
11224
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -11256,7 +11244,7 @@ function registerTeardownCommand(program) {
|
|
|
11256
11244
|
}
|
|
11257
11245
|
}
|
|
11258
11246
|
const composeFilePath = join35(projectDir, composeFile);
|
|
11259
|
-
if (
|
|
11247
|
+
if (existsSync33(composeFilePath)) {
|
|
11260
11248
|
unlinkSync3(composeFilePath);
|
|
11261
11249
|
result.removed.push(composeFile);
|
|
11262
11250
|
if (!isJson) {
|
|
@@ -11264,7 +11252,7 @@ function registerTeardownCommand(program) {
|
|
|
11264
11252
|
}
|
|
11265
11253
|
}
|
|
11266
11254
|
const otelConfigPath = join35(projectDir, "otel-collector-config.yaml");
|
|
11267
|
-
if (
|
|
11255
|
+
if (existsSync33(otelConfigPath)) {
|
|
11268
11256
|
unlinkSync3(otelConfigPath);
|
|
11269
11257
|
result.removed.push("otel-collector-config.yaml");
|
|
11270
11258
|
if (!isJson) {
|
|
@@ -11284,7 +11272,7 @@ function registerTeardownCommand(program) {
|
|
|
11284
11272
|
const stacks = state.stacks ?? (state.stack ? [state.stack] : []);
|
|
11285
11273
|
if (state.otlp?.enabled && stacks.includes("nodejs")) {
|
|
11286
11274
|
const pkgPath = join35(projectDir, "package.json");
|
|
11287
|
-
if (
|
|
11275
|
+
if (existsSync33(pkgPath)) {
|
|
11288
11276
|
try {
|
|
11289
11277
|
const raw = readFileSync29(pkgPath, "utf-8");
|
|
11290
11278
|
const pkg = JSON.parse(raw);
|
|
@@ -11327,7 +11315,7 @@ function registerTeardownCommand(program) {
|
|
|
11327
11315
|
}
|
|
11328
11316
|
}
|
|
11329
11317
|
const harnessDir = join35(projectDir, ".harness");
|
|
11330
|
-
if (
|
|
11318
|
+
if (existsSync33(harnessDir)) {
|
|
11331
11319
|
rmSync4(harnessDir, { recursive: true, force: true });
|
|
11332
11320
|
result.removed.push(".harness/");
|
|
11333
11321
|
if (!isJson) {
|
|
@@ -11335,7 +11323,7 @@ function registerTeardownCommand(program) {
|
|
|
11335
11323
|
}
|
|
11336
11324
|
}
|
|
11337
11325
|
const statePath2 = getStatePath(projectDir);
|
|
11338
|
-
if (
|
|
11326
|
+
if (existsSync33(statePath2)) {
|
|
11339
11327
|
unlinkSync3(statePath2);
|
|
11340
11328
|
result.removed.push(".claude/codeharness.local.md");
|
|
11341
11329
|
if (!isJson) {
|
|
@@ -12016,7 +12004,7 @@ function registerQueryCommand(program) {
|
|
|
12016
12004
|
}
|
|
12017
12005
|
|
|
12018
12006
|
// src/commands/retro-import.ts
|
|
12019
|
-
import { existsSync as
|
|
12007
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31 } from "fs";
|
|
12020
12008
|
import { join as join37 } from "path";
|
|
12021
12009
|
|
|
12022
12010
|
// src/lib/retro-parser.ts
|
|
@@ -12134,7 +12122,7 @@ function isDuplicate(newItem, existingTitles, threshold = 0.8) {
|
|
|
12134
12122
|
}
|
|
12135
12123
|
|
|
12136
12124
|
// src/lib/issue-tracker.ts
|
|
12137
|
-
import { existsSync as
|
|
12125
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, writeFileSync as writeFileSync17, mkdirSync as mkdirSync13 } from "fs";
|
|
12138
12126
|
import { join as join36 } from "path";
|
|
12139
12127
|
import { parse as parse6, stringify as stringify3 } from "yaml";
|
|
12140
12128
|
var VALID_PRIORITIES = /* @__PURE__ */ new Set([
|
|
@@ -12149,7 +12137,7 @@ function issuesPath(dir) {
|
|
|
12149
12137
|
}
|
|
12150
12138
|
function readIssues(dir = process.cwd()) {
|
|
12151
12139
|
const filePath = issuesPath(dir);
|
|
12152
|
-
if (!
|
|
12140
|
+
if (!existsSync34(filePath)) {
|
|
12153
12141
|
return { issues: [] };
|
|
12154
12142
|
}
|
|
12155
12143
|
const raw = readFileSync30(filePath, "utf-8");
|
|
@@ -12162,7 +12150,7 @@ function readIssues(dir = process.cwd()) {
|
|
|
12162
12150
|
function writeIssues(data, dir = process.cwd()) {
|
|
12163
12151
|
const filePath = issuesPath(dir);
|
|
12164
12152
|
const dirPath = join36(dir, ".codeharness");
|
|
12165
|
-
if (!
|
|
12153
|
+
if (!existsSync34(dirPath)) {
|
|
12166
12154
|
mkdirSync13(dirPath, { recursive: true });
|
|
12167
12155
|
}
|
|
12168
12156
|
writeFileSync17(filePath, stringify3(data, { nullStr: "" }), "utf-8");
|
|
@@ -12323,7 +12311,7 @@ function registerRetroImportCommand(program) {
|
|
|
12323
12311
|
}
|
|
12324
12312
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
12325
12313
|
const retroPath = join37(root, STORY_DIR3, retroFile);
|
|
12326
|
-
if (!
|
|
12314
|
+
if (!existsSync35(retroPath)) {
|
|
12327
12315
|
fail(`Retro file not found: ${retroFile}`, { json: isJson });
|
|
12328
12316
|
process.exitCode = 1;
|
|
12329
12317
|
return;
|
|
@@ -12822,7 +12810,7 @@ function registerValidateStateCommand(program) {
|
|
|
12822
12810
|
}
|
|
12823
12811
|
|
|
12824
12812
|
// src/commands/validate-schema.ts
|
|
12825
|
-
import { readdirSync as readdirSync9, existsSync as
|
|
12813
|
+
import { readdirSync as readdirSync9, existsSync as existsSync36 } from "fs";
|
|
12826
12814
|
import { join as join38, resolve as resolve6 } from "path";
|
|
12827
12815
|
function renderSchemaResult(result, isJson) {
|
|
12828
12816
|
if (isJson) {
|
|
@@ -12844,7 +12832,7 @@ function renderSchemaResult(result, isJson) {
|
|
|
12844
12832
|
}
|
|
12845
12833
|
function runSchemaValidation(projectDir) {
|
|
12846
12834
|
const workflowsDir = join38(projectDir, ".codeharness", "workflows");
|
|
12847
|
-
if (!
|
|
12835
|
+
if (!existsSync36(workflowsDir)) {
|
|
12848
12836
|
return {
|
|
12849
12837
|
status: "fail",
|
|
12850
12838
|
files: [{
|
|
@@ -13151,7 +13139,7 @@ function registerAuditCommand(program) {
|
|
|
13151
13139
|
}
|
|
13152
13140
|
|
|
13153
13141
|
// src/commands/stats.ts
|
|
13154
|
-
import { existsSync as
|
|
13142
|
+
import { existsSync as existsSync37, readdirSync as readdirSync10, readFileSync as readFileSync32, writeFileSync as writeFileSync18 } from "fs";
|
|
13155
13143
|
import { join as join39 } from "path";
|
|
13156
13144
|
var RATES = {
|
|
13157
13145
|
input: 15,
|
|
@@ -13175,7 +13163,7 @@ function addToBucket(target, input, output, cacheRead, cacheWrite) {
|
|
|
13175
13163
|
function parseLogFile(filePath, report) {
|
|
13176
13164
|
const basename3 = filePath.split("/").pop() ?? "";
|
|
13177
13165
|
const dateMatch = basename3.match(/(\d{4}-\d{2}-\d{2})/);
|
|
13178
|
-
const
|
|
13166
|
+
const _date = dateMatch ? dateMatch[1] : "unknown";
|
|
13179
13167
|
let currentPhase = "orchestrator";
|
|
13180
13168
|
let currentStory = "unknown";
|
|
13181
13169
|
let currentTool = "";
|
|
@@ -13239,7 +13227,7 @@ function parseLogFile(filePath, report) {
|
|
|
13239
13227
|
function generateReport3(projectDir, logsDir) {
|
|
13240
13228
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13241
13229
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13242
|
-
const resolvedLogsDir = logsDir ?? (
|
|
13230
|
+
const resolvedLogsDir = logsDir ?? (existsSync37(ralphLogs) ? ralphLogs : sessionLogs);
|
|
13243
13231
|
const logFiles = readdirSync10(resolvedLogsDir).filter((f) => f.endsWith(".log")).sort().map((f) => join39(resolvedLogsDir, f));
|
|
13244
13232
|
const report = {
|
|
13245
13233
|
byPhase: /* @__PURE__ */ new Map(),
|
|
@@ -13345,9 +13333,9 @@ function registerStatsCommand(program) {
|
|
|
13345
13333
|
} else {
|
|
13346
13334
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13347
13335
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13348
|
-
logsDir =
|
|
13336
|
+
logsDir = existsSync37(ralphLogs) ? ralphLogs : sessionLogs;
|
|
13349
13337
|
}
|
|
13350
|
-
if (!
|
|
13338
|
+
if (!existsSync37(logsDir)) {
|
|
13351
13339
|
fail("No logs directory found \u2014 checked ralph/logs/ and session-logs/. Run codeharness run first or use --logs-dir <path>");
|
|
13352
13340
|
process.exitCode = 1;
|
|
13353
13341
|
return;
|
|
@@ -13749,7 +13737,6 @@ function parseLine(line) {
|
|
|
13749
13737
|
if (type === "item.started" && item) {
|
|
13750
13738
|
const itemType = item.type;
|
|
13751
13739
|
if (itemType === "command_execution") {
|
|
13752
|
-
const cmd = item.command;
|
|
13753
13740
|
return { type: "tool-start", name: "Bash", id: item.id ?? "" };
|
|
13754
13741
|
}
|
|
13755
13742
|
if (itemType === "file_edit") {
|
|
@@ -13763,7 +13750,6 @@ function parseLine(line) {
|
|
|
13763
13750
|
if (type === "item.completed" && item) {
|
|
13764
13751
|
const itemType = item.type;
|
|
13765
13752
|
if (itemType === "command_execution") {
|
|
13766
|
-
const cmd = item.command;
|
|
13767
13753
|
return { type: "tool-complete" };
|
|
13768
13754
|
}
|
|
13769
13755
|
if (itemType === "agent_message") {
|
|
@@ -14217,7 +14203,7 @@ function registerDriversCommand(program) {
|
|
|
14217
14203
|
}
|
|
14218
14204
|
|
|
14219
14205
|
// src/index.ts
|
|
14220
|
-
var VERSION = true ? "0.36.
|
|
14206
|
+
var VERSION = true ? "0.36.7" : "0.0.0-dev";
|
|
14221
14207
|
function createProgram() {
|
|
14222
14208
|
const program = new Command();
|
|
14223
14209
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|