@reddoorla/maintenance 0.65.0 → 0.65.3
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/README.md +17 -10
- package/dist/airtable-JUPGAI4R.js +9 -0
- package/dist/{announce-GFLKAPTT.js → announce-WXWOHR2I.js} +24 -9
- package/dist/announce-WXWOHR2I.js.map +1 -0
- package/dist/{bump-deps-3QQHYDKJ.js → bump-deps-2MAMI7DB.js} +6 -4
- package/dist/bump-deps-2MAMI7DB.js.map +1 -0
- package/dist/{chunk-MQM5YP4J.js → chunk-ARHDSMFK.js} +2 -2
- package/dist/{chunk-FUD4I2ZW.js → chunk-BTEBRTW4.js} +2 -2
- package/dist/{chunk-7RGQ4KLE.js → chunk-CCXVX5JN.js} +5 -1
- package/dist/chunk-CCXVX5JN.js.map +1 -0
- package/dist/{chunk-4A5PYCGB.js → chunk-IMMB64VH.js} +2 -2
- package/dist/{chunk-UATHDNWP.js → chunk-IRRZG66U.js} +13 -6
- package/dist/chunk-IRRZG66U.js.map +1 -0
- package/dist/{chunk-OQPMZ6BM.js → chunk-J7SZQUCW.js} +10 -2
- package/dist/{chunk-OQPMZ6BM.js.map → chunk-J7SZQUCW.js.map} +1 -1
- package/dist/{chunk-M5LX2VSR.js → chunk-JWA4FO2J.js} +3 -3
- package/dist/{chunk-FX3QBSUF.js → chunk-LCKKIJ22.js} +3 -3
- package/dist/{chunk-LM42CATB.js → chunk-MEP6PR32.js} +5 -4
- package/dist/chunk-MEP6PR32.js.map +1 -0
- package/dist/{chunk-CSTLFSGM.js → chunk-N5MZ6WRX.js} +2 -2
- package/dist/{chunk-OYN6H4CX.js → chunk-PMIKXAPF.js} +4 -4
- package/dist/{chunk-U3MF6RCS.js → chunk-SYTPVYIK.js} +13 -14
- package/dist/chunk-SYTPVYIK.js.map +1 -0
- package/dist/chunk-VPJ7N6P7.js +27 -0
- package/dist/chunk-VPJ7N6P7.js.map +1 -0
- package/dist/{chunk-FH7WQHD7.js → chunk-VUKSRWRD.js} +2 -2
- package/dist/{chunk-TC7Z5LG7.js → chunk-WCN54744.js} +30 -16
- package/dist/{chunk-TC7Z5LG7.js.map → chunk-WCN54744.js.map} +1 -1
- package/dist/{chunk-QSL3EJGI.js → chunk-WXNSLK4Q.js} +3 -3
- package/dist/{chunk-4GACMVNE.js → chunk-YEGHUODU.js} +17 -1
- package/dist/chunk-YEGHUODU.js.map +1 -0
- package/dist/{chunk-O65I7G7G.js → chunk-ZO7WNY57.js} +2 -2
- package/dist/cli/bin.js +14 -14
- package/dist/cli/commands/audit.js +7 -7
- package/dist/{convert-to-pnpm-ZO673UFB.js → convert-to-pnpm-3OEHYF76.js} +6 -4
- package/dist/convert-to-pnpm-3OEHYF76.js.map +1 -0
- package/dist/{digest-R3ROSGLP.js → digest-BTHXYYQZ.js} +3 -3
- package/dist/{github-signals-N5JGWHW2.js → github-signals-H7VU4EOH.js} +5 -5
- package/dist/index.d.ts +29 -7
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/{init-FOHNISF2.js → init-VA3H4OHM.js} +26 -9
- package/dist/init-VA3H4OHM.js.map +1 -0
- package/dist/{launch-TM3IHSSU.js → launch-OMHMW5OK.js} +9 -9
- package/dist/{lighthouse-airtable-5FHELRCA.js → lighthouse-airtable-4KWC3P72.js} +3 -3
- package/dist/{onboard-K2EL4MSG.js → onboard-2PLVVJWN.js} +10 -6
- package/dist/onboard-2PLVVJWN.js.map +1 -0
- package/dist/{orchestrate-OX3Z4DUI.js → orchestrate-6PKHJXLF.js} +4 -4
- package/dist/{renovate-dispatch-H25CQ36P.js → renovate-dispatch-K6VO5KWM.js} +3 -3
- package/dist/{report-UEYKO6WH.js → report-X3XPBRBO.js} +6 -6
- package/dist/reports/maintenance-email/assets/blurredTests.jpg +0 -0
- package/dist/{self-updating-YXOGQWH5.js → self-updating-VXVJSV5T.js} +8 -6
- package/dist/self-updating-VXVJSV5T.js.map +1 -0
- package/dist/{selftest-VE7CSGWE.js → selftest-FV4MO7TX.js} +6 -6
- package/dist/{svelte-codemods-745QM25J.js → svelte-codemods-5RXRRTMK.js} +8 -6
- package/dist/svelte-codemods-5RXRRTMK.js.map +1 -0
- package/dist/{sync-configs-NYC3Z625.js → sync-configs-TPJMRNRU.js} +10 -4
- package/dist/sync-configs-TPJMRNRU.js.map +1 -0
- package/dist/{upgrade-UBPPJ6HN.js → upgrade-7TN2XPFK.js} +8 -10
- package/dist/upgrade-7TN2XPFK.js.map +1 -0
- package/dist/{websites-CSVLSEVL.js → websites-EIPNY4DY.js} +2 -2
- package/dist/{write-audits-to-airtable-JCV7FYAW.js → write-audits-to-airtable-WVWFESZW.js} +4 -4
- package/package.json +1 -1
- package/dist/airtable-GGZJUGQB.js +0 -9
- package/dist/announce-GFLKAPTT.js.map +0 -1
- package/dist/bump-deps-3QQHYDKJ.js.map +0 -1
- package/dist/chunk-4GACMVNE.js.map +0 -1
- package/dist/chunk-7RGQ4KLE.js.map +0 -1
- package/dist/chunk-LM42CATB.js.map +0 -1
- package/dist/chunk-U3MF6RCS.js.map +0 -1
- package/dist/chunk-UATHDNWP.js.map +0 -1
- package/dist/convert-to-pnpm-ZO673UFB.js.map +0 -1
- package/dist/init-FOHNISF2.js.map +0 -1
- package/dist/onboard-K2EL4MSG.js.map +0 -1
- package/dist/self-updating-YXOGQWH5.js.map +0 -1
- package/dist/svelte-codemods-745QM25J.js.map +0 -1
- package/dist/sync-configs-NYC3Z625.js.map +0 -1
- package/dist/upgrade-UBPPJ6HN.js.map +0 -1
- /package/dist/{airtable-GGZJUGQB.js.map → airtable-JUPGAI4R.js.map} +0 -0
- /package/dist/{chunk-MQM5YP4J.js.map → chunk-ARHDSMFK.js.map} +0 -0
- /package/dist/{chunk-FUD4I2ZW.js.map → chunk-BTEBRTW4.js.map} +0 -0
- /package/dist/{chunk-4A5PYCGB.js.map → chunk-IMMB64VH.js.map} +0 -0
- /package/dist/{chunk-M5LX2VSR.js.map → chunk-JWA4FO2J.js.map} +0 -0
- /package/dist/{chunk-FX3QBSUF.js.map → chunk-LCKKIJ22.js.map} +0 -0
- /package/dist/{chunk-CSTLFSGM.js.map → chunk-N5MZ6WRX.js.map} +0 -0
- /package/dist/{chunk-OYN6H4CX.js.map → chunk-PMIKXAPF.js.map} +0 -0
- /package/dist/{chunk-FH7WQHD7.js.map → chunk-VUKSRWRD.js.map} +0 -0
- /package/dist/{chunk-QSL3EJGI.js.map → chunk-WXNSLK4Q.js.map} +0 -0
- /package/dist/{chunk-O65I7G7G.js.map → chunk-ZO7WNY57.js.map} +0 -0
- /package/dist/{digest-R3ROSGLP.js.map → digest-BTHXYYQZ.js.map} +0 -0
- /package/dist/{github-signals-N5JGWHW2.js.map → github-signals-H7VU4EOH.js.map} +0 -0
- /package/dist/{launch-TM3IHSSU.js.map → launch-OMHMW5OK.js.map} +0 -0
- /package/dist/{lighthouse-airtable-5FHELRCA.js.map → lighthouse-airtable-4KWC3P72.js.map} +0 -0
- /package/dist/{orchestrate-OX3Z4DUI.js.map → orchestrate-6PKHJXLF.js.map} +0 -0
- /package/dist/{renovate-dispatch-H25CQ36P.js.map → renovate-dispatch-K6VO5KWM.js.map} +0 -0
- /package/dist/{report-UEYKO6WH.js.map → report-X3XPBRBO.js.map} +0 -0
- /package/dist/{selftest-VE7CSGWE.js.map → selftest-FV4MO7TX.js.map} +0 -0
- /package/dist/{websites-CSVLSEVL.js.map → websites-EIPNY4DY.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-JCV7FYAW.js.map → write-audits-to-airtable-WVWFESZW.js.map} +0 -0
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadBundledImages,
|
|
11
11
|
renderReportHtml,
|
|
12
12
|
resolveCopy
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SYTPVYIK.js";
|
|
14
14
|
import {
|
|
15
15
|
checklistFor,
|
|
16
16
|
isChecklistComplete,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
listWebsites,
|
|
25
25
|
siteSlug,
|
|
26
26
|
updateLaunched
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-CCXVX5JN.js";
|
|
28
28
|
import {
|
|
29
29
|
openBase,
|
|
30
30
|
readAirtableConfig
|
|
@@ -303,4 +303,4 @@ export {
|
|
|
303
303
|
parseAddresses,
|
|
304
304
|
isProbablyEmail
|
|
305
305
|
};
|
|
306
|
-
//# sourceMappingURL=chunk-
|
|
306
|
+
//# sourceMappingURL=chunk-WXNSLK4Q.js.map
|
|
@@ -106,6 +106,22 @@ function makeGitHub(deps) {
|
|
|
106
106
|
}
|
|
107
107
|
return present;
|
|
108
108
|
},
|
|
109
|
+
async fileContentsOnBranch(repo, branch, path) {
|
|
110
|
+
assertUrlSegment("branch", branch);
|
|
111
|
+
assertUrlSegment("path", path);
|
|
112
|
+
const r = await spawn(
|
|
113
|
+
"gh",
|
|
114
|
+
[
|
|
115
|
+
"api",
|
|
116
|
+
`repos/${repo}/contents/${path}?ref=${branch}`,
|
|
117
|
+
"-H",
|
|
118
|
+
"Accept: application/vnd.github.raw"
|
|
119
|
+
],
|
|
120
|
+
{ env, timeoutMs: 6e4 }
|
|
121
|
+
);
|
|
122
|
+
if (r.code !== 0) return null;
|
|
123
|
+
return r.stdout;
|
|
124
|
+
},
|
|
109
125
|
async branchProtectionContexts(repo, branch) {
|
|
110
126
|
assertUrlSegment("branch", branch);
|
|
111
127
|
const r = await spawn(
|
|
@@ -239,4 +255,4 @@ export {
|
|
|
239
255
|
assertUrlSegment,
|
|
240
256
|
makeGitHub
|
|
241
257
|
};
|
|
242
|
-
//# sourceMappingURL=chunk-
|
|
258
|
+
//# sourceMappingURL=chunk-YEGHUODU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/github/gh.ts"],"sourcesContent":["import { defaultSpawn, type SpawnFn } from \"../audits/util/spawn.js\";\n\n/** Aggregate CI state of a PR's head commit, normalized from GitHub's rollup. */\nexport type CiState = \"passing\" | \"failing\" | \"pending\" | \"none\";\n\n/** GitHub's computed mergeability of a PR. `UNKNOWN` is transient — GitHub is\n * still computing it (e.g. right after a push) — so it should be read as \"not\n * known to conflict\", never as conflicting. */\nexport type PrMergeable = \"MERGEABLE\" | \"CONFLICTING\" | \"UNKNOWN\";\n\n/** A minimal open-PR summary with its head-commit CI rollup state + mergeability. */\nexport type PullRequestSummary = {\n number: number;\n title: string;\n url: string;\n headRef: string;\n ciState: CiState;\n mergeable: PrMergeable;\n};\n\n/**\n * Reject a value before it's interpolated into a `gh api` URL path. The\n * `owner/repo` split methods already validate shape; this is the defense-in-depth\n * guard for the `branch` and file-`path` segments. An unexpected value (`..`, a\n * leading `/`, whitespace, or a URL-structural char like `?#%` or a backslash)\n * could otherwise retarget the endpoint (escape the intended path, smuggle a\n * query string, or traverse). Conservative by design — legit branch names like\n * `maint/self-updating-x` and paths like `.github/workflows/ci.yml` pass.\n *\n * Both branch refs (`maint/self-updating-x`) and file paths\n * (`.github/workflows/ci.yml`) legitimately contain `/`, so a single slash is\n * allowed; what's rejected is `..`, a leading `/`, whitespace, or a\n * URL-structural char (`?`, `#`, `%`, backslash) that could escape or retarget\n * the endpoint.\n */\nexport function assertUrlSegment(kind: \"branch\" | \"path\", value: string): void {\n const structural = /[\\s?#%\\\\]|\\.\\./;\n if (value.length === 0 || value.startsWith(\"/\") || structural.test(value)) {\n throw new Error(\n `unsafe ${kind} for gh api path (illegal characters or traversal): ${JSON.stringify(value)}`,\n );\n }\n}\n\n/** Map GitHub's `statusCheckRollup.state` enum to our normalized CiState. */\nfunction mapRollupState(state: string | null | undefined): CiState {\n switch (state) {\n case \"SUCCESS\":\n return \"passing\";\n case \"FAILURE\":\n case \"ERROR\":\n return \"failing\";\n case \"PENDING\":\n case \"EXPECTED\":\n return \"pending\";\n default:\n return \"none\"; // null/undefined = no checks reported\n }\n}\n\n/** Coerce GitHub's `mergeable` enum to our PrMergeable. Anything unexpected\n * (including the literal `UNKNOWN` GitHub returns while still computing) maps to\n * `UNKNOWN` — i.e. \"not known to conflict\". Only an explicit `CONFLICTING` is. */\nfunction mapMergeable(state: string | null | undefined): PrMergeable {\n return state === \"MERGEABLE\" || state === \"CONFLICTING\" ? state : \"UNKNOWN\";\n}\n\nexport type GitHub = {\n openPullRequest: (\n repo: string,\n pr: { head: string; base: string; title: string; body: string },\n ) => Promise<{ url: string }>;\n enableRepoAutoMerge: (repo: string) => Promise<void>;\n protectBranch: (repo: string, branch: string, requiredChecks: string[]) => Promise<void>;\n setRepoSecret: (repo: string, name: string, value: string) => Promise<void>;\n repoExists: (repo: string) => Promise<boolean>;\n defaultBranch: (repo: string) => Promise<string>;\n filesOnBranch: (repo: string, branch: string, paths: string[]) => Promise<string[]>;\n /** The raw contents of `path` on `branch`, or null when the file is absent (404).\n * Lets a caller detect a present-but-STALE file (content drift), where\n * `filesOnBranch` only sees existence. */\n fileContentsOnBranch: (repo: string, branch: string, path: string) => Promise<string | null>;\n branchProtectionContexts: (repo: string, branch: string) => Promise<string[]>;\n secretExists: (repo: string, name: string) => Promise<boolean>;\n autoMergeEnabled: (repo: string) => Promise<boolean>;\n findOpenSelfUpdatingPR: (repo: string) => Promise<string | null>;\n /** All open PRs on a repo with each head commit's normalized CI rollup state. */\n openPullRequests: (repo: string) => Promise<PullRequestSummary[]>;\n /** The default branch's latest-commit date + normalized CI rollup, one query. */\n defaultBranchStatus: (repo: string) => Promise<{ ciState: CiState; lastCommitAt: string | null }>;\n /** Renovate PRs (head `renovate/*`) merged at/after `sinceIso`. Used to record\n * `pr_automerged` fleet events. gh-shell (Actions only). */\n mergedRenovatePullRequests: (\n repo: string,\n sinceIso: string,\n ) => Promise<Array<{ number: number; title: string; url: string; mergedAt: string }>>;\n /** Fire a `workflow_dispatch` for `<workflow>` (a filename like `renovate.yml`)\n * on `ref`. Requires the token's `actions:write` scope; a 404 (no such\n * workflow) or 403 (missing scope) surfaces as a thrown error. */\n dispatchWorkflow: (repo: string, workflow: string, ref: string) => Promise<void>;\n};\n\nexport function makeGitHub(deps: { token: string; spawn?: SpawnFn }): GitHub {\n const spawn = deps.spawn ?? defaultSpawn;\n const env = { ...process.env, GH_TOKEN: deps.token };\n\n async function gh(args: string[]): Promise<string> {\n const r = await spawn(\"gh\", args, { env, timeoutMs: 60_000 });\n if (r.code !== 0) throw new Error(`gh ${args[0]} failed (code ${r.code}): ${r.stderr.trim()}`);\n return r.stdout;\n }\n\n return {\n async openPullRequest(repo, pr) {\n const out = await gh([\n \"pr\",\n \"create\",\n \"--repo\",\n repo,\n \"--head\",\n pr.head,\n \"--base\",\n pr.base,\n \"--title\",\n pr.title,\n \"--body\",\n pr.body,\n ]);\n return { url: out.trim() };\n },\n async enableRepoAutoMerge(repo) {\n await gh([\"api\", \"-X\", \"PATCH\", `repos/${repo}`, \"-F\", \"allow_auto_merge=true\"]);\n },\n async protectBranch(repo, branch, requiredChecks) {\n assertUrlSegment(\"branch\", branch);\n const args = [\n \"api\",\n \"-X\",\n \"PUT\",\n `repos/${repo}/branches/${branch}/protection`,\n \"-H\",\n \"Accept: application/vnd.github+json\",\n \"-F\",\n \"required_status_checks[strict]=true\",\n ...requiredChecks.flatMap((c) => [\"-f\", `required_status_checks[contexts][]=${c}`]),\n \"-F\",\n \"enforce_admins=true\",\n \"-F\",\n \"required_pull_request_reviews=null\",\n \"-F\",\n \"restrictions=null\",\n ];\n await gh(args);\n },\n async setRepoSecret(repo, name, value) {\n await gh([\"secret\", \"set\", name, \"--repo\", repo, \"--body\", value]);\n },\n async repoExists(repo) {\n const r = await spawn(\"gh\", [\"api\", `repos/${repo}`], { env, timeoutMs: 60_000 });\n return r.code === 0;\n },\n async defaultBranch(repo) {\n const out = await gh([\"api\", `repos/${repo}`, \"--jq\", \".default_branch\"]);\n return out.trim();\n },\n // filesOnBranch and branchProtectionContexts call `spawn` directly (not the\n // throwing `gh()` helper) because a 404 is an expected, meaningful answer —\n // \"file/protection absent\" — not an error. The remaining readers use `gh()`\n // since a non-200 there is a genuine failure (e.g. missing token scope).\n async filesOnBranch(repo, branch, paths) {\n assertUrlSegment(\"branch\", branch);\n const present: string[] = [];\n for (const p of paths) {\n assertUrlSegment(\"path\", p);\n const r = await spawn(\"gh\", [`api`, `repos/${repo}/contents/${p}?ref=${branch}`], {\n env,\n timeoutMs: 60_000,\n });\n if (r.code === 0) present.push(p);\n }\n return present;\n },\n async fileContentsOnBranch(repo, branch, path) {\n // Same spawn-directly rationale as filesOnBranch: a 404 (file absent) is an\n // expected answer (null), not an error. The `raw` media type returns the file\n // bytes verbatim (no base64 envelope) so the result compares directly against a\n // canonical template.\n assertUrlSegment(\"branch\", branch);\n assertUrlSegment(\"path\", path);\n const r = await spawn(\n \"gh\",\n [\n \"api\",\n `repos/${repo}/contents/${path}?ref=${branch}`,\n \"-H\",\n \"Accept: application/vnd.github.raw\",\n ],\n { env, timeoutMs: 60_000 },\n );\n if (r.code !== 0) return null; // 404 = file absent on this branch\n return r.stdout;\n },\n async branchProtectionContexts(repo, branch) {\n assertUrlSegment(\"branch\", branch);\n const r = await spawn(\n \"gh\",\n [\n \"api\",\n `repos/${repo}/branches/${branch}/protection`,\n \"--jq\",\n \".required_status_checks.contexts[]?\",\n ],\n { env, timeoutMs: 60_000 },\n );\n if (r.code !== 0) return []; // 404 = no protection configured\n return r.stdout\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n },\n async secretExists(repo, name) {\n // per_page=100: the REST default of 30 would false-negative on a repo with >30 secrets,\n // wrongly reporting an existing secret absent (→ a needless overwrite).\n const out = await gh([\n \"api\",\n `repos/${repo}/actions/secrets?per_page=100`,\n \"--jq\",\n \".secrets[].name\",\n ]);\n return out\n .split(\"\\n\")\n .map((l) => l.trim())\n .includes(name);\n },\n async autoMergeEnabled(repo) {\n const out = await gh([\"api\", `repos/${repo}`, \"--jq\", \".allow_auto_merge\"]);\n return out.trim() === \"true\";\n },\n async findOpenSelfUpdatingPR(repo) {\n // per_page=100: with the REST default of 30, a repo with >30 open PRs (plausible under\n // Renovate) could page past the existing self-updating PR and open a duplicate.\n const out = await gh([\n \"api\",\n `repos/${repo}/pulls?state=open&per_page=100`,\n \"--jq\",\n '.[] | select(.head.ref | startswith(\"maint/self-updating-\")) | .html_url',\n ]);\n const first = out\n .split(\"\\n\")\n .map((l) => l.trim())\n .find((l) => l.length > 0);\n return first ?? null;\n },\n async openPullRequests(repo) {\n const [owner, name, ...rest] = repo.split(\"/\");\n if (!owner || !name || rest.length > 0) {\n throw new Error(`openPullRequests: expected \"owner/repo\", got \"${repo}\"`);\n }\n const query =\n \"query($owner:String!,$name:String!){repository(owner:$owner,name:$name){\" +\n \"pullRequests(states:OPEN,first:100,orderBy:{field:CREATED_AT,direction:DESC}){nodes{number title url headRefName mergeable \" +\n \"commits(last:1){nodes{commit{statusCheckRollup{state}}}}}}}}\";\n const out = await gh([\n \"api\",\n \"graphql\",\n \"-f\",\n `query=${query}`,\n \"-F\",\n `owner=${owner}`,\n \"-F\",\n `name=${name}`,\n ]);\n const parsed = JSON.parse(out) as {\n data?: {\n repository?: {\n pullRequests?: {\n nodes?: Array<{\n number: number;\n title: string;\n url: string;\n headRefName: string;\n mergeable?: string;\n commits?: {\n nodes?: Array<{ commit?: { statusCheckRollup?: { state?: string } } }>;\n };\n }>;\n };\n };\n };\n };\n const nodes = parsed.data?.repository?.pullRequests?.nodes ?? [];\n return nodes.map((n) => ({\n number: n.number,\n title: n.title,\n url: n.url,\n headRef: n.headRefName,\n ciState: mapRollupState(n.commits?.nodes?.[0]?.commit?.statusCheckRollup?.state),\n mergeable: mapMergeable(n.mergeable),\n }));\n },\n async defaultBranchStatus(repo) {\n const [owner, name, ...rest] = repo.split(\"/\");\n if (!owner || !name || rest.length > 0) {\n throw new Error(`defaultBranchStatus: expected \"owner/repo\", got \"${repo}\"`);\n }\n const query =\n \"query($owner:String!,$name:String!){repository(owner:$owner,name:$name){\" +\n \"defaultBranchRef{target{... on Commit{committedDate statusCheckRollup{state}}}}}}\";\n const out = await gh([\n \"api\",\n \"graphql\",\n \"-f\",\n `query=${query}`,\n \"-F\",\n `owner=${owner}`,\n \"-F\",\n `name=${name}`,\n ]);\n const parsed = JSON.parse(out) as {\n data?: {\n repository?: {\n defaultBranchRef?: {\n target?: { committedDate?: string; statusCheckRollup?: { state?: string } | null };\n } | null;\n };\n };\n };\n const target = parsed.data?.repository?.defaultBranchRef?.target;\n return {\n ciState: mapRollupState(target?.statusCheckRollup?.state),\n lastCommitAt: target?.committedDate ?? null,\n };\n },\n async mergedRenovatePullRequests(repo, sinceIso) {\n const [owner, name, ...rest] = repo.split(\"/\");\n if (!owner || !name || rest.length > 0) {\n throw new Error(`mergedRenovatePullRequests: expected \"owner/repo\", got \"${repo}\"`);\n }\n // per_page=50: comfortably covers a week of Renovate merges on one repo. The\n // list endpoint returns merged_at + head.ref, so the filter is local.\n const out = await gh([\n \"api\",\n `repos/${owner}/${name}/pulls?state=closed&sort=updated&direction=desc&per_page=50`,\n ]);\n const arr = JSON.parse(out) as Array<{\n number: number;\n title: string;\n html_url: string;\n merged_at: string | null;\n head?: { ref?: string };\n }>;\n return arr\n .filter(\n (p) =>\n p.merged_at !== null &&\n p.merged_at >= sinceIso && // ISO8601 UTC strings sort lexicographically\n (p.head?.ref ?? \"\").startsWith(\"renovate/\"),\n )\n .map((p) => ({\n number: p.number,\n title: p.title,\n url: p.html_url,\n mergedAt: p.merged_at as string,\n }));\n },\n async dispatchWorkflow(repo, workflow, ref) {\n const [owner, name, ...rest] = repo.split(\"/\");\n if (!owner || !name || rest.length > 0) {\n throw new Error(`dispatchWorkflow: expected \"owner/repo\", got \"${repo}\"`);\n }\n // Every segment interpolates into the API path, so guard them all like the\n // other write methods do (defense in depth). `owner`/`name` are the most\n // operator-controlled (typed into Airtable's \"Git repo\"); `workflow` is a\n // constant today; `ref` is repo-sourced. A junk value like `repo?x=1` would\n // otherwise smuggle a query string past the bare two-part shape check.\n assertUrlSegment(\"path\", owner);\n assertUrlSegment(\"path\", name);\n assertUrlSegment(\"path\", workflow);\n assertUrlSegment(\"branch\", ref);\n await gh([\n \"api\",\n \"-X\",\n \"POST\",\n `repos/${owner}/${name}/actions/workflows/${workflow}/dispatches`,\n \"-f\",\n `ref=${ref}`,\n ]);\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyGotchaCodemods
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-J7SZQUCW.js";
|
|
4
4
|
import {
|
|
5
5
|
withRecipe
|
|
6
6
|
} from "./chunk-XKOZUVK2.js";
|
|
@@ -243,4 +243,4 @@ async function upgradeSvelte4to5(site, opts = {}) {
|
|
|
243
243
|
export {
|
|
244
244
|
upgradeSvelte4to5
|
|
245
245
|
};
|
|
246
|
-
//# sourceMappingURL=chunk-
|
|
246
|
+
//# sourceMappingURL=chunk-ZO7WNY57.js.map
|
package/dist/cli/bin.js
CHANGED
|
@@ -105,7 +105,7 @@ cli.command("sync-configs [site]", "Sync canonical configs into a site.").option
|
|
|
105
105
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
106
106
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
107
107
|
async (site, opts) => runOrExit(
|
|
108
|
-
async () => (await import("../sync-configs-
|
|
108
|
+
async () => (await import("../sync-configs-TPJMRNRU.js")).runSyncConfigsCommand(site, opts),
|
|
109
109
|
opts
|
|
110
110
|
)
|
|
111
111
|
);
|
|
@@ -114,7 +114,7 @@ cli.command("bump-deps [site]", "Bump dependencies.").option("--group <group>",
|
|
|
114
114
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
115
115
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
116
116
|
async (site, opts) => runOrExit(
|
|
117
|
-
async () => (await import("../bump-deps-
|
|
117
|
+
async () => (await import("../bump-deps-2MAMI7DB.js")).runBumpDepsCommand(site, opts),
|
|
118
118
|
opts
|
|
119
119
|
)
|
|
120
120
|
);
|
|
@@ -123,7 +123,7 @@ cli.command(
|
|
|
123
123
|
"Bootstrap a repo to keep itself updated (CI + Renovate + auto-merge)."
|
|
124
124
|
).option("--dry", "List what would be enabled without writing or opening PRs").option("--fleet <inventory>", 'Inventory file (.json or .mjs/.js), or "airtable"').option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
125
125
|
async (site, opts) => runOrExit(
|
|
126
|
-
async () => (await import("../self-updating-
|
|
126
|
+
async () => (await import("../self-updating-VXVJSV5T.js")).runSelfUpdatingCommand(site, opts),
|
|
127
127
|
opts
|
|
128
128
|
)
|
|
129
129
|
);
|
|
@@ -132,7 +132,7 @@ cli.command("upgrade <upgrade> [site]", "Run a named upgrade recipe (svelte-4-to
|
|
|
132
132
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
133
133
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
134
134
|
async (upgrade, site, opts) => runOrExit(
|
|
135
|
-
async () => (await import("../upgrade-
|
|
135
|
+
async () => (await import("../upgrade-7TN2XPFK.js")).runUpgradeCommand(upgrade, site, opts),
|
|
136
136
|
opts
|
|
137
137
|
)
|
|
138
138
|
);
|
|
@@ -144,7 +144,7 @@ cli.command(
|
|
|
144
144
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
145
145
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
146
146
|
async (site, opts) => runOrExit(
|
|
147
|
-
async () => (await import("../convert-to-pnpm-
|
|
147
|
+
async () => (await import("../convert-to-pnpm-3OEHYF76.js")).runConvertToPnpmCommand(site, opts),
|
|
148
148
|
opts
|
|
149
149
|
)
|
|
150
150
|
);
|
|
@@ -153,7 +153,7 @@ cli.command("svelte-codemods [site]", "Apply Svelte 5 gotcha codemods to an alre
|
|
|
153
153
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
154
154
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
155
155
|
async (site, opts) => runOrExit(
|
|
156
|
-
async () => (await import("../svelte-codemods-
|
|
156
|
+
async () => (await import("../svelte-codemods-5RXRRTMK.js")).runSvelteCodemodsCommand(site, opts),
|
|
157
157
|
opts
|
|
158
158
|
)
|
|
159
159
|
);
|
|
@@ -165,7 +165,7 @@ cli.command(
|
|
|
165
165
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
166
166
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
167
167
|
async (site, opts) => runOrExit(
|
|
168
|
-
async () => (await import("../onboard-
|
|
168
|
+
async () => (await import("../onboard-2PLVVJWN.js")).runOnboardCommand(site, opts),
|
|
169
169
|
opts
|
|
170
170
|
)
|
|
171
171
|
);
|
|
@@ -176,14 +176,14 @@ cli.command(
|
|
|
176
176
|
"--fleet <inventory>",
|
|
177
177
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
178
178
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
179
|
-
async (site, opts) => runOrExit(async () => (await import("../init-
|
|
179
|
+
async (site, opts) => runOrExit(async () => (await import("../init-VA3H4OHM.js")).runInitCommand(site, opts), opts)
|
|
180
180
|
);
|
|
181
181
|
cli.command(
|
|
182
182
|
"launch <site>",
|
|
183
183
|
"Bootstrap + first-audit a site, then draft its launch email for approval."
|
|
184
184
|
).action(
|
|
185
185
|
async (site, opts) => runOrExit(
|
|
186
|
-
async () => (await import("../launch-
|
|
186
|
+
async () => (await import("../launch-OMHMW5OK.js")).runLaunchCommand(site, opts),
|
|
187
187
|
opts
|
|
188
188
|
)
|
|
189
189
|
);
|
|
@@ -192,7 +192,7 @@ cli.command(
|
|
|
192
192
|
"Draft the monthly-report announcement email for maintenance sites (all, or one) for approval."
|
|
193
193
|
).action(
|
|
194
194
|
async (site, opts) => runOrExit(
|
|
195
|
-
async () => (await import("../announce-
|
|
195
|
+
async () => (await import("../announce-WXWOHR2I.js")).runAnnounceCommand(site, opts),
|
|
196
196
|
opts
|
|
197
197
|
)
|
|
198
198
|
);
|
|
@@ -201,7 +201,7 @@ cli.command(
|
|
|
201
201
|
"Operator self-tests. kind=email: preview a report email for a site (or --all) to yourself."
|
|
202
202
|
).option("--type <type>", "Report type: announcement (default) | maintenance | testing | launch").option("--to <addr>", "Recipient(s), comma-separated. Default: OPERATOR_EMAIL.").option("--all", "Send a preview for every maintenance site (to --to/operator).").option("--dry-run", "Render only; write reports/<slug>/selftest-<type>.html; do not send.").action(
|
|
203
203
|
async (kind, site, opts) => runOrExit(
|
|
204
|
-
async () => (await import("../selftest-
|
|
204
|
+
async () => (await import("../selftest-FV4MO7TX.js")).runSelftestCommand(kind, site, opts),
|
|
205
205
|
opts
|
|
206
206
|
)
|
|
207
207
|
);
|
|
@@ -216,7 +216,7 @@ cli.command("report [site]", "Draft or send maintenance/testing reports.").optio
|
|
|
216
216
|
"Email the operator one daily digest of reports ready for approval (skips when empty)."
|
|
217
217
|
).action(
|
|
218
218
|
async (site, opts) => runOrExit(
|
|
219
|
-
async () => (await import("../report-
|
|
219
|
+
async () => (await import("../report-X3XPBRBO.js")).runReportCommand(site, opts),
|
|
220
220
|
opts
|
|
221
221
|
)
|
|
222
222
|
);
|
|
@@ -225,7 +225,7 @@ cli.command(
|
|
|
225
225
|
"Sweep the fleet for GitHub signals (Renovate-failing/CI/last-commit) and write Airtable."
|
|
226
226
|
).option("--fleet", "Run across every site in the Airtable inventory.").option("--write-airtable", "Write each site's signals back to its Websites row.").action(
|
|
227
227
|
async (opts) => runOrExit(
|
|
228
|
-
async () => (await import("../github-signals-
|
|
228
|
+
async () => (await import("../github-signals-H7VU4EOH.js")).runGitHubSignalsCommand({
|
|
229
229
|
fleet: opts.fleet,
|
|
230
230
|
writeAirtable: opts.writeAirtable
|
|
231
231
|
}),
|
|
@@ -243,7 +243,7 @@ cli.command(
|
|
|
243
243
|
"Trigger Renovate on fleet sites the security sweep flagged with critical/high vulns."
|
|
244
244
|
).option("--fleet", "Run across every active, repo-backed site in the Airtable inventory.").action(
|
|
245
245
|
async (opts) => runOrExit(
|
|
246
|
-
async () => (await import("../renovate-dispatch-
|
|
246
|
+
async () => (await import("../renovate-dispatch-K6VO5KWM.js")).runRenovateDispatchCommand({
|
|
247
247
|
fleet: opts.fleet
|
|
248
248
|
}),
|
|
249
249
|
opts
|
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
} from "../../chunk-4NAOR44V.js";
|
|
9
9
|
import {
|
|
10
10
|
resolveSites
|
|
11
|
-
} from "../../chunk-
|
|
11
|
+
} from "../../chunk-VUKSRWRD.js";
|
|
12
12
|
import {
|
|
13
13
|
ALL_AUDIT_NAMES,
|
|
14
14
|
runOneAudit
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-WCN54744.js";
|
|
16
16
|
import "../../chunk-LKGVSM2O.js";
|
|
17
17
|
import {
|
|
18
18
|
recordFleetEventsBestEffort
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import "../../chunk-PTPTVVY7.js";
|
|
21
21
|
import "../../chunk-XKKTK6WA.js";
|
|
22
22
|
import "../../chunk-GASBX52O.js";
|
|
23
|
-
import "../../chunk-
|
|
23
|
+
import "../../chunk-YEGHUODU.js";
|
|
24
24
|
import "../../chunk-FDIFTIXC.js";
|
|
25
25
|
import "../../chunk-HVOOCK6L.js";
|
|
26
26
|
import "../../chunk-XXTZBPUY.js";
|
|
@@ -231,9 +231,9 @@ ${skipNotice}`;
|
|
|
231
231
|
let writeBackFailed = false;
|
|
232
232
|
if (opts.writeAirtable !== void 0) {
|
|
233
233
|
const { openBase, readAirtableConfig } = await import("../../client-EPVO3FEH.js");
|
|
234
|
-
const { listWebsites } = await import("../../websites-
|
|
234
|
+
const { listWebsites } = await import("../../websites-EIPNY4DY.js");
|
|
235
235
|
if (opts.fleet !== void 0) {
|
|
236
|
-
const { writeFleetAuditsToAirtable, formatFleetWriteSummary } = await import("../../write-audits-to-airtable-
|
|
236
|
+
const { writeFleetAuditsToAirtable, formatFleetWriteSummary } = await import("../../write-audits-to-airtable-WVWFESZW.js");
|
|
237
237
|
const base = openBase(readAirtableConfig());
|
|
238
238
|
const websites = await listWebsites(base);
|
|
239
239
|
const fleetWrite = await writeFleetAuditsToAirtable({ base, websites, results });
|
|
@@ -249,8 +249,8 @@ ${skipNotice}`;
|
|
|
249
249
|
|
|
250
250
|
${formatFleetWriteSummary(fleetWrite)}`;
|
|
251
251
|
} else {
|
|
252
|
-
const { resolveSlugFromCwd } = await import("../../lighthouse-airtable-
|
|
253
|
-
const { writeAuditsToAirtable } = await import("../../write-audits-to-airtable-
|
|
252
|
+
const { resolveSlugFromCwd } = await import("../../lighthouse-airtable-4KWC3P72.js");
|
|
253
|
+
const { writeAuditsToAirtable } = await import("../../write-audits-to-airtable-WVWFESZW.js");
|
|
254
254
|
const slug = typeof opts.writeAirtable === "string" && opts.writeAirtable.length > 0 ? opts.writeAirtable : await resolveSlugFromCwd(cwd);
|
|
255
255
|
let writeSummary = null;
|
|
256
256
|
await new Listr(
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runRecipeOverSites
|
|
3
|
+
} from "./chunk-VPJ7N6P7.js";
|
|
1
4
|
import {
|
|
2
5
|
appendSkipNotice,
|
|
3
6
|
fleetWorkdir,
|
|
@@ -5,7 +8,7 @@ import {
|
|
|
5
8
|
} from "./chunk-4NAOR44V.js";
|
|
6
9
|
import {
|
|
7
10
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-VUKSRWRD.js";
|
|
9
12
|
import {
|
|
10
13
|
convertToPnpm
|
|
11
14
|
} from "./chunk-2X322ZES.js";
|
|
@@ -39,8 +42,7 @@ async function runConvertToPnpmCommand(site, opts) {
|
|
|
39
42
|
sites = prep.prepared;
|
|
40
43
|
skipped = prep.skipped;
|
|
41
44
|
}
|
|
42
|
-
const results =
|
|
43
|
-
for (const s of sites) results.push(await convertToPnpm(s));
|
|
45
|
+
const results = await runRecipeOverSites("convert-to-pnpm", sites, (s) => convertToPnpm(s));
|
|
44
46
|
const output = results.map(formatResult).join("\n");
|
|
45
47
|
const code = results.some((r) => r.status === "failed") ? 1 : 0;
|
|
46
48
|
return { output: appendSkipNotice(output, skipped), code };
|
|
@@ -48,4 +50,4 @@ async function runConvertToPnpmCommand(site, opts) {
|
|
|
48
50
|
export {
|
|
49
51
|
runConvertToPnpmCommand
|
|
50
52
|
};
|
|
51
|
-
//# sourceMappingURL=convert-to-pnpm-
|
|
53
|
+
//# sourceMappingURL=convert-to-pnpm-3OEHYF76.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/convert-to-pnpm.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { convertToPnpm } from \"../../recipes/convert-to-pnpm.js\";\nimport type { RecipeResult } from \"../../types.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\nimport { prepareFleetSites, appendSkipNotice, type SkippedSite } from \"../fleet/prepare-sites.js\";\nimport { runRecipeOverSites } from \"../fleet/run-recipe-over-sites.js\";\nimport { fleetWorkdir } from \"../../util/fleet-workdir.js\";\n\nexport type ConvertToPnpmCommandOptions = {\n fleet?: string;\n workdir?: string;\n cwd?: string;\n};\n\nfunction formatResult(r: RecipeResult): string {\n if (r.status === \"noop\") return `[${r.site}] noop: ${r.notes ?? \"\"}`;\n if (r.status === \"failed\") return `[${r.site}] failed: ${r.notes ?? \"\"}`;\n return `[${r.site}] applied: ${r.commits.length} commit(s)\\n${r.notes ?? \"\"}`;\n}\n\nexport async function runConvertToPnpmCommand(\n site: string | undefined,\n opts: ConvertToPnpmCommandOptions,\n): Promise<{ output: string; code: number }> {\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n\n let sites = await resolveSites({\n ...(site !== undefined ? { site } : {}),\n ...(opts.fleet !== undefined ? { fleet: opts.fleet } : {}),\n cwd,\n });\n\n let skipped: SkippedSite[] = [];\n if (opts.fleet) {\n const workdir = opts.workdir ?? fleetWorkdir();\n const prep = await prepareFleetSites(sites, { workdir });\n sites = prep.prepared;\n skipped = prep.skipped;\n }\n\n const results = await runRecipeOverSites(\"convert-to-pnpm\", sites, (s) => convertToPnpm(s));\n\n const output = results.map(formatResult).join(\"\\n\");\n const code = results.some((r) => r.status === \"failed\") ? 1 : 0;\n return { output: appendSkipNotice(output, skipped), code };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AAcxB,SAAS,aAAa,GAAyB;AAC7C,MAAI,EAAE,WAAW,OAAQ,QAAO,IAAI,EAAE,IAAI,WAAW,EAAE,SAAS,EAAE;AAClE,MAAI,EAAE,WAAW,SAAU,QAAO,IAAI,EAAE,IAAI,aAAa,EAAE,SAAS,EAAE;AACtE,SAAO,IAAI,EAAE,IAAI,cAAc,EAAE,QAAQ,MAAM;AAAA,EAAe,EAAE,SAAS,EAAE;AAC7E;AAEA,eAAsB,wBACpB,MACA,MAC2C;AAC3C,QAAM,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG,IAAI,QAAQ,IAAI;AAEvD,MAAI,QAAQ,MAAM,aAAa;AAAA,IAC7B,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AAED,MAAI,UAAyB,CAAC;AAC9B,MAAI,KAAK,OAAO;AACd,UAAM,UAAU,KAAK,WAAW,aAAa;AAC7C,UAAM,OAAO,MAAM,kBAAkB,OAAO,EAAE,QAAQ,CAAC;AACvD,YAAQ,KAAK;AACb,cAAU,KAAK;AAAA,EACjB;AAEA,QAAM,UAAU,MAAM,mBAAmB,mBAAmB,OAAO,CAAC,MAAM,cAAc,CAAC,CAAC;AAE1F,QAAM,SAAS,QAAQ,IAAI,YAAY,EAAE,KAAK,IAAI;AAClD,QAAM,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,IAAI,IAAI;AAC9D,SAAO,EAAE,QAAQ,iBAAiB,QAAQ,OAAO,GAAG,KAAK;AAC3D;","names":[]}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
diffAttention,
|
|
9
9
|
readDigestState,
|
|
10
10
|
writeDigestState
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-IMMB64VH.js";
|
|
12
12
|
import {
|
|
13
13
|
isIdempotencyConflict
|
|
14
14
|
} from "./chunk-OGGRFBL4.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import {
|
|
21
21
|
listWebsites,
|
|
22
22
|
siteSlug
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-CCXVX5JN.js";
|
|
24
24
|
import {
|
|
25
25
|
openBase,
|
|
26
26
|
readAirtableConfig
|
|
@@ -226,4 +226,4 @@ export {
|
|
|
226
226
|
renderDigestHtml,
|
|
227
227
|
runDigest
|
|
228
228
|
};
|
|
229
|
-
//# sourceMappingURL=digest-
|
|
229
|
+
//# sourceMappingURL=digest-BTHXYYQZ.js.map
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
} from "./chunk-PZQ3WED2.js";
|
|
4
4
|
import {
|
|
5
5
|
formatFleetWriteSummary
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-MEP6PR32.js";
|
|
7
|
+
import "./chunk-N5MZ6WRX.js";
|
|
8
8
|
import {
|
|
9
9
|
detectSignalEvents,
|
|
10
10
|
fleetSweptEvent
|
|
@@ -16,13 +16,13 @@ import "./chunk-PTPTVVY7.js";
|
|
|
16
16
|
import "./chunk-XKKTK6WA.js";
|
|
17
17
|
import {
|
|
18
18
|
makeGitHub
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-YEGHUODU.js";
|
|
20
20
|
import "./chunk-HVOOCK6L.js";
|
|
21
21
|
import {
|
|
22
22
|
listWebsites,
|
|
23
23
|
siteSlug,
|
|
24
24
|
updateGitHubSignals
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-CCXVX5JN.js";
|
|
26
26
|
import {
|
|
27
27
|
openBase,
|
|
28
28
|
readAirtableConfig
|
|
@@ -134,4 +134,4 @@ export {
|
|
|
134
134
|
githubSignalsExitCode,
|
|
135
135
|
runGitHubSignalsCommand
|
|
136
136
|
};
|
|
137
|
-
//# sourceMappingURL=github-signals-
|
|
137
|
+
//# sourceMappingURL=github-signals-H7VU4EOH.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -69,10 +69,12 @@ type BrowserRunner = {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
/** Result of probing a site's latest PRODUCTION Netlify deploy. Every field is
|
|
72
|
-
* nullable: a
|
|
73
|
-
*
|
|
72
|
+
* nullable: a site with no production deploy yet degrades to all-nulls (a real
|
|
73
|
+
* "none" verdict). A read FAILURE is NOT represented here — it surfaces as
|
|
74
|
+
* `{ ok: false }` on the enclosing `NetlifyDeployFetch` so it can't be mistaken
|
|
75
|
+
* for a verdict. See `NetlifyDeployFetch`.
|
|
74
76
|
* - `state` is Netlify's raw deploy state (`ready`/`error`/`building`/…), lower-cased,
|
|
75
|
-
* or null when
|
|
77
|
+
* or null when the site has no production deploy.
|
|
76
78
|
* - `deployedAt` is the deploy's publish/create time (ISO), or null.
|
|
77
79
|
* - `logUrl` links to the deploy (its live URL or the Netlify admin/build-log page).
|
|
78
80
|
* - `errorMessage` is Netlify's `error_message` for a failed build, or null. */
|
|
@@ -82,12 +84,28 @@ type NetlifyDeployCheck = {
|
|
|
82
84
|
logUrl: string | null;
|
|
83
85
|
errorMessage: string | null;
|
|
84
86
|
};
|
|
87
|
+
/** Outcome of probing Netlify, distinguishing "couldn't read" from "read OK".
|
|
88
|
+
* This distinction is load-bearing: `Deploy status` drives the cockpit's Broken
|
|
89
|
+
* band (an ALARM), so a transient read failure must NOT be allowed to clear a
|
|
90
|
+
* real `error` — unlike a degraded "no deploy yet", which is a real verdict.
|
|
91
|
+
* - `{ ok: false }` — the API was unreachable/unreadable (network error, non-2xx,
|
|
92
|
+
* malformed body). The caller persists nothing, leaving the prior status intact.
|
|
93
|
+
* - `{ ok: true, deploy }` — the API answered. `deploy` is the latest production
|
|
94
|
+
* deploy, or all-nulls when the site genuinely has no production deploy yet
|
|
95
|
+
* (a real verdict, safe to persist). */
|
|
96
|
+
type NetlifyDeployFetch = {
|
|
97
|
+
ok: false;
|
|
98
|
+
} | {
|
|
99
|
+
ok: true;
|
|
100
|
+
deploy: NetlifyDeployCheck;
|
|
101
|
+
};
|
|
85
102
|
/** Injected IO so the check is unit-testable without hitting the Netlify API.
|
|
86
|
-
* `fetchLatestProductionDeploy` returns
|
|
87
|
-
*
|
|
88
|
-
*
|
|
103
|
+
* `fetchLatestProductionDeploy` returns a `NetlifyDeployFetch` — `{ ok: false }`
|
|
104
|
+
* when the call couldn't be read, else `{ ok: true, deploy }` with the latest
|
|
105
|
+
* production deploy (or all-nulls for a site with none). `now` is the clock for
|
|
106
|
+
* the checked-at stamp. */
|
|
89
107
|
type NetlifyDeployDeps = {
|
|
90
|
-
fetchLatestProductionDeploy: (siteId: string) => Promise<
|
|
108
|
+
fetchLatestProductionDeploy: (siteId: string) => Promise<NetlifyDeployFetch>;
|
|
91
109
|
now: Date;
|
|
92
110
|
};
|
|
93
111
|
|
|
@@ -359,6 +377,10 @@ type WebsiteRow = {
|
|
|
359
377
|
/** Real installed-version drift: deps behind the registry's latest, from the
|
|
360
378
|
* committed lockfile (`pnpm outdated`). Null = not determined this run. */
|
|
361
379
|
depsOutdated: number | null;
|
|
380
|
+
/** Of {@link depsOutdated}, how many are a *major* version behind the
|
|
381
|
+
* registry's latest — the "majors available on npm" signal, distinct from the
|
|
382
|
+
* baseline-drift {@link depsMajorBehind}. Null = not determined this run. */
|
|
383
|
+
depsMajorOutdated: number | null;
|
|
362
384
|
securityVulnsCritical: number | null;
|
|
363
385
|
securityVulnsHigh: number | null;
|
|
364
386
|
securityVulnsModerate: number | null;
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-IMMB64VH.js";
|
|
2
2
|
import {
|
|
3
3
|
findDueReports
|
|
4
4
|
} from "./chunk-WVRPOXKH.js";
|
|
5
5
|
import {
|
|
6
6
|
upgradeSvelte4to5
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZO7WNY57.js";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_INIT_STEPS,
|
|
10
10
|
a11yFixturesPage,
|
|
11
11
|
init
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LCKKIJ22.js";
|
|
13
13
|
import {
|
|
14
14
|
convertToPnpm
|
|
15
15
|
} from "./chunk-2X322ZES.js";
|
|
16
16
|
import {
|
|
17
17
|
svelteCodemods
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-BTEBRTW4.js";
|
|
19
|
+
import "./chunk-J7SZQUCW.js";
|
|
20
20
|
import {
|
|
21
21
|
onboard,
|
|
22
22
|
selfCaretRange,
|
|
@@ -24,11 +24,11 @@ import {
|
|
|
24
24
|
} from "./chunk-ZYBOT5PM.js";
|
|
25
25
|
import {
|
|
26
26
|
draftReportForSite
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-JWA4FO2J.js";
|
|
28
28
|
import "./chunk-6LIWDIXU.js";
|
|
29
29
|
import {
|
|
30
30
|
sendApprovedReports
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-WXNSLK4Q.js";
|
|
32
32
|
import "./chunk-OGGRFBL4.js";
|
|
33
33
|
import "./chunk-GECESMVS.js";
|
|
34
34
|
import {
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
CHECK_CID,
|
|
37
37
|
loadBundledImages,
|
|
38
38
|
renderReportHtml
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-SYTPVYIK.js";
|
|
40
40
|
import {
|
|
41
41
|
checklistFor,
|
|
42
42
|
escapeHtml,
|
|
@@ -62,13 +62,13 @@ import {
|
|
|
62
62
|
runAudits,
|
|
63
63
|
runAuditsAcross,
|
|
64
64
|
securityAudit
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-WCN54744.js";
|
|
66
66
|
import "./chunk-LKGVSM2O.js";
|
|
67
67
|
import "./chunk-G2YRXV26.js";
|
|
68
68
|
import "./chunk-PTPTVVY7.js";
|
|
69
69
|
import "./chunk-XKKTK6WA.js";
|
|
70
70
|
import "./chunk-GASBX52O.js";
|
|
71
|
-
import "./chunk-
|
|
71
|
+
import "./chunk-YEGHUODU.js";
|
|
72
72
|
import {
|
|
73
73
|
fromJsonFile,
|
|
74
74
|
localPath
|
|
@@ -78,12 +78,12 @@ import "./chunk-XXTZBPUY.js";
|
|
|
78
78
|
import "./chunk-XTK5VIQB.js";
|
|
79
79
|
import {
|
|
80
80
|
fromAirtableBase
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-ARHDSMFK.js";
|
|
82
82
|
import "./chunk-U5SZ4FOP.js";
|
|
83
83
|
import {
|
|
84
84
|
SEVERITY_RANK,
|
|
85
85
|
siteSlug
|
|
86
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-CCXVX5JN.js";
|
|
87
87
|
import "./chunk-HN6I2XWI.js";
|
|
88
88
|
import "./chunk-WEKL2HYJ.js";
|
|
89
89
|
import "./chunk-6VAL7XJT.js";
|
|
@@ -749,13 +749,13 @@ function a11ySpan(value) {
|
|
|
749
749
|
const display = value === null ? DASH2 : String(value);
|
|
750
750
|
return `<span class="metric a11y">${escapeHtml(display)}</span>`;
|
|
751
751
|
}
|
|
752
|
-
function depsSpan(drifted, majorBehind, outdated) {
|
|
752
|
+
function depsSpan(drifted, majorBehind, outdated, majorOutdated) {
|
|
753
753
|
if (drifted === null || majorBehind === null) {
|
|
754
754
|
return `<span class="metric deps">${DASH2}</span>`;
|
|
755
755
|
}
|
|
756
756
|
const driftPart = drifted === 0 ? "0" : `${drifted} drifted (${majorBehind} major)`;
|
|
757
|
-
const
|
|
758
|
-
return `<span class="metric deps">${escapeHtml(
|
|
757
|
+
const outdatedPart = outdated === null ? "" : ` \xB7 ${outdated} outdated${majorOutdated === null ? "" : ` (${majorOutdated} major)`}`;
|
|
758
|
+
return `<span class="metric deps">${escapeHtml(driftPart + outdatedPart)}</span>`;
|
|
759
759
|
}
|
|
760
760
|
function securitySpan(critical, high, moderate, low) {
|
|
761
761
|
if (critical === null || high === null || moderate === null || low === null) {
|
|
@@ -792,7 +792,7 @@ function card(site) {
|
|
|
792
792
|
</span>
|
|
793
793
|
<span class="cluster health">
|
|
794
794
|
<span class="metric-label">a11y</span> ${a11ySpan(site.a11yViolations)}
|
|
795
|
-
<span class="metric-label">deps</span> ${depsSpan(site.depsDrifted, site.depsMajorBehind, site.depsOutdated)}
|
|
795
|
+
<span class="metric-label">deps</span> ${depsSpan(site.depsDrifted, site.depsMajorBehind, site.depsOutdated, site.depsMajorOutdated)}
|
|
796
796
|
<span class="metric-label">sec</span> ${securitySpan(
|
|
797
797
|
site.securityVulnsCritical,
|
|
798
798
|
site.securityVulnsHigh,
|