@brawnen/harnessly 0.1.0-alpha.5 → 0.1.0-alpha.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.
- package/dist/index.js +54 -36
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -834,8 +834,26 @@ async function loadHarnessConfig(workDir) {
|
|
|
834
834
|
const configText = await readFile(getHarnessPaths(workDir).configFile, "utf8");
|
|
835
835
|
return parseHarnessConfig2(configText);
|
|
836
836
|
}
|
|
837
|
+
function isMissingFileError(error) {
|
|
838
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
839
|
+
}
|
|
837
840
|
async function writeHarnessConfig(workDir, config, force = false) {
|
|
838
|
-
|
|
841
|
+
const configPath = getHarnessPaths(workDir).configFile;
|
|
842
|
+
let mergedConfig = config;
|
|
843
|
+
let didMerge = false;
|
|
844
|
+
try {
|
|
845
|
+
const existing = await loadHarnessConfig(workDir);
|
|
846
|
+
const mergedHosts = [.../* @__PURE__ */ new Set([...existing.enabledHosts, ...config.enabledHosts])];
|
|
847
|
+
if (mergedHosts.length > existing.enabledHosts.length) {
|
|
848
|
+
mergedConfig = { ...existing, ...config, enabledHosts: mergedHosts };
|
|
849
|
+
didMerge = true;
|
|
850
|
+
} else if (!force) {
|
|
851
|
+
return "skipped";
|
|
852
|
+
}
|
|
853
|
+
} catch (error) {
|
|
854
|
+
if (!isMissingFileError(error)) throw error;
|
|
855
|
+
}
|
|
856
|
+
return writeFileIfChanged(configPath, serializeHarnessConfig2(mergedConfig), force || didMerge);
|
|
839
857
|
}
|
|
840
858
|
var AGENT_ROLES = [
|
|
841
859
|
"requirement",
|
|
@@ -1013,14 +1031,14 @@ function getDefaultAgentManifest(role) {
|
|
|
1013
1031
|
toolWhitelist: [...source.toolWhitelist]
|
|
1014
1032
|
};
|
|
1015
1033
|
}
|
|
1016
|
-
function
|
|
1034
|
+
function isMissingFileError2(error) {
|
|
1017
1035
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1018
1036
|
}
|
|
1019
1037
|
async function readFileIfExists(filePath) {
|
|
1020
1038
|
try {
|
|
1021
1039
|
return await readFile2(filePath, "utf8");
|
|
1022
1040
|
} catch (error) {
|
|
1023
|
-
if (
|
|
1041
|
+
if (isMissingFileError2(error)) {
|
|
1024
1042
|
return null;
|
|
1025
1043
|
}
|
|
1026
1044
|
throw error;
|
|
@@ -1134,7 +1152,7 @@ function getFeedbackPoolPath(workDir) {
|
|
|
1134
1152
|
function getFeedbackHistoryPath(workDir) {
|
|
1135
1153
|
return path4.join(getHarnessPaths(workDir).harnessDir, "feedback-history.md");
|
|
1136
1154
|
}
|
|
1137
|
-
function
|
|
1155
|
+
function isMissingFileError3(error) {
|
|
1138
1156
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1139
1157
|
}
|
|
1140
1158
|
function buildFeedbackEntry(ctx, report) {
|
|
@@ -1176,7 +1194,7 @@ async function loadFeedbackPool(workDir) {
|
|
|
1176
1194
|
try {
|
|
1177
1195
|
text = await readFile3(filePath, "utf8");
|
|
1178
1196
|
} catch (error) {
|
|
1179
|
-
if (
|
|
1197
|
+
if (isMissingFileError3(error)) {
|
|
1180
1198
|
return [];
|
|
1181
1199
|
}
|
|
1182
1200
|
throw error;
|
|
@@ -1259,7 +1277,7 @@ async function readJson(filePath) {
|
|
|
1259
1277
|
const text = await readFile4(filePath, "utf8");
|
|
1260
1278
|
return JSON.parse(text);
|
|
1261
1279
|
}
|
|
1262
|
-
function
|
|
1280
|
+
function isMissingFileError4(error) {
|
|
1263
1281
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1264
1282
|
}
|
|
1265
1283
|
function ownerForStage(stage) {
|
|
@@ -1439,7 +1457,7 @@ var TaskManager = class {
|
|
|
1439
1457
|
const filePath = path5.join(ctx.taskDir, "commit-summary.md");
|
|
1440
1458
|
try {
|
|
1441
1459
|
const existing = await readFile4(filePath, "utf8").catch(
|
|
1442
|
-
(error) =>
|
|
1460
|
+
(error) => isMissingFileError4(error) ? "" : Promise.reject(error)
|
|
1443
1461
|
);
|
|
1444
1462
|
const section = `${heading}
|
|
1445
1463
|
${content}
|
|
@@ -1477,7 +1495,7 @@ ${content}
|
|
|
1477
1495
|
try {
|
|
1478
1496
|
return parseTaskReport(await readFile4(this.getReportFile(taskDir), "utf8"));
|
|
1479
1497
|
} catch (error) {
|
|
1480
|
-
if (
|
|
1498
|
+
if (isMissingFileError4(error)) {
|
|
1481
1499
|
return null;
|
|
1482
1500
|
}
|
|
1483
1501
|
if (error instanceof Error) {
|
|
@@ -1494,7 +1512,7 @@ ${content}
|
|
|
1494
1512
|
meta = await readJson(this.getMetaFile(taskDir));
|
|
1495
1513
|
state = await readJson(this.getStateFile(taskDir));
|
|
1496
1514
|
} catch (error) {
|
|
1497
|
-
if (
|
|
1515
|
+
if (isMissingFileError4(error)) {
|
|
1498
1516
|
throw new Error(`task ${taskId} \u4E0D\u5B58\u5728\u3002\u53EF\u5148\u6267\u884C harnessly list \u67E5\u770B\u5DF2\u6709\u4EFB\u52A1\u3002`);
|
|
1499
1517
|
}
|
|
1500
1518
|
throw error;
|
|
@@ -1511,7 +1529,7 @@ ${content}
|
|
|
1511
1529
|
try {
|
|
1512
1530
|
ctx.contract = parseContract(await readFile4(this.getContractFile(taskDir), "utf8"));
|
|
1513
1531
|
} catch (error) {
|
|
1514
|
-
if (!
|
|
1532
|
+
if (!isMissingFileError4(error)) {
|
|
1515
1533
|
throw error;
|
|
1516
1534
|
}
|
|
1517
1535
|
}
|
|
@@ -1537,7 +1555,7 @@ ${content}
|
|
|
1537
1555
|
try {
|
|
1538
1556
|
entries = await readdir2(tasksDir, { withFileTypes: true });
|
|
1539
1557
|
} catch (error) {
|
|
1540
|
-
if (
|
|
1558
|
+
if (isMissingFileError4(error)) {
|
|
1541
1559
|
return [];
|
|
1542
1560
|
}
|
|
1543
1561
|
throw error;
|
|
@@ -1569,7 +1587,7 @@ ${content}
|
|
|
1569
1587
|
var DEFAULT_TOPIC = "tasks";
|
|
1570
1588
|
var AUTO_START = "<!-- harness:auto-start -->";
|
|
1571
1589
|
var AUTO_END = "<!-- harness:auto-end -->";
|
|
1572
|
-
function
|
|
1590
|
+
function isMissingFileError5(error) {
|
|
1573
1591
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1574
1592
|
}
|
|
1575
1593
|
async function fileExists2(filePath) {
|
|
@@ -1577,7 +1595,7 @@ async function fileExists2(filePath) {
|
|
|
1577
1595
|
await access2(filePath);
|
|
1578
1596
|
return true;
|
|
1579
1597
|
} catch (error) {
|
|
1580
|
-
if (
|
|
1598
|
+
if (isMissingFileError5(error)) return false;
|
|
1581
1599
|
throw error;
|
|
1582
1600
|
}
|
|
1583
1601
|
}
|
|
@@ -1589,7 +1607,7 @@ function pickFilesByKind(kind) {
|
|
|
1589
1607
|
}
|
|
1590
1608
|
function readTaskReportSafe(filePath) {
|
|
1591
1609
|
return readFile5(filePath, "utf8").then((text) => parseTaskReport(text)).catch((error) => {
|
|
1592
|
-
if (
|
|
1610
|
+
if (isMissingFileError5(error)) return null;
|
|
1593
1611
|
return null;
|
|
1594
1612
|
});
|
|
1595
1613
|
}
|
|
@@ -1601,7 +1619,7 @@ async function loadHarnessMeta(topicDir) {
|
|
|
1601
1619
|
const text = await readFile5(getHarnessMetaPath(topicDir), "utf8");
|
|
1602
1620
|
return harnessMetaFileSchema.parse(JSON.parse(text));
|
|
1603
1621
|
} catch (error) {
|
|
1604
|
-
if (
|
|
1622
|
+
if (isMissingFileError5(error)) return null;
|
|
1605
1623
|
return null;
|
|
1606
1624
|
}
|
|
1607
1625
|
}
|
|
@@ -1708,7 +1726,7 @@ async function writeReadme(topicDir, topic, meta) {
|
|
|
1708
1726
|
${existing}`;
|
|
1709
1727
|
}
|
|
1710
1728
|
} catch (error) {
|
|
1711
|
-
if (!
|
|
1729
|
+
if (!isMissingFileError5(error)) throw error;
|
|
1712
1730
|
existingBefore = `${AUTO_START}`;
|
|
1713
1731
|
existingAfter = `
|
|
1714
1732
|
${AUTO_END}`;
|
|
@@ -1782,7 +1800,7 @@ async function listDirs(dirPath) {
|
|
|
1782
1800
|
const entries = await readdir3(dirPath, { withFileTypes: true });
|
|
1783
1801
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1784
1802
|
} catch (error) {
|
|
1785
|
-
if (
|
|
1803
|
+
if (isMissingFileError5(error)) return [];
|
|
1786
1804
|
throw error;
|
|
1787
1805
|
}
|
|
1788
1806
|
}
|
|
@@ -1819,7 +1837,7 @@ async function showArchiveTopic(workDir, topic) {
|
|
|
1819
1837
|
try {
|
|
1820
1838
|
readme = await readFile5(path6.join(topicDir, "README.md"), "utf8");
|
|
1821
1839
|
} catch (error) {
|
|
1822
|
-
if (!
|
|
1840
|
+
if (!isMissingFileError5(error)) throw error;
|
|
1823
1841
|
}
|
|
1824
1842
|
const allFiles = /* @__PURE__ */ new Set();
|
|
1825
1843
|
for (const task of meta.source_tasks) {
|
|
@@ -1908,7 +1926,7 @@ async function archiveTaskArtifacts(workDir, taskId, kind, options = {}) {
|
|
|
1908
1926
|
const reportFile = path6.join(ctx.taskDir, "report.json");
|
|
1909
1927
|
const report = await readTaskReportSafe(reportFile);
|
|
1910
1928
|
const previousReadme = await readFile5(path6.join(targets.topicDir, "README.md"), "utf8").catch(
|
|
1911
|
-
(error) =>
|
|
1929
|
+
(error) => isMissingFileError5(error) ? null : Promise.reject(error)
|
|
1912
1930
|
);
|
|
1913
1931
|
await writeFile5(path6.join(targets.topicDir, "README.md"), [
|
|
1914
1932
|
`# Task Archive: ${ctx.goal}`,
|
|
@@ -1937,7 +1955,7 @@ async function archiveTaskArtifacts(workDir, taskId, kind, options = {}) {
|
|
|
1937
1955
|
});
|
|
1938
1956
|
const metadataPath = path6.join(targets.topicDir, `${taskId}.promotion.json`);
|
|
1939
1957
|
const previousMetadata = await readFile5(metadataPath, "utf8").catch(
|
|
1940
|
-
(error) =>
|
|
1958
|
+
(error) => isMissingFileError5(error) ? null : Promise.reject(error)
|
|
1941
1959
|
);
|
|
1942
1960
|
await writeFile5(
|
|
1943
1961
|
metadataPath,
|
|
@@ -1960,7 +1978,7 @@ async function exists(filePath) {
|
|
|
1960
1978
|
return false;
|
|
1961
1979
|
}
|
|
1962
1980
|
}
|
|
1963
|
-
function
|
|
1981
|
+
function isMissingFileError6(error) {
|
|
1964
1982
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
1965
1983
|
}
|
|
1966
1984
|
var REQUIRED_TASK_ARTIFACTS = [
|
|
@@ -2034,7 +2052,7 @@ async function checkWritePermission(workDir, filePath, activeTaskId) {
|
|
|
2034
2052
|
const state = JSON.parse(stateText);
|
|
2035
2053
|
currentStage = state.currentStage;
|
|
2036
2054
|
} catch (error) {
|
|
2037
|
-
if (!
|
|
2055
|
+
if (!isMissingFileError6(error)) throw error;
|
|
2038
2056
|
return { allowed: true, reason: "state.json \u4E0D\u5B58\u5728\uFF0C\u653E\u884C", file: relative };
|
|
2039
2057
|
}
|
|
2040
2058
|
if (!currentStage || resolvedActiveTaskId !== taskId) {
|
|
@@ -2056,7 +2074,7 @@ async function readActiveTaskId(workDir) {
|
|
|
2056
2074
|
const text = await readFile6(path7.join(workDir, ".harness", "active-task.txt"), "utf8");
|
|
2057
2075
|
return text.trim() || void 0;
|
|
2058
2076
|
} catch (error) {
|
|
2059
|
-
if (
|
|
2077
|
+
if (isMissingFileError6(error)) return void 0;
|
|
2060
2078
|
throw error;
|
|
2061
2079
|
}
|
|
2062
2080
|
}
|
|
@@ -2291,7 +2309,7 @@ function runScopeCheck(contract, changedFiles) {
|
|
|
2291
2309
|
};
|
|
2292
2310
|
}
|
|
2293
2311
|
var execAsync = promisify(exec);
|
|
2294
|
-
function
|
|
2312
|
+
function isMissingFileError7(error) {
|
|
2295
2313
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2296
2314
|
}
|
|
2297
2315
|
async function fileExists3(filePath) {
|
|
@@ -2299,7 +2317,7 @@ async function fileExists3(filePath) {
|
|
|
2299
2317
|
await access4(filePath);
|
|
2300
2318
|
return true;
|
|
2301
2319
|
} catch (error) {
|
|
2302
|
-
if (
|
|
2320
|
+
if (isMissingFileError7(error)) return false;
|
|
2303
2321
|
throw error;
|
|
2304
2322
|
}
|
|
2305
2323
|
}
|
|
@@ -2568,7 +2586,7 @@ function getTaskEvidenceDir(taskDir) {
|
|
|
2568
2586
|
function getTaskEvidencePath(taskDir, kind) {
|
|
2569
2587
|
return path10.join(getTaskEvidenceDir(taskDir), `${kind}.json`);
|
|
2570
2588
|
}
|
|
2571
|
-
function
|
|
2589
|
+
function isMissingFileError8(error) {
|
|
2572
2590
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2573
2591
|
}
|
|
2574
2592
|
function buildEvidenceBaseline(evidence) {
|
|
@@ -2630,7 +2648,7 @@ async function loadEvidenceBaseline(workDir) {
|
|
|
2630
2648
|
try {
|
|
2631
2649
|
text = await readFile9(filePath, "utf8");
|
|
2632
2650
|
} catch (error) {
|
|
2633
|
-
if (
|
|
2651
|
+
if (isMissingFileError8(error)) return null;
|
|
2634
2652
|
throw error;
|
|
2635
2653
|
}
|
|
2636
2654
|
try {
|
|
@@ -3058,7 +3076,7 @@ function createTaskReport(ctx, adapter, evidence, commitGate) {
|
|
|
3058
3076
|
});
|
|
3059
3077
|
}
|
|
3060
3078
|
var execAsync5 = promisify5(exec5);
|
|
3061
|
-
function
|
|
3079
|
+
function isMissingFileError9(error) {
|
|
3062
3080
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
3063
3081
|
}
|
|
3064
3082
|
async function loadReviewAgentsConfig(workDir) {
|
|
@@ -3090,7 +3108,7 @@ async function loadReviewAgentsConfig(workDir) {
|
|
|
3090
3108
|
if (current?.name) agents.push(current);
|
|
3091
3109
|
return { review_agents: agents };
|
|
3092
3110
|
} catch (error) {
|
|
3093
|
-
if (
|
|
3111
|
+
if (isMissingFileError9(error)) return null;
|
|
3094
3112
|
throw error;
|
|
3095
3113
|
}
|
|
3096
3114
|
}
|
|
@@ -3164,7 +3182,7 @@ async function readActiveTaskId2(workDir) {
|
|
|
3164
3182
|
const text = await readFile10(getHarnessPaths(workDir).activeTaskFile, "utf8");
|
|
3165
3183
|
return text.trim() || void 0;
|
|
3166
3184
|
} catch (error) {
|
|
3167
|
-
if (
|
|
3185
|
+
if (isMissingFileError9(error)) return void 0;
|
|
3168
3186
|
throw error;
|
|
3169
3187
|
}
|
|
3170
3188
|
}
|
|
@@ -3190,7 +3208,7 @@ function renderResidentReviewFromFindings(findings, trigger, agentsSpawned) {
|
|
|
3190
3208
|
}
|
|
3191
3209
|
async function renderResidentReview(workDir, findings) {
|
|
3192
3210
|
const configText = await readFile10(getHarnessPaths(workDir).reviewAgentsFile, "utf8").catch(
|
|
3193
|
-
(error) =>
|
|
3211
|
+
(error) => isMissingFileError9(error) ? null : Promise.reject(error)
|
|
3194
3212
|
);
|
|
3195
3213
|
const active = Boolean(configText?.includes("review_agents:"));
|
|
3196
3214
|
const failed = findings.filter((finding) => finding.status === "failed");
|
|
@@ -3266,7 +3284,7 @@ function runReviewStage(changedFiles) {
|
|
|
3266
3284
|
}
|
|
3267
3285
|
return findings;
|
|
3268
3286
|
}
|
|
3269
|
-
function
|
|
3287
|
+
function isMissingFileError10(error) {
|
|
3270
3288
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
3271
3289
|
}
|
|
3272
3290
|
function parseStructureRules(text) {
|
|
@@ -3303,7 +3321,7 @@ async function runStructureCheck(workDir, changedFiles) {
|
|
|
3303
3321
|
try {
|
|
3304
3322
|
text = await readFile11(rulesPath, "utf8");
|
|
3305
3323
|
} catch (error) {
|
|
3306
|
-
if (
|
|
3324
|
+
if (isMissingFileError10(error)) {
|
|
3307
3325
|
return [
|
|
3308
3326
|
{
|
|
3309
3327
|
name: "structure.rules",
|
|
@@ -5156,7 +5174,7 @@ import { appendFile as appendFile3, mkdir as mkdir12, readFile as readFile14, wr
|
|
|
5156
5174
|
import path18 from "path";
|
|
5157
5175
|
var FEEDBACK_FILENAME = "intake-feedback.jsonl";
|
|
5158
5176
|
var LAST_DECISION_FILENAME = "intake-last.json";
|
|
5159
|
-
function
|
|
5177
|
+
function isMissingFileError11(error) {
|
|
5160
5178
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
5161
5179
|
}
|
|
5162
5180
|
function normalizePromptForFeedback(prompt) {
|
|
@@ -5182,7 +5200,7 @@ async function readLastIntakeDecision(workDir) {
|
|
|
5182
5200
|
try {
|
|
5183
5201
|
return JSON.parse(await readFile14(getLastIntakeDecisionPath(workDir), "utf8"));
|
|
5184
5202
|
} catch (error) {
|
|
5185
|
-
if (
|
|
5203
|
+
if (isMissingFileError11(error)) return null;
|
|
5186
5204
|
return null;
|
|
5187
5205
|
}
|
|
5188
5206
|
}
|
|
@@ -5219,7 +5237,7 @@ async function loadIntakeFeedback(workDir) {
|
|
|
5219
5237
|
}
|
|
5220
5238
|
return entries;
|
|
5221
5239
|
} catch (error) {
|
|
5222
|
-
if (
|
|
5240
|
+
if (isMissingFileError11(error)) return [];
|
|
5223
5241
|
throw error;
|
|
5224
5242
|
}
|
|
5225
5243
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brawnen/harnessly",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"harnessly": "dist/index.js"
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@brawnen/harnessly-core": "0.1.0-alpha.0",
|
|
29
|
-
"@brawnen/harnessly-host-
|
|
29
|
+
"@brawnen/harnessly-host-codex": "0.1.0-alpha.0",
|
|
30
30
|
"@brawnen/harnessly-host-shared": "0.1.0-alpha.0",
|
|
31
|
-
"@brawnen/harnessly-
|
|
32
|
-
"@brawnen/harnessly-
|
|
31
|
+
"@brawnen/harnessly-host-claude-code": "0.1.0-alpha.0",
|
|
32
|
+
"@brawnen/harnessly-shared": "0.1.0-alpha.0"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsup",
|