@massu/core 0.6.3 → 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.
package/dist/cli.js CHANGED
@@ -125,7 +125,7 @@ function getResolvedPaths() {
125
125
  settingsLocalPath: resolve(root, claudeDirName, "settings.local.json")
126
126
  };
127
127
  }
128
- var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, RawConfigSchema, _config, _projectRoot;
128
+ var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, RawConfigSchema, _config, _projectRoot;
129
129
  var init_config = __esm({
130
130
  "src/config.ts"() {
131
131
  "use strict";
@@ -248,6 +248,32 @@ var init_config = __esm({
248
248
  warning: z.number().default(50)
249
249
  }).optional()
250
250
  }).optional();
251
+ AutoLearningConfigSchema = z.object({
252
+ enabled: z.boolean().default(true),
253
+ incidentDir: z.string().default("docs/incidents"),
254
+ memoryDir: z.string().default("memory"),
255
+ memoryIndexFile: z.string().default("MEMORY.md"),
256
+ enforcementHooksDir: z.string().default("scripts/hooks"),
257
+ fixDetection: z.object({
258
+ enabled: z.boolean().default(true),
259
+ lookbackDays: z.number().default(7),
260
+ signals: z.array(z.string()).default([
261
+ "removed_broken_code",
262
+ "added_error_handling",
263
+ "method_name_correction",
264
+ "auth_fix",
265
+ "nil_handling_fix",
266
+ "concurrency_fix",
267
+ "async_pattern_fix",
268
+ "added_missing_import"
269
+ ])
270
+ }).default({}),
271
+ pipeline: z.object({
272
+ requireIncidentReport: z.boolean().default(true),
273
+ requirePreventionRule: z.boolean().default(true),
274
+ requireEnforcement: z.boolean().default(true)
275
+ }).default({})
276
+ }).optional();
251
277
  CloudConfigSchema = z.object({
252
278
  enabled: z.boolean().default(false),
253
279
  apiKey: z.string().optional(),
@@ -337,7 +363,8 @@ var init_config = __esm({
337
363
  regression: RegressionConfigSchema,
338
364
  cloud: CloudConfigSchema,
339
365
  conventions: ConventionsConfigSchema,
340
- python: PythonConfigSchema
366
+ python: PythonConfigSchema,
367
+ autoLearning: AutoLearningConfigSchema
341
368
  }).passthrough();
342
369
  _config = null;
343
370
  _projectRoot = null;
@@ -0,0 +1,469 @@
1
+ #!/usr/bin/env node
2
+ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/hooks/auto-learning-pipeline.ts
11
+ import { execSync } from "child_process";
12
+ import { existsSync as existsSync2, readFileSync as readFileSync2, unlinkSync, readdirSync } from "fs";
13
+ import { tmpdir } from "os";
14
+ import { join } from "path";
15
+
16
+ // src/config.ts
17
+ import { resolve, dirname } from "path";
18
+ import { existsSync, readFileSync } from "fs";
19
+ import { parse as parseYaml } from "yaml";
20
+ import { z } from "zod";
21
+ var DomainConfigSchema = z.object({
22
+ name: z.string().default("Unknown"),
23
+ routers: z.array(z.string()).default([]),
24
+ pages: z.array(z.string()).default([]),
25
+ tables: z.array(z.string()).default([]),
26
+ allowedImportsFrom: z.array(z.string()).default([])
27
+ });
28
+ var PatternRuleConfigSchema = z.object({
29
+ pattern: z.string().default("**"),
30
+ rules: z.array(z.string()).default([])
31
+ });
32
+ var CostModelSchema = z.object({
33
+ input_per_million: z.number(),
34
+ output_per_million: z.number(),
35
+ cache_read_per_million: z.number().optional(),
36
+ cache_write_per_million: z.number().optional()
37
+ });
38
+ var AnalyticsConfigSchema = z.object({
39
+ quality: z.object({
40
+ weights: z.record(z.string(), z.number()).default({
41
+ bug_found: -5,
42
+ vr_failure: -10,
43
+ incident: -20,
44
+ cr_violation: -3,
45
+ vr_pass: 2,
46
+ clean_commit: 5,
47
+ successful_verification: 3
48
+ }),
49
+ categories: z.array(z.string()).default(["security", "architecture", "coupling", "tests", "rule_compliance"])
50
+ }).optional(),
51
+ cost: z.object({
52
+ models: z.record(z.string(), CostModelSchema).default({}),
53
+ currency: z.string().default("USD")
54
+ }).optional(),
55
+ prompts: z.object({
56
+ success_indicators: z.array(z.string()).default(["committed", "approved", "looks good", "perfect", "great", "thanks"]),
57
+ failure_indicators: z.array(z.string()).default(["revert", "wrong", "that's not", "undo", "incorrect"]),
58
+ max_turns_for_success: z.number().default(2)
59
+ }).optional()
60
+ }).optional();
61
+ var CustomPatternSchema = z.object({
62
+ pattern: z.string(),
63
+ severity: z.string(),
64
+ message: z.string()
65
+ });
66
+ var GovernanceConfigSchema = z.object({
67
+ audit: z.object({
68
+ formats: z.array(z.string()).default(["summary", "detailed", "soc2"]),
69
+ retention_days: z.number().default(365),
70
+ auto_log: z.record(z.string(), z.boolean()).default({
71
+ code_changes: true,
72
+ rule_enforcement: true,
73
+ approvals: true,
74
+ commits: true
75
+ })
76
+ }).optional(),
77
+ validation: z.object({
78
+ realtime: z.boolean().default(true),
79
+ checks: z.record(z.string(), z.boolean()).default({
80
+ rule_compliance: true,
81
+ import_existence: true,
82
+ naming_conventions: true
83
+ }),
84
+ custom_patterns: z.array(CustomPatternSchema).default([])
85
+ }).optional(),
86
+ adr: z.object({
87
+ detection_phrases: z.array(z.string()).default(["chose", "decided", "switching to", "moving from", "going with"]),
88
+ template: z.string().default("default"),
89
+ storage: z.string().default("database"),
90
+ output_dir: z.string().default("docs/adr")
91
+ }).optional()
92
+ }).optional();
93
+ var SecurityPatternSchema = z.object({
94
+ pattern: z.string(),
95
+ severity: z.string(),
96
+ category: z.string(),
97
+ description: z.string()
98
+ });
99
+ var SecurityConfigSchema = z.object({
100
+ patterns: z.array(SecurityPatternSchema).default([]),
101
+ auto_score_on_edit: z.boolean().default(true),
102
+ score_threshold_alert: z.number().default(50),
103
+ severity_weights: z.record(z.string(), z.number()).optional(),
104
+ restrictive_licenses: z.array(z.string()).optional(),
105
+ dep_alternatives: z.record(z.string(), z.array(z.string())).optional(),
106
+ dependencies: z.object({
107
+ package_manager: z.string().default("npm"),
108
+ blocked_packages: z.array(z.string()).default([]),
109
+ preferred_packages: z.record(z.string(), z.string()).default({}),
110
+ max_bundle_size_kb: z.number().default(500)
111
+ }).optional()
112
+ }).optional();
113
+ var TeamConfigSchema = z.object({
114
+ enabled: z.boolean().default(false),
115
+ sync_backend: z.string().default("local"),
116
+ developer_id: z.string().default("auto"),
117
+ share_by_default: z.boolean().default(false),
118
+ expertise_weights: z.object({
119
+ session: z.number().default(20),
120
+ observation: z.number().default(10)
121
+ }).optional(),
122
+ privacy: z.object({
123
+ share_file_paths: z.boolean().default(true),
124
+ share_code_snippets: z.boolean().default(false),
125
+ share_observations: z.boolean().default(true)
126
+ }).optional()
127
+ }).optional();
128
+ var RegressionConfigSchema = z.object({
129
+ test_patterns: z.array(z.string()).default([
130
+ "{dir}/__tests__/{name}.test.{ext}",
131
+ "{dir}/{name}.spec.{ext}",
132
+ "tests/{path}.test.{ext}"
133
+ ]),
134
+ test_runner: z.string().default("npm test"),
135
+ health_thresholds: z.object({
136
+ healthy: z.number().default(80),
137
+ warning: z.number().default(50)
138
+ }).optional()
139
+ }).optional();
140
+ var AutoLearningConfigSchema = z.object({
141
+ enabled: z.boolean().default(true),
142
+ incidentDir: z.string().default("docs/incidents"),
143
+ memoryDir: z.string().default("memory"),
144
+ memoryIndexFile: z.string().default("MEMORY.md"),
145
+ enforcementHooksDir: z.string().default("scripts/hooks"),
146
+ fixDetection: z.object({
147
+ enabled: z.boolean().default(true),
148
+ lookbackDays: z.number().default(7),
149
+ signals: z.array(z.string()).default([
150
+ "removed_broken_code",
151
+ "added_error_handling",
152
+ "method_name_correction",
153
+ "auth_fix",
154
+ "nil_handling_fix",
155
+ "concurrency_fix",
156
+ "async_pattern_fix",
157
+ "added_missing_import"
158
+ ])
159
+ }).default({}),
160
+ pipeline: z.object({
161
+ requireIncidentReport: z.boolean().default(true),
162
+ requirePreventionRule: z.boolean().default(true),
163
+ requireEnforcement: z.boolean().default(true)
164
+ }).default({})
165
+ }).optional();
166
+ var CloudConfigSchema = z.object({
167
+ enabled: z.boolean().default(false),
168
+ apiKey: z.string().optional(),
169
+ endpoint: z.string().optional(),
170
+ sync: z.object({
171
+ memory: z.boolean().default(true),
172
+ analytics: z.boolean().default(true),
173
+ audit: z.boolean().default(true)
174
+ }).default({ memory: true, analytics: true, audit: true })
175
+ }).optional();
176
+ var ConventionsConfigSchema = z.object({
177
+ claudeDirName: z.string().default(".claude").refine(
178
+ (s) => !s.includes("..") && !s.startsWith("/"),
179
+ { message: 'claudeDirName must not contain ".." or start with "/"' }
180
+ ),
181
+ sessionStatePath: z.string().default(".claude/session-state/CURRENT.md").refine(
182
+ (s) => !s.includes("..") && !s.startsWith("/"),
183
+ { message: 'sessionStatePath must not contain ".." or start with "/"' }
184
+ ),
185
+ sessionArchivePath: z.string().default(".claude/session-state/archive").refine(
186
+ (s) => !s.includes("..") && !s.startsWith("/"),
187
+ { message: 'sessionArchivePath must not contain ".." or start with "/"' }
188
+ ),
189
+ knowledgeCategories: z.array(z.string()).default([
190
+ "patterns",
191
+ "commands",
192
+ "incidents",
193
+ "reference",
194
+ "protocols",
195
+ "checklists",
196
+ "playbooks",
197
+ "critical",
198
+ "scripts",
199
+ "status",
200
+ "templates",
201
+ "loop-state",
202
+ "session-state",
203
+ "agents"
204
+ ]),
205
+ knowledgeSourceFiles: z.array(z.string()).default(["CLAUDE.md", "MEMORY.md", "corrections.md"]),
206
+ excludePatterns: z.array(z.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
207
+ }).optional();
208
+ var PythonDomainConfigSchema = z.object({
209
+ name: z.string(),
210
+ packages: z.array(z.string()),
211
+ allowed_imports_from: z.array(z.string()).default([])
212
+ });
213
+ var PythonConfigSchema = z.object({
214
+ root: z.string(),
215
+ alembic_dir: z.string().optional(),
216
+ domains: z.array(PythonDomainConfigSchema).default([]),
217
+ exclude_dirs: z.array(z.string()).default(["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"])
218
+ }).optional();
219
+ var PathsConfigSchema = z.object({
220
+ source: z.string().default("src"),
221
+ aliases: z.record(z.string(), z.string()).default({ "@": "src" }),
222
+ routers: z.string().optional(),
223
+ routerRoot: z.string().optional(),
224
+ pages: z.string().optional(),
225
+ middleware: z.string().optional(),
226
+ schema: z.string().optional(),
227
+ components: z.string().optional(),
228
+ hooks: z.string().optional()
229
+ });
230
+ var RawConfigSchema = z.object({
231
+ project: z.object({
232
+ name: z.string().default("my-project"),
233
+ root: z.string().default("auto")
234
+ }).default({ name: "my-project", root: "auto" }),
235
+ framework: z.object({
236
+ type: z.string().default("typescript"),
237
+ router: z.string().default("none"),
238
+ orm: z.string().default("none"),
239
+ ui: z.string().default("none")
240
+ }).default({ type: "typescript", router: "none", orm: "none", ui: "none" }),
241
+ paths: PathsConfigSchema.default({ source: "src", aliases: { "@": "src" } }),
242
+ toolPrefix: z.string().default("massu"),
243
+ dbAccessPattern: z.string().optional(),
244
+ knownMismatches: z.record(z.string(), z.record(z.string(), z.string())).optional(),
245
+ accessScopes: z.array(z.string()).optional(),
246
+ domains: z.array(DomainConfigSchema).default([]),
247
+ rules: z.array(PatternRuleConfigSchema).default([]),
248
+ analytics: AnalyticsConfigSchema,
249
+ governance: GovernanceConfigSchema,
250
+ security: SecurityConfigSchema,
251
+ team: TeamConfigSchema,
252
+ regression: RegressionConfigSchema,
253
+ cloud: CloudConfigSchema,
254
+ conventions: ConventionsConfigSchema,
255
+ python: PythonConfigSchema,
256
+ autoLearning: AutoLearningConfigSchema
257
+ }).passthrough();
258
+ var _config = null;
259
+ var _projectRoot = null;
260
+ function findProjectRoot() {
261
+ const cwd = process.cwd();
262
+ let dir = cwd;
263
+ while (true) {
264
+ if (existsSync(resolve(dir, "massu.config.yaml"))) {
265
+ return dir;
266
+ }
267
+ const parent = dirname(dir);
268
+ if (parent === dir) break;
269
+ dir = parent;
270
+ }
271
+ dir = cwd;
272
+ while (true) {
273
+ if (existsSync(resolve(dir, "package.json"))) {
274
+ return dir;
275
+ }
276
+ if (existsSync(resolve(dir, ".git"))) {
277
+ return dir;
278
+ }
279
+ const parent = dirname(dir);
280
+ if (parent === dir) break;
281
+ dir = parent;
282
+ }
283
+ return cwd;
284
+ }
285
+ function getProjectRoot() {
286
+ if (!_projectRoot) {
287
+ _projectRoot = findProjectRoot();
288
+ }
289
+ return _projectRoot;
290
+ }
291
+ function getConfig() {
292
+ if (_config) return _config;
293
+ const root = getProjectRoot();
294
+ const configPath = resolve(root, "massu.config.yaml");
295
+ let rawYaml = {};
296
+ if (existsSync(configPath)) {
297
+ const content = readFileSync(configPath, "utf-8");
298
+ rawYaml = parseYaml(content) ?? {};
299
+ }
300
+ const parsed = RawConfigSchema.parse(rawYaml);
301
+ const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve(root, parsed.project.root);
302
+ _config = {
303
+ project: {
304
+ name: parsed.project.name,
305
+ root: projectRoot
306
+ },
307
+ framework: parsed.framework,
308
+ paths: parsed.paths,
309
+ toolPrefix: parsed.toolPrefix,
310
+ dbAccessPattern: parsed.dbAccessPattern,
311
+ knownMismatches: parsed.knownMismatches,
312
+ accessScopes: parsed.accessScopes,
313
+ domains: parsed.domains,
314
+ rules: parsed.rules,
315
+ analytics: parsed.analytics,
316
+ governance: parsed.governance,
317
+ security: parsed.security,
318
+ team: parsed.team,
319
+ regression: parsed.regression,
320
+ cloud: parsed.cloud,
321
+ conventions: parsed.conventions,
322
+ python: parsed.python
323
+ };
324
+ if (!_config.cloud?.apiKey && process.env.MASSU_API_KEY) {
325
+ _config.cloud = {
326
+ enabled: true,
327
+ sync: { memory: true, analytics: true, audit: true },
328
+ ..._config.cloud,
329
+ apiKey: process.env.MASSU_API_KEY
330
+ };
331
+ }
332
+ return _config;
333
+ }
334
+
335
+ // src/hooks/auto-learning-pipeline.ts
336
+ function getSessionFlagPath(sessionId) {
337
+ return join(tmpdir(), "massu-auto-learning", `fixes-${sessionId.slice(0, 12)}.jsonl`);
338
+ }
339
+ async function main() {
340
+ try {
341
+ const input = await readStdin();
342
+ const hookInput = JSON.parse(input);
343
+ const config = getConfig();
344
+ if (config.autoLearning?.enabled === false) {
345
+ process.exit(0);
346
+ return;
347
+ }
348
+ const root = getProjectRoot();
349
+ const incidentDir = config.autoLearning?.incidentDir ?? "docs/incidents";
350
+ const memoryDir = config.autoLearning?.memoryDir ?? "memory";
351
+ const autoLearn = config.autoLearning;
352
+ const flagPath = getSessionFlagPath(hookInput.session_id);
353
+ let sessionFixes = [];
354
+ if (existsSync2(flagPath)) {
355
+ try {
356
+ sessionFixes = readFileSync2(flagPath, "utf-8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
357
+ } catch {
358
+ }
359
+ }
360
+ let uncommittedFix = false;
361
+ try {
362
+ const diff = execSync("git diff --name-only", { cwd: root, timeout: 3e3, encoding: "utf-8" });
363
+ if (diff.trim()) {
364
+ const fullDiff = execSync("git diff", { cwd: root, timeout: 5e3, encoding: "utf-8" });
365
+ const fixPatterns = (fullDiff.match(/^\+.*(try|except|catch|guard|@MainActor|asyncio\.timeout|X-Service-Token|\.save\(|return False)/gm) || []).length;
366
+ const removedBroken = (fullDiff.match(/^-.*(bug|broken|crash|\.store\(|= nil|error)/gm) || []).length;
367
+ if (fixPatterns > 3 || removedBroken > 1) {
368
+ uncommittedFix = true;
369
+ }
370
+ }
371
+ } catch {
372
+ }
373
+ if (sessionFixes.length === 0 && !uncommittedFix) {
374
+ cleanup(flagPath);
375
+ process.exit(0);
376
+ return;
377
+ }
378
+ const lines = [];
379
+ lines.push("");
380
+ lines.push("============================================================================");
381
+ lines.push(" MASSU AUTO-LEARNING PIPELINE \u2014 ACTION REQUIRED BEFORE SESSION END");
382
+ lines.push("============================================================================");
383
+ if (sessionFixes.length > 0) {
384
+ lines.push("");
385
+ lines.push(` ${sessionFixes.length} bug fix(es) detected during this session:`);
386
+ lines.push("");
387
+ const byFile = /* @__PURE__ */ new Map();
388
+ for (const fix of sessionFixes) {
389
+ const existing = byFile.get(fix.file) ?? [];
390
+ existing.push(...fix.signals);
391
+ byFile.set(fix.file, [...new Set(existing)]);
392
+ }
393
+ for (const [file, signals] of byFile) {
394
+ lines.push(` - ${file} (${signals.join(", ")})`);
395
+ }
396
+ }
397
+ if (uncommittedFix) {
398
+ lines.push("");
399
+ lines.push(" Additional uncommitted fix patterns detected in git diff.");
400
+ }
401
+ lines.push("");
402
+ lines.push(" Complete these steps before this session ends:");
403
+ lines.push("");
404
+ if (autoLearn?.pipeline?.requireIncidentReport !== false) {
405
+ lines.push(" STEP 1: INCIDENT REPORT");
406
+ lines.push(` For each distinct bug fixed, create: ${incidentDir}/YYYY-MM-DD-<slug>.md`);
407
+ lines.push(" Include: Date, Severity, Symptoms, Root Cause, Fix, Files Changed, Prevention Rules");
408
+ lines.push("");
409
+ }
410
+ if (autoLearn?.pipeline?.requirePreventionRule !== false) {
411
+ lines.push(" STEP 2: PREVENTION RULE");
412
+ lines.push(` For each incident, create: ${memoryDir}/feedback_<rule_name>.md`);
413
+ lines.push(" Include frontmatter (name, description, type: feedback) + Why + How to apply");
414
+ lines.push(` Update ${config.autoLearning?.memoryIndexFile ?? "MEMORY.md"} index`);
415
+ lines.push("");
416
+ }
417
+ if (autoLearn?.pipeline?.requireEnforcement !== false) {
418
+ lines.push(" STEP 3: ENFORCEMENT PLACEMENT");
419
+ lines.push(" For each new rule, determine enforcement layer(s):");
420
+ lines.push(" a) If statically detectable \u2192 add to pattern-feedback hook");
421
+ lines.push(" b) If about editing certain files \u2192 add to blast-radius hook");
422
+ lines.push(" c) If about dangerous commands \u2192 add to dangerous-command hook");
423
+ lines.push(" d) If critical \u2192 add to pre-commit hook");
424
+ lines.push(" e) If needs runtime monitoring \u2192 create monitoring producer");
425
+ lines.push("");
426
+ }
427
+ lines.push(" STEP 4: VERIFY");
428
+ lines.push(" Test any new enforcement hooks to confirm they detect violations.");
429
+ lines.push("");
430
+ lines.push("============================================================================");
431
+ lines.push("");
432
+ console.log(lines.join("\n"));
433
+ cleanup(flagPath);
434
+ } catch {
435
+ }
436
+ process.exit(0);
437
+ }
438
+ function cleanup(flagPath) {
439
+ try {
440
+ if (existsSync2(flagPath)) unlinkSync(flagPath);
441
+ const dir = join(tmpdir(), "massu-auto-learning");
442
+ if (existsSync2(dir)) {
443
+ const now = Date.now();
444
+ for (const file of readdirSync(dir)) {
445
+ const fullPath = join(dir, file);
446
+ try {
447
+ const stat = __require("fs").statSync(fullPath);
448
+ if (now - stat.mtimeMs > 864e5) {
449
+ unlinkSync(fullPath);
450
+ }
451
+ } catch {
452
+ }
453
+ }
454
+ }
455
+ } catch {
456
+ }
457
+ }
458
+ function readStdin() {
459
+ return new Promise((resolve2) => {
460
+ let data = "";
461
+ process.stdin.setEncoding("utf-8");
462
+ process.stdin.on("data", (chunk) => {
463
+ data += chunk;
464
+ });
465
+ process.stdin.on("end", () => resolve2(data));
466
+ setTimeout(() => resolve2(data), 5e3);
467
+ });
468
+ }
469
+ main();
@@ -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;