codemax-cli 0.1.4 → 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.
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/adapters/detect.ts +38 -9
- package/src/adapters/index.ts +2 -2
- package/src/adapters/simple.ts +7 -6
- package/src/adapters/types.ts +3 -1
- package/src/chat/app.ts +374 -123
- package/src/chat/models.ts +25 -0
- package/src/chat/notes.ts +101 -0
- package/src/chat/palette.ts +14 -1
- package/src/chat/question.ts +192 -0
- package/src/chat/subagents.ts +107 -0
- package/src/cli.ts +2 -1
- package/src/config.ts +17 -4
- package/src/core/termstatus.ts +124 -0
- package/src/core/usage.ts +4 -2
- package/src/engines/acp.ts +123 -10
- package/src/engines/antigravity.ts +95 -0
- package/src/engines/codex.ts +69 -28
- package/src/engines/elicitation.ts +60 -0
- package/src/engines/index.ts +6 -3
- package/src/engines/types.ts +45 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<p align="center"><b>Every AI coding plan you pay for. One terminal.</b></p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
Claude Code · Codex · OpenCode · Grok · Cursor ·
|
|
8
|
+
Claude Code · Codex · OpenCode · Grok · Cursor · Antigravity CLI
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -79,21 +79,21 @@ cd codemax-cli && bun install && bun link
|
|
|
79
79
|
| OpenCode | Your OpenCode login | Supported |
|
|
80
80
|
| Grok | SuperGrok | Supported |
|
|
81
81
|
| Cursor Agent | Cursor plans | Supported (needs Cursor Agent 2026.10 or newer). Changing its model with `/model` also changes Cursor's own default. |
|
|
82
|
-
|
|
|
82
|
+
| Antigravity CLI | Google AI plans | Supported. It has no ACP mode of its own, so codemax offers to download Google's official ACP server for it (about 110 MB, once, from dl.google.com) the first time you switch to it, and signs in with your Google account (a browser may open once). It reports context size but not token counts, so `/usage` shows input only. |
|
|
83
83
|
| Copilot CLI | GitHub Copilot plans | In its own UI via `codemax --tui` |
|
|
84
84
|
|
|
85
85
|
## Everyday keys
|
|
86
86
|
|
|
87
87
|
| | |
|
|
88
88
|
|---|---|
|
|
89
|
+
| **↑** on an empty prompt | Edit a queued message (↑ again for the one before); Enter puts it back, clear it and Enter to remove it, Esc leaves it as it was |
|
|
89
90
|
| `/switch` or **Ctrl+^** | Move to another agent, conversation included |
|
|
90
91
|
| `/ask codex <msg>` | One question to another agent |
|
|
91
92
|
| `@file` | Attach a file to your message |
|
|
92
93
|
| `/task` | The shared task: plan, who did what, where it stopped, files changed |
|
|
93
94
|
| `/update` | Update codemax when a new version is out (also `codemax update`) |
|
|
94
95
|
| `/config` | Every setting in one panel: theme, keep awake, side agent and its model, handoffs, snapshots… |
|
|
95
|
-
|
|
|
96
|
-
| `/forward`, `/notes`, `/review` | Send the side agent's note to the main agent; list notes; ask for a review now. How often it reviews is in `/config`; each review uses the side agent's plan, so a different subscription than the main agent is best |
|
|
96
|
+
| Side agent | Turn it on in `/config` and pick its agent and model. It reviews the work in the background and speaks up only when something needs attention: its note waits above the prompt, where **1** expands it, **2** sends it to the main agent to discuss, **0** dismisses it. It never uses the main agent's plan unless you allow that in `/config` |
|
|
97
97
|
| `/awake on`, `/awake lid` | Keep the machine from sleeping while agents work; `lid` also with the lid closed |
|
|
98
98
|
| `/undo` | Revert the last turn's changes |
|
|
99
99
|
| `/usage`, `/budget` | Usage and spend per agent |
|
|
@@ -111,7 +111,7 @@ cd codemax-cli && bun install && bun link
|
|
|
111
111
|
|
|
112
112
|
| Key | Default | What it does |
|
|
113
113
|
|---|---|---|
|
|
114
|
-
| `order` | `["claude", "codex", "opencode", "cursor", "grok", "
|
|
114
|
+
| `order` | `["claude", "codex", "opencode", "cursor", "grok", "antigravity", "copilot"]` | Which agent comes next on a handoff |
|
|
115
115
|
| `budgets` | `{}` | Daily limit per agent, e.g. `{"claude": 20, "all": 50}` |
|
|
116
116
|
| `routes` | `[]` | Send matching messages to a specific agent |
|
|
117
117
|
| `checkpoints` | `true` | Snapshots for `/undo` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codemax-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "One terminal for every coding agent you pay for: drive Claude Code, Codex, OpenCode, Grok and Gemini CLI from one chat, on your subscriptions, with context that survives switching agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acp",
|
package/src/adapters/detect.ts
CHANGED
|
@@ -1,16 +1,45 @@
|
|
|
1
1
|
import type { DetectResult } from "./types.ts";
|
|
2
2
|
import { platformArgv } from "../core/spawn.ts";
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
|
|
4
|
+
export interface DetectDeps {
|
|
5
|
+
which: (bin: string) => string | null;
|
|
6
|
+
run: (argv: string[], timeoutMs: number) => Promise<{ code: number | null; out: string; timedOut?: boolean }>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const defaultDeps: DetectDeps = {
|
|
10
|
+
which: (b) => Bun.which(b),
|
|
11
|
+
run: async (argv, timeoutMs) => {
|
|
12
|
+
const p = Bun.spawn(platformArgv(argv), { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
|
|
13
|
+
let timedOut = false;
|
|
14
|
+
const timer = setTimeout(() => {
|
|
15
|
+
timedOut = true;
|
|
16
|
+
p.kill();
|
|
17
|
+
}, timeoutMs);
|
|
18
|
+
const [out, err] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]);
|
|
19
|
+
const code = await p.exited;
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
return { code, out: `${out}\n${err}`.trim(), timedOut };
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An agent counts as installed only when its CLI actually runs: `<bin> --version`
|
|
27
|
+
* must exit 0. A file on PATH alone is not enough; on Windows an uninstalled npm
|
|
28
|
+
* CLI can leave shims behind that no longer start, and those must not be offered.
|
|
29
|
+
*/
|
|
30
|
+
export async function detectBin(bin: string, versionArgs: string[] = ["--version"], deps: DetectDeps = defaultDeps, timeoutMs = 15000): Promise<DetectResult> {
|
|
31
|
+
const path = deps.which(bin);
|
|
6
32
|
if (!path) return { installed: false };
|
|
7
33
|
try {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
return { installed:
|
|
13
|
-
|
|
14
|
-
|
|
34
|
+
const r = await deps.run([path, ...versionArgs], timeoutMs);
|
|
35
|
+
const lines = r.out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
36
|
+
// Node prints a stack location first; the line naming the error is the useful one.
|
|
37
|
+
const first = lines.find((l) => /error|not found|cannot|denied/i.test(l)) ?? lines[0] ?? "";
|
|
38
|
+
if (r.timedOut) return { installed: false, path, problem: `${bin} was found at ${path} but did not answer ${versionArgs.join(" ")} within ${Math.round(timeoutMs / 1000)}s` };
|
|
39
|
+
if (r.code !== 0) return { installed: false, path, problem: `${bin} was found at ${path} but does not run${first ? `: ${first.slice(0, 160)}` : ` (exit ${r.code})`}` };
|
|
40
|
+
const m = r.out.match(/\d+\.\d+(\.\d+)?/);
|
|
41
|
+
return { installed: true, path, version: m?.[0] ?? first };
|
|
42
|
+
} catch (e: any) {
|
|
43
|
+
return { installed: false, path, problem: `${bin} was found at ${path} but could not be started: ${String(e?.message ?? e).slice(0, 160)}` };
|
|
15
44
|
}
|
|
16
45
|
}
|
package/src/adapters/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Adapter, AgentId } from "./types.ts";
|
|
2
2
|
import { claude } from "./claude.ts";
|
|
3
3
|
import { codex } from "./codex.ts";
|
|
4
|
-
import { opencode, cursor, grok,
|
|
4
|
+
import { opencode, cursor, grok, antigravity, copilot, fake } from "./simple.ts";
|
|
5
5
|
|
|
6
|
-
const real: Adapter[] = [claude, codex, opencode, cursor, grok,
|
|
6
|
+
const real: Adapter[] = [claude, codex, opencode, cursor, grok, antigravity, copilot];
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The adapters, read at call time: tests set CODEMAX_FAKE_AGENT after another
|
package/src/adapters/simple.ts
CHANGED
|
@@ -63,12 +63,13 @@ export const grok = simple({
|
|
|
63
63
|
apiKeyEnv: ["XAI_API_KEY", "GROK_API_KEY"],
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
/** Google's coding agent for Google AI plans (Antigravity CLI replaced Gemini CLI). */
|
|
67
|
+
export const antigravity = simple({
|
|
68
|
+
id: "antigravity",
|
|
69
|
+
name: "Antigravity CLI",
|
|
70
|
+
bin: "agy",
|
|
71
|
+
resumeArgs: (id) => ["--conversation", id],
|
|
72
|
+
patterns: [/quota exceeded/i, /RESOURCE_EXHAUSTED/, /rate limit/i, /usage limit/i],
|
|
72
73
|
apiKeyEnv: ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
|
|
73
74
|
});
|
|
74
75
|
|
package/src/adapters/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type AgentId = "claude" | "codex" | "opencode" | "cursor" | "grok" | "
|
|
1
|
+
export type AgentId = "claude" | "codex" | "opencode" | "cursor" | "grok" | "antigravity" | "copilot" | "fake";
|
|
2
2
|
|
|
3
3
|
export interface SessionRef {
|
|
4
4
|
agent: AgentId;
|
|
@@ -60,6 +60,8 @@ export interface DetectResult {
|
|
|
60
60
|
installed: boolean;
|
|
61
61
|
path?: string;
|
|
62
62
|
version?: string;
|
|
63
|
+
/** Why a CLI found on PATH does not count as installed (it failed to run). */
|
|
64
|
+
problem?: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
export interface Adapter {
|