@vigent/cli 0.3.1 → 0.3.2

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 CHANGED
@@ -4,7 +4,7 @@ A vim-style, lightweight terminal app for running several coding agents at once,
4
4
 
5
5
  **Website:** [vigent.farming-labs.dev](https://vigent.farming-labs.dev) · **Docs:** [vigent.farming-labs.dev/docs](https://vigent.farming-labs.dev/docs)
6
6
 
7
- ![vigent running a Claude Code agent in its own worktree, with the sessions and engines sidebars](docs/screenshots/showcase.png)
7
+ ![vigent running a Claude Code agent in its own worktree, with the sessions and engines sidebars](https://vigent.farming-labs.dev/showcase.png)
8
8
 
9
9
  ## Install
10
10
 
@@ -97,7 +97,7 @@ Copies go to the system clipboard through the terminal (OSC 52), so they work ov
97
97
 
98
98
  ## Engines: pi, Claude Code, Codex, OpenCode
99
99
 
100
- pi runs inside vigent. Claude Code, Codex and OpenCode are the CLIs you may already use: vigent runs them as installed, in the agent's worktree, so each one uses its own login and settings. vigent never reads their credentials; it only runs their version and sign-in status commands to show what's connected.
100
+ pi runs inside vigent. Claude Code, Codex and OpenCode are the CLIs you may already use: vigent runs them as installed, in the agent's worktree, so each one uses its own login and settings. vigent never reads their credentials; it only runs their version and sign-in status commands to show what's connected. If `ANTHROPIC_API_KEY` is set and Claude Code is also signed in with a Claude account, vigent runs Claude Code without that variable, so it uses your account (a key that isn't scoped to a workspace, or is out of credit, would otherwise fail every request). `:checkhealth` says so: *signed in (Claude account; ANTHROPIC_API_KEY left out)*.
101
101
 
102
102
  ```vim
103
103
  :new fix the race --engine codex " this agent runs Codex
package/dist/app.js CHANGED
@@ -64,6 +64,7 @@ const ICONS = {
64
64
  here: "●",
65
65
  unread: "◆",
66
66
  serve: "⇄ ",
67
+ light: "✦",
67
68
  ok: "●",
68
69
  warn: "◐",
69
70
  off: "○",
@@ -87,6 +88,7 @@ const ICONS = {
87
88
  here: NERD.circle,
88
89
  unread: NERD.bell,
89
90
  serve: "\uf10b ",
91
+ light: "\uf0e7",
90
92
  ok: NERD.check,
91
93
  warn: NERD.warning,
92
94
  off: NERD.circleO,
@@ -110,6 +112,7 @@ const ICONS = {
110
112
  here: "*",
111
113
  unread: "!",
112
114
  serve: "~ ",
115
+ light: "*",
113
116
  ok: "+",
114
117
  warn: "~",
115
118
  off: "-",
@@ -1478,7 +1481,7 @@ export class App {
1478
1481
  this.refreshStorage();
1479
1482
  const by = s.engine !== "pi" ? ` · ${ENGINE_NAMES[s.engine]}` : "";
1480
1483
  if (wt?.path) {
1481
- const how = wt.riftri ? ` · riftri ${wt.riftri}` : wt.riftriSkipped ? " · full copy (riftri declined: :checkhealth)" : "";
1484
+ const how = wt.riftri ? " · lightweight copy" : wt.riftriSkipped ? " · full copy (:checkhealth says why)" : "";
1482
1485
  this.setMessage(`'${name}'${by} on ${wt.branch} in ${this.shortPath(wt.path)}${wt.base ? ` (from ${wt.base})` : ""}${how}`, wt.riftriSkipped ? "WarningMsg" : "ModeMsg");
1483
1486
  }
1484
1487
  else if (wt) {
@@ -2549,7 +2552,7 @@ export class App {
2549
2552
  const s = this.focusedSession;
2550
2553
  const left = s ? ` ${this.icons.open_agent} ${s.name}` : ` ${this.icons.open_agent} [no agent]`;
2551
2554
  const model = s ? ` ${s.engine !== "pi" && s.model !== ENGINE_NAMES[s.engine] ? `${ENGINE_NAMES[s.engine]} · ` : ""}${s.model}${s.effort ? ` · ${s.effort}` : ""}` : "";
2552
- const where = s?.worktree?.path ? `${this.shortPath(s.worktree.path)}${s.worktree.riftri ? " · riftri" : ""}` : s ? "this checkout" : "";
2555
+ const where = s?.worktree?.path ? `${this.shortPath(s.worktree.path)}${s.worktree.riftri ? ` ${this.icons.light}` : ""}` : s ? "this checkout" : "";
2553
2556
  const ext = s && "extensionStatus" in s ? [...s.extensionStatus.values()].join(" · ") : "";
2554
2557
  const status = (s?.state === "paused" ? " paused" : s?.queue.length ? ` ${this.icons.queued}${s.queue.length} queued` : "") + (ext ? ` ${ext}` : "");
2555
2558
  // the path gives way first (from its start: the end names the worktree), always two spaces before it
@@ -321,7 +321,7 @@ export class CliSession extends Session {
321
321
  try {
322
322
  child = spawn(this.opts.bin ?? this.adapter.bin, args, {
323
323
  cwd: this.cwd,
324
- env: this.opts.env ?? process.env,
324
+ env: typeof this.opts.env === "function" ? this.opts.env() : (this.opts.env ?? process.env),
325
325
  stdio: ["ignore", "pipe", "pipe"],
326
326
  });
327
327
  }
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import { App } from "./app.js";
9
9
  import { FOCUS_REPORTING_OFF, FOCUS_REPORTING_ON } from "./notify.js";
10
10
  import { staleBuild, VERSION_TEXT } from "./version.js";
11
11
  import { CliSession } from "./cli-engines.js";
12
- import { defaultEngine, detectEngines, ENGINE_BINS, isEngineId, onPath, piConnected, quickEngines } from "./engines.js";
12
+ import { defaultEngine, detectEngines, ENGINE_BINS, isEngineId, onPath, piConnected, quickEngines, engineEnv } from "./engines.js";
13
13
  import { CONFIG_TEMPLATE, configPath, loadConfig } from "./config.js";
14
14
  import { createDemoSessions } from "./demo.js";
15
15
  import { buildKeymap, KEY_MODES } from "./keys.js";
@@ -306,6 +306,8 @@ async function main() {
306
306
  resumeId,
307
307
  effort,
308
308
  extraArgs: config.engines[engine]?.args,
309
+ // e.g. Claude Code without ANTHROPIC_API_KEY when it has a Claude account (see detectClaude)
310
+ env: () => engineEnv(app.engines?.find((e) => e.id === engine)),
309
311
  onResumeId: (id) => {
310
312
  if (!wt?.path)
311
313
  return;
package/dist/engines.js CHANGED
@@ -12,6 +12,15 @@ import * as os from "node:os";
12
12
  import * as path from "node:path";
13
13
  import { PI_INSTALL, piInstalled } from "./pi-sdk.js";
14
14
  export const ENGINE_IDS = ["pi", "claude", "codex", "opencode"];
15
+ /** The environment to run an engine's CLI with: everything but what detection said to leave out. */
16
+ export function engineEnv(engine, env = process.env) {
17
+ if (!engine?.dropEnv?.length)
18
+ return env;
19
+ const out = { ...env };
20
+ for (const k of engine.dropEnv)
21
+ delete out[k];
22
+ return out;
23
+ }
15
24
  export const ENGINE_NAMES = {
16
25
  pi: "pi",
17
26
  claude: "Claude Code",
@@ -127,8 +136,33 @@ async function detectClaude(env, timeoutMs) {
127
136
  try {
128
137
  const st = JSON.parse(s.stdout);
129
138
  if (st.loggedIn) {
130
- const how = st.authMethod === "api_key" || st.apiKeySource ? "API key" : "Claude account";
131
- return { ...base, installed: true, connected: true, version, detail: `signed in (${how})`, connect: undefined };
139
+ const usesKey = st.authMethod === "api_key" || !!st.apiKeySource;
140
+ // ANTHROPIC_API_KEY wins over a signed-in Claude account. When there is an account too,
141
+ // leave the key out, so Claude Code runs on the login you use it with (an unscoped or
142
+ // spent key otherwise fails every request, e.g. "not scoped to a workspace")
143
+ if (usesKey && env.ANTHROPIC_API_KEY) {
144
+ const without = { ...env };
145
+ delete without.ANTHROPIC_API_KEY;
146
+ const account = await run("claude", ["auth", "status", "--json"], timeoutMs, without);
147
+ try {
148
+ const a = JSON.parse(account.stdout);
149
+ if (a.loggedIn && a.authMethod !== "api_key" && !a.apiKeySource) {
150
+ return {
151
+ ...base,
152
+ installed: true,
153
+ connected: true,
154
+ version,
155
+ detail: "signed in (Claude account; ANTHROPIC_API_KEY left out)",
156
+ connect: undefined,
157
+ dropEnv: ["ANTHROPIC_API_KEY"],
158
+ };
159
+ }
160
+ }
161
+ catch {
162
+ // no account to fall back to: the key it is
163
+ }
164
+ }
165
+ return { ...base, installed: true, connected: true, version, detail: `signed in (${usesKey ? "API key" : "Claude account"})`, connect: undefined };
132
166
  }
133
167
  return { ...base, installed: true, connected: false, version, detail: "not signed in" };
134
168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vigent/cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A vim-style terminal app for running coding agents side by side, each in its own git worktree. Built on pi.",
5
5
  "keywords": [
6
6
  "vim",