@wemuda/launchrail 1.13.0 → 1.15.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.
Files changed (62) hide show
  1. package/README.md +3 -3
  2. package/assets/agents-docs/domain.md +2 -2
  3. package/assets/agents-docs/issue-tracker-github.md +1 -1
  4. package/assets/agents-docs/issue-tracker-linear.md +1 -1
  5. package/assets/ralph.workflow.js +635 -276
  6. package/assets/skills/NOTICE.md +4 -0
  7. package/assets/skills/launchrail/launch/SKILL.md +6 -6
  8. package/assets/skills/launchrail/launch/workflow.md +4 -3
  9. package/assets/skills/launchrail/launch-browser-smoke/SKILL.md +36 -40
  10. package/assets/skills/launchrail/launch-code-review/SKILL.md +1 -1
  11. package/assets/skills/launchrail/launch-design-handoff/SKILL.md +1 -1
  12. package/assets/skills/launchrail/launch-design-validation/SKILL.md +2 -2
  13. package/assets/skills/launchrail/launch-discovery/SKILL.md +2 -2
  14. package/assets/skills/launchrail/launch-grill/SKILL.md +8 -2
  15. package/assets/skills/launchrail/launch-grill/domain-modeling.md +3 -1
  16. package/assets/skills/launchrail/launch-implement/SKILL.md +11 -11
  17. package/assets/skills/launchrail/launch-loop-readiness/SKILL.md +79 -0
  18. package/assets/skills/launchrail/launch-project-alignment/SKILL.md +2 -2
  19. package/assets/skills/launchrail/launch-ralph/SKILL.md +79 -60
  20. package/assets/skills/launchrail/launch-ralph-implement/SKILL.md +9 -8
  21. package/assets/skills/launchrail/launch-resolving-merge-conflicts/SKILL.md +1 -1
  22. package/assets/skills/launchrail/launch-spec/SKILL.md +3 -3
  23. package/assets/skills/launchrail/launch-tickets/SKILL.md +6 -7
  24. package/assets/skills/launchrail/launch-wayfinder/SKILL.md +6 -6
  25. package/dist/commands/add.js +7 -10
  26. package/dist/commands/add.js.map +1 -1
  27. package/dist/commands/doctor.js +84 -8
  28. package/dist/commands/doctor.js.map +1 -1
  29. package/dist/commands/init.js +2 -2
  30. package/dist/commands/init.js.map +1 -1
  31. package/dist/commands/verify.d.ts +13 -3
  32. package/dist/commands/verify.js +24 -8
  33. package/dist/commands/verify.js.map +1 -1
  34. package/dist/index.js +3 -15
  35. package/dist/index.js.map +1 -1
  36. package/dist/lib/adr.d.ts +27 -0
  37. package/dist/lib/adr.js +87 -0
  38. package/dist/lib/adr.js.map +1 -0
  39. package/dist/lib/browser-testing.d.ts +20 -3
  40. package/dist/lib/browser-testing.js +79 -79
  41. package/dist/lib/browser-testing.js.map +1 -1
  42. package/dist/lib/detect.d.ts +2 -0
  43. package/dist/lib/detect.js +3 -0
  44. package/dist/lib/detect.js.map +1 -1
  45. package/dist/lib/manifest.d.ts +12 -1
  46. package/dist/lib/manifest.js +24 -5
  47. package/dist/lib/manifest.js.map +1 -1
  48. package/dist/lib/migrations.js +76 -1
  49. package/dist/lib/migrations.js.map +1 -1
  50. package/dist/lib/project.d.ts +2 -0
  51. package/dist/lib/project.js +2 -1
  52. package/dist/lib/project.js.map +1 -1
  53. package/dist/lib/readiness.d.ts +57 -0
  54. package/dist/lib/readiness.js +129 -0
  55. package/dist/lib/readiness.js.map +1 -0
  56. package/dist/lib/seeds.d.ts +2 -0
  57. package/dist/lib/seeds.js +20 -11
  58. package/dist/lib/seeds.js.map +1 -1
  59. package/package.json +1 -1
  60. package/dist/commands/smoke.d.ts +0 -21
  61. package/dist/commands/smoke.js +0 -171
  62. package/dist/commands/smoke.js.map +0 -1
@@ -0,0 +1,57 @@
1
+ import type { RepoDetection } from "./detect.js";
2
+ import type { Manifest } from "./manifest.js";
3
+ /**
4
+ * Loop readiness (ADR-0033): the implementation loop is only as fast as the
5
+ * repository's gates, caches, and CI triggers let it be. These are the
6
+ * deterministic halves of the readiness story — doctor reports them as warn-only
7
+ * `ralph …` lines, and the `launch-loop-readiness` skill measures and fixes them.
8
+ */
9
+ export declare const READINESS_SKILL = "launch-loop-readiness";
10
+ /** The placeholder init seeds into AGENTS.md when no test command was detected. */
11
+ export declare const AGENTS_COMMANDS_TODO = "TODO: document the commands agents must run";
12
+ export interface FastGateReadiness {
13
+ status: "pass" | "warn";
14
+ message: string;
15
+ }
16
+ /**
17
+ * `verify --fast` runs `testing.checkCommand` and falls back to the unit command.
18
+ * On a project with e2e specs that fallback makes every land pay the full
19
+ * suite — a warning; on a light project it is fine, and only worth a hint.
20
+ */
21
+ export declare function fastGateReadiness(manifest: Manifest, detection: RepoDetection): FastGateReadiness;
22
+ export interface CiTriggerReadiness {
23
+ /** Workflow files found under .github/workflows. */
24
+ workflows: string[];
25
+ /** The ones whose `on` fires on every push — no branch, path, or tag filter. */
26
+ everyPush: string[];
27
+ }
28
+ /**
29
+ * The loop pushes `ralph/*` branches on every green step and the integration
30
+ * branch on every land. A workflow that triggers on every push turns each of
31
+ * those into a CI run nobody waits on — runner minutes and queue slots for
32
+ * nothing. GitHub Actions only; other CI systems are the skill's job.
33
+ */
34
+ export declare function ciTriggerReadiness(cwd: string): CiTriggerReadiness;
35
+ export interface E2eReadiness {
36
+ file: string;
37
+ /** The config pins Playwright to a single worker, so every e2e spec runs serially. */
38
+ serial: boolean;
39
+ evidence: string | null;
40
+ }
41
+ /**
42
+ * A `workers: 1` pin makes the whole e2e suite serial — the full gate's
43
+ * dominant cost in the field. A textual heuristic (the config is code): it flags
44
+ * only the global single-worker pin, never per-project parallelism choices.
45
+ */
46
+ export declare function e2eReadiness(cwd: string, configFile: string): E2eReadiness;
47
+ export type SessionStartHookState = "registered" | "missing" | "invalid-json";
48
+ /**
49
+ * Hosted sessions (Claude Code on the web) start from a fresh container: without
50
+ * a SessionStart hook nothing installs dependencies or the pinned browsers, and
51
+ * the loop's preflight refuses on the mismatch. Any registered SessionStart
52
+ * command counts — the hook's contents are the project's.
53
+ */
54
+ export declare function sessionStartHookState(cwd: string): SessionStartHookState;
55
+ export type AgentsCommandsState = "documented" | "todo" | "missing";
56
+ /** Builders read install, check, and test commands verbatim from AGENTS.md. */
57
+ export declare function agentsCommandsState(cwd: string): AgentsCommandsState;
@@ -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":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI3D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEvD,mFAAmF;AACnF,MAAM,CAAC,MAAM,oBAAoB,GAAG,6CAA6C,CAAC;AAOlF;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB,EAAE,SAAwB;IAC5E,IAAI,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;IACpF,CAAC;IACD,MAAM,KAAK,GACT,QAAQ,CAAC,OAAO,CAAC,sBAAsB,CAAC,KAAK,IAAI;QACjD,QAAQ,CAAC,OAAO,CAAC,UAAU,KAAK,IAAI;QACpC,SAAS,CAAC,oBAAoB,KAAK,IAAI;QACvC,SAAS,CAAC,gBAAgB,CAAC;IAC7B,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,qJAAqJ,eAAe,wBAAwB;SACtM,CAAC;IACJ,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,iGAAiG;KAC3G,CAAC;AACJ,CAAC;AASD,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAErG,SAAS,eAAe,CAAC,GAAY;IACnC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,8EAA8E;IAC9E,kDAAkD;IAClD,MAAM,EAAE,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;IACpD,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,EAAE,KAAK,MAAM,CAAC;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAI,EAA8B,CAAC,IAAI,CAAC;QAClD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC3D,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC9D,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC;SAC/B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACvC,IAAI,EAAE,CAAC;IACV,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,GAAY,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,2DAA2D;QACvE,CAAC;QACD,IAAI,eAAe,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,UAAkB;IAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,KAAK,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AACpF,CAAC;AAID;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,MAAM,OAAO,GAAI,QAA0D,EAAE,KAAK,EAAE,YAAY,CAAC;IACjG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAC7B,CAAC,KAA0B,EAAE,EAAE,CAC7B,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;QAC3B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAA2B,EAAE,EAAE,CAAC,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAClH,CAAC;IACF,OAAO,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAID,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3F,CAAC"}
@@ -4,6 +4,8 @@ export interface SeedContext {
4
4
  projectName: string;
5
5
  manifest: Manifest;
6
6
  launchrailVersion: string;
7
+ /** Project root. Seeds that adopt existing repository content (the ADR registry) read it. */
8
+ cwd: string;
7
9
  }
8
10
  /** The managed Claude instructions file — regenerated whenever module configuration changes. */
9
11
  export declare function claudeGeneratedFile(ctx: SeedContext): FileSpec;
package/dist/lib/seeds.js CHANGED
@@ -1,8 +1,10 @@
1
+ import { ADR_REGISTRY_PATH, adrRegistryContent, scanAdrs } from "./adr.js";
2
+ import { AGENTS_COMMANDS_TODO } from "./readiness.js";
1
3
  function agentsMd(ctx) {
2
4
  const { manifest } = ctx;
3
5
  const commands = manifest.testing.unitCommand
4
6
  ? "```bash\n" + manifest.testing.unitCommand + "\n```"
5
- : "TODO: document the commands agents must run (setup, tests, checks).";
7
+ : `${AGENTS_COMMANDS_TODO} (setup, tests, checks).`;
6
8
  // The stage-7 spec's home follows the tracker (ADR-0023): a `spec`-labelled
7
9
  // issue on a real tracker, or a committed file in local mode.
8
10
  const specPointer = manifest.issueTracker === "local" || manifest.issueTracker === "none"
@@ -26,7 +28,7 @@ TODO: One paragraph on what this project is, who it serves, and what it is not.
26
28
  ## Canonical context
27
29
 
28
30
  1. [docs/vision.md](docs/vision.md) — product vision and non-goals
29
- 2. [docs/adr/](docs/adr/) — accepted architecture decisions
31
+ 2. [docs/adr/README.md](docs/adr/README.md) — the decision registry: read its index first, then only the ADRs touching your area
30
32
  3. ${specPointer}
31
33
 
32
34
  ## Commands
@@ -38,7 +40,7 @@ ${commitSection}
38
40
  - Ask, don't guess. On product decisions, data-model or schema changes, security-relevant behaviour, or anything genuinely ambiguous, stop and ask rather than guessing — a wrong guess on these costs more than the question.
39
41
  - Do not silently change scope; surface deviations from the spec or ADRs.
40
42
  - If implementation invalidates an artifact (vision, spec, ADR, design note), update that artifact in the same change.
41
- - Meaningful decisions become lightweight ADRs in \`docs/adr/\` using [docs/adr/0000-template.md](docs/adr/0000-template.md).
43
+ - Decisions that are hard to reverse, surprising without context, and the result of a real trade-off become lightweight ADRs in \`docs/adr/\` using [docs/adr/0000-template.md](docs/adr/0000-template.md), with a row added to the registry index in the same commit. Prefer amending the ADR that owns an area over minting a sibling; product decisions belong in the spec, not an ADR.
42
44
 
43
45
  ## Definition of done
44
46
 
@@ -63,11 +65,10 @@ function claudeGeneratedMd(ctx) {
63
65
  ? `
64
66
  ## Browser testing
65
67
 
66
- - 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).
67
- - Start the app with \`node scripts/dev.mjs\` (\`--background\` in cloud or CI sessions); prepare an evidence bundle with \`npx @wemuda/launchrail smoke\`.
68
- - 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.
69
- - Smoke evidence lives in \`artifacts/verification/<run-id>/\` — fill in \`summary.md\`; only summary, deviations, and meta are meant to be committed.
70
- - 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.
71
72
  `
72
73
  : "";
73
74
  const ralph = ctx.manifest.modules.ralph
@@ -75,11 +76,13 @@ function claudeGeneratedMd(ctx) {
75
76
  ## The Ralph loop
76
77
 
77
78
  - Implementation starts with \`/launch-implement\` — all ready tickets, or one with \`/launch-implement <ticket>\`. Multi-ticket runs execute as the \`ralph\` workflow (\`.claude/workflows/ralph.js\`), supervised per the \`launch-ralph\` skill; single tickets build in-session. Only ever started explicitly by the user.
78
- - Every run declares one integration target: by default a consolidation branch (named via the \`target\` workflow arg, it collects the campaign and ends by offering one release PR to the default branch, which stays untouched), or the default branch (trunk) as an explicit opt-in for per-ticket merges. The run's recap states where the work lives and the single next step.
79
+ - Every run declares one integration target: by default a consolidation branch (named via the \`target\` workflow arg, it collects the campaign and ends by offering one release PR to the default branch, which stays untouched), or the default branch (trunk) as an explicit opt-in. The loop lands each finished \`ralph/<n>-*\` branch itself — a local squash-merge onto the base under \`npx @wemuda/launchrail verify --fast\`, pushed — and runs the full \`npx @wemuda/launchrail verify\` every few lands and at release; no per-ticket PR, no CI wait — cloud CI runs once, on the offered release PR. The run's recap states where the work lives and the single next step.
80
+ - Implementers push their branch from the first commit on and after every green step; a relaunch adopts pushed branches (pass \`knownGreen: "<sha>"\` to skip re-proving a verified base). Name a quick lint/typecheck/unit gate as \`testing.checkCommand\` in \`.launchrail.yml\` to make every land cheaper (the fast gate falls back to the unit command).
79
81
  - Tickets enter the loop with the \`ready-for-agent\` label and explicit \`Blocked by: #n\` edges; parked tickets carry \`needs-info\` plus their failure history.
80
- - A ticket counts done only when its PR is merged on the remote, the issue is closed, and \`npx @wemuda/launchrail verify\` is green — agent reports are claims, not evidence.
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.
81
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.
82
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.
83
86
  `
84
87
  : "";
85
88
  return `<!-- Managed by Launchrail v${ctx.launchrailVersion}. Do not edit: \`launchrail sync\` may replace this file. Project-specific instructions belong in CLAUDE.md. -->
@@ -88,6 +91,7 @@ function claudeGeneratedMd(ctx) {
88
91
 
89
92
  - This project follows the Launchrail rail — six phases: Intent → Exploration → Decisions → Blueprint → Build → Ship. Report position with the rail banner at every transition; the stage detail and the interaction contract live in \`.claude/skills/launch/workflow.md\`.
90
93
  - Product knowledge (vision, specs, ADRs, designs, tickets, code) is project-owned; Launchrail never overwrites it.
94
+ - Architecture decisions: read \`docs/adr/README.md\` — the registry index — first, and open only the ADRs touching your area. An ADR records a decision, not the current system; never take one as evidence that a component exists or still works as described — the code is the source of truth.
91
95
  - \`.launchrail.yml\` is project configuration; \`.launchrail-lock.json\` is machine-managed — do not hand-edit it.
92
96
  - The issue-tracker workflow (labels included) and the domain-doc consumer rules live in \`docs/agents/\` — seeded from \`.launchrail.yml\`, yours to edit.
93
97
  - Before claiming completion, run the project's deterministic checks. Completion requires evidence, not assertion.
@@ -98,7 +102,9 @@ function adrTemplate() {
98
102
  return `# ADR-NNNN: Short decision title
99
103
 
100
104
  ## Status
101
- Proposed | Accepted | Superseded by ADR-NNNN
105
+ Proposed | Accepted | Accepted — amended by ADR-NNNN | Superseded by ADR-NNNN
106
+
107
+ When a later ADR amends or supersedes this one, update this line and the registry index ([README.md](README.md)) in the same commit.
102
108
 
103
109
  ## Context
104
110
  What requirement or constraint requires a decision?
@@ -126,6 +132,9 @@ export function seedFiles(ctx) {
126
132
  { relPath: "AGENTS.md", content: agentsMd(ctx), ownership: "seeded" },
127
133
  { relPath: "CLAUDE.md", content: claudeMd(), ownership: "seeded" },
128
134
  { relPath: "docs/adr/0000-template.md", content: adrTemplate(), ownership: "seeded" },
135
+ // The registry (ADR-0031) makes the corpus navigable: agents read its index,
136
+ // not the whole directory. Adopting a repo with existing records prefills it.
137
+ { relPath: ADR_REGISTRY_PATH, content: adrRegistryContent(scanAdrs(ctx.cwd)), ownership: "seeded" },
129
138
  claudeGeneratedFile(ctx),
130
139
  ];
131
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../src/lib/seeds.ts"],"names":[],"mappings":"AASA,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;;;;;;;;;CASL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,+BAA+B,GAAG,CAAC,iBAAiB;;;;;;;;;;EAU3D,cAAc,GAAG,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;;;;;;;;;;;;;;;;;;;CAmBR,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,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.13.0",
3
+ "version": "1.15.0",
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":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAgBxC,SAAS,iBAAiB,CAAC,GAAsB;IAC/C,IAAI,GAAG,CAAC,kBAAkB,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IACtD,IAAI,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,GAAG,CAAC,GAAW,EAAE,IAAc;IACtC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;SAChD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;SACtD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,kBAAkB,GAAG;;;;;;;CAO1B,CAAC;AAEF,SAAS,eAAe,CAAC,IAQxB;IACC,MAAM,YAAY,GAChB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QACtB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,CAAC,CAAC,2BAA2B,mBAAmB,oFAAoF,CAAC;IACzI,OAAO,0BAA0B,IAAI,CAAC,KAAK;;YAEjC,IAAI,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE;cAC/E,IAAI,CAAC,OAAO,eAAe,IAAI,CAAC,SAAS;iBACtC,IAAI,CAAC,WAAW;iBAChB,OAAO;;;;;EAKtB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;CAwBb,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAkB;IAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IACvD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,eAAe,iBAAiB,6CAA6C,CAAC,CAAC;QAC7F,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,eAAe,iBAAiB,cAAc,CAAC,CAAC;QAC9D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,KAAK,CACX,mBAAmB,sBAAsB,iDAAiD,sBAAsB,WAAW,CAC5H,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kDAAkD,iBAAiB,uBAAuB,CAAC,CAAC;QAC1G,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QACjG,SAAS,GAAG,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;IAChF,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CACX,eAAe,OAAO,sGAAsG,CAC7H,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvG,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;IACzE,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3F,IAAI,KAAK,GAAG,GAAG,KAAK,IAAI,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;IAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;IACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,KAAK,GAAG,GAAG,KAAK,IAAI,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC;IAC5D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,oBAAoB,mBAAmB,GAAG,CAAC,CAAC;QAC5E,KAAK,MAAM,IAAI,IAAI,QAAQ;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,4BAA4B,mBAAmB,+DAA+D,CAAC,CAAC;IAC9H,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,mDAAmD,KAAK,mDAAmD,CAAC,CAAC;QACzH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAED,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,aAAa,CAAC,aAAa,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;IAEzF,MAAM,IAAI,GAAG;QACX,aAAa,EAAE,CAAC;QAChB,KAAK;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS;QACT,QAAQ;QACR,OAAO;QACP,SAAS;QACT,WAAW;QACX,iBAAiB,EAAE,OAAO;QAC1B,QAAQ;KACT,CAAC;IACF,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACvF,aAAa,CACX,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAC1B,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAC1F,MAAM,CACP,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,wDAAwD,KAAK,GAAG,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,kHAAkH,CAAC,CAAC;IAChI,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC"}