@oh-story/dsh 0.1.7 → 0.1.8

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/README.md CHANGED
@@ -20,21 +20,27 @@
20
20
 
21
21
  ## 安装
22
22
 
23
+ 安装命令会临时提供 pnpm;只安装 Node.js 的机器也能执行。DSH 的 `plugin add` 内部需要 pnpm,单独运行 `npx @deepseek-ai/dsh ... plugin add` 不会自动补上它。
24
+
23
25
  ```bash
24
- npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile web add @oh-story/dsh@0.1.7
26
+ npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.1.2-rc.1 dsh plugin --profile web add @oh-story/dsh@0.1.8 &&
25
27
  npx -y @deepseek-ai/dsh@0.1.2-rc.1 web
26
28
  ```
27
29
 
28
30
  也可以直接安装 GitHub Release 中的预构建包:
29
31
 
30
32
  ```bash
31
- npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile web add https://github.com/zenstory-ai/oh-story-dsh/releases/download/v0.1.7/oh-story-dsh-0.1.7.tgz
33
+ npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.1.2-rc.1 dsh plugin --profile web add https://github.com/zenstory-ai/oh-story-dsh/releases/download/v0.1.8/oh-story-dsh-0.1.8.tgz &&
32
34
  npx -y @deepseek-ai/dsh@0.1.2-rc.1 web
33
35
  ```
34
36
 
35
- 需要 Node.js 24+。首次使用需要在 DSH 的「设置 → 模型」中添加 Provider 并填入 API Key,或在启动前设置环境变量 `DEEPSEEK_API_KEY`。
37
+ 保持终端运行。若浏览器未自动打开,访问终端打印的完整 `http://127.0.0.1:3080/?token=...` 链接完成首次认证。
38
+
39
+ 需要 Node.js 24+。开始 AI 创作前需要在 DSH 的「设置 → 模型」中添加 Provider 并填入 API Key,或在启动前设置环境变量 `DEEPSEEK_API_KEY`。
40
+
41
+ 首次首页尚无创作工作台。点击左侧 Workspaces 旁的 +(添加工作区 / Add workspace)选择作品文件夹,再在下方「选择工作区 / Choose workspace」中选中该目录(或打开已有会话),目录里已有创作项目时,会显示「小说 / 短剧 / 游戏 / 视频」标签;查看已有作品无需 API Key。
36
42
 
37
- 将作品目录添加为 DSH workspace,然后在普通 Agent 会话中使用 `/story`、`/short-drama`、`/novel-to-game quick` 或 `/video-recap`。四个入口始终可见;尚未创建的类型显示对应的创建引导。模型、凭据、Preset、权限、会话记录、停止/继续、Todo、审批和 Composer 均沿用当前 DeepSeek Harness 配置与界面。
43
+ 配置模型后,在普通 Agent 会话中使用 `/story`、`/short-drama`、`/novel-to-game quick` 或 `/video-recap`。空目录会保留 DSH 原生 Chat,Agent 写出第一个创作文件后工作台才会自动出现。工作台收起后,可通过会话区的「创作工作台」按钮重新打开。模型、凭据、Preset、权限、会话记录、停止/继续、Todo、审批和 Composer 均沿用当前 DeepSeek Harness 配置与界面。
38
44
 
39
45
  ## 短剧工作台
40
46
 
@@ -64,15 +70,24 @@ npx -y @deepseek-ai/dsh@0.1.2-rc.1 web
64
70
 
65
71
  Drama Skills 0.6.0 不支持把 v0.5 结构化项目原地升级为 creator-first 项目。旧项目应继续锁定 v0.5 并只读保留;迁移时请新建项目根,逐集人工确认当前工作实际需要的 `剧本.md`、`视觉设定.md`、`分镜.md`、`图片提示词.md` 或 `视频提示词.md`,不要预建空文档。
66
72
 
73
+ ## 没看到界面时
74
+
75
+ - **安装报 `pnpm not found on PATH`**:重新执行上面带 `--package pnpm@11.7.0` 的完整安装命令,确认安装成功后再启动。
76
+ - **浏览器未打开或要求认证**:打开终端打印的完整带 `?token=...` 链接;端口被占用时用 `web --port 3081`,并访问新打印的链接。
77
+ - **没有四个创作标签**:先添加作品目录并打开会话。空目录需要先在 Chat 中运行创作命令,生成创作文件后工作台才会出现;已收起的工作台可用会话区的「创作工作台」按钮恢复。已有作品仍不显示时,检查安装与启动是否使用同一个 profile,重启 DSH 并刷新页面。
78
+ - **独立 `story` profile 没有网页服务**:按下节补上 `@deepseek-ai/dsh-web-app`,仅安装创作插件不会给新 profile 添加 Web 界面。
79
+
67
80
  ## 按需加载
68
81
 
69
- 插件装进哪个 profile,那个 profile 的每个 Session 就都会加载创作 Skills 与三栏工作台。想让原版 `web` 保持干净、只在创作时打开工作台,就装进独立 profile:
82
+ 插件装进哪个 profile,那个 profile 的每个 Session 就都会加载创作 Skills;工作台只在有创作项目时显示。想让原版 `web` 保持干净、只在创作时打开工作台,就装进独立 profile:
70
83
 
71
84
  ```bash
72
- npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile story add @oh-story/dsh@0.1.7
85
+ npx -y --package pnpm@11.7.0 --package @deepseek-ai/dsh@0.1.2-rc.1 dsh plugin --profile story add @oh-story/dsh@0.1.8
73
86
  ```
74
87
 
75
- 新 profile 默认没有界面。编辑 `~/.dsh/profiles/story/package.json`,把 `dsh.profile.bundles` 改成 `["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@oh-story/dsh"]`,顺序照抄,这个包不用另外安装。
88
+ 新 profile 默认没有界面。编辑 `~/.dsh/profiles/story/package.json`,把 `dsh.profile.bundles` 改成 `["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@oh-story/dsh"]`。
89
+
90
+ `@deepseek-ai/dsh-web-app` 是 DSH 自带的 Web 界面包,需要在创作插件之前加载。
76
91
 
77
92
  ```bash
78
93
  npx -y @deepseek-ai/dsh@0.1.2-rc.1 web # 原版 DSH
package/lib/client.js CHANGED
@@ -1810,6 +1810,23 @@ function workbenchPreferenceStorage() {
1810
1810
 
1811
1811
  // inline-css:/home/runner/work/oh-story-dsh/oh-story-dsh/packages/dsh-plugin/src/client/plugin.css
1812
1812
  var plugin_default = `.oh-story-bridge-marker { display: none; }
1813
+ .oh-story-welcome {
1814
+ box-sizing: border-box;
1815
+ order: -1;
1816
+ flex-shrink: 0;
1817
+ width: min(640px, calc(100% - 32px));
1818
+ margin: 24px auto;
1819
+ padding: 20px 24px;
1820
+ border: 1px solid var(--dsw-alias-border-l2);
1821
+ border-radius: 12px;
1822
+ color: var(--dsw-alias-label-primary);
1823
+ background: var(--dsw-alias-bg-base);
1824
+ font: 14px/1.7 var(--dsw-font-family);
1825
+ overflow-wrap: anywhere;
1826
+ }
1827
+ .oh-story-welcome h2 { margin: 0 0 8px; font-size: 20px; }
1828
+ .oh-story-welcome p { margin: 8px 0 0; }
1829
+ .oh-story-welcome ol { margin: 12px 0; padding-left: 24px; }
1813
1830
  .oh-story-split-surface { display: contents; font-family: var(--dsw-font-family); }
1814
1831
 
1815
1832
  /* Collapsed, the plugin owns nothing but this control: DSH renders the
@@ -4120,7 +4137,7 @@ function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions
4120
4137
  };
4121
4138
  }
4122
4139
  let composerSeat = () => scroller.querySelector(":scope > [data-composer-seat]"), parkedAtTail = () => scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight <= 8, parked = parkedAtTail(), drivenAt = 0, markDriven = (event) => {
4123
- event.target instanceof Node && composerSeat()?.contains(event.target) === !0 || (drivenAt = performance.now());
4140
+ event.target instanceof Node && composerSeat()?.contains(event.target) === !0 || event.type === "pointerdown" && event.target !== scroller || (drivenAt = performance.now());
4124
4141
  }, trackParked = () => {
4125
4142
  parkedAtTail() ? parked = !0 : performance.now() - drivenAt < 400 && (parked = !1);
4126
4143
  }, publishLayout = () => {
@@ -4179,8 +4196,47 @@ function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions
4179
4196
  ), target)
4180
4197
  ] });
4181
4198
  }
4199
+ function WorkbenchWelcome() {
4200
+ let marker = (0, import_react3.useRef)(null), [target, setTarget] = (0, import_react3.useState)();
4201
+ return (0, import_react3.useLayoutEffect)(() => {
4202
+ let document = marker.current?.ownerDocument;
4203
+ if (document === void 0) return;
4204
+ let locate = () => {
4205
+ let anchor = document.querySelector("[data-conversation-scroll]");
4206
+ setTarget((current) => current === anchor ? current : anchor ?? void 0);
4207
+ };
4208
+ locate();
4209
+ let observer = new MutationObserver(locate);
4210
+ return observer.observe(document.body, { childList: !0, subtree: !0 }), () => {
4211
+ observer.disconnect();
4212
+ };
4213
+ }, []), /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4214
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: plugin_default }),
4215
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { ref: marker, className: "oh-story-bridge-marker", "aria-hidden": !0 }),
4216
+ target === void 0 ? null : (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "oh-story-welcome", "aria-label": "Oh Story \u4F7F\u7528\u5F15\u5BFC", children: [
4217
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { children: "Oh Story \u5DF2\u52A0\u8F7D" }),
4218
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "\u4F5C\u54C1\u76EE\u5F55\u4E2D\u6709\u521B\u4F5C\u6587\u4EF6\u65F6\uFF0C\u5C0F\u8BF4\u3001\u77ED\u5267\u3001\u6E38\u620F\u3001\u89C6\u9891\u5DE5\u4F5C\u53F0\u4F1A\u81EA\u52A8\u663E\u793A\u3002" }),
4219
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("ol", { children: [
4220
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: "\u70B9\u51FB\u5DE6\u4FA7\u300C\u6DFB\u52A0\u5DE5\u4F5C\u533A / Add workspace\u300D\u7684 \uFF0B\uFF0C\u9009\u62E9\u5B58\u653E\u4F5C\u54C1\u7684\u6587\u4EF6\u5939\u3002" }),
4221
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: "\u5728\u4E0B\u65B9\u300C\u9009\u62E9\u5DE5\u4F5C\u533A / Choose workspace\u300D\u4E2D\u9009\u4E2D\u8BE5\u76EE\u5F55\uFF0C\u6216\u6253\u5F00\u5DF2\u6709\u4F1A\u8BDD\u3002" }),
4222
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: "\u7A7A\u76EE\u5F55\u5148\u5728 Chat \u4E2D\u5F00\u59CB\u521B\u4F5C\uFF0C\u751F\u6210\u7B2C\u4E00\u4E2A\u521B\u4F5C\u6587\u4EF6\u540E\uFF0C\u5DE5\u4F5C\u53F0\u4F1A\u81EA\u52A8\u51FA\u73B0\u3002" })
4223
+ ] }),
4224
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
4225
+ "\u67E5\u770B\u5DF2\u6709\u4F5C\u54C1\u65E0\u9700 API Key\u3002\u5F00\u59CB AI \u521B\u4F5C\u524D\uFF0C\u5728\u300C\u8BBE\u7F6E \u2192 \u6A21\u578B\u300D\u914D\u7F6E\u6A21\u578B\uFF0C\u518D\u8F93\u5165 ",
4226
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "/story" }),
4227
+ "\u3001",
4228
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "/short-drama" }),
4229
+ "\u3001",
4230
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "/novel-to-game quick" }),
4231
+ " \u6216 ",
4232
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "/video-recap" }),
4233
+ "\u3002"
4234
+ ] })
4235
+ ] }), target)
4236
+ ] });
4237
+ }
4182
4238
  function WorkbenchSeat({ SessionProvider, renderSlot }) {
4183
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SessionProvider, { children: renderSlot("oh-story.workspace", {}) });
4239
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SessionProvider, { empty: () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(WorkbenchWelcome, {}), children: renderSlot("oh-story.workspace", {}) });
4184
4240
  }
4185
4241
  function argsOf(block) {
4186
4242
  let raw = ("kind" in block ? block.call?.argsRaw : block.argsRaw) ?? "{}";