Skip to content

Commit 0c26629

Browse files
committed
fix(devx): give checklist-select.mjs a main(), so importing selectItems does not kill the importer
This one was the fatal shape in the ledger. Its top-level CLI ran on import: importing it for `selectItems` — the pure resolver the checklist-test skill's front half is built on — printed a usage block to the importer's stderr and called process.exit(2) mid-import. The probe's own sentinel never printed. The self-test block becomes selfTest(), the CLI block becomes main(), and both run only under isEntrypoint(import.meta.url). No executable line changed other than its enclosing scope; the process.exit() calls stay exactly where they were. Verified byte-for-byte against the pristine base tree, since a main() extraction moves executable lines where a wrap does not — stdout, stderr and exit code all cmp-clean on six legs: default (usage, exit 2), --self-test, `all --json`, `area:approvals`, `all --include-blocked`, and `nope.xxx` (the no-match exit-1 path). Import probe with clean argv: sentinel only, empty stderr, exit 0. check:entry-guard named it STALE before its ledger line went; ledger 9 -> 8.
1 parent 1304629 commit 0c26629

2 files changed

Lines changed: 43 additions & 33 deletions

File tree

‎scripts/check-entry-guard.mjs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,6 @@ const KNOWN_IMPORT_UNSAFE = new Set([
463463
'scripts/check-error-status-conformance.mjs',
464464
'scripts/check-query-options-erasure-ratchet.mjs',
465465
'scripts/check-release-page-status.mjs',
466-
'scripts/checklist-select.mjs',
467466
'scripts/objectui-range.mjs',
468467
'scripts/qa/qa-rollup.mjs',
469468
'scripts/ts-parse.mjs',

‎scripts/checklist-select.mjs‎

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import { readdirSync, readFileSync, existsSync } from 'node:fs';
3838
import { join, basename, dirname } from 'node:path';
39+
import { isEntrypoint } from './invoked-as.mjs';
3940

4041
const ROOT = new URL('..', import.meta.url).pathname;
4142
const AREAS_DIR = join(ROOT, 'docs/qa/platform-checklist/areas');
@@ -117,7 +118,7 @@ function isBlocked(it) {
117118
}
118119

119120
// ── self-test ────────────────────────────────────────────────────────────────
120-
if (process.argv.includes('--self-test')) {
121+
function selfTest() {
121122
const FIX = [
122123
{ id: 'a.one', status: 'active', priority: 'P0', surface: 'browser', since: 'v16', source: ['packages/foo/bar.ts'] },
123124
{ id: 'a.two', status: 'active', priority: 'P1', surface: 'api', since: 'v16.1', source: ['#3358'], blocked: { by: 'fixture', ref: '#1' } },
@@ -153,39 +154,49 @@ if (process.argv.includes('--self-test')) {
153154
}
154155

155156
// ── CLI ──────────────────────────────────────────────────────────────────────
156-
const args = process.argv.slice(2);
157-
const json = args.includes('--json');
158-
const includeBlocked = args.includes('--include-blocked');
159-
const selector = args.find((a) => !a.startsWith('--'));
160-
161-
if (!selector) {
162-
console.error('usage: node scripts/checklist-select.mjs <selector> [--json] [--include-blocked]');
163-
console.error(' selectors: <id> | area:<a> | capability:<k> | priority:P0 | surface:api | since:vN | file:<path> | all');
164-
process.exit(2);
165-
}
166-
if (!existsSync(AREAS_DIR)) {
167-
console.error(`checklist-select: ${AREAS_DIR} not found`);
168-
process.exit(1);
169-
}
157+
function main() {
158+
const args = process.argv.slice(2);
159+
const json = args.includes('--json');
160+
const includeBlocked = args.includes('--include-blocked');
161+
const selector = args.find((a) => !a.startsWith('--'));
170162

171-
const items = loadItems();
172-
const coverage = existsSync(COVERAGE) ? JSON.parse(readFileSync(COVERAGE, 'utf8')) : { metadataKinds: {} };
173-
let matched = selectItems(selector, items, coverage);
174-
const droppedBlocked = includeBlocked ? [] : matched.filter(isBlocked);
175-
if (!includeBlocked) matched = matched.filter((it) => !isBlocked(it));
163+
if (!selector) {
164+
console.error('usage: node scripts/checklist-select.mjs <selector> [--json] [--include-blocked]');
165+
console.error(' selectors: <id> | area:<a> | capability:<k> | priority:P0 | surface:api | since:vN | file:<path> | all');
166+
process.exit(2);
167+
}
168+
if (!existsSync(AREAS_DIR)) {
169+
console.error(`checklist-select: ${AREAS_DIR} not found`);
170+
process.exit(1);
171+
}
176172

177-
if (json) {
178-
process.stdout.write(JSON.stringify(matched.map((it) => ({ id: it.id, priority: it.priority, surface: it.surface, since: it.since, revision: it.revision })), null, 2) + '\n');
179-
}
173+
const items = loadItems();
174+
const coverage = existsSync(COVERAGE) ? JSON.parse(readFileSync(COVERAGE, 'utf8')) : { metadataKinds: {} };
175+
let matched = selectItems(selector, items, coverage);
176+
const droppedBlocked = includeBlocked ? [] : matched.filter(isBlocked);
177+
if (!includeBlocked) matched = matched.filter((it) => !isBlocked(it));
180178

181-
console.error(`\nselector: ${selector} → ${matched.length} runnable item(s)${droppedBlocked.length ? ` (${droppedBlocked.length} blocked, hidden — pass --include-blocked)` : ''}\n`);
182-
for (const it of matched) {
183-
console.error(` ${it.priority} ${String(it.surface).padEnd(8)} ${it.id}${isBlocked(it) ? ' [BLOCKED]' : ''}`);
184-
}
185-
if (droppedBlocked.length) {
186-
console.error(`\n hidden (blocked): ${droppedBlocked.map((i) => i.id).join(', ')}`);
179+
if (json) {
180+
process.stdout.write(JSON.stringify(matched.map((it) => ({ id: it.id, priority: it.priority, surface: it.surface, since: it.since, revision: it.revision })), null, 2) + '\n');
181+
}
182+
183+
console.error(`\nselector: ${selector} → ${matched.length} runnable item(s)${droppedBlocked.length ? ` (${droppedBlocked.length} blocked, hidden — pass --include-blocked)` : ''}\n`);
184+
for (const it of matched) {
185+
console.error(` ${it.priority} ${String(it.surface).padEnd(8)} ${it.id}${isBlocked(it) ? ' [BLOCKED]' : ''}`);
186+
}
187+
if (droppedBlocked.length) {
188+
console.error(`\n hidden (blocked): ${droppedBlocked.map((i) => i.id).join(', ')}`);
189+
}
190+
if (matched.length === 0) {
191+
console.error(' (nothing matched — check the selector; try `all` or `area:<name>`)');
192+
process.exit(1);
193+
}
187194
}
188-
if (matched.length === 0) {
189-
console.error(' (nothing matched — check the selector; try `all` or `area:<name>`)');
190-
process.exit(1);
195+
196+
// The dispatch runs only when node ran THIS file. Imported for `selectItems`
197+
// (the skill's front half is a pure resolver), the old top-level CLI printed a
198+
// usage block to the importer's stderr and killed it with exit 2 mid-import.
199+
if (isEntrypoint(import.meta.url)) {
200+
if (process.argv.includes('--self-test')) selfTest();
201+
main();
191202
}

0 commit comments

Comments
 (0)