@dungsil/dsh-plugin-ui-vcs 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +103 -88
- package/dist/index.js +182 -109
- package/package.json +2 -1
package/dist/client.js
CHANGED
|
@@ -23,6 +23,10 @@ var git_pull_request_draft_default = "<svg xmlns=\"http://www.w3.org/2000/svg\"
|
|
|
23
23
|
var git_pull_request_closed_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"2\"/>\n <circle cx=\"5\" cy=\"19\" r=\"2\"/>\n <circle cx=\"19\" cy=\"19\" r=\"2\"/>\n <path d=\"M5 7v10M19 17v-5M16 3l6 6m0-6-6 6\"/>\n</svg>\n";
|
|
24
24
|
// ../../tools/ui/src/icons/git-merge.svg
|
|
25
25
|
var git_merge_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"2\"/>\n <circle cx=\"5\" cy=\"19\" r=\"2\"/>\n <circle cx=\"19\" cy=\"19\" r=\"2\"/>\n <path d=\"M5 7v10M5 7a12 12 0 0 0 12 12\"/>\n</svg>\n";
|
|
26
|
+
// ../../tools/ui/src/icons/circle-x.svg
|
|
27
|
+
var circle_x_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <path d=\"m9 9 6 6m0-6-6 6\"/>\n</svg>\n";
|
|
28
|
+
// ../../tools/ui/src/icons/circle-minus.svg
|
|
29
|
+
var circle_minus_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <path d=\"M9 12h6\"/>\n</svg>\n";
|
|
26
30
|
// ../../tools/ui/src/client.ts
|
|
27
31
|
function useLocaleSnapshot(locale) {
|
|
28
32
|
const subscribe = (0, react.useCallback)((listener) => locale.subscribe(listener), [locale]);
|
|
@@ -57,6 +61,37 @@ function SettingsRow({ label, children }) {
|
|
|
57
61
|
}), children]
|
|
58
62
|
});
|
|
59
63
|
}
|
|
64
|
+
// ../../tools/ui/src/button-picker.tsx
|
|
65
|
+
function ButtonPicker({ label, value, items, onChange, disabled = false, menuClassName, compact, ...buttonProps }) {
|
|
66
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
67
|
+
(0, react.useEffect)(() => {
|
|
68
|
+
if (disabled) setOpen(false);
|
|
69
|
+
}, [disabled]);
|
|
70
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
71
|
+
open: open && !disabled,
|
|
72
|
+
portal: true,
|
|
73
|
+
compact,
|
|
74
|
+
className: menuClassName,
|
|
75
|
+
selectedId: value,
|
|
76
|
+
items,
|
|
77
|
+
onClose: () => setOpen(false),
|
|
78
|
+
onSelect: (id) => {
|
|
79
|
+
setOpen(false);
|
|
80
|
+
const item = items.find((item) => item.id === id && !item.disabled);
|
|
81
|
+
if (!disabled && item) onChange(item.id);
|
|
82
|
+
},
|
|
83
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
84
|
+
...buttonProps,
|
|
85
|
+
type: "button",
|
|
86
|
+
"aria-label": label,
|
|
87
|
+
"aria-haspopup": "menu",
|
|
88
|
+
"aria-expanded": open && !disabled,
|
|
89
|
+
disabled,
|
|
90
|
+
onClick: () => setOpen((current) => !current),
|
|
91
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: items.find((item) => item.id === value)?.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { "aria-hidden": "true" })]
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
}
|
|
60
95
|
// locale/en.json
|
|
61
96
|
var en_default = {
|
|
62
97
|
meta: {
|
|
@@ -13235,8 +13270,15 @@ const styles = `
|
|
|
13235
13270
|
.dsh-pr-loading{display:inline-flex;flex-shrink:0;width:16px;height:16px;vertical-align:middle;color:var(--dsw-alias-label-secondary)}
|
|
13236
13271
|
.dsh-pr-loading svg{width:100%;height:100%;animation:dsh-pr-spin .8s linear infinite}
|
|
13237
13272
|
.dsh-pr-initial-loading{display:flex;justify-content:center;padding:24px 16px}
|
|
13273
|
+
.dsh-vcs-check-status{display:inline-flex;flex:none;width:14px;height:14px;align-items:center;justify-content:center;vertical-align:middle;color:var(--dsw-alias-label-tertiary)}
|
|
13274
|
+
.dsh-vcs-check-status>span{display:contents}
|
|
13275
|
+
.dsh-vcs-check-status svg{width:100%;height:100%}
|
|
13276
|
+
.dsh-vcs-check-status[data-state=done]{color:var(--dsw-alias-state-success-primary)}
|
|
13277
|
+
.dsh-vcs-check-status[data-state=error]{color:var(--dsw-alias-state-error-primary)}
|
|
13278
|
+
.dsh-vcs-check-status:is([data-state=ongoing],[data-state=warning]){color:var(--dsw-alias-state-warn-primary)}
|
|
13279
|
+
.dsh-vcs-check-status[data-state=ongoing] svg{animation:dsh-pr-spin 1.5s linear infinite}
|
|
13238
13280
|
@keyframes dsh-pr-spin{to{transform:rotate(360deg)}}
|
|
13239
|
-
@media(prefers-reduced-motion:reduce){.dsh-pr-loading svg{animation:none}}
|
|
13281
|
+
@media(prefers-reduced-motion:reduce){.dsh-pr-loading svg,.dsh-vcs-check-status[data-state=ongoing] svg{animation:none}}
|
|
13240
13282
|
.dsh-pr-panel :is(a,textarea,summary,[role=tabpanel]):focus-visible{outline:2px solid var(--dsw-focus-ring-color);outline-offset:-2px}
|
|
13241
13283
|
.dsh-pr-content{overflow:auto;flex:1;min-height:0}
|
|
13242
13284
|
.dsh-pr-content>p{padding:20px 16px;color:var(--dsw-alias-label-secondary);line-height:1.6}
|
|
@@ -13356,6 +13398,7 @@ function bindPullRequestLinks(root, open) {
|
|
|
13356
13398
|
}
|
|
13357
13399
|
// src/pull-requests-client.tsx
|
|
13358
13400
|
var pull_requests_client_exports = /* @__PURE__ */ __exportAll({
|
|
13401
|
+
CheckStatusIcon: () => CheckStatusIcon,
|
|
13359
13402
|
apply: () => apply$2,
|
|
13360
13403
|
checksState: () => checksState,
|
|
13361
13404
|
inject: () => inject$1,
|
|
@@ -13398,6 +13441,14 @@ function checksState(item) {
|
|
|
13398
13441
|
].includes(state))) return "ongoing";
|
|
13399
13442
|
return states.every((state) => ["success", "passed"].includes(state)) ? "done" : "idle";
|
|
13400
13443
|
}
|
|
13444
|
+
function CheckStatusIcon({ state }) {
|
|
13445
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13446
|
+
className: "dsh-vcs-check-status",
|
|
13447
|
+
"data-state": state,
|
|
13448
|
+
"aria-hidden": "true",
|
|
13449
|
+
children: state === "done" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckCircleOutlineRegular, {}) : state === "ongoing" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular, {}) : state === "warning" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQuestionOutlineRegular, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: state === "error" ? circle_x_default : circle_minus_default } })
|
|
13450
|
+
});
|
|
13451
|
+
}
|
|
13401
13452
|
function Loading({ label }) {
|
|
13402
13453
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13403
13454
|
className: "dsh-pr-loading",
|
|
@@ -13430,37 +13481,6 @@ function Description({ text, labels }) {
|
|
|
13430
13481
|
variant: "compact"
|
|
13431
13482
|
}), render(sections)] });
|
|
13432
13483
|
}
|
|
13433
|
-
function Choice({ label, value, items, onChange, disabled }) {
|
|
13434
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
13435
|
-
(0, react.useEffect)(() => {
|
|
13436
|
-
if (disabled) setOpen(false);
|
|
13437
|
-
}, [disabled]);
|
|
13438
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
13439
|
-
open,
|
|
13440
|
-
portal: true,
|
|
13441
|
-
compact: true,
|
|
13442
|
-
className: "dsh-pr-choice",
|
|
13443
|
-
selectedId: value,
|
|
13444
|
-
items,
|
|
13445
|
-
onClose: () => setOpen(false),
|
|
13446
|
-
onSelect: (id) => {
|
|
13447
|
-
const item = items.find((item) => item.id === id && !item.disabled);
|
|
13448
|
-
if (item) onChange(item.id);
|
|
13449
|
-
setOpen(false);
|
|
13450
|
-
},
|
|
13451
|
-
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
13452
|
-
type: "button",
|
|
13453
|
-
size: "sm",
|
|
13454
|
-
className: "dsh-pr-picker",
|
|
13455
|
-
"aria-label": label,
|
|
13456
|
-
"aria-haspopup": "menu",
|
|
13457
|
-
"aria-expanded": open,
|
|
13458
|
-
disabled,
|
|
13459
|
-
onClick: () => setOpen(!open),
|
|
13460
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: items.find((item) => item.id === value)?.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { "aria-hidden": "true" })]
|
|
13461
|
-
})
|
|
13462
|
-
});
|
|
13463
|
-
}
|
|
13464
13484
|
function apply$2(ctx) {
|
|
13465
13485
|
const connection = ctx.get("connection");
|
|
13466
13486
|
const sessions = ctx.get("sessions");
|
|
@@ -13474,6 +13494,7 @@ function apply$2(ctx) {
|
|
|
13474
13494
|
function SessionRequest({ sessionId }) {
|
|
13475
13495
|
(0, react.useSyncExternalStore)(subscribe, () => ctx.locale.getSnapshot().active);
|
|
13476
13496
|
const copy = text();
|
|
13497
|
+
const current = (0, react.useSyncExternalStore)((listener) => ctx.sidebarRight.mounted.subscribe(listener), () => ctx.sidebarRight.mounted.getSnapshot() === sessionId);
|
|
13477
13498
|
const running = (0, react.useSyncExternalStore)((listener) => sessions.list.subscribe(listener), () => sessions.list.getSnapshot().byId[sessionId]?.running ?? false);
|
|
13478
13499
|
const cwd = (0, react.useSyncExternalStore)((listener) => sessions.list.subscribe(listener), () => sessions.list.getSnapshot().byId[sessionId]?.cwd);
|
|
13479
13500
|
const anchor = (0, react.useRef)(null);
|
|
@@ -13491,12 +13512,21 @@ function apply$2(ctx) {
|
|
|
13491
13512
|
return () => node.remove();
|
|
13492
13513
|
}, [sessionId]);
|
|
13493
13514
|
(0, react.useEffect)(() => {
|
|
13494
|
-
let active;
|
|
13495
13515
|
setView(void 0);
|
|
13516
|
+
}, [
|
|
13517
|
+
sessionId,
|
|
13518
|
+
current,
|
|
13519
|
+
cwd
|
|
13520
|
+
]);
|
|
13521
|
+
(0, react.useEffect)(() => {
|
|
13522
|
+
if (!current || running) return;
|
|
13523
|
+
let disposed = false;
|
|
13524
|
+
let active;
|
|
13496
13525
|
const refresh = async () => {
|
|
13497
|
-
active
|
|
13498
|
-
|
|
13499
|
-
|
|
13526
|
+
if (disposed || active || document.visibilityState === "hidden") return;
|
|
13527
|
+
const controller = new AbortController();
|
|
13528
|
+
active = controller;
|
|
13529
|
+
const { signal } = controller;
|
|
13500
13530
|
try {
|
|
13501
13531
|
const result = await connection.rpc.call(channel$1, method, {
|
|
13502
13532
|
sessionId,
|
|
@@ -13505,22 +13535,28 @@ function apply$2(ctx) {
|
|
|
13505
13535
|
if (!signal.aborted) setView(result.ok ? result.value : void 0);
|
|
13506
13536
|
} catch {
|
|
13507
13537
|
if (!signal.aborted) setView(void 0);
|
|
13538
|
+
} finally {
|
|
13539
|
+
if (active === controller) active = void 0;
|
|
13508
13540
|
}
|
|
13509
13541
|
};
|
|
13510
13542
|
refresh();
|
|
13511
13543
|
window.addEventListener("focus", refresh);
|
|
13544
|
+
document.addEventListener("visibilitychange", refresh);
|
|
13512
13545
|
const interval = window.setInterval(refresh, 6e4);
|
|
13513
13546
|
return () => {
|
|
13547
|
+
disposed = true;
|
|
13514
13548
|
active?.abort();
|
|
13515
13549
|
window.removeEventListener("focus", refresh);
|
|
13550
|
+
document.removeEventListener("visibilitychange", refresh);
|
|
13516
13551
|
window.clearInterval(interval);
|
|
13517
13552
|
};
|
|
13518
13553
|
}, [
|
|
13519
13554
|
sessionId,
|
|
13555
|
+
current,
|
|
13520
13556
|
running,
|
|
13521
13557
|
cwd
|
|
13522
13558
|
]);
|
|
13523
|
-
const item = view?.request;
|
|
13559
|
+
const item = current ? view?.request : void 0;
|
|
13524
13560
|
const state = item?.state === "open" && item.draft ? "draft" : item?.state;
|
|
13525
13561
|
const icon = state === "merged" ? git_merge_default : state === "closed" ? git_pull_request_closed_default : state === "draft" ? git_pull_request_draft_default : git_pull_request_default;
|
|
13526
13562
|
const label = item && state ? `${copy.title} ${view?.provider === "gitlab" ? "!" : "#"}${item.number}: ${copy[state]}` : "";
|
|
@@ -13894,10 +13930,7 @@ function apply$2(ctx) {
|
|
|
13894
13930
|
onClick: () => setChecksOpen(!checksOpen),
|
|
13895
13931
|
"aria-busy": loading,
|
|
13896
13932
|
children: [
|
|
13897
|
-
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Loading, { label: copy.loading }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
13898
|
-
state,
|
|
13899
|
-
appearance: "step"
|
|
13900
|
-
}),
|
|
13933
|
+
loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Loading, { label: copy.loading }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckStatusIcon, { state }),
|
|
13901
13934
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.headSha ? checksSummary : copy.checks }),
|
|
13902
13935
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { "aria-hidden": "true" })
|
|
13903
13936
|
]
|
|
@@ -13913,10 +13946,7 @@ function apply$2(ctx) {
|
|
|
13913
13946
|
className: "dsh-pr-checks",
|
|
13914
13947
|
children: item.checks.map((check, index) => {
|
|
13915
13948
|
const status = checkStatus(check.status);
|
|
13916
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
13917
|
-
state: status.state,
|
|
13918
|
-
appearance: "step"
|
|
13919
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
13949
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckStatusIcon, { state: status.state }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
13920
13950
|
className: "dsh-pr-check-name",
|
|
13921
13951
|
children: [check.url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
13922
13952
|
href: check.url,
|
|
@@ -14074,7 +14104,11 @@ function apply$2(ctx) {
|
|
|
14074
14104
|
})] }),
|
|
14075
14105
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14076
14106
|
className: "dsh-pr-actions",
|
|
14077
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
14107
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonPicker, {
|
|
14108
|
+
size: "sm",
|
|
14109
|
+
className: "dsh-pr-picker",
|
|
14110
|
+
menuClassName: "dsh-pr-choice",
|
|
14111
|
+
compact: true,
|
|
14078
14112
|
label: copy.review,
|
|
14079
14113
|
value: reviewAction,
|
|
14080
14114
|
disabled: pending,
|
|
@@ -14279,7 +14313,6 @@ const copy$1 = {
|
|
|
14279
14313
|
invalid: "이름과 올바른 이메일을 함께 입력하거나 두 항목을 모두 비우세요.",
|
|
14280
14314
|
cli: "CLI 인증 상태",
|
|
14281
14315
|
refresh: "새로고침",
|
|
14282
|
-
selectSession: "CLI 상태를 확인하려면 세션을 먼저 여세요.",
|
|
14283
14316
|
authenticated: "인증됨",
|
|
14284
14317
|
unauthenticated: "인증되지 않음",
|
|
14285
14318
|
unavailable: "설치되지 않음",
|
|
@@ -14303,7 +14336,6 @@ const copy$1 = {
|
|
|
14303
14336
|
invalid: "Enter both a name and a valid email, or leave both fields empty.",
|
|
14304
14337
|
cli: "CLI authentication",
|
|
14305
14338
|
refresh: "Refresh",
|
|
14306
|
-
selectSession: "Open a session to check CLI status.",
|
|
14307
14339
|
authenticated: "Authenticated",
|
|
14308
14340
|
unauthenticated: "Not authenticated",
|
|
14309
14341
|
unavailable: "Not installed",
|
|
@@ -14327,7 +14359,6 @@ const copy$1 = {
|
|
|
14327
14359
|
invalid: "请输入姓名和有效邮箱,或将两个字段都留空。",
|
|
14328
14360
|
cli: "CLI 认证状态",
|
|
14329
14361
|
refresh: "刷新",
|
|
14330
|
-
selectSession: "请先打开会话以检查 CLI 状态。",
|
|
14331
14362
|
authenticated: "已认证",
|
|
14332
14363
|
unauthenticated: "未认证",
|
|
14333
14364
|
unavailable: "未安装",
|
|
@@ -14343,7 +14374,6 @@ function VcsSettings({ ctx }) {
|
|
|
14343
14374
|
const text = localized(active);
|
|
14344
14375
|
const id = (0, react.useId)();
|
|
14345
14376
|
const connection = ctx.get("connection");
|
|
14346
|
-
const sessionId = (0, react.useSyncExternalStore)((listener) => ctx.sidebarRight.mounted.subscribe(listener), () => ctx.sidebarRight.mounted.getSnapshot());
|
|
14347
14377
|
const [view, setView] = (0, react.useState)();
|
|
14348
14378
|
const [draft, setDraft] = (0, react.useState)();
|
|
14349
14379
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
@@ -14378,21 +14408,14 @@ function VcsSettings({ ctx }) {
|
|
|
14378
14408
|
const controller = new AbortController();
|
|
14379
14409
|
lifetime.current = controller;
|
|
14380
14410
|
load(controller.signal);
|
|
14411
|
+
check(controller.signal);
|
|
14381
14412
|
return () => controller.abort();
|
|
14382
14413
|
}, []);
|
|
14383
|
-
(0, react.useEffect)(() => {
|
|
14384
|
-
const controller = new AbortController();
|
|
14385
|
-
setCli(void 0);
|
|
14386
|
-
setCliError(false);
|
|
14387
|
-
setChecking(false);
|
|
14388
|
-
if (sessionId) check(controller.signal);
|
|
14389
|
-
return () => controller.abort();
|
|
14390
|
-
}, [sessionId]);
|
|
14391
14414
|
const check = async (signal) => {
|
|
14392
14415
|
setChecking(true);
|
|
14393
14416
|
setCliError(false);
|
|
14394
14417
|
try {
|
|
14395
|
-
const result = await connection.rpc.call(channel, "dungsil-vcs/cli-status", {
|
|
14418
|
+
const result = await connection.rpc.call(channel, "dungsil-vcs/cli-status", {}, signal);
|
|
14396
14419
|
if (signal.aborted) return;
|
|
14397
14420
|
if (!result.ok) throw new Error("unavailable");
|
|
14398
14421
|
setCli(result.value);
|
|
@@ -14452,7 +14475,6 @@ function VcsSettings({ ctx }) {
|
|
|
14452
14475
|
className: "dsh-vcs-settings",
|
|
14453
14476
|
"aria-label": text.nav,
|
|
14454
14477
|
children: [
|
|
14455
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text.scope }),
|
|
14456
14478
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
14457
14479
|
onSubmit: (event) => {
|
|
14458
14480
|
event.preventDefault();
|
|
@@ -14463,6 +14485,7 @@ function VcsSettings({ ctx }) {
|
|
|
14463
14485
|
disabled: blocked,
|
|
14464
14486
|
children: [
|
|
14465
14487
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: text.author }),
|
|
14488
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text.scope }),
|
|
14466
14489
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text.authorHint }),
|
|
14467
14490
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
14468
14491
|
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
@@ -14545,31 +14568,26 @@ function VcsSettings({ ctx }) {
|
|
|
14545
14568
|
]
|
|
14546
14569
|
}),
|
|
14547
14570
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: text.cli }),
|
|
14548
|
-
|
|
14571
|
+
checking && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
14549
14572
|
role: "status",
|
|
14550
|
-
children: text.
|
|
14551
|
-
})
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
account.login,
|
|
14569
|
-
account.method && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" · ", text[account.method]] })
|
|
14570
|
-
] }, index))]
|
|
14571
|
-
}, item.cli))
|
|
14572
|
-
] })
|
|
14573
|
+
children: text.loading
|
|
14574
|
+
}),
|
|
14575
|
+
cliError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
14576
|
+
role: "alert",
|
|
14577
|
+
children: text.error
|
|
14578
|
+
}),
|
|
14579
|
+
cli?.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14580
|
+
className: "dsh-vcs-settings-cli",
|
|
14581
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
14582
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: item.cli }),
|
|
14583
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text[item.status === "error" ? "errorStatus" : item.status] })
|
|
14584
|
+
}), item.accounts.map((account, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
14585
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: account.host }),
|
|
14586
|
+
" · ",
|
|
14587
|
+
account.login,
|
|
14588
|
+
account.method && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" · ", text[account.method]] })
|
|
14589
|
+
] }, index))]
|
|
14590
|
+
}, item.cli))
|
|
14573
14591
|
]
|
|
14574
14592
|
});
|
|
14575
14593
|
}
|
|
@@ -14823,10 +14841,7 @@ function apply(ctx) {
|
|
|
14823
14841
|
className: "dsh-vcs-trigger",
|
|
14824
14842
|
title: `${labels.checks}: ${ciLabel}`,
|
|
14825
14843
|
onClick: () => ctx.sidebarRight.openTab("dungsil-vcs-pull-requests", { params: { section: "checks" } }),
|
|
14826
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
14827
|
-
state: ciState,
|
|
14828
|
-
appearance: "step"
|
|
14829
|
-
}), `${labels.checks}: ${ciLabel}`]
|
|
14844
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckStatusIcon, { state: ciState }), `${labels.checks}: ${ciLabel}`]
|
|
14830
14845
|
})]
|
|
14831
14846
|
});
|
|
14832
14847
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { clientRequestSchema } from "@deepseek-ai/dsh-client-connection";
|
|
3
|
-
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
3
|
+
import { Session, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
5
5
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
|
+
import { homedir } from "node:os";
|
|
7
8
|
// \0rolldown/runtime.js
|
|
8
9
|
var __defProp = Object.defineProperty;
|
|
9
10
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -900,6 +901,69 @@ defineMethod("transform", [
|
|
|
900
901
|
"callback",
|
|
901
902
|
"preserve"
|
|
902
903
|
], ({ inner }, isInner) => inner.toString(isInner));
|
|
904
|
+
// src/inspect-session.ts
|
|
905
|
+
async function inspectSession(ctx, id, signal) {
|
|
906
|
+
signal.throwIfAborted();
|
|
907
|
+
const live = ctx.get("agents")?.get(id);
|
|
908
|
+
if (live) return live.session;
|
|
909
|
+
const inspection = await ctx.sessionController.inspect(id, signal);
|
|
910
|
+
signal.throwIfAborted();
|
|
911
|
+
return Session.create(id, inspection.events, inspection.meta, inspection.inheritedEventCount);
|
|
912
|
+
}
|
|
913
|
+
// ../../tools/async/src/index.ts
|
|
914
|
+
function createTaskQueue({ concurrency, maxPending }) {
|
|
915
|
+
if (!Number.isSafeInteger(concurrency) || concurrency < 1 || !Number.isSafeInteger(maxPending) || maxPending < 0) throw new RangeError("Invalid task queue limits");
|
|
916
|
+
let active = 0;
|
|
917
|
+
const pending = /* @__PURE__ */ new Set();
|
|
918
|
+
const drain = () => {
|
|
919
|
+
while (active < concurrency && pending.size) pending.values().next().value.start();
|
|
920
|
+
};
|
|
921
|
+
return (signal, task) => {
|
|
922
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
923
|
+
if (active >= concurrency && pending.size >= maxPending) return Promise.reject(/* @__PURE__ */ new Error("busy"));
|
|
924
|
+
return new Promise((resolve, reject) => {
|
|
925
|
+
const entry = {
|
|
926
|
+
start() {
|
|
927
|
+
pending.delete(entry);
|
|
928
|
+
signal.removeEventListener("abort", entry.cancel);
|
|
929
|
+
active++;
|
|
930
|
+
(async () => {
|
|
931
|
+
try {
|
|
932
|
+
signal.throwIfAborted();
|
|
933
|
+
resolve(await task());
|
|
934
|
+
} catch (error) {
|
|
935
|
+
reject(error);
|
|
936
|
+
} finally {
|
|
937
|
+
active--;
|
|
938
|
+
drain();
|
|
939
|
+
}
|
|
940
|
+
})();
|
|
941
|
+
},
|
|
942
|
+
cancel() {
|
|
943
|
+
pending.delete(entry);
|
|
944
|
+
signal.removeEventListener("abort", entry.cancel);
|
|
945
|
+
reject(signal.reason);
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
pending.add(entry);
|
|
949
|
+
signal.addEventListener("abort", entry.cancel, { once: true });
|
|
950
|
+
drain();
|
|
951
|
+
});
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
// src/read-queue.ts
|
|
955
|
+
const queues = /* @__PURE__ */ new WeakMap();
|
|
956
|
+
function readQueue(provider) {
|
|
957
|
+
let queue = queues.get(provider);
|
|
958
|
+
if (!queue) {
|
|
959
|
+
queue = createTaskQueue({
|
|
960
|
+
concurrency: 2,
|
|
961
|
+
maxPending: 128
|
|
962
|
+
});
|
|
963
|
+
queues.set(provider, queue);
|
|
964
|
+
}
|
|
965
|
+
return queue;
|
|
966
|
+
}
|
|
903
967
|
// src/pull-requests-protocol.ts
|
|
904
968
|
const channel$1 = "/api";
|
|
905
969
|
const method = "dungsil-vcs/pull-requests/list";
|
|
@@ -975,9 +1039,10 @@ function actionInput$1(value) {
|
|
|
975
1039
|
function apply$3(ctx, config) {
|
|
976
1040
|
const lifetime = new AbortController();
|
|
977
1041
|
const actionsInFlight = /* @__PURE__ */ new Set();
|
|
1042
|
+
const read = readQueue(ctx.subprocess);
|
|
978
1043
|
ctx.effect(() => () => lifetime.abort());
|
|
979
|
-
const list = async (
|
|
980
|
-
const cwd = ctx.workingDirectory.get(
|
|
1044
|
+
const list = async (session, signal, action, requested, summary = false) => {
|
|
1045
|
+
const cwd = ctx.workingDirectory.get(session);
|
|
981
1046
|
const run = async (executable, args, failure = "command_failed", allowed = [0], trim = true) => {
|
|
982
1047
|
let resolved;
|
|
983
1048
|
try {
|
|
@@ -986,7 +1051,7 @@ function apply$3(ctx, config) {
|
|
|
986
1051
|
throw new Error(executable === "git" ? "repository" : "cli_missing");
|
|
987
1052
|
}
|
|
988
1053
|
const argv = [resolved, ...args];
|
|
989
|
-
const policy = ctx.sandboxPolicy.resolve({ session
|
|
1054
|
+
const policy = ctx.sandboxPolicy.resolve({ session });
|
|
990
1055
|
const command = policy.mode === "danger-full-access" ? argv : (await ctx.sandbox.confine(argv, {
|
|
991
1056
|
...policy,
|
|
992
1057
|
mode: policy.mode
|
|
@@ -1119,7 +1184,7 @@ function apply$3(ctx, config) {
|
|
|
1119
1184
|
if (requested.origin !== new URL(origin).origin || provider === "github" && repository.split("/").length !== 2 || !match || !Number.isSafeInteger(Number(match[2]))) throw new Error("unsupported");
|
|
1120
1185
|
if (provider === "github" ? match[1].toLowerCase() !== prefix.toLowerCase() : match[1] !== prefix) {
|
|
1121
1186
|
if (provider === "gitlab") throw new Error("unsupported");
|
|
1122
|
-
const associated = await list(
|
|
1187
|
+
const associated = await list(session, signal, void 0, void 0, summary);
|
|
1123
1188
|
const linkedUrl = `${requested.origin}${match[1]}/${provider === "github" ? "pull" : forge ? "pulls" : "-/merge_requests"}/${match[2]}`;
|
|
1124
1189
|
if ("request" in associated && associated.request && (provider === "github" ? associated.request.url.toLowerCase() === linkedUrl.toLowerCase() : associated.request.url === linkedUrl)) return associated;
|
|
1125
1190
|
throw new Error("unsupported");
|
|
@@ -1714,14 +1779,24 @@ function apply$3(ctx, config) {
|
|
|
1714
1779
|
inFlight = action.sessionId;
|
|
1715
1780
|
}
|
|
1716
1781
|
const requested = route === "dungsil-vcs/pull-requests/list" && input.requestUrl !== void 0 ? lookupUrl(input.requestUrl) : void 0;
|
|
1717
|
-
const resolved = await ctx.sessionController.resolveAgent(SessionId(input.sessionId));
|
|
1718
|
-
if ("error" in resolved) throw new Error("unavailable");
|
|
1719
1782
|
const signal = AbortSignal.any([
|
|
1720
1783
|
request.signal,
|
|
1721
1784
|
lifetime.signal,
|
|
1722
1785
|
AbortSignal.timeout(2e4)
|
|
1723
1786
|
]);
|
|
1724
|
-
const
|
|
1787
|
+
const sessionId = SessionId(input.sessionId);
|
|
1788
|
+
const execute = async () => {
|
|
1789
|
+
signal.throwIfAborted();
|
|
1790
|
+
let session;
|
|
1791
|
+
if (action) {
|
|
1792
|
+
const resolved = await ctx.sessionController.resolveAgent(sessionId);
|
|
1793
|
+
if ("error" in resolved) throw new Error("unavailable");
|
|
1794
|
+
signal.throwIfAborted();
|
|
1795
|
+
session = resolved.agent.session;
|
|
1796
|
+
} else session = await inspectSession(ctx, sessionId, signal);
|
|
1797
|
+
return list(session, signal, action, requested, input.summary === true);
|
|
1798
|
+
};
|
|
1799
|
+
const value = action ? await execute() : await read(signal, execute);
|
|
1725
1800
|
if (action && !("completed" in value)) throw new Error("stale_request");
|
|
1726
1801
|
return reply({
|
|
1727
1802
|
ok: true,
|
|
@@ -5062,8 +5137,6 @@ const name$1 = "dungsil-vcs-settings";
|
|
|
5062
5137
|
const inject$1 = [
|
|
5063
5138
|
"connection",
|
|
5064
5139
|
"configEditor",
|
|
5065
|
-
"sessionController",
|
|
5066
|
-
"workingDirectory",
|
|
5067
5140
|
"subprocess",
|
|
5068
5141
|
"sandbox",
|
|
5069
5142
|
"sandboxPolicy"
|
|
@@ -5143,12 +5216,6 @@ function apply$1(ctx) {
|
|
|
5143
5216
|
value: snapshot()
|
|
5144
5217
|
};
|
|
5145
5218
|
} else {
|
|
5146
|
-
const sessionId = body.payload?.sessionId;
|
|
5147
|
-
if (typeof sessionId !== "string" || !sessionId || sessionId.length > 256) throw new Error("invalid");
|
|
5148
|
-
const resolved = await ctx.sessionController.resolveAgent(SessionId(sessionId));
|
|
5149
|
-
if ("error" in resolved) throw new Error("unavailable");
|
|
5150
|
-
const { agent } = resolved;
|
|
5151
|
-
const cwd = await ctx.workingDirectory.ensure(agent, signal);
|
|
5152
5219
|
const value = await inspectCliStatus(async (executable, args) => {
|
|
5153
5220
|
const bounded = AbortSignal.any([signal, AbortSignal.timeout(1e4)]);
|
|
5154
5221
|
let path;
|
|
@@ -5159,14 +5226,14 @@ function apply$1(ctx) {
|
|
|
5159
5226
|
throw error;
|
|
5160
5227
|
}
|
|
5161
5228
|
const argv = [path, ...args];
|
|
5162
|
-
const policy = ctx.sandboxPolicy.resolve(
|
|
5229
|
+
const policy = ctx.sandboxPolicy.resolve();
|
|
5163
5230
|
const command = policy.mode === "danger-full-access" ? argv : (await ctx.sandbox.confine(argv, {
|
|
5164
5231
|
...policy,
|
|
5165
5232
|
mode: policy.mode
|
|
5166
5233
|
}, bounded)).argv;
|
|
5167
5234
|
const child = ctx.subprocess.spawn({
|
|
5168
5235
|
argv: command,
|
|
5169
|
-
cwd,
|
|
5236
|
+
cwd: homedir(),
|
|
5170
5237
|
signal: bounded,
|
|
5171
5238
|
graceMs: 1e3,
|
|
5172
5239
|
env: {
|
|
@@ -5205,7 +5272,6 @@ function apply$1(ctx) {
|
|
|
5205
5272
|
}
|
|
5206
5273
|
});
|
|
5207
5274
|
signal.throwIfAborted();
|
|
5208
|
-
if (ctx.workingDirectory.get(agent.session) !== cwd) throw new Error("conflict");
|
|
5209
5275
|
result = {
|
|
5210
5276
|
ok: true,
|
|
5211
5277
|
value
|
|
@@ -5241,6 +5307,9 @@ const inject = [
|
|
|
5241
5307
|
"workingDirectory"
|
|
5242
5308
|
];
|
|
5243
5309
|
function apply(ctx, config) {
|
|
5310
|
+
const lifetime = new AbortController();
|
|
5311
|
+
const read = readQueue(ctx.subprocess);
|
|
5312
|
+
ctx.effect(() => () => lifetime.abort(), "ui-vcs: cancel context reads");
|
|
5244
5313
|
ctx.plugin(pull_requests_exports, config);
|
|
5245
5314
|
ctx.plugin(commands_exports, config);
|
|
5246
5315
|
ctx.plugin(settings_exports);
|
|
@@ -5265,100 +5334,104 @@ function apply(ctx, config) {
|
|
|
5265
5334
|
if (body.method !== "dungsil-vcs/describe") throw new Error("Invalid method");
|
|
5266
5335
|
const sessionId = body.payload?.sessionId;
|
|
5267
5336
|
if (typeof sessionId !== "string" || !sessionId) throw new Error("Invalid session");
|
|
5268
|
-
const
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
const cwd = await ctx.workingDirectory.ensure(agent, signal);
|
|
5273
|
-
const git = async (args) => {
|
|
5274
|
-
const argv = [
|
|
5275
|
-
await ctx.subprocess.resolveExecutable("git", void 0, signal),
|
|
5276
|
-
"-c",
|
|
5277
|
-
"core.fsmonitor=false",
|
|
5278
|
-
"-c",
|
|
5279
|
-
"core.hooksPath=/dev/null",
|
|
5280
|
-
...args
|
|
5281
|
-
];
|
|
5282
|
-
const policy = ctx.sandboxPolicy.resolve({ session: agent.session });
|
|
5283
|
-
const command = policy.mode === "danger-full-access" ? argv : (await ctx.sandbox.confine(argv, {
|
|
5284
|
-
...policy,
|
|
5285
|
-
mode: policy.mode
|
|
5286
|
-
}, signal)).argv;
|
|
5287
|
-
const child = ctx.subprocess.spawn({
|
|
5288
|
-
argv: command,
|
|
5289
|
-
cwd,
|
|
5290
|
-
signal,
|
|
5291
|
-
graceMs: 1e3,
|
|
5292
|
-
env: {
|
|
5293
|
-
...Object.fromEntries(Object.keys(process.env).filter((key) => key.startsWith("GIT_")).map((key) => [key, void 0])),
|
|
5294
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
5295
|
-
GIT_OPTIONAL_LOCKS: "0",
|
|
5296
|
-
GIT_NO_LAZY_FETCH: "1"
|
|
5297
|
-
},
|
|
5298
|
-
stdio: {
|
|
5299
|
-
stdin: "ignore",
|
|
5300
|
-
stdout: { maxBytes: 65536 },
|
|
5301
|
-
stderr: { maxBytes: 4096 }
|
|
5302
|
-
}
|
|
5303
|
-
});
|
|
5304
|
-
try {
|
|
5305
|
-
const outcome = await child.done;
|
|
5306
|
-
signal.throwIfAborted();
|
|
5307
|
-
const output = child.collected.stdout.readFrom(0);
|
|
5308
|
-
if (outcome.exitCode !== 0 || output.lossy) throw new Error("Git read failed");
|
|
5309
|
-
return output.text.replace(/\r?\n$/, "");
|
|
5310
|
-
} finally {
|
|
5311
|
-
child.terminate();
|
|
5312
|
-
await child.waitForExit();
|
|
5313
|
-
}
|
|
5314
|
-
};
|
|
5315
|
-
const gitDir = await git([
|
|
5316
|
-
"rev-parse",
|
|
5317
|
-
"--path-format=absolute",
|
|
5318
|
-
"--git-dir"
|
|
5319
|
-
]);
|
|
5320
|
-
const commonDir = await git([
|
|
5321
|
-
"rev-parse",
|
|
5322
|
-
"--path-format=absolute",
|
|
5323
|
-
"--git-common-dir"
|
|
5337
|
+
const signal = AbortSignal.any([
|
|
5338
|
+
request.signal,
|
|
5339
|
+
lifetime.signal,
|
|
5340
|
+
AbortSignal.timeout(1e4)
|
|
5324
5341
|
]);
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
const
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5342
|
+
result = await read(signal, async () => {
|
|
5343
|
+
const session = await inspectSession(ctx, SessionId(sessionId), signal);
|
|
5344
|
+
const cwd = ctx.workingDirectory.get(session);
|
|
5345
|
+
const git = async (args) => {
|
|
5346
|
+
const argv = [
|
|
5347
|
+
await ctx.subprocess.resolveExecutable("git", void 0, signal),
|
|
5348
|
+
"-c",
|
|
5349
|
+
"core.fsmonitor=false",
|
|
5350
|
+
"-c",
|
|
5351
|
+
"core.hooksPath=/dev/null",
|
|
5352
|
+
...args
|
|
5353
|
+
];
|
|
5354
|
+
const policy = ctx.sandboxPolicy.resolve({ session });
|
|
5355
|
+
const command = policy.mode === "danger-full-access" ? argv : (await ctx.sandbox.confine(argv, {
|
|
5356
|
+
...policy,
|
|
5357
|
+
mode: policy.mode
|
|
5358
|
+
}, signal)).argv;
|
|
5359
|
+
const child = ctx.subprocess.spawn({
|
|
5360
|
+
argv: command,
|
|
5361
|
+
cwd,
|
|
5362
|
+
signal,
|
|
5363
|
+
graceMs: 1e3,
|
|
5364
|
+
env: {
|
|
5365
|
+
...Object.fromEntries(Object.keys(process.env).filter((key) => key.startsWith("GIT_")).map((key) => [key, void 0])),
|
|
5366
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
5367
|
+
GIT_OPTIONAL_LOCKS: "0",
|
|
5368
|
+
GIT_NO_LAZY_FETCH: "1"
|
|
5369
|
+
},
|
|
5370
|
+
stdio: {
|
|
5371
|
+
stdin: "ignore",
|
|
5372
|
+
stdout: { maxBytes: 65536 },
|
|
5373
|
+
stderr: { maxBytes: 4096 }
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
5376
|
+
try {
|
|
5377
|
+
const outcome = await child.done;
|
|
5378
|
+
signal.throwIfAborted();
|
|
5379
|
+
const output = child.collected.stdout.readFrom(0);
|
|
5380
|
+
if (outcome.exitCode !== 0 || output.lossy) throw new Error("Git read failed");
|
|
5381
|
+
return output.text.replace(/\r?\n$/, "");
|
|
5382
|
+
} finally {
|
|
5383
|
+
child.terminate();
|
|
5384
|
+
await child.waitForExit();
|
|
5385
|
+
}
|
|
5386
|
+
};
|
|
5387
|
+
const gitDir = await git([
|
|
5388
|
+
"rev-parse",
|
|
5389
|
+
"--path-format=absolute",
|
|
5390
|
+
"--git-dir"
|
|
5332
5391
|
]);
|
|
5333
|
-
const
|
|
5334
|
-
"
|
|
5335
|
-
"--format
|
|
5336
|
-
|
|
5392
|
+
const commonDir = await git([
|
|
5393
|
+
"rev-parse",
|
|
5394
|
+
"--path-format=absolute",
|
|
5395
|
+
"--git-common-dir"
|
|
5337
5396
|
]);
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5397
|
+
let operation = "pr";
|
|
5398
|
+
if (gitDir === commonDir) {
|
|
5399
|
+
const branch = await git([
|
|
5400
|
+
"symbolic-ref",
|
|
5401
|
+
"--quiet",
|
|
5402
|
+
"--short",
|
|
5403
|
+
"HEAD"
|
|
5404
|
+
]);
|
|
5405
|
+
const upstream = await git([
|
|
5406
|
+
"for-each-ref",
|
|
5407
|
+
"--format=%(upstream:remotename)",
|
|
5408
|
+
`refs/heads/${branch}`
|
|
5409
|
+
]);
|
|
5410
|
+
const remotes = (await git(["remote"])).split("\n").filter(Boolean);
|
|
5411
|
+
const remote = upstream && upstream !== "." ? upstream : remotes.includes("origin") ? "origin" : remotes.length === 1 ? remotes[0] : void 0;
|
|
5412
|
+
if (!remote) throw new Error("Default remote unknown");
|
|
5413
|
+
operation = await git([
|
|
5414
|
+
"symbolic-ref",
|
|
5415
|
+
"--quiet",
|
|
5416
|
+
`refs/remotes/${remote}/HEAD`
|
|
5417
|
+
]) === `refs/remotes/${remote}/${branch}` ? "push" : "pr";
|
|
5359
5418
|
}
|
|
5360
|
-
|
|
5361
|
-
|
|
5419
|
+
const headSha = await git(["rev-parse", "HEAD"]);
|
|
5420
|
+
const dirty = !!await git([
|
|
5421
|
+
"status",
|
|
5422
|
+
"--porcelain",
|
|
5423
|
+
"--untracked-files=normal"
|
|
5424
|
+
]);
|
|
5425
|
+
if (ctx.workingDirectory.get(session) !== cwd) throw new Error("Working directory changed");
|
|
5426
|
+
return {
|
|
5427
|
+
ok: true,
|
|
5428
|
+
value: {
|
|
5429
|
+
operation,
|
|
5430
|
+
headSha,
|
|
5431
|
+
dirty
|
|
5432
|
+
}
|
|
5433
|
+
};
|
|
5434
|
+
});
|
|
5362
5435
|
} catch {
|
|
5363
5436
|
result = failure;
|
|
5364
5437
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dungsil/dsh-plugin-ui-vcs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Git actions and PR/MR review for GitHub, GitLab, Gitea and Forgejo.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"@deepseek-ai/dsh-subprocess-local": "0.2.1-rc.5",
|
|
53
53
|
"@deepseek-ai/dsh-working-directory": "0.2.1-rc.5",
|
|
54
54
|
"@deepseek-ai/schemastery": "~3.18.5",
|
|
55
|
+
"@dungsil/dsh-async": "0.0.0",
|
|
55
56
|
"@dungsil/dsh-tsconfig": "0.0.0",
|
|
56
57
|
"@dungsil/dsh-ui": "0.0.0",
|
|
57
58
|
"@types/react": "18.3.31",
|