@klarkxy/dsh-git-commit 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,42 @@
1
+ The Star And Thank Author License (SATA)
2
+ Version 2.1, September 2026
3
+
4
+ Copyright © 2026 Klarkxy(278370456@qq.com)
5
+
6
+ Project Url: https://github.com/klarkxy/dsh-editor
7
+ https://github.com/klarkxy/sata-license
8
+ https://github.com/klarkxy/dsh-plugins
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in
18
+ all copies or substantial portions of the Software.
19
+
20
+ And wait, one more thing — an invitation, not a condition: it would be best if
21
+ you star/+1/like the project(s) in the project url section above, and thank the
22
+ author(s) in the Copyright section. You may, and arguably you should — but the
23
+ permissions above hold either way, star or no star.
24
+
25
+ Here are some suggested ways:
26
+
27
+ - Email the authors a thank-you letter, and make friends with him/her/them.
28
+ - Report bugs or issues.
29
+ - Tell friends what a wonderful project this is.
30
+ - And, sure, you can just express thanks in your mind without telling the world.
31
+
32
+ Contributors of this project by forking have the option to add his/her name and
33
+ forked project url at copyright and project url sections, but shall not delete
34
+ or modify anything else in these two sections.
35
+
36
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @klarkxy/dsh-git-commit
2
+
3
+ Commit workspace changes to git without leaving the chat. Each conversation
4
+ thread gets a **Commit** action in its header: click it, review the branch,
5
+ file count and the model that will be used, then confirm to commit every
6
+ uncommitted path in the repository that contains the session's working
7
+ directory.
8
+
9
+ A model splits the change set into a small number of coherent commits with
10
+ proper messages, then the groups are applied in order as path-scoped commits.
11
+ The model route comes from
12
+ [@klarkxy/dsh-ai-services](https://klarkxy.github.io/dsh-plugins/plugins/ai-services/):
13
+ configure the **Git 提交** (`git-commit.plan`) purpose there in advance to pin
14
+ a dedicated model; when nothing is configured, the request inherits the normal
15
+ model tier and finally the default chat model. If the model call fails or
16
+ returns an invalid plan, the changes land in one fallback commit instead.
17
+
18
+ ## Usage
19
+
20
+ 1. Open a conversation whose workspace is inside a git repository.
21
+ 2. Click **Commit** in the thread header (top right).
22
+ 3. Confirm in the popover and wait for the run.
23
+ 4. The panel lists every commit created (hash + message).
24
+
25
+ The button is disabled while the session is running. The host checks again
26
+ before committing and stops if the workspace changes during planning.
27
+
28
+ ## Notes
29
+
30
+ - Each selected file is committed from its current worktree content. Pre-staged
31
+ changes in other groups stay staged until their group is committed.
32
+ - Untracked files are included; small text files get a content preview for the
33
+ model, binaries are listed by path only.
34
+ - Commits never push; pushing stays a manual decision.
35
+
36
+ ## License
37
+
38
+ SEE LICENSE IN LICENSE
@@ -0,0 +1,5 @@
1
+ # Enabled when installed. Adds a conversation-header Git commit action.
2
+ - insert:
3
+ - id: git-commit
4
+ name: '@klarkxy/dsh-git-commit'
5
+ disabled: false
@@ -0,0 +1,30 @@
1
+ # @klarkxy/dsh-git-commit
2
+
3
+ 在对话里直接把工作区修改提交到 git。每个对话线程的右上角有一个 **提交** 按钮:
4
+ 点一下打开弹层,确认分支、文件数量和将使用的模型,再点一下即可把会话工作目录
5
+ 所在仓库的全部未提交改动分次提交。
6
+
7
+ 模型会把改动整理成若干个内聚的提交并生成提交信息,然后按顺序逐组创建限定路径的提交。模型路由由
8
+ [@klarkxy/dsh-ai-services](https://klarkxy.github.io/dsh-plugins/plugins/ai-services/)
9
+ 提供:在「AI 服务」设置里提前给 **Git 提交**(`git-commit.plan`)用途配置专用模型;
10
+ 没有配置时依次回退到 normal 角色和默认对话模型。模型调用失败或返回非法分组时,
11
+ 改动会合并为一个兜底提交。
12
+
13
+ ## 使用
14
+
15
+ 1. 打开一个工作目录位于 git 仓库内的对话。
16
+ 2. 点击线程右上角的 **提交** 按钮。
17
+ 3. 在弹层里确认并等待执行完成。
18
+ 4. 面板会列出创建的每个提交(哈希 + 信息)。
19
+
20
+ 会话运行期间按钮不可用。宿主在提交前还会再次检查,规划期间工作区变化时会中止。
21
+
22
+ ## 说明
23
+
24
+ - 每个选中文件按当前工作区内容提交。其他分组的已暂存修改会保留到对应分组提交。
25
+ - 未跟踪文件也会提交;较小的文本文件会把内容预览发给模型,二进制文件只列路径。
26
+ - 插件只做 commit,不会 push。
27
+
28
+ ## 许可证
29
+
30
+ SEE LICENSE IN LICENSE
package/icon.svg ADDED
@@ -0,0 +1,16 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="none">
2
+ <defs>
3
+ <linearGradient id="node" x1="8" y1="6" x2="28" y2="30" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#4D75F5"/>
5
+ <stop offset="1" stop-color="#8EB6FF"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <g transform="translate(3.6 3.6) scale(.8)">
9
+ <path d="M11 12V24M11 12C11 14 14 16 19 16H25" stroke="#6392FF" stroke-width="2.8" stroke-linecap="round"/>
10
+ <circle cx="11" cy="9" r="3.6" fill="url(#node)"/>
11
+ <circle cx="11" cy="27" r="3.6" fill="url(#node)"/>
12
+ <circle cx="25" cy="16" r="3.6" fill="#39ABA9"/>
13
+ <path d="M23.6 16L24.8 17.2L26.6 15" stroke="#E0FBF6" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
14
+ <path d="M20 25L22.5 27.5L28 22" stroke="#55D9CE" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
15
+ </g>
16
+ </svg>
@@ -0,0 +1,389 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let react = require("react");
3
+ let react_dom = require("react-dom");
4
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ //#region src/contracts.ts
7
+ const RPC_CHANNEL = "/dsh-git-commit";
8
+ const GIT_COMMIT_CLIENT_SERVICE = "dshGitCommitClient";
9
+ //#endregion
10
+ //#region src/client.tsx
11
+ const name = "dsh-git-commit-client";
12
+ const inject = [
13
+ "slots",
14
+ "connection",
15
+ "locale"
16
+ ];
17
+ const NS = "dsh-git-commit.action";
18
+ const zh = {
19
+ action: "提交",
20
+ title: "提交到 Git",
21
+ commitAction: "分次提交全部工作区修改",
22
+ files: "个文件",
23
+ model: "模型",
24
+ modelDefault: "默认模型",
25
+ modelCustom: "AI 服务配置",
26
+ running: "正在整理修改并分次提交…",
27
+ done: "已创建提交",
28
+ fallback: "模型不可用,已合并为单个提交",
29
+ noWorkspace: "工作区没有修改",
30
+ unavailable: "不可用",
31
+ reasonNoRepo: "当前目录不在 Git 仓库中",
32
+ reasonNoGit: "未找到 git 命令",
33
+ reasonNoCwd: "会话没有工作目录",
34
+ reasonNoSession: "会话不在线",
35
+ sessionRunning: "会话正在运行,提交已暂停",
36
+ refresh: "刷新",
37
+ failed: "操作失败",
38
+ close: "关闭"
39
+ };
40
+ const en = {
41
+ action: "Commit",
42
+ title: "Commit to Git",
43
+ commitAction: "Commit all workspace changes",
44
+ files: "files",
45
+ model: "Model",
46
+ modelDefault: "default model",
47
+ modelCustom: "AI services route",
48
+ running: "Organizing changes into commits…",
49
+ done: "Commits created",
50
+ fallback: "Model unavailable; used a single commit",
51
+ noWorkspace: "No workspace changes",
52
+ unavailable: "Unavailable",
53
+ reasonNoRepo: "Current directory is not inside a Git repository",
54
+ reasonNoGit: "git executable not found",
55
+ reasonNoCwd: "Session has no working directory",
56
+ reasonNoSession: "Session is not live",
57
+ sessionRunning: "Session is running; commits paused",
58
+ refresh: "Refresh",
59
+ failed: "Operation failed",
60
+ close: "Close"
61
+ };
62
+ async function rpc(call, endpoint, payload) {
63
+ const result = await call(endpoint, payload);
64
+ if (!result || result.ok !== true) throw new Error(result && "error" in result ? result.error.message : "request failed");
65
+ return result.value;
66
+ }
67
+ function reasonText(t, status) {
68
+ switch (status.reason) {
69
+ case "not-a-repo": return t("reasonNoRepo");
70
+ case "no-git": return t("reasonNoGit");
71
+ case "no-cwd": return t("reasonNoCwd");
72
+ case "no-session": return t("reasonNoSession");
73
+ default: return t("unavailable");
74
+ }
75
+ }
76
+ function GitBranchIcon() {
77
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
78
+ width: "14",
79
+ height: "14",
80
+ viewBox: "0 0 16 16",
81
+ fill: "none",
82
+ "aria-hidden": "true",
83
+ children: [
84
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
85
+ cx: "4.5",
86
+ cy: "3.5",
87
+ r: "1.6",
88
+ stroke: "currentColor",
89
+ strokeWidth: "1.2"
90
+ }),
91
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
92
+ cx: "4.5",
93
+ cy: "12.5",
94
+ r: "1.6",
95
+ stroke: "currentColor",
96
+ strokeWidth: "1.2"
97
+ }),
98
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
99
+ cx: "11.5",
100
+ cy: "6.5",
101
+ r: "1.6",
102
+ stroke: "currentColor",
103
+ strokeWidth: "1.2"
104
+ }),
105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
106
+ d: "M4.5 5.1v5.8",
107
+ stroke: "currentColor",
108
+ strokeWidth: "1.2"
109
+ }),
110
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
111
+ d: "M11.5 8.1c0 2-1.6 2.9-3.4 3",
112
+ stroke: "currentColor",
113
+ strokeWidth: "1.2"
114
+ })
115
+ ]
116
+ });
117
+ }
118
+ function GitCommitAction({ sessionId, useSession, call, t }) {
119
+ const [open, setOpen] = (0, react.useState)(false);
120
+ const [status, setStatus] = (0, react.useState)();
121
+ const [loading, setLoading] = (0, react.useState)(false);
122
+ const [running, setRunning] = (0, react.useState)(false);
123
+ const [result, setResult] = (0, react.useState)(null);
124
+ const [error, setError] = (0, react.useState)(null);
125
+ const rootRef = (0, react.useRef)(null);
126
+ const triggerRef = (0, react.useRef)(null);
127
+ const panelRef = (0, react.useRef)(null);
128
+ const generationRef = (0, react.useRef)(0);
129
+ const position = (0, _deepseek_ai_dsh_client_ui_primitives.useAnchoredPosition)({
130
+ open,
131
+ anchorRef: triggerRef,
132
+ panelRef,
133
+ gap: 5,
134
+ margin: 16
135
+ });
136
+ const sessionRunning = useSession((snapshot) => snapshot.running === true);
137
+ const changeOpen = (0, react.useCallback)((next) => {
138
+ setOpen(next);
139
+ if (next) {
140
+ setResult(null);
141
+ setError(null);
142
+ }
143
+ }, []);
144
+ (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, open, changeOpen, panelRef);
145
+ (0, react.useEffect)(() => {
146
+ generationRef.current += 1;
147
+ setOpen(false);
148
+ setStatus(void 0);
149
+ setResult(null);
150
+ setError(null);
151
+ setRunning(false);
152
+ }, [sessionId]);
153
+ const loadStatus = (0, react.useCallback)(async () => {
154
+ const generation = generationRef.current;
155
+ setLoading(true);
156
+ setError(null);
157
+ try {
158
+ const next = await rpc(call, "status", { sessionId });
159
+ if (generationRef.current !== generation) return;
160
+ setStatus(next);
161
+ } catch (reason) {
162
+ if (generationRef.current !== generation) return;
163
+ setStatus(void 0);
164
+ setError(reason instanceof Error ? reason.message : String(reason));
165
+ } finally {
166
+ if (generationRef.current === generation) setLoading(false);
167
+ }
168
+ }, [call, sessionId]);
169
+ (0, react.useEffect)(() => {
170
+ if (!open) return;
171
+ loadStatus();
172
+ }, [open, loadStatus]);
173
+ (0, react.useEffect)(() => {
174
+ if (!open) return;
175
+ const dismiss = (event) => {
176
+ if (event.key !== "Escape") return;
177
+ event.preventDefault();
178
+ changeOpen(false);
179
+ triggerRef.current?.focus();
180
+ };
181
+ document.addEventListener("keydown", dismiss);
182
+ return () => document.removeEventListener("keydown", dismiss);
183
+ }, [open, changeOpen]);
184
+ const runCommit = (0, react.useCallback)(async () => {
185
+ const generation = generationRef.current;
186
+ setRunning(true);
187
+ setResult(null);
188
+ setError(null);
189
+ try {
190
+ const value = await rpc(call, "commit", { sessionId });
191
+ if (generationRef.current !== generation) return;
192
+ setResult(value);
193
+ const next = await rpc(call, "status", { sessionId }).catch(() => void 0);
194
+ if (generationRef.current !== generation) return;
195
+ if (next) setStatus(next);
196
+ } catch (reason) {
197
+ if (generationRef.current !== generation) return;
198
+ setError(reason instanceof Error ? reason.message : String(reason));
199
+ } finally {
200
+ if (generationRef.current === generation) setRunning(false);
201
+ }
202
+ }, [call, sessionId]);
203
+ const available = status?.available === true;
204
+ const workspaceCount = status?.workspace.files ?? 0;
205
+ const canCommit = available && !running && !sessionRunning && workspaceCount > 0;
206
+ const modelLabel = status?.model ? `${status.model.provider}/${status.model.model} · ${status.model.source === "purpose" || status.model.source === "override" ? t("modelCustom") : t("modelDefault")}` : void 0;
207
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
208
+ ref: rootRef,
209
+ className: "gcm-root",
210
+ children: [
211
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: css }),
212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
213
+ label: t("title"),
214
+ side: "bottom",
215
+ gap: 4,
216
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
217
+ type: "button",
218
+ ref: triggerRef,
219
+ className: "gcm-trigger",
220
+ "aria-label": t("title"),
221
+ "aria-haspopup": "dialog",
222
+ "aria-expanded": open,
223
+ onClick: () => changeOpen(!open),
224
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GitBranchIcon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
225
+ className: "gcm-triggerLabel",
226
+ children: t("action")
227
+ })]
228
+ })
229
+ }),
230
+ open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
231
+ ref: panelRef,
232
+ className: "gcm-panel",
233
+ style: position ?? {
234
+ visibility: "hidden",
235
+ left: 0,
236
+ top: 0
237
+ },
238
+ role: "dialog",
239
+ tabIndex: -1,
240
+ "aria-label": t("title"),
241
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
242
+ className: "gcm-body",
243
+ children: [
244
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
245
+ className: "gcm-header",
246
+ children: [
247
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
248
+ className: "gcm-title",
249
+ children: t("title")
250
+ }),
251
+ status?.branch ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
252
+ className: "gcm-branch",
253
+ children: status.branch
254
+ }) : null,
255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
256
+ type: "button",
257
+ className: "gcm-iconButton",
258
+ "aria-label": t("refresh"),
259
+ disabled: loading || running,
260
+ onClick: () => void loadStatus(),
261
+ children: "⟳"
262
+ })
263
+ ]
264
+ }),
265
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
266
+ className: "gcm-error",
267
+ role: "alert",
268
+ children: error
269
+ }),
270
+ status && !available && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
271
+ className: "gcm-notice",
272
+ role: "status",
273
+ children: reasonText(t, status)
274
+ }),
275
+ available && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
276
+ modelLabel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
277
+ className: "gcm-meta",
278
+ children: [
279
+ t("model"),
280
+ ": ",
281
+ modelLabel
282
+ ]
283
+ }) : null,
284
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
285
+ type: "button",
286
+ className: "gcm-action gcm-primary",
287
+ disabled: !canCommit,
288
+ onClick: () => void runCommit(),
289
+ children: [
290
+ t("commitAction"),
291
+ "(",
292
+ workspaceCount,
293
+ " ",
294
+ t("files"),
295
+ ")"
296
+ ]
297
+ }),
298
+ workspaceCount === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
299
+ className: "gcm-notice",
300
+ children: t("noWorkspace")
301
+ }),
302
+ sessionRunning && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
303
+ className: "gcm-notice",
304
+ children: t("sessionRunning")
305
+ })
306
+ ] }),
307
+ running && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
308
+ className: "gcm-notice",
309
+ role: "status",
310
+ children: t("running")
311
+ }),
312
+ result && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
313
+ className: "gcm-result",
314
+ children: [
315
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
316
+ className: "gcm-meta",
317
+ children: [
318
+ t("done"),
319
+ " · ",
320
+ result.branch
321
+ ]
322
+ }),
323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
324
+ className: "gcm-commits",
325
+ children: result.commits.map((commit) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
326
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: commit.hash }),
327
+ " ",
328
+ commit.message
329
+ ] }, commit.hash || commit.message))
330
+ }),
331
+ result.fallback && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
332
+ className: "gcm-notice",
333
+ children: t("fallback")
334
+ })
335
+ ]
336
+ })
337
+ ]
338
+ })
339
+ }), document.body)
340
+ ]
341
+ });
342
+ }
343
+ const css = `
344
+ .gcm-root{position:relative;display:inline-flex}
345
+ .gcm-trigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:none;border:0;border-radius:6px;align-items:center;gap:5px;padding:3px 7px;font-size:12px;display:inline-flex}
346
+ .gcm-trigger:hover,.gcm-trigger:focus-visible{color:var(--dsw-alias-label-primary)}
347
+ .gcm-triggerLabel{white-space:nowrap}
348
+ .gcm-panel{--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);z-index:100;box-sizing:border-box;width:min(360px,100vw - 32px);max-height:min(560px,100vh - 32px);box-shadow:var(--dsw-elevation-prominent);border:0;border-radius:12px;display:flex;flex-direction:column;position:fixed;overflow:hidden;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5;font-family:var(--default-font-family,system-ui,sans-serif)}
349
+ .gcm-panel::before{content:"";z-index:-1;background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);border-radius:12px;position:absolute;inset:0}
350
+ .gcm-body{display:grid;gap:8px;padding:12px 14px 14px;overflow-y:auto}
351
+ .gcm-header{display:flex;align-items:center;gap:8px}
352
+ .gcm-title{font-weight:600}
353
+ .gcm-branch{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;font-size:12px}
354
+ .gcm-iconButton{margin-left:auto;border:0;background:none;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:14px;padding:2px 6px;border-radius:6px}
355
+ .gcm-iconButton:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
356
+ .gcm-iconButton:disabled{opacity:.45;cursor:not-allowed}
357
+ .gcm-action{--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);display:block;width:100%;text-align:left;padding:7px 10px;border:0;box-shadow:var(--dsw-elevation-stroke);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer}
358
+ .gcm-action:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}
359
+ .gcm-action:disabled{opacity:.45;cursor:not-allowed}
360
+ .gcm-primary{--dsw-elevation-stroke-color:var(--dsw-alias-brand-primary)}
361
+ .gcm-meta{margin:0;font-size:12px;color:var(--dsw-alias-label-caption);overflow-wrap:anywhere}
362
+ .gcm-notice{margin:0;font-size:12px;color:var(--dsw-alias-label-secondary)}
363
+ .gcm-error{margin:0;font-size:12px;color:var(--dsw-alias-state-error-primary)}
364
+ .gcm-result{display:grid;gap:4px}
365
+ .gcm-commits{margin:0;padding-left:18px;display:grid;gap:2px;font-size:12px;overflow-wrap:anywhere}
366
+ .gcm-commits code{font-size:12px;background:var(--dsw-alias-bg-layer-2);padding:0 4px;border-radius:4px}
367
+ `;
368
+ function apply(ctx) {
369
+ const client = ctx;
370
+ ctx.provide(GIT_COMMIT_CLIENT_SERVICE, { active: true });
371
+ ctx.effect(() => client.locale.register(NS, {
372
+ zh: { ...zh },
373
+ en: { ...en }
374
+ }), "git-commit.locale");
375
+ ctx.effect(() => client.slots.inject("conversation.session.header.actions", () => client.slots.register({
376
+ name: "conversation.session.header.actions",
377
+ id: "git-commit",
378
+ order: 10,
379
+ locale: NS,
380
+ inject: () => ({ call: (endpoint, payload) => client.connection.rpc.call(RPC_CHANNEL, endpoint, payload) })
381
+ }, GitCommitAction)), "git-commit.slot");
382
+ }
383
+ //#endregion
384
+ exports.GitCommitAction = GitCommitAction;
385
+ exports.apply = apply;
386
+ exports.inject = inject;
387
+ exports.name = name;
388
+
389
+ //# sourceMappingURL=client.inner.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.inner.cjs","names":["useState","useRef","useAnchoredPosition","useCallback","Tooltip","createPortal"],"sources":["../src/contracts.ts","../src/client.tsx"],"sourcesContent":["/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-ai-services. */\nexport type { RpcResult } from '@klarkxy/dsh-ai-services/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-git-commit'\nexport const FEATURE_ID = 'git-commit'\nexport const PURPOSE_ID = 'git-commit.plan'\nexport const RPC_CHANNEL = '/dsh-git-commit'\nexport const GIT_COMMIT_CLIENT_SERVICE = 'dshGitCommitClient'\nexport const PROMPT_VERSION = 'git-commit.v1'\nexport const SCHEMA_VERSION = 'commit-plan-json.v1'\nexport const CONTRACT_VERSION = 1\n\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 2048\n/** Total character budget for the change manifest sent to the model. */\nexport const MAX_MANIFEST_CHARS = 48_000\n/** Per-file preview cap for untracked files. */\nexport const MAX_UNTRACKED_PREVIEW_CHARS = 2_000\n/** Recent commit subjects supplied as style reference. */\nexport const RECENT_LOG_COUNT = 10\n/** Hard cap for one generated commit message line. */\nexport const MAX_MESSAGE_CHARS = 120\n/** git subprocess timeout. */\nexport const GIT_TIMEOUT_MS = 30_000\n\nexport interface CommitModelInfo {\n readonly provider: string\n readonly model: string\n /** 'purpose' means the user configured an AI-services route; 'default' means the fallback default model. */\n readonly source: 'override' | 'purpose' | 'default'\n}\n\nexport interface GitCommitStatus {\n readonly available: boolean\n /** Machine-readable reason when unavailable: 'no-session' | 'no-cwd' | 'not-a-repo' | 'no-git'. */\n readonly reason?: string\n readonly detail?: string\n readonly root?: string\n readonly branch?: string\n readonly workspace: { readonly files: number }\n readonly model?: CommitModelInfo\n}\n\nexport interface CommitGroupResult {\n readonly hash: string\n readonly message: string\n readonly files: readonly string[]\n}\n\nexport interface CommitRunResult {\n readonly branch: string\n readonly commits: readonly CommitGroupResult[]\n /** True when the model plan was unavailable and a single fallback commit was used. */\n readonly fallback: boolean\n readonly model?: CommitModelInfo\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Tooltip, useAnchoredPosition, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n GIT_COMMIT_CLIENT_SERVICE, RPC_CHANNEL, type CommitRunResult, type GitCommitStatus, type RpcResult,\n} from './contracts.ts'\n\nexport const name = 'dsh-git-commit-client'\nexport const inject = ['slots', 'connection', 'locale'] as const\n\nconst NS = 'dsh-git-commit.action'\n\nconst zh = {\n action: '提交',\n title: '提交到 Git',\n commitAction: '分次提交全部工作区修改',\n files: '个文件',\n model: '模型',\n modelDefault: '默认模型',\n modelCustom: 'AI 服务配置',\n running: '正在整理修改并分次提交…',\n done: '已创建提交',\n fallback: '模型不可用,已合并为单个提交',\n noWorkspace: '工作区没有修改',\n unavailable: '不可用',\n reasonNoRepo: '当前目录不在 Git 仓库中',\n reasonNoGit: '未找到 git 命令',\n reasonNoCwd: '会话没有工作目录',\n reasonNoSession: '会话不在线',\n sessionRunning: '会话正在运行,提交已暂停',\n refresh: '刷新',\n failed: '操作失败',\n close: '关闭',\n}\n\nconst en: Record<keyof typeof zh, string> = {\n action: 'Commit',\n title: 'Commit to Git',\n commitAction: 'Commit all workspace changes',\n files: 'files',\n model: 'Model',\n modelDefault: 'default model',\n modelCustom: 'AI services route',\n running: 'Organizing changes into commits…',\n done: 'Commits created',\n fallback: 'Model unavailable; used a single commit',\n noWorkspace: 'No workspace changes',\n unavailable: 'Unavailable',\n reasonNoRepo: 'Current directory is not inside a Git repository',\n reasonNoGit: 'git executable not found',\n reasonNoCwd: 'Session has no working directory',\n reasonNoSession: 'Session is not live',\n sessionRunning: 'Session is running; commits paused',\n refresh: 'Refresh',\n failed: 'Operation failed',\n close: 'Close',\n}\n\ntype Key = keyof typeof zh\ntype Translate = (key: Key) => string\n\ninterface ConnectionLike {\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n}\n\ninterface SessionSnapshotLike {\n running?: boolean\n}\n\ninterface UseSessionLike {\n <T>(selector: (snapshot: SessionSnapshotLike) => T): T\n}\n\nexport interface GitCommitActionProps {\n sessionId: string\n useSession: UseSessionLike\n call: (endpoint: string, payload: unknown) => Promise<unknown>\n t: Translate\n}\n\nasync function rpc<T>(call: GitCommitActionProps['call'], endpoint: string, payload: unknown): Promise<T> {\n const result = await call(endpoint, payload) as RpcResult<T> | undefined\n if (!result || result.ok !== true) {\n throw new Error(result && 'error' in result ? result.error.message : 'request failed')\n }\n return result.value\n}\n\nfunction reasonText(t: Translate, status: GitCommitStatus): string {\n switch (status.reason) {\n case 'not-a-repo': return t('reasonNoRepo')\n case 'no-git': return t('reasonNoGit')\n case 'no-cwd': return t('reasonNoCwd')\n case 'no-session': return t('reasonNoSession')\n default: return t('unavailable')\n }\n}\n\nfunction GitBranchIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"4.5\" cy=\"3.5\" r=\"1.6\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n <circle cx=\"4.5\" cy=\"12.5\" r=\"1.6\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n <circle cx=\"11.5\" cy=\"6.5\" r=\"1.6\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n <path d=\"M4.5 5.1v5.8\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n <path d=\"M11.5 8.1c0 2-1.6 2.9-3.4 3\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n </svg>\n )\n}\n\nexport function GitCommitAction({ sessionId, useSession, call, t }: GitCommitActionProps) {\n const [open, setOpen] = useState(false)\n const [status, setStatus] = useState<GitCommitStatus>()\n const [loading, setLoading] = useState(false)\n const [running, setRunning] = useState(false)\n const [result, setResult] = useState<CommitRunResult | null>(null)\n const [error, setError] = useState<string | null>(null)\n const rootRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const panelRef = useRef<HTMLDivElement>(null)\n const generationRef = useRef(0)\n const position = useAnchoredPosition({ open, anchorRef: triggerRef, panelRef, gap: 5, margin: 16 })\n const sessionRunning = useSession(snapshot => snapshot.running === true)\n\n const changeOpen = useCallback((next: boolean) => {\n setOpen(next)\n if (next) {\n setResult(null)\n setError(null)\n }\n }, [])\n\n useDismissOnOutsidePointer(rootRef, open, changeOpen, panelRef)\n\n useEffect(() => {\n generationRef.current += 1\n setOpen(false)\n setStatus(undefined)\n setResult(null)\n setError(null)\n setRunning(false)\n }, [sessionId])\n\n const loadStatus = useCallback(async () => {\n const generation = generationRef.current\n setLoading(true)\n setError(null)\n try {\n const next = await rpc<GitCommitStatus>(call, 'status', { sessionId })\n if (generationRef.current !== generation) return\n setStatus(next)\n } catch (reason) {\n if (generationRef.current !== generation) return\n setStatus(undefined)\n setError(reason instanceof Error ? reason.message : String(reason))\n } finally {\n if (generationRef.current === generation) setLoading(false)\n }\n }, [call, sessionId])\n\n useEffect(() => {\n if (!open) return\n void loadStatus()\n }, [open, loadStatus])\n\n useEffect(() => {\n if (!open) return\n const dismiss = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return\n event.preventDefault()\n changeOpen(false)\n triggerRef.current?.focus()\n }\n document.addEventListener('keydown', dismiss)\n return () => document.removeEventListener('keydown', dismiss)\n }, [open, changeOpen])\n\n const runCommit = useCallback(async () => {\n const generation = generationRef.current\n setRunning(true)\n setResult(null)\n setError(null)\n try {\n const value = await rpc<CommitRunResult>(call, 'commit', { sessionId })\n if (generationRef.current !== generation) return\n setResult(value)\n const next = await rpc<GitCommitStatus>(call, 'status', { sessionId }).catch(() => undefined)\n if (generationRef.current !== generation) return\n if (next) setStatus(next)\n } catch (reason) {\n if (generationRef.current !== generation) return\n setError(reason instanceof Error ? reason.message : String(reason))\n } finally {\n if (generationRef.current === generation) setRunning(false)\n }\n }, [call, sessionId])\n\n const available = status?.available === true\n const workspaceCount = status?.workspace.files ?? 0\n const canCommit = available && !running && !sessionRunning && workspaceCount > 0\n const modelLabel = status?.model\n ? `${status.model.provider}/${status.model.model} · ${status.model.source === 'purpose' || status.model.source === 'override' ? t('modelCustom') : t('modelDefault')}`\n : undefined\n\n return (\n <div ref={rootRef} className=\"gcm-root\">\n <style>{css}</style>\n <Tooltip label={t('title')} side=\"bottom\" gap={4}>\n <button\n type=\"button\"\n ref={triggerRef}\n className=\"gcm-trigger\"\n aria-label={t('title')}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => changeOpen(!open)}\n >\n <GitBranchIcon />\n <span className=\"gcm-triggerLabel\">{t('action')}</span>\n </button>\n </Tooltip>\n {open && createPortal(\n <div\n ref={panelRef}\n className=\"gcm-panel\"\n style={position ?? { visibility: 'hidden', left: 0, top: 0 }}\n role=\"dialog\"\n tabIndex={-1}\n aria-label={t('title')}\n >\n <div className=\"gcm-body\">\n <div className=\"gcm-header\">\n <span className=\"gcm-title\">{t('title')}</span>\n {status?.branch ? <span className=\"gcm-branch\">{status.branch}</span> : null}\n <button type=\"button\" className=\"gcm-iconButton\" aria-label={t('refresh')}\n disabled={loading || running} onClick={() => void loadStatus()}>⟳</button>\n </div>\n {error !== null && <p className=\"gcm-error\" role=\"alert\">{error}</p>}\n {status && !available && <p className=\"gcm-notice\" role=\"status\">{reasonText(t, status)}</p>}\n {available && (\n <>\n {modelLabel ? <p className=\"gcm-meta\">{t('model')}: {modelLabel}</p> : null}\n <button type=\"button\" className=\"gcm-action gcm-primary\"\n disabled={!canCommit}\n onClick={() => void runCommit()}>\n {t('commitAction')}({workspaceCount} {t('files')})\n </button>\n {workspaceCount === 0 && <p className=\"gcm-notice\">{t('noWorkspace')}</p>}\n {sessionRunning && <p className=\"gcm-notice\">{t('sessionRunning')}</p>}\n </>\n )}\n {running && <p className=\"gcm-notice\" role=\"status\">{t('running')}</p>}\n {result && (\n <div className=\"gcm-result\">\n <p className=\"gcm-meta\">{t('done')} · {result.branch}</p>\n <ul className=\"gcm-commits\">\n {result.commits.map(commit => (\n <li key={commit.hash || commit.message}>\n <code>{commit.hash}</code> {commit.message}\n </li>\n ))}\n </ul>\n {result.fallback && <p className=\"gcm-notice\">{t('fallback')}</p>}\n </div>\n )}\n </div>\n </div>,\n document.body,\n )}\n </div>\n )\n}\n\nconst css = `\n.gcm-root{position:relative;display:inline-flex}\n.gcm-trigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:none;border:0;border-radius:6px;align-items:center;gap:5px;padding:3px 7px;font-size:12px;display:inline-flex}\n.gcm-trigger:hover,.gcm-trigger:focus-visible{color:var(--dsw-alias-label-primary)}\n.gcm-triggerLabel{white-space:nowrap}\n.gcm-panel{--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);z-index:100;box-sizing:border-box;width:min(360px,100vw - 32px);max-height:min(560px,100vh - 32px);box-shadow:var(--dsw-elevation-prominent);border:0;border-radius:12px;display:flex;flex-direction:column;position:fixed;overflow:hidden;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5;font-family:var(--default-font-family,system-ui,sans-serif)}\n.gcm-panel::before{content:\"\";z-index:-1;background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);border-radius:12px;position:absolute;inset:0}\n.gcm-body{display:grid;gap:8px;padding:12px 14px 14px;overflow-y:auto}\n.gcm-header{display:flex;align-items:center;gap:8px}\n.gcm-title{font-weight:600}\n.gcm-branch{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;font-size:12px}\n.gcm-iconButton{margin-left:auto;border:0;background:none;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:14px;padding:2px 6px;border-radius:6px}\n.gcm-iconButton:hover:not(:disabled){color:var(--dsw-alias-label-primary)}\n.gcm-iconButton:disabled{opacity:.45;cursor:not-allowed}\n.gcm-action{--dsw-elevation-stroke-color:var(--dsw-alias-border-l2);display:block;width:100%;text-align:left;padding:7px 10px;border:0;box-shadow:var(--dsw-elevation-stroke);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer}\n.gcm-action:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}\n.gcm-action:disabled{opacity:.45;cursor:not-allowed}\n.gcm-primary{--dsw-elevation-stroke-color:var(--dsw-alias-brand-primary)}\n.gcm-meta{margin:0;font-size:12px;color:var(--dsw-alias-label-caption);overflow-wrap:anywhere}\n.gcm-notice{margin:0;font-size:12px;color:var(--dsw-alias-label-secondary)}\n.gcm-error{margin:0;font-size:12px;color:var(--dsw-alias-state-error-primary)}\n.gcm-result{display:grid;gap:4px}\n.gcm-commits{margin:0;padding-left:18px;display:grid;gap:2px;font-size:12px;overflow-wrap:anywhere}\n.gcm-commits code{font-size:12px;background:var(--dsw-alias-bg-layer-2);padding:0 4px;border-radius:4px}\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshGitCommitClient: { active: boolean } }\n}\n\ntype Client = Context & {\n connection: ConnectionLike\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; order: number; locale: string; inject: () => unknown }, render: unknown): () => void\n }\n locale: { register(ns: string, locales: { zh: Record<string, string>; en: Record<string, string> }): () => void }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.provide(GIT_COMMIT_CLIENT_SERVICE, { active: true })\n ctx.effect(() => client.locale.register(NS, { zh: { ...zh }, en: { ...en } }), 'git-commit.locale')\n ctx.effect(() => client.slots.inject('conversation.session.header.actions', () => client.slots.register(\n {\n name: 'conversation.session.header.actions',\n id: 'git-commit',\n order: 10,\n locale: NS,\n inject: () => ({\n call: (endpoint: string, payload: unknown) => client.connection.rpc.call(RPC_CHANNEL, endpoint, payload),\n }),\n },\n GitCommitAction,\n )), 'git-commit.slot')\n}\n"],"mappings":";;;;;;AAMA,MAAa,cAAc;AAC3B,MAAa,4BAA4B;;;ACCzC,MAAa,OAAO;AACpB,MAAa,SAAS;CAAC;CAAS;CAAc;AAAQ;AAEtD,MAAM,KAAK;AAEX,MAAM,KAAK;CACT,QAAQ;CACR,OAAO;CACP,cAAc;CACd,OAAO;CACP,OAAO;CACP,cAAc;CACd,aAAa;CACb,SAAS;CACT,MAAM;CACN,UAAU;CACV,aAAa;CACb,aAAa;CACb,cAAc;CACd,aAAa;CACb,aAAa;CACb,iBAAiB;CACjB,gBAAgB;CAChB,SAAS;CACT,QAAQ;CACR,OAAO;AACT;AAEA,MAAM,KAAsC;CAC1C,QAAQ;CACR,OAAO;CACP,cAAc;CACd,OAAO;CACP,OAAO;CACP,cAAc;CACd,aAAa;CACb,SAAS;CACT,MAAM;CACN,UAAU;CACV,aAAa;CACb,aAAa;CACb,cAAc;CACd,aAAa;CACb,aAAa;CACb,iBAAiB;CACjB,gBAAgB;CAChB,SAAS;CACT,QAAQ;CACR,OAAO;AACT;AAwBA,eAAe,IAAO,MAAoC,UAAkB,SAA8B;CACxG,MAAM,SAAS,MAAM,KAAK,UAAU,OAAO;CAC3C,IAAI,CAAC,UAAU,OAAO,OAAO,MAC3B,MAAM,IAAI,MAAM,UAAU,WAAW,SAAS,OAAO,MAAM,UAAU,gBAAgB;CAEvF,OAAO,OAAO;AAChB;AAEA,SAAS,WAAW,GAAc,QAAiC;CACjE,QAAQ,OAAO,QAAf;EACE,KAAK,cAAc,OAAO,EAAE,cAAc;EAC1C,KAAK,UAAU,OAAO,EAAE,aAAa;EACrC,KAAK,UAAU,OAAO,EAAE,aAAa;EACrC,KAAK,cAAc,OAAO,EAAE,iBAAiB;EAC7C,SAAS,OAAO,EAAE,aAAa;CACjC;AACF;AAEA,SAAS,gBAAgB;CACvB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EAAO,eAAY;EAAxE,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,IAAG;IAAM,IAAG;IAAM,GAAE;IAAM,QAAO;IAAe,aAAY;GAAO,CAAA;GAC3E,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,IAAG;IAAM,IAAG;IAAO,GAAE;IAAM,QAAO;IAAe,aAAY;GAAO,CAAA;GAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,IAAG;IAAO,IAAG;IAAM,GAAE;IAAM,QAAO;IAAe,aAAY;GAAO,CAAA;GAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,GAAE;IAAe,QAAO;IAAe,aAAY;GAAO,CAAA;GAChE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,GAAE;IAA8B,QAAO;IAAe,aAAY;GAAO,CAAA;EAC5E;;AAET;AAEA,SAAgB,gBAAgB,EAAE,WAAW,YAAY,MAAM,KAA2B;CACxF,MAAM,CAAC,MAAM,YAAA,GAAWA,MAAAA,SAAAA,CAAS,KAAK;CACtC,MAAM,CAAC,QAAQ,cAAA,GAAaA,MAAAA,SAAAA,CAA0B;CACtD,MAAM,CAAC,SAAS,eAAA,GAAcA,MAAAA,SAAAA,CAAS,KAAK;CAC5C,MAAM,CAAC,SAAS,eAAA,GAAcA,MAAAA,SAAAA,CAAS,KAAK;CAC5C,MAAM,CAAC,QAAQ,cAAA,GAAaA,MAAAA,SAAAA,CAAiC,IAAI;CACjE,MAAM,CAAC,OAAO,aAAA,GAAYA,MAAAA,SAAAA,CAAwB,IAAI;CACtD,MAAM,WAAA,GAAUC,MAAAA,OAAAA,CAAuB,IAAI;CAC3C,MAAM,cAAA,GAAaA,MAAAA,OAAAA,CAA0B,IAAI;CACjD,MAAM,YAAA,GAAWA,MAAAA,OAAAA,CAAuB,IAAI;CAC5C,MAAM,iBAAA,GAAgBA,MAAAA,OAAAA,CAAO,CAAC;CAC9B,MAAM,YAAA,GAAWC,sCAAAA,oBAAAA,CAAoB;EAAE;EAAM,WAAW;EAAY;EAAU,KAAK;EAAG,QAAQ;CAAG,CAAC;CAClG,MAAM,iBAAiB,YAAW,aAAY,SAAS,YAAY,IAAI;CAEvE,MAAM,cAAA,GAAaC,MAAAA,YAAAA,EAAa,SAAkB;EAChD,QAAQ,IAAI;EACZ,IAAI,MAAM;GACR,UAAU,IAAI;GACd,SAAS,IAAI;EACf;CACF,GAAG,CAAC,CAAC;CAEL,CAAA,GAAA,sCAAA,2BAAA,CAA2B,SAAS,MAAM,YAAY,QAAQ;CAE9D,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,cAAc,WAAW;EACzB,QAAQ,KAAK;EACb,UAAU,KAAA,CAAS;EACnB,UAAU,IAAI;EACd,SAAS,IAAI;EACb,WAAW,KAAK;CAClB,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,cAAA,GAAaA,MAAAA,YAAAA,CAAY,YAAY;EACzC,MAAM,aAAa,cAAc;EACjC,WAAW,IAAI;EACf,SAAS,IAAI;EACb,IAAI;GACF,MAAM,OAAO,MAAM,IAAqB,MAAM,UAAU,EAAE,UAAU,CAAC;GACrE,IAAI,cAAc,YAAY,YAAY;GAC1C,UAAU,IAAI;EAChB,SAAS,QAAQ;GACf,IAAI,cAAc,YAAY,YAAY;GAC1C,UAAU,KAAA,CAAS;GACnB,SAAS,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM,CAAC;EACpE,UAAU;GACR,IAAI,cAAc,YAAY,YAAY,WAAW,KAAK;EAC5D;CACF,GAAG,CAAC,MAAM,SAAS,CAAC;CAEpB,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,MAAM;EACX,WAAgB;CAClB,GAAG,CAAC,MAAM,UAAU,CAAC;CAErB,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,MAAM;EACX,MAAM,WAAW,UAAyB;GACxC,IAAI,MAAM,QAAQ,UAAU;GAC5B,MAAM,eAAe;GACrB,WAAW,KAAK;GAChB,WAAW,SAAS,MAAM;EAC5B;EACA,SAAS,iBAAiB,WAAW,OAAO;EAC5C,aAAa,SAAS,oBAAoB,WAAW,OAAO;CAC9D,GAAG,CAAC,MAAM,UAAU,CAAC;CAErB,MAAM,aAAA,GAAYA,MAAAA,YAAAA,CAAY,YAAY;EACxC,MAAM,aAAa,cAAc;EACjC,WAAW,IAAI;EACf,UAAU,IAAI;EACd,SAAS,IAAI;EACb,IAAI;GACF,MAAM,QAAQ,MAAM,IAAqB,MAAM,UAAU,EAAE,UAAU,CAAC;GACtE,IAAI,cAAc,YAAY,YAAY;GAC1C,UAAU,KAAK;GACf,MAAM,OAAO,MAAM,IAAqB,MAAM,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GAC5F,IAAI,cAAc,YAAY,YAAY;GAC1C,IAAI,MAAM,UAAU,IAAI;EAC1B,SAAS,QAAQ;GACf,IAAI,cAAc,YAAY,YAAY;GAC1C,SAAS,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM,CAAC;EACpE,UAAU;GACR,IAAI,cAAc,YAAY,YAAY,WAAW,KAAK;EAC5D;CACF,GAAG,CAAC,MAAM,SAAS,CAAC;CAEpB,MAAM,YAAY,QAAQ,cAAc;CACxC,MAAM,iBAAiB,QAAQ,UAAU,SAAS;CAClD,MAAM,YAAY,aAAa,CAAC,WAAW,CAAC,kBAAkB,iBAAiB;CAC/E,MAAM,aAAa,QAAQ,QACvB,GAAG,OAAO,MAAM,SAAS,GAAG,OAAO,MAAM,MAAM,KAAK,OAAO,MAAM,WAAW,aAAa,OAAO,MAAM,WAAW,aAAa,EAAE,aAAa,IAAI,EAAE,cAAc,MACjK,KAAA;CAEJ,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,KAAK;EAAS,WAAU;EAA7B,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD,EAAA,UAAQ,IAAW,CAAA;GACnB,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,SAAD;IAAS,OAAO,EAAE,OAAO;IAAG,MAAK;IAAS,KAAK;IAC7C,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;KACE,MAAK;KACL,KAAK;KACL,WAAU;KACV,cAAY,EAAE,OAAO;KACrB,iBAAc;KACd,iBAAe;KACf,eAAe,WAAW,CAAC,IAAI;KAPjC,UAAA,CASE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD,CAAgB,CAAA,GAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAU;MAAoB,UAAA,EAAE,QAAQ;KAAQ,CAAA,CAChD;;GACD,CAAA;GACR,SAAA,GAAQC,UAAAA,aAAAA,CACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,OAAO,YAAY;KAAE,YAAY;KAAU,MAAM;KAAG,KAAK;IAAE;IAC3D,MAAK;IACL,UAAU;IACV,cAAY,EAAE,OAAO;IAErB,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAU;SAAa,UAAA,EAAE,OAAO;QAAQ,CAAA;QAC7C,QAAQ,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAU;SAAc,UAAA,OAAO;QAAa,CAAA,IAAI;QACxE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAU;SAAiB,cAAY,EAAE,SAAS;SACtE,UAAU,WAAW;SAAS,eAAe,KAAK,WAAW;SAAG,UAAA;QAAS,CAAA;OACxE;;MACJ,UAAU,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAU;OAAY,MAAK;OAAS,UAAA;MAAS,CAAA;MAClE,UAAU,CAAC,aAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAU;OAAa,MAAK;OAAU,UAAA,WAAW,GAAG,MAAM;MAAK,CAAA;MAC1F,aACC,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;OACG,aAAa,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;QAAG,WAAU;QAAb,UAAA;SAAyB,EAAE,OAAO;SAAE;SAAG;QAAc;OAAI,CAAA,IAAA;OACvE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAC9B,UAAU,CAAC;QACX,eAAe,KAAK,UAAU;QAFhC,UAAA;SAGG,EAAE,cAAc;SAAE;SAAE;SAAe;SAAE,EAAE,OAAO;SAAE;QAC3C;;OACP,mBAAmB,KAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAG,WAAU;QAAc,UAAA,EAAE,aAAa;OAAK,CAAA;OACvE,kBAAkB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAG,WAAU;QAAc,UAAA,EAAE,gBAAgB;OAAK,CAAA;MACrE,EAAA,CAAA;MAEH,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAU;OAAa,MAAK;OAAU,UAAA,EAAE,SAAS;MAAK,CAAA;MACpE,UACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAU;SAAb,UAAA;UAAyB,EAAE,MAAM;UAAE;UAAI,OAAO;SAAU;;QACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;SAAI,WAAU;SACX,UAAA,OAAO,QAAQ,KAAI,WAClB,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD,EAAA,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,OAAO,KAAW,CAAA;UAAC;UAAE,OAAO;SACjC,EAAA,GAFK,OAAO,QAAQ,OAAO,OAE3B,CACL;QACC,CAAA;QACH,OAAO,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAc,UAAA,EAAE,UAAU;QAAK,CAAA;OAC7D;;KAEJ;;GACF,CAAA,GACL,SAAS,IACX;EACG;;AAET;AAEA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;AAuCZ,SAAgB,MAAM,KAAoB;CACxC,MAAM,SAAS;CACf,IAAI,QAAQ,2BAA2B,EAAE,QAAQ,KAAK,CAAC;CACvD,IAAI,aAAa,OAAO,OAAO,SAAS,IAAI;EAAE,IAAI,EAAE,GAAG,GAAG;EAAG,IAAI,EAAE,GAAG,GAAG;CAAE,CAAC,GAAG,mBAAmB;CAClG,IAAI,aAAa,OAAO,MAAM,OAAO,6CAA6C,OAAO,MAAM,SAC7F;EACE,MAAM;EACN,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,eAAe,EACb,OAAO,UAAkB,YAAqB,OAAO,WAAW,IAAI,KAAK,aAAa,UAAU,OAAO,EACzG;CACF,GACA,eACF,CAAC,GAAG,iBAAiB;AACvB"}