overlord-cli 0.2605291450.0 → 0.2605300746.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 +43 -0
- package/bin/_cli/credentials.mjs +53 -3
- package/bin/_cli/index.mjs +1 -1
- package/bin/_cli/protocol.mjs +1 -1
- package/package.json +1 -1
package/bin/_cli/auth.mjs
CHANGED
|
@@ -500,7 +500,27 @@ function parseOrganizationFlag(args) {
|
|
|
500
500
|
return parsed;
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
function parseTokenFlag(args) {
|
|
504
|
+
const index = args.findIndex(arg => arg === '--token' || arg.startsWith('--token='));
|
|
505
|
+
if (index === -1) return null;
|
|
506
|
+
const raw = args[index].includes('=') ? args[index].split('=')[1] : args[index + 1];
|
|
507
|
+
if (!raw || typeof raw !== 'string') {
|
|
508
|
+
throw new Error('--token requires a value (e.g. --token oat_…)');
|
|
509
|
+
}
|
|
510
|
+
const trimmed = raw.trim();
|
|
511
|
+
if (!trimmed.startsWith('oat_')) {
|
|
512
|
+
throw new Error('--token value must be an agent token starting with oat_');
|
|
513
|
+
}
|
|
514
|
+
return trimmed;
|
|
515
|
+
}
|
|
516
|
+
|
|
503
517
|
export async function authLogin(args = []) {
|
|
518
|
+
const agentToken = parseTokenFlag(args);
|
|
519
|
+
|
|
520
|
+
if (agentToken) {
|
|
521
|
+
return authLoginWithAgentToken(agentToken, args);
|
|
522
|
+
}
|
|
523
|
+
|
|
504
524
|
const preselectedOrganizationId = parseOrganizationFlag(args);
|
|
505
525
|
const storedCredentials = loadCredentials();
|
|
506
526
|
const platformUrl = resolveLoginPlatformUrl(null, storedCredentials?.platform_url ?? null);
|
|
@@ -558,6 +578,27 @@ export async function authLogin(args = []) {
|
|
|
558
578
|
}
|
|
559
579
|
}
|
|
560
580
|
|
|
581
|
+
async function authLoginWithAgentToken(agentToken, args) {
|
|
582
|
+
const preselectedOrganizationId = parseOrganizationFlag(args);
|
|
583
|
+
const storedCredentials = loadCredentials();
|
|
584
|
+
const platformUrl = resolveLoginPlatformUrl(null, storedCredentials?.platform_url ?? null);
|
|
585
|
+
|
|
586
|
+
saveCredentials({
|
|
587
|
+
agent_token: agentToken,
|
|
588
|
+
platform_url: platformUrl,
|
|
589
|
+
...(preselectedOrganizationId !== null ? { organization_id: preselectedOrganizationId } : {})
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
console.log(`Agent token saved. The CLI will use this token for all protocol commands.`);
|
|
593
|
+
if (preselectedOrganizationId !== null) {
|
|
594
|
+
console.log(` Default organization: ${preselectedOrganizationId}`);
|
|
595
|
+
} else {
|
|
596
|
+
console.log(` Organization will be derived from your token's membership.`);
|
|
597
|
+
}
|
|
598
|
+
console.log(` Platform URL: ${platformUrl}`);
|
|
599
|
+
console.log(`\nTo remove: ovld auth logout`);
|
|
600
|
+
}
|
|
601
|
+
|
|
561
602
|
async function printVerboseAuthStatus() {
|
|
562
603
|
const status = await getAuthStatus();
|
|
563
604
|
if (!status.isLoggedIn) {
|
|
@@ -638,6 +679,8 @@ export async function runAuthCommand(subcommand, args = []) {
|
|
|
638
679
|
|
|
639
680
|
Subcommands:
|
|
640
681
|
login Authorize the CLI via browser (works locally or over SSH)
|
|
682
|
+
--token <oat_…> Persist an agent token from Settings → Agents & MCP.
|
|
683
|
+
Skips the browser flow; token never expires.
|
|
641
684
|
--organization-id <id> Optional default organization override
|
|
642
685
|
(ticket-scoped commands infer organization
|
|
643
686
|
from ticket ids such as 1:899)
|
package/bin/_cli/credentials.mjs
CHANGED
|
@@ -79,19 +79,21 @@ function parseStoredCredentialsData(parsed, { requireAuthData = false } = {}) {
|
|
|
79
79
|
typeof parsed.access_token_expires_at === 'string'
|
|
80
80
|
? parsed.access_token_expires_at.trim()
|
|
81
81
|
: '';
|
|
82
|
+
const agentToken = normalizeAgentToken(parsed.agent_token);
|
|
82
83
|
const organizationId =
|
|
83
84
|
typeof parsed.organization_id === 'number' && Number.isFinite(parsed.organization_id)
|
|
84
85
|
? parsed.organization_id
|
|
85
86
|
: null;
|
|
86
87
|
|
|
87
88
|
if (!platformUrl) return null;
|
|
88
|
-
if (requireAuthData && !refreshToken) return null;
|
|
89
|
+
if (requireAuthData && !refreshToken && !agentToken) return null;
|
|
89
90
|
|
|
90
91
|
return {
|
|
91
92
|
platform_url: platformUrl,
|
|
92
93
|
...(refreshToken ? { refresh_token: refreshToken } : {}),
|
|
93
94
|
...(accessToken ? { access_token: accessToken } : {}),
|
|
94
95
|
...(accessTokenExpiresAt ? { access_token_expires_at: accessTokenExpiresAt } : {}),
|
|
96
|
+
...(agentToken ? { agent_token: agentToken } : {}),
|
|
95
97
|
...(organizationId ? { organization_id: organizationId } : {}),
|
|
96
98
|
...(typeof parsed.user_email === 'string' && parsed.user_email.trim()
|
|
97
99
|
? { user_email: parsed.user_email.trim() }
|
|
@@ -116,6 +118,7 @@ function normalizeCredentialsForSave(data) {
|
|
|
116
118
|
...(parsed.access_token_expires_at
|
|
117
119
|
? { access_token_expires_at: parsed.access_token_expires_at }
|
|
118
120
|
: {}),
|
|
121
|
+
...(parsed.agent_token ? { agent_token: parsed.agent_token } : {}),
|
|
119
122
|
...(parsed.organization_id ? { organization_id: parsed.organization_id } : {}),
|
|
120
123
|
...(parsed.user_email ? { user_email: parsed.user_email } : {}),
|
|
121
124
|
...(parsed.updated_at ? { updated_at: parsed.updated_at } : {})
|
|
@@ -181,10 +184,13 @@ function selectStoredCredentials() {
|
|
|
181
184
|
requireAuthData: true
|
|
182
185
|
})
|
|
183
186
|
}
|
|
184
|
-
].filter(candidate => candidate.credentials?.refresh_token);
|
|
187
|
+
].filter(candidate => candidate.credentials?.refresh_token || candidate.credentials?.agent_token);
|
|
185
188
|
|
|
186
189
|
if (candidates.length === 0) return null;
|
|
187
190
|
|
|
191
|
+
const agentTokenCandidate = candidates.find(c => c.credentials?.agent_token);
|
|
192
|
+
if (agentTokenCandidate) return agentTokenCandidate;
|
|
193
|
+
|
|
188
194
|
const fresh = candidates.filter(candidate => isAccessTokenFresh(candidate.credentials));
|
|
189
195
|
const pool = fresh.length > 0 ? fresh : candidates;
|
|
190
196
|
return pool.sort(
|
|
@@ -551,6 +557,27 @@ export async function resolveAuth(options = {}) {
|
|
|
551
557
|
? runtime.local_secret
|
|
552
558
|
: '';
|
|
553
559
|
|
|
560
|
+
const envAgentToken = normalizeAgentToken(process.env.OVERLORD_AGENT_TOKEN);
|
|
561
|
+
if (envAgentToken) {
|
|
562
|
+
const envOrganizationId =
|
|
563
|
+
typeof process.env.OVERLORD_ORGANIZATION_ID === 'string'
|
|
564
|
+
? Number.parseInt(process.env.OVERLORD_ORGANIZATION_ID, 10)
|
|
565
|
+
: null;
|
|
566
|
+
const resolvedOrganizationId =
|
|
567
|
+
organizationIdHint ?? (Number.isFinite(envOrganizationId) ? envOrganizationId : null);
|
|
568
|
+
|
|
569
|
+
// Agent tokens are long-lived and never need refreshing. Organization is
|
|
570
|
+
// optional — the platform derives it from the token owner's membership when
|
|
571
|
+
// no hint is supplied, so a headless CLI keeps working without Desktop.
|
|
572
|
+
return {
|
|
573
|
+
platformUrl,
|
|
574
|
+
bearerToken: envAgentToken,
|
|
575
|
+
localSecret,
|
|
576
|
+
organizationId: resolvedOrganizationId,
|
|
577
|
+
authMode: 'agent_token'
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
554
581
|
const envAccessToken = normalizeAccessToken(process.env.OVERLORD_ACCESS_TOKEN);
|
|
555
582
|
if (envAccessToken) {
|
|
556
583
|
const envOrganizationId =
|
|
@@ -575,6 +602,16 @@ export async function resolveAuth(options = {}) {
|
|
|
575
602
|
}
|
|
576
603
|
}
|
|
577
604
|
|
|
605
|
+
if (creds?.agent_token) {
|
|
606
|
+
return {
|
|
607
|
+
platformUrl,
|
|
608
|
+
bearerToken: creds.agent_token,
|
|
609
|
+
localSecret,
|
|
610
|
+
organizationId: organizationIdHint ?? creds.organization_id ?? null,
|
|
611
|
+
authMode: 'agent_token'
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
578
615
|
if (!creds) {
|
|
579
616
|
return {
|
|
580
617
|
platformUrl,
|
|
@@ -649,10 +686,15 @@ export async function getAuthStatus() {
|
|
|
649
686
|
};
|
|
650
687
|
}
|
|
651
688
|
|
|
689
|
+
const envAgentToken = normalizeAgentToken(process.env.OVERLORD_AGENT_TOKEN);
|
|
652
690
|
const envAccessToken = normalizeAccessToken(process.env.OVERLORD_ACCESS_TOKEN);
|
|
653
691
|
let tokenSource = 'fallback';
|
|
654
|
-
if (
|
|
692
|
+
if (envAgentToken) {
|
|
693
|
+
tokenSource = 'OVERLORD_AGENT_TOKEN';
|
|
694
|
+
} else if (envAccessToken && isEnvAccessTokenUsable(envAccessToken)) {
|
|
655
695
|
tokenSource = 'OVERLORD_ACCESS_TOKEN';
|
|
696
|
+
} else if (creds?.agent_token) {
|
|
697
|
+
tokenSource = getCredentialFileSource() + ' (agent token)';
|
|
656
698
|
} else if (creds?.refresh_token) {
|
|
657
699
|
tokenSource = getCredentialFileSource();
|
|
658
700
|
}
|
|
@@ -704,6 +746,14 @@ function normalizeAccessToken(value) {
|
|
|
704
746
|
return value.trim();
|
|
705
747
|
}
|
|
706
748
|
|
|
749
|
+
const AGENT_TOKEN_PREFIX = 'oat_';
|
|
750
|
+
|
|
751
|
+
function normalizeAgentToken(value) {
|
|
752
|
+
if (typeof value !== 'string') return '';
|
|
753
|
+
const trimmed = value.trim();
|
|
754
|
+
return trimmed.startsWith(AGENT_TOKEN_PREFIX) ? trimmed : '';
|
|
755
|
+
}
|
|
756
|
+
|
|
707
757
|
function isEnvAccessTokenUsable(accessToken) {
|
|
708
758
|
const expiresAt = decodeJwtExpiry(accessToken);
|
|
709
759
|
return expiresAt === null || expiresAt * 1000 - Date.now() > 60_000;
|
package/bin/_cli/index.mjs
CHANGED
|
@@ -57,7 +57,7 @@ Agents:
|
|
|
57
57
|
Key protocol commands: auth-status, discover-project, create, prompt, attach, connect, load-context.
|
|
58
58
|
|
|
59
59
|
Auth:
|
|
60
|
-
${primaryCommand} auth login Authorize CLI via browser
|
|
60
|
+
${primaryCommand} auth login Authorize CLI via browser or --token <oat_…>
|
|
61
61
|
${primaryCommand} auth status Show login status
|
|
62
62
|
${primaryCommand} auth repair Repair shared Desktop/CLI credentials
|
|
63
63
|
${primaryCommand} auth logout Remove stored credentials
|
package/bin/_cli/protocol.mjs
CHANGED
|
@@ -2614,7 +2614,7 @@ Subcommands:
|
|
|
2614
2614
|
Environment fallback:
|
|
2615
2615
|
--session-key <- SESSION_KEY or auto-persisted session from last attach/connect/prompt in this working directory
|
|
2616
2616
|
--ticket-id <- TICKET_ID or auto-persisted session (human-readable ticket_id, e.g. 1:899)
|
|
2617
|
-
auth/host <- OVERLORD_URL, optional OVERLORD_ACCESS_TOKEN + OVERLORD_ORGANIZATION_ID, or shared OAuth credentials from ovld auth/Desktop login
|
|
2617
|
+
auth/host <- OVERLORD_URL, OVERLORD_AGENT_TOKEN (durable; best for headless/CI), optional OVERLORD_ACCESS_TOKEN + OVERLORD_ORGANIZATION_ID, or shared OAuth credentials from ovld auth/Desktop login
|
|
2618
2618
|
--timeout <- OVERLORD_TIMEOUT
|
|
2619
2619
|
|
|
2620
2620
|
Common flags:
|