@mneme-ai/core 2.19.60 → 2.19.62
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/cosmic/aurelian_v1961.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1961.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1961.test.js +62 -0
- package/dist/cosmic/aurelian_v1961.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1962.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1962.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1962.test.js +62 -0
- package/dist/cosmic/aurelian_v1962.test.js.map +1 -0
- package/dist/dll_eviction/dll_eviction.test.d.ts +14 -0
- package/dist/dll_eviction/dll_eviction.test.d.ts.map +1 -0
- package/dist/dll_eviction/dll_eviction.test.js +181 -0
- package/dist/dll_eviction/dll_eviction.test.js.map +1 -0
- package/dist/dll_eviction/index.d.ts +147 -0
- package/dist/dll_eviction/index.d.ts.map +1 -0
- package/dist/dll_eviction/index.js +288 -0
- package/dist/dll_eviction/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/nucleus_daemon.d.ts.map +1 -1
- package/dist/nucleus_daemon.js +52 -0
- package/dist/nucleus_daemon.js.map +1 -1
- package/dist/phoenix/dll_extraction.d.ts +97 -0
- package/dist/phoenix/dll_extraction.d.ts.map +1 -0
- package/dist/phoenix/dll_extraction.js +286 -0
- package/dist/phoenix/dll_extraction.js.map +1 -0
- package/dist/phoenix/dll_extraction.test.d.ts +10 -0
- package/dist/phoenix/dll_extraction.test.d.ts.map +1 -0
- package/dist/phoenix/dll_extraction.test.js +216 -0
- package/dist/phoenix/dll_extraction.test.js.map +1 -0
- package/dist/phoenix/index.d.ts +15 -0
- package/dist/phoenix/index.d.ts.map +1 -0
- package/dist/phoenix/index.js +15 -0
- package/dist/phoenix/index.js.map +1 -0
- package/dist/phoenix/organs.d.ts +110 -0
- package/dist/phoenix/organs.d.ts.map +1 -0
- package/dist/phoenix/organs.js +154 -0
- package/dist/phoenix/organs.js.map +1 -0
- package/dist/phoenix/organs.test.d.ts +9 -0
- package/dist/phoenix/organs.test.d.ts.map +1 -0
- package/dist/phoenix/organs.test.js +189 -0
- package/dist/phoenix/organs.test.js.map +1 -0
- package/dist/phoenix/scout.d.ts +74 -0
- package/dist/phoenix/scout.d.ts.map +1 -0
- package/dist/phoenix/scout.js +163 -0
- package/dist/phoenix/scout.js.map +1 -0
- package/dist/phoenix/scout.test.d.ts +8 -0
- package/dist/phoenix/scout.test.d.ts.map +1 -0
- package/dist/phoenix/scout.test.js +163 -0
- package/dist/phoenix/scout.test.js.map +1 -0
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +67 -51
- package/dist/whats_new.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.62 PHOENIX P5 — 3 priority-1 organs deep tests.
|
|
3
|
+
*
|
|
4
|
+
* Custodian / Sentinel / Surgeon — each is a pure function returning a
|
|
5
|
+
* verdict. Tests cover: shape of reports, threshold semantics, idempotence,
|
|
6
|
+
* composability via runAllOrgans.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect } from "vitest";
|
|
9
|
+
import { runCustodianCycle, runSentinelCycle, runSurgeonCycle, runAllOrgans, PROTOCOL_VERSION, } from "./organs.js";
|
|
10
|
+
describe("v2.19.62 organs PROTOCOL_VERSION", () => {
|
|
11
|
+
it("is 1", () => {
|
|
12
|
+
expect(PROTOCOL_VERSION).toBe(1);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe("v2.19.62 Custodian organ", () => {
|
|
16
|
+
it("returns structured CustodianReport", () => {
|
|
17
|
+
const r = runCustodianCycle();
|
|
18
|
+
expect(r.v).toBe(1);
|
|
19
|
+
expect(r.organ).toBe("custodian");
|
|
20
|
+
expect(typeof r.ts).toBe("string");
|
|
21
|
+
expect(r.tmpDirsSwept).toBeGreaterThanOrEqual(0);
|
|
22
|
+
expect(r.tmpBytesReclaimed).toBeGreaterThanOrEqual(0);
|
|
23
|
+
expect(r.globalOrphansSwept).toBeGreaterThanOrEqual(0);
|
|
24
|
+
expect(r.totalReclaimedBytes).toBeGreaterThanOrEqual(0);
|
|
25
|
+
expect(r.durationMs).toBeGreaterThanOrEqual(0);
|
|
26
|
+
});
|
|
27
|
+
it("never throws on missing ~/.mneme-global", () => {
|
|
28
|
+
expect(() => runCustodianCycle()).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
it("idempotent — second cycle finds nothing new", () => {
|
|
31
|
+
const r1 = runCustodianCycle();
|
|
32
|
+
const r2 = runCustodianCycle();
|
|
33
|
+
expect(r2.tmpDirsSwept).toBeLessThanOrEqual(r1.tmpDirsSwept + 5); // best-effort
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("v2.19.62 Sentinel organ", () => {
|
|
37
|
+
it("returns healthy when no opts provided", () => {
|
|
38
|
+
const r = runSentinelCycle();
|
|
39
|
+
expect(r.organ).toBe("sentinel");
|
|
40
|
+
expect(r.hmacChainOk).toBe(true);
|
|
41
|
+
expect(r.handleCount).toBe(-1); // No counter injected
|
|
42
|
+
expect(r.handleBaseline).toBe(50);
|
|
43
|
+
expect(r.handleLeakDetected).toBe(false);
|
|
44
|
+
expect(r.recommendation).toBe("healthy");
|
|
45
|
+
});
|
|
46
|
+
it("detects handle leak when count > baseline×2", () => {
|
|
47
|
+
const r = runSentinelCycle({ handleCounter: () => 200, handleBaseline: 50 });
|
|
48
|
+
expect(r.handleCount).toBe(200);
|
|
49
|
+
expect(r.handleLeakDetected).toBe(true);
|
|
50
|
+
expect(r.recommendation).toBe("warn-handle-leak");
|
|
51
|
+
});
|
|
52
|
+
it("does NOT flag leak when count == baseline×2 (strict >)", () => {
|
|
53
|
+
const r = runSentinelCycle({ handleCounter: () => 100, handleBaseline: 50 });
|
|
54
|
+
expect(r.handleLeakDetected).toBe(false);
|
|
55
|
+
expect(r.recommendation).toBe("healthy");
|
|
56
|
+
});
|
|
57
|
+
it("escalates to critical when HMAC chain broken", () => {
|
|
58
|
+
const r = runSentinelCycle({
|
|
59
|
+
verifyHmacChain: () => ({ ok: false, brokenAt: 42 }),
|
|
60
|
+
});
|
|
61
|
+
expect(r.hmacChainOk).toBe(false);
|
|
62
|
+
expect(r.hmacChainBrokenAt).toBe(42);
|
|
63
|
+
expect(r.recommendation).toBe("critical-chain-broken");
|
|
64
|
+
});
|
|
65
|
+
it("critical chain-broken takes precedence over handle leak", () => {
|
|
66
|
+
const r = runSentinelCycle({
|
|
67
|
+
handleCounter: () => 500,
|
|
68
|
+
handleBaseline: 50,
|
|
69
|
+
verifyHmacChain: () => ({ ok: false }),
|
|
70
|
+
});
|
|
71
|
+
expect(r.recommendation).toBe("critical-chain-broken");
|
|
72
|
+
});
|
|
73
|
+
it("custom baseline respected", () => {
|
|
74
|
+
const r = runSentinelCycle({ handleCounter: () => 250, handleBaseline: 200 });
|
|
75
|
+
expect(r.handleBaseline).toBe(200);
|
|
76
|
+
// 250 not > 200×2=400, so no leak
|
|
77
|
+
expect(r.handleLeakDetected).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("v2.19.62 Surgeon organ", () => {
|
|
81
|
+
it("returns empty restart list when all healthy", () => {
|
|
82
|
+
const stats = [
|
|
83
|
+
{ name: "indexer", p99Ms: 100, baselineMs: 90 },
|
|
84
|
+
{ name: "embedder", p99Ms: 50, baselineMs: 40 },
|
|
85
|
+
];
|
|
86
|
+
const r = runSurgeonCycle(stats);
|
|
87
|
+
expect(r.organsExamined).toBe(2);
|
|
88
|
+
expect(r.organsToRestart).toEqual([]);
|
|
89
|
+
});
|
|
90
|
+
it("flags organ with 3× p99 degradation", () => {
|
|
91
|
+
const stats = [
|
|
92
|
+
{ name: "indexer", p99Ms: 3000, baselineMs: 1000 },
|
|
93
|
+
];
|
|
94
|
+
const r = runSurgeonCycle(stats);
|
|
95
|
+
expect(r.organsToRestart.length).toBe(1);
|
|
96
|
+
expect(r.organsToRestart[0].name).toBe("indexer");
|
|
97
|
+
expect(r.organsToRestart[0].degradationFactor).toBeCloseTo(3, 1);
|
|
98
|
+
});
|
|
99
|
+
it("does NOT flag organ at 2.9× degradation (under threshold)", () => {
|
|
100
|
+
const stats = [
|
|
101
|
+
{ name: "borderline", p99Ms: 2900, baselineMs: 1000 },
|
|
102
|
+
];
|
|
103
|
+
const r = runSurgeonCycle(stats);
|
|
104
|
+
expect(r.organsToRestart.length).toBe(0);
|
|
105
|
+
});
|
|
106
|
+
it("custom degradationFactor respected", () => {
|
|
107
|
+
const stats = [
|
|
108
|
+
{ name: "loose-threshold", p99Ms: 1500, baselineMs: 1000 },
|
|
109
|
+
];
|
|
110
|
+
const r = runSurgeonCycle(stats, { degradationFactor: 1.4 });
|
|
111
|
+
expect(r.organsToRestart.length).toBe(1);
|
|
112
|
+
});
|
|
113
|
+
it("flags organ on consecutive failures even when latency healthy", () => {
|
|
114
|
+
const stats = [
|
|
115
|
+
{ name: "flaky", p99Ms: 100, baselineMs: 90, consecutiveFailures: 5 },
|
|
116
|
+
];
|
|
117
|
+
const r = runSurgeonCycle(stats);
|
|
118
|
+
expect(r.organsToRestart.length).toBe(1);
|
|
119
|
+
expect(r.organsToRestart[0].reason).toContain("consecutive failures");
|
|
120
|
+
});
|
|
121
|
+
it("custom maxConsecutiveFailures respected", () => {
|
|
122
|
+
const stats = [
|
|
123
|
+
{ name: "borderline-flake", p99Ms: 100, baselineMs: 90, consecutiveFailures: 2 },
|
|
124
|
+
];
|
|
125
|
+
const r1 = runSurgeonCycle(stats);
|
|
126
|
+
expect(r1.organsToRestart.length).toBe(0); // default 3
|
|
127
|
+
const r2 = runSurgeonCycle(stats, { maxConsecutiveFailures: 2 });
|
|
128
|
+
expect(r2.organsToRestart.length).toBe(1);
|
|
129
|
+
});
|
|
130
|
+
it("avoids divide-by-zero when baseline=0", () => {
|
|
131
|
+
const stats = [
|
|
132
|
+
{ name: "no-baseline", p99Ms: 10000, baselineMs: 0 },
|
|
133
|
+
];
|
|
134
|
+
expect(() => runSurgeonCycle(stats)).not.toThrow();
|
|
135
|
+
const r = runSurgeonCycle(stats);
|
|
136
|
+
// baseline=0 short-circuits the ratio check to 0, no restart unless failures hit
|
|
137
|
+
expect(r.organsToRestart.length).toBe(0);
|
|
138
|
+
});
|
|
139
|
+
it("handles empty stats array", () => {
|
|
140
|
+
const r = runSurgeonCycle([]);
|
|
141
|
+
expect(r.organsExamined).toBe(0);
|
|
142
|
+
expect(r.organsToRestart).toEqual([]);
|
|
143
|
+
});
|
|
144
|
+
it("reports include precise reason string", () => {
|
|
145
|
+
const stats = [
|
|
146
|
+
{ name: "slow", p99Ms: 5000, baselineMs: 1000 },
|
|
147
|
+
];
|
|
148
|
+
const r = runSurgeonCycle(stats);
|
|
149
|
+
expect(r.organsToRestart[0].reason).toContain("5000ms");
|
|
150
|
+
expect(r.organsToRestart[0].reason).toContain("1000ms");
|
|
151
|
+
expect(r.organsToRestart[0].reason).toContain("5.0x");
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe("v2.19.62 runAllOrgans composed cycle", () => {
|
|
155
|
+
it("returns all 3 reports in one call", () => {
|
|
156
|
+
const r = runAllOrgans();
|
|
157
|
+
expect(r.custodian.organ).toBe("custodian");
|
|
158
|
+
expect(r.sentinel.organ).toBe("sentinel");
|
|
159
|
+
expect(r.surgeon.organ).toBe("surgeon");
|
|
160
|
+
expect(r.durationMs).toBeGreaterThanOrEqual(0);
|
|
161
|
+
});
|
|
162
|
+
it("passes through Sentinel options", () => {
|
|
163
|
+
const r = runAllOrgans({
|
|
164
|
+
sentinel: { handleCounter: () => 999, handleBaseline: 10 },
|
|
165
|
+
});
|
|
166
|
+
expect(r.sentinel.handleCount).toBe(999);
|
|
167
|
+
expect(r.sentinel.handleLeakDetected).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
it("passes through Surgeon stats", () => {
|
|
170
|
+
const r = runAllOrgans({
|
|
171
|
+
surgeonStats: [{ name: "x", p99Ms: 10000, baselineMs: 1000 }],
|
|
172
|
+
});
|
|
173
|
+
expect(r.surgeon.organsExamined).toBe(1);
|
|
174
|
+
expect(r.surgeon.organsToRestart.length).toBe(1);
|
|
175
|
+
});
|
|
176
|
+
it("composed duration is sum-or-less of individual organs", () => {
|
|
177
|
+
const r = runAllOrgans();
|
|
178
|
+
expect(r.durationMs).toBeGreaterThanOrEqual(0);
|
|
179
|
+
// Each sub-organ duration should be ≤ total
|
|
180
|
+
expect(r.custodian.durationMs).toBeLessThanOrEqual(r.durationMs + 10);
|
|
181
|
+
expect(r.sentinel.durationMs).toBeLessThanOrEqual(r.durationMs + 10);
|
|
182
|
+
expect(r.surgeon.durationMs).toBeLessThanOrEqual(r.durationMs + 10);
|
|
183
|
+
});
|
|
184
|
+
it("never throws on bad input", () => {
|
|
185
|
+
expect(() => runAllOrgans({ surgeonStats: [] })).not.toThrow();
|
|
186
|
+
expect(() => runAllOrgans({ sentinel: {} })).not.toThrow();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=organs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organs.test.js","sourceRoot":"","sources":["../../src/phoenix/organs.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.62 PHOENIX PHASE 1 — SCOUT (P4 step 1: passive npm registry probe).
|
|
3
|
+
*
|
|
4
|
+
* The first step of the PHOENIX Auto-Upgrade Protocol. Scout's only job is
|
|
5
|
+
* to passively observe the npm registry — never to spawn npm install, never
|
|
6
|
+
* to mutate the filesystem, never to interrupt the daemon. Read-only by
|
|
7
|
+
* design so it can run on every daemon tick without amplifying load.
|
|
8
|
+
*
|
|
9
|
+
* Behavior:
|
|
10
|
+
* 1. Hit https://registry.npmjs.org/mneme-ai/latest (HTTP HEAD-or-GET)
|
|
11
|
+
* 2. Compare returned `version` to the running version (passed by caller)
|
|
12
|
+
* 3. Cache result for `cacheTtlMs` (default 5min) so repeated calls don't
|
|
13
|
+
* hammer the registry
|
|
14
|
+
* 4. Return verdict: up-to-date | upgrade-available | unreachable
|
|
15
|
+
*
|
|
16
|
+
* Pure observation. Caller (daemon or PHOENIX Queen in Phase 2) decides
|
|
17
|
+
* what to do with the verdict — start a cocoon, push an inbox alert, or
|
|
18
|
+
* sit on the data until conditions are right.
|
|
19
|
+
*
|
|
20
|
+
* Cache is in-memory only. Persistent state (last-checked timestamp,
|
|
21
|
+
* upgrade history) belongs in the daemon's heartbeat ledger, not here.
|
|
22
|
+
*
|
|
23
|
+
* Network-failure semantics: ALL failures return `unreachable` — never
|
|
24
|
+
* throw. The daemon must remain alive even when offline.
|
|
25
|
+
*/
|
|
26
|
+
declare const PROTOCOL_VERSION = 1;
|
|
27
|
+
export type ScoutVerdict = "up-to-date" | "upgrade-available" | "unreachable";
|
|
28
|
+
export interface ScoutReport {
|
|
29
|
+
v: typeof PROTOCOL_VERSION;
|
|
30
|
+
organ: "scout";
|
|
31
|
+
ts: string;
|
|
32
|
+
verdict: ScoutVerdict;
|
|
33
|
+
packageName: string;
|
|
34
|
+
runningVersion: string;
|
|
35
|
+
latestVersion: string | null;
|
|
36
|
+
cacheHit: boolean;
|
|
37
|
+
cacheAgeMs: number;
|
|
38
|
+
durationMs: number;
|
|
39
|
+
reachability: {
|
|
40
|
+
registry: string;
|
|
41
|
+
httpStatus?: number;
|
|
42
|
+
error?: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export interface ScoutOptions {
|
|
46
|
+
packageName?: string;
|
|
47
|
+
registry?: string;
|
|
48
|
+
cacheTtlMs?: number;
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
/** Inject a fetcher for tests. Should return the parsed registry response
|
|
51
|
+
* ({version: "x.y.z", ...}) or throw on failure. */
|
|
52
|
+
fetchLatest?: (registry: string, packageName: string, timeoutMs: number) => Promise<{
|
|
53
|
+
version: string;
|
|
54
|
+
httpStatus?: number;
|
|
55
|
+
}>;
|
|
56
|
+
/** Optional explicit clock for tests (ms since epoch). */
|
|
57
|
+
now?: () => number;
|
|
58
|
+
}
|
|
59
|
+
/** Compare two semver-ish strings. Returns positive when `a > b`, 0 when
|
|
60
|
+
* equal, negative when `a < b`. Strips leading "v" and any pre-release
|
|
61
|
+
* suffix after the first hyphen. Safe-default — non-numeric segments
|
|
62
|
+
* compared as 0. */
|
|
63
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
64
|
+
/** Probe the npm registry for the latest version of a package. Returns a
|
|
65
|
+
* structured verdict. Never throws — failures become `unreachable` so the
|
|
66
|
+
* daemon loop is undisturbed. */
|
|
67
|
+
export declare function runScoutCycle(runningVersion: string, opts?: ScoutOptions): Promise<ScoutReport>;
|
|
68
|
+
/** Clear Scout's in-memory cache. Used by tests + after a successful
|
|
69
|
+
* upgrade so the next probe sees fresh state. */
|
|
70
|
+
export declare function clearScoutCache(): void;
|
|
71
|
+
/** Inspect current cache size (testing/debug). */
|
|
72
|
+
export declare function scoutCacheSize(): number;
|
|
73
|
+
export { PROTOCOL_VERSION };
|
|
74
|
+
//# sourceMappingURL=scout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scout.d.ts","sourceRoot":"","sources":["../../src/phoenix/scout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,QAAA,MAAM,gBAAgB,IAAI,CAAC;AAM3B,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,mBAAmB,GACnB,aAAa,CAAC;AAElB,MAAM,WAAW,WAAW;IAC1B,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;yDACqD;IACrD,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9H,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAYD;;;qBAGqB;AACrB,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAW5D;AAuCD;;kCAEkC;AAClC,wBAAsB,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAwDrG;AAED;kDACkD;AAClD,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,kDAAkD;AAClD,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.62 PHOENIX PHASE 1 — SCOUT (P4 step 1: passive npm registry probe).
|
|
3
|
+
*
|
|
4
|
+
* The first step of the PHOENIX Auto-Upgrade Protocol. Scout's only job is
|
|
5
|
+
* to passively observe the npm registry — never to spawn npm install, never
|
|
6
|
+
* to mutate the filesystem, never to interrupt the daemon. Read-only by
|
|
7
|
+
* design so it can run on every daemon tick without amplifying load.
|
|
8
|
+
*
|
|
9
|
+
* Behavior:
|
|
10
|
+
* 1. Hit https://registry.npmjs.org/mneme-ai/latest (HTTP HEAD-or-GET)
|
|
11
|
+
* 2. Compare returned `version` to the running version (passed by caller)
|
|
12
|
+
* 3. Cache result for `cacheTtlMs` (default 5min) so repeated calls don't
|
|
13
|
+
* hammer the registry
|
|
14
|
+
* 4. Return verdict: up-to-date | upgrade-available | unreachable
|
|
15
|
+
*
|
|
16
|
+
* Pure observation. Caller (daemon or PHOENIX Queen in Phase 2) decides
|
|
17
|
+
* what to do with the verdict — start a cocoon, push an inbox alert, or
|
|
18
|
+
* sit on the data until conditions are right.
|
|
19
|
+
*
|
|
20
|
+
* Cache is in-memory only. Persistent state (last-checked timestamp,
|
|
21
|
+
* upgrade history) belongs in the daemon's heartbeat ledger, not here.
|
|
22
|
+
*
|
|
23
|
+
* Network-failure semantics: ALL failures return `unreachable` — never
|
|
24
|
+
* throw. The daemon must remain alive even when offline.
|
|
25
|
+
*/
|
|
26
|
+
import { request } from "node:https";
|
|
27
|
+
import { request as httpRequest } from "node:http";
|
|
28
|
+
const PROTOCOL_VERSION = 1;
|
|
29
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 min
|
|
30
|
+
const DEFAULT_TIMEOUT_MS = 8_000;
|
|
31
|
+
const DEFAULT_PACKAGE = "mneme-ai";
|
|
32
|
+
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
33
|
+
// Per-package cache. Cleared on process exit.
|
|
34
|
+
const cache = new Map();
|
|
35
|
+
/** Compare two semver-ish strings. Returns positive when `a > b`, 0 when
|
|
36
|
+
* equal, negative when `a < b`. Strips leading "v" and any pre-release
|
|
37
|
+
* suffix after the first hyphen. Safe-default — non-numeric segments
|
|
38
|
+
* compared as 0. */
|
|
39
|
+
export function compareVersions(a, b) {
|
|
40
|
+
const norm = (s) => s.replace(/^v/i, "").split("-")[0] ?? "0";
|
|
41
|
+
const partsA = norm(a).split(".").map((x) => parseInt(x, 10) || 0);
|
|
42
|
+
const partsB = norm(b).split(".").map((x) => parseInt(x, 10) || 0);
|
|
43
|
+
const len = Math.max(partsA.length, partsB.length);
|
|
44
|
+
for (let i = 0; i < len; i++) {
|
|
45
|
+
const ai = partsA[i] ?? 0;
|
|
46
|
+
const bi = partsB[i] ?? 0;
|
|
47
|
+
if (ai !== bi)
|
|
48
|
+
return ai - bi;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
/** Default fetcher — node:https GET against `${registry}/${pkg}/latest`.
|
|
53
|
+
* Times out after `timeoutMs`. Throws on any failure (caller wraps). */
|
|
54
|
+
async function defaultFetcher(registry, packageName, timeoutMs) {
|
|
55
|
+
const url = `${registry.replace(/\/$/, "")}/${encodeURIComponent(packageName)}/latest`;
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const reqFn = url.startsWith("https://") ? request : httpRequest;
|
|
58
|
+
const req = reqFn(url, { method: "GET", headers: { accept: "application/json", "user-agent": `mneme-phoenix-scout/${PROTOCOL_VERSION}` } }, (res) => {
|
|
59
|
+
const chunks = [];
|
|
60
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
61
|
+
res.on("end", () => {
|
|
62
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
63
|
+
const status = res.statusCode ?? 0;
|
|
64
|
+
if (status >= 400) {
|
|
65
|
+
reject(Object.assign(new Error(`registry HTTP ${status}`), { httpStatus: status }));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(body);
|
|
70
|
+
const version = typeof parsed?.version === "string" ? parsed.version : null;
|
|
71
|
+
if (!version) {
|
|
72
|
+
reject(new Error("registry response missing version"));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
resolve({ version, httpStatus: status });
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
reject(new Error(`registry response parse failed: ${e.message}`));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
req.on("error", reject);
|
|
83
|
+
req.setTimeout(timeoutMs, () => {
|
|
84
|
+
req.destroy(new Error(`registry request timeout after ${timeoutMs}ms`));
|
|
85
|
+
});
|
|
86
|
+
req.end();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Probe the npm registry for the latest version of a package. Returns a
|
|
90
|
+
* structured verdict. Never throws — failures become `unreachable` so the
|
|
91
|
+
* daemon loop is undisturbed. */
|
|
92
|
+
export async function runScoutCycle(runningVersion, opts) {
|
|
93
|
+
const t0 = Date.now();
|
|
94
|
+
const packageName = opts?.packageName ?? DEFAULT_PACKAGE;
|
|
95
|
+
const registry = opts?.registry ?? DEFAULT_REGISTRY;
|
|
96
|
+
const cacheTtlMs = opts?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
97
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
98
|
+
const fetcher = opts?.fetchLatest ?? defaultFetcher;
|
|
99
|
+
const now = opts?.now ?? Date.now;
|
|
100
|
+
const cacheKey = `${registry}::${packageName}`;
|
|
101
|
+
const cached = cache.get(cacheKey);
|
|
102
|
+
const ageMs = cached ? now() - cached.fetchedAt : Infinity;
|
|
103
|
+
let entry;
|
|
104
|
+
let cacheHit = false;
|
|
105
|
+
if (cached && ageMs < cacheTtlMs) {
|
|
106
|
+
entry = cached;
|
|
107
|
+
cacheHit = true;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
try {
|
|
111
|
+
const result = await fetcher(registry, packageName, timeoutMs);
|
|
112
|
+
entry = { fetchedAt: now(), latestVersion: result.version, httpStatus: result.httpStatus };
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
const err = (e ?? {});
|
|
116
|
+
entry = {
|
|
117
|
+
fetchedAt: now(),
|
|
118
|
+
latestVersion: null,
|
|
119
|
+
...(typeof err.httpStatus === "number" ? { httpStatus: err.httpStatus } : {}),
|
|
120
|
+
error: typeof err.message === "string" ? err.message : String(e),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
cache.set(cacheKey, entry);
|
|
124
|
+
}
|
|
125
|
+
let verdict;
|
|
126
|
+
if (entry.latestVersion === null) {
|
|
127
|
+
verdict = "unreachable";
|
|
128
|
+
}
|
|
129
|
+
else if (compareVersions(entry.latestVersion, runningVersion) > 0) {
|
|
130
|
+
verdict = "upgrade-available";
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
verdict = "up-to-date";
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
v: PROTOCOL_VERSION,
|
|
137
|
+
organ: "scout",
|
|
138
|
+
ts: new Date().toISOString(),
|
|
139
|
+
verdict,
|
|
140
|
+
packageName,
|
|
141
|
+
runningVersion,
|
|
142
|
+
latestVersion: entry.latestVersion,
|
|
143
|
+
cacheHit,
|
|
144
|
+
cacheAgeMs: cacheHit ? ageMs : 0,
|
|
145
|
+
durationMs: Date.now() - t0,
|
|
146
|
+
reachability: {
|
|
147
|
+
registry,
|
|
148
|
+
...(entry.httpStatus !== undefined ? { httpStatus: entry.httpStatus } : {}),
|
|
149
|
+
...(entry.error !== undefined ? { error: entry.error } : {}),
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Clear Scout's in-memory cache. Used by tests + after a successful
|
|
154
|
+
* upgrade so the next probe sees fresh state. */
|
|
155
|
+
export function clearScoutCache() {
|
|
156
|
+
cache.clear();
|
|
157
|
+
}
|
|
158
|
+
/** Inspect current cache size (testing/debug). */
|
|
159
|
+
export function scoutCacheSize() {
|
|
160
|
+
return cache.size;
|
|
161
|
+
}
|
|
162
|
+
export { PROTOCOL_VERSION };
|
|
163
|
+
//# sourceMappingURL=scout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scout.js","sourceRoot":"","sources":["../../src/phoenix/scout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.62 PHOENIX P4 step 1 — SCOUT deep tests.
|
|
3
|
+
*
|
|
4
|
+
* Network-free: we inject a fake fetcher so we test the verdict logic +
|
|
5
|
+
* cache behavior + safe-default unreachable semantics deterministically.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=scout.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scout.test.d.ts","sourceRoot":"","sources":["../../src/phoenix/scout.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.62 PHOENIX P4 step 1 — SCOUT deep tests.
|
|
3
|
+
*
|
|
4
|
+
* Network-free: we inject a fake fetcher so we test the verdict logic +
|
|
5
|
+
* cache behavior + safe-default unreachable semantics deterministically.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
8
|
+
import { runScoutCycle, compareVersions, clearScoutCache, scoutCacheSize, PROTOCOL_VERSION, } from "./scout.js";
|
|
9
|
+
describe("v2.19.62 compareVersions", () => {
|
|
10
|
+
it("returns 0 for equal versions", () => {
|
|
11
|
+
expect(compareVersions("1.2.3", "1.2.3")).toBe(0);
|
|
12
|
+
});
|
|
13
|
+
it("returns positive when a > b", () => {
|
|
14
|
+
expect(compareVersions("2.0.0", "1.99.99")).toBeGreaterThan(0);
|
|
15
|
+
expect(compareVersions("1.2.3", "1.2.2")).toBeGreaterThan(0);
|
|
16
|
+
});
|
|
17
|
+
it("returns negative when a < b", () => {
|
|
18
|
+
expect(compareVersions("1.2.3", "1.2.4")).toBeLessThan(0);
|
|
19
|
+
expect(compareVersions("0.9.99", "1.0.0")).toBeLessThan(0);
|
|
20
|
+
});
|
|
21
|
+
it("strips leading v prefix", () => {
|
|
22
|
+
expect(compareVersions("v1.2.3", "1.2.3")).toBe(0);
|
|
23
|
+
});
|
|
24
|
+
it("strips pre-release suffix", () => {
|
|
25
|
+
expect(compareVersions("1.2.3-alpha", "1.2.3")).toBe(0);
|
|
26
|
+
});
|
|
27
|
+
it("handles missing patch level", () => {
|
|
28
|
+
expect(compareVersions("1.2", "1.2.0")).toBe(0);
|
|
29
|
+
expect(compareVersions("1.3", "1.2.99")).toBeGreaterThan(0);
|
|
30
|
+
});
|
|
31
|
+
it("handles non-numeric segments as 0", () => {
|
|
32
|
+
expect(compareVersions("1.x.0", "1.0.0")).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
it("handles real Mneme version progressions", () => {
|
|
35
|
+
expect(compareVersions("2.19.62", "2.19.61")).toBeGreaterThan(0);
|
|
36
|
+
expect(compareVersions("2.19.61", "2.19.62")).toBeLessThan(0);
|
|
37
|
+
expect(compareVersions("2.19.62", "2.19.62")).toBe(0);
|
|
38
|
+
expect(compareVersions("3.0.0", "2.19.62")).toBeGreaterThan(0);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe("v2.19.62 runScoutCycle verdicts", () => {
|
|
42
|
+
beforeEach(() => clearScoutCache());
|
|
43
|
+
it("returns up-to-date when running == latest", async () => {
|
|
44
|
+
const r = await runScoutCycle("2.19.62", {
|
|
45
|
+
fetchLatest: async () => ({ version: "2.19.62", httpStatus: 200 }),
|
|
46
|
+
});
|
|
47
|
+
expect(r.verdict).toBe("up-to-date");
|
|
48
|
+
expect(r.latestVersion).toBe("2.19.62");
|
|
49
|
+
expect(r.runningVersion).toBe("2.19.62");
|
|
50
|
+
});
|
|
51
|
+
it("returns upgrade-available when running < latest", async () => {
|
|
52
|
+
const r = await runScoutCycle("2.19.61", {
|
|
53
|
+
fetchLatest: async () => ({ version: "2.19.62", httpStatus: 200 }),
|
|
54
|
+
});
|
|
55
|
+
expect(r.verdict).toBe("upgrade-available");
|
|
56
|
+
expect(r.latestVersion).toBe("2.19.62");
|
|
57
|
+
});
|
|
58
|
+
it("returns up-to-date when running > latest (running ahead)", async () => {
|
|
59
|
+
const r = await runScoutCycle("3.0.0", {
|
|
60
|
+
fetchLatest: async () => ({ version: "2.19.62", httpStatus: 200 }),
|
|
61
|
+
});
|
|
62
|
+
expect(r.verdict).toBe("up-to-date");
|
|
63
|
+
});
|
|
64
|
+
it("returns unreachable when fetcher throws", async () => {
|
|
65
|
+
const r = await runScoutCycle("2.19.62", {
|
|
66
|
+
fetchLatest: async () => { throw new Error("ENOTFOUND"); },
|
|
67
|
+
});
|
|
68
|
+
expect(r.verdict).toBe("unreachable");
|
|
69
|
+
expect(r.latestVersion).toBeNull();
|
|
70
|
+
expect(r.reachability.error).toContain("ENOTFOUND");
|
|
71
|
+
});
|
|
72
|
+
it("propagates httpStatus from thrown error", async () => {
|
|
73
|
+
const r = await runScoutCycle("2.19.62", {
|
|
74
|
+
fetchLatest: async () => {
|
|
75
|
+
const e = new Error("HTTP 503");
|
|
76
|
+
e.httpStatus = 503;
|
|
77
|
+
throw e;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
expect(r.verdict).toBe("unreachable");
|
|
81
|
+
expect(r.reachability.httpStatus).toBe(503);
|
|
82
|
+
});
|
|
83
|
+
it("NEVER throws — even on totally broken fetcher", async () => {
|
|
84
|
+
await expect(runScoutCycle("2.19.62", {
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
fetchLatest: async () => { throw null; },
|
|
87
|
+
})).resolves.toBeDefined();
|
|
88
|
+
});
|
|
89
|
+
it("returns report shape with correct organ + version fields", async () => {
|
|
90
|
+
const r = await runScoutCycle("2.19.62", {
|
|
91
|
+
fetchLatest: async () => ({ version: "2.19.62" }),
|
|
92
|
+
});
|
|
93
|
+
expect(r.v).toBe(PROTOCOL_VERSION);
|
|
94
|
+
expect(r.organ).toBe("scout");
|
|
95
|
+
expect(typeof r.ts).toBe("string");
|
|
96
|
+
expect(r.packageName).toBe("mneme-ai");
|
|
97
|
+
expect(r.durationMs).toBeGreaterThanOrEqual(0);
|
|
98
|
+
});
|
|
99
|
+
it("respects custom packageName", async () => {
|
|
100
|
+
let calledWithPkg = "";
|
|
101
|
+
const r = await runScoutCycle("1.0.0", {
|
|
102
|
+
packageName: "@mneme-ai/core",
|
|
103
|
+
fetchLatest: async (_reg, pkg) => { calledWithPkg = pkg; return { version: "1.0.0" }; },
|
|
104
|
+
});
|
|
105
|
+
expect(calledWithPkg).toBe("@mneme-ai/core");
|
|
106
|
+
expect(r.packageName).toBe("@mneme-ai/core");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe("v2.19.62 runScoutCycle caching", () => {
|
|
110
|
+
beforeEach(() => clearScoutCache());
|
|
111
|
+
it("caches successful fetch + cacheHit=true on second call", async () => {
|
|
112
|
+
let fetchCount = 0;
|
|
113
|
+
const fetcher = async () => { fetchCount++; return { version: "2.19.62" }; };
|
|
114
|
+
const r1 = await runScoutCycle("2.19.62", { fetchLatest: fetcher });
|
|
115
|
+
expect(r1.cacheHit).toBe(false);
|
|
116
|
+
const r2 = await runScoutCycle("2.19.62", { fetchLatest: fetcher });
|
|
117
|
+
expect(r2.cacheHit).toBe(true);
|
|
118
|
+
expect(fetchCount).toBe(1); // Only the first call hit the fetcher
|
|
119
|
+
});
|
|
120
|
+
it("cache invalidates after TTL", async () => {
|
|
121
|
+
let fetchCount = 0;
|
|
122
|
+
const fetcher = async () => { fetchCount++; return { version: "2.19.62" }; };
|
|
123
|
+
let fakeNow = 1_000_000;
|
|
124
|
+
const r1 = await runScoutCycle("2.19.62", { fetchLatest: fetcher, cacheTtlMs: 1000, now: () => fakeNow });
|
|
125
|
+
expect(r1.cacheHit).toBe(false);
|
|
126
|
+
fakeNow += 999;
|
|
127
|
+
const r2 = await runScoutCycle("2.19.62", { fetchLatest: fetcher, cacheTtlMs: 1000, now: () => fakeNow });
|
|
128
|
+
expect(r2.cacheHit).toBe(true);
|
|
129
|
+
fakeNow += 100; // total > 1000, past TTL
|
|
130
|
+
const r3 = await runScoutCycle("2.19.62", { fetchLatest: fetcher, cacheTtlMs: 1000, now: () => fakeNow });
|
|
131
|
+
expect(r3.cacheHit).toBe(false);
|
|
132
|
+
expect(fetchCount).toBe(2);
|
|
133
|
+
});
|
|
134
|
+
it("caches unreachable failures too (avoids hammering on offline)", async () => {
|
|
135
|
+
let fetchCount = 0;
|
|
136
|
+
const fetcher = async () => { fetchCount++; throw new Error("offline"); };
|
|
137
|
+
const r1 = await runScoutCycle("2.19.62", { fetchLatest: fetcher });
|
|
138
|
+
expect(r1.verdict).toBe("unreachable");
|
|
139
|
+
const r2 = await runScoutCycle("2.19.62", { fetchLatest: fetcher });
|
|
140
|
+
expect(r2.cacheHit).toBe(true);
|
|
141
|
+
expect(fetchCount).toBe(1);
|
|
142
|
+
});
|
|
143
|
+
it("different packages cached independently", async () => {
|
|
144
|
+
const r1 = await runScoutCycle("1.0.0", {
|
|
145
|
+
packageName: "pkg-a",
|
|
146
|
+
fetchLatest: async () => ({ version: "1.0.0" }),
|
|
147
|
+
});
|
|
148
|
+
const r2 = await runScoutCycle("1.0.0", {
|
|
149
|
+
packageName: "pkg-b",
|
|
150
|
+
fetchLatest: async () => ({ version: "2.0.0" }),
|
|
151
|
+
});
|
|
152
|
+
expect(r1.latestVersion).toBe("1.0.0");
|
|
153
|
+
expect(r2.latestVersion).toBe("2.0.0");
|
|
154
|
+
expect(scoutCacheSize()).toBe(2);
|
|
155
|
+
});
|
|
156
|
+
it("clearScoutCache resets cache size to 0", async () => {
|
|
157
|
+
await runScoutCycle("1.0.0", { fetchLatest: async () => ({ version: "1.0.0" }) });
|
|
158
|
+
expect(scoutCacheSize()).toBeGreaterThan(0);
|
|
159
|
+
clearScoutCache();
|
|
160
|
+
expect(scoutCacheSize()).toBe(0);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
//# sourceMappingURL=scout.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scout.test.js","sourceRoot":"","sources":["../../src/phoenix/scout.test.ts"],"names":[],"mappings":"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"}
|