Without --foreground, `executor web` just opens whatever background service is already running, which keeps the scope it was started with. A --scope passed here was silently ignored, so the user could land on a different workspace and wonder where their config went. Now it warns loudly and names the flag that actually applies the scope (`executor web --foreground --scope <dir>`). Adds an e2e scenario in cli-web-transition that asserts the warning names the scope dir and the --foreground flag instead of silently dropping it.
Unified · Split
| @@ -2352,6 +2352,19 @@ const webCommand = Command.make( · 2351 unmodified lines | |||
| 2352 | ({ foreground, port, scope, hostname, allowedHost, authToken }) => | 2352 | ({ foreground, port, scope, hostname, allowedHost, authToken }) => |
| 2353 | Effect.gen(function* () { | 2353 | Effect.gen(function* () { |
| 2354 | if (!foreground) { | 2354 | if (!foreground) { |
| 2355 | // `--scope` can ONLY be honored by a foreground server we boot here. | ||
| 2356 | // Without `--foreground` we just open whatever background service is | ||
| 2357 | // already running, which uses the scope IT was started with — so a | ||
| 2358 | // `--scope` here would be silently ignored and the user could land on a | ||
| 2359 | // different workspace ("where did my config go?"). Say so loudly and | ||
| 2360 | // point at the flag that actually applies it. | ||
| 2361 | if (Option.isSome(scope)) { | ||
| 2362 | console.warn( | ||
| 2363 | `Ignoring --scope ${scope.value}: it only applies with --foreground. ` + | ||
| 2364 | `The running web app uses the scope it was started with. ` + | ||
| 2365 | `Run \`executor web --foreground --scope ${scope.value}\` to serve that workspace.`, | ||
| 2366 | ); | ||
| 2367 | } | ||
| 2355 | yield* openRunningLocalWebApp(); | 2368 | yield* openRunningLocalWebApp(); |
| 2356 | return; | 2369 | return; |
| 2357 | } | 2370 | } |
| @@ -55,3 +55,35 @@ scenario( · 54 unmodified lines | |||
| 55 | } | 55 | } |
| 56 | }), | 56 | }), |
| 57 | ); | 57 | ); |
| 58 | |||
| 59 | scenario( | ||
| 60 | "CLI web · --scope without --foreground warns instead of silently ignoring it", | ||
| 61 | { timeout: 120_000 }, | ||
| 62 | Effect.promise(async () => { | ||
| 63 | // Regression guard for "Had to setup my config again": `executor web --scope X` | ||
| 64 | // without `--foreground` cannot honor the scope (it opens the running service, | ||
| 65 | // which keeps its own scope). That used to be a SILENT no-op — the user lands | ||
| 66 | // on a different workspace and thinks their config vanished. It must warn. | ||
| 67 | const root = mkdtempSync(join(tmpdir(), "executor-web-scope-")); | ||
| 68 | const dataDir = join(root, "data"); | ||
| 69 | const scopeDir = join(root, "workspace"); | ||
| 70 | try { | ||
| 71 | const { stdout, stderr } = await execFileAsync( | ||
| 72 | "bun", | ||
| 73 | ["run", "dev:cli", "web", "--scope", scopeDir], | ||
| 74 | { cwd: repoRoot, env: { ...process.env, EXECUTOR_DATA_DIR: dataDir } }, | ||
| 75 | ); | ||
| 76 | const output = `${stdout}\n${stderr}`; | ||
| 77 | |||
| 78 | expect(output, "the dropped --scope is called out, not silently ignored").toContain( | ||
| 79 | "Ignoring --scope", | ||
| 80 | ); | ||
| 81 | expect(output, "the warning names the scope it dropped").toContain(scopeDir); | ||
| 82 | expect(output, "the warning points at the flag that actually applies scope").toContain( | ||
| 83 | "--foreground", | ||
| 84 | ); | ||
| 85 | } finally { | ||
| 86 | rmSync(root, { recursive: true, force: true }); | ||
| 87 | } | ||
| 88 | }), | ||
| 89 | ); | ||