Ctrl K
ComunidadGuías…

cli-e2e/spec/non_sync_cases.edn

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
{:templates
 {:non-sync/graph-json-env
  {:setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{graph-arg}} >/dev/null"],
   :cleanup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}}"]},
  :non-sync/graph-json-secondary-env
  {:extends :non-sync/graph-json-env,
   :vars
   {:secondary-graph "graph-two", :secondary-graph-arg "graph-two"},
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{secondary-graph-arg}} >/dev/null"],
   :cleanup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{secondary-graph-arg}}"]},
  :non-sync/source-graph-json-env
  {:extends :non-sync/graph-json-secondary-env,
   :vars
   {:secondary-graph "source-graph",
    :secondary-graph-arg "source-graph"}},
  :non-sync/example-command
  {:tags [:example],
   :covers {:options {:global ["--output"]}},
   :expect {:exit 0},
   :vars {:example-output "json"},
   :cmds
   ["{{cli}} --output {{example-output}} example {{example-selector}}"]},
  :non-sync/example-human-command
  {:extends :non-sync/example-command,
   :vars {:example-output "human"}},
  :non-sync/example-json-command
  {:extends :non-sync/example-command,
   :expect {:stdout-json-paths {[:status] "ok"}}},
  :non-sync/example-edn-command
  {:extends :non-sync/example-command,
   :vars {:example-output "edn"},
   :expect {:stdout-edn-paths {[:status] :ok}}},
  :non-sync/completion-command
  {:tags [:completion],
   :covers {:commands ["completion"]},
   :expect {:exit 0},
   :cmds ["{{cli}} completion {{completion-selector}}"]}},
 :cases
 [{:id "global-help",
   :cmds ["{{cli}} --help"],
   :expect
   {:exit 0,
    :stdout-contains
    ["Usage: logseq <command> [options]" "graph create" "completion"]},
   :covers {:options {:global ["--help"]}},
   :tags [:global :smoke]}
  {:id "global-version",
   :cmds ["{{cli}} --version"],
   :expect {:exit 0, :stdout-contains ["Build time:" "Revision:"]},
   :covers {:options {:global ["--version"]}},
   :tags [:global :smoke]}
  {:id "verbose-graph-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --verbose graph list"],
   :expect
   {:exit 0,
    :stderr-contains [":cli/parsed-options"],
    :stdout-json-paths {[:status] "ok"}},
   :covers
   {:commands ["graph list"],
    :options
    {:global ["--config" "--root-dir" "--output" "--verbose"]}},
   :tags [:global :graph]}
  {:id "graph-create-and-info-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{graph-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph info --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok", [:data :graph] "{{graph}}"}},
   :covers
   {:commands ["graph create" "graph info"],
    :options {:global ["--config" "--graph" "--root-dir" "--output"]}},
   :cleanup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}}"],
   :tags [:graph :smoke]}
  {:id "graph-list-human",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human graph list"],
   :expect {:exit 0, :stdout-contains ["{{graph}}"]},
   :covers
   {:commands ["graph list"],
    :options {:global ["--config" "--root-dir" "--output"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:id "graph-list-edn",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output edn graph list"],
   :expect
   {:exit 0,
    :stdout-edn-paths {[:status] :ok, [:data :graphs] ["{{graph}}"]}},
   :covers
   {:commands ["graph list"],
    :options {:global ["--config" "--root-dir" "--output"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:tags [:graph],
   :extends :non-sync/graph-json-secondary-env,
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :message] "switched to {{secondary-graph}}"}},
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph switch --graph {{secondary-graph-arg}}"],
   :id "graph-switch-json",
   :covers
   {:commands ["graph switch"],
    :options {:global ["--config" "--graph" "--root-dir" "--output"]}}}
  {:id "graph-validate-fix-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph validate --graph {{graph-arg}} --fix"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok", [:data :result :errors] nil}},
   :covers
   {:commands ["graph validate"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--fix"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:id "graph-export-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page ExportHome >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph export --graph {{graph-arg}} --type edn --file {{export-path-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["{{export-path}}"]},
   :covers
   {:commands ["graph export"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--file"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:id "graph-export-edn",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page ExportOptionsHome >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph export --graph {{graph-arg}} --type edn --file {{export-path-arg}} --edn-options '{:export-type :graph-human}' --pretty-print"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["{{export-path}}"]},
   :covers
   {:commands ["graph export"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--file" "--edn-options" "--pretty-print"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:id "graph-export-selected-nodes-edn-options",
   :setup
   ["printf '%s' '{:pages-and-blocks [{:page {:block/title \"Export Contract Page\"} :blocks [{:block/title \"selected node survives export\" :block/uuid #uuid \"13071000-0000-4000-8000-000000000001\" :build/keep-uuid? true}]}]}' > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph export --graph {{graph-arg}} --type edn --file {{export-path-arg}} --edn-options '{:export-type :selected-nodes :node-ids [[:block/uuid #uuid \"13071000-0000-4000-8000-000000000001\"]]}' >/dev/null"
    "grep -q 'selected node survives export' {{export-path-arg}}"],
   :expect {:exit 0},
   :covers
   {:commands ["graph export"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--file" "--edn-options"]}},
   :tags [:graph],
   :extends :non-sync/graph-json-env}
  {:id "graph-export-edn-options-timestamps"
   :extends :non-sync/graph-json-env
   :tags [:graph :edn-options]
   :setup ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} upsert page --page TimestampPage >/dev/null"
           "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} upsert block --target-page TimestampPage --content TimestampBlock >/dev/null"]
   :cmds ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output edn --graph {{graph-arg}} query --query '[:find (pull ?e [:block/title :block/created-at :block/updated-at]) :where [?e :block/title ?t] [(contains? #{\"TimestampPage\" \"TimestampBlock\"} ?t)]]' > {{export-path-arg}}.stored"
          "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} graph export --type edn --file {{export-path-arg}} --edn-options '{:export-type :graph-human :graph-options {:include-timestamps? true}}' >/dev/null"
          "bb -e '(require (quote [clojure.edn :as edn])) (let [read-edn #(edn/read-string {:readers {(quote transit/time) identity}} (slurp %)) x (read-edn (first *command-line-args*)) stored (-> (read-edn (second *command-line-args*)) :data :result) p (first (filter #(= \"TimestampPage\" (get-in % [:page :block/title])) (:pages-and-blocks x))) actual (into {} (map (juxt :block/title identity) (cons (:page p) (:blocks p))))] (assert (= 2 (count stored))) (doseq [[node] stored k [:block/created-at :block/updated-at]] (assert (some? (get node k))) (assert (= (get node k) (get-in actual [(:block/title node) k])))))' {{export-path-arg}} {{export-path-arg}}.stored"]
   :expect {:exit 0}
   :covers {:commands ["graph export"] :options {:graph ["--edn-options"]}}}
  {:id "graph-export-edn-options-partial"
   :extends :non-sync/graph-json-env
   :tags [:graph :edn-options]
   :setup ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} upsert page --page TimestampPage >/dev/null"
           "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} upsert block --target-page TimestampPage --content TimestampBlock >/dev/null"]
   :cmds ["BLOCK_ID=$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} query --query '[:find ?e . :where [?e :block/title \"TimestampBlock\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])'); PAGE_ID=$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} query --query '[:find ?e . :where [?e :block/title \"TimestampPage\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])'); BLOCK_UUID=$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} query --query '[:find ?u . :where [?e :block/title \"TimestampBlock\"] [?e :block/uuid ?u]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])'); for options in \"{:export-type :block :block-id $BLOCK_ID}\" \"{:export-type :page :page-id $PAGE_ID}\" \"{:export-type :selected-nodes :node-ids [[:block/uuid #uuid \\\"$BLOCK_UUID\\\"]]}\" \"{:export-type :view-nodes :rows [#uuid \\\"$BLOCK_UUID\\\"] :group-by? false}\" \"{:export-type :view-nodes :rows {{:arbitrary-label true} [$BLOCK_ID]} :group-by? true}\"; do {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} graph export --type edn --file {{export-path-arg}} --edn-options \"$options\" >/dev/null || exit 1; grep -q TimestampBlock {{export-path-arg}} || exit 1; done"
          "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} graph export --type edn --file {{export-path-arg}} --edn-options '{:export-type :graph-ontology :graph-options {:catch-validation-errors? false}}' >/dev/null"
          "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json --graph {{graph-arg}} graph export --type edn --file {{export-path-arg}} --edn-options '{}' >/dev/null"
          "grep -q ':datoms' {{export-path-arg}}"]
   :expect {:exit 0}
   :covers {:commands ["graph export"] :options {:graph ["--edn-options"]}}}
  {:id "graph-export-edn-options-invalid"
   :extends :non-sync/graph-json-env
   :tags [:graph :edn-options]
   :setup []
   :cmds ["set -eu; printf 'existing export\\n' > {{export-path-arg}}; cp {{export-path-arg}} {{export-path-arg}}.original; for mode in human json edn; do for options in '{:export-type :graph-human :include-timestamps? true}' '{:export-type :graph-human :include-timestamps? false :graph-options {:include-timestamps? true}}' '{:export-type :graph-human :graph-options {:typo true}}' '{:no-such-option true}' '{:export-type :graph-human :graph-options {:catch-validation-errors? true :include-timestamps? nil}}' '{:export-type :block}' '{:graph-options {:include-timestamps? false}}'; do for file in {{export-path-arg}} {{export-path-arg}}.absent; do if {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output \"$mode\" --graph {{graph-arg}} graph export --type edn --file \"$file\" --edn-options \"$options\" > {{export-path-arg}}.error; then cat {{export-path-arg}}.error; exit 1; fi; grep -q invalid-options {{export-path-arg}}.error; cmp {{export-path-arg}} {{export-path-arg}}.original; test ! -e {{export-path-arg}}.absent; done; done; done"]
   :expect {:exit 0}
   :covers {:commands ["graph export"] :options {:graph ["--edn-options"]}}}
  {:tags [:graph],
   :extends :non-sync/source-graph-json-env,
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["Imported edn from" "{{export-path}}"]},
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{secondary-graph-arg}} --page ImportSeed >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph export --graph {{secondary-graph-arg}} --type edn --file {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}}"],
   :id "graph-import-json",
   :covers
   {:commands ["graph import"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"]}}}
  {:tags [:graph],
   :extends :non-sync/graph-json-env,
   :expect {:exit 0, :stdout-json-paths {[:status] "ok"}},
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page BackupSeed >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup create --graph {{graph-arg}} --name nightly >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup list --graph {{graph-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup restore --graph {{graph-arg}} --src \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup list --graph {{graph-arg}} | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"backups\"][0][\"name\"])')\" --dst {{restore-graph-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup remove --graph {{graph-arg}} --src \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup list --graph {{graph-arg}} | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"backups\"][0][\"name\"])')\""],
   :id "graph-backup-lifecycle-json",
   :covers
   {:commands
    ["graph backup create"
     "graph backup list"
     "graph backup restore"
     "graph backup remove"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--name" "--src" "--dst"]}},
   :vars
   {:restore-graph "backup-restore",
    :restore-graph-arg "backup-restore"},
   :cleanup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{restore-graph-arg}}"]}
  {:id "page-upsert-and-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list page --graph {{graph-arg}} --fields title,id --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :items 0 :block/title] "Home"}},
   :covers
   {:commands ["upsert page" "list page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--page"],
     :list ["--fields" "--limit" "--sort" "--order"]}},
   :tags [:upsert :list :smoke],
   :extends :non-sync/graph-json-env}
  {:id "task-upsert-and-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --page TaskHome --status todo --priority high --scheduled '2026-02-10T08:00:00.000Z' --deadline '2026-02-12T18:00:00.000Z' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list task --graph {{graph-arg}} --status todo --priority high --content task --fields id,title,status,priority,scheduled,deadline --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :items 0 :block/title] "TaskHome",
     [:data :items 0 :logseq.property/status]
     "logseq.property/status.todo",
     [:data :items 0 :logseq.property/priority]
     "logseq.property/priority.high",
     [:data :items 0 :logseq.property/scheduled] 1770710400000,
     [:data :items 0 :logseq.property/deadline] 1770919200000}},
   :covers
   {:commands ["upsert task" "list task"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert
     ["--page" "--status" "--priority" "--scheduled" "--deadline"],
     :list
     ["--status"
      "--priority"
      "--content"
      "--fields"
      "--limit"
      "--sort"
      "--order"]}},
   :tags [:upsert :list :smoke],
   :extends :non-sync/graph-json-env}
  {:id "task-upsert-clear-properties-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --page TaskHome --status todo --priority high --scheduled '2026-02-10T08:00:00.000Z' --deadline '2026-02-12T18:00:00.000Z' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --page TaskHome --no-status --no-priority --no-scheduled --no-deadline >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list task --graph {{graph-arg}} --content taskhome --fields id,title,status,priority,scheduled,deadline --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :items 0 :block/title] "TaskHome"},
    :stdout-not-contains
    ["logseq.property/priority.high"
     "2026-02-10T08:00:00.000Z"
     "2026-02-12T18:00:00.000Z"]},
   :covers
   {:commands ["upsert task" "list task"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert
     ["--page"
      "--no-status"
      "--no-priority"
      "--no-scheduled"
      "--no-deadline"],
     :list ["--content" "--fields" "--limit" "--sort" "--order"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "task-upsert-set-clear-conflict-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --page TaskHome --status todo --no-status"],
   :expect
   {:exit 1,
    :stdout-contains
    ["invalid-options"
     "--status and --no-status are mutually exclusive"]},
   :covers
   {:commands ["upsert task"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--page" "--status" "--no-status"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "page-upsert-invalid-update-properties-atomic-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name AtomicTag >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page AtomicPage --update-tags '[\"AtomicTag\"]' --update-properties '{:missing-prop \"value\"}'"],
   :expect
   {:exit 1,
    :stdout-json-paths
    {[:status] "error",
     [:error :code] "property-not-found",
     [:error :option] "--update-properties",
     [:error :phase] "resolve-options"},
    :stdout-contains ["missing-prop"]},
   :covers
   {:commands ["upsert page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--page" "--update-tags" "--update-properties"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "node-list-by-tags-properties-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name NodeTag >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name node-prop >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page NodeHome --update-tags '[\"NodeTag\"]' --update-properties '{:node-prop \"v\"}' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list node --graph {{graph-arg}} --tags NodeTag --properties node-prop --fields id,title,type --sort updated-at --order desc --limit 20"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :items 0 :block/title] "NodeHome",
     [:data :items 0 :node/type] "page"}},
   :covers
   {:commands
    ["upsert tag" "upsert property" "upsert page" "list node"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--name" "--page" "--update-tags" "--update-properties"],
     :list
     ["--tags"
      "--properties"
      "--fields"
      "--limit"
      "--sort"
      "--order"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "node-list-renders-block-ref-labels-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name RefNodeTag >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page RefNodePage >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content \"Task [[$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"RefNodePage\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')]]\" --update-tags '[\"RefNodeTag\"]' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list node --graph {{graph-arg}} --tags RefNodeTag --fields id,title,type --sort updated-at --order desc --limit 20"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["Task [[RefNodePage]]"]},
   :covers
   {:commands ["upsert tag" "upsert page" "upsert block" "list node"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--name" "--page" "--target-page" "--content" "--update-tags"],
     :list ["--tags" "--fields" "--limit" "--sort" "--order"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "asset-upsert-and-list-json",
   :setup ["printf 'asset-content' > {{export-path-arg}}.png"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert asset --graph {{graph-arg}} --path {{export-path-arg}}.png --content 'Asset One' --target-page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list asset --graph {{graph-arg}} --fields id,title,asset-type,size --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :items 0 :block/title] "Asset One",
     [:data :items 0 :logseq.property.asset/type] "png",
     [:data :items 0 :logseq.property.asset/size] 13}},
   :covers
   {:commands ["upsert asset" "list asset"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--path" "--content" "--target-page"],
     :list ["--fields" "--limit" "--sort" "--order"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "asset-upsert-update-json",
   :setup
   ["printf 'asset-content' > {{export-path-arg}}.png"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert asset --graph {{graph-arg}} --path {{export-path-arg}}.png --content 'Asset Original' --target-page Home >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert asset --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Asset Original\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --content 'Asset Updated' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list asset --graph {{graph-arg}} --fields id,title --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :items 0 :block/title] "Asset Updated"}},
   :covers
   {:commands ["upsert asset" "list asset"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--id" "--content"],
     :list ["--fields" "--limit" "--sort" "--order"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "page-rename",
   :extends :non-sync/graph-json-env,
   :cmds ["python3 '{{repo-root}}/cli-e2e/scripts/page_rename.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}}"],
   :expect {:exit 0},
   :covers {:commands ["upsert page"], :options {:upsert ["--id" "--page" "--rename" "--update-properties"]}},
   :tags [:upsert :page]}
  {:id "created-entity-result-metadata",
   :extends :non-sync/graph-json-env,
   :cmds ["python3 '{{repo-root}}/cli-e2e/scripts/created_entity_results.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --case metadata"],
   :expect {:exit 0},
   :tags [:upsert :created-entity-result]}
  {:id "created-entity-result-block",
   :extends :non-sync/graph-json-env,
   :cmds ["python3 '{{repo-root}}/cli-e2e/scripts/created_entity_results.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --case block"],
   :expect {:exit 0},
   :tags [:upsert :created-entity-result]}
  {:id "created-entity-result-task",
   :extends :non-sync/graph-json-env,
   :cmds ["python3 '{{repo-root}}/cli-e2e/scripts/created_entity_results.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --case task"],
   :expect {:exit 0},
   :tags [:upsert :created-entity-result]}
  {:id "created-entity-result-asset",
   :extends :non-sync/graph-json-env,
   :cmds ["python3 '{{repo-root}}/cli-e2e/scripts/created_entity_results.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --case asset"],
   :expect {:exit 0},
   :tags [:upsert :created-entity-result]}
  {:id "block-upsert-and-show-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json show --graph {{graph-arg}} --page Home --level 2 --linked-references false"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :root :block/children 0 :block/title] "Alpha block"}},
   :covers
   {:commands ["upsert block" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--target-page" "--content"],
     :show ["--page" "--level" "--linked-references"]}},
   :tags [:upsert :show :smoke],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-page-link-appears-in-linked-references-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page bar_page >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page 'Jul 1st, 2026' --pos last-child --content 'Foo links to [[bar_page]]' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json show --graph {{graph-arg}} --page bar_page --linked-references true --level 2"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :linked-references :count] 1}},
   :covers
   {:commands ["upsert page" "upsert block" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--page" "--target-page" "--pos" "--content"],
     :show ["--page" "--linked-references" "--level"]}},
   :tags [:upsert :show],
   :extends :non-sync/graph-json-env}
  {:id "show-page-default-content-json",
   :setup
   ["printf '%s' '{:pages-and-blocks [{:page {:block/title \"Foo\"} :blocks [{:block/title \"Foo normal content\"}]}]}' > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "FOO_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Foo\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Hierarchy Bar Page\\\" :block/parent {:db/id $FOO_ID}} :blocks [{:block/title \\\"Bar normal content\\\"}]}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "BAR_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Hierarchy Bar Page\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Hierarchy Baz Page\\\" :block/parent {:db/id $BAR_ID}}}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json show --graph {{graph-arg}} --page Foo --linked-references false"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :root :block/title] "Foo",
     [:data :root :block/children 0 :block/title] "Foo normal content"},
    :stdout-not-contains ["Hierarchy Bar Page" "Hierarchy Baz Page"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--page" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "show-page-hierarchy-json",
   :setup
   ["printf '%s' '{:pages-and-blocks [{:page {:block/title \"Foo\"} :blocks [{:block/title \"Foo normal content\"}]}]}' > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "FOO_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Foo\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Hierarchy Bar Page\\\" :block/parent {:db/id $FOO_ID}} :blocks [{:block/title \\\"Bar normal content\\\"}]}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "BAR_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Hierarchy Bar Page\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Hierarchy Baz Page\\\" :block/parent {:db/id $BAR_ID}}}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json show --graph {{graph-arg}} --page Foo --page-hierarchy true --level 3 --linked-references false"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :root :block/title] "Foo",
     [:data :root :block/children 0 :block/title] "Hierarchy Bar Page",
     [:data :root :block/children 0 :block/children 0 :block/title] "Hierarchy Baz Page"},
    :stdout-not-contains ["Foo normal content" "Bar normal content"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--page" "--page-hierarchy" "--level" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "show-library-page-human",
   :setup
   ["LIB_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Library\"] [?e :logseq.property/built-in? true]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Project Alpha\\\" :block/parent {:db/id $LIB_ID}} :blocks [{:block/title \\\"Project page content\\\"}]}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "PROJECT_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Project Alpha\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Nested Alpha\\\" :block/parent {:db/id $PROJECT_ID}}}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Library --level 3 --linked-references false"],
   :expect
   {:exit 0,
    :stdout-contains ["Library" "Project Alpha" "Nested Alpha"],
    :stdout-not-contains ["Project page content"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--page" "--level" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "show-library-page-json",
   :setup
   ["LIB_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Library\"] [?e :logseq.property/built-in? true]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Project Alpha\\\" :block/parent {:db/id $LIB_ID}} :blocks [{:block/title \\\"Project page content\\\"}]}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "PROJECT_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Project Alpha\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; printf '%s' \"{:pages-and-blocks [{:page {:block/title \\\"Nested Alpha\\\" :block/parent {:db/id $PROJECT_ID}}}]}\" > {{export-path-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json show --graph {{graph-arg}} --page Library --level 3 --linked-references false"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :root :block/title] "Library",
     [:data :root :block/children 0 :block/title] "Project Alpha",
     [:data :root :block/children 0 :block/children 0 :block/title] "Nested Alpha"},
    :stdout-not-contains ["Project page content"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--page" "--level" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "tag-upsert-and-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name TagOne >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list tag --graph {{graph-arg}} --with-properties --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :items 0 :block/title] "TagOne"}},
   :covers
   {:commands ["upsert tag" "list tag"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--name"],
     :list ["--with-properties" "--sort" "--order" "--limit"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "tag-upsert-schema-properties-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name SchemaOwner --type default --cardinality one >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name SchemaTag --add-properties '[\"SchemaOwner\"]' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find [?title ...] :where [?tag :block/title \"SchemaTag\"] [?tag :logseq.property.class/properties ?prop] [?prop :block/title ?title]]' | grep -q SchemaOwner"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name SchemaTag --remove-properties '[\"SchemaOwner\"]' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find [?title ...] :where [?tag :block/title \"SchemaTag\"] [?tag :logseq.property.class/properties ?prop] [?prop :block/title ?title]]'"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-not-contains ["SchemaOwner"]},
   :covers
   {:commands ["upsert property" "upsert tag" "query"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--name" "--type" "--cardinality" "--add-properties" "--remove-properties"],
     :query ["--query"]}},
   :tags [:upsert :query],
   :extends :non-sync/graph-json-env}
  {:id "property-upsert-and-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name score --type number --cardinality one >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list property --graph {{graph-arg}} --with-type --sort updated-at --order desc --limit 1"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :items 0 :block/title] "score",
     [:data :items 0 :logseq.property/type] "number",
     [:data :items 0 :db/cardinality] "db.cardinality/one"}},
   :covers
   {:commands ["upsert property" "list property"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--name" "--type" "--cardinality"],
     :list ["--with-type" "--sort" "--order" "--limit"]}},
   :tags [:upsert :list],
   :extends :non-sync/graph-json-env}
  {:id "list-tag-expand-offset-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name TagA >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name TagB >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list tag --graph {{graph-arg}} --expand --with-extends --sort updated-at --order desc --offset 0 --limit 20"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["TagA" "TagB"]},
   :covers
   {:commands ["list tag"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :list
     ["--expand"
      "--with-extends"
      "--offset"
      "--sort"
      "--order"
      "--limit"]}},
   :tags [:list],
   :extends :non-sync/graph-json-env}
  {:id "list-property-classes-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name alpha --type number --cardinality one >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name beta --type number --cardinality one >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list property --graph {{graph-arg}} --with-classes --sort updated-at --order desc --offset 0 --limit 20"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["alpha" "beta"]},
   :covers
   {:commands ["list property"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :list
     ["--with-classes" "--sort" "--order" "--offset" "--limit"]}},
   :tags [:list],
   :extends :non-sync/graph-json-env}
  {:id "list-page-journal-only-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list page --graph {{graph-arg}} --journal-only"],
   :expect
   {:exit 0, :stdout-json-paths {[:status] "ok", [:data :items] []}},
   :covers
   {:commands ["list page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :list ["--journal-only"]}},
   :tags [:list],
   :extends :non-sync/graph-json-env}
  {:id "search-block-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page SearchBlockTarget >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} search block --content blocktarget --output json --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["SearchBlockTarget"]},
   :covers
   {:commands ["search block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :search ["--content"]}},
   :tags [:search :smoke],
   :extends :non-sync/graph-json-env}
  {:id "search-block-renders-block-ref-labels-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page SearchRefPage >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content \"foo [[$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"SearchRefPage\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')]]\" >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json search block --graph {{graph-arg}} --content foo"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["foo [[SearchRefPage]]"]},
   :covers
   {:commands ["upsert page" "upsert block" "search block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--page" "--target-page" "--content"],
     :search ["--content"]}},
   :tags [:upsert :search],
   :extends :non-sync/graph-json-env}
  {:id "search-page-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page SearchPageTarget >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json search page --content target --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["SearchPageTarget"]},
   :covers
   {:commands ["search page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :search ["--content"]}},
   :tags [:search],
   :extends :non-sync/graph-json-env}
  {:id "search-property-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name SearchOwner --type default >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json search property --content owner --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["SearchOwner"]},
   :covers
   {:commands ["search property"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :search ["--content"]}},
   :tags [:search],
   :extends :non-sync/graph-json-env}
  {:id "search-tag-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name SearchTagTarget >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json search tag --content target --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-contains ["SearchTagTarget"]},
   :covers
   {:commands ["search tag"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :search ["--content"]}},
   :tags [:search],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-blocks-file-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Anchor block' >/dev/null"
    "printf '%s\n' '- Inserted from file' > {{export-path-arg}}"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human upsert block --graph {{graph-arg}} --target-id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Anchor block\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --blocks-file {{export-path-arg}} --pos sibling >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect {:exit 0, :stdout-contains ["Inserted from file"]},
   :covers
   {:commands ["upsert block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--blocks-file" "--target-id" "--pos"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-blocks-file-inline-property-name-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name 'Correct-Answer' --type default --cardinality one --public true >/dev/null"
    "printf '%s\n' '- Question block' '  correct-answer:: answer' > {{export-path-arg}}"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --blocks-file {{export-path-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect
   {:exit 0,
    :stdout-contains ["Question block" "Correct-Answer:" "answer"]},
   :covers
   {:commands ["upsert block" "upsert property" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--blocks-file" "--target-page" "--name" "--type" "--cardinality" "--public"],
     :show ["--page"]}},
   :tags [:upsert :show],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-blocks-inline-property-missing-does-not-create-target-page-json",
   :cmds
   ["set +e; out=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page NewPage --blocks $'- Q\n  missing-prop:: x')\"; code=$?; set -e; printf '%s\n' \"$out\"; test \"$code\" -ne 0; printf '%s' \"$out\" | python3 -c 'import sys,json; data=json.load(sys.stdin); assert data[\"status\"] == \"error\"; assert data[\"error\"][\"code\"] == \"property-not-found\"'; page=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"NewPage\"]]')\"; printf '%s\n' \"$page\"; printf '%s' \"$page\" | python3 -c 'import sys,json; data=json.load(sys.stdin); assert data[\"data\"][\"result\"] is None'"],
   :expect
   {:exit 0,
    :stdout-contains ["property-not-found"]},
   :covers
   {:commands ["upsert block" "query"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--blocks" "--target-page"],
     :query ["--query"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-blocks-inline-properties-per-block-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name 'Inline-Note' --type default --cardinality one --public true >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --blocks $'- First inline\n  inline-note:: First note\n- Second inline\n  inline-note:: Second note' >/dev/null"
    "first_id=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"First inline\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; second_id=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Second inline\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; first_show=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --id \"$first_id\")\"; second_show=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --id \"$second_id\")\"; printf '%s\n---\n%s\n' \"$first_show\" \"$second_show\"; printf '%s' \"$first_show\" | grep 'Inline-Note: First note' >/dev/null; ! printf '%s' \"$first_show\" | grep 'Second note' >/dev/null; printf '%s' \"$second_show\" | grep 'Inline-Note: Second note' >/dev/null; ! printf '%s' \"$second_show\" | grep 'First note' >/dev/null"],
   :expect
   {:exit 0,
    :stdout-contains ["First inline" "Inline-Note: First note" "Second inline" "Inline-Note: Second note"]},
   :covers
   {:commands ["upsert block" "upsert property" "query" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--blocks" "--target-page" "--name" "--type" "--cardinality" "--public"],
     :query ["--query"],
     :show ["--id"]}},
   :tags [:upsert :show],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-blocks-dry-run-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"],
   :cmds
   ["out=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --blocks $'- Dry run parent\n  - Dry run child' --dry-run)\"; printf '%s\n' \"$out\"; printf '%s' \"$out\" | python3 -c 'import sys,json; data=json.load(sys.stdin); assert data[\"status\"] == \"ok\"; assert data[\"data\"][\"dry-run\"] is True; assert len(data[\"data\"][\"ops\"]) >= 1'; found=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Dry run parent\"]]')\"; printf '%s\n' \"$found\"; printf '%s' \"$found\" | python3 -c 'import sys,json; data=json.load(sys.stdin); assert data[\"data\"][\"result\"] is None'"],
   :expect
   {:exit 0,
    :stdout-contains ["\"dry-run\":true"]},
   :covers
   {:commands ["upsert block" "query"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--blocks" "--target-page" "--dry-run"],
     :query ["--query"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-target-uuid-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Anchor block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human upsert block --graph {{graph-arg}} --target-uuid \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"Anchor block\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --content 'Inserted by uuid' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect {:exit 0, :stdout-contains ["Inserted by uuid"]},
   :covers
   {:commands ["upsert block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--target-uuid"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-update-id-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human upsert block --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Alpha block\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --content 'Updated by id' --update-tags '[:logseq.class/Quote-block]' --update-properties '{:logseq.property/publishing-public? true}' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect {:exit 0, :stdout-contains ["Updated by id"]},
   :covers
   {:commands ["upsert block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--id" "--update-tags" "--update-properties"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-update-id-custom-many-property-json",
   :vars {:prop-name "Reproducible steps"},
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{graph-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name '{{prop-name}}' --type default --cardinality many --public true >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Alpha block\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --update-properties '{\"{{prop-name}}\" [\"Step 1\" \"Step 2\" \"Step 3\"]}' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Alpha block\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\""],
   :expect
   {:exit 0,
    :stdout-contains ["{{prop-name}}" "Step 1" "Step 2" "Step 3"]},
   :covers
   {:commands ["upsert block" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert
     ["--id" "--target-page" "--content" "--update-properties"],
     :show ["--id"]}},
   :tags [:upsert :show]}
  {:id "show-property-many-ref-default-renders-nested-block-ref-human",
   :setup
   ["printf '%s' '{:properties {:user.property/reproducible-steps {:block/title \"Reproducible steps\" :logseq.property/type :default :db/cardinality :db.cardinality/many :db/valueType :db.type/ref :logseq.property/public? true}} :pages-and-blocks [{:page {:block/title \"Targets\"} :blocks [{:block/title \"Nested target\" :block/uuid #uuid \"11111111-1111-1111-1111-111111111111\" :build/keep-uuid? true} {:block/title \"Step [[11111111-1111-1111-1111-111111111111]]\" :block/uuid #uuid \"22222222-2222-2222-2222-222222222222\" :build/keep-uuid? true} {:block/title \"Verify output\" :block/uuid #uuid \"33333333-3333-3333-3333-333333333333\" :build/keep-uuid? true}]} {:page {:block/title \"Home\"} :blocks [{:block/title \"Alpha block\" :build/properties {:user.property/reproducible-steps #{[:block/uuid #uuid \"22222222-2222-2222-2222-222222222222\"] [:block/uuid #uuid \"33333333-3333-3333-3333-333333333333\"]}}}]}]}' > {{export-path-arg}}"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect
   {:exit 0,
    :stdout-contains ["Reproducible steps:" "Step [[Nested target]]" "Verify output"],
    :stdout-not-contains ["Step [[11111111-1111-1111-1111-111111111111]]"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--page"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "block-upsert-update-uuid-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' --update-tags '[:logseq.class/Quote-block]' --update-properties '{:logseq.property/publishing-public? true}' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human upsert block --graph {{graph-arg}} --uuid \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"Alpha block\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --content 'Updated by uuid' --remove-tags '[:logseq.class/Quote-block]' --remove-properties '[:logseq.property/publishing-public?]' >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home"],
   :expect {:exit 0, :stdout-contains ["Updated by uuid"]},
   :covers
   {:commands ["upsert block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--uuid" "--remove-tags" "--remove-properties"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "property-upsert-update-id-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name score --type number --cardinality one >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list property --graph {{graph-arg}} --fields title,id --limit 200 --sort updated-at --order desc | python3 -c 'import sys,json; print(next(item[\"db/id\"] for item in json.load(sys.stdin)[\"data\"][\"items\"] if item[\"block/title\"] == \"score\"))')\" --hide true --public false"],
   :expect {:exit 0, :stdout-json-paths {[:status] "ok"}},
   :covers
   {:commands ["upsert property"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :upsert ["--id" "--hide" "--public"]}},
   :tags [:upsert],
   :extends :non-sync/graph-json-env}
  {:id "query-custom-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?title . :where [?b :block/title ?title] [(= ?title \"Alpha block\")]]'"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :result] "Alpha block"}},
   :covers
   {:commands ["query"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :query ["--query"]}},
   :tags [:query],
   :extends :non-sync/graph-json-env}
  {:id "query-named-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --name recent-updated --inputs '[1]'"],
   :expect {:exit 0, :stdout-json-paths {[:status] "ok"}},
   :covers
   {:commands ["query"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :query ["--name" "--inputs"]}},
   :tags [:query],
   :extends :non-sync/graph-json-env}
  {:id "query-list-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query list --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :queries 0 :name] "list-priority"}},
   :covers
   {:commands ["query list"],
    :options {:global ["--config" "--graph" "--root-dir" "--output"]}},
   :tags [:query],
   :extends :non-sync/graph-json-env}
  {:id "example-show-human",
   :expect
   {:exit 0,
    :stdout-contains
    ["Selector: show" "Matched commands:" "show" "Examples:"]},
   :covers {:commands ["example show"]},
   :tags [:example],
   :extends :non-sync/example-human-command,
   :vars {:example-selector "show"}}
  {:id "example-upsert-page-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "upsert page",
     [:data :matched-commands 0] "upsert page"}},
   :covers {:commands ["example upsert page"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "upsert page"}}
  {:id "example-upsert-prefix-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "upsert",
     [:data :matched-commands 0] "upsert block"}},
   :covers {:commands ["example upsert"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "upsert"}}
  {:id "example-list-prefix-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "list",
     [:data :matched-commands 0] "list page"}},
   :covers {:commands ["example list"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "list"}}
  {:id "example-list-page-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "list page",
     [:data :matched-commands] ["list page"]}},
   :covers {:commands ["example list page"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "list page"}}
  {:id "example-query-prefix-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "query", [:data :matched-commands 0] "query"}},
   :covers {:commands ["example query"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "query"}}
  {:id "example-query-list-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "query list",
     [:data :matched-commands] ["query list"]}},
   :covers {:commands ["example query list"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "query list"}}
  {:id "example-remove-prefix-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "remove",
     [:data :matched-commands 0] "remove block"}},
   :covers {:commands ["example remove"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "remove"}}
  {:id "example-remove-page-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "remove page",
     [:data :matched-commands] ["remove page"]}},
   :covers {:commands ["example remove page"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "remove page"}}
  {:id "example-search-prefix-json",
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:data :selector] "search",
     [:data :matched-commands 0] "search block"}},
   :covers {:commands ["example search"]},
   :tags [:example],
   :extends :non-sync/example-json-command,
   :vars {:example-selector "search"}}
  {:id "example-search-block-edn",
   :expect
   {:exit 0,
    :stdout-edn-paths
    {[:data :selector] "search block",
     [:data :matched-commands] ["search block"]}},
   :covers {:commands ["example search block"]},
   :tags [:example],
   :extends :non-sync/example-edn-command,
   :vars {:example-selector "search block"}}
  {:id "show-linked-block-id-human",
   :setup
   ["printf '%s' '{:pages-and-blocks [{:page {:block/title \"Targets\"} :blocks [{:block/title \"Target B\" :block/uuid #uuid \"11111111-1111-1111-1111-111111111111\" :build/keep-uuid? true :build/children [{:block/title \"Target child\"}]}]} {:page {:block/title \"Home\"} :blocks [{:block/title \"Source A\" :block/uuid #uuid \"22222222-2222-2222-2222-222222222222\" :build/keep-uuid? true :block/link [:block/uuid #uuid \"11111111-1111-1111-1111-111111111111\"]}]}]}' > {{export-path-arg}}"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human show --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output json query --query '[:find ?e . :where [?e :block/title \"Source A\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --linked-references false"],
   :expect
   {:exit 0,
    :stdout-contains ["→" "Target B" "Target child"],
    :stdout-not-contains ["Source A"]},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--id" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "show-linked-block-id-json",
   :setup
   ["printf '%s' '{:pages-and-blocks [{:page {:block/title \"Targets\"} :blocks [{:block/title \"Target B\" :block/uuid #uuid \"11111111-1111-1111-1111-111111111111\" :build/keep-uuid? true :build/children [{:block/title \"Target child\"}]}]} {:page {:block/title \"Home\"} :blocks [{:block/title \"Source A\" :block/uuid #uuid \"22222222-2222-2222-2222-222222222222\" :build/keep-uuid? true :block/link [:block/uuid #uuid \"11111111-1111-1111-1111-111111111111\"]}]}]}' > {{export-path-arg}}"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph import --graph {{graph-arg}} --type edn --input {{export-path-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output json show --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output json query --query '[:find ?e . :where [?e :block/title \"Source A\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" --linked-references false"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"
                        [:data :root :block/title] "Target B"
                        [:data :root :block/children 0 :block/title] "Target child"}},
   :covers
   {:commands ["graph import" "show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :graph ["--type" "--input"],
     :show ["--id" "--linked-references"]}},
   :tags [:graph :show],
   :extends :non-sync/graph-json-env}
  {:id "show-id-human",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human show --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human query --query '[:find ?e . :where [?e :block/title \"Alpha block\"]]')\""],
   :expect {:exit 0, :stdout-contains ["Alpha block"]},
   :covers
   {:commands ["show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :show ["--id"]}},
   :tags [:show],
   :extends :non-sync/graph-json-env}
  {:id "show-uuid-human",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human show --uuid \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output json query --query '[:find ?uuid . :where [?e :block/title \"Alpha block\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\""],
   :expect {:exit 0, :stdout-contains ["Alpha block"]},
   :covers
   {:commands ["show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :show ["--uuid"]}},
   :tags [:show],
   :extends :non-sync/graph-json-env}
  {:id "show-stdin-id-human",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human query --query '[:find [?e ...] :in $ ?q :where [?e :block/title ?title] [(clojure.string/includes? ?title ?q)]]' --inputs '[\"Alpha\"]' | {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --graph {{graph-arg}} --output human show --id"],
   :expect {:exit 0, :stdout-contains ["Alpha block"]},
   :covers
   {:commands ["show"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :show ["stdin:--id"]}},
   :tags [:show :pipe],
   :extends :non-sync/graph-json-env}
  {:id "debug-pull-id-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json debug pull --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"Home\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\""],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :entity :block/title] "Home"}},
   :covers
   {:commands ["debug pull"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :debug ["--id"]}},
   :tags [:debug],
   :extends :non-sync/graph-json-env}
  {:id "debug-pull-uuid-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json debug pull --graph {{graph-arg}} --uuid \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"Home\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\""],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :entity :block/title] "Home"}},
   :covers
   {:commands ["debug pull"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :debug ["--uuid"]}},
   :tags [:debug],
   :extends :non-sync/graph-json-env}
  {:id "debug-pull-ident-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json debug pull --graph {{graph-arg}} --ident :logseq.class/Tag"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :entity :db/ident] "logseq.class/Tag"}},
   :covers
   {:commands ["debug pull"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :debug ["--ident"]}},
   :tags [:debug],
   :extends :non-sync/graph-json-env}
  {:id "remove-page-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json remove page --graph {{graph-arg}} --page Home"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok", [:data :result] true}},
   :covers
   {:commands ["remove page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :remove ["--page"]}},
   :tags [:remove],
   :extends :non-sync/graph-json-env}
  {:id "remove-page-force-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page ForceMe >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json remove page --graph {{graph-arg}} --page ForceMe --force"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :result] true,
     [:data :permanently-deleted?] true}},
   :covers
   {:commands ["remove page"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :remove ["--page" "--force"]}},
   :tags [:remove],
   :extends :non-sync/graph-json-env}
  {:id "graph-remove-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{graph-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph remove --graph {{graph-arg}}"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph list"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok"},
    :stdout-not-contains ["{{graph}}"]},
   :covers
   {:commands ["graph remove" "graph list"],
    :options {:global ["--config" "--graph" "--root-dir" "--output"]}},
   :tags [:graph :remove]}
  {:id "remove-block-uuid-human",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert page --graph {{graph-arg}} --page Home >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page Home --content 'Alpha block' >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human remove block --graph {{graph-arg}} --uuid \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?uuid . :where [?e :block/title \"Alpha block\"] [?e :block/uuid ?uuid]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\" >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human show --graph {{graph-arg}} --page Home --linked-references false"],
   :expect {:exit 0, :stdout-not-contains ["Alpha block"]},
   :covers
   {:commands ["remove block"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :remove ["--uuid"]}},
   :tags [:remove],
   :extends :non-sync/graph-json-env}
  {:id "remove-tag-name-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name TagOne >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json remove tag --graph {{graph-arg}} --name TagOne >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list tag --graph {{graph-arg}} --fields title,id"],
   :expect {:exit 0, :stdout-not-contains ["TagOne"]},
   :covers
   {:commands ["remove tag"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :remove ["--name"]}},
   :tags [:remove],
   :extends :non-sync/graph-json-env}
  {:id "remove-property-id-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name score --type number --cardinality one >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json remove property --graph {{graph-arg}} --id \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list property --graph {{graph-arg}} --fields title,id --limit 200 --sort updated-at --order desc | python3 -c 'import sys,json; print(next(item[\"db/id\"] for item in json.load(sys.stdin)[\"data\"][\"items\"] if item[\"block/title\"] == \"score\"))')\" >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json list property --graph {{graph-arg}} --fields title,id"],
   :expect {:exit 0, :stdout-not-contains ["score"]},
   :covers
   {:commands ["remove property"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :remove ["--id"]}},
   :tags [:remove],
   :extends :non-sync/graph-json-env}
  {:id "server-cleanup-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server cleanup"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :mismatched] 0,
     [:data :eligible] 0,
     [:data :skipped-owner] 0}},
   :covers
   {:commands ["server cleanup"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :server []}},
   :tags [:server],
   :extends :non-sync/graph-json-env}
  {:id "server-list-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server start --graph {{graph-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server list"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :servers 0 :graph] "{{graph}}"}},
   :covers
   {:commands ["server list"],
    :options {:global ["--config" "--root-dir" "--output"]}},
   :tags [:server],
   :extends :non-sync/graph-json-env}
  {:id "server-restart-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server restart --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :repo] "logseq_db_{{graph}}", [:data :owned] true}},
   :covers
   {:commands ["server restart"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :server ["--graph"]}},
   :tags [:server],
   :extends :non-sync/graph-json-env}
  {:id "server-stop-json",
   :setup
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph create --graph {{graph-arg}} >/dev/null"
    "{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server start --graph {{graph-arg}} >/dev/null"],
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths {[:status] "ok", [:data :repo] "logseq_db_{{graph}}"}},
   :covers
   {:commands ["server stop"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :server ["--graph"]}},
   :tags [:server]}
  {:id "server-start-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server start --graph {{graph-arg}}"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok", [:data :repo] "logseq_db_{{graph}}", [:data :owned] true}},
   :covers
   {:commands ["server start"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"],
     :server ["--graph"]}},
   :tags [:server],
   :extends :non-sync/graph-json-env}
  {:id "agent-bridge-workflows",
   :setup
   ["mkdir -p '{{tmp-dir}}/assigned-root' && printf '{:output-format :json}\\n' > '{{tmp-dir}}/assigned-root/cli.edn' && {{cli}} --root-dir '{{tmp-dir}}/assigned-root' --config '{{tmp-dir}}/assigned-root/cli.edn' --output json graph create --graph cli-e2e-agent-bridge-assigned >/dev/null && {{cli}} --root-dir '{{tmp-dir}}/assigned-root' --config '{{tmp-dir}}/assigned-root/cli.edn' --output json upsert task --graph cli-e2e-agent-bridge-assigned --target-page AgentBridgeE2E --content 'Test AgentBridge task routing and completion status' --status todo >/dev/null"
    "mkdir -p '{{tmp-dir}}/parallel-root' && printf '{:output-format :json}\\n' > '{{tmp-dir}}/parallel-root/cli.edn' && {{cli}} --root-dir '{{tmp-dir}}/parallel-root' --config '{{tmp-dir}}/parallel-root/cli.edn' --output json graph create --graph cli-e2e-agent-bridge-parallel >/dev/null"
    "mkdir -p '{{tmp-dir}}/duplicate-root' && printf '{:output-format :json}\\n' > '{{tmp-dir}}/duplicate-root/cli.edn' && {{cli}} --root-dir '{{tmp-dir}}/duplicate-root' --config '{{tmp-dir}}/duplicate-root/cli.edn' --output json graph create --graph cli-e2e-agent-bridge-duplicate >/dev/null"
    "mkdir -p '{{tmp-dir}}/comment-root' && printf '{:output-format :json}\\n' > '{{tmp-dir}}/comment-root/cli.edn' && {{cli}} --root-dir '{{tmp-dir}}/comment-root' --config '{{tmp-dir}}/comment-root/cli.edn' --output json graph create --graph cli-e2e-agent-bridge-comment >/dev/null"],
   :cmds
   ["python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{tmp-dir}}/assigned-root' --config '{{tmp-dir}}/assigned-root/cli.edn' --graph cli-e2e-agent-bridge-assigned --tmp-dir '{{tmp-dir}}/assigned-work' --repo-root '{{repo-root}}' --assign-after-start"
    "python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{tmp-dir}}/parallel-root' --config '{{tmp-dir}}/parallel-root/cli.edn' --graph cli-e2e-agent-bridge-parallel --tmp-dir '{{tmp-dir}}/parallel-work' --repo-root '{{repo-root}}' --parallel-assignment-check"
    "python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{tmp-dir}}/duplicate-root' --config '{{tmp-dir}}/duplicate-root/cli.edn' --graph cli-e2e-agent-bridge-duplicate --tmp-dir '{{tmp-dir}}/duplicate-work' --repo-root '{{repo-root}}' --duplicate-bridge-check"
    "python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{tmp-dir}}/comment-root' --config '{{tmp-dir}}/comment-root/cli.edn' --graph cli-e2e-agent-bridge-comment --tmp-dir '{{tmp-dir}}/comment-work' --repo-root '{{repo-root}}' --comment-mention-check"
    "bash '{{repo-root}}/cli-e2e/scripts/agent_bridge_demo.sh' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{tmp-dir}}/demo-root' --graph cli-e2e-agent-bridge-demo --repo-root '{{repo-root}}'"],
   :expect
   {:exit 0,
    :stdout-contains ["agent bridge"]},
   :covers
   {:commands ["agent bridge"],
    :options
    {:global ["--config" "--graph" "--root-dir" "--output"]}},
   :cleanup
   ["{{cli}} --root-dir '{{tmp-dir}}/assigned-root' --config '{{tmp-dir}}/assigned-root/cli.edn' --output json server stop --graph cli-e2e-agent-bridge-assigned"
    "{{cli}} --root-dir '{{tmp-dir}}/parallel-root' --config '{{tmp-dir}}/parallel-root/cli.edn' --output json server stop --graph cli-e2e-agent-bridge-parallel"
    "{{cli}} --root-dir '{{tmp-dir}}/duplicate-root' --config '{{tmp-dir}}/duplicate-root/cli.edn' --output json server stop --graph cli-e2e-agent-bridge-duplicate"
    "{{cli}} --root-dir '{{tmp-dir}}/comment-root' --config '{{tmp-dir}}/comment-root/cli.edn' --output json server stop --graph cli-e2e-agent-bridge-comment"],
   :tags [:agent]}
  {:id "skill-show-human",
   :cmds ["{{cli}} skill show"],
   :expect
   {:exit 0, :stdout-contains ["name: logseq-cli" "# Logseq CLI"]},
   :covers {:commands ["skill show"], :options {:skill []}},
   :tags [:skill :smoke]}
  {:id "skill-show-json-still-raw-markdown",
   :cmds ["{{cli}} --output json skill show"],
   :expect
   {:exit 0,
    :stdout-contains ["name: logseq-cli" "# Logseq CLI"],
    :stdout-not-contains ["\"status\"" "\"data\""]},
   :covers {:commands ["skill show"], :options {:global ["--output"]}},
   :tags [:skill]}
  ;; Repo root already contains tracked `.agents/skills/logseq-cli/SKILL.md`,
  ;; so this local-install case must run from an isolated cwd and HOME.
  {:id "skill-install-local",
   :setup
   ["rm -rf ./tmp/cli-e2e-skill-install-local ./tmp/cli-e2e-skill-install-local-home"
    "mkdir -p ./tmp/cli-e2e-skill-install-local ./tmp/cli-e2e-skill-install-local-home"],
   :cmds
   ["cd ./tmp/cli-e2e-skill-install-local && HOME=\"$(pwd)/../cli-e2e-skill-install-local-home\" {{cli}} skill install"
    "python3 -c 'import pathlib; p=pathlib.Path(\"./tmp/cli-e2e-skill-install-local/.agents/skills/logseq-cli/SKILL.md\"); print(\"installed\" if p.exists() else \"missing\")'"],
   :expect {:exit 0, :stdout-contains ["installed"]},
   :covers {:commands ["skill install"], :options {:skill []}},
   :cleanup ["rm -rf ./tmp/cli-e2e-skill-install-local ./tmp/cli-e2e-skill-install-local-home"],
   :tags [:skill]}
  {:id "skill-install-global-preserves-other-skills",
   :setup
   ["rm -rf ./tmp/cli-e2e-skill-home"
    "mkdir -p ./tmp/cli-e2e-skill-home/.agents/skills/existing-skill"
    "python3 -c 'import pathlib; pathlib.Path(\"./tmp/cli-e2e-skill-home/.agents/skills/existing-skill/SKILL.md\").write_text(\"keep\", encoding=\"utf8\")'"],
   :cmds
   ["HOME=\"$(pwd)/tmp/cli-e2e-skill-home\" {{cli}} skill install --global >/dev/null"
    "python3 -c 'import pathlib; home=pathlib.Path(\"./tmp/cli-e2e-skill-home\"); existing=(home / \".agents/skills/existing-skill/SKILL.md\").read_text(encoding=\"utf8\"); installed=(home / \".agents/skills/logseq-cli/SKILL.md\").exists(); print(\"ok\" if existing==\"keep\" and installed else \"bad\")'"],
   :expect {:exit 0, :stdout-contains ["ok"]},
   :covers
   {:commands ["skill install"], :options {:skill ["--global"]}},
   :cleanup ["rm -rf ./tmp/cli-e2e-skill-home"],
   :tags [:skill]}
  {:id "completion-zsh",
   :expect
   {:exit 0,
    :stdout-contains
    ["#compdef logseq" "Auto-generated by `logseq completion zsh`"]},
   :covers {:options {:completion ["zsh"]}},
   :tags [:smoke],
   :extends :non-sync/completion-command,
   :vars {:completion-selector "zsh"}}
  {:id "completion-bash-flag",
   :expect
   {:exit 0,
    :stdout-contains
    ["Auto-generated by `logseq completion bash`"
     "_logseq_json_names_bash"]},
   :covers {:options {:completion ["--shell" "bash"]}},
   :extends :non-sync/completion-command,
   :vars {:completion-selector "--shell bash"}}
  {:id "completion-invalid-shell",
   :expect {:exit 1, :stdout-contains ["unsupported shell: fish"]},
   :extends :non-sync/completion-command,
   :vars {:completion-selector "fish"}}
  {:id "doctor-dev-script-json",
   :cmds
   ["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json doctor --dev-script"],
   :expect
   {:exit 0,
    :stdout-json-paths
    {[:status] "ok",
     [:data :status] "ok",
     [:data :checks 0 :id] "db-worker-script"},
    :stdout-contains ["static/db-worker-node.js"]},
   :covers
   {:commands ["doctor"],
    :options
    {:global ["--config" "--root-dir" "--output"],
     :doctor ["--dev-script"]}},
   :tags [:doctor :smoke]}
  {:id "graph-deletion-worker-lifecycle"
   :cmds ["python3 {{repo-root-arg}}/cli-e2e/scripts/graph_deletion_lifecycle_test.py"]
   :tags [:graph :lifecycle]}
  {:id "graph-lifecycle-cli-followups"
   :cmds ["node --test {{repo-root-arg}}/cli-e2e/scripts/cli_build_revision_test.mjs {{repo-root-arg}}/cli-e2e/scripts/graph_lifecycle_cli_test.cjs"]
   :tags [:graph :lifecycle]}
  {:id "graph-lifecycle-process-protocol"
   :cmds ["node --test {{repo-root-arg}}/cli-e2e/scripts/graph_ownership_test.cjs {{repo-root-arg}}/cli-e2e/scripts/graph_lifecycle_protocol_test.cjs {{repo-root-arg}}/cli-e2e/scripts/graph_lifecycle_upgrade_test.cjs {{repo-root-arg}}/cli-e2e/scripts/graph_lifecycle_startup_test.cjs"]
   :tags [:graph :lifecycle]}]}