harnessed 4.3.0 → 4.4.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/README.md +2 -2
- package/dist/cli.mjs +62 -27
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/workflows/capabilities.yaml +8 -0
- package/workflows/disciplines/doc-discipline.yaml +49 -0
package/README.md
CHANGED
|
@@ -234,7 +234,7 @@ harnessed/
|
|
|
234
234
|
│ ├── verify/ # Stage ④ (progress + code-review + paranoid + qa + cso + design + simplify + multispec)
|
|
235
235
|
│ ├── research/ # standalone Stage ① alternate
|
|
236
236
|
│ ├── retro/ # standalone post-④ milestone close
|
|
237
|
-
│ ├── capabilities.yaml # L5a: ~
|
|
237
|
+
│ ├── capabilities.yaml # L5a: ~100 entries, 7 categories SoT
|
|
238
238
|
│ ├── defaults.yaml # ralph_max_iterations per workflow phase
|
|
239
239
|
│ ├── judgments/ # L5a: three-layer-stack criteria + parallelism + tdd + fallback + rules-routing
|
|
240
240
|
│ │ ├── strategic-gate.yaml
|
|
@@ -296,7 +296,7 @@ harnessed/
|
|
|
296
296
|
└────────────────────────────────────────────────────────────┘
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
-
### 3. Cross-cutting Capabilities (capabilities.yaml — 7 categories, ~
|
|
299
|
+
### 3. Cross-cutting Capabilities (capabilities.yaml — 7 categories, ~100 entries)
|
|
300
300
|
|
|
301
301
|
```
|
|
302
302
|
behavioral (6): karpathy-guidelines + output-style + language + operational + priority + protocols
|
package/dist/cli.mjs
CHANGED
|
@@ -1037,7 +1037,7 @@ function nameToYamlHintPath(name) {
|
|
|
1037
1037
|
function shouldOverwriteFile(content) {
|
|
1038
1038
|
return HARNESSED_MARKER_RX.test(content) || V3_4_3_SIGNATURE_SUB_RX.test(content) || V3_4_3_SIGNATURE_MASTER_RX.test(content);
|
|
1039
1039
|
}
|
|
1040
|
-
async function writeAllCommands(slashNames, commandsDir, rolePrompts, capabilities, installedPlugins, installedUserSkills, writer, fileExists2 = existsSync,
|
|
1040
|
+
async function writeAllCommands(slashNames, commandsDir, rolePrompts, capabilities, installedPlugins, installedUserSkills, writer, fileExists2 = existsSync, readFileSync10 = (p5) => readFileSync(p5, "utf8")) {
|
|
1041
1041
|
const results = [];
|
|
1042
1042
|
const aggregatedWarnings = /* @__PURE__ */ new Set();
|
|
1043
1043
|
for (const name of slashNames) {
|
|
@@ -1056,7 +1056,7 @@ async function writeAllCommands(slashNames, commandsDir, rolePrompts, capabiliti
|
|
|
1056
1056
|
if (fileExists2(path)) {
|
|
1057
1057
|
let existing = "";
|
|
1058
1058
|
try {
|
|
1059
|
-
existing =
|
|
1059
|
+
existing = readFileSync10(path);
|
|
1060
1060
|
} catch {
|
|
1061
1061
|
existing = "";
|
|
1062
1062
|
}
|
|
@@ -1208,7 +1208,8 @@ var init_disciplineLoader = __esm({
|
|
|
1208
1208
|
"language",
|
|
1209
1209
|
"operational",
|
|
1210
1210
|
"priority",
|
|
1211
|
-
"protocols"
|
|
1211
|
+
"protocols",
|
|
1212
|
+
"doc-discipline"
|
|
1212
1213
|
];
|
|
1213
1214
|
_cache = /* @__PURE__ */ new Map();
|
|
1214
1215
|
}
|
|
@@ -1256,6 +1257,27 @@ async function runBeforeCommitHook(ctx) {
|
|
|
1256
1257
|
console.error("\u274C no-skip-hooks violated: --no-verify forbidden");
|
|
1257
1258
|
process.exit(2);
|
|
1258
1259
|
}
|
|
1260
|
+
if (ctx.changedFiles.some((f) => f.includes(".planning/STATE.md"))) {
|
|
1261
|
+
const docD = await loadDiscipline("doc-discipline", ctx.packageRoot);
|
|
1262
|
+
const rule = docD.rules.find((r) => r.id === "state-digest-line-limit");
|
|
1263
|
+
if (rule?.enforcement === "halt") {
|
|
1264
|
+
if (process.env.HARNESSED_ALLOW_LONG_STATE) {
|
|
1265
|
+
console.warn(
|
|
1266
|
+
"\u26A0\uFE0F doc-discipline: state-digest-line-limit override active (HARNESSED_ALLOW_LONG_STATE)"
|
|
1267
|
+
);
|
|
1268
|
+
} else {
|
|
1269
|
+
const content = readFileSync(resolve(ctx.packageRoot, ".planning/STATE.md"), "utf8");
|
|
1270
|
+
const lines = content.split(/\r?\n/);
|
|
1271
|
+
const lineCount = lines[lines.length - 1] === "" ? lines.length - 1 : lines.length;
|
|
1272
|
+
if (lineCount > 100) {
|
|
1273
|
+
console.error(
|
|
1274
|
+
`\u274C doc-discipline: STATE.md exceeds 100-line digest limit (current: ${lineCount} lines). Set HARNESSED_ALLOW_LONG_STATE=1 to override.`
|
|
1275
|
+
);
|
|
1276
|
+
process.exit(2);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1259
1281
|
}
|
|
1260
1282
|
var TS_JS_RE;
|
|
1261
1283
|
var init_before_commit = __esm({
|
|
@@ -2541,6 +2563,7 @@ var init_run2 = __esm({
|
|
|
2541
2563
|
var evidence_exports = {};
|
|
2542
2564
|
__export(evidence_exports, {
|
|
2543
2565
|
checkArtifacts: () => checkArtifacts,
|
|
2566
|
+
checkPlanningSync: () => checkPlanningSync,
|
|
2544
2567
|
detectDrift: () => detectDrift,
|
|
2545
2568
|
hashFile: () => hashFile
|
|
2546
2569
|
});
|
|
@@ -2577,6 +2600,15 @@ async function checkArtifacts(sub, packageRoot) {
|
|
|
2577
2600
|
}
|
|
2578
2601
|
return { status: missing.length === 0 ? "verified" : "missing", found, missing };
|
|
2579
2602
|
}
|
|
2603
|
+
async function checkPlanningSync(cwd, _workflowState) {
|
|
2604
|
+
const planningDir = resolve(cwd, ".planning");
|
|
2605
|
+
const hasPlanningDir = await stat(planningDir).then((s) => s.isDirectory()).catch(() => false);
|
|
2606
|
+
if (!hasPlanningDir) return { status: "none_declared", missing: [] };
|
|
2607
|
+
const stateFile = resolve(cwd, ".planning", "STATE.md");
|
|
2608
|
+
const hasStateFile = await stat(stateFile).then((s) => s.isFile()).catch(() => false);
|
|
2609
|
+
if (!hasStateFile) return { status: "missing", missing: [".planning/STATE.md"] };
|
|
2610
|
+
return { status: "verified", missing: [] };
|
|
2611
|
+
}
|
|
2580
2612
|
async function detectDrift(evidence) {
|
|
2581
2613
|
const drift = [];
|
|
2582
2614
|
for (const ref of evidence) {
|
|
@@ -3406,7 +3438,7 @@ var init_auto_install = __esm({
|
|
|
3406
3438
|
|
|
3407
3439
|
// package.json
|
|
3408
3440
|
var package_default = {
|
|
3409
|
-
version: "4.
|
|
3441
|
+
version: "4.4.0"};
|
|
3410
3442
|
|
|
3411
3443
|
// src/manifest/errors.ts
|
|
3412
3444
|
function instancePathToKeyPath(instancePath) {
|
|
@@ -4257,7 +4289,7 @@ function renderHumanTable(records) {
|
|
|
4257
4289
|
}
|
|
4258
4290
|
}
|
|
4259
4291
|
function pipeToJq(filterExpr, lines) {
|
|
4260
|
-
return new Promise((
|
|
4292
|
+
return new Promise((resolve18, reject) => {
|
|
4261
4293
|
const child = spawn("jq", [filterExpr], {
|
|
4262
4294
|
stdio: ["pipe", "inherit", "inherit"],
|
|
4263
4295
|
windowsHide: true
|
|
@@ -4266,12 +4298,12 @@ function pipeToJq(filterExpr, lines) {
|
|
|
4266
4298
|
const e = err2;
|
|
4267
4299
|
if (e.code === "ENOENT") {
|
|
4268
4300
|
console.error(t("audit_log.jq_missing"));
|
|
4269
|
-
|
|
4301
|
+
resolve18(1);
|
|
4270
4302
|
} else {
|
|
4271
4303
|
reject(err2);
|
|
4272
4304
|
}
|
|
4273
4305
|
});
|
|
4274
|
-
child.on("close", (code) =>
|
|
4306
|
+
child.on("close", (code) => resolve18(code ?? 0));
|
|
4275
4307
|
child.stdin.write(lines.join("\n"));
|
|
4276
4308
|
child.stdin.end();
|
|
4277
4309
|
});
|
|
@@ -4549,11 +4581,14 @@ function registerCheckpoint(program2) {
|
|
|
4549
4581
|
const { mutateSubProgress: mutateSubProgress3 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
4550
4582
|
const { getPackageRoot: getPackageRoot2 } = await Promise.resolve().then(() => (init_packagePath(), packagePath_exports));
|
|
4551
4583
|
const result = await checkArtifacts2(sub, getPackageRoot2());
|
|
4552
|
-
|
|
4584
|
+
const { checkPlanningSync: checkPlanningSync2 } = await Promise.resolve().then(() => (init_evidence(), evidence_exports));
|
|
4585
|
+
const syncResult = await checkPlanningSync2(process.cwd(), null);
|
|
4586
|
+
const allMissing = [...result.missing, ...syncResult.missing];
|
|
4587
|
+
if (allMissing.length > 0 && !opts.force) {
|
|
4553
4588
|
console.error(
|
|
4554
|
-
`[harnessed] checkpoint complete BLOCKED: ${sub} \u2014 ${
|
|
4589
|
+
`[harnessed] checkpoint complete BLOCKED: ${sub} \u2014 ${allMissing.length} item(s) missing (evidence guard + .planning/ sync, fail-closed):`
|
|
4555
4590
|
);
|
|
4556
|
-
for (const m of
|
|
4591
|
+
for (const m of allMissing) console.error(` - ${m}`);
|
|
4557
4592
|
console.error(
|
|
4558
4593
|
" (re-run with --force to override and record evidence_status=overridden)"
|
|
4559
4594
|
);
|
|
@@ -4561,7 +4596,7 @@ function registerCheckpoint(program2) {
|
|
|
4561
4596
|
return;
|
|
4562
4597
|
}
|
|
4563
4598
|
let evidenceStatus;
|
|
4564
|
-
if (
|
|
4599
|
+
if (allMissing.length > 0 && opts.force) evidenceStatus = "overridden";
|
|
4565
4600
|
else if (result.status === "verified") evidenceStatus = "verified";
|
|
4566
4601
|
else evidenceStatus = "none_declared";
|
|
4567
4602
|
const markOpts = evidenceStatus === "none_declared" ? { evidence_status: evidenceStatus } : { evidence: result.found, evidence_status: evidenceStatus };
|
|
@@ -5172,10 +5207,10 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
|
5172
5207
|
child.stderr?.setEncoding("utf8").on("data", (chunk) => {
|
|
5173
5208
|
stderr += chunk;
|
|
5174
5209
|
});
|
|
5175
|
-
return await new Promise((
|
|
5210
|
+
return await new Promise((resolve18) => {
|
|
5176
5211
|
const timer = setTimeout(() => {
|
|
5177
5212
|
child.kill("SIGKILL");
|
|
5178
|
-
|
|
5213
|
+
resolve18({
|
|
5179
5214
|
ok: false,
|
|
5180
5215
|
phase: "spawn",
|
|
5181
5216
|
error: {
|
|
@@ -5190,7 +5225,7 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
|
5190
5225
|
}, effectiveTimeoutMs);
|
|
5191
5226
|
child.on("error", (err2) => {
|
|
5192
5227
|
clearTimeout(timer);
|
|
5193
|
-
|
|
5228
|
+
resolve18({
|
|
5194
5229
|
ok: false,
|
|
5195
5230
|
phase: "spawn",
|
|
5196
5231
|
error: {
|
|
@@ -5205,7 +5240,7 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
|
5205
5240
|
});
|
|
5206
5241
|
child.on("close", (code) => {
|
|
5207
5242
|
clearTimeout(timer);
|
|
5208
|
-
|
|
5243
|
+
resolve18({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
|
|
5209
5244
|
});
|
|
5210
5245
|
});
|
|
5211
5246
|
}
|
|
@@ -5318,7 +5353,7 @@ async function isAlreadyInstalled(ctx, opts = {}) {
|
|
|
5318
5353
|
// src/installers/ccPluginMarketplace.ts
|
|
5319
5354
|
init_readClaudeConfig();
|
|
5320
5355
|
function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
|
|
5321
|
-
return new Promise((
|
|
5356
|
+
return new Promise((resolve18) => {
|
|
5322
5357
|
const isWin = process.platform === "win32";
|
|
5323
5358
|
const child = isWin ? spawn("cmd.exe", ["/c", "claude", ...claudeArgs], { cwd, windowsHide: true }) : spawn("claude", claudeArgs, { cwd, shell: false });
|
|
5324
5359
|
let stderr = "";
|
|
@@ -5327,15 +5362,15 @@ function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
|
|
|
5327
5362
|
});
|
|
5328
5363
|
const timer = setTimeout(() => {
|
|
5329
5364
|
child.kill("SIGKILL");
|
|
5330
|
-
|
|
5365
|
+
resolve18({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
|
|
5331
5366
|
}, timeoutMs);
|
|
5332
5367
|
child.on("error", (e) => {
|
|
5333
5368
|
clearTimeout(timer);
|
|
5334
|
-
|
|
5369
|
+
resolve18({ exitCode: -1, stderr: `${stderr}${e.message}` });
|
|
5335
5370
|
});
|
|
5336
5371
|
child.on("close", (code) => {
|
|
5337
5372
|
clearTimeout(timer);
|
|
5338
|
-
|
|
5373
|
+
resolve18({ exitCode: code ?? -1, stderr });
|
|
5339
5374
|
});
|
|
5340
5375
|
});
|
|
5341
5376
|
}
|
|
@@ -5481,7 +5516,7 @@ ${newEntry}
|
|
|
5481
5516
|
return { ok: true, backupId: bk.backupId, appliedFiles: [settingsFile] };
|
|
5482
5517
|
};
|
|
5483
5518
|
function gitRevParseHead(cwd, timeoutMs = 1e4) {
|
|
5484
|
-
return new Promise((
|
|
5519
|
+
return new Promise((resolve18) => {
|
|
5485
5520
|
const isWin = process.platform === "win32";
|
|
5486
5521
|
const child = isWin ? spawn("cmd.exe", ["/c", "git", "rev-parse", "HEAD"], { cwd, windowsHide: true }) : spawn("git", ["rev-parse", "HEAD"], { cwd, shell: false });
|
|
5487
5522
|
let stdout2 = "";
|
|
@@ -5490,15 +5525,15 @@ function gitRevParseHead(cwd, timeoutMs = 1e4) {
|
|
|
5490
5525
|
});
|
|
5491
5526
|
const timer = setTimeout(() => {
|
|
5492
5527
|
child.kill("SIGKILL");
|
|
5493
|
-
|
|
5528
|
+
resolve18({ sha: "", exit: -1 });
|
|
5494
5529
|
}, timeoutMs);
|
|
5495
5530
|
child.on("error", () => {
|
|
5496
5531
|
clearTimeout(timer);
|
|
5497
|
-
|
|
5532
|
+
resolve18({ sha: "", exit: -1 });
|
|
5498
5533
|
});
|
|
5499
5534
|
child.on("close", (code) => {
|
|
5500
5535
|
clearTimeout(timer);
|
|
5501
|
-
|
|
5536
|
+
resolve18({ sha: stdout2.trim(), exit: code ?? -1 });
|
|
5502
5537
|
});
|
|
5503
5538
|
});
|
|
5504
5539
|
}
|
|
@@ -7666,7 +7701,7 @@ var uninstallNpmCli = async (ctx) => {
|
|
|
7666
7701
|
const m = install.cmd.match(/npm\s+(?:install|i)\s+(?:-g\s+)?(\S+)/);
|
|
7667
7702
|
const pkg = m?.[1] ?? ctx.manifest.metadata.upstream.source;
|
|
7668
7703
|
const isWin = process.platform === "win32";
|
|
7669
|
-
const result = await new Promise((
|
|
7704
|
+
const result = await new Promise((resolve18) => {
|
|
7670
7705
|
const child = isWin ? spawn("cmd.exe", ["/c", "npm", "uninstall", "-g", pkg], { windowsHide: true }) : spawn("npm", ["uninstall", "-g", pkg], { shell: false });
|
|
7671
7706
|
let stderr = "";
|
|
7672
7707
|
child.stderr?.setEncoding("utf8").on("data", (c) => {
|
|
@@ -7674,15 +7709,15 @@ var uninstallNpmCli = async (ctx) => {
|
|
|
7674
7709
|
});
|
|
7675
7710
|
const timer = setTimeout(() => {
|
|
7676
7711
|
child.kill("SIGKILL");
|
|
7677
|
-
|
|
7712
|
+
resolve18({ exitCode: -1, stderr: `${stderr}[timeout]` });
|
|
7678
7713
|
}, 3e4);
|
|
7679
7714
|
child.on("error", (e) => {
|
|
7680
7715
|
clearTimeout(timer);
|
|
7681
|
-
|
|
7716
|
+
resolve18({ exitCode: -1, stderr: e.message });
|
|
7682
7717
|
});
|
|
7683
7718
|
child.on("close", (code) => {
|
|
7684
7719
|
clearTimeout(timer);
|
|
7685
|
-
|
|
7720
|
+
resolve18({ exitCode: code ?? -1, stderr });
|
|
7686
7721
|
});
|
|
7687
7722
|
});
|
|
7688
7723
|
if (result.exitCode !== 0) {
|