codeharness 0.16.1 → 0.17.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.
- package/dist/index.js +124 -19
- package/package.json +1 -1
- package/ralph/drivers/claude-code.sh +3 -0
package/dist/index.js
CHANGED
|
@@ -464,6 +464,10 @@ var WEB_OTLP_PACKAGES = [
|
|
|
464
464
|
var AGENT_OTLP_PACKAGES_NODE = ["@traceloop/node-server-sdk"];
|
|
465
465
|
var AGENT_OTLP_PACKAGES_PYTHON = ["traceloop-sdk"];
|
|
466
466
|
var NODE_REQUIRE_FLAG = "--require @opentelemetry/auto-instrumentations-node/register";
|
|
467
|
+
function truncateError(message, maxLength = 200) {
|
|
468
|
+
if (message.length <= maxLength) return message;
|
|
469
|
+
return message.slice(0, maxLength) + "... (truncated)";
|
|
470
|
+
}
|
|
467
471
|
function installNodeOtlp(projectDir) {
|
|
468
472
|
try {
|
|
469
473
|
execFileSync2("npm", ["install", ...NODE_OTLP_PACKAGES], { cwd: projectDir, stdio: "pipe", timeout: 3e5 });
|
|
@@ -480,7 +484,7 @@ function installNodeOtlp(projectDir) {
|
|
|
480
484
|
packages_installed: false,
|
|
481
485
|
start_script_patched: false,
|
|
482
486
|
env_vars_configured: false,
|
|
483
|
-
error: `Failed to install Node.js OTLP packages: ${message}`
|
|
487
|
+
error: `Failed to install Node.js OTLP packages: ${truncateError(message)}`
|
|
484
488
|
};
|
|
485
489
|
}
|
|
486
490
|
}
|
|
@@ -489,8 +493,14 @@ function patchNodeStartScript(projectDir) {
|
|
|
489
493
|
if (!existsSync3(pkgPath)) {
|
|
490
494
|
return false;
|
|
491
495
|
}
|
|
492
|
-
|
|
493
|
-
|
|
496
|
+
let raw;
|
|
497
|
+
let pkg;
|
|
498
|
+
try {
|
|
499
|
+
raw = readFileSync3(pkgPath, "utf-8");
|
|
500
|
+
pkg = JSON.parse(raw);
|
|
501
|
+
} catch {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
494
504
|
const scripts = pkg["scripts"];
|
|
495
505
|
if (!scripts) {
|
|
496
506
|
return false;
|
|
@@ -554,6 +564,14 @@ function configureWeb(projectDir, stack) {
|
|
|
554
564
|
} catch {
|
|
555
565
|
}
|
|
556
566
|
}
|
|
567
|
+
let endpoint = "http://localhost:4318";
|
|
568
|
+
try {
|
|
569
|
+
const currentState = readState(projectDir);
|
|
570
|
+
if (currentState.otlp?.endpoint) {
|
|
571
|
+
endpoint = currentState.otlp.endpoint;
|
|
572
|
+
}
|
|
573
|
+
} catch {
|
|
574
|
+
}
|
|
557
575
|
const snippet = `// OpenTelemetry Web SDK initialization \u2014 generated by codeharness
|
|
558
576
|
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
|
559
577
|
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
@@ -563,7 +581,7 @@ import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xm
|
|
|
563
581
|
import { registerInstrumentations } from '@opentelemetry/instrumentation';
|
|
564
582
|
|
|
565
583
|
const exporter = new OTLPTraceExporter({
|
|
566
|
-
url: '
|
|
584
|
+
url: '${endpoint}/v1/traces',
|
|
567
585
|
});
|
|
568
586
|
|
|
569
587
|
const provider = new WebTracerProvider();
|
|
@@ -675,12 +693,12 @@ function instrumentProject(projectDir, stack, opts) {
|
|
|
675
693
|
error: "Unsupported stack for OTLP instrumentation"
|
|
676
694
|
};
|
|
677
695
|
}
|
|
696
|
+
configureOtlpEnvVars(projectDir, stack, { appType });
|
|
697
|
+
result.env_vars_configured = true;
|
|
698
|
+
if (!isJson) {
|
|
699
|
+
ok("OTLP: environment variables configured");
|
|
700
|
+
}
|
|
678
701
|
if (result.status === "configured") {
|
|
679
|
-
configureOtlpEnvVars(projectDir, stack, { appType });
|
|
680
|
-
result.env_vars_configured = true;
|
|
681
|
-
if (!isJson) {
|
|
682
|
-
ok("OTLP: environment variables configured");
|
|
683
|
-
}
|
|
684
702
|
if (appType === "cli") {
|
|
685
703
|
configureCli(projectDir);
|
|
686
704
|
if (!isJson) {
|
|
@@ -874,6 +892,11 @@ ${patchContent}
|
|
|
874
892
|
${markers.end}`;
|
|
875
893
|
const startIdx = content.indexOf(markers.start);
|
|
876
894
|
const endIdx = content.indexOf(markers.end);
|
|
895
|
+
if (startIdx !== -1 !== (endIdx !== -1)) {
|
|
896
|
+
throw new Error(
|
|
897
|
+
`Corrupted patch markers for '${patchName}': only ${startIdx !== -1 ? "start" : "end"} marker found in ${filePath}`
|
|
898
|
+
);
|
|
899
|
+
}
|
|
877
900
|
if (startIdx !== -1 && endIdx !== -1) {
|
|
878
901
|
if (endIdx < startIdx) {
|
|
879
902
|
throw new Error(
|
|
@@ -1060,8 +1083,8 @@ var BmadError = class extends Error {
|
|
|
1060
1083
|
};
|
|
1061
1084
|
var PATCH_TARGETS = {
|
|
1062
1085
|
"story-verification": "bmm/workflows/4-implementation/create-story/template.md",
|
|
1063
|
-
"dev-enforcement": "bmm/workflows/4-implementation/dev-story/
|
|
1064
|
-
"review-enforcement": "bmm/workflows/4-implementation/code-review/
|
|
1086
|
+
"dev-enforcement": "bmm/workflows/4-implementation/dev-story/instructions.xml",
|
|
1087
|
+
"review-enforcement": "bmm/workflows/4-implementation/code-review/instructions.xml",
|
|
1065
1088
|
"retro-enforcement": "bmm/workflows/4-implementation/retrospective/instructions.md",
|
|
1066
1089
|
"sprint-beads": "bmm/workflows/4-implementation/sprint-planning/checklist.md",
|
|
1067
1090
|
"sprint-retro": "bmm/workflows/4-implementation/sprint-planning/instructions.md"
|
|
@@ -1110,9 +1133,9 @@ function installBmad(dir) {
|
|
|
1110
1133
|
patches_applied: []
|
|
1111
1134
|
};
|
|
1112
1135
|
}
|
|
1113
|
-
const cmdStr = "npx bmad-method
|
|
1136
|
+
const cmdStr = "npx bmad-method install";
|
|
1114
1137
|
try {
|
|
1115
|
-
execFileSync4("npx", ["bmad-method", "
|
|
1138
|
+
execFileSync4("npx", ["bmad-method", "install"], {
|
|
1116
1139
|
stdio: "pipe",
|
|
1117
1140
|
timeout: 6e4,
|
|
1118
1141
|
cwd: root
|
|
@@ -1121,6 +1144,9 @@ function installBmad(dir) {
|
|
|
1121
1144
|
const message = err instanceof Error ? err.message : String(err);
|
|
1122
1145
|
throw new BmadError(cmdStr, message);
|
|
1123
1146
|
}
|
|
1147
|
+
if (!isBmadInstalled(root)) {
|
|
1148
|
+
throw new BmadError(cmdStr, "_bmad/ directory was not created after successful npx bmad-method install");
|
|
1149
|
+
}
|
|
1124
1150
|
const version = detectBmadVersion(root);
|
|
1125
1151
|
return {
|
|
1126
1152
|
status: "installed",
|
|
@@ -1177,6 +1203,21 @@ function applyAllPatches(dir) {
|
|
|
1177
1203
|
}
|
|
1178
1204
|
return results;
|
|
1179
1205
|
}
|
|
1206
|
+
function detectBmalph(dir) {
|
|
1207
|
+
const root = dir ?? process.cwd();
|
|
1208
|
+
const files = [];
|
|
1209
|
+
const ralphRcPath = join5(root, ".ralph", ".ralphrc");
|
|
1210
|
+
if (existsSync5(ralphRcPath)) {
|
|
1211
|
+
files.push(".ralph/.ralphrc");
|
|
1212
|
+
}
|
|
1213
|
+
const dotRalphDir = join5(root, ".ralph");
|
|
1214
|
+
if (existsSync5(dotRalphDir)) {
|
|
1215
|
+
if (files.length === 0) {
|
|
1216
|
+
files.push(".ralph/");
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
return { detected: files.length > 0, files };
|
|
1220
|
+
}
|
|
1180
1221
|
function generateStoryKey(epicNumber, storyNumber, title) {
|
|
1181
1222
|
const slug = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1182
1223
|
return `${epicNumber}-${storyNumber}-${slug}`;
|
|
@@ -1402,7 +1443,7 @@ function getInstallCommand(stack) {
|
|
|
1402
1443
|
}
|
|
1403
1444
|
|
|
1404
1445
|
// src/commands/init.ts
|
|
1405
|
-
var HARNESS_VERSION = true ? "0.
|
|
1446
|
+
var HARNESS_VERSION = true ? "0.17.0" : "0.0.0-dev";
|
|
1406
1447
|
function getProjectName(projectDir) {
|
|
1407
1448
|
try {
|
|
1408
1449
|
const pkgPath = join6(projectDir, "package.json");
|
|
@@ -1498,7 +1539,7 @@ function generateDocsIndexContent() {
|
|
|
1498
1539
|
}
|
|
1499
1540
|
var DO_NOT_EDIT_HEADER = "<!-- DO NOT EDIT MANUALLY -->\n";
|
|
1500
1541
|
function registerInitCommand(program) {
|
|
1501
|
-
program.command("init").description("Initialize the harness in a project").option("--no-frontend", "Disable frontend enforcement").option("--no-database", "Disable database enforcement").option("--no-api", "Disable API enforcement").option("--otel-endpoint <url>", "Remote OTLP endpoint (skips local Docker stack)").option("--logs-url <url>", "Remote VictoriaLogs URL").option("--metrics-url <url>", "Remote VictoriaMetrics URL").option("--traces-url <url>", "Remote Jaeger/VictoriaTraces URL").action(async (options, cmd) => {
|
|
1542
|
+
program.command("init").description("Initialize the harness in a project").option("--no-frontend", "Disable frontend enforcement").option("--no-database", "Disable database enforcement").option("--no-api", "Disable API enforcement").option("--no-observability", "Skip OTLP package installation").option("--otel-endpoint <url>", "Remote OTLP endpoint (skips local Docker stack)").option("--logs-url <url>", "Remote VictoriaLogs URL").option("--metrics-url <url>", "Remote VictoriaMetrics URL").option("--traces-url <url>", "Remote Jaeger/VictoriaTraces URL").action(async (options, cmd) => {
|
|
1502
1543
|
const globalOpts = cmd.optsWithGlobals();
|
|
1503
1544
|
const isJson = globalOpts.json === true;
|
|
1504
1545
|
const projectDir = process.cwd();
|
|
@@ -1527,6 +1568,47 @@ function registerInitCommand(program) {
|
|
|
1527
1568
|
result.documentation.agents_md = "exists";
|
|
1528
1569
|
result.documentation.docs_scaffold = "exists";
|
|
1529
1570
|
result.documentation.readme = "exists";
|
|
1571
|
+
const depResults = [];
|
|
1572
|
+
for (const spec of DEPENDENCY_REGISTRY) {
|
|
1573
|
+
const check = checkInstalled(spec);
|
|
1574
|
+
const depResult = {
|
|
1575
|
+
name: spec.name,
|
|
1576
|
+
displayName: spec.displayName,
|
|
1577
|
+
status: check.installed ? "already-installed" : "failed",
|
|
1578
|
+
version: check.version
|
|
1579
|
+
};
|
|
1580
|
+
depResults.push(depResult);
|
|
1581
|
+
if (!isJson) {
|
|
1582
|
+
if (check.installed) {
|
|
1583
|
+
const versionStr = check.version ? ` (v${check.version})` : "";
|
|
1584
|
+
ok(`${spec.displayName}: already installed${versionStr}`);
|
|
1585
|
+
} else {
|
|
1586
|
+
fail(`${spec.displayName}: not found`);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
result.dependencies = depResults;
|
|
1591
|
+
if (isBmadInstalled(projectDir)) {
|
|
1592
|
+
try {
|
|
1593
|
+
const patchResults = applyAllPatches(projectDir);
|
|
1594
|
+
const patchNames = patchResults.filter((r) => r.applied).map((r) => r.patchName);
|
|
1595
|
+
const version = detectBmadVersion(projectDir);
|
|
1596
|
+
const bmalpHDetection = detectBmalph(projectDir);
|
|
1597
|
+
result.bmad = {
|
|
1598
|
+
status: "already-installed",
|
|
1599
|
+
version,
|
|
1600
|
+
patches_applied: patchNames,
|
|
1601
|
+
bmalph_detected: bmalpHDetection.detected
|
|
1602
|
+
};
|
|
1603
|
+
if (!isJson) {
|
|
1604
|
+
info("BMAD: already installed, patches verified");
|
|
1605
|
+
if (bmalpHDetection.detected) {
|
|
1606
|
+
warn("bmalph detected \u2014 superseded files noted for cleanup");
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
} catch {
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1530
1612
|
if (isJson) {
|
|
1531
1613
|
jsonOutput(result);
|
|
1532
1614
|
} else {
|
|
@@ -1661,7 +1743,8 @@ function registerInitCommand(program) {
|
|
|
1661
1743
|
result.bmad = {
|
|
1662
1744
|
status: "already-installed",
|
|
1663
1745
|
version,
|
|
1664
|
-
patches_applied: patchNames
|
|
1746
|
+
patches_applied: patchNames,
|
|
1747
|
+
bmalph_detected: false
|
|
1665
1748
|
};
|
|
1666
1749
|
if (!isJson) {
|
|
1667
1750
|
info("BMAD: existing installation detected, patches applied");
|
|
@@ -1673,18 +1756,27 @@ function registerInitCommand(program) {
|
|
|
1673
1756
|
result.bmad = {
|
|
1674
1757
|
status: installResult.status,
|
|
1675
1758
|
version: installResult.version,
|
|
1676
|
-
patches_applied: patchNames
|
|
1759
|
+
patches_applied: patchNames,
|
|
1760
|
+
bmalph_detected: false
|
|
1677
1761
|
};
|
|
1678
1762
|
if (!isJson) {
|
|
1679
1763
|
ok(`BMAD: installed (v${installResult.version ?? "unknown"}), harness patches applied`);
|
|
1680
1764
|
}
|
|
1681
1765
|
}
|
|
1766
|
+
const bmalpHDetection = detectBmalph(projectDir);
|
|
1767
|
+
if (bmalpHDetection.detected && result.bmad) {
|
|
1768
|
+
result.bmad.bmalph_detected = true;
|
|
1769
|
+
if (!isJson) {
|
|
1770
|
+
warn("bmalph detected \u2014 superseded files noted for cleanup");
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1682
1773
|
} catch (err) {
|
|
1683
1774
|
if (err instanceof BmadError) {
|
|
1684
1775
|
result.bmad = {
|
|
1685
1776
|
status: "failed",
|
|
1686
1777
|
version: null,
|
|
1687
1778
|
patches_applied: [],
|
|
1779
|
+
bmalph_detected: false,
|
|
1688
1780
|
error: err.message
|
|
1689
1781
|
};
|
|
1690
1782
|
if (!isJson) {
|
|
@@ -1757,7 +1849,20 @@ function registerInitCommand(program) {
|
|
|
1757
1849
|
ok("Documentation: README.md created");
|
|
1758
1850
|
}
|
|
1759
1851
|
}
|
|
1760
|
-
|
|
1852
|
+
let otlpResult;
|
|
1853
|
+
if (!options.observability) {
|
|
1854
|
+
otlpResult = {
|
|
1855
|
+
status: "skipped",
|
|
1856
|
+
packages_installed: false,
|
|
1857
|
+
start_script_patched: false,
|
|
1858
|
+
env_vars_configured: false
|
|
1859
|
+
};
|
|
1860
|
+
if (!isJson) {
|
|
1861
|
+
info("OTLP: skipped (--no-observability)");
|
|
1862
|
+
}
|
|
1863
|
+
} else {
|
|
1864
|
+
otlpResult = instrumentProject(projectDir, stack, { json: isJson, appType });
|
|
1865
|
+
}
|
|
1761
1866
|
result.otlp = otlpResult;
|
|
1762
1867
|
try {
|
|
1763
1868
|
const updatedState = readState(projectDir);
|
|
@@ -7675,7 +7780,7 @@ function handleStatus(dir, isJson, filterStory) {
|
|
|
7675
7780
|
}
|
|
7676
7781
|
|
|
7677
7782
|
// src/index.ts
|
|
7678
|
-
var VERSION = true ? "0.
|
|
7783
|
+
var VERSION = true ? "0.17.0" : "0.0.0-dev";
|
|
7679
7784
|
function createProgram() {
|
|
7680
7785
|
const program = new Command();
|
|
7681
7786
|
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