@mnemom/mnemom 0.17.2 → 0.17.3-next.0
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/commands/config.d.ts +5 -3
- package/dist/commands/config.js +12 -4
- package/dist/commands/update.d.ts +2 -2
- package/dist/commands/update.js +3 -3
- package/dist/lib/update/decide.d.ts +21 -2
- package/dist/lib/update/decide.js +19 -5
- package/dist/lib/update/doctor.js +3 -1
- package/dist/lib/update/min-version.js +3 -1
- package/dist/lib/update/run.js +1 -0
- package/dist/lib/update/startup.js +7 -2
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Keys are data (CONFIG_KEYS) so list/get/set/unset share one source of truth.
|
|
7
7
|
*/
|
|
8
|
-
import { type UpdatePrefs } from "../lib/update/decide.js";
|
|
8
|
+
import { type InstallHint, type UpdatePrefs } from "../lib/update/decide.js";
|
|
9
9
|
import { setUpdatePref } from "../lib/cli-config.js";
|
|
10
10
|
export interface CliConfigKey {
|
|
11
11
|
key: string;
|
|
@@ -13,8 +13,8 @@ export interface CliConfigKey {
|
|
|
13
13
|
env: string;
|
|
14
14
|
/** Stored value (undefined when unset). */
|
|
15
15
|
stored(prefs: UpdatePrefs): string | undefined;
|
|
16
|
-
/** Value in effect after env + default. */
|
|
17
|
-
effective(prefs: UpdatePrefs, env: Record<string, string | undefined
|
|
16
|
+
/** Value in effect after env + default (`hint` picks the channel default). */
|
|
17
|
+
effective(prefs: UpdatePrefs, env: Record<string, string | undefined>, hint: InstallHint): string;
|
|
18
18
|
/** Validate + persist; throws with a user-facing message on a bad value. */
|
|
19
19
|
set(raw: string, persist: typeof setUpdatePref): void;
|
|
20
20
|
unset(persist: typeof setUpdatePref): void;
|
|
@@ -26,6 +26,8 @@ export interface ConfigDeps {
|
|
|
26
26
|
env: Record<string, string | undefined>;
|
|
27
27
|
persist: typeof setUpdatePref;
|
|
28
28
|
log(line: string): void;
|
|
29
|
+
/** Running version + last-followed channel (picks the default channel). */
|
|
30
|
+
hint: InstallHint;
|
|
29
31
|
}
|
|
30
32
|
/** One line per key: `key = effective (source) — description`. */
|
|
31
33
|
export declare function configListCommand(opts?: {
|
package/dist/commands/config.js
CHANGED
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { isUpdateChannel, isUpdateMode, resolveChannel, resolveMode, UPDATE_CHANNELS, UPDATE_MODES, } from "../lib/update/decide.js";
|
|
9
9
|
import { loadCliConfig, setUpdatePref } from "../lib/cli-config.js";
|
|
10
|
+
import { loadUpdateState } from "../lib/update/state.js";
|
|
11
|
+
import { CLI_VERSION } from "../version.js";
|
|
10
12
|
export const CONFIG_KEYS = [
|
|
11
13
|
{
|
|
12
14
|
key: "update.channel",
|
|
13
|
-
describe: `Release channel for auto-update: ${UPDATE_CHANNELS.join(" | ")} (next requires an invite)`,
|
|
15
|
+
describe: `Release channel for auto-update: ${UPDATE_CHANNELS.join(" | ")} (default: next on a next build, else latest; next requires an invite)`,
|
|
14
16
|
env: "MNEMOM_UPDATE_CHANNEL",
|
|
15
17
|
stored: (p) => p.channel,
|
|
16
|
-
effective: (p, env) => resolveChannel(p, env),
|
|
18
|
+
effective: (p, env, hint) => resolveChannel(p, env, undefined, hint),
|
|
17
19
|
set: (raw, persist) => {
|
|
18
20
|
const v = raw.trim();
|
|
19
21
|
if (!isUpdateChannel(v))
|
|
@@ -49,6 +51,7 @@ function defaultDeps() {
|
|
|
49
51
|
env: process.env,
|
|
50
52
|
persist: setUpdatePref,
|
|
51
53
|
log: (line) => console.log(line),
|
|
54
|
+
hint: { current: CLI_VERSION, followed: loadUpdateState().followChannel },
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
/** One line per key: `key = effective (source) — description`. */
|
|
@@ -57,7 +60,12 @@ export function configListCommand(opts = {}, deps = defaultDeps()) {
|
|
|
57
60
|
const rows = CONFIG_KEYS.map((k) => {
|
|
58
61
|
const stored = k.stored(prefs);
|
|
59
62
|
const source = deps.env[k.env] ? `env ${k.env}` : stored !== undefined ? "config" : "default";
|
|
60
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
key: k.key,
|
|
65
|
+
value: k.effective(prefs, deps.env, deps.hint),
|
|
66
|
+
source,
|
|
67
|
+
describe: k.describe,
|
|
68
|
+
};
|
|
61
69
|
});
|
|
62
70
|
if (opts.json) {
|
|
63
71
|
deps.log(JSON.stringify(rows, null, 2));
|
|
@@ -67,7 +75,7 @@ export function configListCommand(opts = {}, deps = defaultDeps()) {
|
|
|
67
75
|
deps.log(`${r.key} = ${r.value} (${r.source}) — ${r.describe}`);
|
|
68
76
|
}
|
|
69
77
|
export function configGetCommand(key, deps = defaultDeps()) {
|
|
70
|
-
deps.log(findKey(key).effective(deps.prefs(), deps.env));
|
|
78
|
+
deps.log(findKey(key).effective(deps.prefs(), deps.env, deps.hint));
|
|
71
79
|
}
|
|
72
80
|
export function configSetCommand(key, value, deps = defaultDeps()) {
|
|
73
81
|
const spec = findKey(key);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* command is consent). `--check` never installs; `--force` permits a downgrade
|
|
7
7
|
* to the channel's version (e.g. leaving next for latest).
|
|
8
8
|
*/
|
|
9
|
-
import { type ResolvedSettings } from "../lib/update/decide.js";
|
|
9
|
+
import { type InstallHint, type ResolvedSettings } from "../lib/update/decide.js";
|
|
10
10
|
import { type RunDeps, type RunResult } from "../lib/update/run.js";
|
|
11
11
|
export declare const NEXT_NOT_ENTITLED_HINT: string;
|
|
12
12
|
export interface UpdateOptions {
|
|
@@ -16,7 +16,7 @@ export interface UpdateOptions {
|
|
|
16
16
|
json?: boolean;
|
|
17
17
|
}
|
|
18
18
|
/** Validate flags → the settings for this foreground pass, or an error message. */
|
|
19
|
-
export declare function foregroundSettings(opts: UpdateOptions, prefs?: import("../lib/update/decide.js").UpdatePrefs, env?: Record<string, string | undefined
|
|
19
|
+
export declare function foregroundSettings(opts: UpdateOptions, prefs?: import("../lib/update/decide.js").UpdatePrefs, env?: Record<string, string | undefined>, hint?: InstallHint): ResolvedSettings | string;
|
|
20
20
|
/** Human-readable report of one pass. Pure, for testing. */
|
|
21
21
|
export declare function formatUpdateResult(result: RunResult, current: string): string[];
|
|
22
22
|
/** Exit status: non-zero only when something actually failed. */
|
package/dist/commands/update.js
CHANGED
|
@@ -10,17 +10,17 @@ import chalk from "chalk";
|
|
|
10
10
|
import { CLI_VERSION } from "../version.js";
|
|
11
11
|
import { canSelfUpdate, isUpdateChannel, manualUpgradeCommand, resolveChannel, UPDATE_CHANNELS, } from "../lib/update/decide.js";
|
|
12
12
|
import { runUpdate } from "../lib/update/run.js";
|
|
13
|
-
import { acquireLock } from "../lib/update/state.js";
|
|
13
|
+
import { acquireLock, loadUpdateState } from "../lib/update/state.js";
|
|
14
14
|
import { entryRealpath, foregroundCredential, loadUpdatePrefs } from "../lib/update/system.js";
|
|
15
15
|
import { realRunDeps } from "../lib/update/worker.js";
|
|
16
16
|
export const NEXT_NOT_ENTITLED_HINT = "The next channel is available to invited accounts. Ask your Mnemom contact for an invite " +
|
|
17
17
|
"(and make sure you're logged in: mnemom login). Using latest for now.";
|
|
18
18
|
/** Validate flags → the settings for this foreground pass, or an error message. */
|
|
19
|
-
export function foregroundSettings(opts, prefs = loadUpdatePrefs(), env = process.env) {
|
|
19
|
+
export function foregroundSettings(opts, prefs = loadUpdatePrefs(), env = process.env, hint = { current: CLI_VERSION, followed: loadUpdateState().followChannel }) {
|
|
20
20
|
if (opts.channel !== undefined && !isUpdateChannel(opts.channel)) {
|
|
21
21
|
return `--channel must be one of ${UPDATE_CHANNELS.join(", ")} (got '${opts.channel}').`;
|
|
22
22
|
}
|
|
23
|
-
const channel = resolveChannel(prefs, env, opts.channel);
|
|
23
|
+
const channel = resolveChannel(prefs, env, opts.channel, hint);
|
|
24
24
|
return { channel, mode: opts.check ? "notify" : "auto" };
|
|
25
25
|
}
|
|
26
26
|
/** Human-readable report of one pass. Pure, for testing. */
|
|
@@ -62,6 +62,8 @@ export interface UpdateState {
|
|
|
62
62
|
entitlement?: EntitlementCache;
|
|
63
63
|
/** Install method the worker last detected (startup can't afford `npm root -g`). */
|
|
64
64
|
method?: InstallMethod;
|
|
65
|
+
/** Channel the last successful update installed from; feeds defaultChannel. */
|
|
66
|
+
followChannel?: UpdateChannel;
|
|
65
67
|
}
|
|
66
68
|
export interface UpdatePrefs {
|
|
67
69
|
channel?: UpdateChannel;
|
|
@@ -75,8 +77,23 @@ export interface ResolvedSettings {
|
|
|
75
77
|
}
|
|
76
78
|
export declare function isUpdateChannel(v: unknown): v is UpdateChannel;
|
|
77
79
|
export declare function isUpdateMode(v: unknown): v is UpdateMode;
|
|
78
|
-
/**
|
|
79
|
-
export
|
|
80
|
+
/** What the unconfigured default is derived from. */
|
|
81
|
+
export interface InstallHint {
|
|
82
|
+
/** The running CLI version. */
|
|
83
|
+
current?: string;
|
|
84
|
+
/** The channel the last successful update installed from (update state). */
|
|
85
|
+
followed?: UpdateChannel;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The channel when nothing is configured: `next` if this build was installed
|
|
89
|
+
* from `@next` (a prerelease, e.g. a Mnemom Code invite) or the updater last
|
|
90
|
+
* installed from `next` — the latter keeps a `next` follower on `next` after
|
|
91
|
+
* `latest` overtakes it and they land on a stable build. Otherwise `latest`.
|
|
92
|
+
* The entitlement check still applies to a defaulted `next`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function defaultChannel(hint?: InstallHint): UpdateChannel;
|
|
95
|
+
/** Channel precedence: flag > MNEMOM_UPDATE_CHANNEL > config.json > defaultChannel(hint). */
|
|
96
|
+
export declare function resolveChannel(prefs: UpdatePrefs, env: Record<string, string | undefined>, flag?: UpdateChannel, hint?: InstallHint): UpdateChannel;
|
|
80
97
|
/** Mode precedence: flag > MNEMOM_UPDATE_MODE > config.json > auto. */
|
|
81
98
|
export declare function resolveMode(prefs: UpdatePrefs, env: Record<string, string | undefined>, flag?: UpdateMode): UpdateMode;
|
|
82
99
|
/**
|
|
@@ -91,6 +108,8 @@ export declare function resolveSettings(input: {
|
|
|
91
108
|
env: Record<string, string | undefined>;
|
|
92
109
|
isTTY: boolean;
|
|
93
110
|
flags?: UpdatePrefs;
|
|
111
|
+
/** Picks the default channel when none is configured. */
|
|
112
|
+
hint?: InstallHint;
|
|
94
113
|
}): ResolvedSettings;
|
|
95
114
|
/** The channel actually honoured: `next` requires a positive entitlement. */
|
|
96
115
|
export declare function effectiveChannel(requested: UpdateChannel, entitledToNext: boolean): UpdateChannel;
|
|
@@ -45,10 +45,24 @@ export function isUpdateMode(v) {
|
|
|
45
45
|
function truthyEnv(v) {
|
|
46
46
|
return v !== undefined && v !== "" && v !== "0" && v.toLowerCase() !== "false";
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The channel when nothing is configured: `next` if this build was installed
|
|
50
|
+
* from `@next` (a prerelease, e.g. a Mnemom Code invite) or the updater last
|
|
51
|
+
* installed from `next` — the latter keeps a `next` follower on `next` after
|
|
52
|
+
* `latest` overtakes it and they land on a stable build. Otherwise `latest`.
|
|
53
|
+
* The entitlement check still applies to a defaulted `next`.
|
|
54
|
+
*/
|
|
55
|
+
export function defaultChannel(hint = {}) {
|
|
56
|
+
const onPrerelease = hint.current !== undefined && isPrerelease(hint.current);
|
|
57
|
+
return onPrerelease || hint.followed === "next" ? "next" : "latest";
|
|
58
|
+
}
|
|
59
|
+
/** Channel precedence: flag > MNEMOM_UPDATE_CHANNEL > config.json > defaultChannel(hint). */
|
|
60
|
+
export function resolveChannel(prefs, env, flag, hint) {
|
|
50
61
|
const fromEnv = env.MNEMOM_UPDATE_CHANNEL;
|
|
51
|
-
return flag ??
|
|
62
|
+
return (flag ??
|
|
63
|
+
(isUpdateChannel(fromEnv) ? fromEnv : undefined) ??
|
|
64
|
+
prefs.channel ??
|
|
65
|
+
defaultChannel(hint));
|
|
52
66
|
}
|
|
53
67
|
/** Mode precedence: flag > MNEMOM_UPDATE_MODE > config.json > auto. */
|
|
54
68
|
export function resolveMode(prefs, env, flag) {
|
|
@@ -63,8 +77,8 @@ export function resolveMode(prefs, env, flag) {
|
|
|
63
77
|
* every command.
|
|
64
78
|
*/
|
|
65
79
|
export function resolveSettings(input) {
|
|
66
|
-
const { prefs, env, isTTY, flags } = input;
|
|
67
|
-
const channel = resolveChannel(prefs, env, flags?.channel);
|
|
80
|
+
const { prefs, env, isTTY, flags, hint } = input;
|
|
81
|
+
const channel = resolveChannel(prefs, env, flags?.channel, hint);
|
|
68
82
|
const mode = resolveMode(prefs, env, flags?.mode);
|
|
69
83
|
if (truthyEnv(env.MNEMOM_DISABLE_AUTOUPDATE)) {
|
|
70
84
|
return { channel, mode: "off", offReason: "MNEMOM_DISABLE_AUTOUPDATE is set" };
|
|
@@ -53,11 +53,13 @@ export function updateDoctorRow(input) {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
export async function probeUpdateStatus() {
|
|
56
|
+
const state = loadUpdateState();
|
|
56
57
|
const settings = resolveSettings({
|
|
57
58
|
prefs: loadUpdatePrefs(),
|
|
58
59
|
env: process.env,
|
|
59
60
|
isTTY: process.stdout.isTTY === true,
|
|
61
|
+
hint: { current: CLI_VERSION, followed: state.followChannel },
|
|
60
62
|
});
|
|
61
63
|
const method = classifyInstall(entryRealpath(process.argv[1]), await npmGlobalRoot());
|
|
62
|
-
return updateDoctorRow({ current: CLI_VERSION, settings, method, state
|
|
64
|
+
return updateDoctorRow({ current: CLI_VERSION, settings, method, state });
|
|
63
65
|
}
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
8
|
import { canSelfUpdate, PACKAGE_NAME, resolveSettings, } from "./decide.js";
|
|
9
|
+
import { CLI_VERSION } from "../../version.js";
|
|
9
10
|
import { classifyInstall } from "./install-method.js";
|
|
10
11
|
import { isValidVersion, isPrerelease } from "./semver.js";
|
|
11
|
-
import { acquireLock } from "./state.js";
|
|
12
|
+
import { acquireLock, loadUpdateState } from "./state.js";
|
|
12
13
|
import { entryRealpath, loadUpdatePrefs, npmInvocation } from "./system.js";
|
|
13
14
|
/**
|
|
14
15
|
* Returns true when the CLI was upgraded. Only in `auto` mode — `notify` means
|
|
@@ -54,6 +55,7 @@ export function defaultFloorUpgradeDeps() {
|
|
|
54
55
|
prefs: loadUpdatePrefs(),
|
|
55
56
|
env: process.env,
|
|
56
57
|
isTTY: process.stdout.isTTY === true,
|
|
58
|
+
hint: { current: CLI_VERSION, followed: loadUpdateState().followChannel },
|
|
57
59
|
}),
|
|
58
60
|
method: () => {
|
|
59
61
|
const root = spawnNpmSync(inv, ["root", "-g"], { timeout: 15_000 });
|
package/dist/lib/update/run.js
CHANGED
|
@@ -86,6 +86,7 @@ export async function runUpdate(deps, settings, opts = {}) {
|
|
|
86
86
|
available: undefined,
|
|
87
87
|
installBlocked: undefined,
|
|
88
88
|
pending: { from: deps.current, to: action.version, channel },
|
|
89
|
+
followChannel: channel,
|
|
89
90
|
});
|
|
90
91
|
return { ...result, installed: action.version };
|
|
91
92
|
}
|
|
@@ -16,13 +16,18 @@ import { entryRealpath, loadUpdatePrefs } from "./system.js";
|
|
|
16
16
|
const SKIP_COMMANDS = new Set(["update", "config"]);
|
|
17
17
|
export function maybeRunUpdateHook(deps) {
|
|
18
18
|
try {
|
|
19
|
-
const
|
|
19
|
+
const state = deps.loadState();
|
|
20
|
+
const settings = resolveSettings({
|
|
21
|
+
prefs: deps.prefs(),
|
|
22
|
+
env: deps.env,
|
|
23
|
+
isTTY: deps.stdoutTTY,
|
|
24
|
+
hint: { current: deps.current, followed: state.followChannel },
|
|
25
|
+
});
|
|
20
26
|
if (settings.mode === "off")
|
|
21
27
|
return;
|
|
22
28
|
if (classifyInstall(deps.entryPath, undefined) === "dev")
|
|
23
29
|
return;
|
|
24
30
|
const now = deps.now();
|
|
25
|
-
const state = deps.loadState();
|
|
26
31
|
const notice = startupNotice({
|
|
27
32
|
current: deps.current,
|
|
28
33
|
state,
|