Commit graph

57 commits

Author SHA1 Message Date
Richard McCorkle
8800b98df4 fix(lint): carve out window timer calls in prefer-active-doc rule
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>
2026-05-17 07:48:09 +02:00
Richard McCorkle
7458806dde Merge eslint-upgrade: bump eslint-plugin-obsidianmd to 0.3.0
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 07:38:31 +02:00
Richard McCorkle
8311ee1fb8 chore: upgrade eslint-plugin-obsidianmd to 0.3.0, fix resulting lint errors
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>
2026-05-17 07:38:12 +02:00
Richard McCorkle
5c00e60f23 Merge ui-native-alignment: native Obsidian UI alignment
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>
2026-05-17 07:18:34 +02:00
Richard McCorkle
dfcfdcc77d refactor(ui): align styles.css to Obsidian theme variables and spacing scale
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 07:15:03 +02:00
Richard McCorkle
dc36057bb8 refactor(ui): use native Obsidian toggle for license acceptance in settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 06:57:28 +02:00
Richard McCorkle
088374687d refactor(ui): use native Obsidian toggle and CTA button in create-note modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 06:47:43 +02:00
Richard McCorkle
015784ed0c docs: add UI native-alignment implementation plan
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 06:43:03 +02:00
Richard McCorkle
bdbd25b855 chore: ignore .worktrees/ directory
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 06:41:48 +02:00
Richard McCorkle
fe7cea610a Merge secret-storage: cloud API keys in Obsidian secret storage
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.
2026-05-16 23:07:21 +02:00
Richard McCorkle
01755dc6c4 chore: bump to 1.3.0, require Obsidian 1.11.4 for secret storage 2026-05-16 23:06:46 +02:00
Richard McCorkle
4e9c3a328d feat: store cloud API keys in Obsidian secret storage 2026-05-16 23:06:46 +02:00
Richard McCorkle
75cc41fde5 Merge processing-spinner: Braille spinner replacing CSS pulse
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.
2026-05-16 22:51:44 +02:00
Richard McCorkle
a0165d0bc5 chore: sync package-lock.json version field to 1.2.28 2026-05-16 22:51:19 +02:00
Richard McCorkle
75e370d607 fix: remove pulse-bar CSS, add tubesage-spinner rule 2026-05-16 22:51:00 +02:00
Richard McCorkle
82acdb2d73 feat: use ProcessingSpinner in collection and single-video flows 2026-05-16 22:51:00 +02:00
Richard McCorkle
185372a25e feat: add platform-aware ProcessingSpinner (Braille status-bar / in-modal) 2026-05-16 22:51:00 +02:00
Richard McCorkle
470a1b587f docs: add processing-spinner implementation plan 2026-05-16 22:45:57 +02:00
Richard McCorkle
ef3087cd70 Merge Phase 2: CSS !important removal, :has() fix, release.yml doc-alignment
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).
2026-05-16 22:39:53 +02:00
Richard McCorkle
f9cc10c4dd docs: add secret-storage API keys implementation plan 2026-05-16 22:33:33 +02:00
Richard McCorkle
6d82efdf53 docs: refine secret-storage spec to keep apiKeys as runtime field (lower blast radius) 2026-05-16 22:32:13 +02:00
Richard McCorkle
cde8a4e98e docs: add secret-storage API keys design spec 2026-05-16 22:27:04 +02:00
Richard McCorkle
2b3869e7d4 fix: remove all !important from styles.css, raise specificity where needed 2026-05-16 21:42:51 +02:00
Richard McCorkle
74659b4187 fix: replace CSS :has() with a class set on the setting-item in main.ts 2026-05-16 21:38:54 +02:00
Richard McCorkle
8d1d9c3ea9 ci: align release workflow with Obsidian docs (publish directly, canonical assets, tag/manifest check) 2026-05-16 21:34:52 +02:00
Richard McCorkle
a4394a08fa docs: add Obsidian review remediation plan and design specs 2026-05-16 21:25:01 +02:00
Richard McCorkle
c483cd2a5f Merge Phase 1: Obsidian Community Portal review remediation
Clears 10 of ~15 review findings for v1.2.28: LICENSE file, fetch-shim
type assertion, CSS dedupe + shorthand, npm ci + artifact attestation,
de-promoted README, langsmith disclosure, version bump.
2026-05-16 21:24:42 +02:00
Richard McCorkle
ef150f0b85 fix: add trailing newline to LICENSE file 2026-05-16 21:23:27 +02:00
Richard McCorkle
1da27ff151 chore: bump version to 1.2.28 2026-05-16 21:19:15 +02:00
Richard McCorkle
250ccb0f6b docs: de-promote README, fix license link, disclose bundled langsmith timer 2026-05-16 21:19:15 +02:00
Richard McCorkle
dc6467d217 ci: use npm ci for reproducible builds and add artifact attestation 2026-05-16 21:19:15 +02:00
Richard McCorkle
1c9c11faff fix: dedupe CSS selectors and redundant margin shorthand 2026-05-16 21:19:15 +02:00
Richard McCorkle
8aa1406ffe fix: remove unnecessary type assertion in fetch-shim 2026-05-16 21:19:15 +02:00
Richard McCorkle
7bd9542441 chore: add standard LICENSE file for GitHub license detection 2026-05-16 21:19:15 +02:00
Richard McCorkle
fa4b953179 chore: add archon graph+superpowers workflows (local worktree, no PR)
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>
2026-05-14 17:13:10 +02:00
Richard McCorkle
49efdcf83d fix: bump langsmith override to >=0.6.0 to resolve Dependabot alert #67
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>
2026-05-13 21:27:34 +02:00
Richard McCorkle
ef46a30070 Merge branch 'worktree-feat-openrouter-provider'
Add OpenRouter as a fifth LLM provider for summary and timestamps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:25:07 +02:00
Richard McCorkle
2e5e2aefa8 feat: add OpenRouter as a fifth LLM provider for summary and timestamps
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>
2026-05-13 21:23:49 +02:00
Richard McCorkle
1b043d0723 fix: improve timeout error message and detect Gemini DEADLINE_EXCEEDED
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>
2026-05-10 13:37:09 +02:00
Richard McCorkle
17d142d9b7 fix: override fast-uri to >=3.1.2 to resolve Dependabot alerts #65 and #66
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>
2026-05-09 12:54:02 +02:00
Richard McCorkle
e6b83b7e23 fix: trim parenthetical from summary-failed notice text
Keep reasoning in logger.info only; user-visible notice is now concise.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 12:52:08 +02:00
Richard McCorkle
6e03b8e470 fix: stop pipeline at summary failure instead of attempting timestamp pass
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>
2026-05-06 22:21:41 +02:00
Richard McCorkle
20745b57e7 chore: add Codex agent configuration
- 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>
2026-05-06 00:34:46 +02:00
Richard McCorkle
fa56e33284 chore: switch graph:update to bare-path form
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>
2026-05-04 15:22:36 +02:00
Richard McCorkle
7193541aac chore: add fallow audit and graphify update npm scripts
- 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>
2026-05-04 13:12:06 +02:00
Richard McCorkle
a10c620a29 chore: update .gitignore to exclude graphify generated artefacts
Ignore src/graphify-out graph.html, cache/, .graphify_root, .graphify_python
— all regenerated by post-commit hook, not source files.
2026-05-03 15:52:19 +02:00
Richard McCorkle
9338b51960 Bump to 1.2.27: restore uppercase API in UI strings
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>
2026-05-02 09:44:30 +02:00
Richard McCorkle
00023fbfcf ci: skip workflow draft if release already exists for tag
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>
2026-05-02 09:06:46 +02:00
Richard McCorkle
49680c6267 Bump to 1.2.26: lowercase API in UI strings for ObsidianReviewBot
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>
2026-05-02 08:59:33 +02:00
Richard McCorkle
2d7b2437d8 Bump to 1.2.25: fallow audit, lint cleanup, sentence-case UI fixes
- Removed 25 unused exports + 11 unused dependencies via fallow
  (build verified, runtime behavior unchanged)
- ESLint config now ignores graphify-out/, .fallowrc.json, .mcp.json,
  .fallow/ — eliminates 69 phantom JSON-parse errors
- Lint cleanup: deleted dead function bodies, prefixed unused args
  with underscore (npm run lint passes 0/0 on src/utils + src/llm)
- UI string fixes for ObsidianReviewBot:
  - 'YouTube' -> 'Youtube' (split compound brand)
  - 'Scrapecreators' -> 'Scrape creators' (split compound brand)
  - 'Supadata' -> 'Supa data' (split compound brand)
  - 'OpenAI' -> 'Openai' (drop camelCase)
  - 'OAUTH' -> 'oauth' (lowercase acronym)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:00:41 +02:00