dsh-command-palette 0.1.1 → 0.1.3

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.en.md CHANGED
@@ -78,6 +78,16 @@ Service API:
78
78
 
79
79
  Provider IDs must be unique. Commands require at least `id`, `title`, and `run()`; the provider ID is automatically prefixed to the final command ID.
80
80
 
81
+ Dynamic providers may also implement `subscribe(invalidate)`. Call `invalidate()` when external state changes to make the palette collect commands again. The disposer returned by `subscribe` runs automatically when the provider is removed:
82
+
83
+ ```js
84
+ {
85
+ id: 'dynamic-plugin',
86
+ collect: () => buildCommands(currentState),
87
+ subscribe: (invalidate) => externalStore.subscribe(() => invalidate())
88
+ }
89
+ ```
90
+
81
91
  Native Desktop browser tabs, Electron IPC, and native-view coordination are outside this package. A separate Desktop enhancement plugin can add them later through this API.
82
92
 
83
93
  ## Data storage
package/README.md CHANGED
@@ -78,6 +78,16 @@ exports.apply = (ctx) => {
78
78
 
79
79
  Provider ID 必须唯一。命令至少需要 `id`、`title` 和 `run()`;最终命令 ID 会自动加上 Provider 前缀。
80
80
 
81
+ 动态 Provider 可以额外实现 `subscribe(invalidate)`。当外部状态变化时调用 `invalidate()`,命令面板会重新收集命令;`subscribe` 返回的卸载函数会在 Provider 注销时自动执行:
82
+
83
+ ```js
84
+ {
85
+ id: 'dynamic-plugin',
86
+ collect: () => buildCommands(currentState),
87
+ subscribe: (invalidate) => externalStore.subscribe(() => invalidate())
88
+ }
89
+ ```
90
+
81
91
  Desktop 原生浏览器标签、Electron IPC 和原生视图协调不属于本包,后续可以由独立 Desktop 增强插件通过上述接口接入。
82
92
 
83
93
  ## 数据存储
package/client.js CHANGED
@@ -6,6 +6,7 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
7
7
  const React = require('react')
8
8
  const ReactDOM = require('react-dom')
9
+ const { useStore } = require('@deepseek-ai/dsh-client-runtime')
9
10
 
10
11
  const GROUP_ORDER = ['features', 'settings', 'browser', 'workspaces', 'sessions']
11
12
  const GROUP_LABELS = { features: '功能', settings: '设置', browser: '浏览器', workspaces: '工作区', sessions: '会话', recent: '最近会话' }
@@ -36,7 +37,10 @@ window.__ModuleLoader__.load({
36
37
  let revision = 0
37
38
  const emit = (reason) => {
38
39
  const snapshot = { open, revision: ++revision, reason }
39
- for (const listener of listeners) listener(snapshot)
40
+ for (const listener of listeners) {
41
+ try { listener(snapshot) }
42
+ catch (error) { console.warn('[dsh-command-palette] subscriber failed:', error) }
43
+ }
40
44
  }
41
45
  return {
42
46
  registerProvider(provider) {
@@ -45,15 +49,33 @@ window.__ModuleLoader__.load({
45
49
  }
46
50
  const id = provider.id.trim()
47
51
  if (providers.has(id)) throw new Error(`Command palette provider already registered: ${id}`)
48
- providers.set(id, provider)
52
+ const record = { provider, disposeSubscription: null }
53
+ providers.set(id, record)
49
54
  emit('provider-registered')
55
+ if (typeof provider.subscribe === 'function') {
56
+ try {
57
+ const dispose = provider.subscribe(() => emit('provider-updated'))
58
+ if (typeof dispose === 'function') record.disposeSubscription = dispose
59
+ } catch (error) {
60
+ console.warn(`[dsh-command-palette] provider ${id} subscription failed:`, error)
61
+ }
62
+ }
63
+ let removed = false
50
64
  return () => {
51
- if (providers.delete(id)) emit('provider-removed')
65
+ if (removed) return
66
+ removed = true
67
+ const current = providers.get(id)
68
+ if (!current) return
69
+ providers.delete(id)
70
+ try { current.disposeSubscription?.() }
71
+ catch (error) { console.warn(`[dsh-command-palette] provider ${id} disposer failed:`, error) }
72
+ emit('provider-removed')
52
73
  }
53
74
  },
54
75
  collect(context = {}) {
55
76
  const commands = []
56
- for (const [providerId, provider] of providers) {
77
+ for (const [providerId, record] of providers) {
78
+ const provider = record.provider
57
79
  const commandIds = new Set()
58
80
  let provided
59
81
  try { provided = provider.collect(context) }
@@ -227,9 +249,9 @@ window.__ModuleLoader__.load({
227
249
  }
228
250
 
229
251
  function Palette({ useSessions, useWorkspaces, useCommandSettings, saveCustomCommands, openSession, startSession, runCustomCommand, paletteService }) {
230
- const sessions = useSessions((value) => value)
231
- const workspaces = useWorkspaces((value) => value)
232
- const commandSettings = useCommandSettings((value) => value)
252
+ const sessions = useStore(useSessions)
253
+ const workspaces = useStore(useWorkspaces)
254
+ const commandSettings = useStore(useCommandSettings)
233
255
  const customCommands = normalizeCustomCommands(commandSettings.value?.commands)
234
256
  const [open, setOpen] = React.useState(paletteService.isOpen())
235
257
  const [query, setQuery] = React.useState('')
@@ -347,9 +369,9 @@ window.__ModuleLoader__.load({
347
369
  }
348
370
 
349
371
  function ShortcutSettings({ useWorkspaces, useCommandSettings, saveCustomCommands }) {
350
- const commandSettings = useCommandSettings((value) => value)
372
+ const commandSettings = useStore(useCommandSettings)
351
373
  const commands = normalizeCustomCommands(commandSettings.value?.commands)
352
- const workspaceState = typeof useWorkspaces === 'function' ? useWorkspaces((value) => value) : { items: [] }
374
+ const workspaceState = useStore(useWorkspaces)
353
375
  const workspaces = workspaceState?.items || []
354
376
  const emptyDraft = { name: '', prompt: '', sticky: true, workspaceId: '' }
355
377
  const [draft, setDraft] = React.useState(emptyDraft)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-command-palette",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A keyboard-first command palette for DeepSeek Harness sessions, workspaces, settings, features, and reusable custom commands.",
5
5
  "license": "MIT",
6
6
  "author": "chenyangcun",