docs: tighten managed CLI install notes
This commit is contained in:
@@ -1,233 +1,84 @@
|
||||
# Managed CLI Global Install Loop Plan
|
||||
# Managed CLI Global Install
|
||||
|
||||
## Task
|
||||
## Status
|
||||
|
||||
Implement a proper desktop-managed CLI install flow for the desktop app.
|
||||
Implemented on this branch.
|
||||
|
||||
The current implementation installs a user-local shim and routes through the desktop app binary with `--paseo-cli-shim <state-file>`. The target design is:
|
||||
The original plan was to replace the desktop app's state-file trampoline CLI install flow with a stable outer shim, a bundle-managed inner launcher, structured install results, UI fallback instructions, and Docker-like CLI default host resolution. That work now exists in code and this file records what shipped.
|
||||
|
||||
- The installed PATH shim must be trivial and stable, like Tailscale.
|
||||
- The installed PATH shim should forward argv to an inner executable/shim inside the app bundle.
|
||||
- The inner executable/shim should resolve the bundled Node runtime and bundled `@getpaseo/cli` entrypoint and invoke the CLI directly.
|
||||
- The CLI should gain Docker-like default connection resolution so the shim does not need to hardcode daemon transport details.
|
||||
- The desktop install button should attempt a best-effort global install and clearly communicate that a permissions prompt may appear.
|
||||
- If global install does not succeed, the app must present a fallback dialog with exact platform-specific terminal instructions.
|
||||
## What Exists
|
||||
|
||||
This work must be planned and implemented cleanly, not patched onto the current state-file trampoline design.
|
||||
### Desktop runtime and launcher
|
||||
|
||||
## Relevant Code And Current Behavior
|
||||
- The desktop runtime bundle is assembled by [build-managed-runtime.mjs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/scripts/build-managed-runtime.mjs).
|
||||
- The Tauri runtime manager now maintains:
|
||||
- a stable inner launcher under `bin/`
|
||||
- a trivial outer PATH shim
|
||||
- structured CLI install/uninstall results
|
||||
- manual install instructions
|
||||
- The old `--paseo-cli-shim <state-file>` trampoline is no longer the installed shim path.
|
||||
|
||||
- `packages/desktop/src-tauri/src/runtime_manager.rs`
|
||||
- Contains managed runtime install logic, CLI shim install/uninstall logic, and the current `try_run_cli_shim_from_args()` trampoline path.
|
||||
- Today the installed shim calls the desktop app executable, passes `--paseo-cli-shim <state-file>`, and the app then resolves bundled Node + bundled CLI and execs them.
|
||||
- Today macOS/Linux install to `~/.local/bin/paseo`; Windows installs a `.cmd` shim under the user data dir.
|
||||
- `packages/desktop/src-tauri/src/lib.rs`
|
||||
- Exposes `install_cli_shim` / `uninstall_cli_shim` Tauri commands and includes some desktop-side `command -v paseo` checks.
|
||||
- `packages/app/src/desktop/managed-runtime/managed-runtime.ts`
|
||||
- TypeScript bridge for desktop managed-runtime commands.
|
||||
- Today `CliShimResult` is only `{ installed, path, message }`.
|
||||
- `packages/app/src/desktop/components/desktop-updates-section.tsx`
|
||||
- Contains the Install CLI / Uninstall CLI button and current status-message handling.
|
||||
- Today there is no preflight permission notice and no fallback modal with manual commands.
|
||||
- `packages/cli`
|
||||
- The CLI currently expects explicit host wiring in some flows. It needs to be inspected and updated so that when no host is passed it behaves more like Docker:
|
||||
1. use explicit `--host` if provided
|
||||
2. otherwise try local socket / local pipe first
|
||||
3. then fall back to `localhost:6767`
|
||||
Relevant files:
|
||||
|
||||
## Implementation Requirements
|
||||
- [runtime_manager.rs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/src-tauri/src/runtime_manager.rs)
|
||||
- [lib.rs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/src-tauri/src/lib.rs)
|
||||
- [build-managed-runtime.mjs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/scripts/build-managed-runtime.mjs)
|
||||
- [managed-daemon-smoke.mjs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/scripts/managed-daemon-smoke.mjs)
|
||||
|
||||
### 1. Replace the current installed shim architecture with a two-shim design
|
||||
### App UI and desktop bridge
|
||||
|
||||
Implement two distinct layers:
|
||||
- The desktop bridge exposes a structured `CliShimResult` with explicit statuses and optional manual instructions.
|
||||
- The desktop settings UI now:
|
||||
- warns that a permissions prompt may appear before install starts
|
||||
- opens a dedicated modal when manual install is required
|
||||
- shows copyable platform-specific commands
|
||||
|
||||
- Outer PATH shim:
|
||||
- Must be extremely simple and stable.
|
||||
- It should do nothing except invoke an inner executable or shim within the installed app/bundle and forward argv.
|
||||
- It must not embed managed runtime state, a state-file path, runtime id, socket path, or transport details.
|
||||
- On macOS, the desired style is comparable to:
|
||||
`#!/bin/sh`
|
||||
`exec /Applications/Paseo.app/Contents/MacOS/paseo "$@"`
|
||||
- Inner bundle shim / entrypoint:
|
||||
- Lives inside the app bundle / managed runtime and is responsible for finding bundled Node and the bundled CLI entrypoint.
|
||||
- It should invoke the bundled CLI directly, as if launching the packaged CLI with bundled Node.
|
||||
- It must not route back through the desktop app command trampoline with `--paseo-cli-shim`.
|
||||
Relevant files:
|
||||
|
||||
Remove or obsolete the current state-file-based trampoline path if the new direct inner-shim path fully replaces it.
|
||||
- [managed-runtime.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/desktop/managed-runtime/managed-runtime.ts)
|
||||
- [desktop-updates-section.tsx](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/desktop/components/desktop-updates-section.tsx)
|
||||
|
||||
### 2. Make CLI host resolution work by default without shim transport knowledge
|
||||
### CLI default host resolution
|
||||
|
||||
Update the CLI so that the launcher does not have to inject managed socket details in the normal case.
|
||||
- The CLI now resolves default daemon targets in this order when `--host` is not provided:
|
||||
1. local IPC target if discoverable
|
||||
2. configured non-default TCP target
|
||||
3. `localhost:6767`
|
||||
|
||||
Desired behavior when the user runs `paseo` and no host is explicitly passed:
|
||||
Relevant files:
|
||||
|
||||
1. If `--host` is passed, use it.
|
||||
2. Otherwise, try the platform-appropriate local managed/default transport first:
|
||||
- Unix socket on macOS/Linux
|
||||
- Named pipe on Windows, if supported by the CLI host format
|
||||
3. If no local transport is available, fall back to `localhost:6767`.
|
||||
- [client.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/cli/src/utils/client.ts)
|
||||
- [28-client-ipc-targets.test.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/cli/tests/28-client-ipc-targets.test.ts)
|
||||
|
||||
The judge must verify the actual host-resolution code path and ensure it is not just documentation text.
|
||||
## Files Created For This Work
|
||||
|
||||
### 3. Add best-effort global install behavior for the desktop-managed CLI
|
||||
- [MANAGED_CLI_GLOBAL_INSTALL_LOOP_PLAN.md](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/MANAGED_CLI_GLOBAL_INSTALL_LOOP_PLAN.md)
|
||||
- [managed-runtime.test.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/desktop/managed-runtime/managed-runtime.test.ts)
|
||||
- [managed-runtime.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/desktop/managed-runtime/managed-runtime.ts)
|
||||
- [managed-tauri-daemon-transport.test.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/utils/managed-tauri-daemon-transport.test.ts)
|
||||
- [managed-tauri-daemon-transport.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/app/src/utils/managed-tauri-daemon-transport.ts)
|
||||
- [28-client-ipc-targets.test.ts](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/cli/tests/28-client-ipc-targets.test.ts)
|
||||
- [build-managed-runtime.mjs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/scripts/build-managed-runtime.mjs)
|
||||
- [managed-daemon-smoke.mjs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/scripts/managed-daemon-smoke.mjs)
|
||||
- [runtime_manager.rs](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/src-tauri/src/runtime_manager.rs)
|
||||
- [resources/.gitkeep](/Users/moboudra/.paseo/worktrees/1luy0po7/managed-daemon-bundle/packages/desktop/src-tauri/resources/.gitkeep)
|
||||
|
||||
The desktop Install CLI action should attempt to install the outer shim globally in a platform-appropriate location.
|
||||
## Acceptance Check
|
||||
|
||||
Platform expectations:
|
||||
- Stable outer shim: covered by runtime-manager tests that assert the outer shim forwards to a stable inner launcher and does not encode runtime-specific roots.
|
||||
- Inner launcher: implemented inside the managed runtime tree and invoked directly by the outer shim.
|
||||
- Structured install results: implemented in Rust and parsed in TypeScript without string matching.
|
||||
- Permission notice and fallback modal: implemented in the desktop settings UI.
|
||||
- macOS global target: `/usr/local/bin/paseo`.
|
||||
- CLI host ordering: covered by CLI tests, including the non-default TCP fallback case.
|
||||
|
||||
- macOS:
|
||||
- Prefer `/usr/local/bin/paseo`.
|
||||
- Attempt a privileged install so the user sees the normal macOS admin-password prompt when needed.
|
||||
- The flow should be initiated from the click action.
|
||||
- Linux:
|
||||
- Best effort only.
|
||||
- If a reliable privileged install path is not available, fall back to manual instructions.
|
||||
- Do not fake success.
|
||||
- Windows:
|
||||
- Best effort only.
|
||||
- If protected install cannot be completed automatically, return a manual-instructions path.
|
||||
## Verification
|
||||
|
||||
Do not silently keep the old user-local install path as the primary desktop behavior on macOS.
|
||||
- Run `npm run typecheck`
|
||||
- Run targeted tests for the CLI and desktop-managed runtime paths
|
||||
- Perform a manual macOS smoke check for the privileged `/usr/local/bin/paseo` install flow
|
||||
|
||||
### 4. Add explicit user-facing permission guidance before and after the attempt
|
||||
## Remaining Manual Validation
|
||||
|
||||
When the user clicks Install CLI in the desktop UI:
|
||||
|
||||
- Immediately show a clear status line or notice saying that a permissions popup may appear to install the CLI globally.
|
||||
- Do this before awaiting the install attempt, so the user understands what is happening.
|
||||
|
||||
If installation fails, or if the backend reports that manual action is required:
|
||||
|
||||
- Open a dedicated dialog/modal in the desktop UI.
|
||||
- The modal should clearly explain:
|
||||
- A permissions popup should appear prompting for permission to install the CLI globally.
|
||||
- If it does not work, open a terminal and run the provided commands.
|
||||
- Include a selectable and copyable code block with exact platform-specific commands.
|
||||
|
||||
### 5. Return structured install results from the desktop backend
|
||||
|
||||
Expand the desktop backend/frontend result shape for CLI install so the UI can make decisions without parsing freeform error strings.
|
||||
|
||||
The result must be rich enough to distinguish at least:
|
||||
|
||||
- install succeeded automatically
|
||||
- install failed because elevation was denied
|
||||
- install could not be attempted automatically on this platform
|
||||
- manual installation is required
|
||||
|
||||
It must also include:
|
||||
|
||||
- installed path, when available
|
||||
- a user-facing summary message
|
||||
- manual instructions payload, when required
|
||||
|
||||
### 6. Manual fallback instructions must be real and platform-specific
|
||||
|
||||
The fallback dialog must show platform-specific commands that match the actual chosen launcher architecture.
|
||||
|
||||
That means the commands should install or write the simple outer shim that points at the inner app/bundle shim.
|
||||
|
||||
The commands must use real paths derived from the installed app/runtime layout, not placeholder pseudo-paths.
|
||||
|
||||
They must be quoted correctly for spaces in file paths.
|
||||
|
||||
### 7. Preserve or update uninstall behavior coherently
|
||||
|
||||
Uninstall CLI must continue to remove the installed outer shim from whatever location the new install flow uses.
|
||||
|
||||
If install location or result state changes, update the stored metadata and uninstall behavior accordingly.
|
||||
|
||||
### 8. Update or add verification coverage where practical
|
||||
|
||||
Add or update tests for the new behavior where practical and already patterned in the codebase.
|
||||
|
||||
At minimum, verify:
|
||||
|
||||
- any changed TypeScript types and desktop command parsing
|
||||
- any changed Rust result serialization assumptions
|
||||
- any changed CLI host-resolution logic
|
||||
|
||||
If automated coverage for the privileged install is impractical, document the manual verification path in code comments or test notes near the relevant smoke/integration checks rather than hand-waving it away.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Do not reintroduce or preserve the current state-file-based app trampoline design unless strictly required for a narrow compatibility bridge.
|
||||
- Do not parse user-facing error strings in the frontend to determine behavior.
|
||||
- Do not implement the UI fallback as a generic alert with truncated instructions; use a proper modal/dialog with copyable command text.
|
||||
- Do not leave macOS as a `~/.local/bin` install target for the primary desktop-managed global install flow.
|
||||
- Do not skip typecheck. The repo instructions require typecheck after every change.
|
||||
- Be careful with existing unrelated worktree changes; do not revert unrelated user changes.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
The judge should mark the loop successful only if all of the following are true:
|
||||
|
||||
1. The installed outer shim architecture has been simplified so it is a trivial forwarder to an inner app/bundle shim or executable, with no embedded managed state-file path.
|
||||
2. The inner app/bundle shim directly invokes bundled Node + bundled CLI, rather than re-entering the desktop app via the current `--paseo-cli-shim` trampoline.
|
||||
3. CLI default host resolution has been updated in code so that no-host invocation first prefers local transport and then falls back to `localhost:6767`.
|
||||
4. The desktop Install CLI UI shows an up-front notice that a permissions popup may appear.
|
||||
5. The desktop install flow returns structured results that distinguish automatic success from manual fallback cases.
|
||||
6. On failure or manual-required paths, the desktop UI opens a dedicated dialog/modal with copyable platform-specific terminal instructions.
|
||||
7. macOS best-effort install targets `/usr/local/bin/paseo` and is implemented as a privileged install attempt rather than the old user-local path.
|
||||
8. Uninstall behavior remains coherent with the new install location and metadata.
|
||||
9. `npm run typecheck` passes.
|
||||
10. Any relevant tests added or changed by the implementation pass, or the worker explicitly documents why a test path is not runnable and what was verified instead.
|
||||
|
||||
## Hard Acceptance Criteria
|
||||
|
||||
The following are non-negotiable. If any one of them is not true in the code, the judge must return `criteria_met: false`.
|
||||
|
||||
### H1. Stable outer shim across runtime updates
|
||||
|
||||
The installed outer PATH shim must not hardcode a versioned managed-runtime path.
|
||||
|
||||
This specifically means:
|
||||
|
||||
- The installed outer shim at `/usr/local/bin/paseo` on macOS/Linux, or the Windows outer shim path, must not point directly into `paths.runtime_root` or any runtime-id/version-specific directory.
|
||||
- Updating the managed runtime to a new runtime id/version must not require reinstalling the outer PATH shim just to keep `paseo` working.
|
||||
- The outer shim may point at a stable app-bundle executable path or another stable non-versioned path under app-owned state, but not a versioned runtime root.
|
||||
|
||||
The judge must inspect the actual generated launcher code paths and fail if the installed shim still embeds a runtime-root-specific target.
|
||||
|
||||
### H2. CLI default host resolution must preserve configured non-default TCP daemons
|
||||
|
||||
The new CLI default-resolution logic must not discard a configured non-IPC TCP daemon endpoint.
|
||||
|
||||
Required order when `--host` is not passed:
|
||||
|
||||
1. If an explicit host override is present, use it.
|
||||
2. Otherwise, if a local IPC target is discoverable, prefer it first.
|
||||
3. Otherwise, if config or environment resolves to a TCP listen target, use that configured TCP target.
|
||||
4. Only if none of the above is available, fall back to `localhost:6767`.
|
||||
|
||||
This means a user who has intentionally configured the daemon on a non-default TCP endpoint must still have the CLI connect there by default.
|
||||
|
||||
The judge must fail if the implementation:
|
||||
|
||||
- always falls back to `localhost:6767` after checking only IPC candidates, or
|
||||
- ignores configured TCP listen values when no IPC target exists.
|
||||
|
||||
### H3. Tests must prove both hard cases
|
||||
|
||||
Automated verification must cover both failure modes found in review:
|
||||
|
||||
- a test or equivalent deterministic proof that the outer shim target remains stable across runtime updates / runtime-id changes, or at minimum that it resolves through a stable path that does not encode the runtime root
|
||||
- a CLI host-resolution test proving that when no IPC target exists but config/environment specifies a non-default TCP daemon endpoint, that endpoint is chosen before `localhost:6767`
|
||||
|
||||
The judge must not accept hand-wavy reasoning in place of these checks.
|
||||
|
||||
## Execution Notes For Worker
|
||||
|
||||
- Start by tracing the current shim architecture and the CLI host-resolution path before editing.
|
||||
- Prefer cohesive refactoring over additive patch layers.
|
||||
- Keep the outer shim intentionally dumb.
|
||||
- If you need a temporary compatibility bridge, keep it narrow and justify it in code comments or commit notes.
|
||||
- Run `npm run typecheck` after completing the changes.
|
||||
|
||||
## Execution Notes For Judge
|
||||
|
||||
- Verify the actual code paths, not just strings or comments.
|
||||
- Inspect whether the old `--paseo-cli-shim <state-file>` trampoline still remains as the active path. If so, fail unless it is clearly obsolete and no longer used by the installed outer shim flow.
|
||||
- Verify that the fallback dialog is a real modal/dialog in the UI code and that it contains actionable copyable instructions.
|
||||
- Verify the install target logic on macOS is `/usr/local/bin/paseo`.
|
||||
- Verify `npm run typecheck` was run successfully from logs or explicit output artifacts.
|
||||
- Privileged install and uninstall prompts still need the normal on-device macOS smoke pass.
|
||||
- Merge readiness depends on the branch test pass after rebasing onto `origin/main`.
|
||||
|
||||
Reference in New Issue
Block a user