pitroom 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pitroom",
3
3
  "description": "A free pit crew for your expensive coding agent: the superpowers development workflow, run by cheap workers. Delegate research, fixes, tests, reviews and whole plans from Claude Code, Codex or any agent to OpenCode, Codex or Claude Code workers, with receipts that prove the savings.",
4
- "version": "0.11.0",
4
+ "version": "0.12.0",
5
5
  "author": {
6
6
  "name": "TahaAtas"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pitroom",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "A free pit crew for your expensive coding agent: delegate research, fixes, tests, reviews and parallel investigations to cheap worker agents running your own models, with verified answers, exact diffs and cost receipts.",
5
5
  "author": {
6
6
  "name": "TahaAtas"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Cooldowns
6
+ - A model that says "rate limited" (a free daily quota used up, an overloaded provider) is remembered for a while, so the next runs go straight to the fallback instead of each one trying the exhausted model first and waiting for it to fail. The wait comes from the provider's message when it gives one (`retry in 4h28m`), else a guess: 4 hours for a daily quota, 20 minutes for overload; at least a minute, at most a day.
7
+ - A model on cooldown is skipped only while another worker is left to run; if it is the only one it is still tried. Cooldowns expire on their own.
8
+ - The report says `skipped: … (cooling down until 14:05: …)`, the dashboard card shows "Skipped …", `pitroom doctor` warns with the time, and `pitroom cooldown` lists them (`--clear` tries them again). Only rate-limit failures count, not a missing model or a sign-in problem.
9
+
3
10
  ## 0.11.0
4
11
 
5
12
  ### Gemini CLI as your primary agent
package/README.md CHANGED
@@ -457,6 +457,7 @@ pitroom crew [-i] [-g NAME] "task 1" "task 2" … (or --task-file with --- sep
457
457
  pitroom run -i --plan PLAN --step N [--tier T] ["notes"]
458
458
  pitroom review [run | --range A..B [--plan PLAN]] [--tier T | -W T] [--bg]
459
459
  pitroom audit RUN [-W worker]
460
+ pitroom cooldown [--clear]
460
461
  pitroom plan status PLAN [--json] · pitroom plan note PLAN "Task N: …"
461
462
  pitroom status|wait|watch [run… | -g NAME] wait: --any --brief --timeout · watch: --json|--brief --interval
462
463
  pitroom dash [--detach] [--port N] [--open] [--stop] a live page of the runs on 127.0.0.1
@@ -554,7 +555,7 @@ claude haiku low/medium/high/xhigh/max ? - -
554
555
 
555
556
  Pitroom cannot know vendor prices and does not fetch them, so a cost is what you enter: `"costs": {"codex:gpt-6-sol": 1, "codex:gpt-6.1-sol": 2}` in the config, in any unit (they are only compared). `pitroom doctor` then prints the cost of the models in use and says when you priced a cheaper one of the same worker. A target that names only an effort (`codex:#low`) uses the model from `models`; a Codex or Claude Code worker with no pinned model gets a warning, because it would run the vendor's own default, which can change and cost more. `--effort LEVEL` sets the level for one run; your agent picks model and level from `pitroom models` (cheapest that fits: `low` for lookups, `medium` for ordinary changes, `high` for reviews).
556
557
 
557
- Fallbacks cross backends (e.g. `"fallback": ["codex:#low", "opencode"]`): a worker that is rate-limited, logged out or missing its model hands the task to the next. Follow-ups (`--continue`) always stay on the worker that owns the session. Writing an adapter: [docs/backends.md](docs/backends.md).
558
+ Fallbacks cross backends (e.g. `"fallback": ["codex:#low", "opencode"]`): a worker that is rate-limited, logged out or missing its model hands the task to the next. Follow-ups (`--continue`) always stay on the worker that owns the session. Writing an adapter: [docs/backends.md](docs/backends.md). A model that says "rate limited" (a daily quota used up, an overloaded provider) is remembered for the time its message gives, or a guess: the next runs skip it while a fallback is left, so they do not each wait for it to fail. `pitroom cooldown` lists what is skipped and until when, `--clear` tries it again, and `doctor` shows it too.
558
559
 
559
560
  ---
560
561
 
package/dist/lib.mjs CHANGED
@@ -1495,6 +1495,27 @@ function fill(template, values) {
1495
1495
  return template.replace(/\{\{([A-Z_]+)\}\}/g, (_, key) => values[key]);
1496
1496
  }
1497
1497
 
1498
+ // src/core/cooldown.ts
1499
+ var MAX_MS = 24 * 36e5;
1500
+ var OVERLOAD_MS = 20 * 6e4;
1501
+ var DAILY_MS = 4 * 36e5;
1502
+ function retryAfterMs(message) {
1503
+ const compact = /(?:retry|try again|resets?|available again)[^0-9]{0,24}((?:\d+(?:\.\d+)?\s*[dhms]\s*)+)/i.exec(message)?.[1];
1504
+ const words = /(?:retry|try again|resets?)[^0-9]{0,24}(\d+(?:\.\d+)?)\s*(second|minute|hour)s?/i.exec(message);
1505
+ let ms = 0;
1506
+ if (compact) {
1507
+ for (const [, n, unit] of compact.matchAll(/(\d+(?:\.\d+)?)\s*([dhms])/gi)) ms += Number(n) * { d: 864e5, h: 36e5, m: 6e4, s: 1e3 }[unit.toLowerCase()];
1508
+ } else if (words) {
1509
+ ms = Number(words[1]) * { second: 1e3, minute: 6e4, hour: 36e5 }[words[2].toLowerCase()];
1510
+ }
1511
+ return ms > 0 ? ms : void 0;
1512
+ }
1513
+ function cooldownMs(message) {
1514
+ const told = retryAfterMs(message);
1515
+ if (told !== void 0) return Math.min(Math.max(told, 6e4), MAX_MS);
1516
+ return /daily|per.?day|per day|exhausted your/i.test(message) ? DAILY_MS : OVERLOAD_MS;
1517
+ }
1518
+
1498
1519
  // src/core/answers.ts
1499
1520
  var TASK_STATUSES = ["DONE", "DONE_WITH_CONCERNS", "NEEDS_CONTEXT", "BLOCKED"];
1500
1521
  function parseStatus(text) {
@@ -1598,6 +1619,7 @@ export {
1598
1619
  allBackends,
1599
1620
  backendIds,
1600
1621
  brief,
1622
+ cooldownMs,
1601
1623
  describeTarget,
1602
1624
  extractRefs,
1603
1625
  fill,
@@ -1612,5 +1634,6 @@ export {
1612
1634
  parseVerdict,
1613
1635
  planName,
1614
1636
  planTask,
1637
+ retryAfterMs,
1615
1638
  verifyRefs
1616
1639
  };