@klarkxy/dsh-current-title 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 +3 -2
- package/docs/README.zh-CN.md +3 -2
- package/lib/client.inner.cjs +123 -56
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +123 -56
- package/lib/contracts.d.ts +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +22 -12
- package/lib/index.js.map +1 -1
- package/package.json +17 -12
package/README.md
CHANGED
|
@@ -27,11 +27,12 @@ Titles update automatically. Under **Plugins → Auto Title** you can:
|
|
|
27
27
|
- pick a title model (empty follows the current session model);
|
|
28
28
|
- regenerate the title of the open session.
|
|
29
29
|
|
|
30
|
-
If the model list cannot load, or some providers fail, use **Retry** beside the model picker
|
|
30
|
+
If the model list cannot load, or some providers fail, use **Retry** beside the model picker; retrying keeps your saved model and prompt draft.
|
|
31
31
|
|
|
32
32
|
## Limits
|
|
33
33
|
|
|
34
|
-
- Each title costs one model call; failed
|
|
34
|
+
- Each title costs one model call at the model's lowest supported reasoning effort; a failed generation keeps the existing title.
|
|
35
|
+
- Cancellation and timeouts wait for the model call to stop; a provider that ignores cancellation can delay completion.
|
|
35
36
|
- Turning the plugin off hands titles back to the built-in DSH title feature.
|
|
36
37
|
|
|
37
38
|
## License
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -27,11 +27,12 @@ dsh plugin --profile web add @klarkxy/dsh-current-title
|
|
|
27
27
|
- 选择标题模型(留空跟随当前会话模型);
|
|
28
28
|
- 重新生成当前会话的标题。
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
模型列表加载失败或部分提供商不可用时,可在模型选择器旁点击「重试」;重试会保留已保存的模型和提示词草稿。
|
|
31
31
|
|
|
32
32
|
## 限制
|
|
33
33
|
|
|
34
|
-
-
|
|
34
|
+
- 每次生成标题调用一次模型,使用模型支持的最低思考强度;生成失败时保留原标题。
|
|
35
|
+
- 取消和超时会等待模型调用停止;提供商不响应取消时,完成时间可能延后。
|
|
35
36
|
- 关闭插件后,标题交还给 DSH 自带的标题功能。
|
|
36
37
|
|
|
37
38
|
## 许可证
|
package/lib/client.inner.cjs
CHANGED
|
@@ -292,6 +292,17 @@ ${scope} {
|
|
|
292
292
|
/* --- Layout scaffolding. --- */
|
|
293
293
|
& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
|
|
294
294
|
& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
|
|
295
|
+
/* Plugin detail pages share one reading column. These are layout recipes;
|
|
296
|
+
* controls keep their own primitive styles. Form spacing follows the host's
|
|
297
|
+
* settings-form/fields.module.css and SettingsForm.module.css. */
|
|
298
|
+
& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
|
|
299
|
+
& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
|
|
300
|
+
&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
|
|
301
|
+
& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
|
|
302
|
+
& .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; }
|
|
303
|
+
@media (max-width: 560px) {
|
|
304
|
+
& .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
|
|
305
|
+
}
|
|
295
306
|
& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
296
307
|
& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
297
308
|
& .dsh-ui-spacer { flex: 1; min-width: 0; }
|
|
@@ -319,6 +330,9 @@ ${scope} {
|
|
|
319
330
|
* official primitive, so this only owns the vertical rhythm. --- */
|
|
320
331
|
& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
321
332
|
& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
|
|
333
|
+
/* Grid fields share a row, so the stacked-field divider must not win later in
|
|
334
|
+
* the cascade. Reset it here, after the field recipe. */
|
|
335
|
+
& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
|
|
322
336
|
& .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); }
|
|
323
337
|
& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
324
338
|
& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
|
|
@@ -509,29 +523,22 @@ ${scope} {
|
|
|
509
523
|
& *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
|
|
510
524
|
}
|
|
511
525
|
}
|
|
512
|
-
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(
|
|
526
|
+
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
|
|
513
527
|
}
|
|
514
528
|
//#endregion
|
|
515
529
|
//#region ../dsh-plugin-kit/src/contracts.ts
|
|
516
|
-
/**
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
method: "watch",
|
|
529
|
-
mode: "stream",
|
|
530
|
-
invocation: { kind: "direct" },
|
|
531
|
-
parameters: [],
|
|
532
|
-
cancellation: { parameter: "signal" }
|
|
533
|
-
}]
|
|
534
|
-
};
|
|
530
|
+
/** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
|
|
531
|
+
function modelSettingsChangesIdentity(packageName) {
|
|
532
|
+
const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
|
|
533
|
+
const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
534
|
+
if (!parts.length) throw new Error("Model settings package name has no RPC segment");
|
|
535
|
+
const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
|
|
536
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
|
|
537
|
+
return {
|
|
538
|
+
service: segment,
|
|
539
|
+
namespace: segment
|
|
540
|
+
};
|
|
541
|
+
}
|
|
535
542
|
//#endregion
|
|
536
543
|
//#region ../dsh-plugin-kit/src/model-settings-client.ts
|
|
537
544
|
/** This stream carries invalidations only; ready is never a settings snapshot. */
|
|
@@ -546,17 +553,44 @@ function parseModelSettingsChangeFrame(value) {
|
|
|
546
553
|
};
|
|
547
554
|
throw new Error("Invalid model settings change frame");
|
|
548
555
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
556
|
+
/** One owner's contribution. Each package mounts only its own endpoint. */
|
|
557
|
+
function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
|
|
558
|
+
return {
|
|
559
|
+
package: packageName,
|
|
560
|
+
descriptors: [{
|
|
561
|
+
id: `${identity.namespace}/watch`,
|
|
562
|
+
service: identity.service,
|
|
563
|
+
namespace: identity.namespace,
|
|
564
|
+
method: "watch",
|
|
565
|
+
mode: "stream",
|
|
566
|
+
invocation: { kind: "direct" },
|
|
567
|
+
parameters: [],
|
|
568
|
+
cancellation: { parameter: "signal" },
|
|
569
|
+
result: {
|
|
570
|
+
mode: "strict",
|
|
571
|
+
typeSymbol: "ModelSettings.ChangeFrame",
|
|
572
|
+
create: () => ({ parse: parseModelSettingsChangeFrame })
|
|
573
|
+
}
|
|
574
|
+
}]
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
/** Mount from a synchronous apply. Disposal waits for an in-flight mount and
|
|
578
|
+
* then withdraws it, so the contribution cannot outlive the plugin. */
|
|
579
|
+
function mountModelSettingsChanges(ctx, packageName) {
|
|
580
|
+
const contribution = modelSettingsChangesRemote(packageName);
|
|
581
|
+
ctx.inject(["remote"], (injected) => {
|
|
582
|
+
const scope = injected;
|
|
583
|
+
const mounting = scope.remote.$mount(contribution);
|
|
584
|
+
mounting.catch(() => {});
|
|
585
|
+
scope.effect(() => async () => {
|
|
586
|
+
await (await mounting.catch(() => void 0))?.();
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
}
|
|
557
590
|
/** Native RemoteStream owns carrier reconnects; no timers or browser transport.
|
|
558
591
|
* A factory shares one logical stream while at least one subscriber remains. */
|
|
559
|
-
function createModelSettingsSubscriber(ctx,
|
|
592
|
+
function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
|
|
593
|
+
const endpoint = identity;
|
|
560
594
|
const listeners = /* @__PURE__ */ new Set();
|
|
561
595
|
let injection;
|
|
562
596
|
let current;
|
|
@@ -582,12 +616,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
582
616
|
};
|
|
583
617
|
const start = () => {
|
|
584
618
|
const life = ++lifecycle;
|
|
585
|
-
injection = ctx.inject(["remote",
|
|
619
|
+
injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
|
|
586
620
|
if (life !== lifecycle || !listeners.size) return;
|
|
587
621
|
const scope = injected;
|
|
622
|
+
const service = scope.remote[endpoint.namespace];
|
|
623
|
+
if (!service || !("watch" in service) || !service.watch) {
|
|
624
|
+
report("Model settings sync service unavailable");
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const watch = service.watch;
|
|
588
628
|
const stream = scope.remote.$stream({
|
|
589
629
|
name: "Model settings sync",
|
|
590
|
-
open: (signal) =>
|
|
630
|
+
open: (signal) => watch(signal),
|
|
591
631
|
ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
|
|
592
632
|
});
|
|
593
633
|
const session = {
|
|
@@ -622,7 +662,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
622
662
|
invalidate();
|
|
623
663
|
} else {
|
|
624
664
|
if (!ready) throw new Error("Model settings sync change arrived before ready");
|
|
625
|
-
if (
|
|
665
|
+
if (accept(frame.ns)) invalidate();
|
|
626
666
|
}
|
|
627
667
|
}
|
|
628
668
|
} catch (error) {
|
|
@@ -927,7 +967,14 @@ function useModelCatalog(load, options = {}) {
|
|
|
927
967
|
refresh
|
|
928
968
|
};
|
|
929
969
|
}
|
|
930
|
-
/**
|
|
970
|
+
/**
|
|
971
|
+
* Also accepts a mapped state from a caller that owns broader async orchestration.
|
|
972
|
+
*
|
|
973
|
+
* The dsh-ui-* classes carry the styling and resolve through the consuming
|
|
974
|
+
* plugin's own officialUiCss scope (every consumer mounts its root class, so
|
|
975
|
+
* e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
|
|
976
|
+
* stays as a structural hook for tests and layout, never a colour source.
|
|
977
|
+
*/
|
|
931
978
|
function ModelCatalogStatus({ state, locale }) {
|
|
932
979
|
const zh = locale?.toLowerCase().startsWith("zh") === true;
|
|
933
980
|
const copy = zh ? {
|
|
@@ -943,15 +990,17 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
943
990
|
};
|
|
944
991
|
if (!state.loading && !state.error && state.failures.length === 0) return null;
|
|
945
992
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
946
|
-
className: "dsh-model-catalog-status",
|
|
993
|
+
className: "dsh-model-catalog-status dsh-ui-stack",
|
|
947
994
|
lang: zh ? "zh" : "en",
|
|
948
995
|
children: [
|
|
949
996
|
state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
950
997
|
role: "status",
|
|
998
|
+
className: "dsh-ui-loading",
|
|
951
999
|
children: copy.loading
|
|
952
1000
|
}) : null,
|
|
953
1001
|
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
954
1002
|
role: "alert",
|
|
1003
|
+
className: "dsh-ui-error dsh-ui-wrap",
|
|
955
1004
|
children: [
|
|
956
1005
|
copy.error,
|
|
957
1006
|
": ",
|
|
@@ -960,20 +1009,27 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
960
1009
|
}) : null,
|
|
961
1010
|
state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
962
1011
|
role: "status",
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
failure.
|
|
967
|
-
|
|
1012
|
+
className: "dsh-ui-meta",
|
|
1013
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1014
|
+
className: "dsh-ui-list",
|
|
1015
|
+
children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
1016
|
+
failure.name || failure.id,
|
|
1017
|
+
": ",
|
|
1018
|
+
failure.message
|
|
1019
|
+
] }, `${failure.id}:${index}`))
|
|
1020
|
+
})]
|
|
968
1021
|
}) : null,
|
|
969
|
-
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
state.
|
|
975
|
-
|
|
976
|
-
|
|
1022
|
+
state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1023
|
+
className: "dsh-ui-actions",
|
|
1024
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1025
|
+
type: "button",
|
|
1026
|
+
size: "sm",
|
|
1027
|
+
disabled: state.loading,
|
|
1028
|
+
onClick: () => {
|
|
1029
|
+
state.refresh();
|
|
1030
|
+
},
|
|
1031
|
+
children: copy.retry
|
|
1032
|
+
})
|
|
977
1033
|
}) : null
|
|
978
1034
|
]
|
|
979
1035
|
});
|
|
@@ -993,7 +1049,8 @@ function ModelCatalogStatus({ state, locale }) {
|
|
|
993
1049
|
* Sticky group headings, subsequence ranking, highlight walking and focus
|
|
994
1050
|
* hand-back all match the host. SYNC POINT: when the host's ModelSelect or
|
|
995
1051
|
* ModelSelect.module.css changes, this copy must be re-transcribed; styles
|
|
996
|
-
* below may only reference
|
|
1052
|
+
* below may only reference allowlisted theme tokens (the --dsw-* set plus the
|
|
1053
|
+
* host's --ds-* motion tokens), never literal colors.
|
|
997
1054
|
*
|
|
998
1055
|
* It statically imports the primitives, so only browser clients should load
|
|
999
1056
|
* this entry; host code and node tests use the core entry (`./index.ts`).
|
|
@@ -1501,7 +1558,8 @@ function ModelMenu(props) {
|
|
|
1501
1558
|
* sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
|
|
1502
1559
|
* elevation at portal z-index 1100. The trigger mirrors the composer's 28px
|
|
1503
1560
|
* model pill, chevron rotating open. MenuSurface paints fill and backdrop.
|
|
1504
|
-
* Only --dsw
|
|
1561
|
+
* Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
|
|
1562
|
+
* color is a bug.
|
|
1505
1563
|
*/
|
|
1506
1564
|
const modelMenuCss = `
|
|
1507
1565
|
.dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
|
|
@@ -1524,12 +1582,14 @@ const modelMenuCss = `
|
|
|
1524
1582
|
display: flex;
|
|
1525
1583
|
}
|
|
1526
1584
|
.dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
1527
|
-
.dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0
|
|
1585
|
+
.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)); }
|
|
1528
1586
|
.dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
1529
1587
|
.dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
|
|
1530
1588
|
.dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
|
|
1531
|
-
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform
|
|
1589
|
+
.dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
|
|
1532
1590
|
.dsh-model-menu-chevronOpen { transform: rotate(180deg); }
|
|
1591
|
+
/* Portal overlay: the host publishes no z-index token, so the card keeps the
|
|
1592
|
+
* native menu layer's 1100 verbatim. */
|
|
1533
1593
|
.dsh-model-menu-menu {
|
|
1534
1594
|
z-index: 1100;
|
|
1535
1595
|
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
@@ -1555,6 +1615,8 @@ const modelMenuCss = `
|
|
|
1555
1615
|
.dsh-model-menu-searchWithQuery { padding-right: 34px; }
|
|
1556
1616
|
.dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
|
|
1557
1617
|
.dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
|
|
1618
|
+
/* The clear button is a circle by geometry (border-radius: 50%), a shape the
|
|
1619
|
+
* radius token scale does not describe. */
|
|
1558
1620
|
.dsh-model-menu-searchClear {
|
|
1559
1621
|
width: 24px;
|
|
1560
1622
|
height: 24px;
|
|
@@ -2049,7 +2111,7 @@ function TitleSettings(props) {
|
|
|
2049
2111
|
});
|
|
2050
2112
|
}
|
|
2051
2113
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2052
|
-
className: "current-title-settings ct-root dsh-ui-
|
|
2114
|
+
className: "current-title-settings ct-root dsh-ui-page",
|
|
2053
2115
|
lang: seat.locale,
|
|
2054
2116
|
"data-testid": "current-title-settings",
|
|
2055
2117
|
children: [
|
|
@@ -2315,13 +2377,16 @@ function TitleSettings(props) {
|
|
|
2315
2377
|
]
|
|
2316
2378
|
});
|
|
2317
2379
|
}
|
|
2318
|
-
const
|
|
2319
|
-
.ct-root {
|
|
2320
|
-
.ct-prompt { min-height: 96px; }
|
|
2380
|
+
const currentTitleOwnCss = `
|
|
2381
|
+
.ct-root .ct-prompt { min-height: 96px; }
|
|
2321
2382
|
`;
|
|
2383
|
+
const currentTitleStyles = `${officialUiCss("ct-root")}${modelMenuCss}${currentTitleOwnCss}`;
|
|
2384
|
+
const styles = currentTitleStyles;
|
|
2322
2385
|
function apply(ctx) {
|
|
2323
2386
|
const client = ctx;
|
|
2324
|
-
const
|
|
2387
|
+
const packageName = "@klarkxy/dsh-current-title";
|
|
2388
|
+
mountModelSettingsChanges(ctx, packageName);
|
|
2389
|
+
const settingsSubscriber = createModelSettingsSubscriber(ctx, packageName, modelSettingsChangesIdentity(packageName));
|
|
2325
2390
|
const subscribeSettings = (change, error) => settingsSubscriber.subscribe(change, error);
|
|
2326
2391
|
const marker = createTitleClientMarker();
|
|
2327
2392
|
ctx.provide(TITLE_CLIENT_SERVICE, marker);
|
|
@@ -2361,6 +2426,8 @@ exports.TitleSettings = TitleSettings;
|
|
|
2361
2426
|
exports.apply = apply;
|
|
2362
2427
|
exports.applyMarkerFromStatus = applyMarkerFromStatus;
|
|
2363
2428
|
exports.createTitleClientMarker = createTitleClientMarker;
|
|
2429
|
+
exports.currentTitleOwnCss = currentTitleOwnCss;
|
|
2430
|
+
exports.currentTitleStyles = currentTitleStyles;
|
|
2364
2431
|
exports.disposeTitleClientMarker = disposeTitleClientMarker;
|
|
2365
2432
|
exports.inject = inject;
|
|
2366
2433
|
exports.name = name;
|