@mnemonik/cli 7.100.0 → 7.101.4

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 (93) hide show
  1. package/dist/auth/pkce.d.ts +2 -0
  2. package/dist/auth/pkce.d.ts.map +1 -1
  3. package/dist/auth/pkce.js +57 -6
  4. package/dist/auth/pkce.js.map +1 -1
  5. package/dist/auth/status.d.ts +1 -5
  6. package/dist/auth/status.d.ts.map +1 -1
  7. package/dist/auth/status.js +1 -71
  8. package/dist/auth/status.js.map +1 -1
  9. package/dist/digests.json +91 -91
  10. package/dist/install/hosts.d.ts +2 -12
  11. package/dist/install/hosts.d.ts.map +1 -1
  12. package/dist/install/hosts.js +57 -356
  13. package/dist/install/hosts.js.map +1 -1
  14. package/dist/install/journal.d.ts +2 -10
  15. package/dist/install/journal.d.ts.map +1 -1
  16. package/dist/install/journal.js +0 -4
  17. package/dist/install/journal.js.map +1 -1
  18. package/dist/install/journey.d.ts.map +1 -1
  19. package/dist/install/journey.js +185 -158
  20. package/dist/install/journey.js.map +1 -1
  21. package/dist/install/transaction.d.ts +2 -3
  22. package/dist/install/transaction.d.ts.map +1 -1
  23. package/dist/install/transaction.js +1 -90
  24. package/dist/install/transaction.js.map +1 -1
  25. package/dist/install/ui.d.ts.map +1 -1
  26. package/dist/install/ui.js +15 -33
  27. package/dist/install/ui.js.map +1 -1
  28. package/dist/installSession.js +0 -4
  29. package/dist/launcher.d.ts.map +1 -1
  30. package/dist/launcher.js +16 -7
  31. package/dist/launcher.js.map +1 -1
  32. package/dist/output.d.ts +1 -0
  33. package/dist/output.d.ts.map +1 -1
  34. package/dist/output.js +3 -0
  35. package/dist/output.js.map +1 -1
  36. package/dist/preflight.d.ts +2 -0
  37. package/dist/preflight.d.ts.map +1 -1
  38. package/dist/preflight.js +64 -209
  39. package/dist/preflight.js.map +1 -1
  40. package/dist/project/eligibility.d.ts +11 -1
  41. package/dist/project/eligibility.d.ts.map +1 -1
  42. package/dist/project/eligibility.js +12 -1
  43. package/dist/project/eligibility.js.map +1 -1
  44. package/dist/project.d.ts +3 -0
  45. package/dist/project.d.ts.map +1 -1
  46. package/dist/project.js +56 -21
  47. package/dist/project.js.map +1 -1
  48. package/dist/router.d.ts +5 -1
  49. package/dist/router.d.ts.map +1 -1
  50. package/dist/router.js +201 -93
  51. package/dist/router.js.map +1 -1
  52. package/dist/runtime/releaseSource.d.ts +10 -0
  53. package/dist/runtime/releaseSource.d.ts.map +1 -1
  54. package/dist/runtime/releaseSource.js +82 -6
  55. package/dist/runtime/releaseSource.js.map +1 -1
  56. package/dist/runtime/selfUpdate.d.ts +4 -1
  57. package/dist/runtime/selfUpdate.d.ts.map +1 -1
  58. package/dist/runtime/selfUpdate.js +12 -6
  59. package/dist/runtime/selfUpdate.js.map +1 -1
  60. package/dist/runtime/signers.js +15 -7
  61. package/dist/runtime/store.d.ts +2 -1
  62. package/dist/runtime/store.d.ts.map +1 -1
  63. package/dist/runtime/store.js +20 -9
  64. package/dist/runtime/store.js.map +1 -1
  65. package/dist/sbom.json +21 -23
  66. package/dist/scanner/discover.d.ts +12 -1
  67. package/dist/scanner/discover.d.ts.map +1 -1
  68. package/dist/scanner/discover.js +48 -14
  69. package/dist/scanner/discover.js.map +1 -1
  70. package/dist/scanner/enable.d.ts +23 -5
  71. package/dist/scanner/enable.d.ts.map +1 -1
  72. package/dist/scanner/enable.js +93 -21
  73. package/dist/scanner/enable.js.map +1 -1
  74. package/dist/scanner/picker.d.ts +7 -1
  75. package/dist/scanner/picker.d.ts.map +1 -1
  76. package/dist/scanner/picker.js +64 -13
  77. package/dist/scanner/picker.js.map +1 -1
  78. package/dist/scanner-release.json +25 -25
  79. package/dist/screens/journey.d.ts +13 -3
  80. package/dist/screens/journey.d.ts.map +1 -1
  81. package/dist/screens/journey.js +145 -53
  82. package/dist/screens/journey.js.map +1 -1
  83. package/dist/screens.d.ts +2 -3
  84. package/dist/screens.d.ts.map +1 -1
  85. package/dist/screens.js +6 -16
  86. package/dist/screens.js.map +1 -1
  87. package/dist/status.d.ts +5 -3
  88. package/dist/status.d.ts.map +1 -1
  89. package/dist/status.js +194 -110
  90. package/dist/status.js.map +1 -1
  91. package/dist/vendor/local-setup.js +124 -27
  92. package/dist/vendor/shared/runtimeSigners.js +11 -6
  93. package/package.json +45 -41
package/dist/router.js CHANGED
@@ -562,7 +562,7 @@ var init_hookRuntime = __esm({
562
562
  });
563
563
 
564
564
  // packages/cli/src/router.ts
565
- import { enableScanner } from "./scanner/enable.js";
565
+ import { enableScanner, updateScannerRoots } from "./scanner/enable.js";
566
566
  import { controlScanner, scannerReceipt } from "./scanner/control.js";
567
567
  import { updateScanner } from "./scanner/update.js";
568
568
  import { deleteScannerIndex } from "./scanner/data.js";
@@ -4774,8 +4774,6 @@ var stateFor = {
4774
4774
  scanner_not_verified: "LIMITED",
4775
4775
  hook_not_verified: "LIMITED",
4776
4776
  hooks_missing: "ACTION_REQUIRED",
4777
- host_grant_unbound: "LIMITED",
4778
- host_not_connected: "LIMITED",
4779
4777
  scanner_omitted: "LIMITED",
4780
4778
  project_uncovered: "LIMITED",
4781
4779
  host_skipped: "LIMITED",
@@ -4791,8 +4789,6 @@ var rank = {
4791
4789
  FAILED: 3
4792
4790
  };
4793
4791
  function defaultAction(condition) {
4794
- if (condition.kind === "host_skipped" && condition.component)
4795
- return `Connect it later: mnemonik connect ${condition.component}`;
4796
4792
  if (condition.kind === "windows_task_creation_failed")
4797
4793
  return "Run mnemonik scanner enable to try again.";
4798
4794
  return condition.action;
@@ -4821,7 +4817,7 @@ function remainingReadinessCount(summary2) {
4821
4817
  }
4822
4818
  function describeReadiness(summary2) {
4823
4819
  if (summary2.state === "READY")
4824
- return "Done. Your editors will use Mnemonik on their next session.";
4820
+ return "Done.";
4825
4821
  const count = remainingReadinessCount(summary2);
4826
4822
  const opening = summary2.state === "FAILED" ? "Setup failed." : count === 0 ? "Done." : summary2.state === "ACTION_REQUIRED" ? `Setup needs ${count === 1 ? "one action" : `${count} actions`}.` : `Done, with ${count === 1 ? "one thing" : `${count} things`} left.`;
4827
4823
  return [opening, ...summary2.reasons.map(sentence), ...summary2.actions].join(" ");
@@ -4960,18 +4956,23 @@ import {
4960
4956
  import { hostOrder } from "./install/adapters.js";
4961
4957
  import { readInstallVersions } from "./install/ownership.js";
4962
4958
  import { ensureLauncher, removeLauncher, LauncherError } from "./launcher.js";
4963
- import { readFile } from "node:fs/promises";
4959
+ import { readFile, realpath } from "node:fs/promises";
4960
+ import { createInterface } from "node:readline";
4964
4961
  import { RuntimeStore, updateRuntime } from "./runtime/store.js";
4965
- import { updateCli, cliUpdateLine, cliUpdateHint } from "./runtime/selfUpdate.js";
4962
+ import { updateCli, cliUpdateHint } from "./runtime/selfUpdate.js";
4966
4963
  import { homedir as homedir2 } from "node:os";
4967
4964
  import { join as join3 } from "node:path";
4968
4965
  import { Output } from "./output.js";
4969
4966
  import { renderPreflight, runPreflight } from "./preflight.js";
4970
4967
  import { postCurrentReadiness } from "./installSession.js";
4971
4968
  import {
4969
+ createRealProjectRuntime,
4970
+ ensureProjectRoot,
4972
4971
  ensureProjectForAgent,
4972
+ projectLimitMessage,
4973
4973
  runProjectCommand
4974
4974
  } from "./project.js";
4975
+ import { evaluateRoot } from "./project/eligibility.js";
4975
4976
  import { grantTransport, grantHost } from "./auth/status.js";
4976
4977
  import { createCliAuth } from "./auth/index.js";
4977
4978
  import { currentInstallSession, ensureInstallSession } from "./auth/installSession.js";
@@ -4994,6 +4995,16 @@ import {
4994
4995
  sendDiagnostics
4995
4996
  } from "./diagnostics.js";
4996
4997
  var supportedHosts = ["claude-code", "codex", "cursor", "grok"];
4998
+ var editorNames = {
4999
+ "claude-code": "Claude Code",
5000
+ codex: "Codex",
5001
+ cursor: "Cursor",
5002
+ grok: "Grok"
5003
+ };
5004
+ var connectFolderPrompt = (name2) => `Connect ${name2} to Mnemonik? [Y/n]`;
5005
+ var removeFolderPrompt = (name2) => `Stop indexing ${name2}? Its memories stay in your account. [y/N]`;
5006
+ var connectedFolderLine = (name2) => ` \u2713 Connected ${name2}.`;
5007
+ var removedFolderLine = (name2) => ` \u2713 ${name2} is no longer connected.`;
4997
5008
  function maintenanceExitCode(results) {
4998
5009
  if (results.some((result) => result.status === "FAILED")) return 1;
4999
5010
  return results.every((result) => result.status === "READY") ? 0 : 3;
@@ -5003,9 +5014,9 @@ var booleans = /* @__PURE__ */ new Set([
5003
5014
  "non-interactive",
5004
5015
  "agent",
5005
5016
  "accept-scanner",
5017
+ "accept-indexing",
5006
5018
  "accept-limited",
5007
5019
  "apply",
5008
- "approve-host",
5009
5020
  "confirm",
5010
5021
  "without-scanner",
5011
5022
  "non-git",
@@ -5016,12 +5027,12 @@ var booleans = /* @__PURE__ */ new Set([
5016
5027
  "backup",
5017
5028
  "verify",
5018
5029
  "dry-run",
5019
- "reopen-install"
5030
+ "reopen-install",
5031
+ "automatic"
5020
5032
  ]);
5021
5033
  var values = /* @__PURE__ */ new Set([
5022
5034
  "components",
5023
5035
  "hosts",
5024
- "integration-scope",
5025
5036
  "scan-roots",
5026
5037
  "host",
5027
5038
  "scope",
@@ -5039,8 +5050,8 @@ Commands:
5039
5050
  status
5040
5051
  connect <claude-code|codex|cursor|grok>
5041
5052
  project <init|setup|status|link|ensure>
5042
- scanner <enable|start|stop|pause|resume|status|export-preview>
5043
- roots <add|remove|list>
5053
+ add <folder>
5054
+ remove <folder>
5044
5055
  data delete --project <id>
5045
5056
  diagnostics <preview|send>
5046
5057
  doctor
@@ -5053,7 +5064,7 @@ Commands:
5053
5064
  logout
5054
5065
 
5055
5066
  Global options: --json --non-interactive --no-browser --help --version
5056
- Install consent: --accept-scanner --without-scanner --accept-limited --apply`;
5067
+ Install consent: --accept-indexing --accept-limited --apply`;
5057
5068
  function parse(args2) {
5058
5069
  const positionals = [];
5059
5070
  const flags2 = /* @__PURE__ */ new Map();
@@ -5071,7 +5082,7 @@ function parse(args2) {
5071
5082
  }
5072
5083
  if (booleans.has(name2)) {
5073
5084
  if (inline !== void 0) return { positionals, flags: flags2, error: `Unknown flag: ${argument}` };
5074
- flags2.set(name2, true);
5085
+ flags2.set(name2 === "accept-scanner" ? "accept-indexing" : name2, true);
5075
5086
  continue;
5076
5087
  }
5077
5088
  if (values.has(name2)) {
@@ -5141,22 +5152,39 @@ async function hostDependencies(deps, output, state) {
5141
5152
  if (deps.hostManagement) return deps.hostManagement;
5142
5153
  const cliAuth = auth(deps, output, false);
5143
5154
  const grants = grantTransport(async () => {
5144
- const bearer = await cliAuth.getCliBearer();
5145
- if (typeof bearer !== "string") throw new Error(bearer.reason);
5146
- return bearer;
5155
+ const bearer2 = await cliAuth.getCliBearer();
5156
+ if (typeof bearer2 !== "string") throw new Error(bearer2.reason);
5157
+ return bearer2;
5147
5158
  }, deps.grantFetch);
5159
+ const bearer = await cliAuth.getCliBearer();
5160
+ if (typeof bearer !== "string") throw new Error(bearer.reason);
5161
+ if (!cliAuth.accountEmail) throw new Error("account_identity_failed");
5162
+ const email = await cliAuth.accountEmail(bearer);
5163
+ const installation = JSON.parse(
5164
+ await readFile(join3(state, "installation.json"), "utf8").catch(() => "{}")
5165
+ );
5148
5166
  return {
5149
5167
  stateDir: state,
5150
- account: (await grants.list()).account,
5168
+ account: typeof installation.account === "string" ? installation.account : email,
5151
5169
  grants,
5152
5170
  getCliBearer: async () => {
5153
- const bearer = await cliAuth.getCliBearer();
5154
- if (typeof bearer !== "string") throw new Error(bearer.reason);
5155
- return bearer;
5171
+ const bearer2 = await cliAuth.getCliBearer();
5172
+ if (typeof bearer2 !== "string") throw new Error(bearer2.reason);
5173
+ return bearer2;
5156
5174
  },
5157
5175
  credentialFetch: deps.grantFetch
5158
5176
  };
5159
5177
  }
5178
+ async function updateHostDependencies(deps, state) {
5179
+ if (deps.hostManagement) return { ...deps.hostManagement, stateDir: state };
5180
+ const installation = JSON.parse(
5181
+ await readFile(join3(state, "installation.json"), "utf8").catch(() => "{}")
5182
+ );
5183
+ return {
5184
+ stateDir: state,
5185
+ account: typeof installation.account === "string" ? installation.account : ""
5186
+ };
5187
+ }
5160
5188
  async function packageVersion() {
5161
5189
  const contents = await readFile(new URL("../package.json", import.meta.url), "utf8");
5162
5190
  return JSON.parse(contents).version;
@@ -5164,7 +5192,7 @@ async function packageVersion() {
5164
5192
  async function runHostCommand(command, parsed, deps, output, scannerSelected = false) {
5165
5193
  const json = parsed.flags.has("json");
5166
5194
  const state = deps.hostManagement?.stateDir ?? deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
5167
- const scope = parsed.flags.get(command === "install" ? "integration-scope" : "scope");
5195
+ const scope = command === "install" ? void 0 : parsed.flags.get("scope");
5168
5196
  const host = parsed.flags.get("host");
5169
5197
  const component = parsed.flags.get("component");
5170
5198
  const fullUninstall = command === "uninstall" && !host && !scope && !component;
@@ -5179,7 +5207,6 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5179
5207
  if (components.some((c) => !["hooks", "mcp"].includes(c)))
5180
5208
  return placeholder(output, json, "install scanner", "scanner setup");
5181
5209
  const missing = requireConsent(parsed, output, [
5182
- "integration-scope",
5183
5210
  ...scannerSelected ? [] : ["accept-limited"],
5184
5211
  "apply"
5185
5212
  ]);
@@ -5189,7 +5216,7 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5189
5216
  (name2) => [...new Set(components)].map((component2) => ({
5190
5217
  component: component2,
5191
5218
  host: name2,
5192
- scope,
5219
+ scope: "user",
5193
5220
  home: deps.home ?? homedir2(),
5194
5221
  projectRoot: deps.cwd ?? process.cwd()
5195
5222
  }))
@@ -5201,6 +5228,8 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5201
5228
  scope ? String(scope) : void 0,
5202
5229
  component ? String(component) : void 0
5203
5230
  );
5231
+ if (command === "update")
5232
+ resolved.selected = resolved.selected.filter((target) => target.component === "hooks");
5204
5233
  if (resolved.ambiguous.length && !json && !parsed.flags.has("non-interactive")) {
5205
5234
  const profile = await chooseHostProfile(
5206
5235
  deps.input ?? process.stdin,
@@ -5238,7 +5267,7 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5238
5267
  const store = new RuntimeStore(state);
5239
5268
  const cli = all ? await updateCli(store) : void 0;
5240
5269
  const updatedCli = selections.length && (cli?.status === "UPDATED" || cli?.status === "UP_TO_DATE") ? await store.verifyRuntime("cli") : void 0;
5241
- const managed = selections.length || (await interrupted(state)).length ? await hostDependencies(deps, output, state) : void 0;
5270
+ const managed = selections.length || (await interrupted(state)).length ? command === "update" ? await updateHostDependencies(deps, state) : await hostDependencies(deps, output, state) : void 0;
5242
5271
  const result = managed ? await runHosts(
5243
5272
  command,
5244
5273
  selections,
@@ -5250,17 +5279,9 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5250
5279
  join3(updatedCli.directory, "node_modules/@mnemonik/cli/package.json")
5251
5280
  ) : void 0),
5252
5281
  instruction: json ? void 0 : (text) => output.line(text),
5253
- timeout: managed.timeout ?? (json || parsed.flags.has("non-interactive") ? void 0 : async (host2) => (await chooseHostProfile(deps.input ?? process.stdin, output, [
5254
- `Retry ${host2}`,
5255
- `Skip ${host2}`
5256
- ]))?.startsWith("Retry") ? "retry" : "skip"),
5257
- apply: parsed.flags.has("apply"),
5258
- offerRevoke: managed.offerRevoke ?? (json || parsed.flags.has("non-interactive") ? void 0 : async (host2) => (await chooseHostProfile(deps.input ?? process.stdin, output, [
5259
- `Keep ${host2} grant`,
5260
- `Revoke ${host2} grant`
5261
- ]))?.startsWith("Revoke") ?? false)
5282
+ apply: parsed.flags.has("apply")
5262
5283
  },
5263
- parsed.flags.has("integration-scope")
5284
+ false
5264
5285
  ) : { journal: { state: "READY" }, results: [], reports: [] };
5265
5286
  let scanner;
5266
5287
  let launcher;
@@ -5269,11 +5290,15 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5269
5290
  () => false
5270
5291
  )) {
5271
5292
  try {
5293
+ const before = await store.verifyRuntime("scanner").catch(() => void 0);
5272
5294
  const runtime = await updateScanner(
5273
5295
  { stateDir: state, ...deps.scannerService },
5274
5296
  deps.scannerEnable?.source
5275
5297
  );
5276
- scanner = { status: "UPDATED", version: runtime.manifest.version };
5298
+ scanner = {
5299
+ status: before?.reference.version === runtime.reference.version ? "UP_TO_DATE" : "UPDATED",
5300
+ version: runtime.manifest.version
5301
+ };
5277
5302
  } catch (error) {
5278
5303
  scanner = { status: "FAILED", reason: error.message };
5279
5304
  }
@@ -5315,7 +5340,13 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5315
5340
  ...launcher ? { launcher } : {},
5316
5341
  ...cli ? { cli } : {}
5317
5342
  });
5318
- else {
5343
+ else if (command === "update") {
5344
+ if (failed || hostExit !== 0)
5345
+ output.error("Mnemonik could not update. Run mnemonik update again.");
5346
+ else if (cli?.status === "UPDATED" || result.reports.length > 0 || scanner?.status === "UPDATED")
5347
+ output.line("Mnemonik updated.");
5348
+ else output.line("Mnemonik is up to date.");
5349
+ } else {
5319
5350
  for (const target of result.results)
5320
5351
  output.line(
5321
5352
  `${target.target}: ${target.status} (${target.reason}${target.detail ? `: ${target.detail}` : ""})`
@@ -5328,11 +5359,14 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5328
5359
  );
5329
5360
  else if (scanner)
5330
5361
  output.line(`Scanner ${scanner.status}: ${scanner.version ?? scanner.reason}.`);
5331
- if (cli) output.line(cliUpdateLine(cli));
5332
5362
  }
5333
5363
  if (scanner?.status === "failed") output.error(scanner.reason ?? "scanner_uninstall_failed");
5334
5364
  return failed ? 1 : hostExit;
5335
5365
  } catch (error) {
5366
+ if (command === "update" && !json) {
5367
+ output.error("Mnemonik could not update. Run mnemonik update again.");
5368
+ return error instanceof LauncherError ? 3 : 1;
5369
+ }
5336
5370
  if (error instanceof LauncherError) {
5337
5371
  if (json)
5338
5372
  output.json({ status: error.status, reason: error.message, launcher: error.launcher });
@@ -5349,13 +5383,13 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
5349
5383
  }
5350
5384
  async function hostCommand(command, parsed, deps, output, scannerSelected = false) {
5351
5385
  const code = await runHostCommand(command, parsed, deps, output, scannerSelected);
5352
- if (command === "update" || command === "repair") await reportCurrentInstallation(deps, output);
5386
+ if (command === "repair") await reportCurrentInstallation(deps, output);
5353
5387
  return code;
5354
5388
  }
5355
5389
  async function enableCommand(parsed, deps, output) {
5356
5390
  const json = parsed.flags.has("json");
5357
5391
  if (parsed.flags.has("non-interactive") || json) {
5358
- const missing = requireConsent(parsed, output, ["accept-scanner", "apply"]);
5392
+ const missing = requireConsent(parsed, output, ["accept-indexing", "apply"]);
5359
5393
  if (missing !== void 0) return missing;
5360
5394
  if (!parsed.flags.has("scan-roots"))
5361
5395
  return actionRequired2(
@@ -5371,6 +5405,7 @@ async function enableCommand(parsed, deps, output) {
5371
5405
  const result = await enableScanner({
5372
5406
  stateDir: deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home),
5373
5407
  cwd: deps.cwd ?? process.cwd(),
5408
+ home: deps.home,
5374
5409
  input: deps.input ?? process.stdin,
5375
5410
  output,
5376
5411
  nonInteractive: parsed.flags.has("non-interactive") || json,
@@ -5378,7 +5413,9 @@ async function enableCommand(parsed, deps, output) {
5378
5413
  ...typeof roots === "string" ? { roots: roots.split(",").filter(Boolean) } : {},
5379
5414
  ...typeof exclusions === "string" ? { exclusions: exclusions.split(",").filter(Boolean) } : {},
5380
5415
  ...deps.scannerService,
5381
- ...deps.scannerEnable
5416
+ ...deps.scannerEnable,
5417
+ projectExecutor: deps.projectExecutor,
5418
+ projectStateDir: deps.projectStateDir
5382
5419
  });
5383
5420
  if (json) output.json(result);
5384
5421
  else renderStatusSummaries(result, output);
@@ -5398,10 +5435,9 @@ async function installCommand(parsed, deps, output) {
5398
5435
  const invalid = allowed(parsed, [
5399
5436
  "components",
5400
5437
  "hosts",
5401
- "integration-scope",
5402
5438
  "scan-roots",
5403
5439
  "exclusions",
5404
- "accept-scanner",
5440
+ "accept-indexing",
5405
5441
  "accept-limited",
5406
5442
  "without-scanner",
5407
5443
  "apply",
@@ -5416,7 +5452,7 @@ async function installCommand(parsed, deps, output) {
5416
5452
  parsed.flags,
5417
5453
  deps,
5418
5454
  output,
5419
- () => ensureCliAuth(deps, output, parsed.flags.has("no-browser"), !parsed.flags.has("json")),
5455
+ () => ensureCliAuth(deps, output, parsed.flags.has("no-browser"), false),
5420
5456
  () => hostDependencies(deps, output, state)
5421
5457
  );
5422
5458
  }
@@ -5485,7 +5521,7 @@ async function doctorCommand(parsed, deps, output) {
5485
5521
  if (parsed.flags.has("json")) output.json(document);
5486
5522
  else {
5487
5523
  renderPreflight(result, output);
5488
- renderStatusSummaries(document, output);
5524
+ renderStatusSummaries(document, output, { diagnostics: true });
5489
5525
  }
5490
5526
  return document.installation.state === "READY" ? 0 : document.installation.state === "FAILED" ? 1 : 3;
5491
5527
  }
@@ -5513,11 +5549,6 @@ async function collectCurrentInstallation(deps, output) {
5513
5549
  projectHookConditions: deps.projectHookConditions,
5514
5550
  configuredHosts: deps.configuredHosts ?? deps.install?.input.hosts,
5515
5551
  details: deps.statusDetails,
5516
- grants: deps.hostManagement?.grants ?? grantTransport(async () => {
5517
- const bearer = await auth(deps, output, false).getCliBearer();
5518
- if (typeof bearer !== "string") throw new Error(bearer.reason);
5519
- return bearer;
5520
- }, deps.grantFetch),
5521
5552
  generatedAt: deps.statusGeneratedAt,
5522
5553
  launcher: { ...deps.launcher, stateDir: hostStateDir, home: deps.home }
5523
5554
  });
@@ -5540,14 +5571,19 @@ async function reportCurrentInstallation(deps, output, document) {
5540
5571
  }
5541
5572
  }
5542
5573
  async function runCli(args2, deps = {}) {
5543
- const output = new Output(deps.stdout ?? process.stdout, deps.stderr ?? process.stderr, {
5574
+ const parsed = parse(args2);
5575
+ const silent = parsed.flags.has("automatic");
5576
+ const discard = { write: () => {
5577
+ } };
5578
+ const stdout = silent ? discard : deps.stdout ?? process.stdout;
5579
+ const stderr = silent ? discard : deps.stderr ?? process.stderr;
5580
+ const output = new Output(stdout, stderr, {
5544
5581
  home: deps.home ?? homedir2()
5545
5582
  });
5546
- if (process.env.MNEMONIK_DEV_RELEASE_DIR)
5547
- (deps.stderr ?? process.stderr).write(
5583
+ if (process.env.MNEMONIK_DEV_RELEASE_DIR && !silent)
5584
+ stderr.write(
5548
5585
  "WARNING: MNEMONIK_DEV_RELEASE_DIR uses development artifacts; readiness remains LIMITED (dev_release_source).\n"
5549
5586
  );
5550
- const parsed = parse(args2);
5551
5587
  if (parsed.error) return output.error(parsed.error), 2;
5552
5588
  if (parsed.flags.has("version")) {
5553
5589
  if (parsed.positionals.length || parsed.flags.size !== 1)
@@ -5566,21 +5602,84 @@ async function runCli(args2, deps = {}) {
5566
5602
  if (subcommand) return output.error(`Unexpected argument: ${subcommand}`), 2;
5567
5603
  return installCommand(parsed, deps, output);
5568
5604
  }
5569
- if (command === "roots") {
5570
- const invalid = allowed(parsed, ["accept-scanner", "apply", "no-browser"]);
5571
- if (invalid || !["add", "remove", "list"].includes(subcommand ?? "") || rest.length !== (subcommand === "list" ? 0 : 1))
5572
- return output.error(invalid ?? "Usage: mnemonik roots <add|remove> <path>, or roots list"), 2;
5605
+ if (command === "roots" || command === "add" || command === "remove") {
5606
+ const action = command === "roots" ? subcommand : command;
5607
+ const actionArguments = command === "roots" ? rest : [subcommand, ...rest].filter(Boolean);
5608
+ const invalid = allowed(parsed, ["accept-indexing", "apply", "no-browser"]);
5609
+ if (invalid || !["add", "remove", "list"].includes(action ?? "") || actionArguments.length !== (action === "list" ? 0 : 1))
5610
+ return output.error(invalid ?? "Usage: mnemonik add <folder> or mnemonik remove <folder>"), 2;
5573
5611
  const stateDir = deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
5574
5612
  const saved = JSON.parse(
5575
5613
  await readFile(`${stateDir}/scanner/state.json`, "utf8").catch(() => "null")
5576
5614
  );
5577
- if (!saved) return actionRequired2(output, parsed.flags.has("json"), "mnemonik scanner enable");
5578
- if (subcommand === "list") {
5615
+ if (!saved) return actionRequired2(output, parsed.flags.has("json"), "mnemonik install");
5616
+ if (action === "list") {
5579
5617
  if (parsed.flags.has("json")) output.json(saved.config.roots);
5580
5618
  else for (const root of saved.config.roots) output.line(root);
5581
5619
  return 0;
5582
5620
  }
5583
- const roots = subcommand === "add" ? [.../* @__PURE__ */ new Set([...saved.config.roots, rest[0] ?? ""])] : saved.config.roots.filter((root) => root !== rest[0]);
5621
+ if (action === "add" && (parsed.flags.has("non-interactive") || parsed.flags.has("json")) && !parsed.flags.has("apply"))
5622
+ return actionRequired2(output, parsed.flags.has("json"), "Rerun with --apply", "--apply");
5623
+ const pathArgument = actionArguments[0] ?? "";
5624
+ const requested = action === "add" ? await realpath(pathArgument) : saved.config.roots.find((root) => root === pathArgument) ?? pathArgument;
5625
+ const name2 = requested.split(/[\\/]/u).filter(Boolean).at(-1) ?? requested;
5626
+ if (!parsed.flags.has("non-interactive") && !parsed.flags.has("json")) {
5627
+ output.line(action === "add" ? connectFolderPrompt(name2) : removeFolderPrompt(name2));
5628
+ const readline = createInterface({ input: deps.input ?? process.stdin, terminal: false });
5629
+ const answer = String((await readline[Symbol.asyncIterator]().next()).value ?? "").trim();
5630
+ readline.close();
5631
+ if (action === "add" && /^(?:n|no)$/iu.test(answer) || action === "remove" && !/^(?:y|yes)$/iu.test(answer))
5632
+ return 130;
5633
+ }
5634
+ const bearer = await ensureCliAuth(deps, output, parsed.flags.has("no-browser"), false);
5635
+ if (action === "add") {
5636
+ let executor = deps.projectExecutor;
5637
+ if (!executor)
5638
+ executor = (await createRealProjectRuntime({
5639
+ stateDir: deps.projectStateDir ?? stateDir,
5640
+ getCliBearer: async () => bearer,
5641
+ fetch: deps.grantFetch
5642
+ })).executor;
5643
+ const resolution = await executor.resolveProjectIdentity(requested);
5644
+ const decision = await evaluateRoot(resolution, {
5645
+ cwd: requested,
5646
+ home: deps.home,
5647
+ nonGitSelected: true
5648
+ });
5649
+ if (!decision.allowed)
5650
+ return actionRequired2(output, parsed.flags.has("json"), decision.reason);
5651
+ const project = await ensureProjectRoot(requested, executor);
5652
+ const limit = projectLimitMessage(project, requested);
5653
+ if (limit) {
5654
+ if (parsed.flags.has("json"))
5655
+ output.json({
5656
+ status: "ACTION_REQUIRED",
5657
+ state: "project_limit_reached",
5658
+ message: limit.join(" ")
5659
+ });
5660
+ else for (const line of limit) output.line(line);
5661
+ return 3;
5662
+ }
5663
+ if (project.status !== "done") {
5664
+ output.error(
5665
+ `Project action required: ${"state" in project ? project.state : project.status}`
5666
+ );
5667
+ return 3;
5668
+ }
5669
+ }
5670
+ const updated = await updateScannerRoots({
5671
+ stateDir,
5672
+ bearer,
5673
+ add: action === "add" ? [requested] : [],
5674
+ remove: action === "remove" ? [requested] : [],
5675
+ fetch: deps.grantFetch
5676
+ });
5677
+ if (updated.status === "updated") {
5678
+ if (parsed.flags.has("json")) output.json(updated.state.config.roots);
5679
+ else output.line(action === "add" ? connectedFolderLine(name2) : removedFolderLine(name2));
5680
+ return 0;
5681
+ }
5682
+ const roots = action === "add" ? [.../* @__PURE__ */ new Set([...saved.config.roots, requested])] : saved.config.roots.filter((root) => root !== requested);
5584
5683
  parsed.flags.set("scan-roots", roots.join(","));
5585
5684
  parsed.flags.set("exclusions", (saved.config.exclusions ?? []).join(","));
5586
5685
  return enableCommand(parsed, deps, output);
@@ -5642,15 +5741,20 @@ async function runCli(args2, deps = {}) {
5642
5741
  ...deps.scannerService
5643
5742
  };
5644
5743
  if (command === "update") {
5744
+ const store = new RuntimeStore(options.stateDir);
5745
+ const before = await store.verifyRuntime("scanner").catch(() => void 0);
5645
5746
  const runtime = await updateScanner(options, deps.scannerEnable?.source);
5646
5747
  const result = {
5647
- status: "updated",
5748
+ status: before?.reference.version === runtime.reference.version ? "up_to_date" : "updated",
5648
5749
  version: runtime.manifest.version,
5649
5750
  cli: { status: "NOT_SELECTED" },
5650
5751
  ...process.env.MNEMONIK_DEV_RELEASE_DIR ? { status: "LIMITED", reason: "dev_release_source" } : {}
5651
5752
  };
5652
5753
  if (parsed.flags.has("json")) output.json(result);
5653
- else output.line(`Scanner ${result.status}: ${result.version}.`);
5754
+ else
5755
+ output.line(
5756
+ result.status === "updated" ? "Mnemonik updated." : "Mnemonik is up to date."
5757
+ );
5654
5758
  } else {
5655
5759
  await scannerService(options).uninstall();
5656
5760
  const result = {
@@ -5664,16 +5768,23 @@ async function runCli(args2, deps = {}) {
5664
5768
  "Stopped collection; removed local software. Credentials, cloud data and consent retained."
5665
5769
  );
5666
5770
  }
5667
- if (command === "update") await reportCurrentInstallation(deps, output);
5668
5771
  return 0;
5669
5772
  } catch (error) {
5670
- output.error(error.message);
5671
- if (command === "update") await reportCurrentInstallation(deps, output);
5773
+ output.error(
5774
+ command === "update" ? "Mnemonik could not update. Run mnemonik update again." : error.message
5775
+ );
5672
5776
  return 3;
5673
5777
  }
5674
5778
  }
5675
5779
  if (command === "repair" || command === "update" || command === "uninstall") {
5676
- const invalid = allowed(parsed, ["host", "scope", "component", "confirm", "apply"]);
5780
+ const invalid = allowed(parsed, [
5781
+ "host",
5782
+ "scope",
5783
+ "component",
5784
+ "confirm",
5785
+ "apply",
5786
+ ...command === "update" ? ["automatic"] : []
5787
+ ]);
5677
5788
  if (invalid || subcommand)
5678
5789
  return output.error(invalid ?? `Unexpected argument: ${subcommand}`), 2;
5679
5790
  if (command === "uninstall" && parsed.flags.has("non-interactive")) {
@@ -5684,7 +5795,7 @@ async function runCli(args2, deps = {}) {
5684
5795
  return hostCommand(command, parsed, deps, output);
5685
5796
  }
5686
5797
  if (command === "update") {
5687
- const invalid = allowed(parsed, []);
5798
+ const invalid = allowed(parsed, ["automatic"]);
5688
5799
  if (invalid || subcommand)
5689
5800
  return output.error(invalid ?? `Unexpected argument: ${subcommand}`), 2;
5690
5801
  if (!deps.runtimeUpdate)
@@ -5701,8 +5812,7 @@ async function runCli(args2, deps = {}) {
5701
5812
  artifact: runtime.manifest.artifact,
5702
5813
  version: runtime.manifest.version
5703
5814
  });
5704
- else output.line(`Updated ${runtime.manifest.artifact} to ${runtime.manifest.version}.`);
5705
- await reportCurrentInstallation(deps, output);
5815
+ else output.line("Mnemonik updated.");
5706
5816
  return 0;
5707
5817
  }
5708
5818
  if (command === "doctor") {
@@ -5754,7 +5864,6 @@ Preview: ${preview.path}
5754
5864
  deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home)
5755
5865
  );
5756
5866
  if (!parsed.flags.has("json")) {
5757
- output.line(`CLI ${version}.`);
5758
5867
  renderStatusSummaries(document, output);
5759
5868
  }
5760
5869
  const hint = await cliUpdateHint(store, version);
@@ -5765,15 +5874,10 @@ Preview: ${preview.path}
5765
5874
  return statusExitCode(document);
5766
5875
  }
5767
5876
  if (command === "connect") {
5768
- const invalid = allowed(parsed, ["approve-host", "no-browser", "scope"]);
5877
+ const invalid = allowed(parsed, ["scope"]);
5769
5878
  if (invalid) return output.error(invalid), 2;
5770
5879
  if (!subcommand || rest.length || !supportedHosts.includes(subcommand))
5771
5880
  return output.error("Usage: mnemonik connect <claude-code|codex|cursor|grok>"), 2;
5772
- if (parsed.flags.has("non-interactive") || parsed.flags.has("json")) {
5773
- const missing = requireConsent(parsed, output, ["approve-host"]);
5774
- if (missing !== void 0) return missing;
5775
- }
5776
- await ensureCliAuth(deps, output, parsed.flags.has("no-browser"), false);
5777
5881
  const state = deps.hostManagement?.stateDir ?? deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
5778
5882
  const owned = await selectOwned(
5779
5883
  state,
@@ -5781,33 +5885,33 @@ Preview: ${preview.path}
5781
5885
  parsed.flags.get("scope"),
5782
5886
  "mcp"
5783
5887
  );
5888
+ if (!owned.selected.length && !parsed.flags.has("json")) {
5889
+ output.line(
5890
+ `${editorNames[subcommand]} will ask you to sign in to Mnemonik the first time you use it.`
5891
+ );
5892
+ return 3;
5893
+ }
5784
5894
  if (owned.selected.length !== 1)
5785
5895
  return actionRequired2(
5786
5896
  output,
5787
5897
  parsed.flags.has("json"),
5788
5898
  owned.selected.length ? "ambiguous_profile" : "no_recorded_targets"
5789
5899
  );
5790
- const managed = await hostDependencies(deps, output, state);
5900
+ const managed = deps.hostManagement ?? { stateDir: state, account: "" };
5791
5901
  const selected = owned.selected[0];
5792
5902
  if (!selected) throw new Error("no_recorded_targets");
5793
- let approval = parsed.flags.has("approve-host") ? true : void 0;
5903
+ let instructionShown = false;
5794
5904
  const result = await connectHost(selected, {
5795
5905
  ...managed,
5796
- noBrowser: parsed.flags.has("no-browser"),
5797
- approveHost: async () => approval ??= (await chooseHostProfile(deps.input ?? process.stdin, output, [
5798
- `Approve ${subcommand} for account ${managed.account} on this machine`,
5799
- "Cancel"
5800
- ]))?.startsWith("Approve") ?? false,
5801
5906
  instruction: (text) => {
5802
- if (!parsed.flags.has("json")) output.line(text);
5803
- },
5804
- timeout: managed.timeout ?? (parsed.flags.has("json") || parsed.flags.has("non-interactive") ? void 0 : async (host) => (await chooseHostProfile(deps.input ?? process.stdin, output, [
5805
- `Retry ${host}`,
5806
- `Skip ${host}`
5807
- ]))?.startsWith("Retry") ? "retry" : "skip")
5907
+ if (!parsed.flags.has("json")) {
5908
+ output.line(text);
5909
+ instructionShown = true;
5910
+ }
5911
+ }
5808
5912
  });
5809
5913
  if (parsed.flags.has("json")) output.json(result);
5810
- else
5914
+ else if (!instructionShown)
5811
5915
  output.line(`${result.status}: ${result.reason}${result.action ? `. ${result.action}` : ""}`);
5812
5916
  return result.status === "READY" ? 0 : 3;
5813
5917
  }
@@ -5926,7 +6030,7 @@ Preview: ${preview.path}
5926
6030
  return output.error("Usage: mnemonik scanner <enable|start|stop|uninstall|status>"), 2;
5927
6031
  const invalid = allowed(
5928
6032
  parsed,
5929
- subcommand === "enable" ? ["accept-scanner", "apply", "scan-roots", "exclusions", "no-browser"] : subcommand === "export-preview" ? ["out"] : []
6033
+ subcommand === "enable" ? ["accept-indexing", "apply", "scan-roots", "exclusions", "no-browser"] : subcommand === "export-preview" ? ["out"] : []
5930
6034
  );
5931
6035
  if (invalid) return output.error(invalid), 2;
5932
6036
  if (subcommand === "enable") return enableCommand(parsed, deps, output);
@@ -6162,7 +6266,11 @@ Preview: ${preview.path}
6162
6266
  }
6163
6267
  var serializeReadiness2 = (input) => devReadiness(serializeReadiness(input));
6164
6268
  export {
6269
+ connectFolderPrompt,
6270
+ connectedFolderLine,
6165
6271
  help,
6166
6272
  maintenanceExitCode,
6273
+ removeFolderPrompt,
6274
+ removedFolderLine,
6167
6275
  runCli
6168
6276
  };