Marks all checklist items complete and records final merge/CI/issue-close evidence for mosaicstack/stack#454 / #455. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
115 lines
6.0 KiB
Markdown
115 lines
6.0 KiB
Markdown
# Hotfix Scratchpad — `mosaic yolo <runtime>` passes runtime name as initial user message
|
|
|
|
- **Issue:** mosaicstack/stack#454
|
|
- **Branch:** `fix/yolo-runtime-initial-arg`
|
|
- **Type:** Out-of-mission hotfix (not part of Install UX v2 mission)
|
|
- **Started:** 2026-04-11
|
|
|
|
## Objective
|
|
|
|
Stop `mosaic yolo <runtime>` from passing the runtime name (`claude`, `codex`, etc.) as the initial user message to the underlying CLI. Restore the mission-auto-prompt path for yolo launches.
|
|
|
|
## Root cause (confirmed)
|
|
|
|
`packages/mosaic/src/commands/launch.ts:779` — the `yolo <runtime>` action handler:
|
|
|
|
```ts
|
|
.action((runtime: string, _opts: unknown, cmd: Command) => {
|
|
// ... validate runtime ...
|
|
launchRuntime(runtime as RuntimeName, cmd.args, true);
|
|
});
|
|
```
|
|
|
|
Commander.js includes declared positional arguments in `cmd.args`. For `mosaic yolo claude`:
|
|
|
|
- `runtime` (destructured) = `"claude"`
|
|
- `cmd.args` = `["claude"]` — the same value
|
|
|
|
`launchRuntime` treats `["claude"]` as excess positional args, and for the `claude` case that becomes the initial user message. As a secondary consequence, `hasMissionNoArgs` evaluates false, so the mission-auto-prompt path is bypassed too.
|
|
|
|
## Live reproduction (intercepted claude binary)
|
|
|
|
```
|
|
$ PATH=/tmp/fake-claude-bin:$PATH mosaic yolo claude
|
|
[mosaic] Launching Claude Code in YOLO mode...
|
|
argv[1]: --dangerously-skip-permissions
|
|
argv[2]: --append-system-prompt
|
|
argv[3] (len=25601): # ACTIVE MISSION — HARD GATE ...
|
|
argv[4]: claude ← the bug
|
|
```
|
|
|
|
Non-yolo variant `mosaic claude` is clean:
|
|
|
|
```
|
|
argv[1]: --append-system-prompt
|
|
argv[2]: <prompt>
|
|
argv[3]: Active mission detected: MVP. Read the mission state files and report status.
|
|
```
|
|
|
|
## Plan
|
|
|
|
1. Refactor `launch.ts`: extract `registerRuntimeLaunchers(program, handler)` with an injectable handler so commander wiring is testable without spawning subprocesses. `registerLaunchCommands` delegates to it with `launchRuntime` as the handler.
|
|
2. Fix: in the `yolo <runtime>` action, pass `cmd.args.slice(1)` instead of `cmd.args`.
|
|
3. Add `packages/mosaic/src/commands/launch.spec.ts`:
|
|
- Failing-first reproducer: parse `['node','x','yolo','claude']` and assert handler receives `extraArgs=[]` and `yolo=true`.
|
|
- Regression test: parse `['node','x','claude']` asserts handler receives `extraArgs=[]` and `yolo=false`.
|
|
- Excess args: parse `['node','x','yolo','claude','--print','hi']` asserts handler receives `extraArgs=['--print','hi']` (with `--print` kept because `allowUnknownOption` is true).
|
|
- Excess args non-yolo: parse `['node','x','claude','--print','hi']` asserts `extraArgs=['--print','hi']`.
|
|
- Reject unknown runtime under yolo.
|
|
4. Run typecheck, lint, format:check, vitest for `@mosaicstack/mosaic`.
|
|
5. Independent code review (feature-dev:code-reviewer subagent, sonnet tier).
|
|
6. Commit → push → PR via wrappers → merge → CI green → close issue #454.
|
|
7. Release decision (`mosaic-v0.0.30`) deferred to Jason after merge.
|
|
|
|
## Framework compliance sub-findings (out-of-scope; to capture in OpenBrain after)
|
|
|
|
- `~/.config/mosaic/tools/git/issue-create.sh` uses `eval` on `$BODY`; arbitrary bodies with backticks, `$`, or parens break catastrophically.
|
|
- `gitea_issue_create_api` fallback uses `curl -fsS` without `-L`; after the `mosaicstack/mosaic-stack → mosaicstack/stack` rename, the API redirect is not followed and the fallback silently fails.
|
|
- Local repo `origin` remote still points at old `mosaic/mosaic-stack.git` slug. Not touched here per git-config safety rule.
|
|
- `~/.config/mosaic/TOOLS.md` referenced by the global load order but does not exist on disk.
|
|
|
|
These will be captured to OpenBrain after the hotfix merges so they don't get lost, and filed as separate tracking items.
|
|
|
|
## Progress checkpoints
|
|
|
|
- [x] Branch created (`fix/yolo-runtime-initial-arg`)
|
|
- [x] Issue #454 opened
|
|
- [x] Scratchpad scaffolded
|
|
- [x] Failing test added (red)
|
|
- [x] Refactor + fix applied
|
|
- [x] Tests green (launch.spec.ts 11/11)
|
|
- [x] Baselines green (typecheck, lint, format:check, vitest — pre-existing `uninstall.spec.ts:138` failure on branch main acknowledged, not caused by this change)
|
|
- [x] Code review pass (feature-dev:code-reviewer, sonnet — no blockers)
|
|
- [x] Commit + push (commit 1dd4f59)
|
|
- [x] PR opened (mosaicstack/stack#455)
|
|
- [x] CI queue guard cleared (no pending pipelines pre-push or pre-merge)
|
|
- [x] PR merged (squash merge commit b2cec8c6bac29336a6cdcdb4f19806f7b5fa0054)
|
|
- [x] CI green on main (`ci/woodpecker/push/ci` + `ci/woodpecker/push/publish` both success on merge commit)
|
|
- [x] Issue #454 closed
|
|
- [x] Scratchpad final evidence entry
|
|
|
|
## Tests run
|
|
|
|
- `pnpm --filter @mosaicstack/mosaic run typecheck` → green
|
|
- `pnpm --filter @mosaicstack/mosaic run lint` → green
|
|
- `pnpm --filter @mosaicstack/mosaic exec prettier --check "src/**/*.ts"` → green
|
|
- `pnpm --filter @mosaicstack/mosaic exec vitest run src/commands/launch.spec.ts` → 11/11 pass
|
|
- `pnpm --filter @mosaicstack/mosaic exec vitest run` → 270/271 pass (1 pre-existing `uninstall.spec.ts:138` EACCES failure, confirmed on the branch before this change)
|
|
- `pnpm typecheck` (repo) → green
|
|
- `pnpm lint` (repo) → green
|
|
- `pnpm format:check` (repo) → green (after prettier-writing the scratchpad)
|
|
|
|
## Risks / blockers
|
|
|
|
None expected. Refactor is small and the Commander API is stable. Test needs `exitOverride()` to prevent `process.exit` on invalid runtime.
|
|
|
|
## Final verification evidence
|
|
|
|
- PR: mosaicstack/stack#455 — state `closed`, merged.
|
|
- Merge commit: `b2cec8c6bac29336a6cdcdb4f19806f7b5fa0054` (squash to `main`).
|
|
- Post-merge CI (main @ b2cec8c6): `ci/woodpecker/push/ci` = success, `ci/woodpecker/push/publish` = success. (`ci/woodpecker/tag/publish` was last observed as a pre-existing failure on the prior release tag and is unrelated to this change.)
|
|
- Issue mosaicstack/stack#454 closed with a comment linking the merge commit.
|
|
- Launch regression suite: `launch.spec.ts` 11/11 pass on main.
|
|
- Baselines on main after merge are inherited from the PR CI run.
|
|
- Release decision (`mosaicstack/mosaic` 0.0.30) intentionally deferred to the user — the fix is now sitting on main awaiting a release cut.
|