@bitkyc08/opencodex 2.6.17 → 2.6.18

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 (84) hide show
  1. package/README.md +9 -0
  2. package/bin/ocx.mjs +70 -5
  3. package/gui/dist/assets/index-DDcEW0Cm.css +1 -0
  4. package/gui/dist/assets/index-DbTEyo46.js +9 -0
  5. package/gui/dist/index.html +2 -2
  6. package/package.json +3 -1
  7. package/src/adapters/anthropic.ts +9 -2
  8. package/src/adapters/base.ts +6 -0
  9. package/src/adapters/cursor/arg-codec.ts +38 -0
  10. package/src/adapters/cursor/arg-normalize.ts +88 -0
  11. package/src/adapters/cursor/cursor-errors.ts +85 -0
  12. package/src/adapters/cursor/discovery.ts +144 -0
  13. package/src/adapters/cursor/effort-map.ts +74 -0
  14. package/src/adapters/cursor/exec-policy.ts +44 -0
  15. package/src/adapters/cursor/framing.ts +136 -0
  16. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  17. package/src/adapters/cursor/kv-store.ts +25 -0
  18. package/src/adapters/cursor/live-models.ts +93 -0
  19. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  20. package/src/adapters/cursor/live-transport.ts +758 -0
  21. package/src/adapters/cursor/mcp-config.ts +42 -0
  22. package/src/adapters/cursor/mcp-manager.ts +236 -0
  23. package/src/adapters/cursor/message-mapper.ts +46 -0
  24. package/src/adapters/cursor/native-exec-common.ts +55 -0
  25. package/src/adapters/cursor/native-exec-desktop.ts +177 -0
  26. package/src/adapters/cursor/native-exec-fs.ts +284 -0
  27. package/src/adapters/cursor/native-exec-mcp.ts +151 -0
  28. package/src/adapters/cursor/native-exec-network.ts +32 -0
  29. package/src/adapters/cursor/native-exec-shell.ts +191 -0
  30. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  31. package/src/adapters/cursor/native-exec.ts +177 -0
  32. package/src/adapters/cursor/protobuf-events.ts +309 -0
  33. package/src/adapters/cursor/protobuf-request.ts +347 -0
  34. package/src/adapters/cursor/request-builder.ts +98 -0
  35. package/src/adapters/cursor/tool-definitions.ts +301 -0
  36. package/src/adapters/cursor/transport-retry.ts +116 -0
  37. package/src/adapters/cursor/transport.ts +47 -0
  38. package/src/adapters/cursor/types.ts +36 -0
  39. package/src/adapters/cursor.ts +99 -0
  40. package/src/adapters/google.ts +7 -1
  41. package/src/adapters/kiro.ts +15 -0
  42. package/src/adapters/openai-chat.ts +7 -2
  43. package/src/adapters/run-turn-queue.ts +58 -0
  44. package/src/adapters/tool-catalog-nudge.ts +71 -0
  45. package/src/bridge.ts +7 -1
  46. package/src/cli-help.ts +9 -2
  47. package/src/cli-status.ts +7 -5
  48. package/src/cli.ts +122 -79
  49. package/src/codex-catalog.ts +213 -71
  50. package/src/codex-history-provider.ts +31 -14
  51. package/src/codex-inject.ts +17 -9
  52. package/src/codex-paths.ts +2 -1
  53. package/src/codex-shim.ts +30 -7
  54. package/src/codex-sync.ts +70 -0
  55. package/src/config.ts +58 -2
  56. package/src/doctor.ts +4 -2
  57. package/src/index.ts +1 -0
  58. package/src/model-cache.ts +22 -2
  59. package/src/oauth/callback-server.ts +44 -16
  60. package/src/oauth/cursor.ts +188 -0
  61. package/src/oauth/index.ts +29 -3
  62. package/src/oauth/key-providers.ts +20 -33
  63. package/src/oauth/login-cli.ts +7 -4
  64. package/src/open-url.ts +5 -1
  65. package/src/ports.ts +13 -0
  66. package/src/process-control.ts +76 -0
  67. package/src/provider-label.ts +10 -5
  68. package/src/providers/derive.ts +30 -3
  69. package/src/providers/registry.ts +39 -1
  70. package/src/proxy-liveness.ts +122 -0
  71. package/src/responses/parser.ts +1 -0
  72. package/src/responses/state.ts +83 -0
  73. package/src/router.ts +38 -23
  74. package/src/server/adapter-resolve.ts +3 -0
  75. package/src/server.ts +130 -18
  76. package/src/service.ts +94 -32
  77. package/src/types.ts +24 -1
  78. package/src/update-job.ts +360 -0
  79. package/src/update.ts +73 -11
  80. package/src/usage-log.ts +3 -3
  81. package/src/usage-summary.ts +3 -2
  82. package/src/win-paths.ts +68 -0
  83. package/gui/dist/assets/index-DIBiVVC0.css +0 -1
  84. package/gui/dist/assets/index-DcnD944i.js +0 -9
@@ -0,0 +1,25 @@
1
+ export interface CursorKvStore {
2
+ get(key: string): Uint8Array | undefined;
3
+ set(key: string, value: Uint8Array): void;
4
+ }
5
+
6
+ function cloneBytes(value: Uint8Array): Uint8Array {
7
+ return new Uint8Array(value);
8
+ }
9
+
10
+ export function createCursorKvStore(seed: Record<string, Uint8Array> = {}): CursorKvStore {
11
+ const values = new Map<string, Uint8Array>();
12
+ for (const [key, value] of Object.entries(seed)) {
13
+ values.set(key, cloneBytes(value));
14
+ }
15
+
16
+ return {
17
+ get(key) {
18
+ const value = values.get(key);
19
+ return value ? cloneBytes(value) : undefined;
20
+ },
21
+ set(key, value) {
22
+ values.set(key, cloneBytes(value));
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Live Cursor model discovery via the `GetUsableModels` RPC (HTTP/2 + Connect-unary protobuf).
3
+ *
4
+ * Returns the account's actually-usable model ids (the full effort-suffixed variants Cursor offers
5
+ * for THIS plan), so the routed catalog reflects reality instead of a static superset. Returns null on
6
+ * any failure (caller falls back to the static seed).
7
+ *
8
+ * Protocol notes (hard-won, see devlog 350.110):
9
+ * - content-type `application/proto` + `connect-protocol-version: 1` (NOT `application/connect+proto`,
10
+ * which the endpoint rejects with 415).
11
+ * - The request body is the EMPTY `GetUsableModelsRequest` → 0 bytes. It MUST be sent with `req.end()`
12
+ * and NO argument; `req.end(Buffer.alloc(0))` triggers `NGHTTP2_FRAME_SIZE_ERROR` on Bun, and a
13
+ * 5-byte gRPC/Connect frame makes the server mis-parse it ("illegal tag: field no 0").
14
+ */
15
+ import http2 from "node:http2";
16
+ import { fromBinary } from "@bufbuild/protobuf";
17
+ import { GetUsableModelsResponseSchema } from "./gen/agent_pb";
18
+
19
+ const CURSOR_GET_USABLE_MODELS_PATH = "/agent.v1.AgentService/GetUsableModels";
20
+ const CURSOR_DISCOVERY_CLIENT_VERSION = "cli-2026.02.13-41ac335";
21
+
22
+ export interface CursorUsableModelsOptions {
23
+ apiKey: string;
24
+ baseUrl?: string;
25
+ clientVersion?: string;
26
+ timeoutMs?: number;
27
+ }
28
+
29
+ export async function fetchCursorUsableModels(opts: CursorUsableModelsOptions): Promise<string[] | null> {
30
+ const baseUrl = (opts.baseUrl ?? "https://api2.cursor.sh").replace(/\/+$/, "");
31
+ const timeoutMs = opts.timeoutMs ?? 8000;
32
+
33
+ return new Promise<string[] | null>(resolve => {
34
+ let settled = false;
35
+ const finish = (value: string[] | null): void => {
36
+ if (settled) return;
37
+ settled = true;
38
+ resolve(value);
39
+ };
40
+
41
+ let client: http2.ClientHttp2Session;
42
+ try {
43
+ client = http2.connect(baseUrl);
44
+ } catch {
45
+ return finish(null);
46
+ }
47
+
48
+ const timer = setTimeout(() => {
49
+ client.destroy();
50
+ finish(null);
51
+ }, timeoutMs);
52
+ const close = (value: string[] | null): void => {
53
+ clearTimeout(timer);
54
+ client.close();
55
+ finish(value);
56
+ };
57
+
58
+ client.on("error", () => close(null));
59
+
60
+ const req = client.request({
61
+ ":method": "POST",
62
+ ":path": CURSOR_GET_USABLE_MODELS_PATH,
63
+ "content-type": "application/proto",
64
+ "connect-protocol-version": "1",
65
+ authorization: `Bearer ${opts.apiKey}`,
66
+ "x-ghost-mode": "true",
67
+ "x-cursor-client-version": opts.clientVersion ?? CURSOR_DISCOVERY_CLIENT_VERSION,
68
+ "x-cursor-client-type": "cli",
69
+ });
70
+
71
+ let status = 0;
72
+ const chunks: Buffer[] = [];
73
+ req.on("response", headers => {
74
+ status = Number(headers[":status"] ?? 0);
75
+ });
76
+ req.on("data", (chunk: Buffer) => chunks.push(chunk));
77
+ req.on("error", () => close(null));
78
+ req.on("end", () => {
79
+ if (status !== 200) return close(null);
80
+ try {
81
+ const response = fromBinary(GetUsableModelsResponseSchema, new Uint8Array(Buffer.concat(chunks)));
82
+ const ids = (response.models ?? [])
83
+ .map(model => (model as { modelId?: string }).modelId)
84
+ .filter((id): id is string => typeof id === "string" && id.length > 0);
85
+ close(ids.length > 0 ? ids : null);
86
+ } catch {
87
+ close(null);
88
+ }
89
+ });
90
+
91
+ req.end(); // CRITICAL: no body argument (empty Buffer breaks Bun's HTTP/2 framing).
92
+ });
93
+ }
@@ -0,0 +1,41 @@
1
+ export const CURSOR_LIVE_SMOKE_TOKEN_ENV = "OPENCODEX_CURSOR_TEST_TOKEN";
2
+ export const CURSOR_LIVE_SMOKE_BASE_URL_ENV = "OPENCODEX_CURSOR_TEST_BASE_URL";
3
+ export const CURSOR_LIVE_SMOKE_DEFAULT_BASE_URL = "https://api2.cursor.sh";
4
+
5
+ export interface CursorLiveSmokeGate {
6
+ enabled: boolean;
7
+ envName: string;
8
+ baseUrl: string;
9
+ skipReason?: string;
10
+ }
11
+
12
+ export function getCursorLiveSmokeToken(
13
+ env: Record<string, string | undefined> = process.env,
14
+ ): string | undefined {
15
+ const token = env[CURSOR_LIVE_SMOKE_TOKEN_ENV]?.trim();
16
+ return token ? token : undefined;
17
+ }
18
+
19
+ export function readCursorLiveSmokeGate(
20
+ env: Record<string, string | undefined> = process.env,
21
+ ): CursorLiveSmokeGate {
22
+ const baseUrl = env[CURSOR_LIVE_SMOKE_BASE_URL_ENV]?.trim() || CURSOR_LIVE_SMOKE_DEFAULT_BASE_URL;
23
+ if (!getCursorLiveSmokeToken(env)) {
24
+ return {
25
+ enabled: false,
26
+ envName: CURSOR_LIVE_SMOKE_TOKEN_ENV,
27
+ baseUrl,
28
+ skipReason: `${CURSOR_LIVE_SMOKE_TOKEN_ENV} is not set; live Cursor smoke is skipped.`,
29
+ };
30
+ }
31
+ return {
32
+ enabled: true,
33
+ envName: CURSOR_LIVE_SMOKE_TOKEN_ENV,
34
+ baseUrl,
35
+ };
36
+ }
37
+
38
+ export function cursorLiveSmokeSkipMessage(gate: CursorLiveSmokeGate = readCursorLiveSmokeGate()): string {
39
+ if (gate.enabled) return "Cursor live smoke credential is present.";
40
+ return gate.skipReason ?? `${gate.envName} is not set; live Cursor smoke is skipped.`;
41
+ }