@wemuda/launchrail 1.14.0 → 1.15.1

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.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/assets/ralph.workflow.js +37 -24
  3. package/assets/skills/launchrail/launch/SKILL.md +4 -4
  4. package/assets/skills/launchrail/launch/workflow.md +3 -2
  5. package/assets/skills/launchrail/launch-browser-smoke/SKILL.md +36 -40
  6. package/assets/skills/launchrail/launch-implement/SKILL.md +4 -4
  7. package/assets/skills/launchrail/launch-loop-readiness/SKILL.md +79 -0
  8. package/assets/skills/launchrail/launch-project-alignment/SKILL.md +1 -1
  9. package/assets/skills/launchrail/launch-ralph/SKILL.md +7 -8
  10. package/assets/skills/launchrail/launch-ralph-implement/SKILL.md +5 -5
  11. package/dist/commands/add.js +6 -10
  12. package/dist/commands/add.js.map +1 -1
  13. package/dist/commands/doctor.js +55 -8
  14. package/dist/commands/doctor.js.map +1 -1
  15. package/dist/commands/init.js +0 -1
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/verify.d.ts +3 -2
  18. package/dist/commands/verify.js +3 -2
  19. package/dist/commands/verify.js.map +1 -1
  20. package/dist/index.js +0 -15
  21. package/dist/index.js.map +1 -1
  22. package/dist/lib/browser-testing.d.ts +20 -3
  23. package/dist/lib/browser-testing.js +79 -79
  24. package/dist/lib/browser-testing.js.map +1 -1
  25. package/dist/lib/detect.d.ts +2 -0
  26. package/dist/lib/detect.js +3 -0
  27. package/dist/lib/detect.js.map +1 -1
  28. package/dist/lib/manifest.d.ts +6 -1
  29. package/dist/lib/manifest.js +17 -5
  30. package/dist/lib/manifest.js.map +1 -1
  31. package/dist/lib/migrations.js +76 -1
  32. package/dist/lib/migrations.js.map +1 -1
  33. package/dist/lib/readiness.d.ts +57 -0
  34. package/dist/lib/readiness.js +129 -0
  35. package/dist/lib/readiness.js.map +1 -0
  36. package/dist/lib/seeds.js +7 -6
  37. package/dist/lib/seeds.js.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/commands/smoke.d.ts +0 -21
  40. package/dist/commands/smoke.js +0 -171
  41. package/dist/commands/smoke.js.map +0 -1
@@ -0,0 +1,129 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parse } from "yaml";
4
+ import { BROWSER_TESTING_MODULE } from "./browser-testing.js";
5
+ import { CLAUDE_SETTINGS_PATH } from "./claudeSettings.js";
6
+ /**
7
+ * Loop readiness (ADR-0033): the implementation loop is only as fast as the
8
+ * repository's gates, caches, and CI triggers let it be. These are the
9
+ * deterministic halves of the readiness story — doctor reports them as warn-only
10
+ * `ralph …` lines, and the `launch-loop-readiness` skill measures and fixes them.
11
+ */
12
+ export const READINESS_SKILL = "launch-loop-readiness";
13
+ /** The placeholder init seeds into AGENTS.md when no test command was detected. */
14
+ export const AGENTS_COMMANDS_TODO = "TODO: document the commands agents must run";
15
+ /**
16
+ * `verify --fast` runs `testing.checkCommand` and falls back to the unit command.
17
+ * On a project with e2e specs that fallback makes every land pay the full
18
+ * suite — a warning; on a light project it is fine, and only worth a hint.
19
+ */
20
+ export function fastGateReadiness(manifest, detection) {
21
+ if (manifest.testing.checkCommand) {
22
+ return { status: "pass", message: `fast gate: ${manifest.testing.checkCommand}` };
23
+ }
24
+ const heavy = manifest.modules[BROWSER_TESTING_MODULE] === true ||
25
+ manifest.testing.e2eCommand !== null ||
26
+ detection.playwrightConfigFile !== null ||
27
+ detection.hasPlaywrightDep;
28
+ if (heavy) {
29
+ return {
30
+ status: "warn",
31
+ message: `testing.checkCommand unset — the loop's per-land gate is the full unit command, e2e specs included; name a lint + typecheck + quick-unit command (${READINESS_SKILL} measures and sets it)`,
32
+ };
33
+ }
34
+ return {
35
+ status: "pass",
36
+ message: "fast gate falls back to the unit command (set testing.checkCommand for a quicker per-land gate)",
37
+ };
38
+ }
39
+ const PUSH_FILTERS = ["branches", "branches-ignore", "paths", "paths-ignore", "tags", "tags-ignore"];
40
+ function runsOnEveryPush(doc) {
41
+ if (typeof doc !== "object" || doc === null)
42
+ return false;
43
+ const record = doc;
44
+ // YAML 1.1 readers turn the bare key `on` into boolean true; the yaml package
45
+ // (1.2) keeps it a string. Accept both spellings.
46
+ const on = "on" in record ? record.on : record.true;
47
+ if (on === undefined)
48
+ return false;
49
+ if (typeof on === "string")
50
+ return on === "push";
51
+ if (Array.isArray(on))
52
+ return on.includes("push");
53
+ if (typeof on === "object" && on !== null && "push" in on) {
54
+ const push = on.push;
55
+ if (typeof push !== "object" || push === null)
56
+ return true;
57
+ return !PUSH_FILTERS.some((key) => key in push);
58
+ }
59
+ return false;
60
+ }
61
+ /**
62
+ * The loop pushes `ralph/*` branches on every green step and the integration
63
+ * branch on every land. A workflow that triggers on every push turns each of
64
+ * those into a CI run nobody waits on — runner minutes and queue slots for
65
+ * nothing. GitHub Actions only; other CI systems are the skill's job.
66
+ */
67
+ export function ciTriggerReadiness(cwd) {
68
+ const dir = join(cwd, ".github", "workflows");
69
+ if (!existsSync(dir))
70
+ return { workflows: [], everyPush: [] };
71
+ const workflows = readdirSync(dir)
72
+ .filter((file) => /\.ya?ml$/.test(file))
73
+ .sort();
74
+ const everyPush = [];
75
+ for (const file of workflows) {
76
+ let doc;
77
+ try {
78
+ doc = parse(readFileSync(join(dir, file), "utf8"));
79
+ }
80
+ catch {
81
+ continue; // an unparseable workflow is CI's problem, not readiness's
82
+ }
83
+ if (runsOnEveryPush(doc))
84
+ everyPush.push(file);
85
+ }
86
+ return { workflows, everyPush };
87
+ }
88
+ /**
89
+ * A `workers: 1` pin makes the whole e2e suite serial — the full gate's
90
+ * dominant cost in the field. A textual heuristic (the config is code): it flags
91
+ * only the global single-worker pin, never per-project parallelism choices.
92
+ */
93
+ export function e2eReadiness(cwd, configFile) {
94
+ const source = readFileSync(join(cwd, configFile), "utf8");
95
+ const match = /\bworkers\s*:\s*1\b(?!\s*:)/.exec(source);
96
+ return { file: configFile, serial: match !== null, evidence: match?.[0] ?? null };
97
+ }
98
+ /**
99
+ * Hosted sessions (Claude Code on the web) start from a fresh container: without
100
+ * a SessionStart hook nothing installs dependencies or the pinned browsers, and
101
+ * the loop's preflight refuses on the mismatch. Any registered SessionStart
102
+ * command counts — the hook's contents are the project's.
103
+ */
104
+ export function sessionStartHookState(cwd) {
105
+ const path = join(cwd, CLAUDE_SETTINGS_PATH);
106
+ if (!existsSync(path))
107
+ return "missing";
108
+ let settings;
109
+ try {
110
+ settings = JSON.parse(readFileSync(path, "utf8"));
111
+ }
112
+ catch {
113
+ return "invalid-json";
114
+ }
115
+ const entries = settings?.hooks?.SessionStart;
116
+ if (!Array.isArray(entries))
117
+ return "missing";
118
+ const registered = entries.some((entry) => Array.isArray(entry?.hooks) &&
119
+ entry.hooks.some((hook) => typeof hook?.command === "string" && hook.command.length > 0));
120
+ return registered ? "registered" : "missing";
121
+ }
122
+ /** Builders read install, check, and test commands verbatim from AGENTS.md. */
123
+ export function agentsCommandsState(cwd) {
124
+ const path = join(cwd, "AGENTS.md");
125
+ if (!existsSync(path))
126
+ return "missing";
127
+ return readFileSync(path, "utf8").includes(AGENTS_COMMANDS_TODO) ? "todo" : "documented";
128
+ }
129
+ //# sourceMappingURL=readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.js","sourceRoot":"","sources":["../../src/lib/readiness.ts"],"names":[],"mappings":"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"}
package/dist/lib/seeds.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { ADR_REGISTRY_PATH, adrRegistryContent, scanAdrs } from "./adr.js";
2
+ import { AGENTS_COMMANDS_TODO } from "./readiness.js";
2
3
  function agentsMd(ctx) {
3
4
  const { manifest } = ctx;
4
5
  const commands = manifest.testing.unitCommand
5
6
  ? "```bash\n" + manifest.testing.unitCommand + "\n```"
6
- : "TODO: document the commands agents must run (setup, tests, checks).";
7
+ : `${AGENTS_COMMANDS_TODO} (setup, tests, checks).`;
7
8
  // The stage-7 spec's home follows the tracker (ADR-0023): a `spec`-labelled
8
9
  // issue on a real tracker, or a committed file in local mode.
9
10
  const specPointer = manifest.issueTracker === "local" || manifest.issueTracker === "none"
@@ -64,11 +65,10 @@ function claudeGeneratedMd(ctx) {
64
65
  ? `
65
66
  ## Browser testing
66
67
 
67
- - User-facing changes are verified twice: deterministic checks (\`node scripts/verify.mjs\`) and agentic smoke journeys from \`docs/testing/smoke-journeys.md\` (browser-smoke skill).
68
- - Start the app with \`node scripts/dev.mjs\` (\`--background\` in cloud or CI sessions); prepare an evidence bundle with \`npx @wemuda/launchrail smoke\`.
69
- - Drive journeys agentically via the seeded Playwright MCP (\`.mcp.json\`, approve it once in Claude Code) or a Playwright script — whichever the session has; headless CI falls back to the scripts.
70
- - Smoke evidence lives in \`artifacts/verification/<run-id>/\` — fill in \`summary.md\`; only summary, deviations, and meta are meant to be committed.
71
- - When a smoke run finds a real bug: reproduce it, add a failing deterministic test, fix, prove the test passes, re-run the journey.
68
+ - Two lanes (ADR-0034). **e2e** is deterministic and thin: \`npx @wemuda/launchrail verify\` runs the unit command and the Playwright specs under \`tests/e2e/\`; a spec is added for a standing golden path or a behavior only a real browser can exercise, never as the by-product of a smoke. **Browser smoke** is one-off: after building user-facing behavior, drive the running app in a real browser per the \`launch-browser-smoke\` skill to see the change working, report what you saw, and move on — no journeys file, no evidence bundle, no test written from it.
69
+ - Start the app with \`node scripts/dev.mjs\` (\`--background\` in cloud or CI sessions; \`--port <n>\` when other builders share the machine); it writes the URL to \`.launchrail/state/dev.url\` and, in background mode, the pid to \`.launchrail/state/dev.pid\`.
70
+ - The smoke's driver is \`agent-browser\` (installed by \`node scripts/setup.mjs\`), driven from the shell — \`open\`, \`snapshot -i\`, \`click @ref\`, \`fill\`, \`wait\`, \`screenshot\`, \`errors\`, \`console\`, \`network requests\` — one \`--session\` per ticket.
71
+ - A bug the smoke finds gets its regression test at the cheapest seam that catches it — unit or integration first; a Playwright spec only when the ticket asks for one.
72
72
  `
73
73
  : "";
74
74
  const ralph = ctx.manifest.modules.ralph
@@ -82,6 +82,7 @@ function claudeGeneratedMd(ctx) {
82
82
  - A ticket counts done only when its landing commit is on the remote base, the issue is closed, and the gates are green — agent reports are claims, not evidence.
83
83
  - \`.claude/workflows/ralph.js\` is managed by Launchrail: override policy per run via workflow args (e.g. \`{ width: 1 }\`), never by editing the file.
84
84
  - Launch unattended runs in a non-prompting permission mode (bypass/autonomous); a guard hook (\`.claude/hooks/ralph-permission-guard.py\`) warns if the \`ralph\` workflow starts in an interactive mode, since one benign prompt can stall a walk-away run and lose the container mid-ticket.
85
+ - \`launch-loop-readiness\` tunes the repo for the loop — fast gate, parallel e2e specs, shared caches, CI triggers, labels, hosted-session setup, verbatim commands — with measurements; \`doctor\`'s \`ralph …\` readiness lines say when it is worth running.
85
86
  `
86
87
  : "";
87
88
  return `<!-- Managed by Launchrail v${ctx.launchrailVersion}. Do not edit: \`launchrail sync\` may replace this file. Project-specific instructions belong in CLAUDE.md. -->
@@ -1 +1 @@
1
- {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../src/lib/seeds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAY3E,SAAS,QAAQ,CAAC,GAAgB;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW;QAC3C,CAAC,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,OAAO;QACtD,CAAC,CAAC,qEAAqE,CAAC;IAE1E,4EAA4E;IAC5E,8DAA8D;IAC9D,MAAM,WAAW,GACf,QAAQ,CAAC,YAAY,KAAK,OAAO,IAAI,QAAQ,CAAC,YAAY,KAAK,MAAM;QACnE,CAAC,CAAC,sDAAsD;QACxD,CAAC,CAAC,4IAA4I,CAAC;IAEnJ,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,mBAAmB;QAC5D,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,gCAAgC,GAAG,CAAC,WAAW;;;;;;;;;;;;KAYnD,WAAW;;;;EAId,QAAQ;EACR,aAAa;;;;;;;;;;;6BAWc,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE;;;;CAIxG,CAAC;AACF,CAAC;AAED,SAAS,QAAQ;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAgB;IACzC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAC5D,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK;QACtC,CAAC,CAAC;;;;;;;;;;CAUL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,+BAA+B,GAAG,CAAC,iBAAiB;;;;;;;;;;;EAW3D,cAAc,GAAG,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;;;;;;;;;;;;;;;;;;;;;CAqBR,CAAC;AACF,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,GAAgB;IAClD,OAAO,EAAE,OAAO,EAAE,iCAAiC,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC/G,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,GAAgB;IACxC,OAAO;QACL,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QAClE,EAAE,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrF,6EAA6E;QAC7E,8EAA8E;QAC9E,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;QACnG,mBAAmB,CAAC,GAAG,CAAC;KACzB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../src/lib/seeds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAWtD,SAAS,QAAQ,CAAC,GAAgB;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW;QAC3C,CAAC,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,OAAO;QACtD,CAAC,CAAC,GAAG,oBAAoB,0BAA0B,CAAC;IAEtD,4EAA4E;IAC5E,8DAA8D;IAC9D,MAAM,WAAW,GACf,QAAQ,CAAC,YAAY,KAAK,OAAO,IAAI,QAAQ,CAAC,YAAY,KAAK,MAAM;QACnE,CAAC,CAAC,sDAAsD;QACxD,CAAC,CAAC,4IAA4I,CAAC;IAEnJ,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,mBAAmB;QAC5D,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,gCAAgC,GAAG,CAAC,WAAW;;;;;;;;;;;;KAYnD,WAAW;;;;EAId,QAAQ;EACR,aAAa;;;;;;;;;;;6BAWc,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE;;;;CAIxG,CAAC;AACF,CAAC;AAED,SAAS,QAAQ;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAgB;IACzC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAC5D,CAAC,CAAC;;;;;;;CAOL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK;QACtC,CAAC,CAAC;;;;;;;;;;;CAWL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,+BAA+B,GAAG,CAAC,iBAAiB;;;;;;;;;;;EAW3D,cAAc,GAAG,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;;;;;;;;;;;;;;;;;;;;;CAqBR,CAAC;AACF,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,GAAgB;IAClD,OAAO,EAAE,OAAO,EAAE,iCAAiC,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC/G,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,GAAgB;IACxC,OAAO;QACL,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QAClE,EAAE,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrF,6EAA6E;QAC7E,8EAA8E;QAC9E,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;QACnG,mBAAmB,CAAC,GAAG,CAAC;KACzB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wemuda/launchrail",
3
- "version": "1.14.0",
3
+ "version": "1.15.1",
4
4
  "description": "Launchrail — initialize, inspect, update, and validate repositories using the Launchrail development system.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,21 +0,0 @@
1
- export interface SmokeOptions {
2
- cwd: string;
3
- url: string | null;
4
- dryRun: boolean;
5
- }
6
- export interface SmokeOutcome {
7
- code: number;
8
- /** Absolute path of the created run directory, when one was created. */
9
- runDir: string | null;
10
- }
11
- export type SmokeEnvironment = "local" | "ci" | "cloud";
12
- export declare function parseJourneyNames(source: string): string[];
13
- /**
14
- * Prepare an agentic smoke run: confirm the app is reachable, then scaffold a
15
- * traceable evidence bundle under artifacts/verification/<run-id>/. The agent
16
- * (browser-smoke skill) drives the journeys and fills the bundle in.
17
- *
18
- * Only ever creates new files in a fresh run directory — it never modifies
19
- * existing project files, so no checksum tracking is needed.
20
- */
21
- export declare function runSmoke(opts: SmokeOptions): Promise<SmokeOutcome>;
@@ -1,171 +0,0 @@
1
- import { execFileSync } from "node:child_process";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { BROWSER_TESTING_MODULE, SMOKE_JOURNEYS_PATH } from "../lib/browser-testing.js";
5
- import { MANIFEST_FILENAME, parseManifest } from "../lib/manifest.js";
6
- import { VERSION } from "../version.js";
7
- function detectEnvironment(env) {
8
- if (env.CLAUDE_CODE_REMOTE === "true")
9
- return "cloud";
10
- if (env.CI)
11
- return "ci";
12
- return "local";
13
- }
14
- function git(cwd, args) {
15
- try {
16
- return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
17
- }
18
- catch {
19
- return null;
20
- }
21
- }
22
- export function parseJourneyNames(source) {
23
- return source
24
- .split("\n")
25
- .filter((line) => line.startsWith("## Journey:"))
26
- .map((line) => line.slice("## Journey:".length).trim())
27
- .filter((name) => name.length > 0);
28
- }
29
- const EVIDENCE_GITIGNORE = `# Managed by Launchrail: keep summaries and deviations reviewable, ignore bulky evidence.
30
- *
31
- !.gitignore
32
- !*/
33
- !*/summary.md
34
- !*/deviations.md
35
- !*/meta.json
36
- `;
37
- function summaryTemplate(opts) {
38
- const journeyLines = opts.journeys.length > 0
39
- ? opts.journeys.map((name) => `- [ ] ${name}`).join("\n")
40
- : `_No journeys defined in ${SMOKE_JOURNEYS_PATH} — record the journeys actually driven (e.g. from the ticket under verification)._`;
41
- return `# Smoke verification — ${opts.runId}
42
-
43
- - Commit: ${opts.commitSha ?? "no git history"}${opts.gitDirty ? " (working tree dirty)" : ""}
44
- - Base URL: ${opts.baseUrl} (responded ${opts.appStatus})
45
- - Environment: ${opts.environment}
46
- - Launchrail: v${VERSION}
47
- - Spec / ticket references: _fill in_
48
-
49
- ## Journeys
50
-
51
- ${journeyLines}
52
-
53
- ## Standard checks
54
-
55
- - [ ] No uncaught console errors
56
- - [ ] No failed API requests
57
- - [ ] Success state visible for each journey
58
- - [ ] Data remains after refresh
59
-
60
- ## Evidence
61
-
62
- _Reference files in this directory: screenshots/, traces/, console.log, network-errors.json, test-results.json._
63
-
64
- ## Deviations from spec or design
65
-
66
- _None recorded — add details here and in deviations.md when found._
67
-
68
- ## New regression tests
69
-
70
- _Deterministic tests added from smoke findings._
71
-
72
- ## Blockers
73
-
74
- _None._
75
- `;
76
- }
77
- /**
78
- * Prepare an agentic smoke run: confirm the app is reachable, then scaffold a
79
- * traceable evidence bundle under artifacts/verification/<run-id>/. The agent
80
- * (browser-smoke skill) drives the journeys and fills the bundle in.
81
- *
82
- * Only ever creates new files in a fresh run directory — it never modifies
83
- * existing project files, so no checksum tracking is needed.
84
- */
85
- export async function runSmoke(opts) {
86
- const manifestPath = join(opts.cwd, MANIFEST_FILENAME);
87
- if (!existsSync(manifestPath)) {
88
- console.error(`launchrail: ${MANIFEST_FILENAME} not found — run \`launchrail init\` first.`);
89
- return { code: 1, runDir: null };
90
- }
91
- const parsed = parseManifest(readFileSync(manifestPath, "utf8"));
92
- if (!parsed.manifest) {
93
- console.error(`launchrail: ${MANIFEST_FILENAME} is invalid:`);
94
- for (const error of parsed.errors)
95
- console.error(` - ${error}`);
96
- return { code: 1, runDir: null };
97
- }
98
- if (!parsed.manifest.modules[BROWSER_TESTING_MODULE]) {
99
- console.error(`launchrail: the ${BROWSER_TESTING_MODULE} module is not enabled — run \`launchrail add ${BROWSER_TESTING_MODULE}\` first.`);
100
- return { code: 1, runDir: null };
101
- }
102
- const baseUrl = opts.url ?? parsed.manifest.testing.appUrl;
103
- if (!baseUrl) {
104
- console.error(`launchrail: no app URL — set testing.appUrl in ${MANIFEST_FILENAME} or pass --url <url>.`);
105
- return { code: 1, runDir: null };
106
- }
107
- let appStatus = null;
108
- try {
109
- const response = await fetch(baseUrl, { signal: AbortSignal.timeout(3000), redirect: "manual" });
110
- appStatus = `HTTP ${response.status}`;
111
- }
112
- catch {
113
- // Any response counts as reachable; only a connection failure aborts the run.
114
- }
115
- if (appStatus === null) {
116
- console.error(`launchrail: ${baseUrl} is not responding. Start the app first (\`node scripts/dev.mjs --background\`) or pass --url <url>.`);
117
- return { code: 1, runDir: null };
118
- }
119
- const journeysPath = join(opts.cwd, SMOKE_JOURNEYS_PATH);
120
- const journeys = existsSync(journeysPath) ? parseJourneyNames(readFileSync(journeysPath, "utf8")) : [];
121
- const commitSha = git(opts.cwd, ["rev-parse", "HEAD"]);
122
- const gitDirty = (git(opts.cwd, ["status", "--porcelain"]) ?? "") !== "";
123
- const environment = detectEnvironment(process.env);
124
- const stamp = new Date().toISOString().replace(/[-:]/g, "").replace("T", "-").slice(0, 15);
125
- let runId = `${stamp}-${commitSha?.slice(0, 7) ?? "nogit"}`;
126
- const verificationDir = join(opts.cwd, "artifacts", "verification");
127
- for (let n = 2; existsSync(join(verificationDir, runId)); n += 1) {
128
- runId = `${stamp}-${commitSha?.slice(0, 7) ?? "nogit"}-${n}`;
129
- }
130
- const runDir = join(verificationDir, runId);
131
- console.log(`App responding at ${baseUrl} (${appStatus}).`);
132
- if (journeys.length > 0) {
133
- console.log(`\n${journeys.length} journey(s) from ${SMOKE_JOURNEYS_PATH}:`);
134
- for (const name of journeys)
135
- console.log(` - ${name}`);
136
- }
137
- else {
138
- console.log(`\nNo journeys defined in ${SMOKE_JOURNEYS_PATH} — drive the journeys defined by the work under verification.`);
139
- }
140
- if (opts.dryRun) {
141
- console.log(`\nDry run — would create artifacts/verification/${runId}/ (meta.json, summary.md, screenshots/, traces/).`);
142
- return { code: 0, runDir: null };
143
- }
144
- mkdirSync(join(runDir, "screenshots"), { recursive: true });
145
- mkdirSync(join(runDir, "traces"), { recursive: true });
146
- const gitignorePath = join(verificationDir, ".gitignore");
147
- if (!existsSync(gitignorePath))
148
- writeFileSync(gitignorePath, EVIDENCE_GITIGNORE, "utf8");
149
- const meta = {
150
- schemaVersion: 1,
151
- runId,
152
- createdAt: new Date().toISOString(),
153
- commitSha,
154
- gitDirty,
155
- baseUrl,
156
- appStatus,
157
- environment,
158
- launchrailVersion: VERSION,
159
- journeys,
160
- };
161
- writeFileSync(join(runDir, "meta.json"), JSON.stringify(meta, null, 2) + "\n", "utf8");
162
- writeFileSync(join(runDir, "summary.md"), summaryTemplate({ runId, baseUrl, commitSha, gitDirty, environment, appStatus, journeys }), "utf8");
163
- console.log(`\nEvidence bundle scaffolded: artifacts/verification/${runId}/`);
164
- console.log(" - summary.md fill in as journeys complete; check every box you verified");
165
- console.log(" - screenshots/ capture key states as you go");
166
- console.log(" - traces/ Playwright traces where available");
167
- console.log(" - console.log / network-errors.json / test-results.json — write these when relevant");
168
- console.log("\nEvery journey must pass the standard checks. Convert real bugs into failing deterministic tests before fixing.");
169
- return { code: 0, runDir };
170
- }
171
- //# sourceMappingURL=smoke.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"smoke.js","sourceRoot":"","sources":["../../src/commands/smoke.ts"],"names":[],"mappings":"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"}