@klarkxy/dsh-git-commit 0.3.0 → 0.3.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/README.md CHANGED
@@ -23,14 +23,14 @@ Replace `web` with your profile name and restart it if DSH asks.
23
23
 
24
24
  Under **Plugins → Git Commit** you can choose the **Commit planning model** (empty follows the current session model) and turn on **Commit even without a model plan**, which makes one commit when the model is unavailable.
25
25
 
26
- If the model list cannot load, or some providers fail, use **Retry** beside the model picker. Your saved model stays selected.
26
+ If the model list cannot load, or some providers fail, use **Retry** beside the model picker; your saved model stays selected.
27
27
 
28
28
  ## Good to know
29
29
 
30
- - The repository follows the conversation's current working directory. Changing directories while a commit is being planned stops the run.
31
- - All uncommitted changes in the repository are included, including new files.
30
+ - The repository follows the conversation's current working directory; changing directories while a commit is being planned stops the run.
31
+ - All uncommitted changes are included, including new files.
32
32
  - It only commits; it never pushes.
33
- - If the run stops partway, finished commits stay and the panel shows what was left. Nothing is rolled back or retried automatically.
33
+ - If the run stops partway, finished commits stay and the panel shows what was left; nothing is rolled back or retried automatically.
34
34
  - The button is unavailable while the session is running.
35
35
 
36
36
  ## License
@@ -21,14 +21,14 @@ dsh plugin --profile web add @klarkxy/dsh-git-commit
21
21
  3. 确认分支、文件数和模型后提交。
22
22
  4. 面板会列出创建的提交。
23
23
 
24
- 在「插件 → Git 提交」里可以选择**提交规划模型**(留空跟随当前会话模型),也可以打开**模型不可用时仍然提交**,这时所有改动合并为一个提交。
24
+ 在「插件 → Git 提交」里可以选择**提交规划模型**(留空跟随当前会话模型),也可以打开**模型不可用时仍然提交**,模型不可用时改为只做一次提交。
25
25
 
26
- 模型列表加载失败或部分提供商不可用时,可在模型选择器旁点击「重试」。已保存的模型选择会保留。
26
+ 模型列表加载失败或部分提供商不可用时,可在模型选择器旁点击「重试」;已保存的模型选择会保留。
27
27
 
28
28
  ## 注意
29
29
 
30
30
  - 仓库跟随对话当前的工作目录;规划提交期间切换目录会停止本次提交。
31
- - 会提交仓库里的全部未提交改动,包括新文件。
31
+ - 会提交仓库里全部未提交的改动,包括新文件。
32
32
  - 只提交,不推送。
33
33
  - 中途停止时,已完成的提交会保留,面板显示剩余内容;不会自动回滚或重试。
34
34
  - 会话运行期间按钮不可用。
@@ -262,7 +262,14 @@ function useModelCatalog(load, options = {}) {
262
262
  refresh
263
263
  };
264
264
  }
265
- /** Also accepts a mapped state from a caller that owns broader async orchestration. */
265
+ /**
266
+ * Also accepts a mapped state from a caller that owns broader async orchestration.
267
+ *
268
+ * The dsh-ui-* classes carry the styling and resolve through the consuming
269
+ * plugin's own officialUiCss scope (every consumer mounts its root class, so
270
+ * e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
271
+ * stays as a structural hook for tests and layout, never a colour source.
272
+ */
266
273
  function ModelCatalogStatus({ state, locale }) {
267
274
  const zh = locale?.toLowerCase().startsWith("zh") === true;
268
275
  const copy = zh ? {
@@ -278,15 +285,17 @@ function ModelCatalogStatus({ state, locale }) {
278
285
  };
279
286
  if (!state.loading && !state.error && state.failures.length === 0) return null;
280
287
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
281
- className: "dsh-model-catalog-status",
288
+ className: "dsh-model-catalog-status dsh-ui-stack",
282
289
  lang: zh ? "zh" : "en",
283
290
  children: [
284
291
  state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
285
292
  role: "status",
293
+ className: "dsh-ui-loading",
286
294
  children: copy.loading
287
295
  }) : null,
288
296
  state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
289
297
  role: "alert",
298
+ className: "dsh-ui-error dsh-ui-wrap",
290
299
  children: [
291
300
  copy.error,
292
301
  ": ",
@@ -295,20 +304,27 @@ function ModelCatalogStatus({ state, locale }) {
295
304
  }) : null,
296
305
  state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
297
306
  role: "status",
298
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
299
- failure.name || failure.id,
300
- ": ",
301
- failure.message
302
- ] }, `${failure.id}:${index}`)) })]
307
+ className: "dsh-ui-meta",
308
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
309
+ className: "dsh-ui-list",
310
+ children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
311
+ failure.name || failure.id,
312
+ ": ",
313
+ failure.message
314
+ ] }, `${failure.id}:${index}`))
315
+ })]
303
316
  }) : null,
304
- state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
305
- type: "button",
306
- size: "sm",
307
- disabled: state.loading,
308
- onClick: () => {
309
- state.refresh();
310
- },
311
- children: copy.retry
317
+ state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
318
+ className: "dsh-ui-actions",
319
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
320
+ type: "button",
321
+ size: "sm",
322
+ disabled: state.loading,
323
+ onClick: () => {
324
+ state.refresh();
325
+ },
326
+ children: copy.retry
327
+ })
312
328
  }) : null
313
329
  ]
314
330
  });
@@ -328,7 +344,8 @@ function ModelCatalogStatus({ state, locale }) {
328
344
  * Sticky group headings, subsequence ranking, highlight walking and focus
329
345
  * hand-back all match the host. SYNC POINT: when the host's ModelSelect or
330
346
  * ModelSelect.module.css changes, this copy must be re-transcribed; styles
331
- * below may only reference --dsw-* theme tokens, never literal colors.
347
+ * below may only reference allowlisted theme tokens (the --dsw-* set plus the
348
+ * host's --ds-* motion tokens), never literal colors.
332
349
  *
333
350
  * It statically imports the primitives, so only browser clients should load
334
351
  * this entry; host code and node tests use the core entry (`./index.ts`).
@@ -836,7 +853,8 @@ function ModelMenu(props) {
836
853
  * sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
837
854
  * elevation at portal z-index 1100. The trigger mirrors the composer's 28px
838
855
  * model pill, chevron rotating open. MenuSurface paints fill and backdrop.
839
- * Only --dsw-* theme tokens may appear here — a literal color is a bug.
856
+ * Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
857
+ * color is a bug.
840
858
  */
841
859
  const modelMenuCss = `
842
860
  .dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
@@ -859,12 +877,14 @@ const modelMenuCss = `
859
877
  display: flex;
860
878
  }
861
879
  .dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
862
- .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
880
+ .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 var(--dsw-focus-ring-width) var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
863
881
  .dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
864
882
  .dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
865
883
  .dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
866
- .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform 0.12s; }
884
+ .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
867
885
  .dsh-model-menu-chevronOpen { transform: rotate(180deg); }
886
+ /* Portal overlay: the host publishes no z-index token, so the card keeps the
887
+ * native menu layer's 1100 verbatim. */
868
888
  .dsh-model-menu-menu {
869
889
  z-index: 1100;
870
890
  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
@@ -890,6 +910,8 @@ const modelMenuCss = `
890
910
  .dsh-model-menu-searchWithQuery { padding-right: 34px; }
891
911
  .dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
892
912
  .dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
913
+ /* The clear button is a circle by geometry (border-radius: 50%), a shape the
914
+ * radius token scale does not describe. */
893
915
  .dsh-model-menu-searchClear {
894
916
  width: 24px;
895
917
  height: 24px;
@@ -1137,6 +1159,17 @@ ${scope} {
1137
1159
  /* --- Layout scaffolding. --- */
1138
1160
  & .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
1139
1161
  & .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
1162
+ /* Plugin detail pages share one reading column. These are layout recipes;
1163
+ * controls keep their own primitive styles. Form spacing follows the host's
1164
+ * settings-form/fields.module.css and SettingsForm.module.css. */
1165
+ & .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
1166
+ & .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
1167
+ &.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
1168
+ & .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
1169
+ & .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }
1170
+ @media (max-width: 560px) {
1171
+ & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
1172
+ }
1140
1173
  & .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
1141
1174
  & .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
1142
1175
  & .dsh-ui-spacer { flex: 1; min-width: 0; }
@@ -1164,6 +1197,9 @@ ${scope} {
1164
1197
  * official primitive, so this only owns the vertical rhythm. --- */
1165
1198
  & .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
1166
1199
  & .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
1200
+ /* Grid fields share a row, so the stacked-field divider must not win later in
1201
+ * the cascade. Reset it here, after the field recipe. */
1202
+ & .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
1167
1203
  & .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }
1168
1204
  & .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
1169
1205
  & .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
@@ -1354,7 +1390,7 @@ ${scope} {
1354
1390
  & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
1355
1391
  }
1356
1392
  }
1357
- `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);
1393
+ `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
1358
1394
  }
1359
1395
  //#endregion
1360
1396
  //#region ../dsh-plugin-kit/src/contracts.ts
@@ -2039,11 +2075,10 @@ const clientCss = `${officialUiCss("gcm-root")}${modelMenuCss}
2039
2075
  * of at the trigger. Naming both classes puts this rule at the same weight,
2040
2076
  * later in the sheet, so it wins. */
2041
2077
  .gcm-root.gcm-panel { position: fixed; width: min(360px, calc(100vw - 32px)); max-height: min(560px, calc(100vh - 32px)); overflow: auto; }
2042
- .gcm-model { display: flex; align-items: center; gap: 6px; min-width: 0; margin: 0; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-primary); }
2043
- .gcm-commits { margin: 0; padding-inline-start: 18px; display: grid; gap: 2px; font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
2044
- .gcm-commits code { font-size: 12px; background: var(--dsw-alias-bg-layer-2); padding: 0 4px; border-radius: var(--dsw-radius-sm); }
2045
- .gcm-settings { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
2046
- .gcm-settings-status { display: flex; flex-direction: column; gap: 4px; }
2078
+ .gcm-root .gcm-model { display: flex; align-items: center; gap: 6px; min-width: 0; margin: 0; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-primary); }
2079
+ .gcm-root .gcm-commits { margin: 0; padding-inline-start: 18px; display: grid; gap: 2px; font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
2080
+ .gcm-root .gcm-commits code { font-size: 12px; background: var(--dsw-alias-bg-layer-2); padding: 0 4px; border-radius: var(--dsw-radius-sm); }
2081
+ .gcm-root .gcm-settings-status { display: flex; flex-direction: column; gap: 4px; }
2047
2082
  `;
2048
2083
  /** Host UI language, following live switches with the host's English fallback. */
2049
2084
  function useHostLocale(client) {
@@ -2205,7 +2240,7 @@ function GitCommitSettingsPanel(props) {
2205
2240
  text.stale
2206
2241
  ]);
2207
2242
  if (!settings) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2208
- className: "gcm-root gcm-settings",
2243
+ className: "gcm-root gcm-settings dsh-ui-page",
2209
2244
  children: [
2210
2245
  error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2211
2246
  role: "alert",
@@ -2238,7 +2273,7 @@ function GitCommitSettingsPanel(props) {
2238
2273
  const selectedEffort = efforts.find((item) => item.id === (current.reasoningEffort || ""));
2239
2274
  const effortName = selectedEffort ? modelMenuEffortLabel(selectedEffort, language) : void 0;
2240
2275
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2241
- className: "gcm-root gcm-settings",
2276
+ className: "gcm-root gcm-settings dsh-ui-page",
2242
2277
  "data-testid": "git-commit-settings",
2243
2278
  children: [
2244
2279
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {