overlord-cli 4.19.0 → 4.21.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.
@@ -22,8 +22,7 @@ const LOCAL_SECRET_HEADER = 'X-Overlord-Local-Secret';
22
22
  * refresh_token?: string,
23
23
  * organization_id?: number | null,
24
24
  * platform_url: string,
25
- * user_email?: string,
26
- * legacy_agent_token?: string
25
+ * user_email?: string
27
26
  * }} Credentials
28
27
  */
29
28
 
@@ -80,10 +79,9 @@ function parseStoredCredentialsData(parsed, { requireAuthData = false } = {}) {
80
79
  typeof parsed.organization_id === 'number' && Number.isFinite(parsed.organization_id)
81
80
  ? parsed.organization_id
82
81
  : null;
83
- const legacyAgentToken = accessToken && !refreshToken ? accessToken : '';
84
82
 
85
83
  if (!platformUrl) return null;
86
- if (requireAuthData && !refreshToken && !legacyAgentToken) return null;
84
+ if (requireAuthData && !refreshToken) return null;
87
85
 
88
86
  return {
89
87
  platform_url: platformUrl,
@@ -93,8 +91,7 @@ function parseStoredCredentialsData(parsed, { requireAuthData = false } = {}) {
93
91
  ...(organizationId ? { organization_id: organizationId } : {}),
94
92
  ...(typeof parsed.user_email === 'string' && parsed.user_email.trim()
95
93
  ? { user_email: parsed.user_email.trim() }
96
- : {}),
97
- ...(legacyAgentToken ? { legacy_agent_token: legacyAgentToken } : {})
94
+ : {})
98
95
  };
99
96
  }
100
97
 
@@ -151,7 +148,6 @@ export function saveCredentials(data) {
151
148
  }
152
149
  if (credentials.organization_id) electronPayload.organization_id = credentials.organization_id;
153
150
  if (credentials.user_email) electronPayload.user_email = credentials.user_email;
154
- delete electronPayload.legacy_agent_token;
155
151
  delete electronPayload.supabase_refresh_token;
156
152
  writeJsonFileAtomic(ELECTRON_CREDENTIALS_FILE, electronPayload);
157
153
  }
@@ -465,17 +461,23 @@ export async function resolveAuth() {
465
461
  ? runtime.local_secret
466
462
  : '';
467
463
 
468
- const envAgentToken = normalizeAgentToken(process.env.AGENT_TOKEN);
469
- if (envAgentToken) {
464
+ const envAccessToken = normalizeAccessToken(process.env.OVERLORD_ACCESS_TOKEN);
465
+ if (envAccessToken) {
466
+ const envOrganizationId =
467
+ typeof process.env.OVERLORD_ORGANIZATION_ID === 'string'
468
+ ? Number.parseInt(process.env.OVERLORD_ORGANIZATION_ID, 10)
469
+ : null;
470
+ if (!Number.isFinite(envOrganizationId)) {
471
+ throw new Error(
472
+ 'OVERLORD_ACCESS_TOKEN requires OVERLORD_ORGANIZATION_ID so protocol requests stay scoped.'
473
+ );
474
+ }
470
475
  return {
471
476
  platformUrl,
472
- bearerToken: envAgentToken,
477
+ bearerToken: envAccessToken,
473
478
  localSecret,
474
- organizationId:
475
- typeof process.env.OVERLORD_ORGANIZATION_ID === 'string'
476
- ? Number.parseInt(process.env.OVERLORD_ORGANIZATION_ID, 10)
477
- : null,
478
- authMode: 'legacy_agent_token'
479
+ organizationId: envOrganizationId,
480
+ authMode: 'oauth_env'
479
481
  };
480
482
  }
481
483
 
@@ -525,16 +527,6 @@ export async function resolveAuth() {
525
527
  };
526
528
  }
527
529
 
528
- if (creds.legacy_agent_token) {
529
- return {
530
- platformUrl,
531
- bearerToken: creds.legacy_agent_token,
532
- localSecret,
533
- organizationId: creds.organization_id ?? null,
534
- authMode: 'legacy_agent_token'
535
- };
536
- }
537
-
538
530
  return {
539
531
  platformUrl,
540
532
  bearerToken: 'overlord-local-dev-token',
@@ -564,12 +556,10 @@ export async function getAuthStatus() {
564
556
  }
565
557
 
566
558
  let tokenSource = 'fallback';
567
- if (normalizeAgentToken(process.env.AGENT_TOKEN)) {
568
- tokenSource = 'AGENT_TOKEN';
559
+ if (normalizeAccessToken(process.env.OVERLORD_ACCESS_TOKEN)) {
560
+ tokenSource = 'OVERLORD_ACCESS_TOKEN';
569
561
  } else if (creds?.refresh_token) {
570
562
  tokenSource = getCredentialFileSource();
571
- } else if (creds?.legacy_agent_token) {
572
- tokenSource = `${getCredentialFileSource()} (legacy)`;
573
563
  }
574
564
 
575
565
  let platformUrlSource = 'default';
@@ -613,7 +603,7 @@ export function repairCredentials() {
613
603
  };
614
604
  }
615
605
 
616
- function normalizeAgentToken(value) {
606
+ function normalizeAccessToken(value) {
617
607
  if (typeof value !== 'string') return '';
618
608
  return value.trim();
619
609
  }
@@ -173,8 +173,31 @@ async function runAgent(agent, mode = 'run') {
173
173
  } else {
174
174
  execFileSync('opencode', ['--prompt', context], { stdio: 'inherit', env: childEnv });
175
175
  }
176
- } else {
177
- execFileSync('gemini', [context], { stdio: 'inherit', env: childEnv });
176
+ } else if (agent === 'gemini') {
177
+ // Write context to a temp file. Passing inline content as a positional arg
178
+ // causes Gemini's @-reference parser to lstat(cwd + content) when it encounters
179
+ // @ symbols in the markdown (e.g. "@@ -10,6 +10,14 @@" in JSON hunk examples),
180
+ // producing an ENAMETOOLONG crash. Using @file keeps the path short.
181
+ const tag = `overlord-${ticketId.slice(-8)}-${Date.now()}`;
182
+ const contextFile = path.join(os.tmpdir(), `${tag}-ctx.md`);
183
+ fs.writeFileSync(contextFile, context, 'utf-8');
184
+ setTimeout(() => { try { fs.unlinkSync(contextFile); } catch { /* already gone */ } }, 30 * 60_000).unref();
185
+
186
+ if (mode === 'resume') {
187
+ const geminiSessionId = process.env.GEMINI_SESSION_ID?.trim();
188
+ const resumeTarget = geminiSessionId ?? 'latest';
189
+ execFileSync(
190
+ 'gemini',
191
+ ['--resume', resumeTarget, '--include-directories', os.tmpdir(), `@${contextFile}`],
192
+ { stdio: 'inherit', env: childEnv }
193
+ );
194
+ } else {
195
+ execFileSync(
196
+ 'gemini',
197
+ ['--include-directories', os.tmpdir(), `@${contextFile}`],
198
+ { stdio: 'inherit', env: childEnv }
199
+ );
200
+ }
178
201
  }
179
202
  } catch (error) {
180
203
  const isResume = mode === 'resume';
@@ -1280,7 +1280,7 @@ Subcommands:
1280
1280
  Environment fallback:
1281
1281
  --session-key <- SESSION_KEY
1282
1282
  --ticket-id <- TICKET_ID
1283
- auth/host <- OVERLORD_URL, optional legacy AGENT_TOKEN, or shared OAuth credentials from ovld auth/Desktop login
1283
+ auth/host <- OVERLORD_URL, optional OVERLORD_ACCESS_TOKEN + OVERLORD_ORGANIZATION_ID, or shared OAuth credentials from ovld auth/Desktop login
1284
1284
  --timeout <- OVERLORD_TIMEOUT
1285
1285
 
1286
1286
  Common flags:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "4.19.0",
3
+ "version": "4.21.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,7 +7,7 @@ Claude Code plugin that exposes the Overlord local ticket workflow to any Claude
7
7
  - `skills/overlord-ticket/SKILL.md` — durable attach → update → ask → deliver workflow.
8
8
  - `commands/{connect,load,create,spawn}.md` — slash commands for session routing and ticket creation.
9
9
  - `hooks/hooks.json` + `scripts/permission-hook.sh` — PermissionRequest notifier that calls `ovld protocol permission-request`.
10
- - `userConfig` for legacy `overlord_url` and `agent_token` installs. Current installs should authenticate with `ovld auth login` or Overlord Desktop; env vars remain optional overrides for remote shells, CI, and explicit token injection.
10
+ - `userConfig` for `overlord_url`. Current installs should authenticate with `ovld auth login` or Overlord Desktop; env vars remain optional overrides for remote shells, CI, and explicit OAuth token injection.
11
11
 
12
12
  ## Requirements
13
13
 
@@ -29,7 +29,7 @@ claude plugin marketplace add cooperativ/overlord-marketplace
29
29
  claude plugin install overlord@cooperativ
30
30
  ```
31
31
 
32
- Older plugin versions prompted for `overlord_url` and `agent_token` at install time. The current hook goes through `ovld protocol`, so the CLI resolves auth from env vars or the shared `~/.ovld` credentials written by CLI/Desktop login.
32
+ Older plugin versions prompted for `overlord_url` and a legacy token at install time. The current hook goes through `ovld protocol`, so the CLI resolves auth from env vars or the shared `~/.ovld` credentials written by CLI/Desktop login.
33
33
 
34
34
  ## Namespaced components
35
35
 
@@ -2,12 +2,12 @@
2
2
  # Overlord PermissionRequest notification hook (plugin-managed).
3
3
  #
4
4
  # Prefers plugin userConfig values (CLAUDE_PLUGIN_OPTION_*) when set, and falls
5
- # back to the raw OVERLORD_URL / AGENT_TOKEN env vars Overlord-launched shells
6
- # already export. Silently no-ops if we can't authenticate — the hook must
5
+ # back to the raw OVERLORD_URL / OVERLORD_ACCESS_TOKEN env vars Overlord-launched
6
+ # shells already export. Silently no-ops if we can't authenticate — the hook must
7
7
  # never block the user or leak errors into the Claude session.
8
8
  BODY=$(cat -)
9
9
  OVERLORD_BASE_URL="${CLAUDE_PLUGIN_OPTION_OVERLORD_URL:-$OVERLORD_URL}"
10
- OVERLORD_TOKEN="${CLAUDE_PLUGIN_OPTION_AGENT_TOKEN:-$AGENT_TOKEN}"
10
+ OVERLORD_TOKEN="${CLAUDE_PLUGIN_OPTION_OVERLORD_ACCESS_TOKEN:-$OVERLORD_ACCESS_TOKEN}"
11
11
  if [ -n "$OVERLORD_BASE_URL" ] && [ -n "$OVERLORD_TOKEN" ] && [ -n "$TICKET_ID" ]; then
12
12
  curl -sf -m 5 \
13
13
  -X POST "$OVERLORD_BASE_URL/api/protocol/permission-request?ticketId=$TICKET_ID" \
@@ -14,7 +14,7 @@ personal marketplace entry at `~/.agents/plugins/marketplace.json`.
14
14
  ## Requirements
15
15
 
16
16
  - Install the Overlord CLI so `ovld` is available on `PATH`.
17
- - Authenticate with `ovld auth login` or Overlord Desktop. `OVERLORD_URL` and `AGENT_TOKEN` are optional overrides, mainly for remote shells, CI, or explicit token injection.
17
+ - Authenticate with `ovld auth login` or Overlord Desktop. `OVERLORD_URL` can be used to point the CLI at a non-default host.
18
18
  - Optionally set `OVLD_BIN` if the CLI lives at a non-standard path.
19
19
 
20
20
  ## Tool coverage