@dzhechkov/harness-cli 0.3.258 → 0.3.260

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/.dz-manifest.json CHANGED
@@ -9,7 +9,7 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "a38e5ef6a741aec138af0de7bd3616d4356d613ba1616bd8b5417194c1ee5f03"
12
+ "sha256": "6b3bcc252253732b9703f1eb43ac1f0e9f0599979b09d0fea3208932fd0f33a8"
13
13
  },
14
14
  {
15
15
  "path": "coverage/coverage-final.json",
@@ -41,15 +41,15 @@
41
41
  },
42
42
  {
43
43
  "path": "dist/cli.d.ts.map",
44
- "sha256": "f954d1e2e3d9f5941481a2b2ccbf553bab892dfa9ba1e7aefb4bf7d1800e9203"
44
+ "sha256": "4c5fa8c51cc350874413efceb0a2e4dce2f0c71f39914ddd8be425336a37ae2d"
45
45
  },
46
46
  {
47
47
  "path": "dist/cli.js",
48
- "sha256": "5fb105be335591fb20401a3b23bac9829777e7ba96c2a2480c29970f4ffa2774"
48
+ "sha256": "a75034dfe70f0b57811dfad831366bd5c7995583a57db0f218621b026ac8d854"
49
49
  },
50
50
  {
51
51
  "path": "dist/cli.js.map",
52
- "sha256": "a4be3aac6dadec03c1fc85fc5354d9a286ac0a21b4983349c4e511cae49dec79"
52
+ "sha256": "dbe8fa418aedcb77dead3a374bba7cbf0fb5e305dd9a06002946a19604279684"
53
53
  },
54
54
  {
55
55
  "path": "dist/index.d.ts",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  {
75
75
  "path": "package.json",
76
- "sha256": "b502ba368d29e25413ce35e8853bc5650c06f686202e51f997f67db0fac03224"
76
+ "sha256": "72858a1f0199832c7ad781f892b7b117ec980af33ff9598587e1ed1544046a35"
77
77
  },
78
78
  {
79
79
  "path": "src/bin.ts",
@@ -81,7 +81,7 @@
81
81
  },
82
82
  {
83
83
  "path": "src/cli.ts",
84
- "sha256": "a369561502f08d9dd4993a294adcb3a38349f543959fa8de31cd1580778062b0"
84
+ "sha256": "1481238a2fc3a60051f678dcf6b415f8052ce954a9e55ee7577d8c3b2261e062"
85
85
  },
86
86
  {
87
87
  "path": "src/index.ts",
@@ -89,7 +89,7 @@
89
89
  },
90
90
  {
91
91
  "path": "test/cli.test.ts",
92
- "sha256": "555aed692218a73f23a343df2f2b38ce028e694dd9d4aff37e727096f88eb50e"
92
+ "sha256": "24f2feb4c5c4fa939beb79cd658b03fbc7ce4bd87f15da563240abcb252c472c"
93
93
  },
94
94
  {
95
95
  "path": "test/epoch-replay-cli.test.ts",
@@ -109,5 +109,5 @@
109
109
  }
110
110
  ]
111
111
  },
112
- "signature": "CXaYCYQIKEVpAB29MZ5rG0/VUWtihZaeJh86r6x8uFpzKrgzHnrzmg/MmTUW3R/rqeA5w12hcfyfr4kl85ZxBA=="
112
+ "signature": "uYnxiEzDxjwdXlp1SGaC0Zv2x/MW39skbUKw3+xpvnLcoNsEV4pp8kFD5q7urBvC87fC+lRKsIpatoXCNGzwBA=="
113
113
  }
package/README.md CHANGED
@@ -132,7 +132,7 @@ point any tool at (a skill is just Markdown). Dedicated targets are on the [road
132
132
 
133
133
  ## User Journey — from install to mastery
134
134
 
135
- All 62 commands mapped to a real workflow:
135
+ All 63 commands mapped to a real workflow:
136
136
 
137
137
  ```
138
138
  DISCOVER → INSTALL → USE → CREATE → MAINTAIN → SHARE
@@ -604,6 +604,41 @@ ever enter a work order.
604
604
  **When to use:** after `dz compounding` reports the replay as READY; before claiming that recall
605
605
  "works"; and any time you want the claim re-checked as the corpus grows.
606
606
 
607
+ ### Пересмотр после аварийного само-ревью — `dz reqe`
608
+
609
+ The feature-adr pipeline's cross-model guard says *the model that writes code must not review it*.
610
+ Under limit pressure (usage-adaptive `>=70%` switch) that guard is CONSCIOUSLY suspended: coder AND
611
+ Step-8 QE both run on Codex (FR-2.9 — a Claude reviewer is exactly the agent that dies at the
612
+ limit). The rule used to say "re-review manually after limits reset" — an instruction nobody
613
+ remembers. `dz reqe` turns it into a **debt with a lifecycle**: the run records
614
+ `features/<slug>/.fa-state/reqe-due.json`, `dz usage` surfaces the count the moment you check your
615
+ freed-up limits, and settlement is FAIL-CLOSED.
616
+
617
+ ```bash
618
+ $ dz usage
619
+ usage: session ~12% (resets 03:00) · week ~41% (resets 06:00) · estimated
620
+ re-QE due: 1 usage-switched run(s) kept same-family QE — run `dz reqe` for the cross-family pass
621
+
622
+ $ dz reqe # the ledger
623
+ dz reqe — 1 unsettled re-QE debt(s):
624
+ add-x coder=openai qe=openai grade=B 2026-07-30T10:00:00Z → dz reqe --slug add-x
625
+
626
+ $ dz reqe --slug add-x # the ready cross-family review brief (the OTHER family than the coder)
627
+ $ dz reqe --slug add-x --done --report features/add-x/08b_reqe_report.md
628
+ dz reqe: debt settled: re-QE grade C (report …) — settlement appended to features/add-x/08_qe_report.md
629
+ ```
630
+
631
+ **When to use:** any time `dz usage` prints a `re-QE due` line, or a feature-adr result carried
632
+ `reqeDue: true`. **Fail-closed settlement:** the report must exist, be non-trivial, and name exactly
633
+ one line-anchored `GRADE` (the boilerplate phrase `GRADE A-F` does not count); the run's own
634
+ `08_qe_report.md` can never settle its own debt (real-path AND inode compared — a hard link doesn't
635
+ fool it); the settlement epilogue lands in `08_qe_report.md` and the due-file rotates to
636
+ `reqe-settled.json` (evidence kept, never deleted). **Honest scope** (printed by the command):
637
+ nothing re-runs QE automatically, and the validator proves the settlement is procedurally sound —
638
+ which model authored the report stays with the human running the brief. RU: гард «кодер не ревьюит
639
+ сам себя» осознанно снимается под лимитом; `dz reqe` превращает инструкцию «перепроверь потом»
640
+ в долг на диске — виден в `dz usage`, гасится только настоящим кросс-семейным отчётом с грейдом.
641
+
607
642
  ### Usage estimates you can act on — `dz usage`
608
643
 
609
644
  `dz usage` estimates how much of your Claude session (5h block) and week you have spent, from local
@@ -953,7 +988,7 @@ Get the whole set with `dz init --target claude-code --preset meta`, or pick one
953
988
 
954
989
  > **A skill and its npx toolkit are not duplicates — they're a graduation.** Several skills (e.g. `feature-adr`, `design-thinking`) exist BOTH as a skill inside a `dz` preset AND as a standalone `npx` package. The preset's SKILL.md is **fully functional on its own** (the whole methodology — modules + references — travels with it, and it auto-activates by description), and it's the only way to compile that capability to the **non-Claude platforms** (Codex/OpenCode/Hermes/OpenClaude) via `dz`. The npx package adds **project-level runtime governance** around the same skill: a slash command, governance rules, a context shard, and (for feature-adr) reward-learning + `/harvest`. So: pick the **skill/preset** for a working capability across platforms; pick the **npx toolkit** when you want it as a governed, command-driven fixture of one project.
955
990
 
956
- ## All Commands (62)
991
+ ## All Commands (63)
957
992
 
958
993
  ```
959
994
  dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force]
@@ -964,7 +999,7 @@ dz teach "<pattern>" [--reward <0-1>] [--domain <name>] [--type rule
964
999
  dz teach --reinforce "<dzId-or-exact-text>" [--project <dir>] # bump an existing learned pattern instead of writing a near-duplicate
965
1000
  dz teach --from-json <file> [--project <dir>] [--no-mirror] [--harmonize] # bulk-import a `dz recall --all --json` export; prints a harmonize dry-run advisory
966
1001
  dz consolidate [--sessions-dir <dir>] [--project <dir>] [--no-mirror]
967
- dz recall "<query>" [--limit <N>] [--semantic | --no-semantic] [--project <dir>] # hybrid lexical+vector when the vector tier is enabled
1002
+ dz recall "<query>" [--limit <N>] [--domain <name>] [--semantic | --no-semantic] [--project <dir>] # hybrid lexical+vector when the vector tier is enabled; --domain BOOSTS same-domain lessons (never filters)
968
1003
  dz recall --all [--json] [--stats] # export the WHOLE learned store, or inspect learning stats/top uses
969
1004
  dz recall --books "<query>" [--book <slug>] # digitized-book KUs; --book narrows to one book
970
1005
  dz vector status [--project <dir>] [--json] # semantic tier: engine availability, mirrored vs lexical counts, pending queue
@@ -1017,6 +1052,7 @@ dz epoch-replay --emit [--project <dir>] [--limit <N>] [--seed <N>] [--margin <
1017
1052
  dz epoch-replay --judge <filled-work-order.json> [--out <file>] [--json] # blind judge prompts from the filled plans — the file carries {id, prompt} ONLY (no assignment, no arm names); refuses an order whose digest or seed-derived assignment does not check out; half-pairs skipped WITH A REASON, on stdout
1018
1053
  dz epoch-replay --score <judgments.json> --work-order <file> [--slice <name>] [--json] # un-blind against the VERIFIED pre-registered assignment; ONE paired binomial over DECISIVE pairs (ties excluded, reported) → SUPPORTED only when the lift interval (2p−1) lies entirely above zero; FALSIFIED only on harm or a passed non-superiority test (lift upper bound below the margin PRE-REGISTERED in the work order, default 0.05, at 10+ decisive pairs); else INCONCLUSIVE (min 5 decisive pairs). Refuses a forged work order, a --margin flag, or duplicate judgement ids; the verdict is data, not an exit code
1019
1054
  dz score --slug <feature> [--project <dir>] [--json] # process scorecard for ONE feature-adr run, from its artifacts: ADR confirmation, discrimination proof, cross-model QE grade, live verification, README-first, learning loop, amendments — DESCRIPTIVE-ONLY (a low score exits 0); evidence lines are shown so the reader judges the heuristics
1055
+ dz reqe [--slug <feature> [--done --report <f>]] [--project <dir>] [--json] # the re-QE debt ledger: a usage-switched feature-adr run whose Step-8 QE ran on the coder's OWN family (cross-model guard suspended, FR-2.9) records a debt; list debts (also surfaced by dz usage), print the cross-family review brief, settle FAIL-CLOSED against an existing GRADED report (the run's own 08_qe_report.md — even hard-linked — can never settle its own debt); settlement lands in 08_qe_report.md, evidence rotates to reqe-settled.json
1020
1056
  dz backlog <sub> add "<idea>" | list | show <id> | goals [--validate] | roulette [--seed n] [--commit <id>] | enrich <id> | jira <id> | harmonize [--apply] # brain-backed idea backlog: capture an idea → semantic dedup against past ideas/features via the REUSED agentdb vector engine (DUPLICATE≥0.92 / RELATED / NEW) + GoalMap alignment ("map+compass") → weighted seeded roulette picks one to work on → enrich STAGES an idea2prd hand-off → jira writes an auditable outbox via a configurable MCP adapter seam (jira-mcp|copilot-mcp|none). No 2nd vector store; without agentdb it degrades to exact-text dedup (honest)
1021
1057
  dz sign --init --out <path> | --pack <dir> --key <path> # --init: generate the Ed25519 keypair (private OUTSIDE the repo, prints the public key for keys/dz.pub); else sign a pack's manifest + CycloneDX SBOM
1022
1058
  dz sbom --pack <dir> [--out <file>] # emit the CycloneDX 1.5 SBOM for a pack standalone (file-level bill of materials); print to stdout or write to a file
@@ -2311,6 +2347,36 @@ guard, `--loc-cap <n>` tunes, default 700), **secret-scan** (the same high-signa
2311
2347
  edit caps/paths/waivers in `guards.config.json`; the project-critic role should then *not* re-flag these
2312
2348
  rules, only waivers without a reason.
2313
2349
 
2350
+ ### Domain-scoped recall — `--domain <name>` (a boost, never a filter)
2351
+
2352
+ **When to use it.** One brain store, more than one *kind* of work. `dz teach --domain` has always
2353
+ recorded a domain, but until now the ranking ignored it — so medical-research lessons and coding
2354
+ lessons came back interleaved, and the dilution grew with the store.
2355
+
2356
+ ```bash
2357
+ dz recall "signature" --limit 3 --domain security
2358
+ # dz recall "signature" — 3 hit(s), SQLite FTS5 + vector (agentdb) ranking
2359
+ # [0.90] (security) ⟨both⟩ Crypto anti-hallucination anti-pattern: verifying a signature …
2360
+ # [0.85] (publishing) ⟨both⟩ ⚠q 'Re-sign LAST' applies to EVERY signed pack a sweep touches …
2361
+ # [0.80] (testing) ⟨vector⟩ A structural registry-coverage test that only checks key-SET …
2362
+ # domain "security": 1 exact match(es); the order was already correct — nothing moved;
2363
+ # foreign-domain lessons kept (a boost, not a filter)
2364
+
2365
+ dz recall "signature" --limit 3 --domain health-research
2366
+ # domain "health-research": no lesson in this result carries it — order unchanged, nothing was hidden
2367
+ ```
2368
+
2369
+ **Why a boost and not a filter.** Cross-domain transfer is the reason one shared store beats two
2370
+ separate ones: *"a reviewer's evidence needs the same execute-don't-describe discipline as your own
2371
+ claims"* was learned reviewing code and applies verbatim to medical sources. A filter would cut
2372
+ exactly those transfers. So matching hits move UP — at most **2 places** for an exact domain, **1**
2373
+ for a hierarchical relative (`health` ↔ `health-research`) — and nothing is ever dropped: the hit
2374
+ count with `--domain` equals the hit count without it.
2375
+
2376
+ The bound matters: a domain tag is a hint about relevance, not evidence of it, so it breaks near-ties
2377
+ instead of overruling lexical ranking. And the note is honest in both directions — it says when
2378
+ nothing matched, and it distinguishes *matched* from *actually moved*.
2379
+
2314
2380
  ### Semantic recall (vector tier)
2315
2381
 
2316
2382
  `dz recall` is **hybrid** when the vector tier is available and **exactly the old lexical command** when it is not — enabling it never changes behavior for projects that skip it.
@@ -2729,7 +2795,7 @@ npx @dzhechkov/p-replicator init
2729
2795
 
2730
2796
  ## Status
2731
2797
 
2732
- `v0.3.236` — published on npm. Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
2798
+ `v0.3.259` — published on npm. Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
2733
2799
 
2734
2800
  ## Claude Plugin
2735
2801
 
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmXH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACvD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAonO9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4J5E"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA8XH,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACvD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAk3O9E,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8J5E"}
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
- import { chmodSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
6
+ import { appendFileSync, chmodSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
7
7
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
  import { execFileSync, execSync, spawn } from 'node:child_process';
@@ -15,7 +15,7 @@ assembleCandidates, renderPromotionReport, renderPromotionAdr, normalizePromotio
15
15
  // Cold-vs-warm EPOCH RUNNER (feature epoch-replay) — orchestrates + scores, never calls a model.
16
16
  replayableInstances, buildWorkOrder, buildJudgePrompts, unblindJudgments, verifyWorkOrder, isValidMargin, DIGEST_HONEST_SCOPE, scoreEpochReplay, generateMockOutcomes, renderEpochReplayResult, renderWorkOrderSummary, renderJudgePromptsSummary, WORK_ORDER_KIND, DEFAULT_MOCK_N, DEFAULT_MOCK_SEED, scoreRun, renderScorecard, renderCompoundingReport, readReinforcementState, readQuarantineState, registrationExitCode, renderRegistrationReport,
17
17
  // Smart Backlog (feature smart-backlog) — goal-directed idea pipeline over the Brain vector engine.
18
- readBacklogConfig, readIdeas, writeIdeas, ideaId, dedupIdea, readGoalMap, readGoalMapDetailed, parseEffort, ensureBacklogGitignored, isSafeId, alignIdea, mirrorIdeaVector, snapshotIdeas, spinRoulette, rankRoulette, seededRng, eligibleIdeas, stageEnrichment, buildJiraDraft, resolveJiraAdapter, makeBacklogIO, harmonizeBacklog, BACKLOG_BACKENDS, } from '@dzhechkov/harness-core';
18
+ readBacklogConfig, readIdeas, writeIdeas, ideaId, dedupIdea, readGoalMap, readGoalMapDetailed, parseEffort, ensureBacklogGitignored, isSafeId, alignIdea, mirrorIdeaVector, snapshotIdeas, spinRoulette, rankRoulette, seededRng, eligibleIdeas, stageEnrichment, buildJiraDraft, resolveJiraAdapter, makeBacklogIO, harmonizeBacklog, BACKLOG_BACKENDS, applyDomainBoost, countDisplacedByCut, renderDomainBoostNote, renderDomainCutNote, parseReqeDebt, buildReqeBrief, settleReqeDebt, renderReqeList, REQE_SCOPE, } from '@dzhechkov/harness-core';
19
19
  import { getPreset, PRESET_NAMES } from '@dzhechkov/harness-presets';
20
20
  import { scanGitHub, analyzeRepo, generateReport, deepAnalyze, scanAllSources, ScoutMemory } from '@dzhechkov/scout';
21
21
  const USAGE = `dz - DZ cross-platform harness CLI
@@ -48,6 +48,7 @@ Usage:
48
48
  dz epoch-replay --judge <filled-work-order.json> [--out <file>] (blind judge prompts from the filled plans)
49
49
  dz epoch-replay --score <judgments.json> --work-order <file> [--slice <name>] [--json] (un-blind against the pre-registered assignment → SUPPORTED only when the two 95% Wilson CIs are DISJOINT, else FALSIFIED / INCONCLUSIVE)
50
50
  dz score --slug <feature> [--project <dir>] [--json] (process scorecard for ONE feature-adr run, from its artifacts: ADR confirmation, discrimination, cross-model QE grade, live verification, README-first, learning loop, amendments — descriptive-only, a low score exits 0)
51
+ dz reqe [--slug <feature> [--done --report <f>]] [--json] (the re-QE debt ledger: a usage-switched run whose Step-8 QE ran on the coder's OWN family records a debt; list debts, print the cross-family review brief, settle FAIL-CLOSED against a graded report — the settlement lands in 08_qe_report.md)
51
52
  dz backlog add "<idea>" [--effort 1-5] [--proposal <text>] [--dry-run] [--project <dir>] [--json] (capture an idea: semantic dedup against existing ideas via the Brain vector engine (DUPLICATE>=0.92 merges, RELATED links, NEW creates) + GoalMap alignment; --dry-run classifies without writing)
52
53
  dz backlog list [--status <s>] [--goal <id>] [--project <dir>] [--json] (list captured ideas, filterable by status/goal)
53
54
  dz backlog show <id> [--project <dir>] [--json] (full record for one idea)
@@ -60,7 +61,7 @@ Usage:
60
61
  dz teach "<pattern>" [--reward <0-1>] [--domain <name>] [--type rule|success-pattern|lesson-learned] [--project <dir>] [--no-mirror] (--project pins the learned store to <dir>/.dz, not the cwd — pin to a canonical brain)
61
62
  dz teach --from-json <file> [--project <dir>] [--no-mirror] (bulk-import a 'dz recall --all --json' export — share a learned store across machines)
62
63
  dz consolidate [--sessions-dir <dir>] [--project <dir>] [--no-mirror] [--prune-noise [--apply]] [--prune-quarantine [--apply]] (both prunes: DRY-RUN by default; --apply snapshots then deletes; prune-quarantine = expired unproven lessons ONLY, never coupled to noise)
63
- dz recall "<query>" [--limit <N>] [--semantic | --no-semantic] [--books [--book <slug>]] [--project <dir>] | dz recall --all [--json] | dz recall --usage [--json] | dz recall --forget <dzId>[,<dzId>] [--apply] | dz recall --promote <dzId>[,<dzId>] [--apply] (forget/promote: dry-run default; forget snapshots before removing; promote lifts lesson-quarantine)
64
+ dz recall "<query>" [--limit <N>] [--domain <name>] [--semantic | --no-semantic] [--books [--book <slug>]] [--project <dir>] | dz recall --all [--json] | dz recall --usage [--json] | dz recall --forget <dzId>[,<dzId>] [--apply] | dz recall --promote <dzId>[,<dzId>] [--apply] (--domain <name> BOOSTS lessons of that domain without dropping foreign ones — a shared store keeps its cross-domain transfers; forget/promote: dry-run default; forget snapshots before removing; promote lifts lesson-quarantine)
64
65
  dz vector status [--project <dir>] [--json] (semantic tier: engine, mirrored vs lexical counts, pending queue)
65
66
  dz vector reindex [--project <dir>] [--json] (snapshot, re-embed learned-pattern vectors, stamp current model)
66
67
  dz vector export <path> [--project <dir>] (portable VECTOR form (.rvf, opt-in RVF engine); patterns ship via recall --all --json)
@@ -1227,11 +1228,26 @@ function cmdUsage(options, optionLists, flags, cwd, write) {
1227
1228
  };
1228
1229
  if (hasModelLimits && u.weeklyByModel !== undefined)
1229
1230
  payload.weeklyByModel = u.weeklyByModel;
1231
+ // re-QE debt surfacing (backlog 6b40e667 — QE #9: the json contract must carry the debt too,
1232
+ // a probe is exactly the consumer that needs it). The field appears ONLY when a debt exists,
1233
+ // so the zero-debt contract stays byte-identical to the pinned legacy shape. Best-effort.
1234
+ try {
1235
+ const reqeCount = scanReqeDebts(resolve(cwd, options.get('project') ?? '.')).debts.length;
1236
+ if (reqeCount > 0)
1237
+ payload.reqeDue = reqeCount;
1238
+ }
1239
+ catch { /* advisory only */ }
1230
1240
  write(JSON.stringify(payload));
1231
1241
  return 0;
1232
1242
  }
1233
1243
  if (u.sessionPct === null && u.weeklyPct === null) {
1234
1244
  write('usage: unconfigured — set memory.usage.sessionTokenLimit / weeklyTokenLimit in .dz/config.json (percentages are ESTIMATES calibrated from observed exhaustion)');
1245
+ try {
1246
+ const reqe = scanReqeDebts(resolve(cwd, options.get('project') ?? '.'));
1247
+ if (reqe.debts.length > 0)
1248
+ write('re-QE due: ' + reqe.debts.length + ' usage-switched run(s) kept same-family QE — run `dz reqe` for the cross-family pass');
1249
+ }
1250
+ catch { /* advisory only */ }
1235
1251
  return 0;
1236
1252
  }
1237
1253
  // Compact human line — a short HH:MM / weekday hint on the resets, best-effort.
@@ -1249,6 +1265,14 @@ function cmdUsage(options, optionLists, flags, cwd, write) {
1249
1265
  const binding = hasModelLimits && u.weeklyBindingModel !== undefined ? ' ' + u.weeklyBindingModel + '-bound' : '';
1250
1266
  const w = u.weeklyPct === null ? 'n/a' : '~' + u.weeklyPct + '%' + binding;
1251
1267
  write('usage: session ' + s + ' (resets ' + clock(u.sessionResetsAt) + ') · week ' + w + ' (resets ' + clock(u.weeklyResetsAt) + ') · estimated');
1268
+ // re-QE debt surfacing (backlog 6b40e667): the moment someone checks usage is the moment a
1269
+ // usage-switched self-review debt should be visible. Best-effort — never breaks the contract.
1270
+ try {
1271
+ const reqe = scanReqeDebts(resolve(cwd, options.get('project') ?? '.'));
1272
+ if (reqe.debts.length > 0)
1273
+ write('re-QE due: ' + reqe.debts.length + ' usage-switched run(s) kept same-family QE — run `dz reqe` for the cross-family pass');
1274
+ }
1275
+ catch { /* advisory only */ }
1252
1276
  return 0;
1253
1277
  }
1254
1278
  catch {
@@ -1818,13 +1842,30 @@ async function cmdRecall(options, flags, cwd, write) {
1818
1842
  : flags.has('no-semantic') || flags.has('lexical')
1819
1843
  ? 'lexical'
1820
1844
  : 'hybrid';
1821
- const result = await recallHybrid(projectRoot, query, { limit, mode });
1845
+ const wantedDomain = options.get('domain');
1846
+ // OVER-FETCH before boosting (Codex QE #5): the boost used to run on hits ALREADY
1847
+ // truncated to `limit`, so an exact-domain lesson sitting at rank limit+1 could
1848
+ // never receive its promised lift — the feature was weakest in exactly the case it
1849
+ // exists for (foreign-domain dilution pushing a relevant lesson just past the cut).
1850
+ // Fetch a bounded surplus, re-rank, then trim to the limit the caller asked for.
1851
+ const fetchLimit = wantedDomain !== undefined ? Math.min(limit * 3, limit + 20) : limit;
1852
+ const result = await recallHybrid(projectRoot, query, { limit: fetchLimit, mode });
1822
1853
  if (mode === 'semantic' && result.vectorEngine === 'none') {
1823
1854
  // --semantic is an explicit ask — degrading it silently would be dishonest (FR-3).
1824
1855
  write(`dz recall --semantic: ${result.vectorReason ?? 'no vector engine available — run: dz setup --memory agentdb'}`);
1825
1856
  return 1;
1826
1857
  }
1827
- const hits = result.hits;
1858
+ // Domain-aware re-ranking (health-advisor slice H): `--domain <name>` lifts lessons
1859
+ // tagged with that domain WITHOUT dropping foreign ones — a boost, not a filter, so a
1860
+ // shared store keeps the cross-domain transfers that make it worth more than two stores.
1861
+ const boost = wantedDomain !== undefined ? applyDomainBoost(result.hits, wantedDomain) : null;
1862
+ const hits = (boost ? boost.hits : result.hits).slice(0, limit);
1863
+ // The boost never drops a hit, but the CUT still can: promoting a match into the top
1864
+ // `limit` pushes the last one out, so a lesson visible WITHOUT --domain can vanish
1865
+ // WITH it. Cross-model review called this out as a lie by omission — the note said
1866
+ // "foreign-domain lessons kept" about the pre-cut list while the printed list was
1867
+ // missing one. Count it and say so; the reader can act on it (raise --limit).
1868
+ const displaced = boost !== null ? countDisplacedByCut(result.hits, boost.hits, limit) : 0;
1828
1869
  if (asJson) {
1829
1870
  // Portable contract UNCHANGED (I-7/AC-6): a plain PatternRecord[] — round-trips through
1830
1871
  // `dz teach --from-json` regardless of which backend ranked each hit.
@@ -1834,6 +1875,11 @@ async function cmdRecall(options, flags, cwd, write) {
1834
1875
  if (hits.length === 0) {
1835
1876
  write(`dz recall "${query}"`);
1836
1877
  write(` No matching patterns (teach some with \`dz teach\`, or consolidate sessions).`);
1878
+ // The domain note must print here too (Codex QE #10): a --domain run with zero hits
1879
+ // silently said nothing about the domain, so the reader could not tell whether the
1880
+ // boost had been applied and found nothing, or had not run at all.
1881
+ if (boost !== null && wantedDomain !== undefined)
1882
+ write(renderDomainBoostNote(boost, wantedDomain));
1837
1883
  return 0;
1838
1884
  }
1839
1885
  const vectorOn = result.vectorEngine !== 'none' && result.vectorError === undefined && mode !== 'lexical';
@@ -1846,12 +1892,26 @@ async function cmdRecall(options, flags, cwd, write) {
1846
1892
  const qTag = h.quarantined === true ? ' ⚠q' : '';
1847
1893
  if (h.quarantined === true)
1848
1894
  sawQuarantined = true;
1849
- write(` [${h.pattern.reward.toFixed(2)}] (${h.pattern.domain})${backendTag}${qTag} ${h.pattern.pattern.slice(0, 80)}`);
1895
+ // ONE line per hit, always. A lesson may contain newlines, and printing them raw
1896
+ // let stored CONTENT forge lines that look like the tool's own output — including
1897
+ // the domain-boost note that learning_bridge.py reads as a capability probe. Any
1898
+ // consumer that parses this output line-wise has the same exposure, so the fix
1899
+ // belongs at the point of rendering rather than in each reader.
1900
+ const oneLine = h.pattern.pattern.replace(/[\r\n]+/g, ' ⏎ ').slice(0, 80);
1901
+ write(` [${h.pattern.reward.toFixed(2)}] (${h.pattern.domain})${backendTag}${qTag} ${oneLine}`);
1850
1902
  }
1851
1903
  if (sawQuarantined) {
1852
1904
  // The loop stays VISIBLE (ADR D2): a quarantined hit is shown, marked, and explained.
1853
1905
  write(' ⚠q = quarantined (unproven hypothesis, rank damped) — confirm with dz teach --reinforce, or dz recall --promote <dzId> --apply');
1854
1906
  }
1907
+ if (boost !== null && wantedDomain !== undefined) {
1908
+ // Say what the boost did — INCLUDING when it did nothing. A silent reorder would
1909
+ // let the reader believe the ranking was domain-aware when it had no match to work with.
1910
+ write(renderDomainBoostNote(boost, wantedDomain));
1911
+ const cutNote = renderDomainCutNote(displaced, limit);
1912
+ if (cutNote !== '')
1913
+ write(cutNote);
1914
+ }
1855
1915
  if (result.vectorError !== undefined && mode !== 'lexical') {
1856
1916
  // Engine present but the semantic leg failed/timed out — one honest line, exit 0 (05 §2.3).
1857
1917
  write(` ℹ vector search degraded: ${result.vectorError} — showing lexical ranking`);
@@ -5926,6 +5986,213 @@ function nameFor(t, outcome) {
5926
5986
  * `dz score --slug <feature>` — score a feature-adr RUN's process discipline from its artifacts
5927
5987
  * (feature dz-score, Reading C). Descriptive-only: exit 0 on any score; non-zero only on usage errors.
5928
5988
  */
5989
+ /** Scan features/<slug>/.fa-state/reqe-due.json under a project root. Symlinked ANCESTOR dirs are
5990
+ * skipped too, not just the leaf (Codex QE #5 — a symlinked feature dir could smuggle an outside
5991
+ * debt); an oversized or non-regular due-file counts as MALFORMED, never a silent skip (QE #8);
5992
+ * a debt whose embedded slug differs from its directory is MALFORMED — identity is the directory,
5993
+ * the JSON only confirms it (QE #4: an embedded foreign slug must not redirect settlement). */
5994
+ function scanReqeDebts(root) {
5995
+ const out = [];
5996
+ let malformed = 0;
5997
+ const featuresDir = join(root, 'features');
5998
+ let slugs = [];
5999
+ try {
6000
+ if (lstatSync(featuresDir).isSymbolicLink())
6001
+ return { debts: [], malformed: 0 }; // r2 #4: features/ itself
6002
+ slugs = readdirSync(featuresDir);
6003
+ }
6004
+ catch {
6005
+ return { debts: [], malformed: 0 };
6006
+ }
6007
+ for (const slug of slugs.sort()) {
6008
+ const dir = join(featuresDir, slug);
6009
+ const stateDir = join(dir, '.fa-state');
6010
+ const duePath = join(stateDir, 'reqe-due.json');
6011
+ try {
6012
+ if (lstatSync(dir).isSymbolicLink() || lstatSync(stateDir).isSymbolicLink())
6013
+ continue;
6014
+ }
6015
+ catch {
6016
+ continue; // no feature dir / no state dir — nothing to scan
6017
+ }
6018
+ let st;
6019
+ try {
6020
+ st = lstatSync(duePath);
6021
+ }
6022
+ catch {
6023
+ continue; // no due-file — the common, silent case
6024
+ }
6025
+ if (!st.isFile() || st.size > 64 * 1024) {
6026
+ malformed++; // exists but is not a plain small file — named, never silently dropped
6027
+ continue;
6028
+ }
6029
+ try {
6030
+ const debt = parseReqeDebt(readFileSync(duePath, 'utf-8'));
6031
+ if (debt && debt.slug === slug)
6032
+ out.push({ debt, duePath, dir });
6033
+ else
6034
+ malformed++;
6035
+ }
6036
+ catch {
6037
+ malformed++;
6038
+ }
6039
+ }
6040
+ return { debts: out, malformed };
6041
+ }
6042
+ /**
6043
+ * `dz reqe` — the re-QE debt ledger (backlog 6b40e667): list usage-switched same-family QE debts,
6044
+ * print the cross-family review brief, settle FAIL-CLOSED against a graded report.
6045
+ */
6046
+ function cmdReqe(options, flags, cwd, write) {
6047
+ const json = flags.has('json');
6048
+ if (flags.has('help')) {
6049
+ const usage = 'dz reqe [--slug <feature> [--done --report <file>]] [--project <dir>] [--json]';
6050
+ if (json)
6051
+ write(JSON.stringify({ help: usage, exitCode: 0 }));
6052
+ else {
6053
+ write(usage + ' — the re-QE debt ledger');
6054
+ write(' (no args) list unsettled debts (runs whose Step-8 QE ran on the coder’s own family under the usage override)');
6055
+ write(' --slug <s> print the ready cross-family review brief for one debt');
6056
+ write(' --slug <s> --done --report <file> settle the debt — FAIL-CLOSED: requires an existing, non-trivial, GRADED report; appends the settlement to 08_qe_report.md');
6057
+ write(' ' + REQE_SCOPE);
6058
+ }
6059
+ return 0;
6060
+ }
6061
+ for (const flag of flags) {
6062
+ if (!new Set(['json', 'help', 'done']).has(flag)) {
6063
+ write(json ? JSON.stringify({ error: `unknown option --${flag}`, exitCode: 1 }) : `dz reqe: unknown option --${flag}\n allowed: --slug <feature>, --done, --report <file>, --project <dir>, --json`);
6064
+ return 1;
6065
+ }
6066
+ }
6067
+ for (const key of options.keys()) {
6068
+ if (key.startsWith('_positional_') || !new Set(['slug', 'report', 'project']).has(key)) {
6069
+ const what = key.startsWith('_positional_') ? `unexpected argument "${options.get(key)}"` : `unknown option --${key}`;
6070
+ write(json ? JSON.stringify({ error: what, exitCode: 1 }) : `dz reqe: ${what}`);
6071
+ return 1;
6072
+ }
6073
+ }
6074
+ const root = resolve(cwd, options.get('project') ?? '.');
6075
+ const slug = options.get('slug') ?? '';
6076
+ if (slug !== '' && (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(slug) || slug.includes('..'))) {
6077
+ write(json ? JSON.stringify({ error: 'a plain --slug <feature> is required (no path separators)', exitCode: 1 }) : 'dz reqe: a plain --slug <feature> is required (no path separators)');
6078
+ return 1;
6079
+ }
6080
+ const { debts, malformed } = scanReqeDebts(root);
6081
+ if (slug === '') {
6082
+ if (flags.has('done')) {
6083
+ write(json ? JSON.stringify({ error: '--done requires --slug', exitCode: 1 }) : 'dz reqe: --done requires --slug <feature>');
6084
+ return 1;
6085
+ }
6086
+ if (json)
6087
+ write(JSON.stringify({ debts: debts.map((d) => d.debt), malformed, scope: REQE_SCOPE, exitCode: 0 }));
6088
+ else
6089
+ for (const line of renderReqeList(debts.map((d) => d.debt), malformed))
6090
+ write(line);
6091
+ return 0;
6092
+ }
6093
+ const hit = debts.find((d) => d.debt.slug === slug) ?? null;
6094
+ if (!hit) {
6095
+ // distinguish "no debt file" from "malformed debt file" — a corrupt debt must be named
6096
+ const duePath = join(root, 'features', slug, '.fa-state', 'reqe-due.json');
6097
+ const exists = existsSync(duePath);
6098
+ const msg = exists
6099
+ ? `debt file at features/${slug}/.fa-state/reqe-due.json is MALFORMED — inspect it manually (a corrupt debt is named, never auto-cleared)`
6100
+ : `no re-QE debt recorded for "${slug}"`;
6101
+ write(json ? JSON.stringify({ error: msg, exitCode: 1 }) : `dz reqe: ${msg}`);
6102
+ return 1;
6103
+ }
6104
+ if (!flags.has('done')) {
6105
+ const brief = buildReqeBrief(hit.debt, join('features', slug));
6106
+ if (json)
6107
+ write(JSON.stringify({ debt: hit.debt, brief, exitCode: 0 }));
6108
+ else {
6109
+ write(brief.header);
6110
+ for (const line of brief.instructions)
6111
+ write(' ' + line);
6112
+ if (brief.codexCmdTemplate)
6113
+ write(' codex template: ' + brief.codexCmdTemplate);
6114
+ write(' ' + REQE_SCOPE);
6115
+ }
6116
+ return 0;
6117
+ }
6118
+ // --done: FAIL-CLOSED settlement
6119
+ const reportOpt = options.get('report') ?? '';
6120
+ if (reportOpt === '') {
6121
+ write(json ? JSON.stringify({ error: '--done requires --report <file> (the cross-family re-QE report)', exitCode: 1 }) : 'dz reqe: --done requires --report <file>');
6122
+ return 1;
6123
+ }
6124
+ const reportPath = resolve(root, reportOpt);
6125
+ const qeReportPath = join(hit.dir, '08_qe_report.md');
6126
+ // QE #1: the run's OWN same-family Step-8 report must never settle its own debt — the exact
6127
+ // laundering this ledger exists to prevent. Compared by REAL path so a symlink cannot alias it.
6128
+ try {
6129
+ const sameReal = realpathSync(reportPath) === realpathSync(qeReportPath);
6130
+ // r2 #1: a HARD LINK to the same report has a different path but the same inode — compare
6131
+ // dev+ino, not just resolved paths
6132
+ const rSt = statSync(reportPath);
6133
+ const qSt = statSync(qeReportPath);
6134
+ const sameInode = rSt.dev === qSt.dev && rSt.ino === qSt.ino;
6135
+ if (sameReal || sameInode) {
6136
+ write(json ? JSON.stringify({ error: 'the report IS this run’s own 08_qe_report.md (same file/inode) — the same-family review cannot settle its own debt; provide the independent cross-family report', exitCode: 1 }) : 'dz reqe: the report IS this run’s own 08_qe_report.md (same file/inode) — the same-family review cannot settle its own debt (fail-closed)');
6137
+ return 1;
6138
+ }
6139
+ }
6140
+ catch { /* one of the two does not resolve — the reads below decide */ }
6141
+ let reportText = '';
6142
+ try {
6143
+ const st = lstatSync(reportPath);
6144
+ if (!st.isFile())
6145
+ throw new Error('not a regular file'); // symlinked report refused (QE #5)
6146
+ reportText = readFileSync(reportPath, 'utf-8');
6147
+ }
6148
+ catch {
6149
+ write(json ? JSON.stringify({ error: `report not readable at ${reportOpt} (must be a regular file, not a symlink) — refusing to settle`, exitCode: 1 }) : `dz reqe: report not readable at ${reportOpt} (must be a regular file, not a symlink) — refusing to settle (fail-closed)`);
6150
+ return 1;
6151
+ }
6152
+ const settlement = settleReqeDebt(hit.debt, reportText, reportOpt);
6153
+ if (!settlement.ok || settlement.epilogue === null) {
6154
+ write(json ? JSON.stringify({ error: settlement.error, exitCode: 1 }) : `dz reqe: ${settlement.error}`);
6155
+ return 1;
6156
+ }
6157
+ // QE #6 ordering: rotate the debt FIRST, append the human-readable epilogue LAST — a crash may
6158
+ // leave a settled debt without its epilogue (recoverable from reqe-settled.json), never an
6159
+ // epilogue claiming clearance while the debt is still live.
6160
+ const settledBase = join(hit.dir, '.fa-state', 'reqe-settled');
6161
+ let settledPath = settledBase + '.json';
6162
+ for (let n = 2; existsSync(settledPath); n++)
6163
+ settledPath = settledBase + '-' + n + '.json'; // never overwrite prior evidence
6164
+ try {
6165
+ const settled = { ...hit.debt, settledGrade: settlement.grade, settledReport: reportOpt };
6166
+ writeFileSync(settledPath, JSON.stringify(settled) + '\n', { flag: 'wx' }); // wx: never through a planted symlink
6167
+ try {
6168
+ unlinkSync(hit.duePath);
6169
+ }
6170
+ catch (e) {
6171
+ // r2 #5: a failed unlink must not leave a settled marker beside a live debt — roll back
6172
+ try {
6173
+ unlinkSync(settledPath);
6174
+ }
6175
+ catch { /* best-effort rollback */ }
6176
+ throw e;
6177
+ }
6178
+ }
6179
+ catch {
6180
+ write(json ? JSON.stringify({ error: 'could not rotate the debt file — debt NOT cleared, nothing was appended', exitCode: 1 }) : 'dz reqe: could not rotate the debt file — debt NOT cleared, nothing was appended (fail-closed)');
6181
+ return 1;
6182
+ }
6183
+ try {
6184
+ if (lstatSync(qeReportPath).isSymbolicLink())
6185
+ throw new Error('symlinked 08_qe_report.md');
6186
+ appendFileSync(qeReportPath, settlement.epilogue);
6187
+ }
6188
+ catch {
6189
+ write(json ? JSON.stringify({ settled: true, grade: settlement.grade, warning: 'debt cleared (see .fa-state/reqe-settled*.json) but the epilogue could NOT be appended to 08_qe_report.md — append it manually', exitCode: 0 }) : 'dz reqe: debt cleared (evidence in .fa-state/) but the epilogue could NOT be appended to 08_qe_report.md — append it manually');
6190
+ return 0;
6191
+ }
6192
+ const okMsg = `debt settled: re-QE grade ${settlement.grade} (report ${reportOpt}) — settlement appended to features/${slug}/08_qe_report.md`;
6193
+ write(json ? JSON.stringify({ settled: true, grade: settlement.grade, exitCode: 0 }) : `dz reqe: ${okMsg}`);
6194
+ return 0;
6195
+ }
5929
6196
  function cmdScore(options, flags, cwd, write) {
5930
6197
  const json = flags.has('json');
5931
6198
  if (flags.has('help')) {
@@ -6003,10 +6270,25 @@ function cmdScore(options, flags, cwd, write) {
6003
6270
  };
6004
6271
  walk(dir, '', 0);
6005
6272
  const card = scoreRun(slug, artifacts);
6273
+ // re-QE debt note (backlog 6b40e667): a scorecard that praised cross-model QE while an unsettled
6274
+ // same-family debt sits on disk would be half the truth. PARSED, not existence-guessed (QE #9);
6275
+ // a malformed debt file is named. Advisory in both modes — never moves the score or exit code.
6276
+ let reqeNote = null;
6277
+ {
6278
+ const scan = scanReqeDebts(root);
6279
+ const mine = scan.debts.find((d) => d.debt.slug === slug);
6280
+ if (mine)
6281
+ reqeNote = 'UNSETTLED re-QE debt — Step-8 ran same-family under the usage override; run `dz reqe --slug ' + slug + '`';
6282
+ else if (existsSync(join(dir, '.fa-state', 'reqe-due.json')))
6283
+ reqeNote = 'a reqe-due.json exists but is MALFORMED/mismatched — inspect features/' + slug + '/.fa-state/ manually';
6284
+ }
6006
6285
  if (json)
6007
- write(JSON.stringify({ ...card, exitCode: 0 }, null, 2));
6008
- else
6286
+ write(JSON.stringify({ ...card, reqeDebt: reqeNote, exitCode: 0 }, null, 2));
6287
+ else {
6009
6288
  write(renderScorecard(card));
6289
+ if (reqeNote)
6290
+ write('note: ' + reqeNote);
6291
+ }
6010
6292
  return 0;
6011
6293
  }
6012
6294
  /**
@@ -7603,6 +7885,8 @@ export async function runCli(argv, io = {}) {
7603
7885
  return cmdEpochReplay(options, flags, cwd, write);
7604
7886
  case 'score':
7605
7887
  return cmdScore(options, flags, cwd, write);
7888
+ case 'reqe':
7889
+ return cmdReqe(options, flags, cwd, write);
7606
7890
  case 'backlog':
7607
7891
  return await cmdBacklog(options, flags, cwd, write);
7608
7892
  case 'routing':