@tryarcanist/cli 0.1.286 → 0.1.288

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 (2) hide show
  1. package/dist/index.js +82 -61
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8804,47 +8804,6 @@ var MODEL_REGISTRY = [
8804
8804
  sessionStart: { eligible: true },
8805
8805
  visibility: "internal_probe"
8806
8806
  },
8807
- {
8808
- // Served by Fireworks through Ramp Router, never by OpenAI. Pricing is Fireworks' published
8809
- // per-million rate, confirmed against billed dashboard rows to the cent on 2026-08-12 --
8810
- // Ramp's own `GET /v1/models` catalog misprices the OpenAI family and is not a source here.
8811
- id: DeepSeekModel.V4Flash,
8812
- name: "DeepSeek V4 Flash",
8813
- provider: "openai",
8814
- backends: [CODEX_AGENT_RUNTIME_BACKEND],
8815
- capabilities: { codexToolSearch: true },
8816
- contextWindow: 1048576,
8817
- reasoning: { efforts: ["high"], default: "high" },
8818
- pricing: { inputPerMillion: 0.14, outputPerMillion: 0.28, cacheReadPerMillion: 0.028 },
8819
- // Startable but hidden, the same two-axis shape gpt-5.3-codex-spark uses. `sessionStart` is
8820
- // what lets an explicitly authorized caller actually start a session on this model --
8821
- // createSessionState resolves through extractSessionStartModelIdForBackend, which reads this
8822
- // block. `visibility` is what keeps it out of every customer surface: the public provider
8823
- // groups filter on it, and extractSessionStartModelIdAnyBackend refuses a non-subscription
8824
- // probe outright, so no stored default or automatic route can reach it.
8825
- sessionStart: { eligible: true },
8826
- visibility: "internal_probe"
8827
- },
8828
- {
8829
- // The second candidate on the Ramp fallback list, so a Flash capacity 429 does not strand a
8830
- // review. Roughly 12x Flash's rate, which is why the budget reservation prices against Pro.
8831
- id: DeepSeekModel.V4Pro,
8832
- name: "DeepSeek V4 Pro",
8833
- provider: "openai",
8834
- backends: [CODEX_AGENT_RUNTIME_BACKEND],
8835
- capabilities: { codexToolSearch: true },
8836
- contextWindow: 1048576,
8837
- reasoning: { efforts: ["high"], default: "high" },
8838
- pricing: { inputPerMillion: 1.74, outputPerMillion: 3.48, cacheReadPerMillion: 0.348 },
8839
- // Startable but hidden, the same two-axis shape gpt-5.3-codex-spark uses. `sessionStart` is
8840
- // what lets an explicitly authorized caller actually start a session on this model --
8841
- // createSessionState resolves through extractSessionStartModelIdForBackend, which reads this
8842
- // block. `visibility` is what keeps it out of every customer surface: the public provider
8843
- // groups filter on it, and extractSessionStartModelIdAnyBackend refuses a non-subscription
8844
- // probe outright, so no stored default or automatic route can reach it.
8845
- sessionStart: { eligible: true },
8846
- visibility: "internal_probe"
8847
- },
8848
8807
  {
8849
8808
  id: OpenAIModel.GPT53Codex,
8850
8809
  name: "GPT-5.3 Codex",
@@ -8884,6 +8843,67 @@ var MODEL_REGISTRY = [
8884
8843
  contextWindow: 4e5,
8885
8844
  reasoning: { efforts: ["low", "medium", "high", "xhigh"], default: "high" },
8886
8845
  pricing: { inputPerMillion: 1.75, outputPerMillion: 14, cacheReadPerMillion: 0.175 }
8846
+ },
8847
+ {
8848
+ id: DeepSeekModel.V4Flash,
8849
+ name: "DeepSeek V4 Flash",
8850
+ // `provider` names the WIRE PROTOCOL the gateway speaks (OpenAI Responses),
8851
+ // not the vendor. DeepSeek V4 is served by Baseten: the gateway maps these
8852
+ // registry ids to Baseten wire ids and swaps the upstream host, while every
8853
+ // request/response stays OpenAI-shaped. Do NOT "fix" this to a new
8854
+ // "baseten" provider — `ModelProvider` is what review-model validation, the
8855
+ // credential gate (`PROVIDER_ENV_VAR` / spawn credential resolution), and
8856
+ // the sandbox bridge's model guard all key off, so a new provider value
8857
+ // silently fails those closed instead of routing anywhere.
8858
+ provider: "openai",
8859
+ backends: [CODEX_AGENT_RUNTIME_BACKEND],
8860
+ // Required for codex session-start eligibility: the codex backend is the
8861
+ // sole consumer of this flag and drops any model without it from the
8862
+ // session-start set (see modelSupportsRequiredSessionStartCapabilities).
8863
+ capabilities: { codexToolSearch: true },
8864
+ contextWindow: 1048576,
8865
+ // Only the effort our live Baseten probes actually proved. Registry efforts
8866
+ // are treated as supported capabilities and are selectable by other paths
8867
+ // (isValidReasoningEffort, review config, CLI overrides), so widen this list
8868
+ // only after probing each added value end-to-end against Baseten.
8869
+ reasoning: { efforts: ["high"], default: "high" },
8870
+ // Verified against https://www.baseten.co/pricing on 2026-08-11 (Model APIs
8871
+ // token pricing, row `deepseek-ai/DeepSeek-V4-Flash-0731`): $0.13/M input,
8872
+ // $0.028/M cached input, $0.26/M output. Baseten publishes a cached-input
8873
+ // rate for this model, so cacheReadPerMillion carries it rather than
8874
+ // mirroring the input rate. No longContext and no flex: both are OpenAI-only
8875
+ // pricing axes and Baseten prices a single flat tier.
8876
+ pricing: { inputPerMillion: 0.13, outputPerMillion: 0.26, cacheReadPerMillion: 0.028 },
8877
+ sessionStart: { eligible: true },
8878
+ visibility: "internal_probe"
8879
+ // Deliberately no overloadFallback. A Baseten 429 must not silently re-run
8880
+ // an A/B arm on a different model; with no fallback the loop retries the
8881
+ // same model, which is what an A/B comparison requires.
8882
+ },
8883
+ {
8884
+ id: DeepSeekModel.V4Pro,
8885
+ name: "DeepSeek V4 Pro",
8886
+ // See the DeepSeek V4 Flash entry above: "openai" is the wire protocol
8887
+ // (OpenAI Responses), not the vendor. Changing it to a "baseten" provider
8888
+ // breaks review-model validation, the credential gate, and the sandbox
8889
+ // bridge's model guard.
8890
+ provider: "openai",
8891
+ backends: [CODEX_AGENT_RUNTIME_BACKEND],
8892
+ // Required for codex session-start eligibility (sole consumer of the flag).
8893
+ capabilities: { codexToolSearch: true },
8894
+ contextWindow: 262144,
8895
+ // Only the probed effort; widen only after probing each value against
8896
+ // Baseten, since registry efforts are selectable capabilities.
8897
+ reasoning: { efforts: ["high"], default: "high" },
8898
+ // Verified against https://www.baseten.co/pricing on 2026-08-11 (Model APIs
8899
+ // token pricing, row `DeepSeek V4 Pro`): $1.74/M input, $0.145/M cached
8900
+ // input, $3.48/M output. Cached-input rate is published, so it is carried
8901
+ // verbatim. No longContext and no flex (OpenAI-only axes).
8902
+ pricing: { inputPerMillion: 1.74, outputPerMillion: 3.48, cacheReadPerMillion: 0.145 },
8903
+ sessionStart: { eligible: true },
8904
+ visibility: "internal_probe"
8905
+ // Deliberately no overloadFallback — see DeepSeek V4 Flash: an A/B arm must
8906
+ // retry the same model on a Baseten 429, never silently swap models.
8887
8907
  }
8888
8908
  ];
8889
8909
  var MODEL_PROVIDER_NAMES = {
@@ -8954,14 +8974,12 @@ function splitModelIdentifier(value) {
8954
8974
  }
8955
8975
  function getRawModelValue(raw) {
8956
8976
  if (typeof raw === "string") return asNonEmptyString(raw);
8957
- if (!raw || typeof raw !== "object") return void 0;
8958
- const value = raw;
8959
- return asNonEmptyString(value.modelID) ?? asNonEmptyString(value.modelId) ?? asNonEmptyString(value.id);
8977
+ if (!isRecord(raw)) return void 0;
8978
+ return asNonEmptyString(raw.modelID) ?? asNonEmptyString(raw.modelId) ?? asNonEmptyString(raw.id);
8960
8979
  }
8961
8980
  function getExplicitProvider(raw) {
8962
- if (raw && typeof raw === "object") {
8963
- const value = raw;
8964
- const providerID = asNonEmptyString(value.providerID) ?? asNonEmptyString(value.providerId);
8981
+ if (isRecord(raw)) {
8982
+ const providerID = asNonEmptyString(raw.providerID) ?? asNonEmptyString(raw.providerId);
8965
8983
  if (providerID && MODEL_PROVIDERS_SET.has(providerID)) {
8966
8984
  return providerID;
8967
8985
  }
@@ -8978,6 +8996,7 @@ function extractModelId(raw) {
8978
8996
  function getProviderForModel(modelId) {
8979
8997
  return MODEL_PROVIDERS[modelId] ?? "openai";
8980
8998
  }
8999
+ var BASETEN_SERVED_MODEL_IDS = new Set(Object.values(DeepSeekModel));
8981
9000
  function toModelSelection(raw) {
8982
9001
  const modelID = extractModelId(raw);
8983
9002
  if (!modelID) return void 0;
@@ -9273,7 +9292,7 @@ function yamlLineForPath(doc, keyPath) {
9273
9292
  }
9274
9293
  function assertKnownKeys(path, doc, value) {
9275
9294
  const issues = [];
9276
- if (!value || typeof value !== "object" || Array.isArray(value)) {
9295
+ if (!isRecord(value)) {
9277
9296
  return [issue(path, "manifest must be a YAML object", { code: "manifest_type" })];
9278
9297
  }
9279
9298
  const root = value;
@@ -9292,7 +9311,7 @@ function assertKnownKeys(path, doc, value) {
9292
9311
  );
9293
9312
  }
9294
9313
  }
9295
- if (root.layer && typeof root.layer === "object" && !Array.isArray(root.layer)) {
9314
+ if (isRecord(root.layer)) {
9296
9315
  for (const key of Object.keys(root.layer)) {
9297
9316
  if (key !== "dockerfile") {
9298
9317
  issues.push(
@@ -9305,7 +9324,7 @@ function assertKnownKeys(path, doc, value) {
9305
9324
  }
9306
9325
  }
9307
9326
  }
9308
- if (root.smoke && typeof root.smoke === "object" && !Array.isArray(root.smoke)) {
9327
+ if (isRecord(root.smoke)) {
9309
9328
  for (const key of Object.keys(root.smoke)) {
9310
9329
  if (key !== "commands") {
9311
9330
  issues.push(
@@ -9335,7 +9354,7 @@ function parseSandboxLayerManifest(path, text) {
9335
9354
  }
9336
9355
  const parsed = doc.toJSON();
9337
9356
  const issues = assertKnownKeys(path, doc, parsed);
9338
- const raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
9357
+ const raw = isRecord(parsed) ? parsed : {};
9339
9358
  if (!Object.prototype.hasOwnProperty.call(raw, "version")) {
9340
9359
  issues.push(issue(path, "version is required", { field: "version", code: "required" }));
9341
9360
  } else if (raw.version !== 1) {
@@ -9368,7 +9387,7 @@ function parseSandboxLayerManifest(path, text) {
9368
9387
  );
9369
9388
  }
9370
9389
  let normalizedDockerfile;
9371
- const dockerfile = layer && typeof layer === "object" && !Array.isArray(layer) ? layer.dockerfile : void 0;
9390
+ const dockerfile = isRecord(layer) ? layer.dockerfile : void 0;
9372
9391
  if (typeof dockerfile !== "string") {
9373
9392
  issues.push(
9374
9393
  issue(path, "layer.dockerfile must be a string", {
@@ -9393,7 +9412,7 @@ function parseSandboxLayerManifest(path, text) {
9393
9412
  }
9394
9413
  }
9395
9414
  const commandsNode = (0, import_yaml.isMap)(doc.contents) ? doc.getIn(["smoke", "commands"], true) : void 0;
9396
- const rawCommands = raw.smoke?.commands ?? [];
9415
+ const rawCommands = isRecord(raw.smoke) ? raw.smoke.commands : [];
9397
9416
  const smokeCommands = [];
9398
9417
  if (!Array.isArray(rawCommands)) {
9399
9418
  issues.push(
@@ -9633,7 +9652,7 @@ function normalizeSandboxLayerInstructions(instructions) {
9633
9652
  }
9634
9653
  function sortJsonValue(value) {
9635
9654
  if (Array.isArray(value)) return value.map(sortJsonValue);
9636
- if (!value || typeof value !== "object") return value;
9655
+ if (!isRecord(value)) return value;
9637
9656
  return Object.fromEntries(
9638
9657
  Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, sortJsonValue(entry)])
9639
9658
  );
@@ -10255,7 +10274,7 @@ function isOnboardingStageStatus(value) {
10255
10274
  return typeof value === "string" && ONBOARDING_STAGE_STATUSES.includes(value);
10256
10275
  }
10257
10276
  function parseOnboardingStageEvent(input) {
10258
- if (!input || typeof input !== "object" || Array.isArray(input)) return null;
10277
+ if (!isRecord(input)) return null;
10259
10278
  const record = input;
10260
10279
  if (!isOnboardingStage(record.stage)) return null;
10261
10280
  const status = isOnboardingStageStatus(record.status) ? record.status : "started";
@@ -11320,6 +11339,7 @@ var ERROR_CODES = [
11320
11339
  "api_error",
11321
11340
  "model_overloaded",
11322
11341
  "config_error",
11342
+ "github_pr_context",
11323
11343
  "github_app_permission",
11324
11344
  "failed_edits",
11325
11345
  // No producer since the memory subsystem was removed. Retained because the code is
@@ -11366,6 +11386,7 @@ var ERROR_CODE_LABELS = {
11366
11386
  api_error: "Model service error",
11367
11387
  model_overloaded: "Model at capacity",
11368
11388
  config_error: "Configuration error",
11389
+ github_pr_context: "GitHub pull request context unavailable",
11369
11390
  github_app_permission: "GitHub App permissions missing",
11370
11391
  failed_edits: "Edit failure",
11371
11392
  memory_enforcement_failed: "Memory enforcement failed",
@@ -11650,7 +11671,8 @@ function parseSsePayload(payload) {
11650
11671
  let status = null;
11651
11672
  const events = [];
11652
11673
  for (const message of messages) {
11653
- const data = message.data ? parseJsonObject(message.data) : {};
11674
+ const parsed = message.data ? parseJsonObject(message.data) : {};
11675
+ const data = isRecord(parsed) ? parsed : {};
11654
11676
  if (message.event === "status") {
11655
11677
  const phaseRaw = data.phase;
11656
11678
  const phase = typeof phaseRaw === "string" && VALID_PHASES.has(phaseRaw) ? phaseRaw : null;
@@ -11683,8 +11705,7 @@ function validateEnumField(value, validSet) {
11683
11705
  }
11684
11706
  function parseJsonObject(value) {
11685
11707
  try {
11686
- const parsed = JSON.parse(value);
11687
- return parsed && typeof parsed === "object" ? parsed : {};
11708
+ return JSON.parse(value);
11688
11709
  } catch (err) {
11689
11710
  throw new Error(`Malformed SSE JSON payload: ${stringifyError(err)}`);
11690
11711
  }
@@ -11703,7 +11724,7 @@ function buildPromptLabelMap(prompts) {
11703
11724
  return labels;
11704
11725
  }
11705
11726
  function renderWatchEvent(event, state) {
11706
- const data = event.data;
11727
+ const data = isRecord(event.data) ? event.data : {};
11707
11728
  switch (event.type) {
11708
11729
  case "text":
11709
11730
  return { kind: "text", text: String(data.text ?? "") };
@@ -11980,7 +12001,7 @@ async function getSessionCommand(sessionId, options, command) {
11980
12001
  writeJson(payload);
11981
12002
  return;
11982
12003
  }
11983
- const session = payload.session && typeof payload.session === "object" ? payload.session : payload;
12004
+ const session = payload.session && typeof payload.session === "object" && !Array.isArray(payload.session) ? payload.session : payload;
11984
12005
  console.log(`Session: ${String(session.sessionId ?? session.id ?? sessionId)}`);
11985
12006
  console.log(`Status: ${String(session.phase ?? session.status ?? "unknown")}`);
11986
12007
  if (session.repoUrl) console.log(`Repo: ${String(session.repoUrl)}`);
@@ -12062,7 +12083,7 @@ async function usageCommand(sessionId, options, command) {
12062
12083
  writeJson(payload);
12063
12084
  return;
12064
12085
  }
12065
- const usage = payload.usage && typeof payload.usage === "object" ? payload.usage : payload;
12086
+ const usage = payload.usage && typeof payload.usage === "object" && !Array.isArray(payload.usage) ? payload.usage : payload;
12066
12087
  console.log(`Input tokens: ${String(usage.inputTokens ?? 0)}`);
12067
12088
  console.log(`Output tokens: ${String(usage.outputTokens ?? 0)}`);
12068
12089
  console.log(`Total tokens: ${String(usage.totalTokens ?? 0)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.286",
3
+ "version": "0.1.288",
4
4
  "description": "CLI for Arcanist - create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {