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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
- run: pnpm install --frozen-lockfile
- run: pnpm compat:check
- run: pnpm test
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm test:e2e
- run: pnpm docs:check
- run: pnpm build
- run: pnpm test:artifact
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ node_modules/
.pnpm-store/
.zcode/
.cursor/
.tmp/
.tmp/
test-results/
playwright-report/
12 changes: 11 additions & 1 deletion .pnpmfile.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const { join } = require('node:path')
const { developmentPin, pinDshDependencies } = require('./scripts/dsh-release-wave.cjs')

const root = __dirname
const compatibilitySource = readFileSync(join(root, 'src/compat/dsh-version.ts'), 'utf8')
const releases = name => [...compatibilitySource.match(new RegExp('export const ' + name + ' = \\[([^\\]]*)\\]'))[1].matchAll(/'([^']+)'/g)].map(item => item[1])
const supportedReleases = releases('SUPPORTED_DSH_RELEASES')
const credentialReleases = releases('CREDENTIALS_SEAM_DSH_RELEASES')
const rootManifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))

function targetVersion() {
Expand All @@ -29,7 +33,13 @@ function isRootPackage(pkg, context) {
}

function readPackage(pkg, context) {
return pinDshDependencies(pkg, targetVersion(), {
const version = targetVersion()
if (isRootPackage(pkg, context) && supportedReleases.includes(version) && !credentialReleases.includes(version)) {
// pnpm installs a root peer as a direct edge even when optional. Omit only
// this development-lane edge; the published manifest remains unchanged.
if (pkg.peerDependencies) delete pkg.peerDependencies['@deepseek-ai/dsh-credentials']
}
return pinDshDependencies(pkg, version, {
skipPeerDependencies: isRootPackage(pkg, context),
})
}
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The Host core depends only on standard DSH services and launches `git` through `

The Client main fiber contains every portable contribution. Native enhancement belongs in a child `ctx.inject(['desktop'], ...)` fiber and declares only the structural methods it consumes. Provider unload must remove the enhancement without removing the core UI.

Use machine-readable Git output and temporary repositories in tests. Keep GitHub and remote credential workflows outside this package until a separate decision adds them.
Use machine-readable Git output and temporary repositories in tests. GitHub and remote credential workflows are admitted by [ADR-0004](docs/decisions/ADR-0004-remote-platform-integration.md) (status Proposed) and land stage by stage per `docs/plans/active/remote-platform-integration.md`; anything not yet landed stays fail-closed behind `git/remote-unavailable`, and all portability constraints above still apply.

# 文档系统总纲

Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# git hash-object CHANGELOG.md CHANGELOG.zh.md
CHANGELOG.md: 4dfd36eb3efab306ccc4bd293c12cf50bf6d944f
CHANGELOG.zh.md: f838b855a265f924b5c76f294565339975d635c1
CHANGELOG.md: 3adb8ff5532e152ef5c541fdce70108ec58c8958
CHANGELOG.zh.md: 0be125c1508cd68d896508a633f9b65af8ae1025
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ English | [中文](CHANGELOG.zh.md)

All notable changes to this package are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) — the package is pre-1.0, so a minor release may still change the API. Each published version also has a [GitHub Release](https://github.com/cherrchen/dsh-plugin-git/releases) carrying its tarball.

## [Unreleased]

### Changed

- GitHub Remote PR/Issue lists, detail comments, and comparison files no longer stop at a fixed pagination budget. `RemotePage` carries an opaque `next` cursor (the origin-checked `Link rel="next"`), and `remote-list-prs`, `remote-list-issues`, `remote-comments`, and `remote-files` accept `cursor`/`pages` request fields. The Client controller appends items in a serial background stream — a multi-page first request, then one page per continuation — deduplicating by number/comment id/file path, honoring generation checks, and recovering once at `resetAt` after a rate limit. The truncated banner is removed in favor of a streaming hint.
- `remote-files` continuations pin the comparison snapshot: `expectedBaseSha`/`expectedHeadSha` are verified on every continuation page, so inline-comment coordinates never drift between pages. Inline comment submission stays disabled until all files are loaded, and the bounded collections used for notification expansion and write-path coordinate validation are unchanged.
- The PR detail page no longer renders local file diffs. New `remote-commits`/`remote-reviews` endpoints project `RemoteCommit`/`RemoteReview` (review `state` normalized to approved/changes-requested/commented/dismissed/pending) and stream through the same cursor mechanism, while file changes open the GitHub Files page via a `pr.url + '/files'` link. Inline comments are read-only and nested under their owning review through `reviewId`; the inline-comment composer button is removed since there is no anchor picker. `remote-files` and `remote-inline-comment` remain guarded RPC capabilities. The detail surface also stops retrying a failed load/open in a tight loop — each attempt is keyed once per target and revision.

- The PR/Issue detail tab is now a GitHub-style chronological timeline. `RemoteIssue`/`RemoteComment` carry `createdAt` and `RemoteCommit` carries `committedAt`, and a new `RemoteTimeline` interleaves comments, commits, reviews and inline threads by time — empty per-reply reviews are hidden and orphan threads stand alone. The opening post renders as the first card in the same gutter alignment, and the detail tab moved to 20px horizontal padding.
- GitHub bodies render readably instead of leaking raw markup: a pure `github-markdown` transform projects the HTML subset GitHub allows (details/summary, comments, images, links, emphasis, code, pre, lists, tables, blockquote alerts) into Markdown before `MarkdownText`, and `RemoteMarkdown` renders `<details>` folds as native disclosures without ever touching `innerHTML`.
- The platform-authentication dialog was redesigned around a status card plus "Ways to connect" method rows (GitHub account, credentials already on this computer, Git credential helper), each explaining what it does and tagging the method in use. `authAction` accepts an endpoint sequence executed in order inside one busy run; Local/Git credential reconnects prepend `remote-clear-grant` whenever a stored grant or signed-out/invalid marker would override the choice, so Disconnect (persisted signed-out) vs clearing the local grant is expressed through the flow instead of five opaque buttons.

- Follow-up polish on the same surfaces: timeline and auth-dialog markers now render real GitHub avatars — `author.avatarUrl`/viewer `avatarUrl` are projected only from `https://avatars.githubusercontent.com` via a dedicated `avatarUrl()` gate — with an opaque initial-letter fallback that keeps the timeline gutter hidden behind them. The authentication dialog widened to 440px and simplified into a status card plus a GitHub CLI / GitHub OAuth radio group whose checked state derives purely from capability; the git-credential endpoint remains available behind `remote-use-git-credential`.

## [0.2.7] — 2026-10-17

### Changed
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@

本文件记录本 package 的所有重要变更。格式参照 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),版本遵循 [Semantic Versioning](https://semver.org/spec/v2.0.0.html) —— 本包处于 pre-1.0,minor 版本之间仍可能改变 API。每个已发布版本同时有对应的 [GitHub Release](https://github.com/cherrchen/dsh-plugin-git/releases),附该版本的 tarball。

## [Unreleased]

### Changed

- GitHub Remote 的 PR/Issue 列表、详情评论与比较文件不再受固定分页预算截断。`RemotePage` 携带不透明 `next` 续页游标(经 origin 校验的 `Link rel="next"`),`remote-list-prs`、`remote-list-issues`、`remote-comments`、`remote-files` 接受 `cursor`/`pages` 请求字段。Client controller 以串行后台流追加条目——首请求多页、之后每次续取一页——按 number/评论 id/文件路径去重,逐页校验 generation,并在限流后按 `resetAt` 有界恢复一次。truncated 警示条移除,改为流式提示。
- `remote-files` 续页钉住比较快照:每次续取校验 `expectedBaseSha`/`expectedHeadSha`,行内评论坐标不会跨页漂移。行内评论提交在文件全部加载完成前保持禁用;通知线程展开与写路径坐标校验的有界收集保持不变。
- PR 详情页不再渲染本地文件 diff。新增 `remote-commits`/`remote-reviews` 端点,投影 `RemoteCommit`/`RemoteReview` 模型(review `state` 归一为 approved/changes-requested/commented/dismissed/pending)并沿用同一游标流式加载;文件改动经 `pr.url + '/files'` 链接跳转 GitHub Files 页查看。行内评论只读、按 `reviewId` 嵌套在对应 review 下展示;因无锚点选择器,行内评论提交按钮移除。`remote-files` 与 `remote-inline-comment` 保留为受守护 RPC 能力。详情页同时修复了 load/open 失败后紧密循环重试的问题——每个目标与 revision 只尝试一次。

- PR/Issue 详情页改为 GitHub 风格的时间线。`RemoteIssue`/`RemoteComment` 携带 `createdAt`,`RemoteCommit` 携带 `committedAt`;新增 `RemoteTimeline` 按时间交错排列评论、提交、review 与行内 thread——空的 per-reply review 隐藏、孤儿 thread 独立成项。正文作为开场卡与后续项同槽对齐,详情页改用 20px 横向内边距。
- GitHub 正文不再泄漏原始标签:纯模块 `github-markdown` 先把 GitHub 允许的 HTML 子集(details/summary、注释、图片、链接、强调、code、pre、列表、表格、alert 引用)投影为 Markdown 再交给 `MarkdownText`,`RemoteMarkdown` 用原生 `<details>` 渲染折叠块,全程不接触 `innerHTML`。
- 平台认证弹窗重做为状态卡 + “连接方式”方法行(GitHub 账号登录、本机已有的凭据、Git 凭据助手),每种方式附说明并对当前生效的方法标“当前使用”。`authAction` 接受端点序列、在同一 busy 周期内按序执行、首个失败即停;当已有 grant 或 signed-out/invalid marker 会覆盖所选方式时,Local/Git credential 重连自动前置 `remote-clear-grant`,用流程表达“断开连接(持久 signed-out)”与“清除本地授权”的区别,取代原先五个含义不清的按钮。

- 同一批界面的后续打磨:时间线与认证弹窗标记改为真实 GitHub 头像——`author.avatarUrl` 与 viewer `avatarUrl` 仅经专用 `avatarUrl()` 准入 `https://avatars.githubusercontent.com`——失败或缺失时回退为首字母圆点,并保持不透明以遮住时间线竖线。认证弹窗加宽至 440px,并简化为状态卡加 GitHub CLI / GitHub OAuth 单选组,选中态只由 capability 派生;Git 凭据端点仍保留在 `remote-use-git-credential` 之后。

## [0.2.7] — 2026-10-17

### Changed
Expand Down
4 changes: 2 additions & 2 deletions README.i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# git hash-object README.md README.zh.md
README.md: cbf236227463aef4ae92fb9e9a1194ddff67bb2f
README.zh.md: 342e9f3a5809c87a25339c4290b13a58b9504c2e
README.md: 47c4b50a549578ade8a81d0d225835002587fb14
README.zh.md: 3cfa9d1db8f2283fc3e3c58f0ab6e3151bc382e0
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Git joins the tab-type system through the upstream right sidebar's standard two-

Dynamic client plugins may not import runtime values from another plugin package — only `import type` — so the type references erase completely from the bundle and no `external` entry is needed.

**Stage one** — `ctx.sidebarRightTabs.register(definition)` registers three tab types: `git.changes` and `git.graph` are page types (opened by kind, one tab per pane) that each contribute one guide entry (Changes `order: 10`, Graph `order: 11`), replacing the old Details launcher cards on the guide page; `git.diff` is a resource type with pattern `dsh-resource://git/diff/**`, a `canOpen` that validates the address decodes, and a title taken from the decoded file name.
**Stage one** — `ctx.sidebarRightTabs.register(definition)` registers three tab types: `git.changes` and `git.graph` are page types (opened by kind, one tab per pane) that each contribute one guide entry (Changes `order: 11`, Graph `order: 12`), replacing the old Details launcher cards on the guide page; `git.diff` is a resource type with pattern `dsh-resource://git/diff/**`, a `canOpen` that validates the address decodes, and a title taken from the decoded file name. Optional Worktrees and Remote entries use orders 13 and 14, keeping all Git entries between Workspace files (10) and New terminal (20). Graph uses commit-lane artwork; Remote uses a cloud with upload/download arrows.

**Stage two** — each type's body component injects the `sidebar.right.pane.tab` seat under the definition's `id`; bodies read `{ address, params, revision }` from `useTabInfo().tab.navigation`.

Expand Down Expand Up @@ -210,7 +210,7 @@ Commit history is read with a paged `git log` (`GIT_LOG_FORMAT`, one commit per

Commit message generation is opt-in at the host: it needs an LLM runtime and a resolvable model (the session default, or a custom `provider`/`model`). A staged diff (capped by `commitMessage.maxDiffBytes`) is sent to that route and the streamed suggestion is written into the editable commit message input. The system prompt defaults to a Conventional Commit instruction and can be overridden from Plugin configuration. Generation is suggestion-only — it never stages, commits, or pushes anything.

GitHub authentication, hosting-provider workflows, credential prompts, issues, pull requests, stash, cherry-pick, and merge-conflict editing remain outside this package. Push and sync invoke `git push` / `git pull --rebase` as separate argv values and surface Git's own errors when remotes or credentials are missing.
GitHub Remote is available when the host provides the complete optional credentials seam: authentication, PR/Issue browsing, comparisons, PR comments/reviews, verified checkout, Issue branches, and guarded create/close/merge. See the [remote RPC contract](docs/reference/remote-platform-rpc.en.md) for configuration, limits, credential handling and unknown-result recovery, and the [active plan](docs/plans/active/remote-platform-integration.en.md) for acceptance evidence and unverified external scenarios. Git fetch/push uses existing Git transport credentials, independently of platform login. Stash, cherry-pick and merge-conflict editing remain outside this package.

<a id="npm-publication"></a>
## npm publication
Expand Down Expand Up @@ -240,7 +240,7 @@ None. Commit-message generation is an independent Host LLM request and does not

## Known Limitations and Deferred Work

- **No credential UI** — push and sync call Git with no prompt for remotes or credentials; a missing `origin` or rejected auth fails as a Git command error.
- **Independent Git transport** — Remote platform login does not configure Git fetch/push credentials; existing helpers or SSH remain responsible for Git authentication.
- **Bounded command output** — a diff larger than `maxOutputBytes` retains only the subprocess collector's tail, so deployments handling very large diffs must raise that validated setting.
- **Generation needs host + model** — commit message generation requires a host LLM runtime and a resolvable model (session default or a custom route in Plugin configuration); without either, the Generate action stays disabled or reports `git/generation-unavailable`.
- **Worktree entry needs a live directory service** — without the host working-directory service, or without a live agent for that session, the checkout list stays read-only. Writes then keep the previous caller-supplied repository contract. A missing directory is not repaired here; recovery belongs to the host working-directory service.
Expand Down
Loading
Loading