harnessed 3.2.0 → 3.3.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
@@ -344,6 +344,42 @@ planning-with-files /plan (cross-cutting tool) → write artifacts to .planning/
344
344
 
345
345
  ---
346
346
 
347
+ ## 🛠️ 维护命令 (Operational)
348
+
349
+ > 这些是 harnessed 自身维护命令(setup / 健康检查 / 备份回滚 / 状态恢复等),日常 feature 开发用上面的 slash command 即可,这块通常不需要。
350
+
351
+ ### CLI 命令
352
+
353
+ | 命令 | 说明 |
354
+ | ---- | ---- |
355
+ | `harnessed setup` | 一次性 setup,装 workflow skills 到 `~/.claude/skills/` + MCP 到 `~/.claude.json` |
356
+ | `harnessed resume` | session 中断后恢复至最近 checkpoint |
357
+ | `harnessed status` | 当前 phase + lock holder |
358
+ | `harnessed doctor` | 8-check 健康检查 (Node / MCP / jq / Win bash / 路由 / token budget 等) |
359
+ | `harnessed install <name>` | 装上游 manifest |
360
+ | `harnessed uninstall <name>` | 反向卸载 |
361
+ | `harnessed backup` | snapshot 备份管理 |
362
+ | `harnessed rollback <timestamp>` | 一行回滚 (EOL preserve + sha1 verify) |
363
+ | `harnessed gc` | 清理过期 backups |
364
+ | `harnessed audit-log` | 路由透明日志 query (支持 `--filter` jq 表达式) |
365
+
366
+ ### 参数 (Flags)
367
+
368
+ > 所有命令默认 **apply (immediate write)**,无需加 flag。高级用户可加 `--dry-run` 预览。
369
+
370
+ | Flag | 说明 |
371
+ | ---- | ---- |
372
+ | `--dry-run` | 预览不写盘 (高级用户 opt-in) |
373
+ | `--non-interactive` | CI / 脚本场景 |
374
+ | `--system` | L4 全局装允许 (否则降级 L1 npx ephemeral) |
375
+ | `--yes` | uninstall 跳过交互 confirm |
376
+ | `--full-diff` | 展开 > 200 行的 diff 折叠 |
377
+ | `--no-color` | 强制 nocolor (即使 TTY) |
378
+
379
+ > `--apply` flag 仍保留为向后兼容 alias (no-op, 旧脚本不破)。
380
+
381
+ ---
382
+
347
383
  ## ❓ FAQ
348
384
 
349
385
  <details>
@@ -423,41 +459,6 @@ harnessed setup --apply # 自动装齐 gstack + GSD + superpowers + planning-wi
423
459
 
424
460
  ---
425
461
 
426
- ## 🛠️ 维护命令 (Operational)
427
-
428
- > 这些是 harnessed 自身维护命令(setup / 健康检查 / 备份回滚 / 状态恢复等),日常 feature 开发用上面的 slash command 即可,这块通常不需要。
429
-
430
- ### CLI 命令
431
-
432
- | 命令 | 说明 |
433
- | ---- | ---- |
434
- | `harnessed setup` | 一次性 setup,装 workflow skills 到 `~/.claude/skills/` + MCP 到 `~/.claude.json` |
435
- | `harnessed resume` | session 中断后恢复至最近 checkpoint |
436
- | `harnessed status` | 当前 phase + lock holder |
437
- | `harnessed doctor` | 8-check 健康检查 (Node / MCP / jq / Win bash / 路由 / token budget 等) |
438
- | `harnessed install <name>` | 装上游 manifest |
439
- | `harnessed uninstall <name>` | 反向卸载 |
440
- | `harnessed backup` | snapshot 备份管理 |
441
- | `harnessed rollback <timestamp>` | 一行回滚 (EOL preserve + sha1 verify) |
442
- | `harnessed gc` | 清理过期 backups |
443
- | `harnessed audit-log` | 路由透明日志 query (支持 `--filter` jq 表达式) |
444
-
445
- ### 参数 (Flags)
446
-
447
- > 所有命令默认 **apply (immediate write)**,无需加 flag。高级用户可加 `--dry-run` 预览。
448
-
449
- | Flag | 说明 |
450
- | ---- | ---- |
451
- | `--dry-run` | 预览不写盘 (高级用户 opt-in) |
452
- | `--non-interactive` | CI / 脚本场景 |
453
- | `--system` | L4 全局装允许 (否则降级 L1 npx ephemeral) |
454
- | `--yes` | uninstall 跳过交互 confirm |
455
- | `--full-diff` | 展开 > 200 行的 diff 折叠 |
456
- | `--no-color` | 强制 nocolor (即使 TTY) |
457
-
458
- > `--apply` flag 仍保留为向后兼容 alias (no-op, 旧脚本不破)。
459
-
460
- ---
461
462
 
462
463
  ## License
463
464
 
package/dist/cli.mjs CHANGED
@@ -847,7 +847,7 @@ var init_resume = __esm({
847
847
 
848
848
  // package.json
849
849
  var package_default = {
850
- version: "3.2.0"};
850
+ version: "3.3.0"};
851
851
 
852
852
  // src/manifest/errors.ts
853
853
  function instancePathToKeyPath(instancePath) {
@@ -2999,26 +2999,11 @@ function loadPhases(yamlPath, vars) {
2999
2999
  return validated;
3000
3000
  }
3001
3001
 
3002
- // src/cli/lib/validateFlags.ts
3003
- function validateNonInteractiveFlags(raw, cmdName) {
3004
- if (raw.nonInteractive && !raw.apply && !raw.dryRun) {
3005
- console.error(
3006
- `error: --non-interactive requires --apply or --dry-run
3007
- fix: 'harnessed ${cmdName} --non-interactive --dry-run' or '--apply'`
3008
- );
3009
- process.exit(2);
3010
- }
3011
- }
3012
-
3013
3002
  // src/cli/execute-task.ts
3014
3003
  function registerExecuteTask(program2) {
3015
3004
  program2.command("execute-task").description(
3016
3005
  "Run execute-task workflow (4-phase chain \u2192 ralph-loop COMPLETE; immediate by default \u2014 use --dry-run for preview)"
3017
- ).requiredOption("--task <text>", "task description (required)").option("--workflow <name>", "workflow name", "execute-task").option(
3018
- "--apply",
3019
- "(deprecated; kept for backward compat \u2014 execute-task spawns immediately by default)"
3020
- ).option("--dry-run", "preview only \u2014 do not spawn subagent (opt-in for advanced users)").option("--non-interactive", "CI / scripts \u2014 requires --apply or --dry-run").option("--model <model>", "subagent model: 'haiku' | 'sonnet' | 'opus'").option("--model-tier <tier>", "override: 'inherit' bypasses per-phase phase.model (B-10)").option("--max-iterations <n>", "ralph-loop max iter (default 20)", (v) => parseInt(v, 10)).action(async (raw) => {
3021
- validateNonInteractiveFlags(raw, "execute-task --task <text>");
3006
+ ).requiredOption("--task <text>", "task description (required)").option("--workflow <name>", "workflow name", "execute-task").option("--dry-run", "preview only \u2014 do not spawn subagent (opt-in for advanced users)").option("--non-interactive", "CI / scripts").option("--model <model>", "subagent model: 'haiku' | 'sonnet' | 'opus'").option("--model-tier <tier>", "override: 'inherit' bypasses per-phase phase.model (B-10)").option("--max-iterations <n>", "ralph-loop max iter (default 20)", (v) => parseInt(v, 10)).action(async (raw) => {
3022
3007
  if (!raw.task) {
3023
3008
  console.error("error: --task <text> is required");
3024
3009
  process.exit(2);
@@ -3065,7 +3050,7 @@ function registerExecuteTask(program2) {
3065
3050
  packageRoot: process.cwd(),
3066
3051
  cmdType: "git-commit",
3067
3052
  hasUserApproval: true
3068
- // --apply explicit
3053
+ // apply-immediate default
3069
3054
  });
3070
3055
  } catch (err2) {
3071
3056
  console.warn(
@@ -3120,7 +3105,7 @@ async function dirSizeKb(dir) {
3120
3105
  function registerGc(program2) {
3121
3106
  program2.command("gc").description(
3122
3107
  "Garbage-collect old backup snapshots (immediate by default \u2014 use --dry-run for preview)"
3123
- ).option("--older-than <duration>", "delete snapshots older than (e.g. 30d / 24h / 4w)", "30d").option("--keep-last <N>", "always keep the most recent N snapshots", "0").option("--apply", "(deprecated; kept for backward compat \u2014 gc deletes immediately by default)").option("--dry-run", "preview only \u2014 do not delete (opt-in for advanced users)").action(async (opts) => {
3108
+ ).option("--older-than <duration>", "delete snapshots older than (e.g. 30d / 24h / 4w)", "30d").option("--keep-last <N>", "always keep the most recent N snapshots", "0").option("--dry-run", "preview only \u2014 do not delete (opt-in for advanced users)").action(async (opts) => {
3124
3109
  const dryRun = opts.dryRun === true;
3125
3110
  const olderMs = parseDuration(opts.olderThan ?? "30d");
3126
3111
  if (olderMs == null) {
@@ -4475,11 +4460,10 @@ function formatError(e) {
4475
4460
  return `${head}${where}${tip}`;
4476
4461
  }
4477
4462
  function registerInstall(program2) {
4478
- program2.command("install <name>").description("Install an upstream (immediate by default \u2014 use --dry-run for preview)").option("--apply", "(deprecated; kept for backward compat \u2014 install is immediate by default)").option("--dry-run", "preview only \u2014 do not write to disk (opt-in for advanced users)").option("--system", "allow L4 system-wide install (e.g. global npm install)").option("--non-interactive", "skip all prompts (CI / scripts) \u2014 requires --apply or --dry-run").option("--full-diff", "expand diffs longer than 200 lines").option("--no-color", "disable ANSI colors (auto-detected when piped)").option(
4463
+ program2.command("install <name>").description("Install an upstream (immediate by default \u2014 use --dry-run for preview)").option("--dry-run", "preview only \u2014 do not write to disk (opt-in for advanced users)").option("--system", "allow L4 system-wide install (e.g. global npm install)").option("--non-interactive", "skip all prompts (CI / scripts)").option("--full-diff", "expand diffs longer than 200 lines").option("--no-color", "disable ANSI colors (auto-detected when piped)").option(
4479
4464
  "--known-good",
4480
4465
  "use known-good version lock from versions/<harnessed-ver>-known-good.yaml"
4481
4466
  ).action(async (name, raw) => {
4482
- validateNonInteractiveFlags(raw, "install <name>");
4483
4467
  const { resolveAlias: resolveAlias2 } = await Promise.resolve().then(() => (init_aliases(), aliases_exports));
4484
4468
  const resolvedName = resolveAlias2(name) ?? name;
4485
4469
  checkPathSafe(resolvedName);
@@ -4558,11 +4542,7 @@ async function listBaseManifests(cwd) {
4558
4542
  function registerInstallBase(program2) {
4559
4543
  program2.command("install-base").description(
4560
4544
  "Install the phase 1.3 base profile (immediate by default \u2014 use --dry-run for preview)"
4561
- ).option(
4562
- "--apply",
4563
- "(deprecated; kept for backward compat \u2014 install-base is immediate by default)"
4564
- ).option("--dry-run", "preview only \u2014 do not write to disk (opt-in for advanced users)").option("--non-interactive", "skip all prompts (CI / scripts) \u2014 requires --apply or --dry-run").action(async (raw) => {
4565
- validateNonInteractiveFlags(raw, "install-base");
4545
+ ).option("--dry-run", "preview only \u2014 do not write to disk (opt-in for advanced users)").option("--non-interactive", "skip all prompts (CI / scripts)").action(async (raw) => {
4566
4546
  const dryRun = raw.dryRun === true;
4567
4547
  const opts = {
4568
4548
  apply: !dryRun,
@@ -4628,11 +4608,7 @@ function basename(upstream) {
4628
4608
  function registerManifestAdd(program2) {
4629
4609
  program2.command("manifest-add <upstream>").description(
4630
4610
  "Add a new upstream adapter (EE-5 5-question merge gate; immediate by default \u2014 use --dry-run for preview)"
4631
- ).option("--category <cat>", "manifest category (skill-packs | tools)", "skill-packs").option("--name <name>", "short adapter name (defaults to <upstream> basename)").option(
4632
- "--apply",
4633
- "(deprecated; kept for backward compat \u2014 manifest-add persists immediately by default)"
4634
- ).option("--dry-run", "preview only \u2014 do not write JSON (opt-in for advanced users)").option("--non-interactive", "CI/scripts \u2014 requires --apply or --dry-run; WARN-only dry-run").action(async (upstream, raw) => {
4635
- validateNonInteractiveFlags(raw, "manifest-add <upstream>");
4611
+ ).option("--category <cat>", "manifest category (skill-packs | tools)", "skill-packs").option("--name <name>", "short adapter name (defaults to <upstream> basename)").option("--dry-run", "preview only \u2014 do not write JSON (opt-in for advanced users)").option("--non-interactive", "CI/scripts \u2014 WARN-only dry-run").action(async (upstream, raw) => {
4636
4612
  const name = raw.name ?? basename(upstream);
4637
4613
  const category = raw.category ?? "skill-packs";
4638
4614
  const outPath = `manifests/${category}/${name}.ee5-answers.json`;
@@ -4677,11 +4653,7 @@ function registerManifestAdd(program2) {
4677
4653
  function registerResearch(program2) {
4678
4654
  program2.command("research").description(
4679
4655
  "Run research workflow (search category sub-routing \u2192 spawn \u2192 verbatim COMPLETE; immediate by default \u2014 use --dry-run for preview)"
4680
- ).requiredOption("--query <text>", "research prompt (required)").option(
4681
- "--apply",
4682
- "(deprecated; kept for backward compat \u2014 research spawns immediately by default)"
4683
- ).option("--dry-run", "preview only \u2014 do not spawn subagent (opt-in for advanced users)").option("--non-interactive", "skip all prompts (CI / scripts) \u2014 requires --apply or --dry-run").option("--model <model>", "subagent model: 'haiku' | 'sonnet' | 'opus'").action(async (raw) => {
4684
- validateNonInteractiveFlags(raw, "research --query <text>");
4656
+ ).requiredOption("--query <text>", "research prompt (required)").option("--dry-run", "preview only \u2014 do not spawn subagent (opt-in for advanced users)").option("--non-interactive", "skip all prompts (CI / scripts)").option("--model <model>", "subagent model: 'haiku' | 'sonnet' | 'opus'").action(async (raw) => {
4685
4657
  if (!raw.query) {
4686
4658
  console.error("error: --query <text> is required");
4687
4659
  process.exit(2);
@@ -4720,7 +4692,7 @@ function registerResearch(program2) {
4720
4692
  if ("ok" in result && result.ok === false) {
4721
4693
  console.error(`error: ${result.phase} \u2014 ${result.error.message}`);
4722
4694
  if (result.phase === "install") {
4723
- console.error(` fix: 'harnessed install <skill> --apply' (see error above)`);
4695
+ console.error(` fix: 'harnessed install <skill>' (see error above)`);
4724
4696
  }
4725
4697
  process.exit(1);
4726
4698
  }
@@ -5355,7 +5327,7 @@ async function runUninstall(manifest, opts) {
5355
5327
 
5356
5328
  // src/cli/uninstall.ts
5357
5329
  function registerUninstall(program2) {
5358
- program2.command("uninstall <name>").description("Uninstall an upstream (immediate by default \u2014 use --dry-run for preview)").option("--apply", "(deprecated; kept for backward compat \u2014 uninstall is immediate by default)").option("--dry-run", "preview only \u2014 do not delete files (opt-in for advanced users)").option("--yes", "skip interactive confirm (CI / scripts) \u2014 fatal with --dry-run").option("--non-interactive", "alias for --yes (CI compat)").action(async (name, raw) => {
5330
+ program2.command("uninstall <name>").description("Uninstall an upstream (immediate by default \u2014 use --dry-run for preview)").option("--dry-run", "preview only \u2014 do not delete files (opt-in for advanced users)").option("--yes", "skip interactive confirm (CI / scripts) \u2014 fatal with --dry-run").option("--non-interactive", "alias for --yes (CI compat)").action(async (name, raw) => {
5359
5331
  const yes = raw.yes === true || raw.nonInteractive === true;
5360
5332
  if (yes && raw.dryRun) {
5361
5333
  console.error(