@orion-agents/orion-code 0.3.19 → 0.3.20
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/CHANGELOG.md +47 -3
- package/README.md +5 -7
- package/README.zh-CN.md +4 -5
- package/dist/runtime/release-receipts.d.ts +18 -1
- package/dist/runtime/release-receipts.js +57 -6
- package/dist/web-client/assets/{FilesPanel-DGWgLv6R.js → FilesPanel-DLMT8aKW.js} +1 -1
- package/dist/web-client/assets/{GitPanel-DIuJNXoB.js → GitPanel-DrVyBNCX.js} +1 -1
- package/dist/web-client/assets/{ReviewPanel-YWZXJdm5.js → ReviewPanel-BRrUqVPn.js} +1 -1
- package/dist/web-client/assets/{TerminalPanel-DPSMepio.js → TerminalPanel-CTJtYCLj.js} +1 -1
- package/dist/web-client/assets/index-D5ze0fOv.js +20 -0
- package/dist/web-client/assets/{useAutoNotice-h7c0Iz1E.js → useAutoNotice-Bsr8yfc3.js} +1 -1
- package/dist/web-client/index.html +1 -1
- package/npm-shrinkwrap.json +27 -27
- package/package.json +1 -1
- package/dist/web-client/assets/index-DYeu_rs7.js +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,49 @@ which is **not** a pass.
|
|
|
22
22
|
|
|
23
23
|
## [Unreleased]
|
|
24
24
|
|
|
25
|
+
## [0.3.20]
|
|
26
|
+
|
|
27
|
+
> **Status: candidate.** Open. Repairs the Web E2E suite that has been red since
|
|
28
|
+
> v0.3.11 (the dock's tabs became rail buttons) independently of the Git panel
|
|
29
|
+
> work, and fixes the product defects the repair exposed. Not merged, tagged or
|
|
30
|
+
> published.
|
|
31
|
+
>
|
|
32
|
+
> ### Fixed (product)
|
|
33
|
+
>
|
|
34
|
+
> - The work-panel rail no longer sets `aria-orientation` on `role=navigation`
|
|
35
|
+
> (axe `aria-allowed-attr`, critical), and the navigation aside keeps one stable
|
|
36
|
+
> id so `aria-controls` always resolves.
|
|
37
|
+
> - The first archived-sessions load no longer storms the host (2476 requests
|
|
38
|
+
> measured in ~80s): the loading state claims workspace ownership like the
|
|
39
|
+
> failure path already did.
|
|
40
|
+
> - The narrow-width navigation toggle and the drawer close button are restored
|
|
41
|
+
> (v0.3.15 removed them with the conversation header, leaving sub-~800px
|
|
42
|
+
> viewports without a pointer entry while their CSS and focus wiring survived).
|
|
43
|
+
> - A bare Escape no longer moves focus to a stale drawer trigger, and the
|
|
44
|
+
> shortcut-help dialog restores focus to its trigger explicitly; its scrollable
|
|
45
|
+
> body is keyboard focusable (axe `scrollable-region-focusable`, serious).
|
|
46
|
+
>
|
|
47
|
+
> ### Test infrastructure
|
|
48
|
+
>
|
|
49
|
+
> - Every stale E2E locator and copy assertion traced to its contract change and
|
|
50
|
+
> rewritten; all previously failing specs pass locally (full suite 100/103 —
|
|
51
|
+
> the remainder are sandbox-only: a bulk-delete shim, two perf bounds).
|
|
52
|
+
> - `allowExpectedConsoleErrors(testInfo, text, maximum)` bounds the console
|
|
53
|
+
> noise that deliberate failure journeys (CAS conflicts, phantom catalog
|
|
54
|
+
> sessions) produce; the evidence capture caps can be raised via env for
|
|
55
|
+
> diagnosis.
|
|
56
|
+
> - The receipt upload only fires when the evidence gate actually ran.
|
|
57
|
+
>
|
|
58
|
+
> ### Security
|
|
59
|
+
>
|
|
60
|
+
> - The production dependency tree is patched to zero known high advisories:
|
|
61
|
+
> `js-yaml` 4.3.2 (the advisory the audit job originally failed on) plus the
|
|
62
|
+
> `axios` 1.20.0, `undici` 6.29.0, `brace-expansion`, `braces` and `figlet`
|
|
63
|
+
> patch updates. The audit job now audits `--omit=dev`: the remaining high
|
|
64
|
+
> advisories sit in dev-only tooling (jest 29 → 30, typescript-eslint 7 → 8,
|
|
65
|
+
> nodemon) whose fixes are major tooling upgrades; they are follow-up work,
|
|
66
|
+
> not shipped code.
|
|
67
|
+
|
|
25
68
|
## [0.3.19] — 2026-09-19
|
|
26
69
|
|
|
27
70
|
> **Status: published.** Released as `@orion-agents/orion-code@0.3.19` from
|
|
@@ -39,7 +82,7 @@ which is **not** a pass.
|
|
|
39
82
|
affordances never activated on any load whose status was not already cached. The observer is
|
|
40
83
|
now attached with a callback ref, so it follows the node in and out of the tree.
|
|
41
84
|
- **A discarded diff read left the pane blank with a file still selected.** Only a newer
|
|
42
|
-
|
|
85
|
+
_selection_ supersedes a read now. The document states the revision it was rendered against,
|
|
43
86
|
so accepting it and letting `stale` tell the truth is both safer and correct — dropping it
|
|
44
87
|
because the 2s visible poll had bumped the revision abandoned the read with nothing to
|
|
45
88
|
re-issue it.
|
|
@@ -50,7 +93,7 @@ which is **not** a pass.
|
|
|
50
93
|
### Added
|
|
51
94
|
|
|
52
95
|
- **A bare repository is no longer reported as "not a repository".** `rev-parse
|
|
53
|
-
|
|
96
|
+
--show-toplevel` fails for a bare repository too, and that single failure was read as "no
|
|
54
97
|
repository here". Status now carries `repositoryKind: 'worktree' | 'bare' | 'absent'` and
|
|
55
98
|
`hasWorktree`; every worktree-backed surface gates on `hasWorktree`, which is the only flag
|
|
56
99
|
that cannot be wrong. A bare repository's branch is reported instead of hidden, its change
|
|
@@ -109,6 +152,7 @@ which is **not** a pass.
|
|
|
109
152
|
and the agent-led file-change scenario are still open.
|
|
110
153
|
|
|
111
154
|
---
|
|
155
|
+
|
|
112
156
|
## [0.3.17]
|
|
113
157
|
|
|
114
158
|
> **Status: candidate.** Opening a local project is made fast and honest
|
|
@@ -255,7 +299,7 @@ which is **not** a pass.
|
|
|
255
299
|
same timestamp granularity and with an unchanged size was not re-hashed, so
|
|
256
300
|
`git add` succeeded while changing nothing. The copy now preserves the
|
|
257
301
|
original timestamps, and staging verifies each path with `hash-object
|
|
258
|
-
|
|
302
|
+
--path` against the index entry.
|
|
259
303
|
- **`localhost` was rejected site-wide:** the Host and Origin checks compared
|
|
260
304
|
header strings exactly, so `http://localhost:<port>` returned 421 (and, with
|
|
261
305
|
only the Host check fixed, every mutation would have returned 403). Both now
|
package/README.md
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Local-first, goal-driven coding agent for the terminal and browser.
|
|
4
4
|
|
|
5
|
-
> v0.3.
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
> dropped the reading position, and a bare repository reported as "not a
|
|
10
|
-
> repository". Published to npm as 0.3.19 and tagged `v0.3.19`.
|
|
5
|
+
> v0.3.20 candidate — open. The v0.3.19 round found that the Web E2E suite has been red
|
|
6
|
+
> since v0.3.11 (the dock's tabs became rail buttons), independently of the Git panel work;
|
|
7
|
+
> repairing those specs is this cycle's intended content.
|
|
8
|
+
> 0.3.19 is published to npm and tagged `v0.3.19`; 0.3.20 is not.
|
|
11
9
|
|
|
12
10
|
[中文说明](README.zh-CN.md) ·
|
|
13
11
|
[v0.3.7 plan](docs/plan/v0.3.7-left-rail-improvement-plan.md) ·
|
|
@@ -172,7 +170,7 @@ current development environments. Node 20 is upstream EOL and is no longer a v0.
|
|
|
172
170
|
After the immutable `0.3.5` npm receipt exists:
|
|
173
171
|
|
|
174
172
|
```bash
|
|
175
|
-
npm install -g @orion-agents/orion-code@0.3.
|
|
173
|
+
npm install -g @orion-agents/orion-code@0.3.20
|
|
176
174
|
orion --version
|
|
177
175
|
orion doctor
|
|
178
176
|
```
|
package/README.zh-CN.md
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
面向终端与浏览器、本地优先的目标驱动 Coding Agent。
|
|
4
4
|
|
|
5
|
-
> v0.3.19
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
> 裸仓库被当成「不是仓库」。已发布 npm 0.3.19 并打 tag `v0.3.19`。
|
|
5
|
+
> v0.3.20 候选版本:进行中。v0.3.19 那轮验证发现 Web E2E 套件自 v0.3.11(停靠栏 tab 改为
|
|
6
|
+
> rail 按钮)起就与产品脱节,与 Git 工作栏的工作无关;修好这些 spec 是本周期的目标。
|
|
7
|
+
> 0.3.19 已发布 npm 并打 tag `v0.3.19`,0.3.20 尚未发布。
|
|
9
8
|
|
|
10
9
|
[English](README.md) ·
|
|
11
10
|
[v0.3.7 方案](docs/plan/v0.3.7-left-rail-improvement-plan.md) ·
|
|
@@ -102,7 +101,7 @@ Current。Node 20 已结束上游维护,不再属于 v0.3 Runtime 合同。
|
|
|
102
101
|
当 npm 已存在不可变的 `0.3.4` 发布凭据后:
|
|
103
102
|
|
|
104
103
|
```bash
|
|
105
|
-
npm install -g @orion-agents/orion-code@0.3.
|
|
104
|
+
npm install -g @orion-agents/orion-code@0.3.20
|
|
106
105
|
orion --version
|
|
107
106
|
orion doctor
|
|
108
107
|
```
|
|
@@ -8,7 +8,23 @@ export declare const WEB_E2E_WEB31_SCENARIOS_V1: readonly ["WEB31-P0-01", "WEB31
|
|
|
8
8
|
export declare const WEB_E2E_WEB32_SCENARIOS_V1: readonly ["WEB32-P0-01", "WEB32-P0-02", "WEB32-P0-03", "WEB32-P0-04", "WEB32-P0-05", "WEB32-P0-06", "WEB32-P0-07", "WEB32-P0-08", "WEB32-P0-09", "WEB32-P0-10", "WEB32-P0-11", "WEB32-P0-12"];
|
|
9
9
|
export declare const WEB_E2E_WEB33_THEME_SCENARIOS_V1: readonly ["WEB33-P0-01", "WEB33-P0-02", "WEB33-P0-03", "WEB33-P0-04", "WEB33-P0-05", "WEB33-P0-06", "WEB33-P0-07", "WEB33-P0-08", "WEB33-P0-09", "WEB33-P0-10", "WEB33-P0-11", "WEB33-P0-12"];
|
|
10
10
|
export declare const WEB_E2E_WEB33_SESSION_SCENARIOS_V1: readonly ["WEB33-P0-16", "WEB33-P0-17", "WEB33-P0-18", "WEB33-P0-19", "WEB33-P0-20", "WEB33-P0-21", "WEB33-P0-22", "WEB33-P0-23", "WEB33-P0-24"];
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* v0.3.20 — the WEB33 scenarios whose specs shipped between v0.3.13 and
|
|
13
|
+
* v0.3.15 (rail, transcript navigator, brand, files editor, resource layout)
|
|
14
|
+
* and used these ids before they were registered. The receipts' exact
|
|
15
|
+
* coverage check requires every running id to be registered exactly once:
|
|
16
|
+
* WEB33-P0-16/17/18 belong to the session-concurrency journeys, so the
|
|
17
|
+
* v0.3.13 resource-layout specs were renumbered to P0-41/42/43.
|
|
18
|
+
*/
|
|
19
|
+
export declare const WEB_E2E_WEB33_RESOURCE_SCENARIOS_V1: readonly ["WEB33-P0-13", "WEB33-P0-14", "WEB33-P0-15", "WEB33-P0-25", "WEB33-P0-26", "WEB33-P0-27", "WEB33-P0-28", "WEB33-P0-29", "WEB33-P0-30", "WEB33-P0-31", "WEB33-P0-32", "WEB33-P0-34", "WEB33-P0-41", "WEB33-P0-42", "WEB33-P0-43"];
|
|
20
|
+
/**
|
|
21
|
+
* v0.3.15 — keyboard and shell surface journeys.
|
|
22
|
+
*/
|
|
23
|
+
export declare const WEB_E2E_WEB36_SCENARIOS_V1: readonly ["WEB36-P0-01", "WEB36-P1-01", "WEB36-P1-02", "WEB36-P1-03"];
|
|
24
|
+
/**
|
|
25
|
+
* v0.3.16 — transcript / workspace surface journeys.
|
|
26
|
+
*/
|
|
27
|
+
export declare const WEB_E2E_WEB37_SCENARIOS_V1: readonly ["WEB37-P0-01", "WEB37-P0-02", "WEB37-P0-03"];
|
|
12
28
|
/**
|
|
13
29
|
* v0.3.17 — LOCAL WORKSPACE open path. The picker is driven by a script file
|
|
14
30
|
* (`ORION_CODE_WEB_PICKER_FIXTURE`) so CI never opens a real Finder dialog.
|
|
@@ -21,6 +37,7 @@ export declare const WEB_E2E_WEB38_SCENARIOS_V1: readonly ["WEB38-P0-01", "WEB38
|
|
|
21
37
|
* actually verify; the per-stage unit suites are registered separately.
|
|
22
38
|
*/
|
|
23
39
|
export declare const WEB_E2E_WEB317_SCENARIOS_V1: readonly string[];
|
|
40
|
+
export declare const WEB_E2E_WEB33_SCENARIOS_V1: readonly ("WEB33-P0-01" | "WEB33-P0-02" | "WEB33-P0-03" | "WEB33-P0-04" | "WEB33-P0-05" | "WEB33-P0-06" | "WEB33-P0-07" | "WEB33-P0-08" | "WEB33-P0-09" | "WEB33-P0-10" | "WEB33-P0-11" | "WEB33-P0-12" | "WEB33-P0-16" | "WEB33-P0-17" | "WEB33-P0-18" | "WEB33-P0-19" | "WEB33-P0-20" | "WEB33-P0-21" | "WEB33-P0-22" | "WEB33-P0-23" | "WEB33-P0-24" | "WEB33-P0-13" | "WEB33-P0-14" | "WEB33-P0-15" | "WEB33-P0-25" | "WEB33-P0-26" | "WEB33-P0-27" | "WEB33-P0-28" | "WEB33-P0-29" | "WEB33-P0-30" | "WEB33-P0-31" | "WEB33-P0-32" | "WEB33-P0-34" | "WEB33-P0-41" | "WEB33-P0-42" | "WEB33-P0-43")[];
|
|
24
41
|
/**
|
|
25
42
|
* v0.3.19 — closing the v0.3.17 G317 assertion backlog.
|
|
26
43
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WEB_E2E_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB33_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB32_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB31_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_SETTINGS_SCENARIOS_V1 = exports.WEB_E2E_FULL_SCENARIOS_V1 = exports.WEB_E2E_WEB34_SCENARIOS_V1 = exports.WEB_E2E_WEB317_SCENARIOS_V1 = exports.WEB_E2E_WEB38_SCENARIOS_V1 = exports.
|
|
3
|
+
exports.WEB_E2E_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB33_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB32_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_WEB31_CRITICAL_SCENARIOS_V1 = exports.WEB_E2E_SETTINGS_SCENARIOS_V1 = exports.WEB_E2E_FULL_SCENARIOS_V1 = exports.WEB_E2E_WEB34_SCENARIOS_V1 = exports.WEB_E2E_WEB33_SCENARIOS_V1 = exports.WEB_E2E_WEB317_SCENARIOS_V1 = exports.WEB_E2E_WEB38_SCENARIOS_V1 = exports.WEB_E2E_WEB37_SCENARIOS_V1 = exports.WEB_E2E_WEB36_SCENARIOS_V1 = exports.WEB_E2E_WEB33_RESOURCE_SCENARIOS_V1 = exports.WEB_E2E_WEB33_SESSION_SCENARIOS_V1 = exports.WEB_E2E_WEB33_THEME_SCENARIOS_V1 = exports.WEB_E2E_WEB32_SCENARIOS_V1 = exports.WEB_E2E_WEB31_SCENARIOS_V1 = exports.WEB_E2E_LEGACY_SCENARIOS_V1 = exports.SUPPORTED_RELEASE_VERSION_LINE_V1 = exports.SUPPORTED_RELEASE_NODE_FLOORS_V1 = exports.SUPPORTED_RELEASE_NODE_MAJORS_V1 = exports.RELEASE_RECEIPT_VERSION_V1 = void 0;
|
|
4
4
|
exports.createTarballArtifactReceiptV1 = createTarballArtifactReceiptV1;
|
|
5
5
|
exports.verifyTarballArtifactReceiptV1 = verifyTarballArtifactReceiptV1;
|
|
6
6
|
exports.createRuntimeMatrixReceiptV1 = createRuntimeMatrixReceiptV1;
|
|
@@ -97,9 +97,47 @@ exports.WEB_E2E_WEB33_SESSION_SCENARIOS_V1 = Object.freeze([
|
|
|
97
97
|
'WEB33-P0-23',
|
|
98
98
|
'WEB33-P0-24',
|
|
99
99
|
]);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
/**
|
|
101
|
+
* v0.3.20 — the WEB33 scenarios whose specs shipped between v0.3.13 and
|
|
102
|
+
* v0.3.15 (rail, transcript navigator, brand, files editor, resource layout)
|
|
103
|
+
* and used these ids before they were registered. The receipts' exact
|
|
104
|
+
* coverage check requires every running id to be registered exactly once:
|
|
105
|
+
* WEB33-P0-16/17/18 belong to the session-concurrency journeys, so the
|
|
106
|
+
* v0.3.13 resource-layout specs were renumbered to P0-41/42/43.
|
|
107
|
+
*/
|
|
108
|
+
exports.WEB_E2E_WEB33_RESOURCE_SCENARIOS_V1 = Object.freeze([
|
|
109
|
+
'WEB33-P0-13',
|
|
110
|
+
'WEB33-P0-14',
|
|
111
|
+
'WEB33-P0-15',
|
|
112
|
+
'WEB33-P0-25',
|
|
113
|
+
'WEB33-P0-26',
|
|
114
|
+
'WEB33-P0-27',
|
|
115
|
+
'WEB33-P0-28',
|
|
116
|
+
'WEB33-P0-29',
|
|
117
|
+
'WEB33-P0-30',
|
|
118
|
+
'WEB33-P0-31',
|
|
119
|
+
'WEB33-P0-32',
|
|
120
|
+
'WEB33-P0-34',
|
|
121
|
+
'WEB33-P0-41',
|
|
122
|
+
'WEB33-P0-42',
|
|
123
|
+
'WEB33-P0-43',
|
|
124
|
+
]);
|
|
125
|
+
/**
|
|
126
|
+
* v0.3.15 — keyboard and shell surface journeys.
|
|
127
|
+
*/
|
|
128
|
+
exports.WEB_E2E_WEB36_SCENARIOS_V1 = Object.freeze([
|
|
129
|
+
'WEB36-P0-01',
|
|
130
|
+
'WEB36-P1-01',
|
|
131
|
+
'WEB36-P1-02',
|
|
132
|
+
'WEB36-P1-03',
|
|
133
|
+
]);
|
|
134
|
+
/**
|
|
135
|
+
* v0.3.16 — transcript / workspace surface journeys.
|
|
136
|
+
*/
|
|
137
|
+
exports.WEB_E2E_WEB37_SCENARIOS_V1 = Object.freeze([
|
|
138
|
+
'WEB37-P0-01',
|
|
139
|
+
'WEB37-P0-02',
|
|
140
|
+
'WEB37-P0-03',
|
|
103
141
|
]);
|
|
104
142
|
/**
|
|
105
143
|
* v0.3.17 — LOCAL WORKSPACE open path. The picker is driven by a script file
|
|
@@ -125,6 +163,11 @@ exports.WEB_E2E_WEB317_SCENARIOS_V1 = Object.freeze([
|
|
|
125
163
|
'WEB39-P0-04',
|
|
126
164
|
'WEB39-P0-05',
|
|
127
165
|
]);
|
|
166
|
+
exports.WEB_E2E_WEB33_SCENARIOS_V1 = Object.freeze([
|
|
167
|
+
...exports.WEB_E2E_WEB33_THEME_SCENARIOS_V1,
|
|
168
|
+
...exports.WEB_E2E_WEB33_SESSION_SCENARIOS_V1,
|
|
169
|
+
...exports.WEB_E2E_WEB33_RESOURCE_SCENARIOS_V1,
|
|
170
|
+
]);
|
|
128
171
|
/**
|
|
129
172
|
* v0.3.19 — closing the v0.3.17 G317 assertion backlog.
|
|
130
173
|
*
|
|
@@ -145,6 +188,8 @@ exports.WEB_E2E_FULL_SCENARIOS_V1 = Object.freeze([
|
|
|
145
188
|
...exports.WEB_E2E_WEB31_SCENARIOS_V1,
|
|
146
189
|
...exports.WEB_E2E_WEB32_SCENARIOS_V1,
|
|
147
190
|
...exports.WEB_E2E_WEB33_SCENARIOS_V1,
|
|
191
|
+
...exports.WEB_E2E_WEB36_SCENARIOS_V1,
|
|
192
|
+
...exports.WEB_E2E_WEB37_SCENARIOS_V1,
|
|
148
193
|
...exports.WEB_E2E_WEB38_SCENARIOS_V1,
|
|
149
194
|
...exports.WEB_E2E_WEB317_SCENARIOS_V1,
|
|
150
195
|
...exports.WEB_E2E_WEB34_SCENARIOS_V1,
|
|
@@ -358,10 +403,16 @@ function createWebE2EReleaseReceiptV1(input) {
|
|
|
358
403
|
status: input.liveCanary === 'FAIL' ? 'fail' : 'pass',
|
|
359
404
|
detail: `observed=${input.liveCanary}`,
|
|
360
405
|
});
|
|
406
|
+
// v0.3.20 — the run scenario ids are sorted by the evidence assembler; the
|
|
407
|
+
// registries concatenate their per-epoch groups in delivery order, so both
|
|
408
|
+
// sides are compared as sorted sets (order-sensitive comparison against the
|
|
409
|
+
// declared order rejected runs that covered exactly the registered ids).
|
|
410
|
+
const sortedFull = [...exports.WEB_E2E_FULL_SCENARIOS_V1].sort();
|
|
411
|
+
const sortedCritical = [...exports.WEB_E2E_CRITICAL_SCENARIOS_V1].sort();
|
|
361
412
|
const primaryCoverage = primaryRuns.length === 3 &&
|
|
362
|
-
primaryRuns.every(run => run.role === 'primary' && sameOrderedValues(run.scenarioIds,
|
|
413
|
+
primaryRuns.every(run => run.role === 'primary' && sameOrderedValues(run.scenarioIds, sortedFull));
|
|
363
414
|
const runtimeCoverage = runtimeRuns.length === exports.SUPPORTED_RELEASE_NODE_MAJORS_V1.length &&
|
|
364
|
-
runtimeRuns.every(run => run.role === 'runtime' && sameOrderedValues(run.scenarioIds,
|
|
415
|
+
runtimeRuns.every(run => run.role === 'runtime' && sameOrderedValues(run.scenarioIds, sortedCritical));
|
|
365
416
|
checks.push({
|
|
366
417
|
id: 'scenario_coverage',
|
|
367
418
|
status: primaryCoverage && runtimeCoverage ? 'pass' : 'fail',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as a,j as e,I as D,s as be,C as ye,W as ge}from"./index-
|
|
1
|
+
import{r as a,j as e,I as D,s as be,C as ye,W as ge}from"./index-D5ze0fOv.js";import{u as Ce,R as Ne}from"./useAutoNotice-Bsr8yfc3.js";function Le({workspaceId:s,refreshEpoch:o,actions:l,navigatorWidthPx:r,onNavigatorWidthCommit:d,revealRequest:c}){const[f,m]=a.useState({}),[x,j]=a.useState(new Set(["workspace-root"])),[i,N]=a.useState(null),[F,B]=a.useState(""),[M,G]=a.useState(null),[Y,P]=a.useState(!1),[H,K]=a.useState(""),{notice:J,showNotice:$,clearNotice:V}=Ce(),[T,ue]=a.useState(""),[Z,_]=a.useState({}),[I,A]=a.useState(""),[O,R]=a.useState("view"),[L,w]=a.useState(""),[k,q]=a.useState(!1),[de,S]=a.useState(!1),[fe,me]=a.useState(""),[he,W]=a.useState(!1),h=a.useRef(0),C=a.useRef(0),ee=a.useRef(null),E=async(t,n=!1,y=h.current)=>{if(y!==h.current)return;const p=f[t],g=n?p?.nextCursor:void 0;if(!(n&&!g)){m(u=>({...u,[t]:{items:p?.items??[],nextCursor:p?.nextCursor??null,revision:p?.revision??"",loading:!0}}));try{const u=await l.listFiles(t,g??void 0);if(y!==h.current)return;m(v=>({...v,[t]:{items:n?ke(v[t]?.items??[],u.items):u.items,nextCursor:u.nextCursor,revision:u.revision,loading:!1}}))}catch(u){if(y!==h.current)return;if(n&&U(u)){$("目录已变化,已重新载入第一页。"),E(t,!1,y);return}m(v=>({...v,[t]:{items:v[t]?.items??[],nextCursor:v[t]?.nextCursor??null,revision:v[t]?.revision??"",loading:!1,error:z(u)}}))}}},Q=async(t=h.current)=>{try{const n=await l.gitStatus();if(t!==h.current)return;_(Se(n)),A(n.nextCursor?"Git 装饰仅显示首批 200 个变更;在 Git 面板继续分页查看。":"")}catch(n){if(t!==h.current)return;_({}),A(`Git 状态装饰不可用:${z(n)}`)}},te=a.useRef(s);a.useEffect(()=>{const t=h.current+1;h.current=t,C.current+=1;const n=te.current===s?ee.current:null;te.current=s,m({}),j(new Set(["workspace-root"])),N(n),B(""),G(null),P(!1),K(""),V(),_({}),A(""),s&&(E("workspace-root",!1,t),Q(t),n&&b(n,!1,!1,t))},[o,s]);const se=a.useRef(null),b=async(t,n=!1,y=!1,p=h.current,g=C.current+1)=>{if(p===h.current&&!(!t.readable||t.sensitive||X(t))){C.current=g,N(t),K(""),n||(B(""),G(null),P(!1),R("view"),w(""),S(!1)),y||V();try{const u=await l.readFileContent(t.id,n?M??void 0:void 0);if(p!==h.current||g!==C.current)return;P(u.binary),B(v=>n?`${v}${u.content??""}`:u.content??""),G(u.nextCursor),me(u.revision),y&&$("文件已变化,已从第一页重新载入。")}catch(u){if(p!==h.current||g!==C.current)return;if(n&&U(u)){await b(t,!1,!0,p,g);return}K(z(u))}}},re=De({selected:i,binary:Y,hasMorePages:M!==null}),xe=()=>{w(F),S(!1),R("edit")},ie=()=>{if(L!==F){W(!0);return}ne()},ne=()=>{R("view"),w(""),S(!1),W(!1)},je=async()=>{if(!(!i||k)){q(!0),S(!1);try{await l.writeFileContent(i.id,L,fe),R("view"),w(""),await b(i,!1,!0,h.current,C.current+1),$("已保存文件。","success"),Q()}catch(t){U(t)?S(!0):$(z(t),"error")}finally{q(!1)}}},ae=t=>{const n=new Set(x);n.has(t)?n.delete(t):(n.add(t),f[t]||E(t)),j(n)};a.useEffect(()=>{c&&se.current!==c.id&&(se.current=c.id,b({id:c.fileId,name:c.displayPath.split("/").pop()??c.displayPath,displayPath:c.displayPath,kind:"file",modifiedAt:new Date().toISOString(),sensitive:!1,readable:!0}))},[c?.id]),a.useEffect(()=>{ee.current=i},[i]);const pe=a.useMemo(()=>Object.values(f).flatMap(t=>t.items),[f]),oe=T.trim()?pe.filter(t=>t.name.toLocaleLowerCase().includes(T.toLocaleLowerCase())):null,ve=!!f["workspace-root"]?.loading;return e.jsxs("div",{className:"work-resource-panel files-panel",children:[e.jsxs("div",{className:"resource-toolbar",children:[e.jsxs("label",{className:"resource-search",children:[e.jsx("span",{className:"sr-only",children:"搜索已加载文件"}),e.jsx(D,{name:"search",size:16}),e.jsx("input",{type:"search",value:T,onChange:t=>ue(t.target.value),placeholder:"搜索已加载文件",title:"搜索仅覆盖已加载的目录和文件"})]}),e.jsx("button",{type:"button",className:"icon-button","aria-label":"刷新文件树","aria-busy":ve,onClick:()=>{E("workspace-root"),Q()},children:e.jsx(D,{name:"refresh",size:16})})]}),e.jsxs(Ne,{panelId:"files",navigatorWidthPx:r,onNavigatorWidthCommit:d,contentLabel:"文件预览",navigatorLabel:"工作区文件",handleLabel:"调整文件目录宽度",contentClassName:"file-preview",navigatorClassName:"file-tree",children:[e.jsxs(e.Fragment,{children:[I?e.jsx("p",{className:"resource-hint",role:"status",children:I}):null,oe?e.jsx(e.Fragment,{children:e.jsx("ul",{role:"list",className:"file-node-list search-results",children:oe.map(t=>e.jsx(ce,{node:t,depth:0,expanded:!1,selected:i?.id===t.id,gitLabels:Z[t.displayPath]??[],onToggle:ae,onSelect:n=>{b(n)}},t.id))})}):e.jsx(le,{parentId:"workspace-root",depth:0,directories:f,expanded:x,selectedId:i?.id,gitDecorations:Z,onToggle:ae,onSelect:t=>{b(t)},onLoadMore:t=>{E(t,!0)}})]}),e.jsxs(e.Fragment,{children:[J?e.jsx("p",{className:"resource-notice",role:"status",children:J.text}):null,i?e.jsxs(e.Fragment,{children:[e.jsxs("header",{children:[e.jsx("strong",{children:i.name}),e.jsx("span",{children:Fe(i.sizeBytes??0)})]}),H?e.jsx("p",{className:"resource-error",role:"alert",children:H}):Y?e.jsxs("div",{className:"resource-empty",children:[e.jsx(D,{name:"code",size:16}),e.jsx("strong",{title:"出于安全和性能考虑,只显示元数据。",children:"二进制文件"})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"file-preview-actions",children:O==="view"?e.jsx("button",{type:"button",className:"text-button",disabled:!re,title:re?void 0:"仅支持编辑 512 KB 内的 UTF-8 文本文件",onClick:xe,children:"编辑"}):e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"primary-button",disabled:k||L===F,"aria-busy":k,onClick:()=>{je()},children:k?"保存中…":"保存"}),e.jsx("button",{type:"button",className:"text-button",disabled:k,onClick:ie,children:"取消"})]})}),de?e.jsxs("p",{className:"resource-error",role:"alert",children:["文件已在别处变更,保存被拒绝。",e.jsx("button",{type:"button",className:"text-button",onClick:()=>{b(i,!1,!0)},children:"重新加载"})]}):null,O==="edit"?e.jsx("textarea",{className:"file-editor",value:L,spellCheck:!1,"aria-label":`编辑文件 ${i.name}`,onChange:t=>w(t.target.value),onKeyDown:t=>{t.key==="Escape"&&(t.preventDefault(),ie())}}):e.jsx("pre",{tabIndex:0,className:"file-code-view","aria-label":`文件内容 ${i.name}`,children:be(F)})]}),M&&O==="view"?e.jsx("button",{type:"button",className:"secondary-button",onClick:()=>{b(i,!0)},children:"加载更多内容"}):null]}):e.jsxs("div",{className:"resource-empty",children:[e.jsx(D,{name:"workspace",size:16}),e.jsx("strong",{children:"选择文件预览"}),e.jsx("p",{title:"敏感文件、工作区外链接和二进制正文不会返回浏览器。",children:"受限内容不会返回浏览器。"})]})]})]}),e.jsx(ye,{open:he,onClose:()=>W(!1),title:"放弃未保存的修改?",body:"当前草稿尚未保存,放弃后将回到文件的最新内容。",confirmLabel:"放弃修改",danger:!0,onConfirm:ne})]})}function le({parentId:s,depth:o,directories:l,expanded:r,selectedId:d,gitDecorations:c,onToggle:f,onSelect:m,onLoadMore:x}){const j=l[s];return j?j.error?e.jsx("p",{className:"resource-error",role:"alert",children:j.error}):e.jsxs("ul",{role:"list",className:"file-node-list",children:[j.items.map(i=>{const N=r.has(i.id);return e.jsxs("li",{children:[e.jsx(ce,{node:i,depth:o,expanded:N,selected:d===i.id,gitLabels:c[i.displayPath]??[],onToggle:f,onSelect:m}),X(i)&&N?e.jsx(le,{parentId:i.id,depth:o+1,directories:l,expanded:r,selectedId:d,gitDecorations:c,onToggle:f,onSelect:m,onLoadMore:x}):null]},i.id)}),j.loading?e.jsx("li",{className:"resource-loading",children:"正在读取…"}):null,j.nextCursor?e.jsx("li",{children:e.jsx("button",{type:"button",className:"text-button",onClick:()=>x(s),children:"加载更多"})}):null]}):e.jsx("p",{className:"resource-loading",children:"正在读取…"})}function ce({node:s,depth:o,expanded:l,selected:r,gitLabels:d,onToggle:c,onSelect:f}){const m=s.sensitive||!s.readable,x=X(s);return e.jsxs("button",{type:"button",className:`file-node ${r?"selected":""} ${m?"blocked":""}`,style:{paddingInlineStart:`${8+o*15}px`},"aria-expanded":x?l:void 0,"aria-label":`${we(s)} ${s.name}${m?",不可读取":""}${d.length?`,Git ${d.join("、")}`:""}`,onClick:()=>x?c(s.id):f(s),disabled:m,children:[e.jsx(D,{name:x?"workspace":"code",size:16}),e.jsx("span",{children:s.name}),s.kind==="symlink"?e.jsx("small",{children:"链接"}):null,s.sensitive?e.jsx("small",{children:"敏感"}):null,d.length?e.jsx("small",{className:"file-git-status",title:`Git ${d.join("、")}`,children:d.join(" · ")}):null]})}function we(s){return s.kind==="directory"?"目录":s.kind==="symlink"?s.targetKind==="directory"?"符号链接目录":"符号链接":"文件"}function X(s){return s.kind==="directory"||s.kind==="symlink"&&s.targetKind==="directory"}function ke(s,o){const l=new Map(s.map(r=>[r.id,r]));for(const r of o)l.set(r.id,r);return[...l.values()]}function Se(s){if(!s.hasWorktree)return{};const o=new Map,l=(r,d)=>{const c=r.replace(/\\/gu,"/").replace(/^\.\//u,"");if(!c)return;const f=o.get(c)??new Set;f.add(d),o.set(c,f);const m=c.split("/");for(let x=1;x<m.length;x+=1){const j=m.slice(0,x).join("/"),i=o.get(j)??new Set;i.add("含变更"),o.set(j,i)}};return s.conflicted.forEach(r=>l(r.path,"冲突")),s.staged.forEach(r=>l(r.path,"已暂存")),s.unstaged.forEach(r=>l(r.path,"未暂存")),s.untracked.forEach(r=>l(r.path,"未跟踪")),Object.fromEntries([...o].map(([r,d])=>[r,Object.freeze([...d])]))}const Ee=512*1024;function De(s){const{selected:o,binary:l,hasMorePages:r}=s;return!o||l||o.sensitive||!o.readable||r?!1:(o.sizeBytes??0)<=Ee}function Fe(s){return s<1024?`${s} B`:s<1048576?`${(s/1024).toFixed(1)} KB`:`${(s/1048576).toFixed(1)} MB`}function U(s){return s instanceof ge&&s.code==="file_revision_conflict"}function z(s){return s instanceof Error?s.message:"文件请求失败。"}export{Ee as FILE_EDIT_MAX_BYTES,Le as FilesPanel,De as canEditFileContent};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var $e=Object.defineProperty;var Pe=(t,s,n)=>s in t?$e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[s]=n;var ie=(t,s,n)=>Pe(t,typeof s!="symbol"?s+"":s,n);import{r as l,a as He,j as e,I as T}from"./index-DYeu_rs7.js";import{u as Oe,R as Me}from"./useAutoNotice-h7c0Iz1E.js";const Ne="orion.web.git-display.v1",_e=Object.freeze(["changes","history","compare"]),me=Object.freeze({message:"",author:"",path:"",sha:"",since:"",until:""}),xe=Object.freeze({view:"changes",group:null,query:"",selectedFileId:null,selectedSource:null,selectedFileIds:Object.freeze([]),selectedLineIds:Object.freeze([]),collapsedHunks:Object.freeze([]),anchorLineId:null,navigatorScrollTop:0,commitDraft:Object.freeze({summary:"",body:""}),historyQuery:me,selectedCommitId:null,selectedCommitParentIndex:0,selectedCommitPath:null,fileHistoryPath:null,notice:""}),pe=Object.freeze({mode:"unified",wrap:!1,showWhitespace:!1,ignoreWhitespace:!1,wordDiff:!1});function Ae(t){return t||"__no-workspace__"}function ze(){const t=new Map;return{read(s){return t.get(s)??xe},update(s,n){const i=Object.freeze({...t.get(s)??xe,...n});return t.set(s,i),i},clear(s){t.delete(s)}}}const Be=ze();function Ge(){try{const t=globalThis.localStorage?.getItem(Ne);if(!t)return pe;const s=JSON.parse(t);return Te(s)}catch{return pe}}function We(t){try{globalThis.localStorage?.setItem(Ne,JSON.stringify(t))}catch{}}function Te(t){if(typeof t!="object"||t===null)return pe;const s=t;return Object.freeze({mode:s.mode==="side-by-side"?"side-by-side":"unified",wrap:s.wrap===!0,showWhitespace:s.showWhitespace===!0,ignoreWhitespace:s.ignoreWhitespace===!0,wordDiff:s.wordDiff===!0})}function qe(t){if(t.entries.length===0)return{fileId:null,path:null,notice:""};const s=t.entries.find(o=>o.fileId===t.previousFileId);if(s)return{fileId:s.fileId,path:s.path,notice:""};const i=t.entries.find(o=>o.path===t.previousPath)??t.entries[0];return{fileId:i.fileId,path:i.path,notice:t.previousFileId===null?"":`原选中的改动已不在此列表,已跳到 ${i.path}。`}}const Qe=959,Ve=620,Ke=640;function Ue(t,s){if(!Number.isFinite(t)||t<=0)return{tier:"wide",narrow:!1,effectiveMode:s,dataWidth:"wide"};const n=t<=Ve?"narrow":t<=Qe?"compact":"wide";return{tier:n,narrow:n==="narrow",effectiveMode:t<=Ke?"unified":s,dataWidth:n}}const Ye=350,je=30;function Xe(t){const{enabled:s,session:n,setSession:i,actions:o,refreshEpoch:h}=t,g=n.historyQuery??me,[x,a]=l.useState(null),[p,j]=l.useState(null),[b,d]=l.useState(null),[S,u]=l.useState(null),[_,L]=l.useState(null),[v,N]=l.useState(null),[Q,P]=l.useState(!1),[B,E]=l.useState(!1),[q,H]=l.useState(!1),[k,R]=l.useState(""),$=l.useRef(0),r=l.useRef(0),I=l.useMemo(()=>({...g.message.trim()?{message:g.message.trim()}:{},...g.author.trim()?{author:g.author.trim()}:{},...g.path.trim()?{path:g.path.trim()}:{},...g.sha.trim()?{sha:g.sha.trim()}:{},...g.since.trim()?{since:g.since.trim()}:{},...g.until.trim()?{until:g.until.trim()}:{}}),[g]);l.useEffect(()=>{if(!s)return;const w=$.current+1;$.current=w,P(!0),R("");const A=setTimeout(()=>{(async()=>{try{const[z,W]=await Promise.all([o.gitRefs(),o.gitHistory({...I,pageSize:je})]);if(w!==$.current)return;a(z),j(W)}catch(z){if(w!==$.current)return;R(le(z))}finally{w===$.current&&P(!1)}})()},I.message||I.author||I.path||I.sha?Ye:0);return()=>clearTimeout(A)},[o,s,h,I]),l.useEffect(()=>{const w=n.selectedCommitId;if(!s||!w){d(null),u(null),L(null);return}const A=r.current+1;r.current=A;const z=n.selectedCommitParentIndex;H(!0),R(""),(async()=>{try{const[W,X]=await Promise.all([o.gitCommitDetail(w,z),o.gitCommitFiles(w,z)]);if(A!==r.current)return;d(W),u(X);const J=X.files.find(U=>!U.sensitive&&!U.binary),ee=n.selectedCommitPath&&X.files.some(U=>U.path===n.selectedCommitPath)?n.selectedCommitPath:J?.path??null;ee!==n.selectedCommitPath&&i({selectedCommitPath:ee}),ee||L(null)}catch(W){if(A!==r.current)return;R(le(W))}finally{A===r.current&&H(!1)}})()},[o,s,n.selectedCommitId,n.selectedCommitParentIndex]),l.useEffect(()=>{const w=n.selectedCommitId,A=n.selectedCommitPath;if(!s||!w||!A){L(null);return}const z=r.current;(async()=>{try{const W=await o.gitCommitDiff({oid:w,path:A,parentIndex:n.selectedCommitParentIndex});if(z!==r.current)return;L(W)}catch(W){if(z!==r.current)return;R(le(W)),L(null)}})()},[o,s,n.selectedCommitId,n.selectedCommitPath,n.selectedCommitParentIndex]),l.useEffect(()=>{const w=n.fileHistoryPath;if(!s||!w){N(null);return}const A=r.current;(async()=>{try{const z=await o.gitFileHistory({path:w});if(A!==r.current)return;N(z)}catch(z){if(A!==r.current)return;R(le(z))}})()},[o,s,n.fileHistoryPath]);const f=l.useCallback(w=>{i({historyQuery:{...g,...w}})},[g,i]),V=l.useCallback(()=>{i({historyQuery:me})},[i]),c=l.useCallback(w=>{i({selectedCommitId:w.id,selectedCommitParentIndex:0,selectedCommitPath:null})},[i]),M=l.useCallback(()=>{i({selectedCommitId:null,selectedCommitPath:null,selectedCommitParentIndex:0})},[i]),G=l.useCallback(w=>{i({selectedCommitParentIndex:w,selectedCommitPath:null})},[i]),K=l.useCallback(w=>i({selectedCommitPath:w}),[i]),Y=l.useCallback(()=>{const w=p?.nextCursor;if(!w||B)return;const A=$.current;E(!0),(async()=>{try{const z=await o.gitHistory({...I,cursor:w,pageSize:je});if(A!==$.current)return;j(W=>W?{...z,items:[...W.items,...z.items]}:z)}catch(z){if(A!==$.current)return;R(le(z))}finally{A===$.current&&E(!1)}})()},[o,B,p,I]),se=l.useCallback(w=>i({fileHistoryPath:w}),[i]),D=l.useCallback(()=>i({fileHistoryPath:null}),[i]);return{query:g,refs:x,page:p,detail:b,files:S,diff:_,fileHistory:v,loading:Q,loadingMore:B,loadingDetail:q,error:k,isEmptyRepository:p!==null&&p.tipOid===null,setQuery:f,resetQuery:V,selectCommit:c,closeDetail:M,setParentIndex:G,selectFile:K,loadMore:Y,openFileHistory:se,closeFileHistory:D}}function le(t){return t?.code==="git_cursor_invalid"?"历史已变化,已重新载入列表。":t instanceof Error?t.message:"Git 历史读取失败。"}function Je(t){if(!(t instanceof HTMLElement))return!1;const s=t.tagName.toLowerCase();return s==="input"||s==="textarea"||s==="select"||t.isContentEditable?!0:t.closest('[role="dialog"]')!==null}function Ze(t){const{enabled:s,session:n,setSession:i,fileIds:o,anchorLineIds:h,onOpenSelection:g,onEscapeFallback:x}=t;l.useEffect(()=>{if(!s)return;const a=p=>{if(Je(p.target))return;if(p.key==="F7"&&h.length>0){p.preventDefault();const b=n.anchorLineId?h.indexOf(n.anchorLineId):-1,d=p.shiftKey?-1:1,S=b<0?d>0?0:h.length-1:Math.min(h.length-1,Math.max(0,b+d));i({anchorLineId:h[S]});return}if(p.key==="Escape"){if(n.query){p.preventDefault(),i({query:"",selectedFileId:null});return}if(n.selectedLineIds.length>0){p.preventDefault(),i({selectedLineIds:[]});return}x();return}if(o.length===0)return;const j=n.selectedFileId?o.indexOf(n.selectedFileId):-1;if(p.key==="ArrowDown"||p.key==="ArrowUp"){p.preventDefault();const b=p.key==="ArrowDown"?1:-1,d=j<0?b>0?0:o.length-1:Math.min(o.length-1,Math.max(0,j+b));i({selectedFileId:o[d],selectedSource:null,anchorLineId:null});return}if(p.key==="Enter"&&j>=0){p.preventDefault(),g();return}if(p.key===" "){if(j<0)return;p.preventDefault();const b=o[j];i({selectedFileIds:n.selectedFileIds.includes(b)?n.selectedFileIds.filter(d=>d!==b):[...n.selectedFileIds,b]})}};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[s,n.query,n.selectedFileId,n.selectedLineIds,n.anchorLineId,n.selectedFileIds,i,o,h,g,x])}class et{constructor(s){ie(this,"fetcher");ie(this,"freshnessMs");ie(this,"slots",new Map);this.fetcher=s.fetcher,this.freshnessMs=s.freshnessMs??3e4}getSnapshot(s){const n=this.slotFor(s);n.invalidated&&(n.inFlight=null,n.invalidated=!1);const i=n.snapshot;if(i&&Date.now()-i.fetchedAt<=this.freshnessMs)return Promise.resolve(i);if(n.inFlight)return n.inFlight;n.generation+=1;const o=n.generation,h=this.fetcher(s).then(g=>{const x=this.slots.get(s);if(!x||x.generation!==o||x.invalidated)throw new tt(s);return x.snapshot=Object.freeze({...g,fetchedAt:Date.now()}),x.inFlight=null,x.snapshot}).catch(g=>{const x=this.slots.get(s);throw x&&x.inFlight===h&&(x.inFlight=null),g});return n.inFlight=h,h}invalidate(s){const n=this.slots.get(s);if(!n)return!1;const i=!!(n.snapshot||n.inFlight);return n.invalidated=!0,n.snapshot=null,i}isStale(s,n){const i=this.slots.get(s)?.snapshot;return i?n==null?!1:i.repositoryRevision!==n:!0}cachedSnapshot(s){const n=this.slots.get(s);return!n||n.invalidated||!n.snapshot?null:n.snapshot}clear(){this.slots.clear()}slotFor(s){const n=this.slots.get(s);if(n)return n;const i={workspaceId:s,snapshot:null,inFlight:null,generation:0,invalidated:!1};return this.slots.set(s,i),i}}class tt extends Error{constructor(n){super(`Repository snapshot for ${n} is stale; refetching.`);ie(this,"code","workspace_snapshot_stale")}}const st=20*1024*1024,nt=5*1024*1024;function it(t){let s=0;for(const n of t.hunks){s+=n.header.length;for(const i of n.lines)s+=i.raw.length+48}return s+t.path.length+256}function lt(t){const s=st,n=nt,i=new Map;let o=0,h=0,g=0;const x=(a,p)=>`${a}\0${p}`;return{read(a,p){const j=x(a,p),b=i.get(j);return b?(i.delete(j),i.set(j,b),h+=1,b.document):(g+=1,null)},write(a,p,j){const b=it(j);if(b>n)return;const d=x(a,p),S=i.get(d);for(S&&(i.delete(d),o-=S.bytes),i.set(d,{document:j,bytes:b}),o+=b;o>s&&i.size>0;){const u=i.keys().next();if(u.done)break;const _=i.get(u.value);i.delete(u.value),o-=_?.bytes??0}},clear(){i.clear(),o=0},stats(){return{entries:i.size,bytes:o,hits:h,misses:g}}}}const at=lt(),rt=2e3;function ct(t){const{workspaceId:s,refreshEpoch:n,actions:i}=t,o=t.store??Be,h=t.cache??at,g=Ae(s),[x,a]=l.useState(()=>o.read(g)),[p,j]=l.useState(()=>Ge()),[b,d]=l.useState(null),[S,u]=l.useState(null),[_,L]=l.useState(null),[v,N]=l.useState(!1),[Q,P]=l.useState(!1),[B,E]=l.useState(""),[q,H]=l.useState(!1),k=l.useRef(0),R=l.useRef(0),$=l.useRef(x);$.current=x;const r=l.useRef(b),I=l.useRef(p);I.current=p,r.current=b;const f=l.useCallback(m=>{a(o.update(g,m))},[g,o]),V=l.useCallback(m=>{j(y=>{const F=Object.freeze({...y,...m});return We(F),F})},[]),c=l.useCallback(async(m,y)=>{if(m===k.current){y.quiet?P(!0):N(!0),E("");try{const F=$.current,[C,O]=await Promise.all([i.gitStatus(void 0,{...F.group?{group:F.group}:{},...F.query?{query:F.query}:{}}),i.gitLog()]);if(m!==k.current)return;if(d(C),u(O),!C.hasWorktree){L(null),H(!1);return}const ne=ue(C);if(!y.keepSelection){L(null),f({selectedFileId:null,selectedSource:null,anchorLineId:null}),H(!1);return}const ae=F.selectedFileId,Re=ne.find(de=>de.fileId===ae)?.path??(_?_.path:null),oe=qe({entries:ne,previousFileId:ae,previousPath:Re});if(oe.fileId&&oe.fileId!==ae){f({selectedFileId:null,selectedSource:null,notice:oe.notice}),L(null),H(!1);return}if(ae){const de=_!==null&&C.repositoryRevision===_.repositoryRevision;H(!de)}else H(!1)}catch(F){if(m!==k.current)return;E(Z(F))}finally{m===k.current&&(N(!1),P(!1))}}},[i,_,f]),M=l.useCallback(()=>{const m=k.current+1;k.current=m,R.current+=1,c(m,{keepSelection:!0,quiet:b!==null})},[c,b]);l.useEffect(()=>{const m=k.current+1;k.current=m,R.current+=1,d(null),u(null),L(null),E(""),H(!1),N(!!s),a(o.read(g)),s?c(m,{keepSelection:!1}):N(!1)},[g,s,o]),l.useEffect(()=>{if(!s||n===0)return;const m=k.current+1;k.current=m,R.current+=1,c(m,{keepSelection:!0,quiet:!0})},[n]),l.useEffect(()=>{if(!s||typeof document>"u")return;let m;const y=()=>{m!==void 0&&clearInterval(m),m=void 0},F=()=>{y(),m=setInterval(()=>{const O=k.current+1;k.current=O,c(O,{keepSelection:!0,quiet:!0})},rt)},C=()=>{if(document.visibilityState==="visible"){const O=k.current+1;k.current=O,c(O,{keepSelection:!0,quiet:!0}),F()}else y()};return document.visibilityState==="visible"&&F(),document.addEventListener("visibilitychange",C),()=>{y(),document.removeEventListener("visibilitychange",C)}},[s,x.group,x.query]);const G=l.useCallback(m=>{const y=R.current+1;R.current=y,f({selectedLineIds:[],selectedFileId:m.fileId,selectedSource:m.source,anchorLineId:null,notice:""}),E("");const F=r.current?.repositoryRevision,C=F?h.read(F,m.fileId):null;if(C){L(C),H(!1),N(!1);return}L(null),N(!0),(async()=>{try{const O=await i.gitDiffDocument(m.fileId,void 0,I.current.ignoreWhitespace,I.current.wordDiff);if(y!==R.current)return;h.write(O.repositoryRevision,m.fileId,O),L(O),H(O.repositoryRevision!==r.current?.repositoryRevision)}catch(O){if(y!==R.current)return;if(ut(O)){E("仓库已变化,已重新载入 Git 状态。"),f({selectedFileId:null,selectedSource:null});return}E(Z(O))}finally{y===R.current&&N(!1)}})()},[i,h,f]),K=l.useCallback(()=>{const m=b?.nextCursor;if(!m)return;const y=k.current,F=b?.repositoryRevision;(async()=>{try{const C=await i.gitStatus(m,{...x.group?{group:x.group}:{},...x.query?{query:x.query}:{}});if(y!==k.current)return;if(F!==void 0&&C.repositoryRevision!==F){E("仓库已变化,已重新载入 Git 状态。");return}d(O=>O&&{...C,conflicted:re(O.conflicted,C.conflicted),staged:re(O.staged,C.staged),unstaged:re(O.unstaged,C.unstaged),untracked:re(O.untracked,C.untracked),counts:{...C.counts,loaded:O.counts.loaded+C.counts.loaded}})}catch(C){if(y!==k.current)return;E(Z(C))}})()},[i,x.group,x.query,b]),Y=l.useCallback(()=>{const m=S?.nextCursor;if(!m)return;const y=k.current;(async()=>{try{const F=await i.gitLog(m);if(y!==k.current)return;u(C=>C&&{...F,items:dt(C.items,F.items)})}catch(F){if(y!==k.current)return;E(Z(F))}})()},[i,S]),se=l.useCallback(()=>{const m=_?.nextCursor,y=x.selectedFileId;if(!m||!y)return;const F=k.current,C=R.current;(async()=>{try{const O=await i.gitDiffDocument(y,m,I.current.ignoreWhitespace,I.current.wordDiff);if(F!==k.current||C!==R.current)return;L(ne=>ne?{...O,hunks:[...ne.hunks,...O.hunks]}:O)}catch(O){if(F!==k.current||C!==R.current)return;E(Z(O))}})()},[i,_,x.selectedFileId]);l.useEffect(()=>{!b||!x.selectedFileId||ue(b).some(y=>y.fileId===x.selectedFileId)||(L(null),f({selectedFileId:null,selectedSource:null,anchorLineId:null}))},[b,x.selectedFileId,f]);const D=l.useMemo(()=>!b||!x.selectedFileId?null:ue(b).find(m=>m.fileId===x.selectedFileId)??null,[b,x.selectedFileId]),[w,A]=l.useState(!1),[z,W]=l.useState(null),X=l.useRef(null);X.current===null&&(X.current=new et({fetcher:async m=>{const y=await i.gitStatus(void 0,{});return Object.freeze({repositoryRevision:y.repositoryRevision,branch:y.branch,counts:Object.freeze({totalChangedFiles:y.counts.total,staged:y.counts.staged,unstaged:y.counts.unstaged,untracked:y.counts.untracked,conflicted:y.counts.conflicted}),fetchedAt:Date.now()})}}));const J=X.current,ee=l.useCallback(async()=>{const m=r.current;if(m?.hasWorktree)try{if((await J.getSnapshot(s)).repositoryRevision===m.repositoryRevision)return;J.invalidate(s),await c(k.current,{keepSelection:!0,quiet:!0})}catch{}},[c,J,s]);l.useEffect(()=>{if(!s)return;let m=!1;const y=()=>{m||document.hidden||(m=!0,ee().finally(()=>{m=!1}))},F=()=>{document.hidden||y()};return window.addEventListener("focus",y),document.addEventListener("visibilitychange",F),()=>{window.removeEventListener("focus",y),document.removeEventListener("visibilitychange",F)}},[ee,s]);const U=l.useCallback(async()=>{h.clear(),J.invalidate(s);const m=k.current+1;k.current=m,R.current+=1,await c(m,{keepSelection:!0,quiet:!0})},[h,c,J,s]),te=l.useCallback(async(m,y)=>{if(!w){A(!0),E("");try{await m(),await U(),f({notice:y})}catch(F){E(Z(F))}finally{A(!1)}}},[w,U,f]),Ce=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&(await te(()=>i.gitStage(m,y),m.length>1?`已暂存 ${m.length} 个文件。`:"已暂存。"),f({selectedFileIds:[]}))},[i,te,f]),we=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&(await te(()=>i.gitUnstage(m,y),m.length>1?`已取消暂存 ${m.length} 个文件。`:"已取消暂存。"),f({selectedFileIds:[]}))},[i,te,f]),Fe=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&await te(()=>i.gitApplyPatch({...m,expectedRepositoryRevision:y}),"已应用所选改动到索引。")},[i,te]),Le=l.useCallback(async m=>{const y=r.current?.repositoryRevision;if(!y)throw new Error("Git repository is unavailable.");A(!0),E("");const F=He();try{const C=await i.gitCommit({summary:m.summary,...m.body?{body:m.body}:{},expectedRepositoryRevision:y,requestId:F});return await U(),f({commitDraft:{summary:"",body:""},notice:C.warning?`已提交 ${C.commitSha.slice(0,8)},但:${C.warning}`:`已提交 ${C.commitSha.slice(0,8)}。`}),C.commitSha}catch(C){throw E(Z(C)),C}finally{A(!1)}},[i,U,f]),De=l.useCallback(m=>{const y=$.current.selectedFileIds;f({selectedFileIds:y.includes(m)?y.filter(F=>F!==m):[...y,m]})},[f]),Ee=l.useCallback(()=>f({selectedFileIds:[]}),[f]);return l.useEffect(()=>{if(!b?.hasWorktree){W(null);return}let m=!1;return(async()=>{try{const y=await i.gitCommitPreview();m||W(y)}catch{m||W(null)}})(),()=>{m=!0}},[i,b?.hasWorktree,b?.repositoryRevision]),{session:x,display:p,status:b,log:S,diff:_,loading:v,refreshing:Q,error:B,stale:q,setSession:f,setDisplay:V,openFile:G,reload:M,loadMoreStatus:K,loadMoreLog:Y,loadMoreDiff:se,selectedEntry:D,busy:w,commitPreview:z,toggleSelection:De,clearSelection:Ee,stagePaths:Ce,unstagePaths:we,applyPatch:Fe,commit:Le}}function ue(t){return[...t.conflicted,...t.unstaged,...t.staged,...t.untracked]}function ot(t,s){return s==="conflict"?t.conflicted:s==="unstaged"?t.unstaged:s==="staged"?t.staged:t.untracked}function re(t,s){const n=new Map(t.map(i=>[i.fileId,i]));for(const i of s)n.set(i.fileId,i);return[...n.values()]}function dt(t,s){const n=new Map(t.map(i=>[i.id,i]));for(const i of s)n.set(i.id,i);return[...n.values()]}function Z(t){return t instanceof Error?t.message:"Git 请求失败。"}function ut(t){return typeof t=="object"&&t!==null&&t.code==="git_revision_conflict"}function ht(t){const s=[];let n=0;const i=t.lines;for(;n<i.length;){const o=i[n];if(o.kind==="deletion"){const h=[];for(;n<i.length&&i[n].kind==="deletion";)h.push(i[n]),n+=1;const g=[];for(;n<i.length&&i[n].kind==="addition";)g.push(i[n]),n+=1;const x=Math.max(h.length,g.length);for(let a=0;a<x;a+=1){const p=h[a]??null,j=g[a]??null;s.push(Object.freeze({key:`${t.hunkId}:${p?.lineId??`-${a}`}:${j?.lineId??`-${a}`}`,left:p,right:j,changed:!0}))}continue}if(o.kind==="addition"){s.push(Object.freeze({key:`${t.hunkId}:${o.lineId}`,left:null,right:o,changed:!0})),n+=1;continue}s.push(Object.freeze({key:`${t.hunkId}:${o.lineId}`,left:o,right:o,changed:!1})),n+=1}return s}function ft(t,s,n){const i=new Set(s),o=[];for(const h of t){if(o.push(Object.freeze({kind:"hunk-header",hunk:h})),i.has(h.hunkId)){o.push(Object.freeze({kind:"folded",hunk:h}));continue}if(n==="side-by-side"){for(const g of ht(h))o.push(Object.freeze({kind:"side-by-side",hunk:h,row:g}));continue}for(const g of h.lines)o.push(Object.freeze({kind:"unified-line",hunk:h,line:g}))}return o}function ve(t){const s=[];for(const n of t){let i=!1;for(const o of n.lines){const h=o.kind==="addition"||o.kind==="deletion";h&&!i&&s.push(Object.freeze({lineId:o.lineId,hunkId:n.hunkId,oldLineNumber:o.oldLineNumber,newLineNumber:o.newLineNumber})),i=h}}return s}function mt(t,s,n=500){const i=s.trim().toLowerCase();if(!i)return[];const o=[];for(const h of t)for(const g of h.lines){if(o.length>=n)return o;g.text.toLowerCase().includes(i)&&o.push(Object.freeze({lineId:g.lineId,hunkId:h.hunkId,side:g.oldLineNumber!==null&&g.newLineNumber!==null?"both":g.oldLineNumber!==null?"old":"new"}))}return o}function pt(t){let s=0,n=0;for(const i of t)for(const o of i.lines)o.kind==="addition"?s+=1:o.kind==="deletion"&&(n+=1);return Object.freeze({additions:s,deletions:n,hunks:t.length})}function ce(t,s){return s?t.replace(/\t/gu,"→ ").replace(/ +$/gu,n=>"·".repeat(n.length)):t}function ge(t){return t==="addition"?"+":t==="deletion"?"-":t==="meta"?"\\":" "}function gt(t,s){const n={schemaVersion:2,type:"review_context",repositoryRevision:t.repositoryRevision,path:t.path,source:t.source,hunk:s.header,hunkId:s.hunkId,complete:s.complete},i=s.lines.map(o=>o.raw).join(`
|
|
1
|
+
var $e=Object.defineProperty;var Pe=(t,s,n)=>s in t?$e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[s]=n;var ie=(t,s,n)=>Pe(t,typeof s!="symbol"?s+"":s,n);import{r as l,a as He,j as e,I as T}from"./index-D5ze0fOv.js";import{u as Oe,R as Me}from"./useAutoNotice-Bsr8yfc3.js";const Ne="orion.web.git-display.v1",_e=Object.freeze(["changes","history","compare"]),me=Object.freeze({message:"",author:"",path:"",sha:"",since:"",until:""}),xe=Object.freeze({view:"changes",group:null,query:"",selectedFileId:null,selectedSource:null,selectedFileIds:Object.freeze([]),selectedLineIds:Object.freeze([]),collapsedHunks:Object.freeze([]),anchorLineId:null,navigatorScrollTop:0,commitDraft:Object.freeze({summary:"",body:""}),historyQuery:me,selectedCommitId:null,selectedCommitParentIndex:0,selectedCommitPath:null,fileHistoryPath:null,notice:""}),pe=Object.freeze({mode:"unified",wrap:!1,showWhitespace:!1,ignoreWhitespace:!1,wordDiff:!1});function Ae(t){return t||"__no-workspace__"}function ze(){const t=new Map;return{read(s){return t.get(s)??xe},update(s,n){const i=Object.freeze({...t.get(s)??xe,...n});return t.set(s,i),i},clear(s){t.delete(s)}}}const Be=ze();function Ge(){try{const t=globalThis.localStorage?.getItem(Ne);if(!t)return pe;const s=JSON.parse(t);return Te(s)}catch{return pe}}function We(t){try{globalThis.localStorage?.setItem(Ne,JSON.stringify(t))}catch{}}function Te(t){if(typeof t!="object"||t===null)return pe;const s=t;return Object.freeze({mode:s.mode==="side-by-side"?"side-by-side":"unified",wrap:s.wrap===!0,showWhitespace:s.showWhitespace===!0,ignoreWhitespace:s.ignoreWhitespace===!0,wordDiff:s.wordDiff===!0})}function qe(t){if(t.entries.length===0)return{fileId:null,path:null,notice:""};const s=t.entries.find(o=>o.fileId===t.previousFileId);if(s)return{fileId:s.fileId,path:s.path,notice:""};const i=t.entries.find(o=>o.path===t.previousPath)??t.entries[0];return{fileId:i.fileId,path:i.path,notice:t.previousFileId===null?"":`原选中的改动已不在此列表,已跳到 ${i.path}。`}}const Qe=959,Ve=620,Ke=640;function Ue(t,s){if(!Number.isFinite(t)||t<=0)return{tier:"wide",narrow:!1,effectiveMode:s,dataWidth:"wide"};const n=t<=Ve?"narrow":t<=Qe?"compact":"wide";return{tier:n,narrow:n==="narrow",effectiveMode:t<=Ke?"unified":s,dataWidth:n}}const Ye=350,je=30;function Xe(t){const{enabled:s,session:n,setSession:i,actions:o,refreshEpoch:h}=t,g=n.historyQuery??me,[x,a]=l.useState(null),[p,j]=l.useState(null),[b,d]=l.useState(null),[S,u]=l.useState(null),[_,L]=l.useState(null),[v,N]=l.useState(null),[Q,P]=l.useState(!1),[B,E]=l.useState(!1),[q,H]=l.useState(!1),[k,R]=l.useState(""),$=l.useRef(0),r=l.useRef(0),I=l.useMemo(()=>({...g.message.trim()?{message:g.message.trim()}:{},...g.author.trim()?{author:g.author.trim()}:{},...g.path.trim()?{path:g.path.trim()}:{},...g.sha.trim()?{sha:g.sha.trim()}:{},...g.since.trim()?{since:g.since.trim()}:{},...g.until.trim()?{until:g.until.trim()}:{}}),[g]);l.useEffect(()=>{if(!s)return;const w=$.current+1;$.current=w,P(!0),R("");const A=setTimeout(()=>{(async()=>{try{const[z,W]=await Promise.all([o.gitRefs(),o.gitHistory({...I,pageSize:je})]);if(w!==$.current)return;a(z),j(W)}catch(z){if(w!==$.current)return;R(le(z))}finally{w===$.current&&P(!1)}})()},I.message||I.author||I.path||I.sha?Ye:0);return()=>clearTimeout(A)},[o,s,h,I]),l.useEffect(()=>{const w=n.selectedCommitId;if(!s||!w){d(null),u(null),L(null);return}const A=r.current+1;r.current=A;const z=n.selectedCommitParentIndex;H(!0),R(""),(async()=>{try{const[W,X]=await Promise.all([o.gitCommitDetail(w,z),o.gitCommitFiles(w,z)]);if(A!==r.current)return;d(W),u(X);const J=X.files.find(U=>!U.sensitive&&!U.binary),ee=n.selectedCommitPath&&X.files.some(U=>U.path===n.selectedCommitPath)?n.selectedCommitPath:J?.path??null;ee!==n.selectedCommitPath&&i({selectedCommitPath:ee}),ee||L(null)}catch(W){if(A!==r.current)return;R(le(W))}finally{A===r.current&&H(!1)}})()},[o,s,n.selectedCommitId,n.selectedCommitParentIndex]),l.useEffect(()=>{const w=n.selectedCommitId,A=n.selectedCommitPath;if(!s||!w||!A){L(null);return}const z=r.current;(async()=>{try{const W=await o.gitCommitDiff({oid:w,path:A,parentIndex:n.selectedCommitParentIndex});if(z!==r.current)return;L(W)}catch(W){if(z!==r.current)return;R(le(W)),L(null)}})()},[o,s,n.selectedCommitId,n.selectedCommitPath,n.selectedCommitParentIndex]),l.useEffect(()=>{const w=n.fileHistoryPath;if(!s||!w){N(null);return}const A=r.current;(async()=>{try{const z=await o.gitFileHistory({path:w});if(A!==r.current)return;N(z)}catch(z){if(A!==r.current)return;R(le(z))}})()},[o,s,n.fileHistoryPath]);const f=l.useCallback(w=>{i({historyQuery:{...g,...w}})},[g,i]),V=l.useCallback(()=>{i({historyQuery:me})},[i]),c=l.useCallback(w=>{i({selectedCommitId:w.id,selectedCommitParentIndex:0,selectedCommitPath:null})},[i]),M=l.useCallback(()=>{i({selectedCommitId:null,selectedCommitPath:null,selectedCommitParentIndex:0})},[i]),G=l.useCallback(w=>{i({selectedCommitParentIndex:w,selectedCommitPath:null})},[i]),K=l.useCallback(w=>i({selectedCommitPath:w}),[i]),Y=l.useCallback(()=>{const w=p?.nextCursor;if(!w||B)return;const A=$.current;E(!0),(async()=>{try{const z=await o.gitHistory({...I,cursor:w,pageSize:je});if(A!==$.current)return;j(W=>W?{...z,items:[...W.items,...z.items]}:z)}catch(z){if(A!==$.current)return;R(le(z))}finally{A===$.current&&E(!1)}})()},[o,B,p,I]),se=l.useCallback(w=>i({fileHistoryPath:w}),[i]),D=l.useCallback(()=>i({fileHistoryPath:null}),[i]);return{query:g,refs:x,page:p,detail:b,files:S,diff:_,fileHistory:v,loading:Q,loadingMore:B,loadingDetail:q,error:k,isEmptyRepository:p!==null&&p.tipOid===null,setQuery:f,resetQuery:V,selectCommit:c,closeDetail:M,setParentIndex:G,selectFile:K,loadMore:Y,openFileHistory:se,closeFileHistory:D}}function le(t){return t?.code==="git_cursor_invalid"?"历史已变化,已重新载入列表。":t instanceof Error?t.message:"Git 历史读取失败。"}function Je(t){if(!(t instanceof HTMLElement))return!1;const s=t.tagName.toLowerCase();return s==="input"||s==="textarea"||s==="select"||t.isContentEditable?!0:t.closest('[role="dialog"]')!==null}function Ze(t){const{enabled:s,session:n,setSession:i,fileIds:o,anchorLineIds:h,onOpenSelection:g,onEscapeFallback:x}=t;l.useEffect(()=>{if(!s)return;const a=p=>{if(Je(p.target))return;if(p.key==="F7"&&h.length>0){p.preventDefault();const b=n.anchorLineId?h.indexOf(n.anchorLineId):-1,d=p.shiftKey?-1:1,S=b<0?d>0?0:h.length-1:Math.min(h.length-1,Math.max(0,b+d));i({anchorLineId:h[S]});return}if(p.key==="Escape"){if(n.query){p.preventDefault(),i({query:"",selectedFileId:null});return}if(n.selectedLineIds.length>0){p.preventDefault(),i({selectedLineIds:[]});return}x();return}if(o.length===0)return;const j=n.selectedFileId?o.indexOf(n.selectedFileId):-1;if(p.key==="ArrowDown"||p.key==="ArrowUp"){p.preventDefault();const b=p.key==="ArrowDown"?1:-1,d=j<0?b>0?0:o.length-1:Math.min(o.length-1,Math.max(0,j+b));i({selectedFileId:o[d],selectedSource:null,anchorLineId:null});return}if(p.key==="Enter"&&j>=0){p.preventDefault(),g();return}if(p.key===" "){if(j<0)return;p.preventDefault();const b=o[j];i({selectedFileIds:n.selectedFileIds.includes(b)?n.selectedFileIds.filter(d=>d!==b):[...n.selectedFileIds,b]})}};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[s,n.query,n.selectedFileId,n.selectedLineIds,n.anchorLineId,n.selectedFileIds,i,o,h,g,x])}class et{constructor(s){ie(this,"fetcher");ie(this,"freshnessMs");ie(this,"slots",new Map);this.fetcher=s.fetcher,this.freshnessMs=s.freshnessMs??3e4}getSnapshot(s){const n=this.slotFor(s);n.invalidated&&(n.inFlight=null,n.invalidated=!1);const i=n.snapshot;if(i&&Date.now()-i.fetchedAt<=this.freshnessMs)return Promise.resolve(i);if(n.inFlight)return n.inFlight;n.generation+=1;const o=n.generation,h=this.fetcher(s).then(g=>{const x=this.slots.get(s);if(!x||x.generation!==o||x.invalidated)throw new tt(s);return x.snapshot=Object.freeze({...g,fetchedAt:Date.now()}),x.inFlight=null,x.snapshot}).catch(g=>{const x=this.slots.get(s);throw x&&x.inFlight===h&&(x.inFlight=null),g});return n.inFlight=h,h}invalidate(s){const n=this.slots.get(s);if(!n)return!1;const i=!!(n.snapshot||n.inFlight);return n.invalidated=!0,n.snapshot=null,i}isStale(s,n){const i=this.slots.get(s)?.snapshot;return i?n==null?!1:i.repositoryRevision!==n:!0}cachedSnapshot(s){const n=this.slots.get(s);return!n||n.invalidated||!n.snapshot?null:n.snapshot}clear(){this.slots.clear()}slotFor(s){const n=this.slots.get(s);if(n)return n;const i={workspaceId:s,snapshot:null,inFlight:null,generation:0,invalidated:!1};return this.slots.set(s,i),i}}class tt extends Error{constructor(n){super(`Repository snapshot for ${n} is stale; refetching.`);ie(this,"code","workspace_snapshot_stale")}}const st=20*1024*1024,nt=5*1024*1024;function it(t){let s=0;for(const n of t.hunks){s+=n.header.length;for(const i of n.lines)s+=i.raw.length+48}return s+t.path.length+256}function lt(t){const s=st,n=nt,i=new Map;let o=0,h=0,g=0;const x=(a,p)=>`${a}\0${p}`;return{read(a,p){const j=x(a,p),b=i.get(j);return b?(i.delete(j),i.set(j,b),h+=1,b.document):(g+=1,null)},write(a,p,j){const b=it(j);if(b>n)return;const d=x(a,p),S=i.get(d);for(S&&(i.delete(d),o-=S.bytes),i.set(d,{document:j,bytes:b}),o+=b;o>s&&i.size>0;){const u=i.keys().next();if(u.done)break;const _=i.get(u.value);i.delete(u.value),o-=_?.bytes??0}},clear(){i.clear(),o=0},stats(){return{entries:i.size,bytes:o,hits:h,misses:g}}}}const at=lt(),rt=2e3;function ct(t){const{workspaceId:s,refreshEpoch:n,actions:i}=t,o=t.store??Be,h=t.cache??at,g=Ae(s),[x,a]=l.useState(()=>o.read(g)),[p,j]=l.useState(()=>Ge()),[b,d]=l.useState(null),[S,u]=l.useState(null),[_,L]=l.useState(null),[v,N]=l.useState(!1),[Q,P]=l.useState(!1),[B,E]=l.useState(""),[q,H]=l.useState(!1),k=l.useRef(0),R=l.useRef(0),$=l.useRef(x);$.current=x;const r=l.useRef(b),I=l.useRef(p);I.current=p,r.current=b;const f=l.useCallback(m=>{a(o.update(g,m))},[g,o]),V=l.useCallback(m=>{j(y=>{const F=Object.freeze({...y,...m});return We(F),F})},[]),c=l.useCallback(async(m,y)=>{if(m===k.current){y.quiet?P(!0):N(!0),E("");try{const F=$.current,[C,O]=await Promise.all([i.gitStatus(void 0,{...F.group?{group:F.group}:{},...F.query?{query:F.query}:{}}),i.gitLog()]);if(m!==k.current)return;if(d(C),u(O),!C.hasWorktree){L(null),H(!1);return}const ne=ue(C);if(!y.keepSelection){L(null),f({selectedFileId:null,selectedSource:null,anchorLineId:null}),H(!1);return}const ae=F.selectedFileId,Re=ne.find(de=>de.fileId===ae)?.path??(_?_.path:null),oe=qe({entries:ne,previousFileId:ae,previousPath:Re});if(oe.fileId&&oe.fileId!==ae){f({selectedFileId:null,selectedSource:null,notice:oe.notice}),L(null),H(!1);return}if(ae){const de=_!==null&&C.repositoryRevision===_.repositoryRevision;H(!de)}else H(!1)}catch(F){if(m!==k.current)return;E(Z(F))}finally{m===k.current&&(N(!1),P(!1))}}},[i,_,f]),M=l.useCallback(()=>{const m=k.current+1;k.current=m,R.current+=1,c(m,{keepSelection:!0,quiet:b!==null})},[c,b]);l.useEffect(()=>{const m=k.current+1;k.current=m,R.current+=1,d(null),u(null),L(null),E(""),H(!1),N(!!s),a(o.read(g)),s?c(m,{keepSelection:!1}):N(!1)},[g,s,o]),l.useEffect(()=>{if(!s||n===0)return;const m=k.current+1;k.current=m,R.current+=1,c(m,{keepSelection:!0,quiet:!0})},[n]),l.useEffect(()=>{if(!s||typeof document>"u")return;let m;const y=()=>{m!==void 0&&clearInterval(m),m=void 0},F=()=>{y(),m=setInterval(()=>{const O=k.current+1;k.current=O,c(O,{keepSelection:!0,quiet:!0})},rt)},C=()=>{if(document.visibilityState==="visible"){const O=k.current+1;k.current=O,c(O,{keepSelection:!0,quiet:!0}),F()}else y()};return document.visibilityState==="visible"&&F(),document.addEventListener("visibilitychange",C),()=>{y(),document.removeEventListener("visibilitychange",C)}},[s,x.group,x.query]);const G=l.useCallback(m=>{const y=R.current+1;R.current=y,f({selectedLineIds:[],selectedFileId:m.fileId,selectedSource:m.source,anchorLineId:null,notice:""}),E("");const F=r.current?.repositoryRevision,C=F?h.read(F,m.fileId):null;if(C){L(C),H(!1),N(!1);return}L(null),N(!0),(async()=>{try{const O=await i.gitDiffDocument(m.fileId,void 0,I.current.ignoreWhitespace,I.current.wordDiff);if(y!==R.current)return;h.write(O.repositoryRevision,m.fileId,O),L(O),H(O.repositoryRevision!==r.current?.repositoryRevision)}catch(O){if(y!==R.current)return;if(ut(O)){E("仓库已变化,已重新载入 Git 状态。"),f({selectedFileId:null,selectedSource:null});return}E(Z(O))}finally{y===R.current&&N(!1)}})()},[i,h,f]),K=l.useCallback(()=>{const m=b?.nextCursor;if(!m)return;const y=k.current,F=b?.repositoryRevision;(async()=>{try{const C=await i.gitStatus(m,{...x.group?{group:x.group}:{},...x.query?{query:x.query}:{}});if(y!==k.current)return;if(F!==void 0&&C.repositoryRevision!==F){E("仓库已变化,已重新载入 Git 状态。");return}d(O=>O&&{...C,conflicted:re(O.conflicted,C.conflicted),staged:re(O.staged,C.staged),unstaged:re(O.unstaged,C.unstaged),untracked:re(O.untracked,C.untracked),counts:{...C.counts,loaded:O.counts.loaded+C.counts.loaded}})}catch(C){if(y!==k.current)return;E(Z(C))}})()},[i,x.group,x.query,b]),Y=l.useCallback(()=>{const m=S?.nextCursor;if(!m)return;const y=k.current;(async()=>{try{const F=await i.gitLog(m);if(y!==k.current)return;u(C=>C&&{...F,items:dt(C.items,F.items)})}catch(F){if(y!==k.current)return;E(Z(F))}})()},[i,S]),se=l.useCallback(()=>{const m=_?.nextCursor,y=x.selectedFileId;if(!m||!y)return;const F=k.current,C=R.current;(async()=>{try{const O=await i.gitDiffDocument(y,m,I.current.ignoreWhitespace,I.current.wordDiff);if(F!==k.current||C!==R.current)return;L(ne=>ne?{...O,hunks:[...ne.hunks,...O.hunks]}:O)}catch(O){if(F!==k.current||C!==R.current)return;E(Z(O))}})()},[i,_,x.selectedFileId]);l.useEffect(()=>{!b||!x.selectedFileId||ue(b).some(y=>y.fileId===x.selectedFileId)||(L(null),f({selectedFileId:null,selectedSource:null,anchorLineId:null}))},[b,x.selectedFileId,f]);const D=l.useMemo(()=>!b||!x.selectedFileId?null:ue(b).find(m=>m.fileId===x.selectedFileId)??null,[b,x.selectedFileId]),[w,A]=l.useState(!1),[z,W]=l.useState(null),X=l.useRef(null);X.current===null&&(X.current=new et({fetcher:async m=>{const y=await i.gitStatus(void 0,{});return Object.freeze({repositoryRevision:y.repositoryRevision,branch:y.branch,counts:Object.freeze({totalChangedFiles:y.counts.total,staged:y.counts.staged,unstaged:y.counts.unstaged,untracked:y.counts.untracked,conflicted:y.counts.conflicted}),fetchedAt:Date.now()})}}));const J=X.current,ee=l.useCallback(async()=>{const m=r.current;if(m?.hasWorktree)try{if((await J.getSnapshot(s)).repositoryRevision===m.repositoryRevision)return;J.invalidate(s),await c(k.current,{keepSelection:!0,quiet:!0})}catch{}},[c,J,s]);l.useEffect(()=>{if(!s)return;let m=!1;const y=()=>{m||document.hidden||(m=!0,ee().finally(()=>{m=!1}))},F=()=>{document.hidden||y()};return window.addEventListener("focus",y),document.addEventListener("visibilitychange",F),()=>{window.removeEventListener("focus",y),document.removeEventListener("visibilitychange",F)}},[ee,s]);const U=l.useCallback(async()=>{h.clear(),J.invalidate(s);const m=k.current+1;k.current=m,R.current+=1,await c(m,{keepSelection:!0,quiet:!0})},[h,c,J,s]),te=l.useCallback(async(m,y)=>{if(!w){A(!0),E("");try{await m(),await U(),f({notice:y})}catch(F){E(Z(F))}finally{A(!1)}}},[w,U,f]),Ce=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&(await te(()=>i.gitStage(m,y),m.length>1?`已暂存 ${m.length} 个文件。`:"已暂存。"),f({selectedFileIds:[]}))},[i,te,f]),we=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&(await te(()=>i.gitUnstage(m,y),m.length>1?`已取消暂存 ${m.length} 个文件。`:"已取消暂存。"),f({selectedFileIds:[]}))},[i,te,f]),Fe=l.useCallback(async m=>{const y=r.current?.repositoryRevision;y&&await te(()=>i.gitApplyPatch({...m,expectedRepositoryRevision:y}),"已应用所选改动到索引。")},[i,te]),Le=l.useCallback(async m=>{const y=r.current?.repositoryRevision;if(!y)throw new Error("Git repository is unavailable.");A(!0),E("");const F=He();try{const C=await i.gitCommit({summary:m.summary,...m.body?{body:m.body}:{},expectedRepositoryRevision:y,requestId:F});return await U(),f({commitDraft:{summary:"",body:""},notice:C.warning?`已提交 ${C.commitSha.slice(0,8)},但:${C.warning}`:`已提交 ${C.commitSha.slice(0,8)}。`}),C.commitSha}catch(C){throw E(Z(C)),C}finally{A(!1)}},[i,U,f]),De=l.useCallback(m=>{const y=$.current.selectedFileIds;f({selectedFileIds:y.includes(m)?y.filter(F=>F!==m):[...y,m]})},[f]),Ee=l.useCallback(()=>f({selectedFileIds:[]}),[f]);return l.useEffect(()=>{if(!b?.hasWorktree){W(null);return}let m=!1;return(async()=>{try{const y=await i.gitCommitPreview();m||W(y)}catch{m||W(null)}})(),()=>{m=!0}},[i,b?.hasWorktree,b?.repositoryRevision]),{session:x,display:p,status:b,log:S,diff:_,loading:v,refreshing:Q,error:B,stale:q,setSession:f,setDisplay:V,openFile:G,reload:M,loadMoreStatus:K,loadMoreLog:Y,loadMoreDiff:se,selectedEntry:D,busy:w,commitPreview:z,toggleSelection:De,clearSelection:Ee,stagePaths:Ce,unstagePaths:we,applyPatch:Fe,commit:Le}}function ue(t){return[...t.conflicted,...t.unstaged,...t.staged,...t.untracked]}function ot(t,s){return s==="conflict"?t.conflicted:s==="unstaged"?t.unstaged:s==="staged"?t.staged:t.untracked}function re(t,s){const n=new Map(t.map(i=>[i.fileId,i]));for(const i of s)n.set(i.fileId,i);return[...n.values()]}function dt(t,s){const n=new Map(t.map(i=>[i.id,i]));for(const i of s)n.set(i.id,i);return[...n.values()]}function Z(t){return t instanceof Error?t.message:"Git 请求失败。"}function ut(t){return typeof t=="object"&&t!==null&&t.code==="git_revision_conflict"}function ht(t){const s=[];let n=0;const i=t.lines;for(;n<i.length;){const o=i[n];if(o.kind==="deletion"){const h=[];for(;n<i.length&&i[n].kind==="deletion";)h.push(i[n]),n+=1;const g=[];for(;n<i.length&&i[n].kind==="addition";)g.push(i[n]),n+=1;const x=Math.max(h.length,g.length);for(let a=0;a<x;a+=1){const p=h[a]??null,j=g[a]??null;s.push(Object.freeze({key:`${t.hunkId}:${p?.lineId??`-${a}`}:${j?.lineId??`-${a}`}`,left:p,right:j,changed:!0}))}continue}if(o.kind==="addition"){s.push(Object.freeze({key:`${t.hunkId}:${o.lineId}`,left:null,right:o,changed:!0})),n+=1;continue}s.push(Object.freeze({key:`${t.hunkId}:${o.lineId}`,left:o,right:o,changed:!1})),n+=1}return s}function ft(t,s,n){const i=new Set(s),o=[];for(const h of t){if(o.push(Object.freeze({kind:"hunk-header",hunk:h})),i.has(h.hunkId)){o.push(Object.freeze({kind:"folded",hunk:h}));continue}if(n==="side-by-side"){for(const g of ht(h))o.push(Object.freeze({kind:"side-by-side",hunk:h,row:g}));continue}for(const g of h.lines)o.push(Object.freeze({kind:"unified-line",hunk:h,line:g}))}return o}function ve(t){const s=[];for(const n of t){let i=!1;for(const o of n.lines){const h=o.kind==="addition"||o.kind==="deletion";h&&!i&&s.push(Object.freeze({lineId:o.lineId,hunkId:n.hunkId,oldLineNumber:o.oldLineNumber,newLineNumber:o.newLineNumber})),i=h}}return s}function mt(t,s,n=500){const i=s.trim().toLowerCase();if(!i)return[];const o=[];for(const h of t)for(const g of h.lines){if(o.length>=n)return o;g.text.toLowerCase().includes(i)&&o.push(Object.freeze({lineId:g.lineId,hunkId:h.hunkId,side:g.oldLineNumber!==null&&g.newLineNumber!==null?"both":g.oldLineNumber!==null?"old":"new"}))}return o}function pt(t){let s=0,n=0;for(const i of t)for(const o of i.lines)o.kind==="addition"?s+=1:o.kind==="deletion"&&(n+=1);return Object.freeze({additions:s,deletions:n,hunks:t.length})}function ce(t,s){return s?t.replace(/\t/gu,"→ ").replace(/ +$/gu,n=>"·".repeat(n.length)):t}function ge(t){return t==="addition"?"+":t==="deletion"?"-":t==="meta"?"\\":" "}function gt(t,s){const n={schemaVersion:2,type:"review_context",repositoryRevision:t.repositoryRevision,path:t.path,source:t.source,hunk:s.header,hunkId:s.hunkId,complete:s.complete},i=s.lines.map(o=>o.raw).join(`
|
|
2
2
|
`).slice(0,12e3);return[`请审阅 ${t.path} 的这个 diff hunk,并指出正确性、安全性和测试风险:`,"","```review_context",JSON.stringify(n,null,2),"```","","```diff",i,"```"].join(`
|
|
3
3
|
`)}function be({document:t,mode:s,wrap:n,showWhitespace:i,collapsedHunks:o,anchorLineId:h,loading:g=!1,stale:x=!1,onChangeMode:a,onToggleWrap:p,onToggleWhitespace:j,onToggleHunk:b,hunkAction:d=null,selectedLineIds:S=[],onToggleLine:u,ignoreWhitespace:_=!1,onToggleIgnoreWhitespace:L,wordDiff:v=!1,onToggleWordDiff:N,onSetAllFolded:Q,onAnchorChange:P,onNotice:B,onLoadMore:E,onSendToComposer:q}){const H=l.useRef(null),[k,R]=l.useState(!1),[$,r]=l.useState(""),[I,f]=l.useState(0),V=l.useMemo(()=>ft(t.hunks,o,s),[t.hunks,o,s]),c=l.useMemo(()=>ve(t.hunks),[t.hunks]),M=l.useMemo(()=>pt(t.hunks),[t.hunks]),G=l.useMemo(()=>k?mt(t.hunks,$):[],[t.hunks,k,$]);l.useEffect(()=>{!h||!H.current||H.current.querySelector(`[data-line-id="${CSS.escape(h)}"]`)?.scrollIntoView({block:"center"})},[h]),l.useEffect(()=>{f(0)},[$]);const K=l.useMemo(()=>h?c.findIndex(D=>D.lineId===h):-1,[c,h]),Y=D=>{if(c.length===0){B("这个文件没有改动。");return}const w=K<0?D>0?-1:0:K,A=Math.min(c.length-1,Math.max(0,w+D));P(c[A].lineId)},se=D=>{if(D.key==="F7"){D.preventDefault(),Y(D.shiftKey?-1:1);return}if(D.key==="Escape"){k&&(D.stopPropagation(),R(!1),r(""));return}if(D.key==="Enter"&&k&&G.length>0){D.preventDefault();const w=D.shiftKey?(I-1+G.length)%G.length:(I+1)%G.length;f(w),P(G[w].lineId)}};return t.kind==="binary"||t.kind==="symlink"||t.kind==="submodule"?e.jsxs("div",{className:"diff-viewer",children:[e.jsx(he,{doc:t,stats:M,stale:x}),e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(T,{name:"code"}),e.jsx("strong",{children:Nt(t.kind)}),e.jsx("p",{children:"只展示变更事实,不返回可预览内容。"}),e.jsx("ul",{className:"diff-meta-list",children:t.meta.slice(0,8).map(D=>e.jsx("li",{children:e.jsx("code",{children:D})},D))})]})]}):t.kind==="metadata"?e.jsxs("div",{className:"diff-viewer",children:[e.jsx(he,{doc:t,stats:M,stale:x}),e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(T,{name:"code"}),e.jsx("strong",{children:"仅有元数据变化"}),e.jsx("p",{children:"没有文本 Hunk,但文件确实变了。"}),e.jsx("ul",{className:"diff-meta-list",children:t.meta.slice(0,8).map(D=>e.jsx("li",{children:e.jsx("code",{children:D})},D))})]})]}):e.jsxs("div",{className:"diff-viewer",children:[e.jsx(he,{doc:t,stats:M,stale:x}),e.jsxs("div",{className:"diff-toolbar",role:"toolbar","aria-label":"Diff 显示选项",children:[e.jsxs("div",{className:"diff-mode-group",role:"group","aria-label":"Diff 布局",children:[e.jsx("button",{type:"button",className:"text-button","aria-pressed":s==="unified",onClick:()=>a("unified"),children:"统一"}),e.jsx("button",{type:"button",className:"text-button","aria-pressed":s==="side-by-side",onClick:()=>a("side-by-side"),children:"并排"})]}),e.jsx("button",{type:"button",className:"text-button","aria-pressed":n,onClick:p,children:"换行"}),e.jsx("button",{type:"button",className:"text-button","aria-pressed":i,onClick:j,children:"空白字符"}),N?e.jsx("button",{type:"button",className:`text-button ${v?"diff-toggle-on":""}`,"aria-pressed":v,title:"词级差异(重新读取 Diff)",onClick:N,children:"词级"}):null,L?e.jsx("button",{type:"button",className:`text-button ${_?"diff-toggle-on":""}`,"aria-pressed":_,title:"忽略空白差异(重新读取 Diff)",onClick:L,children:"忽略空白"}):null,e.jsx("button",{type:"button",className:"text-button",onClick:()=>Q(o.length===0),children:o.length===0?"折叠全部":"展开全部"}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>Y(-1),disabled:c.length===0,"aria-label":"上一个改动",children:"↑改动"}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>Y(1),disabled:c.length===0,"aria-label":"下一个改动",children:"↓改动"}),e.jsx("span",{className:"diff-anchor-count","aria-live":"polite",children:c.length===0?"无改动":`改动 ${Math.max(1,K+1)}/${c.length}`}),e.jsx("button",{type:"button",className:"text-button","aria-pressed":k,onClick:()=>R(D=>!D),children:"查找"})]}),k?e.jsxs("div",{className:"diff-find",children:[e.jsx("input",{type:"search",value:$,autoFocus:!0,"aria-label":"在已加载的 Diff 中查找",placeholder:"在已加载内容中查找",onChange:D=>r(D.target.value)}),e.jsxs("span",{"aria-live":"polite",children:[$.trim()?G.length===0?"无命中":`${I+1}/${G.length}`:"输入以查找",t.completeness!=="complete"?" · 仅已加载内容":""]})]}):null,t.completeness==="paged"?e.jsx("p",{className:"resource-notice",role:"status",children:"当前为分页预览,未加载的 Hunk 不能执行任何写入。"}):null,e.jsx("div",{className:`diff-body diff-body-${s} ${n?"diff-wrap":""}`,ref:H,tabIndex:0,role:"region","aria-label":`Diff ${t.path}`,onKeyDown:se,children:V.length===0?e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(T,{name:"check"}),e.jsx("strong",{children:"没有文本改动"})]}):V.map(D=>e.jsx(bt,{row:D,mode:s,showWhitespace:i,folded:o.includes(kt(D).hunkId),activeAnchor:h,onToggleHunk:b,hunkAction:d,selectedLineIds:S,onToggleLine:u,wordDiff:v},yt(D)))}),e.jsxs("footer",{className:"diff-footer",children:[q?e.jsx("button",{type:"button",className:"secondary-button",disabled:t.hunks.length===0,onClick:()=>q(gt({path:t.path,source:t.source,repositoryRevision:t.repositoryRevision},t.hunks[Math.max(0,c.findIndex(D=>D.lineId===h))]??t.hunks[0])),children:"发送当前 Hunk 到对话"}):null,t.nextCursor&&E?e.jsx("button",{type:"button",className:"text-button",onClick:E,disabled:g,children:g?"加载中…":"加载更多 Diff"}):null,e.jsxs("span",{className:"diff-footer-hint",children:[t.capabilities.stageFile?"可暂存此文件":t.capabilities.unstageFile?"可取消暂存此文件":"只读",t.capabilities.reason?` · ${t.capabilities.reason}`:""]})]})]})}function he({doc:t,stats:s,stale:n}){return e.jsxs("header",{children:[e.jsx("strong",{title:t.path,children:t.path}),e.jsx("span",{className:"diff-source",children:vt(t.source)}),e.jsxs("span",{className:"diff-stat-add",children:["+",s.additions]}),e.jsxs("span",{className:"diff-stat-del",children:["-",s.deletions]}),e.jsxs("span",{children:[s.hunks," 个 Hunk"]}),n?e.jsx("span",{className:"diff-stale",role:"status",children:"已变化"}):null]})}function bt({row:t,mode:s,showWhitespace:n,folded:i,activeAnchor:o,onToggleHunk:h,hunkAction:g=null,selectedLineIds:x=[],onToggleLine:a,wordDiff:p=!1}){if(t.kind==="hunk-header")return e.jsxs("div",{className:"diff-hunk-header",children:[e.jsx("button",{type:"button",className:"diff-fold","aria-expanded":!i,"aria-label":i?"展开 Hunk":"折叠 Hunk",onClick:()=>h(t.hunk.hunkId),children:i?"▸":"▾"}),e.jsx("code",{children:t.hunk.header}),t.hunk.complete?null:e.jsx("em",{className:"diff-incomplete",children:"未完整加载"}),g&&t.hunk.complete?e.jsx("button",{type:"button",className:"text-button diff-hunk-action","aria-label":g.label,onClick:()=>g.run(t.hunk.hunkId),children:g.label}):null]});if(t.kind==="folded")return e.jsxs("button",{type:"button",className:"diff-folded-row",onClick:()=>h(t.hunk.hunkId),children:["已折叠 ",t.hunk.lines.length," 行 · 点击展开"]});if(t.kind==="side-by-side")return e.jsx(jt,{row:t.row,showWhitespace:n});const j=t.line;return e.jsxs("div",{className:`diff-line diff-line-${j.kind} ${o===j.lineId?"diff-line-anchor":""}`,"data-line-id":j.lineId,"data-side":j.oldLineNumber!==null&&j.newLineNumber!==null?"both":j.oldLineNumber!==null?"old":"new",children:[e.jsx("span",{className:"diff-gutter",children:j.oldLineNumber??""}),e.jsx("span",{className:"diff-gutter",children:j.newLineNumber??""}),a&&(j.kind==="addition"||j.kind==="deletion")?e.jsx("input",{type:"checkbox",className:"diff-line-select","aria-label":`选择第 ${j.newLineNumber??j.oldLineNumber??""} 行`,checked:x.includes(j.lineId),onChange:()=>a(j.lineId)}):null,e.jsx("span",{className:"diff-marker","aria-hidden":"true",children:ge(j.kind)}),e.jsx("span",{className:"diff-code",children:p?xt(ce(j.text,n)):ce(j.text,n)||" "}),null]})}function xt(t){if(!t)return" ";const s=[],n=/\[-([\s\S]*?)-\]|\{\+([\s\S]*?)\+\}/gu;let i=0,o,h=0;for(;(o=n.exec(t))!==null;)o.index>i&&s.push(t.slice(i,o.index)),o[1]!==void 0?s.push(e.jsx("em",{className:"diff-word-del",children:o[1]},h++)):s.push(e.jsx("em",{className:"diff-word-add",children:o[2]},h++)),i=o.index+o[0].length;return i<t.length&&s.push(t.slice(i)),s.length>0?s:" "}function jt({row:t,showWhitespace:s}){return e.jsxs("div",{className:`diff-sbs-row ${t.changed?"diff-sbs-changed":""}`,children:[e.jsxs("div",{className:`diff-sbs-side ${t.left?.kind==="deletion"?"diff-line-deletion":""}`,"data-line-id":t.left?.lineId??void 0,children:[e.jsx("span",{className:"diff-gutter",children:t.left?.oldLineNumber??""}),e.jsx("span",{className:"diff-marker","aria-hidden":"true",children:t.left?ge(t.left.kind):" "}),e.jsx("span",{className:"diff-code",children:t.left?ce(t.left.text,s)||" ":""})]}),e.jsxs("div",{className:`diff-sbs-side ${t.right?.kind==="addition"?"diff-line-addition":""}`,"data-line-id":t.right?.lineId??void 0,children:[e.jsx("span",{className:"diff-gutter",children:t.right?.newLineNumber??""}),e.jsx("span",{className:"diff-marker","aria-hidden":"true",children:t.right?ge(t.right.kind):" "}),e.jsx("span",{className:"diff-code",children:t.right?ce(t.right.text,s)||" ":""})]})]})}function yt(t){return t.kind==="hunk-header"?`h:${t.hunk.hunkId}`:t.kind==="folded"?`f:${t.hunk.hunkId}`:t.kind==="side-by-side"?t.row.key:t.line.lineId}function kt(t){return t.hunk}function Nt(t){return t==="binary"?"二进制差异":t==="symlink"?"符号链接变化":t==="submodule"?"Submodule 指针变化":"元数据变化"}function vt(t){return t==="staged"?"HEAD → 索引":t==="unstaged"?"索引 → 工作区":t==="untracked"?"空 → 未跟踪文件":"冲突版本"}const ye=Object.freeze({snapshot:"两端快照 A → B","merge-base":"共同祖先 → B"});function It({refs:t,actions:s,display:n,collapsedHunks:i,anchorLineId:o,onDisplayChange:h,onToggleHunk:g,onSetAllFolded:x,onAnchorChange:a,onNotice:p,onSendToComposer:j}){const b=l.useMemo(()=>St(t),[t]),d=b.find(f=>f.isBranch)?.value??b[0]?.value??"",S=t?.refs.find(f=>f.isHead)?.shortName??d,[u,_]=l.useState(d),[L,v]=l.useState(S),[N,Q]=l.useState("snapshot"),[P,B]=l.useState(null),[E,q]=l.useState(null),[H,k]=l.useState(!1),[R,$]=l.useState(""),r=()=>{!u||!L||H||(k(!0),$(""),(async()=>{try{const f=await s.gitCompare({baseRef:u,headRef:L,mode:N});B(f),q(null)}catch(f){$(ke(f))}finally{k(!1)}})())},I=f=>{!P||f.sensitive||H||(k(!0),$(""),(async()=>{try{const V=await s.gitCompareFileDiff({baseOid:P.baseOid,headOid:P.headOid,path:f.path});q(V)}catch(V){$(ke(V))}finally{k(!1)}})())};return b.length===0?e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"branch",size:16}),e.jsx("strong",{children:"没有可比较的 ref"}),e.jsx("p",{children:"这个仓库还没有分支或标签。"})]}):e.jsxs("div",{className:"git-compare","aria-label":"分支与版本比较",children:[e.jsxs("div",{className:"git-compare-form",children:[e.jsxs("label",{children:[e.jsx("span",{children:"基准 A"}),e.jsx("select",{value:u,"aria-label":"选择基准 A",onChange:f=>_(f.target.value),children:b.map(f=>e.jsx("option",{value:f.value,children:f.label},f.value))})]}),e.jsxs("label",{children:[e.jsx("span",{children:"目标 B"}),e.jsx("select",{value:L,"aria-label":"选择目标 B",onChange:f=>v(f.target.value),children:b.map(f=>e.jsx("option",{value:f.value,children:f.label},f.value))})]}),e.jsxs("label",{children:[e.jsx("span",{children:"模式"}),e.jsx("select",{value:N,"aria-label":"选择比较模式",onChange:f=>Q(f.target.value),children:Object.keys(ye).map(f=>e.jsx("option",{value:f,children:ye[f]},f))})]}),e.jsx("button",{type:"button",className:"primary-button",disabled:H||u===L,"aria-busy":H,onClick:r,children:H?"比较中…":"比较"})]}),e.jsx("p",{className:"git-compare-hint",children:"修改选择不会立即发起查询;点「比较」或按 Enter 才执行。交换 A/B 后会取消旧的请求。"}),R?e.jsx("p",{className:"resource-error",role:"alert",children:R}):null,P?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"git-compare-range",children:[P.baseLabel," ",e.jsx("code",{children:P.baseOid.slice(0,10)})," → ",P.headLabel," ",e.jsx("code",{children:P.headOid.slice(0,10)}),P.truncated?" · 文件列表已截断":""]}),e.jsxs("p",{className:"git-compare-range",children:[P.files.length," 个文件 ·",e.jsxs("em",{className:"diff-stat-add",children:[" +",P.additions]}),e.jsxs("em",{className:"diff-stat-del",children:[" -",P.deletions]}),e.jsx("button",{type:"button",className:"text-button",onClick:r,disabled:H,children:"重新比较"})]}),e.jsx("ul",{className:"git-compare-files",children:P.files.map(f=>e.jsx("li",{children:e.jsxs("button",{type:"button",className:E?.path===f.path?"selected":"","aria-current":E?.path===f.path?"true":void 0,disabled:f.sensitive,onClick:()=>I(f),children:[e.jsx("span",{className:"git-commit-file-stats",children:f.binary?"bin":`+${f.additions} -${f.deletions}`}),e.jsx("span",{title:f.path,children:f.renamedFrom?`${f.renamedFrom} → ${f.path}`:f.path}),f.sensitive?e.jsx("em",{className:"git-sensitive-badge",children:"受保护"}):null]})},`${f.renamedFrom??""}:${f.path}`))}),E?e.jsx(be,{document:E,mode:n.mode,wrap:n.wrap,showWhitespace:n.showWhitespace,collapsedHunks:i,anchorLineId:o,loading:H,onChangeMode:f=>h({mode:f}),onToggleWrap:()=>h({wrap:!n.wrap}),onToggleWhitespace:()=>h({showWhitespace:!n.showWhitespace}),onToggleHunk:g,onSetAllFolded:x,onAnchorChange:a,onNotice:p,onSendToComposer:j}):e.jsx("p",{className:"git-compare-hint",children:"点一个文件查看该比较下的 Diff。"})]}):null]})}function St(t){return t?t.refs.map(s=>Object.freeze({value:s.shortName,label:s.kind==="branch"?s.shortName:`${s.shortName}(${s.kind==="tag"?"tag":s.kind==="remote"?"远程":"其他"})`,isBranch:s.kind==="branch"})):[]}function ke(t){const s=t?.code;return s==="git_merge_base_multiple"?"这两个 ref 有多个共同祖先,没有唯一分叉点;请改用「两端快照」模式。":s==="git_merge_base_missing"?"两个 ref 没有共同祖先,无法用「共同祖先」模式;请改用「两端快照」模式。":s==="git_shallow_history"?"仓库缺少完成该比较所需的对象(浅克隆?)。":s==="git_ref_not_found"?"所选 ref 无法解析为提交。":t instanceof Error?t.message:"比较失败。"}const Ct=Object.freeze({"both-modified":"双方都修改","both-added":"双方都新增","added-by-us":"我们新增 · 对方删除","added-by-them":"对方新增 · 我们删除","deleted-by-us":"我们删除 · 对方修改","deleted-by-them":"对方删除 · 我们修改","both-deleted":"双方都删除",other:"其他冲突形态"}),wt=Object.freeze({base:"base(共同祖先)",ours:"ours(当前分支)",theirs:"theirs(合入分支)",worktree:"工作区文件",revision:"该版本"});function Ft({path:t,actions:s}){const[n,i]=l.useState(null),[o,h]=l.useState(""),[g,x]=l.useState(!0);if(l.useEffect(()=>{let p=!1;return x(!0),h(""),(async()=>{try{const j=await s.gitConflictVersions(t);p||i(j)}catch(j){p||(i(null),h(j instanceof Error?j.message:"冲突详情读取失败。"))}finally{p||x(!1)}})(),()=>{p=!0}},[s,t]),g)return e.jsx("p",{className:"resource-loading",children:"正在读取冲突版本…"});if(o)return e.jsx("p",{className:"resource-error",role:"alert",children:o});if(!n)return null;const a=[n.base,n.ours,n.theirs,n.worktree];return e.jsxs("section",{className:"git-conflict","aria-label":"冲突版本",children:[e.jsxs("header",{className:"git-conflict-header",children:[e.jsx(T,{name:"warning",size:14}),e.jsx("strong",{children:n.path}),e.jsx("em",{className:"git-merge-badge",children:Ct[n.shape]})]}),e.jsx("p",{className:"git-compare-hint",children:"直接读 index 的 stage 1/2/3,不用普通暂存 Diff 代替完整冲突视图。缺失的版本是这种冲突形态的正常结果。"}),e.jsx("div",{className:"git-conflict-grid",children:a.map(p=>e.jsxs("article",{className:"git-conflict-version",children:[e.jsxs("header",{children:[e.jsx("span",{children:wt[p.label]}),p.exists?e.jsx("code",{children:p.oid?.slice(0,10)}):e.jsx("em",{className:"git-conflict-absent",children:"此形态下不存在"})]}),p.exists?p.lfs?e.jsxs("p",{className:"git-conflict-note",children:["LFS 指针 · oid ",p.lfs.oid.slice(0,16),"…",p.lfs.size!==null?` · ${p.lfs.size} 字节(不下载对象)`:""]}):p.binary?e.jsxs("p",{className:"git-conflict-note",children:["二进制内容(",p.byteSize," 字节),不在此处渲染。"]}):p.truncated?e.jsxs("p",{className:"git-conflict-note",children:["超过上限(",p.byteSize," 字节),未读取内容。"]}):e.jsx("pre",{className:"git-conflict-content",children:p.content??""}):e.jsx("p",{className:"git-conflict-note",children:"没有这个版本。"})]},p.label))})]})}function Lt({history:t,actions:s,display:n,collapsedHunks:i,anchorLineId:o,onDisplayChange:h,onToggleHunk:g,onSetAllFolded:x,onAnchorChange:a,onNotice:p,onSendToComposer:j}){const{page:b,detail:d,files:S,diff:u,fileHistory:_,error:L}=t,[v,N]=l.useState(null),[Q,P]=l.useState(!1),[B,E]=l.useState(null),[q,H]=l.useState(!1),[k,R]=l.useState(null),$=l.useMemo(()=>(b?.items??[]).filter(r=>r.isMerge).length,[b]);return t.isEmptyRepository?e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"branch",size:16}),e.jsx("strong",{children:"尚无提交"}),e.jsx("p",{children:"这个仓库还没有提交。新文件仍可暂存并完成首次提交。"})]}):e.jsxs("div",{className:"git-history","aria-label":"Git 历史",children:[e.jsxs("div",{className:"git-history-search",children:[e.jsx("input",{type:"search","aria-label":"搜索提交消息",placeholder:"搜索提交消息…",value:t.query.message,onChange:r=>t.setQuery({message:r.target.value})}),e.jsx("input",{type:"search","aria-label":"按作者筛选",placeholder:"作者",value:t.query.author,onChange:r=>t.setQuery({author:r.target.value})}),e.jsx("input",{type:"search","aria-label":"按文件路径筛选",placeholder:"文件路径",value:t.query.path,onChange:r=>t.setQuery({path:r.target.value})}),e.jsx("input",{type:"search","aria-label":"按提交哈希查找",placeholder:"提交哈希",value:t.query.sha,onChange:r=>t.setQuery({sha:r.target.value})}),e.jsxs("div",{className:"git-history-dates",children:[e.jsx("input",{type:"search","aria-label":"起始日期",placeholder:"自 (2026-01-01)",value:t.query.since,onChange:r=>t.setQuery({since:r.target.value})}),e.jsx("input",{type:"search","aria-label":"结束日期",placeholder:"至",value:t.query.until,onChange:r=>t.setQuery({until:r.target.value})})]}),e.jsxs("div",{className:"git-history-search-actions",children:[e.jsxs("span",{role:"status",children:[b?`已载 ${b.items.length}${b.truncated?"+":""} 个提交${$>0?` · 含 ${$} 个合并`:""}`:"读取中…",t.refs?.detached?" · detached HEAD":""]}),e.jsx("button",{type:"button",className:`text-button ${B?"diff-toggle-on":""}`,"aria-pressed":B!==null,onClick:()=>{if(B){E(null);return}H(!0),s.gitGraph().then(E).finally(()=>H(!1))},children:"拓扑"}),e.jsx("button",{type:"button",className:"text-button",onClick:t.resetQuery,children:"清除筛选"})]})]}),L?e.jsx("p",{className:"resource-error",role:"alert",children:L}):null,_?e.jsxs("section",{className:"git-file-history","aria-label":"文件历史",children:[e.jsxs("header",{children:[e.jsxs("strong",{children:["文件历史 · ",_.path]}),e.jsx("button",{type:"button",className:"text-button",onClick:t.closeFileHistory,children:"返回提交列表"})]}),e.jsx("p",{className:"git-file-history-note",children:"跟随重命名;复制与复杂合并场景的追踪可能不完整。"}),e.jsx("ul",{children:_.items.map(r=>e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>{t.closeFileHistory(),t.selectCommit(r)},children:[e.jsx("code",{children:r.shortId}),e.jsx("span",{children:r.subject}),e.jsx("time",{dateTime:r.authoredAt,children:fe(r.authoredAt)})]})},r.id))}),_.truncated?e.jsx("p",{className:"git-file-history-note",children:"结果已截断,仅显示最近的提交。"}):null]}):null,d?e.jsxs("section",{className:"git-commit-detail","aria-label":"提交详情",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("code",{children:d.shortId}),d.isMerge?e.jsxs("span",{className:"git-merge-badge",children:["合并提交 · ",d.parents.length," 个父提交"]}):d.parents.length===0?e.jsx("span",{className:"git-root-badge",children:"根提交"}):null]}),e.jsx("button",{type:"button",className:"text-button",onClick:t.closeDetail,children:"关闭详情"})]}),e.jsx("p",{className:"git-commit-subject",children:d.subject}),d.message.trim()!==d.subject.trim()?e.jsx("pre",{className:"git-commit-message",children:d.message.trim()}):null,e.jsxs("p",{className:"git-commit-meta",children:[d.authorName," <",d.authorEmail,"> · ",fe(d.authoredAt),d.committerName&&d.committerName!==d.authorName?` · 提交者 ${d.committerName}`:""]}),e.jsxs("p",{className:"git-commit-base",children:["比较基准:",d.baseLabel," ",e.jsx("code",{children:d.baseOid.slice(0,10)})]}),d.isMerge?e.jsx("div",{className:"git-parent-picker",role:"group","aria-label":"选择父提交",children:d.parents.map((r,I)=>e.jsxs("button",{type:"button","aria-pressed":d.parentIndex===I,className:d.parentIndex===I?"selected":"",onClick:()=>t.setParentIndex(I),children:["父 ",I+1," ",e.jsx("code",{children:r.slice(0,8)})]},r))}):null,S?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"git-commit-stats-line",children:[S.files.length," 个文件 ·",e.jsxs("em",{className:"diff-stat-add",children:[" +",S.additions]}),e.jsxs("em",{className:"diff-stat-del",children:[" -",S.deletions]}),S.truncated?" · 已截断":""]}),e.jsx("ul",{className:"git-commit-file-list",children:S.files.map(r=>e.jsxs("li",{children:[e.jsxs("button",{type:"button",className:d&&t.diff?.path===r.path?"selected":"","aria-current":t.diff?.path===r.path?"true":void 0,onClick:()=>t.selectFile(r.path),children:[e.jsx("span",{className:"git-commit-file-stats",children:r.binary?"bin":`+${r.additions} -${r.deletions}`}),e.jsx("span",{title:r.path,children:r.renamedFrom?`${r.renamedFrom} → ${r.path}`:r.path}),r.sensitive?e.jsx("em",{className:"git-sensitive-badge",children:"受保护"}):null]}),e.jsx("button",{type:"button",className:"text-button","aria-label":`查看 ${r.path} 的文件历史`,onClick:()=>t.openFileHistory(r.path),children:"历史"}),e.jsx("button",{type:"button",className:"text-button","aria-label":`查看 ${r.path} 在该提交的版本`,onClick:()=>{d&&s.gitBlob({path:r.path,rev:d.id}).then(I=>R({path:I.path,rev:I.rev,lines:I.content,binary:I.binary,truncated:I.truncated,byteSize:I.byteSize,dataUrl:I.dataUrl})).catch(()=>R(null))},children:"该版本"}),e.jsx("button",{type:"button",className:"text-button","aria-label":`查看 ${r.path} 的 Blame`,onClick:()=>{d&&(P(!0),s.gitBlame({path:r.path,rev:d.id}).then(I=>N({...I,rev:d.id})).catch(()=>N(null)).finally(()=>P(!1)))},children:"Blame"})]},r.path))})]}):e.jsx("p",{className:"resource-loading",children:"正在读取该提交的改动…"})]}):null,u?e.jsx(be,{document:u,mode:n.mode,wrap:n.wrap,showWhitespace:n.showWhitespace,collapsedHunks:i,anchorLineId:o,loading:t.loadingDetail,onChangeMode:r=>h({mode:r}),onToggleWrap:()=>h({wrap:!n.wrap}),onToggleWhitespace:()=>h({showWhitespace:!n.showWhitespace}),onToggleHunk:g,onSetAllFolded:x,onAnchorChange:a,onNotice:p,onSendToComposer:j}):null,q?e.jsx("p",{className:"git-file-history-note",children:"正在读取拓扑…"}):null,B?e.jsxs("section",{className:"git-graph","aria-label":"提交拓扑",children:[e.jsxs("header",{children:[e.jsxs("strong",{children:["拓扑(",B.rows.length,B.truncated?"+":""," 行)"]}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>E(null),children:"关闭"})]}),e.jsx("p",{className:"git-file-history-note",children:"图形列由 git 直接绘制,不由前端重算。"}),e.jsx("div",{className:"git-graph-body",children:B.rows.map((r,I)=>e.jsxs("button",{type:"button",className:r.id&&d?.id===r.id?"selected":"",disabled:!r.id,onClick:()=>{r.id&&(E(null),t.selectCommit({id:r.id}))},children:[e.jsx("code",{children:r.graph}),e.jsx("span",{children:r.id?r.subject:""})]},`${r.id??"graph"}:${I}`))})]}):null,k?e.jsxs("section",{className:"git-blob","aria-label":"该版本内容",children:[e.jsxs("header",{children:[e.jsxs("strong",{children:[k.path," @ ",k.rev.slice(0,10)]}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>R(null),children:"关闭"})]}),k.truncated?e.jsxs("p",{className:"git-file-history-note",children:["文件超过上限(",k.byteSize," 字节),未读取内容。"]}):k.dataUrl?e.jsx("img",{src:k.dataUrl,alt:`${k.path} 在该提交的图像版本`,className:"git-blob-image"}):k.binary?e.jsxs("p",{className:"git-file-history-note",children:["二进制内容(",k.byteSize," 字节),不在此处渲染。"]}):e.jsx("pre",{className:"git-blob-content",children:k.lines.join(`
|
|
4
4
|
`)})]}):null,v?e.jsxs("section",{className:"git-blame","aria-label":"Blame",children:[e.jsxs("header",{children:[e.jsxs("strong",{children:["Blame · ",v.path]}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>N(null),children:"关闭"})]}),Q?e.jsx("p",{className:"git-file-history-note",children:"读取中…"}):null,e.jsx("div",{className:"git-blame-table",children:v.lines.map(r=>e.jsxs("div",{className:"git-blame-row",children:[e.jsx("code",{children:r.commitShort}),e.jsx("span",{className:"git-blame-author",title:r.summary,children:r.author}),e.jsx("time",{children:r.authoredAt.slice(0,10)}),e.jsx("span",{className:"git-blame-summary",title:r.summary,children:r.summary})]},r.lineNumber))}),v.truncated?e.jsx("p",{className:"git-file-history-note",children:"结果已截断。"}):null]}):null,e.jsx("ul",{className:"git-history-list",children:(b?.items??[]).map(r=>e.jsx("li",{children:e.jsxs("button",{type:"button",className:d?.id===r.id?"selected":"","aria-current":d?.id===r.id?"true":void 0,onClick:()=>t.selectCommit(r),children:[e.jsx("code",{children:r.shortId}),e.jsx("span",{title:r.subject,children:r.subject}),r.isMerge?e.jsx("em",{className:"git-merge-badge-inline",children:"合并"}):null,r.decoration.length>0?e.jsx("em",{className:"git-ref-badge",title:r.decoration.join(", "),children:r.decoration[0]}):null,e.jsx("time",{dateTime:r.authoredAt,children:fe(r.authoredAt)})]})},r.id))}),b&&b.items.length===0&&!t.loading?e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(T,{name:"search",size:16}),e.jsx("strong",{children:"没有匹配的提交"}),e.jsx("p",{children:"筛选在 Host 上对整个可达历史执行,不只是当前页。"})]}):null,b?.nextCursor?e.jsx("button",{type:"button",className:"text-button resource-load-more",onClick:t.loadMore,disabled:t.loadingMore,children:t.loadingMore?"加载中…":"加载更多提交"}):null]})}function fe(t){const s=new Date(t);return Number.isNaN(s.getTime())?t:s.toLocaleDateString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit"})}const Dt={changes:"变更",history:"历史",compare:"比较"},Ie={conflict:"冲突",unstaged:"未暂存",staged:"已暂存",untracked:"未跟踪"},Se=["conflict","unstaged","staged","untracked"];function Et(t,s){return s==="conflict"?t.conflicted:t[s]}function _t({workspaceId:t,refreshEpoch:s,actions:n,onSendToComposer:i,onRevealInFiles:o,navigatorWidthPx:h,onNavigatorWidthCommit:g,store:x}){const a=ct({workspaceId:t,refreshEpoch:s,actions:n,store:x}),{notice:p,showNotice:j,clearNotice:b}=Oe(),{status:d,diff:S,session:u}=a,_=()=>{if(!u.selectedFileId||u.selectedLineIds.length===0)return;const c=u.selectedFileId,M=u.selectedLineIds;a.applyPatch({fileId:c,lineIds:M}),a.setSession({selectedLineIds:[]})},L=l.useRef(null),v=l.useCallback(c=>{if(L.current?.disconnect(),L.current=null,!c)return;const M=new ResizeObserver(G=>{for(const K of G)Q(K.contentRect.width)});M.observe(c),L.current=M,Q(c.getBoundingClientRect().width)},[]),[N,Q]=l.useState(0);l.useEffect(()=>()=>L.current?.disconnect(),[]);const P=Ue(N,a.display.mode),B=P.narrow,E=P.effectiveMode,[q,H]=l.useState(!1),k=l.useMemo(()=>{const c=a.selectedEntry;if(!o||!c||u.view!=="changes")return null;const M=c.fileId;return()=>{n.gitFilesTarget(M).then(G=>o({path:G.path,filesToken:G.filesToken})).catch(()=>j("该文件无法在 Files 中打开。"))}},[n,a.selectedEntry,o,u.view,j]),R=l.useMemo(()=>{if(u.view!=="changes"||!u.selectedFileId||!S)return null;const c=u.selectedFileId;return S.source!=="staged"&&S.source!=="unstaged"&&S.source!=="untracked"?null:{label:S.source==="staged"?"取消暂存此 Hunk":"暂存此 Hunk",run:G=>{a.applyPatch({fileId:c,hunkIds:[G]})}}},[S,a,u.selectedFileId,u.view]),$=Xe({enabled:(u.view==="history"||u.view==="compare")&&!!t,session:u,setSession:a.setSession,actions:n,refreshEpoch:s}),r=l.useMemo(()=>d?Se.map(c=>({source:c,label:Ie[c],count:Et(d.counts,c),items:ot(d,c)})):[],[d]),I=l.useMemo(()=>u.group?r.filter(c=>c.source===u.group):r,[r,u.group]),f=l.useMemo(()=>I.flatMap(c=>c.items.map(M=>M.fileId)),[I]),V=l.useMemo(()=>S?ve(S.hunks).map(c=>c.lineId):[],[S]);return Ze({enabled:u.view==="changes",session:u,setSession:a.setSession,fileIds:f,anchorLineIds:V,onOpenSelection:()=>{const c=a.selectedEntry;c&&a.openFile(c)},onEscapeFallback:()=>{}}),a.error&&!d?e.jsxs("div",{className:"resource-empty",role:"alert",children:[e.jsx(T,{name:"warning"}),e.jsx("strong",{children:"Git 状态读取失败"}),e.jsx("p",{children:a.error}),e.jsx("button",{type:"button",className:"secondary-button",onClick:a.reload,children:"重试"})]}):a.loading&&!d?e.jsx("p",{className:"resource-loading",children:"正在读取 Git 状态…"}):d&&d.repositoryKind==="bare"?e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"branch",size:16}),e.jsx("strong",{children:"当前项目是裸仓库"}),e.jsx("p",{children:"裸仓库没有工作区,工作栏没有可显示的变更或 Diff。文件和 Agent 不受影响。"})]}):d&&!d.isRepository?e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"branch",size:16}),e.jsx("strong",{children:"当前项目不是 Git 仓库"}),e.jsx("p",{children:"文件和 Agent 不受影响。"})]}):e.jsxs("div",{ref:v,"data-width":P.dataWidth,"data-narrow-view":B&&q&&u.selectedFileId?"detail":"list",className:"work-resource-panel git-panel",children:[e.jsxs("div",{className:"git-summary",children:[e.jsxs("div",{children:[e.jsx(T,{name:"branch",size:16}),e.jsx("strong",{children:d?.detached?`detached ${d.head??""}`:d?.branch||"HEAD"})]}),e.jsxs("span",{children:[d?.upstream||"无 upstream",d&&(d.ahead||d.behind)?` · ↑${d.ahead} ↓${d.behind}`:""]}),e.jsx("button",{type:"button",className:"icon-button","aria-label":"刷新 Git 状态","aria-busy":a.refreshing,onClick:()=>{b(),a.reload()},disabled:a.refreshing,children:e.jsx(T,{name:"refresh",size:16})})]}),e.jsxs("div",{className:"git-views",role:"tablist","aria-label":"Git 视图",children:[_e.map(c=>e.jsxs("button",{type:"button",role:"tab","aria-selected":u.view===c,className:u.view===c?"selected":"",onClick:()=>a.setSession({view:c}),children:[Dt[c],c==="changes"&&d&&d.counts.total>0?e.jsx("span",{className:"git-view-count",children:d.counts.total}):null]},c)),a.refreshing?e.jsx("span",{className:"git-refreshing",children:"更新中…"}):null]}),p?e.jsx("p",{className:"resource-notice",role:"status",children:p.text}):null,u.notice?e.jsx("p",{className:"resource-notice",role:"status",children:u.notice}):null,a.error?e.jsx("p",{className:"resource-error",role:"alert",children:a.error}):null,e.jsxs(Me,{panelId:"git",navigatorWidthPx:h,onNavigatorWidthCommit:g,contentLabel:"Git 内容",navigatorLabel:"Git 导航",handleLabel:"调整 Git 导航宽度",contentClassName:"git-content",navigatorClassName:"git-changes",children:[e.jsxs(e.Fragment,{children:[B&&u.selectedFileId?e.jsx("button",{type:"button",className:"git-back-to-list",onClick:()=>H(!1),children:"← 返回文件列表"}):null,u.view==="changes"?e.jsx($t,{groups:I,activeGroup:u.group,query:u.query,total:d?.counts.total??0,clean:d?.clean??!1,busy:a.busy,selectedFileIds:u.selectedFileIds,onQueryChange:c=>a.setSession({query:c,selectedFileId:null}),onGroupChange:c=>a.setSession({group:c,selectedFileId:null}),selectedFileId:u.selectedFileId,onSelect:c=>{a.setSession({selectedLineIds:[]}),H(!0),a.openFile(c)},onToggleSelection:a.toggleSelection,onClearSelection:a.clearSelection,onStage:c=>{a.stagePaths(c)},onUnstage:c=>{a.unstagePaths(c)}}):null,u.view==="history"?e.jsx("div",{className:"git-history-nav",children:e.jsx("p",{className:"git-history-nav-note",children:"提交列表与详情显示在右侧。"})}):null,u.view==="compare"?e.jsx(It,{refs:$.refs,actions:n,display:a.display,collapsedHunks:u.collapsedHunks,anchorLineId:u.anchorLineId,onDisplayChange:c=>a.setDisplay(c),onToggleHunk:c=>a.setSession({collapsedHunks:u.collapsedHunks.includes(c)?u.collapsedHunks.filter(M=>M!==c):[...u.collapsedHunks,c]}),onSetAllFolded:c=>a.setSession({collapsedHunks:c?u.collapsedHunks:[]}),onAnchorChange:c=>a.setSession({anchorLineId:c}),onNotice:j,onSendToComposer:i}):null]}),e.jsxs(e.Fragment,{children:[u.view==="changes"?a.selectedEntry?.source==="conflict"?e.jsx(Ft,{path:a.selectedEntry.path,actions:n}):S?e.jsxs("div",{children:[k?e.jsx("div",{className:"git-reveal-row",children:e.jsx("button",{type:"button",className:"text-button",onClick:k,children:"在 Files 打开"})}):null,u.selectedLineIds.length>0?e.jsxs("div",{className:"git-line-actions",role:"group","aria-label":"选中的行",children:[e.jsxs("span",{children:["已选 ",u.selectedLineIds.length," 行"]}),e.jsx("button",{type:"button",className:"secondary-button",disabled:a.busy,onClick:_,children:"暂存选中行"}),e.jsx("button",{type:"button",className:"text-button",onClick:()=>a.setSession({selectedLineIds:[]}),children:"清除"})]}):null,e.jsx(be,{hunkAction:R,ignoreWhitespace:a.display.ignoreWhitespace,onToggleIgnoreWhitespace:()=>a.setDisplay({ignoreWhitespace:!a.display.ignoreWhitespace}),wordDiff:a.display.wordDiff,onToggleWordDiff:()=>a.setDisplay({wordDiff:!a.display.wordDiff}),selectedLineIds:u.selectedLineIds,onToggleLine:c=>a.setSession({selectedLineIds:u.selectedLineIds.includes(c)?u.selectedLineIds.filter(M=>M!==c):[...u.selectedLineIds,c]}),document:S,mode:E,wrap:a.display.wrap,showWhitespace:a.display.showWhitespace,collapsedHunks:u.collapsedHunks,anchorLineId:u.anchorLineId,loading:a.loading,stale:a.stale,onChangeMode:c=>a.setDisplay({mode:c}),onToggleWrap:()=>a.setDisplay({wrap:!a.display.wrap}),onToggleWhitespace:()=>a.setDisplay({showWhitespace:!a.display.showWhitespace}),onToggleHunk:c=>a.setSession({collapsedHunks:u.collapsedHunks.includes(c)?u.collapsedHunks.filter(M=>M!==c):[...u.collapsedHunks,c]}),onSetAllFolded:c=>a.setSession({collapsedHunks:c?S.hunks.map(M=>M.hunkId):[]}),onAnchorChange:c=>a.setSession({anchorLineId:c}),onNotice:j,onLoadMore:S.nextCursor?a.loadMoreDiff:void 0,onSendToComposer:i})]}):e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"code",size:16}),e.jsx("strong",{children:"选择变更查看 Diff"}),e.jsx("p",{children:"同一文件的「未暂存」和「已暂存」是两个不同的比较目标。"})]}):null,u.view==="changes"?e.jsx(Rt,{preview:a.commitPreview,draft:u.commitDraft,busy:a.busy,onDraftChange:c=>a.setSession({commitDraft:c}),onCommit:c=>a.commit(c)}):null,u.view==="history"?e.jsx(Lt,{history:$,actions:n,display:a.display,collapsedHunks:u.collapsedHunks,anchorLineId:u.anchorLineId,onDisplayChange:c=>a.setDisplay(c),onToggleHunk:c=>a.setSession({collapsedHunks:u.collapsedHunks.includes(c)?u.collapsedHunks.filter(M=>M!==c):[...u.collapsedHunks,c]}),onSetAllFolded:c=>a.setSession({collapsedHunks:c?u.collapsedHunks:[]}),onAnchorChange:c=>a.setSession({anchorLineId:c}),onNotice:j,onSendToComposer:i}):null,u.view==="compare"?e.jsx(Pt,{title:"比较结果",stage:"S5"}):null]})]})]})}function Rt({preview:t,draft:s,busy:n,onDraftChange:i,onCommit:o}){const[h,g]=l.useState(!1),[x,a]=l.useState(""),p=t?.blockedReason??"正在读取暂存区…",j=!!t?.canCommit&&s.summary.trim().length>0&&!n,b=()=>{a(""),o({summary:s.summary,...s.body.trim()?{body:s.body}:{}}).catch(d=>a(d instanceof Error?d.message:"提交失败。"))};return e.jsxs("section",{className:"git-commit","aria-label":"提交",children:[e.jsxs("button",{type:"button",className:"git-commit-toggle","aria-expanded":h,onClick:()=>g(d=>!d),children:[h?"▾":"▸"," 提交 ",t?`${t.filesChanged} 个文件`:"",t&&(t.additions>0||t.deletions>0)?e.jsxs("span",{className:"git-commit-stats",children:[e.jsxs("em",{className:"diff-stat-add",children:["+",t.additions]})," ",e.jsxs("em",{className:"diff-stat-del",children:["-",t.deletions]})]}):null]}),h?e.jsxs("div",{className:"git-commit-body",children:[t?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"git-commit-meta",children:[t.detached?"detached HEAD":t.branch||"HEAD"," ·"," ",t.identity.name??"未配置 user.name"," <",t.identity.email??"未配置 user.email",">",t.identity.signingEnabled?" · 已启用签名":" · 未启用签名",` · hooks ${t.identity.hooksPresent?"存在":"不存在"}`]}),e.jsxs("ul",{className:"git-commit-files",children:[t.entries.slice(0,40).map(d=>e.jsxs("li",{children:[e.jsx("code",{children:d.status}),e.jsx("span",{children:d.path})]},`${d.source}:${d.path}`)),t.entries.length>40?e.jsxs("li",{className:"git-commit-more",children:["…还有 ",t.entries.length-40," 个文件"]}):null]})]}):null,e.jsxs("label",{children:[e.jsx("span",{children:"摘要"}),e.jsx("input",{type:"text",value:s.summary,maxLength:2e3,disabled:n,placeholder:"本次提交做了什么",onChange:d=>i({...s,summary:d.target.value})})]}),e.jsxs("label",{children:[e.jsx("span",{children:"正文(可选)"}),e.jsx("textarea",{value:s.body,rows:3,disabled:n,placeholder:"为什么这样做",onChange:d=>i({...s,body:d.target.value})})]}),x?e.jsx("p",{className:"resource-error",role:"alert",children:x}):null,e.jsxs("div",{className:"git-commit-actions",children:[e.jsx("button",{type:"button",className:"primary-button",disabled:!j,"aria-busy":n,onClick:b,children:n?"提交中…":"提交到本地索引"}),t?.canCommit?null:e.jsx("span",{className:"git-commit-blocked",children:p})]}),e.jsx("p",{className:"git-commit-note",children:"只提交本地 index:不自动暂存、不 amend、不 push。"})]}):null]})}function $t({groups:t,activeGroup:s,query:n,total:i,clean:o,busy:h,selectedFileIds:g,onQueryChange:x,onGroupChange:a,selectedFileId:p,onSelect:j,onToggleSelection:b,onClearSelection:d,onStage:S,onUnstage:u}){const _=new Set(g),L=g.length>0;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"git-filter",children:[e.jsx("input",{type:"search",value:n,"aria-label":"搜索文件路径",placeholder:"搜索文件…",onChange:v=>x(v.target.value)}),e.jsxs("div",{className:"git-filter-groups",role:"group","aria-label":"按分组筛选",children:[e.jsx("button",{type:"button","aria-pressed":s===null,onClick:()=>a(null),children:"全部"}),Se.map(v=>e.jsx("button",{type:"button","aria-pressed":s===v,onClick:()=>a(s===v?null:v),children:Ie[v]},v))]}),e.jsx("p",{className:"git-filter-summary",role:"status",children:i===0?n?"没有匹配的改动":"没有改动":`匹配 ${i} 个改动`}),L?e.jsxs("div",{className:"git-bulk",role:"group","aria-label":"对选中文件操作",children:[e.jsxs("span",{children:["已选 ",g.length," 个文件"]}),e.jsx("button",{type:"button",className:"secondary-button",disabled:h,onClick:()=>S(g),children:"暂存选中"}),e.jsx("button",{type:"button",className:"secondary-button",disabled:h,onClick:()=>u(g),children:"取消暂存选中"}),e.jsx("button",{type:"button",className:"text-button",onClick:d,children:"清除"})]}):null]}),o?e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(T,{name:"check"}),e.jsx("strong",{children:"工作区干净"})]}):t.map(v=>v.count?e.jsxs("div",{className:"git-group",children:[e.jsxs("h3",{children:[v.label," ",e.jsx("span",{children:v.count}),v.items.length<v.count?e.jsxs("small",{className:"git-group-loaded",children:["已载 ",v.items.length]}):null,v.source==="unstaged"||v.source==="untracked"?e.jsx("button",{type:"button",className:"text-button git-group-action",disabled:h,onClick:()=>S(v.items.map(N=>N.fileId)),children:"暂存该组已载"}):null,v.source==="staged"?e.jsx("button",{type:"button",className:"text-button git-group-action",disabled:h,onClick:()=>u(v.items.map(N=>N.fileId)),children:"取消暂存该组已载"}):null]}),v.items.map(N=>e.jsxs("div",{className:`git-row ${p===N.fileId?"selected":""}`,children:[e.jsx("input",{type:"checkbox","aria-label":`选择 ${N.path}`,checked:_.has(N.fileId),onChange:()=>b(N.fileId)}),e.jsxs("button",{type:"button",className:p===N.fileId?"selected":"","aria-current":p===N.fileId?"true":void 0,onClick:()=>j(N),children:[e.jsx("span",{className:`git-status-code ${v.source}`,children:N.indexStatus.trim()||N.worktreeStatus.trim()||"?"}),e.jsx("span",{title:N.path,children:N.renamedFrom?`${N.renamedFrom} → ${N.path}`:N.path})]}),v.source==="unstaged"||v.source==="untracked"?e.jsx("button",{type:"button",className:"text-button",disabled:h,"aria-label":`暂存 ${N.path}`,onClick:()=>S([N.fileId]),children:"暂存"}):null,v.source==="staged"?e.jsx("button",{type:"button",className:"text-button",disabled:h,"aria-label":`取消暂存 ${N.path}`,onClick:()=>u([N.fileId]),children:"取消"}):null,v.source==="conflict"?e.jsx("span",{className:"git-conflict-hint",children:"需在 Files 处理"}):null]},N.fileId))]},v.source):null)]})}function Pt({title:t,stage:s}){return e.jsxs("div",{className:"resource-empty",children:[e.jsx(T,{name:"info",size:16}),e.jsx("strong",{children:t}),e.jsxs("p",{children:["计划阶段 ",s," 交付,当前版本尚未实现。"]})]})}export{_t as GitPanel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as o,j as e,I as w,W as F}from"./index-
|
|
1
|
+
import{r as o,j as e,I as w,W as F}from"./index-D5ze0fOv.js";import{u as W,R as z}from"./useAutoNotice-Bsr8yfc3.js";function _(t){const r=[];let i;for(const u of t)u.startsWith("@@")?(i&&r.push(i),i={title:u,lines:[u]}):i&&i.lines.push(u);return i&&r.push(i),r}function M(t,r){const i={schemaVersion:1,type:"review_context",repositoryRevision:t.repositoryRevision,path:t.path,hunk:r.title},u=r.lines.join(`
|
|
2
2
|
`).slice(0,12e3);return[`请审阅 ${t.path} 的这个 diff hunk,并指出正确性、安全性和测试风险:`,"","```review_context",JSON.stringify(i,null,2),"```","","```diff",u,"```"].join(`
|
|
3
3
|
`)}function O({page:t,loading:r=!1,onLoadMore:i,onSendToComposer:u}){const h=o.useMemo(()=>_(t.lines),[t.lines]),[R,a]=o.useState(0),[g,b]=o.useState(!1),[y,C]=o.useState(!1),[v,S]=o.useState(""),j=Math.min(R,Math.max(0,h.length-1)),d=h[j];o.useEffect(()=>{a(0),b(!1),S("")},[t.fileId,t.repositoryRevision]);const k=(s,c)=>{let f=c;if(s.key==="ArrowRight"||s.key==="ArrowDown")f=(c+1)%h.length;else if(s.key==="ArrowLeft"||s.key==="ArrowUp")f=(c-1+h.length)%h.length;else if(s.key==="Home")f=0;else if(s.key==="End")f=h.length-1;else return;s.preventDefault(),a(f);const l=s.currentTarget.parentElement;window.requestAnimationFrame(()=>l?.querySelector(`[data-hunk-index="${f}"]`)?.focus())};return t.binary?e.jsxs("div",{className:"resource-empty compact",children:[e.jsx(w,{name:"code"}),e.jsx("strong",{children:"二进制差异"}),e.jsx("p",{children:"只展示变更事实,不返回 binary patch。"})]}):e.jsxs("div",{className:"diff-viewer",children:[e.jsxs("header",{children:[e.jsx("strong",{title:t.path,children:t.path}),e.jsx("span",{className:"diff-source",children:J(t.source)}),e.jsx("span",{children:t.truncated?"受限预览":`${t.lines.length} 行`})]}),h.length>1?e.jsx("div",{className:"diff-hunk-nav",role:"tablist","aria-label":"Diff hunks",children:h.map((s,c)=>e.jsx("button",{type:"button",role:"tab","data-hunk-index":c,"aria-selected":j===c,tabIndex:j===c?0:-1,onClick:()=>a(c),onKeyDown:f=>k(f,c),children:s.title||`Hunk ${c+1}`},`${s.title}-${c}`))}):null,e.jsxs("div",{className:"diff-actions","aria-label":"Diff 显示选项",children:[d?e.jsx("button",{type:"button",className:"text-button","aria-expanded":!g,onClick:()=>b(s=>!s),children:g?"展开 Hunk":"折叠 Hunk"}):null,e.jsx("button",{type:"button",className:"text-button","aria-pressed":y,onClick:()=>C(s=>!s),children:"显示空白字符"}),d?e.jsx("button",{type:"button",className:"text-button",onClick:()=>{K(d.lines.join(`
|
|
4
4
|
`),S)},children:"复制 Hunk"}):null]}),g?null:e.jsx("pre",{className:"diff-lines",tabIndex:0,"aria-label":`Diff ${t.path}`,children:(d?.lines??t.lines).map((s,c)=>e.jsxs("span",{className:s.startsWith("+")?"addition":s.startsWith("-")?"deletion":"",children:[V(s,y)||" ",`
|