@dzhechkov/harness-cli 0.4.3 → 0.4.5
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 +3 -3
- package/README.md +132 -1
- package/package.json +10 -10
- package/sbom.json +2 -2
- package/LICENSE +0 -21
package/.dz-manifest.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.md",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "2f053f11ea49780919d0557877302e70adb8f33949299b0b0637ece2809c1b67"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "coverage/coverage-final.json",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"path": "package.json",
|
|
72
|
-
"sha256": "
|
|
72
|
+
"sha256": "00a53276d145112e3c2ae5ca2950ac74877ea4b069b2b81040d49c5903eb6482"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"path": "src/bin.ts",
|
|
@@ -221,5 +221,5 @@
|
|
|
221
221
|
}
|
|
222
222
|
]
|
|
223
223
|
},
|
|
224
|
-
"signature": "
|
|
224
|
+
"signature": "6IQyjN4aazsr6EyD1+y/VrZ1+bclvxc9nXsCLR3WVDomAn6AhNtlTJQWdfbvw49A4/HH+KTW+KkJlj/gFFnqCw=="
|
|
225
225
|
}
|
package/README.md
CHANGED
|
@@ -1141,6 +1141,137 @@ host run there is nothing to read, and it says so rather than inventing a timeli
|
|
|
1141
1141
|
follows from the same boundary: on a non-Claude-Code target the authoring and lint verbs work
|
|
1142
1142
|
unchanged, and only execution is absent.
|
|
1143
1143
|
|
|
1144
|
+
### Build a loop for YOUR scenario — the end-to-end use case (a real one)
|
|
1145
|
+
|
|
1146
|
+
This walkthrough is not an invented example. It is the loop that closed a real roadmap item in this
|
|
1147
|
+
very repo: a test pinned `34 canonical packages` while the workspace had grown past 50 directories —
|
|
1148
|
+
red forever, and nobody trusted a hand count. The job: produce a **verified inventory** of every
|
|
1149
|
+
directory under `packages/@dzhechkov` (canonical vs private vs not-a-package), too much for one
|
|
1150
|
+
sitting → an audit fanout: package chunks audited in parallel lanes, one synthesis, and a quality
|
|
1151
|
+
gate that rejects an inventory that doesn't cover every directory. Every command and output below is
|
|
1152
|
+
a capture from the run that actually fixed the test (MEASURED — reproducer
|
|
1153
|
+
`node --test tests/canonical-packages.test.mjs`: 289 pass / 0 fail after the re-pin).
|
|
1154
|
+
|
|
1155
|
+
**Install (once):**
|
|
1156
|
+
|
|
1157
|
+
```bash
|
|
1158
|
+
npm i -g @dzhechkov/harness-cli # gives you the `dz` binary
|
|
1159
|
+
# or zero-install per call: npx @dzhechkov/harness-cli workflow init …
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
**The division of labour, honestly stated up front:** `dz` AUTHORS, GATES and READS loops — it never
|
|
1163
|
+
RUNS one. Execution belongs to a host with the `Workflow({scriptPath})` runtime, which today means
|
|
1164
|
+
**Claude Code**. So: author anywhere (Codex included), run under Claude Code.
|
|
1165
|
+
|
|
1166
|
+
#### Step 1 — scaffold the plan shape closest to your scenario
|
|
1167
|
+
|
|
1168
|
+
```bash
|
|
1169
|
+
dz workflow init --name pkg-inventory-audit --pattern fanout --o audit.plan.json
|
|
1170
|
+
# → wrote audit.plan.json (pattern: fanout)
|
|
1171
|
+
# → Next: edit the TODO prompts, then `dz workflow validate` + `dz workflow render`.
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
Patterns: `pipeline` (A→B→C), `barrier` (all A, then B), `fanout` (N parallel lanes + a join),
|
|
1175
|
+
`gate` (a checked step with a redo route). The scaffold is a REAL plan with `TODO` prompts — not a
|
|
1176
|
+
template you fight.
|
|
1177
|
+
|
|
1178
|
+
#### Step 2 — make it yours (edit the JSON)
|
|
1179
|
+
|
|
1180
|
+
Fill the `TODO` prompts, name your work units in `fanouts[].registry`, and add the quality gate
|
|
1181
|
+
with a redo route. The real plan's shape (abridged from
|
|
1182
|
+
`features/pkg-inventory-audit/audit.plan.json` in this repo):
|
|
1183
|
+
|
|
1184
|
+
```json
|
|
1185
|
+
"fanouts": [ { "stage": "fan", "chain": ["lane"], "maxFanout": 3,
|
|
1186
|
+
"registry": ["chunk-1","chunk-2","chunk-3","chunk-4","chunk-5","chunk-6"] } ],
|
|
1187
|
+
"joins": [ { "stage": "jn", "forStage": "fan", "joinPolicy": "all-activated",
|
|
1188
|
+
"onInvalid": "named-failure" } ],
|
|
1189
|
+
"steps": [ …lanes…, { "stepId": "synthesize", "kind": "agent", "deps": ["jn"],
|
|
1190
|
+
"prompt": "Merge the lane JSONs into one inventory. Return STRICT JSON…" },
|
|
1191
|
+
{ "stepId": "check", "kind": "gate", "deps": ["synthesize"],
|
|
1192
|
+
"prompt": "…counts.total must equal 52… answer GATE: PASS or GATE: FAIL" } ],
|
|
1193
|
+
"gates": [ { "stepId": "check", "kind": "quality", "failRoute": "synthesize", "maxRedos": 1 } ]
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
The plan surface is deliberately NARROW and fully enacted: anything the generated loop would not
|
|
1197
|
+
actually perform is REJECTED at validate time with a named `ENACT-*` diagnostic — never silently
|
|
1198
|
+
accepted and ignored.
|
|
1199
|
+
|
|
1200
|
+
#### Step 3 — validate, render, lint (the three gates before any run)
|
|
1201
|
+
|
|
1202
|
+
```bash
|
|
1203
|
+
dz workflow validate audit.plan.json
|
|
1204
|
+
# → dz workflow validate: OK (digest sha256:70992d9ddc86de15…)
|
|
1205
|
+
|
|
1206
|
+
dz workflow render audit.plan.json --o audit.loop.js
|
|
1207
|
+
# → wrote audit.loop.plan.json then audit.loop.js (exec-fp sha256:49feb8a2c1e17038…, blobs: trace)
|
|
1208
|
+
|
|
1209
|
+
dz workflow-lint audit.loop.js --plan audit.loop.plan.json --require-plan
|
|
1210
|
+
# → dz workflow-lint: PASS (mode=require-plan; 0 fail, 1 warn, 0 inconclusive over 17 rules)
|
|
1211
|
+
```
|
|
1212
|
+
|
|
1213
|
+
`inconclusive` is never a pass, and the rendered script keeps your hand edits across re-renders
|
|
1214
|
+
(USER regions are preserved).
|
|
1215
|
+
|
|
1216
|
+
#### Step 4 — run it (Claude Code), read it back (anywhere)
|
|
1217
|
+
|
|
1218
|
+
In **Claude Code**, paste exactly this shape:
|
|
1219
|
+
|
|
1220
|
+
> Запусти мой цикл: `Workflow({ scriptPath: 'audit.loop.js', args: { traceDir: '.dz/loop-trace/pkg-audit-1', runId: 'pkg-audit-1' } })` — и когда закончит, покажи `dz workflow-trace --run pkg-audit-1`.
|
|
1221
|
+
|
|
1222
|
+
What the real run produced (captured verbatim; the trace lives at `.dz/loop-trace/pkg-audit-1/` in
|
|
1223
|
+
this repo):
|
|
1224
|
+
|
|
1225
|
+
```
|
|
1226
|
+
run pkg-audit-1; sources: trace, ledger
|
|
1227
|
+
1 run.opened plan=70992d9ddc86 exec-fp=49feb8a2c1e1
|
|
1228
|
+
2 dispatch lane:chunk-1#1 phase=Lanes
|
|
1229
|
+
3 dispatch lane:chunk-2#1 phase=Lanes
|
|
1230
|
+
4 dispatch lane:chunk-3#1 phase=Lanes
|
|
1231
|
+
5..7 settle lane:chunk-{1,2,3} outcome=ok
|
|
1232
|
+
8 dispatch synthesize#1 phase=Synthesize
|
|
1233
|
+
9 settle synthesize#4 outcome=ok
|
|
1234
|
+
10 dispatch check#1 phase=Gate causedBy=[9]
|
|
1235
|
+
11 settle check#5 outcome=ok ← GATE: PASS
|
|
1236
|
+
12 run.closed {"dispatched":5,"settled":5}
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
The gate passed, the inventory (52 directories = 49 canonical + 2 private + 1 non-package) was
|
|
1240
|
+
cross-checked deterministically against the filesystem, and the stale test was re-pinned to it.
|
|
1241
|
+
|
|
1242
|
+
**And the run surfaced a real defect — kept here on purpose.** Read the trace again: the registry
|
|
1243
|
+
names six chunks, but only `chunk-1..3` ever dispatched — `maxFanout: 3` **silently truncated** the
|
|
1244
|
+
other three lanes, and the run stayed green only because the synthesize agent noticed the gap and
|
|
1245
|
+
audited the missing chunks with its own tools. That is exactly what the trace is for: it shows what
|
|
1246
|
+
your loop *did*, not what the plan promised. (Filed in this repo's backlog: over-registry items must
|
|
1247
|
+
become a named failure or a loud trace event, never a silent drop. Until then: keep
|
|
1248
|
+
`fanouts[].registry.length ≤ maxFanout`, and read the trace after the first run of any new plan.)
|
|
1249
|
+
|
|
1250
|
+
#### How to phrase the ASK — Claude Code vs Codex
|
|
1251
|
+
|
|
1252
|
+
**In Claude Code** (it has both `dz` and the `Workflow` runtime — one message does the whole thing):
|
|
1253
|
+
|
|
1254
|
+
> Собери мне цикл под сценарий: «<опиши свой — источники, что делает каждая полоса, как сводить,
|
|
1255
|
+
> какой критерий качества>». Используй `dz workflow init/validate/render/workflow-lint`, покажи мне
|
|
1256
|
+
> план НА СОГЛАСОВАНИЕ до рендера, потом запусти через `Workflow({scriptPath})` и дай ссылку на
|
|
1257
|
+
> `workflow-trace` отчёт.
|
|
1258
|
+
|
|
1259
|
+
The "покажи план до рендера" clause matters: the plan JSON is the one artifact worth your review —
|
|
1260
|
+
prompts, lanes, gate criteria, budgets — and it is small.
|
|
1261
|
+
|
|
1262
|
+
**In Codex** (or any shell-capable agent — AUTHORING only, honestly):
|
|
1263
|
+
|
|
1264
|
+
> In this repo, run `npx @dzhechkov/harness-cli workflow init --name <x> --pattern fanout --o x.plan.json`,
|
|
1265
|
+
> then edit the plan for this scenario: <describe>. Run `workflow validate` and fix every diagnostic
|
|
1266
|
+
> it names, then `workflow render` and `workflow-lint --require-plan`. Do NOT attempt to execute the
|
|
1267
|
+
> generated loop — it runs under Claude Code's `Workflow({scriptPath})` runtime; hand me the green
|
|
1268
|
+
> plan and the rendered script.
|
|
1269
|
+
|
|
1270
|
+
Codex is a fine plan AUTHOR — the validate/lint diagnostics are named and machine-checkable, so its
|
|
1271
|
+
edit loop converges. What it cannot do is run the result: the generated script calls the host's
|
|
1272
|
+
`agent()`/`parallel()` sandbox, which only the Claude Code Workflow runtime provides. A green lint
|
|
1273
|
+
from Codex + a run under Claude Code is a legitimate two-agent split.
|
|
1274
|
+
|
|
1144
1275
|
### Move a run's telemetry to another machine (`workflow-trace export` / `import`)
|
|
1145
1276
|
|
|
1146
1277
|
A run leaves traces on the machine that produced it. `export` puts one run's telemetry into a single
|
|
@@ -3303,7 +3434,7 @@ npx @dzhechkov/p-replicator init
|
|
|
3303
3434
|
|
|
3304
3435
|
## Status
|
|
3305
3436
|
|
|
3306
|
-
`v0.4.
|
|
3437
|
+
`v0.4.5` — published on npm. Also available as [Claude Plugin](#claude-plugin). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness-hub).
|
|
3307
3438
|
|
|
3308
3439
|
## Claude Plugin
|
|
3309
3440
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot. 35 commands, 13 presets, 6 platform targets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,6 +40,13 @@
|
|
|
40
40
|
".dz-manifest.json",
|
|
41
41
|
"sbom.json"
|
|
42
42
|
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"lint": "tsc -p tsconfig.json --noEmit"
|
|
49
|
+
},
|
|
43
50
|
"dependencies": {
|
|
44
51
|
"@dzhechkov/harness-core": "^0.4.0",
|
|
45
52
|
"@dzhechkov/harness-presets": "^0.5.0",
|
|
@@ -75,12 +82,5 @@
|
|
|
75
82
|
"url": "https://github.com/djd1m/dz-harness-hub.git",
|
|
76
83
|
"directory": "packages/@dzhechkov/harness-cli"
|
|
77
84
|
},
|
|
78
|
-
"homepage": "https://github.com/djd1m/dz-harness-hub/tree/main/packages/@dzhechkov/harness-cli#readme"
|
|
79
|
-
|
|
80
|
-
"build": "tsc -p tsconfig.json",
|
|
81
|
-
"test": "vitest run",
|
|
82
|
-
"test:watch": "vitest",
|
|
83
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
84
|
-
"lint": "tsc -p tsconfig.json --noEmit"
|
|
85
|
-
}
|
|
86
|
-
}
|
|
85
|
+
"homepage": "https://github.com/djd1m/dz-harness-hub/tree/main/packages/@dzhechkov/harness-cli#readme"
|
|
86
|
+
}
|
package/sbom.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"hashes": [
|
|
26
26
|
{
|
|
27
27
|
"alg": "SHA-256",
|
|
28
|
-
"content": "
|
|
28
|
+
"content": "2f053f11ea49780919d0557877302e70adb8f33949299b0b0637ece2809c1b67"
|
|
29
29
|
}
|
|
30
30
|
]
|
|
31
31
|
},
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"hashes": [
|
|
176
176
|
{
|
|
177
177
|
"alg": "SHA-256",
|
|
178
|
-
"content": "
|
|
178
|
+
"content": "00a53276d145112e3c2ae5ca2950ac74877ea4b069b2b81040d49c5903eb6482"
|
|
179
179
|
}
|
|
180
180
|
]
|
|
181
181
|
},
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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.
|