@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 +2 -1
- package/docs/README.zh-CN.md +2 -1
- package/lib/client.inner.cjs +60 -32
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +60 -32
- 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/lib/client.js
CHANGED
|
@@ -519,25 +519,18 @@ ${scope} {
|
|
|
519
519
|
}
|
|
520
520
|
//#endregion
|
|
521
521
|
//#region ../dsh-plugin-kit/src/contracts.ts
|
|
522
|
-
/**
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
method: "watch",
|
|
535
|
-
mode: "stream",
|
|
536
|
-
invocation: { kind: "direct" },
|
|
537
|
-
parameters: [],
|
|
538
|
-
cancellation: { parameter: "signal" }
|
|
539
|
-
}]
|
|
540
|
-
};
|
|
522
|
+
/** `@klarkxy/dsh-git-commit` becomes `KlarkxyDshGitCommitModelSettingsChanges`. */
|
|
523
|
+
function modelSettingsChangesIdentity(packageName) {
|
|
524
|
+
const scoped = /^@([^/]+)\/(.+)$/.exec(packageName);
|
|
525
|
+
const parts = (scoped ? `${scoped[1]}/${scoped[2]}` : packageName).split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
526
|
+
if (!parts.length) throw new Error("Model settings package name has no RPC segment");
|
|
527
|
+
const segment = `${parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}ModelSettingsChanges`;
|
|
528
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(segment)) throw new Error(`Model settings sync name is not an RPC segment: ${segment}`);
|
|
529
|
+
return {
|
|
530
|
+
service: segment,
|
|
531
|
+
namespace: segment
|
|
532
|
+
};
|
|
533
|
+
}
|
|
541
534
|
//#endregion
|
|
542
535
|
//#region ../dsh-plugin-kit/src/model-settings-client.ts
|
|
543
536
|
/** This stream carries invalidations only; ready is never a settings snapshot. */
|
|
@@ -552,17 +545,44 @@ function parseModelSettingsChangeFrame(value) {
|
|
|
552
545
|
};
|
|
553
546
|
throw new Error("Invalid model settings change frame");
|
|
554
547
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
548
|
+
/** One owner's contribution. Each package mounts only its own endpoint. */
|
|
549
|
+
function modelSettingsChangesRemote(packageName, identity = modelSettingsChangesIdentity(packageName)) {
|
|
550
|
+
return {
|
|
551
|
+
package: packageName,
|
|
552
|
+
descriptors: [{
|
|
553
|
+
id: `${identity.namespace}/watch`,
|
|
554
|
+
service: identity.service,
|
|
555
|
+
namespace: identity.namespace,
|
|
556
|
+
method: "watch",
|
|
557
|
+
mode: "stream",
|
|
558
|
+
invocation: { kind: "direct" },
|
|
559
|
+
parameters: [],
|
|
560
|
+
cancellation: { parameter: "signal" },
|
|
561
|
+
result: {
|
|
562
|
+
mode: "strict",
|
|
563
|
+
typeSymbol: "ModelSettings.ChangeFrame",
|
|
564
|
+
create: () => ({ parse: parseModelSettingsChangeFrame })
|
|
565
|
+
}
|
|
566
|
+
}]
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
/** Mount from a synchronous apply. Disposal waits for an in-flight mount and
|
|
570
|
+
* then withdraws it, so the contribution cannot outlive the plugin. */
|
|
571
|
+
function mountModelSettingsChanges(ctx, packageName) {
|
|
572
|
+
const contribution = modelSettingsChangesRemote(packageName);
|
|
573
|
+
ctx.inject(["remote"], (injected) => {
|
|
574
|
+
const scope = injected;
|
|
575
|
+
const mounting = scope.remote.$mount(contribution);
|
|
576
|
+
mounting.catch(() => {});
|
|
577
|
+
scope.effect(() => async () => {
|
|
578
|
+
await (await mounting.catch(() => void 0))?.();
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
}
|
|
563
582
|
/** Native RemoteStream owns carrier reconnects; no timers or browser transport.
|
|
564
583
|
* A factory shares one logical stream while at least one subscriber remains. */
|
|
565
|
-
function createModelSettingsSubscriber(ctx,
|
|
584
|
+
function createModelSettingsSubscriber(ctx, packageName, identity = modelSettingsChangesIdentity(packageName), accept = (ns) => ns === packageName) {
|
|
585
|
+
const endpoint = identity;
|
|
566
586
|
const listeners = /* @__PURE__ */ new Set();
|
|
567
587
|
let injection;
|
|
568
588
|
let current;
|
|
@@ -588,12 +608,18 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
588
608
|
};
|
|
589
609
|
const start = () => {
|
|
590
610
|
const life = ++lifecycle;
|
|
591
|
-
injection = ctx.inject(["remote",
|
|
611
|
+
injection = ctx.inject(["remote", `remote.${endpoint.namespace}`], (injected) => {
|
|
592
612
|
if (life !== lifecycle || !listeners.size) return;
|
|
593
613
|
const scope = injected;
|
|
614
|
+
const service = scope.remote[endpoint.namespace];
|
|
615
|
+
if (!service || !("watch" in service) || !service.watch) {
|
|
616
|
+
report("Model settings sync service unavailable");
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const watch = service.watch;
|
|
594
620
|
const stream = scope.remote.$stream({
|
|
595
621
|
name: "Model settings sync",
|
|
596
|
-
open: (signal) =>
|
|
622
|
+
open: (signal) => watch(signal),
|
|
597
623
|
ended: (accepted) => /* @__PURE__ */ new Error(`Model settings sync stream ended ${accepted ? "after" : "before"} ready; refresh or reopen the page`)
|
|
598
624
|
});
|
|
599
625
|
const session = {
|
|
@@ -628,7 +654,7 @@ function createModelSettingsSubscriber(ctx, namespace) {
|
|
|
628
654
|
invalidate();
|
|
629
655
|
} else {
|
|
630
656
|
if (!ready) throw new Error("Model settings sync change arrived before ready");
|
|
631
|
-
if (
|
|
657
|
+
if (accept(frame.ns)) invalidate();
|
|
632
658
|
}
|
|
633
659
|
}
|
|
634
660
|
} catch (error) {
|
|
@@ -2327,7 +2353,9 @@ const styles = `${officialUiCss("ct-root")}${modelMenuCss}
|
|
|
2327
2353
|
`;
|
|
2328
2354
|
function apply(ctx) {
|
|
2329
2355
|
const client = ctx;
|
|
2330
|
-
const
|
|
2356
|
+
const packageName = "@klarkxy/dsh-current-title";
|
|
2357
|
+
mountModelSettingsChanges(ctx, packageName);
|
|
2358
|
+
const settingsSubscriber = createModelSettingsSubscriber(ctx, packageName, modelSettingsChangesIdentity(packageName));
|
|
2331
2359
|
const subscribeSettings = (change, error) => settingsSubscriber.subscribe(change, error);
|
|
2332
2360
|
const marker = createTitleClientMarker();
|
|
2333
2361
|
ctx.provide(TITLE_CLIENT_SERVICE, marker);
|
package/lib/contracts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ModelRoute, defaultModelRoute, normalizeModelRoute } from "@klarkxy/dsh-model-route";
|
|
2
1
|
import { RpcResult } 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
|
declare const PLUGIN_NAME = "@klarkxy/dsh-current-title";
|
|
5
5
|
declare const FEATURE_ID = "current-title";
|
package/lib/index.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ declare class CurrentTitleService {
|
|
|
123
123
|
private settingsPending;
|
|
124
124
|
private disposed;
|
|
125
125
|
private readonly inFlight;
|
|
126
|
+
private readonly generations;
|
|
126
127
|
readonly support: TitleSupport;
|
|
127
128
|
constructor(options: {
|
|
128
129
|
plugin: string;
|
|
@@ -155,6 +156,7 @@ declare class CurrentTitleService {
|
|
|
155
156
|
regenerate(sessionId: string, signal: AbortSignal): Promise<TitleSnapshot | undefined>;
|
|
156
157
|
read(session: SessionLike): TitleSnapshot | undefined;
|
|
157
158
|
private nativeGenerate;
|
|
159
|
+
private runNativeGenerate;
|
|
158
160
|
}
|
|
159
161
|
//#endregion
|
|
160
162
|
//#region src/input.d.ts
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DEFAULT_TIMEOUT_MS, PLUGIN_NAME, PROVIDER_ID, RPC_CHANNEL, SETTINGS_KEY, defaultGenerateConfig, defaultModelRoute, isTitleLocaleMode, normalizeCadence, normalizeModelRoute, normalizePrompt } from "./contracts.js";
|
|
2
2
|
import { registerHostRpc } from "@klarkxy/dsh-plugin-kit/host-rpc";
|
|
3
|
+
import { isSubagentSession, 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
|
-
import "@klarkxy/dsh-model-route";
|
|
5
|
-
import { isSubagentSession } from "@klarkxy/dsh-plugin-kit/contracts";
|
|
6
6
|
import { callLlmText, resolveFeatureModel } from "@klarkxy/dsh-plugin-kit";
|
|
7
7
|
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -251,32 +251,32 @@ async function generateCurrentTitle(options) {
|
|
|
251
251
|
const timeoutMs = Number.isFinite(options.config.timeoutMs) && options.config.timeoutMs > 0 ? options.config.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
252
252
|
const timer = setTimeout(() => deadline.abort(new DOMException("Title generation timed out.", "TimeoutError")), timeoutMs);
|
|
253
253
|
const signal = AbortSignal.any([options.signal, deadline.signal]);
|
|
254
|
-
let abort = () => {};
|
|
255
|
-
const cancelled = new Promise((_resolve, reject) => {
|
|
256
|
-
abort = () => reject(signal.reason);
|
|
257
|
-
if (signal.aborted) abort();
|
|
258
|
-
else signal.addEventListener("abort", abort, { once: true });
|
|
259
|
-
});
|
|
260
254
|
let result;
|
|
261
255
|
try {
|
|
262
|
-
result = await
|
|
256
|
+
result = await callLlmText(options.llm, {
|
|
263
257
|
plugin: PLUGIN_NAME,
|
|
264
258
|
route: callRoute,
|
|
265
259
|
system: systemPrompt(options.config, options.prompt),
|
|
266
260
|
text: framedInput,
|
|
267
261
|
maxTokens: options.config.maxOutputTokens,
|
|
268
262
|
purpose: "session-title",
|
|
263
|
+
configure: (controls, model) => {
|
|
264
|
+
const effort = model.reasoning?.efforts[0]?.id;
|
|
265
|
+
return {
|
|
266
|
+
...controls,
|
|
267
|
+
...effort === void 0 ? {} : { reasoningEffort: effort }
|
|
268
|
+
};
|
|
269
|
+
},
|
|
269
270
|
signal,
|
|
270
271
|
sessionId: options.sessionId,
|
|
271
272
|
isCurrent: options.isCurrent
|
|
272
|
-
})
|
|
273
|
+
});
|
|
273
274
|
signal.throwIfAborted();
|
|
274
275
|
} catch (error) {
|
|
275
276
|
signal.throwIfAborted();
|
|
276
277
|
throw error;
|
|
277
278
|
} finally {
|
|
278
279
|
clearTimeout(timer);
|
|
279
|
-
signal.removeEventListener("abort", abort);
|
|
280
280
|
}
|
|
281
281
|
options.signal.throwIfAborted();
|
|
282
282
|
if (!options.isCurrent()) throw Object.assign(/* @__PURE__ */ new Error("dsh-current-title: generation is no longer current"), { code: "superseded" });
|
|
@@ -487,6 +487,7 @@ var CurrentTitleService = class {
|
|
|
487
487
|
settingsPending = Promise.resolve();
|
|
488
488
|
disposed = false;
|
|
489
489
|
inFlight = /* @__PURE__ */ new Map();
|
|
490
|
+
generations = /* @__PURE__ */ new Set();
|
|
490
491
|
support;
|
|
491
492
|
constructor(options) {
|
|
492
493
|
this.options = options;
|
|
@@ -527,6 +528,7 @@ var CurrentTitleService = class {
|
|
|
527
528
|
this.generation += 1;
|
|
528
529
|
for (const controller of this.inFlight.values()) controller.abort(/* @__PURE__ */ new Error("current-title disabled"));
|
|
529
530
|
this.inFlight.clear();
|
|
531
|
+
await Promise.allSettled([...this.generations]);
|
|
530
532
|
await this.settingsPending;
|
|
531
533
|
const snapshot = this.nativeSlot?.displacement;
|
|
532
534
|
const outcome = await releaseTitleSlot(this.nativeSlot ?? {
|
|
@@ -634,7 +636,14 @@ var CurrentTitleService = class {
|
|
|
634
636
|
updatedAt: snapshot.updatedAt ?? 0
|
|
635
637
|
};
|
|
636
638
|
}
|
|
637
|
-
|
|
639
|
+
nativeGenerate(request) {
|
|
640
|
+
if (this.disposed) return Promise.reject(/* @__PURE__ */ new Error("dsh-current-title: plugin disabled"));
|
|
641
|
+
const pending = this.runNativeGenerate(request);
|
|
642
|
+
this.generations.add(pending);
|
|
643
|
+
pending.then(() => this.generations.delete(pending), () => this.generations.delete(pending));
|
|
644
|
+
return pending;
|
|
645
|
+
}
|
|
646
|
+
async runNativeGenerate(request) {
|
|
638
647
|
const llm = this.options.llm;
|
|
639
648
|
if (!llm) throw new Error("dsh-current-title: llm is not available");
|
|
640
649
|
const generation = this.generation;
|
|
@@ -801,6 +810,7 @@ const inject = [
|
|
|
801
810
|
"agentDefaultModel"
|
|
802
811
|
];
|
|
803
812
|
async function apply(ctx, config = {}) {
|
|
813
|
+
createModelSettingsChanges(ctx, modelSettingsChangesIdentity(PLUGIN_NAME), PLUGIN_NAME);
|
|
804
814
|
const host = ctx;
|
|
805
815
|
const domain = await host.storageDomain.open(titleDomain);
|
|
806
816
|
const table = domain.table("settings");
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/input.ts","../src/output.ts","../src/messages.ts","../src/generate.ts","../src/ownership.ts","../src/native-slot.ts","../src/storage.ts","../src/service.ts","../src/index.ts"],"sourcesContent":["import type { TitleMessage } from './contracts.ts'\n\nexport const FRAME_PREFIX =\n 'Choose the current task from these recent human messages, ordered oldest to newest:\\n'\n\nexport function frameMessages(messages: readonly TitleMessage[]): string {\n return `${FRAME_PREFIX}${JSON.stringify(messages)}`\n}\n\nexport function utf8Bytes(value: string): number {\n return Buffer.byteLength(value, 'utf8')\n}\n\nfunction middleSlice(codePoints: readonly string[], kept: number): string {\n if (kept >= codePoints.length) return codePoints.join('')\n if (kept <= 0) return ''\n if (kept === 1) return '…'\n\n const contentPoints = kept - 1\n const headCount = Math.ceil(contentPoints / 2)\n const tailCount = Math.floor(contentPoints / 2)\n return `${codePoints.slice(0, headCount).join('')}…${\n tailCount === 0 ? '' : codePoints.slice(-tailCount).join('')\n }`\n}\n\nexport function fitSingleMessage(message: TitleMessage, maxInputBytes: number): TitleMessage {\n const empty = { ...message, text: '' }\n if (utf8Bytes(frameMessages([empty])) > maxInputBytes) {\n throw new Error('dsh-current-title: maxInputBytes is too small for the input envelope')\n }\n if (utf8Bytes(frameMessages([message])) <= maxInputBytes) return message\n\n const points = Array.from(message.text)\n let low = 0\n let high = points.length\n let best = ''\n\n while (low <= high) {\n const kept = Math.floor((low + high) / 2)\n const text = middleSlice(points, kept)\n if (utf8Bytes(frameMessages([{ ...message, text }])) <= maxInputBytes) {\n best = text\n low = kept + 1\n } else {\n high = kept - 1\n }\n }\n\n return { ...message, text: best }\n}\n\nexport function selectRecentMessages(\n messages: readonly TitleMessage[],\n maxRecentMessages: number,\n maxInputBytes: number,\n): TitleMessage[] {\n if (messages.length === 0) return []\n\n const selected = messages.slice(-maxRecentMessages).map(message => ({ ...message }))\n while (selected.length > 1 && utf8Bytes(frameMessages(selected)) > maxInputBytes) {\n selected.shift()\n }\n\n if (utf8Bytes(frameMessages(selected)) > maxInputBytes) {\n selected[0] = fitSingleMessage(selected[0]!, maxInputBytes)\n }\n\n return selected\n}\n","export const TITLE_TYPE_KEYS = [\n 'feature',\n 'fix',\n 'optimize',\n 'refactor',\n 'test',\n 'docs',\n 'release',\n 'config',\n 'explore',\n 'discuss',\n] as const\n\nexport const TITLE_LOCALES = ['zh', 'en'] as const\nexport const TITLE_LOCALE_MODES = ['auto', ...TITLE_LOCALES] as const\n\nexport type TitleType = (typeof TITLE_TYPE_KEYS)[number]\nexport type TitleLocale = (typeof TITLE_LOCALES)[number]\nexport type TitleLocaleMode = (typeof TITLE_LOCALE_MODES)[number]\n\nconst TITLE_TYPE_LABELS: Record<TitleLocale, Record<TitleType, string>> = {\n zh: {\n feature: '功能',\n fix: '修复',\n optimize: '优化',\n refactor: '重构',\n test: '测试',\n docs: '文档',\n release: '发布',\n config: '配置',\n explore: '探索',\n discuss: '讨论',\n },\n en: {\n feature: 'Feature',\n fix: 'Fix',\n optimize: 'Optimize',\n refactor: 'Refactor',\n test: 'Test',\n docs: 'Docs',\n release: 'Release',\n config: 'Config',\n explore: 'Explore',\n discuss: 'Discussion',\n },\n}\n\nexport interface ParsedTitle {\n type: TitleType\n summary: string\n}\n\nconst OSC_SEQUENCE = /(?:\\u001B\\]|\\u009D)(?:(?!\\u0007|\\u001B\\\\)[\\s\\S])*(?:\\u0007|\\u001B\\\\|$)/gu\nconst CSI_SEQUENCE = /(?:\\u001B\\[|\\u009B)[0-?]*[ -/]*[@-~]/gu\nconst ESC_SEQUENCE = /\\u001B[@-_]/gu\nconst CONTROL_CHARACTER = /[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u009F]/gu\nconst DIRECTIONAL_CONTROL = /[\\u200B\\u200E\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF]/gu\n\nfunction cleanTitleText(input: string): string {\n return input\n .replace(OSC_SEQUENCE, '')\n .replace(CSI_SEQUENCE, '')\n .replace(ESC_SEQUENCE, '')\n .replace(CONTROL_CHARACTER, '')\n .replace(DIRECTIONAL_CONTROL, '')\n .replace(/\\s+/gu, ' ')\n .trim()\n}\n\nexport function truncateTitleUtf8(input: string, maxBytes: number): string {\n if (!Number.isInteger(maxBytes) || maxBytes <= 0) throw new Error('maxBytes must be a positive integer')\n if (Buffer.byteLength(input, 'utf8') <= maxBytes) return input\n let used = 0\n let output = ''\n for (const character of input) {\n const bytes = Buffer.byteLength(character, 'utf8')\n if (used + bytes > maxBytes) break\n output += character\n used += bytes\n }\n return output\n}\n\n/** Same sanitizing rules as DSH 0.1.7-rc.2 `normalizeSessionTitle`. */\nexport function normalizeSessionTitle(input: string, maxBytes: number): string {\n return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd()\n}\n\nfunction isTitleType(value: string): value is TitleType {\n return (TITLE_TYPE_KEYS as readonly string[]).includes(value)\n}\n\nexport function resolveTitleLocale(\n mode: TitleLocaleMode,\n messages: readonly string[],\n preference?: string,\n): TitleLocale {\n if (mode !== 'auto') return mode\n\n const preferred = preference?.trim().toLowerCase().split('-')[0]\n if (preferred === 'zh' || preferred === 'en') return preferred\n\n const text = messages.join('\\n')\n if (/[\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u.test(text)) return 'en'\n return /\\p{Script=Han}/u.test(text) ? 'zh' : 'en'\n}\n\nfunction removeTitleSyntax(value: string): string {\n return value.replace(/[|`*_~#\\[\\]\"“”]/gu, ' ')\n}\n\nfunction truncateSummary(value: string, targetWords: number, targetCjkCharacters: number): string {\n const containsCjk = /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u.test(value)\n if (containsCjk) {\n return Array.from(value.replace(/\\s+/gu, '')).slice(0, targetCjkCharacters).join('')\n }\n return value.split(/\\s+/u).filter(Boolean).slice(0, targetWords).join(' ')\n}\n\nfunction unwrapModelText(raw: string): string {\n const trimmed = raw.trim()\n const fenced = /^```(?:json)?\\s*([\\s\\S]*?)\\s*```$/iu.exec(trimmed)\n return (fenced?.[1] ?? trimmed).trim()\n}\n\nfunction readJsonObject(raw: string): Record<string, unknown> | undefined {\n const text = unwrapModelText(raw)\n const start = text.indexOf('{')\n const end = text.lastIndexOf('}')\n if (start === -1 || end <= start) return undefined\n try {\n const value = JSON.parse(text.slice(start, end + 1))\n if (value && typeof value === 'object' && !Array.isArray(value)) return value as Record<string, unknown>\n } catch {\n return undefined\n }\n return undefined\n}\n\n/**\n * Accept the required JSON shape, including a code fence or a short preface.\n * Extra keys are ignored. A plain one-line title still becomes a title so a\n * chatty model does not leave the session on the built-in fallback.\n */\nexport function parseModelTitle(\n raw: string,\n targetWords: number,\n targetCjkCharacters: number,\n): ParsedTitle {\n const candidate = readJsonObject(raw)\n const typeValue = typeof candidate?.type === 'string' ? candidate.type.trim().toLowerCase() : ''\n const summaryValue = typeof candidate?.summary === 'string' ? candidate.summary : ''\n const type = isTitleType(typeValue) ? typeValue : 'discuss'\n const source = summaryValue || (candidate ? '' : unwrapModelText(raw).replace(/^[\"'`]+|[\"'`]+$/gu, ''))\n const normalized = normalizeSessionTitle(removeTitleSyntax(source), Number.MAX_SAFE_INTEGER)\n const summary = truncateSummary(normalized, targetWords, targetCjkCharacters)\n if (summary.length === 0) {\n throw new Error('dsh-current-title: title model returned an empty summary')\n }\n return { type, summary }\n}\n\nexport function localMonthDay(now: Date): string {\n const month = String(now.getMonth() + 1).padStart(2, '0')\n const day = String(now.getDate()).padStart(2, '0')\n return `${month}${day}`\n}\n\nexport function formatTitle(parsed: ParsedTitle, locale: TitleLocale, now = new Date()): string {\n return `${localMonthDay(now)} | ${TITLE_TYPE_LABELS[locale][parsed.type]} | ${parsed.summary}`\n}\n","import { normalizeSessionTitle } from './output.ts'\nimport type { TitleMessage, TitleSnapshot, TitleSourceKind } from './contracts.ts'\n\nexport interface SessionEventLike {\n readonly type: string\n readonly seq: number\n readonly time?: number\n readonly data?: {\n readonly source?: { readonly kind?: string; readonly plugin?: string; readonly provider?: string }\n readonly content?: ReadonlyArray<{ readonly type?: string; readonly text?: string }>\n readonly title?: string\n readonly messageSeqs?: readonly number[]\n }\n}\n\nexport interface SessionLike {\n readonly id: string\n readonly seq?: number\n snapshotEvents(): readonly SessionEventLike[]\n append?(type: string, data: unknown): unknown\n}\n\nfunction textFromContent(content: ReadonlyArray<{ readonly type?: string; readonly text?: string }> | undefined): string {\n if (!Array.isArray(content)) return ''\n return content\n .filter(block => block && block.type === 'text' && typeof block.text === 'string')\n .map(block => block.text as string)\n .join('\\n')\n}\n\n/** Eligible human prompts only. Plugin/tool/model user-role rows are excluded. */\nexport function collectHumanMessages(events: readonly SessionEventLike[], throughSeq?: number): TitleMessage[] {\n const messages: TitleMessage[] = []\n for (const event of events) {\n if (throughSeq !== undefined && event.seq > throughSeq) break\n if (event.type !== 'user/message') continue\n if (event.data?.source?.kind !== 'user') continue\n const text = textFromContent(event.data.content)\n if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) continue\n messages.push({ seq: event.seq, text })\n }\n return messages\n}\n\nexport function foldTitle(events: readonly SessionEventLike[]): TitleSnapshot | undefined {\n let latest: SessionEventLike | undefined\n for (const event of events) {\n if (event.type === 'session/title') latest = event\n }\n if (!latest?.data || typeof latest.data.title !== 'string') return undefined\n const kind = latest.data.source?.kind\n const sourceKind: TitleSourceKind = kind === 'user' || kind === 'fallback' || kind === 'provider' ? kind : 'provider'\n return {\n title: latest.data.title,\n messageSeqs: latest.data.messageSeqs ? [...latest.data.messageSeqs] : [],\n source: { kind: sourceKind, ...(typeof latest.data.source?.provider === 'string' ? { provider: latest.data.source.provider } : {}) },\n eventSeq: latest.seq,\n updatedAt: latest.time ?? 0,\n }\n}\n\nexport function userRenameNewerThan(events: readonly SessionEventLike[], watermarkSeq: number): boolean {\n const current = foldTitle(events)\n return Boolean(current && current.source.kind === 'user' && current.eventSeq > watermarkSeq)\n}\n\nexport function sourceVersionOf(sessionId: string, messages: readonly TitleMessage[]): string {\n const last = messages.at(-1)\n return `${sessionId}:${last?.seq ?? -1}:${messages.length}`\n}\n","import { callLlmText, resolveFeatureModel, type LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport type { ModelRoute } from '@klarkxy/dsh-model-route'\nimport type { GenerateConfig, TitleMessage, TitleModelRoute } from './contracts.ts'\nimport { DEFAULT_TIMEOUT_MS, PLUGIN_NAME } from './contracts.ts'\nimport { frameMessages, selectRecentMessages } from './input.ts'\nimport { formatTitle, normalizeSessionTitle, parseModelTitle, resolveTitleLocale, type TitleLocaleMode } from './output.ts'\nimport { sourceVersionOf } from './messages.ts'\n\nexport interface GeneratedTitle {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly model?: { readonly provider: string; readonly model: string }\n readonly sourceVersion: string\n}\n\nexport function systemPrompt(config: GenerateConfig, customPrompt = ''): string {\n const instruction = customPrompt.trim()\n return [\n instruction || 'Name the current task in an AI coding-assistant session.',\n 'Prioritize the newest human messages. Older messages are context only and must not keep a completed task in the title.',\n 'Allowed type values: feature, fix, optimize, refactor, test, docs, release, config, explore, discuss.',\n 'Return exactly one JSON object: {\"type\":\"<type>\",\"summary\":\"<summary>\"}.',\n 'Return no Markdown, code fence, explanation, date, or extra key.',\n 'Keep the summary in the language of the recent messages.',\n `Aim for at most ${config.targetWords} non-CJK words or ${config.targetCjkCharacters} CJK characters.`,\n ].join('\\n')\n}\n\n/**\n * Saved override passed to resolveFeatureModel. Unlike modelRouteOverride,\n * this does not trim or re-apply the 250/80 caps: stored rows are already\n * normalized, and a whitespace-only id must stay a miss (not a trimmed hit)\n * so the host-default fallback is unchanged.\n */\nexport function titleModelRoute(route: TitleModelRoute | undefined): ModelRoute | undefined {\n if (!route?.provider || !route.model) return undefined\n return route.reasoningEffort\n ? { provider: route.provider, model: route.model, reasoningEffort: route.reasoningEffort }\n : { provider: route.provider, model: route.model }\n}\n\nexport async function generateCurrentTitle(options: {\n llm: LlmTextCaller\n host: unknown\n config: GenerateConfig\n sessionId: string\n messages: readonly TitleMessage[]\n prompt?: string\n model?: TitleModelRoute\n localePreference?: string\n localeMode?: TitleLocaleMode\n signal: AbortSignal\n isCurrent: () => boolean\n now?: Date\n}): Promise<GeneratedTitle> {\n options.signal.throwIfAborted()\n if (!options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n const selected = selectRecentMessages(\n options.messages,\n options.config.maxRecentMessages,\n options.config.maxInputBytes,\n )\n if (selected.length === 0) throw new Error('dsh-current-title: at least one source message is required')\n const route = resolveFeatureModel(options.host, titleModelRoute(options.model), options.sessionId)\n if (!route) throw new Error('dsh-current-title: 请在插件页选择模型,或设置宿主默认对话模型。')\n // Titles never think: reasoning effort is never forwarded (matching the\n // bundled dsh-session-title-llm policy), so a thinking model cannot burn the\n // small token cap on hidden reasoning and leave an empty reply.\n const callRoute = { provider: route.provider, model: route.model }\n\n const framedInput = frameMessages(selected)\n const locale = resolveTitleLocale(\n options.localeMode ?? options.config.locale,\n selected.map(message => message.text),\n options.localePreference,\n )\n const sourceVersion = sourceVersionOf(options.sessionId, selected)\n const deadline = new AbortController()\n const timeoutMs = Number.isFinite(options.config.timeoutMs) && options.config.timeoutMs > 0\n ? options.config.timeoutMs : DEFAULT_TIMEOUT_MS\n const timer = setTimeout(() => deadline.abort(new DOMException('Title generation timed out.', 'TimeoutError')), timeoutMs)\n const signal = AbortSignal.any([options.signal, deadline.signal])\n let abort = () => {}\n const cancelled = new Promise<never>((_resolve, reject) => {\n abort = () => reject(signal.reason)\n if (signal.aborted) abort()\n else signal.addEventListener('abort', abort, { once: true })\n })\n let result\n try {\n result = await Promise.race([callLlmText(options.llm, {\n plugin: PLUGIN_NAME,\n route: callRoute,\n system: systemPrompt(options.config, options.prompt),\n text: framedInput,\n maxTokens: options.config.maxOutputTokens,\n purpose: 'session-title',\n signal,\n sessionId: options.sessionId,\n isCurrent: options.isCurrent,\n }), cancelled])\n signal.throwIfAborted()\n } catch (error) {\n // The shared caller translates stream cancellation to AbortError. Retain\n // the originating deadline or lifecycle reason at this feature boundary.\n signal.throwIfAborted()\n throw error\n } finally {\n clearTimeout(timer)\n signal.removeEventListener('abort', abort)\n }\n options.signal.throwIfAborted()\n if (!options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n const parsed = parseModelTitle(result.text, options.config.targetWords, options.config.targetCjkCharacters)\n const title = normalizeSessionTitle(formatTitle(parsed, locale, options.now ?? new Date()), options.config.maxTitleBytes)\n if (!title) throw new Error('dsh-current-title: title model returned an empty summary')\n return {\n title,\n messageSeqs: selected.map(message => message.seq),\n model: { provider: result.provider, model: result.model },\n sourceVersion,\n }\n}\n","export interface OwnershipClaim {\n readonly id: string\n readonly dispose: () => void | Promise<void>\n}\n\nexport interface TitleSlot {\n owner(): string | undefined\n occupy(id: string): Promise<() => void | Promise<void>>\n}\n\n/** Exclusive title-provider ownership. Enable claims the slot; disable releases only while this id still holds it. */\nexport async function claimTitleSlot(slot: TitleSlot, id: string): Promise<OwnershipClaim> {\n const dispose = await slot.occupy(id)\n return { id, dispose }\n}\n\nexport async function releaseTitleSlot(\n slot: TitleSlot,\n claim: OwnershipClaim | undefined,\n): Promise<'released' | 'left-other-owner' | 'idle'> {\n if (!claim) return 'idle'\n if (slot.owner() !== claim.id) return 'left-other-owner'\n await claim.dispose()\n if (slot.owner() && slot.owner() !== claim.id) return 'left-other-owner'\n return 'released'\n}\n\nexport function occupiedProviderId(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error)\n return /session-title provider \"([^\"]+)\" is already registered/.exec(message)?.[1]\n}\n","import { PROVIDER_ID } from './contracts.ts'\nimport { occupiedProviderId, type TitleSlot } from './ownership.ts'\n\nexport interface SessionTitleProvider {\n readonly id: string\n readonly automatic: 'first-prompt' | 'all-prompts'\n generate(request: {\n session: { id: string; snapshotEvents(): readonly unknown[] }\n messages: ReadonlyArray<{ seq: number; text: string }>\n route?: { provider: string; model: string }\n signal: AbortSignal\n }): Promise<{ title: string; messageSeqs: readonly number[]; model?: { provider: string; model: string } }>\n}\n\nexport interface SessionTitleServiceLike {\n register(provider: SessionTitleProvider): () => void | Promise<void>\n get(session: unknown): { title: string; source?: { kind?: string; provider?: string }; eventSeq?: number; updatedAt?: number; messageSeqs?: readonly number[] } | undefined\n refresh(session: unknown, signal?: AbortSignal): Promise<unknown>\n}\n\nexport interface LoaderEntryOptions {\n id?: string\n name?: string\n disabled?: boolean | null\n config?: unknown\n inject?: unknown\n group?: boolean | null\n}\n\nexport interface LoaderEntry {\n id: string\n options?: LoaderEntryOptions\n}\n\nexport interface LoaderFace {\n entries(): Iterable<LoaderEntry>\n update(id: string, options: { disabled?: boolean | null }): Promise<unknown> | unknown\n}\n\nexport interface Displacement {\n readonly id: string\n readonly name: string\n readonly identity: string\n}\n\nfunction catalogLookupId(entryId: string): string {\n const colon = entryId.indexOf(':')\n return colon === -1 ? entryId : entryId.slice(colon + 1)\n}\n\nfunction entryName(entry: LoaderEntry): string {\n return String(entry.options?.name ?? '')\n}\n\nexport function entryDisabled(entry: LoaderEntry): boolean {\n return entry.options?.disabled === true\n}\n\nexport function displacementIdentity(entry: LoaderEntry): string {\n const options = entry.options ?? {}\n const { disabled: _disabled, ...rest } = options\n return JSON.stringify({ id: entry.id, name: entryName(entry), rest })\n}\n\nexport function captureDisplacement(entry: LoaderEntry): Displacement {\n return { id: entry.id, name: entryName(entry), identity: displacementIdentity(entry) }\n}\n\nexport function displacementUnchanged(snapshot: Displacement, entry: LoaderEntry): boolean {\n return entry.id === snapshot.id\n && entryName(entry) === snapshot.name\n && displacementIdentity(entry) === snapshot.identity\n}\n\nexport function findEntryById(loader: LoaderFace, id: string): LoaderEntry | undefined {\n for (const entry of loader.entries()) {\n if (entry.id === id) return entry\n }\n return undefined\n}\n\nexport function findLoaderEntry(loader: LoaderFace, providerId: string): LoaderEntry | undefined {\n for (const entry of loader.entries()) {\n const name = entryName(entry)\n const ids = [entry.id, entry.options?.id, name, catalogLookupId(entry.id)]\n if (ids.some(value => value === providerId)) return entry\n if (name.endsWith(`/${providerId}`) || name.endsWith(providerId)) return entry\n if (providerId === 'session-title-first-prompt-llm' && catalogLookupId(entry.id) === 'session-title-llm') return entry\n }\n return undefined\n}\n\nexport async function restoreOwnDisplacement(loader: LoaderFace | undefined, snapshot: Displacement | undefined): Promise<'restored' | 'skipped'> {\n if (!loader || !snapshot) return 'skipped'\n const current = findEntryById(loader, snapshot.id)\n if (!current || !entryDisabled(current) || !displacementUnchanged(snapshot, current)) return 'skipped'\n await loader.update(snapshot.id, { disabled: false })\n return 'restored'\n}\n\nexport function createNativeTitleSlot(options: {\n sessionTitle: SessionTitleServiceLike\n loader: LoaderFace\n /** Read at each occupy so a settings change can re-register with a new cadence. */\n automatic: () => SessionTitleProvider['automatic']\n generate: SessionTitleProvider['generate']\n}): TitleSlot & { displacement?: Displacement } {\n let owner: string | undefined\n const slot: TitleSlot & { displacement?: Displacement } = {\n owner: () => owner,\n async occupy(id: string) {\n const provider: SessionTitleProvider = {\n id: PROVIDER_ID,\n automatic: options.automatic(),\n generate: options.generate,\n }\n try {\n const dispose = options.sessionTitle.register(provider)\n owner = id\n return async () => {\n await dispose()\n if (owner === id) owner = undefined\n }\n } catch (error) {\n const occupied = occupiedProviderId(error)\n if (!occupied) throw error\n const entry = findLoaderEntry(options.loader, occupied)\n if (!entry || entryDisabled(entry)) throw error\n const snapshot = captureDisplacement(entry)\n await options.loader.update(entry.id, { disabled: true })\n const afterDisable = findEntryById(options.loader, entry.id)\n if (!afterDisable || !displacementUnchanged(snapshot, afterDisable)) throw error\n try {\n const dispose = options.sessionTitle.register(provider)\n slot.displacement = snapshot\n owner = id\n return async () => {\n await dispose()\n if (owner === id) owner = undefined\n }\n } catch (second) {\n if (findEntryById(options.loader, snapshot.id) && displacementUnchanged(snapshot, findEntryById(options.loader, snapshot.id)!)) {\n await options.loader.update(snapshot.id, { disabled: false })\n }\n throw second\n }\n }\n },\n }\n return slot\n}\n","import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\nimport { modelRouteKey as sharedModelRouteKey } from '@klarkxy/dsh-model-route'\nimport { z } from 'zod'\nimport {\n SETTINGS_KEY, defaultModelRoute, isTitleLocaleMode, normalizeCadence, normalizeModelRoute, normalizePrompt,\n type TitleModelRoute, type TitleSettings,\n} from './contracts.ts'\n\nexport { SETTINGS_KEY }\n\nconst localeSchema = z.enum(['auto', 'zh', 'en'])\n\n/** Version 1 stored only the locale. Prompt and model are filled as defaults. */\nconst legacySettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: localeSchema,\n}).strict()\n\nconst modelRouteSchema = z.object({\n provider: z.string(),\n model: z.string(),\n reasoningEffort: z.string().optional(),\n}).strict()\n\nexport const titleSettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: localeSchema,\n prompt: z.string(),\n model: modelRouteSchema,\n /** Defaulted so rows stored before the cadence switch existed still parse. */\n cadence: z.enum(['all-prompts', 'first-prompt']).default('all-prompts'),\n}).strict()\n\nexport const titleDomain = defineDomain({\n name: 'dsh_editor_current_title',\n version: 2,\n tables: {\n settings: domainTable<string, TitleSettings>(titleSettingsSchema),\n },\n})\n\nexport function parseTitleSettings(value: unknown): TitleSettings | undefined {\n const current = titleSettingsSchema.safeParse(value)\n if (current.success) {\n return {\n revision: current.data.revision,\n locale: isTitleLocaleMode(current.data.locale) ? current.data.locale : 'auto',\n prompt: normalizePrompt(current.data.prompt),\n model: normalizeModelRoute(current.data.model),\n cadence: normalizeCadence(current.data.cadence),\n }\n }\n const legacy = legacySettingsSchema.safeParse(value)\n if (!legacy.success || !isTitleLocaleMode(legacy.data.locale)) return undefined\n return {\n revision: legacy.data.revision,\n locale: legacy.data.locale,\n prompt: '',\n model: defaultModelRoute(),\n cadence: 'all-prompts',\n }\n}\n\nexport function storedSettings(value: unknown, _fallbackLocale: TitleSettings['locale'] = 'auto'): TitleSettings {\n const parsed = parseTitleSettings(value)\n return {\n revision: parsed?.revision ?? 0,\n locale: 'auto',\n prompt: parsed?.prompt ?? '',\n model: parsed?.model ?? defaultModelRoute(),\n cadence: parsed?.cadence ?? 'all-prompts',\n }\n}\n\nexport function settingsPatch(current: TitleSettings, patch: {\n prompt?: unknown\n model?: unknown\n cadence?: unknown\n}): Pick<TitleSettings, 'prompt' | 'model' | 'cadence'> & { locale: 'auto' } {\n return {\n locale: 'auto',\n prompt: patch.prompt === undefined ? current.prompt : normalizePrompt(patch.prompt),\n model: patch.model === undefined ? current.model : normalizeModelRoute(patch.model),\n cadence: patch.cadence === undefined ? current.cadence : normalizeCadence(patch.cadence),\n }\n}\n\n/** Same separator and empty-id rule as @klarkxy/dsh-model-route. No in-tree callers. */\nexport function modelRouteKey(route: TitleModelRoute): string {\n return sharedModelRouteKey(route.provider, route.model)\n}\n","import type { RpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport type { LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport type { GenerateConfig, TitleSettings, TitleSnapshot, TitleStatus, TitleSupport } from './contracts.ts'\nimport { PROVIDER_ID, defaultGenerateConfig } from './contracts.ts'\nimport { generateCurrentTitle } from './generate.ts'\nimport { collectHumanMessages, type SessionLike } from './messages.ts'\nimport {\n createNativeTitleSlot, restoreOwnDisplacement, type LoaderFace, type SessionTitleServiceLike,\n} from './native-slot.ts'\nimport { claimTitleSlot, releaseTitleSlot, type OwnershipClaim } from './ownership.ts'\nimport { settingsPatch, storedSettings } from './storage.ts'\nimport type { TitleLocaleMode } from './output.ts'\n\nexport interface TitleSettingsStore {\n load(): TitleSettings | undefined\n save(settings: TitleSettings): Promise<void>\n}\n\nexport interface CurrentTitleHost {\n get(name: string): unknown\n}\n\nexport class CurrentTitleService {\n private settings: TitleSettings\n private config: GenerateConfig\n private claim?: OwnershipClaim\n private nativeSlot?: ReturnType<typeof createNativeTitleSlot>\n private generation = 0\n private settingsPending: Promise<void> = Promise.resolve()\n private disposed = false\n private readonly inFlight = new Map<string, AbortController>()\n readonly support: TitleSupport\n\n constructor(private readonly options: {\n plugin: string\n llm?: LlmTextCaller\n host?: unknown\n sessionTitle?: SessionTitleServiceLike\n loader?: LoaderFace\n sessions?: { get(id: string): SessionLike | undefined }\n store?: TitleSettingsStore\n localePreference?: () => string | undefined\n initialLocale?: TitleLocaleMode\n now?: () => Date\n onSettingsChanged?: (revision: number) => void\n }) {\n const stored = storedSettings(options.store?.load(), options.initialLocale ?? 'auto')\n this.settings = stored\n this.config = defaultGenerateConfig(this.settings.locale)\n this.support = { nativeOwner: null, weOwn: false }\n }\n\n async start(): Promise<void> {\n const { llm, sessionTitle, loader, sessions } = this.options\n if (!llm || !sessionTitle?.register || !sessions || !loader) {\n this.support.weOwn = false\n this.support.limitation = 'required host services are missing'\n return\n }\n this.nativeSlot = createNativeTitleSlot({\n sessionTitle,\n loader,\n automatic: () => this.settings.cadence,\n generate: request => this.nativeGenerate(request),\n })\n try {\n this.claim = await claimTitleSlot(this.nativeSlot, PROVIDER_ID)\n this.support.weOwn = true\n this.support.nativeOwner = PROVIDER_ID\n delete this.support.limitation\n } catch (error) {\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot.owner() ?? null\n this.support.limitation = error instanceof Error ? error.message : 'native title provider slot is occupied'\n }\n }\n\n async dispose(): Promise<void> {\n this.disposed = true\n this.generation += 1\n for (const controller of this.inFlight.values()) controller.abort(new Error('current-title disabled'))\n this.inFlight.clear()\n await this.settingsPending\n const snapshot = this.nativeSlot?.displacement\n const outcome = await releaseTitleSlot(this.nativeSlot ?? { owner: () => undefined, occupy: async () => () => {} }, this.claim)\n if (outcome === 'released') await restoreOwnDisplacement(this.options.loader, snapshot)\n this.claim = undefined\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot?.owner() ?? null\n if (outcome === 'left-other-owner') {\n this.support.limitation = 'another title provider owns the slot; previous owner was not restored'\n }\n }\n\n status(sessionId?: string): TitleStatus {\n const session = sessionId && this.options.sessions ? this.options.sessions.get(sessionId) : undefined\n const snapshot = session ? this.read(session) : undefined\n return {\n settings: { ...this.settings, model: { ...this.settings.model } },\n support: { ...this.support, nativeOwner: this.nativeSlot?.owner() ?? this.support.nativeOwner },\n ...(sessionId ? {\n session: {\n sessionId,\n title: snapshot?.title,\n sourceKind: snapshot?.source.kind,\n generating: this.inFlight.has(sessionId),\n pinned: snapshot?.source.kind === 'user',\n },\n } : {}),\n }\n }\n\n async updateSettings(patch: {\n prompt?: unknown\n model?: unknown\n cadence?: unknown\n expectedRevision: number\n }): Promise<TitleSettings> {\n patch = structuredClone(patch)\n const result = this.settingsPending.then(async () => {\n if (this.disposed) throw Object.assign(new Error('current-title disabled'), { code: 'unavailable' })\n if (this.settings.revision !== patch.expectedRevision) {\n throw Object.assign(new Error('current-title settings changed'), { code: 'revision' })\n }\n const previous = this.settings\n const next: TitleSettings = {\n revision: this.settings.revision + 1,\n ...settingsPatch(this.settings, patch),\n }\n if (this.options.store) await this.options.store.save(next)\n this.settings = next\n // Observer failures cannot roll back a committed settings write.\n try { this.options.onSettingsChanged?.(next.revision) } catch {}\n this.config = { ...this.config, locale: 'auto' }\n if (!this.disposed && next.cadence !== previous.cadence) await this.reclaimWithCadence()\n return {\n revision: next.revision,\n locale: next.locale,\n prompt: next.prompt,\n model: { ...next.model },\n cadence: next.cadence,\n }\n })\n this.settingsPending = result.then(() => {}, () => {})\n return result\n }\n\n /** Re-register the provider so a cadence change takes effect without a restart. */\n private async reclaimWithCadence(): Promise<void> {\n if (!this.claim || !this.nativeSlot) return\n const stale = this.claim\n this.claim = undefined\n await stale.dispose()\n try {\n this.claim = await claimTitleSlot(this.nativeSlot, PROVIDER_ID)\n this.support.weOwn = true\n this.support.nativeOwner = PROVIDER_ID\n delete this.support.limitation\n } catch (error) {\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot.owner() ?? null\n this.support.limitation = error instanceof Error ? error.message : 'native title provider slot is occupied'\n }\n }\n\n /** @deprecated Locale is always auto. Kept so older clients still save a revision. */\n async updateLocale(_locale: TitleLocaleMode, expectedRevision: number): Promise<TitleSettings> {\n return this.updateSettings({ expectedRevision })\n }\n\n async regenerate(sessionId: string, signal: AbortSignal): Promise<TitleSnapshot | undefined> {\n if (!this.support.weOwn) throw Object.assign(new Error('title provider is inactive'), { code: 'unavailable' })\n const session = this.options.sessions?.get(sessionId)\n if (!session) throw Object.assign(new Error('session not found'), { code: 'not-found' })\n await this.options.sessionTitle?.refresh(session, signal)\n return this.read(session)\n }\n\n read(session: SessionLike): TitleSnapshot | undefined {\n const snapshot = this.options.sessionTitle?.get(session)\n if (!snapshot?.title) return undefined\n const kind = snapshot.source?.kind\n return {\n title: snapshot.title,\n messageSeqs: snapshot.messageSeqs ? [...snapshot.messageSeqs] : [],\n source: {\n kind: kind === 'user' || kind === 'fallback' || kind === 'provider' ? kind : 'provider',\n ...(typeof snapshot.source?.provider === 'string' ? { provider: snapshot.source.provider } : {}),\n },\n eventSeq: Number(snapshot.eventSeq ?? 0),\n updatedAt: snapshot.updatedAt ?? 0,\n }\n }\n\n private async nativeGenerate(request: {\n session: { id: string; snapshotEvents(): readonly unknown[] }\n messages: ReadonlyArray<{ seq: number; text: string }>\n signal: AbortSignal\n }) {\n const llm = this.options.llm\n if (!llm) throw new Error('dsh-current-title: llm is not available')\n const generation = this.generation\n const controller = new AbortController()\n this.inFlight.get(request.session.id)?.abort(new Error('newer title generation superseded older work'))\n this.inFlight.set(request.session.id, controller)\n try {\n const combined = AbortSignal.any([request.signal, controller.signal])\n const session = this.options.sessions?.get(request.session.id)\n // The host writes a free deterministic fallback title before it consults a\n // provider, and this provider contract has no \"decline\" result. Declining is\n // therefore the only way to keep delegated child threads off the model: their\n // dispatch prompt arrives as the child's own user message, so `source.kind`\n // cannot exclude them. The host logs the rejection and keeps the fallback.\n if (isSubagentSession(session)) {\n throw Object.assign(new Error('dsh-current-title: delegated child thread keeps the host fallback title'), { code: 'subagent-session' })\n }\n const messages = collectHumanMessages(\n request.messages.map(message => ({\n type: 'user/message',\n seq: message.seq,\n data: { source: { kind: 'user' }, content: [{ type: 'text', text: message.text }] },\n })),\n )\n const generated = await generateCurrentTitle({\n llm,\n host: this.options.host ?? {},\n config: this.config,\n sessionId: request.session.id,\n messages: messages.length > 0 ? messages : [...request.messages],\n prompt: this.settings.prompt,\n model: this.settings.model,\n localePreference: this.options.localePreference?.(),\n signal: combined,\n isCurrent: () => this.generation === generation && this.support.weOwn\n && (!session || this.options.sessions?.get(request.session.id) === session),\n now: this.options.now?.(),\n })\n return { title: generated.title, messageSeqs: generated.messageSeqs, model: generated.model }\n } finally {\n if (this.inFlight.get(request.session.id) === controller) this.inFlight.delete(request.session.id)\n }\n }\n}\n\nexport function hostLocalePreference(host: CurrentTitleHost): string | undefined {\n try {\n const settings = host.get('settings') as { get?(namespace: string): unknown } | undefined\n const value = settings?.get?.('locale')\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\n const preference = (value as Record<string, unknown>).preference\n return typeof preference === 'string' ? preference : undefined\n } catch {\n return undefined\n }\n}\n\nexport async function handleRpc(service: CurrentTitleService, endpoint: string, payload: unknown, signal: AbortSignal): Promise<RpcResult> {\n signal.throwIfAborted()\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n if (endpoint === 'status') {\n return { ok: true, value: service.status(typeof body.sessionId === 'string' ? body.sessionId : undefined) }\n }\n if (endpoint === 'settings') {\n if (typeof body.expectedRevision !== 'number') {\n return { ok: false, error: { code: 'bad-request', message: '标题设置无效。' } }\n }\n try {\n return {\n ok: true,\n value: await service.updateSettings({\n ...(body.prompt !== undefined ? { prompt: body.prompt } : {}),\n ...(body.model !== undefined ? { model: body.model } : {}),\n ...(body.cadence !== undefined ? { cadence: body.cadence } : {}),\n expectedRevision: body.expectedRevision,\n }),\n }\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? String((error as { code?: string }).code) : 'failed'\n if (code === 'revision') return { ok: false, error: { code, message: '设置已更新,请刷新后重试。' } }\n return { ok: false, error: { code: 'failed', message: '无法保存标题设置。' } }\n }\n }\n if (endpoint === 'regenerate') {\n if (typeof body.sessionId !== 'string' || !body.sessionId) {\n return { ok: false, error: { code: 'bad-request', message: '缺少会话。' } }\n }\n try {\n const snapshot = await service.regenerate(body.sessionId, signal)\n return { ok: true, value: snapshot ?? null }\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? String((error as { code?: string }).code) : 'failed'\n if (code === 'not-found') return { ok: false, error: { code, message: '找不到该会话。' } }\n if (code === 'unavailable') return { ok: false, error: { code, message: '标题服务未就绪。' } }\n if (signal.aborted) return { ok: false, error: { code: 'cancelled', message: '已取消。' } }\n return { ok: false, error: { code: 'failed', message: '标题生成失败。' } }\n }\n }\n return { ok: false, error: { code: 'bad-request', message: '未知操作。' } }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-plugin-kit/host-rpc'\nimport { registerModelSettings, notifyModelSettingsChanged, type ModelSettingsEvents } from '@klarkxy/dsh-plugin-kit/model-settings'\nimport { isTitleLocaleMode, PLUGIN_NAME, RPC_CHANNEL, SETTINGS_KEY, type TitleLocaleMode } from './contracts.ts'\nimport { CurrentTitleService, handleRpc, hostLocalePreference } from './service.ts'\nimport type { LoaderFace, SessionTitleServiceLike } from './native-slot.ts'\nimport type { SessionLike } from './messages.ts'\nimport { parseTitleSettings, titleDomain } from './storage.ts'\n\nexport const name = PLUGIN_NAME\nexport const inject = ['sessionTitle', 'llm', 'sessions', 'loader', 'storageDomain', 'connection', 'webServer', 'agents', 'sessionProjections', 'agentDefaultModel'] as const\nexport { CurrentTitleService }\nexport { selectRecentMessages, frameMessages } from './input.ts'\nexport { parseModelTitle, formatTitle, resolveTitleLocale } from './output.ts'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { currentTitle: CurrentTitleService }\n}\n\ntype DomainHandle = {\n table(name: 'settings'): {\n get(key: string): unknown\n put(key: string, value: unknown): Promise<void>\n }\n close(): Promise<void>\n}\n\ntype Host = Context & HostRpcContext & {\n sessionTitle: SessionTitleServiceLike\n llm: LlmTextCaller\n sessions: { get(id: string): SessionLike | undefined }\n loader: LoaderFace\n storageDomain: { open: (spec: typeof titleDomain) => Promise<DomainHandle> }\n}\n\nexport async function apply(ctx: Context, config: { locale?: TitleLocaleMode } = {}): Promise<void> {\n const host = ctx as Host\n const domain = await host.storageDomain.open(titleDomain)\n const table = domain.table('settings')\n const locale = isTitleLocaleMode(config.locale) ? config.locale : 'auto'\n const service = new CurrentTitleService({\n plugin: PLUGIN_NAME,\n onSettingsChanged: revision => notifyModelSettingsChanged(ctx, PLUGIN_NAME, revision),\n llm: host.llm,\n host,\n sessionTitle: host.sessionTitle,\n loader: host.loader,\n sessions: host.sessions,\n store: {\n load: () => parseTitleSettings(table.get(SETTINGS_KEY)),\n save: settings => table.put(SETTINGS_KEY, settings),\n },\n initialLocale: locale,\n localePreference: () => hostLocalePreference(host),\n })\n await service.start()\n ctx.provide('currentTitle', service)\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'current-title.lifecycle')\n ctx.effect(() => registerHostRpc(host, RPC_CHANNEL, (endpoint, payload, signal) => handleRpc(service, endpoint, payload, signal)), 'current-title.rpc')\n ctx.effect(() => registerModelSettings(ctx as unknown as ModelSettingsEvents, {\n ns: PLUGIN_NAME, title: { zh: '自动标题', en: 'Auto Title' },\n read(signal) {\n signal.throwIfAborted()\n const settings = service.status().settings\n return { revision: settings.revision, fields: [{ path: ['model'], label: { zh: '标题模型', en: 'Title model' }, current: settings.model,\n followLabel: { zh: '当前会话 / 宿主默认模型', en: 'Current conversation / host default' }, allowFollow: true }] }\n },\n async write(path, route, expectedRevision, signal) {\n if (path.length !== 1 || path[0] !== 'model') throw new Error('Unknown Current Title model setting')\n signal.throwIfAborted()\n return service.updateSettings({ model: route, expectedRevision })\n },\n }), 'current-title.model-settings')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/input.ts","../src/output.ts","../src/messages.ts","../src/generate.ts","../src/ownership.ts","../src/native-slot.ts","../src/storage.ts","../src/service.ts","../src/index.ts"],"sourcesContent":["import type { TitleMessage } from './contracts.ts'\n\nexport const FRAME_PREFIX =\n 'Choose the current task from these recent human messages, ordered oldest to newest:\\n'\n\nexport function frameMessages(messages: readonly TitleMessage[]): string {\n return `${FRAME_PREFIX}${JSON.stringify(messages)}`\n}\n\nexport function utf8Bytes(value: string): number {\n return Buffer.byteLength(value, 'utf8')\n}\n\nfunction middleSlice(codePoints: readonly string[], kept: number): string {\n if (kept >= codePoints.length) return codePoints.join('')\n if (kept <= 0) return ''\n if (kept === 1) return '…'\n\n const contentPoints = kept - 1\n const headCount = Math.ceil(contentPoints / 2)\n const tailCount = Math.floor(contentPoints / 2)\n return `${codePoints.slice(0, headCount).join('')}…${\n tailCount === 0 ? '' : codePoints.slice(-tailCount).join('')\n }`\n}\n\nexport function fitSingleMessage(message: TitleMessage, maxInputBytes: number): TitleMessage {\n const empty = { ...message, text: '' }\n if (utf8Bytes(frameMessages([empty])) > maxInputBytes) {\n throw new Error('dsh-current-title: maxInputBytes is too small for the input envelope')\n }\n if (utf8Bytes(frameMessages([message])) <= maxInputBytes) return message\n\n const points = Array.from(message.text)\n let low = 0\n let high = points.length\n let best = ''\n\n while (low <= high) {\n const kept = Math.floor((low + high) / 2)\n const text = middleSlice(points, kept)\n if (utf8Bytes(frameMessages([{ ...message, text }])) <= maxInputBytes) {\n best = text\n low = kept + 1\n } else {\n high = kept - 1\n }\n }\n\n return { ...message, text: best }\n}\n\nexport function selectRecentMessages(\n messages: readonly TitleMessage[],\n maxRecentMessages: number,\n maxInputBytes: number,\n): TitleMessage[] {\n if (messages.length === 0) return []\n\n const selected = messages.slice(-maxRecentMessages).map(message => ({ ...message }))\n while (selected.length > 1 && utf8Bytes(frameMessages(selected)) > maxInputBytes) {\n selected.shift()\n }\n\n if (utf8Bytes(frameMessages(selected)) > maxInputBytes) {\n selected[0] = fitSingleMessage(selected[0]!, maxInputBytes)\n }\n\n return selected\n}\n","export const TITLE_TYPE_KEYS = [\n 'feature',\n 'fix',\n 'optimize',\n 'refactor',\n 'test',\n 'docs',\n 'release',\n 'config',\n 'explore',\n 'discuss',\n] as const\n\nexport const TITLE_LOCALES = ['zh', 'en'] as const\nexport const TITLE_LOCALE_MODES = ['auto', ...TITLE_LOCALES] as const\n\nexport type TitleType = (typeof TITLE_TYPE_KEYS)[number]\nexport type TitleLocale = (typeof TITLE_LOCALES)[number]\nexport type TitleLocaleMode = (typeof TITLE_LOCALE_MODES)[number]\n\nconst TITLE_TYPE_LABELS: Record<TitleLocale, Record<TitleType, string>> = {\n zh: {\n feature: '功能',\n fix: '修复',\n optimize: '优化',\n refactor: '重构',\n test: '测试',\n docs: '文档',\n release: '发布',\n config: '配置',\n explore: '探索',\n discuss: '讨论',\n },\n en: {\n feature: 'Feature',\n fix: 'Fix',\n optimize: 'Optimize',\n refactor: 'Refactor',\n test: 'Test',\n docs: 'Docs',\n release: 'Release',\n config: 'Config',\n explore: 'Explore',\n discuss: 'Discussion',\n },\n}\n\nexport interface ParsedTitle {\n type: TitleType\n summary: string\n}\n\nconst OSC_SEQUENCE = /(?:\\u001B\\]|\\u009D)(?:(?!\\u0007|\\u001B\\\\)[\\s\\S])*(?:\\u0007|\\u001B\\\\|$)/gu\nconst CSI_SEQUENCE = /(?:\\u001B\\[|\\u009B)[0-?]*[ -/]*[@-~]/gu\nconst ESC_SEQUENCE = /\\u001B[@-_]/gu\nconst CONTROL_CHARACTER = /[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u009F]/gu\nconst DIRECTIONAL_CONTROL = /[\\u200B\\u200E\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF]/gu\n\nfunction cleanTitleText(input: string): string {\n return input\n .replace(OSC_SEQUENCE, '')\n .replace(CSI_SEQUENCE, '')\n .replace(ESC_SEQUENCE, '')\n .replace(CONTROL_CHARACTER, '')\n .replace(DIRECTIONAL_CONTROL, '')\n .replace(/\\s+/gu, ' ')\n .trim()\n}\n\nexport function truncateTitleUtf8(input: string, maxBytes: number): string {\n if (!Number.isInteger(maxBytes) || maxBytes <= 0) throw new Error('maxBytes must be a positive integer')\n if (Buffer.byteLength(input, 'utf8') <= maxBytes) return input\n let used = 0\n let output = ''\n for (const character of input) {\n const bytes = Buffer.byteLength(character, 'utf8')\n if (used + bytes > maxBytes) break\n output += character\n used += bytes\n }\n return output\n}\n\n/** Same sanitizing rules as DSH 0.1.7-rc.2 `normalizeSessionTitle`. */\nexport function normalizeSessionTitle(input: string, maxBytes: number): string {\n return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd()\n}\n\nfunction isTitleType(value: string): value is TitleType {\n return (TITLE_TYPE_KEYS as readonly string[]).includes(value)\n}\n\nexport function resolveTitleLocale(\n mode: TitleLocaleMode,\n messages: readonly string[],\n preference?: string,\n): TitleLocale {\n if (mode !== 'auto') return mode\n\n const preferred = preference?.trim().toLowerCase().split('-')[0]\n if (preferred === 'zh' || preferred === 'en') return preferred\n\n const text = messages.join('\\n')\n if (/[\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u.test(text)) return 'en'\n return /\\p{Script=Han}/u.test(text) ? 'zh' : 'en'\n}\n\nfunction removeTitleSyntax(value: string): string {\n return value.replace(/[|`*_~#\\[\\]\"“”]/gu, ' ')\n}\n\nfunction truncateSummary(value: string, targetWords: number, targetCjkCharacters: number): string {\n const containsCjk = /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u.test(value)\n if (containsCjk) {\n return Array.from(value.replace(/\\s+/gu, '')).slice(0, targetCjkCharacters).join('')\n }\n return value.split(/\\s+/u).filter(Boolean).slice(0, targetWords).join(' ')\n}\n\nfunction unwrapModelText(raw: string): string {\n const trimmed = raw.trim()\n const fenced = /^```(?:json)?\\s*([\\s\\S]*?)\\s*```$/iu.exec(trimmed)\n return (fenced?.[1] ?? trimmed).trim()\n}\n\nfunction readJsonObject(raw: string): Record<string, unknown> | undefined {\n const text = unwrapModelText(raw)\n const start = text.indexOf('{')\n const end = text.lastIndexOf('}')\n if (start === -1 || end <= start) return undefined\n try {\n const value = JSON.parse(text.slice(start, end + 1))\n if (value && typeof value === 'object' && !Array.isArray(value)) return value as Record<string, unknown>\n } catch {\n return undefined\n }\n return undefined\n}\n\n/**\n * Accept the required JSON shape, including a code fence or a short preface.\n * Extra keys are ignored. A plain one-line title still becomes a title so a\n * chatty model does not leave the session on the built-in fallback.\n */\nexport function parseModelTitle(\n raw: string,\n targetWords: number,\n targetCjkCharacters: number,\n): ParsedTitle {\n const candidate = readJsonObject(raw)\n const typeValue = typeof candidate?.type === 'string' ? candidate.type.trim().toLowerCase() : ''\n const summaryValue = typeof candidate?.summary === 'string' ? candidate.summary : ''\n const type = isTitleType(typeValue) ? typeValue : 'discuss'\n const source = summaryValue || (candidate ? '' : unwrapModelText(raw).replace(/^[\"'`]+|[\"'`]+$/gu, ''))\n const normalized = normalizeSessionTitle(removeTitleSyntax(source), Number.MAX_SAFE_INTEGER)\n const summary = truncateSummary(normalized, targetWords, targetCjkCharacters)\n if (summary.length === 0) {\n throw new Error('dsh-current-title: title model returned an empty summary')\n }\n return { type, summary }\n}\n\nexport function localMonthDay(now: Date): string {\n const month = String(now.getMonth() + 1).padStart(2, '0')\n const day = String(now.getDate()).padStart(2, '0')\n return `${month}${day}`\n}\n\nexport function formatTitle(parsed: ParsedTitle, locale: TitleLocale, now = new Date()): string {\n return `${localMonthDay(now)} | ${TITLE_TYPE_LABELS[locale][parsed.type]} | ${parsed.summary}`\n}\n","import { normalizeSessionTitle } from './output.ts'\nimport type { TitleMessage } from './contracts.ts'\n\nexport interface SessionEventLike {\n readonly type: string\n readonly seq: number\n readonly time?: number\n readonly data?: {\n readonly source?: { readonly kind?: string; readonly plugin?: string; readonly provider?: string }\n readonly content?: ReadonlyArray<{ readonly type?: string; readonly text?: string }>\n readonly title?: string\n readonly messageSeqs?: readonly number[]\n }\n}\n\nexport interface SessionLike {\n readonly id: string\n readonly seq?: number\n snapshotEvents(): readonly SessionEventLike[]\n append?(type: string, data: unknown): unknown\n}\n\nfunction textFromContent(content: ReadonlyArray<{ readonly type?: string; readonly text?: string }> | undefined): string {\n if (!Array.isArray(content)) return ''\n return content\n .filter(block => block && block.type === 'text' && typeof block.text === 'string')\n .map(block => block.text as string)\n .join('\\n')\n}\n\n/** Eligible human prompts only. Plugin/tool/model user-role rows are excluded. */\nexport function collectHumanMessages(events: readonly SessionEventLike[], throughSeq?: number): TitleMessage[] {\n const messages: TitleMessage[] = []\n for (const event of events) {\n if (throughSeq !== undefined && event.seq > throughSeq) break\n if (event.type !== 'user/message') continue\n if (event.data?.source?.kind !== 'user') continue\n const text = textFromContent(event.data.content)\n if (normalizeSessionTitle(text, Number.MAX_SAFE_INTEGER).length === 0) continue\n messages.push({ seq: event.seq, text })\n }\n return messages\n}\n\nexport function sourceVersionOf(sessionId: string, messages: readonly TitleMessage[]): string {\n const last = messages.at(-1)\n return `${sessionId}:${last?.seq ?? -1}:${messages.length}`\n}\n","import { callLlmText, resolveFeatureModel, type LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport type { ModelRoute } from '@klarkxy/dsh-model-route'\nimport type { GenerateConfig, TitleMessage, TitleModelRoute } from './contracts.ts'\nimport { DEFAULT_TIMEOUT_MS, PLUGIN_NAME } from './contracts.ts'\nimport { frameMessages, selectRecentMessages } from './input.ts'\nimport { formatTitle, normalizeSessionTitle, parseModelTitle, resolveTitleLocale, type TitleLocaleMode } from './output.ts'\nimport { sourceVersionOf } from './messages.ts'\n\nexport interface GeneratedTitle {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly model?: { readonly provider: string; readonly model: string }\n readonly sourceVersion: string\n}\n\nexport function systemPrompt(config: GenerateConfig, customPrompt = ''): string {\n const instruction = customPrompt.trim()\n return [\n instruction || 'Name the current task in an AI coding-assistant session.',\n 'Prioritize the newest human messages. Older messages are context only and must not keep a completed task in the title.',\n 'Allowed type values: feature, fix, optimize, refactor, test, docs, release, config, explore, discuss.',\n 'Return exactly one JSON object: {\"type\":\"<type>\",\"summary\":\"<summary>\"}.',\n 'Return no Markdown, code fence, explanation, date, or extra key.',\n 'Keep the summary in the language of the recent messages.',\n `Aim for at most ${config.targetWords} non-CJK words or ${config.targetCjkCharacters} CJK characters.`,\n ].join('\\n')\n}\n\n/**\n * Saved override passed to resolveFeatureModel. Unlike modelRouteOverride,\n * this does not trim or re-apply the 250/80 caps: stored rows are already\n * normalized, and a whitespace-only id must stay a miss (not a trimmed hit)\n * so the host-default fallback is unchanged.\n */\nexport function titleModelRoute(route: TitleModelRoute | undefined): ModelRoute | undefined {\n if (!route?.provider || !route.model) return undefined\n return route.reasoningEffort\n ? { provider: route.provider, model: route.model, reasoningEffort: route.reasoningEffort }\n : { provider: route.provider, model: route.model }\n}\n\nexport async function generateCurrentTitle(options: {\n llm: LlmTextCaller\n host: unknown\n config: GenerateConfig\n sessionId: string\n messages: readonly TitleMessage[]\n prompt?: string\n model?: TitleModelRoute\n localePreference?: string\n localeMode?: TitleLocaleMode\n signal: AbortSignal\n isCurrent: () => boolean\n now?: Date\n}): Promise<GeneratedTitle> {\n options.signal.throwIfAborted()\n if (!options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n const selected = selectRecentMessages(\n options.messages,\n options.config.maxRecentMessages,\n options.config.maxInputBytes,\n )\n if (selected.length === 0) throw new Error('dsh-current-title: at least one source message is required')\n const route = resolveFeatureModel(options.host, titleModelRoute(options.model), options.sessionId)\n if (!route) throw new Error('dsh-current-title: 请在插件页选择模型,或设置宿主默认对话模型。')\n // Like the bundled title provider, select the first (least) advertised\n // effort inside prepareCall, before adapter defaults are materialized.\n const callRoute = { provider: route.provider, model: route.model }\n\n const framedInput = frameMessages(selected)\n const locale = resolveTitleLocale(\n options.localeMode ?? options.config.locale,\n selected.map(message => message.text),\n options.localePreference,\n )\n const sourceVersion = sourceVersionOf(options.sessionId, selected)\n const deadline = new AbortController()\n const timeoutMs = Number.isFinite(options.config.timeoutMs) && options.config.timeoutMs > 0\n ? options.config.timeoutMs : DEFAULT_TIMEOUT_MS\n const timer = setTimeout(() => deadline.abort(new DOMException('Title generation timed out.', 'TimeoutError')), timeoutMs)\n const signal = AbortSignal.any([options.signal, deadline.signal])\n let result\n try {\n result = await callLlmText(options.llm, {\n plugin: PLUGIN_NAME,\n route: callRoute,\n system: systemPrompt(options.config, options.prompt),\n text: framedInput,\n maxTokens: options.config.maxOutputTokens,\n purpose: 'session-title',\n configure: (controls, model) => {\n const effort = model.reasoning?.efforts[0]?.id\n return { ...controls, ...(effort === undefined ? {} : { reasoningEffort: effort }) }\n },\n signal,\n sessionId: options.sessionId,\n isCurrent: options.isCurrent,\n })\n signal.throwIfAborted()\n } catch (error) {\n // The shared caller translates stream cancellation to AbortError. Retain\n // the originating deadline or lifecycle reason at this feature boundary.\n signal.throwIfAborted()\n throw error\n } finally {\n clearTimeout(timer)\n }\n options.signal.throwIfAborted()\n if (!options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n const parsed = parseModelTitle(result.text, options.config.targetWords, options.config.targetCjkCharacters)\n const title = normalizeSessionTitle(formatTitle(parsed, locale, options.now ?? new Date()), options.config.maxTitleBytes)\n if (!title) throw new Error('dsh-current-title: title model returned an empty summary')\n return {\n title,\n messageSeqs: selected.map(message => message.seq),\n model: { provider: result.provider, model: result.model },\n sourceVersion,\n }\n}\n","export interface OwnershipClaim {\n readonly id: string\n readonly dispose: () => void | Promise<void>\n}\n\nexport interface TitleSlot {\n owner(): string | undefined\n occupy(id: string): Promise<() => void | Promise<void>>\n}\n\n/** Exclusive title-provider ownership. Enable claims the slot; disable releases only while this id still holds it. */\nexport async function claimTitleSlot(slot: TitleSlot, id: string): Promise<OwnershipClaim> {\n const dispose = await slot.occupy(id)\n return { id, dispose }\n}\n\nexport async function releaseTitleSlot(\n slot: TitleSlot,\n claim: OwnershipClaim | undefined,\n): Promise<'released' | 'left-other-owner' | 'idle'> {\n if (!claim) return 'idle'\n if (slot.owner() !== claim.id) return 'left-other-owner'\n await claim.dispose()\n if (slot.owner() && slot.owner() !== claim.id) return 'left-other-owner'\n return 'released'\n}\n\nexport function occupiedProviderId(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error)\n return /session-title provider \"([^\"]+)\" is already registered/.exec(message)?.[1]\n}\n","import { PROVIDER_ID } from './contracts.ts'\nimport { occupiedProviderId, type TitleSlot } from './ownership.ts'\n\nexport interface SessionTitleProvider {\n readonly id: string\n readonly automatic: 'first-prompt' | 'all-prompts'\n generate(request: {\n session: { id: string; snapshotEvents(): readonly unknown[] }\n messages: ReadonlyArray<{ seq: number; text: string }>\n route?: { provider: string; model: string }\n signal: AbortSignal\n }): Promise<{ title: string; messageSeqs: readonly number[]; model?: { provider: string; model: string } }>\n}\n\nexport interface SessionTitleServiceLike {\n register(provider: SessionTitleProvider): () => void | Promise<void>\n get(session: unknown): { title: string; source?: { kind?: string; provider?: string }; eventSeq?: number; updatedAt?: number; messageSeqs?: readonly number[] } | undefined\n refresh(session: unknown, signal?: AbortSignal): Promise<unknown>\n}\n\nexport interface LoaderEntryOptions {\n id?: string\n name?: string\n disabled?: boolean | null\n config?: unknown\n inject?: unknown\n group?: boolean | null\n}\n\nexport interface LoaderEntry {\n id: string\n options?: LoaderEntryOptions\n}\n\nexport interface LoaderFace {\n entries(): Iterable<LoaderEntry>\n update(id: string, options: { disabled?: boolean | null }): Promise<unknown> | unknown\n}\n\nexport interface Displacement {\n readonly id: string\n readonly name: string\n readonly identity: string\n}\n\nfunction catalogLookupId(entryId: string): string {\n const colon = entryId.indexOf(':')\n return colon === -1 ? entryId : entryId.slice(colon + 1)\n}\n\nfunction entryName(entry: LoaderEntry): string {\n return String(entry.options?.name ?? '')\n}\n\nexport function entryDisabled(entry: LoaderEntry): boolean {\n return entry.options?.disabled === true\n}\n\nexport function displacementIdentity(entry: LoaderEntry): string {\n const options = entry.options ?? {}\n const { disabled: _disabled, ...rest } = options\n return JSON.stringify({ id: entry.id, name: entryName(entry), rest })\n}\n\nexport function captureDisplacement(entry: LoaderEntry): Displacement {\n return { id: entry.id, name: entryName(entry), identity: displacementIdentity(entry) }\n}\n\nexport function displacementUnchanged(snapshot: Displacement, entry: LoaderEntry): boolean {\n return entry.id === snapshot.id\n && entryName(entry) === snapshot.name\n && displacementIdentity(entry) === snapshot.identity\n}\n\nexport function findEntryById(loader: LoaderFace, id: string): LoaderEntry | undefined {\n for (const entry of loader.entries()) {\n if (entry.id === id) return entry\n }\n return undefined\n}\n\nexport function findLoaderEntry(loader: LoaderFace, providerId: string): LoaderEntry | undefined {\n for (const entry of loader.entries()) {\n const name = entryName(entry)\n const ids = [entry.id, entry.options?.id, name, catalogLookupId(entry.id)]\n if (ids.some(value => value === providerId)) return entry\n if (name.endsWith(`/${providerId}`) || name.endsWith(providerId)) return entry\n if (providerId === 'session-title-first-prompt-llm' && catalogLookupId(entry.id) === 'session-title-llm') return entry\n }\n return undefined\n}\n\nexport async function restoreOwnDisplacement(loader: LoaderFace | undefined, snapshot: Displacement | undefined): Promise<'restored' | 'skipped'> {\n if (!loader || !snapshot) return 'skipped'\n const current = findEntryById(loader, snapshot.id)\n if (!current || !entryDisabled(current) || !displacementUnchanged(snapshot, current)) return 'skipped'\n await loader.update(snapshot.id, { disabled: false })\n return 'restored'\n}\n\nexport function createNativeTitleSlot(options: {\n sessionTitle: SessionTitleServiceLike\n loader: LoaderFace\n /** Read at each occupy so a settings change can re-register with a new cadence. */\n automatic: () => SessionTitleProvider['automatic']\n generate: SessionTitleProvider['generate']\n}): TitleSlot & { displacement?: Displacement } {\n let owner: string | undefined\n const slot: TitleSlot & { displacement?: Displacement } = {\n owner: () => owner,\n async occupy(id: string) {\n const provider: SessionTitleProvider = {\n id: PROVIDER_ID,\n automatic: options.automatic(),\n generate: options.generate,\n }\n try {\n const dispose = options.sessionTitle.register(provider)\n owner = id\n return async () => {\n await dispose()\n if (owner === id) owner = undefined\n }\n } catch (error) {\n const occupied = occupiedProviderId(error)\n if (!occupied) throw error\n const entry = findLoaderEntry(options.loader, occupied)\n if (!entry || entryDisabled(entry)) throw error\n const snapshot = captureDisplacement(entry)\n await options.loader.update(entry.id, { disabled: true })\n const afterDisable = findEntryById(options.loader, entry.id)\n if (!afterDisable || !displacementUnchanged(snapshot, afterDisable)) throw error\n try {\n const dispose = options.sessionTitle.register(provider)\n slot.displacement = snapshot\n owner = id\n return async () => {\n await dispose()\n if (owner === id) owner = undefined\n }\n } catch (second) {\n if (findEntryById(options.loader, snapshot.id) && displacementUnchanged(snapshot, findEntryById(options.loader, snapshot.id)!)) {\n await options.loader.update(snapshot.id, { disabled: false })\n }\n throw second\n }\n }\n },\n }\n return slot\n}\n","import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\nimport { z } from 'zod'\nimport {\n SETTINGS_KEY, defaultModelRoute, isTitleLocaleMode, normalizeCadence, normalizeModelRoute, normalizePrompt,\n type TitleSettings,\n} from './contracts.ts'\n\nexport { SETTINGS_KEY }\n\nconst localeSchema = z.enum(['auto', 'zh', 'en'])\n\n/** Version 1 stored only the locale. Prompt and model are filled as defaults. */\nconst legacySettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: localeSchema,\n}).strict()\n\nconst modelRouteSchema = z.object({\n provider: z.string(),\n model: z.string(),\n reasoningEffort: z.string().optional(),\n}).strict()\n\nexport const titleSettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: localeSchema,\n prompt: z.string(),\n model: modelRouteSchema,\n /** Defaulted so rows stored before the cadence switch existed still parse. */\n cadence: z.enum(['all-prompts', 'first-prompt']).default('all-prompts'),\n}).strict()\n\nexport const titleDomain = defineDomain({\n name: 'dsh_editor_current_title',\n version: 2,\n tables: {\n settings: domainTable<string, TitleSettings>(titleSettingsSchema),\n },\n})\n\nexport function parseTitleSettings(value: unknown): TitleSettings | undefined {\n const current = titleSettingsSchema.safeParse(value)\n if (current.success) {\n return {\n revision: current.data.revision,\n locale: isTitleLocaleMode(current.data.locale) ? current.data.locale : 'auto',\n prompt: normalizePrompt(current.data.prompt),\n model: normalizeModelRoute(current.data.model),\n cadence: normalizeCadence(current.data.cadence),\n }\n }\n const legacy = legacySettingsSchema.safeParse(value)\n if (!legacy.success || !isTitleLocaleMode(legacy.data.locale)) return undefined\n return {\n revision: legacy.data.revision,\n locale: legacy.data.locale,\n prompt: '',\n model: defaultModelRoute(),\n cadence: 'all-prompts',\n }\n}\n\nexport function storedSettings(value: unknown, _fallbackLocale: TitleSettings['locale'] = 'auto'): TitleSettings {\n const parsed = parseTitleSettings(value)\n return {\n revision: parsed?.revision ?? 0,\n locale: 'auto',\n prompt: parsed?.prompt ?? '',\n model: parsed?.model ?? defaultModelRoute(),\n cadence: parsed?.cadence ?? 'all-prompts',\n }\n}\n\nexport function settingsPatch(current: TitleSettings, patch: {\n prompt?: unknown\n model?: unknown\n cadence?: unknown\n}): Pick<TitleSettings, 'prompt' | 'model' | 'cadence'> & { locale: 'auto' } {\n return {\n locale: 'auto',\n prompt: patch.prompt === undefined ? current.prompt : normalizePrompt(patch.prompt),\n model: patch.model === undefined ? current.model : normalizeModelRoute(patch.model),\n cadence: patch.cadence === undefined ? current.cadence : normalizeCadence(patch.cadence),\n }\n}\n","import type { RpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { isSubagentSession } from '@klarkxy/dsh-plugin-kit/contracts'\nimport type { LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport type { GenerateConfig, TitleSettings, TitleSnapshot, TitleStatus, TitleSupport } from './contracts.ts'\nimport { PROVIDER_ID, defaultGenerateConfig } from './contracts.ts'\nimport { generateCurrentTitle } from './generate.ts'\nimport { collectHumanMessages, type SessionLike } from './messages.ts'\nimport {\n createNativeTitleSlot, restoreOwnDisplacement, type LoaderFace, type SessionTitleServiceLike,\n} from './native-slot.ts'\nimport { claimTitleSlot, releaseTitleSlot, type OwnershipClaim } from './ownership.ts'\nimport { settingsPatch, storedSettings } from './storage.ts'\nimport type { TitleLocaleMode } from './output.ts'\n\nexport interface TitleSettingsStore {\n load(): TitleSettings | undefined\n save(settings: TitleSettings): Promise<void>\n}\n\nexport interface CurrentTitleHost {\n get(name: string): unknown\n}\n\nexport class CurrentTitleService {\n private settings: TitleSettings\n private config: GenerateConfig\n private claim?: OwnershipClaim\n private nativeSlot?: ReturnType<typeof createNativeTitleSlot>\n private generation = 0\n private settingsPending: Promise<void> = Promise.resolve()\n private disposed = false\n private readonly inFlight = new Map<string, AbortController>()\n private readonly generations = new Set<Promise<unknown>>()\n readonly support: TitleSupport\n\n constructor(private readonly options: {\n plugin: string\n llm?: LlmTextCaller\n host?: unknown\n sessionTitle?: SessionTitleServiceLike\n loader?: LoaderFace\n sessions?: { get(id: string): SessionLike | undefined }\n store?: TitleSettingsStore\n localePreference?: () => string | undefined\n initialLocale?: TitleLocaleMode\n now?: () => Date\n onSettingsChanged?: (revision: number) => void\n }) {\n const stored = storedSettings(options.store?.load(), options.initialLocale ?? 'auto')\n this.settings = stored\n this.config = defaultGenerateConfig(this.settings.locale)\n this.support = { nativeOwner: null, weOwn: false }\n }\n\n async start(): Promise<void> {\n const { llm, sessionTitle, loader, sessions } = this.options\n if (!llm || !sessionTitle?.register || !sessions || !loader) {\n this.support.weOwn = false\n this.support.limitation = 'required host services are missing'\n return\n }\n this.nativeSlot = createNativeTitleSlot({\n sessionTitle,\n loader,\n automatic: () => this.settings.cadence,\n generate: request => this.nativeGenerate(request),\n })\n try {\n this.claim = await claimTitleSlot(this.nativeSlot, PROVIDER_ID)\n this.support.weOwn = true\n this.support.nativeOwner = PROVIDER_ID\n delete this.support.limitation\n } catch (error) {\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot.owner() ?? null\n this.support.limitation = error instanceof Error ? error.message : 'native title provider slot is occupied'\n }\n }\n\n async dispose(): Promise<void> {\n this.disposed = true\n this.generation += 1\n for (const controller of this.inFlight.values()) controller.abort(new Error('current-title disabled'))\n this.inFlight.clear()\n await Promise.allSettled([...this.generations])\n await this.settingsPending\n const snapshot = this.nativeSlot?.displacement\n const outcome = await releaseTitleSlot(this.nativeSlot ?? { owner: () => undefined, occupy: async () => () => {} }, this.claim)\n if (outcome === 'released') await restoreOwnDisplacement(this.options.loader, snapshot)\n this.claim = undefined\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot?.owner() ?? null\n if (outcome === 'left-other-owner') {\n this.support.limitation = 'another title provider owns the slot; previous owner was not restored'\n }\n }\n\n status(sessionId?: string): TitleStatus {\n const session = sessionId && this.options.sessions ? this.options.sessions.get(sessionId) : undefined\n const snapshot = session ? this.read(session) : undefined\n return {\n settings: { ...this.settings, model: { ...this.settings.model } },\n support: { ...this.support, nativeOwner: this.nativeSlot?.owner() ?? this.support.nativeOwner },\n ...(sessionId ? {\n session: {\n sessionId,\n title: snapshot?.title,\n sourceKind: snapshot?.source.kind,\n generating: this.inFlight.has(sessionId),\n pinned: snapshot?.source.kind === 'user',\n },\n } : {}),\n }\n }\n\n async updateSettings(patch: {\n prompt?: unknown\n model?: unknown\n cadence?: unknown\n expectedRevision: number\n }): Promise<TitleSettings> {\n patch = structuredClone(patch)\n const result = this.settingsPending.then(async () => {\n if (this.disposed) throw Object.assign(new Error('current-title disabled'), { code: 'unavailable' })\n if (this.settings.revision !== patch.expectedRevision) {\n throw Object.assign(new Error('current-title settings changed'), { code: 'revision' })\n }\n const previous = this.settings\n const next: TitleSettings = {\n revision: this.settings.revision + 1,\n ...settingsPatch(this.settings, patch),\n }\n if (this.options.store) await this.options.store.save(next)\n this.settings = next\n // Observer failures cannot roll back a committed settings write.\n try { this.options.onSettingsChanged?.(next.revision) } catch {}\n this.config = { ...this.config, locale: 'auto' }\n if (!this.disposed && next.cadence !== previous.cadence) await this.reclaimWithCadence()\n return {\n revision: next.revision,\n locale: next.locale,\n prompt: next.prompt,\n model: { ...next.model },\n cadence: next.cadence,\n }\n })\n this.settingsPending = result.then(() => {}, () => {})\n return result\n }\n\n /** Re-register the provider so a cadence change takes effect without a restart. */\n private async reclaimWithCadence(): Promise<void> {\n if (!this.claim || !this.nativeSlot) return\n const stale = this.claim\n this.claim = undefined\n await stale.dispose()\n try {\n this.claim = await claimTitleSlot(this.nativeSlot, PROVIDER_ID)\n this.support.weOwn = true\n this.support.nativeOwner = PROVIDER_ID\n delete this.support.limitation\n } catch (error) {\n this.support.weOwn = false\n this.support.nativeOwner = this.nativeSlot.owner() ?? null\n this.support.limitation = error instanceof Error ? error.message : 'native title provider slot is occupied'\n }\n }\n\n /** @deprecated Locale is always auto. Kept so older clients still save a revision. */\n async updateLocale(_locale: TitleLocaleMode, expectedRevision: number): Promise<TitleSettings> {\n return this.updateSettings({ expectedRevision })\n }\n\n async regenerate(sessionId: string, signal: AbortSignal): Promise<TitleSnapshot | undefined> {\n if (!this.support.weOwn) throw Object.assign(new Error('title provider is inactive'), { code: 'unavailable' })\n const session = this.options.sessions?.get(sessionId)\n if (!session) throw Object.assign(new Error('session not found'), { code: 'not-found' })\n await this.options.sessionTitle?.refresh(session, signal)\n return this.read(session)\n }\n\n read(session: SessionLike): TitleSnapshot | undefined {\n const snapshot = this.options.sessionTitle?.get(session)\n if (!snapshot?.title) return undefined\n const kind = snapshot.source?.kind\n return {\n title: snapshot.title,\n messageSeqs: snapshot.messageSeqs ? [...snapshot.messageSeqs] : [],\n source: {\n kind: kind === 'user' || kind === 'fallback' || kind === 'provider' ? kind : 'provider',\n ...(typeof snapshot.source?.provider === 'string' ? { provider: snapshot.source.provider } : {}),\n },\n eventSeq: Number(snapshot.eventSeq ?? 0),\n updatedAt: snapshot.updatedAt ?? 0,\n }\n }\n\n private nativeGenerate(request: Parameters<CurrentTitleService['runNativeGenerate']>[0]) {\n if (this.disposed) return Promise.reject(new Error('dsh-current-title: plugin disabled'))\n const pending = this.runNativeGenerate(request)\n this.generations.add(pending)\n void pending.then(() => this.generations.delete(pending), () => this.generations.delete(pending))\n return pending\n }\n\n private async runNativeGenerate(request: {\n session: { id: string; snapshotEvents(): readonly unknown[] }\n messages: ReadonlyArray<{ seq: number; text: string }>\n signal: AbortSignal\n }) {\n const llm = this.options.llm\n if (!llm) throw new Error('dsh-current-title: llm is not available')\n const generation = this.generation\n const controller = new AbortController()\n this.inFlight.get(request.session.id)?.abort(new Error('newer title generation superseded older work'))\n this.inFlight.set(request.session.id, controller)\n try {\n const combined = AbortSignal.any([request.signal, controller.signal])\n const session = this.options.sessions?.get(request.session.id)\n // The host writes a free deterministic fallback title before it consults a\n // provider, and this provider contract has no \"decline\" result. Declining is\n // therefore the only way to keep delegated child threads off the model: their\n // dispatch prompt arrives as the child's own user message, so `source.kind`\n // cannot exclude them. The host logs the rejection and keeps the fallback.\n if (isSubagentSession(session)) {\n throw Object.assign(new Error('dsh-current-title: delegated child thread keeps the host fallback title'), { code: 'subagent-session' })\n }\n const messages = collectHumanMessages(\n request.messages.map(message => ({\n type: 'user/message',\n seq: message.seq,\n data: { source: { kind: 'user' }, content: [{ type: 'text', text: message.text }] },\n })),\n )\n const generated = await generateCurrentTitle({\n llm,\n host: this.options.host ?? {},\n config: this.config,\n sessionId: request.session.id,\n messages: messages.length > 0 ? messages : [...request.messages],\n prompt: this.settings.prompt,\n model: this.settings.model,\n localePreference: this.options.localePreference?.(),\n signal: combined,\n isCurrent: () => this.generation === generation && this.support.weOwn\n && (!session || this.options.sessions?.get(request.session.id) === session),\n now: this.options.now?.(),\n })\n return { title: generated.title, messageSeqs: generated.messageSeqs, model: generated.model }\n } finally {\n if (this.inFlight.get(request.session.id) === controller) this.inFlight.delete(request.session.id)\n }\n }\n}\n\nexport function hostLocalePreference(host: CurrentTitleHost): string | undefined {\n try {\n const settings = host.get('settings') as { get?(namespace: string): unknown } | undefined\n const value = settings?.get?.('locale')\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\n const preference = (value as Record<string, unknown>).preference\n return typeof preference === 'string' ? preference : undefined\n } catch {\n return undefined\n }\n}\n\nexport async function handleRpc(service: CurrentTitleService, endpoint: string, payload: unknown, signal: AbortSignal): Promise<RpcResult> {\n signal.throwIfAborted()\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n if (endpoint === 'status') {\n return { ok: true, value: service.status(typeof body.sessionId === 'string' ? body.sessionId : undefined) }\n }\n if (endpoint === 'settings') {\n if (typeof body.expectedRevision !== 'number') {\n return { ok: false, error: { code: 'bad-request', message: '标题设置无效。' } }\n }\n try {\n return {\n ok: true,\n value: await service.updateSettings({\n ...(body.prompt !== undefined ? { prompt: body.prompt } : {}),\n ...(body.model !== undefined ? { model: body.model } : {}),\n ...(body.cadence !== undefined ? { cadence: body.cadence } : {}),\n expectedRevision: body.expectedRevision,\n }),\n }\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? String((error as { code?: string }).code) : 'failed'\n if (code === 'revision') return { ok: false, error: { code, message: '设置已更新,请刷新后重试。' } }\n return { ok: false, error: { code: 'failed', message: '无法保存标题设置。' } }\n }\n }\n if (endpoint === 'regenerate') {\n if (typeof body.sessionId !== 'string' || !body.sessionId) {\n return { ok: false, error: { code: 'bad-request', message: '缺少会话。' } }\n }\n try {\n const snapshot = await service.regenerate(body.sessionId, signal)\n return { ok: true, value: snapshot ?? null }\n } catch (error) {\n const code = error instanceof Error && 'code' in error ? String((error as { code?: string }).code) : 'failed'\n if (code === 'not-found') return { ok: false, error: { code, message: '找不到该会话。' } }\n if (code === 'unavailable') return { ok: false, error: { code, message: '标题服务未就绪。' } }\n if (signal.aborted) return { ok: false, error: { code: 'cancelled', message: '已取消。' } }\n return { ok: false, error: { code: 'failed', message: '标题生成失败。' } }\n }\n }\n return { ok: false, error: { code: 'bad-request', message: '未知操作。' } }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { LlmTextCaller } from '@klarkxy/dsh-plugin-kit'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-plugin-kit/host-rpc'\nimport { modelSettingsChangesIdentity } from '@klarkxy/dsh-plugin-kit/contracts'\nimport { createModelSettingsChanges } from '@klarkxy/dsh-plugin-kit/model-settings-changes'\nimport { registerModelSettings, notifyModelSettingsChanged, type ModelSettingsEvents } from '@klarkxy/dsh-plugin-kit/model-settings'\nimport { isTitleLocaleMode, PLUGIN_NAME, RPC_CHANNEL, SETTINGS_KEY, type TitleLocaleMode } from './contracts.ts'\nimport { CurrentTitleService, handleRpc, hostLocalePreference } from './service.ts'\nimport type { LoaderFace, SessionTitleServiceLike } from './native-slot.ts'\nimport type { SessionLike } from './messages.ts'\nimport { parseTitleSettings, titleDomain } from './storage.ts'\n\nexport const name = PLUGIN_NAME\nexport const inject = ['sessionTitle', 'llm', 'sessions', 'loader', 'storageDomain', 'connection', 'webServer', 'agents', 'sessionProjections', 'agentDefaultModel'] as const\nexport { CurrentTitleService }\nexport { selectRecentMessages, frameMessages } from './input.ts'\nexport { parseModelTitle, formatTitle, resolveTitleLocale } from './output.ts'\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { currentTitle: CurrentTitleService }\n}\n\ntype DomainHandle = {\n table(name: 'settings'): {\n get(key: string): unknown\n put(key: string, value: unknown): Promise<void>\n }\n close(): Promise<void>\n}\n\ntype Host = Context & HostRpcContext & {\n sessionTitle: SessionTitleServiceLike\n llm: LlmTextCaller\n sessions: { get(id: string): SessionLike | undefined }\n loader: LoaderFace\n storageDomain: { open: (spec: typeof titleDomain) => Promise<DomainHandle> }\n}\n\nexport async function apply(ctx: Context, config: { locale?: TitleLocaleMode } = {}): Promise<void> {\n createModelSettingsChanges(ctx, modelSettingsChangesIdentity(PLUGIN_NAME), PLUGIN_NAME)\n const host = ctx as Host\n const domain = await host.storageDomain.open(titleDomain)\n const table = domain.table('settings')\n const locale = isTitleLocaleMode(config.locale) ? config.locale : 'auto'\n const service = new CurrentTitleService({\n plugin: PLUGIN_NAME,\n onSettingsChanged: revision => notifyModelSettingsChanged(ctx, PLUGIN_NAME, revision),\n llm: host.llm,\n host,\n sessionTitle: host.sessionTitle,\n loader: host.loader,\n sessions: host.sessions,\n store: {\n load: () => parseTitleSettings(table.get(SETTINGS_KEY)),\n save: settings => table.put(SETTINGS_KEY, settings),\n },\n initialLocale: locale,\n localePreference: () => hostLocalePreference(host),\n })\n await service.start()\n ctx.provide('currentTitle', service)\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'current-title.lifecycle')\n ctx.effect(() => registerHostRpc(host, RPC_CHANNEL, (endpoint, payload, signal) => handleRpc(service, endpoint, payload, signal)), 'current-title.rpc')\n ctx.effect(() => registerModelSettings(ctx as unknown as ModelSettingsEvents, {\n ns: PLUGIN_NAME, title: { zh: '自动标题', en: 'Auto Title' },\n read(signal) {\n signal.throwIfAborted()\n const settings = service.status().settings\n return { revision: settings.revision, fields: [{ path: ['model'], label: { zh: '标题模型', en: 'Title model' }, current: settings.model,\n followLabel: { zh: '当前会话 / 宿主默认模型', en: 'Current conversation / host default' }, allowFollow: true }] }\n },\n async write(path, route, expectedRevision, signal) {\n if (path.length !== 1 || path[0] !== 'model') throw new Error('Unknown Current Title model setting')\n signal.throwIfAborted()\n return service.updateSettings({ model: route, expectedRevision })\n },\n }), 'current-title.model-settings')\n}\n"],"mappings":"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"}
|