@dzhechkov/harness-cli 0.8.21 → 0.8.22

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.
@@ -1 +1 @@
1
- {"version":3,"file":"known-flags.d.ts","sourceRoot":"","sources":["../src/known-flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EA2T5C,CAAC"}
1
+ {"version":3,"file":"known-flags.d.ts","sourceRoot":"","sources":["../src/known-flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EA4T5C,CAAC"}
@@ -324,5 +324,6 @@ export const KNOWN_CLI_FLAGS = [
324
324
  'write',
325
325
  'year',
326
326
  'yes',
327
+ 'mirror-cmd', // dz publish epilogue (mirror-push-on-publish)
327
328
  ];
328
329
  //# sourceMappingURL=known-flags.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"known-flags.js","sourceRoot":"","sources":["../src/known-flags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"known-flags.js","sourceRoot":"","sources":["../src/known-flags.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/harness-cli",
3
- "version": "0.8.21",
3
+ "version": "0.8.22",
4
4
  "description": "The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot. 87 commands, 14 presets, 10 platform targets.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,16 +42,16 @@
42
42
  "src"
43
43
  ],
44
44
  "dependencies": {
45
- "@dzhechkov/harness-core": "^0.8.29",
45
+ "@dzhechkov/harness-core": "^0.8.30",
46
46
  "@dzhechkov/harness-presets": "^0.5.18",
47
- "@dzhechkov/skills-mcp": "^0.3.10",
48
- "@dzhechkov/scout": "^0.8.11",
49
47
  "@dzhechkov/skills-devops": "^0.3.17",
48
+ "@dzhechkov/scout": "^0.8.11",
49
+ "@dzhechkov/skills-mcp": "^0.3.10",
50
50
  "@dzhechkov/skills-web3": "^0.2.9",
51
- "@dzhechkov/skills-meta": "^0.9.55",
52
51
  "@dzhechkov/skills-qe": "^0.3.14",
53
52
  "@dzhechkov/skills-academic": "^0.3.7",
54
53
  "@dzhechkov/skills-ecc": "^0.1.12",
54
+ "@dzhechkov/skills-meta": "^0.9.55",
55
55
  "@dzhechkov/skills-news": "^0.1.16",
56
56
  "@dzhechkov/skills-pm": "^0.1.5",
57
57
  "@dzhechkov/skills-taste": "^0.1.5",
@@ -83,6 +83,7 @@
83
83
  "scripts": {
84
84
  "build": "tsc -p tsconfig.json",
85
85
  "test": "vitest run",
86
+ "test:coverage": "vitest run --coverage",
86
87
  "test:watch": "vitest",
87
88
  "typecheck": "tsc -p tsconfig.json --noEmit",
88
89
  "lint": "tsc -p tsconfig.json --noEmit"
package/sbom.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "hashes": [
26
26
  {
27
27
  "alg": "SHA-256",
28
- "content": "2a3c1e1f9f922913c45df3482f2055ac2efc726108e1d4377195739e026a4034"
28
+ "content": "469aec881b39fe2b3e032bf75354fb7e998a08695327a74a69e0de90ad36a934"
29
29
  }
30
30
  ]
31
31
  },
@@ -115,7 +115,7 @@
115
115
  "hashes": [
116
116
  {
117
117
  "alg": "SHA-256",
118
- "content": "a4f6ad121c0e81336e517b10ba656af428cc07d9f41fdc00967d1cd0122be1ee"
118
+ "content": "9c58b7696526c47244bf5933ddc7ae3d7d43f025f1e74096cd90bfbe5aaada53"
119
119
  }
120
120
  ]
121
121
  },
@@ -125,7 +125,7 @@
125
125
  "hashes": [
126
126
  {
127
127
  "alg": "SHA-256",
128
- "content": "ef3852bb748f37d4e78a9a973505c3993eae2b996cc0cdd0659f531aa76621f4"
128
+ "content": "613f870e75033657b8f68ee4650c4699dce036c08393b588b2ff7ca399dd688f"
129
129
  }
130
130
  ]
131
131
  },
@@ -135,7 +135,7 @@
135
135
  "hashes": [
136
136
  {
137
137
  "alg": "SHA-256",
138
- "content": "9d0a6cc044810b31d261b36913e3f63445f5e96550176fedd0faf606d8cbcd75"
138
+ "content": "112231fa1707bde97a6529c9cf2ad5c81e9d5e382b3a2b1fae89782b9918748a"
139
139
  }
140
140
  ]
141
141
  },
@@ -145,7 +145,7 @@
145
145
  "hashes": [
146
146
  {
147
147
  "alg": "SHA-256",
148
- "content": "3049258ffd0972b6a748eda703221911dd33e3450486c1dec0f598a431faa038"
148
+ "content": "dae7aacba3d82f15c882ebadaca268161159e5b9dfd278ace4e8b802e12d858e"
149
149
  }
150
150
  ]
151
151
  },
@@ -325,7 +325,7 @@
325
325
  "hashes": [
326
326
  {
327
327
  "alg": "SHA-256",
328
- "content": "703058c8bbf0307ab29f12f8355c8984508f38214c32ab85da790446f0cb9699"
328
+ "content": "6b514318ec7c607ce7c6e9f7faccc98f2ddde0f2949aec4b730f0f104ef476c6"
329
329
  }
330
330
  ]
331
331
  },
@@ -335,7 +335,7 @@
335
335
  "hashes": [
336
336
  {
337
337
  "alg": "SHA-256",
338
- "content": "6bae6e7f551b6024e3212655f4c5a8f9e426ae0858ff3e65f08d0539bb617028"
338
+ "content": "a787a333c01e1e0c323581ac605884546011f9d2dbcbc1a0e8cadadb62e70695"
339
339
  }
340
340
  ]
341
341
  },
@@ -345,7 +345,7 @@
345
345
  "hashes": [
346
346
  {
347
347
  "alg": "SHA-256",
348
- "content": "9edabc481a2545ac56ddfdfba82623cd3ac1cf8a37551b5ff43930bf5f2ef48f"
348
+ "content": "8d182f4b1175c8b89cf48fe2cea671f060dc89850b9564669efd4e516b9e61bf"
349
349
  }
350
350
  ]
351
351
  },
@@ -379,7 +379,7 @@
379
379
  },
380
380
  {
381
381
  "name": "dz:canonical-json-sha256-v2",
382
- "value": "52e0e71990b14cf8dc5b07046c30d6d9807f7cec1cdef4463ac6bd155b0312d4"
382
+ "value": "dd1df9b570449d53d4ec48e40df48cc23d78aefd0d2724cbf4aaede96645ebb6"
383
383
  }
384
384
  ]
385
385
  },
@@ -409,7 +409,7 @@
409
409
  "hashes": [
410
410
  {
411
411
  "alg": "SHA-256",
412
- "content": "f34208b28b53697118db5370f82c6aaab883bb7be10d99789a96a39a06acfac7"
412
+ "content": "695b4d6e3d50b78c8ff388a935a8f80634c7f92f64ab9f27d83eac4c7fe02bba"
413
413
  }
414
414
  ]
415
415
  },
@@ -459,7 +459,7 @@
459
459
  "hashes": [
460
460
  {
461
461
  "alg": "SHA-256",
462
- "content": "f00496dde83db529d8dde54cf1a5a0048c4c08c49c085e035ad1c90d6a602b30"
462
+ "content": "d55cf907dda7b0357ffa66e374825f13ab99de69eecf49384f732f443160e76f"
463
463
  }
464
464
  ]
465
465
  }
package/src/cli.ts CHANGED
@@ -669,7 +669,7 @@ Usage:
669
669
  dz upgrade [--target <name>] [--pubkey <path>] [--require-signing] (a TAMPERED pack aborts the upgrade)
670
670
  dz sign --pack <dir> --key <path-outside-repo> (Ed25519 manifest + CycloneDX SBOM for a pack)
671
671
  dz verify-pack --pack <dir> [--pubkey <path>] (signature check; fail-closed; key from the repo, never the pack)
672
- dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] [--require-signing] [--provenance|--no-provenance] (dry-run by default; pass --yes/--confirm/--no-dry-run to go live; claim-check gate default warn — surfaces README claim findings, never blocks; error fails an offending package)
672
+ dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] [--mirror-cmd <cmd>|--no-mirror] [--require-signing] [--provenance|--no-provenance] (dry-run by default; pass --yes/--confirm/--no-dry-run to go live; claim-check gate default warn — surfaces README claim findings, never blocks; error fails an offending package)
673
673
  dz release [--filter <name>] [--tag] [--publish] [--json] [--dry-run] [--no-issue] (VERIFIED release: 4 HARD gates in FRONT of dz publish — full package test suites, audit >=high, node --check of every dist/bin file, bin smoke-boot via "node <bin> --help" — any red gate STOPS the release (exit 1) + best-effort gh issue; all green ⇒ re-sign reminder, then prints the ready dz publish command (or chains with --publish); never duplicates publish's own gates)
674
674
  dz parity [--target <name>] [--json] (the honest feature×target map, COMPUTED from the capability model — which harness feature is full / manual / absent on each of the ${TARGET_NAMES.length} targets, and via which form)
675
675
  dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] (portable Step-10 Delivery Gate: prints the 4-plane review brief + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked)
@@ -841,6 +841,8 @@ export interface CliIo {
841
841
  * without spawning anything.
842
842
  */
843
843
  readonly releaseRunner?: ReleaseExecRunner;
844
+ /** Post-publish mirror command seam; production uses synchronous shell execution. */
845
+ readonly publishMirrorRunner?: PublishMirrorRunner;
844
846
  /**
845
847
  * Test seam for `dz install`: overrides the `npm install` subprocess (production leaves
846
848
  * it unset → real `execSync`, stdio piped). A stub runner that pre-stages a fixture
@@ -860,6 +862,21 @@ export type ReleaseExecRunner = (
860
862
  opts: { readonly cwd: string; readonly timeoutMs: number },
861
863
  ) => { exitCode: number; stdout: string; stderr: string; timedOut?: boolean };
862
864
 
865
+ export type PublishMirrorRunner = (
866
+ command: string,
867
+ options: { readonly cwd: string; readonly env: NodeJS.ProcessEnv },
868
+ ) => string;
869
+
870
+ type PublishMirrorState = {
871
+ readonly status: 'confirmed' | 'unconfirmed' | 'skipped' | 'not-configured';
872
+ readonly command: string;
873
+ readonly commit?: string;
874
+ readonly receipt?: { readonly manifestUrl: string; readonly confirmedAt: string; readonly waitedMs: number };
875
+ readonly error?: string;
876
+ readonly reason?: string;
877
+ readonly warning?: string;
878
+ };
879
+
863
880
  interface ParsedArgs {
864
881
  readonly command: string;
865
882
  readonly options: Map<string, string>;
@@ -2988,6 +3005,8 @@ function cmdStatusline(
2988
3005
  } else if (data.storeHealth?.verdict === 'unreadable') {
2989
3006
  line += ` ⛔ STORE UNREADABLE${data.storeHealth.unreadableFiles !== undefined && data.storeHealth.unreadableFiles.length > 0
2990
3007
  ? `: ${data.storeHealth.unreadableFiles.join(', ')}` : ''}`;
3008
+ } else if (data.storeHealth?.verdict === 'busy') {
3009
+ line += ' ⏳ STORE BUSY';
2991
3010
  } else if (data.storeHealth?.verdict === 'source-changed') {
2992
3011
  line += ' ⚠ store source changed';
2993
3012
  }
@@ -3636,13 +3655,16 @@ function learningStoreLine(
3636
3655
  ) + (reason ? ' [' + reason + ']' : '');
3637
3656
  }
3638
3657
 
3639
- function inspectLearningStore(projectRoot: string): {
3658
+ function inspectLearningStore(
3659
+ projectRoot: string,
3660
+ countOptions?: { readonly busyTimeoutMs?: number; readonly attempts?: number },
3661
+ ): {
3640
3662
  mark: StoreMark | undefined;
3641
3663
  health: StoreHealth;
3642
3664
  rows: ReturnType<typeof countLearningStoreRowsReadonly>;
3643
3665
  } {
3644
3666
  const mark = readStoreMark(projectRoot);
3645
- const rows = countLearningStoreRowsReadonly(projectRoot);
3667
+ const rows = countLearningStoreRowsReadonly(projectRoot, countOptions);
3646
3668
  return { mark, rows, health: checkStoreHealth({ projectRoot, ...rows, mark }) };
3647
3669
  }
3648
3670
 
@@ -3739,7 +3761,8 @@ function refreshLearningStoreMark(
3739
3761
  const rows = countLearningStoreRowsReadonly(projectRoot);
3740
3762
  const counts = observedRows(rows);
3741
3763
  if (counts === undefined) {
3742
- writeErr(`⚠ dz store guard: ${options.reader ? 'reader observation' : 'store operation'} completed but the external mark was not updated — a store tier is unreadable`);
3764
+ const busy = rows.lexicalRows === 'busy' || rows.vectorRows === 'busy';
3765
+ writeErr(`⚠ dz store guard: ${options.reader ? 'reader observation' : 'store operation'} completed but the external mark was not updated — ${busy ? 'store busy; health not measured this run' : 'a store tier is unreadable'}`);
3743
3766
  return;
3744
3767
  }
3745
3768
  writeStoreMark(projectRoot, {
@@ -3773,7 +3796,7 @@ function allowLearningStoreWrite(
3773
3796
  ): boolean {
3774
3797
  let inspection: ReturnType<typeof inspectLearningStore>;
3775
3798
  try {
3776
- inspection = inspectLearningStore(projectRoot);
3799
+ inspection = inspectLearningStore(projectRoot, { busyTimeoutMs: 250, attempts: 3 });
3777
3800
  } catch (error) {
3778
3801
  const health: StoreHealth = {
3779
3802
  verdict: 'unreadable',
@@ -3789,6 +3812,10 @@ function allowLearningStoreWrite(
3789
3812
  // own row had landed.
3790
3813
  return true;
3791
3814
  }
3815
+ if (inspection.health.verdict === 'busy') {
3816
+ writeErr(`dz store guard: NOT MEASURED — ${inspection.health.reason}`);
3817
+ return true;
3818
+ }
3792
3819
  if (inspection.health.verdict === 'source-changed') {
3793
3820
  const counts = observedRows(inspection.rows);
3794
3821
  if (counts === undefined) return false;
@@ -3828,6 +3855,7 @@ function warnLearningStoreRead(projectRoot: string, writeErr: WriteErr, command:
3828
3855
  for (const line of lexicalSourceLines(rows)) writeErr(line);
3829
3856
  return;
3830
3857
  }
3858
+ if (health.verdict === 'busy') return;
3831
3859
  const counts = observedRows(rows);
3832
3860
  if (counts !== undefined && counts.lexicalRows + counts.vectorRows > 0
3833
3861
  && (mark === undefined || mark.lexicalLast !== counts.lexicalRows || mark.vectorLast !== counts.vectorRows
@@ -6857,7 +6885,37 @@ function cmdSbom(options: Map<string, string>, flags: Set<string>, cwd: string,
6857
6885
  return 0;
6858
6886
  }
6859
6887
 
6860
- function cmdPublish(options: Map<string, string>, flags: Set<string>, cwd: string, writeOutput: Write): number {
6888
+ function mirrorCommandFromConfig(cwd: string): { command?: string; warning?: string } {
6889
+ const configPath = join(cwd, '.dz', 'config.json');
6890
+ if (!existsSync(configPath)) return {};
6891
+ try {
6892
+ const config = JSON.parse(readFileSync(configPath, 'utf8')) as { publish?: { mirrorCommand?: unknown } };
6893
+ const command = typeof config.publish?.mirrorCommand === 'string' ? config.publish.mirrorCommand.trim() : '';
6894
+ return command === '' ? {} : { command };
6895
+ } catch (error) {
6896
+ const reason = error instanceof Error ? error.message : String(error);
6897
+ return { warning: `.dz/config.json unreadable — ${reason}` };
6898
+ }
6899
+ }
6900
+
6901
+ function mirrorShellToken(value: string): string {
6902
+ if (value === '') return "''";
6903
+ if (!/^[A-Za-z0-9@/.,+_-]+$/.test(value)) throw new Error('published package/version list is not shell-safe');
6904
+ return value;
6905
+ }
6906
+
6907
+ function mirrorFailureMessage(error: unknown): string {
6908
+ if (error instanceof Error && error.message.trim() !== '') return error.message.trim().split(/\r?\n/, 1)[0] ?? 'mirror command failed';
6909
+ return String(error);
6910
+ }
6911
+
6912
+ function cmdPublish(
6913
+ options: Map<string, string>,
6914
+ flags: Set<string>,
6915
+ cwd: string,
6916
+ writeOutput: Write,
6917
+ mirrorRunner?: PublishMirrorRunner,
6918
+ ): number {
6861
6919
  const json = flags.has('json');
6862
6920
  // Under --json stdout carries exactly one JSON document, so every human line — guard notes, refusals,
6863
6921
  // progress — goes to stderr instead of being dropped: a refusal that prints nothing is the silent
@@ -6865,9 +6923,9 @@ function cmdPublish(options: Map<string, string>, flags: Set<string>, cwd: strin
6865
6923
  const write: Write = json ? (line) => { process.stderr.write(`${line}\n`); } : writeOutput;
6866
6924
  // Reject unknown flags/options so a typo (e.g. `--dry-rum`) can NEVER be
6867
6925
  // silently swallowed and flip the command into live-publish mode.
6868
- const allowedFlags = new Set(['dry-run', 'no-dry-run', 'yes', 'confirm', 'bump-only', 'help', 'require-signing', 'provenance', 'no-provenance', 'json']);
6869
- const allowedOptions = new Set(['filter', 'claim-check', 'no-guard', 'sign-key']);
6870
- const allowedHelp = ' allowed: --dry-run (default), --yes/--confirm/--no-dry-run (go live), --bump-only, --filter <substr>, --claim-check <off|warn|error>, --no-guard "<reason>" (skip the guard pre-flight; logged)';
6926
+ const allowedFlags = new Set(['dry-run', 'no-dry-run', 'yes', 'confirm', 'bump-only', 'help', 'require-signing', 'provenance', 'no-provenance', 'json', 'no-mirror']);
6927
+ const allowedOptions = new Set(['filter', 'claim-check', 'no-guard', 'sign-key', 'mirror-cmd']);
6928
+ const allowedHelp = ' allowed: --dry-run (default), --yes/--confirm/--no-dry-run (go live), --bump-only, --filter <substr>, --claim-check <off|warn|error>, --mirror-cmd <cmd>, --no-mirror, --no-guard "<reason>" (skip the guard pre-flight; logged)';
6871
6929
  for (const flag of flags) {
6872
6930
  if (!allowedFlags.has(flag)) {
6873
6931
  write(`dz publish: unknown option --${flag}`);
@@ -7047,7 +7105,7 @@ function cmdPublish(options: Map<string, string>, flags: Set<string>, cwd: strin
7047
7105
  // longer exist. Default to the same path `dz sign --init` writes, so the ordinary operator needs no
7048
7106
  // new flag; `--sign-key` overrides it.
7049
7107
  const signKey = (options.get('sign-key') ?? join(homedir(), '.dz', 'keys', 'dz.key')).trim();
7050
- const report = publishPackages(cwd, {
7108
+ const publishReport = publishPackages(cwd, {
7051
7109
  provenance,
7052
7110
  dryRun,
7053
7111
  filter,
@@ -7127,9 +7185,82 @@ function cmdPublish(options: Map<string, string>, flags: Set<string>, cwd: strin
7127
7185
  },
7128
7186
  });
7129
7187
 
7188
+ const configMirror = mirrorCommandFromConfig(cwd);
7189
+ const configuredCommand = (options.get('mirror-cmd') ?? configMirror.command ?? '').trim();
7190
+ const publishedVersions = publishReport.packages
7191
+ .filter((pkg) => pkg.status === 'published')
7192
+ .map((pkg) => `${pkg.name}@${pkg.newVersion}`);
7193
+ const expected = publishedVersions.join(',');
7194
+ const fullMirrorCommand = configuredCommand === ''
7195
+ ? ''
7196
+ : `${configuredCommand} --expect ${mirrorShellToken(expected)} --json`;
7197
+ let mirror: PublishMirrorState;
7198
+
7199
+ // This exact conjunction is the Step-7/8 mutation anchor: an epilogue is eligible only after a
7200
+ // live sweep that actually landed at least one package. Other explicit skip states are handled
7201
+ // before command resolution so each reason remains distinguishable in text and JSON.
7202
+ const mirrorEligible = !dryRun && publishReport.published >= 1;
7203
+ if (bumpOnly) {
7204
+ mirror = { status: 'skipped', command: fullMirrorCommand, reason: 'bump-only' };
7205
+ } else if (!mirrorEligible) {
7206
+ mirror = {
7207
+ status: 'skipped',
7208
+ command: fullMirrorCommand,
7209
+ reason: dryRun ? 'dry-run' : 'published=0',
7210
+ };
7211
+ } else if (flags.has('no-mirror')) {
7212
+ mirror = { status: 'skipped', command: fullMirrorCommand, reason: '--no-mirror' };
7213
+ } else if (configMirror.warning !== undefined && options.get('mirror-cmd') === undefined) {
7214
+ mirror = { status: 'not-configured', command: '', warning: configMirror.warning };
7215
+ } else if (configuredCommand === '') {
7216
+ mirror = { status: 'not-configured', command: '' };
7217
+ } else {
7218
+ const runMirror: PublishMirrorRunner = mirrorRunner
7219
+ ?? ((command, runnerOptions) => execSync(command, {
7220
+ cwd: runnerOptions.cwd,
7221
+ env: runnerOptions.env,
7222
+ encoding: 'utf8',
7223
+ stdio: 'pipe',
7224
+ }));
7225
+ try {
7226
+ const stdout = runMirror(fullMirrorCommand, {
7227
+ cwd,
7228
+ env: { ...process.env, DZ_PUBLISHED: expected },
7229
+ });
7230
+ const parsed = JSON.parse(stdout) as {
7231
+ ok?: unknown;
7232
+ commit?: unknown;
7233
+ receipt?: { manifestUrl?: unknown; confirmedAt?: unknown; waitedMs?: unknown };
7234
+ error?: unknown;
7235
+ };
7236
+ if (parsed.ok !== true) throw new Error(typeof parsed.error === 'string' ? parsed.error : 'mirror command returned ok:false');
7237
+ if (typeof parsed.commit !== 'string' || parsed.commit === '') throw new Error('mirror command returned no commit');
7238
+ if (typeof parsed.receipt?.manifestUrl !== 'string'
7239
+ || typeof parsed.receipt.confirmedAt !== 'string'
7240
+ || typeof parsed.receipt.waitedMs !== 'number') {
7241
+ throw new Error('mirror command returned no live-manifest receipt');
7242
+ }
7243
+ mirror = {
7244
+ status: 'confirmed',
7245
+ command: fullMirrorCommand,
7246
+ commit: parsed.commit,
7247
+ receipt: {
7248
+ manifestUrl: parsed.receipt.manifestUrl,
7249
+ confirmedAt: parsed.receipt.confirmedAt,
7250
+ waitedMs: parsed.receipt.waitedMs,
7251
+ },
7252
+ };
7253
+ } catch (error) {
7254
+ mirror = { status: 'unconfirmed', command: fullMirrorCommand, error: mirrorFailureMessage(error) };
7255
+ }
7256
+ }
7257
+
7258
+ const report = { ...publishReport, mirror };
7259
+ const exitCode = report.errors > 0 ? 1 : mirror.status === 'unconfirmed' ? 3 : 0;
7260
+
7130
7261
  if (json) {
7131
7262
  writeOutput(JSON.stringify(report));
7132
- return report.errors > 0 ? 1 : 0;
7263
+ return exitCode;
7133
7264
  }
7134
7265
 
7135
7266
  write(`\ndz publish${dryRun ? ' --dry-run' : ''}${bumpOnly ? ' --bump-only' : ''}${claimCheckOpt !== 'warn' ? ` --claim-check ${claimCheckOpt}` : ''}`);
@@ -7181,7 +7312,19 @@ function cmdPublish(options: Map<string, string>, flags: Set<string>, cwd: strin
7181
7312
  }
7182
7313
  for (const warning of report.warnings ?? []) write(` ⚠ warning: ${warning}`);
7183
7314
  for (const path of report.releaseLineSynced ?? []) write(` ↳ release line synced: ${path}`);
7184
- return report.errors > 0 ? 1 : 0;
7315
+ if (mirror.status === 'confirmed') {
7316
+ write(` ✓ mirror: confirmed — ${mirror.commit} (${mirror.receipt?.manifestUrl})`);
7317
+ } else if (mirror.status === 'not-configured') {
7318
+ if (mirror.warning !== undefined) write(` ⚠ mirror: ${mirror.warning}`);
7319
+ else write(' ℹ mirror: not configured');
7320
+ } else if (mirror.status === 'skipped') {
7321
+ write(` ℹ mirror: skipped (${mirror.reason})`);
7322
+ } else {
7323
+ write(` ✗ mirror: unconfirmed — ${mirror.error}`);
7324
+ const rerun = mirror.command || 'configure publish.mirrorCommand, then run it';
7325
+ write(`dz publish: published, mirror NOT confirmed — ${mirror.error}; re-run: ${rerun}`);
7326
+ }
7327
+ return exitCode;
7185
7328
  }
7186
7329
 
7187
7330
  /* ------------------------------------------------------------------ */
@@ -18107,7 +18250,10 @@ export async function runCli(argv: string[], io: CliIo = {}): Promise<number> {
18107
18250
  // `dz recap` — a refusal built on either list would reject working commands, which is a worse
18108
18251
  // failure than the one being fixed. Goes to STDERR so a `--json` consumer's stdout stays clean.
18109
18252
  if (command !== 'contract-check') {
18110
- for (const notice of unknownFlagNotice([...flags, ...options.keys()].filter((k) => !k.startsWith('_positional_')), KNOWN_CLI_FLAGS)) {
18253
+ for (const notice of unknownFlagNotice(
18254
+ [...flags, ...options.keys()].filter((k) => !k.startsWith('_positional_')),
18255
+ KNOWN_CLI_FLAGS,
18256
+ )) {
18111
18257
  writeErr(notice.line);
18112
18258
  }
18113
18259
  }
@@ -18264,7 +18410,7 @@ export async function runCli(argv: string[], io: CliIo = {}): Promise<number> {
18264
18410
  case 'auto-canonicalize':
18265
18411
  return await cmdAutoCanonicalize(options, cwd, write);
18266
18412
  case 'publish':
18267
- return cmdPublish(options, flags, cwd, write);
18413
+ return cmdPublish(options, flags, cwd, write, io.publishMirrorRunner);
18268
18414
  case 'release':
18269
18415
  return cmdRelease(options, flags, cwd, write, io.releaseRunner);
18270
18416
  case 'parity':
@@ -324,4 +324,5 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
324
324
  'write',
325
325
  'year',
326
326
  'yes',
327
+ 'mirror-cmd', // dz publish epilogue (mirror-push-on-publish)
327
328
  ];