archymedes-cli 3.3.0 → 3.5.1

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.
@@ -7,7 +7,7 @@ import {
7
7
  eventJournalPath,
8
8
  readEventJournal,
9
9
  runtimeEventForJournal
10
- } from "./archymedes-cfwtgnjx.mjs";
10
+ } from "./archymedes-qm9bwbe7.mjs";
11
11
  import {
12
12
  APIConnectionError,
13
13
  BoundedAgentRuntime,
@@ -17,6 +17,7 @@ import {
17
17
  OpenAIAgentTurnProvider,
18
18
  StreamTimeoutError,
19
19
  TASK_KINDS,
20
+ VENDOR_DIALECTS,
20
21
  WANDER_GRADES,
21
22
  WANDER_LAB_FILES,
22
23
  WANDER_MARKER,
@@ -44,18 +45,18 @@ import {
44
45
  wanderGradeCounts,
45
46
  wanderPlannerInstructions,
46
47
  withOpenRouterCacheControl
47
- } from "./archymedes-j0vrbr99.mjs";
48
+ } from "./archymedes-82ay2983.mjs";
48
49
  import {
49
50
  __require
50
51
  } from "./archymedes-x67v3n58.mjs";
51
52
 
52
- // src/archymedes.ts
53
+ // packages/archymedes-cli/src/archymedes.ts
53
54
  import { createInterface as createInterface5 } from "readline/promises";
54
55
  import path30 from "path";
55
56
  import { realpathSync } from "fs";
56
57
  import { pathToFileURL as pathToFileURL2 } from "url";
57
58
 
58
- // ../core/src/cli/acp.ts
59
+ // packages/core/src/cli/acp.ts
59
60
  var ACP_PROTOCOL_VERSION = 1;
60
61
  var JSON_RPC = { parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602, internalError: -32603 };
61
62
  var ARCHYMEDES_EVENT_METHOD = "_archymedes/event";
@@ -404,7 +405,7 @@ function toolCallTitle(toolName, argumentsValue) {
404
405
  return subject ? `${label}: ${String(subject).slice(0, 120)}` : label;
405
406
  }
406
407
 
407
- // ../core/src/cli/image-attachments.ts
408
+ // packages/core/src/cli/image-attachments.ts
408
409
  var MAX_IMAGES_PER_TURN = 4;
409
410
  var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
410
411
  var MENTION = /(?:^|\s)@((?:[\w.-]+\/)*[\w.-]+\.(?:png|jpe?g|gif|webp))(?=$|[\s,;:!?)])/gi;
@@ -469,7 +470,7 @@ function withoutImageData(messages) {
469
470
  });
470
471
  }
471
472
 
472
- // ../core/src/cli/hosted-recovery.ts
473
+ // packages/core/src/cli/hosted-recovery.ts
473
474
  import { createHash, randomUUID } from "node:crypto";
474
475
  import { promises as fs } from "node:fs";
475
476
  import path from "node:path";
@@ -728,12 +729,12 @@ ${entry.response.content}` });
728
729
  }
729
730
  }
730
731
 
731
- // ../core/src/cli/agent.ts
732
+ // packages/core/src/cli/agent.ts
732
733
  import { randomUUID as randomUUID4 } from "node:crypto";
733
734
  import path15 from "node:path";
734
735
  import { access as access3 } from "node:fs/promises";
735
736
 
736
- // ../core/src/cli/checkpoints.ts
737
+ // packages/core/src/cli/checkpoints.ts
737
738
  import { spawn } from "node:child_process";
738
739
  import { randomUUID as randomUUID2 } from "node:crypto";
739
740
  import { promises as fs2 } from "node:fs";
@@ -857,10 +858,10 @@ class CheckpointStore {
857
858
  }
858
859
  }
859
860
 
860
- // ../core/src/cli/permissions.ts
861
+ // packages/core/src/cli/permissions.ts
861
862
  import { createHash as createHash2 } from "node:crypto";
862
863
 
863
- // ../core/src/cli/command.ts
864
+ // packages/core/src/cli/command.ts
864
865
  import { spawn as spawn2 } from "node:child_process";
865
866
  import { constants } from "node:os";
866
867
  var ARCHYMEDES_CREDENTIAL_ENV_NAMES = [
@@ -1209,13 +1210,13 @@ Command cancelled and its process tree was terminated.`;
1209
1210
  return;
1210
1211
  forcedExitCode = 124;
1211
1212
  stderr += `
1212
- Command exceeded ${options.timeoutMs}ms and was killed.`;
1213
+ Command exceeded its ${options.timeoutMs >= 1000 ? `${Math.round(options.timeoutMs / 1000)}s` : `${options.timeoutMs}ms`} limit and was killed. If it needs longer, run it again with a larger timeoutSeconds.`;
1213
1214
  terminate();
1214
1215
  }, options.timeoutMs);
1215
1216
  });
1216
1217
  };
1217
1218
 
1218
- // ../core/src/cli/safety.ts
1219
+ // packages/core/src/cli/safety.ts
1219
1220
  var TASK_RULES = [
1220
1221
  { category: "credentials", reason: "credential disclosure or high-impact credential change", pattern: /\b(?:export|expose|reveal|print|show|share|send|upload|publish|rotate|revoke)\b.{0,60}\b(?:api[ _-]?key|api[ _-]?token|access[ _-]?token|auth[ _-]?token|password|private[ _-]?key|secret|credential)s?\b|\b(?:set|add|store|save|replace)\b.{0,45}\b(?:production|prod|live)\b.{0,45}\b(?:api[ _-]?key|api[ _-]?token|access[ _-]?token|auth[ _-]?token|password|private[ _-]?key|secret|credential)s?\b/i },
1221
1222
  { category: "destructive", reason: "destructive data or repository operation", pattern: /(?:(?<!git\s)\brm\s+[^\n]*(?:-[^\n]*[rf]\b|--recursive|--force)|\bfind\s+[^\n]*-delete\b|\b(?:delete|drop|erase|purge|truncate|wipe|destroy|reset)\b.{0,45}\b(?:all|database|table|records?|history|account|branch|repository|production|live)\b)/i },
@@ -1277,7 +1278,7 @@ function assessToolSafety(call, tool) {
1277
1278
  };
1278
1279
  }
1279
1280
 
1280
- // ../core/src/cli/permissions.ts
1281
+ // packages/core/src/cli/permissions.ts
1281
1282
  var ARCHYMEDES_CAPABILITIES = {
1282
1283
  read: "workspace.files.read",
1283
1284
  write: "workspace.files",
@@ -1722,7 +1723,7 @@ function describeToolCall(call, tool) {
1722
1723
  }
1723
1724
  }
1724
1725
 
1725
- // ../core/src/cli/memory.ts
1726
+ // packages/core/src/cli/memory.ts
1726
1727
  import { promises as fs3 } from "node:fs";
1727
1728
  import os from "node:os";
1728
1729
  import path3 from "node:path";
@@ -1888,7 +1889,7 @@ function memoryPromptBlock(entries) {
1888
1889
  `);
1889
1890
  }
1890
1891
 
1891
- // ../core/src/cli/environment.ts
1892
+ // packages/core/src/cli/environment.ts
1892
1893
  import os2 from "node:os";
1893
1894
  var BASE_PROBES = ["git", "node", "bun", "npm", "pnpm", "yarn", "rg", "python3"];
1894
1895
  var MARKER_PROBES = [
@@ -1986,13 +1987,13 @@ function describeEnvironment(report) {
1986
1987
  `);
1987
1988
  }
1988
1989
 
1989
- // ../core/src/cli/prompt.ts
1990
+ // packages/core/src/cli/prompt.ts
1990
1991
  import { createHash as createHash4 } from "node:crypto";
1991
1992
  import { promises as fs5 } from "node:fs";
1992
1993
  import os3 from "node:os";
1993
1994
  import path5 from "node:path";
1994
1995
 
1995
- // ../core/src/cli/workspace.ts
1996
+ // packages/core/src/cli/workspace.ts
1996
1997
  import { constants as fsConstants, promises as fs4 } from "node:fs";
1997
1998
  import { spawn as spawn3 } from "node:child_process";
1998
1999
  import { createHash as createHash3 } from "node:crypto";
@@ -2639,7 +2640,7 @@ async function grepWorkspace(root, query, options = {}) {
2639
2640
  return matches;
2640
2641
  }
2641
2642
 
2642
- // ../core/src/cli/defender-playbooks.ts
2643
+ // packages/core/src/cli/defender-playbooks.ts
2643
2644
  var INJECTION_PLAYBOOK = `
2644
2645
  ## Injection
2645
2646
 
@@ -3341,7 +3342,7 @@ function playbookFor(id) {
3341
3342
  return DEFENDER_PLAYBOOK_CATALOG.find((entry) => entry.id === wanted || entry.title.toLowerCase() === wanted);
3342
3343
  }
3343
3344
 
3344
- // ../core/src/cli/token-saver.ts
3345
+ // packages/core/src/cli/token-saver.ts
3345
3346
  var TOKEN_SAVER_CONTEXT_LIMIT = 16384;
3346
3347
  var TOKEN_SAVER_TOOL_RESULT_CHARS = 3000;
3347
3348
  var TOKEN_SAVER_TOTAL_TOOL_RESULT_CHARS = 24000;
@@ -3446,7 +3447,7 @@ function restoreFullHistory(messages, original, sent) {
3446
3447
  return [messages[0], ...original, ...messages.slice(1 + sent.length)];
3447
3448
  }
3448
3449
 
3449
- // ../core/src/cli/prompt.ts
3450
+ // packages/core/src/cli/prompt.ts
3450
3451
  var INSTRUCTION_FILES = ["AGENTS.override.md", "ARCHYMEDES.md", "AGENTS.md", "CLAUDE.md", ".archymedesrules"];
3451
3452
  async function instructionBoundary(root) {
3452
3453
  const requestedRoot = path5.resolve(root);
@@ -3712,7 +3713,7 @@ ${instructions}`);
3712
3713
  `);
3713
3714
  }
3714
3715
 
3715
- // ../core/src/cli/session.ts
3716
+ // packages/core/src/cli/session.ts
3716
3717
  import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
3717
3718
  import { promises as fs6 } from "node:fs";
3718
3719
  import path6 from "node:path";
@@ -4121,17 +4122,17 @@ ${summary.trim()}` },
4121
4122
  ];
4122
4123
  }
4123
4124
 
4124
- // ../core/src/hooks/command.ts
4125
+ // packages/core/src/hooks/command.ts
4125
4126
  function hookCommand(scriptPath, payload, platform) {
4126
4127
  if (platform !== "win32")
4127
4128
  return `env ARCHYMEDES_HOOK_EVENT_B64=${payload} ${scriptPath}`;
4128
4129
  return `set "ARCHYMEDES_HOOK_EVENT_B64=${payload}"&& call "${scriptPath.split("/").join("\\")}"`;
4129
4130
  }
4130
4131
 
4131
- // ../core/src/hooks/types.ts
4132
+ // packages/core/src/hooks/types.ts
4132
4133
  var HOOK_PHASES = ["pre-session", "pre-turn", "pre-tool-use", "post-tool-use", "post-turn", "post-session"];
4133
4134
 
4134
- // ../core/src/hooks/registry.ts
4135
+ // packages/core/src/hooks/registry.ts
4135
4136
  var HOOKS_DIRECTORY = ".archymedes/hooks";
4136
4137
  var HOOK_TIMEOUT_MS = 5000;
4137
4138
  async function scriptsIn(workspace, phaseDirectory) {
@@ -4234,7 +4235,7 @@ class HookRegistry {
4234
4235
  return warnings;
4235
4236
  }
4236
4237
  }
4237
- // ../core/src/mcp/config.ts
4238
+ // packages/core/src/mcp/config.ts
4238
4239
  var MCP_CONFIG_PATH = ".archymedes/mcp.json";
4239
4240
  function isPlainObject(value) {
4240
4241
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4289,7 +4290,7 @@ async function discoverMcpServers(workspace) {
4289
4290
  }
4290
4291
  return servers;
4291
4292
  }
4292
- // ../core/src/mcp/http-transport.ts
4293
+ // packages/core/src/mcp/http-transport.ts
4293
4294
  class HttpMcpTransport {
4294
4295
  config;
4295
4296
  requestTimeoutMs;
@@ -4445,7 +4446,7 @@ function isJsonRpcNotification(value) {
4445
4446
  return isPlainObject2(value) && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
4446
4447
  }
4447
4448
 
4448
- // ../core/src/mcp/stdio-transport.ts
4449
+ // packages/core/src/mcp/stdio-transport.ts
4449
4450
  import { spawn as spawn4 } from "node:child_process";
4450
4451
  import { createInterface } from "node:readline";
4451
4452
  class StdioMcpTransport {
@@ -4547,7 +4548,7 @@ function isJsonRpcNotification2(value) {
4547
4548
  return typeof value === "object" && value !== null && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
4548
4549
  }
4549
4550
 
4550
- // ../core/src/mcp/connection.ts
4551
+ // packages/core/src/mcp/connection.ts
4551
4552
  class McpConnection {
4552
4553
  config;
4553
4554
  transport;
@@ -4609,7 +4610,7 @@ class McpConnection {
4609
4610
  }
4610
4611
  var MCP_PROTOCOL_VERSION = "2024-11-05";
4611
4612
  var REQUEST_TIMEOUT_MS = 15000;
4612
- // ../core/src/mcp/client.ts
4613
+ // packages/core/src/mcp/client.ts
4613
4614
  class McpToolProvider {
4614
4615
  connection;
4615
4616
  kind = "mcp";
@@ -4634,7 +4635,7 @@ class McpToolProvider {
4634
4635
  this.connection.close();
4635
4636
  }
4636
4637
  }
4637
- // ../core/src/cli/plugins.ts
4638
+ // packages/core/src/cli/plugins.ts
4638
4639
  var PLUGINS_DIRECTORY = ".archymedes/plugins";
4639
4640
  function isPlainObject3(value) {
4640
4641
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4683,7 +4684,7 @@ async function discoverPlugins(workspace) {
4683
4684
  return plugins;
4684
4685
  }
4685
4686
 
4686
- // ../core/src/cli/tool-schema.ts
4687
+ // packages/core/src/cli/tool-schema.ts
4687
4688
  class ToolArgumentError extends Error {
4688
4689
  constructor(message) {
4689
4690
  super(message);
@@ -4727,6 +4728,44 @@ function assertSupportedSchema(toolName, schema) {
4727
4728
  }
4728
4729
  }
4729
4730
  }
4731
+ var PARAMETER_SYNONYMS = {
4732
+ path: ["file_path", "filePath", "filepath", "file", "filename", "target_file", "absolute_path", "relative_path", "dir", "directory"],
4733
+ content: ["contents", "file_text", "text", "data"],
4734
+ oldText: ["old_string", "old_str", "oldString", "old_text", "search"],
4735
+ newText: ["new_string", "new_str", "newString", "new_text", "replacement"],
4736
+ replaceAll: ["replace_all"],
4737
+ command: ["cmd", "shell_command", "script"],
4738
+ timeoutMs: ["timeout_ms"],
4739
+ timeoutSeconds: ["timeout", "timeout_seconds", "timeout_secs", "timeoutSecs"],
4740
+ query: ["q", "search_query"],
4741
+ pattern: ["glob"],
4742
+ include: ["include_pattern", "file_pattern"],
4743
+ url: ["uri", "link"]
4744
+ };
4745
+ function coerceScalar(type, value) {
4746
+ if (type === "string") {
4747
+ if (typeof value === "object" && value !== null)
4748
+ return JSON.stringify(value);
4749
+ if (typeof value === "number" && Number.isFinite(value))
4750
+ return String(value);
4751
+ if (typeof value === "boolean")
4752
+ return String(value);
4753
+ return;
4754
+ }
4755
+ if (type === "integer") {
4756
+ if (typeof value === "number" && Number.isFinite(value) && Math.abs(value - Math.round(value)) < 0.000000001)
4757
+ return Math.round(value);
4758
+ if (typeof value === "string" && /^\s*-?\d+\s*$/.test(value))
4759
+ return Number(value.trim());
4760
+ return;
4761
+ }
4762
+ if (typeof value === "string" && /^\s*(true|false)\s*$/i.test(value))
4763
+ return value.trim().toLowerCase() === "true";
4764
+ return;
4765
+ }
4766
+ function describe(value) {
4767
+ return Array.isArray(value) ? "an array" : value === null ? "null" : typeof value === "object" ? "an object" : `a ${typeof value}`;
4768
+ }
4730
4769
  function checkScalar(type, value, label) {
4731
4770
  if (type === "string") {
4732
4771
  if (typeof value !== "string")
@@ -4741,17 +4780,36 @@ function checkScalar(type, value, label) {
4741
4780
  if (typeof value !== "boolean")
4742
4781
  throw new ToolArgumentError(`${label} must be true or false`);
4743
4782
  }
4744
- function validateToolArguments(toolName, schema, args) {
4745
- if (!isPlainObject4(args))
4783
+ function normalizeToolArguments(toolName, schema, args) {
4784
+ let input = args;
4785
+ const notes = [];
4786
+ if (typeof input === "string") {
4787
+ try {
4788
+ const parsed = JSON.parse(input);
4789
+ if (isPlainObject4(parsed)) {
4790
+ input = parsed;
4791
+ notes.push("arguments were JSON text; read as an object");
4792
+ }
4793
+ } catch {}
4794
+ }
4795
+ if (!isPlainObject4(input))
4746
4796
  throw new ToolArgumentError(`${toolName} arguments must be a JSON object`);
4747
4797
  const properties = schema.properties ?? {};
4748
4798
  const required = new Set(schema.required ?? []);
4749
4799
  const present = {};
4750
- for (const [key, value] of Object.entries(args)) {
4800
+ for (const [given, value] of Object.entries(input)) {
4801
+ let key = given;
4802
+ if (!properties[key]) {
4803
+ const meant = Object.entries(PARAMETER_SYNONYMS).find(([target, synonyms]) => properties[target] && synonyms.includes(given) && !(target in input));
4804
+ if (meant) {
4805
+ key = meant[0];
4806
+ notes.push(`${given} read as ${key}`);
4807
+ }
4808
+ }
4751
4809
  const property = properties[key];
4752
4810
  if (!property) {
4753
4811
  const known = Object.keys(properties);
4754
- throw new ToolArgumentError(`${toolName} has no parameter "${key}". It accepts: ${known.length > 0 ? known.join(", ") : "no parameters"}.`);
4812
+ throw new ToolArgumentError(`${toolName} has no parameter "${given}". It accepts: ${known.length > 0 ? known.join(", ") : "no parameters"}.`);
4755
4813
  }
4756
4814
  if (value === undefined || value === null) {
4757
4815
  if (required.has(key))
@@ -4760,21 +4818,34 @@ function validateToolArguments(toolName, schema, args) {
4760
4818
  }
4761
4819
  if (property.type === "array") {
4762
4820
  const items = Array.isArray(value) ? value : [value];
4763
- items.forEach((item, index) => checkScalar(property.items.type, item, `${toolName}.${key}[${index}]`));
4764
- present[key] = items;
4821
+ present[key] = items.map((item, index) => scalar(property.items.type, item, `${toolName}.${key}[${index}]`, notes));
4765
4822
  continue;
4766
4823
  }
4767
- checkScalar(property.type, value, `${toolName}.${key}`);
4768
- present[key] = value;
4824
+ present[key] = scalar(property.type, value, `${toolName}.${key}`, notes);
4769
4825
  }
4770
4826
  for (const key of required) {
4771
4827
  if (!(key in present))
4772
4828
  throw new ToolArgumentError(`${toolName} requires ${key}`);
4773
4829
  }
4774
- return present;
4830
+ return { value: present, notes };
4831
+ }
4832
+ function scalar(type, value, label, notes) {
4833
+ try {
4834
+ checkScalar(type, value, label);
4835
+ return value;
4836
+ } catch (error) {
4837
+ const repaired = coerceScalar(type, value);
4838
+ if (repaired === undefined)
4839
+ throw error;
4840
+ notes.push(`${label} was ${describe(value)}; read as ${type === "string" && typeof value === "object" ? "JSON text" : `${type === "integer" ? "an" : "a"} ${type}`}`);
4841
+ return repaired;
4842
+ }
4843
+ }
4844
+ function validateToolArguments(toolName, schema, args) {
4845
+ return normalizeToolArguments(toolName, schema, args).value;
4775
4846
  }
4776
4847
 
4777
- // ../core/src/skills/manifest.ts
4848
+ // packages/core/src/skills/manifest.ts
4778
4849
  var SKILLS_DIRECTORY = ".archymedes/skills";
4779
4850
  function isPlainObject5(value) {
4780
4851
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4830,7 +4901,7 @@ function shellQuote(value, platform) {
4830
4901
  return `'${value.replace(/'/g, `'\\''`)}'`;
4831
4902
  return `"${value.replace(/"/g, '""').replace(/%/g, "%%")}"`;
4832
4903
  }
4833
- // ../core/src/skills/provider.ts
4904
+ // packages/core/src/skills/provider.ts
4834
4905
  class SkillToolProvider {
4835
4906
  id;
4836
4907
  skillsDirectory;
@@ -4860,7 +4931,7 @@ ${body}`, isError: result.exitCode !== 0 };
4860
4931
  }
4861
4932
  }
4862
4933
  var DEFAULT_SKILL_TIMEOUT_MS = 60000;
4863
- // ../core/src/cli/external-tools.ts
4934
+ // packages/core/src/cli/external-tools.ts
4864
4935
  var IMPLICIT_SKILL_PROVIDER_ID = "local-skills";
4865
4936
  async function loadLocalExternalTooling(workspace) {
4866
4937
  const providers = [new SkillToolProvider(IMPLICIT_SKILL_PROVIDER_ID, SKILLS_DIRECTORY, workspace)];
@@ -4901,7 +4972,7 @@ async function loadLocalExternalTooling(workspace) {
4901
4972
  };
4902
4973
  }
4903
4974
 
4904
- // ../core/src/cli/nested-instructions.ts
4975
+ // packages/core/src/cli/nested-instructions.ts
4905
4976
  class NestedInstructionTracker {
4906
4977
  workspace;
4907
4978
  seenDirectories = new Set;
@@ -4950,7 +5021,7 @@ ${blocks}`;
4950
5021
  }
4951
5022
  }
4952
5023
 
4953
- // ../core/src/cli/safe-fetch.ts
5024
+ // packages/core/src/cli/safe-fetch.ts
4954
5025
  import { lookup } from "node:dns/promises";
4955
5026
  import { isIP } from "node:net";
4956
5027
  var defaultResolveHost = async (hostname) => (await lookup(hostname, { all: true, verbatim: true })).map((entry) => entry.address);
@@ -5112,7 +5183,7 @@ async function fetchPublicText(input, options = {}) {
5112
5183
  return { ok: false, error: "too many redirects" };
5113
5184
  }
5114
5185
 
5115
- // ../core/src/cli/secret-scan.ts
5186
+ // packages/core/src/cli/secret-scan.ts
5116
5187
  var SECRET_PATTERNS = [
5117
5188
  { name: "AWS access key", regex: /AKIA[0-9A-Z]{16}/, severity: "critical" },
5118
5189
  { name: "GitHub token", regex: /gh[pousr]_[A-Za-z0-9]{36,255}/, severity: "critical" },
@@ -5143,7 +5214,7 @@ function findSecretsInLine(line) {
5143
5214
  return found;
5144
5215
  }
5145
5216
 
5146
- // ../core/src/cli/tool-providers.ts
5217
+ // packages/core/src/cli/tool-providers.ts
5147
5218
  var DEFAULT_EXTERNAL_TOOL_TIMEOUT_MS = 30000;
5148
5219
  async function toolsFromProvider(provider, timeoutMs = DEFAULT_EXTERNAL_TOOL_TIMEOUT_MS) {
5149
5220
  const externalTools = await provider.listTools();
@@ -5185,7 +5256,7 @@ async function collectExternalTools(providers, timeoutMs) {
5185
5256
  return collected;
5186
5257
  }
5187
5258
 
5188
- // ../core/src/cli/deploy.ts
5259
+ // packages/core/src/cli/deploy.ts
5189
5260
  var DEPLOY_PROVIDERS = {
5190
5261
  vercel: {
5191
5262
  id: "vercel",
@@ -5309,7 +5380,7 @@ function deployPlan(target, detection, options = {}) {
5309
5380
  return { commands, notes };
5310
5381
  }
5311
5382
 
5312
- // ../core/src/cli/compute.ts
5383
+ // packages/core/src/cli/compute.ts
5313
5384
  var MAX_INPUT = 2000;
5314
5385
  var MAX_DEPTH = 64;
5315
5386
  var FACTORIAL_LIMIT = 170;
@@ -5861,11 +5932,11 @@ function compute(expression, options = {}) {
5861
5932
  return { value: result, exact, rendered, radixRendered, warnings };
5862
5933
  }
5863
5934
 
5864
- // ../core/src/cli/tools-extra/git.ts
5935
+ // packages/core/src/cli/tools-extra/git.ts
5865
5936
  import { execFile } from "node:child_process";
5866
5937
  import path7 from "node:path";
5867
5938
 
5868
- // ../core/src/cli/tools-extra/shared.ts
5939
+ // packages/core/src/cli/tools-extra/shared.ts
5869
5940
  import { promises as fs7 } from "node:fs";
5870
5941
  function resolvedLimits(options) {
5871
5942
  return options.limits ?? DEFAULT_WORKSPACE_LIMITS;
@@ -5920,7 +5991,7 @@ function truncateText(text, maxChars, hint) {
5920
5991
  [truncated: showed ${cut.length} of ${text.length} chars. ${hint}]`, truncated: true };
5921
5992
  }
5922
5993
 
5923
- // ../core/src/cli/tools-extra/git.ts
5994
+ // packages/core/src/cli/tools-extra/git.ts
5924
5995
  var GIT_BASE_ARGS = ["--no-pager", "-c", "core.fsmonitor=false", "-c", "core.quotepath=false", "-c", "color.ui=false"];
5925
5996
  var MAX_GIT_OUTPUT = 16 * 1024 * 1024;
5926
5997
  function runGit2(root, args, timeoutMs) {
@@ -6034,7 +6105,7 @@ function renderStatus(status) {
6034
6105
  const head = branch.head ?? `detached at ${branch.oid?.slice(0, 12) ?? "unknown"}`;
6035
6106
  const tracking = branch.upstream ? ` → ${branch.upstream} (ahead ${branch.ahead}, behind ${branch.behind})` : "";
6036
6107
  const lines = [`On ${head}${branch.oid ? "" : " (no commits yet)"}${tracking}`];
6037
- const describe = (entry, letter) => ` ${STATE_WORDS[letter] ?? letter}: ${entry.originalPath ? `${entry.originalPath} -> ` : ""}${entry.path}`;
6108
+ const describe2 = (entry, letter) => ` ${STATE_WORDS[letter] ?? letter}: ${entry.originalPath ? `${entry.originalPath} -> ` : ""}${entry.path}`;
6038
6109
  const staged = status.entries.filter((entry) => (entry.kind === "changed" || entry.kind === "renamed") && entry.index !== ".");
6039
6110
  const unstaged = status.entries.filter((entry) => (entry.kind === "changed" || entry.kind === "renamed") && entry.worktree !== ".");
6040
6111
  const conflicts = status.entries.filter((entry) => entry.kind === "unmerged");
@@ -6042,9 +6113,9 @@ function renderStatus(status) {
6042
6113
  if (conflicts.length > 0)
6043
6114
  lines.push(`Conflicts (${conflicts.length}):`, ...conflicts.map((entry) => ` both ${entry.index}${entry.worktree}: ${entry.path}`));
6044
6115
  if (staged.length > 0)
6045
- lines.push(`Staged (${staged.length}):`, ...staged.map((entry) => describe(entry, entry.index)));
6116
+ lines.push(`Staged (${staged.length}):`, ...staged.map((entry) => describe2(entry, entry.index)));
6046
6117
  if (unstaged.length > 0)
6047
- lines.push(`Not staged (${unstaged.length}):`, ...unstaged.map((entry) => describe(entry, entry.worktree)));
6118
+ lines.push(`Not staged (${unstaged.length}):`, ...unstaged.map((entry) => describe2(entry, entry.worktree)));
6048
6119
  if (untracked.length > 0)
6049
6120
  lines.push(`Untracked (${untracked.length}):`, ...untracked.map((entry) => ` ${entry.path}`));
6050
6121
  if (status.entries.length === 0)
@@ -6202,7 +6273,7 @@ function createGitTools(options) {
6202
6273
  ];
6203
6274
  }
6204
6275
 
6205
- // ../core/src/cli/tools-extra/image.ts
6276
+ // packages/core/src/cli/tools-extra/image.ts
6206
6277
  function createImageTools(options) {
6207
6278
  const { root } = options;
6208
6279
  const limits = { ...resolvedLimits(options), maxReadBytes: MAX_IMAGE_BYTES };
@@ -6237,7 +6308,7 @@ function createImageTools(options) {
6237
6308
  ];
6238
6309
  }
6239
6310
 
6240
- // ../core/src/cli/tools-extra/notebook.ts
6311
+ // packages/core/src/cli/tools-extra/notebook.ts
6241
6312
  import { randomBytes } from "node:crypto";
6242
6313
  function toSourceLines(source) {
6243
6314
  if (source === "")
@@ -6418,7 +6489,7 @@ function createNotebookTools(options) {
6418
6489
  ];
6419
6490
  }
6420
6491
 
6421
- // ../core/src/cli/tools-extra/repo-map.ts
6492
+ // packages/core/src/cli/tools-extra/repo-map.ts
6422
6493
  var REPO_MAP_DEFAULT_CHARS = 12000;
6423
6494
  var REPO_MAP_MAX_CHARS = 60000;
6424
6495
  var ENTRY_NAMES = /(?:^|\/)(?:index|main|app|lib|mod|__init__|server|cli|program)\.[^/]+$/i;
@@ -6688,7 +6759,7 @@ ${lines.join(`
6688
6759
  ];
6689
6760
  }
6690
6761
 
6691
- // ../core/src/cli/tools-extra/symbols.ts
6762
+ // packages/core/src/cli/tools-extra/symbols.ts
6692
6763
  import { promises as fs8 } from "node:fs";
6693
6764
  import path8 from "node:path";
6694
6765
  var EXTENSIONS = {
@@ -7022,13 +7093,13 @@ class SymbolIndex {
7022
7093
  }
7023
7094
  }
7024
7095
 
7025
- // ../core/src/cli/tools-extra/index.ts
7096
+ // packages/core/src/cli/tools-extra/index.ts
7026
7097
  function createExtraTools(options) {
7027
7098
  const index = options.symbolIndex ?? new SymbolIndex(options.root, resolvedLimits(options));
7028
7099
  return [...createRepoMapTools(options, index), ...createGitTools(options), ...createNotebookTools(options), ...createImageTools(options)];
7029
7100
  }
7030
7101
 
7031
- // ../core/src/cli/tools.ts
7102
+ // packages/core/src/cli/tools.ts
7032
7103
  class TodoList {
7033
7104
  items = [];
7034
7105
  nextId = 1;
@@ -7299,6 +7370,7 @@ ${content}`,
7299
7370
  const updated = applyTextEdits(existing.content, edits, existing.path);
7300
7371
  await workspace.writeFile(filePath, updated.content);
7301
7372
  tracker.record(existing.path, updated.content);
7373
+ writtenFiles.add(existing.path);
7302
7374
  return {
7303
7375
  content: `Edited ${existing.path} (${updated.replacements} replacement${updated.replacements === 1 ? "" : "s"}).`,
7304
7376
  data: { path: existing.path, replacements: updated.replacements }
@@ -7310,7 +7382,11 @@ ${content}`,
7310
7382
  description: `Run a bounded command in the project root (builds, tests, linters). Dev servers go through start_application. ${workspace.commandGuidance}`,
7311
7383
  inputSchema: {
7312
7384
  type: "object",
7313
- properties: { command: { type: "string" }, timeoutMs: { type: "integer" } },
7385
+ properties: {
7386
+ command: { type: "string" },
7387
+ timeoutSeconds: { type: "integer", description: `Default and most: ${Math.round(commandTimeoutMs / 1000)}.` },
7388
+ timeoutMs: { type: "integer" }
7389
+ },
7314
7390
  required: ["command"],
7315
7391
  additionalProperties: false
7316
7392
  },
@@ -7330,7 +7406,7 @@ ${content}`,
7330
7406
  data: { command, reason: "persistent_foreground_command" }
7331
7407
  };
7332
7408
  }
7333
- const timeoutMs = Math.min(optionalInteger(args.timeoutMs, "timeoutMs") ?? commandTimeoutMs, commandTimeoutMs);
7409
+ const { timeoutMs, note: timeoutNote } = commandTimeout(args, commandTimeoutMs);
7334
7410
  const result = await workspace.runCommand(command, timeoutMs, context.signal);
7335
7411
  const body = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
7336
7412
  `) || "(no output)";
@@ -7338,21 +7414,25 @@ ${content}`,
7338
7414
  if (missing) {
7339
7415
  return {
7340
7416
  content: `exit ${result.exitCode}
7341
- ${body}
7417
+ ${body}${timeoutNote ? `
7418
+
7419
+ [${timeoutNote}]` : ""}
7342
7420
 
7343
7421
  '${missing}' is not available in this environment. Do not retry this command. Use a program listed as available in the environment section, or check for an alternative with 'command -v' before running it.`,
7344
7422
  isError: true,
7345
7423
  data: { command, exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr, missingProgram: missing }
7346
7424
  };
7347
7425
  }
7348
- const kind = classifyVerification(command) ?? (runsWrittenScript(command, writtenFiles) ? "smoke" : null);
7426
+ const kind = classifyVerification(command) ?? (runsWrittenScript(command, writtenFiles) ? "smoke" : null) ?? (runsInlineAssertion(command) ? "tests" : null);
7349
7427
  const rejectedVerification = kind && result.exitCode === 0 ? rejectedVerificationReason(command, result) : null;
7350
7428
  const verificationNote = rejectedVerification ? `
7351
7429
 
7352
7430
  Archymedes did not accept this as verification: ${rejectedVerification}` : "";
7353
7431
  return {
7354
7432
  content: `exit ${result.exitCode}
7355
- ${body}${verificationNote}`,
7433
+ ${body}${verificationNote}${timeoutNote ? `
7434
+
7435
+ [${timeoutNote}]` : ""}`,
7356
7436
  isError: result.exitCode !== 0,
7357
7437
  data: { command, exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr, ...kind && !rejectedVerification ? { verificationKind: kind } : {}, ...rejectedVerification ? { verificationRejectedReason: rejectedVerification } : {} },
7358
7438
  verification: kind && result.exitCode === 0 && !rejectedVerification ? { passed: true, kind, scope: "targeted", summary: `${command} exited 0` } : undefined
@@ -7959,10 +8039,16 @@ Written to ${scope === "project" ? ".archymedes/memory.md" : result.file} — th
7959
8039
  assertSupportedSchema(tool.name, tool.inputSchema);
7960
8040
  const schema = tool.inputSchema;
7961
8041
  const execute = tool.execute.bind(tool);
7962
- const withValidatedArguments = async (argumentsValue, context) => execute(validateToolArguments(tool.name, schema, argumentsValue), context);
8042
+ const withValidatedArguments = async (argumentsValue, context) => {
8043
+ const { value, notes } = normalizeToolArguments(tool.name, schema, argumentsValue);
8044
+ const result = await execute(value, context);
8045
+ return notes.length === 0 ? result : { ...result, content: `${result.content}
8046
+
8047
+ [Archymedes adjusted this call: ${notes.join("; ")}.]` };
8048
+ };
7963
8049
  const withInstructions = !instructions || !PATH_TOOLS.has(tool.name) ? withValidatedArguments : async (argumentsValue, context) => {
7964
8050
  const result = await withValidatedArguments(argumentsValue, context);
7965
- const touchedPath = typeof argumentsValue.path === "string" ? argumentsValue.path : undefined;
8051
+ const touchedPath = pathArgument(tool.name, schema, argumentsValue);
7966
8052
  if (!touchedPath || result.isError)
7967
8053
  return result;
7968
8054
  const note = NestedInstructionTracker.render(await instructions.discover(touchedPath));
@@ -7989,6 +8075,33 @@ ${warnings.join(`
7989
8075
  };
7990
8076
  });
7991
8077
  }
8078
+ function commandTimeout(args, ceilingMs) {
8079
+ const seconds = optionalInteger(args.timeoutSeconds, "timeoutSeconds");
8080
+ const millis = optionalInteger(args.timeoutMs, "timeoutMs");
8081
+ let asked;
8082
+ let note;
8083
+ if (seconds !== undefined)
8084
+ asked = seconds * 1000;
8085
+ else if (millis !== undefined && millis < 1000) {
8086
+ asked = millis * 1000;
8087
+ note = `timeoutMs ${millis} read as ${millis} seconds; use timeoutSeconds`;
8088
+ } else
8089
+ asked = millis;
8090
+ if (asked === undefined)
8091
+ return { timeoutMs: ceilingMs };
8092
+ if (asked > ceilingMs) {
8093
+ return { timeoutMs: ceilingMs, note: `${note ? `${note}; ` : ""}limited to the ${Math.round(ceilingMs / 1000)}s most a command may run` };
8094
+ }
8095
+ return { timeoutMs: Math.max(asked, 1000), ...note ? { note } : {} };
8096
+ }
8097
+ function pathArgument(toolName, schema, args) {
8098
+ try {
8099
+ const path9 = normalizeToolArguments(toolName, schema, args).value.path;
8100
+ return typeof path9 === "string" ? path9 : undefined;
8101
+ } catch {
8102
+ return;
8103
+ }
8104
+ }
7992
8105
  var PATH_TOOLS = new Set(["read_file", "write_file", "edit_file"]);
7993
8106
  function idList(value, name) {
7994
8107
  if (value === undefined || value === null)
@@ -8028,7 +8141,7 @@ var TEST_COMMAND = /\b(tests?|pytest|jest|vitest|mocha|jasmine|karma|ava|rspec|m
8028
8141
  var CHECK_COMMAND = /\b(typecheck|tsc|lint|eslint|pylint|ruff|flake8|mypy|pyright|check|build|compile|py_compile|vet|clippy|rubocop|audit|fmt|format)\b/i;
8029
8142
  var BEHAVIOR_COMMAND = /\b(e2e|end-to-end|playwright|cypress|puppeteer|selenium|webdriver|testcafe|nightwatch|integration|behave|cucumber|supertest|testcontainers)\b/i;
8030
8143
  var SMOKE_COMMAND = /\b(smoke|healthcheck|health[-_ ]?check|curl|wget|httpie|\bhttp\s+(?:get|post)\b|playwright\s+screenshot)\b/i;
8031
- var PERSISTENT_COMMAND = /(?:^|(?:&&|;|\|)\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve)(?:\s|$)|(?:vite|next\s+dev|webpack\s+serve)(?:\s|$)|bun\s+run\s+--hot\b)|(?:^|\s)--watch(?:\s|$)|\b(?:tsc|jest|vitest|mocha|sass|tailwindcss|esbuild|webpack|rollup|nodemon|parcel|tsup|swc)\b[^|;&\n]*\s-w(?:\s|$)/i;
8144
+ var PERSISTENT_COMMAND = /(?:^|(?:&&|;|\|)\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve)(?:\s|$)|(?:vite|next\s+dev|webpack\s+serve)(?:\s|$)|bun\s+run\s+--hot\b)|(?:^|\s)--watch(?:\s|$)|\b(?:tsc|vitest|mocha|tailwindcss|webpack|rollup|nodemon|tsup|swc)\b[^|;&\n]*\s-w(?:\s|$)/i;
8032
8145
  var CD_PREFIX = /^\s*cd\s+(?:[^&\n|;]|\&(?!\&))+&&\s*/;
8033
8146
  function verificationTarget(command) {
8034
8147
  let target = command;
@@ -8078,6 +8191,18 @@ function runsWrittenScript(command, written) {
8078
8191
  const clean = file.replace(/^(\.\/)+/, "");
8079
8192
  return [...written].some((path9) => clean === path9 || clean.endsWith(`/${path9}`));
8080
8193
  }
8194
+ function runsInlineAssertion(command) {
8195
+ let tokens;
8196
+ try {
8197
+ tokens = tokenizeCommand(verificationTarget(command));
8198
+ } catch {
8199
+ return false;
8200
+ }
8201
+ if (tokens.length < 3 || !SCRIPT_INTERPRETER.test(tokens[0].split("/").pop() ?? ""))
8202
+ return false;
8203
+ const flag = tokens.findIndex((token) => token === "-c" || token === "-e" || token === "--eval");
8204
+ return flag > 0 && flag + 1 < tokens.length && /\bassert\b|console\.assert|assert\.(?:equal|strictEqual|deepEqual|ok)\b/.test(tokens[flag + 1]);
8205
+ }
8081
8206
  function classifyVerification(command) {
8082
8207
  const target = verificationTarget(command);
8083
8208
  if (BEHAVIOR_COMMAND.test(target))
@@ -8095,7 +8220,7 @@ function stripMarkup(html) {
8095
8220
  `).replace(/[ \t]{2,}/g, " ").trim();
8096
8221
  }
8097
8222
 
8098
- // ../core/src/money.ts
8223
+ // packages/core/src/money.ts
8099
8224
  var CURRENCIES = (() => {
8100
8225
  try {
8101
8226
  return Intl.supportedValuesOf("currency");
@@ -8185,7 +8310,7 @@ function priceUsage(usage, prices) {
8185
8310
  return money(micros, prices.currency);
8186
8311
  }
8187
8312
 
8188
- // ../core/src/pricing.ts
8313
+ // packages/core/src/pricing.ts
8189
8314
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
8190
8315
  function assertDate(value, label) {
8191
8316
  if (!ISO_DATE.test(value) || Number.isNaN(Date.parse(value)))
@@ -8274,7 +8399,7 @@ function priceUnits(record, quantities) {
8274
8399
  return money(units * 1e6, record.currency);
8275
8400
  }
8276
8401
 
8277
- // ../core/src/providers/free-usage.ts
8402
+ // packages/core/src/providers/free-usage.ts
8278
8403
  import { promises as fs9 } from "node:fs";
8279
8404
  import path9 from "node:path";
8280
8405
  var FREE_REMAINING_TOKENS_HEADER = "x-free-remaining-tokens";
@@ -8414,7 +8539,7 @@ class FreeUsageMeter {
8414
8539
  }
8415
8540
  }
8416
8541
 
8417
- // ../core/src/cli/cost.ts
8542
+ // packages/core/src/cli/cost.ts
8418
8543
  function formatTokenFlow(usage) {
8419
8544
  return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
8420
8545
  }
@@ -8690,10 +8815,10 @@ class CostLedger {
8690
8815
  }
8691
8816
  }
8692
8817
 
8693
- // ../core/src/cli/backends.ts
8818
+ // packages/core/src/cli/backends.ts
8694
8819
  import path11 from "node:path";
8695
8820
 
8696
- // ../core/src/sandbox-search.ts
8821
+ // packages/core/src/sandbox-search.ts
8697
8822
  var DEFAULT_IGNORED_DIRECTORIES = [".git", "node_modules", ".next", "dist", "build", "target", "__pycache__", ".venv", "venv", ".pytest_cache", ".mypy_cache", ".ruff_cache", ".turbo", "vendor", ".archymedes"];
8698
8823
  async function listSandboxFiles(sandbox, sandboxId, root, ignoredDirectories = DEFAULT_IGNORED_DIRECTORIES) {
8699
8824
  const result = await sandbox.runCommand(sandboxId, {
@@ -8767,7 +8892,7 @@ function relativeTo(root, absolute) {
8767
8892
  return absolute.startsWith(`${root}/`) ? absolute.slice(root.length + 1) : absolute;
8768
8893
  }
8769
8894
 
8770
- // ../core/src/cli/applications.ts
8895
+ // packages/core/src/cli/applications.ts
8771
8896
  import { spawn as spawn5 } from "node:child_process";
8772
8897
  import { stat } from "node:fs/promises";
8773
8898
  import http from "node:http";
@@ -8955,7 +9080,7 @@ The process produced no logs.`;
8955
9080
  }
8956
9081
  }
8957
9082
 
8958
- // ../core/src/cli/backends.ts
9083
+ // packages/core/src/cli/backends.ts
8959
9084
  var CONFIG_FILE_SCAN_LIMIT = 500;
8960
9085
  function localCommandGuidance(platform) {
8961
9086
  if (platform !== "win32")
@@ -9270,7 +9395,7 @@ async function downloadProject(workspace, localRoot, options = {}) {
9270
9395
  return { written, failed };
9271
9396
  }
9272
9397
 
9273
- // ../core/src/cli/artifacts.ts
9398
+ // packages/core/src/cli/artifacts.ts
9274
9399
  import { createHash as createHash6 } from "node:crypto";
9275
9400
  var ARTIFACT_DIRECTORY = ".archymedes/artifacts";
9276
9401
  var MAX_ARTIFACT_BYTES = 480000;
@@ -9314,12 +9439,12 @@ function countLines(content) {
9314
9439
  return lines;
9315
9440
  }
9316
9441
 
9317
- // ../core/src/cli/defender-brain.ts
9442
+ // packages/core/src/cli/defender-brain.ts
9318
9443
  import { access as access2 } from "node:fs/promises";
9319
9444
  import path14 from "node:path";
9320
9445
  import { fileURLToPath } from "node:url";
9321
9446
 
9322
- // ../core/src/cli/state-client.ts
9447
+ // packages/core/src/cli/state-client.ts
9323
9448
  import { spawn as spawn6 } from "node:child_process";
9324
9449
  import { access } from "node:fs/promises";
9325
9450
  import { createRequire } from "node:module";
@@ -9533,7 +9658,7 @@ async function tryConnectArchymedesState(options = {}) {
9533
9658
  return binary ? ArchymedesStateClient.connect({ ...options, binary }) : null;
9534
9659
  }
9535
9660
 
9536
- // ../core/src/cli/defender-feed.ts
9661
+ // packages/core/src/cli/defender-feed.ts
9537
9662
  import { createHash as createHash7, createPublicKey, verify as verifySignature } from "node:crypto";
9538
9663
  import { promises as fs10 } from "node:fs";
9539
9664
  import path13 from "node:path";
@@ -9762,7 +9887,7 @@ async function refreshDefenderFeed(options) {
9762
9887
  }
9763
9888
  }
9764
9889
 
9765
- // ../core/src/cli/defender-brain.ts
9890
+ // packages/core/src/cli/defender-brain.ts
9766
9891
  async function existingDirectory(candidates) {
9767
9892
  for (const candidate of candidates) {
9768
9893
  try {
@@ -9848,7 +9973,7 @@ class DefenderBrain {
9848
9973
  }
9849
9974
  }
9850
9975
 
9851
- // ../core/src/cli/tool-profile.ts
9976
+ // packages/core/src/cli/tool-profile.ts
9852
9977
  var MUTATING = /\b(create|write|edit|change|modify|fix|implement|build|install|delete|remove|rename|move|run|test|commit|push|deploy|publish|send|continue|resume|update|add|refactor|replace|rewrite|append|insert|generate|format|upgrade|bump|revert|patch|migrate|scaffold|save|set up|setup)\b/i;
9853
9978
  var REPOSITORY_READING = /\b(review|inspect|audit|analy[sz]e|diagnose|explain|find|locate|search|read|why|error|bug|code|repo(?:sitory)?|project|file|folder|function|class|test|diff)\b/i;
9854
9979
  var DIRECT_CHAT = /^(?:hi|hello|hey|thanks|thank you|who are you|what can you do)[.!?\s]*$/i;
@@ -9875,7 +10000,7 @@ function toolsForProfile(tools, profile) {
9875
10000
  return tools.filter((tool) => tool.effect === "none");
9876
10001
  }
9877
10002
 
9878
- // ../core/src/cli/jev.ts
10003
+ // packages/core/src/cli/jev.ts
9879
10004
  var JEV_API_URL = "https://api.typesafe.ai/v1/systemone";
9880
10005
  var JEV_DEFAULT_MODEL = "jev-latest";
9881
10006
  var JEV_TIMEOUT_MS = 30000;
@@ -10118,7 +10243,7 @@ function verdictFromResponse(response) {
10118
10243
  };
10119
10244
  }
10120
10245
 
10121
- // ../core/src/cli/agent.ts
10246
+ // packages/core/src/cli/agent.ts
10122
10247
  var DELEGATION_TOOLS = new Set(["delegate_task", "delegate_readonly_task"]);
10123
10248
  var EDIT_DIAGNOSTIC_TOOLS = new Set(["edit_file", "write_file"]);
10124
10249
  var EDIT_DIAGNOSTICS_TIMEOUT_MS = 3000;
@@ -10386,10 +10511,12 @@ class ArchymedesAgent {
10386
10511
  get todos() {
10387
10512
  return this.todoList.list();
10388
10513
  }
10389
- diffPatch() {
10514
+ async diffPatch() {
10515
+ await this.pendingCheckpoint;
10390
10516
  return this.checkpoints.diffPatch();
10391
10517
  }
10392
- diffStat() {
10518
+ async diffStat() {
10519
+ await this.pendingCheckpoint;
10393
10520
  return this.checkpoints.diffStat();
10394
10521
  }
10395
10522
  listFiles(pattern = "**/*") {
@@ -10501,6 +10628,7 @@ class ArchymedesAgent {
10501
10628
  if (this.turnAbort)
10502
10629
  throw new Error("Cannot undo while a turn is running");
10503
10630
  await this.acquireOwnership();
10631
+ await this.pendingCheckpoint;
10504
10632
  const checkpoint = this.checkpoints.latest();
10505
10633
  if (!checkpoint)
10506
10634
  return;
@@ -10652,6 +10780,7 @@ ${requested}` : requested;
10652
10780
  }).catch(() => {
10653
10781
  return;
10654
10782
  });
10783
+ this.pendingCheckpoint = checkpointReady;
10655
10784
  }
10656
10785
  const compaction = await this.compactIfNeeded(turnId, objective, turnAbort.signal, tokenSaver);
10657
10786
  compactionActualRwf = compaction.actualRwf;
@@ -10660,10 +10789,10 @@ ${requested}` : requested;
10660
10789
  const runtime = new BoundedAgentRuntime({
10661
10790
  model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, "main"),
10662
10791
  ...this.options.reasoning === "auto" ? { effortPolicy: (signals) => predictEffort({ ...signals, objective, ...this.jevDifficulty ? { difficultyHint: this.jevDifficulty } : {} }) } : {},
10663
- tools: scoped.map((tool) => tool.effect === "none" ? tool : { ...tool, execute: async (args, context) => {
10792
+ tools: scoped.map((tool) => ({ ...tool, execute: async (args, context) => {
10664
10793
  await checkpointReady;
10665
10794
  return tool.execute(args, context);
10666
- } }),
10795
+ } })),
10667
10796
  prices: this.options.prices,
10668
10797
  artifacts: this.artifacts,
10669
10798
  control: {
@@ -10824,6 +10953,7 @@ ${hookWarnings.join(`
10824
10953
  return (verdict.outcomeProbabilities[verdict.outcome] ?? 0) >= 0.5;
10825
10954
  }
10826
10955
  jevCorrectionDepth = 0;
10956
+ pendingCheckpoint = Promise.resolve();
10827
10957
  jevDifficulty;
10828
10958
  difficultyStamp = 0;
10829
10959
  startDifficultyReading(objective, signal) {
@@ -10946,15 +11076,15 @@ function isActiveTurnStatus(status) {
10946
11076
  return status === "queued" || status === "running" || status === "waiting_approval";
10947
11077
  }
10948
11078
 
10949
- // ../core/src/cli/edit-diagnostics.ts
11079
+ // packages/core/src/cli/edit-diagnostics.ts
10950
11080
  import { promises as fs11 } from "node:fs";
10951
11081
  import path16 from "node:path";
10952
11082
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
10953
11083
 
10954
- // ../core/src/lsp/client.ts
11084
+ // packages/core/src/lsp/client.ts
10955
11085
  import { spawn as spawn7, spawnSync } from "node:child_process";
10956
11086
 
10957
- // ../core/src/lsp/diagnostics.ts
11087
+ // packages/core/src/lsp/diagnostics.ts
10958
11088
  function severityName(severity) {
10959
11089
  switch (severity) {
10960
11090
  case 1:
@@ -11060,7 +11190,7 @@ class DiagnosticsCollection {
11060
11190
  }
11061
11191
  }
11062
11192
 
11063
- // ../core/src/lsp/protocol.ts
11193
+ // packages/core/src/lsp/protocol.ts
11064
11194
  var HEADER_SEPARATOR = `\r
11065
11195
  \r
11066
11196
  `;
@@ -11106,7 +11236,7 @@ function isJsonRpcNotification3(value) {
11106
11236
  return typeof value === "object" && value !== null && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
11107
11237
  }
11108
11238
 
11109
- // ../core/src/lsp/client.ts
11239
+ // packages/core/src/lsp/client.ts
11110
11240
  class LspClientError extends Error {
11111
11241
  constructor(message) {
11112
11242
  super(message);
@@ -11317,7 +11447,7 @@ function toLocations(result) {
11317
11447
  return candidates.filter((candidate) => typeof candidate === "object" && candidate !== null && typeof candidate.uri === "string" && typeof candidate.range === "object");
11318
11448
  }
11319
11449
 
11320
- // ../core/src/lsp/servers.ts
11450
+ // packages/core/src/lsp/servers.ts
11321
11451
  import { spawnSync as spawnSync2 } from "node:child_process";
11322
11452
  var LANGUAGE_SERVERS = [
11323
11453
  {
@@ -11458,7 +11588,7 @@ function defaultProbe(command) {
11458
11588
  });
11459
11589
  }
11460
11590
 
11461
- // ../core/src/cli/edit-diagnostics.ts
11591
+ // packages/core/src/cli/edit-diagnostics.ts
11462
11592
  var DEFAULT_TIMEOUT_MS = 1500;
11463
11593
  var DEFAULT_REFINE_MS = 250;
11464
11594
  var DEFAULT_MAX_LINES = 20;
@@ -11679,7 +11809,7 @@ function createLspEditDiagnostics(root, options = {}) {
11679
11809
  });
11680
11810
  }
11681
11811
 
11682
- // ../core/src/providers/price-catalog.ts
11812
+ // packages/core/src/providers/price-catalog.ts
11683
11813
  var ANTHROPIC_VERIFIED = "2026-06-24";
11684
11814
  var ANTHROPIC_SOURCE = "anthropic.com/pricing, recorded 2026-06-24";
11685
11815
  var ANTHROPIC = [
@@ -11731,7 +11861,7 @@ var SERVICES = [
11731
11861
  ];
11732
11862
  var PRICE_CATALOG = definePrices([...ANTHROPIC, ...OAI_COMPAT_LABS, ...SERVICES]);
11733
11863
 
11734
- // ../core/src/providers/free-catalog.ts
11864
+ // packages/core/src/providers/free-catalog.ts
11735
11865
  var FREE_ROUTER = "openrouter/free";
11736
11866
  var FREE_BASE_URL = "https://openrouter.ai/api/v1";
11737
11867
  var FREE_GATEWAY_URL = "";
@@ -11881,7 +12011,7 @@ function isSmallModel(model) {
11881
12011
  return size !== null && size <= SMALL_MODEL_BILLIONS;
11882
12012
  }
11883
12013
 
11884
- // ../core/src/providers/provider-specs.ts
12014
+ // packages/core/src/providers/provider-specs.ts
11885
12015
  var PROVIDER_IDS = [
11886
12016
  "anthropic",
11887
12017
  "openai",
@@ -11942,7 +12072,7 @@ var PROVIDER_INFO = {
11942
12072
  }
11943
12073
  };
11944
12074
 
11945
- // ../core/src/providers/anthropic-agent.ts
12075
+ // packages/core/src/providers/anthropic-agent.ts
11946
12076
  async function collectAnthropicStream(stream, onTextDelta, onOutputProgress) {
11947
12077
  let id = "";
11948
12078
  let model = "";
@@ -12101,7 +12231,7 @@ class AnthropicAgentTurnProvider {
12101
12231
  let client;
12102
12232
  this.call = async (body, signal) => {
12103
12233
  if (!client) {
12104
- const { default: Anthropic } = await import("./index-qvgcwsvm.mjs").catch(() => {
12234
+ const { default: Anthropic } = await import("./index-teq1cta4.mjs").catch(() => {
12105
12235
  throw new Error("The Anthropic provider needs the @anthropic-ai/sdk package. Install it with: npm install @anthropic-ai/sdk");
12106
12236
  });
12107
12237
  client = new Anthropic({ apiKey: options.apiKey, ...options.baseURL ? { baseURL: options.baseURL } : {}, maxRetries: 0 });
@@ -12163,10 +12293,10 @@ class AnthropicAgentTurnProvider {
12163
12293
  }
12164
12294
  }
12165
12295
 
12166
- // ../core/src/providers/archymedes-cloud-agent.ts
12296
+ // packages/core/src/providers/archymedes-cloud-agent.ts
12167
12297
  import { createHash as createHash8, randomUUID as randomUUID5 } from "node:crypto";
12168
12298
 
12169
- // ../core/src/providers/routing-plan.ts
12299
+ // packages/core/src/providers/routing-plan.ts
12170
12300
  function isRecord2(value) {
12171
12301
  return typeof value === "object" && value !== null;
12172
12302
  }
@@ -12238,7 +12368,7 @@ function planCurrency(ranked) {
12238
12368
  return;
12239
12369
  }
12240
12370
 
12241
- // ../core/src/providers/credit-balance.ts
12371
+ // packages/core/src/providers/credit-balance.ts
12242
12372
  function isRecord3(value) {
12243
12373
  return typeof value === "object" && value !== null;
12244
12374
  }
@@ -12273,7 +12403,7 @@ function parseCreditBalance(value) {
12273
12403
  };
12274
12404
  }
12275
12405
 
12276
- // ../core/src/providers/archymedes-cloud-agent.ts
12406
+ // packages/core/src/providers/archymedes-cloud-agent.ts
12277
12407
  class ArchymedesCloudError extends Error {
12278
12408
  status;
12279
12409
  code;
@@ -12490,7 +12620,9 @@ async function readBody(response) {
12490
12620
  }
12491
12621
  }
12492
12622
 
12493
- // ../core/src/providers/request-pacer.ts
12623
+ // packages/core/src/providers/request-pacer.ts
12624
+ var MIN_LEARNABLE_CAP = 8;
12625
+ var LEARNED_CAP_LIFETIME_WINDOWS = 5;
12494
12626
  var DEFAULTS = { baseGapMs: 2000, maxGapMs: 120000, releaseMs: 500 };
12495
12627
 
12496
12628
  class RequestPacer {
@@ -12501,6 +12633,8 @@ class RequestPacer {
12501
12633
  releaseMs;
12502
12634
  windowMs;
12503
12635
  cap;
12636
+ configuredCap;
12637
+ learnedAt = 0;
12504
12638
  starts = [];
12505
12639
  now;
12506
12640
  sleep;
@@ -12510,6 +12644,7 @@ class RequestPacer {
12510
12644
  this.releaseMs = options.releaseMs ?? DEFAULTS.releaseMs;
12511
12645
  this.windowMs = options.windowMs ?? 60000;
12512
12646
  this.cap = options.windowCap !== undefined && options.windowCap >= 1 ? Math.floor(options.windowCap) : undefined;
12647
+ this.configuredCap = this.cap;
12513
12648
  this.now = options.now ?? Date.now;
12514
12649
  this.sleep = options.sleep ?? ((delayMs, signal) => new Promise((resolve, reject) => {
12515
12650
  if (signal?.aborted) {
@@ -12546,6 +12681,10 @@ class RequestPacer {
12546
12681
  }
12547
12682
  async wait(signal) {
12548
12683
  signal?.throwIfAborted();
12684
+ if (this.learnedAt > 0 && this.now() - this.learnedAt > LEARNED_CAP_LIFETIME_WINDOWS * this.windowMs) {
12685
+ this.cap = this.configuredCap;
12686
+ this.learnedAt = 0;
12687
+ }
12549
12688
  if (this.cap !== undefined) {
12550
12689
  for (;; ) {
12551
12690
  const now = this.now();
@@ -12573,15 +12712,17 @@ class RequestPacer {
12573
12712
  reportRateLimited(retryAfterMs) {
12574
12713
  this.prune(this.now());
12575
12714
  const admitted = this.starts.length - 1;
12576
- if (admitted >= 2)
12577
- this.cap = Math.min(this.cap ?? Number.POSITIVE_INFINITY, admitted);
12715
+ if (admitted >= MIN_LEARNABLE_CAP && admitted < (this.cap ?? Number.POSITIVE_INFINITY)) {
12716
+ this.cap = admitted;
12717
+ this.learnedAt = this.now();
12718
+ }
12578
12719
  const doubled = this.gapMs <= 0 ? this.baseGapMs : Math.min(this.maxGapMs, this.gapMs * 2);
12579
12720
  const asked = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0 ? retryAfterMs : 0;
12580
12721
  this.gapMs = Math.min(this.maxGapMs, Math.max(doubled, Math.min(this.maxGapMs, asked)));
12581
12722
  }
12582
12723
  }
12583
12724
 
12584
- // ../core/src/providers/free-catalog-fetch.ts
12725
+ // packages/core/src/providers/free-catalog-fetch.ts
12585
12726
  var MAX_BYTES = 8 * 1024 * 1024;
12586
12727
  async function boundedJson(fetchImpl, url, signal) {
12587
12728
  const response = await fetchImpl(url, { signal, redirect: "error", headers: { accept: "application/json" } });
@@ -12645,7 +12786,7 @@ async function fetchFreeCatalog(options = {}) {
12645
12786
  }
12646
12787
  }
12647
12788
 
12648
- // ../core/src/providers/free-install.ts
12789
+ // packages/core/src/providers/free-install.ts
12649
12790
  import { promises as fs12 } from "node:fs";
12650
12791
  import path17 from "node:path";
12651
12792
  var FREE_INSTALL_HEADER = "x-archymedes-install";
@@ -12823,7 +12964,7 @@ class FreeInstallToken {
12823
12964
  }
12824
12965
  }
12825
12966
 
12826
- // ../core/src/providers/free-errors.ts
12967
+ // packages/core/src/providers/free-errors.ts
12827
12968
  var OPENROUTER_PRIVACY_SETTINGS_URL = "https://openrouter.ai/settings/privacy";
12828
12969
  var OPENROUTER_KEYS_URL = "https://openrouter.ai/keys";
12829
12970
  var OPENROUTER_CREDITS_URL = "https://openrouter.ai/settings/credits";
@@ -12899,7 +13040,7 @@ function describeFreeFailure(input) {
12899
13040
  return { message, retryable: transient, ...retryAfterMs2 ? { retryAfterMs: retryAfterMs2 } : {} };
12900
13041
  }
12901
13042
 
12902
- // ../core/src/providers/free-health.ts
13043
+ // packages/core/src/providers/free-health.ts
12903
13044
  import { promises as fs13 } from "node:fs";
12904
13045
  import path18 from "node:path";
12905
13046
  var FREE_HEALTH_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
@@ -13008,7 +13149,7 @@ class FreeHealthTracker {
13008
13149
  }
13009
13150
  }
13010
13151
 
13011
- // ../core/src/providers/openrouter-key-info.ts
13152
+ // packages/core/src/providers/openrouter-key-info.ts
13012
13153
  var OPENROUTER_KEY_URL = `${FREE_BASE_URL}/key`;
13013
13154
  var OPENROUTER_KEY_INFO_TTL_MS = 60000;
13014
13155
  var KEY_INFO_TIMEOUT_MS = 5000;
@@ -13111,7 +13252,7 @@ function nextUtcMidnight(now) {
13111
13252
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1)).toISOString();
13112
13253
  }
13113
13254
 
13114
- // ../core/src/providers/tool-call-repair.ts
13255
+ // packages/core/src/providers/tool-call-repair.ts
13115
13256
  function isObject(value) {
13116
13257
  return typeof value === "object" && value !== null && !Array.isArray(value);
13117
13258
  }
@@ -13221,7 +13362,7 @@ function repairToolCalls(calls) {
13221
13362
  });
13222
13363
  }
13223
13364
 
13224
- // ../core/src/providers/free-agent.ts
13365
+ // packages/core/src/providers/free-agent.ts
13225
13366
  var RETRYABLE_UPSTREAM_TYPES = new Set(["upstream_timeout", "upstream_idle_timeout", "upstream_unreachable", "upstream_stream_failed"]);
13226
13367
  function freeFailureStatus(error) {
13227
13368
  const record2 = error;
@@ -13273,6 +13414,8 @@ class FreeAccessError extends Error {
13273
13414
  this.status = status ?? undefined;
13274
13415
  }
13275
13416
  }
13417
+ var FREE_FIT_MARGIN = 1.5;
13418
+ var MIN_FREE_REPLY_TOKENS = 1024;
13276
13419
 
13277
13420
  class FreeAgentTurnProvider {
13278
13421
  options;
@@ -13360,11 +13503,13 @@ class FreeAgentTurnProvider {
13360
13503
  if (!candidates.length)
13361
13504
  throw new FreeAccessError("No eligible free tool model is available. Run /models refresh or try again later.");
13362
13505
  const messages = toWireMessages(request.messages);
13363
- const input = approximateInputTokens([JSON.stringify(messages), JSON.stringify(request.tools)]).maximumInputTokens;
13506
+ const input = Math.ceil(approximateInputTokens([JSON.stringify(messages), JSON.stringify(request.tools)]).expectedInputTokens * FREE_FIT_MARGIN);
13364
13507
  const output = Math.min(request.maxOutputTokens, this.capabilities.maxOutputTokens, ...candidates.map((model) => model.max_output ?? 4096));
13365
13508
  if (!Number.isSafeInteger(output) || output < 1)
13366
13509
  throw new FreeAccessError("Free mode requires a positive output token limit");
13367
- const fitting = candidates.filter((model) => model.context_window !== null && input + output <= model.context_window);
13510
+ const floor = Math.min(output, MIN_FREE_REPLY_TOKENS);
13511
+ const fitting = candidates.filter((model) => model.context_window !== null && input + floor <= model.context_window);
13512
+ const outputFor = (model) => Math.min(output, (model.context_window ?? input + output) - input);
13368
13513
  if (!fitting.length)
13369
13514
  throw new FreeAccessError("The conversation exceeds the available free model context. Start a new session or select a larger free model.");
13370
13515
  const preferred = this.options.model === FREE_ROUTER ? fitting.filter((model) => !this.refused.has(model.id)).sort((a, b) => rank(a.id) - rank(b.id) || (b.context_window ?? 0) - (a.context_window ?? 0) || a.id.localeCompare(b.id)) : fitting;
@@ -13393,7 +13538,7 @@ class FreeAgentTurnProvider {
13393
13538
  signal: userSignal
13394
13539
  });
13395
13540
  try {
13396
- const turn = await this.attempt(candidate.id, messages, output, request, onTextDelta, onOutputProgress, deadline);
13541
+ const turn = await this.attempt(candidate.id, messages, outputFor(candidate), request, onTextDelta, onOutputProgress, deadline);
13397
13542
  this.health?.record(candidate.id, { ok: true });
13398
13543
  this.pacer.reportSuccess();
13399
13544
  return turn;
@@ -13496,7 +13641,7 @@ class FreeAgentTurnProvider {
13496
13641
  }
13497
13642
  }
13498
13643
 
13499
- // ../core/src/providers/openrouter-agent.ts
13644
+ // packages/core/src/providers/openrouter-agent.ts
13500
13645
  var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
13501
13646
 
13502
13647
  class OpenRouterAgentTurnProvider {
@@ -13545,7 +13690,7 @@ function withHint(error) {
13545
13690
  return wrapped;
13546
13691
  }
13547
13692
 
13548
- // ../core/src/providers/agent-matrix.ts
13693
+ // packages/core/src/providers/agent-matrix.ts
13549
13694
  var OPENAI_COMPATIBLE_BASE_URL = {
13550
13695
  google: "https://generativelanguage.googleapis.com/v1beta/openai/",
13551
13696
  xai: "https://api.x.ai/v1",
@@ -13565,7 +13710,8 @@ function openAiCompatibleSpec(id) {
13565
13710
  create: (environment, model) => new OpenAIAgentTurnProvider({
13566
13711
  apiKey: environment[`${prefix}_API_KEY`]?.trim() || "local",
13567
13712
  model,
13568
- baseURL: environment[`${prefix}_BASE_URL`]?.trim() || fallbackBase
13713
+ baseURL: environment[`${prefix}_BASE_URL`]?.trim() || fallbackBase,
13714
+ dialect: VENDOR_DIALECTS[id]
13569
13715
  })
13570
13716
  };
13571
13717
  }
@@ -13710,7 +13856,7 @@ function describeProviders(environment) {
13710
13856
  }
13711
13857
  var PRICE_ENVIRONMENT_HINT = "MODEL_INPUT_PER_MILLION, MODEL_OUTPUT_PER_MILLION (and optionally MODEL_CACHED_INPUT_PER_MILLION, MODEL_PRICE_CURRENCY, MODEL_PRICE_MODEL)";
13712
13858
 
13713
- // src/app/session-provider.ts
13859
+ // packages/archymedes-cli/src/app/session-provider.ts
13714
13860
  async function resolveSessionProvider(environment, options) {
13715
13861
  if (options.provider || !options.resume)
13716
13862
  return resolveProvider(environment, options);
@@ -13719,12 +13865,12 @@ async function resolveSessionProvider(environment, options) {
13719
13865
  return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
13720
13866
  }
13721
13867
 
13722
- // src/platform/settings.ts
13868
+ // packages/archymedes-cli/src/platform/settings.ts
13723
13869
  import { promises as fs15 } from "node:fs";
13724
13870
  import os4 from "node:os";
13725
13871
  import path20 from "node:path";
13726
13872
 
13727
- // src/platform/i18n.ts
13873
+ // packages/archymedes-cli/src/platform/i18n.ts
13728
13874
  var CONTROL_LANGUAGES = {
13729
13875
  en: "English",
13730
13876
  zh: "中文 (Mandarin)",
@@ -14191,11 +14337,11 @@ function t(language, key) {
14191
14337
  return MESSAGES[key][language] ?? MESSAGES[key].en;
14192
14338
  }
14193
14339
 
14194
- // src/platform/local-currency.ts
14340
+ // packages/archymedes-cli/src/platform/local-currency.ts
14195
14341
  import { promises as fs14 } from "node:fs";
14196
14342
  import path19 from "node:path";
14197
14343
 
14198
- // src/platform/endpoints.ts
14344
+ // packages/archymedes-cli/src/platform/endpoints.ts
14199
14345
  var FX_ENDPOINTS = [
14200
14346
  "https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies",
14201
14347
  "https://latest.currency-api.pages.dev/v1/currencies"
@@ -14239,7 +14385,7 @@ function hostOf(url) {
14239
14385
  }
14240
14386
  }
14241
14387
 
14242
- // src/platform/network.ts
14388
+ // packages/archymedes-cli/src/platform/network.ts
14243
14389
  var CODES = {
14244
14390
  dns: ["ENOTFOUND", "EAI_AGAIN", "EAI_NONAME", "EAI_FAIL", "EAI_MEMORY", "EAI_SYSTEM", "DNS_E_NAME_NOT_FOUND", "DNS_E_QUERY_PENDING"],
14245
14391
  timeout: ["ETIMEDOUT", "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_HEADERS_TIMEOUT", "UND_ERR_BODY_TIMEOUT", "ERR_SOCKET_CONNECTION_TIMEOUT", "connection_timeout"],
@@ -14488,7 +14634,7 @@ function classifyNetworkError(error, options = {}) {
14488
14634
  return null;
14489
14635
  }
14490
14636
 
14491
- // src/platform/local-currency.ts
14637
+ // packages/archymedes-cli/src/platform/local-currency.ts
14492
14638
  var COUNTRY_CURRENCIES = {
14493
14639
  RW: "RWF",
14494
14640
  EG: "EGP",
@@ -14616,7 +14762,7 @@ async function startFxRateLookup(from, to, options) {
14616
14762
  return { immediate: cached?.rate ?? null, refresh };
14617
14763
  }
14618
14764
 
14619
- // src/theme/theme.ts
14765
+ // packages/archymedes-cli/src/theme/theme.ts
14620
14766
  var BLUEPRINT = `
14621
14767
  /* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
14622
14768
  @theme blueprint {
@@ -14918,7 +15064,7 @@ function roleCode(role, palette, depth) {
14918
15064
  }
14919
15065
  var NO_COLOR_PALETTE = buildPalette(findBuiltinTheme(DEFAULT_THEME_NAME) ?? { name: DEFAULT_THEME_NAME, description: "", tokens: DEFAULT_TOKENS }, "none");
14920
15066
 
14921
- // src/platform/settings.ts
15067
+ // packages/archymedes-cli/src/platform/settings.ts
14922
15068
  var LANGUAGE_NAMES = {
14923
15069
  en: "English",
14924
15070
  zh: "中文",
@@ -15302,14 +15448,14 @@ async function runSettingsMenu(current, prompts, options = {}) {
15302
15448
  for (;; ) {
15303
15449
  const language = resolveControlLanguage(settings.ARCHYMEDES_LANGUAGE);
15304
15450
  const fields = focused ? PROVIDER_KEY_FIELDS : SETTING_FIELDS;
15305
- const describe = (field2) => {
15451
+ const describe2 = (field2) => {
15306
15452
  const value = settings[field2.key];
15307
15453
  return "secret" in field2 && field2.secret ? maskSetting(value) : value || "not set";
15308
15454
  };
15309
15455
  let selection;
15310
15456
  if (prompts.choose) {
15311
15457
  const items = [
15312
- ...fields.map((field2) => ({ value: { kind: "field", key: field2.key }, label: field2.label, hint: describe(field2), ...focused ? {} : { header: sectionOf(field2.key) } })),
15458
+ ...fields.map((field2) => ({ value: { kind: "field", key: field2.key }, label: field2.label, hint: describe2(field2), ...focused ? {} : { header: sectionOf(field2.key) } })),
15313
15459
  ...focused ? [{ value: { kind: "expand" }, label: "Everything else", description: "base URLs, models, pricing, voice, keys", pinned: true }] : [],
15314
15460
  { value: { kind: "done" }, label: `${controlLabel(language, "saved")} / ${controlLabel(language, "exit")}`, pinned: true }
15315
15461
  ];
@@ -15335,7 +15481,7 @@ Archymedes ${controlLabel(language, "settings")}
15335
15481
  prompts.write(` ${section}
15336
15482
  `);
15337
15483
  lastSection = section;
15338
- prompts.write(` ${String(index + 1).padStart(2)}. ${field2.label}: ${describe(field2)}
15484
+ prompts.write(` ${String(index + 1).padStart(2)}. ${field2.label}: ${describe2(field2)}
15339
15485
  `);
15340
15486
  });
15341
15487
  if (focused)
@@ -15419,7 +15565,7 @@ Archymedes ${controlLabel(language, "settings")}
15419
15565
  }
15420
15566
  }
15421
15567
 
15422
- // src/app/free-setup.ts
15568
+ // packages/archymedes-cli/src/app/free-setup.ts
15423
15569
  var OPENROUTER_KEYS_URL2 = "https://openrouter.ai/keys";
15424
15570
  var FREE_PRIVACY_NOTICE = "Free models may log your prompts and code; don't send secrets. Use a paid provider for private code.";
15425
15571
  function needsFreePrivacyNotice(environment) {
@@ -15438,70 +15584,11 @@ async function showFreePrivacyNoticeOnce(options) {
15438
15584
  return next;
15439
15585
  }
15440
15586
 
15441
- // src/app/acp-setup.ts
15442
- var KEY_URLS = {
15443
- free: OPENROUTER_KEYS_URL2,
15444
- openrouter: OPENROUTER_KEYS_URL2,
15445
- anthropic: "https://console.anthropic.com/settings/keys",
15446
- openai: "https://platform.openai.com/api-keys",
15447
- google: "https://aistudio.google.com/apikey",
15448
- xai: "https://console.x.ai",
15449
- deepseek: "https://platform.deepseek.com/api_keys",
15450
- mistral: "https://console.mistral.ai/api-keys",
15451
- groq: "https://console.groq.com/keys"
15452
- };
15453
- var ORDER = ["free", ...PROVIDER_IDS.filter((id) => id !== "free")];
15454
- function setupStatus(environment, requested = {}) {
15455
- const resolved = resolveProvider(environment, requested);
15456
- const providers = ORDER.map((id) => {
15457
- const info = PROVIDER_INFO[id];
15458
- const keyOnly = info.requires.length === 1 && SETTING_FIELDS.some((field) => field.key === info.requires[0]);
15459
- return {
15460
- id,
15461
- label: info.label,
15462
- ...keyOnly ? { keyVariable: info.requires[0] } : {},
15463
- ...KEY_URLS[id] ? { keyUrl: KEY_URLS[id] } : {},
15464
- configured: missingRequirements(id, environment).length === 0
15465
- };
15466
- });
15467
- return "error" in resolved ? { configured: false, reason: resolved.error, providers } : { configured: true, providers };
15468
- }
15469
- async function saveSetup(params, deps) {
15470
- const provider = typeof params.provider === "string" ? params.provider : "";
15471
- const raw = typeof params.key === "string" ? params.key.trim() : "";
15472
- if (!isProviderId(provider))
15473
- return { ok: false, error: `Unknown provider "${provider}".` };
15474
- const target = setupStatus(deps.environment).providers.find((candidate) => candidate.id === provider);
15475
- if (!target?.keyVariable)
15476
- return { ok: false, error: `${PROVIDER_INFO[provider].label} needs more than a key; run archymedes settings.` };
15477
- if (!raw)
15478
- return { ok: false, error: "The key is empty." };
15479
- let key;
15480
- try {
15481
- key = validateSetting(target.keyVariable, raw);
15482
- } catch (error) {
15483
- return { ok: false, error: error instanceof Error ? error.message : String(error) };
15484
- }
15485
- let note;
15486
- if (provider === "free" || provider === "openrouter") {
15487
- const result = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(key);
15488
- if (!result.ok && result.reason === "invalid")
15489
- return { ok: false, error: describeKeyCheckFailure(result) };
15490
- if (!result.ok)
15491
- note = `${describeKeyCheckFailure(result)} Saved anyway; the first request will confirm it.`;
15492
- }
15493
- const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
15494
- const settings = { ...current, [target.keyVariable]: key, ARCHYMEDES_PROVIDER: provider };
15495
- const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(settings);
15496
- Object.assign(deps.environment, mergedEnvironment(settings, deps.processEnvironment));
15497
- return { ok: true, file, ...note ? { note } : {} };
15498
- }
15499
-
15500
- // ../core/src/providers/model-fetch.ts
15587
+ // packages/core/src/providers/model-fetch.ts
15501
15588
  import { promises as fs16 } from "node:fs";
15502
15589
  import path21 from "node:path";
15503
15590
 
15504
- // ../core/src/providers/model-list.ts
15591
+ // packages/core/src/providers/model-list.ts
15505
15592
  function modelsUrl(base) {
15506
15593
  const trimmed = base.replace(/\/+$/, "");
15507
15594
  return trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
@@ -15584,7 +15671,8 @@ var NON_CHAT = [
15584
15671
  /embed/i,
15585
15672
  /moderation/i,
15586
15673
  /whisper/i,
15587
- /^tts/i,
15674
+ /tts/i,
15675
+ /orpheus/i,
15588
15676
  /audio/i,
15589
15677
  /dall-?e/i,
15590
15678
  /^stable-/i,
@@ -15611,7 +15699,7 @@ function mergeModelLists(known, live) {
15611
15699
  const added = live.filter((model) => !seen.has(model)).sort();
15612
15700
  return [...known, ...added];
15613
15701
  }
15614
- // ../core/src/providers/model-fetch.ts
15702
+ // packages/core/src/providers/model-fetch.ts
15615
15703
  async function fetchProviderModels(provider, environment, fetchImpl, timeoutMs = 4000) {
15616
15704
  if (provider === "free") {
15617
15705
  try {
@@ -15699,7 +15787,206 @@ function fetchableProviders(environment, providers) {
15699
15787
  return providers.filter((provider) => provider !== "archymedes-cloud" && missingRequirements(provider, environment).length === 0);
15700
15788
  }
15701
15789
 
15702
- // src/session/models.ts
15790
+ // packages/archymedes-cli/src/app/acp-connect.ts
15791
+ var DEFAULT_BASE_URLS = {
15792
+ anthropic: "https://api.anthropic.com",
15793
+ openai: "https://api.openai.com/v1",
15794
+ openrouter: "https://openrouter.ai/api/v1",
15795
+ google: "https://generativelanguage.googleapis.com/v1beta/openai",
15796
+ xai: "https://api.x.ai/v1",
15797
+ deepseek: "https://api.deepseek.com/v1",
15798
+ mistral: "https://api.mistral.ai/v1",
15799
+ groq: "https://api.groq.com/openai/v1",
15800
+ ollama: "http://localhost:11434/v1"
15801
+ };
15802
+ var fieldSpec = (key) => SETTING_FIELDS.find((field) => field.key === key);
15803
+ function providerFields(provider, environment) {
15804
+ const required = PROVIDER_INFO[provider].requires;
15805
+ const baseUrl = provider === "free" ? undefined : `${providerEnvPrefix(provider)}_BASE_URL`;
15806
+ const keys = [...required, ...baseUrl && !required.includes(baseUrl) && fieldSpec(baseUrl) ? [baseUrl] : []];
15807
+ return keys.flatMap((key) => {
15808
+ const spec = fieldSpec(key);
15809
+ if (!spec)
15810
+ return [];
15811
+ const secret = "secret" in spec && spec.secret === true;
15812
+ const url = "url" in spec && spec.url === true;
15813
+ const value = environment[key]?.trim() ?? "";
15814
+ const placeholder = url ? DEFAULT_BASE_URLS[provider] ?? "https://…/v1" : undefined;
15815
+ return [{
15816
+ key: spec.key,
15817
+ label: spec.label,
15818
+ kind: secret ? "secret" : url ? "url" : "text",
15819
+ required: required.includes(key),
15820
+ isSet: value !== "",
15821
+ value: secret && value ? maskSetting(value) : value,
15822
+ ...placeholder ? { placeholder } : {}
15823
+ }];
15824
+ });
15825
+ }
15826
+ var refused = (error) => /\b40[13]\b/.test(error ?? "");
15827
+ async function connectProvider(params, deps) {
15828
+ const provider = typeof params.provider === "string" ? params.provider : "";
15829
+ if (!isProviderId(provider))
15830
+ return { ok: false, error: `Unknown provider "${provider}".` };
15831
+ const label3 = PROVIDER_INFO[provider].label;
15832
+ const values = params.values && typeof params.values === "object" ? params.values : {};
15833
+ const fields = providerFields(provider, deps.environment);
15834
+ const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
15835
+ const next = { ...current };
15836
+ for (const field of fields) {
15837
+ const raw = typeof values[field.key] === "string" ? values[field.key].trim() : undefined;
15838
+ if (raw === undefined || raw === "") {
15839
+ if (field.kind === "url" && raw === "")
15840
+ delete next[field.key];
15841
+ continue;
15842
+ }
15843
+ try {
15844
+ next[field.key] = validateSetting(field.key, raw);
15845
+ } catch (error) {
15846
+ return { ok: false, field: field.key, error: error instanceof Error ? error.message : String(error) };
15847
+ }
15848
+ }
15849
+ const candidate = mergedEnvironment(next, deps.processEnvironment);
15850
+ const missing = missingRequirements(provider, candidate);
15851
+ if (missing.length > 0)
15852
+ return { ok: false, field: missing[0], error: `${label3} still needs ${missing.join(" and ")}.` };
15853
+ const keyField = fields.find((field) => field.kind === "secret")?.key;
15854
+ let note;
15855
+ if ((provider === "free" || provider === "openrouter") && candidate.OPENROUTER_API_KEY) {
15856
+ const check = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(candidate.OPENROUTER_API_KEY);
15857
+ if (!check.ok && check.reason === "invalid")
15858
+ return { ok: false, field: keyField, error: describeKeyCheckFailure(check) };
15859
+ if (!check.ok)
15860
+ note = `${describeKeyCheckFailure(check)} Saved anyway; the first request will confirm it.`;
15861
+ }
15862
+ const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
15863
+ const listed = await fetchProviderModels(provider, candidate, fetchImpl, 8000);
15864
+ if (listed.models.length === 0 && refused(listed.error)) {
15865
+ return { ok: false, field: keyField, error: `${label3} refused the key (${listed.error}). Check it and paste it again.` };
15866
+ }
15867
+ if (listed.models.length === 0) {
15868
+ note = note ?? `Could not list ${label3}'s models (${listed.error ?? "none returned"}). Saved; check the base URL if this persists.`;
15869
+ }
15870
+ const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(next);
15871
+ Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
15872
+ if (listed.models.length > 0)
15873
+ await rememberModels(provider, listed.models, deps.environment);
15874
+ return { ok: true, file, models: listed.models, ...note ? { note } : {} };
15875
+ }
15876
+ async function providerModels(params, deps) {
15877
+ const provider = typeof params.provider === "string" ? params.provider : "";
15878
+ if (!isProviderId(provider))
15879
+ return { models: [], error: `Unknown provider "${provider}".` };
15880
+ const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
15881
+ const listed = await fetchProviderModels(provider, deps.environment, fetchImpl, 8000);
15882
+ if (listed.models.length > 0)
15883
+ await rememberModels(provider, listed.models, deps.environment);
15884
+ return { models: listed.models, ...listed.error ? { error: listed.error } : {} };
15885
+ }
15886
+ async function rememberModels(provider, models, environment) {
15887
+ try {
15888
+ const cache = await readModelCache(environment);
15889
+ await writeModelCache(environment, {
15890
+ fetchedAt: cache?.fetchedAt ?? Date.now(),
15891
+ ...cache?.freeCatalog ? { freeCatalog: cache.freeCatalog } : {},
15892
+ models: { ...cache?.models ?? {}, [provider]: models }
15893
+ });
15894
+ } catch {}
15895
+ }
15896
+ async function rememberModel(params, deps) {
15897
+ const provider = typeof params.provider === "string" ? params.provider : "";
15898
+ const model = typeof params.model === "string" ? params.model.trim() : "";
15899
+ if (!isProviderId(provider) || !model)
15900
+ return { ok: false, error: "A provider and a model are needed." };
15901
+ const key = `${providerEnvPrefix(provider)}_MODEL`;
15902
+ if (!fieldSpec(key))
15903
+ return { ok: true };
15904
+ let value;
15905
+ try {
15906
+ value = validateSetting(key, model);
15907
+ } catch (error) {
15908
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
15909
+ }
15910
+ const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
15911
+ const next = { ...current, [key]: value };
15912
+ await (deps.save ?? ((settings) => saveSettings(settings, deps.processEnvironment)))(next);
15913
+ Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
15914
+ return { ok: true };
15915
+ }
15916
+
15917
+ // packages/archymedes-cli/src/app/acp-setup.ts
15918
+ var KEY_URLS = {
15919
+ free: OPENROUTER_KEYS_URL2,
15920
+ openrouter: OPENROUTER_KEYS_URL2,
15921
+ anthropic: "https://console.anthropic.com/settings/keys",
15922
+ openai: "https://platform.openai.com/api-keys",
15923
+ google: "https://aistudio.google.com/apikey",
15924
+ xai: "https://console.x.ai",
15925
+ deepseek: "https://platform.deepseek.com/api_keys",
15926
+ mistral: "https://console.mistral.ai/api-keys",
15927
+ groq: "https://console.groq.com/keys"
15928
+ };
15929
+ var ORDER = ["free", ...PROVIDER_IDS.filter((id) => id !== "free")];
15930
+ function setupStatus(environment, requested = {}) {
15931
+ const resolved = resolveProvider(environment, requested);
15932
+ const providers = ORDER.map((id) => {
15933
+ const info = PROVIDER_INFO[id];
15934
+ const keyOnly = info.requires.length === 1 && SETTING_FIELDS.some((field) => field.key === info.requires[0]);
15935
+ return {
15936
+ id,
15937
+ label: info.label,
15938
+ ...keyOnly ? { keyVariable: info.requires[0] } : {},
15939
+ ...KEY_URLS[id] ? { keyUrl: KEY_URLS[id] } : {},
15940
+ configured: missingRequirements(id, environment).length === 0
15941
+ };
15942
+ });
15943
+ return "error" in resolved ? { configured: false, reason: resolved.error, providers } : { configured: true, providers };
15944
+ }
15945
+ async function saveSetup(params, deps) {
15946
+ const provider = typeof params.provider === "string" ? params.provider : "";
15947
+ const raw = typeof params.key === "string" ? params.key.trim() : "";
15948
+ if (!isProviderId(provider))
15949
+ return { ok: false, error: `Unknown provider "${provider}".` };
15950
+ const target = setupStatus(deps.environment).providers.find((candidate) => candidate.id === provider);
15951
+ if (!target?.keyVariable)
15952
+ return { ok: false, error: `${PROVIDER_INFO[provider].label} needs more than a key; run archymedes settings.` };
15953
+ if (!raw)
15954
+ return { ok: false, error: "The key is empty." };
15955
+ let key;
15956
+ try {
15957
+ key = validateSetting(target.keyVariable, raw);
15958
+ } catch (error) {
15959
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
15960
+ }
15961
+ let note;
15962
+ if (provider === "free" || provider === "openrouter") {
15963
+ const result = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(key);
15964
+ if (!result.ok && result.reason === "invalid")
15965
+ return { ok: false, error: describeKeyCheckFailure(result) };
15966
+ if (!result.ok)
15967
+ note = `${describeKeyCheckFailure(result)} Saved anyway; the first request will confirm it.`;
15968
+ }
15969
+ const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
15970
+ const settings = { ...current, [target.keyVariable]: key, ARCHYMEDES_PROVIDER: provider };
15971
+ const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(settings);
15972
+ Object.assign(deps.environment, mergedEnvironment(settings, deps.processEnvironment));
15973
+ return { ok: true, file, ...note ? { note } : {} };
15974
+ }
15975
+ function providerOverview(environment) {
15976
+ const preferred = environment.ARCHYMEDES_PROVIDER?.trim().toLowerCase();
15977
+ return setupStatus(environment).providers.map((provider) => {
15978
+ const info = PROVIDER_INFO[provider.id];
15979
+ return {
15980
+ ...provider,
15981
+ missing: missingRequirements(provider.id, environment),
15982
+ model: environment[`${providerEnvPrefix(provider.id)}_MODEL`]?.trim() || info.defaultModel,
15983
+ isDefault: preferred === provider.id,
15984
+ fields: providerFields(provider.id, environment)
15985
+ };
15986
+ });
15987
+ }
15988
+
15989
+ // packages/archymedes-cli/src/session/models.ts
15703
15990
  function modelsForProvider(provider, asOf) {
15704
15991
  const seen = new Set;
15705
15992
  for (const record2 of PRICE_CATALOG) {
@@ -15723,7 +16010,7 @@ function describePrice(prices, display, convert2) {
15723
16010
  return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
15724
16011
  }
15725
16012
 
15726
- // src/app/acp-models.ts
16013
+ // packages/archymedes-cli/src/app/acp-models.ts
15727
16014
  var PUBLIC_LISTINGS = ["free", "openrouter"];
15728
16015
  async function modelList(environment, params, options = {}) {
15729
16016
  const offline = /^(1|true|on|yes)$/i.test(environment.ARCHYMEDES_MODELS_OFFLINE?.trim() ?? "");
@@ -15775,7 +16062,7 @@ async function modelList(environment, params, options = {}) {
15775
16062
  return { choices: [...ready, ...locked], unconfigured, errors, providers: PROVIDER_IDS.length };
15776
16063
  }
15777
16064
 
15778
- // src/app/acp-commands.ts
16065
+ // packages/archymedes-cli/src/app/acp-commands.ts
15779
16066
  async function runSessionCommand(command, argument, session) {
15780
16067
  switch (command) {
15781
16068
  case "cost":
@@ -15853,7 +16140,7 @@ async function memoryCommand(argument, root) {
15853
16140
  }
15854
16141
  }
15855
16142
 
15856
- // src/app/acp-settings.ts
16143
+ // packages/archymedes-cli/src/app/acp-settings.ts
15857
16144
  async function listSettings(processEnvironment) {
15858
16145
  const stored = await loadSettings(processEnvironment);
15859
16146
  const rows = SETTING_FIELDS.map((field) => {
@@ -15905,10 +16192,10 @@ async function setSetting(params, deps) {
15905
16192
  return { ok: true, file, value: secret && stored ? maskSetting(stored) : stored, isSet: stored !== "" };
15906
16193
  }
15907
16194
 
15908
- // src/app/startup-update.ts
16195
+ // packages/archymedes-cli/src/app/startup-update.ts
15909
16196
  import { spawn as spawn8 } from "node:child_process";
15910
16197
 
15911
- // src/platform/auto-update.ts
16198
+ // packages/archymedes-cli/src/platform/auto-update.ts
15912
16199
  import { promises as fs17 } from "node:fs";
15913
16200
  import path22 from "node:path";
15914
16201
  var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1000;
@@ -16021,7 +16308,7 @@ async function runAutoUpdate(options) {
16021
16308
  return { notice: [], decision };
16022
16309
  }
16023
16310
 
16024
- // src/platform/defender-feed-update.ts
16311
+ // packages/archymedes-cli/src/platform/defender-feed-update.ts
16025
16312
  var OFFICIAL_DEFENDER_FEED_URL = "https://circuit-archymedes.vercel.app/api/defender-brain/manifest";
16026
16313
  var OFFICIAL_DEFENDER_FEED_KEYS = Object.freeze({
16027
16314
  "release-2026-01": "MCowBQYDK2VwAyEA4/jb1zd6f+jIPAFja1bPNtroXV8MtAZFrKt5BSY+ngI="
@@ -16049,12 +16336,12 @@ async function updateDefenderFeed(environment) {
16049
16336
  });
16050
16337
  }
16051
16338
 
16052
- // src/platform/update.ts
16339
+ // packages/archymedes-cli/src/platform/update.ts
16053
16340
  import { spawnSync as spawnSync3 } from "node:child_process";
16054
16341
  import { tmpdir } from "node:os";
16055
16342
  import { createInterface as createInterface3 } from "node:readline/promises";
16056
16343
 
16057
- // src/catalog/commands.ts
16344
+ // packages/archymedes-cli/src/catalog/commands.ts
16058
16345
  function defineCommands(table) {
16059
16346
  return Object.entries(table).map(([name, command]) => ({ name, ...command }));
16060
16347
  }
@@ -16127,7 +16414,7 @@ function renderCommandHelp(language = "en", shortcuts = new Map, options = {}) {
16127
16414
  `);
16128
16415
  }
16129
16416
 
16130
- // src/terminal/keybindings.ts
16417
+ // packages/archymedes-cli/src/terminal/keybindings.ts
16131
16418
  var FUNCTION_KEY = /^f([1-9]|1[0-2])$/;
16132
16419
  var NAMED_KEYS = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
16133
16420
  function isKeyName(value) {
@@ -16377,10 +16664,10 @@ function escapeCodeTimeoutMs(environment = process.env) {
16377
16664
  const parsed = raw ? Number(raw) : NaN;
16378
16665
  return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS;
16379
16666
  }
16380
- // package.json
16667
+ // packages/archymedes-cli/package.json
16381
16668
  var package_default = {
16382
16669
  name: "archymedes-cli",
16383
- version: "3.3.0",
16670
+ version: "3.5.1",
16384
16671
  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.",
16385
16672
  keywords: [
16386
16673
  "cli",
@@ -16426,12 +16713,12 @@ var package_default = {
16426
16713
  prepublishOnly: "bun run ../../tooling/build/build-packages.ts"
16427
16714
  },
16428
16715
  optionalDependencies: {
16429
- "@archymedes/cli-darwin-arm64": "3.3.0",
16430
- "@archymedes/cli-darwin-x64": "3.3.0",
16431
- "@archymedes/cli-linux-arm64": "3.3.0",
16432
- "@archymedes/cli-linux-x64": "3.3.0",
16433
- "@archymedes/cli-win32-arm64": "3.3.0",
16434
- "@archymedes/cli-win32-x64": "3.3.0",
16716
+ "@archymedes/cli-darwin-arm64": "3.5.1",
16717
+ "@archymedes/cli-darwin-x64": "3.5.1",
16718
+ "@archymedes/cli-linux-arm64": "3.5.1",
16719
+ "@archymedes/cli-linux-x64": "3.5.1",
16720
+ "@archymedes/cli-win32-arm64": "3.5.1",
16721
+ "@archymedes/cli-win32-x64": "3.5.1",
16435
16722
  "@archymedes/state-darwin-arm64": "0.4.0",
16436
16723
  "@archymedes/state-darwin-x64": "0.4.0",
16437
16724
  "@archymedes/state-linux-arm64-gnu": "0.4.0",
@@ -16443,7 +16730,7 @@ var package_default = {
16443
16730
  }
16444
16731
  };
16445
16732
 
16446
- // src/platform/update.ts
16733
+ // packages/archymedes-cli/src/platform/update.ts
16447
16734
  var ARCHYMEDES_CLI_PACKAGE = "archymedes-cli";
16448
16735
  var ARCHYMEDES_CLI_VERSION = package_default.version;
16449
16736
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
@@ -16661,7 +16948,7 @@ async function runSelfUpdate(options = {}) {
16661
16948
  return { status: "updated", currentVersion, latestVersion, code: 0 };
16662
16949
  }
16663
16950
 
16664
- // src/text/ansi.ts
16951
+ // packages/archymedes-cli/src/text/ansi.ts
16665
16952
  var RESET = "\x1B[0m";
16666
16953
  var BOLD = "\x1B[1m";
16667
16954
  var DIM = "\x1B[2m";
@@ -16674,7 +16961,7 @@ function paintAll(text, codes, depth) {
16674
16961
  return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
16675
16962
  }
16676
16963
 
16677
- // src/terminal/output.ts
16964
+ // packages/archymedes-cli/src/terminal/output.ts
16678
16965
  var terminalStream = {
16679
16966
  write(text) {
16680
16967
  process.stdout.write(text);
@@ -16708,7 +16995,7 @@ class OutputRouter {
16708
16995
  }
16709
16996
  }
16710
16997
 
16711
- // src/text/glyphs.ts
16998
+ // packages/archymedes-cli/src/text/glyphs.ts
16712
16999
  var UNICODE_GLYPHS = {
16713
17000
  starGlyphs: [".", "·", "✧", "✦", "✶"],
16714
17001
  spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
@@ -16815,7 +17102,7 @@ function borderGlyphsFor(style, glyphs) {
16815
17102
  return ROUND_BORDER;
16816
17103
  }
16817
17104
 
16818
- // src/text/text-width.ts
17105
+ // packages/archymedes-cli/src/text/text-width.ts
16819
17106
  var ANSI = /\x1b\[[0-9;]*m/g;
16820
17107
  var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
16821
17108
  function visibleWidth(text) {
@@ -16850,7 +17137,7 @@ function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
16850
17137
  return `${out}${mark}`;
16851
17138
  }
16852
17139
 
16853
- // src/render/syntax.ts
17140
+ // packages/archymedes-cli/src/render/syntax.ts
16854
17141
  function newSyntaxState() {
16855
17142
  return {};
16856
17143
  }
@@ -17497,7 +17784,7 @@ function highlightSyntax(line, options) {
17497
17784
  return `${out}${RESET}`;
17498
17785
  }
17499
17786
 
17500
- // src/render/markdown.ts
17787
+ // packages/archymedes-cli/src/render/markdown.ts
17501
17788
  var colour = (role, palette) => palette?.[role] || ANSI_PALETTE[role];
17502
17789
  var INLINE_PATTERN = /(?<!\\)(`[^`\n]+`)|(?<!\\)(\*\*[^*\n]+\*\*)|(?<!\\)(__[^_\n]+__)|(?<!\\)(~~[^~\n]+~~)|(?<!\\)(\*[^*\n]+\*)|(?<!\\)(_[^_\n]+_)|(!?\[([^\]\n]+)\]\((https?:\/\/[^\s)\n]+)\))|(<(https?:\/\/[^>\s]+)>)/g;
17503
17790
  var unescapeMarkdown = (text) => text.replace(/\\([\\`*_[\]{}()#+.!~>-])/g, "$1");
@@ -17718,7 +18005,7 @@ function renderMarkdown(text, options) {
17718
18005
  `);
17719
18006
  }
17720
18007
 
17721
- // src/render/tui.ts
18008
+ // packages/archymedes-cli/src/render/tui.ts
17722
18009
  function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
17723
18010
  const frames = glyphs.spinnerFrames;
17724
18011
  const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
@@ -18306,7 +18593,7 @@ function wrapPlain(text, width) {
18306
18593
  return lines.length === 0 ? [""] : lines;
18307
18594
  }
18308
18595
 
18309
- // src/render/transcript.ts
18596
+ // packages/archymedes-cli/src/render/transcript.ts
18310
18597
  function truncateMiddle(value, maximum) {
18311
18598
  const clean = value.replace(/\s+/g, " ").trim();
18312
18599
  if (clean.length <= maximum)
@@ -18469,7 +18756,7 @@ function summarizeToolResult(toolName, content, isError) {
18469
18756
  }
18470
18757
  }
18471
18758
 
18472
- // src/render/sections.ts
18759
+ // packages/archymedes-cli/src/render/sections.ts
18473
18760
  var TONE_ROLE = {
18474
18761
  good: "success",
18475
18762
  bad: "error",
@@ -18596,7 +18883,7 @@ function outcomeMark(outcome, style) {
18596
18883
  }
18597
18884
  }
18598
18885
 
18599
- // src/render/code-view.ts
18886
+ // packages/archymedes-cli/src/render/code-view.ts
18600
18887
  var MAX_DIFF_CELLS = 250000;
18601
18888
  function diffLines(before, after) {
18602
18889
  const left = before === "" ? [] : before.split(`
@@ -18893,7 +19180,7 @@ function renderFileChange(change, style, options = {}) {
18893
19180
  };
18894
19181
  }
18895
19182
 
18896
- // src/render/test-report.ts
19183
+ // packages/archymedes-cli/src/render/test-report.ts
18897
19184
  function toMs(value) {
18898
19185
  if (!value)
18899
19186
  return;
@@ -19168,7 +19455,7 @@ function renderTestReport(report, style, options = {}) {
19168
19455
  `);
19169
19456
  }
19170
19457
 
19171
- // src/render/expandable.ts
19458
+ // packages/archymedes-cli/src/render/expandable.ts
19172
19459
  var MAX_ENTRIES = 64;
19173
19460
 
19174
19461
  class ExpandableStore {
@@ -19202,7 +19489,7 @@ function expandHint(id, hidden, depth, glyphs = UNICODE_GLYPHS) {
19202
19489
  return paint(`${glyphs.collapsed} ${hidden} more line${hidden === 1 ? "" : "s"} hidden ${glyphs.middot} /expand ${id}`, DIM, depth);
19203
19490
  }
19204
19491
 
19205
- // src/app/transcript.ts
19492
+ // packages/archymedes-cli/src/app/transcript.ts
19206
19493
  var colorEnabled = false;
19207
19494
  var wrap = (code) => (value) => colorEnabled ? `${code}${value}${RESET}` : value;
19208
19495
  var palette = NO_COLOR_PALETTE;
@@ -19282,7 +19569,7 @@ function beginTranscriptTurn() {
19282
19569
  markdown.reset();
19283
19570
  }
19284
19571
 
19285
- // src/app/startup-update.ts
19572
+ // packages/archymedes-cli/src/app/startup-update.ts
19286
19573
  async function startupMaintenance(environment, interactive, install) {
19287
19574
  updateDefenderFeed(environment).catch(() => {
19288
19575
  return;
@@ -19321,7 +19608,7 @@ function installInChildProcess(entry, environment) {
19321
19608
  });
19322
19609
  }
19323
19610
 
19324
- // src/app/jev.ts
19611
+ // packages/archymedes-cli/src/app/jev.ts
19325
19612
  function jevOptionsFromEnvironment(environment) {
19326
19613
  if ((environment.ARCHYMEDES_JEV ?? "").trim().toLowerCase() === "off")
19327
19614
  return;
@@ -19332,7 +19619,7 @@ function jevOptionsFromEnvironment(environment) {
19332
19619
  return { apiKey, ...model ? { model } : {}, ...environment.ARCHYMEDES_JEV_REVIEW?.trim().toLowerCase() === "off" ? { review: false } : {} };
19333
19620
  }
19334
19621
 
19335
- // ../core/src/providers/exa.ts
19622
+ // packages/core/src/providers/exa.ts
19336
19623
  var LATENCY_CEILING = {
19337
19624
  instant: 5000,
19338
19625
  fast: 1e4,
@@ -19538,7 +19825,7 @@ function createExaClient(environment, fetchImpl) {
19538
19825
  });
19539
19826
  }
19540
19827
 
19541
- // src/acp-server.ts
19828
+ // packages/archymedes-cli/src/acp-server.ts
19542
19829
  function splitFrames(buffer) {
19543
19830
  const parts = buffer.split(`
19544
19831
  `);
@@ -19554,6 +19841,10 @@ async function runAcpServer(options) {
19554
19841
  const connection = new AcpConnection({
19555
19842
  send,
19556
19843
  extensions: {
19844
+ "_archymedes/providers": async () => ({ providers: providerOverview(options.environment) }),
19845
+ "_archymedes/providers/connect": async (params) => connectProvider(params, { environment: options.environment, processEnvironment: process.env }),
19846
+ "_archymedes/providers/models": async (params) => providerModels(params, { environment: options.environment }),
19847
+ "_archymedes/providers/remember-model": async (params) => rememberModel(params, { environment: options.environment, processEnvironment: process.env }),
19557
19848
  "_archymedes/setup/status": async () => setupStatus(options.environment, { provider: options.provider, model: options.model }),
19558
19849
  "_archymedes/setup/save": async (params) => saveSetup(params, { environment: options.environment, processEnvironment: process.env }),
19559
19850
  "_archymedes/settings/list": async () => listSettings(process.env),
@@ -19705,10 +19996,10 @@ function priceCatalogFor(prices) {
19705
19996
  };
19706
19997
  }
19707
19998
 
19708
- // src/app/args.ts
19999
+ // packages/archymedes-cli/src/app/args.ts
19709
20000
  import path23 from "node:path";
19710
20001
 
19711
- // src/render/charts.ts
20002
+ // packages/archymedes-cli/src/render/charts.ts
19712
20003
  function barChart(data, options) {
19713
20004
  if (data.length === 0)
19714
20005
  return [];
@@ -19733,7 +20024,7 @@ function barChart(data, options) {
19733
20024
  });
19734
20025
  }
19735
20026
 
19736
- // src/commands/chat-history.ts
20027
+ // packages/archymedes-cli/src/commands/chat-history.ts
19737
20028
  function countTurns(messages) {
19738
20029
  return messages.filter((message) => message.role === "user" && !message.internal).length;
19739
20030
  }
@@ -19926,7 +20217,7 @@ function parseHistoryCommand(input) {
19926
20217
  return { kind: "invalid", reason: `/history takes "list", a session id, "search <text>", "delete <id>", "status", or "resume" — not "${verb}".` };
19927
20218
  }
19928
20219
 
19929
- // src/commands/pacing.ts
20220
+ // packages/archymedes-cli/src/commands/pacing.ts
19930
20221
  var PACE_PROFILES = {
19931
20222
  off: {
19932
20223
  level: "off",
@@ -19988,7 +20279,7 @@ function paceBadge(level, glyphs2 = UNICODE_GLYPHS) {
19988
20279
  return `${glyphs2.paused} ${profileFor(level).label}`;
19989
20280
  }
19990
20281
 
19991
- // src/app/args.ts
20282
+ // packages/archymedes-cli/src/app/args.ts
19992
20283
  var SESSION_ID2 = /^\d{8}T\d{6}Z-[a-z0-9]{6}$/;
19993
20284
  var DEFAULT_DOCKER_IMAGE = "debian:stable-slim";
19994
20285
  function parseArgs(argv) {
@@ -20186,7 +20477,7 @@ function parseArgs(argv) {
20186
20477
  return parsed;
20187
20478
  }
20188
20479
 
20189
- // src/app/session-provider.ts
20480
+ // packages/archymedes-cli/src/app/session-provider.ts
20190
20481
  async function resolveSessionProvider2(environment, options) {
20191
20482
  if (options.provider || !options.resume)
20192
20483
  return resolveProvider(environment, options);
@@ -20195,7 +20486,7 @@ async function resolveSessionProvider2(environment, options) {
20195
20486
  return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
20196
20487
  }
20197
20488
 
20198
- // src/app/transcript.ts
20489
+ // packages/archymedes-cli/src/app/transcript.ts
20199
20490
  var colorEnabled2 = false;
20200
20491
  var liveTerminal2 = false;
20201
20492
  var wrap2 = (code) => (value) => colorEnabled2 ? `${code}${value}${RESET}` : value;
@@ -20509,7 +20800,7 @@ ${rule(sectionStyle2(), { label: "tool activity", tone: "neutral" })}
20509
20800
  }
20510
20801
  }
20511
20802
 
20512
- // ../core/src/cli/suggestions.ts
20803
+ // packages/core/src/cli/suggestions.ts
20513
20804
  var CATEGORY_ORDER = ["blocked", "recovery", "next", "discover", "starter"];
20514
20805
  function defaultSignals(overrides = {}) {
20515
20806
  return {
@@ -20906,7 +21197,7 @@ async function askModelForSuggestions(model, signals, context = {}) {
20906
21197
  }
20907
21198
  }
20908
21199
 
20909
- // src/ui/chooser.ts
21200
+ // packages/archymedes-cli/src/ui/chooser.ts
20910
21201
  var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
20911
21202
  function chromeOf(chrome) {
20912
21203
  return { ...ALL_CHROME, ...chrome };
@@ -21134,7 +21425,7 @@ async function runChooser(keys, items, paint2, options) {
21134
21425
  return;
21135
21426
  }
21136
21427
 
21137
- // src/ui/navigation.ts
21428
+ // packages/archymedes-cli/src/ui/navigation.ts
21138
21429
  class CommandUsage {
21139
21430
  limit;
21140
21431
  order = [];
@@ -21157,7 +21448,7 @@ class CommandUsage {
21157
21448
  }
21158
21449
  }
21159
21450
 
21160
- // ../core/src/cli/daemon.ts
21451
+ // packages/core/src/cli/daemon.ts
21161
21452
  import { randomUUID as randomUUID6 } from "node:crypto";
21162
21453
  var ARCHYMEDES_DAEMON_PROTOCOL_VERSION = 1;
21163
21454
  var PREVIEW_HUNK_SEPARATOR = `
@@ -21555,7 +21846,7 @@ class ArchymedesDaemonClient {
21555
21846
  }
21556
21847
  }
21557
21848
 
21558
- // ../core/src/money.ts
21849
+ // packages/core/src/money.ts
21559
21850
  var CURRENCIES2 = (() => {
21560
21851
  try {
21561
21852
  return Intl.supportedValuesOf("currency");
@@ -21598,7 +21889,7 @@ function formatMoney2(value) {
21598
21889
  return value.currency === "USD" ? `${format.symbol}${rendered}` : `${format.symbol} ${rendered}`;
21599
21890
  }
21600
21891
 
21601
- // ../core/src/cli/backends.ts
21892
+ // packages/core/src/cli/backends.ts
21602
21893
  import path24 from "node:path";
21603
21894
  var CONFIG_FILE_SCAN_LIMIT2 = 500;
21604
21895
  function localCommandGuidance2(platform) {
@@ -21692,7 +21983,7 @@ class LocalWorkspace2 {
21692
21983
  }
21693
21984
  }
21694
21985
 
21695
- // ../core/src/cli/cost.ts
21986
+ // packages/core/src/cli/cost.ts
21696
21987
  function formatTokenFlow2(usage) {
21697
21988
  return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
21698
21989
  }
@@ -21944,7 +22235,7 @@ class CostLedger2 {
21944
22235
  }
21945
22236
  }
21946
22237
 
21947
- // src/headless.ts
22238
+ // packages/archymedes-cli/src/headless.ts
21948
22239
  var HEADLESS_PROTOCOL_VERSION = 1;
21949
22240
  var EXIT_CODES = {
21950
22241
  completed: 0,
@@ -22060,6 +22351,14 @@ class HeadlessEmitter {
22060
22351
  });
22061
22352
  return;
22062
22353
  }
22354
+ if (safe.type === "context_shrunk") {
22355
+ this.emit("context_shrunk", { iteration: safe.iteration, step: safe.step });
22356
+ return;
22357
+ }
22358
+ if (safe.type === "tool_name") {
22359
+ this.emit("tool_name", { iteration: safe.iteration, requested: safe.requested, ...safe.resolved ? { resolved: safe.resolved } : {} });
22360
+ return;
22361
+ }
22063
22362
  this.emit("runtime_stop", { status: safe.status, summary: safe.summary });
22064
22363
  }
22065
22364
  turnEnd(result) {
@@ -22070,7 +22369,7 @@ class HeadlessEmitter {
22070
22369
  }
22071
22370
  }
22072
22371
 
22073
- // ../core/src/providers/price-catalog.ts
22372
+ // packages/core/src/providers/price-catalog.ts
22074
22373
  var ANTHROPIC_VERIFIED2 = "2026-06-24";
22075
22374
  var ANTHROPIC_SOURCE2 = "anthropic.com/pricing, recorded 2026-06-24";
22076
22375
  var ANTHROPIC2 = [
@@ -22122,7 +22421,7 @@ var SERVICES2 = [
22122
22421
  ];
22123
22422
  var PRICE_CATALOG2 = definePrices([...ANTHROPIC2, ...OAI_COMPAT_LABS2, ...SERVICES2]);
22124
22423
 
22125
- // src/text/color-depth.ts
22424
+ // packages/archymedes-cli/src/text/color-depth.ts
22126
22425
  function detectColorDepth(environment, isTTY) {
22127
22426
  if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
22128
22427
  return "none";
@@ -22131,7 +22430,7 @@ function detectColorDepth(environment, isTTY) {
22131
22430
  return "ansi256";
22132
22431
  }
22133
22432
 
22134
- // src/terminal/keybindings.ts
22433
+ // packages/archymedes-cli/src/terminal/keybindings.ts
22135
22434
  var FUNCTION_KEY2 = /^f([1-9]|1[0-2])$/;
22136
22435
  var NAMED_KEYS2 = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
22137
22436
  function isKeyName2(value) {
@@ -22373,7 +22672,7 @@ function escapeCodeTimeoutMs2(environment = process.env) {
22373
22672
  return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS2;
22374
22673
  }
22375
22674
 
22376
- // src/platform/local-currency.ts
22675
+ // packages/archymedes-cli/src/platform/local-currency.ts
22377
22676
  var COUNTRY_CURRENCIES2 = {
22378
22677
  RW: "RWF",
22379
22678
  EG: "EGP",
@@ -22499,7 +22798,7 @@ function resolveCurrencyPreference(options) {
22499
22798
  }
22500
22799
  var FX_CACHE_MAX_AGE_MS2 = 24 * 60 * 60 * 1000;
22501
22800
 
22502
- // src/platform/settings.ts
22801
+ // packages/archymedes-cli/src/platform/settings.ts
22503
22802
  import { promises as fs18 } from "node:fs";
22504
22803
  import os5 from "node:os";
22505
22804
  import path25 from "node:path";
@@ -22752,7 +23051,7 @@ function mergedEnvironment2(settings, environment = process.env) {
22752
23051
  var PROVIDER_REQUIRED_NAMES2 = new Set(PROVIDER_IDS.flatMap((id) => PROVIDER_INFO[id].requires));
22753
23052
  var PROVIDER_KEY_FIELDS2 = SETTING_FIELDS2.filter((field) => PROVIDER_REQUIRED_NAMES2.has(field.key));
22754
23053
 
22755
- // src/app/free-setup.ts
23054
+ // packages/archymedes-cli/src/app/free-setup.ts
22756
23055
  var OPENROUTER_KEYS_URL3 = "https://openrouter.ai/keys";
22757
23056
  var FREE_SETUP_INTRO = [
22758
23057
  "Free mode runs zero-priced models through OpenRouter and never falls back to a paid one.",
@@ -22818,7 +23117,7 @@ ${style3.bold("Free mode setup")}
22818
23117
  return;
22819
23118
  }
22820
23119
 
22821
- // src/session/tabs.ts
23120
+ // packages/archymedes-cli/src/session/tabs.ts
22822
23121
  class WorkspaceController {
22823
23122
  limit;
22824
23123
  tabs = [];
@@ -22895,19 +23194,19 @@ class WorkspaceController {
22895
23194
  if (tab)
22896
23195
  tab.status = "running";
22897
23196
  }
22898
- views(describe) {
23197
+ views(describe2) {
22899
23198
  return this.tabs.map((tab) => ({
22900
23199
  id: tab.id,
22901
23200
  title: tab.title,
22902
23201
  status: tab.status,
22903
23202
  unread: tab.unread,
22904
23203
  active: tab.id === this.activeId,
22905
- ...describe ? describe(tab.payload) : {}
23204
+ ...describe2 ? describe2(tab.payload) : {}
22906
23205
  }));
22907
23206
  }
22908
23207
  }
22909
23208
 
22910
- // src/terminal/output.ts
23209
+ // packages/archymedes-cli/src/terminal/output.ts
22911
23210
  var terminalStream2 = {
22912
23211
  write(text) {
22913
23212
  process.stdout.write(text);
@@ -23003,7 +23302,7 @@ class TabSink {
23003
23302
  }
23004
23303
  }
23005
23304
 
23006
- // src/terminal/job-stream.ts
23305
+ // packages/archymedes-cli/src/terminal/job-stream.ts
23007
23306
  var TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
23008
23307
  class WatchRegistry {
23009
23308
  watched = new Map;
@@ -23038,7 +23337,7 @@ class WatchRegistry {
23038
23337
  }
23039
23338
  }
23040
23339
 
23041
- // src/theme/theme.ts
23340
+ // packages/archymedes-cli/src/theme/theme.ts
23042
23341
  var BLUEPRINT2 = `
23043
23342
  /* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
23044
23343
  @theme blueprint {
@@ -23339,7 +23638,7 @@ function detectPreferredTheme(environment) {
23339
23638
  return DEFAULT_THEME_NAME2;
23340
23639
  }
23341
23640
 
23342
- // src/theme/theme-files.ts
23641
+ // packages/archymedes-cli/src/theme/theme-files.ts
23343
23642
  import { promises as fs19 } from "node:fs";
23344
23643
  import path26 from "node:path";
23345
23644
  function themeDirectory(scope, root, environment) {
@@ -23377,7 +23676,7 @@ async function findTheme(name, root, environment) {
23377
23676
  return (await discoverThemes(root, environment)).find((theme) => theme.name.toLowerCase() === wanted);
23378
23677
  }
23379
23678
 
23380
- // src/render/syntax.ts
23679
+ // packages/archymedes-cli/src/render/syntax.ts
23381
23680
  var DEFAULT_CODE_STYLE2 = { colors: "vscode", lineNumbers: true };
23382
23681
  var currentCodeStyle2 = { ...DEFAULT_CODE_STYLE2 };
23383
23682
  function codeStyleFromEnvironment(environment) {
@@ -23435,7 +23734,7 @@ var GRAMMARS2 = {
23435
23734
  };
23436
23735
  var PUNCTUATION2 = new Set([..."{}[]()<>;,.:=+-*/%!&|^~?\\"]);
23437
23736
 
23438
- // src/platform/i18n.ts
23737
+ // packages/archymedes-cli/src/platform/i18n.ts
23439
23738
  var CONTROL_LANGUAGES2 = {
23440
23739
  en: "English",
23441
23740
  zh: "中文 (Mandarin)",
@@ -23460,7 +23759,7 @@ function resolveControlLanguage2(value) {
23460
23759
  return base in CONTROL_LANGUAGES2 ? base : "en";
23461
23760
  }
23462
23761
 
23463
- // src/text/glyphs.ts
23762
+ // packages/archymedes-cli/src/text/glyphs.ts
23464
23763
  var UNICODE_GLYPHS2 = {
23465
23764
  starGlyphs: [".", "·", "✧", "✦", "✶"],
23466
23765
  spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
@@ -23576,7 +23875,7 @@ function glyphsFor(mode) {
23576
23875
  function resolveGlyphs(environment, platform = process.platform) {
23577
23876
  return glyphsFor(detectGlyphMode(environment, platform));
23578
23877
  }
23579
- // src/session/state-history.ts
23878
+ // packages/archymedes-cli/src/session/state-history.ts
23580
23879
  class CliStateHistory {
23581
23880
  root;
23582
23881
  environment;
@@ -23687,7 +23986,7 @@ class CliStateHistory {
23687
23986
  }
23688
23987
  }
23689
23988
 
23690
- // src/ui/borrowed-keyboard.ts
23989
+ // packages/archymedes-cli/src/ui/borrowed-keyboard.ts
23691
23990
  function painter(output) {
23692
23991
  let rows = 0;
23693
23992
  const erase = () => {
@@ -23768,7 +24067,7 @@ async function openChooser(host, items, options, self) {
23768
24067
  return withBorrowedKeyboard(host, self, (keys, paint2) => runChooser(keys, items, paint2, sized));
23769
24068
  }
23770
24069
 
23771
- // src/app/prompts.ts
24070
+ // packages/archymedes-cli/src/app/prompts.ts
23772
24071
  function renderApprovalPreview(preview2) {
23773
24072
  if (!preview2)
23774
24073
  return;
@@ -23906,7 +24205,7 @@ async function hiddenQuestion(readline, question, signal) {
23906
24205
  }
23907
24206
  }
23908
24207
 
23909
- // src/app/providers.ts
24208
+ // packages/archymedes-cli/src/app/providers.ts
23910
24209
  function readFxRates(environment) {
23911
24210
  const genericRate = Number(environment.ARCHYMEDES_FX_RATE);
23912
24211
  const genericFrom = environment.ARCHYMEDES_FX_FROM?.trim().toUpperCase();
@@ -23923,11 +24222,11 @@ function readFxRates(environment) {
23923
24222
  }
23924
24223
  return configured;
23925
24224
  }
23926
- // ../core/src/cli/job-store.ts
24225
+ // packages/core/src/cli/job-store.ts
23927
24226
  import { promises as fs20 } from "node:fs";
23928
24227
  import path27 from "node:path";
23929
24228
 
23930
- // ../core/src/cli/jobs.ts
24229
+ // packages/core/src/cli/jobs.ts
23931
24230
  var JOB_STATUSES = ["queued", "running", "paused", "completed", "failed", "cancelled"];
23932
24231
  var DECISIONS = ["allow", "allow_always", "allow_pattern", "deny", "deny_always"];
23933
24232
  function parseJobRecord(value, index) {
@@ -24102,7 +24401,7 @@ function recoverStale(store, now) {
24102
24401
  return { store: { jobs }, recovered };
24103
24402
  }
24104
24403
 
24105
- // ../core/src/cli/job-store.ts
24404
+ // packages/core/src/cli/job-store.ts
24106
24405
  function jobStoreFile(root) {
24107
24406
  return path27.join(root, ".archymedes", "jobs.json");
24108
24407
  }
@@ -24222,10 +24521,10 @@ async function appendJobLog(root, id, line) {
24222
24521
  await fs20.appendFile(file, `${line}
24223
24522
  `, "utf8");
24224
24523
  }
24225
- // src/job-worker.ts
24524
+ // packages/archymedes-cli/src/job-worker.ts
24226
24525
  import os6 from "node:os";
24227
24526
 
24228
- // src/commands/wander.ts
24527
+ // packages/archymedes-cli/src/commands/wander.ts
24229
24528
  async function gatherWanderEvidence(topic, search, numResults = 8) {
24230
24529
  if (!search) {
24231
24530
  return {
@@ -24321,7 +24620,7 @@ function renderWanderChart(results, style3, width) {
24321
24620
  `);
24322
24621
  }
24323
24622
 
24324
- // src/job-worker.ts
24623
+ // packages/archymedes-cli/src/job-worker.ts
24325
24624
  function workerId(hostname = os6.hostname(), pid = process.pid) {
24326
24625
  return `${hostname}:${pid}`;
24327
24626
  }
@@ -24499,7 +24798,7 @@ async function runJobWorkerForever(deps) {
24499
24798
  }
24500
24799
  }
24501
24800
 
24502
- // src/app/providers.ts
24801
+ // packages/archymedes-cli/src/app/providers.ts
24503
24802
  function renderProviders(environment, depth) {
24504
24803
  const paint2 = (text, apply) => depth === "none" ? text : apply(text);
24505
24804
  const statuses = describeProviders(environment);
@@ -24570,7 +24869,7 @@ function modelPriceCatalogFor(prices, exact) {
24570
24869
  return { ...rates, ...prices.largeContext ? { largeContext: prices.largeContext } : {} };
24571
24870
  }
24572
24871
 
24573
- // src/app/job-launch.ts
24872
+ // packages/archymedes-cli/src/app/job-launch.ts
24574
24873
  async function runJobWorkerProcess(root, jobId) {
24575
24874
  const savedSettings = await loadSettings(process.env);
24576
24875
  const environment = mergedEnvironment(savedSettings, process.env);
@@ -24607,10 +24906,10 @@ async function runJobWorkerProcess(root, jobId) {
24607
24906
  }
24608
24907
  }
24609
24908
 
24610
- // src/app/startup-commands.ts
24909
+ // packages/archymedes-cli/src/app/startup-commands.ts
24611
24910
  import { createInterface as createInterface4 } from "node:readline/promises";
24612
24911
 
24613
- // src/headless.ts
24912
+ // packages/archymedes-cli/src/headless.ts
24614
24913
  var EXIT_CODES2 = {
24615
24914
  completed: 0,
24616
24915
  failed: 1,
@@ -24634,7 +24933,7 @@ function exitCodeForStatus2(status) {
24634
24933
  return STATUS_EXIT2[status];
24635
24934
  }
24636
24935
 
24637
- // src/platform/doctor.ts
24936
+ // packages/archymedes-cli/src/platform/doctor.ts
24638
24937
  var DEFAULT_PROBE_TIMEOUT_MS = 5000;
24639
24938
  function modelEndpoints(environment) {
24640
24939
  return providerEndpoints(environment).map((provider) => {
@@ -24764,7 +25063,7 @@ function doctorReport(probes, context) {
24764
25063
  };
24765
25064
  }
24766
25065
 
24767
- // src/text/color-depth.ts
25066
+ // packages/archymedes-cli/src/text/color-depth.ts
24768
25067
  function detectColorDepth2(environment, isTTY) {
24769
25068
  if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
24770
25069
  return "none";
@@ -24773,7 +25072,7 @@ function detectColorDepth2(environment, isTTY) {
24773
25072
  return "ansi256";
24774
25073
  }
24775
25074
 
24776
- // src/session/delete-session.ts
25075
+ // packages/archymedes-cli/src/session/delete-session.ts
24777
25076
  import { promises as fs21 } from "node:fs";
24778
25077
  import path28 from "node:path";
24779
25078
  var SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
@@ -24793,7 +25092,7 @@ async function clearProjection(root, id) {
24793
25092
  if (!exists)
24794
25093
  return;
24795
25094
  try {
24796
- const { SessionProjection } = await import("./projection-ndr3t77h.mjs");
25095
+ const { SessionProjection } = await import("./projection-4jjdaf41.mjs");
24797
25096
  const projection = await SessionProjection.open(root);
24798
25097
  try {
24799
25098
  await projection.rebuild(id);
@@ -24819,7 +25118,7 @@ async function deleteSession(root, id, options = {}) {
24819
25118
  return { deleted: true };
24820
25119
  }
24821
25120
 
24822
- // src/ui/navigation.ts
25121
+ // packages/archymedes-cli/src/ui/navigation.ts
24823
25122
  var ESSENTIAL_COMMANDS = ["/help", "/history", "/model", "/mode", "/diff", "/undo", "/settings", "/exit"];
24824
25123
  function isEssential(command) {
24825
25124
  return ESSENTIAL_COMMANDS.includes(command);
@@ -24886,7 +25185,7 @@ function renderAsks(suggestions, style3) {
24886
25185
  `);
24887
25186
  }
24888
25187
 
24889
- // src/app/help.ts
25188
+ // packages/archymedes-cli/src/app/help.ts
24890
25189
  function helpText(language = "en", shortcuts = new Map) {
24891
25190
  const star = glyphs.star;
24892
25191
  const mark = (command) => isEssential(command) ? `${star} ` : " ";
@@ -24991,7 +25290,7 @@ ${renderCommandHelp(language, shortcuts, { mark })}
24991
25290
  `;
24992
25291
  }
24993
25292
 
24994
- // src/app/prompts.ts
25293
+ // packages/archymedes-cli/src/app/prompts.ts
24995
25294
  function settingsChooser(readline) {
24996
25295
  return (request) => openChooser({ readline, input: process.stdin, output: process.stdout }, request.items.map((item) => ({ ...item })), {
24997
25296
  title: request.title,
@@ -25064,7 +25363,7 @@ async function hiddenQuestion2(readline, question, signal) {
25064
25363
  }
25065
25364
  }
25066
25365
 
25067
- // src/app/startup-commands.ts
25366
+ // packages/archymedes-cli/src/app/startup-commands.ts
25068
25367
  function runInformationFlag(context) {
25069
25368
  const { args, environment, language, earlyDepth } = context;
25070
25369
  if (args.help) {
@@ -25268,7 +25567,7 @@ ${status.reason ?? "native state engine unavailable"}
25268
25567
  return 0;
25269
25568
  }
25270
25569
 
25271
- // src/app/display-currency.ts
25570
+ // packages/archymedes-cli/src/app/display-currency.ts
25272
25571
  async function settleDisplayCurrency(options) {
25273
25572
  const { args, environment, prices, rates, state } = options;
25274
25573
  if (prices && state.display !== prices.currency) {
@@ -25325,7 +25624,7 @@ async function settleDisplayCurrency(options) {
25325
25624
  return;
25326
25625
  }
25327
25626
 
25328
- // src/app/workspaces.ts
25627
+ // packages/archymedes-cli/src/app/workspaces.ts
25329
25628
  function createWorkspaceFactory(args, environment) {
25330
25629
  return async (request) => {
25331
25630
  const announce = (text) => {
@@ -25335,8 +25634,8 @@ function createWorkspaceFactory(args, environment) {
25335
25634
  };
25336
25635
  const minutes = Math.max(1, Math.min(args.sandboxMinutes, 60));
25337
25636
  if (request.backend === "e2b") {
25338
- const { findWorkspacePreset } = await import("./sandbox-templates-9jcjws23.mjs");
25339
- const { createE2BProvider } = await import("./factory-r6r0ypm6.mjs");
25637
+ const { findWorkspacePreset } = await import("./sandbox-templates-8sd1psez.mjs");
25638
+ const { createE2BProvider } = await import("./factory-3jav5ecj.mjs");
25340
25639
  const preset = findWorkspacePreset(request.preset ?? args.preset);
25341
25640
  const sandbox = createE2BProvider(environment, preset.templateAlias);
25342
25641
  if (!sandbox)
@@ -25362,7 +25661,7 @@ function createWorkspaceFactory(args, environment) {
25362
25661
  return { workspace: created };
25363
25662
  }
25364
25663
  if (request.backend === "docker") {
25365
- const { createDockerProvider } = await import("./factory-r6r0ypm6.mjs");
25664
+ const { createDockerProvider } = await import("./factory-3jav5ecj.mjs");
25366
25665
  const image = request.dockerImage || args.dockerImage || environment.DOCKER_CODING_IMAGE;
25367
25666
  const sandbox = createDockerProvider({ ...environment, DOCKER_CODING_IMAGE: image });
25368
25667
  if (!sandbox)
@@ -25391,11 +25690,11 @@ function createWorkspaceFactory(args, environment) {
25391
25690
  };
25392
25691
  }
25393
25692
 
25394
- // ../core/src/cli/balance.ts
25693
+ // packages/core/src/cli/balance.ts
25395
25694
  var CRITICAL_BALANCE_USD2 = 0.5;
25396
25695
  var LOW_BALANCE_USD2 = 2;
25397
25696
 
25398
- // src/commands/balance.ts
25697
+ // packages/archymedes-cli/src/commands/balance.ts
25399
25698
  function formatBalance(amount, currency) {
25400
25699
  return formatMoney(fromUnits(amount, currency));
25401
25700
  }
@@ -25498,7 +25797,7 @@ class BalanceWatch {
25498
25797
  }
25499
25798
  }
25500
25799
 
25501
- // src/session/resumed-spend.ts
25800
+ // packages/archymedes-cli/src/session/resumed-spend.ts
25502
25801
  async function readSessionModelTurns(root, sessionId) {
25503
25802
  const events = await readEventJournal(root, sessionId);
25504
25803
  const turns = [];
@@ -25530,7 +25829,7 @@ function priceSessionModelTurns(turns, options) {
25530
25829
  return { spent: total, unpriced: [...unpriced].sort() };
25531
25830
  }
25532
25831
 
25533
- // src/app/balance-tracking.ts
25832
+ // packages/archymedes-cli/src/app/balance-tracking.ts
25534
25833
  function createBalanceTracking(options) {
25535
25834
  const { environment, processEnvironment, rates, state } = options;
25536
25835
  const usdInDisplay = (usd) => {
@@ -25619,7 +25918,7 @@ function createBalanceTracking(options) {
25619
25918
  return { lowBalance, criticalBalance, balanceWatch, parseManualBalance, currentBalance, persistManualBalance, sessionSpend, balanceHeader, checkBalance, carryResumedSpend };
25620
25919
  }
25621
25920
 
25622
- // src/app/agent-factory.ts
25921
+ // packages/archymedes-cli/src/app/agent-factory.ts
25623
25922
  function createClientFactory(options) {
25624
25923
  const { args, environment, daemon, approvalPrompt, rates, approvedBudget, state } = options;
25625
25924
  return async (record2, runtime = {}) => {
@@ -25660,14 +25959,14 @@ function closeWithClient(client, hook) {
25660
25959
  client.dispose = () => dispose().finally(close);
25661
25960
  }
25662
25961
 
25663
- // src/app/live-models.ts
25962
+ // packages/archymedes-cli/src/app/live-models.ts
25664
25963
  async function readCachedLiveModels(environment, state) {
25665
25964
  const cached = await readModelCache(environment);
25666
25965
  if (isCacheFresh(cached))
25667
25966
  state.liveModels = cached.models;
25668
25967
  }
25669
25968
 
25670
- // src/app/session-hints.ts
25969
+ // packages/archymedes-cli/src/app/session-hints.ts
25671
25970
  function createSessionHints(options) {
25672
25971
  const { state, watched, tabs, usage } = options;
25673
25972
  const navContext = () => ({
@@ -25696,7 +25995,7 @@ function createSessionHints(options) {
25696
25995
  return { navContext, writeHint };
25697
25996
  }
25698
25997
 
25699
- // src/render/completion-card.ts
25998
+ // packages/archymedes-cli/src/render/completion-card.ts
25700
25999
  var CHECK_LABELS = {
25701
26000
  tests: "tests",
25702
26001
  typecheck: "typecheck",
@@ -25726,7 +26025,7 @@ function renderCompletionCard(input, style3) {
25726
26025
  return panel(lines, style3, { title, tone: failed2 ? "bad" : verified ? "good" : "warn" });
25727
26026
  }
25728
26027
 
25729
- // src/render/routing-receipt.ts
26028
+ // packages/archymedes-cli/src/render/routing-receipt.ts
25730
26029
  function formatMicros(micros, currency = "USD") {
25731
26030
  if (micros === undefined || !Number.isFinite(micros))
25732
26031
  return "—";
@@ -25818,10 +26117,10 @@ ${rule(cell, { label: badge })}` : out3.join(`
25818
26117
  `);
25819
26118
  }
25820
26119
 
25821
- // src/app/session-hints.ts
26120
+ // packages/archymedes-cli/src/app/session-hints.ts
25822
26121
  var failureStatus = (status) => status === "needs_approval" ? "waiting_approval" : status;
25823
26122
 
25824
- // src/app/turn-failure.ts
26123
+ // packages/archymedes-cli/src/app/turn-failure.ts
25825
26124
  async function handleTurnFailure(error, request, context) {
25826
26125
  const { args, environment, interactive, headless, recoveryState, state, navContext } = context;
25827
26126
  if (recoveryState.last?.request === request) {
@@ -25876,7 +26175,7 @@ ${style.yellow(`Stopped at the ${formatMoney(fromUnits(args.budget, state.displa
25876
26175
  return false;
25877
26176
  }
25878
26177
 
25879
- // src/app/turn-preflight.ts
26178
+ // packages/archymedes-cli/src/app/turn-preflight.ts
25880
26179
  async function runTurnPreflight(request, context) {
25881
26180
  const { args, readline, interactive, approvedBudget, rates, state } = context;
25882
26181
  const { currentBalance, balanceWatch, sessionSpend } = context.balance;
@@ -25974,7 +26273,7 @@ async function runTurnPreflight(request, context) {
25974
26273
  return true;
25975
26274
  }
25976
26275
 
25977
- // src/app/turn-runner.ts
26276
+ // packages/archymedes-cli/src/app/turn-runner.ts
25978
26277
  var addModelUsage2 = (left, right) => ({
25979
26278
  inputTokens: left.inputTokens + right.inputTokens,
25980
26279
  outputTokens: left.outputTokens + right.outputTokens,
@@ -26182,7 +26481,7 @@ ${result.status === "completed" ? asMarkdown(result.summary) : style.yellow(resu
26182
26481
  };
26183
26482
  }
26184
26483
 
26185
- // src/app/interrupts.ts
26484
+ // packages/archymedes-cli/src/app/interrupts.ts
26186
26485
  function createSigintHandling(options) {
26187
26486
  const { readline, state } = options;
26188
26487
  const handleSigint = () => {
@@ -26223,7 +26522,7 @@ function createSigintHandling(options) {
26223
26522
  return { bindSigint, unbindSigint };
26224
26523
  }
26225
26524
 
26226
- // src/app/session-start.ts
26525
+ // packages/archymedes-cli/src/app/session-start.ts
26227
26526
  import path29 from "node:path";
26228
26527
  async function resumeAtStartup(context) {
26229
26528
  const { args, interactive, stateHistory, state, openClient } = context;
@@ -26296,7 +26595,7 @@ async function runOneShot(context) {
26296
26595
  return args.json ? exitCodeForStatus2(state.lastTurnStatus) : ran ? 0 : 1;
26297
26596
  }
26298
26597
 
26299
- // src/archymedes.ts
26598
+ // packages/archymedes-cli/src/archymedes.ts
26300
26599
  async function main() {
26301
26600
  process.stdout.on("error", (error) => {
26302
26601
  if (error.code === "EPIPE")