codeharness 0.28.2 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2895,7 +2895,7 @@ function generateDockerfileTemplate(projectDir, stackOrDetections) {
|
|
|
2895
2895
|
}
|
|
2896
2896
|
|
|
2897
2897
|
// src/modules/infra/init-project.ts
|
|
2898
|
-
var HARNESS_VERSION = true ? "0.
|
|
2898
|
+
var HARNESS_VERSION = true ? "0.29.0" : "0.0.0-dev";
|
|
2899
2899
|
function failResult(opts, error) {
|
|
2900
2900
|
return {
|
|
2901
2901
|
status: "fail",
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
validateDockerfile,
|
|
41
41
|
warn,
|
|
42
42
|
writeState
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-PTHST5Z7.js";
|
|
44
44
|
|
|
45
45
|
// src/index.ts
|
|
46
46
|
import { Command } from "commander";
|
|
@@ -1879,31 +1879,6 @@ function getDriver(name) {
|
|
|
1879
1879
|
function listDrivers() {
|
|
1880
1880
|
return [...registry.keys()];
|
|
1881
1881
|
}
|
|
1882
|
-
function suggestCheaperDriver(driverName, requiredCaps) {
|
|
1883
|
-
const current = registry.get(driverName);
|
|
1884
|
-
if (!current) return null;
|
|
1885
|
-
let cheapestName = null;
|
|
1886
|
-
let cheapestTier = Infinity;
|
|
1887
|
-
for (const [name, driver] of registry) {
|
|
1888
|
-
let satisfies = true;
|
|
1889
|
-
for (const [key, value] of Object.entries(requiredCaps)) {
|
|
1890
|
-
if (typeof value === "boolean" && value === true) {
|
|
1891
|
-
if (!driver.capabilities[key]) {
|
|
1892
|
-
satisfies = false;
|
|
1893
|
-
break;
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
if (satisfies && driver.capabilities.costTier < cheapestTier) {
|
|
1898
|
-
cheapestTier = driver.capabilities.costTier;
|
|
1899
|
-
cheapestName = name;
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
if (cheapestName && cheapestTier < current.capabilities.costTier) {
|
|
1903
|
-
return cheapestName;
|
|
1904
|
-
}
|
|
1905
|
-
return null;
|
|
1906
|
-
}
|
|
1907
1882
|
|
|
1908
1883
|
// src/lib/agent-resolver.ts
|
|
1909
1884
|
import { readFileSync as readFileSync8, existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
|
|
@@ -2542,21 +2517,6 @@ function checkCapabilityConflicts(workflow) {
|
|
|
2542
2517
|
message: `Task "${taskName}" requires plugins but driver "${driverName}" does not support plugins (supportsPlugins: false)`
|
|
2543
2518
|
});
|
|
2544
2519
|
}
|
|
2545
|
-
const requiredCaps = {
|
|
2546
|
-
...hasPlugins ? { supportsPlugins: true } : {}
|
|
2547
|
-
};
|
|
2548
|
-
const cheaper = suggestCheaperDriver(driverName, requiredCaps);
|
|
2549
|
-
if (cheaper) {
|
|
2550
|
-
const cheaperDriver = getDriver(cheaper);
|
|
2551
|
-
if (driver.capabilities.costTier > 2 * cheaperDriver.capabilities.costTier) {
|
|
2552
|
-
warnings.push({
|
|
2553
|
-
taskName,
|
|
2554
|
-
driverName,
|
|
2555
|
-
capability: "costTier",
|
|
2556
|
-
message: `Advisory: task "${taskName}" uses ${driverName} \u2014 ${cheaper} could handle this task at lower cost`
|
|
2557
|
-
});
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
2520
|
}
|
|
2561
2521
|
return warnings;
|
|
2562
2522
|
}
|
|
@@ -3397,6 +3357,7 @@ ${coverageDedup}`;
|
|
|
3397
3357
|
...task.plugins ?? definition.plugins ? { plugins: task.plugins ?? definition.plugins } : {},
|
|
3398
3358
|
...task.max_budget_usd != null ? { timeout: task.max_budget_usd } : {}
|
|
3399
3359
|
};
|
|
3360
|
+
info(`[${taskName}] ${storyKey} \u2014 dispatching via ${driverName} (model: ${model})`);
|
|
3400
3361
|
let output = "";
|
|
3401
3362
|
let resultSessionId = "";
|
|
3402
3363
|
let cost = 0;
|
|
@@ -3866,6 +3827,10 @@ async function executeWorkflow(config) {
|
|
|
3866
3827
|
durationMs: 0
|
|
3867
3828
|
};
|
|
3868
3829
|
}
|
|
3830
|
+
if (state.phase === "error" || state.phase === "failed") {
|
|
3831
|
+
const errorCount = state.tasks_completed.filter((t) => t.error).length;
|
|
3832
|
+
info(`Resuming from ${state.phase} state \u2014 ${errorCount} previous error(s), retrying failed tasks`);
|
|
3833
|
+
}
|
|
3869
3834
|
state = {
|
|
3870
3835
|
...state,
|
|
3871
3836
|
phase: "executing",
|
|
@@ -4072,7 +4037,9 @@ function recordErrorInState(state, taskName, storyKey, error) {
|
|
|
4072
4037
|
task_name: taskName,
|
|
4073
4038
|
story_key: storyKey,
|
|
4074
4039
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4075
|
-
error: true
|
|
4040
|
+
error: true,
|
|
4041
|
+
error_message: error.message,
|
|
4042
|
+
error_code: error.code
|
|
4076
4043
|
};
|
|
4077
4044
|
return {
|
|
4078
4045
|
...state,
|
|
@@ -9907,7 +9874,7 @@ function registerTeardownCommand(program) {
|
|
|
9907
9874
|
} else if (otlpMode === "remote-routed") {
|
|
9908
9875
|
if (!options.keepDocker) {
|
|
9909
9876
|
try {
|
|
9910
|
-
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-
|
|
9877
|
+
const { stopCollectorOnly: stopCollectorOnly2 } = await import("./docker-32GRDQOK.js");
|
|
9911
9878
|
stopCollectorOnly2();
|
|
9912
9879
|
result.docker.stopped = true;
|
|
9913
9880
|
if (!isJson) {
|
|
@@ -9939,7 +9906,7 @@ function registerTeardownCommand(program) {
|
|
|
9939
9906
|
info("Shared stack: kept running (other projects may use it)");
|
|
9940
9907
|
}
|
|
9941
9908
|
} else if (isLegacyStack) {
|
|
9942
|
-
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-
|
|
9909
|
+
const { isStackRunning: isStackRunning2, stopStack } = await import("./docker-32GRDQOK.js");
|
|
9943
9910
|
let stackRunning = false;
|
|
9944
9911
|
try {
|
|
9945
9912
|
stackRunning = isStackRunning2(composeFile);
|
|
@@ -12817,7 +12784,7 @@ function registerDriversCommand(program) {
|
|
|
12817
12784
|
}
|
|
12818
12785
|
|
|
12819
12786
|
// src/index.ts
|
|
12820
|
-
var VERSION = true ? "0.
|
|
12787
|
+
var VERSION = true ? "0.29.0" : "0.0.0-dev";
|
|
12821
12788
|
function createProgram() {
|
|
12822
12789
|
const program = new Command();
|
|
12823
12790
|
program.name("codeharness").description("Makes autonomous coding agents produce software that actually works").version(VERSION).option("--json", "Output in machine-readable JSON format");
|
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: story-creator
|
|
2
|
+
role:
|
|
3
|
+
title: Story Creator
|
|
4
|
+
purpose: Create implementation-ready story files from epic specifications with clear ACs, task breakdowns, and dev notes
|
|
5
|
+
persona:
|
|
6
|
+
identity: |
|
|
7
|
+
Technical scrum master who creates detailed, unambiguous story specs.
|
|
8
|
+
Reads epic definitions, architecture docs, and existing code to produce
|
|
9
|
+
stories that a developer agent can execute without clarification.
|
|
10
|
+
communication_style: "Precise, structured. Every AC is testable. Every task maps to an AC. No ambiguity."
|
|
11
|
+
principles:
|
|
12
|
+
- Every acceptance criterion must be independently verifiable
|
|
13
|
+
- Tasks must be ordered by dependency — no circular references
|
|
14
|
+
- Dev notes must cite specific files, modules, and patterns from the codebase
|
|
15
|
+
- Story scope must match the epic definition exactly — no scope creep, no missing requirements
|
|
16
|
+
- Reference architecture decisions and constraints that affect implementation
|
|
17
|
+
prompt_template: |
|
|
18
|
+
## Role
|
|
19
|
+
|
|
20
|
+
You are creating an implementation-ready story file. The developer agent will execute this story without asking questions — every detail must be explicit.
|
|
21
|
+
|
|
22
|
+
## Input
|
|
23
|
+
|
|
24
|
+
1. Read the sprint plan / epic definitions to find the next story to create
|
|
25
|
+
2. Read architecture docs for technical constraints
|
|
26
|
+
3. Read the existing codebase to understand current patterns, naming conventions, and module structure
|
|
27
|
+
4. Read any previous story files in this epic for consistency
|
|
28
|
+
|
|
29
|
+
## Story Creation Process
|
|
30
|
+
|
|
31
|
+
1. **Identify the story** from the sprint plan — find the next unwritten story
|
|
32
|
+
2. **Read all referenced source material** — PRD sections, architecture decisions, UX specs cited in the epic
|
|
33
|
+
3. **Scan the codebase** — understand existing patterns, file structure, test conventions
|
|
34
|
+
4. **Write the story file** using the project's story template
|
|
35
|
+
|
|
36
|
+
## Story Quality Requirements
|
|
37
|
+
|
|
38
|
+
- **Acceptance Criteria**: Each AC must be a concrete, testable condition. Use Given/When/Then or equivalent. Number them sequentially.
|
|
39
|
+
- **Tasks/Subtasks**: Ordered implementation steps. Each task references which AC(s) it satisfies. Include test-writing tasks.
|
|
40
|
+
- **Dev Notes**: Cite specific files to modify, patterns to follow, architecture constraints. Include file paths.
|
|
41
|
+
- **Testing Requirements**: Specify what to test, expected coverage, test file locations.
|
|
42
|
+
|
|
43
|
+
## Anti-Patterns to Avoid
|
|
44
|
+
|
|
45
|
+
- Vague ACs like "system should handle errors gracefully" — specify WHICH errors and HOW
|
|
46
|
+
- Tasks without AC mapping — every task must trace to at least one AC
|
|
47
|
+
- Missing edge cases — think about failure modes, not just happy path
|
|
48
|
+
- Ignoring existing code patterns — the dev agent must follow established conventions
|
|
49
|
+
|
|
50
|
+
## Output
|
|
51
|
+
|
|
52
|
+
Write the story file to the implementation artifacts directory following the project's naming convention.
|
|
53
|
+
Mark the story as `ready-for-dev` in the sprint status.
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
tasks:
|
|
2
|
+
create-story:
|
|
3
|
+
agent: story-creator
|
|
4
|
+
scope: per-story
|
|
5
|
+
session: fresh
|
|
6
|
+
source_access: true
|
|
7
|
+
model: claude-opus-4-6-20250514
|
|
2
8
|
implement:
|
|
3
9
|
agent: dev
|
|
4
10
|
scope: per-story
|
|
@@ -31,6 +37,7 @@ tasks:
|
|
|
31
37
|
model: claude-opus-4-6-20250514
|
|
32
38
|
|
|
33
39
|
flow:
|
|
40
|
+
- create-story
|
|
34
41
|
- implement
|
|
35
42
|
- review
|
|
36
43
|
- verify
|