@dsh-workbench/core 0.1.10 → 0.1.12

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/bin/dsh-workbench CHANGED
@@ -214,6 +214,29 @@ fi
214
214
  # 而且从那里跑出来同样是隔离的。指向 profile 里那份,别指 npx 缓存(会回收)。
215
215
  OPENCLI_ROOT="$DSH_HOME/workbench/opencli"
216
216
  mkdir -p "$OPENCLI_ROOT/bin" "$OPENCLI_ROOT/home"
217
+
218
+ # DIY 工坊的目录必须**每次启动都在**:`cordis.patch.yml` 的 hmr 行把它列成一个监听根
219
+ # (工坊里的模块是被 link 进 profile 的仓外目录,Node 解析到的是工坊里的真路径,
220
+ # 所以不把它列进去,模块重建 dist/host.js 就不热换 —— 而且**不报错**)。
221
+ # chokidar 对不存在的根收不到事件,所以这里保住它,不必等用户重跑 setup。
222
+ # 只建目录:骨架与依赖是 seed-profile.sh 第 6 步的事。
223
+ mkdir -p "$DSH_HOME/workbench/diy/packages"
224
+
225
+ # 工坊**自己带着** DIY 的指引:软链到随包出货的那一份(本包的 `skills/workbench-module-diy/`)。
226
+ # 为什么放在这里、而不是靠 agent preset 的 `customSkillDirs`:DIY 会话的 cwd 就是工坊
227
+ # (会话 cwd 即沙箱边界),而 dsh 的 skill-filesystem 是从 **cwd 下的 `.agents/skills/`**
228
+ # 发现技能的 —— 本仓自己那条 `module-design` 就是这么被看见的。所以指引住进工坊,
229
+ # 进工坊的会话就天然看得见它,**不用去改用户任何默认设置**(改默认 preset 会连带把
230
+ # 用户后面新建的普通会话也变成 DIY 模式)。preset 留着,是给想**显式选模式**的用户,
231
+ # 额外带 tool-cordis 与 plugin-manager 两处增量。
232
+ # 软链而不是拷贝:指引只有一份(随包出货,字数与链接都有判据钉着),拷一份就是第二份真相。
233
+ # 先 rm -f 再建:包换过位置/名字之后,旧软链会变成死链 —— 而那是**不报错**的失败。
234
+ DIY_SKILLS="$DSH_HOME/workbench/diy/.agents/skills"
235
+ if [ -d "$REPO_DIR/skills/workbench-module-diy" ]; then
236
+ mkdir -p "$DIY_SKILLS"
237
+ rm -f "$DIY_SKILLS/workbench-module-diy"
238
+ ln -s "$REPO_DIR/skills/workbench-module-diy" "$DIY_SKILLS/workbench-module-diy"
239
+ fi
217
240
  # 稳定路径不直接软链到随包脚本:同上面那条 —— pnpm publish 之后
218
241
  # `bin/opencli-isolated` 是 644,软链过去一执行就是 Permission denied
219
242
  # (症状:启动体检永远说"隔离运行时没装好",而它其实是没权限跑)。
package/client.js CHANGED
@@ -1023,6 +1023,7 @@ window.__ModuleLoader__.load({
1023
1023
  "panels.enabled": "enabled in this project",
1024
1024
  "panels.disabled": "not enabled in this project",
1025
1025
  "panels.choose": "Choose modules",
1026
+ "panels.buildModule": "Build a module",
1026
1027
  "panels.failed": "Could not save the change. Try again.",
1027
1028
  "panels.hintEffect": "Disabling = the agent cannot reach that data",
1028
1029
  "panels.dragHint": "Drag to reorder",
@@ -1334,6 +1335,7 @@ window.__ModuleLoader__.load({
1334
1335
  "panels.enabled": "这个项目已启用",
1335
1336
  "panels.disabled": "这个项目未启用",
1336
1337
  "panels.choose": "选择模块",
1338
+ "panels.buildModule": "造一个模块",
1337
1339
  "panels.failed": "改配置失败了,再试一次。",
1338
1340
  "panels.hintEffect": "停用 = agent 拿不到相关数据",
1339
1341
  "panels.dragHint": "拖动调整顺序",
@@ -4580,6 +4582,30 @@ window.__ModuleLoader__.load({
4580
4582
  }, MarketPanel));
4581
4583
  }
4582
4584
  //#endregion
4585
+ //#region src/app/layouts/project-selection.ts
4586
+ var listeners = /* @__PURE__ */ new Set();
4587
+ function selectedProjectId() {
4588
+ const stored = readText(STORAGE_KEY_PROJECT);
4589
+ return stored === "" ? null : stored;
4590
+ }
4591
+ function selectProject(workspaceId) {
4592
+ writeText(STORAGE_KEY_PROJECT, workspaceId);
4593
+ for (const listener of [...listeners]) try {
4594
+ listener();
4595
+ } catch {}
4596
+ }
4597
+ function subscribeProject(listener) {
4598
+ listeners.add(listener);
4599
+ return () => {
4600
+ listeners.delete(listener);
4601
+ };
4602
+ }
4603
+ //#endregion
4604
+ //#region src/shared/api/diy.ts
4605
+ var DIY_PRESET_ID = "workbench-diy";
4606
+ var WORKSHOP_TITLE = "工作台DIY";
4607
+ var WORKSHOP_PAST_TITLES = ["DIY 工坊", "工作台自带 · DIY 模块住这儿"];
4608
+ //#endregion
4583
4609
  //#region src/app/units/index.ts
4584
4610
  var CLIENT_UNITS = [];
4585
4611
  function assembleClientUnits(registry) {
@@ -5441,7 +5467,7 @@ window.__ModuleLoader__.load({
5441
5467
  }
5442
5468
  //#endregion
5443
5469
  //#region src/app/layouts/rightbar/BoardEmpty.tsx
5444
- function BoardEmpty({ t, onOpenModules, onOpenMarket }) {
5470
+ function BoardEmpty({ t, onBuildModule, onOpenModules, onOpenMarket }) {
5445
5471
  return /* @__PURE__ */ h(CenteredState, {
5446
5472
  icon: /* @__PURE__ */ h(IconBrandMark, { size: 32 }),
5447
5473
  title: t("panels.empty"),
@@ -5450,6 +5476,11 @@ window.__ModuleLoader__.load({
5450
5476
  type: "button",
5451
5477
  size: "sm",
5452
5478
  variant: "primary",
5479
+ onClick: onBuildModule
5480
+ }, t("panels.buildModule")), /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.Button, {
5481
+ type: "button",
5482
+ size: "sm",
5483
+ variant: "toolbar",
5453
5484
  onClick: onOpenModules
5454
5485
  }, t("panels.choose")), /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.Button, {
5455
5486
  type: "button",
@@ -6144,25 +6175,6 @@ window.__ModuleLoader__.load({
6144
6175
  };
6145
6176
  }
6146
6177
  //#endregion
6147
- //#region src/app/layouts/project-selection.ts
6148
- var listeners = /* @__PURE__ */ new Set();
6149
- function selectedProjectId() {
6150
- const stored = readText(STORAGE_KEY_PROJECT);
6151
- return stored === "" ? null : stored;
6152
- }
6153
- function selectProject(workspaceId) {
6154
- writeText(STORAGE_KEY_PROJECT, workspaceId);
6155
- for (const listener of [...listeners]) try {
6156
- listener();
6157
- } catch {}
6158
- }
6159
- function subscribeProject(listener) {
6160
- listeners.add(listener);
6161
- return () => {
6162
- listeners.delete(listener);
6163
- };
6164
- }
6165
- //#endregion
6166
6178
  //#region src/app/layouts/rightbar/use-panels.ts
6167
6179
  function shouldDropPanels(workspace, previous) {
6168
6180
  return workspace !== previous;
@@ -6254,7 +6266,7 @@ window.__ModuleLoader__.load({
6254
6266
  onClick: onCollapse
6255
6267
  })))));
6256
6268
  }
6257
- function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, t }) {
6269
+ function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, buildModule, t }) {
6258
6270
  if (top.kind !== "board") {
6259
6271
  const owner = board.stepOwner(top.kind);
6260
6272
  if (owner === void 0) return /* @__PURE__ */ h(CenteredState, {
@@ -6284,6 +6296,7 @@ window.__ModuleLoader__.load({
6284
6296
  title: /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, { active: true }, t("panels.reading"))
6285
6297
  }) : null, plan.empty ? /* @__PURE__ */ h(BoardEmpty, {
6286
6298
  t,
6299
+ onBuildModule: buildModule,
6287
6300
  onOpenModules,
6288
6301
  onOpenMarket
6289
6302
  }) : null, plan.modules.map(({ key, module }) => /* @__PURE__ */ h(CardBoundary, {
@@ -6402,6 +6415,7 @@ window.__ModuleLoader__.load({
6402
6415
  onOpenMarket: openMarket,
6403
6416
  onSummary,
6404
6417
  onOpenModules: () => setModulesOpen(true),
6418
+ buildModule: props.buildModule,
6405
6419
  t: props.t
6406
6420
  })));
6407
6421
  }
@@ -6977,6 +6991,7 @@ window.__ModuleLoader__.load({
6977
6991
  const [storedId, setStoredId] = useState(() => selectedProjectId());
6978
6992
  const [panelEntries, setPanelEntries] = useState(() => props.listPanels());
6979
6993
  useEffect(() => props.subscribePanels(() => setPanelEntries(props.listPanels())), [props]);
6994
+ useEffect(() => subscribeProject(() => setStoredId(selectedProjectId())), []);
6980
6995
  const current = items.find((workspace) => workspace.workspaceId === storedId) ?? items[0] ?? null;
6981
6996
  const pickProject = (workspaceId) => {
6982
6997
  setStoredId(workspaceId);
@@ -7515,7 +7530,8 @@ window.__ModuleLoader__.load({
7515
7530
  "layout",
7516
7531
  "uiWorkspace",
7517
7532
  "workspaces",
7518
- "shortcuts"
7533
+ "shortcuts",
7534
+ "remote"
7519
7535
  ];
7520
7536
  function apply(ctx) {
7521
7537
  try {
@@ -7557,6 +7573,36 @@ window.__ModuleLoader__.load({
7557
7573
  disposeDictionary?.();
7558
7574
  };
7559
7575
  }, "dsh-workbench: dictionaries");
7576
+ const workshopWorkspace = () => ctx.workspaces.list.getSnapshot().items.find((item) => item.path.endsWith("/workbench/diy"));
7577
+ const buildModule = () => {
7578
+ const workshop = workshopWorkspace();
7579
+ if (workshop === void 0) {
7580
+ console.warn("[dsh-workbench] 工坊还没登记成工作区 —— 重启一次工作台");
7581
+ return;
7582
+ }
7583
+ selectProject(workshop.workspaceId);
7584
+ const open = () => {
7585
+ ctx.uiWorkspace.startSession(workshop.workspaceId);
7586
+ };
7587
+ const remoteCreate = sessionCreateOf(ctx.remote);
7588
+ try {
7589
+ if (remoteCreate === void 0) throw new Error("session 那一组拿不到");
7590
+ remoteCreate({
7591
+ workspaceId: workshop.workspaceId,
7592
+ agentPreset: DIY_PRESET_ID
7593
+ }).then((created) => {
7594
+ const id = created.sessionId;
7595
+ if (id === void 0) throw new Error("没有 sessionId");
7596
+ ctx.uiWorkspace.openSession(id);
7597
+ }).catch((error) => {
7598
+ console.warn(`[dsh-workbench] 落 DIY 模式失败,仍切工作区 —— ${String(error)}`);
7599
+ open();
7600
+ });
7601
+ } catch (error) {
7602
+ console.warn(`[dsh-workbench] ctx.remote 拿不到 —— ${String(error)}`);
7603
+ open();
7604
+ }
7605
+ };
7560
7606
  const rightbarActions = {
7561
7607
  openMarket: () => ctx.layout.selectPanel(MARKET_PANEL_ID),
7562
7608
  applyRightbar: ({ shown, track, fullscreen }) => {
@@ -7575,7 +7621,8 @@ window.__ModuleLoader__.load({
7575
7621
  ctx.layout.openRightbar(true, false);
7576
7622
  },
7577
7623
  openPanel: (step) => store.open(step),
7578
- goToPanel: (index) => store.goTo(index)
7624
+ goToPanel: (index) => store.goTo(index),
7625
+ buildModule
7579
7626
  };
7580
7627
  const rightbarHooks = { hooks: { rightbar: observable } };
7581
7628
  const sidebarRight = () => ctx.get("sidebarRight");
@@ -7720,6 +7767,12 @@ window.__ModuleLoader__.load({
7720
7767
  })
7721
7768
  }, Sidebar));
7722
7769
  registerMarketPanel(ctx, units);
7770
+ ctx.effect(() => {
7771
+ const workshop = workshopWorkspace();
7772
+ if (workshop === void 0) return;
7773
+ const title = ctx.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workshop.workspaceId)?.title;
7774
+ if (title !== void 0 && WORKSHOP_PAST_TITLES.includes(title) && title !== "工作台DIY") ctx.workspaces.rename(workshop.workspaceId, WORKSHOP_TITLE).catch(() => void 0);
7775
+ }, "dsh-workbench: 工坊那一行的旧名字换成新名字");
7723
7776
  const gate = createBootGate(ctx);
7724
7777
  ctx.effect(() => () => gate.close(), "dsh-workbench: env gate");
7725
7778
  ctx.slots.inject("conversation.approval.detail", () => ctx.slots.register({
@@ -7789,6 +7842,10 @@ window.__ModuleLoader__.load({
7789
7842
  function menuOpenStateFactory(_standard, state) {
7790
7843
  return () => state;
7791
7844
  }
7845
+ function sessionCreateOf(remote) {
7846
+ const namespaces = remote?.namespaces;
7847
+ return namespaces?.get?.("session")?.service?.create?.bind(namespaces.get("session")?.service);
7848
+ }
7792
7849
  //#endregion
7793
7850
  exports.apply = apply;
7794
7851
  exports.inject = inject;
package/cordis.patch.yml CHANGED
@@ -26,15 +26,23 @@
26
26
 
27
27
  # ── 宿主侧热更新 ──────────────────────────────────────────────────────
28
28
  # 出厂默认 `root: []` = 不监听任何模块目录,改了宿主代码只能重启。
29
- # 这里打开监听:**路径由启动器通过 `DSH_WORKBENCH_ROOT` 给出**。
30
- # 实测过 `'.'`(以 profile 目录为基准)不行:我们的包在 profile 里只是一个指向
31
- # 本仓库的符号链接,从 profile 目录出发根本走不到 /Volumes/…,chokidar 收不到事件。
29
+ # 这里打开监听,**两个根**:
30
+ # 1. 外壳自己(路径由启动器通过 `DSH_WORKBENCH_ROOT` 给出)。实测过 `'.'`
31
+ # (以 profile 目录为基准)不行:我们的包在 profile 里只是一个指向本仓库的
32
+ # 符号链接,从 profile 目录出发根本走不到 /Volumes/…,chokidar 收不到事件。
33
+ # 2. **DIY 工坊**(`$DSH_HOME/workbench/diy`)。工坊里的模块是**被 link 进 profile
34
+ # 的第三方目录**(`link:` 依赖),Node 解析到的是工坊里的真路径,而 dsh-hmr 的
35
+ # 归属判定整个走 realpath —— 所以工坊不在 `root` 里,模块重建 `dist/host.js`
36
+ # 就**不热换**,而且**不报错**(症状是"改了一行,界面上没变")。
37
+ # 外壳自己就是同一个处境的现成反例:它也是 link 进来、也是靠这一条热换的。
32
38
  #
33
39
  # 注意 `config` 是**整体替换**(不深合并),所以 `root` 必须写全。
40
+ # 工坊目录由启动器每次启动 `mkdir -p` 出来(chokidar 的根不存在时收不到事件)。
34
41
  - id: hmr
35
42
  config:
36
43
  root:
37
44
  - !!js process.env.DSH_WORKBENCH_ROOT ?? '.'
45
+ - !!js dshHomePath('workbench/diy')
38
46
 
39
47
  - insert:
40
48
  - id: workbench
@@ -1016,6 +1016,7 @@ var en = {
1016
1016
  "panels.enabled": "enabled in this project",
1017
1017
  "panels.disabled": "not enabled in this project",
1018
1018
  "panels.choose": "Choose modules",
1019
+ "panels.buildModule": "Build a module",
1019
1020
  "panels.failed": "Could not save the change. Try again.",
1020
1021
  "panels.hintEffect": "Disabling = the agent cannot reach that data",
1021
1022
  "panels.dragHint": "Drag to reorder",
@@ -1327,6 +1328,7 @@ var zh = {
1327
1328
  "panels.enabled": "这个项目已启用",
1328
1329
  "panels.disabled": "这个项目未启用",
1329
1330
  "panels.choose": "选择模块",
1331
+ "panels.buildModule": "造一个模块",
1330
1332
  "panels.failed": "改配置失败了,再试一次。",
1331
1333
  "panels.hintEffect": "停用 = agent 拿不到相关数据",
1332
1334
  "panels.dragHint": "拖动调整顺序",
@@ -4573,6 +4575,30 @@ function registerMarketPanel(ctx, units) {
4573
4575
  }, MarketPanel));
4574
4576
  }
4575
4577
  //#endregion
4578
+ //#region src/app/layouts/project-selection.ts
4579
+ var listeners = /* @__PURE__ */ new Set();
4580
+ function selectedProjectId() {
4581
+ const stored = readText(STORAGE_KEY_PROJECT);
4582
+ return stored === "" ? null : stored;
4583
+ }
4584
+ function selectProject(workspaceId) {
4585
+ writeText(STORAGE_KEY_PROJECT, workspaceId);
4586
+ for (const listener of [...listeners]) try {
4587
+ listener();
4588
+ } catch {}
4589
+ }
4590
+ function subscribeProject(listener) {
4591
+ listeners.add(listener);
4592
+ return () => {
4593
+ listeners.delete(listener);
4594
+ };
4595
+ }
4596
+ //#endregion
4597
+ //#region src/shared/api/diy.ts
4598
+ var DIY_PRESET_ID = "workbench-diy";
4599
+ var WORKSHOP_TITLE = "工作台DIY";
4600
+ var WORKSHOP_PAST_TITLES = ["DIY 工坊", "工作台自带 · DIY 模块住这儿"];
4601
+ //#endregion
4576
4602
  //#region src/app/units/index.ts
4577
4603
  var CLIENT_UNITS = [];
4578
4604
  function assembleClientUnits(registry) {
@@ -5434,7 +5460,7 @@ function Breadcrumbs({ trail, onGoTo, titleKeyOf, t }) {
5434
5460
  }
5435
5461
  //#endregion
5436
5462
  //#region src/app/layouts/rightbar/BoardEmpty.tsx
5437
- function BoardEmpty({ t, onOpenModules, onOpenMarket }) {
5463
+ function BoardEmpty({ t, onBuildModule, onOpenModules, onOpenMarket }) {
5438
5464
  return /* @__PURE__ */ h(CenteredState, {
5439
5465
  icon: /* @__PURE__ */ h(IconBrandMark, { size: 32 }),
5440
5466
  title: t("panels.empty"),
@@ -5443,6 +5469,11 @@ function BoardEmpty({ t, onOpenModules, onOpenMarket }) {
5443
5469
  type: "button",
5444
5470
  size: "sm",
5445
5471
  variant: "primary",
5472
+ onClick: onBuildModule
5473
+ }, t("panels.buildModule")), /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.Button, {
5474
+ type: "button",
5475
+ size: "sm",
5476
+ variant: "toolbar",
5446
5477
  onClick: onOpenModules
5447
5478
  }, t("panels.choose")), /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.Button, {
5448
5479
  type: "button",
@@ -6137,25 +6168,6 @@ function createSuiteWorld(input) {
6137
6168
  };
6138
6169
  }
6139
6170
  //#endregion
6140
- //#region src/app/layouts/project-selection.ts
6141
- var listeners = /* @__PURE__ */ new Set();
6142
- function selectedProjectId() {
6143
- const stored = readText(STORAGE_KEY_PROJECT);
6144
- return stored === "" ? null : stored;
6145
- }
6146
- function selectProject(workspaceId) {
6147
- writeText(STORAGE_KEY_PROJECT, workspaceId);
6148
- for (const listener of [...listeners]) try {
6149
- listener();
6150
- } catch {}
6151
- }
6152
- function subscribeProject(listener) {
6153
- listeners.add(listener);
6154
- return () => {
6155
- listeners.delete(listener);
6156
- };
6157
- }
6158
- //#endregion
6159
6171
  //#region src/app/layouts/rightbar/use-panels.ts
6160
6172
  function shouldDropPanels(workspace, previous) {
6161
6173
  return workspace !== previous;
@@ -6247,7 +6259,7 @@ function PanelHeader({ t, trail, onGoTo, titleKeyOf, refreshing, at, refreshEnab
6247
6259
  onClick: onCollapse
6248
6260
  })))));
6249
6261
  }
6250
- function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, t }) {
6262
+ function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, buildModule, t }) {
6251
6263
  if (top.kind !== "board") {
6252
6264
  const owner = board.stepOwner(top.kind);
6253
6265
  if (owner === void 0) return /* @__PURE__ */ h(CenteredState, {
@@ -6277,6 +6289,7 @@ function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onN
6277
6289
  title: /* @__PURE__ */ h(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, { active: true }, t("panels.reading"))
6278
6290
  }) : null, plan.empty ? /* @__PURE__ */ h(BoardEmpty, {
6279
6291
  t,
6292
+ onBuildModule: buildModule,
6280
6293
  onOpenModules,
6281
6294
  onOpenMarket
6282
6295
  }) : null, plan.modules.map(({ key, module }) => /* @__PURE__ */ h(CardBoundary, {
@@ -6395,6 +6408,7 @@ function Rightbar(props) {
6395
6408
  onOpenMarket: openMarket,
6396
6409
  onSummary,
6397
6410
  onOpenModules: () => setModulesOpen(true),
6411
+ buildModule: props.buildModule,
6398
6412
  t: props.t
6399
6413
  })));
6400
6414
  }
@@ -6970,6 +6984,7 @@ function Sidebar(props) {
6970
6984
  const [storedId, setStoredId] = useState(() => selectedProjectId());
6971
6985
  const [panelEntries, setPanelEntries] = useState(() => props.listPanels());
6972
6986
  useEffect(() => props.subscribePanels(() => setPanelEntries(props.listPanels())), [props]);
6987
+ useEffect(() => subscribeProject(() => setStoredId(selectedProjectId())), []);
6973
6988
  const current = items.find((workspace) => workspace.workspaceId === storedId) ?? items[0] ?? null;
6974
6989
  const pickProject = (workspaceId) => {
6975
6990
  setStoredId(workspaceId);
@@ -7508,7 +7523,8 @@ var inject = [
7508
7523
  "layout",
7509
7524
  "uiWorkspace",
7510
7525
  "workspaces",
7511
- "shortcuts"
7526
+ "shortcuts",
7527
+ "remote"
7512
7528
  ];
7513
7529
  function apply(ctx) {
7514
7530
  try {
@@ -7550,6 +7566,36 @@ function mount(ctx) {
7550
7566
  disposeDictionary?.();
7551
7567
  };
7552
7568
  }, "dsh-workbench: dictionaries");
7569
+ const workshopWorkspace = () => ctx.workspaces.list.getSnapshot().items.find((item) => item.path.endsWith("/workbench/diy"));
7570
+ const buildModule = () => {
7571
+ const workshop = workshopWorkspace();
7572
+ if (workshop === void 0) {
7573
+ console.warn("[dsh-workbench] 工坊还没登记成工作区 —— 重启一次工作台");
7574
+ return;
7575
+ }
7576
+ selectProject(workshop.workspaceId);
7577
+ const open = () => {
7578
+ ctx.uiWorkspace.startSession(workshop.workspaceId);
7579
+ };
7580
+ const remoteCreate = sessionCreateOf(ctx.remote);
7581
+ try {
7582
+ if (remoteCreate === void 0) throw new Error("session 那一组拿不到");
7583
+ remoteCreate({
7584
+ workspaceId: workshop.workspaceId,
7585
+ agentPreset: DIY_PRESET_ID
7586
+ }).then((created) => {
7587
+ const id = created.sessionId;
7588
+ if (id === void 0) throw new Error("没有 sessionId");
7589
+ ctx.uiWorkspace.openSession(id);
7590
+ }).catch((error) => {
7591
+ console.warn(`[dsh-workbench] 落 DIY 模式失败,仍切工作区 —— ${String(error)}`);
7592
+ open();
7593
+ });
7594
+ } catch (error) {
7595
+ console.warn(`[dsh-workbench] ctx.remote 拿不到 —— ${String(error)}`);
7596
+ open();
7597
+ }
7598
+ };
7553
7599
  const rightbarActions = {
7554
7600
  openMarket: () => ctx.layout.selectPanel(MARKET_PANEL_ID),
7555
7601
  applyRightbar: ({ shown, track, fullscreen }) => {
@@ -7568,7 +7614,8 @@ function mount(ctx) {
7568
7614
  ctx.layout.openRightbar(true, false);
7569
7615
  },
7570
7616
  openPanel: (step) => store.open(step),
7571
- goToPanel: (index) => store.goTo(index)
7617
+ goToPanel: (index) => store.goTo(index),
7618
+ buildModule
7572
7619
  };
7573
7620
  const rightbarHooks = { hooks: { rightbar: observable } };
7574
7621
  const sidebarRight = () => ctx.get("sidebarRight");
@@ -7713,6 +7760,12 @@ function mount(ctx) {
7713
7760
  })
7714
7761
  }, Sidebar));
7715
7762
  registerMarketPanel(ctx, units);
7763
+ ctx.effect(() => {
7764
+ const workshop = workshopWorkspace();
7765
+ if (workshop === void 0) return;
7766
+ const title = ctx.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workshop.workspaceId)?.title;
7767
+ if (title !== void 0 && WORKSHOP_PAST_TITLES.includes(title) && title !== "工作台DIY") ctx.workspaces.rename(workshop.workspaceId, WORKSHOP_TITLE).catch(() => void 0);
7768
+ }, "dsh-workbench: 工坊那一行的旧名字换成新名字");
7716
7769
  const gate = createBootGate(ctx);
7717
7770
  ctx.effect(() => () => gate.close(), "dsh-workbench: env gate");
7718
7771
  ctx.slots.inject("conversation.approval.detail", () => ctx.slots.register({
@@ -7782,6 +7835,10 @@ function sidebarChildren(ctx) {
7782
7835
  function menuOpenStateFactory(_standard, state) {
7783
7836
  return () => state;
7784
7837
  }
7838
+ function sessionCreateOf(remote) {
7839
+ const namespaces = remote?.namespaces;
7840
+ return namespaces?.get?.("session")?.service?.create?.bind(namespaces.get("session")?.service);
7841
+ }
7785
7842
  //#endregion
7786
7843
  exports.apply = apply;
7787
7844
  exports.inject = inject;
@@ -1019,6 +1019,7 @@ var en = {
1019
1019
  "panels.enabled": "enabled in this project",
1020
1020
  "panels.disabled": "not enabled in this project",
1021
1021
  "panels.choose": "Choose modules",
1022
+ "panels.buildModule": "Build a module",
1022
1023
  "panels.failed": "Could not save the change. Try again.",
1023
1024
  "panels.hintEffect": "Disabling = the agent cannot reach that data",
1024
1025
  "panels.dragHint": "Drag to reorder",
@@ -1330,6 +1331,7 @@ var zh = {
1330
1331
  "panels.enabled": "这个项目已启用",
1331
1332
  "panels.disabled": "这个项目未启用",
1332
1333
  "panels.choose": "选择模块",
1334
+ "panels.buildModule": "造一个模块",
1333
1335
  "panels.failed": "改配置失败了,再试一次。",
1334
1336
  "panels.hintEffect": "停用 = agent 拿不到相关数据",
1335
1337
  "panels.dragHint": "拖动调整顺序",
@@ -4576,6 +4578,30 @@ function registerMarketPanel(ctx, units) {
4576
4578
  }, MarketPanel));
4577
4579
  }
4578
4580
  //#endregion
4581
+ //#region src/app/layouts/project-selection.ts
4582
+ var listeners = /* @__PURE__ */ new Set();
4583
+ function selectedProjectId() {
4584
+ const stored = readText(STORAGE_KEY_PROJECT);
4585
+ return stored === "" ? null : stored;
4586
+ }
4587
+ function selectProject(workspaceId) {
4588
+ writeText(STORAGE_KEY_PROJECT, workspaceId);
4589
+ for (const listener of [...listeners]) try {
4590
+ listener();
4591
+ } catch {}
4592
+ }
4593
+ function subscribeProject(listener) {
4594
+ listeners.add(listener);
4595
+ return () => {
4596
+ listeners.delete(listener);
4597
+ };
4598
+ }
4599
+ //#endregion
4600
+ //#region src/shared/api/diy.ts
4601
+ var DIY_PRESET_ID = "workbench-diy";
4602
+ var WORKSHOP_TITLE = "工作台DIY";
4603
+ var WORKSHOP_PAST_TITLES = ["DIY 工坊", "工作台自带 · DIY 模块住这儿"];
4604
+ //#endregion
4579
4605
  //#region src/app/units/index.ts
4580
4606
  var CLIENT_UNITS = [];
4581
4607
  function assembleClientUnits(registry) {
@@ -5437,7 +5463,7 @@ function Breadcrumbs({ trail, onGoTo, titleKeyOf, t }) {
5437
5463
  }
5438
5464
  //#endregion
5439
5465
  //#region src/app/layouts/rightbar/BoardEmpty.tsx
5440
- function BoardEmpty({ t, onOpenModules, onOpenMarket }) {
5466
+ function BoardEmpty({ t, onBuildModule, onOpenModules, onOpenMarket }) {
5441
5467
  return /* @__PURE__ */ h(CenteredState, {
5442
5468
  icon: /* @__PURE__ */ h(IconBrandMark, { size: 32 }),
5443
5469
  title: t("panels.empty"),
@@ -5446,6 +5472,11 @@ function BoardEmpty({ t, onOpenModules, onOpenMarket }) {
5446
5472
  type: "button",
5447
5473
  size: "sm",
5448
5474
  variant: "primary",
5475
+ onClick: onBuildModule
5476
+ }, t("panels.buildModule")), /* @__PURE__ */ h(Button, {
5477
+ type: "button",
5478
+ size: "sm",
5479
+ variant: "toolbar",
5449
5480
  onClick: onOpenModules
5450
5481
  }, t("panels.choose")), /* @__PURE__ */ h(Button, {
5451
5482
  type: "button",
@@ -6140,25 +6171,6 @@ function createSuiteWorld(input) {
6140
6171
  };
6141
6172
  }
6142
6173
  //#endregion
6143
- //#region src/app/layouts/project-selection.ts
6144
- var listeners = /* @__PURE__ */ new Set();
6145
- function selectedProjectId() {
6146
- const stored = readText(STORAGE_KEY_PROJECT);
6147
- return stored === "" ? null : stored;
6148
- }
6149
- function selectProject(workspaceId) {
6150
- writeText(STORAGE_KEY_PROJECT, workspaceId);
6151
- for (const listener of [...listeners]) try {
6152
- listener();
6153
- } catch {}
6154
- }
6155
- function subscribeProject(listener) {
6156
- listeners.add(listener);
6157
- return () => {
6158
- listeners.delete(listener);
6159
- };
6160
- }
6161
- //#endregion
6162
6174
  //#region src/app/layouts/rightbar/use-panels.ts
6163
6175
  function shouldDropPanels(workspace, previous) {
6164
6176
  return workspace !== previous;
@@ -6250,7 +6262,7 @@ function PanelHeader({ t, trail, onGoTo, titleKeyOf, refreshing, at, refreshEnab
6250
6262
  onClick: onCollapse
6251
6263
  })))));
6252
6264
  }
6253
- function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, t }) {
6265
+ function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onNavigate, onOpenMarket, onSummary, onOpenModules, buildModule, t }) {
6254
6266
  if (top.kind !== "board") {
6255
6267
  const owner = board.stepOwner(top.kind);
6256
6268
  if (owner === void 0) return /* @__PURE__ */ h(CenteredState, {
@@ -6280,6 +6292,7 @@ function BoardContent({ top, plan, world, board, panelToken, onPanelRefresh, onN
6280
6292
  title: /* @__PURE__ */ h(TextShimmer, { active: true }, t("panels.reading"))
6281
6293
  }) : null, plan.empty ? /* @__PURE__ */ h(BoardEmpty, {
6282
6294
  t,
6295
+ onBuildModule: buildModule,
6283
6296
  onOpenModules,
6284
6297
  onOpenMarket
6285
6298
  }) : null, plan.modules.map(({ key, module }) => /* @__PURE__ */ h(CardBoundary, {
@@ -6398,6 +6411,7 @@ function Rightbar(props) {
6398
6411
  onOpenMarket: openMarket,
6399
6412
  onSummary,
6400
6413
  onOpenModules: () => setModulesOpen(true),
6414
+ buildModule: props.buildModule,
6401
6415
  t: props.t
6402
6416
  })));
6403
6417
  }
@@ -6973,6 +6987,7 @@ function Sidebar(props) {
6973
6987
  const [storedId, setStoredId] = useState(() => selectedProjectId());
6974
6988
  const [panelEntries, setPanelEntries] = useState(() => props.listPanels());
6975
6989
  useEffect(() => props.subscribePanels(() => setPanelEntries(props.listPanels())), [props]);
6990
+ useEffect(() => subscribeProject(() => setStoredId(selectedProjectId())), []);
6976
6991
  const current = items.find((workspace) => workspace.workspaceId === storedId) ?? items[0] ?? null;
6977
6992
  const pickProject = (workspaceId) => {
6978
6993
  setStoredId(workspaceId);
@@ -7511,7 +7526,8 @@ var inject = [
7511
7526
  "layout",
7512
7527
  "uiWorkspace",
7513
7528
  "workspaces",
7514
- "shortcuts"
7529
+ "shortcuts",
7530
+ "remote"
7515
7531
  ];
7516
7532
  function apply(ctx) {
7517
7533
  try {
@@ -7553,6 +7569,36 @@ function mount(ctx) {
7553
7569
  disposeDictionary?.();
7554
7570
  };
7555
7571
  }, "dsh-workbench: dictionaries");
7572
+ const workshopWorkspace = () => ctx.workspaces.list.getSnapshot().items.find((item) => item.path.endsWith("/workbench/diy"));
7573
+ const buildModule = () => {
7574
+ const workshop = workshopWorkspace();
7575
+ if (workshop === void 0) {
7576
+ console.warn("[dsh-workbench] 工坊还没登记成工作区 —— 重启一次工作台");
7577
+ return;
7578
+ }
7579
+ selectProject(workshop.workspaceId);
7580
+ const open = () => {
7581
+ ctx.uiWorkspace.startSession(workshop.workspaceId);
7582
+ };
7583
+ const remoteCreate = sessionCreateOf(ctx.remote);
7584
+ try {
7585
+ if (remoteCreate === void 0) throw new Error("session 那一组拿不到");
7586
+ remoteCreate({
7587
+ workspaceId: workshop.workspaceId,
7588
+ agentPreset: DIY_PRESET_ID
7589
+ }).then((created) => {
7590
+ const id = created.sessionId;
7591
+ if (id === void 0) throw new Error("没有 sessionId");
7592
+ ctx.uiWorkspace.openSession(id);
7593
+ }).catch((error) => {
7594
+ console.warn(`[dsh-workbench] 落 DIY 模式失败,仍切工作区 —— ${String(error)}`);
7595
+ open();
7596
+ });
7597
+ } catch (error) {
7598
+ console.warn(`[dsh-workbench] ctx.remote 拿不到 —— ${String(error)}`);
7599
+ open();
7600
+ }
7601
+ };
7556
7602
  const rightbarActions = {
7557
7603
  openMarket: () => ctx.layout.selectPanel(MARKET_PANEL_ID),
7558
7604
  applyRightbar: ({ shown, track, fullscreen }) => {
@@ -7571,7 +7617,8 @@ function mount(ctx) {
7571
7617
  ctx.layout.openRightbar(true, false);
7572
7618
  },
7573
7619
  openPanel: (step) => store.open(step),
7574
- goToPanel: (index) => store.goTo(index)
7620
+ goToPanel: (index) => store.goTo(index),
7621
+ buildModule
7575
7622
  };
7576
7623
  const rightbarHooks = { hooks: { rightbar: observable } };
7577
7624
  const sidebarRight = () => ctx.get("sidebarRight");
@@ -7716,6 +7763,12 @@ function mount(ctx) {
7716
7763
  })
7717
7764
  }, Sidebar));
7718
7765
  registerMarketPanel(ctx, units);
7766
+ ctx.effect(() => {
7767
+ const workshop = workshopWorkspace();
7768
+ if (workshop === void 0) return;
7769
+ const title = ctx.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workshop.workspaceId)?.title;
7770
+ if (title !== void 0 && WORKSHOP_PAST_TITLES.includes(title) && title !== "工作台DIY") ctx.workspaces.rename(workshop.workspaceId, WORKSHOP_TITLE).catch(() => void 0);
7771
+ }, "dsh-workbench: 工坊那一行的旧名字换成新名字");
7719
7772
  const gate = createBootGate(ctx);
7720
7773
  ctx.effect(() => () => gate.close(), "dsh-workbench: env gate");
7721
7774
  ctx.slots.inject("conversation.approval.detail", () => ctx.slots.register({
@@ -7785,5 +7838,9 @@ function sidebarChildren(ctx) {
7785
7838
  function menuOpenStateFactory(_standard, state) {
7786
7839
  return () => state;
7787
7840
  }
7841
+ function sessionCreateOf(remote) {
7842
+ const namespaces = remote?.namespaces;
7843
+ return namespaces?.get?.("session")?.service?.create?.bind(namespaces.get("session")?.service);
7844
+ }
7788
7845
  //#endregion
7789
7846
  export { apply, inject, kit };