@fonlan/dsh-quick-commands 0.1.6 → 0.1.8
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/lib/client.js +138 -13
- package/lib/client.js.map +1 -1
- package/lib/index.js +206 -52
- package/lib/types/index.d.ts +4 -2
- package/lib/types/server/settings.d.ts +14 -4
- package/lib/types/server/shell-path.d.ts +69 -0
- package/lib/types/shared/contract.d.ts +7 -0
- package/package.json +30 -27
- package/src/client/header.tsx +15 -12
- package/src/client/icons.tsx +106 -0
- package/src/client/settings-section.tsx +6 -9
- package/src/index.ts +51 -36
- package/src/server/rpc.ts +8 -3
- package/src/server/runner.ts +7 -3
- package/src/server/settings.ts +74 -29
- package/src/server/shell-path.ts +160 -0
- package/src/shared/contract.ts +10 -0
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","IconPlayOutline16","createPortal","IconCloseOutline16","IconStopFill16","useState","useRef","IconTrashOutline16","IconPlusOutline16"],"sources":["../../../src/client/api.ts","../../../src/client/run-state.ts","../../../src/client/header.tsx","../../../src/client/settings-section.tsx","../../../src/client/locales.ts","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Browser client for the plugin's fenced JSON API\n * (/plugins/@fonlan/dsh-quick-commands/api/<method>). Same-origin fetch with\n * the task-kanban envelope shape: { ok, value } | { ok:false, error }.\n */\nimport type {\n ApiEnvelope,\n QuickCommandsSettings,\n QuickPopupSize,\n QuickRosterEntry,\n QuickRunView,\n} from '../shared/contract'\n\nexport class QuickCommandsApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-quick-commands/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new QuickCommandsApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed = (await response.json().catch(() => null)) as ApiEnvelope<T> | null\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new QuickCommandsApiError(\n (parsed?.error?.code as string | undefined) ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** Current session cwd of a session row (SessionSummary carries cwd). */\nexport interface SessionRow {\n id: string\n cwd?: string\n}\n\n/** One delta read result (mirrors the host RunPollResult). */\nexport interface RunPoll {\n status: 'running' | 'exited'\n exitCode: number | null\n signal: string | null\n stdoutEnd: number\n stderrEnd: number\n stdoutDelta: string\n stderrDelta: string\n stdoutLossy: boolean\n stderrLossy: boolean\n}\n\nexport const quickApi = {\n settingsGet: () => call<QuickCommandsSettings>('settings.get'),\n settingsSetCommands: (workspaceId: string, commands: Array<{ name: string; command: string }>) =>\n call<QuickCommandsSettings>('settings.setCommands', { workspaceId, commands }),\n settingsSetAnchor: (anchor: QuickCommandsSettings['popupAnchor']) =>\n call<QuickCommandsSettings>('settings.setAnchor', { anchor }),\n settingsSetPopupSize: (size: QuickPopupSize) =>\n call<QuickCommandsSettings>('settings.setPopupSize', { width: size.width, height: size.height }),\n workspacesList: () => call<QuickRosterEntry[]>('workspaces.list'),\n runStart: (workspaceId: string, commandName: string, sessionCwd: string) =>\n call<QuickRunView>('run.start', { workspaceId, commandName, sessionCwd }),\n runPoll: (runId: string, stdoutFrom: number, stderrFrom: number) =>\n call<RunPoll>('run.poll', { runId, stdoutFrom, stderrFrom }),\n runKill: (runId: string) => call<{ killed: boolean }>('run.kill', { runId }),\n runList: (workspaceId: string) =>\n call<Array<{ runId: string; commandName: string; startedAt: number; status: 'running' | 'exited' }>>('run.list', { workspaceId }),\n}\n","/**\n * HMR-safe shared run state for the quick-commands header button and output\n * popup. Module-level fields live on one globalThis-backed record keyed with\n * Symbol.for so every client-bundle copy (client-hmr hot swap re-evaluates the\n * bundle without reloading the page) reads/writes the same state cell.\n *\n * The popup handles ONE run at a time (serial per workspace by design); a\n * second workspace can run in parallel with its own popup, so the store keys\n * popups by runId.\n */\nimport { useSyncExternalStore } from 'react'\n\nconst STATE_KEY = Symbol.for('@fonlan/dsh-quick-commands/run-state')\n\n/** One popup slot: menu open flag + the live run the popup streams. */\nexport interface RunPopoverState {\n /** Whether the header command menu is open. */\n menuOpen: boolean\n /** Active run id (undefined when no run is open). */\n runId: string | null\n /** Workspace id owning the active run (for kill/cwd display). */\n workspaceId: string | null\n /** Command display name. */\n commandName: string | null\n /** SSH host id when the run executes on a remote workspace (else null). */\n remoteHost: string | null\n /** Whether the run popup should stream (false while minimized). */\n streaming: boolean\n}\n\ninterface RunPopoverStateInternal extends RunPopoverState {\n listeners: Set<() => void>\n}\n\ninterface QuickCommandsState {\n popover: RunPopoverStateInternal\n /** Cached published snapshot — STABLE reference; rebuilt only after a patch. */\n snapshot: RunPopoverState | null\n}\n\nfunction getState(): QuickCommandsState {\n const g = globalThis as unknown as Record<symbol, QuickCommandsState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = {\n popover: {\n menuOpen: false,\n runId: null,\n workspaceId: null,\n commandName: null,\n remoteHost: null,\n streaming: true,\n listeners: new Set(),\n },\n // Seed the cache with values our equality check will see as unchanged.\n snapshot: {\n menuOpen: false,\n runId: null,\n workspaceId: null,\n commandName: null,\n remoteHost: null,\n streaming: true,\n },\n }\n g[STATE_KEY] = state\n }\n return state\n}\n\nfunction notify(): void {\n // Invalidate the cached snapshot FIRST: useSyncExternalStore reads\n // getSnapshot after notification, so a new stable object must be ready.\n getState().snapshot = null\n for (const listener of getState().popover.listeners) listener()\n}\n\nfunction subscribe(cb: () => void): () => void {\n const listeners = getState().popover.listeners\n listeners.add(cb)\n return () => { listeners.delete(cb) }\n}\n\n/**\n * getSnapshot for useSyncExternalStore. MUST return a stable reference while\n * the underlying fields are unchanged (React compares with Object.is) — return\n * the CACHED object; only rebuild it when a patch invalidated it.\n */\nfunction snapshot(): RunPopoverState {\n const state = getState()\n if (state.snapshot !== null) return state.snapshot\n const p = state.popover\n state.snapshot = {\n menuOpen: p.menuOpen,\n runId: p.runId,\n workspaceId: p.workspaceId,\n commandName: p.commandName,\n remoteHost: p.remoteHost,\n streaming: p.streaming,\n }\n return state.snapshot\n}\n\nfunction patch(partial: Partial<RunPopoverState>): void {\n const state = getState()\n Object.assign(state.popover, partial)\n // Invalidate the cached snapshot so equality flips exactly on real changes.\n state.snapshot = null\n notify()\n}\n\nexport function useRunPopover(): RunPopoverState {\n return useSyncExternalStore(subscribe, snapshot, snapshot)\n}\n\nexport function openMenu(): void { patch({ menuOpen: true }) }\nexport function closeMenu(): void { patch({ menuOpen: false }) }\nexport function toggleMenu(open: boolean): void { patch({ menuOpen: open }) }\n\nexport function openRun(runId: string, workspaceId: string, commandName: string, remoteHost?: string): void {\n patch({ runId, workspaceId, commandName, remoteHost: remoteHost ?? null, menuOpen: false, streaming: true })\n}\n\nexport function closeRun(): void {\n patch({ runId: null, workspaceId: null, commandName: null, remoteHost: null, streaming: false })\n}\n","/**\n * Session-header quick-command surface: the ▶ play icon button (left of the\n * Session log pill), the command menu popover (current workspace's commands),\n * and the live output popup that streams stdout/stderr at ~200ms cadence.\n *\n * Props are the standard session/global kit of `conversation.session.header.utilities`\n * plus this plugin's injected hooks (anchor preference + resolver).\n */\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconPlayOutline16,\n IconCloseOutline16,\n IconStopFill16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { quickApi } from './api'\nimport { useRunPopover, openMenu, closeMenu, openRun, closeRun } from './run-state'\nimport type { QuickPopupSize } from '../shared/contract'\n\n/** Workspace row shape the standard useWorkspaces hook exposes. */\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n}\n\n/** Session list state subset we read (cwd + id). */\ninterface SessionRow {\n id: string\n cwd?: string\n}\n\ninterface HeaderProps {\n sessionId: string\n t: (key: string) => string\n useSessions?: (selector: (s: { byId: Record<string, SessionRow>; current?: string }) => unknown) => unknown\n useWorkspaces?: (selector: (s: { items: WorkspaceRow[] }) => unknown) => unknown\n}\n\ninterface MenuPosition {\n left: number\n top: number\n width: number\n}\n\nconst PHONE_MENU_RAIL_WIDTH = 56\nconst MENU_VIEWPORT_GAP = 12\nconst MENU_PREFERRED_WIDTH = 280\n\n/**\n * Position the portal menu beside its button without ever entering the phone\n * nav rail. Calculating actual pixels (rather than only CSS max-width) also\n * means it remains correct when the header itself sits in a clipped stacking\n * context created by a shell/mobile plugin.\n */\nfunction positionMenu(button: HTMLButtonElement): MenuPosition {\n const rect = button.getBoundingClientRect()\n const narrow = window.matchMedia('(max-width: 767px)').matches\n const minLeft = narrow ? PHONE_MENU_RAIL_WIDTH + MENU_VIEWPORT_GAP : MENU_VIEWPORT_GAP\n const availableWidth = Math.max(0, window.innerWidth - minLeft - MENU_VIEWPORT_GAP)\n const width = Math.min(MENU_PREFERRED_WIDTH, availableWidth)\n const maxLeft = Math.max(minLeft, window.innerWidth - MENU_VIEWPORT_GAP - width)\n return {\n // The old in-header popover used `right:12px`; retain that visual anchor\n // but clamp its left edge to the usable side of the rail.\n left: Math.max(minLeft, Math.min(rect.right - MENU_VIEWPORT_GAP - width, maxLeft)),\n top: Math.min(rect.bottom + 6, Math.max(MENU_VIEWPORT_GAP, window.innerHeight - 72)),\n width,\n }\n}\n\n/** Longest-path workspace match for a cwd (subdirectory allowed). */\nfunction matchWorkspace(cwd: string | undefined, workspaces: WorkspaceRow[]): WorkspaceRow | undefined {\n if (cwd === undefined) return undefined\n let best: WorkspaceRow | undefined\n for (const ws of workspaces) {\n const norm = ws.path.replace(/\\\\/g, '/').replace(/\\/+$/, '')\n const nc = cwd.replace(/\\\\/g, '/')\n if (nc === norm || nc.startsWith(norm + '/')) {\n if (best === undefined || norm.length > best.path.length) best = ws\n }\n }\n return best\n}\n\n/** Resolve the current session's workspace from the standard kits. */\nfunction useCurrentWorkspace(\n sessionId: string,\n useSessions?: HeaderProps['useSessions'],\n useWorkspaces?: HeaderProps['useWorkspaces'],\n): { workspace: WorkspaceRow | undefined; cwd: string | undefined } {\n const row = useSessions?.((s) => s.byId[sessionId]) as SessionRow | undefined\n const workspaces = useWorkspaces?.((s) => s.items) as WorkspaceRow[] | undefined\n return { workspace: matchWorkspace(row?.cwd, workspaces ?? []), cwd: row?.cwd }\n}\n\n/** Header icon button + command menu + live output popup. */\nexport function QuickCommandsHeaderAction(props: HeaderProps): JSX.Element {\n const { sessionId, t } = props\n const { workspace, cwd } = useCurrentWorkspace(sessionId, props.useSessions, props.useWorkspaces)\n const popover = useRunPopover()\n const [commands, setCommands] = useState<Array<{ name: string; command: string }>>([])\n const [menuLoadError, setMenuLoadError] = useState<string | null>(null)\n const [menuRemoteHost, setMenuRemoteHost] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [anchor, setAnchor] = useState<'corner' | 'button'>('corner')\n const [popupSize, setPopupSize] = useState<QuickPopupSize | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const buttonRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPosition, setMenuPosition] = useState<MenuPosition | null>(null)\n\n // Click-outside dismissal: the command menu is portaled to document.body so\n // it escapes the mobile shell's clipped/z-indexed header context. Treat both\n // its portal node and its original header wrap as inside targets.\n useEffect(() => {\n if (!popover.menuOpen) return\n const onPointerDown = (e: PointerEvent): void => {\n const wrap = wrapRef.current\n const menu = menuRef.current\n if (!(e.target instanceof Node)) return\n if (wrap?.contains(e.target) || menu?.contains(e.target)) return\n closeMenu()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => { document.removeEventListener('pointerdown', onPointerDown) }\n }, [popover.menuOpen])\n\n // Recalculate against the actual header button whenever the menu opens and\n // whenever a viewport change moves it (rotation, browser chrome resize).\n useLayoutEffect(() => {\n if (!popover.menuOpen) {\n setMenuPosition(null)\n return\n }\n const update = (): void => {\n const button = buttonRef.current\n if (button !== null) setMenuPosition(positionMenu(button))\n }\n update()\n window.addEventListener('resize', update)\n window.addEventListener('scroll', update, true)\n window.visualViewport?.addEventListener('resize', update)\n return () => {\n window.removeEventListener('resize', update)\n window.removeEventListener('scroll', update, true)\n window.visualViewport?.removeEventListener('resize', update)\n }\n }, [popover.menuOpen])\n\n // Load the workspace's command list + anchor when the menu opens.\n useEffect(() => {\n if (!popover.menuOpen) return\n let cancelled = false\n void (async () => {\n try {\n const [entries, settings] = await Promise.all([quickApi.workspacesList(), quickApi.settingsGet()])\n if (cancelled) return\n const own = entries.find((e) => e.workspaceId === workspace?.workspaceId)\n setCommands(own === undefined ? [] : own.commands)\n setMenuRemoteHost(own?.remoteHost ?? null)\n setAnchor(settings.popupAnchor)\n setPopupSize(settings.popupSize)\n setMenuLoadError(null)\n } catch (e) {\n if (cancelled) return\n setCommands([])\n setMenuLoadError(e instanceof Error ? e.message : String(e))\n }\n })()\n return () => { cancelled = true }\n }, [popover.menuOpen, workspace?.workspaceId])\n\n const startRun = async (commandName: string): Promise<void> => {\n setBusy(true)\n closeMenu()\n try {\n const run = await quickApi.runStart(workspace!.workspaceId, commandName, cwd ?? workspace!.path)\n openRun(run.runId, run.workspaceId, run.commandName, run.remoteHost)\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e)\n if (message.includes('run-busy') || message.includes('already running')) {\n setMenuLoadError(t('runBusy'))\n } else {\n setMenuLoadError(t('runStartFailed') + ': ' + message)\n }\n openMenu()\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div ref={wrapRef} className=\"qc-head-wrap\">\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"qc-head-btn\"\n title={workspace === undefined ? t('noWorkspace') : t('buttonTooltip')}\n aria-label={t('buttonTitle')}\n disabled={workspace === undefined}\n onClick={() => { popover.menuOpen ? closeMenu() : openMenu() }}\n >\n <IconPlayOutline16 size={15} />\n </button>\n\n {popover.menuOpen && workspace !== undefined && menuPosition !== null && createPortal(\n <div\n ref={menuRef}\n className=\"qc-menu qc-menu-portal\"\n role=\"menu\"\n style={{ left: menuPosition.left, top: menuPosition.top, width: menuPosition.width }}\n >\n <div className=\"qc-menu-head\">\n <span className=\"qc-menu-title\">{t('menuTitle')}</span>\n {menuRemoteHost !== null && <span className=\"qc-menu-remote\" title={`SSH · ${menuRemoteHost}`}>SSH</span>}\n <span className=\"qc-menu-ws\">{workspace.title}</span>\n <button type=\"button\" className=\"qc-menu-close\" aria-label={t('runClose')} onClick={closeMenu}>\n <IconCloseOutline16 size={12} />\n </button>\n </div>\n {commands.length === 0 && (\n <p className=\"qc-menu-empty\">{menuLoadError ?? t('noCommands')}</p>\n )}\n {commands.filter((c) => c.name.trim() !== '').map((command) => (\n <button\n key={command.name}\n type=\"button\"\n role=\"menuitem\"\n className=\"qc-menu-item\"\n disabled={busy}\n onClick={() => void startRun(command.name)}\n >\n <span className=\"qc-menu-item-name\">{command.name}</span>\n <span className=\"qc-menu-item-cmd\">{command.command}</span>\n </button>\n ))}\n </div>\n , document.body)}\n\n {popover.runId !== null && (\n <RunPopup\n runId={popover.runId}\n workspaceId={popover.workspaceId ?? ''}\n commandName={popover.commandName ?? ''}\n remoteHost={popover.remoteHost ?? undefined}\n t={t}\n anchor={anchor}\n popupSize={popupSize}\n sessionId={sessionId}\n onClose={closeRun}\n />\n )}\n </div>\n )\n}\n\n// ── popup drag-resize ───────────────────────────────────────────────────────\n// The popup pins its RIGHT edge (both anchors), plus its BOTTOM edge (corner\n// anchor) or TOP edge (button anchor, pinned below the button). So the MOVABLE\n// borders are the LEFT border (width) and the TOP border (corner anchor) /\n// BOTTOM border (button anchor) (height); the free corner (top-left /\n// bottom-left) carries a diagonal grip for simultaneous two-axis resizing.\n// Every handle follows the cursor edge-for-edge — pulling the left border LEFT\n// widens, pulling the top border UP grows taller — nothing feels inverted.\n// The size is clamped to viewport bounds and persisted to settings.\n\nconst POPUP_MIN_W = 320\nconst POPUP_MIN_H = 200\n/** Total horizontal margin kept around the popup (both anchors). */\nconst POPUP_VIEWPORT_MARGIN = 40\n/** Vertical space reserved for header/footer chrome (both anchors). */\nconst POPUP_VIEWPORT_RESERVED = 120\n\nfunction popupDefaultSize(anchor: 'corner' | 'button'): QuickPopupSize {\n return anchor === 'corner' ? { width: 520, height: 340 } : { width: 440, height: 300 }\n}\n\nfunction popupClamp(size: QuickPopupSize): QuickPopupSize {\n const maxW = Math.max(POPUP_MIN_W, window.innerWidth - POPUP_VIEWPORT_MARGIN)\n const maxH = Math.max(POPUP_MIN_H, window.innerHeight - POPUP_VIEWPORT_RESERVED)\n return {\n width: Math.min(Math.max(POPUP_MIN_W, Math.round(size.width)), maxW),\n height: Math.min(Math.max(POPUP_MIN_H, Math.round(size.height)), maxH),\n }\n}\n\n/**\n * Initial popup size: the persisted one when it holds sane numbers, else the\n * per-anchor default. Defensive because schemastery resolves a MISSING object\n * field to `{}` (object schemas carry an implicit `default: {}`), so a\n * never-resized popup can arrive as `popupSize: {}` from settings.get().\n */\nfunction popupSizeOrDefault(size: QuickPopupSize | undefined, anchor: 'corner' | 'button'): QuickPopupSize {\n if (\n size === undefined\n || !Number.isFinite(size.width)\n || !Number.isFinite(size.height)\n || size.width <= 0\n || size.height <= 0\n ) {\n return popupDefaultSize(anchor)\n }\n return popupClamp(size)\n}\n\n/** The streaming output popup. Polls stdout/stderr deltas every ~200ms. */\nfunction RunPopup(props: {\n runId: string\n workspaceId: string\n commandName: string\n remoteHost?: string\n t: (key: string) => string\n anchor: 'corner' | 'button'\n popupSize?: QuickPopupSize\n sessionId: string\n onClose: () => void\n}): JSX.Element {\n const { runId, t, anchor, remoteHost, onClose } = props\n const [size, setSize] = useState<QuickPopupSize>(() => popupSizeOrDefault(props.popupSize, anchor))\n // Mirrors `size` for drag handlers: pointer events can arrive faster than\n // React commits, so pointerup must read the latest value, not the render's.\n const sizeRef = useRef<QuickPopupSize>(size)\n const sizeDragRef = useRef<{\n pointerId: number\n startX: number\n startY: number\n startW: number\n startH: number\n /** Which handle started the drag (controls which axes move). */\n mode: 'left' | 'height' | 'corner'\n } | null>(null)\n const [state, setState] = useState(() => ({\n status: 'running' as 'running' | 'exited',\n exitCode: null as number | null,\n signal: null as string | null,\n stdoutEnd: 0,\n stderrEnd: 0,\n stdout: '',\n stderr: '',\n stdoutLossy: false,\n stderrLossy: false,\n }))\n const [view, setView] = useState<'stdout' | 'stderr'>('stdout')\n const [autoFollow, setAutoFollow] = useState(true)\n const [pollError, setPollError] = useState<string | null>(null)\n const [closing, setClosing] = useState(false)\n const outputRef = useRef<HTMLDivElement | null>(null)\n const autoFollowRef = useRef(true)\n\n // Auto-follow: scroll the output pane to the bottom on new output while the\n // user has not scrolled up (autoFollow mirror keeps the effect cheap).\n useEffect(() => {\n autoFollowRef.current = autoFollow\n }, [autoFollow])\n useEffect(() => {\n if (!autoFollowRef.current) return\n const el = outputRef.current\n if (el === null) return\n el.scrollTop = el.scrollHeight\n }, [state.stdout, state.stderr, view])\n\n // Poll deltas; stop polling at exit (the run stays readable in memory).\n useEffect(() => {\n let cancelled = false\n let outEnd = 0\n let errEnd = 0\n const tick = async (): Promise<void> => {\n try {\n const poll = await quickApi.runPoll(runId, outEnd, errEnd)\n if (cancelled) return\n outEnd = poll.stdoutEnd\n errEnd = poll.stderrEnd\n setState((s) => ({\n status: poll.status,\n exitCode: poll.exitCode,\n signal: poll.signal,\n stdoutEnd: poll.stdoutEnd,\n stderrEnd: poll.stderrEnd,\n stdout: poll.stdoutLossy ? poll.stdoutDelta : s.stdout + poll.stdoutDelta,\n stderr: poll.stderrLossy ? poll.stderrDelta : s.stderr + poll.stderrDelta,\n stdoutLossy: poll.stdoutLossy,\n stderrLossy: poll.stderrLossy,\n }))\n setPollError(null)\n if (poll.status === 'exited') return\n timer = window.setTimeout(() => void tick(), 200)\n } catch (e) {\n if (cancelled) return\n setPollError(e instanceof Error ? e.message : String(e))\n timer = window.setTimeout(() => void tick(), 500)\n }\n }\n let timer: number\n void tick()\n return () => { cancelled = true; window.clearTimeout(timer) }\n }, [runId])\n\n const kill = async (): Promise<void> => {\n setClosing(true)\n try {\n await quickApi.runKill(runId)\n } finally {\n onClose()\n }\n }\n\n // Closing the output surface must not terminate a still-running command:\n // the dedicated stop control owns that destructive action. In particular,\n // an X in a compact touch header is expected to dismiss immediately rather\n // than reveal a second confirmation row below the visible viewport.\n const closeOutput = (): void => { onClose() }\n\n // Some mobile webviews occasionally fail to synthesize `click` for compact\n // header controls after a touch gesture. Handle touch pointer-up directly;\n // click remains the keyboard and mouse activation path.\n const onClosePointerUp = (e: React.PointerEvent<HTMLButtonElement>): void => {\n if (e.pointerType !== 'touch') return\n e.preventDefault()\n closeOutput()\n }\n\n // ── drag-resize: pointer capture on the handles keeps moving/cancelling\n // events flowing even when the cursor leaves the handle or the window.\n // Which border is free to move depends on the anchor: the corner anchor\n // pins bottom+right (top border moves for height), the button anchor pins\n // top+right (bottom border moves for height).\n const heightFree: 'top' | 'bottom' = anchor === 'corner' ? 'top' : 'bottom'\n\n const onResizePointerDown = (e: React.PointerEvent<HTMLDivElement>): void => {\n e.preventDefault() // keep the handle from starting a text-selection gesture\n e.currentTarget.setPointerCapture(e.pointerId)\n sizeDragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n startW: sizeRef.current.width,\n startH: sizeRef.current.height,\n mode: e.currentTarget.dataset.resize as 'left' | 'height' | 'corner',\n }\n }\n\n const onResizePointerMove = (e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = sizeDragRef.current\n if (drag === null || drag.pointerId !== e.pointerId) return\n const dx = e.clientX - drag.startX\n const dy = e.clientY - drag.startY\n const controlsW = drag.mode === 'left' || drag.mode === 'corner'\n const controlsH = drag.mode === 'height' || drag.mode === 'corner'\n const next = popupClamp({\n // Left border follows the cursor: dragging LEFT widens, RIGHT narrows.\n width: controlsW ? drag.startW - dx : drag.startW,\n // Top-free (corner): dragging UP grows. Bottom-free (button): DOWN grows.\n height: controlsH ? drag.startH + (heightFree === 'top' ? -dy : dy) : drag.startH,\n })\n sizeRef.current = next\n setSize(next)\n }\n\n const onResizePointerUp = (e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = sizeDragRef.current\n if (drag === null || drag.pointerId !== e.pointerId) return\n sizeDragRef.current = null\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId)\n }\n // Persist best-effort: a failed save just means the next popup reopens at\n // the default size (or the last successfully saved one).\n void quickApi.settingsSetPopupSize(sizeRef.current).catch(() => undefined)\n }\n\n /** Pointer-handler trio for one resize handle (mode = which axes it drives). */\n const resizeProps = (mode: 'left' | 'height' | 'corner') => ({\n 'data-resize': mode,\n onPointerDown: onResizePointerDown,\n onPointerMove: onResizePointerMove,\n onPointerUp: onResizePointerUp,\n onPointerCancel: onResizePointerUp,\n })\n\n const active = state.status === 'running'\n const title = active ? `${props.commandName} · ${t('runStateRunning')}` : `${props.commandName} · ${t('runStateExited')} (${state.exitCode ?? '?'})`\n\n return (\n <div className={`qc-popup qc-popup-${anchor}`} role=\"dialog\" aria-label={title} style={{ width: size.width, height: size.height }}>\n <header className=\"qc-popup-head\">\n <span className=\"qc-popup-title\" title={title}>{title}</span>\n {remoteHost !== undefined && <span className=\"qc-popup-remote\" title={`SSH · ${remoteHost}`}>SSH</span>}\n <span className=\"qc-popup-cmd\">{props.commandName}</span>\n <button\n type=\"button\"\n className=\"qc-popup-icon qc-popup-kill\"\n disabled={!active || closing}\n title={t('runKill')}\n aria-label={t('runKill')}\n onClick={() => void kill()}\n >\n <IconStopFill16 size={14} />\n </button>\n <button\n type=\"button\"\n className=\"qc-popup-icon qc-popup-close\"\n title={t('runClose')}\n aria-label={t('runClose')}\n onPointerUp={onClosePointerUp}\n onClick={closeOutput}\n >\n <IconCloseOutline16 size={14} />\n </button>\n </header>\n\n <div className=\"qc-popup-tabs\">\n <button\n type=\"button\"\n className={'qc-popup-tab' + (view === 'stdout' ? ' qc-popup-tab-active' : '')}\n onClick={() => setView('stdout')}\n >\n {t('runStdout')}\n </button>\n <button\n type=\"button\"\n className={'qc-popup-tab' + (view === 'stderr' ? ' qc-popup-tab-active' : '')}\n onClick={() => setView('stderr')}\n >\n {t('runStderr')}\n </button>\n </div>\n\n <div\n ref={outputRef}\n className=\"qc-popup-output\"\n onScroll={(e) => {\n const el = e.currentTarget\n const atEnd = Math.abs(el.scrollHeight - el.scrollTop - el.clientHeight) < 24\n setAutoFollow(atEnd)\n }}\n >\n {pollError !== null && <p className=\"qc-popup-error\">{t('runPollFailed')}: {pollError}</p>}\n {view === 'stdout' ? (\n state.stdout === '' && !active ? <p className=\"qc-popup-empty\">{t('runEmpty')}</p>\n : <pre className=\"qc-popup-pre\">{state.stdout}</pre>\n ) : (\n state.stderr === '' && !active ? <p className=\"qc-popup-empty\">{t('runEmpty')}</p>\n : <pre className=\"qc-popup-pre\">{state.stderr}</pre>\n )}\n </div>\n\n <footer className=\"qc-popup-foot\">\n <span className=\"qc-popup-state\">\n {active ? t('runStateRunning') : `${t('runStateExited')} · ${t('runExitCode')} ${state.exitCode ?? '-'}${state.signal !== null ? ` · ${state.signal}` : ''}`}\n </span>\n </footer>\n\n {/* Resize handles: left border = width; top (corner anchor) / bottom\n (button anchor) border = height; free corner = diagonal grip. */}\n <div className=\"qc-popup-resize qc-popup-resize-left\" title={t('runResize')} {...resizeProps('left')} />\n {heightFree === 'top'\n ? <div className=\"qc-popup-resize qc-popup-resize-top\" title={t('runResize')} {...resizeProps('height')} />\n : <div className=\"qc-popup-resize qc-popup-resize-bottom\" title={t('runResize')} {...resizeProps('height')} />}\n {heightFree === 'top' ? (\n <div className=\"qc-popup-resize qc-popup-resize-corner qc-popup-resize-corner-tl\" title={t('runResize')} {...resizeProps('corner')}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M9 9 3 3 M9 5.5 5.5 3 M5.5 9 3 5.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n ) : (\n <div className=\"qc-popup-resize qc-popup-resize-corner qc-popup-resize-corner-bl\" title={t('runResize')} {...resizeProps('corner')}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M9 3 3 9 M9 6.5 6.5 9 M5.5 3 3 5.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Quick-commands settings page (设置 → 侧栏「快捷命令」).\n *\n * Registers into the \"settings.section\" list slot, so the page owns one entry\n * in the settings sidebar and renders in the settings panel's content column.\n * The header is static (title + one-line summary) over the always-visible\n * body: the workspace / command-set editor and the popup anchor preference.\n * Body edits instant-save per change; partial rows (empty name/command)\n * persist while the user types.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport {\n IconPlusOutline16,\n IconTrashOutline16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { quickApi } from './api'\nimport type { QuickRosterEntry, QuickCommandsSettings } from '../shared/contract'\nimport './settings-section.css'\n\ninterface Props {\n t: (key: string) => string\n}\n\ninterface RosterState {\n loaded: boolean\n entries: QuickRosterEntry[]\n anchor: QuickCommandsSettings['popupAnchor']\n}\n\ntype CommandDraft = { name: string; command: string }\n\nexport function QuickCommandsSettingsSection({ t }: Props): JSX.Element {\n const [state, setState] = useState<RosterState>({ loaded: false, entries: [], anchor: 'corner' })\n const [error, setError] = useState<string | null>(null)\n // Guard concurrent saves: the last write wins via a monotonically bumped token.\n const saveToken = useRef(0)\n\n const load = async (): Promise<void> => {\n try {\n const [entries, settings] = await Promise.all([quickApi.workspacesList(), quickApi.settingsGet()])\n setState({ loaded: true, entries, anchor: settings.popupAnchor })\n setError(null)\n } catch (e) {\n setState((s) => ({ ...s, loaded: true }))\n setError(e instanceof Error ? e.message : String(e))\n }\n }\n\n useEffect(() => {\n void load()\n }, [])\n\n /** Instant-save the workspace's whole command set; optimistic UI. */\n const saveCommands = async (workspaceId: string, commands: CommandDraft[]): Promise<void> => {\n const token = ++saveToken.current\n try {\n const next = await quickApi.settingsSetCommands(workspaceId, commands)\n if (token !== saveToken.current) return\n setState((s) => ({\n ...s,\n anchor: next.popupAnchor,\n entries: s.entries.map((e) => (e.workspaceId === workspaceId ? { ...e, commands } : e)),\n }))\n setError(null)\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n // Re-sync to server truth on failure.\n void load()\n }\n }\n\n /** Compute the next command list for a workspace, THEN save + update state. */\n const mutateCommands = (workspaceId: string, next: (current: CommandDraft[]) => CommandDraft[]): void => {\n const entry = state.entries.find((e) => e.workspaceId === workspaceId)\n if (entry === undefined) return\n const commands = next(entry.commands)\n // Optimistic update first (row stays visible immediately), then persist.\n setState((s) => ({\n ...s,\n entries: s.entries.map((e) => (e.workspaceId === workspaceId ? { ...e, commands } : e)),\n }))\n void saveCommands(workspaceId, commands)\n }\n\n const patchEntry = (workspaceId: string, index: number, field: 'name' | 'command', value: string): void => {\n mutateCommands(workspaceId, (current) =>\n current.map((c, i) => (i === index ? { ...c, [field]: value } : c)),\n )\n }\n\n const addCommand = (workspaceId: string): void => {\n mutateCommands(workspaceId, (current) => [...current, { name: '', command: '' }])\n }\n\n const removeCommand = (workspaceId: string, index: number): void => {\n mutateCommands(workspaceId, (current) => current.filter((_, i) => i !== index))\n }\n\n const setAnchor = async (anchor: QuickCommandsSettings['popupAnchor']): Promise<void> => {\n setState((s) => ({ ...s, anchor }))\n try {\n const next = await quickApi.settingsSetAnchor(anchor)\n setState((s) => ({ ...s, anchor: next.popupAnchor }))\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n void load()\n }\n }\n\n const title = t('cardTitle')\n const description = t('sectionSub')\n\n return (\n <div className=\"qc-page\">\n <header className=\"qc-page-head\">\n <h3 className=\"qc-page-title\">{title}</h3>\n <p className=\"qc-page-sub\">{description}</p>\n </header>\n <div className=\"qc-settings-body\">\n <p className=\"qc-settings-intro\">{t('cardIntro')}</p>\n\n <div className=\"qc-settings-anchor\">\n <span className=\"qc-settings-anchor-label\">{t('cardAnchor')}</span>\n <label className=\"qc-settings-radio\">\n <input\n type=\"radio\"\n name=\"qc-anchor\"\n checked={state.anchor === 'corner'}\n onChange={() => void setAnchor('corner')}\n />\n {t('cardAnchorCorner')}\n </label>\n <label className=\"qc-settings-radio\">\n <input\n type=\"radio\"\n name=\"qc-anchor\"\n checked={state.anchor === 'button'}\n onChange={() => void setAnchor('button')}\n />\n {t('cardAnchorButton')}\n </label>\n </div>\n\n {error !== null && <div className=\"qc-settings-error\">{t('cardSaveError')}: {error}</div>}\n\n {state.loaded && state.entries.length === 0 && (\n <p className=\"qc-settings-empty\">{t('cardNoWorkspaces')}</p>\n )}\n\n {state.entries.map((entry) => (\n <section key={entry.workspaceId} className=\"qc-settings-workspace\">\n <header className=\"qc-settings-workspace-head\">\n <span className=\"qc-settings-workspace-title\">{entry.title || entry.path || entry.workspaceId}</span>\n <span className=\"qc-settings-workspace-path\">{entry.path}</span>\n </header>\n {entry.commands.length === 0 && (\n <p className=\"qc-settings-no-commands\">{t('cardNoCommands')}</p>\n )}\n {entry.commands.map((command, index) => (\n <div key={`${entry.workspaceId}-${index}`} className=\"qc-settings-command\">\n <input\n className=\"qc-settings-field qc-settings-field-name\"\n placeholder={t('cardName')}\n value={command.name}\n aria-label={t('cardName')}\n onChange={(e) => patchEntry(entry.workspaceId, index, 'name', e.target.value)}\n />\n <input\n className=\"qc-settings-field qc-settings-field-command\"\n placeholder={t('cardCommand')}\n value={command.command}\n aria-label={t('cardCommand')}\n onChange={(e) => patchEntry(entry.workspaceId, index, 'command', e.target.value)}\n />\n <button\n type=\"button\"\n className=\"qc-settings-icon-btn\"\n aria-label={t('cardRemove')}\n title={t('cardRemove')}\n onClick={() => removeCommand(entry.workspaceId, index)}\n >\n <IconTrashOutline16 size={14} />\n </button>\n </div>\n ))}\n <button type=\"button\" className=\"qc-settings-add-btn\" onClick={() => addCommand(entry.workspaceId)}>\n <IconPlusOutline16 size={14} />\n {t('cardAddCommand')}\n </button>\n </section>\n ))}\n </div>\n </div>\n )\n}\n","/**\n * Client dictionary namespace for @fonlan/dsh-quick-commands.\n */\nexport const LOCALE_NS = 'quick-commands'\n\nexport const zh = {\n // header button\n buttonTitle: '快速命令',\n buttonTooltip: '快速命令(当前工作区)',\n noWorkspace: '当前会话不在任何已配置的工作区中',\n noCommands: '当前工作区未配置命令',\n openSettings: '去设置配置命令',\n\n // command popup menu\n menuTitle: '快速命令',\n menuEmpty: '(无命令)',\n\n // run popup\n runTitle: '运行中',\n runExited: '已退出',\n runExitCode: '退出码',\n runSignal: '信号',\n runStdout: '输出 (stdout)',\n runStderr: '错误 (stderr)',\n runEmpty: '(无输出)',\n runCommand: '命令',\n runCwd: '工作区',\n runStateRunning: '运行中…',\n runStateExited: '已退出',\n runKill: '终止',\n runClose: '关闭',\n runResize: '拖动调整弹窗大小',\n runKillConfirm: '终止后输出弹窗将关闭,确定终止该命令?',\n runBusy: '该工作区已有命令在运行',\n runStartFailed: '命令启动失败',\n runPollFailed: '输出读取失败',\n runLost: '运行记录已失效',\n runNotFound: '工作区或命令未找到',\n\n // settings page (设置 → 侧栏「快捷命令」)\n settingsTitle: '快捷命令',\n cardTitle: '快速命令',\n sectionSub: '为每个工作区配置常用命令,会话头部一键运行',\n cardIntro: '为每个工作区配置常用命令,运行于工作区目录。支持占位符:{workspace} 工作区路径,{cwd} 会话目录,{title} 工作区标题。',\n cardWorkspaces: '工作区',\n cardNoWorkspaces: '没有工作区。请在侧边栏先添加工作区。',\n cardCommands: '命令',\n cardNoCommands: '未配置命令',\n cardAddCommand: '添加命令',\n cardName: '名称',\n cardCommand: '命令',\n cardRemove: '删除',\n cardSaveError: '保存失败',\n cardAnchor: '输出弹窗位置',\n cardAnchorCorner: '右下角',\n cardAnchorButton: '锚定按钮下方',\n} as const\n\nexport const en: Record<keyof typeof zh, string> = {\n buttonTitle: 'Quick commands',\n buttonTooltip: 'Quick commands (current workspace)',\n noWorkspace: 'This session is not in any configured workspace',\n noCommands: 'No commands configured for this workspace',\n openSettings: 'Configure commands in Settings',\n\n menuTitle: 'Quick commands',\n menuEmpty: '(no commands)',\n\n runTitle: 'Running',\n runExited: 'Exited',\n runExitCode: 'Exit code',\n runSignal: 'Signal',\n runStdout: 'Output (stdout)',\n runStderr: 'Errors (stderr)',\n runEmpty: '(no output)',\n runCommand: 'Command',\n runCwd: 'Workspace',\n runStateRunning: 'Running…',\n runStateExited: 'Exited',\n runKill: 'Terminate',\n runClose: 'Close',\n runResize: 'Drag to resize the popup',\n runKillConfirm: 'Terminating closes the output popup. Terminate this command?',\n runBusy: 'A command is already running for this workspace',\n runStartFailed: 'Command failed to start',\n runPollFailed: 'Failed to read output',\n runLost: 'Run record expired',\n runNotFound: 'Workspace or command not found',\n\n settingsTitle: 'Quick Commands',\n cardTitle: 'Quick commands',\n sectionSub: 'Configure common commands per workspace, run them from the session header',\n cardIntro: 'Configure common commands per workspace; they run in the workspace directory. Placeholders: {workspace} workspace path, {cwd} session cwd, {title} workspace title.',\n cardWorkspaces: 'Workspaces',\n cardNoWorkspaces: 'No workspaces. Add one in the sidebar first.',\n cardCommands: 'Commands',\n cardNoCommands: 'No commands configured',\n cardAddCommand: 'Add command',\n cardName: 'Name',\n cardCommand: 'Command',\n cardRemove: 'Remove',\n cardSaveError: 'Save failed',\n cardAnchor: 'Output popup position',\n cardAnchorCorner: 'Bottom right',\n cardAnchorButton: 'Anchored at button',\n}\n","/**\n * @fonlan/dsh-quick-commands client half.\n *\n * Registers:\n * - \"settings.section\" page (id \"quick-commands\", order 330) — per-workspace\n * command CRUD + popup anchor preference, rendered as its own page in the\n * settings sidebar.\n * - \"conversation.session.header.utilities\" entry (id \"quick-commands\",\n * order -1 → left of the Session log pill) — the quick-run ▶ button, command\n * menu, and live output popup.\n */\nimport type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { QuickCommandsHeaderAction } from './header'\nimport { QuickCommandsSettingsSection } from './settings-section'\nimport { LOCALE_NS, zh, en } from './locales'\nimport './quick-commands.css'\n\n/** Slots face (local, erased at build). */\ninterface Slots {\n inject(name: string, callback: () => unknown): unknown\n register(\n def: { name: string; id?: string; order?: number; label?: string | (() => string); locale?: string },\n component: unknown,\n ): unknown\n}\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), 'quick-commands: dictionaries')\n const t = ctx.locale.bind(LOCALE_NS)\n const slots = (ctx as unknown as { slots: Slots }).slots\n\n // The plugin's own settings page (设置 → 侧栏「快捷命令」) rides the\n // \"quick-commands\" locale namespace: a \"settings.section\" list entry gives it\n // one row in the settings sidebar and renders the page in the content column.\n slots.inject('settings.section', () =>\n slots.register({\n name: 'settings.section',\n id: 'quick-commands',\n order: 330,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, QuickCommandsSettingsSection as never),\n )\n\n // Session-header util: order -1 renders LEFT of the Session log pill\n // (session-log-download registers with default order 0).\n slots.inject('conversation.session.header.utilities', () =>\n slots.register({\n name: 'conversation.session.header.utilities',\n id: 'quick-commands',\n order: -1,\n locale: LOCALE_NS,\n }, QuickCommandsHeaderAction as never),\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["primitives","useSyncExternalStore","useState","useRef","createPortal","useState","useRef"],"sources":["../../../src/client/icons.tsx","../../../src/client/api.ts","../../../src/client/run-state.ts","../../../src/shared/contract.ts","../../../src/client/header.tsx","../../../src/client/settings-section.tsx","../../../src/client/locales.ts","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Icon compatibility layer over `@deepseek-ai/dsh-client-ui-primitives`.\n *\n * DSH renamed this package's icon exports in 0.1.7: the size-suffixed names\n * (`IconPlayOutline16`) became weight-suffixed ones (`IconPlayOutlineRegular` /\n * `IconPlayOutlineMedium`, matching what the official header plugins use).\n *\n * A client bundle that statically imports a name the host no longer exports\n * receives `undefined`; rendering that element throws, the slot's per-entry\n * error boundary swallows the whole entry, and the surface silently vanishes —\n * exactly how the header ▶ button disappeared on 0.1.7.\n *\n * Resolving by name at runtime (new scheme → legacy scheme → bundled artwork)\n * keeps every surface rendering across DSH alphas. The bundled artwork is only\n * a last resort, so a future rename can never blank a control again.\n */\nimport type { ReactElement, ReactNode } from 'react'\nimport * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** Props both naming schemes accept (the legacy exports ignore extra fields). */\nexport interface IconProps {\n /** Rendered square size in CSS pixels. */\n size?: number\n className?: string\n}\n\ntype IconComponent = (props: IconProps) => ReactElement\n\nconst ICON_EXPORTS = primitives as unknown as Record<string, IconComponent | undefined>\n\n/** First export name that exists on the running host, else the bundled artwork. */\nfunction pickIcon(exportNames: readonly string[], fallback: IconComponent): IconComponent {\n for (const name of exportNames) {\n const candidate = ICON_EXPORTS[name]\n if (typeof candidate === 'function') return candidate\n }\n return fallback\n}\n\n/** Wrap one locally drawn 16×16 artwork as an icon component. */\nfunction localIcon(children: ReactNode): IconComponent {\n return function LocalIcon({ size = 16, className }: IconProps): ReactElement {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n className={className}\n aria-hidden=\"true\"\n >\n {children}\n </svg>\n )\n }\n}\n\n/** Run/play glyph for the header quick-run button. */\nexport const PlayIcon = pickIcon(\n ['IconPlayOutlineRegular', 'IconPlayOutlineMedium', 'IconPlayOutline16'],\n localIcon(\n <>\n <circle cx=\"8\" cy=\"8\" r=\"6.5\" stroke=\"currentColor\" />\n <path d=\"M6.6 5.9 10.4 8l-3.8 2.1Z\" fill=\"currentColor\" />\n </>,\n ),\n)\n\n/** Dismiss glyph (menu header and popup close). */\nexport const CloseIcon = pickIcon(\n ['IconCloseOutlineRegular', 'IconCloseOutlineMedium', 'IconCloseOutline16'],\n localIcon(\n <path d=\"M4.2 4.2 11.8 11.8M11.8 4.2 4.2 11.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" />,\n ),\n)\n\n/** Stop/kill glyph for a running command. */\nexport const StopIcon = pickIcon(\n ['IconStopFillRegular', 'IconStopFillMedium', 'IconStopFill16'],\n localIcon(<rect x=\"4.6\" y=\"4.6\" width=\"6.8\" height=\"6.8\" rx=\"1.6\" fill=\"currentColor\" />),\n)\n\n/** Add-row glyph in the settings page. */\nexport const PlusIcon = pickIcon(\n ['IconPlusOutlineRegular', 'IconPlusOutlineMedium', 'IconPlusOutline16'],\n localIcon(\n <path d=\"M8 3.4v9.2M3.4 8h9.2\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" />,\n ),\n)\n\n/** Remove-command glyph in the settings page. */\nexport const TrashIcon = pickIcon(\n ['IconTrashOutlineRegular', 'IconTrashOutlineMedium', 'IconTrashOutline16'],\n localIcon(\n <>\n <path d=\"M3.4 4.4h9.2\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <path\n d=\"M6.4 4.4V3.1h3.2v1.3M4.9 4.4l.6 8.5h5l.6-8.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </>,\n ),\n)\n","/**\n * Browser client for the plugin's fenced JSON API\n * (/plugins/@fonlan/dsh-quick-commands/api/<method>). Same-origin fetch with\n * the task-kanban envelope shape: { ok, value } | { ok:false, error }.\n */\nimport type {\n ApiEnvelope,\n QuickCommandsSettings,\n QuickPopupSize,\n QuickRosterEntry,\n QuickRunView,\n} from '../shared/contract'\n\nexport class QuickCommandsApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-quick-commands/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new QuickCommandsApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed = (await response.json().catch(() => null)) as ApiEnvelope<T> | null\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new QuickCommandsApiError(\n (parsed?.error?.code as string | undefined) ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** Current session cwd of a session row (SessionSummary carries cwd). */\nexport interface SessionRow {\n id: string\n cwd?: string\n}\n\n/** One delta read result (mirrors the host RunPollResult). */\nexport interface RunPoll {\n status: 'running' | 'exited'\n exitCode: number | null\n signal: string | null\n stdoutEnd: number\n stderrEnd: number\n stdoutDelta: string\n stderrDelta: string\n stdoutLossy: boolean\n stderrLossy: boolean\n}\n\nexport const quickApi = {\n settingsGet: () => call<QuickCommandsSettings>('settings.get'),\n settingsSetCommands: (workspaceId: string, commands: Array<{ name: string; command: string }>) =>\n call<QuickCommandsSettings>('settings.setCommands', { workspaceId, commands }),\n settingsSetAnchor: (anchor: QuickCommandsSettings['popupAnchor']) =>\n call<QuickCommandsSettings>('settings.setAnchor', { anchor }),\n settingsSetPopupSize: (size: QuickPopupSize) =>\n call<QuickCommandsSettings>('settings.setPopupSize', { width: size.width, height: size.height }),\n workspacesList: () => call<QuickRosterEntry[]>('workspaces.list'),\n runStart: (workspaceId: string, commandName: string, sessionCwd: string) =>\n call<QuickRunView>('run.start', { workspaceId, commandName, sessionCwd }),\n runPoll: (runId: string, stdoutFrom: number, stderrFrom: number) =>\n call<RunPoll>('run.poll', { runId, stdoutFrom, stderrFrom }),\n runKill: (runId: string) => call<{ killed: boolean }>('run.kill', { runId }),\n runList: (workspaceId: string) =>\n call<Array<{ runId: string; commandName: string; startedAt: number; status: 'running' | 'exited' }>>('run.list', { workspaceId }),\n}\n","/**\n * HMR-safe shared run state for the quick-commands header button and output\n * popup. Module-level fields live on one globalThis-backed record keyed with\n * Symbol.for so every client-bundle copy (client-hmr hot swap re-evaluates the\n * bundle without reloading the page) reads/writes the same state cell.\n *\n * The popup handles ONE run at a time (serial per workspace by design); a\n * second workspace can run in parallel with its own popup, so the store keys\n * popups by runId.\n */\nimport { useSyncExternalStore } from 'react'\n\nconst STATE_KEY = Symbol.for('@fonlan/dsh-quick-commands/run-state')\n\n/** One popup slot: menu open flag + the live run the popup streams. */\nexport interface RunPopoverState {\n /** Whether the header command menu is open. */\n menuOpen: boolean\n /** Active run id (undefined when no run is open). */\n runId: string | null\n /** Workspace id owning the active run (for kill/cwd display). */\n workspaceId: string | null\n /** Command display name. */\n commandName: string | null\n /** SSH host id when the run executes on a remote workspace (else null). */\n remoteHost: string | null\n /** Whether the run popup should stream (false while minimized). */\n streaming: boolean\n}\n\ninterface RunPopoverStateInternal extends RunPopoverState {\n listeners: Set<() => void>\n}\n\ninterface QuickCommandsState {\n popover: RunPopoverStateInternal\n /** Cached published snapshot — STABLE reference; rebuilt only after a patch. */\n snapshot: RunPopoverState | null\n}\n\nfunction getState(): QuickCommandsState {\n const g = globalThis as unknown as Record<symbol, QuickCommandsState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = {\n popover: {\n menuOpen: false,\n runId: null,\n workspaceId: null,\n commandName: null,\n remoteHost: null,\n streaming: true,\n listeners: new Set(),\n },\n // Seed the cache with values our equality check will see as unchanged.\n snapshot: {\n menuOpen: false,\n runId: null,\n workspaceId: null,\n commandName: null,\n remoteHost: null,\n streaming: true,\n },\n }\n g[STATE_KEY] = state\n }\n return state\n}\n\nfunction notify(): void {\n // Invalidate the cached snapshot FIRST: useSyncExternalStore reads\n // getSnapshot after notification, so a new stable object must be ready.\n getState().snapshot = null\n for (const listener of getState().popover.listeners) listener()\n}\n\nfunction subscribe(cb: () => void): () => void {\n const listeners = getState().popover.listeners\n listeners.add(cb)\n return () => { listeners.delete(cb) }\n}\n\n/**\n * getSnapshot for useSyncExternalStore. MUST return a stable reference while\n * the underlying fields are unchanged (React compares with Object.is) — return\n * the CACHED object; only rebuild it when a patch invalidated it.\n */\nfunction snapshot(): RunPopoverState {\n const state = getState()\n if (state.snapshot !== null) return state.snapshot\n const p = state.popover\n state.snapshot = {\n menuOpen: p.menuOpen,\n runId: p.runId,\n workspaceId: p.workspaceId,\n commandName: p.commandName,\n remoteHost: p.remoteHost,\n streaming: p.streaming,\n }\n return state.snapshot\n}\n\nfunction patch(partial: Partial<RunPopoverState>): void {\n const state = getState()\n Object.assign(state.popover, partial)\n // Invalidate the cached snapshot so equality flips exactly on real changes.\n state.snapshot = null\n notify()\n}\n\nexport function useRunPopover(): RunPopoverState {\n return useSyncExternalStore(subscribe, snapshot, snapshot)\n}\n\nexport function openMenu(): void { patch({ menuOpen: true }) }\nexport function closeMenu(): void { patch({ menuOpen: false }) }\nexport function toggleMenu(open: boolean): void { patch({ menuOpen: open }) }\n\nexport function openRun(runId: string, workspaceId: string, commandName: string, remoteHost?: string): void {\n patch({ runId, workspaceId, commandName, remoteHost: remoteHost ?? null, menuOpen: false, streaming: true })\n}\n\nexport function closeRun(): void {\n patch({ runId: null, workspaceId: null, commandName: null, remoteHost: null, streaming: false })\n}\n","/**\n * Shared wire contracts for @fonlan/dsh-quick-commands.\n *\n * Browser-safe: no host-only imports live here. The client bundle imports\n * these shapes (type-only + runtime constants), so anything that must cross\n * the fenced JSON API keeps its plain-Object shape here.\n */\n\n/** One configured quick command inside a workspace. */\nexport interface QuickCommandEntry {\n /** Human-facing command name (unique within the workspace). */\n name: string\n /** Shell command line, executed through bash -c / pwsh -c. */\n command: string\n}\n\n/** Config slice bound to one workspace (keyed by workspaceId). */\nexport interface WorkspaceCommands {\n /** DSH workspace registry id this command set belongs to. */\n workspaceId: string\n /** Ordered command entries. */\n commands: QuickCommandEntry[]\n}\n\n/** Output popup dimensions in CSS pixels (user drag-resize state). */\nexport interface QuickPopupSize {\n width: number\n height: number\n}\n\n/** Full user-facing plugin settings document (settings namespace value). */\nexport interface QuickCommandsSettings {\n /** Command sets; a workspace may be absent (no commands configured). */\n workspaces: WorkspaceCommands[]\n /** Output popup anchor preference: fixed bottom-right or anchored at the button. */\n popupAnchor: 'corner' | 'button'\n /** Output popup size; absent until the user drags the resize handle (then per-anchor defaults apply). */\n popupSize?: QuickPopupSize\n}\n\n/**\n * The document's anchor as a usable literal. Wire data is defensive by\n * contract: an older host can still answer with schemastery's empty-object\n * resolution (`{}`) for this field, which must never reach a CSS class name or\n * a radio `checked` comparison.\n */\nexport function anchorOf(value: unknown): 'corner' | 'button' {\n return value === 'button' ? 'button' : 'corner'\n}\n\n/** Placeholder substitution values resolved for one execution. */\nexport interface QuickRunPlaceholders {\n /** Workspace root path (also the execution cwd). */\n workspace: string\n /** Session actual cwd (may be a subdirectory of the workspace). */\n cwd: string\n /** Workspace display title. */\n title: string\n}\n\n/** One live run view returned by `run.start`. */\nexport interface QuickRunView {\n runId: string\n workspaceId: string\n commandName: string\n /** Command line after placeholder substitution (display only). */\n resolvedCommand: string\n /** Non-empty when the command executes over SSH on a remote workspace host. */\n remoteHost?: string\n status: 'running' | 'exited'\n exitCode: number | null\n signal: string | null\n startedAt: number\n /** Total stdout bytes captured so far (offset currency). */\n stdoutEnd: number\n /** Total stderr bytes captured so far (offset currency). */\n stderrEnd: number\n /** stdout tail appended since `stdoutFrom` (whole tail when lossy). */\n stdoutDelta: string\n /** stderr tail appended since `stderrFrom` (whole tail when lossy). */\n stderrDelta: string\n /** True when the in-memory tail lost its head for this stream. */\n stdoutLossy: boolean\n stderrLossy: boolean\n}\n\n/** API response envelope (mirrors task-kanban's fenced fetch wrapper). */\nexport interface ApiEnvelope<T> {\n ok: boolean\n value?: T\n error?: { code: string; message: string }\n}\n\n/** Settings card view: command sets plus the workspace roster for display. */\nexport interface QuickRosterEntry {\n workspaceId: string\n path: string\n title: string\n /** SSH host id when the workspace runs remotely through dsh-ssh (else absent). */\n remoteHost?: string\n commands: QuickCommandEntry[]\n}\n","/**\n * Session-header quick-command surface: the ▶ play icon button (left of the\n * Session log pill), the command menu popover (current workspace's commands),\n * and the live output popup that streams stdout/stderr at ~200ms cadence.\n *\n * Props are the standard session/global kit of `conversation.session.header.utilities`\n * plus this plugin's injected hooks (anchor preference + resolver).\n */\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { PlayIcon, CloseIcon, StopIcon } from './icons'\nimport { quickApi } from './api'\nimport { useRunPopover, openMenu, closeMenu, openRun, closeRun } from './run-state'\nimport { anchorOf, type QuickPopupSize } from '../shared/contract'\n\n/** Workspace row shape the standard useWorkspaces hook exposes. */\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n /** Session membership; the canonical link DSH itself resolves Workspaces by. */\n sessionIds?: string[]\n}\n\n/** Session list state subset we read (cwd + id). */\ninterface SessionRow {\n id: string\n cwd?: string\n}\n\ninterface HeaderProps {\n sessionId: string\n t: (key: string) => string\n useSessions?: (selector: (s: { byId: Record<string, SessionRow>; current?: string }) => unknown) => unknown\n useWorkspaces?: (selector: (s: { items: WorkspaceRow[] }) => unknown) => unknown\n}\n\ninterface MenuPosition {\n left: number\n top: number\n width: number\n}\n\nconst PHONE_MENU_RAIL_WIDTH = 56\nconst MENU_VIEWPORT_GAP = 12\nconst MENU_PREFERRED_WIDTH = 280\n\n/**\n * Position the portal menu beside its button without ever entering the phone\n * nav rail. Calculating actual pixels (rather than only CSS max-width) also\n * means it remains correct when the header itself sits in a clipped stacking\n * context created by a shell/mobile plugin.\n */\nfunction positionMenu(button: HTMLButtonElement): MenuPosition {\n const rect = button.getBoundingClientRect()\n const narrow = window.matchMedia('(max-width: 767px)').matches\n const minLeft = narrow ? PHONE_MENU_RAIL_WIDTH + MENU_VIEWPORT_GAP : MENU_VIEWPORT_GAP\n const availableWidth = Math.max(0, window.innerWidth - minLeft - MENU_VIEWPORT_GAP)\n const width = Math.min(MENU_PREFERRED_WIDTH, availableWidth)\n const maxLeft = Math.max(minLeft, window.innerWidth - MENU_VIEWPORT_GAP - width)\n return {\n // The old in-header popover used `right:12px`; retain that visual anchor\n // but clamp its left edge to the usable side of the rail.\n left: Math.max(minLeft, Math.min(rect.right - MENU_VIEWPORT_GAP - width, maxLeft)),\n top: Math.min(rect.bottom + 6, Math.max(MENU_VIEWPORT_GAP, window.innerHeight - 72)),\n width,\n }\n}\n\n/** Longest-path workspace match for a cwd (subdirectory allowed). */\nfunction matchWorkspace(cwd: string | undefined, workspaces: WorkspaceRow[]): WorkspaceRow | undefined {\n if (cwd === undefined) return undefined\n let best: WorkspaceRow | undefined\n for (const ws of workspaces) {\n const norm = ws.path.replace(/\\\\/g, '/').replace(/\\/+$/, '')\n const nc = cwd.replace(/\\\\/g, '/')\n if (nc === norm || nc.startsWith(norm + '/')) {\n if (best === undefined || norm.length > best.path.length) best = ws\n }\n }\n return best\n}\n\n/** Resolve the current session's workspace from the standard kits. */\nfunction useCurrentWorkspace(\n sessionId: string,\n useSessions?: HeaderProps['useSessions'],\n useWorkspaces?: HeaderProps['useWorkspaces'],\n): { workspace: WorkspaceRow | undefined; cwd: string | undefined } {\n const row = useSessions?.((s) => s.byId[sessionId]) as SessionRow | undefined\n const workspaces = useWorkspaces?.((s) => s.items) as WorkspaceRow[] | undefined\n const items = workspaces ?? []\n // Membership first (how DSH core resolves a session's Workspace, and the only\n // link that survives when a session runs outside the Workspace root), then\n // the longest cwd prefix as the fallback for hosts without membership data.\n const byMembership = items.find((ws) => ws.sessionIds?.includes(sessionId) === true)\n return { workspace: byMembership ?? matchWorkspace(row?.cwd, items), cwd: row?.cwd }\n}\n\n/** Header icon button + command menu + live output popup. */\nexport function QuickCommandsHeaderAction(props: HeaderProps): JSX.Element {\n const { sessionId, t } = props\n const { workspace, cwd } = useCurrentWorkspace(sessionId, props.useSessions, props.useWorkspaces)\n const popover = useRunPopover()\n const [commands, setCommands] = useState<Array<{ name: string; command: string }>>([])\n const [menuLoadError, setMenuLoadError] = useState<string | null>(null)\n const [menuRemoteHost, setMenuRemoteHost] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [anchor, setAnchor] = useState<'corner' | 'button'>('corner')\n const [popupSize, setPopupSize] = useState<QuickPopupSize | undefined>(undefined)\n const wrapRef = useRef<HTMLDivElement | null>(null)\n const buttonRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPosition, setMenuPosition] = useState<MenuPosition | null>(null)\n\n // Click-outside dismissal: the command menu is portaled to document.body so\n // it escapes the mobile shell's clipped/z-indexed header context. Treat both\n // its portal node and its original header wrap as inside targets.\n useEffect(() => {\n if (!popover.menuOpen) return\n const onPointerDown = (e: PointerEvent): void => {\n const wrap = wrapRef.current\n const menu = menuRef.current\n if (!(e.target instanceof Node)) return\n if (wrap?.contains(e.target) || menu?.contains(e.target)) return\n closeMenu()\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => { document.removeEventListener('pointerdown', onPointerDown) }\n }, [popover.menuOpen])\n\n // Recalculate against the actual header button whenever the menu opens and\n // whenever a viewport change moves it (rotation, browser chrome resize).\n useLayoutEffect(() => {\n if (!popover.menuOpen) {\n setMenuPosition(null)\n return\n }\n const update = (): void => {\n const button = buttonRef.current\n if (button !== null) setMenuPosition(positionMenu(button))\n }\n update()\n window.addEventListener('resize', update)\n window.addEventListener('scroll', update, true)\n window.visualViewport?.addEventListener('resize', update)\n return () => {\n window.removeEventListener('resize', update)\n window.removeEventListener('scroll', update, true)\n window.visualViewport?.removeEventListener('resize', update)\n }\n }, [popover.menuOpen])\n\n // Load the workspace's command list + anchor when the menu opens.\n useEffect(() => {\n if (!popover.menuOpen) return\n let cancelled = false\n void (async () => {\n try {\n const [entries, settings] = await Promise.all([quickApi.workspacesList(), quickApi.settingsGet()])\n if (cancelled) return\n const own = entries.find((e) => e.workspaceId === workspace?.workspaceId)\n setCommands(own === undefined ? [] : own.commands)\n setMenuRemoteHost(own?.remoteHost ?? null)\n setAnchor(anchorOf(settings.popupAnchor))\n setPopupSize(settings.popupSize)\n setMenuLoadError(null)\n } catch (e) {\n if (cancelled) return\n setCommands([])\n setMenuLoadError(e instanceof Error ? e.message : String(e))\n }\n })()\n return () => { cancelled = true }\n }, [popover.menuOpen, workspace?.workspaceId])\n\n const startRun = async (commandName: string): Promise<void> => {\n setBusy(true)\n closeMenu()\n try {\n const run = await quickApi.runStart(workspace!.workspaceId, commandName, cwd ?? workspace!.path)\n openRun(run.runId, run.workspaceId, run.commandName, run.remoteHost)\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e)\n if (message.includes('run-busy') || message.includes('already running')) {\n setMenuLoadError(t('runBusy'))\n } else {\n setMenuLoadError(t('runStartFailed') + ': ' + message)\n }\n openMenu()\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div ref={wrapRef} className=\"qc-head-wrap\">\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"qc-head-btn\"\n title={workspace === undefined ? t('noWorkspace') : t('buttonTooltip')}\n aria-label={t('buttonTitle')}\n disabled={workspace === undefined}\n onClick={() => { popover.menuOpen ? closeMenu() : openMenu() }}\n >\n <PlayIcon size={15} />\n </button>\n\n {popover.menuOpen && workspace !== undefined && menuPosition !== null && createPortal(\n <div\n ref={menuRef}\n className=\"qc-menu qc-menu-portal\"\n role=\"menu\"\n style={{ left: menuPosition.left, top: menuPosition.top, width: menuPosition.width }}\n >\n <div className=\"qc-menu-head\">\n <span className=\"qc-menu-title\">{t('menuTitle')}</span>\n {menuRemoteHost !== null && <span className=\"qc-menu-remote\" title={`SSH · ${menuRemoteHost}`}>SSH</span>}\n <span className=\"qc-menu-ws\">{workspace.title}</span>\n <button type=\"button\" className=\"qc-menu-close\" aria-label={t('runClose')} onClick={closeMenu}>\n <CloseIcon size={12} />\n </button>\n </div>\n {commands.length === 0 && (\n <p className=\"qc-menu-empty\">{menuLoadError ?? t('noCommands')}</p>\n )}\n {commands.filter((c) => c.name.trim() !== '').map((command) => (\n <button\n key={command.name}\n type=\"button\"\n role=\"menuitem\"\n className=\"qc-menu-item\"\n disabled={busy}\n onClick={() => void startRun(command.name)}\n >\n <span className=\"qc-menu-item-name\">{command.name}</span>\n <span className=\"qc-menu-item-cmd\">{command.command}</span>\n </button>\n ))}\n </div>\n , document.body)}\n\n {popover.runId !== null && (\n <RunPopup\n runId={popover.runId}\n workspaceId={popover.workspaceId ?? ''}\n commandName={popover.commandName ?? ''}\n remoteHost={popover.remoteHost ?? undefined}\n t={t}\n anchor={anchor}\n popupSize={popupSize}\n sessionId={sessionId}\n onClose={closeRun}\n />\n )}\n </div>\n )\n}\n\n// ── popup drag-resize ───────────────────────────────────────────────────────\n// The popup pins its RIGHT edge (both anchors), plus its BOTTOM edge (corner\n// anchor) or TOP edge (button anchor, pinned below the button). So the MOVABLE\n// borders are the LEFT border (width) and the TOP border (corner anchor) /\n// BOTTOM border (button anchor) (height); the free corner (top-left /\n// bottom-left) carries a diagonal grip for simultaneous two-axis resizing.\n// Every handle follows the cursor edge-for-edge — pulling the left border LEFT\n// widens, pulling the top border UP grows taller — nothing feels inverted.\n// The size is clamped to viewport bounds and persisted to settings.\n\nconst POPUP_MIN_W = 320\nconst POPUP_MIN_H = 200\n/** Total horizontal margin kept around the popup (both anchors). */\nconst POPUP_VIEWPORT_MARGIN = 40\n/** Vertical space reserved for header/footer chrome (both anchors). */\nconst POPUP_VIEWPORT_RESERVED = 120\n\nfunction popupDefaultSize(anchor: 'corner' | 'button'): QuickPopupSize {\n return anchor === 'corner' ? { width: 520, height: 340 } : { width: 440, height: 300 }\n}\n\nfunction popupClamp(size: QuickPopupSize): QuickPopupSize {\n const maxW = Math.max(POPUP_MIN_W, window.innerWidth - POPUP_VIEWPORT_MARGIN)\n const maxH = Math.max(POPUP_MIN_H, window.innerHeight - POPUP_VIEWPORT_RESERVED)\n return {\n width: Math.min(Math.max(POPUP_MIN_W, Math.round(size.width)), maxW),\n height: Math.min(Math.max(POPUP_MIN_H, Math.round(size.height)), maxH),\n }\n}\n\n/**\n * Initial popup size: the persisted one when it holds sane numbers, else the\n * per-anchor default. Defensive because schemastery resolves a MISSING object\n * field to `{}` (object schemas carry an implicit `default: {}`), so a\n * never-resized popup can arrive as `popupSize: {}` from settings.get().\n */\nfunction popupSizeOrDefault(size: QuickPopupSize | undefined, anchor: 'corner' | 'button'): QuickPopupSize {\n if (\n size === undefined\n || !Number.isFinite(size.width)\n || !Number.isFinite(size.height)\n || size.width <= 0\n || size.height <= 0\n ) {\n return popupDefaultSize(anchor)\n }\n return popupClamp(size)\n}\n\n/** The streaming output popup. Polls stdout/stderr deltas every ~200ms. */\nfunction RunPopup(props: {\n runId: string\n workspaceId: string\n commandName: string\n remoteHost?: string\n t: (key: string) => string\n anchor: 'corner' | 'button'\n popupSize?: QuickPopupSize\n sessionId: string\n onClose: () => void\n}): JSX.Element {\n const { runId, t, anchor, remoteHost, onClose } = props\n const [size, setSize] = useState<QuickPopupSize>(() => popupSizeOrDefault(props.popupSize, anchor))\n // Mirrors `size` for drag handlers: pointer events can arrive faster than\n // React commits, so pointerup must read the latest value, not the render's.\n const sizeRef = useRef<QuickPopupSize>(size)\n const sizeDragRef = useRef<{\n pointerId: number\n startX: number\n startY: number\n startW: number\n startH: number\n /** Which handle started the drag (controls which axes move). */\n mode: 'left' | 'height' | 'corner'\n } | null>(null)\n const [state, setState] = useState(() => ({\n status: 'running' as 'running' | 'exited',\n exitCode: null as number | null,\n signal: null as string | null,\n stdoutEnd: 0,\n stderrEnd: 0,\n stdout: '',\n stderr: '',\n stdoutLossy: false,\n stderrLossy: false,\n }))\n const [view, setView] = useState<'stdout' | 'stderr'>('stdout')\n const [autoFollow, setAutoFollow] = useState(true)\n const [pollError, setPollError] = useState<string | null>(null)\n const [closing, setClosing] = useState(false)\n const outputRef = useRef<HTMLDivElement | null>(null)\n const autoFollowRef = useRef(true)\n\n // Auto-follow: scroll the output pane to the bottom on new output while the\n // user has not scrolled up (autoFollow mirror keeps the effect cheap).\n useEffect(() => {\n autoFollowRef.current = autoFollow\n }, [autoFollow])\n useEffect(() => {\n if (!autoFollowRef.current) return\n const el = outputRef.current\n if (el === null) return\n el.scrollTop = el.scrollHeight\n }, [state.stdout, state.stderr, view])\n\n // Poll deltas; stop polling at exit (the run stays readable in memory).\n useEffect(() => {\n let cancelled = false\n let outEnd = 0\n let errEnd = 0\n const tick = async (): Promise<void> => {\n try {\n const poll = await quickApi.runPoll(runId, outEnd, errEnd)\n if (cancelled) return\n outEnd = poll.stdoutEnd\n errEnd = poll.stderrEnd\n setState((s) => ({\n status: poll.status,\n exitCode: poll.exitCode,\n signal: poll.signal,\n stdoutEnd: poll.stdoutEnd,\n stderrEnd: poll.stderrEnd,\n stdout: poll.stdoutLossy ? poll.stdoutDelta : s.stdout + poll.stdoutDelta,\n stderr: poll.stderrLossy ? poll.stderrDelta : s.stderr + poll.stderrDelta,\n stdoutLossy: poll.stdoutLossy,\n stderrLossy: poll.stderrLossy,\n }))\n setPollError(null)\n if (poll.status === 'exited') return\n timer = window.setTimeout(() => void tick(), 200)\n } catch (e) {\n if (cancelled) return\n setPollError(e instanceof Error ? e.message : String(e))\n timer = window.setTimeout(() => void tick(), 500)\n }\n }\n let timer: number\n void tick()\n return () => { cancelled = true; window.clearTimeout(timer) }\n }, [runId])\n\n const kill = async (): Promise<void> => {\n setClosing(true)\n try {\n await quickApi.runKill(runId)\n } finally {\n onClose()\n }\n }\n\n // Closing the output surface must not terminate a still-running command:\n // the dedicated stop control owns that destructive action. In particular,\n // an X in a compact touch header is expected to dismiss immediately rather\n // than reveal a second confirmation row below the visible viewport.\n const closeOutput = (): void => { onClose() }\n\n // Some mobile webviews occasionally fail to synthesize `click` for compact\n // header controls after a touch gesture. Handle touch pointer-up directly;\n // click remains the keyboard and mouse activation path.\n const onClosePointerUp = (e: React.PointerEvent<HTMLButtonElement>): void => {\n if (e.pointerType !== 'touch') return\n e.preventDefault()\n closeOutput()\n }\n\n // ── drag-resize: pointer capture on the handles keeps moving/cancelling\n // events flowing even when the cursor leaves the handle or the window.\n // Which border is free to move depends on the anchor: the corner anchor\n // pins bottom+right (top border moves for height), the button anchor pins\n // top+right (bottom border moves for height).\n const heightFree: 'top' | 'bottom' = anchor === 'corner' ? 'top' : 'bottom'\n\n const onResizePointerDown = (e: React.PointerEvent<HTMLDivElement>): void => {\n e.preventDefault() // keep the handle from starting a text-selection gesture\n e.currentTarget.setPointerCapture(e.pointerId)\n sizeDragRef.current = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n startW: sizeRef.current.width,\n startH: sizeRef.current.height,\n mode: e.currentTarget.dataset.resize as 'left' | 'height' | 'corner',\n }\n }\n\n const onResizePointerMove = (e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = sizeDragRef.current\n if (drag === null || drag.pointerId !== e.pointerId) return\n const dx = e.clientX - drag.startX\n const dy = e.clientY - drag.startY\n const controlsW = drag.mode === 'left' || drag.mode === 'corner'\n const controlsH = drag.mode === 'height' || drag.mode === 'corner'\n const next = popupClamp({\n // Left border follows the cursor: dragging LEFT widens, RIGHT narrows.\n width: controlsW ? drag.startW - dx : drag.startW,\n // Top-free (corner): dragging UP grows. Bottom-free (button): DOWN grows.\n height: controlsH ? drag.startH + (heightFree === 'top' ? -dy : dy) : drag.startH,\n })\n sizeRef.current = next\n setSize(next)\n }\n\n const onResizePointerUp = (e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = sizeDragRef.current\n if (drag === null || drag.pointerId !== e.pointerId) return\n sizeDragRef.current = null\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId)\n }\n // Persist best-effort: a failed save just means the next popup reopens at\n // the default size (or the last successfully saved one).\n void quickApi.settingsSetPopupSize(sizeRef.current).catch(() => undefined)\n }\n\n /** Pointer-handler trio for one resize handle (mode = which axes it drives). */\n const resizeProps = (mode: 'left' | 'height' | 'corner') => ({\n 'data-resize': mode,\n onPointerDown: onResizePointerDown,\n onPointerMove: onResizePointerMove,\n onPointerUp: onResizePointerUp,\n onPointerCancel: onResizePointerUp,\n })\n\n const active = state.status === 'running'\n const title = active ? `${props.commandName} · ${t('runStateRunning')}` : `${props.commandName} · ${t('runStateExited')} (${state.exitCode ?? '?'})`\n\n return (\n <div className={`qc-popup qc-popup-${anchor}`} role=\"dialog\" aria-label={title} style={{ width: size.width, height: size.height }}>\n <header className=\"qc-popup-head\">\n <span className=\"qc-popup-title\" title={title}>{title}</span>\n {remoteHost !== undefined && <span className=\"qc-popup-remote\" title={`SSH · ${remoteHost}`}>SSH</span>}\n <span className=\"qc-popup-cmd\">{props.commandName}</span>\n <button\n type=\"button\"\n className=\"qc-popup-icon qc-popup-kill\"\n disabled={!active || closing}\n title={t('runKill')}\n aria-label={t('runKill')}\n onClick={() => void kill()}\n >\n <StopIcon size={14} />\n </button>\n <button\n type=\"button\"\n className=\"qc-popup-icon qc-popup-close\"\n title={t('runClose')}\n aria-label={t('runClose')}\n onPointerUp={onClosePointerUp}\n onClick={closeOutput}\n >\n <CloseIcon size={14} />\n </button>\n </header>\n\n <div className=\"qc-popup-tabs\">\n <button\n type=\"button\"\n className={'qc-popup-tab' + (view === 'stdout' ? ' qc-popup-tab-active' : '')}\n onClick={() => setView('stdout')}\n >\n {t('runStdout')}\n </button>\n <button\n type=\"button\"\n className={'qc-popup-tab' + (view === 'stderr' ? ' qc-popup-tab-active' : '')}\n onClick={() => setView('stderr')}\n >\n {t('runStderr')}\n </button>\n </div>\n\n <div\n ref={outputRef}\n className=\"qc-popup-output\"\n onScroll={(e) => {\n const el = e.currentTarget\n const atEnd = Math.abs(el.scrollHeight - el.scrollTop - el.clientHeight) < 24\n setAutoFollow(atEnd)\n }}\n >\n {pollError !== null && <p className=\"qc-popup-error\">{t('runPollFailed')}: {pollError}</p>}\n {view === 'stdout' ? (\n state.stdout === '' && !active ? <p className=\"qc-popup-empty\">{t('runEmpty')}</p>\n : <pre className=\"qc-popup-pre\">{state.stdout}</pre>\n ) : (\n state.stderr === '' && !active ? <p className=\"qc-popup-empty\">{t('runEmpty')}</p>\n : <pre className=\"qc-popup-pre\">{state.stderr}</pre>\n )}\n </div>\n\n <footer className=\"qc-popup-foot\">\n <span className=\"qc-popup-state\">\n {active ? t('runStateRunning') : `${t('runStateExited')} · ${t('runExitCode')} ${state.exitCode ?? '-'}${state.signal !== null ? ` · ${state.signal}` : ''}`}\n </span>\n </footer>\n\n {/* Resize handles: left border = width; top (corner anchor) / bottom\n (button anchor) border = height; free corner = diagonal grip. */}\n <div className=\"qc-popup-resize qc-popup-resize-left\" title={t('runResize')} {...resizeProps('left')} />\n {heightFree === 'top'\n ? <div className=\"qc-popup-resize qc-popup-resize-top\" title={t('runResize')} {...resizeProps('height')} />\n : <div className=\"qc-popup-resize qc-popup-resize-bottom\" title={t('runResize')} {...resizeProps('height')} />}\n {heightFree === 'top' ? (\n <div className=\"qc-popup-resize qc-popup-resize-corner qc-popup-resize-corner-tl\" title={t('runResize')} {...resizeProps('corner')}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M9 9 3 3 M9 5.5 5.5 3 M5.5 9 3 5.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n ) : (\n <div className=\"qc-popup-resize qc-popup-resize-corner qc-popup-resize-corner-bl\" title={t('runResize')} {...resizeProps('corner')}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M9 3 3 9 M9 6.5 6.5 9 M5.5 3 3 5.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Quick-commands settings page (设置 → 侧栏「快捷命令」).\n *\n * Registers into the \"settings.section\" list slot, so the page owns one entry\n * in the settings sidebar and renders in the settings panel's content column.\n * The header is static (title + one-line summary) over the always-visible\n * body: the workspace / command-set editor and the popup anchor preference.\n * Body edits instant-save per change; partial rows (empty name/command)\n * persist while the user types.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport { PlusIcon, TrashIcon } from './icons'\nimport { quickApi } from './api'\nimport { anchorOf, type QuickRosterEntry, type QuickCommandsSettings } from '../shared/contract'\nimport './settings-section.css'\n\ninterface Props {\n t: (key: string) => string\n}\n\ninterface RosterState {\n loaded: boolean\n entries: QuickRosterEntry[]\n anchor: QuickCommandsSettings['popupAnchor']\n}\n\ntype CommandDraft = { name: string; command: string }\n\nexport function QuickCommandsSettingsSection({ t }: Props): JSX.Element {\n const [state, setState] = useState<RosterState>({ loaded: false, entries: [], anchor: 'corner' })\n const [error, setError] = useState<string | null>(null)\n // Guard concurrent saves: the last write wins via a monotonically bumped token.\n const saveToken = useRef(0)\n\n const load = async (): Promise<void> => {\n try {\n const [entries, settings] = await Promise.all([quickApi.workspacesList(), quickApi.settingsGet()])\n setState({ loaded: true, entries, anchor: anchorOf(settings.popupAnchor) })\n setError(null)\n } catch (e) {\n setState((s) => ({ ...s, loaded: true }))\n setError(e instanceof Error ? e.message : String(e))\n }\n }\n\n useEffect(() => {\n void load()\n }, [])\n\n /** Instant-save the workspace's whole command set; optimistic UI. */\n const saveCommands = async (workspaceId: string, commands: CommandDraft[]): Promise<void> => {\n const token = ++saveToken.current\n try {\n const next = await quickApi.settingsSetCommands(workspaceId, commands)\n if (token !== saveToken.current) return\n setState((s) => ({\n ...s,\n anchor: next.popupAnchor,\n entries: s.entries.map((e) => (e.workspaceId === workspaceId ? { ...e, commands } : e)),\n }))\n setError(null)\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n // Re-sync to server truth on failure.\n void load()\n }\n }\n\n /** Compute the next command list for a workspace, THEN save + update state. */\n const mutateCommands = (workspaceId: string, next: (current: CommandDraft[]) => CommandDraft[]): void => {\n const entry = state.entries.find((e) => e.workspaceId === workspaceId)\n if (entry === undefined) return\n const commands = next(entry.commands)\n // Optimistic update first (row stays visible immediately), then persist.\n setState((s) => ({\n ...s,\n entries: s.entries.map((e) => (e.workspaceId === workspaceId ? { ...e, commands } : e)),\n }))\n void saveCommands(workspaceId, commands)\n }\n\n const patchEntry = (workspaceId: string, index: number, field: 'name' | 'command', value: string): void => {\n mutateCommands(workspaceId, (current) =>\n current.map((c, i) => (i === index ? { ...c, [field]: value } : c)),\n )\n }\n\n const addCommand = (workspaceId: string): void => {\n mutateCommands(workspaceId, (current) => [...current, { name: '', command: '' }])\n }\n\n const removeCommand = (workspaceId: string, index: number): void => {\n mutateCommands(workspaceId, (current) => current.filter((_, i) => i !== index))\n }\n\n const setAnchor = async (anchor: QuickCommandsSettings['popupAnchor']): Promise<void> => {\n setState((s) => ({ ...s, anchor }))\n try {\n const next = await quickApi.settingsSetAnchor(anchor)\n setState((s) => ({ ...s, anchor: anchorOf(next.popupAnchor) }))\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n void load()\n }\n }\n\n const title = t('cardTitle')\n const description = t('sectionSub')\n\n return (\n <div className=\"qc-page\">\n <header className=\"qc-page-head\">\n <h3 className=\"qc-page-title\">{title}</h3>\n <p className=\"qc-page-sub\">{description}</p>\n </header>\n <div className=\"qc-settings-body\">\n <p className=\"qc-settings-intro\">{t('cardIntro')}</p>\n\n <div className=\"qc-settings-anchor\">\n <span className=\"qc-settings-anchor-label\">{t('cardAnchor')}</span>\n <label className=\"qc-settings-radio\">\n <input\n type=\"radio\"\n name=\"qc-anchor\"\n checked={state.anchor === 'corner'}\n onChange={() => void setAnchor('corner')}\n />\n {t('cardAnchorCorner')}\n </label>\n <label className=\"qc-settings-radio\">\n <input\n type=\"radio\"\n name=\"qc-anchor\"\n checked={state.anchor === 'button'}\n onChange={() => void setAnchor('button')}\n />\n {t('cardAnchorButton')}\n </label>\n </div>\n\n {error !== null && <div className=\"qc-settings-error\">{t('cardSaveError')}: {error}</div>}\n\n {state.loaded && state.entries.length === 0 && (\n <p className=\"qc-settings-empty\">{t('cardNoWorkspaces')}</p>\n )}\n\n {state.entries.map((entry) => (\n <section key={entry.workspaceId} className=\"qc-settings-workspace\">\n <header className=\"qc-settings-workspace-head\">\n <span className=\"qc-settings-workspace-title\">{entry.title || entry.path || entry.workspaceId}</span>\n <span className=\"qc-settings-workspace-path\">{entry.path}</span>\n </header>\n {entry.commands.length === 0 && (\n <p className=\"qc-settings-no-commands\">{t('cardNoCommands')}</p>\n )}\n {entry.commands.map((command, index) => (\n <div key={`${entry.workspaceId}-${index}`} className=\"qc-settings-command\">\n <input\n className=\"qc-settings-field qc-settings-field-name\"\n placeholder={t('cardName')}\n value={command.name}\n aria-label={t('cardName')}\n onChange={(e) => patchEntry(entry.workspaceId, index, 'name', e.target.value)}\n />\n <input\n className=\"qc-settings-field qc-settings-field-command\"\n placeholder={t('cardCommand')}\n value={command.command}\n aria-label={t('cardCommand')}\n onChange={(e) => patchEntry(entry.workspaceId, index, 'command', e.target.value)}\n />\n <button\n type=\"button\"\n className=\"qc-settings-icon-btn\"\n aria-label={t('cardRemove')}\n title={t('cardRemove')}\n onClick={() => removeCommand(entry.workspaceId, index)}\n >\n <TrashIcon size={14} />\n </button>\n </div>\n ))}\n <button type=\"button\" className=\"qc-settings-add-btn\" onClick={() => addCommand(entry.workspaceId)}>\n <PlusIcon size={14} />\n {t('cardAddCommand')}\n </button>\n </section>\n ))}\n </div>\n </div>\n )\n}\n","/**\n * Client dictionary namespace for @fonlan/dsh-quick-commands.\n */\nexport const LOCALE_NS = 'quick-commands'\n\nexport const zh = {\n // header button\n buttonTitle: '快速命令',\n buttonTooltip: '快速命令(当前工作区)',\n noWorkspace: '当前会话不在任何已配置的工作区中',\n noCommands: '当前工作区未配置命令',\n openSettings: '去设置配置命令',\n\n // command popup menu\n menuTitle: '快速命令',\n menuEmpty: '(无命令)',\n\n // run popup\n runTitle: '运行中',\n runExited: '已退出',\n runExitCode: '退出码',\n runSignal: '信号',\n runStdout: '输出 (stdout)',\n runStderr: '错误 (stderr)',\n runEmpty: '(无输出)',\n runCommand: '命令',\n runCwd: '工作区',\n runStateRunning: '运行中…',\n runStateExited: '已退出',\n runKill: '终止',\n runClose: '关闭',\n runResize: '拖动调整弹窗大小',\n runKillConfirm: '终止后输出弹窗将关闭,确定终止该命令?',\n runBusy: '该工作区已有命令在运行',\n runStartFailed: '命令启动失败',\n runPollFailed: '输出读取失败',\n runLost: '运行记录已失效',\n runNotFound: '工作区或命令未找到',\n\n // settings page (设置 → 侧栏「快捷命令」)\n settingsTitle: '快捷命令',\n cardTitle: '快速命令',\n sectionSub: '为每个工作区配置常用命令,会话头部一键运行',\n cardIntro: '为每个工作区配置常用命令,运行于工作区目录。支持占位符:{workspace} 工作区路径,{cwd} 会话目录,{title} 工作区标题。',\n cardWorkspaces: '工作区',\n cardNoWorkspaces: '没有工作区。请在侧边栏先添加工作区。',\n cardCommands: '命令',\n cardNoCommands: '未配置命令',\n cardAddCommand: '添加命令',\n cardName: '名称',\n cardCommand: '命令',\n cardRemove: '删除',\n cardSaveError: '保存失败',\n cardAnchor: '输出弹窗位置',\n cardAnchorCorner: '右下角',\n cardAnchorButton: '锚定按钮下方',\n} as const\n\nexport const en: Record<keyof typeof zh, string> = {\n buttonTitle: 'Quick commands',\n buttonTooltip: 'Quick commands (current workspace)',\n noWorkspace: 'This session is not in any configured workspace',\n noCommands: 'No commands configured for this workspace',\n openSettings: 'Configure commands in Settings',\n\n menuTitle: 'Quick commands',\n menuEmpty: '(no commands)',\n\n runTitle: 'Running',\n runExited: 'Exited',\n runExitCode: 'Exit code',\n runSignal: 'Signal',\n runStdout: 'Output (stdout)',\n runStderr: 'Errors (stderr)',\n runEmpty: '(no output)',\n runCommand: 'Command',\n runCwd: 'Workspace',\n runStateRunning: 'Running…',\n runStateExited: 'Exited',\n runKill: 'Terminate',\n runClose: 'Close',\n runResize: 'Drag to resize the popup',\n runKillConfirm: 'Terminating closes the output popup. Terminate this command?',\n runBusy: 'A command is already running for this workspace',\n runStartFailed: 'Command failed to start',\n runPollFailed: 'Failed to read output',\n runLost: 'Run record expired',\n runNotFound: 'Workspace or command not found',\n\n settingsTitle: 'Quick Commands',\n cardTitle: 'Quick commands',\n sectionSub: 'Configure common commands per workspace, run them from the session header',\n cardIntro: 'Configure common commands per workspace; they run in the workspace directory. Placeholders: {workspace} workspace path, {cwd} session cwd, {title} workspace title.',\n cardWorkspaces: 'Workspaces',\n cardNoWorkspaces: 'No workspaces. Add one in the sidebar first.',\n cardCommands: 'Commands',\n cardNoCommands: 'No commands configured',\n cardAddCommand: 'Add command',\n cardName: 'Name',\n cardCommand: 'Command',\n cardRemove: 'Remove',\n cardSaveError: 'Save failed',\n cardAnchor: 'Output popup position',\n cardAnchorCorner: 'Bottom right',\n cardAnchorButton: 'Anchored at button',\n}\n","/**\n * @fonlan/dsh-quick-commands client half.\n *\n * Registers:\n * - \"settings.section\" page (id \"quick-commands\", order 330) — per-workspace\n * command CRUD + popup anchor preference, rendered as its own page in the\n * settings sidebar.\n * - \"conversation.session.header.utilities\" entry (id \"quick-commands\",\n * order -1 → left of the Session log pill) — the quick-run ▶ button, command\n * menu, and live output popup.\n */\nimport type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { QuickCommandsHeaderAction } from './header'\nimport { QuickCommandsSettingsSection } from './settings-section'\nimport { LOCALE_NS, zh, en } from './locales'\nimport './quick-commands.css'\n\n/** Slots face (local, erased at build). */\ninterface Slots {\n inject(name: string, callback: () => unknown): unknown\n register(\n def: { name: string; id?: string; order?: number; label?: string | (() => string); locale?: string },\n component: unknown,\n ): unknown\n}\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), 'quick-commands: dictionaries')\n const t = ctx.locale.bind(LOCALE_NS)\n const slots = (ctx as unknown as { slots: Slots }).slots\n\n // The plugin's own settings page (设置 → 侧栏「快捷命令」) rides the\n // \"quick-commands\" locale namespace: a \"settings.section\" list entry gives it\n // one row in the settings sidebar and renders the page in the content column.\n slots.inject('settings.section', () =>\n slots.register({\n name: 'settings.section',\n id: 'quick-commands',\n order: 330,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, QuickCommandsSettingsSection as never),\n )\n\n // Session-header util: order -1 renders LEFT of the Session log pill\n // (session-log-download registers with default order 0).\n slots.inject('conversation.session.header.utilities', () =>\n slots.register({\n name: 'conversation.session.header.utilities',\n id: 'quick-commands',\n order: -1,\n locale: LOCALE_NS,\n }, QuickCommandsHeaderAction as never),\n )\n}\n"],"mappings":"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"}
|