@wemuda/launchrail 1.14.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 (41) hide show
  1. package/README.md +2 -2
  2. package/assets/ralph.workflow.js +9 -17
  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 +3 -3
  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 +5 -6
  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
@@ -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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"}