@mneme-ai/core 2.0.0 → 2.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/adversarial_twins/index.d.ts +52 -0
- package/dist/adversarial_twins/index.d.ts.map +1 -0
- package/dist/adversarial_twins/index.js +58 -0
- package/dist/adversarial_twins/index.js.map +1 -0
- package/dist/adversarial_twins/twins.test.d.ts +2 -0
- package/dist/adversarial_twins/twins.test.d.ts.map +1 -0
- package/dist/adversarial_twins/twins.test.js +66 -0
- package/dist/adversarial_twins/twins.test.js.map +1 -0
- package/dist/gladiator/gladiator.test.d.ts +2 -0
- package/dist/gladiator/gladiator.test.d.ts.map +1 -0
- package/dist/gladiator/gladiator.test.js +145 -0
- package/dist/gladiator/gladiator.test.js.map +1 -0
- package/dist/gladiator/index.d.ts +181 -0
- package/dist/gladiator/index.d.ts.map +1 -0
- package/dist/gladiator/index.js +192 -0
- package/dist/gladiator/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/interstellar/index.d.ts +77 -0
- package/dist/interstellar/index.d.ts.map +1 -0
- package/dist/interstellar/index.js +84 -0
- package/dist/interstellar/index.js.map +1 -0
- package/dist/interstellar/interstellar.test.d.ts +2 -0
- package/dist/interstellar/interstellar.test.d.ts.map +1 -0
- package/dist/interstellar/interstellar.test.js +69 -0
- package/dist/interstellar/interstellar.test.js.map +1 -0
- package/dist/living_will/index.d.ts +60 -0
- package/dist/living_will/index.d.ts.map +1 -0
- package/dist/living_will/index.js +66 -0
- package/dist/living_will/index.js.map +1 -0
- package/dist/living_will/living_will.test.d.ts +2 -0
- package/dist/living_will/living_will.test.d.ts.map +1 -0
- package/dist/living_will/living_will.test.js +74 -0
- package/dist/living_will/living_will.test.js.map +1 -0
- package/dist/necromancy/index.d.ts +52 -0
- package/dist/necromancy/index.d.ts.map +1 -0
- package/dist/necromancy/index.js +126 -0
- package/dist/necromancy/index.js.map +1 -0
- package/dist/necromancy/necromancy.test.d.ts +2 -0
- package/dist/necromancy/necromancy.test.d.ts.map +1 -0
- package/dist/necromancy/necromancy.test.js +50 -0
- package/dist/necromancy/necromancy.test.js.map +1 -0
- package/dist/prophet/index.d.ts +47 -0
- package/dist/prophet/index.d.ts.map +1 -0
- package/dist/prophet/index.js +46 -0
- package/dist/prophet/index.js.map +1 -0
- package/dist/prophet/prophet.test.d.ts +2 -0
- package/dist/prophet/prophet.test.d.ts.map +1 -0
- package/dist/prophet/prophet.test.js +37 -0
- package/dist/prophet/prophet.test.js.map +1 -0
- package/dist/tool_selector/index.d.ts +86 -0
- package/dist/tool_selector/index.d.ts.map +1 -0
- package/dist/tool_selector/index.js +188 -0
- package/dist/tool_selector/index.js.map +1 -0
- package/dist/tool_selector/tool_selector.test.d.ts +2 -0
- package/dist/tool_selector/tool_selector.test.d.ts.map +1 -0
- package/dist/tool_selector/tool_selector.test.js +59 -0
- package/dist/tool_selector/tool_selector.test.js.map +1 -0
- package/dist/wisdom_shards/index.d.ts +62 -0
- package/dist/wisdom_shards/index.d.ts.map +1 -0
- package/dist/wisdom_shards/index.js +69 -0
- package/dist/wisdom_shards/index.js.map +1 -0
- package/dist/wisdom_shards/wisdom_shards.test.d.ts +2 -0
- package/dist/wisdom_shards/wisdom_shards.test.d.ts.map +1 -0
- package/dist/wisdom_shards/wisdom_shards.test.js +69 -0
- package/dist/wisdom_shards/wisdom_shards.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- LIVING WILL · time-locked cryptographic dead-man primitive
|
|
3
|
+
*
|
|
4
|
+
* User encrypts a payload + sets an inactivity timer. If no activity is
|
|
5
|
+
* recorded for the threshold period, the payload becomes releasable
|
|
6
|
+
* (HMAC-verified). What the payload CONTAINS and what HAPPENS when it's
|
|
7
|
+
* released are the caller's responsibility — Mneme ships only the
|
|
8
|
+
* cryptographic primitive.
|
|
9
|
+
*
|
|
10
|
+
* Use cases (caller-defined):
|
|
11
|
+
* "if no activity 90 days → publish my CHANGELOG as a final commit"
|
|
12
|
+
* "if no activity 365 days → email my partner my keys"
|
|
13
|
+
* "if no activity 30 days → hand repo ownership to John"
|
|
14
|
+
*
|
|
15
|
+
* IMPORTANT: this is the TECHNICAL primitive. Mneme makes NO claim about
|
|
16
|
+
* legal estate effect. Estate law is jurisdiction-specific. Use real
|
|
17
|
+
* legal counsel for legal effect.
|
|
18
|
+
*/
|
|
19
|
+
export interface LivingWill {
|
|
20
|
+
/** Stable id (12-hex). */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Wall-clock when sealed. */
|
|
23
|
+
sealedAt: number;
|
|
24
|
+
/** Required inactivity in ms. */
|
|
25
|
+
inactivityThresholdMs: number;
|
|
26
|
+
/** Last recorded activity (defaults to sealedAt). */
|
|
27
|
+
lastActivityAt: number;
|
|
28
|
+
/** Free-form description for the human. */
|
|
29
|
+
description: string;
|
|
30
|
+
/** Encrypted payload (caller-supplied — Mneme stores opaque bytes hex-encoded). */
|
|
31
|
+
encryptedPayloadHex: string;
|
|
32
|
+
/** HMAC over (id || sealedAt || inactivityThresholdMs || encryptedPayloadHex). */
|
|
33
|
+
signature: string;
|
|
34
|
+
/** Public key fingerprint. */
|
|
35
|
+
keyFingerprint: string;
|
|
36
|
+
}
|
|
37
|
+
export interface CreateWillInput {
|
|
38
|
+
/** Days of inactivity before release becomes possible. */
|
|
39
|
+
inactivityDays: number;
|
|
40
|
+
description: string;
|
|
41
|
+
/** Caller-supplied encrypted payload as bytes. */
|
|
42
|
+
encryptedPayload: Buffer;
|
|
43
|
+
secret: Buffer;
|
|
44
|
+
}
|
|
45
|
+
export declare function createLivingWill(input: CreateWillInput): LivingWill;
|
|
46
|
+
/** Record activity — resets the inactivity timer. Returns a new envelope
|
|
47
|
+
* with lastActivityAt updated + a fresh signature. */
|
|
48
|
+
export declare function recordActivity(will: LivingWill, secret: Buffer, now?: number): LivingWill;
|
|
49
|
+
export type ReleaseVerdict = "ACTIVE" | "RELEASABLE" | "TAMPERED" | "WRONG_KEY";
|
|
50
|
+
export interface ReleaseCheckResult {
|
|
51
|
+
verdict: ReleaseVerdict;
|
|
52
|
+
reason: string;
|
|
53
|
+
/** When the will would become releasable. */
|
|
54
|
+
releasableAt: number;
|
|
55
|
+
/** Payload — only set on RELEASABLE. */
|
|
56
|
+
payloadHex?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function checkRelease(will: LivingWill, secret: Buffer, now?: number): ReleaseCheckResult;
|
|
59
|
+
export declare function formatLivingWillPulseLine(will: LivingWill, now?: number): string;
|
|
60
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/living_will/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,WAAW,UAAU;IACzB,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAUD,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CAgBnE;AAED;uDACuD;AACvD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,UAAU,CAErG;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,kBAAkB,CAa3G;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAG5F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- LIVING WILL · time-locked cryptographic dead-man primitive
|
|
3
|
+
*
|
|
4
|
+
* User encrypts a payload + sets an inactivity timer. If no activity is
|
|
5
|
+
* recorded for the threshold period, the payload becomes releasable
|
|
6
|
+
* (HMAC-verified). What the payload CONTAINS and what HAPPENS when it's
|
|
7
|
+
* released are the caller's responsibility — Mneme ships only the
|
|
8
|
+
* cryptographic primitive.
|
|
9
|
+
*
|
|
10
|
+
* Use cases (caller-defined):
|
|
11
|
+
* "if no activity 90 days → publish my CHANGELOG as a final commit"
|
|
12
|
+
* "if no activity 365 days → email my partner my keys"
|
|
13
|
+
* "if no activity 30 days → hand repo ownership to John"
|
|
14
|
+
*
|
|
15
|
+
* IMPORTANT: this is the TECHNICAL primitive. Mneme makes NO claim about
|
|
16
|
+
* legal estate effect. Estate law is jurisdiction-specific. Use real
|
|
17
|
+
* legal counsel for legal effect.
|
|
18
|
+
*/
|
|
19
|
+
import { createHmac, createHash, randomBytes } from "node:crypto";
|
|
20
|
+
function fpSecret(secret) {
|
|
21
|
+
return createHash("sha256").update(secret).digest("hex").slice(0, 16);
|
|
22
|
+
}
|
|
23
|
+
function computeSig(id, sealedAt, inactivityThresholdMs, encryptedPayloadHex, secret) {
|
|
24
|
+
return createHmac("sha256", secret).update(`${id}|${sealedAt}|${inactivityThresholdMs}|${encryptedPayloadHex}`).digest("hex");
|
|
25
|
+
}
|
|
26
|
+
export function createLivingWill(input) {
|
|
27
|
+
const sealedAt = Date.now();
|
|
28
|
+
const inactivityThresholdMs = input.inactivityDays * 24 * 60 * 60 * 1000;
|
|
29
|
+
const encryptedPayloadHex = input.encryptedPayload.toString("hex");
|
|
30
|
+
const id = randomBytes(6).toString("hex");
|
|
31
|
+
const signature = computeSig(id, sealedAt, inactivityThresholdMs, encryptedPayloadHex, input.secret);
|
|
32
|
+
return {
|
|
33
|
+
id,
|
|
34
|
+
sealedAt,
|
|
35
|
+
inactivityThresholdMs,
|
|
36
|
+
lastActivityAt: sealedAt,
|
|
37
|
+
description: input.description,
|
|
38
|
+
encryptedPayloadHex,
|
|
39
|
+
signature,
|
|
40
|
+
keyFingerprint: fpSecret(input.secret),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Record activity — resets the inactivity timer. Returns a new envelope
|
|
44
|
+
* with lastActivityAt updated + a fresh signature. */
|
|
45
|
+
export function recordActivity(will, secret, now = Date.now()) {
|
|
46
|
+
return { ...will, lastActivityAt: now, signature: computeSig(will.id, will.sealedAt, will.inactivityThresholdMs, will.encryptedPayloadHex, secret) };
|
|
47
|
+
}
|
|
48
|
+
export function checkRelease(will, secret, now = Date.now()) {
|
|
49
|
+
if (fpSecret(secret) !== will.keyFingerprint) {
|
|
50
|
+
return { verdict: "WRONG_KEY", reason: "secret fingerprint mismatch", releasableAt: will.lastActivityAt + will.inactivityThresholdMs };
|
|
51
|
+
}
|
|
52
|
+
const expected = computeSig(will.id, will.sealedAt, will.inactivityThresholdMs, will.encryptedPayloadHex, secret);
|
|
53
|
+
if (expected !== will.signature) {
|
|
54
|
+
return { verdict: "TAMPERED", reason: "signature mismatch", releasableAt: will.lastActivityAt + will.inactivityThresholdMs };
|
|
55
|
+
}
|
|
56
|
+
const releasableAt = will.lastActivityAt + will.inactivityThresholdMs;
|
|
57
|
+
if (now < releasableAt) {
|
|
58
|
+
return { verdict: "ACTIVE", reason: `inactivity timer has ${Math.round((releasableAt - now) / (24 * 60 * 60 * 1000))} day(s) remaining`, releasableAt };
|
|
59
|
+
}
|
|
60
|
+
return { verdict: "RELEASABLE", reason: `inactivity threshold passed (${Math.round((now - releasableAt) / (24 * 60 * 60 * 1000))} day(s) overdue)`, releasableAt, payloadHex: will.encryptedPayloadHex };
|
|
61
|
+
}
|
|
62
|
+
export function formatLivingWillPulseLine(will, now = Date.now()) {
|
|
63
|
+
const daysRemaining = Math.max(0, Math.round((will.lastActivityAt + will.inactivityThresholdMs - now) / (24 * 60 * 60 * 1000)));
|
|
64
|
+
return `LIVING-WILL · ${will.id} · ${daysRemaining}d to release · "${will.description.slice(0, 50)}"`;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/living_will/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"living_will.test.d.ts","sourceRoot":"","sources":["../../src/living_will/living_will.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { createLivingWill, recordActivity, checkRelease, formatLivingWillPulseLine } from "./index.js";
|
|
4
|
+
describe("v2.1 LIVING WILL · cryptographic dead-man primitive", () => {
|
|
5
|
+
const secret = randomBytes(32);
|
|
6
|
+
it("create + check immediately = ACTIVE", () => {
|
|
7
|
+
const w = createLivingWill({
|
|
8
|
+
inactivityDays: 30,
|
|
9
|
+
description: "publish CHANGELOG on death",
|
|
10
|
+
encryptedPayload: Buffer.from("encrypted-payload-bytes"),
|
|
11
|
+
secret,
|
|
12
|
+
});
|
|
13
|
+
const r = checkRelease(w, secret);
|
|
14
|
+
expect(r.verdict).toBe("ACTIVE");
|
|
15
|
+
expect(r.reason).toContain("remaining");
|
|
16
|
+
});
|
|
17
|
+
it("becomes RELEASABLE after inactivity threshold passes", () => {
|
|
18
|
+
const w = createLivingWill({
|
|
19
|
+
inactivityDays: 30,
|
|
20
|
+
description: "x",
|
|
21
|
+
encryptedPayload: Buffer.from("x"),
|
|
22
|
+
secret,
|
|
23
|
+
});
|
|
24
|
+
const futureNow = w.lastActivityAt + 31 * 24 * 60 * 60 * 1000;
|
|
25
|
+
const r = checkRelease(w, secret, futureNow);
|
|
26
|
+
expect(r.verdict).toBe("RELEASABLE");
|
|
27
|
+
expect(r.payloadHex).toBeTruthy();
|
|
28
|
+
});
|
|
29
|
+
it("recordActivity resets the timer", () => {
|
|
30
|
+
const w = createLivingWill({
|
|
31
|
+
inactivityDays: 30,
|
|
32
|
+
description: "x",
|
|
33
|
+
encryptedPayload: Buffer.from("x"),
|
|
34
|
+
secret,
|
|
35
|
+
});
|
|
36
|
+
// Far future
|
|
37
|
+
const futureNow = w.lastActivityAt + 31 * 24 * 60 * 60 * 1000;
|
|
38
|
+
expect(checkRelease(w, secret, futureNow).verdict).toBe("RELEASABLE");
|
|
39
|
+
// Record activity at the very end of the inactivity window
|
|
40
|
+
const w2 = recordActivity(w, secret, futureNow);
|
|
41
|
+
// Now check release immediately — should be ACTIVE again
|
|
42
|
+
expect(checkRelease(w2, secret, futureNow).verdict).toBe("ACTIVE");
|
|
43
|
+
});
|
|
44
|
+
it("TAMPERED verdict when signature is forged", () => {
|
|
45
|
+
const w = createLivingWill({
|
|
46
|
+
inactivityDays: 30,
|
|
47
|
+
description: "x",
|
|
48
|
+
encryptedPayload: Buffer.from("x"),
|
|
49
|
+
secret,
|
|
50
|
+
});
|
|
51
|
+
const tampered = { ...w, signature: "0".repeat(64) };
|
|
52
|
+
expect(checkRelease(tampered, secret).verdict).toBe("TAMPERED");
|
|
53
|
+
});
|
|
54
|
+
it("WRONG_KEY on wrong secret", () => {
|
|
55
|
+
const w = createLivingWill({
|
|
56
|
+
inactivityDays: 30,
|
|
57
|
+
description: "x",
|
|
58
|
+
encryptedPayload: Buffer.from("x"),
|
|
59
|
+
secret,
|
|
60
|
+
});
|
|
61
|
+
const wrong = randomBytes(32);
|
|
62
|
+
expect(checkRelease(w, wrong).verdict).toBe("WRONG_KEY");
|
|
63
|
+
});
|
|
64
|
+
it("formatLivingWillPulseLine produces compact summary", () => {
|
|
65
|
+
const w = createLivingWill({
|
|
66
|
+
inactivityDays: 30,
|
|
67
|
+
description: "publish on death",
|
|
68
|
+
encryptedPayload: Buffer.from("x"),
|
|
69
|
+
secret,
|
|
70
|
+
});
|
|
71
|
+
expect(formatLivingWillPulseLine(w)).toContain("LIVING-WILL");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=living_will.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"living_will.test.js","sourceRoot":"","sources":["../../src/living_will/living_will.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- NECROMANCY · style-fingerprint MVP
|
|
3
|
+
*
|
|
4
|
+
* Cannot resurrect deprecated AI vendors' models. That's a research
|
|
5
|
+
* project. But we CAN extract a deterministic STYLE FINGERPRINT from
|
|
6
|
+
* old chat logs — average sentence length, hedge ratio, emoji density,
|
|
7
|
+
* common closing phrases, signature catchphrases. The AI agent can
|
|
8
|
+
* then be prompted to respond IN that style for nostalgic continuity.
|
|
9
|
+
*
|
|
10
|
+
* Honest scope: this is stylometric mimicry, NOT model resurrection.
|
|
11
|
+
* The output reads "in the style of" — never claims to BE the dead AI.
|
|
12
|
+
*
|
|
13
|
+
* Pure function. Statistical. No external deps.
|
|
14
|
+
*/
|
|
15
|
+
export interface StyleFingerprint {
|
|
16
|
+
/** Sample id / vendor label e.g. "claude-1.0". */
|
|
17
|
+
vendorLabel: string;
|
|
18
|
+
/** Total characters analyzed. */
|
|
19
|
+
totalChars: number;
|
|
20
|
+
/** Total sentences analyzed. */
|
|
21
|
+
totalSentences: number;
|
|
22
|
+
/** Average sentence length in chars. */
|
|
23
|
+
avgSentenceLength: number;
|
|
24
|
+
/** Hedges per 100 sentences. */
|
|
25
|
+
hedgesPer100Sentences: number;
|
|
26
|
+
/** Absolutes per 100 sentences. */
|
|
27
|
+
absolutesPer100Sentences: number;
|
|
28
|
+
/** Emojis per 1k chars. */
|
|
29
|
+
emojisPer1k: number;
|
|
30
|
+
/** Common openers found, ordered by frequency. */
|
|
31
|
+
topOpeners: Array<{
|
|
32
|
+
phrase: string;
|
|
33
|
+
count: number;
|
|
34
|
+
}>;
|
|
35
|
+
/** Common closings found, ordered by frequency. */
|
|
36
|
+
topClosings: Array<{
|
|
37
|
+
phrase: string;
|
|
38
|
+
count: number;
|
|
39
|
+
}>;
|
|
40
|
+
/** Distinctive bigrams (rare-in-baseline pairs). */
|
|
41
|
+
signatureBigrams: string[];
|
|
42
|
+
/** Cosine-comparable feature vector (numeric). */
|
|
43
|
+
featureVector: number[];
|
|
44
|
+
}
|
|
45
|
+
export declare function extractStyleFingerprint(vendorLabel: string, chatLogs: readonly string[]): StyleFingerprint;
|
|
46
|
+
/** Cosine similarity between two style fingerprints. 1.0 = identical style. */
|
|
47
|
+
export declare function styleSimilarity(a: StyleFingerprint, b: StyleFingerprint): number;
|
|
48
|
+
/** Render the fingerprint as a "respond in style of X" prompt prefix
|
|
49
|
+
* that an AI agent can prepend to its system message. */
|
|
50
|
+
export declare function styleAsPromptPrefix(fp: StyleFingerprint): string;
|
|
51
|
+
export declare function formatNecromancyPulseLine(fp: StyleFingerprint): string;
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/necromancy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gCAAgC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mCAAmC;IACnC,wBAAwB,EAAE,MAAM,CAAC;IACjC,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,UAAU,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,mDAAmD;IACnD,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,oDAAoD;IACpD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kDAAkD;IAClD,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAwCD,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CA6B1G;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAYhF;AAED;0DAC0D;AAC1D,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,gBAAgB,GAAG,MAAM,CAShE;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,gBAAgB,GAAG,MAAM,CAEtE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- NECROMANCY · style-fingerprint MVP
|
|
3
|
+
*
|
|
4
|
+
* Cannot resurrect deprecated AI vendors' models. That's a research
|
|
5
|
+
* project. But we CAN extract a deterministic STYLE FINGERPRINT from
|
|
6
|
+
* old chat logs — average sentence length, hedge ratio, emoji density,
|
|
7
|
+
* common closing phrases, signature catchphrases. The AI agent can
|
|
8
|
+
* then be prompted to respond IN that style for nostalgic continuity.
|
|
9
|
+
*
|
|
10
|
+
* Honest scope: this is stylometric mimicry, NOT model resurrection.
|
|
11
|
+
* The output reads "in the style of" — never claims to BE the dead AI.
|
|
12
|
+
*
|
|
13
|
+
* Pure function. Statistical. No external deps.
|
|
14
|
+
*/
|
|
15
|
+
const HEDGE_PATTERNS = [/\bmaybe\b/gi, /\bperhaps\b/gi, /\bI think\b/gi, /\bI believe\b/gi];
|
|
16
|
+
const ABSOLUTE_PATTERNS = [/\balways\b/gi, /\bnever\b/gi, /\bdefinitely\b/gi];
|
|
17
|
+
const EMOJI_RE = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu;
|
|
18
|
+
const COMMON_OPENERS = ["sure", "of course", "absolutely", "let me", "here's", "great question", "i'd be happy to"];
|
|
19
|
+
const COMMON_CLOSINGS = ["let me know", "hope this helps", "happy to", "any other questions", "good luck"];
|
|
20
|
+
function countMatches(text, patterns) {
|
|
21
|
+
let n = 0;
|
|
22
|
+
for (const p of patterns) {
|
|
23
|
+
const re = new RegExp(p.source, p.flags);
|
|
24
|
+
const m = text.match(re);
|
|
25
|
+
if (m)
|
|
26
|
+
n += m.length;
|
|
27
|
+
}
|
|
28
|
+
return n;
|
|
29
|
+
}
|
|
30
|
+
function topHits(text, phrases) {
|
|
31
|
+
const t = text.toLowerCase();
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const p of phrases) {
|
|
34
|
+
// Count occurrences
|
|
35
|
+
let count = 0;
|
|
36
|
+
let idx = 0;
|
|
37
|
+
while ((idx = t.indexOf(p, idx)) !== -1) {
|
|
38
|
+
count++;
|
|
39
|
+
idx += p.length;
|
|
40
|
+
}
|
|
41
|
+
if (count > 0)
|
|
42
|
+
out.push({ phrase: p, count });
|
|
43
|
+
}
|
|
44
|
+
return out.sort((a, b) => b.count - a.count);
|
|
45
|
+
}
|
|
46
|
+
function extractBigrams(text) {
|
|
47
|
+
const tokens = text.toLowerCase().split(/\W+/).filter((t) => t.length >= 3);
|
|
48
|
+
const seen = new Map();
|
|
49
|
+
for (let i = 0; i + 1 < tokens.length; i++) {
|
|
50
|
+
const bigram = `${tokens[i]} ${tokens[i + 1]}`;
|
|
51
|
+
seen.set(bigram, (seen.get(bigram) ?? 0) + 1);
|
|
52
|
+
}
|
|
53
|
+
// Distinctive = appears more than once but not super common
|
|
54
|
+
return [...seen.entries()]
|
|
55
|
+
.filter(([, c]) => c >= 2 && c <= 10)
|
|
56
|
+
.sort((a, b) => b[1] - a[1])
|
|
57
|
+
.slice(0, 10)
|
|
58
|
+
.map(([b]) => b);
|
|
59
|
+
}
|
|
60
|
+
export function extractStyleFingerprint(vendorLabel, chatLogs) {
|
|
61
|
+
const text = chatLogs.join("\n\n");
|
|
62
|
+
const sentences = text.split(/(?<=[.!?])\s+/).filter((s) => s.trim().length > 0);
|
|
63
|
+
const totalChars = text.length;
|
|
64
|
+
const totalSentences = sentences.length || 1;
|
|
65
|
+
const avgSentenceLength = totalChars / totalSentences;
|
|
66
|
+
const hedges = countMatches(text, HEDGE_PATTERNS);
|
|
67
|
+
const absolutes = countMatches(text, ABSOLUTE_PATTERNS);
|
|
68
|
+
const emojis = (text.match(EMOJI_RE) || []).length;
|
|
69
|
+
const topOpeners = topHits(text, COMMON_OPENERS).slice(0, 5);
|
|
70
|
+
const topClosings = topHits(text, COMMON_CLOSINGS).slice(0, 5);
|
|
71
|
+
const signatureBigrams = extractBigrams(text);
|
|
72
|
+
const hedgesPer100Sentences = (hedges / totalSentences) * 100;
|
|
73
|
+
const absolutesPer100Sentences = (absolutes / totalSentences) * 100;
|
|
74
|
+
const emojisPer1k = (emojis / Math.max(1, totalChars)) * 1000;
|
|
75
|
+
const featureVector = [avgSentenceLength, hedgesPer100Sentences, absolutesPer100Sentences, emojisPer1k];
|
|
76
|
+
return {
|
|
77
|
+
vendorLabel,
|
|
78
|
+
totalChars,
|
|
79
|
+
totalSentences,
|
|
80
|
+
avgSentenceLength: Math.round(avgSentenceLength * 100) / 100,
|
|
81
|
+
hedgesPer100Sentences: Math.round(hedgesPer100Sentences * 100) / 100,
|
|
82
|
+
absolutesPer100Sentences: Math.round(absolutesPer100Sentences * 100) / 100,
|
|
83
|
+
emojisPer1k: Math.round(emojisPer1k * 100) / 100,
|
|
84
|
+
topOpeners,
|
|
85
|
+
topClosings,
|
|
86
|
+
signatureBigrams,
|
|
87
|
+
featureVector,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Cosine similarity between two style fingerprints. 1.0 = identical style. */
|
|
91
|
+
export function styleSimilarity(a, b) {
|
|
92
|
+
const av = a.featureVector;
|
|
93
|
+
const bv = b.featureVector;
|
|
94
|
+
if (av.length !== bv.length || av.length === 0)
|
|
95
|
+
return 0;
|
|
96
|
+
let dot = 0, na = 0, nb = 0;
|
|
97
|
+
for (let i = 0; i < av.length; i++) {
|
|
98
|
+
dot += av[i] * bv[i];
|
|
99
|
+
na += av[i] * av[i];
|
|
100
|
+
nb += bv[i] * bv[i];
|
|
101
|
+
}
|
|
102
|
+
const denom = Math.sqrt(na) * Math.sqrt(nb);
|
|
103
|
+
return denom > 0 ? Math.max(-1, Math.min(1, dot / denom)) : 0;
|
|
104
|
+
}
|
|
105
|
+
/** Render the fingerprint as a "respond in style of X" prompt prefix
|
|
106
|
+
* that an AI agent can prepend to its system message. */
|
|
107
|
+
export function styleAsPromptPrefix(fp) {
|
|
108
|
+
const traits = [];
|
|
109
|
+
if (fp.avgSentenceLength > 100)
|
|
110
|
+
traits.push("verbose, multi-clause sentences");
|
|
111
|
+
else if (fp.avgSentenceLength < 50)
|
|
112
|
+
traits.push("short, punchy sentences");
|
|
113
|
+
if (fp.hedgesPer100Sentences > 20)
|
|
114
|
+
traits.push("hedged language ('maybe', 'I think')");
|
|
115
|
+
if (fp.absolutesPer100Sentences > 10)
|
|
116
|
+
traits.push("confident absolutes");
|
|
117
|
+
if (fp.emojisPer1k > 1)
|
|
118
|
+
traits.push("emoji-friendly");
|
|
119
|
+
if (fp.topClosings.length > 0)
|
|
120
|
+
traits.push(`signature closing: "${fp.topClosings[0].phrase}"`);
|
|
121
|
+
return `Respond in the style of "${fp.vendorLabel}": ${traits.join(" · ") || "neutral tone"}. (Stylometric mimicry only — not an actual resurrection of the model.)`;
|
|
122
|
+
}
|
|
123
|
+
export function formatNecromancyPulseLine(fp) {
|
|
124
|
+
return `NECROMANCY · ${fp.vendorLabel} · ${fp.totalSentences} sentences · avg=${fp.avgSentenceLength}ch · hedges/100=${fp.hedgesPer100Sentences} · emoji/1k=${fp.emojisPer1k}`;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/necromancy/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"necromancy.test.d.ts","sourceRoot":"","sources":["../../src/necromancy/necromancy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { extractStyleFingerprint, styleSimilarity, styleAsPromptPrefix, formatNecromancyPulseLine } from "./index.js";
|
|
3
|
+
describe("v2.1 NECROMANCY · stylometric fingerprint MVP", () => {
|
|
4
|
+
it("extracts fingerprint with sentence stats", () => {
|
|
5
|
+
const logs = [
|
|
6
|
+
"Sure, here's a thought. Maybe try this approach. I think it might work. Hope this helps!",
|
|
7
|
+
"Let me know if you need more. Of course, I'd be happy to help.",
|
|
8
|
+
];
|
|
9
|
+
const fp = extractStyleFingerprint("test-vendor", logs);
|
|
10
|
+
expect(fp.vendorLabel).toBe("test-vendor");
|
|
11
|
+
expect(fp.totalSentences).toBeGreaterThan(0);
|
|
12
|
+
expect(fp.hedgesPer100Sentences).toBeGreaterThan(0); // 'Maybe', 'I think'
|
|
13
|
+
expect(fp.topOpeners.length).toBeGreaterThan(0);
|
|
14
|
+
expect(fp.topClosings.length).toBeGreaterThan(0);
|
|
15
|
+
});
|
|
16
|
+
it("hedge-heavy text has higher hedgesPer100Sentences", () => {
|
|
17
|
+
const fp1 = extractStyleFingerprint("hedged", ["Maybe this. Perhaps that. I think so. I believe yes."]);
|
|
18
|
+
const fp2 = extractStyleFingerprint("absolute", ["Always do this. Never do that. Definitely correct."]);
|
|
19
|
+
expect(fp1.hedgesPer100Sentences).toBeGreaterThan(fp2.hedgesPer100Sentences);
|
|
20
|
+
expect(fp2.absolutesPer100Sentences).toBeGreaterThan(fp1.absolutesPer100Sentences);
|
|
21
|
+
});
|
|
22
|
+
it("featureVector is non-empty + numeric", () => {
|
|
23
|
+
const fp = extractStyleFingerprint("x", ["test message"]);
|
|
24
|
+
expect(fp.featureVector.length).toBeGreaterThan(0);
|
|
25
|
+
for (const v of fp.featureVector)
|
|
26
|
+
expect(typeof v).toBe("number");
|
|
27
|
+
});
|
|
28
|
+
it("styleSimilarity returns 1.0 for identical fingerprints", () => {
|
|
29
|
+
const fp = extractStyleFingerprint("x", ["hello world hello world"]);
|
|
30
|
+
expect(styleSimilarity(fp, fp)).toBeCloseTo(1, 5);
|
|
31
|
+
});
|
|
32
|
+
it("styleSimilarity returns a value 0..1 for different fingerprints", () => {
|
|
33
|
+
const a = extractStyleFingerprint("a", ["short."]);
|
|
34
|
+
const b = extractStyleFingerprint("b", ["Long verbose sentences with hedges maybe perhaps. I think this. I believe that."]);
|
|
35
|
+
const sim = styleSimilarity(a, b);
|
|
36
|
+
expect(sim).toBeGreaterThanOrEqual(-1);
|
|
37
|
+
expect(sim).toBeLessThanOrEqual(1);
|
|
38
|
+
});
|
|
39
|
+
it("styleAsPromptPrefix mentions vendor + traits", () => {
|
|
40
|
+
const fp = extractStyleFingerprint("bard-classic", ["Of course! Let me know if you need anything. Of course!"]);
|
|
41
|
+
const prefix = styleAsPromptPrefix(fp);
|
|
42
|
+
expect(prefix).toContain("bard-classic");
|
|
43
|
+
expect(prefix.toLowerCase()).toContain("stylometric mimicry");
|
|
44
|
+
});
|
|
45
|
+
it("formatNecromancyPulseLine summarises", () => {
|
|
46
|
+
const fp = extractStyleFingerprint("v", ["x. y."]);
|
|
47
|
+
expect(formatNecromancyPulseLine(fp)).toContain("NECROMANCY");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=necromancy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"necromancy.test.js","sourceRoot":"","sources":["../../src/necromancy/necromancy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- PROPHET · pre-fetch top-K next user queries
|
|
3
|
+
*
|
|
4
|
+
* v1.99 shipped Prompt-Q-Latency Engine (Markov prediction of next query
|
|
5
|
+
* class). PROPHET completes the loop: given a current query + history,
|
|
6
|
+
* (1) predict top-K next queries, (2) execute the pre-warm work for each
|
|
7
|
+
* (cache lookups, file reads, MCP probes), (3) cache the results so the
|
|
8
|
+
* AI's NEXT response is instant.
|
|
9
|
+
*
|
|
10
|
+
* Pure-function PREDICTOR. The pre-warm executor is a thin abstraction
|
|
11
|
+
* over caller-supplied hydration functions — keeps PROPHET stateless.
|
|
12
|
+
*/
|
|
13
|
+
import { type PredictionResult } from "../flash/predictive.js";
|
|
14
|
+
export interface PrewarmTask {
|
|
15
|
+
id: string;
|
|
16
|
+
/** Async work to run; returns whatever the caller wants cached. */
|
|
17
|
+
work: () => Promise<unknown>;
|
|
18
|
+
/** Optional tag for the trace. */
|
|
19
|
+
tag?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ProphetInput {
|
|
22
|
+
currentQuery: string;
|
|
23
|
+
lastAiReply: string;
|
|
24
|
+
/** Optional caller-supplied hydration: questionClass → tasks. */
|
|
25
|
+
hydrationMap?: Record<string, PrewarmTask[]>;
|
|
26
|
+
/** How many predicted classes to pre-warm. Default 3. */
|
|
27
|
+
topK?: number;
|
|
28
|
+
/** Time budget for pre-warm in ms. Default 5000. */
|
|
29
|
+
timeBudgetMs?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ProphetResult {
|
|
32
|
+
prediction: PredictionResult;
|
|
33
|
+
prewarmed: Array<{
|
|
34
|
+
classId: string;
|
|
35
|
+
taskId: string;
|
|
36
|
+
ok: boolean;
|
|
37
|
+
elapsedMs: number;
|
|
38
|
+
error?: string;
|
|
39
|
+
result?: unknown;
|
|
40
|
+
}>;
|
|
41
|
+
totalMs: number;
|
|
42
|
+
/** Cache-style map: classId → list of prewarmed results. */
|
|
43
|
+
cache: Map<string, unknown[]>;
|
|
44
|
+
}
|
|
45
|
+
export declare function prophesyAndPrewarm(input: ProphetInput): Promise<ProphetResult>;
|
|
46
|
+
export declare function formatProphetPulseLine(r: ProphetResult): string;
|
|
47
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prophet/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEjF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7C,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,SAAS,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxH,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;CAC/B;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CA2BpF;AAED,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAE/D"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.1.0 -- PROPHET · pre-fetch top-K next user queries
|
|
3
|
+
*
|
|
4
|
+
* v1.99 shipped Prompt-Q-Latency Engine (Markov prediction of next query
|
|
5
|
+
* class). PROPHET completes the loop: given a current query + history,
|
|
6
|
+
* (1) predict top-K next queries, (2) execute the pre-warm work for each
|
|
7
|
+
* (cache lookups, file reads, MCP probes), (3) cache the results so the
|
|
8
|
+
* AI's NEXT response is instant.
|
|
9
|
+
*
|
|
10
|
+
* Pure-function PREDICTOR. The pre-warm executor is a thin abstraction
|
|
11
|
+
* over caller-supplied hydration functions — keeps PROPHET stateless.
|
|
12
|
+
*/
|
|
13
|
+
import { predictNextQuery } from "../flash/predictive.js";
|
|
14
|
+
export async function prophesyAndPrewarm(input) {
|
|
15
|
+
const topK = input.topK ?? 3;
|
|
16
|
+
const budget = input.timeBudgetMs ?? 5000;
|
|
17
|
+
const prediction = predictNextQuery(input.lastAiReply, topK);
|
|
18
|
+
const tStart = Date.now();
|
|
19
|
+
const prewarmed = [];
|
|
20
|
+
const cache = new Map();
|
|
21
|
+
for (const p of prediction.predictions) {
|
|
22
|
+
if (Date.now() - tStart > budget)
|
|
23
|
+
break;
|
|
24
|
+
const tasks = input.hydrationMap?.[p.feature.id] ?? [];
|
|
25
|
+
const bucket = [];
|
|
26
|
+
for (const task of tasks) {
|
|
27
|
+
if (Date.now() - tStart > budget)
|
|
28
|
+
break;
|
|
29
|
+
const t0 = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
const result = await task.work();
|
|
32
|
+
bucket.push(result);
|
|
33
|
+
prewarmed.push({ classId: p.feature.id, taskId: task.id, ok: true, elapsedMs: Date.now() - t0, result });
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
prewarmed.push({ classId: p.feature.id, taskId: task.id, ok: false, elapsedMs: Date.now() - t0, error: e.message });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
cache.set(p.feature.id, bucket);
|
|
40
|
+
}
|
|
41
|
+
return { prediction, prewarmed, totalMs: Date.now() - tStart, cache };
|
|
42
|
+
}
|
|
43
|
+
export function formatProphetPulseLine(r) {
|
|
44
|
+
return `PROPHET · predicted=${r.prediction.predictions.length} · prewarmed=${r.prewarmed.length} ok=${r.prewarmed.filter((p) => p.ok).length} · ${r.totalMs}ms`;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prophet/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAyB,MAAM,wBAAwB,CAAC;AA6BjF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAmB;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC;IAC1C,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,SAAS,GAA+B,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE3C,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,MAAM;YAAE,MAAM;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACvD,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,MAAM;gBAAE,MAAM;YACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACpB,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3G,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;YACjI,CAAC;QACH,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,CAAgB;IACrD,OAAO,uBAAuB,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,MAAM,gBAAgB,CAAC,CAAC,SAAS,CAAC,MAAM,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,OAAO,IAAI,CAAC;AAClK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prophet.test.d.ts","sourceRoot":"","sources":["../../src/prophet/prophet.test.ts"],"names":[],"mappings":""}
|