@mnemom/mnemom 0.17.2-next.6 → 0.17.2-next.8
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/agent-doctor.d.ts +1 -1
- package/dist/commands/agent-doctor.js +5 -1
- package/dist/commands/agent-setup.d.ts +34 -3
- package/dist/commands/agent-setup.js +86 -11
- package/dist/commands/agent-slack.d.ts +1 -0
- package/dist/commands/agent-slack.js +33 -4
- package/dist/commands/agent.js +11 -3
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +82 -0
- package/dist/commands/update.d.ts +30 -0
- package/dist/commands/update.js +90 -0
- package/dist/index.js +41 -0
- package/dist/lib/agent.d.ts +13 -7
- package/dist/lib/agent.js +12 -12
- package/dist/lib/cli-config.d.ts +8 -0
- package/dist/lib/cli-config.js +13 -0
- package/dist/lib/slack-channel.d.ts +3 -0
- package/dist/lib/slack-channel.js +78 -5
- package/dist/lib/slack-route.d.ts +5 -0
- package/dist/lib/slack-router.js +28 -2
- package/dist/lib/slack-state.d.ts +8 -0
- package/dist/lib/slack-state.js +11 -0
- package/dist/lib/slack.d.ts +38 -0
- package/dist/lib/slack.js +69 -0
- package/dist/lib/update/action.d.ts +9 -0
- package/dist/lib/update/action.js +17 -0
- package/dist/lib/update/decide.d.ts +152 -0
- package/dist/lib/update/decide.js +195 -0
- package/dist/lib/update/doctor.d.ts +18 -0
- package/dist/lib/update/doctor.js +63 -0
- package/dist/lib/update/install-method.d.ts +12 -0
- package/dist/lib/update/install-method.js +33 -0
- package/dist/lib/update/min-version.d.ts +34 -0
- package/dist/lib/update/min-version.js +69 -0
- package/dist/lib/update/registry.d.ts +27 -0
- package/dist/lib/update/registry.js +50 -0
- package/dist/lib/update/run.d.ts +54 -0
- package/dist/lib/update/run.js +100 -0
- package/dist/lib/update/semver.d.ts +22 -0
- package/dist/lib/update/semver.js +65 -0
- package/dist/lib/update/startup.d.ts +27 -0
- package/dist/lib/update/startup.js +75 -0
- package/dist/lib/update/state.d.ts +23 -0
- package/dist/lib/update/state.js +83 -0
- package/dist/lib/update/system.d.ts +55 -0
- package/dist/lib/update/system.js +104 -0
- package/dist/lib/update/worker.d.ts +42 -0
- package/dist/lib/update/worker.js +104 -0
- package/dist/lib/version-gate.d.ts +2 -1
- package/dist/lib/version-gate.js +9 -1
- package/dist/update-worker.d.ts +6 -0
- package/dist/update-worker.js +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The detached background worker (entry: src/update-worker.ts) and the real
|
|
3
|
+
* `RunDeps` wiring shared with `mnemom update`.
|
|
4
|
+
*
|
|
5
|
+
* The parent passes the settings it resolved (`<entry> <channel> <mode> <pid>`): the
|
|
6
|
+
* worker runs with stdio ignored, so re-resolving here would always see a
|
|
7
|
+
* non-TTY and force `off`.
|
|
8
|
+
*/
|
|
9
|
+
import { CLI_VERSION } from "../../version.js";
|
|
10
|
+
import { getApiUrl } from "../config.js";
|
|
11
|
+
import { isUpdateChannel, isUpdateMode } from "./decide.js";
|
|
12
|
+
import { classifyInstall } from "./install-method.js";
|
|
13
|
+
import { fetchChannelEntitlement, fetchDistTags } from "./registry.js";
|
|
14
|
+
import { runUpdate } from "./run.js";
|
|
15
|
+
import { acquireLock, loadUpdateState, saveUpdateState } from "./state.js";
|
|
16
|
+
import { npmGlobalRoot, npmInstallGlobal } from "./system.js";
|
|
17
|
+
export function parseWorkerArgs(args) {
|
|
18
|
+
const [entry, channel, mode, pid] = args;
|
|
19
|
+
if (!entry || !isUpdateChannel(channel) || !isUpdateMode(mode))
|
|
20
|
+
return null;
|
|
21
|
+
const parentPid = Number.parseInt(pid ?? "", 10);
|
|
22
|
+
return { entry, settings: { channel, mode }, parentPid: parentPid > 0 ? parentPid : undefined };
|
|
23
|
+
}
|
|
24
|
+
export const PARENT_POLL_MS = 5000;
|
|
25
|
+
/** Give up waiting on a very long session; the next run picks the update up. */
|
|
26
|
+
export const PARENT_WAIT_MAX_MS = 12 * 60 * 60 * 1000;
|
|
27
|
+
/** `kill(pid, 0)` probes liveness without signalling. EPERM still means alive. */
|
|
28
|
+
export function isAlive(pid, kill = (p, s) => void process.kill(p, s)) {
|
|
29
|
+
try {
|
|
30
|
+
kill(pid, 0);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return err.code === "EPERM";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Resolve true once `pid` is gone, false if it outlives `maxMs`. */
|
|
38
|
+
export async function waitForExit(pid, deps = {
|
|
39
|
+
alive: (p) => isAlive(p),
|
|
40
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
41
|
+
now: Date.now,
|
|
42
|
+
}, maxMs = PARENT_WAIT_MAX_MS) {
|
|
43
|
+
if (pid === undefined)
|
|
44
|
+
return true;
|
|
45
|
+
const deadline = deps.now() + maxMs;
|
|
46
|
+
while (deps.alive(pid)) {
|
|
47
|
+
if (deps.now() >= deadline)
|
|
48
|
+
return false;
|
|
49
|
+
await deps.sleep(PARENT_POLL_MS);
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
export function realRunDeps(entry, credential) {
|
|
54
|
+
return {
|
|
55
|
+
current: CLI_VERSION,
|
|
56
|
+
now: Date.now,
|
|
57
|
+
loadState: () => loadUpdateState(),
|
|
58
|
+
saveState: (patch) => saveUpdateState(patch),
|
|
59
|
+
fetchDistTags: () => fetchDistTags(fetch),
|
|
60
|
+
fetchEntitlement: async () => fetchChannelEntitlement(fetch, getApiUrl(), await credential()),
|
|
61
|
+
installMethod: async () => classifyInstall(entry, await npmGlobalRoot()),
|
|
62
|
+
install: (version) => npmInstallGlobal(version),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The install lock is held ONLY around `npm install` — never while waiting for
|
|
67
|
+
* the parent to exit (a 12h wait would look stale at LOCK_STALE_MS and let a
|
|
68
|
+
* second installer in). Lock busy → skip this pass; the other installer wins.
|
|
69
|
+
*/
|
|
70
|
+
export function lockedInstall(parentPid, deps) {
|
|
71
|
+
let release = null;
|
|
72
|
+
return {
|
|
73
|
+
beforeInstall: async () => {
|
|
74
|
+
if (!(await deps.waitForExit(parentPid)))
|
|
75
|
+
return false;
|
|
76
|
+
release = deps.acquireLock();
|
|
77
|
+
return release !== null;
|
|
78
|
+
},
|
|
79
|
+
install: async (version) => {
|
|
80
|
+
try {
|
|
81
|
+
return await deps.install(version);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
release?.();
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export async function runWorker(args, run) {
|
|
90
|
+
const parsed = parseWorkerArgs(args);
|
|
91
|
+
if (!parsed)
|
|
92
|
+
return "bad-args";
|
|
93
|
+
return run(parsed);
|
|
94
|
+
}
|
|
95
|
+
export function defaultWorkerRun(credential) {
|
|
96
|
+
return ({ entry, settings, parentPid }) => runUpdate({
|
|
97
|
+
...realRunDeps(entry, credential),
|
|
98
|
+
...lockedInstall(parentPid, {
|
|
99
|
+
waitForExit: (pid) => waitForExit(pid),
|
|
100
|
+
acquireLock: () => acquireLock(),
|
|
101
|
+
install: (version) => npmInstallGlobal(version),
|
|
102
|
+
}),
|
|
103
|
+
}, settings);
|
|
104
|
+
}
|
|
@@ -28,8 +28,9 @@ export declare function isBelowVersion(current: string, floor: string): boolean;
|
|
|
28
28
|
*
|
|
29
29
|
* @param exit injectable for tests; defaults to process.exit
|
|
30
30
|
* @param write injectable for tests; defaults to process.stderr.write
|
|
31
|
+
* @param upgrade injectable for tests; defaults to the auto-update floor upgrade
|
|
31
32
|
*/
|
|
32
|
-
export declare function enforceMinCliVersion(response: Pick<Response, "headers">, exit?: (code: number) => never, write?: (chunk: string) => void): void;
|
|
33
|
+
export declare function enforceMinCliVersion(response: Pick<Response, "headers">, exit?: (code: number) => never, write?: (chunk: string) => void, upgrade?: (floor: string) => boolean): void;
|
|
33
34
|
/**
|
|
34
35
|
* Drop-in wrapper around global fetch for Mnemom API calls: issues the request,
|
|
35
36
|
* enforces the advertised minimum CLI version on the response, then returns it.
|
package/dist/lib/version-gate.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* wrong outcome.
|
|
15
15
|
*/
|
|
16
16
|
import { CLI_VERSION } from "../version.js";
|
|
17
|
+
import { defaultFloorUpgradeDeps, upgradeToFloor } from "./update/min-version.js";
|
|
17
18
|
const MIN_CLI_HEADER = "x-mnemom-min-cli";
|
|
18
19
|
/**
|
|
19
20
|
* Compare dotted numeric versions. Returns true iff `current` is strictly below
|
|
@@ -53,8 +54,9 @@ let exited = false;
|
|
|
53
54
|
*
|
|
54
55
|
* @param exit injectable for tests; defaults to process.exit
|
|
55
56
|
* @param write injectable for tests; defaults to process.stderr.write
|
|
57
|
+
* @param upgrade injectable for tests; defaults to the auto-update floor upgrade
|
|
56
58
|
*/
|
|
57
|
-
export function enforceMinCliVersion(response, exit = process.exit, write = (chunk) => void process.stderr.write(chunk)) {
|
|
59
|
+
export function enforceMinCliVersion(response, exit = process.exit, write = (chunk) => void process.stderr.write(chunk), upgrade = (floor) => upgradeToFloor(floor, defaultFloorUpgradeDeps())) {
|
|
58
60
|
// Defensive: some callers/tests provide a Response-like object without a real
|
|
59
61
|
// Headers instance. Treat a missing/incompatible headers bag as "no floor".
|
|
60
62
|
const headers = response?.headers;
|
|
@@ -66,6 +68,12 @@ export function enforceMinCliVersion(response, exit = process.exit, write = (chu
|
|
|
66
68
|
if (exited)
|
|
67
69
|
return;
|
|
68
70
|
exited = true;
|
|
71
|
+
// Auto-update on + self-updatable install: fix it now, then ask for a re-run
|
|
72
|
+
// (this process is still the old code).
|
|
73
|
+
if (upgrade(floor)) {
|
|
74
|
+
write(`\n✓ Updated the Mnemom CLI (was v${CLI_VERSION}; server minimum v${floor}). Re-run your command.\n\n`);
|
|
75
|
+
exit(1);
|
|
76
|
+
}
|
|
69
77
|
write(`\n✖ Your Mnemom CLI (v${CLI_VERSION}) is too old for this server (minimum v${floor}).\n` +
|
|
70
78
|
` Old CLIs can silently drop newer request fields — e.g. \`--org\` on \`mnemom agent claim\`.\n\n` +
|
|
71
79
|
` Upgrade: npm i -g @mnemom/mnemom@latest\n\n`);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detached auto-update worker — spawned by lib/update/startup.ts with
|
|
3
|
+
* `<entry> <channel> <mode> <parent-pid>`. All logic lives in lib/update/worker.ts; this
|
|
4
|
+
* driver only wires the real process in and swallows every error.
|
|
5
|
+
*/
|
|
6
|
+
import { backgroundCredential } from "./lib/update/system.js";
|
|
7
|
+
import { defaultWorkerRun, runWorker } from "./lib/update/worker.js";
|
|
8
|
+
runWorker(process.argv.slice(2), defaultWorkerRun(() => backgroundCredential())).catch(() => { });
|