@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.
- package/README.md +2 -2
- package/assets/ralph.workflow.js +37 -24
- package/assets/skills/launchrail/launch/SKILL.md +4 -4
- package/assets/skills/launchrail/launch/workflow.md +3 -2
- package/assets/skills/launchrail/launch-browser-smoke/SKILL.md +36 -40
- package/assets/skills/launchrail/launch-implement/SKILL.md +4 -4
- package/assets/skills/launchrail/launch-loop-readiness/SKILL.md +79 -0
- package/assets/skills/launchrail/launch-project-alignment/SKILL.md +1 -1
- package/assets/skills/launchrail/launch-ralph/SKILL.md +7 -8
- package/assets/skills/launchrail/launch-ralph-implement/SKILL.md +5 -5
- package/dist/commands/add.js +6 -10
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/doctor.js +55 -8
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +0 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/verify.d.ts +3 -2
- package/dist/commands/verify.js +3 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +0 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/browser-testing.d.ts +20 -3
- package/dist/lib/browser-testing.js +79 -79
- package/dist/lib/browser-testing.js.map +1 -1
- package/dist/lib/detect.d.ts +2 -0
- package/dist/lib/detect.js +3 -0
- package/dist/lib/detect.js.map +1 -1
- package/dist/lib/manifest.d.ts +6 -1
- package/dist/lib/manifest.js +17 -5
- package/dist/lib/manifest.js.map +1 -1
- package/dist/lib/migrations.js +76 -1
- package/dist/lib/migrations.js.map +1 -1
- package/dist/lib/readiness.d.ts +57 -0
- package/dist/lib/readiness.js +129 -0
- package/dist/lib/readiness.js.map +1 -0
- package/dist/lib/seeds.js +7 -6
- package/dist/lib/seeds.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/smoke.d.ts +0 -21
- package/dist/commands/smoke.js +0 -171
- 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
|
-
:
|
|
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
|
-
-
|
|
68
|
-
- Start the app with \`node scripts/dev.mjs\` (\`--background\` in cloud or CI sessions);
|
|
69
|
-
-
|
|
70
|
-
-
|
|
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. -->
|
package/dist/lib/seeds.js.map
CHANGED
|
@@ -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;
|
|
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
package/dist/commands/smoke.d.ts
DELETED
|
@@ -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>;
|
package/dist/commands/smoke.js
DELETED
|
@@ -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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"}
|