{"_id":"@achasoft/dsh-worktree","name":"@achasoft/dsh-worktree","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@achasoft/dsh-worktree","version":"0.1.0","description":"Git worktrees and branches for the DeepSeek Harness Web Client: a session-header chip that shows where the session is checked out, branch and worktree switching, and worktrees adopted as harness workspaces","license":"MIT","type":"module","main":"lib/index.js","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","default":"./lib/index.js"},"./host":{"types":"./types/host/index.d.ts","default":"./lib/host.js"},"./client":{"default":"./lib/client.js"},"./remote":{"default":"./lib/remote.js"},"./typert":{"default":"./lib/typert.host.js"},"./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"platform":"web","inject":["@deepseek-ai/dsh-api-remotes","@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-conversation","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-settings-plugins"]}},"scripts":{"build":"tsc -p tsconfig.build.json && tsdown","prepare":"tsc -p tsconfig.build.json && tsdown","typecheck":"tsc --noEmit","test":"node scripts/check-typert.mjs && vitest run","check:typert":"node scripts/check-typert.mjs","regen:typert":"node scripts/emit-typert.mjs"},"peerDependencies":{"@deepseek-ai/cordis":"*","@deepseek-ai/dsh-fs":"*","@deepseek-ai/dsh-settings":"*","@deepseek-ai/dsh-subprocess":"*","@deepseek-ai/dsh-typert-protocol":"*","@deepseek-ai/schemastery":"*"},"dependencies":{"zod":"^4.4.3"},"devDependencies":{"@deepseek-ai/cordis":"link:../../deepseek-harness/vendor/cordis","@deepseek-ai/dsh-api-remotes":"link:../../deepseek-harness/packages/api/remotes","@deepseek-ai/dsh-brand":"link:../../deepseek-harness/packages/util/brand","@deepseek-ai/dsh-client-locale":"link:../../deepseek-harness/packages/client/locale","@deepseek-ai/dsh-client-runtime":"link:../../deepseek-harness/packages/client/runtime","@deepseek-ai/dsh-client-ui-conversation":"link:../../deepseek-harness/packages/client/ui-conversation","@deepseek-ai/dsh-client-ui-primitives":"link:../../deepseek-harness/packages/client/ui-primitives","@deepseek-ai/dsh-client-ui-settings":"link:../../deepseek-harness/packages/client/ui-settings","@deepseek-ai/dsh-client-ui-settings-plugins":"link:../../deepseek-harness/packages/client/ui-settings-plugins","@deepseek-ai/dsh-client-ui-slots":"link:../../deepseek-harness/packages/client/ui-slots","@deepseek-ai/dsh-fs":"link:../../deepseek-harness/packages/fs/fs","@deepseek-ai/dsh-settings":"link:../../deepseek-harness/packages/settings/settings","@deepseek-ai/dsh-subprocess":"link:../../deepseek-harness/packages/subprocess/subprocess","@deepseek-ai/dsh-typert-protocol":"link:../../deepseek-harness/packages/typert/protocol","@deepseek-ai/schemastery":"link:../../deepseek-harness/vendor/schemastery","@types/node":"^22.20.1","@types/react":"~18.3.1","@types/react-dom":"~18.3.1","lightningcss":"^1.30.1","react":"^18.2.0","react-dom":"^18.2.0","tsdown":"^0.15.6","typescript":"^5.9.2","vitest":"^3.2.7"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/navid-kianfar/dsh-worktree.git"},"keywords":["deepseek-harness","dsh","dsh-plugin","git","git-worktree","worktree","branches","branch-switcher","cordis"],"engines":{"node":"^22.19 || >=24"},"gitHead":"286ee88e667a952e4bd04987868d731e7ec1cda2","_id":"@achasoft/dsh-worktree@0.1.0","bugs":{"url":"https://github.com/navid-kianfar/dsh-worktree/issues"},"homepage":"https://github.com/navid-kianfar/dsh-worktree#readme","_nodeVersion":"25.2.1","_npmVersion":"11.19.0","dist":{"integrity":"sha512-u7Mq8g7YX2HjMJP92DLKGw254uCGCsEMzFKpcCjPvMtpT2OG66CQKWZv6d9XIAEfwNe5a/9MlZS+ic2L5h2tGw==","shasum":"fef78ace1a8ae51de280bf9b3fd504b5544c1ae2","tarball":"https://registry.npmjs.org/@achasoft/dsh-worktree/-/dsh-worktree-0.1.0.tgz","fileCount":36,"unpackedSize":1029810,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDP58c/1/sVYaJmIO8fhEOBrF1259q4IfUsb6NenM14MgIhAMTZkKB2k+O/077k7fH/ghbIKoJTcNkDwDDnDuUvUUB6"}]},"_npmUser":{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"},"directories":{},"maintainers":[{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-worktree_0.1.0_1787753138952_0.2637600788101633"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-26T14:05:38.764Z","0.1.0":"2026-08-26T14:05:39.096Z","modified":"2026-08-26T14:05:39.349Z"},"maintainers":[{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"}],"description":"Git worktrees and branches for the DeepSeek Harness Web Client: a session-header chip that shows where the session is checked out, branch and worktree switching, and worktrees adopted as harness workspaces","homepage":"https://github.com/navid-kianfar/dsh-worktree#readme","keywords":["deepseek-harness","dsh","dsh-plugin","git","git-worktree","worktree","branches","branch-switcher","cordis"],"repository":{"type":"git","url":"git+https://github.com/navid-kianfar/dsh-worktree.git"},"bugs":{"url":"https://github.com/navid-kianfar/dsh-worktree/issues"},"license":"MIT","readme":"# @achasoft/dsh-worktree\n\nGit worktrees and branches for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web Client.\n\nA chip in the session header says which branch and which worktree the session is working in. Clicking either half opens a switcher; the `+` beside them creates a new worktree, adopts its directory as a harness Workspace, and opens a session there.\n\n```\n ⑂ main ↑2 •  │  ⧉ my-repo  2      +\n   └ branch      └ worktree        └ new worktree\n```\n\n## What it does\n\n**Branches** — list local and remote-tracking branches with their tip commit, author, age, and ahead/behind counters; filter them by fuzzy search; switch, create, rename, and delete. A branch already checked out in another worktree says so and jumps there instead of failing, because git refuses to check one branch out twice. `Fetch` updates remote-tracking refs and prunes the ones whose remote branch is gone.\n\n**Worktrees** — list every worktree of the repository with its branch, path, and lock or prunable state; open a session in one; lock, unlock, remove, and prune. Creating a worktree fills its directory from a configurable path template, then optionally registers it as a Workspace and starts a session in it.\n\n**Uncommitted work is never discarded.** A checkout with local changes uses `git switch --merge`, which carries them across and aborts on conflict. A force-delete or force-remove is a separate switch, and by default also needs the branch or worktree name typed to confirm.\n\n## Requirements\n\n- DeepSeek Harness with the `web` app.\n- `git` on the host process PATH. `git switch` is used, so **git 2.23 or newer**; git 2.36 adds the NUL-separated worktree listing this plugin prefers and the `locked`/`prunable` attributes it reads, and below that it falls back cleanly.\n- The `@deepseek-ai/dsh-subprocess` and `@deepseek-ai/dsh-fs` capabilities, both of which the base bundle mounts. Without either, the header control stays hidden and the settings card says which one is missing.\n\n## Install\n\n```sh\ndsh plugin --profile web add @achasoft/dsh-worktree\n```\n\nThen add it to the profile's bundle list in `$DSH_HOME/profiles/web/package.json`:\n\n```json\n{\n  \"dsh\": {\n    \"profile\": {\n      \"bundles\": [\"@deepseek-ai/dsh-base\", \"@deepseek-ai/dsh-web-app\", \"@achasoft/dsh-worktree\"]\n    }\n  }\n}\n```\n\nRestart the profile. Nothing else is required — there is no provider to choose and no credential to supply.\n\n## Settings\n\nEvery field is editable from **Settings → Plugins → Worktrees and branches**, and from your profile's `cordis.patch.yml` by the `worktree` id. Changes take effect on the next request; nothing needs a restart.\n\n| Field | Default | What it does |\n| --- | --- | --- |\n| `showChip` | `true` | Render the session-header control. Off keeps the endpoints and this card. |\n| `worktreePathTemplate` | `{repoParent}/{repo}-worktrees/{branch}` | Where a new worktree goes. See below. |\n| `branchPrefix` | `''` | Prefilled when creating a branch, e.g. `feature/`. |\n| `registerWorkspace` | `true` | Adopt a worktree's directory as a harness Workspace. |\n| `openSession` | `true` | Open a session in that Workspace. Requires `registerWorkspace`. |\n| `includeRemoteBranches` | `true` | List remote-tracking branches beside the local ones. |\n| `maxBranches` | `200` | Most branches one reading returns; the list says when it truncated. |\n| `refreshIntervalMs` | `15000` | How often the chip re-reads. `0` reads only on an explicit refresh. |\n| `gitTimeoutMs` | `20000` | Bound for a local git command. |\n| `networkTimeoutMs` | `120000` | Bound for a command that contacts a remote. Never below `gitTimeoutMs`. |\n| `maxOutputBytes` | `1048576` | In-memory cap per captured git stream. |\n| `graceMs` | `5000` | TERM-to-KILL grace when a git command is terminated. |\n| `confirmDestructive` | `true` | Require typing the name before a force-delete or force-remove. |\n\n### Path template\n\nThe template expands against the repository being acted on. A relative result resolves against the repository root.\n\n| Placeholder | Expands to |\n| --- | --- |\n| `{repoRoot}` | the repository's main worktree directory |\n| `{repoParent}` | its parent directory |\n| `{repo}` | its basename |\n| `{branch}` | the branch name with `/` folded to `-`, so `feature/login` stays one directory |\n| `{branchPath}` | the branch name with its slashes kept, so `feature/login` nests |\n\nThe template must contain `{branch}` or `{branchPath}`; without one, every worktree would expand to the same directory and only the first could be created. The plugin refuses such a template at load and the settings card refuses to store it.\n\n## Design notes\n\n**git runs on the host, never in the browser.** Reading a repository means running `git` and parsing its machine formats, and creating a worktree means writing a directory — neither is reachable from a page. What crosses the wire is already classified: parsed readings, and mutation outcomes carrying git's own summary line.\n\n**A value from the browser becomes a git argument only after the host has proved what it names** — a branch through `rev-parse --verify`, a worktree path by matching git's own `worktree list`. The one path that skips that check, a new worktree's destination, must be absent or an empty directory.\n\n**Nothing here is model-facing.** Which branch you are on is operator context that never enters a prompt, so the plugin adds no tool, no prompt contribution, and no session event. The agent reaches git the way it always has: through the shell.\n\n**Remote branches are never deleted.** Deleting one means pushing a deletion to somebody else's repository, which is not something a switcher popover should be able to do by accident.\n\n**Removing a worktree leaves its Workspace registered.** The removal dialog promises to delete a directory and keep the branch; silently un-registering a Workspace you may have created yourself is a different domain's business. Remove it from the sidebar when you want it gone.\n\n## Development\n\n```sh\npnpm install\npnpm run typecheck\npnpm test          # checks the generated Typert contract, then runs the unit tests\npnpm run build\n```\n\n`generated/` holds the Typert RPC contract and is **committed source**, not a build output this package can reproduce: the harness's generator only runs inside a `deepseek-harness` checkout. It is authored to that generator's format by `scripts/emit-typert.mjs`, and `pnpm test` refuses a mismatch — so editing `src/host/types.ts` or the `@Remote` surface means editing that spec and re-running `pnpm run regen:typert`.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-2d0b7830fb45fe4779834a1b59fe28b8"}