@dzhechkov/harness-cli 0.8.5 → 0.8.6
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 +7 -7
- package/README.md +22 -10
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +159 -33
- package/dist/cli.js.map +1 -1
- package/package.json +23 -20
- package/sbom.json +6 -6
- package/src/cli.ts +133 -20
package/.dz-manifest.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.md",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "4a54061280f2c8a3173a07e43492a73a927fdb98dccf6c1acd933735e5b9aca5"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "dist/bin.d.ts",
|
|
@@ -49,15 +49,15 @@
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"path": "dist/cli.d.ts.map",
|
|
52
|
-
"sha256": "
|
|
52
|
+
"sha256": "d02abab0b734f19ac7e75d7a28b25ae43cbfc025911128c5848f8e81ba2bf01f"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"path": "dist/cli.js",
|
|
56
|
-
"sha256": "
|
|
56
|
+
"sha256": "3ac75ba951cac7ae985b2b7407ffb2645ef36d98f44897d9094b00f4db20517f"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
"path": "dist/cli.js.map",
|
|
60
|
-
"sha256": "
|
|
60
|
+
"sha256": "c7c308fbc3d596905c25760ba8fa337656f42de06d0565f73ad7c230979a514d"
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"path": "dist/core-compat.d.ts",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"path": "package.json",
|
|
136
|
-
"sha256": "
|
|
136
|
+
"sha256": "2549a7e988b7a04071319dbbad8917d4231cd648720e70485a594ee9e3bd4aa1"
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"path": "src/bin.ts",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
"path": "src/cli.ts",
|
|
148
|
-
"sha256": "
|
|
148
|
+
"sha256": "5ff3270b1b82fe28e15d09f37d8099468102abc926512303c7ef76e6c75ecf0d"
|
|
149
149
|
},
|
|
150
150
|
{
|
|
151
151
|
"path": "src/core-compat.ts",
|
|
@@ -165,5 +165,5 @@
|
|
|
165
165
|
}
|
|
166
166
|
]
|
|
167
167
|
},
|
|
168
|
-
"signature": "
|
|
168
|
+
"signature": "Wy4woPmqLQEeqD66Hc6eyZZDUc9jyxDeSA9pKbsIZyMLu+d0VJELsfj4hOiC5bQXKRFZqyOACrHd/UBB2ugVDA=="
|
|
169
169
|
}
|
package/README.md
CHANGED
|
@@ -1374,7 +1374,7 @@ Get the whole set with `dz init --target claude-code --preset meta`, or pick one
|
|
|
1374
1374
|
| [@dzhechkov/p-replicator](https://www.npmjs.com/package/@dzhechkov/p-replicator) | `npx @dzhechkov/p-replicator init` | AI product development (/replicate pipeline) |
|
|
1375
1375
|
| [@dzhechkov/health-advisor](https://www.npmjs.com/package/@dzhechkov/health-advisor) | `npx @dzhechkov/health-advisor init` | Medical AI (25 skills) |
|
|
1376
1376
|
| [@dzhechkov/skills-bto](https://www.npmjs.com/package/@dzhechkov/skills-bto) | `npx @dzhechkov/skills-bto init` | BTO benchmarking (Build-Test-Optimize) |
|
|
1377
|
-
| [@dzhechkov/skills-feature-adr](https://www.npmjs.com/package/@dzhechkov/skills-feature-adr) | `npx @dzhechkov/skills-feature-adr init` | 11-step feature pipeline |
|
|
1377
|
+
| [@dzhechkov/skills-feature-adr](https://www.npmjs.com/package/@dzhechkov/skills-feature-adr) | `npx @dzhechkov/skills-feature-adr init` | 11-step feature pipeline with two-axis `primary` + per-family `budget` routing (`normal`/`eco`/`hybrid`); explicit stage models keep precedence |
|
|
1378
1378
|
| [@dzhechkov/skills-edu-site](https://www.npmjs.com/package/@dzhechkov/skills-edu-site) | `npx @dzhechkov/skills-edu-site init` | Gamified edu site generator |
|
|
1379
1379
|
| [@dzhechkov/skills-transcript-site](https://www.npmjs.com/package/@dzhechkov/skills-transcript-site) | `npx @dzhechkov/skills-transcript-site init` | Transcript → interactive site |
|
|
1380
1380
|
| [@dzhechkov/skills-analyst-manual](https://www.npmjs.com/package/@dzhechkov/skills-analyst-manual) | `npx @dzhechkov/skills-analyst-manual init` | 3-phase analyst composite |
|
|
@@ -1619,13 +1619,14 @@ run pkg-audit-1; sources: trace, ledger
|
|
|
1619
1619
|
The gate passed, the inventory (52 directories = 49 canonical + 2 private + 1 non-package) was
|
|
1620
1620
|
cross-checked deterministically against the filesystem, and the stale test was re-pinned to it.
|
|
1621
1621
|
|
|
1622
|
-
**And
|
|
1623
|
-
names six chunks, but only `chunk-1..3`
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1622
|
+
**And this recorded run is now the regression proof for a fixed defect.** Read the trace again: the
|
|
1623
|
+
registry names six chunks, but only `chunk-1..3` dispatched — the old renderer treated
|
|
1624
|
+
`maxFanout: 3` as a prefix cap, and the run survived only because synthesize audited the missing
|
|
1625
|
+
chunks itself. Current plans treat `maxFanout` as concurrency: all six dispatch through a three-wide
|
|
1626
|
+
window. Deliberate sampling is explicit (`overflow: "truncate"` plus a non-blank
|
|
1627
|
+
`truncateReason`) and emits a banner, a `[fanout-truncated]` stderr line, and a trace receipt. The
|
|
1628
|
+
reader now grades this historical trace `region-dispatch-completeness:fan = FAIL` and names
|
|
1629
|
+
`chunk-4..6`; a legacy projection without registry evidence is `INCONCLUSIVE`, never a guessed pass.
|
|
1629
1630
|
|
|
1630
1631
|
#### How to phrase the ASK — Claude Code vs Codex
|
|
1631
1632
|
|
|
@@ -2525,10 +2526,14 @@ dz routing recommend # per-stage args.models suggestion, printed
|
|
|
2525
2526
|
# attributed run-level — an inference, and it says so), and every skipped
|
|
2526
2527
|
# record with WHY. qe is FORCED to the cross-family of the code pick —
|
|
2527
2528
|
# a same-family qe recommendation is unrepresentable, not filtered.
|
|
2529
|
+
# A `store:` line always says current / STALE / UNFED and names
|
|
2530
|
+
# the remedy; JSON carries basis.freshness + basis.unfed.
|
|
2528
2531
|
dz routing recommend --apply # feed the samples into .dz/routing-outcomes.json (the store the
|
|
2529
2532
|
# `auto-cost` plan spec reads) — idempotent by runId: a second apply
|
|
2530
2533
|
# feeds 0 and names the skipped runs. Insufficient data is SAID
|
|
2531
2534
|
# (cold-start pick + escalation chain), never dressed as a bar-met pick.
|
|
2535
|
+
# `dz guard --op publish` warns SOFT as routing-store-stale when
|
|
2536
|
+
# harvested runIds are still missing from that store.
|
|
2532
2537
|
# (status, effort, goal, uses…) is preserved byte-for-byte,
|
|
2533
2538
|
# the previous text lands in .dz/backlog/edits.jsonl, and the
|
|
2534
2539
|
# dedup vector is re-embedded in the same bounded form.
|
|
@@ -3498,7 +3503,7 @@ invariants: HARD rules **block** the operation, SOFT rules warn. Zero config nee
|
|
|
3498
3503
|
cover the known rakes; `.dz/guard.json` (via `dz guard --init`) exists only if you want to tune a severity
|
|
3499
3504
|
or disable a rule.
|
|
3500
3505
|
```bash
|
|
3501
|
-
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · skills-registrable · lockfile-in-sync · no-stubs · review-round · licence-hold
|
|
3506
|
+
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · skills-registrable · lockfile-in-sync · marketplace-parity · no-stubs · review-round · licence-hold
|
|
3502
3507
|
dz guard check --op teach --text "the fix: export sk-abc..." # → BLOCK (exit 1): looks like a credential
|
|
3503
3508
|
dz guard log # append-only audit: every verdict + every forced override
|
|
3504
3509
|
```
|
|
@@ -3533,6 +3538,13 @@ zero specifiers, and then report every real dependency as "not recorded". The ru
|
|
|
3533
3538
|
`.dz/guard.json` cannot promote it to HARD, since a parser designed to admit "I may not understand this
|
|
3534
3539
|
file" must never be able to block a publish.
|
|
3535
3540
|
|
|
3541
|
+
The SOFT, publish-only `marketplace-parity` rule regenerates `.claude-plugin/plugin.json` and
|
|
3542
|
+
`.claude-plugin/marketplace.json` from the live registry in an isolated temp directory and compares
|
|
3543
|
+
their composition with the published showcase. It deliberately excludes `version`, which remains an
|
|
3544
|
+
operator field, and never blocks publication; composition drift warns with the exact repair command
|
|
3545
|
+
`dz plugin --version <published>`. A repository with no complete `.claude-plugin/` showcase is out of
|
|
3546
|
+
scope: the rule records an informational skip reason and emits no violation.
|
|
3547
|
+
|
|
3536
3548
|
**`review-round` (HARD, publish)** — a package that bumps its version AND changes source must bring a
|
|
3537
3549
|
GRADED `features/*/08_qe_report.md` in the same change. The gate had eleven rules and not one asked
|
|
3538
3550
|
whether anyone but the author had read the code; the cost is on the record (health-advisor slice H:
|
|
@@ -4051,7 +4063,7 @@ The self-learning loop is only compounding if every run reads and writes the **s
|
|
|
4051
4063
|
dz vector harmonize --apply --project <brain> # optional: collapse near-dup paraphrases
|
|
4052
4064
|
```
|
|
4053
4065
|
|
|
4054
|
-
- **Route
|
|
4066
|
+
- **Route by primary family, budget, or stage.** The `feature-adr` workflow accepts `primary=claude|codex`, per-family `budget=normal|eco|hybrid`, and an optional per-stage `models` map over `{router, requirements, research, adr, ideation, ddd, architecture, plan, code, qe, fleet}`. Each stage value is a **spec** — Claude `fable|opus|sonnet|haiku` or Codex `codex[:id[:reasoning]]` (ids incl. `gpt-5.5`, `gpt-5.6`). The **load-bearing default** routes unset QE to the other family than the actual coder; Codex QE uses `sol:high` under normal/hybrid and `terra:medium` under eco, with a loud Claude fallback if the selected id is unavailable. Precedence is `models[stage]` > legacy `planner`/`coder`/`qeReviewer`/`codexModel` knobs > primary/budget defaults > session-inherited. Omitting every routing knob keeps the inherited session path; the result reports `modelsUsed`.
|
|
4055
4067
|
```js
|
|
4056
4068
|
// Claude codes, Codex independently QEs (cross-model by construction):
|
|
4057
4069
|
Workflow({ scriptPath: '.claude/workflows/feature-adr.js',
|
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;AASH,OAAO,EAAoC,KAAK,EAAa,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -14,11 +14,12 @@ import { execFile, execFileSync, execSync, spawn, spawnSync } from 'node:child_p
|
|
|
14
14
|
import { createHash, randomBytes } from 'node:crypto';
|
|
15
15
|
import { homedir, tmpdir } from 'node:os';
|
|
16
16
|
import { createRequire } from 'node:module';
|
|
17
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
17
18
|
import { createSkill, getSkillInfo, listSkillsDetailed, formatSkillLoadFailures, formatSkillApplyFailures, resolveTargetName, formatTargetProblem, formatTargetAliasNote, TARGET_NAMES_SORTED, runDoctor, runInit, resolvePackageSkillRoots, PACKAGE_SKILL_LAYOUTS, benchmarkSkill, benchmarkSkills, scanMcp, reconcileCapabilities, RECONCILE_BANNER, buildRegistry, discoverSkillPackDirs, discoverVerifiablePackDirs, checkUpstream, compareSkills, checkAllUpstream, sweepSkillDrift, syncCanonicalSkill, checkUpgrades, discoverPackages, discoverSourcePackages, fetchAllDownloads, filterByCategory, pretrain, recommend, generatePlugin, publishPackages, runSetup, runMigrate, searchRegistry, runSync, runVerify, runInitAgentsMd, runInitGeminiMd, runSyncAgentsPolicy, runSyncCodexHooks, resolveCodexHome, withNamedLockSync,
|
|
18
19
|
// dz workflow run (feature dz-workflow-run): the pure scheduler + the dispatch adapters.
|
|
19
20
|
TRACE_RUNID_RE, WF_RUN_OWNER_HOST, preflight, runWorkflow, makeClaudePDispatcher, makeCodexExecDispatcher, NamedLockTimeoutError, NamedLockCompromisedError, POLICY_SOURCES, detectPolicyDrift, hasPolicyFence, TARGET_NAMES, buildParityMatrix, downgradeForStaleEvidence, findStaleTranscriptEvidence, TARGET_CAPABILITIES, TARGET_SHORT_LABELS, WORKFLOW_TEMPLATES_RETIRED_MESSAGE, parsePlan, isParseErrors, validatePlan, normalizePlan, planDigest, toTraceProjection, renderPlan, mergeRender, lint, lintExitCode, LOOP_BLOBS, parseTrace, assembleTimeline, runInvariants, deriveAttestation, stampAttestation, corroborate, NOT_WITNESSED, renderTimelineHtml, importEcc, recordPattern, resolveLearningBackend, storeStats, consolidateSessions, pruneNoisePatterns, lessonDeltaReport, removePatternsByIds, snapshotStore, recallHybrid, teachGuard, mirrorPatternsToVector, mirrorEntriesToVector, patternVectorEntry, readMemoryLearningConfig, promotePatterns, quarantineExpiryCandidates, pruneQuarantinePatterns, clearAgentdbQuarantine, vectorMirrorEnabled, vectorTierStatus, resolveVectorEngine, reindexVectorStore, harmonizeVectorStore, importRvfCheckpoint, statuslineData, writeFeatureAdrState, computeUsage, deriveCostLedger, planLedgerBackfill, listCostLedgerRuns, resolveLedgerRunId, AMBIGUOUS, stampCheckpointLine, LEDGER_FILL_SOURCE, renderCostLedger, verifyCostLedgerReport, writeCostLedgerJsonl, COST_LEDGER_SCOPE, deriveUsageCalibration, normalizeClaudeUsageModelKey, readUsageLimits, parseWeeklyResetAnchor, claimCheck, summarize, BUNDLED_SLOP_REGISTRY_URL, DEFAULT_SLOP_CONFIG, parseSlopRegistry, slopLint, validateSlopLintConfig, queryBookKnowledge, loadStorePatternsSync, patternRecordId, loadStoreRecords, recordToPattern, bundleSkills, brainHome, listBrain, bookKbPath, promoteProjectToBrain, updateBrainSource, queryBrain, groundPrompt, expandKu, reindexBrainVectors, buildPrimer, exportBrainSlice, importBrainSlice, registerKusToBrain, RECALL_USAGE_LOG_RELATIVE, RECALL_USAGE_LOG_MAX_BYTES, parseRecallUsageLog, buildRecallUsageReport, EVENT_CHAIN_TAIL_BYTES, EMPTY_LOG_TAIL, readTailInfo, appendChainedLines, verifyEventChainText, buildManifest, buildSbom, resolveTrustRoot, decideVerifyPolicy, generateSigningKeypair, evaluateGuard, resolveRules, auditRecord, guardExitCode, DEFAULT_RULES, parsePnpmLockImporters, scannableStubPath,
|
|
20
21
|
// guard-promotion (feature guard-promotion, scout idea #1)
|
|
21
|
-
assembleCandidates, renderPromotionReport, renderPromotionAdr, normalizePromotionState, nextPromotionState, globMatch, promotionAdrRelPath, DEFAULT_WINDOW_DAYS, DEFAULT_PERIODS, MAX_CONTENT_FETCHES, BUILTIN_COVERAGE, decideProvenance, isInsideTree, signManifest, verifyManifest, listSignablePackFiles, assertKeyOutsideTree, decidePublishGate, collectPackageFacts, planReleaseGates, selectAffectedPackages, classifyGateExecutions, buildFailureIssue, buildReleaseNotes, releaseTagName, firstOutputLine, formatPublishError, MANIFEST_NAME, SBOM_NAME, buildArchitectureMap, renderMapHuman, findArchitectureDrift, renderDriftReport, scanWorkspacePackages, loadSubsystemManifest, loadProductVision, checkFeatureAgainstArchitecture, renderArchCheck, planProjectSkills, guidanceForStage, renderInjectionReport, analyzeCorpus, renderRakeReport, renderCriticSection, rakeAsLesson, rakeReward, DEFAULT_RAKE_THRESHOLDS, streamSessionEvents, findLatestTranscript, detectProcessRakes, buildRetro, renderRetro, retroLessonText, PROCESS_SIGNATURES, RETRO_DOMAIN, scanForSetup, buildSetupPlan, scaffoldFromSpec, renderScaffoldPreview, readExistingForScaffold, assembleChallengeContext, buildChallengeBrief, planDiscriminationCheck, classifyDiscrimination, classifyExecutionEvidence, pickAdversaryModel, CHALLENGE_QUESTIONS, loadOutcomes, renderOutcomes, statsForKey, selectAutoCost, recordProvisional, finalizeOutcome, harvestStageOutcomes, recommendModels, planFeed, GRADE_SUCCESS_FLOOR, COST_LADDER, splitScenarios, budgetPlan, selectWinner, proseScopeOk, renderProseDiff, readScenarioIds, DEFAULT_MAX_JUDGE_RUNS, collectDeliveryFacts, planDeliveryCheck, renderDeliveryBrief, classifyDelivery, isUsablePlaneResult, renderDeliveryReview, scanSkillsLayout, declaredPluginSurface, parseInitFacts, verifyRegistration, buildContentProbePrompt, classifyContentProbe, renderContentProbe, findNonRegistrableSkillDirs, assembleCompoundingReport, buildDeadwoodReport, compactCmdUsageIfNeeded, measureCmdUsageDepthDays, recordCommandInvocation, resolveCmdUsageRoot, renderDeadwoodReport, CMD_USAGE_LOG_RELATIVE, banditStats, narrowBanditReport, renderBanditHealth,
|
|
22
|
+
assembleCandidates, renderPromotionReport, renderPromotionAdr, normalizePromotionState, nextPromotionState, globMatch, promotionAdrRelPath, DEFAULT_WINDOW_DAYS, DEFAULT_PERIODS, MAX_CONTENT_FETCHES, BUILTIN_COVERAGE, decideProvenance, isInsideTree, signManifest, verifyManifest, listSignablePackFiles, assertKeyOutsideTree, decidePublishGate, collectPackageFacts, planReleaseGates, selectAffectedPackages, classifyGateExecutions, buildFailureIssue, buildReleaseNotes, releaseTagName, firstOutputLine, formatPublishError, MANIFEST_NAME, SBOM_NAME, buildArchitectureMap, renderMapHuman, findArchitectureDrift, renderDriftReport, scanWorkspacePackages, loadSubsystemManifest, loadProductVision, checkFeatureAgainstArchitecture, renderArchCheck, planProjectSkills, guidanceForStage, renderInjectionReport, analyzeCorpus, renderRakeReport, renderCriticSection, rakeAsLesson, rakeReward, DEFAULT_RAKE_THRESHOLDS, streamSessionEvents, findLatestTranscript, detectProcessRakes, buildRetro, renderRetro, retroLessonText, PROCESS_SIGNATURES, RETRO_DOMAIN, scanForSetup, buildSetupPlan, scaffoldFromSpec, renderScaffoldPreview, readExistingForScaffold, assembleChallengeContext, buildChallengeBrief, planDiscriminationCheck, classifyDiscrimination, classifyExecutionEvidence, pickAdversaryModel, CHALLENGE_QUESTIONS, loadOutcomes, renderOutcomes, statsForKey, selectAutoCost, recordProvisional, finalizeOutcome, harvestStageOutcomes, recommendModels, planFeed, unfedRuns, GRADE_SUCCESS_FLOOR, COST_LADDER, splitScenarios, budgetPlan, selectWinner, proseScopeOk, renderProseDiff, readScenarioIds, DEFAULT_MAX_JUDGE_RUNS, collectDeliveryFacts, planDeliveryCheck, renderDeliveryBrief, classifyDelivery, isUsablePlaneResult, renderDeliveryReview, scanSkillsLayout, declaredPluginSurface, parseInitFacts, verifyRegistration, buildContentProbePrompt, classifyContentProbe, renderContentProbe, findNonRegistrableSkillDirs, assembleCompoundingReport, buildDeadwoodReport, compactCmdUsageIfNeeded, measureCmdUsageDepthDays, recordCommandInvocation, resolveCmdUsageRoot, renderDeadwoodReport, CMD_USAGE_LOG_RELATIVE, banditStats, narrowBanditReport, renderBanditHealth,
|
|
22
23
|
// Cold-vs-warm EPOCH RUNNER (feature epoch-replay) — orchestrates + scores, never calls a model.
|
|
23
24
|
replayableInstances, buildWorkOrder, buildJudgePrompts, unblindJudgments, verifyWorkOrder, isValidMargin, DIGEST_HONEST_SCOPE, scoreEpochReplay, generateMockOutcomes, renderEpochReplayResult, renderWorkOrderSummary, renderJudgePromptsSummary, WORK_ORDER_KIND, DEFAULT_MOCK_N, DEFAULT_MOCK_SEED, scoreRun, readQeGrade, recapWindow, decideHorizon, withinWindow, buildRecap, renderRecap, parseSourceManifest, tgPostHtmlIssues, tgVisibleLength, decideTgSend, TG_TEXT_LIMIT, countRecallEventsForRun, unknownFlagNotice, mirrorWriterExplanation, appendRecallUsage, closenessLine, anyAboveFloor, decideNameCheck, renderNameCheck, exportedNamesIn, dispatchedCommandsIn, decideSourceProvenance, renderSourceProvenance, REFUSED_HORIZONS, renderScorecard, renderCompoundingReport, readReinforcementState, readQuarantineState, registrationExitCode, renderRegistrationReport,
|
|
24
25
|
// Smart Backlog (feature smart-backlog) — goal-directed idea pipeline over the Brain vector engine.
|
|
@@ -115,7 +116,7 @@ Usage:
|
|
|
115
116
|
dz backlog ship <id> [<id>…] [--reason <t>] [--dry-run] [--project <dir>] [--json] (mark work DONE: new|enriched|in-progress → shipped, removing it from the roulette pool — run it after finishing a task; short id prefixes ok, ambiguous = loud error)
|
|
116
117
|
dz backlog drop <id> [<id>…] [--reason <t>] [--dry-run] [--project <dir>] [--json] (retire an idea: new|enriched|in-progress → dropped)
|
|
117
118
|
dz backlog edit <id> --text "<new>" | --append "<more>" [--dry-run] [--project <dir>] [--json] (rewrite ONE idea's text, preserving every other field; re-embeds the dedup vector, and on a failed re-embed MARKS the record embedStale so dedup refuses to trust it — previous text preserved in .dz/backlog/edits.jsonl)
|
|
118
|
-
dz routing recommend [--tier <t>] [--apply] [--json] (per-stage args.models suggestion from REAL telemetry — harness records + imported run-meta sidecars — printed WITH its basis
|
|
119
|
+
dz routing recommend [--tier <t>] [--apply] [--json] (per-stage args.models suggestion from REAL telemetry — harness records + imported run-meta sidecars — printed WITH its basis + current/STALE/UNFED store receipt; qe is FORCED cross-family of code; --apply feeds .dz/routing-outcomes.json idempotently by runId)
|
|
119
120
|
dz backlog reopen <id> [<id>…] [--reason <t>] [--dry-run] [--project <dir>] [--json] (back to the pool: shipped|dropped|in-progress → new)
|
|
120
121
|
dz backlog enrich <id> [--project <dir>] [--json] (stage the idea2prd input scaffold in features/<slug>/ and hand off to the idea2prd-manual skill — the CLI never fabricates a PRD)
|
|
121
122
|
dz backlog jira <id> [--project <dir>] [--json] (draft a Jira issue via the configurable adapter (backlog.jira.adapter: jira-mcp|copilot-mcp|none); none writes an auditable jira-outbox/<id>.json stub)
|
|
@@ -7224,6 +7225,101 @@ function gatherReadmeCounts(root) {
|
|
|
7224
7225
|
function gatherGuardFacts(op, root, text, storeCap) {
|
|
7225
7226
|
const facts = { op };
|
|
7226
7227
|
if (op === 'publish') {
|
|
7228
|
+
// Advisory I/O: unreadable telemetry or fed state is absence of evidence, never a fabricated
|
|
7229
|
+
// stale finding and never a publish blocker.
|
|
7230
|
+
try {
|
|
7231
|
+
const routing = readRoutingTelemetry(root);
|
|
7232
|
+
facts['routingFreshness'] = { unfedRunIds: unfedRuns(routing.harvest.samples, routing.alreadyFed) };
|
|
7233
|
+
}
|
|
7234
|
+
catch { /* fail-open: routing-store-stale is SOFT and needs gathered evidence */ }
|
|
7235
|
+
// marketplace-parity: regenerate the two published showcase manifests from the LIVE registry,
|
|
7236
|
+
// but redirect every write to a unique temp root. Version is operator-owned, so pinning the
|
|
7237
|
+
// published value into generatePlugin makes the comparison composition-only by construction.
|
|
7238
|
+
try {
|
|
7239
|
+
const showcaseDir = join(root, '.claude-plugin');
|
|
7240
|
+
if (!existsSync(showcaseDir)) {
|
|
7241
|
+
facts['marketplaceParity'] = { applicable: false };
|
|
7242
|
+
}
|
|
7243
|
+
else {
|
|
7244
|
+
const pluginPath = join(showcaseDir, 'plugin.json');
|
|
7245
|
+
const marketplacePath = join(showcaseDir, 'marketplace.json');
|
|
7246
|
+
const hasPlugin = existsSync(pluginPath);
|
|
7247
|
+
const hasMarketplace = existsSync(marketplacePath);
|
|
7248
|
+
const manifestFailures = [];
|
|
7249
|
+
const readManifest = (path, file) => {
|
|
7250
|
+
try {
|
|
7251
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
7252
|
+
}
|
|
7253
|
+
catch (error) {
|
|
7254
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7255
|
+
manifestFailures.push({ file, error: message.replace(/\s+/g, ' ').slice(0, 240) });
|
|
7256
|
+
return undefined;
|
|
7257
|
+
}
|
|
7258
|
+
};
|
|
7259
|
+
const versionOf = (manifest) => {
|
|
7260
|
+
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest))
|
|
7261
|
+
return undefined;
|
|
7262
|
+
const version = manifest['version'];
|
|
7263
|
+
return typeof version === 'string' && version !== '' ? version : undefined;
|
|
7264
|
+
};
|
|
7265
|
+
const publishedPlugin = hasPlugin ? readManifest(pluginPath, 'plugin.json') : undefined;
|
|
7266
|
+
const publishedMarketplace = hasMarketplace ? readManifest(marketplacePath, 'marketplace.json') : undefined;
|
|
7267
|
+
const marketplaceRecord = publishedMarketplace && typeof publishedMarketplace === 'object' && !Array.isArray(publishedMarketplace)
|
|
7268
|
+
? publishedMarketplace
|
|
7269
|
+
: undefined;
|
|
7270
|
+
const marketplacePlugins = marketplaceRecord !== undefined && Array.isArray(marketplaceRecord['plugins'])
|
|
7271
|
+
? marketplaceRecord['plugins']
|
|
7272
|
+
: [];
|
|
7273
|
+
const publishedVersion = versionOf(publishedPlugin)
|
|
7274
|
+
?? versionOf(publishedMarketplace)
|
|
7275
|
+
?? versionOf(marketplacePlugins[0]);
|
|
7276
|
+
if (manifestFailures.length > 0) {
|
|
7277
|
+
facts['marketplaceParity'] = {
|
|
7278
|
+
applicable: true,
|
|
7279
|
+
manifestFailures,
|
|
7280
|
+
...(publishedVersion !== undefined ? { publishedVersion } : {}),
|
|
7281
|
+
};
|
|
7282
|
+
}
|
|
7283
|
+
else if (hasPlugin !== hasMarketplace) {
|
|
7284
|
+
facts['marketplaceParity'] = {
|
|
7285
|
+
applicable: true,
|
|
7286
|
+
onlyOnePresent: true,
|
|
7287
|
+
...(publishedVersion !== undefined ? { publishedVersion } : {}),
|
|
7288
|
+
};
|
|
7289
|
+
}
|
|
7290
|
+
else if (!hasPlugin) {
|
|
7291
|
+
facts['marketplaceParity'] = { applicable: false };
|
|
7292
|
+
}
|
|
7293
|
+
else {
|
|
7294
|
+
let scratch;
|
|
7295
|
+
try {
|
|
7296
|
+
const registry = buildRegistry(root);
|
|
7297
|
+
scratch = mkdtempSync(join(tmpdir(), 'dz-guard-marketplace-'));
|
|
7298
|
+
const generated = generatePlugin(scratch, registry, { version: publishedVersion });
|
|
7299
|
+
const freshPlugin = JSON.parse(readFileSync(generated.pluginJsonPath, 'utf8'));
|
|
7300
|
+
const freshMarketplace = JSON.parse(readFileSync(generated.marketplaceJsonPath, 'utf8'));
|
|
7301
|
+
facts['marketplaceParity'] = {
|
|
7302
|
+
applicable: true,
|
|
7303
|
+
diverged: !isDeepStrictEqual(publishedPlugin, freshPlugin)
|
|
7304
|
+
|| !isDeepStrictEqual(publishedMarketplace, freshMarketplace),
|
|
7305
|
+
...(publishedVersion !== undefined ? { publishedVersion } : {}),
|
|
7306
|
+
};
|
|
7307
|
+
}
|
|
7308
|
+
catch {
|
|
7309
|
+
facts['marketplaceParity'] = {
|
|
7310
|
+
applicable: true,
|
|
7311
|
+
regenerateFailed: true,
|
|
7312
|
+
...(publishedVersion !== undefined ? { publishedVersion } : {}),
|
|
7313
|
+
};
|
|
7314
|
+
}
|
|
7315
|
+
finally {
|
|
7316
|
+
if (scratch !== undefined)
|
|
7317
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
}
|
|
7322
|
+
catch { /* fail-open only on unexpected showcase-discovery failure; manifest read/parse errors are structured violations above */ }
|
|
7227
7323
|
// agents-md-policy-sync: fixed registry, no tree walk. The pure detector
|
|
7228
7324
|
// recomputes every expected hash from current source text; this gatherer
|
|
7229
7325
|
// only supplies bytes. Any unexpected gather failure omits the fact, and
|
|
@@ -14016,6 +14112,44 @@ async function cmdBacklog(options, flags, cwd, write) {
|
|
|
14016
14112
|
write(' harmonize [--apply][--threshold 0-1] batch semantic dedup of the backlog');
|
|
14017
14113
|
return sub === undefined ? 0 : 1;
|
|
14018
14114
|
}
|
|
14115
|
+
/** Read the recommender's existing telemetry planes plus its idempotency receipt. One adapter is
|
|
14116
|
+
* shared by `recommend` and the publish advisory so their freshness definitions cannot drift. */
|
|
14117
|
+
function readRoutingTelemetry(repoRoot) {
|
|
14118
|
+
const records = readHarnessRecords(repoRoot);
|
|
14119
|
+
for (const base of [join(repoRoot, 'features'), join(repoRoot, '.dz', 'loop-trace')]) {
|
|
14120
|
+
if (!existsSync(base))
|
|
14121
|
+
continue;
|
|
14122
|
+
let names = [];
|
|
14123
|
+
try {
|
|
14124
|
+
names = readdirSync(base);
|
|
14125
|
+
}
|
|
14126
|
+
catch {
|
|
14127
|
+
continue;
|
|
14128
|
+
}
|
|
14129
|
+
for (const name of names) {
|
|
14130
|
+
const sidecar = join(base, name, 'run-meta.json');
|
|
14131
|
+
if (!existsSync(sidecar))
|
|
14132
|
+
continue;
|
|
14133
|
+
try {
|
|
14134
|
+
const meta = JSON.parse(readFileSync(sidecar, 'utf-8'));
|
|
14135
|
+
if (meta.runMeta?.resolved === true && Array.isArray(meta.runMeta.records))
|
|
14136
|
+
records.push(...meta.runMeta.records);
|
|
14137
|
+
}
|
|
14138
|
+
catch { /* an unreadable sidecar contributes no asserted record */ }
|
|
14139
|
+
}
|
|
14140
|
+
}
|
|
14141
|
+
let alreadyFed = [];
|
|
14142
|
+
const fedPath = join(repoRoot, '.dz', 'routing-fed.json');
|
|
14143
|
+
if (existsSync(fedPath)) {
|
|
14144
|
+
const parsed = JSON.parse(readFileSync(join(repoRoot, '.dz', 'routing-fed.json'), 'utf-8'));
|
|
14145
|
+
if (!Array.isArray(parsed))
|
|
14146
|
+
throw new Error('.dz/routing-fed.json must be a JSON array of runIds');
|
|
14147
|
+
if (parsed.some((v) => typeof v !== 'string'))
|
|
14148
|
+
throw new Error('.dz/routing-fed.json contains a non-string runId');
|
|
14149
|
+
alreadyFed = parsed;
|
|
14150
|
+
}
|
|
14151
|
+
return { harvest: harvestStageOutcomes(records), alreadyFed };
|
|
14152
|
+
}
|
|
14019
14153
|
/**
|
|
14020
14154
|
* `dz routing` — inspect the learned cost-optimal routing outcome store (feature learned-cost-routing). Shows
|
|
14021
14155
|
* what `args.models[stage]='auto-cost'` currently believes per (stage, complexity-tier, model): gated
|
|
@@ -14032,40 +14166,22 @@ function cmdRouting(options, flags, cwd, write) {
|
|
|
14032
14166
|
// ── recommend — harvest real telemetry, print per-stage picks WITH THE BASIS, optionally feed the
|
|
14033
14167
|
// store (a9c3dd5c fn 3, ADR-001). Sources: live harness records + imported run-meta.json sidecars.
|
|
14034
14168
|
if (options.get('_positional_0') === 'recommend') {
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
names = readdirSync(base);
|
|
14043
|
-
}
|
|
14044
|
-
catch {
|
|
14045
|
-
continue;
|
|
14046
|
-
}
|
|
14047
|
-
for (const name of names) {
|
|
14048
|
-
const sidecar = join(base, name, 'run-meta.json');
|
|
14049
|
-
if (!existsSync(sidecar))
|
|
14050
|
-
continue;
|
|
14051
|
-
try {
|
|
14052
|
-
const meta = JSON.parse(readFileSync(sidecar, 'utf-8'));
|
|
14053
|
-
if (meta.runMeta?.resolved === true && Array.isArray(meta.runMeta.records))
|
|
14054
|
-
records.push(...meta.runMeta.records);
|
|
14055
|
-
}
|
|
14056
|
-
catch { /* an unreadable sidecar contributes nothing — counted below as noResult */ }
|
|
14057
|
-
}
|
|
14169
|
+
let routing;
|
|
14170
|
+
try {
|
|
14171
|
+
routing = readRoutingTelemetry(repoRoot);
|
|
14172
|
+
}
|
|
14173
|
+
catch (e) {
|
|
14174
|
+
write(`dz routing recommend: cannot read routing freshness state — ${e.message}`);
|
|
14175
|
+
return 1;
|
|
14058
14176
|
}
|
|
14059
|
-
const harvest =
|
|
14060
|
-
|
|
14177
|
+
const harvest = routing.harvest;
|
|
14178
|
+
let rec = recommendModels(harvest, {
|
|
14179
|
+
...(options.get('tier') !== undefined ? { tier: options.get('tier') } : {}),
|
|
14180
|
+
alreadyFed: routing.alreadyFed,
|
|
14181
|
+
});
|
|
14061
14182
|
if (flags.has('apply')) {
|
|
14062
14183
|
const fedPath = join(repoRoot, '.dz', 'routing-fed.json');
|
|
14063
|
-
|
|
14064
|
-
try {
|
|
14065
|
-
alreadyFed = JSON.parse(readFileSync(fedPath, 'utf-8'));
|
|
14066
|
-
}
|
|
14067
|
-
catch { /* first apply */ }
|
|
14068
|
-
const plan = planFeed(harvest.samples, alreadyFed);
|
|
14184
|
+
const plan = planFeed(harvest.samples, routing.alreadyFed);
|
|
14069
14185
|
for (const sample of plan.toFeed)
|
|
14070
14186
|
finalizeOutcome(repoRoot, sample.stage, sample.tier, sample.model, sample.success);
|
|
14071
14187
|
try {
|
|
@@ -14076,6 +14192,10 @@ function cmdRouting(options, flags, cwd, write) {
|
|
|
14076
14192
|
write(`dz routing recommend: fed ${plan.toFeed.length} sample(s) but could NOT persist the fed-set — a re-apply WILL double-count: ${e.message}`);
|
|
14077
14193
|
return 1;
|
|
14078
14194
|
}
|
|
14195
|
+
rec = recommendModels(harvest, {
|
|
14196
|
+
...(options.get('tier') !== undefined ? { tier: options.get('tier') } : {}),
|
|
14197
|
+
alreadyFed: plan.fedAfter,
|
|
14198
|
+
});
|
|
14079
14199
|
write(`dz routing recommend --apply: fed ${plan.toFeed.length} sample(s) into .dz/routing-outcomes.json${plan.skippedRuns.length > 0 ? `; skipped ${plan.skippedRuns.length} already-fed run(s) (idempotent by runId)` : ''}`);
|
|
14080
14200
|
}
|
|
14081
14201
|
if (flags.has('json')) {
|
|
@@ -14087,6 +14207,12 @@ function cmdRouting(options, flags, cwd, write) {
|
|
|
14087
14207
|
write(` ${s.stage.padEnd(14)} ${s.spec.padEnd(20)} ${s.insufficientData ? '[insufficient data — cold-start pick]' : '[quality bar met]'} ${s.pick.evidence}`);
|
|
14088
14208
|
}
|
|
14089
14209
|
write(` basis: ${rec.basis.rule}`);
|
|
14210
|
+
if (rec.basis.freshness === 'current')
|
|
14211
|
+
write(' store: current (0 unharvested runs)');
|
|
14212
|
+
else if (rec.basis.freshness === 'stale')
|
|
14213
|
+
write(` store: STALE — ${rec.basis.unfed.count} run(s) harvested but never fed; auto-cost is routing from an older snapshot — run \`dz routing recommend --apply\``);
|
|
14214
|
+
else
|
|
14215
|
+
write(' store: UNFED — auto-cost has no learned rows; picks below are cold-start');
|
|
14090
14216
|
write(` basis: skipped records — no result ${rec.basis.skipped.noResult}, no modelsUsed ${rec.basis.skipped.noModels} (predates model routing — history, not an error), no grade ${rec.basis.skipped.noGrade}, unknown model ${rec.basis.skipped.unknownModel}`);
|
|
14091
14217
|
write(` basis: ${rec.basis.crossFamilyNote}`);
|
|
14092
14218
|
return 0;
|