dsh-coding-sidebar 1.0.2 → 1.0.4

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 (96) hide show
  1. package/README.md +27 -42
  2. package/lib/client-editor.js +449 -4278
  3. package/lib/client-registry.js +641 -1343
  4. package/lib/client-terminal.js +172 -262
  5. package/lib/client.js +645 -1347
  6. package/lib/index.js +24 -122
  7. package/lib/types/bundle-route.d.ts +1 -1
  8. package/lib/types/client/SideCardSection.d.ts +3 -3
  9. package/lib/types/client/TextEditor.d.ts +20 -10
  10. package/lib/types/client/add-plugin-modal.d.ts +0 -4
  11. package/lib/types/client/api.d.ts +8 -11
  12. package/lib/types/client/builtins/index.d.ts +10 -10
  13. package/lib/types/client/chunk-loader.d.ts +7 -8
  14. package/lib/types/client/locales.d.ts +0 -26
  15. package/lib/types/client/native-avoid.d.ts +2 -0
  16. package/lib/types/client/plugins-shared.d.ts +6 -6
  17. package/lib/types/client/service.d.ts +13 -83
  18. package/lib/types/context-types.d.ts +19 -10
  19. package/lib/types/index.d.ts +1 -1
  20. package/lib/types/prefs-shared.d.ts +1 -24
  21. package/package.json +26 -30
  22. package/src/bundle-route.ts +1 -1
  23. package/src/client/EditorHost.tsx +52 -122
  24. package/src/client/SandboxStatusBar.tsx +12 -9
  25. package/src/client/SideCardSection.module.css +2 -2
  26. package/src/client/SideCardSection.tsx +28 -81
  27. package/src/client/SideChatView.module.css +12 -12
  28. package/src/client/TextEditor.tsx +89 -266
  29. package/src/client/add-plugin-modal.tsx +16 -24
  30. package/src/client/api.ts +1 -25
  31. package/src/client/builtins/index.ts +10 -14
  32. package/src/client/chunk-loader.ts +7 -8
  33. package/src/client/index.tsx +12 -3
  34. package/src/client/locales-ar.ts +0 -6
  35. package/src/client/locales-de.ts +0 -6
  36. package/src/client/locales-fr.ts +0 -6
  37. package/src/client/locales-hi.ts +0 -6
  38. package/src/client/locales-id.ts +0 -6
  39. package/src/client/locales-it.ts +0 -6
  40. package/src/client/locales-ja.ts +0 -6
  41. package/src/client/locales-ko.ts +0 -6
  42. package/src/client/locales-nl.ts +0 -6
  43. package/src/client/locales-pl.ts +0 -6
  44. package/src/client/locales-pt.ts +0 -6
  45. package/src/client/locales-ru.ts +0 -6
  46. package/src/client/locales-sv.ts +0 -6
  47. package/src/client/locales-th.ts +0 -6
  48. package/src/client/locales-tr.ts +0 -6
  49. package/src/client/locales-vi.ts +0 -6
  50. package/src/client/locales-zh-HK.ts +0 -6
  51. package/src/client/locales-zh-MO.ts +0 -6
  52. package/src/client/locales-zh-TW.ts +0 -6
  53. package/src/client/locales.ts +0 -52
  54. package/src/client/native-avoid.ts +155 -0
  55. package/src/client/plugins-shared.ts +6 -6
  56. package/src/client/prefs.ts +0 -7
  57. package/src/client/service.ts +13 -150
  58. package/src/client/sidebar.module.css +1 -425
  59. package/src/config.ts +1 -4
  60. package/src/context-types.ts +12 -7
  61. package/src/index.ts +12 -78
  62. package/src/jobs-routes.ts +3 -2
  63. package/src/prefs-shared.ts +1 -27
  64. package/src/sidechat-routes.ts +13 -8
  65. package/src/subagent-live-route.ts +2 -1
  66. package/lib/client-mermaid.js +0 -200753
  67. package/lib/types/client/MarkdownHtml.d.ts +0 -32
  68. package/lib/types/client/PdfView.d.ts +0 -6
  69. package/lib/types/client/builtins/viewers.d.ts +0 -3
  70. package/lib/types/client/chunks/mermaid.d.ts +0 -10
  71. package/lib/types/client/editor-load.d.ts +0 -66
  72. package/lib/types/client/image-types.d.ts +0 -3
  73. package/lib/types/client/markdown-html.d.ts +0 -96
  74. package/lib/types/client/markdown-images.d.ts +0 -45
  75. package/lib/types/client/md-toc.d.ts +0 -4
  76. package/lib/types/client/mermaid-blocks.d.ts +0 -47
  77. package/lib/types/client/mermaid-sanitize.d.ts +0 -2
  78. package/lib/types/client/mermaid.d.ts +0 -12
  79. package/lib/types/client/pdf-types.d.ts +0 -2
  80. package/lib/types/client/plugins-viewers.d.ts +0 -3
  81. package/lib/types/html-route.d.ts +0 -59
  82. package/src/client/MarkdownHtml.tsx +0 -296
  83. package/src/client/PdfView.tsx +0 -110
  84. package/src/client/builtins/viewers.tsx +0 -125
  85. package/src/client/chunks/mermaid.tsx +0 -10
  86. package/src/client/editor-load.ts +0 -92
  87. package/src/client/image-types.ts +0 -8
  88. package/src/client/markdown-html.ts +0 -331
  89. package/src/client/markdown-images.ts +0 -137
  90. package/src/client/md-toc.tsx +0 -127
  91. package/src/client/mermaid-blocks.ts +0 -110
  92. package/src/client/mermaid-sanitize.ts +0 -93
  93. package/src/client/mermaid.tsx +0 -406
  94. package/src/client/pdf-types.ts +0 -4
  95. package/src/client/plugins-viewers.ts +0 -30
  96. package/src/html-route.ts +0 -106
@@ -76,7 +76,7 @@
76
76
  .count {
77
77
  padding: 1px 8px;
78
78
  border-radius: 999px;
79
- background: var(--dsw-alias-accent-soft, var(--dsw-alias-bg-layer-2));
79
+ background: var(--dsw-alias-bg-layer-2);
80
80
  font-size: 11px;
81
81
  line-height: 16px;
82
82
  font-weight: 500;
@@ -836,7 +836,7 @@
836
836
  .versionBadgeTag {
837
837
  padding: 1px 8px;
838
838
  border-radius: 999px;
839
- background: var(--dsw-alias-accent-soft, var(--dsw-alias-border-l2));
839
+ background: var(--dsw-alias-border-l2);
840
840
  color: var(--dsw-alias-label-secondary);
841
841
  font-variant-numeric: tabular-nums;
842
842
  }
@@ -12,8 +12,9 @@
12
12
  * external plugins alike), laid out in a responsive grid that wraps
13
13
  * several cards per row — icon chip + title + type id, clicked to toggle
14
14
  * the switch persisted in `prefs.tabsEnabled[id]`.
15
- * - 文件预览: one SMALL CARD per REGISTERED file viewer — icon chip + title
16
- * + the extensions it covers, clicked to toggle `prefs.viewersEnabled[id]`.
15
+ *
16
+ * (v1.0.4: the 文件预览 viewer inventory was retired with the file-viewer
17
+ * registry — file preview is the host's job now.)
17
18
  *
18
19
  * Every group lives in a container card (the DSH PluginCard recipe: l2
19
20
  * hairline, 16px radius, layer-3 fill) with a heading and an inventory count
@@ -64,14 +65,13 @@ import {
64
65
  } from '../prefs-shared.ts'
65
66
  import { api } from './api.ts'
66
67
  import { parsePrefs } from './prefs.ts'
67
- import { AddPluginModal, type PluginKind } from './add-plugin-modal.tsx'
68
+ import { AddPluginModal } from './add-plugin-modal.tsx'
68
69
  import { t } from './locales.ts'
69
70
  import { parseDesktopEnv } from './desktop-env.ts'
70
71
  import { getShellPreset, getShellPresets } from './shell-presets.ts'
71
72
  import type { SidebarStore } from './state.ts'
72
73
  import type {
73
74
  BetterSidebarService,
74
- FileViewerDescriptor,
75
75
  SidebarSettingsRenderProps,
76
76
  SidebarSettingToggle,
77
77
  TabDescriptor,
@@ -124,13 +124,8 @@ function titleBarSchemeValue(prefs: SidebarPrefs): string {
124
124
  return preset !== undefined ? `preset:${preset.id}` : 'auto'
125
125
  }
126
126
 
127
- /** Viewer inventory order: priority desc (the catch-all `code` comes last). */
128
- function viewerOrder(a: FileViewerDescriptor, b: FileViewerDescriptor): number {
129
- return (b.priority ?? 0) - (a.priority ?? 0)
130
- }
131
-
132
127
  /** Whether a feature declares any secondary settings (gear button shows). */
133
- function hasSettings(feature: TabDescriptor | FileViewerDescriptor): boolean {
128
+ function hasSettings(feature: TabDescriptor): boolean {
134
129
  const settings = feature.settings
135
130
  return settings !== undefined && (
136
131
  (settings.toggles?.length ?? 0) > 0
@@ -139,9 +134,9 @@ function hasSettings(feature: TabDescriptor | FileViewerDescriptor): boolean {
139
134
  )
140
135
  }
141
136
 
142
- /** A feature's display name (viewers fall back to their id). */
143
- function featureNameOf(feature: TabDescriptor | FileViewerDescriptor): string {
144
- return textOf('title' in feature ? feature.title : undefined) || feature.id
137
+ /** A feature's display name. */
138
+ function featureNameOf(feature: TabDescriptor): string {
139
+ return textOf(feature.title) || feature.id
145
140
  }
146
141
 
147
142
  /**
@@ -491,7 +486,7 @@ function SelectRow(props: {
491
486
  }
492
487
 
493
488
  /**
494
- * The secondary settings popup body of one feature (tab or viewer):
489
+ * The secondary settings popup body of one registered tab:
495
490
  * - the host-prefs `toggles` rows, then the plugin-owned `pluginToggles`
496
491
  * rows (their values live in `pluginSettings[feature.id]`, projected onto
497
492
  * the prefs face so the shared row renderer reads them);
@@ -501,7 +496,7 @@ function SelectRow(props: {
501
496
  * open-behavior picker) and still ship a custom configuration area.
502
497
  */
503
498
  export function SettingsBody(props: {
504
- feature: TabDescriptor | FileViewerDescriptor
499
+ feature: TabDescriptor
505
500
  prefs: SidebarPrefs
506
501
  store: SidebarStore
507
502
  service: BetterSidebarService
@@ -576,19 +571,18 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
576
571
  const [widthDraft, setWidthDraft] = useState<string>(String(store.getPrefs().defaultWidthPercent))
577
572
  const [error, setError] = useState<string | null>(null)
578
573
  // Which feature's secondary settings popup is open (null = closed).
579
- const [settingsFor, setSettingsFor] = useState<TabDescriptor | FileViewerDescriptor | null>(null)
574
+ const [settingsFor, setSettingsFor] = useState<TabDescriptor | null>(null)
580
575
  // Whether the position-compat strip popup (the gear on the 常规 row) is open.
581
576
  const [stripSettingsOpen, setStripSettingsOpen] = useState(false)
582
577
  // The parsed desktop environment (URL stamps — see desktop-env.ts). Used
583
578
  // ONLY to badge matching presets in the scheme dropdown ("已检测");
584
579
  // nothing is auto-applied.
585
580
  const detectedEnv = useMemo(() => parseDesktopEnv(), [])
586
- // Whether the "add plugin" modal (a dashed card at the end of the
587
- // 侧边栏内容 / 文件预览 grids) is open, and for which extension point
588
- // (null = closed).
589
- const [addPluginsOpen, setAddPluginsOpen] = useState<PluginKind | null>(null)
581
+ // Whether the "add plugin" modal (the dashed card at the end of the
582
+ // 侧边栏内容 grid) is open.
583
+ const [addPluginsOpen, setAddPluginsOpen] = useState(false)
590
584
  // The LATEST optimistic prefs, kept in sync with the state. Nested-map
591
- // merges (tabsEnabled / viewersEnabled / pluginSettings) MUST build from
585
+ // merges (tabsEnabled / pluginSettings) MUST build from
592
586
  // this ref, not from the render-time `prefs`: two same-tick writes (e.g.
593
587
  // a settings panel updating several plugin keys at once) would otherwise
594
588
  // both spread the stale map and the later patch would drop the earlier
@@ -596,14 +590,12 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
596
590
  const optimisticRef = useRef(prefs)
597
591
  useEffect(() => { optimisticRef.current = prefs }, [prefs])
598
592
 
599
- // The declarative inventory: the registered tab types and file viewers.
600
- // Local state + service.subscribe (registry changes are rare — plugin
601
- // load/unload — so a plain effect is enough; no external-store ceremony).
593
+ // The declarative inventory: the registered tab types. Local state +
594
+ // service.subscribe (registry changes are rare — plugin load/unload — so
595
+ // a plain effect is enough; no external-store ceremony).
602
596
  const [tabs, setTabs] = useState<TabDescriptor[]>(() => [...service.getTabs()].sort(tabOrder))
603
- const [viewers, setViewers] = useState<FileViewerDescriptor[]>(() => [...service.getFileViewers()].sort(viewerOrder))
604
597
  useEffect(() => service.subscribe(() => {
605
598
  setTabs([...service.getTabs()].sort(tabOrder))
606
- setViewers([...service.getFileViewers()].sort(viewerOrder))
607
599
  }), [service])
608
600
 
609
601
  // The settings document revision (guards concurrent writes). A ref: commits
@@ -682,11 +674,6 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
682
674
  applyPref({ tabsEnabled: { ...optimisticRef.current.tabsEnabled, [id]: next } })
683
675
  }
684
676
 
685
- /** Flip one per-viewer enable switch (merge into the viewersEnabled map). */
686
- const onToggleViewer = (id: string, next: boolean): void => {
687
- applyPref({ viewersEnabled: { ...optimisticRef.current.viewersEnabled, [id]: next } })
688
- }
689
-
690
677
  /** Flip one declaratively-declared toggle (a SidebarPrefs boolean field). */
691
678
  const onToggleSetting = (toggle: SidebarSettingToggle, next: boolean): void => {
692
679
  applyPref({ [toggle.key]: next })
@@ -1001,7 +988,7 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
1001
988
  <button
1002
989
  type="button"
1003
990
  className={clsx(css.card, css.addCard)}
1004
- onClick={() => { setAddPluginsOpen('tab') }}
991
+ onClick={() => { setAddPluginsOpen(true) }}
1005
992
  >
1006
993
  <span className={css.cardTop}>
1007
994
  <span className={css.cardIconChip}>
@@ -1014,45 +1001,6 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
1014
1001
  </div>
1015
1002
  </div>
1016
1003
 
1017
- {/* 文件预览: one small card per registered file viewer. */}
1018
- <div className={css.group}>
1019
- <div className={css.groupHeading}>
1020
- <span>{t('settingsViewersTitle')}</span>
1021
- <span className={css.count}>{viewers.length}</span>
1022
- </div>
1023
- <div className={css.grid}>
1024
- {viewers.map(viewer => (
1025
- <Fragment key={viewer.id}>
1026
- {renderCard({
1027
- title: textOf(viewer.title) || viewer.id,
1028
- desc: viewer.exts.length === 0 ? t('settingsViewerCatchAll') : viewer.exts.join(' · '),
1029
- icon: iconOf(viewer.icon, 16),
1030
- enabled: prefs.viewersEnabled[viewer.id] !== false,
1031
- onToggle: (next) => { onToggleViewer(viewer.id, next) },
1032
- onOpenSettings: prefs.viewersEnabled[viewer.id] !== false && hasSettings(viewer)
1033
- ? () => { setSettingsFor(viewer) }
1034
- : undefined,
1035
- })}
1036
- </Fragment>
1037
- ))}
1038
- {/* The "add preview plugin" entry: dashed card opening the
1039
- FILE-PREVIEWER registration modal. */}
1040
- <button
1041
- type="button"
1042
- className={clsx(css.card, css.addCard)}
1043
- onClick={() => { setAddPluginsOpen('viewer') }}
1044
- >
1045
- <span className={css.cardTop}>
1046
- <span className={css.cardIconChip}>
1047
- <IconPlusOutline16 size={16} />
1048
- </span>
1049
- <span className={css.cardTitle}>{t('addPluginsViewerCard')}</span>
1050
- </span>
1051
- <span className={css.cardDesc}>{t('addPluginsViewerCardDesc')}</span>
1052
- </button>
1053
- </div>
1054
- </div>
1055
-
1056
1004
  {/* The secondary settings popup: a feature's declared related settings
1057
1005
  as title/desc + switch rows in a wider-than-default Modal with a
1058
1006
  Done footer (Modal chrome is the app's own). Mounted only while a
@@ -1138,18 +1086,17 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
1138
1086
  </Modal>
1139
1087
  )}
1140
1088
 
1141
- {/* The "add plugin" modal (opened by the dashed cards above): declares
1142
- the extension point of the clicked kind, opens the GitHub topic,
1143
- and lists the matching recommended plugin catalog with per-entry
1144
- install buttons (the install flow opens a ~/.dsh terminal with
1145
- the command pre-typed; failures render inline here, in settings
1146
- only). Mounted only while open (Modal runs hooks unconditionally
1147
- — same SSR rule as the settings popup above). */}
1148
- {addPluginsOpen !== null && (
1089
+ {/* The "add plugin" modal (opened by the dashed card above): declares
1090
+ the tab extension point, opens the GitHub topic, and lists the
1091
+ recommended plugin catalog with per-entry install buttons (the
1092
+ install flow opens a ~/.dsh terminal with the command pre-typed;
1093
+ failures render inline here, in settings only). Mounted only while
1094
+ open (Modal runs hooks unconditionally — same SSR rule as the
1095
+ settings popup above). */}
1096
+ {addPluginsOpen && (
1149
1097
  <AddPluginModal
1150
1098
  service={service}
1151
- onClose={() => { setAddPluginsOpen(null) }}
1152
- kind={addPluginsOpen}
1099
+ onClose={() => { setAddPluginsOpen(false) }}
1153
1100
  />
1154
1101
  )}
1155
1102
 
@@ -23,7 +23,7 @@
23
23
  gap: 4px;
24
24
  min-height: 36px;
25
25
  padding: 4px 8px 4px 12px;
26
- border-bottom: 1px solid var(--dsw-alias-hairline);
26
+ border-bottom: 1px solid var(--dsw-alias-border-l);
27
27
  }
28
28
 
29
29
  .sidechatHeaderDot {
@@ -39,7 +39,7 @@
39
39
  flex: none;
40
40
  max-width: 55%;
41
41
  padding: 1px 8px;
42
- border: 1px solid var(--dsw-alias-hairline);
42
+ border: 1px solid var(--dsw-alias-border-l);
43
43
  border-radius: 999px;
44
44
  font: var(--dsw-font-xxs-12);
45
45
  color: var(--dsw-alias-label-tertiary);
@@ -108,9 +108,9 @@
108
108
  padding: 6px 14px;
109
109
  border: none;
110
110
  border-radius: 999px;
111
- background: var(--dsw-alias-button-info-fill, var(--dsw-alias-accent));
112
- color: var(--dsw-alias-button-info-label, var(--dsw-alias-accent-ink, #fff));
113
- font: var(--dsw-font-s-13);
111
+ background: var(--dsw-alias-button-info-fill, var(--dsw-alias-interactive-bg-hover-solid));
112
+ color: #fff;
113
+ font: var(--dsw-font-s-14);
114
114
  cursor: pointer;
115
115
  transition: opacity 100ms ease-out;
116
116
  }
@@ -135,7 +135,7 @@
135
135
  flex: none;
136
136
  padding: 4px 12px;
137
137
  font: var(--dsw-font-xxs-12);
138
- color: var(--dsw-alias-danger);
138
+ color: #d5304d;
139
139
  }
140
140
 
141
141
  /* ── transcript ─────────────────────────────────────────────────────── */
@@ -246,13 +246,13 @@
246
246
 
247
247
  .sidechatRowFailed .sidechatRowLabel,
248
248
  .sidechatRowFailed .sidechatRowMeta {
249
- color: var(--dsw-alias-danger);
249
+ color: #d5304d;
250
250
  }
251
251
 
252
252
  .sidechatRowBody {
253
253
  margin: 2px 0 4px 7px;
254
254
  padding: 2px 0 2px 10px;
255
- border-left: 1px solid var(--dsw-alias-hairline);
255
+ border-left: 1px solid var(--dsw-alias-border-l);
256
256
  }
257
257
 
258
258
  .sidechatRowProse {
@@ -277,7 +277,7 @@
277
277
  }
278
278
 
279
279
  .sidechatRowCode + .sidechatRowCode {
280
- border-top: 1px solid var(--dsw-alias-hairline);
280
+ border-top: 1px solid var(--dsw-alias-border-l);
281
281
  }
282
282
 
283
283
  /* Shimmer sweep text: generating (streaming row labels, creating hero). */
@@ -328,7 +328,7 @@
328
328
  gap: 4px;
329
329
  margin: 0 8px 8px;
330
330
  padding: 8px 8px 6px 14px;
331
- border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-hairline));
331
+ border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-border-l));
332
332
  border-radius: 16px;
333
333
  background: var(--dsw-specific-input-major, var(--dsw-alias-bg-base));
334
334
  box-shadow: var(--dsw-shadow-lv2, none);
@@ -380,8 +380,8 @@
380
380
  padding: 0;
381
381
  border: none;
382
382
  border-radius: 50%;
383
- background: var(--dsw-alias-button-info-fill, var(--dsw-alias-accent));
384
- color: var(--dsw-alias-button-info-label, var(--dsw-alias-accent-ink, #fff));
383
+ background: var(--dsw-alias-button-info-fill, var(--dsw-alias-interactive-bg-hover-solid));
384
+ color: #fff;
385
385
  cursor: pointer;
386
386
  /* send ⇄ stop swap: keyed remount plays this, hover only fades. */
387
387
  animation: sidechatBtnIn 120ms ease-out;