@deepseek-ai/dsh-experimental-client-ui-forge 0.2.2-alpha.2 → 0.2.2-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +12 -12
- package/README.md +19 -11
- package/README.zh.md +20 -12
- package/lib/client.js +7869 -4812
- package/lib/index.js +159 -52
- package/lib/typert.host.js +298 -18
- package/lib/typert.remote-client.d.ts +7 -1
- package/lib/typert.remote-client.js +267 -13
- package/lib/types/client/ChangeRequestCard.d.ts +3 -1
- package/lib/types/client/ChangedFiles.d.ts +36 -0
- package/lib/types/client/ChangesTab.d.ts +11 -1
- package/lib/types/client/DiffFile.d.ts +3 -2
- package/lib/types/client/FileTreePane.d.ts +15 -0
- package/lib/types/client/ForgeTab.d.ts +7 -4
- package/lib/types/client/LocalChangesCard.d.ts +3 -3
- package/lib/types/client/ReviewComposer.d.ts +40 -0
- package/lib/types/client/ReviewThread.d.ts +26 -0
- package/lib/types/client/SubmitReview.d.ts +22 -0
- package/lib/types/client/WorktreeToggle.d.ts +6 -5
- package/lib/types/client/changes-address.d.ts +1 -1
- package/lib/types/client/code-selection.d.ts +23 -0
- package/lib/types/client/file-tree.d.ts +33 -0
- package/lib/types/client/locales.d.ts +58 -4
- package/lib/types/client/review-queue.d.ts +136 -0
- package/lib/types/client/review.d.ts +56 -0
- package/lib/types/client/status.d.ts +6 -2
- package/lib/types/git.d.ts +10 -10
- package/lib/types/index.d.ts +25 -4
- package/lib/types/local-diff.d.ts +11 -4
- package/lib/types/states.d.ts +9 -3
- package/lib/types/types.d.ts +4 -0
- package/package.json +47 -47
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Plain-text comment editor for a frozen selection in either review tab. */
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
+
import type { ReviewQueue } from './review-queue.ts';
|
|
5
|
+
import type { ReviewSelection, ReviewSource } from './review.ts';
|
|
6
|
+
import type { NS } from './locales.ts';
|
|
7
|
+
/** Actions supplied by the owning changes tab. */
|
|
8
|
+
export interface ReviewActions {
|
|
9
|
+
/** The source currently displayed; selecting a range freezes it. */
|
|
10
|
+
readonly source: ReviewSource;
|
|
11
|
+
/** Browser records shared by the changes tab. */
|
|
12
|
+
readonly records?: ReviewQueue;
|
|
13
|
+
/** Whether another comment already started a pending review. */
|
|
14
|
+
readonly reviewStarted?: boolean;
|
|
15
|
+
/** Open the confirmed publication URL. */
|
|
16
|
+
readonly openLink?: (url: string) => void;
|
|
17
|
+
/** A write is running or its outcome still needs confirmation. */
|
|
18
|
+
readonly publishingBlocked?: boolean;
|
|
19
|
+
/** Append an atomic quote without sending the Agent a message. */
|
|
20
|
+
readonly addToInput: (selection: ReviewSelection) => boolean;
|
|
21
|
+
/** Retain a new comment after its quote was accepted. */
|
|
22
|
+
readonly onQuoted?: (selection: ReviewSelection) => void;
|
|
23
|
+
/** Publish one comment; an error string preserves the editor. */
|
|
24
|
+
readonly publish?: (selection: ReviewSelection) => Promise<string | undefined>;
|
|
25
|
+
/** Keep one comment for the final review; false preserves the editor. */
|
|
26
|
+
readonly queue?: (selection: ReviewSelection) => boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Render the line range, plain-text editor, and explicitly named destinations.
|
|
30
|
+
* @param props - frozen selection, actions, cancellation, and localized copy.
|
|
31
|
+
* @returns the inline comment form.
|
|
32
|
+
*/
|
|
33
|
+
export declare function ReviewComposer({ selection, actions, close, visible, split, t }: PropsLocale<typeof NS> & {
|
|
34
|
+
readonly visible?: boolean;
|
|
35
|
+
readonly split?: boolean;
|
|
36
|
+
readonly selection: ReviewSelection;
|
|
37
|
+
readonly actions: ReviewActions;
|
|
38
|
+
readonly close: () => void;
|
|
39
|
+
}): ReactNode;
|
|
40
|
+
//# sourceMappingURL=ReviewComposer.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Inline comment records and editing of a pending review at its captured code location. */
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
+
import type { ReviewActions } from './ReviewComposer.tsx';
|
|
5
|
+
import { type FileReviewState, type ReviewThread as Thread } from './review-queue.ts';
|
|
6
|
+
import type { NS } from './locales.ts';
|
|
7
|
+
/**
|
|
8
|
+
* Subscribe only to comments that belong to the displayed file and source.
|
|
9
|
+
* @param actions - review actions and their browser store.
|
|
10
|
+
* @param path - displayed file path.
|
|
11
|
+
* @returns stable file-scoped comments and write availability.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useFileReview(actions: ReviewActions | undefined, path: string): FileReviewState;
|
|
14
|
+
/**
|
|
15
|
+
* Render a saved comment at its line, with pending edits kept in the browser queue.
|
|
16
|
+
* @param props - record, edit availability, source actions, and localized copy.
|
|
17
|
+
* @returns one compact inline comment card.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ReviewThread({ thread, actions, locked, outdated, split, t }: PropsLocale<typeof NS> & {
|
|
20
|
+
readonly thread: Thread;
|
|
21
|
+
readonly actions: ReviewActions;
|
|
22
|
+
readonly locked: boolean;
|
|
23
|
+
readonly outdated: boolean;
|
|
24
|
+
readonly split: boolean;
|
|
25
|
+
}): ReactNode;
|
|
26
|
+
//# sourceMappingURL=ReviewThread.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Centered review submission with a summary, decision, and pending-comment count. */
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
+
import type { ReviewQueue } from './review-queue.ts';
|
|
5
|
+
import type { NS } from './locales.ts';
|
|
6
|
+
/**
|
|
7
|
+
* Submit a review independently of the diff scroll position; comments remain at their code locations.
|
|
8
|
+
* @param props - durable queue, current head, submission outcome, and modal actions.
|
|
9
|
+
* @returns a portalled modal with keyboard focus ownership.
|
|
10
|
+
*/
|
|
11
|
+
export declare function SubmitReview({ queue, url, headSha, busy, error, submit, close, check, reconcile, t }: PropsLocale<typeof NS> & {
|
|
12
|
+
readonly queue: ReviewQueue;
|
|
13
|
+
readonly url: string;
|
|
14
|
+
readonly headSha: string;
|
|
15
|
+
readonly busy: boolean;
|
|
16
|
+
readonly error: string | null;
|
|
17
|
+
readonly submit: () => void;
|
|
18
|
+
readonly close: () => void;
|
|
19
|
+
readonly check: () => void;
|
|
20
|
+
readonly reconcile: () => void;
|
|
21
|
+
}): ReactNode;
|
|
22
|
+
//# sourceMappingURL=SubmitReview.d.ts.map
|
|
@@ -31,12 +31,13 @@ export interface WorktreeToggleInjected {
|
|
|
31
31
|
export type WorktreeToggleProps = InjectFace<WorktreeToggleInjected> & PropsLocale<typeof NS>;
|
|
32
32
|
/**
|
|
33
33
|
* Render the worktree option while the Session can still start in a worktree:
|
|
34
|
-
* the base branch menu once requested, then the checkbox.
|
|
35
|
-
*
|
|
36
|
-
* withdraws
|
|
37
|
-
* created.
|
|
34
|
+
* the current branch, or the base branch menu once requested, then the checkbox.
|
|
35
|
+
* A blocked request keeps its selected base visible without a menu; the checkbox
|
|
36
|
+
* only withdraws it. Branch details support pointer, touch, and keyboard access.
|
|
37
|
+
* The request stays fixed while the worktree is being created.
|
|
38
38
|
* @param props - panel snapshot hook, request actions, and copy.
|
|
39
|
-
* @returns the option, or nothing
|
|
39
|
+
* @returns the option, or nothing outside a known Git checkout, once a turn started,
|
|
40
|
+
* the request settled, or no worktree service is mounted.
|
|
40
41
|
*/
|
|
41
42
|
export declare function WorktreeToggle({ usePanel, request, cancel, branches, t }: WorktreeToggleProps): ReactNode;
|
|
42
43
|
//# sourceMappingURL=WorktreeToggle.d.ts.map
|
|
@@ -55,7 +55,7 @@ export declare function changesAddress(target: ChangesTarget): string;
|
|
|
55
55
|
*/
|
|
56
56
|
export declare function parseChangesAddress(address: string): ChangesTarget | undefined;
|
|
57
57
|
/**
|
|
58
|
-
* Name a changes view:
|
|
58
|
+
* Name a changes view: 本地变更 for the local changes, #N 的变更 for a change request with a number.
|
|
59
59
|
* @param source - what the view shows.
|
|
60
60
|
* @param t - forge panel copy.
|
|
61
61
|
* @returns the title in the current language.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Read browser text selections from one diff side without including the interleaved opposite column. */
|
|
2
|
+
/** Selected displayed lines and the exact selected text on their side. */
|
|
3
|
+
export interface CodeSelection {
|
|
4
|
+
readonly side: 'L' | 'R';
|
|
5
|
+
readonly from: number;
|
|
6
|
+
readonly to: number;
|
|
7
|
+
readonly text: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Find the side where a text selection begins; unified context belongs to the new side.
|
|
11
|
+
* @param root - this file's diff element.
|
|
12
|
+
* @param node - pointer or selection anchor.
|
|
13
|
+
* @returns the available side, or undefined outside code text.
|
|
14
|
+
*/
|
|
15
|
+
export declare function codeSideAt(root: HTMLElement, node: Node | null): 'L' | 'R' | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Read only code fragments from the selected side, retaining partial first and last lines for copy.
|
|
18
|
+
* @param root - this file's diff element.
|
|
19
|
+
* @param side - side captured when the gesture began.
|
|
20
|
+
* @returns the selected range and text, or undefined for collapsed or cross-file selections.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readCodeSelection(root: HTMLElement, side: 'L' | 'R'): CodeSelection | undefined;
|
|
23
|
+
//# sourceMappingURL=code-selection.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ForgeDiffFile } from '../types.ts';
|
|
2
|
+
/** A changed file or a compacted chain of directories containing changed files. */
|
|
3
|
+
export type ChangedFileNode = {
|
|
4
|
+
readonly kind: 'file';
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly file: ForgeDiffFile;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'directory';
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly children: readonly ChangedFileNode[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Build a directory-first tree, compacting directories with a single directory child.
|
|
16
|
+
* @param files - changed files; Git paths use forward slashes, including on Windows.
|
|
17
|
+
* @returns the root's children in stable name order.
|
|
18
|
+
*/
|
|
19
|
+
export declare function changedFileTree(files: readonly ForgeDiffFile[]): readonly ChangedFileNode[];
|
|
20
|
+
/**
|
|
21
|
+
* Read every file in the tree's depth-first display order, independent of navigation folds and filtering.
|
|
22
|
+
* @param nodes - the complete directory-first tree.
|
|
23
|
+
* @returns the original file objects in display order.
|
|
24
|
+
*/
|
|
25
|
+
export declare function filesInTreeOrder(nodes: readonly ChangedFileNode[]): readonly ForgeDiffFile[];
|
|
26
|
+
/**
|
|
27
|
+
* Keep matching files and their ancestors without changing directory identities.
|
|
28
|
+
* @param nodes - the complete compacted tree.
|
|
29
|
+
* @param query - case-insensitive text matched against current and previous paths.
|
|
30
|
+
* @returns matching branches, or the original tree for an empty query.
|
|
31
|
+
*/
|
|
32
|
+
export declare function filterFileTree(nodes: readonly ChangedFileNode[], query: string): readonly ChangedFileNode[];
|
|
33
|
+
//# sourceMappingURL=file-tree.d.ts.map
|
|
@@ -3,6 +3,51 @@
|
|
|
3
3
|
export declare const NS = "forgePanel";
|
|
4
4
|
/** Chinese copy; its keys define {@link ForgePanelKey}. */
|
|
5
5
|
export declare const zh: {
|
|
6
|
+
readonly 'review.startReview': "开始评审";
|
|
7
|
+
readonly 'review.githubActions': "GitHub 评论选项";
|
|
8
|
+
readonly 'review.publishing': "发布中…";
|
|
9
|
+
readonly 'review.submitting': "提交中…";
|
|
10
|
+
readonly 'review.close': "关闭";
|
|
11
|
+
readonly 'review.pending': "待提交";
|
|
12
|
+
readonly 'review.quoted': "已添加到输入框";
|
|
13
|
+
readonly 'review.yourComment': "你的评论";
|
|
14
|
+
readonly 'review.outdated': "代码已更新";
|
|
15
|
+
readonly 'review.done': "完成";
|
|
16
|
+
readonly 'review.addComment': "添加评论";
|
|
17
|
+
readonly 'diff.resizeFileTree': "调整文件树宽度";
|
|
18
|
+
readonly 'diff.fileTree': "文件树";
|
|
19
|
+
readonly 'diff.showFileTreeLeft': "在左侧显示文件树";
|
|
20
|
+
readonly 'diff.moveFileTreeRight': "将文件树移到右侧";
|
|
21
|
+
readonly 'guide.title': "代码审查和变更";
|
|
22
|
+
readonly 'guide.description': "查看代码变更与本会话的变更请求";
|
|
23
|
+
readonly 'diff.hideFileTree': "隐藏文件树";
|
|
24
|
+
readonly 'review.range': "评论 {range}";
|
|
25
|
+
readonly 'review.comment': "留下评论…";
|
|
26
|
+
readonly 'review.cancel': "取消";
|
|
27
|
+
readonly 'review.addToInput': "添加到输入框";
|
|
28
|
+
readonly 'review.publish': "发布单条评论";
|
|
29
|
+
readonly 'review.queue': "加入评审";
|
|
30
|
+
readonly 'review.selectLine': "选择第 {line} 行";
|
|
31
|
+
readonly 'review.inputFailed': "输入框暂时无法添加引用,请稍后重试";
|
|
32
|
+
readonly 'review.saveFailed': "无法保存评审草稿,请检查浏览器存储后重试";
|
|
33
|
+
readonly 'review.unknown': "无法确认提交结果。请先在 GitHub 核对,避免重复发布";
|
|
34
|
+
readonly 'review.submit': "提交评审";
|
|
35
|
+
readonly 'review.summary': "评审总结…";
|
|
36
|
+
readonly 'review.approve': "批准";
|
|
37
|
+
readonly 'review.requestChanges': "请求更改";
|
|
38
|
+
readonly 'review.summaryRequired': "请求更改时,请填写评审总结";
|
|
39
|
+
readonly 'review.commentOnly': "评论";
|
|
40
|
+
readonly 'review.drafts': "待提交评论({count})";
|
|
41
|
+
readonly 'review.edit': "编辑";
|
|
42
|
+
readonly 'review.remove': "删除";
|
|
43
|
+
readonly 'review.stale': "PR 已有新提交,请刷新并重新选择评论行";
|
|
44
|
+
readonly 'review.published': "已发布到 GitHub";
|
|
45
|
+
readonly 'review.submitted': "已提交评审";
|
|
46
|
+
readonly 'review.failed': "提交失败:{message}";
|
|
47
|
+
readonly 'review.unsupported': "此代码托管服务不支持提交评审";
|
|
48
|
+
readonly 'review.loadFailed': "无法读取评审草稿,请检查浏览器存储";
|
|
49
|
+
readonly 'review.recheck': "在 GitHub 查看";
|
|
50
|
+
readonly 'review.confirmRetry': "已核对,允许重新提交";
|
|
6
51
|
readonly 'tab.title': "变更请求";
|
|
7
52
|
readonly 'header.label': "本会话的变更请求";
|
|
8
53
|
readonly 'header.attention': "本会话的变更请求需要处理";
|
|
@@ -18,7 +63,7 @@ export declare const zh: {
|
|
|
18
63
|
readonly 'changes.title': "本会话的变更请求 · {count}";
|
|
19
64
|
readonly 'changes.empty': "本会话还没有变更请求";
|
|
20
65
|
readonly 'changes.emptyHint': "本会话关联的变更请求(创建、查看、编辑或检出的,以及所在分支或推送分支上的)会显示在这里";
|
|
21
|
-
readonly 'changes.local.title': "
|
|
66
|
+
readonly 'changes.local.title': "本地变更";
|
|
22
67
|
readonly 'changes.local.refs': "{head} → {base}";
|
|
23
68
|
readonly 'changes.local.files': "{count} 个文件";
|
|
24
69
|
readonly 'changes.local.viewAria': "查看本会话的变更:{count} 个文件,新增 {added} 行,删除 {deleted} 行";
|
|
@@ -47,12 +92,17 @@ export declare const zh: {
|
|
|
47
92
|
readonly 'change.ci.running': "检查中";
|
|
48
93
|
readonly 'change.ci.passed': "检查通过";
|
|
49
94
|
readonly 'change.ci.failed': "{count} 项检查失败";
|
|
95
|
+
readonly 'change.ci.cancelled': "已取消 {count} 项检查";
|
|
50
96
|
readonly 'change.ci.failedUnlisted': "检查失败";
|
|
51
97
|
readonly 'change.checks.failed': "{count} 项失败";
|
|
52
98
|
readonly 'change.checks.running': "{count} 项进行中";
|
|
53
99
|
readonly 'change.checks.passed': "{count} 项通过";
|
|
100
|
+
readonly 'change.checks.cancelled': "{count} 项已取消";
|
|
54
101
|
readonly 'change.checks.other': "其他 {count} 项";
|
|
55
|
-
readonly 'change.checks.truncated': "
|
|
102
|
+
readonly 'change.checks.truncated': "已加载 {count} 项检查,仍有更多";
|
|
103
|
+
readonly 'change.checks.loading': "正在加载更多检查";
|
|
104
|
+
readonly 'change.checks.loadFailed': "更多检查加载失败:{message}";
|
|
105
|
+
readonly 'change.checks.retry': "重试加载检查";
|
|
56
106
|
readonly 'change.check.running': "进行中";
|
|
57
107
|
readonly 'change.check.queued': "排队中";
|
|
58
108
|
readonly 'change.flag.changesRequested': "要求修改";
|
|
@@ -102,6 +152,8 @@ export declare const zh: {
|
|
|
102
152
|
readonly 'diff.scopeNote.unstaged': "与暂存区比较,包含未跟踪的文件";
|
|
103
153
|
readonly 'diff.scopeNote.staged': "暂存区与 HEAD 比较";
|
|
104
154
|
readonly 'diff.allFiles': "全部 {count} 个文件";
|
|
155
|
+
readonly 'diff.filterFiles': "筛选文件…";
|
|
156
|
+
readonly 'diff.noMatchingFiles': "没有匹配的文件";
|
|
105
157
|
readonly 'diff.refresh': "刷新变更";
|
|
106
158
|
readonly 'diff.expandAll': "全部展开";
|
|
107
159
|
readonly 'diff.collapseAll': "全部折叠";
|
|
@@ -124,6 +176,7 @@ export declare const zh: {
|
|
|
124
176
|
readonly 'diff.fileTooLarge': "文件太大,无法显示变更";
|
|
125
177
|
readonly 'diff.error': "无法读取变更";
|
|
126
178
|
readonly 'diff.tooLarge': "变更太大,无法在这里显示";
|
|
179
|
+
readonly 'diff.filterConfigFailed': "无法完整读取 Git 过滤器配置,尚未执行比较。请检查 Git 配置和读取上限后重试";
|
|
127
180
|
readonly 'diff.viewInBrowser': "在浏览器中查看";
|
|
128
181
|
readonly 'diff.noForkPoint': "找不到本分支的分叉点,请选择其他范围";
|
|
129
182
|
readonly 'diff.empty': "没有变更";
|
|
@@ -143,15 +196,16 @@ export declare const zh: {
|
|
|
143
196
|
readonly 'duration.seconds': "{seconds} 秒";
|
|
144
197
|
readonly 'duration.minutes': "{minutes} 分 {seconds} 秒";
|
|
145
198
|
readonly 'duration.hours': "{hours} 小时 {minutes} 分";
|
|
146
|
-
readonly 'worktree.label': "
|
|
199
|
+
readonly 'worktree.label': "新建工作树";
|
|
147
200
|
readonly 'worktree.hint': "在独立的工作树中运行本会话:发送后基于所选分支新建分支,修改和提交不影响项目目录";
|
|
148
|
-
readonly 'worktree.blocked.not-git': "工作区不是 Git 仓库,无法使用工作树";
|
|
149
201
|
readonly 'worktree.blocked.outside-writable-root': "这个工作区的 Git 数据不在可写目录中(例如工作区本身就是工作树),暂不支持使用工作树";
|
|
150
202
|
readonly 'worktree.blocked.read-only': "只读模式下无法使用工作树";
|
|
151
203
|
readonly 'worktree.base': "基于 {branch}";
|
|
152
204
|
readonly 'worktree.baseHead': "基于当前 HEAD";
|
|
153
205
|
readonly 'worktree.baseMenu': "选择基准分支";
|
|
154
206
|
readonly 'worktree.currentBranch': "当前分支";
|
|
207
|
+
readonly 'worktree.currentBranchTip': "当前分支:{branch}";
|
|
208
|
+
readonly 'worktree.detachedTip': "未在分支上 · {commit}";
|
|
155
209
|
readonly 'creation.title': "正在创建工作树";
|
|
156
210
|
readonly 'creation.failed': "创建工作树失败";
|
|
157
211
|
readonly 'creation.prepare': "创建分支";
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/** Browser-persisted review drafts and the write whose outcome still needs confirmation. */
|
|
2
|
+
import type { ForgeReviewRequest } from '@deepseek-ai/dsh-experimental-forge/types';
|
|
3
|
+
import type { ReviewSelection, ReviewSource } from './review.ts';
|
|
4
|
+
/** A comment retained after adding its reference or receiving a publication receipt. */
|
|
5
|
+
export type ReviewRecord = {
|
|
6
|
+
readonly kind: 'agent';
|
|
7
|
+
readonly selection: ReviewSelection;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'published';
|
|
10
|
+
readonly selection: ReviewSelection;
|
|
11
|
+
readonly url: string;
|
|
12
|
+
};
|
|
13
|
+
/** One inline record; its numeric key belongs only to the retained browser store. */
|
|
14
|
+
export type ReviewThread = {
|
|
15
|
+
readonly key: number;
|
|
16
|
+
} & (ReviewRecord | {
|
|
17
|
+
readonly kind: 'pending';
|
|
18
|
+
readonly selection: ReviewSelection;
|
|
19
|
+
});
|
|
20
|
+
/** File-scoped snapshot that does not change while unrelated comments or the summary are edited. */
|
|
21
|
+
export interface FileReviewState {
|
|
22
|
+
readonly threads: readonly ReviewThread[];
|
|
23
|
+
readonly locked: boolean;
|
|
24
|
+
readonly error: ReviewQueueState['error'];
|
|
25
|
+
}
|
|
26
|
+
/** Stable snapshot for a file without a comment store. */
|
|
27
|
+
export declare const EMPTY_FILE_REVIEW: FileReviewState;
|
|
28
|
+
/** Immutable queue snapshot; errors leave the original stored bytes untouched. */
|
|
29
|
+
export interface ReviewQueueState {
|
|
30
|
+
readonly comments: readonly ReviewSelection[];
|
|
31
|
+
readonly records: readonly ReviewRecord[];
|
|
32
|
+
readonly body: string;
|
|
33
|
+
readonly event: 'comment' | 'approve' | 'request-changes';
|
|
34
|
+
readonly uncertain: ForgeReviewRequest | null;
|
|
35
|
+
readonly error: 'load' | 'save' | null;
|
|
36
|
+
}
|
|
37
|
+
/** Initial state of a newly opened review tab. */
|
|
38
|
+
export declare const EMPTY_REVIEW: ReviewQueueState;
|
|
39
|
+
/** One review tab's drafts and records, retained until its occurrence closes. */
|
|
40
|
+
export declare class ReviewQueue {
|
|
41
|
+
private readonly key;
|
|
42
|
+
private closed;
|
|
43
|
+
private state;
|
|
44
|
+
private readonly listeners;
|
|
45
|
+
private readonly keys;
|
|
46
|
+
private nextKey;
|
|
47
|
+
private readonly files;
|
|
48
|
+
/** @param key - browser storage key including Session and tab identity. */
|
|
49
|
+
constructor(key: string);
|
|
50
|
+
/** Current queue snapshot, stable between edits and storage failures. */
|
|
51
|
+
readonly getSnapshot: () => ReviewQueueState;
|
|
52
|
+
/**
|
|
53
|
+
* Clear this tab's records and refuse later completions from its outgoing requests.
|
|
54
|
+
* @returns whether its browser storage was cleared; the in-memory state always closes.
|
|
55
|
+
*/
|
|
56
|
+
close(): boolean;
|
|
57
|
+
/** Summary subscribed by the surrounding diff; editing draft text does not invalidate its file rows. */
|
|
58
|
+
readonly getStatus: () => string;
|
|
59
|
+
/**
|
|
60
|
+
* Read stable inline records for one path and review source.
|
|
61
|
+
* @param path - repository-relative file path.
|
|
62
|
+
* @param source - PR or local scope; older head commits remain available as outdated comments.
|
|
63
|
+
* @returns records and edit availability, reusing the snapshot when these values are unchanged.
|
|
64
|
+
*/
|
|
65
|
+
fileComments(path: string, source: ReviewSource): FileReviewState;
|
|
66
|
+
/**
|
|
67
|
+
* Retain an Agent reference at its original code location.
|
|
68
|
+
* @param selection - reference already accepted by the main composer.
|
|
69
|
+
* @returns whether the record was saved.
|
|
70
|
+
*/
|
|
71
|
+
recordAgent(selection: ReviewSelection): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Retain a published comment and settle its outgoing write atomically in browser storage.
|
|
74
|
+
* @param selection - published comment's frozen code location.
|
|
75
|
+
* @param url - confirmed publication URL.
|
|
76
|
+
* @returns whether the receipt and comment were saved.
|
|
77
|
+
*/
|
|
78
|
+
published(selection: ReviewSelection, url: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Observe queue edits and storage failures.
|
|
81
|
+
* @param listener - snapshot invalidation.
|
|
82
|
+
* @returns unsubscribe.
|
|
83
|
+
*/
|
|
84
|
+
readonly subscribe: (listener: () => void) => (() => void);
|
|
85
|
+
/**
|
|
86
|
+
* Save a frozen PR comment unless a write needs reconciliation.
|
|
87
|
+
* @param selection - frozen PR comment.
|
|
88
|
+
* @returns whether it was saved.
|
|
89
|
+
*/
|
|
90
|
+
add(selection: ReviewSelection): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Edit or remove a pending comment without changing its captured lines.
|
|
93
|
+
* @param index - comment position.
|
|
94
|
+
* @param body - replacement text, or null to remove.
|
|
95
|
+
* @returns whether saved.
|
|
96
|
+
*/
|
|
97
|
+
edit(index: number, body: string | null): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Edit the currently pending occurrence addressed by an inline record.
|
|
100
|
+
* @param key - browser-store identity from fileComments.
|
|
101
|
+
* @param body - replacement text, or null to remove.
|
|
102
|
+
* @returns whether the occurrence still exists and the edit was saved.
|
|
103
|
+
*/
|
|
104
|
+
editThread(key: number, body: string | null): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Save the summary and decision for the pending review.
|
|
107
|
+
* @param body - review summary.
|
|
108
|
+
* @param event - review decision.
|
|
109
|
+
* @returns whether saved.
|
|
110
|
+
*/
|
|
111
|
+
summarize(body: string, event: ReviewQueueState['event']): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Persist the outgoing request before network dispatch.
|
|
114
|
+
* @param request - exact write.
|
|
115
|
+
* @returns whether dispatch may start.
|
|
116
|
+
*/
|
|
117
|
+
begin(request: ForgeReviewRequest): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Clear the write after a known result or explicit reconciliation.
|
|
120
|
+
* @param submitted - whether a batch review was published.
|
|
121
|
+
* @param url - confirmed publication URL when retaining submitted comments.
|
|
122
|
+
* @returns whether saved.
|
|
123
|
+
*/
|
|
124
|
+
finish(submitted: boolean, url?: string): boolean;
|
|
125
|
+
private keyOf;
|
|
126
|
+
private save;
|
|
127
|
+
private emit;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Compare review identity while allowing records from an older PR head to remain visible.
|
|
131
|
+
* @param left - recorded source.
|
|
132
|
+
* @param right - displayed source.
|
|
133
|
+
* @returns whether the sources name the same PR or local scope.
|
|
134
|
+
*/
|
|
135
|
+
export declare function sameReviewSource(left: ReviewSource, right: ReviewSource): boolean;
|
|
136
|
+
//# sourceMappingURL=review-queue.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Frozen line selections shared by the diff UI, composer references, and review submission. */
|
|
2
|
+
import type { ForgeDiffFile } from '../types.ts';
|
|
3
|
+
/** A comment on consecutive lines of one side of one displayed hunk. */
|
|
4
|
+
export interface ReviewComment {
|
|
5
|
+
/** Repository-relative destination path, including for renamed files. */
|
|
6
|
+
readonly path: string;
|
|
7
|
+
/** Old or new side of the displayed diff. */
|
|
8
|
+
readonly side: 'L' | 'R';
|
|
9
|
+
/** First selected line, inclusive. */
|
|
10
|
+
readonly startLine: number;
|
|
11
|
+
/** Last selected line, inclusive. */
|
|
12
|
+
readonly endLine: number;
|
|
13
|
+
/** Complete displayed hunk captured before subsequent file changes. */
|
|
14
|
+
readonly hunk: string;
|
|
15
|
+
/** User's plain-text comment. */
|
|
16
|
+
readonly body: string;
|
|
17
|
+
}
|
|
18
|
+
/** The immutable source from which a comment was selected. */
|
|
19
|
+
export type ReviewSource = {
|
|
20
|
+
readonly kind: 'local';
|
|
21
|
+
readonly scope: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'change';
|
|
24
|
+
readonly url: string;
|
|
25
|
+
readonly headSha: string;
|
|
26
|
+
};
|
|
27
|
+
/** One selected range and the source the user saw. */
|
|
28
|
+
export interface ReviewSelection {
|
|
29
|
+
readonly source: ReviewSource;
|
|
30
|
+
readonly comment: ReviewComment;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Capture a range only when both endpoints belong to the same displayed hunk.
|
|
34
|
+
* @param file - loaded diff file.
|
|
35
|
+
* @param side - selected side.
|
|
36
|
+
* @param from - first gesture endpoint.
|
|
37
|
+
* @param to - current gesture endpoint.
|
|
38
|
+
* @returns a frozen selection, or undefined for unchanged gaps or cross-hunk ranges.
|
|
39
|
+
*/
|
|
40
|
+
export declare function selectReviewLines(file: ForgeDiffFile, side: 'L' | 'R', from: number, to: number): ReviewComment | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Format a frozen reference for the ordinary, logged user message.
|
|
43
|
+
* @param selection - source, range, displayed patch, and user comment.
|
|
44
|
+
* @param index - one-based reference number in the composer.
|
|
45
|
+
* @returns Markdown content for an atomic composer quote.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatReviewComment(selection: ReviewSelection, index: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* Check whether the current diff still contains the captured range and hunk.
|
|
50
|
+
* @param selection - saved comment source and patch.
|
|
51
|
+
* @param source - currently displayed review source.
|
|
52
|
+
* @param file - current diff file.
|
|
53
|
+
* @returns whether an inline record can retain its original line placement.
|
|
54
|
+
*/
|
|
55
|
+
export declare function reviewMatches(selection: ReviewSelection, source: ReviewSource, file: ForgeDiffFile): boolean;
|
|
56
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -21,12 +21,16 @@ export type CiSummary = {
|
|
|
21
21
|
| {
|
|
22
22
|
readonly kind: 'failed';
|
|
23
23
|
readonly count: number;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: 'cancelled';
|
|
26
|
+
readonly count: number;
|
|
24
27
|
};
|
|
25
|
-
/** Checks grouped by outcome; `other` holds neutral
|
|
28
|
+
/** Checks grouped by outcome; `other` holds neutral and skipped checks. */
|
|
26
29
|
export interface CheckCounts {
|
|
27
30
|
readonly failed: number;
|
|
28
31
|
readonly running: number;
|
|
29
32
|
readonly passed: number;
|
|
33
|
+
readonly cancelled: number;
|
|
30
34
|
readonly other: number;
|
|
31
35
|
}
|
|
32
36
|
/** The most urgent fact of an open change request that the collapsed card names. */
|
|
@@ -51,7 +55,7 @@ export declare function checkCounts(checks: readonly ChangeRequestCheck[]): Chec
|
|
|
51
55
|
/**
|
|
52
56
|
* Summarize the checks of a change request from the host's combined outcome.
|
|
53
57
|
* @param snapshot - change request status.
|
|
54
|
-
* @returns the combined outcome with
|
|
58
|
+
* @returns the combined outcome with its failure or cancellation count.
|
|
55
59
|
*/
|
|
56
60
|
export declare function ciSummary(snapshot: ChangeRequestSnapshot): CiSummary;
|
|
57
61
|
/**
|
package/lib/types/git.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Git queries in a Session's current directory, using its permissions and execution world. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import type { Session } from '@deepseek-ai/dsh-session';
|
|
4
4
|
import type { GitRemote } from './parse.ts';
|
|
@@ -31,17 +31,17 @@ export interface GitOutput {
|
|
|
31
31
|
readonly stderr: string;
|
|
32
32
|
readonly exitCode: number;
|
|
33
33
|
}
|
|
34
|
-
/** Runs one Git subcommand
|
|
35
|
-
export type Git = (name: string, args: readonly string[], allowedExitCodes?: readonly number[]) => Promise<GitOutput>;
|
|
34
|
+
/** Runs one Git subcommand with optional command-local configuration; output with an exit code outside `allowedExitCodes` throws. */
|
|
35
|
+
export type Git = (name: string, args: readonly string[], allowedExitCodes?: readonly number[], configOverrides?: Readonly<Record<string, string>>) => Promise<GitOutput>;
|
|
36
36
|
/** Thrown when a Git command prints more than `maxOutputBytes` on standard output. */
|
|
37
37
|
export declare class GitOutputTooLarge extends Error {
|
|
38
38
|
name: string;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Inspect the checkout containing `directory`. Every command runs through the
|
|
42
|
-
* mounted subprocess provider under
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* mounted subprocess provider under the Session's sandbox policy and reads
|
|
43
|
+
* refs and configuration only, never the working tree.
|
|
44
|
+
* The top-level and shared Git directories Git prints are resolved
|
|
45
45
|
* through `ctx.fs` into canonical process paths, the form the
|
|
46
46
|
* working-directory service records.
|
|
47
47
|
* @param ctx - context that provides `fs`, `subprocess`, `sandbox`, and `sandboxPolicy`.
|
|
@@ -55,7 +55,7 @@ export declare class GitOutputTooLarge extends Error {
|
|
|
55
55
|
export declare function inspectCheckout(ctx: Context, config: GitConfig, session: Session, directory: string, signal: AbortSignal): Promise<Inspection | undefined>;
|
|
56
56
|
/**
|
|
57
57
|
* List the local branches that can start a worktree of the checkout containing
|
|
58
|
-
* `directory`,
|
|
58
|
+
* `directory`, using the Session's permissions as in {@link inspectCheckout}.
|
|
59
59
|
* @param ctx - context that provides `subprocess`, `sandbox`, and `sandboxPolicy`.
|
|
60
60
|
* @param config - executable and process limits.
|
|
61
61
|
* @param session - Session whose sandbox policy and execution world apply.
|
|
@@ -67,7 +67,7 @@ export declare function inspectCheckout(ctx: Context, config: GitConfig, session
|
|
|
67
67
|
*/
|
|
68
68
|
export declare function listBranches(ctx: Context, config: GitConfig, session: Session, directory: string, limit: number, signal: AbortSignal): Promise<ForgeBranches>;
|
|
69
69
|
/**
|
|
70
|
-
* Report whether a local branch exists,
|
|
70
|
+
* Report whether a local branch exists, using the Session's permissions as in {@link inspectCheckout}.
|
|
71
71
|
* @param ctx - context that provides `subprocess`, `sandbox`, and `sandboxPolicy`.
|
|
72
72
|
* @param config - executable and process limits.
|
|
73
73
|
* @param session - Session whose sandbox policy and execution world apply.
|
|
@@ -79,8 +79,8 @@ export declare function listBranches(ctx: Context, config: GitConfig, session: S
|
|
|
79
79
|
*/
|
|
80
80
|
export declare function hasBranch(ctx: Context, config: GitConfig, session: Session, repositoryRoot: string, branch: string, signal: AbortSignal): Promise<boolean>;
|
|
81
81
|
/**
|
|
82
|
-
* Bind the
|
|
83
|
-
* runs under
|
|
82
|
+
* Bind the Git runner to one Session and directory: every command
|
|
83
|
+
* runs under the Session's sandbox policy with the
|
|
84
84
|
* scrubbed environment, the fixed command prefix, and `config`'s limits.
|
|
85
85
|
* @param ctx - context that provides `subprocess`, `sandbox`, and `sandboxPolicy`.
|
|
86
86
|
* @param config - executable and process limits.
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Host Remote of the forge panel: checkout, code host, sign-in, change request, and worktree state per Session. */
|
|
2
2
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
3
3
|
import z from '@deepseek-ai/schemastery';
|
|
4
|
-
import type { MergeMethod } from '@deepseek-ai/dsh-experimental-forge';
|
|
4
|
+
import type { ChangeRequestSnapshot, ForgeReviewRequest, ForgeReviewResult, MergeMethod } from '@deepseek-ai/dsh-experimental-forge';
|
|
5
5
|
import type { Session } from '@deepseek-ai/dsh-session';
|
|
6
6
|
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
7
7
|
import type { Config, ForgeBranches, ForgeChangeRequestDiff, ForgeChangeRequestStatesFrame, ForgeLocalDiff, ForgeLocalScope, ForgePanelState } from './types.ts';
|
|
@@ -14,7 +14,7 @@ declare module '@deepseek-ai/cordis' {
|
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Serves the forge panel. Following a Session inspects the checkout of its
|
|
17
|
-
* current directory
|
|
17
|
+
* current directory using the Session's permissions and execution world, recognizes the
|
|
18
18
|
* code host of the upstream remote or `origin`, probes sign-in for that host,
|
|
19
19
|
* and polls the Session's bound change requests through `ctx.forge` until the
|
|
20
20
|
* last follower of that Session leaves. A worktree request makes the panel
|
|
@@ -96,13 +96,14 @@ export declare class ForgePanelController extends TypertRemoteService {
|
|
|
96
96
|
refresh(session: Session, signal: AbortSignal): Promise<void>;
|
|
97
97
|
/**
|
|
98
98
|
* Read the changes one scope covers in the checkout of the Session's
|
|
99
|
-
* current directory, with Git
|
|
99
|
+
* current directory, with Git using the Session's sandbox policy.
|
|
100
100
|
* @param session - Session whose checkout is read.
|
|
101
101
|
* @param scope - which changes to read.
|
|
102
102
|
* @param signal - request cancellation.
|
|
103
103
|
* @returns the files, the base of the `branch` scope, and the untracked files left out.
|
|
104
104
|
* @throws `forgePanel/not-a-checkout` outside a checkout; `forgePanel/no-fork-point` for the `branch`
|
|
105
|
-
* scope of a checkout without one; `forgePanel/
|
|
105
|
+
* scope of a checkout without one; `forgePanel/filter-config-failed` when filter configuration cannot be read
|
|
106
|
+
* completely, before any comparison; `forgePanel/diff-too-large` over `maxDiffBytes`; the Git error when Git fails.
|
|
106
107
|
*/
|
|
107
108
|
localDiff(session: Session, scope: ForgeLocalScope, signal: AbortSignal): Promise<ForgeLocalDiff>;
|
|
108
109
|
/**
|
|
@@ -117,6 +118,17 @@ export declare class ForgePanelController extends TypertRemoteService {
|
|
|
117
118
|
* an error for a path outside the checkout, binary content, or a failed read.
|
|
118
119
|
*/
|
|
119
120
|
localText(session: Session, scope: ForgeLocalScope, path: string, signal: AbortSignal): Promise<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Load complete checks for the change request whose list the user opened.
|
|
123
|
+
* @param session - Session retaining the visible binding.
|
|
124
|
+
* @param url - binding URL.
|
|
125
|
+
* @param headSha - commit displayed by the card; a different head rejects the result.
|
|
126
|
+
* @param signal - cancellation when the list closes.
|
|
127
|
+
* @returns the complete snapshot at the displayed head.
|
|
128
|
+
* @throws `forgePanel/not-bound` for an invisible binding, `forgePanel/stale-head` for a moved head,
|
|
129
|
+
* or `forgePanel/checks-failed` when the provider cannot complete the read.
|
|
130
|
+
*/
|
|
131
|
+
changeRequestChecks(session: Session, url: string, headSha: string, signal: AbortSignal): Promise<ChangeRequestSnapshot>;
|
|
120
132
|
/**
|
|
121
133
|
* Read the changes of a change request of a Session as its code host
|
|
122
134
|
* computes them, at the head commit of its latest status. A patch already
|
|
@@ -145,6 +157,15 @@ export declare class ForgePanelController extends TypertRemoteService {
|
|
|
145
157
|
* `forgePanel/diff-failed` when the host does not provide the file otherwise.
|
|
146
158
|
*/
|
|
147
159
|
changeRequestText(session: Session, url: string, commit: string, path: string, signal: AbortSignal): Promise<string>;
|
|
160
|
+
/**
|
|
161
|
+
* Publish a line comment or completed review for a visible Session binding.
|
|
162
|
+
* @param session - Session retaining the change request.
|
|
163
|
+
* @param url - visible binding URL.
|
|
164
|
+
* @param request - reviewed head, ranges, plain text, and explicit review decision.
|
|
165
|
+
* @param signal - request cancellation.
|
|
166
|
+
* @returns confirmed publication or a typed failure; unknown outcomes require reconciliation on the host.
|
|
167
|
+
*/
|
|
168
|
+
submitReview(session: Session, url: string, request: ForgeReviewRequest, signal: AbortSignal): Promise<ForgeReviewResult>;
|
|
148
169
|
/**
|
|
149
170
|
* Mark a draft change request of a Session ready for review; the change
|
|
150
171
|
* request is polled again once the host answers.
|