opencode-copilot-account-switcher 0.13.6 → 0.14.0

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.
Files changed (54) hide show
  1. package/dist/common-settings-actions.d.ts +1 -1
  2. package/dist/common-settings-actions.js +36 -0
  3. package/dist/common-settings-store.d.ts +4 -0
  4. package/dist/common-settings-store.js +26 -0
  5. package/dist/menu-runtime.js +12 -1
  6. package/dist/plugin-hooks.d.ts +8 -0
  7. package/dist/plugin-hooks.js +96 -0
  8. package/dist/providers/codex-menu-adapter.js +8 -1
  9. package/dist/providers/copilot-menu-adapter.js +7 -0
  10. package/dist/store-paths.d.ts +1 -0
  11. package/dist/store-paths.js +3 -0
  12. package/dist/ui/menu.d.ts +33 -0
  13. package/dist/ui/menu.js +85 -0
  14. package/dist/wechat/bridge.d.ts +69 -0
  15. package/dist/wechat/bridge.js +180 -0
  16. package/dist/wechat/broker-client.d.ts +33 -0
  17. package/dist/wechat/broker-client.js +257 -0
  18. package/dist/wechat/broker-entry.d.ts +17 -0
  19. package/dist/wechat/broker-entry.js +182 -0
  20. package/dist/wechat/broker-launcher.d.ts +27 -0
  21. package/dist/wechat/broker-launcher.js +191 -0
  22. package/dist/wechat/broker-server.d.ts +25 -0
  23. package/dist/wechat/broker-server.js +540 -0
  24. package/dist/wechat/command-parser.d.ts +7 -0
  25. package/dist/wechat/command-parser.js +16 -0
  26. package/dist/wechat/compat/openclaw-guided-smoke.d.ts +178 -0
  27. package/dist/wechat/compat/openclaw-guided-smoke.js +1133 -0
  28. package/dist/wechat/compat/openclaw-public-helpers.d.ts +101 -0
  29. package/dist/wechat/compat/openclaw-public-helpers.js +207 -0
  30. package/dist/wechat/compat/openclaw-smoke.d.ts +48 -0
  31. package/dist/wechat/compat/openclaw-smoke.js +100 -0
  32. package/dist/wechat/compat/slash-guard.d.ts +11 -0
  33. package/dist/wechat/compat/slash-guard.js +24 -0
  34. package/dist/wechat/handle.d.ts +8 -0
  35. package/dist/wechat/handle.js +46 -0
  36. package/dist/wechat/ipc-auth.d.ts +6 -0
  37. package/dist/wechat/ipc-auth.js +39 -0
  38. package/dist/wechat/operator-store.d.ts +8 -0
  39. package/dist/wechat/operator-store.js +59 -0
  40. package/dist/wechat/protocol.d.ts +29 -0
  41. package/dist/wechat/protocol.js +75 -0
  42. package/dist/wechat/request-store.d.ts +41 -0
  43. package/dist/wechat/request-store.js +215 -0
  44. package/dist/wechat/session-digest.d.ts +41 -0
  45. package/dist/wechat/session-digest.js +134 -0
  46. package/dist/wechat/state-paths.d.ts +14 -0
  47. package/dist/wechat/state-paths.js +45 -0
  48. package/dist/wechat/status-format.d.ts +14 -0
  49. package/dist/wechat/status-format.js +174 -0
  50. package/dist/wechat/token-store.d.ts +18 -0
  51. package/dist/wechat/token-store.js +100 -0
  52. package/dist/wechat/wechat-status-runtime.d.ts +24 -0
  53. package/dist/wechat/wechat-status-runtime.js +238 -0
  54. package/package.json +8 -3
@@ -0,0 +1,191 @@
1
+ import net from "node:net";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { mkdir, open, readFile, rm } from "node:fs/promises";
5
+ import { spawn } from "node:child_process";
6
+ import { fileURLToPath } from "node:url";
7
+ import { wechatStateRoot } from "./state-paths.js";
8
+ import { parseEnvelopeLine, serializeEnvelope } from "./protocol.js";
9
+ const DEFAULT_BACKOFF_MS = 250;
10
+ const DEFAULT_MAX_ATTEMPTS = 20;
11
+ function isNonEmptyString(value) {
12
+ return typeof value === "string" && value.trim().length > 0;
13
+ }
14
+ function isFiniteNumber(value) {
15
+ return typeof value === "number" && Number.isFinite(value);
16
+ }
17
+ function delay(ms) {
18
+ return new Promise((resolve) => setTimeout(resolve, ms));
19
+ }
20
+ function isProcessAlive(pid) {
21
+ try {
22
+ process.kill(pid, 0);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ async function readBrokerMetadata(filePath) {
30
+ try {
31
+ const raw = await readFile(filePath, "utf8");
32
+ const parsed = JSON.parse(raw);
33
+ if (!isFiniteNumber(parsed.pid) || !isNonEmptyString(parsed.endpoint) || !isFiniteNumber(parsed.startedAt)) {
34
+ return null;
35
+ }
36
+ return {
37
+ pid: parsed.pid,
38
+ endpoint: parsed.endpoint,
39
+ startedAt: parsed.startedAt,
40
+ version: isNonEmptyString(parsed.version) ? parsed.version : "unknown",
41
+ };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ async function defaultPingImpl(endpoint) {
48
+ return new Promise((resolve) => {
49
+ const socket = net.createConnection(endpoint);
50
+ let buffer = "";
51
+ const timer = setTimeout(() => {
52
+ socket.destroy();
53
+ resolve(false);
54
+ }, 500);
55
+ socket.once("error", () => {
56
+ clearTimeout(timer);
57
+ resolve(false);
58
+ });
59
+ socket.once("connect", () => {
60
+ socket.write(serializeEnvelope({ id: `launcher-ping-${Date.now()}`, type: "ping", payload: {} }));
61
+ });
62
+ socket.on("data", (chunk) => {
63
+ buffer += chunk.toString("utf8");
64
+ const newlineIndex = buffer.indexOf("\n");
65
+ if (newlineIndex === -1) {
66
+ return;
67
+ }
68
+ clearTimeout(timer);
69
+ socket.end();
70
+ try {
71
+ const response = parseEnvelopeLine(buffer.slice(0, newlineIndex + 1));
72
+ resolve(response.type === "pong");
73
+ }
74
+ catch {
75
+ resolve(false);
76
+ }
77
+ });
78
+ });
79
+ }
80
+ async function readLaunchLock(filePath) {
81
+ try {
82
+ const raw = await readFile(filePath, "utf8");
83
+ const parsed = JSON.parse(raw);
84
+ if (!isFiniteNumber(parsed.pid) || !isFiniteNumber(parsed.acquiredAt) || !isNonEmptyString(parsed.lockId)) {
85
+ return null;
86
+ }
87
+ return {
88
+ pid: parsed.pid,
89
+ acquiredAt: parsed.acquiredAt,
90
+ lockId: parsed.lockId,
91
+ };
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ async function acquireLaunchLock(filePath) {
98
+ const lock = {
99
+ pid: process.pid,
100
+ acquiredAt: Date.now(),
101
+ lockId: randomUUID(),
102
+ };
103
+ try {
104
+ const handle = await open(filePath, "wx", 0o600);
105
+ await handle.writeFile(JSON.stringify(lock, null, 2), "utf8");
106
+ await handle.close();
107
+ return lock;
108
+ }
109
+ catch (error) {
110
+ if (error.code !== "EEXIST") {
111
+ throw error;
112
+ }
113
+ const existing = await readLaunchLock(filePath);
114
+ if (existing && isProcessAlive(existing.pid)) {
115
+ return null;
116
+ }
117
+ await rm(filePath, { force: true });
118
+ return null;
119
+ }
120
+ }
121
+ async function isBrokerAlive(brokerFilePath, pingImpl) {
122
+ const metadata = await readBrokerMetadata(brokerFilePath);
123
+ if (!metadata) {
124
+ return null;
125
+ }
126
+ const ok = await pingImpl(metadata.endpoint);
127
+ if (!ok) {
128
+ return null;
129
+ }
130
+ return metadata;
131
+ }
132
+ function defaultSpawnImpl(endpoint, stateRoot) {
133
+ const entry = fileURLToPath(new URL("./broker-entry.js", import.meta.url));
134
+ const child = spawn(process.execPath, [entry, `--endpoint=${endpoint}`, `--state-root=${stateRoot}`], {
135
+ cwd: path.resolve(fileURLToPath(new URL("../..", import.meta.url))),
136
+ detached: true,
137
+ stdio: "ignore",
138
+ });
139
+ child.unref();
140
+ return child;
141
+ }
142
+ export async function connectOrSpawnBroker(options = {}) {
143
+ const stateRoot = options.stateRoot ?? wechatStateRoot();
144
+ const brokerJsonFile = options.brokerJsonPath ?? path.join(stateRoot, "broker.json");
145
+ const launchLockFile = options.launchLockPath ?? path.join(stateRoot, "launch.lock");
146
+ const backoffMs = options.backoffMs ?? DEFAULT_BACKOFF_MS;
147
+ const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
148
+ const pingImpl = options.pingImpl ?? defaultPingImpl;
149
+ const spawnImpl = options.spawnImpl ?? defaultSpawnImpl;
150
+ const endpointFactory = options.endpointFactory ?? (() => {
151
+ const suffix = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
152
+ if (process.platform === "win32") {
153
+ return `\\\\.\\pipe\\wechat-broker-${process.pid}-${suffix}`;
154
+ }
155
+ return path.join(stateRoot, `broker-${suffix}.sock`);
156
+ });
157
+ await mkdir(stateRoot, { recursive: true, mode: 0o700 });
158
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
159
+ const running = await isBrokerAlive(brokerJsonFile, pingImpl);
160
+ if (running) {
161
+ return running;
162
+ }
163
+ const lock = await acquireLaunchLock(launchLockFile);
164
+ if (!lock) {
165
+ await delay(backoffMs);
166
+ continue;
167
+ }
168
+ options.onLockAcquired?.(lock);
169
+ try {
170
+ const secondCheck = await isBrokerAlive(brokerJsonFile, pingImpl);
171
+ if (secondCheck) {
172
+ return secondCheck;
173
+ }
174
+ const endpoint = endpointFactory();
175
+ const child = spawnImpl(endpoint, stateRoot);
176
+ void child?.unref?.();
177
+ for (let n = 0; n < 20; n += 1) {
178
+ await delay(100);
179
+ const spawned = await isBrokerAlive(brokerJsonFile, pingImpl);
180
+ if (spawned) {
181
+ return spawned;
182
+ }
183
+ }
184
+ throw new Error("spawned broker did not become available");
185
+ }
186
+ finally {
187
+ await rm(launchLockFile, { force: true });
188
+ }
189
+ }
190
+ throw new Error("broker unavailable");
191
+ }
@@ -0,0 +1,25 @@
1
+ import type { WechatSlashCommand } from "./command-parser.js";
2
+ export declare const DEFAULT_HEARTBEAT_TIMEOUT_MS = 30000;
3
+ export declare const DEFAULT_STATUS_COLLECT_WINDOW_MS = 1500;
4
+ type AggregatedStatusInstance = {
5
+ instanceID: string;
6
+ status: "ok";
7
+ snapshot: unknown;
8
+ } | {
9
+ instanceID: string;
10
+ status: "timeout/unreachable";
11
+ };
12
+ type CollectStatusResult = {
13
+ requestId: string;
14
+ instances: AggregatedStatusInstance[];
15
+ reply: string;
16
+ };
17
+ export type BrokerServerHandle = {
18
+ endpoint: string;
19
+ startedAt: number;
20
+ collectStatus: () => Promise<CollectStatusResult>;
21
+ handleWechatSlashCommand: (command: WechatSlashCommand) => Promise<string>;
22
+ close: () => Promise<void>;
23
+ };
24
+ export declare function startBrokerServer(endpoint: string): Promise<BrokerServerHandle>;
25
+ export {};