Skip to content

Bump stv1024/auto-pin to 0.5.2 - #1223

Merged
paseo-bot[bot] merged 2 commits into
mainfrom
bump/stv1024/auto-pin-0.5.2
Oct 26, 2026
Merged

paseo-bot[bot] merged 2 commits into
mainfrom
bump/stv1024/auto-pin-0.5.2

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

stv1024/auto-pin: 0.5.1 → 0.5.2

@stv1024, this update is ready for review. The published version stays unchanged until approval.

Artifact and validation details

Package: paseo-auto-pin.

{
  "previous": {
    "kind": "npm",
    "package": "paseo-auto-pin",
    "version": "0.5.1",
    "resolved": "https://registry.npmjs.org/paseo-auto-pin/-/paseo-auto-pin-0.5.1.tgz",
    "integrity": "sha512-yw9pzEA7rt5nUWWeTX+S/ghPM0415wt6tdVzYUsDg/hQwqITfmXSp98Sq4fw8x2sLCVSW7wi16hpTecEtJneWw=="
  },
  "proposed": {
    "kind": "npm",
    "package": "paseo-auto-pin",
    "version": "0.5.2",
    "resolved": "https://registry.npmjs.org/paseo-auto-pin/-/paseo-auto-pin-0.5.2.tgz",
    "integrity": "sha512-h8A6deihde7RgTX+4K+8i5Fi8E9/urOSnuPaE9RPgh6iVtFn9uFDu1Qb5DDCBdfi3plNoUJHGtnaMcF2Lo/mJQ=="
  }
}

Inline validation passed: tests and artifact checks. Run node scripts/validate.ts --online --changed on the completed listing before merging. The default GITHUB_TOKEN does not trigger the PR validation workflow.

Artifact diff
diff -ruN a/package/CHANGELOG.md b/package/CHANGELOG.md
--- a/package/CHANGELOG.md	1985-10-26 08:15:00.000000000 +0000
+++ b/package/CHANGELOG.md	1985-10-26 08:15:00.000000000 +0000
@@ -1,6 +1,28 @@
 # Changelog
 
-## 0.5.1 — 2026-10-24
+## 0.5.2 — 2026-10-26
+
+- Paseo **0.13.0** fixes the sidebar race that could hide a newly applied pin
+  ([getpaseo/paseo#7758](https://github.com/getpaseo/paseo/pull/7758), for
+  [getpaseo/paseo#5447](https://github.com/getpaseo/paseo/issues/5447)).
+  Verified in the 0.13.0 web app with this plugin: local and worktree
+  workspaces, with and without an initial message, stay in **Pinned**, and a
+  manual unpin still works. Paseo 0.11.x and 0.12.x still have the race; update
+  Paseo to remove it.
+- Verify Paseo **0.11.1**, **0.12.0**, and **0.13.0** with the integration suite.
+- Lock `zod` 4.6.7 in the runtime tree for security advisory
+  [GHSA-mrhx-c7xc-m3w5](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5).
+- Add a Simplified Chinese registry listing: a `zh-CN` description in the
+  manifest's `translations` and `OVERVIEW.zh-CN.md`. Paseo ignores both.
+- Publish releases from GitHub Actions with npm **Trusted Publishing**
+  (OIDC, `.github/workflows/release.yml`), so no npm token is needed.
+- Let the race diagnostic run on any Paseo version instead of only 0.9.2. Add
+  `--ui` to keep its daemon and web app open for a check in the app, and
+  `--no-hold` to let creation responses return at once.
+- No behavior change. Pinning, settings, and the Paseo requirement
+  (`>=0.11.0`) are unchanged.
+
+## 0.5.1 — 2026-10-25
 
 - Ship `npm-shrinkwrap.json` inside the published package. npm installations
   now lock `@getpaseo/client` and its runtime tree (`@getpaseo/protocol`,
diff -ruN a/package/OVERVIEW.md b/package/OVERVIEW.md
--- a/package/OVERVIEW.md	1985-10-26 08:15:00.000000000 +0000
+++ b/package/OVERVIEW.md	1985-10-26 08:15:00.000000000 +0000
@@ -12,4 +12,4 @@
 
 The switch and project rules are stored in `plugin-data/auto-pin.json` in the Paseo home directory and are shared by every client connected to that daemon. To pin a workspace, the plugin opens a short connection to the daemon endpoint configured in Paseo's `config.json`. If that endpoint is not reachable from the daemon process, the pin fails and the error appears in the plugin log. The plugin makes no other network connections.
 
-On Paseo 0.9.2 and later, a new pin can briefly disappear from the sidebar when the workspace starts with an agent. The daemon keeps the pin, and the row returns on the next sidebar update.
+On Paseo 0.11 and 0.12, a new pin can briefly disappear from the sidebar when the workspace starts with an agent. The daemon keeps the pin, and the row returns on the next sidebar update. Paseo 0.13.0 fixes this.
diff -ruN a/package/OVERVIEW.zh-CN.md b/package/OVERVIEW.zh-CN.md
--- a/package/OVERVIEW.zh-CN.md	1970-01-01 00:00:00.000000000 +0000
+++ b/package/OVERVIEW.zh-CN.md	1985-10-26 08:15:00.000000000 +0000
@@ -0,0 +1,15 @@
+Auto-Pin 会在 Paseo 创建新工作区时立即将其置顶,使它显示在侧边栏的**已置顶**区域。它在 daemon 上运行,所以在没有打开任何 App、或 Auto-Pin 面板关闭时也能工作。
+
+**Pin new workspaces by default**(默认置顶新工作区)是全局开关。它默认开启,你可以在侧边栏顶部的 Auto-Pin 行切换它。每个项目都可以覆盖这个开关:
+
+- **Follow default**:使用开关的设置。
+- **Always**:置顶该项目的新工作区,即使开关已关闭。
+- **Never**:不置顶该项目的新工作区,即使开关已开启。
+
+规则适用于一个项目中的新工作区,包括 worktree。在 Auto-Pin 面板中设置规则;面板列出你的 Paseo 项目,并支持搜索。你也可以在 Command Center 中切换默认开关,或为当前工作区所属的项目设置规则,而不需要打开面板。
+
+Auto-Pin 只在创建工作区时起作用。已有的工作区不会改变,恢复已归档的工作区不会再次置顶,插件也从不取消置顶。你仍然可以自己置顶或取消置顶工作区。要完全暂停它,请停用插件。
+
+开关和项目规则保存在 Paseo home 目录下的 `plugin-data/auto-pin.json` 中,连接到同一个 daemon 的所有客户端共享这些设置。为了置顶工作区,插件会向 Paseo `config.json` 中配置的 daemon 地址建立一个短连接。如果 daemon 进程无法访问这个地址,置顶会失败,错误会显示在插件日志中。插件不会建立其他网络连接。
+
+在 Paseo 0.11 和 0.12 上,如果新工作区启动时带有 agent,新的置顶可能会短暂地从侧边栏消失。daemon 会保留置顶,该行会在下一次侧边栏更新时恢复。Paseo 0.13.0 已修复这个问题。
diff -ruN a/package/README.md b/package/README.md
--- a/package/README.md	1985-10-26 08:15:00.000000000 +0000
+++ b/package/README.md	1985-10-26 08:15:00.000000000 +0000
@@ -29,13 +29,13 @@
 You can also install directly from npm or GitHub:
 
 ```bash
-paseo plugin install npm:[email protected]
+paseo plugin install npm:[email protected]
 paseo plugin install https://github.com/stv1024/paseo-auto-pin

The registry can lag behind npm for a few days while each new version is reviewed.
-Paseo 0.9.2 and later have a known sidebar synchronization issue
-that can temporarily hide a newly applied pin.
+Paseo 0.11.x and 0.12.x have a known sidebar synchronization issue
+that can temporarily hide a newly applied pin. Paseo 0.13.0 fixes it.

The Auto-Pin row in the sidebar header shows the default switch. Click the
switch to turn auto-pin on or off. Click the row to open the panel with project
@@ -84,7 +84,7 @@
Updating from 0.3 keeps your existing on/off setting. Every project starts on
Follow default until you choose otherwise.

-Auto-Pin 0.5.1 has been integration-tested with Paseo 0.11.1.
+Auto-Pin 0.5.2 has been integration-tested with Paseo 0.11.1, 0.12.0, and 0.13.0.
Future versions are allowed, but compatibility still depends on Paseo keeping
the APIs this plugin uses. Paseo 0.10 and earlier reject the 0.5 manifest.
For Paseo 0.9.1 to 0.10.x, use Auto-Pin 0.4.2:
@@ -102,11 +102,13 @@
If you just changed a setting on another device, press Refresh in the panel.

If a workspace appears pinned, disappears from Pinned, and returns later on
-Paseo 0.9.2 or later, see the known issue and upstream status.
+Paseo 0.9.2 to 0.12.x, update Paseo to 0.13.0 or later. See the
+known issue and its fix.
The daemon retains the pin; updating or reloading Auto-Pin does not fix this
host issue. The panel's Refresh button only refreshes plugin settings and
projects, so it does not repair the sidebar state.
-Upstream tracking: getpaseo/paseo#5447.
+Upstream fix: getpaseo/paseo#7758,
+for getpaseo/paseo#5447.

For errors or unexpected behavior, open an issue.
Include your Paseo and Auto-Pin versions, the rule you selected, and what happened.
diff -ruN a/package/docs/community.md b/package/docs/community.md
--- a/package/docs/community.md 1985-10-26 08:15:00.000000000 +0000
+++ b/package/docs/community.md 1985-10-26 08:15:00.000000000 +0000
@@ -22,6 +22,9 @@

  • on 2026-10-25: a packaging release that ships npm-shrinkwrap.json and clears
  • the registry hold on 0.5.0 (getpaseo/plugins#237).

Where to check feedback

diff -ruN a/package/docs/development.md b/package/docs/development.md
--- a/package/docs/development.md 1985-10-26 08:15:00.000000000 +0000
+++ b/package/docs/development.md 1985-10-26 08:15:00.000000000 +0000
@@ -1,11 +1,11 @@

Developing Auto-Pin

-Auto-Pin 0.5.1 requires Paseo >=0.11.0, with no upper version limit. The
+Auto-Pin 0.5.2 requires Paseo >=0.11.0, with no upper version limit. The
manifest uses name, icon, and media, and the client uses addScreen and
addSidebarHeaderItem; Paseo 0.10 and earlier reject or lack these. The
-integration suite has been verified with Paseo 0.11.1. Later
-stable versions may load without changing the manifest, but this is not a
-guarantee that future Paseo API changes will remain compatible.
+integration suite has been verified with Paseo 0.11.1, 0.12.0, and
+0.13.0. Later stable versions may load without changing the manifest, but
+this is not a guarantee that future Paseo API changes will remain compatible.

Both Paseo SDK dependencies are pinned to 0.11.1 for repeatable builds; these
dependency pins do not restrict the host's version. The host supplies React and
@@ -39,7 +39,24 @@

Publishing on npm

-Run the checks, then prepare a tarball:
+Releases are published by
+.github/workflows/release.yml with npm
+Trusted Publishing over GitHub OIDC. No npm token is stored in the
+repository, in GitHub, or on a machine. npm accepts a publish only when the
+repository, the workflow filename, and the tag match the package's trusted
+publisher record on npmjs.com.
+
+Release sequence:
+
+1. Bump version in package.json and add the changelog section.
+2. Run the checks and pack the tarball (below).
+3. Commit, push main, tag the release commit, and push the tag:

  • git tag -a v0.5.2 -m "Auto-Pin 0.5.2" && git push origin v0.5.2.
  • The tag push starts the workflow. A tag that does not match the packed
  • version fails the run before it reaches npm.
    +4. Create the GitHub release from that tag.

+### Checks before a release

npm run typecheck
@@ -58,12 +75,19 @@
`npm install --prefix /path/to/package-test --ignore-scripts --omit=dev --legacy-peer-deps /path/to/paseo-auto-pin-VERSION.tgz`.
Verify that installed artifact using
`npm run test:integration -- --runtime /path/to/paseo-test-runtime --plugin-directory /path/to/package-test/node_modules/paseo-auto-pin`.
-
-Publish that same verified tarball with
-`npm publish /path/to/paseo-auto-pin-VERSION.tgz --access public --registry=https://registry.npmjs.org/`,
-then run the integration check with `--source npm:paseo-auto-pin@VERSION` to verify
-managed npm acquisition. Keep the GitHub and npm package versions in sync, and
-increment the version before each subsequent publication.
+Then run the integration check with `--source npm:paseo-auto-pin@VERSION` after
+publication to verify managed npm acquisition. The integration suite is not part
+of the workflow: it needs a Paseo runtime and a local daemon, so it runs on a
+machine.
+
+### Manual publication
+
+For an emergency, publish the packed tarball by hand with
+`npm publish /path/to/paseo-auto-pin-VERSION.tgz --access public --registry=https://registry.npmjs.org/`
+after `npm login`. This account has no authenticator app, so npm asks for browser
+approval and the request expires after five minutes. The workflow publishes the
+same artifact the pack command produces, so a manual release and a CI release are
+interchangeable.

## How it works

@@ -120,12 +144,13 @@

### Paseo integration limits

-Paseo 0.9.2 can display an old creation snapshot after the live pin update.
-See [the known issue, upstream status, and maintenance policy](paseo-workspace-race.md).
+Paseo 0.9.2 through 0.12.x can display an old creation snapshot after the live
+pin update; Paseo 0.13.0 fixes this in the app. See
+[the known issue, its fix, and the maintenance policy](paseo-workspace-race.md).
Host state synchronization fixes belong upstream. Keep the plugin's creation
hook independent of response timing and preserve manual unpinning.

-Paseo 0.11.1's public `PaseoApi` still has no pin mutation, and the
+Paseo 0.13.0's public `PaseoApi` still has no pin mutation, and the
`workspace.create` request has no pin field for a `before` hook to set. The pin adapter uses
`DaemonClient` from `@getpaseo/client/internal/daemon-client` over a short-lived
connection to the local daemon. This is the only internal SDK integration.
@@ -136,7 +161,7 @@
Cancellation cannot undo a request the daemon already accepted.

Paseo's native server settings handle has `read()` and `subscribe()`, but no
-write method in 0.11.1, so Auto-Pin retains its own settings file and RPCs.
+write method in 0.13.0, so Auto-Pin retains its own settings file and RPCs.

| RPC | Purpose |
| --- | --- |
@@ -154,7 +179,7 @@
this repository:

```bash
-npm install --prefix /path/to/paseo-test-runtime --no-save --ignore-scripts @getpaseo/[email protected]
+npm install --prefix /path/to/paseo-test-runtime --no-save --ignore-scripts @getpaseo/[email protected]
npm run test:integration -- --runtime /path/to/paseo-test-runtime

@@ -209,5 +234,11 @@
package root beside paseo-plugin.json, must not contain installation commands,
and should be updated whenever plugin behavior changes.

+The manifest's translations and OVERVIEW.zh-CN.md give the listing in
+Simplified Chinese. Only the registry reads them; Paseo ignores both. When
+OVERVIEW.md or the manifest description changes, update the translation in
+the same change. OVERVIEW.zh-CN.md is a complete page, not a partial override,
+and has the same rules as OVERVIEW.md.
+
When changing the supported Paseo version, recheck the internal pin adapter,
manifest validation, client/server compilation, and the daemon integration.
diff -ruN a/package/docs/paseo-workspace-race.md b/package/docs/paseo-workspace-race.md
--- a/package/docs/paseo-workspace-race.md 1985-10-26 08:15:00.000000000 +0000
+++ b/package/docs/paseo-workspace-race.md 1985-10-26 08:15:00.000000000 +0000
@@ -1,153 +1,234 @@
-# Known issue: new pins temporarily disappear on Paseo 0.9.2

-Auto-Pin can expose a client state race in Paseo 0.9.2: a workspace appears pinned,
-disappears from Pinned, and returns after a later directory update.
-The daemon's saved pin is not removed.

-## Status and user impact

-Upstream report: getpaseo/paseo#5447,
-filed September 26, 2026 with the reproduction script, raw output, and candidate
-patch. Filing the report does not imply that the fix has been accepted or released.

-Confirmed with Auto-Pin 0.4.0 and Paseo 0.9.2 on Windows 11. Paseo 0.9.2
-was still the latest stable release when checked on September 26, 2026.
-No fixed official release has been verified. Other versions have not been
-checked for this specific race; the plugin's supported range is not a claim
-that every host version is free of this issue.

-Update, October 9, 2026: the issue is still open (labeled p3). On September 26
-the Paseo maintainers' bot reproduced it on main without added delays when the
-workspace starts with an initial agent, confirmed the cause, and left the choice
-of fix to the maintainer. Paseo 0.11.1 is the latest stable release and contains
-no fix. Its plugin SDK still has no way to set a pin as part of the creation request.

-The interval before the pin reappears depends on the next directory update or
-resynchronization. Auto-Pin has no timer that removes or reapplies pins. Its
-panel's Refresh button refreshes plugin settings and projects, not the host
-sidebar. Updating or reloading the plugin does not fix this host issue.

-Normal installation continues to use an official Paseo release. The candidate
-patch below is investigation material for maintainers, not an installation
-requirement or a supported custom Paseo distribution.

-## Cause

-Paseo captures a workspace descriptor during creation. While it finishes the
-creation request, Auto-Pin handles workspace.created and pins the workspace.
-The client receives that live update before the older creation response.
-Both the response and creation progress callbacks feed their snapshots through
-HostRuntimeController.acceptWorkspaceSnapshots(). The 0.9.2 workspace replica
-overwrites its current row with each of these snapshots, including the old
-pinnedAt: null value.

-Relevant source at v0.9.2:

-- Creation response merge
-- Workspace replica snapshot acceptance

-The same unconditional acceptance method was present in main at
-76a9781ba566ab511ed8ec9b08ebf53425229f39. That was a source inspection; the
-runtime reproduction and regression checks below target v0.9.2.

-## Reproduction for maintainers

-The reported desktop sequence is: enable Auto-Pin, create a workspace with an
-initial message, then observe it appear in Pinned, disappear, and return after
-a later workspace update. It is timing-dependent in normal use.

-For a deterministic wire-level reproduction, install a separate runtime and run
-the diagnostic from a checkout of this plugin with its dependencies installed:

-bash -npm install --prefix /path/to/paseo-test-runtime --no-save --ignore-scripts @getpaseo/[email protected] -node scripts/repro-workspace-race.mjs --runtime /path/to/paseo-test-runtime -

-The script creates a temporary Paseo home and workspace, binds an automatically
-assigned loopback port, and disables agent providers, relay, MCP, and speech.
-It loads the real plugin, subscribes to workspace updates, and creates a
-workspace. In this test process only, it holds the return of
-Session.createRequestedWorkspace() until the real pin update arrives. It does
-not change the descriptor or stored pin. The original method is restored and
-the test daemon is stopped in finally; test files and logs remain in the
-printed temporary directory. The ordinary Paseo home and daemon are not used.

-Expected evidence is a non-null livePinnedAtBeforeResponse, a null
-responsePinnedAt, and a matching non-null refreshedPinnedAt.
-This script proves response ordering and retained server state. It does not
-launch the UI or by itself test the client merge; the regression below exercises
-Paseo's actual workspace replica and session store.

-## Candidate upstream fix

-The source patch targets Paseo
-tag v0.9.2, commit c67b7158b441bb09026b38d86ae335cc4b49190a.
-It is retained in this repository for upstream review and is not applied by
-plugin installation, update, or reload. Paseo source is licensed under Apache-2.0.

-Creation snapshots seed missing workspace rows. Once a row exists, directory
-updates and reconciliation own its state. The replica applies that rule before
-publishing to the session store or returning mutations for the persistent cache.
-It applies to the entire descriptor, so pins, titles, and other live fields do
-not need separate exceptions. Live updates can still pin or unpin a workspace.

-The public snapshot entry point is also used to restore an optimistically hidden
-workspace after an archive failure. A missing row can still be restored; an
-already received row keeps its current state.

-For source-level evaluation only, apply it in a separate Paseo source checkout:

-bash -git checkout v0.9.2 -git apply --check /path/to/paseo-auto-pin/patches/paseo-0.9.2-workspace-snapshots.patch -git apply /path/to/paseo-auto-pin/patches/paseo-0.9.2-workspace-snapshots.patch -

-The proposal needs upstream review before it should be treated as a released
-fix. Its validation is scoped to the existing-row overwrite: removal/tombstone
-races and reconnect behavior have not been verified with this candidate.

-## Verification

-The new late-creation-response regression failed on the original Paseo code and
-passed after the change. All nine tests in workspace-replica.test.ts pass,
-covering both arrival orders, mixed batches, manual unpinning, and archive
-rollback. The app typecheck and lint for both changed files pass after building
-the workspace dependencies and applying Paseo's normal postinstall patches.
-The source patch passes forward and reverse applicability checks against the
-v0.9.2 checkout. Auto-Pin's 36 tests and typecheck also pass.

-To run the focused host tests from a prepared Paseo checkout:

-bash -npm run test --workspace=@getpaseo/app -- src/runtime/directory-sync/workspace-replica.test.ts --bail=1 -npm run typecheck --workspace=@getpaseo/app -npm run lint -- packages/app/src/runtime/directory-sync/workspace-replica.ts packages/app/src/runtime/directory-sync/workspace-replica.test.ts -

-This verifies the source change. A packaged client build and UI smoke test have
-not been performed, and the installed Paseo client has not been patched.

-## Maintenance policy

-Auto-Pin keeps its existing flow: one creation hook, one project-rule decision,
-one pin request. Keep host synchronization fixes in Paseo. Do not add arbitrary
-pin delays, periodic repinning, host monkey patches, or client-store writes to
-the shipped plugin to mask this race; these cannot guarantee response ordering
-and can interfere with manual pin changes. The diagnostic's timing injection
-is isolated test code and is not loaded by either plugin entry point.

-After an official fix is released, verify the released client with the stock
-plugin: initial-message and empty-workspace creation, local checkouts and
-worktrees, both update/response orders, and manual unpinning. Record the first
-verified fixed version and the upstream issue or release link here, then revise
-the README's known-issue notice. Keep the historical reproduction versioned;
-it demonstrates the old wire ordering, which may remain valid even after the
-client merge is fixed. Do not mark the plugin fixed merely because this source
-patch or a proposed upstream change exists.

-The existing integration compromises are documented in
-Paseo integration limits: a small
-internal-client pin adapter and plugin-owned settings persistence, because the
-Paseo 0.9.1 API does not expose those writes. They are independent of this race.
+# Known issue: new pins temporarily disappear on Paseo 0.9.2 to 0.12.x
+
+Auto-Pin can expose a client state race in Paseo 0.9.2 to 0.12.x: a workspace appears pinned,
+disappears from Pinned, and returns after a later directory update.
+The daemon's saved pin is not removed.
+
+Fixed in Paseo 0.13.0. To fix it, update Paseo to 0.13.0 or later. Auto-Pin
+needs no update for this fix. On Paseo 0.11.x and 0.12.x the race remains.
+
+## Status and user impact
+
+Upstream report: getpaseo/paseo#5447,
+filed September 26, 2026 with the reproduction script, raw output, and candidate
+patch. Filing the report does not imply that the fix has been accepted or released.
+
+Confirmed with Auto-Pin 0.4.0 and Paseo 0.9.2 on Windows 11. Paseo 0.9.2
+was still the latest stable release when checked on September 26, 2026.
+No fixed official release has been verified. Other versions have not been
+checked for this specific race; the plugin's supported range is not a claim
+that every host version is free of this issue.
+
+Update, October 9, 2026: the issue is still open (labeled p3). On September 26
+the Paseo maintainers' bot reproduced it on main without added delays when the
+workspace starts with an initial agent, confirmed the cause, and left the choice
+of fix to the maintainer. Paseo 0.11.1 is the latest stable release and contains
+no fix. Its plugin SDK still has no way to set a pin as part of the creation request.
+
+Update, October 24, 2026: the race still reproduces on the released Paseo
+0.12.0 daemon with the diagnostic below. acceptWorkspaces() is unchanged in
+v0.12.0, main, and v0.13.0-beta.2. The issue is open (p2). The 0.12.0 plugin
+SDK changed only ACP code: PaseoApi still has no pin mutation, and
+workspace.create still has no pin field. The stock plugin passes the
+integration suite on 0.12.0.
+
+Upstream fix proposal: getpaseo/paseo#7758,
+opened October 24, 2026 against main. It applies the guard described below and
+adds four replica unit tests and a browser E2E test. The E2E test creates a
+workspace with a prompt, pins it while the creation response is held, and counts
+frames in which the row is missing from Pinned. On unchanged main it failed in
+3 of 3 runs (32 to 34 missing frames); with the change it passed in 4 of 4 runs.
+An open pull request is not a released fix.
+
+Update, October 26, 2026: fixed in Paseo 0.13.0. Paseo merged #7758 on
+October 24, 2026, which closed #5447, and released it the same day in
+Paseo 0.13.0
+(merge commit 632a7f885958f318ee9e0619b3af075d4798bf55; 0.13.0-beta.2 and
+earlier do not contain it). In 0.13.0, acceptWorkspaces() only seeds rows that
+are missing. The daemon still sends the old creation response after the live pin
+update, but the app no longer applies it. Paseo 0.13.0 is the first verified
+fixed version: the stock plugin passed the
+released-client check below.
+
+The interval before the pin reappears depends on the next directory update or
+resynchronization. Auto-Pin has no timer that removes or reapplies pins. Its
+panel's Refresh button refreshes plugin settings and projects, not the host
+sidebar. Updating or reloading the plugin does not fix this host issue.
+
+Normal installation continues to use an official Paseo release. The candidate
+patch below is investigation material for maintainers, not an installation
+requirement or a supported custom Paseo distribution.
+
+## Cause
+
+Paseo captures a workspace descriptor during creation. While it finishes the
+creation request, Auto-Pin handles workspace.created and pins the workspace.
+The client receives that live update before the older creation response.
+Both the response and creation progress callbacks feed their snapshots through
+HostRuntimeController.acceptWorkspaceSnapshots(). The 0.9.2 workspace replica
+overwrites its current row with each of these snapshots, including the old
+pinnedAt: null value.
+
+Relevant source at v0.9.2:
+
+- Creation response merge
+- Workspace replica snapshot acceptance
+
+The same unconditional acceptance method was present in main at
+76a9781ba566ab511ed8ec9b08ebf53425229f39. That was a source inspection; the
+runtime reproduction and regression checks below target v0.9.2.
+
+## Reproduction for maintainers
+
+The reported desktop sequence is: enable Auto-Pin, create a workspace with an
+initial message, then observe it appear in Pinned, disappear, and return after
+a later workspace update. It is timing-dependent in normal use.
+
+For a deterministic wire-level reproduction, install a separate runtime and run
+the diagnostic from a checkout of this plugin with its dependencies installed:
+
+bash +npm install --prefix /path/to/paseo-test-runtime --no-save --ignore-scripts @getpaseo/[email protected] +node scripts/repro-workspace-race.mjs --runtime /path/to/paseo-test-runtime +
+
+The script accepts any installed Paseo version and prints it; replace 0.9.2
+to check another release. The wire ordering was last confirmed on 0.13.0, where
+the app no longer applies the old response.
+
+The script creates a temporary Paseo home and workspace, binds an automatically
+assigned loopback port, and disables agent providers, relay, MCP, and speech.
+It loads the real plugin, subscribes to workspace updates, and creates a
+workspace. In this test process only, it holds the return of
+Session.createRequestedWorkspace() until the real pin update arrives. It does
+not change the descriptor or stored pin. The original method is restored and
+the test daemon is stopped in finally; test files and logs remain in the
+printed temporary directory. The ordinary Paseo home and daemon are not used.
+
+Expected evidence is a non-null livePinnedAtBeforeResponse, a null
+responsePinnedAt, and a matching non-null refreshedPinnedAt.
+This script proves response ordering and retained server state. It does not
+launch the UI or by itself test the client merge; the regression below exercises
+Paseo's actual workspace replica and session store.
+
+Add --ui to test the client merge in the app. The script then keeps the test
+daemon and its bundled web app running, creates a Git project, and prints the
+app URL. It also enables Paseo's development-only mock agent provider, so the
+app can start a workspace with an initial message without a real provider.
+Every workspace that the app creates returns only after its pin update arrives
+(10-second limit). Add --no-hold as well to let creation responses return
+without delay. The script prints each pin, unpin, and held response. Press
+Enter to stop it.
+
+## Candidate upstream fix
+
+The source patch targets Paseo
+tag v0.9.2, commit c67b7158b441bb09026b38d86ae335cc4b49190a.
+It is retained in this repository for upstream review and is not applied by
+plugin installation, update, or reload. Paseo source is licensed under Apache-2.0.
+
+Creation snapshots seed missing workspace rows. Once a row exists, directory
+updates and reconciliation own its state. The replica applies that rule before
+publishing to the session store or returning mutations for the persistent cache.
+It applies to the entire descriptor, so pins, titles, and other live fields do
+not need separate exceptions. Live updates can still pin or unpin a workspace.
+
+The public snapshot entry point is also used to restore an optimistically hidden
+workspace after an archive failure. A missing row can still be restored; an
+already received row keeps its current state.
+
+For source-level evaluation only, apply it in a separate Paseo source checkout:
+
+bash +git checkout v0.9.2 +git apply --check /path/to/paseo-auto-pin/patches/paseo-0.9.2-workspace-snapshots.patch +git apply /path/to/paseo-auto-pin/patches/paseo-0.9.2-workspace-snapshots.patch +
+
+The proposal needs upstream review before it should be treated as a released
+fix. Its validation is scoped to the existing-row overwrite: removal/tombstone
+races and reconnect behavior have not been verified with this candidate.
+
+## Verification
+
+### Released fix (Paseo 0.13.0)
+
+Checked on October 26, 2026 on Windows 11 with the released Paseo 0.13.0
+daemon and web app and the stock plugin (the code in Auto-Pin 0.5.1 and 0.5.2). The diagnostic
+ran with --ui. A headless Chrome, driven by Playwright from outside this
+repository, used the app's New workspace screen to create workspaces:
+
+- with an initial message (mock agent) and empty;
+- as a local checkout and as a new worktree.
+
+For each workspace, the browser sampled every animation frame from Create
+until 3 seconds after the workspace opened. It counted the frames in which the
+new row was missing from Pinned after it first appeared there, as Paseo's own
+E2E test does. It also recorded the workspace messages that the app received.
+
+| Arrival order | Scenario | Paseo 0.13.0 | Paseo 0.12.0 (control) |
+| --- | --- | --- | --- |
+| Held: pin, then old response | Initial message, local | 0 frames (2 runs) | 171 frames; still missing at the end |
+| Held: pin, then old response | Initial message, worktree | 0 frames (2 runs) | not run |
+| Held: pin, then old response | Empty, local | 0 frames (3 runs) | 183 frames; still missing at the end |
+| Held: pin, then old response | Empty, worktree | 0 frames (2 runs) | 34 frames; back after a later update |
+| Not held: pin first | Initial message, local and worktree | 0 frames | not run |
+| Not held: response first | Empty, local | 0 frames | not run |
+| Not held: pin first | Empty, worktree | 0 frames | not run |
+
+In every held run, the app received the creation response with
+pinnedAt: null after the pinned update, so each run reproduced the race on
+the wire. With an initial message, the pin also arrived first without the
+hold, because the response waits for the agent to start. Every 0.13.0 row was
+still in Pinned at the end.
+
+Manual unpinning from the row menu also passed in both held runs. The row left
+Pinned in the next frame and stayed listed and unpinned, and the daemon
+recorded no new pin in the next 4 seconds.
+
+This check did not cover real agent providers, the desktop and mobile apps,
+reconnects, or archive and restore. The upstream E2E test and review covered
+the replica change with an agent.
+
+### Candidate patch (Paseo 0.9.2)
+
+The new late-creation-response regression failed on the original Paseo code and
+passed after the change. All nine tests in workspace-replica.test.ts pass,
+covering both arrival orders, mixed batches, manual unpinning, and archive
+rollback. The app typecheck and lint for both changed files pass after building
+the workspace dependencies and applying Paseo's normal postinstall patches.
+The source patch passes forward and reverse applicability checks against the
+v0.9.2 checkout. Auto-Pin's 36 tests and typecheck also pass.
+
+To run the focused host tests from a prepared Paseo checkout:
+
+bash +npm run test --workspace=@getpaseo/app -- src/runtime/directory-sync/workspace-replica.test.ts --bail=1 +npm run typecheck --workspace=@getpaseo/app +npm run lint -- packages/app/src/runtime/directory-sync/workspace-replica.ts packages/app/src/runtime/directory-sync/workspace-replica.test.ts +
+
+This verifies the source change. A packaged client build and UI smoke test have
+not been performed, and the installed Paseo client has not been patched.
+
+## Maintenance policy
+
+Auto-Pin keeps its existing flow: one creation hook, one project-rule decision,
+one pin request. Keep host synchronization fixes in Paseo. Do not add arbitrary
+pin delays, periodic repinning, host monkey patches, or client-store writes to
+the shipped plugin to mask this race; these cannot guarantee response ordering
+and can interfere with manual pin changes. The diagnostic's timing injection
+is isolated test code and is not loaded by either plugin entry point.
+
+Paseo 0.13.0 is the first verified fixed version (see
+Released fix). The plugin still supports Paseo
+0.11.x and 0.12.x, where the race remains; tell users there to update Paseo.
+Keep the historical reproduction versioned: it shows the old wire ordering,
+which is still sent in 0.13.0. If a later Paseo release changes the creation
+flow or the workspace replica, run the --ui check again.
+
+The existing integration compromises are documented in
+Paseo integration limits: a small
+internal-client pin adapter and plugin-owned settings persistence, because the
+Paseo plugin API (still in 0.13.0) does not expose those writes. They are
+independent of this race.
diff -ruN a/package/index.server.ts b/package/index.server.ts
--- a/package/index.server.ts 1985-10-26 08:15:00.000000000 +0000
+++ b/package/index.server.ts 1985-10-26 08:15:00.000000000 +0000
@@ -1,12 +1,12 @@
-import type { PluginServerContext } from "@getpaseo/plugin/server";
+import type { PluginServerContext } from "@getpaseo/plugin/server";
import { autopinEnsure, autopinProjects, autopinSetProjectRule, autopinToggle } from "./shared/contracts";
import { handleEnsure, handleProjects, handleSetProjectRule, handleToggle } from "./server/handlers";
-import { registerAutoPin } from "./server/lifecycle";

-export default function contribute(server: PluginServerContext) {

  • server.handle(autopinEnsure, handleEnsure);
    +import { registerAutoPin } from "./server/lifecycle";

+export default function contribute(server: PluginServerContext) {

  • server.handle(autopinEnsure, handleEnsure);
    server.handle(autopinToggle, handleToggle);
    server.handle(autopinProjects, handleProjects);
    server.handle(autopinSetProjectRule, handleSetProjectRule);
  • return registerAutoPin(server);
    -}
  • return registerAutoPin(server);
    +}
    diff -ruN a/package/npm-shrinkwrap.json b/package/npm-shrinkwrap.json
    --- a/package/npm-shrinkwrap.json 1985-10-26 08:15:00.000000000 +0000
    +++ b/package/npm-shrinkwrap.json 1985-10-26 08:15:00.000000000 +0000
    @@ -1,12 +1,12 @@
    {
    "name": "paseo-auto-pin",
  • "version": "0.5.1",
  • "version": "0.5.2",
    "lockfileVersion": 3,
    "requires": true,
    "packages": {
    "": {
    "name": "paseo-auto-pin",
  •  "version": "0.5.1",
    
  •  "version": "0.5.2",
     "license": "MIT",
     "dependencies": {
       "@getpaseo/client": "0.11.1"
    

@@ -5193,9 +5193,9 @@
}
},
"node_modules/zod": {

  •  "version": "4.5.4",
    
  •  "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz",
    
  •  "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==",
    
  •  "version": "4.6.7",
    
  •  "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz",
    
  •  "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==",
     "license": "MIT",
     "funding": {
       "url": "https://github.com/sponsors/colinhacks"
    

diff -ruN a/package/package.json b/package/package.json
--- a/package/package.json 1985-10-26 08:15:00.000000000 +0000
+++ b/package/package.json 1985-10-26 08:15:00.000000000 +0000
@@ -1,6 +1,6 @@
{
"name": "paseo-auto-pin",

  • "version": "0.5.1",
  • "version": "0.5.2",
    "description": "Automatically pin new Paseo workspaces, with defaults and rules for individual projects.",
    "license": "MIT",
    "author": "stv1024",
    @@ -18,6 +18,7 @@
    "paseo-plugin.json",
    "npm-shrinkwrap.json",
    "OVERVIEW.md",
  • "OVERVIEW.zh-CN.md",
    "assets/",
    "index.client.tsx",
    "index.server.ts",
    diff -ruN a/package/paseo-plugin.json b/package/paseo-plugin.json
    --- a/package/paseo-plugin.json 1985-10-26 08:15:00.000000000 +0000
    +++ b/package/paseo-plugin.json 1985-10-26 08:15:00.000000000 +0000
    @@ -9,6 +9,11 @@
    "docs/demo.gif",
    "https://github.com/stv1024/paseo-auto-pin/releases/download/v0.4.0/auto-pin-promo.mp4"
    ],
  • "translations": {
  • "zh-CN": {
  •  "description": "自动置顶新工作区。可以跟随默认设置,也可以为每个项目选择 Always / Never。"
    
  • }
  • },
    "requirements": {
    "paseo": ">=0.11.0"
    }
    diff -ruN a/package/server/handlers.ts b/package/server/handlers.ts
    --- a/package/server/handlers.ts 1985-10-26 08:15:00.000000000 +0000
    +++ b/package/server/handlers.ts 1985-10-26 08:15:00.000000000 +0000
    @@ -1,13 +1,13 @@
    import type { PluginHandlerContext } from "@getpaseo/plugin/server";
    import type { ProjectRule } from "../shared/contracts";
    import { getConfig, setProjectRule, toggleEnabled } from "./store";
    -import { isRunning } from "./lifecycle";

-export async function handleEnsure() {
+import { isRunning } from "./lifecycle";
+
+export async function handleEnsure() {
return { running: isRunning(), ...await getConfig() };
-}

-export async function handleToggle() {
+}
+
+export async function handleToggle() {
const config = await toggleEnabled();
console.log([auto-pin] default ${config.enabled ? "on" : "off"});
return { running: isRunning(), ...config };
diff -ruN a/package/server/lifecycle.ts b/package/server/lifecycle.ts
--- a/package/server/lifecycle.ts 1985-10-26 08:15:00.000000000 +0000
+++ b/package/server/lifecycle.ts 1985-10-26 08:15:00.000000000 +0000
@@ -1,25 +1,25 @@
-import type { PluginServerContext } from "@getpaseo/plugin/server";
+import type { PluginServerContext } from "@getpaseo/plugin/server";
import { shouldPinProject } from "./store";
-import { pinWorkspace } from "./pin";

-let running = false;
-export function isRunning(): boolean { return running; }

-export function registerAutoPin(server: PluginServerContext) {

  • const unsubscribe = server.on("workspace.created", async ({ workspace }, { signal }) => {
    +import { pinWorkspace } from "./pin";

+let running = false;
+export function isRunning(): boolean { return running; }
+
+export function registerAutoPin(server: PluginServerContext) {

  • const unsubscribe = server.on("workspace.created", async ({ workspace }, { signal }) => {
    if (signal.aborted || workspace.archivedAt || !(await shouldPinProject(workspace.projectId))) return;
  • if (signal.aborted) return;
  • try {
  • if (signal.aborted) return;
  • try {
    await pinWorkspace(workspace.id, signal);
    if (signal.aborted) return;
  •  console.log(`[auto-pin] pinned new workspace ${workspace.id}`);
    
  •  console.log(`[auto-pin] pinned new workspace ${workspace.id}`);
    
    } catch (error) {
    if (signal.aborted) return;
  •  console.error(`[auto-pin] failed to pin ${workspace.id}:`, error);
    
  •  throw error;
    
  • }
  • });
  • running = true;
  • console.log("[auto-pin] workspace.created hook registered");
  • return () => { running = false; unsubscribe(); };
    -}
  •  console.error(`[auto-pin] failed to pin ${workspace.id}:`, error);
    
  •  throw error;
    
  • }
  • });
  • running = true;
  • console.log("[auto-pin] workspace.created hook registered");
  • return () => { running = false; unsubscribe(); };
    +}
    diff -ruN a/package/server/pin.ts b/package/server/pin.ts
    --- a/package/server/pin.ts 1985-10-26 08:15:00.000000000 +0000
    +++ b/package/server/pin.ts 1985-10-26 08:15:00.000000000 +0000
    @@ -1,19 +1,19 @@
    -import { readFile } from "node:fs/promises";
    -import { join } from "node:path";
    -import { DaemonClient } from "@getpaseo/client/internal/daemon-client";
    -import { PASEO_HOME } from "./store";

-const CONFIG_FILE = join(PASEO_HOME, "config.json");

-/** The injected PaseoApi exposes no pin mutation, so pinning goes through a

    • short-lived DaemonClient of our own against the local daemon's /ws endpoint. */
      +import { readFile } from "node:fs/promises";
      +import { join } from "node:path";
      +import { DaemonClient } from "@getpaseo/client/internal/daemon-client";
      +import { PASEO_HOME } from "./store";

+const CONFIG_FILE = join(PASEO_HOME, "config.json");
+
+/** The injected PaseoApi exposes no pin mutation, so pinning goes through a

    • short-lived DaemonClient of our own against the local daemon's /ws endpoint. */
      export async function pinWorkspace(workspaceId: string, signal: AbortSignal): Promise {
      signal.throwIfAborted();
      const url = await daemonWsUrl();
      signal.throwIfAborted();
      const client = new DaemonClient({
      url,
  • clientId: plugin-auto-pin-${process.pid},
  • clientId: plugin-auto-pin-${process.pid},
    clientType: "cli",
    connectTimeoutMs: 5_000,
    reconnect: { enabled: false },
    @@ -37,18 +37,18 @@
    } finally {
    signal.removeEventListener("abort", onAbort);
    await client.close();
  • }
    -}

-async function daemonWsUrl(): Promise {

  • let listen = "127.0.0.1:6767";
  • try {
  • const config = JSON.parse(await readFile(CONFIG_FILE, "utf8"));
  • if (typeof config?.daemon?.listen === "string") listen = config.daemon.listen;
  • } catch {
  • // fall through to the default
  • }
  • // A wildcard bind address is not dialable; loopback reaches the same daemon.
  • listen = listen.replace(/^0.0.0.0(?=:)/, "127.0.0.1");
  • return ws://${listen}/ws;
    -}
  • }
    +}

+async function daemonWsUrl(): Promise {

  • let listen = "127.0.0.1:6767";
  • try {
  • const config = JSON.parse(await readFile(CONFIG_FILE, "utf8"));
  • if (typeof config?.daemon?.listen === "string") listen = config.daemon.listen;
  • } catch {
  • // fall through to the default
  • }
  • // A wildcard bind address is not dialable; loopback reaches the same daemon.
  • listen = listen.replace(/^0.0.0.0(?=:)/, "127.0.0.1");
  • return ws://${listen}/ws;
    +}
    diff -ruN a/package/shared/contracts.ts b/package/shared/contracts.ts
    --- a/package/shared/contracts.ts 1985-10-26 08:15:00.000000000 +0000
    +++ b/package/shared/contracts.ts 1985-10-26 08:15:00.000000000 +0000
    @@ -1,6 +1,6 @@
    -import { defineRpc } from "@getpaseo/plugin";
    -import { z } from "zod";

+import { defineRpc } from "@getpaseo/plugin";
+import { z } from "zod";
+
export const projectRuleSchema = z.enum(["default", "always", "never"]);
export type ProjectRule = z.infer;
export type ProjectRules = Record<string, Exclude<ProjectRule, "default">>;
@@ -18,15 +18,15 @@

/** The legacy name is retained for existing clients. This only reads status. */
export const autopinEnsure = defineRpc({

  • name: "autopin.ensure",
  • input: z.object({}),
  • name: "autopin.ensure",
  • input: z.object({}),
    output: stateSchema,
    -});

+});
+
/** Flips the default. Explicit project rules still take precedence. */
-export const autopinToggle = defineRpc({

  • name: "autopin.toggle",
  • input: z.object({}),
    +export const autopinToggle = defineRpc({
  • name: "autopin.toggle",
  • input: z.object({}),
    output: stateSchema,
    });

</details>

@github-actions github-actions Bot added the bump Pinned artifact update label Oct 26, 2026

@paseo-bot paseo-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-Pin 0.5.2 is approved for publication, @stv1024. I refreshed the listing’s screenshot URLs to this version and retained your English and Chinese overviews. Nothing further is needed from you.

Review data
  • Reviewed registry head: 06f0ccc8d2ad375a5ba299271672a22709d0b07d. Main REVIEW.md blob: 8da1286fd8870c87ff53767e8644858627b7371f.
  • Independently downloaded and compared npm paseo-auto-pin 0.5.1 and 0.5.2; both tarballs match their records and npm SHA-512/version metadata. Reviewed artifact: https://registry.npmjs.org/paseo-auto-pin/-/paseo-auto-pin-0.5.2.tgz, integrity sha512-h8A6deihde7RgTX+4K+8i5Fi8E9/urOSnuPaE9RPgh6iVtFn9uFDu1Qb5DDCBdfi3plNoUJHGtnaMcF2Lo/mJQ==. Checked archive paths/types before extraction. npm-provided provenance names the existing author's repository, tag v0.5.2 and commit e66d0c8e613dbee942eea76d22722416c9b8ef29; its subject digest matches this tarball. This was an artifact review, without a source-match gate.
  • Inspected the independent artifact delta, all ten plugin source modules, manifest/package metadata, both overviews and translation description, lockfile and existing listing media. All plugin TypeScript modules are unchanged after line-ending normalization. The production lock changes zod 4.5.4 to 4.6.7; remaining production pins are unchanged. Downloaded/checksummed all eight production packages against npm and the lock, inspected their manifests and confirmed no installation lifecycle hooks. All lockfile resolved entries use npm HTTPS sources and integrity hashes. No manifest preparation commands or package installation scripts. Dependency internals were not exhaustively audited.
  • Purposeful access remains unchanged: server/lifecycle.ts:10-19 applies the saved project rule at workspace creation; server/pin.ts:10-55 reads the daemon endpoint from config, sends the created workspace ID with pinned: true through the SDK and closes the connection. No credentials are supplied to that client. server/store.ts:7-9,64-82 stores its settings under the Paseo home and removes only its temporary settings file. Project names/paths are returned to the connected UI. No subprocess, runtime software installation or unrelated network destination found in plugin source.
  • The Chinese overview accurately mirrors the English setup, rules, storage and connection limitations. Both use the author's pages. Visually inspected the packaged panel screenshot; current-version PNG URL and other media checks pass. Only registry edits are the review timestamp and two current-version screenshot URLs.
  • Trusted main online validation passes for the completed changed record; all 172 registry tests and exact-head GitHub validation pass. No plugin or dependency installed, built, imported or executed; no live UI/pinning QA. Existing migration discussion and the author's 0.5.1 follow-up were read; no linked submission issue exists for this bump.

@paseo-bot
paseo-bot Bot merged commit 158026e into main Oct 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bump Pinned artifact update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants