@mneme-ai/core 0.11.0 → 0.12.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/insights/chronicle.d.ts +41 -0
- package/dist/insights/chronicle.d.ts.map +1 -0
- package/dist/insights/chronicle.js +169 -0
- package/dist/insights/chronicle.js.map +1 -0
- package/dist/insights/chronicle.test.d.ts +2 -0
- package/dist/insights/chronicle.test.d.ts.map +1 -0
- package/dist/insights/chronicle.test.js +92 -0
- package/dist/insights/chronicle.test.js.map +1 -0
- package/dist/insights/constellation.d.ts +63 -0
- package/dist/insights/constellation.d.ts.map +1 -0
- package/dist/insights/constellation.js +147 -0
- package/dist/insights/constellation.js.map +1 -0
- package/dist/insights/constellation.test.d.ts +2 -0
- package/dist/insights/constellation.test.d.ts.map +1 -0
- package/dist/insights/constellation.test.js +105 -0
- package/dist/insights/constellation.test.js.map +1 -0
- package/dist/insights/dna.d.ts +100 -0
- package/dist/insights/dna.d.ts.map +1 -0
- package/dist/insights/dna.js +264 -0
- package/dist/insights/dna.js.map +1 -0
- package/dist/insights/dna.test.d.ts +2 -0
- package/dist/insights/dna.test.d.ts.map +1 -0
- package/dist/insights/dna.test.js +142 -0
- package/dist/insights/dna.test.js.map +1 -0
- package/dist/insights/drift.d.ts +43 -0
- package/dist/insights/drift.d.ts.map +1 -0
- package/dist/insights/drift.js +170 -0
- package/dist/insights/drift.js.map +1 -0
- package/dist/insights/drift.test.d.ts +2 -0
- package/dist/insights/drift.test.d.ts.map +1 -0
- package/dist/insights/drift.test.js +126 -0
- package/dist/insights/drift.test.js.map +1 -0
- package/dist/insights/index.d.ts +5 -0
- package/dist/insights/index.d.ts.map +1 -1
- package/dist/insights/index.js +5 -0
- package/dist/insights/index.js.map +1 -1
- package/dist/insights/oracle.d.ts +59 -0
- package/dist/insights/oracle.d.ts.map +1 -0
- package/dist/insights/oracle.js +0 -0
- package/dist/insights/oracle.js.map +1 -0
- package/dist/insights/oracle.test.d.ts +2 -0
- package/dist/insights/oracle.test.d.ts.map +1 -0
- package/dist/insights/oracle.test.js +133 -0
- package/dist/insights/oracle.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { extractDna, compareDna } from "./dna.js";
|
|
3
|
+
function mk(p) {
|
|
4
|
+
return {
|
|
5
|
+
hash: p.hash,
|
|
6
|
+
shortHash: p.hash.slice(0, 7),
|
|
7
|
+
authorName: p.author ?? "Alice",
|
|
8
|
+
authorEmail: p.email ?? "alice@example.com",
|
|
9
|
+
authorDate: p.date,
|
|
10
|
+
committerDate: p.date,
|
|
11
|
+
subject: p.subject,
|
|
12
|
+
body: p.body ?? "",
|
|
13
|
+
files: p.files ?? ["src/x.ts"],
|
|
14
|
+
parents: [],
|
|
15
|
+
prNumber: p.pr,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
describe("extractDna", () => {
|
|
19
|
+
it("returns empty strand when no commits match author", () => {
|
|
20
|
+
const dna = extractDna([], "alice@example.com");
|
|
21
|
+
expect(dna.commitCount).toBe(0);
|
|
22
|
+
expect(dna.hash).toBe("0000000");
|
|
23
|
+
});
|
|
24
|
+
it("extracts commitCount and date range correctly", () => {
|
|
25
|
+
const commits = [
|
|
26
|
+
mk({ hash: "a1", date: "2024-01-15T09:00:00Z", subject: "init" }),
|
|
27
|
+
mk({ hash: "a2", date: "2024-06-22T14:00:00Z", subject: "polish" }),
|
|
28
|
+
];
|
|
29
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
30
|
+
expect(dna.commitCount).toBe(2);
|
|
31
|
+
expect(dna.fromDate).toBe("2024-01-15");
|
|
32
|
+
expect(dna.toDate).toBe("2024-06-22");
|
|
33
|
+
});
|
|
34
|
+
it("filters by author email or name", () => {
|
|
35
|
+
const commits = [
|
|
36
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "alice work", author: "Alice", email: "alice@x.com" }),
|
|
37
|
+
mk({ hash: "b1", date: "2024-01-02T09:00:00Z", subject: "bob work", author: "Bob", email: "bob@x.com" }),
|
|
38
|
+
];
|
|
39
|
+
const aliceDna = extractDna(commits, "alice@x.com");
|
|
40
|
+
expect(aliceDna.commitCount).toBe(1);
|
|
41
|
+
const bobDna = extractDna(commits, "Bob");
|
|
42
|
+
expect(bobDna.commitCount).toBe(1);
|
|
43
|
+
});
|
|
44
|
+
it("conventionalRatio detects conventional-commit prefixes", () => {
|
|
45
|
+
const commits = [
|
|
46
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "feat(core): add caching" }),
|
|
47
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "fix: handle null body" }),
|
|
48
|
+
mk({ hash: "a3", date: "2024-01-03T09:00:00Z", subject: "random subject" }),
|
|
49
|
+
];
|
|
50
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
51
|
+
expect(dna.style.conventionalRatio).toBeCloseTo(2 / 3, 2);
|
|
52
|
+
});
|
|
53
|
+
it("imperativeRatio rises when subjects start with imperatives", () => {
|
|
54
|
+
const commits = [
|
|
55
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "Add caching" }),
|
|
56
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "fix typo" }),
|
|
57
|
+
mk({ hash: "a3", date: "2024-01-03T09:00:00Z", subject: "Update docs" }),
|
|
58
|
+
];
|
|
59
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
60
|
+
expect(dna.message.imperativeRatio).toBeGreaterThan(0.6);
|
|
61
|
+
});
|
|
62
|
+
it("bodyRatio counts only commits with non-empty body", () => {
|
|
63
|
+
const commits = [
|
|
64
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "A", body: "explains why" }),
|
|
65
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "B" }),
|
|
66
|
+
];
|
|
67
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
68
|
+
expect(dna.message.bodyRatio).toBeCloseTo(0.5, 2);
|
|
69
|
+
});
|
|
70
|
+
it("topVerbs lists most-used leading verbs", () => {
|
|
71
|
+
const commits = [
|
|
72
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "add x" }),
|
|
73
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "add y" }),
|
|
74
|
+
mk({ hash: "a3", date: "2024-01-03T09:00:00Z", subject: "fix z" }),
|
|
75
|
+
];
|
|
76
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
77
|
+
expect(dna.message.topVerbs[0]?.verb).toBe("add");
|
|
78
|
+
expect(dna.message.topVerbs[0]?.count).toBe(2);
|
|
79
|
+
});
|
|
80
|
+
it("hours histogram counts each commit by UTC hour", () => {
|
|
81
|
+
const commits = [
|
|
82
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "x" }),
|
|
83
|
+
mk({ hash: "a2", date: "2024-01-02T09:30:00Z", subject: "x" }),
|
|
84
|
+
mk({ hash: "a3", date: "2024-01-03T15:00:00Z", subject: "x" }),
|
|
85
|
+
];
|
|
86
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
87
|
+
expect(dna.hours.byHour[9]).toBe(2);
|
|
88
|
+
expect(dna.hours.byHour[15]).toBe(1);
|
|
89
|
+
});
|
|
90
|
+
it("weekendRatio reflects Sat/Sun commits", () => {
|
|
91
|
+
// 2024-06-15 is Saturday, 2024-06-17 is Monday
|
|
92
|
+
const commits = [
|
|
93
|
+
mk({ hash: "a1", date: "2024-06-15T09:00:00Z", subject: "weekend work" }),
|
|
94
|
+
mk({ hash: "a2", date: "2024-06-17T09:00:00Z", subject: "weekday work" }),
|
|
95
|
+
];
|
|
96
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
97
|
+
expect(dna.hours.weekendRatio).toBe(0.5);
|
|
98
|
+
});
|
|
99
|
+
it("topDirs reflects most-touched root directories", () => {
|
|
100
|
+
const commits = [
|
|
101
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "x", files: ["src/auth/x.ts", "src/auth/y.ts"] }),
|
|
102
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "x", files: ["src/payments/z.ts"] }),
|
|
103
|
+
];
|
|
104
|
+
const dna = extractDna(commits, "alice@example.com");
|
|
105
|
+
const topDir = dna.files.topDirs[0]?.dir;
|
|
106
|
+
expect(topDir).toMatch(/^src\//);
|
|
107
|
+
});
|
|
108
|
+
it("hash is deterministic for the same input", () => {
|
|
109
|
+
const commits = [
|
|
110
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "init" }),
|
|
111
|
+
];
|
|
112
|
+
const a = extractDna(commits, "alice@example.com");
|
|
113
|
+
const b = extractDna(commits, "alice@example.com");
|
|
114
|
+
expect(a.hash).toBe(b.hash);
|
|
115
|
+
expect(a.hash.length).toBe(7);
|
|
116
|
+
});
|
|
117
|
+
it("compareDna returns similarity 1.0 for two identical strands", () => {
|
|
118
|
+
const commits = [
|
|
119
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "feat: add caching" }),
|
|
120
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "fix: handle null" }),
|
|
121
|
+
];
|
|
122
|
+
const a = extractDna(commits, "alice@example.com");
|
|
123
|
+
const b = extractDna(commits, "alice@example.com");
|
|
124
|
+
const cmp = compareDna(a, b);
|
|
125
|
+
expect(cmp.similarity).toBeGreaterThan(0.95);
|
|
126
|
+
});
|
|
127
|
+
it("compareDna returns lower similarity for divergent styles", () => {
|
|
128
|
+
const aliceCommits = [
|
|
129
|
+
mk({ hash: "a1", date: "2024-01-01T09:00:00Z", subject: "feat: add x", author: "Alice", email: "a@x.com", files: ["src/auth/a.ts"] }),
|
|
130
|
+
mk({ hash: "a2", date: "2024-01-02T09:00:00Z", subject: "feat: add y", author: "Alice", email: "a@x.com", files: ["src/auth/b.ts"] }),
|
|
131
|
+
];
|
|
132
|
+
const bobCommits = [
|
|
133
|
+
mk({ hash: "b1", date: "2024-01-01T22:00:00Z", subject: "did some stuff", author: "Bob", email: "b@x.com", files: ["legacy/c.py"] }),
|
|
134
|
+
mk({ hash: "b2", date: "2024-01-02T23:00:00Z", subject: "more random work", author: "Bob", email: "b@x.com", files: ["legacy/d.py"] }),
|
|
135
|
+
];
|
|
136
|
+
const a = extractDna(aliceCommits, "a@x.com");
|
|
137
|
+
const b = extractDna(bobCommits, "b@x.com");
|
|
138
|
+
const cmp = compareDna(a, b);
|
|
139
|
+
expect(cmp.similarity).toBeLessThan(0.7);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=dna.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dna.test.js","sourceRoot":"","sources":["../../src/insights/dna.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme drift` — visualize topical drift in a repo's commits over time.
|
|
3
|
+
*
|
|
4
|
+
* Buckets commits into time windows (default: quarter), classifies each
|
|
5
|
+
* commit by intent (feature / refactor / firefight / polish / docs), then
|
|
6
|
+
* emits per-bucket distributions you can plot or render as a sparkline.
|
|
7
|
+
*
|
|
8
|
+
* Why novel: shipped products do not exist for this. Academic papers
|
|
9
|
+
* (arxiv 2110.00697, etc.) cluster commits semantically but stop at the
|
|
10
|
+
* paper. Mneme's drift command brings it to the CLI.
|
|
11
|
+
*/
|
|
12
|
+
import type { Commit } from "../types.js";
|
|
13
|
+
export type DriftKind = "feature" | "refactor" | "firefight" | "polish" | "docs" | "other";
|
|
14
|
+
export interface DriftBucket {
|
|
15
|
+
/** Window label e.g. "2024-Q1" or "2024-08". */
|
|
16
|
+
label: string;
|
|
17
|
+
fromDate: string;
|
|
18
|
+
toDate: string;
|
|
19
|
+
/** Total commits in window. */
|
|
20
|
+
total: number;
|
|
21
|
+
/** Counts by drift kind. */
|
|
22
|
+
byKind: Record<DriftKind, number>;
|
|
23
|
+
/** Dominant kind for this window (highest count). */
|
|
24
|
+
dominant: DriftKind;
|
|
25
|
+
}
|
|
26
|
+
export interface DriftReport {
|
|
27
|
+
/** Granularity used. */
|
|
28
|
+
granularity: "quarter" | "month";
|
|
29
|
+
buckets: DriftBucket[];
|
|
30
|
+
/** Insights derived from the trajectory. */
|
|
31
|
+
insights: DriftInsight[];
|
|
32
|
+
}
|
|
33
|
+
export interface DriftInsight {
|
|
34
|
+
kind: "burnout" | "recovery" | "rewrite-cluster" | "polish-streak" | "shift";
|
|
35
|
+
fromBucket: string;
|
|
36
|
+
toBucket: string;
|
|
37
|
+
description: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function classifyCommit(c: Commit): DriftKind;
|
|
40
|
+
export declare function buildDrift(commits: Commit[], opts?: {
|
|
41
|
+
granularity?: "quarter" | "month";
|
|
42
|
+
}): DriftReport;
|
|
43
|
+
//# sourceMappingURL=drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../../src/insights/drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3F,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAClC,qDAAqD;IACrD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,WAAW,EAAE,SAAS,GAAG,OAAO,CAAC;IACjC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,4CAA4C;IAC5C,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,iBAAiB,GAAG,eAAe,GAAG,OAAO,CAAC;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAUD,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAQnD;AAED,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAAO,GAC/C,WAAW,CAoDb"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
const FEATURE_RE = /\b(feat|feature|add|implement|introduce|support|expose)\b/i;
|
|
2
|
+
const REFACTOR_RE = /\b(refactor|rewrite|migrate|switch(?:ed)? to|extract|consolidate|simplify)\b/i;
|
|
3
|
+
const FIRE_RE = /\b(fix|hotfix|revert|rollback|broken|crash|regression|emergency|urgent|critical)\b/i;
|
|
4
|
+
const POLISH_RE = /\b(typo|format|lint|rename|comment|whitespace|cleanup|chore|polish|tighten)\b/i;
|
|
5
|
+
const DOCS_RE = /\b(docs?|readme|comment|documentation)\b/i;
|
|
6
|
+
const KINDS = ["feature", "refactor", "firefight", "polish", "docs", "other"];
|
|
7
|
+
export function classifyCommit(c) {
|
|
8
|
+
const text = `${c.subject}\n${c.body || ""}`;
|
|
9
|
+
if (FIRE_RE.test(text))
|
|
10
|
+
return "firefight";
|
|
11
|
+
if (REFACTOR_RE.test(text))
|
|
12
|
+
return "refactor";
|
|
13
|
+
if (FEATURE_RE.test(text))
|
|
14
|
+
return "feature";
|
|
15
|
+
if (DOCS_RE.test(text))
|
|
16
|
+
return "docs";
|
|
17
|
+
if (POLISH_RE.test(text))
|
|
18
|
+
return "polish";
|
|
19
|
+
return "other";
|
|
20
|
+
}
|
|
21
|
+
export function buildDrift(commits, opts = {}) {
|
|
22
|
+
const granularity = opts.granularity ?? "quarter";
|
|
23
|
+
const sorted = [...commits].sort((a, b) => a.authorDate.localeCompare(b.authorDate));
|
|
24
|
+
if (sorted.length === 0) {
|
|
25
|
+
return { granularity, buckets: [], insights: [] };
|
|
26
|
+
}
|
|
27
|
+
const buckets = new Map();
|
|
28
|
+
for (const c of sorted) {
|
|
29
|
+
const label = labelOf(c.authorDate, granularity);
|
|
30
|
+
const range = rangeOf(label, granularity);
|
|
31
|
+
let b = buckets.get(label);
|
|
32
|
+
if (!b) {
|
|
33
|
+
b = {
|
|
34
|
+
label,
|
|
35
|
+
fromDate: range.from,
|
|
36
|
+
toDate: range.to,
|
|
37
|
+
total: 0,
|
|
38
|
+
byKind: { feature: 0, refactor: 0, firefight: 0, polish: 0, docs: 0, other: 0 },
|
|
39
|
+
dominant: "other",
|
|
40
|
+
};
|
|
41
|
+
buckets.set(label, b);
|
|
42
|
+
}
|
|
43
|
+
const k = classifyCommit(c);
|
|
44
|
+
b.byKind[k] += 1;
|
|
45
|
+
b.total += 1;
|
|
46
|
+
}
|
|
47
|
+
// resolve dominant
|
|
48
|
+
for (const b of buckets.values()) {
|
|
49
|
+
let best = "other";
|
|
50
|
+
let bestN = -1;
|
|
51
|
+
for (const k of KINDS) {
|
|
52
|
+
const n = b.byKind[k];
|
|
53
|
+
if (n > bestN) {
|
|
54
|
+
bestN = n;
|
|
55
|
+
best = k;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
b.dominant = best;
|
|
59
|
+
}
|
|
60
|
+
const ordered = [...buckets.values()].sort((a, b) => a.fromDate.localeCompare(b.fromDate));
|
|
61
|
+
return {
|
|
62
|
+
granularity,
|
|
63
|
+
buckets: ordered,
|
|
64
|
+
insights: detectInsights(ordered),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function detectInsights(buckets) {
|
|
68
|
+
const out = [];
|
|
69
|
+
if (buckets.length < 2)
|
|
70
|
+
return out;
|
|
71
|
+
// Burnout: firefight ratio rises ≥ 30 percentage points across 2+ adjacent buckets.
|
|
72
|
+
for (let i = 1; i < buckets.length; i++) {
|
|
73
|
+
const prev = buckets[i - 1];
|
|
74
|
+
const cur = buckets[i];
|
|
75
|
+
const prevFire = ratio(prev.byKind.firefight, prev.total);
|
|
76
|
+
const curFire = ratio(cur.byKind.firefight, cur.total);
|
|
77
|
+
if (curFire - prevFire >= 0.3 && cur.total >= 5) {
|
|
78
|
+
out.push({
|
|
79
|
+
kind: "burnout",
|
|
80
|
+
fromBucket: prev.label,
|
|
81
|
+
toBucket: cur.label,
|
|
82
|
+
description: `firefight ratio jumped from ${pct(prevFire)} to ${pct(curFire)} — possible incident streak or burnout signal.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (prevFire >= 0.4 && curFire < prevFire - 0.2) {
|
|
86
|
+
out.push({
|
|
87
|
+
kind: "recovery",
|
|
88
|
+
fromBucket: prev.label,
|
|
89
|
+
toBucket: cur.label,
|
|
90
|
+
description: `firefight ratio fell from ${pct(prevFire)} to ${pct(curFire)} — repo stabilizing.`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Rewrite cluster: 2+ adjacent buckets where dominant = refactor
|
|
95
|
+
for (let i = 0; i < buckets.length - 1; i++) {
|
|
96
|
+
if (buckets[i].dominant === "refactor" && buckets[i + 1].dominant === "refactor") {
|
|
97
|
+
out.push({
|
|
98
|
+
kind: "rewrite-cluster",
|
|
99
|
+
fromBucket: buckets[i].label,
|
|
100
|
+
toBucket: buckets[i + 1].label,
|
|
101
|
+
description: `consecutive periods dominated by refactors — major restructuring effort.`,
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Polish streak: 3+ adjacent buckets dominated by polish or docs
|
|
107
|
+
let polishRun = 0;
|
|
108
|
+
let polishStart = "";
|
|
109
|
+
for (const b of buckets) {
|
|
110
|
+
if (b.dominant === "polish" || b.dominant === "docs") {
|
|
111
|
+
if (polishRun === 0)
|
|
112
|
+
polishStart = b.label;
|
|
113
|
+
polishRun++;
|
|
114
|
+
if (polishRun >= 3) {
|
|
115
|
+
out.push({
|
|
116
|
+
kind: "polish-streak",
|
|
117
|
+
fromBucket: polishStart,
|
|
118
|
+
toBucket: b.label,
|
|
119
|
+
description: `${polishRun} consecutive periods of polish/docs — mature, stable phase.`,
|
|
120
|
+
});
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
polishRun = 0;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
function ratio(num, denom) {
|
|
131
|
+
return denom === 0 ? 0 : num / denom;
|
|
132
|
+
}
|
|
133
|
+
function pct(r) {
|
|
134
|
+
return `${Math.round(r * 100)}%`;
|
|
135
|
+
}
|
|
136
|
+
function labelOf(iso, gran) {
|
|
137
|
+
const d = new Date(iso);
|
|
138
|
+
if (Number.isNaN(d.getTime()))
|
|
139
|
+
return "unknown";
|
|
140
|
+
const y = d.getUTCFullYear();
|
|
141
|
+
const m = d.getUTCMonth(); // 0..11
|
|
142
|
+
if (gran === "month") {
|
|
143
|
+
return `${y}-${String(m + 1).padStart(2, "0")}`;
|
|
144
|
+
}
|
|
145
|
+
const q = Math.floor(m / 3) + 1;
|
|
146
|
+
return `${y}-Q${q}`;
|
|
147
|
+
}
|
|
148
|
+
function rangeOf(label, gran) {
|
|
149
|
+
if (gran === "month") {
|
|
150
|
+
const [y, m] = label.split("-");
|
|
151
|
+
const ynum = Number(y);
|
|
152
|
+
const mnum = Number(m);
|
|
153
|
+
const last = new Date(Date.UTC(ynum, mnum, 0));
|
|
154
|
+
return {
|
|
155
|
+
from: `${y}-${m}-01`,
|
|
156
|
+
to: `${y}-${m}-${String(last.getUTCDate()).padStart(2, "0")}`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// quarter
|
|
160
|
+
const [y, qstr] = label.split("-Q");
|
|
161
|
+
const q = Number(qstr);
|
|
162
|
+
const startMonth = (q - 1) * 3 + 1;
|
|
163
|
+
const endMonth = startMonth + 2;
|
|
164
|
+
const last = new Date(Date.UTC(Number(y), endMonth, 0));
|
|
165
|
+
return {
|
|
166
|
+
from: `${y}-${String(startMonth).padStart(2, "0")}-01`,
|
|
167
|
+
to: `${y}-${String(endMonth).padStart(2, "0")}-${String(last.getUTCDate()).padStart(2, "0")}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/insights/drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.test.d.ts","sourceRoot":"","sources":["../../src/insights/drift.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { buildDrift, classifyCommit } from "./drift.js";
|
|
3
|
+
function mk(p) {
|
|
4
|
+
return {
|
|
5
|
+
hash: p.hash,
|
|
6
|
+
shortHash: p.hash.slice(0, 7),
|
|
7
|
+
authorName: "Test",
|
|
8
|
+
authorEmail: "t@e.com",
|
|
9
|
+
authorDate: p.date,
|
|
10
|
+
committerDate: p.date,
|
|
11
|
+
subject: p.subject,
|
|
12
|
+
body: p.body ?? "",
|
|
13
|
+
files: [],
|
|
14
|
+
parents: [],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
describe("classifyCommit", () => {
|
|
18
|
+
it("classifies firefight from fix/hotfix/revert keywords", () => {
|
|
19
|
+
expect(classifyCommit(mk({ hash: "a", date: "2024-01-01", subject: "fix bug" }))).toBe("firefight");
|
|
20
|
+
expect(classifyCommit(mk({ hash: "b", date: "2024-01-01", subject: "hotfix critical" }))).toBe("firefight");
|
|
21
|
+
expect(classifyCommit(mk({ hash: "c", date: "2024-01-01", subject: "revert bad change" }))).toBe("firefight");
|
|
22
|
+
});
|
|
23
|
+
it("classifies refactor from rewrite/migrate keywords", () => {
|
|
24
|
+
expect(classifyCommit(mk({ hash: "a", date: "2024-01-01", subject: "refactor handler" }))).toBe("refactor");
|
|
25
|
+
expect(classifyCommit(mk({ hash: "b", date: "2024-01-01", subject: "rewrite parser" }))).toBe("refactor");
|
|
26
|
+
expect(classifyCommit(mk({ hash: "c", date: "2024-01-01", subject: "migrate to v3" }))).toBe("refactor");
|
|
27
|
+
});
|
|
28
|
+
it("classifies feature from feat/add/implement keywords", () => {
|
|
29
|
+
expect(classifyCommit(mk({ hash: "a", date: "2024-01-01", subject: "feat: add caching" }))).toBe("feature");
|
|
30
|
+
expect(classifyCommit(mk({ hash: "b", date: "2024-01-01", subject: "add new endpoint" }))).toBe("feature");
|
|
31
|
+
expect(classifyCommit(mk({ hash: "c", date: "2024-01-01", subject: "implement OAuth" }))).toBe("feature");
|
|
32
|
+
});
|
|
33
|
+
it("classifies polish from chore/typo/format keywords", () => {
|
|
34
|
+
expect(classifyCommit(mk({ hash: "a", date: "2024-01-01", subject: "chore: reformat" }))).toBe("polish");
|
|
35
|
+
expect(classifyCommit(mk({ hash: "b", date: "2024-01-01", subject: "fix typo in README" }))).toBe("firefight");
|
|
36
|
+
});
|
|
37
|
+
it("falls back to 'other' for ambiguous subjects", () => {
|
|
38
|
+
expect(classifyCommit(mk({ hash: "a", date: "2024-01-01", subject: "merge branch" }))).toBe("other");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe("buildDrift", () => {
|
|
42
|
+
it("returns empty report for empty input", () => {
|
|
43
|
+
const r = buildDrift([]);
|
|
44
|
+
expect(r.buckets).toHaveLength(0);
|
|
45
|
+
expect(r.insights).toHaveLength(0);
|
|
46
|
+
});
|
|
47
|
+
it("groups commits into quarter buckets by default", () => {
|
|
48
|
+
const commits = [
|
|
49
|
+
mk({ hash: "a1", date: "2024-01-15", subject: "feat: x" }),
|
|
50
|
+
mk({ hash: "a2", date: "2024-04-15", subject: "feat: y" }),
|
|
51
|
+
mk({ hash: "a3", date: "2024-08-15", subject: "feat: z" }),
|
|
52
|
+
];
|
|
53
|
+
const r = buildDrift(commits);
|
|
54
|
+
expect(r.granularity).toBe("quarter");
|
|
55
|
+
expect(r.buckets.length).toBe(3);
|
|
56
|
+
expect(r.buckets[0].label).toBe("2024-Q1");
|
|
57
|
+
expect(r.buckets[1].label).toBe("2024-Q2");
|
|
58
|
+
expect(r.buckets[2].label).toBe("2024-Q3");
|
|
59
|
+
});
|
|
60
|
+
it("supports month granularity", () => {
|
|
61
|
+
const commits = [
|
|
62
|
+
mk({ hash: "a1", date: "2024-01-15", subject: "x" }),
|
|
63
|
+
mk({ hash: "a2", date: "2024-02-15", subject: "y" }),
|
|
64
|
+
];
|
|
65
|
+
const r = buildDrift(commits, { granularity: "month" });
|
|
66
|
+
expect(r.granularity).toBe("month");
|
|
67
|
+
expect(r.buckets[0].label).toBe("2024-01");
|
|
68
|
+
expect(r.buckets[1].label).toBe("2024-02");
|
|
69
|
+
});
|
|
70
|
+
it("dominant kind is the highest-count category in a bucket", () => {
|
|
71
|
+
const commits = [
|
|
72
|
+
mk({ hash: "a1", date: "2024-01-01", subject: "fix bug 1" }),
|
|
73
|
+
mk({ hash: "a2", date: "2024-01-02", subject: "fix bug 2" }),
|
|
74
|
+
mk({ hash: "a3", date: "2024-01-03", subject: "feat: add x" }),
|
|
75
|
+
];
|
|
76
|
+
const r = buildDrift(commits);
|
|
77
|
+
expect(r.buckets[0].dominant).toBe("firefight");
|
|
78
|
+
});
|
|
79
|
+
it("detects burnout insight when firefight ratio jumps", () => {
|
|
80
|
+
const commits = [];
|
|
81
|
+
// Q1: 5 features
|
|
82
|
+
for (let i = 0; i < 5; i++) {
|
|
83
|
+
commits.push(mk({ hash: `f${i}`, date: `2024-01-${(i + 1).toString().padStart(2, "0")}`, subject: `feat: x${i}` }));
|
|
84
|
+
}
|
|
85
|
+
// Q2: 5 fires
|
|
86
|
+
for (let i = 0; i < 5; i++) {
|
|
87
|
+
commits.push(mk({ hash: `b${i}`, date: `2024-04-${(i + 1).toString().padStart(2, "0")}`, subject: `fix bug ${i}` }));
|
|
88
|
+
}
|
|
89
|
+
const r = buildDrift(commits);
|
|
90
|
+
expect(r.insights.some((i) => i.kind === "burnout")).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
it("detects recovery insight when firefight ratio falls", () => {
|
|
93
|
+
const commits = [];
|
|
94
|
+
for (let i = 0; i < 5; i++) {
|
|
95
|
+
commits.push(mk({ hash: `b${i}`, date: `2024-01-${(i + 1).toString().padStart(2, "0")}`, subject: `fix bug ${i}` }));
|
|
96
|
+
}
|
|
97
|
+
for (let i = 0; i < 5; i++) {
|
|
98
|
+
commits.push(mk({ hash: `f${i}`, date: `2024-04-${(i + 1).toString().padStart(2, "0")}`, subject: `feat: nice thing ${i}` }));
|
|
99
|
+
}
|
|
100
|
+
const r = buildDrift(commits);
|
|
101
|
+
expect(r.insights.some((i) => i.kind === "recovery")).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
it("detects rewrite cluster across consecutive quarters", () => {
|
|
104
|
+
const commits = [];
|
|
105
|
+
for (let i = 0; i < 4; i++) {
|
|
106
|
+
commits.push(mk({ hash: `r${i}`, date: `2024-01-${(i + 1).toString().padStart(2, "0")}`, subject: `refactor module ${i}` }));
|
|
107
|
+
}
|
|
108
|
+
for (let i = 0; i < 4; i++) {
|
|
109
|
+
commits.push(mk({ hash: `s${i}`, date: `2024-04-${(i + 1).toString().padStart(2, "0")}`, subject: `rewrite component ${i}` }));
|
|
110
|
+
}
|
|
111
|
+
const r = buildDrift(commits);
|
|
112
|
+
expect(r.insights.some((i) => i.kind === "rewrite-cluster")).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it("orders buckets chronologically by fromDate", () => {
|
|
115
|
+
const commits = [
|
|
116
|
+
mk({ hash: "a3", date: "2025-01-15", subject: "x" }),
|
|
117
|
+
mk({ hash: "a1", date: "2024-01-15", subject: "x" }),
|
|
118
|
+
mk({ hash: "a2", date: "2024-04-15", subject: "x" }),
|
|
119
|
+
];
|
|
120
|
+
const r = buildDrift(commits);
|
|
121
|
+
for (let i = 1; i < r.buckets.length; i++) {
|
|
122
|
+
expect(r.buckets[i - 1].fromDate.localeCompare(r.buckets[i].fromDate)).toBeLessThan(0);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=drift.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.test.js","sourceRoot":"","sources":["../../src/insights/drift.test.ts"],"names":[],"mappings":"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"}
|
package/dist/insights/index.d.ts
CHANGED
|
@@ -21,4 +21,9 @@ export * from "./crystal-ball.js";
|
|
|
21
21
|
export * from "./time-machine.js";
|
|
22
22
|
export * from "./premortem.js";
|
|
23
23
|
export * from "./ghost.js";
|
|
24
|
+
export * from "./dna.js";
|
|
25
|
+
export * from "./drift.js";
|
|
26
|
+
export * from "./chronicle.js";
|
|
27
|
+
export * from "./oracle.js";
|
|
28
|
+
export * from "./constellation.js";
|
|
24
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/insights/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/insights/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
package/dist/insights/index.js
CHANGED
|
@@ -21,4 +21,9 @@ export * from "./crystal-ball.js";
|
|
|
21
21
|
export * from "./time-machine.js";
|
|
22
22
|
export * from "./premortem.js";
|
|
23
23
|
export * from "./ghost.js";
|
|
24
|
+
export * from "./dna.js";
|
|
25
|
+
export * from "./drift.js";
|
|
26
|
+
export * from "./chronicle.js";
|
|
27
|
+
export * from "./oracle.js";
|
|
28
|
+
export * from "./constellation.js";
|
|
24
29
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/insights/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/insights/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme oracle` — predict near-future co-edits and surface likely
|
|
3
|
+
* collisions where two authors will both touch the same file.
|
|
4
|
+
*
|
|
5
|
+
* Builds an author-file affinity matrix from recent history (default:
|
|
6
|
+
* last 90 days), then projects the per-author probability of touching
|
|
7
|
+
* each file in the upcoming window. When two authors both have high
|
|
8
|
+
* probability for the same file, that's a *predicted collision* —
|
|
9
|
+
* worth flagging for a quick sync.
|
|
10
|
+
*
|
|
11
|
+
* Pure data extraction. No external services. Mneme owns the WHO and
|
|
12
|
+
* the WHAT; this combines them.
|
|
13
|
+
*/
|
|
14
|
+
import type { Commit } from "../types.js";
|
|
15
|
+
export interface AuthorFileAffinity {
|
|
16
|
+
author: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
/** How many times the author touched the file in the window. */
|
|
19
|
+
touches: number;
|
|
20
|
+
/** Recency-weighted score 0..1 (more recent = higher). */
|
|
21
|
+
score: number;
|
|
22
|
+
}
|
|
23
|
+
export interface FilePrediction {
|
|
24
|
+
filePath: string;
|
|
25
|
+
/** Top likely editors with probabilities (sorted). */
|
|
26
|
+
candidates: Array<{
|
|
27
|
+
author: string;
|
|
28
|
+
probability: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface Collision {
|
|
32
|
+
filePath: string;
|
|
33
|
+
authorA: string;
|
|
34
|
+
authorB: string;
|
|
35
|
+
/** Joint probability — geometric mean of the two individual probabilities. */
|
|
36
|
+
jointProbability: number;
|
|
37
|
+
/** How recently they both touched it together (days ago, or -1 if never). */
|
|
38
|
+
daysSinceLastJointTouch: number;
|
|
39
|
+
}
|
|
40
|
+
export interface OracleReport {
|
|
41
|
+
/** Total commits considered. */
|
|
42
|
+
windowCommits: number;
|
|
43
|
+
/** Top per-file predictions. */
|
|
44
|
+
predictions: FilePrediction[];
|
|
45
|
+
/** Predicted collisions sorted by jointProbability desc. */
|
|
46
|
+
collisions: Collision[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build an Oracle report. Caller passes the full commit history; we
|
|
50
|
+
* keep only the recent window.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildOracle(commits: Commit[], opts?: {
|
|
53
|
+
nowMs?: number;
|
|
54
|
+
windowDays?: number;
|
|
55
|
+
topPredictionsPerFile?: number;
|
|
56
|
+
minTouchesForFile?: number;
|
|
57
|
+
collisionFloor?: number;
|
|
58
|
+
}): OracleReport;
|
|
59
|
+
//# sourceMappingURL=oracle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracle.d.ts","sourceRoot":"","sources":["../../src/insights/oracle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,UAAU,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,4DAA4D;IAC5D,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE;IACJ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACpB,GACL,YAAY,CA2Fd"}
|
|
Binary file
|