sovr-patch 0.2.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.

Potentially problematic release.


This version of sovr-patch might be problematic. Click here for more details.

Files changed (102) hide show
  1. package/LICENSE +66 -0
  2. package/README.md +112 -0
  3. package/dist/audit/engine.js +140 -0
  4. package/dist/audit/engine.js.map +1 -0
  5. package/dist/audit/packs.js +21 -0
  6. package/dist/audit/packs.js.map +1 -0
  7. package/dist/audit/report.js +79 -0
  8. package/dist/audit/report.js.map +1 -0
  9. package/dist/audit/types.js +5 -0
  10. package/dist/audit/types.js.map +1 -0
  11. package/dist/cli/help.js +108 -0
  12. package/dist/cli/help.js.map +1 -0
  13. package/dist/cli/parse-argv.js +73 -0
  14. package/dist/cli/parse-argv.js.map +1 -0
  15. package/dist/commands/activate.js +179 -0
  16. package/dist/commands/activate.js.map +1 -0
  17. package/dist/commands/audit.js +89 -0
  18. package/dist/commands/audit.js.map +1 -0
  19. package/dist/commands/ci-gate.js +239 -0
  20. package/dist/commands/ci-gate.js.map +1 -0
  21. package/dist/commands/list-rules.js +11 -0
  22. package/dist/commands/list-rules.js.map +1 -0
  23. package/dist/commands/run.js +107 -0
  24. package/dist/commands/run.js.map +1 -0
  25. package/dist/commands/status.js +174 -0
  26. package/dist/commands/status.js.map +1 -0
  27. package/dist/core/engine.js +68 -0
  28. package/dist/core/engine.js.map +1 -0
  29. package/dist/core/license.js +243 -0
  30. package/dist/core/license.js.map +1 -0
  31. package/dist/core/load-project.js +41 -0
  32. package/dist/core/load-project.js.map +1 -0
  33. package/dist/core/report.js +68 -0
  34. package/dist/core/report.js.map +1 -0
  35. package/dist/core/rollback.js +160 -0
  36. package/dist/core/rollback.js.map +1 -0
  37. package/dist/core/safe-apply.js +75 -0
  38. package/dist/core/safe-apply.js.map +1 -0
  39. package/dist/core/types.js +3 -0
  40. package/dist/core/types.js.map +1 -0
  41. package/dist/core/update-check.js +162 -0
  42. package/dist/core/update-check.js.map +1 -0
  43. package/dist/core/verify.js +32 -0
  44. package/dist/core/verify.js.map +1 -0
  45. package/dist/index.js +124 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/patch/apply.js +14 -0
  48. package/dist/patch/apply.js.map +1 -0
  49. package/dist/patch/overlap.js +12 -0
  50. package/dist/patch/overlap.js.map +1 -0
  51. package/dist/patch/preview.js +48 -0
  52. package/dist/patch/preview.js.map +1 -0
  53. package/dist/rules/design-token/classify.js +16 -0
  54. package/dist/rules/design-token/classify.js.map +1 -0
  55. package/dist/rules/design-token/locate.js +113 -0
  56. package/dist/rules/design-token/locate.js.map +1 -0
  57. package/dist/rules/design-token/presets.js +53 -0
  58. package/dist/rules/design-token/presets.js.map +1 -0
  59. package/dist/rules/design-token/rule.js +13 -0
  60. package/dist/rules/design-token/rule.js.map +1 -0
  61. package/dist/rules/design-token/schema.js +84 -0
  62. package/dist/rules/design-token/schema.js.map +1 -0
  63. package/dist/rules/design-token/transform.js +27 -0
  64. package/dist/rules/design-token/transform.js.map +1 -0
  65. package/dist/rules/field-rename/classify.js +77 -0
  66. package/dist/rules/field-rename/classify.js.map +1 -0
  67. package/dist/rules/field-rename/locate.js +294 -0
  68. package/dist/rules/field-rename/locate.js.map +1 -0
  69. package/dist/rules/field-rename/rule.js +13 -0
  70. package/dist/rules/field-rename/rule.js.map +1 -0
  71. package/dist/rules/field-rename/schema.js +35 -0
  72. package/dist/rules/field-rename/schema.js.map +1 -0
  73. package/dist/rules/field-rename/transform.js +160 -0
  74. package/dist/rules/field-rename/transform.js.map +1 -0
  75. package/dist/rules/inline-style/classify.js +17 -0
  76. package/dist/rules/inline-style/classify.js.map +1 -0
  77. package/dist/rules/inline-style/locate.js +163 -0
  78. package/dist/rules/inline-style/locate.js.map +1 -0
  79. package/dist/rules/inline-style/presets.js +71 -0
  80. package/dist/rules/inline-style/presets.js.map +1 -0
  81. package/dist/rules/inline-style/rule.js +13 -0
  82. package/dist/rules/inline-style/rule.js.map +1 -0
  83. package/dist/rules/inline-style/schema.js +97 -0
  84. package/dist/rules/inline-style/schema.js.map +1 -0
  85. package/dist/rules/inline-style/transform.js +52 -0
  86. package/dist/rules/inline-style/transform.js.map +1 -0
  87. package/dist/rules/nullish-fallback/classify.js +22 -0
  88. package/dist/rules/nullish-fallback/classify.js.map +1 -0
  89. package/dist/rules/nullish-fallback/locate.js +175 -0
  90. package/dist/rules/nullish-fallback/locate.js.map +1 -0
  91. package/dist/rules/nullish-fallback/rule.js +13 -0
  92. package/dist/rules/nullish-fallback/rule.js.map +1 -0
  93. package/dist/rules/nullish-fallback/schema.js +10 -0
  94. package/dist/rules/nullish-fallback/schema.js.map +1 -0
  95. package/dist/rules/nullish-fallback/transform.js +49 -0
  96. package/dist/rules/nullish-fallback/transform.js.map +1 -0
  97. package/dist/rules/registry.js +21 -0
  98. package/dist/rules/registry.js.map +1 -0
  99. package/dist/rules/types.js +2 -0
  100. package/dist/rules/types.js.map +1 -0
  101. package/license.json +13 -0
  102. package/package.json +64 -0
@@ -0,0 +1,160 @@
1
+ import { execSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ /**
5
+ * Create a rollback checkpoint before applying patches.
6
+ *
7
+ * Strategy 1 (git-stash): If the repo is a git repo with no uncommitted changes,
8
+ * we use `git stash push` to save the current state. This is the cleanest approach.
9
+ *
10
+ * Strategy 2 (backup-dir): If git is not available or there are uncommitted changes,
11
+ * we copy the affected files to a .sovr-patch-backup/ directory.
12
+ */
13
+ export function createRollbackCheckpoint(repoPath, changedFiles) {
14
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
15
+ // Try git-stash first
16
+ if (isGitRepo(repoPath)) {
17
+ try {
18
+ const stashMessage = `sovr-patch-checkpoint-${timestamp}`;
19
+ // Stage the files that will be changed
20
+ for (const file of changedFiles) {
21
+ const absPath = path.resolve(repoPath, file);
22
+ if (fs.existsSync(absPath)) {
23
+ execSync(`git add "${file}"`, { cwd: repoPath, stdio: "pipe" });
24
+ }
25
+ }
26
+ // Create a stash entry
27
+ const result = execSync(`git stash push -m "${stashMessage}" -- ${changedFiles.map(f => `"${f}"`).join(" ")}`, { cwd: repoPath, stdio: "pipe", encoding: "utf8" });
28
+ // Check if stash was actually created
29
+ if (!result.includes("No local changes")) {
30
+ // Immediately pop the stash to restore working state
31
+ // The stash ref is kept for rollback
32
+ execSync("git stash pop", { cwd: repoPath, stdio: "pipe" });
33
+ return {
34
+ strategy: "git-stash",
35
+ repoPath,
36
+ stashRef: stashMessage,
37
+ changedFiles,
38
+ timestamp,
39
+ };
40
+ }
41
+ }
42
+ catch {
43
+ // Fall through to backup-dir strategy
44
+ }
45
+ }
46
+ // Fallback: backup-dir
47
+ const backupDir = path.join(repoPath, ".sovr-patch-backup", timestamp);
48
+ fs.mkdirSync(backupDir, { recursive: true });
49
+ for (const file of changedFiles) {
50
+ const srcPath = path.resolve(repoPath, file);
51
+ const destPath = path.join(backupDir, file);
52
+ if (fs.existsSync(srcPath)) {
53
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
54
+ fs.copyFileSync(srcPath, destPath);
55
+ }
56
+ }
57
+ // Write metadata
58
+ const meta = {
59
+ timestamp,
60
+ changedFiles,
61
+ strategy: "backup-dir",
62
+ };
63
+ fs.writeFileSync(path.join(backupDir, ".sovr-meta.json"), JSON.stringify(meta, null, 2), "utf8");
64
+ return {
65
+ strategy: "backup-dir",
66
+ repoPath,
67
+ backupDir,
68
+ changedFiles,
69
+ timestamp,
70
+ };
71
+ }
72
+ /**
73
+ * Rollback changes using the handle from createRollbackCheckpoint.
74
+ */
75
+ export function rollback(handle) {
76
+ if (handle.strategy === "backup-dir" && handle.backupDir) {
77
+ if (!fs.existsSync(handle.backupDir)) {
78
+ return { restored: false, message: `Backup directory not found: ${handle.backupDir}` };
79
+ }
80
+ let restoredCount = 0;
81
+ for (const file of handle.changedFiles) {
82
+ const backupPath = path.join(handle.backupDir, file);
83
+ const targetPath = path.resolve(handle.repoPath, file);
84
+ if (fs.existsSync(backupPath)) {
85
+ fs.copyFileSync(backupPath, targetPath);
86
+ restoredCount += 1;
87
+ }
88
+ }
89
+ return {
90
+ restored: true,
91
+ message: `Restored ${restoredCount} files from backup: ${handle.backupDir}`,
92
+ };
93
+ }
94
+ if (handle.strategy === "git-stash") {
95
+ try {
96
+ // For git-stash strategy, we use git checkout to restore the original files
97
+ for (const file of handle.changedFiles) {
98
+ execSync(`git checkout HEAD -- "${file}"`, {
99
+ cwd: handle.repoPath,
100
+ stdio: "pipe",
101
+ });
102
+ }
103
+ return {
104
+ restored: true,
105
+ message: `Restored ${handle.changedFiles.length} files via git checkout`,
106
+ };
107
+ }
108
+ catch (err) {
109
+ return {
110
+ restored: false,
111
+ message: `Git rollback failed: ${err instanceof Error ? err.message : String(err)}`,
112
+ };
113
+ }
114
+ }
115
+ return { restored: false, message: "Unknown rollback strategy" };
116
+ }
117
+ /**
118
+ * List all available backup checkpoints in a repo.
119
+ */
120
+ export function listCheckpoints(repoPath) {
121
+ const backupRoot = path.join(repoPath, ".sovr-patch-backup");
122
+ if (!fs.existsSync(backupRoot)) {
123
+ return [];
124
+ }
125
+ const handles = [];
126
+ for (const entry of fs.readdirSync(backupRoot, { withFileTypes: true })) {
127
+ if (!entry.isDirectory())
128
+ continue;
129
+ const metaPath = path.join(backupRoot, entry.name, ".sovr-meta.json");
130
+ if (!fs.existsSync(metaPath))
131
+ continue;
132
+ try {
133
+ const meta = JSON.parse(fs.readFileSync(metaPath, "utf8"));
134
+ handles.push({
135
+ strategy: "backup-dir",
136
+ repoPath,
137
+ backupDir: path.join(backupRoot, entry.name),
138
+ changedFiles: meta.changedFiles ?? [],
139
+ timestamp: meta.timestamp ?? entry.name,
140
+ });
141
+ }
142
+ catch {
143
+ // Skip malformed metadata
144
+ }
145
+ }
146
+ return handles.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
147
+ }
148
+ function isGitRepo(repoPath) {
149
+ try {
150
+ execSync("git rev-parse --is-inside-work-tree", {
151
+ cwd: repoPath,
152
+ stdio: "pipe",
153
+ });
154
+ return true;
155
+ }
156
+ catch {
157
+ return false;
158
+ }
159
+ }
160
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/core/rollback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { previewPatchedFiles, buildDiffFromPreview } from "../patch/preview.js";
5
+ import { writePreviewToRepo } from "../patch/apply.js";
6
+ import { verifyRepoWithTsc } from "./verify.js";
7
+ function copyDirRecursive(src, dest) {
8
+ fs.mkdirSync(dest, { recursive: true });
9
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
10
+ const srcPath = path.join(src, entry.name);
11
+ const destPath = path.join(dest, entry.name);
12
+ if (entry.isDirectory()) {
13
+ if (entry.name === ".git")
14
+ continue;
15
+ if (entry.name === "node_modules")
16
+ continue;
17
+ copyDirRecursive(srcPath, destPath);
18
+ continue;
19
+ }
20
+ fs.copyFileSync(srcPath, destPath);
21
+ }
22
+ }
23
+ function writePreviewToTempRepo(tempRepoPath, previewMap) {
24
+ for (const [relativeFilePath, preview] of previewMap.entries()) {
25
+ if (preview.before === preview.after)
26
+ continue;
27
+ const absoluteFilePath = path.resolve(tempRepoPath, relativeFilePath);
28
+ fs.mkdirSync(path.dirname(absoluteFilePath), { recursive: true });
29
+ fs.writeFileSync(absoluteFilePath, preview.after, "utf8");
30
+ }
31
+ }
32
+ export function safeApplyWithVerify(loaded, patches) {
33
+ const previewMap = previewPatchedFiles(loaded, patches);
34
+ const summary = buildDiffFromPreview(previewMap);
35
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "sovr-patch-"));
36
+ const tempRepoPath = path.join(tempRoot, "repo");
37
+ copyDirRecursive(loaded.repoPath, tempRepoPath);
38
+ // Symlink node_modules into temp repo so tsc can resolve all types
39
+ const realNodeModules = path.resolve(loaded.repoPath, "node_modules");
40
+ const tempNodeModules = path.join(tempRepoPath, "node_modules");
41
+ if (fs.existsSync(realNodeModules)) {
42
+ fs.symlinkSync(realNodeModules, tempNodeModules, "dir");
43
+ }
44
+ const relativeTsconfig = path.relative(loaded.repoPath, loaded.tsconfigPath);
45
+ const tempTsconfigPath = path.resolve(tempRepoPath, relativeTsconfig);
46
+ writePreviewToTempRepo(tempRepoPath, previewMap);
47
+ /**
48
+ * Key design:
49
+ * tsc binary comes from temp repo's symlinked node_modules/.bin/tsc,
50
+ * tsconfig points to temp directory.
51
+ * node_modules shared via symlink, not copied.
52
+ */
53
+ const verify = verifyRepoWithTsc({
54
+ repoPath: tempRepoPath,
55
+ tsconfigPath: tempTsconfigPath,
56
+ });
57
+ if (!verify.passed) {
58
+ return {
59
+ applied: false,
60
+ changedFiles: summary.changedFiles,
61
+ diffText: summary.diffText,
62
+ verify,
63
+ tempRepoPath,
64
+ };
65
+ }
66
+ const changedFiles = writePreviewToRepo(loaded, previewMap);
67
+ return {
68
+ applied: true,
69
+ changedFiles,
70
+ diffText: summary.diffText,
71
+ verify,
72
+ tempRepoPath,
73
+ };
74
+ }
75
+ //# sourceMappingURL=safe-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-apply.js","sourceRoot":"","sources":["../../src/core/safe-apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ // ─── Severity / Classification ─────────────────────────────────
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,kEAAkE"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * SOVR Patch — Auto-Update Check
3
+ *
4
+ * Checks npm registry for newer versions and prompts the user.
5
+ * Non-blocking: runs after command execution, cached for 24h.
6
+ * No telemetry. No data sent. Just a GET to registry.npmjs.org.
7
+ *
8
+ * Disable: set SOVR_NO_UPDATE_CHECK=1
9
+ * Cache: ~/.sovr-patch/.update-check
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import os from "node:os";
14
+ import https from "node:https";
15
+ // ─── Config ────────────────────────────────────────────────────
16
+ const PACKAGE_NAME = "sovr-patch";
17
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
18
+ const REQUEST_TIMEOUT_MS = 3000; // 3 seconds — never block the user
19
+ // ─── Paths ─────────────────────────────────────────────────────
20
+ function getCachePath() {
21
+ return path.join(os.homedir(), ".sovr-patch", ".update-check");
22
+ }
23
+ function getCurrentVersion() {
24
+ // Read from package.json at build time — this gets inlined by esbuild
25
+ // Fallback: read from the installed package
26
+ try {
27
+ const pkgPath = path.resolve(__dirname, "..", "package.json");
28
+ if (fs.existsSync(pkgPath)) {
29
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
30
+ return pkg.version ?? "0.0.0";
31
+ }
32
+ }
33
+ catch {
34
+ // ignore
35
+ }
36
+ // Fallback: try reading from the source root
37
+ try {
38
+ const srcPkgPath = path.resolve(__dirname, "..", "..", "package.json");
39
+ if (fs.existsSync(srcPkgPath)) {
40
+ const pkg = JSON.parse(fs.readFileSync(srcPkgPath, "utf-8"));
41
+ return pkg.version ?? "0.0.0";
42
+ }
43
+ }
44
+ catch {
45
+ // ignore
46
+ }
47
+ return "0.0.0";
48
+ }
49
+ // ─── Semver comparison (simple: major.minor.patch) ─────────────
50
+ function isNewer(latest, current) {
51
+ const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
52
+ const [lMaj, lMin, lPat] = parse(latest);
53
+ const [cMaj, cMin, cPat] = parse(current);
54
+ if (lMaj !== cMaj)
55
+ return lMaj > cMaj;
56
+ if (lMin !== cMin)
57
+ return lMin > cMin;
58
+ return lPat > cPat;
59
+ }
60
+ // ─── Read/write cache ──────────────────────────────────────────
61
+ function readCache() {
62
+ try {
63
+ const cachePath = getCachePath();
64
+ if (!fs.existsSync(cachePath))
65
+ return null;
66
+ const raw = fs.readFileSync(cachePath, "utf-8");
67
+ return JSON.parse(raw);
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ function writeCache(cache) {
74
+ try {
75
+ const cachePath = getCachePath();
76
+ const dir = path.dirname(cachePath);
77
+ if (!fs.existsSync(dir)) {
78
+ fs.mkdirSync(dir, { recursive: true });
79
+ }
80
+ fs.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
81
+ }
82
+ catch {
83
+ // Non-critical — silently ignore
84
+ }
85
+ }
86
+ // ─── Fetch latest version from npm ─────────────────────────────
87
+ function fetchLatestVersion() {
88
+ return new Promise((resolve) => {
89
+ const req = https.get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: REQUEST_TIMEOUT_MS }, (res) => {
90
+ if (res.statusCode !== 200) {
91
+ resolve(null);
92
+ return;
93
+ }
94
+ let data = "";
95
+ res.on("data", (chunk) => {
96
+ data += chunk.toString();
97
+ });
98
+ res.on("end", () => {
99
+ try {
100
+ const parsed = JSON.parse(data);
101
+ resolve(parsed.version ?? null);
102
+ }
103
+ catch {
104
+ resolve(null);
105
+ }
106
+ });
107
+ });
108
+ req.on("error", () => resolve(null));
109
+ req.on("timeout", () => {
110
+ req.destroy();
111
+ resolve(null);
112
+ });
113
+ });
114
+ }
115
+ // ─── Main: check for updates (non-blocking) ────────────────────
116
+ export async function checkForUpdates() {
117
+ // Respect opt-out
118
+ if (process.env.SOVR_NO_UPDATE_CHECK === "1")
119
+ return;
120
+ const currentVersion = getCurrentVersion();
121
+ if (currentVersion === "0.0.0")
122
+ return; // dev mode, skip
123
+ // Check cache — only hit npm once per 24h
124
+ const cache = readCache();
125
+ if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
126
+ // Use cached result
127
+ if (isNewer(cache.latestVersion, currentVersion)) {
128
+ printUpdateNotice(currentVersion, cache.latestVersion);
129
+ }
130
+ return;
131
+ }
132
+ // Fetch from npm (async, non-blocking)
133
+ const latestVersion = await fetchLatestVersion();
134
+ if (!latestVersion)
135
+ return; // Network error — silently skip
136
+ // Update cache
137
+ writeCache({ lastCheck: Date.now(), latestVersion });
138
+ // Compare
139
+ if (isNewer(latestVersion, currentVersion)) {
140
+ printUpdateNotice(currentVersion, latestVersion);
141
+ }
142
+ }
143
+ // ─── Print the update notice ───────────────────────────────────
144
+ function printUpdateNotice(current, latest) {
145
+ const border = "─".repeat(52);
146
+ console.log("");
147
+ console.log(` \x1b[33m╭${border}╮\x1b[0m`);
148
+ console.log(` \x1b[33m│\x1b[0m \x1b[33m│\x1b[0m`);
149
+ console.log(` \x1b[33m│\x1b[0m Update available: \x1b[31m${current}\x1b[0m → \x1b[32m${latest}\x1b[0m${" ".repeat(Math.max(0, 24 - current.length - latest.length))}\x1b[33m│\x1b[0m`);
150
+ console.log(` \x1b[33m│\x1b[0m \x1b[33m│\x1b[0m`);
151
+ console.log(` \x1b[33m│\x1b[0m Run: \x1b[36mnpm install -g sovr-patch\x1b[0m \x1b[33m│\x1b[0m`);
152
+ console.log(` \x1b[33m│\x1b[0m Or: \x1b[36mnpx sovr-patch@latest\x1b[0m \x1b[33m│\x1b[0m`);
153
+ console.log(` \x1b[33m│\x1b[0m \x1b[33m│\x1b[0m`);
154
+ console.log(` \x1b[33m│\x1b[0m Changelog: \x1b[4mhttps://sovr.app/patch/changelog\x1b[0m \x1b[33m│\x1b[0m`);
155
+ console.log(` \x1b[33m│\x1b[0m Disable: SOVR_NO_UPDATE_CHECK=1 \x1b[33m│\x1b[0m`);
156
+ console.log(` \x1b[33m│\x1b[0m \x1b[33m│\x1b[0m`);
157
+ console.log(` \x1b[33m╰${border}╯\x1b[0m`);
158
+ console.log("");
159
+ }
160
+ // ─── Export for testing ────────────────────────────────────────
161
+ export { getCurrentVersion, isNewer, fetchLatestVersion };
162
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/core/update-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import path from "node:path";
2
+ import { spawnSync } from "node:child_process";
3
+ function resolveTscBin(repoPath) {
4
+ if (process.platform === "win32") {
5
+ return path.resolve(repoPath, "node_modules", ".bin", "tsc.cmd");
6
+ }
7
+ return path.resolve(repoPath, "node_modules", ".bin", "tsc");
8
+ }
9
+ export function verifyRepoWithTsc(params) {
10
+ const localTsc = resolveTscBin(params.repoPath);
11
+ const bin = localTsc;
12
+ const args = ["--noEmit", "-p", params.tsconfigPath];
13
+ const result = spawnSync(bin, args, {
14
+ cwd: params.repoPath,
15
+ encoding: "utf8",
16
+ shell: false,
17
+ });
18
+ return {
19
+ passed: result.status === 0,
20
+ exitCode: result.status ?? 1,
21
+ stdout: result.stdout ?? "",
22
+ stderr: result.stderr ?? "",
23
+ command: [bin, ...args].join(" "),
24
+ };
25
+ }
26
+ export function verifyWithTsc(loaded) {
27
+ return verifyRepoWithTsc({
28
+ repoPath: loaded.repoPath,
29
+ tsconfigPath: loaded.tsconfigPath,
30
+ });
31
+ }
32
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/core/verify.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAGjC;IACC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,QAAQ,CAAC;IACrB,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;QAClC,GAAG,EAAE,MAAM,CAAC,QAAQ;QACpB,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,OAAO,iBAAiB,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;AACL,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { parseCli } from "./cli/parse-argv.js";
5
+ import { printHelp } from "./cli/help.js";
6
+ import { runCommand } from "./commands/run.js";
7
+ import { listRulesCommand } from "./commands/list-rules.js";
8
+ import { ciGateCommand } from "./commands/ci-gate.js";
9
+ import { activateCommand } from "./commands/activate.js";
10
+ import { auditCommand } from "./commands/audit.js";
11
+ import { statusCommand } from "./commands/status.js";
12
+ import { checkForUpdates } from "./core/update-check.js";
13
+ import { listCheckpoints, rollback as executeRollback, } from "./core/rollback.js";
14
+ // ─── Legacy rollback command (kept for backward compat) ─────────
15
+ function runRollback(argv) {
16
+ const repoArg = argv.indexOf("--repo");
17
+ const repoPath = path.resolve(repoArg !== -1 ? (argv[repoArg + 1] ?? ".") : ".");
18
+ const list = argv.includes("--list");
19
+ const json = argv.includes("--json");
20
+ const cpArg = argv.indexOf("--checkpoint");
21
+ const checkpoint = cpArg !== -1 ? argv[cpArg + 1] : undefined;
22
+ if (list) {
23
+ const checkpoints = listCheckpoints(repoPath);
24
+ if (json) {
25
+ console.log(JSON.stringify(checkpoints, null, 2));
26
+ return;
27
+ }
28
+ if (checkpoints.length === 0) {
29
+ console.log("No rollback checkpoints found.");
30
+ return;
31
+ }
32
+ console.log(`Found ${checkpoints.length} checkpoint(s):`);
33
+ console.log("");
34
+ for (const cp of checkpoints) {
35
+ console.log(` ${cp.timestamp} (${cp.strategy}) ${cp.changedFiles.length} files`);
36
+ for (const f of cp.changedFiles) {
37
+ console.log(` - ${f}`);
38
+ }
39
+ console.log("");
40
+ }
41
+ return;
42
+ }
43
+ if (checkpoint) {
44
+ const checkpoints = listCheckpoints(repoPath);
45
+ const target = checkpoints.find((cp) => cp.timestamp === checkpoint);
46
+ if (!target) {
47
+ console.error(`Checkpoint not found: ${checkpoint}`);
48
+ console.error(`Use --list to see available checkpoints.`);
49
+ process.exit(1);
50
+ }
51
+ const result = executeRollback(target);
52
+ if (json) {
53
+ console.log(JSON.stringify(result, null, 2));
54
+ return;
55
+ }
56
+ if (result.restored) {
57
+ console.log(`Rollback successful: ${result.message}`);
58
+ }
59
+ else {
60
+ console.error(`Rollback failed: ${result.message}`);
61
+ process.exit(1);
62
+ }
63
+ return;
64
+ }
65
+ console.error("rollback requires --list or --checkpoint <timestamp>");
66
+ process.exit(1);
67
+ }
68
+ // ─── Main ───────────────────────────────────────────────────────
69
+ async function main() {
70
+ const argv = process.argv;
71
+ // Show help if no args or --help
72
+ if (argv.length <= 2 || argv.includes("--help") || argv.includes("-h")) {
73
+ printHelp();
74
+ return;
75
+ }
76
+ const command = argv[2];
77
+ // Handle activate command
78
+ if (command === "activate") {
79
+ await activateCommand(argv);
80
+ return;
81
+ }
82
+ // Handle status command
83
+ if (command === "status") {
84
+ statusCommand(argv);
85
+ return;
86
+ }
87
+ // Handle audit command
88
+ if (command === "audit") {
89
+ await auditCommand(argv);
90
+ return;
91
+ }
92
+ // Handle ci-gate command (Enterprise)
93
+ if (command === "ci-gate") {
94
+ await ciGateCommand(argv);
95
+ return;
96
+ }
97
+ // Handle rollback separately (legacy)
98
+ if (command === "rollback") {
99
+ runRollback(argv);
100
+ return;
101
+ }
102
+ try {
103
+ const args = parseCli(argv);
104
+ if (args.command === "list-rules") {
105
+ listRulesCommand();
106
+ return;
107
+ }
108
+ if (args.command === "scan" || args.command === "run") {
109
+ await runCommand(args);
110
+ return;
111
+ }
112
+ throw new Error(`unsupported command: "${args.command}". Use --help for usage.`);
113
+ }
114
+ catch (error) {
115
+ const message = error instanceof Error ? error.message : String(error);
116
+ console.error(`Error: ${message}`);
117
+ process.exit(1);
118
+ }
119
+ }
120
+ main().finally(() => {
121
+ // Non-blocking update check — runs after command completes
122
+ checkForUpdates().catch(() => { });
123
+ });
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ export function writePreviewToRepo(loaded, previewMap) {
4
+ const changedFiles = [];
5
+ for (const [filePath, preview] of previewMap.entries()) {
6
+ if (preview.before === preview.after)
7
+ continue;
8
+ const absolute = path.resolve(loaded.repoPath, filePath);
9
+ fs.writeFileSync(absolute, preview.after, "utf8");
10
+ changedFiles.push(filePath);
11
+ }
12
+ return changedFiles;
13
+ }
14
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/patch/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,UAAU,kBAAkB,CAChC,MAAqB,EACrB,UAAoC;IAEpC,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,KAAK;YAAE,SAAS;QAE/C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACzD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAClD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export function detectOverlaps(patches) {
2
+ const sorted = [...patches].sort((a, b) => a.start - b.start);
3
+ for (let i = 1; i < sorted.length; i += 1) {
4
+ const prev = sorted[i - 1];
5
+ const current = sorted[i];
6
+ if (current.start < prev.end) {
7
+ throw new Error(`overlapping patches detected in ${current.filePath}: ` +
8
+ `[${prev.start}, ${prev.end}) overlaps with [${current.start}, ${current.end})`);
9
+ }
10
+ }
11
+ }
12
+ //# sourceMappingURL=overlap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlap.js","sourceRoot":"","sources":["../../src/patch/overlap.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,OAAkB;IAC/C,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,mCAAmC,OAAO,CAAC,QAAQ,IAAI;gBACrD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,oBAAoB,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,GAAG,GAAG,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}