harnessed 4.2.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 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: ~70 entries, 7 categories SoT
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, ~83 entries)
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, readFileSync9 = (p5) => readFileSync(p5, "utf8")) {
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 = readFileSync9(path);
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.2.0"};
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((resolve17, reject) => {
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
- resolve17(1);
4301
+ resolve18(1);
4270
4302
  } else {
4271
4303
  reject(err2);
4272
4304
  }
4273
4305
  });
4274
- child.on("close", (code) => resolve17(code ?? 0));
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
- if (result.missing.length > 0 && !opts.force) {
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 ${result.missing.length} declared artifact(s) missing (evidence guard, fail-closed):`
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 result.missing) console.error(` - ${m}`);
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 (result.missing.length > 0 && opts.force) evidenceStatus = "overridden";
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((resolve17) => {
5210
+ return await new Promise((resolve18) => {
5176
5211
  const timer = setTimeout(() => {
5177
5212
  child.kill("SIGKILL");
5178
- resolve17({
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
- resolve17({
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
- resolve17({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
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((resolve17) => {
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
- resolve17({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
5365
+ resolve18({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
5331
5366
  }, timeoutMs);
5332
5367
  child.on("error", (e) => {
5333
5368
  clearTimeout(timer);
5334
- resolve17({ exitCode: -1, stderr: `${stderr}${e.message}` });
5369
+ resolve18({ exitCode: -1, stderr: `${stderr}${e.message}` });
5335
5370
  });
5336
5371
  child.on("close", (code) => {
5337
5372
  clearTimeout(timer);
5338
- resolve17({ exitCode: code ?? -1, stderr });
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((resolve17) => {
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
- resolve17({ sha: "", exit: -1 });
5528
+ resolve18({ sha: "", exit: -1 });
5494
5529
  }, timeoutMs);
5495
5530
  child.on("error", () => {
5496
5531
  clearTimeout(timer);
5497
- resolve17({ sha: "", exit: -1 });
5532
+ resolve18({ sha: "", exit: -1 });
5498
5533
  });
5499
5534
  child.on("close", (code) => {
5500
5535
  clearTimeout(timer);
5501
- resolve17({ sha: stdout2.trim(), exit: code ?? -1 });
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((resolve17) => {
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
- resolve17({ exitCode: -1, stderr: `${stderr}[timeout]` });
7712
+ resolve18({ exitCode: -1, stderr: `${stderr}[timeout]` });
7678
7713
  }, 3e4);
7679
7714
  child.on("error", (e) => {
7680
7715
  clearTimeout(timer);
7681
- resolve17({ exitCode: -1, stderr: e.message });
7716
+ resolve18({ exitCode: -1, stderr: e.message });
7682
7717
  });
7683
7718
  child.on("close", (code) => {
7684
7719
  clearTimeout(timer);
7685
- resolve17({ exitCode: code ?? -1, stderr });
7720
+ resolve18({ exitCode: code ?? -1, stderr });
7686
7721
  });
7687
7722
  });
7688
7723
  if (result.exitCode !== 0) {