@klarkxy/dsh-git-commit 0.2.5 → 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 +4 -3
- package/docs/README.zh-CN.md +4 -3
- package/lib/client.inner.cjs +120 -58
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +120 -58
- package/lib/contracts.d.ts +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +14 -4
- package/lib/index.js.map +1 -1
- package/package.json +21 -11
package/lib/client.js
CHANGED
|
@@ -268,7 +268,14 @@ function useModelCatalog(load, options = {}) {
|
|
|
268
268
|
refresh
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
|
-
/**
|
|
271
|
+
/**
|
|
272
|
+
* Also accepts a mapped state from a caller that owns broader async orchestration.
|
|
273
|
+
*
|
|
274
|
+
* The dsh-ui-* classes carry the styling and resolve through the consuming
|
|
275
|
+
* plugin's own officialUiCss scope (every consumer mounts its root class, so
|
|
276
|
+
* e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
|
|
277
|
+
* stays as a structural hook for tests and layout, never a colour source.
|
|
278
|
+
*/
|
|
272
279
|
function ModelCatalogStatus({ state, locale }) {
|
|
273
280
|
const zh = locale?.toLowerCase().startsWith("zh") === true;
|
|
274
281
|
const copy = zh ? {
|
|
@@ -284,15 +291,17 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
284
291
|
};
|
|
285
292
|
if (!state.loading && !state.error && state.failures.length === 0) return null;
|
|
286
293
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
287
|
-
className: "dsh-model-catalog-status",
|
|
294
|
+
className: "dsh-model-catalog-status dsh-ui-stack",
|
|
288
295
|
lang: zh ? "zh" : "en",
|
|
289
296
|
children: [
|
|
290
297
|
state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
291
298
|
role: "status",
|
|
299
|
+
className: "dsh-ui-loading",
|
|
292
300
|
children: copy.loading
|
|
293
301
|
}) : null,
|
|
294
302
|
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
295
303
|
role: "alert",
|
|
304
|
+
className: "dsh-ui-error dsh-ui-wrap",
|
|
296
305
|
children: [
|
|
297
306
|
copy.error,
|
|
298
307
|
": ",
|
|
@@ -301,20 +310,27 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
301
310
|
}) : null,
|
|
302
311
|
state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
303
312
|
role: "status",
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
failure.
|
|
308
|
-
|
|
313
|
+
className: "dsh-ui-meta",
|
|
314
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
315
|
+
className: "dsh-ui-list",
|
|
316
|
+
children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
317
|
+
failure.name || failure.id,
|
|
318
|
+
": ",
|
|
319
|
+
failure.message
|
|
320
|
+
] }, `${failure.id}:${index}`))
|
|
321
|
+
})]
|
|
309
322
|
}) : null,
|
|
310
|
-
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
state.
|
|
316
|
-
|
|
317
|
-
|
|
323
|
+
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
324
|
+
className: "dsh-ui-actions",
|
|
325
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
326
|
+
type: "button",
|
|
327
|
+
size: "sm",
|
|
328
|
+
disabled: state.loading,
|
|
329
|
+
onClick: () => {
|
|
330
|
+
state.refresh();
|
|
331
|
+
},
|
|
332
|
+
children: copy.retry
|
|
333
|
+
})
|
|
318
334
|
}) : null
|
|
319
335
|
]
|
|
320
336
|
});
|
|
@@ -334,7 +350,8 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
334
350
|
* Sticky group headings, subsequence ranking, highlight walking and focus
|
|
335
351
|
* hand-back all match the host. SYNC POINT: when the host's ModelSelect or
|
|
336
352
|
* ModelSelect.module.css changes, this copy must be re-transcribed; styles
|
|
337
|
-
* below may only reference
|
|
353
|
+
* below may only reference allowlisted theme tokens (the --dsw-* set plus the
|
|
354
|
+
* host's --ds-* motion tokens), never literal colors.
|
|
338
355
|
*
|
|
339
356
|
* It statically imports the primitives, so only browser clients should load
|
|
340
357
|
* this entry; host code and node tests use the core entry (`./index.ts`).
|
|
@@ -842,7 +859,8 @@ function ModelMenu(props) {
|
|
|
842
859
|
* sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
|
|
843
860
|
* elevation at portal z-index 1100. The trigger mirrors the composer's 28px
|
|
844
861
|
* model pill, chevron rotating open. MenuSurface paints fill and backdrop.
|
|
845
|
-
* Only --dsw
|
|
862
|
+
* Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
|
|
863
|
+
* color is a bug.
|
|
846
864
|
*/
|
|
847
865
|
const modelMenuCss = `
|
|
848
866
|
.dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
|
|
@@ -865,12 +883,14 @@ const modelMenuCss = `
|
|
|
865
883
|
display: flex;
|
|
866
884
|
}
|
|
867
885
|
.dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
868
|
-
.dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0
|
|
886
|
+
.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)); }
|
|
869
887
|
.dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
870
888
|
.dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
|
|
871
889
|
.dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
|
|
872
|
-
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform
|
|
890
|
+
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
|
|
873
891
|
.dsh-model-menu-chevronOpen { transform: rotate(180deg); }
|
|
892
|
+
/* Portal overlay: the host publishes no z-index token, so the card keeps the
|
|
893
|
+
* native menu layer's 1100 verbatim. */
|
|
874
894
|
.dsh-model-menu-menu {
|
|
875
895
|
z-index: 1100;
|
|
876
896
|
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
@@ -896,6 +916,8 @@ const modelMenuCss = `
|
|
|
896
916
|
.dsh-model-menu-searchWithQuery { padding-right: 34px; }
|
|
897
917
|
.dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
|
|
898
918
|
.dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
|
|
919
|
+
/* The clear button is a circle by geometry (border-radius: 50%), a shape the
|
|
920
|
+
* radius token scale does not describe. */
|
|
899
921
|
.dsh-model-menu-searchClear {
|
|
900
922
|
width: 24px;
|
|
901
923
|
height: 24px;
|
|
@@ -1143,6 +1165,17 @@ ${scope} {
|
|
|
1143
1165
|
/* --- Layout scaffolding. --- */
|
|
1144
1166
|
& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
|
|
1145
1167
|
& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
|
|
1168
|
+
/* Plugin detail pages share one reading column. These are layout recipes;
|
|
1169
|
+
* controls keep their own primitive styles. Form spacing follows the host's
|
|
1170
|
+
* settings-form/fields.module.css and SettingsForm.module.css. */
|
|
1171
|
+
& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
|
|
1172
|
+
& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
|
|
1173
|
+
&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
|
|
1174
|
+
& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
|
|
1175
|
+
& .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; }
|
|
1176
|
+
@media (max-width: 560px) {
|
|
1177
|
+
& .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
|
|
1178
|
+
}
|
|
1146
1179
|
& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
1147
1180
|
& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
1148
1181
|
& .dsh-ui-spacer { flex: 1; min-width: 0; }
|
|
@@ -1170,6 +1203,9 @@ ${scope} {
|
|
|
1170
1203
|
* official primitive, so this only owns the vertical rhythm. --- */
|
|
1171
1204
|
& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
1172
1205
|
& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
|
|
1206
|
+
/* Grid fields share a row, so the stacked-field divider must not win later in
|
|
1207
|
+
* the cascade. Reset it here, after the field recipe. */
|
|
1208
|
+
& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
|
|
1173
1209
|
& .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); }
|
|
1174
1210
|
& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
1175
1211
|
& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
|
|
@@ -1360,29 +1396,22 @@ ${scope} {
|
|
|
1360
1396
|
& *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
|
|
1361
1397
|
}
|
|
1362
1398
|
}
|
|
1363
|
-
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(
|
|
1399
|
+
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
|
|
1364
1400
|
}
|
|
1365
1401
|
//#endregion
|
|
1366
1402
|
//#region ../dsh-plugin-kit/src/contracts.ts
|
|
1367
|
-
/**
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
method: "watch",
|
|
1380
|
-
mode: "stream",
|
|
1381
|
-
invocation: { kind: "direct" },
|
|
1382
|
-
parameters: [],
|
|
1383
|
-
cancellation: { parameter: "signal" }
|
|
1384
|
-
}]
|
|
1385
|
-
};
|
|
1403
|
+
/** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
|
|
1404
|
+
function modelSettingsChangesIdentity(packageName) {
|
|
1405
|
+
const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
|
|
1406
|
+
const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
1407
|
+
if (!parts.length) throw new Error("Model settings package name has no RPC segment");
|
|
1408
|
+
const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
|
|
1409
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
|
|
1410
|
+
return {
|
|
1411
|
+
service: segment,
|
|
1412
|
+
namespace: segment
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1386
1415
|
//#endregion
|
|
1387
1416
|
//#region ../dsh-plugin-kit/src/model-settings-client.ts
|
|
1388
1417
|
/** This stream carries invalidations only; ready is never a settings snapshot. */
|
|
@@ -1397,17 +1426,44 @@ function parseModelSettingsChangeFrame(value) {
|
|
|
1397
1426
|
};
|
|
1398
1427
|
throw new Error("Invalid model settings change frame");
|
|
1399
1428
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1429
|
+
/** One owner's contribution. Each package mounts only its own endpoint. */
|
|
1430
|
+
function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
|
|
1431
|
+
return {
|
|
1432
|
+
package: packageName,
|
|
1433
|
+
descriptors: [{
|
|
1434
|
+
id: `${identity.namespace}/watch`,
|
|
1435
|
+
service: identity.service,
|
|
1436
|
+
namespace: identity.namespace,
|
|
1437
|
+
method: "watch",
|
|
1438
|
+
mode: "stream",
|
|
1439
|
+
invocation: { kind: "direct" },
|
|
1440
|
+
parameters: [],
|
|
1441
|
+
cancellation: { parameter: "signal" },
|
|
1442
|
+
result: {
|
|
1443
|
+
mode: "strict",
|
|
1444
|
+
typeSymbol: "ModelSettings.ChangeFrame",
|
|
1445
|
+
create: () => ({ parse: parseModelSettingsChangeFrame })
|
|
1446
|
+
}
|
|
1447
|
+
}]
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
/** Mount from a synchronous apply. Disposal waits for an in-flight mount and
|
|
1451
|
+
* then withdraws it, so the contribution cannot outlive the plugin. */
|
|
1452
|
+
function mountModelSettingsChanges(ctx, packageName) {
|
|
1453
|
+
const contribution = modelSettingsChangesRemote(packageName);
|
|
1454
|
+
ctx.inject(["remote"], (injected) => {
|
|
1455
|
+
const scope = injected;
|
|
1456
|
+
const mounting = scope.remote.$mount(contribution);
|
|
1457
|
+
mounting.catch(() => {});
|
|
1458
|
+
scope.effect(() => async () => {
|
|
1459
|
+
await (await mounting.catch(() => void 0))?.();
|
|
1460
|
+
});
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1408
1463
|
/** Native RemoteStream owns carrier reconnects; no timers or browser transport.
|
|
1409
1464
|
* A factory shares one logical stream while at least one subscriber remains. */
|
|
1410
|
-
function createModelSettingsSubscriber(ctx,
|
|
1465
|
+
function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
|
|
1466
|
+
const endpoint = identity;
|
|
1411
1467
|
const listeners = /* @__PURE__ */ new Set();
|
|
1412
1468
|
let injection;
|
|
1413
1469
|
let current;
|
|
@@ -1433,12 +1489,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1433
1489
|
};
|
|
1434
1490
|
const start = () => {
|
|
1435
1491
|
const life = ++lifecycle;
|
|
1436
|
-
injection = ctx.inject(["remote",
|
|
1492
|
+
injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
|
|
1437
1493
|
if (life !== lifecycle || !listeners.size) return;
|
|
1438
1494
|
const scope = injected;
|
|
1495
|
+
const service = scope.remote[endpoint.namespace];
|
|
1496
|
+
if (!service || !("watch" in service) || !service.watch) {
|
|
1497
|
+
report("Model settings sync service unavailable");
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const watch = service.watch;
|
|
1439
1501
|
const stream = scope.remote.$stream({
|
|
1440
1502
|
name: "Model settings sync",
|
|
1441
|
-
open: (signal) =>
|
|
1503
|
+
open: (signal) => watch(signal),
|
|
1442
1504
|
ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
|
|
1443
1505
|
});
|
|
1444
1506
|
const session = {
|
|
@@ -1473,7 +1535,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
1473
1535
|
invalidate();
|
|
1474
1536
|
} else {
|
|
1475
1537
|
if (!ready) throw new Error("Model settings sync change arrived before ready");
|
|
1476
|
-
if (
|
|
1538
|
+
if (accept(frame.ns)) invalidate();
|
|
1477
1539
|
}
|
|
1478
1540
|
}
|
|
1479
1541
|
} catch (error) {
|
|
@@ -2019,11 +2081,10 @@ const clientCss = `${officialUiCss("gcm-root")}${modelMenuCss}
|
|
|
2019
2081
|
* of at the trigger. Naming both classes puts this rule at the same weight,
|
|
2020
2082
|
* later in the sheet, so it wins. */
|
|
2021
2083
|
.gcm-root.gcm-panel { position: fixed; width: min(360px, calc(100vw - 32px)); max-height: min(560px, calc(100vh - 32px)); overflow: auto; }
|
|
2022
|
-
.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); }
|
|
2023
|
-
.gcm-commits { margin: 0; padding-inline-start: 18px; display: grid; gap: 2px; font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
|
|
2024
|
-
.gcm-commits code { font-size: 12px; background: var(--dsw-alias-bg-layer-2); padding: 0 4px; border-radius: var(--dsw-radius-sm); }
|
|
2025
|
-
.gcm-settings { display: flex; flex-direction: column; gap:
|
|
2026
|
-
.gcm-settings-status { display: flex; flex-direction: column; gap: 4px; }
|
|
2084
|
+
.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); }
|
|
2085
|
+
.gcm-root .gcm-commits { margin: 0; padding-inline-start: 18px; display: grid; gap: 2px; font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
|
|
2086
|
+
.gcm-root .gcm-commits code { font-size: 12px; background: var(--dsw-alias-bg-layer-2); padding: 0 4px; border-radius: var(--dsw-radius-sm); }
|
|
2087
|
+
.gcm-root .gcm-settings-status { display: flex; flex-direction: column; gap: 4px; }
|
|
2027
2088
|
`;
|
|
2028
2089
|
/** Host UI language, following live switches with the host's English fallback. */
|
|
2029
2090
|
function useHostLocale(client) {
|
|
@@ -2185,7 +2246,7 @@ function GitCommitSettingsPanel(props) {
|
|
|
2185
2246
|
text.stale
|
|
2186
2247
|
]);
|
|
2187
2248
|
if (!settings) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2188
|
-
className: "gcm-root gcm-settings",
|
|
2249
|
+
className: "gcm-root gcm-settings dsh-ui-page",
|
|
2189
2250
|
children: [
|
|
2190
2251
|
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2191
2252
|
role: "alert",
|
|
@@ -2218,7 +2279,7 @@ function GitCommitSettingsPanel(props) {
|
|
|
2218
2279
|
const selectedEffort = efforts.find((item) => item.id === (current.reasoningEffort || ""));
|
|
2219
2280
|
const effortName = selectedEffort ? modelMenuEffortLabel(selectedEffort, language) : void 0;
|
|
2220
2281
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2221
|
-
className: "gcm-root gcm-settings",
|
|
2282
|
+
className: "gcm-root gcm-settings dsh-ui-page",
|
|
2222
2283
|
"data-testid": "git-commit-settings",
|
|
2223
2284
|
children: [
|
|
2224
2285
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2345,6 +2406,7 @@ function GitCommitSettingsPanel(props) {
|
|
|
2345
2406
|
}
|
|
2346
2407
|
function apply(ctx) {
|
|
2347
2408
|
const client = ctx;
|
|
2409
|
+
mountModelSettingsChanges(ctx, PLUGIN_NAME);
|
|
2348
2410
|
const settingsSubscriber = createModelSettingsSubscriber(ctx, PLUGIN_NAME);
|
|
2349
2411
|
const subscribeSettings = (change, error) => settingsSubscriber.subscribe(change, error);
|
|
2350
2412
|
ctx.provide(GIT_COMMIT_CLIENT_SERVICE, { active: true });
|
package/lib/contracts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ModelRoute, defaultModelRoute, normalizeModelRoute } from "@klarkxy/dsh-model-route";
|
|
2
1
|
import { RpcResult as RpcResult$1 } from "@klarkxy/dsh-plugin-kit/contracts";
|
|
2
|
+
import { ModelRoute, defaultModelRoute, normalizeModelRoute } from "@klarkxy/dsh-model-route";
|
|
3
3
|
//#region src/contracts.d.ts
|
|
4
4
|
type RpcResult<T = unknown> = Extract<RpcResult$1<T>, {
|
|
5
5
|
ok: true;
|
package/lib/index.d.ts
CHANGED
|
@@ -49,6 +49,9 @@ interface GitCommitServiceDeps {
|
|
|
49
49
|
readonly llm: LlmTextCaller;
|
|
50
50
|
readonly host?: unknown;
|
|
51
51
|
readonly sessions: SessionStoreLike;
|
|
52
|
+
readonly workingDirectory: {
|
|
53
|
+
get(session: SessionLike): string;
|
|
54
|
+
};
|
|
52
55
|
readonly agents?: AgentStoreLike;
|
|
53
56
|
readonly run?: GitRunner;
|
|
54
57
|
readonly preview?: (root: string, path: string) => Promise<UntrackedPreview>;
|
|
@@ -111,7 +114,7 @@ declare function parsePlan(text: string, files: readonly ChangedFile[]): PlanGro
|
|
|
111
114
|
//#endregion
|
|
112
115
|
//#region src/index.d.ts
|
|
113
116
|
declare const name = "@klarkxy/dsh-git-commit";
|
|
114
|
-
declare const inject: readonly ["llm", "sessions", "agents", "storageDomain", "connection", "webServer", "sessionProjections", "agentDefaultModel"];
|
|
117
|
+
declare const inject: readonly ["llm", "sessions", "workingDirectory", "agents", "storageDomain", "connection", "webServer", "sessionProjections", "agentDefaultModel"];
|
|
115
118
|
declare module '@deepseek-ai/cordis' {
|
|
116
119
|
interface Context {
|
|
117
120
|
gitCommit: GitCommitService;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_MAX_OUTPUT_TOKENS, MAX_MANIFEST_CHARS, MAX_UNTRACKED_PREVIEW_CHARS, PLUGIN_NAME, RPC_CHANNEL, SETTINGS_KEY, defaultSettings, normalizeFallback, normalizeModelRoute } from "./contracts.js";
|
|
2
2
|
import { registerHostRpc } from "@klarkxy/dsh-plugin-kit/host-rpc";
|
|
3
|
+
import { modelSettingsChangesIdentity } from "@klarkxy/dsh-plugin-kit/contracts";
|
|
4
|
+
import { createModelSettingsChanges } from "@klarkxy/dsh-plugin-kit/model-settings-changes";
|
|
3
5
|
import { notifyModelSettingsChanged, registerModelSettings } from "@klarkxy/dsh-plugin-kit/model-settings";
|
|
4
6
|
import { modelRouteOverride } from "@klarkxy/dsh-model-route";
|
|
5
7
|
import { callLlmText, resolveFeatureModel } from "@klarkxy/dsh-plugin-kit";
|
|
@@ -771,7 +773,7 @@ var GitCommitService = class {
|
|
|
771
773
|
async resolveRepo(sessionId, signal) {
|
|
772
774
|
const session = this.deps.sessions.get(sessionId);
|
|
773
775
|
if (!session) throw new CommitRunError("no-session", "dsh-git-commit: session is not live on this host");
|
|
774
|
-
const cwd = normalizeCwd(session
|
|
776
|
+
const cwd = normalizeCwd(this.deps.workingDirectory.get(session));
|
|
775
777
|
if (!cwd) throw new CommitRunError("no-cwd", "dsh-git-commit: session has no working directory");
|
|
776
778
|
try {
|
|
777
779
|
return await repoInfo(this.run, cwd, signal);
|
|
@@ -828,13 +830,13 @@ var GitCommitService = class {
|
|
|
828
830
|
await this.waitForSettings(signal);
|
|
829
831
|
if (this.disposed || signal?.aborted) throw new CommitRunError("cancelled", "dsh-git-commit: plugin is no longer active");
|
|
830
832
|
const session = this.deps.sessions.get(sessionId);
|
|
831
|
-
const sessionCwd = normalizeCwd(session
|
|
833
|
+
const sessionCwd = session ? normalizeCwd(this.deps.workingDirectory.get(session)) : void 0;
|
|
832
834
|
const resolved = await this.resolveRepo(sessionId, signal);
|
|
833
835
|
const assertReady = () => {
|
|
834
836
|
signal?.throwIfAborted();
|
|
835
837
|
if (this.disposed || !this.deps.llm) throw new CommitRunError("cancelled", "dsh-git-commit: plugin is no longer active");
|
|
836
838
|
const currentSession = this.deps.sessions.get(sessionId);
|
|
837
|
-
if (currentSession !== session || normalizeCwd(currentSession
|
|
839
|
+
if (currentSession !== session || (currentSession ? normalizeCwd(this.deps.workingDirectory.get(currentSession)) : void 0) !== sessionCwd) throw new CommitRunError("session-changed", "dsh-git-commit: session workspace changed during planning");
|
|
838
840
|
if (this.deps.agents?.get(sessionId)?.status === "running") throw new CommitRunError("session-running", "dsh-git-commit: wait for the session turn to finish");
|
|
839
841
|
};
|
|
840
842
|
assertReady();
|
|
@@ -905,7 +907,11 @@ var GitCommitService = class {
|
|
|
905
907
|
};
|
|
906
908
|
let executed;
|
|
907
909
|
try {
|
|
908
|
-
|
|
910
|
+
const commitRun = (args, options) => {
|
|
911
|
+
if (args[0] === "add" || args[0] === "commit") assertReady();
|
|
912
|
+
return this.run(args, options);
|
|
913
|
+
};
|
|
914
|
+
executed = await commitGroups(commitRun, resolved.root, effective, selected, signal, async () => {
|
|
909
915
|
assertReady();
|
|
910
916
|
if (await this.run([
|
|
911
917
|
"symbolic-ref",
|
|
@@ -917,6 +923,7 @@ var GitCommitService = class {
|
|
|
917
923
|
}).catch(() => "DETACHED") !== branchRef) throw new CommitRunError("workspace-changed", "dsh-git-commit: branch changed during the commit run");
|
|
918
924
|
if (await pathVersions(this.run, resolved.root, paths, signal) !== originalVersions) throw new CommitRunError("workspace-changed", "dsh-git-commit: selected file changed during the commit run");
|
|
919
925
|
await workingTreeChanges(this.run, resolved.root, signal);
|
|
926
|
+
assertReady();
|
|
920
927
|
});
|
|
921
928
|
} catch (error) {
|
|
922
929
|
if (!(error instanceof PartialCommitError)) throw error;
|
|
@@ -991,6 +998,7 @@ const name = PLUGIN_NAME;
|
|
|
991
998
|
const inject = [
|
|
992
999
|
"llm",
|
|
993
1000
|
"sessions",
|
|
1001
|
+
"workingDirectory",
|
|
994
1002
|
"agents",
|
|
995
1003
|
"storageDomain",
|
|
996
1004
|
"connection",
|
|
@@ -1087,6 +1095,7 @@ async function handleRpc(service, endpoint, payload, signal) {
|
|
|
1087
1095
|
}
|
|
1088
1096
|
}
|
|
1089
1097
|
function apply(ctx) {
|
|
1098
|
+
createModelSettingsChanges(ctx, modelSettingsChangesIdentity(PLUGIN_NAME), PLUGIN_NAME);
|
|
1090
1099
|
const host = ctx;
|
|
1091
1100
|
const domainPromise = host.storageDomain.open(gitCommitDomain);
|
|
1092
1101
|
const tablePromise = domainPromise.then((domain) => domain.table("settings"));
|
|
@@ -1096,6 +1105,7 @@ function apply(ctx) {
|
|
|
1096
1105
|
llm: host.llm,
|
|
1097
1106
|
host,
|
|
1098
1107
|
sessions: host.sessions,
|
|
1108
|
+
workingDirectory: host.workingDirectory,
|
|
1099
1109
|
agents: host.agents,
|
|
1100
1110
|
settings: {
|
|
1101
1111
|
load: async () => parseSettings((await tablePromise).get(SETTINGS_KEY)),
|