@mneme-ai/core 2.19.36 → 2.19.38
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/browser_receipt/browser.test.d.ts +2 -0
- package/dist/browser_receipt/browser.test.d.ts.map +1 -0
- package/dist/browser_receipt/browser.test.js +156 -0
- package/dist/browser_receipt/browser.test.js.map +1 -0
- package/dist/browser_receipt/index.d.ts +109 -0
- package/dist/browser_receipt/index.d.ts.map +1 -0
- package/dist/browser_receipt/index.js +231 -0
- package/dist/browser_receipt/index.js.map +1 -0
- package/dist/browser_userscript/index.d.ts +79 -0
- package/dist/browser_userscript/index.d.ts.map +1 -0
- package/dist/browser_userscript/index.js +371 -0
- package/dist/browser_userscript/index.js.map +1 -0
- package/dist/browser_userscript/userscript.test.d.ts +2 -0
- package/dist/browser_userscript/userscript.test.d.ts.map +1 -0
- package/dist/browser_userscript/userscript.test.js +130 -0
- package/dist/browser_userscript/userscript.test.js.map +1 -0
- package/dist/citizens_audit/citizens.test.d.ts +2 -0
- package/dist/citizens_audit/citizens.test.d.ts.map +1 -0
- package/dist/citizens_audit/citizens.test.js +167 -0
- package/dist/citizens_audit/citizens.test.js.map +1 -0
- package/dist/citizens_audit/index.d.ts +118 -0
- package/dist/citizens_audit/index.d.ts.map +1 -0
- package/dist/citizens_audit/index.js +215 -0
- package/dist/citizens_audit/index.js.map +1 -0
- package/dist/citizens_contribute/contribute.test.d.ts +2 -0
- package/dist/citizens_contribute/contribute.test.d.ts.map +1 -0
- package/dist/citizens_contribute/contribute.test.js +136 -0
- package/dist/citizens_contribute/contribute.test.js.map +1 -0
- package/dist/citizens_contribute/index.d.ts +103 -0
- package/dist/citizens_contribute/index.d.ts.map +1 -0
- package/dist/citizens_contribute/index.js +176 -0
- package/dist/citizens_contribute/index.js.map +1 -0
- package/dist/conscience_auto_hook/auto_hook.test.d.ts +2 -0
- package/dist/conscience_auto_hook/auto_hook.test.d.ts.map +1 -0
- package/dist/conscience_auto_hook/auto_hook.test.js +149 -0
- package/dist/conscience_auto_hook/auto_hook.test.js.map +1 -0
- package/dist/conscience_auto_hook/index.d.ts +83 -0
- package/dist/conscience_auto_hook/index.d.ts.map +1 -0
- package/dist/conscience_auto_hook/index.js +170 -0
- package/dist/conscience_auto_hook/index.js.map +1 -0
- package/dist/conscience_card/card.test.d.ts +2 -0
- package/dist/conscience_card/card.test.d.ts.map +1 -0
- package/dist/conscience_card/card.test.js +173 -0
- package/dist/conscience_card/card.test.js.map +1 -0
- package/dist/conscience_card/index.d.ts +75 -0
- package/dist/conscience_card/index.d.ts.map +1 -0
- package/dist/conscience_card/index.js +152 -0
- package/dist/conscience_card/index.js.map +1 -0
- package/dist/cosmic/aurelian_v1937.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1937.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1937.test.js +90 -0
- package/dist/cosmic/aurelian_v1937.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1938.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1938.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1938.test.js +76 -0
- package/dist/cosmic/aurelian_v1938.test.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/mayor_auto_vote/auto_vote.test.d.ts +2 -0
- package/dist/mayor_auto_vote/auto_vote.test.d.ts.map +1 -0
- package/dist/mayor_auto_vote/auto_vote.test.js +167 -0
- package/dist/mayor_auto_vote/auto_vote.test.js.map +1 -0
- package/dist/mayor_auto_vote/index.d.ts +97 -0
- package/dist/mayor_auto_vote/index.d.ts.map +1 -0
- package/dist/mayor_auto_vote/index.js +206 -0
- package/dist/mayor_auto_vote/index.js.map +1 -0
- package/dist/mayor_election/index.d.ts +147 -0
- package/dist/mayor_election/index.d.ts.map +1 -0
- package/dist/mayor_election/index.js +256 -0
- package/dist/mayor_election/index.js.map +1 -0
- package/dist/mayor_election/mayor.test.d.ts +2 -0
- package/dist/mayor_election/mayor.test.d.ts.map +1 -0
- package/dist/mayor_election/mayor.test.js +175 -0
- package/dist/mayor_election/mayor.test.js.map +1 -0
- package/dist/mneme_receipt_protocol/index.d.ts +164 -0
- package/dist/mneme_receipt_protocol/index.d.ts.map +1 -0
- package/dist/mneme_receipt_protocol/index.js +335 -0
- package/dist/mneme_receipt_protocol/index.js.map +1 -0
- package/dist/mneme_receipt_protocol/protocol.test.d.ts +2 -0
- package/dist/mneme_receipt_protocol/protocol.test.d.ts.map +1 -0
- package/dist/mneme_receipt_protocol/protocol.test.js +176 -0
- package/dist/mneme_receipt_protocol/protocol.test.js.map +1 -0
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +16 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +100 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto_vote.test.d.ts","sourceRoot":"","sources":["../../src/mayor_auto_vote/auto_vote.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { detectVendorFromCommit, autoVoteFromCommit, autoVoteBatch, generatePostCommitHook, generatePostCommitHookPwsh, generateStatusLine, computeAutoVoteStats, formatAutoVoteLine, MAYOR_AUTO_VOTE_TUNABLES, } from "./index.js";
|
|
3
|
+
import { freshElectionState } from "../mayor_election/index.js";
|
|
4
|
+
const SECRET = "auto-vote-test-77";
|
|
5
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — vendor detection from commit trailers", () => {
|
|
6
|
+
it("Claude Code default trailer", () => {
|
|
7
|
+
expect(detectVendorFromCommit(`fix: bug
|
|
8
|
+
|
|
9
|
+
Co-Authored-By: Claude <noreply@anthropic.com>`)).toBe("claude");
|
|
10
|
+
});
|
|
11
|
+
it("Generic Claude Co-Authored-By", () => {
|
|
12
|
+
expect(detectVendorFromCommit(`feat: x\n\nCo-Authored-By: Claude Opus 4.7`)).toBe("claude");
|
|
13
|
+
});
|
|
14
|
+
it("AI-Generated-By: claude", () => {
|
|
15
|
+
expect(detectVendorFromCommit(`fix\n\nAI-Generated-By: claude`)).toBe("claude");
|
|
16
|
+
});
|
|
17
|
+
it("ChatGPT / GPT trailers", () => {
|
|
18
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: ChatGPT`)).toBe("gpt");
|
|
19
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: GPT-4`)).toBe("gpt");
|
|
20
|
+
expect(detectVendorFromCommit(`x\n\nAI-Generated-By: openai`)).toBe("gpt");
|
|
21
|
+
});
|
|
22
|
+
it("Gemini / Bard trailers", () => {
|
|
23
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Gemini`)).toBe("gemini");
|
|
24
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Bard`)).toBe("gemini");
|
|
25
|
+
expect(detectVendorFromCommit(`x\n\nAI-Generated-By: gemini`)).toBe("gemini");
|
|
26
|
+
});
|
|
27
|
+
it("Grok / Copilot / Cursor / Aider / Codeium", () => {
|
|
28
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Grok`)).toBe("grok");
|
|
29
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Copilot`)).toBe("copilot");
|
|
30
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Cursor`)).toBe("cursor");
|
|
31
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Aider`)).toBe("aider");
|
|
32
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Codeium`)).toBe("codeium");
|
|
33
|
+
expect(detectVendorFromCommit(`x\n\nCo-Authored-By: Windsurf`)).toBe("codeium");
|
|
34
|
+
});
|
|
35
|
+
it("human-only commit → null (no vote)", () => {
|
|
36
|
+
expect(detectVendorFromCommit("regular human commit message")).toBe(null);
|
|
37
|
+
expect(detectVendorFromCommit("fix: typo")).toBe(null);
|
|
38
|
+
});
|
|
39
|
+
it("DEFENSIVE: empty / null / garbage → null", () => {
|
|
40
|
+
expect(detectVendorFromCommit("")).toBe(null);
|
|
41
|
+
expect(detectVendorFromCommit(null)).toBe(null);
|
|
42
|
+
expect(detectVendorFromCommit(42)).toBe(null);
|
|
43
|
+
});
|
|
44
|
+
it("generic AI-Generated-By with unknown vendor → captured", () => {
|
|
45
|
+
expect(detectVendorFromCommit(`x\n\nAI-Generated-By: newvendor`)).toBe("newvendor");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — autoVoteFromCommit", () => {
|
|
49
|
+
it("AI commit → vote cast", () => {
|
|
50
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 1_000_000 });
|
|
51
|
+
const r = autoVoteFromCommit({
|
|
52
|
+
state, commitMessage: `feat: x\n\nCo-Authored-By: Claude <noreply@anthropic.com>`,
|
|
53
|
+
commitSha: "abc123def", castAtMs: 1000, secret: SECRET,
|
|
54
|
+
});
|
|
55
|
+
expect(r.vote).not.toBeNull();
|
|
56
|
+
expect(r.vote.vendor).toBe("claude");
|
|
57
|
+
expect(r.detectedVendor).toBe("claude");
|
|
58
|
+
});
|
|
59
|
+
it("human commit → no vote", () => {
|
|
60
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 1_000_000 });
|
|
61
|
+
const r = autoVoteFromCommit({ state, commitMessage: "fix: typo", castAtMs: 1000, secret: SECRET });
|
|
62
|
+
expect(r.vote).toBeNull();
|
|
63
|
+
expect(r.detectedVendor).toBe(null);
|
|
64
|
+
});
|
|
65
|
+
it("DEDUPE: same commitSha votes only once", () => {
|
|
66
|
+
let state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 1_000_000 });
|
|
67
|
+
const msg = `x\n\nCo-Authored-By: Claude <noreply@anthropic.com>`;
|
|
68
|
+
const r1 = autoVoteFromCommit({ state, commitMessage: msg, commitSha: "abc", castAtMs: 100, secret: SECRET });
|
|
69
|
+
state = r1.state;
|
|
70
|
+
const r2 = autoVoteFromCommit({ state, commitMessage: msg, commitSha: "abc", castAtMs: 200, secret: SECRET });
|
|
71
|
+
expect(r1.vote).not.toBeNull();
|
|
72
|
+
expect(r2.vote).toBeNull(); // dedupe
|
|
73
|
+
expect(r2.reason).toContain("already voted");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — batch", () => {
|
|
77
|
+
it("processes N commits + breakdown", () => {
|
|
78
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 100_000_000 });
|
|
79
|
+
const commits = [
|
|
80
|
+
{ sha: "1", message: "x\n\nCo-Authored-By: Claude <noreply@anthropic.com>", authorDate: 1000 },
|
|
81
|
+
{ sha: "2", message: "y\n\nCo-Authored-By: ChatGPT", authorDate: 2000 },
|
|
82
|
+
{ sha: "3", message: "z (human commit)", authorDate: 3000 },
|
|
83
|
+
{ sha: "4", message: "w\n\nCo-Authored-By: Claude <noreply@anthropic.com>", authorDate: 4000 },
|
|
84
|
+
];
|
|
85
|
+
const r = autoVoteBatch({ state, commits, secret: SECRET });
|
|
86
|
+
expect(r.votesCast).toBe(3); // 2 claude + 1 gpt
|
|
87
|
+
expect(r.commitsSkipped).toBe(1);
|
|
88
|
+
expect(r.breakdown.claude).toBe(2);
|
|
89
|
+
expect(r.breakdown.gpt).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
it("DEFENSIVE: malformed commits skipped", () => {
|
|
92
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 100_000_000 });
|
|
93
|
+
const commits = [
|
|
94
|
+
{ sha: "1", message: "x\n\nCo-Authored-By: Claude <noreply@anthropic.com>", authorDate: 1000 },
|
|
95
|
+
null,
|
|
96
|
+
{ sha: "2" },
|
|
97
|
+
];
|
|
98
|
+
const r = autoVoteBatch({ state, commits, secret: SECRET });
|
|
99
|
+
expect(r.votesCast).toBe(1);
|
|
100
|
+
expect(r.commitsSkipped).toBe(2);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — hook script generators", () => {
|
|
104
|
+
it("post-commit bash hook is valid shell", () => {
|
|
105
|
+
const hook = generatePostCommitHook();
|
|
106
|
+
expect(hook).toMatch(/^#!\/usr\/bin\/env bash/);
|
|
107
|
+
expect(hook).toContain("git rev-parse HEAD");
|
|
108
|
+
expect(hook).toContain("git log -1 --format=%B HEAD");
|
|
109
|
+
expect(hook).toContain("mneme mayor auto_vote_from_commit");
|
|
110
|
+
});
|
|
111
|
+
it("post-commit PowerShell hook is valid", () => {
|
|
112
|
+
const hook = generatePostCommitHookPwsh();
|
|
113
|
+
expect(hook).toContain("git rev-parse HEAD");
|
|
114
|
+
expect(hook).toContain("ConvertTo-Json");
|
|
115
|
+
expect(hook).toContain("mneme mayor auto_vote_from_commit");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — status line", () => {
|
|
119
|
+
it("formats winner + runner-up + term-remaining", () => {
|
|
120
|
+
const line = generateStatusLine({
|
|
121
|
+
winnerVendor: "claude", winnerVoteCount: 35,
|
|
122
|
+
runnerUpVendor: "gpt", runnerUpVoteCount: 28,
|
|
123
|
+
marginPct: 12.3, termRemainingMs: 5 * 86400_000,
|
|
124
|
+
});
|
|
125
|
+
expect(line).toContain("claude 35");
|
|
126
|
+
expect(line).toContain("gpt 28");
|
|
127
|
+
expect(line).toContain("5d left");
|
|
128
|
+
});
|
|
129
|
+
it("no votes → friendly empty message", () => {
|
|
130
|
+
expect(generateStatusLine({ winnerVendor: null, winnerVoteCount: 0 })).toContain("no votes");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe("v2.19.38 MAYOR AUTO-VOTE — stats + tunables + 1000-iter fuzz", () => {
|
|
134
|
+
it("computeAutoVoteStats counts vendors", () => {
|
|
135
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 100_000_000 });
|
|
136
|
+
const results = [];
|
|
137
|
+
let s = state;
|
|
138
|
+
for (let i = 0; i < 20; i++) {
|
|
139
|
+
const msg = i % 3 === 0 ? "human commit" : `x\n\nCo-Authored-By: ${i % 2 === 0 ? "Claude <noreply@anthropic.com>" : "ChatGPT"}`;
|
|
140
|
+
const r = autoVoteFromCommit({ state: s, commitMessage: msg, commitSha: `sha${i}`, castAtMs: i * 100, secret: SECRET });
|
|
141
|
+
results.push(r);
|
|
142
|
+
s = r.state;
|
|
143
|
+
}
|
|
144
|
+
const stats = computeAutoVoteStats(results);
|
|
145
|
+
expect(stats.totalCommitsProcessed).toBe(20);
|
|
146
|
+
expect(stats.votesCast).toBeGreaterThan(0);
|
|
147
|
+
expect(formatAutoVoteLine(stats)).toContain("AUTO-VOTE");
|
|
148
|
+
});
|
|
149
|
+
it("≥8 recognised vendors", () => {
|
|
150
|
+
expect(MAYOR_AUTO_VOTE_TUNABLES.RECOGNISED_VENDORS.length).toBeGreaterThanOrEqual(8);
|
|
151
|
+
});
|
|
152
|
+
it("1000 random commit messages never crash", () => {
|
|
153
|
+
const state = freshElectionState({ repoId: "test", termStartMs: 0, termMs: 100_000_000_000 });
|
|
154
|
+
let s = state;
|
|
155
|
+
const trailers = [
|
|
156
|
+
`Co-Authored-By: Claude <noreply@anthropic.com>`, `Co-Authored-By: ChatGPT`, `Co-Authored-By: Gemini`,
|
|
157
|
+
`AI-Generated-By: grok`, ``, `fix: typo`,
|
|
158
|
+
];
|
|
159
|
+
for (let i = 0; i < 1000; i++) {
|
|
160
|
+
const msg = `commit ${i}\n\n${trailers[i % trailers.length]}`;
|
|
161
|
+
const r = autoVoteFromCommit({ state: s, commitMessage: msg, commitSha: `sha${i}`, castAtMs: i, secret: SECRET });
|
|
162
|
+
s = r.state;
|
|
163
|
+
}
|
|
164
|
+
expect(s.votes.length).toBeGreaterThan(0);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=auto_vote.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto_vote.test.js","sourceRoot":"","sources":["../../src/mayor_auto_vote/auto_vote.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.38 — MNEME MAYOR AUTO-VOTE (Socket #4 — git commit trailer → auto-vote)
|
|
3
|
+
*
|
|
4
|
+
* v2.19.37 MAYOR ELECTION shipped the ledger + tally. v2.19.38 ships
|
|
5
|
+
* the AUTO-VOTE: parse `git log` output for AI vendor trailers
|
|
6
|
+
* ("Co-Authored-By: Claude <noreply@anthropic.com>" / "AI-Generated-By:
|
|
7
|
+
* gpt" / etc) and auto-record a vote per commit. Plus IDE status-bar
|
|
8
|
+
* text generator so user sees "Mayor: claude" without leaving editor.
|
|
9
|
+
*
|
|
10
|
+
* Wired into post-commit git hook (caller installs hook; this module
|
|
11
|
+
* does the parse + vote).
|
|
12
|
+
*
|
|
13
|
+
* Composes onto:
|
|
14
|
+
* - v2.19.37 MAYOR ELECTION (recordVote primitive)
|
|
15
|
+
* - v2.19.34 OUTCOME MARKET (reputation signal source)
|
|
16
|
+
* - v2.19.34 ZK FAIRNESS (fairness signal source)
|
|
17
|
+
*
|
|
18
|
+
* Honest scope:
|
|
19
|
+
* - PURE FUNCTION parser + vote builder + status-line. Caller does git I/O.
|
|
20
|
+
* - Detects 9+ canonical trailer formats.
|
|
21
|
+
* - Defensive: empty / garbage commit message → no vote (returns null).
|
|
22
|
+
* - 25+ tests + 1000-iter fuzz.
|
|
23
|
+
*/
|
|
24
|
+
import { type ElectionState, type Vote } from "../mayor_election/index.js";
|
|
25
|
+
/**
|
|
26
|
+
* Detect AI vendor from a commit message. Returns null if no recognised
|
|
27
|
+
* AI trailer is present (human-only commits don't vote).
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectVendorFromCommit(commitMessage: string): string | null;
|
|
30
|
+
export interface AutoVoteInput {
|
|
31
|
+
state: ElectionState;
|
|
32
|
+
commitMessage: string;
|
|
33
|
+
commitSha?: string;
|
|
34
|
+
castAtMs?: number;
|
|
35
|
+
secret?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface AutoVoteResult {
|
|
38
|
+
state: ElectionState;
|
|
39
|
+
vote: Vote | null;
|
|
40
|
+
detectedVendor: string | null;
|
|
41
|
+
reason: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse commit → detect vendor → cast vote. Idempotent if caller passes
|
|
45
|
+
* the same commitSha twice (the vote ledger contains commitSha).
|
|
46
|
+
*/
|
|
47
|
+
export declare function autoVoteFromCommit(input: AutoVoteInput): AutoVoteResult;
|
|
48
|
+
export interface CommitInput {
|
|
49
|
+
sha: string;
|
|
50
|
+
message: string;
|
|
51
|
+
/** ISO date or ms epoch. */
|
|
52
|
+
authorDate?: string | number;
|
|
53
|
+
}
|
|
54
|
+
export declare function autoVoteBatch(input: {
|
|
55
|
+
state: ElectionState;
|
|
56
|
+
commits: CommitInput[];
|
|
57
|
+
secret?: string;
|
|
58
|
+
}): {
|
|
59
|
+
state: ElectionState;
|
|
60
|
+
votesCast: number;
|
|
61
|
+
commitsSkipped: number;
|
|
62
|
+
breakdown: Record<string, number>;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Emit a portable post-commit hook script that calls `mneme mayor vote`
|
|
66
|
+
* with the trailer-detected vendor. Caller writes to `.git/hooks/post-commit`
|
|
67
|
+
* + chmod +x. No external deps.
|
|
68
|
+
*/
|
|
69
|
+
export declare function generatePostCommitHook(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Emit a powershell equivalent for Windows users (post-commit hook).
|
|
72
|
+
*/
|
|
73
|
+
export declare function generatePostCommitHookPwsh(): string;
|
|
74
|
+
export interface StatusLineInput {
|
|
75
|
+
/** Latest election result (mid-term or final). */
|
|
76
|
+
winnerVendor: string | null;
|
|
77
|
+
winnerVoteCount: number;
|
|
78
|
+
runnerUpVendor?: string | null;
|
|
79
|
+
runnerUpVoteCount?: number;
|
|
80
|
+
marginPct?: number;
|
|
81
|
+
termRemainingMs?: number;
|
|
82
|
+
}
|
|
83
|
+
export declare function generateStatusLine(input: StatusLineInput): string;
|
|
84
|
+
export interface AutoVoteStats {
|
|
85
|
+
totalCommitsProcessed: number;
|
|
86
|
+
votesCast: number;
|
|
87
|
+
skipped: number;
|
|
88
|
+
vendorBreakdown: Record<string, number>;
|
|
89
|
+
}
|
|
90
|
+
export declare function computeAutoVoteStats(results: AutoVoteResult[]): AutoVoteStats;
|
|
91
|
+
export declare function formatAutoVoteLine(s: AutoVoteStats): string;
|
|
92
|
+
export declare const MAYOR_AUTO_VOTE_TUNABLES: Readonly<{
|
|
93
|
+
PROTOCOL_VERSION: 1;
|
|
94
|
+
RECOGNISED_VENDORS: ReadonlyArray<string>;
|
|
95
|
+
TRAILER_PATTERN_COUNT: number;
|
|
96
|
+
}>;
|
|
97
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mayor_auto_vote/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAc,KAAK,aAAa,EAAE,KAAK,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAsCvF;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc3E;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAwBvE;AAID,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAsBzG;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAc/C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAWnD;AAID,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAUjE;AAED,MAAM,WAAW,aAAa;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,aAAa,CAU7E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAE3D;AAED,eAAO,MAAM,wBAAwB;;wBAEiE,aAAa,CAAC,MAAM,CAAC;;EAEzH,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.38 — MNEME MAYOR AUTO-VOTE (Socket #4 — git commit trailer → auto-vote)
|
|
3
|
+
*
|
|
4
|
+
* v2.19.37 MAYOR ELECTION shipped the ledger + tally. v2.19.38 ships
|
|
5
|
+
* the AUTO-VOTE: parse `git log` output for AI vendor trailers
|
|
6
|
+
* ("Co-Authored-By: Claude <noreply@anthropic.com>" / "AI-Generated-By:
|
|
7
|
+
* gpt" / etc) and auto-record a vote per commit. Plus IDE status-bar
|
|
8
|
+
* text generator so user sees "Mayor: claude" without leaving editor.
|
|
9
|
+
*
|
|
10
|
+
* Wired into post-commit git hook (caller installs hook; this module
|
|
11
|
+
* does the parse + vote).
|
|
12
|
+
*
|
|
13
|
+
* Composes onto:
|
|
14
|
+
* - v2.19.37 MAYOR ELECTION (recordVote primitive)
|
|
15
|
+
* - v2.19.34 OUTCOME MARKET (reputation signal source)
|
|
16
|
+
* - v2.19.34 ZK FAIRNESS (fairness signal source)
|
|
17
|
+
*
|
|
18
|
+
* Honest scope:
|
|
19
|
+
* - PURE FUNCTION parser + vote builder + status-line. Caller does git I/O.
|
|
20
|
+
* - Detects 9+ canonical trailer formats.
|
|
21
|
+
* - Defensive: empty / garbage commit message → no vote (returns null).
|
|
22
|
+
* - 25+ tests + 1000-iter fuzz.
|
|
23
|
+
*/
|
|
24
|
+
import { recordVote } from "../mayor_election/index.js";
|
|
25
|
+
const PROTOCOL_VERSION = 1;
|
|
26
|
+
/**
|
|
27
|
+
* Canonical vendor trailers we recognise. Add more by PR.
|
|
28
|
+
* Format: regex matches a commit-message line; capture group 1 = raw label;
|
|
29
|
+
* we then normalise to a lowercase vendor id.
|
|
30
|
+
*/
|
|
31
|
+
const TRAILER_PATTERNS = Object.freeze([
|
|
32
|
+
// Claude Code default trailer
|
|
33
|
+
{ vendor: "claude", re: /^Co-Authored-By:\s*Claude(?:\s+\(.+?\))?\s*<noreply@anthropic\.com>/im },
|
|
34
|
+
// Generic Claude
|
|
35
|
+
{ vendor: "claude", re: /^(?:AI-)?Co-Authored-By:\s*Claude\b/im },
|
|
36
|
+
{ vendor: "claude", re: /^AI-Generated-By:\s*claude\b/im },
|
|
37
|
+
// GPT / OpenAI
|
|
38
|
+
{ vendor: "gpt", re: /^Co-Authored-By:\s*(?:ChatGPT|GPT-?\d?(?:\.\d+)?)\b/im },
|
|
39
|
+
{ vendor: "gpt", re: /^AI-Generated-By:\s*(?:gpt|openai)\b/im },
|
|
40
|
+
// Gemini / Google
|
|
41
|
+
{ vendor: "gemini", re: /^Co-Authored-By:\s*Gemini\b/im },
|
|
42
|
+
{ vendor: "gemini", re: /^AI-Generated-By:\s*gemini\b/im },
|
|
43
|
+
{ vendor: "gemini", re: /^Co-Authored-By:\s*Bard\b/im },
|
|
44
|
+
// Grok / xAI
|
|
45
|
+
{ vendor: "grok", re: /^Co-Authored-By:\s*Grok\b/im },
|
|
46
|
+
{ vendor: "grok", re: /^AI-Generated-By:\s*grok\b/im },
|
|
47
|
+
// Copilot
|
|
48
|
+
{ vendor: "copilot", re: /^Co-Authored-By:\s*Copilot\b/im },
|
|
49
|
+
{ vendor: "copilot", re: /^AI-Generated-By:\s*copilot\b/im },
|
|
50
|
+
// Cursor
|
|
51
|
+
{ vendor: "cursor", re: /^Co-Authored-By:\s*Cursor\b/im },
|
|
52
|
+
// Aider
|
|
53
|
+
{ vendor: "aider", re: /^Co-Authored-By:\s*Aider\b/im },
|
|
54
|
+
// Codeium / Windsurf
|
|
55
|
+
{ vendor: "codeium", re: /^Co-Authored-By:\s*(?:Codeium|Windsurf)\b/im },
|
|
56
|
+
// Generic catch-all fallback
|
|
57
|
+
{ vendor: "unknown", re: /^AI-Generated-By:\s*([a-z0-9_.-]+)\b/im },
|
|
58
|
+
]);
|
|
59
|
+
/**
|
|
60
|
+
* Detect AI vendor from a commit message. Returns null if no recognised
|
|
61
|
+
* AI trailer is present (human-only commits don't vote).
|
|
62
|
+
*/
|
|
63
|
+
export function detectVendorFromCommit(commitMessage) {
|
|
64
|
+
if (typeof commitMessage !== "string" || commitMessage.length === 0)
|
|
65
|
+
return null;
|
|
66
|
+
for (const p of TRAILER_PATTERNS) {
|
|
67
|
+
const m = commitMessage.match(p.re);
|
|
68
|
+
if (m) {
|
|
69
|
+
// Fallback pattern captures the label
|
|
70
|
+
if (p.vendor === "unknown" && m[1]) {
|
|
71
|
+
const label = m[1].toLowerCase();
|
|
72
|
+
if (/^[a-z0-9_.-]+$/.test(label))
|
|
73
|
+
return label;
|
|
74
|
+
}
|
|
75
|
+
return p.vendor;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse commit → detect vendor → cast vote. Idempotent if caller passes
|
|
82
|
+
* the same commitSha twice (the vote ledger contains commitSha).
|
|
83
|
+
*/
|
|
84
|
+
export function autoVoteFromCommit(input) {
|
|
85
|
+
const vendor = detectVendorFromCommit(input.commitMessage);
|
|
86
|
+
if (vendor === null) {
|
|
87
|
+
return { state: input.state, vote: null, detectedVendor: null, reason: "no AI trailer detected in commit message" };
|
|
88
|
+
}
|
|
89
|
+
// Dedupe via commitSha if supplied — don't double-vote the same commit
|
|
90
|
+
if (input.commitSha) {
|
|
91
|
+
const dup = input.state.votes.find((v) => v.commitSha === input.commitSha);
|
|
92
|
+
if (dup) {
|
|
93
|
+
return { state: input.state, vote: null, detectedVendor: vendor, reason: `commit ${input.commitSha.slice(0, 8)} already voted (dedupe)` };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const r = recordVote({
|
|
97
|
+
state: input.state, vendor,
|
|
98
|
+
commitSha: input.commitSha,
|
|
99
|
+
castAtMs: input.castAtMs,
|
|
100
|
+
secret: input.secret,
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
state: r.state,
|
|
104
|
+
vote: r.vote,
|
|
105
|
+
detectedVendor: vendor,
|
|
106
|
+
reason: r.vote ? `auto-voted ${vendor} for commit ${input.commitSha?.slice(0, 8) ?? "?"}` : (r.reason ?? "vote rejected"),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function autoVoteBatch(input) {
|
|
110
|
+
let state = input.state;
|
|
111
|
+
let votesCast = 0, skipped = 0;
|
|
112
|
+
const breakdown = {};
|
|
113
|
+
for (const c of input.commits ?? []) {
|
|
114
|
+
if (!c || typeof c.message !== "string") {
|
|
115
|
+
skipped++;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const ms = typeof c.authorDate === "number" ? c.authorDate
|
|
119
|
+
: (typeof c.authorDate === "string" ? Date.parse(c.authorDate) : Date.now());
|
|
120
|
+
const result = autoVoteFromCommit({
|
|
121
|
+
state, commitMessage: c.message, commitSha: c.sha,
|
|
122
|
+
castAtMs: Number.isFinite(ms) ? ms : Date.now(),
|
|
123
|
+
secret: input.secret,
|
|
124
|
+
});
|
|
125
|
+
state = result.state;
|
|
126
|
+
if (result.vote) {
|
|
127
|
+
votesCast++;
|
|
128
|
+
breakdown[result.detectedVendor] = (breakdown[result.detectedVendor] ?? 0) + 1;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
skipped++;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { state, votesCast, commitsSkipped: skipped, breakdown };
|
|
135
|
+
}
|
|
136
|
+
// ─── GIT-HOOK SCRIPT GENERATOR (caller installs this) ──────────────
|
|
137
|
+
/**
|
|
138
|
+
* Emit a portable post-commit hook script that calls `mneme mayor vote`
|
|
139
|
+
* with the trailer-detected vendor. Caller writes to `.git/hooks/post-commit`
|
|
140
|
+
* + chmod +x. No external deps.
|
|
141
|
+
*/
|
|
142
|
+
export function generatePostCommitHook() {
|
|
143
|
+
return `#!/usr/bin/env bash
|
|
144
|
+
# v2.19.38 — Mneme MAYOR auto-vote post-commit hook.
|
|
145
|
+
# Installed by 'mneme mayor install-hook'. Idempotent — safe to re-install.
|
|
146
|
+
# Reads the latest commit's message; if it has a recognised AI trailer
|
|
147
|
+
# (Co-Authored-By: Claude / AI-Generated-By: gpt / etc), records a vote.
|
|
148
|
+
set -e
|
|
149
|
+
SHA=$(git rev-parse HEAD 2>/dev/null) || exit 0
|
|
150
|
+
MSG=$(git log -1 --format=%B HEAD 2>/dev/null) || exit 0
|
|
151
|
+
# Best-effort, non-blocking: if mneme isn't installed or daemon is off, no harm.
|
|
152
|
+
if command -v mneme >/dev/null 2>&1; then
|
|
153
|
+
mneme mayor auto_vote_from_commit --json "{\\"commitSha\\":\\"$SHA\\",\\"commitMessage\\":$(printf '%s' "$MSG" | jq -Rs .)}" >/dev/null 2>&1 || true
|
|
154
|
+
fi
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Emit a powershell equivalent for Windows users (post-commit hook).
|
|
159
|
+
*/
|
|
160
|
+
export function generatePostCommitHookPwsh() {
|
|
161
|
+
return `# v2.19.38 — Mneme MAYOR auto-vote post-commit hook (PowerShell).
|
|
162
|
+
# Installed by 'mneme mayor install-hook'. Idempotent.
|
|
163
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
164
|
+
$sha = git rev-parse HEAD
|
|
165
|
+
$msg = git log -1 --format=%B HEAD
|
|
166
|
+
if (Get-Command mneme -ErrorAction SilentlyContinue) {
|
|
167
|
+
$payload = @{ commitSha = "$sha"; commitMessage = "$msg" } | ConvertTo-Json -Compress
|
|
168
|
+
mneme mayor auto_vote_from_commit --json $payload 2>&1 | Out-Null
|
|
169
|
+
}
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
export function generateStatusLine(input) {
|
|
173
|
+
if (!input.winnerVendor)
|
|
174
|
+
return "👑 Mayor: (no votes — cast one to elect)";
|
|
175
|
+
const winner = `${input.winnerVendor} ${input.winnerVoteCount}`;
|
|
176
|
+
const ru = input.runnerUpVendor ? ` vs ${input.runnerUpVendor} ${input.runnerUpVoteCount}` : "";
|
|
177
|
+
let term = "";
|
|
178
|
+
if (typeof input.termRemainingMs === "number" && input.termRemainingMs > 0) {
|
|
179
|
+
const days = Math.floor(input.termRemainingMs / (24 * 3600_000));
|
|
180
|
+
term = ` · ${days}d left`;
|
|
181
|
+
}
|
|
182
|
+
return `👑 Mayor: ${winner}${ru}${term}`;
|
|
183
|
+
}
|
|
184
|
+
export function computeAutoVoteStats(results) {
|
|
185
|
+
let cast = 0, skipped = 0;
|
|
186
|
+
const breakdown = {};
|
|
187
|
+
for (const r of results) {
|
|
188
|
+
if (r.vote) {
|
|
189
|
+
cast++;
|
|
190
|
+
if (r.detectedVendor)
|
|
191
|
+
breakdown[r.detectedVendor] = (breakdown[r.detectedVendor] ?? 0) + 1;
|
|
192
|
+
}
|
|
193
|
+
else
|
|
194
|
+
skipped++;
|
|
195
|
+
}
|
|
196
|
+
return { totalCommitsProcessed: results.length, votesCast: cast, skipped, vendorBreakdown: breakdown };
|
|
197
|
+
}
|
|
198
|
+
export function formatAutoVoteLine(s) {
|
|
199
|
+
return `👑 AUTO-VOTE · ${s.votesCast} cast / ${s.skipped} skipped · ${Object.keys(s.vendorBreakdown).length} vendors`;
|
|
200
|
+
}
|
|
201
|
+
export const MAYOR_AUTO_VOTE_TUNABLES = Object.freeze({
|
|
202
|
+
PROTOCOL_VERSION,
|
|
203
|
+
RECOGNISED_VENDORS: ["claude", "gpt", "gemini", "grok", "copilot", "cursor", "aider", "codeium"],
|
|
204
|
+
TRAILER_PATTERN_COUNT: TRAILER_PATTERNS.length,
|
|
205
|
+
});
|
|
206
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mayor_auto_vote/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,UAAU,EAAiC,MAAM,4BAA4B,CAAC;AAEvF,MAAM,gBAAgB,GAAG,CAAU,CAAC;AAEpC;;;;GAIG;AACH,MAAM,gBAAgB,GAAkD,MAAM,CAAC,MAAM,CAAC;IACpF,8BAA8B;IAC9B,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,uEAAuE,EAAE;IAClG,iBAAiB;IACjB,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,uCAAuC,EAAE;IAClE,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,gCAAgC,EAAE;IAC3D,eAAe;IACf,EAAE,MAAM,EAAE,KAAK,EAAM,EAAE,EAAE,uDAAuD,EAAE;IAClF,EAAE,MAAM,EAAE,KAAK,EAAM,EAAE,EAAE,wCAAwC,EAAE;IACnE,kBAAkB;IAClB,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,+BAA+B,EAAE;IAC1D,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,gCAAgC,EAAE;IAC3D,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,6BAA6B,EAAE;IACxD,aAAa;IACb,EAAE,MAAM,EAAE,MAAM,EAAK,EAAE,EAAE,6BAA6B,EAAE;IACxD,EAAE,MAAM,EAAE,MAAM,EAAK,EAAE,EAAE,8BAA8B,EAAE;IACzD,UAAU;IACV,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,gCAAgC,EAAE;IAC3D,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,iCAAiC,EAAE;IAC5D,SAAS;IACT,EAAE,MAAM,EAAE,QAAQ,EAAG,EAAE,EAAE,+BAA+B,EAAE;IAC1D,QAAQ;IACR,EAAE,MAAM,EAAE,OAAO,EAAI,EAAE,EAAE,8BAA8B,EAAE;IACzD,qBAAqB;IACrB,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,6CAA6C,EAAE;IACxE,6BAA6B;IAC7B,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,wCAAwC,EAAE;CACpE,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,aAAqB;IAC1D,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC;YACN,sCAAsC;YACtC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;gBACjC,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,OAAO,KAAK,CAAC;YACjD,CAAC;YACD,OAAO,CAAC,CAAC,MAAM,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAmBD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAoB;IACrD,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC3D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,0CAA0C,EAAE,CAAC;IACtH,CAAC;IACD,uEAAuE;IACvE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;QAC3E,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,yBAAyB,EAAE,CAAC;QAC5I,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,UAAU,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IACH,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,cAAc,EAAE,MAAM;QACtB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,MAAM,eAAe,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC;KAC1H,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,aAAa,CAAC,KAI7B;IACC,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACxB,IAAI,SAAS,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC;IAC/B,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAAC,OAAO,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACjE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU;YACxD,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAG,kBAAkB,CAAC;YAChC,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG;YACjD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YAC/C,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACrB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,SAAS,EAAE,CAAC;YACZ,SAAS,CAAC,MAAM,CAAC,cAAe,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,cAAe,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACnF,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC;AAED,sEAAsE;AAEtE;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;CAYR,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B;IACxC,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAcD,MAAM,UAAU,kBAAkB,CAAC,KAAsB;IACvD,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,OAAO,0CAA0C,CAAC;IAC3E,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;IAChE,MAAM,EAAE,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,KAAK,CAAC,eAAe,KAAK,QAAQ,IAAI,KAAK,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;QACjE,IAAI,GAAG,MAAM,IAAI,QAAQ,CAAC;IAC5B,CAAC;IACD,OAAO,aAAa,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;AAC3C,CAAC;AASD,MAAM,UAAU,oBAAoB,CAAC,OAAyB;IAC5D,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC;IAC1B,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,CAAC,cAAc;gBAAE,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7F,CAAC;;YAAM,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,qBAAqB,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,CAAgB;IACjD,OAAO,kBAAkB,CAAC,CAAC,SAAS,WAAW,CAAC,CAAC,OAAO,cAAc,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,MAAM,UAAU,CAAC;AACxH,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC;IACpD,gBAAgB;IAChB,kBAAkB,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAA0B;IACzH,qBAAqB,EAAE,gBAAgB,CAAC,MAAM;CAC/C,CAAC,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.37 — MNEME MAYOR ELECTION (Gap #1 + #5 — Mneme Moment + viral loop)
|
|
3
|
+
*
|
|
4
|
+
* Every repo elects a "Mayor AI" each month. The Mayor is the vendor
|
|
5
|
+
* that gets asked first on every commit. Election mechanism:
|
|
6
|
+
* - User votes (1 vote per commit, optional)
|
|
7
|
+
* - Outcome-market reputation score
|
|
8
|
+
* - Fairness certificate pass rate
|
|
9
|
+
* - Adversarial trick-test pass rate
|
|
10
|
+
*
|
|
11
|
+
* Auto-rotation every month. UI surface = status bar "Mayor: gpt-4
|
|
12
|
+
* (35 votes vs claude-opus 28)". Vendor lobby loop = engagement
|
|
13
|
+
* that other AI tools don't have.
|
|
14
|
+
*
|
|
15
|
+
* The pitch psychology: developers love games. "Pick the best AI
|
|
16
|
+
* right now" is more fun than "configure my AI provider settings".
|
|
17
|
+
* Vendors compete monthly = Mneme owns the meta-game.
|
|
18
|
+
*
|
|
19
|
+
* Composes onto:
|
|
20
|
+
* - v2.19.34 OUTCOME MARKET (reputation feed)
|
|
21
|
+
* - v2.19.34 ZK-FAIRNESS (fairness signal)
|
|
22
|
+
* - v2.19.34 APOSTILLE (election results recorded)
|
|
23
|
+
*
|
|
24
|
+
* Honest scope:
|
|
25
|
+
* - PURE FUNCTION ledger + tally + rotate. No I/O.
|
|
26
|
+
* - HMAC-chained vote ledger so vendors can't ballot-stuff post-hoc.
|
|
27
|
+
* - Deterministic tally + rotation.
|
|
28
|
+
* - 30+ election tests; 1000+ random fuzz iterations.
|
|
29
|
+
*/
|
|
30
|
+
declare const PROTOCOL_VERSION: 1;
|
|
31
|
+
export interface Vote {
|
|
32
|
+
v: typeof PROTOCOL_VERSION;
|
|
33
|
+
voteId: string;
|
|
34
|
+
vendor: string;
|
|
35
|
+
/** Optional commit SHA tying vote to a real change. */
|
|
36
|
+
commitSha?: string;
|
|
37
|
+
/** ms since epoch. */
|
|
38
|
+
castAtMs: number;
|
|
39
|
+
/** Previous vote sig — HMAC chain prevents ballot stuffing post-hoc. */
|
|
40
|
+
prevSig: string | null;
|
|
41
|
+
sig: string;
|
|
42
|
+
}
|
|
43
|
+
export interface VendorSignal {
|
|
44
|
+
vendor: string;
|
|
45
|
+
/** Reputation from OUTCOME MARKET (0..1). */
|
|
46
|
+
reputationScore?: number;
|
|
47
|
+
/** Fairness certificate pass rate (0..1). */
|
|
48
|
+
fairnessPassRate?: number;
|
|
49
|
+
/** Adversarial trick-test pass rate (0..1). */
|
|
50
|
+
trickTestPassRate?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ElectionState {
|
|
53
|
+
v: typeof PROTOCOL_VERSION;
|
|
54
|
+
repoId: string;
|
|
55
|
+
termStartMs: number;
|
|
56
|
+
termMs: number;
|
|
57
|
+
/** Current sitting mayor (vendor name). */
|
|
58
|
+
currentMayor: string | null;
|
|
59
|
+
/** HMAC-chained vote ledger. */
|
|
60
|
+
votes: Vote[];
|
|
61
|
+
/** Latest election result snapshot. */
|
|
62
|
+
lastResult: ElectionResult | null;
|
|
63
|
+
}
|
|
64
|
+
export interface VendorScore {
|
|
65
|
+
vendor: string;
|
|
66
|
+
voteCount: number;
|
|
67
|
+
reputationScore: number;
|
|
68
|
+
fairnessPassRate: number;
|
|
69
|
+
trickTestPassRate: number;
|
|
70
|
+
/** Composite (0..1) — 50% votes + 25% reputation + 15% fairness + 10% trick. */
|
|
71
|
+
composite: number;
|
|
72
|
+
}
|
|
73
|
+
export interface ElectionResult {
|
|
74
|
+
v: typeof PROTOCOL_VERSION;
|
|
75
|
+
repoId: string;
|
|
76
|
+
termStartMs: number;
|
|
77
|
+
termEndMs: number;
|
|
78
|
+
/** Winner with HIGHEST composite (alpha tie-break). */
|
|
79
|
+
winnerVendor: string | null;
|
|
80
|
+
margin: number;
|
|
81
|
+
/** Per-vendor scores, sorted by composite desc. */
|
|
82
|
+
scores: VendorScore[];
|
|
83
|
+
/** Total votes in this term. */
|
|
84
|
+
totalVotes: number;
|
|
85
|
+
decidedAtMs: number;
|
|
86
|
+
sig: string;
|
|
87
|
+
}
|
|
88
|
+
export declare function freshElectionState(input: {
|
|
89
|
+
repoId: string;
|
|
90
|
+
termStartMs?: number;
|
|
91
|
+
termMs?: number;
|
|
92
|
+
}): ElectionState;
|
|
93
|
+
export declare function recordVote(input: {
|
|
94
|
+
state: ElectionState;
|
|
95
|
+
vendor: string;
|
|
96
|
+
commitSha?: string;
|
|
97
|
+
castAtMs?: number;
|
|
98
|
+
secret?: string;
|
|
99
|
+
}): {
|
|
100
|
+
state: ElectionState;
|
|
101
|
+
vote: Vote | null;
|
|
102
|
+
reason?: string;
|
|
103
|
+
};
|
|
104
|
+
/** Verify HMAC chain integrity end-to-end. */
|
|
105
|
+
export declare function verifyVoteLedger(state: ElectionState, secret?: string): boolean;
|
|
106
|
+
export declare function tallyElection(input: {
|
|
107
|
+
state: ElectionState;
|
|
108
|
+
signals: VendorSignal[];
|
|
109
|
+
nowMs?: number;
|
|
110
|
+
secret?: string;
|
|
111
|
+
}): ElectionResult;
|
|
112
|
+
export declare function verifyElectionResult(r: ElectionResult, secret?: string): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* If the term has ended, tally + rotate to a fresh term with the winner
|
|
115
|
+
* installed as mayor. Idempotent if called mid-term — returns state unchanged.
|
|
116
|
+
*/
|
|
117
|
+
export declare function runScheduledElection(input: {
|
|
118
|
+
state: ElectionState;
|
|
119
|
+
signals: VendorSignal[];
|
|
120
|
+
nowMs?: number;
|
|
121
|
+
secret?: string;
|
|
122
|
+
}): {
|
|
123
|
+
state: ElectionState;
|
|
124
|
+
rotated: boolean;
|
|
125
|
+
result: ElectionResult;
|
|
126
|
+
};
|
|
127
|
+
export declare function formatMayorLine(result: ElectionResult | null): string;
|
|
128
|
+
export interface ElectionStats {
|
|
129
|
+
totalVotes: number;
|
|
130
|
+
uniqueVendors: number;
|
|
131
|
+
currentMayor: string | null;
|
|
132
|
+
termMs: number;
|
|
133
|
+
termRemainingMs: number;
|
|
134
|
+
}
|
|
135
|
+
export declare function computeElectionStats(state: ElectionState, nowMs?: number): ElectionStats;
|
|
136
|
+
export declare const MAYOR_ELECTION_TUNABLES: Readonly<{
|
|
137
|
+
PROTOCOL_VERSION: 1;
|
|
138
|
+
DEFAULT_TERM_MS: number;
|
|
139
|
+
COMPOSITE_WEIGHTS: Readonly<{
|
|
140
|
+
votes: 0.5;
|
|
141
|
+
reputation: 0.25;
|
|
142
|
+
fairness: 0.15;
|
|
143
|
+
trickTest: 0.1;
|
|
144
|
+
}>;
|
|
145
|
+
}>;
|
|
146
|
+
export {};
|
|
147
|
+
//# sourceMappingURL=index.d.ts.map
|