@chatcode/cco-better-sidebar 0.18.0-alpha.4 → 0.18.0-rc.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 (44) hide show
  1. package/README.md +3 -3
  2. package/README_EN.md +3 -3
  3. package/cordis.patch.yml +6 -5
  4. package/lib/client-editor.js +11140 -724
  5. package/lib/client-mermaid.js +10730 -317
  6. package/lib/client-registry.js +2258 -1652
  7. package/lib/client-terminal.js +257 -257
  8. package/lib/client.js +2254 -1648
  9. package/lib/index.js +61 -40
  10. package/lib/types/client/builtins/tabs.d.ts +9 -0
  11. package/lib/types/client/icons.d.ts +26 -8
  12. package/lib/types/client/service.d.ts +1 -1
  13. package/lib/types/config.d.ts +4 -3
  14. package/lib/types/context-types.d.ts +12 -14
  15. package/lib/types/prefs-shared.d.ts +1 -1
  16. package/lib/types/ui-tweaks/index.d.ts +2 -3
  17. package/package.json +1 -1
  18. package/src/client/BrowserView.tsx +1 -1
  19. package/src/client/DiffTab.tsx +1 -1
  20. package/src/client/EditorHost.tsx +1 -1
  21. package/src/client/FileTree.tsx +10 -5
  22. package/src/client/FreeWindow.tsx +2 -1
  23. package/src/client/GitView.tsx +7 -3
  24. package/src/client/SideCardSection.tsx +2 -8
  25. package/src/client/Sidebar.tsx +2 -2
  26. package/src/client/TabBar.tsx +2 -4
  27. package/src/client/TextEditor.tsx +2 -1
  28. package/src/client/TreePanel.tsx +1 -2
  29. package/src/client/UsageHeatmapSection.tsx +1 -1
  30. package/src/client/builtins/tabs.tsx +9 -2
  31. package/src/client/builtins/viewers.tsx +2 -1
  32. package/src/client/icons.tsx +57 -4
  33. package/src/client/intercept.tsx +1 -1
  34. package/src/client/md-toc.tsx +1 -1
  35. package/src/client/mermaid.tsx +2 -1
  36. package/src/client/open-with-settings.tsx +1 -1
  37. package/src/client/service.ts +1 -1
  38. package/src/client/ui-tweaks/branding.tsx +2 -2
  39. package/src/config.ts +22 -2
  40. package/src/context-types.ts +5 -15
  41. package/src/index.ts +22 -20
  42. package/src/prefs-shared.ts +1 -1
  43. package/src/ui-tweaks/config.ts +1 -1
  44. package/src/ui-tweaks/index.ts +7 -13
package/lib/index.js CHANGED
@@ -3,6 +3,7 @@ import { mkdir, open, opendir, readFile, readdir, realpath, rename, rm, stat, wr
3
3
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { WebSocket, WebSocketServer } from "ws";
5
5
  import z from "schemastery";
6
+ import z$1 from "@deepseek-ai/schemastery";
6
7
  import { createHash, randomUUID } from "node:crypto";
7
8
  import { once } from "node:events";
8
9
  import { chmodSync, createWriteStream, existsSync, readFileSync, realpathSync, statSync } from "node:fs";
@@ -11,9 +12,41 @@ import { execFile, spawn } from "node:child_process";
11
12
  import { SettingsConflictError } from "@deepseek-ai/dsh-settings";
12
13
  import { homedir, userInfo } from "node:os";
13
14
  import { defineTool } from "@deepseek-ai/dsh-tools";
14
- import z$1 from "@deepseek-ai/schemastery";
15
15
  import { workspaceDomainState } from "@deepseek-ai/dsh-workspace";
16
16
  import { YAMLMap, YAMLSeq, parse, parseDocument, stringify } from "yaml";
17
+ //#region src/ui-tweaks/config.ts
18
+ /**
19
+ * dsh-ui-tweaks configuration: conversation font size (px), markdown table
20
+ * style, and feature toggles. Every field
21
+ * defaults at the schema boundary, so a hand-edited settings document and the
22
+ * Settings panel stay consistent.
23
+ * @module dsh-ui-tweaks/config
24
+ */
25
+ /** Settings document namespace owned by this plugin. */
26
+ const UI_TWEAKS_SETTINGS_NAMESPACE = "better-sidebar";
27
+ /** Configuration schema with documented defaults. */
28
+ const Config$1 = z$1.object({
29
+ fontSize: z$1.number().min(10).max(32).default(16),
30
+ codeFontScale: z$1.number().min(50).max(150).default(81),
31
+ codeFontSize: z$1.number().min(8).max(32),
32
+ lineHeight: z$1.number().min(0).max(64).default(16),
33
+ tableStyle: z$1.union(["default", "claude"]).default("default"),
34
+ gitBarEnabled: z$1.boolean().default(false),
35
+ archiveManagerEnabled: z$1.boolean().default(false),
36
+ mcpManagerEnabled: z$1.boolean().default(false),
37
+ initCommandEnabled: z$1.boolean().default(false),
38
+ whaleIndicatorEnabled: z$1.boolean().default(false),
39
+ preciseCacheHitEnabled: z$1.boolean().default(false),
40
+ notificationsEnabled: z$1.boolean().default(false),
41
+ notifyOnlyWhenHidden: z$1.boolean().default(true),
42
+ notifyOnComplete: z$1.boolean().default(true),
43
+ notifyOnInteraction: z$1.boolean().default(true),
44
+ notifyTitleFlash: z$1.boolean().default(true),
45
+ notifySystemNotification: z$1.boolean().default(true),
46
+ notifySound: z$1.boolean().default(false),
47
+ suggestModel: z$1.string()
48
+ });
49
+ //#endregion
17
50
  //#region src/prefs-shared.ts
18
51
  /**
19
52
  * Shared "Side card" preference vocabulary (types + constants), consumed by
@@ -23,7 +56,7 @@ import { YAMLMap, YAMLSeq, parse, parseDocument, stringify } from "yaml";
23
56
  * the browser bundle never pulls the schema runtime in.
24
57
  */
25
58
  /** The user-settings namespace holding the side card preferences. */
26
- const SIDEBAR_PREFS_NS = "dsh-better-sidebar";
59
+ const SIDEBAR_PREFS_NS = "better-sidebar";
27
60
  /** Fallback prefs used whenever the settings document is unreachable or malformed. */
28
61
  const SIDEBAR_PREFS_DEFAULTS = {
29
62
  openByDefault: false,
@@ -65,7 +98,7 @@ const SIDEBAR_PREFS_DEFAULTS = {
65
98
  * @module dsh-better-sidebar/config
66
99
  */
67
100
  /** Schemastery schema for the plugin configuration. */
68
- const Config = z.object({
101
+ const HostConfig = z.object({
69
102
  readLimit: z.number().step(1).min(1).default(524288),
70
103
  mediaLimit: z.number().step(1).min(1).default(20971520),
71
104
  uploadLimit: z.number().step(1).min(1).default(134217728),
@@ -148,6 +181,20 @@ const PrefsSchema = z.object({
148
181
  viewersEnabled: z.dict(z.boolean()).default({}),
149
182
  pluginSettings: z.dict(z.dict(z.any())).default({})
150
183
  });
184
+ function live(schema) {
185
+ Reflect.set(schema.meta, "volatile", true);
186
+ return schema;
187
+ }
188
+ function liveFields(schema) {
189
+ if (schema.type !== "object" || schema.dict === void 0) throw new TypeError("Live settings schema must be an object");
190
+ return Object.fromEntries(Object.entries(schema.dict).map(([key, field]) => [key, live(field)]));
191
+ }
192
+ /** One entry schema: deployment fields stay fixed while sidebar and UI preferences are live-editable. */
193
+ const Config = z.object({
194
+ ...HostConfig.dict,
195
+ ...liveFields(PrefsSchema),
196
+ ...liveFields(Config$1)
197
+ });
151
198
  //#endregion
152
199
  //#region src/wire.ts
153
200
  /** One API failure with its wire code and HTTP status. */
@@ -3225,39 +3272,6 @@ async function performAllUpdates(checks) {
3225
3272
  return results;
3226
3273
  }
3227
3274
  //#endregion
3228
- //#region src/ui-tweaks/config.ts
3229
- /**
3230
- * dsh-ui-tweaks configuration: conversation font size (px), markdown table
3231
- * style, and feature toggles. Every field
3232
- * defaults at the schema boundary, so a hand-edited settings document and the
3233
- * Settings panel stay consistent.
3234
- * @module dsh-ui-tweaks/config
3235
- */
3236
- /** Settings document namespace owned by this plugin. */
3237
- const UI_TWEAKS_SETTINGS_NAMESPACE = "ui-tweaks";
3238
- /** Configuration schema with documented defaults. */
3239
- const Config$1 = z$1.object({
3240
- fontSize: z$1.number().min(10).max(32).default(16),
3241
- codeFontScale: z$1.number().min(50).max(150).default(81),
3242
- codeFontSize: z$1.number().min(8).max(32),
3243
- lineHeight: z$1.number().min(0).max(64).default(16),
3244
- tableStyle: z$1.union(["default", "claude"]).default("default"),
3245
- gitBarEnabled: z$1.boolean().default(false),
3246
- archiveManagerEnabled: z$1.boolean().default(false),
3247
- mcpManagerEnabled: z$1.boolean().default(false),
3248
- initCommandEnabled: z$1.boolean().default(false),
3249
- whaleIndicatorEnabled: z$1.boolean().default(false),
3250
- preciseCacheHitEnabled: z$1.boolean().default(false),
3251
- notificationsEnabled: z$1.boolean().default(false),
3252
- notifyOnlyWhenHidden: z$1.boolean().default(true),
3253
- notifyOnComplete: z$1.boolean().default(true),
3254
- notifyOnInteraction: z$1.boolean().default(true),
3255
- notifyTitleFlash: z$1.boolean().default(true),
3256
- notifySystemNotification: z$1.boolean().default(true),
3257
- notifySound: z$1.boolean().default(false),
3258
- suggestModel: z$1.string()
3259
- });
3260
- //#endregion
3261
3275
  //#region src/ui-tweaks/turn-outcome.ts
3262
3276
  /** Projection key the browser notifier reads through list-row `projectionValues`. */
3263
3277
  const TURN_OUTCOME_PROJECTION_KEY = "dshTurnOutcome";
@@ -5857,10 +5871,11 @@ function installMcpWeb(ctx, backend) {
5857
5871
  //#endregion
5858
5872
  //#region src/ui-tweaks/index.ts
5859
5873
  function apply$1(ctx) {
5860
- ctx.settings.register(UI_TWEAKS_SETTINGS_NAMESPACE, Config$1, { applies: "live" });
5861
5874
  installTurnOutcomeProjection(ctx);
5862
5875
  installUITweaksWeb(ctx, new UITweaksWebBackend(ctx));
5863
- const readConfig = () => ctx.settings.get(UI_TWEAKS_SETTINGS_NAMESPACE);
5876
+ const readConfig = () => {
5877
+ return ctx.settings.describe().find((candidate) => candidate.ns === "better-sidebar")?.value ?? {};
5878
+ };
5864
5879
  installGitWeb(ctx, new GitBackend(ctx, readConfig));
5865
5880
  installArchiveWeb(ctx, new ArchiveBackend(ctx));
5866
5881
  installMcpWeb(ctx, new McpBackend(ctx));
@@ -6468,7 +6483,6 @@ function apply(ctx, config) {
6468
6483
  };
6469
6484
  ctx.inject(["settings"], (sctx) => {
6470
6485
  const ns = SIDEBAR_PREFS_NS;
6471
- const scope = sctx.settings.register(ns, PrefsSchema);
6472
6486
  const viewOf = () => {
6473
6487
  const descriptor = sctx.settings.describe({ redactSecrets: true }).find((candidate) => candidate.ns === ns);
6474
6488
  return descriptor === void 0 ? {
@@ -6490,6 +6504,13 @@ function apply(ctx, config) {
6490
6504
  return viewOf();
6491
6505
  }
6492
6506
  };
6507
+ const scope = { get: () => {
6508
+ const value = viewOf().value;
6509
+ return {
6510
+ ...SIDEBAR_PREFS_DEFAULTS,
6511
+ ...typeof value === "object" && value !== null ? value : {}
6512
+ };
6513
+ } };
6493
6514
  syncToolsGate(scope);
6494
6515
  const syncOpenToolsGate = () => {
6495
6516
  if (scope.get().agentOpenTools) {
@@ -6504,7 +6525,7 @@ function apply(ctx, config) {
6504
6525
  }
6505
6526
  };
6506
6527
  syncOpenToolsGate();
6507
- scope.watch(() => {
6528
+ sctx.on("loader/volatile-update", () => {
6508
6529
  syncToolsGate(scope);
6509
6530
  syncOpenToolsGate();
6510
6531
  });
@@ -1,3 +1,12 @@
1
+ /**
2
+ * The 7 built-in tab descriptors: the plugin registers its own pages
3
+ * (editor / git / terminal / browser / diff) through
4
+ * the same {@link BetterSidebarService} external plugins use — eating its
5
+ * own dogfood. The terminal descriptor owns its quota (`TERMINAL_LIMIT`)
6
+ * and mints `terminal:<uuid>` ids through `createTab`; the browser mints
7
+ * `browser:<n>` the same way (no quota). The editor IS the files window
8
+ * (the old standalone explorer merged into it).
9
+ */
1
10
  import type { Context } from '../../context-types.ts';
2
11
  import type { TabDescriptor } from '../service.ts';
3
12
  /** How many UI-owned terminals may be open at once (agent-owned ones are uncapped). */
@@ -1,11 +1,29 @@
1
- /**
2
- * Icons the sidebar needs beyond the primitives set: a terminal glyph (the
3
- * icon library has none), a diff glyph, and the two panel-toggle glyphs for
4
- * the top-right cluster. Per-tab icons live on the tab descriptors
5
- * (`descriptor.icon`), not in a type-keyed switch — the icon mapping was
6
- * registry-ized with the tab types.
7
- */
8
- import type { IconProps } from '@deepseek-ai/dsh-client-ui-primitives';
1
+ export interface IconProps {
2
+ size?: number;
3
+ className?: string;
4
+ }
5
+ export declare const IconListPenOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
6
+ export declare const IconRefreshOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
7
+ export declare const IconRefreshOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
8
+ export declare const IconChevronRightOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
9
+ export declare const IconChevronLeftOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
10
+ export declare const IconChevronDownOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
11
+ export declare const IconCodeOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
12
+ export declare const IconCopyOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
13
+ export declare const IconDownloadOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
14
+ export declare const IconLinkOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
15
+ export declare const IconLinkOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
16
+ export declare const IconBranchOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
17
+ export declare const IconTrashOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
18
+ export declare const IconWarningOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
19
+ export declare const IconCloseFill14: ({ size, className }: IconProps) => import("react").JSX.Element;
20
+ export declare const IconCloseOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
21
+ export declare const IconLoadingOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
22
+ export declare const IconPlusOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
23
+ export declare const IconSettingsOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
24
+ export declare const IconFolderOpen16: ({ size, className }: IconProps) => import("react").JSX.Element;
25
+ export declare const IconPanelLeftOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
26
+ export declare const IconCheckOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
9
27
  /** User-manual glyph: an open book in the sidebar's 1.5px outline style. */
10
28
  export declare const IconBookOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
11
29
  /**
@@ -418,7 +418,7 @@ export declare function matchUrlTarget(tabs: readonly TabDescriptor[], url: URL)
418
418
  * The plugin version this service instance reports. Keep in lockstep with
419
419
  * `package.json`'s version — `tests/service.spec.ts` asserts the pair.
420
420
  */
421
- export declare const SIDEBAR_SERVICE_VERSION = "0.18.0-alpha.0";
421
+ export declare const SIDEBAR_SERVICE_VERSION = "0.18.0-alpha.4";
422
422
  /**
423
423
  * Monotonic capability list consumers use to gate new API usage (features
424
424
  * are never removed). Each string names a v0.12.0+ capability:
@@ -5,10 +5,11 @@
5
5
  * @module dsh-better-sidebar/config
6
6
  */
7
7
  import z from 'schemastery';
8
+ import { type UITweaksConfig } from './ui-tweaks/config.ts';
8
9
  import { type SidebarPrefs } from './prefs-shared.ts';
9
10
  export { SIDEBAR_PREFS_DEFAULTS, SIDEBAR_PREFS_NS, TERMINAL_FONT_SIZE_DEFAULT, TERMINAL_FONT_SIZE_MAX, TERMINAL_FONT_SIZE_MIN, TITLE_BAR_STRIP_DEFAULT, TITLE_BAR_STRIP_MAX, TITLE_BAR_STRIP_MIN, WIDTH_PERCENT_DEFAULT, WIDTH_PERCENT_MAX, WIDTH_PERCENT_MIN, type SidebarPrefs, } from './prefs-shared.ts';
10
11
  /** Tunable sidebar host limits (every field optional; defaults fill in). */
11
- export interface SidebarConfig {
12
+ export interface SidebarConfig extends Partial<SidebarPrefs>, UITweaksConfig {
12
13
  /** Read cap of one text file (bytes); larger files return truncated. */
13
14
  readLimit?: number;
14
15
  /** Media route cap (bytes); larger binaries are refused. */
@@ -56,8 +57,6 @@ export interface CodingPlanConfig {
56
57
  /** Catalogue request timeout in milliseconds. */
57
58
  requestTimeoutMs?: number;
58
59
  }
59
- /** Schemastery schema for the plugin configuration. */
60
- export declare const Config: z<SidebarConfig>;
61
60
  /** Fully defaulted sidebar host settings. */
62
61
  export interface ResolvedSidebarConfig {
63
62
  readLimit: number;
@@ -93,3 +92,5 @@ export interface ResolvedCodingPlanConfig {
93
92
  export declare function resolveSidebarConfig(config: SidebarConfig | undefined): ResolvedSidebarConfig;
94
93
  /** Schemastery schema for the user-facing preferences (validated by the settings service). */
95
94
  export declare const PrefsSchema: z<SidebarPrefs>;
95
+ /** One entry schema: deployment fields stay fixed while sidebar and UI preferences are live-editable. */
96
+ export declare const Config: z<SidebarConfig>;
@@ -427,21 +427,10 @@ export interface SidebarInvariantsService {
427
427
  /** Reserve one package's checks and install them in the service's child fiber. */
428
428
  register(packageName: string, installer: (ctx: Context, fail: (message: string) => never) => void | Promise<void>): () => void;
429
429
  }
430
- /** The settings service face (mirror of @deepseek-ai/dsh-settings' SettingsProvider). */
430
+ /** The settings service face (mirror of @deepseek-ai/dsh-settings' SettingsForms). */
431
431
  export interface SidebarSettingsService {
432
- /**
433
- * Register one namespace schema (the resolved value layers schema defaults,
434
- * then the composition base, then the user document).
435
- */
436
- register<T>(ns: string, schema: unknown, options?: {
437
- base?: Partial<T>;
438
- applies?: 'live' | 'restart';
439
- }): {
440
- get(): T;
441
- watch(callback: (next: T, prev: T) => void | Promise<void>): () => void;
442
- update(patch: object): Promise<void>;
443
- replace(section: object): Promise<void>;
444
- };
432
+ /** Whether the active profile accepts form edits. */
433
+ readonly writable: boolean;
445
434
  /** Redacted descriptors of every registered namespace (secrets stripped). */
446
435
  describe(options?: {
447
436
  redactSecrets?: boolean;
@@ -455,6 +444,15 @@ export interface SidebarSettingsService {
455
444
  }>;
456
445
  /** Service-level merge write with the revision guard (a stale writer is refused). */
457
446
  update(ns: string, patch: object, expectedRevision?: number): Promise<void>;
447
+ /** Apply path edits without restating fields hidden from the caller. */
448
+ mutate(ns: string, ops: readonly ({
449
+ op: 'set';
450
+ path: readonly string[];
451
+ value: unknown;
452
+ } | {
453
+ op: 'unset';
454
+ path: readonly string[];
455
+ })[], expectedRevision?: number): Promise<void>;
458
456
  }
459
457
  /**
460
458
  * The tools service face (mirror of @deepseek-ai/dsh-tools' ToolRuntime).
@@ -6,7 +6,7 @@
6
6
  * the browser bundle never pulls the schema runtime in.
7
7
  */
8
8
  /** The user-settings namespace holding the side card preferences. */
9
- export declare const SIDEBAR_PREFS_NS = "dsh-better-sidebar";
9
+ export declare const SIDEBAR_PREFS_NS = "better-sidebar";
10
10
  /** User-facing side card preferences (new-conversation defaults). */
11
11
  export interface SidebarPrefs {
12
12
  /** Whether a brand-new conversation opens the side card by default. */
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * dsh-ui-tweaks — server half.
3
3
  *
4
- * Registers the `ui-tweaks` settings namespace so users can tune the
5
- * conversation UI either from the Settings panel or by editing the settings
6
- * document directly (settings.yaml `ui-tweaks:` section). All rendering work
4
+ * Uses the owning sidebar entry's live settings so users can tune the
5
+ * conversation UI from the Settings panel. All rendering work
7
6
  * happens in the browser bundle (`src/client`), which reads and writes this
8
7
  * namespace through the same-origin route mounted here — the Web settings RPC
9
8
  * only exposes a fixed allowlist of namespaces since rc.6, so a custom route is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatcode/cco-better-sidebar",
3
- "version": "0.18.0-alpha.4",
3
+ "version": "0.18.0-rc.2",
4
4
  "description": "ChatCode CLI Web plugin: a VS Code-like right sidebar (explorer / editor / terminal / git / browser), isolated per conversation session. Exposes a service for other plugins to register sidebar tabs and file viewers.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -23,7 +23,7 @@ import {
23
23
  IconLinkOutline14,
24
24
  IconRefreshOutline14,
25
25
  IconWarningOutline16,
26
- } from '@deepseek-ai/dsh-client-ui-primitives'
26
+ } from './icons.tsx'
27
27
  import { VscLinkExternal } from 'react-icons/vsc'
28
28
  import { api } from './api.ts'
29
29
  import { embeddabilityOf, isAllowedLoopbackUrl, normalizeBrowserUrl } from './browser.ts'
@@ -8,7 +8,7 @@
8
8
  * very content it shows.
9
9
  */
10
10
  import { useCallback, useEffect, useState } from 'react'
11
- import { IconRefreshOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
11
+ import { IconRefreshOutline16 } from './icons.tsx'
12
12
  import type { SessionScope } from './api.ts'
13
13
  import { api } from './api.ts'
14
14
  import type { SidebarDiffRef } from './state.ts'
@@ -25,7 +25,7 @@
25
25
  import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
26
26
  import { createElement } from 'react'
27
27
  import clsx from 'clsx'
28
- import { IconCheckOutline16, IconFolderOpen16, IconRefreshOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
28
+ import { IconCheckOutline16, IconFolderOpen16, IconRefreshOutline14 } from './icons.tsx'
29
29
  import type { Context } from '../context-types.ts'
30
30
  import { api, isOutsideWorkspaceMessage, mediaUrl, type SessionScope } from './api.ts'
31
31
  import { BinaryDownload } from './binary-download.tsx'
@@ -23,15 +23,20 @@
23
23
  import { useCallback, useEffect, useRef, useState, type DragEvent, type MouseEvent, type ReactNode } from 'react'
24
24
  import { createPortal } from 'react-dom'
25
25
  import clsx from 'clsx'
26
- import {
27
- IconChevronRightOutline14, IconCodeOutline16, IconCopyOutline16, IconDownloadOutline16,
28
- IconLinkOutline16, Menu, type MenuEntry, type MenuItem, writeClipboard,
29
- } from '@deepseek-ai/dsh-client-ui-primitives'
26
+ import { Menu, type MenuEntry, type MenuItem, writeClipboard } from '@deepseek-ai/dsh-client-ui-primitives'
30
27
  import { SiCursor, SiZedindustries } from 'react-icons/si'
31
28
  import { VscFile, VscFolder, VscFolderOpened, VscLinkExternal, VscPin, VscPinned } from 'react-icons/vsc'
32
29
  import { api, downloadUrl, isOutsideWorkspaceMessage, type FsEntry } from './api.ts'
33
30
  import { FenceErrorNotice } from './FenceErrorNotice.tsx'
34
- import { IconUploadOutline16, IconVscode16 } from './icons.tsx'
31
+ import {
32
+ IconChevronRightOutline14,
33
+ IconCodeOutline16,
34
+ IconCopyOutline16,
35
+ IconDownloadOutline16,
36
+ IconLinkOutline16,
37
+ IconUploadOutline16,
38
+ IconVscode16,
39
+ } from './icons.tsx'
35
40
  import type { OpenWithTarget } from './open-with.ts'
36
41
  import { relativeTo } from './paths.ts'
37
42
  import { t } from './locales.ts'
@@ -16,7 +16,8 @@
16
16
  */
17
17
  import { useEffect, useRef, useState, type ReactNode } from 'react'
18
18
  import clsx from 'clsx'
19
- import { IconCloseFill14, Menu } from '@deepseek-ai/dsh-client-ui-primitives'
19
+ import { Menu } from '@deepseek-ai/dsh-client-ui-primitives'
20
+ import { IconCloseFill14 } from './icons.tsx'
20
21
  import type { FloatWindow, SidebarTab } from './state.ts'
21
22
  import { FLOAT_MIN_H, FLOAT_MIN_W } from './state.ts'
22
23
  import { t } from './locales.ts'
@@ -10,10 +10,14 @@
10
10
  * file changes appear without a manual refresh.
11
11
  */
12
12
  import { useCallback, useEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react'
13
+ import { Button, Input, Menu, Modal, writeClipboard } from '@deepseek-ai/dsh-client-ui-primitives'
13
14
  import {
14
- Button, IconBranchOutline16, IconCodeOutline16, IconCopyOutline16, IconRefreshOutline16,
15
- IconTrashOutline16, Input, Menu, Modal, writeClipboard,
16
- } from '@deepseek-ai/dsh-client-ui-primitives'
15
+ IconBranchOutline16,
16
+ IconCodeOutline16,
17
+ IconCopyOutline16,
18
+ IconRefreshOutline16,
19
+ IconTrashOutline16,
20
+ } from './icons.tsx'
17
21
  import type { GitLogEntry, GitStatusEntry, GitStatusResult, GitWorktree, SessionScope } from './api.ts'
18
22
  import { api } from './api.ts'
19
23
  import { isWithinWorkspace, relativeTo } from './paths.ts'
@@ -41,14 +41,7 @@
41
41
  * shell.
42
42
  */
43
43
  import { Fragment, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
44
- import {
45
- IconChevronDownOutline14,
46
- IconPlusOutline16,
47
- IconSettingsOutline16,
48
- Input,
49
- Menu,
50
- Modal,
51
- } from '@deepseek-ai/dsh-client-ui-primitives'
44
+ import { Input, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives'
52
45
  import clsx from 'clsx'
53
46
  // Type-only: pulls the settings shell's SlotMap merges ('settings.section').
54
47
  import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
@@ -63,6 +56,7 @@ import {
63
56
  type TitleBarScheme,
64
57
  } from '../prefs-shared.ts'
65
58
  import { api } from './api.ts'
59
+ import { IconChevronDownOutline14, IconPlusOutline16, IconSettingsOutline16 } from './icons.tsx'
66
60
  import { parsePrefs } from './prefs.ts'
67
61
  import { AddPluginModal, type PluginKind } from './add-plugin-modal.tsx'
68
62
  import {
@@ -36,7 +36,7 @@ import { createElement, memo, useCallback, useEffect, useMemo, useRef, useState,
36
36
  import { useSyncExternalStore } from 'react'
37
37
  import { createPortal } from 'react-dom'
38
38
  import clsx from 'clsx'
39
- import { IconCloseFill14, Tooltip } from '@deepseek-ai/dsh-client-ui-primitives'
39
+ import { Tooltip } from '@deepseek-ai/dsh-client-ui-primitives'
40
40
  import type { Context } from '../context-types.ts'
41
41
  import { appendToDraft } from './conversation-draft.ts'
42
42
  import {
@@ -47,7 +47,7 @@ import {
47
47
  type DropZone, type SidebarState, type SidebarStore, type SidebarTab, type SplitNode,
48
48
  } from './state.ts'
49
49
  import { collectPinnedTabs, createPinnedVirtualTab, getPinnedHomeScope, injectPinnedIntoTree, isPinnedVirtualId, isPinnedVirtualTab, parsePinnedVirtualId, type PinnedTabEntry } from './pinned.ts'
50
- import { IconBookOutline16, IconPinOutline16 } from './icons.tsx'
50
+ import { IconBookOutline16, IconCloseFill14, IconPinOutline16 } from './icons.tsx'
51
51
  import { IconPanelBottomOutline16, IconPanelRightOutline16 } from './icons.tsx'
52
52
  import { Workbench, type WorkbenchActions } from './split-pane.tsx'
53
53
  import { isNarrowWidth, useViewportSize } from './breakpoints.ts'
@@ -10,13 +10,11 @@
10
10
  */
11
11
  import { useEffect, useRef, useState, type ReactNode } from 'react'
12
12
  import clsx from 'clsx'
13
- import {
14
- IconCloseFill14, IconPlusOutline16, Menu,
15
- } from '@deepseek-ai/dsh-client-ui-primitives'
13
+ import { Menu } from '@deepseek-ai/dsh-client-ui-primitives'
16
14
  import type { SidebarTab } from './state.ts'
17
15
  import { isAgentTabId } from './state.ts'
18
16
  import { isPinnedVirtualTab } from './pinned.ts'
19
- import { IconPinOutline16 } from './icons.tsx'
17
+ import { IconCloseFill14, IconPinOutline16, IconPlusOutline16 } from './icons.tsx'
20
18
  import { t } from './locales.ts'
21
19
  import css from './sidebar.module.css'
22
20
 
@@ -19,7 +19,8 @@ import clsx from 'clsx'
19
19
  import { EditorState } from '@codemirror/state'
20
20
  import { EditorView as CodeMirrorView, keymap, lineNumbers } from '@codemirror/view'
21
21
  import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
22
- import { IconCheckOutline16, MarkdownText } from '@deepseek-ai/dsh-client-ui-primitives'
22
+ import { MarkdownText } from '@deepseek-ai/dsh-client-ui-primitives'
23
+ import { IconCheckOutline16 } from './icons.tsx'
23
24
  import { markdownTextProps } from './markdown-labels.tsx'
24
25
  import { api, htmlUrl } from './api.ts'
25
26
  import { rewriteLocalImageUrls } from './markdown-images.ts'
@@ -17,11 +17,10 @@
17
17
  */
18
18
  import { useEffect, useRef, useState, type InputHTMLAttributes } from 'react'
19
19
  import clsx from 'clsx'
20
- import { IconFolderOpen16, IconRefreshOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
21
20
  import { api } from './api.ts'
22
21
  import type { SidebarStore } from './state.ts'
23
22
  import { FileTree } from './FileTree.tsx'
24
- import { IconUploadOutline16 } from './icons.tsx'
23
+ import { IconFolderOpen16, IconRefreshOutline16, IconUploadOutline16 } from './icons.tsx'
25
24
  import type { OpenWithTarget } from './open-with.ts'
26
25
  import { t } from './locales.ts'
27
26
  import { resolveSidebarPath } from './produced-files.ts'
@@ -4,7 +4,7 @@ import {
4
4
  IconChevronRightOutline14,
5
5
  IconLoadingOutline16,
6
6
  IconRefreshOutline14,
7
- } from '@deepseek-ai/dsh-client-ui-primitives'
7
+ } from './icons.tsx'
8
8
  import clsx from 'clsx'
9
9
  // Type-only: pulls the settings shell's SlotMap merges ('settings.section').
10
10
  import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
@@ -7,7 +7,6 @@
7
7
  * `browser:<n>` the same way (no quota). The editor IS the files window
8
8
  * (the old standalone explorer merged into it).
9
9
  */
10
- import { IconBranchOutline16, IconCodeOutline16, IconFolderOpen16, IconPanelLeftOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
11
10
  import type { Context } from '../../context-types.ts'
12
11
  import { allLeaves, isAgentTabId, type SidebarState } from '../state.ts'
13
12
  import { t } from '../locales.ts'
@@ -18,7 +17,15 @@ import { lazyChunkComponent } from '../lazy-chunk.tsx'
18
17
  import { GitView } from '../GitView.tsx'
19
18
  import { DiffTab } from '../DiffTab.tsx'
20
19
  import { BrowserView } from '../BrowserView.tsx'
21
- import { IconTerminalOutline16, IconDiffOutline16, IconGlobeOutline16 } from '../icons.tsx'
20
+ import {
21
+ IconBranchOutline16,
22
+ IconCodeOutline16,
23
+ IconDiffOutline16,
24
+ IconFolderOpen16,
25
+ IconGlobeOutline16,
26
+ IconPanelLeftOutline16,
27
+ IconTerminalOutline16,
28
+ } from '../icons.tsx'
22
29
  import { TERMINAL_FONT_SIZE_MAX, TERMINAL_FONT_SIZE_MIN } from '../../prefs-shared.ts'
23
30
  import type { ComponentType } from 'react'
24
31
  import type { SessionScope } from '../api.ts'
@@ -22,11 +22,12 @@
22
22
  * and `icon` — so the Side card settings page can render the enable/disable
23
23
  * inventory without hardcoding (eating our own dogfood).
24
24
  */
25
- import { IconCodeOutline16, IconDownloadOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
26
25
  import { lazyChunkComponent } from '../lazy-chunk.tsx'
27
26
  import { PdfView } from '../PdfView.tsx'
28
27
  import { BinaryDownload } from '../binary-download.tsx'
29
28
  import {
29
+ IconCodeOutline16,
30
+ IconDownloadOutline16,
30
31
  IconImageOutline16,
31
32
  IconMarkdownOutline16,
32
33
  IconPdfOutline16,
@@ -1,11 +1,64 @@
1
1
  /**
2
- * Icons the sidebar needs beyond the primitives set: a terminal glyph (the
3
- * icon library has none), a diff glyph, and the two panel-toggle glyphs for
4
- * the top-right cluster. Per-tab icons live on the tab descriptors
2
+ * Icons owned by the sidebar. DSH 0.1.7 stopped exporting the old Icon*
3
+ * components from dsh-client-ui-primitives, so keeping every glyph local
4
+ * makes the browser bundle work against both the 0.1.2 and 0.1.7 hosts.
5
+ * Per-tab icons live on the tab descriptors
5
6
  * (`descriptor.icon`), not in a type-keyed switch — the icon mapping was
6
7
  * registry-ized with the tab types.
7
8
  */
8
- import type { IconProps } from '@deepseek-ai/dsh-client-ui-primitives'
9
+ import {
10
+ FiAlertTriangle,
11
+ FiCheck,
12
+ FiChevronDown,
13
+ FiChevronLeft,
14
+ FiChevronRight,
15
+ FiCode,
16
+ FiCopy,
17
+ FiDownload,
18
+ FiFolder,
19
+ FiGitBranch,
20
+ FiLink,
21
+ FiList,
22
+ FiLoader,
23
+ FiPlus,
24
+ FiRefreshCw,
25
+ FiSettings,
26
+ FiSidebar,
27
+ FiTrash2,
28
+ FiX,
29
+ } from 'react-icons/fi'
30
+ import type { IconType } from 'react-icons'
31
+
32
+ export interface IconProps {
33
+ size?: number
34
+ className?: string
35
+ }
36
+
37
+ const wrapIcon = (Icon: IconType, defaultSize: number) =>
38
+ ({ size = defaultSize, className }: IconProps) => <Icon size={size} className={className} />
39
+
40
+ export const IconListPenOutline16 = wrapIcon(FiList, 16)
41
+ export const IconRefreshOutline16 = wrapIcon(FiRefreshCw, 16)
42
+ export const IconRefreshOutline14 = wrapIcon(FiRefreshCw, 14)
43
+ export const IconChevronRightOutline14 = wrapIcon(FiChevronRight, 14)
44
+ export const IconChevronLeftOutline14 = wrapIcon(FiChevronLeft, 14)
45
+ export const IconChevronDownOutline14 = wrapIcon(FiChevronDown, 14)
46
+ export const IconCodeOutline16 = wrapIcon(FiCode, 16)
47
+ export const IconCopyOutline16 = wrapIcon(FiCopy, 16)
48
+ export const IconDownloadOutline16 = wrapIcon(FiDownload, 16)
49
+ export const IconLinkOutline16 = wrapIcon(FiLink, 16)
50
+ export const IconLinkOutline14 = wrapIcon(FiLink, 14)
51
+ export const IconBranchOutline16 = wrapIcon(FiGitBranch, 16)
52
+ export const IconTrashOutline16 = wrapIcon(FiTrash2, 16)
53
+ export const IconWarningOutline16 = wrapIcon(FiAlertTriangle, 16)
54
+ export const IconCloseFill14 = wrapIcon(FiX, 14)
55
+ export const IconCloseOutline16 = wrapIcon(FiX, 16)
56
+ export const IconLoadingOutline16 = wrapIcon(FiLoader, 16)
57
+ export const IconPlusOutline16 = wrapIcon(FiPlus, 16)
58
+ export const IconSettingsOutline16 = wrapIcon(FiSettings, 16)
59
+ export const IconFolderOpen16 = wrapIcon(FiFolder, 16)
60
+ export const IconPanelLeftOutline16 = wrapIcon(FiSidebar, 16)
61
+ export const IconCheckOutline16 = wrapIcon(FiCheck, 16)
9
62
 
10
63
  /** User-manual glyph: an open book in the sidebar's 1.5px outline style. */
11
64
  export const IconBookOutline16 = ({ size = 16, className }: IconProps) => (
@@ -5,7 +5,7 @@
5
5
  * compatible across that transition. The chips open the file in the sidebar
6
6
  * instead of the host OS.
7
7
  */
8
- import { IconCodeOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
8
+ import { IconCodeOutline16 } from './icons.tsx'
9
9
  import type { Context } from '../context-types.ts'
10
10
  import { firstLeaf, revealPaths, togglePanel, type SidebarStore } from './state.ts'
11
11
  import { t } from './locales.ts'