@bitkyc08/opencodex 2.19.0 → 2.20.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 (119) hide show
  1. package/gui/dist/assets/index-DF_UFrGS.css +1 -0
  2. package/gui/dist/assets/index-DSK3S5HY.js +76 -0
  3. package/gui/dist/index.html +2 -2
  4. package/package.json +1 -1
  5. package/src/adapters/mimo-free.ts +17 -0
  6. package/src/adapters/openai-chat.ts +367 -32
  7. package/src/adapters/registry.ts +144 -0
  8. package/src/chat/inbound.ts +13 -7
  9. package/src/cli/claude.ts +2 -1
  10. package/src/cli/combo.ts +3 -0
  11. package/src/cli/dispatch.ts +8 -0
  12. package/src/cli/export-command.ts +2 -2
  13. package/src/cli/help.ts +2 -0
  14. package/src/cli/index.ts +3 -2
  15. package/src/cli/lab.ts +135 -1
  16. package/src/cli/minimax.ts +491 -0
  17. package/src/cli/models-runtime.ts +22 -1
  18. package/src/cli/models.ts +67 -2
  19. package/src/cli/opencode.ts +2 -1
  20. package/src/cli/registry.ts +22 -2
  21. package/src/clients/config-export.ts +125 -7
  22. package/src/codex/app-server-processes.ts +57 -2
  23. package/src/codex/app-server-restart-service.ts +232 -0
  24. package/src/codex/catalog/aggregation.ts +10 -1
  25. package/src/codex/catalog/effort.ts +15 -3
  26. package/src/codex/catalog/parsing.ts +3 -1
  27. package/src/codex/catalog/provider-fetch.ts +45 -5
  28. package/src/codex/catalog/sync.ts +74 -4
  29. package/src/codex/convergence.ts +2 -0
  30. package/src/combos/index.ts +1 -0
  31. package/src/combos/request.ts +30 -0
  32. package/src/combos/types.ts +6 -0
  33. package/src/config.ts +52 -0
  34. package/src/generated/compatibility-version.json +224 -76
  35. package/src/images/loop.ts +11 -1
  36. package/src/integrations/registry.ts +7 -0
  37. package/src/lab/conformance/jcs.ts +42 -2
  38. package/src/lab/conformance/negative-controls.ts +6 -2
  39. package/src/lab/conformance/runner.ts +16 -5
  40. package/src/lab/fabric/observe.ts +49 -14
  41. package/src/lab/index.ts +16 -0
  42. package/src/lab/ledger/purge.ts +152 -83
  43. package/src/lab/ledger/store.ts +168 -54
  44. package/src/lab/observe/from-conformance.ts +8 -6
  45. package/src/lab/observe/from-live.ts +8 -2
  46. package/src/lab/paths.ts +23 -0
  47. package/src/lab/public/bundle.ts +217 -0
  48. package/src/lab/public/community-authority.ts +175 -0
  49. package/src/lab/public/community-files.ts +29 -0
  50. package/src/lab/public/community.ts +479 -0
  51. package/src/lab/public/file-safety.ts +155 -0
  52. package/src/lab/public/ids.ts +26 -0
  53. package/src/lab/public/index.ts +16 -0
  54. package/src/lab/public/mutation-lock.ts +424 -0
  55. package/src/lab/public/operator.ts +353 -0
  56. package/src/lab/public/origin-purge.ts +79 -0
  57. package/src/lab/public/origin.ts +203 -0
  58. package/src/lab/public/privacy.ts +143 -0
  59. package/src/lab/public/private-file.ts +261 -0
  60. package/src/lab/public/project.ts +124 -0
  61. package/src/lab/public/purge-test-fault.ts +21 -0
  62. package/src/lab/public/purge.ts +223 -0
  63. package/src/lab/public/registry.ts +44 -0
  64. package/src/lab/public/revocation.ts +252 -0
  65. package/src/lab/public/signature.ts +219 -0
  66. package/src/lab/public/storage.ts +105 -0
  67. package/src/lab/public/strict-json.ts +206 -0
  68. package/src/lab/public/time.ts +26 -0
  69. package/src/lab/public/types.ts +172 -0
  70. package/src/lab/public/validate.ts +391 -0
  71. package/src/lib/codex-restart-contract.ts +120 -0
  72. package/src/lib/lab-activation.ts +109 -47
  73. package/src/lib/lab-live-pinned-sender.ts +16 -5
  74. package/src/lib/pinned-http.ts +70 -16
  75. package/src/lib/self-launch-argv.ts +15 -0
  76. package/src/lib/state-store-registrations.ts +2 -0
  77. package/src/lib/upstream-reachability.ts +4 -0
  78. package/src/lib/windows-elevation.ts +10 -1
  79. package/src/providers/derive.ts +24 -4
  80. package/src/providers/registry.ts +7 -3
  81. package/src/providers/request-pacing.ts +310 -0
  82. package/src/providers/service-tier.ts +143 -0
  83. package/src/providers/static-model-discovery.ts +86 -0
  84. package/src/reasoning-effort.ts +27 -1
  85. package/src/router.ts +23 -6
  86. package/src/routing/capability.ts +4 -2
  87. package/src/routing/compatibility/behavior.ts +5 -1
  88. package/src/server/adapter-resolve.ts +2 -32
  89. package/src/server/auth-cors.ts +8 -0
  90. package/src/server/chat-completions.ts +74 -36
  91. package/src/server/chat-native-sse.ts +331 -0
  92. package/src/server/chat-native.ts +371 -0
  93. package/src/server/management/combo-routes.ts +16 -2
  94. package/src/server/management/config-routes.ts +6 -4
  95. package/src/server/management/context.ts +17 -0
  96. package/src/server/management/lab-routes.ts +181 -19
  97. package/src/server/management/model-routes.ts +76 -2
  98. package/src/server/management/model-rows.ts +8 -0
  99. package/src/server/management/provider-capability-config.ts +48 -0
  100. package/src/server/management/provider-routes.ts +76 -4
  101. package/src/server/management/system-restart.ts +4 -2
  102. package/src/server/management/system-routes.ts +38 -0
  103. package/src/server/relay.ts +17 -3
  104. package/src/server/responses/compact.ts +4 -1
  105. package/src/server/responses/core.ts +257 -46
  106. package/src/server/responses/empty-completion-guard.ts +276 -0
  107. package/src/server/responses/fetch-helpers.ts +35 -4
  108. package/src/server/responses/pacing-overload.ts +13 -0
  109. package/src/server/responses/policy-fallback.ts +16 -2
  110. package/src/server/responses/terminal-guard.ts +1 -1
  111. package/src/server/responses/upstream-error.ts +5 -0
  112. package/src/server/responses.ts +17 -2
  113. package/src/types.ts +66 -4
  114. package/src/update/index.ts +6 -5
  115. package/src/update/job.ts +5 -6
  116. package/src/update/notify.ts +5 -3
  117. package/src/usage/log.ts +11 -1
  118. package/gui/dist/assets/index-CQ7bIKee.css +0 -1
  119. package/gui/dist/assets/index-D_JUZLEC.js +0 -76
@@ -8,11 +8,23 @@
8
8
  export class ChatCompletionsRequestError extends Error {}
9
9
 
10
10
  type Rec = Record<string, unknown>;
11
+ type ChatCompletionsRoutingBody = Rec & { model: string; messages: unknown[] };
11
12
 
12
13
  function isRec(v: unknown): v is Rec {
13
14
  return !!v && typeof v === "object" && !Array.isArray(v);
14
15
  }
15
16
 
17
+ /** Validate only the fields needed before Chat routing, without projecting the body. */
18
+ export function assertChatCompletionsRoutingBody(raw: unknown): asserts raw is ChatCompletionsRoutingBody {
19
+ if (!isRec(raw)) throw new ChatCompletionsRequestError("request body must be a JSON object");
20
+ if (typeof raw.model !== "string" || raw.model.length === 0) {
21
+ throw new ChatCompletionsRequestError("model is required");
22
+ }
23
+ if (!Array.isArray(raw.messages) || raw.messages.length === 0) {
24
+ throw new ChatCompletionsRequestError("messages must be a non-empty array");
25
+ }
26
+ }
27
+
16
28
  const OUTPUT_CONFIG_EFFORTS = new Set(["minimal", "low", "medium", "high", "xhigh", "max", "ultra"]);
17
29
  const OUTPUT_CONFIG_SUMMARIES = new Set(["auto", "concise", "detailed", "none"]);
18
30
 
@@ -227,13 +239,7 @@ function resolveReasoningSummary(raw: Rec): string | undefined {
227
239
  * Throws ChatCompletionsRequestError (-> 400) on malformed input.
228
240
  */
229
241
  export function chatCompletionsToResponsesBody(raw: unknown): Rec {
230
- if (!isRec(raw)) throw new ChatCompletionsRequestError("request body must be a JSON object");
231
- if (typeof raw.model !== "string" || raw.model.length === 0) {
232
- throw new ChatCompletionsRequestError("model is required");
233
- }
234
- if (!Array.isArray(raw.messages) || raw.messages.length === 0) {
235
- throw new ChatCompletionsRequestError("messages must be a non-empty array");
236
- }
242
+ assertChatCompletionsRoutingBody(raw);
237
243
 
238
244
  const systemParts: string[] = [];
239
245
  const input: Rec[] = [];
package/src/cli/claude.ts CHANGED
@@ -19,6 +19,7 @@ import { configuredAdminToken } from "../lib/admin-secrets";
19
19
  import { PROXY_MARKER, ownAdmissionTokens, defaultAuthDetectDeps, detectClaudeAuth, type AuthDetectDeps } from "../claude/auth-detect";
20
20
  import { resolveClaudeAuthMode } from "../claude/auth-mode";
21
21
  import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
22
+ import { selfLaunchArgv } from "../lib/self-launch-argv";
22
23
  import { ANTHROPIC_PARENT_ENV_SLOTS, trustedNodeLauncherContext, type AnthropicParentEnvSlot } from "./launcher-context";
23
24
 
24
25
  export interface ClaudeLaunchEnv {
@@ -269,7 +270,7 @@ async function ensureProxyForClaude(): Promise<number | null> {
269
270
  if (live) return live.port;
270
271
  const cfgPort = loadConfig().port;
271
272
  const pinPort = typeof cfgPort === "number" && cfgPort > 0 ? cfgPort : 10100;
272
- const child = spawn(process.execPath, [process.argv[1], "start", "--port", String(pinPort)], {
273
+ const child = spawn(process.execPath, selfLaunchArgv(["start", "--port", String(pinPort)]), {
273
274
  detached: true,
274
275
  stdio: "ignore",
275
276
  windowsHide: true,
package/src/cli/combo.ts CHANGED
@@ -91,6 +91,9 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
91
91
  if (alias !== undefined) combo.alias = alias === "-" ? "" : alias;
92
92
  if (nativeAlias) combo.nativeAlias = true;
93
93
  if (displayName !== undefined) combo.displayName = displayName === "-" ? "" : displayName;
94
+ const current = await runtimeRequest<{ combos?: ComboRow[] }>("/api/combos", {}, deps);
95
+ const existing = (current.combos ?? []).find(row => row.id === (renameFrom ?? id));
96
+ if (existing?.imageInput === "disabled") combo.imageInput = "disabled";
94
97
  const result = await runtimeRequest("/api/combos", {
95
98
  method: "PUT",
96
99
  body: JSON.stringify({ id, combo, ...(renameFrom ? { renameFrom } : {}) }),
@@ -488,6 +488,14 @@ const commandRunners: Record<string, CommandRunner> = {
488
488
  const { cmdOpencode } = await import("./opencode");
489
489
  return await cmdOpencode(deps.args.slice(1));
490
490
  },
491
+ mcode: async deps => {
492
+ const { cmdMcode } = await import("./minimax");
493
+ return await cmdMcode(deps.args.slice(1));
494
+ },
495
+ mmx: async deps => {
496
+ const { cmdMmx } = await import("./minimax");
497
+ return await cmdMmx(deps.args.slice(1));
498
+ },
491
499
  help: async () => {
492
500
  printUsage();
493
501
  return 0;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * `ocx export --client <id>` — print a client config for the live proxy.
3
3
  *
4
- * Seven clients, four formats: opencode and Pi are JSON, OMP, Hermes and Gajae
5
- * are YAML, OpenClaw JSON5, Kimi TOML.
4
+ * Eight clients, four formats: OpenCode and Pi are JSON; OMP, Hermes, Gajae and
5
+ * MiniMax Code are YAML; OpenClaw is JSON5; Kimi is TOML.
6
6
  *
7
7
  * Two consumers, one payload (devlog 260731_client_config_export/020):
8
8
  *
package/src/cli/help.ts CHANGED
@@ -67,6 +67,8 @@ Usage:
67
67
  ocx claude [args...] Launch Claude Code wired to the proxy (model discovery on)
68
68
  ocx claude desktop [sub] Manage and apply Claude Desktop's four-family profile
69
69
  ocx opencode [args...] Launch opencode wired to the proxy (runtime provider config)
70
+ ocx mcode [args...] Launch MiniMax Code through its managed provider
71
+ ocx mmx text <sub> [args] Launch MiniMax CLI text through the proxy
70
72
  ocx help [command] Show help
71
73
  ocx --version | -v Print version
72
74
 
package/src/cli/index.ts CHANGED
@@ -60,6 +60,7 @@ import { setIntegrationEnabled, shouldSyncCodexOnStart, shouldSyncGrokOnStart, s
60
60
 
61
61
  import { removeOwnedConfigState } from "../lib/config-ownership";
62
62
  import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
63
+ import { selfLaunchArgv } from "../lib/self-launch-argv";
63
64
  import { initializeNodeLauncherContext } from "./launcher-context";
64
65
  import { createLocalAttestationSecret } from "../lib/local-management-attestation";
65
66
  import { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../lib/system-restart-contract";
@@ -121,11 +122,11 @@ function grokSyncFailureMessage(err: unknown): string {
121
122
 
122
123
  /** Argv for detached `start`, optionally hard-pinning the listen port. */
123
124
  function startArgv(port?: number): string[] {
124
- const args = [process.argv[1], "start"];
125
+ const args = ["start"];
125
126
  if (typeof port === "number" && Number.isFinite(port) && port > 0 && port <= 65535) {
126
127
  args.push("--port", String(Math.trunc(port)));
127
128
  }
128
- return args;
129
+ return selfLaunchArgv(args);
129
130
  }
130
131
 
131
132
  async function chooseListenPort(requestedPort?: number): Promise<number> {
package/src/cli/lab.ts CHANGED
@@ -36,6 +36,7 @@ import {
36
36
  queryPassiveProductionSignals,
37
37
  type PassiveProductionQueryResultV1,
38
38
  } from "../lab/query";
39
+ import { isLabRouteSubjectId } from "../usage/log";
39
40
  import {
40
41
  CliUsageError,
41
42
  RuntimeApiError,
@@ -63,6 +64,14 @@ import { planManualLabRun } from "../lab/automation/planner";
63
64
  import { listLabAutomationRuns } from "../lab/automation/runs-query";
64
65
  import { LabAutomationError, type LabAutomationLayer } from "../lab/automation/types";
65
66
  import { createProductionLabRouteExecutor } from "../lib/lab-live-route-production";
67
+ import {
68
+ exportLocalPublicEvidence,
69
+ importCommunityEvidenceFile,
70
+ listCommunityEvidenceContext,
71
+ previewLocalPublicEvidence,
72
+ verifyPublicEvidenceFile,
73
+ type PublicVerificationSummaryV1,
74
+ } from "../lab/public";
66
75
 
67
76
  const USAGE = `Usage:
68
77
  ocx lab status [--json]
@@ -76,6 +85,11 @@ const USAGE = `Usage:
76
85
  ocx lab artifacts [--status <s>] [--artifact-class <c>] [--limit <n>] [--cursor <c>] [--json]
77
86
  ocx lab artifact <digest> [--json]
78
87
  ocx lab catalog [--layer <layer>] [--suite <id>] [--json]
88
+ ocx lab public preview --event <eventId> [--event <eventId> ...] [--json]
89
+ ocx lab public export --event <eventId> [--event <eventId> ...] [--json]
90
+ ocx lab public verify --file <bundle.json> [--json]
91
+ ocx lab public import --file <bundle.json> [--json]
92
+ ocx lab public community [--json]
79
93
  ocx lab automation status [--json]
80
94
  ocx lab automation enable [--protocol] [--live] [--json]
81
95
  ocx lab automation disable [--json]
@@ -223,6 +237,119 @@ function runListLines(page: ReturnType<typeof listLabAutomationRuns>): string[]
223
237
  return lines.length > 0 ? lines : ["No automation runs"];
224
238
  }
225
239
 
240
+ function takeRepeatedOptions(args: string[], flag: string): string[] {
241
+ const values: string[] = [];
242
+ while (true) {
243
+ const index = args.indexOf(flag);
244
+ if (index < 0) break;
245
+ const value = args[index + 1];
246
+ if (!value || value.startsWith("--")) {
247
+ throw new CliUsageError(`${flag} requires a value`, USAGE);
248
+ }
249
+ values.push(value);
250
+ args.splice(index, 2);
251
+ }
252
+ return values;
253
+ }
254
+
255
+ function publicPreviewLines(result: ReturnType<typeof previewLocalPublicEvidence>): string[] {
256
+ return [
257
+ `Public evidence preview: ${result.bundle.records.length} exportable record(s)`,
258
+ `Excluded: ${result.excluded.length}`,
259
+ "Unsigned local preview; no publisher key or remote publish is created.",
260
+ ];
261
+ }
262
+
263
+ function publicExportLines(result: ReturnType<typeof exportLocalPublicEvidence>): string[] {
264
+ return [
265
+ "Public evidence exported locally",
266
+ `Bundle: ${result.bundle.bundleId}`,
267
+ `Publisher: ${result.bundle.publisher.keyId}`,
268
+ `Path: ${result.stored.path}`,
269
+ `Excluded: ${result.excluded.length}`,
270
+ "No remote publish occurred.",
271
+ ];
272
+ }
273
+
274
+ function publicVerificationLines(result: PublicVerificationSummaryV1): string[] {
275
+ if (result.status !== "cryptographically_valid") {
276
+ return [
277
+ `Public evidence verification: ${result.status}`,
278
+ "Not locally verified.",
279
+ ];
280
+ }
281
+ return [
282
+ "Public evidence verification: cryptographically valid",
283
+ `Bundle: ${result.bundleId}`,
284
+ `Publisher: ${result.publisherKeyId}`,
285
+ "Not locally verified. Signature validity proves integrity/continuity only.",
286
+ ];
287
+ }
288
+
289
+ function handlePublicLabCommand(
290
+ argv: string[],
291
+ wantsJson: boolean,
292
+ configDir: string,
293
+ ): void {
294
+ const [action, ...restInput] = argv;
295
+ const rest = [...restInput];
296
+ switch (action) {
297
+ case "preview": {
298
+ const eventIds = takeRepeatedOptions(rest, "--event");
299
+ rejectArgs(rest, USAGE);
300
+ const result = previewLocalPublicEvidence({ eventIds }, configDir);
301
+ printData(result, wantsJson, publicPreviewLines(result));
302
+ return;
303
+ }
304
+ case "export": {
305
+ const eventIds = takeRepeatedOptions(rest, "--event");
306
+ rejectArgs(rest, USAGE);
307
+ const result = exportLocalPublicEvidence({ eventIds }, configDir);
308
+ printData(result, wantsJson, publicExportLines(result));
309
+ return;
310
+ }
311
+ case "verify": {
312
+ const path = takeOption(rest, "--file");
313
+ if (!path) throw new CliUsageError("public verify requires --file", USAGE);
314
+ rejectArgs(rest, USAGE);
315
+ const result = verifyPublicEvidenceFile(path);
316
+ printData(result, wantsJson, publicVerificationLines(result));
317
+ if (result.status !== "cryptographically_valid") {
318
+ throw new RuntimeApiError(`public evidence verification failed: ${result.status}`, 422, result);
319
+ }
320
+ return;
321
+ }
322
+ case "import": {
323
+ const path = takeOption(rest, "--file");
324
+ if (!path) throw new CliUsageError("public import requires --file", USAGE);
325
+ rejectArgs(rest, USAGE);
326
+ const result = importCommunityEvidenceFile(path, configDir);
327
+ printData(result, wantsJson, [
328
+ `Community evidence imported: ${result.bundleId}`,
329
+ `Publisher: ${result.publisherKeyId}`,
330
+ "Trust: community_untrusted_v1; not locally verified.",
331
+ ]);
332
+ return;
333
+ }
334
+ case "community": {
335
+ rejectArgs(rest, USAGE);
336
+ const result = listCommunityEvidenceContext(configDir);
337
+ const lines = result.evidence.length > 0
338
+ ? result.evidence.map((row) =>
339
+ `${row.bundleId} publisher=${row.publisherKeyId} active=${row.activeRecordCount} revoked=${row.revokedRecordCount}`,
340
+ )
341
+ : ["No community evidence"];
342
+ printData(result, wantsJson, [
343
+ "Community evidence (untrusted, read-only context; not locally verified)",
344
+ ...lines,
345
+ ]);
346
+ return;
347
+ }
348
+ default:
349
+ throw new CliUsageError("unknown public subcommand", USAGE);
350
+ }
351
+ }
352
+
226
353
  export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): Promise<number> {
227
354
  return runCliAction(async () => {
228
355
  const configDir = deps.configDir ?? getConfigDir();
@@ -232,6 +359,10 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
232
359
 
233
360
  try {
234
361
  switch (sub) {
362
+ case "public": {
363
+ handlePublicLabCommand(rest, wantsJson, configDir);
364
+ return;
365
+ }
235
366
  case "status": {
236
367
  rejectArgs(rest, USAGE);
237
368
  const status = queryLabStatus(configDir);
@@ -243,6 +374,9 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
243
374
  const limit = takeIntegerOption(rest, "--limit", { min: 1 });
244
375
  rejectArgs(rest, USAGE);
245
376
  if (!subjectId) throw new CliUsageError("--subject is required", USAGE);
377
+ if (!isLabRouteSubjectId(subjectId)) {
378
+ throw new CliUsageError("--subject must be an exact Lab route subject id", USAGE);
379
+ }
246
380
  const result = queryPassiveProductionSignals(subjectId, limit, configDir);
247
381
  printData(result, wantsJson, passiveProductionLines(result));
248
382
  return;
@@ -461,7 +595,7 @@ export async function handleLabCommand(argv: string[], deps: LabCliDeps = {}): P
461
595
  throw new CliUsageError(`unknown lab subcommand: ${sub}`, USAGE);
462
596
  }
463
597
  } catch (err) {
464
- if (err instanceof CliUsageError) throw err;
598
+ if (err instanceof CliUsageError || err instanceof RuntimeApiError) throw err;
465
599
  if (err instanceof LabProjectionUnavailableError || err instanceof LabProjectionIncompatibleError) {
466
600
  throw new LabStateError(labErrorMessage(err));
467
601
  }