@aspruyt/xfg 3.7.5 → 3.7.7

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 (156) hide show
  1. package/dist/cli/index.d.ts +6 -0
  2. package/dist/cli/index.js +9 -0
  3. package/dist/cli/program.d.ts +2 -0
  4. package/dist/cli/program.js +70 -0
  5. package/dist/cli/settings-command.d.ts +10 -0
  6. package/dist/cli/settings-command.js +228 -0
  7. package/dist/cli/sync-command.d.ts +25 -0
  8. package/dist/cli/sync-command.js +155 -0
  9. package/dist/cli/types.d.ts +45 -0
  10. package/dist/cli/types.js +15 -0
  11. package/dist/cli.js +2 -19
  12. package/dist/{file-reference-resolver.d.ts → config/file-reference-resolver.d.ts} +1 -1
  13. package/dist/config/index.d.ts +7 -0
  14. package/dist/config/index.js +12 -0
  15. package/dist/config/loader.d.ts +9 -0
  16. package/dist/{config.js → config/loader.js} +3 -24
  17. package/dist/{config-normalizer.d.ts → config/normalizer.d.ts} +1 -1
  18. package/dist/{config-normalizer.js → config/normalizer.js} +1 -1
  19. package/dist/{config.d.ts → config/types.d.ts} +5 -9
  20. package/dist/config/types.js +16 -0
  21. package/dist/{config-validator.d.ts → config/validator.d.ts} +5 -5
  22. package/dist/{config-validator.js → config/validator.js} +60 -372
  23. package/dist/config/validators/file-validator.d.ts +22 -0
  24. package/dist/config/validators/file-validator.js +46 -0
  25. package/dist/config/validators/index.d.ts +3 -0
  26. package/dist/config/validators/index.js +6 -0
  27. package/dist/config/validators/repo-settings-validator.d.ts +10 -0
  28. package/dist/config/validators/repo-settings-validator.js +71 -0
  29. package/dist/config/validators/ruleset-validator.d.ts +18 -0
  30. package/dist/config/validators/ruleset-validator.js +201 -0
  31. package/dist/index.d.ts +3 -66
  32. package/dist/index.js +3 -474
  33. package/dist/output/index.d.ts +4 -0
  34. package/dist/output/index.js +8 -0
  35. package/dist/{summary-utils.d.ts → output/summary-utils.d.ts} +3 -3
  36. package/dist/settings/index.d.ts +3 -0
  37. package/dist/settings/index.js +6 -0
  38. package/dist/{repo-settings-diff.d.ts → settings/repo-settings/diff.d.ts} +2 -2
  39. package/dist/{repo-settings-plan-formatter.d.ts → settings/repo-settings/formatter.d.ts} +1 -1
  40. package/dist/{strategies → settings/repo-settings}/github-repo-settings-strategy.d.ts +4 -4
  41. package/dist/{strategies → settings/repo-settings}/github-repo-settings-strategy.js +3 -3
  42. package/dist/settings/repo-settings/index.d.ts +5 -0
  43. package/dist/settings/repo-settings/index.js +10 -0
  44. package/dist/{repo-settings-processor.d.ts → settings/repo-settings/processor.d.ts} +4 -4
  45. package/dist/{repo-settings-processor.js → settings/repo-settings/processor.js} +6 -6
  46. package/dist/{strategies/repo-settings-strategy.d.ts → settings/repo-settings/types.d.ts} +2 -2
  47. package/dist/{resource-converters.d.ts → settings/resource-converters.d.ts} +4 -4
  48. package/dist/settings/rulesets/diff-algorithm.d.ts +18 -0
  49. package/dist/settings/rulesets/diff-algorithm.js +166 -0
  50. package/dist/{ruleset-diff.d.ts → settings/rulesets/diff.d.ts} +2 -2
  51. package/dist/{ruleset-diff.js → settings/rulesets/diff.js} +1 -1
  52. package/dist/{ruleset-plan-formatter.d.ts → settings/rulesets/formatter.d.ts} +4 -12
  53. package/dist/{ruleset-plan-formatter.js → settings/rulesets/formatter.js} +5 -166
  54. package/dist/{strategies → settings/rulesets}/github-ruleset-strategy.d.ts +4 -4
  55. package/dist/{strategies → settings/rulesets}/github-ruleset-strategy.js +3 -3
  56. package/dist/settings/rulesets/index.d.ts +6 -0
  57. package/dist/settings/rulesets/index.js +10 -0
  58. package/dist/{ruleset-processor.d.ts → settings/rulesets/processor.d.ts} +4 -4
  59. package/dist/{ruleset-processor.js → settings/rulesets/processor.js} +6 -6
  60. package/dist/{strategies/ruleset-strategy.d.ts → settings/rulesets/types.d.ts} +2 -2
  61. package/dist/{command-executor.d.ts → shared/command-executor.d.ts} +10 -2
  62. package/dist/{command-executor.js → shared/command-executor.js} +2 -1
  63. package/dist/shared/index.d.ts +8 -0
  64. package/dist/shared/index.js +16 -0
  65. package/dist/{logger.d.ts → shared/logger.d.ts} +1 -1
  66. package/dist/{logger.js → shared/logger.js} +1 -1
  67. package/dist/sync/auth-options-builder.d.ts +12 -0
  68. package/dist/sync/auth-options-builder.js +54 -0
  69. package/dist/sync/branch-manager.d.ts +7 -0
  70. package/dist/sync/branch-manager.js +36 -0
  71. package/dist/sync/commit-message.d.ts +11 -0
  72. package/dist/sync/commit-message.js +27 -0
  73. package/dist/sync/commit-push-manager.d.ts +8 -0
  74. package/dist/sync/commit-push-manager.js +71 -0
  75. package/dist/sync/file-sync-orchestrator.d.ts +11 -0
  76. package/dist/sync/file-sync-orchestrator.js +58 -0
  77. package/dist/sync/file-writer.d.ts +18 -0
  78. package/dist/sync/file-writer.js +101 -0
  79. package/dist/sync/index.d.ts +14 -0
  80. package/dist/sync/index.js +17 -0
  81. package/dist/sync/manifest-manager.d.ts +10 -0
  82. package/dist/sync/manifest-manager.js +64 -0
  83. package/dist/sync/pr-merge-handler.d.ts +11 -0
  84. package/dist/sync/pr-merge-handler.js +62 -0
  85. package/dist/sync/repository-processor.d.ts +30 -0
  86. package/dist/sync/repository-processor.js +278 -0
  87. package/dist/sync/repository-session.d.ts +9 -0
  88. package/dist/sync/repository-session.js +35 -0
  89. package/dist/sync/types.d.ts +296 -0
  90. package/dist/{xfg-template.d.ts → sync/xfg-template.d.ts} +2 -2
  91. package/dist/{authenticated-git-ops.js → vcs/authenticated-git-ops.js} +3 -3
  92. package/dist/{strategies → vcs}/azure-pr-strategy.d.ts +2 -2
  93. package/dist/{strategies → vcs}/azure-pr-strategy.js +5 -5
  94. package/dist/{strategies → vcs}/commit-strategy-selector.d.ts +3 -3
  95. package/dist/{strategies → vcs}/commit-strategy-selector.js +1 -1
  96. package/dist/{strategies → vcs}/git-commit-strategy.d.ts +2 -2
  97. package/dist/{strategies → vcs}/git-commit-strategy.js +3 -3
  98. package/dist/{git-ops.d.ts → vcs/git-ops.d.ts} +1 -1
  99. package/dist/{git-ops.js → vcs/git-ops.js} +4 -4
  100. package/dist/{github-app-token-manager.d.ts → vcs/github-app-token-manager.d.ts} +1 -1
  101. package/dist/{github-app-token-manager.js → vcs/github-app-token-manager.js} +1 -1
  102. package/dist/{strategies → vcs}/github-pr-strategy.d.ts +2 -2
  103. package/dist/{strategies → vcs}/github-pr-strategy.js +30 -33
  104. package/dist/{strategies → vcs}/gitlab-pr-strategy.d.ts +2 -2
  105. package/dist/{strategies → vcs}/gitlab-pr-strategy.js +5 -5
  106. package/dist/{strategies → vcs}/graphql-commit-strategy.d.ts +2 -2
  107. package/dist/{strategies → vcs}/graphql-commit-strategy.js +3 -3
  108. package/dist/vcs/index.d.ts +16 -0
  109. package/dist/{strategies → vcs}/index.js +15 -10
  110. package/dist/{pr-creator.d.ts → vcs/pr-creator.d.ts} +4 -4
  111. package/dist/{pr-creator.js → vcs/pr-creator.js} +3 -3
  112. package/dist/vcs/pr-strategy.d.ts +41 -0
  113. package/dist/{strategies → vcs}/pr-strategy.js +1 -1
  114. package/dist/{strategies/pr-strategy.d.ts → vcs/types.d.ts} +32 -35
  115. package/dist/vcs/types.js +1 -0
  116. package/package.json +2 -2
  117. package/dist/repository-processor.d.ts +0 -79
  118. package/dist/repository-processor.js +0 -659
  119. package/dist/strategies/commit-strategy.d.ts +0 -36
  120. package/dist/strategies/index.d.ts +0 -18
  121. /package/dist/{file-reference-resolver.js → config/file-reference-resolver.js} +0 -0
  122. /package/dist/{config-formatter.d.ts → config/formatter.d.ts} +0 -0
  123. /package/dist/{config-formatter.js → config/formatter.js} +0 -0
  124. /package/dist/{merge.d.ts → config/merge.d.ts} +0 -0
  125. /package/dist/{merge.js → config/merge.js} +0 -0
  126. /package/dist/{github-summary.d.ts → output/github-summary.d.ts} +0 -0
  127. /package/dist/{github-summary.js → output/github-summary.js} +0 -0
  128. /package/dist/{plan-formatter.d.ts → output/plan-formatter.d.ts} +0 -0
  129. /package/dist/{plan-formatter.js → output/plan-formatter.js} +0 -0
  130. /package/dist/{plan-summary.d.ts → output/plan-summary.d.ts} +0 -0
  131. /package/dist/{plan-summary.js → output/plan-summary.js} +0 -0
  132. /package/dist/{summary-utils.js → output/summary-utils.js} +0 -0
  133. /package/dist/{repo-settings-diff.js → settings/repo-settings/diff.js} +0 -0
  134. /package/dist/{repo-settings-plan-formatter.js → settings/repo-settings/formatter.js} +0 -0
  135. /package/dist/{strategies/repo-settings-strategy.js → settings/repo-settings/types.js} +0 -0
  136. /package/dist/{resource-converters.js → settings/resource-converters.js} +0 -0
  137. /package/dist/{strategies/commit-strategy.js → settings/rulesets/types.js} +0 -0
  138. /package/dist/{env.d.ts → shared/env.d.ts} +0 -0
  139. /package/dist/{env.js → shared/env.js} +0 -0
  140. /package/dist/{repo-detector.d.ts → shared/repo-detector.d.ts} +0 -0
  141. /package/dist/{repo-detector.js → shared/repo-detector.js} +0 -0
  142. /package/dist/{retry-utils.d.ts → shared/retry-utils.d.ts} +0 -0
  143. /package/dist/{retry-utils.js → shared/retry-utils.js} +0 -0
  144. /package/dist/{sanitize-utils.d.ts → shared/sanitize-utils.d.ts} +0 -0
  145. /package/dist/{sanitize-utils.js → shared/sanitize-utils.js} +0 -0
  146. /package/dist/{shell-utils.d.ts → shared/shell-utils.d.ts} +0 -0
  147. /package/dist/{shell-utils.js → shared/shell-utils.js} +0 -0
  148. /package/dist/{workspace-utils.d.ts → shared/workspace-utils.d.ts} +0 -0
  149. /package/dist/{workspace-utils.js → shared/workspace-utils.js} +0 -0
  150. /package/dist/{diff-utils.d.ts → sync/diff-utils.d.ts} +0 -0
  151. /package/dist/{diff-utils.js → sync/diff-utils.js} +0 -0
  152. /package/dist/{manifest.d.ts → sync/manifest.d.ts} +0 -0
  153. /package/dist/{manifest.js → sync/manifest.js} +0 -0
  154. /package/dist/{strategies/ruleset-strategy.js → sync/types.js} +0 -0
  155. /package/dist/{xfg-template.js → sync/xfg-template.js} +0 -0
  156. /package/dist/{authenticated-git-ops.d.ts → vcs/authenticated-git-ops.d.ts} +0 -0
@@ -0,0 +1,166 @@
1
+ // src/settings/rulesets/diff-algorithm.ts
2
+ // =============================================================================
3
+ // Helpers
4
+ // =============================================================================
5
+ export function isObject(val) {
6
+ return val !== null && typeof val === "object" && !Array.isArray(val);
7
+ }
8
+ export function deepEqual(a, b) {
9
+ if (a === b)
10
+ return true;
11
+ if (a === null || b === null || a === undefined || b === undefined)
12
+ return a === b;
13
+ if (typeof a !== typeof b)
14
+ return false;
15
+ if (Array.isArray(a) && Array.isArray(b)) {
16
+ if (a.length !== b.length)
17
+ return false;
18
+ return a.every((val, i) => deepEqual(val, b[i]));
19
+ }
20
+ if (isObject(a) && isObject(b)) {
21
+ const keysA = Object.keys(a);
22
+ const keysB = Object.keys(b);
23
+ if (keysA.length !== keysB.length)
24
+ return false;
25
+ return keysA.every((key) => deepEqual(a[key], b[key]));
26
+ }
27
+ return false;
28
+ }
29
+ export function isArrayOfObjects(arr) {
30
+ return arr.length > 0 && arr.every((item) => isObject(item));
31
+ }
32
+ // =============================================================================
33
+ // Property Diff Algorithm
34
+ // =============================================================================
35
+ /**
36
+ * Recursively compute property-level diffs between two objects.
37
+ */
38
+ export function computePropertyDiffs(current, desired, parentPath = []) {
39
+ const diffs = [];
40
+ const allKeys = new Set([...Object.keys(current), ...Object.keys(desired)]);
41
+ for (const key of allKeys) {
42
+ const path = [...parentPath, key];
43
+ const currentVal = current[key];
44
+ const desiredVal = desired[key];
45
+ if (!(key in current)) {
46
+ // Added property
47
+ diffs.push({ path, action: "add", newValue: desiredVal });
48
+ }
49
+ else if (!(key in desired)) {
50
+ // Removed property
51
+ diffs.push({ path, action: "remove", oldValue: currentVal });
52
+ }
53
+ else if (!deepEqual(currentVal, desiredVal)) {
54
+ // Changed property
55
+ if (isObject(currentVal) && isObject(desiredVal)) {
56
+ // Recurse into nested objects
57
+ diffs.push(...computePropertyDiffs(currentVal, desiredVal, path));
58
+ }
59
+ else if (Array.isArray(currentVal) &&
60
+ Array.isArray(desiredVal) &&
61
+ isArrayOfObjects(currentVal) &&
62
+ isArrayOfObjects(desiredVal)) {
63
+ // Recurse into arrays of objects
64
+ diffs.push(...diffObjectArrays(currentVal, desiredVal, path));
65
+ }
66
+ else {
67
+ diffs.push({
68
+ path,
69
+ action: "change",
70
+ oldValue: currentVal,
71
+ newValue: desiredVal,
72
+ });
73
+ }
74
+ }
75
+ // Unchanged properties are not included
76
+ }
77
+ return diffs;
78
+ }
79
+ // =============================================================================
80
+ // Array Diffing
81
+ // =============================================================================
82
+ /**
83
+ * Diff two arrays of objects by matching items on `type` field (or by index).
84
+ */
85
+ export function diffObjectArrays(currentArr, desiredArr, parentPath) {
86
+ const diffs = [];
87
+ const hasType = desiredArr.every((item) => isObject(item) && "type" in item);
88
+ if (hasType) {
89
+ // Match by type field
90
+ const currentByType = new Map();
91
+ for (let i = 0; i < currentArr.length; i++) {
92
+ const item = currentArr[i];
93
+ const type = item.type;
94
+ if (type)
95
+ currentByType.set(type, { item, index: i });
96
+ }
97
+ const matchedTypes = new Set();
98
+ for (let i = 0; i < desiredArr.length; i++) {
99
+ const desiredItem = desiredArr[i];
100
+ const type = desiredItem.type;
101
+ const label = `[${i}] (${type})`;
102
+ const currentEntry = currentByType.get(type);
103
+ if (currentEntry) {
104
+ matchedTypes.add(type);
105
+ // Recurse into matched pair
106
+ const itemDiffs = computePropertyDiffs(currentEntry.item, desiredItem, [
107
+ ...parentPath,
108
+ label,
109
+ ]);
110
+ diffs.push(...itemDiffs);
111
+ }
112
+ else {
113
+ // New item in desired
114
+ diffs.push({
115
+ path: [...parentPath, label],
116
+ action: "add",
117
+ newValue: desiredItem,
118
+ });
119
+ }
120
+ }
121
+ // Items in current but not in desired
122
+ for (const [type, entry] of currentByType) {
123
+ if (!matchedTypes.has(type)) {
124
+ diffs.push({
125
+ path: [...parentPath, `[${entry.index}] (${type})`],
126
+ action: "remove",
127
+ oldValue: entry.item,
128
+ });
129
+ }
130
+ }
131
+ }
132
+ else {
133
+ // Fallback: match by index
134
+ const maxLen = Math.max(currentArr.length, desiredArr.length);
135
+ for (let i = 0; i < maxLen; i++) {
136
+ const label = `[${i}]`;
137
+ if (i >= currentArr.length) {
138
+ diffs.push({
139
+ path: [...parentPath, label],
140
+ action: "add",
141
+ newValue: desiredArr[i],
142
+ });
143
+ }
144
+ else if (i >= desiredArr.length) {
145
+ diffs.push({
146
+ path: [...parentPath, label],
147
+ action: "remove",
148
+ oldValue: currentArr[i],
149
+ });
150
+ }
151
+ else if (isObject(currentArr[i]) && isObject(desiredArr[i])) {
152
+ const itemDiffs = computePropertyDiffs(currentArr[i], desiredArr[i], [...parentPath, label]);
153
+ diffs.push(...itemDiffs);
154
+ }
155
+ else if (!deepEqual(currentArr[i], desiredArr[i])) {
156
+ diffs.push({
157
+ path: [...parentPath, label],
158
+ action: "change",
159
+ oldValue: currentArr[i],
160
+ newValue: desiredArr[i],
161
+ });
162
+ }
163
+ }
164
+ }
165
+ return diffs;
166
+ }
@@ -1,5 +1,5 @@
1
- import { type Ruleset } from "./config.js";
2
- import type { GitHubRuleset } from "./strategies/github-ruleset-strategy.js";
1
+ import { type Ruleset } from "../../config/index.js";
2
+ import type { GitHubRuleset } from "./github-ruleset-strategy.js";
3
3
  export type RulesetAction = "create" | "update" | "delete" | "unchanged";
4
4
  export interface RulesetChange {
5
5
  action: RulesetAction;
@@ -1,4 +1,4 @@
1
- import { RULESET_COMPARABLE_FIELDS } from "./config.js";
1
+ import { RULESET_COMPARABLE_FIELDS } from "../../config/index.js";
2
2
  // =============================================================================
3
3
  // Normalization (for comparison)
4
4
  // =============================================================================
@@ -1,11 +1,7 @@
1
- import { type RulesetChange, type RulesetAction } from "./ruleset-diff.js";
2
- export type DiffAction = "add" | "change" | "remove";
3
- export interface PropertyDiff {
4
- path: string[];
5
- action: DiffAction;
6
- oldValue?: unknown;
7
- newValue?: unknown;
8
- }
1
+ import { type RulesetChange, type RulesetAction } from "./diff.js";
2
+ import { type PropertyDiff } from "./index.js";
3
+ export type { DiffAction, PropertyDiff } from "./index.js";
4
+ export { computePropertyDiffs } from "./index.js";
9
5
  export interface RulesetPlanEntry {
10
6
  name: string;
11
7
  action: RulesetAction;
@@ -24,10 +20,6 @@ export interface RulesetPlanResult {
24
20
  unchanged: number;
25
21
  entries: RulesetPlanEntry[];
26
22
  }
27
- /**
28
- * Recursively compute property-level diffs between two objects.
29
- */
30
- export declare function computePropertyDiffs(current: Record<string, unknown>, desired: Record<string, unknown>, parentPath?: string[]): PropertyDiff[];
31
23
  /**
32
24
  * Format property diffs as an indented tree structure.
33
25
  */
@@ -1,168 +1,7 @@
1
- // src/ruleset-plan-formatter.ts
2
1
  import chalk from "chalk";
3
- import { projectToDesiredShape, normalizeRuleset, } from "./ruleset-diff.js";
4
- // =============================================================================
5
- // Property Diff Algorithm
6
- // =============================================================================
7
- /**
8
- * Recursively compute property-level diffs between two objects.
9
- */
10
- export function computePropertyDiffs(current, desired, parentPath = []) {
11
- const diffs = [];
12
- const allKeys = new Set([...Object.keys(current), ...Object.keys(desired)]);
13
- for (const key of allKeys) {
14
- const path = [...parentPath, key];
15
- const currentVal = current[key];
16
- const desiredVal = desired[key];
17
- if (!(key in current)) {
18
- // Added property
19
- diffs.push({ path, action: "add", newValue: desiredVal });
20
- }
21
- else if (!(key in desired)) {
22
- // Removed property
23
- diffs.push({ path, action: "remove", oldValue: currentVal });
24
- }
25
- else if (!deepEqual(currentVal, desiredVal)) {
26
- // Changed property
27
- if (isObject(currentVal) && isObject(desiredVal)) {
28
- // Recurse into nested objects
29
- diffs.push(...computePropertyDiffs(currentVal, desiredVal, path));
30
- }
31
- else if (Array.isArray(currentVal) &&
32
- Array.isArray(desiredVal) &&
33
- isArrayOfObjects(currentVal) &&
34
- isArrayOfObjects(desiredVal)) {
35
- // Recurse into arrays of objects
36
- diffs.push(...diffObjectArrays(currentVal, desiredVal, path));
37
- }
38
- else {
39
- diffs.push({
40
- path,
41
- action: "change",
42
- oldValue: currentVal,
43
- newValue: desiredVal,
44
- });
45
- }
46
- }
47
- // Unchanged properties are not included
48
- }
49
- return diffs;
50
- }
51
- // =============================================================================
52
- // Helpers
53
- // =============================================================================
54
- function isObject(val) {
55
- return val !== null && typeof val === "object" && !Array.isArray(val);
56
- }
57
- function deepEqual(a, b) {
58
- if (a === b)
59
- return true;
60
- if (a === null || b === null || a === undefined || b === undefined)
61
- return a === b;
62
- if (typeof a !== typeof b)
63
- return false;
64
- if (Array.isArray(a) && Array.isArray(b)) {
65
- if (a.length !== b.length)
66
- return false;
67
- return a.every((val, i) => deepEqual(val, b[i]));
68
- }
69
- if (isObject(a) && isObject(b)) {
70
- const keysA = Object.keys(a);
71
- const keysB = Object.keys(b);
72
- if (keysA.length !== keysB.length)
73
- return false;
74
- return keysA.every((key) => deepEqual(a[key], b[key]));
75
- }
76
- return false;
77
- }
78
- function isArrayOfObjects(arr) {
79
- return arr.length > 0 && arr.every((item) => isObject(item));
80
- }
81
- /**
82
- * Diff two arrays of objects by matching items on `type` field (or by index).
83
- */
84
- function diffObjectArrays(currentArr, desiredArr, parentPath) {
85
- const diffs = [];
86
- const hasType = desiredArr.every((item) => isObject(item) && "type" in item);
87
- if (hasType) {
88
- // Match by type field
89
- const currentByType = new Map();
90
- for (let i = 0; i < currentArr.length; i++) {
91
- const item = currentArr[i];
92
- const type = item.type;
93
- if (type)
94
- currentByType.set(type, { item, index: i });
95
- }
96
- const matchedTypes = new Set();
97
- for (let i = 0; i < desiredArr.length; i++) {
98
- const desiredItem = desiredArr[i];
99
- const type = desiredItem.type;
100
- const label = `[${i}] (${type})`;
101
- const currentEntry = currentByType.get(type);
102
- if (currentEntry) {
103
- matchedTypes.add(type);
104
- // Recurse into matched pair
105
- const itemDiffs = computePropertyDiffs(currentEntry.item, desiredItem, [
106
- ...parentPath,
107
- label,
108
- ]);
109
- diffs.push(...itemDiffs);
110
- }
111
- else {
112
- // New item in desired
113
- diffs.push({
114
- path: [...parentPath, label],
115
- action: "add",
116
- newValue: desiredItem,
117
- });
118
- }
119
- }
120
- // Items in current but not in desired
121
- for (const [type, entry] of currentByType) {
122
- if (!matchedTypes.has(type)) {
123
- diffs.push({
124
- path: [...parentPath, `[${entry.index}] (${type})`],
125
- action: "remove",
126
- oldValue: entry.item,
127
- });
128
- }
129
- }
130
- }
131
- else {
132
- // Fallback: match by index
133
- const maxLen = Math.max(currentArr.length, desiredArr.length);
134
- for (let i = 0; i < maxLen; i++) {
135
- const label = `[${i}]`;
136
- if (i >= currentArr.length) {
137
- diffs.push({
138
- path: [...parentPath, label],
139
- action: "add",
140
- newValue: desiredArr[i],
141
- });
142
- }
143
- else if (i >= desiredArr.length) {
144
- diffs.push({
145
- path: [...parentPath, label],
146
- action: "remove",
147
- oldValue: currentArr[i],
148
- });
149
- }
150
- else if (isObject(currentArr[i]) && isObject(desiredArr[i])) {
151
- const itemDiffs = computePropertyDiffs(currentArr[i], desiredArr[i], [...parentPath, label]);
152
- diffs.push(...itemDiffs);
153
- }
154
- else if (!deepEqual(currentArr[i], desiredArr[i])) {
155
- diffs.push({
156
- path: [...parentPath, label],
157
- action: "change",
158
- oldValue: currentArr[i],
159
- newValue: desiredArr[i],
160
- });
161
- }
162
- }
163
- }
164
- return diffs;
165
- }
2
+ import { projectToDesiredShape, normalizeRuleset, } from "./diff.js";
3
+ import { computePropertyDiffs, isObject, } from "./index.js";
4
+ export { computePropertyDiffs } from "./index.js";
166
5
  /**
167
6
  * Build a tree structure from flat property diffs.
168
7
  */
@@ -372,10 +211,10 @@ function formatFullConfig(ruleset, indent = 2) {
372
211
  lines.push(style.color(`${pad}+ ${key}:`));
373
212
  for (const item of value) {
374
213
  if (typeof item === "object" && item !== null) {
375
- lines.push(style.color(`${pad} - ${JSON.stringify(item)}`));
214
+ lines.push(style.color(`${pad} + ${JSON.stringify(item)}`));
376
215
  }
377
216
  else {
378
- lines.push(style.color(`${pad} - ${formatValue(item)}`));
217
+ lines.push(style.color(`${pad} + ${formatValue(item)}`));
379
218
  }
380
219
  }
381
220
  }
@@ -1,7 +1,7 @@
1
- import { ICommandExecutor } from "../command-executor.js";
2
- import { RepoInfo } from "../repo-detector.js";
3
- import type { Ruleset } from "../config.js";
4
- import type { IRulesetStrategy } from "./ruleset-strategy.js";
1
+ import { ICommandExecutor } from "../../shared/command-executor.js";
2
+ import { RepoInfo } from "../../shared/repo-detector.js";
3
+ import type { Ruleset } from "../../config/index.js";
4
+ import type { IRulesetStrategy } from "./types.js";
5
5
  /**
6
6
  * GitHub Ruleset response from API (snake_case).
7
7
  */
@@ -1,6 +1,6 @@
1
- import { defaultExecutor } from "../command-executor.js";
2
- import { isGitHubRepo } from "../repo-detector.js";
3
- import { escapeShellArg } from "../shell-utils.js";
1
+ import { defaultExecutor, } from "../../shared/command-executor.js";
2
+ import { isGitHubRepo, } from "../../shared/repo-detector.js";
3
+ import { escapeShellArg } from "../../shared/shell-utils.js";
4
4
  // =============================================================================
5
5
  // Conversion Functions
6
6
  // =============================================================================
@@ -0,0 +1,6 @@
1
+ export type { IRulesetStrategy } from "./types.js";
2
+ export { computePropertyDiffs, diffObjectArrays, deepEqual, isObject, isArrayOfObjects, type DiffAction, type PropertyDiff, } from "./diff-algorithm.js";
3
+ export { RulesetProcessor, type IRulesetProcessor, type RulesetProcessorOptions, type RulesetProcessorResult, } from "./processor.js";
4
+ export { diffRulesets, normalizeRuleset, projectToDesiredShape, type RulesetAction, type RulesetChange, } from "./diff.js";
5
+ export { formatRulesetPlan, type RulesetPlanResult, type RulesetPlanEntry, } from "./formatter.js";
6
+ export { GitHubRulesetStrategy, configToGitHub, type GitHubRuleset, type GitHubBypassActor, type GitHubRulesetConditions, type GitHubRule, type RulesetStrategyOptions, } from "./github-ruleset-strategy.js";
@@ -0,0 +1,10 @@
1
+ // Diff algorithm - property-level diffing for ruleset comparisons
2
+ export { computePropertyDiffs, diffObjectArrays, deepEqual, isObject, isArrayOfObjects, } from "./diff-algorithm.js";
3
+ // Ruleset processor
4
+ export { RulesetProcessor, } from "./processor.js";
5
+ // Ruleset diff
6
+ export { diffRulesets, normalizeRuleset, projectToDesiredShape, } from "./diff.js";
7
+ // Ruleset formatter
8
+ export { formatRulesetPlan, } from "./formatter.js";
9
+ // Ruleset strategies
10
+ export { GitHubRulesetStrategy, configToGitHub, } from "./github-ruleset-strategy.js";
@@ -1,7 +1,7 @@
1
- import type { RepoConfig } from "./config.js";
2
- import type { RepoInfo } from "./repo-detector.js";
3
- import { GitHubRulesetStrategy } from "./strategies/github-ruleset-strategy.js";
4
- import { RulesetPlanResult } from "./ruleset-plan-formatter.js";
1
+ import type { RepoConfig } from "../../config/index.js";
2
+ import type { RepoInfo } from "../../shared/repo-detector.js";
3
+ import { GitHubRulesetStrategy } from "./github-ruleset-strategy.js";
4
+ import { RulesetPlanResult } from "./formatter.js";
5
5
  export interface IRulesetProcessor {
6
6
  process(repoConfig: RepoConfig, repoInfo: RepoInfo, options: RulesetProcessorOptions): Promise<RulesetProcessorResult>;
7
7
  }
@@ -1,9 +1,9 @@
1
- import { isGitHubRepo, getRepoDisplayName } from "./repo-detector.js";
2
- import { GitHubRulesetStrategy, } from "./strategies/github-ruleset-strategy.js";
3
- import { diffRulesets } from "./ruleset-diff.js";
4
- import { formatRulesetPlan, } from "./ruleset-plan-formatter.js";
5
- import { hasGitHubAppCredentials } from "./strategies/index.js";
6
- import { GitHubAppTokenManager } from "./github-app-token-manager.js";
1
+ import { isGitHubRepo, getRepoDisplayName, } from "../../shared/repo-detector.js";
2
+ import { GitHubRulesetStrategy, } from "./github-ruleset-strategy.js";
3
+ import { diffRulesets } from "./diff.js";
4
+ import { formatRulesetPlan } from "./formatter.js";
5
+ import { hasGitHubAppCredentials } from "../../vcs/index.js";
6
+ import { GitHubAppTokenManager } from "../../vcs/github-app-token-manager.js";
7
7
  // =============================================================================
8
8
  // Processor Implementation
9
9
  // =============================================================================
@@ -1,5 +1,5 @@
1
- import type { RepoInfo } from "../repo-detector.js";
2
- import type { Ruleset } from "../config.js";
1
+ import type { RepoInfo } from "../../shared/repo-detector.js";
2
+ import type { Ruleset } from "../../config/index.js";
3
3
  import type { GitHubRuleset, RulesetStrategyOptions } from "./github-ruleset-strategy.js";
4
4
  export interface IRulesetStrategy {
5
5
  list(repoInfo: RepoInfo, options?: RulesetStrategyOptions): Promise<GitHubRuleset[]>;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Options for command execution.
3
+ */
4
+ export interface ExecOptions {
5
+ /** Additional environment variables to set for the command */
6
+ env?: Record<string, string>;
7
+ }
1
8
  /**
2
9
  * Interface for executing shell commands.
3
10
  * Enables dependency injection for testing and alternative implementations.
@@ -7,17 +14,18 @@ export interface ICommandExecutor {
7
14
  * Execute a shell command and return the output.
8
15
  * @param command The command to execute
9
16
  * @param cwd The working directory for the command
17
+ * @param options Optional execution options (env vars, etc.)
10
18
  * @returns Promise resolving to the trimmed stdout output
11
19
  * @throws Error if the command fails
12
20
  */
13
- exec(command: string, cwd: string): Promise<string>;
21
+ exec(command: string, cwd: string, options?: ExecOptions): Promise<string>;
14
22
  }
15
23
  /**
16
24
  * Default implementation that uses Node.js child_process.execSync.
17
25
  * Note: Commands are escaped using escapeShellArg before being passed here.
18
26
  */
19
27
  export declare class ShellCommandExecutor implements ICommandExecutor {
20
- exec(command: string, cwd: string): Promise<string>;
28
+ exec(command: string, cwd: string, options?: ExecOptions): Promise<string>;
21
29
  }
22
30
  /**
23
31
  * Default executor instance for production use.
@@ -5,12 +5,13 @@ import { sanitizeCredentials } from "./sanitize-utils.js";
5
5
  * Note: Commands are escaped using escapeShellArg before being passed here.
6
6
  */
7
7
  export class ShellCommandExecutor {
8
- async exec(command, cwd) {
8
+ async exec(command, cwd, options) {
9
9
  try {
10
10
  return execSync(command, {
11
11
  cwd,
12
12
  encoding: "utf-8",
13
13
  stdio: ["pipe", "pipe", "pipe"],
14
+ env: options?.env ? { ...process.env, ...options.env } : undefined,
14
15
  }).trim();
15
16
  }
16
17
  catch (error) {
@@ -0,0 +1,8 @@
1
+ export { Logger, logger, type ILogger, type LoggerStats } from "./logger.js";
2
+ export { withRetry, isPermanentError, isTransientError, promisify, DEFAULT_PERMANENT_ERROR_PATTERNS, DEFAULT_TRANSIENT_ERROR_PATTERNS, AbortError, type RetryOptions, } from "./retry-utils.js";
3
+ export { ShellCommandExecutor, defaultExecutor, type ICommandExecutor, } from "./command-executor.js";
4
+ export { escapeShellArg } from "./shell-utils.js";
5
+ export { sanitizeCredentials } from "./sanitize-utils.js";
6
+ export { interpolateEnvVars, interpolateEnvVarsInString, interpolateEnvVarsInLines, interpolateContent, type EnvInterpolationOptions, } from "./env.js";
7
+ export { generateWorkspaceName } from "./workspace-utils.js";
8
+ export { detectRepoType, parseGitUrl, getRepoDisplayName, isGitHubRepo, isAzureDevOpsRepo, isGitLabRepo, type RepoType, type RepoInfo, type GitHubRepoInfo, type AzureDevOpsRepoInfo, type GitLabRepoInfo, type RepoDetectorContext, } from "./repo-detector.js";
@@ -0,0 +1,16 @@
1
+ // Logging
2
+ export { Logger, logger } from "./logger.js";
3
+ // Retry utilities
4
+ export { withRetry, isPermanentError, isTransientError, promisify, DEFAULT_PERMANENT_ERROR_PATTERNS, DEFAULT_TRANSIENT_ERROR_PATTERNS, AbortError, } from "./retry-utils.js";
5
+ // Command execution
6
+ export { ShellCommandExecutor, defaultExecutor, } from "./command-executor.js";
7
+ // Shell utilities
8
+ export { escapeShellArg } from "./shell-utils.js";
9
+ // Sanitization
10
+ export { sanitizeCredentials } from "./sanitize-utils.js";
11
+ // Environment
12
+ export { interpolateEnvVars, interpolateEnvVarsInString, interpolateEnvVarsInLines, interpolateContent, } from "./env.js";
13
+ // Workspace utilities
14
+ export { generateWorkspaceName } from "./workspace-utils.js";
15
+ // Repository detection
16
+ export { detectRepoType, parseGitUrl, getRepoDisplayName, isGitHubRepo, isAzureDevOpsRepo, isGitLabRepo, } from "./repo-detector.js";
@@ -1,4 +1,4 @@
1
- import { FileStatus } from "./diff-utils.js";
1
+ import { FileStatus } from "../sync/diff-utils.js";
2
2
  export interface ILogger {
3
3
  info(message: string): void;
4
4
  fileDiff(fileName: string, status: FileStatus, diffLines: string[]): void;
@@ -1,5 +1,5 @@
1
1
  import chalk from "chalk";
2
- import { formatStatusBadge } from "./diff-utils.js";
2
+ import { formatStatusBadge } from "../sync/diff-utils.js";
3
3
  export class Logger {
4
4
  stats = {
5
5
  total: 0,
@@ -0,0 +1,12 @@
1
+ import { RepoInfo } from "../shared/repo-detector.js";
2
+ import { ILogger } from "../shared/logger.js";
3
+ import { GitHubAppTokenManager } from "../vcs/github-app-token-manager.js";
4
+ import type { AuthResult, IAuthOptionsBuilder } from "./types.js";
5
+ export declare class AuthOptionsBuilder implements IAuthOptionsBuilder {
6
+ private readonly tokenManager;
7
+ private readonly log;
8
+ constructor(tokenManager: GitHubAppTokenManager | null, log: ILogger);
9
+ resolve(repoInfo: RepoInfo, repoName: string): Promise<AuthResult>;
10
+ private getInstallationToken;
11
+ private buildAuthOptions;
12
+ }
@@ -0,0 +1,54 @@
1
+ import { isGitHubRepo, } from "../shared/repo-detector.js";
2
+ export class AuthOptionsBuilder {
3
+ tokenManager;
4
+ log;
5
+ constructor(tokenManager, log) {
6
+ this.tokenManager = tokenManager;
7
+ this.log = log;
8
+ }
9
+ async resolve(repoInfo, repoName) {
10
+ // 1. Get installation token if GitHub App configured
11
+ const installationToken = await this.getInstallationToken(repoInfo);
12
+ // 2. Handle "no installation found" case
13
+ if (installationToken === null) {
14
+ return {
15
+ skipResult: {
16
+ success: true,
17
+ repoName,
18
+ message: `No GitHub App installation found for ${repoInfo.owner}`,
19
+ skipped: true,
20
+ },
21
+ };
22
+ }
23
+ // 3. Build effective token (installation token or PAT fallback)
24
+ const token = installationToken ??
25
+ (isGitHubRepo(repoInfo) ? process.env.GH_TOKEN : undefined);
26
+ // 4. Build auth options if we have a token
27
+ const authOptions = token
28
+ ? this.buildAuthOptions(repoInfo, token)
29
+ : undefined;
30
+ return { token, authOptions };
31
+ }
32
+ async getInstallationToken(repoInfo) {
33
+ if (!this.tokenManager || !isGitHubRepo(repoInfo)) {
34
+ return undefined;
35
+ }
36
+ try {
37
+ return await this.tokenManager.getTokenForRepo(repoInfo);
38
+ }
39
+ catch (error) {
40
+ this.log.info(`Warning: Failed to get GitHub App token: ${error instanceof Error ? error.message : String(error)}`);
41
+ return undefined;
42
+ }
43
+ }
44
+ buildAuthOptions(repoInfo, token) {
45
+ return {
46
+ token,
47
+ host: isGitHubRepo(repoInfo)
48
+ ? repoInfo.host
49
+ : "github.com",
50
+ owner: repoInfo.owner,
51
+ repo: repoInfo.repo,
52
+ };
53
+ }
54
+ }
@@ -0,0 +1,7 @@
1
+ import type { IBranchManager, BranchSetupOptions } from "./types.js";
2
+ /**
3
+ * Handles branch creation and existing PR cleanup.
4
+ */
5
+ export declare class BranchManager implements IBranchManager {
6
+ setupBranch(options: BranchSetupOptions): Promise<void>;
7
+ }