Skip to content

Commit 3688dac

Browse files
committed
refactor: run progress metrics as TypeScript
1 parent ca7aaf5 commit 3688dac

4 files changed

Lines changed: 15 additions & 20 deletions

File tree

docs/adr/0001-provider-first-integration-scenarios.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Coverage is expected to improve over the old handler-heavy unit suite, but the f
5858

5959
Operational metrics are generated by `pnpm test:integration:progress`. CI runs `pnpm test:integration:progress:check` after integration tests so public-command coverage, device-observable workflow flag coverage, and public-flag classification cannot silently regress. The script is the source of truth for provider-backed integration size, handler-unit size, mock-heavy handler pressure, public-command coverage, command-family ownership, device-observable workflow flag coverage, provider transcript pressure, and low-coverage files after a coverage run. Config, remote transport, Metro preparation, parser/client-only, report-writing, and boot-fallback flags stay in their owning unit/CLI suites and are reported as explicit exclusions rather than silently missing from the denominator. Provider pressure separates semantic Apple `simctl`/`devicectl`, macOS helper, and macOS host usage from generic Apple host-tool usage, and separates semantic Linux desktop/accessibility/clipboard/screenshot/input usage from generic Linux tool usage, so remote-adapter pressure is visible without treating named subproviders as raw shell intent.
6060

61-
The progress CLI should stay a thin report and check runner over a progress model. The model owns discovery, coverage classification, provider-pressure accounting, and check-failure derivation; the CLI owns Markdown output and process exit behavior. Source parsing inside the model is an implementation detail, not the desired long-term interface. It should move to command-family metadata only when the progress script can consume that metadata without changing Node runtime assumptions or importing command modules with unrelated side effects.
61+
The progress CLI should stay a thin report and check runner over a progress model. The model owns discovery, coverage classification, provider-pressure accounting, and check-failure derivation; the CLI owns Markdown output and process exit behavior. The progress script runs as a Node type-stripped TypeScript script and should consume command metadata directly when the metadata API exposes the needed facet. Source parsing inside the model is an implementation detail, not the desired long-term interface, and should remain limited to facets that are not yet represented as runtime metadata, such as mapping typed client method calls back to command names.
6262

6363
Every public command should have at least one provider-backed integration scenario that runs through the request router and request-scoped provider seams. Unit tests remain for parser matrices, selector matching, capability maps, malformed inputs, state machines, cleanup behavior, provider scope routing, and platform error boundaries.
6464

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@
132132
"test:unit": "vitest run --project unit",
133133
"test:coverage": "vitest run --coverage",
134134
"test:integration:provider": "vitest run --project provider-integration",
135-
"test:integration:progress": "node scripts/integration-progress.mjs",
136-
"test:integration:progress:check": "node scripts/integration-progress.mjs --check",
135+
"test:integration:progress": "node --experimental-strip-types scripts/integration-progress.ts",
136+
"test:integration:progress:check": "node --experimental-strip-types scripts/integration-progress.ts --check",
137137
"test:skillgym": "node test/skillgym/runner-environment.ts && pnpm build && skillgym run ./test/skillgym/suites/agent-device-smoke-suite.ts --config ./test/skillgym/skillgym.config.ts",
138138
"test:skillgym:case": "node test/skillgym/runner-environment.ts && pnpm build && skillgym run ./test/skillgym/suites/agent-device-smoke-suite.ts --config ./test/skillgym/skillgym.config.ts --case",
139139
"test:smoke": "node --test test/integration/smoke-*.test.ts",
Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3+
import { PUBLIC_COMMANDS } from '../src/command-catalog.ts';
4+
import { listCommandMetadata } from '../src/commands/command-metadata.ts';
35

46
const EMPTY_COVERAGE_METRIC = { pct: 0 };
57
const EMPTY_STATEMENT_COVERAGE = { covered: 0, pct: 0, total: 0 };
68

79
let ROOT = process.cwd();
810
let COVERAGE_SUMMARY = path.join(ROOT, 'coverage/coverage-summary.json');
9-
let COMMAND_CATALOG_SOURCE = '';
1011
let clientCommandMethods = new Map();
1112

1213
export function buildIntegrationProgressModel({ root = process.cwd() } = {}) {
1314
ROOT = root;
1415
COVERAGE_SUMMARY = path.join(ROOT, 'coverage/coverage-summary.json');
1516
const handlerTestDir = path.join(ROOT, 'src/daemon/handlers/__tests__');
1617
const providerScenarioDir = path.join(ROOT, 'test/integration/provider-scenarios');
17-
const commandCatalog = path.join(ROOT, 'src/command-catalog.ts');
1818
const commandContractFiles = listFiles(path.join(ROOT, 'src/commands'), (file) =>
1919
file.endsWith(`${path.sep}index.ts`),
2020
);
21-
COMMAND_CATALOG_SOURCE = fs.readFileSync(commandCatalog, 'utf8');
2221
clientCommandMethods = readClientCommandMethods(commandContractFiles);
2322

2423
const handlerTests = listFiles(handlerTestDir, (file) => file.endsWith('.test.ts'));
@@ -417,19 +416,15 @@ function summarizePublicCommandCoverage(files) {
417416
}
418417

419418
function readPublicCommands() {
420-
return [...readPublicCommandEntries().values()].sort();
421-
}
422-
423-
function readPublicCommandEntries() {
424-
const match = COMMAND_CATALOG_SOURCE.match(/export const PUBLIC_COMMANDS = \{([\s\S]*?)\} as const;/);
425-
if (!match) {
426-
throw new Error('Unable to find PUBLIC_COMMANDS in src/command-catalog.ts');
427-
}
428-
const commands = new Map();
429-
for (const command of match[1].matchAll(/\b([A-Za-z0-9_]+):\s*'([^']+)'/g)) {
430-
commands.set(command[1], command[2]);
431-
}
432-
return commands;
419+
const metadataNames = new Set(listCommandMetadata().map((metadata) => metadata.name));
420+
return Object.values(PUBLIC_COMMANDS)
421+
.map((name) => {
422+
if (!metadataNames.has(name)) {
423+
throw new Error(`Missing command metadata for public command: ${name}`);
424+
}
425+
return name;
426+
})
427+
.sort();
433428
}
434429

435430
function readClientCommandMethods(commandContractFiles) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
buildIntegrationProgressFailures,
55
buildIntegrationProgressModel,
66
formatPercent,
7-
} from './integration-progress-model.mjs';
7+
} from './integration-progress-model.ts';
88

99
const CHECK_MODE = process.argv.includes('--check');
1010
const progress = buildIntegrationProgressModel({ root: process.cwd() });

0 commit comments

Comments
 (0)