opencode-copilot-account-switcher 0.14.9 → 0.14.11

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.
@@ -88,6 +88,7 @@ export declare function buildPluginHooks(input: {
88
88
  };
89
89
  directory?: CopilotRetryContext["directory"];
90
90
  serverUrl?: CopilotRetryContext["serverUrl"];
91
+ ensureWechatBrokerStarted?: () => Promise<unknown>;
91
92
  createWechatBridgeLifecycleImpl?: (input: WechatBridgeLifecycleInput) => Promise<{
92
93
  close: () => Promise<void>;
93
94
  }>;
@@ -20,6 +20,7 @@ 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
22
  import { createWechatBridgeLifecycle, } from "./wechat/bridge.js";
23
+ import { connectOrSpawnBroker } from "./wechat/broker-launcher.js";
23
24
  const SESSION_BINDING_IDLE_TTL_MS = 30 * 60 * 1000;
24
25
  const RATE_LIMIT_WINDOW_MS = 5 * 60 * 1000;
25
26
  const RATE_LIMIT_HIT_THRESHOLD = 3;
@@ -583,6 +584,7 @@ export function buildPluginHooks(input) {
583
584
  const appendRouteDecisionEventImpl = input.appendRouteDecisionEventImpl ?? appendRouteDecisionEvent;
584
585
  const readRoutingStateImpl = input.readRoutingStateImpl ?? readRoutingState;
585
586
  const triggerBillingCompensation = input.triggerBillingCompensation ?? (async () => { });
587
+ const ensureWechatBrokerStarted = input.ensureWechatBrokerStarted ?? (async () => connectOrSpawnBroker());
586
588
  const createWechatBridgeLifecycleImpl = input.createWechatBridgeLifecycleImpl ?? createWechatBridgeLifecycle;
587
589
  if (input.serverUrl && hasWechatBridgeClientShape(input.client)) {
588
590
  const wechatBridgeClient = input.client;
@@ -594,13 +596,18 @@ export function buildPluginHooks(input) {
594
596
  attachWechatBridgeAutoClose();
595
597
  void ensureWechatBridgeLifecycle({
596
598
  key: lifecycleKey,
597
- create: () => createWechatBridgeLifecycleImpl({
598
- client: wechatBridgeClient,
599
- project: input.project,
600
- directory: input.directory,
601
- serverUrl: input.serverUrl,
602
- statusCollectionEnabled: true,
603
- }),
599
+ create: async () => {
600
+ void Promise.resolve()
601
+ .then(() => ensureWechatBrokerStarted())
602
+ .catch(() => { });
603
+ return createWechatBridgeLifecycleImpl({
604
+ client: wechatBridgeClient,
605
+ project: input.project,
606
+ directory: input.directory,
607
+ serverUrl: input.serverUrl,
608
+ statusCollectionEnabled: true,
609
+ });
610
+ },
604
611
  }).catch(() => { });
605
612
  }
606
613
  const loadCandidateAccountLoads = input.loadCandidateAccountLoads ?? (async (ctx) => {
@@ -15,6 +15,7 @@ type LaunchOptions = {
15
15
  launchLockPath?: string;
16
16
  backoffMs?: number;
17
17
  maxAttempts?: number;
18
+ expectedVersion?: string;
18
19
  endpointFactory?: () => string;
19
20
  spawnImpl?: (endpoint: string, stateRoot: string) => {
20
21
  pid?: number | undefined;
@@ -17,6 +17,17 @@ function isFiniteNumber(value) {
17
17
  function delay(ms) {
18
18
  return new Promise((resolve) => setTimeout(resolve, ms));
19
19
  }
20
+ async function readCurrentPackageVersion() {
21
+ try {
22
+ const packageJsonPath = new URL("../../package.json", import.meta.url);
23
+ const raw = await readFile(packageJsonPath, "utf8");
24
+ const parsed = JSON.parse(raw);
25
+ return isNonEmptyString(parsed.version) ? parsed.version : "unknown";
26
+ }
27
+ catch {
28
+ return "unknown";
29
+ }
30
+ }
20
31
  function isProcessAlive(pid) {
21
32
  try {
22
33
  process.kill(pid, 0);
@@ -118,11 +129,14 @@ async function acquireLaunchLock(filePath) {
118
129
  return null;
119
130
  }
120
131
  }
121
- async function isBrokerAlive(brokerFilePath, pingImpl) {
132
+ async function isBrokerAlive(brokerFilePath, pingImpl, expectedVersion) {
122
133
  const metadata = await readBrokerMetadata(brokerFilePath);
123
134
  if (!metadata) {
124
135
  return null;
125
136
  }
137
+ if (isNonEmptyString(expectedVersion) && metadata.version !== expectedVersion) {
138
+ return null;
139
+ }
126
140
  const ok = await pingImpl(metadata.endpoint);
127
141
  if (!ok) {
128
142
  return null;
@@ -145,6 +159,7 @@ export async function connectOrSpawnBroker(options = {}) {
145
159
  const launchLockFile = options.launchLockPath ?? path.join(stateRoot, "launch.lock");
146
160
  const backoffMs = options.backoffMs ?? DEFAULT_BACKOFF_MS;
147
161
  const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
162
+ const expectedVersion = options.expectedVersion ?? await readCurrentPackageVersion();
148
163
  const pingImpl = options.pingImpl ?? defaultPingImpl;
149
164
  const spawnImpl = options.spawnImpl ?? defaultSpawnImpl;
150
165
  const endpointFactory = options.endpointFactory ?? (() => {
@@ -156,7 +171,7 @@ export async function connectOrSpawnBroker(options = {}) {
156
171
  });
157
172
  await mkdir(stateRoot, { recursive: true, mode: 0o700 });
158
173
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
159
- const running = await isBrokerAlive(brokerJsonFile, pingImpl);
174
+ const running = await isBrokerAlive(brokerJsonFile, pingImpl, expectedVersion);
160
175
  if (running) {
161
176
  return running;
162
177
  }
@@ -167,7 +182,7 @@ export async function connectOrSpawnBroker(options = {}) {
167
182
  }
168
183
  options.onLockAcquired?.(lock);
169
184
  try {
170
- const secondCheck = await isBrokerAlive(brokerJsonFile, pingImpl);
185
+ const secondCheck = await isBrokerAlive(brokerJsonFile, pingImpl, expectedVersion);
171
186
  if (secondCheck) {
172
187
  return secondCheck;
173
188
  }
@@ -176,7 +191,7 @@ export async function connectOrSpawnBroker(options = {}) {
176
191
  void child?.unref?.();
177
192
  for (let n = 0; n < 20; n += 1) {
178
193
  await delay(100);
179
- const spawned = await isBrokerAlive(brokerJsonFile, pingImpl);
194
+ const spawned = await isBrokerAlive(brokerJsonFile, pingImpl, expectedVersion);
180
195
  if (spawned) {
181
196
  return spawned;
182
197
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-copilot-account-switcher",
3
- "version": "0.14.9",
3
+ "version": "0.14.11",
4
4
  "description": "GitHub Copilot account switcher plugin for OpenCode",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",