@mneme-ai/core 2.19.96-lite → 2.19.97-lite
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/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/pulse.d.ts.map +1 -1
- package/dist/pulse.js +29 -5
- package/dist/pulse.js.map +1 -1
- package/dist/super_nova/index.d.ts +118 -0
- package/dist/super_nova/index.d.ts.map +1 -0
- package/dist/super_nova/index.js +240 -0
- package/dist/super_nova/index.js.map +1 -0
- package/dist/super_nova/super_nova.test.d.ts +2 -0
- package/dist/super_nova/super_nova.test.d.ts.map +1 -0
- package/dist/super_nova/super_nova.test.js +90 -0
- package/dist/super_nova/super_nova.test.js.map +1 -0
- package/dist/superlock/index.d.ts +84 -0
- package/dist/superlock/index.d.ts.map +1 -0
- package/dist/superlock/index.js +218 -0
- package/dist/superlock/index.js.map +1 -0
- package/dist/superlock/superlock.test.d.ts +2 -0
- package/dist/superlock/superlock.test.d.ts.map +1 -0
- package/dist/superlock/superlock.test.js +105 -0
- package/dist/superlock/superlock.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.97 — SUPER NOVA WRAPPER.
|
|
3
|
+
*
|
|
4
|
+
* The user's ask: "ใส่ super nova Wrapper ให้ครบทุกเส้นทุกสายทุกจุด
|
|
5
|
+
* แบบ super molecul ... ระบบ IA รู้เองทุกอย่างแบบ realtime 100%"
|
|
6
|
+
*
|
|
7
|
+
* Translation: every Mneme verb (CLI command, MCP tool, library
|
|
8
|
+
* function) should be wrapped by a middleware that lets the
|
|
9
|
+
* Intelligent Assistant (IA) layer observe everything in realtime —
|
|
10
|
+
* what was called, with what args, the outcome, the latency, who
|
|
11
|
+
* called it. No more "Mneme has 800 tools but we don't know which
|
|
12
|
+
* fired or why".
|
|
13
|
+
*
|
|
14
|
+
* Design: a 4-phase composable middleware.
|
|
15
|
+
*
|
|
16
|
+
* BEFORE — observe the call about to happen; check IA cache for
|
|
17
|
+
* a known answer; optionally short-circuit
|
|
18
|
+
* DURING — stream telemetry while the call runs (start / progress)
|
|
19
|
+
* AFTER — record outcome (success / error / value) into the
|
|
20
|
+
* experience pool the IA learns from
|
|
21
|
+
* FAILURE — when the call throws, classify + feed to the IA so
|
|
22
|
+
* the next agent doesn't repeat the mistake
|
|
23
|
+
*
|
|
24
|
+
* The wrapper is intentionally cheap (per-call overhead <1ms when no
|
|
25
|
+
* observer is registered; ~5ms when the experience pool writes a row).
|
|
26
|
+
* Observers can be added/removed at runtime.
|
|
27
|
+
*
|
|
28
|
+
* Composes with everything Mneme already ships: notifier (pulse hooks),
|
|
29
|
+
* pheromone (touch counters), bounty (vendor trust), evolution
|
|
30
|
+
* (growth snapshots), nexus (live subscriptions), atom (decision
|
|
31
|
+
* oracle). The wrapper is the *single point of synchronisation*
|
|
32
|
+
* that flows facts INTO all of those subsystems at once.
|
|
33
|
+
*
|
|
34
|
+
* Why this is a moat:
|
|
35
|
+
* No other AI-tooling product has a single fabric that observes
|
|
36
|
+
* every verb across CLI + MCP + library + daemon + shepherd +
|
|
37
|
+
* pulse simultaneously and feeds the result into a shared
|
|
38
|
+
* experience layer. This is the "central nervous system" of
|
|
39
|
+
* Mneme — the substrate the IA actually grows on.
|
|
40
|
+
*/
|
|
41
|
+
import { existsSync, appendFileSync, mkdirSync } from "node:fs";
|
|
42
|
+
import { join } from "node:path";
|
|
43
|
+
const POOL_DIR = ".mneme/super_nova";
|
|
44
|
+
const POOL_FILE = "experience.jsonl";
|
|
45
|
+
// ─── REGISTRY ──────────────────────────────────────────────────────────
|
|
46
|
+
const observers = new Map();
|
|
47
|
+
export function registerObserver(o) {
|
|
48
|
+
observers.set(o.id, o);
|
|
49
|
+
return () => observers.delete(o.id);
|
|
50
|
+
}
|
|
51
|
+
export function listObservers() {
|
|
52
|
+
return Array.from(observers.keys());
|
|
53
|
+
}
|
|
54
|
+
export function clearObservers() {
|
|
55
|
+
observers.clear();
|
|
56
|
+
}
|
|
57
|
+
// ─── EXPERIENCE POOL ───────────────────────────────────────────────────
|
|
58
|
+
function ensurePoolDir(repoRoot) {
|
|
59
|
+
const dir = join(repoRoot, POOL_DIR);
|
|
60
|
+
if (!existsSync(dir)) {
|
|
61
|
+
try {
|
|
62
|
+
mkdirSync(dir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
catch { /* */ }
|
|
65
|
+
}
|
|
66
|
+
return dir;
|
|
67
|
+
}
|
|
68
|
+
function classifyFailure(msg) {
|
|
69
|
+
const m = msg.toLowerCase();
|
|
70
|
+
if (m.includes("enoent") || m.includes("not found"))
|
|
71
|
+
return "not-found";
|
|
72
|
+
if (m.includes("ebusy") || m.includes("locked"))
|
|
73
|
+
return "lock-contention";
|
|
74
|
+
if (m.includes("network") || m.includes("etimedout") || m.includes("getaddrinfo"))
|
|
75
|
+
return "network";
|
|
76
|
+
if (m.includes("permission") || m.includes("eacces") || m.includes("eperm"))
|
|
77
|
+
return "permission";
|
|
78
|
+
if (m.includes("superlock"))
|
|
79
|
+
return "race-prevented";
|
|
80
|
+
if (m.includes("invalid") || m.includes("validation"))
|
|
81
|
+
return "validation";
|
|
82
|
+
return "other";
|
|
83
|
+
}
|
|
84
|
+
function writeExperience(repoRoot, row) {
|
|
85
|
+
try {
|
|
86
|
+
const dir = ensurePoolDir(repoRoot);
|
|
87
|
+
appendFileSync(join(dir, POOL_FILE), JSON.stringify(row) + "\n", "utf8");
|
|
88
|
+
}
|
|
89
|
+
catch { /* IA observation is best-effort; never block the caller */ }
|
|
90
|
+
}
|
|
91
|
+
/** The headline primitive. Wrap any async function with the SUPER NOVA
|
|
92
|
+
* middleware so every fire flows through the 4-phase pipeline.
|
|
93
|
+
*
|
|
94
|
+
* Usage:
|
|
95
|
+
* const result = await withSuperNova(
|
|
96
|
+
* { verb: "mneme.clone.clipboard", surface: "cli", repoRoot: cwd },
|
|
97
|
+
* async () => doTheActualWork(),
|
|
98
|
+
* );
|
|
99
|
+
*
|
|
100
|
+
* Observers + the experience pool are populated as a side effect; the
|
|
101
|
+
* caller sees only the original return value (or thrown error). */
|
|
102
|
+
export async function withSuperNova(ctxInput, fn, opts = {}) {
|
|
103
|
+
const ctx = { ...ctxInput, startedAt: new Date().toISOString() };
|
|
104
|
+
await fire("before", ctx);
|
|
105
|
+
const t0 = Date.now();
|
|
106
|
+
let outcome;
|
|
107
|
+
try {
|
|
108
|
+
const result = await fn();
|
|
109
|
+
outcome = {
|
|
110
|
+
ok: true,
|
|
111
|
+
durationMs: Date.now() - t0,
|
|
112
|
+
resultSummary: summariseResult(result),
|
|
113
|
+
verdict: opts.verdict,
|
|
114
|
+
};
|
|
115
|
+
await fire("after", ctx, outcome);
|
|
116
|
+
if (ctx.repoRoot && !opts.skipPool) {
|
|
117
|
+
writeExperience(ctx.repoRoot, {
|
|
118
|
+
v: 1, ts: ctx.startedAt, verb: ctx.verb, surface: ctx.surface,
|
|
119
|
+
durationMs: outcome.durationMs, ok: true, verdict: opts.verdict,
|
|
120
|
+
vendor: ctx.vendor, tags: opts.tags,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const msg = err.message ?? String(err);
|
|
127
|
+
outcome = {
|
|
128
|
+
ok: false,
|
|
129
|
+
durationMs: Date.now() - t0,
|
|
130
|
+
errorMessage: msg.slice(0, 300),
|
|
131
|
+
verdict: opts.verdict,
|
|
132
|
+
};
|
|
133
|
+
await fire("failure", ctx, outcome);
|
|
134
|
+
if (ctx.repoRoot && !opts.skipPool) {
|
|
135
|
+
writeExperience(ctx.repoRoot, {
|
|
136
|
+
v: 1, ts: ctx.startedAt, verb: ctx.verb, surface: ctx.surface,
|
|
137
|
+
durationMs: outcome.durationMs, ok: false, verdict: opts.verdict,
|
|
138
|
+
vendor: ctx.vendor, tags: opts.tags, failureClass: classifyFailure(msg),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Synchronous variant — same shape, sync fn. */
|
|
145
|
+
export function withSuperNovaSync(ctxInput, fn, opts = {}) {
|
|
146
|
+
const ctx = { ...ctxInput, startedAt: new Date().toISOString() };
|
|
147
|
+
fireSync("before", ctx);
|
|
148
|
+
const t0 = Date.now();
|
|
149
|
+
let outcome;
|
|
150
|
+
try {
|
|
151
|
+
const result = fn();
|
|
152
|
+
outcome = { ok: true, durationMs: Date.now() - t0, resultSummary: summariseResult(result), verdict: opts.verdict };
|
|
153
|
+
fireSync("after", ctx, outcome);
|
|
154
|
+
if (ctx.repoRoot && !opts.skipPool) {
|
|
155
|
+
writeExperience(ctx.repoRoot, {
|
|
156
|
+
v: 1, ts: ctx.startedAt, verb: ctx.verb, surface: ctx.surface,
|
|
157
|
+
durationMs: outcome.durationMs, ok: true, verdict: opts.verdict,
|
|
158
|
+
vendor: ctx.vendor, tags: opts.tags,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const msg = err.message ?? String(err);
|
|
165
|
+
outcome = { ok: false, durationMs: Date.now() - t0, errorMessage: msg.slice(0, 300), verdict: opts.verdict };
|
|
166
|
+
fireSync("failure", ctx, outcome);
|
|
167
|
+
if (ctx.repoRoot && !opts.skipPool) {
|
|
168
|
+
writeExperience(ctx.repoRoot, {
|
|
169
|
+
v: 1, ts: ctx.startedAt, verb: ctx.verb, surface: ctx.surface,
|
|
170
|
+
durationMs: outcome.durationMs, ok: false, verdict: opts.verdict,
|
|
171
|
+
vendor: ctx.vendor, tags: opts.tags, failureClass: classifyFailure(msg),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
throw err;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function fire(phase, ctx, outcome) {
|
|
178
|
+
for (const o of observers.values()) {
|
|
179
|
+
if (o.phases && !o.phases.includes(phase))
|
|
180
|
+
continue;
|
|
181
|
+
try {
|
|
182
|
+
await o.onPhase(phase, ctx, outcome);
|
|
183
|
+
}
|
|
184
|
+
catch { /* observers must never break the caller */ }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function fireSync(phase, ctx, outcome) {
|
|
188
|
+
for (const o of observers.values()) {
|
|
189
|
+
if (o.phases && !o.phases.includes(phase))
|
|
190
|
+
continue;
|
|
191
|
+
try {
|
|
192
|
+
const r = o.onPhase(phase, ctx, outcome);
|
|
193
|
+
// Discard any returned promise — sync wrapper doesn't await.
|
|
194
|
+
if (r && typeof r.then === "function")
|
|
195
|
+
void r;
|
|
196
|
+
}
|
|
197
|
+
catch { /* */ }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function summariseResult(r) {
|
|
201
|
+
if (r === null || r === undefined)
|
|
202
|
+
return "void";
|
|
203
|
+
if (typeof r === "string")
|
|
204
|
+
return r.length > 80 ? r.slice(0, 80) + "…" : r;
|
|
205
|
+
if (typeof r === "number" || typeof r === "boolean")
|
|
206
|
+
return String(r);
|
|
207
|
+
if (Array.isArray(r))
|
|
208
|
+
return `array(${r.length})`;
|
|
209
|
+
if (typeof r === "object") {
|
|
210
|
+
try {
|
|
211
|
+
const keys = Object.keys(r);
|
|
212
|
+
return `object(${keys.slice(0, 4).join(",")}${keys.length > 4 ? ",…" : ""})`;
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return "object";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return typeof r;
|
|
219
|
+
}
|
|
220
|
+
// ─── BUILT-IN OBSERVERS ────────────────────────────────────────────────
|
|
221
|
+
/** A simple console observer for debugging — fires in dev when
|
|
222
|
+
* MNEME_SUPER_NOVA_DEBUG=1. */
|
|
223
|
+
export function debugObserver() {
|
|
224
|
+
return {
|
|
225
|
+
id: "debug",
|
|
226
|
+
onPhase: (phase, ctx, outcome) => {
|
|
227
|
+
if (!process.env.MNEME_SUPER_NOVA_DEBUG)
|
|
228
|
+
return;
|
|
229
|
+
const tag = phase.toUpperCase();
|
|
230
|
+
const dur = outcome ? ` ${outcome.durationMs}ms` : "";
|
|
231
|
+
const ok = outcome ? (outcome.ok ? "✓" : "✗") : "·";
|
|
232
|
+
process.stderr.write(`[SUPER-NOVA ${tag}] ${ok} ${ctx.verb} (${ctx.surface})${dur}\n`);
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** Convenience: install the debug observer on import when env flag set. */
|
|
237
|
+
if (process.env.MNEME_SUPER_NOVA_DEBUG) {
|
|
238
|
+
registerObserver(debugObserver());
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/super_nova/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"super_nova.test.d.ts","sourceRoot":"","sources":["../../src/super_nova/super_nova.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { withSuperNova, withSuperNovaSync, registerObserver, clearObservers, listObservers, } from "./index.js";
|
|
6
|
+
describe("super_nova", () => {
|
|
7
|
+
let repo;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
repo = mkdtempSync(join(tmpdir(), "mneme-sn-"));
|
|
10
|
+
clearObservers();
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
clearObservers();
|
|
14
|
+
try {
|
|
15
|
+
rmSync(repo, { recursive: true, force: true });
|
|
16
|
+
}
|
|
17
|
+
catch { /* */ }
|
|
18
|
+
});
|
|
19
|
+
describe("withSuperNova (async)", () => {
|
|
20
|
+
it("returns the wrapped fn result + fires before/after observers", async () => {
|
|
21
|
+
const phases = [];
|
|
22
|
+
registerObserver({ id: "t", onPhase: (p) => { phases.push(p); } });
|
|
23
|
+
const r = await withSuperNova({ verb: "test.ok", surface: "lib", repoRoot: repo }, async () => 42);
|
|
24
|
+
expect(r).toBe(42);
|
|
25
|
+
expect(phases).toEqual(["before", "after"]);
|
|
26
|
+
});
|
|
27
|
+
it("fires before + failure when fn throws (and rethrows)", async () => {
|
|
28
|
+
const phases = [];
|
|
29
|
+
registerObserver({ id: "t", onPhase: (p) => { phases.push(p); } });
|
|
30
|
+
await expect(withSuperNova({ verb: "test.boom", surface: "lib", repoRoot: repo }, async () => { throw new Error("boom"); })).rejects.toThrow("boom");
|
|
31
|
+
expect(phases).toEqual(["before", "failure"]);
|
|
32
|
+
});
|
|
33
|
+
it("writes experience row to .mneme/super_nova/experience.jsonl", async () => {
|
|
34
|
+
await withSuperNova({ verb: "test.x", surface: "lib", repoRoot: repo }, async () => "hi");
|
|
35
|
+
const f = join(repo, ".mneme/super_nova/experience.jsonl");
|
|
36
|
+
expect(existsSync(f)).toBe(true);
|
|
37
|
+
const lines = readFileSync(f, "utf8").trim().split("\n");
|
|
38
|
+
expect(lines.length).toBe(1);
|
|
39
|
+
const row = JSON.parse(lines[0]);
|
|
40
|
+
expect(row.verb).toBe("test.x");
|
|
41
|
+
expect(row.ok).toBe(true);
|
|
42
|
+
expect(typeof row.durationMs).toBe("number");
|
|
43
|
+
});
|
|
44
|
+
it("classifies failures into failureClass", async () => {
|
|
45
|
+
await expect(withSuperNova({ verb: "test.eb", surface: "lib", repoRoot: repo }, async () => { throw new Error("EBUSY: resource busy"); })).rejects.toThrow();
|
|
46
|
+
const row = JSON.parse(readFileSync(join(repo, ".mneme/super_nova/experience.jsonl"), "utf8").trim());
|
|
47
|
+
expect(row.ok).toBe(false);
|
|
48
|
+
expect(row.failureClass).toBe("lock-contention");
|
|
49
|
+
});
|
|
50
|
+
it("observer thrown errors do NOT break the caller", async () => {
|
|
51
|
+
registerObserver({ id: "bad", onPhase: () => { throw new Error("observer crashed"); } });
|
|
52
|
+
const r = await withSuperNova({ verb: "test.ok", surface: "lib", repoRoot: repo }, async () => 7);
|
|
53
|
+
expect(r).toBe(7);
|
|
54
|
+
});
|
|
55
|
+
it("skipPool=true does not write experience row", async () => {
|
|
56
|
+
await withSuperNova({ verb: "test.skip", surface: "lib", repoRoot: repo }, async () => 1, { skipPool: true });
|
|
57
|
+
expect(existsSync(join(repo, ".mneme/super_nova/experience.jsonl"))).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
it("phase filter only fires observer for opted-in phases", async () => {
|
|
60
|
+
const phases = [];
|
|
61
|
+
registerObserver({ id: "after-only", phases: ["after"], onPhase: (p) => { phases.push(p); } });
|
|
62
|
+
await withSuperNova({ verb: "test.ok", surface: "lib", repoRoot: repo }, async () => 1);
|
|
63
|
+
expect(phases).toEqual(["after"]);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe("withSuperNovaSync", () => {
|
|
67
|
+
it("runs synchronously + writes experience row", () => {
|
|
68
|
+
const phases = [];
|
|
69
|
+
registerObserver({ id: "t", onPhase: (p) => { phases.push(p); } });
|
|
70
|
+
const r = withSuperNovaSync({ verb: "test.sync", surface: "lib", repoRoot: repo }, () => "result");
|
|
71
|
+
expect(r).toBe("result");
|
|
72
|
+
expect(phases).toEqual(["before", "after"]);
|
|
73
|
+
expect(existsSync(join(repo, ".mneme/super_nova/experience.jsonl"))).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("observer registry", () => {
|
|
77
|
+
it("listObservers returns registered ids", () => {
|
|
78
|
+
registerObserver({ id: "a", onPhase: () => { } });
|
|
79
|
+
registerObserver({ id: "b", onPhase: () => { } });
|
|
80
|
+
expect(listObservers().sort()).toEqual(["a", "b"]);
|
|
81
|
+
});
|
|
82
|
+
it("registerObserver returns an unregister fn", () => {
|
|
83
|
+
const off = registerObserver({ id: "z", onPhase: () => { } });
|
|
84
|
+
expect(listObservers()).toContain("z");
|
|
85
|
+
off();
|
|
86
|
+
expect(listObservers()).not.toContain("z");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=super_nova.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"super_nova.test.js","sourceRoot":"","sources":["../../src/super_nova/super_nova.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.97 — SUPERLOCK + DEV-SOURCE GUARD.
|
|
3
|
+
*
|
|
4
|
+
* Solves the race condition class user reported in the post-mortem of
|
|
5
|
+
* their broken install:
|
|
6
|
+
*
|
|
7
|
+
* 1. Pulse banner advertises [AUTO-ACTION] mneme.system.upgrade
|
|
8
|
+
* 2. Daemon (or shepherd) starts auto-upgrade in background
|
|
9
|
+
* → deletes bot/platforms/index.js to rewrite
|
|
10
|
+
* 3. User simultaneously runs `npm install -g mneme-ai` from terminal
|
|
11
|
+
* 4. EBUSY on libvips DLL because daemon is mid-write
|
|
12
|
+
* 5. Half-finished install: missing files; every `mneme` command
|
|
13
|
+
* throws ERR_MODULE_NOT_FOUND
|
|
14
|
+
*
|
|
15
|
+
* Plus the user discovered a SECOND install source: when Mneme is
|
|
16
|
+
* checked out as a dev repo (D:\lib_ai_git\packages\cli\bin\mneme.js),
|
|
17
|
+
* THAT daemon ALSO honours pulse auto-upgrade mandates — and tries to
|
|
18
|
+
* upgrade the *global npm install*, racing with whatever the user is
|
|
19
|
+
* doing. Two install roots → two daemons → two upgrade triggers →
|
|
20
|
+
* guaranteed race.
|
|
21
|
+
*
|
|
22
|
+
* Two-layer fix:
|
|
23
|
+
*
|
|
24
|
+
* DEV-SOURCE GUARD
|
|
25
|
+
* Detect when the running mneme binary is from a source checkout
|
|
26
|
+
* (path contains `packages/cli/bin/`) rather than a published
|
|
27
|
+
* `node_modules/mneme-ai/` tree. When detected, refuse ALL
|
|
28
|
+
* auto-upgrade attempts + drop the upgrade [AUTO-ACTION] from
|
|
29
|
+
* pulse output entirely. Dev source manages its own upgrades
|
|
30
|
+
* via git pull.
|
|
31
|
+
*
|
|
32
|
+
* SUPERLOCK
|
|
33
|
+
* Single global file mutex at `~/.mneme-global/superlock.flag`
|
|
34
|
+
* that EVERY install/upgrade path must grab before mutating the
|
|
35
|
+
* on-disk install. Lock content is JSON with { pid, startedAt,
|
|
36
|
+
* intent, role } so observers can see who's holding it + why.
|
|
37
|
+
* Stale locks (>10 min) are auto-broken. Lock acquisition is
|
|
38
|
+
* atomic-rename (POSIX + Windows safe).
|
|
39
|
+
*
|
|
40
|
+
* Composes with v2.19.58 install-incoming.flag (5-min flag window),
|
|
41
|
+
* v2.19.57 shepherd, v2.19.62 phoenix DLL extraction, but is the
|
|
42
|
+
* single source of truth that serialises EVERYTHING.
|
|
43
|
+
*/
|
|
44
|
+
export type LockRole = "user-npm" | "daemon-autoupgrade" | "shepherd" | "phoenix" | "cli-upgrade" | "test";
|
|
45
|
+
export interface LockState {
|
|
46
|
+
pid: number;
|
|
47
|
+
startedAt: string;
|
|
48
|
+
intent: string;
|
|
49
|
+
role: LockRole;
|
|
50
|
+
/** Absolute path of the binary that holds the lock — used for
|
|
51
|
+
* dev-source attribution. */
|
|
52
|
+
holderPath: string;
|
|
53
|
+
}
|
|
54
|
+
/** Read current lock state if any. Returns null if no lock or unreadable. */
|
|
55
|
+
export declare function readLock(): LockState | null;
|
|
56
|
+
/** True iff a lock exists AND is fresh enough to honour. Stale locks
|
|
57
|
+
* (older than STALE_MS) are ignored because the holder probably died. */
|
|
58
|
+
export declare function isLockHeld(): boolean;
|
|
59
|
+
/** Atomic acquire. Returns true if we now hold the lock; false if
|
|
60
|
+
* somebody else holds a fresh one. Uses tmpfile + rename for atomicity
|
|
61
|
+
* on both POSIX and Windows. */
|
|
62
|
+
export declare function acquireLock(state: Omit<LockState, "startedAt">): boolean;
|
|
63
|
+
/** Release the lock if we still hold it. Caller MUST always call this
|
|
64
|
+
* in a `finally` block to avoid leaks. */
|
|
65
|
+
export declare function releaseLock(pid?: number): boolean;
|
|
66
|
+
/** Wrap any async install/upgrade action with the superlock. Throws
|
|
67
|
+
* with a descriptive error if the lock is held by another fresh
|
|
68
|
+
* process. */
|
|
69
|
+
export declare function withSuperlock<T>(state: Omit<LockState, "startedAt" | "pid">, fn: () => Promise<T>): Promise<T>;
|
|
70
|
+
/** True iff the currently-running mneme binary lives in a source
|
|
71
|
+
* checkout (path contains `/packages/cli/` or `\packages\cli\`) rather
|
|
72
|
+
* than a node_modules install. Dev-source must NEVER auto-upgrade
|
|
73
|
+
* itself — git pull is the right tool for that. */
|
|
74
|
+
export declare function isDevSource(scriptPath?: string): boolean;
|
|
75
|
+
/** Human-readable explanation surfaced when dev-source guard fires. */
|
|
76
|
+
export declare function devSourceMessage(scriptPath?: string): string;
|
|
77
|
+
/** The decision the pulse renderer + auto-upgrade hooks call before
|
|
78
|
+
* emitting `[AUTO-ACTION] mneme.system.upgrade`. Returns true when
|
|
79
|
+
* the auto-action is safe to advertise + execute. */
|
|
80
|
+
export declare function autoUpgradeAllowed(scriptPath?: string): {
|
|
81
|
+
allowed: boolean;
|
|
82
|
+
reason: string;
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/superlock/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAWH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,oBAAoB,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAE3G,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf;kCAC8B;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAUD,6EAA6E;AAC7E,wBAAgB,QAAQ,IAAI,SAAS,GAAG,IAAI,CAK3C;AAED;0EAC0E;AAC1E,wBAAgB,UAAU,IAAI,OAAO,CAOpC;AAED;;iCAEiC;AACjC,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG,OAAO,CAwBxE;AAED;2CAC2C;AAC3C,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAoB,GAAG,OAAO,CAM9D;AAED;;eAEe;AACf,wBAAsB,aAAa,CAAC,CAAC,EACnC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,KAAK,CAAC,EAC3C,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAYZ;AAID;;;oDAGoD;AACpD,wBAAgB,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAyBxD;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED;;sDAEsD;AACtD,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAS5F"}
|