11 KiB
Search Content Option Migration Implementation Plan
Goal: Replace positional search query arguments with explicit --content for all search subcommands so trailing global options are parsed reliably.
Architecture: Keep query execution and db-worker-node transport unchanged and limit behavior change to CLI parsing, action building, help text, completion metadata, tests, and docs.
Architecture: logseq-cli will continue to call :thread-api/q through /v1/invoke, so worker-side search semantics and result shape stay stable.
Tech Stack: ClojureScript, babashka.cli, existing logseq.cli.command.* architecture, db-worker-node HTTP /v1/invoke, Datascript query execution.
Related: Builds on /Users/rcmerci/gh-repos/logseq/docs/agent-guide/069-logseq-cli-search-subcommands.md.
Related: Touches /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs.
Related: Touches /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/search.cljs.
Related: References /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/core.cljs parsing behavior.
Related: References /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/transport.cljs and /Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_worker_node.cljs for protocol compatibility.
Problem statement
Current search commands use free-form positional query text.
Current examples are logseq search block task --graph my-graph and similar forms.
parse-leading-global-opts only extracts global options that appear before the command path.
For search, trailing options can leak into positional args, which is why search.cljs currently has extract-inline-graph as a command-specific workaround.
This workaround handles only --graph and -g and does not solve general trailing global options like --output json.
As a result, commands like search block something --output json can produce unstable UX by mixing option tokens into query text or requiring option placement discipline that users do not expect.
The CLI should use explicit command options for search input to avoid positional swallowing behavior.
Current baseline and compatibility constraints
search entries are defined in /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/search.cljs with empty command-specific spec maps.
search build logic currently receives positional args and joins them into :query.
commands.cljs validation currently checks (string/join " " args) for :missing-query-text.
Execution already uses transport/invoke with :thread-api/q and submits [repo [query query-text]].
db-worker-node invoke routing is method-generic and does not encode CLI syntax assumptions.
Therefore this migration is a CLI surface change and test-doc update, not a worker protocol migration.
Target behavior
Canonical command syntax
logseq search block --content <search-content> [global options]
logseq search page --content <search-content> [global options]
logseq search property --content <search-content> [global options]
logseq search tag --content <search-content> [global options]
Examples:
logseq search block --content "task" --graph my-graph --output json
logseq search page --content "project notes" --output edn --graph my-graph
Validation behavior
--content is required for all four search subcommands.
Blank content is rejected with :missing-query-text.
Legacy positional query usage is rejected with an explicit :invalid-options message that instructs users to use --content.
Non-goals
No change to search result schema.
No change to Datascript query semantics.
No new db-worker-node endpoints.
No fuzzy search or ranking changes.
Testing Plan
I will add unit and integration-style CLI tests that validate behavior rather than internal implementation details.
I will first add failing parser tests that assert search <scope> --content ... succeeds and positional search <scope> foo fails with migration guidance.
I will then add failing build-action tests that assert query text is sourced from options instead of positional args.
I will add completion tests to ensure --content is discoverable in generated zsh/bash scripts.
I will update CLI e2e cases so search coverage uses --content and includes a trailing global option order check.
I will update docs examples and help snapshots where search syntax is listed.
NOTE: I will write all tests before I add any implementation behavior.
Implementation plan
-
Add failing parse tests in
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/commands_test.cljs. -
Replace positional search parse expectations with
:options {:content ...}expectations. -
Add a failing test that
search block positionalreturns:invalid-optionswith migration guidance. -
Add a failing test that
search block --content alpha --output jsonkeeps query asalphaand does not consume--outputas content. -
Add failing unit tests in
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/command/search_test.cljsforbuild-actionusing options map input. -
Add a failing unit test that blank
--contentis rejected with:missing-query-text. -
Update
searchcommand specs in/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/search.cljsto include:contentoption metadata. -
Remove positional-args normalization and inline graph extraction logic from
search.cljs. -
Change
search-command/build-actionto read query text fromopts[:content]and repo from resolved graph config path as already done by central parser. -
Update
commands.cljsvalidation for search commands to read fromopts[:content]and to reject unexpected positional args with a clear migration hint. -
Update
commands.cljscall-site so search build-action is invoked withoptionsinstead of rawargs. -
Keep execute path unchanged because worker invocation contract already accepts final query string only.
-
Add completion assertions in
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/completion_generator_test.cljsfor--contentunder search subcommands. -
Update CLI e2e inventory in
/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_inventory.ednso search options include--content. -
Update CLI e2e cases in
/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_cases.ednto use--contentand at least one trailing-global-order scenario. -
Update user docs in
/Users/rcmerci/gh-repos/logseq/docs/cli/logseq-cli.mdto replacesearch <scope> <query>withsearch <scope> --content <query>across command list and examples. -
Run focused tests.
-
Run broader lint and test suites.
File-by-file change map
| File | Planned change |
|---|---|
/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/search.cljs |
Add :content command option spec for all search subcommands and switch build-action input source to options. |
/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs |
Validate --content, reject legacy positional args for search, and pass options to search build-action. |
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/command/search_test.cljs |
Convert build-action tests from positional args to option-driven content and add migration failure coverage. |
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/commands_test.cljs |
Update parse and build-action tests for search syntax and trailing global option behavior. |
/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/completion_generator_test.cljs |
Assert completion output includes --content for search commands. |
/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_inventory.edn |
Add --content to search options inventory. |
/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_cases.edn |
Replace search command invocations with --content and add option-order stability checks. |
/Users/rcmerci/gh-repos/logseq/docs/cli/logseq-cli.md |
Update syntax, examples, and command reference text. |
db-worker-node impact
No API route changes are required in /Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_worker_node.cljs.
No thread-api additions are required in /Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_core.cljs for this migration.
logseq-cli will still call :thread-api/q with the same query payload shape.
This means rollout risk is concentrated in CLI parse and docs/test updates.
Verification commands
bb dev:test -v logseq.cli.command.search-test
bb dev:test -v logseq.cli.commands-test
bb dev:test -v logseq.cli.completion-generator-test
bb -f cli-e2e/bb.edn test --skip-build
bb dev:lint-and-test
Expected outcomes:
All updated search parser tests pass with explicit --content syntax.
No test still asserts positional query behavior for search.
CLI e2e search cases pass with globals after command while preserving content fidelity.
Rollout notes
This change intentionally breaks legacy positional search syntax to remove ambiguity and option swallowing risk.
Error messaging must include a direct rewrite hint from search <scope> <query> to search <scope> --content <query>.
If immediate hard cut is considered too disruptive, an optional short deprecation period can be introduced, but it should still reject option-like trailing tokens in positional mode to avoid unstable behavior.
Edge cases
--content " " should fail with missing query text.
--content values containing leading dashes as literal text should remain accepted when properly quoted.
--content should preserve multi-word queries exactly as user input after trim.
Search commands should still fail with :missing-repo when graph resolution is unavailable.
Testing Details
The tests will assert user-visible behavior for parse success, parse failure guidance, and stable interaction with trailing global options.
The tests will not mock babashka.cli internals and will exercise commands/parse-args, commands/build-action, and real completion generation output strings.
The e2e tests will verify actual executable command lines against a temporary graph and inspect output payload fields.
Implementation Details
- Use command-specific
:contentoption specs so help and completion are automatically generated. - Keep search execution logic and worker transport untouched to minimize regression surface.
- Keep
:missing-query-textcode path for blank content. - Add explicit legacy positional rejection in central command finalization for consistent error style.
- Update search examples in command entries to demonstrate trailing global options after
--content. - Ensure docs and e2e inventory are updated together so command contract is synchronized.
- Preserve existing table output format for search results.
- Validate that
--graphand--outputcan both appear after subcommands without affecting query extraction. - Prefer one clear migration error message over silent fallback behavior.
Question
Should we enforce an immediate hard cut for positional search syntax, or keep a one-release compatibility shim with a warning and then remove it in the next release?