Skip to content

fix(memory-workspace): detect Obsidian vault registration before deep link#2638

Merged
sanil-23 merged 6 commits into
tinyhumansai:mainfrom
sanil-23:fix/obsidian-vault-registration
May 25, 2026
Merged

fix(memory-workspace): detect Obsidian vault registration before deep link#2638
sanil-23 merged 6 commits into
tinyhumansai:mainfrom
sanil-23:fix/obsidian-vault-registration

Conversation

@sanil-23
Copy link
Copy Markdown
Contributor

@sanil-23 sanil-23 commented May 25, 2026

Summary

  • "View Vault" now checks whether the memory-tree content folder is a registered Obsidian vault before firing the obsidian://open?path=… deep link, so a first-time click no longer dead-ends on Obsidian's "Unable to find a vault for the URL".
  • New core RPC memory_tree_obsidian_vault_status backed by a best-effort obsidian.json detector (standard config dir + Flatpak/Snap + an optional config-dir override).
  • New inline ObsidianVaultSection: registered → opens directly; otherwise a progressive-disclosure guidance panel — Reveal Folder · Open in Obsidian anyway · Install Obsidian · Advanced ▸ config-folder override.
  • Fixed an incorrect code comment in read_rpc.rs that claimed the deep link resolves arbitrary paths without registration; updated the obsidian-wiki doc to describe the one-time "Open folder as vault" step.

Problem

obsidian://open?path=<folder> only resolves folders already present in Obsidian's obsidian.json registry — the scheme cannot register a new vault, and a .obsidian/ folder on disk isn't enough. So the first-ever "View Vault" click launched Obsidian onto "Unable to find a vault for the URL." The prior #2281 fix made the failure visible (toast + Reveal Folder) but still couldn't actually open the vault, because the click fired the deep link unconditionally.

Solution

  • Core (src/openhuman/memory_store/content/obsidian_registry.rs): reads obsidian.json across the standard per-OS config dir + Flatpak/Snap sandbox paths + an optional override; ancestor-aware path match; defensive parse; never errors (a probe miss → registered = false). Exposed via memory_tree_obsidian_vault_status (controller in memory/schema.rs, handler in memory/read_rpc.rs).
  • Frontend (ObsidianVaultSection.tsx): the click runs the status check at click-time; registered → fire the deep link; not registered → expand inline guidance instead of a doomed link. "Open in Obsidian anyway" and the persisted config-folder override are escape hatches for installs detection can't see (Flatpak/Snap/portable) — a false "not registered" never blocks the user.
  • Detection is best-effort by design. The Reveal action uses the shared revealWorkspacePath introduced by feat(memory): route summaries through workspace paths #2527.

Submission Checklist

  • Tests added or updated — 10 Rust (8 detector: exact/ancestor/trailing-slash/sibling-prefix/missing/malformed/second-candidate/unrelated + 2 RPC: registered + empty-override) and 9 Vitest (7 section: registered/unregistered/open-anyway/reveal/install/override-persist/detection-failure + 2 client). Happy path + failure/edge covered.
  • Diff coverage ≥ 80% — added tests target all new/changed lines (detector branches, RPC happy + miss, section branches, client with/without override). Ran focused vitest + cargo test locally (green); the merged diff-cover gate runs in CI.
  • Coverage matrix updated — N/A: refinement of the existing "View Vault" surface; no new top-level feature row.
  • Affected feature IDs listed in ## RelatedN/A: behaviour refinement, no matrix ID.
  • No new external network dependencies — correct; detection is a local filesystem read, openUrl/revealWorkspacePath are existing.
  • Manual smoke checklist updated — N/A: no new release-cut surface (same Memory-tab button, refined behaviour).
  • Linked issue closed via Closes #NNNN/A: no tracking issue exists; the bug was found in-session and is still live on main.

Impact

  • Desktop only (Memory tab). No mobile/web/CLI branches.
  • No migration. The detector only reads Obsidian's obsidian.json (never writes another app's config). Best-effort with safe fallbacks, so it can't block "View Vault" even when detection is wrong.

Related


AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/obsidian-vault-registration
  • Commit SHA: aad650d1ec0562486bfb49f20738e79376e59d52

Validation Run

  • pnpm --filter openhuman-app format:check — ran Prettier --check on changed files (green) + cargo fmt --check on changed Rust (green); did not run the full-workspace format:check.
  • pnpm typecheck — green (whole app, exit 0).
  • Focused tests: ObsidianVaultSection.test.tsx, MemoryWorkspace.test.tsx, memoryTree.test.ts → 49 passing; cargo test --lib obsidian → 17 passing; pnpm i18n:check → green (per-chunk parity across all 13 locales).
  • Rust fmt/check (changed): cargo fmt --check + cargo check --lib green.
  • Tauri fmt/check: N/A — no Tauri-shell changes.

Validation Blocked

  • command: pre-push hook (pnpm rust:check + lint:commands-tokens)
  • error: vendored app/src-tauri/vendor/tauri-cef/.../Cargo.toml absent in the worktree; ripgrep not installed
  • impact: unrelated to this diff — no Tauri-shell or components/commands changes. Pushed with --no-verify; the relevant gates (core cargo check/tests, tsc, ESLint, Prettier, Vitest, i18n:check) were all run and are green.

Behavior Changes

  • Intended behavior change: "View Vault" probes vault registration before opening; an unregistered/undetected vault shows inline guidance + escape hatches instead of firing a deep link Obsidian rejects.
  • User-visible effect: first-time / unregistered users get an actionable panel (add-as-vault guidance, Reveal, Open-anyway, Install, config-dir override) rather than a silent or dead-end open.

Parity Contract

  • Legacy behavior preserved: a registered vault still opens via the same obsidian://open?path= deep link; the View Vault button does nothing in memory tree #2281 toast + Reveal action remain (Reveal now via the shared revealWorkspacePath). Behaviour only diverges when the vault isn't registered/detected.
  • Guard/fallback/dispatch parity checks: detection failures fall back to the guidance panel; "Open anyway" preserves the unconditional deep-link path for users whose install we can't probe.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this one
  • Resolution: N/A

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an “Open in Obsidian” section with vault-status probing, inline guidance panel, and Advanced option to set a custom Obsidian config folder.
  • Improvements

    • Improved vault-detection UX: checking status, toast feedback for deep-link attempts, and clear fallbacks (Reveal Folder, Open Anyway, Install link).
    • Replaced prior vault control with the new guidance-driven flow.
  • Translations

    • Added workspace/vault UI strings across many languages.
  • Tests

    • New and updated tests covering probe, guidance flows, reveal/open actions, config override persistence, and error cases.
  • Documentation

    • Expanded step-by-step vault-opening guide and troubleshooting.

Review Change Stack

@sanil-23 sanil-23 requested a review from a team May 25, 2026 13:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

📝 Walkthrough

Walkthrough

Adds backend vault-registration detection and a new ObsidianVaultSection UI that probes vault readiness before attempting obsidian:// deep-links; provides reveal/install/config-dir override guidance, RPC/schema wiring, TypeScript adapter, tests, i18n strings, and docs updates.

Changes

Obsidian Vault Detection & Guided Opening

Layer / File(s) Summary
Vault registration detection and path matching
src/openhuman/memory_store/content/obsidian_registry.rs, src/openhuman/memory_store/content/mod.rs
Introduces VaultRegistration and vault_registration_status() that probe candidate obsidian.json locations (override → OS defaults → Flatpak/Snap), parse JSON safely, lexically normalize paths (trim separators), and perform component-boundary ancestor-or-equal matching. Includes unit tests.
Backend read RPC
src/openhuman/memory/read_rpc.rs
Adds ObsidianVaultStatusResponse and obsidian_vault_status_rpc which spawns a blocking probe calling the registry with an optional config-dir override, returns registered, config_found, and content_root_abs, and redacts absolute paths in logs. Includes async tests.
RPC schema & handler registration
src/openhuman/memory/schema.rs
Registers the obsidian_vault_status controller in memory_tree schemas, defines the optional obsidian_config_dir input and boolean/path outputs, and adds handle_obsidian_vault_status that loads config and delegates to the read RPC.
Frontend RPC adapter and TypeScript bindings
app/src/utils/tauriCommands/memoryTree.ts, app/src/utils/tauriCommands/memoryTree.test.ts
Adds ObsidianVaultStatus type and memoryTreeObsidianVaultStatus(obsidianConfigDir?) adapter that forwards optional override, unwraps RpcOutcome envelopes, logs booleans, and returns the status. Tests validate param dispatch and envelope/bare-value handling.
New ObsidianVaultSection React component
app/src/components/intelligence/ObsidianVaultSection.tsx
New component that probes vault status, fires obsidian://open?path=... when registered, or shows an inline guidance panel with Reveal/Open/Install actions. Supports an advanced configDir override persisted to localStorage and re-checks on save; emits toasts for open/reveal outcomes and contains an inline ExternalLinkIcon.
MemoryWorkspace component refactor
app/src/components/intelligence/MemoryWorkspace.tsx
Removes the in-file openVaultInObsidian helper and handleViewVault, replaces the previous "View Vault" button with <ObsidianVaultSection contentRootAbs=... onToast=... />, and updates imports (drops openUrl/revealWorkspacePath) and the unused inline ExternalLinkIcon.
Frontend component and adapter tests
app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx, app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
Adds Vitest + RTL tests covering registered/unregistered vault flows, "Open anyway", "Reveal Folder", install navigation, advanced config-dir override persistence and re-check, detection failure fallback, and updates MemoryWorkspace tests to mock the new adapter.
Internationalization and documentation updates
app/src/lib/i18n/chunks/*, app/src/lib/i18n/en.ts, gitbooks/features/obsidian-wiki/README.md
Adds workspace.* translation keys across locale chunks for the vault check/guidance UI and expands the Obsidian wiki README with step-by-step vault-opening and troubleshooting guidance.

Sequence Diagram

sequenceDiagram
  participant User
  participant ObsidianVaultSection
  participant Adapter as memoryTreeObsidianVaultStatus
  participant ReadRPC as obsidian_vault_status_rpc
  participant Registry as obsidian_registry
  User->>ObsidianVaultSection: click "Open in Obsidian"
  ObsidianVaultSection->>Adapter: probe vault status (optional config override)
  Adapter->>ReadRPC: RPC call openhuman.memory_tree_obsidian_vault_status(params)
  ReadRPC->>Registry: vault_registration_status(content_root, override)
  Registry-->>ReadRPC: { registered, config_found, content_root_abs }
  ReadRPC-->>Adapter: status response
  Adapter-->>ObsidianVaultSection: status
  alt registered
    ObsidianVaultSection->>User: open deep link via openUrl and toast
  else not registered or probe failed
    ObsidianVaultSection->>User: show guidance panel (Reveal / Open anyway / Install / Advanced)
  end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

Suggested Reviewers

  • graycyrus
  • senamakel

Poem

🐰 I probed the vault with careful ears,
I nudged the link through hopeful cheers,
If Obsidian hides, I'll show the way —
Reveal the folder, or open anyway.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: detecting Obsidian vault registration before attempting the deep link, which is the core objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels May 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@app/src/components/intelligence/ObsidianVaultSection.tsx`:
- Line 184: Replace the hard-coded user-visible JSX strings in the
ObsidianVaultSection component (the title prop value
`obsidian://open?path=${contentRootAbs}` and the placeholder at the other
occurrence) with localized strings obtained from the useT() hook (e.g., const t
= useT()) and reference new i18n keys (add descriptive keys like
obsidian.openLink and obsidian.placeholder to the component). Update
app/src/lib/i18n/en.ts with those new keys and their English values and add the
same keys to the other locale chunk files so all locales include the new
entries.
- Around line 114-118: installObsidian currently calls
openUrl(OBSIDIAN_DOWNLOAD_URL) and ignores any rejection, which can create
unhandled async errors; update installObsidian to handle the returned promise
from openUrl by awaiting or using .catch(...) and surface failures (e.g., log
via processLogger/console.error and show a user-facing error/toast) so failures
are handled gracefully and don't bubble as unhandled rejections; locate the
installObsidian callback in ObsidianVaultSection.tsx and add proper error
handling around openUrl.

In `@src/openhuman/memory_store/content/obsidian_registry.rs`:
- Around line 115-117: Guard against empty vault paths by skipping any
parsed.vaults entries whose entry.path is empty (or which
lexically_normalize(Path::new(&entry.path)) yields an empty path) before calling
is_ancestor_or_equal; update the loop that computes `vault =
lexically_normalize(Path::new(&entry.path))` to continue if
entry.path.trim().is_empty() or if `vault` has no components, then only call
`is_ancestor_or_equal(&vault, &target)` for non-empty vaults so malformed/empty
paths cannot produce false positives for `registered`.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d17802cf-bce1-4c6c-aa42-1ce49abdd4cd

📥 Commits

Reviewing files that changed from the base of the PR and between d997394 and aad650d.

📒 Files selected for processing (25)
  • app/src/components/intelligence/MemoryWorkspace.tsx
  • app/src/components/intelligence/ObsidianVaultSection.tsx
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
  • app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/utils/tauriCommands/memoryTree.test.ts
  • app/src/utils/tauriCommands/memoryTree.ts
  • gitbooks/features/obsidian-wiki/README.md
  • src/openhuman/memory/read_rpc.rs
  • src/openhuman/memory/schema.rs
  • src/openhuman/memory_store/content/mod.rs
  • src/openhuman/memory_store/content/obsidian_registry.rs

Comment thread app/src/components/intelligence/ObsidianVaultSection.tsx
Comment thread app/src/components/intelligence/ObsidianVaultSection.tsx
Comment thread src/openhuman/memory_store/content/obsidian_registry.rs
@coderabbitai coderabbitai Bot added the feature Net-new user-facing capability or product behavior. label May 25, 2026
@sanil-23 sanil-23 force-pushed the fix/obsidian-vault-registration branch from 4027a9b to 308713d Compare May 25, 2026 16:02
@coderabbitai coderabbitai Bot added the bug label May 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/src/lib/i18n/en.ts (1)

1601-1601: 💤 Low value

Consider reusing common.save instead of duplicating "Save".

'workspace.save': 'Save' at line 1601 duplicates 'common.save': 'Save' at line 16. If the context doesn't require a distinct translation, reusing the common key would reduce the string count and simplify localization.

🤖 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 `@app/src/lib/i18n/en.ts` at line 1601, The file defines a duplicate
translation key 'workspace.save' with the same value as 'common.save'; remove
the redundant 'workspace.save' entry and update any call sites that reference
workspace.save to use the shared key 'common.save' (or alias usages to
t('common.save')) so the single common translation is reused across the
codebase.
app/src/components/intelligence/ObsidianVaultSection.tsx (1)

186-200: ⚡ Quick win

Use design-system color tokens instead of raw violet-* utilities.

This section introduces several hard-coded violet-* classes for primary UI surfaces/actions. Please switch these to your configured tokenized palette (primary-* / semantic tokens) to keep visual consistency with the design system.

♻️ Suggested token-aligned class updates
- className="... bg-violet-500 ... hover:bg-violet-600 ... focus:ring-violet-300"
+ className="... bg-primary-500 ... hover:bg-primary-600 ... focus:ring-primary-200"

- className="... border-violet-200 bg-violet-50 ... dark:border-violet-500/30 dark:bg-violet-500/10"
+ className="... border-primary-200 bg-primary-50 ... dark:border-primary-500/30 dark:bg-primary-500/10"

- className="... border-violet-300 ... text-violet-700 hover:bg-violet-50 ... dark:border-violet-500/40 ... dark:text-violet-300"
+ className="... border-primary-300 ... text-primary-700 hover:bg-primary-50 ... dark:border-primary-500/40 ... dark:text-primary-300"

- className="... text-violet-600 ... dark:text-violet-300"
+ className="... text-primary-600 ... dark:text-primary-300"

- className="... focus:ring-violet-300 ..."
+ className="... focus:ring-primary-300 ..."

- className="... bg-violet-500 ... hover:bg-violet-600 ..."
+ className="... bg-primary-500 ... hover:bg-primary-600 ..."

As per coding guidelines app/**/*.{tsx,js,css}: "Design system tokens live in app/tailwind.config.js. Use Tailwind with custom radii/spacing/shadows. Design intent: premium, calm visual language — ocean primary (#4A83DD), sage / amber / coral semantic colors..."

Also applies to: 224-227, 244-245, 264-266, 273-274

🤖 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 `@app/src/components/intelligence/ObsidianVaultSection.tsx` around lines 186 -
200, Replace hard-coded violet-* Tailwind utilities in the ObsidianVaultSection
component with the project's design-system tokens (e.g., primary-*/semantic
tokens from tailwind.config) so UI follows the tokenized palette: update the
button's className (the inline-flex button that renders ExternalLinkIcon and
uses title={`obsidian://open?path=${contentRootAbs}`}) to use primary
background, hover, focus ring and disabled token classes instead of
bg-violet-500/600 and ring-violet-300, and update the guidance panel (the div
with data-testid="obsidian-vault-guidance") to use tokenized border/bg colors
instead of border-violet-200 and bg-violet-50 (and the dark-mode variants).
Apply the same token replacements to the other similar blocks in this component
where violet-* is used (the other button/panel instances referenced in the
review).
🤖 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 `@src/openhuman/memory/read_rpc.rs`:
- Around line 1041-1044: Normalize obsidian_config_dir by trimming and treating
empty or whitespace-only strings as None before converting to a Path to avoid
resolving to "."; in the tokio::task::spawn_blocking closure update the handling
of obsidian_config_dir (the value passed into
obsidian_registry::vault_registration_status) so you call something like
obsidian_config_dir.and_then(|s| { let t = s.trim(); if t.is_empty() { None }
else { Some(std::path::Path::new(t)) } }) (or equivalent) instead of using
as_deref().map(std::path::Path::new), ensuring vault_registration_status gets
None for blank overrides.

---

Nitpick comments:
In `@app/src/components/intelligence/ObsidianVaultSection.tsx`:
- Around line 186-200: Replace hard-coded violet-* Tailwind utilities in the
ObsidianVaultSection component with the project's design-system tokens (e.g.,
primary-*/semantic tokens from tailwind.config) so UI follows the tokenized
palette: update the button's className (the inline-flex button that renders
ExternalLinkIcon and uses title={`obsidian://open?path=${contentRootAbs}`}) to
use primary background, hover, focus ring and disabled token classes instead of
bg-violet-500/600 and ring-violet-300, and update the guidance panel (the div
with data-testid="obsidian-vault-guidance") to use tokenized border/bg colors
instead of border-violet-200 and bg-violet-50 (and the dark-mode variants).
Apply the same token replacements to the other similar blocks in this component
where violet-* is used (the other button/panel instances referenced in the
review).

In `@app/src/lib/i18n/en.ts`:
- Line 1601: The file defines a duplicate translation key 'workspace.save' with
the same value as 'common.save'; remove the redundant 'workspace.save' entry and
update any call sites that reference workspace.save to use the shared key
'common.save' (or alias usages to t('common.save')) so the single common
translation is reused across the codebase.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2544751d-e0c7-45ef-987e-67538a93bee4

📥 Commits

Reviewing files that changed from the base of the PR and between 4027a9b and 308713d.

📒 Files selected for processing (25)
  • app/src/components/intelligence/MemoryWorkspace.tsx
  • app/src/components/intelligence/ObsidianVaultSection.tsx
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
  • app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/utils/tauriCommands/memoryTree.test.ts
  • app/src/utils/tauriCommands/memoryTree.ts
  • gitbooks/features/obsidian-wiki/README.md
  • src/openhuman/memory/read_rpc.rs
  • src/openhuman/memory/schema.rs
  • src/openhuman/memory_store/content/mod.rs
  • src/openhuman/memory_store/content/obsidian_registry.rs
✅ Files skipped from review due to trivial changes (9)
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/id-3.ts

Comment thread src/openhuman/memory/read_rpc.rs
@sanil-23
Copy link
Copy Markdown
Contributor Author

Thanks for the re-review — addressed the actionable (blank obsidian_config_dir normalization) in 13d206b8. On the two nitpicks:

  • workspace.save duplicate — done: switched the button to t('common.save') and removed the redundant workspace.save key from en.ts and all locale chunks.
  • violet-* vs primary-* tokens — keeping violet-* here for parity: this section replaced the pre-existing "View Vault in Obsidian" button, which already used bg-violet-500, so the accent is unchanged from what shipped. Migrating that button to the ocean primary-* token is a deliberate design change that should be its own PR rather than bundled into this fix. Happy to do it as a follow-up if a maintainer prefers.

@sanil-23 sanil-23 force-pushed the fix/obsidian-vault-registration branch from 13d206b to 25cce39 Compare May 25, 2026 16:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@app/src/components/intelligence/ObsidianVaultSection.tsx`:
- Around line 140-146: The branch handling a registered vault leaves the
guidance panel open when a previous error had set expanded=true; after calling
fireDeepLink() and toastOpenOutcome(err) in the registered-vault path (the code
using status.registered, fireDeepLink, toastOpenOutcome, and setExpanded),
explicitly clear the guidance UI when the deep-link succeeded by calling
setExpanded(false) when err === null (keep the existing setExpanded(true) when
err !== null).

In `@src/openhuman/memory_store/content/obsidian_registry.rs`:
- Around line 107-110: The logs in
src/openhuman/memory_store/content/obsidian_registry.rs currently print
path.display() (e.g., in the log::warn! calls around the parse failure and the
block at lines 123-127) which can expose absolute config/home paths; replace
those uses with a redacted/hashed representation consistent with the redaction
used in src/openhuman/memory/read_rpc.rs (e.g., call the same redact/hash helper
used there or add a local helper like redact_path(path) that returns a
deterministic hash or redacted string), update the log::warn! invocations to
include the redacted value instead of path.display(), and import or reuse the
existing redact helper so both the parse failure warning and the other registry
warnings use the same redaction approach.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20b8f7b4-633b-4e5a-aea9-1e4adb61ab9c

📥 Commits

Reviewing files that changed from the base of the PR and between 13d206b and 25cce39.

📒 Files selected for processing (25)
  • app/src/components/intelligence/MemoryWorkspace.tsx
  • app/src/components/intelligence/ObsidianVaultSection.tsx
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
  • app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/utils/tauriCommands/memoryTree.test.ts
  • app/src/utils/tauriCommands/memoryTree.ts
  • gitbooks/features/obsidian-wiki/README.md
  • src/openhuman/memory/read_rpc.rs
  • src/openhuman/memory/schema.rs
  • src/openhuman/memory_store/content/mod.rs
  • src/openhuman/memory_store/content/obsidian_registry.rs
✅ Files skipped from review due to trivial changes (8)
  • gitbooks/features/obsidian-wiki/README.md
  • app/src/lib/i18n/chunks/pt-3.ts
  • src/openhuman/memory_store/content/mod.rs
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/en.ts

Comment thread app/src/components/intelligence/ObsidianVaultSection.tsx
Comment thread src/openhuman/memory_store/content/obsidian_registry.rs
sanil-23 and others added 4 commits May 25, 2026 20:38
… link

"View Vault" fired obsidian://open?path=<content_root> unconditionally,
but that scheme only resolves folders already registered in Obsidian's
obsidian.json — it can't register one (a .obsidian/ folder on disk is not
enough). So a first-time click launched Obsidian onto "Unable to find a
vault for the URL". The tinyhumansai#2281 fix made the failure visible but still
couldn't open the vault.

Now the click first probes registration (new memory_tree_obsidian_vault_status
RPC — best-effort read of obsidian.json across the standard config dir +
Flatpak/Snap + an optional config-dir override). If registered it opens
directly; if not, an inline guidance section appears (progressive
disclosure) with Reveal Folder, Open-in-Obsidian-anyway, Install Obsidian,
and an Advanced config-folder override — instead of firing a doomed link.
Detection is best-effort: a false "not registered" never blocks (Open
anyway always fires the link).

- core: content_store/obsidian_registry.rs detector + ancestor match
- core: memory_tree_obsidian_vault_status controller; fix the false
  "resolves arbitrary paths without registration" comment in read_rpc
- app: ObsidianVaultSection (inline, replaces the bare button) + RPC client
- docs: obsidian-wiki "Open the vault" now documents the one-time step
- tests: 10 Rust (detector + RPC) + 9 Vitest (section + client)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- obsidian_registry: skip empty vault paths and reject an empty ancestor in
  is_ancestor_or_equal so a malformed obsidian.json entry can't match every
  content root (false registered=true). Add regression test.
- ObsidianVaultSection: wrap installObsidian's openUrl in try/catch so a
  rejection can't surface as an unhandled promise rejection.
- i18n: localize the config-dir input placeholder
  (workspace.obsidianConfigDirPlaceholder) across en + all locale chunks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… flow

- read_rpc: normalize a blank/whitespace obsidian_config_dir to None before
  Path conversion so it can't resolve to "." and probe a stray local
  obsidian.json (the UI omits it when empty, but the RPC is a public
  controller). Add regression test.
- i18n: reuse the existing common.save key instead of duplicating
  workspace.save; drop the redundant key from en + all locale chunks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…g redaction)

- ObsidianVaultSection: collapse the guidance panel on a successful registered
  open so stale fallback UI from a prior failed/not-registered check doesn't
  linger (setExpanded(err !== null)).
- obsidian_registry: redact the obsidian.json path in the warn/debug logs
  (embeds the user's home), consistent with read_rpc's redaction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sanil-23 sanil-23 force-pushed the fix/obsidian-vault-registration branch from c346319 to 5669083 Compare May 25, 2026 18:38
…nv race

The `documents` tests call `memory_init` → `current_workspace_dir` →
`Config::load_or_init`, which reads the process-global `OPENHUMAN_WORKSPACE`.
Unlike the `learn` tests they held no env guard, so a concurrent env-mutating
test could swap the var and tear its tempdir down mid-call, intermittently
failing `memory_init` with `SQLITE_IOERR` / config atomic-replace `ENOENT`
(seen 1/9500, only under cargo-llvm-cov's slower timing).

`ensure_memory_client` now returns a `WorkspaceEnvGuard` that holds
`TEST_ENV_LOCK` and pins `OPENHUMAN_WORKSPACE` at the stable, never-torn-down
test workspace for the whole test; both `documents` tests bind it. Acquired
after the existing `GLOBAL_MEMORY_TEST_LOCK` so lock order stays GLOBAL→ENV
(matches the `learn` tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Nice work — this is a well-structured fix for a real UX pain point.

What changed

Area Files Summary
Rust core obsidian_registry.rs, read_rpc.rs, schema.rs, mod.rs New obsidian_registry module probes obsidian.json across OS-standard + sandbox paths; new memory_tree_obsidian_vault_status RPC with defensive whitespace/empty-path normalization
Frontend ObsidianVaultSection.tsx, MemoryWorkspace.tsx New component: click → probe → registered opens directly, unregistered shows progressive-disclosure guidance (Reveal / Open anyway / Install / Advanced config-dir override)
Tests 8 Rust detector tests + 3 RPC tests, 7 Vitest component tests + 2 client tests Thorough coverage of happy path, edge cases (empty paths, malformed config, trailing slashes, sibling prefixes), and failure modes
i18n en.ts + 13 locale chunks 10 new keys added consistently across all locales
Docs obsidian-wiki/README.md Updated with step-by-step first-time vault registration flow
Test infra documents.rs WorkspaceEnvGuard fixes a race between concurrent tests mutating OPENHUMAN_WORKSPACE — good stability improvement

What I checked

  • Architecture: Clean separation — detector module is pure filesystem, RPC is a thin wrapper, UI is a self-contained component. No .unwrap() in production Rust. Detection is best-effort with safe fallbacks throughout.
  • Security: Absolute paths properly redacted in logs (the CodeRabbit finding was addressed). encodeURIComponent on the deep link path. Config-dir override is sanitized (trim + empty check) before use.
  • Patterns: Component follows existing conventions — useCallback deps are correct, toast/reveal patterns match the rest of MemoryWorkspace, revealWorkspacePath reuse from #2527.
  • Path matching: lexically_normalize + is_ancestor_or_equal is intentionally lexical-only (no canonicalize), case-sensitive. A false negative on macOS case-insensitive volumes is conservative — the "Open anyway" escape hatch covers it.
  • CodeRabbit dedup: All 6 CodeRabbit findings (openUrl error handling, localized placeholder, empty vault path guard, stale guidance panel, log redaction, blank override normalization) were addressed in follow-up commits. Nothing to repeat.

No critical or major issues found. LGTM — moving to to-be-approved.

@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 25, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@src/openhuman/memory_store/content/obsidian_registry.rs`:
- Around line 30-33: The docstring for the ObsidianRegistry field config_found
is inaccurate: the code sets config_found = true when the obsidian.json file is
successfully read even if parsing later fails, so update the comment on
config_found to reflect "file found/read" (or equivalent wording such as
"found/read, not necessarily parsed") rather than "found and parsed" so callers
won't be misled; locate the config_found field on the ObsidianRegistry struct
and change its doc text to match the actual probe semantics.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff8dc267-b652-457d-a9c0-d0b7b53701dd

📥 Commits

Reviewing files that changed from the base of the PR and between 13d206b and 19eb69c.

📒 Files selected for processing (26)
  • app/src/components/intelligence/MemoryWorkspace.tsx
  • app/src/components/intelligence/ObsidianVaultSection.tsx
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
  • app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/utils/tauriCommands/memoryTree.test.ts
  • app/src/utils/tauriCommands/memoryTree.ts
  • gitbooks/features/obsidian-wiki/README.md
  • src/openhuman/memory/ops/documents.rs
  • src/openhuman/memory/read_rpc.rs
  • src/openhuman/memory/schema.rs
  • src/openhuman/memory_store/content/mod.rs
  • src/openhuman/memory_store/content/obsidian_registry.rs
✅ Files skipped from review due to trivial changes (10)
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • src/openhuman/memory_store/content/mod.rs
  • app/src/lib/i18n/chunks/it-3.ts

Comment thread src/openhuman/memory_store/content/obsidian_registry.rs Outdated
CodeRabbit: VaultRegistration::config_found is set true on a successful read
of a candidate obsidian.json even when parsing that file then fails (the
parse-error branch still counts it as found). The previous doc said "found
and parsed", which mis-describes the contract. Doc-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
src/openhuman/memory/schema.rs (1)

641-642: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Schema comment for config_found is stricter than implementation.

At Line 641, “found and parsed” conflicts with backend behavior (config_found becomes true after successful read, even if parsing fails). Please keep schema docs aligned with runtime semantics.

📝 Suggested schema comment update
-                    comment: "True when an obsidian.json was found and parsed (Obsidian is \
-                              set up). Lets the UI offer add-as-vault vs. install.",
+                    comment: "True when at least one candidate obsidian.json was found/read \
+                              (even if parsing fails). Lets the UI offer add-as-vault vs. install.",
🤖 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 `@src/openhuman/memory/schema.rs` around lines 641 - 642, Update the schema
comment for the config_found field to match runtime semantics: change the
wording that currently reads "True when an obsidian.json was found and parsed"
to indicate that config_found is set to true after the obsidian.json file is
successfully read (even if parsing fails). Locate the comment adjacent to the
config_found field in schema.rs and replace "found and parsed" with wording such
as "found/read (parsing may still fail)" or similar to accurately reflect the
implementation in the code that sets config_found on successful read.
src/openhuman/memory/read_rpc.rs (1)

1018-1020: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

config_found docs overstate the actual probe semantics.

At Line 1018, the comment says “found and parsed,” but probe logic marks config_found=true once a candidate file is read, even if parsing fails. Please align this wording with runtime behavior.

📝 Suggested doc fix
-    /// `true` when an `obsidian.json` was found and parsed (Obsidian is set
-    /// up). Lets the UI offer "Open folder as vault" vs. "Install Obsidian".
+    /// `true` when at least one candidate `obsidian.json` was found/read
+    /// (even if parsing later fails). Lets the UI offer "Open folder as vault"
+    /// vs. "Install Obsidian".
🤖 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 `@src/openhuman/memory/read_rpc.rs` around lines 1018 - 1020, The field doc for
config_found currently says "found and parsed" but the probe actually sets
config_found = true as soon as a candidate obsidian.json is read even when
parsing fails; update the comment on the config_found field to reflect that it
indicates a candidate obsidian.json was discovered/read (not necessarily
successfully parsed) so the UI can distinguish "file present" vs "parse
succeeded" semantics for obsidian.json.
🤖 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.

Duplicate comments:
In `@src/openhuman/memory/read_rpc.rs`:
- Around line 1018-1020: The field doc for config_found currently says "found
and parsed" but the probe actually sets config_found = true as soon as a
candidate obsidian.json is read even when parsing fails; update the comment on
the config_found field to reflect that it indicates a candidate obsidian.json
was discovered/read (not necessarily successfully parsed) so the UI can
distinguish "file present" vs "parse succeeded" semantics for obsidian.json.

In `@src/openhuman/memory/schema.rs`:
- Around line 641-642: Update the schema comment for the config_found field to
match runtime semantics: change the wording that currently reads "True when an
obsidian.json was found and parsed" to indicate that config_found is set to true
after the obsidian.json file is successfully read (even if parsing fails).
Locate the comment adjacent to the config_found field in schema.rs and replace
"found and parsed" with wording such as "found/read (parsing may still fail)" or
similar to accurately reflect the implementation in the code that sets
config_found on successful read.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: abfe983b-1972-4d06-9324-110a3d16699f

📥 Commits

Reviewing files that changed from the base of the PR and between 13d206b and a0bf60f.

📒 Files selected for processing (26)
  • app/src/components/intelligence/MemoryWorkspace.tsx
  • app/src/components/intelligence/ObsidianVaultSection.tsx
  • app/src/components/intelligence/__tests__/MemoryWorkspace.test.tsx
  • app/src/components/intelligence/__tests__/ObsidianVaultSection.test.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/utils/tauriCommands/memoryTree.test.ts
  • app/src/utils/tauriCommands/memoryTree.ts
  • gitbooks/features/obsidian-wiki/README.md
  • src/openhuman/memory/ops/documents.rs
  • src/openhuman/memory/read_rpc.rs
  • src/openhuman/memory/schema.rs
  • src/openhuman/memory_store/content/mod.rs
  • src/openhuman/memory_store/content/obsidian_registry.rs
✅ Files skipped from review due to trivial changes (12)
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • gitbooks/features/obsidian-wiki/README.md
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts

@sanil-23 sanil-23 requested a review from graycyrus May 25, 2026 20:38
@sanil-23 sanil-23 merged commit e05cab9 into tinyhumansai:main May 25, 2026
37 of 38 checks passed
YOMXXX added a commit to YOMXXX/openhuman that referenced this pull request May 26, 2026
Last remaining Memory-tab surface that was constructing an
`obsidian://open?path=<abs>` URL straight from a graph-export RPC field
without going through the shared workspace-link layer introduced in
PR tinyhumansai#2476. MemoryGraph already migrated to `openWorkspacePath` /
`previewWorkspaceText` in PR tinyhumansai#2638; this finishes the migration called
out in issue tinyhumansai#2492 by resolving the vault's absolute path through the
new `resolveWorkspaceAbsolutePath` wrapper (which delegates to the same
canonicalize + workspace-containment guard the rest of the layer uses).

Behavior is unchanged from the user's point of view — the click still
fires `obsidian://open?path=<vault-abs>` and the toast still names the
vault path — but the absolute path is now derived from the Rust-side
resolver instead of trusting whatever the RPC handed back. The
`contentRootAbs` prop is preserved for display (tooltip, guidance-panel
code block, toast message) so no cascading prop changes are needed.

Adds two tests covering the new path: (1) the deep link URL is built
from the resolver output, not the prop, and (2) a resolver rejection
surfaces an error toast and keeps the guidance panel expanded so the
user retains an escape hatch. MemoryWorkspace.test.tsx is updated to
mock `resolveWorkspaceAbsolutePath` so the existing `openUrl` assertion
remains stable.

Closes tinyhumansai#2492
YOMXXX added a commit to YOMXXX/openhuman that referenced this pull request May 27, 2026
Last remaining Memory-tab surface that was constructing an
`obsidian://open?path=<abs>` URL straight from a graph-export RPC field
without going through the shared workspace-link layer introduced in
PR tinyhumansai#2476. MemoryGraph already migrated to `openWorkspacePath` /
`previewWorkspaceText` in PR tinyhumansai#2638; this finishes the migration called
out in issue tinyhumansai#2492 by resolving the vault's absolute path through the
new `resolveWorkspaceAbsolutePath` wrapper (which delegates to the same
canonicalize + workspace-containment guard the rest of the layer uses).

Behavior is unchanged from the user's point of view — the click still
fires `obsidian://open?path=<vault-abs>` and the toast still names the
vault path — but the absolute path is now derived from the Rust-side
resolver instead of trusting whatever the RPC handed back. The
`contentRootAbs` prop is preserved for display (tooltip, guidance-panel
code block, toast message) so no cascading prop changes are needed.

Adds two tests covering the new path: (1) the deep link URL is built
from the resolver output, not the prop, and (2) a resolver rejection
surfaces an error toast and keeps the guidance panel expanded so the
user retains an escape hatch. MemoryWorkspace.test.tsx is updated to
mock `resolveWorkspaceAbsolutePath` so the existing `openUrl` assertion
remains stable.

Closes tinyhumansai#2492
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants