mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge branch 'master' into enhance/pdf-annotation-asset-blocks
This commit is contained in:
@@ -29,7 +29,7 @@ Use `logseq` to inspect and edit graph entities, run Datascript queries, and con
|
||||
- `doctor`
|
||||
- `sync status|start|stop|upload|download|remote-graphs|ensure-keys|grant-access|config set|get|unset`
|
||||
- Authentication: `login|logout`
|
||||
- Utilities: `agent bridge|agent bridge list`, `completion`, `debug`, `example`, `skill`
|
||||
- Utilities: `agent bridge`, `completion`, `debug`, `example`, `skill`
|
||||
|
||||
## Global options
|
||||
|
||||
@@ -118,7 +118,6 @@ Use `logseq` to inspect and edit graph entities, run Datascript queries, and con
|
||||
- `query list` returns both built-ins and `custom-queries` from `cli.edn`.
|
||||
- `agent bridge --dry-run` checks the local bridge setup, resolves `:agent-name` or hostname, registers the AgentBridge name in the graph, finds routable `#Task` TODO blocks assigned to that AgentBridge name, and prints the Codex commands it would run without starting Codex or writing `agent-session-id`.
|
||||
- `agent bridge` starts/reuses db-worker-node, listens to db-worker-node events, scans routable tasks on startup and each event, starts `codex exec --json` for matched tasks, stores the Codex session/thread id in `agent-bridge-sessions.edn`, and writes it to the task's `agent-session-id` property.
|
||||
- `agent bridge list` reads root-dir scoped bridge session records and hides completed sessions by default; use `--all` to include them.
|
||||
- `show --id` accepts either one db/id or an EDN vector of ids.
|
||||
- `remove block --id` also accepts one db/id or an EDN vector.
|
||||
- `upsert block` enters update mode when `--id` or `--uuid` is provided.
|
||||
|
||||
@@ -26,7 +26,7 @@ root_dir=""
|
||||
graph="agent-bridge-demo-$(date +%s)"
|
||||
timeout_sec=45
|
||||
agent_name="AgentBridgeDemo"
|
||||
task_title="AgentBridge demo task: mark this block done"
|
||||
task_title="AgentBridge demo task: mark this block in review"
|
||||
expected_session="thread-agent-bridge-demo"
|
||||
bridge_pid=""
|
||||
graph_created=0
|
||||
@@ -247,7 +247,7 @@ agent_session=""
|
||||
while (( SECONDS < deadline )); do
|
||||
task_status="$(query_task_status "$task_id")"
|
||||
agent_session="$(query_agent_session "$task_id")"
|
||||
if [[ "$task_status" == "logseq.property/status.done" && "$agent_session" == "$expected_session" ]]; then
|
||||
if [[ "$task_status" == "logseq.property/status.in-review" && "$agent_session" == "$expected_session" ]]; then
|
||||
break
|
||||
fi
|
||||
if [[ -n "${bridge_pid:-}" ]] && ! kill -0 "$bridge_pid" 2>/dev/null; then
|
||||
@@ -259,8 +259,8 @@ while (( SECONDS < deadline )); do
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if [[ "$task_status" != "logseq.property/status.done" ]]; then
|
||||
echo "Expected task status done, got: ${task_status:-<empty>}" >&2
|
||||
if [[ "$task_status" != "logseq.property/status.in-review" ]]; then
|
||||
echo "Expected task status in-review, got: ${task_status:-<empty>}" >&2
|
||||
cat "$bridge_log" >&2
|
||||
cat "$bridge_err" >&2
|
||||
exit 1
|
||||
@@ -293,6 +293,6 @@ if "Block UUID:" not in prompt:
|
||||
raise SystemExit("block uuid missing from Codex prompt")
|
||||
PY
|
||||
|
||||
echo "task status: done"
|
||||
echo "task status: in-review"
|
||||
echo "agent-session-id: $agent_session"
|
||||
echo "agent bridge demo completed"
|
||||
|
||||
@@ -8,7 +8,7 @@ import subprocess
|
||||
import time
|
||||
|
||||
|
||||
TASK_TITLE = "测试 agent bridge 功能,把当前task status设置为done"
|
||||
TASK_TITLE = "Test AgentBridge task routing and completion status"
|
||||
EXPECTED_SESSION = "thread-e2e-agent-bridge"
|
||||
PARALLEL_TASK_TITLES = [
|
||||
"测试 agent bridge 并行执行任务 1",
|
||||
|
||||
@@ -1278,23 +1278,22 @@
|
||||
: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 '测试 agent bridge 功能,把当前task status设置为done' --status todo >/dev/null"
|
||||
["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}}/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}}/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}}'"
|
||||
"mkdir -p '{{tmp-dir}}/list-root' && printf '{:output-format :json}\\n' > '{{tmp-dir}}/list-root/cli.edn' && {{cli}} --root-dir '{{tmp-dir}}/list-root' --config '{{tmp-dir}}/list-root/cli.edn' --output json agent bridge list --all"],
|
||||
"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-json-paths {[:status] "ok", [:data :sessions] []}},
|
||||
:stdout-contains ["agent bridge"]},
|
||||
:covers
|
||||
{:commands ["agent bridge" "agent bridge list"],
|
||||
{:commands ["agent bridge"],
|
||||
:options
|
||||
{:global ["--config" "--graph" "--root-dir" "--output"],
|
||||
:agent ["--all"]}},
|
||||
:agent ["--dry-run"]}},
|
||||
: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"
|
||||
|
||||
@@ -155,9 +155,8 @@
|
||||
:options ["--dev-script"]}
|
||||
|
||||
:agent
|
||||
{:commands ["agent bridge"
|
||||
"agent bridge list"]
|
||||
:options ["--all"]}
|
||||
{:commands ["agent bridge"]
|
||||
:options ["--dry-run"]}
|
||||
|
||||
:completion
|
||||
{:commands ["completion"]
|
||||
|
||||
25
deps/db/src/logseq/db/sqlite/export.cljs
vendored
25
deps/db/src/logseq/db/sqlite/export.cljs
vendored
@@ -39,6 +39,29 @@
|
||||
(or (block-title pvalue)
|
||||
(:logseq.property/value pvalue)))
|
||||
|
||||
(defn- referenced-property-value-contents
|
||||
[db property]
|
||||
(if (= :db.type/ref (:db/valueType property))
|
||||
(->> (d/datoms db :avet (:db/ident property))
|
||||
(keep (fn [datom]
|
||||
(some->> (:v datom)
|
||||
(d/entity db)
|
||||
property-value-content)))
|
||||
set)
|
||||
#{}))
|
||||
|
||||
(defn- closed-values-for-export
|
||||
[db property]
|
||||
(let [referenced-contents (referenced-property-value-contents db property)]
|
||||
(->> (concat (entity-plus/lookup-kv-then-entity property :property/closed-values)
|
||||
(filter #(contains? referenced-contents (property-value-content %))
|
||||
(:block/_closed-value-property property)))
|
||||
(reduce (fn [closed-values value]
|
||||
(assoc closed-values (:db/id value) value))
|
||||
{})
|
||||
vals
|
||||
(sort-by :block/order))))
|
||||
|
||||
(defn- shallow-copy-page
|
||||
"Given a page or journal entity, shallow copies it e.g. no properties or tags info included.
|
||||
Pages that are shallow copied are at the edges of export and help keep the export size reasonable and
|
||||
@@ -147,7 +170,7 @@
|
||||
(->> user-property-idents
|
||||
(map (fn [ident]
|
||||
(let [property (d/entity db ident)
|
||||
closed-values (entity-plus/lookup-kv-then-entity property :property/closed-values)]
|
||||
closed-values (closed-values-for-export db property)]
|
||||
[property
|
||||
(cond-> (select-keys property
|
||||
(-> (disj db-property/schema-properties :logseq.property/classes)
|
||||
|
||||
52
deps/db/test/logseq/db/sqlite/export_test.cljs
vendored
52
deps/db/test/logseq/db/sqlite/export_test.cljs
vendored
@@ -553,6 +553,58 @@
|
||||
(get-in export-edn [:classes :user.class/MyClass :build/class-properties])))
|
||||
(is (not (contains? (:properties export-edn) legacy-property)))))
|
||||
|
||||
(deftest graph-export-omits-legacy-plugin-property-schema-attrs
|
||||
(let [plugin-property :plugin.property.degrande-colors/mugpet_degrande_colors_controls
|
||||
conn (db-test/create-conn-with-import-map
|
||||
{:properties {plugin-property {:logseq.property/type :json}}
|
||||
:pages-and-blocks [{:page {:block/title "page1"}
|
||||
:blocks [{:block/title "b1"}]}]})
|
||||
plugin-property-ent (d/entity @conn plugin-property)
|
||||
_ (d/transact! conn [{:db/id (:db/id plugin-property-ent)
|
||||
:hide? true
|
||||
:public? false}])
|
||||
export-edn (sqlite-export/build-export @conn {:export-type :graph})
|
||||
validation (sqlite-export/validate-export export-edn)]
|
||||
(is (nil? (:error validation)))
|
||||
(is (= {:logseq.property/type :json
|
||||
:db/cardinality :db.cardinality/one
|
||||
:block/title "mugpet_degrande_colors_controls"}
|
||||
(get-in export-edn [:properties plugin-property])))))
|
||||
|
||||
(deftest graph-export-keeps-referenced-recycled-closed-value-config
|
||||
(let [property-id :plugin.property.degrande-colors/tldraw
|
||||
closed-value-uuid (random-uuid)
|
||||
conn (db-test/create-conn-with-import-map
|
||||
{:properties {property-id {:logseq.property/type :default
|
||||
:build/closed-values [{:value "tldraw"
|
||||
:uuid closed-value-uuid}]}}
|
||||
:pages-and-blocks [{:page {:block/title "page1"}
|
||||
:blocks [{:block/title "b1"
|
||||
:build/properties {property-id [:block/uuid closed-value-uuid]}}]}]})
|
||||
closed-value (d/entity @conn [:block/uuid closed-value-uuid])
|
||||
_ (d/transact! conn [{:db/id (:db/id closed-value)
|
||||
:logseq.property/deleted-at 1}])
|
||||
export-edn (sqlite-export/build-export @conn {:export-type :graph})
|
||||
validation (sqlite-export/validate-export export-edn)]
|
||||
(is (nil? (:error validation)))
|
||||
(is (= [{:value "tldraw" :uuid closed-value-uuid}]
|
||||
(get-in export-edn [:properties property-id :build/closed-values])))))
|
||||
|
||||
(deftest graph-export-ignores-scalar-values-when-finding-referenced-closed-values
|
||||
(let [property-id :user.property/datetime
|
||||
conn (db-test/create-conn-with-import-map
|
||||
{:properties {property-id {:logseq.property/type :datetime}}
|
||||
:pages-and-blocks [{:page {:block/title "page1"}
|
||||
:blocks [{:block/title "b1"
|
||||
:build/properties {property-id 1779841453610}}]}]})
|
||||
export-edn (sqlite-export/build-export @conn {:export-type :graph})
|
||||
validation (sqlite-export/validate-export export-edn)]
|
||||
(is (nil? (:error validation)))
|
||||
(is (= {:logseq.property/type :datetime
|
||||
:db/cardinality :db.cardinality/one
|
||||
:block/title "datetime"}
|
||||
(get-in export-edn [:properties property-id])))))
|
||||
|
||||
(deftest import-view-blocks
|
||||
(let [original-data
|
||||
;; Test a mix of page and block types
|
||||
|
||||
@@ -113,7 +113,6 @@ The top-level help groups commands into graph inspection/editing, graph manageme
|
||||
- `login`
|
||||
- `logout`
|
||||
- `agent bridge`
|
||||
- `agent bridge list`
|
||||
- `completion`
|
||||
- `debug pull`
|
||||
- `skill show`
|
||||
@@ -126,8 +125,6 @@ The top-level help groups commands into graph inspection/editing, graph manageme
|
||||
|
||||
`agent bridge` is the first AgentBridge command surface. It resolves the target graph using normal CLI config precedence, resolves the AgentBridge name from `:agent-name` in `cli.edn` or the machine hostname, checks that `codex` is available, starts or reuses the graph's db-worker-node, registers the AgentBridge name in the graph, scans TODO `#Task` blocks assigned to that AgentBridge name, and listens to db-worker-node events for follow-up scans. Matched tasks are routed to `codex exec --json`; the bridge records the Codex session/thread id in `agent-bridge-sessions.edn` and writes it to the task's `agent-session-id` property. `--dry-run` performs the setup and scan but only prints the Codex commands it would run.
|
||||
|
||||
`agent bridge list` reads root-dir scoped bridge session records from `agent-bridge-sessions.edn`. Human output uses the columns `SESSION`, `STATUS`, `BACKEND`, `GRAPH`, `BLOCK`, `AGENT`, `STARTED`, and `UPDATED`, ending with `Count: N`. Completed sessions are hidden by default; use `--all` to include them.
|
||||
|
||||
## Global flags and output modes
|
||||
|
||||
Global flags are defined in `logseq.cli.command.core/global-spec`:
|
||||
|
||||
@@ -2605,6 +2605,8 @@
|
||||
util/caret-range)
|
||||
mobile-range (when mobile? (get-cursor-range))]
|
||||
(when (and (not forbidden-edit?) (contains? #{1 0} button))
|
||||
(when (= 1 button)
|
||||
(block-selection/set-pointer-down!))
|
||||
(cond
|
||||
(and meta? shift?)
|
||||
(when-not (empty? selection-blocks)
|
||||
@@ -3680,6 +3682,7 @@
|
||||
(defn- select-block-under-pointer!
|
||||
[selection-block-ids scroll-direction]
|
||||
(when (and (seq selection-block-ids)
|
||||
(block-selection/pointer-down?)
|
||||
(or (state/get-selection-start-block)
|
||||
(seq (state/get-selection-blocks))))
|
||||
(when-let [block-dom-node (or (visible-selection-boundary-block selection-block-ids scroll-direction)
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
(ns frontend.components.block.selection)
|
||||
|
||||
(defonce *pointer-is-down? (atom false))
|
||||
|
||||
(defn set-pointer-down!
|
||||
[]
|
||||
(reset! *pointer-is-down? true))
|
||||
|
||||
(defn clear-pointer-down!
|
||||
([]
|
||||
(reset! *pointer-is-down? false))
|
||||
([_]
|
||||
(clear-pointer-down!)))
|
||||
|
||||
(defn pointer-down?
|
||||
[]
|
||||
(true? @*pointer-is-down?))
|
||||
|
||||
(defn select-on-hover?
|
||||
[{:keys [last-client-y client-y dragging? editing-same-block? active-selection?]}]
|
||||
(and (or (not= last-client-y client-y)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [cljs-drag-n-drop.core :as dnd]
|
||||
[clojure.string :as string]
|
||||
[dommy.core :as d]
|
||||
[frontend.components.block.selection :as block-selection]
|
||||
[frontend.components.content :as cp-content]
|
||||
[frontend.components.find-in-page :as find-in-page]
|
||||
[frontend.components.handbooks :as handbooks]
|
||||
@@ -382,6 +383,9 @@
|
||||
(mixins/event-mixin
|
||||
(fn [state]
|
||||
(mixins/listen state js/window "pointerdown" hide-context-menu-and-clear-selection)
|
||||
(mixins/listen state js/window "pointerup" block-selection/clear-pointer-down!)
|
||||
(mixins/listen state js/window "pointercancel" block-selection/clear-pointer-down!)
|
||||
(mixins/listen state js/window "blur" block-selection/clear-pointer-down!)
|
||||
(mixins/listen state js/window "keydown"
|
||||
(fn [e]
|
||||
(cond
|
||||
|
||||
@@ -1668,7 +1668,7 @@
|
||||
[:div
|
||||
[:div (t :plugin/checking-for-updates)]
|
||||
(when sub-content [:p.opacity-60 sub-content])]
|
||||
(ui/loading ""))
|
||||
:info)
|
||||
(when uid (notification/clear! uid))))
|
||||
[check-pending? sub-content])
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[frontend.util :as util]
|
||||
[logseq.common.config :as common-config]
|
||||
[logseq.common.graph-registry :as graph-registry]
|
||||
[logseq.common.uuid :as common-uuid]
|
||||
[logseq.db :as ldb]
|
||||
[promesa.core :as p]))
|
||||
|
||||
@@ -96,6 +97,20 @@
|
||||
(ldb/get-graph-local-uuid db*))
|
||||
str))))
|
||||
|
||||
(defn- new-local-graph-uuid
|
||||
[]
|
||||
(uuid (str "00000000" (subs (str (common-uuid/gen-uuid)) 8))))
|
||||
|
||||
(defn- <ensure-local-graph-uuid!
|
||||
[repo db*]
|
||||
(if-let [local-graph-uuid (ldb/get-graph-local-uuid db*)]
|
||||
(p/resolved local-graph-uuid)
|
||||
(let [local-graph-uuid (new-local-graph-uuid)]
|
||||
(p/let [_ (db/transact! repo
|
||||
[(ldb/kv :logseq.kv/local-graph-uuid local-graph-uuid)]
|
||||
{:graph-open/ensure-local-graph-uuid? true})]
|
||||
local-graph-uuid))))
|
||||
|
||||
(defn remember-current-graph-id-in-tab!
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
@@ -106,13 +121,15 @@
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [db* (db/get-db repo)]
|
||||
(<upsert-graph-registry-entry!
|
||||
{:repo repo
|
||||
:graph-name (common-config/strip-leading-db-version-prefix repo)
|
||||
:local-graph-id (some-> (ldb/get-graph-local-uuid db*) str)
|
||||
:graph-id (some-> (or (ldb/get-graph-rtc-uuid db*)
|
||||
(ldb/get-graph-local-uuid db*))
|
||||
str)}))))
|
||||
(p/let [local-graph-uuid (<ensure-local-graph-uuid! repo db*)
|
||||
db* (or (db/get-db repo) db*)
|
||||
graph-uuid (or (ldb/get-graph-rtc-uuid db*)
|
||||
local-graph-uuid)]
|
||||
(<upsert-graph-registry-entry!
|
||||
{:repo repo
|
||||
:graph-name (common-config/strip-leading-db-version-prefix repo)
|
||||
:local-graph-id (str local-graph-uuid)
|
||||
:graph-id (some-> graph-uuid str)})))))
|
||||
|
||||
(defn settle-metadata-to-local!
|
||||
[m]
|
||||
|
||||
@@ -354,6 +354,7 @@
|
||||
[(t :plugin/up-to-date ":)") :success]
|
||||
|
||||
[error-code :error])
|
||||
rate-limit-error? (some-> msg str (string/includes? "API rate limit"))
|
||||
pending? (seq (:plugin/updates-pending @state/state))]
|
||||
|
||||
(if (and only-check pending?)
|
||||
@@ -365,11 +366,12 @@
|
||||
(state/consume-updates-from-coming-plugin! payload true))
|
||||
|
||||
;; notify human tips
|
||||
(notification/show!
|
||||
(str
|
||||
(if (= :error type) "[Error]" "")
|
||||
"<" (:id payload) "> "
|
||||
msg) type)))
|
||||
(when-not rate-limit-error?
|
||||
(notification/show!
|
||||
(str
|
||||
(if (= :error type) "[Error]" "")
|
||||
"<" (:id payload) "> "
|
||||
msg) type))))
|
||||
|
||||
(when-not fake-error?
|
||||
(js/console.error "Update Error:" (:error-code payload))))
|
||||
|
||||
@@ -108,8 +108,6 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
|
||||
(defn- throw-upsert-blocks-error!
|
||||
[item]
|
||||
(js/console.error "Upsert blocks wrong data: ")
|
||||
(js/console.dir item)
|
||||
(throw (ex-info "Search upsert-blocks wrong data: "
|
||||
(bean/->clj item))))
|
||||
|
||||
@@ -537,6 +535,10 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
(string/join " "))
|
||||
title)))
|
||||
|
||||
(defn- block-result-title
|
||||
[block]
|
||||
(db-content/recur-replace-uuid-in-block-title block))
|
||||
|
||||
(defn- matched-alias
|
||||
[q block]
|
||||
(when-not (string/blank? q)
|
||||
@@ -669,13 +671,13 @@ DROP TRIGGER IF EXISTS blocks_au;
|
||||
(when (include-search-block? conn block code-class option)
|
||||
(let [alias-source (some-> (first (:block/_alias block))
|
||||
(select-keys [:block/uuid :block/title]))
|
||||
alias-match (matched-alias q block)
|
||||
display-title (if (:enable-snippet? option)
|
||||
(if (page-or-object? block)
|
||||
(ensure-highlighted-snippet snippet (:block/title block) q)
|
||||
(ensure-highlighted-snippet snippet title q))
|
||||
(if (page-or-object? block)
|
||||
(:block/title block)
|
||||
alias-match (matched-alias q block)
|
||||
page-or-object-result? (page-or-object? block)
|
||||
result-title (if page-or-object-result? (block-result-title block) title)
|
||||
display-title (if (:enable-snippet? option)
|
||||
(ensure-highlighted-snippet snippet result-title q)
|
||||
(if page-or-object-result?
|
||||
result-title
|
||||
(or snippet title)))
|
||||
block-page (or
|
||||
(:block/uuid (:block/page block))
|
||||
|
||||
@@ -20,23 +20,13 @@
|
||||
{:dry-run {:desc "Print Codex commands without starting Codex or writing agent-session-id"
|
||||
:coerce :boolean}})
|
||||
|
||||
(def ^:private bridge-list-spec
|
||||
{:all {:desc "Include completed sessions"
|
||||
:coerce :boolean}})
|
||||
|
||||
(def entries
|
||||
[(core/command-entry ["agent" "bridge"]
|
||||
:agent-bridge
|
||||
"Run task agent bridge"
|
||||
bridge-spec
|
||||
{:examples ["logseq agent bridge --graph my-graph"
|
||||
"logseq agent bridge --graph my-graph --dry-run"]})
|
||||
(core/command-entry ["agent" "bridge" "list"]
|
||||
:agent-bridge-list
|
||||
"List agent bridge sessions"
|
||||
bridge-list-spec
|
||||
{:examples ["logseq agent bridge list"
|
||||
"logseq agent bridge list --all"]})])
|
||||
"logseq agent bridge --graph my-graph --dry-run"]})])
|
||||
|
||||
(defn- trim-non-empty
|
||||
[value]
|
||||
@@ -75,11 +65,6 @@
|
||||
:graph graph
|
||||
:dry-run? (boolean (:dry-run options))}})
|
||||
|
||||
:agent-bridge-list
|
||||
{:ok? true
|
||||
:action {:type :agent-bridge-list
|
||||
:all? (boolean (:all options))}}
|
||||
|
||||
{:ok? false
|
||||
:error {:code :unknown-command
|
||||
:message (str "unknown agent command: " command)}}))
|
||||
@@ -456,19 +441,6 @@
|
||||
:status status
|
||||
:updated-at (js/Date.now)}))
|
||||
|
||||
(defn list-sessions
|
||||
[config {:keys [all?]}]
|
||||
(let [sessions (vec (:sessions (read-session-store config)))]
|
||||
(if all?
|
||||
sessions
|
||||
(vec (remove #(= :completed (:status %)) sessions)))))
|
||||
|
||||
(defn execute-list
|
||||
[action config]
|
||||
{:status :ok
|
||||
:command :agent-bridge-list
|
||||
:data {:sessions (list-sessions config {:all? (:all? action)})}})
|
||||
|
||||
(defn- now-iso
|
||||
[]
|
||||
(.toISOString (js/Date.)))
|
||||
@@ -873,6 +845,17 @@
|
||||
{}]))]
|
||||
true)))
|
||||
|
||||
(defn- mark-agent-bridge-task-in-review!
|
||||
[cfg repo block]
|
||||
(let [block-uuid (:block/uuid block)]
|
||||
(p/let [_ (transport/invoke cfg :thread-api/apply-outliner-ops
|
||||
[repo [[:batch-set-property [[block-uuid]
|
||||
:logseq.property/status
|
||||
:logseq.property/status.in-review
|
||||
{}]]]
|
||||
{}])]
|
||||
true)))
|
||||
|
||||
(def ^:private routable-task-query
|
||||
'[:find [(pull ?e [:db/id
|
||||
:block/uuid
|
||||
@@ -953,11 +936,18 @@
|
||||
(emit-log! cfg (log-line (str "Codex command prepared for " (block-uuid-str block) ": " preview)))
|
||||
(p/let [{:keys [session]} (start-codex! command
|
||||
{:on-exit (fn [code session-id]
|
||||
(when session-id
|
||||
(update-session-status! cfg session-id
|
||||
(if (zero? (or code 1))
|
||||
:completed
|
||||
:failed))))})
|
||||
(let [success? (zero? (or code 1))]
|
||||
(when session-id
|
||||
(update-session-status! cfg session-id
|
||||
(if success?
|
||||
:completed
|
||||
:failed))
|
||||
(when success?
|
||||
(-> (p/let [cfg* (cli-server/ensure-server! cfg repo)
|
||||
_ (mark-agent-bridge-task-in-review! cfg* repo block)]
|
||||
true)
|
||||
(p/catch (fn [e]
|
||||
(log/error :agent-bridge-task-in-review-failed e))))))))})
|
||||
_ (when-not (seq session)
|
||||
(throw (ex-info "codex session id missing"
|
||||
{:code :codex-session-id-missing})))
|
||||
|
||||
@@ -1320,23 +1320,21 @@
|
||||
:logseq.property.asset/checksum (:asset/checksum metadata)
|
||||
:block/tags #{asset-tag-id}})
|
||||
blocks)))
|
||||
block-uuid (get-in action* [:blocks 0 :block/uuid])
|
||||
_ (when-not (uuid? block-uuid)
|
||||
(throw (ex-info "created asset block missing uuid"
|
||||
{:code :asset-create-failed})))
|
||||
_ (copy-asset-file-to-graph! config
|
||||
(:repo action)
|
||||
block-uuid
|
||||
(:asset/type metadata)
|
||||
asset-path)
|
||||
create-result (add-command/execute-add-block (assoc action* :type :add-block) config)
|
||||
created-ids (vec (or (get-in create-result [:data :result]) []))
|
||||
created-id (first created-ids)
|
||||
_ (when-not (some? created-id)
|
||||
(throw (ex-info "asset block not created"
|
||||
{:code :asset-create-failed})))
|
||||
created-entity (pull-entity-by-id cfg (:repo action) [:db/id :block/uuid] created-id)
|
||||
block-uuid (:block/uuid created-entity)
|
||||
_ (when-not (uuid? block-uuid)
|
||||
(throw (ex-info "created asset block missing uuid"
|
||||
{:code :asset-create-failed
|
||||
:id created-id})))
|
||||
_ (copy-asset-file-to-graph! config
|
||||
(:repo action)
|
||||
block-uuid
|
||||
(:asset/type metadata)
|
||||
asset-path)]
|
||||
{:code :asset-create-failed})))]
|
||||
{:status :ok
|
||||
:data {:result [created-id]}})
|
||||
|
||||
|
||||
@@ -325,6 +325,14 @@
|
||||
:else
|
||||
nil))
|
||||
|
||||
(defn- validate-agent-bridge
|
||||
[summary {:keys [command args cmds]}]
|
||||
(when (and (= command :agent-bridge)
|
||||
(seq args))
|
||||
(command-core/unknown-command-result
|
||||
summary
|
||||
(str "unknown command: " (string/join " " (concat cmds args))))))
|
||||
|
||||
(defn- validate-graph-sync-and-completion
|
||||
[summary {:keys [command opts import-export-type completion-shell-error]}]
|
||||
(cond
|
||||
@@ -379,6 +387,7 @@
|
||||
(or (validate-write-and-upsert summary validation-context)
|
||||
(validate-target-query-and-search summary validation-context)
|
||||
(validate-option-contracts summary validation-context)
|
||||
(validate-agent-bridge summary validation-context)
|
||||
(validate-graph-sync-and-completion summary validation-context)))
|
||||
|
||||
(defn- command-has-content?
|
||||
@@ -589,7 +598,7 @@
|
||||
(:graph-list :graph-create :graph-switch :graph-remove :graph-validate :graph-info)
|
||||
(graph-command/build-graph-action command graph repo options)
|
||||
|
||||
(:agent-bridge :agent-bridge-list)
|
||||
:agent-bridge
|
||||
(agent-command/build-action command options repo graph)
|
||||
|
||||
:graph-backup-list
|
||||
@@ -701,7 +710,6 @@
|
||||
(case (:type action)
|
||||
:graph-list (graph-command/execute-graph-list action config)
|
||||
:agent-bridge (agent-command/execute-bridge action config)
|
||||
:agent-bridge-list (agent-command/execute-list action config)
|
||||
:graph-backup-list (graph-command/execute-graph-backup-list action config)
|
||||
:graph-backup-create (graph-command/execute-graph-backup-create action config)
|
||||
:graph-backup-restore (graph-command/execute-graph-backup-restore action config)
|
||||
|
||||
@@ -576,26 +576,6 @@
|
||||
(str table "\n\n" warning)
|
||||
table)))
|
||||
|
||||
(defn- format-agent-bridge-list
|
||||
[sessions now-ms]
|
||||
(let [session-field (fn [value]
|
||||
(cond
|
||||
(keyword? value) (name value)
|
||||
(nil? value) nil
|
||||
:else (str value)))]
|
||||
(format-counted-table
|
||||
["SESSION" "STATUS" "BACKEND" "GRAPH" "BLOCK" "AGENT" "STARTED" "UPDATED"]
|
||||
(mapv (fn [session]
|
||||
[(session-field (:session session))
|
||||
(session-field (:status session))
|
||||
(session-field (:backend session))
|
||||
(session-field (:graph session))
|
||||
(session-field (:block session))
|
||||
(session-field (:agent session))
|
||||
(human-ago (:started-at session) now-ms)
|
||||
(human-ago (:updated-at session) now-ms)])
|
||||
(or sessions [])))))
|
||||
|
||||
(defn- format-agent-bridge
|
||||
[data]
|
||||
(if (seq (:logs data))
|
||||
@@ -1051,7 +1031,6 @@
|
||||
:server-list (format-server-list (:servers data)
|
||||
(get-in human [:server-list :revision-mismatch]))
|
||||
:agent-bridge (format-agent-bridge data)
|
||||
:agent-bridge-list (format-agent-bridge-list (:sessions data) now-ms)
|
||||
:server-cleanup (format-server-cleanup data)
|
||||
(:server-start :server-stop :server-restart)
|
||||
(format-server-action command data)
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
(:require [cljs.test :refer [are deftest is]]
|
||||
[frontend.components.block.selection :as selection]))
|
||||
|
||||
(deftest pointer-down-state-lifecycle
|
||||
(selection/clear-pointer-down!)
|
||||
(is (false? (selection/pointer-down?)))
|
||||
(selection/set-pointer-down!)
|
||||
(is (true? (selection/pointer-down?)))
|
||||
(selection/clear-pointer-down!)
|
||||
(is (false? (selection/pointer-down?)))
|
||||
(selection/set-pointer-down!)
|
||||
(selection/clear-pointer-down! #js {:type "pointerup"})
|
||||
(is (false? (selection/pointer-down?))))
|
||||
|
||||
(deftest select-on-hover-keeps-active-selection-while-scroll-moves-block-under-pointer
|
||||
(is (true?
|
||||
(selection/select-on-hover?
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
(ns frontend.handler.graph-test
|
||||
(:require [cljs.test :refer [async deftest is testing]]
|
||||
[datascript.core :as d]
|
||||
[frontend.db :as db]
|
||||
[frontend.common.idb :as idb]
|
||||
[frontend.handler.graph]
|
||||
[frontend.state :as state]
|
||||
[frontend.util.url :as url-util]
|
||||
[logseq.common.graph-registry :as graph-registry]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.schema :as db-schema]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(deftest graph-registry-key-is-indexeddb-compatible-test
|
||||
@@ -49,6 +53,42 @@
|
||||
:graph-id "remote-uuid"}
|
||||
@stored-graph))))))
|
||||
|
||||
(deftest upsert-current-graph-registry-repairs-missing-local-graph-uuid-test
|
||||
(async done
|
||||
(let [upsert-current-f (some-> (resolve 'frontend.handler.graph/<upsert-current-graph-registry!) deref)
|
||||
conn (d/create-conn db-schema/schema)
|
||||
registry-entry (atom nil)]
|
||||
(is (fn? upsert-current-f) "Current graph registry upsert should exist")
|
||||
(d/transact! conn [{:db/ident :logseq.kv/schema-version
|
||||
:kv/value db-schema/version}])
|
||||
(p/with-redefs [state/get-current-repo (constantly "logseq_db_broken")
|
||||
db/get-db (fn
|
||||
([repo]
|
||||
(when (= "logseq_db_broken" repo) @conn))
|
||||
([repo deref?]
|
||||
(when (= "logseq_db_broken" repo)
|
||||
(if deref? @conn conn))))
|
||||
db/transact! (fn [repo tx-data tx-meta]
|
||||
(is (= "logseq_db_broken" repo))
|
||||
(d/transact! conn tx-data tx-meta)
|
||||
(p/resolved nil))
|
||||
frontend.handler.graph/<upsert-graph-registry-entry!
|
||||
(fn [entry]
|
||||
(reset! registry-entry entry)
|
||||
(p/resolved nil))]
|
||||
(-> (upsert-current-f)
|
||||
(.then (fn [_]
|
||||
(let [local-graph-uuid (ldb/get-graph-local-uuid @conn)]
|
||||
(is (uuid? local-graph-uuid))
|
||||
(is (= (str local-graph-uuid)
|
||||
(:local-graph-id @registry-entry)))
|
||||
(is (= (:local-graph-id @registry-entry)
|
||||
(:graph-id @registry-entry)))
|
||||
(done))))
|
||||
(.catch (fn [e]
|
||||
(is false (str e))
|
||||
(done))))))))
|
||||
|
||||
(deftest resolve-startup-repo-prefers-tab-repo-before-global-current-test
|
||||
(let [resolve-f (some-> (resolve 'frontend.handler.graph/resolve-startup-repo) deref)]
|
||||
(is (fn? resolve-f) "Startup repo resolver should exist")
|
||||
|
||||
@@ -618,6 +618,36 @@
|
||||
(is (= "Artificial Intelligence" (:block/title result)))
|
||||
(is (not (contains? result :alias))))))))
|
||||
|
||||
(deftest search-result-replaces-page-title-uuid-refs-without-alias-title
|
||||
(testing "page result titles resolve uuid refs but do not display alias titles from the search index"
|
||||
(let [page-id #uuid "00000000-0000-0000-0000-000000000246"
|
||||
ref-id #uuid "00000000-0000-0000-0000-000000000247"
|
||||
page {:db/id 1
|
||||
:block/uuid page-id
|
||||
:block/title (str "Artificial [[" ref-id "]]")
|
||||
:block/refs [{:block/uuid ref-id
|
||||
:block/title "Machine Learning"}]
|
||||
:block/alias [{:db/id 2
|
||||
:block/uuid #uuid "00000000-0000-0000-0000-000000000248"
|
||||
:block/title "ai"}]}]
|
||||
(with-redefs [d/entity (fn [_db [_attr id]]
|
||||
(when (= id page-id)
|
||||
page))
|
||||
ldb/page? (fn [entity] (= (:db/id entity) (:db/id page)))
|
||||
ldb/object? (constantly false)
|
||||
ldb/built-in? (constantly false)
|
||||
ldb/hidden? (constantly false)]
|
||||
(let [result (#'search/search-result->block-result
|
||||
(atom :db)
|
||||
"Artificial"
|
||||
nil
|
||||
{:enable-snippet? false}
|
||||
{:id (str page-id)
|
||||
:page (str page-id)
|
||||
:title "Artificial [[Machine Learning]] ai"})]
|
||||
(is (= "Artificial [[Machine Learning]]" (:block/title result)))
|
||||
(is (not (contains? result :alias))))))))
|
||||
|
||||
(deftest search-result-snippet-uses-canonical-page-title
|
||||
(testing "page snippets do not display alias titles from the search index"
|
||||
(let [page-id #uuid "00000000-0000-0000-0000-000000000242"
|
||||
|
||||
@@ -130,14 +130,16 @@
|
||||
|
||||
(deftest test-agent-command-entries
|
||||
(testing "parse agent bridge command surface"
|
||||
(let [bridge (commands/parse-args ["agent" "bridge" "--graph" "demo" "--dry-run"])
|
||||
list-result (commands/parse-args ["agent" "bridge" "list"])]
|
||||
(let [bridge (commands/parse-args ["agent" "bridge" "--graph" "demo" "--dry-run"])]
|
||||
(is (true? (:ok? bridge)))
|
||||
(is (= :agent-bridge (:command bridge)))
|
||||
(is (= "demo" (get-in bridge [:options :graph])))
|
||||
(is (true? (get-in bridge [:options :dry-run])))
|
||||
(is (true? (:ok? list-result)))
|
||||
(is (= :agent-bridge-list (:command list-result)))))
|
||||
(is (true? (get-in bridge [:options :dry-run])))))
|
||||
|
||||
(testing "agent bridge list is not a command"
|
||||
(let [result (commands/parse-args ["agent" "bridge" "list"])]
|
||||
(is (false? (:ok? result)))
|
||||
(is (= :unknown-command (get-in result [:error :code])))))
|
||||
|
||||
(testing "top-level help exposes the agent utility group"
|
||||
(let [summary (:summary (commands/parse-args ["--help"]))]
|
||||
@@ -166,14 +168,14 @@
|
||||
(is (= "logseq_db_demo" (get-in result [:action :repo])))
|
||||
(is (true? (get-in result [:action :dry-run?])))))
|
||||
|
||||
(testing "agent bridge list is root-dir scoped and does not require graph"
|
||||
(testing "agent bridge list action is not supported"
|
||||
(let [result (commands/build-action {:ok? true
|
||||
:command :agent-bridge-list
|
||||
:options {}
|
||||
:args []}
|
||||
{})]
|
||||
(is (true? (:ok? result)))
|
||||
(is (= :agent-bridge-list (get-in result [:action :type]))))))
|
||||
(is (false? (:ok? result)))
|
||||
(is (= :unknown-command (get-in result [:error :code]))))))
|
||||
|
||||
(deftest test-resolve-agent-name
|
||||
(testing "config overrides hostname"
|
||||
@@ -1264,6 +1266,72 @@
|
||||
(is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest test-agent-bridge-task-route-marks-successful-completion-in-review
|
||||
(async done
|
||||
(let [block (task-block {})
|
||||
route-opts {:repo "logseq_db_demo"
|
||||
:graph "demo"
|
||||
:agent-name "build-host"
|
||||
:prompt-templates {:task "Task {{graph}} {{block-uuid}} {{agent-name}}\n{{task-block-tree}}"}}
|
||||
route! (fn []
|
||||
(#'agent-command/route-task! {:root-dir "/tmp/logseq"}
|
||||
route-opts
|
||||
{:block block
|
||||
:tree-text "- Ship the CLI bridge"}))
|
||||
run-scenario
|
||||
(fn [exit-code]
|
||||
(let [ops* (atom [])
|
||||
session-statuses* (atom [])]
|
||||
(p/let [_ (p/with-redefs [transport/invoke
|
||||
(fn [_ method args]
|
||||
(case method
|
||||
:thread-api/q
|
||||
(if (string/includes? (pr-str args) ":logseq.property/status")
|
||||
(p/resolved :logseq.property/status.todo)
|
||||
(p/resolved nil))
|
||||
|
||||
:thread-api/apply-outliner-ops
|
||||
(let [[_ ops _] args]
|
||||
(swap! ops* into ops)
|
||||
(p/resolved {:ok true}))
|
||||
|
||||
(p/rejected (ex-info "unexpected invoke"
|
||||
{:method method
|
||||
:args args}))))
|
||||
cli-server/ensure-server! (fn [cfg _repo]
|
||||
(assoc cfg :base-url "http://127.0.0.1:1234"))
|
||||
agent-command/start-codex! (fn [_command opts]
|
||||
((:on-exit opts) exit-code "session-123")
|
||||
(p/resolved {:session "session-123"
|
||||
:status :running}))
|
||||
agent-command/record-session! (fn [_cfg _session-record]
|
||||
true)
|
||||
agent-command/update-session-status! (fn [_cfg session-id status]
|
||||
(swap! session-statuses* conj [session-id status])
|
||||
true)
|
||||
agent-command/write-agent-session-id! (fn [_cfg _repo _block-uuid _session-id]
|
||||
(p/resolved true))]
|
||||
(p/let [_ (route!)
|
||||
_ (p/delay 10)]
|
||||
true))]
|
||||
{:ops @ops*
|
||||
:session-statuses @session-statuses*})))
|
||||
in-review-op [:batch-set-property [[(:block/uuid block)]
|
||||
:logseq.property/status
|
||||
:logseq.property/status.in-review
|
||||
{}]]]
|
||||
(-> (p/let [success (run-scenario 0)
|
||||
failure (run-scenario 1)]
|
||||
(is (= [["session-123" :completed]]
|
||||
(:session-statuses success)))
|
||||
(is (some #(= in-review-op %) (:ops success)))
|
||||
(is (= [["session-123" :failed]]
|
||||
(:session-statuses failure)))
|
||||
(is (not-any? #(= in-review-op %) (:ops failure))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest test-agent-bridge-task-route-does-not-mark-started-before-session-id-is-written
|
||||
(async done
|
||||
(let [block (task-block {})
|
||||
@@ -1390,15 +1458,10 @@
|
||||
:agent "build-host"
|
||||
:started-at 1000
|
||||
:updated-at 3000})
|
||||
(testing "list hides completed sessions by default"
|
||||
(is (= ["codex-running"]
|
||||
(mapv :session (agent-command/list-sessions config {})))))
|
||||
(testing "list can include completed sessions"
|
||||
(is (= ["codex-running" "codex-done"]
|
||||
(mapv :session (agent-command/list-sessions config {:all? true})))))
|
||||
(testing "session file is EDN data"
|
||||
(let [payload (reader/read-string (fs/readFileSync (agent-command/session-store-path config) "utf8"))]
|
||||
(is (= 2 (count (:sessions payload))))))
|
||||
(is (= ["codex-running" "codex-done"]
|
||||
(mapv :session (:sessions payload))))))
|
||||
(finally
|
||||
(fs/rmSync root #js {:recursive true :force true})))))
|
||||
|
||||
@@ -1415,7 +1478,8 @@
|
||||
:agent "build-host"
|
||||
:started-at 1000
|
||||
:updated-at 2000})
|
||||
(let [session (first (agent-command/list-sessions config {:all? true}))]
|
||||
(let [payload (reader/read-string (fs/readFileSync (agent-command/session-store-path config) "utf8"))
|
||||
session (first (:sessions payload))]
|
||||
(is (= :completed (:status session)))
|
||||
(is (= :codex (:backend session)))
|
||||
(is (= "demo" (:graph session)))
|
||||
@@ -1426,32 +1490,6 @@
|
||||
(finally
|
||||
(fs/rmSync root #js {:recursive true :force true})))))
|
||||
|
||||
(deftest test-execute-agent-bridge-list-and-format
|
||||
(let [root (temp-root)]
|
||||
(try
|
||||
(agent-command/record-session! {:root-dir root}
|
||||
{:session "codex-running"
|
||||
:status :running
|
||||
:backend :codex
|
||||
:graph "demo"
|
||||
:block "11111111-1111-1111-1111-111111111111"
|
||||
:agent "build-host"
|
||||
:started-at 1000
|
||||
:updated-at 2000})
|
||||
(let [result (agent-command/execute-list {:type :agent-bridge-list} {:root-dir root})
|
||||
output (cli-format/format-result result {:output-format :human :now-ms 3000})]
|
||||
(is (= :ok (:status result)))
|
||||
(is (string/includes? output "SESSION"))
|
||||
(is (string/includes? output "STATUS"))
|
||||
(is (string/includes? output "BACKEND"))
|
||||
(is (string/includes? output "codex-running"))
|
||||
(is (string/includes? output "running"))
|
||||
(is (not (string/includes? output ":running")))
|
||||
(is (not (string/includes? output ":codex")))
|
||||
(is (string/includes? output "Count: 1")))
|
||||
(finally
|
||||
(fs/rmSync root #js {:recursive true :force true})))))
|
||||
|
||||
(deftest test-format-agent-bridge-logs
|
||||
(let [output (cli-format/format-result {:status :ok
|
||||
:command :agent-bridge
|
||||
@@ -1575,7 +1613,8 @@
|
||||
:logseq.property/status.doing
|
||||
{}]]]]]
|
||||
@calls))
|
||||
(let [sessions (agent-command/list-sessions {:root-dir root} {})]
|
||||
(let [payload (reader/read-string (fs/readFileSync (agent-command/session-store-path {:root-dir root}) "utf8"))
|
||||
sessions (:sessions payload)]
|
||||
(is (= [{:session "session-123"
|
||||
:status :running
|
||||
:backend :codex
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
(deftest test-execute-upsert-asset-create-applies-metadata-and-copies-file
|
||||
(async done
|
||||
(let [add-actions* (atom [])
|
||||
lifecycle-calls* (atom [])
|
||||
copy-calls* (atom [])
|
||||
action {:type :upsert-asset
|
||||
:mode :create
|
||||
@@ -84,16 +85,19 @@
|
||||
:graph "demo-graph"
|
||||
:asset-path "/tmp/logo.png"
|
||||
:content "Logo"
|
||||
:blocks [{:block/title "Logo"}] }]
|
||||
:blocks [{:block/title "Logo"
|
||||
:block/uuid (uuid "00000000-0000-0000-0000-000000000101")}] }]
|
||||
(-> (p/with-redefs [cli-server/ensure-server! (fn [config _repo]
|
||||
(p/resolved (assoc config :base-url "http://example")))
|
||||
upsert-command/asset-file-exists? (fn [_] true)
|
||||
upsert-command/asset-file-size-bytes (fn [_] 123)
|
||||
upsert-command/asset-file-checksum (fn [_] "sha-256-value")
|
||||
upsert-command/copy-asset-file-to-graph! (fn [_ repo block-uuid asset-type source-path]
|
||||
(swap! lifecycle-calls* conj :copy)
|
||||
(swap! copy-calls* conj [repo block-uuid asset-type source-path])
|
||||
"/tmp/copied/logo.png")
|
||||
add-command/execute-add-block (fn [add-action _]
|
||||
(swap! lifecycle-calls* conj :add-block)
|
||||
(swap! add-actions* conj add-action)
|
||||
(p/resolved {:status :ok
|
||||
:data {:result [101]}}))
|
||||
@@ -127,7 +131,8 @@
|
||||
(uuid "00000000-0000-0000-0000-000000000101")
|
||||
"png"
|
||||
"/tmp/logo.png"]]
|
||||
@copy-calls*))))
|
||||
@copy-calls*))
|
||||
(is (= [:copy :add-block] @lifecycle-calls*))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
@@ -773,4 +778,3 @@
|
||||
(p/catch (fn [e]
|
||||
(is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user