codeharness 0.36.5 → 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 = (() => {
|
|
@@ -3884,7 +3867,8 @@ var storyFlowActor = fromPromise2(async ({ input }) => {
|
|
|
3884
3867
|
});
|
|
3885
3868
|
var epicStepActor = fromPromise2(async ({ input }) => {
|
|
3886
3869
|
const { epicId, epicItems, config, storyFlowTasks } = input;
|
|
3887
|
-
|
|
3870
|
+
const { errors, storiesProcessed, currentStepIndex } = input;
|
|
3871
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
3888
3872
|
const projectDir = config.projectDir ?? process.cwd();
|
|
3889
3873
|
const step = config.workflow.epicFlow[currentStepIndex];
|
|
3890
3874
|
if (!step || halted || config.abortSignal?.aborted) {
|
|
@@ -4018,7 +4002,8 @@ var epicMachine = setup({
|
|
|
4018
4002
|
});
|
|
4019
4003
|
var runEpicActor = fromPromise2(async ({ input }) => {
|
|
4020
4004
|
const { config, storyFlowTasks, epicEntries, currentEpicIndex } = input;
|
|
4021
|
-
|
|
4005
|
+
const { errors, storiesProcessed } = input;
|
|
4006
|
+
let { workflowState: state, tasksCompleted, lastContract, accumulatedCostUsd, halted } = input;
|
|
4022
4007
|
if (currentEpicIndex >= epicEntries.length || halted || config.abortSignal?.aborted) {
|
|
4023
4008
|
if (config.abortSignal?.aborted) {
|
|
4024
4009
|
const projectDir = config.projectDir ?? process.cwd();
|
|
@@ -5062,12 +5047,12 @@ function LastThought({ text }) {
|
|
|
5062
5047
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: text })
|
|
5063
5048
|
] });
|
|
5064
5049
|
}
|
|
5065
|
-
function RetryNotice({ info:
|
|
5050
|
+
function RetryNotice({ info: info2 }) {
|
|
5066
5051
|
return /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
5067
5052
|
"\u23F3 API retry ",
|
|
5068
|
-
|
|
5053
|
+
info2.attempt,
|
|
5069
5054
|
" (waiting ",
|
|
5070
|
-
|
|
5055
|
+
info2.delay,
|
|
5071
5056
|
"ms)"
|
|
5072
5057
|
] });
|
|
5073
5058
|
}
|
|
@@ -5132,7 +5117,7 @@ function loopIteration(tasks, taskStates) {
|
|
|
5132
5117
|
});
|
|
5133
5118
|
return anyStarted ? 1 : 0;
|
|
5134
5119
|
}
|
|
5135
|
-
function WorkflowGraph({ flow, currentTask, taskStates, taskMeta }) {
|
|
5120
|
+
function WorkflowGraph({ flow, currentTask: _currentTask, taskStates, taskMeta }) {
|
|
5136
5121
|
if (flow.length === 0 || Object.keys(taskStates).length === 0) {
|
|
5137
5122
|
return null;
|
|
5138
5123
|
}
|
|
@@ -5540,12 +5525,12 @@ function Separator() {
|
|
|
5540
5525
|
function formatCost2(cost) {
|
|
5541
5526
|
return `$${cost.toFixed(2)}`;
|
|
5542
5527
|
}
|
|
5543
|
-
function Header({ info:
|
|
5544
|
-
if (!
|
|
5528
|
+
function Header({ info: info2, laneCount }) {
|
|
5529
|
+
if (!info2) return null;
|
|
5545
5530
|
const parts = ["codeharness run"];
|
|
5546
5531
|
if (laneCount != null && laneCount > 1) parts.push(`${laneCount} lanes`);
|
|
5547
|
-
if (
|
|
5548
|
-
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;
|
|
5549
5534
|
if (displayCost != null) parts.push(`${formatCost2(displayCost)} spent`);
|
|
5550
5535
|
const left = parts.join(" | ");
|
|
5551
5536
|
const right = "[q to quit]";
|
|
@@ -5574,20 +5559,20 @@ function ProgressBar({ done, total, inProgress }) {
|
|
|
5574
5559
|
` ${label}`
|
|
5575
5560
|
] });
|
|
5576
5561
|
}
|
|
5577
|
-
function EpicInfo({ info:
|
|
5578
|
-
if (!
|
|
5579
|
-
const title =
|
|
5580
|
-
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}-`;
|
|
5581
5566
|
const epicStories = stories?.filter((s) => s.key.startsWith(epicPrefix2)) ?? [];
|
|
5582
5567
|
const ipCount = epicStories.filter((s) => s.status === "in-progress").length;
|
|
5583
|
-
const doneCount =
|
|
5584
|
-
const totalCount =
|
|
5568
|
+
const doneCount = info2.epicStoriesDone ?? 0;
|
|
5569
|
+
const totalCount = info2.epicStoriesTotal ?? epicStories.length;
|
|
5585
5570
|
const progressParts = [];
|
|
5586
5571
|
if (doneCount > 0) progressParts.push(`${doneCount} verified`);
|
|
5587
5572
|
if (ipCount > 0) progressParts.push(`${ipCount} implemented`);
|
|
5588
5573
|
const progress = totalCount > 0 ? ` \u2014 ${progressParts.join(", ")} / ${totalCount} stories` : "";
|
|
5589
5574
|
return /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
5590
|
-
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${
|
|
5575
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: `Epic ${info2.epicId}: ${title}` }),
|
|
5591
5576
|
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: progress })
|
|
5592
5577
|
] });
|
|
5593
5578
|
}
|
|
@@ -6356,7 +6341,6 @@ function registerRunCommand(program) {
|
|
|
6356
6341
|
}
|
|
6357
6342
|
}
|
|
6358
6343
|
if (isEpicTask) {
|
|
6359
|
-
const epicStories = storyEntries.filter((s) => s.key.startsWith(`${epicId}-`));
|
|
6360
6344
|
renderer.updateStories([...storyEntries]);
|
|
6361
6345
|
}
|
|
6362
6346
|
}
|
|
@@ -6534,7 +6518,7 @@ function registerRunCommand(program) {
|
|
|
6534
6518
|
}
|
|
6535
6519
|
|
|
6536
6520
|
// src/commands/verify.ts
|
|
6537
|
-
import { existsSync as
|
|
6521
|
+
import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
|
|
6538
6522
|
import { join as join29 } from "path";
|
|
6539
6523
|
|
|
6540
6524
|
// src/modules/verify/index.ts
|
|
@@ -7353,7 +7337,7 @@ function closeBeadsIssue(_storyId, _dir) {
|
|
|
7353
7337
|
}
|
|
7354
7338
|
|
|
7355
7339
|
// src/modules/verify/parser.ts
|
|
7356
|
-
import { existsSync as
|
|
7340
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
7357
7341
|
|
|
7358
7342
|
// src/modules/verify/parser-keywords.ts
|
|
7359
7343
|
var UI_KEYWORDS = [
|
|
@@ -7397,7 +7381,7 @@ function classifyAC(description) {
|
|
|
7397
7381
|
return "general";
|
|
7398
7382
|
}
|
|
7399
7383
|
function parseStoryACs(storyFilePath) {
|
|
7400
|
-
if (!
|
|
7384
|
+
if (!existsSync22(storyFilePath)) {
|
|
7401
7385
|
throw new Error(
|
|
7402
7386
|
`Story file not found: ${storyFilePath}. Ensure the story file exists at the expected path.`
|
|
7403
7387
|
);
|
|
@@ -7613,7 +7597,7 @@ function normalizeSeverity(severity) {
|
|
|
7613
7597
|
}
|
|
7614
7598
|
|
|
7615
7599
|
// src/modules/observability/coverage.ts
|
|
7616
|
-
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";
|
|
7617
7601
|
import { join as join23 } from "path";
|
|
7618
7602
|
var STATE_FILE2 = "sprint-state.json";
|
|
7619
7603
|
var DEFAULT_STATIC_TARGET = 80;
|
|
@@ -7631,7 +7615,7 @@ function defaultCoverageState() {
|
|
|
7631
7615
|
}
|
|
7632
7616
|
function readStateFile(projectDir) {
|
|
7633
7617
|
const fp = join23(projectDir, STATE_FILE2);
|
|
7634
|
-
if (!
|
|
7618
|
+
if (!existsSync23(fp)) {
|
|
7635
7619
|
return ok2({});
|
|
7636
7620
|
}
|
|
7637
7621
|
try {
|
|
@@ -7702,7 +7686,7 @@ function parseGapArray(raw) {
|
|
|
7702
7686
|
}
|
|
7703
7687
|
|
|
7704
7688
|
// src/modules/observability/runtime-coverage.ts
|
|
7705
|
-
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";
|
|
7706
7690
|
import { join as join24 } from "path";
|
|
7707
7691
|
|
|
7708
7692
|
// src/modules/observability/coverage-gate.ts
|
|
@@ -7906,7 +7890,7 @@ function parseLogEvents(text) {
|
|
|
7906
7890
|
|
|
7907
7891
|
// src/modules/verify/browser.ts
|
|
7908
7892
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7909
|
-
import { existsSync as
|
|
7893
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
|
|
7910
7894
|
|
|
7911
7895
|
// src/modules/verify/validation-ac-fr.ts
|
|
7912
7896
|
var FR_ACS = [
|
|
@@ -8545,7 +8529,7 @@ function getACById(id) {
|
|
|
8545
8529
|
// src/modules/verify/validation-runner.ts
|
|
8546
8530
|
import { execSync as execSync5 } from "child_process";
|
|
8547
8531
|
import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync10 } from "fs";
|
|
8548
|
-
import { join as join26, dirname as
|
|
8532
|
+
import { join as join26, dirname as dirname2 } from "path";
|
|
8549
8533
|
var MAX_VALIDATION_ATTEMPTS = 10;
|
|
8550
8534
|
var AC_COMMAND_TIMEOUT_MS = 3e4;
|
|
8551
8535
|
var VAL_KEY_PREFIX = "val-";
|
|
@@ -8697,7 +8681,7 @@ function createFixStory(ac, error) {
|
|
|
8697
8681
|
"Fix the root cause so the validation command passes.",
|
|
8698
8682
|
""
|
|
8699
8683
|
].join("\n");
|
|
8700
|
-
mkdirSync10(
|
|
8684
|
+
mkdirSync10(dirname2(storyPath), { recursive: true });
|
|
8701
8685
|
writeFileSync13(storyPath, markdown, "utf-8");
|
|
8702
8686
|
return ok2(storyKey);
|
|
8703
8687
|
} catch (err) {
|
|
@@ -9024,7 +9008,7 @@ function runValidationCycle() {
|
|
|
9024
9008
|
|
|
9025
9009
|
// src/modules/verify/env.ts
|
|
9026
9010
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
9027
|
-
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";
|
|
9028
9012
|
import { join as join28, basename as basename2 } from "path";
|
|
9029
9013
|
import { createHash } from "crypto";
|
|
9030
9014
|
|
|
@@ -9079,7 +9063,7 @@ function isValidStoryKey(storyKey) {
|
|
|
9079
9063
|
}
|
|
9080
9064
|
function computeDistHash(projectDir) {
|
|
9081
9065
|
const distDir = join28(projectDir, "dist");
|
|
9082
|
-
if (!
|
|
9066
|
+
if (!existsSync26(distDir)) return null;
|
|
9083
9067
|
const hash = createHash("sha256");
|
|
9084
9068
|
const files = collectFiles(distDir).sort();
|
|
9085
9069
|
for (const file of files) {
|
|
@@ -9127,7 +9111,7 @@ function detectProjectType(projectDir) {
|
|
|
9127
9111
|
const rootDetection = allStacks.find((s) => s.dir === ".");
|
|
9128
9112
|
const stack = rootDetection ? rootDetection.stack : null;
|
|
9129
9113
|
if (stack && STACK_TO_PROJECT_TYPE[stack]) return STACK_TO_PROJECT_TYPE[stack];
|
|
9130
|
-
if (
|
|
9114
|
+
if (existsSync26(join28(projectDir, ".claude-plugin", "plugin.json"))) return "plugin";
|
|
9131
9115
|
return "generic";
|
|
9132
9116
|
}
|
|
9133
9117
|
function buildVerifyImage(options = {}) {
|
|
@@ -9225,15 +9209,15 @@ function prepareVerifyWorkspace(storyKey, projectDir) {
|
|
|
9225
9209
|
throw new Error(`Invalid story key: ${storyKey}. Keys must contain only alphanumeric characters, hyphens, and underscores.`);
|
|
9226
9210
|
}
|
|
9227
9211
|
const storyFile = join28(root, STORY_DIR, `${storyKey}.md`);
|
|
9228
|
-
if (!
|
|
9212
|
+
if (!existsSync26(storyFile)) throw new Error(`Story file not found: ${storyFile}`);
|
|
9229
9213
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9230
|
-
if (
|
|
9214
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9231
9215
|
mkdirSync11(workspace, { recursive: true });
|
|
9232
9216
|
cpSync(storyFile, join28(workspace, "story.md"));
|
|
9233
9217
|
const readmePath = join28(root, "README.md");
|
|
9234
|
-
if (
|
|
9218
|
+
if (existsSync26(readmePath)) cpSync(readmePath, join28(workspace, "README.md"));
|
|
9235
9219
|
const docsDir = join28(root, "docs");
|
|
9236
|
-
if (
|
|
9220
|
+
if (existsSync26(docsDir) && statSync6(docsDir).isDirectory()) {
|
|
9237
9221
|
cpSync(docsDir, join28(workspace, "docs"), { recursive: true });
|
|
9238
9222
|
}
|
|
9239
9223
|
mkdirSync11(join28(workspace, "verification"), { recursive: true });
|
|
@@ -9278,7 +9262,7 @@ function cleanupVerifyEnv(storyKey) {
|
|
|
9278
9262
|
}
|
|
9279
9263
|
const workspace = `${TEMP_PREFIX}${storyKey}`;
|
|
9280
9264
|
const containerName = `codeharness-verify-${storyKey}`;
|
|
9281
|
-
if (
|
|
9265
|
+
if (existsSync26(workspace)) rmSync3(workspace, { recursive: true, force: true });
|
|
9282
9266
|
try {
|
|
9283
9267
|
execFileSync5("docker", ["stop", containerName], { stdio: "pipe", timeout: 15e3 });
|
|
9284
9268
|
} catch {
|
|
@@ -9296,7 +9280,7 @@ function buildPluginImage(projectDir) {
|
|
|
9296
9280
|
cpSync(pluginDir, join28(buildContext, ".claude-plugin"), { recursive: true });
|
|
9297
9281
|
for (const dir of ["commands", "hooks", "knowledge", "skills"]) {
|
|
9298
9282
|
const src = join28(projectDir, dir);
|
|
9299
|
-
if (
|
|
9283
|
+
if (existsSync26(src) && statSync6(src).isDirectory()) {
|
|
9300
9284
|
cpSync(src, join28(buildContext, dir), { recursive: true });
|
|
9301
9285
|
}
|
|
9302
9286
|
}
|
|
@@ -9397,7 +9381,7 @@ function verifyRetro(opts, isJson, root) {
|
|
|
9397
9381
|
}
|
|
9398
9382
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
9399
9383
|
const retroPath = join29(root, STORY_DIR2, retroFile);
|
|
9400
|
-
if (!
|
|
9384
|
+
if (!existsSync27(retroPath)) {
|
|
9401
9385
|
if (isJson) {
|
|
9402
9386
|
jsonOutput({ status: "fail", epic: epicNum, retroFile, message: `${retroFile} not found` });
|
|
9403
9387
|
} else {
|
|
@@ -9426,7 +9410,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9426
9410
|
return;
|
|
9427
9411
|
}
|
|
9428
9412
|
const readmePath = join29(root, "README.md");
|
|
9429
|
-
if (!
|
|
9413
|
+
if (!existsSync27(readmePath)) {
|
|
9430
9414
|
if (isJson) {
|
|
9431
9415
|
jsonOutput({ status: "fail", message: "No README.md found \u2014 verification requires user documentation" });
|
|
9432
9416
|
} else {
|
|
@@ -9436,7 +9420,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9436
9420
|
return;
|
|
9437
9421
|
}
|
|
9438
9422
|
const storyFilePath = join29(root, STORY_DIR2, `${storyId}.md`);
|
|
9439
|
-
if (!
|
|
9423
|
+
if (!existsSync27(storyFilePath)) {
|
|
9440
9424
|
fail(`Story file not found: ${storyFilePath}`, { json: isJson });
|
|
9441
9425
|
process.exitCode = 1;
|
|
9442
9426
|
return;
|
|
@@ -9477,7 +9461,7 @@ function verifyStory(storyId, isJson, root) {
|
|
|
9477
9461
|
}
|
|
9478
9462
|
const storyTitle = extractStoryTitle(storyFilePath);
|
|
9479
9463
|
const expectedProofPath = join29(root, "verification", `${storyId}-proof.md`);
|
|
9480
|
-
const proofPath =
|
|
9464
|
+
const proofPath = existsSync27(expectedProofPath) ? expectedProofPath : createProofDocument(storyId, storyTitle, acs, root);
|
|
9481
9465
|
const proofQuality = validateProofQuality(proofPath);
|
|
9482
9466
|
if (!proofQuality.passed) {
|
|
9483
9467
|
if (isJson) {
|
|
@@ -9647,11 +9631,11 @@ function resolveEndpoints(state) {
|
|
|
9647
9631
|
}
|
|
9648
9632
|
|
|
9649
9633
|
// src/lib/onboard-checks.ts
|
|
9650
|
-
import { existsSync as
|
|
9634
|
+
import { existsSync as existsSync30 } from "fs";
|
|
9651
9635
|
import { join as join32 } from "path";
|
|
9652
9636
|
|
|
9653
9637
|
// src/lib/coverage/parser.ts
|
|
9654
|
-
import { existsSync as
|
|
9638
|
+
import { existsSync as existsSync28, readFileSync as readFileSync26 } from "fs";
|
|
9655
9639
|
import { join as join30 } from "path";
|
|
9656
9640
|
function parseTestCounts(output) {
|
|
9657
9641
|
const vitestMatch = /Tests\s+(\d+)\s+passed(?:\s*\|\s*(\d+)\s+failed)?/i.exec(output);
|
|
@@ -9717,7 +9701,7 @@ function parseVitestCoverage(dir) {
|
|
|
9717
9701
|
}
|
|
9718
9702
|
function parsePythonCoverage(dir) {
|
|
9719
9703
|
const reportPath = join30(dir, "coverage.json");
|
|
9720
|
-
if (!
|
|
9704
|
+
if (!existsSync28(reportPath)) {
|
|
9721
9705
|
warn("Coverage report not found at coverage.json");
|
|
9722
9706
|
return 0;
|
|
9723
9707
|
}
|
|
@@ -9731,7 +9715,7 @@ function parsePythonCoverage(dir) {
|
|
|
9731
9715
|
}
|
|
9732
9716
|
function parseTarpaulinCoverage(dir) {
|
|
9733
9717
|
const reportPath = join30(dir, "coverage", "tarpaulin-report.json");
|
|
9734
|
-
if (!
|
|
9718
|
+
if (!existsSync28(reportPath)) {
|
|
9735
9719
|
warn("Tarpaulin report not found at coverage/tarpaulin-report.json");
|
|
9736
9720
|
return 0;
|
|
9737
9721
|
}
|
|
@@ -9749,14 +9733,14 @@ function findCoverageSummary(dir) {
|
|
|
9749
9733
|
join30(dir, "src", "coverage", "coverage-summary.json")
|
|
9750
9734
|
];
|
|
9751
9735
|
for (const p of candidates) {
|
|
9752
|
-
if (
|
|
9736
|
+
if (existsSync28(p)) return p;
|
|
9753
9737
|
}
|
|
9754
9738
|
return null;
|
|
9755
9739
|
}
|
|
9756
9740
|
|
|
9757
9741
|
// src/lib/coverage/runner.ts
|
|
9758
9742
|
import { execSync as execSync7 } from "child_process";
|
|
9759
|
-
import { existsSync as
|
|
9743
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27 } from "fs";
|
|
9760
9744
|
import { join as join31 } from "path";
|
|
9761
9745
|
function detectCoverageTool(dir) {
|
|
9762
9746
|
const baseDir = dir ?? process.cwd();
|
|
@@ -9813,14 +9797,14 @@ function getStateToolHint(dir) {
|
|
|
9813
9797
|
}
|
|
9814
9798
|
}
|
|
9815
9799
|
function detectNodeCoverageTool(dir, stateHint) {
|
|
9816
|
-
const hasVitestConfig =
|
|
9800
|
+
const hasVitestConfig = existsSync29(join31(dir, "vitest.config.ts")) || existsSync29(join31(dir, "vitest.config.js"));
|
|
9817
9801
|
const pkgPath = join31(dir, "package.json");
|
|
9818
9802
|
let hasVitestCoverageV8 = false;
|
|
9819
9803
|
let hasVitestCoverageIstanbul = false;
|
|
9820
9804
|
let hasC8 = false;
|
|
9821
9805
|
let hasJest = false;
|
|
9822
9806
|
let pkgScripts = {};
|
|
9823
|
-
if (
|
|
9807
|
+
if (existsSync29(pkgPath)) {
|
|
9824
9808
|
try {
|
|
9825
9809
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
9826
9810
|
const allDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
@@ -9876,7 +9860,7 @@ function getNodeTestCommand(scripts, runner) {
|
|
|
9876
9860
|
}
|
|
9877
9861
|
function detectPythonCoverageTool(dir) {
|
|
9878
9862
|
const reqPath = join31(dir, "requirements.txt");
|
|
9879
|
-
if (
|
|
9863
|
+
if (existsSync29(reqPath)) {
|
|
9880
9864
|
try {
|
|
9881
9865
|
const content = readFileSync27(reqPath, "utf-8");
|
|
9882
9866
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -9890,7 +9874,7 @@ function detectPythonCoverageTool(dir) {
|
|
|
9890
9874
|
}
|
|
9891
9875
|
}
|
|
9892
9876
|
const pyprojectPath = join31(dir, "pyproject.toml");
|
|
9893
|
-
if (
|
|
9877
|
+
if (existsSync29(pyprojectPath)) {
|
|
9894
9878
|
try {
|
|
9895
9879
|
const content = readFileSync27(pyprojectPath, "utf-8");
|
|
9896
9880
|
if (content.includes("pytest-cov") || content.includes("coverage")) {
|
|
@@ -10102,7 +10086,7 @@ function printCoverageOutput(result, evaluation) {
|
|
|
10102
10086
|
// src/lib/onboard-checks.ts
|
|
10103
10087
|
function checkHarnessInitialized(dir) {
|
|
10104
10088
|
const statePath2 = getStatePath(dir ?? process.cwd());
|
|
10105
|
-
return { ok:
|
|
10089
|
+
return { ok: existsSync30(statePath2) };
|
|
10106
10090
|
}
|
|
10107
10091
|
function checkBmadInstalled(dir) {
|
|
10108
10092
|
return { ok: isBmadInstalled(dir) };
|
|
@@ -10721,7 +10705,7 @@ function registerStatusCommand(program) {
|
|
|
10721
10705
|
}
|
|
10722
10706
|
|
|
10723
10707
|
// src/modules/audit/dimensions.ts
|
|
10724
|
-
import { existsSync as
|
|
10708
|
+
import { existsSync as existsSync31, readdirSync as readdirSync8 } from "fs";
|
|
10725
10709
|
import { join as join33 } from "path";
|
|
10726
10710
|
function gap(dimension, description, suggestedFix) {
|
|
10727
10711
|
return { dimension, description, suggestedFix };
|
|
@@ -10835,10 +10819,10 @@ function checkVerification(projectDir) {
|
|
|
10835
10819
|
try {
|
|
10836
10820
|
const gaps = [];
|
|
10837
10821
|
const sprintPath = join33(projectDir, "_bmad-output", "implementation-artifacts", "sprint-status.yaml");
|
|
10838
|
-
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")]);
|
|
10839
10823
|
const vDir = join33(projectDir, "verification");
|
|
10840
10824
|
let proofCount = 0, totalChecked = 0;
|
|
10841
|
-
if (
|
|
10825
|
+
if (existsSync31(vDir)) {
|
|
10842
10826
|
for (const file of readdirSafe(vDir)) {
|
|
10843
10827
|
if (!file.endsWith("-proof.md")) continue;
|
|
10844
10828
|
totalChecked++;
|
|
@@ -10919,13 +10903,13 @@ function formatAuditJson(result) {
|
|
|
10919
10903
|
}
|
|
10920
10904
|
|
|
10921
10905
|
// src/modules/audit/fix-generator.ts
|
|
10922
|
-
import { existsSync as
|
|
10923
|
-
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";
|
|
10924
10908
|
function buildStoryKey(gap2, index) {
|
|
10925
10909
|
const safeDimension = gap2.dimension.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
10926
10910
|
return `audit-fix-${safeDimension}-${index}`;
|
|
10927
10911
|
}
|
|
10928
|
-
function buildStoryMarkdown(gap2,
|
|
10912
|
+
function buildStoryMarkdown(gap2, _key) {
|
|
10929
10913
|
return [
|
|
10930
10914
|
`# Fix: ${gap2.dimension} \u2014 ${gap2.description}`,
|
|
10931
10915
|
"",
|
|
@@ -10962,7 +10946,7 @@ function generateFixStories(auditResult) {
|
|
|
10962
10946
|
const gap2 = dimension.gaps[i];
|
|
10963
10947
|
const key = buildStoryKey(gap2, i + 1);
|
|
10964
10948
|
const filePath = join34(artifactsDir, `${key}.md`);
|
|
10965
|
-
if (
|
|
10949
|
+
if (existsSync32(filePath)) {
|
|
10966
10950
|
stories.push({
|
|
10967
10951
|
key,
|
|
10968
10952
|
filePath,
|
|
@@ -10974,7 +10958,7 @@ function generateFixStories(auditResult) {
|
|
|
10974
10958
|
continue;
|
|
10975
10959
|
}
|
|
10976
10960
|
const markdown = buildStoryMarkdown(gap2, key);
|
|
10977
|
-
mkdirSync12(
|
|
10961
|
+
mkdirSync12(dirname3(filePath), { recursive: true });
|
|
10978
10962
|
writeFileSync15(filePath, markdown, "utf-8");
|
|
10979
10963
|
stories.push({ key, filePath, gap: gap2, skipped: false });
|
|
10980
10964
|
created++;
|
|
@@ -11151,7 +11135,7 @@ function registerOnboardCommand(program) {
|
|
|
11151
11135
|
}
|
|
11152
11136
|
|
|
11153
11137
|
// src/commands/teardown.ts
|
|
11154
|
-
import { existsSync as
|
|
11138
|
+
import { existsSync as existsSync33, unlinkSync as unlinkSync3, readFileSync as readFileSync29, writeFileSync as writeFileSync16, rmSync as rmSync4 } from "fs";
|
|
11155
11139
|
import { join as join35 } from "path";
|
|
11156
11140
|
function buildDefaultResult() {
|
|
11157
11141
|
return {
|
|
@@ -11198,7 +11182,7 @@ function registerTeardownCommand(program) {
|
|
|
11198
11182
|
} else if (otlpMode === "remote-routed") {
|
|
11199
11183
|
if (!options.keepDocker) {
|
|
11200
11184
|
try {
|
|
11201
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
11185
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-W7JLB33I.js");
|
|
11202
11186
|
stopCollectorOnly2();
|
|
11203
11187
|
result.docker.stopped = true;
|
|
11204
11188
|
if (!isJson) {
|
|
@@ -11230,7 +11214,7 @@ function registerTeardownCommand(program) {
|
|
|
11230
11214
|
info("Shared stack: kept running (other projects may use it)");
|
|
11231
11215
|
}
|
|
11232
11216
|
} else if (isLegacyStack) {
|
|
11233
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
11217
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-W7JLB33I.js");
|
|
11234
11218
|
let stackRunning = false;
|
|
11235
11219
|
try {
|
|
11236
11220
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -11256,7 +11240,7 @@ function registerTeardownCommand(program) {
|
|
|
11256
11240
|
}
|
|
11257
11241
|
}
|
|
11258
11242
|
const composeFilePath = join35(projectDir, composeFile);
|
|
11259
|
-
if (
|
|
11243
|
+
if (existsSync33(composeFilePath)) {
|
|
11260
11244
|
unlinkSync3(composeFilePath);
|
|
11261
11245
|
result.removed.push(composeFile);
|
|
11262
11246
|
if (!isJson) {
|
|
@@ -11264,7 +11248,7 @@ function registerTeardownCommand(program) {
|
|
|
11264
11248
|
}
|
|
11265
11249
|
}
|
|
11266
11250
|
const otelConfigPath = join35(projectDir, "otel-collector-config.yaml");
|
|
11267
|
-
if (
|
|
11251
|
+
if (existsSync33(otelConfigPath)) {
|
|
11268
11252
|
unlinkSync3(otelConfigPath);
|
|
11269
11253
|
result.removed.push("otel-collector-config.yaml");
|
|
11270
11254
|
if (!isJson) {
|
|
@@ -11284,7 +11268,7 @@ function registerTeardownCommand(program) {
|
|
|
11284
11268
|
const stacks = state.stacks ?? (state.stack ? [state.stack] : []);
|
|
11285
11269
|
if (state.otlp?.enabled && stacks.includes("nodejs")) {
|
|
11286
11270
|
const pkgPath = join35(projectDir, "package.json");
|
|
11287
|
-
if (
|
|
11271
|
+
if (existsSync33(pkgPath)) {
|
|
11288
11272
|
try {
|
|
11289
11273
|
const raw = readFileSync29(pkgPath, "utf-8");
|
|
11290
11274
|
const pkg = JSON.parse(raw);
|
|
@@ -11327,7 +11311,7 @@ function registerTeardownCommand(program) {
|
|
|
11327
11311
|
}
|
|
11328
11312
|
}
|
|
11329
11313
|
const harnessDir = join35(projectDir, ".harness");
|
|
11330
|
-
if (
|
|
11314
|
+
if (existsSync33(harnessDir)) {
|
|
11331
11315
|
rmSync4(harnessDir, { recursive: true, force: true });
|
|
11332
11316
|
result.removed.push(".harness/");
|
|
11333
11317
|
if (!isJson) {
|
|
@@ -11335,7 +11319,7 @@ function registerTeardownCommand(program) {
|
|
|
11335
11319
|
}
|
|
11336
11320
|
}
|
|
11337
11321
|
const statePath2 = getStatePath(projectDir);
|
|
11338
|
-
if (
|
|
11322
|
+
if (existsSync33(statePath2)) {
|
|
11339
11323
|
unlinkSync3(statePath2);
|
|
11340
11324
|
result.removed.push(".claude/codeharness.local.md");
|
|
11341
11325
|
if (!isJson) {
|
|
@@ -12016,7 +12000,7 @@ function registerQueryCommand(program) {
|
|
|
12016
12000
|
}
|
|
12017
12001
|
|
|
12018
12002
|
// src/commands/retro-import.ts
|
|
12019
|
-
import { existsSync as
|
|
12003
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31 } from "fs";
|
|
12020
12004
|
import { join as join37 } from "path";
|
|
12021
12005
|
|
|
12022
12006
|
// src/lib/retro-parser.ts
|
|
@@ -12134,7 +12118,7 @@ function isDuplicate(newItem, existingTitles, threshold = 0.8) {
|
|
|
12134
12118
|
}
|
|
12135
12119
|
|
|
12136
12120
|
// src/lib/issue-tracker.ts
|
|
12137
|
-
import { existsSync as
|
|
12121
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, writeFileSync as writeFileSync17, mkdirSync as mkdirSync13 } from "fs";
|
|
12138
12122
|
import { join as join36 } from "path";
|
|
12139
12123
|
import { parse as parse6, stringify as stringify3 } from "yaml";
|
|
12140
12124
|
var VALID_PRIORITIES = /* @__PURE__ */ new Set([
|
|
@@ -12149,7 +12133,7 @@ function issuesPath(dir) {
|
|
|
12149
12133
|
}
|
|
12150
12134
|
function readIssues(dir = process.cwd()) {
|
|
12151
12135
|
const filePath = issuesPath(dir);
|
|
12152
|
-
if (!
|
|
12136
|
+
if (!existsSync34(filePath)) {
|
|
12153
12137
|
return { issues: [] };
|
|
12154
12138
|
}
|
|
12155
12139
|
const raw = readFileSync30(filePath, "utf-8");
|
|
@@ -12162,7 +12146,7 @@ function readIssues(dir = process.cwd()) {
|
|
|
12162
12146
|
function writeIssues(data, dir = process.cwd()) {
|
|
12163
12147
|
const filePath = issuesPath(dir);
|
|
12164
12148
|
const dirPath = join36(dir, ".codeharness");
|
|
12165
|
-
if (!
|
|
12149
|
+
if (!existsSync34(dirPath)) {
|
|
12166
12150
|
mkdirSync13(dirPath, { recursive: true });
|
|
12167
12151
|
}
|
|
12168
12152
|
writeFileSync17(filePath, stringify3(data, { nullStr: "" }), "utf-8");
|
|
@@ -12323,7 +12307,7 @@ function registerRetroImportCommand(program) {
|
|
|
12323
12307
|
}
|
|
12324
12308
|
const retroFile = `epic-${epicNum}-retrospective.md`;
|
|
12325
12309
|
const retroPath = join37(root, STORY_DIR3, retroFile);
|
|
12326
|
-
if (!
|
|
12310
|
+
if (!existsSync35(retroPath)) {
|
|
12327
12311
|
fail(`Retro file not found: ${retroFile}`, { json: isJson });
|
|
12328
12312
|
process.exitCode = 1;
|
|
12329
12313
|
return;
|
|
@@ -12822,7 +12806,7 @@ function registerValidateStateCommand(program) {
|
|
|
12822
12806
|
}
|
|
12823
12807
|
|
|
12824
12808
|
// src/commands/validate-schema.ts
|
|
12825
|
-
import { readdirSync as readdirSync9, existsSync as
|
|
12809
|
+
import { readdirSync as readdirSync9, existsSync as existsSync36 } from "fs";
|
|
12826
12810
|
import { join as join38, resolve as resolve6 } from "path";
|
|
12827
12811
|
function renderSchemaResult(result, isJson) {
|
|
12828
12812
|
if (isJson) {
|
|
@@ -12844,7 +12828,7 @@ function renderSchemaResult(result, isJson) {
|
|
|
12844
12828
|
}
|
|
12845
12829
|
function runSchemaValidation(projectDir) {
|
|
12846
12830
|
const workflowsDir = join38(projectDir, ".codeharness", "workflows");
|
|
12847
|
-
if (!
|
|
12831
|
+
if (!existsSync36(workflowsDir)) {
|
|
12848
12832
|
return {
|
|
12849
12833
|
status: "fail",
|
|
12850
12834
|
files: [{
|
|
@@ -13151,7 +13135,7 @@ function registerAuditCommand(program) {
|
|
|
13151
13135
|
}
|
|
13152
13136
|
|
|
13153
13137
|
// src/commands/stats.ts
|
|
13154
|
-
import { existsSync as
|
|
13138
|
+
import { existsSync as existsSync37, readdirSync as readdirSync10, readFileSync as readFileSync32, writeFileSync as writeFileSync18 } from "fs";
|
|
13155
13139
|
import { join as join39 } from "path";
|
|
13156
13140
|
var RATES = {
|
|
13157
13141
|
input: 15,
|
|
@@ -13175,7 +13159,7 @@ function addToBucket(target, input, output, cacheRead, cacheWrite) {
|
|
|
13175
13159
|
function parseLogFile(filePath, report) {
|
|
13176
13160
|
const basename3 = filePath.split("/").pop() ?? "";
|
|
13177
13161
|
const dateMatch = basename3.match(/(\d{4}-\d{2}-\d{2})/);
|
|
13178
|
-
const
|
|
13162
|
+
const _date = dateMatch ? dateMatch[1] : "unknown";
|
|
13179
13163
|
let currentPhase = "orchestrator";
|
|
13180
13164
|
let currentStory = "unknown";
|
|
13181
13165
|
let currentTool = "";
|
|
@@ -13239,7 +13223,7 @@ function parseLogFile(filePath, report) {
|
|
|
13239
13223
|
function generateReport3(projectDir, logsDir) {
|
|
13240
13224
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13241
13225
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13242
|
-
const resolvedLogsDir = logsDir ?? (
|
|
13226
|
+
const resolvedLogsDir = logsDir ?? (existsSync37(ralphLogs) ? ralphLogs : sessionLogs);
|
|
13243
13227
|
const logFiles = readdirSync10(resolvedLogsDir).filter((f) => f.endsWith(".log")).sort().map((f) => join39(resolvedLogsDir, f));
|
|
13244
13228
|
const report = {
|
|
13245
13229
|
byPhase: /* @__PURE__ */ new Map(),
|
|
@@ -13345,9 +13329,9 @@ function registerStatsCommand(program) {
|
|
|
13345
13329
|
} else {
|
|
13346
13330
|
const ralphLogs = join39(projectDir, "ralph", "logs");
|
|
13347
13331
|
const sessionLogs = join39(projectDir, "session-logs");
|
|
13348
|
-
logsDir =
|
|
13332
|
+
logsDir = existsSync37(ralphLogs) ? ralphLogs : sessionLogs;
|
|
13349
13333
|
}
|
|
13350
|
-
if (!
|
|
13334
|
+
if (!existsSync37(logsDir)) {
|
|
13351
13335
|
fail("No logs directory found \u2014 checked ralph/logs/ and session-logs/. Run codeharness run first or use --logs-dir <path>");
|
|
13352
13336
|
process.exitCode = 1;
|
|
13353
13337
|
return;
|
|
@@ -13749,7 +13733,6 @@ function parseLine(line) {
|
|
|
13749
13733
|
if (type === "item.started" && item) {
|
|
13750
13734
|
const itemType = item.type;
|
|
13751
13735
|
if (itemType === "command_execution") {
|
|
13752
|
-
const cmd = item.command;
|
|
13753
13736
|
return { type: "tool-start", name: "Bash", id: item.id ?? "" };
|
|
13754
13737
|
}
|
|
13755
13738
|
if (itemType === "file_edit") {
|
|
@@ -13763,7 +13746,6 @@ function parseLine(line) {
|
|
|
13763
13746
|
if (type === "item.completed" && item) {
|
|
13764
13747
|
const itemType = item.type;
|
|
13765
13748
|
if (itemType === "command_execution") {
|
|
13766
|
-
const cmd = item.command;
|
|
13767
13749
|
return { type: "tool-complete" };
|
|
13768
13750
|
}
|
|
13769
13751
|
if (itemType === "agent_message") {
|
|
@@ -14217,7 +14199,7 @@ function registerDriversCommand(program) {
|
|
|
14217
14199
|
}
|
|
14218
14200
|
|
|
14219
14201
|
// src/index.ts
|
|
14220
|
-
var VERSION = true ? "0.36.
|
|
14202
|
+
var VERSION = true ? "0.36.6" : "0.0.0-dev";
|
|
14221
14203
|
function createProgram() {
|
|
14222
14204
|
const program = new Command();
|
|
14223
14205
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|