@aiwuk/autocomplete 1.0.2 → 1.0.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 +2 -2
- package/client.js +51 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Part of [AIWUK Team for DSH](https://github.com/walke2019/dsh-capability-team) (
|
|
|
6
6
|
dsh plugin add @aiwuk/autocomplete
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Requires DSH >= 0.2.2-rc.1 (below 0.3.0) and Node.js >=
|
|
9
|
+
Requires DSH >= 0.2.2-rc.1 (below 0.3.0) and Node.js >= 24.9.
|
|
10
10
|
|
|
11
11
|
Composer autocomplete for DSH Web (`@aiwuk/autocomplete`, patch id `autocomplete`). The plugin name, description, settings and on-screen text follow the DSH language (Chinese / English).
|
|
12
12
|
|
|
@@ -86,4 +86,4 @@ Change them from **Settings → General** or the plugin's page under **Plugins**
|
|
|
86
86
|
|
|
87
87
|
## Development
|
|
88
88
|
|
|
89
|
-
`client.js` is generated from `client/*.js
|
|
89
|
+
`client.js` is generated from `client/*.js` and is not tracked in git. It is built by `pretest`, by `prepack` (so `npm pack` and `npm publish` build it automatically) and by the CI "Build generated files" step. Edit the fragments, then run `npm run build:autocomplete` from the repository root. Tests live in `tests/autocomplete/`.
|
package/client.js
CHANGED
|
@@ -85,7 +85,11 @@ window.__ModuleLoader__.load({
|
|
|
85
85
|
let rect = range.getBoundingClientRect();
|
|
86
86
|
if (!rect.width && !rect.height) rect = range.getClientRects()[0] ?? rect;
|
|
87
87
|
if ((!rect.width && !rect.height) || (!rect.top && !rect.left)) {
|
|
88
|
-
|
|
88
|
+
let node = range.startContainer, offset = range.startOffset;
|
|
89
|
+
if (node?.nodeType === Node.ELEMENT_NODE && offset > 0) {
|
|
90
|
+
node = node.childNodes[offset - 1] || node;
|
|
91
|
+
offset = node.nodeType === Node.TEXT_NODE ? node.textContent?.length ?? 0 : node.childNodes?.length ?? 0;
|
|
92
|
+
}
|
|
89
93
|
if (node?.nodeType === Node.TEXT_NODE && offset > 0) {
|
|
90
94
|
const probe = document.createRange();
|
|
91
95
|
probe.setStart(node, offset - 1); probe.setEnd(node, offset);
|
|
@@ -96,17 +100,17 @@ window.__ModuleLoader__.load({
|
|
|
96
100
|
return !rect.width && !rect.height ? null : { left: rect.left, top: rect.top, height: rect.height };
|
|
97
101
|
}
|
|
98
102
|
/** The caret position, only when it sits at the end of the draft (continuations append, never splice). */
|
|
99
|
-
function caretAtEnd(editor,
|
|
103
|
+
function caretAtEnd(editor, _draft) {
|
|
100
104
|
const selection = window.getSelection();
|
|
101
105
|
if (!selection?.rangeCount) return null;
|
|
102
106
|
const range = selection.getRangeAt(0);
|
|
103
107
|
if (!range.collapsed || !editor.contains(range.startContainer)) return null;
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return
|
|
108
|
+
const suffix = document.createRange();
|
|
109
|
+
suffix.selectNodeContents(editor);
|
|
110
|
+
suffix.setStart(range.startContainer, range.startOffset);
|
|
111
|
+
if (suffix.toString().trim() !== '') return null;
|
|
112
|
+
if (!editor.textContent?.trim()) return null;
|
|
113
|
+
return caretRect(range);
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
const zh = {
|
|
@@ -198,7 +202,11 @@ window.__ModuleLoader__.load({
|
|
|
198
202
|
function candidateOf(ghost, draft) {
|
|
199
203
|
const raw = ghost.items.length ? ghost.items[Math.min(ghost.index, ghost.items.length - 1)] ?? ''
|
|
200
204
|
: ghost.stream.trim().split(/\r?\n/)[0]?.replace(/^[-*0-9.)\s]+/, '') ?? '';
|
|
201
|
-
|
|
205
|
+
if (ghost.mode !== 'continue') return raw;
|
|
206
|
+
if (raw.startsWith(draft)) return raw.slice(draft.length);
|
|
207
|
+
const lowerRaw = raw.toLowerCase(), lowerDraft = draft.toLowerCase();
|
|
208
|
+
if (lowerRaw.startsWith(lowerDraft)) return raw.slice(draft.length);
|
|
209
|
+
return raw;
|
|
202
210
|
}
|
|
203
211
|
|
|
204
212
|
/** Insert into the shell-owned draft; never submits. Falls back to the editor's own insert on older hosts. */
|
|
@@ -266,8 +274,38 @@ window.__ModuleLoader__.load({
|
|
|
266
274
|
};
|
|
267
275
|
measure();
|
|
268
276
|
window.addEventListener('resize', measure);
|
|
269
|
-
|
|
277
|
+
const scrollEl = anchorRef.current?.closest('[data-composer-card]')?.querySelector('[data-input-scroll]');
|
|
278
|
+
scrollEl?.addEventListener('scroll', measure, { passive: true });
|
|
279
|
+
return () => {
|
|
280
|
+
window.removeEventListener('resize', measure);
|
|
281
|
+
scrollEl?.removeEventListener('scroll', measure);
|
|
282
|
+
};
|
|
270
283
|
}, [ghost.mode, draft, sessionId, current]);
|
|
284
|
+
React.useLayoutEffect(() => {
|
|
285
|
+
if (typeof document === 'undefined') return undefined;
|
|
286
|
+
const ID = 'aiwuk-autocomplete-ghost-style';
|
|
287
|
+
if (!document.getElementById(ID)) {
|
|
288
|
+
const tag = document.createElement('style');
|
|
289
|
+
tag.id = ID;
|
|
290
|
+
tag.textContent = '[data-aiwuk-ghost-next] [data-composer-placeholder]{visibility:hidden !important;}';
|
|
291
|
+
(document.head || document.documentElement).appendChild(tag);
|
|
292
|
+
}
|
|
293
|
+
const card = anchorRef.current?.closest('[data-composer-card]') || anchorRef.current?.parentElement;
|
|
294
|
+
if (!card) return undefined;
|
|
295
|
+
if (visible && ghost.mode === 'next') card.setAttribute('data-aiwuk-ghost-next', '');
|
|
296
|
+
else card.removeAttribute('data-aiwuk-ghost-next');
|
|
297
|
+
return () => { card.removeAttribute('data-aiwuk-ghost-next'); };
|
|
298
|
+
}, [visible, ghost.mode]);
|
|
299
|
+
React.useEffect(() => {
|
|
300
|
+
if (!visible) return undefined;
|
|
301
|
+
const onSelectionChange = () => {
|
|
302
|
+
const found = composerNear(anchorRef.current);
|
|
303
|
+
if (!found) return;
|
|
304
|
+
if (ghost.mode === 'continue' && !caretAtEnd(found.editor, draft)) setBox(null);
|
|
305
|
+
};
|
|
306
|
+
document.addEventListener('selectionchange', onSelectionChange);
|
|
307
|
+
return () => document.removeEventListener('selectionchange', onSelectionChange);
|
|
308
|
+
}, [visible, ghost.mode, draft]);
|
|
271
309
|
React.useEffect(() => {
|
|
272
310
|
if (!visible) return undefined;
|
|
273
311
|
const onKeyDown = event => {
|
|
@@ -298,8 +336,8 @@ window.__ModuleLoader__.load({
|
|
|
298
336
|
return h(React.Fragment, null, anchor,
|
|
299
337
|
h('div', { key: 'ghost', 'data-composer-prediction': ghost.mode, style: { position: 'absolute', top: `${box.top}px`, left: `${box.left}px`,
|
|
300
338
|
maxWidth: box.maxWidth ? `${box.maxWidth}px` : undefined, height: `${box.height}px`, display: 'flex', alignItems: 'center', gap: '6px',
|
|
301
|
-
color: 'var(--dsw-alias-label-tertiary, #888)', pointerEvents: 'none', userSelect: 'none', whiteSpace: '
|
|
302
|
-
h('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis', opacity: 0.85 } }, current),
|
|
339
|
+
color: 'var(--dsw-alias-label-tertiary, #888)', pointerEvents: 'none', userSelect: 'none', whiteSpace: 'pre', overflow: 'hidden', zIndex: 10 } },
|
|
340
|
+
h('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis', opacity: 0.85, whiteSpace: 'pre' } }, current),
|
|
303
341
|
ghost.items.length > 1 ? h('span', { style: tag }, `${ghost.index + 1}/${ghost.items.length}`) : null,
|
|
304
342
|
ghost.active ? null : h('kbd', { style: tag }, 'Tab')));
|
|
305
343
|
}
|
|
@@ -1125,7 +1163,7 @@ window.__ModuleLoader__.load({
|
|
|
1125
1163
|
},
|
|
1126
1164
|
};
|
|
1127
1165
|
// Test-only seam: harnesses may define window.__acTestHook; browsers never do.
|
|
1128
|
-
if (typeof window.__acTestHook === 'function') window.__acTestHook({ ComposerOverlay, GhostOverlay, TouchSuggestionBar, TouchDock, TouchAskButton, touchStore, measureCardInset, AutocompleteSettings, parseSse, isTriggerToken, configOf, candidateOf, ENDPOINT, zh, en });
|
|
1166
|
+
if (typeof window.__acTestHook === 'function') window.__acTestHook({ ComposerOverlay, GhostOverlay, TouchSuggestionBar, TouchDock, TouchAskButton, touchStore, measureCardInset, AutocompleteSettings, parseSse, isTriggerToken, configOf, candidateOf, caretAtEnd, caretRect, ENDPOINT, zh, en });
|
|
1129
1167
|
|
|
1130
1168
|
return plugin;
|
|
1131
1169
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiwuk/autocomplete",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIWUK Autocomplete, composer autocomplete for DeepSeek Harness (DSH) with inline continuation and next-message suggestions accepted with Tab, never sent automatically",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"repository": { "type": "git", "url": "git+https://github.com/walke2019/dsh-capability-team.git", "directory": "packages/autocomplete" },
|
|
10
10
|
"bugs": { "url": "https://github.com/walke2019/dsh-capability-team/issues" },
|
|
11
11
|
"keywords": ["aiwuk", "dsh", "dsh-plugin", "deepseek-harness", "cordis", "autocomplete", "composer", "prediction", "llm"],
|
|
12
|
-
"engines": { "node": ">=
|
|
12
|
+
"engines": { "node": ">=24.9", "dsh": ">=0.2.2-rc.1 <0.3.0" },
|
|
13
13
|
"dependencies": { "@deepseek-ai/schemastery": "~3.18.5" },
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@deepseek-ai/cordis": ">=4.0.1",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"exports": { ".": "./index.js", "./client": "./client.js", "./locale/*.json": "./locale/*.json", "./i18n/*.json": "./i18n/*.json", "./icon": "./icon.svg" },
|
|
25
25
|
"files": ["index.js", "predictor.js", "schema.js", "fleet-defaults.js", "managed-route.js", "client.js", "cordis.patch.yml", "locale/*.json", "i18n/*.json", "icon.svg", "README.md", "LICENSE"],
|
|
26
|
-
"scripts": { "build": "node scripts/build-client.mjs", "test": "node --test ../../tests/autocomplete/*.test.mjs" },
|
|
26
|
+
"scripts": { "build": "node scripts/build-client.mjs", "prepack": "node ../../shared-ui/build.mjs && node scripts/build-client.mjs", "test": "node --test ../../tests/autocomplete/*.test.mjs" },
|
|
27
27
|
"dsh": {
|
|
28
28
|
"bundle": { "patch": "./cordis.patch.yml" },
|
|
29
29
|
"client": {
|