dsh-vscode-mode 0.23.0 → 0.23.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vscode-mode",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "description": "DSH 上的类 VSCode 编码体验:Monaco 编辑器(文件页签/QuickOpen/状态栏,可驻 DSH 0.1.5+ 官方右侧 Sidebar 与对话同屏)+ 命令栏(Ctrl+Shift+P)与可扩展指令系统 + VS Code 兼容代码片段(.code-snippets 全局/项目,IntelliSense 展开)+ Agent 编辑差异审查(整文件差异/采纳/拒绝/归档/回滚)+ SVN 集成(侧栏变更面板/日志弹窗/并排差异)+ 语言服务器(LSP)智能(跳转定义/引用/hover/大纲 + VSIX 扩展市场安装),状态持久化到工作区旁车,界面状态(页签/光标/侧栏/编辑 Tab/导航历史)镜像到 DSH home 跨重启恢复",
5
5
  "icon": "assets/icon.svg",
6
6
  "keywords": [
@@ -2,7 +2,7 @@
2
2
  import type { ReviewDetail, ReviewItem, ReviewPage, ReviewResult } from '../shared/review.js'
3
3
 
4
4
  export interface BatchPort {
5
- list: (cursor?: number) => Promise<ReviewPage>
5
+ snapshot: () => Promise<ReviewPage>
6
6
  detail: (id: string) => Promise<ReviewDetail>
7
7
  decide: (detail: ReviewDetail, reject: boolean, operationId: string) => Promise<ReviewResult<{ revision: number }>>
8
8
  guard: () => void
@@ -10,27 +10,23 @@ export interface BatchPort {
10
10
  }
11
11
  export interface BatchResult { completed: number; total: number; paths: string[]; error: string }
12
12
 
13
- /** @public @author ddj 2026年10月27号 @param port Authenticated RPC adapter. @returns Frozen complete pending set; aborts before any decision if pagination shifts. @throws Incomplete or changing pages. */
14
- export async function loadPending(port: Pick<BatchPort, 'list'>): Promise<ReviewItem[]> {
15
- const items: ReviewItem[] = []
13
+ /**
14
+ * @public
15
+ * @author ddj 2026年10月31号
16
+ * @description: 取一次完整待审快照。分页计数只用于展示,批量写入必须一次取全,避免把页内数字当成总数。
17
+ * @param port 已鉴权的 RPC 适配器
18
+ * @returns 冻结的完整待审集;任何不一致都在首个写入前中止
19
+ * @throws 快照重复、版本已变或数量不完整
20
+ */
21
+ export async function loadPending(port: Pick<BatchPort, 'snapshot'>): Promise<ReviewItem[]> {
22
+ const page = await port.snapshot()
16
23
  const seen = new Set<string>()
17
- const cursors = new Set<number>()
18
- let cursor: number | undefined
19
- let expected: number | undefined
20
- do {
21
- const page = await port.list(cursor)
22
- expected ??= page.pending
23
- if (page.pending !== expected) throw new Error('待审记录在分页期间变化,请刷新后重试')
24
- for (const item of page.items) {
25
- if (seen.has(item.id) || !item.current || item.decision !== 'pending') throw new Error('待审分页发生重复或版本变化,请刷新后重试')
26
- seen.add(item.id); items.push(item)
27
- }
28
- if (page.nextCursor === null) break
29
- if (cursors.has(page.nextCursor) || page.items.length === 0) throw new Error('待审分页未完整返回,请刷新后重试')
30
- cursor = page.nextCursor; cursors.add(cursor)
31
- } while (true)
32
- if (items.length !== expected) throw new Error('待审记录数量不完整,未执行批量操作')
33
- return items
24
+ for (const item of page.items) {
25
+ if (seen.has(item.id) || !item.current || item.decision !== 'pending') throw new Error('待审快照发生重复或版本变化,请刷新后重试')
26
+ seen.add(item.id)
27
+ }
28
+ if (page.nextCursor !== null || page.items.length !== page.pending) throw new Error('待审记录数量不完整,未执行批量操作')
29
+ return page.items
34
30
  }
35
31
 
36
32
  /** @public @author ddj 2026年10月27号 @param port Guarded existing per-file decision adapter. @param reject Undo instead of Keep. @returns Precise partial result; Undo stops at first conflict, never claims atomic multi-file rollback. */
@@ -3479,7 +3479,11 @@ export function EditorView(props) {
3479
3479
  setStatus(reject ? '正在检查并 Undo 全部待审记录…' : '正在 Keep 全部待审记录…')
3480
3480
  try {
3481
3481
  const result = await runReviewBatch({
3482
- list: async (cursor) => { const res = await rpc('edrv.review.list', { sessionId, cursor }); if (!res.ok) throw new Error(res.error); return res.page },
3482
+ snapshot: async () => {
3483
+ const res = await rpc('edrv.review.list', { sessionId, all: true })
3484
+ if (!res.ok) throw new Error(res.error)
3485
+ return res.page
3486
+ },
3483
3487
  detail: async (id) => { const res = await rpc('edrv.review.detail', { sessionId, id }); if (!res.ok) throw new Error(res.error); return res.detail },
3484
3488
  decide: (detail, undo, operationId) => rpc('edrv.review.decide', { sessionId, id: detail.item.id, seq: detail.item.seq, revision: detail.item.revision, operationId, scope: 'file', decision: undo ? 'rejected' : 'accepted' }),
3485
3489
  guard: () => guardReviewAll(reject, token), operation: batchOperation,
package/src/reviewRpc.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /** Session-scoped official review RPC. @author ddj 2026年10月26号 */
2
2
  import type { RpcHandlerMap } from './shared/rpc.js'
3
+ import type { ReviewItem, ReviewPage } from './shared/review.js'
3
4
  import type { PendingPage } from './shared/pendingReview.js'
4
5
  import { decideReview, reviewDetail, reviewPage } from './reviewDb.js'
5
6
  import { undoReview } from './reviewUndo.js'
@@ -9,6 +10,41 @@ import { bucketOf, resolveScope, sessionOf } from './registry.js'
9
10
  import type { Registry } from './registry.js'
10
11
  import type { Ctx } from './store.js'
11
12
 
13
+ /** 批量写入快照的硬上限:待审积压超过它说明状态异常,宁可拒绝也不做无界写循环。 */
14
+ const BATCH_LIMIT = 2000
15
+
16
+ /**
17
+ * @private
18
+ * @author ddj 2026年10月31号
19
+ * @description: 批量写入用的一次性完整快照。合并口径与列表一致(待审投影优先、同路径官方旧行让位),
20
+ * 但一次取全,且 items 与 pending 同源,客户端才能把它当成写前不变式。
21
+ * @param cwd 工作区
22
+ * @param pending 该会话可见的待审页
23
+ * @returns 完整快照;待审积压超过上限或分页期间数量漂移时返回错误
24
+ */
25
+ function batchSnapshot(cwd: string, pending: PendingPage): { ok: true; page: ReviewPage } | { ok: false; error: string } {
26
+ const first = reviewPage(cwd)
27
+ if (first.pending > BATCH_LIMIT) return { ok: false, error: `待审记录过多(${first.pending} 条,上限 ${BATCH_LIMIT}),请先分批处理后重试` }
28
+
29
+ const official: ReviewItem[] = []
30
+ let page: ReviewPage | undefined = first
31
+ while (page) {
32
+ for (const item of page.items) if (item.current && item.decision === 'pending') official.push(item)
33
+ page = page.nextCursor === null ? undefined : reviewPage(cwd, page.nextCursor)
34
+ }
35
+ // 分页期间有记录被判定掉:数量对不上就不给客户端一份半截快照
36
+ if (official.length !== first.pending) return { ok: false, error: '待审记录数量不完整,未执行批量操作' }
37
+
38
+ // 待审投影已接管的路径,官方旧行必须让位,否则同一文件会被批量写两次
39
+ const live = pending.items.filter((item) => !item.settled)
40
+ const kept = official.filter((row) => !live.some((entry) => pendingSamePath(entry.path, row.currentPath) || pendingSamePath(entry.path, row.path)))
41
+ const items = [...live.map((entry) => pendingItemOf(entry, cwd)), ...kept]
42
+ return {
43
+ ok: true,
44
+ page: { items, pending: items.length, nextCursor: null, gaps: first.gaps, ...(first.overview ? { overview: first.overview } : {}) },
45
+ }
46
+ }
47
+
12
48
  /**
13
49
  * @public
14
50
  * @author ddj 2026年10月26号 / 2026年10月28号
@@ -52,6 +88,10 @@ export function reviewHandlers(ctx: Ctx, registry: Registry): Partial<RpcHandler
52
88
  return {
53
89
  'edrv.review.list': async (args) => {
54
90
  const cwd = await workspace(args.sessionId)
91
+ // 批量通道要的是一次性完整快照:分页口径的 pending 只是页内展示计数,不能当完整性不变式
92
+ if (args.all && !args.history && args.path === undefined) {
93
+ return batchSnapshot(cwd, pendingPageOf(cwd, args.sessionId))
94
+ }
55
95
  const official = reviewPage(cwd, args.cursor, args.history, args.path)
56
96
  const pending = pendingPageOf(cwd, args.sessionId)
57
97
  // 历史快照只属于官方通道;待审条目没有轮次历史,混进去会造出假的「轮次 0」。
package/src/shared/rpc.ts CHANGED
@@ -375,7 +375,7 @@ export interface UiStatePatchInput {
375
375
 
376
376
  /** 每个方法的请求参数(sessionId 为公共可选字段)。 */
377
377
  export interface RpcRequestMap {
378
- 'edrv.review.list': ReviewRequest & { cursor?: number; history?: boolean; path?: string }
378
+ 'edrv.review.list': ReviewRequest & { cursor?: number; history?: boolean; path?: string; all?: boolean }
379
379
  'edrv.review.detail': ReviewRequest & { id: string }
380
380
  'edrv.review.decide': DecideReview
381
381
  'edrv.pending.list': PendingRequest