@skillre/dsh-plugin-sticky-wall 0.0.0-stage → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 skillre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,154 @@
1
+ # @skillre/dsh-plugin-sticky-wall · Sticky Wall
2
+
3
+ > Status: experimental · for DSH `0.2.2-rc.1`
4
+
5
+ A sticky-note wall in the DSH left sidebar: capture a passing idea, a piece of temporary work, or a short reminder, and place it on the board **like a real sticky on a desk** — drag it, resize it, tidy the whole wall in one click. Bodies are written in **Markdown** and rendered right on the card. Both the notes and their placement are persisted by the Host, so position and content survive a DSH restart.
6
+
7
+ [中文](README.md)
8
+
9
+ ## What it solves
10
+
11
+ Ideas arrive at the busiest moments, and the friction of "open a document, invent a title, pick a folder" is enough to lose them. The sticky wall compresses it into three steps: click the sidebar entry, type one line, press `⌘/Ctrl + Enter`. It is a **scratchpad**, not a knowledge base: no hierarchy, backlinks or rich text — just capture now and find it later.
12
+
13
+ Non-goals: task management (no scheduling, assignment or reminders), collaboration, exporting a Markdown knowledge base, or a WYSIWYG rich-text editor (the body stays Markdown source; rendering is a reading view).
14
+
15
+ ## Features
16
+
17
+ - **Sidebar entry** — a "Notes" glyph in `sidebar.panellist`; clicking it swaps the centre column to the wall.
18
+ - **Free canvas** — notes are cards on a canvas, not list rows. Position, rotation and a three-step width (small/medium/large) are note data owned by the Host, so the same wall opens with the same arrangement in another window.
19
+ - **Drag to place** — press anywhere on a card and drag; releasing writes the new position to the Host. A drag does **not** bump `updatedAt`, so tidying your desk never reshuffles a "by updated" sort.
20
+ - **One-click tidy** — "Tidy" repacks the visible notes with a deterministic shelf algorithm: pressing it twice yields the same wall instead of reshuffling every time.
21
+ - **Three views** — canvas (default, free placement), grid (responsive masonry for reading long notes) and list (one line per note for finding one by title).
22
+ - **Zoom** — a floating `− / percent / + / reset` control on the canvas, plus `⌘/Ctrl + wheel` (0.4×–2×).
23
+ - **Markdown bodies** — headings, paragraphs, bold/italic/strikethrough, `code`, code blocks, ordered and unordered lists, `- [ ]` checkboxes, quotes, rules, tables and http(s)/mailto links. The composer has a "Preview" toggle.
24
+ - **Quick capture** — "New" opens a note sheet with an optional title, required body, tags, six pastel colors and a width preset.
25
+ - **Pin and archive** — pinned notes carry a coloured left rail and a star; archived notes hide by default, the "Archive" filter fetches them on its own, and "Clear archive" is a permanent delete.
26
+ - **Note actions** — hovering or keyboard-focusing a note reveals pin, resize, edit, archive and delete at its top-right; on touch devices they stay visible.
27
+ - **Search and sort** — live filtering over body, title and tags; order by pinned, created or updated.
28
+ - **Light and dark** — the frame uses only DSH theme tokens; note pastels are the plugin's own palette with dark variants.
29
+ - **Bilingual** — follows the DSH GUI language live, without a reload.
30
+ - **Model-visible** — optionally registers a `sticky_wall` tool, so "note that …" creates a real note, and `arrange` tidies the wall.
31
+
32
+ ## Data and permissions
33
+
34
+ | Item | Detail |
35
+ |---|---|
36
+ | Data owner | Host. Notes (including canvas placement) persist through the native DSH `storageDomain`, domain `skillre_sticky_wall`, `per-record` layout (one file per note). |
37
+ | Data location | Decided by the profile's storage backend; the shipped profile's `storage-json` row writes domain files under `$DSH_HOME/storages`. |
38
+ | Network | No external requests. Browser ↔ Host uses the local DSH `/api` channel only. |
39
+ | Filesystem | Only the domain directory through the storage backend; no arbitrary user files. |
40
+ | Secrets | None. |
41
+ | Model-visible | Only when `enableAgentTool` is true (default): the `sticky_wall` tool, whose results include note text in the session. |
42
+
43
+ ## Configuration
44
+
45
+ Override by row id in the profile's `cordis.patch.yml` (a patch replaces the whole `config`, so omitted keys take their defaults):
46
+
47
+ ```yaml
48
+ - id: skillre-sticky-wall
49
+ name: '@skillre/dsh-plugin-sticky-wall'
50
+ config:
51
+ maxNotes: 400
52
+ enableAgentTool: true
53
+ seedWelcomeNote: true
54
+ ```
55
+
56
+ | Key | Default | Meaning |
57
+ |---|---|---|
58
+ | `maxNotes` | `400` | Cap on live (non-archived) notes, 1–5000. Creating, unarchiving and batch-restoring all respect it; going over returns `sticky-wall/wall-full`, so archive or delete first. |
59
+ | `enableAgentTool` | `true` | Whether to register the model-facing `sticky_wall` tool. |
60
+ | `seedWelcomeNote` | `true` | Whether a brand-new empty wall gets one welcome note explaining the shortcuts. |
61
+
62
+ ## Install
63
+
64
+ After development and test cleanup, **the user** chooses the source and confirms install/enable in the DSH Desktop Client or Web UI **Plugins** manager; no developer or agent preinstalls it into the user's profile.
65
+
66
+ - **In the plugin market**: add `https://skillre.github.io/dsh-plugin-market/index.json` under **Plugins → Discover → Index sources** (enable the experimental *Custom plugin markets* bundle first), then install the plugin from Discover.
67
+ - **npm (recommended, and the only source that supports in-place updates)**: enter the npm spec `@skillre/dsh-plugin-sticky-wall@<version>` in the install dialog.
68
+ - Not published: an absolute path to a built `.tgz` may be offered only after verifying that this manager accepts the source and the artifact is installable.
69
+ - This repository is a **self-contained** Git source: the built `lib/` output is committed and no `scripts.prepare` is declared, so an install runs no build script. The pinned spec looks like `git+https://github.com/skillre/dsh-plugin-sticky-wall.git#<commit>` and has been verified installable.
70
+
71
+ ## Update and rollback
72
+
73
+ From the DSH `0.2.2` line, the plugin page has an official **Versions** section (`listVersions` / `updateBundle`) that can check and update in place. Whether a bundle gets it depends **only on the install source and package contents**, never on repository configuration:
74
+
75
+ | Install source | In-place update |
76
+ |---|---|
77
+ | npm registry (`@skillre/dsh-plugin-sticky-wall@<version>`) | Yes — the detail page shows a Versions section and updates in place |
78
+ | `git+https://…#<commit>` (this repository's market entry) | No — no Versions section; uninstall and reinstall |
79
+ | Local `.tgz` / `file:` | No — same as above |
80
+
81
+ Every `updatable` condition holds for this plugin: third-party bundle, registry spec saved under its own package name, valid SemVer, and no protected plugin-management row such as `@deepseek-ai/dsh-plugin-manager`. **Install by npm package name to get the official update path.**
82
+
83
+ Update semantics, stated plainly:
84
+
85
+ - **Upgrade only** — the UI never offers an older version than the installed one.
86
+ - A successful update stores an **exact version** in the profile dependency (even if it was a range); a restore after failure does the same.
87
+ - An update is remove-then-install: under HMR the reinstalled bundle can move to the end of the bundle list and change configuration-layer order.
88
+ - Failure is recoverable: a failed install, cancellation or boot failure restores the previous version; if the restore also fails the package is left uninstalled.
89
+ - A version that needs new build-script approval fails and restores the old version.
90
+ - `allow-version` exemptions exist only in the CLI and agent tooling, not in the plugin page.
91
+
92
+ - **Rollback**: npm versions are immutable. `npm deprecate` the faulty version and publish a fix; the user removes the faulty bundle in the plugin manager and reinstalls a known-good version (if the UI cannot pin an older one, the user decides the recovery channel).
93
+ - **Data compatibility**: the domain carries a `version` field and compatibility only holds within the same version. Back up the domain directory under `$DSH_HOME/storages` before downgrading. Canvas placement is a new optional field: an older note loads with `layout: null` and the UI derives a preview position from the note id, so a downgrade does not fail on the missing field.
94
+ - **Uninstall**: see [UNINSTALL.md](UNINSTALL.md). Uninstalling the plugin does **not** delete note data automatically.
95
+
96
+ ## Display metadata (plugin card and detail page)
97
+
98
+ DSH reads the plugin card and detail page **without activating the plugin**, so these resources must ship in the package, in three layers:
99
+
100
+ | Layer | Files | Content |
101
+ |---|---|---|
102
+ | Card title/subtitle | `meta.title` / `meta.description` in `locale/en.json`, `locale/zh.json` | One line, <= 120 characters, plain text |
103
+ | Detail page | `meta.detail` -> `docs/DETAIL.md` / `docs/DETAIL.zh.md` | **Exactly one** `![alt](preview*.svg)` line |
104
+ | Developer docs | `README.md` / `README.en.md` (this file) | Install, configuration, compatibility, limitations |
105
+
106
+ - `locale/*.json` is resolved through the Node ESM resolver, so `exports` must declare `"./locale/*.json"`. Without it, `ERR_PACKAGE_PATH_NOT_EXPORTED` is thrown and DSH **swallows it silently**, leaving the card showing the bare package name with no diagnostic anywhere.
107
+ - `meta.detail` is new in DSH `0.2.2`: a package-relative Markdown path read from the **package directory** (not through exports), so `files` must include `docs`. Without `meta.detail`, DSH falls back to `README.md` — dumping this developer manual into the detail page, which is exactly what this version fixes.
108
+ - Preview images: `docs/preview.svg` (English) and `docs/preview.zh.svg` (Chinese), at the fixed 640x300 logical ratio (this repository uses 1280x600). Rules live in the fleet's `docs/display-contract.md`; the whiteboard registry is [docs/PREVIEW.md](docs/PREVIEW.md).
109
+
110
+ ```sh
111
+ node scripts/preview.mjs check # offline preview/locale check (`npm run check` runs it)
112
+ ```
113
+
114
+ ## Plugin market
115
+
116
+ The plugin is published to the market index this fleet generates:
117
+
118
+ - Index: `https://skillre.github.io/dsh-plugin-market/index.json`
119
+ - Entry: `@skillre/dsh-plugin-sticky-wall@0.1.2`, commit-pinned Git source (`83c932f`)
120
+ - Icon: `https://skillre.github.io/dsh-plugin-market/icons/sticky-wall.svg`
121
+
122
+ The install path was verified end to end: derive the spec from the live index, install into an isolated profile, `--dump-config`, bounded startup, live route (evidence in `docs/evidence/market-install-0.1.2.json`).
123
+
124
+ ## Known limitations
125
+
126
+ - The wall is a scratchpad: body up to 4000 characters, title 120, up to 8 tags — hard limits.
127
+ - **Markdown is a deliberate subset**, not full CommonMark: headings (`#`–`####`), paragraphs and hard breaks, bold/italic/strikethrough, inline `` `code` ``, ``` / ~~~ code blocks, ordered and unordered lists, `- [ ]` checkboxes, quotes, rules, pipe tables and http(s)/mailto links. **Not supported**: nested list indentation, images, footnotes, or interactive checkboxes (they render as a read-only glyph).
128
+ - **Raw HTML in a body is shown as text** — it is neither executed nor rendered. That is a safety decision, not a bug.
129
+ - Card width has only **three presets** (small/medium/large); there is no arbitrary resize. Rotation resets to zero while dragging and the tidy pass re-adds a slight tilt.
130
+ - The canvas is a flat plane: no grouping, layers, connectors or snap alignment.
131
+ - Placement is owned by the Host, but two windows open on the same wall each render their own snapshot and do not live-push the other's drags.
132
+ - Archived notes do not occupy a `maxNotes` slot, but restoring them does; a restore at the cap is rejected instead of silently overshooting.
133
+ - "Clear archive" is a permanent, irreversible delete.
134
+ - Batch archive/delete is all-or-nothing: one unknown id in the request rejects the whole batch.
135
+ - With several windows open, each fetches its own snapshot; the Host is the single source of truth, but no live push across windows.
136
+ - Verified only against DSH `0.2.2-rc.1`; no other DSH line is claimed.
137
+
138
+ ## Compatibility
139
+
140
+ See [compatibility.json](compatibility.json) for the DSH versions really mounted, verification dates and checks. `engines.dsh` is an install declaration, **not** compatibility evidence.
141
+
142
+ ## Development
143
+
144
+ ```sh
145
+ npm install
146
+ npm run check # typecheck + tests + publication view
147
+ npm pack # build the installable tarball
148
+ ```
149
+
150
+ Package contents: `lib/` (built Host and Client artifacts with declarations), `cordis.patch.yml`, `compatibility.json`, `locale/*.json`, `icon.svg`, docs and license.
151
+
152
+ ## License
153
+
154
+ MIT
package/README.md CHANGED
@@ -1,3 +1,165 @@
1
- # Temporary Holding Version
1
+ # @skillre/dsh-plugin-sticky-wall · 便签墙
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > 状态:experimental · 面向 DSH `0.2.2-rc.1`
4
+
5
+ 在 DSH 左侧栏加一个「便签墙」入口:随手记下一闪而过的灵感、临时的活儿和短提醒,像便签贴在桌上一样**自由摆放** —— 拖动、缩放、一键整理;正文用 **Markdown** 写,卡片上直接渲染出来。便签与摆位都由 Host 持久化,重启 DSH 后位置和内容都在。
6
+
7
+ [English](README.en.md)
8
+
9
+ ## 它解决什么
10
+
11
+ 灵感往往出现在最忙的时候,而「打开一个文档、想个标题、找个位置」的摩擦足以让灵感溜走。便签墙把这件事压缩成三步:点侧栏 → 写一行 → `⌘/Ctrl + Enter`。它是**速记板**,不是知识库:不追求层级、双链或富文本,只保证「想到就记下、回头找得到」。
12
+
13
+ 非目标:不做任务管理(不排期、不分派、不提醒)、不做协作共享、不导出 Markdown 知识库、不做富文本所见即所得编辑器(正文是纯 Markdown 源码,渲染只是阅读视图)。
14
+
15
+ ## 功能
16
+
17
+ - **左侧栏入口**:`sidebar.panellist` 中的「便签墙」图标,点击把中央区域切换到便签墙页面。
18
+ - **自由画布**:便签不是列表项,而是画布上的卡片。位置、旋转角、宽度三档(小/中/大)都属于便签数据,由 Host 保存;同一面墙在另一个窗口打开时摆位一致。
19
+ - **拖动摆放**:按住卡片任意位置即可拖动,松手时把新位置写回 Host。拖动本身**不会**改 `updatedAt`,所以「按更新」排序不会因为你整理桌面而乱掉。
20
+ - **一键整理**:「整理」把当前可见便签按确定性货架算法重新排布 —— 同一面墙按两次得到同一个结果,不会每按一次就重排一遍。
21
+ - **三种视图**:画布(默认,自由摆位)、网格(响应式瀑布流,适合读长文)、列表(一行一条,适合按标题找)。
22
+ - **缩放**:画布左下角有 `− / 百分比 / + / 重置`,`⌘/Ctrl + 滚轮` 也能缩放(0.4×–2×)。
23
+ - **Markdown 正文**:正文按 Markdown 渲染 —— 标题、段落、粗体/斜体/删除线、`代码`、代码块、有序/无序列表、`- [ ]` 复选、引用、分隔线、表格、http(s)/mailto 链接。编辑时右侧有「预览」切换。
24
+ - **随手记录**:`+ 新建` 打开便签纸,标题可选、正文必填,可打标签、选六种柔和底色、选卡片宽度。
25
+ - **置顶与归档**:置顶的便签带左侧色条与星标;归档的便签默认隐藏,「归档」筛选会单独拉取它们,「清空归档」是永久删除。
26
+ - **便签操作**:悬停或用键盘聚焦便签时,右上角出现置顶、换尺寸、编辑、归档、删除五个按钮;触屏设备上常驻显示。
27
+ - **搜索与排序**:按正文、标题、标签实时过滤;可按「置顶优先 / 按创建 / 按更新」排序。
28
+ - **深浅色**:只使用 DSH 主题 token 绘制框架,便签底色与文字色为插件自有配色并各自提供深色变体。
29
+ - **中英双语**:跟随 DSH 界面语言实时切换,无需刷新。
30
+ - **模型可用**:可选注册 `sticky_wall` 工具,直接对我说「记一下……」即可落成一张便签;也能让我 `arrange` 整理整面墙。
31
+
32
+ ## 数据与权限
33
+
34
+ | 项目 | 说明 |
35
+ |---|---|
36
+ | 数据所有者 | Host。便签(含画布摆位)通过 DSH 原生 `storageDomain` 持久化,域名为 `skillre_sticky_wall`,`per-record` 布局(一张便签一个文件)。 |
37
+ | 数据位置 | 由 profile 的 storage 后端决定;shipped profile 的 `storage-json` 行把域文件放在 `$DSH_HOME/storages` 下。 |
38
+ | 网络 | 无外部网络请求。浏览器 ↔ Host 只走本机 DSH 的 `/api` 通道。 |
39
+ | 文件系统 | 仅经由 storage 后端读写该域目录,不读写任意用户文件。 |
40
+ | 密钥 | 不使用任何密钥。 |
41
+ | 模型可见 | 仅当 `enableAgentTool` 为真(默认)时注册 `sticky_wall` 工具;便签内容在工具调用返回时进入会话。 |
42
+
43
+ ## 配置
44
+
45
+ 在 profile 的 `cordis.patch.yml` 中按行 id 覆盖(`config` 整行替换,未写出的键取默认值):
46
+
47
+ ```yaml
48
+ - id: skillre-sticky-wall
49
+ name: '@skillre/dsh-plugin-sticky-wall'
50
+ config:
51
+ maxNotes: 400
52
+ enableAgentTool: true
53
+ seedWelcomeNote: true
54
+ ```
55
+
56
+ | 键 | 默认 | 含义 |
57
+ |---|---|---|
58
+ | `maxNotes` | `400` | 未归档便签的数量上限(1–5000)。新建、取消归档、批量恢复都受此约束,超出时返回 `sticky-wall/wall-full`,需先归档或删除。 |
59
+ | `enableAgentTool` | `true` | 是否向模型注册 `sticky_wall` 工具。 |
60
+ | `seedWelcomeNote` | `true` | 全新的空墙是否写入一张欢迎便签(说明快捷键与用法)。 |
61
+
62
+ ## 安装
63
+
64
+ 开发与测试完成后,**由用户本人**在 DSH Desktop Client 或 Web UI 的 **Plugins / 插件管理**界面选择来源并确认安装、启用,开发者或 agent 不在用户 profile 中代装。
65
+
66
+ - **已加入插件市场**:在 **Plugins → Discover → Index sources** 添加 `https://skillre.github.io/dsh-plugin-market/index.json`(需先启用实验包 *Custom plugin markets*),然后在 Discover 里直接安装本插件。
67
+ - **npm(推荐,也是唯一支持原地更新的来源)**:在安装对话框输入 npm 包规格 `@skillre/dsh-plugin-sticky-wall@<version>`。
68
+ - 未发布时:可提供已构建产物的 `.tgz` 绝对路径,前提是先核实该管理器接受此来源且包可安装。
69
+ - 本仓库是**自包含**的 Git 源:`lib/` 构建产物已提交,且不声明 `scripts.prepare`,因此安装不触发构建脚本。对应的固定 spec 形如 `git+https://github.com/skillre/dsh-plugin-sticky-wall.git#<commit>`,已实测可安装。
70
+
71
+ ## 更新与回滚
72
+
73
+ DSH `0.2.2` 线起,插件页有官方的**版本**区块(`listVersions` / `updateBundle`),可以原地检查并更新。
74
+ 能否走这条路,**只取决于安装来源和包内容**,与仓库配置无关:
75
+
76
+ | 安装来源 | 能原地更新吗 |
77
+ |---|---|
78
+ | npm registry(`@skillre/dsh-plugin-sticky-wall@<version>`) | ✅ 详情页出现「版本」区块,可检查更新并原地升级 |
79
+ | `git+https://…#<commit>`(本仓库的市场条目) | ❌ 没有「版本」区块,只能卸载后重装 |
80
+ | `.tgz` 本地文件 / `file:` | ❌ 同上 |
81
+
82
+ 本插件的 `updatable` 条件全部满足:第三方 bundle、以自己包名保存的 registry spec、合法 SemVer、
83
+ 不携带 `@deepseek-ai/dsh-plugin-manager` 等受保护的插件管理行。**因此想获得官方更新能力,请用 npm 包名安装。**
84
+
85
+ 更新语义(如实记录,避免误期):
86
+
87
+ - **只升不降**:界面不会提供比已装版本更旧的版本;
88
+ - 更新成功后 profile 依赖被写成**精确版本**(原本是 range 也会变成精确版),失败回装同理;
89
+ - 更新 = 先移除再安装两步,HMR 下回装的 bundle 可能排到 bundle 列表末尾,改变配置层顺序;
90
+ - 失败可恢复:装不上/取消/起不来会回装原版本;回装也失败则该包处于未安装状态;
91
+ - 新版本若需要新的 build-script 批准会失败并回装旧版;
92
+ - 版本豁免(`allow-version`)只有 CLI 与 agent 工具,插件页没有入口。
93
+
94
+ - **回滚**:npm 版本不可覆盖。故障版本用 `npm deprecate` 标记并发布新的修复版本;用户在插件管理界面
95
+ 移除故障 bundle 后重装已知可用的版本(若界面不支持指定旧版,需由用户决定恢复渠道)。
96
+ - **数据兼容**:数据域带 `version` 字段,向后兼容只发生在同版本。跨版本降级前先备份
97
+ `$DSH_HOME/storages` 下的该域目录。画布摆位是本版本新增的可选字段,旧便签读入时 `layout` 为
98
+ `null`,由界面按 id 推导一个预览位置,因此**降级不会因为缺字段而报错**。
99
+ - **卸载**:见 [UNINSTALL.md](UNINSTALL.md)。卸载插件**不会**自动删除便签数据。
100
+
101
+ ## 显示元数据(插件卡片与详情页)
102
+
103
+ DSH 读取插件卡片与详情页时**不激活插件**,所以这些资源必须随包发布,且分三层:
104
+
105
+ | 层 | 文件 | 内容 |
106
+ |---|---|---|
107
+ | 卡片标题/副标题 | `locale/en.json`、`locale/zh.json` 的 `meta.title` / `meta.description` | 一行,≤ 120 字符,纯文本 |
108
+ | 详情页 | `meta.detail` → `docs/DETAIL.md` / `docs/DETAIL.zh.md` | **只有一行** `![alt](preview*.svg)` |
109
+ | 开发者文档 | `README.md` / `README.en.md`(本文件) | 安装、配置、兼容性、限制…… |
110
+
111
+ - `locale/*.json` 经 Node ESM resolver 解析,因此 `exports` 必须声明 `"./locale/*.json"`;缺这一条会抛
112
+ `ERR_PACKAGE_PATH_NOT_EXPORTED`,而 DSH 会**静默吞掉**该错误,卡片退化成裸包名 —— 没有任何地方会报错。
113
+ - `meta.detail` 是 DSH `0.2.2` 新增的字段,指向包内相对路径的 Markdown,由 DSH 从**包目录**直接读(不走 exports),
114
+ 所以 `files` 必须包含 `docs`。缺 `meta.detail` 时 DSH 回退到 `README.md` —— 也就是把这份开发者手册塞进详情页,
115
+ 这正是本版本要修掉的问题。
116
+ - 详情页图片:`docs/preview.svg`(英文)与 `docs/preview.zh.svg`(中文),固定 640×300 逻辑比例(本仓库用 1280×600)。
117
+ 规则见 fleet 的 `docs/display-contract.md`,画板记录在 [docs/PREVIEW.md](docs/PREVIEW.md)。
118
+
119
+ ```sh
120
+ node scripts/preview.mjs check # 离线校验预览图与 locale 元数据(npm run check 会自动跑)
121
+ ```
122
+
123
+ ## 插件市场
124
+
125
+ 本插件已发布到由本舰队生成的插件市场索引:
126
+
127
+ - 索引:`https://skillre.github.io/dsh-plugin-market/index.json`
128
+ - 条目:`@skillre/dsh-plugin-sticky-wall@0.1.2`,来源为 commit-pinned Git(`83c932f`)
129
+ - 图标:`https://skillre.github.io/dsh-plugin-market/icons/sticky-wall.svg`
130
+
131
+ 安装路径已实测:从线上索引取 spec → 装进隔离 profile → `--dump-config` → 有界启动 → 路由可用(证据见 `docs/evidence/market-install-0.1.2.json`)。
132
+
133
+ ## 已知限制
134
+
135
+ - 便签墙是速记板:正文上限 4000 字符、标题 120 字符、标签 8 个,均为硬限制。
136
+ - **Markdown 是刻意的子集**,不是完整 CommonMark:支持标题(`#`–`####`)、段落与换行、粗体/斜体/删除线、
137
+ 行内 `` `code` ``、`` ``` ``/`~~~` 代码块、有序/无序列表、`- [ ]` 复选、引用、分隔线、管道表格、
138
+ http(s)/mailto 链接。**不支持**嵌套列表缩进、图片、脚注、任务列表交互(复选框是只读字形)。
139
+ - 正文里的**原始 HTML 一律当文本显示**,不会执行也不会渲染 —— 这是安全选择,不是缺陷。
140
+ - 卡片宽度只有小/中/大**三档预设**,不支持任意拖拽调整宽度;旋转角在拖动时归零,整理时会重新加回轻微角度。
141
+ - 画布是二维平面:没有分组、图层、连线或吸附对齐。
142
+ - 便签的位置由 Host 保存;同一面墙在两个窗口同时打开时,各自渲染自己的快照,不会实时推送另一个窗口的拖动结果。
143
+ - 归档便签不占 `maxNotes` 名额,但恢复它们会占名额;名额已满时恢复会被拒绝而不是悄悄超限。
144
+ - 「清空归档」是永久删除,不可撤销。
145
+ - 批量归档/删除要么全部生效,要么一条都不改:请求里含一个不存在的 id 时整批被拒绝。
146
+ - 多窗口同时打开时会各自拉取快照;Host 是唯一事实源,但界面不会实时推送其他窗口的改动。
147
+ - 本版本仅在 DSH `0.2.1-rc.5` 上做过真实挂载验证,未宣称兼容其他 DSH 版本。
148
+
149
+ ## 兼容性
150
+
151
+ 见 [compatibility.json](compatibility.json):记录真实挂载过的 DSH 版本、验证日期与检查项。`engines.dsh` 只是安装声明,**不是**兼容性证据。
152
+
153
+ ## 开发
154
+
155
+ ```sh
156
+ npm install
157
+ npm run check # typecheck + 测试 + 打包视图
158
+ npm pack # 生成可安装的 tarball
159
+ ```
160
+
161
+ 包内容:`lib/`(Host 与 Client 构建产物及声明)、`cordis.patch.yml`、`compatibility.json`、`locale/*.json`、`icon.svg`、文档与许可证。
162
+
163
+ ## 许可
164
+
165
+ MIT
package/UNINSTALL.md ADDED
@@ -0,0 +1,26 @@
1
+ # Uninstall and rollback
2
+
3
+ The user removes this bundle in their DSH Desktop Client or Web UI **Plugins** manager. To roll back, the user removes the faulty version and chooses a verified known-good package/version in that manager, if supported. Neither an agent nor a developer uninstalls preexisting user bundles or installs the replacement for them.
4
+
5
+ ## What removal does and does not touch
6
+
7
+ Removing the package removes its bundle layer, so the sidebar entry, the wall page, the `/api/skillre-sticky-wall/execute` route and the optional `sticky_wall` tool all disappear with it. **Note data is not removed.**
8
+
9
+ - The notes live in the storage domain `skillre_sticky_wall`, which the profile's storage backend owns. For the shipped profile this is a directory under `$DSH_HOME/storages`; the exact path is decided by the `storage-json` row's `root` and the domain's own directory naming.
10
+ - Reinstalling the same version reuses that data, because the domain name and version are unchanged.
11
+ - A user who wants the data gone can remove that domain directory while DSH is stopped. That is a user action, and it is irreversible — back it up first if the notes might matter.
12
+ - Because a reinstall resolves the same domain name, deleting the directory while DSH is running is not supported: stop the app, delete, then start again.
13
+
14
+ ## Rollback across versions
15
+
16
+ The domain declares `version: 1`. A downgrade to a build that declares a different version fails loudly at domain open (`version-mismatch` from the storage backend) instead of silently rewriting notes. Before downgrading, copy the domain directory so the previous notes can be restored.
17
+
18
+ ## Temporary development installs
19
+
20
+ Temporary tests use a different rule: stop the test process; remove only the test-created bundle/dependency/selection/config or the confirmed owned isolated non-Desktop profile; verify the test state is absent. If an actual user profile was used with prior approval, preserve its baseline installations and data and report any residue that could not be restored.
21
+
22
+ If the interface cannot start, arrange user-authorized recovery through the applicable CLI/profile recovery procedure; do not assume Electron's `desktop` profile can be operated with CLI `--profile desktop`. Removing the package removes its bundle layer.
23
+
24
+ ## Leftover files an installed build can leave behind
25
+
26
+ None by design. The plugin writes no file of its own outside the storage domain, registers no timer, and holds no process. The one residue worth knowing is the note data described above, which deliberately outlives the plugin.
@@ -0,0 +1,83 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "package": "@skillre/dsh-plugin-sticky-wall",
4
+ "verified": [
5
+ {
6
+ "dsh": "0.2.2-rc.1",
7
+ "verifiedAt": "2026-11-06",
8
+ "result": "passed",
9
+ "checks": [
10
+ "dump-config",
11
+ "bounded-startup",
12
+ "packed-install",
13
+ "api-list",
14
+ "api-create",
15
+ "api-update",
16
+ "api-move",
17
+ "api-move-clamped",
18
+ "api-move-bounds",
19
+ "api-arrange",
20
+ "api-archive",
21
+ "api-archive-hides-note",
22
+ "api-archive-batch-atomic",
23
+ "api-delete",
24
+ "api-delete-batch-atomic",
25
+ "api-auth-fence",
26
+ "api-error-no-internal-leak",
27
+ "storage-persistence-across-restart",
28
+ "storage-persistence-layout",
29
+ "fiber-cleanup",
30
+ "browser",
31
+ "zh-locale",
32
+ "browser-canvas-drag",
33
+ "browser-canvas-arrange",
34
+ "browser-tidy-no-overlap",
35
+ "browser-drag-keeps-rotation",
36
+ "browser-markdown",
37
+ "browser-view-modes",
38
+ "browser-theme-switch",
39
+ "display-detail-image",
40
+ "display-locale-detail"
41
+ ],
42
+ "notes": "Packed tarball 0.2.0 installed into an owned, disposable, non-Desktop web profile created from the shipped template (DSH 0.2.2-rc.1). dsh --profile <test> --dump-config composed the bundle row; a bounded real startup served the Web app; the authenticated browser transport exercised the exact /api/skillre-sticky-wall/execute route: list, create, update, move (placement echoed back without bumping updatedAt), an out-of-bounds move CLAMPED into the world while a non-finite one is refused as sticky-wall/bad-request, arrange, archive, delete, plus storage persistence of both the note and its canvas placement across a full restart, and an unauthenticated request returning 401. Cleanup stopped every owned process, removed the owned profile root and verified it was gone. The real DSH Web UI was then driven in headless Chromium against a FRESH owned profile: the 便签墙 sidebar entry appeared and selected the panel (the shell's own preview-notice mask was dismissed first, otherwise it swallows pointer input), the wall mounted with the seeded welcome note, the composer created a note whose Markdown body rendered as strong/code/list elements with no literal markers left, pin moved it first, search filtered to it, archive hid it from the default wall, the archived toggle showed it again, the note survived a full page reload, canvas cards were absolutely positioned from stored layouts, a real pointer drag wrote a new placement through the Host, 整理 repacked the wall and left NO overlapping cards, grid and list views rendered the same note set, and the note palette switched between light and dark. 24/24 UI assertions passed with no uncaught errors. Cleanup stopped the harness, killed Chrome, removed both the owned profile and the Chrome scratch directory, and verified they were gone. The display contract was verified offline: meta.detail resolves to docs/DETAIL*.md, each carries exactly one banner image at the 640x300 ratio, and both SVGs render (evidence PNGs committed). Two real defects were found and fixed during this verification: card heights were under-estimated for CJK text (so the tidy pass overlapped cards), and arrange packed only the live set (so an archived visible card stayed on top of tidied ones). A post-review pass fixed four defects the independent review found and proved each with a test that fails when the fix is reverted: (1) the height estimate charged a long title a flat 1.4 lines, so a 120-char CJK title estimated 104px against a rendered ~244px and tidy overlapped; the title and tag pills are now measured by columns. (2) The packer silently clamped cards past the world coordinate limit, pinning hundreds to one edge; the shelf width now scales with the wall and a 300-card worst case is asserted overlap-free. (3) Every drag wrote rotate: 0, destroying the tilt tidy applied; the drag now carries rotation through and the UI harness asserts it. (4) Derived preview positions were indexed off the filtered list, so legacy notes jumped while typing in the search box; the index now comes from the unfiltered snapshot. Rotation is also budgeted into the shelf gap, and the transport clamps instead of rejecting an out-of-bounds drag. 0.2.1 makes the drag direct: the canvas card no longer transitions its transform (which turned every per-frame write into an animation target and made the card trail the pointer), the drag flag moved from React state to a node attribute so pressing no longer re-renders the wall, pointer moves are coalesced into one write per animation frame, the pointer loop is registered once instead of per press, and the hover lift no longer overwrites the drag transform on the canvas. The UI harness caught a regression in that rewrite (the drop cleared the inline transform and stripped the card's tilt) and the fix is covered by a test.",
43
+ "evidence": [
44
+ "docs/evidence/isolated-mount-0.2.1.json",
45
+ "docs/evidence/market-install-0.2.1.json",
46
+ "docs/evidence/ui-verification.json",
47
+ "docs/evidence/preview-banner-en-0.1.3.png",
48
+ "docs/evidence/preview-banner-zh-0.1.3.png",
49
+ "docs/evidence/sticky-wall-canvas.png",
50
+ "docs/evidence/sticky-wall-light.png",
51
+ "docs/evidence/sticky-wall-dark.png",
52
+ "tests/store.spec.ts",
53
+ "tests/transport.spec.ts",
54
+ "tests/plugin.spec.ts",
55
+ "tests/client-bundle.spec.ts",
56
+ "tests/view.spec.tsx",
57
+ "tests/layout.spec.ts",
58
+ "tests/markdown.spec.tsx"
59
+ ]
60
+ }
61
+ ],
62
+ "observations": [
63
+ {
64
+ "dsh": "0.2.2-rc.1",
65
+ "observedAt": "2026-11-06",
66
+ "install": "packed tarball installed into an owned, disposable, non-Desktop DSH web profile",
67
+ "checks": [
68
+ "artifact-envelope",
69
+ "host-contracts",
70
+ "packed-payload-bytes"
71
+ ],
72
+ "evidence": {
73
+ "artifact-envelope": "tests/client-bundle.spec.ts loads lib/client.js through window.__ModuleLoader__.load and asserts one registration, only the seeded react modules, the Cordis client contract and both slot registrations",
74
+ "host-contracts": "tests/transport.spec.ts drives the exact Fetch route with real Request objects; tests/store.spec.ts covers the domain-backed store; tests/plugin.spec.ts covers config resolution and Fiber-scoped lifetime",
75
+ "packed-payload-bytes": "scripts/verify-isolated.mjs checks every required packed file exists in the installed package under the owned profile root"
76
+ },
77
+ "pending": [
78
+ "desktop-client"
79
+ ],
80
+ "pendingDetail": "Verified in the standalone DSH Web application. The Desktop Client (Electron) was not exercised: its profile is managed by the application and cannot be driven by this CLI-based harness. A Desktop-targeted release must repeat the visual check there."
81
+ }
82
+ ]
83
+ }
@@ -0,0 +1,10 @@
1
+ # One Host row for this bundle: it owns the durable note table (storage domain)
2
+ # and the exact Connection route the sidebar panel renders from, and the Client
3
+ # half of the same package registers the sidebar entry and the wall page.
4
+ #
5
+ # The user's profile may override this row's configuration (see README); every
6
+ # key is optional and schema-validated at mount time.
7
+ - insert:
8
+ - id: skillre-sticky-wall
9
+ name: '@skillre/dsh-plugin-sticky-wall'
10
+ config: {}
package/docs/DETAIL.md ADDED
@@ -0,0 +1 @@
1
+ ![The sticky wall inside DSH: a dark canvas scattered with pastel note cards of different sizes and angles, a sidebar entry, a search toolbar and a floating zoom control](preview.svg)
@@ -0,0 +1 @@
1
+ ![便签墙在 DSH 中的样子:深色画布上散布着大小、角度各异的彩色便签,左侧栏入口、搜索工具栏与悬浮缩放控件](preview.zh.svg)
@@ -0,0 +1,39 @@
1
+ # 预览图画板
2
+
3
+ 详情页的预览图以**飞书画板**为编辑源,`docs/preview*.svg` 是它的导出快照。
4
+ 本文件记录两种语言各自对应的画板,供 `node scripts/preview.mjs push|pull` 使用。
5
+
6
+ > 状态:当前 `docs/preview.svg` 与 `docs/preview.zh.svg` 由手写 SVG 直接绘制,
7
+ > 尚未回填到飞书画板。下表的 token 为空即表示「尚未建板」;建板后用 `push` 上传,
8
+ > 再把文档 URL 与 token 填回来,此后改图走 `pull` / `push` 往返。
9
+
10
+ | 语言 | 文档 | 画板 token |
11
+ |---|---|---|
12
+ | `en` | (待建:飞书文档 URL) | (待建:whiteboard token) |
13
+ | `zh` | (待建:飞书文档 URL) | (待建:whiteboard token) |
14
+
15
+ ## 操作
16
+
17
+ ```sh
18
+ # 把本地 SVG 推上画板(整板重建)
19
+ node scripts/preview.mjs push --lang zh
20
+
21
+ # 从画板导出 SVG 覆盖本地文件
22
+ node scripts/preview.mjs pull --lang zh
23
+
24
+ # 离线校验(npm run check 会自动调用)
25
+ node scripts/preview.mjs check
26
+ ```
27
+
28
+ ## 画面约定
29
+
30
+ 两张图必须同构,只换语言:
31
+
32
+ 1. **主体**:深色画布上散落 7–9 张大小、角度不同的便签卡(六色柔和底色之一),
33
+ 卡片之间刻意不排成网格 —— 这正是「自由画布」与旧版瀑布流的区别。
34
+ 2. **机制**:卡内正文展示 Markdown 的真实渲染结果 —— 标题、粗体、列表、
35
+ 代码块、复选清单各出现一次,说明「正文即 Markdown」。
36
+ 3. **界面**:左侧栏入口、顶部搜索框与筛选 chip、画布左下角悬浮缩放控件。
37
+ 4. **细节**:置顶卡的左侧色条与星标;一张卡带拖拽提示(虚线框或光标)。
38
+
39
+ 规则见 fleet 的 `docs/display-contract.md`。