@aipanel/dsh-client 1.1.69

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/lib/client.js ADDED
@@ -0,0 +1,188 @@
1
+ window.__ModuleLoader__.load({ id: '@aipanel/dsh-client', factory: (require) => {
2
+ var module = { exports: {} };
3
+ var exports = module.exports;
4
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
5
+ "use strict";
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+
24
+ // dsh-client/src/client/index.ts
25
+ var index_exports = {};
26
+ __export(index_exports, {
27
+ INSERT_ELEMENT_EVENT: () => INSERT_ELEMENT_EVENT,
28
+ SESSION_READY_EVENT: () => SESSION_READY_EVENT,
29
+ apply: () => apply
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+ var SELECTION_STORAGE_KEY = "dsh.bridge.selection";
33
+ var SESSION_READY_EVENT = "aipanel:session-ready";
34
+ var INSERT_ELEMENT_EVENT = "aipanel:insert-element";
35
+ var SESSION_SETTLE_MS = 400;
36
+ function elementLabel(e) {
37
+ if (e.description) return e.description;
38
+ const text = e.innerText?.trim();
39
+ if (text) return text.slice(0, 40);
40
+ return "\u5143\u7D20";
41
+ }
42
+ function elementContextRef(e) {
43
+ return JSON.stringify(e);
44
+ }
45
+ function serializeElement(ref) {
46
+ try {
47
+ const e = JSON.parse(ref);
48
+ if (!e || typeof e !== "object") throw new Error("not an element payload");
49
+ const selector = (e.description || "element").replace(
50
+ /[\\/]/g,
51
+ (m) => m === "/" ? "\uFF0F" : "\uFF3C"
52
+ );
53
+ const text = e.innerText?.trim();
54
+ const textPreview = text ? (text.length > 5 ? text.slice(0, 5) + "..." : text).replace(
55
+ /[\\/]/g,
56
+ (m) => m === "/" ? "\uFF0F" : "\uFF3C"
57
+ ) : "";
58
+ return `@\u9009\u4E2D\u5143\u7D20:${selector}${textPreview ? `(${textPreview})` : ""}`;
59
+ } catch {
60
+ return `@${ref}`;
61
+ }
62
+ }
63
+ function toReference(e) {
64
+ const label = elementLabel(e);
65
+ return {
66
+ source: "aipanel",
67
+ ref: elementContextRef(e),
68
+ label,
69
+ appearance: "file",
70
+ clipboardText: label
71
+ };
72
+ }
73
+ function toCandidate(e) {
74
+ return {
75
+ name: elementLabel(e),
76
+ description: e.description || e.innerText || void 0,
77
+ value: elementContextRef(e)
78
+ };
79
+ }
80
+ function readSelectionCandidates() {
81
+ try {
82
+ const raw = localStorage.getItem(SELECTION_STORAGE_KEY);
83
+ if (!raw) return [];
84
+ const elements = JSON.parse(raw);
85
+ if (!Array.isArray(elements)) return [];
86
+ return elements.filter((e) => !!e && typeof e === "object").slice(0, 20).map(toCandidate);
87
+ } catch {
88
+ return [];
89
+ }
90
+ }
91
+ function apply(ctx) {
92
+ const inputTriggers = ctx.get("inputTriggers");
93
+ if (!inputTriggers) return;
94
+ const source = {
95
+ trigger: "@",
96
+ name: "aipanel",
97
+ order: 300,
98
+ showGroupTitle: false,
99
+ // 候选 = 最近选中元素(bridge 写入),按输入查询过滤
100
+ candidates: async (_session, req) => {
101
+ const all = readSelectionCandidates();
102
+ const query = req.query.trim().toLowerCase();
103
+ if (!query) return all;
104
+ return all.filter(
105
+ (c) => c.name.toLowerCase().includes(query) || (c.description ?? "").toLowerCase().includes(query)
106
+ );
107
+ },
108
+ // 选定 → 铸造 file 引用:ref/label 分离(label 短,ref 携完整上下文)
109
+ onPick: (pick) => ({
110
+ insert: {
111
+ source: "aipanel",
112
+ ref: pick.candidate.value ?? pick.candidate.name,
113
+ label: pick.candidate.name,
114
+ appearance: "file",
115
+ clipboardText: pick.candidate.name
116
+ }
117
+ }),
118
+ // 模型投影
119
+ codec: {
120
+ clipboardText: (ref) => ref,
121
+ serialize: async (ref) => serializeElement(ref)
122
+ }
123
+ };
124
+ ctx.effect(() => inputTriggers.registerSource(source), "aipanel: @ source");
125
+ const sessions = ctx.get("sessions");
126
+ if (sessions && sessions.list) {
127
+ let lastCurrent;
128
+ let settleTimer = null;
129
+ const notifyBridge = (sessionId) => {
130
+ try {
131
+ window.dispatchEvent(new CustomEvent(SESSION_READY_EVENT, { detail: { sessionId } }));
132
+ } catch {
133
+ }
134
+ };
135
+ const probe = () => {
136
+ const snapshot = sessions.list.getSnapshot();
137
+ const current = snapshot?.current;
138
+ if (!current) {
139
+ lastCurrent = void 0;
140
+ if (settleTimer) {
141
+ clearTimeout(settleTimer);
142
+ settleTimer = null;
143
+ }
144
+ return;
145
+ }
146
+ if (current === lastCurrent) return;
147
+ lastCurrent = current;
148
+ if (settleTimer) clearTimeout(settleTimer);
149
+ settleTimer = setTimeout(() => {
150
+ settleTimer = null;
151
+ if (sessions.list.getSnapshot()?.current === current) {
152
+ notifyBridge(current);
153
+ }
154
+ }, SESSION_SETTLE_MS);
155
+ };
156
+ probe();
157
+ const dispose = sessions.list.subscribe(probe);
158
+ ctx.effect(() => dispose, "aipanel: session-ready watcher");
159
+ }
160
+ const conversation = ctx.get("conversation");
161
+ const insertElementListener = (event) => {
162
+ const detail = event.detail;
163
+ const element = detail?.element;
164
+ if (!element) return;
165
+ const current = sessions?.list?.getSnapshot()?.current;
166
+ if (!current) return;
167
+ try {
168
+ const actx = sessions.scope?.(current);
169
+ const input = conversation?.input?.for?.(actx);
170
+ if (!input || typeof input.insertReference !== "function") return;
171
+ const snapshot = input.state?.getSnapshot?.();
172
+ if (!snapshot) return;
173
+ const at = snapshot.draft.length;
174
+ input.insertReference(toReference(element), {
175
+ start: at,
176
+ end: at,
177
+ draftRev: snapshot.draftRev
178
+ });
179
+ } catch {
180
+ }
181
+ };
182
+ window.addEventListener(INSERT_ELEMENT_EVENT, insertElementListener);
183
+ ctx.effect(
184
+ () => () => window.removeEventListener(INSERT_ELEMENT_EVENT, insertElementListener),
185
+ "aipanel: insert-element listener"
186
+ );
187
+ }
188
+ return module.exports; } });
package/lib/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export const name = "aipanel-client";
2
+ export function apply() {}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@aipanel/dsh-client",
3
+ "version": "1.1.69",
4
+ "type": "module",
5
+ "description": "AIPanel 浏览器侧插件(dsh web Web Client):注册 @aipanel 文件引用 source,选中元素以 file chip 高亮插入并可供模型解析。",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "files": [
11
+ "lib"
12
+ ],
13
+ "dependencies": {},
14
+ "devDependencies": {
15
+ "@deepseek-ai/cordis": "^4.0.1",
16
+ "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.1-rc.2",
17
+ "esbuild": "^0.25.0"
18
+ },
19
+ "exports": {
20
+ ".": "./lib/index.js",
21
+ "./client": "./lib/client.js",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "dsh": {
25
+ "client": {
26
+ "platform": "web",
27
+ "inject": []
28
+ }
29
+ },
30
+ "scripts": {
31
+ "build": "node scripts/build.mjs",
32
+ "typecheck": "tsc -p tsconfig.json"
33
+ }
34
+ }