Skip to content

feat: add full Oh My Pi (OMP) support - #256

Open
Lynricsy wants to merge 6 commits into
cortexkit:masterfrom
Lynricsy:feat/omp-support
Open

feat: add full Oh My Pi (OMP) support#256
Lynricsy wants to merge 6 commits into
cortexkit:masterfrom
Lynricsy:feat/omp-support

Conversation

@Lynricsy

@Lynricsy Lynricsy commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • add OMP as a first-class CLI harness with native plugin-manager detection, setup, doctor, repair, and OpenCode session migration
  • reuse the Pi-compatible runtime while preserving OMP profile, XDG, child-process, extension allowlist, and shared-memory semantics
  • discover OMP JSON model selectors and default/named-profile sessions in the dashboard
  • publish an explicit OMP extension manifest and document installation, conflicts, migration, configuration, troubleshooting, and dashboard behavior

Compatibility decisions

  • OMP uses the existing Pi runtime and keeps the harness='pi' discriminator for session-scoped rows
  • project memories remain shared across OpenCode, Pi, and OMP
  • setup disables OMP native compaction and automatic memory transactionally to avoid competing context managers
  • model discovery consumes omp models --json selectors so scoped and nested IDs are preserved

Verification

  • CLI: 292 passed, 2 skipped, 0 failed; lint, typecheck, build passed
  • Pi/OMP extension: 711 passed, 0 failed; typecheck, build, npm pack dry-run passed
  • docs: Astro build completed all 22 pages
  • real OMP 17.1.7 smoke: linked the local package through omp plugin, launched OMP, and /ctx-status reported Magic Context v0.33.0 with historian idle
  • dashboard session module: 8 Rust tests passed through an isolated crate that includes the production source; touched Rust files pass rustfmt parsing/check

Environment note

The full Tauri Cargo suite could not link on this workstation because pkg-config/DBus development metadata is absent; the failure occurs in libdbus-sys before project code compiles.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Add first-class Oh My Pi (OMP) support across the CLI, extension, and dashboard. You can install, health-check, and migrate sessions to OMP, with models and sessions visible in the dashboard; the runtime, config, and database are shared with Pi. The dashboard now deduplicates multi-root sessions.

  • New Features

    • CLI: new omp harness adapter with setup --harness omp and doctor --harness omp; auto-detects the OMP binary, plugin entry, and version; reads OMP profiles and XDG paths; discovers models via omp models --json.
    • OMP setup: disables native compaction and automatic memory to avoid conflicts; verifies minimum OMP version; writes config atomically; supports force-repair in doctor --harness omp --force.
    • Extension: @cortexkit/pi-magic-context declares an OMP manifest and runs on both Pi and OMP; resolves relative allowlist entries from PI_CODING_AGENT_DIR.
    • Dashboard: discovers OMP models and sessions; preserves scoped/nested model selectors; shows OMP alongside OpenCode and Pi; deduplicates sessions across aliased roots.
    • Compatibility: reuses the Pi-compatible runtime and keeps harness='pi' for session rows; project memories and config are shared across OpenCode, Pi, and OMP.
  • Migration

    • doctor migrate --from opencode --to omp converts an OpenCode session to Pi/OMP JSONL and writes it to the active OMP sessions root.

Written for commit f979800. Summary will update on new commits.

Review in cubic

Greptile Summary

Adds first-class Oh My Pi support across the CLI, Pi-compatible extension, dashboard, and documentation.

  • Adds OMP detection, setup, doctor/repair, model discovery, profile/XDG path handling, and OpenCode-to-OMP migration.
  • Extends the dashboard to discover Pi-compatible sessions across Pi and OMP roots while deduplicating logical sessions.
  • Updates the extension manifest and child-process handling for OMP compatibility.
  • Documents OMP installation, configuration, migration, conflicts, troubleshooting, and dashboard behavior.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/cli/src/adapters/omp.ts Adds OMP installation detection and plugin-manager integration, including enable-state verification and rollback behavior.
packages/cli/src/commands/setup-omp.ts Adds transactional OMP setup that installs the extension and disables conflicting native context-management features.
packages/cli/src/commands/doctor-omp.ts Adds OMP-specific health checks and force-repair behavior.
packages/cli/src/lib/omp-helpers.ts Adds OMP binary, profile, plugin, settings, and model-discovery helpers.
packages/cli/src/commands/migrate.ts Extends OpenCode session migration to target the active OMP session root.
packages/dashboard/src-tauri/src/pi_sessions.rs Adds Pi-compatible OMP session-root discovery and resolves the previously reported duplicate-session behavior by canonical path and logical session ID.
packages/dashboard/src-tauri/src/commands.rs Extends dashboard model discovery to include OMP JSON model selectors.
packages/pi-plugin/src/subagent-runner.ts Adapts Pi-compatible child-process and extension allowlist behavior for OMP environments.
packages/pi-plugin/package.json Publishes explicit OMP extension metadata for the existing Pi-compatible package.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  CLI[Magic Context CLI] --> Detect[Detect OpenCode / Pi / OMP]
  Detect --> Setup[Setup and doctor]
  Setup --> OMP[OMP plugin manager and settings]
  OMP --> Runtime[Pi-compatible Magic Context runtime]
  Runtime --> DB[(Shared CortexKit database)]
  PiRoots[Pi session roots] --> Dashboard[Dashboard session discovery]
  OMPRoots[OMP default and profile roots] --> Dashboard
  Dashboard --> Dedup[Deduplicate logical sessions]
  Dedup --> SessionUI[Session list and details]
Loading

Reviews (3): Last reviewed commit: "fix(dashboard): 🐛 deduplicate multi-roo..." | Re-trigger Greptile

Lynricsy and others added 5 commits July 28, 2026 15:43
Co-authored-by: Wine Fox <fox@ling.plus>
Co-authored-by: Wine Fox <fox@ling.plus>
Co-authored-by: Wine Fox <fox@ling.plus>
Co-authored-by: Wine Fox <fox@ling.plus>
Co-authored-by: Wine Fox <fox@ling.plus>

@cubic-dev-ai cubic-dev-ai 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.

11 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/docs/src/content/docs/index.mdx">

<violation number="1" location="packages/docs/src/content/docs/index.mdx:3">
P3: The description now includes "Oh My Pi" in the supported-agents list, but the "Works with" section below still lists only OpenCode and Pi, and the sentence says "shared across both harnesses." Add OMP to the list and update "both" → "all" so the page is internally consistent.</violation>
</file>

<file name="packages/cli/src/commands/setup-pi.ts">

<violation number="1" location="packages/cli/src/commands/setup-pi.ts:60">
P2: DEFAULT_HOST doesn't implement rollbackPluginEntry, so for Pi (unlike OMP) a failure in writeMagicContextConfig after the plugin entry was successfully added leaves the settings file referencing the package with no valid Magic Context config written. Consider adding a rollbackPluginEntry for the Pi host (e.g. remove the added package entry) to match the new rollback contract.</violation>

<violation number="2" location="packages/cli/src/commands/setup-pi.ts:285">
P3: The generalized 'not found' message no longer mentions the home-directory fallback paths that detectPiBinary/detectOmpBinary actually check, which is a minor UX regression compared to the previous Pi-specific message.</violation>
</file>

<file name="packages/cli/src/commands/doctor-omp.ts">

<violation number="1" location="packages/cli/src/commands/doctor-omp.ts:120">
P3: The catch-all message "gh CLI unavailable" is shown even when `gh` is installed but the user isn't authenticated (since `gh auth status` exits non-zero in that case too); consider distinguishing "not installed" from "not authenticated" for a clearer message.</violation>

<violation number="2" location="packages/cli/src/commands/doctor-omp.ts:300">
P2: `repair()` bails out entirely with `if (!omp) return 0` before checking `plan.writeUserConfig`, so `magic-context omp doctor --force` will never create the default Magic Context config when the OMP binary isn't detected — even though that repair action has nothing to do with OMP being installed. Consider moving the `writeUserConfig` handling above the `!omp` early return (or handling it separately) so it always runs when needed.</violation>
</file>

<file name="packages/dashboard/src-tauri/src/commands.rs">

<violation number="1" location="packages/dashboard/src-tauri/src/commands.rs:1191">
P2: Inserting the OMP fallback before the pi login-shell fallback means a real Pi installation that's only resolvable via the login shell (e.g. an exotic PATH setup not covered by the static candidate list) will never be tried if OMP is also installed with a non-empty model list — get_available_pi_models will return OMP models under the 'pi' models cache instead. Consider moving the OMP fallback after the pi login-shell attempt (or making the two probes run independently) so a working Pi install is never masked by an unrelated OMP install.</violation>
</file>

<file name="packages/cli/src/commands/setup-omp.test.ts">

<violation number="1" location="packages/cli/src/commands/setup-omp.test.ts:67">
P2: Mock binary shebang `#!/usr/bin/node` breaks tests on machines where node lives outside /usr/bin (common for nvm, fnm, asdf, Homebrew). Use `#!/usr/bin/env node` instead so the binary resolves through PATH.</violation>
</file>

<file name="packages/dashboard/src-tauri/src/pi_sessions.rs">

<violation number="1" location="packages/dashboard/src-tauri/src/pi_sessions.rs:96">
P2: normalize_omp_profile() doesn't validate the profile name format like the CLI's resolveOmpPaths() does (regex-restricted to lowercase alnum/._- , max 64 chars). Without that guard, a crafted OMP_PROFILE/PI_PROFILE value containing '..' or path separators can make the profile-derived path escape the intended `.omp`/XDG root when later joined and scanned.</violation>

<violation number="2" location="packages/dashboard/src-tauri/src/pi_sessions.rs:184">
P3: scan_pi_session_dir()/scan_pi_cache_session_dir() no longer call pi_sessions_root(), and no other file references it — it's now unused dead code left over from the refactor and can be removed.</violation>
</file>

<file name="packages/cli/src/lib/omp-helpers.ts">

<violation number="1" location="packages/cli/src/lib/omp-helpers.ts:43">
P3: `runOmpCommand`'s spawnSync call has no explicit `maxBuffer`, so a large model catalog or plugin list JSON payload could exceed Node's default 1MB buffer and fail the call (surfaced as a generic failure) instead of being parsed; consider setting a higher `maxBuffer` for the JSON-producing subcommands.</violation>

<violation number="2" location="packages/cli/src/lib/omp-helpers.ts:51">
P2: When the OMP command times out (or otherwise fails after spawning with no stderr output), `result.stderr` is an empty string rather than null/undefined, so the `??` fallback to `result.error?.message` never triggers and the real error (e.g. `ETIMEDOUT`) is silently dropped. Doctor/setup flows that display `result.stderr` to the user (adapters/omp.ts, doctor-omp.ts, setup-omp.ts) will show a blank or generic failure message instead of the actionable cause.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread packages/pi-plugin/README.md
dryRun: boolean;
configureHost: boolean;
}) => Promise<SetupRollback | false>;
rollbackPluginEntry?: (registration: PluginEntryResult) => Promise<void>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: DEFAULT_HOST doesn't implement rollbackPluginEntry, so for Pi (unlike OMP) a failure in writeMagicContextConfig after the plugin entry was successfully added leaves the settings file referencing the package with no valid Magic Context config written. Consider adding a rollbackPluginEntry for the Pi host (e.g. remove the added package entry) to match the new rollback contract.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/setup-pi.ts, line 60:

<comment>DEFAULT_HOST doesn't implement rollbackPluginEntry, so for Pi (unlike OMP) a failure in writeMagicContextConfig after the plugin entry was successfully added leaves the settings file referencing the package with no valid Magic Context config written. Consider adding a rollbackPluginEntry for the Pi host (e.g. remove the added package entry) to match the new rollback contract.</comment>

<file context>
@@ -40,9 +41,29 @@ export interface SetupEnvironment {
+        dryRun: boolean;
+        configureHost: boolean;
+    }) => Promise<SetupRollback | false>;
+    rollbackPluginEntry?: (registration: PluginEntryResult) => Promise<void>;
+}
+
</file context>

}

async function repair(plan: RepairPlan, deps: DoctorDeps, prompts: PromptIO): Promise<number> {
const omp = deps.detectOmpBinary();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: repair() bails out entirely with if (!omp) return 0 before checking plan.writeUserConfig, so magic-context omp doctor --force will never create the default Magic Context config when the OMP binary isn't detected — even though that repair action has nothing to do with OMP being installed. Consider moving the writeUserConfig handling above the !omp early return (or handling it separately) so it always runs when needed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/doctor-omp.ts, line 300:

<comment>`repair()` bails out entirely with `if (!omp) return 0` before checking `plan.writeUserConfig`, so `magic-context omp doctor --force` will never create the default Magic Context config when the OMP binary isn't detected — even though that repair action has nothing to do with OMP being installed. Consider moving the `writeUserConfig` handling above the `!omp` early return (or handling it separately) so it always runs when needed.</comment>

<file context>
@@ -0,0 +1,411 @@
+}
+
+async function repair(plan: RepairPlan, deps: DoctorDeps, prompts: PromptIO): Promise<number> {
+    const omp = deps.detectOmpBinary();
+    if (!omp) return 0;
+    let fixed = 0;
</file context>

}
}

let omp_models = get_available_omp_models().await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Inserting the OMP fallback before the pi login-shell fallback means a real Pi installation that's only resolvable via the login shell (e.g. an exotic PATH setup not covered by the static candidate list) will never be tried if OMP is also installed with a non-empty model list — get_available_pi_models will return OMP models under the 'pi' models cache instead. Consider moving the OMP fallback after the pi login-shell attempt (or making the two probes run independently) so a working Pi install is never masked by an unrelated OMP install.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/dashboard/src-tauri/src/commands.rs, line 1191:

<comment>Inserting the OMP fallback before the pi login-shell fallback means a real Pi installation that's only resolvable via the login shell (e.g. an exotic PATH setup not covered by the static candidate list) will never be tried if OMP is also installed with a non-empty model list — get_available_pi_models will return OMP models under the 'pi' models cache instead. Consider moving the OMP fallback after the pi login-shell attempt (or making the two probes run independently) so a working Pi install is never masked by an unrelated OMP install.</comment>

<file context>
@@ -1108,6 +1188,10 @@ pub async fn get_available_pi_models() -> Vec<String> {
         }
     }
 
+    let omp_models = get_available_omp_models().await;
+    if !omp_models.is_empty() {
+        return omp_models;
</file context>

return {
ok: result.status === 0 && !result.error,
stdout: result.stdout?.trim() ?? "",
stderr: result.stderr?.trim() ?? result.error?.message ?? "",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When the OMP command times out (or otherwise fails after spawning with no stderr output), result.stderr is an empty string rather than null/undefined, so the ?? fallback to result.error?.message never triggers and the real error (e.g. ETIMEDOUT) is silently dropped. Doctor/setup flows that display result.stderr to the user (adapters/omp.ts, doctor-omp.ts, setup-omp.ts) will show a blank or generic failure message instead of the actionable cause.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/lib/omp-helpers.ts, line 51:

<comment>When the OMP command times out (or otherwise fails after spawning with no stderr output), `result.stderr` is an empty string rather than null/undefined, so the `??` fallback to `result.error?.message` never triggers and the real error (e.g. `ETIMEDOUT`) is silently dropped. Doctor/setup flows that display `result.stderr` to the user (adapters/omp.ts, doctor-omp.ts, setup-omp.ts) will show a blank or generic failure message instead of the actionable cause.</comment>

<file context>
@@ -0,0 +1,143 @@
+        return {
+            ok: result.status === 0 && !result.error,
+            stdout: result.stdout?.trim() ?? "",
+            stderr: result.stderr?.trim() ?? result.error?.message ?? "",
+        };
+    } catch (error) {
</file context>
Suggested change
stderr: result.stderr?.trim() ?? result.error?.message ?? "",
stderr: result.stderr?.trim() || result.error?.message || "",

---
title: Magic Context
description: Persistent memory and self-managing context for OpenCode and Pi coding agents.
description: Persistent memory and self-managing context for OpenCode, Pi, and Oh My Pi coding agents.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The description now includes "Oh My Pi" in the supported-agents list, but the "Works with" section below still lists only OpenCode and Pi, and the sentence says "shared across both harnesses." Add OMP to the list and update "both" → "all" so the page is internally consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/docs/src/content/docs/index.mdx, line 3:

<comment>The description now includes "Oh My Pi" in the supported-agents list, but the "Works with" section below still lists only OpenCode and Pi, and the sentence says "shared across both harnesses." Add OMP to the list and update "both" → "all" so the page is internally consistent.</comment>

<file context>
@@ -1,6 +1,6 @@
 ---
 title: Magic Context
-description: Persistent memory and self-managing context for OpenCode and Pi coding agents.
+description: Persistent memory and self-managing context for OpenCode, Pi, and Oh My Pi coding agents.
 template: splash
 hero:
</file context>

const binary = env.detectPiBinary();
if (!binary) {
spinner.stop(`${host.displayName} not found`);
prompts.log.warn(`Could not find \`${host.cliName}\` on PATH.`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The generalized 'not found' message no longer mentions the home-directory fallback paths that detectPiBinary/detectOmpBinary actually check, which is a minor UX regression compared to the previous Pi-specific message.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/setup-pi.ts, line 285:

<comment>The generalized 'not found' message no longer mentions the home-directory fallback paths that detectPiBinary/detectOmpBinary actually check, which is a minor UX regression compared to the previous Pi-specific message.</comment>

<file context>
@@ -231,45 +278,40 @@ export async function runSetup(options: RunSetupOptions = {}): Promise<number> {
+    const binary = env.detectPiBinary();
+    if (!binary) {
+        spinner.stop(`${host.displayName} not found`);
+        prompts.log.warn(`Could not find \`${host.cliName}\` on PATH.`);
+        prompts.log.message(`Install ${host.displayName} first, then rerun setup.`);
+        prompts.outro(`Setup stopped — install ${host.displayName} and try again`);
</file context>

try {
const value = req(path) as { version?: unknown };
if (typeof value.version === "string") return value.version;
} catch {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The catch-all message "gh CLI unavailable" is shown even when gh is installed but the user isn't authenticated (since gh auth status exits non-zero in that case too); consider distinguishing "not installed" from "not authenticated" for a clearer message.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/doctor-omp.ts, line 120:

<comment>The catch-all message "gh CLI unavailable" is shown even when `gh` is installed but the user isn't authenticated (since `gh auth status` exits non-zero in that case too); consider distinguishing "not installed" from "not authenticated" for a clearer message.</comment>

<file context>
@@ -0,0 +1,411 @@
+        try {
+            const value = req(path) as { version?: unknown };
+            if (typeof value.version === "string") return value.version;
+        } catch {
+            // Try the source/published alternate layout.
+        }
</file context>

Comment on lines +43 to +47
const result = spawnSync(invocation.command, invocation.args, {
encoding: "utf-8",
timeout,
stdio: ["ignore", "pipe", "pipe"],
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: runOmpCommand's spawnSync call has no explicit maxBuffer, so a large model catalog or plugin list JSON payload could exceed Node's default 1MB buffer and fail the call (surfaced as a generic failure) instead of being parsed; consider setting a higher maxBuffer for the JSON-producing subcommands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/lib/omp-helpers.ts, line 43:

<comment>`runOmpCommand`'s spawnSync call has no explicit `maxBuffer`, so a large model catalog or plugin list JSON payload could exceed Node's default 1MB buffer and fail the call (surfaced as a generic failure) instead of being parsed; consider setting a higher `maxBuffer` for the JSON-producing subcommands.</comment>

<file context>
@@ -0,0 +1,143 @@
+export function runOmpCommand(ompPath: string, args: string[], timeout = 30_000): OmpCommandResult {
+    try {
+        const invocation = getPiCommandInvocation(ompPath, args);
+        const result = spawnSync(invocation.command, invocation.args, {
+            encoding: "utf-8",
+            timeout,
</file context>
Suggested change
const result = spawnSync(invocation.command, invocation.args, {
encoding: "utf-8",
timeout,
stdio: ["ignore", "pipe", "pipe"],
});
const result = spawnSync(invocation.command, invocation.args, {
encoding: "utf-8",
timeout,
maxBuffer: 10 * 1024 * 1024,
stdio: ["ignore", "pipe", "pipe"],
});

roots
}

pub fn scan_pi_session_dir() -> Vec<PiSessionMeta> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: scan_pi_session_dir()/scan_pi_cache_session_dir() no longer call pi_sessions_root(), and no other file references it — it's now unused dead code left over from the refactor and can be removed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/dashboard/src-tauri/src/pi_sessions.rs, line 184:

<comment>scan_pi_session_dir()/scan_pi_cache_session_dir() no longer call pi_sessions_root(), and no other file references it — it's now unused dead code left over from the refactor and can be removed.</comment>

<file context>
@@ -90,18 +90,109 @@ pub fn pi_sessions_root() -> Option<PathBuf> {
+    roots
+}
+
+pub fn scan_pi_session_dir() -> Vec<PiSessionMeta> {
+    pi_compatible_session_roots()
+        .into_iter()
</file context>

Co-authored-by: Wine Fox <fox@ling.plus>
@Lynricsy

Copy link
Copy Markdown
Author

Addressed the multi-root session review in f979800. Dashboard discovery now canonicalizes paths, deduplicates by session ID, sorts duplicates by modified time descending with a stable path tie-break, and therefore keeps the newest continued copy rather than root-order priority. Added regression coverage for a newer duplicate in the second root; the production module now passes 9 isolated Rust tests.

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 42 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/dashboard/src-tauri/src/pi_sessions.rs">

<violation number="1" location="packages/dashboard/src-tauri/src/pi_sessions.rs:193">
P2: When two duplicate session entries have identical `modified` timestamps, the tie-break falls back to lexical comparison of `jsonl_path`, which has no semantic relationship to which root should take priority (e.g. OMP vs legacy Pi vs XDG). Consider breaking ties using an explicit root-priority index captured during root traversal instead of raw path bytes, so dedup resolution is deterministic and matches intended precedence.</violation>

<violation number="2" location="packages/dashboard/src-tauri/src/pi_sessions.rs:198">
P3: Deduplication now performs `fs::canonicalize` per session on every scan across all discovered roots, which is extra I/O on top of the existing meta cache and could add latency as the number of OMP profiles/roots grows. Consider caching canonicalized paths or only canonicalizing when a path collision by non-canonical form is first detected.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

right
.modified
.cmp(&left.modified)
.then_with(|| left.jsonl_path.cmp(&right.jsonl_path))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When two duplicate session entries have identical modified timestamps, the tie-break falls back to lexical comparison of jsonl_path, which has no semantic relationship to which root should take priority (e.g. OMP vs legacy Pi vs XDG). Consider breaking ties using an explicit root-priority index captured during root traversal instead of raw path bytes, so dedup resolution is deterministic and matches intended precedence.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/dashboard/src-tauri/src/pi_sessions.rs, line 193:

<comment>When two duplicate session entries have identical `modified` timestamps, the tie-break falls back to lexical comparison of `jsonl_path`, which has no semantic relationship to which root should take priority (e.g. OMP vs legacy Pi vs XDG). Consider breaking ties using an explicit root-priority index captured during root traversal instead of raw path bytes, so dedup resolution is deterministic and matches intended precedence.</comment>

<file context>
@@ -90,18 +90,137 @@ pub fn pi_sessions_root() -> Option<PathBuf> {
+        right
+            .modified
+            .cmp(&left.modified)
+            .then_with(|| left.jsonl_path.cmp(&right.jsonl_path))
+    });
+    let mut seen_paths = HashSet::new();
</file context>

let mut seen_paths = HashSet::new();
let mut seen_ids = HashSet::new();
sessions.retain(|session| {
let canonical_path =

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Deduplication now performs fs::canonicalize per session on every scan across all discovered roots, which is extra I/O on top of the existing meta cache and could add latency as the number of OMP profiles/roots grows. Consider caching canonicalized paths or only canonicalizing when a path collision by non-canonical form is first detected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/dashboard/src-tauri/src/pi_sessions.rs, line 198:

<comment>Deduplication now performs `fs::canonicalize` per session on every scan across all discovered roots, which is extra I/O on top of the existing meta cache and could add latency as the number of OMP profiles/roots grows. Consider caching canonicalized paths or only canonicalizing when a path collision by non-canonical form is first detected.</comment>

<file context>
@@ -90,18 +90,137 @@ pub fn pi_sessions_root() -> Option<PathBuf> {
+    let mut seen_paths = HashSet::new();
+    let mut seen_ids = HashSet::new();
+    sessions.retain(|session| {
+        let canonical_path =
+            fs::canonicalize(&session.jsonl_path).unwrap_or_else(|_| session.jsonl_path.clone());
+        if !seen_paths.insert(canonical_path) {
</file context>

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.

1 participant