dsh-better-sidebar 0.10.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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/README_EN.md +139 -0
- package/lib/client-docx.js +7649 -0
- package/lib/client-editor.js +32677 -0
- package/lib/client-pptx.js +63438 -0
- package/lib/client-registry.js +8021 -0
- package/lib/client-terminal.js +8060 -0
- package/lib/client-xlsx.js +359755 -0
- package/lib/client.js +8021 -0
- package/lib/index.js +2604 -0
- package/lib/invariant.js +22 -0
- package/lib/types/agent-pty.d.ts +220 -0
- package/lib/types/browser-probe.d.ts +15 -0
- package/lib/types/bundle-route.d.ts +13 -0
- package/lib/types/client/BrowserView.d.ts +22 -0
- package/lib/types/client/DiffTab.d.ts +6 -0
- package/lib/types/client/DiffView.d.ts +51 -0
- package/lib/types/client/EditorHost.d.ts +10 -0
- package/lib/types/client/ExplorerView.d.ts +9 -0
- package/lib/types/client/GitView.d.ts +8 -0
- package/lib/types/client/OrphanedTab.d.ts +11 -0
- package/lib/types/client/PdfView.d.ts +6 -0
- package/lib/types/client/PptxView.d.ts +6 -0
- package/lib/types/client/SandboxStatusBar.d.ts +10 -0
- package/lib/types/client/SideCardSection.d.ts +27 -0
- package/lib/types/client/Sidebar.d.ts +6 -0
- package/lib/types/client/SubagentView.d.ts +16 -0
- package/lib/types/client/TabBar.d.ts +38 -0
- package/lib/types/client/TerminalView.d.ts +8 -0
- package/lib/types/client/TextEditor.d.ts +10 -0
- package/lib/types/client/api.d.ts +170 -0
- package/lib/types/client/binary-download.d.ts +12 -0
- package/lib/types/client/breakpoints.d.ts +12 -0
- package/lib/types/client/browser.d.ts +50 -0
- package/lib/types/client/builtins/index.d.ts +17 -0
- package/lib/types/client/builtins/tabs.d.ts +6 -0
- package/lib/types/client/builtins/viewers.d.ts +3 -0
- package/lib/types/client/chunk-loader.d.ts +74 -0
- package/lib/types/client/chunks/docx.d.ts +8 -0
- package/lib/types/client/chunks/editor.d.ts +9 -0
- package/lib/types/client/chunks/pptx.d.ts +8 -0
- package/lib/types/client/chunks/terminal.d.ts +9 -0
- package/lib/types/client/chunks/xlsx.d.ts +9 -0
- package/lib/types/client/cm-themes.d.ts +24 -0
- package/lib/types/client/conversation-draft.d.ts +14 -0
- package/lib/types/client/docx-view.d.ts +8 -0
- package/lib/types/client/editor-load.d.ts +66 -0
- package/lib/types/client/icons.d.ts +47 -0
- package/lib/types/client/image-types.d.ts +3 -0
- package/lib/types/client/ime-guard.d.ts +36 -0
- package/lib/types/client/index.d.ts +10 -0
- package/lib/types/client/intercept.d.ts +20 -0
- package/lib/types/client/lang.d.ts +12 -0
- package/lib/types/client/lazy-chunk.d.ts +25 -0
- package/lib/types/client/link-intercept.d.ts +35 -0
- package/lib/types/client/locales.d.ts +237 -0
- package/lib/types/client/office-shared.d.ts +33 -0
- package/lib/types/client/office-types.d.ts +36 -0
- package/lib/types/client/office-view.d.ts +12 -0
- package/lib/types/client/openpath-intercept.d.ts +41 -0
- package/lib/types/client/paths.d.ts +19 -0
- package/lib/types/client/pdf-types.d.ts +2 -0
- package/lib/types/client/prefs.d.ts +30 -0
- package/lib/types/client/produced-files.d.ts +27 -0
- package/lib/types/client/selection-payload.d.ts +27 -0
- package/lib/types/client/service.d.ts +214 -0
- package/lib/types/client/split-pane.d.ts +29 -0
- package/lib/types/client/state.d.ts +322 -0
- package/lib/types/client/subagent-activity.d.ts +35 -0
- package/lib/types/client/subagent-detect.d.ts +47 -0
- package/lib/types/client/subagent-jobs.d.ts +63 -0
- package/lib/types/client/theme.d.ts +28 -0
- package/lib/types/client/xlsx-to-univer.d.ts +33 -0
- package/lib/types/client/xlsx-view.d.ts +10 -0
- package/lib/types/config.d.ts +41 -0
- package/lib/types/context-types.d.ts +431 -0
- package/lib/types/fs-tree.d.ts +41 -0
- package/lib/types/git.d.ts +75 -0
- package/lib/types/html-route.d.ts +48 -0
- package/lib/types/index.d.ts +39 -0
- package/lib/types/invariant.d.ts +15 -0
- package/lib/types/jobs-routes.d.ts +45 -0
- package/lib/types/prefs-shared.d.ts +106 -0
- package/lib/types/pty-manager.d.ts +76 -0
- package/lib/types/tools.d.ts +28 -0
- package/lib/types/trust-fence.d.ts +24 -0
- package/lib/types/wire.d.ts +38 -0
- package/package.json +168 -0
- package/src/agent-pty.ts +519 -0
- package/src/browser-probe.ts +26 -0
- package/src/bundle-route.ts +130 -0
- package/src/client/BrowserView.tsx +253 -0
- package/src/client/DiffTab.tsx +110 -0
- package/src/client/DiffView.tsx +266 -0
- package/src/client/EditorHost.tsx +101 -0
- package/src/client/ExplorerView.tsx +283 -0
- package/src/client/GitView.tsx +540 -0
- package/src/client/OrphanedTab.tsx +27 -0
- package/src/client/PdfView.tsx +110 -0
- package/src/client/PptxView.tsx +131 -0
- package/src/client/SandboxStatusBar.tsx +60 -0
- package/src/client/SideCardSection.module.css +271 -0
- package/src/client/SideCardSection.tsx +426 -0
- package/src/client/Sidebar.tsx +861 -0
- package/src/client/SubagentView.module.css +547 -0
- package/src/client/SubagentView.tsx +866 -0
- package/src/client/TabBar.tsx +188 -0
- package/src/client/TerminalView.tsx +233 -0
- package/src/client/TextEditor.tsx +382 -0
- package/src/client/api.ts +215 -0
- package/src/client/binary-download.tsx +23 -0
- package/src/client/breakpoints.ts +51 -0
- package/src/client/browser.ts +119 -0
- package/src/client/builtins/index.ts +33 -0
- package/src/client/builtins/tabs.tsx +211 -0
- package/src/client/builtins/viewers.tsx +151 -0
- package/src/client/chunk-loader.ts +196 -0
- package/src/client/chunks/docx.tsx +8 -0
- package/src/client/chunks/editor.tsx +9 -0
- package/src/client/chunks/pptx.tsx +8 -0
- package/src/client/chunks/terminal.tsx +9 -0
- package/src/client/chunks/xlsx.tsx +9 -0
- package/src/client/cm-themes.ts +129 -0
- package/src/client/conversation-draft.ts +29 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/docx-view.tsx +113 -0
- package/src/client/editor-load.ts +92 -0
- package/src/client/icons.tsx +137 -0
- package/src/client/image-types.ts +8 -0
- package/src/client/ime-guard.ts +47 -0
- package/src/client/index.tsx +238 -0
- package/src/client/intercept.tsx +94 -0
- package/src/client/lang.ts +95 -0
- package/src/client/layout.css +54 -0
- package/src/client/lazy-chunk.tsx +89 -0
- package/src/client/link-intercept.ts +66 -0
- package/src/client/locales.ts +476 -0
- package/src/client/office-shared.tsx +40 -0
- package/src/client/office-types.ts +48 -0
- package/src/client/office-view.tsx +12 -0
- package/src/client/openpath-intercept.ts +62 -0
- package/src/client/paths.ts +28 -0
- package/src/client/pdf-types.ts +4 -0
- package/src/client/prefs.ts +100 -0
- package/src/client/produced-files.ts +87 -0
- package/src/client/selection-payload.ts +86 -0
- package/src/client/service.ts +434 -0
- package/src/client/sidebar.module.css +1917 -0
- package/src/client/split-pane.tsx +292 -0
- package/src/client/state.ts +1048 -0
- package/src/client/subagent-activity.ts +67 -0
- package/src/client/subagent-detect.ts +125 -0
- package/src/client/subagent-jobs.ts +161 -0
- package/src/client/theme.ts +44 -0
- package/src/client/xlsx-to-univer.ts +260 -0
- package/src/client/xlsx-view.tsx +116 -0
- package/src/config.ts +95 -0
- package/src/context-types.ts +445 -0
- package/src/fs-tree.ts +115 -0
- package/src/git.ts +236 -0
- package/src/html-route.ts +70 -0
- package/src/index.ts +897 -0
- package/src/invariant.ts +32 -0
- package/src/jobs-routes.ts +257 -0
- package/src/prefs-shared.ts +127 -0
- package/src/pty-manager.ts +199 -0
- package/src/tools.ts +477 -0
- package/src/trust-fence.ts +77 -0
- package/src/wire.ts +94 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout push: when a panel is open it OCCUPIES the layout instead of
|
|
3
|
+
* floating over it — the app shell (#root, the AppFrame three-column grid)
|
|
4
|
+
* gives up space. Only the center column is flexible (1fr), so the right
|
|
5
|
+
* panel's width squeeze (margin-right on #root) lands exactly on the
|
|
6
|
+
* conversation output and the input bar, like a VSCode sidebar.
|
|
7
|
+
*
|
|
8
|
+
* The bottom panel squeezes ONLY the center column — it must not cover the
|
|
9
|
+
* app's own left sidebar or the right panel. The AppFrame's grid items are
|
|
10
|
+
* (#root > div > div:nth-child(2)): sidebarCol, centerCol, detailsCol, so
|
|
11
|
+
* the vertical push lands on the center column alone. The fixed panels
|
|
12
|
+
* cover the vacated strips, which looks seamless because #root's background
|
|
13
|
+
* is the theme base.
|
|
14
|
+
*
|
|
15
|
+
* The sizes ride CSS variables updated by the Sidebar shell (0 while
|
|
16
|
+
* collapsed); expand/collapse animates both the margins and the panel
|
|
17
|
+
* slides on the same theme duration. Drags disable the transition so the
|
|
18
|
+
* layout tracks the pointer.
|
|
19
|
+
*/
|
|
20
|
+
#root {
|
|
21
|
+
margin-right: var(--dsh-sidebar-width, 0px);
|
|
22
|
+
transition: margin-right var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* The AppFrame's grid items are sidebarCol, centerCol, detailsCol (children
|
|
26
|
+
1-3 of #root > div) — nth-child(2) is the center column. A stretched grid
|
|
27
|
+
item shrinks by its margins, so the conversation content (output + input
|
|
28
|
+
bar) lifts without touching the sidebars. */
|
|
29
|
+
#root > div > div:nth-child(2) {
|
|
30
|
+
margin-bottom: var(--dsh-sidebar-height, 0px);
|
|
31
|
+
transition: margin-bottom var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* When the sidebar is collapsed, the toggle cluster reclaims the top-right
|
|
35
|
+
corner. Push the DSH session header's right padding out so its right-aligned
|
|
36
|
+
utilities (the "Session log" download capsule) yield the corner instead of
|
|
37
|
+
hiding under the cluster. The header default right-pads 28px; the 2-button
|
|
38
|
+
cluster spans right 10→70px, so 78px clears it with an 8px gap. The
|
|
39
|
+
Sidebar shell toggles the body attribute with the panel open state. */
|
|
40
|
+
body[data-dsh-sidebar-collapsed] #root > div > div:nth-child(2) header {
|
|
41
|
+
padding-right: 78px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
body[data-dsh-sidebar-dragging] #root,
|
|
45
|
+
body[data-dsh-sidebar-dragging] #root > div > div:nth-child(2) {
|
|
46
|
+
transition: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@media (prefers-reduced-motion: reduce) {
|
|
50
|
+
#root,
|
|
51
|
+
#root > div > div:nth-child(2) {
|
|
52
|
+
transition: none;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy chunk view wrapper: mounts a component that lives in a lazy chunk,
|
|
3
|
+
* showing a loading placeholder while the chunk script loads and an error +
|
|
4
|
+
* retry affordance on failure. Used by the built-in tab/viewer descriptors.
|
|
5
|
+
*
|
|
6
|
+
* Contract note: {@link lazyChunkComponent} returns a plain render-prop
|
|
7
|
+
* function — the descriptor contract is `component: (props) => ReactNode`,
|
|
8
|
+
* and the repo renders descriptors BOTH ways: Sidebar calls
|
|
9
|
+
* `descriptor.component(props)` directly, EditorHost renders it via
|
|
10
|
+
* `createElement`. The wrapper function body therefore contains no hooks;
|
|
11
|
+
* all state lives in the inner {@link LazyChunkView} component.
|
|
12
|
+
*/
|
|
13
|
+
import { createElement, useEffect, useState, type ComponentType, type ReactNode } from 'react'
|
|
14
|
+
import { loadChunk, type ChunkExports, type ChunkName } from './chunk-loader.ts'
|
|
15
|
+
import { t } from './locales.ts'
|
|
16
|
+
import css from './sidebar.module.css'
|
|
17
|
+
|
|
18
|
+
interface LazyChunkViewProps<P> {
|
|
19
|
+
chunk: ChunkName
|
|
20
|
+
/** Module-level-stable selector (an inline lambda would re-trigger the effect). */
|
|
21
|
+
pick: (mod: ChunkExports) => ComponentType<P> | undefined
|
|
22
|
+
props: P
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function LazyChunkView<P>({ chunk, pick, props }: LazyChunkViewProps<P>): ReactNode {
|
|
26
|
+
const [attempt, setAttempt] = useState(0)
|
|
27
|
+
const [state, setState] = useState<
|
|
28
|
+
| { status: 'loading' }
|
|
29
|
+
| { status: 'error'; message: string }
|
|
30
|
+
| { status: 'ready'; Comp: ComponentType<any> }
|
|
31
|
+
>({ status: 'loading' })
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let cancelled = false
|
|
35
|
+
setState({ status: 'loading' })
|
|
36
|
+
loadChunk(chunk).then((mod) => {
|
|
37
|
+
if (cancelled) return
|
|
38
|
+
const Comp = pick(mod)
|
|
39
|
+
if (Comp === undefined) {
|
|
40
|
+
setState({ status: 'error', message: `[dsh-better-sidebar] chunk "${chunk}" is missing its component` })
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
setState({ status: 'ready', Comp })
|
|
44
|
+
}).catch((error: unknown) => {
|
|
45
|
+
if (cancelled) return
|
|
46
|
+
setState({ status: 'error', message: error instanceof Error ? error.message : String(error) })
|
|
47
|
+
})
|
|
48
|
+
return () => { cancelled = true }
|
|
49
|
+
}, [chunk, pick, attempt])
|
|
50
|
+
|
|
51
|
+
if (state.status === 'loading') {
|
|
52
|
+
return <div className={css.editorPlaceholder}>{t('loading')}</div>
|
|
53
|
+
}
|
|
54
|
+
if (state.status === 'error') {
|
|
55
|
+
return (
|
|
56
|
+
<div className={css.editorError}>
|
|
57
|
+
<span>{state.message}</span>
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
className={css.terminalRetry}
|
|
61
|
+
onClick={() => { setAttempt(current => current + 1) }}
|
|
62
|
+
>
|
|
63
|
+
{t('terminalRetry')}
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
return createElement(state.Comp, props)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build a descriptor-compatible lazy wrapper for a chunk-resident component.
|
|
73
|
+
* The returned function is the descriptor `component` itself: it returns an
|
|
74
|
+
* element and never calls hooks, so both invocation styles (plain function
|
|
75
|
+
* call and createElement/JSX render) work. `pick` must be a module-level
|
|
76
|
+
* function (stable identity) — an inline lambda would re-trigger the load
|
|
77
|
+
* effect on every render.
|
|
78
|
+
* @param chunk - the chunk name (see chunk-loader.ts).
|
|
79
|
+
* @param pick - select the component from the chunk's exports.
|
|
80
|
+
*/
|
|
81
|
+
export function lazyChunkComponent<P extends object>(
|
|
82
|
+
chunk: ChunkName,
|
|
83
|
+
pick: (mod: ChunkExports) => ComponentType<P> | undefined,
|
|
84
|
+
): (props: P) => ReactNode {
|
|
85
|
+
return (props: P) => createElement(
|
|
86
|
+
LazyChunkView as ComponentType<LazyChunkViewProps<P>>,
|
|
87
|
+
{ chunk, pick, props },
|
|
88
|
+
)
|
|
89
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat/GUI external-link interception: clicking an http(s) link that points
|
|
3
|
+
* OUTSIDE the GUI (chat messages, tool rows, prose mentions) opens the
|
|
4
|
+
* sidebar browser instead of a new browser tab. Gated by BOTH the
|
|
5
|
+
* `browserInterceptLinks` pref and the browser tab's enable switch; a
|
|
6
|
+
* Ctrl/Cmd/Shift/Alt-modified click always bypasses the takeover so the
|
|
7
|
+
* user can still force a real browser tab.
|
|
8
|
+
*
|
|
9
|
+
* Only the GUI's OWN document is watched — links inside the browser tab's
|
|
10
|
+
* sandboxed iframe live in another document and never bubble here (and
|
|
11
|
+
* their clicks must keep working inside the sidebar).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** The pure decision: the URL to open in the sidebar, or null to let the
|
|
15
|
+
* click fall through. Extracted so the policy is unit-testable without a
|
|
16
|
+
* DOM. `anchorHref` must be the ABSOLUTE href (`<a>.href` already is). */
|
|
17
|
+
export function shouldInterceptLink(anchorHref: string, selfOrigin: string): string | null {
|
|
18
|
+
let url: URL
|
|
19
|
+
try {
|
|
20
|
+
url = new URL(anchorHref)
|
|
21
|
+
} catch {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return null
|
|
25
|
+
// Same-origin links are GUI-internal navigation (settings pages, tool
|
|
26
|
+
// docs) — never routed into the sidebar browser.
|
|
27
|
+
try {
|
|
28
|
+
if (url.origin === new URL(selfOrigin).origin) return null
|
|
29
|
+
} catch {
|
|
30
|
+
// Unparsable selfOrigin (never in practice): intercept defensively.
|
|
31
|
+
}
|
|
32
|
+
return url.href
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Whether a left-click may be taken over (unmodified left click only). */
|
|
36
|
+
export function isPlainLeftClick(event: { button: number; metaKey: boolean; ctrlKey: boolean; shiftKey: boolean; altKey: boolean }): boolean {
|
|
37
|
+
return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Register the document-level click capture that funnels external links
|
|
42
|
+
* into the sidebar browser. Returns the disposer (HMR-safe).
|
|
43
|
+
*/
|
|
44
|
+
export function registerLinkInterception(opts: {
|
|
45
|
+
takeoverEnabled: () => boolean
|
|
46
|
+
/** Open the sidebar browser tab at `url` (the caller resolves the session). */
|
|
47
|
+
openInSidebar: (url: string) => void
|
|
48
|
+
/** The GUI's own origin (window.location.origin at registration). */
|
|
49
|
+
selfOrigin: string
|
|
50
|
+
}): () => void {
|
|
51
|
+
const onClick = (event: MouseEvent): void => {
|
|
52
|
+
if (!isPlainLeftClick(event)) return
|
|
53
|
+
if (event.defaultPrevented) return
|
|
54
|
+
if (!opts.takeoverEnabled()) return
|
|
55
|
+
const target = event.target
|
|
56
|
+
if (target === null || typeof (target as Element).closest !== 'function') return
|
|
57
|
+
const anchor = (target as Element).closest('a[href]') as HTMLAnchorElement | null
|
|
58
|
+
if (anchor === null) return
|
|
59
|
+
const url = shouldInterceptLink(anchor.href, opts.selfOrigin)
|
|
60
|
+
if (url === null) return
|
|
61
|
+
event.preventDefault()
|
|
62
|
+
opts.openInSidebar(url)
|
|
63
|
+
}
|
|
64
|
+
document.addEventListener('click', onClick, true)
|
|
65
|
+
return () => { document.removeEventListener('click', onClick, true) }
|
|
66
|
+
}
|