@mnemonik/cli 7.100.0 → 7.101.3

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 +37 -6
  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
@@ -4684,14 +4684,8 @@ function apiOrigin(env = process.env) {
4684
4684
  }
4685
4685
 
4686
4686
  // packages/cli/src/install/hosts.ts
4687
- import {
4688
- bindInstalledHostGrants,
4689
- grantHost,
4690
- matchHostGrant
4691
- } from "../auth/status.js";
4692
4687
  import { readFile, rm } from "node:fs/promises";
4693
4688
  import { dirname as dirname2, join as join2, resolve } from "node:path";
4694
- import { setTimeout as delay } from "node:timers/promises";
4695
4689
  import {
4696
4690
  hostPackageImports
4697
4691
  } from "./adapters.js";
@@ -4708,29 +4702,12 @@ import {
4708
4702
  } from "./ownership.js";
4709
4703
  import { ensureInstallSession } from "../auth/installSession.js";
4710
4704
  import { createCliCredentials } from "../auth/credentials.js";
4705
+ import { readInstallation } from "../installation.js";
4711
4706
  function codexTrustAction(resolvedPath) {
4712
4707
  const desktop = resolvedPath?.includes("/ChatGPT.app/") || /[\\/]Programs[\\/]OpenAI[\\/]Codex[\\/]/i.test(resolvedPath ?? "");
4713
4708
  return desktop ? "Open the ChatGPT app and use the 'Hooks need review' notice at startup to review and allow the Mnemonik hooks. If the notice does not appear, restart the app once." : "Run the codex command in a terminal and use its hook trust prompt to allow the Mnemonik hooks; then quit and reopen Codex.";
4714
4709
  }
4715
4710
  var CODEX_TRUST_ACTION = codexTrustAction();
4716
- var hostLabels = {
4717
- "claude-code": "Claude Code",
4718
- codex: "Codex",
4719
- cursor: "Cursor",
4720
- grok: "Grok"
4721
- };
4722
- var hostNotConnectedCondition = (host) => ({
4723
- kind: "host_not_connected",
4724
- component: host,
4725
- reason: `${host}: signed in, not connected yet`,
4726
- action: `open ${hostLabels[host]} and start a session, then run mnemonik status`
4727
- });
4728
- var hostStillConnectingCondition = (host) => ({
4729
- kind: "login_pending",
4730
- component: host,
4731
- reason: `${hostLabels[host]} is still connecting. Finish the sign-in in the app, then run mnemonik status.`,
4732
- action: "mnemonik status"
4733
- });
4734
4711
  var identity = (t) => `${t.host}:${t.component ?? "hooks"}:${t.scope}:${t.profilePath ?? (t.scope === "user" ? t.home : t.projectRoot)}`;
4735
4712
  async function hostSource(host, packagePath = new URL("../../package.json", import.meta.url)) {
4736
4713
  const pkg = JSON.parse(await readFile(packagePath, "utf8"));
@@ -4775,11 +4752,7 @@ async function apply(journal, run2) {
4775
4752
  for (const target of journal.data.targets.filter((t) => t.group === run2.id))
4776
4753
  await journal.commit(target);
4777
4754
  }
4778
- function actionFor(reason, selection, searchedLocations = [], resolvedPath) {
4779
- if (reason === "not_found") {
4780
- const name2 = hostLabels[selection.host];
4781
- return searchedLocations.length ? `${name2} was not found (looked on PATH and in ${searchedLocations.join(", ")}). Install it, or open a new terminal if you just installed it.` : `${name2} was not found on PATH. Install it, or open a new terminal if you just installed it.`;
4782
- }
4755
+ function actionFor(reason, selection, resolvedPath) {
4783
4756
  if (reason === "unsupported_version")
4784
4757
  return `upgrade ${selection.host} to ${selection.host === "codex" ? "0.145.0" : "a supported version"} and retry`;
4785
4758
  if (reason === "unverified_version")
@@ -4792,15 +4765,10 @@ function actionFor(reason, selection, searchedLocations = [], resolvedPath) {
4792
4765
  return `Resolve the existing Mnemonik MCP declaration in ${selection.host}, then retry.`;
4793
4766
  if (reason === "project_shared_declaration_conflict")
4794
4767
  return "Ask the collaborator who owns the project declaration to reconcile it, then retry.";
4795
- if (reason === "host_grant_unverified") return `Run mnemonik connect ${selection.host}.`;
4796
- if (reason === "host_enable_required")
4797
- return `Enable Mnemonik in ${hostLabels[selection.host]}, then run mnemonik connect ${selection.host}.`;
4798
4768
  if (reason === "hooks_missing" || reason === "mcp_declaration_missing")
4799
4769
  return `mnemonik repair --host ${selection.host} --component ${selection.component ?? "hooks"}`;
4800
4770
  if (reason === "installation_required") return "Run mnemonik install first.";
4801
4771
  if (reason === "digest_mismatch") return "mnemonik repair";
4802
- if (reason === "host_account_mismatch")
4803
- return `Sign out of Mnemonik in ${selection.host}${selection.profilePath ? ` profile ${selection.profilePath}` : ""}, then run mnemonik connect ${selection.host}.`;
4804
4772
  if (reason === "hook_credential_authorization_required")
4805
4773
  return "Run `mnemonik auth login --reopen-install` to start a new install session";
4806
4774
  return void 0;
@@ -4857,6 +4825,8 @@ var protectInstall = (deps, work) => async (journal) => {
4857
4825
  }
4858
4826
  };
4859
4827
  async function runHosts(command, selections, deps, allowMigration = false) {
4828
+ if (command === "install")
4829
+ selections = selections.map((selection) => ({ ...selection, scope: "user" }));
4860
4830
  const pending = (await interrupted(deps.stateDir))[0];
4861
4831
  if (pending && !pending.data.hostRequest) throw new Error("resolve_interrupted_install_first");
4862
4832
  const outcome = await withInstall(
@@ -4888,7 +4858,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
4888
4858
  return { results, reports: journal.data.reports, journal: journal.data };
4889
4859
  }
4890
4860
  const completed = journal.data.hostRuns.filter(
4891
- (run2) => (run2.status === "complete" || run2.status === "verified" || run2.reason === "host_skipped") && !journal.data.targets.some(
4861
+ (run2) => (run2.status === "complete" || run2.status === "verified") && !journal.data.targets.some(
4892
4862
  (target) => target.group === run2.id && target.status === "restored"
4893
4863
  )
4894
4864
  );
@@ -4910,8 +4880,8 @@ async function runHosts(command, selections, deps, allowMigration = false) {
4910
4880
  results.push({
4911
4881
  target: run2.id,
4912
4882
  elapsedMs: run2.elapsedMs ?? 0,
4913
- status: run2.reason === "host_skipped" ? "LIMITED" : run2.candidate?.component === "mcp" && !run2.candidate.grant ? "ACTION_REQUIRED" : deps.grants ? "READY" : "LIMITED",
4914
- reason: run2.reason ?? "host_grant_unverified"
4883
+ status: run2.reason === "codex_trust_pending" ? "ACTION_REQUIRED" : "READY",
4884
+ reason: run2.reason ?? "declaration installed"
4915
4885
  });
4916
4886
  }
4917
4887
  selections = request.selections.filter(
@@ -4936,8 +4906,8 @@ async function runHosts(command, selections, deps, allowMigration = false) {
4936
4906
  results.push({
4937
4907
  target: run2.id,
4938
4908
  elapsedMs: run2.elapsedMs ?? 0,
4939
- status: run2.reason === "uninstalled" ? "READY" : run2.candidate?.component === "mcp" && !run2.candidate.grant ? "ACTION_REQUIRED" : "LIMITED",
4940
- reason: run2.reason ?? "host_grant_unverified"
4909
+ status: run2.reason === "codex_trust_pending" ? "ACTION_REQUIRED" : "READY",
4910
+ reason: run2.reason ?? "declaration installed"
4941
4911
  });
4942
4912
  }
4943
4913
  if (request.command === "uninstall")
@@ -4971,8 +4941,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
4971
4941
  journal.data.hostRuns.push(run2);
4972
4942
  await journal.save();
4973
4943
  let freshRuntimeVersion;
4974
- let searchedLocations = [];
4975
- let resolvedPath;
4944
+ let runtimeChanged = false;
4976
4945
  try {
4977
4946
  const pointer = store.pointerPath(selection.host);
4978
4947
  const beforePointer = await bytesAt(pointer);
@@ -4981,6 +4950,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
4981
4950
  if (command === "update" || command === "install") {
4982
4951
  const source = await (deps.source ?? hostSource)(selection.host);
4983
4952
  const previous = beforePointer ? JSON.parse(beforePointer.toString()) : void 0;
4953
+ runtimeChanged = previous?.current.version !== source.manifest.version;
4984
4954
  const proposed = previous?.current.version === source.manifest.version ? beforePointer : Buffer.from(
4985
4955
  JSON.stringify({
4986
4956
  current: {
@@ -5001,6 +4971,11 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5001
4971
  await journal.commit(runtimeTarget);
5002
4972
  } else runtime = await store.verifyRuntime(selection.host);
5003
4973
  const target = targetFor(selection, runtime, store, old);
4974
+ if (target.component === "mcp" && target.scope === "user") {
4975
+ target.installationId = await readInstallation(deps.stateDir);
4976
+ if (command !== "uninstall" && !target.installationId)
4977
+ throw new Error("installation_required");
4978
+ }
5004
4979
  const module2 = await (deps.imports ?? hostPackageImports)[selection.host](runtime);
5005
4980
  const adapter = module2.createHostAdapter({
5006
4981
  target,
@@ -5009,17 +4984,6 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5009
4984
  artifactDigest: runtime.reference.manifestSha256
5010
4985
  });
5011
4986
  if (adapter.name !== selection.host) throw new Error("adapter_identity_mismatch");
5012
- const detected = await adapter.detect();
5013
- resolvedPath = detected.resolvedPath;
5014
- if (!detected.supported) {
5015
- searchedLocations = detected.searchedLocations ?? [];
5016
- if (target.component === "mcp" && command !== "update" && command !== "repair") {
5017
- const instruction = await adapter.launch();
5018
- journal.data.reports.push(instruction);
5019
- deps.instruction?.(instruction);
5020
- }
5021
- throw new Error(detected.reason ?? "unverified_version");
5022
- }
5023
4987
  if (!adapter.capabilities().components.includes(target.component))
5024
4988
  throw new Error("unsupported_component");
5025
4989
  if (!adapter.capabilities().scopes.includes(selection.scope))
@@ -5033,7 +4997,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5033
4997
  target.credentialFamily = old?.credentialFamily ?? record.targets.find(
5034
4998
  (candidate) => candidate.host === selection.host && candidate.component === "hooks" && candidate.home === selection.home
5035
4999
  )?.credentialFamily ?? "";
5036
- if (command !== "uninstall" && (!target.credentialFamily || !await credentials.readFamily(target.credentialFamily))) {
5000
+ if (command !== "update" && command !== "uninstall" && (!target.credentialFamily || !await credentials.readFamily(target.credentialFamily))) {
5037
5001
  let bearer = await deps.getCliBearer?.();
5038
5002
  if (!bearer) throw new Error("hook_credential_authorization_required");
5039
5003
  const issue = () => (deps.credentialFetch ?? fetch)(`${apiOrigin()}/api/v1/component-credentials`, {
@@ -5048,10 +5012,8 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5048
5012
  let response = await issue();
5049
5013
  const body2 = response.status === 403 ? await response.json().catch(() => ({})) : void 0;
5050
5014
  if (body2?.error === "install_session_required") {
5051
- const installation = (await deps.grants?.list())?.deviceInstallationId;
5015
+ const installation = await readInstallation(deps.stateDir);
5052
5016
  if (!installation) throw new Error("hook_credential_authorization_required");
5053
- if (!deps.authorizeInstallSession && !deps.timeout)
5054
- throw new Error("hook_credential_authorization_required");
5055
5017
  try {
5056
5018
  bearer = await ensureInstallSession({
5057
5019
  stateDir: deps.stateDir,
@@ -5141,44 +5103,19 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5141
5103
  if (command === "uninstall") {
5142
5104
  if ((await adapter.verify(target)).declarationPresent)
5143
5105
  throw new Error("uninstall_verification_failed");
5144
- if (target.component === "mcp" && await deps.offerRevoke?.(selection.host)) {
5145
- await revokeHostGrants(selection.host, deps, old?.grant?.id);
5146
- if (old?.grant && adapter.revoke) await adapter.revoke(old.grant);
5147
- else deps.instruction?.(adapter.revokeAction);
5148
- }
5149
5106
  } else {
5150
- try {
5151
- inspection = await waitForHost(
5152
- adapter,
5153
- target,
5154
- selection.host,
5155
- {
5156
- ...deps,
5157
- instruction: (text) => {
5158
- journal.data.reports.push(`${run2.id}: ${text}`);
5159
- deps.instruction?.(text);
5160
- }
5161
- },
5162
- old?.grant,
5163
- command
5164
- );
5165
- run2.reason = inspection.trustPending ? "codex_trust_pending" : target.component === "hooks" || inspection.grant ? "hooks_not_verified" : "host_grant_unverified";
5166
- if (inspection.trustPending)
5167
- journal.data.reports.push(
5168
- `codex: ${codexTrustAction(inspection.resolvedPath ?? resolvedPath)}`
5169
- );
5170
- } catch (error) {
5171
- if (target.component !== "mcp") throw error;
5172
- run2.reason = error instanceof Error ? error.message : "host_verification_timeout";
5173
- if (deps.afterHosts && run2.reason === "host_verification_timeout")
5174
- run2.reason = "login_pending";
5175
- journal.data.reports.push(
5176
- `${run2.id}: URL-only entry retained, not connected. Run mnemonik connect ${selection.host}.`
5107
+ inspection = await adapter.verify(target);
5108
+ if (inspection.trustDeclined) throw new Error("codex_trust_declined");
5109
+ if (!inspection.declarationPresent)
5110
+ throw new Error(
5111
+ target.component === "hooks" ? "hooks_missing" : "mcp_declaration_missing"
5177
5112
  );
5178
- }
5113
+ run2.reason = inspection.trustPending ? "codex_trust_pending" : target.component === "hooks" ? "hooks installed" : "MCP entry declared";
5114
+ if (inspection.trustPending)
5115
+ journal.data.reports.push(`codex: ${codexTrustAction(inspection.resolvedPath)}`);
5179
5116
  }
5180
5117
  await journal.event("host_observed", run2.id);
5181
- const migrated = inspection?.grant || target.component === "hooks" ? otherScopes : [];
5118
+ const migrated = inspection?.declarationPresent ? otherScopes : [];
5182
5119
  for (const other of migrated) {
5183
5120
  const removals = [];
5184
5121
  const otherOwned = record.targets.find(
@@ -5207,16 +5144,13 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5207
5144
  if (command !== "uninstall") {
5208
5145
  const profilePath2 = old?.profilePath ?? ownedChanges.at(-1)?.path;
5209
5146
  if (!profilePath2) throw new Error("adapter_empty_plan");
5210
- const grant = inspection?.grant ?? old?.grant;
5211
5147
  const candidate = {
5212
5148
  ...selection,
5213
5149
  id: run2.id,
5214
5150
  component: target.component,
5215
5151
  credentialFamily: target.credentialFamily,
5216
- ...grant ? { grant } : {},
5217
5152
  profilePath: profilePath2,
5218
5153
  version: runtime.manifest.version,
5219
- ...detected.version ? { editorVersion: detected.version } : {},
5220
5154
  artifactDigest: runtime.reference.manifestSha256,
5221
5155
  runtimePointer: pointer,
5222
5156
  files: ownedChanges.map((c) => {
@@ -5240,7 +5174,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5240
5174
  }
5241
5175
  } : {}
5242
5176
  };
5243
- if (!grant) delete candidate.grant;
5177
+ delete candidate.grant;
5244
5178
  run2.candidate = candidate;
5245
5179
  }
5246
5180
  run2.reason ??= "uninstalled";
@@ -5250,70 +5184,38 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5250
5184
  await saveOwnership(deps.stateDir, journal, run2);
5251
5185
  run2.status = "complete";
5252
5186
  await journal.event("local_commit", run2.id);
5253
- if (command === "update")
5187
+ if (command === "update" && runtimeChanged)
5254
5188
  journal.data.reports.push(
5255
5189
  `${selection.host}: shared runtime updated for all scopes to ${runtime.manifest.version}.`
5256
5190
  );
5257
5191
  const result = {
5258
5192
  target: run2.id,
5259
5193
  elapsedMs: run2.elapsedMs ?? 0,
5260
- status: inspection?.trustPending || target.component === "mcp" && command !== "uninstall" && !inspection?.grant ? "ACTION_REQUIRED" : deps.grants ? "READY" : "LIMITED",
5194
+ status: inspection?.trustPending ? "ACTION_REQUIRED" : "READY",
5261
5195
  reason: run2.reason,
5262
- ...actionFor(run2.reason, selection, [], inspection?.resolvedPath ?? resolvedPath) ? {
5263
- action: actionFor(
5264
- run2.reason,
5265
- selection,
5266
- [],
5267
- inspection?.resolvedPath ?? resolvedPath
5268
- )
5196
+ ...actionFor(run2.reason, selection, inspection?.resolvedPath) ? {
5197
+ action: actionFor(run2.reason, selection, inspection?.resolvedPath)
5269
5198
  } : {}
5270
5199
  };
5271
5200
  results.push(result);
5272
- if (command === "install" && deps.afterHosts && (inspection?.trustPending || run2.reason === "login_pending"))
5201
+ if (command === "install" && deps.afterHosts && inspection?.trustPending)
5273
5202
  completionChecks.push(async () => {
5274
5203
  const reread = await adapter.verify(target);
5275
5204
  if (reread.trustDeclined) {
5276
5205
  result.status = "ACTION_REQUIRED";
5277
5206
  result.reason = "codex_trust_declined";
5278
- result.action = actionFor(
5279
- result.reason,
5280
- selection,
5281
- [],
5282
- reread.resolvedPath ?? resolvedPath
5283
- );
5207
+ result.action = actionFor(result.reason, selection, reread.resolvedPath);
5284
5208
  return;
5285
5209
  }
5286
5210
  if (reread.trustPending) return;
5287
5211
  if (target.component === "hooks") {
5288
- result.status = reread.declarationPresent ? deps.grants ? "READY" : "LIMITED" : "ACTION_REQUIRED";
5289
- result.reason = reread.declarationPresent ? "hooks_not_verified" : "hooks_missing";
5212
+ result.status = reread.declarationPresent ? "READY" : "ACTION_REQUIRED";
5213
+ result.reason = reread.declarationPresent ? "hooks installed" : "hooks_missing";
5290
5214
  if (reread.declarationPresent) delete result.action;
5291
5215
  else result.action = `mnemonik repair --host ${selection.host} --component hooks`;
5292
- const report = `codex: ${codexTrustAction(reread.resolvedPath ?? resolvedPath)}`;
5216
+ const report = `codex: ${codexTrustAction(reread.resolvedPath)}`;
5293
5217
  const index = journal.data.reports.indexOf(report);
5294
5218
  if (index >= 0) journal.data.reports.splice(index, 1);
5295
- return;
5296
- }
5297
- if (!deps.grants) return;
5298
- const listing = await deps.grants.list();
5299
- if (!deps.account || listing.account !== deps.account) return;
5300
- const grants = listing.grants.filter(
5301
- (grant) => grantHost(grant) === selection.host && grant.resource === `${apiOrigin()}/mcp` && grant.scopes.includes("mcp:use")
5302
- );
5303
- const bound = grants.find(
5304
- (grant) => listing.deviceInstallationId && grant.deviceInstallationId === listing.deviceInstallationId && grant.activatedAt
5305
- ) ?? grants.find(
5306
- (grant) => listing.deviceInstallationId && grant.deviceInstallationId === listing.deviceInstallationId
5307
- );
5308
- if (bound && !bound.activatedAt) {
5309
- const condition = hostNotConnectedCondition(selection.host);
5310
- result.status = "LIMITED";
5311
- result.reason = condition.reason;
5312
- result.action = condition.action;
5313
- } else if (bound?.activatedAt && reread.declarationPresent && reread.authenticatedTools) {
5314
- result.status = "READY";
5315
- result.reason = "connected to this machine";
5316
- delete result.action;
5317
5219
  }
5318
5220
  });
5319
5221
  } catch (error) {
@@ -5334,7 +5236,7 @@ async function runHosts(command, selections, deps, allowMigration = false) {
5334
5236
  status: "ACTION_REQUIRED",
5335
5237
  reason: run2.reason,
5336
5238
  ...detail ? { detail } : {},
5337
- ...actionFor(run2.reason, selection, searchedLocations, resolvedPath) ? { action: actionFor(run2.reason, selection, searchedLocations, resolvedPath) } : {}
5239
+ ...actionFor(run2.reason, selection) ? { action: actionFor(run2.reason, selection) } : {}
5338
5240
  });
5339
5241
  await journal.save();
5340
5242
  } finally {
@@ -5478,167 +5380,13 @@ async function hookStatusConditions(deps, hosts) {
5478
5380
  }
5479
5381
  return conditions;
5480
5382
  }
5481
- async function finishMcpTarget(adapter, target, deps, status) {
5482
- if (adapter.capabilities().nativeListing === false) {
5483
- if (!status.declarationPresent || !deps.grants) return status;
5484
- const hookPath = (await adapter.verify({ ...target, component: "hooks" })).declarationPath;
5485
- const hooks = (await readOwnership(deps.stateDir)).targets.find(
5486
- (t) => t.host === adapter.name && t.component === "hooks" && t.profilePath === hookPath
5487
- );
5488
- if (!hooks?.credentialFamily || !(await adapter.verify({
5489
- ...target,
5490
- component: "hooks",
5491
- credentialFamily: hooks.credentialFamily
5492
- })).declarationPresent)
5493
- return status;
5494
- const listing = await deps.grants.list();
5495
- if (!deps.account || listing.account !== deps.account) throw new Error("host_account_mismatch");
5496
- return {
5497
- ...status,
5498
- authenticatedTools: listing.grants.some(
5499
- (g) => grantHost(g) === adapter.name && g.resource === `${apiOrigin()}/mcp` && !!g.activatedAt && g.scopes.includes("mcp:use")
5500
- )
5501
- };
5502
- }
5503
- if (!status.enableRequired) return status;
5504
- const instruction = await adapter.enable?.();
5505
- if (instruction) deps.instruction?.(instruction);
5506
- const verified = await adapter.verify(target);
5507
- if (!verified.authenticatedTools) throw new Error("host_enable_required");
5508
- return verified;
5509
- }
5510
- async function waitForHost(adapter, target, host, deps, recorded, command) {
5511
- if (command === "update" || command === "repair") {
5512
- let status = await adapter.verify(target);
5513
- if (!status.trustPending && !status.trustDeclined && status.enableRequired) {
5514
- const instruction = await adapter.enable?.();
5515
- if (instruction) deps.instruction?.(instruction);
5516
- status = await adapter.verify(target);
5517
- }
5518
- if (status.trustDeclined) throw new Error("codex_trust_declined");
5519
- if (status.trustPending) return status;
5520
- if (status.enableRequired) throw new Error("host_enable_required");
5521
- if (!status.declarationPresent)
5522
- throw new Error(target.component === "hooks" ? "hooks_missing" : "mcp_declaration_missing");
5523
- if (target.component === "hooks") return status;
5524
- if (!deps.grants) throw new Error("host_grant_unverified");
5525
- if (!recorded) {
5526
- if (!deps.account) throw new Error("host_account_mismatch");
5527
- status = await finishMcpTarget(adapter, target, deps, status);
5528
- if (!status.authenticatedTools) throw new Error("host_grant_unverified");
5529
- try {
5530
- const matched = await matchHostGrant(
5531
- status,
5532
- host,
5533
- deps.account,
5534
- deps.grants,
5535
- (deps.now ?? Date.now)(),
5536
- void 0,
5537
- deps.approveHost,
5538
- "recovered"
5539
- );
5540
- if (matched.grant?.installationId) return matched;
5541
- } catch (error) {
5542
- if (error instanceof Error && error.message === "host_connection_pending")
5543
- throw new Error("host_grant_unverified");
5544
- throw error;
5545
- }
5546
- throw new Error("host_grant_unverified");
5547
- }
5548
- const listing = await deps.grants.list();
5549
- if (!deps.account || listing.account !== deps.account || recorded.account !== deps.account)
5550
- throw new Error("host_account_mismatch");
5551
- const live = listing.grants.find(
5552
- (grant) => grant.id === recorded.id && grantHost(grant) === host && grant.resource === `${apiOrigin()}/mcp` && !!grant.activatedAt && grant.scopes.includes("mcp:use") && (!grant.deviceInstallationId || grant.deviceInstallationId === listing.deviceInstallationId) && (!recorded.installationId || recorded.installationId === listing.deviceInstallationId)
5553
- );
5554
- if (!live) throw new Error("host_grant_unverified");
5555
- return { ...status, grant: { ...recorded, scopes: live.scopes } };
5556
- }
5557
- for (; ; ) {
5558
- const now = deps.now ?? Date.now;
5559
- const attemptStartedAt = now();
5560
- let signedIn = false;
5561
- let waitingForActivation = false;
5562
- let staleRecord = false;
5563
- const match = async (status, approvalMode = "all") => {
5564
- const grants = deps.grants;
5565
- if (!grants) return status;
5566
- try {
5567
- return await matchHostGrant(
5568
- status,
5569
- host,
5570
- deps.account,
5571
- grants,
5572
- attemptStartedAt,
5573
- recorded,
5574
- deps.approveHost,
5575
- approvalMode
5576
- );
5577
- } catch (error) {
5578
- if (!(error instanceof Error) || error.message !== "host_connection_pending") throw error;
5579
- if (approvalMode === "recovered" && recorded) {
5580
- staleRecord = true;
5581
- deps.instruction?.(
5582
- `${hostLabels[host]} is no longer signed in to Mnemonik; starting a new sign-in.`
5583
- );
5584
- return void 0;
5585
- }
5586
- if (!waitingForActivation && !staleRecord)
5587
- deps.instruction?.(
5588
- `${host === "codex" ? "Codex" : host} is still finishing its connection.`
5589
- );
5590
- waitingForActivation = true;
5591
- return void 0;
5592
- }
5593
- };
5594
- if (target.component === "mcp" && deps.grants) {
5595
- const status = await finishMcpTarget(adapter, target, deps, await adapter.verify(target));
5596
- if (status.declarationPresent && status.authenticatedTools) {
5597
- const matched = await match(status, "recovered");
5598
- if (matched?.grant?.installationId) return matched;
5599
- signedIn = !staleRecord && (waitingForActivation || !!matched?.grant);
5600
- }
5601
- }
5602
- if (target.component === "mcp" && adapter.capabilities().nativeConnect && deps.grants && !signedIn && !staleRecord) {
5603
- const status = await deps.grants.list();
5604
- if (!deps.account || status.account !== deps.account)
5605
- throw new Error("host_account_mismatch");
5606
- signedIn = status.grants.some(
5607
- (grant) => grantHost(grant) === host && grant.resource === `${apiOrigin()}/mcp` && !!grant.activatedAt && grant.scopes.includes("mcp:use")
5608
- );
5609
- }
5610
- const instruction = target.component === "mcp" && !waitingForActivation ? await adapter.launch({ signedIn: signedIn && !staleRecord }) : "";
5611
- if (instruction) deps.instruction?.(instruction);
5612
- const deadline = now() + 12e4;
5613
- while (now() < deadline) {
5614
- const status = target.component === "mcp" ? await finishMcpTarget(adapter, target, deps, await adapter.verify(target)) : await adapter.verify(target);
5615
- if (status.trustDeclined) throw new Error("codex_trust_declined");
5616
- if (status.trustPending) return status;
5617
- if (status.declarationPresent && (target.component === "hooks" || status.authenticatedTools)) {
5618
- if (target.component === "hooks") return status;
5619
- if (!deps.grants) throw new Error("host_grant_unverified");
5620
- try {
5621
- const matched = await match(status);
5622
- if (matched) return matched;
5623
- } catch (error) {
5624
- deps.instruction?.(`Sign out of Mnemonik in ${host}, then run mnemonik connect ${host}.`);
5625
- throw error;
5626
- }
5627
- }
5628
- await (deps.sleep ?? delay)(Math.max(0, Math.min(2e3, deadline - now())));
5629
- }
5630
- if (host === "cursor" && instruction) deps.instruction?.(instruction);
5631
- deps.instruction?.(`mnemonik connect ${host}: retry or skip this host for now.`);
5632
- if (await deps.timeout?.(host) !== "retry") throw new Error("host_verification_timeout");
5633
- }
5634
- }
5635
5383
  async function revokeHostGrants(host, deps, grantId) {
5636
5384
  if (!deps.grants) throw new Error("host_grant_unverified");
5637
5385
  const status = await deps.grants.list();
5638
5386
  if (status.account !== deps.account) throw new Error("host_account_mismatch");
5639
- const { grantHost: grantHost2 } = await import("../auth/status.js");
5387
+ const { grantHost } = await import("../auth/status.js");
5640
5388
  const grants = status.grants.filter(
5641
- (g) => (!grantId || g.id === grantId) && grantHost2(g) === host && g.resource === `${apiOrigin()}/mcp`
5389
+ (g) => (!grantId || g.id === grantId) && grantHost(g) === host && g.resource === `${apiOrigin()}/mcp`
5642
5390
  );
5643
5391
  for (const grant of grants) await deps.grants.revoke(grant.id);
5644
5392
  return grants.map((g) => g.id);
@@ -5663,66 +5411,22 @@ async function logoutHost(host, deps) {
5663
5411
  return ids;
5664
5412
  }
5665
5413
  async function connectHost(selection, deps) {
5666
- return withInstall(
5667
- deps.stateDir,
5668
- {
5669
- account: deps.account,
5670
- hosts: [selection.host],
5671
- components: ["mcp"],
5672
- scopes: {},
5673
- roots: [],
5674
- credentials: []
5675
- },
5676
- void 0,
5677
- async (journal) => {
5678
- const now = deps.now ?? Date.now;
5679
- const startedAt = now();
5680
- const current = (await readOwnership(deps.stateDir)).targets.find(
5681
- (t) => t.id === selection.id
5682
- );
5683
- if (!current || current.component !== "mcp") throw new Error("no_recorded_targets");
5684
- const store = new RuntimeStore(deps.stateDir);
5685
- const runtime = await store.verifyRuntime(current.host);
5686
- const target = targetFor(current, runtime, store);
5687
- const adapter = (await (deps.imports ?? hostPackageImports)[current.host](runtime)).createHostAdapter({ target, env: environment(current, deps.env) });
5688
- let reason = "hooks_not_verified";
5689
- let status = "LIMITED";
5690
- const candidate = { ...current };
5691
- const run2 = { id: current.id, host: current.host, status: "verified", candidate };
5692
- try {
5693
- const inspection = await waitForHost(adapter, target, current.host, deps, current.grant);
5694
- if (deps.grants) {
5695
- const listing = await deps.grants.list();
5696
- if (listing.account !== deps.account) throw new Error("host_account_mismatch");
5697
- await bindInstalledHostGrants(listing, [current.host], deps.grants);
5698
- }
5699
- if (inspection.grant) run2.candidate = { ...candidate, grant: inspection.grant };
5700
- if (inspection.grant?.installationId) {
5701
- status = "READY";
5702
- reason = "connected to this machine";
5703
- } else reason = "host_grant_unbound";
5704
- } catch (error) {
5705
- reason = error instanceof Error ? error.message : "host_verification_timeout";
5706
- status = "ACTION_REQUIRED";
5707
- }
5708
- await saveOwnership(deps.stateDir, journal, run2);
5709
- journal.data.phase = "complete";
5710
- journal.data.state = status;
5711
- run2.elapsedMs = Math.max(0, now() - startedAt);
5712
- journal.data.hostRuns = [run2];
5713
- await journal.event("complete");
5714
- return {
5715
- target: current.id,
5716
- elapsedMs: run2.elapsedMs,
5717
- status,
5718
- reason,
5719
- ...status === "ACTION_REQUIRED" ? {
5720
- action: reason === "installation_required" ? "Run mnemonik install first." : reason === "host_account_mismatch" ? `Sign out of Mnemonik in ${current.host} profile ${current.profilePath}, then run mnemonik connect ${current.host}.` : `Run mnemonik connect ${current.host}.`
5721
- } : {}
5722
- };
5723
- },
5724
- deps.fault
5725
- );
5414
+ const now = deps.now ?? Date.now;
5415
+ const startedAt = now();
5416
+ const current = (await readOwnership(deps.stateDir)).targets.find((t) => t.id === selection.id);
5417
+ if (!current || current.component !== "mcp") throw new Error("no_recorded_targets");
5418
+ const store = new RuntimeStore(deps.stateDir);
5419
+ const runtime = await store.verifyRuntime(current.host);
5420
+ const target = targetFor(current, runtime, store);
5421
+ const adapter = (await (deps.imports ?? hostPackageImports)[current.host](runtime)).createHostAdapter({ target, env: environment(current, deps.env) });
5422
+ const instruction = await adapter.launch();
5423
+ if (instruction) deps.instruction?.(instruction);
5424
+ return {
5425
+ target: current.id,
5426
+ elapsedMs: Math.max(0, now() - startedAt),
5427
+ status: "READY",
5428
+ reason: "native_login"
5429
+ };
5726
5430
  }
5727
5431
  export {
5728
5432
  CODEX_TRUST_ACTION,
@@ -5730,12 +5434,9 @@ export {
5730
5434
  codexTrustConditions,
5731
5435
  connectHost,
5732
5436
  hookStatusConditions,
5733
- hostNotConnectedCondition,
5734
5437
  hostSource,
5735
- hostStillConnectingCondition,
5736
5438
  logoutHost,
5737
5439
  revokeHostGrants,
5738
5440
  runHosts,
5739
- selectOwned,
5740
- waitForHost
5441
+ selectOwned
5741
5442
  };