Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
- **Claude Code 配置(Agentic Git 预置)**:新增两项与 Claude Code 相关的配置为 M5 [AI 接缝](./docs/research/05-ai-agent-seams.md) 铺路——① 设置项 `hyperGit.claudeCode.executablePath`(Claude Code CLI 可执行路径,**留空=从 `PATH` 自动探测 `claude`**;描述内嵌 `command:` 链接就地提供「浏览 / 打开 Claude 设置」);② 命令 `hyperGit.setClaudeCodePath`(QuickPick:Browse 文件选择器写回 / **Use system Claude Code** 清空覆盖)与 `hyperGit.openClaudeSettings`(打开 `~/.claude/settings.json`,缺失时经确认创建 `{}`)。采用**原生设置 + 命令**承载(零新增 Webview 面板),路径解析下沉纯函数 [`engine/agent/claude-path.ts`](./src/engine/agent/claude-path.ts)(Vitest 可测),命令实现见 [`adapter/claude-commands.ts`](./src/adapter/claude-commands.ts)。**仅落地配置与快捷入口**,`agent/` 五接缝与 `hyperGit.ai.enabled` 行为不变、零破坏。同步校正 README 指标行(`6 视图 · 101 命令 · 7 配置项 · 372 单元测试`,此前 `97 命令 / 324 测试` 已滞后 HEAD)。完整叙述见 [Claude Code 配置](./docs/features/claude-code-config.md)。
- **Branches 视图按 `/` 前缀分组为文件夹树**:Local / Remote / Tags 三段支持在**平铺**与**按 `/` 前缀分组的可折叠文件夹树**间切换——共享前缀的分支收拢到以前缀命名的文件夹下、叶子仅显示末段后缀(如 `bak/2025`、`bak/master-2025-07` → 📁`bak` → `2025` / `master-2025-07`;远程整体收拢为 `origin` 文件夹并内嵌 `feature`)。新增纯逻辑引擎 [`buildRefTree`](./src/engine/ref/ref-tree.ts)(复用「变更文件目录树」`buildFileTree` 的 trie 构建 + compact 折叠范式;叶子携完整 `RawRef`、命令定位不受影响;分支感知排序:当前 HEAD → 收藏 → 同档文件夹优先、名称数字感知升序),并**隐藏 `origin/HEAD` 符号引用**(对齐主流 Git UI,消除 `origin` 叶子与 `origin` 文件夹同名冲突)。工具栏提供「平铺 ⇄ 树」切换(`hyperGit.branchesGroupByPrefix` / `hyperGit.branchesFlatten`,context key 驱动按钮互斥),偏好按仓库持久化于 `workspaceState`(默认树形),文件夹默认展开、展开态跨刷新稳定。文件夹节点用独立 `contextValue` 且不登记任何右键命令,checkout / delete / rename / merge / rebase / compare / favorite 与多选批量均零改动、零破坏。完整叙述见 [分支前缀分组树](./docs/features/branch-tree-group-by-prefix.md)。

### Changed

- **面板视图默认布局调整(显隐与顺序)**:`package.json` `contributes.views` 声明式微调六视图默认态——**Stash / Shelf** 由 `collapsed` 改为 `visibility:"hidden"`(VS Code schema 中 `hidden` 映射 `hideByDefault`:默认不出现在容器内,仍可经视图标题右键菜单勾选恢复);**Commit / Worktrees** 由 `visible` 改为 `collapsed`(显示但默认折叠、点击标题即展开);**Branches / Graph** 保持 `visible`;容器内声明顺序调整为 **Commit · Branches · Graph · Worktrees**(Stash · Shelf 隐藏排其后)。`initialSize` 权重不变,`src/` 零改动,命令 / 协议 / 菜单 / `viewsWelcome` / 交互零破坏。新增 [`tests/unit/views-layout.test.ts`](./tests/unit/views-layout.test.ts) 声明式护栏锁定顺序与各视图 `visibility`。**平台约束**:`visibility` 仅影响全新安装 / 干净 profile 的初始态——老用户升级后需命令面板「View: Reset View Locations」或右键容器页签「Reset Location」方采用新默认(同 [issue #12](./docs/.agents/issue.md) / [#13](./docs/.agents/issue.md) 平台行为)。决策详见 [issue #16](./docs/.agents/issue.md)。

## [0.0.14] - 2026-07-06 — 修复 GRAPH 视图提交记录时间倒序

修复 GRAPH 视图「All」范围下提交记录未按时间倒序排列的问题——取数参数由 `--topo-order` 改为 `--author-date-order`,令跨分支提交按作者日期正确交错、消除「日期回跳」。纯取数排序修复,不改数据协议、布局算法与任何视图交互。完整用户视角叙述见 [Release Note v0.0.14](./docs/releases/v0.0.14.md)。
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<b>English</b> · <a href="./docs/i18n/zh-CN/README.md">简体中文</a>
</p>

<p align="center"><sub>6 views · 101 commands · 11 settings · 372 unit tests</sub></p>
<p align="center"><sub>6 views · 101 commands · 11 settings · 375 unit tests</sub></p>

## Features

Expand Down Expand Up @@ -78,7 +78,7 @@ See the [Engineering Plan](./docs/architecture/engineering-plan.md), the [Implem
pnpm install # install dependencies
pnpm run compile # type-check + lint + build
pnpm run watch # watch build (press F5 to launch the Extension Host debugger)
pnpm run test:unit # unit tests (pure engine logic, Vitest, 324 cases)
pnpm run test:unit # unit tests (pure engine logic, Vitest, 375 cases)
pnpm run test:integration # integration tests (@vscode/test-electron)
pnpm run package # production build
pnpm dlx @vscode/vsce package # package the .vsix
Expand Down
10 changes: 9 additions & 1 deletion docs/.agents/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@

- **表因**:用户反馈 Worktrees 视图展开后无法继续缩小(截图中仍占大片空白),要求「所有视图可拖到任意高度、取消最小高度限制」。
- **根因**:侧边栏每个视图面板(`Pane`)的最小体高由 VS Code 核心**硬编码 = 120px**(竖直方向;构造函数 `this._minimumBodySize = ... orientation === HORIZONTAL ? 200 : 120`,见 `src/vs/base/browser/ui/splitview/paneview.ts`),加 22px 标题栏,展开态最小 ≈ **142px**,该值经 `minimumSize` 直接驱动 SplitView 拖拽分隔条下限。`WebviewViewPane extends ViewPane` **未覆写** `minimumBodySize`,故本扩展 2 个 webview(Commit/Graph)与 4 个 tree(Branches/Stash/Shelf/Worktrees)视图**共用同一 142px 下限**。允许扩展为活动栏容器内视图指定固定/最小/最大高度的官方特性请求 [microsoft/vscode#123715](https://github.com/microsoft/vscode/issues/123715) 已被**关闭为 not planned / out-of-scope**,从未新增任何 API 或 `package.json` 贡献点。扩展运行于独立进程,拿不到工作台面板对象,`minimumBodySize` setter 仅核心 `ViewPaneContainer` 调用;注入 CSS 亦无效(`.pane-body{min-height:0}` 改不动 JS 层用于夹取拖拽下限的 `minimumSize`)。
- **处理方式**:该限制**无法经扩展解除**,采用受支持的折中缓解——在 `package.json` `contributes.views` 调初始布局默认值:次要视图 Stash/Shelf 设 `visibility:"collapsed"`(默认仅 22px 标题栏、点击即展开),Worktrees 保持 `visible`(仅以 `initialSize` 权重收窄),全部视图加 `initialSize`(Commit 3 / Graph 3 / Branches 2 / 其余 1,类 CSS flex 的高度权重)。两字段经 `src/vs/workbench/api/browser/viewsExtensionPoint.ts` 的 `viewDescriptor` schema 确认可用;`initialSize` **仅当「同一扩展同时拥有视图与视图容器」时生效**(本扩展拥有 `hyper-git` 容器与全部视图,条件满足)。
- **处理方式**:该限制**无法经扩展解除**,采用受支持的折中缓解——在 `package.json` `contributes.views` 调初始布局默认值:次要视图 Stash/Shelf 设 `visibility:"collapsed"`(默认仅 22px 标题栏、点击即展开),Worktrees 保持 `visible`(仅以 `initialSize` 权重收窄),全部视图加 `initialSize`(Commit 3 / Graph 3 / Branches 2 / 其余 1,类 CSS flex 的高度权重)。两字段经 `src/vs/workbench/api/browser/viewsExtensionPoint.ts` 的 `viewDescriptor` schema 确认可用;`initialSize` **仅当「同一扩展同时拥有视图与视图容器」时生效**(本扩展拥有 `hyper-git` 容器与全部视图,条件满足)。**注**:此处枚举系 v0.0.12 时点缓解快照——自 #16 起默认布局改为 Stash/Shelf `hidden`、Commit/Worktrees `collapsed`、顺序重排为 Commit·Branches·Graph·Worktrees,**当前默认布局以 #16 为准**。
- **后续防范**:① VS Code 侧边栏视图存在约 **142px 硬性最小展开高度**,无法经扩展降低——遇「任意高度 / 无最小高度」类诉求应直接引 #123715(not planned)说明平台边界,**勿承诺实现**;判断「webview 内容 CSS `min-height`」与「外层面板最小高度」是两回事。② `visibility` / `initialSize` **只影响初始状态**(「用户手动折叠/移动/隐藏过后即不再生效」)——老用户需命令面板「View: Reset View Locations」或右键容器图标「Reset Location」才采用新默认;实机验证须用**干净 profile 或先重置**以规避持久化布局。③ 想让展开视图更紧凑,只能靠「减少常驻视图数(默认折叠)+ 权重」,而非解除下限。
- **同类问题影响**:所有向活动栏/侧边栏容器贡献 TreeView/WebviewView 且希望自定义或取消视图高度的扩展;凡把「webview 内容 `min-height` CSS」误认为能改变外层面板最小高度的实现。

Expand Down Expand Up @@ -131,4 +131,12 @@
- **后续防范**:① 为差异的「缺失端」构造 URI 时,**一律用 git 空树 ref**,不要对不存在对象取 `'HEAD'` / `${hash}^` 这类具名 ref——它们只在旧版 VS Code(容错 readFile)上侥幸可用,新版必抛 FileNotFound。② VS Code git 扩展内部行为(如 readFile 容错性)随版本变化,复用其 `toGitUri` 时须确认跨 `engines.vscode` 下限到当前主线的兼容矩阵;空树 ref 是少数有契约保障的「稳定回空」途径。③ webview 的 `data-*` 属性应承载**数据**(机器可用的稳定 key/路径),展示串(含 `"old → new"` 这类人为拼接)只放在可见标签文本里——二者混用会导致 `joinPath` 之类以数据为输入的下游崩溃。④ 逐文件级语义(status)须端到端透传到决策点(host 命令),勿用提交级布尔(`hasParent`)模糊替代——后者无法区分单文件是 A/D/M/R。⑤ 测试断言「差异已打开」时勿按标签计数(VS Code `{preview:true}` 会复用预览槽替换而非新增),应先 `closeAllEditors` 再按差异标题(含文件名)匹配标签。
- **同类问题影响**:所有消费 vscode.git `toGitUri` 自建差异打开逻辑的扩展,凡为缺失端取具名 ref 的均在新版 VS Code 复现;凡 webview `data-path` 复用展示串(含分隔符)的实现均会在路径拼接处崩溃;以及任何「逐文件操作」误用「提交级 / 全局级」标志判定单文件形态的设计。

## #16 面板视图默认布局调整(Stash/Shelf 默认隐藏 · Commit/Worktrees 默认折叠 · 顺序重排)

- **表因**:用户(附 VS Code「视图显隐」右键菜单截图)要求——Stash / Shelf **默认不显示**、仅在用户勾选后出现;其余视图显示顺序为 **Commit → Branches → Graph → Worktrees**;且 Commit 与 Worktrees **默认折叠**。
- **根因**:非缺陷,系默认布局的 UX 决策落地。视图的显隐 / 顺序 / 初始尺寸**纯由 `package.json` `contributes.views` 声明式驱动**(`src/` 无任何代码断言或依赖,两处 `.focus` 在折叠/可见态均正常),可零代码达成。此前 #12 缓解取值(Stash/Shelf `collapsed`、Worktrees/Commit/Graph/Branches `visible`)与本诉求不符,需重排数组并改写 `visibility`。
- **处理方式**:重排 `contributes.views["hyper-git"]` 数组为 `commit → branches → log → worktrees → stash → shelf → changesBadge`(容器内顺序取声明顺序);`visibility` 改写为 Commit/Worktrees=`collapsed`、Branches/Graph=`visible`、**Stash/Shelf=`hidden`**(VS Code `src/vs/workbench/api/browser/viewsExtensionPoint.ts` 的 `viewDescriptor` schema 确认 `visibility` 枚举为 `['visible','hidden','collapsed']`,`hidden` 映射 `hideByDefault:true`——不入容器但「可经视图菜单发现/勾选」,正对附图未勾选态);`initialSize` 权重与 `changesBadge`(`when:false`,恒末位)不变。命令 / 协议 / 菜单 / `viewsWelcome` 均按 id 匹配、与顺序无关,零破坏。新增 [`tests/unit/views-layout.test.ts`](../../tests/unit/views-layout.test.ts) 声明式护栏锁定顺序 + 各视图 `visibility` + `changesBadge` 的 `when:false`。
- **后续防范**:① `visibility` / 顺序 / `initialSize` **仅影响全新安装 / 干净 profile 的初始态**(复用 #12 结论,不重述)——老用户须「View: Reset View Locations」或右键容器「Reset Location」方生效,实机验证须用干净 profile。② `visibility:"hidden"` ≠ `when:"false"`:前者「默认隐藏但用户可经视图菜单勾选恢复」(Stash/Shelf),后者「恒不渲染」(changesBadge 角标承载专用)——诉求「默认不显示但用户可自行开启」**必须**用 `hidden`,误用 `when:false` 会致用户无法启用。③ 容器**内**视图相对顺序可控(声明顺序驱动),但容器相对内置页签的顺序不可控(见 #13),勿承诺后者。④ 三态语义以 VS Code schema 为权威,勿据「本仓此前只用过 `visible`/`collapsed`」臆断 `hidden` 不存在。
- **同类问题影响**:所有以 `contributes.views` 声明默认布局的 VS Code 扩展;凡将「默认隐藏但可恢复」误用 `when:false`(致用户无法启用)或反向混淆的实现;以及把「仅初始态生效」误当「持久强制」而困惑于老用户升级后不生效的排障。


4 changes: 2 additions & 2 deletions docs/i18n/zh-CN/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<a href="../../../README.md">English</a> · <b>简体中文</b>
</p>

<p align="center"><sub>6 视图 · 101 命令 · 11 配置项 · 372 单元测试</sub></p>
<p align="center"><sub>6 视图 · 101 命令 · 11 配置项 · 375 单元测试</sub></p>

## 核心能力

Expand Down Expand Up @@ -78,7 +78,7 @@
pnpm install # 安装依赖
pnpm run compile # 类型检查 + lint + 构建
pnpm run watch # 监听构建(F5 启动 Extension Host 调试)
pnpm run test:unit # 单元测试(engine 纯逻辑,Vitest,324 例)
pnpm run test:unit # 单元测试(engine 纯逻辑,Vitest,375 例)
pnpm run test:integration # 集成测试(@vscode/test-electron)
pnpm run package # 生产构建
pnpm dlx @vscode/vsce package # 打包 .vsix
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,15 @@
"id": "hyperGit.commit",
"name": "Commit",
"type": "webview",
"visibility": "visible",
"visibility": "collapsed",
"initialSize": 3
},
{
"id": "hyperGit.branches",
"name": "Branches",
"visibility": "visible",
"initialSize": 2
},
{
"id": "hyperGit.log",
"name": "Graph",
Expand All @@ -73,27 +79,21 @@
"initialSize": 3
},
{
"id": "hyperGit.branches",
"name": "Branches",
"visibility": "visible",
"initialSize": 2
"id": "hyperGit.worktrees",
"name": "Worktrees",
"visibility": "collapsed",
"initialSize": 1
},
{
"id": "hyperGit.stash",
"name": "Stash",
"visibility": "collapsed",
"visibility": "hidden",
"initialSize": 1
},
{
"id": "hyperGit.shelf",
"name": "Shelf",
"visibility": "collapsed",
"initialSize": 1
},
{
"id": "hyperGit.worktrees",
"name": "Worktrees",
"visibility": "visible",
"visibility": "hidden",
"initialSize": 1
},
{
Expand Down
52 changes: 52 additions & 0 deletions tests/unit/views-layout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, it, expect } from 'vitest';
import pkg from '../../package.json';

/**
* 面板视图默认布局护栏:`contributes.views["hyper-git"]` 的声明顺序与各视图
* `visibility` 纯由 package.json 驱动(`src/` 无代码断言/依赖),一旦被误改,
* 用户可见的默认排序与显隐即随之漂移。此处锁定「设计基线」,呼应本仓
* `--topo-order` 回归护栏文化。语义见 docs/.agents/issue.md #16(决策)/ #12(平台约束)。
*/

/** VS Code view descriptor 的最小子集(仅取本护栏关心的字段)。 */
interface ViewDescriptor {
id: string;
visibility?: string;
when?: string;
}

const views = pkg.contributes.views['hyper-git'] as unknown as ViewDescriptor[];
/** 用户可见视图 = 排除 `when:false` 的角标承载视图(changesBadge,永不渲染)。 */
const userViews = views.filter((v) => v.when !== 'false');

describe('Hyper Git 面板视图默认布局(package.json 声明式护栏)', () => {
it('用户可见视图声明顺序固定为 Commit·Branches·Graph·Worktrees·Stash·Shelf', () => {
expect(userViews.map((v) => v.id)).toEqual([
'hyperGit.commit',
'hyperGit.branches',
'hyperGit.log',
'hyperGit.worktrees',
'hyperGit.stash',
'hyperGit.shelf',
]);
});

it('各视图默认 visibility 符合设计(Commit/Worktrees 折叠、Branches/Graph 展开、Stash/Shelf 隐藏)', () => {
const visibilityById = Object.fromEntries(userViews.map((v) => [v.id, v.visibility]));
expect(visibilityById).toEqual({
'hyperGit.commit': 'collapsed',
'hyperGit.branches': 'visible',
'hyperGit.log': 'visible',
'hyperGit.worktrees': 'collapsed',
'hyperGit.stash': 'hidden',
'hyperGit.shelf': 'hidden',
});
});

it('changesBadge 为 when:false 的隐藏角标承载视图,且恒定末位', () => {
const badge = views.find((v) => v.id === 'hyperGit.changesBadge');
expect(badge?.when).toBe('false');
expect(badge?.visibility).toBeUndefined();
expect(views[views.length - 1].id).toBe('hyperGit.changesBadge');
});
});