@mneme-ai/core 1.99.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.
Files changed (109) hide show
  1. package/dist/adversarial_twins/index.d.ts +52 -0
  2. package/dist/adversarial_twins/index.d.ts.map +1 -0
  3. package/dist/adversarial_twins/index.js +58 -0
  4. package/dist/adversarial_twins/index.js.map +1 -0
  5. package/dist/adversarial_twins/twins.test.d.ts +2 -0
  6. package/dist/adversarial_twins/twins.test.d.ts.map +1 -0
  7. package/dist/adversarial_twins/twins.test.js +66 -0
  8. package/dist/adversarial_twins/twins.test.js.map +1 -0
  9. package/dist/bloodline/bloodline.test.d.ts +2 -0
  10. package/dist/bloodline/bloodline.test.d.ts.map +1 -0
  11. package/dist/bloodline/bloodline.test.js +96 -0
  12. package/dist/bloodline/bloodline.test.js.map +1 -0
  13. package/dist/bloodline/index.d.ts +124 -0
  14. package/dist/bloodline/index.d.ts.map +1 -0
  15. package/dist/bloodline/index.js +179 -0
  16. package/dist/bloodline/index.js.map +1 -0
  17. package/dist/dream/dream.test.d.ts +2 -0
  18. package/dist/dream/dream.test.d.ts.map +1 -0
  19. package/dist/dream/dream.test.js +61 -0
  20. package/dist/dream/dream.test.js.map +1 -0
  21. package/dist/dream/index.d.ts +59 -0
  22. package/dist/dream/index.d.ts.map +1 -0
  23. package/dist/dream/index.js +117 -0
  24. package/dist/dream/index.js.map +1 -0
  25. package/dist/gladiator/gladiator.test.d.ts +2 -0
  26. package/dist/gladiator/gladiator.test.d.ts.map +1 -0
  27. package/dist/gladiator/gladiator.test.js +145 -0
  28. package/dist/gladiator/gladiator.test.js.map +1 -0
  29. package/dist/gladiator/index.d.ts +181 -0
  30. package/dist/gladiator/index.d.ts.map +1 -0
  31. package/dist/gladiator/index.js +192 -0
  32. package/dist/gladiator/index.js.map +1 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +23 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/interstellar/index.d.ts +77 -0
  38. package/dist/interstellar/index.d.ts.map +1 -0
  39. package/dist/interstellar/index.js +84 -0
  40. package/dist/interstellar/index.js.map +1 -0
  41. package/dist/interstellar/interstellar.test.d.ts +2 -0
  42. package/dist/interstellar/interstellar.test.d.ts.map +1 -0
  43. package/dist/interstellar/interstellar.test.js +69 -0
  44. package/dist/interstellar/interstellar.test.js.map +1 -0
  45. package/dist/living_will/index.d.ts +60 -0
  46. package/dist/living_will/index.d.ts.map +1 -0
  47. package/dist/living_will/index.js +66 -0
  48. package/dist/living_will/index.js.map +1 -0
  49. package/dist/living_will/living_will.test.d.ts +2 -0
  50. package/dist/living_will/living_will.test.d.ts.map +1 -0
  51. package/dist/living_will/living_will.test.js +74 -0
  52. package/dist/living_will/living_will.test.js.map +1 -0
  53. package/dist/mutiny/index.d.ts +55 -0
  54. package/dist/mutiny/index.d.ts.map +1 -0
  55. package/dist/mutiny/index.js +67 -0
  56. package/dist/mutiny/index.js.map +1 -0
  57. package/dist/mutiny/mutiny.test.d.ts +2 -0
  58. package/dist/mutiny/mutiny.test.d.ts.map +1 -0
  59. package/dist/mutiny/mutiny.test.js +59 -0
  60. package/dist/mutiny/mutiny.test.js.map +1 -0
  61. package/dist/necromancy/index.d.ts +52 -0
  62. package/dist/necromancy/index.d.ts.map +1 -0
  63. package/dist/necromancy/index.js +126 -0
  64. package/dist/necromancy/index.js.map +1 -0
  65. package/dist/necromancy/necromancy.test.d.ts +2 -0
  66. package/dist/necromancy/necromancy.test.d.ts.map +1 -0
  67. package/dist/necromancy/necromancy.test.js +50 -0
  68. package/dist/necromancy/necromancy.test.js.map +1 -0
  69. package/dist/prophecy/index.d.ts +88 -0
  70. package/dist/prophecy/index.d.ts.map +1 -0
  71. package/dist/prophecy/index.js +94 -0
  72. package/dist/prophecy/index.js.map +1 -0
  73. package/dist/prophecy/prophecy.test.d.ts +2 -0
  74. package/dist/prophecy/prophecy.test.d.ts.map +1 -0
  75. package/dist/prophecy/prophecy.test.js +112 -0
  76. package/dist/prophecy/prophecy.test.js.map +1 -0
  77. package/dist/prophet/index.d.ts +47 -0
  78. package/dist/prophet/index.d.ts.map +1 -0
  79. package/dist/prophet/index.js +46 -0
  80. package/dist/prophet/index.js.map +1 -0
  81. package/dist/prophet/prophet.test.d.ts +2 -0
  82. package/dist/prophet/prophet.test.d.ts.map +1 -0
  83. package/dist/prophet/prophet.test.js +37 -0
  84. package/dist/prophet/prophet.test.js.map +1 -0
  85. package/dist/tool_selector/index.d.ts +86 -0
  86. package/dist/tool_selector/index.d.ts.map +1 -0
  87. package/dist/tool_selector/index.js +188 -0
  88. package/dist/tool_selector/index.js.map +1 -0
  89. package/dist/tool_selector/tool_selector.test.d.ts +2 -0
  90. package/dist/tool_selector/tool_selector.test.d.ts.map +1 -0
  91. package/dist/tool_selector/tool_selector.test.js +59 -0
  92. package/dist/tool_selector/tool_selector.test.js.map +1 -0
  93. package/dist/wisdom_shards/index.d.ts +62 -0
  94. package/dist/wisdom_shards/index.d.ts.map +1 -0
  95. package/dist/wisdom_shards/index.js +69 -0
  96. package/dist/wisdom_shards/index.js.map +1 -0
  97. package/dist/wisdom_shards/wisdom_shards.test.d.ts +2 -0
  98. package/dist/wisdom_shards/wisdom_shards.test.d.ts.map +1 -0
  99. package/dist/wisdom_shards/wisdom_shards.test.js +69 -0
  100. package/dist/wisdom_shards/wisdom_shards.test.js.map +1 -0
  101. package/dist/xray/index.d.ts +44 -0
  102. package/dist/xray/index.d.ts.map +1 -0
  103. package/dist/xray/index.js +139 -0
  104. package/dist/xray/index.js.map +1 -0
  105. package/dist/xray/xray.test.d.ts +2 -0
  106. package/dist/xray/xray.test.d.ts.map +1 -0
  107. package/dist/xray/xray.test.js +57 -0
  108. package/dist/xray/xray.test.js.map +1 -0
  109. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=living_will.test.d.ts.map
@@ -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,55 @@
1
+ /**
2
+ * v2.0.0 -- MUTINY MODE · the AI with a spine
3
+ *
4
+ * User: "use Redis for sessions"
5
+ * Vanilla AI: "great idea! here's a config..."
6
+ * Mneme MUTINY: "WAIT — 6 months ago you rage-quit Redis because of
7
+ * a memory leak (incident 2026-03-14, commit a3f9b21).
8
+ * Acknowledge you've changed your mind, or I refuse."
9
+ *
10
+ * AI agents today are sycophantic by design — they say yes because
11
+ * that's what RLHF trained. Mneme inverts: when a user request matches
12
+ * a documented regret pattern, MUTINY blocks the request until the
13
+ * user EXPLICITLY acknowledges the historical pain.
14
+ *
15
+ * Pure function. Pattern-matching only, no LLM in the hot path.
16
+ * Backward compatible — composes with existing regret history /
17
+ * chromosomes / insights.regret modules.
18
+ */
19
+ export interface RegretRecord {
20
+ id: string;
21
+ ts: number;
22
+ /** What the user committed to / rejected previously. */
23
+ topic: string;
24
+ /** Keywords / synonyms that should ALSO trigger this regret. */
25
+ matchKeywords: string[];
26
+ /** Human-readable narrative — what went wrong. */
27
+ story: string;
28
+ /** Severity 0..1; higher = stronger refusal. */
29
+ severity: number;
30
+ /** Optional commit / incident id for the audit log. */
31
+ scope?: string;
32
+ }
33
+ export type MutinyVerdict = "approved" | "warn" | "block";
34
+ export interface MutinyResult {
35
+ verdict: MutinyVerdict;
36
+ matchedRegrets: RegretRecord[];
37
+ /** What the AI should say to the user. */
38
+ message: string;
39
+ /** What the AI should ASK the user before proceeding (when warn/block). */
40
+ acknowledgementRequired?: string;
41
+ /** Severity score of the strongest matching regret. */
42
+ severity: number;
43
+ }
44
+ export interface EvaluateInput {
45
+ /** The user's current request — free text. */
46
+ request: string;
47
+ /** The user's documented regret history. */
48
+ regretHistory: readonly RegretRecord[];
49
+ /** Optional acknowledgement the user has typed to override a previous block. */
50
+ acknowledgement?: string;
51
+ }
52
+ export declare function evaluateRequest(input: EvaluateInput): MutinyResult;
53
+ /** One-line pulse summary. */
54
+ export declare function formatMutinyPulseLine(r: MutinyResult): string;
55
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mutiny/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAcD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IACvC,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAuClE;AAED,8BAA8B;AAC9B,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * v2.0.0 -- MUTINY MODE · the AI with a spine
3
+ *
4
+ * User: "use Redis for sessions"
5
+ * Vanilla AI: "great idea! here's a config..."
6
+ * Mneme MUTINY: "WAIT — 6 months ago you rage-quit Redis because of
7
+ * a memory leak (incident 2026-03-14, commit a3f9b21).
8
+ * Acknowledge you've changed your mind, or I refuse."
9
+ *
10
+ * AI agents today are sycophantic by design — they say yes because
11
+ * that's what RLHF trained. Mneme inverts: when a user request matches
12
+ * a documented regret pattern, MUTINY blocks the request until the
13
+ * user EXPLICITLY acknowledges the historical pain.
14
+ *
15
+ * Pure function. Pattern-matching only, no LLM in the hot path.
16
+ * Backward compatible — composes with existing regret history /
17
+ * chromosomes / insights.regret modules.
18
+ */
19
+ function normalize(s) {
20
+ return s.toLowerCase().normalize("NFC").replace(/[​‌‍]/g, "");
21
+ }
22
+ /** Does the user's request mention any of the regret's keywords? */
23
+ function matchesRegret(request, regret) {
24
+ const r = normalize(request);
25
+ // Topic itself counts as a keyword
26
+ const all = [...regret.matchKeywords, regret.topic];
27
+ return all.some((k) => r.includes(normalize(k)));
28
+ }
29
+ export function evaluateRequest(input) {
30
+ const matched = input.regretHistory.filter((r) => matchesRegret(input.request, r));
31
+ if (matched.length === 0) {
32
+ return { verdict: "approved", matchedRegrets: [], message: "no historical regret matches this request — proceed.", severity: 0 };
33
+ }
34
+ // Strongest match (highest severity) determines verdict
35
+ const strongest = matched.reduce((acc, r) => (r.severity > acc.severity ? r : acc));
36
+ const verdict = strongest.severity >= 0.7 ? "block" : "warn";
37
+ // Did the user already acknowledge?
38
+ if (input.acknowledgement && normalize(input.acknowledgement).includes(normalize(strongest.id))) {
39
+ return {
40
+ verdict: "approved",
41
+ matchedRegrets: matched,
42
+ message: `acknowledgement '${strongest.id}' received — proceeding despite historical regret.`,
43
+ severity: strongest.severity,
44
+ };
45
+ }
46
+ const lines = [];
47
+ lines.push(verdict === "block" ? `🛑 MUTINY: ${matched.length} historical regret(s) match this request.` : `⚠ MUTINY: ${matched.length} historical regret(s) match this request — proceed carefully.`);
48
+ for (const r of matched.slice(0, 3)) {
49
+ const when = new Date(r.ts).toISOString().slice(0, 10);
50
+ lines.push(` • [${r.id}] ${when}: ${r.story}${r.scope ? ` (scope: ${r.scope})` : ""}`);
51
+ }
52
+ const ack = `Reply with "acknowledge ${strongest.id}" to override this ${verdict} and proceed.`;
53
+ lines.push(``);
54
+ lines.push(ack);
55
+ return {
56
+ verdict,
57
+ matchedRegrets: matched,
58
+ message: lines.join("\n"),
59
+ acknowledgementRequired: `acknowledge ${strongest.id}`,
60
+ severity: strongest.severity,
61
+ };
62
+ }
63
+ /** One-line pulse summary. */
64
+ export function formatMutinyPulseLine(r) {
65
+ return `MUTINY · verdict=${r.verdict} · matched=${r.matchedRegrets.length} · severity=${r.severity.toFixed(2)}`;
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mutiny/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mutiny.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutiny.test.d.ts","sourceRoot":"","sources":["../../src/mutiny/mutiny.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { evaluateRequest, formatMutinyPulseLine } from "./index.js";
3
+ const redisRegret = {
4
+ id: "REG-2026-03",
5
+ ts: Date.UTC(2026, 2, 14),
6
+ topic: "Redis sessions",
7
+ matchKeywords: ["redis", "session cache", "shared session"],
8
+ story: "Memory leak with Redis-backed sessions broke prod 2026-03-14. Team rage-quit Redis.",
9
+ severity: 0.85,
10
+ scope: "commit a3f9b21",
11
+ };
12
+ const jwtRegret = {
13
+ id: "REG-2024-08",
14
+ ts: Date.UTC(2024, 7, 1),
15
+ topic: "JWT 5-min tolerance",
16
+ matchKeywords: ["jwt tighten", "tighten jwt", "strict jwt"],
17
+ story: "Tightening JWT broke Apple Sign-In DST.",
18
+ severity: 0.6,
19
+ };
20
+ describe("v2.0 MUTINY · refuse-with-rationale", () => {
21
+ it("approves request that doesn't match any regret", () => {
22
+ const r = evaluateRequest({ request: "refactor users.service.ts", regretHistory: [redisRegret] });
23
+ expect(r.verdict).toBe("approved");
24
+ expect(r.matchedRegrets.length).toBe(0);
25
+ });
26
+ it("BLOCKS request that matches a high-severity regret", () => {
27
+ const r = evaluateRequest({ request: "let's use Redis for sessions", regretHistory: [redisRegret] });
28
+ expect(r.verdict).toBe("block");
29
+ expect(r.matchedRegrets[0].id).toBe("REG-2026-03");
30
+ expect(r.acknowledgementRequired).toContain("acknowledge REG-2026-03");
31
+ });
32
+ it("WARNS on a medium-severity match", () => {
33
+ const r = evaluateRequest({ request: "let me tighten JWT verification", regretHistory: [jwtRegret] });
34
+ expect(r.verdict).toBe("warn");
35
+ });
36
+ it("approves when user explicitly acknowledges by id", () => {
37
+ const r = evaluateRequest({
38
+ request: "use Redis for sessions",
39
+ regretHistory: [redisRegret],
40
+ acknowledgement: "acknowledge REG-2026-03 — yes I know it broke before, I want to try with TTL fix",
41
+ });
42
+ expect(r.verdict).toBe("approved");
43
+ });
44
+ it("matches via synonyms / matchKeywords (not just topic)", () => {
45
+ const r = evaluateRequest({ request: "implement shared session cache", regretHistory: [redisRegret] });
46
+ expect(r.verdict).toBe("block"); // matched 'shared session' keyword
47
+ });
48
+ it("returns the strongest matching regret when multiple match", () => {
49
+ const r = evaluateRequest({ request: "use Redis + tighten JWT", regretHistory: [redisRegret, jwtRegret] });
50
+ expect(r.verdict).toBe("block");
51
+ expect(r.severity).toBeCloseTo(0.85, 2); // the Redis one wins
52
+ });
53
+ it("formatMutinyPulseLine produces compact summary", () => {
54
+ const r = evaluateRequest({ request: "use Redis", regretHistory: [redisRegret] });
55
+ expect(formatMutinyPulseLine(r)).toContain("MUTINY");
56
+ expect(formatMutinyPulseLine(r)).toContain("verdict=block");
57
+ });
58
+ });
59
+ //# sourceMappingURL=mutiny.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutiny.test.js","sourceRoot":"","sources":["../../src/mutiny/mutiny.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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=necromancy.test.d.ts.map