@dzhechkov/harness-cli 0.4.6 → 0.5.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/.dz-manifest.json CHANGED
@@ -9,43 +9,63 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "2f053f11ea49780919d0557877302e70adb8f33949299b0b0637ece2809c1b67"
12
+ "sha256": "27e2ddfd256e5c89a1c51a2520b52cc4b947dd7295f5730bde0a2c735186fb8f"
13
13
  },
14
14
  {
15
15
  "path": "coverage/coverage-final.json",
16
- "sha256": "e539390d6899ede6cdd0acb76cae6c58e90d4fb3d4389c00dce8604a014aeea7"
16
+ "sha256": "d2eef62228d4f2b31f5c7fca703f0f6844cf517d41be9dee516f3489f5babfec"
17
+ },
18
+ {
19
+ "path": "coverage/coverage-summary.json",
20
+ "sha256": "981eef381eb1e9a040a31eaa561ea078c6f6711d9908990e796d5213d6ffe89f"
17
21
  },
18
22
  {
19
23
  "path": "dist/bin.d.ts",
20
- "sha256": "58be9f04d2fe63cca2efe3957b9933068e443a0e57f9838ff9ef800cc191e03f"
24
+ "sha256": "1d651fdfe05fc306c857bbbee44c395b63b39c1e0c53a8166eb7ca43c6cfa157"
21
25
  },
22
26
  {
23
27
  "path": "dist/bin.d.ts.map",
24
- "sha256": "b1e41c8c19fa56ae9dec2267740eb4389bc785431478861a8843867f99c1b25b"
28
+ "sha256": "74105b3edb4c4a7d75393a7cb2dda06a0f545b1cce75e9a772a30b18b3609374"
25
29
  },
26
30
  {
27
31
  "path": "dist/bin.js",
28
- "sha256": "c4a6b64f875db72a2897df0e3b0c7cd279308dba2471ae29a57775dad7a7d8f8"
32
+ "sha256": "e215d5ebb9d87106c3bdfda29c8cb1af59bc9bdbd62c11b2b6a313a2bd3ecd7c"
29
33
  },
30
34
  {
31
35
  "path": "dist/bin.js.map",
32
- "sha256": "9661e4d167ea1c13c3f40de510f311024da3c44bcb452d3781fb89f46373eadc"
36
+ "sha256": "31849f2576f6e57a8a71f49cbb1a6e6c692f98dd8303217ec836933420d08dac"
33
37
  },
34
38
  {
35
39
  "path": "dist/cli.d.ts",
36
- "sha256": "9afd7c4a02708d7d425214c5d3b76a2ad7bd5ea3ba6c725e4880a91d76062f34"
40
+ "sha256": "56db11f99b505b2ffbc314aa70b4bcd17ec741e14ca99a3662d0ca9f4afcc1cc"
37
41
  },
38
42
  {
39
43
  "path": "dist/cli.d.ts.map",
40
- "sha256": "5bdc153e789ac180543e9b4955ea36666dc27b7238637b05875e048fc49ae30f"
44
+ "sha256": "19170be889713fffd051dfde1044074125f66bb4623e415c355f812a47721436"
41
45
  },
42
46
  {
43
47
  "path": "dist/cli.js",
44
- "sha256": "0183c01a98e232554a7460be48ee5fdf59dd3a7d09c719a31b08acc9c6b3528c"
48
+ "sha256": "c80fe1740887b68a3521ee6d22e09303785238c6e27dd0c80fb76289927e73a4"
45
49
  },
46
50
  {
47
51
  "path": "dist/cli.js.map",
48
- "sha256": "c5bd1b0b852dd21de328494d7a99db336afbde4397b7c687d416f1a6f3c297b2"
52
+ "sha256": "1ef2072181086e6b14c30005417f3edba91db5c3f2ae82201236ea493385d6a8"
53
+ },
54
+ {
55
+ "path": "dist/core-compat.d.ts",
56
+ "sha256": "dedfc859e163f229af0445d6439172a4b66c150c0942bce3ae1bf0304dbb3290"
57
+ },
58
+ {
59
+ "path": "dist/core-compat.d.ts.map",
60
+ "sha256": "bce1ded9ffac15080908af1a9571b67141c141374ec4ba90b987fd6fd8883aab"
61
+ },
62
+ {
63
+ "path": "dist/core-compat.js",
64
+ "sha256": "57930e6918c2a5d90826c74924a62de9a1ffab53d8196ff8f98a59c89baf23be"
65
+ },
66
+ {
67
+ "path": "dist/core-compat.js.map",
68
+ "sha256": "e95005978fdd733f78208d6d916f62f970123530241739c9da7d3a74154b7a13"
49
69
  },
50
70
  {
51
71
  "path": "dist/index.d.ts",
@@ -69,28 +89,64 @@
69
89
  },
70
90
  {
71
91
  "path": "package.json",
72
- "sha256": "00a53276d145112e3c2ae5ca2950ac74877ea4b069b2b81040d49c5903eb6482"
92
+ "sha256": "be73e142cc0dcd05cf774c73827572b1e55e503c8ab84f4a396fa785b271980b"
73
93
  },
74
94
  {
75
95
  "path": "src/bin.ts",
76
- "sha256": "f799d9771166fe95eb40463d1ebbeb0dd3acdd78fa9c692e086a6a673f54752a"
96
+ "sha256": "42a1f67e1f39c4cda2df0887c16fbb6f54eb108ba0cb18612bb83ee153092463"
77
97
  },
78
98
  {
79
99
  "path": "src/cli.ts",
80
- "sha256": "0a1097fc3a2294f934fc50f5871b287cfbc5ec85becdab914b7caeca42cb7d1a"
100
+ "sha256": "c875709ccafe3493342776b28c8aa7b34e1fb800e2fccedcb499e6490e6ad1c0"
101
+ },
102
+ {
103
+ "path": "src/core-compat.ts",
104
+ "sha256": "3638272a91166a047c3edc14626c0011e91b2de862a197d1b8e424470e7a0575"
81
105
  },
82
106
  {
83
107
  "path": "src/index.ts",
84
108
  "sha256": "395b27b317e575b94a1049cdb284db185e0ec382fbae1e588c78ff2398b2563f"
85
109
  },
110
+ {
111
+ "path": "test/agents-sync.test.ts",
112
+ "sha256": "32606890dc57d58257e6b4a38246acb343eea88b6e4b2f643f061325a34d066a"
113
+ },
86
114
  {
87
115
  "path": "test/cli.test.ts",
88
- "sha256": "c66bdd2fbbe2e0b622e3bc4e0e4521e865cc8088e581bd4b4862c1c550307900"
116
+ "sha256": "83d8c6a9d7e8d46b57bb2e5da47c0345e8a512bdcc2e7cc8c59e163ade41de10"
117
+ },
118
+ {
119
+ "path": "test/command-count.test.ts",
120
+ "sha256": "9958e10a8adb80ee64baad0d91fb4c9a3b6e8801c6379f7ba5f8f5ab6c1f1716"
121
+ },
122
+ {
123
+ "path": "test/core-compat-guard.test.ts",
124
+ "sha256": "98086d0b6bd7ce32cc844e0cbbc710c4dbf009389c1d020aed48ced2de8acd57"
125
+ },
126
+ {
127
+ "path": "test/core-compat.test.ts",
128
+ "sha256": "c54d5aa80a2455a396b396ff9fc398c141c3be4ec9c830e0941f830658758866"
129
+ },
130
+ {
131
+ "path": "test/core-import-floor.test.ts",
132
+ "sha256": "84e16e0f31608570f72575038ae246d9ff002671ade0e9f9fa6009dd862dfc03"
133
+ },
134
+ {
135
+ "path": "test/discrimination-check-cli.test.ts",
136
+ "sha256": "cd7507c8ec1f621fea6f05596541235d09efbd215540b56b012cf465e06b6ba0"
89
137
  },
90
138
  {
91
139
  "path": "test/epoch-replay-cli.test.ts",
92
140
  "sha256": "a5a48585b565288ca1ea96030b02b2ccb37a621ef7b3cfe54cd7aaa7164d6904"
93
141
  },
142
+ {
143
+ "path": "test/fixtures/discrimination-check/fake-runner.sh",
144
+ "sha256": "126bbd1ba9c08ef9de826cfa21df3981720e4bc36cd993dff28e0de435cbebae"
145
+ },
146
+ {
147
+ "path": "test/fixtures/discrimination-check/fixture.py",
148
+ "sha256": "bb413a8b6e9dc597eb298e7646fb84e23ccd3e117eb61201776ef3e9e27a0e0a"
149
+ },
94
150
  {
95
151
  "path": "test/fixtures/install-layouts-helpers.ts",
96
152
  "sha256": "7c1d53c295ec4cb7ee8e3036b663f20d660a1acff35dbcb5c99257aed7268b68"
@@ -183,22 +239,42 @@
183
239
  "path": "test/install-layouts.test.ts",
184
240
  "sha256": "43cc6e3251500cd547997ac0916c250c8558f6c3d5c4a60254753e1e80ba24f5"
185
241
  },
242
+ {
243
+ "path": "test/install-sync-partial.test.ts",
244
+ "sha256": "35824489662dbe9315d78cd20ecf968d416fbe80685d74b6588c8521a08497ea"
245
+ },
246
+ {
247
+ "path": "test/list-partial.test.ts",
248
+ "sha256": "fd98385a9b1021cf8341d154abcdf4506a84aaadddd465fcc7e057ba1927fe64"
249
+ },
186
250
  {
187
251
  "path": "test/mutation-gate-cli.test.ts",
188
252
  "sha256": "3b33c786713e2dfaa192ea32df8cdcf534170c59d58ce285872a3fde008afbc4"
189
253
  },
190
254
  {
191
255
  "path": "test/mutation-registry.json",
192
- "sha256": "fe8e5792626cf58678c1e2bcb809f63413655c2e171439157b74deb8b4fd80fb"
256
+ "sha256": "3e6f9bb105154121988da41568ff85573099235857ba25e76c4264c166b414ae"
257
+ },
258
+ {
259
+ "path": "test/skills-verify-static-advisories.test.ts",
260
+ "sha256": "b1140c20ec04d1c8ae67f97a42dbcece1e8e63c98a5de2c087f0359d27c25f17"
193
261
  },
194
262
  {
195
263
  "path": "test/statusline-panel.test.ts",
196
264
  "sha256": "b09b42c4ece1a83e5d3f3765629b0756a8f30a7122f3fc30363f93f092a44c0d"
197
265
  },
266
+ {
267
+ "path": "test/target-alias-cli.test.ts",
268
+ "sha256": "96df42acb1cc5ada5ca97912d3b7da5b486067e851b9dd395855b1b540ce738c"
269
+ },
198
270
  {
199
271
  "path": "test/trace-bundle-cli.test.ts",
200
272
  "sha256": "fdaad63359ca7ce351e505e613b547bbc653e0847403edfae88d22a8a524b7a0"
201
273
  },
274
+ {
275
+ "path": "test/version-flag.test.ts",
276
+ "sha256": "7acd80deb073fb2987c6d14a028a64c6d44324ac61a05410b7d4b6c87ff5acc6"
277
+ },
202
278
  {
203
279
  "path": "test/workflow-init-lint-clean.test.ts",
204
280
  "sha256": "b7a64462983901adca86ecc29e76b3f95885210e5aaba68352356191e6bfac7f"
@@ -221,5 +297,5 @@
221
297
  }
222
298
  ]
223
299
  },
224
- "signature": "6IQyjN4aazsr6EyD1+y/VrZ1+bclvxc9nXsCLR3WVDomAn6AhNtlTJQWdfbvw49A4/HH+KTW+KkJlj/gFFnqCw=="
300
+ "signature": "jyIwJnH5LH3+Wrq8W19HGqMpqt8e0srMnfZH/atV2H3ddnlrYzMe0f7bvyigDpdLzVApxiq+Xna5z4psVILMDg=="
225
301
  }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dzhechko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -125,6 +125,140 @@ point any tool at (a skill is just Markdown). Dedicated targets are on the [road
125
125
  **❌ No target applies:** `nemoclaw` (NVIDIA agent-safety runtime — not a code editor, no rules file) ·
126
126
  `v0` (UI-only, no repo file). *(`pi` is a real coder but reads `AGENTS.md` → covered by `agents-md`.)*
127
127
 
128
+ #### `--target` aliases and did-you-mean
129
+
130
+ `--target claude` used to be rejected outright — the canonical name is `claude-code`, and the error
131
+ just re-printed the list. All **eight** `--target`-taking commands (`init`, `verify`, `install`,
132
+ `compose`, `setup`, `upgrade`, `parity`, `feature-adr-setup`) now resolve the value first.
133
+
134
+ *(This sentence used to say "every" and name only seven: `dz parity` was missed, and shipped the
135
+ original defect verbatim. It is now checked rather than promised — `test/target-alias-cli.test.ts`
136
+ asserts that no command reads `--target` without reaching the resolver, and that every command whose
137
+ `--help` advertises `--target` appears in the per-command sweep.)*
138
+
139
+ **Accepted aliases** (a table, so adding one is a data edit):
140
+
141
+ | You type | You get | Why it is a row |
142
+ |----------|---------|-----------------|
143
+ | `claude` · `cc` | `claude-code` | the tool's everyday name |
144
+ | `agents` | `agents-md` | the everyday name of the `AGENTS.md` target |
145
+ | `gpt` · `openai` | `codex` | the vendor name, not the CLI's |
146
+
147
+ Case, padding and separators are handled **without** a row: `CLAUDE`, `Claude_Code`, `claudecode`
148
+ and ` claude-code ` all resolve to `claude-code`; `agentsmd` and `agents.md` resolve to `agents-md`.
149
+
150
+ **A typo is SUGGESTED, never silently accepted** — installing to the wrong target on a guess is worse
151
+ than one round-trip:
152
+
153
+ ```console
154
+ $ dz init --target clade-code --preset devops > out.txt # the refusal is on STDERR
155
+ dz init: unknown --target "clade-code" — did you mean "claude-code"?
156
+ --target must be one of: agents-md, claude-code, codex, copilot, cursor, gemini, hermes, openclaude, opencode, windsurf
157
+ $ echo $?
158
+ 1
159
+ $ wc -c out.txt
160
+ 0 out.txt # stdout stays a clean data channel, even on a refusal
161
+ ```
162
+
163
+ **Both lines go to stderr** — the refusal, like the alias note below, is diagnosis, not data. `dz
164
+ parity --target <bad> --json` likewise writes its structured error to stderr and leaves stdout empty,
165
+ so `| jq` is never handed a diagnostic.
166
+
167
+ An ambiguous prefix gets no guess at all (`--target co` could be `codex` or `copilot`), and neither
168
+ does nonsense (`--target totally-bogus` prints the plain list). When an alias IS accepted, the
169
+ substitution is announced **on stderr**, so piped stdout stays machine-readable:
170
+
171
+ ```console
172
+ $ dz init --target claude --preset devops > installed.txt
173
+ dz init: --target "claude" → claude-code (alias)
174
+ ```
175
+
176
+ **When this matters:** you are following a blog post or a teammate's snippet that says `--target claude`.
177
+ It now works, and you are told what it resolved to.
178
+
179
+ ### `dz list` — one broken skill never hides the rest
180
+
181
+ `dz list` used to abort on the FIRST unparseable `SKILL.md`: exit 1, an error naming neither the file
182
+ nor a count, and every other skill in the tree invisible. A pack you installed could blank your whole
183
+ listing. Now the loadable skills are listed on **stdout** and the unloadable ones are named on
184
+ **stderr**:
185
+
186
+ ```console
187
+ $ dz list --skills-dir .claude/skills
188
+ 105 skill(s) in /home/you/proj/.claude/skills:
189
+
190
+ api-design Designs REST and GraphQL APIs with OpenAPI specs…
191
+ …103 more…
192
+ test-writer Writes focused unit and integration tests…
193
+ $ echo $?
194
+ 1
195
+ ```
196
+
197
+ …with the diagnosis kept out of the data:
198
+
199
+ ```console
200
+ $ dz list --skills-dir .claude/skills 2>/dev/null # stdout only — clean, pipeable
201
+ 105 skill(s) in …
202
+
203
+ $ dz list --skills-dir .claude/skills 1>/dev/null # stderr only — the actionable part
204
+ dz list: 105 listed, 1 skipped in /home/you/proj/.claude/skills
205
+ ⚠ 1 skill(s) skipped (unparseable SKILL.md):
206
+ /home/you/proj/.claude/skills/broken-one/SKILL.md
207
+ SKILL.md must begin with a "---" frontmatter fence
208
+ (line 1: "# Broken One")
209
+ ```
210
+
211
+ The full contract:
212
+
213
+ | valid skills | skipped | stdout | stderr | exit |
214
+ |--------------|---------|--------|--------|------|
215
+ | >0 | 0 | the listing | *empty* | 0 |
216
+ | >0 | >0 | the listing of the valid ones | named summary | 1 |
217
+ | 0 | >0 | *nothing* | named summary (`0 listed, N skipped`) | 1 |
218
+ | 0 | 0 | *nothing* | `dz list: no skills found in <dir>` | 1 |
219
+
220
+ `dz init`, `dz install` and `dz sync` behave the same way — the good skills are installed, the bad ones
221
+ are named, and the command exits 1.
222
+
223
+ **Two failure kinds, two headers, two subjects.** A skill that will not PARSE and a skill that will not
224
+ WRITE are different accusations, so `dz init` reports them separately:
225
+
226
+ ```console
227
+ $ dz init --target claude-code --skills-dir ./skills --project ./proj
228
+ dz init --target claude-code: 1 skill(s), 1 file(s) written, 0 skipped
229
+ dz init: 1 installed, 1 failed to write # ← stderr
230
+ ✗ 1 skill(s) failed to install (compile/write error):
231
+ alpha
232
+ EEXIST: file already exists, mkdir './proj/.claude/skills/alpha'
233
+ ```
234
+
235
+ The header names the **target**, not `alpha/SKILL.md` — which is perfectly valid. (It used to print
236
+ `⚠ 1 skill(s) skipped (unparseable SKILL.md)` and quote `line 1: "---"`, a valid frontmatter fence, as
237
+ its evidence: a failure that names the wrong artifact is worse than an anonymous one.)
238
+
239
+ `dz install` renders the offending path **relative to the package**
240
+ and says so explicitly, because a `node_modules/**` path is not something you can act on:
241
+
242
+ ```console
243
+ $ dz install @someone/skills-pack
244
+ dz install @someone/skills-pack: 12 skill(s), 24 file(s) written, 0 skipped
245
+ dz install: @someone/skills-pack ships 1 unparseable skill(s) —
246
+ ⚠ 1 skill(s) skipped (unparseable SKILL.md):
247
+ skills/broken-one/SKILL.md
248
+ SKILL.md must begin with a "---" frontmatter fence
249
+ This is a defect in the package, not in your project.
250
+ Workaround: npx -y @someone/skills-pack init
251
+ ```
252
+
253
+ **When this matters:** a package you installed shipped a broken skill — you still see everything else,
254
+ you know exactly which file is at fault, and you know whose defect it is.
255
+
256
+ > **`dz` requires `@dzhechkov/harness-core >= 0.4.7`.** If you ever see
257
+ > `dz: needs @dzhechkov/harness-core >= 0.4.7, found 0.4.1`, a stale core was reused from a cache:
258
+ > `rm -rf ~/.npm/_npx && npx @dzhechkov/harness-cli@latest --version`. That named message replaced a
259
+ > bare `SyntaxError: … does not provide an export named 'GRADE_SUCCESS_FLOOR'` that used to kill even
260
+ > `dz --version`.
261
+
128
262
  > **"Nothing installs" / "no skills found"?** Update the CLI:
129
263
  > `cd /tmp && npm i -g @dzhechkov/harness-cli@latest`. Older global installs couldn't locate their
130
264
  > own bundled packs outside the monorepo — now fixed, so `dz registry`/`dz init`/`dz setup` work
@@ -132,7 +266,7 @@ point any tool at (a skill is just Markdown). Dedicated targets are on the [road
132
266
 
133
267
  ## User Journey — from install to mastery
134
268
 
135
- All 66 commands (MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases) mapped to a real workflow:
269
+ All 67 commands (MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases) mapped to a real workflow:
136
270
 
137
271
  ```
138
272
  DISCOVER → INSTALL → USE → CREATE → MAINTAIN → SHARE
@@ -1015,7 +1149,7 @@ green: re-sign reminder (`dz sign …` — the publish signature gate is refuse-
1015
1149
  before a multi-package npm release, or whenever a broken dist/bin must be impossible to ship; keep plain
1016
1150
  `dz publish` for routine pushes. `dz publish` itself is byte-identical whether or not release exists.
1017
1151
 
1018
- ### Skill Packs (23 packs · 179 skills)
1152
+ ### Skill Packs (18 packs · 189 skills)
1019
1153
 
1020
1154
  Each pack is an npm package — click through for the **full per-skill documentation** (what each skill does + how to trigger it). Install a whole pack with `dz install <pkg>`, or pick skills with `dz init --select` / a `--preset`.
1021
1155
 
@@ -1038,6 +1172,7 @@ Each pack is an npm package — click through for the **full per-skill documenta
1038
1172
  | [@dzhechkov/skills-taste](https://www.npmjs.com/package/@dzhechkov/skills-taste) | 1 | *imported (MIT)* — `design-taste-frontend`: anti-slop landing/portfolio/redesign framework (dials + pre-flight + GSAP skeletons); complements frontend-design (`dz init --select design-taste-frontend`) ([ADR-0002](https://github.com/djd1m/dz-harness-hub/blob/main/docs/adr/0002-product-and-design-expansion.md)) |
1039
1173
  | [@dzhechkov/skills-book-digitizer](https://www.npmjs.com/package/@dzhechkov/skills-book-digitizer) | 8 | *dz-original* — book → installable methodology pack: `digitize-book` (orchestrator) + ingest/extract/distill/pack/kb-index + `book-brain-register` (CP6 promote → cross-project brain) + `source-brain-ingest` (repo sibling). Verified provenance, IP-safe, resumable (`dz init --select digitize-book`) ([ADR-001](https://github.com/djd1m/dz-harness-hub/blob/main/features/book-knowledge-digitizer/03_adr/001-book-to-skillpack-pipeline.md)) |
1040
1174
  | [@dzhechkov/skills-12factor](https://www.npmjs.com/package/@dzhechkov/skills-12factor) | 12 | *generated by the digitizer, CC BY 4.0* — The Twelve-Factor App distilled into 12 decision-moment skills (one per factor). The first PUBLIC digitized-book pack; paraphrased (shingling-gated), routing-gated (every factor carries triggers), attributed (`NOTICE`) (`dz init --select 12factor-config-in-environment,…`) |
1175
+ | [@dzhechkov/skills-book-ai-apps](https://www.npmjs.com/package/@dzhechkov/skills-book-ai-apps) | 17 | *generated by the digitizer, CP5-published* — «Building Applications with AI Agents» (Albada, рус. пер.) distilled into 17 decision-moment skills across the whole agent-building arc: agent-fit & model choice, single-vs-multi, orchestration, tool design, knowledge & memory, context engineering, evaluation, probabilistic behaviour checks, release gates, improvement loops, drift, human-in-the-loop, agent UX, governance, security. Ships our page-anchored Knowledge Units, NOT the book text — shingling-gated at 0 uncited verbatim runs >=8 words; publication is the recorded CP5 owner decision; `trust_tier 1` (routing-gated, not human-reviewed) Since 0.2.2 it also ships `brain/ai-apps.sqlite`, the 223-KU knowledge slice: `dz brain add --from-pack @dzhechkov/skills-book-ai-apps` loads it into your `~/.dz/brain`, then `dz brain query --source ai-apps` answers in any project (`dz install @dzhechkov/skills-book-ai-apps --target claude-code`) |
1041
1176
 
1042
1177
  ### Available Presets (14)
1043
1178
 
@@ -1376,9 +1511,9 @@ only at their documented scopes (plan + step), and `fanouts[].registry` items mu
1376
1511
  ItemKey domain the trace plane enforces — `trace.emit` can never decide whether a valid plan runs.
1377
1512
  Deferred options are on the loop-designer roadmap.
1378
1513
 
1379
- ## All Commands (66)
1514
+ ## All Commands (68)
1380
1515
 
1381
- *(66 MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases.)*
1516
+ *(67 MEASURED — reproducer: `grep -c "^ case '" src/cli.ts`, the dispatch cases.)*
1382
1517
 
1383
1518
  ```
1384
1519
  dz setup --target <name> [--preset <name>] [--select id,id,...] [--skills-dir <dir>] [--memory agentdb] [--no-memory] [--no-hooks] [--install-driver] [--force]
@@ -1433,7 +1568,7 @@ dz feature-adr-setup [--plan] [--from-spec <f>] [--apply] # guided project onb
1433
1568
  dz challenge --plan <plan.md> [--json] [--context-only] [--author <model>] # adversarial plan-gate (behind the `challenge-panel` skill): assemble a WIDE context pack (plan + vision + testing + map + degradations) + the fixed C1-C8 "break it" brief for a FRESH adversary (≠ plan author); advisory, never blocks
1434
1569
  dz routing [--stage <s>] [--json] # inspect the learned cost-optimal routing store: what `args.models.<stage>='auto-cost'` believes per (stage, complexity-tier, model) — gated attempts/successes/rate (feeds feature-adr model selection)
1435
1570
  dz bto-optimize --split|--plan|--select|--scope-check|--diff [--json] # deterministic engine behind /bto-optimize: hold-out split + hard-capped budget + no-regress-on-holdout winner selection (defeats judge-gaming); prose-only, diff-confirmed, never auto-writes
1436
- dz discrimination-check --test <f[,f]> [--base <ref>] [--name <filter>] [--runner <cmd>] [--json] # §42 test-discrimination gate for feature-adr Step-8: run the ADR's property test in an isolated git worktree at pre-feature base — it MUST go red without the fix; a green is a false green (HIGH finding, advisory, never auto-aborts)
1571
+ dz discrimination-check --test <f[,f]> [--base <ref>] [--name <filter>] [--runner <cmd>] [--timeout <ms>] [--json] # §42 test-discrimination gate for feature-adr Step-8: run the ADR's property test in an isolated git worktree at pre-feature base — it MUST go red without the fix. SEVEN verdicts, each gated on EXECUTION evidence: DISCRIMINATES · DISCRIMINATES_VIA_ERROR · NON_DISCRIMINATING (false green) · TEST_FILE_ABSENT · LOAD_ERROR_AT_BOTH_REVS · FAILS_AT_TIP · CANNOT_ISOLATE (+ typed reason). Advisory, never auto-aborts
1437
1572
  dz mutation-gate [--package <dir>] [--registry <file>] [--test-cmd "<cmd>"] [--only <id[,id]>] [--timeout <ms>] [--rebaseline per-entry|final] [--keep-scratch] [--json] # the mutation gate: for each NAMED protection in a declarative registry, copy the package to a scratch dir (shadow-repo layout, node_modules symlinked, git-initialized), verify the baseline is green, apply the entry's exact {find, replace} mutation, run the suite, REQUIRE red, restore — and require the red to be ATTRIBUTABLE to the protection: a mutated file that no longer parses is MUTATION_UNPARSEABLE, a failing count far above the entry's bound (maxFailing, default from observed) is OVER_FAILING, and a restored tree that does not reproduce green makes the entry INCONCLUSIVE (flaky suite). A mutation that does not apply, a green suite, or an inconclusive run is a FAILURE — never a skip. exit 0 all proven / 1 gate failed / 2 setup error
1438
1573
  dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] # portable Step-10 Delivery Gate: the `manual` form that travels to every shell target — prints the 4-plane review brief (regressions ‖ security ‖ code-quality ‖ product-honesty) + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off (only cross-validated BLOCKER/HIGH count) and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked
1439
1574
  dz skills-verify [--dir <project>] [--expect a,b] [--static] [--strict] [--timeout <s>] [--json] # does .claude/skills/ actually REGISTER? --static = instant layout scan (CI-safe, no session): flags dirs that can never register; default also starts a real session and reads the authoritative system/init listing. exit 0 pass / 1 fail / 2 inconclusive — an unobservable registration is NEVER a pass
@@ -1456,6 +1591,8 @@ dz release [--filter <name>] [--affected] [--audit-dev] [--tag] [--pub
1456
1591
  dz auto-canonicalize --source <github-url> --pack <skills-pack>
1457
1592
  dz sync-upstream [--package <dir>] [--list] [--all]
1458
1593
  dz drift-check [--all] [--json] [--project <dir>] # CI gate: exit 1 on NEW shared-skill drift (baseline: .dz/drift-allowlist.json; --all incl .claude dogfood)
1594
+ dz agents-sync [--check] [--json] [--project <dir>] # sync anchored bearing rules into the root AGENTS.md policy fence; exit 0 sync / 1 drift / 3 inconclusive
1595
+ dz hooks-sync --target codex [--check] [--remove] [--json] # install + ARM the dz veto/recall hooks in $CODEX_HOME/hooks.json; exit 0 armed+trusted / 1 not armed / 3 inconclusive
1459
1596
  dz sync-canonical <skill> [--check] [--from <dir>] [--auto] [--project <dir>] # heal every copy from skills-meta/<skill> or --from; no canonical + --check = compare copies to each other (exit 1 on drift); no canonical + write = refuse unless --auto (LOUD, picks most-complete copy); --check writes nothing
1460
1597
  dz scout [--topics <list>] [--since <date>] [--deep] [--output <file>] [--diff] [--report]
1461
1598
  dz workflow init --name <n> [--pattern pipeline|barrier|fanout|gate] [--o <plan.json>] | validate <plan.json> [--json] | render <plan.json> --o <script.js> [--check] [--force] | blobs [--check] # loop-plan/1 authoring (the ADR-005 templates are retired)
@@ -1477,8 +1614,8 @@ dz help
1477
1614
  ## Global: `dz --version` / `-v` / `dz version`
1478
1615
 
1479
1616
  ```bash
1480
- dz --version # 0.4.6
1481
- dz --version --json # {"name":"dz","version":"0.4.6","node":"v22.22.0","schemas":{"loopPlan":"loop-plan/1"}}
1617
+ dz --version # 0.4.8
1618
+ dz --version --json # {"name":"dz","version":"0.4.8","node":"v22.22.0","schemas":{"loopPlan":"loop-plan/1"}}
1482
1619
  ```
1483
1620
 
1484
1621
  One line, exit 0. Unresolvable ⇒ the literal `unknown` and exit **1** — never a fabricated number,
@@ -2083,6 +2220,78 @@ dz sync-upstream --package packages/@dzhechkov/skills-devops # check one packag
2083
2220
 
2084
2221
  Discovers all skill packs with `sources.json`, fetches SKILL.md from origin repos, reports which skills have upstream changes.
2085
2222
 
2223
+ ### dz agents-sync — Codex starts with the repository's bearing rules
2224
+
2225
+ Use this after changing an anchored policy clause in `CLAUDE.md` or `.claude/rules/*.md`, and run
2226
+ the check form in CI. It updates only the `dz:policies` fence in the root `AGENTS.md`; authored
2227
+ content and the independent `dz:skills` fence remain untouched.
2228
+
2229
+ ```console
2230
+ $ dz agents-sync
2231
+ dz agents-sync: wrote — 9 policy section(s), 8097 bytes (24.71% of 32768)
2232
+
2233
+ $ dz agents-sync --check
2234
+ dz agents-sync: in sync — 9 policy section(s), 8097 bytes (24.71% of 32768)
2235
+ ```
2236
+
2237
+ Exit codes are **0** for synchronized, **1** for drift and **3** when fixed source evidence is
2238
+ missing or unreadable. `--check` never writes. Each section carries a 12-hex hash recomputed from
2239
+ its source anchor; this proves synchronization only — not that Codex read or obeyed the rule. The
2240
+ separate cold-start acceptance probe establishes runtime visibility.
2241
+
2242
+ ### dz hooks-sync — Codex runs the same veto and recall hooks Claude Code does
2243
+
2244
+ **When to use it.** Once per machine, after `npm i -g @dzhechkov/harness-cli`, if you drive Codex as
2245
+ well as Claude Code. It installs two hooks into the **user-global** `$CODEX_HOME/hooks.json`
2246
+ (default `~/.codex/hooks.json`) and **arms** them — Codex hooks are trust-gated, and an untrusted
2247
+ entry is silently never run. Re-run it after a dz upgrade; it is byte-idempotent, so an unchanged
2248
+ install rewrites nothing and the hook keeps its trust.
2249
+
2250
+ ```console
2251
+ $ dz hooks-sync --target codex
2252
+ dz hooks-sync: codex hooks installed and ARMED (trust: trusted) — ready
2253
+
2254
+ $ dz hooks-sync --target codex --check
2255
+ dz hooks-sync: codex hooks installed and ARMED (trust: trusted) — ready
2256
+
2257
+ $ dz hooks-sync --target codex --remove
2258
+ dz hooks-sync: removed 2 managed entr(ies) from /root/.codex/hooks.json
2259
+ ```
2260
+
2261
+ Exit codes are **0** for armed **and** trusted, **1** for not-armed / drift / a refusal, and **3**
2262
+ when the answer is inconclusive (including "no `codex` binary on PATH", where dz writes **nothing**).
2263
+ `--check` writes nothing and is **silent** in a home that never opted in.
2264
+
2265
+ **What the two hooks do.**
2266
+
2267
+ | Hook | Event | Behaviour |
2268
+ |---|---|---|
2269
+ | `dz-codex-veto.cjs` | `PreToolUse` | judges the shell command against one rule, `ssh-explicit-auth-weakening` |
2270
+ | `dz-codex-recall.cjs` | `UserPromptSubmit` | injects matching learned lessons and records the use with `runtime: "codex"` |
2271
+
2272
+ **The veto WARNS by default and never blocks.** A hit prints `DZ-VETO-WARN:` and exits 0. Enforcement
2273
+ is opt-in **per project**:
2274
+
2275
+ ```console
2276
+ $ cat .dz/config.json
2277
+ {"hooks": {"shellVeto": "block"}} # off | warn (default) | block
2278
+ ```
2279
+
2280
+ Only then does a hit exit 2 and stop the command. The rule fires only on tokens by which the command
2281
+ *explicitly* asks for weaker ssh authentication — `sshpass`, `-o PasswordAuthentication=yes`,
2282
+ `-o PubkeyAuthentication=no`, `-o PreferredAuthentications=…password…`. A bare `ssh myhost` whose
2283
+ identity comes from `~/.ssh/config` or `ssh-agent` is **allowed**: this guard is user-global, so a
2284
+ rule that blocks the normal secure case is not a guard, it is an outage.
2285
+
2286
+ **Radius.** Both helpers are INERT outside an opted-in dz project — the activation marker is a `.dz`
2287
+ directory, not `.git`. In a plain git checkout they take no decision, print nothing, and create
2288
+ nothing.
2289
+
2290
+ **Removal is conservative.** `--remove` deletes only entries whose command hash is recorded in dz's
2291
+ own manifest. An entry that merely *looks* like dz's is kept and reported — dz never deletes what it
2292
+ cannot prove it wrote. Foreign entries are preserved byte-for-byte by every operation, and a
2293
+ `hooks.json.bak-<ISO>` copy (newest 3 kept) is taken before each modifying write.
2294
+
2086
2295
  ### dz drift-check / dz sync-canonical — intra-monorepo skill-drift guard
2087
2296
 
2088
2297
  **What.** The same skill is physically duplicated across many packages (`packages/@dzhechkov/*/​<skill>/` + `.claude/skills/<skill>/`). These two commands make that duplication safe:
@@ -2756,23 +2965,56 @@ feature-adr Step-8 asserts the ADR's load-bearing safety property **has** a test
2756
2965
  false green — it may never exercise the property, so it would stay green even if the property regressed. The
2757
2966
  `§42` gate (learned from rUv's `cve-bench/evaluate.mjs`) proves the test **discriminates**: it runs the property
2758
2967
  test in a throwaway git worktree at the pre-feature base (no fix) and requires it to go **red**.
2968
+
2969
+ **Use it when** you are about to accept "the property has a test" as evidence — in Step-8 QE, in a review of
2970
+ someone else's fix, or before trusting a regression test you did not write. Run it against `HEAD` while your
2971
+ change is still uncommitted; that is what makes `HEAD` the pre-feature base.
2972
+
2759
2973
  ```bash
2760
2974
  # the Step-7 feature diff is uncommitted mid-pipeline, so HEAD is the pre-feature base
2761
2975
  dz discrimination-check --test packages/x/test/auth-property.test.ts --base HEAD --json
2976
+
2977
+ # human output, a longer suite, and a runner that is not vitest
2978
+ dz discrimination-check --test packages/x/test/auth-property.test.ts \
2979
+ --base HEAD --runner "node --test" --timeout 600000
2762
2980
  ```
2763
2981
  ```
2764
2982
  discrimination-check @ HEAD — verdict: NON_DISCRIMINATING
2765
2983
  ✗ packages/x/test/auth-property.test.ts: NON_DISCRIMINATING
2984
+ measurementValid: true · primaryAction: strengthen-test
2766
2985
 
2767
2986
  [high] non-discriminating property test (false green)
2768
- 1 property test(s) PASS at pre-feature base — they do not exercise the ADR safety property … (Advisory — the pipeline continues; the owner decides.)
2987
+ 1 property test(s) PASS at pre-feature base WITH execution evidence — they do not exercise the ADR safety
2988
+ property and would stay green if the fix regressed … Action: strengthen-test. (Advisory — the pipeline
2989
+ continues; the owner decides.)
2769
2990
  ```
2770
- Verdicts: `DISCRIMINATES` (red by assertion — good) · `DISCRIMINATES_VIA_ERROR` (couldn't load at base, e.g. a
2771
- brand-new module inferred) · `NON_DISCRIMINATING` (green at base a false green, HIGH finding) ·
2772
- `CANNOT_ISOLATE` (no runnable property test folds into "property untested"). It **never auto-aborts** (dz's
2773
- rule: a false gate kills trust)exit 0 on any verdict, exit 2 only on a usage/setup error. The worktree +
2774
- sanitation live in tested CLI code; base ref, paths, name filter, and runner are all injection-checked, and the
2775
- worktree is always removed. Step-8 runs this on the ADR Confirmation's `Required automated check` automatically.
2991
+
2992
+ **Every verdict is gated on EXECUTION evidence.** The gate reads the runner's own output shape (vitest /
2993
+ node --test) and requires it to demonstrate that the *named* test actually ran. An outcome nobody can prove
2994
+ degrades loudly instead of minting trust — MEASURED before this change, `--runner false` (a command that
2995
+ executes nothing and prints nothing) returned `DISCRIMINATES`; it now returns `CANNOT_ISOLATE` with
2996
+ reason `unrecognised-runner-output`.
2997
+
2998
+ | Verdict | Means | ✓/✗ | Action |
2999
+ |---|---|---|---|
3000
+ | `DISCRIMINATES` | assertion-red at base, execution-evidenced | ✓ | none |
3001
+ | `DISCRIMINATES_VIA_ERROR` | evidenced load error at base **and** an evidenced pass at TIP | ✓ | none (inference — note it) |
3002
+ | `NON_DISCRIMINATING` | evidenced pass at base — a proven false green | ✗ | `strengthen-test` |
3003
+ | `TEST_FILE_ABSENT` | the named check is not a regular file (stat+isFile, before any worktree) | ✗ | `create-missing-test` |
3004
+ | `LOAD_ERROR_AT_BOTH_REVS` | could not execute at EITHER rev — zero signal | ✗ | `fix-runner-invocation` |
3005
+ | `FAILS_AT_TIP` | the feature's own test is red **with** the feature present | ✗ | `fix-red-feature-test` |
3006
+ | `CANNOT_ISOLATE` | no established observation; the row carries a typed `reason` | ✗ | `map-a-test` / `fix-runner-invocation` |
3007
+
3008
+ `--json` carries the full reading: `perTest[]` (verdict + `reason`), the per-run `evidence` rows, `findings[]`
3009
+ (**one per distinct non-clean verdict** — the scalar `aggregate` can only name the worst), `measurementValid`
3010
+ (`true | false | 'partial'` — did the instrument measure at all), `primaryAction`, and `tipTree` (the live
3011
+ tree's HEAD + dirty-file count when a tip control ran). The singular `finding` is a **deprecated** alias for
3012
+ `findings[0]`; read `findings[]`. `--timeout <ms>` (default 300000) bounds each run — a timed-out run is
3013
+ `CANNOT_ISOLATE` reason `timeout`, never a pass.
3014
+
3015
+ It **never auto-aborts** (dz's rule: a false gate kills trust) — exit 0 on any verdict, exit 2 only on a
3016
+ usage/setup error. Base ref, paths, name filter, and runner are all injection-checked, and the worktree is
3017
+ always removed. Step-8 runs this on the ADR Confirmation's `Required automated check` automatically.
2776
3018
 
2777
3019
  ### `dz guard` — when a self-mutating operation should be refused, not regretted
2778
3020
 
@@ -3506,9 +3748,20 @@ npx @dzhechkov/p-replicator init
3506
3748
 
3507
3749
  ## Status
3508
3750
 
3509
- `v0.4.6` — published on npm. Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
3751
+ `v0.4.8` — staged (not yet published). Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
3752
+
3753
+ New in 0.4.8 (feature `crossrt-1-agents-md`): `dz agents-sync` ports the fixed registry of bearing
3754
+ rules into an early root-`AGENTS.md` fence, `--check` exposes source drift to CI, and both surfaces
3755
+ report the measured Codex project-doc byte budget. A live cold-start probe, not file presence,
3756
+ remains the runtime acceptance gate.
3757
+
3758
+ New in this change (feature `dz-cli-defects`, slice A — three defects confirmed by RUNNING the CLI, then fixed):
3759
+
3760
+ - **`dz list` skips and collects** — one unparseable `SKILL.md` no longer hides the rest; the broken files are named on stderr and the exit code stays 1. Same for `dz init` / `dz install` / `dz sync`. [Details](#dz-list--one-broken-skill-never-hides-the-rest)
3761
+ - **`--target` aliases + did-you-mean** — `--target claude` (and `cc`, `agents`, `gpt`/`openai`) resolve; typos are suggested, never silently accepted. [Details](#--target-aliases-and-did-you-mean)
3762
+ - **A named refusal instead of a `SyntaxError`** — `dz` now requires `@dzhechkov/harness-core >= 0.4.7` (was `^0.4.0`, which npm could legally resolve to a core too old to link) and says so in words, before anything is imported.
3510
3763
 
3511
- New in this change: the global `dz --version` / `-v` / `dz version` surface (one parseable line), and `dz skills-verify --plugin-dir` / `--expect-commands` so slash-command registration is gate-visible. Both exist for `@dzhechkov/loop-designer-plugin`, which requires `dz` in `^0.4`, verifies it at run time, and falls back to `npx -y @dzhechkov/harness-cli@^0.4` when the `dz` on PATH is stale, unparseable or missing.
3764
+ Previously: the global `dz --version` / `-v` / `dz version` surface (one parseable line), and `dz skills-verify --plugin-dir` / `--expect-commands` so slash-command registration is gate-visible. Both exist for `@dzhechkov/loop-designer-plugin`, which requires `dz` in `^0.4`, verifies it at run time, and falls back to `npx -y @dzhechkov/harness-cli@^0.4` when the `dz` on PATH is stale, unparseable or missing.
3512
3765
 
3513
3766
  ## Claude Plugin
3514
3767
 
package/dist/bin.d.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * `dz` executable entry point.
4
+ *
5
+ * Two phases, and the split is load-bearing (feature dz-cli-defects, D5):
6
+ *
7
+ * phase 1 — ZERO `@dzhechkov/harness-core` imports: probe the installed core version
8
+ * and refuse with a NAMED message if it is below `MIN_CORE`;
9
+ * phase 2 — `await import('./cli.js')`, which is where the ~100-name static graph is
10
+ * linked. A STATIC import here would link that graph before any guard could
11
+ * run, which is exactly how a cached lower core produced a bare
12
+ * `SyntaxError: … does not provide an export named 'GRADE_SUCCESS_FLOOR'`
13
+ * with nothing pointing at the cause.
4
14
  */
5
15
  export {};
6
16
  //# sourceMappingURL=bin.d.ts.map
package/dist/bin.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;GAEG"}
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}