Skip to content

Add OMP hook installation and session restore - #5413

Merged
austinywang merged 7 commits into
manaflow-ai:mainfrom
joshrzemien:omp-hook-session-restore
Jun 5, 2026
Merged

austinywang merged 7 commits into
manaflow-ai:mainfrom
joshrzemien:omp-hook-session-restore

Conversation

@joshrzemien

@joshrzemien joshrzemien commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds first-class OMP support for cmux session restore:

  • installs/uninstalls OMP hook extension via cmux hooks omp
  • captures OMP session lifecycle events through cmux-omp-session.ts
  • detects OMP sessions from --session, --resume, -r, PI_CODING_AGENT_DIR, and PI_CONFIG_DIR
  • restores OMP launches through CMUXAgentLaunch
  • sanitizes persisted launch metadata so prompts, old session IDs, and secrets are not replayed
  • wires OMP hook and launch tests into CI

Verification

  • ./scripts/reload.sh --tag omp-support-pr
  • xcodebuild test -project cmux.xcodeproj -scheme cmux-unit -destination 'platform=macOS' -derivedDataPath /tmp/cmux-omp-support-pr -only-testing:cmuxTests/OmpSupportTests
  • swift test --package-path Packages/CMUXAgentLaunch
  • python3 tests/test_omp_extension_install.py
  • ./scripts/check-pbxproj.sh
  • ./scripts/lint-pbxproj-test-wiring.sh
  • git diff --check origin/main..HEAD

Localization

No new user-facing UI strings were added. Existing cli.hooks.omp.* localization keys were audited and remain covered.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Adds first-class OMP support. cmux hooks omp installs a native OMP extension that captures lifecycle events, and cmux safely restores OMP sessions; Vault, Task Manager, and CMUXAgentLaunch now detect and resume OMP.

  • New Features

    • cmux hooks omp: install/uninstall a non-blocking extension at ~/.omp/agent/extensions/cmux-omp-session.ts or $PI_CODING_AGENT_DIR/extensions/cmux-omp-session.ts; refuses to delete non-cmux files; opt out via CMUX_OMP_HOOKS_DISABLED=1.
    • Session detection and restore: detect via --session, --resume, -r, PI_CODING_AGENT_DIR, and PI_CONFIG_DIR (explicit selectors win); add built-in omp to Vault/Task Manager with process-name and argv detection (@oh-my-pi/pi-coding-agent) and session dir ~/.omp/agent/sessions; resume with omp --session <id>; per-directory CWD namespacing.
    • Launch safety in CMUXAgentLaunch: treat omp like pi for argv sanitization (drop prompts and session selectors, including -r); preserve PI_CODING_AGENT_DIR and PI_CONFIG_DIR; AgentResumeArgv builds omp --session <id>; docs, CLI help, localization, and CI tests (Swift + tests/test_omp_extension_install.py) updated.
  • Bug Fixes

    • Fixed OMP stop hook payload delivery so stop events include the full payload and reliably persist session end.
    • Avoided blocking OMP stop hook dispatch to prevent hangs during shutdown.
    • Report OMP extension read failures with clear errors to aid troubleshooting.

Written for commit 795243c. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • OMP agent support: CLI commands to install/uninstall OMP hooks, resume and persist OMP sessions, idempotent install with prompts and status messages; OMP treated as a first-class agent for session resume.
  • Documentation

    • Docs and web pages updated with OMP setup, resume command, session-restore behavior, and troubleshooting; localized CLI messages added.
  • Tests

    • New unit and end-to-end tests covering OMP detection, session restore/persistence, and extension install/uninstall.
  • Chores

    • CI updated to run the OMP extension install regression test.

@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

@joshrzemien is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds OMP agent support: embed OMP TypeScript extension with Swift install/uninstall and CLI wiring; register OMP in Vault and TaskManager; parse OMP session selectors and prefer OMP session roots from env; extend agent-launch sanitizer/resume argv; add unit/integration tests, docs, localization, CI, and Xcode wiring.

Changes

OMP Integration

Layer / File(s) Summary
OMP Hook Extension and CLI Integration
CLI/CMUXCLI+OmpExtension.swift, CLI/CMUXCLI+AgentHookDefinitions.swift, CLI/cmux.swift, Resources/Localizable.xcstrings, .github/workflows/ci.yml, cmux.xcodeproj/project.pbxproj
Embed TypeScript OMP session extension and implement Swift install/uninstall (atomic write, idempotency, marker checks, prompts); add CLI wiring for cmux hooks setup omp and install/uninstall branches; add localized strings; add Python regression test run to CI and wire sources into Xcode targets.
Vault Agent Registration & Session Resolution
Sources/VaultAgentRegistry.swift, Sources/VaultAgentProcessScanner.swift, Sources/TaskManagerTypes.swift
Add built-in omp CmuxVaultAgentRegistration; extend detect rule with alternateArgvContains; parse Pi/OMP session selectors (--session, --resume, -r), prefer exact JSONL basename matches, and insert OMP-specific session-root fallbacks using PI_CODING_AGENT_DIR or PI_CONFIG_DIR + HOME.
Agent Launch Pipeline Support
Packages/CMUXAgentLaunch/Sources/...
Add PI_CONFIG_DIR to allowlisted environment keys; apply piPolicy preserved-arguments logic for kind == "omp"; include -r in piPolicy value options; generate resume argv for omp --session <id>.
Tests and Regressions
cmuxTests/OmpSupportTests.swift, Packages/CMUXAgentLaunch/Tests/*, tests/test_omp_extension_install.py
Add Swift tests validating OMP session selector parsing, session-root fallbacks, custom session directory precedence, and process classification; add Python e2e regression exercising install, Bun import/load, hook invocation payloads/env/argv encoding, persistence RPC behavior, and uninstall safeguards; minor test spacing edits.
Documentation and Web UI
docs/agent-hooks.md, docs/feed.md, docs/vault.md, web/app/[locale]/docs/session-restore/page.tsx
Document OMP in hooks/feed/vault docs, add cmux hooks setup omp example, list OMP in session-restore UI and agent table, and document CMUX_OMP_HOOKS_DISABLED env override.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I found a tiny hook to sow,
OMP now joins the cmux flow,
TypeScript tucked in Swift’s warm care,
Sessions leap back from anywhere,
Hop — install, persist, and go!


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error AgentHookDef contains non-Sendable closure property without isolation, violating Swift 6 concurrency rules for shared reference types. Mark configDirResolver as @Sendable closure: let configDirResolver: (@sendable () -> String)? or declare AgentHookDef as nonisolated struct.
Cmux User-Facing Error Privacy ❌ Error The OMP extension install error message includes String(describing: error) which exposes raw NSError descriptions violating the rule against raw upstream error messages. Remove String(describing: error) from the "readFailed" error or use silent error handling like the Pi extension does: (try? ...) ?? empty.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.48% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (15 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Blocking Runtime ✅ Passed Production Swift code adds no blocking/timing synchronization. CMUXCLI+OmpExtension.swift and OMP additions contain zero blocking patterns per swift-blocking-runtime.md.
Cmux No Hacky Sleeps ✅ Passed All sleep patterns found are in tests/test_omp_extension_install.py—deterministic test scaffolding with timeouts. No production code contains hacky sleeps.
Cmux Algorithmic Complexity ✅ Passed OMP support reuses existing Pi session detection with small bounded collections (4 registrations, 1-2 needles). No nested scans, per-target rescans, or new hot paths introduced.
Cmux Swift Concurrency ✅ Passed PR introduces only synchronous Swift code for OMP hooks: synchronous methods, synchronous closures, file I/O without async patterns, no DispatchQueue/Task/Combine additions.
Cmux Swift @Concurrent ✅ Passed All Swift changes in PR are synchronous; no async functions or @concurrent annotations were added or required, fully compliant with swift-concurrent-annotation.md rules.
Cmux Swift File And Package Boundaries ✅ Passed CMUXCLI+OmpExtension.swift (304 lines) is under 400-line threshold for new files, has single cohesive responsibility, and follows established CMUXCLI+AmpExtension pattern. Appropriate CLI glue code.
Cmux Swift Logging ✅ Passed All print statements in new Swift code (CMUXCLI+OmpExtension.swift) are localized, user-facing CLI output (allowed per rules). No secrets, personal data, or inappropriate logging patterns detected.
Cmux Full Internationalization ✅ Passed All 9 OMP Swift user-facing strings use String(localized:...) with complete translations (20 locales); web UI uses next-intl; agent names follow existing hardcoded pattern.
Cmux Swiftui State Layout ✅ Passed No SwiftUI changes present. All modifications are CLI commands, agent infrastructure, session detection, and tests—no View structs, @Published, @StateObject, or layout violations.
Cmux Architecture Rethink ✅ Passed No sleeps, locks, observers, duplicate wiring, or split lifecycle ownership. Adds OMP via standard dispatch pattern and optional configDirResolver extension to AgentHookDef.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR does not create any NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup objects. All changes are CLI configuration and test-only code without UI window creation.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding OMP hook installation and session restore functionality, which aligns with the PR's core objectives.
Description check ✅ Passed The PR description comprehensively covers the summary, testing approach, verification steps, and localization audit, closely matching the template structure.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

205-462: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add explicit least-privilege permissions for the workflow token.

Line 205 onward runs many jobs without a permissions: block, so GITHUB_TOKEN keeps default broad scopes. Please pin permissions explicitly (for most jobs, contents: read) and grant write scopes only to the specific release/upload jobs that need them.

Suggested hardening
 name: CI
+permissions:
+  contents: read
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 205 - 462, Summary: workflow missing
explicit least-privilege permissions for GITHUB_TOKEN in the "tests" job; add a
permissions block. Update the "tests" job definition to include an explicit
permissions: block (e.g., permissions: contents: read) so token scope is
least-privilege for the many steps run under the tests job, and then add/adjust
permissions only on jobs that require write access (release/upload jobs) to
grant specific write scopes (e.g., contents: write, packages: write) instead of
broad defaults; locate and modify the job named "tests" and the release/upload
job(s) that perform publishing to set the minimal required scopes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/CMUXCLI`+AgentHookDefinitions.swift:
- Around line 196-203: The AgentHookDef for "omp" currently lacks
configDirEnvOverride, causing resolvedConfigDir() to disagree with installer
behavior in CMUXCLI+OmpExtension.swift which uses PI_CODING_AGENT_DIR or
PI_CONFIG_DIR/agent; add the appropriate configDirEnvOverride to the
AgentHookDef for name "omp" (matching the env var(s) used by
CMUXCLI+OmpExtension.swift) so AgentHookDef.resolvedConfigDir() and the
installer use the same override-aware path resolution logic.

In `@CLI/CMUXCLI`+OmpExtension.swift:
- Around line 168-177: The ompAgentDirectory() resolver currently treats
PI_CODING_AGENT_DIR and PI_CONFIG_DIR as plain strings and always appends
PI_CONFIG_DIR under $HOME; update it to normalize and respect absolute/tilde
paths: in ompAgentDirectory(), when
nonEmptyEnvironmentValue("PI_CODING_AGENT_DIR", ...) returns a value, expand
tilde (use NSString().expandingTildeInPath) and if the result is an absolute
path use it directly as the agent directory; otherwise treat it as a relative
path as before. For PI_CONFIG_DIR, expand tilde and if the expanded value is
absolute, use that path instead of appending it to home; only append when the
config dir is a relative path. Refer to ompAgentDirectory() and
nonEmptyEnvironmentValue(...) when applying these fixes.

In
`@Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift`:
- Around line 416-443: Extend the
dropsOmpSessionSelectorsWithoutReplayingPrompts test to also assert that
AgentLaunchSanitizer.sanitizedLaunchArguments removes "--session" selectors
(both "--session", "--session=old-session" and combined forms) the same way it
handles "-r" and "--resume"; add expectations calling
AgentLaunchSanitizer.sanitizedLaunchArguments (with launcher: "omp",
fallbackKind: "omp") that input arrays containing "--session",
"--session=old-session" (and a case where "--session" is followed by the session
id as a separate argument) result in the sanitized array without any session
selector and without replaying the original prompt or session id.

In `@Sources/VaultAgentProcessScanner.swift`:
- Around line 1004-1008: The current sessionRoot precedence wrongly calls
ompAgentSessionsRoot(for:registration:) before honoring
registration.sessionDirectory and always synthesizes an OMP path; change the
precedence so registration.sessionDirectory is checked before calling
ompAgentSessionsRoot, and modify ompAgentSessionsRoot usage so it is only
invoked when an explicit OMP override/environment/flag is present (e.g., when
process.arguments.value(afterOption: "--session-dir") or
process.environment["PI_CODING_AGENT_SESSION_DIR"] indicates OMP should be
used); ensure sessionRoot falls back to defaultSessionsRoot() only after
registration.sessionDirectory and explicit omp override are absent, and update
any similar logic around omp handling in the same block (the code that
references sessionRoot, ompAgentSessionsRoot(for:registration:),
registration.sessionDirectory, process.arguments.value(afterOption:),
process.environment["PI_CODING_AGENT_SESSION_DIR"], and defaultSessionsRoot())
to preserve configured registration.sessionDirectory overrides.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 205-462: Summary: workflow missing explicit least-privilege
permissions for GITHUB_TOKEN in the "tests" job; add a permissions block. Update
the "tests" job definition to include an explicit permissions: block (e.g.,
permissions: contents: read) so token scope is least-privilege for the many
steps run under the tests job, and then add/adjust permissions only on jobs that
require write access (release/upload jobs) to grant specific write scopes (e.g.,
contents: write, packages: write) instead of broad defaults; locate and modify
the job named "tests" and the release/upload job(s) that perform publishing to
set the minimal required scopes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2fe67c09-e701-4df5-8024-21caa93c17dd

📥 Commits

Reviewing files that changed from the base of the PR and between 45603c6 and 97980d0.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • CLI/CMUXCLI+AgentHookDefinitions.swift
  • CLI/CMUXCLI+OmpExtension.swift
  • CLI/cmux.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerPrimaryPolicies.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchEnvironmentPolicyTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeWorkingDirectoryTests.swift
  • Resources/Localizable.xcstrings
  • Sources/TaskManagerTypes.swift
  • Sources/VaultAgentProcessScanner.swift
  • Sources/VaultAgentRegistry.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/OmpSupportTests.swift
  • cmuxTests/PiVaultAgentPersistenceTests.swift
  • cmuxTests/TaskManagerResourcesTests.swift
  • docs/agent-hooks.md
  • docs/feed.md
  • docs/vault.md
  • tests/test_omp_extension_install.py
  • web/app/[locale]/docs/session-restore/page.tsx

Comment thread CLI/CMUXCLI+OmpExtension.swift Outdated
Comment thread Sources/VaultAgentProcessScanner.swift
@greptile-apps

greptile-apps Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds first-class OMP support to cmux: a cmux hooks omp CLI command that installs/uninstalls a TypeScript extension at the OMP agent directory, session detection and restore via --session/--resume/-r selectors and environment-based directory resolution (PI_CODING_AGENT_DIR, PI_CONFIG_DIR), and launch-argv sanitization so prompts and old session selectors are not replayed.

  • CLI/CMUXCLI+OmpExtension.swift embeds the TypeScript extension source and handles idempotent install/uninstall with cmux-marker safety; existingOmpExtensionContents surfaces String(describing: error) — raw Cocoa error internals — in the user-facing error path instead of error.localizedDescription.
  • Sources/VaultAgentProcessScanner.swift adds javaScriptRuntimeScriptArgumentIndex, piCompatibleSessionID, and ompAgentSessionsRoot so bun-invoked OMP processes and all three session selectors are correctly resolved; PiSessionLocator now prefers exact session-file basename matches over partial ones.
  • CMUXAgentLaunch changes are minimal: OMP is routed through the existing piPolicy sanitizer with -r added to the stripped options list, and AgentResumeArgv builds omp --session <id> identically to Pi.

Confidence Score: 4/5

Safe to merge after addressing the raw error-detail leak in the install/uninstall path.

The only issue in new production code is that existingOmpExtensionContents re-throws String(describing: error) verbatim into user-visible CLI output, exposing NSCocoaErrorDomain codes and UserInfo keys. Swapping to error.localizedDescription is a one-line fix. Everything else — session detection, sanitizer routing, resume argv, localization, and CI wiring — looks correct and is well covered by the new test suite.

CLI/CMUXCLI+OmpExtension.swift — the existingOmpExtensionContents error path leaks raw Cocoa error internals to the user.

Important Files Changed

Filename Overview
CLI/CMUXCLI+OmpExtension.swift New file embedding OMP TypeScript extension; install/uninstall logic is sound but existingOmpExtensionContents throws a raw String(describing:error) in user-facing output, exposing Cocoa error internals.
Sources/VaultAgentProcessScanner.swift Extends pi-compatible session ID parsing to support --resume/-r selectors, exact-vs-partial file match, and OMP-specific session directory resolution from PI_CODING_AGENT_DIR/PI_CONFIG_DIR; logic is detailed but each added helper is well-tested.
Sources/VaultAgentRegistry.swift Adds builtInOmp registration and alternateArgvContains field; detection logic and serialisation look correct; the primary-path argvContains gap for bun-invoked OMP is already tracked in a previous thread.
Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift OMP is routed through the existing piPolicy sanitizer; -r is correctly added to the non-restorable options list so session-resume flags are stripped on persist.
Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift OMP resume argv is built identically to pi (omp --session ); straightforward and correct.
Resources/Localizable.xcstrings All new cli.hooks.omp.* keys include translations for every locale already present in the catalog.
Sources/TaskManagerTypes.swift OMP definition added before Pi so @oh-my-pi/pi-coding-agent needle matches OMP before Pi when both could qualify; the ordering test confirms this.
cmuxTests/OmpSupportTests.swift Comprehensive suite covering exact/partial session matching, PI_CODING_AGENT_DIR, PI_CONFIG_DIR, bun-invoked detection, hosted runtime preload flags, and task-manager classification priority.
tests/test_omp_extension_install.py End-to-end Python test for install/uninstall; NUL-separator encoding mismatch vs. TypeScript extension tracked in a previous thread.
.github/workflows/ci.yml Adds least-privilege permissions block and wires the new OMP extension install test into the CI run.

Sequence Diagram

sequenceDiagram
    participant User
    participant OMP as OMP Process
    participant Ext as cmux-omp-session.ts
    participant cmux as cmux CLI
    participant Vault as VaultAgentProcessScanner
    participant Launch as CMUXAgentLaunch

    User->>OMP: omp [--session id]
    OMP->>Ext: session_start event
    Ext->>cmux: hooks omp session-start (stdin JSON)
    Note over Ext,cmux: sendHook - non-blocking async

    OMP->>Ext: before_agent_start event
    Ext->>cmux: hooks omp prompt-submit

    OMP->>Ext: agent_end event
    Ext->>cmux: hooks omp stop

    Note over Vault: Parallel process scan
    Vault->>Vault: "match processName=omp OR alternateArgvContains"
    Vault->>Vault: piCompatibleSessionID via --session/--resume/-r
    Vault->>Vault: ompAgentSessionsRoot via PI_CODING_AGENT_DIR or PI_CONFIG_DIR
    Vault-->>Launch: SessionRestorableAgentSnapshot

    User->>cmux: surface resume
    cmux->>Launch: AgentResumeArgv omp sessionId
    Launch-->>User: omp --session id
Loading

Reviews (8): Last reviewed commit: "fix: avoid blocking OMP stop hook dispat..." | Re-trigger Greptile

Comment on lines +129 to +139
static var builtInOmp: CmuxVaultAgentRegistration {
CmuxVaultAgentRegistration(
id: "omp",
name: "OMP",
detect: CmuxVaultAgentDetectRule(processName: "omp"),
sessionIdSource: .piSessionFile,
resumeCommand: "{{executable}} --session {{sessionId}}",
cwd: .preserve,
sessionDirectory: "~/.omp/agent/sessions"
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Vault detect rule missing argvContains for bun-invoked OMP

builtInPi uses CmuxVaultAgentDetectRule(processName: "pi", argvContains: ["pi"]) so the vault process scanner also matches Pi processes launched via bun /path/to/@mariozechner/pi-coding-agent/.... builtInOmp only has processName: "omp", so when OMP runs via bun /path/to/@oh-my-pi/pi-coding-agent/src/main.ts the vault process scanner won't match it — process.name is "bun", not "omp" — and vault-based session tracking won't fire for that invocation path. Adding argvContains: ["@oh-my-pi/pi-coding-agent"] would close the gap and mirror the Pi pattern.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current code already detects bun-invoked OMP via alternateArgvContains: ["@oh-my-pi/pi-coding-agent"], and cmuxTests/OmpSupportTests.swift covers that path with vaultDetectsBunInvokedOmpPackage.

— Claude Code

foreign_path.parent.mkdir(parents=True, exist_ok=True)
foreign_path.write_text("// user extension\n", encoding="utf-8")
uninstall_foreign = subprocess.run(
[cli_path, "hooks", "omp", "uninstall", "--yes"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 CMUX_AGENT_LAUNCH_ARGV_B64 encoding mismatch between test and production extension

The TypeScript base64NulSeparated function appends a NUL byte after every element including the last, producing arg1\0arg2\0arg3\0. This test uses "\0".join(launch_argv) (NUL as separator, no trailing NUL), producing arg1\0arg2\0arg3. The two encodings differ in the trailing byte. If the Swift hook handler splits strictly on NUL without filtering empty strings, the TypeScript-generated value would decode with an extra empty element at the tail, producing an argv list that differs from what this test asserts. Using b"\0".join(v.encode() for v in launch_argv) + b"\0" would match the real extension output.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current production code and the regression fixture both encode CMUX_AGENT_LAUNCH_ARGV_B64 as NUL-separated argv with a trailing NUL; the test decodes and filters the terminator before comparing argv values.

— Claude Code

@joshrzemien
joshrzemien force-pushed the omp-hook-session-restore branch 2 times, most recently from 6604f42 to ebe8c2f Compare June 5, 2026 01:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/VaultAgentProcessScanner.swift (1)

809-817: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prefer exact session-file matches before substring fallback.

Line 809 now resolves explicit --session / --resume / -r selectors through resolvedSessionPath(...), but that helper picks the newest .jsonl whose basename merely contains the requested id. If both abc.jsonl and xabcx.jsonl exist, --session abc can resolve to the wrong conversation.

Suggested fix
-        var newest: (url: URL, modified: Date)?
+        var exactNewest: (url: URL, modified: Date)?
+        var partialNewest: (url: URL, modified: Date)?
         for case let url as URL in enumerator where url.pathExtension == "jsonl" {
-            guard url.deletingPathExtension().lastPathComponent.contains(trimmed) else { continue }
+            let basename = url.deletingPathExtension().lastPathComponent
+            guard basename == trimmed || basename.contains(trimmed) else { continue }
             let values = try? url.resourceValues(forKeys: [.contentModificationDateKey, .isRegularFileKey])
             guard values?.isRegularFile == true, let modified = values?.contentModificationDate else { continue }
-            if newest == nil || modified > newest!.modified {
-                newest = (url, modified)
+            if basename == trimmed {
+                if exactNewest == nil || modified > exactNewest!.modified {
+                    exactNewest = (url, modified)
+                }
+            } else if partialNewest == nil || modified > partialNewest!.modified {
+                partialNewest = (url, modified)
             }
         }
-        return newest?.url.path
+        return exactNewest?.url.path ?? partialNewest?.url.path

Also applies to: 963-997

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/VaultAgentProcessScanner.swift` around lines 809 - 817, The current
resolution via PiSessionLocator.resolvedSessionPath(for: process, ...) may match
any filename whose basename contains the requested piCompatibleSessionID,
causing e.g. "abc" to match "xabcx.jsonl"; update resolvedSessionPath (and the
other similar call sites using piCompatibleSessionID /
PiSessionLocator.latestSessionPath) to first look for an exact basename match
(basename == id or basenameWithoutExtension == id) and return that file, and
only if no exact match exists fall back to the existing substring/contains
logic; keep using the same parameters (process, registration, fileManager) and
preserve behavior when no match is found by returning the original id or
delegating to latestSessionPath as currently done.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/CMUXCLI`+OmpExtension.swift:
- Around line 207-245: The code currently swallows read errors by using (try?
String(contentsOf: extensionURL, encoding: .utf8)) ?? "" which treats unreadable
or non‑UTF8 existing files as empty and allows overwrite; change this to
explicitly detect and surface read failures: use FileManager to check whether
extensionURL exists and then attempt String(contentsOf:encoding:) with a
do/catch so that if reading fails you throw a CLIError (include
extensionURL.path and the underlying error) instead of defaulting to "",
preserving the existing logic that allows empty/nonexistent files to proceed;
apply the same fix to the duplicated occurrence that uses the same try? pattern
(the second block around lines 267–278) so both places validate read success
before checking Self.ompExtensionMarker or writing Self.ompExtensionSource.

---

Outside diff comments:
In `@Sources/VaultAgentProcessScanner.swift`:
- Around line 809-817: The current resolution via
PiSessionLocator.resolvedSessionPath(for: process, ...) may match any filename
whose basename contains the requested piCompatibleSessionID, causing e.g. "abc"
to match "xabcx.jsonl"; update resolvedSessionPath (and the other similar call
sites using piCompatibleSessionID / PiSessionLocator.latestSessionPath) to first
look for an exact basename match (basename == id or basenameWithoutExtension ==
id) and return that file, and only if no exact match exists fall back to the
existing substring/contains logic; keep using the same parameters (process,
registration, fileManager) and preserve behavior when no match is found by
returning the original id or delegating to latestSessionPath as currently done.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c1167dac-ea31-4553-a1e7-89be0cc581aa

📥 Commits

Reviewing files that changed from the base of the PR and between 97980d0 and 6604f42.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • CLI/CMUXCLI+AgentHookDefinitions.swift
  • CLI/CMUXCLI+OmpExtension.swift
  • CLI/cmux.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerPrimaryPolicies.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchEnvironmentPolicyTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeWorkingDirectoryTests.swift
  • Resources/Localizable.xcstrings
  • Sources/TaskManagerTypes.swift
  • Sources/VaultAgentProcessScanner.swift
  • Sources/VaultAgentRegistry.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/OmpSupportTests.swift
  • cmuxTests/PiVaultAgentPersistenceTests.swift
  • cmuxTests/TaskManagerResourcesTests.swift
  • docs/agent-hooks.md
  • docs/feed.md
  • docs/vault.md
  • tests/test_omp_extension_install.py
  • web/app/[locale]/docs/session-restore/page.tsx

Comment thread CLI/CMUXCLI+OmpExtension.swift Outdated
@joshrzemien
joshrzemien force-pushed the omp-hook-session-restore branch from ebe8c2f to 47c095b Compare June 5, 2026 01:56
Detect OMP sessions from supported selector flags and session roots, restore OMP launches through CMUXAgentLaunch, and cover hook persistence plus direct process detection.
@joshrzemien
joshrzemien force-pushed the omp-hook-session-restore branch from 47c095b to 5b31ba2 Compare June 5, 2026 01:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/VaultAgentProcessScanner.swift (1)

819-827: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix piCompatibleSessionID to not treat -r/--resume as value-carrying session selectors

Sources/VaultAgentProcessScanner.swift makes piCompatibleSessionID scan the entire argv and returns the token after -r/--resume as the session id. This breaks:

  • Node-backed launches: Node’s -r/--require <module> preloads the module before the main script, so this parser can treat the preload module path as the session id.
  • kiro-cli semantics: in kiro-cli, -r/--resume are boolean flags (no value); the value-carrying form is --resume-id <id>. Returning the next token as the session id will also misparse.

Adjust the logic to only parse the actual value-carrying flags (e.g. --resume-id / --session) and/or restrict scanning to the agent “tail” (after stripping node runtime options), similar to how OpenCode uses nodeScriptArgumentIndex.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/VaultAgentProcessScanner.swift` around lines 819 - 827, The
piCompatibleSessionID logic is incorrectly treating -r/--resume as
value-bearing; update the implementation in VaultAgentProcessScanner so
piCompatibleSessionID only extracts session IDs from explicit value flags (e.g.
--resume-id, --session, --session-id) and/or by scanning only the agent tail
after runtime options (use the same nodeScriptArgumentIndex approach OpenCode
uses to strip node runtime flags), instead of returning the token after
-r/--resume; ensure callers like PiSessionLocator.resolvedSessionPath and
PiSessionLocator.latestSessionPath keep the same behavior but receive the
corrected session string.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 10-11: The workflow-level permissions block currently only sets
"contents: read", which implicitly disables other scopes like "actions" and
breaks cache/artifact operations; update the permissions mapping in the CI
workflow's permissions block to include "actions: write" (and optionally
"actions: read" if you prefer explicit restores) so actions/cache and artifact
upload/download can succeed, i.e., add "actions: write" alongside "contents:
read" in the permissions block at the top of the CI YAML.

In `@CLI/CMUXCLI`+OmpExtension.swift:
- Around line 24-35: resolveExecutable currently returns the first PATH entry
that passes fs.accessSync(candidate, fs.constants.X_OK), but on POSIX X_OK can
be true for searchable directories so a directory named "omp" may be persisted;
update resolveExecutable to additionally stat the candidate (e.g., fs.statSync)
and only accept it if stat.isFile() (or isSymbolicLink resolved to a file) and
it is executable before returning; reference the resolveExecutable function and
perform the isFile/isSymbolicLink + permission check sequence to avoid
persisting directories.

In `@tests/test_omp_extension_install.py`:
- Around line 442-444: The test waits for only 3 non-empty lines via
wait_for_text(fake_stdin_log, 3) which can complete after two cmux invocations
(each writes two lines: payload and '---'), causing a race on the third
invocation and the `"last_assistant_message":"done"` assertion; change the wait
count to expect all three stdin payloads (e.g., wait_for_text(fake_stdin_log, 6)
or compute 2*number_of_invocations) and similarly ensure args_log/env_log
expectations match the actual number of lines written (use
wait_for_text(fake_args_log, expected_count), wait_for_text(fake_env_log,
expected_count)) so the test only proceeds after all three cmux runs complete.

---

Outside diff comments:
In `@Sources/VaultAgentProcessScanner.swift`:
- Around line 819-827: The piCompatibleSessionID logic is incorrectly treating
-r/--resume as value-bearing; update the implementation in
VaultAgentProcessScanner so piCompatibleSessionID only extracts session IDs from
explicit value flags (e.g. --resume-id, --session, --session-id) and/or by
scanning only the agent tail after runtime options (use the same
nodeScriptArgumentIndex approach OpenCode uses to strip node runtime flags),
instead of returning the token after -r/--resume; ensure callers like
PiSessionLocator.resolvedSessionPath and PiSessionLocator.latestSessionPath keep
the same behavior but receive the corrected session string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 72afbeac-d6da-4509-80b6-b39b1580d7da

📥 Commits

Reviewing files that changed from the base of the PR and between 6604f42 and ebe8c2f.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • CLI/CMUXCLI+AgentHookDefinitions.swift
  • CLI/CMUXCLI+OmpExtension.swift
  • CLI/cmux.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerPrimaryPolicies.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchEnvironmentPolicyTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeWorkingDirectoryTests.swift
  • Resources/Localizable.xcstrings
  • Sources/TaskManagerTypes.swift
  • Sources/VaultAgentProcessScanner.swift
  • Sources/VaultAgentRegistry.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/OmpSupportTests.swift
  • cmuxTests/PiVaultAgentPersistenceTests.swift
  • cmuxTests/TaskManagerResourcesTests.swift
  • docs/agent-hooks.md
  • docs/feed.md
  • docs/vault.md
  • tests/test_omp_extension_install.py
  • web/app/[locale]/docs/session-restore/page.tsx

Comment thread .github/workflows/ci.yml
Comment thread CLI/CMUXCLI+OmpExtension.swift
Comment thread tests/test_omp_extension_install.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/CMUXCLI`+AgentHookDefinitions.swift:
- Around line 73-75: The special-case check if name == "omp" bypasses the
generic configDirEnvOverride logic and needs an explanatory comment and precise
behavior: add a comment above the if-block describing that OMP must resolve its
directory using CMUXCLI.resolvedOmpAgentDirectory() because OMP requires
checking both PI_CODING_AGENT_DIR (higher precedence) and PI_CONFIG_DIR
(fallback), a precedence that the generic configDirEnvOverride cannot express;
ensure the comment references the env vars PI_CODING_AGENT_DIR and PI_CONFIG_DIR
and mentions CMUXCLI.resolvedOmpAgentDirectory() implements that two-var
resolution so future maintainers understand why OMP is special-cased.
- Around line 199-206: The current special-case env-var precedence for the "omp"
AgentHookDef should be generalized: add an optional closure field to
AgentHookDef named resolveConfigDir: ((String) -> String)? or extend the
existing configDirEnvOverride to accept [String] so resolution supports multiple
env vars with precedence; update the AgentHookDef initializer and the config-dir
resolution logic to call that closure or iterate the env-var array when present,
then convert the "omp" entry to use this new field (removing the bespoke if/else
handling) so future agents can reuse the multi-env-var precedence behavior.

In `@CLI/CMUXCLI`+OmpExtension.swift:
- Around line 205-215: The catch that handles failures from String(contentsOf:
url, encoding: .utf8) incorrectly reuses the "not a cmux extension" message;
change it to throw a dedicated read-failure CLIError (e.g.,
"cli.hooks.omp.error.readFailed" or a clear literal like "Failed to read file")
and include the underlying error formatted with String(describing: error)
instead of error.localizedDescription; update the catch in
CMUXCLI+OmpExtension.swift where String(contentsOf:) is called to construct and
throw this new read-failure CLIError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0d02c38e-fe4a-4654-8e74-97e07f4de1ff

📥 Commits

Reviewing files that changed from the base of the PR and between ebe8c2f and 5b31ba2.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • CLI/CMUXCLI+AgentHookDefinitions.swift
  • CLI/CMUXCLI+OmpExtension.swift
  • CLI/cmux.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchEnvironmentPolicy.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerPrimaryPolicies.swift
  • Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentResumeArgv.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchEnvironmentPolicyTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeArgvTests.swift
  • Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentResumeWorkingDirectoryTests.swift
  • Resources/Localizable.xcstrings
  • Sources/TaskManagerTypes.swift
  • Sources/VaultAgentProcessScanner.swift
  • Sources/VaultAgentRegistry.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/OmpSupportTests.swift
  • cmuxTests/PiVaultAgentPersistenceTests.swift
  • cmuxTests/TaskManagerResourcesTests.swift
  • docs/agent-hooks.md
  • docs/feed.md
  • docs/vault.md
  • tests/test_omp_extension_install.py
  • web/app/[locale]/docs/session-restore/page.tsx

Comment thread CLI/CMUXCLI+AgentHookDefinitions.swift Outdated
Comment thread CLI/CMUXCLI+AgentHookDefinitions.swift
Comment thread CLI/CMUXCLI+OmpExtension.swift Outdated
@vercel

vercel Bot commented Jun 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 5, 2026 6:01am

Comment on lines +205 to +208
api.on("agent_end", async (event, ctx) => {
sendHookSync("stop", ctx, { last_assistant_message: lastAssistantMessage(event) });
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 sendHookSync blocks the event loop for up to 5 s at agent teardown

api.on("agent_end", async ...) declares an async handler, but the body calls sendHookSync — a synchronous spawnSync with timeout: 5000 — without await. That means every OMP session end blocks Node's event loop for up to 5 seconds waiting for the cmux subprocess. The other two hooks (session_start, before_agent_start) correctly use await sendHook(...) which resolves as soon as stdin is flushed. If OMP's extension API honours the returned promise from an async handler, replacing the call here with await sendHook("stop", ...) gives the same delivery guarantee without a wall-clock block.

Rule Used: Flag fixed sleeps, delayed dispatch, timers, polli... (source)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 795243c by removing spawnSync and awaiting the same detached stdin-flush sendHook path for agent_end. The Python regression now uses a slow fake cmux command so synchronous Stop dispatch would fail the timing assertion while still proving all three payloads arrive.

— Claude Code

This branch was successfully deployed

1 active deployment
Preview – cmux — 795243c9 Deployed Jun 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants