{"_id":"@banana-peeljj12/dsh-scratchpad","_rev":"5-512a0698cb3c6d2cfccbfda843ebfbec","name":"@banana-peeljj12/dsh-scratchpad","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@banana-peeljj12/dsh-scratchpad","version":"0.2.0","keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"license":"MIT","_id":"@banana-peeljj12/dsh-scratchpad@0.2.0","maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"homepage":"https://github.com/1264459640/dsh-scratchpad#readme","bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"dsh":{"bundle":{"patch":"cordis.patch.yml"},"client":{"inject":[],"platform":"web","immediately":false}},"dist":{"shasum":"79a10e7f8fb7e9e80a9ff738bfd038bba9dba80b","tarball":"https://registry.npmjs.org/@banana-peeljj12/dsh-scratchpad/-/dsh-scratchpad-0.2.0.tgz","fileCount":15,"integrity":"sha512-k9aZAUkmBN05Ev7+JyOp+AI4rkdaWwtoOBiwoYSHS4rFvkonxFhkkvD9Bggq+acWgvq6ojDbhNy1Yml849ovZA==","signatures":[{"sig":"MEUCIHpvdjmcl4QR3DrLjoaW/zfqqOPoH3PXeXS7A3hy0VV9AiEA19C48zKwVgltZbXOejrcFW9Qf3D39txKGGnWvPkWE6w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76985},"main":"src/index.js","type":"module","exports":{".":"./src/index.js","./paths":"./src/paths.js","./client":"./lib/client.js","./config":"./src/config.js","./fileset":"./src/fileset.js","./promote":"./src/promote.js","./package.json":"./package.json"},"gitHead":"2e75498baff9264d17ff50f169caa63285e5a25c","scripts":{"test":"node --test"},"_npmUser":{"name":"banana-peeljj12","email":"1264459640@qq.com"},"repository":{"url":"git+https://github.com/1264459640/dsh-scratchpad.git","type":"git"},"_npmVersion":"11.17.0","description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^4.4.3","@deepseek-ai/schemastery":"^3.18.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-scratchpad_0.2.0_1788010544504_0.16904912244017045","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@banana-peeljj12/dsh-scratchpad","version":"0.2.1","keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"license":"MIT","_id":"@banana-peeljj12/dsh-scratchpad@0.2.1","maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"homepage":"https://github.com/1264459640/dsh-scratchpad#readme","bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"dsh":{"bundle":{"patch":"cordis.patch.yml"},"client":{"inject":[],"platform":"web","immediately":false}},"dist":{"shasum":"6fd7835b0c55f1098a001f1b29a6a13c45b3a2b0","tarball":"https://registry.npmjs.org/@banana-peeljj12/dsh-scratchpad/-/dsh-scratchpad-0.2.1.tgz","fileCount":15,"integrity":"sha512-foXmHT1Qq9BRKnTbvCdnh0+Ihq2g4PX6tMAl6yD9CNR7Ix5kDkPyN+rgiDnrIL8RDGBCwUD99yyivDAgi7KQQg==","signatures":[{"sig":"MEQCIHKCOJbe7G9R43Ji2PBTpOk2ExFXCNl8rLGYi5KNgHcWAiAyH0V4kwtLBGDoY0HbixA34+a0ScX27ieSUcm0NhRKqg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76985},"main":"src/index.js","type":"module","exports":{".":"./src/index.js","./paths":"./src/paths.js","./client":"./lib/client.js","./config":"./src/config.js","./fileset":"./src/fileset.js","./promote":"./src/promote.js","./package.json":"./package.json"},"gitHead":"b0447fe191aa20631056bc4e8b2fffc09fd10891","scripts":{"test":"node --test"},"_npmUser":{"name":"banana-peeljj12","email":"1264459640@qq.com"},"repository":{"url":"git+https://github.com/1264459640/dsh-scratchpad.git","type":"git"},"_npmVersion":"11.17.0","description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^4.4.3","@deepseek-ai/schemastery":"^3.18.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-scratchpad_0.2.1_1788055657991_0.5748518438108292","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@banana-peeljj12/dsh-scratchpad","version":"0.2.2","keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"license":"MIT","_id":"@banana-peeljj12/dsh-scratchpad@0.2.2","maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"homepage":"https://github.com/1264459640/dsh-scratchpad#readme","bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"dsh":{"bundle":{"patch":"cordis.patch.yml"},"client":{"inject":[],"platform":"web","immediately":false}},"dist":{"shasum":"241777f2e7156866de7d12aab7cc756f45f859a8","tarball":"https://registry.npmjs.org/@banana-peeljj12/dsh-scratchpad/-/dsh-scratchpad-0.2.2.tgz","fileCount":15,"integrity":"sha512-cqn0gnMp7UH7d+5EhL6JTzO3mvMQ85GpObC9bvoAFdLk0jXmmkZDZwvOKkkZNuJHZz9lrz6qTuRh535lg9ISAA==","signatures":[{"sig":"MEYCIQCIV12uLMZS/ifOmTDgD+UOKxhTVxEeOxa07MNObkXbbAIhANA26q3Yl/NvZAEu0PX8MDCEFkVIWXCdFSMo0mw7RqhV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77163},"main":"src/index.js","type":"module","exports":{".":"./src/index.js","./paths":"./src/paths.js","./client":"./lib/client.js","./config":"./src/config.js","./fileset":"./src/fileset.js","./promote":"./src/promote.js","./package.json":"./package.json"},"gitHead":"284a9ab25362c469033cdd5faa738bdfb4d57dda","scripts":{"test":"node --test"},"_npmUser":{"name":"banana-peeljj12","email":"1264459640@qq.com"},"repository":{"url":"git+https://github.com/1264459640/dsh-scratchpad.git","type":"git"},"_npmVersion":"11.17.0","description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^4.4.3","@deepseek-ai/schemastery":"^3.18.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-scratchpad_0.2.2_1788056626558_0.7620843074031536","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@banana-peeljj12/dsh-scratchpad","version":"0.2.3","keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"license":"MIT","_id":"@banana-peeljj12/dsh-scratchpad@0.2.3","maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"homepage":"https://github.com/1264459640/dsh-scratchpad#readme","bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"dsh":{"bundle":{"patch":"cordis.patch.yml"},"client":{"inject":[],"platform":"web","immediately":false}},"dist":{"shasum":"bf6fbbc219e41afe56b2ce7714b684dd931d6c9c","tarball":"https://registry.npmjs.org/@banana-peeljj12/dsh-scratchpad/-/dsh-scratchpad-0.2.3.tgz","fileCount":15,"integrity":"sha512-fdpPQo7BfZ3bXBryv5AVWJ5hbGsFG7u6nx95A4ad2ylluIX0ZJ19dLPXs/v3clncgaYpkNWNmbfuSx3i1L7vtQ==","signatures":[{"sig":"MEUCIQCq8t7HGkKo9eWi5HvRsuJvdAYSfB0RL/JibuGx+uxWigIgeQxeO8rnHUSV1bu8JMSbPvOc/4VIpDXSgdphGiWb0fI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77180},"main":"src/index.js","type":"module","exports":{".":"./src/index.js","./paths":"./src/paths.js","./client":"./lib/client.js","./config":"./src/config.js","./fileset":"./src/fileset.js","./promote":"./src/promote.js","./package.json":"./package.json"},"gitHead":"aa7bae295ad54a953fd2a500093114427a8e28f9","scripts":{"test":"node --test"},"_npmUser":{"name":"banana-peeljj12","email":"1264459640@qq.com"},"repository":{"url":"git+https://github.com/1264459640/dsh-scratchpad.git","type":"git"},"_npmVersion":"11.17.0","description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^4.4.3","@deepseek-ai/schemastery":"^3.18.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dsh-scratchpad_0.2.3_1788057165946_0.7333159038048163","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@banana-peeljj12/dsh-scratchpad","version":"0.3.0","description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","type":"module","main":"src/index.js","exports":{".":"./src/index.js","./config":"./src/config.js","./paths":"./src/paths.js","./fileset":"./src/fileset.js","./promote":"./src/promote.js","./client":"./lib/client.js","./package.json":"./package.json"},"scripts":{"test":"node --test"},"repository":{"type":"git","url":"git+https://github.com/1264459640/dsh-scratchpad.git"},"keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"license":"MIT","dependencies":{"@deepseek-ai/schemastery":"^3.18.1","zod":"^4.4.3"},"dsh":{"bundle":{"patch":"cordis.patch.yml"},"client":{"platform":"web","inject":[],"immediately":false}},"gitHead":"9fe9ba8abe0dd6cac81a6a33e31ba6687a82f6ea","_id":"@banana-peeljj12/dsh-scratchpad@0.3.0","bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"homepage":"https://github.com/1264459640/dsh-scratchpad#readme","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-9b471c5fyhoQhS+XxAPJfxOvcgXYFnkIf3oLYxwsulQNMk3fPXSY5+lPAI3SqFD4aQBIg/BmxBBcmiXDfqbt/Q==","shasum":"b90b1a8e6f1f636167dad35aa53e07f5b02c5b5a","tarball":"https://registry.npmjs.org/@banana-peeljj12/dsh-scratchpad/-/dsh-scratchpad-0.3.0.tgz","fileCount":16,"unpackedSize":95236,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBU7mgkfasABGq3VU/i3GHfY5fVCJUhFILLVRyks2BUwAiEA+1za0qkzgkdeaJx5oq7w8w3fQy+m4ZxbjRF4ifd2UrM="}]},"_npmUser":{"name":"banana-peeljj12","email":"1264459640@qq.com"},"directories":{},"maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-scratchpad_0.3.0_1788091452983_0.5780631684381834"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-29T13:35:44.349Z","modified":"2026-08-30T12:04:13.302Z","0.2.0":"2026-08-29T13:35:44.632Z","0.2.1":"2026-08-30T02:07:38.137Z","0.2.2":"2026-08-30T02:23:46.690Z","0.2.3":"2026-08-30T02:32:46.078Z","0.3.0":"2026-08-30T12:04:13.121Z"},"bugs":{"url":"https://github.com/1264459640/dsh-scratchpad/issues"},"license":"MIT","homepage":"https://github.com/1264459640/dsh-scratchpad#readme","keywords":["dsh","deepseek-harness","plugin","scratchpad","free-chat","workspace"],"repository":{"type":"git","url":"git+https://github.com/1264459640/dsh-scratchpad.git"},"description":"Workspace-free free chat for DeepSeek Harness — a sidebar entry that opens a shared scratchpad workspace (~/.dsh/scratchpad), keeps every tool available, and auto-promotes sessions that produce real files into isolated sibling workspaces (~/.dsh/projects/","maintainers":[{"name":"banana-peeljj12","email":"1264459640@qq.com"}],"readme":"# dsh-scratchpad\n\n**Workspace-free free chat for DeepSeek Harness.** Start a conversation without\npicking a project directory: a persistent sidebar entry opens a shared\nscratchpad workspace, every tool stays available, and sessions that produce\nreal files are automatically promoted into isolated sibling project workspaces\nwith a new-session handoff.\n\n## What it does\n\n| Capability | How |\n|---|---|\n| **One-click free chat** | An independent sidebar section 「自由对话」 — a titled block between the new-session button and the workspaces list (56px rail collapse: a single sparkle icon button) → `GET /scratchpad/open` → `workspaces.startSession(workspaceId)` opens a blank session bound to the shared scratchpad. |\n| **Shared default directory** | All free chats share `${DSH_HOME:-~/.dsh}/scratchpad/` (mkdir + `workspaceRegistry.create` at startup, idempotent). |\n| **Fully open tools (no stripping)** | The plugin never restricts tools — bash, write/edit, web search etc. all work; safety stays with DSH's own sandbox + approval. |\n| **Isolated artifact promotion** | When a session produces files, its file-set is **copied** (never moved — the scratchpad is shared) into `${DSH_HOME:-~/.dsh}/projects/<date>-<slug>` — a **sibling** of the scratchpad, never a child — registered as a new workspace, and a banner offers **「在新工作区打开」** (`workspaces.startSession(projectWorkspaceId)`) so you continue in a fresh session bound to the project. |\n| **Detection** | Two layers: `fs/observed` + `fs/write-intent` events (exact absolute paths, attributed via the acting agent's session) plus a per-turn recursive scratchpad scan that catches files bash/subprocess created (bash emits no fs events). A single global snapshot prevents two sessions from double-claiming a file. |\n\n## Why promote → new session (not \"redirect\")\n\nA DSH session's `cwd` is fixed in its immutable `SessionHeader`, and workspace\nmembership is *derived* from that canonical `cwd` (`attachSession` validates\n`realpath(header.cwd) === workspace.path`). There is no API to move a live\nsession to another workspace. Promotion therefore:\n\n1. `mkdir` the projects root and atomically claim a unique\n   `<date>-<slug>[-N]` directory (`mkdir({recursive:false})` + EEXIST retry);\n2. copy the session's file-set in under a staging temp dir, then rename into\n   place (`projects/<slug>/artifacts/`), **preserving each file's path\n   relative to the scratchpad root** (so `scratchpad/src/a.go` lands at\n   `artifacts/src/a.go` — no basename flattening, no collisions between\n   same-named files in different subdirs); a half-copied project never\n   reaches the registry (copy failure rolls the whole claimed dir back);\n3. `workspaceRegistry.create(projectDir, title)` — only after the directory\n   exists (the registry `realpath`s the path);\n4. the client banner hands off to a **new session** in that workspace.\n\nThe scratchpad session stays put; originals remain in the shared scratchpad\n(copy semantics) and can be cleaned with `/scratchpad-tidy`.\n\n## Requirements\n\n- DSH with the **web profile** (the host half injects `workspaceRegistry`\n  from `@deepseek-ai/dsh-workspace`, `webServer`, `commands`, `fs`, `timer`,\n  `sessions`, `sessionQuery`, `agents` — all shipped in the web profile's\n  base/web-app bundles; no extra composition rows needed).\n- Dependency: `zod` and `@deepseek-ai/schemastery` (declared in\n  `package.json`).\n\n## Install\n\n```bash\n# from the npm registry\ndsh plugin --profile web add -w @banana-peeljj12/dsh-scratchpad\n\n# from a packed tarball / source checkout (development)\ndsh plugin --profile web add -w link:/abs/path/to/dsh-scratchpad\n```\n\nThen restart `dsh web`. An independent 「自由对话」 section appears between the\nnew-session button and the workspace list; collapse the sidebar to get a single\nicon button between the new-session and workspace icons.\n\n## Configuration\n\nIn the web profile's `cordis.patch.yml` (or by merging this package's\n`cordis.patch.yml`):\n\n```yaml\n- insert:\n    - id: scratchpad\n      name: '@banana-peeljj12/dsh-scratchpad'\n      config:\n        scratchpadPath: ''   # default ${DSH_HOME:-~/.dsh}/scratchpad\n        projectsPath: ''     # default ${DSH_HOME:-~/.dsh}/projects\n        autoPromote: true    # false: only the manual command stays active\n        slugMaxLen: 8\n```\n\nPath rules enforced at load:\n\n- `~` expands to the user home; `$DSH_HOME` (when set) replaces `~/.dsh`.\n- canonical `projectsPath` **must not** equal or nest inside canonical\n  `scratchpadPath` — the plugin throws a clear config error otherwise (the\n  isolation invariant is the point).\n\n## Development\n\n```bash\nnode test/paths-test.mjs      # slug derivation, collisions, error classes\nnode test/config-test.mjs     # ~/DSH_HOME expansion, isolation guard\nnode test/fileset-test.mjs    # shared-scratchpad attribution, double-claim prevention\nnode test/promote-test.mjs    # copy atomicity + structure, collision, rollback, mkdir-then-create\nnode test/host-test.mjs       # mounted host half over stubbed services\nnode test/injection-test.mjs  # client-side injection locator chain + degrade criteria (mock DOM)\n```\n\nThe client half is a hand-written, zero-build browser bundle\n(`lib/client.js`, `window.__ModuleLoader__.load` + react/jsx-runtime +\n`dsh-client-ui-primitives`) registered through the public slot system —\nno build step.\n\n## Verify\n\n```bash\nnode test/injection-test.mjs\nnode test/paths-test.mjs && node test/config-test.mjs && node test/fileset-test.mjs && node test/promote-test.mjs && node test/host-test.mjs\ndsh web --dump-config | grep scratchpad    # row composed into the profile\ncurl 'http://127.0.0.1:3080/scratchpad/open'        # { \"workspaceId\": \"…\" } — idempotent twice\ncurl 'http://127.0.0.1:3080/scratchpad/promotions'  # { \"promotions\": […] }\n```\n\nManual UI checklist:\n\n1. Wide sidebar: an independent 「自由对话」 section (title + 「开始自由对话」)\n   shows between the new-session button and the workspaces list; the bottom\n   「自由对话」 footer button is gone.\n2. Click 「开始自由对话」 → a blank session in the scratchpad workspace opens.\n3. Collapse the sidebar (56px rail): the section collapses to a single icon\n   button between the new-session and workspace icons, visually distinct from\n   the new-session icon; clicking it behaves the same.\n4. Light/dark theme switch → the section follows the theme.\n5. Ask the agent to write a file (or run bash that creates one) → after the\n   turn a banner appears: 产物已提升到独立工作区 … + 「在新工作区打开」.\n6. Click it → a new session opens bound to `projects/<date>-<slug>`; the\n   artifact is under `artifacts/`.\n7. `/scratchpad` shows the paths, workspace id and promotion count;\n   `/scratchpad-tidy` (then `--apply`) removes originals that no other live\n   scratchpad session still references.\n8. Reload or remove the plugin → the injected section DOM is removed with no\n   residue in the sidebar; after a reload the section comes back.\n\n## Design notes\n\n- **Independent section via anchor + portal (reviewed DOM injection)** — the\n  slot system has no sidebar-section slot, so the client keeps a `display:none`\n  anchor inside its `sidebar.footer.action` registration and resolves the\n  sidebar root + workspaces region through an explicit per-step criteria chain\n  (`closest('[data-slot=\"sidebar.footer.action\"]')` → footerActions → footArea\n  → root; regionArea must be footArea's previous sibling owning the workspaces\n  outlet). It injects a `flex:none` section div in front of the regionArea and\n  renders it with `createPortal` — same React tree, so locales and contexts\n  keep working. Every failed criterion degrades **visibly** to the legacy\n  footer button (warn + fallback render); the injected node carries a data\n  mark for idempotent reuse and an owner token so unmount/HMR cleanup never\n  leaves residue.\n- **Slot-only UI, zero shadowing** — `sidebar.footer.action` and\n  `conversation.input.dock` are additive `list` slots; the plugin registers\n  nothing into `sidebar.workspaces`/`sidebar.settings` (both `single`) and so\n  cannot shadow core UI or other plugins; unloads cleanly (every host\n  registration is a fiber effect).\n- **Theme tokens only** — all colors are `--dsw-alias-*` variables;\n  light/dark follows the shell for free (`color-scheme`).\n- **Copy, never move** — the scratchpad is shared across sessions; moving\n  files would break other live sessions' tool paths. Originals stay until a\n  user-confirmed `/scratchpad-tidy --apply`.\n- **Rollback-safe promotion** — staging temp dir + rename publishes the\n  project only when complete; registry-create failure rolls the claimed dir\n  back; a new workspace is never registered pointing at a half-copied dir.\n\n## Rollback / uninstall\n\nRemove the plugin row (or `dsh plugin --profile web remove @banana-peeljj12/dsh-scratchpad`)\nand restart. All host registrations (routes, commands, listeners) are fiber\neffects and disappear; the registered workspaces stay usable as ordinary\nworkspaces, and no physical files are deleted.\n\nMIT — see [LICENSE](./LICENSE).","readmeFilename":"README.md"}