@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.
- package/dist/auth/pkce.d.ts +2 -0
- package/dist/auth/pkce.d.ts.map +1 -1
- package/dist/auth/pkce.js +57 -6
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/status.d.ts +1 -5
- package/dist/auth/status.d.ts.map +1 -1
- package/dist/auth/status.js +1 -71
- package/dist/auth/status.js.map +1 -1
- package/dist/digests.json +91 -91
- package/dist/install/hosts.d.ts +2 -12
- package/dist/install/hosts.d.ts.map +1 -1
- package/dist/install/hosts.js +57 -356
- package/dist/install/hosts.js.map +1 -1
- package/dist/install/journal.d.ts +2 -10
- package/dist/install/journal.d.ts.map +1 -1
- package/dist/install/journal.js +0 -4
- package/dist/install/journal.js.map +1 -1
- package/dist/install/journey.d.ts.map +1 -1
- package/dist/install/journey.js +185 -158
- package/dist/install/journey.js.map +1 -1
- package/dist/install/transaction.d.ts +2 -3
- package/dist/install/transaction.d.ts.map +1 -1
- package/dist/install/transaction.js +1 -90
- package/dist/install/transaction.js.map +1 -1
- package/dist/install/ui.d.ts.map +1 -1
- package/dist/install/ui.js +15 -33
- package/dist/install/ui.js.map +1 -1
- package/dist/installSession.js +0 -4
- package/dist/launcher.d.ts.map +1 -1
- package/dist/launcher.js +16 -7
- package/dist/launcher.js.map +1 -1
- package/dist/output.d.ts +1 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +3 -0
- package/dist/output.js.map +1 -1
- package/dist/preflight.d.ts +2 -0
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +64 -209
- package/dist/preflight.js.map +1 -1
- package/dist/project/eligibility.d.ts +11 -1
- package/dist/project/eligibility.d.ts.map +1 -1
- package/dist/project/eligibility.js +12 -1
- package/dist/project/eligibility.js.map +1 -1
- package/dist/project.d.ts +3 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +56 -21
- package/dist/project.js.map +1 -1
- package/dist/router.d.ts +5 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +201 -93
- package/dist/router.js.map +1 -1
- package/dist/runtime/releaseSource.d.ts +10 -0
- package/dist/runtime/releaseSource.d.ts.map +1 -1
- package/dist/runtime/releaseSource.js +82 -6
- package/dist/runtime/releaseSource.js.map +1 -1
- package/dist/runtime/selfUpdate.d.ts +4 -1
- package/dist/runtime/selfUpdate.d.ts.map +1 -1
- package/dist/runtime/selfUpdate.js +12 -6
- package/dist/runtime/selfUpdate.js.map +1 -1
- package/dist/runtime/signers.js +15 -7
- package/dist/runtime/store.d.ts +2 -1
- package/dist/runtime/store.d.ts.map +1 -1
- package/dist/runtime/store.js +20 -9
- package/dist/runtime/store.js.map +1 -1
- package/dist/sbom.json +21 -23
- package/dist/scanner/discover.d.ts +12 -1
- package/dist/scanner/discover.d.ts.map +1 -1
- package/dist/scanner/discover.js +48 -14
- package/dist/scanner/discover.js.map +1 -1
- package/dist/scanner/enable.d.ts +23 -5
- package/dist/scanner/enable.d.ts.map +1 -1
- package/dist/scanner/enable.js +93 -21
- package/dist/scanner/enable.js.map +1 -1
- package/dist/scanner/picker.d.ts +7 -1
- package/dist/scanner/picker.d.ts.map +1 -1
- package/dist/scanner/picker.js +64 -13
- package/dist/scanner/picker.js.map +1 -1
- package/dist/scanner-release.json +25 -25
- package/dist/screens/journey.d.ts +13 -3
- package/dist/screens/journey.d.ts.map +1 -1
- package/dist/screens/journey.js +145 -53
- package/dist/screens/journey.js.map +1 -1
- package/dist/screens.d.ts +2 -3
- package/dist/screens.d.ts.map +1 -1
- package/dist/screens.js +6 -16
- package/dist/screens.js.map +1 -1
- package/dist/status.d.ts +5 -3
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +194 -110
- package/dist/status.js.map +1 -1
- package/dist/vendor/local-setup.js +124 -27
- package/dist/vendor/shared/runtimeSigners.js +11 -6
- package/package.json +45 -41
package/dist/install/hosts.js
CHANGED
|
@@ -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,
|
|
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"
|
|
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 === "
|
|
4914
|
-
reason: run2.reason ?? "
|
|
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 === "
|
|
4940
|
-
reason: run2.reason ?? "
|
|
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
|
|
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 =
|
|
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
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
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?.
|
|
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
|
-
|
|
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
|
|
5194
|
+
status: inspection?.trustPending ? "ACTION_REQUIRED" : "READY",
|
|
5261
5195
|
reason: run2.reason,
|
|
5262
|
-
...actionFor(run2.reason, selection,
|
|
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 &&
|
|
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 ?
|
|
5289
|
-
result.reason = reread.declarationPresent ? "
|
|
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
|
|
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
|
|
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
|
|
5387
|
+
const { grantHost } = await import("../auth/status.js");
|
|
5640
5388
|
const grants = status.grants.filter(
|
|
5641
|
-
(g) => (!grantId || g.id === grantId) &&
|
|
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
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
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
|
};
|