sela-core 1.0.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.
Files changed (144) hide show
  1. package/README.md +93 -0
  2. package/bin/sela.js +3 -0
  3. package/dist/cli/ErrorHandler.d.ts +10 -0
  4. package/dist/cli/ErrorHandler.d.ts.map +1 -0
  5. package/dist/cli/ErrorHandler.js +70 -0
  6. package/dist/cli/commands/bulk.d.ts +3 -0
  7. package/dist/cli/commands/bulk.d.ts.map +1 -0
  8. package/dist/cli/commands/bulk.js +140 -0
  9. package/dist/cli/commands/find.d.ts +3 -0
  10. package/dist/cli/commands/find.d.ts.map +1 -0
  11. package/dist/cli/commands/find.js +51 -0
  12. package/dist/cli/commands/init.d.ts +3 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -0
  14. package/dist/cli/commands/init.js +133 -0
  15. package/dist/cli/commands/list.d.ts +3 -0
  16. package/dist/cli/commands/list.d.ts.map +1 -0
  17. package/dist/cli/commands/list.js +56 -0
  18. package/dist/cli/commands/refactor.d.ts +3 -0
  19. package/dist/cli/commands/refactor.d.ts.map +1 -0
  20. package/dist/cli/commands/refactor.js +30 -0
  21. package/dist/cli/commands/status.d.ts +3 -0
  22. package/dist/cli/commands/status.d.ts.map +1 -0
  23. package/dist/cli/commands/status.js +51 -0
  24. package/dist/cli/commands/sync.d.ts +3 -0
  25. package/dist/cli/commands/sync.d.ts.map +1 -0
  26. package/dist/cli/commands/sync.js +123 -0
  27. package/dist/cli/index.d.ts +2 -0
  28. package/dist/cli/index.d.ts.map +1 -0
  29. package/dist/cli/index.js +42 -0
  30. package/dist/cli/ui/DnaTable.d.ts +3 -0
  31. package/dist/cli/ui/DnaTable.d.ts.map +1 -0
  32. package/dist/cli/ui/DnaTable.js +70 -0
  33. package/dist/cli/ui/LocatorPicker.d.ts +8 -0
  34. package/dist/cli/ui/LocatorPicker.d.ts.map +1 -0
  35. package/dist/cli/ui/LocatorPicker.js +33 -0
  36. package/dist/cli/ui/ProgressReporter.d.ts +11 -0
  37. package/dist/cli/ui/ProgressReporter.d.ts.map +1 -0
  38. package/dist/cli/ui/ProgressReporter.js +33 -0
  39. package/dist/cli/ui/RefactorWizard.d.ts +26 -0
  40. package/dist/cli/ui/RefactorWizard.d.ts.map +1 -0
  41. package/dist/cli/ui/RefactorWizard.js +269 -0
  42. package/dist/config/ConfigLoader.d.ts +15 -0
  43. package/dist/config/ConfigLoader.d.ts.map +1 -0
  44. package/dist/config/ConfigLoader.js +174 -0
  45. package/dist/config/SelaConfig.d.ts +67 -0
  46. package/dist/config/SelaConfig.d.ts.map +1 -0
  47. package/dist/config/SelaConfig.js +57 -0
  48. package/dist/config/defineConfig.d.ts +3 -0
  49. package/dist/config/defineConfig.d.ts.map +1 -0
  50. package/dist/config/defineConfig.js +9 -0
  51. package/dist/engine/FixwrightEngine.d.ts +24 -0
  52. package/dist/engine/FixwrightEngine.d.ts.map +1 -0
  53. package/dist/engine/FixwrightEngine.js +403 -0
  54. package/dist/engine/HealingRegistry.d.ts +40 -0
  55. package/dist/engine/HealingRegistry.d.ts.map +1 -0
  56. package/dist/engine/HealingRegistry.js +98 -0
  57. package/dist/engine/singleton.d.ts +3 -0
  58. package/dist/engine/singleton.d.ts.map +1 -0
  59. package/dist/engine/singleton.js +5 -0
  60. package/dist/fixtures/expectProxy.d.ts +12 -0
  61. package/dist/fixtures/expectProxy.d.ts.map +1 -0
  62. package/dist/fixtures/expectProxy.js +228 -0
  63. package/dist/fixtures/index.d.ts +6 -0
  64. package/dist/fixtures/index.d.ts.map +1 -0
  65. package/dist/fixtures/index.js +688 -0
  66. package/dist/fixtures/moduleExpect.d.ts +2 -0
  67. package/dist/fixtures/moduleExpect.d.ts.map +1 -0
  68. package/dist/fixtures/moduleExpect.js +46 -0
  69. package/dist/index.d.ts +7 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +28 -0
  72. package/dist/services/ASTSourceUpdater.d.ts +79 -0
  73. package/dist/services/ASTSourceUpdater.d.ts.map +1 -0
  74. package/dist/services/ASTSourceUpdater.js +3177 -0
  75. package/dist/services/ArgumentTypeAnalyzer.d.ts +26 -0
  76. package/dist/services/ArgumentTypeAnalyzer.d.ts.map +1 -0
  77. package/dist/services/ArgumentTypeAnalyzer.js +92 -0
  78. package/dist/services/BlastRadiusAnalyzer.d.ts +15 -0
  79. package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -0
  80. package/dist/services/BlastRadiusAnalyzer.js +103 -0
  81. package/dist/services/ChainValidator.d.ts +76 -0
  82. package/dist/services/ChainValidator.d.ts.map +1 -0
  83. package/dist/services/ChainValidator.js +569 -0
  84. package/dist/services/CrossFileHealer.d.ts +6 -0
  85. package/dist/services/CrossFileHealer.d.ts.map +1 -0
  86. package/dist/services/CrossFileHealer.js +134 -0
  87. package/dist/services/DefinitionTracer.d.ts +41 -0
  88. package/dist/services/DefinitionTracer.d.ts.map +1 -0
  89. package/dist/services/DefinitionTracer.js +350 -0
  90. package/dist/services/DnaEditorService.d.ts +31 -0
  91. package/dist/services/DnaEditorService.d.ts.map +1 -0
  92. package/dist/services/DnaEditorService.js +198 -0
  93. package/dist/services/DnaIndexService.d.ts +24 -0
  94. package/dist/services/DnaIndexService.d.ts.map +1 -0
  95. package/dist/services/DnaIndexService.js +131 -0
  96. package/dist/services/HealingAdvisory.d.ts +22 -0
  97. package/dist/services/HealingAdvisory.d.ts.map +1 -0
  98. package/dist/services/HealingAdvisory.js +42 -0
  99. package/dist/services/HealthReportService.d.ts +10 -0
  100. package/dist/services/HealthReportService.d.ts.map +1 -0
  101. package/dist/services/HealthReportService.js +84 -0
  102. package/dist/services/InitializerUpdater.d.ts +16 -0
  103. package/dist/services/InitializerUpdater.d.ts.map +1 -0
  104. package/dist/services/InitializerUpdater.js +37 -0
  105. package/dist/services/IntentAuditor.d.ts +39 -0
  106. package/dist/services/IntentAuditor.d.ts.map +1 -0
  107. package/dist/services/IntentAuditor.js +302 -0
  108. package/dist/services/LLMService.d.ts +100 -0
  109. package/dist/services/LLMService.d.ts.map +1 -0
  110. package/dist/services/LLMService.js +439 -0
  111. package/dist/services/SafetyGuard.d.ts +65 -0
  112. package/dist/services/SafetyGuard.d.ts.map +1 -0
  113. package/dist/services/SafetyGuard.js +524 -0
  114. package/dist/services/SnapshotService.d.ts +11 -0
  115. package/dist/services/SnapshotService.d.ts.map +1 -0
  116. package/dist/services/SnapshotService.js +349 -0
  117. package/dist/services/SourceLinkService.d.ts +26 -0
  118. package/dist/services/SourceLinkService.d.ts.map +1 -0
  119. package/dist/services/SourceLinkService.js +156 -0
  120. package/dist/services/SourceUpdater.d.ts +45 -0
  121. package/dist/services/SourceUpdater.d.ts.map +1 -0
  122. package/dist/services/SourceUpdater.js +1021 -0
  123. package/dist/services/TemplateDiffService.d.ts +25 -0
  124. package/dist/services/TemplateDiffService.d.ts.map +1 -0
  125. package/dist/services/TemplateDiffService.js +331 -0
  126. package/dist/services/types.d.ts +59 -0
  127. package/dist/services/types.d.ts.map +1 -0
  128. package/dist/services/types.js +2 -0
  129. package/dist/storage/SnapshotManager.d.ts +5 -0
  130. package/dist/storage/SnapshotManager.d.ts.map +1 -0
  131. package/dist/storage/SnapshotManager.js +31 -0
  132. package/dist/types/index.d.ts +95 -0
  133. package/dist/types/index.d.ts.map +1 -0
  134. package/dist/types/index.js +7 -0
  135. package/dist/utils/DOMUtils.d.ts +33 -0
  136. package/dist/utils/DOMUtils.d.ts.map +1 -0
  137. package/dist/utils/DOMUtils.js +179 -0
  138. package/dist/utils/StackUtils.d.ts +11 -0
  139. package/dist/utils/StackUtils.d.ts.map +1 -0
  140. package/dist/utils/StackUtils.js +120 -0
  141. package/dist/vendor/enquirer.d.ts +33 -0
  142. package/dist/vendor/enquirer.d.ts.map +1 -0
  143. package/dist/vendor/enquirer.js +11 -0
  144. package/package.json +67 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerStatus = registerStatus;
4
+ const ConfigLoader_js_1 = require("../../config/ConfigLoader.js");
5
+ const DnaIndexService_js_1 = require("../../services/DnaIndexService.js");
6
+ const HealthReportService_js_1 = require("../../services/HealthReportService.js");
7
+ const ProgressReporter_js_1 = require("../ui/ProgressReporter.js");
8
+ // Compact JSON shape for CI/CD consumers — avoids serialising full DnaRecord arrays.
9
+ function toJsonOutput(report) {
10
+ const { total, orphaned, recentlyHealed, neverHealed, topHealedFiles } = report;
11
+ const brokenTotal = orphaned.length + report.unverifiedHeals.length;
12
+ const brokenRatio = total > 0 ? parseFloat(((brokenTotal / total) * 100).toFixed(2)) : 0;
13
+ return {
14
+ generatedAt: report.generatedAt,
15
+ snapshotDir: report.snapshotDir,
16
+ stats: {
17
+ total,
18
+ orphaned: orphaned.length,
19
+ unverifiedHeals: report.unverifiedHeals.length,
20
+ healedLast7Days: recentlyHealed.length,
21
+ healedAllTime: total - neverHealed.length,
22
+ neverHealed: neverHealed.length,
23
+ brokenRatioPct: brokenRatio,
24
+ },
25
+ orphanedKeys: orphaned.map((r) => r.key),
26
+ unverifiedKeys: report.unverifiedHeals.map((r) => r.key),
27
+ topHealedFiles: topHealedFiles.slice(0, 10),
28
+ };
29
+ }
30
+ function registerStatus(program) {
31
+ program
32
+ .command('status')
33
+ .description('Show ecosystem health report')
34
+ .option('--json', 'Emit raw JSON instead of formatted output')
35
+ .option('--dir <path>', 'Override snapshot directory')
36
+ .action(async (opts) => {
37
+ const config = ConfigLoader_js_1.ConfigLoader.getInstance();
38
+ const snapshotDir = opts.dir ?? config.dnaStoragePath;
39
+ const progress = new ProgressReporter_js_1.ProgressReporter(opts.json);
40
+ const dnaIndex = new DnaIndexService_js_1.DnaIndexService();
41
+ const index = await progress.run('Scanning DNA snapshots…', () => dnaIndex.buildIndex(snapshotDir));
42
+ const healthSvc = new HealthReportService_js_1.HealthReportService();
43
+ const report = await progress.run('Generating health report…', async () => healthSvc.generate(index));
44
+ if (opts.json) {
45
+ process.stdout.write(JSON.stringify(toJsonOutput(report), null, 2) + '\n');
46
+ }
47
+ else {
48
+ process.stdout.write(healthSvc.format(report));
49
+ }
50
+ });
51
+ }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerSyncSource(dna: Command): void;
3
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBzC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CA+HrD"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerSyncSource = registerSyncSource;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const ConfigLoader_js_1 = require("../../config/ConfigLoader.js");
10
+ const DnaIndexService_js_1 = require("../../services/DnaIndexService.js");
11
+ const SourceLinkService_js_1 = require("../../services/SourceLinkService.js");
12
+ const ProgressReporter_js_1 = require("../ui/ProgressReporter.js");
13
+ function registerSyncSource(dna) {
14
+ dna
15
+ .command('sync-source <key>')
16
+ .description('Write current DNA selector back to .spec.ts via AST')
17
+ .option('--locator-index <n>', 'Which locator on the line (0-based)', '0')
18
+ .option('--dry-run', 'Preview without writing')
19
+ .option('--json', 'Emit JSON result')
20
+ .option('--dir <path>', 'Override snapshot directory')
21
+ .action(async (key, opts) => {
22
+ const config = ConfigLoader_js_1.ConfigLoader.getInstance();
23
+ const snapshotDir = opts.dir ?? config.dnaStoragePath;
24
+ const locatorIndex = Math.max(0, parseInt(opts.locatorIndex, 10) || 0);
25
+ const progress = new ProgressReporter_js_1.ProgressReporter(opts.json);
26
+ const dnaIndex = new DnaIndexService_js_1.DnaIndexService();
27
+ await progress.run('Scanning DNA snapshots…', () => dnaIndex.buildIndex(snapshotDir));
28
+ const record = dnaIndex.getByKey(key);
29
+ if (!record) {
30
+ if (opts.json) {
31
+ process.stdout.write(JSON.stringify({ success: false, reason: `DNA not found: ${key}` }, null, 2) + '\n');
32
+ process.exit(3);
33
+ }
34
+ const err = new Error(`DNA not found: ${key}`);
35
+ err.code = 'DNA_NOT_FOUND';
36
+ throw err;
37
+ }
38
+ if (!record.sourceFile || record.sourceLine <= 0) {
39
+ if (opts.json) {
40
+ process.stdout.write(JSON.stringify({ success: false, reason: `DNA "${key}" has no sourceFile/sourceLine` }, null, 2) + '\n');
41
+ }
42
+ else {
43
+ process.stdout.write(chalk_1.default.yellow(` ⚠ DNA "${key}" has no sourceFile/sourceLine — cannot sync.\n`));
44
+ }
45
+ return;
46
+ }
47
+ const sourceLink = new SourceLinkService_js_1.SourceLinkService();
48
+ const locators = await progress.run('Analyzing AST for locator update…', async () => sourceLink.enumerateLocatorsOnLine(record.sourceFile, record.sourceLine));
49
+ const target = locators[locatorIndex] ?? locators[0];
50
+ const relPath = path_1.default.relative(process.cwd(), record.sourceFile);
51
+ if (!opts.json) {
52
+ process.stdout.write('\n');
53
+ process.stdout.write(` ${chalk_1.default.bold('DNA selector:')} ${chalk_1.default.green(record.selector)}\n`);
54
+ process.stdout.write(` ${chalk_1.default.bold('Source file:')} ${relPath}:${record.sourceLine}\n`);
55
+ }
56
+ if (!target) {
57
+ if (opts.json) {
58
+ process.stdout.write(JSON.stringify({ success: false, reason: `No locator at index ${locatorIndex} on line ${record.sourceLine}` }, null, 2) + '\n');
59
+ }
60
+ else {
61
+ process.stdout.write(chalk_1.default.yellow(` ⚠ No locator found at index ${locatorIndex} on line ${record.sourceLine}.\n\n`));
62
+ }
63
+ return;
64
+ }
65
+ if (!opts.json) {
66
+ process.stdout.write(` ${chalk_1.default.bold('Locator found:')} [${locatorIndex}] ${chalk_1.default.yellow(target.preview)}\n`);
67
+ process.stdout.write(` ${chalk_1.default.bold('Current value:')} ${chalk_1.default.red(target.selector)}\n`);
68
+ process.stdout.write(` ${chalk_1.default.bold('Will become:')} ${chalk_1.default.green(record.selector)}\n\n`);
69
+ }
70
+ if (target.selector === record.selector) {
71
+ if (opts.json) {
72
+ process.stdout.write(JSON.stringify({ success: true, reason: 'Already in sync — nothing to do' }, null, 2) + '\n');
73
+ }
74
+ else {
75
+ process.stdout.write(chalk_1.default.dim(' Source already matches DNA selector. Nothing to do.\n\n'));
76
+ }
77
+ return;
78
+ }
79
+ if (opts.dryRun) {
80
+ if (opts.json) {
81
+ process.stdout.write(JSON.stringify({
82
+ dryRun: true,
83
+ key,
84
+ sourceFile: record.sourceFile,
85
+ sourceLine: record.sourceLine,
86
+ locatorIndex,
87
+ oldSelector: target.selector,
88
+ newSelector: record.selector,
89
+ }, null, 2) + '\n');
90
+ }
91
+ else {
92
+ process.stdout.write(chalk_1.default.dim(' [dry-run] No files written.\n\n'));
93
+ }
94
+ return;
95
+ }
96
+ const patch = {
97
+ key,
98
+ field: 'selector',
99
+ oldValue: target.selector,
100
+ newValue: record.selector,
101
+ applySourceUpdate: true,
102
+ locatorIndex,
103
+ };
104
+ const result = await progress.run('Applying AST source update…', () => sourceLink.applySourceUpdate(record, patch));
105
+ if (opts.json) {
106
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
107
+ if (!result.success)
108
+ process.exit(5);
109
+ }
110
+ else {
111
+ if (result.success) {
112
+ const lineInfo = result.lineUpdated ? ` (line ${result.lineUpdated})` : '';
113
+ process.stdout.write(` ${chalk_1.default.green('✓')} Source updated${lineInfo}\n\n`);
114
+ }
115
+ else {
116
+ process.stdout.write(` ${chalk_1.default.red('✗')} Source update failed: ${result.reason}\n\n`);
117
+ const err = new Error(result.reason);
118
+ err.code = 'AST_ERROR';
119
+ throw err;
120
+ }
121
+ }
122
+ });
123
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commander_1 = require("commander");
4
+ const ErrorHandler_js_1 = require("./ErrorHandler.js");
5
+ const init_js_1 = require("./commands/init.js");
6
+ const status_js_1 = require("./commands/status.js");
7
+ const list_js_1 = require("./commands/list.js");
8
+ const find_js_1 = require("./commands/find.js");
9
+ const refactor_js_1 = require("./commands/refactor.js");
10
+ const bulk_js_1 = require("./commands/bulk.js");
11
+ const sync_js_1 = require("./commands/sync.js");
12
+ (0, ErrorHandler_js_1.registerGlobalHandlers)();
13
+ // Diagnostic console.log from services (ConfigLoader etc.) → stderr so stdout stays pipe-clean
14
+ console.log = (...args) => process.stderr.write(args.map(String).join(' ') + '\n');
15
+ const program = new commander_1.Command();
16
+ program
17
+ .name('sela')
18
+ .description('Sela CLI — proactive DNA management for Fixwright')
19
+ .version('1.0.0')
20
+ .exitOverride(ErrorHandler_js_1.handleError)
21
+ .configureOutput({ outputError: () => { } });
22
+ // ── sela init ────────────────────────────────────────────────────────────────
23
+ (0, init_js_1.registerInit)(program);
24
+ // ── sela status (T-06) ────────────────────────────────────────────────────────
25
+ (0, status_js_1.registerStatus)(program);
26
+ // ── sela list (T-07) ─────────────────────────────────────────────────────────
27
+ (0, list_js_1.registerList)(program);
28
+ // ── sela dna <subcommand> ─────────────────────────────────────────────────────
29
+ const dna = new commander_1.Command('dna')
30
+ .description('DNA management commands')
31
+ .exitOverride(ErrorHandler_js_1.handleError)
32
+ .configureOutput({ outputError: () => { } });
33
+ // ── sela dna find (T-08) ─────────────────────────────────────────────────────
34
+ (0, find_js_1.registerFind)(dna);
35
+ // ── sela dna refactor (T-12/T-13) ────────────────────────────────────────────
36
+ (0, refactor_js_1.registerRefactor)(dna);
37
+ // ── sela dna bulk-update (T-14) ───────────────────────────────────────────────
38
+ (0, bulk_js_1.registerBulkUpdate)(dna);
39
+ // ── sela dna sync-source (T-15) ───────────────────────────────────────────────
40
+ (0, sync_js_1.registerSyncSource)(dna);
41
+ program.addCommand(dna);
42
+ program.parseAsync(process.argv).catch(ErrorHandler_js_1.handleError);
@@ -0,0 +1,3 @@
1
+ import type { DnaRecord } from '../../services/types.js';
2
+ export declare function renderTable(records: DnaRecord[]): string;
3
+ //# sourceMappingURL=DnaTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DnaTable.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/DnaTable.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAuCzD,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAoBxD"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderTable = renderTable;
7
+ const cli_table3_1 = __importDefault(require("cli-table3"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const path_1 = __importDefault(require("path"));
10
+ // Truncate before chalk so ANSI codes don't corrupt visual width calculations.
11
+ function trunc(s, maxLen, fallback = '—') {
12
+ if (s == null || s.trim() === '')
13
+ return chalk_1.default.dim(fallback);
14
+ return s.length <= maxLen ? s : s.slice(0, maxLen - 1) + '…';
15
+ }
16
+ function relativeTime(iso) {
17
+ if (!iso)
18
+ return chalk_1.default.dim('never');
19
+ const d = Math.floor((Date.now() - new Date(iso).getTime()) / 86_400_000);
20
+ if (d === 0)
21
+ return chalk_1.default.green('today');
22
+ if (d < 7)
23
+ return `${d}d ago`;
24
+ if (d < 30)
25
+ return `${Math.floor(d / 7)}w ago`;
26
+ return `${Math.floor(d / 30)}mo ago`;
27
+ }
28
+ function statusBadge(r) {
29
+ if (r.isOrphaned)
30
+ return chalk_1.default.red('orphaned');
31
+ if (r.status === 'healed')
32
+ return chalk_1.default.yellow('⚠ unverified');
33
+ if (r.status === 'broken')
34
+ return chalk_1.default.red('broken');
35
+ if (r.lastHealed !== null)
36
+ return chalk_1.default.green('healed');
37
+ return chalk_1.default.cyan('active');
38
+ }
39
+ function sourceCell(r) {
40
+ if (!r.sourceFile)
41
+ return chalk_1.default.dim('—');
42
+ const rel = path_1.default.relative(process.cwd(), r.sourceFile);
43
+ const display = rel.length < r.sourceFile.length ? rel : r.sourceFile;
44
+ const suffix = r.sourceLine > 0 ? `:${r.sourceLine}` : '';
45
+ return trunc(display + suffix, 32);
46
+ }
47
+ // colWidths = content + 2 (1-space padding each side)
48
+ const COLS = {
49
+ head: ['Key', 'Test Title', 'Source : Line', 'Selector', 'Last Healed', 'Status'],
50
+ colWidths: [11, 24, 36, 44, 13, 11],
51
+ };
52
+ function renderTable(records) {
53
+ const table = new cli_table3_1.default({
54
+ head: COLS.head.map((h) => chalk_1.default.bold(h)),
55
+ colWidths: COLS.colWidths,
56
+ wordWrap: false,
57
+ style: { head: [], border: ['dim'] },
58
+ });
59
+ for (const r of records) {
60
+ table.push([
61
+ chalk_1.default.dim(r.key.slice(0, 9)),
62
+ trunc(r.testTitle, 22),
63
+ sourceCell(r),
64
+ chalk_1.default.yellow(trunc(r.selector, 42)),
65
+ relativeTime(r.lastHealed),
66
+ statusBadge(r),
67
+ ]);
68
+ }
69
+ return table.toString();
70
+ }
@@ -0,0 +1,8 @@
1
+ import type { LocatorEnumeration } from '../../services/SourceLinkService.js';
2
+ /**
3
+ * Presents an interactive list when a source line contains multiple locators.
4
+ * Returns the 0-based index of the user's selection.
5
+ * Pre-selects the entry whose selector matches currentSelector (normalized comparison).
6
+ */
7
+ export declare function pickLocator(locators: LocatorEnumeration[], currentSelector: string): Promise<number>;
8
+ //# sourceMappingURL=LocatorPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocatorPicker.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/LocatorPicker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAE9E;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,CAAC,CAsBjB"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pickLocator = pickLocator;
7
+ const enquirer_js_1 = require("../../vendor/enquirer.js");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ /**
10
+ * Presents an interactive list when a source line contains multiple locators.
11
+ * Returns the 0-based index of the user's selection.
12
+ * Pre-selects the entry whose selector matches currentSelector (normalized comparison).
13
+ */
14
+ async function pickLocator(locators, currentSelector) {
15
+ const norm = currentSelector.trim();
16
+ const defaultIdx = locators.findIndex((l) => l.selector.trim() === norm);
17
+ const choices = locators.map((l) => {
18
+ const isCurrent = l.selector.trim() === norm;
19
+ const hint = isCurrent ? chalk_1.default.dim(' ← current DNA selector') : '';
20
+ return {
21
+ name: String(l.index),
22
+ message: `[${l.index}] ${chalk_1.default.yellow(l.preview)}${hint}`,
23
+ };
24
+ });
25
+ const prompt = new enquirer_js_1.Select({
26
+ name: 'locatorIndex',
27
+ message: `Line has ${locators.length} locators. Which are you refactoring?`,
28
+ choices,
29
+ initial: defaultIdx >= 0 ? defaultIdx : 0,
30
+ });
31
+ const result = (await prompt.run());
32
+ return parseInt(result, 10);
33
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Wraps ora spinners. Pass silent=true (e.g. when --json active) to skip all
3
+ * spinner output and run the task directly. All spinner output goes to stderr
4
+ * so stdout stays pipe-clean.
5
+ */
6
+ export declare class ProgressReporter {
7
+ private silent;
8
+ constructor(silent?: boolean);
9
+ run<T>(label: string, fn: () => Promise<T>): Promise<T>;
10
+ }
11
+ //# sourceMappingURL=ProgressReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressReporter.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/ProgressReporter.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAU;gBAEZ,MAAM,UAAQ;IAIpB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAY9D"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ProgressReporter = void 0;
7
+ const ora_1 = __importDefault(require("ora"));
8
+ /**
9
+ * Wraps ora spinners. Pass silent=true (e.g. when --json active) to skip all
10
+ * spinner output and run the task directly. All spinner output goes to stderr
11
+ * so stdout stays pipe-clean.
12
+ */
13
+ class ProgressReporter {
14
+ silent;
15
+ constructor(silent = false) {
16
+ this.silent = silent;
17
+ }
18
+ async run(label, fn) {
19
+ if (this.silent)
20
+ return fn();
21
+ const spinner = (0, ora_1.default)({ text: label, stream: process.stderr }).start();
22
+ try {
23
+ const result = await fn();
24
+ spinner.succeed();
25
+ return result;
26
+ }
27
+ catch (err) {
28
+ spinner.fail();
29
+ throw err;
30
+ }
31
+ }
32
+ }
33
+ exports.ProgressReporter = ProgressReporter;
@@ -0,0 +1,26 @@
1
+ import type { IDnaIndexService } from '../../services/DnaIndexService.js';
2
+ import type { IDnaEditorService } from '../../services/DnaEditorService.js';
3
+ import type { ISourceLinkService } from '../../services/SourceLinkService.js';
4
+ export interface WizardOptions {
5
+ noSource?: boolean;
6
+ dryRun?: boolean;
7
+ }
8
+ interface WizardServices {
9
+ dnaIndex: IDnaIndexService;
10
+ dnaEditor: IDnaEditorService;
11
+ sourceLink: ISourceLinkService;
12
+ }
13
+ export declare class RefactorWizard {
14
+ private readonly svc;
15
+ private readonly opts;
16
+ constructor(svc: WizardServices, opts?: WizardOptions);
17
+ run(initialKey?: string): Promise<void>;
18
+ private resolveKey;
19
+ private selectDna;
20
+ private selectField;
21
+ private editValue;
22
+ private confirm;
23
+ private buildDnaPatch;
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=RefactorWizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RefactorWizard.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/RefactorWizard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAuB,MAAM,oCAAoC,CAAC;AACjG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAM9E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,cAAc;IACtB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAwFD,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,GAAG,EAAE,cAAc,EACnB,IAAI,GAAE,aAAkB;IAGrC,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4G7C,OAAO,CAAC,UAAU;YAUJ,SAAS;YAwBT,WAAW;YAgBX,SAAS;YAyBT,OAAO;IAKrB,OAAO,CAAC,aAAa;CAGtB"}