@modelprofile.com/authswitch 2.1.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/.smartconfig.json +34 -0
- package/cli.js +21 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/accounts.d.ts +31 -0
- package/dist_ts/accounts.js +74 -0
- package/dist_ts/classes.accountlist.d.ts +17 -0
- package/dist_ts/classes.accountlist.js +214 -0
- package/dist_ts/classes.claudecodeharness.d.ts +34 -0
- package/dist_ts/classes.claudecodeharness.js +123 -0
- package/dist_ts/classes.claudestatus.d.ts +8 -0
- package/dist_ts/classes.claudestatus.js +139 -0
- package/dist_ts/classes.cli.d.ts +31 -0
- package/dist_ts/classes.cli.js +584 -0
- package/dist_ts/classes.codexauth.d.ts +35 -0
- package/dist_ts/classes.codexauth.js +184 -0
- package/dist_ts/classes.codexdaemon.d.ts +38 -0
- package/dist_ts/classes.codexdaemon.js +122 -0
- package/dist_ts/classes.codexharness.d.ts +35 -0
- package/dist_ts/classes.codexharness.js +199 -0
- package/dist_ts/classes.codexhome.d.ts +25 -0
- package/dist_ts/classes.codexhome.js +60 -0
- package/dist_ts/classes.codexpreuse.d.ts +8 -0
- package/dist_ts/classes.codexpreuse.js +90 -0
- package/dist_ts/classes.codexstatus.d.ts +20 -0
- package/dist_ts/classes.codexstatus.js +304 -0
- package/dist_ts/classes.codexswitcher.d.ts +61 -0
- package/dist_ts/classes.codexswitcher.js +226 -0
- package/dist_ts/classes.credentialstore.d.ts +32 -0
- package/dist_ts/classes.credentialstore.js +115 -0
- package/dist_ts/classes.fileharness.d.ts +47 -0
- package/dist_ts/classes.fileharness.js +119 -0
- package/dist_ts/classes.login.d.ts +42 -0
- package/dist_ts/classes.login.js +102 -0
- package/dist_ts/classes.opencodeharness.d.ts +34 -0
- package/dist_ts/classes.opencodeharness.js +125 -0
- package/dist_ts/classes.operations.d.ts +44 -0
- package/dist_ts/classes.operations.js +97 -0
- package/dist_ts/classes.remotecontrol.d.ts +46 -0
- package/dist_ts/classes.remotecontrol.js +169 -0
- package/dist_ts/classes.service.d.ts +47 -0
- package/dist_ts/classes.service.js +142 -0
- package/dist_ts/classes.stashstore.d.ts +63 -0
- package/dist_ts/classes.stashstore.js +192 -0
- package/dist_ts/classes.tui.d.ts +11 -0
- package/dist_ts/classes.tui.js +195 -0
- package/dist_ts/formatting.d.ts +8 -0
- package/dist_ts/formatting.js +13 -0
- package/dist_ts/helpers.d.ts +39 -0
- package/dist_ts/helpers.js +92 -0
- package/dist_ts/index.d.ts +22 -0
- package/dist_ts/index.js +27 -0
- package/dist_ts/interfaces.d.ts +145 -0
- package/dist_ts/interfaces.harness.d.ts +130 -0
- package/dist_ts/interfaces.harness.js +2 -0
- package/dist_ts/interfaces.js +2 -0
- package/dist_ts/interfaces.list.d.ts +19 -0
- package/dist_ts/interfaces.list.js +2 -0
- package/dist_ts/plugins.d.ts +14 -0
- package/dist_ts/plugins.js +18 -0
- package/dist_ts/preuse.d.ts +6 -0
- package/dist_ts/preuse.js +13 -0
- package/license.md +21 -0
- package/package.json +53 -0
- package/readme.md +502 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/accounts.ts +78 -0
- package/ts/classes.accountlist.ts +211 -0
- package/ts/classes.claudecodeharness.ts +111 -0
- package/ts/classes.claudestatus.ts +99 -0
- package/ts/classes.cli.ts +479 -0
- package/ts/classes.codexauth.ts +199 -0
- package/ts/classes.codexdaemon.ts +137 -0
- package/ts/classes.codexharness.ts +233 -0
- package/ts/classes.codexhome.ts +68 -0
- package/ts/classes.codexpreuse.ts +76 -0
- package/ts/classes.codexstatus.ts +257 -0
- package/ts/classes.codexswitcher.ts +272 -0
- package/ts/classes.credentialstore.ts +101 -0
- package/ts/classes.fileharness.ts +120 -0
- package/ts/classes.login.ts +103 -0
- package/ts/classes.opencodeharness.ts +114 -0
- package/ts/classes.operations.ts +101 -0
- package/ts/classes.remotecontrol.ts +208 -0
- package/ts/classes.service.ts +152 -0
- package/ts/classes.stashstore.ts +223 -0
- package/ts/classes.tui.ts +138 -0
- package/ts/formatting.ts +14 -0
- package/ts/helpers.ts +109 -0
- package/ts/index.ts +28 -0
- package/ts/interfaces.harness.ts +112 -0
- package/ts/interfaces.list.ts +19 -0
- package/ts/interfaces.ts +158 -0
- package/ts/plugins.ts +20 -0
- package/ts/preuse.ts +15 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IActiveAuth, ICodexIdentity } from './interfaces.js';
|
|
2
|
+
import { CodexHome } from './classes.codexhome.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reads, writes and clears the Codex file credential store, and derives the
|
|
5
|
+
* account identity used to key a stash.
|
|
6
|
+
*
|
|
7
|
+
* Nothing in this class logs or returns a token value; only the raw string that
|
|
8
|
+
* callers copy verbatim between the active slot and the stash.
|
|
9
|
+
*/
|
|
10
|
+
export declare class CodexAuth {
|
|
11
|
+
readonly codexHome: CodexHome;
|
|
12
|
+
constructor(codexHomeArg: CodexHome);
|
|
13
|
+
/**
|
|
14
|
+
* Extracts the account identity from the content of an auth.json.
|
|
15
|
+
* Returns null when the file holds no recognisable credential.
|
|
16
|
+
*/
|
|
17
|
+
identityFromRaw(rawArg: string): ICodexIdentity | null;
|
|
18
|
+
/**
|
|
19
|
+
* A short, non-reversible label for an API key so two different keys get two
|
|
20
|
+
* different stashes without the key itself ever being written down.
|
|
21
|
+
*/
|
|
22
|
+
private fingerprint;
|
|
23
|
+
/** Reads the active credential, if any. */
|
|
24
|
+
readActive(): IActiveAuth;
|
|
25
|
+
/**
|
|
26
|
+
* When no auth.json exists the credential is either absent or held by an OS
|
|
27
|
+
* keyring. The age-encrypted secrets directory is the observable marker of the
|
|
28
|
+
* keyring-backed store, so use it to tell the two apart.
|
|
29
|
+
*/
|
|
30
|
+
private detectNonFileSource;
|
|
31
|
+
/** Writes a credential into the active slot atomically and owner-only. */
|
|
32
|
+
writeActive(rawArg: string): void;
|
|
33
|
+
/** Removes the active credential. Safe to call when none exists. */
|
|
34
|
+
clearActive(): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { CodexHome } from './classes.codexhome.js';
|
|
3
|
+
import { writeSecretFileAtomically } from './helpers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Decodes the payload of a JWT without verifying it.
|
|
6
|
+
*
|
|
7
|
+
* authswitch never uses these claims for authorization -- only to label a stash
|
|
8
|
+
* with the account it belongs to -- so signature verification would buy nothing.
|
|
9
|
+
*/
|
|
10
|
+
const decodeJwtPayload = (tokenArg) => {
|
|
11
|
+
const segments = tokenArg.split('.');
|
|
12
|
+
if (segments.length < 2) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const decoded = Buffer.from(segments[1], 'base64url').toString('utf8');
|
|
17
|
+
const parsed = JSON.parse(decoded);
|
|
18
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
19
|
+
return parsed;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const asString = (valueArg) => typeof valueArg === 'string' && valueArg.length > 0 ? valueArg : null;
|
|
28
|
+
/**
|
|
29
|
+
* Walks an arbitrary JSON value and returns the first string that looks like a JWT.
|
|
30
|
+
* Used as a fallback so a Codex schema change cannot silently break stash labelling.
|
|
31
|
+
*/
|
|
32
|
+
const findFirstJwt = (valueArg, depthArg = 0) => {
|
|
33
|
+
if (depthArg > 6) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (typeof valueArg === 'string') {
|
|
37
|
+
return /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]+$/.test(valueArg) ? valueArg : null;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(valueArg)) {
|
|
40
|
+
for (const itemArg of valueArg) {
|
|
41
|
+
const found = findFirstJwt(itemArg, depthArg + 1);
|
|
42
|
+
if (found)
|
|
43
|
+
return found;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (valueArg && typeof valueArg === 'object') {
|
|
48
|
+
for (const itemArg of Object.values(valueArg)) {
|
|
49
|
+
const found = findFirstJwt(itemArg, depthArg + 1);
|
|
50
|
+
if (found)
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Reads, writes and clears the Codex file credential store, and derives the
|
|
58
|
+
* account identity used to key a stash.
|
|
59
|
+
*
|
|
60
|
+
* Nothing in this class logs or returns a token value; only the raw string that
|
|
61
|
+
* callers copy verbatim between the active slot and the stash.
|
|
62
|
+
*/
|
|
63
|
+
export class CodexAuth {
|
|
64
|
+
codexHome;
|
|
65
|
+
constructor(codexHomeArg) {
|
|
66
|
+
this.codexHome = codexHomeArg;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Extracts the account identity from the content of an auth.json.
|
|
70
|
+
* Returns null when the file holds no recognisable credential.
|
|
71
|
+
*/
|
|
72
|
+
identityFromRaw(rawArg) {
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = JSON.parse(rawArg);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const record = parsed;
|
|
84
|
+
const tokens = (record.tokens ?? null);
|
|
85
|
+
const idToken = (tokens ? asString(tokens.id_token) : null) ?? findFirstJwt(record);
|
|
86
|
+
if (idToken) {
|
|
87
|
+
const claims = decodeJwtPayload(idToken) ?? {};
|
|
88
|
+
const authClaim = (claims['https://api.openai.com/auth'] ?? {});
|
|
89
|
+
const profileClaim = (claims['https://api.openai.com/profile'] ?? {});
|
|
90
|
+
const email = asString(claims.email) ??
|
|
91
|
+
asString(profileClaim.email) ??
|
|
92
|
+
asString(authClaim.user_email);
|
|
93
|
+
const accountId = asString(authClaim.chatgpt_account_id) ??
|
|
94
|
+
(tokens ? asString(tokens.account_id) : null) ??
|
|
95
|
+
asString(record.account_id);
|
|
96
|
+
if (email) {
|
|
97
|
+
return {
|
|
98
|
+
kind: 'chatgpt',
|
|
99
|
+
email: email.toLowerCase(),
|
|
100
|
+
accountId,
|
|
101
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
102
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (accountId) {
|
|
106
|
+
// An OAuth credential we cannot label by email is still worth stashing;
|
|
107
|
+
// key it by account id so it round-trips instead of being silently dropped.
|
|
108
|
+
return {
|
|
109
|
+
kind: 'chatgpt',
|
|
110
|
+
email: `account:${accountId}`,
|
|
111
|
+
accountId,
|
|
112
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
113
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const apiKey = asString(record.OPENAI_API_KEY) ?? asString(record.openai_api_key);
|
|
118
|
+
if (apiKey) {
|
|
119
|
+
const fingerprint = this.fingerprint(apiKey);
|
|
120
|
+
return {
|
|
121
|
+
kind: 'apikey',
|
|
122
|
+
email: `apikey:${fingerprint}`,
|
|
123
|
+
accountId: null,
|
|
124
|
+
planType: null,
|
|
125
|
+
userId: null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A short, non-reversible label for an API key so two different keys get two
|
|
132
|
+
* different stashes without the key itself ever being written down.
|
|
133
|
+
*/
|
|
134
|
+
fingerprint(secretArg) {
|
|
135
|
+
let hash = 0x811c9dc5;
|
|
136
|
+
for (let index = 0; index < secretArg.length; index++) {
|
|
137
|
+
hash ^= secretArg.charCodeAt(index);
|
|
138
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
139
|
+
}
|
|
140
|
+
return hash.toString(16).padStart(8, '0');
|
|
141
|
+
}
|
|
142
|
+
/** Reads the active credential, if any. */
|
|
143
|
+
readActive() {
|
|
144
|
+
const authFilePath = this.codexHome.authFilePath;
|
|
145
|
+
if (!plugins.fs.existsSync(authFilePath)) {
|
|
146
|
+
return {
|
|
147
|
+
source: this.detectNonFileSource(),
|
|
148
|
+
authFilePath,
|
|
149
|
+
identity: null,
|
|
150
|
+
raw: null,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const raw = plugins.fs.readFileSync(authFilePath, 'utf8');
|
|
154
|
+
return {
|
|
155
|
+
source: 'file',
|
|
156
|
+
authFilePath,
|
|
157
|
+
identity: this.identityFromRaw(raw),
|
|
158
|
+
raw,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* When no auth.json exists the credential is either absent or held by an OS
|
|
163
|
+
* keyring. The age-encrypted secrets directory is the observable marker of the
|
|
164
|
+
* keyring-backed store, so use it to tell the two apart.
|
|
165
|
+
*/
|
|
166
|
+
detectNonFileSource() {
|
|
167
|
+
if (plugins.fs.existsSync(this.codexHome.secretsDir)) {
|
|
168
|
+
return 'keyring';
|
|
169
|
+
}
|
|
170
|
+
return 'none';
|
|
171
|
+
}
|
|
172
|
+
/** Writes a credential into the active slot atomically and owner-only. */
|
|
173
|
+
writeActive(rawArg) {
|
|
174
|
+
plugins.fs.mkdirSync(this.codexHome.dir, { recursive: true });
|
|
175
|
+
writeSecretFileAtomically(this.codexHome.authFilePath, rawArg);
|
|
176
|
+
}
|
|
177
|
+
/** Removes the active credential. Safe to call when none exists. */
|
|
178
|
+
clearActive() {
|
|
179
|
+
if (plugins.fs.existsSync(this.codexHome.authFilePath)) {
|
|
180
|
+
plugins.fs.rmSync(this.codexHome.authFilePath);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2RleGF1dGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNvZGV4YXV0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXpEOzs7OztHQUtHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLFFBQWdCLEVBQWtDLEVBQUU7SUFDNUUsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNyQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDeEIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsSUFBSSxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sTUFBTSxHQUFZLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUMsSUFBSSxNQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ25FLE9BQU8sTUFBaUMsQ0FBQztRQUMzQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQyxDQUFDO0FBRUYsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUFpQixFQUFFLENBQ3BELE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxR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
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ICommandResult, IDaemonStatus } from './interfaces.js';
|
|
2
|
+
import { CodexHome } from './classes.codexhome.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drives the Codex CLI itself for everything Codex already exposes.
|
|
5
|
+
*
|
|
6
|
+
* The local app-server holds the remote-control websocket, keeps the state
|
|
7
|
+
* database open, and refreshes tokens on its own schedule, so a credential swap
|
|
8
|
+
* has to happen while it is stopped. Codex ships
|
|
9
|
+
* `codex app-server daemon {start,stop,version}` for exactly this, so authswitch
|
|
10
|
+
* goes through those rather than signalling pids behind Codex' back.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CodexDaemon {
|
|
13
|
+
readonly codexHome: CodexHome;
|
|
14
|
+
private readonly binary;
|
|
15
|
+
constructor(codexHomeArg: CodexHome, binaryArg?: string);
|
|
16
|
+
/** Whether the Codex CLI can be executed at all. */
|
|
17
|
+
isAvailable(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Authoritative daemon status, straight from Codex.
|
|
20
|
+
* Returns null when the Codex CLI cannot be reached or answers unexpectedly,
|
|
21
|
+
* which callers treat as "unknown" rather than "stopped".
|
|
22
|
+
*/
|
|
23
|
+
status(): IDaemonStatus | null;
|
|
24
|
+
/** True when remote control is enabled for future daemon starts. */
|
|
25
|
+
isRemoteControlEnabled(): boolean;
|
|
26
|
+
/** The pid of the managed daemon, when its pid file is readable. */
|
|
27
|
+
daemonPid(): number | null;
|
|
28
|
+
/**
|
|
29
|
+
* Whether a daemon is up. Prefers Codex' own answer and falls back to the pid
|
|
30
|
+
* file so the check still works when the Codex CLI is not on PATH.
|
|
31
|
+
*/
|
|
32
|
+
isDaemonRunning(): boolean;
|
|
33
|
+
stop(): ICommandResult;
|
|
34
|
+
start(): ICommandResult;
|
|
35
|
+
/** A one-line diagnosis of a failed invocation, suitable for an error message. */
|
|
36
|
+
describeFailure(resultArg: ICommandResult): string;
|
|
37
|
+
private run;
|
|
38
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { CodexHome } from './classes.codexhome.js';
|
|
3
|
+
import { describeCodexFailure } from './helpers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Drives the Codex CLI itself for everything Codex already exposes.
|
|
6
|
+
*
|
|
7
|
+
* The local app-server holds the remote-control websocket, keeps the state
|
|
8
|
+
* database open, and refreshes tokens on its own schedule, so a credential swap
|
|
9
|
+
* has to happen while it is stopped. Codex ships
|
|
10
|
+
* `codex app-server daemon {start,stop,version}` for exactly this, so authswitch
|
|
11
|
+
* goes through those rather than signalling pids behind Codex' back.
|
|
12
|
+
*/
|
|
13
|
+
export class CodexDaemon {
|
|
14
|
+
codexHome;
|
|
15
|
+
binary;
|
|
16
|
+
constructor(codexHomeArg, binaryArg) {
|
|
17
|
+
this.codexHome = codexHomeArg;
|
|
18
|
+
this.binary = binaryArg ?? process.env.AUTHSWITCH_CODEX_BIN ?? 'codex';
|
|
19
|
+
}
|
|
20
|
+
/** Whether the Codex CLI can be executed at all. */
|
|
21
|
+
isAvailable() {
|
|
22
|
+
return this.run(['--version']).ok;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Authoritative daemon status, straight from Codex.
|
|
26
|
+
* Returns null when the Codex CLI cannot be reached or answers unexpectedly,
|
|
27
|
+
* which callers treat as "unknown" rather than "stopped".
|
|
28
|
+
*/
|
|
29
|
+
status() {
|
|
30
|
+
const result = this.run(['app-server', 'daemon', 'version']);
|
|
31
|
+
if (!result.ok) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(result.stdout.trim());
|
|
36
|
+
return {
|
|
37
|
+
running: parsed.status === 'running',
|
|
38
|
+
backend: typeof parsed.backend === 'string' ? parsed.backend : null,
|
|
39
|
+
appServerVersion: typeof parsed.appServerVersion === 'string' ? parsed.appServerVersion : null,
|
|
40
|
+
cliVersion: typeof parsed.cliVersion === 'string' ? parsed.cliVersion : null,
|
|
41
|
+
socketPath: typeof parsed.socketPath === 'string' ? parsed.socketPath : null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** True when remote control is enabled for future daemon starts. */
|
|
49
|
+
isRemoteControlEnabled() {
|
|
50
|
+
const settingsPath = this.codexHome.appServerSettingsPath;
|
|
51
|
+
if (!plugins.fs.existsSync(settingsPath)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(plugins.fs.readFileSync(settingsPath, 'utf8'));
|
|
56
|
+
return parsed.remoteControlEnabled === true;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** The pid of the managed daemon, when its pid file is readable. */
|
|
63
|
+
daemonPid() {
|
|
64
|
+
const pidPath = this.codexHome.appServerPidPath;
|
|
65
|
+
if (!plugins.fs.existsSync(pidPath)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(plugins.fs.readFileSync(pidPath, 'utf8'));
|
|
70
|
+
return typeof parsed.pid === 'number' ? parsed.pid : null;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Whether a daemon is up. Prefers Codex' own answer and falls back to the pid
|
|
78
|
+
* file so the check still works when the Codex CLI is not on PATH.
|
|
79
|
+
*/
|
|
80
|
+
isDaemonRunning() {
|
|
81
|
+
const status = this.status();
|
|
82
|
+
if (status !== null) {
|
|
83
|
+
return status.running;
|
|
84
|
+
}
|
|
85
|
+
const pid = this.daemonPid();
|
|
86
|
+
if (pid === null) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
process.kill(pid, 0);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
stop() {
|
|
98
|
+
return this.run(['app-server', 'daemon', 'stop']);
|
|
99
|
+
}
|
|
100
|
+
start() {
|
|
101
|
+
return this.run(['app-server', 'daemon', 'start']);
|
|
102
|
+
}
|
|
103
|
+
/** A one-line diagnosis of a failed invocation, suitable for an error message. */
|
|
104
|
+
describeFailure(resultArg) {
|
|
105
|
+
return describeCodexFailure(this.binary, resultArg.stdout, resultArg.stderr, resultArg.spawnError);
|
|
106
|
+
}
|
|
107
|
+
run(argsArg) {
|
|
108
|
+
const result = plugins.childProcess.spawnSync(this.binary, argsArg, {
|
|
109
|
+
encoding: 'utf8',
|
|
110
|
+
timeout: 60_000,
|
|
111
|
+
env: { ...process.env, CODEX_HOME: this.codexHome.dir },
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
ok: result.status === 0,
|
|
115
|
+
stdout: result.stdout ?? '',
|
|
116
|
+
stderr: result.stderr ?? '',
|
|
117
|
+
code: result.status,
|
|
118
|
+
spawnError: result.error ? result.error.message : null,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2RleGRhZW1vbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuY29kZXhkYWVtb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFFeEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVwRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ04sU0FBUyxDQUFZO0lBQ3BCLE1BQU0sQ0FBUztJQUVoQyxZQUFZLFlBQXVCLEVBQUUsU0FBa0I7UUFDckQsSUFBSSxDQUFDLFNBQVMsR0FBRyxZQUFZLENBQUM7UUFDOUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsSUFBSSxPQUFPLENBQUM7SUFDekUsQ0FBQztJQUVELG9EQUFvRDtJQUM3QyxXQUFXO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTTtRQUNYLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNmLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBNEIsQ0FBQztZQUMzRSxPQUFPO2dCQUNMLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxLQUFLLFNBQVM7Z0JB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
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CodexSwitcher } from './classes.codexswitcher.js';
|
|
2
|
+
import { CodexAccountStatus } from './classes.codexstatus.js';
|
|
3
|
+
import { CodexPreuse } from './classes.codexpreuse.js';
|
|
4
|
+
import type { IAuthHarness, IHarnessAccountStatus, IHarnessOutcome, IHarnessState, IHarnessPreuseOptions, IHarnessPreuseResult } from './interfaces.harness.js';
|
|
5
|
+
import type { IHarnessLoginOptions, IHarnessLoginProvider } from './interfaces.harness.js';
|
|
6
|
+
/** Codex-specific credentials, remote-control handling and service status. */
|
|
7
|
+
export declare class CodexHarness implements IAuthHarness {
|
|
8
|
+
private readonly switcher;
|
|
9
|
+
private readonly accountStatus;
|
|
10
|
+
private readonly preuse;
|
|
11
|
+
readonly id = "codex";
|
|
12
|
+
readonly label = "Codex";
|
|
13
|
+
readonly loginHint = "Use authswitch codex login to sign in and save another account.";
|
|
14
|
+
readonly loginProviders: IHarnessLoginProvider[];
|
|
15
|
+
readonly diagnosticsLabel = "Check credential storage and remote control";
|
|
16
|
+
constructor(switcher?: CodexSwitcher, accountStatus?: Pick<CodexAccountStatus, 'read'>, preuse?: Pick<CodexPreuse, 'run'>);
|
|
17
|
+
beginLogin(options?: IHarnessLoginOptions): Promise<import("./interfaces.harness.js").IHarnessLoginHandle>;
|
|
18
|
+
readState(): IHarnessState;
|
|
19
|
+
readAccountStatus(accountIdArg: string): Promise<IHarnessAccountStatus>;
|
|
20
|
+
preuseAccount(accountIdArg: string, optionsArg: IHarnessPreuseOptions): Promise<IHarnessPreuseResult>;
|
|
21
|
+
private readAccountCredential;
|
|
22
|
+
private activeAccountId;
|
|
23
|
+
resolveAccount(referenceArg: string): {
|
|
24
|
+
id: string;
|
|
25
|
+
} | {
|
|
26
|
+
candidates: string[];
|
|
27
|
+
};
|
|
28
|
+
switchAccount(accountIdArg: string): IHarnessOutcome;
|
|
29
|
+
removeAccount(accountIdArg: string): IHarnessOutcome;
|
|
30
|
+
saveCurrent(optionsArg: {
|
|
31
|
+
keepActive: boolean;
|
|
32
|
+
}): IHarnessOutcome;
|
|
33
|
+
private formatRemoteControl;
|
|
34
|
+
diagnose(): IHarnessOutcome;
|
|
35
|
+
}
|