The local prefer-active-doc rule flagged every `window` identifier as
preferring `activeWindow`. obsidianmd 0.3.0's new `prefer-window-timers`
rule requires the opposite for timer calls (`window.setTimeout` etc.),
so the two rules contradicted, leaving 11 unfixable warnings.
Add a `window.<timerMethod>` carve-out to the local rule, mirroring the
same exception in upstream eslint-plugin-obsidianmd's prefer-active-doc.
Lint now reports 0 warnings (4 errors remain: intentional brand-name
casing left per project decision).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bump eslint-plugin-obsidianmd 0.2.9 -> 0.3.0 and typescript-eslint
8.58.2 -> 8.59.3. ESLint stays at 9.39.4: obsidianmd 0.3.0 peer-pins
@eslint/js ^9 and @eslint/json 0.14.0, so ESLint 10 is not yet
cleanly supported.
obsidianmd 0.3.0 adds two new rules. Fixes for the errors they raise:
- no-unnecessary-type-assertion: remove 4 redundant type assertions
(main.ts x3, fetch-shim.ts x1) - all compile-time-only, tsc confirms.
- prefer-window-timers: switch 11 activeWindow timer calls to window
(main.ts, form-utils.ts, processing-spinner.ts). TubeSage has no
popout-window feature, so window === activeWindow at every call site.
Note: obsidianmd 0.3.0's prefer-active-doc rule (warning) now flags
window.* as preferring activeWindow, directly contradicting the
error-level prefer-window-timers rule. window.* is kept because it
satisfies the error-level rule; the 11 advisory warnings are an
upstream rule conflict and cannot be resolved without suppression.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace hand-rolled toggle switches and process button with native
Obsidian components, eliminate JS-set inline styles, and align styles.css
to Obsidian theme variables and spacing scale.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cloud-provider keys (OpenAI/Anthropic/Google/OpenRouter) move out of the
plaintext data.json into app.secretStorage, with a one-time migration that
scrubs existing keys. Bumps to 1.3.0; minAppVersion 1.2.0 -> 1.11.4.
Desktop gets a status-bar Braille spinner (adapted from TubeSage-Wiki-Pro);
mobile gets an in-modal Braille spinner (no status bar on mobile). The CSS
pulse-bar animation is removed.
Visual check passed. Removes all 85 !important from styles.css (specificity
bumps where needed), replaces :has() with a class set in main.ts, and aligns
release.yml with the Obsidian docs (publish directly, canonical assets).
Add two project-scoped Archon workflows that combine codebase context
from graphify, Superpowers skills on plan/implement/validate/finish
nodes, and a local merge-back step instead of GitHub PR ceremony:
- archon-graph-superpowers-feature: for net-new features/requirements
- archon-graph-superpowers-fix-issue: for GitHub issues / bugs
Each workflow runs in an Archon-managed git worktree, pulls graph
context via `graphify query` before planning, refreshes `graphify-out/
graph.json` after delivery, then merges the worktree's branch back
into `main` locally. No remote push, no PR, no PR-based review pipeline.
Design spec: docs/superpowers/specs/2026-05-14-archon-graphified-workflows-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
langsmith 0.5.26 (transitive via @langchain/core) is vulnerable to
GHSA-3644-q5cj-c5c7 (public prompt pull deserializes untrusted manifests
without trust boundary warning). Patched in 0.6.0.
The previous override was pinning to ^0.5.18 which kept the vulnerable
0.5.x line — relaxed to >=0.6.0. Resolves to 0.6.3.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OpenRouter exposes an OpenAI-compatible Chat Completions API, so reuse the
existing @langchain/openai ChatOpenAI client with a custom baseURL —
no new SDK required. The obsidianFetch shim continues to apply through
getLangChainConfiguration, preserving cross-platform (mobile) support.
Changes:
- model-limits-registry: add 'openrouter' to Provider union; seed registry
with curated namespaced models (openai/gpt-4o, anthropic/claude-3.5-sonnet,
google/gemini-2.5-flash, meta-llama/llama-3.1-70b-instruct, etc.)
- langchain-client: new 'openrouter' switch case mirroring the OpenAI path
but routing to https://openrouter.ai/api/v1 with the recommended
HTTP-Referer and X-Title attribution headers
- main.ts: wire openrouter into DEFAULT_SETTINGS (apiKey, selectedModel,
fetchedModels), getModelForProvider fallback, provider dropdown, and the
providerCatalog UI block with the same shape as the other providers
Both the summary pass and the timestamp-linking pass dispatch through the
same LangChainClient, so OpenRouter is available for both automatically.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: for 2hr+ transcripts, the Gemini API returns a server-side
DEADLINE_EXCEEDED (504) — not a client-side timeout. The error was being
categorised as a generic timeout and the message told the user to "try again",
which is misleading since retrying the same large transcript will fail again.
Changes:
- error-utils: catch DEADLINE_EXCEEDED/deadline exceeded as Timeout category
- error-utils: replace "try again" timeout message with actionable advice
(try shorter video, reduce max tokens, or switch model)
- gemini-client: log full error body for easier debugging; surface gRPC
status code in error message; throw DEADLINE_EXCEEDED prefix on 504 so
upstream categorisation is unambiguous
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fast-uri 3.1.0 (transitive via eslint-plugin-obsidianmd → ajv) is
vulnerable to path traversal and host confusion via percent-encoded
segments. Pinned to 3.1.2 via npm overrides.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When summarizeTranscript() fails (transcript skip, empty result, or
thrown error), the existing flow created the note with a SUMMARY FAILED
placeholder and then tried addSectionLinksToNote — which calls the same
LLM for timestamp linking. If the summary failed for any reason (rate
limit, network, auth, model error), the timestamp pass was almost
certain to fail the same way: wasted tokens, wasted latency, second
user-facing error.
Track a summaryFailed flag through all three failure paths and gate the
timestamp pass on !summaryFailed in addition to !transcriptFailed. Note
is still created with the failure marker so the user keeps the
transcript and gets a clear signal.
The collection-flow pipeline (~line 3240) was already implicitly
correct: summarizeTranscript() throwing aborts the whole video via the
outer try, so no separate fix needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- AGENTS.md: Codex-equivalent of CLAUDE.md (project architecture,
development directives, graphify integration rules)
- .codex/config.toml: register fallow MCP server for Codex sessions
Mirrors the Claude Code setup so the project is fully usable from
either coding assistant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligns with graphify skill convention 'graphify <path> --update'
documented in lucasrosati/claude-code-memory-setup guide.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- postbuild: auto-run fallow audit after every build
- audit:fallow: standalone audit against main branch
- graph:update: refresh graphify knowledge graph
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverting the lowercase 'api' from 1.2.26 — local
obsidianmd/ui/sentence-case rule wants uppercase 'API'. Local
linter is the bot's scanner, so aligning UI strings with what the
linter accepts is the correct path through bot review.
Lines 4072, 4073, 4106, 4134: 'api key' -> 'API key'.
Line 4222 keeps 'Openai' (no change).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prevents duplicate draft releases when gh release create is run
manually before the workflow fires on tag push.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bot has been rejecting uppercase 'API' acronym casing in UI
strings; reverting to lowercase 'api' across the four bot-flagged
setting names and the description string. The local
obsidianmd/ui/sentence-case rule expects uppercase 'API', so 4
lint errors are expected on these lines and are NOT suppressed —
the bot is the authority we are trying to satisfy.
- 'Youtube data API key' -> 'Youtube data api key'
- 'Scrape creators API key' -> 'Scrape creators api key'
- 'Supa data API key' -> 'Supa data api key'
- 'Your Google cloud console API key for accessing public Youtube
transcripts...' -> '...console api key for accessing public Youtube
transcripts...'
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>