@caddis/cli 0.4.56 → 0.4.58

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 (45) hide show
  1. package/bundles/antigravity-plugin/caddis_statusline.py +45 -11
  2. package/bundles/antigravity-plugin/guard_agy.py +700 -68
  3. package/bundles/antigravity-plugin/hooks.json +2 -1
  4. package/bundles/antigravity-plugin/plugin.json +1 -1
  5. package/bundles/antigravity-plugin/scripts/caddis_adhoc.py +69 -23
  6. package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +63 -12
  7. package/bundles/antigravity-plugin/scripts/caddis_docs_pr.py +9 -8
  8. package/bundles/antigravity-plugin/scripts/caddis_gate.py +21 -0
  9. package/bundles/antigravity-plugin/scripts/caddis_lanes.py +39 -2
  10. package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +67 -22
  11. package/bundles/antigravity-plugin/scripts/caddis_review.py +81 -11
  12. package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +124 -29
  13. package/bundles/antigravity-plugin/scripts/caddis_roadmap_page.py +80 -7
  14. package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +26 -9
  15. package/bundles/antigravity-plugin/scripts/caddis_spawn.py +24 -4
  16. package/bundles/antigravity-plugin/scripts/caddis_spend.py +120 -10
  17. package/bundles/antigravity-plugin/scripts/caddis_statusline.py +45 -11
  18. package/bundles/antigravity-plugin/scripts/caddis_worktree_close.py +14 -9
  19. package/bundles/antigravity-plugin/scripts/caddis_worktree_safety.py +12 -0
  20. package/bundles/antigravity-plugin/scripts/hook_log.py +13 -2
  21. package/bundles/antigravity-plugin/scripts/oss_review.py +300 -79
  22. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +20 -6
  23. package/bundles/antigravity-plugin/session_end_agy.py +13 -10
  24. package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +53 -8
  25. package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +11 -8
  26. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +1 -1
  27. package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +9 -5
  28. package/bundles/antigravity-plugin/skills/implement/SKILL.md +18 -11
  29. package/bundles/antigravity-plugin/skills/mmr/SKILL.md +4 -1
  30. package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +44 -4
  31. package/bundles/antigravity-plugin/skills/review-pr/SKILL.md +13 -4
  32. package/bundles/antigravity-plugin/skills/ship/SKILL.md +26 -7
  33. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +31 -0
  34. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +42 -4
  35. package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +3 -2
  36. package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +52 -175
  37. package/bundles/antigravity-plugin/warm_start_agy.py +26 -15
  38. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  39. package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
  40. package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +1 -1
  41. package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +9 -5
  42. package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +52 -175
  43. package/bundles/manifest.json +3 -3
  44. package/dist/cli.js +310 -46
  45. package/package.json +1 -1
@@ -329,7 +329,12 @@ def ram_facts():
329
329
  return None
330
330
 
331
331
 
332
- def record_context(cwd: str, pct: float) -> None:
332
+ def _safe_session_id(session_id) -> str:
333
+ """A file-name-safe form of a session id (letters, digits, - and _ only, 64 chars at most); "" when empty."""
334
+ return "".join(ch if (ch.isalnum() and ch.isascii()) or ch in "-_" else "_" for ch in str(session_id or ""))[:64].strip(".")
335
+
336
+
337
+ def record_context(cwd: str, pct: float, session_id: str = "") -> None:
333
338
  """Cache the runtime context figure for tools that never see the statusline payload.
334
339
 
335
340
  Claude Code hands `context_window.used_percentage` to the statusline and to NOTHING else.
@@ -342,6 +347,11 @@ def record_context(cwd: str, pct: float) -> None:
342
347
  render. Only writes where `.caddis/` already exists, so cd-ing into an unrelated folder
343
348
  never scatters artifact dirs. Fail-open and silent: a status line must never break a
344
349
  prompt, and this is the least important thing it does.
350
+
351
+ One folder can host several sessions, so the figure is also kept per session, in
352
+ `.caddis/context-window/<session id>.json`; a reader that knows its session id reads that file and
353
+ never another session's figure. `context-window.json` stays as the shared "last writer" for a reader
354
+ that does not know its session (robustness #19). Per-session files older than 2 days are removed.
345
355
  """
346
356
  try:
347
357
  if not cwd:
@@ -349,20 +359,44 @@ def record_context(cwd: str, pct: float) -> None:
349
359
  art = os.path.join(cwd, ".caddis")
350
360
  if not os.path.isdir(art):
351
361
  return
352
- target = os.path.join(art, "context-window.json")
353
362
  payload = {"used_percentage": round(float(pct), 1), "at": int(time.time())}
354
- try:
355
- with open(target, encoding="utf-8") as fh:
356
- if json.load(fh).get("used_percentage") == payload["used_percentage"]:
357
- return
358
- except Exception:
359
- pass
360
- tmp = target + ".tmp"
363
+ sid = _safe_session_id(session_id)
364
+ if sid:
365
+ per_dir = os.path.join(art, "context-window")
366
+ os.makedirs(per_dir, exist_ok=True)
367
+ _write_if_changed(os.path.join(per_dir, sid + ".json"), payload)
368
+ try:
369
+ cutoff = time.time() - 2 * 86400
370
+ for name in os.listdir(per_dir):
371
+ old = os.path.join(per_dir, name)
372
+ if os.path.getmtime(old) < cutoff:
373
+ os.unlink(old)
374
+ except Exception:
375
+ pass
376
+ _write_if_changed(os.path.join(art, "context-window.json"), payload)
377
+ except Exception:
378
+ pass
379
+
380
+
381
+ def _write_if_changed(target: str, payload: dict) -> None:
382
+ """Write the JSON `payload` atomically (a temp file named for this process), only when the figure changed."""
383
+ try:
384
+ with open(target, encoding="utf-8") as fh:
385
+ if json.load(fh).get("used_percentage") == payload["used_percentage"]:
386
+ return
387
+ except Exception:
388
+ pass
389
+ tmp = f"{target}.{os.getpid()}.tmp"
390
+ try:
361
391
  with open(tmp, "w", encoding="utf-8") as fh:
362
392
  json.dump(payload, fh)
363
393
  os.replace(tmp, target)
364
394
  except Exception:
365
- pass
395
+ try:
396
+ os.unlink(tmp)
397
+ except OSError:
398
+ pass
399
+ raise
366
400
 
367
401
 
368
402
  def relay_present(cwd: str) -> bool:
@@ -501,7 +535,7 @@ def render_claude(data: dict, cfg: dict) -> str:
501
535
  used = as_int(cw.get("total_input_tokens"))
502
536
  max_tokens = as_int(cw.get("context_window_size"))
503
537
  pct = float(as_int(cw.get("used_percentage")))
504
- record_context(cwd, pct) # feeds /caddis:spawn-session's 95% gate; see record_context
538
+ record_context(cwd, pct, str(dig(data, "session_id") or "")) # feeds /caddis:spawn-session's 95% gate; see record_context
505
539
  parts.append(context_segment(c, cfg, used, max_tokens, pct))
506
540
  loud = cached_segment(c, cfg, cached)
507
541
  if loud: