archymedes-cli 3.1.0 → 3.2.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.
@@ -15970,56 +15970,6 @@ async function saveSetup(params, deps) {
15970
15970
  return { ok: true, file, ...note ? { note } : {} };
15971
15971
  }
15972
15972
 
15973
- // packages/archymedes-cli/src/session/models.ts
15974
- function modelsForProvider(provider, asOf) {
15975
- const seen = new Set;
15976
- for (const record2 of PRICE_CATALOG) {
15977
- if (record2.provider !== provider || record2.modality !== "text" || record2.billingUnit !== "tokens")
15978
- continue;
15979
- seen.add(record2.model);
15980
- }
15981
- const fallback = PROVIDERS[provider].defaultModel;
15982
- seen.add(fallback);
15983
- const models = [...seen].filter((model) => model !== fallback).sort();
15984
- return [fallback, ...models];
15985
- }
15986
- function buildModelCatalog(environment, asOf, live) {
15987
- const choices = [];
15988
- const unconfigured = [];
15989
- for (const provider of PROVIDER_IDS) {
15990
- const spec = PROVIDERS[provider];
15991
- const missing = missingRequirements(provider, environment);
15992
- if (missing.length > 0) {
15993
- unconfigured.push({ provider, label: spec.label, missing });
15994
- continue;
15995
- }
15996
- const known = modelsForProvider(provider, asOf);
15997
- const knownSet = new Set(known);
15998
- const extra = (live?.[provider] ?? []).filter((model) => !knownSet.has(model) && (provider !== "free" || isFreeModelId(model))).slice().sort();
15999
- for (const model of [...known, ...extra]) {
16000
- choices.push({
16001
- provider,
16002
- providerLabel: spec.label,
16003
- model,
16004
- isProviderDefault: model === (environment[`${providerEnvPrefix(provider)}_MODEL`]?.trim() || spec.defaultModel),
16005
- prices: catalogPrices(provider, model, asOf),
16006
- ...knownSet.has(model) ? {} : { live: true }
16007
- });
16008
- }
16009
- }
16010
- return { choices, unconfigured };
16011
- }
16012
- function describePrice(prices, display, convert2) {
16013
- if (!prices)
16014
- return "unpriced";
16015
- const input = convert2({ currency: prices.currency, micros: prices.inputPerMillion });
16016
- const output = convert2({ currency: prices.currency, micros: prices.outputPerMillion });
16017
- if (!input || !output) {
16018
- return `${formatMoney(money(prices.inputPerMillion, prices.currency))}/${formatMoney(money(prices.outputPerMillion, prices.currency))} per Mtok`;
16019
- }
16020
- return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
16021
- }
16022
-
16023
15973
  // packages/core/src/providers/model-fetch.ts
16024
15974
  import { promises as fs16 } from "node:fs";
16025
15975
  import path21 from "node:path";
@@ -16036,10 +15986,8 @@ function modelsEndpoint(provider, environment) {
16036
15986
  return { url: `${FREE_BASE_URL}/models`, headers: {} };
16037
15987
  case "openrouter": {
16038
15988
  const key = trimmed(environment.OPENROUTER_API_KEY);
16039
- if (!key)
16040
- return;
16041
15989
  const base = trimmed(environment.OPENROUTER_BASE_URL) ?? "https://openrouter.ai/api/v1";
16042
- return { url: modelsUrl(base), headers: { authorization: `Bearer ${key}` } };
15990
+ return { url: modelsUrl(base), headers: key ? { authorization: `Bearer ${key}` } : {} };
16043
15991
  }
16044
15992
  case "archymedes-cloud":
16045
15993
  return;
@@ -16224,48 +16172,79 @@ function fetchableProviders(environment, providers) {
16224
16172
  return providers.filter((provider) => provider !== "archymedes-cloud" && missingRequirements(provider, environment).length === 0);
16225
16173
  }
16226
16174
 
16227
- // packages/archymedes-cli/src/app/live-models.ts
16228
- function createLiveModelRefresh(environment, state) {
16229
- return async (options = {}) => {
16230
- const providers = fetchableProviders(environment, PROVIDER_IDS);
16231
- if (providers.length === 0)
16232
- return { errors: [] };
16233
- const loaded = await loadLiveModels(providers, environment, options);
16234
- if (Object.keys(loaded.models).length > 0)
16235
- state.liveModels = loaded.models;
16236
- return {
16237
- errors: loaded.errors.filter((error) => error.provider !== "ollama" || Boolean(environment.OLLAMA_BASE_URL?.trim())).map((error) => `${error.provider}: ${error.error}`)
16238
- };
16239
- };
16175
+ // packages/archymedes-cli/src/session/models.ts
16176
+ function modelsForProvider(provider, asOf) {
16177
+ const seen = new Set;
16178
+ for (const record2 of PRICE_CATALOG) {
16179
+ if (record2.provider !== provider || record2.modality !== "text" || record2.billingUnit !== "tokens")
16180
+ continue;
16181
+ seen.add(record2.model);
16182
+ }
16183
+ const fallback = PROVIDERS[provider].defaultModel;
16184
+ seen.add(fallback);
16185
+ const models = [...seen].filter((model) => model !== fallback).sort();
16186
+ return [fallback, ...models];
16240
16187
  }
16241
- async function readCachedLiveModels(environment, state) {
16242
- const cached = await readModelCache(environment);
16243
- if (isCacheFresh(cached))
16244
- state.liveModels = cached.models;
16188
+ function describePrice(prices, display, convert2) {
16189
+ if (!prices)
16190
+ return "unpriced";
16191
+ const input = convert2({ currency: prices.currency, micros: prices.inputPerMillion });
16192
+ const output = convert2({ currency: prices.currency, micros: prices.outputPerMillion });
16193
+ if (!input || !output) {
16194
+ return `${formatMoney(money(prices.inputPerMillion, prices.currency))}/${formatMoney(money(prices.outputPerMillion, prices.currency))} per Mtok`;
16195
+ }
16196
+ return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
16245
16197
  }
16246
16198
 
16247
16199
  // packages/archymedes-cli/src/app/acp-models.ts
16248
- async function modelList(environment, params) {
16249
- const state = {};
16200
+ var PUBLIC_LISTINGS = ["free", "openrouter"];
16201
+ async function modelList(environment, params, options = {}) {
16202
+ const offline = /^(1|true|on|yes)$/i.test(environment.ARCHYMEDES_MODELS_OFFLINE?.trim() ?? "");
16203
+ const cached = await readModelCache(environment);
16204
+ let live = isCacheFresh(cached, options.now) ? cached.models : undefined;
16250
16205
  let errors = [];
16251
- if (params.refresh === true)
16252
- errors = (await createLiveModelRefresh(environment, state)({ refresh: true })).errors;
16253
- else
16254
- await readCachedLiveModels(environment, state);
16255
- const catalog = buildModelCatalog(environment, undefined, state.liveModels);
16256
- return {
16257
- choices: catalog.choices.map((choice) => ({
16258
- provider: choice.provider,
16259
- providerLabel: choice.providerLabel,
16260
- model: choice.model,
16261
- isDefault: choice.isProviderDefault,
16262
- live: Boolean(choice.live),
16263
- price: choice.prices ? describePrice(choice.prices, choice.prices.currency, (value) => value) : "unpriced"
16264
- })),
16265
- unconfigured: catalog.unconfigured.map(({ provider, label: label3, missing }) => ({ provider, label: label3, missing })),
16266
- errors,
16267
- providers: PROVIDER_IDS.length
16268
- };
16206
+ if (params.refresh === true || !live && !offline) {
16207
+ const asked = new Set(fetchableProviders(environment, PROVIDER_IDS));
16208
+ if (!offline)
16209
+ for (const provider of PUBLIC_LISTINGS)
16210
+ asked.add(provider);
16211
+ const loaded = await loadLiveModels([...asked], environment, { refresh: true, ...options });
16212
+ if (Object.keys(loaded.models).length > 0)
16213
+ live = { ...live ?? cached?.models ?? {}, ...loaded.models };
16214
+ errors = loaded.errors.filter((error) => error.provider !== "ollama" || Boolean(environment.OLLAMA_BASE_URL?.trim())).map((error) => `${error.provider}: ${error.error}`);
16215
+ }
16216
+ live ??= cached?.models;
16217
+ const ready = [];
16218
+ const locked = [];
16219
+ const unconfigured = [];
16220
+ const freeIds = new Set(live?.free ?? []);
16221
+ for (const provider of PROVIDER_IDS) {
16222
+ const spec = PROVIDERS[provider];
16223
+ const missing = missingRequirements(provider, environment);
16224
+ if (missing.length > 0)
16225
+ unconfigured.push({ provider, label: spec.label, missing });
16226
+ const known = modelsForProvider(provider);
16227
+ const knownSet = new Set(known);
16228
+ const extra = (live?.[provider] ?? []).filter((model) => !knownSet.has(model) && (provider !== "free" || isFreeModelId(model)) && !(provider === "openrouter" && freeIds.has(model))).sort();
16229
+ const preferred = environment[`${providerEnvPrefix(provider)}_MODEL`]?.trim() || spec.defaultModel;
16230
+ for (const model of [...known, ...extra]) {
16231
+ const prices = catalogPrices(provider, model);
16232
+ const free = provider === "free" || model.endsWith(":free") || Boolean(prices && prices.inputPerMillion === 0 && prices.outputPerMillion === 0);
16233
+ const choice = {
16234
+ provider,
16235
+ providerLabel: spec.label,
16236
+ model,
16237
+ isDefault: model === preferred,
16238
+ live: !knownSet.has(model),
16239
+ price: free ? "free" : prices ? describePrice(prices, prices.currency, (value) => value) : "unpriced",
16240
+ free,
16241
+ locked: missing.length > 0,
16242
+ missing
16243
+ };
16244
+ (choice.locked ? locked : ready).push(choice);
16245
+ }
16246
+ }
16247
+ return { choices: [...ready, ...locked], unconfigured, errors, providers: PROVIDER_IDS.length };
16269
16248
  }
16270
16249
 
16271
16250
  // packages/archymedes-cli/src/app/acp-commands.ts
@@ -16773,7 +16752,7 @@ function escapeCodeTimeoutMs(environment = process.env) {
16773
16752
  // packages/archymedes-cli/package.json
16774
16753
  var package_default = {
16775
16754
  name: "archymedes-cli",
16776
- version: "3.1.0",
16755
+ version: "3.2.0",
16777
16756
  description: "Archymedes CLI — a coding agent that shows its work. Runs against your working tree or an isolated remote sandbox, with guarded approvals, git checkpoints, and exact, measured cost accounting.",
16778
16757
  keywords: [
16779
16758
  "cli",
@@ -16819,12 +16798,12 @@ var package_default = {
16819
16798
  prepublishOnly: "bun run ../../tooling/build/build-packages.ts"
16820
16799
  },
16821
16800
  optionalDependencies: {
16822
- "@archymedes/cli-darwin-arm64": "3.1.0",
16823
- "@archymedes/cli-darwin-x64": "3.1.0",
16824
- "@archymedes/cli-linux-arm64": "3.1.0",
16825
- "@archymedes/cli-linux-x64": "3.1.0",
16826
- "@archymedes/cli-win32-arm64": "3.1.0",
16827
- "@archymedes/cli-win32-x64": "3.1.0",
16801
+ "@archymedes/cli-darwin-arm64": "3.2.0",
16802
+ "@archymedes/cli-darwin-x64": "3.2.0",
16803
+ "@archymedes/cli-linux-arm64": "3.2.0",
16804
+ "@archymedes/cli-linux-x64": "3.2.0",
16805
+ "@archymedes/cli-win32-arm64": "3.2.0",
16806
+ "@archymedes/cli-win32-x64": "3.2.0",
16828
16807
  "@archymedes/state-darwin-arm64": "0.4.0",
16829
16808
  "@archymedes/state-darwin-x64": "0.4.0",
16830
16809
  "@archymedes/state-linux-arm64-gnu": "0.4.0",
@@ -26040,7 +26019,7 @@ function closeWithClient(client, hook) {
26040
26019
  }
26041
26020
 
26042
26021
  // packages/archymedes-cli/src/app/live-models.ts
26043
- async function readCachedLiveModels2(environment, state) {
26022
+ async function readCachedLiveModels(environment, state) {
26044
26023
  const cached = await readModelCache(environment);
26045
26024
  if (isCacheFresh(cached))
26046
26025
  state.liveModels = cached.models;
@@ -27113,7 +27092,7 @@ async function main() {
27113
27092
  out2.route(firstSink);
27114
27093
  let explainedTabs = false;
27115
27094
  let liveModels = {};
27116
- await readCachedLiveModels2(environment, state);
27095
+ await readCachedLiveModels(environment, state);
27117
27096
  if (args.estimateOnly) {
27118
27097
  out2.write(`${ledger.formatPrediction(await agent.estimate(args.prompt))}
27119
27098
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archymedes-cli",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Archymedes CLI — a coding agent that shows its work. Runs against your working tree or an isolated remote sandbox, with guarded approvals, git checkpoints, and exact, measured cost accounting.",
5
5
  "keywords": [
6
6
  "cli",
@@ -46,12 +46,12 @@
46
46
  "prepublishOnly": "bun run ../../tooling/build/build-packages.ts"
47
47
  },
48
48
  "optionalDependencies": {
49
- "@archymedes/cli-darwin-arm64": "3.1.0",
50
- "@archymedes/cli-darwin-x64": "3.1.0",
51
- "@archymedes/cli-linux-arm64": "3.1.0",
52
- "@archymedes/cli-linux-x64": "3.1.0",
53
- "@archymedes/cli-win32-arm64": "3.1.0",
54
- "@archymedes/cli-win32-x64": "3.1.0",
49
+ "@archymedes/cli-darwin-arm64": "3.2.0",
50
+ "@archymedes/cli-darwin-x64": "3.2.0",
51
+ "@archymedes/cli-linux-arm64": "3.2.0",
52
+ "@archymedes/cli-linux-x64": "3.2.0",
53
+ "@archymedes/cli-win32-arm64": "3.2.0",
54
+ "@archymedes/cli-win32-x64": "3.2.0",
55
55
  "@archymedes/state-darwin-arm64": "0.4.0",
56
56
  "@archymedes/state-darwin-x64": "0.4.0",
57
57
  "@archymedes/state-linux-arm64-gnu": "0.4.0",