@mnemonik/cli 7.104.2 → 7.104.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.
Files changed (70) hide show
  1. package/dist/auth/credentials.js +11 -6
  2. package/dist/bin.js +5 -4
  3. package/dist/bin.js.map +1 -1
  4. package/dist/diagnostics.d.ts.map +1 -1
  5. package/dist/diagnostics.js +12 -7
  6. package/dist/diagnostics.js.map +1 -1
  7. package/dist/digests.json +68 -64
  8. package/dist/humanReason.d.ts +19 -0
  9. package/dist/humanReason.d.ts.map +1 -0
  10. package/dist/humanReason.js +222 -0
  11. package/dist/humanReason.js.map +1 -0
  12. package/dist/identity/migrate.js +8 -2
  13. package/dist/install/journal.d.ts +1 -0
  14. package/dist/install/journal.d.ts.map +1 -1
  15. package/dist/install/journal.js +25 -2
  16. package/dist/install/journal.js.map +1 -1
  17. package/dist/install/journey.js +8 -2
  18. package/dist/install/ownership.js +8 -2
  19. package/dist/install/ui.d.ts.map +1 -1
  20. package/dist/install/ui.js +3 -2
  21. package/dist/install/ui.js.map +1 -1
  22. package/dist/installSession.d.ts.map +1 -1
  23. package/dist/installSession.js +3 -2
  24. package/dist/installSession.js.map +1 -1
  25. package/dist/installation.js +8 -2
  26. package/dist/launcher.js +8 -2
  27. package/dist/output.d.ts +1 -1
  28. package/dist/output.d.ts.map +1 -1
  29. package/dist/output.js +4 -2
  30. package/dist/output.js.map +1 -1
  31. package/dist/preflight.d.ts +1 -0
  32. package/dist/preflight.d.ts.map +1 -1
  33. package/dist/preflight.js +9 -6
  34. package/dist/preflight.js.map +1 -1
  35. package/dist/project/records.js +8 -2
  36. package/dist/project.d.ts.map +1 -1
  37. package/dist/project.js +20 -10
  38. package/dist/project.js.map +1 -1
  39. package/dist/router.d.ts.map +1 -1
  40. package/dist/router.js +100 -96
  41. package/dist/router.js.map +1 -1
  42. package/dist/runtime/bootstrap.d.ts.map +1 -1
  43. package/dist/runtime/bootstrap.js +57 -9
  44. package/dist/runtime/bootstrap.js.map +1 -1
  45. package/dist/runtime/selfUpdate.d.ts.map +1 -1
  46. package/dist/runtime/selfUpdate.js +10 -3
  47. package/dist/runtime/selfUpdate.js.map +1 -1
  48. package/dist/runtime/signers.js +53 -23
  49. package/dist/runtime/store.js +40 -12
  50. package/dist/runtime/store.js.map +1 -1
  51. package/dist/sbom.json +50 -21
  52. package/dist/scanner/control.js +8 -2
  53. package/dist/scanner/enable.js +10 -4
  54. package/dist/scanner/enable.js.map +1 -1
  55. package/dist/scanner/picker.d.ts.map +1 -1
  56. package/dist/scanner/picker.js +2 -6
  57. package/dist/scanner/picker.js.map +1 -1
  58. package/dist/scanner/update.js +8 -2
  59. package/dist/scanner-release.json +23 -23
  60. package/dist/screens/journey.d.ts +1 -0
  61. package/dist/screens/journey.d.ts.map +1 -1
  62. package/dist/screens/journey.js +11 -9
  63. package/dist/screens/journey.js.map +1 -1
  64. package/dist/status.d.ts +12 -4
  65. package/dist/status.d.ts.map +1 -1
  66. package/dist/status.js +802 -152
  67. package/dist/status.js.map +1 -1
  68. package/dist/vendor/local-setup.js +15 -5
  69. package/dist/vendor/shared/runtimeSigners.js +65 -19
  70. package/package.json +31 -31
package/dist/router.js CHANGED
@@ -562,6 +562,7 @@ var init_hookRuntime = __esm({
562
562
  });
563
563
 
564
564
  // packages/cli/src/router.ts
565
+ import { humanReason, humanReport, humanIdentityState } from "./humanReason.js";
565
566
  import { enableScanner, updateScannerRoots } from "./scanner/enable.js";
566
567
  import { controlScanner, scannerReceipt } from "./scanner/control.js";
567
568
  import { updateScanner } from "./scanner/update.js";
@@ -4949,7 +4950,6 @@ import {
4949
4950
  runHosts,
4950
4951
  hostSource,
4951
4952
  codexTrustConditions,
4952
- connectHost,
4953
4953
  logoutHost,
4954
4954
  selectOwned
4955
4955
  } from "./install/hosts.js";
@@ -4978,7 +4978,7 @@ import { createCliAuth } from "./auth/index.js";
4978
4978
  import { currentInstallSession, ensureInstallSession } from "./auth/installSession.js";
4979
4979
  import { runIdentityMigration } from "./identity/migrate.js";
4980
4980
  import { renderScannerStatus } from "./scanner/picker.js";
4981
- import { interrupted } from "./install/journal.js";
4981
+ import { abandonInterrupted, interrupted } from "./install/journal.js";
4982
4982
  import {
4983
4983
  installFailureReason,
4984
4984
  runInstall
@@ -4987,9 +4987,13 @@ import { chooseHostProfile, simulatedInstall, terminalInstallUI } from "./instal
4987
4987
  import {
4988
4988
  CODEX_TRUST_MESSAGE,
4989
4989
  collectStatusDocument,
4990
+ localEditorStatus,
4991
+ localInstallationConditions,
4992
+ mcpTurnOnAction,
4990
4993
  renderStatusSummaries,
4991
4994
  statusExitCode
4992
4995
  } from "./status.js";
4996
+ import { editorAuthorizationRows } from "./screens/journey.js";
4993
4997
  import {
4994
4998
  DiagnosticsError,
4995
4999
  previewDiagnostics,
@@ -5118,7 +5122,10 @@ function actionRequired2(output, json, message, flag) {
5118
5122
  ...flag ? { flag } : {},
5119
5123
  action: message
5120
5124
  });
5121
- else output.error(flag ? `Missing required consent flag: ${flag}` : message);
5125
+ else
5126
+ output.error(
5127
+ flag ? `Missing required consent flag: ${flag}` : /^[a-z][a-z0-9_]*$/u.test(message) ? humanReason(message) : message
5128
+ );
5122
5129
  return 3;
5123
5130
  }
5124
5131
  function requireConsent(parsed, output, required) {
@@ -5206,6 +5213,7 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5206
5213
  const fullUninstall = command === "uninstall" && !host && !scope && !component;
5207
5214
  if (scope && !["user", "project"].includes(String(scope)) || host && !hostOrder.includes(host) || component && !["hooks", "mcp"].includes(String(component)))
5208
5215
  return output.error("Invalid host, scope or component"), 2;
5216
+ if (command === "uninstall") await abandonInterrupted(state);
5209
5217
  let selections;
5210
5218
  if (command === "install") {
5211
5219
  const names = String(parsed.flags.get("hosts") ?? hostOrder.join(",")).split(",");
@@ -5323,6 +5331,8 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5323
5331
  }
5324
5332
  let failed = scanner?.status === "FAILED" || cli?.status === "FAILED";
5325
5333
  const hostExit = maintenanceExitCode(result.results);
5334
+ const remaining = command === "repair" ? await collectCurrentInstallation(deps, output) : void 0;
5335
+ const remainingExit = remaining?.installation.state === "FAILED" ? 1 : remaining?.installation.state === "READY" || !remaining ? 0 : 3;
5326
5336
  const hostsFailed = hostUpdateFailed(result);
5327
5337
  const codexTrustPending = result.results.some(
5328
5338
  (target) => target.reason === "codex_trust_pending"
@@ -5355,12 +5365,13 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5355
5365
  }
5356
5366
  if (json)
5357
5367
  output.json({
5358
- status: failed ? "FAILED" : scanner?.status === "uninstalled" ? "uninstalled" : result.journal.state,
5368
+ status: failed || remainingExit === 1 ? "FAILED" : remainingExit === 3 ? "ACTION_REQUIRED" : scanner?.status === "uninstalled" ? "uninstalled" : result.journal.state,
5359
5369
  targets: result.results,
5360
5370
  reports: result.reports,
5361
5371
  ...scanner ? { scanner } : {},
5362
5372
  ...launcher ? { launcher } : {},
5363
- ...cli ? { cli } : {}
5373
+ ...cli ? { cli } : {},
5374
+ ...remaining ? { remaining } : {}
5364
5375
  });
5365
5376
  else if (command === "update") {
5366
5377
  if (failed || hostsFailed) output.error(updateFailureMessage);
@@ -5373,20 +5384,27 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5373
5384
  else output.line("Mnemonik is up to date.");
5374
5385
  } else {
5375
5386
  for (const target of result.results)
5376
- output.line(
5377
- `${target.target}: ${target.status} (${target.reason}${target.detail ? `: ${target.detail}` : ""})`
5378
- );
5379
- for (const report of result.reports) output.line(report);
5380
- if (!selections.length && !fullUninstall) output.line("No recorded host targets.");
5387
+ output.line(target.status === "READY" ? "Done." : humanReason(target.reason));
5388
+ for (const report of result.reports) output.line(humanReport(report));
5389
+ if (remaining) renderStatusSummaries(remaining, output);
5390
+ if (!selections.length && !fullUninstall && !remaining)
5391
+ output.line("No recorded host targets.");
5381
5392
  if (fullUninstall && !failed && hostExit === 0)
5382
5393
  output.line(
5383
5394
  "Stopped collection; removed local software. Credentials, cloud data and consent retained."
5384
5395
  );
5385
5396
  else if (scanner)
5386
- output.line(`Scanner ${scanner.status}: ${scanner.version ?? scanner.reason}.`);
5397
+ output.line(
5398
+ scanner.reason ? humanReason(scanner.reason) : scanner.status === "not_installed" ? "The scanner is not installed." : "The scanner was uninstalled."
5399
+ );
5400
+ }
5401
+ if (scanner?.status === "failed") {
5402
+ const reason = scanner.reason ?? "scanner_uninstall_failed";
5403
+ if (json) output.error(reason, false);
5404
+ else output.error(humanReason(reason));
5387
5405
  }
5388
- if (scanner?.status === "failed") output.error(scanner.reason ?? "scanner_uninstall_failed");
5389
- return failed ? 1 : hostExit;
5406
+ if (failed || remainingExit === 1) return 1;
5407
+ return hostExit || remainingExit;
5390
5408
  } catch (error) {
5391
5409
  if (command === "update" && !json) {
5392
5410
  output.error(updateFailureMessage);
@@ -5395,14 +5413,14 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5395
5413
  if (error instanceof LauncherError) {
5396
5414
  if (json)
5397
5415
  output.json({ status: error.status, reason: error.message, launcher: error.launcher });
5398
- else output.error(error.message);
5416
+ else output.error(humanReason(error.message));
5399
5417
  return 3;
5400
5418
  }
5401
5419
  const reason = installFailureReason(error);
5402
5420
  if (reason === "lock_held") {
5403
5421
  if (json) output.json({ status: "FAILED", reason });
5404
5422
  else output.error("Another mnemonik command holds the state lock; retry in a moment.");
5405
- } else output.error(reason);
5423
+ } else output.error(humanReason(reason));
5406
5424
  return 1;
5407
5425
  }
5408
5426
  }
@@ -5452,7 +5470,7 @@ async function enableCommand(parsed, deps, output) {
5452
5470
  action: "mnemonik scanner enable"
5453
5471
  };
5454
5472
  if (json) output.json(result);
5455
- else output.error(`${result.reason}: ${result.action}`);
5473
+ else output.error(humanReason(result.reason));
5456
5474
  return 3;
5457
5475
  }
5458
5476
  }
@@ -5492,7 +5510,7 @@ async function installCommand(parsed, deps, output) {
5492
5510
  try {
5493
5511
  await ensureCliAuth(deps, output, parsed.flags.has("no-browser"));
5494
5512
  } catch (error) {
5495
- output.error(`Sign-in refused: ${installFailureReason(error)}`);
5513
+ output.error(humanReason(installFailureReason(error)));
5496
5514
  return 1;
5497
5515
  }
5498
5516
  }
@@ -5507,10 +5525,10 @@ async function installCommand(parsed, deps, output) {
5507
5525
  const pending = await interrupted(install.stateDir);
5508
5526
  const result = await runInstall(install, pending[0]);
5509
5527
  output.line(`${result.state}: install ${result.runId}`);
5510
- for (const report of result.reports) output.line(report);
5528
+ for (const report of result.reports) output.line(humanReport(report));
5511
5529
  return result.phase === "rolled_back" ? 130 : result.state === "FAILED" ? 1 : result.state === "READY" ? 0 : 3;
5512
5530
  } catch (error) {
5513
- output.error(`Install failed: ${installFailureReason(error)}`);
5531
+ output.error(humanReason(installFailureReason(error)));
5514
5532
  return 1;
5515
5533
  } finally {
5516
5534
  terminal?.close();
@@ -5551,14 +5569,23 @@ async function doctorCommand(parsed, deps, output) {
5551
5569
  return document.installation.state === "READY" ? 0 : document.installation.state === "FAILED" ? 1 : 3;
5552
5570
  }
5553
5571
  async function collectCurrentInstallation(deps, output) {
5554
- const result = await runPreflight({ cwd: deps.cwd, home: deps.home, ...deps.preflight });
5572
+ const result = await runPreflight({
5573
+ cwd: deps.cwd,
5574
+ home: deps.home,
5575
+ ...deps.preflight,
5576
+ fetch: async () => new Response(null, { status: 204 })
5577
+ });
5555
5578
  output.setContext({ home: deps.home ?? homedir2(), projectRoot: result.project.root });
5556
5579
  const hostStateDir = deps.hostManagement?.stateDir ?? deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
5557
- const trustConditions = await (deps.codexTrustConditions ?? (() => codexTrustConditions({
5558
- stateDir: hostStateDir,
5559
- env: deps.hostManagement?.env,
5560
- imports: deps.hostManagement?.imports
5561
- })))();
5580
+ const localConditions = deps.projectHookConditions ? [] : [
5581
+ ...await localInstallationConditions(deps.home ?? homedir2(), hostStateDir, deps.launcher),
5582
+ // Installed Codex hooks that Codex has not trusted cannot run.
5583
+ ...await (deps.codexTrustConditions ?? (() => codexTrustConditions({
5584
+ stateDir: hostStateDir,
5585
+ env: deps.hostManagement?.env,
5586
+ imports: deps.hostManagement?.imports
5587
+ })))()
5588
+ ];
5562
5589
  const document = await collectStatusDocument({
5563
5590
  preflight: result,
5564
5591
  cwd: deps.cwd ?? process.cwd(),
@@ -5567,11 +5594,13 @@ async function collectCurrentInstallation(deps, output) {
5567
5594
  executor: deps.projectExecutor,
5568
5595
  resolver: deps.projectResolver ?? (deps.preflight?.resolveIdentity ? { resolveProjectIdentity: deps.preflight.resolveIdentity } : void 0),
5569
5596
  stateDir: deps.projectStateDir ?? deps.installStateDir,
5597
+ // The project section reports project access, as doctor and the console
5598
+ // route do. Local evidence still decides the installation verdict.
5570
5599
  getCliBearer: deps.getCliBearer,
5571
5600
  transport: deps.projectTransport,
5572
5601
  scannerStatus: deps.scannerStatus,
5573
- installationConditions: [...deps.installationConditions ?? [], ...trustConditions],
5574
- projectHookConditions: deps.projectHookConditions,
5602
+ installationConditions: [...deps.installationConditions ?? [], ...localConditions],
5603
+ projectHookConditions: deps.projectHookConditions ?? [],
5575
5604
  configuredHosts: deps.configuredHosts ?? deps.install?.input.hosts,
5576
5605
  details: deps.statusDetails,
5577
5606
  generatedAt: deps.statusGeneratedAt,
@@ -5585,15 +5614,13 @@ async function collectCurrentInstallation(deps, output) {
5585
5614
  async function reportCurrentInstallation(deps, output, document) {
5586
5615
  const bearer = await auth(deps, output, false).getCliBearer().catch(() => void 0);
5587
5616
  if (typeof bearer !== "string") return;
5588
- try {
5589
- await postCurrentReadiness(
5590
- bearer,
5591
- serializeReadiness(document ?? await collectCurrentInstallation(deps, output)),
5592
- deps.grantFetch
5593
- );
5594
- } catch {
5595
- output.error("The final installation status could not be uploaded.");
5596
- }
5617
+ const send = deps.grantFetch ?? globalThis.fetch;
5618
+ await postCurrentReadiness(
5619
+ bearer,
5620
+ serializeReadiness(document ?? await collectCurrentInstallation(deps, output)),
5621
+ (url, options) => send(url, { ...options, signal: AbortSignal.timeout(2500) })
5622
+ ).catch(() => {
5623
+ });
5597
5624
  }
5598
5625
  async function runCli(args2, deps = {}) {
5599
5626
  const parsed = parse(args2);
@@ -5607,7 +5634,7 @@ async function runCli(args2, deps = {}) {
5607
5634
  });
5608
5635
  if (process.env.MNEMONIK_DEV_RELEASE_DIR && !silent)
5609
5636
  stderr.write(
5610
- "WARNING: MNEMONIK_DEV_RELEASE_DIR uses development artifacts; readiness remains LIMITED (dev_release_source).\n"
5637
+ "WARNING: MNEMONIK_DEV_RELEASE_DIR uses development artifacts; readiness remains LIMITED.\n"
5611
5638
  );
5612
5639
  if (parsed.error) return output.error(parsed.error), 2;
5613
5640
  if (parsed.flags.has("version")) {
@@ -5686,9 +5713,7 @@ async function runCli(args2, deps = {}) {
5686
5713
  return 3;
5687
5714
  }
5688
5715
  if (project.status !== "done") {
5689
- output.error(
5690
- `Project action required: ${"state" in project ? project.state : project.status}`
5691
- );
5716
+ output.error(humanReason("project_setup_required"));
5692
5717
  return 3;
5693
5718
  }
5694
5719
  }
@@ -5734,7 +5759,7 @@ async function runCli(args2, deps = {}) {
5734
5759
  );
5735
5760
  return 0;
5736
5761
  } catch (error) {
5737
- output.error(error.message);
5762
+ output.error(humanReason(error.message));
5738
5763
  return 3;
5739
5764
  }
5740
5765
  }
@@ -5753,7 +5778,7 @@ async function runCli(args2, deps = {}) {
5753
5778
  );
5754
5779
  return 0;
5755
5780
  } catch (error) {
5756
- output.error(error.message);
5781
+ output.error(humanReason(error.message));
5757
5782
  return 3;
5758
5783
  }
5759
5784
  }
@@ -5797,7 +5822,9 @@ async function runCli(args2, deps = {}) {
5797
5822
  }
5798
5823
  return 0;
5799
5824
  } catch (error) {
5800
- output.error(command === "update" ? updateFailureMessage : error.message);
5825
+ output.error(
5826
+ command === "update" ? updateFailureMessage : humanReason(error.message)
5827
+ );
5801
5828
  return 3;
5802
5829
  }
5803
5830
  }
@@ -5880,9 +5907,19 @@ Preview: ${preview.path}
5880
5907
  }
5881
5908
  return 0;
5882
5909
  } catch (error) {
5883
- const code = error instanceof DiagnosticsError ? error.code : "diagnostics_failed";
5910
+ const nativeCode = error.code;
5911
+ const code = error instanceof DiagnosticsError ? error.code : typeof nativeCode === "string" ? nativeCode : "diagnostics_failed";
5884
5912
  if (parsed.flags.has("json")) output.json({ status: "error", error: code });
5885
- else output.error(code);
5913
+ else if (/^(?:bundle_id_invalid|bundle_hash_mismatch|diagnostics_preview_invalid|ENOENT)$/u.test(
5914
+ code
5915
+ ))
5916
+ output.error(
5917
+ "Saved diagnostics could not be used.\nRun mnemonik diagnostics preview, then try again."
5918
+ );
5919
+ else
5920
+ output.error(
5921
+ subcommand === "preview" ? "Diagnostics could not be created.\nRun mnemonik install to try again." : "Diagnostics could not be sent.\nCheck your internet connection, then try again."
5922
+ );
5886
5923
  return 1;
5887
5924
  }
5888
5925
  }
@@ -5910,42 +5947,20 @@ Preview: ${preview.path}
5910
5947
  if (invalid) return output.error(invalid), 2;
5911
5948
  if (!subcommand || rest.length || !hostOrder.includes(subcommand))
5912
5949
  return output.error(`Usage: mnemonik connect <${hostOrder.join("|")}>`), 2;
5913
- const state = deps.hostManagement?.stateDir ?? deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
5914
- const owned = await selectOwned(
5915
- state,
5916
- subcommand,
5917
- parsed.flags.get("scope"),
5918
- "mcp"
5950
+ const host = subcommand;
5951
+ const editor = (await localEditorStatus(deps.home ?? homedir2())).find(
5952
+ (candidate) => candidate.host === host
5919
5953
  );
5920
- if (!owned.selected.length && !parsed.flags.has("json")) {
5921
- output.line(
5922
- `${launchHostLabels[subcommand]} will ask you to sign in to Mnemonik the first time you use it.`
5923
- );
5924
- return 3;
5954
+ const reason = editor?.mcp === "disabled" ? `${editor.name} connection is turned off.` : editor?.mcp === "ready" ? "Finish signing in to Mnemonik in the editor." : `${launchHostLabels[host]} connection is missing.`;
5955
+ const actions = editor?.mcp === "ready" ? editorAuthorizationRows([host]) : [
5956
+ editor?.mcp === "disabled" ? mcpTurnOnAction[host] : "Run mnemonik install to set it up again."
5957
+ ];
5958
+ if (parsed.flags.has("json")) output.json({ status: "ACTION_REQUIRED", reason, actions });
5959
+ else {
5960
+ output.line(reason);
5961
+ for (const action of actions) output.line(action);
5925
5962
  }
5926
- if (owned.selected.length !== 1)
5927
- return actionRequired2(
5928
- output,
5929
- parsed.flags.has("json"),
5930
- owned.selected.length ? "ambiguous_profile" : "no_recorded_targets"
5931
- );
5932
- const managed = deps.hostManagement ?? { stateDir: state, account: "" };
5933
- const selected = owned.selected[0];
5934
- if (!selected) throw new Error("no_recorded_targets");
5935
- let instructionShown = false;
5936
- const result = await connectHost(selected, {
5937
- ...managed,
5938
- instruction: (text) => {
5939
- if (!parsed.flags.has("json")) {
5940
- output.line(text);
5941
- instructionShown = true;
5942
- }
5943
- }
5944
- });
5945
- if (parsed.flags.has("json")) output.json(result);
5946
- else if (!instructionShown)
5947
- output.line(`${result.status}: ${result.reason}${result.action ? `. ${result.action}` : ""}`);
5948
- return result.status === "READY" ? 0 : 3;
5963
+ return 3;
5949
5964
  }
5950
5965
  if (command === "project") {
5951
5966
  if (!subcommand || !["init", "setup", "status", "link", "ensure"].includes(subcommand))
@@ -6026,25 +6041,19 @@ Preview: ${preview.path}
6026
6041
  stateDir: deps.identityStateDir
6027
6042
  });
6028
6043
  } catch (error) {
6029
- output.error(`Identity migration failed: ${error.message}`);
6044
+ output.error(humanReason(error.message));
6030
6045
  return 1;
6031
6046
  }
6032
6047
  if (parsed.flags.has("json")) output.json(result);
6033
6048
  else if ("report" in result) {
6034
6049
  for (const entry of result.report.entries)
6035
- output.line(
6036
- `${entry.state.padEnd(16)} ${entry.path}${entry.actionRequired ? " - ACTION REQUIRED" : ""}${entry.detail ? ` - ${entry.detail}` : ""}`
6037
- );
6038
- output.line(
6039
- `Summary: ${Object.entries(result.report.summary).map(([state, count]) => `${state}=${count}`).join(" ")}`
6040
- );
6050
+ output.line(`${entry.path}: ${humanIdentityState(entry.state)}`);
6051
+ output.line(`Checked ${result.report.entries.length} project identity files.`);
6041
6052
  if (result.status === "backed_up")
6042
6053
  output.line(`Backup run: ${result.runId} (${result.count} file(s))`);
6043
6054
  } else {
6044
- output.line(
6045
- `${result.status}: run ${result.runId}; passed=${result.passed}; failed=${result.failed}`
6046
- );
6047
- for (const failure of result.failures) output.error(failure);
6055
+ output.line(`Identity migration: ${result.passed} passed; ${result.failed} failed.`);
6056
+ for (const failure of result.failures) output.error(humanReason(failure));
6048
6057
  }
6049
6058
  return "failed" in result && result.failed > 0 ? 1 : 0;
6050
6059
  }
@@ -6171,8 +6180,6 @@ Preview: ${preview.path}
6171
6180
  output.line(
6172
6181
  subcommand === "status" && supervisor ? supervisor.installed ? `Scanner status: ${result.status} (service: ${supervisor.kind}, ${supervisor.running ? "running" : "stopped"})` : `Scanner status: ${result.status} (service not registered; run mnemonik scanner start)` : `Scanner ${subcommand}: ${result.status}`
6173
6182
  );
6174
- if ("receipt" in result && result.receipt)
6175
- output.line(JSON.stringify(result.receipt.snapshot));
6176
6183
  }
6177
6184
  return 0;
6178
6185
  } catch (error) {
@@ -6184,10 +6191,7 @@ Preview: ${preview.path}
6184
6191
  choices: ["retry", "skip"]
6185
6192
  };
6186
6193
  if (json) output.json(result);
6187
- else
6188
- output.line(
6189
- `LIMITED: ${result.reason}: ${result.detail}. Retry: ${result.action}, or skip.`
6190
- );
6194
+ else output.line(humanReason(result.reason));
6191
6195
  return 3;
6192
6196
  }
6193
6197
  }