✨ feat: redesign CLI with context-aware addressing#76
Conversation
Covers the full command tree reorganisation (project/worktree/window/pane resource groups), env-var-defaulted address flags (MORI_PROJECT/WORKTREE/ WINDOW/PANE_ID), new IPC commands needed, migration/deprecation stance, and a shared address-resolution helper pattern. Assisted-by: Claude Code:claude-sonnet-4-6
- Remove all backward-compatibility aliases; old commands are gone - pane list now scopes to current window by default (mirrors window list scoping to current worktree), with no-filter fallback for global view - Add symmetry table showing list/new/rename/close across all resource levels - paneSend and windowNew replace the removed .send / .newWindow IPC cases Assisted-by: Claude Code:claude-sonnet-4-6
README: - Lead with the problem Mori solves, not a feature list - Add mental model section with Project→Worktree→Window→Pane hierarchy diagram - Show the tmux mapping inline so readers understand the model immediately - Update CLI section to reflect new flag-based command design - Fix "tab" label (was "New tab", now "New window (tab)" to match UI) architecture.md: - Replace single-paragraph mapping with a table + named explanations - Document MORI_* env var injection (was undocumented here) README.zh-Hans.md: full sync with English changes Assisted-by: Claude Code:claude-sonnet-4-6
Implements the full CLI redesign from docs/cli-redesign.md: - IPC layer: add worktreeList/Delete, windowList/New/Rename/Close, paneNew/Send/Rename/Close, focusWindow; remove .send and .newWindow - TmuxBackend: add renamePane (tmux select-pane -T) - WorkspaceManager: add deleteWorktree() headless method, new WorkspaceError cases (worktreeNotFound, cannotDeleteMainWorktree) - IPCHandler: handlers for all new commands; shared resolveWorktree/ resolveWindow helpers; WindowEntry/PaneNewEntry response models - CLI: Window command group; WorktreeCmd gains list/delete; PaneCmd gains new/send/rename/close; all address args replaced with --flags + env-var resolution; resolveRequired/resolveOptional helpers - OutputFormatter: formatWorktreeList, formatWindowList, formatPaneNew - Localization: en + zh-Hans strings for all new commands - Tests: update MoriIPC tests to match new command signatures; add round-trip tests for all new commands (77 assertions, all pass) Assisted-by: Claude:claude-sonnet-4-6
Assisted-by: Claude:claude-sonnet-4-6
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd4140644c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let proj = try resolveRequired(project, envKey: "MORI_PROJECT", label: "project") | ||
| let wt = try resolveRequired(worktree, envKey: "MORI_WORKTREE", label: "worktree") | ||
| let win = try resolveRequired(window, envKey: "MORI_WINDOW", label: "window") | ||
| let paneId = resolveOptional(pane, envKey: "MORI_PANE_ID") |
There was a problem hiding this comment.
Stop defaulting pane target when window is overridden
This line always resolves pane from MORI_PANE_ID; inside Mori terminals that env var is set, so mori pane send --window logs "q" (documented in this command’s examples) will still target the current pane instead of the active pane in logs. That means window/worktree overrides can silently send keys to the wrong process unless users remember to also pass --pane every time.
Useful? React with 👍 / 👎.
| // project only — focus its last active worktree; requires a worktree to be known | ||
| // Fall back to requiring worktree | ||
| throw CLIError.missingAddress(label: "worktree", envKey: "MORI_WORKTREE") |
There was a problem hiding this comment.
Implement advertised project-only focus behavior
The new focus help text advertises a project-only mode, but this branch unconditionally errors when no worktree is resolved. As a result, mori focus --project myapp fails outside a Mori pane instead of focusing that project’s last active worktree, so the documented redesign behavior is not actually available.
Useful? React with 👍 / 👎.
| let proj = try resolveRequired(project, envKey: "MORI_PROJECT", label: "project") | ||
| let wt = try resolveRequired(worktree, envKey: "MORI_WORKTREE", label: "worktree") | ||
| let data = try sendIPCRequest(.worktreeDelete(project: proj, worktree: wt)) | ||
| printSuccess(data, json: output.json, label: "Deleted worktree '\(wt)'") |
There was a problem hiding this comment.
Localize new CLI success strings
/workspace/mori/AGENTS.md requires that all new user-facing strings use .localized(), but this new success message is hard-coded English. The same pattern appears across other added commands, so zh-Hans users will receive untranslated output and localization coverage regresses.
Useful? React with 👍 / 👎.
- pane send: don't inherit MORI_PANE_ID when --window is explicitly overridden (would send to wrong pane in the target window) - localize all hard-coded success strings in CLI commands - add focusProject IPC command so `mori focus --project myapp` works without requiring a worktree Assisted-by: Claude:claude-sonnet-4-6
Replace outdated positional-arg reference with the new context-aware command tree: worktree list/delete, window group, pane new/send/rename/ close, focus improvements, and an expanded Agent Integration section with discovery, parallel pane splitting, and a minimal bash example. Assisted-by: Claude:claude-sonnet-4-6
Summary
--project,--worktree,--window,--pane) defaults to the matchingMORI_*env var — zero ceremony inside Mori terminalsmori windowgroup:list,new,rename,closemori worktree list+worktree delete: headless delete kills tmux session and removes the git worktreepane new(split),pane send,pane rename,pane closemori focusupgraded: now accepts--windowto target a specific windowpane listscoping:--windowfilter; inside a Mori terminal defaults to the current windowsend,new-window, and positionalfocusWhat's in this branch
5a5b2aececb78fbc26dea86e0b36dd41406Test plan
mise run test— all 983 assertions pass (core 657, ipc 77, tmux 249)swift build --product Mori+swift build --product moriswift build -c release --product Morimori worktree list,mori window list,mori pane send,mori pane newinside a live Mori terminal🤖 Generated with Claude Code