Skip to content

feat(deep-link): Phase 2 — CLI dispatch, bootstrap integration, TUI notification, --init wizard#5052

Merged
bug-ops merged 3 commits into
mainfrom
deep-link-phase-2
Jun 7, 2026
Merged

feat(deep-link): Phase 2 — CLI dispatch, bootstrap integration, TUI notification, --init wizard#5052
bug-ops merged 3 commits into
mainfrom
deep-link-phase-2

Conversation

@bug-ops

@bug-ops bug-ops commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • url-open <URI> CLI subcommand dispatches zeph:// deep links with INV-LOOP guard (ZEPH_URL_OPEN_DEPTH), URI parse, CWD validation, confirm gate, and prompt injection into the agent bootstrap path
  • url-scheme register/unregister/status subcommands for Linux (.desktop + xdg-mime), macOS (manual instructions), Windows (reg.exe)
  • --init wizard gains a step_deep_link section — scheme registration toggle and confirm_before_prompt preference
  • TUI emits a status bar notification ("Opened via deep link: …") within 1 s of warmup and auto-clears after 3 s
  • AgentBuilder::with_initial_message builder method added in zeph-core
  • All code gated behind #[cfg(feature = "deep-link")]

Closes #5013

Security invariants implemented

  • INV-LOOP: ZEPH_URL_OPEN_DEPTH=1 env guard prevents re-entrant dispatch
  • INV-NOTTY: no-TTY stdin → prompt discarded, blank session started
  • INV-TRUST: prompt sanitized via ContentSanitizer::sanitize with ContentSourceKind::McpResponse (ExternalUntrusted + spotlighting) before with_initial_message
  • INV-CWD: validate_deep_link_cwd (absolute, canonicalize, denylist, allowlist) from Phase 1 used on every dispatch

Test plan

  • cargo nextest run --workspace --features deep-link --lib --bins10823 PASS
  • cargo +nightly fmt --check — clean
  • cargo clippy --all-targets --features deep-link -p zeph -- -D warnings — clean
  • RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --features deep-link --locked — clean
  • RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --features desktop,ide,server,chat,pdf,scheduler --locked — clean (confirmed)
  • RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --features deep-link -p zeph — clean
  • Live OS registration (Linux xdg-mime + macOS manual) — pending (requires TTY session)
  • TTY confirm gate interactive flow — pending (requires interactive terminal)
  • TUI notification timing (800 ms delay, 3 s auto-clear) — pending (requires --tui --features tui,deep-link)

Known Phase 2 scope gaps (deferred to Phase 3)

  • model URI parameter is validated but not wired to provider override (Phase 3)
  • prefer_acp = auto/always is parsed but treated as Never (Phase 3)
  • macOS full .app wrapper auto-registration (Phase 3, OQ-1)

@github-actions github-actions Bot added documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate enhancement New feature or request size/XL Extra large PR (500+ lines) labels Jun 7, 2026
bug-ops added 3 commits June 8, 2026 01:18
…otification, --init wizard

Implements spec-066 Phase 2 (closes #5013):

- src/url_scheme/prompt.rs: `confirm_prompt` / `ConfirmResult` — INV-NOTTY
  (no-TTY → Discarded) and interactive y/N gate before prompt injection
- src/url_scheme/register.rs: Linux (.desktop + xdg-mime), macOS (manual
  instructions), Windows (reg.exe) scheme registration; `url-scheme
  register/unregister/status` commands
- src/cli.rs: `url-open <URI>` and `url-scheme register/unregister/status`
  subcommands; hidden `--deep-link-prompt` / `--deep-link-uri` bootstrap fields
- src/runner.rs: `handle_url_open` — INV-LOOP guard (ZEPH_URL_OPEN_DEPTH),
  URI parse, CWD validation, model validation, confirm gate, CLI field stash;
  `url-scheme` commands wired in main dispatch
- src/tui_bridge.rs: `TuiRunParams::deep_link_uri` field; `run_tui_agent`
  emits AgentEvent::Status notification within 1 s of warmup, auto-clears
  after 3 s (spec-066 §9)
- src/init/mod.rs: `step_deep_link` wizard step — scheme registration toggle
  and `confirm_before_prompt` preference; OS registration triggered in
  `step_review_and_write` after config write
- crates/zeph-core/src/agent/builder.rs: `with_initial_message` builder method

All code gated behind `#[cfg(feature = "deep-link")]`.
10817 tests pass; fmt, clippy, RUSTFLAGS=-D warnings clean.
P1: remove erroneous `return` from UrlOpen match arm — `run()` now falls
through to the normal agent bootstrap path after `handle_url_open` succeeds.

C1 (INV-TRUST): invoke `ContentSanitizer::sanitize` with
`ContentSourceKind::McpResponse` (ExternalUntrusted) on the deep-link prompt
before passing it to `with_initial_message`. Injection patterns are flagged
and the prompt is wrapped in the external-data spotlighting envelope.

S1: add `tracing::warn!` documenting that the validated model name is not yet
wired into the session (provider switching deferred to Phase 3).

M1: consolidate three `Config::load` calls in `handle_url_open` into one at
the top of the function.

M2: move the TUI deep-link notification task from `tokio::spawn` (dropped
handle) to `forwarders.spawn` (tracked in the existing JoinSet, aborted on
TUI/agent exit).

M3: correct `SAFETY` comment — tokio runtime is active; the actual guarantee
is that no concurrent code reads ZEPH_URL_OPEN_DEPTH on this call path.

M4: add three unit tests — `deep_link_prompt_sanitizer_applies_mcp_response_source`
(C1 coverage), `model_error_message_lists_known_providers`, and
`model_error_message_none_configured` (unknown-model error path coverage).

10823 tests pass; fmt, clippy, RUSTFLAGS=-D warnings clean.
- Extract deep-link notification task into a helper function to bring
  run_tui_agent under the 100-line clippy limit
- Add cfg_attr allow(unused_mut) on runner::run for builds without the
  deep-link feature where mut cli is unnecessary
- Remove broken intra-doc link to private QueuedMessage type in
  AgentBuilder::with_initial_message doc comment
@bug-ops
bug-ops force-pushed the deep-link-phase-2 branch from e8872b9 to de6d71a Compare June 7, 2026 23:18
@bug-ops
bug-ops enabled auto-merge (squash) June 7, 2026 23:20
@bug-ops
bug-ops merged commit cc95165 into main Jun 7, 2026
35 checks passed
@bug-ops
bug-ops deleted the deep-link-phase-2 branch June 7, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core zeph-core crate documentation Improvements or additions to documentation enhancement New feature or request rust Rust code changes size/XL Extra large PR (500+ lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(deep-link): Phase 2 — CLI dispatch, bootstrap integration, TUI

1 participant