diff --git a/home-manager/services/obsidian/default.nix b/home-manager/services/obsidian/default.nix index 077302ce0..d43f246e4 100644 --- a/home-manager/services/obsidian/default.nix +++ b/home-manager/services/obsidian/default.nix @@ -24,6 +24,18 @@ let } ) ); + + # Trigger obsidian-git's auto-backup via CDP. The Electron renderer's + # setTimeout doesn't fire under headless xvfb (futex blocks the event + # loop), but CDP uses IPC and bypasses it. All git operations still + # run through the obsidian-git plugin. + obsidianGitTrigger = pkgs.writeShellScriptBin "obsidian-git-trigger" ( + builtins.readFile ( + pkgs.replaceVars ./obsidian-git-trigger.sh { + inherit (pkgs) curl jq websocat; + } + ) + ); in # Only enable on kyber (gateway host) - desktops already get pkgs.obsidian # directly via home-manager/packages/default.nix. @@ -49,4 +61,29 @@ lib.mkIf host.isKyber { WantedBy = [ "default.target" ]; }; }; + + systemd.user.services.obsidian-git-trigger = { + Unit = { + Description = "Trigger obsidian-git auto-backup via CDP"; + After = [ "obsidian.service" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${obsidianGitTrigger}/bin/obsidian-git-trigger"; + }; + }; + + systemd.user.timers.obsidian-git-trigger = { + Unit = { + Description = "Trigger obsidian-git auto-backup every 3 minutes"; + }; + Timer = { + OnBootSec = "2min"; + OnUnitActiveSec = "3min"; + Unit = "obsidian-git-trigger.service"; + }; + Install = { + WantedBy = [ "timers.target" ]; + }; + }; } diff --git a/home-manager/services/obsidian/obsidian-git-trigger.sh b/home-manager/services/obsidian/obsidian-git-trigger.sh new file mode 100644 index 000000000..eb92096f8 --- /dev/null +++ b/home-manager/services/obsidian/obsidian-git-trigger.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Trigger obsidian-git's commitAndSync via CDP. +# +# The Electron renderer's setTimeout doesn't fire under headless xvfb +# (futex_wait_queue blocks the event loop pump), but CDP messages use +# IPC and bypass the stuck loop. We trigger the backup and keep the +# websocket open with ping-interval for 15s to pump the event loop +# while git operations complete through the obsidian-git plugin. + +CDP="http://localhost:9222" + +WS_URL=$(@curl@/bin/curl -sf "$CDP/json" | @jq@/bin/jq -r '.[0].webSocketDebuggerUrl // empty') +[ -z "$WS_URL" ] && exit 0 + +# Send trigger, then keep stdin open for 15s so websocat stays alive. +# The --ping-interval sends websocket pings that pump the Electron +# event loop, allowing the obsidian-git promise queue to execute. +{ + echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}' + sleep 15 +} | @websocat@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true diff --git a/home-manager/services/obsidian/obsidian-headless.sh b/home-manager/services/obsidian/obsidian-headless.sh index d61a81749..1d28c0724 100644 --- a/home-manager/services/obsidian/obsidian-headless.sh +++ b/home-manager/services/obsidian/obsidian-headless.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -exec @xvfbRun@/bin/xvfb-run -a -s "-screen 0 1280x1024x24" @obsidian@/bin/obsidian --no-sandbox --disable-gpu --disable-features=FontationsFontIndexer --vault @homeDir@/ghq/github.com/shunkakinoki/wiki "$@" +exec @xvfbRun@/bin/xvfb-run -a -s "-screen 0 1280x1024x24" @obsidian@/bin/obsidian --no-sandbox --disable-gpu --disable-features=FontationsFontIndexer --remote-debugging-port=9222 --vault @homeDir@/ghq/github.com/shunkakinoki/wiki "$@" diff --git a/spec/coverage_spec.sh b/spec/coverage_spec.sh index 70355d45c..09f695838 100644 --- a/spec/coverage_spec.sh +++ b/spec/coverage_spec.sh @@ -368,6 +368,7 @@ home-manager/modules/local-scripts/notify-local.sh home-manager/modules/local-scripts/pushover-notify.sh home-manager/modules/local-scripts/tmux-bridge.sh home-manager/modules/npm-globals/install-npm-globals.sh +home-manager/services/obsidian/obsidian-git-trigger.sh home-manager/services/obsidian/obsidian-headless.sh home-manager/services/openclaw/activate.sh home-manager/services/paperclip/activate.sh diff --git a/spec/obsidian_git_trigger_spec.sh b/spec/obsidian_git_trigger_spec.sh new file mode 100644 index 000000000..28195c01f --- /dev/null +++ b/spec/obsidian_git_trigger_spec.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2329 + +Describe 'home-manager/services/obsidian/obsidian-git-trigger.sh' +SCRIPT="$PWD/home-manager/services/obsidian/obsidian-git-trigger.sh" + +Describe 'script properties' +It 'uses bash shebang' +When run bash -c "head -1 '$SCRIPT'" +The output should include '#!/usr/bin/env bash' +End + +It 'passes bash syntax check after replacing placeholders' +When run bash -c "sed -e 's|@curl@|/usr|g' -e 's|@jq@|/usr|g' -e 's|@websocat@|/usr|g' '$SCRIPT' | bash -n" +The status should be success +End +End + +Describe 'placeholder references' +It 'references curl via placeholder' +When run bash -c "grep '@curl@' '$SCRIPT'" +The output should include '@curl@' +End + +It 'references jq via placeholder' +When run bash -c "grep '@jq@' '$SCRIPT'" +The output should include '@jq@' +End + +It 'references websocat via placeholder' +When run bash -c "grep '@websocat@' '$SCRIPT'" +The output should include '@websocat@' +End +End + +Describe 'CDP integration' +It 'connects to CDP on port 9222' +When run bash -c "grep '9222' '$SCRIPT'" +The output should include '9222' +End + +It 'triggers doAutoCommitAndSync' +When run bash -c "grep 'doAutoCommitAndSync' '$SCRIPT'" +The output should include 'doAutoCommitAndSync' +End +End + +End