@steerable/agent-shell-web 0.6.70 → 0.6.71
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/package.json +4 -4
- package/src/lib/host-bridge.ts +16 -12
- package/src/lib/host-paste.ts +14 -15
- package/src/lib/tauri-bridge.ts +8 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steerable/agent-shell-web",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.71",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Steerable framework — product-neutral renderer SPA source for @steerable/agent-shell (React + Vite). Consumed by product web entry points via the `@/` alias (anchored at this package's src/) and the createProductViteConfig factory. Published as a source package (src/), plus the compiled vite.base config factory (vite.base.js + .d.ts) for Node-side config loading.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"react-router-dom": "^6.30.0",
|
|
46
46
|
"rehype-raw": "^7.0.0",
|
|
47
47
|
"remark-gfm": "^4.0.1",
|
|
48
|
-
"@steerable/agent-protocol": "0.6.
|
|
49
|
-
"@steerable/agent-ui": "0.6.
|
|
48
|
+
"@steerable/agent-protocol": "0.6.71",
|
|
49
|
+
"@steerable/agent-ui": "0.6.71"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@tailwindcss/vite": "^4.3.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"typescript": "^5.8.3",
|
|
60
60
|
"vite": "^5.4.21",
|
|
61
61
|
"vitest": "^3.2.4",
|
|
62
|
-
"@steerable/pack-sdk": "0.6.
|
|
62
|
+
"@steerable/pack-sdk": "0.6.71"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"gen": "echo agent-shell-web",
|
package/src/lib/host-bridge.ts
CHANGED
|
@@ -129,6 +129,18 @@ export interface PythonRunnerSnapshot {
|
|
|
129
129
|
restartRequired: boolean;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
export interface HostClipboardFile {
|
|
133
|
+
name: string;
|
|
134
|
+
path?: string;
|
|
135
|
+
dataBase64?: string;
|
|
136
|
+
mime?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface HostClipboard {
|
|
140
|
+
text: string;
|
|
141
|
+
files: HostClipboardFile[];
|
|
142
|
+
}
|
|
143
|
+
|
|
132
144
|
export interface HostBridge {
|
|
133
145
|
runtime: 'local';
|
|
134
146
|
platform: NodeJS.Platform;
|
|
@@ -197,25 +209,17 @@ export interface HostBridge {
|
|
|
197
209
|
offMenuOpenTerminal?: () => void;
|
|
198
210
|
/**
|
|
199
211
|
* App menu IPC — `Cmd+V` / 编辑 → 粘贴 fires `menu:paste`.
|
|
200
|
-
* WKWebView does not expose that pasteboard to the page, so the
|
|
201
|
-
*
|
|
212
|
+
* WKWebView does not expose that pasteboard to the page, so the host reads
|
|
213
|
+
* it before emitting the event.
|
|
202
214
|
*/
|
|
203
|
-
onMenuPaste?: (callback: () => void) => void;
|
|
215
|
+
onMenuPaste?: (callback: (clipboard: HostClipboard) => void) => void;
|
|
204
216
|
offMenuPaste?: () => void;
|
|
205
217
|
/**
|
|
206
218
|
* OS pasteboard. `files` are copied paths or a screenshot PNG.
|
|
207
219
|
* Text is empty when the pasteboard holds files, so the path is not
|
|
208
220
|
* inserted into the composer as well.
|
|
209
221
|
*/
|
|
210
|
-
readClipboard?: () => Promise<
|
|
211
|
-
text: string;
|
|
212
|
-
files: Array<{
|
|
213
|
-
name: string;
|
|
214
|
-
path?: string;
|
|
215
|
-
dataBase64?: string;
|
|
216
|
-
mime?: string;
|
|
217
|
-
}>;
|
|
218
|
-
}>;
|
|
222
|
+
readClipboard?: () => Promise<HostClipboard>;
|
|
219
223
|
/** Plain text from the OS pasteboard. Empty when the clipboard has no text. */
|
|
220
224
|
readClipboardText?: () => Promise<string>;
|
|
221
225
|
/**
|
package/src/lib/host-paste.ts
CHANGED
|
@@ -4,18 +4,13 @@
|
|
|
4
4
|
* and writes it into the focused field.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
7
|
+
import {
|
|
8
|
+
getHostBridge,
|
|
9
|
+
type HostClipboard,
|
|
10
|
+
type HostClipboardFile,
|
|
11
|
+
} from './host-bridge';
|
|
13
12
|
|
|
14
|
-
export
|
|
15
|
-
text: string;
|
|
16
|
-
files: HostClipboardFile[];
|
|
17
|
-
}
|
|
18
|
-
import { getHostBridge } from './host-bridge';
|
|
13
|
+
export type { HostClipboardFile } from './host-bridge';
|
|
19
14
|
|
|
20
15
|
let pending = false;
|
|
21
16
|
let lastEditable: HTMLElement | null = null;
|
|
@@ -44,8 +39,8 @@ export function installHostPaste(): void {
|
|
|
44
39
|
if (isEditable(target)) lastEditable = target;
|
|
45
40
|
});
|
|
46
41
|
const bridge = getHostBridge();
|
|
47
|
-
bridge?.onMenuPaste?.(() => {
|
|
48
|
-
|
|
42
|
+
bridge?.onMenuPaste?.((clipboard) => {
|
|
43
|
+
insertHostClipboard(clipboard);
|
|
49
44
|
});
|
|
50
45
|
}
|
|
51
46
|
|
|
@@ -58,8 +53,7 @@ export function requestHostPaste(target?: HTMLElement | null): void {
|
|
|
58
53
|
pending = true;
|
|
59
54
|
void readHostClipboard(readClipboard, readText)
|
|
60
55
|
.then((clip) => {
|
|
61
|
-
|
|
62
|
-
if (clip.text) insertHostText(clip.text, target ?? null);
|
|
56
|
+
insertHostClipboard(clip, target ?? null);
|
|
63
57
|
})
|
|
64
58
|
.catch((error: unknown) => {
|
|
65
59
|
console.warn('[host-paste] clipboard read failed', error);
|
|
@@ -100,6 +94,11 @@ export function hostClipboardAvailable(): boolean {
|
|
|
100
94
|
);
|
|
101
95
|
}
|
|
102
96
|
|
|
97
|
+
function insertHostClipboard(clipboard: HostClipboard, target: HTMLElement | null = null): void {
|
|
98
|
+
if (clipboard.files.length > 0) insertHostFiles(clipboard.files, target);
|
|
99
|
+
if (clipboard.text) insertHostText(clipboard.text, target);
|
|
100
|
+
}
|
|
101
|
+
|
|
103
102
|
function isEditable(target: EventTarget | null): target is HTMLElement {
|
|
104
103
|
if (isTerminalInput(target) || !(target instanceof HTMLElement)) return false;
|
|
105
104
|
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) return true;
|
package/src/lib/tauri-bridge.ts
CHANGED
|
@@ -10,22 +10,23 @@ import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
|
|
10
10
|
import html2canvas from 'html2canvas';
|
|
11
11
|
import type {
|
|
12
12
|
AppReleaseSnapshot,
|
|
13
|
+
HostClipboard,
|
|
13
14
|
HostBridge,
|
|
14
15
|
PythonRunnerSnapshot,
|
|
15
16
|
} from './host-bridge';
|
|
16
17
|
import { createHttpBridge } from './http-bridge';
|
|
17
18
|
|
|
18
|
-
type
|
|
19
|
+
type EventCallback<T> = (payload: T) => void;
|
|
19
20
|
|
|
20
|
-
function createMenuSubscription(event: string): {
|
|
21
|
-
on(callback:
|
|
21
|
+
function createMenuSubscription<T = void>(event: string): {
|
|
22
|
+
on(callback: EventCallback<T>): void;
|
|
22
23
|
off(): void;
|
|
23
24
|
} {
|
|
24
|
-
const subscriptions = new Map<
|
|
25
|
+
const subscriptions = new Map<EventCallback<T>, Promise<UnlistenFn>>();
|
|
25
26
|
return {
|
|
26
27
|
on(callback) {
|
|
27
28
|
if (subscriptions.has(callback)) return;
|
|
28
|
-
const subscription = listen(event, () => callback());
|
|
29
|
+
const subscription = listen<T>(event, ({ payload }) => callback(payload));
|
|
29
30
|
subscriptions.set(callback, subscription);
|
|
30
31
|
},
|
|
31
32
|
off() {
|
|
@@ -42,7 +43,7 @@ export function createTauriBridge(): HostBridge {
|
|
|
42
43
|
const bridge = createHttpBridge();
|
|
43
44
|
const newChatMenu = createMenuSubscription('menu:new-chat');
|
|
44
45
|
const terminalMenu = createMenuSubscription('menu:open-terminal');
|
|
45
|
-
const pasteMenu = createMenuSubscription('menu:paste');
|
|
46
|
+
const pasteMenu = createMenuSubscription<HostClipboard>('menu:paste');
|
|
46
47
|
|
|
47
48
|
return {
|
|
48
49
|
...bridge,
|
|
@@ -92,11 +93,7 @@ export function createTauriBridge(): HostBridge {
|
|
|
92
93
|
offMenuOpenTerminal: terminalMenu.off,
|
|
93
94
|
onMenuPaste: pasteMenu.on,
|
|
94
95
|
offMenuPaste: pasteMenu.off,
|
|
95
|
-
readClipboard: () =>
|
|
96
|
-
invoke<{
|
|
97
|
-
text: string;
|
|
98
|
-
files: Array<{ name: string; path?: string; dataBase64?: string; mime?: string }>;
|
|
99
|
-
}>('host_read_clipboard'),
|
|
96
|
+
readClipboard: () => invoke<HostClipboard>('host_read_clipboard'),
|
|
100
97
|
readClipboardText: () => invoke<string>('host_read_clipboard_text'),
|
|
101
98
|
app: {
|
|
102
99
|
snapshot: () => invoke<AppReleaseSnapshot>('app_release_snapshot'),
|