oc-codex-multi-auth 6.5.0 → 6.6.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.
@@ -1,4 +1,5 @@
1
1
  type CleanupFn = () => void | Promise<void>;
2
+ export declare function setShutdownOwnsProcess(owns: boolean): void;
2
3
  export declare function registerCleanup(fn: CleanupFn): void;
3
4
  export declare function unregisterCleanup(fn: CleanupFn): void;
4
5
  export declare function runCleanup(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../lib/shutdown.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAK5C,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAKrD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAWhD;AAmBD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../lib/shutdown.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAyB5C,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAKrD;AAED,wBAAgB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB1C;AAuBD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -1,5 +1,26 @@
1
1
  const cleanupFunctions = [];
2
2
  let shutdownRegistered = false;
3
+ /**
4
+ * Whether this process is ours to terminate.
5
+ *
6
+ * Defaults to false: the package normally runs as a plugin *inside* the
7
+ * opencode host process, where calling `process.exit` from a signal handler
8
+ * preempts opencode's own shutdown (#187). Only an entrypoint that IS the
9
+ * process — the standalone `warm` CLI — opts in. Read lazily at signal time,
10
+ * so the opt-in may happen after handlers are installed.
11
+ */
12
+ let ownsProcess = false;
13
+ /**
14
+ * The in-flight drain, if one is running. Concurrent callers (a signal handler
15
+ * and `beforeExit` firing in the same shutdown) share it rather than racing on
16
+ * an already-emptied queue. Cleared once settled, so *sequential* calls each
17
+ * drain freshly — `AccountManager` re-registers its flush handler after an
18
+ * external `runCleanup()`, and the test suites depend on that.
19
+ */
20
+ let inFlight = null;
21
+ export function setShutdownOwnsProcess(owns) {
22
+ ownsProcess = owns;
23
+ }
3
24
  export function registerCleanup(fn) {
4
25
  cleanupFunctions.push(fn);
5
26
  ensureShutdownHandler();
@@ -10,29 +31,41 @@ export function unregisterCleanup(fn) {
10
31
  cleanupFunctions.splice(index, 1);
11
32
  }
12
33
  }
13
- export async function runCleanup() {
34
+ export function runCleanup() {
35
+ if (inFlight)
36
+ return inFlight;
14
37
  const fns = [...cleanupFunctions];
15
38
  cleanupFunctions.length = 0;
16
- for (const fn of fns) {
17
- try {
18
- await fn();
19
- }
20
- catch {
21
- // Ignore cleanup errors during shutdown
39
+ inFlight = (async () => {
40
+ for (const fn of fns) {
41
+ try {
42
+ await fn();
43
+ }
44
+ catch {
45
+ // Ignore cleanup errors during shutdown
46
+ }
22
47
  }
23
- }
48
+ })().finally(() => {
49
+ inFlight = null;
50
+ });
51
+ return inFlight;
24
52
  }
25
53
  function ensureShutdownHandler() {
26
54
  if (shutdownRegistered)
27
55
  return;
28
56
  shutdownRegistered = true;
29
- const handleSignal = () => {
30
- void runCleanup().finally(() => {
31
- process.exit(0);
57
+ const handleSignal = (signal) => {
58
+ const drained = runCleanup();
59
+ // A guest in someone else's process: run cleanup, then let the host
60
+ // finish its own shutdown. Exiting here is what broke #187.
61
+ if (!ownsProcess)
62
+ return;
63
+ void drained.finally(() => {
64
+ process.exit(signal === "SIGTERM" ? 143 : 130);
32
65
  });
33
66
  };
34
- process.once("SIGINT", handleSignal);
35
- process.once("SIGTERM", handleSignal);
67
+ process.once("SIGINT", () => handleSignal("SIGINT"));
68
+ process.once("SIGTERM", () => handleSignal("SIGTERM"));
36
69
  process.once("beforeExit", () => {
37
70
  void runCleanup();
38
71
  });
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../lib/shutdown.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAgB,EAAE,CAAC;AACzC,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAE/B,MAAM,UAAU,eAAe,CAAC,EAAa;IAC5C,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,qBAAqB,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAa;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC/B,MAAM,GAAG,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAClC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAE5B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC;YACJ,MAAM,EAAE,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACR,wCAAwC;QACzC,CAAC;IACF,CAAC;AACF,CAAC;AAED,SAAS,qBAAqB;IAC7B,IAAI,kBAAkB;QAAE,OAAO;IAC/B,kBAAkB,GAAG,IAAI,CAAC;IAE1B,MAAM,YAAY,GAAG,GAAG,EAAE;QACzB,KAAK,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE;QAC/B,KAAK,UAAU,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,gBAAgB,CAAC,MAAM,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../lib/shutdown.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAgB,EAAE,CAAC;AACzC,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAE/B;;;;;;;;GAQG;AACH,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB;;;;;;GAMG;AACH,IAAI,QAAQ,GAAyB,IAAI,CAAC;AAE1C,MAAM,UAAU,sBAAsB,CAAC,IAAa;IACnD,WAAW,GAAG,IAAI,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAAa;IAC5C,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,qBAAqB,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAa;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU;IACzB,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,GAAG,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAClC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAE5B,QAAQ,GAAG,CAAC,KAAK,IAAI,EAAE;QACtB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACJ,MAAM,EAAE,EAAE,CAAC;YACZ,CAAC;YAAC,MAAM,CAAC;gBACR,wCAAwC;YACzC,CAAC;QACF,CAAC;IACF,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;QACjB,QAAQ,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,SAAS,qBAAqB;IAC7B,IAAI,kBAAkB;QAAE,OAAO;IAC/B,kBAAkB,GAAG,IAAI,CAAC;IAE1B,MAAM,YAAY,GAAG,CAAC,MAA4B,EAAE,EAAE;QACrD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,oEAAoE;QACpE,4DAA4D;QAC5D,IAAI,CAAC,WAAW;YAAE,OAAO;QACzB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;YACzB,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE;QAC/B,KAAK,UAAU,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,gBAAgB,CAAC,MAAM,CAAC;AAChC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oc-codex-multi-auth",
3
- "version": "6.5.0",
3
+ "version": "6.6.0",
4
4
  "description": "OpenCode plugin for ChatGPT Plus/Pro OAuth with Codex/GPT-5 routing, multi-account rotation, account switching, health checks, diagnostics, and recovery tools",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -361,13 +361,19 @@ async function loadWarmRuntime(env) {
361
361
  const distRoot = join(repoRoot, "dist", "lib");
362
362
  const toUrl = (rel) => pathToFileURL(join(distRoot, rel)).href;
363
363
  try {
364
- const [storageMod, usageMod, warmReqMod, warmMod] = await Promise.all([
364
+ const [storageMod, usageMod, warmReqMod, warmMod, shutdownMod] = await Promise.all([
365
365
  import(toUrl("storage.js")),
366
366
  import(toUrl("codex-usage.js")),
367
367
  import(toUrl("accounts/warm-request.js")),
368
368
  import(toUrl("accounts/warm.js")),
369
+ import(toUrl("shutdown.js")),
369
370
  ]);
370
- return { storageMod, usageMod, warmReqMod, warmMod };
371
+ // Unlike the plugin, this CLI *is* the process, so it owns termination:
372
+ // Ctrl+C must abort the warm run rather than wait for it to drain.
373
+ // Refreshing a token here persists credentials, which registers the
374
+ // shutdown handler via the storage lock.
375
+ shutdownMod.setShutdownOwnsProcess(true);
376
+ return { storageMod, usageMod, warmReqMod, warmMod, shutdownMod };
371
377
  } catch (error) {
372
378
  throw new Error(
373
379
  `Could not load warm runtime from dist/. Build the package first (npm run build). Cause: ${formatErrorForLog(error)}`,