@massu/core 0.6.2 → 0.7.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.
@@ -0,0 +1,426 @@
1
+ #!/usr/bin/env node
2
+ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
3
+
4
+ // src/hooks/incident-pipeline.ts
5
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync } from "fs";
6
+ import { basename, resolve as resolve2 } from "path";
7
+
8
+ // src/config.ts
9
+ import { resolve, dirname } from "path";
10
+ import { existsSync, readFileSync } from "fs";
11
+ import { parse as parseYaml } from "yaml";
12
+ import { z } from "zod";
13
+ var DomainConfigSchema = z.object({
14
+ name: z.string().default("Unknown"),
15
+ routers: z.array(z.string()).default([]),
16
+ pages: z.array(z.string()).default([]),
17
+ tables: z.array(z.string()).default([]),
18
+ allowedImportsFrom: z.array(z.string()).default([])
19
+ });
20
+ var PatternRuleConfigSchema = z.object({
21
+ pattern: z.string().default("**"),
22
+ rules: z.array(z.string()).default([])
23
+ });
24
+ var CostModelSchema = z.object({
25
+ input_per_million: z.number(),
26
+ output_per_million: z.number(),
27
+ cache_read_per_million: z.number().optional(),
28
+ cache_write_per_million: z.number().optional()
29
+ });
30
+ var AnalyticsConfigSchema = z.object({
31
+ quality: z.object({
32
+ weights: z.record(z.string(), z.number()).default({
33
+ bug_found: -5,
34
+ vr_failure: -10,
35
+ incident: -20,
36
+ cr_violation: -3,
37
+ vr_pass: 2,
38
+ clean_commit: 5,
39
+ successful_verification: 3
40
+ }),
41
+ categories: z.array(z.string()).default(["security", "architecture", "coupling", "tests", "rule_compliance"])
42
+ }).optional(),
43
+ cost: z.object({
44
+ models: z.record(z.string(), CostModelSchema).default({}),
45
+ currency: z.string().default("USD")
46
+ }).optional(),
47
+ prompts: z.object({
48
+ success_indicators: z.array(z.string()).default(["committed", "approved", "looks good", "perfect", "great", "thanks"]),
49
+ failure_indicators: z.array(z.string()).default(["revert", "wrong", "that's not", "undo", "incorrect"]),
50
+ max_turns_for_success: z.number().default(2)
51
+ }).optional()
52
+ }).optional();
53
+ var CustomPatternSchema = z.object({
54
+ pattern: z.string(),
55
+ severity: z.string(),
56
+ message: z.string()
57
+ });
58
+ var GovernanceConfigSchema = z.object({
59
+ audit: z.object({
60
+ formats: z.array(z.string()).default(["summary", "detailed", "soc2"]),
61
+ retention_days: z.number().default(365),
62
+ auto_log: z.record(z.string(), z.boolean()).default({
63
+ code_changes: true,
64
+ rule_enforcement: true,
65
+ approvals: true,
66
+ commits: true
67
+ })
68
+ }).optional(),
69
+ validation: z.object({
70
+ realtime: z.boolean().default(true),
71
+ checks: z.record(z.string(), z.boolean()).default({
72
+ rule_compliance: true,
73
+ import_existence: true,
74
+ naming_conventions: true
75
+ }),
76
+ custom_patterns: z.array(CustomPatternSchema).default([])
77
+ }).optional(),
78
+ adr: z.object({
79
+ detection_phrases: z.array(z.string()).default(["chose", "decided", "switching to", "moving from", "going with"]),
80
+ template: z.string().default("default"),
81
+ storage: z.string().default("database"),
82
+ output_dir: z.string().default("docs/adr")
83
+ }).optional()
84
+ }).optional();
85
+ var SecurityPatternSchema = z.object({
86
+ pattern: z.string(),
87
+ severity: z.string(),
88
+ category: z.string(),
89
+ description: z.string()
90
+ });
91
+ var SecurityConfigSchema = z.object({
92
+ patterns: z.array(SecurityPatternSchema).default([]),
93
+ auto_score_on_edit: z.boolean().default(true),
94
+ score_threshold_alert: z.number().default(50),
95
+ severity_weights: z.record(z.string(), z.number()).optional(),
96
+ restrictive_licenses: z.array(z.string()).optional(),
97
+ dep_alternatives: z.record(z.string(), z.array(z.string())).optional(),
98
+ dependencies: z.object({
99
+ package_manager: z.string().default("npm"),
100
+ blocked_packages: z.array(z.string()).default([]),
101
+ preferred_packages: z.record(z.string(), z.string()).default({}),
102
+ max_bundle_size_kb: z.number().default(500)
103
+ }).optional()
104
+ }).optional();
105
+ var TeamConfigSchema = z.object({
106
+ enabled: z.boolean().default(false),
107
+ sync_backend: z.string().default("local"),
108
+ developer_id: z.string().default("auto"),
109
+ share_by_default: z.boolean().default(false),
110
+ expertise_weights: z.object({
111
+ session: z.number().default(20),
112
+ observation: z.number().default(10)
113
+ }).optional(),
114
+ privacy: z.object({
115
+ share_file_paths: z.boolean().default(true),
116
+ share_code_snippets: z.boolean().default(false),
117
+ share_observations: z.boolean().default(true)
118
+ }).optional()
119
+ }).optional();
120
+ var RegressionConfigSchema = z.object({
121
+ test_patterns: z.array(z.string()).default([
122
+ "{dir}/__tests__/{name}.test.{ext}",
123
+ "{dir}/{name}.spec.{ext}",
124
+ "tests/{path}.test.{ext}"
125
+ ]),
126
+ test_runner: z.string().default("npm test"),
127
+ health_thresholds: z.object({
128
+ healthy: z.number().default(80),
129
+ warning: z.number().default(50)
130
+ }).optional()
131
+ }).optional();
132
+ var AutoLearningConfigSchema = z.object({
133
+ enabled: z.boolean().default(true),
134
+ incidentDir: z.string().default("docs/incidents"),
135
+ memoryDir: z.string().default("memory"),
136
+ memoryIndexFile: z.string().default("MEMORY.md"),
137
+ enforcementHooksDir: z.string().default("scripts/hooks"),
138
+ fixDetection: z.object({
139
+ enabled: z.boolean().default(true),
140
+ lookbackDays: z.number().default(7),
141
+ signals: z.array(z.string()).default([
142
+ "removed_broken_code",
143
+ "added_error_handling",
144
+ "method_name_correction",
145
+ "auth_fix",
146
+ "nil_handling_fix",
147
+ "concurrency_fix",
148
+ "async_pattern_fix",
149
+ "added_missing_import"
150
+ ])
151
+ }).default({}),
152
+ pipeline: z.object({
153
+ requireIncidentReport: z.boolean().default(true),
154
+ requirePreventionRule: z.boolean().default(true),
155
+ requireEnforcement: z.boolean().default(true)
156
+ }).default({})
157
+ }).optional();
158
+ var CloudConfigSchema = z.object({
159
+ enabled: z.boolean().default(false),
160
+ apiKey: z.string().optional(),
161
+ endpoint: z.string().optional(),
162
+ sync: z.object({
163
+ memory: z.boolean().default(true),
164
+ analytics: z.boolean().default(true),
165
+ audit: z.boolean().default(true)
166
+ }).default({ memory: true, analytics: true, audit: true })
167
+ }).optional();
168
+ var ConventionsConfigSchema = z.object({
169
+ claudeDirName: z.string().default(".claude").refine(
170
+ (s) => !s.includes("..") && !s.startsWith("/"),
171
+ { message: 'claudeDirName must not contain ".." or start with "/"' }
172
+ ),
173
+ sessionStatePath: z.string().default(".claude/session-state/CURRENT.md").refine(
174
+ (s) => !s.includes("..") && !s.startsWith("/"),
175
+ { message: 'sessionStatePath must not contain ".." or start with "/"' }
176
+ ),
177
+ sessionArchivePath: z.string().default(".claude/session-state/archive").refine(
178
+ (s) => !s.includes("..") && !s.startsWith("/"),
179
+ { message: 'sessionArchivePath must not contain ".." or start with "/"' }
180
+ ),
181
+ knowledgeCategories: z.array(z.string()).default([
182
+ "patterns",
183
+ "commands",
184
+ "incidents",
185
+ "reference",
186
+ "protocols",
187
+ "checklists",
188
+ "playbooks",
189
+ "critical",
190
+ "scripts",
191
+ "status",
192
+ "templates",
193
+ "loop-state",
194
+ "session-state",
195
+ "agents"
196
+ ]),
197
+ knowledgeSourceFiles: z.array(z.string()).default(["CLAUDE.md", "MEMORY.md", "corrections.md"]),
198
+ excludePatterns: z.array(z.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
199
+ }).optional();
200
+ var PythonDomainConfigSchema = z.object({
201
+ name: z.string(),
202
+ packages: z.array(z.string()),
203
+ allowed_imports_from: z.array(z.string()).default([])
204
+ });
205
+ var PythonConfigSchema = z.object({
206
+ root: z.string(),
207
+ alembic_dir: z.string().optional(),
208
+ domains: z.array(PythonDomainConfigSchema).default([]),
209
+ exclude_dirs: z.array(z.string()).default(["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"])
210
+ }).optional();
211
+ var PathsConfigSchema = z.object({
212
+ source: z.string().default("src"),
213
+ aliases: z.record(z.string(), z.string()).default({ "@": "src" }),
214
+ routers: z.string().optional(),
215
+ routerRoot: z.string().optional(),
216
+ pages: z.string().optional(),
217
+ middleware: z.string().optional(),
218
+ schema: z.string().optional(),
219
+ components: z.string().optional(),
220
+ hooks: z.string().optional()
221
+ });
222
+ var RawConfigSchema = z.object({
223
+ project: z.object({
224
+ name: z.string().default("my-project"),
225
+ root: z.string().default("auto")
226
+ }).default({ name: "my-project", root: "auto" }),
227
+ framework: z.object({
228
+ type: z.string().default("typescript"),
229
+ router: z.string().default("none"),
230
+ orm: z.string().default("none"),
231
+ ui: z.string().default("none")
232
+ }).default({ type: "typescript", router: "none", orm: "none", ui: "none" }),
233
+ paths: PathsConfigSchema.default({ source: "src", aliases: { "@": "src" } }),
234
+ toolPrefix: z.string().default("massu"),
235
+ dbAccessPattern: z.string().optional(),
236
+ knownMismatches: z.record(z.string(), z.record(z.string(), z.string())).optional(),
237
+ accessScopes: z.array(z.string()).optional(),
238
+ domains: z.array(DomainConfigSchema).default([]),
239
+ rules: z.array(PatternRuleConfigSchema).default([]),
240
+ analytics: AnalyticsConfigSchema,
241
+ governance: GovernanceConfigSchema,
242
+ security: SecurityConfigSchema,
243
+ team: TeamConfigSchema,
244
+ regression: RegressionConfigSchema,
245
+ cloud: CloudConfigSchema,
246
+ conventions: ConventionsConfigSchema,
247
+ python: PythonConfigSchema,
248
+ autoLearning: AutoLearningConfigSchema
249
+ }).passthrough();
250
+ var _config = null;
251
+ var _projectRoot = null;
252
+ function findProjectRoot() {
253
+ const cwd = process.cwd();
254
+ let dir = cwd;
255
+ while (true) {
256
+ if (existsSync(resolve(dir, "massu.config.yaml"))) {
257
+ return dir;
258
+ }
259
+ const parent = dirname(dir);
260
+ if (parent === dir) break;
261
+ dir = parent;
262
+ }
263
+ dir = cwd;
264
+ while (true) {
265
+ if (existsSync(resolve(dir, "package.json"))) {
266
+ return dir;
267
+ }
268
+ if (existsSync(resolve(dir, ".git"))) {
269
+ return dir;
270
+ }
271
+ const parent = dirname(dir);
272
+ if (parent === dir) break;
273
+ dir = parent;
274
+ }
275
+ return cwd;
276
+ }
277
+ function getProjectRoot() {
278
+ if (!_projectRoot) {
279
+ _projectRoot = findProjectRoot();
280
+ }
281
+ return _projectRoot;
282
+ }
283
+ function getConfig() {
284
+ if (_config) return _config;
285
+ const root = getProjectRoot();
286
+ const configPath = resolve(root, "massu.config.yaml");
287
+ let rawYaml = {};
288
+ if (existsSync(configPath)) {
289
+ const content = readFileSync(configPath, "utf-8");
290
+ rawYaml = parseYaml(content) ?? {};
291
+ }
292
+ const parsed = RawConfigSchema.parse(rawYaml);
293
+ const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve(root, parsed.project.root);
294
+ _config = {
295
+ project: {
296
+ name: parsed.project.name,
297
+ root: projectRoot
298
+ },
299
+ framework: parsed.framework,
300
+ paths: parsed.paths,
301
+ toolPrefix: parsed.toolPrefix,
302
+ dbAccessPattern: parsed.dbAccessPattern,
303
+ knownMismatches: parsed.knownMismatches,
304
+ accessScopes: parsed.accessScopes,
305
+ domains: parsed.domains,
306
+ rules: parsed.rules,
307
+ analytics: parsed.analytics,
308
+ governance: parsed.governance,
309
+ security: parsed.security,
310
+ team: parsed.team,
311
+ regression: parsed.regression,
312
+ cloud: parsed.cloud,
313
+ conventions: parsed.conventions,
314
+ python: parsed.python
315
+ };
316
+ if (!_config.cloud?.apiKey && process.env.MASSU_API_KEY) {
317
+ _config.cloud = {
318
+ enabled: true,
319
+ sync: { memory: true, analytics: true, audit: true },
320
+ ..._config.cloud,
321
+ apiKey: process.env.MASSU_API_KEY
322
+ };
323
+ }
324
+ return _config;
325
+ }
326
+
327
+ // src/hooks/incident-pipeline.ts
328
+ async function main() {
329
+ try {
330
+ const input = await readStdin();
331
+ const hookInput = JSON.parse(input);
332
+ const filePath = hookInput.tool_input?.file_path;
333
+ if (!filePath) {
334
+ process.exit(0);
335
+ return;
336
+ }
337
+ const config = getConfig();
338
+ if (config.autoLearning?.enabled === false) {
339
+ process.exit(0);
340
+ return;
341
+ }
342
+ const root = getProjectRoot();
343
+ const incidentDir = config.autoLearning?.incidentDir ?? "docs/incidents";
344
+ const memoryDir = config.autoLearning?.memoryDir ?? "memory";
345
+ const relPath = filePath.startsWith(root + "/") ? filePath.slice(root.length + 1) : filePath;
346
+ if (!relPath.startsWith(incidentDir) || !relPath.endsWith(".md")) {
347
+ process.exit(0);
348
+ return;
349
+ }
350
+ if (!existsSync2(filePath)) {
351
+ process.exit(0);
352
+ return;
353
+ }
354
+ const content = readFileSync2(filePath, "utf-8");
355
+ const titleMatch = content.match(/^#\s+(.+)/m);
356
+ const title = titleMatch?.[1] ?? basename(filePath, ".md");
357
+ const slug = basename(filePath, ".md").replace(/^\d{4}-\d{2}-\d{2}-?/, "").toLowerCase();
358
+ const memoryDirAbs = resolve2(root, memoryDir);
359
+ let hasExistingRule = false;
360
+ if (existsSync2(memoryDirAbs)) {
361
+ const ruleFiles = readdirSync(memoryDirAbs).filter((f) => f.startsWith("feedback_"));
362
+ for (const ruleFile of ruleFiles) {
363
+ if (ruleFile.toLowerCase().includes(slug.slice(0, 20))) {
364
+ hasExistingRule = true;
365
+ break;
366
+ }
367
+ }
368
+ }
369
+ if (hasExistingRule) {
370
+ process.exit(0);
371
+ return;
372
+ }
373
+ const hasPrevention = /## Prevention Rules|## Prevention|## Rules/i.test(content);
374
+ if (config.autoLearning?.pipeline?.requirePreventionRule === false) {
375
+ process.exit(0);
376
+ return;
377
+ }
378
+ const lines = [];
379
+ lines.push("");
380
+ lines.push("============================================================================");
381
+ lines.push(" AUTO-LEARNING: Incident Report Created \u2014 Rule Derivation Required");
382
+ lines.push("============================================================================");
383
+ lines.push("");
384
+ lines.push(` Incident: ${title}`);
385
+ lines.push(` File: ${filePath}`);
386
+ lines.push("");
387
+ if (!hasPrevention) {
388
+ lines.push(' No "## Prevention Rules" section found in the incident report.');
389
+ lines.push(" Add one first, then proceed with rule derivation.");
390
+ lines.push("");
391
+ }
392
+ lines.push(" DERIVE A PREVENTION RULE:");
393
+ lines.push(` a) Read the incident root cause and prevention rules`);
394
+ lines.push(` b) Create: ${memoryDir}/feedback_<rule_name>.md`);
395
+ lines.push(" Template:");
396
+ lines.push(" ---");
397
+ lines.push(" name: <Rule Name>");
398
+ lines.push(" description: <one-line description>");
399
+ lines.push(" type: feedback");
400
+ lines.push(" ---");
401
+ lines.push(" <Rule statement>");
402
+ lines.push(" **Why:** <Root cause from incident>");
403
+ lines.push(" **How to apply:** <Concrete steps>");
404
+ lines.push("");
405
+ lines.push(` c) Add one-line entry to ${config.autoLearning?.memoryIndexFile ?? "MEMORY.md"}`);
406
+ lines.push("");
407
+ lines.push(" This step is MANDATORY per the auto-learning pipeline.");
408
+ lines.push("============================================================================");
409
+ lines.push("");
410
+ console.log(lines.join("\n"));
411
+ } catch {
412
+ }
413
+ process.exit(0);
414
+ }
415
+ function readStdin() {
416
+ return new Promise((resolve3) => {
417
+ let data = "";
418
+ process.stdin.setEncoding("utf-8");
419
+ process.stdin.on("data", (chunk) => {
420
+ data += chunk;
421
+ });
422
+ process.stdin.on("end", () => resolve3(data));
423
+ setTimeout(() => resolve3(data), 3e3);
424
+ });
425
+ }
426
+ main();
@@ -129,6 +129,32 @@ var RegressionConfigSchema = z.object({
129
129
  warning: z.number().default(50)
130
130
  }).optional()
131
131
  }).optional();
132
+ var AutoLearningConfigSchema = z.object({
133
+ enabled: z.boolean().default(true),
134
+ incidentDir: z.string().default("docs/incidents"),
135
+ memoryDir: z.string().default("memory"),
136
+ memoryIndexFile: z.string().default("MEMORY.md"),
137
+ enforcementHooksDir: z.string().default("scripts/hooks"),
138
+ fixDetection: z.object({
139
+ enabled: z.boolean().default(true),
140
+ lookbackDays: z.number().default(7),
141
+ signals: z.array(z.string()).default([
142
+ "removed_broken_code",
143
+ "added_error_handling",
144
+ "method_name_correction",
145
+ "auth_fix",
146
+ "nil_handling_fix",
147
+ "concurrency_fix",
148
+ "async_pattern_fix",
149
+ "added_missing_import"
150
+ ])
151
+ }).default({}),
152
+ pipeline: z.object({
153
+ requireIncidentReport: z.boolean().default(true),
154
+ requirePreventionRule: z.boolean().default(true),
155
+ requireEnforcement: z.boolean().default(true)
156
+ }).default({})
157
+ }).optional();
132
158
  var CloudConfigSchema = z.object({
133
159
  enabled: z.boolean().default(false),
134
160
  apiKey: z.string().optional(),
@@ -218,7 +244,8 @@ var RawConfigSchema = z.object({
218
244
  regression: RegressionConfigSchema,
219
245
  cloud: CloudConfigSchema,
220
246
  conventions: ConventionsConfigSchema,
221
- python: PythonConfigSchema
247
+ python: PythonConfigSchema,
248
+ autoLearning: AutoLearningConfigSchema
222
249
  }).passthrough();
223
250
  var _config = null;
224
251
  var _projectRoot = null;
@@ -131,6 +131,32 @@ var RegressionConfigSchema = z.object({
131
131
  warning: z.number().default(50)
132
132
  }).optional()
133
133
  }).optional();
134
+ var AutoLearningConfigSchema = z.object({
135
+ enabled: z.boolean().default(true),
136
+ incidentDir: z.string().default("docs/incidents"),
137
+ memoryDir: z.string().default("memory"),
138
+ memoryIndexFile: z.string().default("MEMORY.md"),
139
+ enforcementHooksDir: z.string().default("scripts/hooks"),
140
+ fixDetection: z.object({
141
+ enabled: z.boolean().default(true),
142
+ lookbackDays: z.number().default(7),
143
+ signals: z.array(z.string()).default([
144
+ "removed_broken_code",
145
+ "added_error_handling",
146
+ "method_name_correction",
147
+ "auth_fix",
148
+ "nil_handling_fix",
149
+ "concurrency_fix",
150
+ "async_pattern_fix",
151
+ "added_missing_import"
152
+ ])
153
+ }).default({}),
154
+ pipeline: z.object({
155
+ requireIncidentReport: z.boolean().default(true),
156
+ requirePreventionRule: z.boolean().default(true),
157
+ requireEnforcement: z.boolean().default(true)
158
+ }).default({})
159
+ }).optional();
134
160
  var CloudConfigSchema = z.object({
135
161
  enabled: z.boolean().default(false),
136
162
  apiKey: z.string().optional(),
@@ -220,7 +246,8 @@ var RawConfigSchema = z.object({
220
246
  regression: RegressionConfigSchema,
221
247
  cloud: CloudConfigSchema,
222
248
  conventions: ConventionsConfigSchema,
223
- python: PythonConfigSchema
249
+ python: PythonConfigSchema,
250
+ autoLearning: AutoLearningConfigSchema
224
251
  }).passthrough();
225
252
  var _config = null;
226
253
  var _projectRoot = null;
@@ -131,6 +131,32 @@ var RegressionConfigSchema = z.object({
131
131
  warning: z.number().default(50)
132
132
  }).optional()
133
133
  }).optional();
134
+ var AutoLearningConfigSchema = z.object({
135
+ enabled: z.boolean().default(true),
136
+ incidentDir: z.string().default("docs/incidents"),
137
+ memoryDir: z.string().default("memory"),
138
+ memoryIndexFile: z.string().default("MEMORY.md"),
139
+ enforcementHooksDir: z.string().default("scripts/hooks"),
140
+ fixDetection: z.object({
141
+ enabled: z.boolean().default(true),
142
+ lookbackDays: z.number().default(7),
143
+ signals: z.array(z.string()).default([
144
+ "removed_broken_code",
145
+ "added_error_handling",
146
+ "method_name_correction",
147
+ "auth_fix",
148
+ "nil_handling_fix",
149
+ "concurrency_fix",
150
+ "async_pattern_fix",
151
+ "added_missing_import"
152
+ ])
153
+ }).default({}),
154
+ pipeline: z.object({
155
+ requireIncidentReport: z.boolean().default(true),
156
+ requirePreventionRule: z.boolean().default(true),
157
+ requireEnforcement: z.boolean().default(true)
158
+ }).default({})
159
+ }).optional();
134
160
  var CloudConfigSchema = z.object({
135
161
  enabled: z.boolean().default(false),
136
162
  apiKey: z.string().optional(),
@@ -220,7 +246,8 @@ var RawConfigSchema = z.object({
220
246
  regression: RegressionConfigSchema,
221
247
  cloud: CloudConfigSchema,
222
248
  conventions: ConventionsConfigSchema,
223
- python: PythonConfigSchema
249
+ python: PythonConfigSchema,
250
+ autoLearning: AutoLearningConfigSchema
224
251
  }).passthrough();
225
252
  var _config = null;
226
253
  var _projectRoot = null;
@@ -130,6 +130,32 @@ var RegressionConfigSchema = z.object({
130
130
  warning: z.number().default(50)
131
131
  }).optional()
132
132
  }).optional();
133
+ var AutoLearningConfigSchema = z.object({
134
+ enabled: z.boolean().default(true),
135
+ incidentDir: z.string().default("docs/incidents"),
136
+ memoryDir: z.string().default("memory"),
137
+ memoryIndexFile: z.string().default("MEMORY.md"),
138
+ enforcementHooksDir: z.string().default("scripts/hooks"),
139
+ fixDetection: z.object({
140
+ enabled: z.boolean().default(true),
141
+ lookbackDays: z.number().default(7),
142
+ signals: z.array(z.string()).default([
143
+ "removed_broken_code",
144
+ "added_error_handling",
145
+ "method_name_correction",
146
+ "auth_fix",
147
+ "nil_handling_fix",
148
+ "concurrency_fix",
149
+ "async_pattern_fix",
150
+ "added_missing_import"
151
+ ])
152
+ }).default({}),
153
+ pipeline: z.object({
154
+ requireIncidentReport: z.boolean().default(true),
155
+ requirePreventionRule: z.boolean().default(true),
156
+ requireEnforcement: z.boolean().default(true)
157
+ }).default({})
158
+ }).optional();
133
159
  var CloudConfigSchema = z.object({
134
160
  enabled: z.boolean().default(false),
135
161
  apiKey: z.string().optional(),
@@ -219,7 +245,8 @@ var RawConfigSchema = z.object({
219
245
  regression: RegressionConfigSchema,
220
246
  cloud: CloudConfigSchema,
221
247
  conventions: ConventionsConfigSchema,
222
- python: PythonConfigSchema
248
+ python: PythonConfigSchema,
249
+ autoLearning: AutoLearningConfigSchema
223
250
  }).passthrough();
224
251
  var _config = null;
225
252
  var _projectRoot = null;
@@ -131,6 +131,32 @@ var RegressionConfigSchema = z.object({
131
131
  warning: z.number().default(50)
132
132
  }).optional()
133
133
  }).optional();
134
+ var AutoLearningConfigSchema = z.object({
135
+ enabled: z.boolean().default(true),
136
+ incidentDir: z.string().default("docs/incidents"),
137
+ memoryDir: z.string().default("memory"),
138
+ memoryIndexFile: z.string().default("MEMORY.md"),
139
+ enforcementHooksDir: z.string().default("scripts/hooks"),
140
+ fixDetection: z.object({
141
+ enabled: z.boolean().default(true),
142
+ lookbackDays: z.number().default(7),
143
+ signals: z.array(z.string()).default([
144
+ "removed_broken_code",
145
+ "added_error_handling",
146
+ "method_name_correction",
147
+ "auth_fix",
148
+ "nil_handling_fix",
149
+ "concurrency_fix",
150
+ "async_pattern_fix",
151
+ "added_missing_import"
152
+ ])
153
+ }).default({}),
154
+ pipeline: z.object({
155
+ requireIncidentReport: z.boolean().default(true),
156
+ requirePreventionRule: z.boolean().default(true),
157
+ requireEnforcement: z.boolean().default(true)
158
+ }).default({})
159
+ }).optional();
134
160
  var CloudConfigSchema = z.object({
135
161
  enabled: z.boolean().default(false),
136
162
  apiKey: z.string().optional(),
@@ -220,7 +246,8 @@ var RawConfigSchema = z.object({
220
246
  regression: RegressionConfigSchema,
221
247
  cloud: CloudConfigSchema,
222
248
  conventions: ConventionsConfigSchema,
223
- python: PythonConfigSchema
249
+ python: PythonConfigSchema,
250
+ autoLearning: AutoLearningConfigSchema
224
251
  }).passthrough();
225
252
  var _config = null;
226
253
  var _projectRoot = null;