@klarkxy/dsh-current-title 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/docs/README.zh-CN.md +2 -2
- package/lib/client.inner.cjs +0 -32
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +0 -32
- package/lib/index.d.ts +1 -1
- package/lib/index.js +10 -7
- package/lib/index.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ Keep a DSH session title aligned with the current human task.
|
|
|
6
6
|
|
|
7
7
|
Migrated from [`dsh-plugins/dsh-current-title`](https://github.com/klarkxy/dsh-plugins/tree/main/plugins/dsh-current-title). Title type labels stay bilingual (`功能` / `Feature`, and the rest of the fixed vocabulary). Generation uses `@klarkxy/dsh-ai-services` purpose `current-title.generate` on the weak role.
|
|
8
8
|
|
|
9
|
-
The bundle insert is enabled after installation. It does not permanently turn off the built-in first-prompt title provider: this entry claims the native `sessionTitle` slot only while active, and disabling restores that owner when this package still owns the slot and the displaced loader entry is unchanged.
|
|
9
|
+
The bundle insert is enabled after installation. It does not permanently turn off the built-in first-prompt title provider: this entry claims the native `sessionTitle` slot only while active, and disabling restores that owner when this package still owns the slot and the displaced loader entry is unchanged. Locale follows the host preference automatically; there is no settings page.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
|
-
Requires Node.js ≥22 and DSH `0.1.7-
|
|
13
|
+
Requires Node.js ≥22 and DSH `0.1.7-rc.2`. The **当前标题** entry starts enabled and can be disabled in plugin settings. Native title storage and scheduling come from host `sessionTitle`; generation needs `@klarkxy/dsh-ai-services`.
|
|
14
14
|
|
|
15
15
|
## Title shape
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ Requires Node.js ≥22 and DSH `0.1.7-alpha.1`. The **当前标题** entry start
|
|
|
18
18
|
0903 | 修复 | 登录回调失败
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Only recent real human `user/message` events are used. Plugin auxiliary messages are ignored. A manual rename is kept by native title storage
|
|
21
|
+
Only recent real human `user/message` events are used. Plugin auxiliary messages are ignored. A manual rename is kept by native title storage. Disable cancels work and drops late results.
|
|
22
22
|
|
|
23
23
|
## License
|
|
24
24
|
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
从 [`dsh-plugins/dsh-current-title`](https://github.com/klarkxy/dsh-plugins/tree/main/plugins/dsh-current-title) 迁入。类型前缀中英对照。生成走 `@klarkxy/dsh-ai-services` 的弱模型用途 `current-title.generate`。
|
|
8
8
|
|
|
9
|
-
安装后默认启用,不会永久停用宿主自带的标题插件。启用期间占用 `sessionTitle`
|
|
9
|
+
安装后默认启用,不会永久停用宿主自带的标题插件。启用期间占用 `sessionTitle` 槽位;关闭时若仍由本包持有,且被让出的加载项身份未变,则交还。类型标签语言跟随宿主偏好,没有单独设置页。
|
|
10
10
|
|
|
11
|
-
需要 Node.js ≥22 与 DSH `0.1.7-
|
|
11
|
+
需要 Node.js ≥22 与 DSH `0.1.7-rc.2`。标题写入宿主 `sessionTitle`。生成依赖 `@klarkxy/dsh-ai-services`。
|
|
12
12
|
|
|
13
13
|
许可证为 [SATA 2.1](https://github.com/klarkxy/dsh-editor/blob/main/packages/dsh-current-title/LICENSE),保留原插件出处。
|
package/lib/client.inner.cjs
CHANGED
|
@@ -392,20 +392,6 @@ function TitleSettings(props) {
|
|
|
392
392
|
]
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
|
-
const styles = `
|
|
396
|
-
.current-title-settings{display:grid;gap:8px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}
|
|
397
|
-
.current-title-settings p{margin:0}
|
|
398
|
-
.current-title-settings p[translate="no"]{overflow-wrap:anywhere}
|
|
399
|
-
.current-title-meta{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}
|
|
400
|
-
.current-title-settings button{min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}
|
|
401
|
-
.current-title-settings button:hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}
|
|
402
|
-
.current-title-settings button:active:not(:disabled){transform:scale(.97)}
|
|
403
|
-
.current-title-settings button:disabled{opacity:.45;cursor:not-allowed}
|
|
404
|
-
.current-title-settings fieldset{margin:0;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:10px;padding:8px 12px;display:grid;gap:8px}
|
|
405
|
-
.current-title-settings label{display:flex;gap:8px;align-items:center}
|
|
406
|
-
.current-title-settings :focus-visible{outline:2px solid currentColor;outline-offset:3px}
|
|
407
|
-
@media(prefers-reduced-motion:reduce){.current-title-settings button{transition:none}}
|
|
408
|
-
`;
|
|
409
395
|
function apply(ctx) {
|
|
410
396
|
const client = ctx;
|
|
411
397
|
const marker = createTitleClientMarker();
|
|
@@ -424,24 +410,6 @@ function apply(ctx) {
|
|
|
424
410
|
disposeTitleClientMarker(marker);
|
|
425
411
|
};
|
|
426
412
|
}, "current-title.marker");
|
|
427
|
-
ctx.effect(() => {
|
|
428
|
-
if (typeof document === "undefined") return () => {};
|
|
429
|
-
const style = document.createElement("style");
|
|
430
|
-
style.setAttribute("data-plugin", "@klarkxy/dsh-current-title");
|
|
431
|
-
style.textContent = styles;
|
|
432
|
-
document.head.appendChild(style);
|
|
433
|
-
return () => style.remove();
|
|
434
|
-
}, "current-title.styles");
|
|
435
|
-
ctx.effect(() => client.slots.inject("settings.section", () => client.slots.register({
|
|
436
|
-
name: "settings.section",
|
|
437
|
-
id: "current-title",
|
|
438
|
-
order: 80,
|
|
439
|
-
label: "当前标题"
|
|
440
|
-
}, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TitleSettings, {
|
|
441
|
-
client,
|
|
442
|
-
marker,
|
|
443
|
-
owner: props
|
|
444
|
-
}))), "current-title.settings");
|
|
445
413
|
}
|
|
446
414
|
//#endregion
|
|
447
415
|
exports.TitleSettings = TitleSettings;
|
package/lib/client.inner.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.inner.cjs","names":["useSyncExternalStore","useCallback","useRef","useState","useRef","useCallback"],"sources":["../../dsh-ai-services/src/client-utils.ts","../src/contracts.ts","../src/client-work.ts","../src/marker.ts","../src/client.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\nexport interface NativeSurfaceClient {\n sessions: {\n binding?(sessionId: string): { eventSource: { subscribe(listener: () => void): () => void } } | undefined\n }\n uiWorkspace: { current?: { getSnapshot(): { sessionId: string } | undefined; subscribe(listener: () => void): () => void } }\n uiSession: { adapter: { current: { getSnapshot(): { key?: string }; subscribe(listener: () => void): () => void } } }\n locale: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n connection?: { generation?: { subscribe(listener: () => void): () => void } }\n}\n\n/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */\nexport function selectedSessionId(client: Pick<NativeSurfaceClient, 'uiWorkspace' | 'uiSession'>): string {\n return client.uiWorkspace.current\n ? client.uiWorkspace.current.getSnapshot()?.sessionId ?? ''\n : client.uiSession.adapter.current.getSnapshot().key ?? ''\n}\n\n/** Owner props win; native settings only supplies close, so resolve its selected session. */\nexport function useNativeSeat(client: NativeSurfaceClient, props: unknown) {\n const current = useSyncExternalStore(\n useCallback((fn: () => void) => (client.uiWorkspace.current ?? client.uiSession.adapter.current).subscribe(fn), [client]),\n useCallback(() => selectedSessionId(client), [client]),\n () => '',\n )\n const language = useSyncExternalStore(\n useCallback((fn: () => void) => client.locale.subscribe(fn), [client]),\n useCallback(() => client.locale.getSnapshot().active, [client]),\n () => 'en',\n )\n const row = props && typeof props === 'object' ? props as Record<string, unknown> : {}\n const owner = row.owner && typeof row.owner === 'object' ? row.owner as Record<string, unknown> : {}\n const sessionId = typeof row.sessionId === 'string' ? row.sessionId\n : typeof owner.sessionId === 'string' ? owner.sessionId : current\n const requestedLocale = row.locale ?? owner.locale ?? language\n return { sessionId, locale: (String(requestedLocale).startsWith('zh') ? 'zh' : 'en') as 'zh' | 'en',\n hidden: row.hidden === true || owner.hidden === true }\n}\n\n/** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */\nexport function useFeatureRefresh(\n client: NativeSurfaceClient, sessionId: string, refresh: () => void,\n working = false, enabled = true,\n): void {\n const refreshRef = useRef(refresh)\n refreshRef.current = refresh\n useEffect(() => {\n if (!enabled) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const queue = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n clearTimeout(timer)\n timer = setTimeout(() => refreshRef.current(), 150)\n }\n const source = sessionId ? client.sessions.binding?.(sessionId)?.eventSource : undefined\n const stopEvents = source?.subscribe(queue)\n const stopConnection = client.connection?.generation?.subscribe(queue)\n const visibility = () => { if (document.visibilityState === 'visible') queue() }\n window.addEventListener('focus', queue)\n document.addEventListener('visibilitychange', visibility)\n // Details are collapsed by default; opening an existing panel must get current state.\n document.addEventListener('toggle', queue, true)\n return () => {\n clearTimeout(timer)\n stopEvents?.(); stopConnection?.()\n window.removeEventListener('focus', queue)\n document.removeEventListener('visibilitychange', visibility)\n document.removeEventListener('toggle', queue, true)\n }\n }, [client, sessionId, enabled])\n useEffect(() => {\n if (!enabled || !working) return\n let delay = 250\n const until = Date.now() + 300_000\n let timer: ReturnType<typeof setTimeout>\n const tick = () => {\n if (Date.now() >= until) return\n if (document.visibilityState !== 'hidden') refreshRef.current()\n delay = Math.min(delay * 2, 2000)\n timer = setTimeout(tick, delay)\n }\n timer = setTimeout(tick, delay)\n return () => clearTimeout(timer)\n }, [client, sessionId, working, enabled])\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-ai-services. */\nexport type { RpcResult } from '@klarkxy/dsh-ai-services/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-current-title'\nexport const FEATURE_ID = 'current-title'\nexport const PROVIDER_ID = '@klarkxy/dsh-current-title'\nexport const PURPOSE_ID = 'current-title.generate'\nexport const RPC_CHANNEL = '/dsh-current-title'\nexport const TITLE_CLIENT_SERVICE = 'dshCurrentTitleClient'\nexport const PROMPT_VERSION = 'current-title.v1'\nexport const SCHEMA_VERSION = 'title-json.v1'\nexport const CONTRACT_VERSION = 1\nexport const SETTINGS_KEY = 'current'\n\nexport const DEFAULT_MAX_RECENT_MESSAGES = 8\nexport const DEFAULT_TARGET_WORDS = 5\nexport const DEFAULT_TARGET_CJK = 10\nexport const DEFAULT_MAX_INPUT_BYTES = 4096\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 64\nexport const DEFAULT_TIMEOUT_MS = 60_000\nexport const DEFAULT_MAX_TITLE_BYTES = 80\n\nexport type TitleLocaleMode = 'auto' | 'zh' | 'en'\nexport type TitleSourceKind = 'fallback' | 'provider' | 'user'\n\nexport interface TitleMessage {\n readonly seq: number\n readonly text: string\n}\n\nexport interface TitleSnapshot {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly source: { readonly kind: TitleSourceKind; readonly provider?: string }\n readonly eventSeq: number\n readonly updatedAt: number\n}\n\nexport interface TitleSettings {\n revision: number\n locale: TitleLocaleMode\n}\n\nexport interface TitleSupport {\n nativeOwner: string | null\n weOwn: boolean\n limitation?: string\n}\n\nexport interface TitleStatus {\n settings: TitleSettings\n support: TitleSupport\n session?: {\n sessionId: string\n title?: string\n sourceKind?: TitleSourceKind\n generating: boolean\n pinned: boolean\n }\n}\n\nexport interface TitleClientMarker {\n active: boolean\n}\n\nexport interface GenerateConfig {\n readonly maxRecentMessages: number\n readonly locale: TitleLocaleMode\n readonly targetWords: number\n readonly targetCjkCharacters: number\n readonly maxInputBytes: number\n readonly maxOutputTokens: number\n readonly timeoutMs: number\n readonly maxTitleBytes: number\n}\n\nexport function defaultSettings(locale: TitleLocaleMode = 'auto'): TitleSettings {\n return { revision: 0, locale }\n}\n\nexport function defaultGenerateConfig(locale: TitleLocaleMode = 'auto'): GenerateConfig {\n return {\n maxRecentMessages: DEFAULT_MAX_RECENT_MESSAGES,\n locale,\n targetWords: DEFAULT_TARGET_WORDS,\n targetCjkCharacters: DEFAULT_TARGET_CJK,\n maxInputBytes: DEFAULT_MAX_INPUT_BYTES,\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxTitleBytes: DEFAULT_MAX_TITLE_BYTES,\n }\n}\n\nexport function isTitleLocaleMode(value: unknown): value is TitleLocaleMode {\n return value === 'auto' || value === 'zh' || value === 'en'\n}\n","import type { RpcResult, TitleLocaleMode, TitleStatus } from './contracts.ts'\n\nexport const titleCopy = {\n zh: {\n label: '当前标题',\n pinned: '已手动命名',\n generating: '正在生成标题…',\n regenerate: '重新生成',\n locale: '类型标签语言',\n auto: '自动',\n saved: '已保存。',\n failed: '无法读取标题设置。',\n },\n en: {\n label: 'Current title',\n pinned: 'Renamed manually',\n generating: 'Generating title…',\n regenerate: 'Regenerate',\n locale: 'Type-label language',\n auto: 'Auto',\n saved: 'Saved.',\n failed: 'Could not read title settings.',\n },\n} as const\n\nexport function settingsCopy(locale: 'zh' | 'en') {\n return titleCopy[locale] ?? titleCopy.zh\n}\n\nexport function shouldSkipTitleRefresh(input: { busy: boolean }): boolean {\n return input.busy\n}\n\nexport function createTitleClientWork() {\n let generation = 0\n let request = 0\n let disposed = false\n return {\n get disposed() { return disposed },\n beginLoad() {\n generation += 1\n request += 1\n return generation\n },\n captureLoad() {\n return generation\n },\n beginRequest() {\n request += 1\n return { generation, request }\n },\n isLoad(generationToken: number) {\n return !disposed && generation === generationToken\n },\n isRequest(token: { generation: number; request: number }) {\n return !disposed && generation === token.generation && request === token.request\n },\n dispose() {\n disposed = true\n generation += 1\n request += 1\n },\n }\n}\n\nexport type TitleClientWork = ReturnType<typeof createTitleClientWork>\nexport type TitleClientCall = (endpoint: string, payload?: unknown) => Promise<unknown>\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\nasync function invoke<T>(call: TitleClientCall, endpoint: string, payload?: unknown): Promise<T> {\n return unwrap(await call(endpoint, payload) as RpcResult<T>)\n}\n\nexport async function runTitleStatusLoad(input: {\n call: TitleClientCall\n sessionId?: string\n isCurrent: () => boolean\n failedMessage: string\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n try {\n const status = await invoke<TitleStatus>(\n input.call,\n 'status',\n input.sessionId ? { sessionId: input.sessionId } : {},\n )\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch {\n if (!input.isCurrent()) return\n input.onMarker(undefined)\n input.onError(input.failedMessage)\n }\n}\n\nexport async function runTitleRegenerateFlow(input: {\n call: TitleClientCall\n sessionId: string\n isCurrent: () => boolean\n failedMessage: string\n onBusy: (busy: boolean) => void\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n if (!input.sessionId || !input.isCurrent()) return\n input.onBusy(true)\n try {\n await invoke(input.call, 'regenerate', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n const status = await invoke<TitleStatus>(input.call, 'status', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n\nexport async function runTitleSettingsSave(input: {\n call: TitleClientCall\n locale: TitleLocaleMode\n expectedRevision: number\n isCurrent: () => boolean\n savedMessage: string\n failedMessage: string\n onBusy: (busy: boolean) => void\n onSettings: (settings: TitleStatus['settings']) => void\n onNote: (note: string) => void\n onError: (message: string) => void\n}): Promise<void> {\n input.onBusy(true)\n try {\n const settings = await invoke<TitleStatus['settings']>(input.call, 'settings', {\n locale: input.locale,\n expectedRevision: input.expectedRevision,\n })\n if (!input.isCurrent()) return\n input.onSettings(settings)\n input.onNote(input.savedMessage)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n","import type { TitleClientMarker, TitleStatus } from './contracts.ts'\n\nexport function createTitleClientMarker(): TitleClientMarker {\n return { active: false }\n}\n\nexport function applyMarkerFromStatus(marker: TitleClientMarker, status: Pick<TitleStatus, 'support'> | undefined, live: boolean): void {\n if (!live) return\n marker.active = status?.support.weOwn === true\n}\n\nexport function disposeTitleClientMarker(marker: TitleClientMarker): void {\n marker.active = false\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { NativeSurfaceClient } from '@klarkxy/dsh-ai-services/client-utils'\nimport { useFeatureRefresh, useNativeSeat } from '@klarkxy/dsh-ai-services/client-utils'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { RPC_CHANNEL, TITLE_CLIENT_SERVICE, type RpcResult, type TitleLocaleMode, type TitleStatus } from './contracts.ts'\nimport {\n createTitleClientWork, runTitleRegenerateFlow, runTitleSettingsSave, runTitleStatusLoad,\n shouldSkipTitleRefresh, titleCopy, type TitleClientCall, type TitleClientWork,\n} from './client-work.ts'\nimport { applyMarkerFromStatus, createTitleClientMarker, disposeTitleClientMarker } from './marker.ts'\n\nexport const name = 'dsh-current-title-client'\nexport const inject = ['slots', 'connection', 'sessions', 'locale', 'uiWorkspace', 'uiSession'] as const\nexport { createTitleClientMarker, disposeTitleClientMarker, applyMarkerFromStatus }\n\ntype Client = NativeSurfaceClient & {\n connection: NonNullable<NativeSurfaceClient['connection']> & {\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; label: string; order: number }, render: unknown): () => void\n }\n}\n\nexport function TitleSettings(props: {\n client: Client\n marker: { active: boolean }\n owner?: unknown\n}) {\n const seat = useNativeSeat(props.client, props.owner)\n const sessionId = seat.sessionId\n const text = titleCopy[seat.locale]\n const [status, setStatus] = useState<TitleStatus>()\n const [busy, setBusy] = useState(false)\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const workRef = useRef<TitleClientWork>(undefined)\n if (!workRef.current) workRef.current = createTitleClientWork()\n const work = workRef.current\n const busyRef = useRef(busy)\n busyRef.current = busy\n\n const call: TitleClientCall = (endpoint, payload = {}) => (\n props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload)\n )\n\n function commitMarker(next: TitleStatus | undefined) {\n applyMarkerFromStatus(props.marker, next, true)\n }\n\n useEffect(() => () => { work.dispose() }, [work])\n\n useEffect(() => {\n const generation = work.beginLoad()\n const isCurrent = () => work.isLoad(generation)\n setBusy(false)\n setError('')\n setNote('')\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent,\n failedMessage: text.failed,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n return () => { if (work.isLoad(generation)) work.beginLoad() }\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n const refreshStatus = useCallback(() => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return\n const generation = work.captureLoad()\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent: () => work.isLoad(generation) && !shouldSkipTitleRefresh({ busy: busyRef.current }),\n failedMessage: text.failed,\n onStatus: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n setStatus(next)\n },\n onError: () => {},\n onMarker: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n commitMarker(next)\n },\n })\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n useFeatureRefresh(\n props.client,\n sessionId,\n refreshStatus,\n status?.session?.generating === true && !busy,\n Boolean(sessionId),\n )\n\n const locale = status?.settings.locale ?? 'auto'\n const modes: Array<{ id: TitleLocaleMode; label: string }> = [\n { id: 'auto', label: text.auto },\n { id: 'zh', label: '中文' },\n { id: 'en', label: 'English' },\n ]\n const title = status?.session?.title\n const pinned = status?.session?.pinned === true\n const weOwn = status?.support.weOwn === true\n const canRegenerate = Boolean(sessionId) && weOwn && !busy\n\n return <section className=\"current-title-settings\" data-testid=\"current-title-settings\">\n {!status && !error ? <p role=\"status\">{seat.locale === 'en' ? 'Loading title settings…' : '正在读取标题设置…'}</p> : null}\n {title ? <p translate=\"no\">{title}</p> : null}\n {pinned ? <p className=\"current-title-meta\">{text.pinned}</p> : null}\n {status?.session?.generating ? <p role=\"status\">{text.generating}</p> : null}\n {error ? <p role=\"alert\">{error}</p> : null}\n {note ? <p role=\"status\">{note}</p> : null}\n {sessionId ? <button type=\"button\" disabled={!canRegenerate} aria-label={text.regenerate}\n onClick={() => {\n if (!sessionId) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleRegenerateFlow({\n call,\n sessionId,\n isCurrent: () => work.isRequest(token),\n failedMessage: text.failed,\n onBusy: setBusy,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n }}>{text.regenerate}</button> : null}\n <fieldset disabled={busy || !status} aria-label={text.locale}>\n <legend>{text.locale}</legend>\n {modes.map(mode => (\n <label key={mode.id}>\n <input type=\"radio\" name=\"current-title-locale\" value={mode.id} checked={locale === mode.id}\n onChange={() => {\n if (!status) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleSettingsSave({\n call,\n locale: mode.id,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => setStatus({ ...status, settings }),\n onNote: setNote,\n onError: setError,\n })\n }} />\n {mode.label}\n </label>\n ))}\n </fieldset>\n </section>\n}\n\nconst styles = `\n.current-title-settings{display:grid;gap:8px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}\n.current-title-settings p{margin:0}\n.current-title-settings p[translate=\"no\"]{overflow-wrap:anywhere}\n.current-title-meta{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}\n.current-title-settings button{min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}\n.current-title-settings button:hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}\n.current-title-settings button:active:not(:disabled){transform:scale(.97)}\n.current-title-settings button:disabled{opacity:.45;cursor:not-allowed}\n.current-title-settings fieldset{margin:0;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:10px;padding:8px 12px;display:grid;gap:8px}\n.current-title-settings label{display:flex;gap:8px;align-items:center}\n.current-title-settings :focus-visible{outline:2px solid currentColor;outline-offset:3px}\n@media(prefers-reduced-motion:reduce){.current-title-settings button{transition:none}}\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshCurrentTitleClient: { active: boolean } }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n const marker = createTitleClientMarker()\n ctx.provide(TITLE_CLIENT_SERVICE, marker)\n ctx.effect(() => {\n let live = true\n void client.connection.rpc.call(RPC_CHANNEL, 'status', {}).then(result => {\n const row = result as RpcResult<TitleStatus>\n if (!live) return\n applyMarkerFromStatus(marker, row?.ok ? row.value : undefined, live)\n }).catch(() => { if (live) applyMarkerFromStatus(marker, undefined, live) })\n return () => { live = false; disposeTitleClientMarker(marker) }\n }, 'current-title.marker')\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', '@klarkxy/dsh-current-title')\n style.textContent = styles\n document.head.appendChild(style)\n return () => style.remove()\n }, 'current-title.styles')\n ctx.effect(() => client.slots.inject('settings.section', () => client.slots.register({\n name: 'settings.section', id: 'current-title', order: 80, label: '当前标题',\n }, (props: unknown) => <TitleSettings client={client} marker={marker} owner={props} />)), 'current-title.settings')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.inner.cjs","names":["useSyncExternalStore","useCallback","useRef","useState","useRef","useCallback"],"sources":["../../dsh-ai-services/src/client-utils.ts","../src/contracts.ts","../src/client-work.ts","../src/marker.ts","../src/client.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\nexport interface NativeSurfaceClient {\n sessions: {\n binding?(sessionId: string): { eventSource: { subscribe(listener: () => void): () => void } } | undefined\n }\n uiWorkspace: { current?: { getSnapshot(): { sessionId: string } | undefined; subscribe(listener: () => void): () => void } }\n uiSession: { adapter: { current: { getSnapshot(): { key?: string }; subscribe(listener: () => void): () => void } } }\n locale: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n connection?: { generation?: { subscribe(listener: () => void): () => void } }\n}\n\n/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */\nexport function selectedSessionId(client: Pick<NativeSurfaceClient, 'uiWorkspace' | 'uiSession'>): string {\n return client.uiWorkspace.current\n ? client.uiWorkspace.current.getSnapshot()?.sessionId ?? ''\n : client.uiSession.adapter.current.getSnapshot().key ?? ''\n}\n\n/** Owner props win; native settings only supplies close, so resolve its selected session. */\nexport function useNativeSeat(client: NativeSurfaceClient, props: unknown) {\n const current = useSyncExternalStore(\n useCallback((fn: () => void) => (client.uiWorkspace.current ?? client.uiSession.adapter.current).subscribe(fn), [client]),\n useCallback(() => selectedSessionId(client), [client]),\n () => '',\n )\n const language = useSyncExternalStore(\n useCallback((fn: () => void) => client.locale.subscribe(fn), [client]),\n useCallback(() => client.locale.getSnapshot().active, [client]),\n () => 'en',\n )\n const row = props && typeof props === 'object' ? props as Record<string, unknown> : {}\n const owner = row.owner && typeof row.owner === 'object' ? row.owner as Record<string, unknown> : {}\n const sessionId = typeof row.sessionId === 'string' ? row.sessionId\n : typeof owner.sessionId === 'string' ? owner.sessionId : current\n const requestedLocale = row.locale ?? owner.locale ?? language\n return { sessionId, locale: (String(requestedLocale).startsWith('zh') ? 'zh' : 'en') as 'zh' | 'en',\n hidden: row.hidden === true || owner.hidden === true }\n}\n\n/** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */\nexport function useFeatureRefresh(\n client: NativeSurfaceClient, sessionId: string, refresh: () => void,\n working = false, enabled = true,\n): void {\n const refreshRef = useRef(refresh)\n refreshRef.current = refresh\n useEffect(() => {\n if (!enabled) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const queue = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n clearTimeout(timer)\n timer = setTimeout(() => refreshRef.current(), 150)\n }\n const source = sessionId ? client.sessions.binding?.(sessionId)?.eventSource : undefined\n const stopEvents = source?.subscribe(queue)\n const stopConnection = client.connection?.generation?.subscribe(queue)\n const visibility = () => { if (document.visibilityState === 'visible') queue() }\n window.addEventListener('focus', queue)\n document.addEventListener('visibilitychange', visibility)\n // Details are collapsed by default; opening an existing panel must get current state.\n document.addEventListener('toggle', queue, true)\n return () => {\n clearTimeout(timer)\n stopEvents?.(); stopConnection?.()\n window.removeEventListener('focus', queue)\n document.removeEventListener('visibilitychange', visibility)\n document.removeEventListener('toggle', queue, true)\n }\n }, [client, sessionId, enabled])\n useEffect(() => {\n if (!enabled || !working) return\n let delay = 250\n const until = Date.now() + 300_000\n let timer: ReturnType<typeof setTimeout>\n const tick = () => {\n if (Date.now() >= until) return\n if (document.visibilityState !== 'hidden') refreshRef.current()\n delay = Math.min(delay * 2, 2000)\n timer = setTimeout(tick, delay)\n }\n timer = setTimeout(tick, delay)\n return () => clearTimeout(timer)\n }, [client, sessionId, working, enabled])\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-ai-services. */\nexport type { RpcResult } from '@klarkxy/dsh-ai-services/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-current-title'\nexport const FEATURE_ID = 'current-title'\nexport const PROVIDER_ID = '@klarkxy/dsh-current-title'\nexport const PURPOSE_ID = 'current-title.generate'\nexport const RPC_CHANNEL = '/dsh-current-title'\nexport const TITLE_CLIENT_SERVICE = 'dshCurrentTitleClient'\nexport const PROMPT_VERSION = 'current-title.v1'\nexport const SCHEMA_VERSION = 'title-json.v1'\nexport const CONTRACT_VERSION = 1\nexport const SETTINGS_KEY = 'current'\n\nexport const DEFAULT_MAX_RECENT_MESSAGES = 8\nexport const DEFAULT_TARGET_WORDS = 5\nexport const DEFAULT_TARGET_CJK = 10\nexport const DEFAULT_MAX_INPUT_BYTES = 4096\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 64\nexport const DEFAULT_TIMEOUT_MS = 60_000\nexport const DEFAULT_MAX_TITLE_BYTES = 80\n\nexport type TitleLocaleMode = 'auto' | 'zh' | 'en'\nexport type TitleSourceKind = 'fallback' | 'provider' | 'user'\n\nexport interface TitleMessage {\n readonly seq: number\n readonly text: string\n}\n\nexport interface TitleSnapshot {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly source: { readonly kind: TitleSourceKind; readonly provider?: string }\n readonly eventSeq: number\n readonly updatedAt: number\n}\n\nexport interface TitleSettings {\n revision: number\n locale: TitleLocaleMode\n}\n\nexport interface TitleSupport {\n nativeOwner: string | null\n weOwn: boolean\n limitation?: string\n}\n\nexport interface TitleStatus {\n settings: TitleSettings\n support: TitleSupport\n session?: {\n sessionId: string\n title?: string\n sourceKind?: TitleSourceKind\n generating: boolean\n pinned: boolean\n }\n}\n\nexport interface TitleClientMarker {\n active: boolean\n}\n\nexport interface GenerateConfig {\n readonly maxRecentMessages: number\n readonly locale: TitleLocaleMode\n readonly targetWords: number\n readonly targetCjkCharacters: number\n readonly maxInputBytes: number\n readonly maxOutputTokens: number\n readonly timeoutMs: number\n readonly maxTitleBytes: number\n}\n\nexport function defaultSettings(locale: TitleLocaleMode = 'auto'): TitleSettings {\n return { revision: 0, locale }\n}\n\nexport function defaultGenerateConfig(locale: TitleLocaleMode = 'auto'): GenerateConfig {\n return {\n maxRecentMessages: DEFAULT_MAX_RECENT_MESSAGES,\n locale,\n targetWords: DEFAULT_TARGET_WORDS,\n targetCjkCharacters: DEFAULT_TARGET_CJK,\n maxInputBytes: DEFAULT_MAX_INPUT_BYTES,\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxTitleBytes: DEFAULT_MAX_TITLE_BYTES,\n }\n}\n\nexport function isTitleLocaleMode(value: unknown): value is TitleLocaleMode {\n return value === 'auto' || value === 'zh' || value === 'en'\n}\n","import type { RpcResult, TitleLocaleMode, TitleStatus } from './contracts.ts'\n\nexport const titleCopy = {\n zh: {\n label: '当前标题',\n pinned: '已手动命名',\n generating: '正在生成标题…',\n regenerate: '重新生成',\n locale: '类型标签语言',\n auto: '自动',\n saved: '已保存。',\n failed: '无法读取标题设置。',\n },\n en: {\n label: 'Current title',\n pinned: 'Renamed manually',\n generating: 'Generating title…',\n regenerate: 'Regenerate',\n locale: 'Type-label language',\n auto: 'Auto',\n saved: 'Saved.',\n failed: 'Could not read title settings.',\n },\n} as const\n\nexport function settingsCopy(locale: 'zh' | 'en') {\n return titleCopy[locale] ?? titleCopy.zh\n}\n\nexport function shouldSkipTitleRefresh(input: { busy: boolean }): boolean {\n return input.busy\n}\n\nexport function createTitleClientWork() {\n let generation = 0\n let request = 0\n let disposed = false\n return {\n get disposed() { return disposed },\n beginLoad() {\n generation += 1\n request += 1\n return generation\n },\n captureLoad() {\n return generation\n },\n beginRequest() {\n request += 1\n return { generation, request }\n },\n isLoad(generationToken: number) {\n return !disposed && generation === generationToken\n },\n isRequest(token: { generation: number; request: number }) {\n return !disposed && generation === token.generation && request === token.request\n },\n dispose() {\n disposed = true\n generation += 1\n request += 1\n },\n }\n}\n\nexport type TitleClientWork = ReturnType<typeof createTitleClientWork>\nexport type TitleClientCall = (endpoint: string, payload?: unknown) => Promise<unknown>\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\nasync function invoke<T>(call: TitleClientCall, endpoint: string, payload?: unknown): Promise<T> {\n return unwrap(await call(endpoint, payload) as RpcResult<T>)\n}\n\nexport async function runTitleStatusLoad(input: {\n call: TitleClientCall\n sessionId?: string\n isCurrent: () => boolean\n failedMessage: string\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n try {\n const status = await invoke<TitleStatus>(\n input.call,\n 'status',\n input.sessionId ? { sessionId: input.sessionId } : {},\n )\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch {\n if (!input.isCurrent()) return\n input.onMarker(undefined)\n input.onError(input.failedMessage)\n }\n}\n\nexport async function runTitleRegenerateFlow(input: {\n call: TitleClientCall\n sessionId: string\n isCurrent: () => boolean\n failedMessage: string\n onBusy: (busy: boolean) => void\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n if (!input.sessionId || !input.isCurrent()) return\n input.onBusy(true)\n try {\n await invoke(input.call, 'regenerate', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n const status = await invoke<TitleStatus>(input.call, 'status', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n\nexport async function runTitleSettingsSave(input: {\n call: TitleClientCall\n locale: TitleLocaleMode\n expectedRevision: number\n isCurrent: () => boolean\n savedMessage: string\n failedMessage: string\n onBusy: (busy: boolean) => void\n onSettings: (settings: TitleStatus['settings']) => void\n onNote: (note: string) => void\n onError: (message: string) => void\n}): Promise<void> {\n input.onBusy(true)\n try {\n const settings = await invoke<TitleStatus['settings']>(input.call, 'settings', {\n locale: input.locale,\n expectedRevision: input.expectedRevision,\n })\n if (!input.isCurrent()) return\n input.onSettings(settings)\n input.onNote(input.savedMessage)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n","import type { TitleClientMarker, TitleStatus } from './contracts.ts'\n\nexport function createTitleClientMarker(): TitleClientMarker {\n return { active: false }\n}\n\nexport function applyMarkerFromStatus(marker: TitleClientMarker, status: Pick<TitleStatus, 'support'> | undefined, live: boolean): void {\n if (!live) return\n marker.active = status?.support.weOwn === true\n}\n\nexport function disposeTitleClientMarker(marker: TitleClientMarker): void {\n marker.active = false\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { NativeSurfaceClient } from '@klarkxy/dsh-ai-services/client-utils'\nimport { useFeatureRefresh, useNativeSeat } from '@klarkxy/dsh-ai-services/client-utils'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { RPC_CHANNEL, TITLE_CLIENT_SERVICE, type RpcResult, type TitleLocaleMode, type TitleStatus } from './contracts.ts'\nimport {\n createTitleClientWork, runTitleRegenerateFlow, runTitleSettingsSave, runTitleStatusLoad,\n shouldSkipTitleRefresh, titleCopy, type TitleClientCall, type TitleClientWork,\n} from './client-work.ts'\nimport { applyMarkerFromStatus, createTitleClientMarker, disposeTitleClientMarker } from './marker.ts'\n\nexport const name = 'dsh-current-title-client'\nexport const inject = ['slots', 'connection', 'sessions', 'locale', 'uiWorkspace', 'uiSession'] as const\nexport { createTitleClientMarker, disposeTitleClientMarker, applyMarkerFromStatus }\n\ntype Client = NativeSurfaceClient & {\n connection: NonNullable<NativeSurfaceClient['connection']> & {\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; id: string; label: string; order: number }, render: unknown): () => void\n }\n}\n\nexport function TitleSettings(props: {\n client: Client\n marker: { active: boolean }\n owner?: unknown\n}) {\n const seat = useNativeSeat(props.client, props.owner)\n const sessionId = seat.sessionId\n const text = titleCopy[seat.locale]\n const [status, setStatus] = useState<TitleStatus>()\n const [busy, setBusy] = useState(false)\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const workRef = useRef<TitleClientWork>(undefined)\n if (!workRef.current) workRef.current = createTitleClientWork()\n const work = workRef.current\n const busyRef = useRef(busy)\n busyRef.current = busy\n\n const call: TitleClientCall = (endpoint, payload = {}) => (\n props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload)\n )\n\n function commitMarker(next: TitleStatus | undefined) {\n applyMarkerFromStatus(props.marker, next, true)\n }\n\n useEffect(() => () => { work.dispose() }, [work])\n\n useEffect(() => {\n const generation = work.beginLoad()\n const isCurrent = () => work.isLoad(generation)\n setBusy(false)\n setError('')\n setNote('')\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent,\n failedMessage: text.failed,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n return () => { if (work.isLoad(generation)) work.beginLoad() }\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n const refreshStatus = useCallback(() => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return\n const generation = work.captureLoad()\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent: () => work.isLoad(generation) && !shouldSkipTitleRefresh({ busy: busyRef.current }),\n failedMessage: text.failed,\n onStatus: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n setStatus(next)\n },\n onError: () => {},\n onMarker: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n commitMarker(next)\n },\n })\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n useFeatureRefresh(\n props.client,\n sessionId,\n refreshStatus,\n status?.session?.generating === true && !busy,\n Boolean(sessionId),\n )\n\n const locale = status?.settings.locale ?? 'auto'\n const modes: Array<{ id: TitleLocaleMode; label: string }> = [\n { id: 'auto', label: text.auto },\n { id: 'zh', label: '中文' },\n { id: 'en', label: 'English' },\n ]\n const title = status?.session?.title\n const pinned = status?.session?.pinned === true\n const weOwn = status?.support.weOwn === true\n const canRegenerate = Boolean(sessionId) && weOwn && !busy\n\n return <section className=\"current-title-settings\" data-testid=\"current-title-settings\">\n {!status && !error ? <p role=\"status\">{seat.locale === 'en' ? 'Loading title settings…' : '正在读取标题设置…'}</p> : null}\n {title ? <p translate=\"no\">{title}</p> : null}\n {pinned ? <p className=\"current-title-meta\">{text.pinned}</p> : null}\n {status?.session?.generating ? <p role=\"status\">{text.generating}</p> : null}\n {error ? <p role=\"alert\">{error}</p> : null}\n {note ? <p role=\"status\">{note}</p> : null}\n {sessionId ? <button type=\"button\" disabled={!canRegenerate} aria-label={text.regenerate}\n onClick={() => {\n if (!sessionId) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleRegenerateFlow({\n call,\n sessionId,\n isCurrent: () => work.isRequest(token),\n failedMessage: text.failed,\n onBusy: setBusy,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n }}>{text.regenerate}</button> : null}\n <fieldset disabled={busy || !status} aria-label={text.locale}>\n <legend>{text.locale}</legend>\n {modes.map(mode => (\n <label key={mode.id}>\n <input type=\"radio\" name=\"current-title-locale\" value={mode.id} checked={locale === mode.id}\n onChange={() => {\n if (!status) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleSettingsSave({\n call,\n locale: mode.id,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => setStatus({ ...status, settings }),\n onNote: setNote,\n onError: setError,\n })\n }} />\n {mode.label}\n </label>\n ))}\n </fieldset>\n </section>\n}\n\nconst styles = `\n.current-title-settings{display:grid;gap:8px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}\n.current-title-settings p{margin:0}\n.current-title-settings p[translate=\"no\"]{overflow-wrap:anywhere}\n.current-title-meta{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}\n.current-title-settings button{min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}\n.current-title-settings button:hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}\n.current-title-settings button:active:not(:disabled){transform:scale(.97)}\n.current-title-settings button:disabled{opacity:.45;cursor:not-allowed}\n.current-title-settings fieldset{margin:0;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:10px;padding:8px 12px;display:grid;gap:8px}\n.current-title-settings label{display:flex;gap:8px;align-items:center}\n.current-title-settings :focus-visible{outline:2px solid currentColor;outline-offset:3px}\n@media(prefers-reduced-motion:reduce){.current-title-settings button{transition:none}}\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshCurrentTitleClient: { active: boolean } }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n const marker = createTitleClientMarker()\n ctx.provide(TITLE_CLIENT_SERVICE, marker)\n ctx.effect(() => {\n let live = true\n void client.connection.rpc.call(RPC_CHANNEL, 'status', {}).then(result => {\n const row = result as RpcResult<TitleStatus>\n if (!live) return\n applyMarkerFromStatus(marker, row?.ok ? row.value : undefined, live)\n }).catch(() => { if (live) applyMarkerFromStatus(marker, undefined, live) })\n return () => { live = false; disposeTitleClientMarker(marker) }\n }, 'current-title.marker')\n}\n"],"mappings":"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"}
|
package/lib/client.js
CHANGED
|
@@ -559,20 +559,6 @@ function TitleSettings(props) {
|
|
|
559
559
|
]
|
|
560
560
|
});
|
|
561
561
|
}
|
|
562
|
-
const styles = `
|
|
563
|
-
.current-title-settings{display:grid;gap:8px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}
|
|
564
|
-
.current-title-settings p{margin:0}
|
|
565
|
-
.current-title-settings p[translate="no"]{overflow-wrap:anywhere}
|
|
566
|
-
.current-title-meta{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}
|
|
567
|
-
.current-title-settings button{min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}
|
|
568
|
-
.current-title-settings button:hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}
|
|
569
|
-
.current-title-settings button:active:not(:disabled){transform:scale(.97)}
|
|
570
|
-
.current-title-settings button:disabled{opacity:.45;cursor:not-allowed}
|
|
571
|
-
.current-title-settings fieldset{margin:0;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:10px;padding:8px 12px;display:grid;gap:8px}
|
|
572
|
-
.current-title-settings label{display:flex;gap:8px;align-items:center}
|
|
573
|
-
.current-title-settings :focus-visible{outline:2px solid currentColor;outline-offset:3px}
|
|
574
|
-
@media(prefers-reduced-motion:reduce){.current-title-settings button{transition:none}}
|
|
575
|
-
`;
|
|
576
562
|
function apply(ctx) {
|
|
577
563
|
const client = ctx;
|
|
578
564
|
const marker = createTitleClientMarker();
|
|
@@ -591,24 +577,6 @@ function apply(ctx) {
|
|
|
591
577
|
disposeTitleClientMarker(marker);
|
|
592
578
|
};
|
|
593
579
|
}, "current-title.marker");
|
|
594
|
-
ctx.effect(() => {
|
|
595
|
-
if (typeof document === "undefined") return () => {};
|
|
596
|
-
const style = document.createElement("style");
|
|
597
|
-
style.setAttribute("data-plugin", "@klarkxy/dsh-current-title");
|
|
598
|
-
style.textContent = styles;
|
|
599
|
-
document.head.appendChild(style);
|
|
600
|
-
return () => style.remove();
|
|
601
|
-
}, "current-title.styles");
|
|
602
|
-
ctx.effect(() => client.slots.inject("settings.section", () => client.slots.register({
|
|
603
|
-
name: "settings.section",
|
|
604
|
-
id: "current-title",
|
|
605
|
-
order: 80,
|
|
606
|
-
label: "当前标题"
|
|
607
|
-
}, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TitleSettings, {
|
|
608
|
-
client,
|
|
609
|
-
marker,
|
|
610
|
-
owner: props
|
|
611
|
-
}))), "current-title.settings");
|
|
612
580
|
}
|
|
613
581
|
//#endregion
|
|
614
582
|
exports.TitleSettings = TitleSettings;
|
package/lib/index.d.ts
CHANGED
|
@@ -134,7 +134,7 @@ declare class CurrentTitleService {
|
|
|
134
134
|
start(): Promise<void>;
|
|
135
135
|
dispose(): Promise<void>;
|
|
136
136
|
status(sessionId?: string): TitleStatus;
|
|
137
|
-
updateLocale(
|
|
137
|
+
updateLocale(_locale: TitleLocaleMode, expectedRevision: number): Promise<TitleSettings>;
|
|
138
138
|
regenerate(sessionId: string, signal: AbortSignal): Promise<TitleSnapshot | undefined>;
|
|
139
139
|
read(session: SessionLike): TitleSnapshot | undefined;
|
|
140
140
|
private nativeGenerate;
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PLUGIN_NAME, PROMPT_VERSION, PROVIDER_ID, PURPOSE_ID, RPC_CHANNEL, SCHEMA_VERSION, SETTINGS_KEY, defaultGenerateConfig,
|
|
1
|
+
import { PLUGIN_NAME, PROMPT_VERSION, PROVIDER_ID, PURPOSE_ID, RPC_CHANNEL, SCHEMA_VERSION, SETTINGS_KEY, defaultGenerateConfig, isTitleLocaleMode } from "./contracts.js";
|
|
2
2
|
import { registerHostRpc } from "@klarkxy/dsh-ai-services/host-rpc";
|
|
3
3
|
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -113,7 +113,7 @@ function truncateTitleUtf8(input, maxBytes) {
|
|
|
113
113
|
}
|
|
114
114
|
return output;
|
|
115
115
|
}
|
|
116
|
-
/** Same sanitizing rules as DSH 0.1.7-
|
|
116
|
+
/** Same sanitizing rules as DSH 0.1.7-rc.2 `normalizeSessionTitle`. */
|
|
117
117
|
function normalizeSessionTitle(input, maxBytes) {
|
|
118
118
|
return truncateTitleUtf8(cleanTitleText(input), maxBytes).trimEnd();
|
|
119
119
|
}
|
|
@@ -400,8 +400,11 @@ function parseTitleSettings(value) {
|
|
|
400
400
|
if (!isTitleLocaleMode(parsed.data.locale)) return void 0;
|
|
401
401
|
return parsed.data;
|
|
402
402
|
}
|
|
403
|
-
function storedSettings(value,
|
|
404
|
-
return
|
|
403
|
+
function storedSettings(value, _fallbackLocale = "auto") {
|
|
404
|
+
return {
|
|
405
|
+
revision: parseTitleSettings(value)?.revision ?? 0,
|
|
406
|
+
locale: "auto"
|
|
407
|
+
};
|
|
405
408
|
}
|
|
406
409
|
//#endregion
|
|
407
410
|
//#region src/service.ts
|
|
@@ -488,17 +491,17 @@ var CurrentTitleService = class {
|
|
|
488
491
|
} } : {}
|
|
489
492
|
};
|
|
490
493
|
}
|
|
491
|
-
async updateLocale(
|
|
494
|
+
async updateLocale(_locale, expectedRevision) {
|
|
492
495
|
if (this.settings.revision !== expectedRevision) throw Object.assign(/* @__PURE__ */ new Error("current-title settings changed"), { code: "revision" });
|
|
493
496
|
const next = {
|
|
494
497
|
revision: this.settings.revision + 1,
|
|
495
|
-
locale
|
|
498
|
+
locale: "auto"
|
|
496
499
|
};
|
|
497
500
|
if (this.options.store) await this.options.store.save(next);
|
|
498
501
|
this.settings = next;
|
|
499
502
|
this.config = {
|
|
500
503
|
...this.config,
|
|
501
|
-
locale
|
|
504
|
+
locale: "auto"
|
|
502
505
|
};
|
|
503
506
|
return { ...this.settings };
|
|
504
507
|
}
|
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-alpha.1 `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\nexport function parseModelTitle(\n raw: string,\n targetWords: number,\n targetCjkCharacters: number,\n): ParsedTitle {\n let value: unknown\n try {\n value = JSON.parse(raw.trim())\n } catch (cause) {\n throw new Error('dsh-current-title: title model returned invalid JSON', { cause })\n }\n\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('dsh-current-title: title model response must be an object')\n }\n\n const candidate = value as Record<string, unknown>\n if (Object.keys(candidate).sort().join(',') !== 'summary,type') {\n throw new Error('dsh-current-title: title model response must contain only type and summary')\n }\n if (typeof candidate.type !== 'string' || !isTitleType(candidate.type)) {\n throw new Error('dsh-current-title: title model returned an unsupported type')\n }\n if (typeof candidate.summary !== 'string') {\n throw new Error('dsh-current-title: title model summary must be a string')\n }\n\n const normalized = normalizeSessionTitle(removeTitleSyntax(candidate.summary), 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\n return { type: candidate.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 type { AiFeatureScope } from '@klarkxy/dsh-ai-services/contracts'\nimport type { GenerateConfig, TitleMessage } from './contracts.ts'\nimport { CONTRACT_VERSION, DEFAULT_MAX_OUTPUT_TOKENS, PROMPT_VERSION, PURPOSE_ID, SCHEMA_VERSION } 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): string {\n return [\n '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\nexport function registerTitlePurpose(scope: AiFeatureScope): () => void {\n return scope.registerPurpose({\n id: PURPOSE_ID,\n label: '当前标题',\n defaultTarget: { kind: 'role', role: 'weak' },\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n })\n}\n\nexport async function generateCurrentTitle(options: {\n scope: AiFeatureScope\n config: GenerateConfig\n sessionId: string\n messages: readonly TitleMessage[]\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.scope.active || !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\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 let settled = false\n const aborted = new Promise<never>((_, reject) => {\n const fail = () => {\n if (settled) return\n reject(options.signal.reason ?? new Error('dsh-current-title: generation cancelled'))\n }\n if (options.signal.aborted) { fail(); return }\n options.signal.addEventListener('abort', fail, { once: true })\n })\n let result: Awaited<ReturnType<AiFeatureScope['run']>>\n try {\n result = await Promise.race([\n options.scope.run({\n purpose: PURPOSE_ID,\n sessionId: options.sessionId,\n input: framedInput,\n system: systemPrompt(options.config),\n sourceVersion,\n contractVersion: CONTRACT_VERSION,\n promptVersion: PROMPT_VERSION,\n schemaVersion: SCHEMA_VERSION,\n signal: options.signal,\n isCurrent: () => options.scope.active && options.isCurrent(),\n priority: 'background',\n }),\n aborted,\n ])\n } finally {\n settled = true\n }\n options.signal.throwIfAborted()\n if (!options.scope.active || !options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n if (result.receipt.status === 'cancelled' || result.receipt.status === 'superseded') {\n throw Object.assign(new Error('dsh-current-title: generation did not complete'), { code: result.receipt.status })\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 const route = result.receipt.route\n return {\n title,\n messageSeqs: selected.map(message => message.seq),\n ...(route?.provider && route.model ? { model: { provider: route.provider, model: route.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 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: 'all-prompts',\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 { SETTINGS_KEY, defaultSettings, isTitleLocaleMode, type TitleSettings } from './contracts.ts'\n\nexport { SETTINGS_KEY }\n\nexport const titleSettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: z.enum(['auto', 'zh', 'en']),\n}).strict()\n\nexport const titleDomain = defineDomain({\n name: 'dsh_editor_current_title',\n version: 1,\n tables: {\n settings: domainTable<string, TitleSettings>(titleSettingsSchema),\n },\n})\n\nexport function parseTitleSettings(value: unknown): TitleSettings | undefined {\n const parsed = titleSettingsSchema.safeParse(value)\n if (!parsed.success) return undefined\n if (!isTitleLocaleMode(parsed.data.locale)) return undefined\n return parsed.data\n}\n\nexport function storedSettings(value: unknown, fallbackLocale: TitleSettings['locale'] = 'auto'): TitleSettings {\n return parseTitleSettings(value) ?? defaultSettings(fallbackLocale)\n}\n","import type { AiFeatureScope, AiServices, RpcResult } from '@klarkxy/dsh-ai-services/contracts'\nimport type { GenerateConfig, TitleSettings, TitleSnapshot, TitleStatus, TitleSupport } from './contracts.ts'\nimport { PROVIDER_ID, defaultGenerateConfig, isTitleLocaleMode } from './contracts.ts'\nimport { generateCurrentTitle, registerTitlePurpose } 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 { 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 scope?: AiFeatureScope\n private unregisterPurpose?: () => void\n private claim?: OwnershipClaim\n private nativeSlot?: ReturnType<typeof createNativeTitleSlot>\n private generation = 0\n private readonly inFlight = new Map<string, AbortController>()\n readonly support: TitleSupport\n\n constructor(private readonly options: {\n plugin: string\n ai?: AiServices\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 }) {\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 { ai, sessionTitle, loader, sessions } = this.options\n if (!ai || !sessionTitle?.register || !sessions || !loader) {\n this.support.weOwn = false\n this.support.limitation = 'required host services are missing'\n return\n }\n this.scope = ai.activate(this.options.plugin)\n this.unregisterPurpose = registerTitlePurpose(this.scope)\n this.nativeSlot = createNativeTitleSlot({\n sessionTitle,\n loader,\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.generation += 1\n for (const controller of this.inFlight.values()) controller.abort(new Error('current-title disabled'))\n this.inFlight.clear()\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 this.unregisterPurpose?.()\n this.unregisterPurpose = undefined\n this.scope?.dispose()\n this.scope = undefined\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 },\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 updateLocale(locale: TitleLocaleMode, expectedRevision: number): Promise<TitleSettings> {\n if (this.settings.revision !== expectedRevision) {\n throw Object.assign(new Error('current-title settings changed'), { code: 'revision' })\n }\n const next = { revision: this.settings.revision + 1, locale }\n if (this.options.store) await this.options.store.save(next)\n this.settings = next\n this.config = { ...this.config, locale }\n return { ...this.settings }\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 scope = this.scope\n if (!scope) throw new Error('dsh-current-title: aiServices 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, scope.signal])\n const session = this.options.sessions?.get(request.session.id)\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 scope,\n config: this.config,\n sessionId: request.session.id,\n messages: messages.length > 0 ? messages : [...request.messages],\n localePreference: this.options.localePreference?.(),\n signal: combined,\n isCurrent: () => this.generation === generation && scope.active && 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 (!isTitleLocaleMode(body.locale) || typeof body.expectedRevision !== 'number') {\n return { ok: false, error: { code: 'bad-request', message: '标题语言设置无效。' } }\n }\n try {\n return { ok: true, value: await service.updateLocale(body.locale, body.expectedRevision) }\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 { AiServices } from '@klarkxy/dsh-ai-services/contracts'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-ai-services/host-rpc'\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', 'aiServices', 'sessions', 'loader', 'storageDomain', 'connection', 'webServer'] 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 aiServices: AiServices\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 ai: host.aiServices,\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}\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\nexport function parseModelTitle(\n raw: string,\n targetWords: number,\n targetCjkCharacters: number,\n): ParsedTitle {\n let value: unknown\n try {\n value = JSON.parse(raw.trim())\n } catch (cause) {\n throw new Error('dsh-current-title: title model returned invalid JSON', { cause })\n }\n\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('dsh-current-title: title model response must be an object')\n }\n\n const candidate = value as Record<string, unknown>\n if (Object.keys(candidate).sort().join(',') !== 'summary,type') {\n throw new Error('dsh-current-title: title model response must contain only type and summary')\n }\n if (typeof candidate.type !== 'string' || !isTitleType(candidate.type)) {\n throw new Error('dsh-current-title: title model returned an unsupported type')\n }\n if (typeof candidate.summary !== 'string') {\n throw new Error('dsh-current-title: title model summary must be a string')\n }\n\n const normalized = normalizeSessionTitle(removeTitleSyntax(candidate.summary), 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\n return { type: candidate.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 type { AiFeatureScope } from '@klarkxy/dsh-ai-services/contracts'\nimport type { GenerateConfig, TitleMessage } from './contracts.ts'\nimport { CONTRACT_VERSION, DEFAULT_MAX_OUTPUT_TOKENS, PROMPT_VERSION, PURPOSE_ID, SCHEMA_VERSION } 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): string {\n return [\n '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\nexport function registerTitlePurpose(scope: AiFeatureScope): () => void {\n return scope.registerPurpose({\n id: PURPOSE_ID,\n label: '当前标题',\n defaultTarget: { kind: 'role', role: 'weak' },\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n })\n}\n\nexport async function generateCurrentTitle(options: {\n scope: AiFeatureScope\n config: GenerateConfig\n sessionId: string\n messages: readonly TitleMessage[]\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.scope.active || !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\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 let settled = false\n const aborted = new Promise<never>((_, reject) => {\n const fail = () => {\n if (settled) return\n reject(options.signal.reason ?? new Error('dsh-current-title: generation cancelled'))\n }\n if (options.signal.aborted) { fail(); return }\n options.signal.addEventListener('abort', fail, { once: true })\n })\n let result: Awaited<ReturnType<AiFeatureScope['run']>>\n try {\n result = await Promise.race([\n options.scope.run({\n purpose: PURPOSE_ID,\n sessionId: options.sessionId,\n input: framedInput,\n system: systemPrompt(options.config),\n sourceVersion,\n contractVersion: CONTRACT_VERSION,\n promptVersion: PROMPT_VERSION,\n schemaVersion: SCHEMA_VERSION,\n signal: options.signal,\n isCurrent: () => options.scope.active && options.isCurrent(),\n priority: 'background',\n }),\n aborted,\n ])\n } finally {\n settled = true\n }\n options.signal.throwIfAborted()\n if (!options.scope.active || !options.isCurrent()) {\n throw Object.assign(new Error('dsh-current-title: generation is no longer current'), { code: 'superseded' })\n }\n if (result.receipt.status === 'cancelled' || result.receipt.status === 'superseded') {\n throw Object.assign(new Error('dsh-current-title: generation did not complete'), { code: result.receipt.status })\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 const route = result.receipt.route\n return {\n title,\n messageSeqs: selected.map(message => message.seq),\n ...(route?.provider && route.model ? { model: { provider: route.provider, model: route.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 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: 'all-prompts',\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 { SETTINGS_KEY, isTitleLocaleMode, type TitleSettings } from './contracts.ts'\n\nexport { SETTINGS_KEY }\n\nexport const titleSettingsSchema = z.object({\n revision: z.number().int().nonnegative(),\n locale: z.enum(['auto', 'zh', 'en']),\n}).strict()\n\nexport const titleDomain = defineDomain({\n name: 'dsh_editor_current_title',\n version: 1,\n tables: {\n settings: domainTable<string, TitleSettings>(titleSettingsSchema),\n },\n})\n\nexport function parseTitleSettings(value: unknown): TitleSettings | undefined {\n const parsed = titleSettingsSchema.safeParse(value)\n if (!parsed.success) return undefined\n if (!isTitleLocaleMode(parsed.data.locale)) return undefined\n return parsed.data\n}\n\nexport function storedSettings(value: unknown, _fallbackLocale: TitleSettings['locale'] = 'auto'): TitleSettings {\n const parsed = parseTitleSettings(value)\n return { revision: parsed?.revision ?? 0, locale: 'auto' }\n}\n","import type { AiFeatureScope, AiServices, RpcResult } from '@klarkxy/dsh-ai-services/contracts'\nimport type { GenerateConfig, TitleSettings, TitleSnapshot, TitleStatus, TitleSupport } from './contracts.ts'\nimport { PROVIDER_ID, defaultGenerateConfig, isTitleLocaleMode } from './contracts.ts'\nimport { generateCurrentTitle, registerTitlePurpose } 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 { 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 scope?: AiFeatureScope\n private unregisterPurpose?: () => void\n private claim?: OwnershipClaim\n private nativeSlot?: ReturnType<typeof createNativeTitleSlot>\n private generation = 0\n private readonly inFlight = new Map<string, AbortController>()\n readonly support: TitleSupport\n\n constructor(private readonly options: {\n plugin: string\n ai?: AiServices\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 }) {\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 { ai, sessionTitle, loader, sessions } = this.options\n if (!ai || !sessionTitle?.register || !sessions || !loader) {\n this.support.weOwn = false\n this.support.limitation = 'required host services are missing'\n return\n }\n this.scope = ai.activate(this.options.plugin)\n this.unregisterPurpose = registerTitlePurpose(this.scope)\n this.nativeSlot = createNativeTitleSlot({\n sessionTitle,\n loader,\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.generation += 1\n for (const controller of this.inFlight.values()) controller.abort(new Error('current-title disabled'))\n this.inFlight.clear()\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 this.unregisterPurpose?.()\n this.unregisterPurpose = undefined\n this.scope?.dispose()\n this.scope = undefined\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 },\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 updateLocale(_locale: TitleLocaleMode, expectedRevision: number): Promise<TitleSettings> {\n if (this.settings.revision !== expectedRevision) {\n throw Object.assign(new Error('current-title settings changed'), { code: 'revision' })\n }\n const next = { revision: this.settings.revision + 1, locale: 'auto' as const }\n if (this.options.store) await this.options.store.save(next)\n this.settings = next\n this.config = { ...this.config, locale: 'auto' }\n return { ...this.settings }\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 scope = this.scope\n if (!scope) throw new Error('dsh-current-title: aiServices 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, scope.signal])\n const session = this.options.sessions?.get(request.session.id)\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 scope,\n config: this.config,\n sessionId: request.session.id,\n messages: messages.length > 0 ? messages : [...request.messages],\n localePreference: this.options.localePreference?.(),\n signal: combined,\n isCurrent: () => this.generation === generation && scope.active && 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 (!isTitleLocaleMode(body.locale) || typeof body.expectedRevision !== 'number') {\n return { ok: false, error: { code: 'bad-request', message: '标题语言设置无效。' } }\n }\n try {\n return { ok: true, value: await service.updateLocale(body.locale, body.expectedRevision) }\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 { AiServices } from '@klarkxy/dsh-ai-services/contracts'\nimport { registerHostRpc, type HostRpcContext } from '@klarkxy/dsh-ai-services/host-rpc'\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', 'aiServices', 'sessions', 'loader', 'storageDomain', 'connection', 'webServer'] 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 aiServices: AiServices\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 ai: host.aiServices,\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}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klarkxy/dsh-current-title",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Update DeepSeek Harness session titles from the latest human task while preserving manual names.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
]
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@deepseek-ai/dsh-storage-domain": "0.1.7-
|
|
64
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2",
|
|
65
65
|
"zod": "^4.1.5",
|
|
66
|
-
"@klarkxy/dsh-ai-services": "0.1.
|
|
66
|
+
"@klarkxy/dsh-ai-services": "0.1.3"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
69
|
+
"@deepseek-ai/cordis": "^4.0.4"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
72
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
73
73
|
"react": "^18.2.0",
|
|
74
74
|
"@types/react": "18.3.31"
|
|
75
75
|
},
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"registry": "https://registry.npmjs.org/"
|
|
96
96
|
},
|
|
97
97
|
"dshRelease": {
|
|
98
|
-
"contentHash": "sha256-
|
|
98
|
+
"contentHash": "sha256-846101af786aa8c02ab3d0e8cebc8224d2e45997f90e3ac7e0bbbbd63e12ef83"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"build": "tsdown && node ../../scripts/wrap-client.mjs @klarkxy/dsh-current-title",
|