sela-core 1.0.6 → 1.0.8

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 (124) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/ErrorHandler.d.ts +1 -1
  3. package/dist/cli/ErrorHandler.js +14 -14
  4. package/dist/cli/commands/bulk.d.ts +1 -1
  5. package/dist/cli/commands/bulk.d.ts.map +1 -1
  6. package/dist/cli/commands/bulk.js +51 -33
  7. package/dist/cli/commands/init.d.ts +1 -1
  8. package/dist/cli/commands/init.d.ts.map +1 -1
  9. package/dist/cli/commands/init.js +26 -18
  10. package/dist/cli/commands/showReport.d.ts +1 -1
  11. package/dist/cli/commands/showReport.d.ts.map +1 -1
  12. package/dist/cli/commands/showReport.js +12 -10
  13. package/dist/cli/commands/status.d.ts +1 -1
  14. package/dist/cli/commands/status.d.ts.map +1 -1
  15. package/dist/cli/commands/status.js +8 -8
  16. package/dist/cli/commands/sync.d.ts +1 -1
  17. package/dist/cli/commands/sync.d.ts.map +1 -1
  18. package/dist/cli/commands/sync.js +38 -30
  19. package/dist/cli/index.js +9 -9
  20. package/dist/cli/ui/DnaTable.d.ts +1 -1
  21. package/dist/cli/ui/DnaTable.d.ts.map +1 -1
  22. package/dist/cli/ui/DnaTable.js +23 -16
  23. package/dist/cli/ui/RefactorWizard.d.ts +3 -3
  24. package/dist/cli/ui/RefactorWizard.d.ts.map +1 -1
  25. package/dist/cli/ui/RefactorWizard.js +108 -82
  26. package/dist/config/ConfigLoader.d.ts +3 -2
  27. package/dist/config/ConfigLoader.d.ts.map +1 -1
  28. package/dist/config/ConfigLoader.js +23 -13
  29. package/dist/config/DryRunGuard.d.ts +14 -0
  30. package/dist/config/DryRunGuard.d.ts.map +1 -0
  31. package/dist/config/DryRunGuard.js +79 -0
  32. package/dist/config/SelaConfig.d.ts +26 -16
  33. package/dist/config/SelaConfig.d.ts.map +1 -1
  34. package/dist/config/SelaConfig.js +54 -22
  35. package/dist/engine/HealingRegistry.d.ts +1 -1
  36. package/dist/engine/HealingRegistry.js +3 -3
  37. package/dist/engine/SelaEngine.d.ts +13 -10
  38. package/dist/engine/SelaEngine.d.ts.map +1 -1
  39. package/dist/engine/SelaEngine.js +292 -101
  40. package/dist/errors/SelaError.d.ts +132 -0
  41. package/dist/errors/SelaError.d.ts.map +1 -0
  42. package/dist/errors/SelaError.js +154 -0
  43. package/dist/fixtures/expectProxy.d.ts +1 -1
  44. package/dist/fixtures/expectProxy.d.ts.map +1 -1
  45. package/dist/fixtures/expectProxy.js +17 -10
  46. package/dist/fixtures/index.d.ts +7 -1
  47. package/dist/fixtures/index.d.ts.map +1 -1
  48. package/dist/fixtures/index.js +26 -11
  49. package/dist/fixtures/proxyTag.d.ts +12 -0
  50. package/dist/fixtures/proxyTag.d.ts.map +1 -0
  51. package/dist/fixtures/proxyTag.js +45 -0
  52. package/dist/index.d.ts +8 -6
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +9 -4
  55. package/dist/reporter/SelaReporter.d.ts +143 -0
  56. package/dist/reporter/SelaReporter.d.ts.map +1 -0
  57. package/dist/reporter/SelaReporter.js +428 -0
  58. package/dist/services/ASTSourceUpdater.d.ts +20 -1
  59. package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
  60. package/dist/services/ASTSourceUpdater.js +257 -89
  61. package/dist/services/ArgumentTypeAnalyzer.js +7 -7
  62. package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -1
  63. package/dist/services/BlastRadiusAnalyzer.js +5 -2
  64. package/dist/services/ChainValidator.js +22 -22
  65. package/dist/services/CrossFileHealer.js +7 -7
  66. package/dist/services/DefinitionTracer.d.ts +1 -1
  67. package/dist/services/DefinitionTracer.d.ts.map +1 -1
  68. package/dist/services/DefinitionTracer.js +28 -13
  69. package/dist/services/DnaEditorService.d.ts +2 -2
  70. package/dist/services/DnaEditorService.d.ts.map +1 -1
  71. package/dist/services/DnaEditorService.js +81 -62
  72. package/dist/services/DnaIndexService.d.ts +1 -1
  73. package/dist/services/DnaIndexService.d.ts.map +1 -1
  74. package/dist/services/DnaIndexService.js +14 -14
  75. package/dist/services/HealReportService.d.ts +43 -1
  76. package/dist/services/HealReportService.d.ts.map +1 -1
  77. package/dist/services/HealReportService.js +108 -25
  78. package/dist/services/HealingAdvisory.js +1 -1
  79. package/dist/services/HealingCacheService.d.ts +135 -0
  80. package/dist/services/HealingCacheService.d.ts.map +1 -0
  81. package/dist/services/HealingCacheService.js +460 -0
  82. package/dist/services/HealthReportService.d.ts +1 -1
  83. package/dist/services/HealthReportService.d.ts.map +1 -1
  84. package/dist/services/HealthReportService.js +25 -25
  85. package/dist/services/InitializerUpdater.d.ts.map +1 -1
  86. package/dist/services/InitializerUpdater.js +20 -1
  87. package/dist/services/IntentAuditor.d.ts +18 -1
  88. package/dist/services/IntentAuditor.d.ts.map +1 -1
  89. package/dist/services/IntentAuditor.js +50 -26
  90. package/dist/services/InteractiveReview.d.ts +15 -0
  91. package/dist/services/InteractiveReview.d.ts.map +1 -0
  92. package/dist/services/InteractiveReview.js +125 -0
  93. package/dist/services/LLMService.d.ts +18 -2
  94. package/dist/services/LLMService.d.ts.map +1 -1
  95. package/dist/services/LLMService.js +33 -23
  96. package/dist/services/PRAutomationService.d.ts +14 -1
  97. package/dist/services/PRAutomationService.d.ts.map +1 -1
  98. package/dist/services/PRAutomationService.js +287 -92
  99. package/dist/services/PendingPromptLedger.d.ts +44 -0
  100. package/dist/services/PendingPromptLedger.d.ts.map +1 -0
  101. package/dist/services/PendingPromptLedger.js +180 -0
  102. package/dist/services/ReportGenerator.d.ts +70 -0
  103. package/dist/services/ReportGenerator.d.ts.map +1 -0
  104. package/dist/services/ReportGenerator.js +191 -0
  105. package/dist/services/SafetyGuard.d.ts +30 -7
  106. package/dist/services/SafetyGuard.d.ts.map +1 -1
  107. package/dist/services/SafetyGuard.js +85 -116
  108. package/dist/services/SnapshotService.js +5 -5
  109. package/dist/services/SourceLinkService.d.ts +2 -2
  110. package/dist/services/SourceLinkService.d.ts.map +1 -1
  111. package/dist/services/SourceLinkService.js +31 -22
  112. package/dist/services/SourceUpdater.d.ts +1 -1
  113. package/dist/services/SourceUpdater.d.ts.map +1 -1
  114. package/dist/services/SourceUpdater.js +66 -34
  115. package/dist/services/TemplateDiffService.d.ts.map +1 -1
  116. package/dist/services/TemplateDiffService.js +18 -15
  117. package/dist/services/WorkspaceSnapshotService.d.ts +71 -0
  118. package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -0
  119. package/dist/services/WorkspaceSnapshotService.js +200 -0
  120. package/dist/types/index.d.ts +1 -1
  121. package/dist/utils/IsolatedDiff.d.ts +45 -0
  122. package/dist/utils/IsolatedDiff.d.ts.map +1 -0
  123. package/dist/utils/IsolatedDiff.js +382 -0
  124. package/package.json +71 -67
@@ -1,4 +1,4 @@
1
- import { ResolvedConfig } from './SelaConfig';
1
+ import { ResolvedConfig } from "./SelaConfig";
2
2
  export declare class ConfigLoader {
3
3
  private static resolved;
4
4
  private static branch;
@@ -7,9 +7,10 @@ export declare class ConfigLoader {
7
7
  * calls return the cached result at zero cost.
8
8
  */
9
9
  static getInstance(): ResolvedConfig;
10
+ private static logEnvBanners;
10
11
  /** Returns the detected Git branch name, or null if detection failed. */
11
12
  static getBranch(): string | null;
12
- /** Clears the singleton cache useful for testing. */
13
+ /** Clears the singleton cache - useful for testing. */
13
14
  static reset(): void;
14
15
  }
15
16
  //# sourceMappingURL=ConfigLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAc,cAAc,EAAiB,MAAM,cAAc,CAAC;AAoGzE,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA+B;IACtD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAuB;IAE5C;;;OAGG;IACH,MAAM,CAAC,WAAW,IAAI,cAAc;IAiCpC,yEAAyE;IACzE,MAAM,CAAC,SAAS,IAAI,MAAM,GAAG,IAAI;IAMjC,uDAAuD;IACvD,MAAM,CAAC,KAAK,IAAI,IAAI;CAIrB"}
1
+ {"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAc,cAAc,EAAiB,MAAM,cAAc,CAAC;AA4GzE,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA+B;IACtD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAuB;IAE5C;;;OAGG;IACH,MAAM,CAAC,WAAW,IAAI,cAAc;IAuCpC,OAAO,CAAC,MAAM,CAAC,aAAa;IAW5B,yEAAyE;IACzE,MAAM,CAAC,SAAS,IAAI,MAAM,GAAG,IAAI;IAMjC,uDAAuD;IACvD,MAAM,CAAC,KAAK,IAAI,IAAI;CAIrB"}
@@ -48,7 +48,7 @@ const SelaConfig_1 = require("./SelaConfig");
48
48
  function findConfigFile(startDir) {
49
49
  let dir = startDir;
50
50
  while (true) {
51
- for (const name of ['sela.config.ts', 'sela.config.js']) {
51
+ for (const name of ["sela.config.ts", "sela.config.js"]) {
52
52
  const candidate = path.join(dir, name);
53
53
  if (fs.existsSync(candidate))
54
54
  return candidate;
@@ -65,19 +65,19 @@ function findConfigFile(startDir) {
65
65
  function getCurrentBranch() {
66
66
  try {
67
67
  // Fail fast if not a git repo or git is unavailable
68
- const branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
69
- encoding: 'utf-8',
70
- stdio: ['pipe', 'pipe', 'pipe'],
68
+ const branch = (0, child_process_1.execSync)("git rev-parse --abbrev-ref HEAD", {
69
+ encoding: "utf-8",
70
+ stdio: ["pipe", "pipe", "pipe"],
71
71
  }).trim();
72
- if (branch === 'HEAD') {
72
+ if (branch === "HEAD") {
73
73
  // Detached HEAD (common in CI with explicit SHA checkout)
74
- console.warn('[Sela] ⚠️ Detached HEAD detected branch overrides skipped');
74
+ console.warn("[Sela] ⚠️ Detached HEAD detected - branch overrides skipped");
75
75
  return null;
76
76
  }
77
77
  return branch;
78
78
  }
79
79
  catch {
80
- console.warn('[Sela] ⚠️ Git branch detection failed branch overrides skipped');
80
+ console.warn("[Sela] ⚠️ Git branch detection failed - branch overrides skipped");
81
81
  return null;
82
82
  }
83
83
  }
@@ -91,8 +91,8 @@ function loadRawConfig(configPath) {
91
91
  // eslint-disable-next-line @typescript-eslint/no-var-requires
92
92
  const mod = require(configPath);
93
93
  const config = mod?.default ?? mod ?? {};
94
- if (typeof config !== 'object' || config === null) {
95
- console.warn(`[Sela] ⚠️ sela.config did not export an object using defaults`);
94
+ if (typeof config !== "object" || config === null) {
95
+ console.warn(`[Sela] ⚠️ sela.config did not export an object - using defaults`);
96
96
  return {};
97
97
  }
98
98
  return config;
@@ -103,7 +103,7 @@ function loadRawConfig(configPath) {
103
103
  }
104
104
  }
105
105
  // ─────────────────────────────────────────────────────────────────
106
- // DEEP MERGE (plain objects only arrays are replaced, not merged)
106
+ // DEEP MERGE (plain objects only - arrays are replaced, not merged)
107
107
  // ─────────────────────────────────────────────────────────────────
108
108
  function deepMerge(base, override) {
109
109
  const result = { ...base };
@@ -111,10 +111,10 @@ function deepMerge(base, override) {
111
111
  const baseVal = result[key];
112
112
  const overrideVal = override[key];
113
113
  if (overrideVal !== null &&
114
- typeof overrideVal === 'object' &&
114
+ typeof overrideVal === "object" &&
115
115
  !Array.isArray(overrideVal) &&
116
116
  baseVal !== null &&
117
- typeof baseVal === 'object' &&
117
+ typeof baseVal === "object" &&
118
118
  !Array.isArray(baseVal)) {
119
119
  result[key] = deepMerge(baseVal, overrideVal);
120
120
  }
@@ -141,6 +141,7 @@ class ConfigLoader {
141
141
  if (!configPath) {
142
142
  // Zero-breaking-change guarantee: no config → pure defaults
143
143
  ConfigLoader.resolved = (0, SelaConfig_1.resolveConfig)({});
144
+ ConfigLoader.logEnvBanners(ConfigLoader.resolved);
144
145
  return ConfigLoader.resolved;
145
146
  }
146
147
  console.log(`[Sela] 📄 Loaded config from: ${path.relative(process.cwd(), configPath)}`);
@@ -156,8 +157,17 @@ class ConfigLoader {
156
157
  }
157
158
  }
158
159
  ConfigLoader.resolved = (0, SelaConfig_1.resolveConfig)(rawConfig);
160
+ ConfigLoader.logEnvBanners(ConfigLoader.resolved);
159
161
  return ConfigLoader.resolved;
160
162
  }
163
+ static logEnvBanners(resolved) {
164
+ if (resolved.dryRun) {
165
+ console.log("[Sela] 🌵 DRY RUN active (SELA_DRY_RUN) - disk writes & git commits suppressed.");
166
+ }
167
+ if (resolved.noCache) {
168
+ console.log("[Sela] 🧊 Cache disabled (SELA_NO_CACHE).");
169
+ }
170
+ }
161
171
  /** Returns the detected Git branch name, or null if detection failed. */
162
172
  static getBranch() {
163
173
  // Ensure getInstance() has been called at least once
@@ -165,7 +175,7 @@ class ConfigLoader {
165
175
  ConfigLoader.getInstance();
166
176
  return ConfigLoader.branch;
167
177
  }
168
- /** Clears the singleton cache useful for testing. */
178
+ /** Clears the singleton cache - useful for testing. */
169
179
  static reset() {
170
180
  ConfigLoader.resolved = null;
171
181
  ConfigLoader.branch = null;
@@ -0,0 +1,14 @@
1
+ export declare const DryRunGuard: {
2
+ /**
3
+ * Returns true when `SELA_DRY_RUN` is set to a truthy value in the current
4
+ * process environment. Throws via `parseEnvBoolean` when the value is not
5
+ * one of the accepted tokens - fail-fast keeps misconfigured CI loud.
6
+ */
7
+ active(env?: NodeJS.ProcessEnv): boolean;
8
+ /**
9
+ * Centralised log line for skipped writes so the diff between a dry run
10
+ * and a real run is auditable in test output and CI logs.
11
+ */
12
+ logSkippedWrite(label: string, target: string): void;
13
+ };
14
+ //# sourceMappingURL=DryRunGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DryRunGuard.d.ts","sourceRoot":"","sources":["../../src/config/DryRunGuard.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,WAAW;IACtB;;;;OAIG;iBACS,MAAM,CAAC,UAAU,GAAiB,OAAO;IAIrD;;;OAGG;2BACoB,MAAM,UAAU,MAAM,GAAG,IAAI;CAIrD,CAAC"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ // src/config/DryRunGuard.ts
3
+ //
4
+ // Single source of truth for the "dry run" runtime gate.
5
+ //
6
+ // The flag is sourced from the `SELA_DRY_RUN` environment variable using the
7
+ // strict parser in SelaConfig.parseEnvBoolean (no silent coercion - bad
8
+ // values throw). The variable is re-read on every call so tests and
9
+ // long-running processes can toggle it without restarting the engine.
10
+ //
11
+ // Two writer paths route through this guard:
12
+ //
13
+ // 1. SourceUpdater._coreUpdate - every `fs.writeFileSync` to a spec/source
14
+ // file. When dry-run is active the write is skipped and a console
15
+ // breadcrumb is emitted with the absolute path that *would have* been
16
+ // written.
17
+ //
18
+ // 2. ASTSourceUpdater._persistChanges - wraps ts-morph `SourceFile.saveSync`.
19
+ // When dry-run is active the in-memory AST mutation stays, but the
20
+ // `saveSync` call (which forwards to fs.writeFileSync inside ts-morph)
21
+ // is skipped so the spec on disk is identical pre/post heal.
22
+ //
23
+ // Git auto-commit operations consult `DryRunGuard.active()` directly so
24
+ // `git add` / `git commit` never fire during a dry run.
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
37
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
38
+ }) : function(o, v) {
39
+ o["default"] = v;
40
+ });
41
+ var __importStar = (this && this.__importStar) || (function () {
42
+ var ownKeys = function(o) {
43
+ ownKeys = Object.getOwnPropertyNames || function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54
+ __setModuleDefault(result, mod);
55
+ return result;
56
+ };
57
+ })();
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.DryRunGuard = void 0;
60
+ const path = __importStar(require("path"));
61
+ const SelaConfig_1 = require("./SelaConfig");
62
+ exports.DryRunGuard = {
63
+ /**
64
+ * Returns true when `SELA_DRY_RUN` is set to a truthy value in the current
65
+ * process environment. Throws via `parseEnvBoolean` when the value is not
66
+ * one of the accepted tokens - fail-fast keeps misconfigured CI loud.
67
+ */
68
+ active(env = process.env) {
69
+ return (0, SelaConfig_1.parseEnvBoolean)("SELA_DRY_RUN", env.SELA_DRY_RUN);
70
+ },
71
+ /**
72
+ * Centralised log line for skipped writes so the diff between a dry run
73
+ * and a real run is auditable in test output and CI logs.
74
+ */
75
+ logSkippedWrite(label, target) {
76
+ const display = target ? path.basename(target) : "<no-path>";
77
+ console.log(`[Sela] 🌵 Dry Run - skip ${label} → ${display}`);
78
+ },
79
+ };
@@ -1,11 +1,11 @@
1
- export type PRStrategy = 'directCommit' | 'pr' | 'draftPR' | 'readOnly';
2
- export type BugAction = 'failCI' | 'createIssue' | 'labelOnly';
1
+ export type PRStrategy = "directCommit" | "pr" | "draftPR" | "readOnly";
2
+ export type BugAction = "failCI" | "createIssue" | "labelOnly";
3
3
  export interface SelaPRAutomationConfig {
4
4
  /** Master switch. Default: false (fully backward-compatible). */
5
5
  enabled?: boolean;
6
6
  /** Git-flow strategy. Default: 'readOnly' (safest). */
7
7
  strategy?: PRStrategy;
8
- /** Branches on which directCommit is FORBIDDEN auto-downgraded. */
8
+ /** Branches on which directCommit is FORBIDDEN - auto-downgraded. */
9
9
  protectedBranches?: string[];
10
10
  /** Trust-aware downgrade thresholds (0–100). 0 = never downgrade by that metric. */
11
11
  reviewThresholds?: {
@@ -14,7 +14,7 @@ export interface SelaPRAutomationConfig {
14
14
  /** Min auditor adjusted confidence required for directCommit. Below → downgrade. */
15
15
  minAuditorScoreForDirectCommit?: number;
16
16
  /** Strategy to downgrade TO. Default: 'draftPR'. */
17
- downgradeTo?: Exclude<PRStrategy, 'directCommit'>;
17
+ downgradeTo?: Exclude<PRStrategy, "directCommit">;
18
18
  };
19
19
  /** Behavior when SafetyGuard blocks a heal (PROTECTED events). Default: 'failCI'. */
20
20
  onBugDetected?: BugAction;
@@ -31,15 +31,13 @@ export interface SelaPRAutomationConfig {
31
31
  }
32
32
  export interface SelaConfig {
33
33
  /** Shorthand preset that expands to concrete threshold values. */
34
- healingPolicy?: 'conservative' | 'balanced' | 'aggressive';
34
+ healingPolicy?: "conservative" | "balanced" | "aggressive";
35
35
  /** Fine-grained threshold overrides. Explicit values always win over preset expansion. */
36
36
  thresholds?: {
37
37
  /** Minimum AI confidence to attempt a heal. Default: 85. Maps to CONFIDENCE_HARD_STOP. */
38
38
  minHealerConfidence?: number;
39
39
  /** How strictly the Intent Auditor treats SUSPICIOUS verdicts. Default: 'balanced'. */
40
- auditorStrictness?: 'strict' | 'balanced' | 'loose';
41
- /** Similarity floor for UNKNOWN-role assertion text changes. Default: 0.70. */
42
- assertionSimilarityFloor?: number;
40
+ auditorStrictness?: "strict" | "balanced" | "loose";
43
41
  };
44
42
  agenticDiscovery?: {
45
43
  enabled?: boolean;
@@ -47,7 +45,7 @@ export interface SelaConfig {
47
45
  forbiddenSelectors?: string[];
48
46
  };
49
47
  /** How healed selectors are persisted. Default: 'inPlace'. */
50
- updateStrategy?: 'inPlace' | 'commentOnly' | 'branch';
48
+ updateStrategy?: "inPlace" | "commentOnly" | "branch";
51
49
  /**
52
50
  * @deprecated Use `prAutomation.strategy = 'directCommit'` instead.
53
51
  * When `prAutomation.enabled` is true this flag is forced to false and
@@ -71,14 +69,12 @@ export interface ResolvedThresholds {
71
69
  confidenceHardStop: number;
72
70
  /** Confidence below which a heal is tagged REQUIRES_REVIEW instead of SAFE. */
73
71
  confidenceReviewThreshold: number;
74
- /** Similarity floor for UNKNOWN→UNKNOWN assertion text changes. */
75
- assertionSimilarityFloor: number;
76
72
  /** Minimum auditor confidence to treat a verdict as CONSISTENT. */
77
73
  auditorConfidenceMin: number;
78
74
  /** When true, SUSPICIOUS in assertion mode yields REQUIRES_REVIEW instead of BLOCKED. */
79
75
  allowSuspicious: boolean;
80
- /** The resolved strictness name used for policy-aware log messages. */
81
- auditorStrictness: 'strict' | 'balanced' | 'loose';
76
+ /** The resolved strictness name - used for policy-aware log messages. */
77
+ auditorStrictness: "strict" | "balanced" | "loose";
82
78
  }
83
79
  export interface ResolvedPRAutomation {
84
80
  enabled: boolean;
@@ -87,7 +83,7 @@ export interface ResolvedPRAutomation {
87
83
  reviewThresholds: {
88
84
  minConfidenceForDirectCommit: number;
89
85
  minAuditorScoreForDirectCommit: number;
90
- downgradeTo: Exclude<PRStrategy, 'directCommit'>;
86
+ downgradeTo: Exclude<PRStrategy, "directCommit">;
91
87
  };
92
88
  onBugDetected: BugAction;
93
89
  branchNameTemplate: string;
@@ -98,7 +94,7 @@ export interface ResolvedPRAutomation {
98
94
  }
99
95
  export interface ResolvedConfig {
100
96
  thresholds: ResolvedThresholds;
101
- updateStrategy: 'inPlace' | 'commentOnly' | 'branch';
97
+ updateStrategy: "inPlace" | "commentOnly" | "branch";
102
98
  autoCommit: boolean;
103
99
  dnaStoragePath: string;
104
100
  prAutomation: ResolvedPRAutomation;
@@ -107,7 +103,21 @@ export interface ResolvedConfig {
107
103
  maxSteps: number;
108
104
  forbiddenSelectors: string[];
109
105
  };
106
+ /**
107
+ * When true, every disk-mutating side-effect in the heal pipeline is
108
+ * suppressed: `fs.writeFileSync`, ts-morph `saveSync`, and git auto-commits.
109
+ * The heal still runs end-to-end (LLM call, SafetyGuard, candidate diff),
110
+ * but no source files are modified and no commits are produced.
111
+ * Sourced from `SELA_DRY_RUN` env var (`1`, `true`, `yes`, `on`).
112
+ */
113
+ dryRun: boolean;
114
+ /**
115
+ * When true, the healing cache layer is bypassed - every heal request
116
+ * goes straight to the LLM. Sourced from `SELA_NO_CACHE` env var.
117
+ */
118
+ noCache: boolean;
110
119
  }
111
120
  export declare function resolveThresholds(config: SelaConfig): ResolvedThresholds;
112
- export declare function resolveConfig(config: SelaConfig): ResolvedConfig;
121
+ export declare function parseEnvBoolean(varName: string, rawValue: string | undefined): boolean;
122
+ export declare function resolveConfig(config: SelaConfig, env?: NodeJS.ProcessEnv): ResolvedConfig;
113
123
  //# sourceMappingURL=SelaConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SelaConfig.d.ts","sourceRoot":"","sources":["../../src/config/SelaConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelaConfig.d.ts","sourceRoot":"","sources":["../../src/config/SelaConfig.ts"],"names":[],"mappings":"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"}
@@ -3,11 +3,21 @@
3
3
  // Single source of truth for all Sela configuration types and preset expansion logic.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.resolveThresholds = resolveThresholds;
6
+ exports.parseEnvBoolean = parseEnvBoolean;
6
7
  exports.resolveConfig = resolveConfig;
7
8
  const PRESET_MAP = {
8
- conservative: { minHealerConfidence: 92, auditorStrictness: 'strict', assertionSimilarityFloor: 0.85 },
9
- balanced: { minHealerConfidence: 85, auditorStrictness: 'balanced', assertionSimilarityFloor: 0.70 },
10
- aggressive: { minHealerConfidence: 75, auditorStrictness: 'loose', assertionSimilarityFloor: 0.55 },
9
+ conservative: {
10
+ minHealerConfidence: 92,
11
+ auditorStrictness: "strict",
12
+ },
13
+ balanced: {
14
+ minHealerConfidence: 85,
15
+ auditorStrictness: "balanced",
16
+ },
17
+ aggressive: {
18
+ minHealerConfidence: 75,
19
+ auditorStrictness: "loose",
20
+ },
11
21
  };
12
22
  const STRICTNESS_CONFIDENCE = {
13
23
  strict: 90,
@@ -25,15 +35,13 @@ function resolveThresholds(config) {
25
35
  // Explicit thresholds always win over preset expansion
26
36
  const merged = { ...fromPreset, ...config.thresholds };
27
37
  const minHealerConfidence = merged.minHealerConfidence ?? 85;
28
- const auditorStrictness = merged.auditorStrictness ?? 'balanced';
29
- const assertionSimilarityFloor = merged.assertionSimilarityFloor ?? 0.7;
38
+ const auditorStrictness = merged.auditorStrictness ?? "balanced";
30
39
  return {
31
40
  confidenceHardStop: minHealerConfidence,
32
41
  confidenceReviewThreshold: 95,
33
- assertionSimilarityFloor,
34
42
  auditorConfidenceMin: STRICTNESS_CONFIDENCE[auditorStrictness],
35
- // allowSuspicious is derived never independently settable to avoid footguns
36
- allowSuspicious: auditorStrictness === 'loose',
43
+ // allowSuspicious is derived - never independently settable to avoid footguns
44
+ allowSuspicious: auditorStrictness === "loose",
37
45
  auditorStrictness,
38
46
  };
39
47
  }
@@ -41,47 +49,71 @@ function resolvePRAutomation(config) {
41
49
  const pr = config.prAutomation ?? {};
42
50
  // Legacy bridge: autoCommit:true with no explicit prAutomation block
43
51
  // → enable prAutomation in directCommit mode. Explicit prAutomation always wins.
44
- const legacyEnabled = config.autoCommit === true &&
45
- config.prAutomation === undefined;
52
+ const legacyEnabled = config.autoCommit === true && config.prAutomation === undefined;
46
53
  const enabled = pr.enabled ?? legacyEnabled;
47
- const strategy = pr.strategy ?? (legacyEnabled ? 'directCommit' : 'readOnly');
54
+ const strategy = pr.strategy ?? (legacyEnabled ? "directCommit" : "readOnly");
48
55
  return {
49
56
  enabled,
50
57
  strategy,
51
- protectedBranches: pr.protectedBranches ?? ['main', 'master', 'release'],
58
+ protectedBranches: pr.protectedBranches ?? ["main", "master", "release"],
52
59
  reviewThresholds: {
53
60
  minConfidenceForDirectCommit: pr.reviewThresholds?.minConfidenceForDirectCommit ?? 0,
54
61
  minAuditorScoreForDirectCommit: pr.reviewThresholds?.minAuditorScoreForDirectCommit ?? 0,
55
- downgradeTo: pr.reviewThresholds?.downgradeTo ?? 'draftPR',
62
+ downgradeTo: pr.reviewThresholds?.downgradeTo ?? "draftPR",
56
63
  },
57
- onBugDetected: pr.onBugDetected ?? 'failCI',
58
- branchNameTemplate: pr.branchNameTemplate ?? 'sela/heal-${id}',
59
- titleTemplate: pr.titleTemplate ?? 'fix(sela): heal selector in ${fileName}',
64
+ onBugDetected: pr.onBugDetected ?? "failCI",
65
+ branchNameTemplate: pr.branchNameTemplate ?? "sela/heal-${id}",
66
+ titleTemplate: pr.titleTemplate ?? "fix(sela): heal selector in ${fileName}",
60
67
  bodyTemplate: pr.bodyTemplate ?? null,
61
68
  labels: pr.labels ?? [],
62
- reportArtifactPath: pr.reportArtifactPath ?? 'sela-report.html',
69
+ reportArtifactPath: pr.reportArtifactPath ?? "sela-report.html",
63
70
  };
64
71
  }
65
- function resolveConfig(config) {
72
+ // ═══════════════════════════════════════════════════════════════════
73
+ // ENV FLAG PARSING - strict, fail-fast
74
+ //
75
+ // Accepted truthy values (case-insensitive): "1", "true", "yes", "on".
76
+ // Accepted falsy values (case-insensitive): "0", "false", "no", "off", "".
77
+ // Anything else → throws so misconfigured CI environments fail loudly
78
+ // instead of silently running the wrong mode.
79
+ // ═══════════════════════════════════════════════════════════════════
80
+ const ENV_TRUTHY = new Set(["1", "true", "yes", "on"]);
81
+ const ENV_FALSY = new Set(["0", "false", "no", "off", ""]);
82
+ function parseEnvBoolean(varName, rawValue) {
83
+ if (rawValue === undefined)
84
+ return false;
85
+ const normalized = rawValue.trim().toLowerCase();
86
+ if (ENV_TRUTHY.has(normalized))
87
+ return true;
88
+ if (ENV_FALSY.has(normalized))
89
+ return false;
90
+ throw new Error(`[Sela] Invalid value for env var "${varName}": "${rawValue}". ` +
91
+ `Expected one of: 1, 0, true, false, yes, no, on, off.`);
92
+ }
93
+ function resolveConfig(config, env = process.env) {
66
94
  const prAutomation = resolvePRAutomation(config);
67
95
  // When prAutomation owns the git pipeline, suppress per-heal git side-effects
68
96
  // in SourceUpdater (autoCommit + updateStrategy:'branch') to avoid double-commits.
69
97
  const suppressLegacyGit = prAutomation.enabled;
70
- const requestedUpdateStrategy = config.updateStrategy ?? 'inPlace';
71
- const updateStrategy = suppressLegacyGit && requestedUpdateStrategy === 'branch'
72
- ? 'inPlace'
98
+ const requestedUpdateStrategy = config.updateStrategy ?? "inPlace";
99
+ const updateStrategy = suppressLegacyGit && requestedUpdateStrategy === "branch"
100
+ ? "inPlace"
73
101
  : requestedUpdateStrategy;
74
102
  const autoCommit = suppressLegacyGit ? false : (config.autoCommit ?? false);
103
+ const dryRun = parseEnvBoolean("SELA_DRY_RUN", env.SELA_DRY_RUN);
104
+ const noCache = parseEnvBoolean("SELA_NO_CACHE", env.SELA_NO_CACHE);
75
105
  return {
76
106
  thresholds: resolveThresholds(config),
77
107
  updateStrategy,
78
108
  autoCommit,
79
- dnaStoragePath: config.dnaStoragePath ?? 'fixwright-snapshots',
109
+ dnaStoragePath: config.dnaStoragePath ?? "fixwright-snapshots",
80
110
  prAutomation,
81
111
  agenticDiscovery: {
82
112
  enabled: config.agenticDiscovery?.enabled ?? false,
83
113
  maxSteps: config.agenticDiscovery?.maxSteps ?? 10,
84
114
  forbiddenSelectors: config.agenticDiscovery?.forbiddenSelectors ?? [],
85
115
  },
116
+ dryRun,
117
+ noCache,
86
118
  };
87
119
  }
@@ -29,7 +29,7 @@ export declare class HealingRegistry {
29
29
  /**
30
30
  * Resolve a selector within a specific call-site context.
31
31
  * Falls back to a context-free lookup ONLY when the fingerprint
32
- * has no entry prevents poisoning while still enabling same-file reuse.
32
+ * has no entry - prevents poisoning while still enabling same-file reuse.
33
33
  */
34
34
  resolveSelector(selector: string, ctx?: SelectorContext): string;
35
35
  private walkChain;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // src/engine/HealingRegistry.ts full replacement
2
+ // src/engine/HealingRegistry.ts - full replacement
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.HealingRegistry = void 0;
5
5
  const crypto_1 = require("crypto");
@@ -60,7 +60,7 @@ class HealingRegistry {
60
60
  /**
61
61
  * Resolve a selector within a specific call-site context.
62
62
  * Falls back to a context-free lookup ONLY when the fingerprint
63
- * has no entry prevents poisoning while still enabling same-file reuse.
63
+ * has no entry - prevents poisoning while still enabling same-file reuse.
64
64
  */
65
65
  resolveSelector(selector, ctx) {
66
66
  if (ctx) {
@@ -72,7 +72,7 @@ class HealingRegistry {
72
72
  return resolved;
73
73
  }
74
74
  }
75
- return selector; // No global fallback intentional
75
+ return selector; // No global fallback - intentional
76
76
  }
77
77
  walkChain(selector, store) {
78
78
  let current = selector;
@@ -5,6 +5,8 @@ export declare class SelaEngine {
5
5
  private llmService;
6
6
  private snapshotService;
7
7
  private safetyGuard;
8
+ private astDirectiveScanner;
9
+ private healingCache;
8
10
  private config;
9
11
  private dnaBuffer;
10
12
  private healMetaBuffer;
@@ -15,17 +17,18 @@ export declare class SelaEngine {
15
17
  private _toReportFile;
16
18
  private _safeReadLine;
17
19
  /**
18
- * Capture the native `git diff --unified=1 HEAD -- <file>` for the file the
19
- * AST mutation just wrote to. Returns an empty string when git is not
20
- * available, the file is not tracked, or any other failure — callers must
21
- * treat empty output as "no diff captured" and fall back to a direct disk
22
- * read of the mutated line.
20
+ * Clean-Room isolated diff: render a unified diff between the file's
21
+ * pre-Sela disk snapshot (`contentBefore`) and the post-write disk state
22
+ * (`contentAfter`) captured by `WorkspaceSnapshotService`. Returns "" when
23
+ * the file was never tracked (no snapshot) or the AST mutation produced
24
+ * no net change.
23
25
  *
24
- * Path safety: the absolute path is always wrapped in double quotes after
25
- * escaping any embedded double quotes, which makes the call safe on Windows
26
- * paths containing spaces or backslashes as well as POSIX paths.
26
+ * This is what makes the HTML report immune to developer dirty edits: any
27
+ * pre-existing uncommitted changes live in BOTH buffers identically and
28
+ * are therefore filtered out by the diff. The output contains only Sela's
29
+ * selector swap.
27
30
  */
28
- private _captureGitDiff;
31
+ private _captureIsolatedDiff;
29
32
  /**
30
33
  * Walk a unified diff and pull out the first removed line and the first
31
34
  * added line so the legacy report fields (`oldCodeLine`, `newCodeLine`)
@@ -33,7 +36,7 @@ export declare class SelaEngine {
33
36
  * `gitUnifiedDiff` payload yet.
34
37
  *
35
38
  * Carefully skips the diff preamble (--- a/file, +++ b/file, "diff ",
36
- * "index ", rename headers) those lines would otherwise be mistaken for
39
+ * "index ", rename headers) - those lines would otherwise be mistaken for
37
40
  * a -/+ change pair and produce nonsense like the original "line replaced
38
41
  * by itself" output. Real change lines only count once the parser has seen
39
42
  * a "@@" hunk header.
@@ -1 +1 @@
1
- {"version":3,"file":"SelaEngine.d.ts","sourceRoot":"","sources":["../../src/engine/SelaEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAOxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAe,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAyChE,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,eAAe,CAAkC;;IAanD,YAAY,CAChB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiDnB,IAAI,CACR,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,QAAmB,GAC5B,OAAO,CAAC,MAAM,CAAC;IAyclB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,aAAa;IAarB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,eAAe;IAwBvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,2BAA2B;IA4BnC,OAAO,CAAC,yBAAyB;IAwBjC,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,oBAAoB;IAuC5B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;YA6FtB,aAAa;IAsB3B,OAAO,CAAC,0BAA0B;IAiClC,OAAO,CAAC,WAAW;IA6Bb,wBAAwB,CAC5B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;CAqBnB;AAED,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"SelaEngine.d.ts","sourceRoot":"","sources":["../../src/engine/SelaEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAaxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EAAe,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAmEhE,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,mBAAmB,CAAmB;IAC9C,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,eAAe,CAAkC;;IAqBnD,YAAY,CAChB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiDnB,IAAI,CACR,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,QAAmB,GAC5B,OAAO,CAAC,MAAM,CAAC;IAilBlB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,aAAa;IAerB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,2BAA2B;IA4BnC,OAAO,CAAC,yBAAyB;IAmCjC,OAAO,CAAC,kBAAkB;IA8D1B,OAAO,CAAC,oBAAoB;IAyD5B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;YAqItB,aAAa;IAsB3B,OAAO,CAAC,0BAA0B;IAiClC,OAAO,CAAC,WAAW;IA6Bb,wBAAwB,CAC5B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;CAqBnB;AAED,OAAO,EAAE,CAAC"}