@lincyaw/dsh 0.0.0-stage → 0.1.0

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 (55) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +22 -2
  3. package/build/client.mjs +66 -0
  4. package/build/dist/client.js +90 -0
  5. package/build/dist/client.json +70 -0
  6. package/build/ensure.mjs +30 -0
  7. package/cordis.patch.yml +17 -0
  8. package/package.json +95 -3
  9. package/profile.patch.yml +25 -0
  10. package/rows/context.mjs +7 -0
  11. package/rows/load.mjs +8 -0
  12. package/rows/policy.mjs +7 -0
  13. package/rows/routes.mjs +7 -0
  14. package/rows/service.mjs +7 -0
  15. package/rows/skills.mjs +7 -0
  16. package/rows/tools.mjs +7 -0
  17. package/rows/turns.mjs +7 -0
  18. package/rows/workbench.mjs +9 -0
  19. package/rows/workspaces.mjs +7 -0
  20. package/skills/presmium-author/SKILL.md +95 -0
  21. package/skills/presmium-author/references/assistance.md +27 -0
  22. package/skills/presmium-author/references/code.md +52 -0
  23. package/skills/presmium-author/references/directives.md +592 -0
  24. package/skills/presmium-author/references/publishing.md +60 -0
  25. package/skills/presmium-author/references/writing.md +72 -0
  26. package/skills/presmium-present/SKILL.md +69 -0
  27. package/skills/presmium-present/references/classroom.md +46 -0
  28. package/skills/presmium-present/references/delivery.md +63 -0
  29. package/skills/presmium-present/references/lecture.md +58 -0
  30. package/src/client/Frame.tsx +314 -0
  31. package/src/client/brand.tsx +90 -0
  32. package/src/client/chrome.tsx +79 -0
  33. package/src/client/contract.ts +35 -0
  34. package/src/client/dsh.d.ts +129 -0
  35. package/src/client/fallback.tsx +49 -0
  36. package/src/client/frame.css +345 -0
  37. package/src/client/index.tsx +154 -0
  38. package/src/client/layout.ts +217 -0
  39. package/src/client/messages.ts +78 -0
  40. package/src/client/source.tsx +81 -0
  41. package/src/client/styles.css +3 -0
  42. package/src/client/theme.ts +149 -0
  43. package/src/node/context.ts +55 -0
  44. package/src/node/dsh.ts +93 -0
  45. package/src/node/launch.ts +59 -0
  46. package/src/node/policy.ts +59 -0
  47. package/src/node/routes.ts +46 -0
  48. package/src/node/service.ts +280 -0
  49. package/src/node/skills.ts +46 -0
  50. package/src/node/tools.ts +43 -0
  51. package/src/node/turns/index.ts +165 -0
  52. package/src/node/watchdog.mjs +36 -0
  53. package/src/node/workbench.ts +43 -0
  54. package/src/node/workspaces.ts +10 -0
  55. package/web.patch.yml +190 -0
@@ -0,0 +1,90 @@
1
+ import { PmButton, WorkbenchProvider } from '@lincyaw/workbench'
2
+ import type { Workbench } from '@lincyaw/workbench'
3
+ import { useEffect, useSyncExternalStore } from 'react'
4
+ import { Modal } from '@deepseek-ai/dsh-client-ui-primitives'
5
+ import { BRAND_LANGUAGES, BRAND_SLOTS, ONBOARDING } from './contract.ts'
6
+ import { BRAND_COPY, FRAME_MESSAGES } from './messages.ts'
7
+ import type { FrameMessages } from './messages.ts'
8
+
9
+ export function Logo({ size = 24, className }: { size?: number, className?: string }) {
10
+ return (
11
+ <svg className={className ? `pmw-logo ${className}` : 'pmw-logo'} width={size} height={size} viewBox="0 0 32 32" role="img" aria-label="Presmium">
12
+ <rect width="32" height="32" rx="7" fill="#0F5F5C" />
13
+ <path d="M11 8h7.5a6.5 6.5 0 0 1 0 13H15v4h-4zM15 12v5h3.5a2.5 2.5 0 0 0 0-5z" fill="#F7F5F0" fillRule="evenodd" />
14
+ </svg>
15
+ )
16
+ }
17
+
18
+ export function useFrameMessages(workbench: Workbench): FrameMessages {
19
+ const locale = useSyncExternalStore(workbench.subscribe, () => workbench.getState().locale)
20
+ return FRAME_MESSAGES[locale]
21
+ }
22
+
23
+ const WELCOMED = 'presmium.workbench.welcomed'
24
+
25
+ function welcomed(): boolean {
26
+ try {
27
+ return localStorage.getItem(WELCOMED) === '1'
28
+ } catch {
29
+ return false
30
+ }
31
+ }
32
+
33
+ function Welcome({ workbench, complete, openSection }: { workbench: Workbench, complete?: () => void, openSection?: (id: string) => void }) {
34
+ const t = useFrameMessages(workbench)
35
+ const read = welcomed()
36
+ useEffect(() => {
37
+ if (read) complete?.()
38
+ }, [read, complete])
39
+ if (read) return null
40
+ const done = () => {
41
+ try {
42
+ localStorage.setItem(WELCOMED, '1')
43
+ } catch {
44
+ }
45
+ complete?.()
46
+ }
47
+ return (
48
+ <WorkbenchProvider workbench={workbench} protectChanges={false}>
49
+ <Modal open title={t.welcomeTitle} onClose={done} headless>
50
+ <div className="pmw-welcome__card pm-ui" data-pmw-welcome="">
51
+ <Logo size={40} />
52
+ <h2 id="pmw-welcome-title" className="pmw-welcome__title">{t.welcomeTitle}</h2>
53
+ <p>{t.welcome}</p>
54
+ <div className="pmw-welcome__actions">
55
+ <PmButton
56
+ onClick={() => {
57
+ done()
58
+ openSection?.('models')
59
+ }}
60
+ >
61
+ {t.models}
62
+ </PmButton>
63
+ <PmButton variant="primary" onClick={done}>{t.start}</PmButton>
64
+ </div>
65
+ </div>
66
+ </Modal>
67
+ </WorkbenchProvider>
68
+ )
69
+ }
70
+
71
+ function PassOver({ complete }: { complete?: () => void }) {
72
+ useEffect(() => {
73
+ complete?.()
74
+ }, [complete])
75
+ return null
76
+ }
77
+
78
+ export function brand(ctx: DshClientContext, workbench: Workbench): void {
79
+ const [mark, name, hero] = BRAND_SLOTS
80
+ ctx.effect(() => ctx.slots.inject(mark, () => ctx.slots.register({ name: mark }, ({ size }: { size?: number }) => <Logo size={size ?? 24} />)), 'presmium: sidebar brand mark')
81
+ ctx.effect(() => ctx.slots.inject(name, () => ctx.slots.register({ name }, () => <span className="pmw-brand-name">Presmium</span>)), 'presmium: sidebar brand name')
82
+ ctx.effect(() => ctx.slots.inject(hero, () => ctx.slots.register({ name: hero }, ({ size, className }: { size?: number, className?: string }) => <Logo size={size ?? 34} className={className} />)), 'presmium: conversation brand mark')
83
+ const [welcome, signIn] = ONBOARDING.steps
84
+ ctx.effect(() => ctx.slots.inject(ONBOARDING.slot, () => ctx.slots.register({ name: ONBOARDING.slot, id: welcome, priority: -1, order: -100 }, props => <Welcome workbench={workbench} {...props} />)), 'presmium: first-use notice')
85
+ ctx.effect(() => ctx.slots.inject(ONBOARDING.slot, () => ctx.slots.register({ name: ONBOARDING.slot, id: signIn, priority: -1, order: 0 }, PassOver)), 'presmium: no DeepSeek sign-in step')
86
+ for (const language of BRAND_LANGUAGES) {
87
+ ctx.effect(() => ctx.locale.addLanguage({ id: language.id, label: language.label, fallback: language.fallback }), `presmium: language ${language.id}`)
88
+ for (const [ns, dict] of Object.entries(BRAND_COPY[language.id])) ctx.effect(() => ctx.locale.register(ns, language.id, dict), `presmium: ${ns} copy ${language.id}`)
89
+ }
90
+ }
@@ -0,0 +1,79 @@
1
+ import { PmIconButton } from '@lincyaw/workbench'
2
+ import type { Workbench } from '@lincyaw/workbench'
3
+ import type { ReactNode } from 'react'
4
+ import { useFrameMessages } from './brand.tsx'
5
+ import type { LayoutActions, LayoutState } from './layout.ts'
6
+ import { NARROW, SIDE_COLLAPSE } from './layout.ts'
7
+
8
+ interface SidebarProps {
9
+ renderSlot(name: string, props?: Record<string, unknown>, options?: Record<string, unknown>): ReactNode
10
+ }
11
+
12
+ /** Replace navigation chrome through public slots; Harness still owns the session browser and dialogs. */
13
+ export function chrome(ctx: DshClientContext, workbench: Workbench, actions: LayoutActions, currentLayout: () => LayoutState, startSession: () => Promise<void>): DshObservable<readonly DshSlotEntry[]> {
14
+ let panels: DshSlotEntry[] = []
15
+ const listeners = new Set<() => void>()
16
+ const panelStore = {
17
+ getSnapshot: () => panels,
18
+ subscribe(listener: () => void) { listeners.add(listener); return () => { listeners.delete(listener) } },
19
+ }
20
+ // An already running host retains its old plugin roster until it is restarted.
21
+ if (!window.__DSH_BOOT__?.entries.some(entry => entry.id === '@deepseek-ai/dsh-client-ui-sidebar')) ctx.effect(() => {
22
+ const offPanels = ctx.slots.subscribe('sidebar.panellist', () => {
23
+ panels = ctx.slots.entries('sidebar.panellist')
24
+ for (const listener of listeners) listener()
25
+ })
26
+ ctx.slots.inject('sidebar.panellist', () => {
27
+ panels = ctx.slots.entries('sidebar.panellist')
28
+ for (const listener of listeners) listener()
29
+ })
30
+ const closeHistory = () => {
31
+ if (currentLayout().layoutInfo.viewportWidth < SIDE_COLLAPSE) actions.revealConversation()
32
+ else actions.toggleSidebar()
33
+ }
34
+ function Sidebar({ renderSlot }: SidebarProps) {
35
+ const t = useFrameMessages(workbench)
36
+ return <section className="pmw-history" aria-label={t.conversationHistory}>
37
+ <header className="pmw-history__header"><h2>{t.conversationHistory}</h2><PmIconButton icon="close" small label={t.closeHistory} onClick={closeHistory} /></header>
38
+ <div className="pmw-history__browser">{renderSlot('sidebar.workspaces', { wide: true, expandSidebar: () => actions.choose('sessions') })}</div>
39
+ <div hidden>{renderSlot('sidebar.settings', { wide: false })}</div>
40
+ </section>
41
+ }
42
+ let offSidebar: (() => void) | undefined
43
+ ctx.slots.inject('sidebar', () => {
44
+ offSidebar = ctx.slots.register({ name: 'sidebar', priority: -1, children: {
45
+ 'sidebar.brand.mark': { kind: 'single', scope: 'root' },
46
+ 'sidebar.brand.name': { kind: 'single', scope: 'root' },
47
+ 'sidebar.toggle.badge': { kind: 'single', scope: 'root' },
48
+ 'sidebar.workspaces': { kind: 'single', scope: 'root' },
49
+ 'sidebar.settings': { kind: 'single', scope: 'root' },
50
+ 'sidebar.footer.action': { kind: 'list', scope: 'root' },
51
+ } }, Sidebar)
52
+ })
53
+ return () => { offSidebar?.(); offPanels() }
54
+ }, 'presmium: one navigation shell')
55
+ ctx.effect(() => {
56
+ function ConversationActions() {
57
+ const t = useFrameMessages(workbench)
58
+ return <div className="pmw-chat-actions pm-ui" role="group" aria-label={t.conversation}>
59
+ <PmIconButton icon="plus" label={t.newConversation} small onClick={() => void startSession()} />
60
+ <PmIconButton icon="history" label={t.conversationHistory} small onClick={() => actions.showHistory()} />
61
+ <PmIconButton icon="close" label={t.hideConversation} small onClick={() => {
62
+ if (currentLayout().layoutInfo.viewportWidth < NARROW) actions.show(workbench.state.document === undefined ? 'documents' : 'preview')
63
+ else actions.setDockOpen(false)
64
+ }} />
65
+ </div>
66
+ }
67
+ let off: (() => void) | undefined
68
+ ctx.slots.inject('conversation.header.leading', () => { off = ctx.slots.register({ name: 'conversation.header.leading', priority: -1 }, ConversationActions) })
69
+ return () => off?.()
70
+ }, 'presmium: conversation actions in its resident header')
71
+ ctx.effect(() => {
72
+ let off: (() => void) | undefined
73
+ ctx.slots.inject('conversation.session.header.corner', () => {
74
+ off = ctx.slots.register({ name: 'conversation.session.header.corner', priority: -1 }, () => null)
75
+ })
76
+ return () => off?.()
77
+ }, 'presmium: remove the duplicate sidebar opener')
78
+ return panelStore
79
+ }
@@ -0,0 +1,35 @@
1
+ export const CLIENT_ID = '@lincyaw/dsh'
2
+
3
+ export const ROOT_CHILDREN = {
4
+ 'sidebar': { kind: 'single', scope: 'root' },
5
+ 'main': { kind: 'keyed', scope: 'root' },
6
+ 'rightbar': { kind: 'single', scope: 'root' },
7
+ 'shell.bottom': { kind: 'single', scope: 'root' },
8
+ 'shell.overlay': { kind: 'list', scope: 'root' },
9
+ 'shell.leading': { kind: 'single', scope: 'root' },
10
+ } as const
11
+
12
+ export const LAYOUT_MEMBERS = ['panelInfo', 'selectPanel', 'beginNavigation', 'toggleSidebar', 'openRightbar', 'closeRightbar'] as const
13
+
14
+ export const BRAND_SLOTS = ['sidebar.brand.mark', 'sidebar.brand.name', 'conversation.hero.brand.mark'] as const
15
+ export const ONBOARDING = { slot: 'settings.onboarding', steps: ['welcome-notice', 'deepseek-official'] } as const
16
+
17
+ export const SHELL_MODULES = [
18
+ 'react',
19
+ 'react/jsx-runtime',
20
+ 'react-dom',
21
+ 'react-dom/client',
22
+ '@deepseek-ai/cordis',
23
+ 'zod',
24
+ '@tanstack/react-virtual',
25
+ '@deepseek-ai/dsh-client-store',
26
+ '@deepseek-ai/dsh-client-ui-slots',
27
+ '@deepseek-ai/dsh-client-ui-primitives',
28
+ '@deepseek-ai/dsh-client-ui-dockkit',
29
+ ] as const
30
+
31
+ export const EXPERIMENTAL_GROUP = '[data-plugin-group="extensions"]'
32
+
33
+ export const UI_LAYOUT = '@deepseek-ai/dsh-client-ui-layout'
34
+
35
+ export const BRAND_LANGUAGES = [{ id: 'zh-CN', label: '简体中文(Presmium)', fallback: 'zh' }, { id: 'en-US', label: 'English (Presmium)', fallback: 'en' }] as const
@@ -0,0 +1,129 @@
1
+ declare module '@deepseek-ai/dsh-client-ui-primitives' {
2
+ export const Modal: import('react').ComponentType<{
3
+ open: boolean
4
+ title: string
5
+ onClose(): void
6
+ headless: true
7
+ children?: import('react').ReactNode
8
+ }>
9
+ }
10
+
11
+ declare module '@deepseek-ai/dsh-client-store' {
12
+ export interface StoreInstance<S, A> {
13
+ actions: A
14
+ getSnapshot(): S
15
+ subscribe(listener: () => void): () => void
16
+ }
17
+ export interface StoreHandle<S, A> {
18
+ create(): StoreInstance<S, A>
19
+ }
20
+ type Bound<A> = { [K in keyof A]: A[K] extends (draft: any, ...args: infer P) => void ? (...args: P) => void : never }
21
+ export function defineStore<S, A extends Record<string, (draft: S, ...args: any[]) => void>>(spec: { init: () => S, actions: A }): StoreHandle<S, Bound<A>>
22
+ }
23
+
24
+ interface DshObservable<T> {
25
+ getSnapshot(): T
26
+ subscribe(listener: () => void): () => void
27
+ }
28
+
29
+ type DshSelectorHook<T> = <U>(select: (value: T) => U) => U
30
+
31
+ interface DshSlotOptions {
32
+ name: string
33
+ key?: string
34
+ id?: string
35
+ priority?: number
36
+ order?: number
37
+ locale?: string
38
+ label?: string | (() => string)
39
+ children?: Record<string, { kind: 'single' | 'keyed' | 'list', scope: 'root' }>
40
+ store?: unknown
41
+ inject?: unknown
42
+ }
43
+
44
+ interface DshSlotEntry {
45
+ options: { key?: string, id?: string, label?: string | (() => string) }
46
+ }
47
+
48
+ interface DshSlots {
49
+ register(options: DshSlotOptions, component: (props: any) => unknown): () => void
50
+ inject(name: string, effect: () => unknown): void
51
+ entries(name: string): DshSlotEntry[]
52
+ subscribe(name: string, listener: () => void): () => void
53
+ provideRoot(options: { hooks: Record<string, DshObservable<unknown>> }): () => void
54
+ }
55
+
56
+ interface DshThemeSnapshot {
57
+ preference: string
58
+ fontSizes: { text: number, code: number, terminal: number }
59
+ fontFamilies: { text: string, code: string, terminal: string }
60
+ active: { id: string, colorScheme: 'light' | 'dark', tokens: Record<string, string> }
61
+ }
62
+
63
+ interface DshTheme {
64
+ getTheme(): DshThemeSnapshot
65
+ overrideTokens(source: string, tokens: Record<string, { light: string, dark: string }>): () => void
66
+ }
67
+
68
+ interface DshLocale {
69
+ getLocale(): { active: string, locales: readonly { id: string }[] }
70
+ subscribe(listener: () => void): () => void
71
+ addLanguage(language: { id: string, label: string, fallback?: string }): () => void
72
+ register(ns: string, locale: string | Record<string, Record<string, string>>, dict?: Record<string, string>): () => void
73
+ bind(ns: string): (key: string, values?: Record<string, string>) => string
74
+ }
75
+
76
+ interface DshShortcuts {
77
+ register(command: {
78
+ id: string
79
+ label: () => string
80
+ aliases?: string[]
81
+ defaults: Record<string, { code: string, modifiers: string[] }>
82
+ regions?: string[]
83
+ modals?: string[]
84
+ resolve: () => { status: 'handled', run: () => void }
85
+ }): () => void
86
+ }
87
+
88
+ interface DshSidebarRightTabs {
89
+ register(definition: {
90
+ id: string
91
+ kind: string
92
+ priority?: 'extension' | 'builtin' | 'fallback'
93
+ keepMounted?: boolean
94
+ patterns?: readonly string[]
95
+ canOpen?(address: string): boolean
96
+ title: (address?: string) => string
97
+ guide?: { id: string, order?: number, title: () => string, description?: () => string }[]
98
+ }): () => void
99
+ }
100
+
101
+ interface DshSourceTabProps {
102
+ useTabInfo(): { tab: {
103
+ contentId: string
104
+ visible: boolean
105
+ navigation: { revision: number, params?: { line?: unknown } }
106
+ actions: { close(): void }
107
+ } }
108
+ }
109
+
110
+ interface DshClientContext {
111
+ effect(effect: () => unknown, label?: string): void
112
+ on(event: string, listener: (...args: any[]) => void): () => void
113
+ inject(names: string[], apply: (ctx: DshClientContext) => void): void
114
+ reflect: { provide(name: string, value: unknown): () => void }
115
+ slots: DshSlots
116
+ theme: DshTheme
117
+ locale: DshLocale
118
+ shortcuts: DshShortcuts
119
+ sidebarRightTabs: DshSidebarRightTabs
120
+ sidebarRight: { active(): { id: string, kind: string, contentId: string } | undefined, close(id: string): void, isExpanded(): boolean, toggleExpanded(): void }
121
+ layout: { selectPanel(id: string | null): void }
122
+ sessions: { list: DshObservable<{ byId: Record<string, { id: string, cwd?: string, retainedBy: { mainView?: number } }> }> }
123
+ uiWorkspace: { openWorkspace(id: string, beforeOpen?: (sessionId: string) => void): Promise<void>, startSession(id?: string): void }
124
+ workspaces: { list: DshObservable<{ items: readonly { workspaceId: string, path: string }[] }> }
125
+ }
126
+
127
+ interface Window {
128
+ __DSH_BOOT__?: { entries: { id: string }[], release?: { version: string, commit?: string } }
129
+ }
@@ -0,0 +1,49 @@
1
+ import { ChangesPanel, DocumentView, FilesPanel, HomePanel, PreviewPanel, useWorkbench, WorkbenchProvider } from '@lincyaw/workbench'
2
+ import type { Workbench } from '@lincyaw/workbench'
3
+ import type { ComponentType } from 'react'
4
+ import { Logo } from './brand.tsx'
5
+ import { CLIENT_ID } from './contract.ts'
6
+ import { FRAME_MESSAGES } from './messages.ts'
7
+
8
+ export const FALLBACK_PANEL = 'presmium'
9
+
10
+ function Centre() {
11
+ const document_ = useWorkbench(state => state.document)
12
+ return (
13
+ <div className="pmw-fallback pm-ui" data-pmw-fallback="">
14
+ {document_ === undefined
15
+ ? <HomePanel />
16
+ : (
17
+ <div className="pmw-fallback__doc">
18
+ <FilesPanel />
19
+ <DocumentView />
20
+ </div>
21
+ )}
22
+ </div>
23
+ )
24
+ }
25
+
26
+ export function fallback(ctx: DshClientContext, workbench: Workbench): void {
27
+ const t = () => FRAME_MESSAGES[workbench.state.locale]
28
+ const provided = (Component: ComponentType, className?: string, protectChanges = false) => function PresmiumPanel() {
29
+ return (
30
+ <WorkbenchProvider workbench={workbench} protectChanges={protectChanges}>
31
+ {className ? <div className={className}><Component /></div> : <Component />}
32
+ </WorkbenchProvider>
33
+ )
34
+ }
35
+ ctx.effect(() => ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({ name: 'sidebar.panellist', id: FALLBACK_PANEL, order: -10, label: () => t().product }, () => <Logo size={20} />)), 'presmium: the panel list entry')
36
+ ctx.effect(() => ctx.slots.register({ name: 'main', key: FALLBACK_PANEL }, provided(Centre, undefined, true)), 'presmium: the workbench as a global panel')
37
+ ctx.inject(['sidebarRightTabs'], (inner) => {
38
+ const tabs = [
39
+ { kind: 'presmium-preview', Panel: PreviewPanel, title: () => `Presmium · ${t().preview}` },
40
+ { kind: 'presmium-changes', Panel: ChangesPanel, title: () => `Presmium · ${t().changes}` },
41
+ ]
42
+ for (const { kind, Panel, title } of tabs) {
43
+ const id = `${CLIENT_ID}/${kind}`
44
+ const Body = provided(Panel, 'pmw-fallback__tab pm-ui')
45
+ inner.effect(() => inner.sidebarRightTabs.register({ id, kind, priority: 'extension', keepMounted: true, title, guide: [{ id: kind, order: 50, title }] }), `presmium: ${kind} tab type`)
46
+ inner.effect(() => inner.slots.inject('sidebar.right.pane.tab', () => inner.slots.register({ name: 'sidebar.right.pane.tab', key: id }, Body)), `presmium: ${kind} tab body`)
47
+ }
48
+ })
49
+ }