@mnemonik/cli 7.111.5 → 7.111.7
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/device.d.ts +5 -0
- package/dist/auth/device.d.ts.map +1 -1
- package/dist/auth/device.js +2 -1
- package/dist/auth/device.js.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/digests.json +47 -47
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +7 -2
- package/dist/help.js.map +1 -1
- package/dist/humanReason.d.ts +22 -0
- package/dist/humanReason.d.ts.map +1 -1
- package/dist/humanReason.js +22 -3
- package/dist/humanReason.js.map +1 -1
- package/dist/install/journey.d.ts.map +1 -1
- package/dist/install/journey.js +8 -2
- package/dist/install/journey.js.map +1 -1
- package/dist/installSession.js +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +229 -63
- package/dist/router.js.map +1 -1
- package/dist/runtime/updateCheck.d.ts +1 -1
- package/dist/runtime/updateCheck.d.ts.map +1 -1
- package/dist/runtime/updateCheck.js +4 -1
- package/dist/runtime/updateCheck.js.map +1 -1
- package/dist/sbom.json +21 -21
- package/dist/scanner/enable.d.ts +2 -0
- package/dist/scanner/enable.d.ts.map +1 -1
- package/dist/scanner/enable.js +13 -2
- package/dist/scanner/enable.js.map +1 -1
- package/dist/scanner/picker.d.ts +7 -0
- package/dist/scanner/picker.d.ts.map +1 -1
- package/dist/scanner/picker.js +12 -1
- package/dist/scanner/picker.js.map +1 -1
- package/dist/scanner/service.d.ts.map +1 -1
- package/dist/scanner/service.js +3 -2
- package/dist/scanner/service.js.map +1 -1
- package/dist/scanner/update.d.ts +3 -1
- package/dist/scanner/update.d.ts.map +1 -1
- package/dist/scanner/update.js +13 -2
- package/dist/scanner/update.js.map +1 -1
- package/dist/scanner-release.json +28 -28
- package/dist/status.d.ts +4 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +52 -14
- package/dist/status.js.map +1 -1
- package/package.json +31 -31
package/dist/router.js
CHANGED
|
@@ -2516,7 +2516,12 @@ import {
|
|
|
2516
2516
|
humanIdentityState,
|
|
2517
2517
|
INTERRUPTED_INSTALL,
|
|
2518
2518
|
INTERRUPTED_INSTALL_MESSAGE,
|
|
2519
|
+
approvalMessage,
|
|
2520
|
+
knownReason,
|
|
2521
|
+
SCANNER_APPROVAL_ACTION,
|
|
2522
|
+
SCANNER_APPROVAL_NOTE,
|
|
2519
2523
|
SCANNER_CONSENT_MESSAGE,
|
|
2524
|
+
SCANNER_ENABLE_ACTION,
|
|
2520
2525
|
SCANNER_UPDATE_CONSENT_MESSAGE
|
|
2521
2526
|
} from "./humanReason.js";
|
|
2522
2527
|
import { consentDecision, consentLines } from "./consent.js";
|
|
@@ -2533,6 +2538,7 @@ import { deleteScannerIndex } from "./scanner/data.js";
|
|
|
2533
2538
|
import { devReadiness } from "./runtime/releaseSource.js";
|
|
2534
2539
|
import {
|
|
2535
2540
|
scannerService,
|
|
2541
|
+
SCANNER_LIMITED_SENTENCE,
|
|
2536
2542
|
ScannerServiceLimited
|
|
2537
2543
|
} from "./scanner/service.js";
|
|
2538
2544
|
|
|
@@ -6733,6 +6739,8 @@ var stateFor = {
|
|
|
6733
6739
|
host_trust_pending: "ACTION_REQUIRED",
|
|
6734
6740
|
vendor_policy_pending: "ACTION_REQUIRED",
|
|
6735
6741
|
login_pending: "ACTION_REQUIRED",
|
|
6742
|
+
consent_pending: "ACTION_REQUIRED",
|
|
6743
|
+
update_pending: "READY",
|
|
6736
6744
|
restart_pending: "ACTION_REQUIRED",
|
|
6737
6745
|
project_identity_choice_pending: "ACTION_REQUIRED",
|
|
6738
6746
|
scanner_not_verified: "LIMITED",
|
|
@@ -7191,10 +7199,10 @@ import {
|
|
|
7191
7199
|
validGrant
|
|
7192
7200
|
} from "./auth/status.js";
|
|
7193
7201
|
import { createCliAuth } from "./auth/index.js";
|
|
7194
|
-
import { runEditorLogin } from "./auth/pkce.js";
|
|
7202
|
+
import { OAuthProtocolError, runEditorLogin } from "./auth/pkce.js";
|
|
7195
7203
|
import { currentInstallSession, ensureInstallSession } from "./auth/installSession.js";
|
|
7196
7204
|
import { runIdentityMigration } from "./identity/migrate.js";
|
|
7197
|
-
import { renderScannerStatus } from "./scanner/picker.js";
|
|
7205
|
+
import { folderList, renderScannerStatus } from "./scanner/picker.js";
|
|
7198
7206
|
import { abandonInterrupted, closeUntouchedScannerRun, interrupted } from "./install/journal.js";
|
|
7199
7207
|
import {
|
|
7200
7208
|
installFailureReason,
|
|
@@ -7302,8 +7310,35 @@ function personPresent(parsed, deps) {
|
|
|
7302
7310
|
if (deps.input) return deps.input.isTTY !== false;
|
|
7303
7311
|
return process.stdin.isTTY === true;
|
|
7304
7312
|
}
|
|
7305
|
-
|
|
7306
|
-
if (
|
|
7313
|
+
function approvalStopped(error, held) {
|
|
7314
|
+
if (error instanceof OAuthProtocolError) {
|
|
7315
|
+
if (error.code === "expired_token") return "scanner_approval_expired";
|
|
7316
|
+
if (error.code === "access_denied") return "scanner_approval_declined";
|
|
7317
|
+
}
|
|
7318
|
+
const message = error.message;
|
|
7319
|
+
if (message === "consent_declined" || message === "browser_consent_required")
|
|
7320
|
+
return "scanner_approval_declined";
|
|
7321
|
+
return held;
|
|
7322
|
+
}
|
|
7323
|
+
function relayApprovalLink(output, json, reason) {
|
|
7324
|
+
return (url, expiresAt) => {
|
|
7325
|
+
if (json)
|
|
7326
|
+
output.json({
|
|
7327
|
+
status: "awaiting_approval",
|
|
7328
|
+
reason,
|
|
7329
|
+
approvalUrl: url,
|
|
7330
|
+
expiresAt: new Date(expiresAt).toISOString()
|
|
7331
|
+
});
|
|
7332
|
+
else {
|
|
7333
|
+
output.line(APPROVAL_LINK_LINE);
|
|
7334
|
+
output.line(url);
|
|
7335
|
+
}
|
|
7336
|
+
};
|
|
7337
|
+
}
|
|
7338
|
+
var APPROVAL_LINK_LINE = "Give the person this link to approve the updated notice:";
|
|
7339
|
+
async function approveScannerUpdate(parsed, deps, output, stateDir, held = "scanner_update_consent_required") {
|
|
7340
|
+
if (parsed.flags.has("automatic")) return { status: "pending", reason: held };
|
|
7341
|
+
const present = personPresent(parsed, deps);
|
|
7307
7342
|
const saved = JSON.parse(await readFile4(join7(stateDir, "scanner/state.json"), "utf8"));
|
|
7308
7343
|
try {
|
|
7309
7344
|
const document = await enableScanner({
|
|
@@ -7312,30 +7347,43 @@ async function approveScannerUpdate(parsed, deps, output, stateDir) {
|
|
|
7312
7347
|
home: deps.home,
|
|
7313
7348
|
input: deps.input ?? process.stdin,
|
|
7314
7349
|
output,
|
|
7350
|
+
nonInteractive: !present,
|
|
7315
7351
|
noBrowser: parsed.flags.has("no-browser"),
|
|
7316
7352
|
roots: saved.config.roots,
|
|
7317
7353
|
exclusions: saved.config.exclusions ?? [],
|
|
7354
|
+
...present ? {} : { onApprovalLink: relayApprovalLink(output, parsed.flags.has("json"), held) },
|
|
7318
7355
|
...deps.scannerService,
|
|
7319
7356
|
...deps.scannerEnable,
|
|
7320
7357
|
projectExecutor: deps.projectExecutor,
|
|
7321
7358
|
projectStateDir: deps.projectStateDir
|
|
7322
7359
|
});
|
|
7323
|
-
return document.installation.state === "READY" ? "approved" : "pending";
|
|
7324
|
-
} catch {
|
|
7325
|
-
return "pending";
|
|
7360
|
+
return document.installation.state === "READY" ? { status: "approved" } : { status: "pending", reason: held };
|
|
7361
|
+
} catch (error) {
|
|
7362
|
+
return { status: "pending", reason: approvalStopped(error, held) };
|
|
7326
7363
|
}
|
|
7327
7364
|
}
|
|
7328
|
-
function
|
|
7365
|
+
function approvalLines(reason, agent) {
|
|
7366
|
+
if (reason === "scanner_approval_expired" || reason === "scanner_approval_declined") {
|
|
7367
|
+
const sentence2 = reason === "scanner_approval_expired" ? "The approval request for the updated notice expired." : "The updated notice was not approved.";
|
|
7368
|
+
if (agent)
|
|
7369
|
+
return [sentence2, "Run mnemonik update again and give the person the new approval link."];
|
|
7370
|
+
return reason === "scanner_approval_expired" ? [sentence2, SCANNER_UPDATE_CONSENT_MESSAGE.nextStep] : [sentence2];
|
|
7371
|
+
}
|
|
7372
|
+
const message = approvalMessage(
|
|
7373
|
+
reason === "scanner_consent_required" ? SCANNER_CONSENT_MESSAGE : SCANNER_UPDATE_CONSENT_MESSAGE,
|
|
7374
|
+
agent
|
|
7375
|
+
);
|
|
7376
|
+
return [message.sentence, message.nextStep];
|
|
7377
|
+
}
|
|
7378
|
+
function scannerConsentRequired(output, json, agent) {
|
|
7329
7379
|
if (json)
|
|
7330
7380
|
output.json({
|
|
7331
7381
|
status: "ACTION_REQUIRED",
|
|
7332
7382
|
reason: "scanner_consent_required",
|
|
7333
|
-
action:
|
|
7383
|
+
action: SCANNER_APPROVAL_ACTION,
|
|
7384
|
+
approval: SCANNER_APPROVAL_NOTE
|
|
7334
7385
|
});
|
|
7335
|
-
else
|
|
7336
|
-
output.line(SCANNER_CONSENT_MESSAGE.sentence);
|
|
7337
|
-
output.line(SCANNER_CONSENT_MESSAGE.nextStep);
|
|
7338
|
-
}
|
|
7386
|
+
else for (const line of approvalLines("scanner_consent_required", agent)) output.line(line);
|
|
7339
7387
|
return 3;
|
|
7340
7388
|
}
|
|
7341
7389
|
function hostUpdateFailed(result) {
|
|
@@ -7694,7 +7742,9 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
|
|
|
7694
7742
|
() => true,
|
|
7695
7743
|
() => false
|
|
7696
7744
|
)) {
|
|
7745
|
+
const pausedForApproval = pausedForConsent(await scannerReceipt(state));
|
|
7697
7746
|
try {
|
|
7747
|
+
if (pausedForApproval) throw new ScannerConsentRequired();
|
|
7698
7748
|
const before = await store.verifyRuntime("scanner").catch(() => void 0);
|
|
7699
7749
|
const runtime = await retryUpdateOnce(
|
|
7700
7750
|
() => updateScanner(
|
|
@@ -7716,13 +7766,21 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
|
|
|
7716
7766
|
version: runtime.manifest.version
|
|
7717
7767
|
};
|
|
7718
7768
|
} catch (error) {
|
|
7719
|
-
if (error instanceof ScannerConsentRequired)
|
|
7720
|
-
|
|
7769
|
+
if (error instanceof ScannerConsentRequired) {
|
|
7770
|
+
const approval = await approveScannerUpdate(
|
|
7771
|
+
parsed,
|
|
7772
|
+
deps,
|
|
7773
|
+
output,
|
|
7774
|
+
state,
|
|
7775
|
+
pausedForApproval ? "scanner_consent_required" : "scanner_update_consent_required"
|
|
7776
|
+
);
|
|
7777
|
+
scanner = approval.status === "approved" ? { status: "UPDATED" } : {
|
|
7721
7778
|
status: "ACTION_REQUIRED",
|
|
7722
|
-
reason:
|
|
7723
|
-
action:
|
|
7779
|
+
reason: approval.reason,
|
|
7780
|
+
action: SCANNER_APPROVAL_ACTION,
|
|
7781
|
+
approval: SCANNER_APPROVAL_NOTE
|
|
7724
7782
|
};
|
|
7725
|
-
else scanner = { status: "FAILED", reason: error.message };
|
|
7783
|
+
} else scanner = { status: "FAILED", reason: error.message };
|
|
7726
7784
|
if (!json && scanner.status === "FAILED")
|
|
7727
7785
|
scannerRecovery = await scannerRecoveryAction(error, {
|
|
7728
7786
|
stateDir: state,
|
|
@@ -7742,7 +7800,7 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
|
|
|
7742
7800
|
if (all)
|
|
7743
7801
|
await recordUpdateCheck(
|
|
7744
7802
|
state,
|
|
7745
|
-
failed || hostsFailed ? "failed" : cli?.status === "UPDATED" || result.reports.length > 0 || scanner?.status === "UPDATED" ? "updated" : "current"
|
|
7803
|
+
failed || hostsFailed ? "failed" : scannerConsentPending ? "consent_pending" : cli?.status === "UPDATED" || result.reports.length > 0 || scanner?.status === "UPDATED" ? "updated" : "current"
|
|
7746
7804
|
);
|
|
7747
7805
|
if (fullUninstall && hostExit === 0) {
|
|
7748
7806
|
const installed = await Promise.all(
|
|
@@ -7818,15 +7876,18 @@ async function runHostCommand(command, parsed, deps, output, scannerSelected = f
|
|
|
7818
7876
|
} else if (cli?.status === "UPDATED" || result.reports.length > 0 || scanner?.status === "UPDATED")
|
|
7819
7877
|
output.line("Mnemonik updated.");
|
|
7820
7878
|
else output.line("Mnemonik is up to date.");
|
|
7821
|
-
if (scannerConsentPending)
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7879
|
+
if (scannerConsentPending)
|
|
7880
|
+
for (const line of approvalLines(
|
|
7881
|
+
scanner?.reason ?? "scanner_update_consent_required",
|
|
7882
|
+
!personPresent(parsed, deps)
|
|
7883
|
+
))
|
|
7884
|
+
output.line(line);
|
|
7825
7885
|
} else {
|
|
7826
7886
|
for (const target of result.results)
|
|
7827
7887
|
output.line(target.status === "READY" ? "Done." : humanReason(target.reason));
|
|
7828
7888
|
for (const report of result.reports) output.line(humanReport(report));
|
|
7829
|
-
if (remaining)
|
|
7889
|
+
if (remaining)
|
|
7890
|
+
renderStatusSummaries(remaining, output, { agent: !personPresent(parsed, deps) });
|
|
7830
7891
|
if (!selections.length && !fullUninstall && !remaining)
|
|
7831
7892
|
output.line("No recorded host targets.");
|
|
7832
7893
|
if (fullUninstall && !failed && hostExit === 0)
|
|
@@ -7888,28 +7949,133 @@ async function scannerRecoveryAction(error, options) {
|
|
|
7888
7949
|
action: failure?.action ?? SCANNER_RETRY_MESSAGE
|
|
7889
7950
|
};
|
|
7890
7951
|
}
|
|
7952
|
+
var FOLDER_REFUSED = /^(?:filesystem_root|home_directory|temporary_directory|mnemonik_state_directory|user_data_directory|host_config_directory|broad_workspace_parent)$/u;
|
|
7953
|
+
var ENABLE_FAILURES = {
|
|
7954
|
+
browser_consent_required: {
|
|
7955
|
+
summary: "The folders were not approved in your browser.",
|
|
7956
|
+
action: SCANNER_ENABLE_ACTION
|
|
7957
|
+
},
|
|
7958
|
+
consent_declined: {
|
|
7959
|
+
summary: "Background indexing was not approved.",
|
|
7960
|
+
action: SCANNER_ENABLE_ACTION
|
|
7961
|
+
},
|
|
7962
|
+
scanner_approval_declined: {
|
|
7963
|
+
summary: "Background indexing was not approved.",
|
|
7964
|
+
action: SCANNER_ENABLE_ACTION
|
|
7965
|
+
},
|
|
7966
|
+
scanner_approval_expired: {
|
|
7967
|
+
summary: "The approval request expired before it was approved.",
|
|
7968
|
+
action: SCANNER_ENABLE_ACTION
|
|
7969
|
+
},
|
|
7970
|
+
// The scanner this CLI carries names a notice the account's approval does not cover.
|
|
7971
|
+
release_consent_required: {
|
|
7972
|
+
summary: "This version of Mnemonik cannot install the newer scanner yet.",
|
|
7973
|
+
action: "mnemonik update"
|
|
7974
|
+
},
|
|
7975
|
+
scan_roots_required: {
|
|
7976
|
+
summary: "No folder was chosen for background indexing.",
|
|
7977
|
+
action: `${SCANNER_ENABLE_ACTION} --scan-roots <folder>`
|
|
7978
|
+
}
|
|
7979
|
+
};
|
|
7980
|
+
function folderFailure(code, folder) {
|
|
7981
|
+
if (code === "ENOENT")
|
|
7982
|
+
return {
|
|
7983
|
+
reason: "folder_missing",
|
|
7984
|
+
folder,
|
|
7985
|
+
summary: `This folder does not exist: ${folder}`,
|
|
7986
|
+
action: "Pass folders that exist in --scan-roots, or leave --scan-roots out to keep the folders already approved."
|
|
7987
|
+
};
|
|
7988
|
+
if (code === "EACCES" || code === "EPERM")
|
|
7989
|
+
return {
|
|
7990
|
+
reason: "folder_unreadable",
|
|
7991
|
+
folder,
|
|
7992
|
+
summary: `Mnemonik cannot open this folder: ${folder}`,
|
|
7993
|
+
action: "Give the user read access to the folder, or choose another, then run the command again."
|
|
7994
|
+
};
|
|
7995
|
+
return void 0;
|
|
7996
|
+
}
|
|
7997
|
+
function enableFailure(error) {
|
|
7998
|
+
const message = error.message;
|
|
7999
|
+
const limited = scannerFailure(error);
|
|
8000
|
+
if (limited) return { reason: message, summary: limited.summary, step: limited.action };
|
|
8001
|
+
const { code, path } = error;
|
|
8002
|
+
const folder = path ? folderFailure(code, path) : void 0;
|
|
8003
|
+
if (folder) return folder;
|
|
8004
|
+
if (FOLDER_REFUSED.test(message)) return { reason: message, summary: "" };
|
|
8005
|
+
const stopped = error instanceof OAuthProtocolError ? approvalStopped(error, message) : message;
|
|
8006
|
+
const known = ENABLE_FAILURES[stopped];
|
|
8007
|
+
if (known) return { reason: stopped, ...known };
|
|
8008
|
+
if (message === "lock_held") return { reason: message, summary: humanReason(message) };
|
|
8009
|
+
const words = knownReason(message);
|
|
8010
|
+
if (words) return { reason: message, summary: words.sentence, step: words.nextStep };
|
|
8011
|
+
return {
|
|
8012
|
+
reason: message,
|
|
8013
|
+
summary: SCANNER_LIMITED_SENTENCE,
|
|
8014
|
+
action: SCANNER_ENABLE_ACTION
|
|
8015
|
+
};
|
|
8016
|
+
}
|
|
8017
|
+
function enableFailed(output, json, agent, failure) {
|
|
8018
|
+
const action = failure.action ?? failure.step;
|
|
8019
|
+
if (json)
|
|
8020
|
+
output.json({
|
|
8021
|
+
status: "ACTION_REQUIRED",
|
|
8022
|
+
reason: failure.reason,
|
|
8023
|
+
...failure.folder ? { folder: failure.folder } : {},
|
|
8024
|
+
...action ? { action } : {}
|
|
8025
|
+
});
|
|
8026
|
+
else {
|
|
8027
|
+
if (failure.summary) output.error(failure.summary);
|
|
8028
|
+
const next = agent ? action : failure.step;
|
|
8029
|
+
if (next) output.error(/^mnemonik /u.test(next) ? `Run ${next}.` : next);
|
|
8030
|
+
}
|
|
8031
|
+
return 3;
|
|
8032
|
+
}
|
|
8033
|
+
async function approvedSelection(stateDir) {
|
|
8034
|
+
const saved = JSON.parse(
|
|
8035
|
+
await readFile4(join7(stateDir, "scanner/state.json"), "utf8").catch(() => "null")
|
|
8036
|
+
);
|
|
8037
|
+
const roots = saved?.config?.roots;
|
|
8038
|
+
if (!Array.isArray(roots) || !roots.length || !roots.every((r) => typeof r === "string"))
|
|
8039
|
+
return void 0;
|
|
8040
|
+
const exclusions = saved?.config?.exclusions;
|
|
8041
|
+
return {
|
|
8042
|
+
roots,
|
|
8043
|
+
exclusions: Array.isArray(exclusions) ? exclusions.filter((e) => typeof e === "string") : []
|
|
8044
|
+
};
|
|
8045
|
+
}
|
|
7891
8046
|
async function enableCommand(parsed, deps, output) {
|
|
7892
8047
|
const json = parsed.flags.has("json");
|
|
7893
8048
|
const present = personPresent(parsed, deps);
|
|
8049
|
+
const stateDir = deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
|
|
8050
|
+
const home = deps.home ?? homedir4();
|
|
7894
8051
|
if (!present) {
|
|
7895
8052
|
const missing = requireConsent(parsed, output, ["accept-indexing", "apply"]);
|
|
7896
8053
|
if (missing !== void 0) return missing;
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
8054
|
+
}
|
|
8055
|
+
const rootsFlag = parsed.flags.get("scan-roots");
|
|
8056
|
+
const exclusionsFlag = parsed.flags.get("exclusions");
|
|
8057
|
+
let roots = typeof rootsFlag === "string" ? folderList(rootsFlag, home) : void 0;
|
|
8058
|
+
let exclusions = typeof exclusionsFlag === "string" ? folderList(exclusionsFlag, home) : void 0;
|
|
8059
|
+
if (!roots && (!present || parsed.flags.has("apply"))) {
|
|
8060
|
+
const approved = await approvedSelection(stateDir);
|
|
8061
|
+
if (approved) {
|
|
8062
|
+
roots = approved.roots;
|
|
8063
|
+
exclusions ??= approved.exclusions;
|
|
8064
|
+
}
|
|
8065
|
+
}
|
|
8066
|
+
if (!present && !roots)
|
|
8067
|
+
return actionRequired2(output, json, "Supply --scan-roots with approved roots", "--scan-roots");
|
|
8068
|
+
for (const folder of [...roots ?? [], ...exclusions ?? []]) {
|
|
8069
|
+
const failure = await realpath(folder).then(
|
|
8070
|
+
() => void 0,
|
|
8071
|
+
(error) => folderFailure(error.code, folder)
|
|
8072
|
+
);
|
|
8073
|
+
if (failure) return enableFailed(output, json, !present, failure);
|
|
7904
8074
|
}
|
|
7905
8075
|
try {
|
|
7906
|
-
await closeUntouchedScannerRun(
|
|
7907
|
-
deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home)
|
|
7908
|
-
).catch(() => false);
|
|
7909
|
-
const roots = parsed.flags.get("scan-roots");
|
|
7910
|
-
const exclusions = parsed.flags.get("exclusions");
|
|
8076
|
+
await closeUntouchedScannerRun(stateDir).catch(() => false);
|
|
7911
8077
|
const result = await enableScanner({
|
|
7912
|
-
stateDir
|
|
8078
|
+
stateDir,
|
|
7913
8079
|
cwd: deps.cwd ?? process.cwd(),
|
|
7914
8080
|
home: deps.home,
|
|
7915
8081
|
input: deps.input ?? process.stdin,
|
|
@@ -7917,29 +8083,20 @@ async function enableCommand(parsed, deps, output) {
|
|
|
7917
8083
|
nonInteractive: !present,
|
|
7918
8084
|
noBrowser: parsed.flags.has("no-browser"),
|
|
7919
8085
|
timeout: retryOnce(parsed.flags),
|
|
7920
|
-
|
|
7921
|
-
...
|
|
8086
|
+
// An agent's run hands over the browser approval link as soon as it exists.
|
|
8087
|
+
...present ? {} : { onApprovalLink: relayApprovalLink(output, json, "scanner_consent_required") },
|
|
8088
|
+
...roots ? { roots } : {},
|
|
8089
|
+
...exclusions ? { exclusions } : {},
|
|
7922
8090
|
...deps.scannerService,
|
|
7923
8091
|
...deps.scannerEnable,
|
|
7924
8092
|
projectExecutor: deps.projectExecutor,
|
|
7925
8093
|
projectStateDir: deps.projectStateDir
|
|
7926
8094
|
});
|
|
7927
8095
|
if (json) output.json(result);
|
|
7928
|
-
else renderStatusSummaries(result, output);
|
|
8096
|
+
else renderStatusSummaries(result, output, { agent: !present });
|
|
7929
8097
|
return result.installation.state === "READY" ? 0 : 3;
|
|
7930
8098
|
} catch (error) {
|
|
7931
|
-
|
|
7932
|
-
const result = {
|
|
7933
|
-
status: "ACTION_REQUIRED",
|
|
7934
|
-
reason: error.message,
|
|
7935
|
-
action: failure.action
|
|
7936
|
-
};
|
|
7937
|
-
if (json) output.json(result);
|
|
7938
|
-
else {
|
|
7939
|
-
output.error(failure.summary);
|
|
7940
|
-
if (failure.action) output.error(failure.action);
|
|
7941
|
-
}
|
|
7942
|
-
return 3;
|
|
8099
|
+
return enableFailed(output, json, !present, enableFailure(error));
|
|
7943
8100
|
}
|
|
7944
8101
|
}
|
|
7945
8102
|
async function installCommand(parsed, deps, output) {
|
|
@@ -8305,7 +8462,7 @@ async function runCli(args2, deps = {}) {
|
|
|
8305
8462
|
);
|
|
8306
8463
|
if (!saved) return actionRequired2(output, parsed.flags.has("json"), "mnemonik install");
|
|
8307
8464
|
if ((action === "add" || action === "remove") && pausedForConsent(await scannerReceipt(stateDir)))
|
|
8308
|
-
return scannerConsentRequired(output, parsed.flags.has("json"));
|
|
8465
|
+
return scannerConsentRequired(output, parsed.flags.has("json"), !personPresent(parsed, deps));
|
|
8309
8466
|
if (action === "list") {
|
|
8310
8467
|
if (parsed.flags.has("json")) output.json(saved.config.roots);
|
|
8311
8468
|
else for (const root of saved.config.roots) output.line(root);
|
|
@@ -8395,7 +8552,7 @@ async function runCli(args2, deps = {}) {
|
|
|
8395
8552
|
status: "revoked",
|
|
8396
8553
|
verbs: ["revoke access"],
|
|
8397
8554
|
retained: ["local software", "cloud data"],
|
|
8398
|
-
action:
|
|
8555
|
+
action: SCANNER_ENABLE_ACTION
|
|
8399
8556
|
};
|
|
8400
8557
|
if (parsed.flags.has("json")) output.json(result);
|
|
8401
8558
|
else
|
|
@@ -8458,6 +8615,8 @@ async function runCli(args2, deps = {}) {
|
|
|
8458
8615
|
...deps.scannerService
|
|
8459
8616
|
};
|
|
8460
8617
|
if (command === "update") {
|
|
8618
|
+
if (pausedForConsent(await scannerReceipt(options.stateDir)))
|
|
8619
|
+
throw new ScannerConsentRequired(true);
|
|
8461
8620
|
const store = new RuntimeStore(options.stateDir);
|
|
8462
8621
|
const before = await store.verifyRuntime("scanner").catch(() => void 0);
|
|
8463
8622
|
const runtime = await retryUpdateOnce(
|
|
@@ -8496,7 +8655,14 @@ async function runCli(args2, deps = {}) {
|
|
|
8496
8655
|
} catch (error) {
|
|
8497
8656
|
if (command === "update" && error instanceof ScannerConsentRequired) {
|
|
8498
8657
|
const stateDir = deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home);
|
|
8499
|
-
|
|
8658
|
+
const approval = await approveScannerUpdate(
|
|
8659
|
+
parsed,
|
|
8660
|
+
deps,
|
|
8661
|
+
output,
|
|
8662
|
+
stateDir,
|
|
8663
|
+
error.paused ? "scanner_consent_required" : "scanner_update_consent_required"
|
|
8664
|
+
);
|
|
8665
|
+
if (approval.status === "approved") {
|
|
8500
8666
|
if (parsed.flags.has("json")) output.json({ status: "updated" });
|
|
8501
8667
|
else output.line("Mnemonik updated.");
|
|
8502
8668
|
return 0;
|
|
@@ -8504,13 +8670,13 @@ async function runCli(args2, deps = {}) {
|
|
|
8504
8670
|
if (parsed.flags.has("json"))
|
|
8505
8671
|
output.json({
|
|
8506
8672
|
status: "ACTION_REQUIRED",
|
|
8507
|
-
reason:
|
|
8508
|
-
action:
|
|
8673
|
+
reason: approval.reason,
|
|
8674
|
+
action: SCANNER_APPROVAL_ACTION,
|
|
8675
|
+
approval: SCANNER_APPROVAL_NOTE
|
|
8509
8676
|
});
|
|
8510
|
-
else
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
}
|
|
8677
|
+
else
|
|
8678
|
+
for (const line of approvalLines(approval.reason, !personPresent(parsed, deps)))
|
|
8679
|
+
output.line(line);
|
|
8514
8680
|
return 3;
|
|
8515
8681
|
}
|
|
8516
8682
|
const failure = scannerFailure(error);
|
|
@@ -8665,7 +8831,7 @@ Preview: ${preview.path}
|
|
|
8665
8831
|
deps.installStateDir ?? stateDirectory(process.platform, process.env, deps.home)
|
|
8666
8832
|
);
|
|
8667
8833
|
if (!parsed.flags.has("json")) {
|
|
8668
|
-
renderStatusSummaries(shown, output);
|
|
8834
|
+
renderStatusSummaries(shown, output, { agent: !personPresent(parsed, deps) });
|
|
8669
8835
|
for (const line of codingToolLines(shown.codingTools)) output.line(line);
|
|
8670
8836
|
await renderRefusals(refusalStateDir(deps), output);
|
|
8671
8837
|
}
|
|
@@ -8960,7 +9126,7 @@ Preview: ${preview.path}
|
|
|
8960
9126
|
...deps.scannerService
|
|
8961
9127
|
};
|
|
8962
9128
|
if (subcommand === "resume" && pausedForConsent(await scannerReceipt(options.stateDir)))
|
|
8963
|
-
return scannerConsentRequired(output, json);
|
|
9129
|
+
return scannerConsentRequired(output, json, !personPresent(parsed, deps));
|
|
8964
9130
|
if (subcommand === "pause" || subcommand === "resume")
|
|
8965
9131
|
await controlScanner(subcommand, options);
|
|
8966
9132
|
else if (subcommand === "export-preview") {
|