vite-plugin-opencode-assistant 1.0.27 → 1.0.28
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/es/client/App.vue.js +64 -36
- package/es/client/composables/index.d.ts +10 -0
- package/es/client/composables/index.js +22 -0
- package/es/client/composables/useOpencodeSSE.d.ts +64 -0
- package/es/client/composables/useOpencodeSSE.js +29 -0
- package/es/client/composables/useOpencodeSessionSSE.d.ts +66 -0
- package/es/client/composables/useOpencodeSessionSSE.js +168 -0
- package/es/client/composables/useSSE.d.ts +85 -18
- package/es/client/composables/useSSE.js +101 -44
- package/es/client/composables/useServerSSE.d.ts +53 -0
- package/es/client/composables/useServerSSE.js +36 -0
- package/es/client/composables/useServiceStatus.d.ts +0 -2
- package/es/client/composables/useServiceStatus.js +1 -7
- package/es/client/composables/useSessions.d.ts +24 -5
- package/es/client/composables/useSessions.js +16 -2
- package/es/core/proxy-server.js +38 -148
- package/es/index.js +3 -1
- package/lib/client/App.vue.js +63 -35
- package/lib/client/composables/index.d.ts +10 -0
- package/lib/client/composables/index.js +54 -0
- package/lib/client/composables/useOpencodeSSE.d.ts +64 -0
- package/lib/client/composables/useOpencodeSSE.js +52 -0
- package/lib/client/composables/useOpencodeSessionSSE.d.ts +66 -0
- package/lib/client/composables/useOpencodeSessionSSE.js +187 -0
- package/lib/client/composables/useSSE.d.ts +85 -18
- package/lib/client/composables/useSSE.js +100 -43
- package/lib/client/composables/useServerSSE.d.ts +53 -0
- package/lib/client/composables/useServerSSE.js +59 -0
- package/lib/client/composables/useServiceStatus.d.ts +0 -2
- package/lib/client/composables/useServiceStatus.js +1 -7
- package/lib/client/composables/useSessions.d.ts +24 -5
- package/lib/client/composables/useSessions.js +16 -2
- package/lib/client.js +2823 -2566
- package/lib/core/proxy-server.js +38 -148
- package/lib/index.js +3 -1
- package/lib/style.css +1 -1
- package/package.json +4 -4
|
@@ -1,59 +1,116 @@
|
|
|
1
|
-
import { ref, onUnmounted } from "vue";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
function useSSE(
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { ref, computed, onUnmounted } from "vue";
|
|
2
|
+
const DEFAULT_MAX_RETRIES = 10;
|
|
3
|
+
const DEFAULT_RETRY_DELAY = 1e3;
|
|
4
|
+
function useSSE(options) {
|
|
5
|
+
const {
|
|
6
|
+
endpoint,
|
|
7
|
+
autoConnect = true,
|
|
8
|
+
enabled,
|
|
9
|
+
maxRetries = DEFAULT_MAX_RETRIES,
|
|
10
|
+
retryDelay = DEFAULT_RETRY_DELAY,
|
|
11
|
+
onConnected,
|
|
12
|
+
onDisconnected,
|
|
13
|
+
onError,
|
|
14
|
+
onMessage
|
|
15
|
+
} = options;
|
|
16
|
+
const connection = ref(null);
|
|
17
|
+
const status = ref("idle");
|
|
18
|
+
const retryCount = ref(0);
|
|
19
|
+
function handleMessage(event) {
|
|
9
20
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const data = JSON.parse(event.data);
|
|
22
|
+
onMessage == null ? void 0 : onMessage(data);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
onMessage == null ? void 0 : onMessage(event.data);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function connect() {
|
|
28
|
+
if (connection.value || status.value === "connecting") {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if ((enabled == null ? void 0 : enabled.value) === false) {
|
|
32
|
+
status.value = "idle";
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
status.value = "connecting";
|
|
36
|
+
retryCount.value = 0;
|
|
37
|
+
try {
|
|
38
|
+
connection.value = new EventSource(endpoint);
|
|
39
|
+
connection.value.onopen = () => {
|
|
40
|
+
status.value = "connected";
|
|
41
|
+
retryCount.value = 0;
|
|
42
|
+
onConnected == null ? void 0 : onConnected();
|
|
26
43
|
};
|
|
27
|
-
|
|
44
|
+
connection.value.onmessage = handleMessage;
|
|
45
|
+
connection.value.onerror = () => {
|
|
28
46
|
var _a;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
47
|
+
const wasConnected = status.value === "connected";
|
|
48
|
+
status.value = "error";
|
|
49
|
+
(_a = connection.value) == null ? void 0 : _a.close();
|
|
50
|
+
connection.value = null;
|
|
51
|
+
const error = new Error(`SSE connection error: ${endpoint}`);
|
|
52
|
+
onError == null ? void 0 : onError(error);
|
|
53
|
+
if (retryCount.value < maxRetries) {
|
|
54
|
+
retryCount.value++;
|
|
55
|
+
const delay = retryDelay * retryCount.value;
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
if ((enabled == null ? void 0 : enabled.value) !== false && !connection.value) {
|
|
58
|
+
connect();
|
|
59
|
+
}
|
|
60
|
+
}, delay);
|
|
61
|
+
} else if (wasConnected) {
|
|
62
|
+
onDisconnected == null ? void 0 : onDisconnected();
|
|
34
63
|
}
|
|
35
64
|
};
|
|
36
65
|
} catch (e) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
66
|
+
status.value = "error";
|
|
67
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
68
|
+
onError == null ? void 0 : onError(error);
|
|
69
|
+
if (retryCount.value < maxRetries) {
|
|
70
|
+
retryCount.value++;
|
|
71
|
+
const delay = retryDelay * retryCount.value;
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
if (!connection.value) {
|
|
74
|
+
connect();
|
|
75
|
+
}
|
|
76
|
+
}, delay);
|
|
41
77
|
}
|
|
42
78
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
79
|
+
}
|
|
80
|
+
function disconnect() {
|
|
81
|
+
if (connection.value) {
|
|
82
|
+
connection.value.close();
|
|
83
|
+
connection.value = null;
|
|
84
|
+
status.value = "disconnected";
|
|
85
|
+
retryCount.value = 0;
|
|
86
|
+
onDisconnected == null ? void 0 : onDisconnected();
|
|
48
87
|
}
|
|
49
|
-
}
|
|
88
|
+
}
|
|
89
|
+
function reconnect() {
|
|
90
|
+
disconnect();
|
|
91
|
+
connect();
|
|
92
|
+
}
|
|
93
|
+
function resetRetryCount() {
|
|
94
|
+
retryCount.value = 0;
|
|
95
|
+
}
|
|
96
|
+
if (autoConnect && (enabled == null ? void 0 : enabled.value) !== false) {
|
|
97
|
+
connect();
|
|
98
|
+
}
|
|
50
99
|
onUnmounted(() => {
|
|
51
|
-
|
|
100
|
+
disconnect();
|
|
52
101
|
});
|
|
53
102
|
return {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
103
|
+
// 状态
|
|
104
|
+
connection,
|
|
105
|
+
status,
|
|
106
|
+
retryCount,
|
|
107
|
+
isConnected: computed(() => status.value === "connected"),
|
|
108
|
+
isConnecting: computed(() => status.value === "connecting"),
|
|
109
|
+
// 方法
|
|
110
|
+
connect,
|
|
111
|
+
disconnect,
|
|
112
|
+
reconnect,
|
|
113
|
+
resetRetryCount
|
|
57
114
|
};
|
|
58
115
|
}
|
|
59
116
|
export {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
|
|
2
|
+
/**
|
|
3
|
+
* Server SSE 状态同步数据
|
|
4
|
+
*/
|
|
5
|
+
export interface ServerSSEStatusSyncData {
|
|
6
|
+
type: "STATUS_SYNC";
|
|
7
|
+
isStarted?: boolean;
|
|
8
|
+
task: ServiceStartupTask;
|
|
9
|
+
errorType?: string;
|
|
10
|
+
errorMessage?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Server SSE 任务更新数据
|
|
14
|
+
*/
|
|
15
|
+
export interface ServerSSETaskUpdateData {
|
|
16
|
+
type: "TASK_UPDATE";
|
|
17
|
+
task: ServiceStartupTask;
|
|
18
|
+
errorType?: string;
|
|
19
|
+
errorMessage?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Server SSE 消息类型
|
|
23
|
+
*/
|
|
24
|
+
export type ServerSSEMessage = {
|
|
25
|
+
type: "CONNECTED";
|
|
26
|
+
} | ServerSSEStatusSyncData | ServerSSETaskUpdateData | {
|
|
27
|
+
type: "CLEAR_ELEMENTS";
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Server SSE 配置选项
|
|
31
|
+
*/
|
|
32
|
+
export interface ServerSSEOptions {
|
|
33
|
+
/** 状态同步回调 */
|
|
34
|
+
onStatusSync?: (data: ServerSSEStatusSyncData) => void;
|
|
35
|
+
/** 任务更新回调 */
|
|
36
|
+
onTaskUpdate?: (data: ServerSSETaskUpdateData) => void;
|
|
37
|
+
/** 清除元素回调 */
|
|
38
|
+
onClearElements?: () => void;
|
|
39
|
+
/** 连接成功回调 */
|
|
40
|
+
onConnected?: () => void;
|
|
41
|
+
/** 是否启用 */
|
|
42
|
+
enabled?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 监听 Vite Server SSE 事件
|
|
46
|
+
* 端点: /__opencode_events__
|
|
47
|
+
*/
|
|
48
|
+
export declare function useServerSSE(options?: ServerSSEOptions): {
|
|
49
|
+
status: import("vue").Ref<import("./useSSE").SSEConnectionStatus, import("./useSSE").SSEConnectionStatus>;
|
|
50
|
+
isConnected: import("vue").ComputedRef<boolean>;
|
|
51
|
+
connect: () => void;
|
|
52
|
+
disconnect: () => void;
|
|
53
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useSSE } from "./useSSE";
|
|
2
|
+
function useServerSSE(options = {}) {
|
|
3
|
+
const { onStatusSync, onTaskUpdate, onClearElements, onConnected } = options;
|
|
4
|
+
const { status, isConnected, connect, disconnect } = useSSE({
|
|
5
|
+
endpoint: "/__opencode_events__",
|
|
6
|
+
autoConnect: false,
|
|
7
|
+
onMessage: (data) => {
|
|
8
|
+
const message = data;
|
|
9
|
+
switch (message.type) {
|
|
10
|
+
case "CONNECTED":
|
|
11
|
+
onConnected == null ? void 0 : onConnected();
|
|
12
|
+
break;
|
|
13
|
+
case "STATUS_SYNC":
|
|
14
|
+
onStatusSync == null ? void 0 : onStatusSync(message);
|
|
15
|
+
break;
|
|
16
|
+
case "TASK_UPDATE":
|
|
17
|
+
onTaskUpdate == null ? void 0 : onTaskUpdate(message);
|
|
18
|
+
break;
|
|
19
|
+
case "CLEAR_ELEMENTS":
|
|
20
|
+
onClearElements == null ? void 0 : onClearElements();
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
// 状态
|
|
27
|
+
status,
|
|
28
|
+
isConnected,
|
|
29
|
+
// 方法
|
|
30
|
+
connect,
|
|
31
|
+
disconnect
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
useServerSSE
|
|
36
|
+
};
|
|
@@ -5,9 +5,7 @@ export declare function useServiceStatus(): {
|
|
|
5
5
|
chromeMcpFailed: import("vue").Ref<boolean, boolean>;
|
|
6
6
|
chromeMcpErrorType: import("vue").Ref<string | undefined, string | undefined>;
|
|
7
7
|
chromeMcpErrorMessage: import("vue").Ref<string | undefined, string | undefined>;
|
|
8
|
-
thinking: import("vue").Ref<boolean, boolean>;
|
|
9
8
|
loadingText: import("vue").ComputedRef<string>;
|
|
10
9
|
updateStatusFromTask: (task: ServiceStartupTask | "", errorType?: string, errorMessage?: string) => void;
|
|
11
10
|
setStarting: () => void;
|
|
12
|
-
setThinking: (value: boolean) => void;
|
|
13
11
|
};
|
|
@@ -6,7 +6,6 @@ function useServiceStatus() {
|
|
|
6
6
|
const chromeMcpFailed = ref(false);
|
|
7
7
|
const chromeMcpErrorType = ref(void 0);
|
|
8
8
|
const chromeMcpErrorMessage = ref(void 0);
|
|
9
|
-
const thinking = ref(false);
|
|
10
9
|
const loadingText = computed(() => {
|
|
11
10
|
if (!currentTask.value) return "\u52A0\u8F7D\u4E2D...";
|
|
12
11
|
return SERVICE_STARTUP_TASKS[currentTask.value] || "\u52A0\u8F7D\u4E2D...";
|
|
@@ -32,20 +31,15 @@ function useServiceStatus() {
|
|
|
32
31
|
const setStarting = () => {
|
|
33
32
|
serviceStatus.value = "starting";
|
|
34
33
|
};
|
|
35
|
-
const setThinking = (value) => {
|
|
36
|
-
thinking.value = value;
|
|
37
|
-
};
|
|
38
34
|
return {
|
|
39
35
|
currentTask,
|
|
40
36
|
serviceStatus,
|
|
41
37
|
chromeMcpFailed,
|
|
42
38
|
chromeMcpErrorType,
|
|
43
39
|
chromeMcpErrorMessage,
|
|
44
|
-
thinking,
|
|
45
40
|
loadingText,
|
|
46
41
|
updateStatusFromTask,
|
|
47
|
-
setStarting
|
|
48
|
-
setThinking
|
|
42
|
+
setStarting
|
|
49
43
|
};
|
|
50
44
|
}
|
|
51
45
|
export {
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
1
2
|
import type { OpenCodeWidgetSession } from "@vite-plugin-opencode-assistant/shared";
|
|
2
|
-
export
|
|
3
|
-
|
|
3
|
+
export interface UseSessionsOptions {
|
|
4
|
+
showNotification: (msg: string) => void;
|
|
5
|
+
/** Session 更新回调 (从 SSE 事件接收) */
|
|
6
|
+
onSessionUpdate?: Ref<((session: {
|
|
7
|
+
id: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
time?: {
|
|
10
|
+
updated?: number;
|
|
11
|
+
};
|
|
12
|
+
}) => void) | undefined>;
|
|
13
|
+
}
|
|
14
|
+
export declare function useSessions(options: UseSessionsOptions): {
|
|
15
|
+
sessions: Ref<{
|
|
4
16
|
id: string;
|
|
5
17
|
title?: string | undefined;
|
|
6
18
|
updatedAt?: (string | number | Date) | undefined;
|
|
@@ -15,12 +27,19 @@ export declare function useSessions(showNotification: (msg: string) => void): {
|
|
|
15
27
|
directory?: string | undefined;
|
|
16
28
|
url?: string | undefined;
|
|
17
29
|
}[]>;
|
|
18
|
-
loadingSessionList:
|
|
19
|
-
currentSessionId:
|
|
30
|
+
loadingSessionList: Ref<boolean | undefined, boolean | undefined>;
|
|
31
|
+
currentSessionId: Ref<string | null, string | null>;
|
|
20
32
|
iframeSrc: import("vue").ComputedRef<string>;
|
|
21
|
-
iframeLoading:
|
|
33
|
+
iframeLoading: Ref<boolean, boolean>;
|
|
22
34
|
loadSessions: () => Promise<void>;
|
|
23
35
|
createSession: () => Promise<void>;
|
|
24
36
|
deleteSession: (session: OpenCodeWidgetSession) => Promise<void>;
|
|
25
37
|
selectSession: (session: OpenCodeWidgetSession) => void;
|
|
38
|
+
updateSessionInfo: (sessionUpdate: {
|
|
39
|
+
id: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
time?: {
|
|
42
|
+
updated?: number;
|
|
43
|
+
};
|
|
44
|
+
}) => void;
|
|
26
45
|
};
|
|
@@ -39,7 +39,8 @@ var __async = (__this, __arguments, generator) => {
|
|
|
39
39
|
};
|
|
40
40
|
import { ref, computed } from "vue";
|
|
41
41
|
import { SESSIONS_API_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
42
|
-
function useSessions(
|
|
42
|
+
function useSessions(options) {
|
|
43
|
+
const { showNotification } = options;
|
|
43
44
|
const sessions = ref([]);
|
|
44
45
|
const loadingSessionList = ref(void 0);
|
|
45
46
|
const currentSessionId = ref(null);
|
|
@@ -70,6 +71,18 @@ function useSessions(showNotification) {
|
|
|
70
71
|
loadingSessionList.value = false;
|
|
71
72
|
}
|
|
72
73
|
});
|
|
74
|
+
const updateSessionInfo = (sessionUpdate) => {
|
|
75
|
+
var _a;
|
|
76
|
+
const index = sessions.value.findIndex((s) => s.id === sessionUpdate.id);
|
|
77
|
+
if (index === -1) return;
|
|
78
|
+
const session = sessions.value[index];
|
|
79
|
+
if (sessionUpdate.title && sessionUpdate.title !== session.title) {
|
|
80
|
+
sessions.value[index] = __spreadProps(__spreadValues({}, session), {
|
|
81
|
+
title: sessionUpdate.title,
|
|
82
|
+
updatedAt: ((_a = sessionUpdate.time) == null ? void 0 : _a.updated) || Date.now()
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
73
86
|
const createSession = () => __async(null, null, function* () {
|
|
74
87
|
try {
|
|
75
88
|
const response = yield fetch(SESSIONS_API_PATH, { method: "POST" });
|
|
@@ -119,7 +132,8 @@ function useSessions(showNotification) {
|
|
|
119
132
|
loadSessions,
|
|
120
133
|
createSession,
|
|
121
134
|
deleteSession,
|
|
122
|
-
selectSession
|
|
135
|
+
selectSession,
|
|
136
|
+
updateSessionInfo
|
|
123
137
|
};
|
|
124
138
|
}
|
|
125
139
|
export {
|
package/es/core/proxy-server.js
CHANGED
|
@@ -102,15 +102,15 @@ function generateBridgeScript(options) {
|
|
|
102
102
|
if (event.data && event.data.type === "OPENCODE_SET_THEME") {
|
|
103
103
|
setTheme(event.data.theme);
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
if (event.data && event.data.type === "OPENCODE_INSERT_FILE_PART") {
|
|
107
107
|
insertFilePart(event.data.element);
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
if (event.data && event.data.type === "minimize-state-change") {
|
|
111
111
|
handleMinimizeStateChange(event.data.minimized);
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
if (event.data && event.data.type === "prompt-dock-visibility-change") {
|
|
115
115
|
handlePromptDockVisibilityChange(event.data.visible);
|
|
116
116
|
}
|
|
@@ -124,11 +124,11 @@ function generateBridgeScript(options) {
|
|
|
124
124
|
savedMinimizedState = minimized;
|
|
125
125
|
const dockSurface = document.querySelector('[data-dock-surface="tray"]');
|
|
126
126
|
const sessionTurnList = document.querySelector('[data-slot="session-turn-list"]');
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
if (dockSurface) {
|
|
129
129
|
dockSurface.style.display = minimized ? 'none' : '';
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
if (sessionTurnList) {
|
|
133
133
|
sessionTurnList.style.paddingBottom = minimized ? '10px' : '';
|
|
134
134
|
}
|
|
@@ -155,11 +155,11 @@ function generateBridgeScript(options) {
|
|
|
155
155
|
|
|
156
156
|
// === \u4FDD\u5B58\u8F93\u5165\u6846\u5149\u6807\u4F4D\u7F6E ===
|
|
157
157
|
let savedRange = null;
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
function setupPromptInputListener() {
|
|
160
160
|
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
161
161
|
if (!promptInput) return;
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
promptInput.addEventListener('blur', function() {
|
|
164
164
|
const selection = window.getSelection();
|
|
165
165
|
if (selection && selection.rangeCount > 0) {
|
|
@@ -169,7 +169,7 @@ function generateBridgeScript(options) {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
});
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
promptInput.addEventListener('focus', function() {
|
|
174
174
|
savedRange = null;
|
|
175
175
|
});
|
|
@@ -195,29 +195,29 @@ function generateBridgeScript(options) {
|
|
|
195
195
|
|
|
196
196
|
const jsonStr = JSON.stringify({
|
|
197
197
|
nodeContext: {
|
|
198
|
-
"filePath": {
|
|
199
|
-
"value": filePath ?? '\u672A\u77E5',
|
|
200
|
-
"desc": "\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84"
|
|
198
|
+
"filePath": {
|
|
199
|
+
"value": filePath ?? '\u672A\u77E5',
|
|
200
|
+
"desc": "\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84"
|
|
201
201
|
},
|
|
202
|
-
"line": {
|
|
203
|
-
"value": line ?? '\u672A\u77E5',
|
|
204
|
-
"desc": "\u4EE3\u7801\u6240\u5728\u884C\u53F7"
|
|
202
|
+
"line": {
|
|
203
|
+
"value": line ?? '\u672A\u77E5',
|
|
204
|
+
"desc": "\u4EE3\u7801\u6240\u5728\u884C\u53F7"
|
|
205
205
|
},
|
|
206
|
-
"column": {
|
|
207
|
-
"value": column ?? '\u672A\u77E5',
|
|
208
|
-
"desc": "\u4EE3\u7801\u6240\u5728\u5217\u53F7"
|
|
206
|
+
"column": {
|
|
207
|
+
"value": column ?? '\u672A\u77E5',
|
|
208
|
+
"desc": "\u4EE3\u7801\u6240\u5728\u5217\u53F7"
|
|
209
209
|
},
|
|
210
|
-
"description": {
|
|
211
|
-
"value": description ?? '\u672A\u77E5',
|
|
212
|
-
"desc": "DOM \u5143\u7D20\u9009\u62E9\u5668"
|
|
210
|
+
"description": {
|
|
211
|
+
"value": description ?? '\u672A\u77E5',
|
|
212
|
+
"desc": "DOM \u5143\u7D20\u9009\u62E9\u5668"
|
|
213
213
|
},
|
|
214
|
-
"innerText": {
|
|
215
|
-
"value": innerText ? innerText.substring(0, 500) : '',
|
|
216
|
-
"desc": "DOM \u5143\u7D20\u5185\u90E8\u6587\u672C"
|
|
214
|
+
"innerText": {
|
|
215
|
+
"value": innerText ? innerText.substring(0, 500) : '',
|
|
216
|
+
"desc": "DOM \u5143\u7D20\u5185\u90E8\u6587\u672C"
|
|
217
217
|
},
|
|
218
|
-
"selectAt": {
|
|
219
|
-
"value": previewPageUrl || '\u672A\u77E5',
|
|
220
|
-
"desc": "\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL"
|
|
218
|
+
"selectAt": {
|
|
219
|
+
"value": previewPageUrl || '\u672A\u77E5',
|
|
220
|
+
"desc": "\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL"
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
});
|
|
@@ -226,30 +226,30 @@ function generateBridgeScript(options) {
|
|
|
226
226
|
span.setAttribute('data-type', 'file');
|
|
227
227
|
span.setAttribute('data-path', jsonStr);
|
|
228
228
|
span.setAttribute('contenteditable', 'false');
|
|
229
|
-
|
|
229
|
+
|
|
230
230
|
span.textContent = displayText;
|
|
231
231
|
|
|
232
232
|
if (savedRange) {
|
|
233
233
|
const range = savedRange;
|
|
234
234
|
range.collapse(false);
|
|
235
235
|
range.insertNode(span);
|
|
236
|
-
|
|
236
|
+
|
|
237
237
|
const space = document.createTextNode('\\u00A0');
|
|
238
238
|
span.parentNode.insertBefore(space, span.nextSibling);
|
|
239
|
-
|
|
239
|
+
|
|
240
240
|
const newRange = document.createRange();
|
|
241
241
|
newRange.setStartAfter(space);
|
|
242
242
|
newRange.collapse(true);
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
promptInput.focus();
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
const selection = window.getSelection();
|
|
247
247
|
if (selection) {
|
|
248
248
|
selection.removeAllRanges();
|
|
249
249
|
selection.addRange(newRange);
|
|
250
250
|
}
|
|
251
251
|
savedRange = null;
|
|
252
|
-
|
|
252
|
+
|
|
253
253
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
@@ -257,20 +257,20 @@ function generateBridgeScript(options) {
|
|
|
257
257
|
const selection = window.getSelection();
|
|
258
258
|
if (selection && selection.rangeCount > 0) {
|
|
259
259
|
const range = selection.getRangeAt(0);
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
if (promptInput.contains(range.commonAncestorContainer)) {
|
|
262
262
|
range.collapse(false);
|
|
263
263
|
range.insertNode(span);
|
|
264
|
-
|
|
264
|
+
|
|
265
265
|
const space = document.createTextNode('\\u00A0');
|
|
266
266
|
span.parentNode.insertBefore(space, span.nextSibling);
|
|
267
|
-
|
|
267
|
+
|
|
268
268
|
const newRange = document.createRange();
|
|
269
269
|
newRange.setStartAfter(space);
|
|
270
270
|
newRange.collapse(true);
|
|
271
271
|
selection.removeAllRanges();
|
|
272
272
|
selection.addRange(newRange);
|
|
273
|
-
|
|
273
|
+
|
|
274
274
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
@@ -279,7 +279,7 @@ function generateBridgeScript(options) {
|
|
|
279
279
|
promptInput.appendChild(span);
|
|
280
280
|
const space = document.createTextNode('\\u00A0');
|
|
281
281
|
promptInput.appendChild(space);
|
|
282
|
-
|
|
282
|
+
|
|
283
283
|
const newRange = document.createRange();
|
|
284
284
|
newRange.setStartAfter(space);
|
|
285
285
|
newRange.collapse(true);
|
|
@@ -288,119 +288,16 @@ function generateBridgeScript(options) {
|
|
|
288
288
|
newSelection.removeAllRanges();
|
|
289
289
|
newSelection.addRange(newRange);
|
|
290
290
|
}
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
293
293
|
promptInput.focus();
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
// === \u601D\u8003\u72B6\u6001\u76D1\u542C (\u5B8C\u5168\u590D\u523B OpenCode Web \u5B9E\u73B0) ===
|
|
297
|
-
// OpenCode Web \u6838\u5FC3\u903B\u8F91:
|
|
298
|
-
// working = !!pending() || sessionStatus().type !== "idle"
|
|
299
|
-
// pending = \u6700\u540E\u4E00\u6761\u672A\u5B8C\u6210\u7684 assistant \u6D88\u606F (time.completed \u4E0D\u662F\u6570\u5B57)
|
|
300
|
-
// sessionStatus = sync.data.session_status[sessionID]
|
|
301
|
-
|
|
302
|
-
let eventSource = null;
|
|
303
|
-
const sessionStatus = {};
|
|
304
|
-
const pendingMessages = {};
|
|
305
|
-
|
|
306
|
-
function getCurrentSessionID() {
|
|
307
|
-
const match = window.location.pathname.match(/\\/session\\/([^\\/]+)/);
|
|
308
|
-
return match ? match[1] : null;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function isPending(message) {
|
|
312
|
-
return message.role === 'assistant' && typeof message.time?.completed !== 'number';
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function updateThinkingState(sessionID) {
|
|
316
|
-
const status = sessionStatus[sessionID];
|
|
317
|
-
const pending = pendingMessages[sessionID];
|
|
318
|
-
|
|
319
|
-
const isThinking = !!pending || (status && status.type !== 'idle');
|
|
320
|
-
|
|
321
|
-
if (window.parent !== window) {
|
|
322
|
-
window.parent.postMessage({
|
|
323
|
-
type: 'OPENCODE_THINKING_STATE',
|
|
324
|
-
thinking: isThinking,
|
|
325
|
-
sessionID: sessionID,
|
|
326
|
-
statusType: status?.type || 'idle',
|
|
327
|
-
hasPending: !!pending
|
|
328
|
-
}, '*');
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function handleEvent(payload) {
|
|
333
|
-
const type = payload.type;
|
|
334
|
-
const props = payload.properties;
|
|
335
|
-
|
|
336
|
-
switch (type) {
|
|
337
|
-
case 'session.status': {
|
|
338
|
-
const sessionID = props.sessionID;
|
|
339
|
-
sessionStatus[sessionID] = props.status;
|
|
340
|
-
updateThinkingState(sessionID);
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
case 'message.updated': {
|
|
345
|
-
const info = props.info;
|
|
346
|
-
if (!info || !info.sessionID) break;
|
|
347
|
-
const sessionID = info.sessionID;
|
|
348
|
-
|
|
349
|
-
if (info.role === 'assistant') {
|
|
350
|
-
if (isPending(info)) {
|
|
351
|
-
pendingMessages[sessionID] = info;
|
|
352
|
-
} else {
|
|
353
|
-
delete pendingMessages[sessionID];
|
|
354
|
-
}
|
|
355
|
-
updateThinkingState(sessionID);
|
|
356
|
-
}
|
|
357
|
-
break;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
case 'message.part.delta': {
|
|
361
|
-
const sessionID = props.sessionID;
|
|
362
|
-
if (sessionID && !pendingMessages[sessionID]) {
|
|
363
|
-
pendingMessages[sessionID] = { role: 'assistant', time: {} };
|
|
364
|
-
updateThinkingState(sessionID);
|
|
365
|
-
}
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function setupThinkingListener() {
|
|
372
|
-
if (eventSource) {
|
|
373
|
-
eventSource.close();
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
eventSource = new EventSource('/global/event');
|
|
377
|
-
|
|
378
|
-
eventSource.onmessage = function(event) {
|
|
379
|
-
try {
|
|
380
|
-
const data = JSON.parse(event.data);
|
|
381
|
-
const payload = data.payload;
|
|
382
|
-
if (!payload) return;
|
|
383
|
-
handleEvent(payload);
|
|
384
|
-
} catch (e) {
|
|
385
|
-
// ignore parse errors
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
eventSource.onerror = function(err) {
|
|
390
|
-
console.warn('[OpenCode Bridge] SSE connection error, retrying in 3s...');
|
|
391
|
-
eventSource.close();
|
|
392
|
-
setTimeout(setupThinkingListener, 3000);
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
console.log('[OpenCode Bridge] SSE listener setup complete');
|
|
396
|
-
}
|
|
397
|
-
|
|
398
296
|
// === \u5C31\u7EEA\u901A\u77E5 ===
|
|
399
297
|
function init() {
|
|
400
298
|
if (window.parent !== window) {
|
|
401
299
|
window.parent.postMessage({ type: "OPENCODE_READY" }, "*");
|
|
402
300
|
}
|
|
403
|
-
setupThinkingListener();
|
|
404
301
|
setupPromptInputListener();
|
|
405
302
|
applySavedStates();
|
|
406
303
|
|
|
@@ -426,13 +323,6 @@ function generateBridgeScript(options) {
|
|
|
426
323
|
} else {
|
|
427
324
|
init();
|
|
428
325
|
}
|
|
429
|
-
|
|
430
|
-
window.addEventListener('beforeunload', function() {
|
|
431
|
-
if (eventSource) {
|
|
432
|
-
eventSource.close();
|
|
433
|
-
eventSource = null;
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
326
|
})();
|
|
437
327
|
`;
|
|
438
328
|
}
|