redlinegate 0.0.1

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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/commands/redline-init.md +54 -0
  4. package/commands/redline-verify.md +69 -0
  5. package/dist/bin/redline.js +605 -0
  6. package/dist/bin/redline.js.map +1 -0
  7. package/dist/commands/exempt.js +45 -0
  8. package/dist/commands/exempt.js.map +1 -0
  9. package/dist/commands/init.js +615 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/policy.js +25 -0
  12. package/dist/commands/policy.js.map +1 -0
  13. package/dist/commands/remove.js +427 -0
  14. package/dist/commands/remove.js.map +1 -0
  15. package/dist/commands/review.js +72 -0
  16. package/dist/commands/review.js.map +1 -0
  17. package/dist/commands/sync.js +42 -0
  18. package/dist/commands/sync.js.map +1 -0
  19. package/dist/commands/verify.js +478 -0
  20. package/dist/commands/verify.js.map +1 -0
  21. package/dist/config/redline-json.js +187 -0
  22. package/dist/config/redline-json.js.map +1 -0
  23. package/dist/core/errors.js +25 -0
  24. package/dist/core/errors.js.map +1 -0
  25. package/dist/core/git.js +152 -0
  26. package/dist/core/git.js.map +1 -0
  27. package/dist/core/log.js +22 -0
  28. package/dist/core/log.js.map +1 -0
  29. package/dist/core/severity.js +16 -0
  30. package/dist/core/severity.js.map +1 -0
  31. package/dist/core/version.js +15 -0
  32. package/dist/core/version.js.map +1 -0
  33. package/dist/detect/scan.js +79 -0
  34. package/dist/detect/scan.js.map +1 -0
  35. package/dist/detect/stack.js +71 -0
  36. package/dist/detect/stack.js.map +1 -0
  37. package/dist/enforce/ladder.js +148 -0
  38. package/dist/enforce/ladder.js.map +1 -0
  39. package/dist/exempt/parse.js +86 -0
  40. package/dist/exempt/parse.js.map +1 -0
  41. package/dist/metrics/options.js +257 -0
  42. package/dist/metrics/options.js.map +1 -0
  43. package/dist/metrics/run.js +72 -0
  44. package/dist/metrics/run.js.map +1 -0
  45. package/dist/platforms/azure/client.js +53 -0
  46. package/dist/platforms/azure/client.js.map +1 -0
  47. package/dist/platforms/azure/index.js +69 -0
  48. package/dist/platforms/azure/index.js.map +1 -0
  49. package/dist/platforms/azure/install.js +917 -0
  50. package/dist/platforms/azure/install.js.map +1 -0
  51. package/dist/platforms/azure/policy-types.js +70 -0
  52. package/dist/platforms/azure/policy-types.js.map +1 -0
  53. package/dist/platforms/azure/verify.js +309 -0
  54. package/dist/platforms/azure/verify.js.map +1 -0
  55. package/dist/platforms/detect.js +40 -0
  56. package/dist/platforms/detect.js.map +1 -0
  57. package/dist/platforms/github/client.js +49 -0
  58. package/dist/platforms/github/client.js.map +1 -0
  59. package/dist/platforms/github/index.js +54 -0
  60. package/dist/platforms/github/index.js.map +1 -0
  61. package/dist/platforms/github/install.js +558 -0
  62. package/dist/platforms/github/install.js.map +1 -0
  63. package/dist/platforms/github/push.js +102 -0
  64. package/dist/platforms/github/push.js.map +1 -0
  65. package/dist/platforms/github/remote.js +36 -0
  66. package/dist/platforms/github/remote.js.map +1 -0
  67. package/dist/platforms/github/verify.js +366 -0
  68. package/dist/platforms/github/verify.js.map +1 -0
  69. package/dist/platforms/http.js +58 -0
  70. package/dist/platforms/http.js.map +1 -0
  71. package/dist/platforms/pull-request-templates.js +157 -0
  72. package/dist/platforms/pull-request-templates.js.map +1 -0
  73. package/dist/platforms/remote.js +21 -0
  74. package/dist/platforms/remote.js.map +1 -0
  75. package/dist/platforms/resolve.js +69 -0
  76. package/dist/platforms/resolve.js.map +1 -0
  77. package/dist/platforms/shape.js +19 -0
  78. package/dist/platforms/shape.js.map +1 -0
  79. package/dist/platforms/types.js +24 -0
  80. package/dist/platforms/types.js.map +1 -0
  81. package/dist/policy/checks.js +91 -0
  82. package/dist/policy/checks.js.map +1 -0
  83. package/dist/policy/diff.js +50 -0
  84. package/dist/policy/diff.js.map +1 -0
  85. package/dist/registry/discover.js +74 -0
  86. package/dist/registry/discover.js.map +1 -0
  87. package/dist/registry/serialize.js +41 -0
  88. package/dist/registry/serialize.js.map +1 -0
  89. package/dist/registry/types.js +2 -0
  90. package/dist/registry/types.js.map +1 -0
  91. package/dist/remove/host.js +294 -0
  92. package/dist/remove/host.js.map +1 -0
  93. package/dist/render/commands.js +139 -0
  94. package/dist/render/commands.js.map +1 -0
  95. package/dist/render/manifest.js +82 -0
  96. package/dist/render/manifest.js.map +1 -0
  97. package/dist/render/markers.js +166 -0
  98. package/dist/render/markers.js.map +1 -0
  99. package/dist/render/profile.js +23 -0
  100. package/dist/render/profile.js.map +1 -0
  101. package/dist/render/standards.js +169 -0
  102. package/dist/render/standards.js.map +1 -0
  103. package/dist/render/vendors.js +199 -0
  104. package/dist/render/vendors.js.map +1 -0
  105. package/dist/review/engines/api.js +95 -0
  106. package/dist/review/engines/api.js.map +1 -0
  107. package/dist/review/engines/embedded.js +20 -0
  108. package/dist/review/engines/embedded.js.map +1 -0
  109. package/dist/review/engines/types.js +2 -0
  110. package/dist/review/engines/types.js.map +1 -0
  111. package/dist/review/glob.js +29 -0
  112. package/dist/review/glob.js.map +1 -0
  113. package/dist/review/prompt.js +45 -0
  114. package/dist/review/prompt.js.map +1 -0
  115. package/dist/review/rules.js +25 -0
  116. package/dist/review/rules.js.map +1 -0
  117. package/dist/review/schema.js +84 -0
  118. package/dist/review/schema.js.map +1 -0
  119. package/dist/review/scope.js +27 -0
  120. package/dist/review/scope.js.map +1 -0
  121. package/dist/sarif/map.js +58 -0
  122. package/dist/sarif/map.js.map +1 -0
  123. package/dist/sarif/parse.js +88 -0
  124. package/dist/sarif/parse.js.map +1 -0
  125. package/dist/sarif/types.js +2 -0
  126. package/dist/sarif/types.js.map +1 -0
  127. package/dist/sync/host.js +21 -0
  128. package/dist/sync/host.js.map +1 -0
  129. package/dist/sync/plan.js +47 -0
  130. package/dist/sync/plan.js.map +1 -0
  131. package/dist/sync/render.js +57 -0
  132. package/dist/sync/render.js.map +1 -0
  133. package/dist/sync/run.js +118 -0
  134. package/dist/sync/run.js.map +1 -0
  135. package/dist/verify/host.js +52 -0
  136. package/dist/verify/host.js.map +1 -0
  137. package/dist/verify/remote.js +146 -0
  138. package/dist/verify/remote.js.map +1 -0
  139. package/package.json +52 -0
  140. package/platforms/azure/gate-template.yml +105 -0
  141. package/rulesets/redline-org-ruleset.json +46 -0
  142. package/rulesets/redline-ruleset.json +49 -0
  143. package/scripts/assign-rule-ids.mjs +129 -0
  144. package/scripts/build-baseline.mjs +124 -0
  145. package/scripts/build-correlation.mjs +74 -0
  146. package/scripts/build-dashboard.mjs +584 -0
  147. package/scripts/build-digest.mjs +164 -0
  148. package/scripts/build-inbox.mjs +133 -0
  149. package/scripts/build-registry.mjs +42 -0
  150. package/scripts/build-roi.mjs +181 -0
  151. package/scripts/check-pins.mjs +88 -0
  152. package/scripts/collect-telemetry.mjs +300 -0
  153. package/scripts/lib/__tests__/baseline.test.mjs +132 -0
  154. package/scripts/lib/__tests__/correlate.test.mjs +131 -0
  155. package/scripts/lib/__tests__/dora.test.mjs +110 -0
  156. package/scripts/lib/__tests__/exemptions.test.mjs +85 -0
  157. package/scripts/lib/__tests__/metrics-scanner.test.mjs +65 -0
  158. package/scripts/lib/__tests__/sarif.test.mjs +125 -0
  159. package/scripts/lib/__tests__/spend.test.mjs +64 -0
  160. package/scripts/lib/baseline.mjs +156 -0
  161. package/scripts/lib/correlate.mjs +125 -0
  162. package/scripts/lib/dora.mjs +133 -0
  163. package/scripts/lib/exemptions.mjs +79 -0
  164. package/scripts/lib/metrics.mjs +172 -0
  165. package/scripts/lib/rules.mjs +107 -0
  166. package/scripts/lib/sarif.mjs +108 -0
  167. package/scripts/lib/spend.mjs +69 -0
  168. package/scripts/measure-context.mjs +101 -0
  169. package/scripts/render-self.mjs +18 -0
  170. package/scripts/score-seeds.mjs +294 -0
  171. package/scripts/validate.mjs +394 -0
  172. package/standards/core.md +124 -0
  173. package/standards/manifest.json +214 -0
  174. package/standards/stacks/csharp.md +29 -0
  175. package/standards/stacks/go.md +30 -0
  176. package/standards/stacks/java.md +30 -0
  177. package/standards/stacks/javascript.md +42 -0
  178. package/standards/stacks/kotlin.md +27 -0
  179. package/standards/stacks/microservices.md +37 -0
  180. package/standards/stacks/nodejs.md +34 -0
  181. package/standards/stacks/python.md +29 -0
  182. package/standards/stacks/react-native.md +29 -0
  183. package/standards/stacks/react.md +46 -0
  184. package/standards/stacks/swift.md +26 -0
  185. package/standards/stacks/terraform.md +27 -0
  186. package/templates/CODEOWNERS +29 -0
  187. package/templates/azure/pull_request_template.md +72 -0
  188. package/templates/github/pull_request_template.md +72 -0
  189. package/templates/redline.yml +35 -0
  190. package/templates/repo-context.md +64 -0
  191. package/workflows/dashboard.yml +119 -0
  192. package/workflows/inbox.yml +97 -0
  193. package/workflows/redline-collect.yml +61 -0
  194. package/workflows/redline-gate.yml +301 -0
  195. package/workflows/redline-sync.yml +79 -0
  196. package/workflows/seed-canary.yml +231 -0
  197. package/workflows/verify-onboarding.yml +115 -0
  198. package/workflows/weekly-digest.yml +78 -0
@@ -0,0 +1,25 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { RedlineError } from "../core/errors.js";
3
+ import { SEVERITY_RANK } from "../core/severity.js";
4
+ import { loadManifest } from "../render/manifest.js";
5
+ import { parseDiff } from "../policy/diff.js";
6
+ import { formatFinding, runChecks } from "../policy/checks.js";
7
+ export function policy(opts) {
8
+ let diff;
9
+ try {
10
+ diff = readFileSync(opts.diffFile, 'utf8');
11
+ }
12
+ catch (error) {
13
+ throw new RedlineError('usage', `cannot read the diff from ${opts.diffFile}: ${error instanceof Error ? error.message : String(error)}`);
14
+ }
15
+ const manifest = loadManifest(opts.root);
16
+ const classified = manifest.deterministic ?? [];
17
+ const added = parseDiff(diff);
18
+ const { findings, evaluated } = runChecks({ added, files: [...new Set(added.map((a) => a.file))], body: '' }, classified);
19
+ const unimplemented = classified.filter((id) => !evaluated.includes(id));
20
+ const failOn = opts.failOn ?? 'BLOCKER';
21
+ const ok = !findings.some((f) => SEVERITY_RANK[f.severity] >= SEVERITY_RANK[failOn]);
22
+ return { findings, evaluated, unimplemented, ok };
23
+ }
24
+ export { formatFinding };
25
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../cli/commands/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAsB,MAAM,qBAAqB,CAAC;AAuBnF,MAAM,UAAU,MAAM,CAAC,IAAmB;IACxC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,6BAA6B,IAAI,CAAC,QAAQ,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACxG,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,CACvC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAClE,UAAU,CACX,CAAC;IAEF,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC;IACxC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAErF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,427 @@
1
+ import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { isRedlineError, RedlineError } from "../core/errors.js";
4
+ import { CONFIG_FILE, readConfig } from "../config/redline-json.js";
5
+ import { loadManifest } from "../render/manifest.js";
6
+ import { resolveProfile } from "../render/profile.js";
7
+ import { stripBlock } from "../render/standards.js";
8
+ import { COMMAND_HOSTS, contentId, loadCommands } from "../render/commands.js";
9
+ import { LOCAL_RULES_FILE, VENDORS, readLocalRules, } from "../render/vendors.js";
10
+ import { observePullRequestTemplates } from "../platforms/pull-request-templates.js";
11
+ import { isPending } from "../platforms/types.js";
12
+ export const REMOVE_BRANCH = 'redline/remove';
13
+ // CONTRACT with cli/render/commands.ts's MANAGED_BY / MANAGED_HEADER: the
14
+ // attribution line Redline writes into the frontmatter of every command file it
15
+ // renders, and the only thing that tells its frontmatter apart from a team's own
16
+ // — nothing about the SHAPE of a lone `description:` key does.
17
+ const MANAGED_HEADER = /^# Managed by Redline\b/m;
18
+ // CONTRACT with MANAGED_BY_REDLINE in cli/platforms/github/install.ts and
19
+ // cli/platforms/azure/install.ts. Those two accept exactly two proofs that the
20
+ // gate machinery file is Redline's and may be overwritten: this ownership line,
21
+ // or the reusable-workflow reference that `readGateMachinery` reads back as the
22
+ // check the file publishes. What init is allowed to overwrite is precisely what
23
+ // remove is allowed to delete, so both signals are honoured here too.
24
+ const MANAGED_BY_REDLINE = /^#[ \t]*Managed by Redline\b/m;
25
+ // The CODEOWNERS header `ensureReviewOwnership` writes, and the only way to
26
+ // tell a seeded file from one this repository already had. That adapter seeds
27
+ // `.github/CODEOWNERS` only when NONE of its candidate paths exists, so a
28
+ // repository with its own file never got one — but the run that seeded it
29
+ // records nothing about having done so, and `already` versus `applied` is not
30
+ // in `.redline.json`. The header is: a file carrying it was written by Redline,
31
+ // and a file that does not is left alone whatever its path.
32
+ const CODEOWNERS_HEADER = /^#[ \t]*Managed by Redline\b/;
33
+ const CODEOWNERS_PATH = '.github/CODEOWNERS';
34
+ const read = (cwd, relPath) => {
35
+ const abs = join(cwd, relPath);
36
+ return existsSync(abs) ? readFileSync(abs, 'utf8') : null;
37
+ };
38
+ function readBlock(body, label) {
39
+ let stripped;
40
+ try {
41
+ stripped = stripBlock(body, label);
42
+ }
43
+ catch (error) {
44
+ if (!isRedlineError(error))
45
+ throw error;
46
+ return { kind: 'mangled', why: error.message };
47
+ }
48
+ if (stripped === body)
49
+ return { kind: 'none' };
50
+ if (stripped === null)
51
+ return { kind: 'whole' };
52
+ return { kind: 'partial', keep: stripped };
53
+ }
54
+ function renderedSurface(root, cwd, profile) {
55
+ const manifest = loadManifest(root);
56
+ // The stacks decide only WHICH per-stack artifacts a render would produce,
57
+ // and every one of them is recognised below by its vendor's prune rule rather
58
+ // than by name — so an empty stack list costs nothing here. That matters,
59
+ // because resolveProfile throws on a profile the org has since dropped, and a
60
+ // repository whose profile no longer exists is exactly the one that most
61
+ // needs a way to back out.
62
+ let stacks = [];
63
+ try {
64
+ stacks = resolveProfile(manifest, profile).stacks;
65
+ }
66
+ catch (error) {
67
+ if (!isRedlineError(error))
68
+ throw error;
69
+ }
70
+ const ctx = { manifest, root, profile, stacks, local: readLocalRules(cwd) };
71
+ const merged = [];
72
+ const prunes = [];
73
+ for (const renderer of Object.values(VENDORS)) {
74
+ const output = renderer(ctx);
75
+ prunes.push(...output.prune);
76
+ for (const [path, file] of output.files) {
77
+ if (file.merge === true)
78
+ merged.push(path);
79
+ }
80
+ }
81
+ return { merged, prunes };
82
+ }
83
+ // A shared file: strip the block, keep everything else byte for byte, and
84
+ // delete the file only when nothing but the block was ever in it — which is
85
+ // what a `CLAUDE.md` that `redline init` created on a greenfield repository is.
86
+ function planMergedFile(cwd, relPath, actions) {
87
+ const body = read(cwd, relPath);
88
+ if (body === null)
89
+ return;
90
+ const block = readBlock(body, relPath);
91
+ if (block.kind === 'mangled') {
92
+ actions.push({ kind: 'kept', path: relPath, reason: block.why });
93
+ return;
94
+ }
95
+ if (block.kind === 'none') {
96
+ actions.push({
97
+ kind: 'kept',
98
+ path: relPath,
99
+ reason: 'carries no REDLINE block, so nothing in it is Redline\'s',
100
+ });
101
+ return;
102
+ }
103
+ if (block.kind === 'whole') {
104
+ actions.push({
105
+ kind: 'delete',
106
+ path: relPath,
107
+ directory: false,
108
+ reason: 'nothing but the Redline block was in it',
109
+ });
110
+ return;
111
+ }
112
+ actions.push({
113
+ kind: 'unmerge',
114
+ path: relPath,
115
+ reason: 'the Redline block only — every byte outside it is kept as it is',
116
+ keep: block.keep,
117
+ });
118
+ }
119
+ // Mirrors the deselect path in cli/render/commands.ts, which is where Redline
120
+ // already takes its own half of a command file back out again. Three proofs of
121
+ // ownership, in the order that one is asked: the file is nothing but the block;
122
+ // what sits outside the block carries the attribution line; or the file predates
123
+ // the block entirely and is byte-for-byte what `.redline.json` recorded Redline
124
+ // writing there. A file with a block and none of the three keeps its own bytes
125
+ // and loses only the block.
126
+ function planCommandFiles(cwd, root, known, actions) {
127
+ const commands = loadCommands(root);
128
+ for (const renderer of Object.values(COMMAND_HOSTS)) {
129
+ for (const command of commands) {
130
+ const { path } = renderer(command);
131
+ const body = read(cwd, path);
132
+ if (body === null)
133
+ continue;
134
+ const recorded = known[path];
135
+ const block = readBlock(body, path);
136
+ if (block.kind === 'mangled') {
137
+ actions.push({ kind: 'kept', path, reason: block.why });
138
+ continue;
139
+ }
140
+ if (block.kind === 'none') {
141
+ // No block, so the only thing that can still make it Redline's is the
142
+ // record of the exact bytes Redline last wrote there. A file onboarded
143
+ // before the marker block existed is that case, and it is the one
144
+ // ownership proof a later edit to `commands/<name>.md` cannot move.
145
+ if (recorded !== undefined && recorded === contentId(body)) {
146
+ actions.push({
147
+ kind: 'delete',
148
+ path,
149
+ directory: false,
150
+ reason: `still byte-for-byte the content ${CONFIG_FILE} recorded Redline writing here`,
151
+ });
152
+ }
153
+ continue;
154
+ }
155
+ if (block.kind === 'whole') {
156
+ actions.push({
157
+ kind: 'delete',
158
+ path,
159
+ directory: false,
160
+ reason: 'nothing but the Redline block was in it',
161
+ });
162
+ continue;
163
+ }
164
+ if (MANAGED_HEADER.test(block.keep)) {
165
+ actions.push({
166
+ kind: 'delete',
167
+ path,
168
+ directory: false,
169
+ reason: 'its frontmatter carries the Redline ownership line',
170
+ });
171
+ continue;
172
+ }
173
+ actions.push({
174
+ kind: 'unmerge',
175
+ path,
176
+ reason: "the Redline block only — this repository's own prompt is kept",
177
+ keep: block.keep,
178
+ });
179
+ }
180
+ }
181
+ }
182
+ function planGateMachinery(platform, cwd, actions) {
183
+ const machinery = platform.readGateMachinery(cwd);
184
+ if (!machinery.present)
185
+ return;
186
+ const body = read(cwd, machinery.path);
187
+ if (body === null)
188
+ return;
189
+ // YAML takes no marker block — a second `name:`/`on:` key stops the workflow
190
+ // running at all — so the file is either Redline's whole or nobody's to
191
+ // touch, which is the same pair of answers `installGate` allows itself.
192
+ if (machinery.publishes !== null || MANAGED_BY_REDLINE.test(body)) {
193
+ actions.push({
194
+ kind: 'delete',
195
+ path: machinery.path,
196
+ directory: false,
197
+ reason: machinery.publishes !== null
198
+ ? `it references Redline's reusable gate and publishes ${machinery.publishes}`
199
+ : 'it carries the Redline ownership line',
200
+ });
201
+ return;
202
+ }
203
+ actions.push({
204
+ kind: 'kept',
205
+ path: machinery.path,
206
+ reason: 'it carries nothing that attributes it to Redline, so it is this repository\'s own file ' +
207
+ 'sitting at a Redline-shaped path',
208
+ });
209
+ }
210
+ function planPullRequestTemplates(platform, cwd, actions) {
211
+ for (const template of observePullRequestTemplates(platform.host, cwd)) {
212
+ if (template.state === 'mangled') {
213
+ actions.push({
214
+ kind: 'kept',
215
+ path: template.path,
216
+ reason: 'its REDLINE:BEGIN/END pair is broken, so which part is Redline\'s cannot be told',
217
+ });
218
+ continue;
219
+ }
220
+ if (template.state !== 'managed') {
221
+ actions.push({
222
+ kind: 'kept',
223
+ path: template.path,
224
+ reason: 'carries no REDLINE block — it answers the gate on its own and is this repository\'s',
225
+ });
226
+ continue;
227
+ }
228
+ planMergedFile(cwd, template.path, actions);
229
+ }
230
+ }
231
+ function planCodeowners(cwd, actions) {
232
+ const body = read(cwd, CODEOWNERS_PATH);
233
+ if (body === null)
234
+ return;
235
+ if (CODEOWNERS_HEADER.test(body)) {
236
+ actions.push({
237
+ kind: 'delete',
238
+ path: CODEOWNERS_PATH,
239
+ directory: false,
240
+ reason: 'seeded by Redline on a repository that had no CODEOWNERS, and still carries its header',
241
+ });
242
+ return;
243
+ }
244
+ actions.push({
245
+ kind: 'kept',
246
+ path: CODEOWNERS_PATH,
247
+ reason: 'it does not carry the header Redline seeds, so this repository either wrote it or has since ' +
248
+ 'made it its own — review the sensitive-path rules in it by hand',
249
+ });
250
+ }
251
+ /**
252
+ * Everything `redline init` put in the working tree, in the order it is acted
253
+ * on. `.redline.json` is deliberately last: while it is there, `redline verify`
254
+ * can still describe the repository, and a run that failed halfway through
255
+ * leaves a repository that still knows what it was rather than one that has
256
+ * forgotten and cannot be verified or repaired.
257
+ */
258
+ function plan(platform, opts, profile, commandFiles) {
259
+ const { cwd, root } = opts;
260
+ const actions = [];
261
+ const surface = renderedSurface(root, cwd, profile);
262
+ // Artifacts Redline owns whole, recognised by the prune rule of the vendor
263
+ // that renders them. `matches` is the `redline-` prefix test, so a file a
264
+ // human put in the same directory without the prefix is never a candidate.
265
+ for (const rule of surface.prunes) {
266
+ const abs = join(cwd, rule.dir);
267
+ if (!existsSync(abs))
268
+ continue;
269
+ for (const entry of readdirSync(abs)) {
270
+ if (!rule.matches(entry))
271
+ continue;
272
+ actions.push({
273
+ kind: 'delete',
274
+ path: join(rule.dir, entry),
275
+ directory: rule.directories === true,
276
+ reason: `a Redline-rendered artifact in ${rule.dir}`,
277
+ });
278
+ }
279
+ }
280
+ for (const relPath of surface.merged)
281
+ planMergedFile(cwd, relPath, actions);
282
+ planCommandFiles(cwd, root, commandFiles, actions);
283
+ planGateMachinery(platform, cwd, actions);
284
+ planPullRequestTemplates(platform, cwd, actions);
285
+ planCodeowners(cwd, actions);
286
+ actions.push({
287
+ kind: 'delete',
288
+ path: CONFIG_FILE,
289
+ directory: false,
290
+ reason: 'Redline\'s own record of this repository — removed last',
291
+ });
292
+ return actions;
293
+ }
294
+ function apply(cwd, action) {
295
+ if (action.kind === 'kept')
296
+ return;
297
+ const abs = join(cwd, action.path);
298
+ if (action.kind === 'unmerge') {
299
+ writeFileSync(abs, action.keep);
300
+ return;
301
+ }
302
+ // `recursive` covers the skill folders, which Redline owns as directories.
303
+ rmSync(abs, { recursive: true, force: true });
304
+ }
305
+ export async function remove(platform, hostFor, opts) {
306
+ const { cwd } = opts;
307
+ const dryRun = opts.dryRun === true;
308
+ // `readConfig` throws RedlineError('failed') when the file is there and
309
+ // cannot be read, which is the right answer: something is recorded and this
310
+ // run cannot tell what. A file that is simply absent is a different thing —
311
+ // the operator asked to remove Redline from a repository it was never on —
312
+ // and it gets the same `usage` answer, and so the same exit code, that
313
+ // `redline verify` gives that repository.
314
+ const config = readConfig(cwd);
315
+ if (config === null) {
316
+ throw new RedlineError('usage', `no ${CONFIG_FILE} in ${cwd} — Redline was never installed here, so there is nothing to remove`, 'run redline verify to see what this repository looks like to Redline');
317
+ }
318
+ const actions = plan(platform, opts, config.profile, config.commandFiles);
319
+ const files = actions.filter((action) => action.kind !== 'kept').map((action) => action.path);
320
+ const notes = [
321
+ 'the security floor stays on: secret scanning, push protection and dependency alerts are the ' +
322
+ "organisation's minimum, not Redline's own state, and removing Redline is not a reason to " +
323
+ 'lower them. This command has no flag that turns them off',
324
+ `once ${CONFIG_FILE} is gone, redline verify stops recognising this repository: it reports "not ` +
325
+ 'onboarded" and exits 2 rather than reporting drift',
326
+ ];
327
+ if (existsSync(join(cwd, LOCAL_RULES_FILE))) {
328
+ notes.push(`${LOCAL_RULES_FILE} is this repository's own rules file — Redline never wrote it and does not ` +
329
+ 'remove it; it is left exactly where it is');
330
+ }
331
+ const hostPlan = [
332
+ `withdraw Redline's own state on ${config.host}: the merge policy it applied, the labels it ` +
333
+ 'created, and the repository property it set where the host has them',
334
+ `pull request on ${REMOVE_BRANCH}`,
335
+ ];
336
+ if (dryRun) {
337
+ // Nothing is written, nothing is read from the host, and no credential is
338
+ // needed — the same contract `redline init --dry-run` holds, and the reason
339
+ // someone evaluating whether they can back Redline out can find out before
340
+ // going to get an admin token.
341
+ return {
342
+ host: config.host,
343
+ dryRun: true,
344
+ actions,
345
+ files,
346
+ outcomes: [],
347
+ pendingAdmin: [],
348
+ pullRequest: null,
349
+ pullRequestError: null,
350
+ hostPlan,
351
+ notes,
352
+ };
353
+ }
354
+ const ref = await platform.repoRef(cwd);
355
+ // Files first, host after, `.redline.json` last of the files — but the config
356
+ // is only removed once the host withdrawal has had its turn, because it is
357
+ // what says which host to talk to at all. A run that died between the two
358
+ // leaves a repository whose record still describes it.
359
+ for (const action of actions) {
360
+ if (action.path === CONFIG_FILE)
361
+ continue;
362
+ apply(cwd, action);
363
+ }
364
+ const withdrawal = await (await hostFor()).withdraw(ref);
365
+ notes.push(...withdrawal.notes);
366
+ const outcomes = withdrawal.outcomes;
367
+ const pendingAdmin = outcomes.filter(isPending).map((outcome) => outcome.capability);
368
+ const configAction = actions.find((action) => action.path === CONFIG_FILE);
369
+ if (configAction)
370
+ apply(cwd, configAction);
371
+ let pullRequest = null;
372
+ let pullRequestError = null;
373
+ try {
374
+ pullRequest = await platform.openPullRequest(ref, cwd, {
375
+ branch: REMOVE_BRANCH,
376
+ title: 'chore(redline): remove Redline from this repository',
377
+ body: removalBody(pendingAdmin),
378
+ // No labels. The `redline-sync` label this would carry is one of the
379
+ // labels this very run deletes, and asking the host to apply a label that
380
+ // no longer exists fails the pull request over housekeeping.
381
+ labels: [],
382
+ files,
383
+ });
384
+ }
385
+ catch (error) {
386
+ // A dirty index is refused before a branch exists and before anything is
387
+ // pushed — the caller's input error, not a half-finished removal.
388
+ if (isRedlineError(error) && error.kind === 'usage')
389
+ throw error;
390
+ pullRequestError = error instanceof Error ? error.message : String(error);
391
+ }
392
+ if (pullRequest?.outcomes)
393
+ outcomes.push(...pullRequest.outcomes);
394
+ return {
395
+ host: config.host,
396
+ dryRun: false,
397
+ actions,
398
+ files,
399
+ outcomes,
400
+ pendingAdmin,
401
+ pullRequest,
402
+ pullRequestError,
403
+ hostPlan,
404
+ notes,
405
+ };
406
+ }
407
+ function removalBody(pendingAdmin) {
408
+ const pending = pendingAdmin.length === 0
409
+ ? 'Every host setting Redline applied has been withdrawn.'
410
+ : `A repository administrator still has to remove: ${pendingAdmin.join(', ')}. Until then ` +
411
+ 'some of Redline\'s host state is still in place.';
412
+ return [
413
+ 'Removes Redline from this repository: the rendered standards, the merge gate machinery, the',
414
+ 'slash-command files and `.redline.json`.',
415
+ '',
416
+ 'Only content Redline wrote is removed. Files it merely merged into keep every byte outside the',
417
+ '`<!-- REDLINE:BEGIN -->` block, and anything that could not be attributed to Redline was left',
418
+ 'in place and named in the run output.',
419
+ '',
420
+ 'The security floor — secret scanning, push protection and dependency alerts — is untouched. It',
421
+ 'is the organisation\'s minimum rather than Redline\'s own state, and removing Redline is not a',
422
+ 'reason to lower it.',
423
+ '',
424
+ pending,
425
+ ].join('\n');
426
+ }
427
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../cli/commands/remove.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { RedlineError } from "../core/errors.js";
3
+ import { createGit } from "../core/git.js";
4
+ import { readConfig } from "../config/redline-json.js";
5
+ import { loadManifest } from "../render/manifest.js";
6
+ import { loadRuleIds } from "../review/rules.js";
7
+ import { buildPrompt } from "../review/prompt.js";
8
+ import { resolveScope } from "../review/scope.js";
9
+ import { parseReview, renderFinding } from "../review/schema.js";
10
+ function readDiff(opts) {
11
+ const source = opts.source ?? { kind: 'worktree' };
12
+ if (source.kind === 'diff-file') {
13
+ try {
14
+ return readFileSync(source.path, 'utf8');
15
+ }
16
+ catch (error) {
17
+ throw new RedlineError('usage', `cannot read the diff from ${source.path}: ${error instanceof Error ? error.message : String(error)}`);
18
+ }
19
+ }
20
+ const git = createGit(opts.cwd);
21
+ const base = opts.base ?? git.defaultBranch();
22
+ if (source.kind === 'staged')
23
+ return git.diffStaged();
24
+ // Against the merge base itself, not `base...HEAD`. The three-dot form diffs
25
+ // two commits, so it cannot see work that is not committed yet — which made
26
+ // the default mode review nothing at all in the case the command exists for:
27
+ // "check this before I commit it". Diffing the working tree against the merge
28
+ // base keeps the property three dots was chosen for (never review commits that
29
+ // landed on the base branch since this one started) and includes uncommitted
30
+ // and staged work as well.
31
+ return git.diff(git.mergeBase(base));
32
+ }
33
+ export async function review(engine, opts) {
34
+ const diff = readDiff(opts);
35
+ if (diff.trim() === '') {
36
+ throw new RedlineError('usage', 'there is nothing to review — the diff is empty', 'stage something, or pass --base to compare against a different branch');
37
+ }
38
+ const manifest = loadManifest(opts.root);
39
+ const config = readConfig(opts.cwd);
40
+ const profile = opts.profile ?? config?.profile;
41
+ if (!profile) {
42
+ throw new RedlineError('usage', 'no profile: this repository has no .redline.json and none was given', 'run: npx redlinegate init — or pass --profile <name>');
43
+ }
44
+ const files = [...new Set([...diff.matchAll(/^\+\+\+ b\/(.+)$/gm)].map((m) => m[1]))].filter((f) => f !== '/dev/null');
45
+ const scope = resolveScope(manifest, profile, files);
46
+ const prompt = buildPrompt({ root: opts.root, manifest, scope, diff });
47
+ const response = await engine.review({ prompt });
48
+ if (response.kind === 'prompt') {
49
+ return {
50
+ scope,
51
+ prompt: response.prompt,
52
+ note: response.note,
53
+ findings: [],
54
+ rejected: [],
55
+ rendered: [],
56
+ excludedFromTelemetry: true,
57
+ };
58
+ }
59
+ const known = loadRuleIds(opts.root, manifest, scope.stacks);
60
+ const { findings, rejected } = parseReview(response.raw, known);
61
+ return {
62
+ scope,
63
+ prompt: null,
64
+ note: null,
65
+ findings,
66
+ rejected,
67
+ // Rendered by code. The comment contract is never free-typed by a model.
68
+ rendered: findings.map(renderFinding),
69
+ excludedFromTelemetry: true,
70
+ };
71
+ }
72
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../cli/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { RedlineError } from "../core/errors.js";
4
+ import { parseRegistry } from "../registry/serialize.js";
5
+ import { runSync } from "../sync/run.js";
6
+ export const REGISTRY_FILE = 'registry.json';
7
+ export function readRegistry(cwd, path = REGISTRY_FILE) {
8
+ let raw;
9
+ try {
10
+ // resolve, not join: an absolute override has to stay absolute, and join
11
+ // would silently nest it under cwd and report the register as missing.
12
+ raw = readFileSync(resolve(cwd, path), 'utf8');
13
+ }
14
+ catch {
15
+ throw new RedlineError('usage', `no ${path} in ${cwd} — the register of onboarded repositories has not been derived yet`, 'run the Redline Registry workflow, or: node scripts/build-registry.mjs');
16
+ }
17
+ return parseRegistry(raw);
18
+ }
19
+ export function standardsVersion(root) {
20
+ const manifest = JSON.parse(readFileSync(resolve(root, 'standards/manifest.json'), 'utf8'));
21
+ if (typeof manifest.version !== 'string') {
22
+ throw new RedlineError('failed', 'standards/manifest.json has no string "version"');
23
+ }
24
+ return manifest.version;
25
+ }
26
+ // Distribute the current standards to every registered repository that is behind.
27
+ //
28
+ // It opens pull requests and never merges them, and it never pushes to a default
29
+ // branch. A repository that ignores its sync pull request drifts, and the estate
30
+ // dashboard's coverage figure is what makes that visible — sync's job is to make
31
+ // the change available, not to impose it.
32
+ export async function sync(host, opts) {
33
+ const registry = readRegistry(opts.cwd, opts.registryPath);
34
+ return runSync(host, registry, {
35
+ root: opts.root,
36
+ standardsVersion: standardsVersion(opts.root),
37
+ ...(opts.repo ? { repo: opts.repo } : {}),
38
+ ...(opts.force ? { force: true } : {}),
39
+ ...(opts.dryRun ? { dryRun: true } : {}),
40
+ });
41
+ }
42
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,EAAE,OAAO,EAAkC,MAAM,gBAAgB,CAAC;AAkBzE,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,IAAI,GAAG,aAAa;IAC5D,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,yEAAyE;QACzE,uEAAuE;QACvE,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,MAAM,IAAI,OAAO,GAAG,oEAAoE,EACxF,wEAAwE,CACzE,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,yBAAyB,CAAC,EAAE,MAAM,CAAC,CAEzF,CAAC;IACF,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,iDAAiD,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC;AAC1B,CAAC;AAED,kFAAkF;AAClF,EAAE;AACF,iFAAiF;AACjF,iFAAiF;AACjF,iFAAiF;AACjF,0CAA0C;AAC1C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc,EAAE,IAAiB;IAC1D,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE;QAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,gBAAgB,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzC,CAAC,CAAC;AACL,CAAC"}