@mmnto/cli 1.5.9 → 1.5.11

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 (97) hide show
  1. package/dist/adapters/github-cli-pr.d.ts +7 -0
  2. package/dist/adapters/github-cli-pr.d.ts.map +1 -1
  3. package/dist/adapters/github-cli-pr.js +31 -1
  4. package/dist/adapters/github-cli-pr.js.map +1 -1
  5. package/dist/adapters/pr-adapter.d.ts +7 -0
  6. package/dist/adapters/pr-adapter.d.ts.map +1 -1
  7. package/dist/commands/check.d.ts +6 -0
  8. package/dist/commands/check.d.ts.map +1 -0
  9. package/dist/commands/check.js +34 -0
  10. package/dist/commands/check.js.map +1 -0
  11. package/dist/commands/check.test.d.ts +2 -0
  12. package/dist/commands/check.test.d.ts.map +1 -0
  13. package/dist/commands/check.test.js +60 -0
  14. package/dist/commands/check.test.js.map +1 -0
  15. package/dist/commands/docs.d.ts +8 -1
  16. package/dist/commands/docs.d.ts.map +1 -1
  17. package/dist/commands/docs.js +13 -10
  18. package/dist/commands/docs.js.map +1 -1
  19. package/dist/commands/docs.test.js +22 -2
  20. package/dist/commands/docs.test.js.map +1 -1
  21. package/dist/commands/extract.d.ts +1 -0
  22. package/dist/commands/extract.d.ts.map +1 -1
  23. package/dist/commands/extract.js +1 -1
  24. package/dist/commands/extract.js.map +1 -1
  25. package/dist/commands/ledger-analyzer.d.ts.map +1 -1
  26. package/dist/commands/ledger-analyzer.js +2 -0
  27. package/dist/commands/ledger-analyzer.js.map +1 -1
  28. package/dist/commands/review-learn.d.ts.map +1 -1
  29. package/dist/commands/review-learn.js +38 -1
  30. package/dist/commands/review-learn.js.map +1 -1
  31. package/dist/commands/shield-incremental.test.d.ts +2 -0
  32. package/dist/commands/shield-incremental.test.d.ts.map +1 -0
  33. package/dist/commands/shield-incremental.test.js +164 -0
  34. package/dist/commands/shield-incremental.test.js.map +1 -0
  35. package/dist/commands/shield.d.ts +9 -0
  36. package/dist/commands/shield.d.ts.map +1 -1
  37. package/dist/commands/shield.js +145 -13
  38. package/dist/commands/shield.js.map +1 -1
  39. package/dist/commands/status.d.ts +2 -0
  40. package/dist/commands/status.d.ts.map +1 -0
  41. package/dist/commands/status.js +88 -0
  42. package/dist/commands/status.js.map +1 -0
  43. package/dist/commands/status.test.d.ts +2 -0
  44. package/dist/commands/status.test.d.ts.map +1 -0
  45. package/dist/commands/status.test.js +131 -0
  46. package/dist/commands/status.test.js.map +1 -0
  47. package/dist/commands/triage-pr.d.ts +4 -1
  48. package/dist/commands/triage-pr.d.ts.map +1 -1
  49. package/dist/commands/triage-pr.js +163 -3
  50. package/dist/commands/triage-pr.js.map +1 -1
  51. package/dist/exemptions/__tests__/exemption-engine.test.d.ts +2 -0
  52. package/dist/exemptions/__tests__/exemption-engine.test.d.ts.map +1 -0
  53. package/dist/exemptions/__tests__/exemption-engine.test.js +317 -0
  54. package/dist/exemptions/__tests__/exemption-engine.test.js.map +1 -0
  55. package/dist/exemptions/exemption-engine.d.ts +27 -0
  56. package/dist/exemptions/exemption-engine.d.ts.map +1 -0
  57. package/dist/exemptions/exemption-engine.js +193 -0
  58. package/dist/exemptions/exemption-engine.js.map +1 -0
  59. package/dist/exemptions/exemption-schema.d.ts +127 -0
  60. package/dist/exemptions/exemption-schema.d.ts.map +1 -0
  61. package/dist/exemptions/exemption-schema.js +32 -0
  62. package/dist/exemptions/exemption-schema.js.map +1 -0
  63. package/dist/exemptions/exemption-store.d.ts +22 -0
  64. package/dist/exemptions/exemption-store.d.ts.map +1 -0
  65. package/dist/exemptions/exemption-store.js +80 -0
  66. package/dist/exemptions/exemption-store.js.map +1 -0
  67. package/dist/git.d.ts +25 -0
  68. package/dist/git.d.ts.map +1 -1
  69. package/dist/git.js +60 -0
  70. package/dist/git.js.map +1 -1
  71. package/dist/git.test.js +98 -2
  72. package/dist/git.test.js.map +1 -1
  73. package/dist/index.js +37 -4
  74. package/dist/index.js.map +1 -1
  75. package/dist/parsers/bot-review-parser.d.ts +8 -0
  76. package/dist/parsers/bot-review-parser.d.ts.map +1 -1
  77. package/dist/parsers/bot-review-parser.js +48 -11
  78. package/dist/parsers/bot-review-parser.js.map +1 -1
  79. package/dist/parsers/bot-review-parser.test.js +108 -1
  80. package/dist/parsers/bot-review-parser.test.js.map +1 -1
  81. package/dist/services/__tests__/deferred-issuer.test.d.ts +2 -0
  82. package/dist/services/__tests__/deferred-issuer.test.d.ts.map +1 -0
  83. package/dist/services/__tests__/deferred-issuer.test.js +114 -0
  84. package/dist/services/__tests__/deferred-issuer.test.js.map +1 -0
  85. package/dist/services/deferred-issuer.d.ts +17 -0
  86. package/dist/services/deferred-issuer.d.ts.map +1 -0
  87. package/dist/services/deferred-issuer.js +64 -0
  88. package/dist/services/deferred-issuer.js.map +1 -0
  89. package/dist/utils/__tests__/milestone-inference.test.d.ts +2 -0
  90. package/dist/utils/__tests__/milestone-inference.test.d.ts.map +1 -0
  91. package/dist/utils/__tests__/milestone-inference.test.js +35 -0
  92. package/dist/utils/__tests__/milestone-inference.test.js.map +1 -0
  93. package/dist/utils/milestone-inference.d.ts +6 -0
  94. package/dist/utils/milestone-inference.d.ts.map +1 -0
  95. package/dist/utils/milestone-inference.js +15 -0
  96. package/dist/utils/milestone-inference.js.map +1 -0
  97. package/package.json +2 -2
@@ -0,0 +1,193 @@
1
+ import * as crypto from 'node:crypto';
2
+ import { PROMOTION_THRESHOLD } from './exemption-schema.js';
3
+ // ─── Stopwords ──────────────────────────────────────────
4
+ const STOPWORDS = new Set([
5
+ 'a',
6
+ 'an',
7
+ 'the',
8
+ 'is',
9
+ 'are',
10
+ 'was',
11
+ 'were',
12
+ 'be',
13
+ 'been',
14
+ 'being',
15
+ 'have',
16
+ 'has',
17
+ 'had',
18
+ 'do',
19
+ 'does',
20
+ 'did',
21
+ 'will',
22
+ 'would',
23
+ 'shall',
24
+ 'should',
25
+ 'may',
26
+ 'might',
27
+ 'must',
28
+ 'can',
29
+ 'could',
30
+ 'to',
31
+ 'of',
32
+ 'in',
33
+ 'for',
34
+ 'on',
35
+ 'with',
36
+ 'at',
37
+ 'by',
38
+ 'from',
39
+ 'as',
40
+ 'or',
41
+ 'and',
42
+ 'but',
43
+ 'not',
44
+ 'this',
45
+ 'that',
46
+ 'it',
47
+ 'its',
48
+ 'no',
49
+ 'if',
50
+ 'so',
51
+ 'up',
52
+ 'out',
53
+ 'about',
54
+ ]);
55
+ function extractKeywords(message) {
56
+ return message
57
+ .toLowerCase()
58
+ .replace(/[^a-z0-9\s]/g, ' ')
59
+ .split(/\s+/)
60
+ .filter((w) => w.length >= 3 && !STOPWORDS.has(w))
61
+ .sort();
62
+ }
63
+ export function computePatternId(message) {
64
+ const keywords = extractKeywords(message);
65
+ const source = keywords.length > 0 ? keywords.join(':') : message.toLowerCase().trim();
66
+ const hash = crypto.createHash('sha256').update(source).digest('hex');
67
+ return `shield:${hash}`;
68
+ }
69
+ export function recordFalsePositive(local, patternId, source, message) {
70
+ const existing = local.patterns[patternId] ?? {
71
+ count: 0,
72
+ sources: [],
73
+ lastSeenAt: new Date().toISOString(),
74
+ sampleMessages: [],
75
+ };
76
+ const count = existing.count + 1;
77
+ const sources = existing.sources.includes(source)
78
+ ? existing.sources
79
+ : [...existing.sources, source];
80
+ const sampleMessages = existing.sampleMessages.length < 3
81
+ ? [...existing.sampleMessages, message]
82
+ : existing.sampleMessages;
83
+ const updated = {
84
+ count,
85
+ sources,
86
+ lastSeenAt: new Date().toISOString(),
87
+ sampleMessages,
88
+ };
89
+ const updatedLocal = {
90
+ patterns: { ...local.patterns, [patternId]: updated },
91
+ };
92
+ return { updatedLocal, promoted: count === PROMOTION_THRESHOLD };
93
+ }
94
+ export function promoteToShared(shared, patternId, localPattern) {
95
+ if (shared.exemptions.some((e) => e.patternId === patternId)) {
96
+ return shared;
97
+ }
98
+ const keywords = localPattern.sampleMessages[0]
99
+ ? extractKeywords(localPattern.sampleMessages[0]).slice(0, 5).join(' ')
100
+ : '';
101
+ const label = keywords || patternId;
102
+ const entry = {
103
+ patternId,
104
+ label,
105
+ reason: `Auto-promoted after ${localPattern.count} false positives`,
106
+ promotedAt: new Date().toISOString(),
107
+ promotedBy: 'auto',
108
+ sampleMessages: localPattern.sampleMessages,
109
+ };
110
+ return {
111
+ ...shared,
112
+ exemptions: [...shared.exemptions, entry],
113
+ };
114
+ }
115
+ function escapeRegExp(s) {
116
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
117
+ }
118
+ function buildManualLabelMatchers(shared) {
119
+ return shared.exemptions
120
+ .filter((e) => e.patternId.startsWith('manual:'))
121
+ .map((e) => new RegExp('\\b' + escapeRegExp(e.label.toLowerCase()) + '\\b', 'i'));
122
+ }
123
+ export function filterExemptedFindings(findings, shared) {
124
+ const autoExemptedIds = new Set(shared.exemptions.filter((e) => !e.patternId.startsWith('manual:')).map((e) => e.patternId));
125
+ const manualLabelPatterns = buildManualLabelMatchers(shared);
126
+ const filtered = [];
127
+ const exempted = [];
128
+ for (const finding of findings) {
129
+ const pid = computePatternId(finding.message);
130
+ const matchesAuto = autoExemptedIds.has(pid);
131
+ const matchesManual = manualLabelPatterns.some((re) => re.test(finding.message));
132
+ if (matchesAuto || matchesManual) {
133
+ exempted.push({ ...finding, severity: 'INFO' });
134
+ }
135
+ else {
136
+ filtered.push(finding);
137
+ }
138
+ }
139
+ return { filtered, exempted };
140
+ }
141
+ export function isExempted(patternId, exemptions) {
142
+ return exemptions.exemptions.some((e) => e.patternId === patternId);
143
+ }
144
+ export function addManualSuppression(shared, label, reason) {
145
+ const trimmed = label.trim();
146
+ if (!trimmed)
147
+ return shared;
148
+ const patternId = `manual:${trimmed}`;
149
+ if (shared.exemptions.some((e) => e.patternId === patternId)) {
150
+ return shared;
151
+ }
152
+ const entry = {
153
+ patternId,
154
+ label: trimmed,
155
+ reason,
156
+ promotedAt: new Date().toISOString(),
157
+ promotedBy: 'manual',
158
+ sampleMessages: [],
159
+ };
160
+ return {
161
+ ...shared,
162
+ exemptions: [...shared.exemptions, entry],
163
+ };
164
+ }
165
+ /**
166
+ * Track false positives for a batch of findings. Returns updated local/shared
167
+ * state and a list of promoted pattern messages (for logging).
168
+ */
169
+ export function trackFalsePositives(findings, source, local, shared) {
170
+ let currentLocal = local;
171
+ let currentShared = shared;
172
+ const promoted = [];
173
+ const seenPatternIds = new Set();
174
+ const manualPatterns = buildManualLabelMatchers(shared);
175
+ for (const finding of findings) {
176
+ const pid = computePatternId(finding.message);
177
+ if (seenPatternIds.has(pid))
178
+ continue;
179
+ seenPatternIds.add(pid);
180
+ if (isExempted(pid, currentShared))
181
+ continue;
182
+ if (manualPatterns.some((re) => re.test(finding.message)))
183
+ continue;
184
+ const { updatedLocal, promoted: didPromote } = recordFalsePositive(currentLocal, pid, source, finding.message);
185
+ currentLocal = updatedLocal;
186
+ if (didPromote) {
187
+ currentShared = promoteToShared(currentShared, pid, updatedLocal.patterns[pid]);
188
+ promoted.push(finding.message.slice(0, 80));
189
+ }
190
+ }
191
+ return { local: currentLocal, shared: currentShared, promoted };
192
+ }
193
+ //# sourceMappingURL=exemption-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exemption-engine.js","sourceRoot":"","sources":["../../src/exemptions/exemption-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import { z } from 'zod';
2
+ declare const ExemptionPatternSchema: z.ZodObject<{
3
+ count: z.ZodNumber;
4
+ sources: z.ZodArray<z.ZodEnum<["shield", "bot"]>, "many">;
5
+ lastSeenAt: z.ZodString;
6
+ sampleMessages: z.ZodArray<z.ZodString, "many">;
7
+ }, "strip", z.ZodTypeAny, {
8
+ count: number;
9
+ sources: ("shield" | "bot")[];
10
+ lastSeenAt: string;
11
+ sampleMessages: string[];
12
+ }, {
13
+ count: number;
14
+ sources: ("shield" | "bot")[];
15
+ lastSeenAt: string;
16
+ sampleMessages: string[];
17
+ }>;
18
+ export declare const ExemptionLocalSchema: z.ZodObject<{
19
+ patterns: z.ZodRecord<z.ZodString, z.ZodObject<{
20
+ count: z.ZodNumber;
21
+ sources: z.ZodArray<z.ZodEnum<["shield", "bot"]>, "many">;
22
+ lastSeenAt: z.ZodString;
23
+ sampleMessages: z.ZodArray<z.ZodString, "many">;
24
+ }, "strip", z.ZodTypeAny, {
25
+ count: number;
26
+ sources: ("shield" | "bot")[];
27
+ lastSeenAt: string;
28
+ sampleMessages: string[];
29
+ }, {
30
+ count: number;
31
+ sources: ("shield" | "bot")[];
32
+ lastSeenAt: string;
33
+ sampleMessages: string[];
34
+ }>>;
35
+ }, "strip", z.ZodTypeAny, {
36
+ patterns: Record<string, {
37
+ count: number;
38
+ sources: ("shield" | "bot")[];
39
+ lastSeenAt: string;
40
+ sampleMessages: string[];
41
+ }>;
42
+ }, {
43
+ patterns: Record<string, {
44
+ count: number;
45
+ sources: ("shield" | "bot")[];
46
+ lastSeenAt: string;
47
+ sampleMessages: string[];
48
+ }>;
49
+ }>;
50
+ export type ExemptionLocal = z.infer<typeof ExemptionLocalSchema>;
51
+ export type ExemptionPattern = z.infer<typeof ExemptionPatternSchema>;
52
+ declare const SharedExemptionEntrySchema: z.ZodObject<{
53
+ patternId: z.ZodString;
54
+ label: z.ZodString;
55
+ reason: z.ZodString;
56
+ promotedAt: z.ZodString;
57
+ promotedBy: z.ZodEnum<["auto", "manual"]>;
58
+ sampleMessages: z.ZodArray<z.ZodString, "many">;
59
+ }, "strip", z.ZodTypeAny, {
60
+ sampleMessages: string[];
61
+ patternId: string;
62
+ label: string;
63
+ reason: string;
64
+ promotedAt: string;
65
+ promotedBy: "auto" | "manual";
66
+ }, {
67
+ sampleMessages: string[];
68
+ patternId: string;
69
+ label: string;
70
+ reason: string;
71
+ promotedAt: string;
72
+ promotedBy: "auto" | "manual";
73
+ }>;
74
+ export declare const ExemptionSharedSchema: z.ZodObject<{
75
+ version: z.ZodLiteral<1>;
76
+ exemptions: z.ZodArray<z.ZodObject<{
77
+ patternId: z.ZodString;
78
+ label: z.ZodString;
79
+ reason: z.ZodString;
80
+ promotedAt: z.ZodString;
81
+ promotedBy: z.ZodEnum<["auto", "manual"]>;
82
+ sampleMessages: z.ZodArray<z.ZodString, "many">;
83
+ }, "strip", z.ZodTypeAny, {
84
+ sampleMessages: string[];
85
+ patternId: string;
86
+ label: string;
87
+ reason: string;
88
+ promotedAt: string;
89
+ promotedBy: "auto" | "manual";
90
+ }, {
91
+ sampleMessages: string[];
92
+ patternId: string;
93
+ label: string;
94
+ reason: string;
95
+ promotedAt: string;
96
+ promotedBy: "auto" | "manual";
97
+ }>, "many">;
98
+ }, "strip", z.ZodTypeAny, {
99
+ version: 1;
100
+ exemptions: {
101
+ sampleMessages: string[];
102
+ patternId: string;
103
+ label: string;
104
+ reason: string;
105
+ promotedAt: string;
106
+ promotedBy: "auto" | "manual";
107
+ }[];
108
+ }, {
109
+ version: 1;
110
+ exemptions: {
111
+ sampleMessages: string[];
112
+ patternId: string;
113
+ label: string;
114
+ reason: string;
115
+ promotedAt: string;
116
+ promotedBy: "auto" | "manual";
117
+ }[];
118
+ }>;
119
+ export type ExemptionShared = z.infer<typeof ExemptionSharedSchema>;
120
+ export type SharedExemptionEntry = z.infer<typeof SharedExemptionEntrySchema>;
121
+ export declare const EMPTY_LOCAL: ExemptionLocal;
122
+ export declare const EMPTY_SHARED: ExemptionShared;
123
+ export declare const PROMOTION_THRESHOLD = 3;
124
+ export declare const LOCAL_FILE = "exemption-local.json";
125
+ export declare const SHARED_FILE = "exemptions.json";
126
+ export {};
127
+ //# sourceMappingURL=exemption-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exemption-schema.d.ts","sourceRoot":"","sources":["../../src/exemptions/exemption-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;EAK1B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,QAAA,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;EAO9B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,WAAW,EAAE,cAAiC,CAAC;AAC5D,eAAO,MAAM,YAAY,EAAE,eAAgD,CAAC;AAI5E,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,UAAU,yBAAyB,CAAC;AACjD,eAAO,MAAM,WAAW,oBAAoB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ // ─── Local: per-developer FP tracking (gitignored) ─────
3
+ const ExemptionPatternSchema = z.object({
4
+ count: z.number().int().nonnegative(),
5
+ sources: z.array(z.enum(['shield', 'bot'])),
6
+ lastSeenAt: z.string().datetime(),
7
+ sampleMessages: z.array(z.string()).max(3),
8
+ });
9
+ export const ExemptionLocalSchema = z.object({
10
+ patterns: z.record(z.string(), ExemptionPatternSchema),
11
+ });
12
+ // ─── Shared: committed team-wide exemptions ─────────────
13
+ const SharedExemptionEntrySchema = z.object({
14
+ patternId: z.string().min(1),
15
+ label: z.string().min(1),
16
+ reason: z.string(),
17
+ promotedAt: z.string().datetime(),
18
+ promotedBy: z.enum(['auto', 'manual']),
19
+ sampleMessages: z.array(z.string()).max(3),
20
+ });
21
+ export const ExemptionSharedSchema = z.object({
22
+ version: z.literal(1),
23
+ exemptions: z.array(SharedExemptionEntrySchema),
24
+ });
25
+ // ─── Defaults ───────────────────────────────────────────
26
+ export const EMPTY_LOCAL = { patterns: {} };
27
+ export const EMPTY_SHARED = { version: 1, exemptions: [] };
28
+ // ─── Constants ──────────────────────────────────────────
29
+ export const PROMOTION_THRESHOLD = 3;
30
+ export const LOCAL_FILE = 'exemption-local.json';
31
+ export const SHARED_FILE = 'exemptions.json';
32
+ //# sourceMappingURL=exemption-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exemption-schema.js","sourceRoot":"","sources":["../../src/exemptions/exemption-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,0DAA0D;AAE1D,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACrC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC;CACvD,CAAC,CAAC;AAKH,2DAA2D;AAE3D,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC;CAChD,CAAC,CAAC;AAKH,2DAA2D;AAE3D,MAAM,CAAC,MAAM,WAAW,GAAmB,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAoB,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AAE5E,2DAA2D;AAE3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ExemptionLocal, ExemptionShared } from './exemption-schema.js';
2
+ /**
3
+ * Read local exemption tracking state from .totem/cache/exemption-local.json.
4
+ * Returns EMPTY_LOCAL if missing, corrupt, or unreadable.
5
+ */
6
+ export declare function readLocalExemptions(cacheDir: string, onWarn?: (msg: string) => void): ExemptionLocal;
7
+ /**
8
+ * Write local exemption tracking state.
9
+ * Creates cache directory if needed. Fire-and-forget on failure.
10
+ */
11
+ export declare function writeLocalExemptions(cacheDir: string, data: ExemptionLocal, onWarn?: (msg: string) => void): void;
12
+ /**
13
+ * Read shared exemptions from .totem/exemptions.json (committed, team-wide).
14
+ * Returns EMPTY_SHARED if missing or invalid.
15
+ */
16
+ export declare function readSharedExemptions(totemDir: string, onWarn?: (msg: string) => void): ExemptionShared;
17
+ /**
18
+ * Write shared exemptions file.
19
+ * Creates directory if needed. Fire-and-forget on failure.
20
+ */
21
+ export declare function writeSharedExemptions(totemDir: string, data: ExemptionShared, onWarn?: (msg: string) => void): void;
22
+ //# sourceMappingURL=exemption-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exemption-store.d.ts","sourceRoot":"","sources":["../../src/exemptions/exemption-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAU7E;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC7B,cAAc,CAgBhB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC7B,IAAI,CASN;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC7B,eAAe,CAgBjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,eAAe,EACrB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC7B,IAAI,CASN"}
@@ -0,0 +1,80 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { EMPTY_LOCAL, EMPTY_SHARED, ExemptionLocalSchema, ExemptionSharedSchema, LOCAL_FILE, SHARED_FILE, } from './exemption-schema.js';
4
+ /**
5
+ * Read local exemption tracking state from .totem/cache/exemption-local.json.
6
+ * Returns EMPTY_LOCAL if missing, corrupt, or unreadable.
7
+ */
8
+ export function readLocalExemptions(cacheDir, onWarn) {
9
+ const filePath = path.join(cacheDir, LOCAL_FILE);
10
+ try {
11
+ const raw = fs.readFileSync(filePath, 'utf-8');
12
+ const parsed = JSON.parse(raw);
13
+ const result = ExemptionLocalSchema.safeParse(parsed);
14
+ if (result.success)
15
+ return result.data;
16
+ onWarn?.(`Corrupt exemption-local.json — resetting to empty state`);
17
+ return { ...EMPTY_LOCAL };
18
+ }
19
+ catch (err) {
20
+ if (err.code !== 'ENOENT') {
21
+ const msg = err instanceof Error ? err.message : String(err);
22
+ onWarn?.(`Failed to read exemption-local.json: ${msg}`);
23
+ }
24
+ return { ...EMPTY_LOCAL };
25
+ }
26
+ }
27
+ /**
28
+ * Write local exemption tracking state.
29
+ * Creates cache directory if needed. Fire-and-forget on failure.
30
+ */
31
+ export function writeLocalExemptions(cacheDir, data, onWarn) {
32
+ try {
33
+ fs.mkdirSync(cacheDir, { recursive: true });
34
+ const filePath = path.join(cacheDir, LOCAL_FILE);
35
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
36
+ }
37
+ catch (err) {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ onWarn?.(`Failed to write exemption-local.json: ${msg}`);
40
+ }
41
+ }
42
+ /**
43
+ * Read shared exemptions from .totem/exemptions.json (committed, team-wide).
44
+ * Returns EMPTY_SHARED if missing or invalid.
45
+ */
46
+ export function readSharedExemptions(totemDir, onWarn) {
47
+ const filePath = path.join(totemDir, SHARED_FILE);
48
+ try {
49
+ const raw = fs.readFileSync(filePath, 'utf-8');
50
+ const parsed = JSON.parse(raw);
51
+ const result = ExemptionSharedSchema.safeParse(parsed);
52
+ if (result.success)
53
+ return result.data;
54
+ onWarn?.(`Corrupt exemptions.json — treating as empty`);
55
+ return { ...EMPTY_SHARED };
56
+ }
57
+ catch (err) {
58
+ if (err.code !== 'ENOENT') {
59
+ const msg = err instanceof Error ? err.message : String(err);
60
+ onWarn?.(`Failed to read exemptions.json: ${msg}`);
61
+ }
62
+ return { ...EMPTY_SHARED };
63
+ }
64
+ }
65
+ /**
66
+ * Write shared exemptions file.
67
+ * Creates directory if needed. Fire-and-forget on failure.
68
+ */
69
+ export function writeSharedExemptions(totemDir, data, onWarn) {
70
+ try {
71
+ fs.mkdirSync(totemDir, { recursive: true });
72
+ const filePath = path.join(totemDir, SHARED_FILE);
73
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
74
+ }
75
+ catch (err) {
76
+ const msg = err instanceof Error ? err.message : String(err);
77
+ onWarn?.(`Failed to write exemptions.json: ${msg}`);
78
+ }
79
+ }
80
+ //# sourceMappingURL=exemption-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exemption-store.js","sourceRoot":"","sources":["../../src/exemptions/exemption-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EACL,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,MAA8B;IAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QACvC,MAAM,EAAE,CAAC,yDAAyD,CAAC,CAAC;QACpE,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,EAAE,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,IAAoB,EACpB,MAA8B;IAE9B,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACjD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,MAA8B;IAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QACvC,MAAM,EAAE,CAAC,6CAA6C,CAAC,CAAC;QACxD,OAAO,EAAE,GAAG,YAAY,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,EAAE,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,EAAE,GAAG,YAAY,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,IAAqB,EACrB,MAA8B;IAE9B,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAClD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
package/dist/git.d.ts CHANGED
@@ -1,4 +1,29 @@
1
1
  export { extractChangedFiles, filterDiffByPatterns, getDefaultBranch, getGitBranch, getGitBranchDiff, getGitDiff, getGitDiffStat, getGitLogSince, getGitStatus, getLatestTag, getTagDate, isFileDirty, resolveGitRoot, } from '@mmnto/totem';
2
+ /**
3
+ * Check if `base` is an ancestor of `head` (or HEAD if omitted).
4
+ * Returns true if `git merge-base --is-ancestor` exits 0.
5
+ */
6
+ export declare function isAncestor(cwd: string, base: string, head?: string): boolean;
7
+ /**
8
+ * Get shortstat between two refs. Returns parsed line counts.
9
+ */
10
+ export declare function getShortstat(cwd: string, base: string, head?: string): {
11
+ files: number;
12
+ insertions: number;
13
+ deletions: number;
14
+ };
15
+ /**
16
+ * Get file statuses between two refs. Returns array of { status, file }.
17
+ * Status is 'A' (added), 'M' (modified), 'D' (deleted), etc.
18
+ */
19
+ export declare function getNameStatus(cwd: string, base: string, head?: string): Array<{
20
+ status: string;
21
+ file: string;
22
+ }>;
23
+ /**
24
+ * Get the diff between two refs.
25
+ */
26
+ export declare function getDiffBetween(cwd: string, base: string, head?: string): string;
2
27
  export interface DiffForReviewOptions {
3
28
  staged?: boolean;
4
29
  }
package/dist/git.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA8BrC"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,cAAc,CAAC;AAMtB;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAO5E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAU1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAazC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/E;AAID,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA8BrC"}
package/dist/git.js CHANGED
@@ -1,5 +1,65 @@
1
1
  // Pure git utilities — delegated to core, re-exported for backward compatibility
2
2
  export { extractChangedFiles, filterDiffByPatterns, getDefaultBranch, getGitBranch, getGitBranchDiff, getGitDiff, getGitDiffStat, getGitLogSince, getGitStatus, getLatestTag, getTagDate, isFileDirty, resolveGitRoot, } from '@mmnto/totem';
3
+ import { safeExec } from '@mmnto/totem';
4
+ // ─── Incremental shield helpers (#1010) ─────────────────
5
+ /**
6
+ * Check if `base` is an ancestor of `head` (or HEAD if omitted).
7
+ * Returns true if `git merge-base --is-ancestor` exits 0.
8
+ */
9
+ export function isAncestor(cwd, base, head) {
10
+ try {
11
+ safeExec('git', ['merge-base', '--is-ancestor', base, head ?? 'HEAD'], { cwd });
12
+ return true;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ /**
19
+ * Get shortstat between two refs. Returns parsed line counts.
20
+ */
21
+ export function getShortstat(cwd, base, head) {
22
+ try {
23
+ const output = safeExec('git', ['diff', '--shortstat', base, head ?? 'HEAD'], { cwd });
24
+ const files = parseInt(output.match(/(\d+) file/)?.[1] ?? '0', 10);
25
+ const insertions = parseInt(output.match(/(\d+) insertion/)?.[1] ?? '0', 10);
26
+ const deletions = parseInt(output.match(/(\d+) deletion/)?.[1] ?? '0', 10);
27
+ return { files, insertions, deletions };
28
+ }
29
+ catch {
30
+ return { files: 0, insertions: 0, deletions: 0 };
31
+ }
32
+ }
33
+ /**
34
+ * Get file statuses between two refs. Returns array of { status, file }.
35
+ * Status is 'A' (added), 'M' (modified), 'D' (deleted), etc.
36
+ */
37
+ export function getNameStatus(cwd, base, head) {
38
+ try {
39
+ const output = safeExec('git', ['diff', '--name-status', base, head ?? 'HEAD'], { cwd });
40
+ return output
41
+ .split('\n')
42
+ .filter(Boolean)
43
+ .map((line) => {
44
+ const [status, ...rest] = line.split('\t');
45
+ return { status: status ?? '', file: rest.join('\t') };
46
+ });
47
+ }
48
+ catch {
49
+ return [];
50
+ }
51
+ }
52
+ /**
53
+ * Get the diff between two refs.
54
+ */
55
+ export function getDiffBetween(cwd, base, head) {
56
+ try {
57
+ return safeExec('git', ['diff', base, head ?? 'HEAD'], { cwd, maxBuffer: 10 * 1024 * 1024 });
58
+ }
59
+ catch {
60
+ return '';
61
+ }
62
+ }
3
63
  /**
4
64
  * Shared diff-fetching logic used by both `shield` and `lint` commands.
5
65
  *
package/dist/git.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,cAAc,CAAC;AAkBtB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA6B,EAC7B,MAA2B,EAC3B,GAAW,EACX,GAAW;IAEX,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,EACJ,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,GACX,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAEjC,MAAM,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/C,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,UAAU,CAAC,CAAC;IACjF,IAAI,IAAI,GAAG,oBAAoB,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;IAElE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,qDAAqD,IAAI,aAAa,CAAC,CAAC;QACrF,IAAI,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC/C,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,YAAY,CAAC,MAAM,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEpF,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}