Commit graph

1058 commits

Author SHA1 Message Date
Zero Liu
9712d52590
introduce model migration script 2026-05-28 16:03:46 -07:00
Zero Liu
31dc17625a
BYOK model management 2026-05-28 16:02:48 -07:00
Zero Liu
e069b08070
Add vault test with test fixture 2026-05-28 16:02:48 -07:00
Zero Liu
e9c0a983da
Add copilot plus flash support in opencode 2026-05-28 16:02:48 -07:00
Zero Liu
044686094e
improve agent model enabler settings 2026-05-28 16:02:47 -07:00
Zero Liu
60c0a5b8d5
Fix model picker padding 2026-05-28 16:02:47 -07:00
Zero Liu
d7fc1b93ff
Render model descriptions 2026-05-28 16:02:47 -07:00
Zero Liu
be6dd96c9a
Fix claude extended thinking 2026-05-28 16:02:47 -07:00
Zero Liu
feb915240e
Fix opencode enable model UI 2026-05-28 16:02:47 -07:00
Zero Liu
25b5e48ca0
Add BYOK settings - agent enablement 2026-05-28 16:02:47 -07:00
Zero Liu
2537348b2d
Fix lint error 2026-05-28 16:00:38 -07:00
Zero Liu
814c63d62a
Add BYOK settings modal 2026-05-28 16:00:38 -07:00
Zero Liu
6856a327b2
Add backend config registry and byok setup api 2026-05-28 16:00:38 -07:00
Zero Liu
43bbf2634a
implement verification logic 2026-05-28 16:00:38 -07:00
Zero Liu
a2167708e6
Add provider and configured model registry 2026-05-28 16:00:38 -07:00
Zero Liu
e73fef8db1
Add service APIs 2026-05-28 16:00:38 -07:00
Zero Liu
8617b0b9e4
introduce catalog download service 2026-05-28 16:00:38 -07:00
Zero Liu
d9388116bc
boostrap new model managmeent 2026-05-28 16:00:38 -07:00
Zero Liu
46863aeeb1
docs(design): add model management redesign spec + data model spec
Replaces the older MODEL_MANAGEMENT_REDESIGN.md with a more focused tech spec,
a data-model spec with review notes, and a portal-container contract doc that
the upcoming reimplementation will follow.
2026-05-28 16:00:38 -07:00
Zero Liu
d72e3ee05a
refactor(agent-mode): redesign agent binary configuration UI (#2517)
Replace the per-backend install/settings panels with a shared Configure
dialog layout. Introduces ConfigDialogShell + ConfigSection, InstallCommandRow,
and an installStatus badge/status-line module (with tests), and reworks the
Claude, Codex, and opencode Configure dialogs onto it. The settings page now
shows each backend's icon, an install-status badge, and a Configure button,
dropping the old BinaryInstallContent and SimpleBackendSettingsPanel helpers.
Copy is simplified for non-technical users and dialog spacing/dividers are
made consistent.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:15:52 -07:00
Zero Liu
0114cdbd12
docs(agent-mode): migrate pending TODOs to GitHub issues (#2516)
Replaces every pending top-level `- [ ]` in `AGENT_MODE_TODOS.md` with a
link to its corresponding issue in logancyang/obsidian-copilot-preview
(#59-#98). Follows the playbook in `AGENT_TODOS_TO_ISSUES_PLAYBOOK.md`:
sub-bullets folded into issue bodies, and "Integrate copilot plus tool
calls" split into 5 child issues (#80-#84) under a now-plain parent
bullet. 39 issues opened end-to-end via paired author/reviewer subagents.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 11:03:27 -07:00
Zero Liu
3aea987832
docs(agent-mode): add issue-creation skill, migration playbook, refresh TODOs (#2514)
- Add `.claude/skills/create-agent-issue/SKILL.md`: project-level skill that
  codifies the standard for one well-formed GitHub issue (title shape, body
  sections, label palette, draft artifact format, reviewer rubric, three-stage
  workflow: draft / review-and-push / all).
- Add `designdocs/todo/AGENT_TODOS_TO_ISSUES_PLAYBOOK.md`: orchestrator
  playbook for migrating `AGENT_MODE_TODOS.md` into GitHub issues with a
  two-subagent (author + reviewer) flow, autonomous triage, parallelism,
  idempotency, and verbatim subagent prompt templates.
- Revamp `designdocs/todo/AGENT_MODE_TODOS.md`: richer per-item context,
  "design needed" markers, reorganized MCP and Codex auth items, current
  pending count is 33 top-level items (P0=7, P1=17, P2=7, P3=2).
- Drop `designdocs/todo/MCP_EXTERNALLY_MANAGED_SERVERS.md` (stale).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:42:27 -07:00
Zero Liu
e7477385ae
docs(skills): add design doc for project-folder discovery redesign (#2513)
Replaces the rescan/import-consent flow with unified discovery across
canonical and agent project folders, lazy migration with a global
suppress flag, and an overflow-menu lockdown for mirrored duplicates.
2026-05-27 23:50:22 -07:00
Zero Liu
3e396d1a1d
docs(agent-mode): update TODO checklist (#2509)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:38:55 -07:00
Zero Liu
05434a59df
fix(skills): eliminate Skills Settings UI lag from watcher-driven refreshes (#2508)
* fix(skills): eliminate Skills Settings UI lag from watcher-driven refreshes

Replaces the time-based watcher suppression with path-scoped expectations:
each SkillManager FS write registers predicates (exists/missing/modified/
subtree-*) and the matching vault events are dropped without triggering a
debounced reconcile. A 10s safety timer backstops never-arriving events.
Toggle/delete/rename/saveProperties now publish incremental in-memory updates
instead of re-running full discovery, so the Properties modal save returns
synchronously and the grid reflects the change on the next render.

* fix(skills): heal drift when expectations expire; preserve external reconciles

Two fixes for the watcher-suppression machinery on PR #2508:

- `armSafetyTimer`: when the 10s backstop fires with expectations still
  pending, schedule a debounced reconcile before clearing. Catches the case
  where an external process undid our change (e.g. deleted a link we expected
  to exist) — the matching event was suppressed, predicate never satisfied,
  and previously the state drifted silently until an unrelated watched event
  fired.

- `runInternalMutation`: stop cancelling pre-existing reconcile timers in
  the finally block. Events fired during the mutation are dropped by the
  depth gate, so any debounce timer left armed was scheduled by an external
  event before the mutation started and still needs servicing.

Adds two regression tests and updates the pre-existing "safety timer clears
stale expectations" test which is superseded by the new healing behavior.
2026-05-21 15:07:49 -07:00
Zero Liu
8520b24477
perf(agent-mode): warm-adopt preload probe to skip first-chat spawn (#2507)
* perf(agent-mode): warm-adopt preload probe to skip first-chat spawn

The preloader's probe subprocess is now retained as a "warm" entry and
adopted by the first chat-open on that backend, so the first session
skips both the subprocess spawn and the `newSession` round-trip. Preload
status is also tracked per-backend: the chat gates on the active
backend's status only, and the picker shows per-backend loading rows for
the others.

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

* fix(agent-mode): defer model+effort seeding to backend confirmation

- Seed only baseModelId (not effort) so descriptor-style backends
  (Claude) don't see a matching seeded effort and skip the real
  setConfigOption inside applyInitialSessionConfig.
- Gate warm-session `ready` on confirmSeededSelection so sendPrompt
  can't race onto the probe's model before setModel resolves.
- Add regression tests covering both paths.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:48:49 -07:00
Zero Liu
a207694cbf
docs: fix Copilot command ID in CLI testing guide (#2506)
Replace non-existent `copilot:open-copilot-chat` with the registered
`copilot:agent-chat-open-window` ID in both the "Run a command" example
and the smoke-test scaffold so the documented commands actually work.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:00:20 -07:00
Zero Liu
9fe7a3b95e
docs: add Obsidian CLI e2e testing guide (#2505)
Adds OBSIDIAN_CLI_TEST.md with a field guide for driving the plugin
through the Obsidian desktop CLI: multi-vault targeting (the biggest
gotcha — default routes to whichever window was touched last), popout
window limitations, settings round-trips via eval/saveData, real-input
UI driving via dev:cdp, screenshots, console/error capture, performance
metrics, and a smoke-test scaffold. AGENTS.md now points to it and
keeps only the multi-vault warning inline so there is one source of
truth.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:56:44 -07:00
Zero Liu
bf0308dd51
feat(agent-mode): make note links clickable in chat and tool cards (#2503)
* feat(agent-mode): make note links clickable in chat and tool cards

Switches markdown rendering to the modern `MarkdownRenderer.render(app, …)`
API via a shared `renderMarkdown` wrapper, and adds a delegated click
handler so `a.internal-link` inside chat/agent/plan-preview views opens
via `app.workspace.openLinkText` (left-click in current pane, cmd/middle
in a new tab). Tool ActionCards now also expose the collapsed line as
a clickable target once the call has completed.

Threads `app` explicitly through the components and utilities that
previously relied on the global `app` (lexicalTextUtils, notePreviewUtils,
vaultPath, AtMention/Note/Paste/TextInsertion plugins) using the
`useApp()` hook at the leaf, and updates AGENTS.md to discourage new
uses of the global.

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

* test(chat): fix ChatSingleMessage mocks for wireInternalLinks

The `renderMarkdown` wrapper now calls `component.register(...)` after
`MarkdownRenderer.render(...)`. The test's `obsidian.Component` mock was
missing `register`, causing the promise to reject and `logError` (which
calls the unmocked `getSettings()`) to crash. Add `register` to the
Component mock and mock `getSettings` as a safety net.

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

* fix(agent-mode): resolve internal links against active note

Pass the active file path as sourcePath to renderMarkdown so wikilinks
with duplicate basenames or heading-only references resolve to the right
file instead of falling back to vault root.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:05:10 -07:00
Zero Liu
4e8c604efb
feat(agent-mode): teach backends about @-mention pill syntax (#2498)
* feat(agent-mode): teach backends about @-mention pill syntax

The chat editor serializes @-mention pills to `[[note]]`, `{folder}`, and
`{activeNote}` tokens, but only `[[note]]` was understood — the others
were literal strings to the agent. Add a shared pill-syntax directive
appended to opencode, codex, and claude SDK spawn-time instructions
(mirroring the existing skill-creation directive plumbing), and resolve
`{activeNote}` to the real `[[Note Title]]` at send time since the active
file is a client-side concept the agent can't query.

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

* chore(agent-mode): prune narration comments from pill-syntax change

Cut multi-line JSDoc and inline rationale that explained WHAT or referenced
callers, per the project's "one short line max, only WHY" rule.

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

* fix(agent-mode): preserve extension when resolving {activeNote}

Non-markdown active files (.pdf, .canvas) lost their extension when
{activeNote} was rewritten via activeFile.basename, leaving the agent
with an ambiguous [[name]] that didn't match the path the pill envelope
carries. Mirror NotePillNode.getTextContent's extension-aware
serialization so the inline token matches.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:32:49 -07:00
Zero Liu
898c31ac1b
fix(agent-mode): reject invalid env variable names before commit (#2502)
`rowsToRecord` was persisting every non-empty trimmed key, so names
failing `ENV_VAR_NAME_RE` (e.g. `BAD KEY`, `FOO=BAR`) flowed through
`onChange` into settings and were applied verbatim by backend spawn
paths, which read `envOverrides` directly without re-sanitizing.
Filter invalid rows at the commit boundary so the persisted record
and subprocess env only contain valid POSIX identifiers.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:28:13 -07:00
Zero Liu
cdcd9bb601
fix(skills): allow assigning Claude-only skills to any agent (#2501)
Codex (and other non-Claude agents) silently ignore the Claude-only
frontmatter flags (`disable-model-invocation`, `user-invocable`,
`model`), so hard-disabling their toggles on those skills was overly
restrictive. The inline chips on the row already communicate which
flags are Claude-specific.
2026-05-20 23:02:20 -07:00
Zero Liu
c39b9bf44c
feat(agent-mode): per-backend env variable overrides (#2499)
Adds an "Environment variables" editor to each Agent Mode backend
(Claude, Codex, opencode) so users can inject vars like
CLAUDE_CONFIG_DIR, CODEX_HOME, XDG_CONFIG_HOME, or HTTPS_PROXY without
polluting the parent shell. Overrides are merged onto process.env at
spawn (Codex, opencode) or per prompt() (Claude SDK), and persisted
through a shared sanitizer that enforces POSIX-style names, drops
control chars, and caps the record at 64 entries. The editor debounces
commits to avoid rewriting settings on every keystroke.

Also relocates BinaryPathSetting into src/agentMode/backends/shared/
to honor the agent-mode layer boundaries.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:58:57 -07:00
Zero Liu
1c0a750b31
fix(agent-mode): apply status-bar clearance padding to agent chat view (#2497) 2026-05-20 22:31:51 -07:00
Zero Liu
c4b92fcb16
feat(agent-mode): inline tool permission cards in chat (#2493)
Replace the modal-based permission prompter with inline ToolPermissionCard
rendered at the tail of the chat scroll, matching how plan proposals already
work. Refactor AgentSession status to be derived from underlying primitives
(resolver maps, abortController, etc.) so it cannot drift from reality, and
add tests covering the awaiting_permission lifecycle and turn-error reset.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
f53672d091
fix(agent-mode): make tool-card verbs status-aware (#2491)
Replaces the brief "Read Read" / "Edited Edit" flash that appeared while
a tool call's input JSON was still streaming. `targetFromTitle` now
returns an ellipsis when the title is just the vendor tool name (the
SDK's documented placeholder state), and a new `verb()` helper picks the
present-participle form for pending/in_progress calls and the past-tense
form for completed/failed ones — so cards read "Reading notes/foo.md" →
"Read notes/foo.md", "Fetching url" → "Fetched url", etc.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
a3c4c583cf
docs(design): refine model management redesign + add Quick Chat follow-up (#2490)
- MODEL_MANAGEMENT_REDESIGN.md: BYOK is now the central, user-bring-only
  registry; drop per-model and per-provider Availability/Capability toggles;
  one global table with provider section rows; Quick Chat added as a 4th
  agent sub-tab; OpenCode/Plus models stay in the Agent panel only.
- QUICK_CHAT_AGENT_INTEGRATION.md (new): follow-up plan for elevating
  LangChain chat into a first-class agent backend (routing service, session
  adapter, v2->v3 settings migration, milestones Q1-Q6).
- AGENT_MODE_TODOS.md: mark shipped items; add notes for opencode/local
  models and subscription-based opencode flows.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
9263f9ae11
Stop persisting agent mode selection (#2487)
* Stop persisting agent mode selection

* Force canonical default mode on every new agent session

Restore `applyPersistedMode` as a small coerce helper and wire it back
into every backend's `applyInitialSessionConfig` with a literal
`"default"` — never reading from settings. Codex-acp's natural starting
native mode is `read-only` (canonical `plan`), so without this the
picker landed on Plan on every fresh chat.

For codex specifically, also pin the spawn-time approval/sandbox config
via `-c approval_policy="on-request"` and `-c sandbox_mode="workspace-write"`
so codex-acp's first `currentModeId` already matches the canonical `auto`
preset. Without these, the picker briefly flashed "Plan" before the
post-spawn coerce switched it.

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

* Drop redundant post-spawn mode coerce

The codex picker briefly flashing "Plan" was fixed at the spawn level
(`-c approval_policy/sandbox_mode` in CodexBackend). Claude's SDK and
opencode's spawn-time `default_agent` already start in canonical
`default`, so the runtime `applyPersistedMode(session, "default")`
calls on all three backends were dead defense-in-depth. Remove them
along with the now-unused helper.

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

* Drop stale type-only import comment in settings/model.ts

`import type` is erased at runtime, so there's no actual cycle to
guard against — the keyword itself already signals "type-only" to
any reader.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
122dd4adf5
fix(agent-mode): keep mode picker visible while generating (#2489)
Hoist the agent-mode picker out of the not-generating branch so users
can flip between Auto/Plan/Safe mid-turn instead of having to wait for
the agent to stop. Non-agent chats are unaffected since they don't
pass modePickerOverride.
2026-05-20 19:05:41 -07:00
Zero Liu
0f03c41742
docs(design): add Model Management redesign handoff doc (#2488)
Consolidates the three duplicated model configuration surfaces (basic
settings keys, Models settings table, agent mode curation) into a
single design for product designer handoff. Covers unified Models
panel, agent-first onboarding with three paths, per-backend defaults,
and OpenCode/Copilot Plus as system-managed sections.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
0ebbc73424
fix(agent-mode): disable mode/model picker while session is starting (#2485)
* fix(agent-mode): queue mode/model switch while session is still starting

* fix(agent-mode): disable picker while session is starting instead of queueing

Replace the await-session.ready queueing approach with a UI-level gate:
canSwitchModel/Effort/Mode now return false while status === "starting",
so the picker renders as disabled until the backend session is ready.
The await-during-onChange path made the picker feel buggy because clicks
appeared to do nothing for a beat before applying.

* fix(agent-mode): re-render mode/model picker on session status change

The picker hooks compute a memoization signal that React diffs to decide
when to rebuild the override. Status was not part of the signal, so the
starting → idle transition fired listeners but the snapshot string was
unchanged and the picker stayed disabled forever. Include `getStatus()`
in both signals so the picker re-enables once the session is ready.
2026-05-20 19:05:41 -07:00
Zero Liu
ad4bd759a0
feat(agent-mode): tint chat input border and mode picker by mode (#2486)
* feat(agent-mode): tint chat input border and mode picker by mode

Plan mode shows a blue border and soft glow; auto mode shows red.
The mode picker label picks up a matching faded color that brightens
on hover/focus, making the active agent mode obvious at a glance.

* fix(agent-mode): preserve mode tint on keyboard focus

The ghost2 button variant applies focus-visible:tw-text-normal, which
overrode the focus: tint on keyboard focus. Switch to focus-visible:
so tailwind-merge resolves the conflict in favor of the mode color.
2026-05-20 19:05:41 -07:00
Zero Liu
c9ea0f7e1c
fix(agent-mode): preserve persisted enabled flag on mobile (#2484)
* fix(agent-mode): preserve persisted enabled flag on mobile

Sanitization no longer force-overrides agentMode.enabled on mobile, so
a desktop-synced preference is not silently overwritten the next time
mobile persists settings. Mobile gating now lives at usage sites via a
shared isAgentModeEnabled / useIsAgentModeEnabled helper.

* fix(lint): drop unused Platform import in commands/index.ts

The remaining `Platform.isDesktopApp` site uses a dynamic import that
shadows the top-level binding, so the static import is unused after the
agent-mode gating refactor.
2026-05-20 19:05:41 -07:00
Zero Liu
c722d0d9eb
Support agent image and PDF context (#2483)
* Support agent image and PDF prompt context

* Use agent read for PDF context
2026-05-20 19:05:41 -07:00
Zero Liu
02b9ac31c9
Add agent chat autosave resume support (#2482) 2026-05-20 19:05:41 -07:00
Zero Liu
e0c166ac0f
feat(agent-mode): enable by default on desktop, force off on mobile (#2481)
New installs now start with Agent Mode on. Mobile is locked off at the
sanitizer level so a desktop-synced settings file can't activate the
unsupported subprocess flow.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
1205a34612
fix(agent-mode): make binary auto-detect work under Obsidian's sparse GUI PATH (#2480)
macOS GUI apps launched from Finder/Dock inherit a minimal launchd PATH
(`/usr/bin:/bin:/usr/sbin:/sbin`) that omits Homebrew and user install
prefixes, so `which codex-acp` returned nothing and the Auto-detect button
falsely reported "not found." Augment PATH with the well-known prefixes
(`/opt/homebrew/bin`, `/usr/local/bin`) before invoking `which`, sharing
one source of truth with the existing spawn-time augmentation in
`nodeShebangPath`. For Claude, the Auto-detect button now routes through
the existing `resolveClaudeBinary` resolver (Volta/asdf/NVM/Homebrew/
npm-global/`~/.local/bin`) via a new optional `detect` prop on
`BinaryPathSetting`, matching the candidate list already used by the top
status row.
2026-05-20 19:05:41 -07:00
Zero Liu
9b5151533e
feat(agent-mode): reveal full bash command on action card expand (#2479)
Bash tool calls collapse the command to 60 chars in the trail, which is
correct for noise but left the full command unreachable. Add an optional
`expandedDetails` hook on `ToolSummary` and implement it for Bash so
clicking the card surfaces the full command (with `# description`
prefix when present). Drop the `!inline` expand restriction so commands
inside an `AggregateCard` are individually expandable too.

Also adds an AGENTS.md rule requiring `cn()` around any Tailwind class
string that lives outside a literal JSX `className=` attribute so
`eslint-plugin-tailwindcss` actually lints them, and refactors
ActionCard's class composition to follow it.

Includes two unrelated micro-edits already in the working tree:
trailing-whitespace fix in chatModelManager.ts and a stale TODO removal
in AGENT_MODE_TODOS.md.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
c2ac27edef
feat(agent-mode): introduce Agent Mode feature
Squashed from 8 commits on zero/acp-test:
- feat(agent-mode): introduce Agent Mode feature (squashed)
- Fix eslint
- hide add context button
- chore: ban parent-relative imports and rewrite existing ones to @/ aliases
- wip(agent-mode): skills management + slash command revamp
- fix(agent-mode): initialize SkillManager before preload probes
- fix(build): align svgr jsxRuntime with tsconfig classic jsx
- fix(test): stub ItemView/WorkspaceLeaf in ChatSingleMessage obsidian mock
2026-05-20 19:05:41 -07:00
Logan Yang
bd8829f538
release: v3.3.3 (#2494) 2026-05-20 18:27:22 -07:00