@mulmoclaude/core 0.1.0 → 0.2.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/collection/server/index.cjs +46 -1716
- package/dist/collection/server/index.js +1 -1669
- package/dist/collection-watchers/config.d.ts +49 -0
- package/dist/collection-watchers/index.cjs +554 -0
- package/dist/collection-watchers/index.cjs.map +1 -0
- package/dist/collection-watchers/index.d.ts +3 -0
- package/dist/collection-watchers/index.js +539 -0
- package/dist/collection-watchers/index.js.map +1 -0
- package/dist/collection-watchers/reconciler.d.ts +33 -0
- package/dist/collection-watchers/watcher.d.ts +34 -0
- package/dist/notifier/index.cjs +20 -483
- package/dist/notifier/index.js +1 -463
- package/dist/notifier-6PjsLxLm.js +464 -0
- package/dist/{notifier/index.js.map → notifier-6PjsLxLm.js.map} +1 -1
- package/dist/notifier-lJ4v2Y6B.cjs +578 -0
- package/dist/{notifier/index.cjs.map → notifier-lJ4v2Y6B.cjs.map} +1 -1
- package/dist/server-BhIdZgqu.js +1671 -0
- package/dist/server-BhIdZgqu.js.map +1 -0
- package/dist/server-BjoKk2tR.cjs +1942 -0
- package/dist/server-BjoKk2tR.cjs.map +1 -0
- package/dist/skill-bridge/index.cjs +88 -0
- package/dist/skill-bridge/index.cjs.map +1 -0
- package/dist/skill-bridge/index.d.ts +30 -0
- package/dist/skill-bridge/index.js +80 -0
- package/dist/skill-bridge/index.js.map +1 -0
- package/package.json +13 -1
- package/dist/collection/server/index.cjs.map +0 -1
- package/dist/collection/server/index.js.map +0 -1
package/dist/notifier/index.cjs
CHANGED
|
@@ -1,484 +1,21 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
require("../
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* is incoherent — fyi if it's a ping, `nudge`/`urgent` if it's a
|
|
23
|
-
* real obligation worth a landing page.
|
|
24
|
-
*
|
|
25
|
-
* Both rules are mirrored in the HTTP layer so plugin-runtime callers
|
|
26
|
-
* and HTTP callers hit the same wall. */
|
|
27
|
-
var NOTIFIER_LIFECYCLES = ["fyi", "action"];
|
|
28
|
-
/** Severity drives badge color (gray / amber / red, worst-wins) and
|
|
29
|
-
* in a future iteration channel routing. Mostly stored verbatim by
|
|
30
|
-
* the engine; the one engine-visible interaction is the rule that
|
|
31
|
-
* `action` lifecycle cannot pair with `info` severity (see
|
|
32
|
-
* `NotifierLifecycle` above). */
|
|
33
|
-
var NOTIFIER_SEVERITIES = [
|
|
34
|
-
"info",
|
|
35
|
-
"nudge",
|
|
36
|
-
"urgent"
|
|
37
|
-
];
|
|
38
|
-
/** History size cap. The bell popup's History section renders this
|
|
39
|
-
* many entries; older ones fall off when new terminations land. */
|
|
40
|
-
var HISTORY_CAP = 50;
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region src/notifier/store.ts
|
|
43
|
-
function isNotFoundError(err) {
|
|
44
|
-
return typeof err === "object" && err !== null && err.code === "ENOENT";
|
|
45
|
-
}
|
|
46
|
-
/** Read the active-entries file. Returns an empty store when the file
|
|
47
|
-
* doesn't exist yet (first ever call on a fresh workspace). Any other
|
|
48
|
-
* read or parse failure throws — the caller has to decide whether to
|
|
49
|
-
* surface or recover, since silently treating "malformed file" as
|
|
50
|
-
* "no entries" would lose data. */
|
|
51
|
-
async function loadActive(filePath) {
|
|
52
|
-
let text;
|
|
53
|
-
try {
|
|
54
|
-
text = await node_fs.promises.readFile(filePath, "utf-8");
|
|
55
|
-
} catch (err) {
|
|
56
|
-
if (isNotFoundError(err)) return { entries: {} };
|
|
57
|
-
throw err;
|
|
58
|
-
}
|
|
59
|
-
const parsed = JSON.parse(text);
|
|
60
|
-
if (typeof parsed !== "object" || parsed === null || !("entries" in parsed)) throw new Error(`notifier: malformed active.json at ${filePath}`);
|
|
61
|
-
const { entries } = parsed;
|
|
62
|
-
if (typeof entries !== "object" || entries === null || Array.isArray(entries)) throw new Error(`notifier: malformed active.json at ${filePath}`);
|
|
63
|
-
return parsed;
|
|
64
|
-
}
|
|
65
|
-
/** Write the active-entries file via the injected atomic writer so a
|
|
66
|
-
* half-written file is never visible to readers. The caller serialises
|
|
67
|
-
* writes (engine.ts queues mutations) — this function makes no
|
|
68
|
-
* concurrency guarantees of its own. */
|
|
69
|
-
async function saveActive(writeJson, filePath, state) {
|
|
70
|
-
await writeJson(filePath, state);
|
|
71
|
-
}
|
|
72
|
-
/** Read the history file. Empty array on first run. Same parse-error
|
|
73
|
-
* policy as `loadActive`. */
|
|
74
|
-
async function loadHistory(filePath) {
|
|
75
|
-
let text;
|
|
76
|
-
try {
|
|
77
|
-
text = await node_fs.promises.readFile(filePath, "utf-8");
|
|
78
|
-
} catch (err) {
|
|
79
|
-
if (isNotFoundError(err)) return { entries: [] };
|
|
80
|
-
throw err;
|
|
81
|
-
}
|
|
82
|
-
const parsed = JSON.parse(text);
|
|
83
|
-
if (typeof parsed !== "object" || parsed === null || !("entries" in parsed) || !Array.isArray(parsed.entries)) throw new Error(`notifier: malformed history.json at ${filePath}`);
|
|
84
|
-
return parsed;
|
|
85
|
-
}
|
|
86
|
-
async function saveHistory(writeJson, filePath, state) {
|
|
87
|
-
await writeJson(filePath, state);
|
|
88
|
-
}
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region src/notifier/validate.ts
|
|
91
|
-
/** Hard caps on publish-input fields. The engine reads each entry on
|
|
92
|
-
* every list/get call (no in-memory cache), so unbounded fields hurt
|
|
93
|
-
* every reader. Caps chosen to be generous for legitimate UX copy
|
|
94
|
-
* while bounding active.json growth: a notification fundamentally is
|
|
95
|
-
* a short blurb, not a document. */
|
|
96
|
-
var NOTIFIER_LIMITS = {
|
|
97
|
-
titleMax: 200,
|
|
98
|
-
bodyMax: 4e3,
|
|
99
|
-
navigateTargetMax: 1e3,
|
|
100
|
-
pluginDataMaxBytes: 16 * 1024
|
|
101
|
-
};
|
|
102
|
-
function validateTitle(title) {
|
|
103
|
-
if (typeof title !== "string" || title.length === 0) return "title must be a non-empty string";
|
|
104
|
-
if (title.length > NOTIFIER_LIMITS.titleMax) return `title exceeds max length of ${NOTIFIER_LIMITS.titleMax} chars`;
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
function validateBody(body) {
|
|
108
|
-
if (body === void 0) return null;
|
|
109
|
-
if (body.length > NOTIFIER_LIMITS.bodyMax) return `body exceeds max length of ${NOTIFIER_LIMITS.bodyMax} chars`;
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
function validateNavigateTarget(target) {
|
|
113
|
-
if (target === void 0) return null;
|
|
114
|
-
if (target.length === 0) return "navigateTarget must be a non-empty relative path when set";
|
|
115
|
-
if (target.length > NOTIFIER_LIMITS.navigateTargetMax) return `navigateTarget exceeds max length of ${NOTIFIER_LIMITS.navigateTargetMax} chars`;
|
|
116
|
-
if (!target.startsWith("/") || target.startsWith("//")) return "navigateTarget must be a relative path beginning with a single '/' (no scheme, no '//')";
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
function validatePluginData(pluginData) {
|
|
120
|
-
if (pluginData === void 0) return null;
|
|
121
|
-
let serialized;
|
|
122
|
-
try {
|
|
123
|
-
serialized = JSON.stringify(pluginData);
|
|
124
|
-
} catch (err) {
|
|
125
|
-
return `pluginData is not JSON-serialisable: ${String(err)}`;
|
|
126
|
-
}
|
|
127
|
-
if (typeof serialized !== "string") return "pluginData is not JSON-serialisable";
|
|
128
|
-
if (serialized.length > NOTIFIER_LIMITS.pluginDataMaxBytes) return `pluginData JSON exceeds ${NOTIFIER_LIMITS.pluginDataMaxBytes} bytes`;
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
function validateActionCoherence(input) {
|
|
132
|
-
if (input.lifecycle !== "action") return null;
|
|
133
|
-
if (input.severity === "info") return "action lifecycle is incompatible with info severity (use fyi for low-priority pings)";
|
|
134
|
-
if (typeof input.navigateTarget !== "string" || input.navigateTarget.length === 0) return "action lifecycle requires a non-empty navigateTarget";
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
/** Validate a `PublishInput`. Returns `null` if OK, or a
|
|
138
|
-
* human-readable error string. Order matters — shape/size errors are
|
|
139
|
-
* reported before lifecycle/severity coherence errors so the message
|
|
140
|
-
* the caller sees points at the most fundamental problem first. */
|
|
141
|
-
function validatePublishInput(input) {
|
|
142
|
-
return validateTitle(input.title) ?? validateBody(input.body) ?? validateNavigateTarget(input.navigateTarget) ?? validatePluginData(input.pluginData) ?? validateActionCoherence(input);
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
//#region src/notifier/engine.ts
|
|
146
|
-
var NOOP_LOG = {
|
|
147
|
-
warn: () => {},
|
|
148
|
-
error: () => {}
|
|
149
|
-
};
|
|
150
|
-
var config = null;
|
|
151
|
-
var activeFilePath = "";
|
|
152
|
-
var historyFilePath = "";
|
|
153
|
-
function logger() {
|
|
154
|
-
return config?.log ?? NOOP_LOG;
|
|
155
|
-
}
|
|
156
|
-
/** Wire the engine's I/O deps. Call once at startup, before the first
|
|
157
|
-
* mutation. Does NOT set file paths — those are set independently via
|
|
158
|
-
* `setNotifierFilePaths` so a host can bind production paths at module
|
|
159
|
-
* load and a test can override them without re-supplying the deps. */
|
|
160
|
-
function configureNotifier(injected) {
|
|
161
|
-
config = injected;
|
|
162
|
-
}
|
|
163
|
-
var listeners = [];
|
|
164
|
-
/** Register an in-process listener for engine events. Returns an
|
|
165
|
-
* unsubscribe function the caller can use during teardown. */
|
|
166
|
-
function onEvent(listener) {
|
|
167
|
-
listeners.push(listener);
|
|
168
|
-
return () => {
|
|
169
|
-
const idx = listeners.indexOf(listener);
|
|
170
|
-
if (idx >= 0) listeners.splice(idx, 1);
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
function emit(event) {
|
|
174
|
-
for (const listener of listeners) try {
|
|
175
|
-
listener(event);
|
|
176
|
-
} catch (err) {
|
|
177
|
-
logger().error("in-process listener failed", {
|
|
178
|
-
type: event.type,
|
|
179
|
-
error: String(err)
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (!config) {
|
|
183
|
-
logger().warn("emit before init", { type: event.type });
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
config.publishEvent(event);
|
|
188
|
-
} catch (err) {
|
|
189
|
-
logger().error("emit failed", {
|
|
190
|
-
type: event.type,
|
|
191
|
-
error: String(err)
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
var writing = false;
|
|
196
|
-
var waiters = [];
|
|
197
|
-
/** Point the engine at its active/history files. Resets the write
|
|
198
|
-
* queue, so callers must not have in-flight mutations. The host calls
|
|
199
|
-
* this once with the workspace paths; tests call it per-case with temp
|
|
200
|
-
* files. */
|
|
201
|
-
function setNotifierFilePaths(paths) {
|
|
202
|
-
activeFilePath = paths.active;
|
|
203
|
-
historyFilePath = paths.history;
|
|
204
|
-
writing = false;
|
|
205
|
-
waiters = [];
|
|
206
|
-
}
|
|
207
|
-
/** Test-only: clear config + queue so each suite starts clean. */
|
|
208
|
-
function resetNotifier() {
|
|
209
|
-
config = null;
|
|
210
|
-
activeFilePath = "";
|
|
211
|
-
historyFilePath = "";
|
|
212
|
-
writing = false;
|
|
213
|
-
waiters = [];
|
|
214
|
-
listeners.length = 0;
|
|
215
|
-
}
|
|
216
|
-
function requireWriteJson() {
|
|
217
|
-
if (!config) throw new Error("notifier: configureNotifier() not called");
|
|
218
|
-
return config.writeJson;
|
|
219
|
-
}
|
|
220
|
-
function applyBatchMutations(batch, state) {
|
|
221
|
-
return batch.map((waiter) => {
|
|
222
|
-
try {
|
|
223
|
-
return {
|
|
224
|
-
ok: true,
|
|
225
|
-
outcome: waiter.mutate(state)
|
|
226
|
-
};
|
|
227
|
-
} catch (err) {
|
|
228
|
-
return {
|
|
229
|
-
ok: false,
|
|
230
|
-
error: err
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
function collectEvents(results) {
|
|
236
|
-
const events = [];
|
|
237
|
-
for (const result of results) if (result.ok && result.outcome !== null) events.push(result.outcome.event);
|
|
238
|
-
return events;
|
|
239
|
-
}
|
|
240
|
-
function collectHistoryEntries(results) {
|
|
241
|
-
const entries = [];
|
|
242
|
-
for (const result of results) if (result.ok && result.outcome !== null && result.outcome.historyEntry) entries.push(result.outcome.historyEntry);
|
|
243
|
-
return entries;
|
|
244
|
-
}
|
|
245
|
-
function settleBatch(batch, results) {
|
|
246
|
-
for (let index = 0; index < batch.length; index += 1) {
|
|
247
|
-
const result = results[index];
|
|
248
|
-
if (result.ok) batch[index].resolve();
|
|
249
|
-
else batch[index].reject(result.error);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
function rejectBatch(batch, err) {
|
|
253
|
-
for (const waiter of batch) waiter.reject(err);
|
|
254
|
-
}
|
|
255
|
-
async function persistHistory(newEntries) {
|
|
256
|
-
const existing = await loadHistory(historyFilePath);
|
|
257
|
-
const merged = [...newEntries.slice().reverse(), ...existing.entries].slice(0, 50);
|
|
258
|
-
await saveHistory(requireWriteJson(), historyFilePath, { entries: merged });
|
|
259
|
-
}
|
|
260
|
-
async function processBatch(batch) {
|
|
261
|
-
let state;
|
|
262
|
-
try {
|
|
263
|
-
state = await loadActive(activeFilePath);
|
|
264
|
-
} catch (err) {
|
|
265
|
-
logger().error("load failed", { error: String(err) });
|
|
266
|
-
rejectBatch(batch, err);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const results = applyBatchMutations(batch, state);
|
|
270
|
-
const events = collectEvents(results);
|
|
271
|
-
const historyEntries = collectHistoryEntries(results);
|
|
272
|
-
if (events.length > 0) {
|
|
273
|
-
try {
|
|
274
|
-
await saveActive(requireWriteJson(), activeFilePath, state);
|
|
275
|
-
} catch (err) {
|
|
276
|
-
logger().error("active write failed", { error: String(err) });
|
|
277
|
-
rejectBatch(batch, err);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
if (historyEntries.length > 0) try {
|
|
281
|
-
await persistHistory(historyEntries);
|
|
282
|
-
} catch (err) {
|
|
283
|
-
logger().error("history write failed", { error: String(err) });
|
|
284
|
-
}
|
|
285
|
-
for (const event of events) emit(event);
|
|
286
|
-
}
|
|
287
|
-
settleBatch(batch, results);
|
|
288
|
-
}
|
|
289
|
-
async function drain() {
|
|
290
|
-
writing = true;
|
|
291
|
-
try {
|
|
292
|
-
while (waiters.length > 0) {
|
|
293
|
-
const batch = waiters;
|
|
294
|
-
waiters = [];
|
|
295
|
-
await processBatch(batch);
|
|
296
|
-
}
|
|
297
|
-
} finally {
|
|
298
|
-
writing = false;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function enqueue(mutate) {
|
|
302
|
-
return new Promise((resolve, reject) => {
|
|
303
|
-
waiters.push({
|
|
304
|
-
mutate,
|
|
305
|
-
resolve,
|
|
306
|
-
reject
|
|
307
|
-
});
|
|
308
|
-
if (!writing) drain();
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
function removeEntry(state, entryId) {
|
|
312
|
-
const { [entryId]: __removed, ...remaining } = state.entries;
|
|
313
|
-
return remaining;
|
|
314
|
-
}
|
|
315
|
-
function buildHistoryEntry(entry, terminalType) {
|
|
316
|
-
return {
|
|
317
|
-
...entry,
|
|
318
|
-
terminalType,
|
|
319
|
-
terminalAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
async function publish(input) {
|
|
323
|
-
const validationError = validatePublishInput(input);
|
|
324
|
-
if (validationError) throw new Error(`notifier.publish: ${validationError}`);
|
|
325
|
-
const entryId = (0, node_crypto.randomUUID)();
|
|
326
|
-
const entry = {
|
|
327
|
-
id: entryId,
|
|
328
|
-
pluginPkg: input.pluginPkg,
|
|
329
|
-
severity: input.severity,
|
|
330
|
-
lifecycle: input.lifecycle,
|
|
331
|
-
title: input.title,
|
|
332
|
-
body: input.body,
|
|
333
|
-
navigateTarget: input.navigateTarget,
|
|
334
|
-
pluginData: input.pluginData,
|
|
335
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
336
|
-
};
|
|
337
|
-
await enqueue((state) => {
|
|
338
|
-
state.entries[entryId] = entry;
|
|
339
|
-
return { event: {
|
|
340
|
-
type: "published",
|
|
341
|
-
entry
|
|
342
|
-
} };
|
|
343
|
-
});
|
|
344
|
-
return { id: entryId };
|
|
345
|
-
}
|
|
346
|
-
async function clear(entryId) {
|
|
347
|
-
await enqueue((state) => {
|
|
348
|
-
const entry = state.entries[entryId];
|
|
349
|
-
if (!entry) return null;
|
|
350
|
-
state.entries = removeEntry(state, entryId);
|
|
351
|
-
return {
|
|
352
|
-
event: {
|
|
353
|
-
type: "cleared",
|
|
354
|
-
id: entryId
|
|
355
|
-
},
|
|
356
|
-
historyEntry: buildHistoryEntry(entry, "cleared")
|
|
357
|
-
};
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
async function cancel(entryId) {
|
|
361
|
-
await enqueue((state) => {
|
|
362
|
-
const entry = state.entries[entryId];
|
|
363
|
-
if (!entry) return null;
|
|
364
|
-
state.entries = removeEntry(state, entryId);
|
|
365
|
-
return {
|
|
366
|
-
event: {
|
|
367
|
-
type: "cancelled",
|
|
368
|
-
id: entryId
|
|
369
|
-
},
|
|
370
|
-
historyEntry: buildHistoryEntry(entry, "cancelled")
|
|
371
|
-
};
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
/** In-place update for an active entry. Only the fields present on
|
|
375
|
-
* `patch` are rewritten; `id`, `pluginPkg`, `lifecycle`, and
|
|
376
|
-
* `createdAt` stay fixed. Emits a single `"updated"` event with the
|
|
377
|
-
* post-mutation entry — no history record is written because the
|
|
378
|
-
* entry is still active, just with refreshed content.
|
|
379
|
-
*
|
|
380
|
-
* No-ops (no throw) when the id is unknown, the entry belongs to a
|
|
381
|
-
* different plugin, or the merged shape would violate
|
|
382
|
-
* `validatePublishInput`. The silent skip matches `clearForPlugin`'s
|
|
383
|
-
* isolation semantics; validation failures are logged for diagnosis. */
|
|
384
|
-
async function updateForPlugin(pluginPkg, entryId, patch) {
|
|
385
|
-
await enqueue((state) => {
|
|
386
|
-
const entry = state.entries[entryId];
|
|
387
|
-
if (!entry) return null;
|
|
388
|
-
if (entry.pluginPkg !== pluginPkg) return null;
|
|
389
|
-
const next = {
|
|
390
|
-
...entry,
|
|
391
|
-
...patch.severity !== void 0 ? { severity: patch.severity } : {},
|
|
392
|
-
...patch.title !== void 0 ? { title: patch.title } : {},
|
|
393
|
-
...patch.body !== void 0 ? { body: patch.body } : {},
|
|
394
|
-
...patch.navigateTarget !== void 0 ? { navigateTarget: patch.navigateTarget } : {},
|
|
395
|
-
...patch.pluginData !== void 0 ? { pluginData: patch.pluginData } : {}
|
|
396
|
-
};
|
|
397
|
-
const validationError = validatePublishInput({
|
|
398
|
-
pluginPkg: next.pluginPkg,
|
|
399
|
-
severity: next.severity,
|
|
400
|
-
title: next.title,
|
|
401
|
-
body: next.body,
|
|
402
|
-
lifecycle: next.lifecycle,
|
|
403
|
-
navigateTarget: next.navigateTarget,
|
|
404
|
-
pluginData: next.pluginData
|
|
405
|
-
});
|
|
406
|
-
if (validationError) {
|
|
407
|
-
logger().warn("update rejected by validation", {
|
|
408
|
-
entryId,
|
|
409
|
-
pluginPkg,
|
|
410
|
-
error: validationError
|
|
411
|
-
});
|
|
412
|
-
return null;
|
|
413
|
-
}
|
|
414
|
-
state.entries[entryId] = next;
|
|
415
|
-
return { event: {
|
|
416
|
-
type: "updated",
|
|
417
|
-
entry: next
|
|
418
|
-
} };
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
/** Plugin-scoped point lookup. Returns the entry by id, but only if it
|
|
422
|
-
* belongs to the caller's plugin; otherwise undefined. Cross-plugin
|
|
423
|
-
* reads return undefined for isolation — same property as
|
|
424
|
-
* `clearForPlugin` / `updateForPlugin`. */
|
|
425
|
-
async function getForPlugin(pluginPkg, entryId) {
|
|
426
|
-
const entry = (await loadActive(activeFilePath)).entries[entryId];
|
|
427
|
-
if (!entry) return void 0;
|
|
428
|
-
if (entry.pluginPkg !== pluginPkg) return void 0;
|
|
429
|
-
return entry;
|
|
430
|
-
}
|
|
431
|
-
/** Plugin-scoped clear. Same as `clear` but no-ops if the entry's
|
|
432
|
-
* `pluginPkg` doesn't match the caller's, so a plugin can't dismiss
|
|
433
|
-
* another plugin's notification by guessing or scraping its id. */
|
|
434
|
-
async function clearForPlugin(pluginPkg, entryId) {
|
|
435
|
-
await enqueue((state) => {
|
|
436
|
-
const entry = state.entries[entryId];
|
|
437
|
-
if (!entry) return null;
|
|
438
|
-
if (entry.pluginPkg !== pluginPkg) return null;
|
|
439
|
-
state.entries = removeEntry(state, entryId);
|
|
440
|
-
return {
|
|
441
|
-
event: {
|
|
442
|
-
type: "cleared",
|
|
443
|
-
id: entryId
|
|
444
|
-
},
|
|
445
|
-
historyEntry: buildHistoryEntry(entry, "cleared")
|
|
446
|
-
};
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
async function get(entryId) {
|
|
450
|
-
return (await loadActive(activeFilePath)).entries[entryId];
|
|
451
|
-
}
|
|
452
|
-
async function listFor(pluginPkg) {
|
|
453
|
-
const state = await loadActive(activeFilePath);
|
|
454
|
-
return Object.values(state.entries).filter((entry) => entry.pluginPkg === pluginPkg);
|
|
455
|
-
}
|
|
456
|
-
async function listAll() {
|
|
457
|
-
const state = await loadActive(activeFilePath);
|
|
458
|
-
return Object.values(state.entries);
|
|
459
|
-
}
|
|
460
|
-
async function listHistory() {
|
|
461
|
-
return (await loadHistory(historyFilePath)).entries;
|
|
462
|
-
}
|
|
463
|
-
//#endregion
|
|
464
|
-
exports.HISTORY_CAP = HISTORY_CAP;
|
|
465
|
-
exports.NOTIFIER_LIFECYCLES = NOTIFIER_LIFECYCLES;
|
|
466
|
-
exports.NOTIFIER_LIMITS = NOTIFIER_LIMITS;
|
|
467
|
-
exports.NOTIFIER_SEVERITIES = NOTIFIER_SEVERITIES;
|
|
468
|
-
exports.cancel = cancel;
|
|
469
|
-
exports.clear = clear;
|
|
470
|
-
exports.clearForPlugin = clearForPlugin;
|
|
471
|
-
exports.configureNotifier = configureNotifier;
|
|
472
|
-
exports.get = get;
|
|
473
|
-
exports.getForPlugin = getForPlugin;
|
|
474
|
-
exports.listAll = listAll;
|
|
475
|
-
exports.listFor = listFor;
|
|
476
|
-
exports.listHistory = listHistory;
|
|
477
|
-
exports.onEvent = onEvent;
|
|
478
|
-
exports.publish = publish;
|
|
479
|
-
exports.resetNotifier = resetNotifier;
|
|
480
|
-
exports.setNotifierFilePaths = setNotifierFilePaths;
|
|
481
|
-
exports.updateForPlugin = updateForPlugin;
|
|
482
|
-
exports.validatePublishInput = validatePublishInput;
|
|
483
|
-
|
|
484
|
-
//# sourceMappingURL=index.cjs.map
|
|
2
|
+
const require_notifier = require("../notifier-lJ4v2Y6B.cjs");
|
|
3
|
+
exports.HISTORY_CAP = require_notifier.HISTORY_CAP;
|
|
4
|
+
exports.NOTIFIER_LIFECYCLES = require_notifier.NOTIFIER_LIFECYCLES;
|
|
5
|
+
exports.NOTIFIER_LIMITS = require_notifier.NOTIFIER_LIMITS;
|
|
6
|
+
exports.NOTIFIER_SEVERITIES = require_notifier.NOTIFIER_SEVERITIES;
|
|
7
|
+
exports.cancel = require_notifier.cancel;
|
|
8
|
+
exports.clear = require_notifier.clear;
|
|
9
|
+
exports.clearForPlugin = require_notifier.clearForPlugin;
|
|
10
|
+
exports.configureNotifier = require_notifier.configureNotifier;
|
|
11
|
+
exports.get = require_notifier.get;
|
|
12
|
+
exports.getForPlugin = require_notifier.getForPlugin;
|
|
13
|
+
exports.listAll = require_notifier.listAll;
|
|
14
|
+
exports.listFor = require_notifier.listFor;
|
|
15
|
+
exports.listHistory = require_notifier.listHistory;
|
|
16
|
+
exports.onEvent = require_notifier.onEvent;
|
|
17
|
+
exports.publish = require_notifier.publish;
|
|
18
|
+
exports.resetNotifier = require_notifier.resetNotifier;
|
|
19
|
+
exports.setNotifierFilePaths = require_notifier.setNotifierFilePaths;
|
|
20
|
+
exports.updateForPlugin = require_notifier.updateForPlugin;
|
|
21
|
+
exports.validatePublishInput = require_notifier.validatePublishInput;
|