@golden-frijoles/kit 0.0.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/bin.mjs +108 -0
- package/dist/LICENSE +202 -0
- package/dist/NOTICE +7 -0
- package/dist/babysit-pr.mjs +213 -0
- package/dist/build-order-sync.mjs +141 -0
- package/dist/build-order.mjs +178 -0
- package/dist/cross-panel.mjs +216 -0
- package/dist/cross-panel.prompt.md +115 -0
- package/dist/doc-format.enforced.json +4 -0
- package/dist/doc-format.mjs +856 -0
- package/dist/doc-hygiene.mjs +279 -0
- package/dist/init.mjs +132 -0
- package/dist/lib/cross-agent-cli.mjs +695 -0
- package/dist/lib/gh-rest.mjs +229 -0
- package/dist/lib/golden-onboarding.mjs +204 -0
- package/dist/lib/jev.mjs +334 -0
- package/dist/lib/log-branch.mjs +106 -0
- package/dist/lib/pmo-benchmarks.mjs +61 -0
- package/dist/lib/pmo-delivery.mjs +102 -0
- package/dist/lib/pmo-metrics.mjs +200 -0
- package/dist/lib/pmo-templates.mjs +132 -0
- package/dist/lib/pmo-window-log.mjs +99 -0
- package/dist/lib/project-root.mjs +78 -0
- package/dist/lib/prose-brief.mjs +191 -0
- package/dist/lib/prose-guard.mjs +761 -0
- package/dist/lib/prose-writer.mjs +410 -0
- package/dist/lib/report-registry.mjs +469 -0
- package/dist/lib/reporting-config.mjs +266 -0
- package/dist/lib/roadmap-contract.mjs +305 -0
- package/dist/lib/roadmap-status-buckets.mjs +20 -0
- package/dist/lib/standup-deck.mjs +120 -0
- package/dist/lib/telegram-format.mjs +91 -0
- package/dist/live-smoke.mjs +303 -0
- package/dist/pmo/benchmarks.json +77 -0
- package/dist/pmo/templates/metrics-sheet.md +27 -0
- package/dist/pmo/templates/monthly-stakeholder-packet.md +53 -0
- package/dist/pmo/templates/weekly-story-deck.md +66 -0
- package/dist/pmo-report.mjs +338 -0
- package/dist/preflight.mjs +444 -0
- package/dist/prose/cpo-persona.md +108 -0
- package/dist/prose/internal.task.md +48 -0
- package/dist/prose/standup.task.md +38 -0
- package/dist/prose/weekly.task.md +36 -0
- package/dist/prose-draft.mjs +198 -0
- package/dist/prose-lessons.md +59 -0
- package/dist/roadmap-extract.mjs +410 -0
- package/dist/skeleton/Roadmap/00-ideas/README.md +85 -0
- package/dist/skeleton/Roadmap/00-ideas/audits/.gitkeep +0 -0
- package/dist/skeleton/Roadmap/00-ideas/seeds/.gitkeep +0 -0
- package/dist/skeleton/Roadmap/LEARNINGS.md +164 -0
- package/dist/skeleton/Roadmap/README.md +67 -0
- package/dist/skeleton/Roadmap/WAYS-OF-WORKING.md +233 -0
- package/dist/standup/templates/daily-story-deck.md +46 -0
- package/dist/standup.mjs +634 -0
- package/dist/vercel-prune-previews.mjs +164 -0
- package/dist/weekly-recap.mjs +526 -0
- package/package.json +33 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// vercel-prune-previews.mjs — delete stale PREVIEW deployments for a Vercel project.
|
|
3
|
+
//
|
|
4
|
+
// Why: Vercel retains every deployment forever. Deleting a merged git branch does NOT remove its
|
|
5
|
+
// preview deployments — they linger as clutter (a deleted branch can leave a dozen). This prunes
|
|
6
|
+
// them. It NEVER touches production deployments (your rollback history) — only `target !== production`.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// node scripts/vercel-prune-previews.mjs --project <name> # DRY-RUN, all previews
|
|
10
|
+
// node scripts/vercel-prune-previews.mjs --project <name> --age 7 # only previews older than 7 days
|
|
11
|
+
// node scripts/vercel-prune-previews.mjs --project <name> --apply # actually delete (dry-run is the default)
|
|
12
|
+
// node scripts/vercel-prune-previews.mjs --project <name> --keep-branch feat/x,feat/y # protect open-PR branches
|
|
13
|
+
//
|
|
14
|
+
// `--project` is REQUIRED and has no default. An earlier version defaulted to the origin project's
|
|
15
|
+
// name, which meant a fresh checkout ran confidently against SOMEONE ELSE'S Vercel project — a
|
|
16
|
+
// wrong-target delete is exactly the failure a default should never be able to cause.
|
|
17
|
+
//
|
|
18
|
+
// ALWAYS pass --keep-branch for any branch that still has an OPEN PR (its preview is the live review
|
|
19
|
+
// target) — or just run after that PR merges. Production deployments are never touched.
|
|
20
|
+
//
|
|
21
|
+
// Token resolution (first that works): VERCEL_API_TOKEN / VERCEL_TOKEN env, else the local Vercel
|
|
22
|
+
// CLI login (auth.json). Team: VERCEL_TEAM_ID env, else auto-detected from the account's first team.
|
|
23
|
+
// Zero npm deps — Node 18+ (global fetch).
|
|
24
|
+
|
|
25
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
26
|
+
import { join } from 'node:path';
|
|
27
|
+
|
|
28
|
+
const API = 'https://api.vercel.com';
|
|
29
|
+
|
|
30
|
+
function arg(name, def = undefined) {
|
|
31
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
32
|
+
if (i < 0) return def;
|
|
33
|
+
const next = process.argv[i + 1];
|
|
34
|
+
return next && !next.startsWith('--') ? next : true;
|
|
35
|
+
}
|
|
36
|
+
const PROJECT_ARG = arg('project');
|
|
37
|
+
if (!PROJECT_ARG || PROJECT_ARG === true) {
|
|
38
|
+
console.error('vercel-prune-previews: --project <name> is required (no default, by design).');
|
|
39
|
+
console.error(' Pass the Vercel project this repo deploys to. There is deliberately no fallback:');
|
|
40
|
+
console.error(' a defaulted project name means pruning whatever project the default happens to');
|
|
41
|
+
console.error(' point at, which is a destructive no-op at best and the wrong target at worst.');
|
|
42
|
+
process.exit(2);
|
|
43
|
+
}
|
|
44
|
+
const PROJECT = String(PROJECT_ARG);
|
|
45
|
+
const AGE_DAYS = Number(arg('age', 0)); // delete previews strictly older than this many days
|
|
46
|
+
const APPLY = !!arg('apply', false); // dry-run unless --apply
|
|
47
|
+
const KEEP = new Set(
|
|
48
|
+
String(arg('keep-branch', '') || '')
|
|
49
|
+
.split(',')
|
|
50
|
+
.map((s) => s.trim())
|
|
51
|
+
.filter(Boolean)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
function resolveToken() {
|
|
55
|
+
if (process.env.VERCEL_API_TOKEN) return process.env.VERCEL_API_TOKEN;
|
|
56
|
+
if (process.env.VERCEL_TOKEN) return process.env.VERCEL_TOKEN;
|
|
57
|
+
const candidates = [
|
|
58
|
+
join(process.env.HOME || '', 'Library/Application Support/com.vercel.cli/auth.json'),
|
|
59
|
+
join(
|
|
60
|
+
process.env.XDG_DATA_HOME || join(process.env.HOME || '', '.local/share'),
|
|
61
|
+
'com.vercel.cli/auth.json'
|
|
62
|
+
),
|
|
63
|
+
join(process.env.HOME || '', '.vercel/auth.json'),
|
|
64
|
+
];
|
|
65
|
+
for (const p of candidates) {
|
|
66
|
+
try {
|
|
67
|
+
if (existsSync(p)) {
|
|
68
|
+
const t = JSON.parse(readFileSync(p, 'utf8')).token;
|
|
69
|
+
if (t) return t;
|
|
70
|
+
}
|
|
71
|
+
} catch {}
|
|
72
|
+
}
|
|
73
|
+
console.error('No Vercel token: set VERCEL_API_TOKEN or run `vercel login`.');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
const TOKEN = resolveToken();
|
|
77
|
+
const H = { Authorization: `Bearer ${TOKEN}` };
|
|
78
|
+
|
|
79
|
+
async function api(path) {
|
|
80
|
+
const r = await fetch(`${API}${path}`, { headers: H });
|
|
81
|
+
const j = await r.json();
|
|
82
|
+
if (!r.ok) throw new Error(`${path} → ${r.status} ${JSON.stringify(j).slice(0, 200)}`);
|
|
83
|
+
return j;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function resolveTeamId() {
|
|
87
|
+
if (process.env.VERCEL_TEAM_ID) return process.env.VERCEL_TEAM_ID;
|
|
88
|
+
const j = await api('/v2/teams');
|
|
89
|
+
return j.teams && j.teams[0] && j.teams[0].id ? j.teams[0].id : '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
(async () => {
|
|
93
|
+
const teamId = await resolveTeamId();
|
|
94
|
+
const tq = teamId ? `teamId=${teamId}` : '';
|
|
95
|
+
const proj = await api(`/v9/projects/${PROJECT}?${tq}`);
|
|
96
|
+
const projectId = proj.id;
|
|
97
|
+
|
|
98
|
+
// Page all deployments; keep only previews (target !== 'production').
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
let until,
|
|
101
|
+
previews = [],
|
|
102
|
+
total = 0;
|
|
103
|
+
for (let i = 0; i < 100; i++) {
|
|
104
|
+
const j = await api(
|
|
105
|
+
`/v6/deployments?projectId=${projectId}&${tq}&limit=100${until ? `&until=${until}` : ''}`
|
|
106
|
+
);
|
|
107
|
+
if (!j.deployments || !j.deployments.length) break;
|
|
108
|
+
total += j.deployments.length;
|
|
109
|
+
for (const d of j.deployments) {
|
|
110
|
+
if (d.target === 'production') continue; // never touch production
|
|
111
|
+
if (['BUILDING', 'QUEUED', 'INITIALIZING'].includes(d.state)) continue; // skip in-flight
|
|
112
|
+
const branch = (d.meta && (d.meta.githubCommitRef || d.meta.gitBranch)) || '(unknown)';
|
|
113
|
+
if (KEEP.has(branch)) continue; // protect live / open-PR branches
|
|
114
|
+
const ageDays = (now - d.created) / 86400000;
|
|
115
|
+
if (ageDays >= AGE_DAYS) previews.push({ id: d.uid, age: ageDays, branch });
|
|
116
|
+
}
|
|
117
|
+
if (!j.pagination || !j.pagination.next) break;
|
|
118
|
+
until = j.pagination.next;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(`Project ${PROJECT} (${projectId}) — scanned ${total} deployments.`);
|
|
122
|
+
console.log(
|
|
123
|
+
`Preview deployments to remove (target!=production${AGE_DAYS ? `, older than ${AGE_DAYS}d` : ''}): ${previews.length}`
|
|
124
|
+
);
|
|
125
|
+
const byBranch = {};
|
|
126
|
+
for (const p of previews) byBranch[p.branch] = (byBranch[p.branch] || 0) + 1;
|
|
127
|
+
Object.entries(byBranch)
|
|
128
|
+
.sort((a, b) => b[1] - a[1])
|
|
129
|
+
.slice(0, 40)
|
|
130
|
+
.forEach(([b, n]) => console.log(` ${String(n).padStart(3)} ${b}`));
|
|
131
|
+
|
|
132
|
+
if (!previews.length) {
|
|
133
|
+
console.log('Nothing to prune.');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (!APPLY) {
|
|
137
|
+
console.log('\nDRY-RUN — re-run with --apply to delete the above.');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`\nDeleting ${previews.length} preview deployments…`);
|
|
142
|
+
let ok = 0,
|
|
143
|
+
fail = 0,
|
|
144
|
+
idx = 0;
|
|
145
|
+
const worker = async () => {
|
|
146
|
+
while (idx < previews.length) {
|
|
147
|
+
const p = previews[idx++];
|
|
148
|
+
try {
|
|
149
|
+
const r = await fetch(`${API}/v13/deployments/${p.id}?${tq}`, { method: 'DELETE', headers: H });
|
|
150
|
+
if (!r.ok) throw new Error(`${r.status} ${(await r.text()).slice(0, 120)}`);
|
|
151
|
+
ok++;
|
|
152
|
+
} catch (e) {
|
|
153
|
+
fail++;
|
|
154
|
+
console.error(` ! ${p.id} (${p.branch}): ${e.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
await Promise.all(Array.from({ length: 8 }, worker)); // small concurrency pool
|
|
159
|
+
console.log(`Done — deleted ${ok}, failed ${fail}.`);
|
|
160
|
+
if (fail) process.exit(1);
|
|
161
|
+
})().catch((e) => {
|
|
162
|
+
console.error(e.message || e);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|