Replaces the 64-line __test manual export block in main.ts with a
single import from src/test-exports.ts. Also removes 30+ imports that
were only needed for __test re-export. main.ts reduced from 788 to
693 lines.
Change-Id: I029f127faf053135d04dba17b8c39c8c39ca8540
Moves RequestUrlFunction type, endpointUrl, responseJson, requestJsonBody,
shouldRetryWithoutStructuredOutput, and requestJsonBodyWithStructuredFallback
to a dedicated provider-request.ts module (103 lines). providers.ts reduced
from 377 to 277 lines.
Change-Id: I013d6a0b9565770c00e48eb416541fcf08d1c5e8
Decomposes the 76-line render() method into renderHeader(),
renderStaleBanner(), renderLoadingState(), renderErrorState(), and
renderCardList(). Each helper is under 22 lines. render() is now a
15-line orchestrator that delegates to the appropriate helper.
Change-Id: Iffcf31131fcf0bce882c1e9ee35aaf58d002b5fa
The CI workflow still referenced the deleted modules.test.js and
direct-modules.test.js files. Now uses npm test which runs all 24
test files via the package.json script.
Change-Id: Iba3575459e56aa036f4002c76ecaa9c5f2e82278
Replaces the monolithic direct-modules.test.js (780 lines) with focused
per-module test files sharing a common direct-test-setup.js. Each file
is under 165 lines. All existing test assertions preserved.
New files: direct-test-setup.js, direct-cache.test.js,
direct-providers.test.js, direct-settings.test.js, direct-i18n.test.js,
direct-streaming.test.js
Change-Id: Ie9cceaf3b9b71e618c0d7e524a5186b5c44079c8
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
- 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
- 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