Files
apes-sidebar/src/client/reference-in-chat.ts
T
Menghuan1918 51546f7433 feat(native): render the plugin's tabs in DSH's native right Sidebar
Phase 2 of the 0.1.5 adaptation: the plugin stops drawing its own right
panel and contributes tab TYPES to DSH's native right Sidebar, which owns
the right column. The bottom workbench (terminal dock) stays plugin-owned.

Registrations (src/client/native/):
- every TabDescriptor becomes a native tab type (kind = descriptor.id, the
  default `extension` band) plus a keyed body in `sidebar.right.pane.tab`
  and a live chip title in `sidebar.right.pane.tab.title`
- the `editor` type also claims `dsh-resource://file/**`, so it outranks
  the built-in `text` preview (fallback) and every file the product opens
  lands in the plugin's editor
- the built-in `files` page kind is TAKEN OVER by an extension
  registration of the same kind: `openTab('files')` draws the plugin's
  explorer, and the built-in resumes when the plugin unregisters
- registrations follow the plugin registry + the side-card settings: a
  type registered later (external plugin) gets its native type too, a
  disabled type is unregistered (absent from the guide, refuses opens)

Adapter (src/client/native/tab-adapter.tsx):
- one synthetic plugin `SidebarTab` per native tab id, minted from the
  native record + navigation params (or the descriptor's own createTab,
  which a native guide open bypasses), kept live across navigations and
  updateTab writes
- the explorer's per-tab expansion/reveal sets and the per-kind instance
  counter, which the plugin's own layout used to hold

Service routing (src/client/service.ts):
- `setSurface` installs the native write face; openTab/openFile land
  natively (a path becomes a resource address, a path-less editor open
  becomes the `files` page, the rest carry the seed as navigation params),
  closeTab/updateTab/activateTab recognise native tab ids
- new optional `OpenTabSeed.target` ('right' default, 'bottom' keeps the
  bottom workbench); the bottom panel's own + menu and auto-terminal pass
  'bottom'
- src/client/native/surface.ts probes the controller's per-session writes
  (`openTabIn`/`openResourceIn`/`closeIn`, not in `ISidebarRight`) and
  queues opens for a session whose surface is not mounted yet

Right panel retired behaviourally (Phase 3 deletes the code): Sidebar
renders its bottom workbench only, keeps the panel collapsed, and hides
the right-panel toggle. The panel-specific e2e specs are removed; the
mount lane now drives the native guide (tab sweep), the plugin explorer
inside the native pane (editor/mermaid/README chunks) and the sidechat
host routes.

Verified: pnpm typecheck / lint / build / test (126 files, 1349 tests) /
check:consumer-types, plus pnpm test:mount against a real
@deepseek-ai/dsh@0.1.5-alpha.1 host (7/7).
2026-09-09 11:47:31 +08:00

43 lines
1.6 KiB
TypeScript

/**
* The explorer's `@`-reference button: insert one file or folder reference
* into the conversation draft of a session.
*
* Directories append the folder mention (`@dir/`) as plain text so DSH's
* folder decoration and completion keep working; files insert a structured
* chip like the native `@` picker, so the whole reference stays one link
* instead of decorating only the leading folder. The session-scope context and
* the conversation input service are resolved at click time; a missing service
* or scope degrades to a logged no-op, never a crash.
*
* Shared by the plugin's own panel and the native right-Sidebar tab body, so
* both surfaces behave identically.
*/
import type { Context } from '../context-types.ts'
import { appendToDraft, insertFileReference } from './conversation-draft.ts'
import { relativeTo } from './paths.ts'
/**
* Reference one path in the session's conversation draft.
* @param ctx - the client context.
* @param sessionId - the session whose draft receives the reference.
* @param cwd - that session's workspace root (for the relative spelling).
* @param path - the absolute or workspace-relative path to reference.
* @param isDir - whether the path is a directory (folder mention vs file chip).
*/
export function referenceInChat(
ctx: Context,
sessionId: string,
cwd: string | undefined,
path: string,
isDir: boolean,
): void {
const rel = relativeTo(cwd ?? '', path)
if (isDir) {
appendToDraft(ctx, sessionId, `@${rel === '.' ? './' : `${rel}/`}`)
return
}
if (!insertFileReference(ctx, sessionId, rel)) {
appendToDraft(ctx, sessionId, `@${rel}`)
}
}