From 02435ee1ed46dd87aca016f6472d510d4d301c20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 04:32:06 +0000 Subject: [PATCH 1/2] chore(deps): bump actions/checkout from 6.0.2 to 6.0.3 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1e9cb8f..255342b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Run StyLua check uses: JohnnyMorganz/stylua-action@76fd70c03e6340ceaf673366712db9b20560b402 # v5.0.0 with: @@ -49,7 +49,7 @@ jobs: - nightly steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up Neovim uses: rhysd/action-setup-vim@febef33995d6649302e9d88dda81e071b68f16a7 # v1.6.1 with: From 8d46ad188a1b72996534b362f15fb01629d21c6d Mon Sep 17 00:00:00 2001 From: Masaaki Hirotsu Date: Tue, 16 Jun 2026 06:35:21 +0900 Subject: [PATCH 2/2] fix(persist): isolate overlapping writes with unique tmp paths Make the temp file name unique per write via hrtime and a counter so concurrent writes to the same scope no longer collide on rename/unlink. Resolve the root window through stack.get_root_winid so saving from the stack view no longer depends on filetype and window state timing. --- lua/peekstack/persist/sessions.lua | 13 ++------- lua/peekstack/persist/store.lua | 13 +++++++-- tests/persist_store_spec.lua | 47 ++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/lua/peekstack/persist/sessions.lua b/lua/peekstack/persist/sessions.lua index 11af447..62def7c 100644 --- a/lua/peekstack/persist/sessions.lua +++ b/lua/peekstack/persist/sessions.lua @@ -24,19 +24,10 @@ end ---@return integer function M.resolve_root_winid(root_winid) if root_winid and type(root_winid) == "number" and vim.api.nvim_win_is_valid(root_winid) then - return root_winid + return stack.get_root_winid(root_winid) end - local winid = vim.api.nvim_get_current_win() - local bufnr = vim.api.nvim_win_get_buf(winid) - if vim.bo[bufnr].filetype == "peekstack-stack" then - local ok, stack_root_winid = pcall(vim.api.nvim_win_get_var, winid, "peekstack_root_winid") - if ok and type(stack_root_winid) == "number" and vim.api.nvim_win_is_valid(stack_root_winid) then - return stack_root_winid - end - end - - return winid + return stack.get_root_winid(vim.api.nvim_get_current_win()) end ---Collect the current stack items (truncated to `persist.max_items`). diff --git a/lua/peekstack/persist/store.lua b/lua/peekstack/persist/store.lua index ea3dd70..bfd479d 100644 --- a/lua/peekstack/persist/store.lua +++ b/lua/peekstack/persist/store.lua @@ -4,6 +4,15 @@ local notify = require("peekstack.util.notify") local M = {} +local write_counter = 0 + +---@param path string +---@return string +local function next_tmp_path(path) + write_counter = write_counter + 1 + return string.format("%s.%d.%d.tmp", path, vim.uv.hrtime(), write_counter) +end + ---@param path string ---@return boolean local function ensure_parent_dir(path) @@ -110,7 +119,7 @@ function M.write(scope, data, opts) return end - local tmp_path = path .. ".tmp" + local tmp_path = next_tmp_path(path) vim.uv.fs_open(tmp_path, "w", 438, function(open_err, fd) if open_err or not fd then vim.schedule(function() @@ -159,7 +168,7 @@ function M.write_sync(scope, data) return false end - local tmp_path = path .. ".tmp" + local tmp_path = next_tmp_path(path) local fd = vim.uv.fs_open(tmp_path, "w", 438) if not fd then notify.warn("Failed to write session data: " .. path) diff --git a/tests/persist_store_spec.lua b/tests/persist_store_spec.lua index 5da7042..20ce245 100644 --- a/tests/persist_store_spec.lua +++ b/tests/persist_store_spec.lua @@ -192,6 +192,53 @@ describe("peekstack.persist.store", function() assert.same(data, store.read_sync(test_scope)) end) + it("allows overlapping async writes to the same scope", function() + local first = { + version = 2, + sessions = { + first = { + items = {}, + meta = { created_at = 1, updated_at = 1 }, + }, + }, + } + local second = { + version = 2, + sessions = { + second = { + items = {}, + meta = { created_at = 2, updated_at = 2 }, + }, + }, + } + + local done = 0 + local successes = {} + store.write(test_scope, first, { + on_done = function(ok) + done = done + 1 + successes[#successes + 1] = ok + end, + }) + store.write(test_scope, second, { + on_done = function(ok) + done = done + 1 + successes[#successes + 1] = ok + end, + }) + + local ok = vim.wait(wait_timeout_ms, function() + return done == 2 + end, wait_interval_ms) + assert.is_true(ok, "Timed out waiting for overlapping store writes") + assert.is_true(successes[1]) + assert.is_true(successes[2]) + + local result = read_and_wait(test_scope) + assert.equals(2, result.version) + assert.is_true(result.sessions.first ~= nil or result.sessions.second ~= nil) + end) + it("write_sync returns false when payload cannot be encoded", function() local ok = store.write_sync(test_scope, { version = 2,