Commit graph

154 commits

Author SHA1 Message Date
fancivez
a5d9d74b54 feat: toggle right sidebar instead of detaching tab + component tests
UX change:
- The "open Parallel Reader" command now toggles the right sidebar's
  collapsed state instead of detaching the leaf. The tab and its content
  are preserved across hide/show, matching standard Obsidian behaviour
  for File Explorer and friends. Detaching the tab on every second
  press destroyed cached cards and forced re-generation.

Behaviour:
- No leaf yet → create + reveal
- Leaf exists, right sidebar collapsed → reveal (expands sidebar)
- Leaf exists, right sidebar expanded → collapse(); tab is preserved
- No right sidebar (mobile / unusual layout) → reveal as fallback

Tests:
- New tests/view-render.test.js (18 cases) covering the component layer
  that was previously a gap. The 1.0.12 → 1.0.13 sidebar regression
  could not have been caught by any existing pure-function test; this
  file fills that gap by mocking app.workspace + view spies and running
  real runForFile / refreshViewAfterCache* / toggleParallelView.
- shouldRender matrix (4 cases): silentView × sourceFile state — the
  exact regression introduced in PR2 where guards were over-applied.
- toggleParallelView (4 cases): no-leaf opens, expanded → collapse,
  collapsed → reveal, no-rightSplit fallback.
- refreshViewAfterCacheDelete + Clear (4 cases): matching file vs
  different file vs no-view, plus clear-all always renderEmpty.
- runForFile outcome enum mapping (6 cases): already-running early
  return, already-running from catch, cancelled, generic error,
  regenerate-confirm cancellation, skipEditConfirm bypass — these
  drive batch statistics and were untested before.
- view.deleteCard / updateCard cardPersistFailed path (3 cases):
  exposes ParallelReaderView via test-exports for instantiation;
  mocks cacheReplaceCards returning false to verify the failure
  notice path lands and the public method returns false.

src/test-exports.ts: export ParallelReaderView for component tests.
tests/catalog.json: register view-render.test.js under component.

Change-Id: I439b5fca07b0928e6fe44d9025c2421c71c6cb28
2026-05-02 15:38:41 +08:00
fancivez
8e055cce50 chore: bump version to 1.0.13
Change-Id: I56e56f0f6fd3a440d26249b5baf845c65db15785
2026-05-02 14:10:49 +08:00
fancivez
d058348f6f fix: regressions in 1.0.12 — sidebar render guard + open-view toggle
Two regressions reported after 1.0.12 was installed:

1. Hotkey-triggered Generate did not update the sidebar. PR2 added
   `viewIsShowingFile(view, file)` guards to renderLoading/loadFor/
   renderError in runForFile to keep batch (silentView) jobs from
   disturbing a panel showing a different note. The guard was applied
   to all paths, breaking the interactive case: when the sidebar had
   never been opened (sourceFile=null) or was showing a different note,
   every render call was skipped and the sidebar stayed blank while
   generation completed in the background.

   Fix: compute `shouldRender = !silentView || viewIsShowingFile(...)`
   once. Non-silent (user pressed Generate on this file) renders
   unconditionally; silentView keeps the existing "only if it's already
   this file" behaviour.

2. The open-view command had no toggle behaviour. Pressing the hotkey a
   second time silently re-opened the same panel.

   Fix: if a parallel-reader leaf already exists, detach it; otherwise
   ensureView + sync.

Change-Id: I1db3d70806d8d07965d18bf3717023de027ac577
2026-05-02 14:10:49 +08:00
fancivez
a283cb588a chore: bump version to 1.0.12
Change-Id: I25e04737ba455e13c9809f517444df430c582c56
2026-05-02 13:52:53 +08:00
fancivez
76d2e8050a fix: address 10 P2 behavioral and concurrency findings
Findings from the original review (P2):
- streaming: flush unterminated final SSE event at EOF (some providers
  close the stream without a trailing blank line, dropping the last delta)
- cache-manager: validate entry shape on load — drop entries where
  cards is not an array, anchor is not a string, or bullets is not an
  array. Tolerates missing optional fields (treated as cache miss).
- view: card edit/delete now check cacheReplaceCards return and surface
  failures via a localized Notice instead of pretending success
- main: clear-current / clear-all / file-menu-clear refresh open view
  via renderEmpty so stale UI does not display deleted data
- prompt + settings-tab: card count is normalized via a single helper
  used by buildPrompts and onChange. Prompt and fingerprint stay in sync.
  UI value is written back to the textbox after clamping.
- generation-job-manager: global concurrency limit (default 3) with a
  cancellable wait queue. Race-safe slot accounting via a reserved
  counter so resolved-but-not-yet-set waiters are visible to fast-path
  start() callers.
- runForFile: now returns RunForFileResult; accepts preloadedContent +
  silentView + skipEditConfirm options used by batch (and reflected on
  the PluginHost interface).
- batch: avoid double file read, do not steal UI focus, classify
  results correctly (generated / cached / already-running / empty / ...)

Follow-up from the 1.0.11 review:
- generationFingerprint: codex backend excludes settings.model from the
  hash. Codex ignores --model; previously editing model spuriously
  invalidated all codex cache.

Codex review pass:
- generation-job-manager: race fix — releaseSlot's resolve microtask
  and a synchronous start() fast-path could briefly overshoot
  maxConcurrent. Reserve the slot synchronously inside the wrapped
  resolve to close the window.
- cache-manager: anchor type validation in addition to bullets.

NOTE: Codex backend users will see a one-time "stale cache" banner on
existing notes due to the fingerprint change; regenerate to refresh.

Change-Id: I7721c7dfe51dea3f51b0215764f721523c2f6806
2026-05-02 13:52:49 +08:00
fancivez
d1f36d52a0 chore: bump version to 1.0.11
Change-Id: I1a24c7e05011ff320eccfd5e917ec3793fa3164e
2026-05-02 13:11:27 +08:00
fancivez
c10c641949 docs: trim e2e gate section in readme
Drop the self-contained/no-Python historical note and the contributor-
focused tests/catalog.json paragraph; keep the gate command + TEST_LIVE=1
hint. Public README does not need internal test classification details.

Change-Id: Ic7a2ed45af0ebeb3be227aed03079ce258ed30c2
2026-05-02 12:51:19 +08:00
fancivez
01ec934d28 fix: address 13 review findings (security, UX, i18n)
P1:
- cli: pin codex --sandbox read-only (defeat prompt injection)
- settings: clear apiKey/apiHeaders on provider preset switch
- main/view: render error state when LLM returns empty cards
- schema/cli: do not log raw model output; UI errors expose length only

P2:
- cli: pass --model to Claude Code when settings.model set
- settings-tab: add CLI timeout input + normalizeCliTimeoutMs (min 1s)
- view: export source link uses [[path|basename]]
- view: export failures surface a localized Notice

P3:
- schema: cardUntitled fallback now respects uiLanguage
- generation-job-manager: error codes localized via main.ts
- batch: settled guard on promptForBatchFolder modal
- README: drop stale e2e validator install note

Codex review pass:
- provider-parsers: forward settings to normalizeCardsPayload
- generation-job-manager: classifyGenerationError regex covers new EN/zh
  schema-error messages
- cli: do NOT pass --model to codex (DEFAULT_SETTINGS.model is a Claude
  name and would break codex; codex relies on its own config)

Tests: cli (codex sandbox + claude --model + classify zh/en), settings
(applyApiProviderPreset isolation + normalizeCliTimeoutMs), schema
(language-aware fallback title), test-exports (new symbols).

Change-Id: I9f4c21f9299e1a9bf166f69f712859854482fe92
2026-05-02 12:50:35 +08:00
fancivez
dc03345dc7 chore: bump version to 1.0.10
Change-Id: I2ba1c339f13e4e40fcaa5c85e911b51b97f19640
2026-04-30 15:02:06 +08:00
fancivez
418f733d14 ci(e2e): enforce self-contained release gate
Change-Id: I4a7385a861981223edf5b4a3f1861b349ef520bf
2026-04-30 14:45:56 +08:00
fancivez
15e81cbcb6 docs: expand readme badges and language switcher
Change-Id: Ia547e146cca71f0daf04c896fd14f892940ed707
2026-04-29 18:16:43 +08:00
wujunchen
310c81a073 fix: add cancel action to batch prompt
Change-Id: Ic3922d55d776d369959eff4e5c811c5d3434db2b
2026-04-29 14:13:47 +08:00
wujunchen
57c1c0e124 docs: document e2e contract gate
Change-Id: I940bac18e567c55a7cd57e1ccf37203f871c6aec
2026-04-29 14:09:55 +08:00
wujunchen
970a7bc364 chore: add e2e contract gate
Change-Id: Idf5c36b17a5b816e354d07f1e28ff4011e54f32e
2026-04-29 14:08:38 +08:00
wujunchen
3bdd6d67c6 fix: localize batch prompt confirmation
Change-Id: I13b546785c5984a9d0cb5abaffa843f9ad7655d0
2026-04-29 13:58:10 +08:00
wujunchen
2bf4e86451 fix: confirm before overwriting exports
Change-Id: I922fca90e46a8982686a3449b00ed793e924097b
2026-04-29 13:56:36 +08:00
wujunchen
5304ed3a48 fix: localize remaining action labels
Change-Id: I4ac6db14c4aede9a106e8023effac3c99d3c037a
2026-04-29 13:54:53 +08:00
wujunchen
2d39a91aed test: split architecture guard tests
Change-Id: Ibde4ae79f202ae0e26658ab47bbcf5b52ef9effe
2026-04-29 13:53:19 +08:00
wujunchen
39ddd4289e fix: count batch generation failures
Change-Id: Ie6b29cb3efc22fe72250e9c63c1e82c71b24a356
2026-04-29 13:51:33 +08:00
fancivez
ceea8d6ff0 chore: bump version to 1.0.9
Change-Id: I5bd7ac74eb9101ffeeb99ef24518f68e91b9c101
2026-04-27 20:41:14 +08:00
fancivez
dae5175b6c fix: add void operator to all floating promises in callbacks
Satisfies @typescript-eslint/no-floating-promises for fire-and-forget
async calls (runForFile, copyToClipboard, scrollEditorToLine, etc.)

Change-Id: I758cc8e1ae49deacd7e8527abcda90c0e3d4fe1c
2026-04-27 20:39:14 +08:00
wujunchen
f8bf0f99ca chore: bump version to 1.0.8
Change-Id: I0eedef0d4ad19f84f189f8c95a4a1f69b6d09eb4
2026-04-27 20:27:52 +08:00
wujunchen
0801b644f6 fix: address CR findings — bump script, test runner, temp cleanup
- bump-version.mjs: reject duplicate versions (use --force to override),
  auto git-add manifest.json + versions.json for npm version hook
- run-tests.mjs: use execFileSync to handle paths with spaces
- test-setup.js: clean up esbuild temp directory on process exit

Change-Id: I44410b550d09487dd7f5e30a8f9385a2c500252a
2026-04-27 20:19:53 +08:00
wujunchen
199ab73188 refactor: split main.test.js into focused test files
Reduce main.test.js from 560 to 70 lines by keeping only architecture
guards and export smoke tests. Moved provider error tests, Anthropic
tool-use parsing, and cancellationNoticeKey tests to providers.test.js.
Settings, cache, and other tests were already covered in their
dedicated test files.

Change-Id: I8f0f3c576dec7fcf5a4c6e0c2b6071601940349d
2026-04-27 19:59:46 +08:00
wujunchen
f5f974fd74 build: remove __test barrel from production bundle
Tests now load src/test-exports.ts via esbuild buildSync instead of
importing __test from the production main.js. This removes ~60 internal
symbols and all test-only module code from the shipped plugin bundle.

Change-Id: I2caf5232f6894c7514215e1751f2e268b74d7dc4
2026-04-27 19:57:28 +08:00
wujunchen
0bf5ab12b1 lint: extend Biome coverage to tests/ and scripts/
Add tests/**/*.js and scripts/**/*.mjs to biome.json includes and
update npm lint scripts to cover these directories. Auto-fixed all
formatting issues in 26 files.

Change-Id: I8c2763cb9683616a8abc1484d91bf8af79bb590e
2026-04-27 19:53:35 +08:00
wujunchen
b26b241c7f refactor: centralize obsidian mock into tests/obsidian-mock.js
Extracts the duplicated Module._load obsidian stub from main.test.js,
generation-job-manager.test.js, and test-setup.js into a single shared
file. All three now require('./obsidian-mock') instead of defining
their own copy.

Change-Id: I8ac38f779299ac250963357eee9f7824e13c7d33
2026-04-27 19:52:34 +08:00
wujunchen
e10cbbbe9c build: add version bump script
npm run version <x.y.z> atomically updates manifest.json and
versions.json. Replaces the manual three-file version dance.

Change-Id: Ib894147f654b284d8f4c1df95bd8ff5da80d5dcc
2026-04-27 19:51:11 +08:00
wujunchen
e5f5af43ca ci: add tag-triggered release workflow
On tag push (e.g. 1.0.7), builds from source, runs typecheck + tests,
then creates a GitHub Release with main.js, main.js.map, manifest.json,
and styles.css attached. This replaces the need to commit main.js to
the repository.

Change-Id: I8ccbdddaa45267d2738cc43a4e7fccd1d35346ab
2026-04-27 19:50:17 +08:00
wujunchen
f6ce405249 build: remove main.js from git tracking
main.js is now a build artifact produced by esbuild, not tracked in
git. The release workflow (next commit) will build and attach it to
GitHub Releases. Also removes the check-build-artifacts script that
enforced main.js stay in sync.

Change-Id: I35f7dede09c5ac3c2d788c11248e2ed4931a95bc
2026-04-27 19:49:45 +08:00
wujunchen
098fee763c build: enable linked source maps for production builds
Generates main.js.map alongside main.js so error stack traces in the
Obsidian developer console point to original source locations.

Change-Id: I3f63196bfa421c2ac69aee371e4c294d42ee629c
2026-04-27 19:48:26 +08:00
wujunchen
f9e33d4c5d build: align tsconfig target and esbuild target to ES2022
Both were ES2020 while lib was already ES2022, creating a mismatch
that could allow using APIs esbuild wouldn't polyfill. Obsidian 1.4+
runs Electron 25+ which fully supports ES2022.

Change-Id: I732538280146c6a91cf52cc52ef124f6a364dc5e
2026-04-27 19:47:41 +08:00
wujunchen
552dd41109 chore: bump version to 1.0.7
Change-Id: Id06610a41ee7664e29f0b3f2894e2270b36649b7
2026-04-27 19:08:13 +08:00
wujunchen
df48dc2cc4 fix: remove unsupported --max-tokens flag from claude CLI args
The Claude Code CLI doesn't support --max-tokens. This caused the CLI
backend to always fail with exit code 1. Also adds args validation tests
for both claude and codex CLI backends.

Change-Id: I57c5cc672ed08de291e3941511ce68ba56e5b4ff
2026-04-27 19:07:53 +08:00
wujunchen
ea5f440ca5 chore: bump version to 1.0.6
Change-Id: Icc2aa02d42c7ffe32c1b6cc5ae8b2ea995460a3f
2026-04-27 17:21:07 +08:00
wujunchen
1fff3cb343 fix: address CR findings — test runner, CI dedup, error cause
- Create scripts/run-tests.mjs to auto-discover test files, replacing
  the 900-char inline test command in package.json (P3-1)
- Add test:only script for CI to avoid duplicate build+typecheck (P2-1)
- Preserve original SyntaxError as cause in responseJson (P2-3)

Change-Id: I51d0c8c51d3b0b648ed5ff4ea282bda070b0d457
2026-04-27 16:04:03 +08:00
wujunchen
986143b05b refactor: split settings-tab renderBackendSection into CLI/API methods
Extracts renderCliBackendSettings() and renderApiBackendSettings() from
the 144-line renderBackendSection(). The parent method is now a 5-line
dispatcher. CLI settings (14 lines) and API settings (128 lines) are
cleanly separated.

Change-Id: Ic866ba78d3b572f5f564760b248460584b0819c5
2026-04-27 15:45:25 +08:00
wujunchen
4b7b8cccfc refactor: create test-exports.ts barrel to clean up main.ts
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
2026-04-27 15:43:58 +08:00
wujunchen
60e9ad6bb2 refactor: extract provider HTTP helpers to provider-request.ts
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
2026-04-27 15:41:28 +08:00
wujunchen
ed93e25cc9 refactor: split view.ts render() into 5 focused helper methods
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
2026-04-27 15:39:12 +08:00
wujunchen
49c75a5a15 fix: update CI to use npm test instead of hardcoded test file list
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
2026-04-27 15:38:17 +08:00
wujunchen
05ac2b923f test: add batch.ts comprehensive tests including isFileInBatchFolder
Tests cover isFileInBatchFolder (root, subfolder, nested), edge cases
for normalizeBatchFolderInput (null, undefined, only slashes),
hasUnsafeBatchFolderSegments (null, single dot, dotfile), selectBatchFiles
with complex folder structures, and stats immutability verification.

Change-Id: If4964355db427347060ea3f902e8f6ef71ea2471
2026-04-27 15:31:37 +08:00
wujunchen
741012e535 test: add settings.ts edge case tests for utility functions
Tests cover stableStringify (key sorting, nested, types), isApiBackend,
getApiFormat/getApiAuthType fallback behavior, normalizeMaxCacheEntries,
hashContent consistency, normalizeSettings validation (invalid uiLanguage,
apiProvider, apiFormat, apiAuthType, non-string customSystemPrompt),
and pruneCacheEntries with null/empty/non-object inputs.

Change-Id: I96269c69871e3c17ccb06a71ac9cfb9733a382f6
2026-04-27 15:30:33 +08:00
wujunchen
6f80d0de03 test: add generation.ts cancellationNoticeKey edge case tests
Tests cover all backend types (api, anthropic-api, claude-code, codex),
all generation phases (queued, reading, cache-check, generating, saving),
and null settings/job edge cases.

Change-Id: I722fb0cf1129c7cf45dfc5bf2544577652df843d
2026-04-27 15:29:29 +08:00
wujunchen
0f8625874e test: add comprehensive markdown.ts unit tests
Tests cover cardToMarkdown, cardToPlain, and cardsToMarkdown with
edge cases: empty/missing fields, anchor whitespace normalization,
null cards array, empty title fallback, plain text bullet formatting.

Change-Id: I1972705d385f0393c9fd1be7f80d6513f5328d06
2026-04-27 15:28:34 +08:00
wujunchen
1e2ccc0840 test: add comprehensive prompt.ts unit tests
Tests cover promptLanguageInstruction, promptSchemaExample,
renderPromptTemplate, and buildPrompts edge cases including
auto language, truncation markers, custom prompt variable
substitution, card count normalization, and fallback behavior.

Change-Id: I75d5b354df15456ddbd08d9d21846f74d6b6cea3
2026-04-27 15:27:19 +08:00
wujunchen
0264ef0b6c refactor: split direct-modules.test.js into 5 per-module test files
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
2026-04-27 15:24:32 +08:00
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