opencode-copilot-account-switcher 0.13.6 → 0.14.1
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/dist/common-settings-actions.d.ts +1 -1
- package/dist/common-settings-actions.js +54 -0
- package/dist/common-settings-store.d.ts +25 -0
- package/dist/common-settings-store.js +81 -0
- package/dist/menu-runtime.js +12 -1
- package/dist/plugin-hooks.d.ts +8 -0
- package/dist/plugin-hooks.js +96 -0
- package/dist/providers/codex-menu-adapter.js +14 -1
- package/dist/providers/copilot-menu-adapter.js +13 -0
- package/dist/store-paths.d.ts +1 -0
- package/dist/store-paths.js +3 -0
- package/dist/ui/menu.d.ts +73 -34
- package/dist/ui/menu.js +195 -0
- package/dist/wechat/bind-flow.d.ts +25 -0
- package/dist/wechat/bind-flow.js +101 -0
- package/dist/wechat/bridge.d.ts +69 -0
- package/dist/wechat/bridge.js +180 -0
- package/dist/wechat/broker-client.d.ts +33 -0
- package/dist/wechat/broker-client.js +257 -0
- package/dist/wechat/broker-entry.d.ts +17 -0
- package/dist/wechat/broker-entry.js +182 -0
- package/dist/wechat/broker-launcher.d.ts +27 -0
- package/dist/wechat/broker-launcher.js +191 -0
- package/dist/wechat/broker-server.d.ts +25 -0
- package/dist/wechat/broker-server.js +540 -0
- package/dist/wechat/command-parser.d.ts +7 -0
- package/dist/wechat/command-parser.js +16 -0
- package/dist/wechat/compat/openclaw-guided-smoke.d.ts +178 -0
- package/dist/wechat/compat/openclaw-guided-smoke.js +1133 -0
- package/dist/wechat/compat/openclaw-public-helpers.d.ts +111 -0
- package/dist/wechat/compat/openclaw-public-helpers.js +262 -0
- package/dist/wechat/compat/openclaw-smoke.d.ts +48 -0
- package/dist/wechat/compat/openclaw-smoke.js +100 -0
- package/dist/wechat/compat/slash-guard.d.ts +11 -0
- package/dist/wechat/compat/slash-guard.js +24 -0
- package/dist/wechat/handle.d.ts +8 -0
- package/dist/wechat/handle.js +46 -0
- package/dist/wechat/ipc-auth.d.ts +6 -0
- package/dist/wechat/ipc-auth.js +39 -0
- package/dist/wechat/openclaw-account-adapter.d.ts +30 -0
- package/dist/wechat/openclaw-account-adapter.js +70 -0
- package/dist/wechat/operator-store.d.ts +9 -0
- package/dist/wechat/operator-store.js +69 -0
- package/dist/wechat/protocol.d.ts +29 -0
- package/dist/wechat/protocol.js +75 -0
- package/dist/wechat/request-store.d.ts +41 -0
- package/dist/wechat/request-store.js +215 -0
- package/dist/wechat/session-digest.d.ts +41 -0
- package/dist/wechat/session-digest.js +134 -0
- package/dist/wechat/state-paths.d.ts +14 -0
- package/dist/wechat/state-paths.js +45 -0
- package/dist/wechat/status-format.d.ts +14 -0
- package/dist/wechat/status-format.js +174 -0
- package/dist/wechat/token-store.d.ts +18 -0
- package/dist/wechat/token-store.js +100 -0
- package/dist/wechat/wechat-status-runtime.d.ts +24 -0
- package/dist/wechat/wechat-status-runtime.js +238 -0
- package/package.json +8 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommonSettingsStore } from "./common-settings-store.js";
|
|
2
|
-
export type CommonSettingsActionType = "toggle-loop-safety" | "toggle-loop-safety-provider-scope" | "toggle-experimental-slash-commands" | "toggle-network-retry";
|
|
2
|
+
export type CommonSettingsActionType = "toggle-loop-safety" | "toggle-loop-safety-provider-scope" | "toggle-experimental-slash-commands" | "toggle-network-retry" | "wechat-bind" | "wechat-rebind" | "wechat-unbind" | "toggle-wechat-notifications" | "toggle-wechat-question-notify" | "toggle-wechat-permission-notify" | "toggle-wechat-session-error-notify";
|
|
3
3
|
type WriteMeta = {
|
|
4
4
|
reason?: string;
|
|
5
5
|
source?: string;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
export async function applyCommonSettingsAction(input) {
|
|
2
2
|
const settings = await input.readSettings();
|
|
3
|
+
const existingNotifications = settings.wechat?.notifications;
|
|
4
|
+
const notifications = {
|
|
5
|
+
enabled: existingNotifications?.enabled !== false,
|
|
6
|
+
question: existingNotifications?.question !== false,
|
|
7
|
+
permission: existingNotifications?.permission !== false,
|
|
8
|
+
sessionError: existingNotifications?.sessionError !== false,
|
|
9
|
+
};
|
|
10
|
+
if (!settings.wechat) {
|
|
11
|
+
settings.wechat = {
|
|
12
|
+
notifications,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
else if (!settings.wechat.notifications) {
|
|
16
|
+
settings.wechat.notifications = notifications;
|
|
17
|
+
}
|
|
3
18
|
if (input.action.type === "toggle-loop-safety") {
|
|
4
19
|
settings.loopSafetyEnabled = settings.loopSafetyEnabled !== true;
|
|
5
20
|
await input.writeSettings(settings, {
|
|
@@ -38,5 +53,44 @@ export async function applyCommonSettingsAction(input) {
|
|
|
38
53
|
});
|
|
39
54
|
return true;
|
|
40
55
|
}
|
|
56
|
+
if (input.action.type === "toggle-wechat-notifications") {
|
|
57
|
+
settings.wechat.notifications.enabled = settings.wechat.notifications.enabled !== true;
|
|
58
|
+
await input.writeSettings(settings, {
|
|
59
|
+
reason: "toggle-wechat-notifications",
|
|
60
|
+
source: "applyCommonSettingsAction",
|
|
61
|
+
actionType: "toggle-wechat-notifications",
|
|
62
|
+
});
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (input.action.type === "toggle-wechat-question-notify") {
|
|
66
|
+
settings.wechat.notifications.question = settings.wechat.notifications.question !== true;
|
|
67
|
+
await input.writeSettings(settings, {
|
|
68
|
+
reason: "toggle-wechat-question-notify",
|
|
69
|
+
source: "applyCommonSettingsAction",
|
|
70
|
+
actionType: "toggle-wechat-question-notify",
|
|
71
|
+
});
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
if (input.action.type === "toggle-wechat-permission-notify") {
|
|
75
|
+
settings.wechat.notifications.permission = settings.wechat.notifications.permission !== true;
|
|
76
|
+
await input.writeSettings(settings, {
|
|
77
|
+
reason: "toggle-wechat-permission-notify",
|
|
78
|
+
source: "applyCommonSettingsAction",
|
|
79
|
+
actionType: "toggle-wechat-permission-notify",
|
|
80
|
+
});
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (input.action.type === "toggle-wechat-session-error-notify") {
|
|
84
|
+
settings.wechat.notifications.sessionError = settings.wechat.notifications.sessionError !== true;
|
|
85
|
+
await input.writeSettings(settings, {
|
|
86
|
+
reason: "toggle-wechat-session-error-notify",
|
|
87
|
+
source: "applyCommonSettingsAction",
|
|
88
|
+
actionType: "toggle-wechat-session-error-notify",
|
|
89
|
+
});
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (input.action.type === "wechat-bind" || input.action.type === "wechat-rebind" || input.action.type === "wechat-unbind") {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
41
95
|
return false;
|
|
42
96
|
}
|
|
@@ -4,6 +4,31 @@ export type CommonSettingsStore = {
|
|
|
4
4
|
networkRetryEnabled?: boolean;
|
|
5
5
|
experimentalSlashCommandsEnabled?: boolean;
|
|
6
6
|
experimentalStatusSlashCommandEnabled?: boolean;
|
|
7
|
+
wechat?: WechatMenuSettings;
|
|
8
|
+
wechatNotificationsEnabled?: boolean;
|
|
9
|
+
wechatQuestionNotifyEnabled?: boolean;
|
|
10
|
+
wechatPermissionNotifyEnabled?: boolean;
|
|
11
|
+
wechatSessionErrorNotifyEnabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type WechatBinding = {
|
|
14
|
+
accountId: string;
|
|
15
|
+
userId?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
configured?: boolean;
|
|
19
|
+
boundAt?: number;
|
|
20
|
+
};
|
|
21
|
+
export type WechatMenuSettings = {
|
|
22
|
+
primaryBinding?: WechatBinding;
|
|
23
|
+
notifications: {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
question: boolean;
|
|
26
|
+
permission: boolean;
|
|
27
|
+
sessionError: boolean;
|
|
28
|
+
};
|
|
29
|
+
future?: {
|
|
30
|
+
accounts?: WechatBinding[];
|
|
31
|
+
};
|
|
7
32
|
};
|
|
8
33
|
export declare function parseCommonSettingsStore(raw: string): CommonSettingsStore;
|
|
9
34
|
export declare function commonSettingsPath(): string;
|
|
@@ -3,9 +3,68 @@ import { promises as fs } from "node:fs";
|
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { commonSettingsPath as defaultCommonSettingsPath, legacyCopilotStorePath } from "./store-paths.js";
|
|
5
5
|
import { parseStore } from "./store.js";
|
|
6
|
+
function normalizeWechatBinding(input) {
|
|
7
|
+
if (!input || typeof input !== "object")
|
|
8
|
+
return undefined;
|
|
9
|
+
const value = input;
|
|
10
|
+
if (typeof value.accountId !== "string" || value.accountId.length === 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
const binding = { accountId: value.accountId };
|
|
13
|
+
if (typeof value.userId === "string")
|
|
14
|
+
binding.userId = value.userId;
|
|
15
|
+
if (typeof value.name === "string")
|
|
16
|
+
binding.name = value.name;
|
|
17
|
+
if (typeof value.enabled === "boolean")
|
|
18
|
+
binding.enabled = value.enabled;
|
|
19
|
+
if (typeof value.configured === "boolean")
|
|
20
|
+
binding.configured = value.configured;
|
|
21
|
+
if (typeof value.boundAt === "number" && Number.isFinite(value.boundAt))
|
|
22
|
+
binding.boundAt = value.boundAt;
|
|
23
|
+
return binding;
|
|
24
|
+
}
|
|
25
|
+
function normalizeWechatSettings(source) {
|
|
26
|
+
const wechatValue = source.wechat && typeof source.wechat === "object"
|
|
27
|
+
? source.wechat
|
|
28
|
+
: undefined;
|
|
29
|
+
const notificationsValue = wechatValue?.notifications && typeof wechatValue.notifications === "object"
|
|
30
|
+
? wechatValue.notifications
|
|
31
|
+
: undefined;
|
|
32
|
+
const futureValue = wechatValue?.future && typeof wechatValue.future === "object"
|
|
33
|
+
? wechatValue.future
|
|
34
|
+
: undefined;
|
|
35
|
+
const enabled = typeof notificationsValue?.enabled === "boolean"
|
|
36
|
+
? notificationsValue.enabled
|
|
37
|
+
: source.wechatNotificationsEnabled !== false;
|
|
38
|
+
const question = typeof notificationsValue?.question === "boolean"
|
|
39
|
+
? notificationsValue.question
|
|
40
|
+
: source.wechatQuestionNotifyEnabled !== false;
|
|
41
|
+
const permission = typeof notificationsValue?.permission === "boolean"
|
|
42
|
+
? notificationsValue.permission
|
|
43
|
+
: source.wechatPermissionNotifyEnabled !== false;
|
|
44
|
+
const sessionError = typeof notificationsValue?.sessionError === "boolean"
|
|
45
|
+
? notificationsValue.sessionError
|
|
46
|
+
: source.wechatSessionErrorNotifyEnabled !== false;
|
|
47
|
+
const primaryBinding = normalizeWechatBinding(wechatValue?.primaryBinding);
|
|
48
|
+
const accounts = Array.isArray(futureValue?.accounts)
|
|
49
|
+
? futureValue.accounts
|
|
50
|
+
.map((account) => normalizeWechatBinding(account))
|
|
51
|
+
.filter((account) => Boolean(account))
|
|
52
|
+
: undefined;
|
|
53
|
+
return {
|
|
54
|
+
...(primaryBinding ? { primaryBinding } : {}),
|
|
55
|
+
notifications: {
|
|
56
|
+
enabled,
|
|
57
|
+
question,
|
|
58
|
+
permission,
|
|
59
|
+
sessionError,
|
|
60
|
+
},
|
|
61
|
+
...(accounts ? { future: { accounts } } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
6
64
|
function normalizeCommonSettingsStore(input) {
|
|
7
65
|
const source = input ?? {};
|
|
8
66
|
const legacySlashCommandsEnabled = source.experimentalStatusSlashCommandEnabled;
|
|
67
|
+
const wechat = normalizeWechatSettings(source);
|
|
9
68
|
return {
|
|
10
69
|
...(source.loopSafetyEnabled !== false ? { loopSafetyEnabled: true } : { loopSafetyEnabled: false }),
|
|
11
70
|
loopSafetyProviderScope: source.loopSafetyProviderScope === "all-models" ? "all-models" : "copilot-only",
|
|
@@ -15,6 +74,7 @@ function normalizeCommonSettingsStore(input) {
|
|
|
15
74
|
: legacySlashCommandsEnabled === false
|
|
16
75
|
? false
|
|
17
76
|
: true,
|
|
77
|
+
wechat,
|
|
18
78
|
};
|
|
19
79
|
}
|
|
20
80
|
function parsePartialCommonSettingsStore(raw) {
|
|
@@ -35,6 +95,21 @@ function parsePartialCommonSettingsStore(raw) {
|
|
|
35
95
|
if (parsed.experimentalStatusSlashCommandEnabled === true || parsed.experimentalStatusSlashCommandEnabled === false) {
|
|
36
96
|
partial.experimentalStatusSlashCommandEnabled = parsed.experimentalStatusSlashCommandEnabled;
|
|
37
97
|
}
|
|
98
|
+
if (parsed.wechat && typeof parsed.wechat === "object") {
|
|
99
|
+
partial.wechat = parsed.wechat;
|
|
100
|
+
}
|
|
101
|
+
if (parsed.wechatNotificationsEnabled === true || parsed.wechatNotificationsEnabled === false) {
|
|
102
|
+
partial.wechatNotificationsEnabled = parsed.wechatNotificationsEnabled;
|
|
103
|
+
}
|
|
104
|
+
if (parsed.wechatQuestionNotifyEnabled === true || parsed.wechatQuestionNotifyEnabled === false) {
|
|
105
|
+
partial.wechatQuestionNotifyEnabled = parsed.wechatQuestionNotifyEnabled;
|
|
106
|
+
}
|
|
107
|
+
if (parsed.wechatPermissionNotifyEnabled === true || parsed.wechatPermissionNotifyEnabled === false) {
|
|
108
|
+
partial.wechatPermissionNotifyEnabled = parsed.wechatPermissionNotifyEnabled;
|
|
109
|
+
}
|
|
110
|
+
if (parsed.wechatSessionErrorNotifyEnabled === true || parsed.wechatSessionErrorNotifyEnabled === false) {
|
|
111
|
+
partial.wechatSessionErrorNotifyEnabled = parsed.wechatSessionErrorNotifyEnabled;
|
|
112
|
+
}
|
|
38
113
|
return partial;
|
|
39
114
|
}
|
|
40
115
|
function readLegacyCommonSettings(store) {
|
|
@@ -55,6 +130,11 @@ function mergeCommonSettings(current, legacy) {
|
|
|
55
130
|
networkRetryEnabled: current.networkRetryEnabled ?? legacy.networkRetryEnabled,
|
|
56
131
|
experimentalSlashCommandsEnabled: current.experimentalSlashCommandsEnabled ?? legacy.experimentalSlashCommandsEnabled,
|
|
57
132
|
experimentalStatusSlashCommandEnabled: current.experimentalStatusSlashCommandEnabled ?? legacy.experimentalStatusSlashCommandEnabled,
|
|
133
|
+
wechat: current.wechat,
|
|
134
|
+
wechatNotificationsEnabled: current.wechatNotificationsEnabled ?? legacy.wechatNotificationsEnabled,
|
|
135
|
+
wechatQuestionNotifyEnabled: current.wechatQuestionNotifyEnabled ?? legacy.wechatQuestionNotifyEnabled,
|
|
136
|
+
wechatPermissionNotifyEnabled: current.wechatPermissionNotifyEnabled ?? legacy.wechatPermissionNotifyEnabled,
|
|
137
|
+
wechatSessionErrorNotifyEnabled: current.wechatSessionErrorNotifyEnabled ?? legacy.wechatSessionErrorNotifyEnabled,
|
|
58
138
|
});
|
|
59
139
|
}
|
|
60
140
|
export function parseCommonSettingsStore(raw) {
|
|
@@ -116,6 +196,7 @@ export async function writeCommonSettingsStore(store, options) {
|
|
|
116
196
|
loopSafetyProviderScope: normalized.loopSafetyProviderScope,
|
|
117
197
|
networkRetryEnabled: normalized.networkRetryEnabled,
|
|
118
198
|
experimentalSlashCommandsEnabled: normalized.experimentalSlashCommandsEnabled,
|
|
199
|
+
wechat: normalized.wechat,
|
|
119
200
|
};
|
|
120
201
|
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
121
202
|
await fs.writeFile(file, JSON.stringify(persisted, null, 2), { mode: 0o600 });
|
package/dist/menu-runtime.js
CHANGED
|
@@ -10,6 +10,15 @@ function parseSharedActionResult(result) {
|
|
|
10
10
|
persistHandled: false,
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
+
function providerActionReason(name) {
|
|
14
|
+
if (name.startsWith("wechat-")) {
|
|
15
|
+
return `wechat-action:${name}`;
|
|
16
|
+
}
|
|
17
|
+
return `provider-action:${name}`;
|
|
18
|
+
}
|
|
19
|
+
function isNonPersistentProviderAction(name) {
|
|
20
|
+
return name === "wechat-bind";
|
|
21
|
+
}
|
|
13
22
|
export async function runProviderMenu(input) {
|
|
14
23
|
const now = input.now ?? Date.now;
|
|
15
24
|
const store = await input.adapter.loadStore();
|
|
@@ -99,8 +108,10 @@ export async function runProviderMenu(input) {
|
|
|
99
108
|
continue;
|
|
100
109
|
if (!await input.adapter.applyAction(store, action))
|
|
101
110
|
continue;
|
|
111
|
+
if (isNonPersistentProviderAction(action.name))
|
|
112
|
+
continue;
|
|
102
113
|
await input.adapter.writeStore(store, {
|
|
103
|
-
reason:
|
|
114
|
+
reason: providerActionReason(action.name),
|
|
104
115
|
source: "menu-runtime",
|
|
105
116
|
actionType: action.name,
|
|
106
117
|
});
|
package/dist/plugin-hooks.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { handleStatusCommand } from "./status-command.js";
|
|
|
9
9
|
import { handleCodexStatusCommand } from "./codex-status-command.js";
|
|
10
10
|
import { handleCompactCommand, handleStopToolCommand } from "./session-control-command.js";
|
|
11
11
|
import { type AppendSessionTouchEventInput, type RouteDecisionEvent, type RoutingSnapshot, type RoutingEvent } from "./routing-state.js";
|
|
12
|
+
import { type WechatBridgeLifecycleInput } from "./wechat/bridge.js";
|
|
12
13
|
type ChatHeadersHook = (input: {
|
|
13
14
|
sessionID: string;
|
|
14
15
|
agent: string;
|
|
@@ -81,8 +82,15 @@ export declare function buildPluginHooks(input: {
|
|
|
81
82
|
}) => Promise<OfficialChatHeadersHook>;
|
|
82
83
|
createRetryFetch?: (fetch: FetchLike, ctx?: CopilotRetryContext) => FetchLike;
|
|
83
84
|
client?: CopilotRetryContext["client"];
|
|
85
|
+
project?: {
|
|
86
|
+
id?: string;
|
|
87
|
+
name?: string;
|
|
88
|
+
};
|
|
84
89
|
directory?: CopilotRetryContext["directory"];
|
|
85
90
|
serverUrl?: CopilotRetryContext["serverUrl"];
|
|
91
|
+
createWechatBridgeLifecycleImpl?: (input: WechatBridgeLifecycleInput) => Promise<{
|
|
92
|
+
close: () => Promise<void>;
|
|
93
|
+
}>;
|
|
86
94
|
clearAccountSwitchContext?: (lastAccountSwitchAt?: number) => Promise<void>;
|
|
87
95
|
now?: () => number;
|
|
88
96
|
refreshQuota?: RefreshQuota;
|
package/dist/plugin-hooks.js
CHANGED
|
@@ -19,6 +19,7 @@ import { handleStatusCommand, showStatusToast } from "./status-command.js";
|
|
|
19
19
|
import { handleCodexStatusCommand } from "./codex-status-command.js";
|
|
20
20
|
import { handleCompactCommand, handleStopToolCommand, } from "./session-control-command.js";
|
|
21
21
|
import { appendRoutingEvent, appendRouteDecisionEvent, appendSessionTouchEvent, buildCandidateAccountLoads, isAccountRateLimitCooledDown, readRoutingState, routingStatePath, } from "./routing-state.js";
|
|
22
|
+
import { createWechatBridgeLifecycle, } from "./wechat/bridge.js";
|
|
22
23
|
const SESSION_BINDING_IDLE_TTL_MS = 30 * 60 * 1000;
|
|
23
24
|
const RATE_LIMIT_WINDOW_MS = 5 * 60 * 1000;
|
|
24
25
|
const RATE_LIMIT_HIT_THRESHOLD = 3;
|
|
@@ -27,6 +28,70 @@ const MAX_SESSION_BINDINGS = 256;
|
|
|
27
28
|
const TOUCH_WRITE_CACHE_IDLE_TTL_MS = 30 * 60 * 1000;
|
|
28
29
|
const MAX_TOUCH_WRITE_CACHE_ENTRIES = 2048;
|
|
29
30
|
const INTERNAL_DEBUG_LINK_HEADER = "x-opencode-debug-link-id";
|
|
31
|
+
let wechatBridgeLifecycleState;
|
|
32
|
+
let wechatBridgeAutoCloseAttached = false;
|
|
33
|
+
function buildWechatBridgeLifecycleKey(input) {
|
|
34
|
+
const projectName = typeof input.project?.name === "string" ? input.project.name : "";
|
|
35
|
+
const projectId = typeof input.project?.id === "string" ? input.project.id : "";
|
|
36
|
+
const directory = typeof input.directory === "string" ? input.directory : "";
|
|
37
|
+
const serverUrl = input.serverUrl?.href ?? "";
|
|
38
|
+
return `${serverUrl}|${directory}|${projectName}|${projectId}`;
|
|
39
|
+
}
|
|
40
|
+
function attachWechatBridgeAutoClose() {
|
|
41
|
+
if (wechatBridgeAutoCloseAttached) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
wechatBridgeAutoCloseAttached = true;
|
|
45
|
+
const closeLifecycle = () => {
|
|
46
|
+
const state = wechatBridgeLifecycleState;
|
|
47
|
+
if (!state)
|
|
48
|
+
return;
|
|
49
|
+
closeWechatBridgeLifecycleState(state);
|
|
50
|
+
};
|
|
51
|
+
process.once("beforeExit", closeLifecycle);
|
|
52
|
+
process.once("SIGINT", closeLifecycle);
|
|
53
|
+
process.once("SIGTERM", closeLifecycle);
|
|
54
|
+
}
|
|
55
|
+
function closeWechatBridgeLifecycleState(state) {
|
|
56
|
+
if (state.closeRequested) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
state.closeRequested = true;
|
|
60
|
+
void state.promise
|
|
61
|
+
.then((lifecycle) => lifecycle.close().catch(() => { }))
|
|
62
|
+
.catch(() => { });
|
|
63
|
+
}
|
|
64
|
+
function ensureWechatBridgeLifecycle(input) {
|
|
65
|
+
if (wechatBridgeLifecycleState?.key === input.key) {
|
|
66
|
+
return wechatBridgeLifecycleState.promise;
|
|
67
|
+
}
|
|
68
|
+
const previous = wechatBridgeLifecycleState;
|
|
69
|
+
const promise = input.create();
|
|
70
|
+
const state = {
|
|
71
|
+
key: input.key,
|
|
72
|
+
promise,
|
|
73
|
+
closeRequested: false,
|
|
74
|
+
};
|
|
75
|
+
wechatBridgeLifecycleState = state;
|
|
76
|
+
if (previous) {
|
|
77
|
+
closeWechatBridgeLifecycleState(previous);
|
|
78
|
+
}
|
|
79
|
+
void promise
|
|
80
|
+
.then((lifecycle) => {
|
|
81
|
+
if (wechatBridgeLifecycleState !== state) {
|
|
82
|
+
closeWechatBridgeLifecycleState(state);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
state.lifecycle = lifecycle;
|
|
86
|
+
})
|
|
87
|
+
.catch((error) => {
|
|
88
|
+
if (wechatBridgeLifecycleState === state) {
|
|
89
|
+
wechatBridgeLifecycleState = undefined;
|
|
90
|
+
}
|
|
91
|
+
console.warn("[plugin-hooks] failed to initialize wechat bridge lifecycle", error);
|
|
92
|
+
});
|
|
93
|
+
return promise;
|
|
94
|
+
}
|
|
30
95
|
export class InjectCommandHandledError extends Error {
|
|
31
96
|
constructor() {
|
|
32
97
|
super("copilot-inject-handled");
|
|
@@ -249,6 +314,17 @@ function getFinalSentRequestHeadersRecord(request, init) {
|
|
|
249
314
|
headers.delete(INTERNAL_DEBUG_LINK_HEADER);
|
|
250
315
|
return sanitizeLoggedRequestHeadersRecord(Object.fromEntries(headers.entries()));
|
|
251
316
|
}
|
|
317
|
+
function hasWechatBridgeClientShape(value) {
|
|
318
|
+
if (typeof value !== "object" || value === null)
|
|
319
|
+
return false;
|
|
320
|
+
const client = value;
|
|
321
|
+
return typeof client.session?.list === "function"
|
|
322
|
+
&& typeof client.session?.status === "function"
|
|
323
|
+
&& typeof client.session?.todo === "function"
|
|
324
|
+
&& typeof client.session?.messages === "function"
|
|
325
|
+
&& typeof client.question?.list === "function"
|
|
326
|
+
&& typeof client.permission?.list === "function";
|
|
327
|
+
}
|
|
252
328
|
function sanitizeLoggedRequestHeadersRecord(headers) {
|
|
253
329
|
const sanitized = { ...headers };
|
|
254
330
|
if (typeof sanitized.authorization === "string" && sanitized.authorization.length > 0) {
|
|
@@ -507,6 +583,26 @@ export function buildPluginHooks(input) {
|
|
|
507
583
|
const appendRouteDecisionEventImpl = input.appendRouteDecisionEventImpl ?? appendRouteDecisionEvent;
|
|
508
584
|
const readRoutingStateImpl = input.readRoutingStateImpl ?? readRoutingState;
|
|
509
585
|
const triggerBillingCompensation = input.triggerBillingCompensation ?? (async () => { });
|
|
586
|
+
const createWechatBridgeLifecycleImpl = input.createWechatBridgeLifecycleImpl ?? createWechatBridgeLifecycle;
|
|
587
|
+
if (input.serverUrl && hasWechatBridgeClientShape(input.client)) {
|
|
588
|
+
const wechatBridgeClient = input.client;
|
|
589
|
+
const lifecycleKey = buildWechatBridgeLifecycleKey({
|
|
590
|
+
directory: input.directory,
|
|
591
|
+
serverUrl: input.serverUrl,
|
|
592
|
+
project: input.project,
|
|
593
|
+
});
|
|
594
|
+
attachWechatBridgeAutoClose();
|
|
595
|
+
void ensureWechatBridgeLifecycle({
|
|
596
|
+
key: lifecycleKey,
|
|
597
|
+
create: () => createWechatBridgeLifecycleImpl({
|
|
598
|
+
client: wechatBridgeClient,
|
|
599
|
+
project: input.project,
|
|
600
|
+
directory: input.directory,
|
|
601
|
+
serverUrl: input.serverUrl,
|
|
602
|
+
statusCollectionEnabled: true,
|
|
603
|
+
}),
|
|
604
|
+
}).catch(() => { });
|
|
605
|
+
}
|
|
510
606
|
const loadCandidateAccountLoads = input.loadCandidateAccountLoads ?? (async (ctx) => {
|
|
511
607
|
const snapshot = await readRoutingStateImpl(routingDirectory);
|
|
512
608
|
return buildCandidateAccountLoads({
|
|
@@ -7,6 +7,7 @@ import { recoverInvalidCodexAccount } from "../codex-invalid-account.js";
|
|
|
7
7
|
import { readAuth } from "../store.js";
|
|
8
8
|
import { readCommonSettingsStore, writeCommonSettingsStore, } from "../common-settings-store.js";
|
|
9
9
|
import { applyCommonSettingsAction } from "../common-settings-actions.js";
|
|
10
|
+
import { runWechatBindFlow } from "../wechat/bind-flow.js";
|
|
10
11
|
function pickName(input) {
|
|
11
12
|
const accountId = input.accountId?.trim();
|
|
12
13
|
if (accountId)
|
|
@@ -370,7 +371,11 @@ export function createCodexMenuAdapter(inputDeps) {
|
|
|
370
371
|
if (action.name === "toggle-loop-safety"
|
|
371
372
|
|| action.name === "toggle-loop-safety-provider-scope"
|
|
372
373
|
|| action.name === "toggle-experimental-slash-commands"
|
|
373
|
-
|| action.name === "toggle-network-retry"
|
|
374
|
+
|| action.name === "toggle-network-retry"
|
|
375
|
+
|| action.name === "toggle-wechat-notifications"
|
|
376
|
+
|| action.name === "toggle-wechat-question-notify"
|
|
377
|
+
|| action.name === "toggle-wechat-permission-notify"
|
|
378
|
+
|| action.name === "toggle-wechat-session-error-notify") {
|
|
374
379
|
await applyCommonSettingsAction({
|
|
375
380
|
action: { type: action.name },
|
|
376
381
|
readSettings: readCommonSettings,
|
|
@@ -378,6 +383,14 @@ export function createCodexMenuAdapter(inputDeps) {
|
|
|
378
383
|
});
|
|
379
384
|
return false;
|
|
380
385
|
}
|
|
386
|
+
if (action.name === "wechat-bind" || action.name === "wechat-rebind") {
|
|
387
|
+
await runWechatBindFlow({
|
|
388
|
+
action: action.name,
|
|
389
|
+
readCommonSettings,
|
|
390
|
+
writeCommonSettings,
|
|
391
|
+
});
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
381
394
|
return false;
|
|
382
395
|
},
|
|
383
396
|
};
|
|
@@ -5,6 +5,7 @@ import { getGitHubToken, normalizeDomain } from "../copilot-api-helpers.js";
|
|
|
5
5
|
import { listAssignableAccountsForModel, listKnownCopilotModels, rewriteModelAccountAssignments, } from "../model-account-map.js";
|
|
6
6
|
import { applyMenuAction, persistAccountSwitch } from "../plugin-actions.js";
|
|
7
7
|
import { readCommonSettingsStore, writeCommonSettingsStore, } from "../common-settings-store.js";
|
|
8
|
+
import { runWechatBindFlow } from "../wechat/bind-flow.js";
|
|
8
9
|
import { select, selectMany } from "../ui/select.js";
|
|
9
10
|
import { authPath, readAuth, readStore } from "../store.js";
|
|
10
11
|
const CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
@@ -726,6 +727,10 @@ export function createCopilotMenuAdapter(inputDeps) {
|
|
|
726
727
|
|| action.name === "toggle-loop-safety-provider-scope"
|
|
727
728
|
|| action.name === "toggle-experimental-slash-commands"
|
|
728
729
|
|| action.name === "toggle-network-retry"
|
|
730
|
+
|| action.name === "toggle-wechat-notifications"
|
|
731
|
+
|| action.name === "toggle-wechat-question-notify"
|
|
732
|
+
|| action.name === "toggle-wechat-permission-notify"
|
|
733
|
+
|| action.name === "toggle-wechat-session-error-notify"
|
|
729
734
|
|| action.name === "toggle-synthetic-agent-initiator") {
|
|
730
735
|
await applyMenuAction({
|
|
731
736
|
action: { type: action.name },
|
|
@@ -736,6 +741,14 @@ export function createCopilotMenuAdapter(inputDeps) {
|
|
|
736
741
|
});
|
|
737
742
|
return false;
|
|
738
743
|
}
|
|
744
|
+
if (action.name === "wechat-bind" || action.name === "wechat-rebind") {
|
|
745
|
+
await runWechatBindFlow({
|
|
746
|
+
action: action.name,
|
|
747
|
+
readCommonSettings,
|
|
748
|
+
writeCommonSettings,
|
|
749
|
+
});
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
739
752
|
if (action.name === "list-models") {
|
|
740
753
|
const modelID = await select([
|
|
741
754
|
{ label: "Back", value: "" },
|
package/dist/store-paths.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export declare function accountSwitcherConfigDir(): string;
|
|
|
2
2
|
export declare function commonSettingsPath(): string;
|
|
3
3
|
export declare function copilotAccountsPath(): string;
|
|
4
4
|
export declare function codexAccountsPath(): string;
|
|
5
|
+
export declare function wechatConfigDir(): string;
|
|
5
6
|
export declare function legacyCopilotStorePath(): string;
|
|
6
7
|
export declare function legacyCodexStorePath(): string;
|
package/dist/store-paths.js
CHANGED
|
@@ -16,6 +16,9 @@ export function copilotAccountsPath() {
|
|
|
16
16
|
export function codexAccountsPath() {
|
|
17
17
|
return path.join(accountSwitcherConfigDir(), "codex-accounts.json");
|
|
18
18
|
}
|
|
19
|
+
export function wechatConfigDir() {
|
|
20
|
+
return path.join(accountSwitcherConfigDir(), "wechat");
|
|
21
|
+
}
|
|
19
22
|
export function legacyCopilotStorePath() {
|
|
20
23
|
return path.join(configBaseDir(), "opencode", "copilot-accounts.json");
|
|
21
24
|
}
|
package/dist/ui/menu.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { select, type MenuItem } from "./select.js";
|
|
2
2
|
import { confirm } from "./confirm.js";
|
|
3
|
+
import { type CommonSettingsStore } from "../common-settings-store.js";
|
|
4
|
+
import { type OperatorBinding } from "../wechat/operator-store.js";
|
|
3
5
|
export type AccountStatus = "active" | "expired" | "unknown";
|
|
4
6
|
export interface AccountInfo {
|
|
5
7
|
name: string;
|
|
@@ -69,6 +71,20 @@ export type MenuAction = {
|
|
|
69
71
|
type: "toggle-experimental-slash-commands";
|
|
70
72
|
} | {
|
|
71
73
|
type: "toggle-network-retry";
|
|
74
|
+
} | {
|
|
75
|
+
type: "wechat-menu";
|
|
76
|
+
} | {
|
|
77
|
+
type: "wechat-bind";
|
|
78
|
+
} | {
|
|
79
|
+
type: "wechat-rebind";
|
|
80
|
+
} | {
|
|
81
|
+
type: "toggle-wechat-notifications";
|
|
82
|
+
} | {
|
|
83
|
+
type: "toggle-wechat-question-notify";
|
|
84
|
+
} | {
|
|
85
|
+
type: "toggle-wechat-permission-notify";
|
|
86
|
+
} | {
|
|
87
|
+
type: "toggle-wechat-session-error-notify";
|
|
72
88
|
} | {
|
|
73
89
|
type: "toggle-synthetic-agent-initiator";
|
|
74
90
|
} | {
|
|
@@ -84,6 +100,42 @@ export type MenuAction = {
|
|
|
84
100
|
};
|
|
85
101
|
export type MenuLanguage = "zh" | "en";
|
|
86
102
|
export type MenuProvider = "copilot" | "codex";
|
|
103
|
+
export type MenuWechatPrimaryBinding = {
|
|
104
|
+
accountId: string;
|
|
105
|
+
userId?: string;
|
|
106
|
+
name?: string;
|
|
107
|
+
enabled?: boolean;
|
|
108
|
+
configured?: boolean;
|
|
109
|
+
boundAt?: number;
|
|
110
|
+
};
|
|
111
|
+
export type MenuWechatOperatorBinding = {
|
|
112
|
+
wechatAccountId: string;
|
|
113
|
+
userId: string;
|
|
114
|
+
boundAt: number;
|
|
115
|
+
};
|
|
116
|
+
export type ShowMenuInput = {
|
|
117
|
+
provider?: MenuProvider;
|
|
118
|
+
refresh?: {
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
minutes: number;
|
|
121
|
+
};
|
|
122
|
+
lastQuotaRefresh?: number;
|
|
123
|
+
modelAccountAssignmentCount?: number;
|
|
124
|
+
defaultAccountGroupCount?: number;
|
|
125
|
+
loopSafetyEnabled?: boolean;
|
|
126
|
+
loopSafetyProviderScope?: "copilot-only" | "all-models";
|
|
127
|
+
networkRetryEnabled?: boolean;
|
|
128
|
+
wechatNotificationsEnabled?: boolean;
|
|
129
|
+
wechatQuestionNotifyEnabled?: boolean;
|
|
130
|
+
wechatPermissionNotifyEnabled?: boolean;
|
|
131
|
+
wechatSessionErrorNotifyEnabled?: boolean;
|
|
132
|
+
wechatPrimaryBinding?: MenuWechatPrimaryBinding;
|
|
133
|
+
wechatOperatorBinding?: MenuWechatOperatorBinding;
|
|
134
|
+
syntheticAgentInitiatorEnabled?: boolean;
|
|
135
|
+
experimentalSlashCommandsEnabled?: boolean;
|
|
136
|
+
capabilities?: Partial<MenuCapabilities>;
|
|
137
|
+
language?: MenuLanguage;
|
|
138
|
+
};
|
|
87
139
|
type MenuCapabilities = {
|
|
88
140
|
importAuth: boolean;
|
|
89
141
|
quota: boolean;
|
|
@@ -96,6 +148,7 @@ type MenuCapabilities = {
|
|
|
96
148
|
experimentalSlashCommands: boolean;
|
|
97
149
|
networkRetry: boolean;
|
|
98
150
|
syntheticAgentInitiator: boolean;
|
|
151
|
+
wechatNotificationsMenu: boolean;
|
|
99
152
|
};
|
|
100
153
|
export declare function getMenuCopy(language?: MenuLanguage, provider?: MenuProvider): {
|
|
101
154
|
menuTitle: string;
|
|
@@ -130,6 +183,16 @@ export declare function getMenuCopy(language?: MenuLanguage, provider?: MenuProv
|
|
|
130
183
|
syntheticInitiatorOn: string;
|
|
131
184
|
syntheticInitiatorOff: string;
|
|
132
185
|
syntheticInitiatorHint: string;
|
|
186
|
+
wechatNotificationsHeading: string;
|
|
187
|
+
wechatBind: string;
|
|
188
|
+
wechatNotificationsOn: string;
|
|
189
|
+
wechatNotificationsOff: string;
|
|
190
|
+
wechatQuestionNotifyOn: string;
|
|
191
|
+
wechatQuestionNotifyOff: string;
|
|
192
|
+
wechatPermissionNotifyOn: string;
|
|
193
|
+
wechatPermissionNotifyOff: string;
|
|
194
|
+
wechatSessionErrorNotifyOn: string;
|
|
195
|
+
wechatSessionErrorNotifyOff: string;
|
|
133
196
|
accountsHeading: string;
|
|
134
197
|
dangerHeading: string;
|
|
135
198
|
removeAll: string;
|
|
@@ -147,48 +210,24 @@ export declare function buildMenuItems(input: {
|
|
|
147
210
|
loopSafetyEnabled: boolean;
|
|
148
211
|
loopSafetyProviderScope?: "copilot-only" | "all-models";
|
|
149
212
|
networkRetryEnabled: boolean;
|
|
213
|
+
wechatNotificationsEnabled?: boolean;
|
|
214
|
+
wechatQuestionNotifyEnabled?: boolean;
|
|
215
|
+
wechatPermissionNotifyEnabled?: boolean;
|
|
216
|
+
wechatSessionErrorNotifyEnabled?: boolean;
|
|
217
|
+
wechatPrimaryBinding?: MenuWechatPrimaryBinding;
|
|
218
|
+
wechatOperatorBinding?: MenuWechatOperatorBinding;
|
|
150
219
|
syntheticAgentInitiatorEnabled?: boolean;
|
|
151
220
|
experimentalSlashCommandsEnabled?: boolean;
|
|
152
221
|
capabilities?: Partial<MenuCapabilities>;
|
|
153
222
|
language?: MenuLanguage;
|
|
154
223
|
}): MenuItem<MenuAction>[];
|
|
155
|
-
export declare function showMenu(accounts: AccountInfo[], input?:
|
|
156
|
-
|
|
157
|
-
refresh?: {
|
|
158
|
-
enabled: boolean;
|
|
159
|
-
minutes: number;
|
|
160
|
-
};
|
|
161
|
-
lastQuotaRefresh?: number;
|
|
162
|
-
modelAccountAssignmentCount?: number;
|
|
163
|
-
defaultAccountGroupCount?: number;
|
|
164
|
-
loopSafetyEnabled?: boolean;
|
|
165
|
-
loopSafetyProviderScope?: "copilot-only" | "all-models";
|
|
166
|
-
networkRetryEnabled?: boolean;
|
|
167
|
-
syntheticAgentInitiatorEnabled?: boolean;
|
|
168
|
-
experimentalSlashCommandsEnabled?: boolean;
|
|
169
|
-
capabilities?: Partial<MenuCapabilities>;
|
|
170
|
-
language?: MenuLanguage;
|
|
171
|
-
}): Promise<MenuAction>;
|
|
172
|
-
export declare function showMenuWithDeps(accounts: AccountInfo[], input?: {
|
|
173
|
-
provider?: MenuProvider;
|
|
174
|
-
refresh?: {
|
|
175
|
-
enabled: boolean;
|
|
176
|
-
minutes: number;
|
|
177
|
-
};
|
|
178
|
-
lastQuotaRefresh?: number;
|
|
179
|
-
modelAccountAssignmentCount?: number;
|
|
180
|
-
defaultAccountGroupCount?: number;
|
|
181
|
-
loopSafetyEnabled?: boolean;
|
|
182
|
-
loopSafetyProviderScope?: "copilot-only" | "all-models";
|
|
183
|
-
networkRetryEnabled?: boolean;
|
|
184
|
-
syntheticAgentInitiatorEnabled?: boolean;
|
|
185
|
-
experimentalSlashCommandsEnabled?: boolean;
|
|
186
|
-
capabilities?: Partial<MenuCapabilities>;
|
|
187
|
-
language?: MenuLanguage;
|
|
188
|
-
}, deps?: {
|
|
224
|
+
export declare function showMenu(accounts: AccountInfo[], input?: ShowMenuInput): Promise<MenuAction>;
|
|
225
|
+
export declare function showMenuWithDeps(accounts: AccountInfo[], input?: ShowMenuInput, deps?: {
|
|
189
226
|
select?: typeof select;
|
|
190
227
|
confirm?: typeof confirm;
|
|
191
228
|
showAccountActions?: typeof showAccountActions;
|
|
229
|
+
readCommonSettings?: () => Promise<CommonSettingsStore>;
|
|
230
|
+
readOperatorBinding?: () => Promise<OperatorBinding | undefined>;
|
|
192
231
|
}): Promise<MenuAction>;
|
|
193
232
|
export declare function buildAccountActionItems(account: AccountInfo, input?: {
|
|
194
233
|
provider?: MenuProvider;
|