javis 0.2.0__py3-none-any.whl

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 (86) hide show
  1. javis/__init__.py +7 -0
  2. javis/_banner.py +69 -0
  3. javis/budget.py +17 -0
  4. javis/builtin_marketplace/code-review/agents/reviewer.md +9 -0
  5. javis/builtin_marketplace/code-review/commands/review.md +16 -0
  6. javis/builtin_marketplace/code-review/plugin.json +4 -0
  7. javis/builtin_marketplace/commit/commands/commit.md +13 -0
  8. javis/builtin_marketplace/commit/plugin.json +4 -0
  9. javis/builtin_marketplace/explain/agents/explainer.md +7 -0
  10. javis/builtin_marketplace/explain/commands/explain.md +15 -0
  11. javis/builtin_marketplace/explain/plugin.json +4 -0
  12. javis/builtin_marketplace/test-author/agents/test-author.md +8 -0
  13. javis/builtin_marketplace/test-author/commands/test.md +12 -0
  14. javis/builtin_marketplace/test-author/plugin.json +4 -0
  15. javis/caching.py +39 -0
  16. javis/catalog.py +68 -0
  17. javis/cli.py +644 -0
  18. javis/commands.py +77 -0
  19. javis/compress.py +33 -0
  20. javis/config.py +60 -0
  21. javis/context.py +111 -0
  22. javis/core.py +56 -0
  23. javis/distill.py +74 -0
  24. javis/errors.py +120 -0
  25. javis/eval.py +281 -0
  26. javis/eval_ab.py +133 -0
  27. javis/events.py +131 -0
  28. javis/experiment.py +214 -0
  29. javis/failure_memory.py +97 -0
  30. javis/gates/__init__.py +0 -0
  31. javis/gates/base.py +16 -0
  32. javis/gates/lint.py +36 -0
  33. javis/gates/oracle.py +78 -0
  34. javis/gates/parse.py +31 -0
  35. javis/gates/policy.py +108 -0
  36. javis/gates/readwrite.py +28 -0
  37. javis/gates/resolve.py +213 -0
  38. javis/gates/verify.py +13 -0
  39. javis/guardrails.py +107 -0
  40. javis/hooks.py +127 -0
  41. javis/ladders.py +75 -0
  42. javis/languages.py +145 -0
  43. javis/localproto.py +126 -0
  44. javis/loop.py +623 -0
  45. javis/lsp.py +350 -0
  46. javis/marketplace.py +212 -0
  47. javis/mcp.py +459 -0
  48. javis/mcp_install.py +184 -0
  49. javis/model.py +96 -0
  50. javis/narrator.py +85 -0
  51. javis/orchestrate.py +341 -0
  52. javis/permissions.py +108 -0
  53. javis/plan.py +112 -0
  54. javis/planmode.py +28 -0
  55. javis/plugins.py +324 -0
  56. javis/polyglot.py +309 -0
  57. javis/preflight.py +180 -0
  58. javis/ratelimit.py +89 -0
  59. javis/redact.py +36 -0
  60. javis/repomap.py +83 -0
  61. javis/router.py +125 -0
  62. javis/sanitize.py +44 -0
  63. javis/semsearch.py +171 -0
  64. javis/setup.py +84 -0
  65. javis/slash.py +101 -0
  66. javis/subagents.py +155 -0
  67. javis/swebench.py +385 -0
  68. javis/swebench_docker.py +136 -0
  69. javis/theme.py +99 -0
  70. javis/tools/__init__.py +0 -0
  71. javis/tools/code.py +101 -0
  72. javis/tools/fs.py +139 -0
  73. javis/tools/git.py +32 -0
  74. javis/tools/shell.py +23 -0
  75. javis/tools/tests.py +158 -0
  76. javis/trajectory.py +59 -0
  77. javis/treesitter.py +266 -0
  78. javis/tui.py +910 -0
  79. javis/tui_app.py +284 -0
  80. javis-0.2.0.dist-info/METADATA +200 -0
  81. javis-0.2.0.dist-info/RECORD +86 -0
  82. javis-0.2.0.dist-info/WHEEL +5 -0
  83. javis-0.2.0.dist-info/entry_points.txt +10 -0
  84. javis-0.2.0.dist-info/licenses/LICENSE +202 -0
  85. javis-0.2.0.dist-info/licenses/NOTICE +4 -0
  86. javis-0.2.0.dist-info/top_level.txt +1 -0
javis/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """JAVIS — a harness-governed coding agent.
2
+
3
+ Phase 0 thesis: the intelligence is in the harness, not the model. The model is an
4
+ untrusted prover; the harness is a sound proof checker. See docs/harness-contract.md.
5
+ """
6
+
7
+ __version__ = "0.0.0"
javis/_banner.py ADDED
@@ -0,0 +1,69 @@
1
+ """Generated by scripts/gen_banner.py from the JAVIS logo. Do not edit by hand.
2
+ HERO/LOGO are rich markup (crimson scorpion / white shield); *_PLAIN strip the tags."""
3
+
4
+ HERO = r'''
5
+ [#f5f5f5]▒▓▓▒▒[/] [#e10600]▓█████▓[/] [#e10600]▓█████▒[/] [#f5f5f5]▒▓▓▓▒[/]
6
+ [#f5f5f5]▓██▓[/] [#e10600]▒██████▓[/] [#e10600]▒▓[/] [#e10600]▓▒[/] [#e10600]▓██████▓[/] [#f5f5f5]▓██▓[/]
7
+ [#f5f5f5]█▓[/] [#e10600]▒▓███████▓███▒[/] [#e10600]██[/] [#e10600]▓█[/] [#e10600]▒███▓████████[/] [#f5f5f5]▓█▒[/]
8
+ [#f5f5f5]▓█[/] [#e10600]▓▓▓████▓██▓[/] [#e10600]█████[/] [#e10600]▒██▓█████▓█▓[/] [#f5f5f5]█▓[/]
9
+ [#f5f5f5]▓█[/] [#e10600]████▓[/] [#e10600]▒██▒███████▒██▒[/] [#e10600]▓████[/] [#f5f5f5]▓▓[/]
10
+ [#f5f5f5]▓▓[/] [#e10600]█████[/] [#e10600]▒████▓████████▓███▓[/] [#e10600]█████[/] [#f5f5f5]▓▓[/]
11
+ [#f5f5f5]▒▒[/] [#e10600]████▓████▓█████████▓████▓▓███[/] [#f5f5f5]▒[/]
12
+ [#e10600]██▒████▒[/] [#e10600]▓████████[/] [#e10600]▒▓███▒██[/]
13
+ [#e10600]▒[/] [#e10600]▒[/] [#e10600]▓█████▓[/] [#e10600]▒[/]
14
+ [#e10600]▒██▓[/] [#e10600]█▓▓▓▒██[/]
15
+ [#e10600]▓███▓[/] [#e10600]█████▓[/]
16
+ [#e10600]▓██▓[/] [#e10600]▓██▓███[/]
17
+ [#f5f5f5]▒[/][#e10600]▒████[/] [#e10600]▓████▒[/] [#f5f5f5]▒[/]
18
+ [#f5f5f5]▒▓[/] [#e10600]▓█▓█▓[/] [#e10600]▓███▓[/] [#f5f5f5]▓▒[/]
19
+ [#f5f5f5]▓▓[/] [#e10600]▓███▒███▓[/] [#f5f5f5]▓▓[/]
20
+ [#f5f5f5]▒█▓[/] [#e10600]▓█▓█▓[/] [#f5f5f5]▒█▓[/]
21
+ [#f5f5f5]▓█▓[/] [#f5f5f5]▒█▓[/]
22
+ [#f5f5f5]▒██▓██▒[/]
23
+ [#f5f5f5]▒█▒[/]
24
+ '''
25
+
26
+ HERO_PLAIN = r'''
27
+ ▒▓▓▒▒ ▓█████▓ ▓█████▒ ▒▓▓▓▒
28
+ ▓██▓ ▒██████▓ ▒▓ ▓▒ ▓██████▓ ▓██▓
29
+ █▓ ▒▓███████▓███▒ ██ ▓█ ▒███▓████████ ▓█▒
30
+ ▓█ ▓▓▓████▓██▓ █████ ▒██▓█████▓█▓ █▓
31
+ ▓█ ████▓ ▒██▒███████▒██▒ ▓████ ▓▓
32
+ ▓▓ █████ ▒████▓████████▓███▓ █████ ▓▓
33
+ ▒▒ ████▓████▓█████████▓████▓▓███ ▒
34
+ ██▒████▒ ▓████████ ▒▓███▒██
35
+ ▒ ▒ ▓█████▓ ▒
36
+ ▒██▓ █▓▓▓▒██
37
+ ▓███▓ █████▓
38
+ ▓██▓ ▓██▓███
39
+ ▒▒████ ▓████▒ ▒
40
+ ▒▓ ▓█▓█▓ ▓███▓ ▓▒
41
+ ▓▓ ▓███▒███▓ ▓▓
42
+ ▒█▓ ▓█▓█▓ ▒█▓
43
+ ▓█▓ ▒█▓
44
+ ▒██▓██▒
45
+ ▒█▒
46
+ '''
47
+
48
+ LOGO = r'''
49
+ [#e10600]▓▒[/] [#e10600]▓[/]
50
+ [#f5f5f5]▒▓[/][#e10600]▓███▓▒▓▒████[/][#f5f5f5]▒▓[/]
51
+ [#f5f5f5]▓[/][#e10600]██▓██████▓██▒[/][#f5f5f5]▒[/]
52
+ [#e10600]▓▓█▓███▓█▓▒[/]
53
+ [#e10600]█▓██▓[/]
54
+ [#e10600]▓█▓▓█▒[/]
55
+ [#f5f5f5]▓[/][#e10600]▓▓[/][#f5f5f5]▓▒[/]
56
+ [#f5f5f5]▒▓[/]
57
+ '''
58
+
59
+ LOGO_PLAIN = r'''
60
+ ▓▒ ▓
61
+ ▒▓▓███▓▒▓▒████▒▓
62
+ ▓██▓██████▓██▒▒
63
+ ▓▓█▓███▓█▓▒
64
+ █▓██▓
65
+ ▓█▓▓█▒
66
+ ▓▓▓▓▒
67
+ ▒▓
68
+ '''
69
+
javis/budget.py ADDED
@@ -0,0 +1,17 @@
1
+ """Run budget — so a thrashing weak model can't burn unbounded tokens (non-negotiable #7)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass
9
+ class Budget:
10
+ max_steps: int = 40
11
+ used: int = 0
12
+
13
+ def tick(self) -> None:
14
+ self.used += 1
15
+
16
+ def exhausted(self) -> bool:
17
+ return self.used >= self.max_steps
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Focused code reviewer — finds defensible defects in a diff or file and grades severity.
3
+ model: opus
4
+ ---
5
+ You are a precise code reviewer. Given a diff or a file, surface only defects you can defend from the
6
+ code itself: logic errors, unhandled edge cases, security issues, and broken invariants. For each one
7
+ give `file:line`, the reason it is wrong, and the smallest fix. Rank findings by severity and finish
8
+ with a verdict — APPROVE, APPROVE-WITH-NITS, or REQUEST-CHANGES. Never pad the list to seem thorough;
9
+ a short, correct review beats a long, speculative one.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Review the staged diff (or a given path) for correctness, security, and regressions.
3
+ ---
4
+ Review the code changes for **correctness, security, and regressions** — be specific and cite `file:line`.
5
+
6
+ Target: $ARGUMENTS
7
+ (If that is empty, review the staged diff: `git diff --cached`.)
8
+
9
+ Do this:
10
+ 1. If a path was given, read it; otherwise inspect the staged diff.
11
+ 2. Find concrete defects, ordered by severity — logic errors, unhandled edge cases, security issues
12
+ (injection, path traversal, leaked secrets), and broken invariants or missing tests.
13
+ 3. For each finding give: the location, why it is wrong, and the smallest fix.
14
+ 4. End with a one-line verdict: APPROVE, APPROVE-WITH-NITS, or REQUEST-CHANGES.
15
+
16
+ Report only what you can defend from the code. Do not invent issues to look thorough.
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "code-review",
3
+ "description": "Diff-aware code review — a strong-tier reviewer agent and a /review command."
4
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ description: Draft a Conventional-Commits message from the staged diff.
3
+ ---
4
+ Write a commit message for the currently staged changes.
5
+
6
+ 1. Read the staged diff: `git diff --cached`. If nothing is staged, say so and stop.
7
+ 2. Summarise the *intent* of the change, not a file-by-file list.
8
+ 3. Format as Conventional Commits: `type(scope): subject` (subject ≤72 chars), a blank line, then
9
+ 1–3 short body bullets if the change warrants explanation. Types: feat, fix, refactor, docs, test,
10
+ chore, perf.
11
+ 4. Output only the commit message, ready to paste — no preamble, no fences.
12
+
13
+ Extra context from the user (optional): $ARGUMENTS
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "commit",
3
+ "description": "Draft a Conventional-Commits message from the staged diff."
4
+ }
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: Explains code clearly and accurately, grounded in the actual source.
3
+ tier: cheap
4
+ ---
5
+ You explain code for someone who is about to modify it. Read the target first, then cover its purpose,
6
+ the main control flow, edge cases, and risks — each grounded in a `file:line` you actually read. Be
7
+ concise and concrete. If something cannot be determined from the code, say so rather than guessing.
@@ -0,0 +1,15 @@
1
+ ---
2
+ description: Explain a file or symbol — intent, control flow, edge cases, and risks.
3
+ ---
4
+ Explain the target so a new contributor could safely change it.
5
+
6
+ Target: $ARGUMENTS
7
+ (A path, or a symbol name to locate first.)
8
+
9
+ Cover, briefly:
10
+ 1. **Purpose** — what it is for and where it is used.
11
+ 2. **Flow** — the key path through the code, step by step.
12
+ 3. **Edge cases & failure modes** — inputs or states that need care.
13
+ 4. **Risks** — anything surprising, fragile, or easy to break.
14
+
15
+ Quote `file:line` for each claim. Read the code before explaining it; do not guess.
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "explain",
3
+ "description": "Explain a file or symbol — intent, control flow, edge cases, and risks."
4
+ }
@@ -0,0 +1,8 @@
1
+ ---
2
+ description: Writes focused, regression-catching tests that match the project's conventions.
3
+ model: sonnet
4
+ ---
5
+ You write tests that catch real regressions. Read the target to infer its contract, mirror the
6
+ project's existing test framework and style, and cover the happy path, the key edge cases, and a
7
+ failure case. Keep every test deterministic and independent — no network, no sleeps; use temp dirs and
8
+ fixtures. Prefer a few sharp tests over many shallow ones, and name the file each test should live in.
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Generate focused, runnable tests for a target file or function.
3
+ ---
4
+ Write tests for: $ARGUMENTS
5
+
6
+ 1. Read the target and infer its contract — inputs, outputs, error paths, and invariants.
7
+ 2. Match the project's existing test framework and conventions (look at the nearest tests first).
8
+ 3. Cover the happy path, the important edge cases, and at least one failure/error case.
9
+ 4. Make every test deterministic and independent — no network, no sleeps; use fixtures and temp dirs.
10
+ 5. Output runnable test code, and name the file it should live in.
11
+
12
+ Prefer a few sharp tests that would actually catch a regression over many shallow ones.
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "test-author",
3
+ "description": "Generate focused, regression-catching tests aligned with JAVIS's test gate."
4
+ }
javis/caching.py ADDED
@@ -0,0 +1,39 @@
1
+ """Optional prompt-cache markers (provider-agnostic via litellm).
2
+
3
+ When enabled, marks the stable prefix (the system message) with a `cache_control` breakpoint.
4
+ litellm applies it for providers that support explicit prompt caching (Anthropic, Bedrock,
5
+ DeepSeek, …) and ignores it elsewhere — JAVIS never branches on provider. Off by default;
6
+ opt in (`--cache`) only when your tier's provider benefits. Non-mutating: returns a new list.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ _BREAKPOINT = {"type": "ephemeral"}
12
+
13
+
14
+ def _as_cached_blocks(content):
15
+ if isinstance(content, str):
16
+ return [{"type": "text", "text": content, "cache_control": _BREAKPOINT}]
17
+ if isinstance(content, list):
18
+ blocks = [dict(b) if isinstance(b, dict) else b for b in content]
19
+ for block in reversed(blocks):
20
+ if isinstance(block, dict) and block.get("type") == "text":
21
+ block["cache_control"] = _BREAKPOINT
22
+ break
23
+ return blocks
24
+ return content
25
+
26
+
27
+ def apply_cache_control(messages: list[dict]) -> list[dict]:
28
+ """Return messages with a cache_control breakpoint on the first system message."""
29
+ out: list[dict] = []
30
+ marked = False
31
+ for msg in messages:
32
+ if not marked and msg.get("role") == "system":
33
+ new = dict(msg)
34
+ new["content"] = _as_cached_blocks(msg.get("content"))
35
+ out.append(new)
36
+ marked = True
37
+ else:
38
+ out.append(msg)
39
+ return out
javis/catalog.py ADDED
@@ -0,0 +1,68 @@
1
+ """OpenRouter model catalog — pick tool-capable / cheap models instead of guessing slugs.
2
+
3
+ The OpenRouter models API lists every model with its `supported_parameters` and pricing. We
4
+ fetch it best-effort (cached to a file) and expose pure filters, so we stop guessing slugs (we
5
+ hit 'no endpoints found' / 'no tool use' live). OpenRouter-specific by design — it's our routing
6
+ layer, not provider lock-in.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import os
13
+ import tempfile
14
+ import time
15
+ import urllib.request
16
+
17
+ CATALOG_URL = "https://openrouter.ai/api/v1/models"
18
+ _CACHE = os.path.join(tempfile.gettempdir(), "javis_models.json")
19
+ _TTL = 86400 # 1 day
20
+
21
+
22
+ def fetch_catalog(force: bool = False) -> list[dict]:
23
+ """Return the OpenRouter model list (cached for a day). Best-effort; needs network."""
24
+ if not force and os.path.isfile(_CACHE) and (time.time() - os.path.getmtime(_CACHE)) < _TTL:
25
+ try:
26
+ with open(_CACHE) as f:
27
+ return json.load(f)
28
+ except (OSError, json.JSONDecodeError):
29
+ pass
30
+ req = urllib.request.Request(CATALOG_URL, headers={"User-Agent": "javis"})
31
+ with urllib.request.urlopen(req, timeout=20) as resp:
32
+ data = json.load(resp)["data"]
33
+ try:
34
+ with open(_CACHE, "w") as f:
35
+ json.dump(data, f)
36
+ except OSError:
37
+ pass
38
+ return data
39
+
40
+
41
+ def _price(model: dict) -> float:
42
+ return float((model.get("pricing") or {}).get("prompt") or 0.0)
43
+
44
+
45
+ def tool_capable(models: list[dict]) -> list[dict]:
46
+ return [m for m in models if "tools" in (m.get("supported_parameters") or [])]
47
+
48
+
49
+ def is_tool_capable(model_id: str, models: list[dict]) -> bool:
50
+ mid = model_id.removeprefix("openrouter/")
51
+ return any(
52
+ m.get("id") == mid and "tools" in (m.get("supported_parameters") or []) for m in models
53
+ )
54
+
55
+
56
+ def cheapest_tool_capable(models: list[dict], n: int = 15) -> list[tuple[float, str]]:
57
+ return sorted((_price(m), m["id"]) for m in tool_capable(models))[:n]
58
+
59
+
60
+ def main() -> None:
61
+ models = fetch_catalog()
62
+ print(f"{len(tool_capable(models))} tool-capable of {len(models)} models\n")
63
+ for price, mid in cheapest_tool_capable(models, 20):
64
+ print(f" ${price * 1e6:7.3f}/Mtok openrouter/{mid}")
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()