Files
logseq/cli-e2e/spec/non_sync_cases.edn
2026-05-22 15:56:18 +08:00

1447 lines
79 KiB
Clojure
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{: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}
{: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"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup restore --src \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup list | 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 --src \"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph backup list | 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 "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 "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 "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 "qmd-and-qsearch-json",
:setup
["python3 - <<'PY'\nimport base64, pathlib\np = pathlib.Path('{{tmp-dir}}/fake-bin/qmd')\np.parent.mkdir(parents=True, exist_ok=True)\np.write_bytes(base64.b64decode('IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwppbXBvcnQganNvbgppbXBvcnQgb3MKaW1wb3J0IHBhdGhsaWIKaW1wb3J0IHJlCmltcG9ydCBzeXMKCmFyZ3MgPSBzeXMuYXJndlsxOl0Kc3RhdGUgPSBwYXRobGliLlBhdGgob3MuZW52aXJvblsnUU1EX0ZBS0VfU1RBVEUnXSkKCmlmIGFyZ3MgPT0gWyctLWhlbHAnXToKICAgIHByaW50KCdxbWQgaGVscCcpCiAgICBzeXMuZXhpdCgwKQoKaWYgYXJnc1s6Ml0gPT0gWydjb2xsZWN0aW9uJywgJ3Nob3cnXToKICAgIGlmIG5vdCBzdGF0ZS5leGlzdHMoKToKICAgICAgICBwcmludCgnQ29sbGVjdGlvbiBub3QgZm91bmQnLCBmaWxlPXN5cy5zdGRlcnIpCiAgICAgICAgc3lzLmV4aXQoMSkKICAgIHByaW50KCdDb2xsZWN0aW9uOiAnICsgYXJnc1syXSkKICAgIHByaW50KCcgIFBhdGg6ICAgICAnICsgc3RhdGUucmVhZF90ZXh0KCkuc3RyaXAoKSkKICAgIHByaW50KCcgIFBhdHRlcm46ICAqKi8qLm1kJykKICAgIHN5cy5leGl0KDApCgppZiBhcmdzWzoyXSA9PSBbJ2NvbGxlY3Rpb24nLCAnYWRkJ106CiAgICBzdGF0ZS53cml0ZV90ZXh0KGFyZ3NbMl0pCiAgICBwcmludCgnY3JlYXRlZCcpCiAgICBzeXMuZXhpdCgwKQoKaWYgYXJnc1s6MV0gPT0gWydlbWJlZCddOgogICAgcHJpbnQoJ2VtYmVkZGVkJykKICAgIHN5cy5leGl0KDApCgppZiBhcmdzWzoxXSA9PSBbJ3VwZGF0ZSddOgogICAgcHJpbnQoJ3VwZGF0ZWQnKQogICAgc3lzLmV4aXQoMCkKCmlmIGFyZ3NbOjFdID09IFsncXVlcnknXToKICAgIHJvb3QgPSBwYXRobGliLlBhdGgoc3RhdGUucmVhZF90ZXh0KCkuc3RyaXAoKSkKICAgIHJvd3MgPSBbXQogICAgZm9yIHBhdGggaW4gcm9vdC5yZ2xvYignKi5tZCcpOgogICAgICAgIHRleHQgPSBwYXRoLnJlYWRfdGV4dChlbmNvZGluZz0ndXRmOCcpCiAgICAgICAgbWF0Y2ggPSByZS5zZWFyY2gocic8IS0tIGlkOiAoXGQrKSAtLT4nLCB0ZXh0KQogICAgICAgIGlmIG1hdGNoOgogICAgICAgICAgICByb3dzLmFwcGVuZCh7CiAgICAgICAgICAgICAgICAnc2NvcmUnOiAxLAogICAgICAgICAgICAgICAgJ2ZpbGUnOiAncW1kOi8vY3VzdG9tLycgKyBwYXRoLm5hbWUsCiAgICAgICAgICAgICAgICAnc25pcHBldCc6ICctIHFtZCB0YXJnZXQgPCEtLSBpZDogJyArIG1hdGNoLmdyb3VwKDEpICsgJyAtLT4nLAogICAgICAgICAgICB9KQogICAgICAgICAgICBicmVhawogICAgcHJpbnQoanNvbi5kdW1wcyhyb3dzKSkKICAgIHN5cy5leGl0KDApCgpwcmludCgndW5leHBlY3RlZCBhcmdzOiAnICsgcmVwcihhcmdzKSwgZmlsZT1zeXMuc3RkZXJyKQpzeXMuZXhpdCgyKQo='))\np.chmod(0o755)\nPY"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page QmdSearchPage --content \"qmd target\" >/dev/null"],
:cmds
["QMD_FAKE_STATE={{tmp-dir-arg}}/qmd-state PATH={{tmp-dir-arg}}/fake-bin:$PATH {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json qmd --graph {{graph-arg}}"
"QMD_FAKE_STATE={{tmp-dir-arg}}/qmd-state PATH={{tmp-dir-arg}}/fake-bin:$PATH {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json qsearch qmd target --graph {{graph-arg}} --no-rerank"],
:expect
{:exit 0,
:stdout-json-paths {[:status] "ok"},
:stdout-contains ["qmd target"]},
:covers
{:commands ["qmd" "qsearch"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:qmd []
:qsearch ["--no-rerank"]}},
:tags [:qmd :search],
:extends :non-sync/graph-json-env}
{:id "qmd-and-qsearch-human-page-groups",
:setup
["python3 - <<'PY'
import pathlib
p = pathlib.Path('{{tmp-dir}}/fake-bin/qmd')
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(r'''#!/usr/bin/env python3
import json
import os
import pathlib
import re
import sys
args = sys.argv[1:]
state = pathlib.Path(os.environ['QMD_FAKE_STATE'])
if args == ['--help']:
print('qmd help')
sys.exit(0)
if args[:2] == ['collection', 'show']:
if not state.exists():
print('Collection not found', file=sys.stderr)
sys.exit(1)
print('Collection: ' + args[2])
print(' Path: ' + state.read_text().strip())
print(' Pattern: **/*.md')
sys.exit(0)
if args[:2] == ['collection', 'add']:
state.write_text(args[2])
print('created')
sys.exit(0)
if args[:1] == ['embed']:
print('embedded')
sys.exit(0)
if args[:1] == ['update']:
print('updated')
sys.exit(0)
if args[:1] == ['query']:
root = pathlib.Path(state.read_text().strip())
rows = []
for path in sorted(root.rglob('*.md')):
text = path.read_text(encoding='utf8')
match = re.search(r'<!-- id: (\\d+) -->', text)
if match:
rows.append({
'score': 1,
'file': 'qmd://custom/' + path.name,
'snippet': '- qmd target <!-- id: ' + match.group(1) + ' -->',
})
break
print(json.dumps(rows))
sys.exit(0)
print('unexpected args: ' + repr(args), file=sys.stderr)
sys.exit(2)
''')
p.chmod(0o755)
PY"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert tag --graph {{graph-arg}} --name QmdHumanTag >/dev/null"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert property --graph {{graph-arg}} --name qmd-human-prop --public true >/dev/null"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --target-page QmdHumanPage --content \"qmd target\" --update-tags '[\"QmdHumanTag\"]' --update-properties '{:qmd-human-prop \"rich value\"}' >/dev/null"],
:cmds
["QMD_FAKE_STATE={{tmp-dir-arg}}/qmd-human-state PATH={{tmp-dir-arg}}/fake-bin:$PATH {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json qmd --graph {{graph-arg}} >/dev/null"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json graph switch --graph {{graph-arg}} >/dev/null"
"QMD_FAKE_STATE={{tmp-dir-arg}}/qmd-human-state PATH={{tmp-dir-arg}}/fake-bin:$PATH {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output human qsearch qmd target --no-rerank"],
:expect
{:exit 0,
:stdout-contains ["QmdHumanPage" "qmd target #QmdHumanTag" "qmd-human-prop: rich value" "└──"],
:stdout-not-contains ["QmdHumanPage (1 match)" "PAGE-TITLE" "Count:"]},
:covers
{:commands ["upsert tag" "upsert property" "qmd" "graph switch" "qsearch"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:upsert ["--name" "--target-page" "--content" "--update-tags" "--update-properties"],
:qmd []
:qsearch ["--no-rerank"]}},
:tags [:qmd :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 '[{:block/title \"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-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 "debug-pull-current-graph-fallback-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 --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" "--root-dir" "--output"], :debug ["--id"]}},
: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 "graph-remove-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 stop --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",
: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 :repo] "{{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] "{{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"],
: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] "{{graph}}"}},
:covers
{:commands ["server stop"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:server ["--graph"]}},
:tags [:server]}
{:id "server-start-json",
:setup
["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}} >/dev/null"],
: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] "{{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-routes-assigned-task",
:setup
["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --target-page AgentBridgeE2E --content '测试 agent bridge 功能把当前task status设置为done' --status todo >/dev/null"],
:cmds
["python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{root-dir}}' --config '{{config-path}}' --graph '{{graph}}' --tmp-dir '{{tmp-dir}}' --repo-root '{{repo-root}}' --assign-after-start"],
:expect {:exit 0, :stdout-contains ["agent bridge routed task to thread-e2e-agent-bridge"]},
:covers
{:commands ["agent bridge"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:agent []}},
:cleanup
["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}}"],
:tags [:agent],
:extends :non-sync/graph-json-env}
{:id "agent-bridge-demo-script",
:cmds
["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 demo completed"
"task status: done"
"agent-session-id: thread-agent-bridge-demo"]},
:covers
{:commands ["agent bridge"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:agent []}},
:tags [:agent]}
{:id "agent-bridge-dry-run-json",
:setup
["python3 '{{repo-root}}/cli-e2e/scripts/agent_bridge_e2e.py' --cli '{{repo-root}}/static/logseq-cli.js' --root-dir '{{root-dir}}' --config '{{config-path}}' --graph '{{graph}}' --tmp-dir '{{tmp-dir}}' --repo-root '{{repo-root}}' --prepare-fake-codex-only"
"{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert task --graph {{graph-arg}} --target-page AgentBridgeE2E --content '测试 agent bridge 功能把当前task status设置为done' --status todo >/dev/null"
"TASK_ID=\"$({{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json query --graph {{graph-arg}} --query '[:find ?e . :where [?e :block/title \"测试 agent bridge 功能把当前task status设置为done\"]]' | python3 -c 'import sys,json; print(json.load(sys.stdin)[\"data\"][\"result\"])')\"; {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json upsert block --graph {{graph-arg}} --id \"$TASK_ID\" --update-properties \"{\\\"Assignee\\\" \\\"$(hostname)\\\"}\" >/dev/null"],
:cmds
["CODEX_FAKE_LOG={{tmp-dir-arg}}/dry-run-codex.jsonl PATH={{tmp-dir-arg}}/fake-bin:$PATH {{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json agent bridge --graph {{graph-arg}} --dry-run"],
:expect
{:exit 0,
:stdout-json-paths {[:status] "ok", [:data :mode] "dry-run"},
:stdout-contains ["测试 agent bridge 功能把当前task status设置为done"]},
:covers
{:commands ["agent bridge"],
:options
{:global ["--config" "--graph" "--root-dir" "--output"],
:agent ["--dry-run"]}},
:cleanup
["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json server stop --graph {{graph-arg}}"],
:tags [:agent],
:extends :non-sync/graph-json-env}
{:id "agent-bridge-list-all-json",
:cmds
["{{cli}} --root-dir {{root-dir-arg}} --config {{config-path-arg}} --output json agent bridge list --all"],
:expect {:exit 0, :stdout-json-paths {[:status] "ok", [:data :sessions] []}},
:covers
{:commands ["agent bridge list"],
:options
{:global ["--config" "--root-dir" "--output"],
:agent ["--all"]}},
: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.
{:id "skill-install-local",
:setup
["rm -rf ./tmp/cli-e2e-skill-install-local"
"mkdir -p ./tmp/cli-e2e-skill-install-local"],
:cmds
["cd ./tmp/cli-e2e-skill-install-local && {{cli}} skill install >/dev/null"
"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"],
: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]}]}