bjir-cli 0.1.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.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ <h1 align="center">BJiR</h1>
2
+
3
+ <p align="center">A token-lean AI coding agent for the terminal.</p>
4
+
5
+ <p align="center"><b>One obsession: do the same work for far fewer tokens.</b></p>
6
+
7
+ <p align="center">
8
+ <a href="README.md">English</a> |
9
+ <a href="README.id.md">Bahasa Indonesia</a>
10
+ </p>
11
+
12
+ ---
13
+
14
+ ## What is BJiR?
15
+
16
+ BJiR is an AI coding agent you run in your terminal. It reads and edits code, runs commands, and talks to a model (Claude, GPT, Gemini, MiMo, local models).
17
+
18
+ The difference is token usage. Every request is trimmed, every reply is steered to be terse, and noisy tool output (test logs, big JSON, `git status`) is compressed before it reaches the model. These optimizations are compiled in and always on, so you save without configuring anything. Less context in and less text out means lower cost, faster replies, and longer sessions.
19
+
20
+ ## Install
21
+
22
+ ### npm (recommended)
23
+
24
+ ```bash
25
+ npm i -g bjir # or: bun add -g bjir / pnpm add -g bjir / yarn global add bjir
26
+ bjir # launch
27
+ ```
28
+
29
+ ### From source
30
+
31
+ ```bash
32
+ git clone https://github.com/gogetrekt/bjir
33
+ cd bjir
34
+ bun install
35
+ ./bin/bjir.sh
36
+ ```
37
+
38
+ To run `bjir` from anywhere on a source checkout, symlink it onto your PATH:
39
+
40
+ ```bash
41
+ ln -s "$PWD/bin/bjir.sh" ~/.local/bin/bjir
42
+ ```
43
+
44
+ ### API key
45
+
46
+ BJiR needs a model provider. Launch `bjir`, open the provider dialog, and add one (OpenAI-compatible, Anthropic-compatible, or a preset). Name, base URL, key, and models are saved and persist across restarts.
47
+
48
+ ## Quick start
49
+
50
+ Run `bjir` (just `bjir`) to open the interactive TUI:
51
+
52
+ ```bash
53
+ bjir # open the TUI in the current directory
54
+ bjir /path/to/project # open the TUI in a specific project
55
+ bjir run "summarize today's changes" # one-shot, non-interactive
56
+ bjir gain # show tokens saved
57
+ ```
58
+
59
+ In the TUI: type to chat, press `Tab` to switch between the build agent (full access) and the plan agent (read-only), run `/reducer` to change optimization intensity, and watch the sidebar for a live tokens-saved counter.
60
+
61
+ ## Optimizations
62
+
63
+ Built into the binary, always on. Nothing to configure.
64
+
65
+ | Optimization | What it does |
66
+ | --- | --- |
67
+ | Ponytail | Code-minimalism rules. The agent writes the smallest correct change, so replies and diffs stay small. |
68
+ | Caveman | Response-style rules that make the model answer tersely. The biggest cut to output tokens. Three intensity levels (see `/reducer`). |
69
+ | I/O Refiner | Trims the assembled prompt right before it is sent, cutting input tokens. |
70
+ | Context Prune | Drops stale history each turn so old context stops costing tokens. |
71
+ | Read Dedup | Skips re-sending a file that was already read. |
72
+ | Semantic Read | Returns only the relevant parts of a file when that is enough. |
73
+ | Tool-output compression | Big tool results are compressed by type: SmartCrusher for large JSON, Log Compressor for build and shell logs, and CCR, which stashes the full output and lets the agent pull back any part on demand. Lossless or skipped. |
74
+ | RTK | Wraps shell commands (`git`, `cargo`, `npm`, `bun`, `docker`) so their output is compressed before the agent sees it. |
75
+ | BJiR Gateway | A local OpenAI-compatible gateway that routes across providers with automatic fallback and meters token usage. |
76
+
77
+ ### Intensity
78
+
79
+ Caveman has three levels: `lite`, `standard`, `ultra`. Switch live in the TUI with `/reducer` (also `/caveman`, `/ponytail`); it applies on your next message. From the CLI, `bjir profile [explain|balanced|ultra]` sets a persistent profile. Set `BJIR_OPTIMIZE=0` to turn the layer off.
80
+
81
+ ## Savings
82
+
83
+ ```bash
84
+ bjir gain # ranked table of tokens saved
85
+ bjir gain --json # machine-readable
86
+ bjir gain --reset # clear history
87
+ ```
88
+
89
+ Numbers come from real session data. The TUI sidebar shows a running total.
90
+
91
+ ## Commands
92
+
93
+ Run `bjir <command> --help` for options.
94
+
95
+ | Command | Description |
96
+ | --- | --- |
97
+ | `bjir` | Launch the interactive TUI (default). |
98
+ | `bjir run "<prompt>"` | One-shot, non-interactive run. |
99
+ | `bjir serve` | Run the headless HTTP API server. |
100
+ | `bjir attach` | Connect to a running server. |
101
+ | `bjir gain` | Show the token-savings summary. |
102
+ | `bjir compress` | Caveman-compress memory files (`CLAUDE.md`, `AGENTS.md`, `.opencode/memory.md`). |
103
+ | `bjir profile [name]` | Show or switch the optimization profile. |
104
+ | `bjir gateway` | Start the BJiR Gateway (usually automatic). |
105
+ | `bjir models` | List available models. |
106
+ | `bjir providers` | Manage providers and credentials. |
107
+ | `bjir revoke [id]` | Remove a connected provider. |
108
+ | `bjir agent` | Create and manage agents. |
109
+ | `bjir mcp` | Manage MCP servers. |
110
+ | `bjir github` | Set up and run the GitHub agent. |
111
+ | `bjir upgrade` | Update to the latest version. |
112
+ | `bjir uninstall` | Uninstall BJiR. |
113
+
114
+ ## Configuration
115
+
116
+ BJiR reads config from `~/.config/opencode/opencode.json` (seeded on first run) and a project-local `opencode.json` or `.opencode/opencode.json`. Providers added through the connect dialog are written here. Built-in optimizations are not config; tune them with `/reducer`, `bjir profile`, and `BJIR_*` environment variables.
117
+
118
+ ## Agents
119
+
120
+ Switch with `Tab`:
121
+
122
+ - build: full-access agent for writing and changing code.
123
+ - plan: read-only, denies edits and asks before running commands.
124
+
125
+ Invoke the general subagent for complex searches with `@general`.
126
+
127
+ ## License
128
+
129
+ MIT. BJiR is a fork of [opencode](https://github.com/anomalyco/opencode) and is not affiliated with or endorsed by the opencode team.
package/bin/bjir.cjs ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ // bjir launcher — find binary, start gateway if needed, run agent.
3
+ const childProcess = require("child_process")
4
+ const fs = require("fs")
5
+ const path = require("path")
6
+ const os = require("os")
7
+ const http = require("http")
8
+
9
+ const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
10
+ const archMap = { x64: "x64", arm64: "arm64", arm: "arm" }
11
+ const platform = platformMap[os.platform()] || os.platform()
12
+ const arch = archMap[os.arch()] || os.arch()
13
+ const base = "bjir-" + platform + "-" + arch
14
+ const binName = platform === "windows" ? "bjir.exe" : "bjir"
15
+ const names = [base, base + "-baseline", base + "-musl", base + "-baseline-musl"]
16
+
17
+ function findBinary(startDir) {
18
+ let current = startDir
19
+ for (;;) {
20
+ const modules = path.join(current, "node_modules")
21
+ if (fs.existsSync(modules)) {
22
+ for (const name of names) {
23
+ const candidate = path.join(modules, name, "bin", binName)
24
+ if (fs.existsSync(candidate)) return candidate
25
+ }
26
+ }
27
+ const parent = path.dirname(current)
28
+ if (parent === current) return
29
+ current = parent
30
+ }
31
+ }
32
+
33
+ const binary = process.env.BJIR_BIN_PATH || findBinary(path.dirname(fs.realpathSync(__filename)))
34
+ if (!binary) {
35
+ console.error("bjir: could not find the platform binary (" + names.join(" / ") + "). Reinstall `bjir`.")
36
+ process.exit(1)
37
+ }
38
+
39
+ const PORT = Number(process.env.BJIR_GATEWAY_PORT || 9090)
40
+ const args = process.argv.slice(2)
41
+
42
+ // `bjir gateway ...` -> run the gateway directly (no wrapper orchestration).
43
+ if (args[0] === "gateway") {
44
+ childProcess.spawn(binary, args, { stdio: "inherit" }).on("exit", (c) => process.exit(c || 0))
45
+ return
46
+ }
47
+
48
+ // Ensure a default config exists (never clobber an existing one).
49
+ try {
50
+ const cfgDir = path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config"), "opencode")
51
+ const cfg = path.join(cfgDir, "opencode.json")
52
+ const def = path.join(__dirname, "..", "share", "opencode.json")
53
+ if (!fs.existsSync(cfg) && fs.existsSync(def)) {
54
+ fs.mkdirSync(cfgDir, { recursive: true })
55
+ fs.copyFileSync(def, cfg)
56
+ }
57
+ } catch {}
58
+
59
+ function health(cb) {
60
+ const req = http.get({ host: "localhost", port: PORT, path: "/health", timeout: 500 }, (res) => {
61
+ res.resume()
62
+ cb(res.statusCode === 200)
63
+ })
64
+ req.on("error", () => cb(false))
65
+ req.on("timeout", () => {
66
+ req.destroy()
67
+ cb(false)
68
+ })
69
+ }
70
+
71
+ function startAgent(routerProc) {
72
+ // Bare launch (no subcommand) -> open the TUI in the user's cwd.
73
+ const passed = args.length === 0 ? [process.cwd()] : args
74
+ const child = childProcess.spawn(binary, passed, { stdio: "inherit" })
75
+ const cleanup = () => {
76
+ if (routerProc) try { routerProc.kill() } catch {}
77
+ }
78
+ for (const s of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(s, () => { try { child.kill(s) } catch {} })
79
+ child.on("exit", (code, signal) => {
80
+ cleanup()
81
+ if (signal) return process.kill(process.pid, signal)
82
+ process.exit(typeof code === "number" ? code : 0)
83
+ })
84
+ }
85
+
86
+ health((up) => {
87
+ if (up) return startAgent(null)
88
+ const router = childProcess.spawn(binary, ["gateway"], { stdio: "ignore", detached: false })
89
+ let waited = 0
90
+ const tick = () =>
91
+ health((ok) => {
92
+ if (ok || waited >= 6000) return startAgent(router)
93
+ waited += 250
94
+ setTimeout(tick, 250)
95
+ })
96
+ setTimeout(tick, 250)
97
+ })
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "bjir-cli",
3
+ "version": "0.1.0",
4
+ "description": "BJiR: Bloat Judgement & I/O Refiner, a token-lean AI coding agent for the terminal.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/gogetrekt/bjir",
7
+ "repository": { "type": "git", "url": "git+https://github.com/gogetrekt/bjir.git" },
8
+ "keywords": ["ai", "agent", "cli", "tui", "coding", "tokens", "llm", "terminal"],
9
+ "bin": { "bjir": "./bin/bjir.cjs" },
10
+ "files": ["bin", "scripts", "share", "vendor"],
11
+ "scripts": { "postinstall": "node scripts/postinstall.cjs" },
12
+ "optionalDependencies": {
13
+ "bjir-linux-x64": "0.1.0",
14
+ "bjir-linux-x64-baseline": "0.1.0",
15
+ "bjir-linux-x64-musl": "0.1.0",
16
+ "bjir-linux-x64-baseline-musl": "0.1.0",
17
+ "bjir-linux-arm64": "0.1.0",
18
+ "bjir-linux-arm64-musl": "0.1.0",
19
+ "bjir-darwin-arm64": "0.1.0",
20
+ "bjir-darwin-x64": "0.1.0",
21
+ "bjir-darwin-x64-baseline": "0.1.0",
22
+ "bjir-windows-x64": "0.1.0",
23
+ "bjir-windows-x64-baseline": "0.1.0",
24
+ "bjir-windows-arm64": "0.1.0"
25
+ },
26
+ "preferUnplugged": true
27
+ }
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bjir postinstall — copy the matching rtk binary to ~/.bjir/bin/rtk so the bash
4
+ * tool finds it (shell-output compression). Best-effort: never fails install.
5
+ * The default opencode config is written on first run by the launcher.
6
+ */
7
+ const fs = require("fs")
8
+ const path = require("path")
9
+ const os = require("os")
10
+
11
+ try {
12
+ const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
13
+ const platform = platformMap[os.platform()] || os.platform()
14
+ const arch = os.arch() === "arm64" ? "arm64" : "x64"
15
+ const ext = platform === "windows" ? ".exe" : ""
16
+ const src = path.join(__dirname, "..", "vendor", "rtk", `rtk-${platform}-${arch}${ext}`)
17
+ if (!fs.existsSync(src)) {
18
+ console.warn(`[bjir] no bundled rtk for ${platform}-${arch}; shell compression disabled until rtk is on PATH`)
19
+ return
20
+ }
21
+ const destDir = path.join(os.homedir(), ".bjir", "bin")
22
+ const dest = path.join(destDir, `rtk${ext}`)
23
+ fs.mkdirSync(destDir, { recursive: true })
24
+ fs.copyFileSync(src, dest)
25
+ if (platform !== "windows") fs.chmodSync(dest, 0o755)
26
+ console.log(`[bjir] rtk installed -> ${dest}`)
27
+ } catch (e) {
28
+ console.warn(`[bjir] postinstall skipped: ${e && e.message ? e.message : e}`)
29
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "provider": {
4
+ "bjir-gw": {
5
+ "npm": "@ai-sdk/openai-compatible",
6
+ "name": "BJiR Gateway",
7
+ "options": { "baseURL": "http://localhost:9090/v1", "apiKey": "local" },
8
+ "models": {
9
+ "auto": { "name": "auto" },
10
+ "claude-sonnet-4-6": { "name": "Claude Sonnet 4.6" },
11
+ "gpt-4o": { "name": "GPT-4o" },
12
+ "gemini/gemini-2.0-flash": { "name": "Gemini 2.0 Flash" },
13
+ "ollama:qwen2.5-coder": { "name": "Qwen2.5 Coder (Ollama)" }
14
+ }
15
+ }
16
+ },
17
+ "model": "bjir-gw/auto",
18
+ "lsp": true,
19
+ "reducer": "standard"
20
+ }
Binary file