dsh-novel-generator 0.1.1 → 0.1.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.
Files changed (2) hide show
  1. package/client.js +26 -16
  2. package/package.json +3 -2
package/client.js CHANGED
@@ -185,6 +185,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
185
185
  .dsn-input:focus,.dsn-select:focus,.dsn-textarea:focus{border-color:var(--dsw-alias-brand-primary)}
186
186
  .dsn-input.dsn-readonly{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);cursor:default}
187
187
  .dsn-input.dsn-readonly:focus{border-color:var(--dsw-alias-border-l1)}
188
+ .dsn-input.dsn-input-invalid{border-color:var(--dsw-alias-state-warn-primary)}
188
189
  .dsn-path{display:flex;gap:6px}
189
190
  .dsn-list{display:flex;flex-direction:column;gap:8px}
190
191
  .dsn-row{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:12px;
@@ -425,7 +426,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
425
426
  }, busy ? t('保存中…', "Saving…") : t('保存', "Save")))));
426
427
  }
427
428
 
428
- function ProjectsPage({ boot, workspace, onOpen, onReload, onEditModel }) {
429
+ function ProjectsPage({ boot, resolveWorkspace, onOpen, onReload, onEditModel }) {
429
430
  const [title, setTitle] = useState('');
430
431
  const [cwd, setCwd] = useState('');
431
432
  const [preset, setPreset] = useState('');
@@ -451,17 +452,20 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
451
452
  }, [models]);
452
453
 
453
454
  const pickDirectory = useCallback(async () => {
454
- if (!workspace || typeof workspace.pickDirectory !== 'function') {
455
- setError(t('当前界面无法调用目录选择器,这个部署暂时不能创建作品', "The directory picker is unavailable here, so this deployment cannot create works."));
455
+ // Resolved at click time: the workspace service may activate after this
456
+ // plugin, so an instance captured in `apply` can come back undefined.
457
+ const ui = typeof resolveWorkspace === 'function' ? resolveWorkspace() : null;
458
+ if (!ui || typeof ui.pickDirectory !== 'function') {
459
+ setError(t('目录选择器还没就绪,请稍后再点一次「选择」', 'The directory picker is not ready yet — try "Select" again in a moment.'));
456
460
  return;
457
461
  }
458
462
  try {
459
- const picked = await workspace.pickDirectory();
463
+ const picked = await ui.pickDirectory();
460
464
  if (picked) setCwd(picked);
461
465
  } catch (pickError) {
462
466
  setError(messageOf(pickError));
463
467
  }
464
- }, [workspace]);
468
+ }, [resolveWorkspace]);
465
469
 
466
470
  const create = useCallback(async () => {
467
471
  setError('');
@@ -502,13 +506,12 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
502
506
  h('label', { className: 'dsn-field' },
503
507
  h('span', { className: 'dsn-label' }, t('作品名称', "Title")),
504
508
  h('input', {
505
- className: 'dsn-input',
509
+ className: `dsn-input${titleIssue ? ' dsn-input-invalid' : ''}`,
506
510
  value: title,
507
511
  placeholder: t('例如:长夜将尽', "e.g. The Long Night Ends"),
512
+ title: titleIssue || t('会成为工作目录下的文件夹名', "Becomes a folder name inside the working directory."),
508
513
  onChange: (event) => setTitle(event.target.value),
509
- }),
510
- h('span', { className: `dsn-hint${titleIssue ? ' warn' : ''}` },
511
- titleIssue || t('会成为工作目录下的文件夹名', "Becomes a folder name inside the working directory."))),
514
+ })),
512
515
  h('label', { className: 'dsn-field' },
513
516
  h('span', { className: 'dsn-label' }, t('工作目录', "Working directory")),
514
517
  h('div', { className: 'dsn-path' },
@@ -557,7 +560,9 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
557
560
  onClick: create,
558
561
  }, busy ? t('创建中…', "Creating…") : t('创建作品并开会话', "Create work and open its session")))),
559
562
 
560
- error ? h('div', { className: 'dsn-error', style: { margin: 0 } }, error) : null,
563
+ error || titleIssue
564
+ ? h('div', { className: 'dsn-error', style: { margin: 0 } }, error || titleIssue)
565
+ : null,
561
566
 
562
567
  h('div', { className: 'dsn-list' },
563
568
  boot.projects.length === 0
@@ -1654,7 +1659,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1654
1659
 
1655
1660
  /* ------------------------------------------------------------ studio app */
1656
1661
 
1657
- function StudioApp({ workspace }) {
1662
+ function StudioApp({ resolveWorkspace }) {
1658
1663
  // Subscribes every screen below to Settings → General → Language.
1659
1664
  useLocaleId();
1660
1665
  const [boot, setBoot] = useState(null);
@@ -1742,7 +1747,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1742
1747
  ? h('div', { className: 'dsn-scroll' },
1743
1748
  h(ProjectsPage, {
1744
1749
  boot,
1745
- workspace,
1750
+ resolveWorkspace,
1746
1751
  onOpen: openProject,
1747
1752
  onReload: loadBoot,
1748
1753
  onEditModel: setModelTarget,
@@ -1772,12 +1777,12 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1772
1777
  : null);
1773
1778
  }
1774
1779
 
1775
- function StudioOverlay({ workspace }) {
1780
+ function StudioOverlay({ resolveWorkspace }) {
1776
1781
  const open = useOverlayOpen();
1777
1782
  if (!open) return null;
1778
1783
  // No backdrop-click close: leaving with unsaved chapter text goes through
1779
1784
  // the 关闭 button, which asks first.
1780
- return h('div', { className: 'dsn-overlay' }, h(StudioApp, { workspace }));
1785
+ return h('div', { className: 'dsn-overlay' }, h(StudioApp, { resolveWorkspace }));
1781
1786
  }
1782
1787
 
1783
1788
  /* ---------------------------------------------------------------- apply */
@@ -1785,7 +1790,12 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1785
1790
  return {
1786
1791
  inject: ['slots'],
1787
1792
  apply(ctx) {
1788
- const uiWorkspace = ctx.get('uiWorkspace');
1793
+ /**
1794
+ * Read at use time, not at activation: this plugin may mount before the
1795
+ * workspace UI that owns `uiWorkspace`, and a captured instance would
1796
+ * then be undefined for the life of the page.
1797
+ */
1798
+ const resolveWorkspace = () => ctx.get('uiWorkspace') || null;
1789
1799
  // Settings → General → Language drives every string that goes through
1790
1800
  // the translator below; a host without the service stays Chinese.
1791
1801
  localeService = ctx.get('locale') || null;
@@ -1798,7 +1808,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1798
1808
  name: 'shell.overlay',
1799
1809
  id: 'dsh-novel-generator-studio',
1800
1810
  order: 40,
1801
- }, () => h(StudioOverlay, { workspace: uiWorkspace })));
1811
+ }, () => h(StudioOverlay, { resolveWorkspace })));
1802
1812
  },
1803
1813
  };
1804
1814
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-novel-generator",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "Novel studio for DeepSeek Harness: a draggable story timeline, world snapshots, chapter outlines, and chapters written by the work's own agent.",
6
6
  "license": "MIT",
@@ -51,7 +51,8 @@
51
51
  "platform": "web",
52
52
  "immediately": true,
53
53
  "inject": [
54
- "@deepseek-ai/dsh-client-locale"
54
+ "@deepseek-ai/dsh-client-locale",
55
+ "@deepseek-ai/dsh-client-ui-workspace"
55
56
  ]
56
57
  }
57
58
  }