cortad 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/local.mjs +18 -5
  2. package/package.json +4 -1
package/local.mjs CHANGED
@@ -149,8 +149,13 @@ function envOrigins(envFiles) {
149
149
  const THROUGHPUT = /(RATE_?LIMIT|DAILY_LIMIT|HOURLY_LIMIT|MINUTE_LIMIT|REQUESTS_PER|TOKEN_BUDGET|MAX_SSE|MAX_CONCURRENT|THROTTLE|_RPM$|_RPS$|_QPS$)/;
150
150
  const GUARDED = /(AUTH|LOGIN|PASSWORD|BREAKER|LOCKOUT|ATTEMPT|FAIL|BAN|BLOCK)/;
151
151
  const SWITCH = /_(?:ENABLED|DISABLED|ENABLE|DISABLE)$|^(?:ENABLE|DISABLE)_/;
152
- function liftedLimits(envFiles) {
153
- const lifted = {};
152
+ // Limit-shaped names the code itself reads (process.env.GUEST_DAILY_LIMIT, os.environ.get("RATE_LIMIT_RPM"))
153
+ // count too: a limit with a default in code and no line in .env is the one that closes on a run.
154
+ const ENV_READ = /(?:process\.env(?:\.|\[\s*['"])|os\.(?:environ\.get|getenv)\(\s*['"]|os\.environ\[\s*['"]|\benv\(\s*['"]|Deno\.env\.get\(\s*['"])([A-Z][A-Z0-9_]*)/g;
155
+ const lifted = (name) => (/(TOKEN_BUDGET|TOKENS)/.test(name) ? "1000000000" : "1000000");
156
+ const liftable = (name) => THROUGHPUT.test(name) && !GUARDED.test(name) && !SWITCH.test(name);
157
+ function liftedLimits(envFiles, sources = []) {
158
+ const out = {};
154
159
  for (const file of envFiles) {
155
160
  let text = "";
156
161
  try { text = readFileSync(file, "utf8"); } catch { continue; }
@@ -159,10 +164,16 @@ function liftedLimits(envFiles) {
159
164
  if (!m) continue;
160
165
  const [, name, raw] = m;
161
166
  const value = raw.trim().replace(/^(['"])(.*)\1$/, "$2");
162
- if (THROUGHPUT.test(name) && !GUARDED.test(name) && !SWITCH.test(name) && /^\d+$/.test(value)) lifted[name] = /(TOKEN_BUDGET|TOKENS)/.test(name) ? "1000000000" : "1000000";
167
+ if (liftable(name) && /^\d+$/.test(value)) out[name] = lifted(name);
163
168
  }
164
169
  }
165
- return lifted;
170
+ for (const file of sources) {
171
+ if (!/\.(?:[cm]?[jt]sx?|py|go|rb|php|rs)$/.test(file)) continue;
172
+ let text = "";
173
+ try { if (statSync(file).size > 512_000) continue; text = readFileSync(file, "utf8"); } catch { continue; }
174
+ for (const m of text.matchAll(ENV_READ)) if (liftable(m[1]) && !(m[1] in out)) out[m[1]] = lifted(m[1]);
175
+ }
176
+ return out;
166
177
  }
167
178
  let secrets = [];
168
179
  let identities = null;
@@ -335,6 +346,7 @@ async function startApp() {
335
346
  const wanted = Number(flag("--port"));
336
347
  if (wanted) {
337
348
  if (!(await answers(wanted))) fail(`nothing is answering on port ${wanted}. Start your app first, then run this again.`);
349
+ say("your app was already running, so its request limits stay as they are; if it answers 429, stop it and run this without --port and they are raised for the session");
338
350
  return { port: wanted, cmd: null };
339
351
  }
340
352
  const plan = startPlan({ root, typed: flag("--start"), onPath });
@@ -343,7 +355,7 @@ async function startApp() {
343
355
  appDir = plan?.cwd ?? root;
344
356
  pinned = pinnedNode();
345
357
  if (plan?.within) say(`your app is in ${plan.within}, started there with: ${cmd}`);
346
- const lifted = liftedLimits(envFiles);
358
+ const lifted = liftedLimits(envFiles, files.map((f) => join(root, f)));
347
359
  if (Object.keys(lifted).length) say(`higher request limits for this session: ${Object.keys(lifted).join(", ")}`);
348
360
  launched = { cmd, lifted };
349
361
  step(`starting your app: ${cmd}`);
@@ -480,6 +492,7 @@ if (explain) {
480
492
  `not sent anything git ignores, env files (${envFiles.length} here: ${envFiles.slice(0, 6).map(rel).join(", ") || "none"}), key files, data files, node_modules, .git`,
481
493
  `env files read here only: to hide their values in replies, and to sign in a test account`,
482
494
  `would start ${flag("--port") ? `nothing: uses your app on port ${flag("--port")}` : plan ? `${plan.cmd} (in ${rel(plan.cwd)})` : "asks you how your app starts"}`,
495
+ `would raise ${flag("--port") ? "nothing: your app's own request limits stay as they are" : `${Object.keys(liftedLimits(envFiles, files.map((f) => join(root, f)))).join(", ") || "no request limits found"} (for this session only)`}`,
483
496
  `loads into app lib/trace.cjs (Node) or lib/pyhook/sitecustomize.py (Python): records the one request during which your app calls a model`,
484
497
  `agent edits in your files, each with an undo kept in ~/.cortad/checkpoints; git is never touched`,
485
498
  `agent shell confined by the OS: your project and toolchains only, writes to temp and build folders, localhost only`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortad",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Connects the AI app on your machine to Cortad for test conversations. No dependencies.",
5
5
  "bin": {
6
6
  "cortad": "local.mjs"
@@ -18,6 +18,9 @@
18
18
  "lib/trace.cjs",
19
19
  "local.mjs"
20
20
  ],
21
+ "scripts": {
22
+ "test": "node --test lib/*.test.mjs"
23
+ },
21
24
  "engines": {
22
25
  "node": ">=20"
23
26
  },