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.
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/commands/redline-init.md +54 -0
- package/commands/redline-verify.md +69 -0
- package/dist/bin/redline.js +605 -0
- package/dist/bin/redline.js.map +1 -0
- package/dist/commands/exempt.js +45 -0
- package/dist/commands/exempt.js.map +1 -0
- package/dist/commands/init.js +615 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/policy.js +25 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/remove.js +427 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/review.js +72 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/sync.js +42 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/verify.js +478 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/config/redline-json.js +187 -0
- package/dist/config/redline-json.js.map +1 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/git.js +152 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/log.js +22 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/severity.js +16 -0
- package/dist/core/severity.js.map +1 -0
- package/dist/core/version.js +15 -0
- package/dist/core/version.js.map +1 -0
- package/dist/detect/scan.js +79 -0
- package/dist/detect/scan.js.map +1 -0
- package/dist/detect/stack.js +71 -0
- package/dist/detect/stack.js.map +1 -0
- package/dist/enforce/ladder.js +148 -0
- package/dist/enforce/ladder.js.map +1 -0
- package/dist/exempt/parse.js +86 -0
- package/dist/exempt/parse.js.map +1 -0
- package/dist/metrics/options.js +257 -0
- package/dist/metrics/options.js.map +1 -0
- package/dist/metrics/run.js +72 -0
- package/dist/metrics/run.js.map +1 -0
- package/dist/platforms/azure/client.js +53 -0
- package/dist/platforms/azure/client.js.map +1 -0
- package/dist/platforms/azure/index.js +69 -0
- package/dist/platforms/azure/index.js.map +1 -0
- package/dist/platforms/azure/install.js +917 -0
- package/dist/platforms/azure/install.js.map +1 -0
- package/dist/platforms/azure/policy-types.js +70 -0
- package/dist/platforms/azure/policy-types.js.map +1 -0
- package/dist/platforms/azure/verify.js +309 -0
- package/dist/platforms/azure/verify.js.map +1 -0
- package/dist/platforms/detect.js +40 -0
- package/dist/platforms/detect.js.map +1 -0
- package/dist/platforms/github/client.js +49 -0
- package/dist/platforms/github/client.js.map +1 -0
- package/dist/platforms/github/index.js +54 -0
- package/dist/platforms/github/index.js.map +1 -0
- package/dist/platforms/github/install.js +558 -0
- package/dist/platforms/github/install.js.map +1 -0
- package/dist/platforms/github/push.js +102 -0
- package/dist/platforms/github/push.js.map +1 -0
- package/dist/platforms/github/remote.js +36 -0
- package/dist/platforms/github/remote.js.map +1 -0
- package/dist/platforms/github/verify.js +366 -0
- package/dist/platforms/github/verify.js.map +1 -0
- package/dist/platforms/http.js +58 -0
- package/dist/platforms/http.js.map +1 -0
- package/dist/platforms/pull-request-templates.js +157 -0
- package/dist/platforms/pull-request-templates.js.map +1 -0
- package/dist/platforms/remote.js +21 -0
- package/dist/platforms/remote.js.map +1 -0
- package/dist/platforms/resolve.js +69 -0
- package/dist/platforms/resolve.js.map +1 -0
- package/dist/platforms/shape.js +19 -0
- package/dist/platforms/shape.js.map +1 -0
- package/dist/platforms/types.js +24 -0
- package/dist/platforms/types.js.map +1 -0
- package/dist/policy/checks.js +91 -0
- package/dist/policy/checks.js.map +1 -0
- package/dist/policy/diff.js +50 -0
- package/dist/policy/diff.js.map +1 -0
- package/dist/registry/discover.js +74 -0
- package/dist/registry/discover.js.map +1 -0
- package/dist/registry/serialize.js +41 -0
- package/dist/registry/serialize.js.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/remove/host.js +294 -0
- package/dist/remove/host.js.map +1 -0
- package/dist/render/commands.js +139 -0
- package/dist/render/commands.js.map +1 -0
- package/dist/render/manifest.js +82 -0
- package/dist/render/manifest.js.map +1 -0
- package/dist/render/markers.js +166 -0
- package/dist/render/markers.js.map +1 -0
- package/dist/render/profile.js +23 -0
- package/dist/render/profile.js.map +1 -0
- package/dist/render/standards.js +169 -0
- package/dist/render/standards.js.map +1 -0
- package/dist/render/vendors.js +199 -0
- package/dist/render/vendors.js.map +1 -0
- package/dist/review/engines/api.js +95 -0
- package/dist/review/engines/api.js.map +1 -0
- package/dist/review/engines/embedded.js +20 -0
- package/dist/review/engines/embedded.js.map +1 -0
- package/dist/review/engines/types.js +2 -0
- package/dist/review/engines/types.js.map +1 -0
- package/dist/review/glob.js +29 -0
- package/dist/review/glob.js.map +1 -0
- package/dist/review/prompt.js +45 -0
- package/dist/review/prompt.js.map +1 -0
- package/dist/review/rules.js +25 -0
- package/dist/review/rules.js.map +1 -0
- package/dist/review/schema.js +84 -0
- package/dist/review/schema.js.map +1 -0
- package/dist/review/scope.js +27 -0
- package/dist/review/scope.js.map +1 -0
- package/dist/sarif/map.js +58 -0
- package/dist/sarif/map.js.map +1 -0
- package/dist/sarif/parse.js +88 -0
- package/dist/sarif/parse.js.map +1 -0
- package/dist/sarif/types.js +2 -0
- package/dist/sarif/types.js.map +1 -0
- package/dist/sync/host.js +21 -0
- package/dist/sync/host.js.map +1 -0
- package/dist/sync/plan.js +47 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/render.js +57 -0
- package/dist/sync/render.js.map +1 -0
- package/dist/sync/run.js +118 -0
- package/dist/sync/run.js.map +1 -0
- package/dist/verify/host.js +52 -0
- package/dist/verify/host.js.map +1 -0
- package/dist/verify/remote.js +146 -0
- package/dist/verify/remote.js.map +1 -0
- package/package.json +52 -0
- package/platforms/azure/gate-template.yml +105 -0
- package/rulesets/redline-org-ruleset.json +46 -0
- package/rulesets/redline-ruleset.json +49 -0
- package/scripts/assign-rule-ids.mjs +129 -0
- package/scripts/build-baseline.mjs +124 -0
- package/scripts/build-correlation.mjs +74 -0
- package/scripts/build-dashboard.mjs +584 -0
- package/scripts/build-digest.mjs +164 -0
- package/scripts/build-inbox.mjs +133 -0
- package/scripts/build-registry.mjs +42 -0
- package/scripts/build-roi.mjs +181 -0
- package/scripts/check-pins.mjs +88 -0
- package/scripts/collect-telemetry.mjs +300 -0
- package/scripts/lib/__tests__/baseline.test.mjs +132 -0
- package/scripts/lib/__tests__/correlate.test.mjs +131 -0
- package/scripts/lib/__tests__/dora.test.mjs +110 -0
- package/scripts/lib/__tests__/exemptions.test.mjs +85 -0
- package/scripts/lib/__tests__/metrics-scanner.test.mjs +65 -0
- package/scripts/lib/__tests__/sarif.test.mjs +125 -0
- package/scripts/lib/__tests__/spend.test.mjs +64 -0
- package/scripts/lib/baseline.mjs +156 -0
- package/scripts/lib/correlate.mjs +125 -0
- package/scripts/lib/dora.mjs +133 -0
- package/scripts/lib/exemptions.mjs +79 -0
- package/scripts/lib/metrics.mjs +172 -0
- package/scripts/lib/rules.mjs +107 -0
- package/scripts/lib/sarif.mjs +108 -0
- package/scripts/lib/spend.mjs +69 -0
- package/scripts/measure-context.mjs +101 -0
- package/scripts/render-self.mjs +18 -0
- package/scripts/score-seeds.mjs +294 -0
- package/scripts/validate.mjs +394 -0
- package/standards/core.md +124 -0
- package/standards/manifest.json +214 -0
- package/standards/stacks/csharp.md +29 -0
- package/standards/stacks/go.md +30 -0
- package/standards/stacks/java.md +30 -0
- package/standards/stacks/javascript.md +42 -0
- package/standards/stacks/kotlin.md +27 -0
- package/standards/stacks/microservices.md +37 -0
- package/standards/stacks/nodejs.md +34 -0
- package/standards/stacks/python.md +29 -0
- package/standards/stacks/react-native.md +29 -0
- package/standards/stacks/react.md +46 -0
- package/standards/stacks/swift.md +26 -0
- package/standards/stacks/terraform.md +27 -0
- package/templates/CODEOWNERS +29 -0
- package/templates/azure/pull_request_template.md +72 -0
- package/templates/github/pull_request_template.md +72 -0
- package/templates/redline.yml +35 -0
- package/templates/repo-context.md +64 -0
- package/workflows/dashboard.yml +119 -0
- package/workflows/inbox.yml +97 -0
- package/workflows/redline-collect.yml +61 -0
- package/workflows/redline-gate.yml +301 -0
- package/workflows/redline-sync.yml +79 -0
- package/workflows/seed-canary.yml +231 -0
- package/workflows/verify-onboarding.yml +115 -0
- package/workflows/weekly-digest.yml +78 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { RedlineError } from "../core/errors.js";
|
|
4
|
+
import { ADMIN_CAPABILITIES, HOSTS } from "../platforms/types.js";
|
|
5
|
+
import { isRung } from "../enforce/ladder.js";
|
|
6
|
+
export const CONFIG_FILE = '.redline.json';
|
|
7
|
+
export const CAPABILITY_KEYS = ['gate', 'mergePolicy', 'labels'];
|
|
8
|
+
export const MENU_KEYS = [
|
|
9
|
+
'blockingGate',
|
|
10
|
+
'adrForLargeDiffs',
|
|
11
|
+
'accessibility',
|
|
12
|
+
'speckit',
|
|
13
|
+
'sensitivePathReviewers',
|
|
14
|
+
];
|
|
15
|
+
// The names an operator types, and where each one is recorded. Review
|
|
16
|
+
// ownership resolves to `menu.sensitivePathReviewers` because that key already
|
|
17
|
+
// is the switch — see the comment on CapabilitySelections.
|
|
18
|
+
const CAPABILITY_NAMES = {
|
|
19
|
+
gate: 'gate',
|
|
20
|
+
'merge-policy': 'mergePolicy',
|
|
21
|
+
labels: 'labels',
|
|
22
|
+
'review-ownership': 'reviewOwnership',
|
|
23
|
+
};
|
|
24
|
+
// Not a capability an operator may decline. Secret scanning, push protection
|
|
25
|
+
// and dependency alerts are the organisation's floor, not this repository's
|
|
26
|
+
// preference, and unlike a gate pipeline or a branch policy there is no
|
|
27
|
+
// "we already have our own" to respect: they are host settings that add to
|
|
28
|
+
// whatever else the repository runs. An opt-out here would be a supported way
|
|
29
|
+
// to fall below the floor, so the flag is refused by name — which is the one
|
|
30
|
+
// thing a silent ignore could never do, tell the operator it did not happen.
|
|
31
|
+
export const MANDATORY_CAPABILITIES = {
|
|
32
|
+
'security-floor': 'the security floor is the organisation-wide minimum: secret scanning, push protection and ' +
|
|
33
|
+
'dependency alerts are additive host settings, so nothing a repository already runs is ' +
|
|
34
|
+
'displaced by them',
|
|
35
|
+
};
|
|
36
|
+
export const OPTIONAL_CAPABILITIES = Object.keys(CAPABILITY_NAMES);
|
|
37
|
+
// The gate install is what creates Redline's labels — GitHub pre-declares the
|
|
38
|
+
// gate's soft-fail labels there, and Azure creates pull request labels on use —
|
|
39
|
+
// so a deselected gate takes the labels with it whatever the operator chose for
|
|
40
|
+
// them. True of the effective state, never of the record: `.redline.json` keeps
|
|
41
|
+
// the operator's own choice, so re-selecting the gate brings the labels back
|
|
42
|
+
// without a second flag.
|
|
43
|
+
export function labelsCarriedByGate(capabilities) {
|
|
44
|
+
return !capabilities.gate && capabilities.labels;
|
|
45
|
+
}
|
|
46
|
+
// The operator-facing names of everything that is off, in the order they are
|
|
47
|
+
// documented. `redline verify` reports the same list, which is how a reader
|
|
48
|
+
// tells "off because we chose to" from "off because it broke" — so it reports
|
|
49
|
+
// what is actually off, not only what was asked for: a capability reported as
|
|
50
|
+
// on while nothing will ever create it is the silence this selection exists to
|
|
51
|
+
// end. `labelsCarriedByGate` above is the one place the two differ.
|
|
52
|
+
export function deselectedCapabilities(menu, capabilities) {
|
|
53
|
+
return OPTIONAL_CAPABILITIES.filter((name) => {
|
|
54
|
+
const key = CAPABILITY_NAMES[name];
|
|
55
|
+
if (key === 'reviewOwnership')
|
|
56
|
+
return !menu.sensitivePathReviewers;
|
|
57
|
+
if (key === 'labels')
|
|
58
|
+
return !capabilities.labels || labelsCarriedByGate(capabilities);
|
|
59
|
+
return key !== undefined && !capabilities[key];
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// `--skip a,b` and `--with a,b`. Per capability, not a whole selection: naming
|
|
63
|
+
// one capability must not silently re-select the others the repository already
|
|
64
|
+
// declined.
|
|
65
|
+
export function capabilitySelection(skip, keep) {
|
|
66
|
+
const flags = { menu: {}, capabilities: {} };
|
|
67
|
+
for (const name of skip) {
|
|
68
|
+
if (keep.includes(name)) {
|
|
69
|
+
throw new RedlineError('usage', `"${name}" is named in both --skip and --with, so neither can be meant`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const [names, on] of [
|
|
73
|
+
[skip, false],
|
|
74
|
+
[keep, true],
|
|
75
|
+
]) {
|
|
76
|
+
for (const name of names) {
|
|
77
|
+
const mandatory = MANDATORY_CAPABILITIES[name];
|
|
78
|
+
if (mandatory !== undefined) {
|
|
79
|
+
if (on)
|
|
80
|
+
continue; // already on and staying on
|
|
81
|
+
throw new RedlineError('usage', `"${name}" cannot be deselected — ${mandatory}`);
|
|
82
|
+
}
|
|
83
|
+
const key = CAPABILITY_NAMES[name];
|
|
84
|
+
if (key === undefined) {
|
|
85
|
+
throw new RedlineError('usage', `unknown capability "${name}". Known: ${OPTIONAL_CAPABILITIES.join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
if (key === 'reviewOwnership')
|
|
88
|
+
flags.menu.sensitivePathReviewers = on;
|
|
89
|
+
else
|
|
90
|
+
flags.capabilities[key] = on;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return flags;
|
|
94
|
+
}
|
|
95
|
+
const bad = (what) => {
|
|
96
|
+
throw new RedlineError('failed', `${CONFIG_FILE} is invalid: ${what}`);
|
|
97
|
+
};
|
|
98
|
+
export function parseConfig(raw) {
|
|
99
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
100
|
+
bad('expected an object');
|
|
101
|
+
const o = raw;
|
|
102
|
+
const str = (key) => typeof o[key] === 'string' && o[key] !== '' ? o[key] : bad(`${key} must be a non-empty string`);
|
|
103
|
+
const host = str('host');
|
|
104
|
+
if (!HOSTS.includes(host))
|
|
105
|
+
bad(`host must be one of ${HOSTS.join(', ')}`);
|
|
106
|
+
const vendors = o['vendors'];
|
|
107
|
+
if (!Array.isArray(vendors) || !vendors.every((v) => typeof v === 'string')) {
|
|
108
|
+
bad('vendors must be an array of strings');
|
|
109
|
+
}
|
|
110
|
+
const menuRaw = o['menu'];
|
|
111
|
+
if (typeof menuRaw !== 'object' || menuRaw === null)
|
|
112
|
+
bad('menu must be an object');
|
|
113
|
+
const menuObj = menuRaw;
|
|
114
|
+
const menu = {};
|
|
115
|
+
for (const key of MENU_KEYS) {
|
|
116
|
+
if (typeof menuObj[key] !== 'boolean')
|
|
117
|
+
bad(`menu.${key} must be a boolean`);
|
|
118
|
+
menu[key] = menuObj[key];
|
|
119
|
+
}
|
|
120
|
+
const pending = o['pendingAdmin'];
|
|
121
|
+
if (!Array.isArray(pending))
|
|
122
|
+
bad('pendingAdmin must be an array');
|
|
123
|
+
for (const entry of pending) {
|
|
124
|
+
if (typeof entry !== 'string' || !ADMIN_CAPABILITIES.includes(entry)) {
|
|
125
|
+
bad(`pendingAdmin contains an unknown capability "${String(entry)}"`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Only an explicit `false` deselects. A key some other tool wrote, or one a
|
|
129
|
+
// hand edit mistyped, must never be the way a repository falls below the
|
|
130
|
+
// standard — so anything that is not `false` reads back selected, and a
|
|
131
|
+
// whole missing object selects everything.
|
|
132
|
+
const capabilityRaw = o['capabilities'];
|
|
133
|
+
const capabilityObj = typeof capabilityRaw === 'object' && capabilityRaw !== null && !Array.isArray(capabilityRaw)
|
|
134
|
+
? capabilityRaw
|
|
135
|
+
: {};
|
|
136
|
+
const capabilities = {};
|
|
137
|
+
for (const key of CAPABILITY_KEYS)
|
|
138
|
+
capabilities[key] = capabilityObj[key] !== false;
|
|
139
|
+
const commandRaw = o['commandFiles'];
|
|
140
|
+
const commandFiles = {};
|
|
141
|
+
if (typeof commandRaw === 'object' && commandRaw !== null && !Array.isArray(commandRaw)) {
|
|
142
|
+
for (const [path, id] of Object.entries(commandRaw)) {
|
|
143
|
+
if (typeof id === 'string')
|
|
144
|
+
commandFiles[path] = id;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Anything not a recognised rung reads back as `observe`. A typo must not be
|
|
148
|
+
// able to raise enforcement on a repository, and the failure direction for an
|
|
149
|
+
// unreadable value is the one that blocks nobody.
|
|
150
|
+
const rungRaw = o['rung'];
|
|
151
|
+
const rung = isRung(rungRaw) ? rungRaw : 'observe';
|
|
152
|
+
const onboardedAt = str('onboardedAt');
|
|
153
|
+
const lastRunRaw = o['lastRunAt'];
|
|
154
|
+
const lastRunAt = typeof lastRunRaw === 'string' && lastRunRaw !== '' ? lastRunRaw : onboardedAt;
|
|
155
|
+
return {
|
|
156
|
+
standardsVersion: str('standardsVersion'),
|
|
157
|
+
cliVersion: str('cliVersion'),
|
|
158
|
+
host: host,
|
|
159
|
+
profile: str('profile'),
|
|
160
|
+
vendors: vendors,
|
|
161
|
+
menu,
|
|
162
|
+
pendingAdmin: pending,
|
|
163
|
+
onboardedAt,
|
|
164
|
+
lastRunAt,
|
|
165
|
+
rung,
|
|
166
|
+
localRules: o['localRules'] === true,
|
|
167
|
+
capabilities,
|
|
168
|
+
commandFiles,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
export function readConfig(cwd) {
|
|
172
|
+
const path = join(cwd, CONFIG_FILE);
|
|
173
|
+
if (!existsSync(path))
|
|
174
|
+
return null;
|
|
175
|
+
let raw;
|
|
176
|
+
try {
|
|
177
|
+
raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
throw new RedlineError('failed', `${CONFIG_FILE} is not valid JSON`, 'delete it and re-run redline init');
|
|
181
|
+
}
|
|
182
|
+
return parseConfig(raw);
|
|
183
|
+
}
|
|
184
|
+
export function writeConfig(cwd, config) {
|
|
185
|
+
writeFileSync(join(cwd, CONFIG_FILE), `${JSON.stringify(config, null, 2)}\n`);
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=redline-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redline-json.js","sourceRoot":"","sources":["../../cli/config/redline-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAmC,MAAM,uBAAuB,CAAC;AACnG,OAAO,EAAE,MAAM,EAAa,MAAM,sBAAsB,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AA8B3C,MAAM,CAAC,MAAM,eAAe,GAAmC,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;AA0CjG,MAAM,CAAC,MAAM,SAAS,GAA6B;IACjD,cAAc;IACd,kBAAkB;IAClB,eAAe;IACf,SAAS;IACT,wBAAwB;CACzB,CAAC;AAEF,sEAAsE;AACtE,+EAA+E;AAC/E,2DAA2D;AAC3D,MAAM,gBAAgB,GAAmE;IACvF,IAAI,EAAE,MAAM;IACZ,cAAc,EAAE,aAAa;IAC7B,MAAM,EAAE,QAAQ;IAChB,kBAAkB,EAAE,iBAAiB;CACtC,CAAC;AAEF,6EAA6E;AAC7E,4EAA4E;AAC5E,wEAAwE;AACxE,2EAA2E;AAC3E,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,sBAAsB,GAA2B;IAC5D,gBAAgB,EACd,4FAA4F;QAC5F,wFAAwF;QACxF,mBAAmB;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAEnE,8EAA8E;AAC9E,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAChF,6EAA6E;AAC7E,yBAAyB;AACzB,MAAM,UAAU,mBAAmB,CAAC,YAAkC;IACpE,OAAO,CAAC,YAAY,CAAC,IAAI,IAAI,YAAY,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,oEAAoE;AACpE,MAAM,UAAU,sBAAsB,CACpC,IAAoB,EACpB,YAAkC;IAElC,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3C,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG,KAAK,iBAAiB;YAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC;QACnE,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,CAAC,YAAY,CAAC,MAAM,IAAI,mBAAmB,CAAC,YAAY,CAAC,CAAC;QACvF,OAAO,GAAG,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAOD,+EAA+E;AAC/E,+EAA+E;AAC/E,YAAY;AACZ,MAAM,UAAU,mBAAmB,CAAC,IAAc,EAAE,IAAc;IAChE,MAAM,KAAK,GAAoB,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,IAAI,IAAI,+DAA+D,CAAC,CAAC;QAC3G,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI;QACxB,CAAC,IAAI,EAAE,KAAK,CAAC;QACb,CAAC,IAAI,EAAE,IAAI,CAAC;KACJ,EAAE,CAAC;QACX,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,EAAE;oBAAE,SAAS,CAAC,4BAA4B;gBAC9C,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,IAAI,IAAI,4BAA4B,SAAS,EAAE,CAAC,CAAC;YACnF,CAAC;YACD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,uBAAuB,IAAI,aAAa,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3E,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,KAAK,iBAAiB;gBAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAC;;gBACjE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,IAAY,EAAS,EAAE;IAClC,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,WAAW,gBAAgB,IAAI,EAAE,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC7F,MAAM,CAAC,GAAG,GAA8B,CAAC;IAEzC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAU,EAAE,CAClC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC,GAAG,CAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,6BAA6B,CAAC,CAAC;IAE9G,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,CAAE,KAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,GAAG,CAAC,uBAAuB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEjG,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;QAC5E,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,OAAkC,CAAC;IACnD,MAAM,IAAI,GAAG,EAAoB,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,oBAAoB,CAAC,CAAC;QAC5E,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAY,CAAC;IACtC,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAClE,KAAK,MAAM,KAAK,IAAI,OAAoB,EAAE,CAAC;QACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAE,kBAAwC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,gDAAgD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,yEAAyE;IACzE,wEAAwE;IACxE,2CAA2C;IAC3C,MAAM,aAAa,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;IACxC,MAAM,aAAa,GACjB,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QAC1F,CAAC,CAAE,aAAyC;QAC5C,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,YAAY,GAAG,EAA0B,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,eAAe;QAAE,YAAY,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;IAEpF,MAAM,UAAU,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;IACrC,MAAM,YAAY,GAA2B,EAAE,CAAC;IAChD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACxF,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAqC,CAAC,EAAE,CAAC;YAC/E,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACtD,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,kDAAkD;IAClD,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAS,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzD,MAAM,WAAW,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;IAEjG,OAAO;QACL,gBAAgB,EAAE,GAAG,CAAC,kBAAkB,CAAC;QACzC,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC;QAC7B,IAAI,EAAE,IAAY;QAClB,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC;QACvB,OAAO,EAAE,OAAmB;QAC5B,IAAI;QACJ,YAAY,EAAE,OAA4B;QAC1C,WAAW;QACX,SAAS;QACT,IAAI;QACJ,UAAU,EAAE,CAAC,CAAC,YAAY,CAAC,KAAK,IAAI;QACpC,YAAY;QACZ,YAAY;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,WAAW,oBAAoB,EAAE,mCAAmC,CAAC,CAAC;IAC5G,CAAC;IACD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,MAAqB;IAC5D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const EXIT_CODES = {
|
|
2
|
+
failed: 1,
|
|
3
|
+
usage: 2,
|
|
4
|
+
permission: 3,
|
|
5
|
+
host: 4,
|
|
6
|
+
};
|
|
7
|
+
export function exitCodeFor(kind) {
|
|
8
|
+
return EXIT_CODES[kind];
|
|
9
|
+
}
|
|
10
|
+
export class RedlineError extends Error {
|
|
11
|
+
kind;
|
|
12
|
+
exitCode;
|
|
13
|
+
hint;
|
|
14
|
+
constructor(kind, message, hint) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'RedlineError';
|
|
17
|
+
this.kind = kind;
|
|
18
|
+
this.exitCode = exitCodeFor(kind);
|
|
19
|
+
this.hint = hint;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function isRedlineError(e) {
|
|
23
|
+
return e instanceof RedlineError;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../cli/core/errors.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAqC;IACnD,MAAM,EAAE,CAAC;IACT,KAAK,EAAE,CAAC;IACR,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAsB;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAmB;IACvB,QAAQ,CAAS;IACjB,IAAI,CAAqB;IAElC,YAAY,IAAsB,EAAE,OAAe,EAAE,IAAa;QAChE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,CAAU;IACvC,OAAO,CAAC,YAAY,YAAY,CAAC;AACnC,CAAC"}
|
package/dist/core/git.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { RedlineError } from "./errors.js";
|
|
3
|
+
export const execGit = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
4
|
+
// git is a real system boundary: a rejected push, a protected branch, an
|
|
5
|
+
// expired credential and a failing pre-commit hook are all routine, and
|
|
6
|
+
// execFileSync reports them as a raw "Command failed: git push …" that the
|
|
7
|
+
// CLI's catch-all turns into "redline failed unexpectedly". Every mutating
|
|
8
|
+
// call below converts that into a RedlineError whose hint says what state
|
|
9
|
+
// the working tree was left in.
|
|
10
|
+
function stderrText(error) {
|
|
11
|
+
const stderr = typeof error === 'object' && error !== null
|
|
12
|
+
? error['stderr']
|
|
13
|
+
: undefined;
|
|
14
|
+
return typeof stderr === 'string'
|
|
15
|
+
? stderr
|
|
16
|
+
: Buffer.isBuffer(stderr)
|
|
17
|
+
? stderr.toString('utf8')
|
|
18
|
+
: error instanceof Error
|
|
19
|
+
? error.message
|
|
20
|
+
: String(error);
|
|
21
|
+
}
|
|
22
|
+
function gitFailure(error) {
|
|
23
|
+
return (stderrText(error).trim().split('\n').filter(Boolean).slice(-2).join(' — ') ||
|
|
24
|
+
'git reported no detail');
|
|
25
|
+
}
|
|
26
|
+
// The local non-fast-forward marker is " ! [rejected]"; a server-side policy
|
|
27
|
+
// rejection prints " ! [remote rejected]" instead, which this deliberately
|
|
28
|
+
// does not match — that one really is an access problem.
|
|
29
|
+
const NON_FAST_FORWARD = /non-fast-forward|\[rejected\]/;
|
|
30
|
+
export function createGit(cwd, run = execGit) {
|
|
31
|
+
const g = (...args) => run(args, cwd);
|
|
32
|
+
const currentBranch = () => {
|
|
33
|
+
try {
|
|
34
|
+
return g('rev-parse', '--abbrev-ref', 'HEAD');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return 'HEAD';
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
isRepo() {
|
|
42
|
+
try {
|
|
43
|
+
return g('rev-parse', '--is-inside-work-tree') === 'true';
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
remoteUrl(remote = 'origin') {
|
|
50
|
+
// No remote configured is a routine brownfield state, not a crash:
|
|
51
|
+
// the empty string flows into parseRemote(''), whose usage error
|
|
52
|
+
// already tells the user to `git remote add origin <url>`.
|
|
53
|
+
try {
|
|
54
|
+
return g('remote', 'get-url', remote);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
defaultBranch() {
|
|
61
|
+
try {
|
|
62
|
+
return g('symbolic-ref', '--short', 'refs/remotes/origin/HEAD').replace(/^origin\//, '');
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return 'main';
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
currentBranch,
|
|
69
|
+
diff(range) {
|
|
70
|
+
try {
|
|
71
|
+
// No colour, no external diff tool, full context off: the output is
|
|
72
|
+
// parsed and shown to a model, not to a terminal.
|
|
73
|
+
return g('diff', '--no-color', '--no-ext-diff', range);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw new RedlineError('usage', `cannot diff ${range}: ${stderrText(error)}`, 'check the ref exists — `git fetch` first if it is a branch you have not pulled');
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
mergeBase(ref) {
|
|
80
|
+
try {
|
|
81
|
+
return g('merge-base', ref, 'HEAD');
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new RedlineError('usage', `cannot find the merge base with ${ref}: ${stderrText(error)}`, 'fetch the base branch first, or pass --base with one you have');
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
diffStaged() {
|
|
88
|
+
try {
|
|
89
|
+
return g('diff', '--no-color', '--no-ext-diff', '--cached');
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw new RedlineError('usage', `cannot read the staged diff: ${stderrText(error)}`);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
checkoutNewBranch(name) {
|
|
96
|
+
try {
|
|
97
|
+
g('checkout', '-B', name);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw new RedlineError('host', `could not create the branch "${name}": ${gitFailure(error)}`, `you are still on "${currentBranch()}" and nothing was committed — resolve the git error and re-run`);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
checkoutBranch(name) {
|
|
104
|
+
try {
|
|
105
|
+
g('checkout', name);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new RedlineError('host', `could not switch back to "${name}": ${gitFailure(error)}`, `you are on "${currentBranch()}" — switch back yourself with: git checkout ${name}`);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
stagePaths(paths) {
|
|
112
|
+
if (paths.length === 0)
|
|
113
|
+
return;
|
|
114
|
+
g('add', '--', ...paths);
|
|
115
|
+
},
|
|
116
|
+
hasStagedChanges() {
|
|
117
|
+
try {
|
|
118
|
+
g('diff', '--cached', '--quiet');
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
commit(message) {
|
|
126
|
+
try {
|
|
127
|
+
g('commit', '-m', message);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw new RedlineError('host', `could not commit the Redline changes: ${gitFailure(error)}`, `the changes are still staged on "${currentBranch()}" — commit them yourself, or resolve the git error and re-run`);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
// A push that git refuses is overwhelmingly an access problem — no write
|
|
134
|
+
// permission, a protected branch, an expired credential — so it maps to
|
|
135
|
+
// `permission` rather than `host`: the operator needs rights, not a
|
|
136
|
+
// retry. The exception is a non-fast-forward rejection: that means a
|
|
137
|
+
// previous partial run already pushed this branch, and telling the
|
|
138
|
+
// operator to "get push access" would be the wrong diagnosis.
|
|
139
|
+
push(branch) {
|
|
140
|
+
try {
|
|
141
|
+
g('push', '--set-upstream', 'origin', branch);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (NON_FAST_FORWARD.test(stderrText(error))) {
|
|
145
|
+
throw new RedlineError('failed', `origin already has a "${branch}" branch this push cannot fast-forward: ${gitFailure(error)}`, `a previous run left it behind — delete it (git push origin --delete ${branch}) or merge its open pull request, then re-run`);
|
|
146
|
+
}
|
|
147
|
+
throw new RedlineError('permission', `could not push "${branch}" to origin: ${gitFailure(error)}`, `the Redline changes are committed locally on "${branch}" — push that branch and open the pull request yourself, or get push access and re-run`);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../cli/core/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,CAAC,MAAM,OAAO,GAAc,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAC9C,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAuBjG,yEAAyE;AACzE,wEAAwE;AACxE,2EAA2E;AAC3E,2EAA2E;AAC3E,0EAA0E;AAC1E,gCAAgC;AAChC,SAAS,UAAU,CAAC,KAAc;IAChC,MAAM,MAAM,GACV,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QACzC,CAAC,CAAE,KAAiC,CAAC,QAAQ,CAAC;QAC9C,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,OAAO,MAAM,KAAK,QAAQ;QAC/B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACzB,CAAC,CAAC,KAAK,YAAY,KAAK;gBACtB,CAAC,CAAC,KAAK,CAAC,OAAO;gBACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,CACL,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC1E,wBAAwB,CACzB,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,2EAA2E;AAC3E,yDAAyD;AACzD,MAAM,gBAAgB,GAAG,+BAA+B,CAAC;AAEzD,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAiB,OAAO;IAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,IAAc,EAAU,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,GAAW,EAAE;QACjC,IAAI,CAAC;YACH,OAAO,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,MAAM;YACJ,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,WAAW,EAAE,uBAAuB,CAAC,KAAK,MAAM,CAAC;YAC5D,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,SAAS,CAAC,MAAM,GAAG,QAAQ;YACzB,mEAAmE;YACnE,iEAAiE;YACjE,2DAA2D;YAC3D,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QACD,aAAa;YACX,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,cAAc,EAAE,SAAS,EAAE,0BAA0B,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC3F,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,aAAa;QACb,IAAI,CAAC,KAAK;YACR,IAAI,CAAC;gBACH,oEAAoE;gBACpE,kDAAkD;gBAClD,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,eAAe,KAAK,KAAK,UAAU,CAAC,KAAK,CAAC,EAAE,EAC5C,gFAAgF,CACjF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,mCAAmC,GAAG,KAAK,UAAU,CAAC,KAAK,CAAC,EAAE,EAC9D,+DAA+D,CAChE,CAAC;YACJ,CAAC;QACH,CAAC;QACD,UAAU;YACR,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;YAC9D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,gCAAgC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QACD,iBAAiB,CAAC,IAAI;YACpB,IAAI,CAAC;gBACH,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CACpB,MAAM,EACN,gCAAgC,IAAI,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,EAC7D,qBAAqB,aAAa,EAAE,gEAAgE,CACrG,CAAC;YACJ,CAAC;QACH,CAAC;QACD,cAAc,CAAC,IAAI;YACjB,IAAI,CAAC;gBACH,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACtB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CACpB,MAAM,EACN,6BAA6B,IAAI,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,EAC1D,eAAe,aAAa,EAAE,+CAA+C,IAAI,EAAE,CACpF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,UAAU,CAAC,KAAK;YACd,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC/B,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,gBAAgB;YACd,IAAI,CAAC;gBACH,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;gBACjC,OAAO,KAAK,CAAC;YACf,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,MAAM,CAAC,OAAO;YACZ,IAAI,CAAC;gBACH,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CACpB,MAAM,EACN,yCAAyC,UAAU,CAAC,KAAK,CAAC,EAAE,EAC5D,oCAAoC,aAAa,EAAE,+DAA+D,CACnH,CAAC;YACJ,CAAC;QACH,CAAC;QACD,yEAAyE;QACzE,wEAAwE;QACxE,oEAAoE;QACpE,qEAAqE;QACrE,mEAAmE;QACnE,8DAA8D;QAC9D,IAAI,CAAC,MAAM;YACT,IAAI,CAAC;gBACH,CAAC,CAAC,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC7C,MAAM,IAAI,YAAY,CACpB,QAAQ,EACR,yBAAyB,MAAM,2CAA2C,UAAU,CAAC,KAAK,CAAC,EAAE,EAC7F,uEAAuE,MAAM,+CAA+C,CAC7H,CAAC;gBACJ,CAAC;gBACD,MAAM,IAAI,YAAY,CACpB,YAAY,EACZ,mBAAmB,MAAM,gBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,EAC5D,iDAAiD,MAAM,wFAAwF,CAChJ,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/core/log.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const consoleSink = {
|
|
2
|
+
out: (line) => console.log(line),
|
|
3
|
+
err: (line) => console.error(line),
|
|
4
|
+
};
|
|
5
|
+
export function createLog(sink = consoleSink) {
|
|
6
|
+
return {
|
|
7
|
+
info: (line) => sink.out(line),
|
|
8
|
+
warn: (line) => sink.out(`warn ${line}`),
|
|
9
|
+
error(message, hint) {
|
|
10
|
+
sink.err(`error ${message}`);
|
|
11
|
+
if (hint)
|
|
12
|
+
sink.err(` ${hint}`);
|
|
13
|
+
},
|
|
14
|
+
report(findings) {
|
|
15
|
+
for (const finding of findings) {
|
|
16
|
+
const marker = finding.unknown ? ' ??' : finding.ok ? 'ok ' : 'FAIL';
|
|
17
|
+
sink.out(`${marker} ${finding.check.padEnd(22)} ${finding.detail}`);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../cli/core/log.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,GAAS;IACxB,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;CACnC,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,OAAa,WAAW;IAChD,OAAO;QACL,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAC9B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,KAAK,CAAC,OAAO,EAAE,IAAI;YACjB,IAAI,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;YAC9B,IAAI,IAAI;gBAAE,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,CAAC,QAAQ;YACb,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;gBACvE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The three severities of the output contract, and their order.
|
|
2
|
+
//
|
|
3
|
+
// The contract itself lives in standards/core.md and is what every finding —
|
|
4
|
+
// Redline's own or one ingested from another tool — is expressed in. There are
|
|
5
|
+
// exactly three, deliberately: "do not invent severities" is a rule in the
|
|
6
|
+
// standard, and a fourth would make every historical aggregate incomparable.
|
|
7
|
+
export const SEVERITIES = ['BLOCKER', 'HIGH', 'SUGGESTION'];
|
|
8
|
+
// Higher is more serious. Used to pick the most severe of a set, never to
|
|
9
|
+
// average them: an average severity is not a thing.
|
|
10
|
+
export const SEVERITY_RANK = {
|
|
11
|
+
BLOCKER: 3,
|
|
12
|
+
HIGH: 2,
|
|
13
|
+
SUGGESTION: 1,
|
|
14
|
+
};
|
|
15
|
+
export const isSeverity = (value) => typeof value === 'string' && SEVERITIES.includes(value);
|
|
16
|
+
//# sourceMappingURL=severity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.js","sourceRoot":"","sources":["../../cli/core/severity.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,CAAU,CAAC;AAGrE,0EAA0E;AAC1E,oDAAoD;AACpD,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;IACP,UAAU,EAAE,CAAC;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAc,EAAqB,EAAE,CAC9D,OAAO,KAAK,KAAK,QAAQ,IAAK,UAAgC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { RedlineError } from "./errors.js";
|
|
3
|
+
export function parseVersion(raw) {
|
|
4
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
5
|
+
throw new RedlineError('failed', 'package.json is not a JSON object');
|
|
6
|
+
}
|
|
7
|
+
const version = raw['version'];
|
|
8
|
+
if (typeof version !== 'string') {
|
|
9
|
+
throw new RedlineError('failed', 'package.json is missing a string "version" field');
|
|
10
|
+
}
|
|
11
|
+
return version;
|
|
12
|
+
}
|
|
13
|
+
const pkg = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
|
|
14
|
+
export const CLI_VERSION = parseVersion(pkg);
|
|
15
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../cli/core/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,mCAAmC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,OAAO,GAAI,GAA+B,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,kDAAkD,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtG,MAAM,CAAC,MAAM,WAAW,GAAW,YAAY,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const SKIP = new Set([
|
|
4
|
+
'.git',
|
|
5
|
+
'node_modules',
|
|
6
|
+
'dist',
|
|
7
|
+
'build',
|
|
8
|
+
'out',
|
|
9
|
+
'vendor',
|
|
10
|
+
'target',
|
|
11
|
+
'.next',
|
|
12
|
+
'.venv',
|
|
13
|
+
'__pycache__',
|
|
14
|
+
]);
|
|
15
|
+
const MAX_FILES = 5000;
|
|
16
|
+
const MAX_DEPTH = 6;
|
|
17
|
+
function isNonNullObject(value) {
|
|
18
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
function parsePackageManifest(raw) {
|
|
21
|
+
if (!isNonNullObject(raw))
|
|
22
|
+
return undefined;
|
|
23
|
+
const { dependencies, devDependencies } = raw;
|
|
24
|
+
if (dependencies !== undefined && !isNonNullObject(dependencies))
|
|
25
|
+
return undefined;
|
|
26
|
+
if (devDependencies !== undefined && !isNonNullObject(devDependencies))
|
|
27
|
+
return undefined;
|
|
28
|
+
const manifest = {};
|
|
29
|
+
if (dependencies !== undefined)
|
|
30
|
+
manifest.dependencies = dependencies;
|
|
31
|
+
if (devDependencies !== undefined) {
|
|
32
|
+
manifest.devDependencies = devDependencies;
|
|
33
|
+
}
|
|
34
|
+
return manifest;
|
|
35
|
+
}
|
|
36
|
+
export function scanRepo(cwd) {
|
|
37
|
+
const paths = [];
|
|
38
|
+
// Breadth-first so root-level manifests (go.mod, pom.xml) always land within
|
|
39
|
+
// MAX_FILES, even when an early subtree alone would exhaust the budget.
|
|
40
|
+
const queue = [{ dir: cwd, prefix: '', depth: 0 }];
|
|
41
|
+
let frame;
|
|
42
|
+
while ((frame = queue.shift()) !== undefined && paths.length < MAX_FILES) {
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = readdirSync(frame.dir, { withFileTypes: true });
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (paths.length >= MAX_FILES)
|
|
52
|
+
break;
|
|
53
|
+
if (SKIP.has(entry.name))
|
|
54
|
+
continue;
|
|
55
|
+
const rel = frame.prefix ? `${frame.prefix}/${entry.name}` : entry.name;
|
|
56
|
+
if (!entry.isDirectory()) {
|
|
57
|
+
paths.push(rel);
|
|
58
|
+
}
|
|
59
|
+
else if (entry.name.endsWith('.xcodeproj')) {
|
|
60
|
+
// Xcode projects are directories; emit a marker so the ios signal fires,
|
|
61
|
+
// and skip their metadata contents.
|
|
62
|
+
paths.push(rel);
|
|
63
|
+
}
|
|
64
|
+
else if (frame.depth < MAX_DEPTH) {
|
|
65
|
+
queue.push({ dir: join(frame.dir, entry.name), prefix: rel, depth: frame.depth + 1 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let packageJson;
|
|
70
|
+
try {
|
|
71
|
+
const raw = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
|
|
72
|
+
packageJson = parsePackageManifest(raw);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
packageJson = undefined;
|
|
76
|
+
}
|
|
77
|
+
return packageJson === undefined ? { paths } : { paths, packageJson };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../cli/detect/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const RULES = [
|
|
2
|
+
{
|
|
3
|
+
profile: 'mobile-rn',
|
|
4
|
+
when: (s) => s.dep('react-native') || s.has('metro.config.js') || s.has('metro.config.cjs')
|
|
5
|
+
? ['react-native dependency or metro config']
|
|
6
|
+
: null,
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
profile: 'fullstack-node',
|
|
10
|
+
when: (s) => (s.dep('@nestjs/core') || s.has('nest-cli.json')) && (s.dep('react') || s.ext('.tsx'))
|
|
11
|
+
? ['nest and react in one repository']
|
|
12
|
+
: null,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
profile: 'service-node',
|
|
16
|
+
when: (s) => (s.dep('@nestjs/core') || s.has('nest-cli.json') ? ['nest-cli.json'] : null),
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
profile: 'mobile-android',
|
|
20
|
+
when: (s) => s.has('AndroidManifest.xml') && (s.ext('.kt') || s.has('build.gradle.kts'))
|
|
21
|
+
? ['AndroidManifest.xml with kotlin sources']
|
|
22
|
+
: null,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
profile: 'mobile-ios',
|
|
26
|
+
when: (s) => s.has('Package.swift') || s.ext('.xcodeproj') || s.ext('.swift')
|
|
27
|
+
? ['swift package or sources']
|
|
28
|
+
: null,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
profile: 'service-java',
|
|
32
|
+
when: (s) => s.has('pom.xml') || s.has('build.gradle') || s.has('build.gradle.kts')
|
|
33
|
+
? ['maven or gradle build file']
|
|
34
|
+
: null,
|
|
35
|
+
},
|
|
36
|
+
{ profile: 'service-go', when: (s) => (s.has('go.mod') ? ['go.mod'] : null) },
|
|
37
|
+
{
|
|
38
|
+
profile: 'service-python',
|
|
39
|
+
when: (s) => s.has('pyproject.toml') || s.has('requirements.txt') || s.has('setup.py')
|
|
40
|
+
? ['python project file']
|
|
41
|
+
: null,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
profile: 'service-dotnet',
|
|
45
|
+
when: (s) => (s.ext('.csproj') || s.ext('.sln') ? ['dotnet project file'] : null),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
profile: 'web',
|
|
49
|
+
when: (s) => (s.dep('react') || s.ext('.tsx') || s.ext('.jsx') ? ['react sources'] : null),
|
|
50
|
+
},
|
|
51
|
+
{ profile: 'infra', when: (s) => (s.ext('.tf') ? ['terraform sources'] : null) },
|
|
52
|
+
];
|
|
53
|
+
export function proposeProfile(input) {
|
|
54
|
+
const names = new Set(input.paths.map((p) => p.split('/').at(-1) ?? p));
|
|
55
|
+
const deps = {
|
|
56
|
+
...(input.packageJson?.dependencies ?? {}),
|
|
57
|
+
...(input.packageJson?.devDependencies ?? {}),
|
|
58
|
+
};
|
|
59
|
+
const signals = {
|
|
60
|
+
has: (name) => names.has(name),
|
|
61
|
+
ext: (suffix) => input.paths.some((p) => p.endsWith(suffix)),
|
|
62
|
+
dep: (name) => name in deps,
|
|
63
|
+
};
|
|
64
|
+
for (const rule of RULES) {
|
|
65
|
+
const evidence = rule.when(signals);
|
|
66
|
+
if (evidence)
|
|
67
|
+
return { profile: rule.profile, confidence: 'high', evidence };
|
|
68
|
+
}
|
|
69
|
+
return { profile: 'tooling', confidence: 'low', evidence: ['no recognised stack signal'] };
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../../cli/detect/stack.ts"],"names":[],"mappings":"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"}
|