Commit graph

107 commits

Author SHA1 Message Date
wujunchen
7cb68658f5 refactor: split modules.test.js into 12 per-module test files
Replaces the monolithic modules.test.js (983 lines) with focused
per-module test files sharing a common test-setup.js. Each file is
under 225 lines. All existing test assertions preserved.

New files: test-setup.js, anchor.test.js, schema.test.js, cache.test.js,
cards-nav.test.js, markdown.test.js, vault-batch.test.js, i18n.test.js,
scroll.test.js, settings.test.js, providers.test.js, streaming.test.js,
cli.test.js

Change-Id: I37a3342a1588807277e679e6535cde361e650565
2026-04-27 15:21:03 +08:00
wujunchen
62f99718f6 refactor: extract API_PROVIDER_PRESETS to provider-presets.ts
Moves 18 provider preset definitions (148 lines) from settings.ts into
a dedicated provider-presets.ts file. settings.ts reduced from 443 to
297 lines, now contains only utility functions and non-preset constants.

Change-Id: Ia9a1ef48854ab79cb405df9cd1f88d19826317d6
2026-04-27 15:15:23 +08:00
wujunchen
15b471efad refactor: extract i18n translation strings to dedicated i18n-strings.ts
Moves the STRINGS object (330 lines of zh/en translations) from i18n.ts
into a separate i18n-strings.ts file. i18n.ts now contains only the
resolveUiLanguage and translate logic (28 lines).

Change-Id: I9ddea79bddb4e8313dc16aae2a7c8d4eeff96fe1
2026-04-27 15:13:31 +08:00
fancivez
f4e0d84a9c refactor: replace magic numbers in scroll.ts with named constants
Add DEFAULT_MAX_OFFSET_PX (80), DEFAULT_PROBE_RATIO (0.1), and
FALLBACK_FRAME_MS (16) to document the purpose of each value.

Change-Id: Ie34d61c290384de81ae001f292e89f17b410e701
2026-04-27 14:11:37 +08:00
fancivez
be8a424d42 chore: upgrade biome noNonNullAssertion from warn to error
No violations exist in the codebase, so this prevents future regressions.

Change-Id: I2e5fa7fea867f1ad5752e48d277a03ce6d9560d7
2026-04-27 14:11:37 +08:00
fancivez
3338c80311 refactor: extract runForFile error handler and streaming callback
Split runForFile into focused methods: handleGenerationError for the
catch block and streamProgressFor for streaming callback creation.
Reduces runForFile from 91 to ~55 lines with clearer separation.

Change-Id: Icb0195092f25ab640f8227834a96519d14cab8df
2026-04-27 14:11:37 +08:00
fancivez
b2716da4ca test: add getApiKey, cacheEntryMatches, normalizeCardCount edge case tests
Cover normalizeCardCount boundary values (0, negative, NaN, max 30, string).
Test getApiKey with direct key, env var, precedence, and trimming.
Test cacheEntryMatches for valid match, null entry, wrong hash, wrong schema.

Change-Id: I1113d923885e03f6b28d47721cc303bbbb6d70ed
2026-04-27 14:11:37 +08:00
fancivez
bda21a0fb1 fix: replace unsafe (e as Error).message casts with instanceof guards
Fix 4 locations in providers.ts, cli.ts, and settings-tab.ts where error
objects were cast to Error without checking. Now uses proper instanceof
narrowing with String fallback for non-Error throwables.

Change-Id: Ib324380f5d56945672e32b9d3621855f6179186a
2026-04-27 14:11:37 +08:00
fancivez
5eb005f293 refactor: extract body builders and types to src/provider-bodies.ts
Move buildAnthropicMessagesBody, buildOpenAiChatBody, buildOpenAiResponsesBody,
buildGeminiBody, tokenLimitFieldForOpenAiChat and their type interfaces to a
new module. Reduces providers.ts from 494 to 367 lines (under 400 target).

Change-Id: Ib124d5cf5f2f66bac03acbf83e1a224cb6325d12
2026-04-27 14:11:37 +08:00
fancivez
c111865fbd test: add resolveCardAnchors unit tests
Cover sorting by startLine, unanchored cards pushed to end, empty/null
input, all-unanchored relative order, and default level value.

Change-Id: I74c48041897e8e4fb44555aaa319e6ebde8f91b1
2026-04-27 14:11:37 +08:00
fancivez
0ef6395ed7 test: add parseApiHeaders unit tests covering all input formats
Export parseApiHeaders for testing. Cover: JSON object input, empty/whitespace,
line-based input, comments/blank lines, malformed JSON, array input fallback,
missing colon, non-string JSON values filtered, colons in values preserved.

Change-Id: Ia00898888c6a0b78a284b43f29e382cc4080ba88
2026-04-27 14:11:37 +08:00
fancivez
ff08dbe3c2 fix: eliminate unsafe as-unknown-as casts in scroll.ts
Replace fragile double-casts with a branded ScheduleId wrapper that
unifies RAF (returns number) and setTimeout (returns Timeout) IDs
without losing type safety. The wrapper is opaque to callers.

Change-Id: I304d68b562ff803d0b20ebcbfb71a3c3d9e1d881
2026-04-27 14:11:37 +08:00
fancivez
5f8b3cfd86 chore: upgrade biome noImplicitAnyLet to error, fix parsed type in schema
Set noImplicitAnyLet to error in biome.json. Fix the violation in
parseCardsJson by typing the parsed variable as unknown. Widen
normalizeCardsPayload to accept unknown (it already handles non-object
input defensively). Remove now-unnecessary cast in provider-parsers.ts.

Change-Id: I57ee46d3179775d5d7c34f35803a44c45061b0ec
2026-04-27 14:11:37 +08:00
fancivez
c4f25a7957 style: fix import ordering and formatting per biome rules
Change-Id: I8cb97ba7c64bd56ae5408f7e8b6fdf882e832206
2026-04-27 14:11:37 +08:00
fancivez
3a2c4e6a1c test: add vault.ts normalizeVaultPath and folderPathsForTarget tests
Cover normalizeVaultPath with clean paths, whitespace trimming, parent
traversal stripping, dot segments, null input, and empty segments.
Test folderPathsForTarget ancestor chain generation for various depths.

Change-Id: I4de1744301df1e42d35f0bd5702d5cc58fb9a277
2026-04-27 14:11:37 +08:00
fancivez
d6b89924f2 test: add i18n translate and resolveUiLanguage unit tests
Cover translate() with explicit languages, variable interpolation (single,
multiple, numeric), missing keys, null settings, unmatched placeholders.
Test resolveUiLanguage for explicit/auto/null settings.
Validate zh/en STRINGS parity (same key count, no missing keys).

Change-Id: I06c3bdc9d824eaa0e205b335b9856d872a1aefd1
2026-04-27 14:11:37 +08:00
fancivez
1efacf695c test: add schema.ts edge case coverage for repair and JSON extraction
Test repairTruncatedCardsJson with whitespace variations, escaped quotes,
braces in string values, all-truncated cards, and empty arrays.
Add collectJsonObjectCandidates tests for empty input, nested objects,
braces in strings, and unclosed braces.

Change-Id: I82392bff6eaf457934dbbe63e7c5788ea6a44e19
2026-04-27 14:11:37 +08:00
fancivez
4f5e9e9923 refactor: extract card rendering and context menu from view.ts render()
Split the 160-line render() method into three focused methods:
- render(): orchestrates header, state, and card list (now ~60 lines)
- renderCard(): handles single card DOM creation with content and events
- showCardContextMenu(): builds the right-click context menu

Change-Id: I46f94e75d6aef1043ac905f1dc33c13cf4ae8447
2026-04-27 14:11:36 +08:00
fancivez
be8ad72ba2 test: add comprehensive parseSseBuffer and deltaExtractor tests
Cover SSE parsing edge cases: single/multiple events, incomplete buffers,
CRLF line endings, [DONE] sentinel, multi-line data fields, malformed JSON
skipping, comment/event lines, data: without trailing space, empty buffer.
Test both OpenAI and Anthropic delta extractors with various input shapes.

Change-Id: I108352e07233490d23b86ed31b855692c360d4d1
2026-04-27 14:11:36 +08:00
fancivez
4c4468dd85 fix: add logging to silent catch blocks in CLI, job manager, and main
Replace silent error swallowing with console.warn in:
- GenerationJobManager cancel handler errors
- CLI process kill failures (timeout and cancellation)
- CLI stdin close failures
Add descriptive comments to intentionally silent scroll-related catches.

Change-Id: I2ec8fda6ca92186ed2d4fc1560efffd0677f3bcd
2026-04-27 14:11:36 +08:00
fancivez
ba6e44194a refactor: extract batch folder prompt dialog to src/batch.ts
Move the inline Modal dialog for batch folder selection into a reusable
promptForBatchFolder function. Removes Modal import from main.ts.
main.ts now 775 lines.

Change-Id: I7a5c62b7df95635dcbe0ac814007838ff83eded4
2026-04-27 14:11:36 +08:00
fancivez
50a3c4bec3 refactor: extract resolveCardAnchors and confirmRegenerateEditedCards from main.ts
Move resolveCardAnchors to src/cards.ts and confirmRegenerateEditedCards
to src/modal.ts to reduce main.ts from 835 to 796 lines (under 800 target).

Change-Id: If38ed4e45c61658b7cc52a6283f8e0e24458761e
2026-04-27 14:11:36 +08:00
fancivez
b3d774f4df test: add provider-parsers edge case coverage
Test all parser functions with empty responses, missing fields, null inputs,
legacy format fallbacks, multi-block concatenation, and tool-use rejection
for wrong tool names and missing content arrays.

Change-Id: Ie3c15aa636a6b421ca6bf4315313368c249f2782
2026-04-27 14:11:36 +08:00
fancivez
f7c4f42a5a test: add comprehensive CacheManager unit test coverage
Cover previously untested methods: get(), move() (success/failure/edge
cases), readFile() with corrupt JSON and missing entries, pruneIfNeeded(),
replaceCards() for missing entries, and scheduleSave()+flush() behavior.

Change-Id: Iee71e574d37925c2111eb70a292d5f59a80dc3c5
2026-04-27 14:11:36 +08:00
wujunchen
185f4fd146 chore: bump version to 1.0.5
Change-Id: Iaa1c3718557ab936d10ebcc659c245a9ebb8f801
2026-04-27 13:02:11 +08:00
wujunchen
3082e4a7bb chore: rebuild main.js after engineering quality improvements
Change-Id: Id0249bc0c38a237ca085d59dae6eac6a56cb5548
2026-04-27 12:58:40 +08:00
wujunchen
538d7bcedd test: add structured output fallback and non-retryable error tests
Cover the two key paths in requestJsonBodyWithStructuredFallback:
1. 400 with response_format mention → retry without structured output
2. 500 server error → no retry, error propagated

Change-Id: If8d0fc484e49238699444131cbadcf1b18bf992f
2026-04-27 12:44:42 +08:00
wujunchen
67a9ccdafb test: add applyApiProviderPreset model swap coverage
Cover the key scenarios for provider switching: model swapped when
matching previous preset, custom model preserved across switches,
empty model triggers swap, and input immutability verified.

Change-Id: I467604d51e8c11e990e54621347094cf914cb6b7
2026-04-27 12:43:29 +08:00
wujunchen
bc1de37868 fix: remove unsafe fallback cast in CardEditModal constructor
The constructor always receives a validated ResolvedCard from the call
site (which guards with !this.sections[index]). The fallback to an
empty object cast as ResolvedCard was dead code that hid type safety.

Change-Id: I35c9731d9079b9aeea5eb0fda7eda46a740bc964
2026-04-27 12:41:13 +08:00
wujunchen
f635823499 fix: add error handling to fire-and-forget async patterns
Replace void-prefixed async calls with .catch() error logging in:
- onunload flush operations (settings + cache)
- file-open, rename, and delete event handlers
- settings-tab cache commit handler

Also await syncViewToFile in the open-view command where it was
unnecessarily fire-and-forget inside an already-async callback.

Change-Id: Ied1e88035b77a92a59c50ab6caef539a254c7787
2026-04-27 12:40:29 +08:00
wujunchen
f2e197453c fix: prevent modal confirmation promise from resolving twice
The regenerate confirmation modal's onClose callback fired after button
click handlers, calling resolve() a second time. While Promise.resolve
is idempotent, this was confusing. Added explicit settlement tracking
so the promise resolves exactly once regardless of how the modal closes.

Change-Id: Ief4cbb78f15fe220a20adaf8343d744ffa8c1653
2026-04-27 12:34:33 +08:00
wujunchen
b02d0f4f30 test: add cache pruning interleaved with put test
Verify that when a new entry is added via put() and the cache exceeds
maxCacheEntries, the oldest entry (by timestamp) is pruned and the
pruned state is correctly persisted to disk.

Change-Id: Ia937800a97d7591877e1d2d1fe808b86858735e1
2026-04-27 12:30:56 +08:00
wujunchen
cfdd985f78 test: add batch state isolation and cancellation tests
Verify that two concurrent BatchRunState objects don't interfere with
each other (cancelling one doesn't affect the other), and that stats
accumulate correctly when processing is stopped mid-iteration.

Change-Id: Id32b27307beafe49594cfde6fa818b2f22b87c66
2026-04-27 12:29:42 +08:00
wujunchen
593817734b test: add streaming cancellation edge case tests
Cover pre-aborted signal (aborted before fetch starts) and mid-read
abort (signal aborted while reading response body). Both verify that
abort listeners are properly cleaned up after rejection.

Change-Id: I0760f6ed051de1504e9b7aeead01a10cfd12476e
2026-04-27 12:28:36 +08:00
wujunchen
1d3aa81678 fix: close abort signal race window in streaming fetch
The previous code checked signal.aborted before adding the listener,
creating a timing window where the signal could abort between the check
and addEventListener. Now the listener is always registered first, then
signal.aborted is checked after, ensuring no abort event is missed.

Change-Id: I1abc3ad21e5bb93559d66922edf7c325a977bc65
2026-04-27 12:22:43 +08:00
wujunchen
09f39dde8d fix: make normalizeSettings return a new object instead of mutating input
normalizeSettings previously modified its input parameter in-place.
While callers already created copies before calling it, the function
signature was misleading. Now it creates a shallow copy internally and
operates on that, with a Readonly<PluginSettings> parameter type to
signal intent. Added a test verifying the original object is unchanged.

Change-Id: I7600ac37930bbcebb02aa7c84d8988cb7aa71196
2026-04-27 12:20:56 +08:00
wujunchen
816b015e56 chore: bump version to 1.0.4
Change-Id: Id5040ec82babe747976121e07b7eabe1f6d82406
2026-04-27 12:11:29 +08:00
wujunchen
ff1116d7f4 fix: pass --max-tokens to Claude Code CLI to prevent output truncation
The CLI path was not forwarding settings.apiMaxTokens, causing the
model to use its own default which is too small for long documents
with many CJK cards. This was the root cause of repeated "LLM 返回
非 JSON" errors — the JSON was being cut off mid-card.

Change-Id: Ia738418e2e6cf7f919752cb3128a82768d95cedf
2026-04-27 11:58:04 +08:00
wujunchen
abce923f14 fix: salvage truncated LLM JSON and make errors copyable
- Add repairTruncatedCardsJson to recover complete cards when output
  is cut off mid-card (e.g. token limit reached)
- Log raw LLM response to console on parse failure for debugging
- Make error panel text selectable and add "copy error" button

Change-Id: I4e76121138888234d42f84f3695cbbfd6beba886
2026-04-27 11:56:40 +08:00
wujunchen
5f12113fcd chore: improve engineering quality and hardening
- Fix CI to run all 4 test files (was missing direct-modules.test.js)
- Remove unused ESLint dependencies (eslint, @typescript-eslint/*, eslint-plugin-obsidianmd)
- Enable noImplicitReturns in tsconfig.json for stricter type safety
- Make applyApiProviderPreset return new object instead of mutating input
- Add per-file error handling in batch processing loop with error count in summary
- Narrow all catch clause types to unknown with proper instanceof narrowing

Change-Id: I76975dbd5ebdb5645d18c5858c8a52fd6da3405e
2026-04-27 11:15:35 +08:00
wujunchen
b1e35fc8fc chore: bump version to 1.0.3
Change-Id: I58a40e2a7037c83bed96f30af077c096314160f2
2026-04-27 10:46:01 +08:00
wujunchen
d75107d84c chore: update versions.json for 1.0.2 release
Change-Id: Icc8e905a4b117a5707d6e6b48729a8d6dc60a619
2026-04-27 10:45:27 +08:00
wujunchen
6e83d216c2 feat: add generate button to empty state panel
When a note has no cached parallel notes, the empty state now shows a
clickable "Generate" button so users can trigger generation directly
without going through the command palette. Closes #2.

Change-Id: I879897168ef77c44e0ab570e9c094fa9af9f66d4
2026-04-27 10:24:05 +08:00
wujunchen
6aba90bfd3 fix: remove unnecessary async from catch handler
The catch callback no longer contains any await expressions
after the previous refactor removed await on sync view methods.

Change-Id: I054c50fe209aba0e925bd1838896228bce686841
2026-04-26 21:12:16 +08:00
wujunchen
da535cb064 fix: address remaining Obsidian review bot required issues
- Remove unnecessary TFile cast (instanceof already narrows)
- Remove await on non-Promise view methods (loadFor, renderLoading, renderError)
- Remove async from CacheManager.touch() (no await expression)
- Replace this-aliasing with captured locals in batch modal
- Use CSS class instead of inline style for modal input width
- Fix sentence case in settings UI text

Change-Id: I2a222c6429eb7e4d69761cca8369956fef510054
2026-04-26 19:34:45 +08:00
wujunchen
de08ec778a chore: add eslint tooling dependencies
Change-Id: I3f855a85e1ed9ef45a0f77210d5a68081a967d59
2026-04-26 19:25:51 +08:00
wujunchen
3d8d72b66e refactor: split settings tab renderers
Change-Id: I456ddd16868150b2e22f5592c97d579a3540e48d
2026-04-26 19:17:12 +08:00
wujunchen
486060bddf test: cover cache manager with fake adapter
Change-Id: I83f6b71a46af31f783522faa53bffbfc6c4bc54d
2026-04-26 18:31:17 +08:00
wujunchen
557908ca44 fix: clean up streaming abort listener
Change-Id: I9fa8ace7bc0fa723466ef851f7ec2960c6638eba
2026-04-26 18:29:48 +08:00
wujunchen
bc51acd00e fix: parse multiline sse events
Change-Id: I9c013dbe6840a0892836eb5d71206c6fcde5ec78
2026-04-26 18:27:28 +08:00