cortad 0.4.5 → 0.4.6

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.
package/lib/proxy.mjs CHANGED
@@ -19,7 +19,9 @@ const { MAX, REPLY_MAX, MODEL_HOST, scrubbed, turnOf, decoded, cookieNames, make
19
19
  // Where each SDK sends its calls when the app's settings name nowhere else.
20
20
  const DEFAULTS = { OPENAI_BASE_URL: "https://api.openai.com/v1", ANTHROPIC_BASE_URL: "https://api.anthropic.com", GOOGLE_GEMINI_BASE_URL: "https://generativelanguage.googleapis.com" };
21
21
  // Another setting of the app's that addresses a model: a URL on a model host, or a base URL named for one.
22
- const MODEL_SETTING = /OPENAI|ANTHROPIC|GEMINI|LLM|OLLAMA|LITELLM|VLLM/i;
22
+ // `MODEL`: an app that names its own provider rather than an SDK's calls the setting
23
+ // MODEL_ENDPOINT or MODEL_URL (Helix Foundry does), and that address is the one to take over.
24
+ const MODEL_SETTING = /OPENAI|ANTHROPIC|GEMINI|LLM|OLLAMA|LITELLM|VLLM|MODEL/i;
23
25
  const ADDRESS_SETTING = /BASE|URL|ENDPOINT|HOST/i;
24
26
  const SECRET_SETTING = /KEY|TOKEN|SECRET|PASSWORD/i;
25
27
  // Said by one connection, never passed on. A provider's reply is passed on decoded, so its encoding goes too.
package/local.mjs CHANGED
@@ -730,12 +730,13 @@ async function startProxied(up, waitMs) {
730
730
 
731
731
  async function start(waitMs) {
732
732
  const { cmd, lifted } = launched;
733
+ const cmdText = commandText(cmd, appDir);
733
734
  // The record of what the app writes opens with the app: the first run starts itself on the
734
735
  // server's side, with no verb here to mark it, and a restart mid-run keeps the record open.
735
736
  try { markRun(writesDirOf(homeOf(projectOf(root))), "session", { keep: true }); } catch { /* the app's writes go unrecorded */ }
736
737
  toolsAtStart = toolsNow();
737
738
  // Taken before the app reads a file: a save after this moment is a change it has not loaded.
738
- const note = { own: true, at: Date.now(), reloads: RELOADER.test(commandText(cmd, appDir)), answered: false };
739
+ const note = { own: true, at: Date.now(), reloads: RELOADER.test(cmdText), answered: false };
739
740
  note.files = sourceOf(root, files);
740
741
  loaded = note;
741
742
  // The app gets this terminal's environment, as a start by hand would, its own request limits raised
@@ -779,8 +780,12 @@ async function start(waitMs) {
779
780
  const ports = await listening(mine.pid);
780
781
  // The socket can open before the server answers; the log line is the tiebreak among several.
781
782
  const plain = withoutStores(seen.replace(/\x1b\[[0-9;]*m/g, ""));
782
- const said = [...plain.matchAll(/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1?\]):(\d{2,5})\b|\bport\s*[:=]?\s*(\d{4,5})\b/gi)].map((m) => Number(m[1] || m[2]));
783
- for (const port of [...new Set([...(wantedPort ? [wantedPort] : []), ...said.reverse().filter((p) => ports.includes(p)), ...ports])]) {
783
+ const said = [...plain.matchAll(/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1?\]):(\d{2,5})\b|\bport\s*[:=]?\s*(\d{4,5})\b/gi)].map((m) => Number(m[1] || m[2])).reverse();
784
+ // A container publishes its port through the daemon, so nothing in this command's own process
785
+ // family listens on it and `ports` stays empty however long the wait runs. What the container
786
+ // said is then the only evidence there is, and `answers` still has to agree before it is used.
787
+ const alsoSaid = IN_CONTAINER.test(cmdText) ? said : [];
788
+ for (const port of [...new Set([...(wantedPort ? [wantedPort] : []), ...said.filter((p) => ports.includes(p)), ...ports, ...alsoSaid])]) {
784
789
  if (await answers(port)) {
785
790
  note.answered = true;
786
791
  if (loaded === note) noteApp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortad",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Connects the AI app on your machine to Cortad for test conversations, and gives your coding agent the MCP and skill to run them. No dependencies.",
5
5
  "bin": {
6
6
  "cortad": "local.mjs"