Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96cc334143 | ||
|
|
9ea9e9b9fa | ||
|
|
2f3944a8bd | ||
|
|
fbd183e93f | ||
|
|
cebc21aef2 | ||
|
|
aa28c1fbc7 | ||
|
|
34e86141bd | ||
|
|
c0441d3a7e | ||
|
|
427266a191 | ||
|
|
a7bcdef21b | ||
|
|
257b8b4eea | ||
|
|
2a7e030b3b |
@@ -16,7 +16,7 @@ body:
|
||||
options:
|
||||
- label: 我已搜索现有 issue,确认没有**完全相同**的条目(只有完全一致才算重复)| I searched existing issues and confirmed there is no **exact duplicate** (only exactly identical issues count as duplicates)
|
||||
required: true
|
||||
- label: 我已确认使用最新版本 dsh-better-sidebar / I confirmed I am on the latest dsh-better-sidebar version
|
||||
- label: 我已确认使用最新版本 dsh-apes-sidebar / I confirmed I am on the latest dsh-apes-sidebar version
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
@@ -58,8 +58,8 @@ body:
|
||||
id: plugin-version
|
||||
attributes:
|
||||
label: 插件版本 / Plugin version
|
||||
description: dsh-better-sidebar 的版本号 | The dsh-better-sidebar version
|
||||
placeholder: "如 0.13.1(`dsh plugin --profile web add dsh-better-sidebar@latest` 安装的版本)"
|
||||
description: dsh-apes-sidebar 的版本号 | The dsh-apes-sidebar version
|
||||
placeholder: "如 0.13.1(`dsh plugin --profile web add dsh-apes-sidebar@latest` 安装的版本)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
# config; the runner has none by default.
|
||||
- name: Configure git identity for tests
|
||||
run: |
|
||||
git config --global user.name "dsh-better-sidebar-ci"
|
||||
git config --global user.name "dsh-apes-sidebar-ci"
|
||||
git config --global user.email "ci@dsh.invalid"
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
# identity and rely on ambient config, which the runner lacks.
|
||||
- name: Configure git identity for tests
|
||||
run: |
|
||||
git config --global user.name "dsh-better-sidebar-ci"
|
||||
git config --global user.name "dsh-apes-sidebar-ci"
|
||||
git config --global user.email "ci@dsh.invalid"
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
run: pnpm test:mount
|
||||
|
||||
# Aggregate double-mount regression: a fixture aggregate bundle mounts
|
||||
# dsh-better-sidebar under its own entry id BEFORE the plugin's bundle
|
||||
# dsh-apes-sidebar under its own entry id BEFORE the plugin's bundle
|
||||
# row; the plugin must back off (no duplicate /sidebar/api, boot OK).
|
||||
# Uses the pinned DSH CLI installed above.
|
||||
- name: Aggregate double-mount regression
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: Release
|
||||
|
||||
# Publishes `dsh-better-sidebar` to npm via npm Trusted Publishing (OIDC) —
|
||||
# Publishes `dsh-apes-sidebar` to npm via npm Trusted Publishing (OIDC) —
|
||||
# no NPM_TOKEN secret required, provenance is attached to the tarball.
|
||||
#
|
||||
# Trigger: a GitHub Release is published (tag vX.Y.Z). The tag MUST match
|
||||
@@ -12,7 +12,7 @@ name: Release
|
||||
# supports the stable DSH line); stable versions publish as `latest`.
|
||||
#
|
||||
# One-time npm-side setup (manual, on npmjs.com):
|
||||
# 1. package `dsh-better-sidebar` -> Settings -> Publishing access
|
||||
# 1. package `dsh-apes-sidebar` -> Settings -> Publishing access
|
||||
# -> Trusted Publishers -> "Add Trusted Publisher".
|
||||
# 2. Provider: GitHub Actions
|
||||
# Organization or user: omdsh-dev
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
# (see tests/smoke.spec.ts); the runner has none by default.
|
||||
- name: Configure git identity for tests
|
||||
run: |
|
||||
git config --global user.name "dsh-better-sidebar-ci"
|
||||
git config --global user.name "dsh-apes-sidebar-ci"
|
||||
git config --global user.email "ci@dsh.invalid"
|
||||
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# dsh-better-sidebar
|
||||
# dsh-apes-sidebar
|
||||
|
||||
> **Fork notice** — This project is a fork of [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) v0.18.0 (commit `9e1a034`), distributed under the MIT License. Original copyright (c) 2026 dsh-external. This fork adds the `apes:*` information-layer tabs (tasks / agents / apps / messages / profile) on top of the upstream sidebar. See `package.json → forkedFrom` for the exact upstream pin.
|
||||
|
||||
<!-- Hero -->
|
||||
<div align="center">
|
||||
@@ -261,7 +263,48 @@ GitHub topic [`dsh-better-sidebar`](https://github.com/topics/dsh-better-sidebar
|
||||
|
||||
## 🆕 最近更新
|
||||
|
||||
**支持的 DSH 版本**:<a href="https://www.npmjs.com/package/@deepseek-ai/dsh?activeTab=versions"><img alt="支持的 DSH 版本(v0.18.0 正式版):0.1.2-rc.1+" src="https://img.shields.io/badge/DSH-0.1.2--rc.1%2B-4d6bfe" /></a> · 完整发布历史见 [Releases](https://github.com/omdsh-dev/DSH-better-sidebar/releases)
|
||||
**支持的 DSH 版本**:<a href="https://www.npmjs.com/package/@deepseek-ai/dsh?activeTab=versions"><img alt="支持的 DSH 版本(v0.18.0 正式版):0.1.5-rc.2+" src="https://img.shields.io/badge/DSH-0.1.5--rc.2%2B-4d6bfe" /></a> · 完整发布历史见 [Releases](https://github.com/omdsh-dev/DSH-better-sidebar/releases)
|
||||
|
||||
### v1.1.0(fork · DSH 2.0.10 / 0.1.5-rc.2 适配 + 精简 + 风格对齐)
|
||||
|
||||
> 📌 **DSH 2.0.10 适配**:跟随 DSH 2.0.10 内发的 `@deepseek-ai/dsh-*@0.1.5-rc.2`,peer + devDeps 全量对齐。
|
||||
|
||||
**🗑 精简 tab(去 `apes:tasks`)**
|
||||
|
||||
- 移除 `apes:tasks` —— 与 DSH 原生侧栏的官方会话树功能重叠,保留 **3 个** `apes:*` 信息层 tab:`apes:agents` / `apes:apps` / `apes:profile`
|
||||
- 同步清理死代码:`ApesTasksView` + `collectTreeJobs`/`orderJobs`/`isJobLive`/`jobDotState` import + apes i18n 死 key(tasks/status/duration)
|
||||
|
||||
**🎨 风格对齐 DSW 设计令牌**
|
||||
|
||||
- apes 视图内联样式的颜色全部改用 DSW alias 令牌(`--dsw-alias-bg-*` / `--dsw-alias-border-*` / `--dsw-alias-label-*` / `--dsw-alias-state-success-*` / `--dsw-alias-interactive-*`),与 DSH 原生侧栏视觉统一;`var(...)` 带字面 fallback 保证非 DSH 环境(单测 harness)仍可渲染
|
||||
- 字号 / 间距 / 圆角保持内联值(DSH 未对插件面板公开 `--ds-*` 几何令牌,其自身 vendor bundle 亦内联)
|
||||
|
||||
**🔧 0.1.5-rc.2 适配修复**
|
||||
|
||||
- primitives npm 发布缺陷(15 个运行时依赖被误列为 devDeps)→ 补进本地 `devDependencies` 供 vitest 内联解析
|
||||
- sidechat seed 校验契约升级:`dsh-session@0.1.5` 的 `assertAssistantSettlementShape` 要求 assistant 消息的 `data` 顶层带 `stream: Array` → 测试 seed helper 对齐
|
||||
- 完整 gate:typecheck ✓ / build ✓ / test 119 files · 1249 passed ✓
|
||||
|
||||
---
|
||||
|
||||
### v1.0.0(fork · apes 信息层)
|
||||
|
||||
> 📌 **fork 独立版本线**:自 upstream `dsh-better-sidebar@v0.18.0`(commit `9e1a034`)fork,新增 `apes:*` 信息层 tab。upstream 历史版本见下方 v0.18.0 段。
|
||||
|
||||
**🪧 新增 4 个 `apes:*` 信息层 tab**(独立模块 `src/client/apes/`,与 upstream builtin tab 解耦)
|
||||
|
||||
- **`apes:tasks` 任务**:接 `ctx.sessions.list` 的 `jobsBySession` + running sessions —— live 任务列表(label / 运行中·完成·失败 / kind / 耗时 + owner 归属)
|
||||
- **`apes:agents` 智能体**:接 `subagentsByParent` 目录(降级 `byId`)—— subagent 拓扑(main → 直接 children 的 activity:running / inactive)
|
||||
- **`apes:apps` 应用**:展示当前工作区 cwd(`scope.cwd` + `byId[current].cwd`;无 DSH host feed,保留说明占位)
|
||||
- **`apes:profile` 画像**:接 `byId[current]` —— 当前会话画像(title / cwd / running / agent 状态)
|
||||
|
||||
**🔌 数据接入**
|
||||
|
||||
- 数据源 `ctx.sessions.list.getSnapshot()` 经 `useSyncExternalStore` 响应式订阅(snapshot 含 `current` / `byId` / `subagentsByParent` / `jobsBySession`)
|
||||
- 复用 upstream pure helper(无 UI / Node 依赖):`subagent-lineage.ts`(`rootAncestor` / `isSideThreadSummary`)+ `subagent-jobs.ts`(`collectTreeJobs` / `orderJobs` / `isJobLive` / `jobDotState`)
|
||||
- UI 独立内联样式,不耦合 builtin CSS module / `StateDot`(保持 apes 模块隔离,cherry-pick upstream 时只碰 `index.tsx` 一处)
|
||||
|
||||
**🌏 i18n**:4 个视图全部走 `t(key)`,`zh` 默认 + `en` fallback,状态 / 耗时 / 空态均有双语词条
|
||||
|
||||
### v0.18.0
|
||||
|
||||
|
||||
+7
-7
@@ -1,12 +1,12 @@
|
||||
# dsh-better-sidebar bundle patch
|
||||
# dsh-apes-sidebar bundle patch
|
||||
#
|
||||
# This file is the `dsh.bundle.patch` layer of the published npm package: when
|
||||
# the plugin is installed through the official CLI —
|
||||
#
|
||||
# dsh plugin --profile <name> add dsh-better-sidebar@<version>
|
||||
# dsh plugin --profile <name> add dsh-apes-sidebar@<version>
|
||||
#
|
||||
# — the command reconciles `dsh.profile.bundles` against installed packages
|
||||
# and, seeing this declaration, appends `dsh-better-sidebar` to the bundle
|
||||
# and, seeing this declaration, appends `dsh-apes-sidebar` to the bundle
|
||||
# stack. The profile boot then merges THIS patch (a single `insert` of the
|
||||
# plugin row) exactly like the manual cordis.patch.yml mount line used
|
||||
# before. No profile file edits needed — one command installs and mounts.
|
||||
@@ -23,7 +23,7 @@
|
||||
#
|
||||
# - insert:
|
||||
# - id: better-sidebar
|
||||
# name: 'dsh-better-sidebar'
|
||||
# name: 'dsh-apes-sidebar'
|
||||
# config:
|
||||
# shell: /bin/zsh
|
||||
# shellArgs:
|
||||
@@ -35,7 +35,7 @@
|
||||
# `web-ui-better-sidebar`). Two mounts register /sidebar/api twice and fail the
|
||||
# whole plugin tree at boot ("duplicate prefix route"). The `!!js` disabled
|
||||
# expression backs THIS row off when another *enabled* entry already mounts
|
||||
# `dsh-better-sidebar`; the aggregate instance then owns the sidebar. The
|
||||
# `dsh-apes-sidebar`; the aggregate instance then owns the sidebar. The
|
||||
# loader evaluates it when this row is processed (entry-list order, only rows
|
||||
# before this one are visible), so the aggregate bundle must precede this one
|
||||
# in `dsh.profile.bundles` — the standard install order, since `dsh plugin add`
|
||||
@@ -45,5 +45,5 @@
|
||||
# fail loudly at the loader as before.
|
||||
- insert:
|
||||
- id: better-sidebar
|
||||
name: 'dsh-better-sidebar'
|
||||
disabled: !!js "[...ctx.loader.entries()].some((e) => e.options.name === 'dsh-better-sidebar' && e.options.id !== 'better-sidebar' && !e.disabled)"
|
||||
name: 'dsh-apes-sidebar'
|
||||
disabled: !!js "[...ctx.loader.entries()].some((e) => e.options.name === 'dsh-apes-sidebar' && e.options.id !== 'better-sidebar' && !e.disabled)"
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "dsh-external/dsh-better-sidebar",
|
||||
"version": "0.18.0",
|
||||
"id": "dsh-external/dsh-apes-sidebar",
|
||||
"version": "1.1.0",
|
||||
"main": "./lib/index.js",
|
||||
"description": "VSCode 风格右侧侧边栏:文件资源管理器 / 编辑器 / 终端 / Git / 浏览器,按会话隔离。暴露服务供其他插件注册侧边栏页面和文件预览器",
|
||||
"engines": {
|
||||
|
||||
+64
-38
@@ -1,12 +1,18 @@
|
||||
{
|
||||
"name": "dsh-better-sidebar",
|
||||
"version": "0.18.0",
|
||||
"description": "DSH web plugin: a VSCode-like right sidebar (explorer / editor / terminal / git / browser), isolated per conversation session. Exposes a service for other plugins to register sidebar tabs and file viewers.",
|
||||
"name": "dsh-apes-sidebar",
|
||||
"version": "1.1.0",
|
||||
"description": "APE fork of dsh-better-sidebar v0.18.0: VSCode-like right sidebar (explorer / editor / terminal / git / browser) + apes:* information-layer tabs (agents / apps / profile). Forked from omdsh-dev/DSH-better-sidebar under MIT.",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"forkedFrom": {
|
||||
"name": "dsh-better-sidebar",
|
||||
"version": "0.18.0",
|
||||
"commit": "9e1a034",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -66,6 +72,7 @@
|
||||
"src",
|
||||
"scripts/install.sh",
|
||||
"scripts/install.ps1",
|
||||
"scripts/switch.sh",
|
||||
"cordis.patch.yml",
|
||||
"README.md",
|
||||
"README_EN.md",
|
||||
@@ -82,24 +89,28 @@
|
||||
"test:mount": "bash scripts/e2e-mount.sh",
|
||||
"test:mount:aggregate": "bash scripts/e2e-aggregate-mount.sh",
|
||||
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
|
||||
"check:consumer-types": "bash scripts/check-consumer-types.sh"
|
||||
"check:consumer-types": "bash scripts/check-consumer-types.sh",
|
||||
"switch": "bash scripts/switch.sh",
|
||||
"switch:status": "bash scripts/switch.sh --status",
|
||||
"switch:aps": "bash scripts/switch.sh aps",
|
||||
"switch:upstream": "bash scripts/switch.sh upstream"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "^4.0.2",
|
||||
"@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-host-webserver": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-invariants": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-subagent": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
@@ -143,26 +154,26 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
|
||||
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-code-runtime": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-invariants": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-llm": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-scope": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session-projection": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-settings": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-subagent": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-tools": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-user-approval": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-util-time": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-agent": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-attachment": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-code-runtime": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-host-webserver": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-invariants": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-llm": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-scope": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session-projection": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-settings": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-subagent": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-system-prompt": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-tools": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-user-approval": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-util-time": "0.1.5-rc.2",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"@playwright/test": "^1.62.1",
|
||||
"@types/node": "^24.0.0",
|
||||
@@ -179,6 +190,21 @@
|
||||
"tsdown": "^0.22.2",
|
||||
"typescript": "^5.6.0",
|
||||
"unrun": "^0.2.39",
|
||||
"vitest": "^4.1.8"
|
||||
"vitest": "^4.1.8",
|
||||
"anser": "^2.3.5",
|
||||
"shiki": "^4.3.1",
|
||||
"@shikijs/langs": "^4.3.1",
|
||||
"katex": "^0.16.47",
|
||||
"mdast-util-from-markdown": "^2.0.3",
|
||||
"mdast-util-gfm": "^3.1.0",
|
||||
"mdast-util-math": "^3.0.0",
|
||||
"micromark-core-commonmark": "^2.0.3",
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"micromark-extension-math": "^3.1.0",
|
||||
"micromark-factory-space": "^2.0.1",
|
||||
"micromark-util-character": "^2.1.1",
|
||||
"micromark-util-classify-character": "^2.0.1",
|
||||
"micromark-util-sanitize-uri": "^2.0.1",
|
||||
"micromark-util-symbol": "^2.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
{
|
||||
"name": "dsh-apes-sidebar",
|
||||
"version": "1.0.0",
|
||||
"description": "APE fork of dsh-better-sidebar v0.18.0: VSCode-like right sidebar (explorer / editor / terminal / git / browser) + apes:* information-layer tabs (tasks / agents / apps / messages / profile). Forked from omdsh-dev/DSH-better-sidebar under MIT.",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"forkedFrom": {
|
||||
"name": "dsh-better-sidebar",
|
||||
"version": "0.18.0",
|
||||
"commit": "9e1a034",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./lib/types/client/index.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./client/service": {
|
||||
"types": "./lib/types/client/service.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./client/api": {
|
||||
"types": "./lib/types/client/service.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"packageManager": "pnpm@11.8.0",
|
||||
"dsh": {
|
||||
"bundle": {
|
||||
"patch": "./cordis.patch.yml"
|
||||
},
|
||||
"client": {
|
||||
"inject": [
|
||||
"@deepseek-ai/dsh-client-locale",
|
||||
"@deepseek-ai/dsh-client-ui-slots",
|
||||
"@deepseek-ai/dsh-client-ui-conversation",
|
||||
"@deepseek-ai/dsh-client-modules"
|
||||
],
|
||||
"platform": "web"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/client-registry.js",
|
||||
"lib/client-terminal.js",
|
||||
"lib/client-editor.js",
|
||||
"lib/client-mermaid.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"src",
|
||||
"scripts/install.sh",
|
||||
"scripts/install.ps1",
|
||||
"scripts/switch.sh",
|
||||
"cordis.patch.yml",
|
||||
"README.md",
|
||||
"README_EN.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsdown",
|
||||
"prepublishOnly": "pnpm build",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"bundle": "tsdown",
|
||||
"watch": "tsdown --watch",
|
||||
"prepare": "tsdown",
|
||||
"test": "vitest run",
|
||||
"test:mount": "bash scripts/e2e-mount.sh",
|
||||
"test:mount:aggregate": "bash scripts/e2e-aggregate-mount.sh",
|
||||
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
|
||||
"check:consumer-types": "bash scripts/check-consumer-types.sh",
|
||||
"switch": "bash scripts/switch.sh",
|
||||
"switch:status": "bash scripts/switch.sh --status",
|
||||
"switch:aps": "bash scripts/switch.sh aps",
|
||||
"switch:upstream": "bash scripts/switch.sh upstream"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "^4.0.2",
|
||||
"@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-host-webserver": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-invariants": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@huanlin/dsh-plugin-better-locale": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.10.4",
|
||||
"@codemirror/lang-cpp": "^6.0.3",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-go": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.12",
|
||||
"@codemirror/lang-java": "^6.0.2",
|
||||
"@codemirror/lang-javascript": "^6.2.5",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
"@codemirror/lang-markdown": "^6.5.2",
|
||||
"@codemirror/lang-php": "^6.0.2",
|
||||
"@codemirror/lang-python": "^6.2.1",
|
||||
"@codemirror/lang-rust": "^6.0.2",
|
||||
"@codemirror/lang-sql": "^6.10.0",
|
||||
"@codemirror/lang-vue": "^0.1.3",
|
||||
"@codemirror/lang-xml": "^6.1.0",
|
||||
"@codemirror/lang-yaml": "^6.1.3",
|
||||
"@codemirror/language": "^6.12.4",
|
||||
"@codemirror/legacy-modes": "^6.5.3",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.7.1",
|
||||
"@codemirror/view": "^6.43.8",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"clsx": "^2.1.1",
|
||||
"dompurify": "^3.4.14",
|
||||
"mermaid": "^11.16.1",
|
||||
"node-pty": "^1.1.0",
|
||||
"react-icons": "5.7.0",
|
||||
"rxjs": "^7.8.2",
|
||||
"schemastery": "^3.18.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
|
||||
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-attachment": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-code-runtime": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-invariants": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-llm": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-scope": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-session-projection": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-settings": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-subagent": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-tools": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-user-approval": "0.1.2-rc.1",
|
||||
"@deepseek-ai/dsh-util-time": "0.1.2-rc.1",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"@playwright/test": "^1.62.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "~18.3.1",
|
||||
"@types/react-dom": "~18.3.1",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"cordis": "^4.0.0-rc.8",
|
||||
"jsdom": "^29.1.1",
|
||||
"lightningcss": "^1.32.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tsdown": "^0.22.2",
|
||||
"typescript": "^5.6.0",
|
||||
"unrun": "^0.2.39",
|
||||
"vitest": "^4.1.8"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
{
|
||||
"name": "dsh-apes-sidebar",
|
||||
"version": "1.0.0",
|
||||
"description": "APE fork of dsh-better-sidebar v0.18.0: VSCode-like right sidebar (explorer / editor / terminal / git / browser) + apes:* information-layer tabs (tasks / agents / apps / messages / profile). Forked from omdsh-dev/DSH-better-sidebar under MIT.",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"forkedFrom": {
|
||||
"name": "dsh-better-sidebar",
|
||||
"version": "0.18.0",
|
||||
"commit": "9e1a034",
|
||||
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./lib/types/client/index.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./client/service": {
|
||||
"types": "./lib/types/client/service.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./client/api": {
|
||||
"types": "./lib/types/client/service.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"packageManager": "pnpm@11.8.0",
|
||||
"dsh": {
|
||||
"bundle": {
|
||||
"patch": "./cordis.patch.yml"
|
||||
},
|
||||
"client": {
|
||||
"inject": [
|
||||
"@deepseek-ai/dsh-client-locale",
|
||||
"@deepseek-ai/dsh-client-ui-slots",
|
||||
"@deepseek-ai/dsh-client-ui-conversation",
|
||||
"@deepseek-ai/dsh-client-modules"
|
||||
],
|
||||
"platform": "web"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/client-registry.js",
|
||||
"lib/client-terminal.js",
|
||||
"lib/client-editor.js",
|
||||
"lib/client-mermaid.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"src",
|
||||
"scripts/install.sh",
|
||||
"scripts/install.ps1",
|
||||
"scripts/switch.sh",
|
||||
"cordis.patch.yml",
|
||||
"README.md",
|
||||
"README_EN.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsdown",
|
||||
"prepublishOnly": "pnpm build",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"bundle": "tsdown",
|
||||
"watch": "tsdown --watch",
|
||||
"prepare": "tsdown",
|
||||
"test": "vitest run",
|
||||
"test:mount": "bash scripts/e2e-mount.sh",
|
||||
"test:mount:aggregate": "bash scripts/e2e-aggregate-mount.sh",
|
||||
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
|
||||
"check:consumer-types": "bash scripts/check-consumer-types.sh",
|
||||
"switch": "bash scripts/switch.sh",
|
||||
"switch:status": "bash scripts/switch.sh --status",
|
||||
"switch:aps": "bash scripts/switch.sh aps",
|
||||
"switch:upstream": "bash scripts/switch.sh upstream"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "^4.0.2",
|
||||
"@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-subagent": "^0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@huanlin/dsh-plugin-better-locale": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.10.4",
|
||||
"@codemirror/lang-cpp": "^6.0.3",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-go": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.12",
|
||||
"@codemirror/lang-java": "^6.0.2",
|
||||
"@codemirror/lang-javascript": "^6.2.5",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
"@codemirror/lang-markdown": "^6.5.2",
|
||||
"@codemirror/lang-php": "^6.0.2",
|
||||
"@codemirror/lang-python": "^6.2.1",
|
||||
"@codemirror/lang-rust": "^6.0.2",
|
||||
"@codemirror/lang-sql": "^6.10.0",
|
||||
"@codemirror/lang-vue": "^0.1.3",
|
||||
"@codemirror/lang-xml": "^6.1.0",
|
||||
"@codemirror/lang-yaml": "^6.1.3",
|
||||
"@codemirror/language": "^6.12.4",
|
||||
"@codemirror/legacy-modes": "^6.5.3",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.7.1",
|
||||
"@codemirror/view": "^6.43.8",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"clsx": "^2.1.1",
|
||||
"dompurify": "^3.4.14",
|
||||
"mermaid": "^11.16.1",
|
||||
"node-pty": "^1.1.0",
|
||||
"react-icons": "5.7.0",
|
||||
"rxjs": "^7.8.2",
|
||||
"schemastery": "^3.18.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
|
||||
"@deepseek-ai/dsh-agent": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-attachment": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-code-runtime": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-host-webserver": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-invariants": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-llm": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-scope": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-session-projection": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-settings": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-subagent": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-system-prompt": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-tools": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-user-approval": "0.1.5-rc.2",
|
||||
"@deepseek-ai/dsh-util-time": "0.1.5-rc.2",
|
||||
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
||||
"@playwright/test": "^1.62.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "~18.3.1",
|
||||
"@types/react-dom": "~18.3.1",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"cordis": "^4.0.0-rc.8",
|
||||
"jsdom": "^29.1.1",
|
||||
"lightningcss": "^1.32.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tsdown": "^0.22.2",
|
||||
"typescript": "^5.6.0",
|
||||
"unrun": "^0.2.39",
|
||||
"vitest": "^4.1.8"
|
||||
}
|
||||
}
|
||||
Generated
+378
-563
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Consumer-facing type surface check: build a tiny standalone consumer that
|
||||
# imports `dsh-better-sidebar/client/service` WITHOUT @types/node and with
|
||||
# imports `dsh-apes-sidebar/client/service` WITHOUT @types/node and with
|
||||
# skipLibCheck: false, then type-check it with the repo's tsc.
|
||||
#
|
||||
# This is the exact scenario the v0.12.0 API work cares about: the shipped
|
||||
@@ -35,14 +35,14 @@ mkdir -p "$WORK/node_modules"
|
||||
# (GetFinalPathNameByHandle on Windows) expands junctions, which bash-level
|
||||
# resolution may leave untouched; node is guaranteed here (tsc runs below).
|
||||
resolve_dir() { node -e 'process.stdout.write(require("node:fs").realpathSync.native(process.argv[1]))' "$1"; }
|
||||
ln -s "$(resolve_dir "$(pwd)")" "$WORK/node_modules/dsh-better-sidebar"
|
||||
ln -s "$(resolve_dir "$(pwd)")" "$WORK/node_modules/dsh-apes-sidebar"
|
||||
# The vendored cordis base (and, through its realpath, cosmokit / standard-schema)
|
||||
# must resolve so the consumer can type `Context` against the DSH runtime scope.
|
||||
mkdir -p "$WORK/node_modules/@deepseek-ai"
|
||||
ln -s "$(resolve_dir "$(pwd)/node_modules/@deepseek-ai/cordis")" "$WORK/node_modules/@deepseek-ai/cordis"
|
||||
# Loud guard: both links must resolve to a package root, or tsc below would
|
||||
# report misleading module-resolution errors.
|
||||
for pkg_json in "$WORK/node_modules/dsh-better-sidebar/package.json" "$WORK/node_modules/@deepseek-ai/cordis/package.json"; do
|
||||
for pkg_json in "$WORK/node_modules/dsh-apes-sidebar/package.json" "$WORK/node_modules/@deepseek-ai/cordis/package.json"; do
|
||||
if [ ! -f "$pkg_json" ]; then
|
||||
echo "[check-consumer-types] FAIL: $pkg_json does not resolve (broken link). Link layer:" >&2
|
||||
ls -la "$WORK/node_modules" "$WORK/node_modules/@deepseek-ai" >&2 || true
|
||||
@@ -51,14 +51,14 @@ for pkg_json in "$WORK/node_modules/dsh-better-sidebar/package.json" "$WORK/node
|
||||
done
|
||||
|
||||
cat > "$WORK/check.ts" <<'EOF'
|
||||
import { SIDEBAR_FEATURES, SIDEBAR_SERVICE_VERSION } from 'dsh-better-sidebar/client/service'
|
||||
import type {} from 'dsh-better-sidebar/client/service'
|
||||
import { SIDEBAR_FEATURES, SIDEBAR_SERVICE_VERSION } from 'dsh-apes-sidebar/client/service'
|
||||
import type {} from 'dsh-apes-sidebar/client/service'
|
||||
import type {
|
||||
BetterSidebarService, FileViewerDescriptor, OpenTabSeed, SidebarSettingsRenderProps,
|
||||
TabComponentProps, TabDescriptor,
|
||||
} from 'dsh-better-sidebar/client/service'
|
||||
import type { SessionScope, SidebarSnapshot, SidebarState, SidebarStore, SidebarTab } from 'dsh-better-sidebar/client/service'
|
||||
import type { SidebarPrefs } from 'dsh-better-sidebar/client/service'
|
||||
} from 'dsh-apes-sidebar/client/service'
|
||||
import type { SessionScope, SidebarSnapshot, SidebarState, SidebarStore, SidebarTab } from 'dsh-apes-sidebar/client/service'
|
||||
import type { SidebarPrefs } from 'dsh-apes-sidebar/client/service'
|
||||
// The vendored-cordis path: `Context` from '@deepseek-ai/cordis' plus the
|
||||
// side-effect type import above must expose `ctx.betterSidebar` — the consumer
|
||||
// never needs to import this package's own Context type.
|
||||
@@ -126,14 +126,14 @@ set -e
|
||||
# Fail only on errors that mention OUR package / declarations / the fixture.
|
||||
# Upstream noise (vendored cordis / cosmokit declaration warnings under the
|
||||
# repo's pinned TS lib) lives anywhere under node_modules and is filtered.
|
||||
if grep -E "dsh-better-sidebar|lib/types|check\.ts" "$WORK/strict.log" | grep -vE "node_modules/[^ ]*(cordis|cosmokit)"; then
|
||||
echo "[check-consumer-types] FAIL: errors in the dsh-better-sidebar declaration surface:" >&2
|
||||
grep -E "dsh-better-sidebar|lib/types|check\.ts" "$WORK/strict.log" >&2
|
||||
if grep -E "dsh-apes-sidebar|lib/types|check\.ts" "$WORK/strict.log" | grep -vE "node_modules/[^ ]*(cordis|cosmokit)"; then
|
||||
echo "[check-consumer-types] FAIL: errors in the dsh-apes-sidebar declaration surface:" >&2
|
||||
grep -E "dsh-apes-sidebar|lib/types|check\.ts" "$WORK/strict.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$STATUS" -ne 0 ]; then
|
||||
echo "[check-consumer-types] pass 2 note: strict mode only reports upstream declaration noise:"
|
||||
grep -v "dsh-better-sidebar\|lib/types\|check\.ts" "$WORK/strict.log" | head -5 || true
|
||||
grep -v "dsh-apes-sidebar\|lib/types\|check\.ts" "$WORK/strict.log" | head -5 || true
|
||||
fi
|
||||
echo "[check-consumer-types] OK: the client/service declaration surface is node-free and self-contained."
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# dsh-better-sidebar 聚合双挂载冒烟(CI + 本地):
|
||||
# dsh-apes-sidebar 聚合双挂载冒烟(CI + 本地):
|
||||
#
|
||||
# 场景:一个聚合 bundle(tests/fixtures/aggregate-better-sidebar)先以独立
|
||||
# 条目 id 挂载 dsh-better-sidebar,插件自身的 bundle patch 后到 —— 旧行为
|
||||
# 条目 id 挂载 dsh-apes-sidebar,插件自身的 bundle patch 后到 —— 旧行为
|
||||
# 两个实例都注册 /sidebar/api,整个插件树启动失败(duplicate prefix
|
||||
# route);新行为插件行检测到已有启用中的同包名挂载后自动 disabled,由
|
||||
# 聚合行接管 sidebar。
|
||||
@@ -22,7 +22,7 @@
|
||||
# 环境变量(均可省略):
|
||||
# DSH_CMD dsh 命令;缺省 PATH 上的 `dsh`,回退 npx 拉官方包
|
||||
# (同 e2e-mount.sh)
|
||||
# TARBALL 插件 tarball;缺省仓库根 dsh-better-sidebar-*.tgz(须已 pack)
|
||||
# TARBALL 插件 tarball;缺省仓库根 dsh-apes-sidebar-*.tgz(须已 pack)
|
||||
# PORT 固定端口(默认 0 = OS 分配,从日志解析 URL)
|
||||
# DSH_HOME_BASE scratch 根目录(默认系统临时目录)。脚本始终在其下新建
|
||||
# 本调用拥有的独立子目录,只写入/删除该子目录;调用方提供
|
||||
|
||||
@@ -57,9 +57,9 @@ e2e_resolve_dsh_cmd() {
|
||||
# 过期产物上。未找到候选时返回非零,由调用方按各自文案 die。
|
||||
e2e_resolve_tarball() {
|
||||
if [ -z "${TARBALL:-}" ]; then
|
||||
TARBALL="$(ls -t "$ROOT"/dsh-better-sidebar-*.tgz 2>/dev/null | head -1 || true)"
|
||||
TARBALL="$(ls -t "$ROOT"/dsh-apes-sidebar-*.tgz 2>/dev/null | head -1 || true)"
|
||||
local count
|
||||
count="$(ls "$ROOT"/dsh-better-sidebar-*.tgz 2>/dev/null | wc -l | tr -d ' ' || true)"
|
||||
count="$(ls "$ROOT"/dsh-apes-sidebar-*.tgz 2>/dev/null | wc -l | tr -d ' ' || true)"
|
||||
[ "$count" -le 1 ] || warn "发现 $count 个 tarball,按 mtime 选用最新:$(basename "$TARBALL")(建议清理其余)"
|
||||
fi
|
||||
[ -n "$TARBALL" ] && [ -f "$TARBALL" ]
|
||||
@@ -134,7 +134,7 @@ allowBuilds:
|
||||
protobufjs: true
|
||||
|
||||
minimumReleaseAgeExclude:
|
||||
- dsh-better-sidebar
|
||||
- dsh-apes-sidebar
|
||||
- '@deepseek-ai/*'
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# dsh-better-sidebar 挂载冒烟编排(CI + 本地):
|
||||
# dsh-apes-sidebar 挂载冒烟编排(CI + 本地):
|
||||
#
|
||||
# 1. 用官方 CLI 把 npm 打包产物(tarball)真实挂载进一个全新 scratch
|
||||
# profile(`dsh plugin --profile web add file:<tarball>`,触发
|
||||
@@ -14,7 +14,7 @@
|
||||
#
|
||||
# 环境变量(均可省略):
|
||||
# DSH_CMD dsh 命令;缺省 PATH 上的 `dsh`,回退 npx 拉官方包
|
||||
# TARBALL 插件 tarball;缺省仓库根 dsh-better-sidebar-*.tgz(须已 pack)
|
||||
# TARBALL 插件 tarball;缺省仓库根 dsh-apes-sidebar-*.tgz(须已 pack)
|
||||
# PORT 固定端口(默认 0 = OS 分配,从日志解析 URL)
|
||||
# DSH_HOME_BASE 覆盖 scratch 根目录(默认系统临时目录)。脚本始终在其下
|
||||
# 新建本调用拥有的独立子目录,只写入/删除该子目录;调用方
|
||||
@@ -44,7 +44,7 @@ e2e_require_cmd pnpm "dsh plugin 转发给 pnpm"
|
||||
|
||||
e2e_resolve_dsh_cmd
|
||||
|
||||
e2e_resolve_tarball || die "找不到 tarball(TARBALL 或 \$ROOT/dsh-better-sidebar-*.tgz)——先运行 pnpm build && pnpm pack"
|
||||
e2e_resolve_tarball || die "找不到 tarball(TARBALL 或 \$ROOT/dsh-apes-sidebar-*.tgz)——先运行 pnpm build && pnpm pack"
|
||||
TARBALL="$(cd "$(dirname "$TARBALL")" && pwd)/$(basename "$TARBALL")"
|
||||
say "tarball: $TARBALL"
|
||||
|
||||
@@ -72,18 +72,18 @@ e2e_write_profile "$PROFILE_DIR"
|
||||
say "执行 dsh plugin --profile web add file:$TARBALL ..."
|
||||
$DSH_CMD plugin --profile web add "file:$TARBALL"
|
||||
|
||||
# 步骤 3:校验挂载生效(dsh.profile.bundles 含 dsh-better-sidebar)
|
||||
# 步骤 3:校验挂载生效(dsh.profile.bundles 含 dsh-apes-sidebar)
|
||||
if ! node -e '
|
||||
const fs = require("fs");
|
||||
const p = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
||||
const bundles = p.dsh?.profile?.bundles ?? [];
|
||||
process.exit(bundles.includes("dsh-better-sidebar") ? 0 : 1);
|
||||
process.exit(bundles.includes("dsh-apes-sidebar") ? 0 : 1);
|
||||
' "$PROFILE_DIR/package.json"; then
|
||||
warn "dsh-better-sidebar 未出现在 dsh.profile.bundles 中——挂载未注册"
|
||||
warn "dsh-apes-sidebar 未出现在 dsh.profile.bundles 中——挂载未注册"
|
||||
cat "$PROFILE_DIR/package.json"
|
||||
exit 1
|
||||
fi
|
||||
say "挂载已注册:dsh.profile.bundles 包含 dsh-better-sidebar"
|
||||
say "挂载已注册:dsh.profile.bundles 包含 dsh-apes-sidebar"
|
||||
|
||||
# 步骤 4:启动 dsh web(--port 0 = OS 分配,避免端口冲突;keyless 可起)
|
||||
say "启动 dsh web(port=${PORT})..."
|
||||
|
||||
+10
-10
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# dsh-better-sidebar 一键安装脚本(官方 CLI 方式,macOS / Linux / Windows Git Bash)
|
||||
# dsh-apes-sidebar 一键安装脚本(官方 CLI 方式,macOS / Linux / Windows Git Bash)
|
||||
#
|
||||
# 通过 DSH 官方插件命令安装 npm 包并自动挂载:
|
||||
# dsh plugin --profile web add dsh-better-sidebar@<version>
|
||||
# dsh plugin --profile web add dsh-apes-sidebar@<version>
|
||||
#
|
||||
# 包内声明了 dsh.bundle.patch(cordis.patch.yml):CLI 的 bundle 协调会把它
|
||||
# 自动加进 profile 的 dsh.profile.bundles,下次启动即挂载——无需手动写
|
||||
@@ -38,8 +38,8 @@
|
||||
# minimumReleaseAgeExclude(幂等),放行本插件,避免"重跑一次才成功"。
|
||||
# - 老版本(<0.10.2)用手动挂载行,bundle 通道激活后需移除,否则双挂载
|
||||
# (Node 半挂两次、页面两个侧边栏)。脚本会幂等移除 better-sidebar 挂载行。
|
||||
# - 回滚:dsh plugin --profile web remove dsh-better-sidebar,或把 profile 依赖
|
||||
# 改回 "dsh-better-sidebar": "link:<路径>" 再 pnpm install。
|
||||
# - 回滚:dsh plugin --profile web remove dsh-apes-sidebar,或把 profile 依赖
|
||||
# 改回 "dsh-apes-sidebar": "link:<路径>" 再 pnpm install。
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
@@ -47,7 +47,7 @@ set -euo pipefail
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then
|
||||
cat <<'EOF'
|
||||
dsh-better-sidebar 一键安装 / 依赖修复脚本
|
||||
dsh-apes-sidebar 一键安装 / 依赖修复脚本
|
||||
|
||||
用法:
|
||||
bash scripts/install.sh [版本] [--restart] [--dry-run] [--profile <名>]
|
||||
@@ -67,7 +67,7 @@ done
|
||||
|
||||
DSH_HOME="${DSH_HOME:-${HOME:-${USERPROFILE:-}}/.dsh}"
|
||||
REGISTRY="${REGISTRY:-https://registry.npmjs.org}"
|
||||
PKG="dsh-better-sidebar"
|
||||
PKG="dsh-apes-sidebar"
|
||||
DSH_CMD="${DSH_CMD:-dsh}"
|
||||
|
||||
RESTART=false
|
||||
@@ -118,11 +118,11 @@ if (!/^\s*allowBuilds:\s*$/m.test(t)) {
|
||||
}
|
||||
}
|
||||
// minimumReleaseAgeExclude:放行本插件(版本无关),避免 <24h 新版本被拒
|
||||
if (!/^\s*-\s+dsh-better-sidebar\s*$/m.test(t)) {
|
||||
if (!/^\s*-\s+dsh-apes-sidebar\s*$/m.test(t)) {
|
||||
if (/^\s*minimumReleaseAgeExclude:\s*$/m.test(t)) {
|
||||
t = t.replace(/^(\s*minimumReleaseAgeExclude:\s*)$/m, "$1\n - dsh-better-sidebar");
|
||||
t = t.replace(/^(\s*minimumReleaseAgeExclude:\s*)$/m, "$1\n - dsh-apes-sidebar");
|
||||
} else {
|
||||
t += "\nminimumReleaseAgeExclude:\n - dsh-better-sidebar\n";
|
||||
t += "\nminimumReleaseAgeExclude:\n - dsh-apes-sidebar\n";
|
||||
}
|
||||
}
|
||||
if (t !== before) fs.writeFileSync(p, t);
|
||||
@@ -224,7 +224,7 @@ if ! node -e '
|
||||
const bundles = p.dsh?.profile?.bundles ?? [];
|
||||
process.exit(bundles.includes(process.argv[2]) ? 0 : 1);
|
||||
' "$PROFILE_DIR/package.json" "$PKG"; then
|
||||
warn "dsh-better-sidebar 未出现在 dsh.profile.bundles 中——挂载未注册。"
|
||||
warn "dsh-apes-sidebar 未出现在 dsh.profile.bundles 中——挂载未注册。"
|
||||
warn "若上面的 pnpm 输出提示 ignored build scripts,请确认 $WS_YML 的 allowBuilds 后重跑本脚本。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* pnpm build
|
||||
* node scripts/package-registry.mjs
|
||||
* dsh registry install ./registry
|
||||
* dsh registry enable dsh-external/dsh-better-sidebar
|
||||
* dsh registry enable dsh-external/dsh-apes-sidebar
|
||||
*
|
||||
* The registry install copies the whole source directory (`cp -r`), so
|
||||
* installing the repo root would drag in `node_modules/` (machine-local
|
||||
@@ -54,4 +54,4 @@ for (const file of files) {
|
||||
cpSync(source, target)
|
||||
}
|
||||
console.log(`registry/ assembled (${files.length} files)`)
|
||||
console.log('next: dsh registry install ./registry && dsh registry enable dsh-external/dsh-better-sidebar')
|
||||
console.log('next: dsh registry install ./registry && dsh registry enable dsh-external/dsh-apes-sidebar')
|
||||
|
||||
Executable
+294
@@ -0,0 +1,294 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# dsh-apes-sidebar 两线切换脚本(apes fork 线 ↔ upstream better-sidebar 线)
|
||||
#
|
||||
# 同一个 DSH profile 内**二选一**切换侧边栏插件——双装不可行(两条线都注册
|
||||
# 进 `ctx.betterSidebar`,cordis entry id 冲突,第二个被丢弃)。切换 =
|
||||
# 换 profile 依赖 + 换 dsh.profile.bundles + pnpm install + 提示重启。
|
||||
#
|
||||
# aps 本 fork 线(dsh-apes-sidebar,含 4 个 apes:* 信息层 tab)
|
||||
# 依赖:dsh-apes-sidebar: <file: 本地路径>(本地开发)或
|
||||
# dsh-apes-sidebar@<版本>(npm,发布后)
|
||||
# upstream upstream 线(dsh-better-sidebar,官方 8 tab + 生态)
|
||||
# 依赖:dsh-better-sidebar@<版本>(registry,默认 latest)
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/switch.sh aps # 切到本 fork 线(本地 file: 安装)
|
||||
# bash scripts/switch.sh upstream # 切到 upstream 线(registry 安装)
|
||||
# bash scripts/switch.sh upstream 0.18.0 # 指定 upstream 版本
|
||||
# bash scripts/switch.sh --status # 只看当前线,不改任何东西
|
||||
#
|
||||
# 通用 flag(两线均适用):
|
||||
# --profile <名> 目标 profile(缺省 desktop)
|
||||
# --dry-run 只打印将执行的操作,不写任何文件
|
||||
# -h/--help 打印本帮助
|
||||
#
|
||||
# 环境(均可省略,脚本自动探测):
|
||||
# DSH_HOME 默认 ~/.dsh
|
||||
# REGISTRY 默认 https://registry.npmjs.org
|
||||
# DSH_CMD 默认 PATH 上的 dsh,缺省 npx -y --package @deepseek-ai/dsh
|
||||
# APS_SRC aps 线本地源码路径(缺省 = 本仓库根,即 file: 指向自己)
|
||||
#
|
||||
# 机制(幂等,可重复跑):
|
||||
# 1. 探测当前线(依赖里哪个包在)
|
||||
# 2. 与目标线相同 → 提示后直接退出(不重装)
|
||||
# 3. 移除另一线的依赖 + 从 bundles 摘除另一线的 bundle
|
||||
# 4. 写入目标线依赖 + 确保 workspace 放行 node-pty/protobufjs 构建
|
||||
# 5. cd profile && pnpm install(reconcileProfilePnpmWorkspace 会重建
|
||||
# node_modules——这是预期行为,两线不共存)
|
||||
# 6. 确保 bundles 含目标线包名(bundle 通道挂载生效的判据)
|
||||
# 7. 幂等移除 cordis.patch.yml 里对手线的手动挂载行(避免双挂载)
|
||||
# 8. 提示重启 DSH
|
||||
#
|
||||
# 回滚:跑 `bash scripts/switch.sh <另一线>` 即可切回去。
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then
|
||||
cat <<'EOF'
|
||||
dsh-apes-sidebar 两线切换(同一 profile 内二选一)
|
||||
|
||||
用法:
|
||||
bash scripts/switch.sh <aps|upstream> [版本]
|
||||
bash scripts/switch.sh --status
|
||||
|
||||
aps 切到本 fork 线(dsh-apes-sidebar,4 个 apes:* tab)
|
||||
upstream 切到 upstream 线(dsh-better-sidebar,官方)
|
||||
<版本> 仅对 upstream 生效(缺省 latest)
|
||||
--status 只看当前线,不改动
|
||||
--profile 目标 profile(缺省 desktop)
|
||||
--dry-run 只打印操作,不写文件
|
||||
-h/--help 本帮助
|
||||
|
||||
环境变量:DSH_HOME、REGISTRY、DSH_CMD、APS_SRC(aps 本地源码路径)
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
DSH_HOME="${DSH_HOME:-${HOME:-${USERPROFILE:-}}/.dsh}"
|
||||
REGISTRY="${REGISTRY:-https://registry.npmjs.org}"
|
||||
DSH_CMD="${DSH_CMD:-dsh}"
|
||||
# aps 线本地源码:缺省 = 本仓库根(脚本在 scripts/ 下,根 = 上一级)
|
||||
APS_SRC="${APS_SRC:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||
|
||||
APS_PKG="dsh-apes-sidebar"
|
||||
UP_PKG="dsh-better-sidebar"
|
||||
|
||||
DRY_RUN=false
|
||||
STATUS_ONLY=false
|
||||
TARGET=""
|
||||
UP_VERSION=""
|
||||
PROFILE_NAME="desktop"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--status) STATUS_ONLY=true ;;
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--profile)
|
||||
if [ $# -lt 2 ]; then echo "--profile 需要一个 profile 名(如 desktop)" >&2; exit 2; fi
|
||||
PROFILE_NAME="$2"; shift ;;
|
||||
aps|upstream) TARGET="$1" ;;
|
||||
-h|--help) : ;;
|
||||
-*) echo "未知参数: ${1}(用 -h 查看用法)" >&2; exit 2 ;;
|
||||
*) UP_VERSION="$1" ;; # 版本参数(仅 upstream 用)
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
PROFILE_DIR="$DSH_HOME/profiles/$PROFILE_NAME"
|
||||
PKG_JSON="$PROFILE_DIR/package.json"
|
||||
WS_YML="$PROFILE_DIR/pnpm-workspace.yaml"
|
||||
PATCH_YML="$PROFILE_DIR/cordis.patch.yml"
|
||||
|
||||
say() { printf '\033[32m[switch]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[33m[warn]\033[0m %s\n' "$*" >&2; }
|
||||
die() { printf '\033[31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
command -v node >/dev/null 2>&1 || die "未找到 node(DSH 运行需要 Node.js ≥ 20)。"
|
||||
[ -d "$PROFILE_DIR" ] || die "找不到 profile 目录:${PROFILE_DIR}(请先初始化 ${PROFILE_NAME} profile)"
|
||||
[ -f "$PKG_JSON" ] || die "找不到 ${PKG_JSON}(profile 未初始化)"
|
||||
|
||||
# ── 探测当前线(依赖里哪个包在)─────────────────────────────────────────
|
||||
current_line() {
|
||||
node -e '
|
||||
const p = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||
const deps = p.dependencies || {};
|
||||
if (deps["dsh-apes-sidebar"]) console.log("aps");
|
||||
else if (deps["dsh-better-sidebar"]) console.log("upstream");
|
||||
else console.log("none");
|
||||
' "$PKG_JSON"
|
||||
}
|
||||
|
||||
if [ "$STATUS_ONLY" = true ]; then
|
||||
CUR="$(current_line)"
|
||||
say "profile: ${PROFILE_NAME} (${PROFILE_DIR})"
|
||||
case "$CUR" in
|
||||
aps) say "当前线:aps(${APS_PKG})" ;;
|
||||
upstream) say "当前线:upstream(${UP_PKG})" ;;
|
||||
none) say "当前线:无(两条线都未装)" ;;
|
||||
esac
|
||||
# 附带显示 bundles 里的 sidebar 条目
|
||||
node -e '
|
||||
const p = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||
const b = (p.dsh && p.dsh.profile && p.dsh.profile.bundles) || [];
|
||||
const side = b.filter(x => /sidebar/.test(x));
|
||||
console.log("bundles 里的 sidebar 条目: " + (side.length ? side.join(", ") : "(无)"));
|
||||
' "$PKG_JSON"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ -n "$TARGET" ] || die "缺少目标线(aps | upstream)。用 --status 查看当前线。"
|
||||
|
||||
CUR="$(current_line)"
|
||||
case "$TARGET" in
|
||||
aps) T_PKG="$APS_PKG"; T_DEP="file:${APS_SRC}" ;;
|
||||
upstream)
|
||||
T_PKG="$UP_PKG"
|
||||
# pnpm 从依赖 key 取包名,值只给版本 spec(不含包名,否则双 @)
|
||||
case "${UP_VERSION:-latest}" in
|
||||
latest) T_DEP="latest" ;;
|
||||
*) T_DEP="$UP_VERSION" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
[ "$CUR" = "$TARGET" ] && {
|
||||
say "当前已是 ${TARGET} 线(${T_PKG}),无需切换。"
|
||||
say "如需强制重装:先跑 --status 确认,再手动移除依赖后重跑。"
|
||||
exit 0
|
||||
}
|
||||
|
||||
OTHER_PKG=""
|
||||
case "$TARGET" in
|
||||
aps) OTHER_PKG="$UP_PKG" ;;
|
||||
upstream) OTHER_PKG="$APS_PKG" ;;
|
||||
esac
|
||||
|
||||
say "切换:${CUR} → ${TARGET}(profile: ${PROFILE_NAME})"
|
||||
say "目标依赖:${T_DEP}"
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
say "[dry-run] 步骤 1:移除 ${OTHER_PKG:-(无)} 依赖 + 从 bundles 摘除 ${OTHER_PKG:-(无)}"
|
||||
say "[dry-run] 步骤 2:写入 ${T_PKG} 依赖(${T_DEP})"
|
||||
say "[dry-run] 步骤 3:确保 ${WS_YML} 放行 node-pty/protobufjs 构建"
|
||||
say "[dry-run] 步骤 4:cd ${PROFILE_DIR} && pnpm install(重建 node_modules)"
|
||||
say "[dry-run] 步骤 5:确保 bundles 含 ${T_PKG}"
|
||||
say "[dry-run] 步骤 6:幂等移除 ${PATCH_YML} 里 ${OTHER_PKG:-对手线} 的手动挂载行"
|
||||
say "[dry-run] 步骤 7:提示重启 DSH"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── 步骤 1+2+5 合并:一次 node 调用完成依赖 + bundles 的对称改写 ─────────
|
||||
# 移除对手线依赖 + bundle,写入目标线依赖 + 确保目标 bundle 在列。幂等。
|
||||
node -e '
|
||||
const fs = require("fs");
|
||||
const p = process.argv[1];
|
||||
const keep = process.argv[2]; // 目标包名
|
||||
const depSpec = process.argv[3]; // 目标依赖 spec(file:... 或 pkg@ver)
|
||||
const remove = process.argv[4]; // 对手包名(可能为空串)
|
||||
const t = JSON.parse(fs.readFileSync(p, "utf8"));
|
||||
t.dependencies = t.dependencies || {};
|
||||
// 移除对手线依赖
|
||||
if (remove) { const had = t.dependencies[remove]; delete t.dependencies[remove]; if (had) console.log("removed dep: " + remove + "=" + had); }
|
||||
// 写入目标线依赖
|
||||
t.dependencies[keep] = depSpec;
|
||||
// bundles:摘除对手线,确保目标线在列
|
||||
const prof = (t.dsh && t.dsh.profile) || {};
|
||||
const b = prof.bundles || [];
|
||||
const nb = b.filter(x => x !== remove);
|
||||
if (!nb.includes(keep)) nb.push(keep);
|
||||
t.dsh = t.dsh || {}; t.dsh.profile = prof; prof.bundles = nb;
|
||||
fs.writeFileSync(p, JSON.stringify(t, null, 2) + "\n");
|
||||
console.log("deps now: " + JSON.stringify(t.dependencies));
|
||||
console.log("bundles now: " + nb.join(", "));
|
||||
' "$PKG_JSON" "$T_PKG" "$T_DEP" "$OTHER_PKG"
|
||||
say "依赖 + bundles 已改写"
|
||||
|
||||
# ── 步骤 3:确保 workspace 放行 node-pty/protobufjs 构建(幂等)─────────
|
||||
if [ -f "$WS_YML" ]; then
|
||||
WS_RESULT="$(node -e '
|
||||
const fs = require("fs");
|
||||
const p = process.argv[1];
|
||||
let t = fs.readFileSync(p, "utf8");
|
||||
const before = t;
|
||||
t = t.replace(/^(\s*)(node-pty|protobufjs):.*$/gm, "$1$2: true");
|
||||
if (!/^\s*allowBuilds:\s*$/m.test(t)) {
|
||||
t += "\nallowBuilds:\n node-pty: true\n protobufjs: true\n";
|
||||
} else {
|
||||
for (const k of ["node-pty", "protobufjs"]) {
|
||||
if (!new RegExp("^\\s*" + k + ":\\s*true\\s*$", "m").test(t)) {
|
||||
t = t.replace(/^(\s*allowBuilds:\s*)$/m, "$1\n " + k + ": true");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t !== before) fs.writeFileSync(p, t);
|
||||
console.log(t === before ? "unchanged" : "updated");
|
||||
' "$WS_YML")"
|
||||
[ "$WS_RESULT" = "updated" ] && say "已确保 ${WS_YML}:allowBuilds(node-pty/protobufjs: true)" \
|
||||
|| say "workspace 设置已就绪,跳过"
|
||||
else
|
||||
warn "找不到 ${WS_YML},跳过 workspace 预写(若 pnpm install 报 ignored build scripts 需手动补)"
|
||||
fi
|
||||
|
||||
# ── 步骤 4:pnpm install(重建 node_modules——两线不共存,这是预期)──────
|
||||
command -v pnpm >/dev/null 2>&1 || die "未找到 pnpm。请安装 pnpm 9+ 并加入 PATH。"
|
||||
say "执行 cd ${PROFILE_DIR} && pnpm install(reconcileProfilePnpmWorkspace 会重建 node_modules)..."
|
||||
if ! (cd "$PROFILE_DIR" && pnpm install); then
|
||||
die "pnpm install 失败。请确认网络可用、依赖 spec 正确,然后重试。"
|
||||
fi
|
||||
|
||||
# ── 步骤 5 校验:bundles 含目标包(挂载生效判据)────────────────────────
|
||||
if ! node -e '
|
||||
const p = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||
const b = (p.dsh && p.dsh.profile && p.dsh.profile.bundles) || [];
|
||||
process.exit(b.includes(process.argv[2]) ? 0 : 1);
|
||||
' "$PKG_JSON" "$T_PKG"; then
|
||||
warn "${T_PKG} 未出现在 dsh.profile.bundles——挂载未注册,请检查 ${PKG_JSON}。"
|
||||
exit 1
|
||||
fi
|
||||
say "bundle 已注册:dsh.profile.bundles 含 ${T_PKG}(下次启动自动挂载)"
|
||||
|
||||
# ── 步骤 6:幂等移除对手线在 cordis.patch.yml 里的手动挂载行 ─────────────
|
||||
if [ -f "$PATCH_YML" ]; then
|
||||
MOUNT_RESULT="$(node -e '
|
||||
const fs = require("fs");
|
||||
const p = process.argv[1];
|
||||
const removePkg = process.argv[2];
|
||||
if (!removePkg) { console.log("none"); process.exit(0); }
|
||||
const lines = fs.readFileSync(p, "utf8").split("\n");
|
||||
const out = [];
|
||||
let i = 0;
|
||||
let removed = false;
|
||||
while (i < lines.length) {
|
||||
const line = lines[i];
|
||||
if (/^[ \t]*- insert:\s*$/.test(line)) {
|
||||
const block = [line];
|
||||
let j = i + 1;
|
||||
while (j < lines.length && lines[j].trim() !== "" && !/^- \s/.test(lines[j])) {
|
||||
block.push(lines[j]);
|
||||
j++;
|
||||
}
|
||||
if (block.some((l) => new RegExp("id:\\s*" + removePkg.replace(/[-/]/g, "\\$&") + "\\b").test(l))) {
|
||||
while (out.length && /^[ \t]*#/.test(out[out.length - 1])) out.pop();
|
||||
i = j;
|
||||
removed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push(line);
|
||||
i++;
|
||||
}
|
||||
if (!removed) console.log("none");
|
||||
else { const t = out.join("\n").replace(/\n{3,}/g, "\n\n"); fs.writeFileSync(p, t); console.log("removed"); }
|
||||
' "$PATCH_YML" "$OTHER_PKG")"
|
||||
[ "$MOUNT_RESULT" = "removed" ] && say "已从 ${PATCH_YML} 移除 ${OTHER_PKG} 的手动挂载行" \
|
||||
|| say "无 ${OTHER_PKG} 手动挂载行,跳过"
|
||||
else
|
||||
say "无 ${PATCH_YML},跳过手动挂载行清理"
|
||||
fi
|
||||
|
||||
# ── 步骤 7:提示重启 ────────────────────────────────────────────────────
|
||||
say "切换完成:${CUR} → ${TARGET}(${T_PKG})"
|
||||
say "下一步:重启 DSH 并硬刷新(Cmd/Ctrl+Shift+R)使新副本生效。"
|
||||
@@ -26,14 +26,14 @@ export class RenderBoundary extends Component<{ children?: ReactNode; className?
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: ErrorInfo): void {
|
||||
console.error('[dsh-better-sidebar] render error:', error, info.componentStack)
|
||||
console.error('[dsh-apes-sidebar] render error:', error, info.componentStack)
|
||||
}
|
||||
|
||||
render(): ReactNode {
|
||||
if (this.state.error !== null) {
|
||||
return (
|
||||
<div className={this.props.className}>
|
||||
<span>dsh-better-sidebar: {this.state.error}</span>
|
||||
<span>dsh-apes-sidebar: {this.state.error}</span>
|
||||
<button
|
||||
type="button"
|
||||
className={css.terminalRetry}
|
||||
|
||||
@@ -463,7 +463,7 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
if (closed) return
|
||||
failures += 1
|
||||
if (failures >= FAILURE_LIMIT) {
|
||||
console.error('[dsh-better-sidebar] agent-terminals connection failed; stopping reconnect loop', sessionId)
|
||||
console.error('[dsh-apes-sidebar] agent-terminals connection failed; stopping reconnect loop', sessionId)
|
||||
return
|
||||
}
|
||||
retry = window.setTimeout(connect, 2000)
|
||||
@@ -535,7 +535,7 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
if (closed) return
|
||||
failures += 1
|
||||
if (failures >= FAILURE_LIMIT) {
|
||||
console.error('[dsh-better-sidebar] agent-opens connection failed; stopping reconnect loop', sessionId)
|
||||
console.error('[dsh-apes-sidebar] agent-opens connection failed; stopping reconnect loop', sessionId)
|
||||
return
|
||||
}
|
||||
retry = window.setTimeout(connect, 2000)
|
||||
@@ -1468,7 +1468,7 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
try {
|
||||
value = descriptor.badge(ctx, { sessionId, cwd }, state)
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] tab badge error:', error)
|
||||
console.error('[dsh-apes-sidebar] tab badge error:', error)
|
||||
return null
|
||||
}
|
||||
if (value === null || value === undefined || value === '') return null
|
||||
|
||||
@@ -715,7 +715,7 @@ export function SubagentView(props: {
|
||||
try {
|
||||
sessions.openSubagent?.(address)
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] openSubagent failed:', error)
|
||||
console.error('[dsh-apes-sidebar] openSubagent failed:', error)
|
||||
}
|
||||
}, [sessions, onOpenChild])
|
||||
|
||||
@@ -725,7 +725,7 @@ export function SubagentView(props: {
|
||||
try {
|
||||
sessions.open?.(rootId)
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] open session failed:', error)
|
||||
console.error('[dsh-apes-sidebar] open session failed:', error)
|
||||
}
|
||||
}, [sessions, rootId])
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
||||
failures += 1
|
||||
if (failures >= FAILURE_LIMIT) {
|
||||
const detail = event.reason !== '' ? ` (${event.code}: ${event.reason})` : ` (${event.code})`
|
||||
console.error('[dsh-better-sidebar] terminal connection failed:', event.code, event.reason, url)
|
||||
console.error('[dsh-apes-sidebar] terminal connection failed:', event.code, event.reason, url)
|
||||
setFatal(`${t('terminalConnectFailed')}${detail}`)
|
||||
return
|
||||
}
|
||||
@@ -323,7 +323,7 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
||||
fit.fit()
|
||||
sendResize()
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] xterm open failed:', error)
|
||||
console.error('[dsh-apes-sidebar] xterm open failed:', error)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Tab glyphs for the apes tabs (智能体 / 应用 / 画像).
|
||||
*
|
||||
* These follow the SAME recipe as this repo's own icon set in
|
||||
* `src/client/icons.tsx` — the one the sidebar already uses for 终端 /
|
||||
* 浏览器 / 文件变动: a 16×16 viewBox whose artwork spans 1.5–14.5, a 1.5px
|
||||
* `currentColor` stroke, round caps/joins, `fill: none`.
|
||||
*
|
||||
* That recipe is what makes an icon sit at the native visual weight in the
|
||||
* `+` new-tab menu and the right-panel tile grid: DSH's own glyphs fill
|
||||
* ~92–96% of the box, so artwork padded any tighter renders visibly small
|
||||
* next to them.
|
||||
*
|
||||
* (An earlier revision drew these as fill-only paths spanning only 10–12 of
|
||||
* the 16 units — that is why they read as a separate, lighter family.)
|
||||
*/
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
/** Agent glyph: a rounded robot head with two fill eyes. */
|
||||
export function IconAgentOutline16({ size = 16, className }: { size?: number; className?: string }): ReactNode {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
|
||||
<rect x="1.5" y="3" width="13" height="11.5" rx="4.2" stroke="currentColor" strokeWidth="1.5" />
|
||||
<circle cx="5.8" cy="8.6" r="1.25" fill="currentColor" />
|
||||
<circle cx="10.2" cy="8.6" r="1.25" fill="currentColor" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/** Apps glyph: a 2×2 grid of rounded squares. */
|
||||
export function IconAppsOutline16({ size = 16, className }: { size?: number; className?: string }): ReactNode {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
|
||||
<rect x="1.5" y="1.5" width="5.5" height="5.5" rx="1.8" stroke="currentColor" strokeWidth="1.5" />
|
||||
<rect x="9" y="1.5" width="5.5" height="5.5" rx="1.8" stroke="currentColor" strokeWidth="1.5" />
|
||||
<rect x="1.5" y="9" width="5.5" height="5.5" rx="1.8" stroke="currentColor" strokeWidth="1.5" />
|
||||
<rect x="9" y="9" width="5.5" height="5.5" rx="1.8" stroke="currentColor" strokeWidth="1.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/** Profile glyph: a head over shoulders. */
|
||||
export function IconUserOutline16({ size = 16, className }: { size?: number; className?: string }): ReactNode {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
|
||||
<circle cx="8" cy="4.9" r="3.4" stroke="currentColor" strokeWidth="1.5" />
|
||||
<path d="M1.5 14.5c0-3.3 2.8-5.3 6.5-5.3s6.5 2 6.5 5.3" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* apes:* information-layer tabs — the fork's own contribution on top of the
|
||||
* upstream dsh-better-sidebar. Three tabs ship (agents / apps / profile);
|
||||
* `apes:tasks` was removed (C6) because it overlaps the official DSH session
|
||||
* tree in the native sidebar, and `messages` is deferred (no DSH
|
||||
* message-stream API yet — tracked separately).
|
||||
*
|
||||
* Isolated under `src/client/apes/` so the upstream `builtins/` tree stays
|
||||
* untouched: cherry-picking upstream releases only has to keep the single
|
||||
* `registerApesTabs(...)` call site in `index.tsx` (see D1 = module B).
|
||||
*
|
||||
* Every descriptor is registered through the same `BetterSidebarService`
|
||||
* the builtins use (dogfood), so the apes tabs get the full sidebar
|
||||
* lifecycle for free: + menu, enable/disable switches, badge pills,
|
||||
* dedupe/focus, and HMR-safe disposal via the returned disposer.
|
||||
*/
|
||||
import type { Context } from '../../context-types.ts'
|
||||
import type { BetterSidebarService } from '../service.ts'
|
||||
import { apesTabs } from './tabs.tsx'
|
||||
|
||||
// Re-exported so index.tsx can register the apes dictionaries + attach the
|
||||
// locale service in one import (keeps the apes module self-contained).
|
||||
export { APES_LOCALE_NS, apesZh, apesEn, attachApesLocale } from './locales.ts'
|
||||
|
||||
/**
|
||||
* Register the apes:* tabs with the sidebar service. Returns a disposer that
|
||||
* unregisters all of them (cordis auto-invokes it on fiber disposal, so HMR
|
||||
* re-activation re-registers cleanly — same contract as registerBuiltins).
|
||||
*/
|
||||
export function registerApesTabs(
|
||||
_ctx: Context,
|
||||
service: BetterSidebarService,
|
||||
): () => void {
|
||||
const disposers: (() => void)[] = []
|
||||
for (const tab of apesTabs) {
|
||||
disposers.push(service.registerTab(tab))
|
||||
}
|
||||
return () => {
|
||||
for (const d of disposers) {
|
||||
try { d() } catch { /* already disposed */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* apes:* tab i18n — isolated from the upstream `betterSidebar` locale
|
||||
* namespace (D1 = module B). The fork keeps its own `apes` namespace and
|
||||
* its own `t()` so that adding apes keys never touches the upstream
|
||||
* `locales.ts` (whose `CopyKey = keyof typeof zh` is closed over its own
|
||||
* dicts). The `t()` mirrors the upstream implementation's resolution order
|
||||
* (active-locale chain → key fallback) but reads the apes dicts; it is NOT
|
||||
* wired to the better-locale override store in Phase 1 (those third-language
|
||||
* overrides ride the lazy `locale` chunk that only covers `betterSidebar`
|
||||
* entries — apes keys fall back to zh/en, which is acceptable for the
|
||||
* placeholder round and gets the override integration in Phase 2).
|
||||
*/
|
||||
|
||||
/** The apes locale namespace (registered with ctx.locale under this key). */
|
||||
export const APES_LOCALE_NS = 'apes'
|
||||
|
||||
/** The zh dictionary (source of truth). */
|
||||
export const apesZh = {
|
||||
// View titles
|
||||
apesAgentsTitle: '智能体',
|
||||
apesAppsTitle: '应用',
|
||||
apesProfileTitle: '画像',
|
||||
// Agents view
|
||||
apesAgentsEmpty: '当前会话没有子智能体',
|
||||
apesAgentsRoot: '主智能体',
|
||||
apesAgentRunning: '运行中',
|
||||
apesAgentInactive: '空闲',
|
||||
apesAgentOneShot: '一次性',
|
||||
apesAgentContinuable: '可续',
|
||||
// Profile view
|
||||
apesProfileCurrent: '当前会话',
|
||||
apesProfileCwd: '工作目录',
|
||||
apesProfileNoCwd: '未知',
|
||||
apesProfileRunning: '运行中',
|
||||
apesProfileIdle: '空闲',
|
||||
/** Guide-page capsule description (official right sidebar's entry list). */
|
||||
apesProfileGuideDesc: '当前会话的身份与工作目录',
|
||||
// Apps view
|
||||
apesAppsNoFeed: '当前 DSH 版本未提供工作区应用数据源',
|
||||
apesAppsWorkspace: '工作区',
|
||||
} as const
|
||||
|
||||
/** The en dictionary (checked against zh — every zh key must appear here). */
|
||||
export const apesEn: Record<keyof typeof apesZh, string> = {
|
||||
apesAgentsTitle: 'Agents',
|
||||
apesAppsTitle: 'Apps',
|
||||
apesProfileTitle: 'Profile',
|
||||
apesAgentsEmpty: 'No subagents in this session',
|
||||
apesAgentsRoot: 'Main agent',
|
||||
apesAgentRunning: 'running',
|
||||
apesAgentInactive: 'idle',
|
||||
apesAgentOneShot: 'one-shot',
|
||||
apesAgentContinuable: 'continuable',
|
||||
apesProfileCurrent: 'Current session',
|
||||
apesProfileCwd: 'Working directory',
|
||||
apesProfileNoCwd: 'unknown',
|
||||
apesProfileRunning: 'running',
|
||||
apesProfileIdle: 'idle',
|
||||
apesProfileGuideDesc: "This session's identity and working directory",
|
||||
apesAppsNoFeed: 'This DSH version exposes no workspace-app feed',
|
||||
apesAppsWorkspace: 'Workspace',
|
||||
}
|
||||
|
||||
export type ApesCopyKey = keyof typeof apesZh
|
||||
|
||||
/** Resolve the currently active DSH locale ('zh' | 'en' today). */
|
||||
export function attachApesLocale(service: { getSnapshot(): { active: string } } | undefined): void {
|
||||
apesLocaleService = service
|
||||
}
|
||||
|
||||
let apesLocaleService: { getSnapshot(): { active: string } } | undefined
|
||||
|
||||
/**
|
||||
* Translate an apes key. Resolution order: active-locale chain (zh dict when
|
||||
* the DSH preference is zh, en dict otherwise) → key fallback (shows the key
|
||||
* itself rather than `undefined`). Mirrors the upstream t() minus the
|
||||
* better-locale override (Phase 2).
|
||||
*/
|
||||
export function t(key: ApesCopyKey, params?: Record<string, string | number>): string {
|
||||
const active = apesLocaleService?.getSnapshot().active ?? 'zh'
|
||||
const dict = active.toLowerCase().startsWith('zh') ? apesZh : apesEn
|
||||
let text: string | undefined = dict[key]
|
||||
if (text === undefined) text = key
|
||||
if (params !== undefined) {
|
||||
for (const [name, value] of Object.entries(params)) {
|
||||
text = text.replaceAll(`{${name}}`, String(value))
|
||||
}
|
||||
}
|
||||
return text
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Native right-sidebar bridge (Phase A spike) — registers apes:* tabs as
|
||||
* OFFICIAL `@deepseek-ai/dsh-client-ui-sidebar-right` tab types through the
|
||||
* public two-stage protocol its README documents:
|
||||
*
|
||||
* 1. TYPE — `ctx.sidebarRightTabs.register({ id, kind, priority, title, guide? })`
|
||||
* a static declaration with no runtime hooks; the `id` is the type's
|
||||
* identity in the tab system AND the key its body registers under.
|
||||
* 2. BODY — `ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register(
|
||||
* { name: 'sidebar.right.pane.tab', key: <id> }, Body))`
|
||||
* the keyed seat dispatches a tab's body to the type registered for its
|
||||
* `kind`; the body reads `useTabInfo()` (injected by the seat) for
|
||||
* `{ sidebar, panel, tab }`.
|
||||
*
|
||||
* ACTIVATION ORDER — `sidebarRightTabs` is installed by that package's own
|
||||
* `apply()` through `ctx.reflect.provide(...)`, so it may not exist yet when
|
||||
* our plugin activates. We therefore reach it through `ctx.inject(['sidebarRightTabs'], …)`
|
||||
* (the same pattern intercept.tsx uses for the async `remote.session`
|
||||
* namespace): the callback runs when the service exists and re-runs after a
|
||||
* remount, so the bridge is order-independent and HMR-safe. Deployments
|
||||
* without the official right sidebar simply never see the callback — the
|
||||
* fork's own shell stays the only surface, which is also what the render-time
|
||||
* `guide`/type registration tolerates.
|
||||
*
|
||||
* SCOPE — the spike registers exactly ONE tab (`apes:profile` / 画像) to prove
|
||||
* the path end-to-end before deciding on the full nine-tab migration. The
|
||||
* existing `service.registerTab` route in `tabs.tsx` is deliberately left
|
||||
* untouched, so both surfaces coexist during the spike and the whole spike
|
||||
* reverts by deleting this file plus its one call site.
|
||||
*
|
||||
* Side effect worth knowing (inherent to the official default-page rule): the
|
||||
* dock's default page depends on how many guide entries are registered —
|
||||
* exactly one auto-opens it, zero or many open the guide page. Our guide entry
|
||||
* therefore turns a fresh-empty dock from "Files" into the guide page listing
|
||||
* every entry capsule.
|
||||
*/
|
||||
import { useMemo, type ReactNode } from 'react'
|
||||
import { IconUserOutline16 } from './icons.tsx'
|
||||
import { t } from './locales.ts'
|
||||
import { ApesProfileView } from './tabs.tsx'
|
||||
import type { TabComponentProps } from '../service.ts'
|
||||
|
||||
/** The apes type's identity in the official tab system. Package-scoped so it
|
||||
* can never collide with a native or third-party registration. */
|
||||
const PROFILE_ID = 'dsh-apes-sidebar/profile'
|
||||
/** The kind the panel opens the tab with (`openTab(kind)`); `apes:` prefixed so
|
||||
* it reads as ours in the official registry. */
|
||||
const PROFILE_KIND = 'apes:profile'
|
||||
|
||||
/** The official registry's definition shape (the subset we use). */
|
||||
interface NativeTabDefinition {
|
||||
id: string
|
||||
kind: string
|
||||
priority?: 'builtin' | 'extension' | 'fallback'
|
||||
title: () => string
|
||||
guide?: Array<{
|
||||
order: number
|
||||
title: () => string
|
||||
description?: () => string
|
||||
icon?: (props: { size?: number; className?: string }) => ReactNode
|
||||
}>
|
||||
}
|
||||
|
||||
/** The registry service face the official package provides. */
|
||||
interface NativeTabRegistry {
|
||||
register(definition: NativeTabDefinition): () => void
|
||||
}
|
||||
|
||||
/** The slots service face (structural subset of `@deepseek-ai/dsh-client-ui-slots`). */
|
||||
interface NativeSlots {
|
||||
inject(key: string, callback: () => () => void): () => void
|
||||
register(options: {
|
||||
name: string
|
||||
key?: string
|
||||
locale?: string
|
||||
inject?: (...args: unknown[]) => Record<string, unknown>
|
||||
}, component: (props: Record<string, unknown>) => ReactNode): () => void
|
||||
}
|
||||
|
||||
/** What the seat hands a tab body in addition to our own injected props. */
|
||||
interface NativeTabBodyProps {
|
||||
useTabInfo?: () => unknown
|
||||
sessionId?: string
|
||||
ctx: TabComponentProps['ctx']
|
||||
}
|
||||
|
||||
/** The tab info the seat's `useTabInfo()` hook returns (the subset we read). */
|
||||
interface NativeTabInfo {
|
||||
sidebar?: { expanded?: boolean; fullscreen?: boolean }
|
||||
panel?: { id?: string }
|
||||
tab?: { id?: string; title?: string; visible?: boolean }
|
||||
}
|
||||
|
||||
/** Fallback reader for an absent seat hook (never in production — the seat
|
||||
* always injects `tabInfo`; this keeps the body hook-safe either way, since
|
||||
* the fallback calls no hooks of its own). */
|
||||
function fallbackTabInfo(): NativeTabInfo {
|
||||
return { sidebar: { expanded: true }, panel: { id: '' }, tab: { visible: true } }
|
||||
}
|
||||
|
||||
/**
|
||||
* The official surface's body for 画像: the SAME `ApesProfileView` the fork
|
||||
* already ships, re-bound to the official tab scope. The view reads only
|
||||
* `props.ctx` (the sessions feed) and `props.scope` (sessionId / cwd), so the
|
||||
* shell-only props are filled with placeholders — which is the spike's whole
|
||||
* point: the panel content is shared, never duplicated.
|
||||
*/
|
||||
function ProfileNativeBody(props: NativeTabBodyProps): ReactNode {
|
||||
const useInfo = props.useTabInfo ?? fallbackTabInfo
|
||||
const info = useInfo() as NativeTabInfo | undefined
|
||||
const sessionId = props.sessionId
|
||||
?? props.ctx.sessions.list.getSnapshot().current
|
||||
?? ''
|
||||
const scope = useMemo(() => ({ sessionId }), [sessionId])
|
||||
const viewProps = {
|
||||
ctx: props.ctx,
|
||||
scope,
|
||||
visible: info?.tab?.visible ?? true,
|
||||
store: undefined,
|
||||
tab: {
|
||||
id: info?.tab?.id ?? PROFILE_ID,
|
||||
type: PROFILE_KIND,
|
||||
title: info?.tab?.title ?? t('apesProfileTitle'),
|
||||
},
|
||||
} as unknown as TabComponentProps
|
||||
return <ApesProfileView {...viewProps} />
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the apes:profile tab as an official right-sidebar tab type.
|
||||
* @param ctx — the client context whose `inject` waits for the registry service.
|
||||
* @returns a disposer that disposes the inject fiber (which unwinds both stages).
|
||||
*/
|
||||
export function registerApesNativeTabs(ctx: unknown): () => void {
|
||||
const anyCtx = ctx as {
|
||||
inject?: (deps: string[], callback: (fctx: unknown) => void) => { dispose(): void }
|
||||
}
|
||||
if (typeof anyCtx.inject !== 'function') return () => {}
|
||||
const fiber = anyCtx.inject(['sidebarRightTabs'], (fctx: unknown) => {
|
||||
const inner = fctx as {
|
||||
get?: (name: string) => unknown
|
||||
slots?: NativeSlots
|
||||
effect?: (callback: () => () => void, label?: string) => unknown
|
||||
}
|
||||
const registry = inner.get?.('sidebarRightTabs') as NativeTabRegistry | undefined
|
||||
const slots = inner.slots
|
||||
if (registry === undefined || slots === undefined || typeof inner.effect !== 'function') return
|
||||
inner.effect(() => {
|
||||
const disposers: Array<() => void> = []
|
||||
try {
|
||||
// Stage 1 — the type. A page type: it recognizes no resource address
|
||||
// and is opened by kind; `extension` is the band for types contributed
|
||||
// from outside the product (highest rank, so it can also take over a
|
||||
// builtin of the same kind).
|
||||
disposers.push(registry.register({
|
||||
id: PROFILE_ID,
|
||||
kind: PROFILE_KIND,
|
||||
priority: 'extension',
|
||||
title: () => t('apesProfileTitle'),
|
||||
guide: [{
|
||||
order: 70,
|
||||
title: () => t('apesProfileTitle'),
|
||||
description: () => t('apesProfileGuideDesc'),
|
||||
icon: IconUserOutline16,
|
||||
}],
|
||||
}))
|
||||
// Stage 2 — the body, dispatched through the keyed seat. `inject`
|
||||
// hands the body the client context the view reads its feed from.
|
||||
disposers.push(slots.inject('sidebar.right.pane.tab', () => slots.register({
|
||||
name: 'sidebar.right.pane.tab',
|
||||
key: PROFILE_ID,
|
||||
inject: () => ({ ctx }),
|
||||
}, ProfileNativeBody as unknown as (props: Record<string, unknown>) => ReactNode)))
|
||||
} catch (error) {
|
||||
// A half-registered bridge must never take the fork's own sidebar
|
||||
// down: unwind what landed and let the own-shell surface carry on.
|
||||
console.error('[dsh-apes-sidebar] native right-sidebar registration failed:', error)
|
||||
}
|
||||
return () => {
|
||||
for (const dispose of disposers.reverse()) {
|
||||
try { dispose() } catch { /* already disposed */ }
|
||||
}
|
||||
}
|
||||
}, 'dsh-apes-sidebar: apes native tab (profile)')
|
||||
})
|
||||
return () => { void fiber.dispose() }
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* apes:* tab views (D2 = data wiring). Each tab reads live data from the
|
||||
* sessions list feed (`ctx.sessions.list`) via `useSyncExternalStore` and
|
||||
* reuses the fork's PURE lineage/job helpers — these are framework-free and
|
||||
* live outside `builtins/`, so importing them does not couple the apes module
|
||||
* to upstream UI and survives cherry-picks.
|
||||
*
|
||||
* Three information-layer tabs (C6: `apes:tasks` removed — it overlaps the
|
||||
* official DSH session tree in the native sidebar):
|
||||
* - apes:agents → the subagent topology rooted at the main agent of the
|
||||
* current session (rootAncestor + per-parent catalogs).
|
||||
* - apes:apps → no DSH host feed today: shows the workspace (cwd) of the
|
||||
* current session, otherwise an honest "no feed" note.
|
||||
* - apes:profile → the current session's summary row (title, cwd, running).
|
||||
*
|
||||
* Visual unity (C7): colors use the DSW design-token aliases
|
||||
* (`--dsw-alias-*`) so the apes panels match the native DSH sidebar
|
||||
* surface; the runtime defines these on :root. Font sizes / spacing /
|
||||
* radius stay inline (DSH exposes no public `--ds-*` geometry alias for
|
||||
* plugin panels — its own vendor bundles inline those too).
|
||||
*
|
||||
* Data sources (structural mirror — runtime provided by the DSH host):
|
||||
* - `ctx.sessions.list.getSnapshot()` → { current, byId, subagentsByParent? };
|
||||
* `subscribe(cb)` is uSES-safe.
|
||||
* - `scope.sessionId` = the currently-open session.
|
||||
*/
|
||||
import { useCallback, useMemo, useState, type CSSProperties } from 'react'
|
||||
import { useSyncExternalStore } from 'react'
|
||||
import { IconAgentOutline16, IconAppsOutline16, IconUserOutline16 } from './icons.tsx'
|
||||
import type { TabComponentProps, TabDescriptor } from '../service.ts'
|
||||
import type {
|
||||
SidebarSessionList,
|
||||
SidebarSessionSummary,
|
||||
SidebarSubagentCatalog,
|
||||
SidebarSubagentChildEntry,
|
||||
} from '../../context-types.ts'
|
||||
import { rootAncestor, isSideThreadSummary } from '../subagent-lineage.ts'
|
||||
import { t } from './locales.ts'
|
||||
|
||||
/**
|
||||
* DSW design-token color aliases. The DSH runtime defines these on :root
|
||||
* (same set the native dsh-client-ui-* vendor bundles consume). We reference
|
||||
* them by name via `var(...)` with a literal fallback so the panels still
|
||||
* render in a non-DSH context (unit harness) with a sane dark palette.
|
||||
*/
|
||||
const DSW = {
|
||||
bgBase: 'var(--dsw-alias-bg-base, #1a1a1a)',
|
||||
bgLayer1: 'var(--dsw-alias-bg-layer-1, #202020)',
|
||||
borderL1: 'var(--dsw-alias-border-l1, #2a2a2a)',
|
||||
borderL2: 'var(--dsw-alias-border-l2, #303030)',
|
||||
labelPrimary: 'var(--dsw-alias-label-primary, #e8e8e8)',
|
||||
labelSecondary: 'var(--dsw-alias-label-secondary, #a0a0a0)',
|
||||
labelTertiary: 'var(--dsw-alias-label-tertiary, #7a7a7a)',
|
||||
success: 'var(--dsw-alias-state-success-primary, #52c41a)',
|
||||
interactiveHover: 'var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.06))',
|
||||
} as const
|
||||
|
||||
/** Shared inline styles (KISS: one object, no CSS module). Colors via DSW. */
|
||||
const S: Record<string, CSSProperties> = {
|
||||
body: { padding: 12, display: 'flex', flexDirection: 'column', gap: 12 },
|
||||
title: { margin: 0, fontSize: 14, fontWeight: 600, color: DSW.labelPrimary },
|
||||
hint: { margin: 0, fontSize: 12, color: DSW.labelTertiary },
|
||||
list: { display: 'flex', flexDirection: 'column', gap: 8 },
|
||||
card: { border: `1px solid ${DSW.borderL1}`, borderRadius: 8, padding: 10, display: 'flex', flexDirection: 'column', gap: 6, background: DSW.bgLayer1 },
|
||||
cardRow: { display: 'flex', alignItems: 'center', gap: 8 },
|
||||
cardLabel: { fontSize: 13, fontWeight: 500, flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: DSW.labelPrimary },
|
||||
cardSecondary: { fontSize: 11, color: DSW.labelSecondary, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
|
||||
badge: { fontSize: 11, color: DSW.labelTertiary, flexShrink: 0 },
|
||||
}
|
||||
|
||||
/** A small colored status dot (self-contained, not the builtin StateDot). */
|
||||
function Dot(props: { color: string }) {
|
||||
const style: CSSProperties = {
|
||||
width: 8, height: 8, borderRadius: '50%', background: props.color, flexShrink: 0, display: 'inline-block',
|
||||
}
|
||||
return <span aria-hidden style={style} />
|
||||
}
|
||||
|
||||
/** Subscribe to the sessions list feed (uSES-safe). Returns the live snapshot. */
|
||||
function useSessionList(ctx: TabComponentProps['ctx']): SidebarSessionList {
|
||||
const sessions = ctx.sessions
|
||||
return useSyncExternalStore(
|
||||
useMemo(() => (callback: () => void) => sessions.list.subscribe(callback), [sessions]),
|
||||
useCallback(() => sessions.list.getSnapshot(), [sessions]),
|
||||
)
|
||||
}
|
||||
|
||||
/** One level of the subagent topology (rooted at the main agent). */
|
||||
function agentChildren(
|
||||
byId: Readonly<Record<string, SidebarSessionSummary>>,
|
||||
parentSessionId: string,
|
||||
): SidebarSessionSummary[] {
|
||||
return Object.values(byId).filter(
|
||||
s => s.origin === 'subagent' && s.parentId === parentSessionId && !isSideThreadSummary(s),
|
||||
)
|
||||
}
|
||||
|
||||
/** apes:agents — the subagent topology of the current session's tree. */
|
||||
function ApesAgentsView(props: TabComponentProps) {
|
||||
const list = useSessionList(props.ctx)
|
||||
const { byId, subagentsByParent } = list
|
||||
const rootId = useMemo(() => rootAncestor(byId, props.scope.sessionId), [byId, props.scope.sessionId])
|
||||
const rootSummary = rootId === undefined ? undefined : byId[rootId]
|
||||
const rootCatalog = rootId === undefined ? undefined : subagentsByParent?.[rootId]
|
||||
|
||||
// The topology: the main agent + its direct subagent children (one level,
|
||||
// with per-child activity). A lazy catalog (subagentsByParent) is preferred
|
||||
// for the child list when present; otherwise fall back to durable byId rows.
|
||||
// (`.filter` does not narrow a union — narrow explicitly to child entries.)
|
||||
const children: SidebarSubagentChildEntry[] = (rootCatalog?.entries ?? [])
|
||||
.filter((e): e is SidebarSubagentChildEntry => e.kind === 'child')
|
||||
.concat(rootCatalog === undefined
|
||||
? agentChildren(byId, rootId ?? '').map<SidebarSubagentChildEntry>(s => ({
|
||||
kind: 'child', id: s.id, mode: 'continuable',
|
||||
activity: s.running === true ? 'running' : 'inactive',
|
||||
label: s.displayTitle, hasChildren: agentChildren(byId, s.id).length > 0,
|
||||
}))
|
||||
: [])
|
||||
|
||||
return (
|
||||
<div style={S.body}>
|
||||
<h2 style={S.title}>{t('apesAgentsTitle')}</h2>
|
||||
{rootSummary === undefined && children.length === 0
|
||||
? <p style={S.hint}>{t('apesAgentsEmpty')}</p>
|
||||
: (
|
||||
<div style={S.list}>
|
||||
{/* Root (main agent) node */}
|
||||
{rootSummary !== undefined && (
|
||||
<div style={S.card}>
|
||||
<div style={S.cardRow}>
|
||||
<Dot color={rootSummary.running === true ? DSW.success : DSW.labelTertiary} />
|
||||
<span style={S.cardLabel} title={rootSummary.displayTitle}>{t('apesAgentsRoot')}: {rootSummary.displayTitle}</span>
|
||||
</div>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.badge}>{rootSummary.running === true ? t('apesAgentRunning') : t('apesAgentInactive')}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* Direct subagent children */}
|
||||
{children.map(entry => {
|
||||
const summary = byId[entry.id]
|
||||
const running = entry.activity === 'running'
|
||||
const label = entry.label ?? summary?.displayTitle ?? entry.id
|
||||
return (
|
||||
<div key={entry.id} style={{ ...S.card, marginLeft: 14, borderLeft: `2px solid ${DSW.borderL2}` }}>
|
||||
<div style={S.cardRow}>
|
||||
<Dot color={running ? DSW.success : DSW.labelTertiary} />
|
||||
<span style={S.cardLabel} title={label}>{label}</span>
|
||||
</div>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.cardSecondary}>
|
||||
{entry.mode === 'one-shot' ? t('apesAgentOneShot') : t('apesAgentContinuable')}
|
||||
{' · '}
|
||||
{running ? t('apesAgentRunning') : t('apesAgentInactive')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** apes:profile — the current session's identity (title, cwd, running state). */
|
||||
export function ApesProfileView(props: TabComponentProps) {
|
||||
const list = useSessionList(props.ctx)
|
||||
const current = list.current
|
||||
const summary = current === undefined ? undefined : list.byId[current]
|
||||
const cwd = summary?.cwd ?? props.scope.cwd
|
||||
|
||||
return (
|
||||
<div style={S.body}>
|
||||
<h2 style={S.title}>{t('apesProfileTitle')}</h2>
|
||||
{summary === undefined
|
||||
? <p style={S.hint}>{t('apesProfileNoCwd')}</p>
|
||||
: (
|
||||
<div style={S.list}>
|
||||
<div style={S.card}>
|
||||
<div style={S.cardRow}>
|
||||
<Dot color={summary.running === true ? DSW.success : DSW.labelTertiary} />
|
||||
<span style={S.cardLabel} title={summary.displayTitle}>{t('apesProfileCurrent')}</span>
|
||||
</div>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.badge}>{summary.running === true ? t('apesProfileRunning') : t('apesProfileIdle')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={S.card}>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.cardLabel}>{summary.displayTitle}</span>
|
||||
</div>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.cardSecondary}>{t('apesProfileCwd')}: {cwd ?? t('apesProfileNoCwd')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** apes:apps — no DSH host feed today; shows the current workspace (cwd). */
|
||||
function ApesAppsView(props: TabComponentProps) {
|
||||
const list = useSessionList(props.ctx)
|
||||
const current = list.current
|
||||
const summary = current === undefined ? undefined : list.byId[current]
|
||||
const cwd = summary?.cwd ?? props.scope.cwd
|
||||
|
||||
return (
|
||||
<div style={S.body}>
|
||||
<h2 style={S.title}>{t('apesAppsTitle')}</h2>
|
||||
<p style={S.hint}>{t('apesAppsNoFeed')}</p>
|
||||
<div style={S.card}>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.cardLabel}>{t('apesAppsWorkspace')}</span>
|
||||
</div>
|
||||
<div style={S.cardRow}>
|
||||
<span style={S.cardSecondary}>{cwd ?? t('apesProfileNoCwd')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The three apes:* tab descriptors (C6: `apes:tasks` removed — overlaps the
|
||||
* official DSH session tree). Order 901-903: agents/apps/profile. Each is
|
||||
* already shaped as `TabDescriptor` (component + single-instance + icon
|
||||
* element + i18n title function) so `registerApesTabs` can hand them straight
|
||||
* to `service.registerTab`. Information-layer tabs are single-instance.
|
||||
*/
|
||||
export const apesTabs: TabDescriptor[] = [
|
||||
{ id: 'apes:agents', title: () => t('apesAgentsTitle'), icon: (size: number) => <IconAgentOutline16 size={size} />, order: 60, single: true, component: ApesAgentsView },
|
||||
{ id: 'apes:apps', title: () => t('apesAppsTitle'), icon: (size: number) => <IconAppsOutline16 size={size} />, order: 65, single: true, component: ApesAppsView },
|
||||
{ id: 'apes:profile', title: () => t('apesProfileTitle'), icon: (size: number) => <IconUserOutline16 size={size} />, order: 70, single: true, component: ApesProfileView },
|
||||
]
|
||||
@@ -154,7 +154,7 @@ const defaultScriptLoader: ChunkScriptLoader = (src) => new Promise((resolve, re
|
||||
}, { once: true })
|
||||
el.addEventListener('error', () => {
|
||||
el.remove()
|
||||
reject(new Error(`[dsh-better-sidebar] chunk script ${src} failed to load`))
|
||||
reject(new Error(`[dsh-apes-sidebar] chunk script ${src} failed to load`))
|
||||
}, { once: true })
|
||||
document.head.append(el)
|
||||
})
|
||||
@@ -192,7 +192,7 @@ async function buildExternalsRequire(modules: ChunkModuleSystem): Promise<(spec:
|
||||
if (!table.has(spec)) {
|
||||
// Single quotes: the bundle-consistency scan regexes for require("...")
|
||||
// lexical calls — a double-quoted literal here would trip it.
|
||||
throw new Error(`[dsh-better-sidebar] chunk require('${spec}') missed the module table`)
|
||||
throw new Error(`[dsh-apes-sidebar] chunk require('${spec}') missed the module table`)
|
||||
}
|
||||
return table.get(spec)
|
||||
}
|
||||
@@ -250,12 +250,12 @@ export async function loadChunk(name: ChunkName): Promise<ChunkExports> {
|
||||
if (test !== undefined) return test()
|
||||
const modules = moduleSystem()
|
||||
if (modules === undefined) {
|
||||
throw new Error(`[dsh-better-sidebar] chunk "${name}": client module system unavailable`)
|
||||
throw new Error(`[dsh-apes-sidebar] chunk "${name}": client module system unavailable`)
|
||||
}
|
||||
await scriptLoader(CHUNK_URL(name))
|
||||
const factory = chunkRegistry()[name]
|
||||
if (typeof factory !== 'function') {
|
||||
throw new Error(`[dsh-better-sidebar] chunk "${name}" script did not register its factory`)
|
||||
throw new Error(`[dsh-apes-sidebar] chunk "${name}" script did not register its factory`)
|
||||
}
|
||||
const require = await buildExternalsRequire(modules)
|
||||
const exports = factory(require)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Lazy chunk entry: the code/markdown/html text editor (CodeMirror 6 + the
|
||||
* language packages). Built as `lib/client-editor.js` and registered under
|
||||
* `dsh-better-sidebar/editor` — fetched only when a text file is first
|
||||
* `dsh-apes-sidebar/editor` — fetched only when a text file is first
|
||||
* opened (see chunk-loader.ts and docs/plans/2026-08-12-lazy-chunks-design.md).
|
||||
* Never import this module from the core bundle: it pulls CodeMirror into
|
||||
* the startup path.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Lazy chunk entry: the interactive terminal (xterm + fit addon). Built as
|
||||
* `lib/client-terminal.js` and registered under
|
||||
* `dsh-better-sidebar/terminal` — fetched only when a terminal tab is first
|
||||
* `dsh-apes-sidebar/terminal` — fetched only when a terminal tab is first
|
||||
* opened (see chunk-loader.ts and docs/plans/2026-08-12-lazy-chunks-design.md).
|
||||
* Never import this module from the core bundle: it pulls xterm (and its
|
||||
* stylesheet) into the startup path.
|
||||
|
||||
@@ -170,12 +170,12 @@ export function appendToDraft(ctx: Context, sessionId: string, text: string): bo
|
||||
try {
|
||||
const actx = ctx.sessions.scope(sessionId)
|
||||
if (actx === undefined) {
|
||||
console.warn('[dsh-better-sidebar] draft insert skipped: no session scope', sessionId)
|
||||
console.warn('[dsh-apes-sidebar] draft insert skipped: no session scope', sessionId)
|
||||
return false
|
||||
}
|
||||
const conversation = ctx.get('conversation') as SidebarConversation | undefined
|
||||
if (conversation === undefined) {
|
||||
console.warn('[dsh-better-sidebar] draft insert skipped: conversation service unavailable')
|
||||
console.warn('[dsh-apes-sidebar] draft insert skipped: conversation service unavailable')
|
||||
return false
|
||||
}
|
||||
const input = conversation.input.for(actx)
|
||||
@@ -189,7 +189,7 @@ export function appendToDraft(ctx: Context, sessionId: string, text: string): bo
|
||||
placeComposerCaretAfterInsert(next, caretAfter)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.warn('[dsh-better-sidebar] draft insert failed:', error)
|
||||
console.warn('[dsh-apes-sidebar] draft insert failed:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -249,7 +249,7 @@ export function insertFileReference(ctx: Context, sessionId: string, relativePat
|
||||
const after = input.state.getSnapshot()
|
||||
return after.draftRev !== before.draftRev
|
||||
} catch (error) {
|
||||
console.warn('[dsh-better-sidebar] file-reference insert failed:', error)
|
||||
console.warn('[dsh-apes-sidebar] file-reference insert failed:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
+42
-15
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Client half of dsh-better-sidebar: resolves the user's "Side card"
|
||||
* Client half of dsh-apes-sidebar: resolves the user's "Side card"
|
||||
* preferences through the plugin's own fenced settings route, mounts the
|
||||
* right sidebar portal (inside an error boundary so a rendering failure
|
||||
* shows an error strip instead of a blank panel), registers the turn-tail
|
||||
@@ -15,6 +15,8 @@ import { allLeaves, createSidebarStore, isAgentTabId } from './state.ts'
|
||||
import { createBetterSidebarService, matchUrlTarget } from './service.ts'
|
||||
import { revalidateChunksOnReactivate, setChunkModuleSystem } from './chunk-loader.ts'
|
||||
import { registerBuiltins } from './builtins/index.ts'
|
||||
import { registerApesTabs, APES_LOCALE_NS, apesZh, apesEn, attachApesLocale } from './apes/index.ts'
|
||||
import { registerApesNativeTabs } from './apes/native-tabs.tsx'
|
||||
import { Sidebar } from './Sidebar.tsx'
|
||||
import { RenderBoundary } from './RenderBoundary.tsx'
|
||||
import { registerOpenPathInterception, registerTurnTailInterception } from './intercept.tsx'
|
||||
@@ -57,11 +59,17 @@ export function apply(ctx: Context): void {
|
||||
// plugin's dictionaries into the shared locale registry. The disposers
|
||||
// run on fiber disposal, so re-activation (HMR) re-registers cleanly.
|
||||
attachLocale(ctx.locale)
|
||||
// The apes module has its own locale namespace (isolated from the upstream
|
||||
// betterSidebar dicts per D1=B); attach it so apes t() tracks the DSH
|
||||
// active-locale preference, and register its zh/en dicts under `apes`.
|
||||
attachApesLocale(ctx.locale)
|
||||
ctx.effect(() => {
|
||||
const offZh = ctx.locale.register(LOCALE_NS, 'zh', zh)
|
||||
const offEn = ctx.locale.register(LOCALE_NS, 'en', en)
|
||||
return () => { offZh(); offEn() }
|
||||
}, 'dsh-better-sidebar: dictionaries')
|
||||
const offApesZh = ctx.locale.register(APES_LOCALE_NS, 'zh', apesZh as Record<string, string>)
|
||||
const offApesEn = ctx.locale.register(APES_LOCALE_NS, 'en', apesEn as Record<string, string>)
|
||||
return () => { offZh(); offEn(); offApesZh(); offApesEn() }
|
||||
}, 'dsh-apes-sidebar: dictionaries')
|
||||
|
||||
// Opt-in third-language support through @huanlin/dsh-plugin-better-locale.
|
||||
// When that plugin is installed, it publishes `ctx.betterLocale` (the
|
||||
@@ -125,7 +133,7 @@ export function apply(ctx: Context): void {
|
||||
dispose?.()
|
||||
attachBetterLocale(undefined)
|
||||
}
|
||||
}, 'dsh-better-sidebar: better-locale lazy integration')
|
||||
}, 'dsh-apes-sidebar: better-locale lazy integration')
|
||||
// One store instance per activation: production code creates it only here,
|
||||
// then hands it to the mounted panel and closes over it in the slot
|
||||
// registrations (the official createXXXStore() factory rule — no
|
||||
@@ -162,19 +170,38 @@ export function apply(ctx: Context): void {
|
||||
// fiber disposal (HMR-safe).
|
||||
ctx.effect(
|
||||
() => registerBuiltins(ctx, service, { terminalTitle: () => terminalTitle }),
|
||||
'dsh-better-sidebar: register built-in tabs and viewers',
|
||||
'dsh-apes-sidebar: register built-in tabs and viewers',
|
||||
)
|
||||
// The apes:* information-layer tabs (the fork's own contribution, isolated
|
||||
// under src/client/apes per D1=B). Registered through the same service as
|
||||
// the builtins so they get the full sidebar lifecycle; the disposer runs on
|
||||
// fiber disposal (HMR-safe). A throw here is caught by the outer try and
|
||||
// routed to fail() — a bad apes registration must never blank the sidebar.
|
||||
ctx.effect(
|
||||
() => registerApesTabs(ctx, service),
|
||||
'dsh-apes-sidebar: register apes tabs',
|
||||
)
|
||||
// Phase A spike: also publish apes:profile as an OFFICIAL right-sidebar tab
|
||||
// type (ctx.sidebarRightTabs + the keyed `sidebar.right.pane.tab` seat), so
|
||||
// the tab renders inside DSH's own panel instead of only in the fork's
|
||||
// shell. Both surfaces coexist during the spike; the disposer reverses the
|
||||
// two-stage registration on fiber disposal (HMR-safe). A throw is caught
|
||||
// inside the bridge and never reaches this effect.
|
||||
ctx.effect(
|
||||
() => registerApesNativeTabs(ctx),
|
||||
'dsh-apes-sidebar: apes native right-sidebar tabs',
|
||||
)
|
||||
// A failure anywhere in the client lifecycle must never take the app down
|
||||
// silently: log with the plugin prefix and pin a visible diagnostic strip
|
||||
// to the page so a blank panel is never the only symptom.
|
||||
const fail = (phase: string, error: unknown): void => {
|
||||
console.error(`[dsh-better-sidebar] ${phase} error:`, error)
|
||||
console.error(`[dsh-apes-sidebar] ${phase} error:`, error)
|
||||
try {
|
||||
const bar = document.createElement('div')
|
||||
bar.style.cssText = 'position:fixed;left:8px;bottom:8px;z-index:2147483000;max-width:70vw;padding:8px 12px;'
|
||||
+ 'font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;color:#f2a1a1;background:#1b1b22;'
|
||||
+ 'border:1px solid #f2a1a1;border-radius:8px;white-space:pre-wrap'
|
||||
bar.textContent = `[dsh-better-sidebar] ${phase} error: ${error instanceof Error ? error.message : String(error)}`
|
||||
bar.textContent = `[dsh-apes-sidebar] ${phase} error: ${error instanceof Error ? error.message : String(error)}`
|
||||
document.body.appendChild(bar)
|
||||
} catch {
|
||||
// Nothing left to report with.
|
||||
@@ -244,7 +271,7 @@ export function apply(ctx: Context): void {
|
||||
return
|
||||
}
|
||||
layer.setAttribute('data-dsh-panel-host-degraded', '')
|
||||
console.warn('[dsh-better-sidebar] panel host geometry mismatch — a page-level transform was detected; using degraded viewport sync')
|
||||
console.warn('[dsh-apes-sidebar] panel host geometry mismatch — a page-level transform was detected; using degraded viewport sync')
|
||||
// Track our own compensating translation so the loop judges the
|
||||
// UNCORRECTED geometry: clearing degraded mode must wait for the
|
||||
// ancestor transform to actually disappear — the frame right after
|
||||
@@ -275,7 +302,7 @@ export function apply(ctx: Context): void {
|
||||
if (mounted || disposed) return
|
||||
try {
|
||||
host = document.createElement('div')
|
||||
host.setAttribute('data-dsh-better-sidebar', '')
|
||||
host.setAttribute('data-dsh-apes-sidebar', '')
|
||||
document.body.appendChild(host)
|
||||
root = createRoot(host)
|
||||
root.render(createElement(RenderBoundary, { className: css.boundaryError }, createElement(Sidebar, { ctx, store: sidebarStore })))
|
||||
@@ -322,7 +349,7 @@ export function apply(ctx: Context): void {
|
||||
offRemote?.()
|
||||
unmount()
|
||||
}
|
||||
}, 'dsh-better-sidebar: sidebar mount')
|
||||
}, 'dsh-apes-sidebar: sidebar mount')
|
||||
|
||||
ctx.effect(
|
||||
() => {
|
||||
@@ -333,7 +360,7 @@ export function apply(ctx: Context): void {
|
||||
return () => {}
|
||||
}
|
||||
},
|
||||
'dsh-better-sidebar: turn-tail interception',
|
||||
'dsh-apes-sidebar: turn-tail interception',
|
||||
)
|
||||
|
||||
ctx.effect(
|
||||
@@ -345,7 +372,7 @@ export function apply(ctx: Context): void {
|
||||
return () => {}
|
||||
}
|
||||
},
|
||||
'dsh-better-sidebar: open-path interception',
|
||||
'dsh-apes-sidebar: open-path interception',
|
||||
)
|
||||
|
||||
ctx.effect(
|
||||
@@ -389,7 +416,7 @@ export function apply(ctx: Context): void {
|
||||
return () => {}
|
||||
}
|
||||
},
|
||||
'dsh-better-sidebar: link interception',
|
||||
'dsh-apes-sidebar: link interception',
|
||||
)
|
||||
|
||||
// The IME guard: composition keys (candidate arrows, confirm, cancel)
|
||||
@@ -409,7 +436,7 @@ export function apply(ctx: Context): void {
|
||||
return () => {}
|
||||
}
|
||||
},
|
||||
'dsh-better-sidebar: IME composition guard',
|
||||
'dsh-apes-sidebar: IME composition guard',
|
||||
)
|
||||
|
||||
// DSH 0.1.x does not yet carry an icon through the settings.section
|
||||
@@ -419,7 +446,7 @@ export function apply(ctx: Context): void {
|
||||
// the marker for HMR / plugin disable.
|
||||
ctx.effect(
|
||||
() => registerSettingsNavIcon(() => t('settingsNav')),
|
||||
'dsh-better-sidebar: settings navigation icon',
|
||||
'dsh-apes-sidebar: settings navigation icon',
|
||||
)
|
||||
|
||||
// The "Side card" settings section: appears in the DSH Settings shell
|
||||
|
||||
@@ -142,7 +142,7 @@ export function registerTurnTailInterception(ctx: Context, store: SidebarStore):
|
||||
return matched
|
||||
},
|
||||
priority: -1,
|
||||
registrant: 'dsh-better-sidebar',
|
||||
registrant: 'dsh-apes-sidebar',
|
||||
inject: (sessionId: string) => ({
|
||||
openInSidebar: (path: string) => { openSidebarFile(ctx, store, sessionId, path) },
|
||||
onShowInFolder: (files: readonly string[]) => { revealInExplorer(ctx, store, sessionId, files) },
|
||||
@@ -180,7 +180,7 @@ export function registerOpenPathInterception(ctx: Context, store: SidebarStore):
|
||||
openInSidebar: (path, sessionId) => { openSidebarFile(ctx, store, sessionId, path) },
|
||||
revealInExplorer: (_path, sessionId) => { revealInExplorer(ctx, store, sessionId, lastProduced) },
|
||||
})
|
||||
}, 'dsh-better-sidebar: open-path interception wrap')
|
||||
}, 'dsh-apes-sidebar: open-path interception wrap')
|
||||
})
|
||||
return () => { void fiber.dispose() }
|
||||
}
|
||||
|
||||
+1
-1
@@ -217,7 +217,7 @@ export function languageForPath(path: string): Language | LanguageSupport | null
|
||||
return FACTORIES[key]!()
|
||||
} catch (error) {
|
||||
// A broken factory degrades to plain text, never crashes the editor.
|
||||
console.warn(`[dsh-better-sidebar] language factory "${key}" failed:`, error)
|
||||
console.warn(`[dsh-apes-sidebar] language factory "${key}" failed:`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ function LazyChunkView<P>({ chunk, pick, props }: LazyChunkViewProps<P>): ReactN
|
||||
if (cancelled) return
|
||||
const Comp = pick(mod)
|
||||
if (Comp === undefined) {
|
||||
setState({ status: 'error', message: `[dsh-better-sidebar] chunk "${chunk}" is missing its component` })
|
||||
setState({ status: 'error', message: `[dsh-apes-sidebar] chunk "${chunk}" is missing its component` })
|
||||
return
|
||||
}
|
||||
setState({ status: 'ready', Comp })
|
||||
|
||||
@@ -396,7 +396,7 @@ export const ar: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'تسجيل معاينة نوع ملف',
|
||||
addPluginsTabDesc: 'يمكن توسيع صفحات الشريط الجانبي (التبويبات) بواسطة الإضافات. تُسجَّل الإضافات عبر خدمة ctx.betterSidebar؛ النقر على «تثبيت» ينسخ أمر التثبيت — الصقه في طرفية حيث يقيم ملف DSH الشخصي وشغّله.',
|
||||
addPluginsViewerDesc: 'يمكن توسيع عارضات الملفات بواسطة الإضافات. تُسجَّل الإضافات عبر خدمة ctx.betterSidebar؛ النقر على «تثبيت» ينسخ أمر التثبيت — الصقه في طرفية حيث يقيم ملف DSH الشخصي وشغّله.',
|
||||
addPluginsBrowseMore: 'تصفّح المزيد من الإضافات على GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'تصفّح المزيد من الإضافات على GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'البحث باسم الإضافة / الوصف…',
|
||||
addPluginsNoMatch: 'لا إضافات مطابقة',
|
||||
addPluginsRecommended: 'إضافات موصى بها',
|
||||
@@ -409,7 +409,7 @@ export const ar: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'تبويب GitHub Workbench: شجرة المستودع البعيد + Issues / Pull requests / Actions مع دعم كامل للكتابة — إنشاء Issue/PR، والتعليق، والتعديل، والإغلاق/إعادة الفتح، والدمج عبر squash·merge·rebase (بتأكيد قوي)، وإعادة تشغيل CI أو إلغائها؛ يعرض مبدّل المستودعات تلقائيًا المستودعات المتاحة ويتيح البحث في المستودعات العامة؛ وبدون better-sidebar يتحول تلقائيًا إلى لوحة جانبية مستقلة على اليمين',
|
||||
pluginMdExportDesc: 'يضيف زر «تصدير» إلى شريط أدوات Markdown في better-sidebar: يعرض ملف .md الحالي بنقرة واحدة كملف HTML مستقل (الجداول/كتل الأكواد/مخططات Mermaid مدمجة، والتخطيط يتبع سمة المعاينة) ويحفظه بجوار الملف، أو يصدّره PDF عبر نافذة الطباعة',
|
||||
pluginCodeNavDesc: 'تنقل معاينة الكود: يكتشف اللغة تلقائياً من نوع الملف ويبرز الصياغة، مخطط الرموز (تصفية الفئات/الطرق/المتغيرات + قفزة بنقرة واحدة)، والبحث داخل الملف (إبراز كل التطابقات، السابق/التالي، مطابقة حالة الأحرف) — يتولى معاينة ملفات الكود في محرر better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'يربط بيئة Suhuang Scroll المحلية بإعدادات DSH وbetter-sidebar لإعداد النموذج واختبار الاتصال والتحكم في التصحيح المتواصل؛ يتطلب Suhuang Scroll Runtime وdsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'يربط بيئة Suhuang Scroll المحلية بإعدادات DSH وbetter-sidebar لإعداد النموذج واختبار الاتصال والتحكم في التصحيح المتواصل؛ يتطلب Suhuang Scroll Runtime وdsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'تبويب Overleaf لـ better-sidebar: تسجيل دخول مباشر عبر متصفح CDP (يدعم Chromium من جهات أخرى)، قائمة المشاريع/التبديل، نسخ git محلية ضمن <workspace>/overleaf/، مزامنة git ثنائية الاتجاه مع تراجع إلى API للقراءة فقط، ومعاينة الملفات عبر مساحة عمل الشريط الجانبي',
|
||||
pluginGitRemotesDesc: 'تبويب Git Remotes: فرع/أصل/أمام-خلف، fetch (مع prune اختياري)، ff-only pull، والدفع فقط بعد تأكيد داخل التبويب. لا يستبدل تبويب Git المدمج للإدراج/التثبيت، ولا يقدّم force-push أو أداة دفع آلي للنموذج',
|
||||
pluginSentinelDesc: 'نظام إيقاظ وكيل يحرّكه تحقّق الشروط: مستشعرات ملف/عملية/منفذ/HTTP/أمر/webhook توقظ الجلسات الخاملة عند تحقّق الشرط؛ يُسجِّل تبويب «Sentinel» مع جدول مراقبة شامل للخادم',
|
||||
|
||||
@@ -381,7 +381,7 @@ export const de: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Eine Dateityp-Vorschau registrieren',
|
||||
addPluginsTabDesc: 'Seitenleisten-Seiten (Tabs) können durch Plugins erweitert werden. Plugins registrieren sich über den ctx.betterSidebar-Dienst; ein Klick auf „Installieren“ kopiert den Installationsbefehl – fügen Sie ihn in einem Terminal ein, in dem Ihr DSH-Profil liegt, und führen Sie ihn aus.',
|
||||
addPluginsViewerDesc: 'Datei-Viewer können durch Plugins erweitert werden. Plugins registrieren sich über den ctx.betterSidebar-Dienst; ein Klick auf „Installieren“ kopiert den Installationsbefehl – fügen Sie ihn in einem Terminal ein, in dem Ihr DSH-Profil liegt, und führen Sie ihn aus.',
|
||||
addPluginsBrowseMore: 'Weitere Plugins auf GitHub durchsuchen (Topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Weitere Plugins auf GitHub durchsuchen (Topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Nach Plugin-Name oder -Beschreibung suchen…',
|
||||
addPluginsNoMatch: 'Keine passenden Plugins',
|
||||
addPluginsRecommended: 'Empfohlene Plugins',
|
||||
@@ -394,7 +394,7 @@ export const de: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: '„GitHub Workbench“-Tab: Repository-Baum + Issues / Pull requests / Actions mit vollen Schreibrechten — Issue/PR erstellen, kommentieren, bearbeiten, schließen/wieder öffnen, squash·merge·rebase-Merge (mit starker Bestätigung), CI erneut ausführen/abbrechen; der Repo-Umschalter listet automatisch zugreifbare Repos auf und durchsucht öffentliche; ohne better-sidebar fällt er auf ein eigenständiges rechtes Panel zurück',
|
||||
pluginMdExportDesc: 'Fügt einen „Export"-Button zur Markdown-Symbolleiste in better-sidebar hinzu: rendert die aktuelle .md per Klick in eigenständiges HTML (Tabellen/Codeblöcke/Mermaid-Diagramme inline, Layout folgt dem Vorschau-Theme) und speichert es neben der .md, oder exportiert über den Druckdialog als PDF',
|
||||
pluginCodeNavDesc: 'Code-Vorschau-Navigation: erkennt die Sprache am Dateityp und hebt die Syntax hervor, Symbol-Gliederung (Filter für Klassen/Methoden/Variablen + Sprung mit einem Klick) und Suche in der Datei (alle Treffer hervorgehoben, vor/zurück, Groß-/Kleinschreibung) — übernimmt die Code-Dateivorschau im better-sidebar-Editor',
|
||||
pluginSuhuangScrollDesc: 'Verbindet die lokale Suhuang Scroll Runtime mit den DSH-Einstellungen und better-sidebar für Modellkonfiguration, Verbindungstests und fortlaufende Bewertung; benötigt Suhuang Scroll Runtime und dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Verbindet die lokale Suhuang Scroll Runtime mit den DSH-Einstellungen und better-sidebar für Modellkonfiguration, Verbindungstests und fortlaufende Bewertung; benötigt Suhuang Scroll Runtime und dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Overleaf-Tab für better-sidebar: Login direkt über CDP-Browser (Chromium von Drittanbietern unterstützt), Projekliste/-wechsel, lokale git-Spiegel unter <workspace>/overleaf/, bidirektionaler git-Abgleich mit Read-only-API-Fallback und Dateivorschau über die Sidebar-Workbench',
|
||||
pluginGitRemotesDesc: '„Git-Remotes“-Tab: Branches/Upstream/ahead-behind ansehen, fetch (optional prune), ff-only pull und push erst nach Bestätigung im Tab. Ersetzt nicht den eingebauten Stagen/Commit-Tab und bietet weder force-push noch automatisches Push-Werkzeug für das Modell',
|
||||
pluginSentinelDesc: 'Bedingungsgesteuertes Wecksystem für Agenten: Datei-/Prozess-/Port-/HTTP-/Befehls-/Webhook-Sensoren wecken ruhende Sitzungen, wenn Bedingungen zutreffen; registriert einen „Sentinel“-Tab mit der serverweiten Überwachungstabelle',
|
||||
|
||||
@@ -388,7 +388,7 @@ export const fr: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Enregistrer un aperçu d’un type de fichier',
|
||||
addPluginsTabDesc: 'Les pages de la barre latérale (onglets) peuvent être étendues par des plugins. Les plugins s’enregistrent via le service ctx.betterSidebar ; cliquez sur « Installer » pour copier la commande d’installation, collez-la dans un terminal de l’environnement DSH et exécutez-la.',
|
||||
addPluginsViewerDesc: 'Les aperçus de fichiers peuvent être étendus par des plugins. Les plugins s’enregistrent via le service ctx.betterSidebar ; cliquez sur « Installer » pour copier la commande d’installation, collez-la dans un terminal de l’environnement DSH et exécutez-la.',
|
||||
addPluginsBrowseMore: 'Parcourir plus de plugins sur GitHub (topic : dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Parcourir plus de plugins sur GitHub (topic : dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Rechercher par nom / description de plugin…',
|
||||
addPluginsNoMatch: 'Aucun plugin correspondant',
|
||||
addPluginsRecommended: 'Plugins recommandés',
|
||||
@@ -401,7 +401,7 @@ export const fr: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Onglet « GitHub Workbench » de better-sidebar : arborescence du dépôt distant + Issues / Pull requests / Actions avec prise en charge complète en écriture — création d’issue/PR, commentaire, édition, fermeture/réouverture, merge squash·merge·rebase (confirmation renforcée), relance/annulation de la CI ; le sélecteur de dépôt liste automatiquement les dépôts accessibles et recherche les dépôts publics ; sans better-sidebar, il bascule sur un panneau latéral droit autonome',
|
||||
pluginMdExportDesc: 'Ajoute un bouton « Exporter » à la barre d’outils Markdown de better-sidebar : rend en un clic le .md courant en HTML autonome (tableaux/blocs de code/diagrammes Mermaid en ligne, mise en page fidèle au thème d’aperçu) et l’enregistre à côté du .md, ou exporte en PDF via la boîte de dialogue d’impression',
|
||||
pluginCodeNavDesc: 'Navigation de prévisualisation de code : détecte le langage selon le type de fichier et colore la syntaxe, plan des symboles (filtres classes/méthodes/variables + saut en un clic) et recherche dans le fichier (toutes les correspondances surlignées, précédent/suivant, respect de la casse) — prend en charge l’aperçu des fichiers de code dans l’éditeur better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Connecte le Runtime Suhuang Scroll local aux réglages DSH et à better-sidebar pour configurer le modèle, tester la connexion et contrôler la correction continue ; nécessite Suhuang Scroll Runtime et dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Connecte le Runtime Suhuang Scroll local aux réglages DSH et à better-sidebar pour configurer le modèle, tester la connexion et contrôler la correction continue ; nécessite Suhuang Scroll Runtime et dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Onglet Overleaf pour better-sidebar : connexion directe via navigateur CDP (Chromium tiers pris en charge), liste/sélection de projets, miroirs git locaux sous <workspace>/overleaf/, synchronisation git bidirectionnelle avec repli API en lecture seule, et aperçu des fichiers via l’atelier de la barre latérale',
|
||||
pluginGitRemotesDesc: 'Onglet Git Remotes de better-sidebar : branches/amonts/ahead-behind, fetch (avec prune possible), pull en ff-only, push seulement après confirmation. Ne remplace pas la mise en scène/les commits du Git intégré et ne fournit pas de force-push ni de push automatique par le modèle',
|
||||
pluginSentinelDesc: 'Système de réveil d’agent piloté par conditions : capteurs fichier/processus/port/HTTP/commande/webhook, les sessions en veille se réveillent automatiquement lorsque les conditions sont remplies ; enregistre l’onglet « Sentinel » affichant le tableau de surveillance global du serveur',
|
||||
|
||||
@@ -395,7 +395,7 @@ export const hi: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'फ़ाइल-प्रकार पूर्वावलोकन पंजीकृत करें',
|
||||
addPluginsTabDesc: 'साइडबार पृष्ठ (टैब) प्लगइन्स द्वारा विस्तारित हो सकते हैं। प्लगइन्स ctx.betterSidebar सेवा के माध्यम से पंजीकृत होते हैं; इंस्टॉल क्लिक करने पर इंस्टॉल कमांड कॉपी होता है — इसे उस टर्मिनल में पेस्ट करें जहाँ आपका DSH प्रोफ़ाइल है और चलाएँ।',
|
||||
addPluginsViewerDesc: 'फ़ाइल पूर्वावलोकक प्लगइन्स द्वारा विस्तारित हो सकते हैं। प्लगइन्स ctx.betterSidebar सेवा के माध्यम से पंजीकृत होते हैं; इंस्टॉल क्लिक करने पर इंस्टॉल कमांड कॉपी होता है — इसे उस टर्मिनल में पेस्ट करें जहाँ आपका DSH प्रोफ़ाइल है और चलाएँ।',
|
||||
addPluginsBrowseMore: 'GitHub पर और प्लगइन्स देखें (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'GitHub पर और प्लगइन्स देखें (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'प्लगइन नाम या विवरण से खोजें…',
|
||||
addPluginsNoMatch: 'कोई प्लगइन मेल नहीं खाता',
|
||||
addPluginsRecommended: 'अनुशंसित प्लगइन',
|
||||
@@ -408,7 +408,7 @@ export const hi: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'GitHub Workbench टैब: रिमोट रिपॉज़िटरी ट्री + Issues / Pull requests / Actions, पढ़ने के साथ-साथ पूर्ण लेखन समर्थन — Issue/PR बनाना, टिप्पणी करना, संपादन, बंद करना/पुनः खोलना, squash·merge·rebase मर्ज (पुष्टि अनिवार्य), CI पुनः चलाना/रद्द करना; रिपॉज़िटरी स्विचर स्वतः सुलभ रिपॉज़िटरी सूचीबद्ध करता है और सार्वजनिक रिपॉज़िटरी खोजता है; better-sidebar न होने पर स्वतंत्र दाईं ओर पैनल में फ़ॉलबैक होता है',
|
||||
pluginMdExportDesc: 'better-sidebar के Markdown टूलबार में "एक्सपोर्ट" बटन जोड़ता है: एक क्लिक में वर्तमान .md को स्टैंडअलोन HTML (टेबल/कोड ब्लॉक/Mermaid आरेख इनलाइन, लेआउट प्रीव्यू थीम का अनुसरण करता है) में रेंडर करके उसी फ़ोल्डर में सहेजता है, या प्रिंट डायलॉग से PDF निर्यात करता है',
|
||||
pluginCodeNavDesc: 'कोड प्रीव्यू नेविगेशन: फ़ाइल प्रकार से भाषा पहचानकर सिंटैक्स हाइलाइट, सिंबल आउटलाइन (क्लास/मेथड/वेरिएबल फ़िल्टर + एक-क्लिक जंप), फ़ाइल में खोज (सभी मैच हाइलाइट, पिछला/अगला, केस मैच) — better-sidebar एडिटर में कोड फ़ाइल प्रीव्यू संभालता है',
|
||||
pluginSuhuangScrollDesc: 'स्थानीय Suhuang Scroll Runtime को DSH सेटिंग्स और better-sidebar से जोड़ता है, ताकि मॉडल कॉन्फ़िगरेशन, कनेक्शन परीक्षण और निरंतर ग्रेडिंग नियंत्रण उपलब्ध हों; Suhuang Scroll Runtime और dsh-better-sidebar आवश्यक हैं',
|
||||
pluginSuhuangScrollDesc: 'स्थानीय Suhuang Scroll Runtime को DSH सेटिंग्स और better-sidebar से जोड़ता है, ताकि मॉडल कॉन्फ़िगरेशन, कनेक्शन परीक्षण और निरंतर ग्रेडिंग नियंत्रण उपलब्ध हों; Suhuang Scroll Runtime और dsh-apes-sidebar आवश्यक हैं',
|
||||
pluginBetterOverleafDesc: 'better-sidebar के लिए Overleaf टैब: सीधे CDP ब्राउज़र से लॉगिन (तीसरे पक्ष का Chromium समर्थित), प्रोजेक्ट सूची/स्विच, <workspace>/overleaf/ में स्थानीय git मिरर, रीड-ओनली API फ़ॉलबैक के साथ द्विदिश git सिंक, और फ़ाइल प्रीव्यू साइडबार वर्कबेंच से',
|
||||
pluginGitRemotesDesc: 'Git Remotes टैब: ब्रांच/अपस्ट्रीम/ahead-behind, fetch (वैकल्पिक prune), ff-only pull, और केवल टैब-में पुष्टि के बाद push। अंतर्निहित Git स्टेज/कमिट टैब को प्रतिस्थापित नहीं करता, और force-push या मॉडल ऑटो-push टूल नहीं देता',
|
||||
pluginSentinelDesc: 'स्थिति-संचालित एजेंट जागरूकता: फ़ाइल/प्रक्रिया/पोर्ट/http/कमांड/webhook सेंसर स्थितियाँ पूरी होने पर निष्क्रिय सत्र जगाते हैं; सर्वर-व्यापी वॉच टेबल के साथ "Sentinel" टैब पंजीकृत करता है',
|
||||
|
||||
@@ -393,7 +393,7 @@ export const id: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Daftarkan pratinjau tipe berkas',
|
||||
addPluginsTabDesc: 'Halaman sidebar (tab) dapat diperluas oleh plugin. Plugin mendaftar melalui layanan ctx.betterSidebar; klik Install menyalin perintah instalasi — tempel ke terminal tempat profil DSH Anda berada dan jalankan.',
|
||||
addPluginsViewerDesc: 'Pratinjau berkas dapat diperluas oleh plugin. Plugin mendaftar melalui layanan ctx.betterSidebar; klik Install menyalin perintah instalasi — tempel ke terminal tempat profil DSH Anda berada dan jalankan.',
|
||||
addPluginsBrowseMore: 'Jelajahi lebih banyak plugin di GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Jelajahi lebih banyak plugin di GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Cari berdasarkan nama / deskripsi plugin…',
|
||||
addPluginsNoMatch: 'Tidak ada plugin yang cocok',
|
||||
addPluginsRecommended: 'Plugin yang direkomendasikan',
|
||||
@@ -406,7 +406,7 @@ export const id: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Tab GitHub Workbench: pohon repo remote + Issues / Pull requests / Actions dengan dukungan tulis penuh — buat Issue/PR, komentar, edit, tutup/buka ulang, merge squash·merge·rebase (konfirmasi kuat), jalankan ulang/batalkan CI; pengalih repo otomatis mencantumkan repo yang dapat diakses dan mencari repo publik; tanpa better-sidebar otomatis beralih ke panel kanan mandiri',
|
||||
pluginMdExportDesc: 'Menambahkan tombol "Ekspor" ke bilah alat Markdown di better-sidebar: merender .md saat ini menjadi HTML mandiri dalam satu klik (tabel/blok kode/diagram Mermaid inline, tata letak mengikuti tema pratinjau) dan menyimpannya di folder yang sama, atau mengekspor ke PDF lewat dialog cetak',
|
||||
pluginCodeNavDesc: 'Navigasi pratinjau kode: mengenali bahasa dari jenis berkas dan menyorot sintaks, kerangka simbol (filter kelas/metode/variabel + lompat sekali klik), serta pencarian dalam berkas (sorot semua kecocokan, sebelum/berikutnya, peka huruf besar-kecil) — mengambil alih pratinjau berkas kode di editor better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Menghubungkan Suhuang Scroll Runtime lokal ke pengaturan DSH dan better-sidebar untuk konfigurasi model, uji koneksi, dan kontrol penilaian berkelanjutan; memerlukan Suhuang Scroll Runtime dan dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Menghubungkan Suhuang Scroll Runtime lokal ke pengaturan DSH dan better-sidebar untuk konfigurasi model, uji koneksi, dan kontrol penilaian berkelanjutan; memerlukan Suhuang Scroll Runtime dan dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Tab Overleaf untuk better-sidebar: login langsung lewat peramban CDP (mendukung Chromium pihak ketiga), daftar/pergantian proyek, mirror git lokal di <workspace>/overleaf/, sinkronisasi git dua arah dengan fallback API baca-saja, dan pratinjau berkas melalui workbench sidebar',
|
||||
pluginGitRemotesDesc: 'Tab Git Remotes: branch/upstream/ahead-behind, fetch (prune opsional), ff-only pull, dan push hanya setelah konfirmasi dalam tab. Tidak menggantikan tab stage/commit Git bawaan, dan tidak menawarkan force-push atau alat auto-push model',
|
||||
pluginSentinelDesc: 'Sistem bangun agen berbasis kondisi: sensor berkas/proses/port/http/perintah/webhook membangunkan sesi yang tidur saat kondisi terpicu; mendaftarkan tab "Sentinel" dengan tabel pengawasan server-wide',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* consumed by the better-locale override store (see `locales.ts` for the
|
||||
* zh/en/ja lookup chain and the `attachBetterLocale` contract).
|
||||
*
|
||||
* @module dsh-better-sidebar/client/locales-it
|
||||
* @module dsh-apes-sidebar/client/locales-it
|
||||
*/
|
||||
|
||||
export const it: Record<string, string> = {
|
||||
@@ -386,7 +386,7 @@ export const it: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Registri un’anteprima di tipo di file',
|
||||
addPluginsTabDesc: 'Le pagine della barra laterale (schede) possono essere estese dai plugin. I plugin si registrano tramite il servizio ctx.betterSidebar; cliccando Installa viene copiato il comando di installazione — lo incolli in un terminale dove risiede il profilo DSH e lo esegua.',
|
||||
addPluginsViewerDesc: 'I visualizzatori di file possono essere estesi dai plugin. I plugin si registrano tramite il servizio ctx.betterSidebar; cliccando Installa viene copiato il comando di installazione — lo incolli in un terminale dove risiede il profilo DSH e lo esegua.',
|
||||
addPluginsBrowseMore: 'Sfogli altri plugin su GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Sfogli altri plugin su GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Cerca per nome / descrizione del plugin…',
|
||||
addPluginsNoMatch: 'Nessun plugin corrispondente',
|
||||
addPluginsRecommended: 'Plugin consigliati',
|
||||
@@ -399,7 +399,7 @@ export const it: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Scheda GitHub Workbench: albero del repository remoto + Issues / Pull requests / Actions con pieno supporto in scrittura — creazione di issue/PR, commenti, modifica, chiusura/riapertura, merge squash·merge·rebase (conferma rafforzata), riavvio/annullamento della CI; il selettore dei repository elenca automaticamente quelli accessibili e cerca tra quelli pubblici; senza better-sidebar esegue il fallback a un pannello laterale destro indipendente',
|
||||
pluginMdExportDesc: 'Aggiunge un pulsante «Esporta» alla barra degli strumenti Markdown di better-sidebar: con un clic esegue il rendering del .md corrente in HTML autonomo (tabelle/blocchi di codice/diagrammi Mermaid in linea, layout fedele al tema di anteprima) e lo salva accanto al .md, oppure esporta in PDF tramite la finestra di stampa',
|
||||
pluginCodeNavDesc: 'Navigazione dell’anteprima del codice: rileva il linguaggio dal tipo di file ed evidenzia la sintassi, struttura dei simboli (filtri classi/metodi/variabili + salto con un clic) e ricerca nel file (tutte le corrispondenze evidenziate, precedente/successiva, maiuscole/minuscole) — gestisce l’anteprima dei file di codice nell’editor better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Collega il Runtime Suhuang Scroll locale alle impostazioni DSH e a better-sidebar per configurare il modello, testare la connessione e controllare la correzione continua; richiede Suhuang Scroll Runtime e dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Collega il Runtime Suhuang Scroll locale alle impostazioni DSH e a better-sidebar per configurare il modello, testare la connessione e controllare la correzione continua; richiede Suhuang Scroll Runtime e dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Tab Overleaf per better-sidebar: accesso diretto tramite browser CDP (supporta Chromium di terze parti), elenco/cambio progetti, mirror git locali in <workspace>/overleaf/, sincronizzazione git bidirezionale con fallback API di sola lettura e anteprima dei file tramite la workbench della barra laterale',
|
||||
pluginGitRemotesDesc: 'Scheda Git Remotes: rami/upstream/ahead-behind, fetch (prune opzionale), pull ff-only e push solo dopo una conferma nella scheda. Non sostituisce la scheda stage/commit integrata di Git, e non offre force-push o uno strumento di push automatico del modello',
|
||||
pluginSentinelDesc: 'Sistema di risveglio dell’agente guidato da condizioni: sensori file/processo/porta/HTTP/comando/webhook risvegliano le sessioni dormienti quando le condizioni si verificano; registra una scheda «Sentinella» con la tabella di monitoraggio globale del server',
|
||||
|
||||
@@ -395,7 +395,7 @@ export const ja: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: '新しいファイル種別プレビューを登録',
|
||||
addPluginsTabDesc: 'サイドバーページ(Tab)はプラグインで拡張可能。プラグインは ctx.betterSidebar サービス経由で登録。「インストール」をクリックしてインストールコマンドをコピー、DSH 環境のターミナルに貼り付けて実行。',
|
||||
addPluginsViewerDesc: 'ファイルプレビューアーはプラグインで拡張可能。プラグインは ctx.betterSidebar サービス経由で登録。「インストール」をクリックしてインストールコマンドをコピー、DSH 環境のターミナルに貼り付けて実行。',
|
||||
addPluginsBrowseMore: 'GitHub でプラグинをさらに閲覧(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'GitHub でプラグинをさらに閲覧(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'プラグイン名 / 説明で検索…',
|
||||
addPluginsNoMatch: '一致するプラグインなし',
|
||||
addPluginsRecommended: '推奨プラグイン',
|
||||
@@ -407,7 +407,7 @@ export const ja: Record<string, string> = {
|
||||
pluginFlowglassDesc: 'ライブセッションフローグラフ:ユーザー、アシスタント、ツール呼び出しの 3 レーン泳道、並列グループ、サブエージェント支線、ドリルダウン、ライブ状態をサポート。better-sidebar インストール時にネイティブ「Flowglass」Tab を登録、未インストール時は独立ドロワーを保持',
|
||||
pluginGitForgeDesc: 'better-sidebar「Git Forge」Tab:GitHub/Gitea 等 Forge アカウントライブラリ + プロジェクト単位の認可 + push ポリシー硬核拒絶。token はローカル secrets のみ、モデルコンテキストに入らない。読み取り専用 GitForge ツールと agent HTTPS credential helper を提供',
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar「GitHub ワークベンチ」タブ:リモートリポジトリのツリー + Issues / Pull requests / Actions タブ。読み取りに加え、Issue・PR の作成、コメント、編集、クローズ/再オープン、squash・merge・rebase マージ(強確認)、CI の再実行/キャンセルに対応。リポジトリ切替ポップアップはアクセス可能なリポジトリを自動取得し、公開リポジトリの検索にも対応。better-sidebar 未導入時は独立右パネルへ自動フォールバック',
|
||||
pluginSuhuangScrollDesc: 'ローカルの Suhuang Scroll Runtime を DSH 設定と better-sidebar に接続し、モデル設定、接続テスト、連続採点の操作を提供。Suhuang Scroll Runtime と dsh-better-sidebar が必要',
|
||||
pluginSuhuangScrollDesc: 'ローカルの Suhuang Scroll Runtime を DSH 設定と better-sidebar に接続し、モデル設定、接続テスト、連続採点の操作を提供。Suhuang Scroll Runtime と dsh-apes-sidebar が必要',
|
||||
pluginBetterOverleafDesc: 'better-sidebar の Overleaf タブ:CDP ブラウザーに直接接続してログイン(サードパーティー Chromium 対応)、プロジェクト一覧/切替、<workspace>/overleaf/ のローカル git ミラー、双方向 git 同期(API 読み取り専用フォールバック)、ファイルプレビューはサイドバーのワークベンチを利用',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git リモート Tab:ブランチ/アップストリーム/ahead-behind 表示、fetch(prune 可)、ff-only pull、確認後のみ push。内蔵 Git のステージ/コミットは置き換えず、force-push やモデル自動 push ツールは提供しない',
|
||||
pluginSentinelDesc: '条件駆動の agent 起動システム:ファイル/プロセス/ポート/HTTP/コマンド/webhook センサーが条件達成時に休眠会話を自動起動。「Sentinel」Tab を登録しサーバー全体の監視テーブルを表示',
|
||||
|
||||
@@ -387,7 +387,7 @@ export const ko: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: '새 파일 형식 미리보기 등록',
|
||||
addPluginsTabDesc: '사이드바 페이지(Tab)는 플러그인으로 확장할 수 있습니다. 플러그인은 ctx.betterSidebar 서비스를 통해 등록합니다. "설치"를 클릭하면 설치 명령이 복사되며, DSH가 설치된 환경의 터미널에 붙여넣어 실행하세요.',
|
||||
addPluginsViewerDesc: '파일 미리보기는 플러그인으로 확장할 수 있습니다. 플러그인은 ctx.betterSidebar 서비스를 통해 등록합니다. "설치"를 클릭하면 설치 명령이 복사되며, DSH가 설치된 환경의 터미널에 붙여넣어 실행하세요.',
|
||||
addPluginsBrowseMore: 'GitHub에서 더 많은 플러그인 보기(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'GitHub에서 더 많은 플러그인 보기(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: '플러그인 이름 / 설명 검색…',
|
||||
addPluginsNoMatch: '일치하는 플러그인 없음',
|
||||
addPluginsRecommended: '추천 플러그인',
|
||||
@@ -400,7 +400,7 @@ export const ko: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar "GitHub Workbench" Tab: 원격 저장소 트리 + Issues / Pull requests / Actions 탭. 읽기 외에 Issue·PR 생성, 댓글, 편집, 닫기/다시 열기, squash·merge·rebase 병합(강한 확인), CI 재실행/취소를 지원합니다. 저장소 전환 팝업은 접근 가능한 저장소를 자동으로 가져오고 공개 저장소 검색도 지원합니다. better-sidebar 미설치 시 독립 우측 패널로 자동 폴백합니다',
|
||||
pluginMdExportDesc: 'better-sidebar의 Markdown 툴바에 "내보내기" 버튼을 추가: 클릭 한 번으로 현재 .md를 독립 실행형 HTML(표/코드 블록/Mermaid 다이어그램 인라인, 레이아웃은 미리보기 테마 따름)로 렌더링해 같은 폴더에 저장하거나, 인쇄 대화상자로 PDF를 내보냅니다',
|
||||
pluginCodeNavDesc: '코드 미리보기 내비게이션: 파일 형식으로 언어를 자동 인식해 구문 강조, 심볼 아웃라인(클래스/메서드/변수 필터 + 원클릭 이동), 파일 내 검색(모든 일치 강조, 이전/다음, 대소문자 구분) — better-sidebar 편집기의 코드 파일 미리보기를 대신 맡습니다',
|
||||
pluginSuhuangScrollDesc: '로컬 Suhuang Scroll Runtime을 DSH 설정과 better-sidebar에 연결하여 모델 구성, 연결 테스트, 연속 채점 제어를 제공합니다. Suhuang Scroll Runtime과 dsh-better-sidebar가 필요합니다',
|
||||
pluginSuhuangScrollDesc: '로컬 Suhuang Scroll Runtime을 DSH 설정과 better-sidebar에 연결하여 모델 구성, 연결 테스트, 연속 채점 제어를 제공합니다. Suhuang Scroll Runtime과 dsh-apes-sidebar가 필요합니다',
|
||||
pluginBetterOverleafDesc: 'better-sidebar의 Overleaf 탭: CDP 브라우저 직접 로그인(서드파티 Chromium 지원), 프로젝트 목록/전환, <workspace>/overleaf/ 로컬 git 미러, 읽기 전용 API 폴백이 있는 양방향 git 동기화, 파일 미리보기는 사이드바 워크벤치 사용',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git 원격 Tab: 브랜치/업스트림/ahead-behind 확인, fetch(prune 가능), ff-only pull, 확인 후에만 push. 내장 Git의 스테이징/커밋을 대체하지 않으며, force-push나 모델 자동 push도 제공하지 않습니다',
|
||||
pluginSentinelDesc: '조건 기반 agent 웨이크업 시스템: 파일/프로세스/포트/HTTP/명령/webhook 센서가 조건을 충족하면 휴면 세션을 자동으로 깨웁니다. "센티널(哨兵)" Tab을 등록하여 서버 전역 모니터링 표를 보여줍니다',
|
||||
|
||||
@@ -393,7 +393,7 @@ export const nl: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Een bestandstype-preview registreren',
|
||||
addPluginsTabDesc: 'Zijbalkpagina\'s (tabbladen) kunnen door plugins worden uitgebreid. Plugins registreren via de ctx.betterSidebar-service; op Installeren klikken kopieert het installatiecommando — plak het in een terminal waar uw DSH-profiel zich bevindt en voer het uit.',
|
||||
addPluginsViewerDesc: 'Bestandsviewers kunnen door plugins worden uitgebreid. Plugins registreren via de ctx.betterSidebar-service; op Installeren klikken kopieert het installatiecommando — plak het in een terminal waar uw DSH-profiel zich bevindt en voer het uit.',
|
||||
addPluginsBrowseMore: 'Meer plugins bekijken op GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Meer plugins bekijken op GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Zoek op plugin-naam of -beschrijving…',
|
||||
addPluginsNoMatch: 'Geen plugins komen overeen',
|
||||
addPluginsRecommended: 'Aanbevolen plugins',
|
||||
@@ -406,7 +406,7 @@ export const nl: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'GitHub Workbench-tab: externe repositoryboom + Issues / Pull requests / Actions met volledige schrijfontsteuning — issue/PR aanmaken, reageren, bewerken, sluiten/heropenen, squash·merge·rebase-merge (sterke bevestiging), CI opnieuw uitvoeren/annuleren; de repo-wisselaar toont automatisch toegankelijke repo’s en doorzoekt openbare; zonder better-sidebar valt het terug op een zelfstandig rechterpaneel',
|
||||
pluginMdExportDesc: 'Voegt een knop «Exporteren» toe aan de Markdown-werkbalk van better-sidebar: rendert de huidige .md in één klik naar zelfstandige HTML (tabellen/codeblokken/Mermaid-diagrammen inline, lay-out volgt het voorbeeldthema) en slaat die naast het .md op, of exporteert via het afdrukvenster naar PDF',
|
||||
pluginCodeNavDesc: 'Codevoorbeeldnavigatie: detecteert de taal op bestandstype en kleurt de syntaxis, symbooloverzicht (filters voor klassen/methoden/variabelen + sprong met één klik) en zoeken in het bestand (alle treffers gemarkeerd, vorige/volgende, hoofdlettergevoelig) — neemt het codevoorbeeld in de better-sidebar-editor over',
|
||||
pluginSuhuangScrollDesc: 'Verbindt de lokale Suhuang Scroll Runtime met DSH-instellingen en better-sidebar voor modelconfiguratie, verbindingstests en doorlopende beoordelingsbediening; vereist Suhuang Scroll Runtime en dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Verbindt de lokale Suhuang Scroll Runtime met DSH-instellingen en better-sidebar voor modelconfiguratie, verbindingstests en doorlopende beoordelingsbediening; vereist Suhuang Scroll Runtime en dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Overleaf-tabblad voor better-sidebar: directe browserlogin via CDP (ondersteunt Chromium van derden), projectlijst/wisselen, lokale git-spiegels onder <workspace>/overleaf/, tweerichtingssynchronisatie met read-only-API-terugval en bestandsvoorbeeld via de sidebar-werkbank',
|
||||
pluginGitRemotesDesc: 'Git Remotes-tabblad: branch/upstream/ahead-behind, fetch (optioneel prune), ff-only pull, en push pas na een bevestiging in het tabblad. Vervangt het ingebouwde Git stage/commit-tabblad niet, en biedt geen force-push of een model-auto-push-tool',
|
||||
pluginSentinelDesc: 'Conditie-gedreven agent-wakeupsysteem: bestands/proces/poort/http/command/webhook-sensoren wekken slapende sessies wanneer condities af gaan; registreert een "Sentinel"-tabblad met de serverbrede watch-tabel',
|
||||
|
||||
@@ -397,7 +397,7 @@ export const pl: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Zarejestruj podgląd typu pliku',
|
||||
addPluginsTabDesc: 'Strony panelu bocznego (karty) mogą być rozszerzane przez wtyczki. Wtyczki rejestrują się przez usługę ctx.betterSidebar; kliknięcie „Zainstaluj” kopiuje polecenie instalacji — wklej je do terminala tam, gdzie żyje Twój profil DSH, i uruchom.',
|
||||
addPluginsViewerDesc: 'Podglądy plików mogą być rozszerzane przez wtyczki. Wtyczki rejestrują się przez usługę ctx.betterSidebar; kliknięcie „Zainstaluj” kopiuje polecenie instalacji — wklej je do terminala tam, gdzie żyje Twój profil DSH, i uruchom.',
|
||||
addPluginsBrowseMore: 'Przeglądaj więcej wtyczek na GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Przeglądaj więcej wtyczek na GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Szukaj po nazwie lub opisie wtyczki…',
|
||||
addPluginsNoMatch: 'Brak pasujących wtyczek',
|
||||
addPluginsRecommended: 'Zalecane wtyczki',
|
||||
@@ -410,7 +410,7 @@ export const pl: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Karta GitHub Workbench: drzewo zdalnego repozytorium + Issues / Pull requests / Actions z pełną obsługą zapisu — tworzenie issue/PR, komentowanie, edycja, zamykanie/ponowne otwieranie, scalanie squash·merge·rebase (mocne potwierdzenie), ponowne uruchomienie/anulowanie CI; przełącznik repozytoriów automatycznie wyświetla dostępne repozytoria i wyszukuje publiczne; bez better-sidebar następuje przejście na samodzielny panel po prawej stronie',
|
||||
pluginMdExportDesc: 'Dodaje przycisk „Eksportuj" do paska narzędzi Markdown w better-sidebar: jednym kliknięciem renderuje bieżący .md do samodzielnego HTML (tabele/bloki kodu/diagramy Mermaid w treści, układ zgodny z motywem podglądu) i zapisuje obok pliku .md albo eksportuje do PDF przez okno drukowania',
|
||||
pluginCodeNavDesc: 'Nawigacja podglądu kodu: rozpoznaje język po typie pliku i koloruje składnię, konspekt symboli (filtry klas/metod/zmiennych + skok jednym kliknięciem) oraz wyszukiwanie w pliku (podświetlanie wszystkich trafień, poprzedni/następny, rozróżnianie wielkości liter) — przejmuje podgląd plików kodu w edytorze better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Łączy lokalny Suhuang Scroll Runtime z ustawieniami DSH i better-sidebar, zapewniając konfigurację modelu, test połączenia i sterowanie ciągłym ocenianiem; wymaga Suhuang Scroll Runtime i dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Łączy lokalny Suhuang Scroll Runtime z ustawieniami DSH i better-sidebar, zapewniając konfigurację modelu, test połączenia i sterowanie ciągłym ocenianiem; wymaga Suhuang Scroll Runtime i dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Karta Overleaf dla better-sidebar: logowanie bezpośrednio przez przeglądarkę CDP (obsługa Chromium innych firm), lista/przełączanie projektów, lokalne kopie lustrzane git w <workspace>/overleaf/, dwukierunkowa synchronizacja git z awaryjnym API tylko do odczytu oraz podgląd plików przez warsztat panelu bocznego',
|
||||
pluginGitRemotesDesc: 'Karta Git Remotes: gałąź/nadrzędne/ahead-behind, fetch (z opcjonalnym prune), ff-only pull i push dopiero po potwierdzeniu w karcie. Nie zastępuje wbudowanej karty Git stage/commit i nie oferuje force-push ani narzędzia auto-push modelu',
|
||||
pluginSentinelDesc: 'Budzenie agenta sterowane warunkami: czujniki plików/procesów/portów/HTTP/poleceń/webhooków wybudzają uśpione sesje, gdy warunek zajdzie; rejestruje kartę „Sentinel” z ogólnoserwerową tabelą obserwacji',
|
||||
|
||||
@@ -378,7 +378,7 @@ export const pt: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Registrar uma pré-visualização de tipo de arquivo',
|
||||
addPluginsTabDesc: 'As páginas da barra lateral (abas) podem ser estendidas por plugins. Os plugins registram pelo serviço ctx.betterSidebar; clicar em Instalar copia o comando de instalação — cole-o em um terminal onde seu perfil do DSH vive e execute.',
|
||||
addPluginsViewerDesc: 'Os visualizadores de arquivos podem ser estendidos por plugins. Os plugins registram pelo serviço ctx.betterSidebar; clicar em Instalar copia o comando de instalação — cole-o em um terminal onde seu perfil do DSH vive e execute.',
|
||||
addPluginsBrowseMore: 'Navegue por mais plugins no GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Navegue por mais plugins no GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Pesquisar por nome ou descrição do plugin…',
|
||||
addPluginsNoMatch: 'Nenhum plugin corresponde',
|
||||
addPluginsRecommended: 'Plugins recomendados',
|
||||
@@ -391,7 +391,7 @@ export const pt: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Aba GitHub Workbench: árvore do repositório remoto + Issues / Pull requests / Actions com suporte completo de escrita — criar Issue/PR, comentar, editar, fechar/reabrir, merge squash·merge·rebase (confirmação reforçada), reexecutar/cancelar CI; o seletor de repositórios lista automaticamente os repositórios acessíveis e busca nos públicos; sem better-sidebar, faz fallback para um painel lateral direito independente',
|
||||
pluginMdExportDesc: 'Adiciona um botão «Exportar» à barra de ferramentas do Markdown no better-sidebar: com um clique, renderiza o .md atual em HTML autônomo (tabelas/blocos de código/diagramas Mermaid embutidos, layout seguindo o tema de pré-visualização) e salva na mesma pasta, ou exporta para PDF pela caixa de impressão',
|
||||
pluginCodeNavDesc: 'Navegação de pré-visualização de código: detecta a linguagem pelo tipo de arquivo e destaca a sintaxe, contorno de símbolos (filtros de classes/métodos/variáveis + salto em um clique) e busca no arquivo (todas as ocorrências destacadas, anterior/próxima, diferenciando maiúsculas) — assume a pré-visualização de arquivos de código no editor do better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Conecta o Suhuang Scroll Runtime local às configurações do DSH e ao better-sidebar para configurar o modelo, testar a conexão e controlar a correção contínua; requer Suhuang Scroll Runtime e dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Conecta o Suhuang Scroll Runtime local às configurações do DSH e ao better-sidebar para configurar o modelo, testar a conexão e controlar a correção contínua; requer Suhuang Scroll Runtime e dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Aba Overleaf para better-sidebar: login direto pelo navegador via CDP (compatível com Chromium de terceiros), lista/troca de projetos, espelhos git locais em <workspace>/overleaf/, sincronização git bidirecional com fallback de API somente leitura e pré-visualização de arquivos pela bancada da barra lateral',
|
||||
pluginGitRemotesDesc: 'Aba de remotos Git: branch/upstream/ahead-behind, fetch (prune opcional), pull ff-only e push apenas após confirmar na aba. Não substitui a aba interna de stage/commit do Git e não oferece force-push nem push automático pelo modelo',
|
||||
pluginSentinelDesc: 'Despertar de agentes dirigido por condições: sensores de arquivo/processo/porta/HTTP/comando/webhook acordam sessões adormecidas quando as condições disparam; registra uma aba "Sentinelas" com a tabela de monitoramento global do servidor',
|
||||
|
||||
@@ -393,7 +393,7 @@ export const ru: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Зарегистрировать предпросмотр типа файлов',
|
||||
addPluginsTabDesc: 'Страницы боковой панели (вкладки) расширяются плагинами. Плагины регистрируются через службу ctx.betterSidebar; щелчок по «Установить» копирует команду — вставьте её в терминал, где находится профиль DSH, и выполните.',
|
||||
addPluginsViewerDesc: 'Просмотрщики файлов расширяются плагинами. Плагины регистрируются через службу ctx.betterSidebar; щелчок по «Установить» копирует команду — вставьте её в терминал, где находится профиль DSH, и выполните.',
|
||||
addPluginsBrowseMore: 'Найти больше плагинов на GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Найти больше плагинов на GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Поиск по имени или описанию плагина…',
|
||||
addPluginsNoMatch: 'Нет совпадающих плагинов',
|
||||
addPluginsRecommended: 'Рекомендуемые плагины',
|
||||
@@ -406,7 +406,7 @@ export const ru: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Вкладка «GitHub Workbench»: дерево удалённого репозитория + Issues / Pull requests / Actions с полной поддержкой записи — создание Issue/PR, комментарии, редактирование, закрытие/повторное открытие, merge squash·merge·rebase (с сильным подтверждением), перезапуск/отмена CI; переключатель репозиториев автоматически показывает доступные репозитории и ищет по публичным; без better-sidebar используется отдельная правая панель',
|
||||
pluginMdExportDesc: 'Добавляет кнопку «Экспорт» на панель инструментов Markdown в better-sidebar: одним кликом рендерит текущий .md в самостоятельный HTML (таблицы/блоки кода/Mermaid-диаграммы встроены, вёрстка следует теме предпросмотра) и сохраняет рядом с .md либо экспортирует в PDF через диалог печати',
|
||||
pluginCodeNavDesc: 'Навигация по предпросмотру кода: определяет язык по типу файла и подсвечивает синтаксис, схема символов (фильтры классов/методов/переменных + переход в один клик) и поиск по файлу (подсветка всех совпадений, назад/вперёд, учёт регистра) — берёт на себя предпросмотр файлов кода в редакторе better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Подключает локальный Suhuang Scroll Runtime к настройкам DSH и better-sidebar для настройки модели, проверки соединения и управления непрерывной проверкой; требуются Suhuang Scroll Runtime и dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Подключает локальный Suhuang Scroll Runtime к настройкам DSH и better-sidebar для настройки модели, проверки соединения и управления непрерывной проверкой; требуются Suhuang Scroll Runtime и dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Вкладка Overleaf для better-sidebar: вход напрямую через CDP-браузер (поддержка стороннего Chromium), список/переключение проектов, локальные git-зеркала в <workspace>/overleaf/, двунаправленная синхронизация git с откатом к API только для чтения, просмотр файлов через рабочую панель сайдбара',
|
||||
pluginGitRemotesDesc: 'Вкладка Git Remotes: просмотр веток/апстрима/ahead-behind, fetch (с возможностью prune), ff-only pull и push только после подтверждения во вкладке. Не заменяет встроенную вкладку Git (индексирование/коммит), не предоставляет force-push и инструмент авто-push для модели',
|
||||
pluginSentinelDesc: 'Система пробуждения агента по условиям: сенсоры файлов/процессов/портов/HTTP/команд/webhook будят спящие сессии при срабатывании; регистрирует вкладку «Sentinel» с глобальной таблицей наблюдений сервера',
|
||||
|
||||
@@ -378,7 +378,7 @@ export const sv: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Registrera en filtypsförhandsgranskning',
|
||||
addPluginsTabDesc: 'Sidopanelens sidor (flikar) kan utökas av plugins. Plugins registreras via ctx.betterSidebar-tjänsten; att klicka på Installera kopierar installationskommandot — klistra in det i en terminal där er DSH-profil lever och kör det.',
|
||||
addPluginsViewerDesc: 'Filförhandsgranskare kan utökas av plugins. Plugins registreras via ctx.betterSidebar-tjänsten; att klicka på Installera kopierar installationskommandot — klistra in det i en terminal där er DSH-profil lever och kör det.',
|
||||
addPluginsBrowseMore: 'Bläddra bland fler plugins på GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Bläddra bland fler plugins på GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Sök på plugin-namn eller beskrivning…',
|
||||
addPluginsNoMatch: 'Inga plugins matchar',
|
||||
addPluginsRecommended: 'Rekommenderade plugins',
|
||||
@@ -391,7 +391,7 @@ export const sv: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'GitHub Workbench-flik: fjärrrepo-träd + Issues / Pull requests / Actions med fullt skrivstöd — skapa issue/PR, kommentera, redigera, stäng/öppna igen, squash·merge·rebase-merge (stark bekräftelse), kör om/avbryt CI; repoväxlaren listar automatiskt tillgängliga repon och söker i publika; utan better-sidebar växlar den till en fristående höger panel',
|
||||
pluginMdExportDesc: 'Lägger till en «Exportera»-knapp i Markdown-verktygsfältet i better-sidebar: renderar nuvarande .md till fristående HTML i ett klick (tabeller/kodblock/Mermaid-diagram inline, layout följer förhandsvisningstemat) och sparar bredvid .md-filen, eller exporterar till PDF via utskriftsdialogen',
|
||||
pluginCodeNavDesc: 'Kodförhandsvisningsnavigering: känner automatiskt av språket från filtypen och färglägger syntaxen, symbolöversikt (filter för klasser/metoder/variabler + hopp med ett klick) och filsökning (markera alla träffar, föregående/nästa, skiftlägeskänsligt) — tar över kodfilförhandsvisning i better-sidebar-redigeraren',
|
||||
pluginSuhuangScrollDesc: 'Ansluter den lokala Suhuang Scroll Runtime till DSH-inställningar och better-sidebar för modellkonfiguration, anslutningstest och styrning av kontinuerlig rättning; kräver Suhuang Scroll Runtime och dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Ansluter den lokala Suhuang Scroll Runtime till DSH-inställningar och better-sidebar för modellkonfiguration, anslutningstest och styrning av kontinuerlig rättning; kräver Suhuang Scroll Runtime och dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Overleaf-flik för better-sidebar: direktinloggning via CDP-webbläsare (stöd för tredjeparts-Chromium), projektlista/byte, lokala git-speglar under <workspace>/overleaf/, dubbelriktad git-synk med read-only-API-fallback och förhandsvisning av filer via sidofältets workbench',
|
||||
pluginGitRemotesDesc: 'Git Remotes-flik: gren/upstream/ahead-behind, fetch (valbar prune), ff-only pull och push endast efter bekräftelse i fliken. Ersätter inte den inbyggda Git-köa/commit-fliken, och erbjuder inte force-push eller ett model-auto-push-verktyg',
|
||||
pluginSentinelDesc: 'Villkorsdriven agentväckning: fil-/process-/port-/http-/kommando-/webhook-sensorer väcker vilande sessioner när villkor utlöses; registrerar en "Sentinel"-flik med serverns globala bevakningstabell',
|
||||
|
||||
@@ -395,7 +395,7 @@ export const th: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'ลงทะเบียนพรีวิวประเภทไฟล์',
|
||||
addPluginsTabDesc: 'หน้าแถบด้านข้าง (tab) สามารถขยายได้ด้วยปลั๊กอิน ปลั๊กอินลงทะเบียนผ่านบริการ ctx.betterSidebar; การคลิก Install จะคัดลอกคำสั่งติดตั้ง — วางลงในเทอร์มินัลที่ DSH profile ของคุณอยู่แล้วเรียกใช้',
|
||||
addPluginsViewerDesc: 'ตัวพรีวิวไฟล์สามารถขยายได้ด้วยปลั๊กอิน ปลั๊กอินลงทะเบียนผ่านบริการ ctx.betterSidebar; การคลิก Install จะคัดลอกคำสั่งติดตั้ง — วางลงในเทอร์มินัลที่ DSH profile ของคุณอยู่แล้วเรียกใช้',
|
||||
addPluginsBrowseMore: 'เรียกดูปลั๊กอินเพิ่มเติมบน GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'เรียกดูปลั๊กอินเพิ่มเติมบน GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'ค้นหาตามชื่อหรือคำอธิบายปลั๊กอิน…',
|
||||
addPluginsNoMatch: 'ไม่มีปลั๊กอินที่ตรง',
|
||||
addPluginsRecommended: 'ปลั๊กอินแนะนำ',
|
||||
@@ -408,7 +408,7 @@ export const th: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'แท็บ GitHub Workbench: โครงสร้าง repo รีโมต + Issues / Pull requests / Actions พร้อมรองรับการเขียนครบวงจร — สร้าง Issue/PR, แสดงความคิดเห็น, แก้ไข, ปิด/เปิดใหม่, รวมแบบ squash·merge·rebase (ยืนยันก่อนเสมอ), รัน/ยกเลิก CI ใหม่; ตัวสลับ repo จะดึงรายการ repo ที่มีสิทธิ์เข้าถึงโดยอัตโนมัติและค้นหา repo สาธารณะได้; หากไม่ได้ติดตั้ง better-sidebar จะสลับไปใช้แผงด้านขวาแบบสแตนด์อโลนอัตโนมัติ',
|
||||
pluginMdExportDesc: 'เพิ่มปุ่ม "ส่งออก" ในแถบเครื่องมือ Markdown ของ better-sidebar: เรนเดอร์ .md ปัจจุบันเป็น HTML แบบสแตนด์อโลนในคลิกเดียว (ตาราง/บล็อกโค้ด/ไดอะแกรม Mermaid แบบอินไลน์ เลย์เอาต์ตามธีมพรีวิว) แล้วบันทึกไว้โฟลเดอร์เดียวกัน หรือส่งออกเป็น PDF ผ่านกล่องโต้ตอบการพิมพ์',
|
||||
pluginCodeNavDesc: 'การนำทางพรีวิวโค้ด: ระบุภาษาอัตโนมัติจากประเภทไฟล์และไฮไลต์ไวยากรณ์ โครงร่างสัญลักษณ์ (กรองคลาส/เมธอด/ตัวแปร + กระโดดคลิกเดียว) และค้นหาในไฟล์ (ไฮไลต์ทุกจุดที่ตรง ก่อนหน้า/ถัดไป แยกตัวพิมพ์ใหญ่เล็ก) — รับช่วงพรีวิวไฟล์โค้ดในตัวแก้ไข better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'เชื่อมต่อ Suhuang Scroll Runtime ในเครื่องกับการตั้งค่า DSH และ better-sidebar สำหรับการกำหนดค่าโมเดล การทดสอบการเชื่อมต่อ และการควบคุมการตรวจงานต่อเนื่อง โดยต้องติดตั้ง Suhuang Scroll Runtime และ dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'เชื่อมต่อ Suhuang Scroll Runtime ในเครื่องกับการตั้งค่า DSH และ better-sidebar สำหรับการกำหนดค่าโมเดล การทดสอบการเชื่อมต่อ และการควบคุมการตรวจงานต่อเนื่อง โดยต้องติดตั้ง Suhuang Scroll Runtime และ dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'แท็บ Overleaf สำหรับ better-sidebar: เข้าสู่ระบบผ่านเบราว์เซอร์ CDP โดยตรง (รองรับ Chromium ของบุคคลที่สาม) รายการ/สลับโปรเจกต์ มิเรอร์ git ภายในเครื่องที่ <workspace>/overleaf/ ซิงก์ git สองทางพร้อมสำรองแบบ API อ่านอย่างเดียว และดูตัวอย่างไฟล์ผ่านเวิร์กเบนช์ของแถบข้าง',
|
||||
pluginGitRemotesDesc: 'tab Git Remotes: branch/upstream/ahead-behind, fetch (optional prune), ff-only pull และ push หลังการยืนยันใน tab เท่านั้น ไม่แทนที่ tab stage/commit ของ Git แบบ built-in และไม่เสนอ force-push หรือเครื่องมือ auto-push ของโมเดล',
|
||||
pluginSentinelDesc: 'การปลุกตัวแทนที่ขับเคลื่อนด้วยเงื่อนไข: เซนเซอร์ file/process/port/http/command/webhook ปลุกเซสชันที่หลับเมื่อเงื่อนไขเกิดขึ้น; ลงทะเบียน tab "Sentinel" พร้อมตารางเฝ้าระวังทั่วทั้งเซิร์ฟเวอร์',
|
||||
|
||||
@@ -395,7 +395,7 @@ export const tr: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Yeni bir dosya türü önizlemesi kaydet',
|
||||
addPluginsTabDesc: 'Kenar çubuğu sayfaları (sekmeler) eklentilerce genişletilebilir. Eklentiler ctx.betterSidebar hizmeti aracılığıyla kaydolur; Yükle’ye tıklamak kurulum komutunu kopyalar — DSH profilinizin yaşadığı bir terminale yapıştırın ve çalıştırın.',
|
||||
addPluginsViewerDesc: 'Dosya önizleyicileri eklentilerce genişletilebilir. Eklentiler ctx.betterSidebar hizmeti aracılığıyla kaydolur; Yükle’ye tıklamak kurulum komutunu kopyalar — DSH profilinizin yaşadığı bir terminale yapıştırın ve çalıştırın.',
|
||||
addPluginsBrowseMore: 'GitHub’da daha fazla eklentiye göz atın (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'GitHub’da daha fazla eklentiye göz atın (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Eklenti adı / açıklamasına göre ara…',
|
||||
addPluginsNoMatch: 'Eşleşen eklenti yok',
|
||||
addPluginsRecommended: 'Önerilen eklentiler',
|
||||
@@ -408,7 +408,7 @@ export const tr: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'GitHub Workbench sekmesi: uzak depo ağacı + Issues / Pull requests / Actions tam yazma desteğiyle — Issue/PR oluşturma, yorum yapma, düzenleme, kapatma/yeniden açma, squash·merge·rebase birleştirme (güçlü onay), CI’yi yeniden çalıştırma/iptal etme; repo değiştirici erişilebilir depoları otomatik listeler ve genel depolarda arama yapar; better-sidebar yoksa bağımsız sağ panele geri düşer',
|
||||
pluginMdExportDesc: 'better-sidebar Markdown araç çubuğuna «Dışa aktar» düğmesi ekler: geçerli .md dosyasını tek tıkla bağımsız HTML biçimine dönüştürür (tablolar/kod blokları/Mermaid diyagramları gömülü, düzen önizleme temasını izler) ve .md dosyasının yanına kaydeder ya da yazdırma penceresinden PDF dışa aktarır',
|
||||
pluginCodeNavDesc: 'Kod önizleme gezinmesi: dosya türünden dili otomatik algılayıp söz dizimini vurgular, simge şeması (sınıf/yöntem/değişken filtreleri + tek tıkla atlama) ve dosya içi arama (tüm eşleşmeleri vurgula, önceki/sonraki, büyük/küçük harf duyarlı) — better-sidebar düzenleyicisinde kod dosyası önizlemesini devralır',
|
||||
pluginSuhuangScrollDesc: 'Yerel Suhuang Scroll Runtime ortamını model yapılandırması, bağlantı testi ve kesintisiz değerlendirme denetimi için DSH ayarlarına ve better-sidebar öğesine bağlar; Suhuang Scroll Runtime ve dsh-better-sidebar gerektirir',
|
||||
pluginSuhuangScrollDesc: 'Yerel Suhuang Scroll Runtime ortamını model yapılandırması, bağlantı testi ve kesintisiz değerlendirme denetimi için DSH ayarlarına ve better-sidebar öğesine bağlar; Suhuang Scroll Runtime ve dsh-apes-sidebar gerektirir',
|
||||
pluginBetterOverleafDesc: 'better-sidebar için Overleaf sekmesi: doğrudan CDP tarayıcı girişi (üçüncü taraf Chromium destekli), proje listesi/geçiş, <workspace>/overleaf/ altında yerel git aynaları, salt okunur API yedekli çift yönlü git senkronizasyonu ve dosya önizlemesi kenar çubuğu workbench üzerinden',
|
||||
pluginGitRemotesDesc: 'Git Remotes sekmesi: dal/yukarı akış/ahead-behind, fetch (isteğe bağlı prune), ff-only pull ve yalnızca sekme içi onaydan sonra push. Yerleşik Git sahnele/işle sekmesini değiştirmez; force-push veya model otomatik push aracı sunmaz',
|
||||
pluginSentinelDesc: 'Koşul odaklı aracı uyandırma: dosya/süreç/port/HTTP/komut/web algılayıcılar koşullar tetiklendiğinde uyuyan oturumları uyandırır; sunucu geneli izleme tablosuyla «Sentinel» sekmesi kaydeder',
|
||||
|
||||
@@ -395,7 +395,7 @@ export const vi: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: 'Đăng ký xem trước loại tệp mới',
|
||||
addPluginsTabDesc: 'Trang thanh bên (tab) có thể mở rộng qua plugin. Plugin đăng ký qua service ctx.betterSidebar; nhấp «Cài đặt» để sao chép lệnh cài, dán vào terminal nơi DSH chạy rồi thực thi.',
|
||||
addPluginsViewerDesc: 'Trình xem tệp có thể mở rộng qua plugin. Plugin đăng ký qua service ctx.betterSidebar; nhấp «Cài đặt» để sao chép lệnh cài, dán vào terminal nơi DSH chạy rồi thực thi.',
|
||||
addPluginsBrowseMore: 'Duyệt thêm plugin trên GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Duyệt thêm plugin trên GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Tìm theo tên / mô tả plugin…',
|
||||
addPluginsNoMatch: 'Không có plugin phù hợp',
|
||||
addPluginsRecommended: 'Plugin đề xuất',
|
||||
@@ -408,7 +408,7 @@ export const vi: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'Tab GitHub Workbench: cây repo từ xa + Issues / Pull requests / Actions với hỗ trợ ghi đầy đủ — tạo Issue/PR, bình luận, chỉnh sửa, đóng/mở lại, merge squash·merge·rebase (xác nhận mạnh), chạy lại/hủy CI; bộ chuyển repo tự liệt kê các repo có quyền truy cập và tìm kiếm repo công khai; khi chưa cài better-sidebar sẽ tự động chuyển sang panel bên phải độc lập',
|
||||
pluginMdExportDesc: 'Thêm nút «Xuất» vào thanh công cụ Markdown của better-sidebar: một cú nhấp chuyển .md hiện tại thành HTML độc lập (bảng/khối mã/sơ đồ Mermaid nhúng, bố cục theo theme xem trước) và lưu cạnh tệp .md, hoặc xuất PDF qua hộp thoại in',
|
||||
pluginCodeNavDesc: 'Điều hướng xem trước mã: tự nhận diện ngôn ngữ theo loại tệp và tô sáng cú pháp, phác thảo ký hiệu (lọc lớp/phương thức/biến + nhảy một cú nhấp), tìm kiếm trong tệp (tô sáng mọi kết quả, trước/sau, phân biệt hoa thường) — đảm nhận xem trước tệp mã trong trình soạn thảo better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Kết nối Suhuang Scroll Runtime cục bộ với phần cài đặt DSH và better-sidebar để cấu hình mô hình, kiểm tra kết nối và điều khiển chấm bài liên tục; yêu cầu Suhuang Scroll Runtime và dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Kết nối Suhuang Scroll Runtime cục bộ với phần cài đặt DSH và better-sidebar để cấu hình mô hình, kiểm tra kết nối và điều khiển chấm bài liên tục; yêu cầu Suhuang Scroll Runtime và dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'Tab Overleaf cho better-sidebar: đăng nhập trực tiếp qua trình duyệt CDP (hỗ trợ Chromium bên thứ ba), danh sách/chuyển dự án, mirror git cục bộ trong <workspace>/overleaf/, đồng bộ git hai chiều với dự phòng API chỉ đọc, xem trước tệp qua workbench của thanh bên',
|
||||
pluginGitRemotesDesc: 'Tab Git Remotes của better-sidebar: xem branch/upstream/ahead-behind, fetch (có thể prune), pull ff-only, push chỉ sau khi xác nhận trong tab. Không thay thế tab stage/commit Git built-in, cũng không cung cấp force-push hay công cụ auto-push cho mô hình',
|
||||
pluginSentinelDesc: 'Hệ thống đánh thức agent theo điều kiện: cảm biến file/process/port/HTTP/command/webhook, khi điều kiện đạt sẽ tự đánh thức phiên ngủ; đăng ký tab «Sentinel» hiển thị bảng giám sát toàn server',
|
||||
|
||||
@@ -410,7 +410,7 @@ export const zhHK: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: '註冊新的檔案類型預覽',
|
||||
addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: '搜尋插件名稱 / 描述…',
|
||||
addPluginsNoMatch: '沒有匹配的插件',
|
||||
addPluginsRecommended: '推薦插件',
|
||||
@@ -423,7 +423,7 @@ export const zhHK: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar「GitHub 工作台」Tab:遠端儲存庫目錄樹 + Issues / Pull requests / Actions 頁簽,讀取之外支援新建 Issue/PR、評論、編輯、關閉重開、squash·merge·rebase 合併(強確認)與重跑/取消 CI;儲存庫彈出層自動拉取有權限列表並支援公開儲存庫搜尋;未安裝 better-sidebar 時自動降級為獨立右側面板',
|
||||
pluginMdExportDesc: '在 better-sidebar 的 Markdown 工具列上新增「匯出」按鈕:一鍵把目前 .md 渲染為獨立 HTML(表格/程式碼區塊/Mermaid 圖表內嵌,版面跟隨預覽主題)直接儲存到同目錄,或透過列印對話框匯出為 PDF',
|
||||
pluginCodeNavDesc: '程式碼預覽導覽:按檔案類型自動識別語言並高亮語法,符號大綱(類別/方法/變數篩選 + 一鍵跳轉),檔案內搜尋(全部符合高亮、上/下一處、區分大小寫),接管 better-sidebar 的程式碼檔案預覽',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'better-sidebar 的 Overleaf 分頁:直連 CDP 瀏覽器登入(支援第三方 Chromium),專案列表/切換,<workspace>/overleaf/ 本地 git 映像,git 雙向同步(API 唯讀兜底),檔案預覽走側邊欄工作台',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送',
|
||||
pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表',
|
||||
|
||||
@@ -410,7 +410,7 @@ export const zhMO: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: '註冊新的檔案類型預覽',
|
||||
addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: '搜尋插件名稱 / 描述…',
|
||||
addPluginsNoMatch: '沒有匹配的插件',
|
||||
addPluginsRecommended: '推薦插件',
|
||||
@@ -423,7 +423,7 @@ export const zhMO: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar「GitHub 工作台」Tab:遠端儲存庫目錄樹 + Issues / Pull requests / Actions 頁簽,讀取之外支援新建 Issue/PR、評論、編輯、關閉重開、squash·merge·rebase 合併(強確認)與重跑/取消 CI;儲存庫彈層自動拉取有權限清單並支援公開儲存庫搜尋;未安裝 better-sidebar 時自動降級為獨立右側面板',
|
||||
pluginMdExportDesc: '在 better-sidebar 的 Markdown 工具列上新增「匯出」按鈕:一鍵把目前 .md 渲染為獨立 HTML(表格/程式碼區塊/Mermaid 圖表內嵌,版面跟隨預覽主題)直接儲存到同目錄,或透過列印對話框匯出為 PDF',
|
||||
pluginCodeNavDesc: '程式碼預覽導覽:按檔案類型自動識別語言並高亮語法,符號大綱(類別/方法/變數篩選 + 一鍵跳轉),檔案內搜尋(全部符合高亮、上/下一處、區分大小寫),接管 better-sidebar 的程式碼檔案預覽',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'better-sidebar 的 Overleaf 分頁:直連 CDP 瀏覽器登入(支援第三方 Chromium),專案列表/切換,<workspace>/overleaf/ 本地 git 映像,git 雙向同步(API 唯讀兜底),檔案預覽走側邊欄工作台',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送',
|
||||
pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表',
|
||||
|
||||
@@ -410,7 +410,7 @@ export const zhTW: Record<string, string> = {
|
||||
addPluginsViewerCardDesc: '註冊新的檔案類型預覽',
|
||||
addPluginsTabDesc: '側邊欄頁面(Tab)可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsViewerDesc: '檔案預覽器可以由插件擴展。插件透過 ctx.betterSidebar 服務註冊;點擊「安裝」複製安裝命令,貼到 DSH 所在環境的終端執行。',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: '在 GitHub 上瀏覽更多插件(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: '搜尋插件名稱 / 描述…',
|
||||
addPluginsNoMatch: '沒有匹配的插件',
|
||||
addPluginsRecommended: '推薦插件',
|
||||
@@ -423,7 +423,7 @@ export const zhTW: Record<string, string> = {
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar「GitHub 工作台」Tab:遠端儲存庫目錄樹 + Issues / Pull requests / Actions 頁籤,讀取之外支援建立 Issue/PR、留言、編輯、關閉重開、squash·merge·rebase 合併(強確認)與重跑/取消 CI;儲存庫彈出視窗自動載入有權限清單並支援公開儲存庫搜尋;未安裝 better-sidebar 時自動降級為獨立右側面板',
|
||||
pluginMdExportDesc: '在 better-sidebar 的 Markdown 工具列上新增「匯出」按鈕:一鍵把目前 .md 渲染為獨立 HTML(表格/程式碼區塊/Mermaid 圖表內嵌,版面跟隨預覽主題)直接儲存到同目錄,或透過列印對話框匯出為 PDF',
|
||||
pluginCodeNavDesc: '程式碼預覽導覽:按檔案類型自動識別語言並高亮語法,符號大綱(類別/方法/變數篩選 + 一鍵跳轉),檔案內搜尋(全部符合高亮、上/下一處、區分大小寫),接管 better-sidebar 的程式碼檔案預覽',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: '把本機蘇黃共閱 Runtime 接入 DSH 設定與 better-sidebar,支援模型設定、連線測試及連續閱卷控制;使用前須安裝 Suhuang Scroll Runtime 與 dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'better-sidebar 的 Overleaf 分頁:直連 CDP 瀏覽器登入(支援第三方 Chromium),專案列表/切換,<workspace>/overleaf/ 本地 git 映像,git 雙向同步(API 唯讀兜底),檔案預覽走側邊欄工作台',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git 遠端 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、確認後才 push。不替換內建 Git 的暫存/提交,也不提供 force-push 或模型自動推送',
|
||||
pluginSentinelDesc: '條件驅動的 agent 喚醒系統:檔案/程序/連接埠/HTTP/命令/webhook 感測器,條件達成自動喚醒休眠工作階段;註冊「哨兵」Tab 展示伺服器全域監控表',
|
||||
|
||||
@@ -402,7 +402,7 @@ export const zh = {
|
||||
addPluginsViewerCardDesc: '注册新的文件类型预览',
|
||||
addPluginsTabDesc: '侧边栏页面(Tab)可以由插件扩展。插件通过 ctx.betterSidebar 服务注册;点击「安装」复制安装命令,粘贴到 DSH 所在环境的终端执行。',
|
||||
addPluginsViewerDesc: '文件预览器可以由插件扩展。插件通过 ctx.betterSidebar 服务注册;点击「安装」复制安装命令,粘贴到 DSH 所在环境的终端执行。',
|
||||
addPluginsBrowseMore: '在 GitHub 上浏览更多插件(topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: '在 GitHub 上浏览更多插件(topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: '搜索插件名称 / 描述…',
|
||||
addPluginsNoMatch: '没有匹配的插件',
|
||||
addPluginsRecommended: '推荐插件',
|
||||
@@ -414,7 +414,7 @@ export const zh = {
|
||||
pluginFlowglassDesc: '实时会话流程图:三列泳道展示用户、助手与工具调用,支持并行分组、子代理支线、逐层钻取和实时状态;安装 better-sidebar 后注册原生「流镜」Tab,未安装时保留独立抽屉',
|
||||
pluginGitForgeDesc: 'better-sidebar「Git 凭据」Tab:GitHub/Gitea 等 Forge 账号库 + 按项目授权 + push 策略硬拦;token 仅存本地 secrets,不进模型上下文;提供只读 GitForge 工具与 agent HTTPS credential helper',
|
||||
pluginGithubWorkbenchDesc: 'better-sidebar「GitHub 工作台」Tab:远端仓库目录树 + Issues / Pull requests / Actions 页签,读之外支持新建 Issue/PR、评论、编辑、关闭重开、squash·merge·rebase 合并(强确认)与重跑/取消 CI;仓库弹层自动拉取有权限列表并支持公开仓搜索;未装 better-sidebar 时自动降级为独立右侧面板',
|
||||
pluginSuhuangScrollDesc: '把本地苏黄共阅 Runtime 接入 DSH 设置与 better-sidebar,支持模型配置、连接测试和连续阅卷控制;使用前需安装 Suhuang Scroll Runtime 与 dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: '把本地苏黄共阅 Runtime 接入 DSH 设置与 better-sidebar,支持模型配置、连接测试和连续阅卷控制;使用前需安装 Suhuang Scroll Runtime 与 dsh-apes-sidebar',
|
||||
pluginBetterOverleafDesc: 'better-sidebar 的 Overleaf 标签页:直连 CDP 浏览器登录(支持第三方 Chromium),项目列表/切换,<workspace>/overleaf/ 本地 git 镜像,git 双向同步(API 只读兜底),文件预览走侧边栏工作台',
|
||||
pluginGitRemotesDesc: 'better-sidebar Git 远程 Tab:看分支/上游/ahead-behind,fetch(可 prune)、ff-only pull、确认后才 push。不替换内置 Git 的暂存/提交,也不提供 force-push 或模型自动推送',
|
||||
pluginSentinelDesc: '条件驱动的 agent 唤醒系统:文件/进程/端口/HTTP/命令/webhook 传感器,条件达成自动唤醒休眠会话;注册「哨兵」Tab 展示服务器全局监控表',
|
||||
@@ -811,7 +811,7 @@ export const en: Record<keyof typeof zh, string> = {
|
||||
addPluginsViewerCardDesc: 'Register a file-type preview',
|
||||
addPluginsTabDesc: 'Sidebar pages (tabs) can be extended by plugins. Plugins register through the ctx.betterSidebar service; clicking Install copies the install command — paste it into a terminal where your DSH profile lives and run it.',
|
||||
addPluginsViewerDesc: 'File previewers can be extended by plugins. Plugins register through the ctx.betterSidebar service; clicking Install copies the install command — paste it into a terminal where your DSH profile lives and run it.',
|
||||
addPluginsBrowseMore: 'Browse more plugins on GitHub (topic: dsh-better-sidebar)',
|
||||
addPluginsBrowseMore: 'Browse more plugins on GitHub (topic: dsh-apes-sidebar)',
|
||||
addPluginsSearch: 'Search by plugin name or description…',
|
||||
addPluginsNoMatch: 'No plugins match',
|
||||
addPluginsRecommended: 'Recommended plugins',
|
||||
@@ -829,7 +829,7 @@ export const en: Record<keyof typeof zh, string> = {
|
||||
pluginSidebarQaDesc: 'Select-and-ask: Select conversation text → ask in the right-side panel → a dedicated follow-up session (❓追问) in the same workspace; a fast no-thinking model compresses the main context and injects it with the quote, without interrupting the main conversation. Follow-ups nest, continue, and archive',
|
||||
pluginSidenoteDesc: 'Codex-style side chat + selection annotations: fork the current session into a persistent side panel (archived out of the session list, multi-instance, /side command, survives reload, model follows the main session); select assistant text → numbered badge + note editor → an "N annotations" chip that rides your next message, or ask straight into a side chat',
|
||||
pluginSshTunnelDesc: 'SSH Tunnel tab: multi-host inventory + per-project grants + local secrets; SSHManager tool (exec/SFTP/session strategies); center interactive terminal and dual-pane SFTP',
|
||||
pluginSuhuangScrollDesc: 'Connect the local Suhuang Scroll Runtime to DSH settings and better-sidebar for model configuration, connection tests, and continuous grading controls; requires Suhuang Scroll Runtime and dsh-better-sidebar',
|
||||
pluginSuhuangScrollDesc: 'Connect the local Suhuang Scroll Runtime to DSH settings and better-sidebar for model configuration, connection tests, and continuous grading controls; requires Suhuang Scroll Runtime and dsh-apes-sidebar',
|
||||
pluginTurnReviewDesc: 'A human gate on the just-finished turn: Approve / Request changes per path with an optional comment; paths grouped by main session / subagent / unattributed; inline snapshot-vs-now diff before you decide. No fork, no /rewind',
|
||||
pluginVideoPreviewDesc: 'Inline video preview (.mp4/.webm/.mov/.mkv/.avi etc.) for the better-sidebar editor, backed by a dedicated /video host route with HTTP Range (206) support — scrubbing works and files are not capped by the 20MB mediaLimit',
|
||||
pluginCodeNavDesc: 'Code preview navigator: detects the language by file type and highlights syntax, symbol outline (class / method / variable filters + one-click jump), and in-file search (highlight all matches, prev/next, match case) — takes over code file preview in the better-sidebar editor',
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* 文件预览 grids).
|
||||
*/
|
||||
|
||||
/** The GitHub topic page listing every repo tagged `dsh-better-sidebar`. */
|
||||
export const PLUGIN_TOPIC_URL = 'https://github.com/topics/dsh-better-sidebar'
|
||||
/** The GitHub topic page listing every repo tagged `dsh-apes-sidebar`. */
|
||||
export const PLUGIN_TOPIC_URL = 'https://github.com/topics/dsh-apes-sidebar'
|
||||
|
||||
/** One curated plugin entry (name / url / description / install script). */
|
||||
export interface PluginEntry {
|
||||
|
||||
+20
-20
@@ -31,25 +31,25 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
description: () => t('pluginEgoBrowserDesc'),
|
||||
// Registers a sidebar tab for the agent browser; optional peer of
|
||||
// better-sidebar (auto-tab when present, floating bubble when not).
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add git+https://github.com/Fisfzy/ego-browser.git',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add git+https://github.com/Fisfzy/ego-browser.git',
|
||||
},
|
||||
{
|
||||
id: 'dsh-better-overleaf',
|
||||
name: 'dsh-better-overleaf Overleaf 标签页',
|
||||
url: 'https://github.com/Hoemr/dsh-better-overleaf',
|
||||
description: () => t('pluginBetterOverleafDesc'),
|
||||
// Published on npm; peer-depends on dsh-better-sidebar (Overleaf tab),
|
||||
// Published on npm; peer-depends on dsh-apes-sidebar (Overleaf tab),
|
||||
// so the install line installs the prerequisite first.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-better-overleaf',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-better-overleaf',
|
||||
},
|
||||
{
|
||||
id: 'dsh-docs-panel',
|
||||
name: 'dsh-docs-panel 全局文档',
|
||||
url: 'https://github.com/mlosun/dsh-docs-panel',
|
||||
description: () => t('pluginDocsPanelDesc'),
|
||||
// dsh-docs-panel hard-depends on dsh-better-sidebar (required peer), so
|
||||
// dsh-docs-panel hard-depends on dsh-apes-sidebar (required peer), so
|
||||
// the install line installs the prerequisite first, then the plugin.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-docs-panel',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-docs-panel',
|
||||
},
|
||||
{
|
||||
id: 'dsh-flowglass',
|
||||
@@ -58,23 +58,23 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
description: () => t('pluginFlowglassDesc'),
|
||||
// Flowglass keeps its standalone drawer as a fallback and registers the
|
||||
// native tab automatically when better-sidebar is present.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-flowglass',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-flowglass',
|
||||
},
|
||||
{
|
||||
id: 'dsh-git-forge',
|
||||
name: 'dsh-git-forge Git 凭据',
|
||||
url: 'https://github.com/thirsty5034/dsh-git-forge',
|
||||
description: () => t('pluginGitForgeDesc'),
|
||||
// Peer-depends on dsh-better-sidebar (Git Forge tab). Install the
|
||||
// Peer-depends on dsh-apes-sidebar (Git Forge tab). Install the
|
||||
// prerequisite first; package is GitHub-sourced until npm publish.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add "dsh-git-forge@github:thirsty5034/dsh-git-forge"',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add "dsh-git-forge@github:thirsty5034/dsh-git-forge"',
|
||||
},
|
||||
{
|
||||
id: 'dsh-git-remotes',
|
||||
name: 'dsh-git-remotes Git 远程',
|
||||
url: 'https://github.com/yq04/dsh-git-remotes',
|
||||
description: () => t('pluginGitRemotesDesc'),
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add git+https://github.com/yq04/dsh-git-remotes.git',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add git+https://github.com/yq04/dsh-git-remotes.git',
|
||||
},
|
||||
{
|
||||
id: 'dsh-github-workbench',
|
||||
@@ -91,18 +91,18 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
name: 'dsh-sidebar-qa 划选追问',
|
||||
url: 'https://github.com/ChenRuoT/dsh-sidebar-qa',
|
||||
description: () => t('pluginSidebarQaDesc'),
|
||||
// dsh-sidebar-qa hard-depends on dsh-better-sidebar (required peer), so
|
||||
// dsh-sidebar-qa hard-depends on dsh-apes-sidebar (required peer), so
|
||||
// the install line installs the prerequisite first, then the plugin.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add git+https://github.com/ChenRuoT/dsh-sidebar-qa.git',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add git+https://github.com/ChenRuoT/dsh-sidebar-qa.git',
|
||||
},
|
||||
{
|
||||
id: 'dsh-sidenote',
|
||||
name: 'dsh-sidenote 侧边聊天',
|
||||
url: 'https://github.com/g-yixuan/dsh-sidenote',
|
||||
description: () => t('pluginSidenoteDesc'),
|
||||
// dsh-sidenote hard-depends on dsh-better-sidebar (required peer), so
|
||||
// dsh-sidenote hard-depends on dsh-apes-sidebar (required peer), so
|
||||
// the install line installs the prerequisite first, then the plugin.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-sidenote',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-sidenote',
|
||||
},
|
||||
{
|
||||
id: 'dsh-server-deck',
|
||||
@@ -112,7 +112,7 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
// Published on npm; dual-mount like flowglass — registers the native
|
||||
// "Servers" tab when better-sidebar is present, standalone drawer
|
||||
// otherwise. Install the prerequisite first.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-server-deck@latest',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-server-deck@latest',
|
||||
},
|
||||
{
|
||||
id: 'dsh-suhuang-scroll',
|
||||
@@ -121,24 +121,24 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
description: () => t('pluginSuhuangScrollDesc'),
|
||||
// Suhuang Scroll is a DSH Web plugin whose runtime console registers in
|
||||
// better-sidebar. Install the sidebar prerequisite before the npm package.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add dsh-suhuang-scroll',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add dsh-suhuang-scroll',
|
||||
},
|
||||
{
|
||||
id: 'dsh-ssh-tunnel',
|
||||
name: 'dsh-ssh-tunnel SSH 隧道',
|
||||
url: 'https://github.com/thirsty5034/dsh-ssh-tunnel',
|
||||
description: () => t('pluginSshTunnelDesc'),
|
||||
// Peer-depends on dsh-better-sidebar (SSH Tunnel tab + center terminal/SFTP).
|
||||
// Peer-depends on dsh-apes-sidebar (SSH Tunnel tab + center terminal/SFTP).
|
||||
// Install the prerequisite first; package is GitHub-sourced until npm publish.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add "dsh-ssh-tunnel@github:thirsty5034/dsh-ssh-tunnel"',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add "dsh-ssh-tunnel@github:thirsty5034/dsh-ssh-tunnel"',
|
||||
},
|
||||
{
|
||||
id: 'dsh-turn-review',
|
||||
name: 'dsh-turn-review 本轮审查',
|
||||
url: 'https://github.com/yq04/dsh-turn-review',
|
||||
description: () => t('pluginTurnReviewDesc'),
|
||||
// Needs dsh-better-sidebar (optional peer) for the tab; no model tools.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add git+https://github.com/yq04/dsh-turn-review.git',
|
||||
// Needs dsh-apes-sidebar (optional peer) for the tab; no model tools.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add git+https://github.com/yq04/dsh-turn-review.git',
|
||||
},
|
||||
{
|
||||
id: 'dsh-bilingual-reader',
|
||||
@@ -148,6 +148,6 @@ export const builtinTabPlugins: readonly PluginEntry[] = [
|
||||
// Bilingual paper reading: a native-PDF tab with LLM selection translation,
|
||||
// isolated from the main conversation context. Hard-depends on the
|
||||
// better-sidebar tab service, so install the prerequisite first.
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add github:Johnblur/dsh-bilingual-reader',
|
||||
install: 'cd ~/.dsh && dsh plugin --profile web add dsh-apes-sidebar && dsh plugin --profile web add github:Johnblur/dsh-bilingual-reader',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -453,7 +453,7 @@ export function matchUrlTarget(tabs: readonly TabDescriptor[], url: URL): TabDes
|
||||
try {
|
||||
claimed = tab.urlTarget(url) === true
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] urlTarget error:', error)
|
||||
console.error('[dsh-apes-sidebar] urlTarget error:', error)
|
||||
continue
|
||||
}
|
||||
if (claimed) return tab
|
||||
@@ -465,7 +465,7 @@ export function matchUrlTarget(tabs: readonly TabDescriptor[], url: URL): TabDes
|
||||
* The plugin version this service instance reports. Keep in lockstep with
|
||||
* `package.json`'s version — `tests/service.spec.ts` asserts the pair.
|
||||
*/
|
||||
export const SIDEBAR_SERVICE_VERSION = '0.18.0'
|
||||
export const SIDEBAR_SERVICE_VERSION = '1.1.0'
|
||||
|
||||
/**
|
||||
* Monotonic capability list consumers use to gate new API usage (features
|
||||
@@ -503,7 +503,7 @@ function safeCall(fn: () => void): void {
|
||||
try {
|
||||
fn()
|
||||
} catch (error) {
|
||||
console.error('[dsh-better-sidebar] plugin callback error:', error)
|
||||
console.error('[dsh-apes-sidebar] plugin callback error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ export function createBetterSidebarService(store: SidebarStore): BetterSidebarSe
|
||||
|
||||
const registerTab = (descriptor: TabDescriptor): (() => void) => {
|
||||
if (tabs.has(descriptor.id)) {
|
||||
throw new Error(`[dsh-better-sidebar] tab type "${descriptor.id}" already registered`)
|
||||
throw new Error(`[dsh-apes-sidebar] tab type "${descriptor.id}" already registered`)
|
||||
}
|
||||
tabs.set(descriptor.id, descriptor)
|
||||
notify()
|
||||
@@ -542,7 +542,7 @@ export function createBetterSidebarService(store: SidebarStore): BetterSidebarSe
|
||||
|
||||
const registerFileViewer = (descriptor: FileViewerDescriptor): (() => void) => {
|
||||
if (viewers.has(descriptor.id)) {
|
||||
throw new Error(`[dsh-better-sidebar] file viewer "${descriptor.id}" already registered`)
|
||||
throw new Error(`[dsh-apes-sidebar] file viewer "${descriptor.id}" already registered`)
|
||||
}
|
||||
viewers.set(descriptor.id, descriptor)
|
||||
notify()
|
||||
@@ -598,7 +598,7 @@ export function createBetterSidebarService(store: SidebarStore): BetterSidebarSe
|
||||
// + menu nor from derived flows (file opens, subagent auto-open,
|
||||
// external plugins). Already-open tabs keep rendering.
|
||||
if (!isTabEnabled(seed.type)) {
|
||||
console.warn(`[dsh-better-sidebar] tab type "${seed.type}" is disabled in the side card settings`)
|
||||
console.warn(`[dsh-apes-sidebar] tab type "${seed.type}" is disabled in the side card settings`)
|
||||
return
|
||||
}
|
||||
const descriptor = tabs.get(seed.type)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* disposal, so the adaptation remains HMR-safe.
|
||||
*/
|
||||
|
||||
export const SETTINGS_NAV_MARKER = 'data-dsh-better-sidebar-settings-nav'
|
||||
export const SETTINGS_NAV_MARKER = 'data-dsh-apes-sidebar-settings-nav'
|
||||
|
||||
/**
|
||||
* Keep the marker on the settings-nav button whose visible text is this
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* Serializable configuration and defaults for the sidebar host half. Loader
|
||||
* schema validation normally fills defaults; {@link resolveSidebarConfig}
|
||||
* applies the same defaults for direct callers that bypass the Loader.
|
||||
* @module dsh-better-sidebar/config
|
||||
* @module dsh-apes-sidebar/config
|
||||
*/
|
||||
|
||||
import z from 'schemastery'
|
||||
|
||||
@@ -568,14 +568,14 @@ export interface SidebarContextShape {
|
||||
/**
|
||||
* The Context this plugin sees: the vendored cordis Context intersected with
|
||||
* the structural service faces above. Re-exported from the package root so a
|
||||
* consumer can `import type { Context } from 'dsh-better-sidebar'`.
|
||||
* consumer can `import type { Context } from 'dsh-apes-sidebar'`.
|
||||
*/
|
||||
export type Context = CordisContext & SidebarContextShape
|
||||
|
||||
/**
|
||||
* Consumer-facing augmentation (deliberately the only one kept): a plugin
|
||||
* that imports `Context` from `@deepseek-ai/cordis` and does
|
||||
* `import type {} from 'dsh-better-sidebar'` sees `ctx.betterSidebar`
|
||||
* `import type {} from 'dsh-apes-sidebar'` sees `ctx.betterSidebar`
|
||||
* without importing this package's own Context type.
|
||||
*/
|
||||
declare module '@deepseek-ai/cordis' {
|
||||
|
||||
+14
-14
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* dsh-better-sidebar host half: the /sidebar JSON API (explorer listing, file
|
||||
* dsh-apes-sidebar host half: the /sidebar JSON API (explorer listing, file
|
||||
* read/write, git), the /sidebar/file media route (images), the /sidebar/html
|
||||
* preview route, the /sidebar/bundle lazy-chunk route (client code splits),
|
||||
* and the terminal WebSocket upgrade. Every route passes the same
|
||||
@@ -59,7 +59,7 @@ import { readJsonBody, requireString, SidebarError, writeError, writeJson, write
|
||||
export { Config }
|
||||
export type { SidebarConfig, ResolvedSidebarConfig }
|
||||
// Re-export the Context augmentation (`declare module '@deepseek-ai/cordis'`)
|
||||
// so consumers `import type {} from 'dsh-better-sidebar'` and gain
|
||||
// so consumers `import type {} from 'dsh-apes-sidebar'` and gain
|
||||
// `ctx.betterSidebar`; the Context re-export below is the vendored cordis
|
||||
// Context intersected with the structural service faces.
|
||||
// Also re-export the service descriptor types so consumers can type their
|
||||
@@ -75,7 +75,7 @@ export type {
|
||||
} from './client/service.ts'
|
||||
|
||||
/** Plugin identity for cordis.yml rows. */
|
||||
export const name = 'dsh-better-sidebar'
|
||||
export const name = 'dsh-apes-sidebar'
|
||||
|
||||
/** Services required before mounting: the webserver routes, the session store, the web runtime's trusted hosts, and the tool registry. */
|
||||
export const inject = ['webServer', 'sessions', 'webRuntime', 'tools']
|
||||
@@ -699,7 +699,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
const detail = status.ok
|
||||
? 'unknown cause'
|
||||
: `${status.cause}. Repair: ${status.command}`
|
||||
ctx.logger?.warn(`[dsh-better-sidebar] node-pty (${DSH_NODE_PTY_RANGE}) failed to load: ${detail}`)
|
||||
ctx.logger?.warn(`[dsh-apes-sidebar] node-pty (${DSH_NODE_PTY_RANGE}) failed to load: ${detail}`)
|
||||
}
|
||||
const ptyManager = nodePty !== null
|
||||
? new PtyManager(terminalShell, resolved.terminalsPerSession, resolved.shellArgs, nodePty)
|
||||
@@ -755,7 +755,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
}
|
||||
ctx.inject(['settings'], (sctx) => {
|
||||
// DSH 0.1.2-alpha.2 validates namespaces at compile time
|
||||
// (SettingsNamespaceInput); the 'dsh-better-sidebar' literal passes, so the
|
||||
// (SettingsNamespaceInput); the 'dsh-apes-sidebar' literal passes, so the
|
||||
// runtime helper this used to call (settingsNamespace) is gone upstream.
|
||||
const ns = SIDEBAR_PREFS_NS
|
||||
// The structural settings mirror types `schema` as unknown, so the
|
||||
@@ -858,7 +858,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
writeError(res, error)
|
||||
}
|
||||
},
|
||||
}), 'dsh-better-sidebar: /sidebar/api routes')
|
||||
}), 'dsh-apes-sidebar: /sidebar/api routes')
|
||||
|
||||
// ── Raw upload route ───────────────────────────────────────────────────
|
||||
// One request writes one file without JSON/base64 inflation. Folder uploads
|
||||
@@ -900,13 +900,13 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
writeError(res, error)
|
||||
}
|
||||
},
|
||||
}), 'dsh-better-sidebar: /sidebar/upload route')
|
||||
}), 'dsh-apes-sidebar: /sidebar/upload route')
|
||||
|
||||
// ── Lazy chunk route (client bundle splits) ─────────────────────────────
|
||||
// Serves the client half's split bundles (lib/client-<name>.js) so the
|
||||
// heavy preview/terminal libraries load on first use, not at page start
|
||||
// (see bundle-route.ts / src/client/chunk-loader.ts).
|
||||
ctx.effect(() => registerBundleRoute(ctx, fence), 'dsh-better-sidebar: /sidebar/bundle chunk route')
|
||||
ctx.effect(() => registerBundleRoute(ctx, fence), 'dsh-apes-sidebar: /sidebar/bundle chunk route')
|
||||
|
||||
// ── Media route (images for the editor) ─────────────────────────────────
|
||||
ctx.effect(() => ctx.webServer.register({
|
||||
@@ -948,7 +948,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
writeError(res, error)
|
||||
}
|
||||
},
|
||||
}), 'dsh-better-sidebar: /sidebar/file media route')
|
||||
}), 'dsh-apes-sidebar: /sidebar/file media route')
|
||||
|
||||
// ── HTML preview route (sandboxed HTML + its relative assets) ───────────
|
||||
// Serves files under the session cwd for the built-in HTML previewer. The
|
||||
@@ -1010,7 +1010,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
writeError(res, error)
|
||||
}
|
||||
},
|
||||
}), 'dsh-better-sidebar: /sidebar/html preview route')
|
||||
}), 'dsh-apes-sidebar: /sidebar/html preview route')
|
||||
|
||||
// ── Terminal WebSocket ──────────────────────────────────────────────────
|
||||
// One upgrade endpoint serves both UI-tab terminals (?tab=...) and
|
||||
@@ -1034,7 +1034,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
void attachTerminal(ctx, ptyManager, agentPtyRegistry, ws, req, resolved, () => settingsFace)
|
||||
})
|
||||
},
|
||||
}), 'dsh-better-sidebar: terminal WebSocket')
|
||||
}), 'dsh-apes-sidebar: terminal WebSocket')
|
||||
|
||||
// ── Agent terminals push WebSocket ──────────────────────────────────────
|
||||
// Pushes the live list of agent terminals for one session to the sidebar
|
||||
@@ -1056,7 +1056,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
void attachAgentList(agentPtyRegistry, ws, req)
|
||||
})
|
||||
},
|
||||
}), 'dsh-better-sidebar: agent-terminals push WebSocket')
|
||||
}), 'dsh-apes-sidebar: agent-terminals push WebSocket')
|
||||
|
||||
// ── Agent opens push WebSocket ─────────────────────────────────────────
|
||||
// Pushes `sidebar_open` requests for one session to the sidebar view: the
|
||||
@@ -1076,7 +1076,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
void attachAgentOpen(agentOpenRegistry, ws, req)
|
||||
})
|
||||
},
|
||||
}), 'dsh-better-sidebar: agent-opens push WebSocket')
|
||||
}), 'dsh-apes-sidebar: agent-opens push WebSocket')
|
||||
|
||||
ctx.effect(() => () => {
|
||||
toolsDisposers?.()
|
||||
@@ -1087,7 +1087,7 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
|
||||
wss.close()
|
||||
agentListWss.close()
|
||||
agentOpenWss.close()
|
||||
}, 'dsh-better-sidebar: teardown')
|
||||
}, 'dsh-apes-sidebar: teardown')
|
||||
}
|
||||
|
||||
/** Push queued `sidebar_open` requests for one session to a connected view. */
|
||||
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* Package-owned invariant companion for `dsh-better-sidebar`.
|
||||
* @module dsh-better-sidebar/invariant
|
||||
* Package-owned invariant companion for `dsh-apes-sidebar`.
|
||||
* @module dsh-apes-sidebar/invariant
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
import type { Context } from './context-types.ts'
|
||||
|
||||
const PACKAGE_NAME = 'dsh-better-sidebar'
|
||||
const PACKAGE_NAME = 'dsh-apes-sidebar'
|
||||
|
||||
/** Cordis companion plugin name. */
|
||||
export const name = 'dsh-better-sidebar-invariant'
|
||||
export const name = 'dsh-apes-sidebar-invariant'
|
||||
/** Service required before the companion can reserve package ownership. */
|
||||
export const inject = ['invariants']
|
||||
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ function createJobOutputMirror(ctx: Context): { entries(sessionId: string): read
|
||||
push(sessionId, trace)
|
||||
}
|
||||
})
|
||||
ctx.effect(() => dispose, 'dsh-better-sidebar: job-output event mirror')
|
||||
ctx.effect(() => dispose, 'dsh-apes-sidebar: job-output event mirror')
|
||||
|
||||
const push = (sessionId: string, trace: JobOutputTrace): void => {
|
||||
let list = perSession.get(sessionId)
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
/** The user-settings namespace holding the side card preferences. */
|
||||
export const SIDEBAR_PREFS_NS = 'dsh-better-sidebar'
|
||||
export const SIDEBAR_PREFS_NS = 'dsh-apes-sidebar'
|
||||
|
||||
/** User-facing side card preferences (new-conversation defaults). */
|
||||
export interface SidebarPrefs {
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ function isPluginRoot(dir: string): boolean {
|
||||
if (!existsSync(file)) return false
|
||||
try {
|
||||
const parsed = JSON.parse(readFileSync(file, 'utf8')) as { name?: unknown }
|
||||
return parsed.name === 'dsh-better-sidebar'
|
||||
return parsed.name === 'dsh-apes-sidebar'
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export const SIDE_BOUNDARY_PREFIX = 'Side conversation boundary'
|
||||
/** The plugin identity stamped on the source of context-injection messages
|
||||
* (boundary prompt + parked snapshot), so the transcript recognizes them
|
||||
* structurally — not by text prefix. */
|
||||
export const SIDE_INJECTION_PLUGIN = 'dsh-better-sidebar'
|
||||
export const SIDE_INJECTION_PLUGIN = 'dsh-apes-sidebar'
|
||||
|
||||
/**
|
||||
* The boundary prompt delivered as the thread's first user message: the
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* apes:* tab registration tests (Phase 1/1b, C6: 3 tabs). The fork registers
|
||||
* its three information-layer tabs (agents / apps / profile) through the same
|
||||
* BetterSidebarService the upstream builtins use (dogfood). `apes:tasks` was
|
||||
* removed in C6 — it overlaps the official DSH session tree in the native
|
||||
* sidebar. The spec pins the registration contract (id / single / order /
|
||||
* component presence) and the isolated i18n contract (the apes namespace
|
||||
* resolves zh vs en through the attached locale service, and every apesZh
|
||||
* key has an apesEn entry).
|
||||
*
|
||||
* Runs in the node vitest environment like builtins.spec.ts — no DOM, no
|
||||
* real DSH host (a live cordis scratch mount is Phase 2+).
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest'
|
||||
// Browser globals before the client graph loads (mirror of builtins.spec.ts).
|
||||
import './browser-globals.ts'
|
||||
|
||||
import type { Context } from '../src/context-types.ts'
|
||||
import { createBetterSidebarService } from '../src/client/service.ts'
|
||||
import { createSidebarStore } from '../src/client/state.ts'
|
||||
import { registerApesTabs } from '../src/client/apes/index.ts'
|
||||
import { apesZh, apesEn, attachApesLocale, t, type ApesCopyKey } from '../src/client/apes/locales.ts'
|
||||
|
||||
function setup(): {
|
||||
service: ReturnType<typeof createBetterSidebarService>
|
||||
store: ReturnType<typeof createSidebarStore>
|
||||
dispose: () => void
|
||||
} {
|
||||
const store = createSidebarStore()
|
||||
const service = createBetterSidebarService(store)
|
||||
const dispose = registerApesTabs({} as Context, service)
|
||||
return { service, store, dispose }
|
||||
}
|
||||
|
||||
describe('apes:* tab registrations', () => {
|
||||
it('registers the 3 apes tabs with the apes: namespace', () => {
|
||||
const { service, dispose } = setup()
|
||||
try {
|
||||
expect(service.getTabs().map(t => t.id).sort()).toEqual(
|
||||
['apes:agents', 'apes:apps', 'apes:profile'],
|
||||
)
|
||||
} finally {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('every apes tab is single-instance, visible, and component-carrying', () => {
|
||||
const { service, dispose } = setup()
|
||||
try {
|
||||
for (const id of ['apes:agents', 'apes:apps', 'apes:profile']) {
|
||||
const tab = service.getTab(id)
|
||||
expect(tab, `${id} registered`).toBeDefined()
|
||||
expect(tab?.single, `${id} single`).toBe(true)
|
||||
expect(tab?.hidden, `${id} hidden`).not.toBe(true)
|
||||
expect(tab?.component, `${id} component`).toBeDefined()
|
||||
expect(tab?.icon, `${id} icon`).toBeDefined()
|
||||
}
|
||||
} finally {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('apes tabs sort after the upstream builtins (order 40+)', () => {
|
||||
const { service, dispose } = setup()
|
||||
try {
|
||||
const orders = {
|
||||
agents: service.getTab('apes:agents')?.order,
|
||||
apps: service.getTab('apes:apps')?.order,
|
||||
profile: service.getTab('apes:profile')?.order,
|
||||
}
|
||||
// C8: order 40-50 places apes tabs immediately after the native builtins
|
||||
// (10-35), not in a far-away 900+ band — visual unity in the tab strip.
|
||||
expect(orders.agents).toBeGreaterThanOrEqual(40)
|
||||
expect(orders.apps).toBeGreaterThanOrEqual(40)
|
||||
expect(orders.profile).toBeGreaterThanOrEqual(40)
|
||||
// Strictly ordered: agents < apps < profile.
|
||||
expect(orders.agents!).toBeLessThan(orders.apps!)
|
||||
expect(orders.apps!).toBeLessThan(orders.profile!)
|
||||
} finally {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('the disposer unregisters all apes tabs (HMR-safe)', () => {
|
||||
const store = createSidebarStore()
|
||||
const service = createBetterSidebarService(store)
|
||||
const dispose = registerApesTabs({} as Context, service)
|
||||
expect(service.getTabs()).toHaveLength(3)
|
||||
dispose()
|
||||
expect(service.getTabs()).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('apes i18n contract', () => {
|
||||
it('every apesZh key has an apesEn entry (no missing translations)', () => {
|
||||
const zhKeys = Object.keys(apesZh) as ApesCopyKey[]
|
||||
for (const key of zhKeys) {
|
||||
expect(apesEn[key], `en entry for ${key}`).toBeDefined()
|
||||
expect(typeof apesEn[key]).toBe('string')
|
||||
expect((apesEn[key] ?? '').length).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('resolves zh when the DSH preference is zh', () => {
|
||||
attachApesLocale({ getSnapshot: () => ({ active: 'zh-CN' }) })
|
||||
expect(t('apesAgentsTitle')).toBe('智能体')
|
||||
expect(t('apesAppsTitle')).toBe('应用')
|
||||
expect(t('apesProfileTitle')).toBe('画像')
|
||||
})
|
||||
|
||||
it('resolves en when the DSH preference is en', () => {
|
||||
attachApesLocale({ getSnapshot: () => ({ active: 'en' }) })
|
||||
expect(t('apesAgentsTitle')).toBe('Agents')
|
||||
expect(t('apesAppsTitle')).toBe('Apps')
|
||||
expect(t('apesProfileTitle')).toBe('Profile')
|
||||
})
|
||||
|
||||
it('falls back to zh when no locale service is attached', () => {
|
||||
attachApesLocale(undefined)
|
||||
expect(t('apesAgentsTitle')).toBe('智能体')
|
||||
})
|
||||
})
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Mirrors the "external consumer" fixture: what is importable here from
|
||||
* `../src/client/service.ts` must also be importable from
|
||||
* `dsh-better-sidebar/client/service` in the built package.
|
||||
* `dsh-apes-sidebar/client/service` in the built package.
|
||||
*/
|
||||
import type {} from '../src/client/service.ts'
|
||||
import {
|
||||
|
||||
@@ -68,7 +68,7 @@ test('right panel keeps desktop session actions in their header positions', asyn
|
||||
const root = page.locator('#root')
|
||||
const frame = page.locator('#root [data-dsh-frame], #root > [data-slot="root"] > div').first()
|
||||
const appSidebarExpanded = root.getByRole('button', { name: /^(Collapse sidebar|收起侧边栏)$/ })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
const sessionLog = page.getByRole('button', { name: 'Session log', exact: true })
|
||||
const sessionLogLabel = sessionLog.getByText('Session log', { exact: true })
|
||||
await expect(sessionLogLabel, 'the desktop session-log action starts as a text button').toBeVisible({ timeout: 30_000 })
|
||||
|
||||
@@ -68,7 +68,7 @@ interface FrameSample {
|
||||
test('width drag tracks the shell 1:1 with transitions disabled (issue #92)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
|
||||
// Dismiss whatever onboarding takeover is present (same dance as the mount
|
||||
@@ -119,7 +119,7 @@ test('width drag tracks the shell 1:1 with transitions disabled (issue #92)', as
|
||||
// window's tree-dock handle matches too, but the panel strip is always the
|
||||
// LEFTMOST one (the dock sits at the panel's right edge).
|
||||
const locateStrip = `(() => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
if (host === null) return null
|
||||
const boxes = [...host.querySelectorAll('*')]
|
||||
.filter(el => getComputedStyle(el).cursor === 'col-resize')
|
||||
@@ -156,7 +156,7 @@ test('width drag tracks the shell 1:1 with transitions disabled (issue #92)', as
|
||||
const samples: Sample[] = []
|
||||
// Same rule as the strip locator above: the LEFTMOST col-resize element
|
||||
// inside the sidebar host (the tree-dock handle is further right).
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
const strip = host === null
|
||||
? null
|
||||
: [...host.querySelectorAll<HTMLElement>('*')]
|
||||
@@ -246,7 +246,7 @@ test('width drag tracks the shell 1:1 with transitions disabled (issue #92)', as
|
||||
test('a very fast width drag still commits the dragged position (no rollback on quick release)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
|
||||
// Dismiss whatever onboarding takeover is present (same dance as the
|
||||
@@ -296,7 +296,7 @@ test('a very fast width drag still commits the dragged position (no rollback on
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const box = await page.evaluate(() => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
const el = [...host!.querySelectorAll('*')]
|
||||
.filter(e => getComputedStyle(e).cursor === 'col-resize')
|
||||
.map(e => e.getBoundingClientRect())
|
||||
@@ -310,7 +310,7 @@ test('a very fast width drag still commits the dragged position (no rollback on
|
||||
}, { timeout: 30_000 })
|
||||
.toBe(true)
|
||||
const stripBox = await page.evaluate(() => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
if (host === null) return null
|
||||
const boxes = [...host.querySelectorAll('*')]
|
||||
.filter(el => getComputedStyle(el).cursor === 'col-resize')
|
||||
@@ -394,7 +394,7 @@ async function settleWidthStrip(page: Page): Promise<{ startX: number; startY: n
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const box = await page.evaluate(() => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
const el = [...host!.querySelectorAll('*')]
|
||||
.filter(e => getComputedStyle(e).cursor === 'col-resize')
|
||||
.map(e => e.getBoundingClientRect())
|
||||
@@ -408,7 +408,7 @@ async function settleWidthStrip(page: Page): Promise<{ startX: number; startY: n
|
||||
}, { timeout: 30_000 })
|
||||
.toBe(true)
|
||||
const stripBox = await page.evaluate(() => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
if (host === null) return null
|
||||
const boxes = [...host.querySelectorAll('*')]
|
||||
.filter(el => getComputedStyle(el).cursor === 'col-resize')
|
||||
@@ -436,7 +436,7 @@ async function dispatchPointerOnStrip(
|
||||
init: { clientX?: number; clientY?: number },
|
||||
): Promise<void> {
|
||||
await page.evaluate(({ type, init }) => {
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const host = document.querySelector('[data-dsh-apes-sidebar]')
|
||||
if (host === null) throw new Error('sidebar host missing')
|
||||
const el = [...host.querySelectorAll<HTMLElement>('*')]
|
||||
.filter(el => getComputedStyle(el).cursor === 'col-resize')
|
||||
@@ -458,7 +458,7 @@ async function dispatchPointerOnStrip(
|
||||
test('an interrupted fast drag (pointercancel → lostpointercapture) keeps the dragged width (issue #247)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissOnboarding(page)
|
||||
await expandSidebar(page, sidebar)
|
||||
@@ -493,7 +493,7 @@ test('an interrupted fast drag (pointercancel → lostpointercapture) keeps the
|
||||
test('a capture-lost drag with no usable coordinates keeps the last applied width (issue #247)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissOnboarding(page)
|
||||
await expandSidebar(page, sidebar)
|
||||
@@ -528,7 +528,7 @@ test('a capture-lost drag with no usable coordinates keeps the last applied widt
|
||||
test('bottom panel never flashes full-width after a width drag release (issue #258)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissOnboarding(page)
|
||||
await expandSidebar(page, sidebar)
|
||||
@@ -560,7 +560,7 @@ test('bottom panel never flashes full-width after a width drag release (issue #2
|
||||
await page.evaluate(() => {
|
||||
const samples: Array<{ t: number; bottomRight: number; colRight: number; varW: string; dragging: boolean; iw: number }> = []
|
||||
const loop = (): void => {
|
||||
const bottom = document.querySelector('[data-dsh-better-sidebar] [data-dsh-bottom-panel]')
|
||||
const bottom = document.querySelector('[data-dsh-apes-sidebar] [data-dsh-bottom-panel]')
|
||||
const col = document.querySelector('#root [data-slot="conversation"]')?.parentElement
|
||||
samples.push({
|
||||
t: performance.now(),
|
||||
@@ -621,7 +621,7 @@ test('the bottom-push anchor resolves through the shell-written center-column ta
|
||||
// node: a stale tag on a swapped-out node (boot swap / HMR) would leave
|
||||
// the push rule anchorless or doubled.
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('[data-dsh-better-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('[data-dsh-apes-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect
|
||||
.poll(async () => page.evaluate(() => document.querySelectorAll('#root [data-dsh-center-col]').length), { timeout: 90_000 })
|
||||
.toBe(1)
|
||||
@@ -651,7 +651,7 @@ test('dragging the bottom strip while the right panel is closed keeps the host l
|
||||
// derives from it); only the PUSHED width must ride the panelOpen gate.
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissOnboarding(page)
|
||||
|
||||
@@ -714,7 +714,7 @@ test('dragging the bottom strip while the right panel is closed keeps the host l
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const probe = await page.evaluate(() => {
|
||||
const bottom = document.querySelector('[data-dsh-better-sidebar] [data-dsh-bottom-panel]')
|
||||
const bottom = document.querySelector('[data-dsh-apes-sidebar] [data-dsh-bottom-panel]')
|
||||
if (bottom === null) return null
|
||||
const strip = [...bottom.querySelectorAll<HTMLElement>('*')].find(el => getComputedStyle(el).cursor === 'row-resize')
|
||||
if (strip === undefined) return null
|
||||
@@ -726,7 +726,7 @@ test('dragging the bottom strip while the right panel is closed keeps the host l
|
||||
}, { timeout: 30_000 })
|
||||
.toBeLessThanOrEqual(8)
|
||||
const stripBox = await page.evaluate(() => {
|
||||
const bottom = document.querySelector('[data-dsh-better-sidebar] [data-dsh-bottom-panel]')
|
||||
const bottom = document.querySelector('[data-dsh-apes-sidebar] [data-dsh-bottom-panel]')
|
||||
if (bottom === null) return null
|
||||
const strip = [...bottom.querySelectorAll<HTMLElement>('*')].find(el => getComputedStyle(el).cursor === 'row-resize')
|
||||
if (strip === undefined) return null
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* floats another tab with the hint overlay showing mid-drag.
|
||||
*
|
||||
* Crash discipline mirrors the mount lane: pageerror / plugin console errors
|
||||
* / dsh-better-sidebar strips fail the test at every step.
|
||||
* / dsh-apes-sidebar strips fail the test at every step.
|
||||
*/
|
||||
import { mkdirSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
@@ -23,7 +23,7 @@ import { PAGE_URL, createHostApi, hostRpc } from './host'
|
||||
|
||||
const WORKSPACE_PATH = process.env.DSH_E2E_WORKSPACE ?? join(tmpdir(), 'dsh-e2e-float-workspace')
|
||||
|
||||
const CRASH_STRIP_PATTERNS = [/^dsh-better-sidebar:/, /^\[dsh-better-sidebar\]/]
|
||||
const CRASH_STRIP_PATTERNS = [/^dsh-apes-sidebar:/, /^\[dsh-apes-sidebar\]/]
|
||||
|
||||
let api: APIRequestContext
|
||||
|
||||
@@ -84,7 +84,7 @@ const bootExpanded = async (page: Page): Promise<ReturnType<Page['locator']>> =>
|
||||
})
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissTakeovers(page)
|
||||
await expect(sidebar.locator('[title]').first()).toBeAttached({ timeout: 90_000 })
|
||||
@@ -96,13 +96,13 @@ const bootExpanded = async (page: Page): Promise<ReturnType<Page['locator']>> =>
|
||||
), { timeout: 90_000 })
|
||||
.not.toBe('')
|
||||
expect(pageErrors, 'page errors during boot').toEqual([])
|
||||
expect(consoleErrors.filter(text => text.includes('dsh-better-sidebar')), 'plugin console errors during boot').toEqual([])
|
||||
expect(consoleErrors.filter(text => text.includes('dsh-apes-sidebar')), 'plugin console errors during boot').toEqual([])
|
||||
return sidebar
|
||||
}
|
||||
|
||||
/** The crash assertions shared by every step (mount-lane discipline). */
|
||||
async function assertNoCrash(page: Page): Promise<void> {
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
const stripTexts = await sidebar.locator('div').evaluateAll(
|
||||
(nodes, patterns) => nodes.filter((node) => {
|
||||
const text = (node.textContent ?? '').trim()
|
||||
@@ -110,7 +110,7 @@ async function assertNoCrash(page: Page): Promise<void> {
|
||||
}).map((node) => (node.textContent ?? '').trim()),
|
||||
CRASH_STRIP_PATTERNS,
|
||||
)
|
||||
expect(stripTexts, 'a dsh-better-sidebar error strip is present').toEqual([])
|
||||
expect(stripTexts, 'a dsh-apes-sidebar error strip is present').toEqual([])
|
||||
}
|
||||
|
||||
/** The conversation column's viewport rect — the production drag-out target
|
||||
@@ -183,7 +183,7 @@ test('float a tab, move the window, reload restores it, dock it back', async ({
|
||||
await page.waitForTimeout(500)
|
||||
await page.reload({ waitUntil: 'domcontentloaded' })
|
||||
await dismissTakeovers(page)
|
||||
const sidebar2 = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar2 = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar2.locator('[data-dsh-float-window]')).toHaveCount(1, { timeout: 90_000 })
|
||||
await assertNoCrash(page)
|
||||
|
||||
|
||||
+11
-11
@@ -10,7 +10,7 @@
|
||||
* (the same `workspace.create` / `session.create` calls the UI makes),
|
||||
* so the sidebar has a real session to render;
|
||||
* 2. loads the page in headless Chromium and asserts the shell and the
|
||||
* plugin's `[data-dsh-better-sidebar]` host mount;
|
||||
* plugin's `[data-dsh-apes-sidebar]` host mount;
|
||||
* 3. asserts the plugin's crash markers never appear (no RenderBoundary /
|
||||
* fail() strips, no `pageerror`, no plugin-prefixed console errors);
|
||||
* 4. expands the collapsed panel (openByDefault defaults off), sweeps every
|
||||
@@ -54,7 +54,7 @@ const SEEDED_README_FILE = 'readme-style.md'
|
||||
* renders a strip whose text starts with these prefixes instead of crashing
|
||||
* (see src/client/index.tsx `fail()` and src/client/RenderBoundary.tsx).
|
||||
*/
|
||||
const CRASH_STRIP_PATTERNS = [/^dsh-better-sidebar:/, /^\[dsh-better-sidebar\]/]
|
||||
const CRASH_STRIP_PATTERNS = [/^dsh-apes-sidebar:/, /^\[dsh-apes-sidebar\]/]
|
||||
|
||||
/** Built-in tab titles the sweep drives (en-US copy; follows DSH locale). */
|
||||
const BUILTIN_TABS = ['Files', 'Changes', 'Tasks', 'Side Chat (beta)', 'Terminal', 'Browser']
|
||||
@@ -150,7 +150,7 @@ test('plugin mounts into the DSH shell and survives a built-in tab sweep', async
|
||||
})
|
||||
|
||||
// Load the shell. The app renders into #root; the plugin appends its own
|
||||
// [data-dsh-better-sidebar] host once its client half activates.
|
||||
// [data-dsh-apes-sidebar] host once its client half activates.
|
||||
//
|
||||
// The editor chunk (client-editor.js) loads as soon as ANY files-window tab
|
||||
// renders — the seeded home tab mounts the moment the panel expands, long
|
||||
@@ -162,7 +162,7 @@ test('plugin mounts into the DSH shell and survives a built-in tab sweep', async
|
||||
)
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
// The unified panel host: the fixed containing block every panel lives in
|
||||
// (data-dsh-panel-host). Its presence is part of the injection contract.
|
||||
@@ -265,7 +265,7 @@ test('plugin mounts into the DSH shell and survives a built-in tab sweep', async
|
||||
}).map((node) => (node.textContent ?? '').trim()),
|
||||
CRASH_STRIP_PATTERNS,
|
||||
)
|
||||
expect(stripTexts, 'a dsh-better-sidebar error strip is present in the sidebar').toEqual([])
|
||||
expect(stripTexts, 'a dsh-apes-sidebar error strip is present in the sidebar').toEqual([])
|
||||
}
|
||||
|
||||
// Sweep every built-in tab through the "+" menu (the sidebar's own open-tab
|
||||
@@ -429,7 +429,7 @@ test('plugin mounts into the DSH shell and survives a built-in tab sweep', async
|
||||
).toHaveCount(1, { timeout: 30_000 })
|
||||
// The markdown PREVIEW must render before the mermaid chunk can be
|
||||
// requested — this assertion separates a preview/render regression from a
|
||||
// chunk-loading one. (sidebar is already scoped to [data-dsh-better-sidebar].)
|
||||
// chunk-loading one. (sidebar is already scoped to [data-dsh-apes-sidebar].)
|
||||
await expect(
|
||||
sidebar.getByText('tail text'),
|
||||
'the markdown preview must render the seeded document',
|
||||
@@ -540,7 +540,7 @@ test('plugin mounts into the DSH shell and survives a built-in tab sweep', async
|
||||
|
||||
// The plugin's own console prefix must never appear in errors, and no
|
||||
// unhandled rejection may escape the sweep.
|
||||
const pluginErrors = consoleErrors.filter((text) => /dsh-better-sidebar|Unhandled/.test(text))
|
||||
const pluginErrors = consoleErrors.filter((text) => /dsh-apes-sidebar|Unhandled/.test(text))
|
||||
expect(pluginErrors, 'plugin-prefixed or unhandled console errors during the sweep').toEqual([])
|
||||
expect(pageErrors, 'pageerrors during the sweep').toEqual([])
|
||||
|
||||
@@ -556,7 +556,7 @@ test('conservative auto: URL stamps alone never modify the layout; plugin chrome
|
||||
// semantics) — the strip/body attribute appear only for real standard
|
||||
// geometry (see the WCO scenario below) or an opt-in preset.
|
||||
await gotoPage(page, { 'dsh-desktop-mode': 'advanced', 'dsh-desktop-platform': 'win32' })
|
||||
await expect(page.locator('[data-dsh-better-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('[data-dsh-apes-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(
|
||||
page.locator('body[data-dsh-title-bar-compat]'),
|
||||
'stamps alone must NOT auto-enable title-bar compatibility under auto',
|
||||
@@ -604,7 +604,7 @@ test('standard WCO geometry drives the strip reactively (issue #257)', async ({
|
||||
}
|
||||
})
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('[data-dsh-better-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('[data-dsh-apes-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
// Real reported height (36px, not a hardcoded 32) drives the strip.
|
||||
await expect(page.locator('body[data-dsh-title-bar-compat]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect
|
||||
@@ -631,7 +631,7 @@ test('opt-in shell preset applies its strip when WCO is absent (data-driven, man
|
||||
expect(update.ok(), `settings.update: ${update.status()}`).toBe(true)
|
||||
try {
|
||||
await gotoPage(page, { 'dsh-desktop-mode': 'advanced', 'dsh-desktop-platform': 'win32' })
|
||||
await expect(page.locator('[data-dsh-better-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('[data-dsh-apes-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('body[data-dsh-title-bar-compat]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect
|
||||
.poll(() => page.evaluate(() => document.documentElement.style.getPropertyValue('--dsh-title-bar-strip')))
|
||||
@@ -656,7 +656,7 @@ test('custom scheme injects the user stylesheet live', async ({ request, page })
|
||||
expect(update.ok(), `settings.update: ${update.status()}`).toBe(true)
|
||||
try {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('[data-dsh-better-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('[data-dsh-apes-sidebar]')).toBeAttached({ timeout: 90_000 })
|
||||
await expect(page.locator('style[data-dsh-custom-css="custom"]')).toBeAttached()
|
||||
// The injected CSS is live (a custom property the page can read back).
|
||||
const marker = await page.evaluate(() => getComputedStyle(document.documentElement).getPropertyValue('--dsh-e2e-marker').trim())
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* It exists to put NUMBERS on the sidebar's client-side cost in a real
|
||||
* mounted `dsh web` (the same scratch-profile boot as scripts/e2e-mount.sh):
|
||||
*
|
||||
* 1. mount latency — navigationStart → `[data-dsh-better-sidebar]`
|
||||
* 1. mount latency — navigationStart → `[data-dsh-apes-sidebar]`
|
||||
* attached, sampled by an init-script probe (rAF loop, so it catches
|
||||
* the attach even before Playwright's first poll);
|
||||
* 2. longtasks — every >50ms main-thread task from first paint
|
||||
@@ -62,7 +62,7 @@ const PERF_PROBE = `(() => {
|
||||
for (const entry of list.getEntries()) perf.longtasks.push({ start: entry.startTime, duration: entry.duration })
|
||||
}).observe({ entryTypes: ['longtask'] })
|
||||
const check = () => {
|
||||
if (document.querySelector('[data-dsh-better-sidebar]') !== null) { perf.mountAt = performance.now(); return }
|
||||
if (document.querySelector('[data-dsh-apes-sidebar]') !== null) { perf.mountAt = performance.now(); return }
|
||||
requestAnimationFrame(check)
|
||||
}
|
||||
requestAnimationFrame(check)
|
||||
@@ -113,7 +113,7 @@ test('measure: mount latency, longtasks and bundle cost through a full tab sweep
|
||||
await page.addInitScript(PERF_PROBE)
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
|
||||
const mountLatency = await page.evaluate(() =>
|
||||
@@ -183,7 +183,7 @@ test('measure: bottom-strip drag frame pacing', async ({ page }) => {
|
||||
await page.addInitScript(PERF_PROBE)
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
await dismissOnboarding(page)
|
||||
|
||||
@@ -221,7 +221,7 @@ test('measure: bottom-strip drag frame pacing', async ({ page }) => {
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const probe = await page.evaluate(() => {
|
||||
const bottom = document.querySelector('[data-dsh-better-sidebar] [data-dsh-bottom-panel]')
|
||||
const bottom = document.querySelector('[data-dsh-apes-sidebar] [data-dsh-bottom-panel]')
|
||||
if (bottom === null) return null
|
||||
const strip = [...bottom.querySelectorAll<HTMLElement>('*')].find(el => getComputedStyle(el).cursor === 'row-resize')
|
||||
if (strip === undefined) return null
|
||||
@@ -233,7 +233,7 @@ test('measure: bottom-strip drag frame pacing', async ({ page }) => {
|
||||
}, { timeout: 30_000 })
|
||||
.toBeLessThanOrEqual(8)
|
||||
const stripPoint = await page.evaluate(() => {
|
||||
const bottom = document.querySelector('[data-dsh-better-sidebar] [data-dsh-bottom-panel]')
|
||||
const bottom = document.querySelector('[data-dsh-apes-sidebar] [data-dsh-bottom-panel]')
|
||||
if (bottom === null) return null
|
||||
const strip = [...bottom.querySelectorAll<HTMLElement>('*')].find(el => getComputedStyle(el).cursor === 'row-resize')
|
||||
if (strip === undefined) return null
|
||||
|
||||
@@ -51,7 +51,7 @@ interface FrameSample {
|
||||
test('bottom panel tracks the center column during the right-panel toggle transition (issue #315)', async ({ page }) => {
|
||||
await page.goto(PAGE_URL, { waitUntil: 'domcontentloaded' })
|
||||
await expect(page.locator('#root > *')).not.toHaveCount(0, { timeout: 90_000 })
|
||||
const sidebar = page.locator('[data-dsh-better-sidebar]')
|
||||
const sidebar = page.locator('[data-dsh-apes-sidebar]')
|
||||
await expect(sidebar).toBeAttached({ timeout: 90_000 })
|
||||
|
||||
// Dismiss onboarding (same dance as the drag lane).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Fixture aggregate bundle: mounts dsh-better-sidebar under its own entry id,
|
||||
# Fixture aggregate bundle: mounts dsh-apes-sidebar under its own entry id,
|
||||
# the way real aggregate bundles (e.g. @linxin666/dsh-web-ui-all) do. Used by
|
||||
# scripts/e2e-aggregate-mount.sh to prove the plugin's own bundle patch backs
|
||||
# off when another enabled entry already mounts the same package.
|
||||
- insert:
|
||||
- id: aggregate-better-sidebar
|
||||
name: 'dsh-better-sidebar'
|
||||
name: 'dsh-apes-sidebar'
|
||||
|
||||
@@ -6,9 +6,9 @@ import { join, resolve } from 'node:path'
|
||||
import { parseWorktreeList, resolveWorktree, status, worktrees } from '../src/git.ts'
|
||||
|
||||
const IDENTITY = {
|
||||
GIT_AUTHOR_NAME: 'dsh-better-sidebar-test',
|
||||
GIT_AUTHOR_NAME: 'dsh-apes-sidebar-test',
|
||||
GIT_AUTHOR_EMAIL: 'test@dsh.invalid',
|
||||
GIT_COMMITTER_NAME: 'dsh-better-sidebar-test',
|
||||
GIT_COMMITTER_NAME: 'dsh-apes-sidebar-test',
|
||||
GIT_COMMITTER_EMAIL: 'test@dsh.invalid',
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ const canonical = (path: string): string => normalizePath(realpathSync.native(pa
|
||||
|
||||
describe('git parsing', () => {
|
||||
it('discovers and selects direct child repositories under a workspace directory', async () => {
|
||||
const workspace = await mkdtemp(join(tmpdir(), 'dsh-better-sidebar-git-'))
|
||||
const workspace = await mkdtemp(join(tmpdir(), 'dsh-apes-sidebar-git-'))
|
||||
const first = join(workspace, 'first-repo')
|
||||
const second = join(workspace, 'second-repo')
|
||||
try {
|
||||
|
||||
@@ -60,7 +60,7 @@ function assertInMemoryInvocation(executable: string): void {
|
||||
const output = `${result.stdout}\n${result.stderr}`
|
||||
|
||||
expect(result.status, output).toBe(0)
|
||||
expect(output).toContain('dsh-better-sidebar@0.11.0')
|
||||
expect(output).toContain('dsh-apes-sidebar@0.11.0')
|
||||
expect(output).toContain('[dry-run]')
|
||||
expect(output).not.toContain('False False')
|
||||
}
|
||||
@@ -118,7 +118,7 @@ describe('PowerShell installer entry points', () => {
|
||||
const output = `${result.stdout}\n${result.stderr}`
|
||||
|
||||
expect(result.status, output).toBe(0)
|
||||
expect(output).toContain('dsh-better-sidebar@0.11.0')
|
||||
expect(output).toContain('dsh-apes-sidebar@0.11.0')
|
||||
expect(output).toContain('[dry-run]')
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Native right-sidebar bridge tests (Phase A spike).
|
||||
*
|
||||
* `registerApesNativeTabs` publishes apes:profile as an OFFICIAL
|
||||
* `@deepseek-ai/dsh-client-ui-sidebar-right` tab type over the public
|
||||
* two-stage protocol: the type declaration on `ctx.sidebarRightTabs`, then the
|
||||
* keyed body on the `sidebar.right.pane.tab` seat. The bridge reaches the
|
||||
* registry through `ctx.inject(['sidebarRightTabs'], …)` so activation order
|
||||
* cannot strand it, and a deployment without the official sidebar must stay a
|
||||
* silent no-op instead of breaking the fork's own shell.
|
||||
*
|
||||
* The spec drives that contract with a fake cordis context (a recording
|
||||
* `inject` + `effect`), so it pins: the dependency name, the definition's
|
||||
* identity/band/guide entry, the body's seat key, the disposer's unwind, and
|
||||
* both no-op paths. No DOM and no real DSH host — same node environment as
|
||||
* apes-tabs.spec.ts.
|
||||
*/
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
// Browser globals before the client graph loads (mirror of apes-tabs.spec.ts).
|
||||
import './browser-globals.ts'
|
||||
|
||||
import { registerApesNativeTabs } from '../src/client/apes/native-tabs.tsx'
|
||||
|
||||
/** One recorded type declaration. */
|
||||
interface RecordedDefinition {
|
||||
id: string
|
||||
kind: string
|
||||
priority?: string
|
||||
title: () => string
|
||||
guide?: Array<{ order: number; title: () => string; description?: () => string; icon?: unknown }>
|
||||
}
|
||||
|
||||
/** One recorded body registration. */
|
||||
interface RecordedBody {
|
||||
options: { name: string; key?: string; inject?: (...args: unknown[]) => Record<string, unknown> }
|
||||
component: unknown
|
||||
}
|
||||
|
||||
/** Build a fake client context plus the registries it hands the bridge. */
|
||||
function harness(options: { service?: boolean } = {}) {
|
||||
const definitions: RecordedDefinition[] = []
|
||||
const bodies: RecordedBody[] = []
|
||||
let typeUnwound = false
|
||||
let bodyUnwound = false
|
||||
|
||||
const registry = {
|
||||
register(definition: RecordedDefinition) {
|
||||
definitions.push(definition)
|
||||
return () => { if (!typeUnwound) typeUnwound = true }
|
||||
},
|
||||
}
|
||||
const slots = {
|
||||
inject(key: string, callback: () => () => void) {
|
||||
// The seat exists: run the declaration callback like the real registry.
|
||||
expect(key).toBe('sidebar.right.pane.tab')
|
||||
return callback()
|
||||
},
|
||||
register(registration: RecordedBody['options'], component: unknown) {
|
||||
bodies.push({ options: registration, component })
|
||||
return () => { if (!bodyUnwound) bodyUnwound = true }
|
||||
},
|
||||
}
|
||||
const effects: Array<() => void> = []
|
||||
const fctx = {
|
||||
get: (name: string) => (options.service === false ? undefined : name === 'sidebarRightTabs' ? registry : undefined),
|
||||
slots,
|
||||
effect: (callback: () => () => void) => { effects.push(callback()) },
|
||||
}
|
||||
const inject = vi.fn((deps: string[], callback: (inner: unknown) => void) => {
|
||||
expect(deps).toEqual(['sidebarRightTabs'])
|
||||
callback(fctx)
|
||||
return { dispose: () => { for (const dispose of effects) dispose() } }
|
||||
})
|
||||
return {
|
||||
ctx: { inject },
|
||||
inject,
|
||||
definitions,
|
||||
bodies,
|
||||
get typeUnwound() { return typeUnwound },
|
||||
get bodyUnwound() { return bodyUnwound },
|
||||
}
|
||||
}
|
||||
|
||||
describe('apes native right-sidebar bridge (spike)', () => {
|
||||
it('waits on ctx.inject for the official registry service', () => {
|
||||
const h = harness()
|
||||
const dispose = registerApesNativeTabs(h.ctx)
|
||||
expect(h.inject).toHaveBeenCalledTimes(1)
|
||||
expect(h.inject.mock.calls[0]![0]).toEqual(['sidebarRightTabs'])
|
||||
dispose()
|
||||
})
|
||||
|
||||
it('registers the profile type in the extension band with a guide entry', () => {
|
||||
const h = harness()
|
||||
const dispose = registerApesNativeTabs(h.ctx)
|
||||
try {
|
||||
expect(h.definitions).toHaveLength(1)
|
||||
const def = h.definitions[0]!
|
||||
expect(def.id).toBe('dsh-apes-sidebar/profile')
|
||||
expect(def.kind).toBe('apes:profile')
|
||||
// `extension` is the band for types contributed from outside the product.
|
||||
expect(def.priority).toBe('extension')
|
||||
// The title is read fresh (locale switches must follow).
|
||||
expect(def.title()).toBe('画像')
|
||||
expect(def.guide).toHaveLength(1)
|
||||
const entry = def.guide![0]!
|
||||
expect(entry.order).toBe(70)
|
||||
expect(entry.title()).toBe('画像')
|
||||
expect(typeof entry.description?.()).toBe('string')
|
||||
expect(entry.icon).toBeDefined()
|
||||
} finally {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('registers the body under the type id on the keyed seat', () => {
|
||||
const h = harness()
|
||||
const dispose = registerApesNativeTabs(h.ctx)
|
||||
try {
|
||||
expect(h.bodies).toHaveLength(1)
|
||||
const body = h.bodies[0]!
|
||||
expect(body.options.name).toBe('sidebar.right.pane.tab')
|
||||
// The seat key MUST equal the registered id — that is how the panel
|
||||
// dispatches a tab body to our type.
|
||||
expect(body.options.key).toBe(h.definitions[0]!.id)
|
||||
expect(body.component).toBeDefined()
|
||||
// The body's injected props carry the client context the view reads.
|
||||
expect(body.options.inject?.()).toEqual({ ctx: h.ctx })
|
||||
} finally {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('the disposer unwinds both stages (HMR-safe)', () => {
|
||||
const h = harness()
|
||||
const dispose = registerApesNativeTabs(h.ctx)
|
||||
expect(h.definitions).toHaveLength(1)
|
||||
expect(h.bodies).toHaveLength(1)
|
||||
dispose()
|
||||
expect(h.typeUnwound).toBe(true)
|
||||
expect(h.bodyUnwound).toBe(true)
|
||||
})
|
||||
|
||||
it('is a silent no-op when the official registry service never arrives', () => {
|
||||
const h = harness({ service: false })
|
||||
const dispose = registerApesNativeTabs(h.ctx)
|
||||
expect(h.inject).toHaveBeenCalledTimes(1)
|
||||
expect(h.definitions).toHaveLength(0)
|
||||
expect(h.bodies).toHaveLength(0)
|
||||
expect(() => dispose()).not.toThrow()
|
||||
})
|
||||
|
||||
it('is a no-op for a context without inject (non-cordis harness)', () => {
|
||||
expect(() => registerApesNativeTabs({} as never)()).not.toThrow()
|
||||
})
|
||||
})
|
||||
@@ -8,7 +8,7 @@ import * as sidebar from '../src/index.ts'
|
||||
* the official plugin repos ship (dsh-external/turtle-ui,
|
||||
* packages/ui/jsonrpc).
|
||||
*/
|
||||
describe('dsh-better-sidebar plugin export shape', () => {
|
||||
describe('dsh-apes-sidebar plugin export shape', () => {
|
||||
it('has the namespace-plugin export shape (no stray default) so the Loader keeps name/inject/Config/apply', () => {
|
||||
expect('default' in sidebar).toBe(false)
|
||||
expect(typeof sidebar.apply).toBe('function')
|
||||
@@ -16,7 +16,7 @@ describe('dsh-better-sidebar plugin export shape', () => {
|
||||
const loader = Object.create(Loader.prototype) as Loader
|
||||
const unwrapped = loader.unwrapExports(sidebar) as Record<string, unknown>
|
||||
expect(unwrapped).toBe(sidebar)
|
||||
expect(unwrapped.name).toBe('dsh-better-sidebar')
|
||||
expect(unwrapped.name).toBe('dsh-apes-sidebar')
|
||||
expect(unwrapped.inject).toEqual(['webServer', 'sessions', 'webRuntime', 'tools'])
|
||||
expect(unwrapped.Config).toBeDefined()
|
||||
expect(typeof unwrapped.apply).toBe('function')
|
||||
@@ -53,7 +53,7 @@ describe('dsh-better-sidebar plugin export shape', () => {
|
||||
|
||||
it('registers the side card preferences schema with the documented defaults', async () => {
|
||||
const { PrefsSchema, SIDEBAR_PREFS_NS } = await import('../src/config.ts')
|
||||
expect(SIDEBAR_PREFS_NS).toBe('dsh-better-sidebar')
|
||||
expect(SIDEBAR_PREFS_NS).toBe('dsh-apes-sidebar')
|
||||
const resolved = (PrefsSchema as unknown as {
|
||||
(input: Record<string, unknown> | undefined): Record<string, unknown>
|
||||
})(undefined)
|
||||
|
||||
@@ -114,12 +114,12 @@ describe('findProfileDir / findPluginRoot', () => {
|
||||
beforeEach(() => {
|
||||
root = mkdtempSync(join(tmpdir(), 'pty-deps-'))
|
||||
// A fake plugin module deep inside the profile's pnpm node_modules.
|
||||
const pkgRoot = join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-better-sidebar@0.0.0', 'node_modules', 'dsh-better-sidebar')
|
||||
const pkgRoot = join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-apes-sidebar@0.0.0', 'node_modules', 'dsh-apes-sidebar')
|
||||
const libDir = join(pkgRoot, 'lib')
|
||||
mkdirSync(libDir, { recursive: true })
|
||||
writeFileSync(join(root, 'profiles', 'web', 'package.json'), JSON.stringify({ name: 'dsh-profile-web' }))
|
||||
writeFileSync(join(root, 'profiles', 'web', 'pnpm-workspace.yaml'), '')
|
||||
writeFileSync(join(pkgRoot, 'package.json'), JSON.stringify({ name: 'dsh-better-sidebar' }))
|
||||
writeFileSync(join(pkgRoot, 'package.json'), JSON.stringify({ name: 'dsh-apes-sidebar' }))
|
||||
moduleFile = join(libDir, 'index.js')
|
||||
writeFileSync(moduleFile, '')
|
||||
})
|
||||
@@ -131,7 +131,7 @@ describe('findProfileDir / findPluginRoot', () => {
|
||||
})
|
||||
|
||||
it('walks up to the plugin package root by package.json name', () => {
|
||||
expect(findPluginRoot(moduleFile)).toBe(realpathSync(join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-better-sidebar@0.0.0', 'node_modules', 'dsh-better-sidebar')))
|
||||
expect(findPluginRoot(moduleFile)).toBe(realpathSync(join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-apes-sidebar@0.0.0', 'node_modules', 'dsh-apes-sidebar')))
|
||||
})
|
||||
|
||||
it('falls back to $DSH_HOME/profiles/web when no ancestor looks like a profile', () => {
|
||||
@@ -161,12 +161,12 @@ describe('depsStatus', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
root = mkdtempSync(join(tmpdir(), 'pty-deps-'))
|
||||
const pkgRoot = join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-better-sidebar@0.0.0', 'node_modules', 'dsh-better-sidebar')
|
||||
const pkgRoot = join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-apes-sidebar@0.0.0', 'node_modules', 'dsh-apes-sidebar')
|
||||
mkdirSync(join(pkgRoot, 'scripts'), { recursive: true })
|
||||
mkdirSync(join(pkgRoot, 'lib'), { recursive: true })
|
||||
writeFileSync(join(root, 'profiles', 'web', 'package.json'), JSON.stringify({ name: 'dsh-profile-web' }))
|
||||
writeFileSync(join(root, 'profiles', 'web', 'pnpm-workspace.yaml'), '')
|
||||
writeFileSync(join(pkgRoot, 'package.json'), JSON.stringify({ name: 'dsh-better-sidebar' }))
|
||||
writeFileSync(join(pkgRoot, 'package.json'), JSON.stringify({ name: 'dsh-apes-sidebar' }))
|
||||
writeFileSync(join(pkgRoot, 'scripts', 'install.sh'), '#!/usr/bin/env bash\n')
|
||||
writeFileSync(join(pkgRoot, 'scripts', 'install.ps1'), '# repair fixture\n')
|
||||
moduleFile = join(pkgRoot, 'lib', 'index.js')
|
||||
@@ -190,7 +190,7 @@ describe('depsStatus', () => {
|
||||
if (status.ok) throw new Error('unreachable')
|
||||
expect(status.cause).toBe('Cannot find package node-pty')
|
||||
const scriptName = process.platform === 'win32' ? 'install.ps1' : 'install.sh'
|
||||
const script = realpathSync(join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-better-sidebar@0.0.0', 'node_modules', 'dsh-better-sidebar', 'scripts', scriptName))
|
||||
const script = realpathSync(join(root, 'profiles', 'web', 'node_modules', '.pnpm', 'dsh-apes-sidebar@0.0.0', 'node_modules', 'dsh-apes-sidebar', 'scripts', scriptName))
|
||||
expect(status.command).toBe(process.platform === 'win32'
|
||||
? `powershell -ExecutionPolicy Bypass -File "${script}" -Repair -Profile "web"`
|
||||
: `bash "${script}" --repair --profile "web"`)
|
||||
|
||||
@@ -373,7 +373,7 @@ function threadLog(): Array<ReturnType<typeof ev>> {
|
||||
ev('turn/end', 1, { turn: 0, reason: { kind: 'completed' } }),
|
||||
ev('session/end-seed', 2),
|
||||
ev('subagent/descriptor', 3, { mode: 'continuable' }),
|
||||
ev('user/message', 4, { content: [{ type: 'text', text: 'Side conversation boundary.' }], source: { kind: 'plugin', plugin: 'dsh-better-sidebar' } }),
|
||||
ev('user/message', 4, { content: [{ type: 'text', text: 'Side conversation boundary.' }], source: { kind: 'plugin', plugin: 'dsh-apes-sidebar' } }),
|
||||
ev('user/message', 5, { content: [{ type: 'text', text: 'the side question' }], source: { kind: 'user' } }),
|
||||
ev('assistant/chunk', 6, { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'an' } }),
|
||||
ev('assistant/chunk', 7, { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'swer' } }),
|
||||
|
||||
@@ -56,7 +56,7 @@ function parentLog(): SidebarSessionEvent[] {
|
||||
ev('user/message', 0, userMessage('first question')),
|
||||
ev('turn/start', 1, { turn: 1 }),
|
||||
ev('step/start', 2, { turn: 1, step: 1 }),
|
||||
ev('assistant/message', 3, { turn: 1, step: 1, message: assistantMessage('first answer') }),
|
||||
ev('assistant/message', 3, { turn: 1, step: 1, stream: [], message: assistantMessage('first answer') }),
|
||||
ev('step/end', 4, { turn: 1, step: 1 }),
|
||||
ev('turn/end', 5, { turn: 1, reason: { kind: 'completed' } }),
|
||||
ev('user/message', 6, userMessage('pending question')),
|
||||
|
||||
+2
-2
@@ -388,9 +388,9 @@ describe('host plugin smoke', () => {
|
||||
*/
|
||||
describe('git destructive operations (scratch repository)', () => {
|
||||
const FIXTURE_IDENTITY = {
|
||||
GIT_AUTHOR_NAME: 'dsh-better-sidebar-test',
|
||||
GIT_AUTHOR_NAME: 'dsh-apes-sidebar-test',
|
||||
GIT_AUTHOR_EMAIL: 'test@dsh.invalid',
|
||||
GIT_COMMITTER_NAME: 'dsh-better-sidebar-test',
|
||||
GIT_COMMITTER_NAME: 'dsh-apes-sidebar-test',
|
||||
GIT_COMMITTER_EMAIL: 'test@dsh.invalid',
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ setupReactAct()
|
||||
const deps = {
|
||||
ok: false as const,
|
||||
cause: 'Cannot find package node-pty',
|
||||
command: 'bash "/Users/u/.dsh/profiles/web/node_modules/.pnpm/dsh-better-sidebar@0.0.0/node_modules/dsh-better-sidebar/scripts/install.sh" --repair --profile "web"',
|
||||
command: 'bash "/Users/u/.dsh/profiles/web/node_modules/.pnpm/dsh-apes-sidebar@0.0.0/node_modules/dsh-apes-sidebar/scripts/install.sh" --repair --profile "web"',
|
||||
profile: 'web',
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ describe('turn-tail interception registration (issue #15)', () => {
|
||||
const { options, component } = fake.registered[0]!
|
||||
expect(options.name).toBe('conversation.chat.turnTail')
|
||||
expect(options.priority).toBe(-1)
|
||||
expect(options.registrant).toBe('dsh-better-sidebar')
|
||||
expect(options.registrant).toBe('dsh-apes-sidebar')
|
||||
expect(options.select).toBeTypeOf('function')
|
||||
expect(options.inject).toBeTypeOf('function')
|
||||
expect(component).toBeTypeOf('function')
|
||||
|
||||
+9
-9
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* tsdown build for dsh-better-sidebar: the host-half lib (lib/index.js and
|
||||
* tsdown build for dsh-apes-sidebar: the host-half lib (lib/index.js and
|
||||
* the lib/invariant.js companion, ESM node) plus the two browser client
|
||||
* bundles (lib/client.js and lib/client-registry.js, CJS closure factory) —
|
||||
* one per install channel:
|
||||
*
|
||||
* - `lib/client.js` serves the official profile channel, registering with
|
||||
* the package-name id `dsh-better-sidebar` (the client-modules compose
|
||||
* the package-name id `dsh-apes-sidebar` (the client-modules compose
|
||||
* keys on the package name; keep it in sync with package.json `name`),
|
||||
* - `lib/client-registry.js` serves the plugin-registry channel
|
||||
* (dsh.plugin.json), registering with the manifest id
|
||||
* `dsh-external/dsh-better-sidebar` (the registry browser-side `arrive()`
|
||||
* `dsh-external/dsh-apes-sidebar` (the registry browser-side `arrive()`
|
||||
* check requires bundle id === plugin id).
|
||||
*
|
||||
* Both bundles replicate the official DSH client-bundle preset
|
||||
@@ -119,9 +119,9 @@ function browserSourcePath(source: string, sourcemapPath: string): string {
|
||||
/**
|
||||
* One client bundle build for a plugin id. The same src/client/index.tsx is
|
||||
* compiled twice with only the registered id and the output file name
|
||||
* differing: the official channel uses the package name (`dsh-better-sidebar`)
|
||||
* differing: the official channel uses the package name (`dsh-apes-sidebar`)
|
||||
* and the registry channel uses the manifest id
|
||||
* (`dsh-external/dsh-better-sidebar`).
|
||||
* (`dsh-external/dsh-apes-sidebar`).
|
||||
* @param pluginId - the `__ModuleLoader__.load({ id })` value and the
|
||||
* data-plugin style-tag prefix of this bundle.
|
||||
* @param entryFile - the output file name under lib/.
|
||||
@@ -186,7 +186,7 @@ function clientBundle(pluginId: string, entryFile: string): UserConfig {
|
||||
* loader (src/client/chunk-loader.ts) materializes it with a require built
|
||||
* from the module table's seed words.
|
||||
*
|
||||
* Chunk css tags use the constant plugin id `dsh-better-sidebar` (matching
|
||||
* Chunk css tags use the constant plugin id `dsh-apes-sidebar` (matching
|
||||
* the official channel; the registry channel re-injects an identical copy
|
||||
* of the shared module css — same content, no functional impact).
|
||||
* @param name - chunk name; entry src/client/chunks/<name>.tsx, output
|
||||
@@ -216,7 +216,7 @@ function chunkBundle(name: string): UserConfig {
|
||||
noExternal: (id: string) => (CLIENT_EXTERNALS.includes(id) ? undefined : true),
|
||||
plugins: [
|
||||
purityGatePlugin(),
|
||||
makeCssPlugin('dsh-better-sidebar'),
|
||||
makeCssPlugin('dsh-apes-sidebar'),
|
||||
...(name === 'mermaid' ? [mermaidChunkAliases()] : []),
|
||||
],
|
||||
outputOptions: {
|
||||
@@ -341,9 +341,9 @@ export default [
|
||||
clean: false,
|
||||
},
|
||||
// Official profile channel: bundle id = package name (package.json `name`).
|
||||
clientBundle('dsh-better-sidebar', 'client.js'),
|
||||
clientBundle('dsh-apes-sidebar', 'client.js'),
|
||||
// Plugin-registry channel: bundle id = manifest id (dsh.plugin.json `id`).
|
||||
clientBundle('dsh-external/dsh-better-sidebar', 'client-registry.js'),
|
||||
clientBundle('dsh-external/dsh-apes-sidebar', 'client-registry.js'),
|
||||
// Lazy chunks: shared by both channels, fetched on first use through the
|
||||
// plugin's /sidebar/bundle route (see src/client/chunk-loader.ts).
|
||||
...CHUNKS.map(chunkBundle),
|
||||
|
||||
Reference in New Issue
Block a user