Explorar o código

fix lint, remove deprecated cmds

rcmerci hai 5 días
pai
achega
2a9ba965cf

+ 2 - 0
.carve/ignore

@@ -68,6 +68,8 @@ frontend.worker.rtc.op-mem-layer/_sync-loop-canceler
 frontend.worker.db-worker/init
 frontend.worker.db-worker/init
 ;; Used by shadow.cljs (node entrypoint)
 ;; Used by shadow.cljs (node entrypoint)
 frontend.worker.db-worker-node/main
 frontend.worker.db-worker-node/main
+;; CLI entrypoint (shadow-cljs :node-script)
+logseq.cli.main/main
 ;; Future use?
 ;; Future use?
 frontend.worker.rtc.hash/hash-blocks
 frontend.worker.rtc.hash/hash-blocks
 ;; Repl fn
 ;; Repl fn

+ 22 - 8
docs/agent-guide/001-logseq-cli.md

@@ -17,7 +17,7 @@ The CLI should provide a stable interface for scripting and troubleshooting, and
 
 
 ## Testing Plan
 ## Testing Plan
 
 
-I will add an integration test that starts db-worker-node on a test port and verifies the CLI can connect and run a simple request like ping or status.
+I will add an integration test that starts db-worker-node on a test port and verifies the CLI can connect and run a simple graph/content request.
 I will add unit tests for command parsing, configuration precedence, and error formatting.
 I will add unit tests for command parsing, configuration precedence, and error formatting.
 I will add unit tests for the client transport layer to ensure timeouts and retries behave correctly.
 I will add unit tests for the client transport layer to ensure timeouts and retries behave correctly.
 I will add unit tests for new graph/content commands (parsing, validation, and request mapping).
 I will add unit tests for new graph/content commands (parsing, validation, and request mapping).
@@ -45,7 +45,7 @@ The CLI will use JSON for request and response bodies for ease of scripting.
 
 
 ## Implementation plan
 ## Implementation plan
 
 
-1. Use TodoWrite to track the full task list and include the @test-driven-development red-green-refactor steps.
+1. Use tool(update_plan) to track the full task list and include the @test-driven-development red-green-refactor steps.
 2. Read @test-driven-development guidelines and confirm the red phase will include all CLI tests first.
 2. Read @test-driven-development guidelines and confirm the red phase will include all CLI tests first.
 3. Identify existing db-worker-node request handlers and document their request and response shapes.
 3. Identify existing db-worker-node request handlers and document their request and response shapes.
 4. Define the initial CLI command surface as a table that includes command, input, output, and errors.
 4. Define the initial CLI command surface as a table that includes command, input, output, and errors.
@@ -63,14 +63,28 @@ The CLI will use JSON for request and response bodies for ease of scripting.
 16. Refactor for naming and reuse while keeping tests green.
 16. Refactor for naming and reuse while keeping tests green.
 17. Document how to build and run the CLI in a short section in README.md.
 17. Document how to build and run the CLI in a short section in README.md.
 
 
+## Current status (2026-01-14)
+
+Implemented:
+- CLI build target, entrypoint, config resolution, transport, formatting, and command wiring.
+- Graph commands: list/create/switch/remove/validate/info.
+- Content commands: add/remove/search/tree.
+- Unit tests for config/commands/format/transport and integration tests for graph/content commands.
+- CLI docs moved to `docs/cli/logseq-cli.md` and linked from README.
+
+Not fully aligned with plan:
+- Red-first TDD sequence was not strictly followed (some tests added after initial implementation).
+- README section was replaced by a link to the dedicated doc.
+- `search` currently queries `:block/title` only (no page name/content search).
+
+Open follow-ups (optional):
+- Expand `search` to include page name/content and update tests.
+- Add any additional graph metadata to `graph-info` beyond `:logseq.kv/graph-created-at` and `:logseq.kv/schema-version`.
+
 ## Command surface definition
 ## Command surface definition
 
 
 | Command | Input | Output | Errors |
 | Command | Input | Output | Errors |
 | --- | --- | --- | --- |
 | --- | --- | --- | --- |
-| ping | none | ok message | server unavailable, timeout |
-| status | none | server version, db state | server unavailable, timeout |
-| query | query string or file | query result JSON | invalid query, parse error |
-| export | target path and format | export result | unsupported format, write error |
 | graph-list | none | list of graphs | server unavailable, timeout |
 | graph-list | none | list of graphs | server unavailable, timeout |
 | graph-create | graph name | created graph + set current graph | invalid name, server unavailable |
 | graph-create | graph name | created graph + set current graph | invalid name, server unavailable |
 | graph-switch | graph name | switched graph + set current graph | missing graph, server unavailable |
 | graph-switch | graph name | switched graph + set current graph | missing graph, server unavailable |
@@ -79,7 +93,7 @@ The CLI will use JSON for request and response bodies for ease of scripting.
 | graph-info | graph name or current graph | graph metadata/info | missing graph, server unavailable |
 | graph-info | graph name or current graph | graph metadata/info | missing graph, server unavailable |
 | add | block/page payload | created block IDs | invalid input, server unavailable |
 | add | block/page payload | created block IDs | invalid input, server unavailable |
 | remove | block/page id or name | removal confirmation | invalid input, server unavailable |
 | remove | block/page id or name | removal confirmation | invalid input, server unavailable |
-| search | query string | matched blocks/pages | invalid input, server unavailable |
+| search | text query | matched blocks/pages | invalid input, server unavailable |
 | tree | block/page id or name | hierarchical tree output | invalid input, server unavailable |
 | tree | block/page id or name | hierarchical tree output | invalid input, server unavailable |
 
 
 ## Edge cases
 ## Edge cases
@@ -141,7 +155,7 @@ I will keep unit tests focused on pure functions like parsing, formatting, and c
 
 
 ## Question
 ## Question
 
 
-Which exact db-worker-node endpoints and request schemas should the CLI use for ping, status, query, and export.
+Which exact db-worker-node endpoints and request schemas should the CLI use for graph/content commands.
 - Answer: all thread-apis are available in http endpoint, check @src/main/frontend/worker/db_worker_node.cljs
 - Answer: all thread-apis are available in http endpoint, check @src/main/frontend/worker/db_worker_node.cljs
 
 
 Do we want WebSocket or HTTP as the default transport for the CLI.
 Do we want WebSocket or HTTP as the default transport for the CLI.

+ 1 - 1
docs/cli/logseq-cli.md

@@ -18,7 +18,7 @@ node ./static/db-worker-node.js
 ## Run the CLI
 ## Run the CLI
 
 
 ```bash
 ```bash
-node ./static/logseq-cli.js ping --base-url http://127.0.0.1:9101
+node ./static/logseq-cli.js graph-list --base-url http://127.0.0.1:9101
 ```
 ```
 
 
 ## Configuration
 ## Configuration

+ 143 - 229
src/main/logseq/cli/commands.cljs

@@ -1,4 +1,5 @@
 (ns logseq.cli.commands
 (ns logseq.cli.commands
+  "Command parsing and action building for the Logseq CLI."
   (:require ["fs" :as fs]
   (:require ["fs" :as fs]
             [cljs-time.coerce :as tc]
             [cljs-time.coerce :as tc]
             [cljs.reader :as reader]
             [cljs.reader :as reader]
@@ -12,11 +13,7 @@
             [promesa.core :as p]))
             [promesa.core :as p]))
 
 
 (def ^:private command->keyword
 (def ^:private command->keyword
-  {"ping" :ping
-   "status" :status
-   "query" :query
-   "export" :export
-   "graph-list" :graph-list
+  {"graph-list" :graph-list
    "graph-create" :graph-create
    "graph-create" :graph-create
    "graph-switch" :graph-switch
    "graph-switch" :graph-switch
    "graph-remove" :graph-remove
    "graph-remove" :graph-remove
@@ -45,7 +42,7 @@
    [nil "--json" "Output JSON"
    [nil "--json" "Output JSON"
     :id :json?
     :id :json?
     :default false]
     :default false]
-   [nil "--format FORMAT" "Output format (tree/export)"]
+   [nil "--format FORMAT" "Output format (tree)"]
    [nil "--limit N" "Limit results"
    [nil "--limit N" "Limit results"
     :parse-fn #(js/parseInt % 10)]
     :parse-fn #(js/parseInt % 10)]
    [nil "--page PAGE" "Page name"]
    [nil "--page PAGE" "Page name"]
@@ -54,10 +51,7 @@
    [nil "--content TEXT" "Block content for add"]
    [nil "--content TEXT" "Block content for add"]
    [nil "--blocks EDN" "EDN vector of blocks for add"]
    [nil "--blocks EDN" "EDN vector of blocks for add"]
    [nil "--blocks-file PATH" "EDN file of blocks for add"]
    [nil "--blocks-file PATH" "EDN file of blocks for add"]
-   [nil "--text TEXT" "Search text"]
-   [nil "--query QUERY" "EDN query input"]
-   [nil "--file PATH" "Path to EDN query file"]
-   [nil "--out PATH" "Output path"]])
+   [nil "--text TEXT" "Search text"]])
 
 
 (defn parse-args
 (defn parse-args
   [args]
   [args]
@@ -115,21 +109,6 @@
       (first command-args)
       (first command-args)
       (:repo config)))
       (:repo config)))
 
 
-(defn- read-query
-  [{:keys [query file]}]
-  (cond
-    (seq query)
-    {:ok? true :value (reader/read-string query)}
-
-    (seq file)
-    (let [contents (.toString (fs/readFileSync file) "utf8")]
-      {:ok? true :value (reader/read-string contents)})
-
-    :else
-    {:ok? false
-     :error {:code :missing-query
-             :message "query is required"}}))
-
 (defn- read-blocks
 (defn- read-blocks
   [options command-args]
   [options command-args]
   (cond
   (cond
@@ -151,14 +130,6 @@
      :error {:code :missing-content
      :error {:code :missing-content
              :message "content is required"}}))
              :message "content is required"}}))
 
 
-(defn- ensure-vector
-  [value]
-  (if (vector? value)
-    {:ok? true :value value}
-    {:ok? false
-     :error {:code :invalid-query
-             :message "query must be a vector"}}))
-
 (defn- ensure-blocks
 (defn- ensure-blocks
   [value]
   [value]
   (if (vector? value)
   (if (vector? value)
@@ -289,6 +260,139 @@
     (when (seq graph)
     (when (seq graph)
       (graph->repo graph))))
       (graph->repo graph))))
 
 
+(defn- missing-graph-error
+  []
+  {:ok? false
+   :error {:code :missing-graph
+           :message "graph name is required"}})
+
+(defn- missing-repo-error
+  [message]
+  {:ok? false
+   :error {:code :missing-repo
+           :message message}})
+
+(defn- build-graph-action
+  [command graph repo]
+  (case command
+    :graph-list
+    {:ok? true
+     :action {:type :invoke
+              :method "thread-api/list-db"
+              :direct-pass? false
+              :args []}}
+
+    :graph-create
+    (if-not (seq graph)
+      (missing-graph-error)
+      {:ok? true
+       :action {:type :invoke
+                :method "thread-api/create-or-open-db"
+                :direct-pass? false
+                :args [repo {}]
+                :persist-repo (repo->graph repo)}})
+
+    :graph-switch
+    (if-not (seq graph)
+      (missing-graph-error)
+      {:ok? true
+       :action {:type :graph-switch
+                :repo repo
+                :graph (repo->graph repo)}})
+
+    :graph-remove
+    (if-not (seq graph)
+      (missing-graph-error)
+      {:ok? true
+       :action {:type :invoke
+                :method "thread-api/unsafe-unlink-db"
+                :direct-pass? false
+                :args [repo]}})
+
+    :graph-validate
+    (if-not (seq repo)
+      (missing-graph-error)
+      {:ok? true
+       :action {:type :invoke
+                :method "thread-api/validate-db"
+                :direct-pass? false
+                :args [repo]}})
+
+    :graph-info
+    (if-not (seq repo)
+      (missing-graph-error)
+      {:ok? true
+       :action {:type :graph-info
+                :repo repo
+                :graph (repo->graph repo)}})))
+
+(defn- build-add-action
+  [options args repo]
+  (if-not (seq repo)
+    (missing-repo-error "repo is required for add")
+    (let [blocks-result (read-blocks options args)]
+      (if-not (:ok? blocks-result)
+        blocks-result
+        (let [vector-result (ensure-blocks (:value blocks-result))]
+          (if-not (:ok? vector-result)
+            vector-result
+            {:ok? true
+             :action {:type :add
+                      :repo repo
+                      :graph (repo->graph repo)
+                      :page (:page options)
+                      :parent (:parent options)
+                      :blocks (:value vector-result)}}))))))
+
+(defn- build-remove-action
+  [options repo]
+  (if-not (seq repo)
+    (missing-repo-error "repo is required for remove")
+    (let [block (:block options)
+          page (:page options)]
+      (if (or (seq block) (seq page))
+        {:ok? true
+         :action {:type :remove
+                  :repo repo
+                  :block block
+                  :page page}}
+        {:ok? false
+         :error {:code :missing-target
+                 :message "block or page is required"}}))))
+
+(defn- build-search-action
+  [options args repo]
+  (if-not (seq repo)
+    (missing-repo-error "repo is required for search")
+    (let [text (or (:text options) (string/join " " args))]
+      (if (seq text)
+        {:ok? true
+         :action {:type :search
+                  :repo repo
+                  :text text
+                  :limit (:limit options)}}
+        {:ok? false
+         :error {:code :missing-search-text
+                 :message "search text is required"}}))))
+
+(defn- build-tree-action
+  [options repo]
+  (if-not (seq repo)
+    (missing-repo-error "repo is required for tree")
+    (let [block (:block options)
+          page (:page options)
+          target (or block page)]
+      (if (seq target)
+        {:ok? true
+         :action {:type :tree
+                  :repo repo
+                  :block block
+                  :page page
+                  :format (some-> (:format options) string/lower-case)}}
+        {:ok? false
+         :error {:code :missing-target
+                 :message "block or page is required"}}))))
+
 (defn build-action
 (defn build-action
   [parsed config]
   [parsed config]
   (if-not (:ok? parsed)
   (if-not (:ok? parsed)
@@ -297,198 +401,20 @@
           graph (pick-graph options args config)
           graph (pick-graph options args config)
           repo (resolve-repo graph)]
           repo (resolve-repo graph)]
       (case command
       (case command
-        :ping
-        {:ok? true :action {:type :ping}}
-
-        :status
-        {:ok? true :action {:type :status}}
-
-        :query
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-repo
-                   :message "repo is required for query"}}
-          (let [query-result (read-query options)]
-            (if-not (:ok? query-result)
-              query-result
-              (let [vector-result (ensure-vector (:value query-result))]
-                (if-not (:ok? vector-result)
-                  vector-result
-                  {:ok? true
-                   :action {:type :invoke
-                            :method "thread-api/q"
-                            :direct-pass? false
-                            :args [repo (:value vector-result)]}})))))
-
-        :export
-        (let [format (some-> (:format options) string/lower-case)
-              out (:out options)
-              repo repo]
-          (cond
-            (not (seq repo))
-            {:ok? false
-             :error {:code :missing-repo
-                     :message "repo is required for export"}}
-
-            (not (seq out))
-            {:ok? false
-             :error {:code :missing-output
-                     :message "output path is required"}}
-
-            (= format "edn")
-            {:ok? true
-             :action {:type :invoke
-                      :method "thread-api/export-edn"
-                      :direct-pass? false
-                      :args [repo {}]
-                      :write {:format :edn
-                              :path out}}}
-
-            (= format "db")
-            {:ok? true
-             :action {:type :invoke
-                      :method "thread-api/export-db"
-                      :direct-pass? true
-                      :args [repo]
-                      :write {:format :db
-                              :path out}}}
-
-            :else
-            {:ok? false
-             :error {:code :unsupported-format
-                     :message (str "unsupported format: " format)}}))
-
-        :graph-list
-        {:ok? true
-         :action {:type :invoke
-                  :method "thread-api/list-db"
-                  :direct-pass? false
-                  :args []}}
-
-        :graph-create
-        (if-not (seq graph)
-          {:ok? false
-           :error {:code :missing-graph
-                   :message "graph name is required"}}
-          {:ok? true
-           :action {:type :invoke
-                    :method "thread-api/create-or-open-db"
-                    :direct-pass? false
-                    :args [repo {}]
-                    :persist-repo (repo->graph repo)}})
-
-        :graph-switch
-        (if-not (seq graph)
-          {:ok? false
-           :error {:code :missing-graph
-                   :message "graph name is required"}}
-          {:ok? true
-           :action {:type :graph-switch
-                    :repo repo
-                    :graph (repo->graph repo)}})
-
-        :graph-remove
-        (if-not (seq graph)
-          {:ok? false
-           :error {:code :missing-graph
-                   :message "graph name is required"}}
-          {:ok? true
-           :action {:type :invoke
-                    :method "thread-api/unsafe-unlink-db"
-                    :direct-pass? false
-                    :args [repo]}})
-
-        :graph-validate
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-graph
-                   :message "graph name is required"}}
-          {:ok? true
-           :action {:type :invoke
-                    :method "thread-api/validate-db"
-                    :direct-pass? false
-                    :args [repo]}})
-
-        :graph-info
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-graph
-                   :message "graph name is required"}}
-          {:ok? true
-           :action {:type :graph-info
-                    :repo repo
-                    :graph (repo->graph repo)}})
+        (:graph-list :graph-create :graph-switch :graph-remove :graph-validate :graph-info)
+        (build-graph-action command graph repo)
 
 
         :add
         :add
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-repo
-                   :message "repo is required for add"}}
-          (let [blocks-result (read-blocks options args)]
-            (if-not (:ok? blocks-result)
-              blocks-result
-              (let [vector-result (ensure-blocks (:value blocks-result))]
-                (if-not (:ok? vector-result)
-                  vector-result
-                  {:ok? true
-                   :action {:type :add
-                            :repo repo
-                            :graph (repo->graph repo)
-                            :page (:page options)
-                            :parent (:parent options)
-                            :blocks (:value vector-result)}})))))
+        (build-add-action options args repo)
 
 
         :remove
         :remove
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-repo
-                   :message "repo is required for remove"}}
-          (let [block (:block options)
-                page (:page options)]
-            (if (or (seq block) (seq page))
-              {:ok? true
-               :action {:type :remove
-                        :repo repo
-                        :block block
-                        :page page}}
-              {:ok? false
-               :error {:code :missing-target
-                       :message "block or page is required"}})))
+        (build-remove-action options repo)
 
 
         :search
         :search
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-repo
-                   :message "repo is required for search"}}
-          (let [text (or (:text options) (string/join " " args))]
-            (if (seq text)
-              {:ok? true
-               :action {:type :search
-                        :repo repo
-                        :text text
-                        :limit (:limit options)}}
-              {:ok? false
-               :error {:code :missing-search-text
-                       :message "search text is required"}})))
+        (build-search-action options args repo)
 
 
         :tree
         :tree
-        (if-not (seq repo)
-          {:ok? false
-           :error {:code :missing-repo
-                   :message "repo is required for tree"}}
-          (let [block (:block options)
-                page (:page options)
-                target (or block page)]
-            (if (seq target)
-              {:ok? true
-               :action {:type :tree
-                        :repo repo
-                        :block block
-                        :page page
-                        :format (some-> (:format options) string/lower-case)}}
-              {:ok? false
-               :error {:code :missing-target
-                       :message "block or page is required"}})))
+        (build-tree-action options repo)
 
 
         {:ok? false
         {:ok? false
          :error {:code :unknown-command
          :error {:code :unknown-command
@@ -497,18 +423,6 @@
 (defn execute
 (defn execute
   [action config]
   [action config]
   (case (:type action)
   (case (:type action)
-    :ping
-    (-> (transport/ping config)
-        (p/then (fn [_]
-                  {:status :ok :data {:message "ok"}})))
-
-    :status
-    (-> (p/let [ready? (transport/ready config)
-                dbs (transport/list-db config)]
-          {:status :ok
-           :data {:ready ready?
-                  :dbs dbs}}))
-
     :invoke
     :invoke
     (-> (p/let [result (transport/invoke config
     (-> (p/let [result (transport/invoke config
                                          (:method action)
                                          (:method action)

+ 4 - 3
src/main/logseq/cli/config.cljs

@@ -1,10 +1,11 @@
 (ns logseq.cli.config
 (ns logseq.cli.config
+  "CLI configuration resolution and persistence."
   (:require [cljs.reader :as reader]
   (:require [cljs.reader :as reader]
             [clojure.string :as string]
             [clojure.string :as string]
             [goog.object :as gobj]
             [goog.object :as gobj]
             ["fs" :as fs]
             ["fs" :as fs]
             ["os" :as os]
             ["os" :as os]
-            ["path" :as path]))
+            ["path" :as node-path]))
 
 
 (defn- parse-int
 (defn- parse-int
   [value]
   [value]
@@ -13,7 +14,7 @@
 
 
 (defn- default-config-path
 (defn- default-config-path
   []
   []
-  (path/join (.homedir os) ".logseq" "cli.edn"))
+  (node-path/join (.homedir os) ".logseq" "cli.edn"))
 
 
 (defn- read-config-file
 (defn- read-config-file
   [config-path]
   [config-path]
@@ -24,7 +25,7 @@
 (defn- ensure-config-dir!
 (defn- ensure-config-dir!
   [config-path]
   [config-path]
   (when (seq config-path)
   (when (seq config-path)
-    (let [dir (path/dirname config-path)]
+    (let [dir (node-path/dirname config-path)]
       (when (and (seq dir) (not (fs/existsSync dir)))
       (when (and (seq dir) (not (fs/existsSync dir)))
         (.mkdirSync fs dir #js {:recursive true})))))
         (.mkdirSync fs dir #js {:recursive true})))))
 
 

+ 2 - 2
src/main/logseq/cli/format.cljs

@@ -1,6 +1,6 @@
 (ns logseq.cli.format
 (ns logseq.cli.format
-  (:require [clojure.string :as string]
-            [clojure.walk :as walk]))
+  "Formatting helpers for CLI output."
+  (:require [clojure.walk :as walk]))
 
 
 (defn- normalize-json
 (defn- normalize-json
   [value]
   [value]

+ 4 - 3
src/main/logseq/cli/main.cljs

@@ -1,4 +1,5 @@
 (ns logseq.cli.main
 (ns logseq.cli.main
+  "CLI entrypoint for invoking db-worker-node."
   (:refer-clojure :exclude [run!])
   (:refer-clojure :exclude [run!])
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
             [logseq.cli.commands :as commands]
             [logseq.cli.commands :as commands]
@@ -11,14 +12,14 @@
   (string/join "\n"
   (string/join "\n"
                ["logseq-cli <command> [options]"
                ["logseq-cli <command> [options]"
                 ""
                 ""
-                "Commands: ping, status, query, export, graph-list, graph-create, graph-switch, graph-remove, graph-validate, graph-info, add, remove, search, tree"
+                "Commands: graph-list, graph-create, graph-switch, graph-remove, graph-validate, graph-info, add, remove, search, tree"
                 ""
                 ""
                 "Options:"
                 "Options:"
                 summary]))
                 summary]))
 
 
 (defn run!
 (defn run!
-  ([args] (run! args {:exit? true}))
-  ([args {:keys [exit?] :or {exit? true}}]
+  ([args] (run! args {}))
+  ([args _opts]
    (let [parsed (commands/parse-args args)]
    (let [parsed (commands/parse-args args)]
      (cond
      (cond
        (:help? parsed)
        (:help? parsed)

+ 18 - 37
src/main/logseq/cli/transport.cljs

@@ -1,4 +1,5 @@
 (ns logseq.cli.transport
 (ns logseq.cli.transport
+  "HTTP transport for communicating with db-worker-node."
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
             [logseq.db :as ldb]
             [logseq.db :as ldb]
             [promesa.core :as p]
             [promesa.core :as p]
@@ -66,39 +67,23 @@
 (defn request
 (defn request
   [{:keys [method url headers body timeout-ms retries]
   [{:keys [method url headers body timeout-ms retries]
     :or {retries 0}}]
     :or {retries 0}}]
-  (p/loop [attempt 0]
-    (-> (p/let [response (<raw-request {:method method
-                                        :url url
-                                        :headers headers
-                                        :body body
-                                        :timeout-ms timeout-ms})]
-          (if (<= 200 (:status response) 299)
-            response
-            (throw (ex-info "http request failed"
-                            {:code :http-error
-                             :status (:status response)
-                             :body (:body response)}))))
-        (p/catch (fn [error]
-                   (if (and (< attempt retries) (retryable-error? error))
-                     (p/recur (inc attempt))
-                     (throw error)))))))
-
-(defn ping
-  [{:keys [base-url timeout-ms retries]}]
-  (request {:method "GET"
-            :url (str (string/replace base-url #"/$" "") "/healthz")
-            :timeout-ms timeout-ms
-            :retries retries
-            :headers {}}))
-
-(defn ready
-  [{:keys [base-url timeout-ms retries]}]
-  (-> (request {:method "GET"
-                :url (str (string/replace base-url #"/$" "") "/readyz")
-                :timeout-ms timeout-ms
-                :retries retries
-                :headers {}})
-      (p/then (fn [_] true))))
+  (letfn [(attempt-request [attempt]
+            (-> (p/let [response (<raw-request {:method method
+                                                :url url
+                                                :headers headers
+                                                :body body
+                                                :timeout-ms timeout-ms})]
+                  (if (<= 200 (:status response) 299)
+                    response
+                    (throw (ex-info "http request failed"
+                                    {:code :http-error
+                                     :status (:status response)
+                                     :body (:body response)}))))
+                (p/catch (fn [error]
+                           (if (and (< attempt retries) (retryable-error? error))
+                             (attempt-request (inc attempt))
+                             (throw error))))))]
+    (attempt-request 0)))
 
 
 (defn invoke
 (defn invoke
   [{:keys [base-url auth-token timeout-ms retries]}
   [{:keys [base-url auth-token timeout-ms retries]}
@@ -123,10 +108,6 @@
         result
         result
         (ldb/read-transit-str resultTransit)))))
         (ldb/read-transit-str resultTransit)))))
 
 
-(defn list-db
-  [config]
-  (invoke config "thread-api/list-db" false []))
-
 (defn write-output
 (defn write-output
   [{:keys [format path data]}]
   [{:keys [format path data]}]
   (case format
   (case format

+ 5 - 37
src/test/logseq/cli/commands_test.cljs

@@ -3,10 +3,11 @@
             [logseq.cli.commands :as commands]))
             [logseq.cli.commands :as commands]))
 
 
 (deftest test-parse-args
 (deftest test-parse-args
-  (testing "parses ping"
-    (let [result (commands/parse-args ["ping"])]
-      (is (true? (:ok? result)))
-      (is (= :ping (:command result)))))
+  (testing "rejects removed commands"
+    (doseq [command ["ping" "status" "query" "export"]]
+      (let [result (commands/parse-args [command])]
+        (is (false? (:ok? result)))
+        (is (= :unknown-command (get-in result [:error :code]))))))
 
 
   (testing "errors on missing command"
   (testing "errors on missing command"
     (let [result (commands/parse-args [])]
     (let [result (commands/parse-args [])]
@@ -18,39 +19,6 @@
       (is (false? (:ok? result)))
       (is (false? (:ok? result)))
       (is (= :unknown-command (get-in result [:error :code]))))))
       (is (= :unknown-command (get-in result [:error :code]))))))
 
 
-(deftest test-build-action
-  (testing "query requires repo"
-    (let [parsed {:ok? true
-                  :command :query
-                  :options {:query "[:find ?e :where [?e :block/name]]"}}
-          result (commands/build-action parsed {})]
-      (is (false? (:ok? result)))
-      (is (= :missing-repo (get-in result [:error :code])))))
-
-  (testing "query uses repo from config"
-    (let [parsed {:ok? true
-                  :command :query
-                  :options {:query "[:find ?e :where [?e :block/name]]"}}
-          result (commands/build-action parsed {:repo "test-repo"})]
-      (is (true? (:ok? result)))
-      (is (= "thread-api/q" (get-in result [:action :method])))))
-
-  (testing "export rejects unsupported format"
-    (let [parsed {:ok? true
-                  :command :export
-                  :options {:repo "repo" :format "nope" :out "output.edn"}}
-          result (commands/build-action parsed {})]
-      (is (false? (:ok? result)))
-      (is (= :unsupported-format (get-in result [:error :code])))))
-
-  (testing "export builds edn action"
-    (let [parsed {:ok? true
-                  :command :export
-                  :options {:repo "repo" :format "edn" :out "output.edn"}}
-          result (commands/build-action parsed {})]
-      (is (true? (:ok? result)))
-      (is (= "thread-api/export-edn" (get-in result [:action :method]))))))
-
 (deftest test-graph-commands
 (deftest test-graph-commands
   (testing "graph-list uses list-db"
   (testing "graph-list uses list-db"
     (let [parsed {:ok? true :command :graph-list :options {}}
     (let [parsed {:ok? true :command :graph-list :options {}}

+ 5 - 5
src/test/logseq/cli/config_test.cljs

@@ -1,11 +1,11 @@
 (ns logseq.cli.config-test
 (ns logseq.cli.config-test
   (:require [cljs.reader :as reader]
   (:require [cljs.reader :as reader]
-            [cljs.test :refer [deftest is testing]]
+            [cljs.test :refer [deftest is]]
             [frontend.test.node-helper :as node-helper]
             [frontend.test.node-helper :as node-helper]
             [goog.object :as gobj]
             [goog.object :as gobj]
             [logseq.cli.config :as config]
             [logseq.cli.config :as config]
             ["fs" :as fs]
             ["fs" :as fs]
-            ["path" :as path]))
+            ["path" :as node-path]))
 
 
 (defn- with-env
 (defn- with-env
   [env f]
   [env f]
@@ -21,7 +21,7 @@
 
 
 (deftest test-config-precedence
 (deftest test-config-precedence
   (let [dir (node-helper/create-tmp-dir)
   (let [dir (node-helper/create-tmp-dir)
-        cfg-path (path/join dir "cli.edn")
+        cfg-path (node-path/join dir "cli.edn")
         _ (fs/writeFileSync cfg-path
         _ (fs/writeFileSync cfg-path
                             (str "{:base-url \"http://file:7777\" "
                             (str "{:base-url \"http://file:7777\" "
                                  ":auth-token \"file-token\" "
                                  ":auth-token \"file-token\" "
@@ -53,7 +53,7 @@
 
 
 (deftest test-env-overrides-file
 (deftest test-env-overrides-file
   (let [dir (node-helper/create-tmp-dir)
   (let [dir (node-helper/create-tmp-dir)
-        cfg-path (path/join dir "cli.edn")
+        cfg-path (node-path/join dir "cli.edn")
         _ (fs/writeFileSync cfg-path "{:base-url \"http://file:7777\" :repo \"file-repo\"}")
         _ (fs/writeFileSync cfg-path "{:base-url \"http://file:7777\" :repo \"file-repo\"}")
         env {"LOGSEQ_DB_WORKER_URL" "http://env:9999"
         env {"LOGSEQ_DB_WORKER_URL" "http://env:9999"
              "LOGSEQ_CLI_REPO" "env-repo"}
              "LOGSEQ_CLI_REPO" "env-repo"}
@@ -63,7 +63,7 @@
 
 
 (deftest test-update-config
 (deftest test-update-config
   (let [dir (node-helper/create-tmp-dir "cli")
   (let [dir (node-helper/create-tmp-dir "cli")
-        cfg-path (path/join dir "cli.edn")
+        cfg-path (node-path/join dir "cli.edn")
         _ (fs/writeFileSync cfg-path "{:repo \"old\"}")
         _ (fs/writeFileSync cfg-path "{:repo \"old\"}")
         _ (config/update-config! {:config-path cfg-path} {:repo "new"})
         _ (config/update-config! {:config-path cfg-path} {:repo "new"})
         contents (.toString (fs/readFileSync cfg-path) "utf8")
         contents (.toString (fs/readFileSync cfg-path) "utf8")

+ 4 - 20
src/test/logseq/cli/integration_test.cljs

@@ -5,7 +5,7 @@
             [logseq.cli.main :as cli-main]
             [logseq.cli.main :as cli-main]
             [promesa.core :as p]
             [promesa.core :as p]
             ["fs" :as fs]
             ["fs" :as fs]
-            ["path" :as path]))
+            ["path" :as node-path]))
 
 
 (defn- run-cli
 (defn- run-cli
   [args url cfg-path]
   [args url cfg-path]
@@ -16,22 +16,6 @@
   [result]
   [result]
   (js->clj (js/JSON.parse (:output result)) :keywordize-keys true))
   (js->clj (js/JSON.parse (:output result)) :keywordize-keys true))
 
 
-(deftest test-cli-ping
-  (async done
-    (let [data-dir (node-helper/create-tmp-dir "db-worker")]
-      (-> (p/let [daemon (db-worker-node/start-daemon! {:host "127.0.0.1"
-                                                        :port 0
-                                                        :data-dir data-dir})
-                  url (str "http://127.0.0.1:" (:port daemon))
-                  result (cli-main/run! ["ping" "--base-url" url "--json"] {:exit? false})]
-            (is (= 0 (:exit-code result)))
-            (is (= "{\"status\":\"ok\",\"data\":{\"message\":\"ok\"}}" (:output result)))
-            (p/let [_ ((:stop! daemon))]
-              (done)))
-          (p/catch (fn [e]
-                     (is false (str "unexpected error: " e))
-                     (done)))))))
-
 (deftest test-cli-graph-list
 (deftest test-cli-graph-list
   (async done
   (async done
     (let [data-dir (node-helper/create-tmp-dir "db-worker")]
     (let [data-dir (node-helper/create-tmp-dir "db-worker")]
@@ -39,7 +23,7 @@
                                                         :port 0
                                                         :port 0
                                                         :data-dir data-dir})
                                                         :data-dir data-dir})
                   url (str "http://127.0.0.1:" (:port daemon))
                   url (str "http://127.0.0.1:" (:port daemon))
-                  cfg-path (path/join (node-helper/create-tmp-dir "cli") "cli.edn")
+                  cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
                   result (run-cli ["graph-list"] url cfg-path)
                   result (run-cli ["graph-list"] url cfg-path)
                   payload (parse-json-output result)]
                   payload (parse-json-output result)]
             (is (= 0 (:exit-code result)))
             (is (= 0 (:exit-code result)))
@@ -58,7 +42,7 @@
                                                         :port 0
                                                         :port 0
                                                         :data-dir data-dir})
                                                         :data-dir data-dir})
                   url (str "http://127.0.0.1:" (:port daemon))
                   url (str "http://127.0.0.1:" (:port daemon))
-                  cfg-path (path/join (node-helper/create-tmp-dir "cli") "cli.edn")
+                  cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
                   _ (fs/writeFileSync cfg-path "{}")
                   _ (fs/writeFileSync cfg-path "{}")
                   create-result (run-cli ["graph-create" "--graph" "demo-graph"] url cfg-path)
                   create-result (run-cli ["graph-create" "--graph" "demo-graph"] url cfg-path)
                   create-payload (parse-json-output create-result)
                   create-payload (parse-json-output create-result)
@@ -82,7 +66,7 @@
                                                         :port 0
                                                         :port 0
                                                         :data-dir data-dir})
                                                         :data-dir data-dir})
                   url (str "http://127.0.0.1:" (:port daemon))
                   url (str "http://127.0.0.1:" (:port daemon))
-                  cfg-path (path/join (node-helper/create-tmp-dir "cli") "cli.edn")
+                  cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
                   _ (fs/writeFileSync cfg-path "{}")
                   _ (fs/writeFileSync cfg-path "{}")
                   _ (run-cli ["graph-create" "--graph" "content-graph"] url cfg-path)
                   _ (run-cli ["graph-create" "--graph" "content-graph"] url cfg-path)
                   add-result (run-cli ["add" "--page" "TestPage" "--content" "hello world"] url cfg-path)
                   add-result (run-cli ["add" "--page" "TestPage" "--content" "hello world"] url cfg-path)

+ 1 - 1
src/test/logseq/cli/transport_test.cljs

@@ -1,5 +1,5 @@
 (ns logseq.cli.transport-test
 (ns logseq.cli.transport-test
-  (:require [cljs.test :refer [deftest is async testing]]
+  (:require [cljs.test :refer [deftest is async]]
             [promesa.core :as p]
             [promesa.core :as p]
             [logseq.cli.transport :as transport]))
             [logseq.cli.transport :as transport]))