@maximoai/maximo-syntax-cli 0.1.23 → 0.1.24

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 (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.mjs +672 -32
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -210,6 +210,8 @@ maximo login
210
210
  | **Maximo AI account** | First-party Maximo AI subscription/pro API key | Default provider; routes through `https://api.maximoai.co/v1`. |
211
211
  | **MyTabulon Coding Plan** | MyTabulon platform API key (`mtb_live_…`) | Sign in via browser OAuth or paste a `mtb_live_` key. |
212
212
  | **Cencori** | Cencori OpenAI-compatible API key (`csk_…`) | Cencori is OpenAI-compatible, so chat and models go through `https://api.cencori.com/v1`. Paste your `csk_` key at the prompt — the key is saved to your global config and used for all API calls. |
213
+ | **OpenRouter** | OpenRouter API key | Uses `https://openrouter.ai/api/v1/chat/completions` and loads models from `https://openrouter.ai/api/v1/models`. |
214
+ | **OpenCode** | OpenCode Zen or Go API key | Choose Zen or Go, then use the corresponding Chat Completions endpoint and model catalog from `https://opencode.ai/zen/v1` or `https://opencode.ai/zen/go/v1`. |
213
215
  | **3rd-party platform** | OpenAI, Gemini, Bedrock, Ollama, and more | Set the relevant environment variables and restart. See [Alternative Providers](#alternative-providers). |
214
216
 
215
217
  To switch providers (e.g. to Cencori) at any time, run `maximo login` again and choose the provider you want.
package/dist/cli.mjs CHANGED
@@ -108411,6 +108411,42 @@ var init_betas = __esm(() => {
108411
108411
  });
108412
108412
 
108413
108413
  // src/services/api/maximoModels.ts
108414
+ function normalizedBaseUrl(baseUrl) {
108415
+ return (baseUrl || "").replace(/\/+$/, "").toLowerCase();
108416
+ }
108417
+ function getOpenCodePlanForBaseUrl(baseUrl) {
108418
+ const normalized = normalizedBaseUrl(baseUrl);
108419
+ if (normalized === OPENCODE_GO_BASE_URL)
108420
+ return "go";
108421
+ if (normalized === OPENCODE_ZEN_BASE_URL)
108422
+ return "zen";
108423
+ return;
108424
+ }
108425
+ function getOpenAICompatibleProviderForBaseUrl(baseUrl) {
108426
+ const normalized = normalizedBaseUrl(baseUrl);
108427
+ if (normalized.includes("api.mytabulon.com"))
108428
+ return "mytabulon";
108429
+ if (normalized.includes("api.cencori.com"))
108430
+ return "cencori";
108431
+ if (normalized.includes("maximoai.co"))
108432
+ return "maximoai";
108433
+ if (normalized === OPENROUTER_BASE_URL)
108434
+ return "openrouter";
108435
+ if (getOpenCodePlanForBaseUrl(normalized))
108436
+ return "opencode";
108437
+ return;
108438
+ }
108439
+ function isOpenCodeChatCompletionModel(model, plan) {
108440
+ return OPENCODE_CHAT_COMPLETION_MODELS[plan].has(model.id);
108441
+ }
108442
+ function fallbackModelForProvider(provider) {
108443
+ if (provider === "openrouter")
108444
+ return "openai/gpt-5.4";
108445
+ return "deepseek-v4-flash";
108446
+ }
108447
+ function chooseOpenRouterDefaultModel(models) {
108448
+ return models.find((model) => model.id === "openai/gpt-5.4")?.id || models.find((model) => model.architecture?.output_modalities?.includes("text") && model.supported_parameters?.includes("tools"))?.id || models[0]?.id || fallbackModelForProvider("openrouter");
108449
+ }
108414
108450
  function firstPositiveInteger(...values) {
108415
108451
  for (const value of values) {
108416
108452
  if (typeof value === "number" && Number.isFinite(value) && value > 0) {
@@ -108504,6 +108540,9 @@ function isMaximoAIProviderInternal() {
108504
108540
  if (isCencoriProvider()) {
108505
108541
  return true;
108506
108542
  }
108543
+ if (isOpenRouterProvider() || isOpenCodeProvider()) {
108544
+ return true;
108545
+ }
108507
108546
  const oauthTokens = getMaximoAIOAuthTokens();
108508
108547
  if (oauthTokens?.accessToken && isMaximoAISubscriber()) {
108509
108548
  return true;
@@ -108522,10 +108561,22 @@ function isCencoriProvider() {
108522
108561
  const hasOpenAIConfig = process.env.MAXIMO_SYNTAX_USE_OPENAI === "1" || process.env.MAXIMO_SYNTAX_USE_OPENAI === "true" || Boolean(globalConfig2.cencoriApiKey);
108523
108562
  return hasOpenAIConfig && baseUrl.includes("api.cencori.com");
108524
108563
  }
108564
+ function isOpenRouterProvider() {
108565
+ const globalConfig2 = getGlobalConfig();
108566
+ const baseUrl = process.env.OPENAI_BASE_URL || globalConfig2.openAIBaseUrl || "";
108567
+ const hasOpenAIConfig = process.env.MAXIMO_SYNTAX_USE_OPENAI === "1" || process.env.MAXIMO_SYNTAX_USE_OPENAI === "true" || Boolean(globalConfig2.maximoApiKey);
108568
+ return hasOpenAIConfig && getOpenAICompatibleProviderForBaseUrl(baseUrl) === "openrouter";
108569
+ }
108570
+ function isOpenCodeProvider() {
108571
+ const globalConfig2 = getGlobalConfig();
108572
+ const baseUrl = process.env.OPENAI_BASE_URL || globalConfig2.openAIBaseUrl || "";
108573
+ const hasOpenAIConfig = process.env.MAXIMO_SYNTAX_USE_OPENAI === "1" || process.env.MAXIMO_SYNTAX_USE_OPENAI === "true" || Boolean(globalConfig2.maximoApiKey);
108574
+ return hasOpenAIConfig && getOpenAICompatibleProviderForBaseUrl(baseUrl) === "opencode";
108575
+ }
108525
108576
  function getMaximoAIBaseUrl() {
108526
108577
  const globalConfig2 = getGlobalConfig();
108527
108578
  const configuredBaseUrl = globalConfig2.openAIBaseUrl || process.env.OPENAI_BASE_URL;
108528
- return configuredBaseUrl?.includes("maximoai.co") || configuredBaseUrl?.includes("api.mytabulon.com") || configuredBaseUrl?.includes("api.cencori.com") ? configuredBaseUrl : "https://api.maximoai.co/v1";
108579
+ return configuredBaseUrl?.includes("maximoai.co") || configuredBaseUrl?.includes("api.mytabulon.com") || configuredBaseUrl?.includes("api.cencori.com") || configuredBaseUrl?.includes("openrouter.ai/api/v1") || configuredBaseUrl?.includes("opencode.ai/zen/") ? configuredBaseUrl : "https://api.maximoai.co/v1";
108529
108580
  }
108530
108581
  function getMaximoApiKey() {
108531
108582
  const globalConfig2 = getGlobalConfig();
@@ -108561,7 +108612,13 @@ async function fetchMaximoModels({
108561
108612
  if (!Array.isArray(models)) {
108562
108613
  throw new Error("Failed to fetch models: malformed response");
108563
108614
  }
108564
- const sortedModels = baseUrl.includes("api.mytabulon.com") ? [...models] : [...models].sort((a2, b) => {
108615
+ const provider = getOpenAICompatibleProviderForBaseUrl(baseUrl);
108616
+ const openCodePlan = getOpenCodePlanForBaseUrl(baseUrl);
108617
+ const compatibleModels = provider === "opencode" && openCodePlan ? models.filter((model) => isOpenCodeChatCompletionModel(model, openCodePlan)) : models;
108618
+ if (provider === "opencode" && compatibleModels.length === 0) {
108619
+ throw new Error(`OpenCode ${openCodePlan === "go" ? "Go" : "Zen"} returned no models supported by its Chat Completions endpoint.`);
108620
+ }
108621
+ const sortedModels = provider === "mytabulon" || provider === "openrouter" || provider === "opencode" ? [...compatibleModels] : [...compatibleModels].sort((a2, b) => {
108565
108622
  const aIsPandora = a2.id.includes("pandora");
108566
108623
  const bIsPandora = b.id.includes("pandora");
108567
108624
  if (aIsPandora && !bIsPandora)
@@ -108595,7 +108652,7 @@ async function fetchMaximoModels({
108595
108652
  if (throwOnError) {
108596
108653
  throw error41;
108597
108654
  }
108598
- return cachedModels || [];
108655
+ return cachedModelsBaseUrl === baseUrl ? cachedModels || [] : [];
108599
108656
  }
108600
108657
  }
108601
108658
  function clearMaximoModelsCache() {
@@ -108645,10 +108702,7 @@ async function getMaximoModelOptions() {
108645
108702
  if (models.length === 0) {
108646
108703
  return null;
108647
108704
  }
108648
- if (isMyTabulonProvider()) {
108649
- return models.map(toModelOption);
108650
- }
108651
- if (isCencoriProvider()) {
108705
+ if (isMyTabulonProvider() || isCencoriProvider() || isOpenRouterProvider() || isOpenCodeProvider()) {
108652
108706
  return models.map(toModelOption);
108653
108707
  }
108654
108708
  const groupedModels = {};
@@ -108771,8 +108825,12 @@ function persistMyTabulonState(apiKey, baseUrl, models, account) {
108771
108825
  ...current,
108772
108826
  maximoApiKey: apiKey,
108773
108827
  openAIBaseUrl: baseUrl,
108828
+ openAIProvider: "mytabulon",
108829
+ openCodePlan: undefined,
108830
+ openAIModel: undefined,
108774
108831
  mytabulonDefaultModel: defaultModel,
108775
- mytabulonAccount: account
108832
+ mytabulonAccount: account,
108833
+ cencoriApiKey: undefined
108776
108834
  }));
108777
108835
  }
108778
108836
  async function configureMyTabulonProvider(apiKey) {
@@ -108810,8 +108868,11 @@ function persistCencoriState(apiKey, baseUrl, model) {
108810
108868
  saveGlobalConfig((current) => ({
108811
108869
  ...current,
108812
108870
  cencoriApiKey: apiKey,
108871
+ maximoApiKey: apiKey,
108813
108872
  openAIBaseUrl: baseUrl,
108873
+ openAIProvider: "cencori",
108814
108874
  openAIModel: model ?? current.openAIModel,
108875
+ openCodePlan: undefined,
108815
108876
  mytabulonDefaultModel: undefined,
108816
108877
  mytabulonAccount: undefined
108817
108878
  }));
@@ -108845,17 +108906,145 @@ async function configureCencoriProvider(apiKey) {
108845
108906
  };
108846
108907
  }
108847
108908
  }
108909
+ function persistExternalProviderState({
108910
+ apiKey,
108911
+ baseUrl,
108912
+ provider,
108913
+ plan,
108914
+ model
108915
+ }) {
108916
+ const defaultModel = model || fallbackModelForProvider(provider);
108917
+ process.env.MAXIMO_SYNTAX_USE_OPENAI = "1";
108918
+ process.env.OPENAI_API_KEY = apiKey;
108919
+ process.env.OPENAI_BASE_URL = baseUrl;
108920
+ process.env.OPENAI_MODEL = defaultModel;
108921
+ saveGlobalConfig((current) => ({
108922
+ ...current,
108923
+ maximoApiKey: apiKey,
108924
+ openAIBaseUrl: baseUrl,
108925
+ openAIProvider: provider,
108926
+ openAIModel: defaultModel,
108927
+ openCodePlan: provider === "opencode" ? plan : undefined,
108928
+ cencoriApiKey: undefined,
108929
+ mytabulonDefaultModel: undefined,
108930
+ mytabulonAccount: undefined,
108931
+ oauthAccount: undefined
108932
+ }));
108933
+ }
108934
+ async function configureExternalProvider({
108935
+ apiKey,
108936
+ baseUrl,
108937
+ provider,
108938
+ plan
108939
+ }) {
108940
+ const trimmedKey = apiKey.trim();
108941
+ if (!trimmedKey) {
108942
+ throw new Error(`Enter your ${provider === "openrouter" ? "OpenRouter" : "OpenCode"} API key.`);
108943
+ }
108944
+ clearMaximoModelsCache();
108945
+ try {
108946
+ const models = await fetchMaximoModels({
108947
+ baseUrl,
108948
+ apiKey: trimmedKey,
108949
+ forceRefresh: true,
108950
+ persistMyTabulonAccount: false,
108951
+ throwOnError: true
108952
+ });
108953
+ if (models.length === 0) {
108954
+ throw new Error("The provider returned no usable Chat Completions models.");
108955
+ }
108956
+ const defaultModel = provider === "openrouter" ? chooseOpenRouterDefaultModel(models) : models[0]?.id || fallbackModelForProvider(provider);
108957
+ persistExternalProviderState({
108958
+ apiKey: trimmedKey,
108959
+ baseUrl,
108960
+ provider,
108961
+ plan,
108962
+ model: defaultModel
108963
+ });
108964
+ return { models, defaultModel };
108965
+ } catch (error41) {
108966
+ if (error41 instanceof Error && /Failed to fetch models: (401|403)\b/.test(error41.message)) {
108967
+ throw error41;
108968
+ }
108969
+ const fallbackModel = fallbackModelForProvider(provider);
108970
+ persistExternalProviderState({
108971
+ apiKey: trimmedKey,
108972
+ baseUrl,
108973
+ provider,
108974
+ plan,
108975
+ model: fallbackModel
108976
+ });
108977
+ const providerLabel = provider === "openrouter" ? "OpenRouter" : `OpenCode ${plan === "go" ? "Go" : "Zen"}`;
108978
+ const reason = error41 instanceof Error ? error41.message : "unknown error";
108979
+ return {
108980
+ models: [],
108981
+ defaultModel: fallbackModel,
108982
+ warning: `Connected to ${providerLabel}, but couldn't read the model list ` + `(${reason}). You're logged in — refresh the model list before choosing a model.`
108983
+ };
108984
+ }
108985
+ }
108986
+ function configureOpenRouterProvider(apiKey) {
108987
+ return configureExternalProvider({
108988
+ apiKey,
108989
+ baseUrl: OPENROUTER_BASE_URL,
108990
+ provider: "openrouter"
108991
+ });
108992
+ }
108993
+ function configureOpenCodeProvider(apiKey, plan = "zen") {
108994
+ return configureExternalProvider({
108995
+ apiKey,
108996
+ baseUrl: plan === "go" ? OPENCODE_GO_BASE_URL : OPENCODE_ZEN_BASE_URL,
108997
+ provider: "opencode",
108998
+ plan
108999
+ });
109000
+ }
108848
109001
  function prefetchMaximoModels() {
108849
109002
  if (isMaximoAIProviderInternal()) {
108850
109003
  fetchMaximoModels();
108851
109004
  }
108852
109005
  }
108853
- var cachedModels = null, lastFetchTime = 0, cachedModelsBaseUrl = null, cachedMyTabulonAccount = null, CACHE_TTL, MYTABULON_BASE_URL = "https://api.mytabulon.com/v1", CENCORI_BASE_URL = "https://api.cencori.com/v1";
109006
+ var cachedModels = null, lastFetchTime = 0, cachedModelsBaseUrl = null, cachedMyTabulonAccount = null, CACHE_TTL, MYTABULON_BASE_URL = "https://api.mytabulon.com/v1", CENCORI_BASE_URL = "https://api.cencori.com/v1", OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1", OPENCODE_ZEN_BASE_URL = "https://opencode.ai/zen/v1", OPENCODE_GO_BASE_URL = "https://opencode.ai/zen/go/v1", OPENCODE_CHAT_COMPLETION_MODELS;
108854
109007
  var init_maximoModels = __esm(() => {
108855
109008
  init_config2();
108856
109009
  init_log3();
108857
109010
  init_auth2();
108858
109011
  CACHE_TTL = 5 * 60 * 1000;
109012
+ OPENCODE_CHAT_COMPLETION_MODELS = {
109013
+ zen: new Set([
109014
+ "deepseek-v4-pro",
109015
+ "deepseek-v4-flash",
109016
+ "minimax-m3",
109017
+ "minimax-m2.7",
109018
+ "minimax-m2.5",
109019
+ "glm-5.2",
109020
+ "glm-5.1",
109021
+ "glm-5",
109022
+ "kimi-k2.5",
109023
+ "kimi-k2.6",
109024
+ "kimi-k2.7-code",
109025
+ "kimi-k3",
109026
+ "big-pickle",
109027
+ "mimo-v2.5-free",
109028
+ "laguna-s-2.1-free",
109029
+ "ling-3.0-flash-free",
109030
+ "north-mini-code-free",
109031
+ "nemotron-3-ultra-free",
109032
+ "deepseek-v4-flash-free"
109033
+ ]),
109034
+ go: new Set([
109035
+ "grok-4.5",
109036
+ "glm-5.2",
109037
+ "glm-5.1",
109038
+ "kimi-k3",
109039
+ "kimi-k2.7-code",
109040
+ "kimi-k2.6",
109041
+ "deepseek-v4-pro",
109042
+ "deepseek-v4-flash",
109043
+ "mimo-v2.5",
109044
+ "mimo-v2.5-pro",
109045
+ "hy3"
109046
+ ])
109047
+ };
108859
109048
  });
108860
109049
 
108861
109050
  // src/utils/fastMode.ts
@@ -109490,6 +109679,12 @@ function getOpenAIProviderDefaultModel(fallback) {
109490
109679
  if (baseUrl.includes("maximoai.co")) {
109491
109680
  return "maximo-pandora-3.8-nano";
109492
109681
  }
109682
+ if (baseUrl.includes("openrouter.ai/api/v1")) {
109683
+ return globalConfig2.openAIModel || "openai/gpt-5.4";
109684
+ }
109685
+ if (baseUrl.includes("opencode.ai/zen/")) {
109686
+ return globalConfig2.openAIModel || "deepseek-v4-flash";
109687
+ }
109493
109688
  return fallback;
109494
109689
  }
109495
109690
  function getSmallFastModel() {
@@ -110662,6 +110857,25 @@ function convertContentBlocks(content) {
110662
110857
  }
110663
110858
  break;
110664
110859
  }
110860
+ case "document": {
110861
+ const src = block.source;
110862
+ const filename = typeof block.title === "string" && block.title ? block.title : src?.media_type === "application/pdf" ? "attachment.pdf" : "attachment";
110863
+ if (src?.type === "base64" && src.media_type && src.data) {
110864
+ parts.push({
110865
+ type: "file",
110866
+ file: {
110867
+ filename,
110868
+ file_data: `data:${src.media_type};base64,${src.data}`
110869
+ }
110870
+ });
110871
+ } else if (src?.type === "url" && src.url) {
110872
+ parts.push({
110873
+ type: "file",
110874
+ file: { filename, file_data: src.url }
110875
+ });
110876
+ }
110877
+ break;
110878
+ }
110665
110879
  case "tool_use":
110666
110880
  break;
110667
110881
  case "tool_result":
@@ -110993,6 +111207,88 @@ async function* openaiStreamToAnthropic(response, model) {
110993
111207
  }
110994
111208
  yield { type: "message_stop" };
110995
111209
  }
111210
+ async function* bufferedMessageToAnthropic(message) {
111211
+ let contentBlockIndex = 0;
111212
+ const hasToolUse = message.content.some((block) => block.type === "tool_use");
111213
+ yield {
111214
+ type: "message_start",
111215
+ message: {
111216
+ id: message.id,
111217
+ type: "message",
111218
+ role: "assistant",
111219
+ content: [],
111220
+ model: message.model,
111221
+ stop_reason: null,
111222
+ stop_sequence: null,
111223
+ usage: {
111224
+ input_tokens: 0,
111225
+ output_tokens: 0,
111226
+ cache_creation_input_tokens: 0,
111227
+ cache_read_input_tokens: 0
111228
+ }
111229
+ }
111230
+ };
111231
+ for (const block of message.content) {
111232
+ if (block.type === "text" && typeof block.text === "string") {
111233
+ const index = contentBlockIndex++;
111234
+ yield {
111235
+ type: "content_block_start",
111236
+ index,
111237
+ content_block: { type: "text", text: "" }
111238
+ };
111239
+ if (block.text) {
111240
+ yield {
111241
+ type: "content_block_delta",
111242
+ index,
111243
+ delta: { type: "text_delta", text: block.text }
111244
+ };
111245
+ }
111246
+ yield { type: "content_block_stop", index };
111247
+ continue;
111248
+ }
111249
+ if (block.type === "tool_use") {
111250
+ const index = contentBlockIndex++;
111251
+ const id = typeof block.id === "string" ? block.id : `call_${makeMessageId2()}`;
111252
+ const name = typeof block.name === "string" ? block.name : "unknown";
111253
+ const input = JSON.stringify(block.input ?? {});
111254
+ yield {
111255
+ type: "content_block_start",
111256
+ index,
111257
+ content_block: {
111258
+ type: "tool_use",
111259
+ id,
111260
+ name,
111261
+ input: {}
111262
+ }
111263
+ };
111264
+ yield {
111265
+ type: "content_block_delta",
111266
+ index,
111267
+ delta: { type: "input_json_delta", partial_json: input }
111268
+ };
111269
+ yield { type: "content_block_stop", index };
111270
+ }
111271
+ }
111272
+ yield {
111273
+ type: "message_delta",
111274
+ delta: {
111275
+ stop_reason: hasToolUse ? "tool_use" : message.stop_reason,
111276
+ stop_sequence: null
111277
+ },
111278
+ usage: message.usage
111279
+ };
111280
+ yield { type: "message_stop" };
111281
+ }
111282
+ function containsImageContent(value) {
111283
+ if (Array.isArray(value))
111284
+ return value.some(containsImageContent);
111285
+ if (!value || typeof value !== "object")
111286
+ return false;
111287
+ const record2 = value;
111288
+ if (record2.type === "image")
111289
+ return true;
111290
+ return containsImageContent(record2.content) || containsImageContent(record2.message);
111291
+ }
110996
111292
 
110997
111293
  class OpenAIShimMessages {
110998
111294
  defaultHeaders;
@@ -111006,12 +111302,19 @@ class OpenAIShimMessages {
111006
111302
  const promise2 = (async () => {
111007
111303
  const request = resolveProviderRequest({ model: params.model });
111008
111304
  const requestControl = createRequestControl(options?.signal, self2.timeout);
111305
+ const bufferVisionResponse = params.stream === true && request.transport === "chat_completions" && containsImageContent(params.messages);
111306
+ const requestParams = bufferVisionResponse ? { ...params, stream: false } : params;
111009
111307
  try {
111010
- const response = await self2._doRequest(request, params, {
111308
+ const response = await self2._doRequest(request, requestParams, {
111011
111309
  ...options,
111012
111310
  signal: requestControl.signal
111013
111311
  });
111014
111312
  if (params.stream) {
111313
+ if (bufferVisionResponse) {
111314
+ const data2 = await response.json();
111315
+ const message = self2._convertNonStreamingResponse(data2, request.resolvedModel);
111316
+ return new OpenAIShimStream(bufferedMessageToAnthropic(message), requestControl.controller, requestControl.dispose);
111317
+ }
111015
111318
  return new OpenAIShimStream(request.transport === "codex_responses" ? codexStreamToAnthropic(response, request.resolvedModel) : openaiStreamToAnthropic(response, request.resolvedModel), requestControl.controller, requestControl.dispose);
111016
111319
  }
111017
111320
  let data;
@@ -111111,6 +111414,10 @@ class OpenAIShimMessages {
111111
111414
  if (apiKey) {
111112
111415
  headers.Authorization = `Bearer ${apiKey}`;
111113
111416
  }
111417
+ if (/openrouter\.ai\/api\/v1/i.test(request.baseUrl)) {
111418
+ headers["HTTP-Referer"] = "https://maximoai.co";
111419
+ headers["X-OpenRouter-Title"] = "Maximo Syntax";
111420
+ }
111114
111421
  const response = await fetch(`${request.baseUrl}/chat/completions`, {
111115
111422
  method: "POST",
111116
111423
  headers,
@@ -111119,7 +111426,7 @@ class OpenAIShimMessages {
111119
111426
  });
111120
111427
  if (!response.ok) {
111121
111428
  const errorBody = await response.text().catch(() => "unknown error");
111122
- throw new Error(`MaximoAI API error ${response.status}: ${errorBody}`);
111429
+ throw new Error(`OpenAI-compatible API error ${response.status}: ${errorBody}`);
111123
111430
  }
111124
111431
  return response;
111125
111432
  }
@@ -123670,7 +123977,7 @@ var init_metadata = __esm(() => {
123670
123977
  isMaximoAiAuth: isMaximoAISubscriber(),
123671
123978
  version: "99.0.0",
123672
123979
  versionBase: getVersionBase(),
123673
- buildTime: "2026-08-03T12:06:47.158Z",
123980
+ buildTime: "2026-08-04T01:30:08.298Z",
123674
123981
  deploymentEnvironment: env3.detectDeploymentEnvironment(),
123675
123982
  ...isEnvTruthy(process.env.GITHUB_ACTIONS) && {
123676
123983
  githubEventName: process.env.GITHUB_EVENT_NAME,
@@ -125938,8 +126245,10 @@ var init_config2 = __esm(() => {
125938
126245
  "remoteDialogSeen",
125939
126246
  "maximoApiKey",
125940
126247
  "openAIBaseUrl",
126248
+ "openAIProvider",
125941
126249
  "cencoriApiKey",
125942
- "openAIModel"
126250
+ "openAIModel",
126251
+ "openCodePlan"
125943
126252
  ];
125944
126253
  PROJECT_CONFIG_KEYS = [
125945
126254
  "allowedTools",
@@ -178086,6 +178395,22 @@ async function maybeResizeAndDownsampleImageBuffer(imageBuffer, originalSize, ex
178086
178395
  if (imageBuffer.length === 0) {
178087
178396
  throw new ImageResizeError("Image file is empty (0 bytes)");
178088
178397
  }
178398
+ const base64SizeBeforeProcessing = Math.ceil(originalSize * 4 / 3);
178399
+ if (base64SizeBeforeProcessing <= API_IMAGE_MAX_BASE64_SIZE) {
178400
+ const detected = detectImageFormatFromBuffer(imageBuffer);
178401
+ const detectedFormat = detected.slice(6);
178402
+ const dimensions = detectImageDimensionsFromBuffer(imageBuffer);
178403
+ return {
178404
+ buffer: imageBuffer,
178405
+ mediaType: detectedFormat === "jpg" ? "jpeg" : detectedFormat,
178406
+ dimensions: dimensions ? {
178407
+ originalWidth: dimensions.width,
178408
+ originalHeight: dimensions.height,
178409
+ displayWidth: dimensions.width,
178410
+ displayHeight: dimensions.height
178411
+ } : undefined
178412
+ };
178413
+ }
178089
178414
  try {
178090
178415
  const sharp = await getImageProcessor();
178091
178416
  const image = sharp(imageBuffer);
@@ -178242,7 +178567,7 @@ async function maybeResizeAndDownsampleImageBuffer(imageBuffer, originalSize, ex
178242
178567
  const dimensions = detectImageDimensionsFromBuffer(imageBuffer);
178243
178568
  const base64Size = Math.ceil(originalSize * 4 / 3);
178244
178569
  const overDim = imageBuffer.length >= 24 && imageBuffer[0] === 137 && imageBuffer[1] === 80 && imageBuffer[2] === 78 && imageBuffer[3] === 71 && (imageBuffer.readUInt32BE(16) > IMAGE_MAX_WIDTH || imageBuffer.readUInt32BE(20) > IMAGE_MAX_HEIGHT);
178245
- if (base64Size <= API_IMAGE_MAX_BASE64_SIZE && !overDim) {
178570
+ if (base64Size <= API_IMAGE_MAX_BASE64_SIZE) {
178246
178571
  logEvent("tengu_image_resize_fallback", {
178247
178572
  original_size_bytes: originalSize,
178248
178573
  base64_size_bytes: base64Size,
@@ -274216,8 +274541,12 @@ async function performLogout({
274216
274541
  updated.oauthAccount = undefined;
274217
274542
  updated.maximoApiKey = undefined;
274218
274543
  updated.openAIBaseUrl = undefined;
274544
+ updated.openAIProvider = undefined;
274219
274545
  updated.mytabulonDefaultModel = undefined;
274220
274546
  updated.mytabulonAccount = undefined;
274547
+ updated.openCodePlan = undefined;
274548
+ updated.cencoriApiKey = undefined;
274549
+ updated.openAIModel = undefined;
274221
274550
  return updated;
274222
274551
  });
274223
274552
  }
@@ -276413,7 +276742,7 @@ import { access as access3, writeFile as writeFile13 } from "fs/promises";
276413
276742
  import { homedir as homedir22 } from "os";
276414
276743
  import { join as join65 } from "path";
276415
276744
  function getCurrentRealVersion() {
276416
- return "0.1.23";
276745
+ return "0.1.24";
276417
276746
  }
276418
276747
  async function getRolloutConfig() {
276419
276748
  try {
@@ -277845,8 +278174,10 @@ async function installOAuthTokens(tokens) {
277845
278174
  ...current,
277846
278175
  maximoApiKey: tokens.accessToken,
277847
278176
  openAIBaseUrl: "https://api.maximoai.co/v1",
278177
+ openAIProvider: "maximoai",
277848
278178
  mytabulonDefaultModel: undefined,
277849
- mytabulonAccount: undefined
278179
+ mytabulonAccount: undefined,
278180
+ openCodePlan: undefined
277850
278181
  }));
277851
278182
  process.env.MAXIMO_SYNTAX_USE_OPENAI = "true";
277852
278183
  process.env.OPENAI_BASE_URL = "https://api.maximoai.co/v1";
@@ -277864,8 +278195,46 @@ async function authLogin({
277864
278195
  email: email3,
277865
278196
  sso,
277866
278197
  console: useConsole,
277867
- maximoai
278198
+ maximoai,
278199
+ openrouter,
278200
+ opencode,
278201
+ opencodePlan,
278202
+ apiKey
277868
278203
  }) {
278204
+ if (openrouter || opencode) {
278205
+ if (useConsole || maximoai || sso || openrouter && opencode) {
278206
+ process.stderr.write(`Error: choose exactly one OpenAI-compatible provider for this login.
278207
+ `);
278208
+ process.exit(1);
278209
+ }
278210
+ if (!apiKey?.trim()) {
278211
+ process.stderr.write(`Error: an API key is required. Use --api-key or the interactive /login flow.
278212
+ `);
278213
+ process.exit(1);
278214
+ }
278215
+ if (opencodePlan && opencodePlan !== "zen" && opencodePlan !== "go") {
278216
+ process.stderr.write(`Error: --opencode-plan must be zen or go.
278217
+ `);
278218
+ process.exit(1);
278219
+ }
278220
+ try {
278221
+ const result = openrouter ? await configureOpenRouterProvider(apiKey) : await configureOpenCodeProvider(apiKey, opencodePlan ?? "zen");
278222
+ if (result.warning)
278223
+ process.stderr.write(`${result.warning}
278224
+ `);
278225
+ saveGlobalConfig((current) => ({
278226
+ ...current,
278227
+ hasCompletedOnboarding: true
278228
+ }));
278229
+ process.stdout.write(`Login successful.
278230
+ `);
278231
+ process.exit(0);
278232
+ } catch (err2) {
278233
+ process.stderr.write(`Login failed: ${errorMessage(err2)}
278234
+ `);
278235
+ process.exit(1);
278236
+ }
278237
+ }
277869
278238
  if (useConsole && maximoai) {
277870
278239
  process.stderr.write(`Error: --console and --maximoai cannot be used together.
277871
278240
  `);
@@ -278041,6 +278410,7 @@ var init_auth7 = __esm(() => {
278041
278410
  init_analytics();
278042
278411
  init_errorUtils();
278043
278412
  init_firstTokenDate();
278413
+ init_maximoModels();
278044
278414
  init_client2();
278045
278415
  init_getOauthProfile();
278046
278416
  init_oauth2();
@@ -286844,6 +287214,7 @@ function ConsoleOAuthFlow({
286844
287214
  });
286845
287215
  const [maximoApiKey, setMaximoApiKey] = import_react63.useState("");
286846
287216
  const [maximoApiKeyCursor, setMaximoApiKeyCursor] = import_react63.useState(0);
287217
+ const [openCodePlan, setOpenCodePlan] = import_react63.useState("zen");
286847
287218
  const [showPastePrompt, setShowPastePrompt] = import_react63.useState(false);
286848
287219
  const [urlCopied, setUrlCopied] = import_react63.useState(false);
286849
287220
  const textInputColumns = useTerminalSize().columns - PASTE_HERE_MSG.length - 1;
@@ -286896,7 +287267,7 @@ function ConsoleOAuthFlow({
286896
287267
  setOAuthStatus({ state: "idle" });
286897
287268
  }, {
286898
287269
  context: "Navigation",
286899
- isActive: oauthStatus.state === "maximoai_setup" || oauthStatus.state === "mytabulon_method" || oauthStatus.state === "mytabulon_setup" || oauthStatus.state === "cencori_setup"
287270
+ isActive: oauthStatus.state === "maximoai_setup" || oauthStatus.state === "mytabulon_method" || oauthStatus.state === "mytabulon_setup" || oauthStatus.state === "cencori_setup" || oauthStatus.state === "openrouter_setup" || oauthStatus.state === "opencode_method" || oauthStatus.state === "opencode_setup"
286900
287271
  });
286901
287272
  import_react63.useEffect(() => {
286902
287273
  if (pastedCode === "c" && (oauthStatus.state === "waiting_for_login" || oauthStatus.state === "mytabulon_waiting_for_login") && (showPastePrompt || oauthStatus.state === "mytabulon_waiting_for_login") && !urlCopied) {
@@ -287157,6 +287528,8 @@ function ConsoleOAuthFlow({
287157
287528
  maximoApiKeyCursor,
287158
287529
  setMaximoApiKeyCursor,
287159
287530
  startMyTabulonOAuth,
287531
+ openCodePlan,
287532
+ setOpenCodePlan,
287160
287533
  onDone
287161
287534
  })
287162
287535
  })
@@ -287184,6 +287557,8 @@ function OAuthStatusMessage(t0) {
287184
287557
  maximoApiKeyCursor,
287185
287558
  setMaximoApiKeyCursor,
287186
287559
  startMyTabulonOAuth,
287560
+ openCodePlan,
287561
+ setOpenCodePlan,
287187
287562
  onDone
287188
287563
  } = t0;
287189
287564
  switch (oauthStatus.state) {
@@ -287293,6 +287668,34 @@ function OAuthStatusMessage(t0) {
287293
287668
  } else {
287294
287669
  t_cencori = $2[51];
287295
287670
  }
287671
+ const t_openrouter = {
287672
+ label: /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
287673
+ children: [
287674
+ "OpenRouter · ",
287675
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
287676
+ dimColor: true,
287677
+ children: "API key and model routing"
287678
+ }),
287679
+ `
287680
+ `
287681
+ ]
287682
+ }),
287683
+ value: "openrouter"
287684
+ };
287685
+ const t_opencode = {
287686
+ label: /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
287687
+ children: [
287688
+ "OpenCode · ",
287689
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
287690
+ dimColor: true,
287691
+ children: "Go or Zen coding models"
287692
+ }),
287693
+ `
287694
+ `
287695
+ ]
287696
+ }),
287697
+ value: "opencode"
287698
+ };
287296
287699
  let t6;
287297
287700
  if ($2[6] === Symbol.for("react.memo_cache_sentinel")) {
287298
287701
  t6 = [
@@ -287300,6 +287703,8 @@ function OAuthStatusMessage(t0) {
287300
287703
  t_maximo,
287301
287704
  t5,
287302
287705
  t_cencori,
287706
+ t_openrouter,
287707
+ t_opencode,
287303
287708
  {
287304
287709
  label: /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
287305
287710
  children: [
@@ -287346,6 +287751,16 @@ function OAuthStatusMessage(t0) {
287346
287751
  setOAuthStatus({
287347
287752
  state: "cencori_setup"
287348
287753
  });
287754
+ } else if (value_0 === "openrouter") {
287755
+ logEvent("tengu_oauth_openrouter_selected", {});
287756
+ setOAuthStatus({
287757
+ state: "openrouter_setup"
287758
+ });
287759
+ } else if (value_0 === "opencode") {
287760
+ logEvent("tengu_oauth_opencode_selected", {});
287761
+ setOAuthStatus({
287762
+ state: "opencode_method"
287763
+ });
287349
287764
  } else {
287350
287765
  setOAuthStatus({
287351
287766
  state: "ready_to_start"
@@ -287436,8 +287851,10 @@ function OAuthStatusMessage(t0) {
287436
287851
  ...current,
287437
287852
  maximoApiKey: apiKey,
287438
287853
  openAIBaseUrl: "https://api.maximoai.co/v1",
287854
+ openAIProvider: "maximoai",
287439
287855
  mytabulonDefaultModel: undefined,
287440
- mytabulonAccount: undefined
287856
+ mytabulonAccount: undefined,
287857
+ openCodePlan: undefined
287441
287858
  }));
287442
287859
  logEvent("tengu_oauth_maximoai_api_key_saved", {});
287443
287860
  setOAuthStatus({ state: "success" });
@@ -287847,6 +288264,212 @@ ${result.warning}
287847
288264
  }
287848
288265
  return t5;
287849
288266
  }
288267
+ case "openrouter_setup": {
288268
+ return /* @__PURE__ */ jsx_runtime71.jsxs(ThemedBox_default, {
288269
+ flexDirection: "column",
288270
+ gap: 1,
288271
+ marginTop: 1,
288272
+ children: [
288273
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288274
+ bold: true,
288275
+ children: "Connect with OpenRouter"
288276
+ }),
288277
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288278
+ children: "OpenRouter provides an OpenAI-compatible Chat Completions API with access to many models. Enter your API key to load its model list."
288279
+ }),
288280
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedBox_default, {
288281
+ flexDirection: "column",
288282
+ children: [
288283
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288284
+ children: "Enter your OpenRouter API key:"
288285
+ }),
288286
+ /* @__PURE__ */ jsx_runtime71.jsx(TextInput, {
288287
+ value: maximoApiKey,
288288
+ onChange: setMaximoApiKey,
288289
+ onPaste: setMaximoApiKey,
288290
+ onSubmit: (value) => {
288291
+ configureOpenRouterProvider(value).then((result) => {
288292
+ logEvent("tengu_oauth_openrouter_api_key_saved", {});
288293
+ if (result.warning)
288294
+ console.log(`
288295
+ ${result.warning}
288296
+ `);
288297
+ setOAuthStatus({ state: "success" });
288298
+ onDone();
288299
+ }).catch((error42) => {
288300
+ logError2(error42);
288301
+ setOAuthStatus({
288302
+ state: "error",
288303
+ message: error42.message,
288304
+ toRetry: { state: "openrouter_setup" }
288305
+ });
288306
+ });
288307
+ },
288308
+ cursorOffset: maximoApiKeyCursor,
288309
+ onChangeCursorOffset: setMaximoApiKeyCursor,
288310
+ columns: textInputColumns,
288311
+ mask: "*",
288312
+ placeholder: "Enter your OpenRouter API key..."
288313
+ })
288314
+ ]
288315
+ }),
288316
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288317
+ dimColor: true,
288318
+ children: "Get your API key from: https://openrouter.ai/settings/keys"
288319
+ }),
288320
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288321
+ dimColor: true,
288322
+ children: [
288323
+ "Press ",
288324
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288325
+ bold: true,
288326
+ children: "Escape"
288327
+ }),
288328
+ " to go back."
288329
+ ]
288330
+ })
288331
+ ]
288332
+ });
288333
+ }
288334
+ case "opencode_method": {
288335
+ return /* @__PURE__ */ jsx_runtime71.jsxs(ThemedBox_default, {
288336
+ flexDirection: "column",
288337
+ gap: 1,
288338
+ marginTop: 1,
288339
+ children: [
288340
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288341
+ bold: true,
288342
+ children: "Connect with OpenCode"
288343
+ }),
288344
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288345
+ children: "Choose an OpenCode subscription. Both options use the official OpenAI-compatible Chat Completions endpoint and load their models."
288346
+ }),
288347
+ /* @__PURE__ */ jsx_runtime71.jsx(Select, {
288348
+ options: [
288349
+ {
288350
+ label: /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288351
+ children: [
288352
+ "OpenCode Zen · ",
288353
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288354
+ dimColor: true,
288355
+ children: "Curated, pay-as-you-go models"
288356
+ }),
288357
+ `
288358
+ `
288359
+ ]
288360
+ }),
288361
+ value: "zen"
288362
+ },
288363
+ {
288364
+ label: /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288365
+ children: [
288366
+ "OpenCode Go · ",
288367
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288368
+ dimColor: true,
288369
+ children: "Low-cost coding subscription"
288370
+ }),
288371
+ `
288372
+ `
288373
+ ]
288374
+ }),
288375
+ value: "go"
288376
+ }
288377
+ ],
288378
+ onChange: (value) => {
288379
+ const plan = value === "go" ? "go" : "zen";
288380
+ setOpenCodePlan(plan);
288381
+ setOAuthStatus({ state: "opencode_setup", plan });
288382
+ }
288383
+ }),
288384
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288385
+ dimColor: true,
288386
+ children: [
288387
+ "Press ",
288388
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288389
+ bold: true,
288390
+ children: "Escape"
288391
+ }),
288392
+ " to go back."
288393
+ ]
288394
+ })
288395
+ ]
288396
+ });
288397
+ }
288398
+ case "opencode_setup": {
288399
+ const planLabel = oauthStatus.plan === "go" ? "Go" : "Zen";
288400
+ return /* @__PURE__ */ jsx_runtime71.jsxs(ThemedBox_default, {
288401
+ flexDirection: "column",
288402
+ gap: 1,
288403
+ marginTop: 1,
288404
+ children: [
288405
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288406
+ bold: true,
288407
+ children: [
288408
+ "Connect with OpenCode ",
288409
+ planLabel
288410
+ ]
288411
+ }),
288412
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288413
+ children: "Enter your OpenCode API key. Maximo Syntax will fetch the models available through the OpenAI-compatible Chat Completions endpoint."
288414
+ }),
288415
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedBox_default, {
288416
+ flexDirection: "column",
288417
+ children: [
288418
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288419
+ children: [
288420
+ "Enter your OpenCode ",
288421
+ planLabel,
288422
+ " API key:"
288423
+ ]
288424
+ }),
288425
+ /* @__PURE__ */ jsx_runtime71.jsx(TextInput, {
288426
+ value: maximoApiKey,
288427
+ onChange: setMaximoApiKey,
288428
+ onPaste: setMaximoApiKey,
288429
+ onSubmit: (value) => {
288430
+ configureOpenCodeProvider(value, oauthStatus.plan).then((result) => {
288431
+ logEvent("tengu_oauth_opencode_api_key_saved", {});
288432
+ if (result.warning)
288433
+ console.log(`
288434
+ ${result.warning}
288435
+ `);
288436
+ setOAuthStatus({ state: "success" });
288437
+ onDone();
288438
+ }).catch((error42) => {
288439
+ logError2(error42);
288440
+ setOAuthStatus({
288441
+ state: "error",
288442
+ message: error42.message,
288443
+ toRetry: { state: "opencode_setup", plan: oauthStatus.plan }
288444
+ });
288445
+ });
288446
+ },
288447
+ cursorOffset: maximoApiKeyCursor,
288448
+ onChangeCursorOffset: setMaximoApiKeyCursor,
288449
+ columns: textInputColumns,
288450
+ mask: "*",
288451
+ placeholder: `Enter your OpenCode ${planLabel} API key...`
288452
+ })
288453
+ ]
288454
+ }),
288455
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288456
+ dimColor: true,
288457
+ children: "Get your key from: https://opencode.ai/auth"
288458
+ }),
288459
+ /* @__PURE__ */ jsx_runtime71.jsxs(ThemedText, {
288460
+ dimColor: true,
288461
+ children: [
288462
+ "Press ",
288463
+ /* @__PURE__ */ jsx_runtime71.jsx(ThemedText, {
288464
+ bold: true,
288465
+ children: "Escape"
288466
+ }),
288467
+ " to go back."
288468
+ ]
288469
+ })
288470
+ ]
288471
+ });
288472
+ }
287850
288473
  case "platform_setup": {
287851
288474
  let t1;
287852
288475
  if ($2[12] === Symbol.for("react.memo_cache_sentinel")) {
@@ -363880,7 +364503,7 @@ function getAnthropicEnvMetadata() {
363880
364503
  function getBuildAgeMinutes() {
363881
364504
  if (false)
363882
364505
  ;
363883
- const buildTime = new Date("2026-08-03T12:06:47.158Z").getTime();
364506
+ const buildTime = new Date("2026-08-04T01:30:08.298Z").getTime();
363884
364507
  if (isNaN(buildTime))
363885
364508
  return;
363886
364509
  return Math.floor((Date.now() - buildTime) / 60000);
@@ -369134,7 +369757,7 @@ var init_FileReadTool = __esm(() => {
369134
369757
  },
369135
369758
  renderToolUseErrorMessage: renderToolUseErrorMessage11,
369136
369759
  async validateInput({ file_path, pages }, toolUseContext) {
369137
- if (pages !== undefined) {
369760
+ if (pages !== undefined && pages.trim() !== "") {
369138
369761
  const parsed = parsePDFPageRange(pages);
369139
369762
  if (!parsed) {
369140
369763
  return {
@@ -429954,7 +430577,7 @@ function getRecentActivitySync() {
429954
430577
  return cachedActivity;
429955
430578
  }
429956
430579
  function getLogoDisplayData() {
429957
- const version2 = process.env.DEMO_VERSION ?? "0.1.23" ?? "99.0.0";
430580
+ const version2 = process.env.DEMO_VERSION ?? "0.1.24" ?? "99.0.0";
429958
430581
  const serverUrl = getDirectConnectServerUrl();
429959
430582
  const displayPath = process.env.DEMO_VERSION ? "/code/maximo" : getDisplayPath(getCwd());
429960
430583
  const cwd2 = serverUrl ? `${displayPath} in ${serverUrl.replace(/^https?:\/\//, "")}` : displayPath;
@@ -459419,7 +460042,7 @@ var init_bridge_kick = __esm(() => {
459419
460042
  var call57 = async () => {
459420
460043
  return {
459421
460044
  type: "text",
459422
- value: `${"99.0.0"} (built ${"2026-08-03T12:06:47.158Z"})`
460045
+ value: `${"99.0.0"} (built ${"2026-08-04T01:30:08.298Z"})`
459423
460046
  };
459424
460047
  }, version2, version_default;
459425
460048
  var init_version = __esm(() => {
@@ -484426,9 +485049,18 @@ function applySafeConfigEnvironmentVariables() {
484426
485049
  if (globalConfig2.maximoApiKey && !process.env.OPENAI_API_KEY) {
484427
485050
  process.env.MAXIMO_SYNTAX_USE_OPENAI = "1";
484428
485051
  process.env.OPENAI_API_KEY = globalConfig2.maximoApiKey;
484429
- process.env.OPENAI_BASE_URL = globalConfig2.openAIBaseUrl || "https://api.maximoai.co/v1";
485052
+ const baseUrl = globalConfig2.openAIBaseUrl || "https://api.maximoai.co/v1";
485053
+ process.env.OPENAI_BASE_URL = baseUrl;
484430
485054
  if (!process.env.OPENAI_MODEL) {
484431
- process.env.OPENAI_MODEL = globalConfig2.openAIBaseUrl?.includes("api.mytabulon.com") ? globalConfig2.mytabulonDefaultModel || "maximo-atlas-preview" : "maximo-pandora-3.8-nano";
485055
+ if (baseUrl.includes("api.mytabulon.com")) {
485056
+ process.env.OPENAI_MODEL = globalConfig2.mytabulonDefaultModel || "maximo-atlas-preview";
485057
+ } else if (baseUrl.includes("openrouter.ai/api/v1")) {
485058
+ process.env.OPENAI_MODEL = "openai/gpt-5.4";
485059
+ } else if (baseUrl.includes("opencode.ai/zen/")) {
485060
+ process.env.OPENAI_MODEL = "deepseek-v4-flash";
485061
+ } else {
485062
+ process.env.OPENAI_MODEL = "maximo-pandora-3.8-nano";
485063
+ }
484432
485064
  }
484433
485065
  }
484434
485066
  }
@@ -533771,7 +534403,7 @@ function SetupRow({ children }) {
533771
534403
  }
533772
534404
  function WelcomeV2() {
533773
534405
  const { columns } = useTerminalSize();
533774
- const version3 = "0.1.23";
534406
+ const version3 = "0.1.24";
533775
534407
  const width = Math.max(48, Math.min(columns || 92, 92));
533776
534408
  const stacked = width < OCTOPUS_COMPACT_WIDTH + 42;
533777
534409
  return /* @__PURE__ */ jsx_runtime479.jsx(ThemedBox_default, {
@@ -553698,7 +554330,7 @@ Usage: maximo --remote "your task description"`, () => gracefulShutdown(1));
553698
554330
  pendingHookMessages
553699
554331
  }, renderAndRun);
553700
554332
  }
553701
- }).version("0.1.23 (Maximo Syntax)", "-v, --version", "Output the version number");
554333
+ }).version("0.1.24 (Maximo Syntax)", "-v, --version", "Output the version number");
553702
554334
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
553703
554335
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
553704
554336
  if (canUserConfigureAdvisor()) {
@@ -553776,18 +554408,26 @@ Usage: maximo --remote "your task description"`, () => gracefulShutdown(1));
553776
554408
  if (false) {}
553777
554409
  if (false) {}
553778
554410
  const auth2 = program2.command("auth").description("Manage authentication").configureHelp(createSortedHelpConfig());
553779
- auth2.command("login").description("Sign in to Maximo AI").option("--email <email>", "Pre-populate email address on the login page").option("--sso", "Force SSO login flow").option("--console", "Use Maximo AI API usage billing instead of a Maximo subscription").option("--maximoai", "Use Maximo subscription (default)").action(async ({
554411
+ auth2.command("login").description("Sign in to Maximo AI or an OpenAI-compatible provider").option("--email <email>", "Pre-populate email address on the login page").option("--sso", "Force SSO login flow").option("--console", "Use Maximo AI API usage billing instead of a Maximo subscription").option("--maximoai", "Use Maximo subscription (default)").option("--openrouter", "Use OpenRouter with an OpenAI-compatible API key").option("--opencode", "Use OpenCode Go or Zen with an OpenAI-compatible API key").option("--opencode-plan <plan>", "OpenCode plan: zen or go", "zen").option("--api-key <key>", "API key for --openrouter or --opencode").action(async ({
553780
554412
  email: email3,
553781
554413
  sso,
553782
554414
  console: useConsole,
553783
- maximoai
554415
+ maximoai,
554416
+ openrouter,
554417
+ opencode,
554418
+ opencodePlan,
554419
+ apiKey
553784
554420
  }) => {
553785
554421
  const { authLogin: authLogin2 } = await Promise.resolve().then(() => (init_auth7(), exports_auth2));
553786
554422
  await authLogin2({
553787
554423
  email: email3,
553788
554424
  sso,
553789
554425
  console: useConsole,
553790
- maximoai
554426
+ maximoai,
554427
+ openrouter,
554428
+ opencode,
554429
+ opencodePlan,
554430
+ apiKey
553791
554431
  });
553792
554432
  });
553793
554433
  auth2.command("status").description("Show authentication status").option("--json", "Output as JSON (default)").option("--text", "Output as human-readable text").action(async (opts) => {
@@ -554229,7 +554869,7 @@ function validateProviderEnvOrExit() {
554229
554869
  async function main2() {
554230
554870
  const args = process.argv.slice(2);
554231
554871
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
554232
- console.log(`${"0.1.23"} (Maximo Syntax)`);
554872
+ console.log(`${"0.1.24"} (Maximo Syntax)`);
554233
554873
  return;
554234
554874
  }
554235
554875
  validateProviderEnvOrExit();
@@ -554306,4 +554946,4 @@ async function main2() {
554306
554946
  }
554307
554947
  main2();
554308
554948
 
554309
- //# debugId=A69DD0EA5FE13F0D64756E2164756E21
554949
+ //# debugId=ED7D9CB2B638531E64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maximoai/maximo-syntax-cli",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Maximo Syntax CLI - A powerful AI-powered command-line interface for code development with any LLM",
5
5
  "type": "module",
6
6
  "bin": {