UNPKG

trellis

Version:

Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications

185 lines (182 loc) 5.57 kB
import { __esm } from "./chunk-2ESYSVXG.js"; // src/vcs/test-manifest.ts import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import { dirname, join } from "path"; function testManifestPath(rootPath) { return join(rootPath, MANIFEST_REL); } function loadTestManifest(rootPath) { const path = testManifestPath(rootPath); if (!existsSync(path)) return null; try { const raw = JSON.parse(readFileSync(path, "utf-8")); if (!raw?.suites || typeof raw.suites !== "object") { throw new Error('tests.json: missing "suites" object'); } return raw; } catch (err) { const msg = err instanceof Error ? err.message : String(err); throw new Error(`Invalid ${MANIFEST_REL}: ${msg}`); } } function requireTestManifest(rootPath) { const manifest = loadTestManifest(rootPath); if (!manifest) { throw new Error( `No test manifest at ${MANIFEST_REL}. Add suites or pass an explicit command on criteria.` ); } return manifest; } function resolveSuite(manifest, suiteId) { const suite = manifest.suites[suiteId]; if (!suite?.command) { const known = Object.keys(manifest.suites).sort().join(", ") || "(none)"; throw new Error( `Unknown test suite "${suiteId}". Known suites: ${known}` ); } return suite; } function suiteTimeoutMs(suite) { return suite.timeoutMs ?? DEFAULT_TIMEOUT_MS; } function listSuiteIds(manifest) { return Object.keys(manifest.suites).sort(); } function getPromoteRequiredSuites(manifest) { const fromPromote = manifest.promote?.require?.filter(Boolean) ?? []; if (fromPromote.length > 0) return fromPromote; if (manifest.defaultSuite) return [manifest.defaultSuite]; return []; } function inferCheckSuiteId(manifest) { for (const id of listSuiteIds(manifest)) { const cmd = manifest.suites[id]?.command ?? ""; if (CHECK_CMD_INFER_RE.test(cmd)) return id; } return void 0; } function inferE2eSuiteId(manifest) { for (const id of listSuiteIds(manifest)) { const cmd = manifest.suites[id]?.command ?? ""; if (E2E_CMD_INFER_RE.test(cmd)) return id; } return void 0; } function resolveReviewLadder(manifest) { const checkSuiteId = manifest.review?.check ?? inferCheckSuiteId(manifest); const e2eSuiteId = manifest.review?.e2e ?? inferE2eSuiteId(manifest); if (!checkSuiteId) { throw new Error( `${MANIFEST_REL}: review.check suite missing and no check-like suite found (pnpm check, svelte-check, etc.)` ); } if (!e2eSuiteId) { throw new Error( `${MANIFEST_REL}: review.e2e suite missing and no e2e-like suite found (test:e2e, playwright)` ); } return { checkSuiteId, e2eSuiteId, check: resolveSuite(manifest, checkSuiteId), e2e: resolveSuite(manifest, e2eSuiteId) }; } function resolveCriterionCommand(manifest, criterion) { if (criterion.command) return criterion.command; if (!criterion.suite) return void 0; if (!manifest) { throw new Error( `Criterion references suite "${criterion.suite}" but ${MANIFEST_REL} is missing` ); } return resolveSuite(manifest, criterion.suite).command; } function resolveIssueStartCriteria(manifest, labels) { if (!manifest) return []; const seen = /* @__PURE__ */ new Set(); const out = []; const add = (templates) => { if (!templates) return; for (const t of templates) { const key = `${t.suite ?? ""}\0${t.command ?? ""}\0${t.description}`; if (seen.has(key)) continue; seen.add(key); out.push(t); } }; add(manifest.issueStart?.default); for (const label of labels) { add(manifest.issueLabels?.[label]); } return out; } function ensureDefaultTestManifest(rootPath, template = DEFAULT_TEST_MANIFEST) { const path = testManifestPath(rootPath); if (existsSync(path)) return false; mkdirSync(dirname(path), { recursive: true }); writeFileSync(path, `${JSON.stringify(template, null, 2)} `, "utf-8"); return true; } var CHECK_CMD_INFER_RE, E2E_CMD_INFER_RE, MANIFEST_REL, DEFAULT_TIMEOUT_MS, DEFAULT_TEST_MANIFEST; var init_test_manifest = __esm({ "src/vcs/test-manifest.ts"() { CHECK_CMD_INFER_RE = /\b(pnpm\s+check|npm\s+run\s+check|svelte-check|vue-tsc)\b/i; E2E_CMD_INFER_RE = /\b(test:e2e|playwright)\b/i; MANIFEST_REL = join(".trellis", "tests.json"); DEFAULT_TIMEOUT_MS = 12e4; DEFAULT_TEST_MANIFEST = { version: 1, defaultSuite: "unit", suites: { unit: { description: "Unit tests", command: "npm test" }, e2e: { description: "End-to-end tests", command: "npx playwright test", timeoutMs: 6e5 }, "browser-smoke": { description: "Live-tab smoke via Trellis extension", kind: "browser", command: "trellis browser verify browser-smoke", stepsFile: ".trellis/browser-suites/browser-smoke.json", timeoutMs: 3e4 } }, promote: { require: ["unit"] }, issueStart: { default: [{ description: "Unit tests pass", suite: "unit" }] }, issueLabels: { "needs-e2e": [{ description: "E2E suite passes", suite: "e2e" }] }, review: { check: "unit", e2e: "e2e" } }; } }); export { testManifestPath, loadTestManifest, requireTestManifest, resolveSuite, suiteTimeoutMs, listSuiteIds, getPromoteRequiredSuites, resolveReviewLadder, resolveCriterionCommand, resolveIssueStartCriteria, DEFAULT_TEST_MANIFEST, ensureDefaultTestManifest, init_test_manifest };