@syncended/dsh-automations 0.1.2 → 0.2.1

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
@@ -8,7 +8,7 @@ A DeepSeek Harness plugin for durable, configurable cron jobs. Each occurrence s
8
8
 
9
9
  - Standard five-field cron expressions with `UTC` or IANA timezones.
10
10
  - Per-job project directory, provider/model, reasoning effort, agent preset, permission preset, and timeout.
11
- - Enable/disable, Run now, edit, delete, cancel, and recent run history in **Settings → Automations**.
11
+ - Enable/disable, Run now, edit, delete, cancel, and recent run history from the main **Automations** sidebar action or **Settings → Automations**.
12
12
  - Overlap policies:
13
13
  - `skip` — record and skip an occurrence while the job has queued/running work.
14
14
  - `queue` — serialize occurrences for the same job.
@@ -42,7 +42,7 @@ pnpm build
42
42
  dsh plugin --profile web add .
43
43
  ```
44
44
 
45
- The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open **Settings → Automations**.
45
+ The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open **Automations** from the main sidebar, or use **Settings → Automations**.
46
46
 
47
47
  To remove it:
48
48
 
@@ -15,7 +15,7 @@ Non-goals for the first release:
15
15
  ## Components
16
16
 
17
17
  ```text
18
- Settings UI / HTTP API
18
+ Sidebar / Settings UI / HTTP API
19
19
 
20
20
 
21
21
  AutomationService ─── ProjectPolicy
@@ -28,6 +28,10 @@ Settings UI / HTTP API
28
28
  └── HarnessAgentExecutor (MVP)
29
29
  ```
30
30
 
31
+ ### Browser surfaces
32
+
33
+ The same automation page is available through two additive DSH extension points: `settings.section` keeps the configuration page inside Settings, while `sidebar.footer.action` opens a frame-wide `shell.overlay`. A small client-only disclosure store coordinates the sidebar trigger and overlay; neither surface owns scheduler state, and both read the same package HTTP API.
34
+
31
35
  ### AutomationService
32
36
 
33
37
  Cordis service `ctx.automations`. It owns input validation, canonical project authorization, metadata discovery, the Web route, and the public executor-registration seam.
package/lib/client.js CHANGED
@@ -12,7 +12,7 @@ window.__ModuleLoader__.load({
12
12
  // x-dsh-automation-client fence header plus an application/json body.
13
13
  const React = require("react");
14
14
  const h = React.createElement;
15
- const { useCallback, useEffect, useRef, useState } = React;
15
+ const { useCallback, useEffect, useId, useRef, useState, useSyncExternalStore } = React;
16
16
  const inject = ["slots"];
17
17
 
18
18
  const API_PREFIX = "/api/automations";
@@ -66,6 +66,31 @@ window.__ModuleLoader__.load({
66
66
  return error instanceof Error ? error.message : String(error);
67
67
  }
68
68
 
69
+ const CJK_LABEL_PATTERN = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;
70
+ const BUILTIN_AGENT_PRESET_LABELS = {
71
+ standard: "Standard mode",
72
+ code: "PTC mode",
73
+ minimal: "Minimal mode",
74
+ cordis: "Creator mode",
75
+ };
76
+
77
+ function humanizePresetId(id) {
78
+ return id
79
+ .split(/[-_]+/)
80
+ .filter(Boolean)
81
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
82
+ .join(" ");
83
+ }
84
+
85
+ function agentPresetDisplayLabel(preset) {
86
+ const id = preset && typeof preset.id === "string" ? preset.id.trim() : "";
87
+ const name = preset && typeof preset.name === "string" ? preset.name.trim() : "";
88
+ if (id === "") return name !== "" && !CJK_LABEL_PATTERN.test(name) ? name : "Unknown preset";
89
+ if (name !== "" && name !== id && !CJK_LABEL_PATTERN.test(name)) return name + " (" + id + ")";
90
+ const readableId = BUILTIN_AGENT_PRESET_LABELS[id] || humanizePresetId(id) || id;
91
+ return readableId === id ? id : readableId + " (" + id + ")";
92
+ }
93
+
69
94
  function browserTimezone() {
70
95
  return BROWSER_TIMEZONE;
71
96
  }
@@ -443,7 +468,7 @@ window.__ModuleLoader__.load({
443
468
  h(
444
469
  "option",
445
470
  { key: preset.id, value: preset.id },
446
- preset.name + (preset.broken ? " (broken: " + preset.broken + ")" : ""),
471
+ agentPresetDisplayLabel(preset) + (preset.broken ? " (broken: " + preset.broken + ")" : ""),
447
472
  ),
448
473
  ),
449
474
  ),
@@ -559,7 +584,10 @@ window.__ModuleLoader__.load({
559
584
  ? meta.agentPresets.find((preset) => preset.id === job.execution.agentPreset)
560
585
  : undefined;
561
586
  const presetLabel = job.execution.agentPreset
562
- ? (agentPreset ? agentPreset.name : job.execution.agentPreset)
587
+ ? agentPresetDisplayLabel(agentPreset || {
588
+ id: job.execution.agentPreset,
589
+ name: job.execution.agentPreset,
590
+ })
563
591
  : "";
564
592
 
565
593
  return h(
@@ -1139,7 +1167,242 @@ window.__ModuleLoader__.load({
1139
1167
  );
1140
1168
  }
1141
1169
 
1170
+ function createDisclosureStore() {
1171
+ let open = false;
1172
+ let disposed = false;
1173
+ const listeners = new Set();
1174
+ const publish = (next) => {
1175
+ if (disposed || open === next) return;
1176
+ open = next;
1177
+ for (const listener of Array.from(listeners)) listener();
1178
+ };
1179
+ return {
1180
+ getSnapshot: () => open,
1181
+ subscribe: (listener) => {
1182
+ if (disposed) return () => {};
1183
+ listeners.add(listener);
1184
+ return () => listeners.delete(listener);
1185
+ },
1186
+ open: () => publish(true),
1187
+ close: () => publish(false),
1188
+ toggle: () => publish(!open),
1189
+ dispose: () => {
1190
+ disposed = true;
1191
+ open = false;
1192
+ listeners.clear();
1193
+ },
1194
+ };
1195
+ }
1196
+
1197
+ const MODAL_FOCUS_SELECTOR = [
1198
+ "a[href]",
1199
+ "button:not([disabled])",
1200
+ "input:not([disabled])",
1201
+ "select:not([disabled])",
1202
+ "textarea:not([disabled])",
1203
+ "[contenteditable=\"true\"]",
1204
+ "[tabindex]:not([tabindex=\"-1\"])",
1205
+ ].join(",");
1206
+
1207
+ function modalFocusables(panel) {
1208
+ if (!panel) return [];
1209
+ return Array.from(panel.querySelectorAll(MODAL_FOCUS_SELECTOR)).filter((element) =>
1210
+ !element.hasAttribute("hidden") &&
1211
+ element.getAttribute("aria-hidden") !== "true" &&
1212
+ element.getClientRects().length > 0,
1213
+ );
1214
+ }
1215
+
1216
+ function trapModalTab(event, panel) {
1217
+ if (
1218
+ event.key !== "Tab" ||
1219
+ event.defaultPrevented ||
1220
+ event.altKey ||
1221
+ event.ctrlKey ||
1222
+ event.metaKey
1223
+ ) return;
1224
+ const focusables = modalFocusables(panel);
1225
+ if (focusables.length === 0) {
1226
+ event.preventDefault();
1227
+ panel?.focus();
1228
+ return;
1229
+ }
1230
+ const first = focusables[0];
1231
+ const last = focusables[focusables.length - 1];
1232
+ const active = panel.ownerDocument.activeElement;
1233
+ if (event.shiftKey) {
1234
+ if (active === first || !panel.contains(active)) {
1235
+ event.preventDefault();
1236
+ last.focus();
1237
+ }
1238
+ return;
1239
+ }
1240
+ if (active === last || !panel.contains(active)) {
1241
+ event.preventDefault();
1242
+ first.focus();
1243
+ }
1244
+ }
1245
+
1246
+ function AutomationGlyph({ size = 18 }) {
1247
+ return h(
1248
+ "svg",
1249
+ {
1250
+ width: size,
1251
+ height: size,
1252
+ viewBox: "0 0 24 24",
1253
+ fill: "none",
1254
+ stroke: "currentColor",
1255
+ strokeWidth: "1.7",
1256
+ strokeLinecap: "round",
1257
+ strokeLinejoin: "round",
1258
+ "aria-hidden": "true",
1259
+ focusable: "false",
1260
+ },
1261
+ h("rect", { x: "3.5", y: "5.5", width: "17", height: "15", rx: "3" }),
1262
+ h("path", { d: "M8 3.5v4M16 3.5v4M3.5 10h17" }),
1263
+ h("circle", { cx: "12", cy: "15.25", r: "2.75" }),
1264
+ h("path", { d: "M12 13.8v1.65l1.15.7" }),
1265
+ );
1266
+ }
1267
+
1268
+ function CloseGlyph() {
1269
+ return h(
1270
+ "svg",
1271
+ {
1272
+ width: "16",
1273
+ height: "16",
1274
+ viewBox: "0 0 16 16",
1275
+ fill: "none",
1276
+ stroke: "currentColor",
1277
+ strokeWidth: "1.5",
1278
+ strokeLinecap: "round",
1279
+ "aria-hidden": "true",
1280
+ focusable: "false",
1281
+ },
1282
+ h("path", { d: "M3.5 3.5l9 9M12.5 3.5l-9 9" }),
1283
+ );
1284
+ }
1285
+
1286
+ function AutomationsSidebarAction({ wide, disclosure }) {
1287
+ const open = useSyncExternalStore(
1288
+ disclosure.subscribe,
1289
+ disclosure.getSnapshot,
1290
+ disclosure.getSnapshot,
1291
+ );
1292
+ const triggerRef = useRef(null);
1293
+ const previousOpenRef = useRef(open);
1294
+
1295
+ useEffect(() => {
1296
+ const previous = previousOpenRef.current;
1297
+ previousOpenRef.current = open;
1298
+ if (!previous || open) return undefined;
1299
+ const frame = window.requestAnimationFrame(() => triggerRef.current?.focus());
1300
+ return () => window.cancelAnimationFrame(frame);
1301
+ }, [open]);
1302
+
1303
+ return h(
1304
+ "div",
1305
+ { className: "dsh-auto-sidebar-action" + (wide ? "" : " dsh-auto-sidebar-action-rail") },
1306
+ h(
1307
+ "button",
1308
+ {
1309
+ ref: triggerRef,
1310
+ type: "button",
1311
+ className: "dsh-auto-sidebar-trigger",
1312
+ title: wide ? undefined : "Automations",
1313
+ "aria-label": "Automations",
1314
+ "aria-haspopup": "dialog",
1315
+ "aria-expanded": open,
1316
+ "data-active": open ? "true" : undefined,
1317
+ "data-dsh-automations-trigger": "true",
1318
+ onClick: disclosure.toggle,
1319
+ },
1320
+ h(AutomationGlyph, { size: wide ? 16 : 18 }),
1321
+ wide ? h("span", { className: "dsh-auto-sidebar-label" }, "Automations") : null,
1322
+ ),
1323
+ );
1324
+ }
1325
+
1326
+ function AutomationsOverlay({ disclosure }) {
1327
+ const open = useSyncExternalStore(
1328
+ disclosure.subscribe,
1329
+ disclosure.getSnapshot,
1330
+ disclosure.getSnapshot,
1331
+ );
1332
+ const closeRef = useRef(null);
1333
+ const panelRef = useRef(null);
1334
+ const titleId = useId();
1335
+
1336
+ useEffect(() => {
1337
+ if (!open) return undefined;
1338
+ const frame = window.requestAnimationFrame(() => closeRef.current?.focus());
1339
+ return () => window.cancelAnimationFrame(frame);
1340
+ }, [open]);
1341
+
1342
+ if (!open) return null;
1343
+ return h(
1344
+ "div",
1345
+ { className: "dsh-auto-overlay", "data-dsh-automations-overlay": "true" },
1346
+ h("div", { className: "dsh-auto-overlay-mask", "aria-hidden": "true", onClick: disclosure.close }),
1347
+ h(
1348
+ "section",
1349
+ {
1350
+ ref: panelRef,
1351
+ className: "dsh-auto-overlay-panel",
1352
+ role: "dialog",
1353
+ tabIndex: -1,
1354
+ "aria-modal": "true",
1355
+ "aria-labelledby": titleId,
1356
+ onKeyDownCapture: (event) => {
1357
+ if (event.key === "Escape") {
1358
+ event.preventDefault();
1359
+ disclosure.close();
1360
+ return;
1361
+ }
1362
+ trapModalTab(event, panelRef.current);
1363
+ },
1364
+ },
1365
+ h(
1366
+ "header",
1367
+ { className: "dsh-auto-overlay-header" },
1368
+ h("span", { id: titleId, className: "dsh-auto-sr-only" }, "Automations"),
1369
+ h(
1370
+ "button",
1371
+ {
1372
+ ref: closeRef,
1373
+ type: "button",
1374
+ className: "dsh-auto-overlay-close",
1375
+ "aria-label": "Close Automations",
1376
+ title: "Close",
1377
+ onClick: disclosure.close,
1378
+ },
1379
+ h(CloseGlyph),
1380
+ ),
1381
+ ),
1382
+ h("div", { className: "dsh-auto-overlay-body" }, h(AutomationsSection)),
1383
+ ),
1384
+ );
1385
+ }
1386
+
1142
1387
  const STYLE_CSS = [
1388
+ ".dsh-auto-sidebar-action{box-sizing:border-box;width:100%;height:42px;flex:none;display:flex;align-items:center;margin:4px 0 0;}",
1389
+ ".dsh-auto-sidebar-trigger{box-sizing:border-box;appearance:none;width:calc(100% + 4px);height:42px;margin:0 -2px;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#0f1115);display:flex;align-items:center;gap:8px;overflow:hidden;font:14px/22px inherit;cursor:pointer;}",
1390
+ ".dsh-auto-sidebar-trigger:hover,.dsh-auto-sidebar-trigger[data-active=\"true\"]{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));}",
1391
+ ".dsh-auto-sidebar-trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4176e6);outline-offset:-2px;}",
1392
+ ".dsh-auto-sidebar-trigger svg{flex:none;}",
1393
+ ".dsh-auto-sidebar-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
1394
+ ".dsh-auto-sidebar-action-rail{width:36px;height:36px;margin:0;}",
1395
+ ".dsh-auto-sidebar-action-rail .dsh-auto-sidebar-trigger{width:36px;height:36px;margin:0;padding:0;justify-content:center;gap:0;border-radius:50%;}",
1396
+ ".dsh-auto-overlay{z-index:1000;pointer-events:auto;position:fixed;inset:0;display:flex;align-items:center;justify-content:center;}",
1397
+ ".dsh-auto-overlay-mask{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.46));backdrop-filter:var(--dsw-mask-blur,blur(2px));}",
1398
+ ".dsh-auto-overlay-panel{box-sizing:border-box;z-index:1;position:relative;width:900px;max-width:calc(100vw - 48px);height:min(800px,calc(100vh - 48px));border:0;border-radius:24px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:var(--dsw-shadow-lv3,0 18px 60px rgba(0,0,0,.3));color:var(--dsw-alias-label-primary,#0f1115);display:flex;flex-direction:column;overflow:hidden;}",
1399
+ ".dsh-auto-overlay-header{box-sizing:border-box;height:52px;flex:none;display:flex;align-items:center;justify-content:flex-end;padding:10px 16px;}",
1400
+ ".dsh-auto-overlay-close{appearance:none;width:30px;height:30px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary,#4f5661);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;}",
1401
+ ".dsh-auto-overlay-close:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));color:var(--dsw-alias-label-primary,#0f1115);}",
1402
+ ".dsh-auto-overlay-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4176e6);outline-offset:1px;}",
1403
+ ".dsh-auto-overlay-body{box-sizing:border-box;min-height:0;flex:1;padding:0 28px 28px;overflow-y:auto;overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
1404
+ ".dsh-auto-overlay-body>.dsh-auto-root{width:100%;margin:0 auto;padding-top:0;}",
1405
+ ".dsh-auto-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important;}",
1143
1406
  ".dsh-auto-root{--dsh-auto-border:var(--dsw-alias-border-l2,rgba(15,17,21,.14));--dsh-auto-border-strong:var(--dsw-alias-border-l3,rgba(15,17,21,.2));--dsh-auto-surface:var(--dsw-alias-bg-layer-3,#fff);--dsh-auto-surface-active:var(--dsw-alias-bg-layer-2,#fff);--dsh-auto-input-bg:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1,#fff));--dsh-auto-text:var(--dsw-alias-label-primary,#0f1115);--dsh-auto-text-secondary:var(--dsw-alias-label-secondary,#4f5661);--dsh-auto-muted:var(--dsw-alias-label-tertiary,#81858c);--dsh-auto-caption:var(--dsw-alias-label-caption,#adb2b8);--dsh-auto-accent:var(--dsw-alias-state-business-primary,#4176e6);--dsh-auto-primary-fill:var(--dsw-alias-button-primary-fill,#0f1115);--dsh-auto-primary-hover:var(--dsw-alias-button-primary-hover,#34415b);--dsh-auto-on-primary:var(--dsw-alias-label-primary-foreground,#fff);--dsh-auto-danger:var(--dsw-alias-state-error-primary,#ec1313);--dsh-auto-success:var(--dsw-alias-state-success-primary,#22c55e);--dsh-auto-warning:var(--dsw-alias-state-warn-primary,#f59e0b);box-sizing:border-box;max-width:820px;padding-top:12px;display:flex;flex-direction:column;gap:16px;font-family:inherit;color:var(--dsh-auto-text);}",
1144
1407
  "body:not([data-ds-dark-theme]) .dsh-auto-root{color-scheme:light;}",
1145
1408
  "body[data-ds-dark-theme] .dsh-auto-root{color-scheme:dark;}",
@@ -1225,12 +1488,13 @@ window.__ModuleLoader__.load({
1225
1488
  "@keyframes dsh-auto-pulse{0%,100%{opacity:1}50%{opacity:.35}}",
1226
1489
  ".dsh-auto-empty,.dsh-auto-loading,.dsh-auto-error{padding:22px 16px;text-align:center;border:1px dashed var(--dsh-auto-border);border-radius:12px;font-size:13px;color:var(--dsh-auto-text-secondary);}",
1227
1490
  ".dsh-auto-error{color:var(--dsh-auto-danger);display:flex;flex-direction:column;gap:10px;align-items:center;}",
1228
- "@media (max-width:640px){.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
1491
+ "@media (max-width:640px){.dsh-auto-overlay-panel{max-width:calc(100vw - 16px);height:calc(100vh - 16px);border-radius:16px;}.dsh-auto-overlay-header{height:46px;padding:8px 10px;}.dsh-auto-overlay-body{padding:0 16px 16px;}.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
1229
1492
  ].join("\n");
1230
1493
 
1231
1494
  function apply(ctx) {
1232
- // The page styles ride a style element owned by this plugin's fiber:
1233
- // created now and removed when the plugin unloads.
1495
+ const disclosure = createDisclosureStore();
1496
+ // All package-owned surfaces share one style element and one disclosure
1497
+ // store; both are released with the client-plugin fiber.
1234
1498
  ctx.effect(() => {
1235
1499
  const tag = document.createElement("style");
1236
1500
  tag.setAttribute("data-plugin", "@syncended/dsh-automations");
@@ -1239,15 +1503,31 @@ window.__ModuleLoader__.load({
1239
1503
  return () => {
1240
1504
  tag.remove();
1241
1505
  };
1242
- }, "@syncended/dsh-automations: settings page styles");
1506
+ }, "@syncended/dsh-automations: client styles");
1507
+ ctx.effect(() => () => disclosure.dispose(), "@syncended/dsh-automations: disclosure store");
1243
1508
  ctx.slots.inject("settings.section", () => ctx.slots.register({
1244
1509
  name: "settings.section",
1245
1510
  id: "automations",
1246
1511
  order: 25,
1247
1512
  label: "Automations",
1248
1513
  }, AutomationsSection));
1514
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
1515
+ name: "sidebar.footer.action",
1516
+ id: "automations",
1517
+ order: 50,
1518
+ label: "Automations",
1519
+ inject: () => ({ disclosure }),
1520
+ }, AutomationsSidebarAction));
1521
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
1522
+ name: "shell.overlay",
1523
+ id: "automations",
1524
+ order: 50,
1525
+ label: "Automations",
1526
+ inject: () => ({ disclosure }),
1527
+ }, AutomationsOverlay));
1249
1528
  }
1250
1529
 
1530
+ exports.agentPresetDisplayLabel = agentPresetDisplayLabel;
1251
1531
  exports.inject = inject;
1252
1532
  exports.apply = apply;
1253
1533
  return module.exports;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncended/dsh-automations",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Durable cron automations for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,6 +29,8 @@
29
29
  "client": {
30
30
  "inject": [
31
31
  "@deepseek-ai/dsh-client-runtime",
32
+ "@deepseek-ai/dsh-client-ui-layout",
33
+ "@deepseek-ai/dsh-client-ui-sidebar",
32
34
  "@deepseek-ai/dsh-client-ui-settings"
33
35
  ],
34
36
  "platform": "web"
@@ -80,7 +82,9 @@
80
82
  "@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.2",
81
83
  "@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.2",
82
84
  "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
85
+ "@deepseek-ai/dsh-client-ui-layout": "^0.1.1-rc.2",
83
86
  "@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
87
+ "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.1-rc.2",
84
88
  "@deepseek-ai/dsh-host-webserver": "^0.1.1-rc.2",
85
89
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
86
90
  "@deepseek-ai/dsh-permission-presets": "^0.1.1-rc.2",
@@ -93,7 +97,9 @@
93
97
  "@deepseek-ai/dsh-agent-default-model": "0.1.1-rc.2",
94
98
  "@deepseek-ai/dsh-agent-presets": "0.1.1-rc.2",
95
99
  "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
100
+ "@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2",
96
101
  "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
102
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.1.1-rc.2",
97
103
  "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
98
104
  "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
99
105
  "@deepseek-ai/dsh-permission-presets": "0.1.1-rc.2",