@klarkxy/dsh-current-title 0.2.5 → 0.3.0

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
@@ -31,7 +31,8 @@ If the model list cannot load, or some providers fail, use **Retry** beside the
31
31
 
32
32
  ## Limits
33
33
 
34
- - Each title costs one model call; failed generations keep the existing title.
34
+ - Each title costs one model call, using the model's lowest supported reasoning effort; failed generations keep the existing title.
35
+ - Cancellation and timeouts wait for the model call to stop. A provider that does not honor 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
@@ -31,7 +31,8 @@ dsh plugin --profile web add @klarkxy/dsh-current-title
31
31
 
32
32
  ## 限制
33
33
 
34
- - 每次生成标题会调用一次模型;生成失败时保留原标题。
34
+ - 每次生成标题会调用一次模型,使用模型支持的最低思考强度;生成失败时保留原标题。
35
+ - 取消和超时会等待模型调用真正停止;提供商不响应取消时,完成时间可能延后。
35
36
  - 关闭插件后,标题交还给 DSH 自带的标题功能。
36
37
 
37
38
  ## 许可证
@@ -513,25 +513,18 @@ ${scope} {
513
513
  }
514
514
  //#endregion
515
515
  //#region ../dsh-plugin-kit/src/contracts.ts
516
- /**
517
- * Remote contribution for model-settings change notifications.
518
- * Provided by `@klarkxy/dsh-model-hub` (`ModelSettingsChangesController`);
519
- * subscribers degrade silently when that package is not installed.
520
- * The stream carries invalidations only — `ready` is never a settings snapshot.
521
- */
522
- const MODEL_SETTINGS_CHANGES_REMOTE = {
523
- package: "@klarkxy/dsh-model-hub",
524
- descriptors: [{
525
- id: "modelSettingsChanges/watch",
526
- service: "modelSettingsChangesController",
527
- namespace: "modelSettingsChanges",
528
- method: "watch",
529
- mode: "stream",
530
- invocation: { kind: "direct" },
531
- parameters: [],
532
- cancellation: { parameter: "signal" }
533
- }]
534
- };
516
+ /** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
517
+ function modelSettingsChangesIdentity(packageName) {
518
+ const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
519
+ const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
520
+ if (!parts.length) throw new Error("Model settings package name has no RPC segment");
521
+ const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
522
+ if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
523
+ return {
524
+ service: segment,
525
+ namespace: segment
526
+ };
527
+ }
535
528
  //#endregion
536
529
  //#region ../dsh-plugin-kit/src/model-settings-client.ts
537
530
  /** This stream carries invalidations only; ready is never a settings snapshot. */
@@ -546,17 +539,44 @@ function parseModelSettingsChangeFrame(value) {
546
539
  };
547
540
  throw new Error("Invalid model settings change frame");
548
541
  }
549
- MODEL_SETTINGS_CHANGES_REMOTE.package, MODEL_SETTINGS_CHANGES_REMOTE.descriptors.map((descriptor) => ({
550
- ...descriptor,
551
- result: {
552
- mode: "strict",
553
- typeSymbol: "ModelSettings.ChangeFrame",
554
- create: () => ({ parse: parseModelSettingsChangeFrame })
555
- }
556
- }));
542
+ /** One owner's contribution. Each package mounts only its own endpoint. */
543
+ function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
544
+ return {
545
+ package: packageName,
546
+ descriptors: [{
547
+ id: `${identity.namespace}/watch`,
548
+ service: identity.service,
549
+ namespace: identity.namespace,
550
+ method: "watch",
551
+ mode: "stream",
552
+ invocation: { kind: "direct" },
553
+ parameters: [],
554
+ cancellation: { parameter: "signal" },
555
+ result: {
556
+ mode: "strict",
557
+ typeSymbol: "ModelSettings.ChangeFrame",
558
+ create: () => ({ parse: parseModelSettingsChangeFrame })
559
+ }
560
+ }]
561
+ };
562
+ }
563
+ /** Mount from a synchronous apply. Disposal waits for an in-flight mount and
564
+ * then withdraws it, so the contribution cannot outlive the plugin. */
565
+ function mountModelSettingsChanges(ctx, packageName) {
566
+ const contribution = modelSettingsChangesRemote(packageName);
567
+ ctx.inject(["remote"], (injected) => {
568
+ const scope = injected;
569
+ const mounting = scope.remote.$mount(contribution);
570
+ mounting.catch(() => {});
571
+ scope.effect(() => async () => {
572
+ await (await mounting.catch(() => void 0))?.();
573
+ });
574
+ });
575
+ }
557
576
  /** Native RemoteStream owns carrier reconnects; no timers or browser transport.
558
577
  * A factory shares one logical stream while at least one subscriber remains. */
559
- function createModelSettingsSubscriber(ctx, namespace) {
578
+ function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
579
+ const endpoint = identity;
560
580
  const listeners = /* @__PURE__ */ new Set();
561
581
  let injection;
562
582
  let current;
@@ -582,12 +602,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
582
602
  };
583
603
  const start = () => {
584
604
  const life = ++lifecycle;
585
- injection = ctx.inject(["remote", "remote.modelSettingsChanges"], (injected) => {
605
+ injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
586
606
  if (life !== lifecycle || !listeners.size) return;
587
607
  const scope = injected;
608
+ const service = scope.remote[endpoint.namespace];
609
+ if (!service || !("watch" in service) || !service.watch) {
610
+ report("Model settings sync service unavailable");
611
+ return;
612
+ }
613
+ const watch = service.watch;
588
614
  const stream = scope.remote.$stream({
589
615
  name: "Model settings sync",
590
- open: (signal) => scope.remote.modelSettingsChanges.watch(signal),
616
+ open: (signal) => watch(signal),
591
617
  ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
592
618
  });
593
619
  const session = {
@@ -622,7 +648,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
622
648
  invalidate();
623
649
  } else {
624
650
  if (!ready) throw new Error("Model settings sync change arrived before ready");
625
- if (namespace === "*" || frame.ns === namespace) invalidate();
651
+ if (accept(frame.ns)) invalidate();
626
652
  }
627
653
  }
628
654
  } catch (error) {
@@ -2321,7 +2347,9 @@ const styles = `${officialUiCss("ct-root")}${modelMenuCss}
2321
2347
  `;
2322
2348
  function apply(ctx) {
2323
2349
  const client = ctx;
2324
- const settingsSubscriber = createModelSettingsSubscriber(ctx, "@klarkxy/dsh-current-title");
2350
+ const packageName = "@klarkxy/dsh-current-title";
2351
+ mountModelSettingsChanges(ctx, packageName);
2352
+ const settingsSubscriber = createModelSettingsSubscriber(ctx, packageName, modelSettingsChangesIdentity(packageName));
2325
2353
  const subscribeSettings = (change, error) => settingsSubscriber.subscribe(change, error);
2326
2354
  const marker = createTitleClientMarker();
2327
2355
  ctx.provide(TITLE_CLIENT_SERVICE, marker);