Detaching a method via `const fn = obj.method` loses its `this`
context. Replaced with Reflect.apply(fn, s, args) so the Obsidian
Settings object's internal `this.app` reference stays intact.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Resolves all Required issues flagged by the Obsidian community plugin
review bot:
- Replace explicit `any` types with typed interfaces and intersection
types across providers, tools, UI components, and services
- Remove `async` from functions/methods with no `await`; return
Promise.resolve() where the interface demands Promise<string>
- Replace `fetch` bare global with `window.fetch` and remove
eslint-disable comments for no-restricted-globals
- Replace `globalThis.fetch` with `window.fetch` (prefer-active-doc)
- Replace string literal style assignments with template literals to
satisfy no-static-styles-assignment; remove disable comments
- Fix sentence case: "Apply all" / "Reject all" in en.json
- Change default chats folder migration to use regex instead of
hardcoded .obsidian/ path literal (hardcoded-config-path)
- Remove unnecessary type assertion in migrateSettings
- Remove await from non-Promise listFolder call (await-thenable)
- Add argsIgnorePattern to no-unused-vars in eslint.config.mjs
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Migrate to ESLint v9 flat config, integrate obsidianmd plugin, fix all
required errors (prefer-active-window-timers, no-tfile-tfolder-cast,
no-unsupported-api, floating promises, etc.), and bump minAppVersion to
1.7.2 to match revealLeaf API requirement.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Adds required disclosures (account, payment, network use) to README and
README-cn.md per Obsidian developer policies.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
- Plugin id/name updated to obsidian-note-agent (Bin-Home)
- Class renamed ObsidianAgentPlugin → ObsidianNoteAgentPlugin throughout
- VIEW_TYPE and default chatsFolder path updated to match new id
- Status bar and provider indicator button now use activeProfile() so
the default model name shows instead of "-" when no override is set
- Indicator button separator changed from " / " to ":" to match status bar
- Add README.md and README-cn.md
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
- Add user-profile "About Me" setting injected into every system prompt
- Chat history moved to .obsidian/plugins/obsidian-agent/chats (hidden from vault); auto-purge after 30 days
- Fix ApprovalQueue stuck state: re-insert entry on commit failure, always emit
- Fix list_folder returning only .md files (getMarkdownFiles → getFiles)
- Add auto-approve toggle in Edit mode: auto-commits writes, backs up originals to __auto_backup__/{timestamp}/{path}, shows Notice per backup
- Update DeepSeek default model to deepseek-v4-pro
- Build outputs to dist/ (main.js, styles.css, manifest.json); remove root build artifacts
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Translates remaining hardcoded UI strings — chat shell, conversation
history drawer, diff review, mode toggle, settings tab — and adds a
parity test so en.json and zh-CN.json key sets stay in lockstep.
Conversation list now uses sentinel group keys for ordering and
Intl.DateTimeFormat for locale-aware date rows.
Each provider now has its own apiKey / baseUrl / model stored under
settings.providers[id]. Switching providers no longer clobbers the
other one's credentials. Base URL shows the provider's default as
placeholder (empty = use default), and migrateSettings folds legacy
flat fields into the active provider's profile.
Also: API key input no longer masked, key/URL/model/chats-folder
inputs widened to a uniform half-row width, and chatsFolder changes
now apply without a reload.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Replaces the simple token-budget trimmer with a ContextManager that derives
budgets from per-model context windows, auto-compacts older turns into a
rolling summary once pressure crosses a threshold, and exposes a stable
prefix boundary so providers with prompt caching (Anthropic) can reuse it.
Adds a "compacting" status in the UI and persists the summary alongside the
conversation.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
- Agent loop no longer awaits per-write approval; queues pending writes
and returns { status: "queued" } to the LLM so multi-step edits finish
in one turn. Diffs render inline under the assistant message that
produced them, with per-block Approve/Reject and a bulk Apply All /
Reject All footer.
- ApprovalQueue rewritten as a synchronous pending-writes store with an
injected commit callback; clear() drops unresolved writes on view
close or new conversation; scheduled (no-UI) runs auto-approveAll
after the loop drains.
- history-trimmer keeps assistant-with-tool_calls + its tool responses
as one atomic group so the provider never sees a tool message without
its preceding tool_calls (fixes DeepSeek 400 on large tool bursts).
- Add pulsing thinking-dots indicator in MessageList whenever the turn
is busy and streamBuf is empty, covering network latency, tool-call
argument accumulation, and inter-iteration gaps.
- Drop [openai] console logs (errors/warns retained); remove superfluous
aria-labels and title tooltips from chat UI.
- Add CLAUDE.md.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
conversation.model was set at conversation creation time and never
updated. Changing the model in settings had no effect until a new
conversation was started. Now sendMessage reads the current settings
before each request, so changes apply immediately.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
1. User message now appears immediately on send, before the first
network response arrives (optimistic update before the for-await loop).
2. Streaming response renders as formatted markdown in real-time using
the same use:markdown action as finished messages. The version-guard
in markdown-action.ts handles rapid updates without race conditions.
Removed the redundant messages sync on every text chunk — streamBuf
alone drives the live view, cutting unnecessary re-renders.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
- Default turnTimeoutMs: 120s → 300s (5min). With retry backoff sleep
up to 75s + a slow GLM response the old 120s was routinely exceeded.
- Timeout now yields a visible error instead of silently stopping:
distinguishes DOMException AbortError (timeout) from user cancel.
- Adds "Request timeout (seconds)" field in plugin settings so users
can tune it without touching code.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
1. Text selection: override Obsidian's global `user-select: none` on `*`
with `user-select: text` on `.ml-root` and all its descendants.
Buttons remain non-selectable.
2. Tool results: instead of just "tool result", each row now shows:
- tool name (accent color)
- first argument value as a hint (e.g. the search query)
- result preview (e.g. "5 notes", "no results", "error: …")
Hovering shows the full raw result in a tooltip.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Both httpSSE (streaming) and httpJson now automatically retry up to 4
times when the provider responds with 429. Delays: 5s → 10s → 20s → 40s,
capped at 60s; respects Retry-After header when present.
Also fixes the agent loop to treat an AbortError during retry sleep as a
clean cancellation (stopped) rather than an error.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Zhipu (and other providers) return JSON bodies on 429. Extract the
human-readable .error.message instead of dumping raw JSON to the user.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Errors on the second LLM call (after a tool result) were being silently
wiped: ChatView's finally block overwrote `messages` with conversation
history, which doesn't include the transient error message. Fix tracks
the error in a local variable and re-appends it after the finally sync.
Also adds console.debug/warn/error throughout the agent loop so errors
are visible in Obsidian DevTools (Ctrl+Shift+I → Console).
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
esbuild writes Svelte CSS to main.css but Obsidian only reads styles.css
from the plugin folder. Copy main.css → styles.css after every build so
the redesigned component styles are actually loaded at runtime.
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>