feat(ultraplan-local): Bug 4 — wire --cleanup into /ultracontinue-local [skip-docs]

Step 10 of v3.4.1 plan.

commands/ultracontinue-local.md:
- New Phase 0.5 between Phase 0 and Phase 1 — terminal cleanup mode
  triggered by parsed flags['--cleanup'] === true. Requires explicit
  positional[0] (no "clean all"), no template placeholders in the Bash
  invocation. Passes through to cleanupProject via inline ESM. Cleanup
  never falls through to Phase 1/2/3/4.
- Phase 0 usage block updated to document --cleanup and --cleanup
  --confirm forms alongside the legacy <project-dir> form.

tests/commands/ultracontinue.test.mjs:
- Test (Bug 4 prose) — Phase 0.5 header present, references
  cleanupProject and flags['--cleanup'], appears between Phase 0 and
  Phase 1 in document order, usage mentions --cleanup --confirm.
- Test (f-1) dry-run on completed project lists candidates without
  deleting; both files still on disk.
- Test (f-2 + f-3) confirm-mode deletes both files; subsequent
  invocation on the already-cleaned dir signals CLEANUP_NO_STATE_FILE
  (deterministic terminal state, idempotent for operators).

Tests 355 -> 358 (+3).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-04 17:42:56 +02:00
commit 9fa83bdf2f
2 changed files with 133 additions and 3 deletions

View file

@ -46,9 +46,11 @@ Phase 1. Do NOT print the usage block on empty args.
/ultracontinue — Resume the next session in a multi-session ultraplan project.
Usage:
/ultracontinue # auto-discover state file under cwd
/ultracontinue <project-dir> # explicit project directory
/ultracontinue --help # this message
/ultracontinue # auto-discover state file under cwd
/ultracontinue <project-dir> # explicit project directory
/ultracontinue --cleanup <project-dir> # dry-run: list stale files
/ultracontinue --cleanup --confirm <project-dir> # actually delete (requires status: completed)
/ultracontinue --help # this message
Reads .claude/projects/<project>/.session-state.local.json (per-project,
gitignored). On a valid resumable state, prints a 3-line summary and begins
@ -72,6 +74,52 @@ Typical flow:
/ultracontinue # reads session-state, runs next session
```
## Phase 0.5 — Cleanup mode dispatch
After `parseArgs` has resolved `$ARGUMENTS`, check the parsed `flags`
object directly (NOT a string contains-check on raw `$ARGUMENTS` — that
substring pattern was the root cause of Bug 1).
If `flags['--cleanup'] === true`, switch into the terminal cleanup
flow and do NOT proceed to Phase 1 or any later phase.
**Required positional:** an explicit `<project-dir>` (`positional[0]`).
There is no "clean all" mode — accidental wholesale deletion would be
irreversible. If `positional[0]` is missing, empty, or starts with `-`,
print this usage block to stderr and exit non-zero:
```
Error: /ultracontinue-local --cleanup requires <project-dir>.
Usage:
/ultracontinue-local --cleanup <project-dir> # dry-run: list stale files
/ultracontinue-local --cleanup --confirm <project-dir> # actually delete (status: completed)
```
**Compute mode from parsed flags:**
```
dryRun = (flags['--confirm'] !== true)
confirm = (flags['--confirm'] === true)
```
**Invoke cleanup inline.** Emit the concrete project-dir path as a literal
token in the Bash command — never a template placeholder — same
anti-substitution rule as Phase 2:
```
node --input-type=module -e "import {cleanupProject} from './lib/util/cleanup.mjs'; const [, dir, mode] = process.argv; const r = cleanupProject(dir, {dryRun: mode !== 'confirm', confirm: mode === 'confirm'}); console.log(JSON.stringify(r, null, 2)); process.exit(r.valid ? 0 : 1)" '<RESOLVED-PROJECT-DIR>' '<MODE>'
```
Substitute `<RESOLVED-PROJECT-DIR>` with the literal `positional[0]`
value you have in your working context, and `<MODE>` with either the
literal string `dryrun` or the literal string `confirm` based on the
booleans above. The validator emits a `{valid, errors, warnings, parsed}`
JSON record. Print it to stdout. Exit with the validator's exit code.
**Cleanup is a terminal mode.** It must not fall through to Phase 1/2/3/4.
Operators who want to resume after cleanup must invoke `/ultracontinue`
again without `--cleanup`.
## Phase 1 — Resolve project directory
The parsed `positional[0]` from Phase 0 is the explicit project-dir argument,