dsh-plugin-deck-studio 0.2.6 → 0.2.9

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.
Files changed (53) hide show
  1. package/cordis.example.yml +85 -7
  2. package/cordis.patch.yml +78 -7
  3. package/index.js +367 -27
  4. package/lib/capabilities.js +234 -0
  5. package/lib/citation-check.js +93 -0
  6. package/lib/config.js +27 -0
  7. package/lib/deck-brief.js +35 -1
  8. package/lib/deck-docs.js +45 -7
  9. package/lib/deck-templates.js +8 -1
  10. package/lib/deck-workspace.js +27 -1
  11. package/lib/designs.js +15 -0
  12. package/lib/fact-labels.js +81 -0
  13. package/lib/first-draft.js +119 -0
  14. package/lib/image-review.js +523 -0
  15. package/lib/page-contract.js +112 -0
  16. package/lib/proposal-decision.js +249 -75
  17. package/lib/render.js +101 -10
  18. package/lib/review-agent.js +1 -1
  19. package/lib/review-personas.js +49 -2
  20. package/lib/review-protocol.js +411 -0
  21. package/lib/review-readers.js +300 -0
  22. package/lib/review-score.js +198 -0
  23. package/lib/title-chain.js +122 -0
  24. package/lib/tools.js +973 -78
  25. package/lib/update-check.js +166 -0
  26. package/package.json +12 -11
  27. package/seeds/docs/assets/screenshots/f186-01-agent-style-create.png +0 -0
  28. package/seeds/docs/assets/screenshots/f186-02-designs-card.png +0 -0
  29. package/seeds/docs/assets/screenshots/f187-01-review-readers.png +0 -0
  30. package/seeds/docs/assets/screenshots/f187-02-gap-report.png +0 -0
  31. package/seeds/docs/assets/screenshots/f188-01-header-buttons.png +0 -0
  32. package/seeds/docs/assets/screenshots/f188-02-update-toast.png +0 -0
  33. package/seeds/docs/assets/screenshots/f188-03-review-doc-tabs.png +0 -0
  34. package/seeds/docs/assets/screenshots/f188-04-script-doc-nochips.png +0 -0
  35. package/seeds/docs/assets/screenshots/i14-01-create.png +0 -0
  36. package/seeds/docs/assets/screenshots/i14-02-first-draft.png +0 -0
  37. package/seeds/docs/assets/screenshots/i14-03-rendered.png +0 -0
  38. package/seeds/docs/assets/screenshots/i14-04-image-review.png +0 -0
  39. package/seeds/docs/assets/screenshots/i14-05-p01-page.png +0 -0
  40. package/seeds/docs/install.en.md +13 -3
  41. package/seeds/docs/install.md +13 -4
  42. package/seeds/docs/manual.en.md +17 -0
  43. package/seeds/docs/manual.md +17 -0
  44. package/seeds/docs/sample-deck.en.md +1 -1
  45. package/seeds/docs/sample-deck.md +1 -1
  46. package/seeds/docs/styles.en.md +2 -1
  47. package/seeds/docs/styles.md +14 -4
  48. package/seeds/samples/DSA-01.jpg +0 -0
  49. package/seeds/samples/DSA-02.jpg +0 -0
  50. package/seeds/samples/DSA-03.jpg +0 -0
  51. package/seeds/styles/DSA.json +22 -0
  52. package/ui/workbench.css +25 -3
  53. package/ui/workbench.html +286 -10
@@ -0,0 +1,166 @@
1
+ /**
2
+ * 插件自更新:版本比较 + 安装方式判断 + 更新命令(F-188)。
3
+ *
4
+ * 背景:插件装好之后没有「检查更新 / 一键更新」入口,用户只能自己去终端 `dsh plugin add`。
5
+ * 工作台顶栏给一个刷新按钮(有新版时带小圆点),点了能看版本差异并直接更新;旁边是仓库入口(提 issue)。
6
+ *
7
+ * 纪律:
8
+ * - **只在 npm 安装模式下执行更新**;本机 `link:` / `file:` 开发安装一律拒绝执行,只解释原因
9
+ * (开发树里跑 pnpm add 会把本地 link 换成 registry 版本,把人正在改的代码顶掉)。
10
+ * - 更新只改 profile 里的依赖,**不改运行中的进程**:跑完提示重启 DSH 才生效。
11
+ * - 版本比较按 semver 的「主.次.补 + 预发」做,不引第三方依赖。
12
+ *
13
+ * @module dsh-plugin-deck-studio/update-check
14
+ */
15
+
16
+
17
+ const clamp = (value) => String(value ?? "").trim();
18
+
19
+ /** 解析 "1.2.3-rc.4" → { main:[1,2,3], pre:["rc","4"] };非法返回 null。 */
20
+ export function parseVersion(raw) {
21
+ const text = clamp(raw).replace(/^v/i, "");
22
+ const match = text.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
23
+ if (!match) return null;
24
+ return {
25
+ main: [Number(match[1]), Number(match[2]), Number(match[3])],
26
+ pre: match[4] ? match[4].split(".") : [],
27
+ };
28
+ }
29
+
30
+ /** semver 优先级比较:a>b 返回 1,a<b 返回 -1,相等 0(含预发版规则)。非法版本抛错。 */
31
+ export function compareVersions(a, b) {
32
+ const left = parseVersion(a);
33
+ const right = parseVersion(b);
34
+ if (!left) throw new Error(`版本号不合法:${a}`);
35
+ if (!right) throw new Error(`版本号不合法:${b}`);
36
+ for (let i = 0; i < 3; i += 1) {
37
+ if (left.main[i] !== right.main[i]) return left.main[i] > right.main[i] ? 1 : -1;
38
+ }
39
+ // 有预发标记的版本低于同号正式版(0.3.0-rc.1 < 0.3.0)
40
+ if (!left.pre.length && !right.pre.length) return 0;
41
+ if (!left.pre.length) return 1;
42
+ if (!right.pre.length) return -1;
43
+ const size = Math.max(left.pre.length, right.pre.length);
44
+ for (let i = 0; i < size; i += 1) {
45
+ const x = left.pre[i];
46
+ const y = right.pre[i];
47
+ if (x === undefined) return -1;
48
+ if (y === undefined) return 1;
49
+ if (x === y) continue;
50
+ const xn = /^\d+$/.test(x);
51
+ const yn = /^\d+$/.test(y);
52
+ if (xn && yn) return Number(x) > Number(y) ? 1 : -1;
53
+ if (xn) return -1; // 数字标识符优先级低于字母
54
+ if (yn) return 1;
55
+ return x > y ? 1 : -1;
56
+ }
57
+ return 0;
58
+ }
59
+
60
+ /** latest 比 current 新才返回 true;任一版本号非法时返回 false(宁可不动)。 */
61
+ export function isNewer(latest, current) {
62
+ try {
63
+ return compareVersions(latest, current) > 0;
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ /** 从 registry 的 packument / version 文档里取 latest 版本(兼容 dist-tags 与单版本文档)。 */
70
+ export function latestFromRegistry(payload) {
71
+ if (!payload || typeof payload !== "object") return "";
72
+ const tagged = clamp(payload["dist-tags"]?.latest);
73
+ if (tagged && parseVersion(tagged)) return tagged; // 坏 tag("abc")不许当版本
74
+ const single = clamp(payload.version);
75
+ return parseVersion(single) ? single : "";
76
+ }
77
+
78
+ /**
79
+ * 判断插件是怎么装进 profile 的:
80
+ * - `linked`:`link:` / `file:` / `portal:` 等本地路径 —— 开发模式,更新走 git,不执行 pnpm
81
+ * - `npm`:semver 版本(或 `^` / `~` / `latest` 等 tag)—— 可以 `pnpm add <pkg>@latest`
82
+ * - `unknown`:找不到 profile 或依赖缺失
83
+ */
84
+ export function installModeOf({ profileDir = "", packageName = "" } = {}) {
85
+ if (!profileDir || !packageName) return { mode: "unknown", spec: "", reason: "拿不到 profile 目录或包名" };
86
+ let pkg;
87
+ try {
88
+ pkg = JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8"));
89
+ } catch {
90
+ return { mode: "unknown", spec: "", reason: `读不到 ${join(profileDir, "package.json")}` };
91
+ }
92
+ const spec = clamp(pkg?.dependencies?.[packageName]);
93
+ if (!spec) return { mode: "unknown", spec: "", reason: `profile 的 dependencies 里没有 ${packageName}` };
94
+ if (/^(link|file|portal|workspace):/i.test(spec) || spec.startsWith(".") || spec.startsWith("/")) {
95
+ return { mode: "linked", spec, reason: "本机是开发链接安装(link:/file:),更新走仓库,不在界面里执行" };
96
+ }
97
+ return { mode: "npm", spec, reason: "" };
98
+ }
99
+
100
+ /**
101
+ * 找出插件所在的 profile 目录(更新命令要在那里跑 pnpm):
102
+ * 1. 从插件真实路径往上走,哪一级 package.json 的 dependencies 声明了这个包,哪一级就是 profile
103
+ * —— npm 布局下插件在 `<profile>/node_modules/<pkg>`,这一条就够,不依赖 env;
104
+ * 2. 退而用 env.DSH_PROFILE_DIR(DSH 启动时注入),要求它确实声明了这个依赖;
105
+ * 3. 都没有返回 ""(界面只解释、不执行)。
106
+ */
107
+ export function detectProfileDir({ pluginDir = "", packageName = "", env = {} } = {}) {
108
+ if (!pluginDir || !packageName) return "";
109
+ const declares = (dir) => {
110
+ try {
111
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
112
+ return Boolean(pkg?.dependencies?.[packageName]);
113
+ } catch {
114
+ return false;
115
+ }
116
+ };
117
+ let dir = "";
118
+ try {
119
+ dir = realpathSync(pluginDir);
120
+ } catch {
121
+ dir = pluginDir;
122
+ }
123
+ // 逐级向上(最多 6 层,避免走到磁盘根)
124
+ for (let depth = 0; depth < 6; depth += 1) {
125
+ const parent = dirname(dir);
126
+ if (parent === dir) break;
127
+ if (declares(parent)) return parent;
128
+ dir = parent;
129
+ }
130
+ const hinted = clamp(env?.DSH_PROFILE_DIR);
131
+ if (hinted && declares(hinted)) return hinted;
132
+ // 开发链接安装:插件不在 profile 里,扫 DSH_HOME/profiles/*,挑一个确实声明了依赖的
133
+ const root = clamp(env?.DSH_HOME) ? join(clamp(env?.DSH_HOME), "profiles") : "";
134
+ if (root) {
135
+ try {
136
+ const candidates = readdirSync(root)
137
+ .map((entry) => join(root, entry))
138
+ .filter((dir) => declares(dir));
139
+ if (candidates.length) {
140
+ const named = env?.DSH_PROFILE ? candidates.find((dir) => dir.endsWith(`/${env.DSH_PROFILE}`)) : null;
141
+ return named ?? candidates[0];
142
+ }
143
+ } catch {
144
+ /* profiles 目录不存在就算了 */
145
+ }
146
+ }
147
+ return "";
148
+ }
149
+
150
+ /** 插件包里仓库相关链接(用于顶栏「GitHub」按钮);没有就留空。 */
151
+ export function repoLinksOf(packageJson = {}) {
152
+ const repo = packageJson.repository;
153
+ const raw = typeof repo === "string" ? repo : clamp(repo?.url);
154
+ const url = raw
155
+ .replace(/^git\+/, "")
156
+ .replace(/^git@github\.com:/, "https://github.com/")
157
+ .replace(/\.git$/, "");
158
+ const homepage = clamp(packageJson.homepage) || url;
159
+ const bugs = typeof packageJson.bugs === "string" ? packageJson.bugs : clamp(packageJson.bugs?.url);
160
+ const issues = bugs ? bugs.replace(/\/+$/, "") : url ? `${url}/issues` : "";
161
+ const suggest = issues.endsWith("/issues") ? `${issues}/new/choose` : url ? `${url}/issues/new/choose` : "";
162
+ return { repo: url, homepage, issues, suggest };
163
+ }
164
+
165
+ import { readFileSync, readdirSync, realpathSync } from "node:fs";
166
+ import { dirname, join } from "node:path";
package/package.json CHANGED
@@ -1,14 +1,24 @@
1
1
  {
2
2
  "name": "dsh-plugin-deck-studio",
3
- "version": "0.2.6",
4
- "private": false,
3
+ "version": "0.2.9",
5
4
  "description": "Deckline:DSH 的 image deck / PPT 工作台插件——原生 Chat + 整页图片 deck 工作区 + 设计风格库;用对话做 PPT、按页出图、版本可追踪、导出 PDF/PPTX。",
5
+ "homepage": "https://github.com/yuna78/dsh-deck-studio#readme",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/yuna78/dsh-deck-studio.git",
9
+ "directory": "plugin/deck-studio"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/yuna78/dsh-deck-studio/issues"
13
+ },
14
+ "private": false,
6
15
  "license": "MIT",
7
16
  "type": "module",
8
17
  "main": "./index.js",
9
18
  "exports": {
10
19
  ".": "./index.js",
11
20
  "./client": "./client.js",
21
+ "./capabilities": "./lib/capabilities.js",
12
22
  "./package.json": "./package.json"
13
23
  },
14
24
  "keywords": [
@@ -51,15 +61,6 @@
51
61
  ]
52
62
  }
53
63
  },
54
- "repository": {
55
- "type": "git",
56
- "url": "git+https://github.com/yuna78/dsh-deck-studio.git",
57
- "directory": "plugin/deck-studio"
58
- },
59
- "homepage": "https://github.com/yuna78/dsh-deck-studio#readme",
60
- "bugs": {
61
- "url": "https://github.com/yuna78/dsh-deck-studio/issues"
62
- },
63
64
  "peerDependencies": {
64
65
  "@deepseek-ai/dsh": ">=0.2.1-rc.2 <0.3.0"
65
66
  },
@@ -6,7 +6,17 @@ assets / conversations on the right. It is not a standalone app — it runs on a
6
6
 
7
7
  > Target users: people who build content and presentations with DSH. After setup you can edit a deck
8
8
  > from its script, render slide images on request (single page or a named batch), manage governance documents, register your own
9
- > design styles (with sample images) and start from 8 preset styles.
9
+ > design styles (with sample images) and start from 9 preset styles.
10
+
11
+ ## Assistant capabilities (0.2.7+)
12
+
13
+ The Deckline preset explicitly mounts Web search/fetch, scoped file/image reading and search, scratch-file write/edit, a read-only research subagent, questions, todos, file delivery, time context and compaction. No shell, arbitrary-preset delegation or developer skills; internal audience reviewers remain tool-free.
14
+
15
+ Search uses the host Web settings. The default DeepSeek backend requires its account/`DEEPSEEK_API_KEY`; a third-party chat key does not configure search. HTTP fetch reads public destinations. Missing credentials must produce an explicit error, not fabricated results.
16
+
17
+ Generic reads are limited to the session workspace and explicit `deck-capabilities.config.readRoots`; secret paths and symlinks are denied. Authorize exact external material paths rather than an entire home directory. DSH image attachments use explicit `attachmentRoots` within its attachment objects subtree, for `read_image` only; this does not authorize the whole DSH directory. Image input also requires a vision-capable model route. Generic writes/edits are restricted to `.deck-assistant-scratch` under the workspace. Formal scripts, intent and revisions must use deck tools. Narrow directory searches to clean material directories if secret/symlink checks reject a broad scan.
18
+
19
+ If a handwritten profile overrides `preset-deck-studio.config.plugins`, merge the capability entries from the updated `cordis.example.yml`, restart and check a new session. Do not mount the whole standard preset or shell as a workaround.
10
20
 
11
21
  ## 0. Prerequisites
12
22
 
@@ -229,9 +239,9 @@ Refresh the page afterwards. png / jpg / webp are supported; names are free-form
229
239
 
230
240
  ### Use preset styles (no prompt writing needed)
231
241
 
232
- **+ Import preset styles** on the Designs page imports all 8 bundled styles (business consulting /
242
+ **+ Import preset styles** on the Designs page imports all 9 bundled styles (business consulting /
233
243
  premium dark / Japanese minimal / magazine editorial / tech blueprint / hand-drawn whiteboard /
234
- Swiss minimal / aurora gradient), each with samples. See [styles.md](styles.md).
244
+ Swiss minimal / aurora gradient / deep-sea amber), each with samples. See [styles.md](styles.md).
235
245
 
236
246
  ## 6. Troubleshooting
237
247
 
@@ -7,7 +7,16 @@ Deckline(`dsh-plugin-deck-studio`)是 DeepSeek Harness(DSH)的 **image d
7
7
  它不是独立 App,必须挂在 DSH 的 profile 上运行。
8
8
 
9
9
  > 目标用户:用 DSH 做内容/演示的人。装完后你可以:读 script 改 deck、按页出图(可点名批量连出)、管理治理文档、
10
- > 登记自己的设计风格(上传样张),并用 8 个预设风格直接开工。
10
+ > 登记自己的设计风格(上传样张),并用 9 个预设风格直接开工。
11
+
12
+ ## 主助手基础能力(0.2.7起)
13
+
14
+ Deckline制作模式显式提供联网搜索/抓取、文件/图片读取与检索、辅助草稿写编辑、只读研究子Agent、提问/待办/文件交付、时间与上下文压缩。不开放shell、任意preset委派或开发技能;内部听众审稿仍零工具。
15
+
16
+ - `web_search`使用DSH宿主的搜索设置;默认DeepSeek后端需相应账户或`DEEPSEEK_API_KEY`。使用第三方LLM key不代表搜索已配置。`web_fetch`默认读取公开HTTP(S)网页。缺凭证/失败明确报错,不能靠加提示词修复。
17
+ - 通用读只允许当前会话工作区与`deck-capabilities.config.readRoots`显式授权路径;秘密文件和symlink拒绝。读取其他资料请在profile精确授权,勿授权整个home;DSH图片附件使用`attachmentRoots`精确授权其objects子树下的图片文件/目录,仅`read_image`可用,不授权整个DSH目录。视觉读取还要求当前模型路由支持image输入。
18
+ - 通用`write/edit`仅限工作区`.deck-assistant-scratch`辅助目录;脚本/意图/版本须用deck工具,不可绕过确认。宽泛目录搜索因秘密文件/链接被拒时缩小到干净资料目录。
19
+ - 手写profile若覆盖`preset-deck-studio.config.plugins`,请合并新版`cordis.example.yml`的基础能力条目,重启后用新会话核对工具。不要把完整标准preset或Bash直接挂进来。
11
20
 
12
21
  ## 0. 前置条件
13
22
 
@@ -285,8 +294,8 @@ export DSH_DECK_IMAGE_API_KEY="sk-…" # 只放在你的 shell / 密钥
285
294
 
286
295
  ### 用预设风格(不用自己写 prompt)
287
296
 
288
- Designs 页 **+ 导入预设风格** 会一次导入 8 个自带风格(商务咨询 / 高端深色 fancy / 日系极简 /
289
- 杂志编辑 / 科技蓝图 / 手绘白板 / 瑞士极简 / 渐变极光),每个都带样张,见 [docs/styles.md](styles.md)。
297
+ Designs 页 **+ 导入预设风格** 会一次导入 9 个自带风格(商务咨询 / 高端深色 fancy / 日系极简 /
298
+ 杂志编辑 / 科技蓝图 / 手绘白板 / 瑞士极简 / 渐变极光 / 深海琥珀),每个都带样张,见 [docs/styles.md](styles.md)。
290
299
 
291
300
  ## 6. 排障
292
301
 
@@ -319,7 +328,7 @@ dsh --profile deck-studio --no-open # 本仓开发 profile(端口
319
328
  | 左侧 DSH 外壳栏(工作区 / 会话) | 收起隐藏,只留 Deckline 导航 | profile 里 `hideShellSidebar: false` |
320
329
  | Decks 页 | 自动登记 **Deckline 示例手册**(仓库 `samples/deckline-intro`,只读) | 配了任意 `decks[]` 就不登记;或 `bootstrap: false` |
321
330
  | 资源库 | 自动拷入品牌素材(logo / mark)到 `<dataRoot>/resources` | 该目录非空时不动;或 `bootstrap: false` |
322
- | Designs 页 | 自动导入 8 个预设风格(含样张) | 已有风格时不重复;或 `bootstrap: false` |
331
+ | Designs 页 | 自动导入 9 个预设风格(含样张) | 已有风格时不重复;或 `bootstrap: false` |
323
332
  | 问候语 / 新 deck 作者 | 首次启动弹「先记个名字」,存 `<dataRoot>/user.json`;首页显示「XX,欢迎你」,新 deck 的 owner / 封面作者默认用它 | 点「稍后」不写;之后可在 profile 里用 `userName` 覆盖 |
324
333
 
325
334
  自举只在「空」的时候发生,重复启动不会覆盖你已有的内容;想彻底关掉,在 profile patch 里给根挂载加
@@ -292,3 +292,20 @@ fabrication, explicit confirmation); suspicious instructions are flagged, never
292
292
  | `exports/` | exported PDF / PPTX / handoff bundles. |
293
293
 
294
294
  `.deck/` and `exports/` are gitignored; the repository only ships code, docs, samples and preset styles.
295
+ ## 13. Updating the plugin & giving feedback
296
+
297
+ Three always-on buttons live in the top-right of the workbench header:
298
+
299
+ | Button | What it does |
300
+ |---|---|
301
+ | **⚙** | Jumps to the settings panel (render node / model / API key source / size); from the home page it returns to the current deck first |
302
+ | **↻ vX.Y.Z** | Checks npm for the latest release: up to date → tells you the version; newer → asks "current vX → vY", then runs `dsh plugin add` for you (restart DSH to apply). A `link:` / `file:` dev install is never auto-updated — it explains to pull the repo instead, so your local link is not replaced by a registry copy |
303
+ | **GitHub** | Opens the repo's new-issue page (feature requests / bug reports) |
304
+
305
+ Command-line equivalent:
306
+
307
+ ```sh
308
+ dsh plugin --profile deckline add dsh-plugin-deck-studio@latest
309
+ ```
310
+
311
+ If npm is unreachable the button says so ("check timed out") instead of hanging.
@@ -256,3 +256,20 @@ key 值只存在本机数据文件里,任何接口都不会回显。
256
256
  | `exports/` | 导出产物(PDF / PPTX / 交接包)。 |
257
257
 
258
258
  `.deck/` 与 `exports/` 都在 `.gitignore` 里;仓库只带代码、文档、示例与预设风格。
259
+ ## 13. 更新插件与反馈
260
+
261
+ 工作台顶栏右上角三个常驻按钮,装好之后不用记命令:
262
+
263
+ | 按钮 | 行为 |
264
+ |---|---|
265
+ | **⚙** | 直接切到右栏「设置」页(出图节点 / 模型 / key 来源 / 尺寸);在首页时先回到当前 deck 再切 |
266
+ | **↻ vX.Y.Z** | 点一下查 npm 最新版:已是最新 → 提示版本号;有新版 → 弹「当前 vX → vY」确认,点「更新」直接跑 `dsh plugin add`,完成后**重启 DSH 生效**;本机 `link:` / `file:` 开发安装只解释「更新走仓库」,不会把本地链接换成 registry 包 |
267
+ | **GitHub** | 打开仓库的「新建 issue」页(提建议 / 报问题) |
268
+
269
+ 命令行的等价写法:
270
+
271
+ ```sh
272
+ dsh plugin --profile deckline add dsh-plugin-deck-studio@latest
273
+ ```
274
+
275
+ 不上网时点 ↻ 会明确提示「检查更新超时:连不上 npm registry」,不会卡住界面。
@@ -44,7 +44,7 @@ Field cheat sheet (copy-paste ready): [`samples/deckline-intro/popup.md`](../sam
44
44
  CHANGELOG.md —— v0.1.0 能力清单与边界
45
45
  docs/productization.md —— 产品化定位、路线图、发布范围、一期边界
46
46
  docs/install.md —— 安装、profile 配置、出图节点与 key 放置、fake 模式
47
- docs/styles.md —— 8 个预设风格 + 自定义风格方法
47
+ docs/styles.md —— 9 个预设风格 + 自定义风格方法
48
48
  docs/sample-deck.md —— 用示例 deck 跑通流程(本页步骤来源)
49
49
 
50
50
  【2. 代码(真实链接)】
@@ -41,7 +41,7 @@
41
41
  CHANGELOG.md —— v0.1.0 能力清单与边界
42
42
  docs/productization.md —— 产品化定位、路线图、发布范围、一期边界
43
43
  docs/install.md —— 安装、profile 配置、出图节点与 key 放置、fake 模式
44
- docs/styles.md —— 8 个预设风格 + 自定义风格方法
44
+ docs/styles.md —— 9 个预设风格 + 自定义风格方法
45
45
  docs/sample-deck.md —— 用示例 deck 跑通流程(本页步骤来源)
46
46
 
47
47
  【2. 代码(真实链接)】
@@ -6,7 +6,7 @@ language for the images.
6
6
 
7
7
  ## 1. Use preset styles (recommended starting point)
8
8
 
9
- Designs page → **+ Import preset styles** imports the 8 styles below in one click (each ships with
9
+ Designs page → **+ Import preset styles** imports the 9 styles below in one click (each ships with
10
10
  3 real baseline samples: cover / info page / data page). It is idempotent — existing abbreviations are
11
11
  skipped, never duplicated.
12
12
 
@@ -20,6 +20,7 @@ skipped, never duplicated.
20
20
  | SKT | Hand-drawn whiteboard (workshop) | Whiteboard + markers + sticky notes + handwritten headings | Workshops, co-creation, training |
21
21
  | SWS | Swiss minimal (black/white/red) | Pure white + oversized black type + true red + generous whitespace | Minimal manifestos, big-type posters |
22
22
  | GRD | Aurora gradient (modern SaaS) | Violet-cyan aurora gradients + glow + 3D abstraction + glass cards | Product launches, internet style |
23
+ | DSA | Deep Sea Amber (deep teal + gold hairlines) | Near-ink teal base + champagne-gold hairlines + serif headlines + generous whitespace | Premium talks, dark narratives, big-type covers |
23
24
 
24
25
  Definitions: `plugin/deck-studio/seeds/styles/<ABBR>.json`; samples:
25
26
  `plugin/deck-studio/seeds/samples/<ABBR>-0{1,2,3}.jpg` (3 baseline samples, 1280-wide previews).
@@ -7,7 +7,7 @@ Agent 出图时会以这份描述作为画面语言的基础。
7
7
 
8
8
  ## 一、用预设风格(推荐先从这里开始)
9
9
 
10
- Designs 页 → **+ 导入预设风格**:一次导入下面 8 个风格(每个都带 3 张真实基线样张:封面 / 信息页 / 数据页),幂等——
10
+ Designs 页 → **+ 导入预设风格**:一次导入下面 9 个风格(每个都带 3 张真实基线样张:封面 / 信息页 / 数据页),幂等——
11
11
  已存在的缩写自动跳过,不会重复创建。
12
12
 
13
13
  | 缩写 | 名称 | 画面语言 | 适合 |
@@ -20,12 +20,22 @@ Designs 页 → **+ 导入预设风格**:一次导入下面 8 个风格(
20
20
  | SKT | 手绘白板(工作坊) | 白板 + 马克笔 + 便签 + 手写标题 | 研讨、共创、培训 |
21
21
  | SWS | 瑞士极简(黑白红) | 纯白 + 超大黑体 + 正红 + 大留白 | 极简宣言、大字报 |
22
22
  | GRD | 渐变极光(深色玻璃 · 编辑感) | 近黑炭底 + 紫青极光丝带 + 玻璃面板 + 香槟金细线 | 深色封面、编辑感信息页 |
23
+ | DSA | 深海琥珀(深青 + 香槟金细线) | 深青近墨底 + 香槟金细线 + 衬线大标题 + 大留白 | 高端分享、深色叙事、封面大标题 |
23
24
 
24
25
  定义文件:`plugin/deck-studio/seeds/styles/<ABBR>.json`;样张:`plugin/deck-studio/seeds/samples/<ABBR>-0{1,2,3}.jpg`
25
26
  (3 张基线样张,1280 宽预览)。导入逻辑幂等:再点一次只会跳过已存在的风格。
26
27
 
27
28
  ## 二、自己加一个风格
28
29
 
30
+ ### 方式 0:普通会话里直接说(F-186,做完才发现风格时最省事)
31
+
32
+ 没先选风格也做了 deck,觉得这套视觉语言想复用?直接在 Deckline 会话里说「这个风格好看,帮我登记一下」:
33
+
34
+ 1. Agent 先读页面实际视觉,写一套风格提示词(颜色 / 材质 / 字体 / 版式);
35
+ 2. `deck_style_create` 建 design(缩写不用你给,自动生成),并把已出图页面的**成品图复制**成样张——默认挑 3 张(封面 / 信息页 / 数据对比页各一,三张才说明风格在各类版面上都成立;不重新出图、不花额度);
36
+ 3. 登记完即可在新建 Deck 时选到,也可以用 `deck_design_bind` 把当前 deck 关联过去;
37
+ 4. 想给已有风格再加样张:让它传 `designId` + `pages` 补(只加样张,不动名称和提示词)。
38
+
29
39
  ### 方式 1:界面里加(可以贴图)
30
40
 
31
41
  1. Designs 页 → **+ 添加风格**;
@@ -59,7 +69,7 @@ Designs 页 → **+ 导入预设风格**:一次导入下面 8 个风格(
59
69
  ```
60
70
 
61
71
  - `styleBrief`:**风格提示词本体**。Agent 出样张时自动带上(`composeSamplePrompt`),只需要再补「这张要试的画面」(brief)。
62
- 预设包里的 8 个风格都已按真实样张补齐;改风格用 `deck_style_update` / 界面「复制」后改。
72
+ 预设包里的 9 个风格都已按真实样张补齐;改风格用 `deck_style_update` / 界面「复制」后改。
63
73
  注意:`reference` 只给人看,不进 image prompt——写机构 / 客户品牌名会触发 image adapter 内容过滤(表现为 180s 超时)。
64
74
  - `baselineBriefs`:预设自带的 3 张基线样张的版面 brief(封面 / 信息页 / 数据页),供重制脚本与「导入预设」使用。
65
75
 
@@ -83,11 +93,11 @@ Designs 页 → **+ 导入预设风格**:一次导入下面 8 个风格(
83
93
 
84
94
  ## 五、预设基线样张(3 张打底)与重制
85
95
 
86
- 8 个预设风格每个都有 3 张基线样张(封面 / 信息页 / 数据页),作用是:**一眼看清这个风格能做成什么样**,
96
+ 9 个预设风格每个都有 3 张基线样张(封面 / 信息页 / 数据页),作用是:**一眼看清这个风格能做成什么样**,
87
97
  同时给 Agent 一个「同风格但不同版面」的参照。重制流程:
88
98
 
89
99
  ```bash
90
- # 8 个预设 × 3 张(1920×1080 出图 → 压 1280 宽 JPEG 回写 seeds/samples)
100
+ # 9 个预设 × 3 张(1920×1080 出图 → 压 1280 宽 JPEG 回写 seeds/samples)
91
101
  node scripts/f74-regenerate-presets.mjs
92
102
  # 只重制一个风格 / 只试一张
93
103
  node scripts/f74-regenerate-presets.mjs --only=BIZ --limit=1
Binary file
Binary file
Binary file
@@ -0,0 +1,22 @@
1
+ {
2
+ "abbr": "DSA",
3
+ "name": "深海琥珀(深青 + 香槟金细线)",
4
+ "description": "深青近墨底 + 香槟金细线 + 衬线中文大标题 + 大面积留白 + 右侧竖排英文小字;信息页用暖米色直角卡片承载要点。克制、单一层次。",
5
+ "constraints": "不要亮色 / 高饱和色块;不要渐变、光晕、玻璃拟态;不要金色填充块或粗金边;不要无衬线做大标题;不要图标堆砌、插画、3D;不要满版密排或多栏密集网格;不要重投影卡片。",
6
+ "reference": "高端分享会 / 深色咨询风(深海青底 + 香槟金细线),非客户素材",
7
+ "styleBrief": "深青(deep teal)近墨底铺满整页,无渐变、无明显纹理,压暗整体明度。香槟金(champagne gold)极细线条只做结构与框定:1px 页边细框、细横线分隔,不用金色填充块、不做粗金边。中文大标题用高对比衬线(宋体系),字重中等偏粗、字号大、行距紧,左对齐,是页面唯一视觉重心;正文用低对比灰青小字,行距舒展。大面积留白不少于 40%,元素集中在左半区或上下角,不做满版密排。英文小字竖排在页面右侧边缘,字号小、字距拉开、自上而下,作版式标注。信息页用暖米色(warm ivory)直角卡片承载要点,无阴影或极弱阴影,卡片内字用深青 / 近黑。整体克制、单一层次,靠留白与细线建立秩序,不靠图标与插画。",
8
+ "baselineBriefs": [
9
+ {
10
+ "title": "封面(深青金线)",
11
+ "brief": "深青近墨底满版铺底,无渐变;1px 香槟金页边细框 + 一条细金横线。左对齐两行中文衬线大标题(第二行略小、含一个金色词或金色细下划线),标题上方一枚加宽字距的金色小标签;右下角一行低对比灰青小字注记与页码;右侧边缘竖排英文小字;留白不少于 40%,不放大图、不放插画。"
12
+ },
13
+ {
14
+ "title": "数据对比页",
15
+ "brief": "深青近墨底 + 金色细框;左上两行中文衬线标题 + 一行灰青小字结论;中部并排两块暖米色直角卡片(各含一个大数字 / 短标签 / 两行说明,数字用深青近黑),两块卡片之间一条金色细竖线分隔,卡片无阴影或极弱阴影;底部细金横线 + 页码;右侧竖排英文小字。"
16
+ },
17
+ {
18
+ "title": "要点 / 决策页",
19
+ "brief": "深青近墨底 + 金色细框;左上中文衬线大标题,下方 3 组要点用细金横线分隔,每组一行加宽字距的小标签 + 两行低对比灰青说明,不用图标、不用色块;右侧竖排英文小字标注;页面下部大面积留白,底部金线 + 页码。"
20
+ }
21
+ ]
22
+ }
package/ui/workbench.css CHANGED
@@ -83,9 +83,19 @@
83
83
  .tool-line.err{border-left-color:#c0533f;background:#faf0ed;color:#8c3a2c;white-space:normal}
84
84
 
85
85
  /* 8 份必备文档(中间区标签) */
86
- .doc-head{display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;margin-bottom:10px}
87
- .doc-head h2{margin:6px 0 0;font-family:"Noto Serif SC",Georgia,serif;font-size:22px;color:var(--ink)}
88
- .doc-head .doc-file{margin-left:auto;color:#8a9599;font-size:10.5px;align-self:center}
86
+ .doc-head{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
87
+ .doc-head-top{display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap}
88
+ .doc-head-top h2{margin:6px 0 0;font-family:"Noto Serif SC",Georgia,serif;font-size:22px;color:var(--ink)}
89
+ .doc-head-side{margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;gap:5px;text-align:right}
90
+ .doc-head .doc-file{color:#8a9599;font-size:10.5px}
91
+ /* F-187:审稿页的相关文件切换(听众读后感 / 意图差距 / 工程口径 …)
92
+ F-188 后续:一轮评审有 5 个 chip,跟标题挤一行会右对齐折成两截,改成独立一行、左对齐。 */
93
+ .doc-head-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:2px}
94
+ .doc-head .doc-files{margin:0;display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-start;max-width:100%}
95
+ .doc-head-extra{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
96
+ .doc-file-chip{border:1px solid #d7dee0;background:#fff;color:#5a6a70;border-radius:999px;padding:3px 10px;font-size:10.5px;cursor:pointer}
97
+ .doc-file-chip:hover{border-color:#0f6f7a;color:#0f6f7a}
98
+ .doc-file-chip.active{background:#0f6f7a;border-color:#0f6f7a;color:#fff}
89
99
  .doc-status{font-size:10.5px;padding:2px 9px;border-radius:9px;border:1px solid var(--line);color:#6c7a7e;white-space:nowrap}
90
100
  .doc-status.ok{color:#2f7a52;border-color:color-mix(in srgb,#2f7a52 40%,transparent);background:#eef6f0}
91
101
  .doc-status.partial,.doc-status.draft{color:var(--gold);border-color:color-mix(in srgb,var(--gold) 45%,transparent);background:#fbf4e8}
@@ -685,3 +695,15 @@ body.presenting{overflow:hidden}
685
695
  .source-title .doc-status{margin-left:8px;font-size:9px;font-weight:400;vertical-align:2px}
686
696
  .doc-status.optional{color:#7a7f7c;background:#efece3;border:1px solid #e0dbcd;border-radius:8px;padding:0 6px;line-height:16px}
687
697
  .source-hint{font-size:10px;color:#8b8f8b;margin-top:3px;line-height:1.5}
698
+
699
+ /* F-188:顶栏「更新 / GitHub」小按钮 + 临时提示(顶栏是深色,沿用 .top button 的浅色底) */
700
+ .top .dl-icon-btn{position:relative;display:inline-flex;align-items:center;gap:5px;padding:6px 9px;cursor:pointer;font:inherit;font-size:12px;line-height:1}
701
+ .top .dl-icon-btn:hover{background:#ffffff2e}
702
+ .top .dl-icon-btn:active{transform:translateY(1px)}
703
+ .top .dl-icon-btn.busy svg{animation:dl-spin 1s linear infinite}
704
+ .top .dl-icon-btn svg{flex:0 0 auto;opacity:.85}
705
+ .top .dl-icon-ver{opacity:.72;font-size:11px;font-variant-numeric:tabular-nums}
706
+ .top .dl-icon-dot{position:absolute;top:3px;right:4px;width:7px;height:7px;border-radius:50%;background:#e8b45c;box-shadow:0 0 0 2px var(--ink)}
707
+ .dl-toast{position:fixed;left:50%;top:66px;transform:translateX(-50%) translateY(-6px);z-index:80;max-width:min(560px,90vw);padding:9px 14px;border:1px solid var(--line);border-radius:10px;background:#fffdf7;color:#2c2a26;font-size:13px;line-height:1.5;box-shadow:0 10px 28px rgba(0,0,0,.18);opacity:0;pointer-events:none;transition:opacity .16s ease,transform .16s ease;white-space:pre-wrap}
708
+ .dl-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
709
+ @keyframes dl-spin{to{transform:rotate(360deg)}}