overlord-cli 4.23.0 → 5.0.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/bin/_cli/auth.mjs CHANGED
@@ -556,10 +556,13 @@ async function printVerboseAuthStatus() {
556
556
  console.log(` Error: ${status.error}`);
557
557
  }
558
558
  console.log(` Local secret: ${status.hasLocalSecret ? 'yes' : 'no'}`);
559
- console.log(` credentials.json: ${status.credentialsFileExists ? 'present' : 'missing'}`);
560
- console.log(
561
- ` electron-credentials.json: ${status.electronCredentialsFileExists ? 'present' : 'missing'}`
562
- );
559
+ console.log(` credentials.cli.json: ${status.credentialsFileExists ? 'present' : 'missing'}`);
560
+ if (status.legacyCredentialsFileExists) {
561
+ console.log(` credentials.json (legacy): present`);
562
+ }
563
+ if (status.electronCredentialsFileExists) {
564
+ console.log(` electron-credentials.json (legacy): present`);
565
+ }
563
566
  }
564
567
 
565
568
  export async function authStatus(args = []) {
@@ -8,8 +8,10 @@ import path from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
 
10
10
  const CREDENTIALS_DIR = path.join(os.homedir(), '.ovld');
11
- const CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'credentials.json');
12
- const ELECTRON_CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'electron-credentials.json');
11
+ const CLI_CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'credentials.cli.json');
12
+ const LEGACY_CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'credentials.json');
13
+ const LEGACY_ELECTRON_CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'electron-credentials.json');
14
+ const LEGACY_MIGRATION_MARKER = path.join(CREDENTIALS_DIR, '.cli-migrated');
13
15
  const RUNTIME_FILE_PATTERN = /^runtime\..+\.json$/;
14
16
  const HOSTED_OVERLORD_URL = 'https://www.ovld.ai';
15
17
  const LOCAL_DEV_OVERLORD_URL = 'http://localhost:3000';
@@ -114,18 +116,39 @@ function normalizeCredentialsForSave(data) {
114
116
  };
115
117
  }
116
118
 
117
- /** @returns {Credentials | null} */
118
- export function loadCredentials() {
119
- const cliCredentials = parseStoredCredentialsData(readJsonFile(CREDENTIALS_FILE), {
119
+ function migrateLegacyCredentials() {
120
+ if (fileExists(LEGACY_MIGRATION_MARKER)) return null;
121
+
122
+ const legacyShared = parseStoredCredentialsData(readJsonFile(LEGACY_CREDENTIALS_FILE), {
120
123
  requireAuthData: true
121
124
  });
122
- const electronCredentials = parseStoredCredentialsData(readJsonFile(ELECTRON_CREDENTIALS_FILE), {
125
+ const legacyElectron = parseStoredCredentialsData(readJsonFile(LEGACY_ELECTRON_CREDENTIALS_FILE), {
126
+ requireAuthData: true
127
+ });
128
+
129
+ const source = legacyShared ?? legacyElectron;
130
+ if (!source) return null;
131
+
132
+ try {
133
+ writeJsonFileAtomic(CLI_CREDENTIALS_FILE, { ...source, updated_at: new Date().toISOString() });
134
+ ensureCredentialsDir();
135
+ fs.writeFileSync(LEGACY_MIGRATION_MARKER, new Date().toISOString(), { mode: 0o600 });
136
+ } catch {
137
+ // Best-effort migration
138
+ }
139
+
140
+ return source;
141
+ }
142
+
143
+ /** @returns {Credentials | null} */
144
+ export function loadCredentials() {
145
+ const cliCredentials = parseStoredCredentialsData(readJsonFile(CLI_CREDENTIALS_FILE), {
123
146
  requireAuthData: true
124
147
  });
125
148
 
126
149
  if (cliCredentials?.refresh_token) return cliCredentials;
127
- if (electronCredentials?.refresh_token) return electronCredentials;
128
- return cliCredentials ?? electronCredentials;
150
+
151
+ return migrateLegacyCredentials();
129
152
  }
130
153
 
131
154
  /** @param {Credentials} data */
@@ -135,45 +158,36 @@ export function saveCredentials(data) {
135
158
  throw new Error('Cannot save empty Overlord credentials.');
136
159
  }
137
160
 
138
- const sharedCredentials = { ...credentials, updated_at: new Date().toISOString() };
139
- writeJsonFileAtomic(CREDENTIALS_FILE, sharedCredentials);
140
-
141
- const existingElectronCredentials = readJsonFile(ELECTRON_CREDENTIALS_FILE);
142
- if (existingElectronCredentials && typeof existingElectronCredentials === 'object') {
143
- const electronPayload = { ...existingElectronCredentials };
144
- electronPayload.updated_at = sharedCredentials.updated_at;
145
- if (credentials.platform_url) electronPayload.platform_url = credentials.platform_url;
146
- if (credentials.access_token_expires_at) {
147
- electronPayload.access_token_expires_at = credentials.access_token_expires_at;
148
- }
149
- if (credentials.organization_id) electronPayload.organization_id = credentials.organization_id;
150
- if (credentials.user_email) electronPayload.user_email = credentials.user_email;
151
- delete electronPayload.supabase_refresh_token;
152
- writeJsonFileAtomic(ELECTRON_CREDENTIALS_FILE, electronPayload);
153
- }
161
+ writeJsonFileAtomic(CLI_CREDENTIALS_FILE, { ...credentials, updated_at: new Date().toISOString() });
154
162
  }
155
163
 
156
164
  export function clearCredentials() {
157
- for (const filePath of [CREDENTIALS_FILE, ELECTRON_CREDENTIALS_FILE]) {
158
- try {
159
- fs.unlinkSync(filePath);
160
- } catch {
161
- // Already gone
162
- }
165
+ try {
166
+ fs.unlinkSync(CLI_CREDENTIALS_FILE);
167
+ } catch {
168
+ // Already gone
163
169
  }
164
170
  }
165
171
 
166
172
  function getCredentialFileSource() {
167
- const cliCredentials = parseStoredCredentialsData(readJsonFile(CREDENTIALS_FILE), {
168
- requireAuthData: true
169
- });
170
- const electronCredentials = parseStoredCredentialsData(readJsonFile(ELECTRON_CREDENTIALS_FILE), {
173
+ const cliCredentials = parseStoredCredentialsData(readJsonFile(CLI_CREDENTIALS_FILE), {
171
174
  requireAuthData: true
172
175
  });
173
- if (cliCredentials?.refresh_token) return 'credentials.json';
174
- if (electronCredentials?.refresh_token) return 'electron-credentials.json';
175
- if (cliCredentials) return 'credentials.json';
176
- if (electronCredentials) return 'electron-credentials.json';
176
+ if (cliCredentials?.refresh_token) return 'credentials.cli.json';
177
+
178
+ if (fileExists(LEGACY_CREDENTIALS_FILE)) {
179
+ const legacyShared = parseStoredCredentialsData(readJsonFile(LEGACY_CREDENTIALS_FILE), {
180
+ requireAuthData: true
181
+ });
182
+ if (legacyShared?.refresh_token) return 'credentials.json (legacy)';
183
+ }
184
+
185
+ if (fileExists(LEGACY_ELECTRON_CREDENTIALS_FILE)) {
186
+ const legacyElectron = parseStoredCredentialsData(readJsonFile(LEGACY_ELECTRON_CREDENTIALS_FILE), {
187
+ requireAuthData: true
188
+ });
189
+ if (legacyElectron?.refresh_token) return 'electron-credentials.json (legacy)';
190
+ }
177
191
 
178
192
  return 'none';
179
193
  }
@@ -579,8 +593,9 @@ export async function getAuthStatus() {
579
593
  organizationId: resolved.organizationId ?? null,
580
594
  authMode: resolved.authMode,
581
595
  error,
582
- credentialsFileExists: fileExists(CREDENTIALS_FILE),
583
- electronCredentialsFileExists: fileExists(ELECTRON_CREDENTIALS_FILE)
596
+ credentialsFileExists: fileExists(CLI_CREDENTIALS_FILE),
597
+ legacyCredentialsFileExists: fileExists(LEGACY_CREDENTIALS_FILE),
598
+ electronCredentialsFileExists: fileExists(LEGACY_ELECTRON_CREDENTIALS_FILE)
584
599
  };
585
600
  }
586
601
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "4.23.0",
3
+ "version": "5.0.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "type": "module",
6
6
  "bin": {